89 lines
2.8 KiB
Rust
89 lines
2.8 KiB
Rust
use crate::operands::{Byte, ImmediateOperand, Word};
|
|
|
|
use super::interpreter::InterpreterError;
|
|
|
|
/// 2*20 = 1MiB
|
|
const MEMORY_SIZE: usize = 1048576;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Memory {
|
|
pub raw: Vec<Byte>,
|
|
}
|
|
|
|
impl Memory {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
// allocating is better for such bigger objects
|
|
raw: vec![0u8; MEMORY_SIZE],
|
|
}
|
|
}
|
|
|
|
/// 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_le_bytes([b1, b2]))
|
|
}
|
|
|
|
/// Try to read C null-terminated string from memory location
|
|
/// BUG: This does not use segment registers for indexing!
|
|
pub fn read_c_string(&self, addr: usize) -> Option<String> {
|
|
let mem = &self.raw;
|
|
|
|
if addr >= mem.len() {
|
|
return None;
|
|
}
|
|
|
|
let raw = &mem[addr..];
|
|
|
|
log::debug!("Raw is {:?}", &raw[..=16]);
|
|
|
|
let nul_pos = raw.iter().position(|&b| b == 0)?;
|
|
|
|
log::debug!("Starting to read at {addr} until {nul_pos}");
|
|
|
|
let c_slice = &raw[..=nul_pos];
|
|
let c_str = std::ffi::CStr::from_bytes_with_nul(c_slice).ok()?;
|
|
|
|
c_str.to_str().ok().map(|s| s.to_owned())
|
|
}
|
|
}
|