diff --git a/src/emu/flags.rs b/src/emu/flags.rs index 508b559..d67bd31 100644 --- a/src/emu/flags.rs +++ b/src/emu/flags.rs @@ -87,11 +87,22 @@ impl Flags { OperandWidth::Word => 0x8000, } } + + // The rotate ops update OF don't touch PF/AF/ZF/SF so we make + // everything eager so they don't get clobbered + pub fn update_of(&mut self, of: bool) { + let mut flags = (*self).into(); + flags &= !(1 << OF_BIT); // Mask out old OF Flag + if of { flags |= 1 << OF_BIT; } // Mask in new OF Flag + + self.flag_op = FlagOp::Eager; + self.res = flags; + } } #[derive(Clone, Copy)] pub enum FlagOp { - Eager, // precomputed into result, for e.g. POPF? (Anything else?) + Eager, // precomputed into result, for POPF or anything that changes only some flags DEC, INC, SHIFT, diff --git a/src/emu/i8088.rs b/src/emu/i8088.rs index 75f4d08..dbcca96 100644 --- a/src/emu/i8088.rs +++ b/src/emu/i8088.rs @@ -520,16 +520,24 @@ impl i8088 { 0xBF => mov[reg=di, d16] / 4, 0xC3 => pop[bus, regval=ss, reg=sp, reg=ip] / 20, // RET 0xCD => int[cpu, bus, d8] / 71, - 0xD0: { 0x20 => shl[form=byte3, flags, modrm8, const=1u8] / "2/23+", // SHL r/m8, 1 + 0xD0: { 0x00 => rol[form=byte3, flags, modrm8, const=1u8] / "2/23+", // ROL r/m16, 1 + 0x08 => ror[form=byte3, flags, modrm8, const=1u8] / "2/23+", // ROR r/m16, 1 + 0x20 => shl[form=byte3, flags, modrm8, const=1u8] / "2/23+", // SHL r/m8, 1 0x28 => shr[form=byte3, flags, modrm8, const=1u8] / "2/23+", // SHR r/m8, 1 0x38 => sar[form=byte3, flags, modrm8, const=1u8] / "2/23+" }, // SAR r/m8, 1 - 0xD1: { 0x20 => shl[form=word3, flags, modrm16, const=1u16] / "2/23+", // SHL r/m16, 1 + 0xD1: { 0x00 => rol[form=word3, flags, modrm16, const=1u16] / "2/23+", // ROL r/m16, 1 + 0x08 => ror[form=word3, flags, modrm16, const=1u16] / "2/23+", // ROR r/m16, 1 + 0x20 => shl[form=word3, flags, modrm16, const=1u16] / "2/23+", // SHL r/m16, 1 0x28 => shr[form=word3, flags, modrm16, const=1u16] / "2/23+", // SHR r/m16, 1 0x38 => sar[form=word3, flags, modrm16, const=1u16] / "2/23+" }, // SAR r/m16, 1 - 0xD2: { 0x20 => shl[form=byte3, flags, modrm8, reglo=c] / "2/23+", // SHL r/m8, CL + 0xD2: { 0x00 => rol[form=byte3, flags, modrm8, reglo=c] / "8/28++4n", // ROL r/m8, CL + 0x08 => ror[form=byte3, flags, modrm8, reglo=c] / "8/28++4n", // ROR r/m8, CL + 0x20 => shl[form=byte3, flags, modrm8, reglo=c] / "2/23+", // SHL r/m8, CL 0x28 => shr[form=byte3, flags, modrm8, reglo=c] / "2/23+", // SHR r/m8, CL 0x38 => sar[form=byte3, flags, modrm8, reglo=c] / "2/23+" }, // SAR r/m8, CL - 0xD3: { 0x20 => shl[form=word3, flags, modrm16, reglo=c] / "2/23+", // SHL r/m16, CL + 0xD3: { 0x00 => rol[form=word3, flags, modrm16, reglo=c] / "8/28++4n", // ROL r/m16, CL + 0x08 => ror[form=word3, flags, modrm16, reglo=c] / "8/28++4n", // ROR r/m16, CL + 0x20 => shl[form=word3, flags, modrm16, reglo=c] / "2/23+", // SHL r/m16, CL 0x28 => shr[form=word3, flags, modrm16, reglo=c] / "2/23+", // SHR r/m16, CL 0x38 => sar[form=word3, flags, modrm16, reglo=c] / "2/23+" }, // SAR r/m16, CL 0xE3 => jcxz[reg=ip, reg=c, rel8] / "18/6", // JCXZ rel8 diff --git a/src/emu/operands.rs b/src/emu/operands.rs index 62be6f7..4cc9138 100644 --- a/src/emu/operands.rs +++ b/src/emu/operands.rs @@ -8,20 +8,19 @@ use emu::pc::Bus; pub trait Operand: Copy + 'static + std::convert::Into + - nt::Num + - nt::Bounded + + 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::WrappingSub + - std::ops::BitAnd + - std::ops::BitXor + std::ops::Shl + + std::ops::Shr { type Signed: nt::ops::checked::CheckedShr; const WIDTH: OperandWidth; const HI_BIT_MASK: Self; + const BITS: Self; fn hi_bit(self) -> bool; fn as_signed(self) -> Self::Signed; @@ -37,6 +36,7 @@ impl Operand for u8 { type Signed = i8; const WIDTH: OperandWidth = OperandWidth::Byte; const HI_BIT_MASK: u8 = 0x80; + const BITS: u8 = 8; fn hi_bit(self) -> bool { self >> 7 == 1 @@ -55,6 +55,7 @@ impl Operand for u16 { type Signed = i16; const WIDTH: OperandWidth = OperandWidth::Word; const HI_BIT_MASK: u16 = 0x8000; + const BITS: u16 = 16; fn hi_bit(self) -> bool { self >> 15 == 1 diff --git a/src/emu/operations.rs b/src/emu/operations.rs index b6498c8..ea2ab29 100644 --- a/src/emu/operations.rs +++ b/src/emu/operations.rs @@ -327,6 +327,40 @@ pub fn push_modrm<'a>(ss: u16, sp: Reg, src: DynLValue<'a>, bus: &mut Bus) { } } +pub fn rol(flags: &mut Flags, + mut dst: LVal, + src: RVal) +where T: Operand + From, + U: Operand + AsPrimitive, + LVal: LValue, + RVal: RValue +{ + let dst_before = dst.read(); + let src_before = src.read(); // may alias dst + if src_before == U::zero() { return } // 286 and beyond probably masks shamt before this check? + let res = dst_before.rotate_left(src_before.as_()); + dst.write(res); + flags.cf = T::zero() != dst_before & (T::HI_BIT_MASK >> (>::from(src_before - U::one()) % T::BITS)); + flags.update_of(T::zero() != T::HI_BIT_MASK & (dst_before ^ res)); +} + +pub fn ror(flags: &mut Flags, + mut dst: LVal, + src: RVal) +where T: Operand + From, + U: Operand + Into + AsPrimitive, + LVal: LValue, + RVal: RValue +{ + let dst_before = dst.read(); + let src_before = src.read(); // may alias dst + if src_before == U::zero() { return } // 286 and beyond probably masks shamt before this check? + let res = dst_before.rotate_right(src_before.as_()); + dst.write(res); + flags.cf = T::zero() != dst_before & (T::one() << (>::from(src_before - U::one()) % T::BITS)); + flags.update_of(T::zero() != T::HI_BIT_MASK & (dst_before ^ res)); +} + pub fn sar(flags: &mut Flags, mut dst: LVal, src: RVal) where T: Operand, U: Operand + AsPrimitive, @@ -386,7 +420,7 @@ where T: Operand, RVal: RValue { let dst_before = dst.read(); - let src_before = src.read(); // may alias dst + let src_before = src.read(); // may alias dst let res = match dst_before.checked_shl(src_before.as_()) { Some(shifted) => shifted, None => T::zero() @@ -409,7 +443,7 @@ where T: Operand, RVal: RValue { let dst_before = dst.read(); - let src_before = src.read(); // may alias dst + let src_before = src.read(); // may alias dst let res = match dst_before.checked_shr(src_before.as_()) { Some(shifted) => shifted, None => T::zero()