65 lines
2.1 KiB
Rust
65 lines
2.1 KiB
Rust
use crate::operands::{Byte, ImmediateOperand, Word};
|
|
|
|
use super::interpreter::InterpreterError;
|
|
|
|
/// 2*20 = 1MiB
|
|
const MEMORY_SIZE: usize = 1048576;
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub struct Memory {
|
|
pub raw: [Byte; MEMORY_SIZE as usize],
|
|
}
|
|
|
|
impl Memory {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
raw: [0; MEMORY_SIZE as usize],
|
|
}
|
|
}
|
|
|
|
/// Safely writes a [`ImmediateOperand`] into an index of memory.
|
|
/// Warning: Does access at `addr`, not `DS:addr`!
|
|
pub fn write_raw(&mut self, addr: Word, val: ImmediateOperand) -> Result<(), InterpreterError> {
|
|
match val {
|
|
ImmediateOperand::Byte(b) => {
|
|
if addr as usize > MEMORY_SIZE {
|
|
return Err(InterpreterError::MemoryOutOfBound(addr));
|
|
} else {
|
|
self.raw[addr as usize] = b;
|
|
log::debug!("Wrote raw byte {b:#04x} at addr {addr:#04x}");
|
|
}
|
|
}
|
|
ImmediateOperand::Word(w) => {
|
|
if (addr + 1) as usize > MEMORY_SIZE {
|
|
return Err(InterpreterError::MemoryOutOfBound(addr));
|
|
} else {
|
|
let [low, high] = w.to_le_bytes();
|
|
self.raw[addr as usize] = low;
|
|
self.raw[(addr + 1) as usize] = high;
|
|
log::debug!(
|
|
"Wrote raw byte {low:#04x} and {high:#04x}, starting at addr {addr:#04x}"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Safely reads a [`Word`] from an index of memory.
|
|
/// Warning: Does access at `addr`, not `DS:addr`!
|
|
pub fn read_raw(&self, addr: Word) -> Result<Word, InterpreterError> {
|
|
let b1 = self
|
|
.raw
|
|
.get(addr as usize)
|
|
.ok_or(InterpreterError::MemoryOutOfBound(addr))?
|
|
.to_owned();
|
|
let b2 = self
|
|
.raw
|
|
.get((addr + 1) as usize)
|
|
.ok_or(InterpreterError::MemoryOutOfBound(addr))?
|
|
.to_owned();
|
|
log::debug!("Read raw byte {b1:#04x} and {b2:#04x}, starting at addr {addr:#04x}");
|
|
Ok(Word::from_be_bytes([b2, b1]))
|
|
}
|
|
}
|