jurubas/crates/riscv-cpu/src/memory.rs

174 lines
4.7 KiB
Rust

/// Emulates main memory.
pub struct Memory { /// Memory content
data: Vec<u64>,
}
impl Memory {
/// Creates a new `Memory`
pub fn new() -> Self {
Memory { data: vec![] }
}
/// Initializes memory content.
/// This method is expected to be called only once.
///
/// # Arguments
/// * `capacity`
pub fn init(&mut self, capacity: u64) {
for _i in 0..((capacity + 7) / 8) {
self.data.push(0);
}
}
/// Reads a byte from memory.
///
/// # Arguments
/// * `address`
pub fn read_byte(&self, address: u64) -> u8 {
let index = (address >> 3) as usize;
let pos = (address % 8) * 8;
(self.data[index] >> pos) as u8
}
/// Reads two bytes from memory.
///
/// # Arguments
/// * `address`
pub fn read_halfword(&self, address: u64) -> u16 {
if (address % 2) == 0 {
let index = (address >> 3) as usize;
let pos = (address % 8) * 8;
(self.data[index] >> pos) as u16
} else {
self.read_bytes(address, 2) as u16
}
}
/// Reads four bytes from memory.
///
/// # Arguments
/// * `address`
pub fn read_word(&self, address: u64) -> u32 {
if (address % 4) == 0 {
let index = (address >> 3) as usize;
let pos = (address % 8) * 8;
(self.data[index] >> pos) as u32
} else {
self.read_bytes(address, 4) as u32
}
}
/// Reads eight bytes from memory.
///
/// # Arguments
/// * `address`
pub fn read_doubleword(&self, address: u64) -> u64 {
if (address % 8) == 0 {
let index = (address >> 3) as usize;
self.data[index]
} else if (address % 4) == 0 {
(self.read_word(address) as u64)
| ((self.read_word(address.wrapping_add(4)) as u64) << 4)
} else {
self.read_bytes(address, 8)
}
}
/// Reads multiple bytes from memory.
///
/// # Arguments
/// * `address`
/// * `width` up to eight
pub fn read_bytes(&self, address: u64, width: u64) -> u64 {
let mut data = 0;
for i in 0..width {
data |= (self.read_byte(address.wrapping_add(i)) as u64) << (i * 8);
}
data
}
/// Writes a byte to memory.
///
/// # Arguments
/// * `address`
/// * `value`
pub fn write_byte(&mut self, address: u64, value: u8) {
let index = (address >> 3) as usize;
let pos = (address % 8) * 8;
self.data[index] = (self.data[index] & !(0xff << pos)) | ((value as u64) << pos);
}
/// Writes two bytes to memory.
///
/// # Arguments
/// * `address`
/// * `value`
pub fn write_halfword(&mut self, address: u64, value: u16) {
if (address % 2) == 0 {
let index = (address >> 3) as usize;
let pos = (address % 8) * 8;
self.data[index] = (self.data[index] & !(0xffff << pos)) | ((value as u64) << pos);
} else {
self.write_bytes(address, value as u64, 2);
}
}
/// Writes four bytes to memory.
///
/// # Arguments
/// * `address`
/// * `value`
pub fn write_word(&mut self, address: u64, value: u32) {
if (address % 4) == 0 {
let index = (address >> 3) as usize;
let pos = (address % 8) * 8;
self.data[index] = (self.data[index] & !(0xffffffff << pos)) | ((value as u64) << pos);
} else {
self.write_bytes(address, value as u64, 4);
}
}
/// Writes eight bytes to memory.
///
/// # Arguments
/// * `address`
/// * `value`
pub fn write_doubleword(&mut self, address: u64, value: u64) {
if (address % 8) == 0 {
let index = (address >> 3) as usize;
self.data[index] = value;
} else if (address % 4) == 0 {
self.write_word(address, (value & 0xffffffff) as u32);
self.write_word(address.wrapping_add(4), (value >> 32) as u32);
} else {
self.write_bytes(address, value, 8);
}
}
/// Write multiple bytes to memory.
///
/// # Arguments
/// * `address`
/// * `value`
/// * `width` up to eight
pub fn write_bytes(&mut self, address: u64, value: u64, width: u64) {
for i in 0..width {
self.write_byte(address.wrapping_add(i), (value >> (i * 8)) as u8);
}
}
/// Check if the address is valid memory address
///
/// # Arguments
/// * `address`
pub fn validate_address(&self, address: u64) -> bool {
(address as usize) < self.data.len()
}
}
impl Default for Memory {
fn default() -> Self {
Self::new()
}
}