Skip to main content

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}