diff --git a/src/interpreter/computer.rs b/src/interpreter/computer.rs index f7a8eac..72192c3 100644 --- a/src/interpreter/computer.rs +++ b/src/interpreter/computer.rs @@ -4,13 +4,17 @@ use crate::operands::{ImmediateOperand, ModRmTarget}; use super::{flags::Flags, memory::Memory, register::Register}; -/// Wrapper for easier argument passing of arithmetic operations. +/// Wrapper for easier argument passing of multi-type operations. #[derive(Debug, Clone)] pub enum Operand { Immediate(crate::operands::ImmediateOperand), ModRmTarget(ModRmTarget), } +type Result = ImmediateOperand; +type Lhs = ImmediateOperand; +type Rhs = ImmediateOperand; + #[derive(Debug, Clone)] pub struct Computer { pub regs: Register, @@ -27,38 +31,48 @@ impl Computer { } } + /// Perform binary `dest` = `dest` + `src`. Sets flags. pub fn add(&mut self, dest: ModRmTarget, src: Operand) { - let op = |lhs, rhs| lhs + rhs; - // TODO let flag_check = |_| (); - self.op(op, dest, src); + let op: fn(Lhs, Rhs) -> Result = |lhs, rhs| lhs + rhs; + let flag_set: fn(&mut Flags, Result, Lhs, Rhs) = |flags, result, lhs, rhs| { + flags.cf = result < rhs; + flags.of = lhs.msb() && rhs.msb() != result.msb(); + flags.zf = result.zero(); + flags.sf = result.msb(); + flags.pf = result.parity(); + // flags.af = + }; + self.op(op, flag_set, dest, src); } + /// Perform binary `dest` = `dest` - `src`. Sets flags. pub fn sub(&mut self, dest: ModRmTarget, src: Operand) { - let op = |lhs, rhs| lhs - rhs; - // TODO let flag_check = |_| (); - self.op(op, dest, src); + let op: fn(Lhs, Rhs) -> Result = |lhs, rhs| lhs - rhs; + let flag_set: fn(&mut Flags, Result, Lhs, Rhs) = |_, _, _, _| (); + self.op(op, flag_set, dest, src); } - /// Applies a binary operator [`O`] to two [`Argument`]s, saves it to `dest` - /// and sets flags, if necessary. - /// A value can never be saved to an immediate Operand, so `dest` can only + /// Applies a binary operator [`O`] to the value of two [`Operand`]s, saves + /// it to `dest` and sets flags, according to [`F`]. + /// A result can never be saved to an immediate Operand, so `dest` can only /// be a [`ModRmTarget`]. - fn op(&mut self, op: O, dest: ModRmTarget, src: Operand) + fn op(&mut self, op: O, flag_set: F, dest: ModRmTarget, src: Operand) where - O: Fn(ImmediateOperand, ImmediateOperand) -> ImmediateOperand, - // F: Fn(&mut Flags); + O: Fn(Lhs, Rhs) -> Result, + F: Fn(&mut Flags, Result, Lhs, Rhs), { match src { - Operand::ModRmTarget(src_target) => self.op_modrm(op, dest, src_target), - Operand::Immediate(src_operand) => self.op_imm(op, dest, src_operand), + Operand::ModRmTarget(src_target) => self.op_modrm(op, flag_set, dest, src_target), + Operand::Immediate(src_operand) => self.op_imm(op, flag_set, dest, src_operand), } } - /// Applies a binary operator [`O`] to two [`ModRmTargets`]s, saves it to - /// dest and sets flags, if necessary. - fn op_modrm(&mut self, op: O, dest: ModRmTarget, src: ModRmTarget) + /// Applies a binary operator [`O`] to two memory locations, pointed to by a + /// [`ModRmTargets`]s, saves it to dest and sets flags, according to [`F`]. + fn op_modrm(&mut self, op: O, flag_set: F, dest: ModRmTarget, src: ModRmTarget) where - O: Fn(ImmediateOperand, ImmediateOperand) -> ImmediateOperand, + O: Fn(Lhs, Rhs) -> Result, + F: Fn(&mut Flags, Result, Lhs, Rhs), { match dest { ModRmTarget::Memory(dest_memory_idx) => match src { @@ -72,7 +86,7 @@ impl Computer { let rhs = self.regs.read(src_register); let result = op(lhs, rhs); self.memory.write(&self.regs, dest_memory_idx, result); - // flag_check(&mut self.flags); + flag_set(&mut self.flags, result, lhs, rhs); } }, ModRmTarget::Register(dest_register) => match src { @@ -82,7 +96,7 @@ impl Computer { let rhs = self.memory.read(&self.regs, src_memory_index); let result = op(lhs, rhs); self.regs.write(dest_register, result); - // flag_check(&mut self.flags); + flag_set(&mut self.flags, result, lhs, rhs); } // reg, reg ModRmTarget::Register(src_register) => { @@ -90,7 +104,7 @@ impl Computer { let rhs = self.regs.read(src_register); let result = op(lhs, rhs); self.regs.write(dest_register, result); - // flag_check(&mut self.flags); + flag_set(&mut self.flags, result, lhs, rhs); } }, } @@ -98,24 +112,24 @@ impl Computer { /// Applies a binary operator [`O`] to [`ImmediateOperand`] and a location /// pointed to by a [`ModRmTarget`], saves it to dest and sets flags, - /// if necessary. - fn op_imm(&mut self, op: O, dest: ModRmTarget, src: ImmediateOperand) + /// according to [`F`]. + fn op_imm(&mut self, op: O, flag_set: F, dest: ModRmTarget, src: ImmediateOperand) where - O: Fn(ImmediateOperand, ImmediateOperand) -> ImmediateOperand, - // F: for<'F> Fn(&'F mut Flags), + O: Fn(Lhs, Rhs) -> Result, + F: Fn(&mut Flags, Result, Lhs, Rhs), { match dest { ModRmTarget::Memory(dest_mem) => { let lhs = self.memory.read(&self.regs, dest_mem); let result = op(lhs, src); self.memory.write(&self.regs, dest_mem, result); - // flag_check(&mut self.flags); + flag_set(&mut self.flags, result, lhs, src); } ModRmTarget::Register(dest_reg) => { let lhs = self.regs.read(dest_reg); let result = op(lhs, src); self.regs.write(dest_reg, result); - // flag_check(&mut self.flags); + flag_set(&mut self.flags, result, lhs, src); } } } diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index 457e464..c1d1176 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -78,6 +78,18 @@ impl Interpreter { ModRmTarget::Register(crate::register::Register::AX), Operand::Immediate(ImmediateOperand::Word(src_word)), ), + /* + * PUSH + */ + + /* + * POP + */ + + /* + * OR + */ + /* * SUB */ diff --git a/src/operands.rs b/src/operands.rs index b9be55b..8756ae0 100644 --- a/src/operands.rs +++ b/src/operands.rs @@ -16,15 +16,53 @@ pub type IWord = i16; // used for displacement of memory access pub type DWord = u32; #[derive(Debug, Clone, Ord, Eq, PartialEq, PartialOrd, Copy)] -/// Encodes either Byte- or Word-sized operands. +/// Encodes either Byte- or Word-sized immediate operands. /// Also sometimes used to decide if an instruction is Byte- or Word-sized, /// which is usually indicated by using a value of 0 and the disregarding /// the value when read. +/// Can either be interpreted as signed or unsigned, depending on the context. pub enum ImmediateOperand { Byte(Byte), Word(Word), } +impl ImmediateOperand { + // Check if value is zero. + pub fn zero(&self) -> bool { + match self { + Self::Byte(byte) => return *byte == 0, + Self::Word(word) => return *word == 0, + } + } + + // Check if leasy significant byte has even number of 1's. + pub fn parity(&self) -> bool { + match self { + Self::Byte(byte) => return byte.count_ones() % 2 != 0, + Self::Word(word) => { + let [low, _]: [u8; 2] = word.to_le_bytes(); + return low.count_ones() % 2 != 0; + } + } + } + + /// Check if least significant bit is set. + pub fn lsb(&self) -> bool { + match self { + Self::Byte(byte) => return byte & 1 == 1, + Self::Word(word) => return word & 1 == 1, + } + } + + /// Check if most significant bit is set. + pub fn msb(&self) -> bool { + match self { + Self::Byte(byte) => return byte & (1 << 3) == 1, + Self::Word(word) => return word & (1 << 7) == 1, + } + } +} + impl Add for ImmediateOperand { type Output = Self; @@ -162,7 +200,7 @@ impl std::fmt::Display for ModRmTarget { } #[derive(Debug, Clone, PartialEq, Eq, Copy)] -/// Memory displacements are signed versions of Byte and Word operands. +/// Memory displacements are concrete signed versions of Byte and Word operands. /// Encodes either Byte- or Word-sized operands. /// Generally, a [`Displacement`] is the result of a ModRM byte parse and /// usually really is the signed displacement of a [`MemoryIndex`] for memory