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, } 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 { 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 { 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()) } }