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#[derive(LogicBlock)]
21pub struct SDRAMSimulator<
22 const R: usize, const C: usize, const A: usize, const D: usize, > {
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 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 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 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 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 }
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 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 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 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); 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(); wait_clock_cycle!($sim, $clock, $uut);
383 sdram_cmd!($uut, SDRAMCommand::NOP);
384 wait_clock_cycles!($sim, $clock, $uut, 2); 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 $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 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 sdram_activate!(sim, clock, x, 2, 14);
471 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}