rust_hdl_widgets/fifo/
cross_fifo.rs

1use crate::fifo::async_fifo::AsynchronousFIFO;
2use crate::fifo::fifo_expander_n::WordOrder;
3use crate::fifo::sync_fifo::SynchronousFIFO;
4use crate::prelude::{FIFOExpanderN, FIFOReducerN};
5use rust_hdl_core::prelude::*;
6
7#[derive(LogicBlock)]
8pub struct CrossWidenFIFO<
9    const DN: usize,   // Narrow width
10    const NN: usize,   // Number of bits on the narrow side address
11    const NNP1: usize, // NN + 1
12    const DW: usize,   // Wide width
13    const WN: usize,   // Number of bits on the wide side address
14    const WNP1: usize, // WN + 1
15> {
16    // Write interface
17    pub data_in: Signal<In, Bits<DN>>,
18    pub write: Signal<In, Bit>,
19    pub full: Signal<Out, Bit>,
20    pub write_clock: Signal<In, Clock>,
21    // Read interface
22    pub data_out: Signal<Out, Bits<DW>>,
23    pub read: Signal<In, Bit>,
24    pub empty: Signal<Out, Bit>,
25    pub read_clock: Signal<In, Clock>,
26    // Input FIFO
27    pub in_fifo: AsynchronousFIFO<Bits<DN>, NN, NNP1, 1>,
28    // Output FIFO
29    pub out_fifo: SynchronousFIFO<Bits<DW>, WN, WNP1, 1>,
30    // Expander
31    pub xpand: FIFOExpanderN<DN, DW>,
32}
33
34impl<
35        const DN: usize,
36        const NN: usize,
37        const NNP1: usize,
38        const DW: usize,
39        const WN: usize,
40        const WNP1: usize,
41    > CrossWidenFIFO<DN, NN, NNP1, DW, WN, WNP1>
42{
43    pub fn new(order: WordOrder) -> Self {
44        Self {
45            data_in: Default::default(),
46            write: Default::default(),
47            full: Default::default(),
48            write_clock: Default::default(),
49            data_out: Default::default(),
50            read: Default::default(),
51            empty: Default::default(),
52            read_clock: Default::default(),
53            in_fifo: Default::default(),
54            out_fifo: Default::default(),
55            xpand: FIFOExpanderN::new(order),
56        }
57    }
58}
59
60impl<
61        const DN: usize,
62        const NN: usize,
63        const NNP1: usize,
64        const DW: usize,
65        const WN: usize,
66        const WNP1: usize,
67    > Default for CrossWidenFIFO<DN, NN, NNP1, DW, WN, WNP1>
68{
69    fn default() -> Self {
70        Self::new(WordOrder::MostSignificantFirst)
71    }
72}
73
74impl<
75        const DN: usize,
76        const NN: usize,
77        const NNP1: usize,
78        const DW: usize,
79        const WN: usize,
80        const WNP1: usize,
81    > Logic for CrossWidenFIFO<DN, NN, NNP1, DW, WN, WNP1>
82{
83    #[hdl_gen]
84    fn update(&mut self) {
85        // Connect the write side of the input fifo to the write interface
86        self.in_fifo.data_in.next = self.data_in.val();
87        self.in_fifo.write.next = self.write.val();
88        self.full.next = self.in_fifo.full.val();
89        self.in_fifo.write_clock.next = self.write_clock.val();
90        // Connect the read side of the input fifo to the expander
91        self.xpand.data_in.next = self.in_fifo.data_out.val();
92        self.xpand.empty.next = self.in_fifo.empty.val();
93        self.in_fifo.read.next = self.xpand.read.val();
94        self.in_fifo.read_clock.next = self.read_clock.val();
95        clock!(self, read_clock, xpand, out_fifo);
96        // Connect the read side of the output fifo to the read interface
97        self.data_out.next = self.out_fifo.data_out.val();
98        self.empty.next = self.out_fifo.empty.val();
99        self.out_fifo.read.next = self.read.val();
100        // Connect the write side of the output fifo to the expander
101        self.out_fifo.data_in.next = self.xpand.data_out.val();
102        self.xpand.full.next = self.out_fifo.full.val();
103        self.out_fifo.write.next = self.xpand.write.val();
104    }
105}
106
107#[test]
108fn cross_widen_fifo_is_synthesizable() {
109    let mut dev = CrossWidenFIFO::<16, 8, 9, 128, 5, 6>::new(WordOrder::MostSignificantFirst);
110    dev.connect_all();
111    yosys_validate("cross_wide", &generate_verilog(&dev)).unwrap();
112}
113
114#[derive(LogicBlock)]
115pub struct CrossNarrowFIFO<
116    const DW: usize,
117    const WN: usize,
118    const WNP1: usize,
119    const DN: usize,
120    const NN: usize,
121    const NNP1: usize,
122> {
123    // Write interface
124    pub data_in: Signal<In, Bits<DW>>,
125    pub write: Signal<In, Bit>,
126    pub full: Signal<Out, Bit>,
127    pub write_clock: Signal<In, Clock>,
128    // Read interface
129    pub data_out: Signal<Out, Bits<DN>>,
130    pub read: Signal<In, Bit>,
131    pub empty: Signal<Out, Bit>,
132    pub read_clock: Signal<In, Clock>,
133    // Input FIFO
134    pub in_fifo: AsynchronousFIFO<Bits<DW>, WN, WNP1, 1>,
135    // Output FIFO
136    pub out_fifo: SynchronousFIFO<Bits<DN>, NN, NNP1, 1>,
137    // Reducer
138    pub reducer: FIFOReducerN<DW, DN>,
139}
140
141impl<
142        const DW: usize,
143        const WN: usize,
144        const WNP1: usize,
145        const DN: usize,
146        const NN: usize,
147        const NNP1: usize,
148    > CrossNarrowFIFO<DW, WN, WNP1, DN, NN, NNP1>
149{
150    pub fn new(order: WordOrder) -> Self {
151        Self {
152            data_in: Default::default(),
153            write: Default::default(),
154            full: Default::default(),
155            write_clock: Default::default(),
156            data_out: Default::default(),
157            read: Default::default(),
158            empty: Default::default(),
159            read_clock: Default::default(),
160            in_fifo: Default::default(),
161            out_fifo: Default::default(),
162            reducer: FIFOReducerN::new(order),
163        }
164    }
165}
166
167impl<
168        const DW: usize,
169        const WN: usize,
170        const WNP1: usize,
171        const DN: usize,
172        const NN: usize,
173        const NNP1: usize,
174    > Logic for CrossNarrowFIFO<DW, WN, WNP1, DN, NN, NNP1>
175{
176    #[hdl_gen]
177    fn update(&mut self) {
178        // Connect the write side of the input fifo to the write interface
179        self.in_fifo.data_in.next = self.data_in.val();
180        self.in_fifo.write.next = self.write.val();
181        self.full.next = self.in_fifo.full.val();
182        self.in_fifo.write_clock.next = self.write_clock.val();
183        // Connect the read side of the input fifo to the reducer
184        self.reducer.data_in.next = self.in_fifo.data_out.val();
185        self.reducer.empty.next = self.in_fifo.empty.val();
186        self.in_fifo.read.next = self.reducer.read.val();
187        self.in_fifo.read_clock.next = self.read_clock.val();
188        clock!(self, read_clock, reducer, out_fifo);
189        // Connect the read side of the output fifo to the read interface
190        self.data_out.next = self.out_fifo.data_out.val();
191        self.empty.next = self.out_fifo.empty.val();
192        self.out_fifo.read.next = self.read.val();
193        // Connect the write side of the output fifo to the reducer
194        self.out_fifo.data_in.next = self.reducer.data_out.val();
195        self.reducer.full.next = self.out_fifo.full.val();
196        self.out_fifo.write.next = self.reducer.write.val();
197    }
198}
199
200impl<
201        const DW: usize,
202        const WN: usize,
203        const WNP1: usize,
204        const DN: usize,
205        const NN: usize,
206        const NNP1: usize,
207    > Default for CrossNarrowFIFO<DW, WN, WNP1, DN, NN, NNP1>
208{
209    fn default() -> Self {
210        Self::new(WordOrder::MostSignificantFirst)
211    }
212}
213
214#[test]
215fn cross_narrow_fifo_is_synthesizable() {
216    let mut dev = CrossNarrowFIFO::<128, 5, 6, 16, 8, 9>::new(WordOrder::MostSignificantFirst);
217    dev.connect_all();
218    yosys_validate("cross_narrow", &generate_verilog(&dev)).unwrap();
219}
220
221#[macro_export]
222macro_rules! declare_expanding_fifo {
223    ($name: ident, $narrow_bits: expr, $narrow_count: expr, $wide_bits: expr, $wide_count: expr) => {
224        pub type $name = CrossWidenFIFO<
225            $narrow_bits,
226            { clog2($narrow_count) },
227            { clog2($narrow_count) + 1 },
228            $wide_bits,
229            { clog2($wide_count) },
230            { clog2($wide_count) + 1 },
231        >;
232    };
233}
234
235#[macro_export]
236macro_rules! declare_narrowing_fifo {
237    ($name: ident, $wide_bits: expr, $wide_count: expr, $narrow_bits: expr, $narrow_count: expr) => {
238        pub type $name = CrossNarrowFIFO<
239            $wide_bits,
240            { clog2($wide_count) },
241            { clog2($wide_count) + 1 },
242            $narrow_bits,
243            { clog2($narrow_count) },
244            { clog2($narrow_count) + 1 },
245        >;
246    };
247}