diff --git a/src/emu/flags.rs b/src/emu/flags.rs index e40ba07..244cd31 100644 --- a/src/emu/flags.rs +++ b/src/emu/flags.rs @@ -40,6 +40,7 @@ impl Flags { FlagOp::Eager { cf, .. } => cf, FlagOp::DEC { cf } => cf, FlagOp::INC { cf } => cf, + FlagOp::LOGIC => false, FlagOp::NEG { .. } => { self.res != 0 }, FlagOp::POPF => { self.res & 1 << CF_BIT != 0 }, FlagOp::RCL { dst, shamt, bits, old_cf, .. } => { @@ -101,6 +102,7 @@ impl Flags { pub fn af(&self) -> bool { match self.flag_op { FlagOp::Eager { af, .. } => af, + FlagOp::LOGIC => false, // undefined FlagOp::POPF => { self.res & 1 << AF_BIT != 0 }, FlagOp::RCL { af, .. } | FlagOp::RCR { af, .. } @@ -139,6 +141,7 @@ impl Flags { FlagOp::Eager { of, .. } => of, FlagOp::DEC { .. } => { self.res == self.sign_mask - 1 }, FlagOp::INC { .. } => { self.res == self.sign_mask }, + FlagOp::LOGIC => false, FlagOp::NEG { dst } => { self.res == dst && dst != 0 }, FlagOp::POPF => { self.res & 1 << OF_BIT != 0 }, FlagOp::RCL { dst, .. } @@ -166,6 +169,7 @@ pub enum FlagOp { Eager { cf: bool, pf: bool, af: bool, zf: bool, sf: bool, of: bool }, // all flags precomputed DEC { cf: bool }, INC { cf: bool }, + LOGIC, NEG { dst: u16 }, POPF, // flags encoded in result RCL { dst: u16, shamt: u16, bits: u16, old_cf: bool, pf: bool, af: bool, zf: bool, sf: bool }, diff --git a/src/emu/i8088.rs b/src/emu/i8088.rs index 679eb92..071069b 100644 --- a/src/emu/i8088.rs +++ b/src/emu/i8088.rs @@ -46,7 +46,7 @@ pub enum RepPrefix { macro_rules! step { // Base case: all args processed and ready to call op - (@code $(form=($($tyargs:tt),*),)? ( $($done:tt)* ), + (@code $(form=($($tyargs:tt),*),)? ( $($done:tt)* ), $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt, $name:ident, $cycles:literal, ()) => { ops::$name$(::<$($tyargs),*>)?($($done),*); @@ -403,13 +403,31 @@ impl i8088 { opcodes: { 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 + 0x09 _ => or[flags, modrm16, r16] / "3/24+", // OR r/m16, r16 + 0x0A _ => or[flags, r8, modrm8] / "3/13+", // OR r8, r/m8 + 0x0B _ => or[flags, r16, modrm16] / "3/13+", // OR r16, r/m16 + 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, 0x16 => push[bus, regval=ss, reg=sp, regval=ss] / 14, 0x17 => pop[bus, regval=ss, reg=sp, reg=ss] / 12, 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 + 0x21 _ => and[flags, modrm16, r16] / "3/24+", // AND r/m16, r16 + 0x22 _ => and[flags, r8, modrm8] / "3/13+", // AND r8, r/m8 + 0x23 _ => and[flags, r16, modrm16] / "3/13+", // AND r16, r/m16 + 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, 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 + 0x32 _ => xor[flags, r8, modrm8] / "3/13+", // XOR r8, r/m8 + 0x33 _ => xor[flags, r16, modrm16] / "3/13+", // XOR r16, r/m16 + 0x34 => xor[flags, reglo=a, d8] / 4, // XOR al, d8 + 0x35 => xor[flags, reg=a, d16] / 4, // XOR ax, d16 0x36 => nop[seg=ss, prefix] / 2, 0x38 _ => cmp[flags, modrm8, r8] / "3/24+", 0x39 _ => cmp[flags, modrm16, r16] / "3/24+", @@ -470,9 +488,20 @@ 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: { 0x38 => cmp[flags, modrm8, d8] / "4/23+", }, - 0x81: { 0x38 => cmp[flags, modrm16, d16] / "4/23+", }, - 0x83: { 0x38 => cmp[flags, modrm16, d8_as_d16] / "4/23+", }, + 0x80: { 0x08 => or[flags, modrm8, d8] / "4/23+", // OR r/m8, d8 + 0x20 => and[flags, modrm8, d8] / "4/23+", // AND 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 + 0x20 => and[flags, modrm16, d16] / "4/23+", // AND 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 + 0x20 => and[flags, modrm16, d8_as_d16] / "4/23+", // AND 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 + 0x85 _ => test[flags, modrm16, r16] / "3/13+", // TEST r/m16, r16 0x86 _ => xchg[r8, modrm8] / "4/25+", // XCHG r8, r/m8 0x87 _ => xchg[r16, modrm16] / "4/25+", // XCHG r16, r/m16 0x88 _ => mov[modrm8, r8] / "2/13+", // MOV r/m8, r8 @@ -509,6 +538,8 @@ impl i8088 { 0xA5 => movs[form=word0, flags, bus, rep, reg=c, seg=ds, seg, reg=si, reg=es, reg=di] / "26/9+25n", 0xA6 => cmps[form=byte0, flags, bus, rep, reg=c, seg=ds, seg, reg=si, reg=es, reg=di] / "22/9+22n", 0xA7 => cmps[form=word0, flags, bus, rep, reg=c, seg=ds, seg, reg=si, reg=es, reg=di] / "30/9+30n", + 0xA8 => test[flags, reglo=a, d8] / 4, // TEST al, d8 + 0xA9 => test[flags, reg=a, d16] / 4, // TEST ax, d16 0xAA => stos[flags, bus, rep, reg=c, reg=es, reg=di, reglo=a] / "11/9+10n", 0xAB => stos[flags, bus, rep, reg=c, reg=es, reg=di, reg=a] / "15/9+14n", 0xAC => lods[flags, bus, rep, reg=c, seg=ds, seg, reg=si, reglo=a] / "12/9+13n", @@ -573,9 +604,11 @@ impl i8088 { 0xF2 => nop[rep=NotEqual, prefix] / 0, // REPNE/REPNZ 0xF3 => nop[rep=Equal, prefix] / 0, // REP/REPE/REPZ 0xF5 => cmc[flags] / 2, // CMC (Complement Carry Flag) - 0xF6: { 0x10 => not[form=byte1, modrm8] / "3/24+", // NOT r/m8 + 0xF6: { 0x00 => test[flags, modrm8, d8] / "5/11+", // TEST r/m8, d8 + 0x10 => not[form=byte1, modrm8] / "3/24+", // NOT r/m8 0x18 => neg[form=byte1, flags, modrm8] / "3/24+" }, // NEG r/m8 - 0xF7: { 0x10 => not[form=word1, modrm16] / "3/24+", // NOT r/m16 + 0xF7: { 0x00 => test[flags, modrm16, d16] / "5/11+", // TEST r/m16, d16 + 0x10 => not[form=word1, modrm16] / "3/24+", // NOT r/m16 0x18 => neg[form=word1, flags, modrm16] / "3/24+" }, // NEG r/m16 0xF8 => clc[flags] / 2, // CLC (Clear Carry Flag) 0xF9 => stc[flags] / 2, // STC (Set Carry Flag) diff --git a/src/emu/operations.rs b/src/emu/operations.rs index b0ae4c8..42289a1 100644 --- a/src/emu/operations.rs +++ b/src/emu/operations.rs @@ -66,6 +66,12 @@ pub fn peek(addr: impl Address + RValue) { println!("PEEK: @{:#X} = {:#X} ({})", addr.addr(), addr.read(), addr.read()); } +pub fn and(flags: &mut Flags, mut dst: impl LValue, src: impl RValue) { + let res = dst.read() & src.read(); + dst.write(res); + flags.update(FlagOp::LOGIC, res.into(), T::HI_BIT_MASK.into()); +} + pub fn call(mut ip: Reg, bus: &mut Bus, ss: u16, sp: Reg, rel16: u16) { let target = ip.read().wrapping_add(rel16); push(bus, ss, sp, ip.read()); @@ -332,6 +338,13 @@ pub fn neg>(flags: &mut Flags, mut dst: LVal) { T::HI_BIT_MASK.into()); } +pub fn or(flags: &mut Flags, mut dst: impl LValue, src: impl RValue) { + let res = dst.read() | src.read(); + dst.write(res); + flags.update(FlagOp::LOGIC, res.into(), T::HI_BIT_MASK.into()); +} + + pub fn pop>(bus: &mut Bus, ss: u16, mut sp: Reg, mut dst: LVal) { let ptr = FarPtr { bus: bus, segment: ss, offset: sp.read() }; dst.write(ptr.read()); @@ -657,8 +670,19 @@ where RVal: RValue, }); } +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()); +} + pub fn xchg, Src: LValue>(mut dst: Dst, mut src: Src) { let tmp = src.read(); src.write(dst.read()); dst.write(tmp); } + +pub fn xor(flags: &mut Flags, mut dst: impl LValue, src: impl RValue) { + let res = dst.read() ^ src.read(); + dst.write(res); + flags.update(FlagOp::LOGIC, res.into(), T::HI_BIT_MASK.into()); +}