rust_hdl_widgets/fifo/
fifo_reducer.rs1use rust_hdl_core::prelude::*;
2
3use crate::{dff::DFF, dff_setup};
4
5#[derive(LogicBlock)]
6pub struct FIFOReducer<const DW: usize, const DN: usize, const REVERSE: bool> {
7 pub data_in: Signal<In, Bits<DW>>,
9 pub read: Signal<Out, Bit>,
10 pub empty: Signal<In, Bit>,
11 pub data_out: Signal<Out, Bits<DN>>,
13 pub write: Signal<Out, Bit>,
14 pub full: Signal<In, Bit>,
15 pub clock: Signal<In, Clock>,
18 loaded: DFF<Bit>,
19 data_available: Signal<Local, Bit>,
20 can_write: Signal<Local, Bit>,
21 will_run: Signal<Local, Bit>,
22 data_to_write: Signal<Local, Bits<DN>>,
23 offset: Constant<Bits<DW>>,
24 reverse: Constant<Bit>,
25}
26
27impl<const DW: usize, const DN: usize, const REVERSE: bool> Default
28 for FIFOReducer<DW, DN, REVERSE>
29{
30 fn default() -> Self {
31 assert_eq!(DW, DN * 2);
32 Self {
33 data_in: Default::default(),
34 read: Default::default(),
35 empty: Default::default(),
36 data_out: Default::default(),
37 write: Default::default(),
38 full: Default::default(),
39 clock: Default::default(),
40 loaded: Default::default(),
41 data_available: Default::default(),
42 can_write: Default::default(),
43 will_run: Default::default(),
44 data_to_write: Default::default(),
45 offset: Constant::new(DN.to_bits()),
46 reverse: Constant::new(REVERSE),
47 }
48 }
49}
50
51impl<const DW: usize, const DN: usize, const REVERSE: bool> Logic for FIFOReducer<DW, DN, REVERSE> {
52 #[hdl_gen]
53 fn update(&mut self) {
54 dff_setup!(self, clock, loaded);
56 self.data_available.next = self.loaded.q.val() || !self.empty.val();
58 self.can_write.next = self.data_available.val() && !self.full.val();
60 self.will_run.next = self.data_available.val() && self.can_write.val();
62 if self.reverse.val() ^ self.loaded.q.val() {
64 self.data_to_write.next = self.data_in.val().get_bits::<DN>(self.offset.val().index());
65 } else {
66 self.data_to_write.next = self.data_in.val().get_bits::<DN>(0);
67 }
68 self.data_out.next = self.data_to_write.val();
70 self.write.next = self.can_write.val();
72 self.loaded.d.next = self.loaded.q.val() ^ self.will_run.val();
74 self.read.next = self.loaded.q.val() && self.will_run.val() && !self.empty.val();
76 }
77}
78
79#[test]
80fn fifo_reducer_is_synthesizable() {
81 let mut dev: FIFOReducer<8, 4, false> = Default::default();
82 dev.connect_all();
83 yosys_validate("fifo_reducer", &generate_verilog(&dev)).unwrap();
84}