rust_hdl_widgets/sdram/
burst_controller.rs

1use crate::dff::DFF;
2use crate::dff_setup;
3use crate::prelude::DelayLine;
4use crate::sdram::cmd::{SDRAMCommand, SDRAMCommandEncoder};
5use crate::sdram::{OutputBuffer, SDRAMDriver};
6use rust_hdl_core::prelude::*;
7
8use super::timings::MemoryTimings;
9
10// Controller states...
11#[derive(Copy, Clone, PartialEq, Debug, LogicState)]
12enum State {
13    Boot,
14    Precharge1,
15    AutoRefresh1,
16    AutoRefresh2,
17    LoadModeRegister,
18    Idle,
19    IssueRead,
20    IssueWrite,
21    Refresh,
22    ReadActivate,
23    ReadCycle,
24    WriteActivate,
25    WritePrep,
26    WriteCycle,
27    Recovery,
28    Precharge,
29    Error,
30}
31
32// Limits - can only run a 4 bank SDRAM.  If you need a different
33// number of banks, you will need to modify it.
34//
35// Constants:
36//  R - Row bits in the address
37//  C - Col bits in the address
38//  D - Data bus width
39//  L - Burst size (< 32)
40#[derive(LogicBlock)]
41pub struct SDRAMBurstController<const R: usize, const C: usize, const L: u32, const D: usize> {
42    pub clock: Signal<In, Clock>,
43    pub sdram: SDRAMDriver<D>,
44    // The input interface does not allow flow control.  You must hook this up to a
45    // FIFO on the consumer side to send data or risk data loss.  It is your
46    // responsibility to ensure that you can provide L values on the input interface
47    // on demand when you issue the WRITE command.
48    pub data_in: Signal<In, Bits<D>>,
49    pub data_strobe: Signal<Out, Bit>,
50    // The output interface does not allow flow control.  You must hook this up to a
51    // FIFO on the consumer side to receive data or risk data loss.  It is your
52    // responsibility to ensure that you can accept L values on the output interface
53    // when you issue the READ command.
54    pub data_out: Signal<Out, Bits<D>>,
55    pub data_valid: Signal<Out, Bit>,
56    // Command interface
57    pub write_not_read: Signal<In, Bit>,
58    pub cmd_strobe: Signal<In, Bit>,
59    pub cmd_address: Signal<In, Bits<32>>,
60    pub busy: Signal<Out, Bit>,
61    pub error: Signal<Out, Bit>,
62    cmd: Signal<Local, SDRAMCommand>,
63    encode: SDRAMCommandEncoder,
64    boot_delay: Constant<Bits<16>>,
65    t_rp: Constant<Bits<16>>,
66    t_rfc: Constant<Bits<16>>,
67    t_refresh_max: Constant<Bits<16>>,
68    t_rcd: Constant<Bits<16>>,
69    t_wr: Constant<Bits<16>>,
70    max_transfer_size: Constant<Bits<6>>,
71    mode_register: Constant<Bits<13>>,
72    cas_delay: Constant<Bits<3>>,
73    state: DFF<State>,
74    reg_address: DFF<Bits<32>>,
75    reg_cmd_address: DFF<Bits<32>>,
76    delay_counter: DFF<Bits<16>>,
77    refresh_counter: DFF<Bits<16>>,
78    transfer_counter: DFF<Bits<6>>,
79    read_valid: DelayLine<Bit, 8, 3>,
80    addr_bank: Signal<Local, Bits<2>>,
81    addr_row: Signal<Local, Bits<13>>,
82    addr_col: Signal<Local, Bits<13>>,
83    write_pending: DFF<Bit>,
84    read_pending: DFF<Bit>,
85    refresh_needed: DFF<Bit>,
86    row_bits: Constant<Bits<32>>,
87    col_bits: Constant<Bits<32>>,
88    // These are used to decouple the timing of the controller from the
89    // outside world
90    data_in_reg: DFF<Bits<D>>,
91    data_strobe_reg: DFF<Bit>,
92    data_out_reg: DFF<Bits<D>>,
93}
94
95impl<const R: usize, const C: usize, const L: u32, const D: usize>
96    SDRAMBurstController<R, C, L, D>
97{
98    pub fn new(
99        cas_delay: u32,
100        timings: MemoryTimings,
101        buffer: OutputBuffer,
102    ) -> SDRAMBurstController<R, C, L, D> {
103        assert!(L < 64);
104        assert_eq!((1 << C) % L, 0);
105        // mode register definitions
106        // A2:A0 are the burst length, this design does not use burst transfers
107        // so A2:A0 are 0
108        // A3 is 0 because of burst type sequential
109        // A6:A4 define the CAS latency in clocks.  We assume 3 clocks of latency.
110        // The rest of the bits should all be zero
111        // So the mode register is basically just CAS << 4
112        let mode_register = cas_delay << 4;
113        Self {
114            clock: Default::default(),
115            sdram: Default::default(),
116            cmd: Default::default(),
117            data_in: Default::default(),
118            data_strobe: Default::default(),
119            write_not_read: Default::default(),
120            cmd_strobe: Default::default(),
121            cmd_address: Default::default(),
122            busy: Default::default(),
123            data_out: Default::default(),
124            data_valid: Default::default(),
125            error: Default::default(),
126            boot_delay: Constant::new((timings.t_boot() + 50).to_bits()),
127            t_rp: Constant::new((timings.t_rp()).to_bits()),
128            t_rfc: Constant::new((timings.t_rfc()).to_bits()),
129            t_refresh_max: Constant::new((timings.t_refresh_max() * 7 / 10).to_bits()),
130            t_rcd: Constant::new((timings.t_rcd()).to_bits()),
131            t_wr: Constant::new((timings.t_wr()).to_bits()),
132            max_transfer_size: Constant::new(L.to_bits()),
133            mode_register: Constant::new(mode_register.to_bits()),
134            /*
135             * For a registered buffer, we need to add 2 cycles to the cas delay
136             * - we add 1 on the send side because we add 1 on the send side and
137             *   1 on the receive side
138             */
139            cas_delay: Constant::new(
140                match buffer {
141                    OutputBuffer::Wired => cas_delay + 1,
142                    OutputBuffer::DelayOne => cas_delay + 2,
143                    OutputBuffer::DelayTwo => cas_delay + 3,
144                }
145                .to_bits(),
146            ),
147            state: Default::default(),
148            reg_address: Default::default(),
149            reg_cmd_address: Default::default(),
150            delay_counter: Default::default(),
151            refresh_counter: Default::default(),
152            transfer_counter: Default::default(),
153            read_valid: Default::default(),
154            addr_bank: Default::default(),
155            addr_row: Default::default(),
156            addr_col: Default::default(),
157            write_pending: Default::default(),
158            row_bits: Constant::new(R.to_bits()),
159            col_bits: Constant::new(C.to_bits()),
160            data_in_reg: Default::default(),
161            read_pending: Default::default(),
162            encode: Default::default(),
163            refresh_needed: Default::default(),
164            data_out_reg: Default::default(),
165            data_strobe_reg: Default::default(),
166        }
167    }
168}
169
170impl<const R: usize, const C: usize, const L: u32, const D: usize> Logic
171    for SDRAMBurstController<R, C, L, D>
172{
173    #[hdl_gen]
174    fn update(&mut self) {
175        // Clock the internal logic
176        dff_setup!(
177            self,
178            clock,
179            state,
180            reg_address,
181            reg_cmd_address,
182            delay_counter,
183            refresh_counter,
184            transfer_counter,
185            write_pending,
186            read_pending,
187            refresh_needed,
188            data_in_reg,
189            data_strobe_reg,
190            data_out_reg
191        );
192        clock!(self, clock, read_valid);
193        // Latch prevention
194        self.delay_counter.d.next = self.delay_counter.q.val() + 1;
195        self.refresh_counter.d.next = self.refresh_counter.q.val() + 1;
196        self.cmd.next = SDRAMCommand::NOP;
197        self.sdram.address.next = 0.into();
198        self.sdram.bank.next = 0.into();
199        // Insert registers to decouple the DRAM bus from the external bus
200        self.data_out.next = self.data_out_reg.q.val();
201        self.data_out_reg.d.next = self.sdram.read_data.val();
202        self.data_valid.next = self.read_valid.data_out.val();
203        self.sdram.write_enable.next = false;
204        // Connect the DRAM to the staging register to decouple timing
205        self.sdram.write_data.next = self.data_in_reg.q.val();
206        self.data_strobe.next = self.data_strobe_reg.q.val();
207        self.read_valid.data_in.next = false;
208        self.read_valid.delay.next = self.cas_delay.val();
209        // Calculate the read and write addresses
210        self.addr_col.next = bit_cast::<13, C>(self.reg_address.q.val().get_bits::<C>(0));
211        self.addr_row.next = bit_cast::<13, R>(
212            self.reg_address
213                .q
214                .val()
215                .get_bits::<R>(self.col_bits.val().index()),
216        );
217        self.addr_bank.next = self
218            .reg_address
219            .q
220            .val()
221            .get_bits::<2>(self.col_bits.val().index() + self.row_bits.val().index());
222        self.transfer_counter.d.next = self.transfer_counter.q.val();
223        // State machine
224        self.busy.next = (self.state.q.val() != State::Idle)
225            | self.write_pending.q.val()
226            | self.read_pending.q.val();
227        self.data_strobe_reg.d.next = false;
228        match self.state.q.val() {
229            State::Boot => {
230                if self.delay_counter.q.val() == self.boot_delay.val() {
231                    self.state.d.next = State::Precharge1;
232                    self.cmd.next = SDRAMCommand::Precharge;
233                    self.sdram.address.next = 0xFFF.into();
234                    self.delay_counter.d.next = 0.into();
235                }
236            }
237            State::Precharge1 => {
238                if self.delay_counter.q.val() == self.t_rp.val() {
239                    self.state.d.next = State::AutoRefresh1;
240                    self.cmd.next = SDRAMCommand::AutoRefresh;
241                    self.delay_counter.d.next = 0.into();
242                }
243            }
244            State::AutoRefresh1 => {
245                if self.delay_counter.q.val() == self.t_rfc.val() {
246                    self.state.d.next = State::AutoRefresh2;
247                    self.cmd.next = SDRAMCommand::AutoRefresh;
248                    self.delay_counter.d.next = 0.into();
249                }
250            }
251            State::AutoRefresh2 => {
252                if self.delay_counter.q.val() == self.t_rfc.val() {
253                    self.state.d.next = State::LoadModeRegister;
254                    self.cmd.next = SDRAMCommand::LoadModeRegister;
255                    self.sdram.address.next = self.mode_register.val();
256                    self.delay_counter.d.next = 0.into();
257                }
258            }
259            State::LoadModeRegister => {
260                if self.delay_counter.q.val() == 4 {
261                    self.state.d.next = State::Idle;
262                }
263            }
264            State::Idle => {
265                self.delay_counter.d.next = 0.into();
266                self.transfer_counter.d.next = 0.into();
267                if self.refresh_needed.q.val() {
268                    // Refresh takes the highest priority
269                    self.cmd.next = SDRAMCommand::AutoRefresh;
270                    self.state.d.next = State::Refresh;
271                    self.refresh_counter.d.next = 0.into();
272                    self.refresh_needed.d.next = false;
273                } else if self.read_pending.q.val() {
274                    self.reg_address.d.next = self.reg_cmd_address.q.val();
275                    self.state.d.next = State::IssueRead;
276                } else if self.write_pending.q.val() {
277                    self.reg_address.d.next = self.reg_cmd_address.q.val();
278                    self.state.d.next = State::IssueWrite;
279                }
280            }
281            State::IssueRead => {
282                self.cmd.next = SDRAMCommand::Active;
283                self.sdram.bank.next = self.addr_bank.val();
284                self.sdram.address.next = self.addr_row.val();
285                self.state.d.next = State::ReadActivate;
286                self.read_pending.d.next = false;
287            }
288            State::IssueWrite => {
289                self.cmd.next = SDRAMCommand::Active;
290                self.sdram.bank.next = self.addr_bank.val();
291                self.sdram.address.next = self.addr_row.val();
292                self.state.d.next = State::WriteActivate;
293                self.write_pending.d.next = false;
294                self.sdram.write_enable.next = true;
295            }
296            State::Refresh => {
297                if self.delay_counter.q.val() == self.t_rfc.val() {
298                    self.state.d.next = State::Idle;
299                }
300            }
301            State::ReadActivate => {
302                if self.delay_counter.q.val() == self.t_rcd.val() {
303                    self.state.d.next = State::ReadCycle;
304                    self.transfer_counter.d.next = 0.into();
305                }
306            }
307            State::WriteActivate => {
308                self.sdram.write_enable.next = true;
309                if self.delay_counter.q.val() == self.t_rcd.val() {
310                    self.state.d.next = State::WritePrep;
311                    self.transfer_counter.d.next = 0.into();
312                    self.data_strobe_reg.d.next = true;
313                }
314            }
315            State::WritePrep => {
316                self.state.d.next = State::WriteCycle;
317                self.data_strobe_reg.d.next = true;
318                self.sdram.write_enable.next = true;
319            }
320            State::WriteCycle => {
321                self.sdram.write_enable.next = true;
322                if self.transfer_counter.q.val() < self.max_transfer_size.val() {
323                    self.sdram.bank.next = self.addr_bank.val();
324                    self.sdram.address.next = self.addr_col.val();
325                    self.cmd.next = SDRAMCommand::Write;
326                    self.transfer_counter.d.next = self.transfer_counter.q.val() + 1;
327                    self.reg_address.d.next = self.reg_address.q.val() + 1;
328                } else {
329                    self.delay_counter.d.next = 0.into();
330                    self.state.d.next = State::Recovery;
331                }
332                if self.transfer_counter.q.val() < self.max_transfer_size.val() - 2 {
333                    self.data_strobe_reg.d.next = true;
334                }
335            }
336            State::Recovery => {
337                self.sdram.write_enable.next = true;
338                if self.delay_counter.q.val() == self.t_wr.val() {
339                    self.cmd.next = SDRAMCommand::Precharge;
340                    // 13 bits is 0001_1111_1111_1111 0x1FFF or
341                    self.sdram.address.next = 0x1FFF.into();
342                    self.delay_counter.d.next = 0.into();
343                    self.state.d.next = State::Precharge;
344                }
345            }
346            State::Precharge => {
347                if self.delay_counter.q.val() == self.t_rp.val() {
348                    self.state.d.next = State::Idle;
349                }
350            }
351            State::ReadCycle => {
352                if self.transfer_counter.q.val() < self.max_transfer_size.val() {
353                    self.sdram.bank.next = self.addr_bank.val();
354                    self.sdram.address.next = self.addr_col.val();
355                    self.cmd.next = SDRAMCommand::Read;
356                    self.transfer_counter.d.next = self.transfer_counter.q.val() + 1;
357                    self.read_valid.data_in.next = true;
358                    self.reg_address.d.next = self.reg_address.q.val() + 1;
359                } else {
360                    self.delay_counter.d.next = 0.into();
361                    self.state.d.next = State::Recovery;
362                }
363            }
364            State::Error => {}
365            _ => {
366                self.state.d.next = State::Boot;
367            }
368        }
369        self.error.next = self.state.q.val() == State::Error;
370        // Handle the input command latching
371        if self.cmd_strobe.val() & !self.read_pending.q.val() & !self.write_pending.q.val() {
372            self.reg_cmd_address.d.next = self.cmd_address.val();
373            if self.write_not_read.val() {
374                self.write_pending.d.next = true;
375            } else {
376                self.read_pending.d.next = true;
377            }
378        }
379        if self.refresh_counter.q.val() >= self.t_refresh_max.val() {
380            self.refresh_needed.d.next = true;
381        }
382        // Connect up the command encoder
383        self.sdram.cs_not.next = self.encode.cs_not.val();
384        self.sdram.cas_not.next = self.encode.cas_not.val();
385        self.sdram.ras_not.next = self.encode.ras_not.val();
386        self.sdram.we_not.next = self.encode.we_not.val();
387        self.encode.cmd.next = self.cmd.val();
388        self.sdram.clk.next = self.clock.val();
389        self.data_in_reg.d.next = self.data_in.val();
390    }
391}