emu: Make FlagOp enum algebraic to carry op-specific data

Avoids writing operand data for lazy flags that won't be read
This commit is contained in:
2021-03-30 00:09:22 -07:00
parent d8600151d6
commit 984ff891c0
3 changed files with 19 additions and 38 deletions

View File

@@ -1,7 +1,5 @@
use std::fmt::{Debug, Formatter};
use emu::operands::OperandWidth;
const CF_BIT: u8 = 0; // Carry Flag
const PF_BIT: u8 = 2; // Parity Flag
const AF_BIT: u8 = 4; // Adjust Flag
@@ -30,10 +28,8 @@ pub struct Flags {
// ALU state for lazy flag evaluation
flag_op: FlagOp,
dst: u16,
src: u16,
res: u16,
sign_bit_mask: u16,
sign_mask: u16,
}
impl Flags {
@@ -61,31 +57,26 @@ impl Flags {
pub fn sf(&self) -> bool {
match self.flag_op {
FlagOp::Eager => { self.res & 1 << SF_BIT != 0 },
_ => { self.res & self.sign_bit_mask != 0 },
_ => { self.res & self.sign_mask != 0 },
}
}
pub fn of(&self) -> bool {
match self.flag_op {
FlagOp::Eager => { self.res & 1 << OF_BIT != 0 },
FlagOp::DEC => { self.res == self.sign_bit_mask - 1 },
FlagOp::INC => { self.res == self.sign_bit_mask },
FlagOp::SHIFT => { 0 != self.sign_bit_mask & (self.dst ^ self.res) },
FlagOp::SUB => { 0 != self.sign_bit_mask & // In the (maybe) sign bit...
(self.src ^ self.dst) & // ...operands have different signs...
(self.dst ^ self.res) /* ...and result sign-bit changed */ },
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 */
}
}
pub fn update(&mut self, op: FlagOp, dst: u16, src: u16, res: u16, op_width: OperandWidth) {
pub fn update(&mut self, op: FlagOp, res: u16, sign_mask: u16) {
self.flag_op = op;
self.dst = dst;
self.src = src;
self.res = res;
self.sign_bit_mask = match op_width {
OperandWidth::Byte => 0x80,
OperandWidth::Word => 0x8000,
}
self.sign_mask = sign_mask;
}
// The rotate ops update OF don't touch PF/AF/ZF/SF so we make
@@ -105,8 +96,8 @@ pub enum FlagOp {
Eager, // precomputed into result, for POPF or anything that changes only some flags
DEC,
INC,
SHIFT,
SUB,
SHIFT { dst: u16 },
SUB { dst: u16, src: u16 },
}
impl Default for FlagOp {
@@ -122,10 +113,8 @@ impl From<u16> for Flags {
df: flags & 1 << DF_BIT != 0,
flag_op: FlagOp::Eager,
dst: 0,
src: 0,
res: flags,
sign_bit_mask: 0,
sign_mask: 0,
}
}
}