diff --git a/src/interpreter/computer.rs b/src/interpreter/computer.rs index 3487113..91a2bdf 100644 --- a/src/interpreter/computer.rs +++ b/src/interpreter/computer.rs @@ -1,16 +1,23 @@ use core::fmt; -use crate::operands::{ImmediateOperand, ModRmTarget}; +use crate::operands::{ImmediateOperand, MemoryIndex, ModRmTarget}; -use super::{flags::Flags, memory::Memory, register::Register}; +use super::{flags::Flags, interpreter::InterpreterError, memory::Memory, register::Register}; -/// Wrapper for easier argument passing of multi-type operations. +/// Wrapper for easier argument passing of polymorph arithmetic operations. #[derive(Debug, Clone)] pub enum Operand { Immediate(crate::operands::ImmediateOperand), ModRmTarget(ModRmTarget), } +/// Wrapper for easier argument passing of polymorph pop operations. +#[derive(Debug, Clone)] +pub enum PopTarget { + Register(crate::register::Register), + MemoryIndex(MemoryIndex), +} + type ArithmeticResult = ImmediateOperand; type Lhs = ImmediateOperand; type Rhs = ImmediateOperand; @@ -31,6 +38,28 @@ 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()) + } + + /// Retrieve value from stack and increment stack pointer. + pub fn pop_stack(&mut self, target: PopTarget) -> Result<(), InterpreterError> { + let word = self.memory.read_raw(self.regs.sp)?; + + match target { + PopTarget::Register(reg) => self.regs.write(reg, word.into()), + PopTarget::MemoryIndex(mem_idx) => self + .memory + .write_raw(Memory::calc_memidx(&self.regs, mem_idx).into(), word.into())?, + } + + self.regs.pop()?; + + Ok(()) + } + /// Perform binary `dest` = `dest` + `src`. Sets flags. pub fn add(&mut self, dest: ModRmTarget, src: Operand) { let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs + rhs; diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index ec705a3..e5242a2 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -3,8 +3,8 @@ use std::{fmt::Debug, process::exit}; use crate::{ instructions::{Instruction, Mnemonic}, - interpreter::{interrupt::Mess1, memory::Memory}, - operands::{Byte, ImmediateOperand, ModRmTarget}, + interpreter::{computer::PopTarget, interrupt::Mess1, memory::Memory}, + operands::{Byte, ImmediateOperand, ModRmTarget, Word}, }; use super::{ @@ -17,8 +17,10 @@ type InstructionPointer<'a> = std::slice::Iter<'a, Instruction>; #[derive(Debug, Clone)] pub enum InterpreterError { EndOfData, - InvalidSyscall(u8), - InstructionNotFound(usize), + InvalidSyscall(Byte), + InstructionNotFound(Word), + MemoryOutOfBound(Word), + InvalidRegisterState(crate::interpreter::register::Register), } impl fmt::Display for InterpreterError { @@ -31,6 +33,15 @@ impl fmt::Display for InterpreterError { InterpreterError::InstructionNotFound(addr) => { write!(f, "IP({addr}) points at invalid instruction") } + InterpreterError::MemoryOutOfBound(addr) => { + write!( + f, + "Attempted memory write out of physical bounds: ({addr:#04x})" + ) + } + InterpreterError::InvalidRegisterState(reg) => { + write!(f, "Invalid Register State: {reg:?}") + } } } } @@ -90,10 +101,18 @@ impl Interpreter { /* * 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_S(_) => todo!(), /* * POP */ + Mnemonic::POP_R(reg) => self.computer.pop_stack(PopTarget::Register(reg))?, + Mnemonic::POP_M(idx) => self.computer.pop_stack(PopTarget::MemoryIndex(idx))?, + Mnemonic::POP_S(_) => todo!(), /* * OR diff --git a/src/interpreter/memory.rs b/src/interpreter/memory.rs index c13c447..2406a5a 100644 --- a/src/interpreter/memory.rs +++ b/src/interpreter/memory.rs @@ -1,16 +1,47 @@ use crate::operands::{Byte, Displacement, ImmediateOperand, MemoryIndex, Word}; +use super::interpreter::InterpreterError; + #[derive(Debug, Clone, Copy)] pub struct Memory { - memory: [Byte; 65536], + memory: [Byte; Word::MAX as usize], } impl Memory { pub fn new() -> Self { - Self { memory: [0; 65536] } + Self { + memory: [0; Word::MAX as usize], + } } - // Write an [`ImmediateOperand`] to a memory location indexed by a [`MemoryIndex`]. + /// Safely writes a [`Word`] into an index of memory. + pub fn write_raw(&mut self, idx: Word, val: Word) -> Result<(), InterpreterError> { + if idx + 1 > Word::MAX { + return Err(InterpreterError::MemoryOutOfBound(idx)); + } else { + let [low, high] = val.to_le_bytes(); + self.memory[idx as usize] = low; + self.memory[(idx + 1) as usize] = high; + Ok(()) + } + } + + /// Safely reads a [`Word`] from an index of memory + pub fn read_raw(&self, idx: Word) -> Result { + let b1 = self + .memory + .get(idx as usize) + .ok_or(InterpreterError::MemoryOutOfBound(idx))? + .to_owned(); + let b2 = self + .memory + .get((idx + 1) as usize) + .ok_or(InterpreterError::MemoryOutOfBound(idx))? + .to_owned(); + Ok(Word::from_be_bytes([b1, b2])) + } + + /// Write an [`ImmediateOperand`] to a memory location indexed by a [`MemoryIndex`]. pub fn write( &mut self, regs: &crate::interpreter::register::Register, diff --git a/src/interpreter/register.rs b/src/interpreter/register.rs index 562253c..025fe6e 100644 --- a/src/interpreter/register.rs +++ b/src/interpreter/register.rs @@ -1,6 +1,8 @@ use crate::operands::{Byte, ImmediateOperand, Word}; use core::fmt; +use super::interpreter::InterpreterError; + #[derive(Debug, Clone, Copy)] pub struct Register { pub ax: AX, @@ -20,13 +22,33 @@ impl Register { bx: BX::new(), cx: CX::new(), dx: DX::new(), - sp: 0, + sp: 0xffff, bp: 0, si: 0, di: 0, } } + /// Decrement stack pointer + pub fn push(&mut self) -> Result<(), InterpreterError> { + if self.sp <= 2 { + return Err(InterpreterError::InvalidRegisterState(*self)); + } else { + self.sp -= 2; + Ok(()) + } + } + + /// Increment stack pointer + pub fn pop(&mut self) -> Result<(), InterpreterError> { + if self.sp >= 0xffff - 2 { + return Err(InterpreterError::InvalidRegisterState(*self)); + } else { + self.sp += 2; + Ok(()) + } + } + /// Read value from a [`crate::register::Register`]. pub fn read(&self, reg: crate::register::Register) -> ImmediateOperand { match reg { diff --git a/src/operands.rs b/src/operands.rs index 7185748..4819b43 100644 --- a/src/operands.rs +++ b/src/operands.rs @@ -34,9 +34,9 @@ impl ImmediateOperand { match self { Self::Byte(_) => { return if self.msb() { - self.flip_sign().as_word().flip_sign() + self.flip_sign().word().flip_sign() } else { - self.as_word() + self.word() }; } Self::Word(_) => self, @@ -46,7 +46,7 @@ impl ImmediateOperand { /// Interprets [`Self::Byte`] as [`Self::Word`]. /// Returns word, if already a [`Self::Word`]. /// CAUTION: You probably want to use [`Self::sign_extend()`] instead. - fn as_word(self) -> Self { + fn word(self) -> Self { match self { Self::Byte(b) => Self::Word(b as Word), Self::Word(_) => self, @@ -566,7 +566,7 @@ mod tests { let b: u8 = 5; let byte = ImmediateOperand::Byte(b); let word = ImmediateOperand::Word(b as Word); - assert_eq!(byte.as_word(), word); + assert_eq!(byte.word(), word); assert_eq!(word, word); }