1use rust_hdl_core::prelude::*;
2
3use crate::{dff::DFF, dff_setup};
4
5#[derive(LogicBlock)]
8pub struct FIFOReadLogic<D: Synth, const N: usize, const NP1: usize, const BLOCK_SIZE: u32> {
9 pub clock: Signal<In, Clock>,
11 pub read: Signal<In, Bit>,
13 pub data_out: Signal<Out, D>,
14 pub empty: Signal<Out, Bit>,
15 pub almost_empty: Signal<Out, Bit>,
16 pub underflow: Signal<Out, Bit>,
17 pub write_address_delayed: Signal<In, Bits<NP1>>,
19 pub ram_read_address: Signal<Out, Bits<N>>,
21 pub ram_read_data: Signal<In, D>,
22 pub ram_read_clock: Signal<Out, Clock>,
23 pub read_address_out: Signal<Out, Bits<NP1>>,
25 pub fill_level: Signal<Out, Bits<NP1>>,
26 read_address: DFF<Bits<NP1>>,
28 is_empty: Signal<Local, Bit>,
29 is_full: Signal<Local, Bit>,
30 dff_underflow: DFF<Bit>,
31 fifo_address_mask: Constant<Bits<NP1>>,
32 fifo_size: Constant<Bits<NP1>>,
33 block_size: Constant<Bits<NP1>>,
34}
35
36impl<D: Synth, const N: usize, const NP1: usize, const BLOCK_SIZE: u32> Logic
37 for FIFOReadLogic<D, N, NP1, BLOCK_SIZE>
38{
39 #[hdl_gen]
40 fn update(&mut self) {
41 dff_setup!(self, clock, read_address, dff_underflow);
42 self.ram_read_clock.next = self.clock.val();
44 self.is_empty.next = (self.read_address.q.val() == self.write_address_delayed.val()).into();
46 self.is_full.next = !self.is_empty.val()
47 & ((self.read_address.q.val() & self.fifo_address_mask.val())
48 == (self.write_address_delayed.val() & self.fifo_address_mask.val()));
49 self.fill_level.next = ((self.write_address_delayed.val() & self.fifo_address_mask.val())
51 + self.fifo_size.val()
52 - (self.read_address.q.val() & self.fifo_address_mask.val()))
53 & self.fifo_address_mask.val();
54 if self.is_full.val() {
55 self.fill_level.next = self.fifo_size.val();
56 }
57 self.almost_empty.next = (self.fill_level.val() < self.block_size.val()).into();
59 self.empty.next = self.is_empty.val();
61 self.ram_read_address.next =
63 bit_cast::<N, NP1>(self.read_address.q.val() & self.fifo_address_mask.val());
64 self.data_out.next = self.ram_read_data.val();
66 if self.read.val() & !self.is_empty.val() {
69 self.read_address.d.next = self.read_address.q.val() + 1;
70 self.ram_read_address.next =
73 bit_cast::<N, NP1>((self.read_address.q.val() + 1) & self.fifo_address_mask.val());
74 } else {
75 self.read_address.d.next = self.read_address.q.val();
76 }
77 self.dff_underflow.d.next =
78 self.dff_underflow.q.val() | (self.is_empty.val() & self.read.val());
79 self.underflow.next = self.dff_underflow.q.val();
80 self.read_address_out.next = self.read_address.q.val();
81 }
82}
83
84impl<D: Synth, const N: usize, const NP1: usize, const BLOCK_SIZE: u32> Default
85 for FIFOReadLogic<D, N, NP1, BLOCK_SIZE>
86{
87 fn default() -> Self {
88 Self {
89 clock: Default::default(),
90 read: Default::default(),
91 data_out: Default::default(),
92 empty: Default::default(),
93 almost_empty: Default::default(),
94 underflow: Default::default(),
95 write_address_delayed: Default::default(),
96 ram_read_address: Default::default(),
97 ram_read_data: Default::default(),
98 ram_read_clock: Default::default(),
99 read_address_out: Default::default(),
100 read_address: Default::default(),
101 is_empty: Default::default(),
102 is_full: Default::default(),
103 fill_level: Default::default(),
104 dff_underflow: Default::default(),
105 fifo_address_mask: Constant::new(((1_u32 << (N)) - 1).to_bits()),
106 fifo_size: Constant::new(Bits::<N>::count().to_bits()),
107 block_size: Constant::new(BLOCK_SIZE.to_bits()),
108 }
109 }
110}
111
112#[test]
113fn fifo_read_is_synthesizable() {
114 let mut dev: FIFOReadLogic<Bits<8>, 8, 9, 4> = Default::default();
115 dev.connect_all();
116 yosys_validate("fifo_read", &generate_verilog(&dev)).unwrap();
117}
118
119#[derive(LogicBlock)]
120pub struct FIFOWriteLogic<D: Synth, const N: usize, const NP1: usize, const BLOCK_SIZE: u32> {
121 pub write: Signal<In, Bit>,
122 pub data_in: Signal<In, D>,
123 pub full: Signal<Out, Bit>,
124 pub almost_full: Signal<Out, Bit>,
125 pub overflow: Signal<Out, Bit>,
126 pub clock: Signal<In, Clock>,
127 pub ram_write_address: Signal<Out, Bits<N>>,
128 pub ram_write_clock: Signal<Out, Clock>,
129 pub ram_write_data: Signal<Out, D>,
130 pub ram_write_enable: Signal<Out, Bit>,
131 pub read_address: Signal<In, Bits<NP1>>,
132 pub write_address_delayed: Signal<Out, Bits<NP1>>,
133 write_address: DFF<Bits<NP1>>,
134 dff_write_address_delay: DFF<Bits<NP1>>,
135 is_empty: Signal<Local, Bit>,
136 is_full: Signal<Local, Bit>,
137 pub fill_level: Signal<Out, Bits<NP1>>,
138 dff_overflow: DFF<Bit>,
139 fifo_address_mask: Constant<Bits<NP1>>,
140 fifo_size: Constant<Bits<NP1>>,
141 almost_full_level: Constant<Bits<NP1>>,
142}
143
144impl<D: Synth, const N: usize, const NP1: usize, const BLOCK_SIZE: u32> Default
145 for FIFOWriteLogic<D, N, NP1, BLOCK_SIZE>
146{
147 fn default() -> Self {
148 assert_eq!(N + 1, NP1);
149 assert!(NP1 < 32);
150 Self {
151 write: Default::default(),
152 data_in: Default::default(),
153 full: Default::default(),
154 almost_full: Default::default(),
155 overflow: Default::default(),
156 clock: Default::default(),
157 ram_write_address: Default::default(),
158 ram_write_clock: Default::default(),
159 ram_write_data: Default::default(),
160 ram_write_enable: Default::default(),
161 read_address: Default::default(),
162 write_address: Default::default(),
163 write_address_delayed: Default::default(),
164 dff_write_address_delay: Default::default(),
165 is_empty: Default::default(),
166 is_full: Default::default(),
167 fill_level: Default::default(),
168 dff_overflow: Default::default(),
169 fifo_address_mask: Constant::new(((1_u32 << (N)) - 1).to_bits()),
170 fifo_size: Constant::new(Bits::<N>::count().to_bits()),
171 almost_full_level: Constant::new((Bits::<N>::count() - (BLOCK_SIZE as u128)).to_bits()),
172 }
173 }
174}
175
176impl<D: Synth, const N: usize, const NP1: usize, const BLOCK_SIZE: u32> Logic
177 for FIFOWriteLogic<D, N, NP1, BLOCK_SIZE>
178{
179 #[hdl_gen]
180 fn update(&mut self) {
181 dff_setup!(
182 self,
183 clock,
184 dff_overflow,
185 write_address,
186 dff_write_address_delay
187 );
188 self.ram_write_clock.next = self.clock.val();
189 self.dff_write_address_delay.d.next = self.write_address.q.val();
193 self.write_address_delayed.next = self.dff_write_address_delay.q.val();
194 self.ram_write_enable.next = false.into();
196 self.is_empty.next =
199 (self.read_address.val() == self.dff_write_address_delay.q.val()).into();
200 self.is_full.next = !self.is_empty.val()
203 & ((self.read_address.val() & self.fifo_address_mask.val())
204 == (self.write_address.q.val() & self.fifo_address_mask.val()));
205 self.fill_level.next = ((self.dff_write_address_delay.q.val()
210 & self.fifo_address_mask.val())
211 + self.fifo_size.val()
212 - (self.read_address.val() & self.fifo_address_mask.val()))
213 & self.fifo_address_mask.val();
214 if self.is_full.val() {
215 self.fill_level.next = self.fifo_size.val();
216 }
217 self.almost_full.next = (self.fill_level.val() >= self.almost_full_level.val()).into();
218 self.full.next = self.is_full.val();
219 self.ram_write_address.next =
221 bit_cast::<N, NP1>(self.write_address.q.val() & self.fifo_address_mask.val());
222 self.ram_write_data.next = self.data_in.val();
223 if self.write.val() & !self.is_full.val() {
226 self.write_address.d.next = self.write_address.q.val() + 1;
227 self.ram_write_enable.next = true;
228 } else {
229 self.write_address.d.next = self.write_address.q.val();
230 self.ram_write_enable.next = false;
231 }
232 self.dff_overflow.d.next =
234 self.dff_overflow.q.val() | (self.is_full.val() & self.write.val());
235 self.overflow.next = self.dff_overflow.q.val();
236 }
237}
238
239#[test]
240fn fifo_write_is_synthesizable() {
241 let mut dev: FIFOWriteLogic<Bits<8>, 8, 9, 4> = Default::default();
242 dev.connect_all();
243 yosys_validate("fifo_write", &generate_verilog(&dev)).unwrap();
244}