1use std::collections::VecDeque;
7
8use super::model::{Bus, BusError, Hart, Region};
9
10pub const ROM_BASE: u64 = 0x0001_0000;
12pub const ROM_SIZE: u64 = 0x4000;
13pub const SRAM_BASE: u64 = 0x0002_0000;
15pub const SRAM_SIZE: u64 = 0x2000;
16pub const IO_BASE: u64 = 0x1000_0000;
18pub const IO_SIZE: u64 = 0x1_0000;
19pub const RAM_BASE: u64 = 0x8000_0000;
21pub const RAM_SIZE: u64 = 128 << 20;
22
23pub const RESET_PC: u64 = ROM_BASE;
24
25pub fn memory_map() -> Vec<Region> {
27 vec![
28 Region::rom(ROM_BASE, ROM_SIZE),
29 Region::data(SRAM_BASE, SRAM_SIZE),
30 Region::io(IO_BASE, IO_SIZE),
31 Region::memory(RAM_BASE, RAM_SIZE),
32 ]
33}
34
35pub struct Reg {
37 pub name: &'static str,
38 pub addr: u64,
39 pub doc: &'static str,
40}
41
42const fn reg(name: &'static str, addr: u64, doc: &'static str) -> Reg {
43 Reg { name, addr, doc }
44}
45
46pub const SYS: u64 = IO_BASE;
47pub const UART: u64 = IO_BASE + 0x1000;
48pub const LINK: u64 = IO_BASE + 0x2000;
49pub const BUTTONS: u64 = IO_BASE + 0x3000;
50pub const QSPI: u64 = IO_BASE + 0x4000;
51pub const DDR: u64 = IO_BASE + 0x5000;
52
53pub const REGS: &[Reg] = &[
55 reg("SYS_ID", SYS, "read: the board's identity, SOC_ID"),
56 reg("SYS_CYCLES", SYS + 0x08, "read: clock cycles since reset"),
57 reg("SYS_FLAGS", SYS + 0x10, "read: bit 0 the DDR2 is ready, bit 1 its calibration failed"),
58 reg("SYS_RTL_MD5_LO", SYS + 0x18, "read: the first 8 bytes of the bitstream's RTL fingerprint"),
59 reg("SYS_RTL_MD5_HI", SYS + 0x20, "read: the last 8 bytes of the bitstream's RTL fingerprint"),
60 reg("SYS_SWITCHES", SYS + 0x28, "read: the 16 slide switches"),
61 reg("SYS_RESET", SYS + 0x30, "write SOC_RESET_KEY: restart the board from its reset vector"),
62 reg("SYS_EXIT", SYS + 0x38, "write: the firmware's exit status; the board stops there"),
63 reg("UART_TX", UART, "write: one byte to the log UART"),
64 reg("UART_STATUS", UART + 0x08, "read: bit 0 the transmit queue is full"),
65 reg("LINK_TX", LINK, "write: one byte into the terminal link, as the laptop would send it"),
66 reg("LINK_RX", LINK + 0x08, "read: bit 8 a byte is there, bits 7:0 the byte (the read takes it)"),
67 reg("LINK_STATUS", LINK + 0x10, "read: bit 0 the transmit queue is full, bit 1 a byte is waiting"),
68 reg("BUTTONS_STATE", BUTTONS, "read: the debounced buttons: bit 0 centre, 1 up, 2 left, 3 right, 4 down"),
69 reg("BUTTONS_LEDS", BUTTONS + 0x08, "read/write: the 16 LEDs"),
70 reg("QSPI_START", QSPI, "write: begin a streaming read of the flash at this byte address (it wraps at the end)"),
71 reg("QSPI_DATA", QSPI + 0x08, "read: the next 8 bytes of the stream (the read waits for them); all ones with no stream"),
72 reg("QSPI_STOP", QSPI + 0x10, "write: end the stream"),
73 reg("DDR_STATUS", DDR, "read: bit 0 calibrated, bit 1 failed; bits 15:8 the read latency found"),
74 reg("DDR_CAL", DDR + 0x08, "read: the calibration's per-lane taps"),
75];
76
77pub const SOC_ID: u64 = u64::from_le_bytes(*b"LOGOSHRT");
79pub const SOC_RESET_KEY: u64 = 0x5245_5345_545f_4b45;
81
82pub const SHIM_BASE: u64 = RAM_BASE;
85pub const SHIM_SIZE: u64 = 0x20_0000;
86pub const FIRMWARE_BASE: u64 = RAM_BASE + SHIM_SIZE;
87pub const MMAP_BASE: u64 = 0x8400_0000;
88pub const MMAP_SIZE: u64 = 0x200_0000;
89pub const STAGING_BASE: u64 = 0x8600_0000;
90pub const STAGING_SIZE: u64 = 0x180_0000;
91pub const STACK_BASE: u64 = 0x8780_0000;
92pub const STACK_SIZE: u64 = 0x80_0000;
93pub const BOOT_WORK_BASE: u64 = MMAP_BASE;
96
97pub const FLASH_SIZE: u64 = 16 << 20;
99pub const IMAGE_OFFSET: u64 = 0x40_0000;
100
101pub const IMAGE_MAGIC: u64 = u64::from_le_bytes(*b"LOGOSIMG");
104pub const IMAGE_VERSION: u32 = 1;
105pub const IMAGE_HEADER_SIZE: u64 = 128;
106
107pub const SECTION_SHIM: u32 = 1;
109pub const SECTION_FIRMWARE: u32 = 2;
110pub const SECTION_BUNDLE: u32 = 3;
111pub const SECTION_ARGS: u32 = 4;
112
113pub const CONSTANTS: &[(&str, u64)] = &[
115 ("ROM_BASE", ROM_BASE),
116 ("ROM_SIZE", ROM_SIZE),
117 ("SRAM_BASE", SRAM_BASE),
118 ("SRAM_SIZE", SRAM_SIZE),
119 ("IO_BASE", IO_BASE),
120 ("IO_SIZE", IO_SIZE),
121 ("RAM_BASE", RAM_BASE),
122 ("RAM_SIZE", RAM_SIZE),
123 ("RESET_PC", RESET_PC),
124 ("SOC_ID", SOC_ID),
125 ("SOC_RESET_KEY", SOC_RESET_KEY),
126 ("SHIM_BASE", SHIM_BASE),
127 ("SHIM_SIZE", SHIM_SIZE),
128 ("FIRMWARE_BASE", FIRMWARE_BASE),
129 ("MMAP_BASE", MMAP_BASE),
130 ("MMAP_SIZE", MMAP_SIZE),
131 ("STAGING_BASE", STAGING_BASE),
132 ("STAGING_SIZE", STAGING_SIZE),
133 ("STACK_BASE", STACK_BASE),
134 ("STACK_SIZE", STACK_SIZE),
135 ("BOOT_WORK_BASE", BOOT_WORK_BASE),
136 ("FLASH_SIZE", FLASH_SIZE),
137 ("IMAGE_OFFSET", IMAGE_OFFSET),
138 ("IMAGE_MAGIC", IMAGE_MAGIC),
139 ("IMAGE_VERSION", IMAGE_VERSION as u64),
140 ("IMAGE_HEADER_SIZE", IMAGE_HEADER_SIZE),
141 ("SECTION_SHIM", SECTION_SHIM as u64),
142 ("SECTION_FIRMWARE", SECTION_FIRMWARE as u64),
143 ("SECTION_BUNDLE", SECTION_BUNDLE as u64),
144 ("SECTION_ARGS", SECTION_ARGS as u64),
145 ("HART_HZ", HART_HZ),
146 ("HART_HWCAP", HART_HWCAP),
147];
148
149pub const HART_HWCAP: u64 = letter(b'i') | letter(b'm') | letter(b'a') | letter(b'f') | letter(b'd') | letter(b'c');
152
153const fn letter(c: u8) -> u64 {
154 1 << (c - b'a')
155}
156
157pub const HART_HZ: u64 = 62_500_000;
159
160pub fn c_header() -> String {
162 let mut s = String::from(
163 "// Generated from codegen_sva::hart::soc — the one definition of the board's addresses. Do not edit.\n\
164 #pragma once\n\n",
165 );
166 for (name, v) in CONSTANTS {
167 s.push_str(&format!("#define {name} 0x{v:x}ull\n"));
168 }
169 s.push('\n');
170 for r in REGS {
171 s.push_str(&format!("// {}\n#define {} 0x{:x}ull\n", r.doc, r.name, r.addr));
172 }
173 s
174}
175
176pub fn verilog_defines() -> String {
178 let mut s = String::from("// Generated from codegen_sva::hart::soc. Do not edit.\n`ifndef SOC_DEFINES_VH\n`define SOC_DEFINES_VH\n");
179 for (name, v) in CONSTANTS {
180 s.push_str(&format!("`define SOC_{name} 64'h{v:016x}\n"));
181 }
182 for r in REGS {
183 s.push_str(&format!("`define SOC_{} 64'h{:016x}\n", r.name, r.addr));
184 }
185 s.push_str("`endif\n");
186 s
187}
188
189pub struct Devices {
194 rom: Vec<u8>,
195 sram: Vec<u8>,
196 ram: Vec<u8>,
197 pub flash: Vec<u8>,
199 pub uart: Vec<u8>,
201 pub link_out: VecDeque<u8>,
203 pub link_in: VecDeque<u8>,
205 pub buttons: u64,
206 pub leds: u64,
207 pub switches: u64,
208 pub rtl_md5: [u8; 16],
210 pub ddr_ready: bool,
212 pub ddr_failed: bool,
213 pub cycles: u64,
215 pub exit: Option<u64>,
217 pub reset: bool,
219 stream: Option<u64>,
220}
221
222fn read_le(bytes: &[u8], o: usize, size: u8) -> u64 {
223 bytes[o..o + size as usize].iter().rev().fold(0, |v, &b| (v << 8) | b as u64)
224}
225
226fn write_le(bytes: &mut [u8], o: usize, size: u8, value: u64) {
227 for (i, b) in bytes[o..o + size as usize].iter_mut().enumerate() {
228 *b = (value >> (8 * i)) as u8;
229 }
230}
231
232impl Devices {
233 pub fn new(rom: &[u8], flash: Vec<u8>, rtl_md5: [u8; 16]) -> Self {
235 assert!(rom.len() as u64 <= ROM_SIZE, "the boot ROM image is larger than the ROM");
236 assert_eq!(flash.len() as u64, FLASH_SIZE, "the flash is {FLASH_SIZE} bytes");
237 let mut rom_bytes = vec![0; ROM_SIZE as usize];
238 rom_bytes[..rom.len()].copy_from_slice(rom);
239 Devices {
240 rom: rom_bytes,
241 sram: vec![0; SRAM_SIZE as usize],
242 ram: vec![0; RAM_SIZE as usize],
243 flash,
244 uart: Vec::new(),
245 link_out: VecDeque::new(),
246 link_in: VecDeque::new(),
247 buttons: 0,
248 leds: 0,
249 switches: 0,
250 rtl_md5,
251 ddr_ready: true,
252 ddr_failed: false,
253 cycles: 0,
254 exit: None,
255 reset: false,
256 stream: None,
257 }
258 }
259
260 fn io_read(&mut self, addr: u64) -> u64 {
262 let md5 = |i: usize| u64::from_le_bytes(self.rtl_md5[8 * i..8 * i + 8].try_into().unwrap());
263 match addr {
264 a if a == SYS => SOC_ID,
265 a if a == SYS + 0x08 => self.cycles,
266 a if a == SYS + 0x10 => (self.ddr_ready as u64) | ((self.ddr_failed as u64) << 1),
267 a if a == SYS + 0x18 => md5(0),
268 a if a == SYS + 0x20 => md5(1),
269 a if a == SYS + 0x28 => self.switches,
270 a if a == UART + 0x08 => 0,
271 a if a == LINK + 0x08 => self.link_in.pop_front().map(|b| 0x100 | b as u64).unwrap_or(0),
272 a if a == LINK + 0x10 => (!self.link_in.is_empty() as u64) << 1,
273 a if a == BUTTONS => self.buttons,
274 a if a == BUTTONS + 0x08 => self.leds,
275 a if a == QSPI + 0x08 => match self.stream {
276 Some(at) => {
277 let word = (0..8)
278 .map(|i| self.flash[((at + i) & (FLASH_SIZE - 1)) as usize] as u64)
279 .rev()
280 .fold(0, |v, b| (v << 8) | b);
281 self.stream = Some((at + 8) & (FLASH_SIZE - 1));
282 word
283 }
284 None => u64::MAX,
285 },
286 a if a == DDR => (self.ddr_ready as u64) | ((self.ddr_failed as u64) << 1),
287 _ => 0,
288 }
289 }
290
291 fn io_write(&mut self, addr: u64, value: u64) {
293 match addr {
294 a if a == SYS + 0x30 => self.reset = value == SOC_RESET_KEY,
295 a if a == SYS + 0x38 => self.exit = Some(value),
296 a if a == UART => self.uart.push(value as u8),
297 a if a == LINK => self.link_out.push_back(value as u8),
298 a if a == BUTTONS + 0x08 => self.leds = value & 0xffff,
299 a if a == QSPI => self.stream = Some(value & (FLASH_SIZE - 1)),
300 a if a == QSPI + 0x10 => self.stream = None,
301 _ => {}
302 }
303 }
304}
305
306impl Bus for Devices {
307 fn read(&mut self, addr: u64, size: u8) -> Result<u64, BusError> {
308 match addr {
309 a if (ROM_BASE..ROM_BASE + ROM_SIZE).contains(&a) => Ok(read_le(&self.rom, (a - ROM_BASE) as usize, size)),
310 a if (SRAM_BASE..SRAM_BASE + SRAM_SIZE).contains(&a) => Ok(read_le(&self.sram, (a - SRAM_BASE) as usize, size)),
311 a if (RAM_BASE..RAM_BASE + RAM_SIZE).contains(&a) => Ok(read_le(&self.ram, (a - RAM_BASE) as usize, size)),
312 a if (IO_BASE..IO_BASE + IO_SIZE).contains(&a) && size == 8 => Ok(self.io_read(a)),
313 _ => Err(BusError),
314 }
315 }
316
317 fn write(&mut self, addr: u64, size: u8, value: u64) -> Result<(), BusError> {
318 match addr {
319 a if (SRAM_BASE..SRAM_BASE + SRAM_SIZE).contains(&a) => {
320 write_le(&mut self.sram, (a - SRAM_BASE) as usize, size, value);
321 Ok(())
322 }
323 a if (RAM_BASE..RAM_BASE + RAM_SIZE).contains(&a) => {
324 write_le(&mut self.ram, (a - RAM_BASE) as usize, size, value);
325 Ok(())
326 }
327 a if (IO_BASE..IO_BASE + IO_SIZE).contains(&a) && size == 8 => {
328 self.io_write(a, value);
329 Ok(())
330 }
331 _ => Err(BusError),
332 }
333 }
334}
335
336#[derive(Clone, Copy, Debug, PartialEq, Eq)]
338pub enum Stopped {
339 Exited(u64),
341 StepLimit,
343}
344
345pub struct Board {
347 pub hart: Hart,
348 pub devices: Devices,
349}
350
351impl Board {
352 pub fn new(rom: &[u8], flash: Vec<u8>, rtl_md5: [u8; 16]) -> Self {
353 Board {
354 hart: Hart::new(RESET_PC, memory_map()),
355 devices: Devices::new(rom, flash, rtl_md5),
356 }
357 }
358
359 pub fn run(&mut self, steps: u64) -> Stopped {
361 for _ in 0..steps {
362 self.hart.step(&mut self.devices);
363 self.devices.cycles += 1;
364 if let Some(status) = self.devices.exit {
365 return Stopped::Exited(status);
366 }
367 if self.devices.reset {
368 self.devices.reset = false;
369 self.hart = Hart::new(RESET_PC, memory_map());
370 }
371 }
372 Stopped::StepLimit
373 }
374}