|
| 1 | +use super::Error; |
| 2 | + |
| 3 | +use byteorder::{LittleEndian, ReadBytesExt}; |
| 4 | +use std::io::{Cursor, Seek, SeekFrom}; |
| 5 | + |
| 6 | +pub trait Memory { |
| 7 | + fn mmap( |
| 8 | + &mut self, |
| 9 | + addr: usize, |
| 10 | + size: usize, |
| 11 | + source: &[u8], |
| 12 | + offset: usize, |
| 13 | + ) -> Result<usize, Error>; |
| 14 | + |
| 15 | + // TODO: maybe parameterize those? |
| 16 | + fn load16(&self, addr: usize) -> Result<u16, Error>; |
| 17 | + fn load32(&self, addr: usize) -> Result<u32, Error>; |
| 18 | +} |
| 19 | + |
| 20 | +// Here we build a flat memory based Memory object as a starting point for fast |
| 21 | +// iteration. Later we might want to re-evaluate this to see if we need a real |
| 22 | +// MMU system. |
| 23 | +// Current system is lacking the following features needed in a real production |
| 24 | +// system: |
| 25 | +// |
| 26 | +// * mmap should work on pages, not arbitrary memory segments |
| 27 | +// * disallow unaligned address on page boundary |
| 28 | +// * read/write/execute permission checking |
| 29 | +impl Memory for Vec<u8> { |
| 30 | + fn mmap( |
| 31 | + &mut self, |
| 32 | + addr: usize, |
| 33 | + size: usize, |
| 34 | + source: &[u8], |
| 35 | + offset: usize, |
| 36 | + ) -> Result<usize, Error> { |
| 37 | + if addr + size > self.len() || offset + size > source.len() { |
| 38 | + return Err(Error::OutOfBound); |
| 39 | + } |
| 40 | + let (_, right) = self.split_at_mut(addr); |
| 41 | + let (slice, _) = right.split_at_mut(size); |
| 42 | + slice.copy_from_slice(&source[offset..offset + size]); |
| 43 | + Ok(addr) |
| 44 | + } |
| 45 | + |
| 46 | + fn load16(&self, addr: usize) -> Result<u16, Error> { |
| 47 | + if addr + 4 > self.len() { |
| 48 | + return Err(Error::OutOfBound); |
| 49 | + } |
| 50 | + let mut reader = Cursor::new(&self); |
| 51 | + reader |
| 52 | + .seek(SeekFrom::Start(addr as u64)) |
| 53 | + .map_err(Error::IO)?; |
| 54 | + // NOTE: Base RISC-V ISA is defined as a little-endian memory system. |
| 55 | + reader.read_u16::<LittleEndian>().map_err(Error::IO) |
| 56 | + } |
| 57 | + |
| 58 | + fn load32(&self, addr: usize) -> Result<u32, Error> { |
| 59 | + if addr + 4 > self.len() { |
| 60 | + return Err(Error::OutOfBound); |
| 61 | + } |
| 62 | + let mut reader = Cursor::new(&self); |
| 63 | + reader |
| 64 | + .seek(SeekFrom::Start(addr as u64)) |
| 65 | + .map_err(Error::IO)?; |
| 66 | + // NOTE: Base RISC-V ISA is defined as a little-endian memory system. |
| 67 | + reader.read_u32::<LittleEndian>().map_err(Error::IO) |
| 68 | + } |
| 69 | +} |
0 commit comments