logicaffeine_compile/codegen_sva/hart/
ddr2.rs1use super::super::ddr2_phy::{ddr2_pins, Ddr2Cmd, InitStep, ModeReg};
12
13pub const CK_PS: u64 = 8_000;
15pub const FRAME_PS: u64 = 2 * CK_PS;
16
17#[derive(Clone, Copy, Debug)]
19pub struct Part {
20 pub trcd: u64,
22 pub trp: u64,
24 pub tras: u64,
26 pub trc: u64,
28 pub trrd: u64,
30 pub twr: u64,
32 pub twtr: u64,
34 pub trtp: u64,
36 pub trfc: u64,
38 pub trefi: u64,
40 pub power_up: u64,
42 pub cke_settle: u64,
44 pub tmrd_ck: u64,
46 pub tdllk_ck: u64,
48 pub cl: u64,
50}
51
52pub const MT47H64M16: Part = Part {
53 trcd: 12_500,
54 trp: 12_500,
55 tras: 45_000,
56 trc: 57_500,
57 trrd: 10_000,
58 twr: 15_000,
59 twtr: 7_500,
60 trtp: 7_500,
61 trfc: 127_500,
62 trefi: 7_800_000,
63 power_up: 200_000_000,
64 cke_settle: 400_000,
65 tmrd_ck: 2,
66 tdllk_ck: 200,
67 cl: 5,
68};
69
70pub const BURST_BEATS: u64 = 8;
72pub const BURSTS_PER_LINE: u64 = 4;
73
74pub const fn frames(ps: u64) -> u64 {
76 (ps + FRAME_PS - 1) / FRAME_PS
77}
78
79pub const fn cks(ps: u64) -> u64 {
81 (ps + CK_PS - 1) / CK_PS
82}
83
84#[derive(Clone, Copy, Debug, PartialEq, Eq)]
89pub struct Schedule {
90 pub rcd: u64,
91 pub ccd: u64,
92 pub read_done: u64,
93 pub write_done: u64,
94 pub rfc: u64,
95 pub refi: u64,
96 pub power_up: u64,
97 pub cke_settle: u64,
98 pub mrd: u64,
99 pub dllk: u64,
100}
101
102impl Schedule {
103 pub fn cas(&self, k: u64) -> u64 {
104 self.rcd + k * self.ccd
105 }
106}
107
108pub fn schedule(p: &Part) -> Schedule {
109 let rcd = frames(p.trcd);
110 let ccd = BURST_BEATS / 4;
111 let last = rcd + (BURSTS_PER_LINE - 1) * ccd;
112 let rd_pre_ps = (last * FRAME_PS + (BURST_BEATS / 2 - 2) * CK_PS + p.trtp.max(2 * CK_PS)).max(p.tras);
115 let read_done = frames(rd_pre_ps + p.trp).max(frames(p.trc));
116 let wl = p.cl - 1;
118 let wr_pre_ps = (last * FRAME_PS + (wl + BURST_BEATS / 2 + cks(p.twr)) * CK_PS).max(p.tras);
119 let write_done = frames(wr_pre_ps + p.trp).max(frames(p.trc));
120 Schedule {
121 rcd,
122 ccd,
123 read_done,
124 write_done,
125 rfc: frames(p.trfc),
126 refi: p.trefi / FRAME_PS - 2 * write_done,
128 power_up: frames(p.power_up),
129 cke_settle: frames(p.cke_settle),
130 mrd: (p.tmrd_ck + 1) / 2,
131 dllk: (p.tdllk_ck + 1) / 2,
132 }
133}
134
135pub fn mr(p: &Part, dll_reset: bool) -> u16 {
137 let bl8 = 0b011;
138 let cl = (p.cl as u16 & 0b111) << 4;
139 let wr = ((cks(p.twr) as u16 - 1) & 0b111) << 9;
140 bl8 | cl | wr | if dll_reset { 1 << 8 } else { 0 }
141}
142
143pub fn emr1(ocd: u16) -> u16 {
146 (ocd & 0b111) << 7
147}
148
149pub fn init_sequence(p: &Part) -> Vec<InitStep> {
151 use InitStep::*;
152 let s = schedule(p);
153 let rp = frames(p.trp);
154 vec![
155 CkeLowWait { cycles: s.power_up },
156 Wait { cycles: s.cke_settle },
157 PrechargeAll,
158 Wait { cycles: rp },
159 LoadMode { reg: ModeReg::Emr2, a: 0 },
160 Wait { cycles: s.mrd },
161 LoadMode { reg: ModeReg::Emr3, a: 0 },
162 Wait { cycles: s.mrd },
163 LoadMode { reg: ModeReg::Emr1, a: emr1(0) },
164 Wait { cycles: s.mrd },
165 LoadMode { reg: ModeReg::Mr, a: mr(p, true) },
166 Wait { cycles: s.mrd },
167 PrechargeAll,
168 Wait { cycles: rp },
169 Refresh,
170 Wait { cycles: s.rfc },
171 Refresh,
172 Wait { cycles: s.rfc },
173 LoadMode { reg: ModeReg::Mr, a: mr(p, false) },
174 Wait { cycles: s.dllk },
175 LoadMode { reg: ModeReg::Emr1, a: emr1(0b111) },
176 Wait { cycles: s.mrd },
177 LoadMode { reg: ModeReg::Emr1, a: emr1(0) },
178 Wait { cycles: s.mrd },
179 ]
180}
181
182pub fn init_word(step: &InitStep) -> u64 {
185 let (cke, cmd, ba, a, wait) = match *step {
186 InitStep::CkeLowWait { cycles } => (0u64, Ddr2Cmd::Deselect, 0u64, 0u64, cycles),
187 InitStep::Wait { cycles } => (1, Ddr2Cmd::Nop, 0, 0, cycles),
188 InitStep::PrechargeAll => (1, Ddr2Cmd::Precharge, 0, 1 << 10, 0),
189 InitStep::Refresh => (1, Ddr2Cmd::Refresh, 0, 0, 0),
190 InitStep::LoadMode { reg, a } => (1, Ddr2Cmd::LoadMode, reg.ba() as u64, a as u64, 0),
191 };
192 assert!(wait < 1 << 24, "an init wait of {wait} frames does not fit the ROM word");
193 let (cs, ras, cas, we) = ddr2_pins(cmd);
194 (cke << 44)
195 | ((cs as u64) << 43)
196 | ((ras as u64) << 42)
197 | ((cas as u64) << 41)
198 | ((we as u64) << 40)
199 | (ba << 37)
200 | (a << 24)
201 | wait
202}
203
204pub fn locate(offset: u64) -> (u64, u64, u64) {
207 ((offset >> 14) & 0x1fff, (offset >> 11) & 0b111, (offset >> 1) & 0x3ff)
208}
209
210pub fn calibration_line() -> [u64; 8] {
214 let mut words = [0u64; 8];
215 let mut x: u32 = 0x9e37_79b9;
216 let mut used = [[false; 256]; 2];
217 for beat in 0..32 {
218 for lane in 0..2 {
219 let byte = loop {
220 x ^= x << 13;
221 x ^= x >> 17;
222 x ^= x << 5;
223 let b = (x >> 11) as u8;
224 if !used[lane][b as usize] && !used[lane][!b as usize] {
225 used[lane][b as usize] = true;
226 break b;
227 }
228 };
229 words[beat / 4] |= (byte as u64) << (16 * (beat % 4) + 8 * lane);
230 }
231 }
232 words
233}
234
235pub fn verilog_params(p: &Part) -> String {
238 let s = schedule(p);
239 let seq = init_sequence(p);
240 let mut v = String::from("// Generated from codegen_sva::hart::ddr2. Do not edit.\n`ifndef HART_DDR2_PARAMS_VH\n`define HART_DDR2_PARAMS_VH\n");
241 for (name, value) in [
242 ("RCD", s.rcd),
243 ("CCD", s.ccd),
244 ("READ_DONE", s.read_done),
245 ("WRITE_DONE", s.write_done),
246 ("RFC", s.rfc),
247 ("REFI", s.refi),
248 ("INIT_STEPS", seq.len() as u64),
249 ] {
250 v.push_str(&format!("`define DDR2_{name} {value}\n"));
251 }
252 v.push_str("`define DDR2_INIT_ROM(rom) \\\n");
253 for (i, step) in seq.iter().enumerate() {
254 v.push_str(&format!(" rom[{i}] = 45'h{:012x}; \\\n", init_word(step)));
255 }
256 v.push_str(" ;\n`define DDR2_CAL_LINE(line) \\\n");
257 for (i, w) in calibration_line().iter().enumerate() {
258 v.push_str(&format!(" line[{i}] = 64'h{w:016x}; \\\n"));
259 }
260 v.push_str(" ;\n`endif\n");
261 v
262}