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