diff --git a/README.md b/README.md index c77bd6f..3a20ede 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ It includes: - a.out Parser to parse legacy MINIX 1.x executables. - 8086 disassembler to parse the 16-bit instructions into an IR and prints them in a `objdump(1)`-style fashion. -- 8086 interpreter which interprets the instructions with MINIX 1.x conventions (e.g. interrupts, memory layout, ...) in mind. +- 8086 interpreter which interprets the instructions with MINIX 1.x conventions (e.g. interrupts, memory layout, ...) in mind and obeys segment register indirection, which enables the usage of the entire 20-bit memory bus. ## Usage diff --git a/src/interpreter/computer.rs b/src/interpreter/computer.rs index ab9cc94..a55d2d9 100644 --- a/src/interpreter/computer.rs +++ b/src/interpreter/computer.rs @@ -1,6 +1,6 @@ use core::fmt; -use crate::operands::{ImmediateOperand, ModRmTarget, Word}; +use crate::operands::{ImmediateOperand, ImmediateOperandSigned, MemoryIndex, ModRmTarget, Word}; use super::{ flags::Flags, interpreter::InterpreterError, memory::Memory, register::Register, @@ -38,20 +38,32 @@ 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.sregs.ss * 16 + self.regs.sp, val.into()) + self.regs.push_sp()?; + self.memory.write_raw( + self.mem_addr( + ImmediateOperand::from(self.regs.sp).into(), + &crate::register::SegmentRegister::SS, + ), + val.into(), + ) } /// Retrieve value from stack and increment stack pointer. pub fn pop_stack(&mut self) -> Result { - let word = self.memory.read_raw(&self.sregs.ss * 16 + self.regs.sp)?; - self.regs.pop()?; + let word = self.memory.read_raw(self.mem_addr( + ImmediateOperand::from(self.regs.sp).into(), + &crate::register::SegmentRegister::SS, + ))?; + self.regs.pop_sp()?; Ok(word) } /// Perform binary `dest` = `dest` + `src`. Sets flags. - pub fn add(&mut self, dest: ModRmTarget, src: ArithmeticOperand) { + pub fn add( + &mut self, + dest: ModRmTarget, + src: ArithmeticOperand, + ) -> Result<(), InterpreterError> { let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs + rhs; let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, lhs, rhs| { flags.cf = result < rhs; @@ -60,11 +72,15 @@ impl Computer { flags.sf = result.msb(); flags.pf = result.parity(); }; - self.op(op, flag_set, true, dest, src); + self.op(op, flag_set, true, dest, src) } /// Perform binary `dest` = `dest` - `src`. Sets flags. - pub fn sub(&mut self, dest: ModRmTarget, src: ArithmeticOperand) { + pub fn sub( + &mut self, + dest: ModRmTarget, + src: ArithmeticOperand, + ) -> Result<(), InterpreterError> { let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs - rhs; let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, lhs, rhs| { flags.cf = lhs < rhs; @@ -73,11 +89,15 @@ impl Computer { flags.sf = result.msb(); flags.pf = result.parity(); }; - self.op(op, flag_set, true, dest, src); + self.op(op, flag_set, true, dest, src) } /// Perform binary `dest` = `dest` | `src`. Sets flags. - pub fn or(&mut self, dest: ModRmTarget, src: ArithmeticOperand) { + pub fn or( + &mut self, + dest: ModRmTarget, + src: ArithmeticOperand, + ) -> Result<(), InterpreterError> { let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs | rhs; let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, _, _| { flags.cf = false; @@ -86,11 +106,15 @@ impl Computer { flags.sf = result.msb(); flags.pf = result.parity(); }; - self.op(op, flag_set, true, dest, src); + self.op(op, flag_set, true, dest, src) } /// Perform binary `dest` = `dest` & `src`. Sets flags. - pub fn and(&mut self, dest: ModRmTarget, src: ArithmeticOperand) { + pub fn and( + &mut self, + dest: ModRmTarget, + src: ArithmeticOperand, + ) -> Result<(), InterpreterError> { let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs & rhs; let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, _, _rhs| { flags.cf = false; @@ -99,11 +123,15 @@ impl Computer { flags.sf = result.msb(); flags.pf = result.parity(); }; - self.op(op, flag_set, true, dest, src); + self.op(op, flag_set, true, dest, src) } /// Perform binary `dest` = `dest` ^ `src`. Sets flags. - pub fn xor(&mut self, dest: ModRmTarget, src: ArithmeticOperand) { + pub fn xor( + &mut self, + dest: ModRmTarget, + src: ArithmeticOperand, + ) -> Result<(), InterpreterError> { let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs ^ rhs; let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, _, _| { flags.cf = false; @@ -112,12 +140,16 @@ impl Computer { flags.sf = result.msb(); flags.pf = result.parity(); }; - self.op(op, flag_set, true, dest, src); + self.op(op, flag_set, true, dest, src) } /// Perform compare operation, which acts like [`Self::sub()`], but without /// saving the result and only setting [`Self::flags`]. - pub fn cmp(&mut self, dest: ModRmTarget, src: ArithmeticOperand) { + pub fn cmp( + &mut self, + dest: ModRmTarget, + src: ArithmeticOperand, + ) -> Result<(), InterpreterError> { let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs - rhs; let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, lhs, rhs| { flags.cf = lhs < rhs; @@ -126,12 +158,16 @@ impl Computer { flags.sf = result.msb(); flags.pf = result.parity(); }; - self.op(op, flag_set, false, dest, src); + self.op(op, flag_set, false, dest, src) } /// Perform test operation, which acts like [`Self::and()`], but without /// saving the result and only setting [`Self::flags`]. - pub fn test(&mut self, dest: ModRmTarget, src: ArithmeticOperand) { + pub fn test( + &mut self, + dest: ModRmTarget, + src: ArithmeticOperand, + ) -> Result<(), InterpreterError> { let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs & rhs; let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, _, _| { flags.cf = false; @@ -140,11 +176,15 @@ impl Computer { flags.sf = result.msb(); flags.pf = result.parity(); }; - self.op(op, flag_set, false, dest, src); + self.op(op, flag_set, false, dest, src) } /// Perform `dest` = `dest` + `src` + CF. Sets flags. - pub fn adc(&mut self, dest: ModRmTarget, src: ArithmeticOperand) { + pub fn adc( + &mut self, + dest: ModRmTarget, + src: ArithmeticOperand, + ) -> Result<(), InterpreterError> { let cf = self.flags.cf as u8; // cheating, by flattening into immediates, but this allows to easily add the opt. carry let src_with_carry = match src { @@ -153,9 +193,7 @@ impl Computer { } ArithmeticOperand::ModRmTarget(mod_rm_target) => { ArithmeticOperand::Immediate(match mod_rm_target { - ModRmTarget::Memory(idx) => { - (self.memory.read(&self.regs, &self.sregs, idx) + cf as u16).into() - } + ModRmTarget::Memory(idx) => (self.read(idx).unwrap() + cf as u16).into(), ModRmTarget::Register(reg) => self.regs.read(reg) + cf, }) } @@ -168,11 +206,15 @@ impl Computer { flags.sf = result.msb(); flags.pf = result.parity(); }; - self.op(op, flag_set, true, dest, src_with_carry); + self.op(op, flag_set, true, dest, src_with_carry) } /// Perform `dest` = `dest` - (`src` + CF). Sets flags. - pub fn sbb(&mut self, dest: ModRmTarget, src: ArithmeticOperand) { + pub fn sbb( + &mut self, + dest: ModRmTarget, + src: ArithmeticOperand, + ) -> Result<(), InterpreterError> { let cf = self.flags.cf as u8; // cheating, by flattening into immediates, but this allows to easily add the opt. carry let src_with_carry = match src { @@ -181,9 +223,7 @@ impl Computer { } ArithmeticOperand::ModRmTarget(mod_rm_target) => { ArithmeticOperand::Immediate(match mod_rm_target { - ModRmTarget::Memory(idx) => { - (self.memory.read(&self.regs, &self.sregs, idx) + cf as u16).into() - } + ModRmTarget::Memory(idx) => (self.read(idx)? + cf as u16).into(), ModRmTarget::Register(reg) => self.regs.read(reg) + cf, }) } @@ -196,7 +236,7 @@ impl Computer { flags.sf = result.msb(); flags.pf = result.parity(); }; - self.op(op, flag_set, true, dest, src_with_carry); + self.op(op, flag_set, true, dest, src_with_carry) } /// Applies a binary operator [`O`] to the value of two [`Operand`]s, saves @@ -210,46 +250,102 @@ impl Computer { write: bool, dest: ModRmTarget, src: ArithmeticOperand, - ) where + ) -> Result<(), InterpreterError> + where O: Fn(Lhs, Rhs) -> ArithmeticResult, F: Fn(&mut Flags, ArithmeticResult, Lhs, Rhs), { - let lhs = self.read_modrm(dest); + let lhs = self.read_modrm(dest)?; let rhs = match src { ArithmeticOperand::Immediate(imm) => imm, - ArithmeticOperand::ModRmTarget(target) => self.read_modrm(target), + ArithmeticOperand::ModRmTarget(target) => self.read_modrm(target)?, }; let result = op(lhs, rhs); if write { - self.write_modrm(dest, result); + self.write_modrm(dest, result)?; } flag_set(&mut self.flags, result, lhs, rhs); + + Ok(()) + } + + /// Finds the memory address to a [`MemoryIndex`], obeying either the `DS` + /// or `SS` segment register. + pub fn mem_addr( + &self, + idx: MemoryIndex, + segment_selector: &crate::register::SegmentRegister, + ) -> Word { + let mut base = ImmediateOperand::Word(0); + let mut index = ImmediateOperand::Word(0); + let mut disp = ImmediateOperandSigned::Word(0); + + if let Some(base_reg) = idx.base { + base = self.regs.read(base_reg); + }; + if let Some(index_reg) = idx.index { + index = self.regs.read(index_reg); + }; + if let Some(displacement) = idx.displacement { + disp = ImmediateOperandSigned::from(displacement); + } + + let factor = match segment_selector { + crate::register::SegmentRegister::DS => self.sregs.ds * 16, + crate::register::SegmentRegister::SS => self.sregs.ss * 16, + _ => 0, + }; + (ImmediateOperand::from(factor) + base + index + disp).into() + } + + /// Write an [`ImmediateOperand`] into memory, index by an [`MemoryIndex`], accessed at `DS:idx` + pub fn write( + &mut self, + val: ImmediateOperand, + idx: MemoryIndex, + ) -> Result<(), InterpreterError> { + let addr = self.mem_addr(idx, &crate::register::SegmentRegister::DS); + self.memory.write_raw(addr, val) + } + + /// Read into memory, index by a [`MemoryIndex`], accessed at `DS:idx` + /// Always reads a whole word. + pub fn read(&self, idx: MemoryIndex) -> Result { + let addr = self.mem_addr(idx, &crate::register::SegmentRegister::DS); + self.memory.read_raw(addr) } /// Write an [`ImmediateOperand`] into [`Self::memory`] or [`Self::regs`]. - pub fn write_modrm(&mut self, target: ModRmTarget, val: ImmediateOperand) { + pub fn write_modrm( + &mut self, + target: ModRmTarget, + val: ImmediateOperand, + ) -> Result<(), InterpreterError> { match target { - ModRmTarget::Memory(idx) => self.memory.write(&self.regs, &self.sregs, idx, val), + ModRmTarget::Memory(idx) => self.write(val.into(), idx)?, ModRmTarget::Register(reg) => self.regs.write(reg, val), }; + Ok(()) } /// 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, &self.sregs, idx).into(), + pub fn read_modrm(&self, target: ModRmTarget) -> Result { + let imm = match target { + ModRmTarget::Memory(idx) => self.read(idx)?.into(), ModRmTarget::Register(reg) => self.regs.read(reg), - } + }; + Ok(imm) } + /// Rotate bits of data, pointed to from a [`ModRmTarget`]. pub fn rotate( &mut self, target: ModRmTarget, rotations: usize, // how many rotations carry_usage: CarryUsage, // if carry should be included, or should just receive a copy rotation_direction: RotationDirection, // direction of rotation - ) { - let mut bits = self.read_modrm(target).bits(); + ) -> Result<(), InterpreterError> { + let mut bits = self.read_modrm(target)?.bits(); match carry_usage { CarryUsage::FullRotation => bits.push(self.flags.cf), _ => {} @@ -270,7 +366,7 @@ impl Computer { } } } - self.write_modrm(target, ImmediateOperand::from(bits)); + self.write_modrm(target, ImmediateOperand::from(bits)) } } diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index a8d79e3..57568cd 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -6,7 +6,6 @@ use crate::{ interpreter::{ computer::{CarryUsage, RotationDirection}, interrupt::Mess1, - memory::Memory, register::SegmentRegister, }, operands::{Byte, ImmediateOperand, ModRmTarget, Word}, @@ -86,56 +85,60 @@ impl Interpreter { Mnemonic::ADD_FromReg(dest, src) => self.computer.add( dest, ArithmeticOperand::ModRmTarget(ModRmTarget::Register(src)), - ), + )?, Mnemonic::ADD_ToReg(src, dest) => self.computer.add( ModRmTarget::Register(dest), ArithmeticOperand::ModRmTarget(src), - ), + )?, Mnemonic::ADD_Ib(dest, src) => self.computer.add( dest, ArithmeticOperand::Immediate(ImmediateOperand::Byte(src)), - ), + )?, Mnemonic::ADD_Iv(dest, src) => self.computer.add( dest, ArithmeticOperand::Immediate(ImmediateOperand::Word(src)), - ), + )?, Mnemonic::ADD_ALIb(src_byte) => self.computer.add( ModRmTarget::Register(crate::register::Register::AL), ArithmeticOperand::Immediate(ImmediateOperand::Byte(src_byte)), - ), + )?, Mnemonic::ADD_AXIv(src_word) => self.computer.add( ModRmTarget::Register(crate::register::Register::AX), ArithmeticOperand::Immediate(ImmediateOperand::Word(src_word)), - ), + )?, /* * PUSH */ Mnemonic::PUSH_R(reg) => self.computer.push_stack(self.computer.regs.read(reg))?, - Mnemonic::PUSH_Mod(target) => { - self.computer.push_stack(self.computer.read_modrm(target))? - } + Mnemonic::PUSH_Mod(target) => self + .computer + .push_stack(self.computer.read_modrm(target)?)?, Mnemonic::PUSH_S(_) => todo!(), /* * POP */ Mnemonic::POP_R(reg) => { - let val = self.computer.pop_stack()?.into(); - self.computer.regs.write(reg, val); + let val = self.computer.pop_stack()?; + self.computer.regs.write(reg, val.into()); } Mnemonic::POP_M(idx) => { - let val = self.computer.pop_stack()?.into(); + let val = self.computer.pop_stack()?; self.computer.memory.write_raw( - Memory::absolute_addr_from_idx( - &self.computer.regs, - &self.computer.sregs, - idx, - ) - .into(), - val, + self.computer + .mem_addr(idx, &crate::register::SegmentRegister::SS), + val.into(), )? } - Mnemonic::POP_S(_) => todo!(), + Mnemonic::POP_S(sreg) => { + let val = self.computer.pop_stack()?; + match sreg { + crate::register::SegmentRegister::DS => self.computer.sregs.ds = val, + crate::register::SegmentRegister::ES => self.computer.sregs.es = val, + crate::register::SegmentRegister::SS => self.computer.sregs.ss = val, + crate::register::SegmentRegister::CS => self.computer.sregs.cs = val, + } + } /* * OR @@ -143,27 +146,27 @@ impl Interpreter { Mnemonic::OR_FromReg(dest, src) => self.computer.or( dest, ArithmeticOperand::ModRmTarget(ModRmTarget::Register(src)), - ), + )?, Mnemonic::OR_ToReg(src, dest) => self.computer.or( ModRmTarget::Register(dest), ArithmeticOperand::ModRmTarget(src), - ), + )?, Mnemonic::OR_Ib(dest, src) => self.computer.or( dest, ArithmeticOperand::Immediate(ImmediateOperand::Byte(src)), - ), + )?, Mnemonic::OR_Iv(dest, src) => self.computer.or( dest, ArithmeticOperand::Immediate(ImmediateOperand::Word(src)), - ), + )?, Mnemonic::OR_ALIb(src_byte) => self.computer.or( ModRmTarget::Register(crate::register::Register::AL), ArithmeticOperand::Immediate(ImmediateOperand::Byte(src_byte)), - ), + )?, Mnemonic::OR_AXIv(src_word) => self.computer.or( ModRmTarget::Register(crate::register::Register::AX), ArithmeticOperand::Immediate(ImmediateOperand::Word(src_word)), - ), + )?, /* * ADC - add with carry @@ -171,27 +174,27 @@ impl Interpreter { Mnemonic::ADC_FromReg(dest, src) => self.computer.adc( dest, ArithmeticOperand::ModRmTarget(ModRmTarget::Register(src)), - ), + )?, Mnemonic::ADC_ToReg(src, dest) => self.computer.adc( ModRmTarget::Register(dest), ArithmeticOperand::ModRmTarget(src), - ), + )?, Mnemonic::ADC_Ib(dest, src) => self.computer.adc( dest, ArithmeticOperand::Immediate(ImmediateOperand::Byte(src)), - ), + )?, Mnemonic::ADC_Iv(dest, src) => self.computer.adc( dest, ArithmeticOperand::Immediate(ImmediateOperand::Word(src)), - ), + )?, Mnemonic::ADC_ALIb(src_byte) => self.computer.adc( ModRmTarget::Register(crate::register::Register::AL), ArithmeticOperand::Immediate(ImmediateOperand::Byte(src_byte)), - ), + )?, Mnemonic::ADC_AXIv(src_word) => self.computer.adc( ModRmTarget::Register(crate::register::Register::AX), ArithmeticOperand::Immediate(ImmediateOperand::Word(src_word)), - ), + )?, /* * SBB - subtract with borrow @@ -199,27 +202,27 @@ impl Interpreter { Mnemonic::SBB_FromReg(dest, src) => self.computer.sbb( dest, ArithmeticOperand::ModRmTarget(ModRmTarget::Register(src)), - ), + )?, Mnemonic::SBB_ToReg(src, dest) => self.computer.sbb( ModRmTarget::Register(dest), ArithmeticOperand::ModRmTarget(src), - ), + )?, Mnemonic::SBB_Ib(dest, src) => self.computer.sbb( dest, ArithmeticOperand::Immediate(ImmediateOperand::Byte(src)), - ), + )?, Mnemonic::SBB_Iv(dest, src) => self.computer.sbb( dest, ArithmeticOperand::Immediate(ImmediateOperand::Word(src)), - ), + )?, Mnemonic::SBB_ALIb(src_byte) => self.computer.sbb( ModRmTarget::Register(crate::register::Register::AL), ArithmeticOperand::Immediate(ImmediateOperand::Byte(src_byte)), - ), + )?, Mnemonic::SBB_AXIv(src_word) => self.computer.sbb( ModRmTarget::Register(crate::register::Register::AX), ArithmeticOperand::Immediate(ImmediateOperand::Word(src_word)), - ), + )?, /* * AND @@ -227,27 +230,27 @@ impl Interpreter { Mnemonic::AND_FromReg(dest, src) => self.computer.and( dest, ArithmeticOperand::ModRmTarget(ModRmTarget::Register(src)), - ), + )?, Mnemonic::AND_ToReg(src, dest) => self.computer.and( ModRmTarget::Register(dest), ArithmeticOperand::ModRmTarget(src), - ), + )?, Mnemonic::AND_Ib(dest, src) => self.computer.and( dest, ArithmeticOperand::Immediate(ImmediateOperand::Byte(src)), - ), + )?, Mnemonic::AND_Iv(dest, src) => self.computer.and( dest, ArithmeticOperand::Immediate(ImmediateOperand::Word(src)), - ), + )?, Mnemonic::AND_ALIb(src_byte) => self.computer.and( ModRmTarget::Register(crate::register::Register::AL), ArithmeticOperand::Immediate(ImmediateOperand::Byte(src_byte)), - ), + )?, Mnemonic::AND_AXIv(src_word) => self.computer.and( ModRmTarget::Register(crate::register::Register::AX), ArithmeticOperand::Immediate(ImmediateOperand::Word(src_word)), - ), + )?, /* * Override */ @@ -262,27 +265,27 @@ impl Interpreter { Mnemonic::SUB_FromReg(dest, src) => self.computer.sub( dest, ArithmeticOperand::ModRmTarget(ModRmTarget::Register(src)), - ), + )?, Mnemonic::SUB_ToReg(src, dest) => self.computer.sub( ModRmTarget::Register(dest), ArithmeticOperand::ModRmTarget(src), - ), + )?, Mnemonic::SUB_Ib(dest, src) => self.computer.sub( dest, ArithmeticOperand::Immediate(ImmediateOperand::Byte(src)), - ), + )?, Mnemonic::SUB_Iv(dest, src) => self.computer.sub( dest, ArithmeticOperand::Immediate(ImmediateOperand::Word(src)), - ), + )?, Mnemonic::SUB_ALIb(src_byte) => self.computer.sub( ModRmTarget::Register(crate::register::Register::AL), ArithmeticOperand::Immediate(ImmediateOperand::Byte(src_byte)), - ), + )?, Mnemonic::SUB_AXIv(src_word) => self.computer.sub( ModRmTarget::Register(crate::register::Register::AX), ArithmeticOperand::Immediate(ImmediateOperand::Word(src_word)), - ), + )?, /* * XOR @@ -290,27 +293,27 @@ impl Interpreter { Mnemonic::XOR_FromReg(dest, src) => self.computer.xor( dest, ArithmeticOperand::ModRmTarget(ModRmTarget::Register(src)), - ), + )?, Mnemonic::XOR_ToReg(src, dest) => self.computer.xor( ModRmTarget::Register(dest), ArithmeticOperand::ModRmTarget(src), - ), + )?, Mnemonic::XOR_Ib(dest, src) => self.computer.xor( dest, ArithmeticOperand::Immediate(ImmediateOperand::Byte(src)), - ), + )?, Mnemonic::XOR_Iv(dest, src) => self.computer.xor( dest, ArithmeticOperand::Immediate(ImmediateOperand::Word(src)), - ), + )?, Mnemonic::XOR_ALIb(src_byte) => self.computer.xor( ModRmTarget::Register(crate::register::Register::AL), ArithmeticOperand::Immediate(ImmediateOperand::Byte(src_byte)), - ), + )?, Mnemonic::XOR_AXIv(src_word) => self.computer.xor( ModRmTarget::Register(crate::register::Register::AX), ArithmeticOperand::Immediate(ImmediateOperand::Word(src_word)), - ), + )?, /* * CMP @@ -318,27 +321,27 @@ impl Interpreter { Mnemonic::CMP_FromReg(dest, src) => self.computer.cmp( dest, ArithmeticOperand::ModRmTarget(ModRmTarget::Register(src)), - ), + )?, Mnemonic::CMP_ToReg(src, dest) => self.computer.cmp( ModRmTarget::Register(dest), ArithmeticOperand::ModRmTarget(src), - ), + )?, Mnemonic::CMP_Ib(dest, src) => self.computer.cmp( dest, ArithmeticOperand::Immediate(ImmediateOperand::Byte(src)), - ), + )?, Mnemonic::CMP_Iv(dest, src) => self.computer.cmp( dest, ArithmeticOperand::Immediate(ImmediateOperand::Word(src)), - ), + )?, Mnemonic::CMP_ALIb(src_byte) => self.computer.cmp( ModRmTarget::Register(crate::register::Register::AL), ArithmeticOperand::Immediate(ImmediateOperand::Byte(src_byte)), - ), + )?, Mnemonic::CMP_AXIv(src_word) => self.computer.cmp( ModRmTarget::Register(crate::register::Register::AX), ArithmeticOperand::Immediate(ImmediateOperand::Word(src_word)), - ), + )?, /* * INC @@ -348,8 +351,8 @@ impl Interpreter { .regs .write(reg, self.computer.regs.read(reg) + 1), Mnemonic::INC_Mod(target) => { - let val = self.computer.read_modrm(target); - self.computer.write_modrm(target, val + 1); + let val = self.computer.read_modrm(target)?; + self.computer.write_modrm(target, val + 1)? } /* @@ -360,8 +363,8 @@ impl Interpreter { .regs .write(reg, self.computer.regs.read(reg) - 1), Mnemonic::DEC_Mod(target) => { - let val = self.computer.read_modrm(target); - self.computer.write_modrm(target, val - 1); + let val = self.computer.read_modrm(target)?; + self.computer.write_modrm(target, val - 1)? } /* @@ -431,23 +434,12 @@ impl Interpreter { ptr.word.into(), ); } - Mnemonic::JMP_Mod(target) => match target { - ModRmTarget::Memory(idx) => Self::ip_jump( - &self.instructions, - &mut ip, - &self.computer.sregs, - self.computer - .memory - .read(&self.computer.regs, &self.computer.sregs, idx) - .into(), - ), - ModRmTarget::Register(register) => Self::ip_jump( - &self.instructions, - &mut ip, - &self.computer.sregs, - self.computer.regs.read(register).into(), - ), - }, + Mnemonic::JMP_Mod(target) => Self::ip_jump( + &self.instructions, + &mut ip, + &self.computer.sregs, + self.computer.read_modrm(target)?.into(), + ), Mnemonic::CALL_p(ptr) => { if let Some(next_instr) = ip.next() { self.computer.push_stack(next_instr.addr.into())?; @@ -474,7 +466,7 @@ impl Interpreter { &self.instructions, &mut ip, &self.computer.sregs, - self.computer.read_modrm(target).into(), + self.computer.read_modrm(target)?.into(), ); } Mnemonic::CALL_Mp(ptr) => { @@ -495,31 +487,31 @@ impl Interpreter { Mnemonic::TEST(dest, src) => self.computer.test( dest, ArithmeticOperand::ModRmTarget(ModRmTarget::Register(src)), - ), + )?, Mnemonic::TEST_Ib(dest, src) => self.computer.test( dest, ArithmeticOperand::Immediate(ImmediateOperand::Byte(src)), - ), + )?, Mnemonic::TEST_Iv(dest, src) => self.computer.test( dest, ArithmeticOperand::Immediate(ImmediateOperand::Word(src)), - ), + )?, Mnemonic::TEST_ALIb(src_byte) => self.computer.test( ModRmTarget::Register(crate::register::Register::AL), ArithmeticOperand::Immediate(ImmediateOperand::Byte(src_byte)), - ), + )?, Mnemonic::TEST_AXIv(src_word) => self.computer.test( ModRmTarget::Register(crate::register::Register::AX), ArithmeticOperand::Immediate(ImmediateOperand::Word(src_word)), - ), + )?, /* * XCHG */ Mnemonic::XCHG(target, reg) => { - let tmp = self.computer.read_modrm(target); + let tmp = self.computer.read_modrm(target)?; self.computer - .write_modrm(target, self.computer.regs.read(reg)); + .write_modrm(target, self.computer.regs.read(reg))?; self.computer.regs.write(reg, tmp); } Mnemonic::XCHG_AX(reg) => { @@ -535,15 +527,15 @@ impl Interpreter { */ Mnemonic::MOV_FromReg(target, reg) => self .computer - .write_modrm(target, self.computer.regs.read(reg)), + .write_modrm(target, self.computer.regs.read(reg))?, Mnemonic::MOV_ToReg(target, reg) => self .computer .regs - .write(reg, self.computer.read_modrm(target)), + .write(reg, self.computer.read_modrm(target)?), Mnemonic::MOV_FromSReg(_, _) => todo!(), Mnemonic::MOV_ToSReg(_, _) => todo!(), - Mnemonic::MOV_Ib(target, val) => self.computer.write_modrm(target, val.into()), - Mnemonic::MOV_Iv(target, val) => self.computer.write_modrm(target, val.into()), + Mnemonic::MOV_Ib(target, val) => self.computer.write_modrm(target, val.into())?, + Mnemonic::MOV_Iv(target, val) => self.computer.write_modrm(target, val.into())?, Mnemonic::MOV_AL0b(val) => self.computer.regs.ax.lower = val, Mnemonic::MOV_AX0v(val) => self.computer.regs.ax.write(val), @@ -572,12 +564,10 @@ impl Interpreter { */ Mnemonic::LEA(target, reg) => { let val = match target { - ModRmTarget::Memory(idx) => Memory::absolute_addr_from_idx( - &self.computer.regs, - &self.computer.sregs, - idx, - ) - .into(), + ModRmTarget::Memory(idx) => self + .computer + .mem_addr(idx, &crate::register::SegmentRegister::DS) + .into(), ModRmTarget::Register(reg) => self.computer.regs.read(reg), }; self.computer.regs.write(reg, val); @@ -632,28 +622,16 @@ impl Interpreter { * Load ES/DS Register */ Mnemonic::LES(reg, ptr) => { - let offset = self - .computer - .memory - .read_raw(self.computer.sregs.ds * 16 + ptr.word)?; - let segment = self - .computer - .memory - .read_raw(self.computer.sregs.ds * 16 + ptr.word + 2)?; + let offset = self.computer.read(ptr.into())?; + let segment = self.computer.read((ptr + 2).into())?; self.computer.sregs.es = segment; self.computer .regs .write(reg, ImmediateOperand::from(offset)); } Mnemonic::LDS(reg, ptr) => { - let offset = self - .computer - .memory - .read_raw(self.computer.sregs.ds * 16 + ptr.word)?; - let segment = self - .computer - .memory - .read_raw(self.computer.sregs.ds * 16 + ptr.word + 2)?; + let offset = self.computer.read(ptr.into())?; + let segment = self.computer.read((ptr + 2).into())?; self.computer.sregs.ds = segment; self.computer .regs @@ -665,11 +643,11 @@ impl Interpreter { */ Mnemonic::NOT(target) => { self.computer - .write_modrm(target, !self.computer.read_modrm(target)); + .write_modrm(target, !self.computer.read_modrm(target)?)?; } Mnemonic::NEG(target) => { - let val = !self.computer.read_modrm(target); - self.computer.write_modrm(target, val + 0b1); + let val = !self.computer.read_modrm(target)?; + self.computer.write_modrm(target, val + 0b1)?; } /* @@ -696,68 +674,68 @@ impl Interpreter { b.into(), CarryUsage::ReceiveCopy, RotationDirection::Left, - ), + )?, Mnemonic::ROR_b(target, b) => self.computer.rotate( target, b.into(), CarryUsage::ReceiveCopy, RotationDirection::Right, - ), + )?, Mnemonic::RCL_b(target, b) => self.computer.rotate( target, b.into(), CarryUsage::FullRotation, RotationDirection::Left, - ), + )?, Mnemonic::RCR_b(target, b) => self.computer.rotate( target, b.into(), CarryUsage::FullRotation, RotationDirection::Right, - ), + )?, Mnemonic::ROL_fromReg(target, reg) => self.computer.rotate( target, self.computer.regs.read(reg).into(), CarryUsage::ReceiveCopy, RotationDirection::Left, - ), + )?, Mnemonic::ROR_fromReg(target, reg) => self.computer.rotate( target, self.computer.regs.read(reg).into(), CarryUsage::ReceiveCopy, RotationDirection::Right, - ), + )?, Mnemonic::RCL_fromReg(target, reg) => self.computer.rotate( target, self.computer.regs.read(reg).into(), CarryUsage::FullRotation, RotationDirection::Left, - ), + )?, Mnemonic::RCR_fromReg(target, reg) => self.computer.rotate( target, self.computer.regs.read(reg).into(), CarryUsage::FullRotation, RotationDirection::Right, - ), + )?, /* * Shfit */ Mnemonic::SHL_b(target, b) => self .computer - .write_modrm(target, self.computer.read_modrm(target) << b), + .write_modrm(target, self.computer.read_modrm(target)? << b)?, Mnemonic::SHR_b(target, b) => self .computer - .write_modrm(target, self.computer.read_modrm(target) >> b), + .write_modrm(target, self.computer.read_modrm(target)? >> b)?, Mnemonic::SAR_b(_, _) => todo!(), Mnemonic::SHL_fromReg(target, reg) => self.computer.write_modrm( target, - self.computer.read_modrm(target) << self.computer.regs.read(reg), - ), + self.computer.read_modrm(target)? << self.computer.regs.read(reg), + )?, Mnemonic::SHR_fromReg(target, reg) => self.computer.write_modrm( target, - self.computer.read_modrm(target) >> self.computer.regs.read(reg), - ), + self.computer.read_modrm(target)? >> self.computer.regs.read(reg), + )?, Mnemonic::SAR_fromReg(_, _) => todo!(), /* diff --git a/src/interpreter/memory.rs b/src/interpreter/memory.rs index 8346f1c..10b0905 100644 --- a/src/interpreter/memory.rs +++ b/src/interpreter/memory.rs @@ -1,7 +1,6 @@ -use crate::operands::{Byte, ImmediateOperand, ImmediateOperandSigned, MemoryIndex, Word}; +use crate::operands::{Byte, ImmediateOperand, Word}; use super::interpreter::InterpreterError; -use crate::interpreter::register::{Register, SegmentRegister}; /// 2*20 = 1MiB const MEMORY_SIZE: usize = 1048576; @@ -18,17 +17,24 @@ impl Memory { } } - /// Safely writes a [`Word`] into an index of memory. + /// 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: Word) -> Result<(), InterpreterError> { + pub fn write_raw(&mut self, addr: Word, val: ImmediateOperand) -> Result<(), InterpreterError> { if (addr + 1) as usize > MEMORY_SIZE { return Err(InterpreterError::MemoryOutOfBound(addr)); } else { - let [low, high] = val.to_le_bytes(); - self.memory[addr as usize] = low; - self.memory[(addr + 1) as usize] = high; - Ok(()) + match val { + ImmediateOperand::Byte(b) => { + self.memory[addr as usize] = b; + } + ImmediateOperand::Word(w) => { + let [low, high] = w.to_le_bytes(); + self.memory[addr as usize] = low; + self.memory[(addr + 1) as usize] = high; + } + } } + Ok(()) } /// Safely reads a [`Word`] from an index of memory. @@ -46,69 +52,4 @@ impl Memory { .to_owned(); Ok(Word::from_be_bytes([b2, b1])) } - - /// Write an [`ImmediateOperand`] to a memory location indexed by a [`MemoryIndex`]. - pub fn write( - &mut self, - regs: &Register, - sregs: &SegmentRegister, - idx: MemoryIndex, - val: ImmediateOperand, - ) { - 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}"); - self.memory[idx as usize] = b - } - ImmediateOperand::Word(value) => { - let byte1 = idx / 2; - let byte2 = idx / 2 + 1; - let [low, high]: [u8; 2] = value.to_le_bytes(); - log::debug!( - "Writing bytes {low:#04x} and {high:#04x} to memory location {byte1:#04x} and {byte2:#04x}" - ); - self.memory[byte1 as usize] = low; - self.memory[byte1 as usize] = high; - } - } - } - - /// Read into memory with a [`MemoryIndex`] as index. - /// Always reads a whole word. - 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 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 = ImmediateOperandSigned::Word(0); - - if let Some(base_reg) = idx.base { - base = regs.read(base_reg); - }; - if let Some(index_reg) = idx.index { - index = regs.read(index_reg); - }; - if let Some(displacement) = idx.displacement { - disp = ImmediateOperandSigned::from(displacement); - } - - Self::addr_offset((base + index + disp).into(), sregs) - } } diff --git a/src/interpreter/register.rs b/src/interpreter/register.rs index cdc3d49..8f88be3 100644 --- a/src/interpreter/register.rs +++ b/src/interpreter/register.rs @@ -30,7 +30,7 @@ impl Register { } /// Decrement stack pointer - pub fn push(&mut self) -> Result<(), InterpreterError> { + pub fn push_sp(&mut self) -> Result<(), InterpreterError> { if self.sp < 2 { return Err(InterpreterError::InvalidRegisterState(*self)); } else { @@ -40,7 +40,7 @@ impl Register { } /// Increment stack pointer - pub fn pop(&mut self) -> Result<(), InterpreterError> { + pub fn pop_sp(&mut self) -> Result<(), InterpreterError> { if self.sp > 0xffff - 2 { return Err(InterpreterError::InvalidRegisterState(*self)); } else { diff --git a/src/operands.rs b/src/operands.rs index fcb34e4..e943a47 100644 --- a/src/operands.rs +++ b/src/operands.rs @@ -148,6 +148,16 @@ impl From for ImmediateOperand { } } +impl Into for ImmediateOperand { + fn into(self) -> MemoryIndex { + MemoryIndex { + base: None, + index: None, + displacement: Some(self), + } + } +} + impl Into for ImmediateOperand { fn into(self) -> u16 { match self { @@ -529,26 +539,6 @@ pub struct MemoryIndex { pub displacement: Option, } -impl MemoryIndex { - /// Creates a [`MemoryIndex`] with just a single [`Register`] - pub fn reg(reg: Register) -> Self { - Self { - base: Some(reg), - index: None, - displacement: None, - } - } - - /// Creates a [`MemoryIndex`] with an [`ImmediateOperand`] - pub fn disp(disp: ImmediateOperand) -> Self { - Self { - base: None, - index: None, - displacement: Some(disp), - } - } -} - impl fmt::Display for MemoryIndex { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match &self.base { @@ -607,6 +597,26 @@ pub struct Pointer16 { pub word: Word, } +impl Into for Pointer16 { + fn into(self) -> MemoryIndex { + MemoryIndex { + base: None, + index: None, + displacement: Some(self.word.into()), + } + } +} + +impl Add for Pointer16 { + type Output = Self; + + fn add(self, rhs: u16) -> Self::Output { + Self { + word: self.word + rhs, + } + } +} + impl std::fmt::Display for Pointer16 { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "ptr word [{:#04x}]", self.word)