emu: ADD/ADC/SUB/SBB operations
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 +
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user