diff --git a/src/emu/flags.rs b/src/emu/flags.rs index 225d6af..463be84 100644 --- a/src/emu/flags.rs +++ b/src/emu/flags.rs @@ -12,7 +12,7 @@ const OF_BIT: u8 = 11; // Overflow Flag #[derive(Clone, Copy, Default)] pub struct Flags { - pub cf: bool, // 0: Carry Flag: 1=CY(Carry), 0=NC(No Carry) + // 0: Carry Flag: 1=CY(Carry), 0=NC(No Carry) // 1: Reserved // 2: LAZY Parity Flag: 1=PE(Even), 0=PO(Odd) // 3: Reserved @@ -33,9 +33,40 @@ pub struct Flags { } impl Flags { + pub fn cf(&self) -> bool { + match self.flag_op { + FlagOp::Eager => { self.res & 1 << CF_BIT != 0 }, + FlagOp::DEC { cf } => { cf }, + FlagOp::INC { cf } => { cf }, + FlagOp::ROL { dst, src, bits, .. } => { dst & (self.sign_mask >> ((src - 1) % bits as u16)) != 0 }, + FlagOp::ROR { dst, src, bits, .. } => { dst & (1 << ((src - 1) % bits as u16)) != 0 }, + FlagOp::SAR { dst, src, sign_bit } => { + match 1u16.checked_shl(src as u32 - 1) { + Some(carrymask) => dst & carrymask != 0, + None => sign_bit + } + }, + FlagOp::SHL { dst, src } => { + match self.sign_mask.checked_shr(src as u32 - 1) { + Some(carrymask) => dst & carrymask != 0, + None => false + } + }, + FlagOp::SHR { dst, src } => { + match 1u16.checked_shl(src as u32 - 1) { + Some(carrymask) => dst & carrymask != 0, + None => false + } + }, + FlagOp::SUB { cf, .. } => { cf }, + } + } + pub fn pf(&self) -> bool { match self.flag_op { FlagOp::Eager => { self.res & 1 << PF_BIT != 0 }, + FlagOp::ROL { pf, .. } + | FlagOp::ROR { pf, .. } => { pf }, _ => { self.res.count_ones() & 1 == 0 }, } } @@ -43,6 +74,8 @@ impl Flags { pub fn af(&self) -> bool { match self.flag_op { FlagOp::Eager => { self.res & 1 << AF_BIT != 0 }, + FlagOp::ROL { af, .. } + | FlagOp::ROR { af, .. } => { af }, _ => { false /* XXX: unimplemented! */ }, } } @@ -50,6 +83,8 @@ impl Flags { pub fn zf(&self) -> bool { match self.flag_op { FlagOp::Eager => { self.res & 1 << ZF_BIT != 0 }, + FlagOp::ROL { zf, .. } + | FlagOp::ROR { zf, .. } => { zf }, _ => { self.res == 0 }, } } @@ -57,6 +92,8 @@ impl Flags { pub fn sf(&self) -> bool { match self.flag_op { FlagOp::Eager => { self.res & 1 << SF_BIT != 0 }, + FlagOp::ROL { sf, .. } + | FlagOp::ROR { sf, .. } => { sf }, _ => { self.res & self.sign_mask != 0 }, } } @@ -64,12 +101,16 @@ impl Flags { pub fn of(&self) -> bool { match self.flag_op { FlagOp::Eager => { self.res & 1 << OF_BIT != 0 }, - FlagOp::DEC => { self.res == self.sign_mask - 1 }, - FlagOp::INC => { self.res == self.sign_mask }, - FlagOp::SHIFT { 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 ^ self.res) }, /* ...and result sign-bit changed */ + FlagOp::DEC { .. } => { self.res == self.sign_mask - 1 }, + FlagOp::INC { .. } => { self.res == self.sign_mask }, + FlagOp::ROL { dst, .. } + | FlagOp::ROR { dst, .. } => { self.sign_mask & (dst ^ self.res) != 0 }, + FlagOp::SAR { dst, .. } + | 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 ^ self.res) }, /* ...and result sign-bit changed */ } } @@ -78,26 +119,19 @@ impl Flags { self.res = res; self.sign_mask = sign_mask; } - - // 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 POPF or anything that changes only some flags - DEC, - INC, - SHIFT { dst: u16 }, - SUB { dst: u16, src: u16 }, + Eager, // precomputed into result, for e.g. POPF + DEC { cf: bool }, + INC { cf: bool }, + ROL { dst: u16, src: u16, bits: u8, cf: bool, pf: bool, af: bool, zf: bool, sf: bool }, + ROR { dst: u16, src: u16, bits: u8, cf: bool, pf: bool, af: bool, zf: bool, sf: bool }, + SAR { dst: u16, src: u16, sign_bit: bool }, + SHL { dst: u16, src: u16 }, + SHR { dst: u16, src: u16 }, + SUB { dst: u16, src: u16, cf: bool }, } impl Default for FlagOp { @@ -107,7 +141,6 @@ impl Default for FlagOp { impl From for Flags { fn from(flags: u16) -> Self { Self { - cf: flags & 1 << CF_BIT != 0, tf: flags & 1 << TF_BIT != 0, ie: flags & 1 << IF_BIT != 0, df: flags & 1 << DF_BIT != 0, @@ -122,7 +155,7 @@ impl From for Flags { impl From for u16 { fn from(flags: Flags) -> Self { 0b1111_0000_0010_1010 // Not sure what all reserved bits should be, but it shouldn't matter - | (flags.cf as u16) + | (flags.cf() as u16) | (flags.pf() as u16) << PF_BIT | (flags.af() as u16) << AF_BIT | (flags.zf() as u16) << ZF_BIT @@ -138,7 +171,7 @@ impl Debug for Flags { fn fmt(&self, fmt: &mut Formatter) -> Result<(), std::fmt::Error> { use std::fmt::Write; fmt.write_str("[ ")?; - for flag in [ (self.cf, "CF "), + for flag in [ (self.cf(), "CF "), (self.pf(), "PF "), (self.af(), "AF "), (self.zf(), "ZF "), diff --git a/src/emu/operands.rs b/src/emu/operands.rs index df2d7cf..bdde70f 100644 --- a/src/emu/operands.rs +++ b/src/emu/operands.rs @@ -19,7 +19,7 @@ pub trait Operand: Copy + 'static + { type Signed: nt::ops::checked::CheckedShr; const HI_BIT_MASK: Self; - const BITS: Self; + const BITS: u8; fn hi_bit(self) -> bool; fn as_signed(self) -> Self::Signed; @@ -47,7 +47,7 @@ impl Operand for u8 { impl Operand for u16 { type Signed = i16; const HI_BIT_MASK: u16 = 0x8000; - const BITS: u16 = 16; + const BITS: u8 = 16; fn hi_bit(self) -> bool { self >> 15 == 1 diff --git a/src/emu/operations.rs b/src/emu/operations.rs index a926ed3..9a92438 100644 --- a/src/emu/operations.rs +++ b/src/emu/operations.rs @@ -75,8 +75,9 @@ pub fn call(mut ip: Reg, bus: &mut Bus, ss: u16, sp: Reg, rel16: u16) { pub fn cmp(flags: &mut Flags, dst: impl RValue, src: impl RValue) { let (dst, src) = (dst.read(), src.read()); let (res, carry) = dst.overflowing_sub(&src); - flags.cf = carry; - flags.update(FlagOp::SUB { dst: dst.into(), src: src.into() }, res.into(), T::HI_BIT_MASK.into()); + flags.update(FlagOp::SUB { dst: dst.into(), src: src.into(), cf: carry }, + res.into(), + T::HI_BIT_MASK.into()); } pub fn cmps(flags: &mut Flags, @@ -102,14 +103,16 @@ pub fn dec>(flags: &mut Flags, mut dst: LVal) { let dst_before = dst.read(); let res = dst_before.wrapping_sub(&T::one()); dst.write(res); - flags.update(FlagOp::DEC, res.into(), T::HI_BIT_MASK.into()); + let cf = flags.cf(); // we'll store current CF so we don't clobber it + flags.update(FlagOp::DEC { cf }, res.into(), T::HI_BIT_MASK.into()); } pub fn inc>(flags: &mut Flags, mut dst: LVal) { let dst_before = dst.read(); let res = dst_before.wrapping_add(&T::one()); dst.write(res); - flags.update(FlagOp::INC, res.into(), T::HI_BIT_MASK.into()); + let cf = flags.cf(); // we'll store current CF so we don't clobber it + flags.update(FlagOp::INC { cf }, res.into(), T::HI_BIT_MASK.into()); } pub fn int(cpu: &mut i8088, bus: &mut Bus, num: u8) { @@ -120,25 +123,25 @@ pub fn int(cpu: &mut i8088, bus: &mut Bus, num: u8) { } pub fn ja(flags: &Flags, mut ip: Reg, rel8: u16) { - if !flags.cf && !flags.zf() { + if !flags.cf() && !flags.zf() { ip.write(ip.read().wrapping_add(rel8)); } } pub fn jae(flags: &Flags, mut ip: Reg, rel8: u16) { - if !flags.cf { + if !flags.cf() { ip.write(ip.read().wrapping_add(rel8)); } } pub fn jb(flags: &Flags, mut ip: Reg, rel8: u16) { - if flags.cf { + if flags.cf() { ip.write(ip.read().wrapping_add(rel8)); } } pub fn jbe(flags: &Flags, mut ip: Reg, rel8: u16) { - if flags.cf || flags.zf() { + if flags.cf() || flags.zf() { ip.write(ip.read().wrapping_add(rel8)); } } @@ -330,7 +333,7 @@ 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, +where T: Operand, U: Operand + AsPrimitive, LVal: LValue, RVal: RValue @@ -340,15 +343,23 @@ where T: Operand + From, 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)); + flags.update(FlagOp::ROL { dst: dst_before.into(), + src: src_before.into(), + bits: T::BITS, + cf: flags.cf(), + pf: flags.pf(), + af: flags.af(), + zf: flags.zf(), + sf: flags.sf() }, + res.into(), + T::HI_BIT_MASK.into()); } pub fn ror(flags: &mut Flags, mut dst: LVal, src: RVal) -where T: Operand + From, - U: Operand + Into + AsPrimitive, +where T: Operand, + U: Operand + AsPrimitive, LVal: LValue, RVal: RValue { @@ -357,8 +368,16 @@ where T: Operand + From, 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)); + flags.update(FlagOp::ROR { dst: dst_before.into(), + src: src_before.into(), + bits: T::BITS, + cf: flags.cf(), + pf: flags.pf(), + af: flags.af(), + zf: flags.zf(), + sf: flags.sf() }, + res.into(), + T::HI_BIT_MASK.into()); } pub fn sar(flags: &mut Flags, mut dst: LVal, src: RVal) @@ -385,11 +404,9 @@ where T: Operand, None => if sign_bit { T::max_value() } else { T::zero() } // Out-of-Range yields all sign bits }; dst.write(res); - flags.cf = match T::one().checked_shl(src_before.as_() - 1) { - Some(carrymask) => dst_before & carrymask != T::zero(), - None => sign_bit - }; - flags.update(FlagOp::SHIFT { dst: dst_before.into() }, res.into(), T::HI_BIT_MASK.into()); + flags.update(FlagOp::SAR { dst: dst_before.into(), src: src_before.into(), sign_bit }, + res.into(), + T::HI_BIT_MASK.into()); } pub fn scas(flags: &mut Flags, @@ -426,11 +443,9 @@ where T: Operand, None => T::zero() }; dst.write(res); - flags.cf = match T::HI_BIT_MASK.checked_shr(src_before.as_() - 1) { - Some(carrymask) => dst_before & carrymask != T::zero(), - None => false - }; - flags.update(FlagOp::SHIFT { dst: dst_before.into() }, res.into(), T::HI_BIT_MASK.into()); + flags.update(FlagOp::SHL { dst: dst_before.into(), src: src_before.into() }, + res.into(), + T::HI_BIT_MASK.into()); } // See comments on sar() @@ -449,11 +464,9 @@ where T: Operand, None => T::zero() }; dst.write(res); - flags.cf = match T::one().checked_shl(src_before.as_() - 1) { - Some(carrymask) => dst_before & carrymask != T::zero(), - None => false - }; - flags.update(FlagOp::SHIFT { dst: dst_before.into() }, res.into(), T::HI_BIT_MASK.into()); + flags.update(FlagOp::SHR { dst: dst_before.into(), src: src_before.into() }, + res.into(), + T::HI_BIT_MASK.into()); } pub fn stos(flags: &Flags,