Files
8086-rs/src/interpreter/memory.rs

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