rust_hdl_widgets/fifo/
async_fifo.rs

1use crate::fifo::fifo_logic::{FIFOReadLogic, FIFOWriteLogic};
2use crate::ramrom::ram::RAM;
3use crate::synchronizer::VectorSynchronizer;
4use rust_hdl_core::prelude::*;
5
6#[macro_export]
7macro_rules! declare_async_fifo {
8    ($name: ident, $kind: ty, $count: expr, $block: expr) => {
9        pub type $name = AsynchronousFIFO<$kind, { clog2($count) }, { clog2($count) + 1 }, $block>;
10    };
11}
12
13#[derive(LogicBlock, Default)]
14pub struct AsynchronousFIFO<D: Synth, const N: usize, const NP1: usize, const BLOCK_SIZE: u32> {
15    // Read interface
16    pub read: Signal<In, Bit>,
17    pub data_out: Signal<Out, D>,
18    pub empty: Signal<Out, Bit>,
19    pub almost_empty: Signal<Out, Bit>,
20    pub underflow: Signal<Out, Bit>,
21    pub read_clock: Signal<In, Clock>,
22    pub read_fill: Signal<Out, Bits<NP1>>,
23    // Write interface
24    pub write: Signal<In, Bit>,
25    pub data_in: Signal<In, D>,
26    pub full: Signal<Out, Bit>,
27    pub almost_full: Signal<Out, Bit>,
28    pub overflow: Signal<Out, Bit>,
29    pub write_clock: Signal<In, Clock>,
30    pub write_fill: Signal<Out, Bits<NP1>>,
31    // Internal RAM
32    ram: RAM<D, N>,
33    // Read Logic
34    read_logic: FIFOReadLogic<D, N, NP1, BLOCK_SIZE>,
35    // write logic
36    write_logic: FIFOWriteLogic<D, N, NP1, BLOCK_SIZE>,
37    // Synchronize the write pointer to the read side
38    write_to_read: VectorSynchronizer<Bits<NP1>>,
39    // Synchronize the read pointer to the write side
40    read_to_write: VectorSynchronizer<Bits<NP1>>,
41}
42
43impl<D: Synth, const N: usize, const NP1: usize, const BLOCK_SIZE: u32> Logic
44    for AsynchronousFIFO<D, N, NP1, BLOCK_SIZE>
45{
46    #[hdl_gen]
47    fn update(&mut self) {
48        // Connect up the read interface
49        self.read_logic.clock.next = self.read_clock.val();
50        self.read_logic.read.next = self.read.val();
51        self.empty.next = self.read_logic.empty.val();
52        self.almost_empty.next = self.read_logic.almost_empty.val();
53        self.data_out.next = self.read_logic.data_out.val();
54        self.underflow.next = self.read_logic.underflow.val();
55        // Connect up the write interface
56        self.write_logic.clock.next = self.write_clock.val();
57        self.overflow.next = self.write_logic.overflow.val();
58        self.almost_full.next = self.write_logic.almost_full.val();
59        self.full.next = self.write_logic.full.val();
60        self.write_logic.write.next = self.write.val();
61        self.write_logic.data_in.next = self.data_in.val();
62        // Connect the RAM to the two blocks
63        self.ram.write_clock.next = self.write_logic.ram_write_clock.val();
64        self.ram.write_enable.next = self.write_logic.ram_write_enable.val();
65        self.ram.write_address.next = self.write_logic.ram_write_address.val();
66        self.ram.write_data.next = self.write_logic.ram_write_data.val();
67        self.ram.read_clock.next = self.read_logic.ram_read_clock.val();
68        self.ram.read_address.next = self.read_logic.ram_read_address.val();
69        self.read_logic.ram_read_data.next = self.ram.read_data.val();
70        // Connect the read block --> write block via a synchronizer
71        self.read_to_write.clock_in.next = self.read_clock.val();
72        self.read_to_write.clock_out.next = self.write_clock.val();
73        self.read_to_write.sig_in.next = self.read_logic.read_address_out.val();
74        self.write_logic.read_address.next = self.read_to_write.sig_out.val();
75        self.read_to_write.send.next = !self.read_to_write.busy.val();
76        // Connect the write block --> read block via a synchronizer
77        self.write_to_read.clock_in.next = self.write_clock.val();
78        self.write_to_read.clock_out.next = self.read_clock.val();
79        self.write_to_read.sig_in.next = self.write_logic.write_address_delayed.val();
80        self.read_logic.write_address_delayed.next = self.write_to_read.sig_out.val();
81        self.write_to_read.send.next = !self.write_to_read.busy.val();
82        // Provide the fill level estimates
83        self.write_fill.next = self.write_logic.fill_level.val();
84        self.read_fill.next = self.read_logic.fill_level.val();
85    }
86}
87
88#[test]
89fn component_async_fifo_is_synthesizable() {
90    declare_async_fifo!(TFifo, Bits<8>, 16, 1);
91    let mut dev: TFifo = Default::default();
92    dev.connect_all();
93    yosys_validate("async_fifo", &generate_verilog(&dev)).unwrap();
94}