From 269c4cc54b3e77f8021c0973ddffd21483bc30e8 Mon Sep 17 00:00:00 2001 From: Marco Thomas Date: Wed, 11 Jun 2025 16:31:07 +0900 Subject: [PATCH] ft(interpreter): impl adc and sbb --- src/interpreter/computer.rs | 82 ++++++++++++++++++++++++++-------- src/interpreter/interpreter.rs | 49 ++++++++++++++++++-- 2 files changed, 108 insertions(+), 23 deletions(-) diff --git a/src/interpreter/computer.rs b/src/interpreter/computer.rs index cd99062..8c1d65b 100644 --- a/src/interpreter/computer.rs +++ b/src/interpreter/computer.rs @@ -11,7 +11,7 @@ pub enum Operand { ModRmTarget(ModRmTarget), } -type Result = ImmediateOperand; +type ArithmeticResult = ImmediateOperand; type Lhs = ImmediateOperand; type Rhs = ImmediateOperand; @@ -33,8 +33,8 @@ impl Computer { /// Perform binary `dest` = `dest` + `src`. Sets flags. pub fn add(&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) = |flags, result, lhs, rhs| { + 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; flags.of = lhs.msb() && rhs.msb() != result.msb(); flags.zf = result.zero(); @@ -46,8 +46,8 @@ impl Computer { /// 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) = |flags, result, lhs, rhs| { + 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; flags.of = lhs.msb() != rhs.msb() && lhs.msb() != result.msb(); flags.zf = result.zero(); @@ -59,8 +59,8 @@ impl Computer { /// 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) = |flags, result, _, _| { + let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs | rhs; + let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, _, _| { flags.cf = false; flags.of = false; flags.zf = result.zero(); @@ -72,8 +72,8 @@ impl Computer { /// 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) = |flags, result, _, _rhs| { + 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; flags.of = false; flags.zf = result.zero(); @@ -85,8 +85,8 @@ impl Computer { /// 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) = |flags, result, _, _| { + let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs ^ rhs; + let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, _, _| { flags.cf = false; flags.of = false; flags.zf = result.zero(); @@ -99,8 +99,8 @@ impl Computer { /// 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) = |flags, result, lhs, rhs| { + 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; flags.of = lhs.msb() != rhs.msb() && lhs.msb() != result.msb(); flags.zf = result.zero(); @@ -110,14 +110,58 @@ impl Computer { self.op(op, flag_set, false, dest, src); } + /// Perform `dest` = `dest` + `src` + CF. Sets flags. + pub fn adc(&mut self, dest: ModRmTarget, src: Operand) { + 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 { + Operand::Immediate(immediate_operand) => Operand::Immediate(immediate_operand + cf), + Operand::ModRmTarget(mod_rm_target) => Operand::Immediate(match mod_rm_target { + ModRmTarget::Memory(idx) => self.memory.read(&self.regs, idx) + cf, + ModRmTarget::Register(reg) => self.regs.read(reg) + cf, + }), + }; + 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; + flags.of = lhs.msb() && rhs.msb() != result.msb(); + flags.zf = result.zero(); + flags.sf = result.msb(); + flags.pf = result.parity(); + }; + 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: Operand) { + 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 { + Operand::Immediate(immediate_operand) => Operand::Immediate(immediate_operand + cf), + Operand::ModRmTarget(mod_rm_target) => Operand::Immediate(match mod_rm_target { + ModRmTarget::Memory(idx) => self.memory.read(&self.regs, idx) + cf, + ModRmTarget::Register(reg) => self.regs.read(reg) + cf, + }), + }; + 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; + flags.of = lhs.msb() && rhs.msb() != result.msb(); + flags.zf = result.zero(); + flags.sf = result.msb(); + flags.pf = result.parity(); + }; + self.op(op, flag_set, true, dest, src_with_carry); + } + /// Applies a binary operator [`O`] to the value of two [`Operand`]s, saves /// 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, write: bool, dest: ModRmTarget, src: Operand) where - O: Fn(Lhs, Rhs) -> Result, - F: Fn(&mut Flags, Result, Lhs, Rhs), + O: Fn(Lhs, Rhs) -> ArithmeticResult, + F: Fn(&mut Flags, ArithmeticResult, Lhs, Rhs), { match src { Operand::ModRmTarget(src_target) => { @@ -138,8 +182,8 @@ impl Computer { dest: ModRmTarget, src: ModRmTarget, ) where - O: Fn(Lhs, Rhs) -> Result, - F: Fn(&mut Flags, Result, Lhs, Rhs), + O: Fn(Lhs, Rhs) -> ArithmeticResult, + F: Fn(&mut Flags, ArithmeticResult, Lhs, Rhs), { match dest { ModRmTarget::Memory(dest_memory_idx) => match src { @@ -194,8 +238,8 @@ impl Computer { dest: ModRmTarget, src: ImmediateOperand, ) where - O: Fn(Lhs, Rhs) -> Result, - F: Fn(&mut Flags, Result, Lhs, Rhs), + O: Fn(Lhs, Rhs) -> ArithmeticResult, + F: Fn(&mut Flags, ArithmeticResult, Lhs, Rhs), { match dest { ModRmTarget::Memory(dest_mem) => { diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index 2273277..8cd54c4 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -118,13 +118,54 @@ impl Interpreter { ModRmTarget::Register(crate::register::Register::AX), Operand::Immediate(ImmediateOperand::Word(src_word)), ), - /* - * ADC - */ /* - * SBB + * ADC - add with carry */ + Mnemonic::ADC_FromReg(dest, src) => self + .computer + .adc(dest, Operand::ModRmTarget(ModRmTarget::Register(src))), + Mnemonic::ADC_ToReg(src, dest) => self + .computer + .adc(ModRmTarget::Register(dest), Operand::ModRmTarget(src)), + Mnemonic::ADC_Ib(dest, src) => self + .computer + .adc(dest, Operand::Immediate(ImmediateOperand::Byte(src))), + Mnemonic::ADC_Iv(dest, src) => self + .computer + .adc(dest, Operand::Immediate(ImmediateOperand::Word(src))), + Mnemonic::ADC_ALIb(src_byte) => self.computer.adc( + ModRmTarget::Register(crate::register::Register::AL), + Operand::Immediate(ImmediateOperand::Byte(src_byte)), + ), + Mnemonic::ADC_AXIv(src_word) => self.computer.adc( + ModRmTarget::Register(crate::register::Register::AX), + Operand::Immediate(ImmediateOperand::Word(src_word)), + ), + + /* + * SBB - subtract with borrow + */ + Mnemonic::SBB_FromReg(dest, src) => self + .computer + .sbb(dest, Operand::ModRmTarget(ModRmTarget::Register(src))), + Mnemonic::SBB_ToReg(src, dest) => self + .computer + .sbb(ModRmTarget::Register(dest), Operand::ModRmTarget(src)), + Mnemonic::SBB_Ib(dest, src) => self + .computer + .sbb(dest, Operand::Immediate(ImmediateOperand::Byte(src))), + Mnemonic::SBB_Iv(dest, src) => self + .computer + .sbb(dest, Operand::Immediate(ImmediateOperand::Word(src))), + Mnemonic::SBB_ALIb(src_byte) => self.computer.sbb( + ModRmTarget::Register(crate::register::Register::AL), + Operand::Immediate(ImmediateOperand::Byte(src_byte)), + ), + Mnemonic::SBB_AXIv(src_word) => self.computer.sbb( + ModRmTarget::Register(crate::register::Register::AX), + Operand::Immediate(ImmediateOperand::Word(src_word)), + ), /* * AND