rust_hdl_widgets/png/
lfsr.rs

1use crate::{dff_setup, prelude::DFFWithInit};
2use rust_hdl_core::prelude::*;
3
4// Adopted from Alchitry.com Lucid module `pn_gen`
5// This version does not provide seed setting.  It generates a fixed sequence.
6#[derive(LogicBlock)]
7pub struct LFSRSimple {
8    pub clock: Signal<In, Clock>,
9    pub strobe: Signal<In, Bit>,
10    pub num: Signal<Out, Bits<32>>,
11    x: DFFWithInit<Bits<32>>,
12    y: DFFWithInit<Bits<32>>,
13    z: DFFWithInit<Bits<32>>,
14    w: DFFWithInit<Bits<32>>,
15    t: Signal<Local, Bits<32>>,
16}
17
18const SEED: u128 = 0x843233523a613966423b622562592c62;
19
20impl Default for LFSRSimple {
21    fn default() -> Self {
22        Self {
23            clock: Default::default(),
24            strobe: Default::default(),
25            num: Default::default(),
26            t: Default::default(),
27            x: DFFWithInit::new((SEED & 0xFFFF_FFFF_u128).to_bits()),
28            y: DFFWithInit::new(((SEED >> 32) & 0xFFFF_FFFF_u128).to_bits()),
29            z: DFFWithInit::new(((SEED >> 64) & 0xFFFF_FFFF_u128).to_bits()),
30            w: DFFWithInit::new(((SEED >> 96) & 0xFFFF_FFFF_u128).to_bits()),
31        }
32    }
33}
34
35impl Logic for LFSRSimple {
36    #[hdl_gen]
37    fn update(&mut self) {
38        dff_setup!(self, clock, x, y, z, w);
39        self.num.next = self.w.q.val();
40        self.t.next = self.x.q.val() ^ (self.x.q.val() << 11);
41        if self.strobe.val() {
42            self.x.d.next = self.y.q.val();
43            self.y.d.next = self.z.q.val();
44            self.z.d.next = self.w.q.val();
45            self.w.d.next =
46                self.w.q.val() ^ (self.w.q.val() >> 19) ^ self.t.val() ^ (self.t.val() >> 8);
47        }
48    }
49}
50
51#[test]
52fn test_lfsr_simple_synthesizes() {
53    let mut uut = LFSRSimple::default();
54    uut.connect_all();
55    yosys_validate("lfsr", &generate_verilog(&uut)).unwrap();
56}