rust_hdl_widgets/fifo/
fifo_reducer_n.rs1use crate::{dff::DFF, dff_setup, fifo::fifo_expander_n::WordOrder};
2use rust_hdl_core::prelude::*;
3
4#[derive(LogicBlock)]
5pub struct FIFOReducerN<const DW: usize, const DN: usize> {
6 pub data_in: Signal<In, Bits<DW>>,
8 pub read: Signal<Out, Bit>,
9 pub empty: Signal<In, Bit>,
10 pub data_out: Signal<Out, Bits<DN>>,
12 pub write: Signal<Out, Bit>,
13 pub full: Signal<In, Bit>,
14 pub clock: Signal<In, Clock>,
17 load_count: DFF<Bits<8>>,
18 data_available: Signal<Local, Bit>,
19 will_write: Signal<Local, Bit>,
20 will_consume: Signal<Local, Bit>,
21 data_store: DFF<Bits<DW>>,
22 msw_first: Constant<Bit>,
23 ratio: Constant<Bits<8>>,
24 offset: Constant<Bits<DW>>,
25 select: Constant<Bits<16>>,
26}
27
28impl<const DW: usize, const DN: usize> Logic for FIFOReducerN<DW, DN> {
29 #[hdl_gen]
30 fn update(&mut self) {
31 dff_setup!(self, clock, load_count, data_store);
32 self.data_available.next = self.load_count.q.val().any() | !self.empty.val();
35 self.will_write.next = self.data_available.val() & !self.full.val();
37 self.will_consume.next =
40 !self.load_count.q.val().any() & !self.empty.val() & self.will_write.val();
41 if self.load_count.q.val().any() {
42 self.data_out.next = self
45 .data_store
46 .q
47 .val()
48 .get_bits::<DN>(self.select.val().index())
49 } else {
50 self.data_out.next = self.data_in.val().get_bits::<DN>(self.select.val().index());
52 }
53 if self.will_write.val() {
55 if !self.msw_first.val() {
56 self.data_store.d.next = self.data_store.q.val() >> self.offset.val();
57 } else {
58 self.data_store.d.next = self.data_store.q.val() << self.offset.val();
59 }
60 if self.load_count.q.val().any() {
61 self.load_count.d.next = self.load_count.q.val() - 1;
62 }
63 }
64 if self.will_consume.val() {
66 if !self.msw_first.val() {
67 self.data_store.d.next = self.data_in.val() >> self.offset.val();
68 } else {
69 self.data_store.d.next = self.data_in.val() << self.offset.val();
70 }
71 self.load_count.d.next = self.ratio.val();
72 }
73 self.write.next = self.will_write.val();
74 self.read.next = self.will_consume.val();
75 }
76}
77
78impl<const DW: usize, const DN: usize> FIFOReducerN<DW, DN> {
79 pub fn new(order: WordOrder) -> Self {
80 assert_eq!(DW % DN, 0);
81 let msw_first = match order {
82 WordOrder::LeastSignificantFirst => false,
83 WordOrder::MostSignificantFirst => true,
84 };
85 Self {
86 data_in: Default::default(),
87 read: Default::default(),
88 empty: Default::default(),
89 data_out: Default::default(),
90 write: Default::default(),
91 full: Default::default(),
92 clock: Default::default(),
93 load_count: Default::default(),
94 data_available: Default::default(),
95 will_write: Default::default(),
96 will_consume: Default::default(),
97 data_store: Default::default(),
98 msw_first: Constant::new(msw_first),
99 ratio: Constant::new((DW / DN - 1).to_bits()),
100 offset: Constant::new(DN.to_bits()),
101 select: if !msw_first {
102 Constant::new(0.into())
103 } else {
104 Constant::new((DW - DN).to_bits())
105 },
106 }
107 }
108}
109
110#[test]
111fn fifo_reducern_is_synthesizable() {
112 let mut dev = FIFOReducerN::<32, 4>::new(WordOrder::MostSignificantFirst);
113 dev.connect_all();
114 yosys_validate("fifo_reducern", &generate_verilog(&dev)).unwrap();
115}