emu: Make flags lazy, implement parity flag & JPE/JPO ops
This commit is contained in:
138
src/emu/flags.rs
138
src/emu/flags.rs
@@ -1,34 +1,118 @@
|
||||
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
|
||||
const ZF_BIT: u8 = 6; // Zero Flag
|
||||
const SF_BIT: u8 = 7; // Sign Flag
|
||||
const TF_BIT: u8 = 8; // Trap Flag
|
||||
const IF_BIT: u8 = 9; // Interrupt Enable
|
||||
const DF_BIT: u8 = 10; // Direction Flag
|
||||
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)
|
||||
// 1: Reserved
|
||||
pub pf: bool, // 2: Parity Flag: 1=PE(Even), 0=PO(Odd)
|
||||
// 2: LAZY Parity Flag: 1=PE(Even), 0=PO(Odd)
|
||||
// 3: Reserved
|
||||
pub af: bool, // 4: Adjust Flag: 1=AC(Aux Carry), 0=NA(No Aux Carry)
|
||||
// 4: LAZY Adjust Flag: 1=AC(Aux Carry), 0=NA(No Aux Carry)
|
||||
// 5: Reserved
|
||||
pub zf: bool, // 6: Zero Flag: 1=ZR(Zero), 0=NZ(Not Zero)
|
||||
pub sf: bool, // 7: Sign Flag: 1=NG(Negative), 0=PL(Positive)
|
||||
// 6: LAZY Zero Flag: 1=ZR(Zero), 0=NZ(Not Zero)
|
||||
// 7: LAZY Sign Flag: 1=NG(Negative), 0=PL(Positive)
|
||||
pub tf: bool, // 8: Trap Flag
|
||||
pub ie: bool, // 9: (Real name "IF") Interrupt Enable: 1=EI(Enable Interrupt), 0=DI(Disable Interrupt)
|
||||
pub df: bool, // 10: Direction Flag: 1=DN(Down), 0=UP(Up)
|
||||
pub of: bool, // 11: Overflow Flag: 1=OV(Overflow), 0=NV(Not Overflow)
|
||||
// 11: LAZY Overflow Flag: 1=OV(Overflow), 0=NV(Not Overflow)
|
||||
// bits 12-15 always 1
|
||||
|
||||
// ALU state for lazy flag evaluation
|
||||
flag_op: FlagOp,
|
||||
dst: u16,
|
||||
src: u16,
|
||||
res: u16,
|
||||
sign_bit_mask: u16,
|
||||
}
|
||||
|
||||
impl Flags {
|
||||
pub fn pf(&self) -> bool {
|
||||
match self.flag_op {
|
||||
FlagOp::Eager => { self.res & 1 << PF_BIT != 0 },
|
||||
_ => { self.res.count_ones() & 1 == 0 },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn af(&self) -> bool {
|
||||
match self.flag_op {
|
||||
FlagOp::Eager => { self.res & 1 << AF_BIT != 0 },
|
||||
_ => { false /* XXX: unimplemented! */ },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zf(&self) -> bool {
|
||||
match self.flag_op {
|
||||
FlagOp::Eager => { self.res & 1 << ZF_BIT != 0 },
|
||||
_ => { self.res == 0 },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sf(&self) -> bool {
|
||||
match self.flag_op {
|
||||
FlagOp::Eager => { self.res & 1 << SF_BIT != 0 },
|
||||
_ => { self.res & self.sign_bit_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::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 */ },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, op: FlagOp, dst: u16, src: u16, res: u16, op_width: OperandWidth) {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum FlagOp {
|
||||
Eager, // precomputed into result, for e.g. POPF? (Anything else?)
|
||||
DEC,
|
||||
INC,
|
||||
SUB,
|
||||
}
|
||||
|
||||
impl Default for FlagOp {
|
||||
fn default() -> Self { FlagOp::Eager }
|
||||
}
|
||||
|
||||
impl From<u16> for Flags {
|
||||
fn from(flags: u16) -> Self {
|
||||
Self {
|
||||
cf: flags & 1 != 0,
|
||||
pf: flags & 1 << 2 != 0,
|
||||
af: flags & 1 << 4 != 0,
|
||||
zf: flags & 1 << 6 != 0,
|
||||
sf: flags & 1 << 7 != 0,
|
||||
tf: flags & 1 << 8 != 0,
|
||||
ie: flags & 1 << 9 != 0,
|
||||
df: flags & 1 << 10 != 0,
|
||||
of: flags & 1 << 11 != 0,
|
||||
cf: flags & 1 << CF_BIT != 0,
|
||||
tf: flags & 1 << TF_BIT != 0,
|
||||
ie: flags & 1 << IF_BIT != 0,
|
||||
df: flags & 1 << DF_BIT != 0,
|
||||
|
||||
flag_op: FlagOp::Eager,
|
||||
dst: 0,
|
||||
src: 0,
|
||||
res: flags,
|
||||
sign_bit_mask: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,14 +121,14 @@ 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.pf as u16) << 2
|
||||
| (flags.af as u16) << 4
|
||||
| (flags.zf as u16) << 6
|
||||
| (flags.sf as u16) << 7
|
||||
| (flags.tf as u16) << 8
|
||||
| (flags.ie as u16) << 9
|
||||
| (flags.df as u16) << 10
|
||||
| (flags.of as u16) << 11
|
||||
| (flags.pf() as u16) << PF_BIT
|
||||
| (flags.af() as u16) << AF_BIT
|
||||
| (flags.zf() as u16) << ZF_BIT
|
||||
| (flags.sf() as u16) << SF_BIT
|
||||
| (flags.tf as u16) << TF_BIT
|
||||
| (flags.ie as u16) << IF_BIT
|
||||
| (flags.df as u16) << DF_BIT
|
||||
| (flags.of() as u16) << OF_BIT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,14 +137,14 @@ impl Debug for Flags {
|
||||
use std::fmt::Write;
|
||||
fmt.write_str("[ ")?;
|
||||
for flag in [ (self.cf, "CF "),
|
||||
(self.pf, "PF "),
|
||||
(self.af, "AF "),
|
||||
(self.zf, "ZF "),
|
||||
(self.sf, "SF "),
|
||||
(self.pf(), "PF "),
|
||||
(self.af(), "AF "),
|
||||
(self.zf(), "ZF "),
|
||||
(self.sf(), "SF "),
|
||||
(self.tf, "TF "),
|
||||
(self.ie, "IF "),
|
||||
(self.df, "DF "),
|
||||
(self.of, "OF ") ].iter() {
|
||||
(self.of(), "OF ") ].iter() {
|
||||
if flag.0 { fmt.write_str(flag.1)? };
|
||||
}
|
||||
fmt.write_char(']')?;
|
||||
|
||||
Reference in New Issue
Block a user