diff --git a/src/interpreter/computer.rs b/src/interpreter/computer.rs index 494ee5f..118eba0 100644 --- a/src/interpreter/computer.rs +++ b/src/interpreter/computer.rs @@ -40,37 +40,74 @@ impl Computer { flags.zf = result.zero(); flags.sf = result.msb(); flags.pf = result.parity(); - // flags.af = }; - self.op(op, flag_set, 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: Operand) { 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); + self.op(op, flag_set, true, dest, src); + } + + /// Perform binary `dest` = `dest` | `src`. Sets flags. + pub fn or(&mut self, dest: ModRmTarget, src: Operand) { + let op: fn(Lhs, Rhs) -> Result = |lhs, rhs| lhs | rhs; + let flag_set: fn(&mut Flags, Result, Lhs, Rhs) = |_, _, _, _| (); + self.op(op, flag_set, true, dest, src); + } + + /// Perform binary `dest` = `dest` & `src`. Sets flags. + pub fn and(&mut self, dest: ModRmTarget, src: Operand) { + let op: fn(Lhs, Rhs) -> Result = |lhs, rhs| lhs & rhs; + let flag_set: fn(&mut Flags, Result, Lhs, Rhs) = |_, _, _, _| (); + self.op(op, flag_set, true, dest, src); + } + + /// Perform binary `dest` = `dest` ^ `src`. Sets flags. + pub fn xor(&mut self, dest: ModRmTarget, src: Operand) { + let op: fn(Lhs, Rhs) -> Result = |lhs, rhs| lhs ^ rhs; + let flag_set: fn(&mut Flags, Result, Lhs, Rhs) = |_, _, _, _| (); + 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: Operand) { + let op: fn(Lhs, Rhs) -> Result = |lhs, rhs| lhs - rhs; + let flag_set: fn(&mut Flags, Result, Lhs, Rhs) = |_, _, _, _| (); + self.op(op, flag_set, false, dest, src); } /// Applies a binary operator [`O`] to the value of two [`Operand`]s, saves - /// it to `dest` and sets flags, according to [`F`]. + /// it to `dest`, if `write` is set, 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, flag_set: F, dest: ModRmTarget, src: Operand) + fn op(&mut self, op: O, flag_set: F, write: bool, dest: ModRmTarget, src: Operand) where O: Fn(Lhs, Rhs) -> Result, F: Fn(&mut Flags, Result, Lhs, Rhs), { match src { - 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), + Operand::ModRmTarget(src_target) => { + self.op_modrm(op, flag_set, write, dest, src_target) + } + Operand::Immediate(src_operand) => self.op_imm(op, flag_set, write, dest, src_operand), } } /// 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 + /// [`ModRmTargets`]s, saves it to dest, if `write` is set, and sets flags, + /// according to [`F`]. + fn op_modrm( + &mut self, + op: O, + flag_set: F, + write: bool, + dest: ModRmTarget, + src: ModRmTarget, + ) where O: Fn(Lhs, Rhs) -> Result, F: Fn(&mut Flags, Result, Lhs, Rhs), { @@ -85,7 +122,9 @@ impl Computer { let lhs = self.memory.read(&self.regs, dest_memory_idx); let rhs = self.regs.read(src_register); let result = op(lhs, rhs); - self.memory.write(&self.regs, dest_memory_idx, result); + if write { + self.memory.write(&self.regs, dest_memory_idx, result); + } flag_set(&mut self.flags, result, lhs, rhs); } }, @@ -95,7 +134,9 @@ impl Computer { let lhs = self.regs.read(dest_register); let rhs = self.memory.read(&self.regs, src_memory_index); let result = op(lhs, rhs); - self.regs.write(dest_register, result); + if write { + self.regs.write(dest_register, result); + } flag_set(&mut self.flags, result, lhs, rhs); } // reg, reg @@ -103,7 +144,9 @@ impl Computer { let lhs = self.regs.read(dest_register); let rhs = self.regs.read(src_register); let result = op(lhs, rhs); - self.regs.write(dest_register, result); + if write { + self.regs.write(dest_register, result); + } flag_set(&mut self.flags, result, lhs, rhs); } }, @@ -111,10 +154,16 @@ impl Computer { } /// Applies a binary operator [`O`] to [`ImmediateOperand`] and a location - /// pointed to by a [`ModRmTarget`], saves it to dest and sets flags, - /// according to [`F`]. - fn op_imm(&mut self, op: O, flag_set: F, dest: ModRmTarget, src: ImmediateOperand) - where + /// pointed to by a [`ModRmTarget`], saves it to dest, if `write` is set + /// and sets flags, according to [`F`]. + fn op_imm( + &mut self, + op: O, + flag_set: F, + write: bool, + dest: ModRmTarget, + src: ImmediateOperand, + ) where O: Fn(Lhs, Rhs) -> Result, F: Fn(&mut Flags, Result, Lhs, Rhs), { @@ -122,13 +171,17 @@ impl Computer { 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); + if write { + self.memory.write(&self.regs, dest_mem, result); + } 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); + if write { + self.regs.write(dest_reg, result); + } flag_set(&mut self.flags, result, lhs, src); } } diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index c1d1176..8acbf65 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -89,6 +89,64 @@ impl Interpreter { /* * OR */ + Mnemonic::OR_FromReg(dest, src) => self + .computer + .or(dest, Operand::ModRmTarget(ModRmTarget::Register(src))), + Mnemonic::OR_ToReg(src, dest) => self + .computer + .or(ModRmTarget::Register(dest), Operand::ModRmTarget(src)), + Mnemonic::OR_Ib(dest, src) => self + .computer + .or(dest, Operand::Immediate(ImmediateOperand::Byte(src))), + Mnemonic::OR_Iv(dest, src) => self + .computer + .or(dest, Operand::Immediate(ImmediateOperand::Word(src))), + Mnemonic::OR_ALIb(src_byte) => self.computer.or( + ModRmTarget::Register(crate::register::Register::AL), + Operand::Immediate(ImmediateOperand::Byte(src_byte)), + ), + Mnemonic::OR_AXIv(src_word) => self.computer.or( + ModRmTarget::Register(crate::register::Register::AX), + Operand::Immediate(ImmediateOperand::Word(src_word)), + ), + /* + * ADC + */ + + /* + * SBB + */ + + /* + * AND + */ + Mnemonic::AND_FromReg(dest, src) => self + .computer + .and(dest, Operand::ModRmTarget(ModRmTarget::Register(src))), + Mnemonic::AND_ToReg(src, dest) => self + .computer + .and(ModRmTarget::Register(dest), Operand::ModRmTarget(src)), + Mnemonic::AND_Ib(dest, src) => self + .computer + .and(dest, Operand::Immediate(ImmediateOperand::Byte(src))), + Mnemonic::AND_Iv(dest, src) => self + .computer + .and(dest, Operand::Immediate(ImmediateOperand::Word(src))), + Mnemonic::AND_ALIb(src_byte) => self.computer.and( + ModRmTarget::Register(crate::register::Register::AL), + Operand::Immediate(ImmediateOperand::Byte(src_byte)), + ), + Mnemonic::AND_AXIv(src_word) => self.computer.and( + ModRmTarget::Register(crate::register::Register::AX), + Operand::Immediate(ImmediateOperand::Word(src_word)), + ), + /* + * Override + */ + + /* + * Decimal Adjust + */ /* * SUB @@ -114,11 +172,195 @@ impl Interpreter { Operand::Immediate(ImmediateOperand::Word(src_word)), ), + /* + * XOR + */ + Mnemonic::XOR_FromReg(dest, src) => self + .computer + .xor(dest, Operand::ModRmTarget(ModRmTarget::Register(src))), + Mnemonic::XOR_ToReg(src, dest) => self + .computer + .xor(ModRmTarget::Register(dest), Operand::ModRmTarget(src)), + Mnemonic::XOR_Ib(dest, src) => self + .computer + .xor(dest, Operand::Immediate(ImmediateOperand::Byte(src))), + Mnemonic::XOR_Iv(dest, src) => self + .computer + .xor(dest, Operand::Immediate(ImmediateOperand::Word(src))), + Mnemonic::XOR_ALIb(src_byte) => self.computer.xor( + ModRmTarget::Register(crate::register::Register::AL), + Operand::Immediate(ImmediateOperand::Byte(src_byte)), + ), + Mnemonic::XOR_AXIv(src_word) => self.computer.xor( + ModRmTarget::Register(crate::register::Register::AX), + Operand::Immediate(ImmediateOperand::Word(src_word)), + ), + + /* + * CMP + */ + Mnemonic::CMP_FromReg(dest, src) => self + .computer + .cmp(dest, Operand::ModRmTarget(ModRmTarget::Register(src))), + Mnemonic::CMP_ToReg(src, dest) => self + .computer + .cmp(ModRmTarget::Register(dest), Operand::ModRmTarget(src)), + Mnemonic::CMP_Ib(dest, src) => self + .computer + .cmp(dest, Operand::Immediate(ImmediateOperand::Byte(src))), + Mnemonic::CMP_Iv(dest, src) => self + .computer + .cmp(dest, Operand::Immediate(ImmediateOperand::Word(src))), + Mnemonic::CMP_ALIb(src_byte) => self.computer.cmp( + ModRmTarget::Register(crate::register::Register::AL), + Operand::Immediate(ImmediateOperand::Byte(src_byte)), + ), + Mnemonic::CMP_AXIv(src_word) => self.computer.cmp( + ModRmTarget::Register(crate::register::Register::AX), + Operand::Immediate(ImmediateOperand::Word(src_word)), + ), + + /* + * INC + */ + Mnemonic::INC_Reg(reg) => self + .computer + .regs + .write(reg, self.computer.regs.read(reg) + 1), + Mnemonic::INC_Mod(target) => match target { + ModRmTarget::Memory(idx) => { + let val = self.computer.memory.read(&mut self.computer.regs, idx); + self.computer + .memory + .write(&mut self.computer.regs, idx, val + 1); + } + ModRmTarget::Register(reg) => self + .computer + .regs + .write(reg, self.computer.regs.read(reg) + 1), + }, + + /* + * DEC + */ + Mnemonic::DEC_Reg(reg) => self + .computer + .regs + .write(reg, self.computer.regs.read(reg) - 1), + Mnemonic::DEC_Mod(target) => match target { + ModRmTarget::Memory(idx) => { + let val = self.computer.memory.read(&mut self.computer.regs, idx); + self.computer + .memory + .write(&mut self.computer.regs, idx, val - 1); + } + ModRmTarget::Register(reg) => self + .computer + .regs + .write(reg, self.computer.regs.read(reg) - 1), + }, + + /* + * Jumps + */ + + /* + * Test + */ + + /* + * XCHG + */ + /* * MOV */ Mnemonic::MOV_BXIv(word) => self.computer.regs.bx.write(word), + + /* + * LEA + */ + + /* + * Sign extensions + */ + + /* + * Call + */ + + /* + * Jump + */ + + /* + * Wait + */ + + /* + * Push/Pop Flags + */ + + /* + * String Byte Operations + */ + + /* + * RET + */ + + /* + * Load ES/DS Register + */ + + /* + * Not/Neg + */ + + /* + * MUL + */ + + /* + * DIV + */ + + /* + * HLT + */ + + /* + * Shift and Rotate + */ + + /* + * IN + */ + + /* + * OUT + */ + + /* + * INT + */ Mnemonic::INT(id) => self.interpret_interrupt(id)?, + + /* + * Flag manipulation + */ + + /* + * Repeat prefixes + */ + + /* + * Adjust + */ + + /* + * Misc + */ _ => log::info!("no action done"), } } diff --git a/src/operands.rs b/src/operands.rs index f557323..fd21823 100644 --- a/src/operands.rs +++ b/src/operands.rs @@ -7,7 +7,7 @@ use crate::register::SegmentRegister; use crate::{disasm::DisasmError, register::Register}; use core::fmt; -use std::ops::{Add, Div, Mul, Sub}; +use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Sub}; pub type Byte = u8; // b pub type IByte = i8; // used for displacements of memory access @@ -102,16 +102,17 @@ impl Add for ImmediateOperand { match self { ImmediateOperand::Byte(lhsb) => match other { ImmediateOperand::Byte(rhsb) => ImmediateOperand::Byte(lhsb.wrapping_add(rhsb)), - _ => panic!("Cannot add Word to Byte"), + ImmediateOperand::Word(rhsw) => ImmediateOperand::Word(match other.sign_extend() { + ImmediateOperand::Word(lhsw) => lhsw.wrapping_add(rhsw), + _ => panic!("unreachable"), + }), }, ImmediateOperand::Word(lhsw) => match other { ImmediateOperand::Word(rhsw) => ImmediateOperand::Word(lhsw.wrapping_add(rhsw)), - ImmediateOperand::Byte(_) => { - ImmediateOperand::Word(lhsw.wrapping_add(match other.sign_extend() { - ImmediateOperand::Word(w) => w, - _ => panic!("Sign-extended Word is a Byte"), - })) - } + ImmediateOperand::Byte(_) => ImmediateOperand::Word(match other.sign_extend() { + ImmediateOperand::Word(rhsw) => lhsw.wrapping_add(rhsw), + _ => panic!("unreachable"), + }), }, } } @@ -142,6 +143,16 @@ impl Add for ImmediateOperand { } } +impl Add for ImmediateOperand { + type Output = ImmediateOperand; + + fn add(self, imm: Byte) -> Self::Output { + match self { + Self::Byte(b) => Self::Byte(b.wrapping_add(imm)), + Self::Word(w) => Self::Word(w.wrapping_add(imm as Word)), + } + } +} impl Sub for ImmediateOperand { type Output = Self; @@ -149,21 +160,32 @@ impl Sub for ImmediateOperand { match self { ImmediateOperand::Byte(lhsb) => match other { ImmediateOperand::Byte(rhsb) => ImmediateOperand::Byte(lhsb.wrapping_sub(rhsb)), - _ => panic!("Cannot substract Word from Byte"), + ImmediateOperand::Word(rhsw) => ImmediateOperand::Word(match other.sign_extend() { + ImmediateOperand::Word(lhsw) => lhsw.wrapping_sub(rhsw), + _ => panic!("unreachable"), + }), }, ImmediateOperand::Word(lhsw) => match other { ImmediateOperand::Word(rhsw) => ImmediateOperand::Word(lhsw.wrapping_sub(rhsw)), - ImmediateOperand::Byte(_) => { - ImmediateOperand::Word(lhsw.wrapping_sub(match other.sign_extend() { - ImmediateOperand::Word(w) => w, - _ => panic!("Sign-extended Word is a Byte"), - })) - } + ImmediateOperand::Byte(_) => ImmediateOperand::Word(match other.sign_extend() { + ImmediateOperand::Word(rhsw) => lhsw.wrapping_sub(rhsw), + _ => panic!("unreachable"), + }), }, } } } +impl Sub for ImmediateOperand { + type Output = ImmediateOperand; + + fn sub(self, imm: Byte) -> Self::Output { + match self { + Self::Byte(b) => Self::Byte(b.wrapping_sub(imm)), + Self::Word(w) => Self::Word(w.wrapping_sub(imm as Word)), + } + } +} impl Mul for ImmediateOperand { type Output = Self; @@ -171,16 +193,17 @@ impl Mul for ImmediateOperand { match self { ImmediateOperand::Byte(lhsb) => match other { ImmediateOperand::Byte(rhsb) => ImmediateOperand::Byte(lhsb.wrapping_mul(rhsb)), - _ => panic!("Cannot multiply Byte with Word"), + ImmediateOperand::Word(rhsw) => ImmediateOperand::Word(match other.sign_extend() { + ImmediateOperand::Word(lhsw) => lhsw.wrapping_mul(rhsw), + _ => panic!("unreachable"), + }), }, ImmediateOperand::Word(lhsw) => match other { ImmediateOperand::Word(rhsw) => ImmediateOperand::Word(lhsw.wrapping_mul(rhsw)), - ImmediateOperand::Byte(_) => { - ImmediateOperand::Word(lhsw.wrapping_mul(match other.sign_extend() { - ImmediateOperand::Word(w) => w, - _ => panic!("Sign-extended Word is a Byte"), - })) - } + ImmediateOperand::Byte(_) => ImmediateOperand::Word(match other.sign_extend() { + ImmediateOperand::Word(rhsw) => lhsw.wrapping_mul(rhsw), + _ => panic!("unreachable"), + }), }, } } @@ -193,16 +216,86 @@ impl Div for ImmediateOperand { match self { ImmediateOperand::Byte(lhsb) => match other { ImmediateOperand::Byte(rhsb) => ImmediateOperand::Byte(lhsb.wrapping_div(rhsb)), - _ => panic!("Cannot divide Byte with Word"), + ImmediateOperand::Word(rhsw) => ImmediateOperand::Word(match other.sign_extend() { + ImmediateOperand::Word(lhsw) => lhsw.wrapping_div(rhsw), + _ => panic!("unreachable"), + }), }, ImmediateOperand::Word(lhsw) => match other { ImmediateOperand::Word(rhsw) => ImmediateOperand::Word(lhsw.wrapping_div(rhsw)), - ImmediateOperand::Byte(_) => { - ImmediateOperand::Word(lhsw.wrapping_div(match other.sign_extend() { - ImmediateOperand::Word(w) => w, - _ => panic!("Sign-extended Word is a Byte"), - })) - } + ImmediateOperand::Byte(_) => ImmediateOperand::Word(match other.sign_extend() { + ImmediateOperand::Word(rhsw) => lhsw.wrapping_div(rhsw), + _ => panic!("unreachable"), + }), + }, + } + } +} + +impl BitOr for ImmediateOperand { + type Output = Self; + + fn bitor(self, other: Self) -> Self { + match self { + ImmediateOperand::Byte(lhsb) => match other { + ImmediateOperand::Byte(rhsb) => ImmediateOperand::Byte(lhsb | rhsb), + ImmediateOperand::Word(rhsw) => match other.sign_extend() { + ImmediateOperand::Word(lhsw) => ImmediateOperand::Word(lhsw | rhsw), + _ => panic!("unreachable"), + }, + }, + ImmediateOperand::Word(lhsw) => match other { + ImmediateOperand::Word(rhsw) => ImmediateOperand::Word(lhsw | rhsw), + ImmediateOperand::Byte(_) => match other.sign_extend() { + ImmediateOperand::Word(rhsw) => ImmediateOperand::Word(lhsw | rhsw), + _ => panic!("unreachable"), + }, + }, + } + } +} + +impl BitAnd for ImmediateOperand { + type Output = Self; + + fn bitand(self, other: Self) -> Self { + match self { + ImmediateOperand::Byte(lhsb) => match other { + ImmediateOperand::Byte(rhsb) => ImmediateOperand::Byte(lhsb & rhsb), + ImmediateOperand::Word(rhsw) => match other.sign_extend() { + ImmediateOperand::Word(lhsw) => ImmediateOperand::Word(lhsw & rhsw), + _ => panic!("unreachable"), + }, + }, + ImmediateOperand::Word(lhsw) => match other { + ImmediateOperand::Word(rhsw) => ImmediateOperand::Word(lhsw & rhsw), + ImmediateOperand::Byte(_) => match other.sign_extend() { + ImmediateOperand::Word(rhsw) => ImmediateOperand::Word(lhsw & rhsw), + _ => panic!("unreachable"), + }, + }, + } + } +} + +impl BitXor for ImmediateOperand { + type Output = Self; + + fn bitxor(self, other: Self) -> Self { + match self { + ImmediateOperand::Byte(lhsb) => match other { + ImmediateOperand::Byte(rhsb) => ImmediateOperand::Byte(lhsb ^ rhsb), + ImmediateOperand::Word(rhsw) => match other.sign_extend() { + ImmediateOperand::Word(lhsw) => ImmediateOperand::Word(lhsw ^ rhsw), + _ => panic!("unreachable"), + }, + }, + ImmediateOperand::Word(lhsw) => match other { + ImmediateOperand::Word(rhsw) => ImmediateOperand::Word(lhsw ^ rhsw), + ImmediateOperand::Byte(_) => match other.sign_extend() { + ImmediateOperand::Word(rhsw) => ImmediateOperand::Word(lhsw ^ rhsw), + _ => panic!("unreachable"), + }, }, } }