1use std::{fs, path::Path};
2
3use log::info;
4use serde::{Deserialize, Serialize};
5
6pub use lib_rv32_isa::traits::Memory as MemoryTrait;
7use lib_rv32_isa::{common::bit_slice, RiscvError};
8
9#[derive(Clone, Serialize, Deserialize)]
11pub struct Memory {
12 pub size: usize,
13 mem: Vec<u8>,
14}
15
16impl Memory {
17 pub fn new(size: usize) -> Self {
19 assert!(size % 4 == 0);
20 assert!(size > 0);
21
22 Memory {
23 size,
24 mem: vec![0; size],
25 }
26 }
27
28 fn read(&self, base: usize, size: usize, log: bool) -> Result<u32, RiscvError> {
30 if base % size != 0 {
32 return Err(RiscvError::MemoryAlignmentError(base as u32));
33 } else if base >= self.size as usize {
35 return Err(RiscvError::MemoryOutOfBoundsError(base as u32));
36 }
37
38 let data = self.mem[base..base + size]
39 .iter()
40 .enumerate()
41 .map(|(i, b)| ((*b as u32) << (i * 8)) as u32)
42 .sum();
43
44 if log {
45 match size {
46 1 => info!("(byte *)0x{:08x} = 0x{:x} ({})", base, data, data as i32),
47 2 => info!(
48 "(half-word *)0x{:08x} = 0x{:x} ({})",
49 base, data, data as i32
50 ),
51 4 => info!("(word *)0x{:08x} = 0x{:x} ({})", base, data, data as i32),
52 _ => (),
53 }
54 }
55
56 Ok(data)
57 }
58
59 fn write(&mut self, base: usize, data: u32, size: usize, log: bool) -> Result<(), RiscvError> {
61 if log {
62 match size {
63 1 => info!("(byte *)0x{:08x} <- 0x{:x} ({})", base, data, data as i32),
64 2 => info!(
65 "(half-word *)0x{:08x} <- 0x{:x} ({})",
66 base, data, data as i32
67 ),
68 4 => info!("(word *)0x{:08x} <- 0x{:x} ({})", base, data, data as i32),
69 _ => (),
70 }
71 }
72
73 if base % size != 0 {
75 return Err(RiscvError::MemoryAlignmentError(base as u32));
76 } else if base >= self.size as usize {
78 return Err(RiscvError::MemoryOutOfBoundsError(base as u32));
79 }
80
81 for (i, b) in self.mem[base..base + size].iter_mut().enumerate() {
82 *b = bit_slice!(data, 8 * (i + 1), 8 * i) as u8;
83 }
84
85 Ok(())
86 }
87
88 pub fn program_le_bytes(&mut self, bytes: &[u8]) -> Result<(), RiscvError> {
90 for (word_addr, chunk) in bytes.chunks(4).enumerate() {
91 for (byte_offset, byte) in chunk.iter().enumerate() {
92 if let Err(why) = self.write(word_addr * 4 + byte_offset, *byte as u32, 1, false) {
93 return Err(why);
94 }
95 }
96 }
97 Ok(())
98 }
99
100 pub fn program_words(&mut self, words: &[u32]) -> Result<(), RiscvError> {
102 for (addr, word) in words.iter().enumerate() {
103 if let Err(why) = self.write(addr * 4, *word as u32, 4, false) {
104 return Err(why);
105 }
106 }
107 Ok(())
108 }
109
110 pub fn program_from_file(&mut self, path: &Path) -> Result<u32, RiscvError> {
112 let prog_bytes = fs::read(&path).expect("Could not read binary.");
113 match self.program_le_bytes(&prog_bytes) {
114 Err(why) => Err(why),
115 Ok(_) => Ok(prog_bytes.len() as u32),
116 }
117 }
118}
119
120impl MemoryTrait for Memory {
122 fn fetch(&self, pc: u32) -> Result<u32, RiscvError> {
123 self.read(pc as usize, 4, false)
124 }
125
126 fn read_word(&self, addr: u32) -> Result<u32, RiscvError> {
127 self.read(addr as usize, 4, true)
128 }
129
130 fn read_half_word(&self, addr: u32) -> Result<u32, RiscvError> {
131 match self.read(addr as usize, 2, true) {
132 Ok(d) => Ok(d),
133 Err(why) => Err(why),
134 }
135 }
136 fn read_byte(&self, addr: u32) -> Result<u32, RiscvError> {
137 match self.read(addr as usize, 1, true) {
138 Ok(d) => Ok(d),
139 Err(why) => Err(why),
140 }
141 }
142
143 fn write_word(&mut self, addr: u32, data: u32) -> Result<(), RiscvError> {
144 self.write(addr as usize, data, 4, true)
145 }
146
147 fn write_half_word(&mut self, addr: u32, data: u32) -> Result<(), RiscvError> {
148 self.write(addr as usize, data as u32, 2, true)
149 }
150
151 fn write_byte(&mut self, addr: u32, data: u32) -> Result<(), RiscvError> {
152 self.write(addr as usize, data as u32, 1, true)
153 }
154}
155
156#[cfg(test)]
157mod test {
158 use super::*;
159
160 #[test]
161 #[should_panic]
162 fn test_create_misaligned() {
163 let _ = Memory::new(3);
164 }
165
166 #[test]
167 #[should_panic]
168 fn test_create_zero() {
169 let _ = Memory::new(0);
170 }
171
172 #[test]
173 fn test_out_of_bounds() {
174 let mem = Memory::new(1024);
175 match mem.read_byte(1028) {
176 Err(why) => assert_eq!(why, RiscvError::MemoryOutOfBoundsError(1028)),
177 _ => panic!(),
178 };
179 }
180
181 #[test]
182 fn test_misaligned() {
183 let mut mem = Memory::new(1024);
184
185 match mem.read_half_word(3) {
186 Err(why) => assert_eq!(why, RiscvError::MemoryAlignmentError(3)),
187 _ => panic!(),
188 };
189 match mem.read_word(2) {
190 Err(why) => assert_eq!(why, RiscvError::MemoryAlignmentError(2)),
191 _ => panic!(),
192 };
193 match mem.write_half_word(3, 0) {
194 Err(why) => assert_eq!(why, RiscvError::MemoryAlignmentError(3)),
195 _ => panic!(),
196 };
197 match mem.write_word(2, 0) {
198 Err(why) => assert_eq!(why, RiscvError::MemoryAlignmentError(2)),
199 _ => panic!(),
200 };
201 }
202
203 #[test]
204 fn test_create() {
205 let mem = Memory::new(1024);
206 assert_eq!(1024, mem.size);
207 }
208
209 #[test]
210 fn test_byte() {
211 let mut mem = Memory::new(1024);
212
213 for data in 0..0xFF {
214 for addr in 0..16 {
215 mem.write_byte(addr, data).unwrap();
216 assert_eq!(data, mem.read_byte(addr).unwrap());
217 }
218 }
219 }
220
221 #[test]
222 fn test_half_word_write() {
223 const ADDR: u32 = 0x02;
224 let mut mem = Memory::new(1024);
225
226 mem.write_half_word(ADDR, 0x1712).unwrap();
227
228 assert_eq!(mem.mem[ADDR as usize], 0x12);
230 assert_eq!(mem.mem[(ADDR + 1) as usize], 0x17);
231 }
232
233 #[test]
234 fn test_half_word_read() {
235 const ADDR: u32 = 0x02;
236 let mut mem = Memory::new(1024);
237
238 mem.mem[ADDR as usize] = 0x12;
240 mem.mem[(ADDR + 1) as usize] = 0x17;
241
242 assert_eq!(0x1712, mem.read_half_word(ADDR).unwrap());
243 }
244
245 #[test]
246 fn test_half_word_read_write() {
247 const ADDR: u32 = 0x02;
248 let mut mem = Memory::new(1024);
249 for data in 0..0xFFFF {
250 mem.write_half_word(ADDR, data).unwrap();
251 assert_eq!(data, mem.read_half_word(ADDR).unwrap());
252 }
253 }
254
255 #[test]
256 fn test_word_write() {
257 const ADDR: u32 = 0x04;
258 let mut mem = Memory::new(1024);
259
260 mem.write_word(ADDR, 0x76821712).unwrap();
261
262 assert_eq!(mem.mem[ADDR as usize], 0x12);
264 assert_eq!(mem.mem[(ADDR + 1) as usize], 0x17);
265 assert_eq!(mem.mem[(ADDR + 2) as usize], 0x82);
266 assert_eq!(mem.mem[(ADDR + 3) as usize], 0x76);
267 }
268
269 #[test]
270 fn test_word_read() {
271 const ADDR: u32 = 0x04;
272 let mut mem = Memory::new(1024);
273
274 mem.mem[ADDR as usize] = 0x12;
276 mem.mem[(ADDR + 1) as usize] = 0x17;
277 mem.mem[(ADDR + 2) as usize] = 0x82;
278 mem.mem[(ADDR + 3) as usize] = 0x76;
279
280 assert_eq!(0x76821712, mem.read_word(ADDR).unwrap());
281 }
282
283 #[test]
284 fn test_word_read_write() {
285 const ADDR: u32 = 0x04;
286 let mut mem = Memory::new(1024);
287 for data in 0xFE000000..0xFE100000 {
288 mem.write_word(ADDR, data).unwrap();
289 assert_eq!(data, mem.read_word(ADDR).unwrap());
290 }
291 }
292
293 #[test]
294 fn test_program_little_endian() {
295 const NUM: u32 = 0x12345678;
296 const LE_BYTES: [u8; 4] = [0x78, 0x56, 0x34, 0x12];
297
298 let mut mem = Memory::new(1024);
299 mem.program_le_bytes(&LE_BYTES).unwrap();
300
301 assert_eq!(NUM, mem.read_word(0).unwrap());
302 }
303}