emu: ADD/ADC/SUB/SBB operations

This commit is contained in:
2021-04-27 01:15:30 -07:00
parent 940f2d1d1e
commit bd00e9ca5f
4 changed files with 92 additions and 4 deletions

View File

@@ -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,

View File

@@ -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

View File

@@ -12,6 +12,7 @@ pub trait Operand: Copy + 'static +
nt::int::PrimInt +
nt::ops::checked::CheckedShl<Output = Self> +
nt::ops::checked::CheckedShr<Output = Self> +
nt::ops::overflowing::OverflowingAdd +
nt::ops::overflowing::OverflowingSub +
nt::ops::wrapping::WrappingAdd +
nt::ops::wrapping::WrappingNeg +

View File

@@ -66,6 +66,29 @@ pub fn peek(addr: impl Address + RValue<u8>) {
println!("PEEK: @{:#X} = {:#X} ({})", addr.addr(), addr.read(), addr.read());
}
pub fn adc<T: Operand>(flags: &mut Flags, mut dst: impl LValue<T>, src: impl RValue<T>)
where bool: Into<T>
{
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<T: Operand>(flags: &mut Flags, mut dst: impl LValue<T>, src: impl RValue<T>) {
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<T: Operand>(flags: &mut Flags, mut dst: impl LValue<T>, src: impl RValue<T>) {
let res = dst.read() & src.read();
dst.write(res);
@@ -572,6 +595,19 @@ where T: Operand,
T::HI_BIT_MASK.into());
}
pub fn sbb<T: Operand>(flags: &mut Flags, mut dst: impl LValue<T>, src: impl RValue<T>)
where bool: Into<T>
{
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<T, RVal>(flags: &mut Flags,
bus: &mut Bus,
rep: RepPrefix,
@@ -670,6 +706,16 @@ where RVal: RValue<T>,
});
}
pub fn sub<T: Operand>(flags: &mut Flags, mut dst: impl LValue<T>, src: impl RValue<T>) {
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<T: Operand>(flags: &mut Flags, dst: impl RValue<T>, src: impl RValue<T>) {
let res = dst.read() & src.read();
flags.update(FlagOp::LOGIC, res.into(), T::HI_BIT_MASK.into());