From 5a61eb5fd65ce7d81e286b96bfd02ea522d145d6 Mon Sep 17 00:00:00 2001 From: Marco Thomas Date: Wed, 18 Jun 2025 17:03:01 +0900 Subject: [PATCH] ft(interpreter): use DS and SS sregs as correct segment offsets --- src/interpreter/computer.rs | 13 +++++----- src/interpreter/interpreter.rs | 30 +++++++++++++++------- src/interpreter/memory.rs | 47 ++++++++++++++++++++++------------ 3 files changed, 58 insertions(+), 32 deletions(-) diff --git a/src/interpreter/computer.rs b/src/interpreter/computer.rs index 4627bf4..ab9cc94 100644 --- a/src/interpreter/computer.rs +++ b/src/interpreter/computer.rs @@ -39,12 +39,13 @@ impl Computer { /// Decrement stack pointer and write `val` onto the stack. pub fn push_stack(&mut self, val: ImmediateOperand) -> Result<(), InterpreterError> { self.regs.push()?; - self.memory.write_raw(self.regs.sp, val.into()) + self.memory + .write_raw(&self.sregs.ss * 16 + self.regs.sp, val.into()) } /// Retrieve value from stack and increment stack pointer. pub fn pop_stack(&mut self) -> Result { - let word = self.memory.read_raw(self.regs.sp)?; + let word = self.memory.read_raw(&self.sregs.ss * 16 + self.regs.sp)?; self.regs.pop()?; Ok(word) } @@ -153,7 +154,7 @@ impl Computer { ArithmeticOperand::ModRmTarget(mod_rm_target) => { ArithmeticOperand::Immediate(match mod_rm_target { ModRmTarget::Memory(idx) => { - (self.memory.read(&self.regs, idx) + cf as u16).into() + (self.memory.read(&self.regs, &self.sregs, idx) + cf as u16).into() } ModRmTarget::Register(reg) => self.regs.read(reg) + cf, }) @@ -181,7 +182,7 @@ impl Computer { ArithmeticOperand::ModRmTarget(mod_rm_target) => { ArithmeticOperand::Immediate(match mod_rm_target { ModRmTarget::Memory(idx) => { - (self.memory.read(&self.regs, idx) + cf as u16).into() + (self.memory.read(&self.regs, &self.sregs, idx) + cf as u16).into() } ModRmTarget::Register(reg) => self.regs.read(reg) + cf, }) @@ -228,7 +229,7 @@ impl Computer { /// Write an [`ImmediateOperand`] into [`Self::memory`] or [`Self::regs`]. pub fn write_modrm(&mut self, target: ModRmTarget, val: ImmediateOperand) { match target { - ModRmTarget::Memory(idx) => self.memory.write(&self.regs, idx, val), + ModRmTarget::Memory(idx) => self.memory.write(&self.regs, &self.sregs, idx, val), ModRmTarget::Register(reg) => self.regs.write(reg, val), }; } @@ -236,7 +237,7 @@ impl Computer { /// Read an [`ImmediateOperand`] from [`Self::memory`] or [`Self::regs`]. pub fn read_modrm(&self, target: ModRmTarget) -> ImmediateOperand { match target { - ModRmTarget::Memory(idx) => self.memory.read(&self.regs, idx).into(), + ModRmTarget::Memory(idx) => self.memory.read(&self.regs, &self.sregs, idx).into(), ModRmTarget::Register(reg) => self.regs.read(reg), } } diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index 2ea4713..879d114 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -125,9 +125,15 @@ impl Interpreter { } Mnemonic::POP_M(idx) => { let val = self.computer.pop_stack()?.into(); - self.computer - .memory - .write_raw(Memory::calc_memidx(&self.computer.regs, idx).into(), val)? + self.computer.memory.write_raw( + Memory::absolute_addr_from_idx( + &self.computer.regs, + &self.computer.sregs, + idx, + ) + .into(), + val, + )? } Mnemonic::POP_S(_) => todo!(), @@ -430,7 +436,10 @@ impl Interpreter { &self.instructions, &mut ip, &self.computer.sregs, - self.computer.memory.read(&self.computer.regs, idx).into(), + self.computer + .memory + .read(&self.computer.regs, &self.computer.sregs, idx) + .into(), ), ModRmTarget::Register(register) => Self::ip_jump( &self.instructions, @@ -563,9 +572,12 @@ impl Interpreter { */ Mnemonic::LEA(target, reg) => { let val = match target { - ModRmTarget::Memory(idx) => { - Memory::calc_memidx(&self.computer.regs, idx).into() - } + ModRmTarget::Memory(idx) => Memory::absolute_addr_from_idx( + &self.computer.regs, + &self.computer.sregs, + idx, + ) + .into(), ModRmTarget::Register(reg) => self.computer.regs.read(reg), }; self.computer.regs.write(reg, val); @@ -709,7 +721,7 @@ impl Interpreter { Mnemonic::SHR_b(target, b) => self .computer .write_modrm(target, self.computer.read_modrm(target) >> b), - Mnemonic::SAR_b(target, b) => todo!(), + Mnemonic::SAR_b(_, _) => todo!(), Mnemonic::SHL_fromReg(target, reg) => self.computer.write_modrm( target, self.computer.read_modrm(target) << self.computer.regs.read(reg), @@ -718,7 +730,7 @@ impl Interpreter { target, self.computer.read_modrm(target) >> self.computer.regs.read(reg), ), - Mnemonic::SAR_fromReg(target, reg) => todo!(), + Mnemonic::SAR_fromReg(_, _) => todo!(), /* * IN diff --git a/src/interpreter/memory.rs b/src/interpreter/memory.rs index a2a398c..b98ca12 100644 --- a/src/interpreter/memory.rs +++ b/src/interpreter/memory.rs @@ -1,6 +1,7 @@ use crate::operands::{Byte, Displacement, ImmediateOperand, MemoryIndex, Word}; use super::interpreter::InterpreterError; +use crate::interpreter::register::{Register, SegmentRegister}; /// 2*20 = 1MiB const MEMORY_SIZE: usize = 1048576; @@ -18,28 +19,30 @@ impl Memory { } /// Safely writes a [`Word`] into an index of memory. - pub fn write_raw(&mut self, idx: Word, val: Word) -> Result<(), InterpreterError> { - if (idx + 1) as usize > MEMORY_SIZE { - return Err(InterpreterError::MemoryOutOfBound(idx)); + /// Warning: Does access at `addr`, not `DS:addr`! + pub fn write_raw(&mut self, addr: Word, val: Word) -> Result<(), InterpreterError> { + if (addr + 1) as usize > MEMORY_SIZE { + return Err(InterpreterError::MemoryOutOfBound(addr)); } else { let [low, high] = val.to_le_bytes(); - self.memory[idx as usize] = low; - self.memory[(idx + 1) as usize] = high; + self.memory[addr as usize] = low; + self.memory[(addr + 1) as usize] = high; Ok(()) } } - /// Safely reads a [`Word`] from an index of memory - pub fn read_raw(&self, idx: Word) -> Result { + /// 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 .memory - .get(idx as usize) - .ok_or(InterpreterError::MemoryOutOfBound(idx))? + .get(addr as usize) + .ok_or(InterpreterError::MemoryOutOfBound(addr))? .to_owned(); let b2 = self .memory - .get((idx + 1) as usize) - .ok_or(InterpreterError::MemoryOutOfBound(idx))? + .get((addr + 1) as usize) + .ok_or(InterpreterError::MemoryOutOfBound(addr))? .to_owned(); Ok(Word::from_be_bytes([b2, b1])) } @@ -47,11 +50,12 @@ impl Memory { /// Write an [`ImmediateOperand`] to a memory location indexed by a [`MemoryIndex`]. pub fn write( &mut self, - regs: &crate::interpreter::register::Register, + regs: &Register, + sregs: &SegmentRegister, idx: MemoryIndex, val: ImmediateOperand, ) { - let idx = Memory::calc_memidx(regs, idx); + let idx = Memory::absolute_addr_from_idx(regs, sregs, idx); match val { ImmediateOperand::Byte(b) => { log::debug!("Writing byte {b:#04x} to memory location {idx:#04x}"); @@ -72,16 +76,25 @@ impl Memory { /// Read into memory with a [`MemoryIndex`] as index. /// Always reads a whole word. - pub fn read(&self, regs: &crate::interpreter::register::Register, idx: MemoryIndex) -> Word { - let idx = Self::calc_memidx(regs, idx); + pub fn read(&self, regs: &Register, sregs: &SegmentRegister, idx: MemoryIndex) -> Word { + let idx = Self::absolute_addr_from_idx(regs, sregs, idx); let byte1 = idx / 2; let byte2 = idx / 2 + 1; log::debug!("Reading bytes {byte1:#04x} and {byte2:#04x} from memory"); Word::from_le_bytes([self.memory[byte1 as usize], self.memory[byte2 as usize]]) } + /// Memory is always accessed with the data segment `ds` register as an offset. + fn addr_offset(addr: Word, sregs: &crate::interpreter::register::SegmentRegister) -> Word { + sregs.ds * 16 + addr + } + /// Calculate the absolute memory address from a [`MemoryIndex`] struct. - pub fn calc_memidx(regs: &crate::interpreter::register::Register, idx: MemoryIndex) -> Word { + pub fn absolute_addr_from_idx( + regs: &Register, + sregs: &SegmentRegister, + idx: MemoryIndex, + ) -> Word { let mut base = ImmediateOperand::Word(0); let mut index = ImmediateOperand::Word(0); let mut disp = Displacement::IWord(0); @@ -96,6 +109,6 @@ impl Memory { disp = displacement; } - (base + index + disp).into() + Self::addr_offset((base + index + disp).into(), sregs) } }