sc_neurocore_engine/encoder.rs
1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Commercial license available
3// © Concepts 1996–2026 Miroslav Šotek. All rights reserved.
4// © Code 2020–2026 Miroslav Šotek. All rights reserved.
5// ORCID: 0009-0009-3560-0851
6// Contact: www.anulum.li | protoscience@anulum.li
7// SC-NeuroCore — Stochastic Encoders
8
9//! # Stochastic Encoders
10//!
11//! LFSR-driven Bernoulli encoding utilities used by SC-NeuroCore kernels.
12
13/// 16-bit linear-feedback shift register used as pseudo-random source.
14#[derive(Clone, Debug)]
15pub struct Lfsr16 {
16 /// Current register value.
17 pub reg: u16,
18 /// Register width in bits.
19 pub width: u32,
20}
21
22impl Lfsr16 {
23 /// Create an LFSR with a non-zero seed.
24 pub fn new(seed: u16) -> Self {
25 assert_ne!(seed, 0, "LFSR seed must be non-zero.");
26 Self {
27 reg: seed,
28 width: 16,
29 }
30 }
31
32 /// Advance one LFSR step and return the new register value.
33 pub fn step(&mut self) -> u16 {
34 let feedback =
35 ((self.reg >> 15) ^ (self.reg >> 13) ^ (self.reg >> 12) ^ (self.reg >> 10)) & 1;
36 self.reg = (self.reg << 1) | feedback;
37 self.reg
38 }
39
40 /// Reset register state. If `seed` is `None`, keeps current seed value.
41 pub fn reset(&mut self, seed: Option<u16>) {
42 let next = seed.unwrap_or(self.reg);
43 assert_ne!(next, 0, "LFSR seed must be non-zero.");
44 self.reg = next;
45 }
46}
47
48/// Comparator-based stochastic bitstream encoder.
49#[derive(Clone, Debug)]
50pub struct BitstreamEncoder {
51 /// Underlying LFSR source.
52 pub lfsr: Lfsr16,
53 /// Data path width for compatibility with fixed-point callers.
54 pub data_width: u32,
55 seed_init: u16,
56}
57
58impl BitstreamEncoder {
59 /// Create a new encoder with deterministic seed.
60 pub fn new(data_width: u32, seed: u16) -> Self {
61 Self {
62 lfsr: Lfsr16::new(seed),
63 data_width,
64 seed_init: seed,
65 }
66 }
67
68 /// Emit one stochastic bit by comparing RNG value against `x_value`.
69 ///
70 /// Matches Verilog RTL semantics: compare current register, then advance.
71 /// (Non-blocking assignment in `sc_bitstream_encoder.v` reads pre-advance state.)
72 pub fn step(&mut self, x_value: u16) -> u8 {
73 let bit = if self.lfsr.reg < x_value { 1 } else { 0 };
74 self.lfsr.step();
75 bit
76 }
77
78 /// Reset the encoder LFSR state.
79 pub fn reset(&mut self, seed: Option<u16>) {
80 let next = seed.unwrap_or(self.seed_init);
81 self.lfsr = Lfsr16::new(next);
82 }
83}