rrs_lib/
memories.rs

1// Copyright 2021 Gregory Chadwick <mail@gregchadwick.co.uk>
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5//! Various [Memory] implementations useful for an ISS and utility functions
6
7use super::{MemAccessSize, Memory};
8use std::io;
9use std::io::Read;
10
11/// Read bytes from an [std::io::Read] into a [Memory] starting at the given address
12pub fn read_to_memory(
13    reader: impl Read,
14    memory: &mut impl Memory,
15    start_addr: u32,
16) -> io::Result<()> {
17    let mut write_addr = start_addr;
18    for b in reader.bytes() {
19        let b = b?;
20        if !memory.write_mem(write_addr, MemAccessSize::Byte, b as u32) {
21            return Err(io::Error::new(
22                io::ErrorKind::Other,
23                format!("Could not write byte at address 0x{:08x}", write_addr),
24            ));
25        }
26        write_addr += 1;
27    }
28
29    Ok(())
30}
31
32/// [Vec] backed memory.
33///
34/// The [Vec] uses `u32` as the base type. Any read or write that falls out of the [Vec]s size will
35/// result in a failed read or write.
36pub struct VecMemory {
37    pub mem: Vec<u32>,
38}
39
40impl VecMemory {
41    pub fn new(init_mem: Vec<u32>) -> VecMemory {
42        VecMemory { mem: init_mem }
43    }
44}
45
46impl Memory for VecMemory {
47    fn read_mem(&mut self, addr: u32, size: MemAccessSize) -> Option<u32> {
48        // Calculate a mask and shift to apply to a 32-bit word to get the required data
49        let (shift, mask) = match size {
50            MemAccessSize::Byte => (addr & 0x3, 0xff),
51            MemAccessSize::HalfWord => (addr & 0x2, 0xffff),
52            MemAccessSize::Word => (0, 0xffffffff),
53        };
54
55        if (addr & 0x3) != shift {
56            panic!("Memory read must be aligned");
57        }
58
59        // Calculate vector index required data is contained in
60        let word_addr = addr >> 2;
61
62        // Read data from vector
63        let read_data = self.mem.get(word_addr as usize).copied()?;
64
65        // Apply mask and shift to extract required data from word
66        Some((read_data >> (shift * 8)) & mask)
67    }
68
69    fn write_mem(&mut self, addr: u32, size: MemAccessSize, store_data: u32) -> bool {
70        // Calculate a mask and shift needed to update 32-bit word
71        let (shift, mask) = match size {
72            MemAccessSize::Byte => (addr & 0x3, 0xff),
73            MemAccessSize::HalfWord => (addr & 0x2, 0xffff),
74            MemAccessSize::Word => (0, 0xffffffff),
75        };
76
77        if (addr & 0x3) != shift {
78            panic!("Memory write must be aligned");
79        }
80
81        // `mask` << (shift * 8) gives bits being updated, invert to get bits not being updated
82        let write_mask = !(mask << (shift * 8));
83
84        // Calculate vector index data to update is contained in
85        let word_addr = (addr >> 2) as usize;
86
87        if let Some(update_data) = self.mem.get(word_addr) {
88            // Update word with store data, if it exists
89            let new = (update_data & write_mask) | ((store_data & mask) << (shift * 8));
90            self.mem[word_addr] = new;
91            true
92        } else {
93            false
94        }
95    }
96}
97
98struct MemoryRegion {
99    base: u32,
100    size: u32,
101    memory: Box<dyn Memory>,
102}
103
104/// A [Memory] that represents an address space forwarding reads and writes to other inner
105/// memories.
106///
107/// When reads and writes are forwarded to an inner memory the base address is adjusted appropriate
108/// (e.g. a [Memory] added with [MemorySpace::add_memory] at address `0x100000` will get a read at
109/// address `0x0` if the [MemorySpace] gets a read at `0x100000`
110///
111/// The inner memory regions cannot overlap and base addresses must be 32-bit aligned.
112pub struct MemorySpace {
113    memory_regions: Vec<MemoryRegion>,
114}
115
116#[derive(Debug, PartialEq)]
117pub enum MemorySpaceError {
118    RegionOverlap,
119    Unaligned,
120}
121
122impl MemorySpace {
123    pub fn new() -> Self {
124        MemorySpace {
125            memory_regions: Vec::new(),
126        }
127    }
128
129    // Returns true if region with given base and size overlaps with an existing region.
130    fn region_overlaps_existing(&self, base: u32, size: u32) -> bool {
131        for memory_region in self.memory_regions.iter() {
132            if base + size <= memory_region.base {
133                continue;
134            }
135
136            if memory_region.base + memory_region.size <= base {
137                continue;
138            }
139
140            return true;
141        }
142
143        false
144    }
145
146    // Gets the memory region that covers an address if it exists.
147    fn get_memory_region_by_addr(&mut self, addr: u32) -> Option<&mut MemoryRegion> {
148        for memory_region in self.memory_regions.iter_mut() {
149            if (addr >= memory_region.base) && (addr < (memory_region.base + memory_region.size)) {
150                return Some(memory_region);
151            }
152        }
153
154        None
155    }
156
157    /// Add an inner memory.
158    ///
159    /// When `Ok` is returned a memory index is provided which can be used with
160    /// [MemorySpace::get_memory_ref] and [MemorySpace::get_memory_mut] to get a reference to that
161    /// memory.
162    pub fn add_memory(
163        &mut self,
164        base: u32,
165        size: u32,
166        memory: Box<dyn Memory>,
167    ) -> Result<usize, MemorySpaceError> {
168        if ((base & 0x3) != 0) || ((size & 0x3) != 0) {
169            return Err(MemorySpaceError::Unaligned);
170        }
171
172        if self.region_overlaps_existing(base, size) {
173            return Err(MemorySpaceError::RegionOverlap);
174        }
175
176        let new_mem_index = self.memory_regions.len();
177        self.memory_regions
178            .push(MemoryRegion { base, size, memory });
179
180        Ok(new_mem_index)
181    }
182
183    /// Get a reference to an inner memory
184    ///
185    /// This performs downcasting to the provided `T`. `None` is returned where the downcast fails.
186    pub fn get_memory_ref<T: Memory>(&self, index: usize) -> Option<&T> {
187        self.memory_regions.get(index)?.memory.downcast_ref::<T>()
188    }
189
190    /// Get a mutable reference to an inner memory
191    ///
192    /// This performs downcasting to the provided `T`. `None` is returned where the downcast fails.
193    pub fn get_memory_mut<T: Memory>(&mut self, index: usize) -> Option<&mut T> {
194        self.memory_regions
195            .get_mut(index)?
196            .memory
197            .downcast_mut::<T>()
198    }
199}
200
201impl Default for MemorySpace {
202    fn default() -> Self {
203        Self::new()
204    }
205}
206
207impl Memory for MemorySpace {
208    fn read_mem(&mut self, addr: u32, size: MemAccessSize) -> Option<u32> {
209        let memory_region = self.get_memory_region_by_addr(addr)?;
210
211        memory_region
212            .memory
213            .read_mem(addr - memory_region.base, size)
214    }
215
216    fn write_mem(&mut self, addr: u32, size: MemAccessSize, store_data: u32) -> bool {
217        if let Some(memory_region) = self.get_memory_region_by_addr(addr) {
218            memory_region
219                .memory
220                .write_mem(addr - memory_region.base, size, store_data)
221        } else {
222            false
223        }
224    }
225}
226
227#[cfg(test)]
228mod tests {
229    use super::*;
230    #[test]
231    fn test_vec_memory() {
232        let mut test_mem = VecMemory::new(vec![0xdeadbeef, 0xbaadf00d]);
233
234        assert_eq!(test_mem.read_mem(0x0, MemAccessSize::Byte), Some(0xef));
235
236        assert_eq!(test_mem.read_mem(0x5, MemAccessSize::Byte), Some(0xf0));
237
238        assert_eq!(
239            test_mem.read_mem(0x6, MemAccessSize::HalfWord),
240            Some(0xbaad)
241        );
242
243        assert_eq!(
244            test_mem.read_mem(0x4, MemAccessSize::Word),
245            Some(0xbaadf00d)
246        );
247
248        assert_eq!(test_mem.write_mem(0x7, MemAccessSize::Byte, 0xff), true);
249
250        assert_eq!(
251            test_mem.write_mem(0x2, MemAccessSize::HalfWord, 0xaaaaface),
252            true
253        );
254
255        assert_eq!(
256            test_mem.write_mem(0x1, MemAccessSize::Byte, 0x1234abcd),
257            true
258        );
259
260        assert_eq!(
261            test_mem.read_mem(0x0, MemAccessSize::Word),
262            Some(0xfacecdef)
263        );
264
265        assert_eq!(
266            test_mem.read_mem(0x4, MemAccessSize::Word),
267            Some(0xffadf00d)
268        );
269
270        assert_eq!(test_mem.read_mem(0x8, MemAccessSize::Word), None);
271
272        assert_eq!(test_mem.write_mem(0x8, MemAccessSize::Word, 0x0), false);
273    }
274
275    struct TestMemory;
276
277    impl Memory for TestMemory {
278        fn read_mem(&mut self, _addr: u32, _size: MemAccessSize) -> Option<u32> {
279            Some(0x1234abcd)
280        }
281
282        fn write_mem(&mut self, _addr: u32, _size: MemAccessSize, _store_data: u32) -> bool {
283            true
284        }
285    }
286
287    #[test]
288    fn test_memory_space() {
289        let mem_1_vec = vec![0x11111111, 0x22222222];
290        let mem_2_vec = vec![0x33333333, 0x44444444, 0x55555555];
291
292        let mut test_mem_space = MemorySpace::new();
293
294        assert_eq!(
295            test_mem_space.add_memory(0x100, 8, Box::new(VecMemory::new(mem_1_vec))),
296            Ok(0)
297        );
298
299        assert_eq!(
300            test_mem_space.add_memory(0x200, 12, Box::new(VecMemory::new(mem_2_vec))),
301            Ok(1)
302        );
303
304        assert_eq!(
305            test_mem_space.add_memory(0x300, 0x100, Box::new(TestMemory {})),
306            Ok(2)
307        );
308
309        assert_eq!(
310            test_mem_space.add_memory(0x280, 0x100, Box::new(TestMemory {})),
311            Err(MemorySpaceError::RegionOverlap)
312        );
313
314        assert_eq!(
315            test_mem_space.add_memory(0x280, 0x80, Box::new(TestMemory {})),
316            Ok(3)
317        );
318
319        assert_eq!(
320            test_mem_space.add_memory(0x403, 0x100, Box::new(TestMemory {})),
321            Err(MemorySpaceError::Unaligned)
322        );
323
324        assert_eq!(
325            test_mem_space.add_memory(0x400, 0x103, Box::new(TestMemory {})),
326            Err(MemorySpaceError::Unaligned)
327        );
328
329        assert!(test_mem_space.get_memory_ref::<VecMemory>(0).is_some());
330        assert!(test_mem_space.get_memory_ref::<TestMemory>(0).is_none());
331        assert!(test_mem_space.get_memory_mut::<TestMemory>(2).is_some());
332        assert!(test_mem_space.get_memory_mut::<TestMemory>(1).is_none());
333
334        assert_eq!(
335            test_mem_space.read_mem(0x100, MemAccessSize::Word),
336            Some(0x11111111)
337        );
338
339        assert_eq!(
340            test_mem_space.read_mem(0x204, MemAccessSize::Word),
341            Some(0x44444444)
342        );
343
344        assert_eq!(
345            test_mem_space.write_mem(0x208, MemAccessSize::Word, 0xffffffff),
346            true
347        );
348
349        assert_eq!(
350            test_mem_space.write_mem(0x20c, MemAccessSize::Word, 0xffffffff),
351            false
352        );
353
354        assert_eq!(test_mem_space.read_mem(0x108, MemAccessSize::Word), None);
355
356        for i in 0..0x40 {
357            assert_eq!(
358                test_mem_space.read_mem(i * 4 + 0x300, MemAccessSize::Word),
359                Some(0x1234abcd)
360            );
361        }
362
363        assert_eq!(test_mem_space.read_mem(0x400, MemAccessSize::Word), None);
364
365        assert_eq!(
366            test_mem_space.get_memory_ref::<VecMemory>(1).unwrap().mem[2],
367            0xffffffff
368        );
369
370        test_mem_space.get_memory_mut::<VecMemory>(0).unwrap().mem[0] = 0xdeadbeef;
371
372        assert_eq!(
373            test_mem_space.read_mem(0x100, MemAccessSize::Word),
374            Some(0xdeadbeef)
375        );
376    }
377
378    #[test]
379    fn test_read_to_memory() {
380        let test_bytes: Vec<u8> = (5..21).collect();
381        let mut test_memory = VecMemory::new(vec![0; 4]);
382
383        assert!(read_to_memory(test_bytes.as_slice(), &mut test_memory, 0).is_ok());
384
385        for a in 0..16 {
386            assert_eq!(test_memory.read_mem(a, MemAccessSize::Byte), Some(a + 5));
387        }
388
389        let test_bytes: Vec<u8> = (10..15).collect();
390
391        assert!(read_to_memory(test_bytes.as_slice(), &mut test_memory, 5).is_ok());
392
393        for a in 5..10 {
394            assert_eq!(test_memory.read_mem(a, MemAccessSize::Byte), Some(a + 5));
395        }
396
397        assert_eq!(
398            format!(
399                "{:?}",
400                read_to_memory(test_bytes.as_slice(), &mut test_memory, 13)
401                    .unwrap_err()
402                    .get_ref()
403                    .unwrap()
404            ),
405            "\"Could not write byte at address 0x00000010\""
406        );
407    }
408}