207 lines
6.3 KiB
Rust
207 lines
6.3 KiB
Rust
use std::fmt::{Debug, Formatter};
|
|
|
|
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 {
|
|
// 0: Carry Flag: 1=CY(Carry), 0=NC(No Carry)
|
|
// 1: Reserved
|
|
// 2: LAZY Parity Flag: 1=PE(Even), 0=PO(Odd)
|
|
// 3: Reserved
|
|
// 4: LAZY Adjust Flag: 1=AC(Aux Carry), 0=NA(No Aux Carry)
|
|
// 5: Reserved
|
|
// 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)
|
|
// 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,
|
|
res: u16,
|
|
sign_mask: u16,
|
|
}
|
|
|
|
impl Flags {
|
|
pub fn cf(&self) -> bool {
|
|
match self.flag_op {
|
|
FlagOp::Eager { cf, .. } => cf,
|
|
FlagOp::DEC { cf } => cf,
|
|
FlagOp::INC { cf } => cf,
|
|
FlagOp::POPF => { self.res & 1 << CF_BIT != 0 },
|
|
FlagOp::ROL { dst, src, rot_mask, .. } => {
|
|
dst & (self.sign_mask >> ((src.wrapping_sub(1)) & rot_mask as u16)) != 0
|
|
},
|
|
FlagOp::ROR { dst, src, rot_mask, .. } => {
|
|
dst & (1 << ((src.wrapping_sub(1)) & rot_mask 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 { pf, .. } => pf,
|
|
FlagOp::POPF => { self.res & 1 << PF_BIT != 0 },
|
|
FlagOp::ROL { pf, .. }
|
|
| FlagOp::ROR { pf, .. } => pf,
|
|
_ => { self.res.count_ones() & 1 == 0 },
|
|
}
|
|
}
|
|
|
|
pub fn af(&self) -> bool {
|
|
match self.flag_op {
|
|
FlagOp::Eager { af, .. } => af,
|
|
FlagOp::POPF => { self.res & 1 << AF_BIT != 0 },
|
|
FlagOp::ROL { af, .. }
|
|
| FlagOp::ROR { af, .. } => af,
|
|
_ => { false /* XXX: unimplemented! */ },
|
|
}
|
|
}
|
|
|
|
pub fn zf(&self) -> bool {
|
|
match self.flag_op {
|
|
FlagOp::Eager { zf, .. } => zf,
|
|
FlagOp::POPF => { self.res & 1 << ZF_BIT != 0 },
|
|
FlagOp::ROL { zf, .. }
|
|
| FlagOp::ROR { zf, .. } => zf,
|
|
_ => { self.res == 0 },
|
|
}
|
|
}
|
|
|
|
pub fn sf(&self) -> bool {
|
|
match self.flag_op {
|
|
FlagOp::Eager { sf, .. } => sf,
|
|
FlagOp::POPF => { self.res & 1 << SF_BIT != 0 },
|
|
FlagOp::ROL { sf, .. }
|
|
| FlagOp::ROR { sf, .. } => sf,
|
|
_ => { self.res & self.sign_mask != 0 },
|
|
}
|
|
}
|
|
|
|
pub fn of(&self) -> bool {
|
|
match self.flag_op {
|
|
FlagOp::Eager { of, .. } => of,
|
|
FlagOp::POPF => { self.res & 1 << OF_BIT != 0 },
|
|
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 */
|
|
}
|
|
}
|
|
|
|
pub fn update(&mut self, op: FlagOp, res: u16, sign_mask: u16) {
|
|
self.flag_op = op;
|
|
self.res = res;
|
|
self.sign_mask = sign_mask;
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy)]
|
|
pub enum FlagOp {
|
|
Eager { cf: bool, pf: bool, af: bool, zf: bool, sf: bool, of: bool }, // all flags precomputed
|
|
DEC { cf: bool },
|
|
INC { cf: bool },
|
|
POPF, // flags encoded in result
|
|
ROL { dst: u16, src: u16, rot_mask: u16, cf: bool, pf: bool, af: bool, zf: bool, sf: bool },
|
|
ROR { dst: u16, src: u16, rot_mask: u16, 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 {
|
|
fn default() -> Self {
|
|
FlagOp::Eager { cf: false,
|
|
pf: false,
|
|
af: false,
|
|
zf: false,
|
|
sf: false,
|
|
of: false }
|
|
}
|
|
}
|
|
|
|
impl From<u16> for Flags {
|
|
fn from(flags: u16) -> Self {
|
|
Self {
|
|
tf: flags & 1 << TF_BIT != 0,
|
|
ie: flags & 1 << IF_BIT != 0,
|
|
df: flags & 1 << DF_BIT != 0,
|
|
|
|
flag_op: FlagOp::POPF,
|
|
res: flags,
|
|
sign_mask: 0,
|
|
}
|
|
}
|
|
}
|
|
|
|
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) << 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
|
|
}
|
|
}
|
|
|
|
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 "),
|
|
(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() {
|
|
if flag.0 { fmt.write_str(flag.1)? };
|
|
}
|
|
fmt.write_char(']')?;
|
|
Ok(())
|
|
}
|
|
}
|