rust_hdl_widgets/sdram/
fifo_sdram.rs

1use crate::{dff::DFF, dff_setup, fifo::async_fifo::AsynchronousFIFO, sdram::SDRAMDriver};
2use rust_hdl_core::prelude::*;
3
4use super::{burst_controller::SDRAMBurstController, timings::MemoryTimings, OutputBuffer};
5
6#[derive(Copy, Clone, Debug, PartialEq, LogicState)]
7enum State {
8    Idle,
9    Read,
10    Write,
11    Busy,
12}
13
14#[derive(LogicBlock)]
15pub struct SDRAMFIFOController<
16    const R: usize, // Number of rows in the SDRAM
17    const C: usize, // Number of columns in the SDRAM
18    const L: u32,   // Line size (multiple of the SDRAM interface width) - rem(2^C, L) = 0
19    const D: usize, // Number of bits in the SDRAM interface width
20    const A: usize, // Number of address bits in the SDRAM (should be C + R + B)
21> {
22    pub clock: Signal<In, Clock>,
23    pub sdram: SDRAMDriver<D>,
24    pub ram_clock: Signal<In, Clock>,
25    // FIFO interface
26    pub data_in: Signal<In, Bits<D>>,
27    pub write: Signal<In, Bit>,
28    pub full: Signal<Out, Bit>,
29    pub data_out: Signal<Out, Bits<D>>,
30    pub read: Signal<In, Bit>,
31    pub empty: Signal<Out, Bit>,
32    pub overflow: Signal<Out, Bit>,
33    pub underflow: Signal<Out, Bit>,
34    pub status: Signal<Out, Bits<8>>,
35    controller: SDRAMBurstController<R, C, L, D>,
36    fp: AsynchronousFIFO<Bits<D>, 5, 6, L>,
37    bp: AsynchronousFIFO<Bits<D>, 5, 6, L>,
38    can_write: DFF<Bit>,
39    can_read: DFF<Bit>,
40    read_pointer: DFF<Bits<A>>,
41    write_pointer: DFF<Bits<A>>,
42    dram_is_empty: DFF<Bit>,
43    dram_is_full: DFF<Bit>,
44    state: DFF<State>,
45    line_to_word_ratio: Constant<Bits<A>>,
46    fill: DFF<Bits<A>>,
47    fill_0: Constant<Bits<A>>,
48    fill_1: Constant<Bits<A>>,
49    fill_2: Constant<Bits<A>>,
50    fill_3: Constant<Bits<A>>,
51}
52
53impl<const R: usize, const C: usize, const L: u32, const D: usize, const A: usize>
54    SDRAMFIFOController<R, C, L, D, A>
55{
56    pub fn new(cas_delay: u32, timings: MemoryTimings, buffer: OutputBuffer) -> Self {
57        assert_eq!((1 << C) % L, 0);
58        assert_eq!(A, C + R + 2);
59        assert!(L < 32);
60        let banks = 4; // Assume 4 banks
61                       // Number of total bits
62        let bit_count = R * C * D * banks;
63        // The number of bits in each entry
64        let entry_bits = L as usize * D;
65        let max_entries = bit_count / entry_bits;
66        // So the number of elements we want to mark with each LED is N/5
67        let entries_per_led = max_entries / 5;
68        Self {
69            clock: Default::default(),
70            sdram: Default::default(),
71            ram_clock: Default::default(),
72            data_in: Default::default(),
73            write: Default::default(),
74            full: Default::default(),
75            data_out: Default::default(),
76            read: Default::default(),
77            empty: Default::default(),
78            overflow: Default::default(),
79            underflow: Default::default(),
80            status: Default::default(),
81            controller: SDRAMBurstController::new(cas_delay, timings, buffer),
82            fp: Default::default(),
83            bp: Default::default(),
84            can_write: Default::default(),
85            can_read: Default::default(),
86            read_pointer: Default::default(),
87            write_pointer: Default::default(),
88            dram_is_empty: Default::default(),
89            dram_is_full: Default::default(),
90            state: Default::default(),
91            line_to_word_ratio: Constant::new(L.to_bits()),
92            fill: Default::default(),
93            fill_0: Constant::new((entries_per_led).to_bits()),
94            fill_1: Constant::new((entries_per_led * 2).to_bits()),
95            fill_2: Constant::new((entries_per_led * 3).to_bits()),
96            fill_3: Constant::new((entries_per_led * 4).to_bits()),
97        }
98    }
99}
100
101impl<const R: usize, const C: usize, const L: u32, const D: usize, const A: usize> Logic
102    for SDRAMFIFOController<R, C, L, D, A>
103{
104    #[hdl_gen]
105    fn update(&mut self) {
106        clock!(self, ram_clock, controller);
107        SDRAMDriver::<D>::link(&mut self.sdram, &mut self.controller.sdram);
108        dff_setup!(
109            self,
110            ram_clock,
111            read_pointer,
112            write_pointer,
113            dram_is_empty,
114            dram_is_full,
115            can_read,
116            can_write,
117            state,
118            fill
119        );
120        // The FP write clock is external, but the read clock is the DRAM clock
121        self.fp.write_clock.next = self.clock.val();
122        self.fp.read_clock.next = self.ram_clock.val();
123        // The BP write clock is DRAM, the read clock is external
124        self.bp.write_clock.next = self.ram_clock.val();
125        self.bp.read_clock.next = self.clock.val();
126        // Connect the write interface to the FP fifo
127        self.fp.data_in.next = self.data_in.val();
128        self.fp.write.next = self.write.val();
129        self.full.next = self.fp.full.val();
130        self.overflow.next = self.fp.overflow.val();
131        // Connect the read interface to the BP fifo
132        self.data_out.next = self.bp.data_out.val();
133        self.bp.read.next = self.read.val();
134        self.empty.next = self.bp.empty.val();
135        self.underflow.next = self.bp.underflow.val();
136        // The almost empty/full signals in the async fifos are in the
137        // DRAM clock domain, so we need to synchronize them back
138        // Connect the read interface of the FP fifo to the DRAM controller
139        self.controller.data_in.next = self.fp.data_out.val();
140        self.fp.read.next = self.controller.data_strobe.val();
141        // Connect the write interface of the DRAM controller to the BP fifo
142        self.bp.data_in.next = self.controller.data_out.val();
143        self.bp.write.next = self.controller.data_valid.val();
144        // That takes care of the outside facing part of the fifo...
145        //  Now the internals.
146        self.dram_is_empty.d.next = self.read_pointer.q.val() == self.write_pointer.q.val();
147        self.dram_is_full.d.next = (self.write_pointer.q.val() + self.line_to_word_ratio.val())
148            == self.read_pointer.q.val();
149        self.can_write.d.next = !self.dram_is_full.q.val() & !self.fp.almost_empty.val();
150        self.can_read.d.next = !self.dram_is_empty.q.val() & !self.bp.almost_full.val();
151        self.controller.cmd_address.next = 0.into();
152        self.controller.write_not_read.next = false;
153        self.controller.cmd_strobe.next = false;
154        self.fill.clock.next = self.ram_clock.val();
155        self.fill.d.next = self.fill.q.val();
156        match self.state.q.val() {
157            State::Idle => {
158                if !self.controller.busy.val() {
159                    if self.can_read.q.val() {
160                        self.state.d.next = State::Read;
161                        self.controller.cmd_address.next =
162                            bit_cast::<32, A>(self.read_pointer.q.val());
163                        self.controller.write_not_read.next = false;
164                        self.controller.cmd_strobe.next = true;
165                    } else if self.can_write.q.val() {
166                        self.state.d.next = State::Write;
167                        self.controller.cmd_address.next =
168                            bit_cast::<32, A>(self.write_pointer.q.val());
169                        self.controller.write_not_read.next = true;
170                        self.controller.cmd_strobe.next = true;
171                    }
172                }
173            }
174            State::Read => {
175                self.read_pointer.d.next =
176                    self.read_pointer.q.val() + self.line_to_word_ratio.val();
177                self.fill.d.next = self.fill.q.val() - 1;
178                self.state.d.next = State::Busy;
179            }
180            State::Write => {
181                self.write_pointer.d.next =
182                    self.write_pointer.q.val() + self.line_to_word_ratio.val();
183                self.fill.d.next = self.fill.q.val() + 1;
184                self.state.d.next = State::Busy;
185            }
186            State::Busy => {
187                if !self.controller.busy.val() {
188                    self.state.d.next = State::Idle;
189                }
190            }
191            _ => {
192                self.state.d.next = State::Idle;
193            }
194        }
195        self.status.next = 0.into();
196        if self.fill.q.val() > self.fill_0.val() {
197            self.status.next = self.status.val() | 1;
198        }
199        if self.fill.q.val() > self.fill_1.val() {
200            self.status.next = self.status.val() | 2;
201        }
202        if self.fill.q.val() > self.fill_2.val() {
203            self.status.next = self.status.val() | 4;
204        }
205        if self.fill.q.val() > self.fill_3.val() {
206            self.status.next = self.status.val() | 8;
207        }
208        if self.underflow.val() | self.overflow.val() {
209            self.status.next = self.status.val() | 16;
210        }
211        if self.dram_is_empty.q.val() {
212            self.status.next = self.status.val() | 32;
213        }
214        if self.fp.empty.val() {
215            self.status.next = self.status.val() | 64;
216        }
217        if self.bp.full.val() {
218            self.status.next = self.status.val() | 128;
219        }
220    }
221}