1use rust_hdl_core::prelude::*;
2use rust_hdl_widgets::prelude::*;
3
4#[derive(Copy, Clone, PartialEq, Debug, LogicState)]
5pub enum BankState {
6 Boot,
7 Idle,
8 Active,
9 Reading,
10 Precharging,
11 Writing,
12 Error,
13 Autorefreshing,
14 WriteRecovery,
15}
16
17#[derive(LogicBlock)]
23pub struct MemoryBank<const R: usize, const C: usize, const A: usize, const D: usize> {
24 pub clock: Signal<In, Clock>,
26 pub cas_delay: Signal<In, Bits<3>>,
27 pub write_burst: Signal<In, Bit>,
28 pub address: Signal<In, Bits<13>>,
29 pub burst_len: Signal<In, Bits<4>>,
30 pub cmd: Signal<In, SDRAMCommand>,
31 pub error: Signal<Out, Bit>,
32 pub busy: Signal<Out, Bit>,
33 pub write_data: Signal<In, Bits<D>>,
34 pub read_data: Signal<Out, Bits<D>>,
35 pub read_valid: Signal<Out, Bit>,
36 pub select: Signal<In, Bit>,
37 delay_line: DelayLine<Bits<D>, 7, 3>,
38 read_delay_line: DelayLine<Bit, 7, 3>,
39 refresh_counter: DFF<Bits<32>>,
40 refresh_active: DFF<Bit>,
41 mem: RAM<Bits<D>, A>,
42 write_reg: DFF<Bits<D>>,
43 state: DFF<BankState>,
44 auto_precharge: DFF<Bit>,
45 active_row: DFF<Bits<R>>,
46 burst_counter: DFF<Bits<4>>,
47 active_col: DFF<Bits<C>>,
48 delay_counter: DFF<Bits<32>>,
49 t_activate: DFF<Bits<32>>,
50 t_ras: Constant<Bits<32>>, t_rc: Constant<Bits<32>>, t_rcd: Constant<Bits<32>>, t_rp: Constant<Bits<32>>, t_wr: Constant<Bits<32>>, t_refresh_max: Constant<Bits<32>>,
56 t_rfc: Constant<Bits<32>>,
57 row_shift: Constant<Bits<A>>,
58}
59
60impl<const R: usize, const C: usize, const A: usize, const D: usize> MemoryBank<R, C, A, D> {
61 pub fn new(timings: MemoryTimings) -> Self {
62 assert_eq!(R + C, A);
63 let t_ras = timings.t_ras() - 1;
64 let t_rc = timings.t_rc() - 1;
65 let t_rcd = timings.t_rcd() - 1;
66 let t_rp = timings.t_rp() - 1;
67 let t_refresh_max = timings.t_refresh_max() - 1;
68 let t_rfc = timings.t_rfc() - 1;
69 let t_wr = timings.t_wr() - 1;
70 Self {
71 clock: Default::default(),
72 cas_delay: Default::default(),
73 write_burst: Default::default(),
74 address: Default::default(),
75 burst_len: Default::default(),
76 cmd: Default::default(),
77 error: Default::default(),
78 busy: Default::default(),
79 write_data: Default::default(),
80 read_data: Default::default(),
81 read_valid: Default::default(),
82 select: Default::default(),
83 delay_line: Default::default(),
84 read_delay_line: Default::default(),
85 mem: Default::default(),
86 write_reg: Default::default(),
87 state: Default::default(),
88 auto_precharge: Default::default(),
89 active_row: Default::default(),
90 burst_counter: Default::default(),
91 active_col: Default::default(),
92 delay_counter: Default::default(),
93 refresh_counter: Default::default(),
94 refresh_active: Default::default(),
95 t_activate: Default::default(),
96 t_ras: Constant::new(t_ras.to_bits()),
97 t_rc: Constant::new(t_rc.to_bits()),
98 t_rcd: Constant::new(t_rcd.to_bits()),
99 t_rp: Constant::new(t_rp.to_bits()),
100 t_wr: Constant::new(t_wr.to_bits()),
101 t_refresh_max: Constant::new(t_refresh_max.to_bits()),
102 t_rfc: Constant::new(t_rfc.to_bits()),
103 row_shift: Constant::new(C.to_bits()),
104 }
105 }
106}
107
108impl<const R: usize, const C: usize, const A: usize, const D: usize> Logic
109 for MemoryBank<R, C, A, D>
110{
111 #[hdl_gen]
112 fn update(&mut self) {
113 self.mem.read_clock.next = self.clock.val();
115 self.mem.write_clock.next = self.clock.val();
116 dff_setup!(
117 self,
118 clock,
119 refresh_counter,
120 refresh_active,
121 write_reg,
122 state,
123 auto_precharge,
124 active_row,
125 burst_counter,
126 active_col,
127 delay_counter,
128 t_activate
129 );
130 clock!(self, clock, delay_line, read_delay_line);
131 self.delay_counter.d.next = self.delay_counter.q.val() + 1;
132 self.error.next = false;
133 self.mem.read_address.next = (bit_cast::<A, R>(self.active_row.q.val())
135 << self.row_shift.val())
136 | bit_cast::<A, C>(self.active_col.q.val());
137 self.mem.write_address.next = (bit_cast::<A, R>(self.active_row.q.val())
138 << self.row_shift.val())
139 | bit_cast::<A, C>(self.active_col.q.val());
140 self.write_reg.d.next = self.write_data.val();
141 self.mem.write_data.next = self.write_reg.q.val();
142 self.mem.write_enable.next = false;
143 self.delay_line.data_in.next = self.mem.read_data.val();
144 self.read_data.next = self.delay_line.data_out.val();
145 self.delay_line.delay.next = self.cas_delay.val() - 2;
146 self.t_activate.d.next = self.t_activate.q.val() + 1;
148 self.busy.next = true;
149 self.read_delay_line.data_in.next = false;
150 self.read_delay_line.delay.next = self.cas_delay.val() - 1;
151 self.read_valid.next = self.read_delay_line.data_out.val();
152 self.refresh_counter.d.next = self.refresh_counter.q.val() + self.refresh_active.q.val();
153 match self.state.q.val() {
154 BankState::Boot => {
155 self.t_activate.d.next = 0xFFFF.into();
156 self.state.d.next = BankState::Idle;
157 }
158 BankState::Idle => {
159 self.busy.next = false;
160 if self.select.val() {
161 match self.cmd.val() {
162 SDRAMCommand::Active => {
163 if self.t_activate.q.val() < self.t_rc.val() {
165 self.state.d.next = BankState::Error;
166 } else {
167 self.t_activate.d.next = 0.into();
168 self.active_row.d.next = self.address.val().get_bits::<R>(0);
171 self.delay_counter.d.next = 0.into();
173 self.state.d.next = BankState::Active;
175 }
176 }
177 SDRAMCommand::NOP => {}
178 SDRAMCommand::Precharge => {} SDRAMCommand::AutoRefresh => {
180 if self.refresh_active.q.val()
181 & (self.refresh_counter.q.val() < self.t_rc.val())
182 {
183 self.state.d.next = BankState::Error;
184 } else {
185 self.state.d.next = BankState::Autorefreshing;
186 self.refresh_active.d.next = true;
187 self.refresh_counter.d.next = 0.into();
188 }
189 } SDRAMCommand::LoadModeRegister => {} _ => {
192 self.state.d.next = BankState::Error;
193 }
194 }
195 }
196 }
197 BankState::Active => {
198 if self.select.val() {
199 match self.cmd.val() {
200 SDRAMCommand::NOP => {}
201 SDRAMCommand::Read => {
202 if self.t_activate.q.val() < self.t_rcd.val() {
203 self.state.d.next = BankState::Error;
204 } else {
205 self.active_col.d.next = self.address.val().get_bits::<C>(0);
207 self.burst_counter.d.next = 0.into();
208 self.state.d.next = BankState::Reading;
209 self.auto_precharge.d.next = self.address.val().get_bit(10);
211 }
212 }
213 SDRAMCommand::Write => {
214 if self.t_activate.q.val() < self.t_rcd.val() {
215 self.state.d.next = BankState::Error;
216 } else {
217 self.active_col.d.next = self.address.val().get_bits::<C>(0);
219 self.burst_counter.d.next = 0.into();
220 self.state.d.next = BankState::Writing;
221 self.auto_precharge.d.next = self.address.val().get_bit(10);
223 }
224 }
225 SDRAMCommand::Precharge => {
226 if self.t_activate.q.val() < self.t_ras.val() {
227 self.state.d.next = BankState::Error;
228 } else {
229 self.delay_counter.d.next = 0.into();
231 self.state.d.next = BankState::Precharging;
232 }
233 }
234 _ => {
235 self.state.d.next = BankState::Error;
236 }
237 }
238 }
239 }
240 BankState::Reading => {
241 self.burst_counter.d.next = self.burst_counter.q.val() + 1;
243 self.active_col.d.next = self.active_col.q.val() + 1;
244 self.read_delay_line.data_in.next = true;
245 if self.burst_counter.q.val() == self.burst_len.val() {
247 self.read_delay_line.data_in.next = false;
248 if self.auto_precharge.q.val() {
249 self.delay_counter.d.next = 0.into();
250 self.state.d.next = BankState::Precharging;
251 } else {
252 self.state.d.next = BankState::Active
253 }
254 }
255 if self.select.val() {
256 match self.cmd.val() {
257 SDRAMCommand::NOP => {}
258 SDRAMCommand::Read => {
259 self.active_col.d.next = self.address.val().get_bits::<C>(0);
261 self.burst_counter.d.next = 0.into();
262 self.auto_precharge.d.next = self.address.val().get_bit(10);
264 self.state.d.next = BankState::Reading;
265 }
266 SDRAMCommand::Precharge => {
267 if self.auto_precharge.q.val() {
268 self.state.d.next = BankState::Error;
269 } else {
270 self.delay_counter.d.next = 0.into();
271 self.state.d.next = BankState::Precharging;
272 }
273 }
274 _ => {
275 self.state.d.next = BankState::Error;
276 }
277 }
278 }
279 }
280 BankState::Precharging => {
281 if self.delay_counter.q.val() == self.t_rp.val() {
282 self.state.d.next = BankState::Idle;
283 }
284 if self.select.val() {
285 match self.cmd.val() {
286 SDRAMCommand::NOP => {}
287 _ => {
288 self.state.d.next = BankState::Error;
289 }
290 }
291 }
292 }
293 BankState::Autorefreshing => {
294 if self.refresh_counter.q.val() == self.t_rfc.val() {
295 self.state.d.next = BankState::Idle;
296 }
297 if self.select.val() {
298 match self.cmd.val() {
299 SDRAMCommand::NOP => {}
300 _ => {
301 self.state.d.next = BankState::Error;
302 }
303 }
304 }
305 }
306 BankState::Writing => {
307 self.mem.write_enable.next = true;
308 self.burst_counter.d.next = self.burst_counter.q.val() + 1;
310 self.active_col.d.next = self.active_col.q.val() + 1;
311 if self.burst_counter.q.val() == self.burst_len.val() - 1 {
313 self.delay_counter.d.next = 0.into();
314 if self.auto_precharge.q.val() {
315 self.state.d.next = BankState::Precharging;
316 } else {
317 self.state.d.next = BankState::WriteRecovery
318 }
319 }
320 if self.select.val() {
321 match self.cmd.val() {
322 SDRAMCommand::NOP => {}
323 SDRAMCommand::Write => {
324 self.active_col.d.next = self.address.val().get_bits::<C>(0);
325 self.burst_counter.d.next = 0.into();
326 self.auto_precharge.d.next = self.address.val().get_bit(10);
328 self.state.d.next = BankState::Writing;
329 }
330 SDRAMCommand::Precharge => {
331 if self.auto_precharge.q.val() {
332 self.state.d.next = BankState::Error;
333 } else {
334 self.delay_counter.d.next = 0.into();
335 self.state.d.next = BankState::Precharging;
336 }
337 }
338 _ => {
339 self.state.d.next = BankState::Error;
340 }
341 }
342 }
343 }
344 BankState::Error => {
345 self.error.next = true;
346 }
347 BankState::WriteRecovery => {
348 if self.delay_counter.q.val() == self.t_wr.val() {
349 self.state.d.next = BankState::Active;
350 }
351 match self.cmd.val() {
352 SDRAMCommand::NOP => {}
353 SDRAMCommand::Read => {
354 self.active_col.d.next = self.address.val().get_bits::<C>(0);
355 self.burst_counter.d.next = 0.into();
356 self.state.d.next = BankState::Reading;
357 self.auto_precharge.d.next = self.address.val().get_bit(10);
359 }
360 SDRAMCommand::Write => {
361 self.active_col.d.next = self.address.val().get_bits::<C>(0);
362 self.burst_counter.d.next = 0.into();
363 self.state.d.next = BankState::Writing;
364 self.auto_precharge.d.next = self.address.val().get_bit(10);
366 }
367 _ => {
368 self.state.d.next = BankState::Error;
369 }
370 }
371 }
372 _ => {
373 self.state.d.next = BankState::Boot;
374 }
375 }
376 if self.refresh_counter.q.val() >= self.t_refresh_max.val() {
377 self.state.d.next = BankState::Error;
378 }
379 }
380}
381
382#[cfg(test)]
384fn mk_bank_sim() -> MemoryBank<5, 5, 10, 16> {
385 let mut uut = MemoryBank::new(MemoryTimings::mt48lc8m16a2(500e6));
386 uut.address.connect();
387 uut.cmd.connect();
388 uut.clock.connect();
389 uut.cas_delay.connect();
390 uut.write_burst.connect();
391 uut.burst_len.connect();
392 uut.write_data.connect();
393 uut.select.connect();
394 uut.connect_all();
395 uut.burst_len.next = 8.into();
396 uut.write_burst.next = true;
397 uut.cas_delay.next = 3.into();
398 uut.cmd.next = SDRAMCommand::NOP;
399 uut.select.next = true;
400 uut
401}
402
403#[test]
404fn test_bank_sim_synthesizes() {
405 let uut = mk_bank_sim();
406 let vlog = generate_verilog(&uut);
407 yosys_validate("sdram_bank", &vlog).unwrap();
408}
409
410#[test]
411fn test_bank_activation_immediate_close_is_ok_with_delay() {
412 let uut = mk_bank_sim();
413 let mut sim = Simulation::new();
414 let clock_period = 2000;
416 sim.add_clock(clock_period / 2, |x: &mut Box<MemoryBank<5, 5, 10, 16>>| {
417 x.clock.next = !x.clock.val();
418 });
419 sim.add_testbench(move |mut sim: Sim<MemoryBank<5, 5, 10, 16>>| {
420 let mut x = sim.init()?;
421 let timing = MemoryTimings::mt48lc8m16a2(500e6);
422
423 wait_clock_true!(sim, clock, x);
424 wait_clock_cycles!(sim, clock, x, 30);
425 x.cmd.next = SDRAMCommand::Active;
426 x.address.next = 14.into();
427 wait_clock_cycle!(sim, clock, x);
428 let start_time = sim.time();
429 let wait_for_precharge =
432 timing.t_ras_row_active_min_time_nanoseconds * 1000.0 - clock_period as f64;
433 while sim.time() - start_time < wait_for_precharge as u64 {
434 x.cmd.next = SDRAMCommand::NOP;
435 wait_clock_cycle!(sim, clock, x);
436 }
437 x.cmd.next = SDRAMCommand::Precharge;
438 wait_clock_cycle!(sim, clock, x);
439 let start_time = sim.time();
440 let precharge_time = timing.t_rp_recharge_period_nanoseconds * 1000.0 - clock_period as f64;
441 while sim.time() - start_time < precharge_time as u64 {
442 x.cmd.next = SDRAMCommand::NOP;
443 wait_clock_cycle!(sim, clock, x);
444 sim_assert!(sim, x.state.q.val() != BankState::Idle, x);
445 }
446 wait_clock_cycle!(sim, clock, x);
447 sim_assert_eq!(sim, x.state.q.val(), BankState::Idle, x);
448 wait_clock_cycle!(sim, clock, x, 10);
449 sim_assert!(sim, !x.error.val(), x);
450 sim.done(x)
451 });
452 sim.run(Box::new(uut), 1_000_000).unwrap();
453}
454
455#[test]
456fn test_bank_activation_immediate_close_fails_for_timing() {
457 let uut = mk_bank_sim();
458 let mut sim = Simulation::new();
459 let clock_period = 2000;
461 sim.add_clock(clock_period / 2, |x: &mut Box<MemoryBank<5, 5, 10, 16>>| {
462 x.clock.next = !x.clock.val();
463 });
464 sim.add_testbench(move |mut sim: Sim<MemoryBank<5, 5, 10, 16>>| {
465 let mut x = sim.init()?;
466 let timing = MemoryTimings::mt48lc8m16a2(500e6);
467
468 wait_clock_true!(sim, clock, x);
469 wait_clock_cycle!(sim, clock, x);
470 x.cmd.next = SDRAMCommand::Active;
471 x.address.next = 14.into();
472 wait_clock_cycle!(sim, clock, x);
473 let start_time = sim.time();
474 let wait_for_precharge =
478 (timing.t_ras_row_active_min_time_nanoseconds * 1000.0) as u64 - clock_period * 2;
479 while sim.time() - start_time < wait_for_precharge as u64 {
480 x.cmd.next = SDRAMCommand::NOP;
481 wait_clock_cycle!(sim, clock, x);
482 }
483 x.cmd.next = SDRAMCommand::Precharge;
484 wait_clock_cycle!(sim, clock, x);
485 x.cmd.next = SDRAMCommand::NOP;
486 wait_clock_cycle!(sim, clock, x, 10);
487 sim_assert!(sim, x.error.val(), x);
488 sim.done(x)
489 });
490 sim.run(Box::new(uut), 1_000_000).unwrap();
491}
492
493#[test]
494fn test_bank_write() {
495 let uut = mk_bank_sim();
496 let mut sim = Simulation::new();
497 let clock_period = 2000;
499 sim.add_clock(clock_period / 2, |x: &mut Box<MemoryBank<5, 5, 10, 16>>| {
500 x.clock.next = !x.clock.val();
501 });
502 let data = [
503 0xABCD, 0xDEAD, 0xBEEF, 0x1234, 0xFACE, 0x5EA1, 0xCAFE, 0xBABE,
504 ];
505 sim.add_testbench(move |mut sim: Sim<MemoryBank<5, 5, 10, 16>>| {
506 let mut x = sim.init()?;
507 x = sim.watch(
508 |x| x.clock.val().clk & (x.cmd.val() == SDRAMCommand::Read),
509 x,
510 )?;
511 let cas_start_time = sim.time();
512 x = sim.watch(|x| x.clock.val().clk & x.read_valid.val(), x)?;
513 let cas_end_time = sim.time();
514 sim_assert!(
515 sim,
516 (cas_end_time - cas_start_time) == (x.cas_delay.val().index() as u64) * clock_period,
517 x
518 );
519 sim.done(x)
520 });
521 sim.add_testbench(move |mut sim: Sim<MemoryBank<5, 5, 10, 16>>| {
522 let mut x = sim.init()?;
523 for _ in 0..2 {
524 x = sim.watch(|x| !x.clock.val().clk & x.read_valid.val(), x)?;
525 for val in &data {
526 sim_assert!(sim, x.read_data.val() == *val, x);
527 wait_clock_cycle!(sim, clock, x);
528 }
529 }
530 sim.done(x)
531 });
532 sim.add_testbench(move |mut sim: Sim<MemoryBank<5, 5, 10, 16>>| {
533 let mut x = sim.init()?;
534 let timing = MemoryTimings::mt48lc8m16a2(500e6);
535
536 wait_clock_true!(sim, clock, x);
537 wait_clock_cycles!(sim, clock, x, 30);
538 x.cmd.next = SDRAMCommand::Active;
539 x.address.next = 14.into();
540 wait_clock_cycle!(sim, clock, x);
541 let start_time = sim.time();
542 let wait_for_active =
545 (timing.t_rcd_row_to_column_min_time_nanoseconds * 1000.0) as u64 - clock_period;
546 while sim.time() - start_time < wait_for_active as u64 {
547 x.cmd.next = SDRAMCommand::NOP;
548 wait_clock_cycle!(sim, clock, x);
549 }
550 x.cmd.next = SDRAMCommand::Write;
551 x.write_data.next = data[0].into();
552 x.address.next = 0.into();
553 wait_clock_cycle!(sim, clock, x);
554 for datum in data.iter().skip(1) {
555 x.cmd.next = SDRAMCommand::NOP;
556 x.write_data.next = (*datum).into();
557 wait_clock_cycle!(sim, clock, x);
558 }
559 x.cmd.next = SDRAMCommand::NOP;
560 wait_clock_cycles!(sim, clock, x, 10);
561 x.cmd.next = SDRAMCommand::Read;
563 x.address.next = 0.into();
564 wait_clock_cycle!(sim, clock, x);
565 x.cmd.next = SDRAMCommand::NOP;
566 wait_clock_cycles!(sim, clock, x, 8);
567 x.cmd.next = SDRAMCommand::Read;
569 x.address.next = 1024.into();
570 wait_clock_cycle!(sim, clock, x);
571 x.cmd.next = SDRAMCommand::NOP;
572 wait_clock_cycles!(sim, clock, x, 10);
573 let precharge_clocks = timing.t_rp();
574 wait_clock_cycles!(sim, clock, x, precharge_clocks);
575 sim_assert!(sim, !x.busy.val(), x);
576 sim_assert!(sim, !x.error.val(), x);
577 sim.done(x)
578 });
579 sim.run_to_file(Box::new(uut), 1_000_000, &vcd_path!("sdram_write.vcd"))
580 .unwrap();
581}