emu: CMC/CLC/STC/CLD/STC instructions. POPF flags differ from Eager
This commit is contained in:
@@ -35,9 +35,10 @@ pub struct Flags {
|
|||||||
impl Flags {
|
impl Flags {
|
||||||
pub fn cf(&self) -> bool {
|
pub fn cf(&self) -> bool {
|
||||||
match self.flag_op {
|
match self.flag_op {
|
||||||
FlagOp::Eager => { self.res & 1 << CF_BIT != 0 },
|
FlagOp::Eager { cf, .. } => cf,
|
||||||
FlagOp::DEC { cf } => { cf },
|
FlagOp::DEC { cf } => cf,
|
||||||
FlagOp::INC { cf } => { cf },
|
FlagOp::INC { cf } => cf,
|
||||||
|
FlagOp::POPF => { self.res & 1 << CF_BIT != 0 },
|
||||||
FlagOp::ROL { dst, src, rot_mask, .. } => {
|
FlagOp::ROL { dst, src, rot_mask, .. } => {
|
||||||
dst & (self.sign_mask >> ((src.wrapping_sub(1)) & rot_mask as u16)) != 0
|
dst & (self.sign_mask >> ((src.wrapping_sub(1)) & rot_mask as u16)) != 0
|
||||||
},
|
},
|
||||||
@@ -62,49 +63,54 @@ impl Flags {
|
|||||||
None => false
|
None => false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
FlagOp::SUB { cf, .. } => { cf },
|
FlagOp::SUB { cf, .. } => cf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pf(&self) -> bool {
|
pub fn pf(&self) -> bool {
|
||||||
match self.flag_op {
|
match self.flag_op {
|
||||||
FlagOp::Eager => { self.res & 1 << PF_BIT != 0 },
|
FlagOp::Eager { pf, .. } => pf,
|
||||||
|
FlagOp::POPF => { self.res & 1 << PF_BIT != 0 },
|
||||||
FlagOp::ROL { pf, .. }
|
FlagOp::ROL { pf, .. }
|
||||||
| FlagOp::ROR { pf, .. } => { pf },
|
| FlagOp::ROR { pf, .. } => pf,
|
||||||
_ => { self.res.count_ones() & 1 == 0 },
|
_ => { self.res.count_ones() & 1 == 0 },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn af(&self) -> bool {
|
pub fn af(&self) -> bool {
|
||||||
match self.flag_op {
|
match self.flag_op {
|
||||||
FlagOp::Eager => { self.res & 1 << AF_BIT != 0 },
|
FlagOp::Eager { af, .. } => af,
|
||||||
|
FlagOp::POPF => { self.res & 1 << AF_BIT != 0 },
|
||||||
FlagOp::ROL { af, .. }
|
FlagOp::ROL { af, .. }
|
||||||
| FlagOp::ROR { af, .. } => { af },
|
| FlagOp::ROR { af, .. } => af,
|
||||||
_ => { false /* XXX: unimplemented! */ },
|
_ => { false /* XXX: unimplemented! */ },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn zf(&self) -> bool {
|
pub fn zf(&self) -> bool {
|
||||||
match self.flag_op {
|
match self.flag_op {
|
||||||
FlagOp::Eager => { self.res & 1 << ZF_BIT != 0 },
|
FlagOp::Eager { zf, .. } => zf,
|
||||||
|
FlagOp::POPF => { self.res & 1 << ZF_BIT != 0 },
|
||||||
FlagOp::ROL { zf, .. }
|
FlagOp::ROL { zf, .. }
|
||||||
| FlagOp::ROR { zf, .. } => { zf },
|
| FlagOp::ROR { zf, .. } => zf,
|
||||||
_ => { self.res == 0 },
|
_ => { self.res == 0 },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sf(&self) -> bool {
|
pub fn sf(&self) -> bool {
|
||||||
match self.flag_op {
|
match self.flag_op {
|
||||||
FlagOp::Eager => { self.res & 1 << SF_BIT != 0 },
|
FlagOp::Eager { sf, .. } => sf,
|
||||||
|
FlagOp::POPF => { self.res & 1 << SF_BIT != 0 },
|
||||||
FlagOp::ROL { sf, .. }
|
FlagOp::ROL { sf, .. }
|
||||||
| FlagOp::ROR { sf, .. } => { sf },
|
| FlagOp::ROR { sf, .. } => sf,
|
||||||
_ => { self.res & self.sign_mask != 0 },
|
_ => { self.res & self.sign_mask != 0 },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn of(&self) -> bool {
|
pub fn of(&self) -> bool {
|
||||||
match self.flag_op {
|
match self.flag_op {
|
||||||
FlagOp::Eager => { self.res & 1 << OF_BIT != 0 },
|
FlagOp::Eager { of, .. } => of,
|
||||||
|
FlagOp::POPF => { self.res & 1 << OF_BIT != 0 },
|
||||||
FlagOp::DEC { .. } => { self.res == self.sign_mask - 1 },
|
FlagOp::DEC { .. } => { self.res == self.sign_mask - 1 },
|
||||||
FlagOp::INC { .. } => { self.res == self.sign_mask },
|
FlagOp::INC { .. } => { self.res == self.sign_mask },
|
||||||
FlagOp::ROL { dst, .. }
|
FlagOp::ROL { dst, .. }
|
||||||
@@ -127,9 +133,10 @@ impl Flags {
|
|||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum FlagOp {
|
pub enum FlagOp {
|
||||||
Eager, // precomputed into result, for e.g. POPF
|
Eager { cf: bool, pf: bool, af: bool, zf: bool, sf: bool, of: bool }, // all flags precomputed
|
||||||
DEC { cf: bool },
|
DEC { cf: bool },
|
||||||
INC { 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 },
|
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 },
|
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 },
|
SAR { dst: u16, src: u16, sign_bit: bool },
|
||||||
@@ -139,7 +146,14 @@ pub enum FlagOp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FlagOp {
|
impl Default for FlagOp {
|
||||||
fn default() -> Self { FlagOp::Eager }
|
fn default() -> Self {
|
||||||
|
FlagOp::Eager { cf: false,
|
||||||
|
pf: false,
|
||||||
|
af: false,
|
||||||
|
zf: false,
|
||||||
|
sf: false,
|
||||||
|
of: false }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u16> for Flags {
|
impl From<u16> for Flags {
|
||||||
@@ -149,7 +163,7 @@ impl From<u16> for Flags {
|
|||||||
ie: flags & 1 << IF_BIT != 0,
|
ie: flags & 1 << IF_BIT != 0,
|
||||||
df: flags & 1 << DF_BIT != 0,
|
df: flags & 1 << DF_BIT != 0,
|
||||||
|
|
||||||
flag_op: FlagOp::Eager,
|
flag_op: FlagOp::POPF,
|
||||||
res: flags,
|
res: flags,
|
||||||
sign_mask: 0,
|
sign_mask: 0,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -548,6 +548,11 @@ impl i8088 {
|
|||||||
0xE8 => call[reg=ip, bus, regval=ss, reg=sp, rel16] / 23,
|
0xE8 => call[reg=ip, bus, regval=ss, reg=sp, rel16] / 23,
|
||||||
0xF2 => nop[rep=NotEqual, prefix] / 0, // REPNE/REPNZ
|
0xF2 => nop[rep=NotEqual, prefix] / 0, // REPNE/REPNZ
|
||||||
0xF3 => nop[rep=Equal, prefix] / 0, // REP/REPE/REPZ
|
0xF3 => nop[rep=Equal, prefix] / 0, // REP/REPE/REPZ
|
||||||
|
0xF5 => cmc[flags] / 2, // CMC (Complement Carry Flag)
|
||||||
|
0xF8 => clc[flags] / 2, // CLC (Clear Carry Flag)
|
||||||
|
0xF9 => stc[flags] / 2, // STC (Set Carry Flag)
|
||||||
|
0xFC => cld[flags] / 2, // CLD (Clear Direction Flag)
|
||||||
|
0xFD => std[flags] / 2, // STD (Set Direction Flag)
|
||||||
0xFE: { 0x00 => inc[form=byte1, flags, modrm8] / "3/23+", // INC r/m8
|
0xFE: { 0x00 => inc[form=byte1, flags, modrm8] / "3/23+", // INC r/m8
|
||||||
0x08 => dec[form=byte1, flags, modrm8] / "3/23+", }, // DEC r/m8
|
0x08 => dec[form=byte1, flags, modrm8] / "3/23+", }, // DEC r/m8
|
||||||
0xFF: { 0x00 => inc[form=word1, flags, modrm16] / "3/23+", // INC r/m16
|
0xFF: { 0x00 => inc[form=word1, flags, modrm16] / "3/23+", // INC r/m16
|
||||||
|
|||||||
@@ -72,6 +72,30 @@ pub fn call(mut ip: Reg, bus: &mut Bus, ss: u16, sp: Reg, rel16: u16) {
|
|||||||
ip.write(target);
|
ip.write(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clc(flags: &mut Flags) {
|
||||||
|
flags.update(FlagOp::Eager { cf: false,
|
||||||
|
pf: flags.pf(),
|
||||||
|
af: flags.af(),
|
||||||
|
zf: flags.zf(),
|
||||||
|
sf: flags.sf(),
|
||||||
|
of: flags.of() },
|
||||||
|
0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cld(flags: &mut Flags) {
|
||||||
|
flags.df = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cmc(flags: &mut Flags) {
|
||||||
|
flags.update(FlagOp::Eager { cf: !flags.cf(),
|
||||||
|
pf: flags.pf(),
|
||||||
|
af: flags.af(),
|
||||||
|
zf: flags.zf(),
|
||||||
|
sf: flags.sf(),
|
||||||
|
of: flags.of() },
|
||||||
|
0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn cmp<T: Operand>(flags: &mut Flags, dst: impl RValue<T>, src: impl RValue<T>) {
|
pub fn cmp<T: Operand>(flags: &mut Flags, dst: impl RValue<T>, src: impl RValue<T>) {
|
||||||
let (dst, src) = (dst.read(), src.read());
|
let (dst, src) = (dst.read(), src.read());
|
||||||
let (res, carry) = dst.overflowing_sub(&src);
|
let (res, carry) = dst.overflowing_sub(&src);
|
||||||
@@ -471,6 +495,20 @@ where T: Operand,
|
|||||||
T::HI_BIT_MASK.into());
|
T::HI_BIT_MASK.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn stc(flags: &mut Flags) {
|
||||||
|
flags.update(FlagOp::Eager { cf: true,
|
||||||
|
pf: flags.pf(),
|
||||||
|
af: flags.af(),
|
||||||
|
zf: flags.zf(),
|
||||||
|
sf: flags.sf(),
|
||||||
|
of: flags.of() },
|
||||||
|
0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn std(flags: &mut Flags) {
|
||||||
|
flags.df = true;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn stos<T, RVal>(flags: &Flags,
|
pub fn stos<T, RVal>(flags: &Flags,
|
||||||
bus: &mut Bus,
|
bus: &mut Bus,
|
||||||
rep: RepPrefix,
|
rep: RepPrefix,
|
||||||
|
|||||||
Reference in New Issue
Block a user