rust_hdl_sim/sdr_sdram/
chip.rs

1use crate::sdr_sdram::bank::MemoryBank;
2use rust_hdl_core::prelude::*;
3use rust_hdl_widgets::{
4    prelude::*,
5    sdram::{cmd::SDRAMCommandDecoder, SDRAMDevice},
6};
7
8#[derive(Copy, Clone, PartialEq, Debug, LogicState)]
9enum MasterState {
10    Boot,
11    WaitPrecharge,
12    Precharge,
13    WaitAutorefresh,
14    LoadModeRegister,
15    Ready,
16    Error,
17}
18
19// Clock enable, and DQM are ignored.
20#[derive(LogicBlock)]
21pub struct SDRAMSimulator<
22    const R: usize, // Number of rows
23    const C: usize, // Number of columns
24    const A: usize, // A = R + C
25    const D: usize, // Bits per word
26> {
27    pub sdram: SDRAMDevice<D>,
28    pub test_error: Signal<Out, Bit>,
29    pub test_ready: Signal<Out, Bit>,
30    decode: SDRAMCommandDecoder,
31    clock: Signal<Local, Clock>,
32    cmd: Signal<Local, SDRAMCommand>,
33    state: DFF<MasterState>,
34    counter: DFF<Bits<32>>,
35    auto_refresh_init_counter: DFF<Bits<32>>,
36    write_burst_mode: DFF<Bit>,
37    cas_latency: DFF<Bits<3>>,
38    burst_type: DFF<Bit>,
39    burst_len: DFF<Bits<3>>,
40    op_mode: DFF<Bits<2>>,
41    banks: [MemoryBank<R, C, A, D>; 4],
42    // Timings
43    // Number of clocks to delay for boot initialization
44    boot_delay: Constant<Bits<32>>,
45    t_rp: Constant<Bits<32>>,
46    load_mode_timing: Constant<Bits<32>>,
47    t_rrd: Constant<Bits<32>>,
48    banks_busy: Signal<Local, Bit>,
49}
50
51impl<const R: usize, const C: usize, const A: usize, const D: usize> Logic
52    for SDRAMSimulator<R, C, A, D>
53{
54    #[hdl_gen]
55    fn update(&mut self) {
56        // Clock logic
57        self.clock.next = self.sdram.clk.val();
58        dff_setup!(
59            self,
60            clock,
61            state,
62            counter,
63            auto_refresh_init_counter,
64            write_burst_mode,
65            cas_latency,
66            burst_type,
67            burst_len,
68            op_mode
69        );
70        // Connect the command decoder to the bus
71        self.decode.we_not.next = self.sdram.we_not.val();
72        self.decode.cas_not.next = self.sdram.cas_not.val();
73        self.decode.ras_not.next = self.sdram.ras_not.val();
74        self.decode.cs_not.next = self.sdram.cs_not.val();
75        self.cmd.next = self.decode.cmd.val();
76        self.test_error.next = false;
77        self.test_ready.next = false;
78        // Connect up the banks to the I/O buffer
79        self.sdram.read_data.next = 0.into();
80        for i in 0..4 {
81            self.banks[i].clock.next = self.clock.val();
82            if self.sdram.write_enable.val() {
83                self.banks[i].write_data.next = self.sdram.write_data.val();
84            } else {
85                self.banks[i].write_data.next = 0.into();
86            }
87            if self.banks[i].read_valid.val() {
88                self.sdram.read_data.next = self.banks[i].read_data.val();
89            }
90            self.banks[i].address.next = self.sdram.address.val();
91            self.banks[i].cmd.next = self.cmd.val();
92            self.banks[i].write_burst.next = self.write_burst_mode.q.val();
93            self.banks[i].burst_len.next = 1.into();
94            match self.burst_len.q.val().index() {
95                0 => self.banks[i].burst_len.next = 1.into(),
96                1 => self.banks[i].burst_len.next = 2.into(),
97                2 => self.banks[i].burst_len.next = 4.into(),
98                3 => self.banks[i].burst_len.next = 8.into(),
99                _ => self.state.d.next = MasterState::Error,
100            }
101            self.banks[i].cas_delay.next = 2.into();
102            match self.cas_latency.q.val().index() {
103                0 => self.banks[i].cas_delay.next = 0.into(),
104                2 => self.banks[i].cas_delay.next = 2.into(),
105                3 => self.banks[i].cas_delay.next = 3.into(),
106                _ => self.state.d.next = MasterState::Error,
107            }
108            if self.sdram.bank.val().index() == i {
109                self.banks[i].select.next = true;
110            } else {
111                self.banks[i].select.next = false;
112            }
113            if self.cmd.val() == SDRAMCommand::AutoRefresh {
114                self.banks[i].select.next = true;
115            }
116            if (self.cmd.val() == SDRAMCommand::Precharge) & self.sdram.address.val().get_bit(10) {
117                self.banks[i].select.next = true;
118            }
119        }
120        self.banks_busy.next = self.banks[0].busy.val()
121            | self.banks[1].busy.val()
122            | self.banks[2].busy.val()
123            | self.banks[3].busy.val();
124        match self.state.q.val() {
125            MasterState::Boot => {
126                if (self.cmd.val() != SDRAMCommand::NOP) & (self.counter.q.val().any()) {
127                    // self.state.d.next = MasterState::Error;
128                    // Although the spec says you should not do this, it is unavoidable with
129                    // the Lattice FPGA.
130                }
131                self.counter.d.next = self.counter.q.val() + 1;
132                if self.counter.q.val() == self.boot_delay.val() {
133                    self.state.d.next = MasterState::WaitPrecharge;
134                }
135            }
136            MasterState::WaitPrecharge => {
137                match self.cmd.val() {
138                    SDRAMCommand::NOP => {}
139                    SDRAMCommand::Precharge => {
140                        // make sure the ALL bit is set
141                        if self.sdram.address.val().get_bit(10) != true {
142                            self.state.d.next = MasterState::Error;
143                        } else {
144                            self.counter.d.next = 0.into();
145                            self.state.d.next = MasterState::Precharge;
146                        }
147                    }
148                    _ => {
149                        self.state.d.next = MasterState::Error;
150                    }
151                }
152            }
153            MasterState::Precharge => {
154                self.counter.d.next = self.counter.q.val() + 1;
155                if self.counter.q.val() == self.t_rp.val() {
156                    self.state.d.next = MasterState::WaitAutorefresh;
157                }
158                if self.cmd.val() != SDRAMCommand::NOP {
159                    self.state.d.next = MasterState::Error;
160                }
161            }
162            MasterState::WaitAutorefresh => match self.cmd.val() {
163                SDRAMCommand::NOP => {}
164                SDRAMCommand::AutoRefresh => {
165                    if self.banks_busy.val() {
166                        self.state.d.next = MasterState::Error;
167                    } else {
168                        self.auto_refresh_init_counter.d.next =
169                            self.auto_refresh_init_counter.q.val() + 1;
170                    }
171                }
172                SDRAMCommand::LoadModeRegister => {
173                    if self.auto_refresh_init_counter.q.val() < 2 {
174                        self.state.d.next = MasterState::Error;
175                    } else {
176                        self.counter.d.next = 0.into();
177                        self.state.d.next = MasterState::LoadModeRegister;
178                        self.burst_len.d.next = self.sdram.address.val().get_bits::<3>(0);
179                        self.burst_type.d.next = self.sdram.address.val().get_bit(3);
180                        self.cas_latency.d.next = self.sdram.address.val().get_bits::<3>(4);
181                        self.op_mode.d.next = self.sdram.address.val().get_bits::<2>(7);
182                        self.write_burst_mode.d.next = self.sdram.address.val().get_bit(9);
183                        if self.sdram.address.val().get_bits::<2>(10) != 0 {
184                            self.state.d.next = MasterState::Error;
185                        }
186                    }
187                }
188                _ => {
189                    self.state.d.next = MasterState::Error;
190                }
191            },
192            MasterState::LoadModeRegister => {
193                self.counter.d.next = self.counter.q.val() + 1;
194                if self.counter.q.val() == self.load_mode_timing.val() {
195                    self.state.d.next = MasterState::Ready;
196                }
197                if self.cmd.val() != SDRAMCommand::NOP {
198                    self.state.d.next = MasterState::Error;
199                }
200                if self.burst_len.q.val() > 3 {
201                    self.state.d.next = MasterState::Error;
202                }
203                if (self.cas_latency.q.val() > 3) | (self.cas_latency.q.val() == 0) {
204                    self.state.d.next = MasterState::Error;
205                }
206                if self.op_mode.q.val() != 0 {
207                    self.state.d.next = MasterState::Error;
208                }
209            }
210            MasterState::Error => {
211                self.test_error.next = true;
212            }
213            MasterState::Ready => {
214                self.test_ready.next = true;
215            }
216            _ => {
217                self.state.d.next = MasterState::Boot;
218            }
219        }
220        // Any banks that are in error mean the chip is in error.
221        for i in 0..4 {
222            if self.banks[i].error.val() {
223                self.state.d.next = MasterState::Error;
224            }
225        }
226    }
227}
228
229impl<const R: usize, const C: usize, const A: usize, const D: usize> SDRAMSimulator<R, C, A, D> {
230    pub fn new(timings: MemoryTimings) -> Self {
231        // Calculate the number of picoseconds per clock cycle
232        let boot_delay = timings.t_boot();
233        let precharge_delay = timings.t_rp() - 1;
234        let bank_bank_delay = timings.t_rrd() - 1;
235        Self {
236            clock: Default::default(),
237            cmd: Signal::default(),
238            sdram: Default::default(),
239            test_error: Default::default(),
240            test_ready: Default::default(),
241            state: Default::default(),
242            counter: Default::default(),
243            auto_refresh_init_counter: Default::default(),
244            write_burst_mode: Default::default(),
245            cas_latency: Default::default(),
246            burst_type: Default::default(),
247            burst_len: Default::default(),
248            op_mode: Default::default(),
249            banks: array_init::array_init(|_| MemoryBank::new(timings)),
250            boot_delay: Constant::new(boot_delay.to_bits()),
251            t_rp: Constant::new(precharge_delay.to_bits()),
252            t_rrd: Constant::new(bank_bank_delay.to_bits()),
253            load_mode_timing: Constant::new(
254                (timings.load_mode_command_timing_clocks - 1).to_bits(),
255            ),
256            banks_busy: Default::default(),
257            decode: Default::default(),
258        }
259    }
260}
261
262#[cfg(test)]
263fn mk_sdr_sim() -> SDRAMSimulator<5, 5, 10, 16> {
264    let mut uut = SDRAMSimulator::new(MemoryTimings::fast_boot_sim(125e6));
265    uut.sdram.link_connect_dest();
266    uut.connect_all();
267    uut
268}
269
270#[test]
271fn test_sdram_sim_synthesizes() {
272    let uut = mk_sdr_sim();
273    let vlog = generate_verilog(&uut);
274    yosys_validate("sdram", &vlog).unwrap();
275}
276
277#[macro_export]
278macro_rules! sdram_cmd {
279    ($uut: ident, $cmd: expr) => {
280        match $cmd {
281            SDRAMCommand::NOP => {
282                $uut.sdram.ras_not.next = true;
283                $uut.sdram.cas_not.next = true;
284                $uut.sdram.we_not.next = true;
285            }
286            SDRAMCommand::BurstTerminate => {
287                $uut.sdram.ras_not.next = true;
288                $uut.sdram.cas_not.next = true;
289                $uut.sdram.we_not.next = false;
290            }
291            SDRAMCommand::Read => {
292                $uut.sdram.ras_not.next = true;
293                $uut.sdram.cas_not.next = false;
294                $uut.sdram.we_not.next = true;
295            }
296            SDRAMCommand::Write => {
297                $uut.sdram.ras_not.next = true;
298                $uut.sdram.cas_not.next = false;
299                $uut.sdram.we_not.next = false;
300            }
301            SDRAMCommand::Active => {
302                $uut.sdram.ras_not.next = false;
303                $uut.sdram.cas_not.next = true;
304                $uut.sdram.we_not.next = true;
305            }
306            SDRAMCommand::Precharge => {
307                $uut.sdram.ras_not.next = false;
308                $uut.sdram.cas_not.next = true;
309                $uut.sdram.we_not.next = false;
310            }
311            SDRAMCommand::AutoRefresh => {
312                $uut.sdram.ras_not.next = false;
313                $uut.sdram.cas_not.next = false;
314                $uut.sdram.we_not.next = true;
315            }
316            SDRAMCommand::LoadModeRegister => {
317                $uut.sdram.ras_not.next = false;
318                $uut.sdram.cas_not.next = false;
319                $uut.sdram.we_not.next = false;
320            }
321        }
322    };
323}
324
325#[macro_export]
326macro_rules! sdram_activate {
327    ($sim: ident, $clock: ident, $uut: ident, $bank: expr, $row: expr) => {
328        sdram_cmd!($uut, SDRAMCommand::Active);
329        $uut.sdram.address.next = ($row as u32).to_bits();
330        $uut.sdram.bank.next = ($bank as u32).to_bits();
331        wait_clock_cycle!($sim, $clock, $uut);
332        sdram_cmd!($uut, SDRAMCommand::NOP);
333    };
334}
335
336#[macro_export]
337macro_rules! sdram_write {
338    ($sim: ident, $clock: ident, $uut: ident, $bank: expr, $addr: expr, $data: expr) => {
339        sdram_cmd!($uut, SDRAMCommand::Write);
340        $uut.sdram.bank.next = ($bank as u32).to_bits();
341        $uut.sdram.write_enable.next = true;
342        $uut.sdram.write_data.next = ($data[0] as u32).to_bits();
343        $uut.sdram.address.next = ($addr as u32).to_bits();
344        wait_clock_cycle!($sim, $clock, $uut);
345        for i in 1..($data).len() {
346            sdram_cmd!($uut, SDRAMCommand::NOP);
347            $uut.sdram.write_data.next = ($data[i] as u32).to_bits();
348            $uut.sdram.address.next = 0.into();
349            wait_clock_cycle!($sim, $clock, $uut);
350        }
351        $uut.sdram.write_enable.next = false;
352    };
353}
354
355#[macro_export]
356macro_rules! sdram_read {
357    ($sim: ident, $clock: ident, $uut: ident, $bank: expr, $addr: expr, $data: expr) => {
358        sdram_cmd!($uut, SDRAMCommand::Read);
359        $uut.sdram.bank.next = ($bank as u32).to_bits();
360        $uut.sdram.address.next = ($addr as u32).to_bits();
361        wait_clock_cycle!($sim, $clock, $uut);
362        sdram_cmd!($uut, SDRAMCommand::NOP);
363        wait_clock_cycles!($sim, $clock, $uut, 2); // Programmed CAS delay - 1
364        for datum in $data {
365            sdram_cmd!($uut, SDRAMCommand::NOP);
366            sim_assert!(
367                $sim,
368                $uut.sdram.read_data.val() == (datum as u32).to_bits(),
369                $uut
370            );
371            wait_clock_cycle!($sim, $clock, $uut);
372        }
373    };
374}
375
376#[macro_export]
377macro_rules! sdram_reada {
378    ($sim: ident, $clock: ident, $uut: ident, $bank: expr, $addr: expr, $data: expr) => {
379        sdram_cmd!($uut, SDRAMCommand::Read);
380        $uut.sdram.bank.next = ($bank as u32).to_bits();
381        $uut.sdram.address.next = ($addr as u32 | 1024_u32).to_bits(); // Signal autoprecharge
382        wait_clock_cycle!($sim, $clock, $uut);
383        sdram_cmd!($uut, SDRAMCommand::NOP);
384        wait_clock_cycles!($sim, $clock, $uut, 2); // Programmed CAS delay
385        for datum in $data {
386            sdram_cmd!($uut, SDRAMCommand::NOP);
387            sim_assert!(
388                $sim,
389                $uut.sdram.read_data.val() == (datum as u32).to_bits(),
390                $uut
391            );
392            wait_clock_cycle!($sim, $clock, $uut);
393        }
394    };
395}
396
397#[macro_export]
398macro_rules! sdram_precharge_one {
399    ($sim: ident, $clock: ident, $uut: ident, $bank: expr) => {
400        sdram_cmd!($uut, SDRAMCommand::Precharge);
401        $uut.sdram.bank.next = ($bank as u32).to_bits();
402        $uut.sdram.address.next = 0.into();
403        wait_clock_cycle!($sim, $clock, $uut);
404        sdram_cmd!($uut, SDRAMCommand::NOP);
405    };
406}
407
408#[macro_export]
409macro_rules! sdram_refresh {
410    ($sim: ident, $clock: ident, $uut: ident, $timings: expr) => {
411        sdram_cmd!($uut, SDRAMCommand::AutoRefresh);
412        $uut.sdram.bank.next = 0.into();
413        $uut.sdram.address.next = 0.into();
414        wait_clock_cycle!($sim, $clock, $uut);
415        sdram_cmd!($uut, SDRAMCommand::NOP);
416        wait_clock_cycles!($sim, $clock, $uut, $timings.t_rfc());
417    };
418}
419
420#[macro_export]
421macro_rules! sdram_boot {
422    ($sim: ident, $clock: ident, $uut: ident, $timings: ident) => {
423        sdram_cmd!($uut, SDRAMCommand::NOP);
424        wait_clock_true!($sim, $clock, $uut);
425        // Wait for 100 microseconds
426        // 100 microseconds = 100 * 1_000_000
427        // Pad by 100 nanoseconds
428        $uut = $sim.wait(
429            (($timings.initial_delay_in_nanoseconds + 600.0) * 1000.0) as u64,
430            $uut,
431        )?;
432        wait_clock_true!($sim, $clock, $uut);
433        wait_clock_cycle!($sim, $clock, $uut);
434        sdram_cmd!($uut, SDRAMCommand::Precharge);
435        $uut.sdram.address.next = 0xFFF.into();
436        wait_clock_cycle!($sim, $clock, $uut);
437        sdram_cmd!($uut, SDRAMCommand::NOP);
438        wait_clock_cycles!($sim, $clock, $uut, $timings.t_rp());
439        sdram_cmd!($uut, SDRAMCommand::AutoRefresh);
440        wait_clock_cycle!($sim, $clock, $uut);
441        sdram_cmd!($uut, SDRAMCommand::NOP);
442        wait_clock_cycles!($sim, $clock, $uut, $timings.t_rfc());
443        sdram_cmd!($uut, SDRAMCommand::AutoRefresh);
444        wait_clock_cycle!($sim, $clock, $uut);
445        sdram_cmd!($uut, SDRAMCommand::NOP);
446        wait_clock_cycles!($sim, $clock, $uut, $timings.t_rfc());
447    };
448}
449
450#[test]
451fn test_sdram_init_works() {
452    let uut = mk_sdr_sim();
453    let mut sim = Simulation::new();
454    // Clock period at 125 MHz is 8000ps
455    sim.add_clock(4000, |x: &mut Box<SDRAMSimulator<5, 5, 10, 16>>| {
456        x.sdram.clk.next = !x.sdram.clk.val();
457    });
458    sim.add_testbench(move |mut sim: Sim<SDRAMSimulator<5, 5, 10, 16>>| {
459        let mut x = sim.init()?;
460        let timings = MemoryTimings::fast_boot_sim(125e6);
461        wait_clock_cycles!(sim, clock, x, 16);
462        sdram_boot!(sim, clock, x, timings);
463        sdram_cmd!(x, SDRAMCommand::LoadModeRegister);
464        x.sdram.address.next = 0b000_0_00_011_0_011.into();
465        wait_clock_cycle!(sim, clock, x);
466        sdram_cmd!(x, SDRAMCommand::NOP);
467        wait_clock_cycles!(sim, clock, x, 5);
468        sim_assert_eq!(sim, x.state.q.val(), MasterState::Ready, x);
469        // Activate row 14 on bank 2
470        sdram_activate!(sim, clock, x, 2, 14);
471        // Activate row 7 on bank 1
472        wait_clock_cycles!(sim, clock, x, timings.t_rrd());
473        sdram_activate!(sim, clock, x, 1, 7);
474        wait_clock_cycles!(sim, clock, x, timings.t_ras());
475        sdram_write!(
476            sim,
477            clock,
478            x,
479            2,
480            16,
481            [0xABCD, 0xDEAD, 0xBEEF, 0x1234, 0xFACE, 0x5EA1, 0xCAFE, 0xBABE]
482        );
483        sdram_precharge_one!(sim, clock, x, 2);
484        sdram_write!(
485            sim,
486            clock,
487            x,
488            1,
489            24,
490            [0xABCE, 0xDEAE, 0xBEE0, 0x1235, 0xFACF, 0x5EA2, 0xCAFF, 0xBABF]
491        );
492        sdram_precharge_one!(sim, clock, x, 1);
493        wait_clock_cycles!(sim, clock, x, timings.t_rp() + 1);
494        sim_assert!(sim, !x.banks_busy.val(), x);
495        sim_assert_eq!(sim, x.state.q.val(), MasterState::Ready, x);
496        sdram_activate!(sim, clock, x, 1, 7);
497        wait_clock_cycles!(sim, clock, x, timings.t_rcd());
498        sdram_read!(
499            sim,
500            clock,
501            x,
502            1,
503            24,
504            [0xABCE, 0xDEAE, 0xBEE0, 0x1235, 0xFACF, 0x5EA2, 0xCAFF, 0xBABF]
505        );
506        sdram_precharge_one!(sim, clock, x, 1);
507        sdram_activate!(sim, clock, x, 2, 14);
508        wait_clock_cycles!(sim, clock, x, timings.t_rcd());
509        sdram_reada!(
510            sim,
511            clock,
512            x,
513            2,
514            16,
515            [0xABCD, 0xDEAD, 0xBEEF, 0x1234, 0xFACE, 0x5EA1, 0xCAFE, 0xBABE]
516        );
517        wait_clock_cycles!(sim, clock, x, timings.t_rp() + 1);
518        sim_assert!(sim, !x.banks_busy.val(), x);
519        sim_assert_eq!(sim, x.state.q.val(), MasterState::Ready, x);
520        sdram_refresh!(sim, clock, x, timings);
521        sim_assert!(sim, !x.banks_busy.val(), x);
522        sim_assert_eq!(sim, x.state.q.val(), MasterState::Ready, x);
523        wait_clock_cycles!(sim, clock, x, 10);
524        sim.done(x)
525    });
526    sim.run_to_file(Box::new(uut), 200_000_000, &vcd_path!("sdr_init.vcd"))
527        .unwrap()
528}