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, const NN: usize, const NNP1: usize, const DW: usize, const WN: usize, const WNP1: usize, > {
16 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 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 pub in_fifo: AsynchronousFIFO<Bits<DN>, NN, NNP1, 1>,
28 pub out_fifo: SynchronousFIFO<Bits<DW>, WN, WNP1, 1>,
30 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 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 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 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 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 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 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 pub in_fifo: AsynchronousFIFO<Bits<DW>, WN, WNP1, 1>,
135 pub out_fifo: SynchronousFIFO<Bits<DN>, NN, NNP1, 1>,
137 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 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 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 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 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}