1pub const ROM_SIZE: usize = 32 * 1024;
3pub const SRAM_SIZE: usize = 520 * 1024;
5
6pub struct Memory {
9 rom: Vec<u8>,
10 sram: Vec<u8>,
11 xip: Vec<u8>,
12}
13
14impl Memory {
15 pub fn new() -> Self {
16 Self {
17 rom: vec![0u8; ROM_SIZE],
18 sram: vec![0u8; SRAM_SIZE],
19 xip: Vec::new(),
20 }
21 }
22
23 pub fn with_sizes(rom_size: usize, sram_size: usize) -> Self {
28 Self {
29 rom: vec![0u8; rom_size],
30 sram: vec![0u8; sram_size],
31 xip: Vec::new(),
32 }
33 }
34
35 pub fn with_flash(rom_size: usize, sram_size: usize, flash_size: usize) -> Self {
43 Self {
44 rom: vec![0u8; rom_size],
45 sram: vec![0u8; sram_size],
46 xip: vec![0u8; flash_size],
47 }
48 }
49
50 pub fn flash_size(&self) -> usize {
54 self.xip.len()
55 }
56
57 pub fn load_rom(&mut self, data: &[u8]) {
60 let len = data.len().min(self.rom.len());
61 self.rom[..len].copy_from_slice(&data[..len]);
62 }
63
64 pub fn rom_read8(&self, offset: u32) -> u8 {
65 self.rom.get(offset as usize).copied().unwrap_or(0)
66 }
67
68 pub fn rom_read16(&self, offset: u32) -> u16 {
69 let off = offset as usize;
70 if off + 1 < self.rom.len() {
71 u16::from_le_bytes([self.rom[off], self.rom[off + 1]])
72 } else {
73 0
74 }
75 }
76
77 pub fn rom_read32(&self, offset: u32) -> u32 {
78 let off = offset as usize;
79 if off + 3 < self.rom.len() {
80 u32::from_le_bytes([
81 self.rom[off],
82 self.rom[off + 1],
83 self.rom[off + 2],
84 self.rom[off + 3],
85 ])
86 } else {
87 0
88 }
89 }
90
91 pub fn sram_read8(&self, offset: u32) -> u8 {
94 self.sram.get(offset as usize).copied().unwrap_or(0)
95 }
96
97 pub fn sram_read16(&self, offset: u32) -> u16 {
98 let off = offset as usize;
99 if off + 1 < self.sram.len() {
100 u16::from_le_bytes([self.sram[off], self.sram[off + 1]])
101 } else {
102 0
103 }
104 }
105
106 pub fn sram_read32(&self, offset: u32) -> u32 {
107 let off = offset as usize;
108 if off + 3 < self.sram.len() {
109 u32::from_le_bytes([
110 self.sram[off],
111 self.sram[off + 1],
112 self.sram[off + 2],
113 self.sram[off + 3],
114 ])
115 } else {
116 0
117 }
118 }
119
120 pub fn sram_write8(&mut self, offset: u32, val: u8) {
121 let off = offset as usize;
122 if off < self.sram.len() {
123 self.sram[off] = val;
124 }
125 }
126
127 pub fn sram_write16(&mut self, offset: u32, val: u16) {
128 let off = offset as usize;
129 if off + 1 < self.sram.len() {
130 let bytes = val.to_le_bytes();
131 self.sram[off] = bytes[0];
132 self.sram[off + 1] = bytes[1];
133 }
134 }
135
136 pub fn sram_write32(&mut self, offset: u32, val: u32) {
137 let off = offset as usize;
138 if off + 3 < self.sram.len() {
139 let bytes = val.to_le_bytes();
140 self.sram[off] = bytes[0];
141 self.sram[off + 1] = bytes[1];
142 self.sram[off + 2] = bytes[2];
143 self.sram[off + 3] = bytes[3];
144 }
145 }
146
147 pub fn load_flash(&mut self, data: &[u8]) {
158 if self.xip.is_empty() {
159 self.xip = data.to_vec();
160 } else {
161 let n = data.len().min(self.xip.len());
162 self.xip[..n].copy_from_slice(&data[..n]);
163 for b in &mut self.xip[n..] {
164 *b = 0;
165 }
166 }
167 }
168
169 pub fn xip_read8(&self, offset: u32) -> u8 {
170 self.xip.get(offset as usize).copied().unwrap_or(0)
171 }
172
173 pub fn xip_read16(&self, offset: u32) -> u16 {
174 let off = offset as usize;
175 if off + 1 < self.xip.len() {
176 u16::from_le_bytes([self.xip[off], self.xip[off + 1]])
177 } else {
178 0
179 }
180 }
181
182 pub fn xip_read32(&self, offset: u32) -> u32 {
183 let off = offset as usize;
184 if off + 3 < self.xip.len() {
185 u32::from_le_bytes([
186 self.xip[off],
187 self.xip[off + 1],
188 self.xip[off + 2],
189 self.xip[off + 3],
190 ])
191 } else {
192 0
193 }
194 }
195
196 pub fn peek8(&self, addr: u32) -> u8 {
199 match addr >> 28 {
200 0x0 => self.rom_read8(addr & 0x0FFF_FFFF),
201 0x1 => self.xip_read8(addr & 0x0FFF_FFFF),
202 0x2 => self.sram_read8(addr & 0x00FF_FFFF), _ => 0,
204 }
205 }
206
207 pub fn poke8(&mut self, addr: u32, val: u8) {
208 if addr >> 28 == 0x2 {
210 self.sram_write8(addr & 0x00FF_FFFF, val);
211 }
212 }
213
214 pub fn peek32(&self, addr: u32) -> u32 {
215 match addr >> 28 {
216 0x0 => self.rom_read32(addr & 0x0FFF_FFFF),
217 0x1 => self.xip_read32(addr & 0x0FFF_FFFF),
218 0x2 => self.sram_read32(addr & 0x00FF_FFFF), _ => 0,
220 }
221 }
222
223 pub fn poke32(&mut self, addr: u32, val: u32) {
224 if addr >> 28 == 0x2 {
226 self.sram_write32(addr & 0x00FF_FFFF, val);
227 }
228 }
229
230 pub fn into_parts(self) -> (Vec<u8>, Vec<u8>, Vec<u8>) {
235 (self.rom, self.sram, self.xip)
236 }
237}
238
239impl Default for Memory {
240 fn default() -> Self {
241 Self::new()
242 }
243}
244
245#[cfg(test)]
246mod tests {
247 use super::*;
248
249 #[test]
250 fn with_flash_preallocates_zeroed_buffer() {
251 let mem = Memory::with_flash(16 * 1024, 264 * 1024, 2 * 1024 * 1024);
255 assert_eq!(mem.flash_size(), 2 * 1024 * 1024);
256 assert_eq!(mem.xip_read8(0), 0);
257 assert_eq!(mem.xip_read8(2 * 1024 * 1024 - 1), 0);
258 assert_eq!(mem.xip_read32(0), 0);
259 }
260
261 #[test]
262 fn with_flash_load_clamps_into_fixed_buffer() {
263 let mut mem = Memory::with_flash(16 * 1024, 264 * 1024, 2 * 1024 * 1024);
267 mem.load_flash(&[0xAA, 0xBB, 0xCC, 0xDD]);
268 assert_eq!(mem.xip_read32(0), 0xDDCCBBAA);
269 assert_eq!(mem.xip_read8(4), 0);
271 assert_eq!(mem.xip_read8((2 * 1024 * 1024) - 1), 0);
272 mem.load_flash(&[0x01]);
274 assert_eq!(mem.xip_read8(0), 0x01);
275 assert_eq!(mem.xip_read8(1), 0);
276 assert_eq!(mem.xip_read8(3), 0);
277 }
278
279 #[test]
280 fn with_sizes_keeps_legacy_dynamic_flash_behavior() {
281 let mut mem = Memory::with_sizes(32 * 1024, 520 * 1024);
285 assert_eq!(mem.flash_size(), 0);
286 mem.load_flash(&[0x11, 0x22, 0x33, 0x44]);
287 assert_eq!(mem.flash_size(), 4);
288 assert_eq!(mem.xip_read32(0), 0x44332211);
289 }
290
291 #[test]
296 fn new_uses_rp2350_default_sizes() {
297 let mem = Memory::new();
298 assert_eq!(mem.rom_read8(ROM_SIZE as u32 - 1), 0);
301 assert_eq!(mem.flash_size(), 0);
303 }
304
305 #[test]
306 fn default_matches_new() {
307 let a = Memory::default();
310 let b = Memory::new();
311 assert_eq!(a.flash_size(), b.flash_size());
312 assert_eq!(a.sram_read8(SRAM_SIZE as u32 - 1), 0);
314 assert_eq!(b.sram_read8(SRAM_SIZE as u32 - 1), 0);
315 }
316
317 #[test]
322 fn rom_load_and_read_roundtrip() {
323 let mut mem = Memory::new();
324 let data: Vec<u8> = (0..ROM_SIZE as u32 + 64)
326 .map(|i| (i & 0xFF) as u8)
327 .collect();
328 mem.load_rom(&data);
329 assert_eq!(mem.rom_read8(0), 0x00);
331 assert_eq!(mem.rom_read8(1), 0x01);
332 let expected16 = u16::from_le_bytes([data[2], data[3]]);
334 assert_eq!(mem.rom_read16(2), expected16);
335 let expected32 = u32::from_le_bytes([data[4], data[5], data[6], data[7]]);
336 assert_eq!(mem.rom_read32(4), expected32);
337 }
338
339 #[test]
340 fn rom_reads_out_of_range_return_zero() {
341 let mut mem = Memory::new();
344 mem.load_rom(&[0xFF; 16]);
345 assert_eq!(mem.rom_read8(ROM_SIZE as u32), 0);
347 assert_eq!(mem.rom_read16(ROM_SIZE as u32 - 1), 0);
349 assert_eq!(mem.rom_read16(ROM_SIZE as u32), 0);
350 assert_eq!(mem.rom_read32(ROM_SIZE as u32 - 3), 0);
352 assert_eq!(mem.rom_read32(ROM_SIZE as u32), 0);
353 }
354
355 #[test]
360 fn sram_roundtrip_all_widths() {
361 let mut mem = Memory::new();
362 mem.sram_write8(0, 0xAB);
363 assert_eq!(mem.sram_read8(0), 0xAB);
364 mem.sram_write16(4, 0xBEEF);
365 assert_eq!(mem.sram_read16(4), 0xBEEF);
366 mem.sram_write32(8, 0xDEAD_BEEF);
367 assert_eq!(mem.sram_read32(8), 0xDEAD_BEEF);
368 }
369
370 #[test]
371 fn sram_reads_out_of_range_return_zero() {
372 let mem = Memory::new();
374 assert_eq!(mem.sram_read8(SRAM_SIZE as u32), 0);
375 assert_eq!(mem.sram_read16(SRAM_SIZE as u32 - 1), 0);
376 assert_eq!(mem.sram_read32(SRAM_SIZE as u32 - 3), 0);
377 }
378
379 #[test]
380 fn sram_writes_out_of_range_are_noops() {
381 let mut mem = Memory::new();
384 mem.sram_write8(SRAM_SIZE as u32 - 1, 0x5A);
386 mem.sram_write8(SRAM_SIZE as u32, 0xFF);
387 mem.sram_write16(SRAM_SIZE as u32 - 1, 0x1234);
389 mem.sram_write32(SRAM_SIZE as u32 - 3, 0xDEAD_BEEF);
391 assert_eq!(mem.sram_read8(SRAM_SIZE as u32 - 1), 0x5A);
393 assert_eq!(mem.sram_read8(SRAM_SIZE as u32 + 16), 0);
395 }
396
397 #[test]
398 fn sram_write_then_read_at_edge_valid() {
399 let mut mem = Memory::new();
402 let edge = SRAM_SIZE as u32 - 4;
403 mem.sram_write32(edge, 0xCAFE_F00D);
404 assert_eq!(mem.sram_read32(edge), 0xCAFE_F00D);
405 }
406
407 #[test]
412 fn xip_reads_out_of_range_return_zero() {
413 let mut mem = Memory::with_flash(16 * 1024, 264 * 1024, 16);
416 mem.load_flash(&[0xDE, 0xAD, 0xBE, 0xEF]);
417 assert_eq!(mem.xip_read16(0), 0xADDE);
419 assert_eq!(mem.xip_read16(2), 0xEFBE);
420 assert_eq!(mem.xip_read32(0), 0xEFBEADDE);
421 assert_eq!(mem.xip_read16(15), 0);
423 assert_eq!(mem.xip_read16(16), 0);
424 assert_eq!(mem.xip_read32(13), 0);
426 assert_eq!(mem.xip_read32(16), 0);
427 assert_eq!(mem.xip_read8(16), 0);
429 }
430
431 #[test]
432 fn xip_dynamic_mode_out_of_range_reads_zero() {
433 let mem = Memory::with_sizes(32 * 1024, 520 * 1024);
436 assert_eq!(mem.xip_read8(0), 0);
437 assert_eq!(mem.xip_read16(0), 0);
438 assert_eq!(mem.xip_read32(0), 0);
439 }
440
441 #[test]
446 fn peek_and_poke_cover_all_regions() {
447 let mut mem = Memory::with_flash(16, 64, 8);
450 mem.load_rom(&[0x11, 0x22, 0x33, 0x44]);
452 mem.load_flash(&[0xAA, 0xBB, 0xCC, 0xDD]);
453 assert_eq!(mem.peek8(0x0000_0000), 0x11);
455 assert_eq!(mem.peek32(0x0000_0000), 0x44332211);
456 assert_eq!(mem.peek8(0x1000_0000), 0xAA);
458 assert_eq!(mem.peek32(0x1000_0000), 0xDDCCBBAA);
459 mem.poke32(0x2000_0010, 0xF00D_CAFE);
461 assert_eq!(mem.peek32(0x2000_0010), 0xF00D_CAFE);
462 mem.poke8(0x2000_0020, 0x7E);
463 assert_eq!(mem.peek8(0x2000_0020), 0x7E);
464 assert_eq!(mem.peek8(0xE000_0000), 0);
466 assert_eq!(mem.peek32(0xE000_0000), 0);
467 mem.poke8(0x0000_0000, 0xFF); mem.poke32(0x1000_0000, 0xFFFF_FFFF); mem.poke8(0xE000_0000, 0xFF); mem.poke32(0xE000_0000, 0xFFFF_FFFF); assert_eq!(mem.peek8(0x2000_0020), 0x7E);
474 assert_eq!(mem.peek32(0x2000_0010), 0xF00D_CAFE);
475 }
476
477 #[test]
478 fn into_parts_yields_owned_buffers() {
479 let mut mem = Memory::with_flash(16, 64, 8);
482 mem.load_rom(&[0x77; 4]);
483 mem.sram_write8(3, 0xA5);
484 mem.load_flash(&[0x42; 2]);
485 let (rom, sram, xip) = mem.into_parts();
486 assert_eq!(rom.len(), 16);
487 assert_eq!(rom[..4], [0x77; 4]);
488 assert_eq!(sram.len(), 64);
489 assert_eq!(sram[3], 0xA5);
490 assert_eq!(xip.len(), 8);
491 assert_eq!(xip[..2], [0x42; 2]);
492 assert_eq!(xip[2..], [0u8; 6]);
494 }
495
496 #[test]
497 fn load_rom_clamps_to_rom_len_not_constant() {
498 let mut mem = Memory::with_sizes(16 * 1024, 0);
506 let data: Vec<u8> = (0..32 * 1024_u32).map(|i| (i & 0xFF) as u8).collect();
507 mem.load_rom(&data);
509 for i in 0..16 * 1024_u32 {
511 assert_eq!(mem.rom_read8(i), (i & 0xFF) as u8);
512 }
513 assert_eq!(mem.rom_read8(0x4000), 0);
517 assert_eq!(mem.rom_read32(0x4000), 0);
518 }
519
520 #[test]
521 fn with_sizes_zero_regions_are_usable() {
522 let mut mem = Memory::with_sizes(0, 0);
526 mem.load_rom(&[]);
527 mem.sram_write8(0, 0xFF);
528 mem.sram_write16(0, 0xFFFF);
529 mem.sram_write32(0, 0xFFFF_FFFF);
530 assert_eq!(mem.rom_read8(0), 0);
531 assert_eq!(mem.rom_read16(0), 0);
532 assert_eq!(mem.rom_read32(0), 0);
533 assert_eq!(mem.sram_read8(0), 0);
534 assert_eq!(mem.sram_read16(0), 0);
535 assert_eq!(mem.sram_read32(0), 0);
536 }
537}