From 35fefb762570be186ff939218a53913930c722d5 Mon Sep 17 00:00:00 2001 From: Marco Thomas Date: Tue, 10 Jun 2025 10:59:35 +0900 Subject: [PATCH] ft(interpreter): generalize binary operations --- src/interpreter/computer.rs | 74 ++++++++++++++++++++++------------ src/interpreter/interpreter.rs | 23 +++++++++++ src/operands.rs | 40 +++++++++++++++++- 3 files changed, 110 insertions(+), 27 deletions(-) diff --git a/src/interpreter/computer.rs b/src/interpreter/computer.rs index 30a6c84..f7a8eac 100644 --- a/src/interpreter/computer.rs +++ b/src/interpreter/computer.rs @@ -27,30 +27,52 @@ impl Computer { } } - /// Adds two [`Argument`]s, saves it to `dest` and sets flags, if necessary. + pub fn add(&mut self, dest: ModRmTarget, src: Operand) { + let op = |lhs, rhs| lhs + rhs; + // TODO let flag_check = |_| (); + self.op(op, dest, src); + } + + pub fn sub(&mut self, dest: ModRmTarget, src: Operand) { + let op = |lhs, rhs| lhs - rhs; + // TODO let flag_check = |_| (); + self.op(op, 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 /// be a [`ModRmTarget`]. - pub fn add(&mut self, dest: ModRmTarget, src: Operand) { + fn op(&mut self, op: O, dest: ModRmTarget, src: Operand) + where + O: Fn(ImmediateOperand, ImmediateOperand) -> ImmediateOperand, + // F: Fn(&mut Flags); + { match src { - Operand::ModRmTarget(src_target) => self.add_modrm(dest, src_target), - Operand::Immediate(src_operand) => self.add_imm(dest, src_operand), + Operand::ModRmTarget(src_target) => self.op_modrm(op, dest, src_target), + Operand::Immediate(src_operand) => self.op_imm(op, dest, src_operand), } } - /// Adds two [`ModRmTarget`]s togeher, saves it to `dest` and sets flags, if necessary. - fn add_modrm(&mut self, dest: ModRmTarget, src: ModRmTarget) { + /// 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) + where + O: Fn(ImmediateOperand, ImmediateOperand) -> ImmediateOperand, + { match dest { ModRmTarget::Memory(dest_memory_idx) => match src { // mem, mem - ModRmTarget::Memory(_) => panic!("Cannot add Memory to Memory!"), + ModRmTarget::Memory(_) => { + panic!("Cannot apply binary operator from Memory to Memory!") + } // mem, reg ModRmTarget::Register(src_register) => { let lhs = self.memory.read(&self.regs, dest_memory_idx); let rhs = self.regs.read(src_register); - let result = lhs + rhs; + let result = op(lhs, rhs); self.memory.write(&self.regs, dest_memory_idx, result); - // unsigned overflow - self.flags.of = result < rhs; + // flag_check(&mut self.flags); } }, ModRmTarget::Register(dest_register) => match src { @@ -58,42 +80,42 @@ impl Computer { ModRmTarget::Memory(src_memory_index) => { let lhs = self.regs.read(dest_register); let rhs = self.memory.read(&self.regs, src_memory_index); - let result = lhs + rhs; + let result = op(lhs, rhs); self.regs.write(dest_register, result); - // unsigned overflow - self.flags.of = result < rhs; + // flag_check(&mut self.flags); } // reg, reg ModRmTarget::Register(src_register) => { let lhs = self.regs.read(dest_register); let rhs = self.regs.read(src_register); - let result = lhs + rhs; + let result = op(lhs, rhs); self.regs.write(dest_register, result); - - // unsigned overflow - self.flags.of = result < rhs + // flag_check(&mut self.flags); } }, } } - /// Adds an [`ImmediateOperand`] to a location pointed to by a - /// [`ModRmTarget`], saves it to dest and sets flags, if necessary. - fn add_imm(&mut self, dest: ModRmTarget, src: ImmediateOperand) { + /// 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) + where + O: Fn(ImmediateOperand, ImmediateOperand) -> ImmediateOperand, + // F: for<'F> Fn(&'F mut Flags), + { match dest { ModRmTarget::Memory(dest_mem) => { let lhs = self.memory.read(&self.regs, dest_mem); - let result = lhs + src; - // unsigned overflow - self.flags.of = result < src; + let result = op(lhs, src); self.memory.write(&self.regs, dest_mem, result); + // flag_check(&mut self.flags); } ModRmTarget::Register(dest_reg) => { let lhs = self.regs.read(dest_reg); - let result = lhs + src; - // unsigned overflow - self.flags.of = result < src; + let result = op(lhs, src); self.regs.write(dest_reg, result); + // flag_check(&mut self.flags); } } } diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index 6eaf024..457e464 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -78,6 +78,29 @@ impl Interpreter { ModRmTarget::Register(crate::register::Register::AX), Operand::Immediate(ImmediateOperand::Word(src_word)), ), + /* + * SUB + */ + Mnemonic::SUB_FromReg(dest, src) => self + .computer + .sub(dest, Operand::ModRmTarget(ModRmTarget::Register(src))), + Mnemonic::SUB_ToReg(src, dest) => self + .computer + .sub(ModRmTarget::Register(dest), Operand::ModRmTarget(src)), + Mnemonic::SUB_Ib(dest, src) => self + .computer + .sub(dest, Operand::Immediate(ImmediateOperand::Byte(src))), + Mnemonic::SUB_Iv(dest, src) => self + .computer + .sub(dest, Operand::Immediate(ImmediateOperand::Word(src))), + Mnemonic::SUB_ALIb(src_byte) => self.computer.sub( + ModRmTarget::Register(crate::register::Register::AL), + Operand::Immediate(ImmediateOperand::Byte(src_byte)), + ), + Mnemonic::SUB_AXIv(src_word) => self.computer.sub( + ModRmTarget::Register(crate::register::Register::AX), + Operand::Immediate(ImmediateOperand::Word(src_word)), + ), /* * MOV diff --git a/src/operands.rs b/src/operands.rs index f9d137b..b9be55b 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, Sub}; +use std::ops::{Add, Div, Mul, Sub}; pub type Byte = u8; // b pub type IByte = i8; // used for displacements of memory access @@ -88,6 +88,44 @@ impl Sub for ImmediateOperand { } } +impl Mul for ImmediateOperand { + type Output = Self; + + fn mul(self, other: Self) -> Self { + match self { + ImmediateOperand::Byte(lhsb) => match other { + ImmediateOperand::Byte(rhsb) => ImmediateOperand::Byte(lhsb.wrapping_mul(rhsb)), + _ => panic!("Cannot multiply Byte with Word"), + }, + ImmediateOperand::Word(lhsw) => match other { + ImmediateOperand::Word(rhsw) => ImmediateOperand::Word(lhsw.wrapping_mul(rhsw)), + ImmediateOperand::Byte(rhsb) => { + ImmediateOperand::Word(lhsw.wrapping_mul(rhsb as Word)) + } + }, + } + } +} + +impl Div for ImmediateOperand { + type Output = Self; + + fn div(self, other: Self) -> Self { + match self { + ImmediateOperand::Byte(lhsb) => match other { + ImmediateOperand::Byte(rhsb) => ImmediateOperand::Byte(lhsb.wrapping_div(rhsb)), + _ => panic!("Cannot divide Byte with Word"), + }, + ImmediateOperand::Word(lhsw) => match other { + ImmediateOperand::Word(rhsw) => ImmediateOperand::Word(lhsw.wrapping_div(rhsw)), + ImmediateOperand::Byte(rhsb) => { + ImmediateOperand::Word(lhsw.wrapping_div(rhsb as Word)) + } + }, + } + } +} + impl fmt::Display for ImmediateOperand { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self {