emu: flags: make CF & OF always lazy. Remove Flags::update_of()

Rotate ops now backup flags manually into their enum data instead of
converting everything to eager mode
This commit is contained in:
2021-03-30 01:53:27 -07:00
parent 984ff891c0
commit a789b7e87d
3 changed files with 104 additions and 58 deletions

View File

@@ -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<u16> 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<u16> for Flags {
impl From<Flags> 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 "),