rust_hdl_hls/
test_helpers.rs

1use crate::bridge::Bridge;
2use crate::bus::{
3    FIFOReadController, FIFOReadResponder, FIFOWriteController, FIFOWriteResponder,
4    SoCBusController, SoCPortController,
5};
6use crate::controller::BaseController;
7use crate::fifo::AsyncFIFO;
8use crate::miso_port::MISOPort;
9use crate::mosi_port::MOSIPort;
10use rand::Rng;
11use rust_hdl_core::prelude::*;
12use rust_hdl_widgets::prelude::*;
13use std::collections::BTreeMap;
14use std::f64::consts::PI;
15
16pub fn snore<const P: usize>(x: u32) -> Bits<P> {
17    let amp = (f64::exp(f64::sin(((x as f64) - 128.0 / 2.) * PI / 128.0)) - 0.36787944) * 108.0;
18    let amp = (amp.max(0.0).min(255.0).floor() / 255.0 * (1 << P) as f64) as u8;
19    amp.to_bits()
20}
21
22#[derive(LogicBlock)]
23pub struct FaderWithSyncROM {
24    pub clock: Signal<In, Clock>,
25    pub active: Signal<Out, Bit>,
26    pub enable: Signal<In, Bit>,
27    strobe: Strobe<32>,
28    pwm: PulseWidthModulator<6>,
29    rom: SyncROM<Bits<6>, 8>,
30    counter: DFF<Bits<8>>,
31}
32
33impl FaderWithSyncROM {
34    pub fn new(clock_frequency: u64, phase: u32) -> Self {
35        let rom = (0..256)
36            .map(|x| (x.to_bits(), snore(x + phase)))
37            .collect::<BTreeMap<_, _>>();
38        Self {
39            clock: Signal::default(),
40            active: Signal::new_with_default(false),
41            enable: Signal::default(),
42            strobe: Strobe::new(clock_frequency, 120.0),
43            pwm: PulseWidthModulator::default(),
44            rom: SyncROM::new(rom),
45            counter: Default::default(),
46        }
47    }
48}
49
50impl Logic for FaderWithSyncROM {
51    #[hdl_gen]
52    fn update(&mut self) {
53        clock!(self, clock, strobe, pwm, counter);
54        self.rom.clock.next = self.clock.val();
55        self.rom.address.next = self.counter.q.val();
56        self.counter.d.next = self.counter.q.val() + self.strobe.strobe.val();
57        self.strobe.enable.next = self.enable.val();
58        self.pwm.enable.next = self.enable.val();
59        self.active.next = self.pwm.active.val();
60        self.pwm.threshold.next = self.rom.data.val();
61    }
62}
63
64#[derive(LogicState, Debug, Copy, Clone, PartialEq)]
65enum FIFOFeederState {
66    Idle,
67    Running,
68    Sleeping,
69    Done,
70}
71
72#[derive(LogicBlock)]
73pub struct LazyFIFOFeeder<T: Synth, const N: usize> {
74    pub clock: Signal<In, Clock>,
75    pub bus: FIFOWriteController<T>,
76    pub done: Signal<Out, Bit>,
77    pub start: Signal<In, Bit>,
78    state: DFF<FIFOFeederState>,
79    sleep_counter: DFF<Bits<32>>,
80    index: DFF<Bits<N>>,
81    data_rom: ROM<T, N>,
82    sleep_rom: ROM<Bits<32>, N>,
83    data_len: Constant<Bits<N>>,
84}
85
86impl<T: Synth, const N: usize> LazyFIFOFeeder<T, N> {
87    pub fn new(data: &[T], sleeps: &[Bits<32>]) -> LazyFIFOFeeder<T, N> {
88        assert!(clog2(data.len()) <= N);
89        assert_eq!(data.len(), sleeps.len());
90        Self {
91            clock: Default::default(),
92            bus: Default::default(),
93            done: Default::default(),
94            start: Default::default(),
95            state: Default::default(),
96            sleep_counter: Default::default(),
97            index: Default::default(),
98            data_rom: data.to_vec().into_iter().into(),
99            sleep_rom: sleeps.to_vec().into_iter().into(),
100            data_len: Constant::new(data.len().to_bits()),
101        }
102    }
103}
104
105impl<T: Synth, const N: usize> Logic for LazyFIFOFeeder<T, N> {
106    #[hdl_gen]
107    fn update(&mut self) {
108        dff_setup!(self, clock, state, sleep_counter, index);
109        // Wire the FIFO bus to our data array
110        self.bus.data.next = self.data_rom.data.val();
111        self.bus.write.next = false;
112        // Connect the ROMS
113        self.sleep_rom.address.next = self.index.q.val();
114        self.data_rom.address.next = self.index.q.val();
115        self.done.next = false;
116        match self.state.q.val() {
117            FIFOFeederState::Idle => {
118                if self.start.val() {
119                    self.state.d.next = FIFOFeederState::Running;
120                }
121            }
122            FIFOFeederState::Running => {
123                if !self.bus.full.val() {
124                    self.bus.write.next = true;
125                    if self.index.q.val() == (self.data_len.val() - 1) {
126                        self.state.d.next = FIFOFeederState::Done;
127                    } else if self.sleep_rom.data.val().any() {
128                        self.state.d.next = FIFOFeederState::Sleeping;
129                        self.sleep_counter.d.next = self.sleep_rom.data.val();
130                    } else {
131                        self.index.d.next = self.index.q.val() + 1;
132                    }
133                }
134            }
135            FIFOFeederState::Sleeping => {
136                if self.sleep_counter.q.val() == 0 {
137                    self.state.d.next = FIFOFeederState::Running;
138                    self.index.d.next = self.index.q.val() + 1;
139                } else {
140                    self.sleep_counter.d.next = self.sleep_counter.q.val() - 1;
141                }
142            }
143            FIFOFeederState::Done => {
144                self.done.next = true;
145            }
146            _ => {
147                self.state.d.next = FIFOFeederState::Idle;
148            }
149        }
150    }
151}
152
153#[derive(LogicBlock)]
154pub struct LazyFIFOReader<T: Synth, const N: usize> {
155    pub clock: Signal<In, Clock>,
156    pub bus: FIFOReadController<T>,
157    pub done: Signal<Out, Bit>,
158    pub start: Signal<In, Bit>,
159    pub error: Signal<Out, Bit>,
160    mismatch: DFF<Bit>,
161    state: DFF<FIFOFeederState>,
162    sleep_counter: DFF<Bits<32>>,
163    index: DFF<Bits<N>>,
164    data_rom: ROM<T, N>,
165    sleep_rom: ROM<Bits<32>, N>,
166    data_len: Constant<Bits<N>>,
167}
168
169impl<T: Synth, const N: usize> LazyFIFOReader<T, N> {
170    pub fn new(data: &[T], sleeps: &[Bits<32>]) -> LazyFIFOReader<T, N> {
171        assert!(clog2(data.len()) <= N);
172        assert_eq!(data.len(), sleeps.len());
173        Self {
174            clock: Default::default(),
175            bus: Default::default(),
176            done: Default::default(),
177            start: Default::default(),
178            error: Default::default(),
179            mismatch: Default::default(),
180            state: Default::default(),
181            sleep_counter: Default::default(),
182            index: Default::default(),
183            data_rom: data.to_vec().into_iter().into(),
184            sleep_rom: sleeps.to_vec().into_iter().into(),
185            data_len: Constant::new(data.len().to_bits()),
186        }
187    }
188}
189
190impl<T: Synth, const N: usize> Logic for LazyFIFOReader<T, N> {
191    #[hdl_gen]
192    fn update(&mut self) {
193        dff_setup!(self, clock, mismatch, state, sleep_counter, index);
194        self.bus.read.next = false;
195        self.done.next = false;
196        // Connect the ROMS
197        self.sleep_rom.address.next = self.index.q.val();
198        self.data_rom.address.next = self.index.q.val();
199        self.error.next = self.mismatch.q.val();
200        match self.state.q.val() {
201            FIFOFeederState::Idle => {
202                if self.start.val() {
203                    self.state.d.next = FIFOFeederState::Running;
204                }
205            }
206            FIFOFeederState::Running => {
207                if !self.bus.empty.val() {
208                    if self.bus.data.val() != self.data_rom.data.val() {
209                        self.mismatch.d.next = true;
210                    }
211                    self.bus.read.next = true;
212                    if self.index.q.val() == (self.data_len.val() - 1) {
213                        self.state.d.next = FIFOFeederState::Done;
214                    } else if self.sleep_rom.data.val().any() {
215                        self.state.d.next = FIFOFeederState::Sleeping;
216                        self.sleep_counter.d.next = self.sleep_rom.data.val();
217                    } else {
218                        self.index.d.next = self.index.q.val() + 1;
219                    }
220                }
221            }
222            FIFOFeederState::Sleeping => {
223                if self.sleep_counter.q.val() == 0 {
224                    self.state.d.next = FIFOFeederState::Running;
225                    self.index.d.next = self.index.q.val() + 1;
226                } else {
227                    self.sleep_counter.d.next = self.sleep_counter.q.val() - 1;
228                }
229            }
230            FIFOFeederState::Done => {
231                self.done.next = true;
232            }
233            _ => {
234                self.state.d.next = FIFOFeederState::Idle;
235            }
236        }
237    }
238}
239
240pub fn bursty_rand() -> Bits<32> {
241    if rand::thread_rng().gen::<f64>() < 0.9 {
242        Bits::from(0)
243    } else {
244        ((rand::thread_rng().gen::<f64>() * 40.0) as u32).to_bits()
245    }
246}
247
248pub fn bursty_vec(len: usize) -> Vec<Bits<32>> {
249    (0..len).map(|_| bursty_rand()).collect()
250}
251
252#[derive(LogicBlock)]
253pub struct SoCTestChip {
254    pub clock: Signal<In, Clock>,
255    pub sys_clock: Signal<In, Clock>,
256    pub from_cpu: FIFOWriteResponder<Bits<16>>,
257    pub to_cpu: FIFOReadResponder<Bits<16>>,
258    from_cpu_fifo: AsyncFIFO<Bits<16>, 8, 9, 1>,
259    to_cpu_fifo: AsyncFIFO<Bits<16>, 8, 9, 1>,
260    soc_host: BaseController<8>,
261    bridge: Bridge<16, 8, 2>,
262    mosi_port: MOSIPort<16>, // At address
263    miso_port: MISOPort<16>,
264    data_fifo: SynchronousFIFO<Bits<16>, 8, 9, 1>,
265}
266
267impl Default for SoCTestChip {
268    fn default() -> Self {
269        Self {
270            clock: Default::default(),
271            sys_clock: Default::default(),
272            from_cpu: Default::default(),
273            to_cpu: Default::default(),
274            from_cpu_fifo: Default::default(),
275            to_cpu_fifo: Default::default(),
276            soc_host: Default::default(),
277            bridge: Bridge::new(["mosi", "miso"]),
278            mosi_port: Default::default(),
279            miso_port: Default::default(),
280            data_fifo: Default::default(),
281        }
282    }
283}
284
285impl Logic for SoCTestChip {
286    #[hdl_gen]
287    fn update(&mut self) {
288        self.from_cpu_fifo.write_clock.next = self.clock.val();
289        self.to_cpu_fifo.read_clock.next = self.clock.val();
290        self.from_cpu_fifo.read_clock.next = self.sys_clock.val();
291        self.to_cpu_fifo.write_clock.next = self.sys_clock.val();
292        self.soc_host.clock.next = self.sys_clock.val();
293        // Connect the controller to the bridge
294        SoCBusController::<16, 8>::join(&mut self.soc_host.bus, &mut self.bridge.upstream);
295        SoCPortController::<16>::join(&mut self.bridge.nodes[0], &mut self.mosi_port.bus);
296        SoCPortController::<16>::join(&mut self.bridge.nodes[1], &mut self.miso_port.bus);
297        clock!(self, sys_clock, data_fifo);
298        // Wire the MOSI port to the input of the data_fifo
299        self.data_fifo.data_in.next = self.mosi_port.port_out.val() << 1;
300        self.data_fifo.write.next = self.mosi_port.strobe_out.val();
301        self.mosi_port.ready.next = !self.data_fifo.full.val();
302        // Wire the MISO port to the output of the data fifo
303        self.miso_port.port_in.next = self.data_fifo.data_out.val();
304        self.data_fifo.read.next = self.miso_port.strobe_out.val();
305        self.miso_port.ready_in.next = !self.data_fifo.empty.val();
306        // Wire the cpu fifos to the host
307        FIFOWriteResponder::<Bits<16>>::link(&mut self.from_cpu, &mut self.from_cpu_fifo.bus_write);
308        FIFOReadResponder::<Bits<16>>::link(&mut self.to_cpu, &mut self.to_cpu_fifo.bus_read);
309        FIFOReadResponder::<Bits<16>>::join(
310            &mut self.from_cpu_fifo.bus_read,
311            &mut self.soc_host.from_cpu,
312        );
313        FIFOWriteResponder::<Bits<16>>::join(
314            &mut self.to_cpu_fifo.bus_write,
315            &mut self.soc_host.to_cpu,
316        );
317    }
318}