From bd00e9ca5f2e4bd50601a1888852d9d81518910f Mon Sep 17 00:00:00 2001 From: Jared Burce Date: Tue, 27 Apr 2021 01:15:30 -0700 Subject: [PATCH] emu: ADD/ADC/SUB/SBB operations --- src/emu/flags.rs | 7 ++++++- src/emu/i8088.rs | 42 ++++++++++++++++++++++++++++++++++++--- src/emu/operands.rs | 1 + src/emu/operations.rs | 46 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 4 deletions(-) diff --git a/src/emu/flags.rs b/src/emu/flags.rs index 244cd31..14df95c 100644 --- a/src/emu/flags.rs +++ b/src/emu/flags.rs @@ -38,6 +38,7 @@ impl Flags { pub fn cf(&self) -> bool { match self.flag_op { FlagOp::Eager { cf, .. } => cf, + FlagOp::ADD { cf, .. } => cf, FlagOp::DEC { cf } => cf, FlagOp::INC { cf } => cf, FlagOp::LOGIC => false, @@ -139,6 +140,9 @@ impl Flags { pub fn of(&self) -> bool { match self.flag_op { FlagOp::Eager { of, .. } => of, + FlagOp::ADD { dst, src, .. } => { 0 != self.sign_mask & // In the (maybe) sign bit... + (dst ^ src ^ self.sign_mask) & // ...operands have same sign... + (dst ^ self.res) }, // ...and result sign-bit changed FlagOp::DEC { .. } => { self.res == self.sign_mask - 1 }, FlagOp::INC { .. } => { self.res == self.sign_mask }, FlagOp::LOGIC => false, @@ -152,7 +156,7 @@ impl Flags { | FlagOp::SHL { dst, .. } | FlagOp::SHR { dst, .. } => { 0 != self.sign_mask & (dst ^ self.res) }, FlagOp::SUB { dst, src, .. } => { 0 != self.sign_mask & // In the (maybe) sign bit... - (src ^ dst) & // ...operands have different signs... + (dst ^ src) & // ...operands have different signs... (dst ^ self.res) }, // ...and result sign-bit changed } } @@ -167,6 +171,7 @@ impl Flags { #[derive(Clone, Copy)] pub enum FlagOp { Eager { cf: bool, pf: bool, af: bool, zf: bool, sf: bool, of: bool }, // all flags precomputed + ADD { dst: u16, src: u16, cf: bool }, DEC { cf: bool }, INC { cf: bool }, LOGIC, diff --git a/src/emu/i8088.rs b/src/emu/i8088.rs index 56c974c..1e0e531 100644 --- a/src/emu/i8088.rs +++ b/src/emu/i8088.rs @@ -427,6 +427,12 @@ impl i8088 { loop { step!((self, bus) => opcodes: { + 0x00 _ => add[flags, modrm8, r8] / "3/24+", // ADD r/m8, r8 + 0x01 _ => add[flags, modrm16, r16] / "3/24+", // ADD r/m16, r16 + 0x02 _ => add[flags, r8, modrm8] / "3/13+", // ADD r8, r/m8 + 0x03 _ => add[flags, r16, modrm16] / "3/13+", // ADD r16, r/m16 + 0x04 => add[flags, reglo=a, d8] / 4, // ADD al, d8 + 0x05 => add[flags, reg=a, d16] / 4, // ADD ax, d16 0x06 => push[bus, regval=ss, reg=sp, regval=es] / 14, 0x07 => pop[bus, regval=ss, reg=sp, reg=es] / 12, 0x08 _ => or[flags, modrm8, r8] / "3/24+", // OR r/m8, r8 @@ -436,8 +442,20 @@ impl i8088 { 0x0C => or[flags, reglo=a, d8] / 4, // OR al, d8 0x0D => or[flags, reg=a, d16] / 4, // OR ax, d16 0x0E => push[bus, regval=ss, reg=sp, regval=cs] / 14, + 0x10 _ => adc[flags, modrm8, r8] / "3/24+", // ADC r/m8, r8 + 0x11 _ => adc[flags, modrm16, r16] / "3/24+", // ADC r/m16, r16 + 0x12 _ => adc[flags, r8, modrm8] / "3/13+", // ADC r8, r/m8 + 0x13 _ => adc[flags, r16, modrm16] / "3/13+", // ADC r16, r/m16 + 0x14 => adc[flags, reglo=a, d8] / 4, // ADC al, d8 + 0x15 => adc[flags, reg=a, d16] / 4, // ADC ax, d16 0x16 => push[bus, regval=ss, reg=sp, regval=ss] / 14, 0x17 => pop[bus, regval=ss, reg=sp, reg=ss] / 12, + 0x18 _ => sbb[flags, modrm8, r8] / "3/24+", // SBB r/m8, r8 + 0x19 _ => sbb[flags, modrm16, r16] / "3/24+", // SBB r/m16, r16 + 0x1A _ => sbb[flags, r8, modrm8] / "3/13+", // SBB r8, r/m8 + 0x1B _ => sbb[flags, r16, modrm16] / "3/13+", // SBB r16, r/m16 + 0x1C => sbb[flags, reglo=a, d8] / 4, // SBB al, d8 + 0x1D => sbb[flags, reg=a, d16] / 4, // SBB ax, d16 0x1E => push[bus, regval=ss, reg=sp, regval=ds] / 14, 0x1F => pop[bus, regval=ss, reg=sp, reg=ds] / 12, 0x20 _ => and[flags, modrm8, r8] / "3/24+", // AND r/m8, r8 @@ -447,6 +465,12 @@ impl i8088 { 0x24 => and[flags, reglo=a, d8] / 4, // AND al, d8 0x25 => and[flags, reg=a, d16] / 4, // AND ax, d16 0x26 => nop[seg=es, prefix] / 2, + 0x28 _ => sub[flags, modrm8, r8] / "3/24+", // SUB r/m8, r8 + 0x29 _ => sub[flags, modrm16, r16] / "3/24+", // SUB r/m16, r16 + 0x2A _ => sub[flags, r8, modrm8] / "3/13+", // SUB r8, r/m8 + 0x2B _ => sub[flags, r16, modrm16] / "3/13+", // SUB r16, r/m16 + 0x2C => sub[flags, reglo=a, d8] / 4, // SUB al, d8 + 0x2D => sub[flags, reg=a, d16] / 4, // SUB ax, d16 0x2E => nop[seg=cs, prefix] / 2, 0x30 _ => xor[flags, modrm8, r8] / "3/24+", // XOR r/m8, r8 0x31 _ => xor[flags, modrm16, r16] / "3/24+", // XOR r/m16, r16 @@ -514,16 +538,28 @@ impl i8088 { 0x7D => jge[flags, reg=ip, rel8] / "16/4", // JNL/JGE rel8 0x7E => jle[flags, reg=ip, rel8] / "16/4", // JLE/JNG rel8 0x7F => jg[flags, reg=ip, rel8] / "16/4", // JNLE/JG rel8 - 0x80: { 0x08 => or[flags, modrm8, d8] / "4/23+", // OR r/m8, d8 + 0x80: { 0x00 => add[flags, modrm8, d8] / "4/23+", // ADD r/m8, d8 + 0x08 => or[flags, modrm8, d8] / "4/23+", // OR r/m8, d8 + 0x10 => adc[flags, modrm8, d8] / "4/23+", // ADC r/m8, d8 + 0x18 => sbb[flags, modrm8, d8] / "4/23+", // SBB r/m8, d8 0x20 => and[flags, modrm8, d8] / "4/23+", // AND r/m8, d8 + 0x28 => sub[flags, modrm8, d8] / "4/23+", // SUB r/m8, d8 0x30 => xor[flags, modrm8, d8] / "4/23+", // XOR r/m8, d8 0x38 => cmp[flags, modrm8, d8] / "4/23+", }, // CMP r/m8, d8 - 0x81: { 0x08 => or[flags, modrm16, d16] / "4/23+", // OR r/m16, d16 + 0x81: { 0x00 => add[flags, modrm16, d16] / "4/23+", // ADD r/m16, d16 + 0x08 => or[flags, modrm16, d16] / "4/23+", // OR r/m16, d16 + 0x10 => adc[flags, modrm16, d16] / "4/23+", // ADC r/m16, d16 + 0x18 => sbb[flags, modrm16, d16] / "4/23+", // SBB r/m16, d16 0x20 => and[flags, modrm16, d16] / "4/23+", // AND r/m16, d16 + 0x28 => sub[flags, modrm16, d16] / "4/23+", // SUB r/m16, d16 0x30 => xor[flags, modrm16, d16] / "4/23+", // XOR r/m16, d16 0x38 => cmp[flags, modrm16, d16] / "4/23+", }, // CMP r/m16, d16 - 0x83: { 0x08 => or[flags, modrm16, d8_as_d16] / "4/23+", // OR r/m16, d8 + 0x83: { 0x00 => add[flags, modrm16, d8_as_d16] / "4/23+", // ADD r/m16, d8 + 0x08 => or[flags, modrm16, d8_as_d16] / "4/23+", // OR r/m16, d8 + 0x10 => adc[flags, modrm16, d8_as_d16] / "4/23+", // ADC r/m16, d8 + 0x18 => sbb[flags, modrm16, d8_as_d16] / "4/23+", // SBB r/m16, d8 0x20 => and[flags, modrm16, d8_as_d16] / "4/23+", // AND r/m16, d8 + 0x28 => sub[flags, modrm16, d8_as_d16] / "4/23+", // SUB r/m16, d8 0x30 => xor[flags, modrm16, d8_as_d16] / "4/23+", // XOR r/m16, d8 0x38 => cmp[flags, modrm16, d8_as_d16] / "4/23+", }, // CMP r/m16, d8 0x84 _ => test[flags, modrm8, r8] / "3/13+", // TEST r/m8, r8 diff --git a/src/emu/operands.rs b/src/emu/operands.rs index 7f3697d..f93529b 100644 --- a/src/emu/operands.rs +++ b/src/emu/operands.rs @@ -12,6 +12,7 @@ pub trait Operand: Copy + 'static + nt::int::PrimInt + nt::ops::checked::CheckedShl + nt::ops::checked::CheckedShr + + nt::ops::overflowing::OverflowingAdd + nt::ops::overflowing::OverflowingSub + nt::ops::wrapping::WrappingAdd + nt::ops::wrapping::WrappingNeg + diff --git a/src/emu/operations.rs b/src/emu/operations.rs index 42289a1..07242de 100644 --- a/src/emu/operations.rs +++ b/src/emu/operations.rs @@ -66,6 +66,29 @@ pub fn peek(addr: impl Address + RValue) { println!("PEEK: @{:#X} = {:#X} ({})", addr.addr(), addr.read(), addr.read()); } +pub fn adc(flags: &mut Flags, mut dst: impl LValue, src: impl RValue) +where bool: Into +{ + let dst_before = dst.read(); + let src_before = src.read(); // may alias dst + let (res_tmp, carry) = dst_before.overflowing_add(&src_before); + let (res, carry2) = res_tmp.overflowing_add(&flags.cf().into()); + dst.write(res); + flags.update(FlagOp::ADD { dst: dst_before.into(), src: src_before.into(), cf: carry | carry2 }, + res.into(), + T::HI_BIT_MASK.into()); +} + +pub fn add(flags: &mut Flags, mut dst: impl LValue, src: impl RValue) { + let dst_before = dst.read(); + let src_before = src.read(); // may alias dst + let (res, carry) = dst_before.overflowing_add(&src_before); + dst.write(res); + flags.update(FlagOp::ADD { dst: dst_before.into(), src: src_before.into(), cf: carry }, + res.into(), + T::HI_BIT_MASK.into()); +} + pub fn and(flags: &mut Flags, mut dst: impl LValue, src: impl RValue) { let res = dst.read() & src.read(); dst.write(res); @@ -572,6 +595,19 @@ where T: Operand, T::HI_BIT_MASK.into()); } +pub fn sbb(flags: &mut Flags, mut dst: impl LValue, src: impl RValue) +where bool: Into +{ + let dst_before = dst.read(); + let src_before = src.read(); + let (res_tmp, carry) = dst_before.overflowing_sub(&src_before); + let (res, carry2) = res_tmp.overflowing_sub(&flags.cf().into()); + dst.write(res); + flags.update(FlagOp::SUB { dst: dst_before.into(), src: src_before.into(), cf: carry | carry2 }, + res.into(), + T::HI_BIT_MASK.into()); +} + pub fn scas(flags: &mut Flags, bus: &mut Bus, rep: RepPrefix, @@ -670,6 +706,16 @@ where RVal: RValue, }); } +pub fn sub(flags: &mut Flags, mut dst: impl LValue, src: impl RValue) { + let dst_before = dst.read(); + let src_before = src.read(); + let (res, carry) = dst_before.overflowing_sub(&src_before); + dst.write(res); + flags.update(FlagOp::SUB { dst: dst_before.into(), src: src_before.into(), cf: carry }, + res.into(), + T::HI_BIT_MASK.into()); +} + pub fn test(flags: &mut Flags, dst: impl RValue, src: impl RValue) { let res = dst.read() & src.read(); flags.update(FlagOp::LOGIC, res.into(), T::HI_BIT_MASK.into());