emu: ROL/ROR operations

This commit is contained in:
2021-03-29 22:56:16 -07:00
parent f5ab9cfad2
commit d8600151d6
4 changed files with 66 additions and 12 deletions

View File

@@ -87,11 +87,22 @@ impl Flags {
OperandWidth::Word => 0x8000, OperandWidth::Word => 0x8000,
} }
} }
// 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)] #[derive(Clone, Copy)]
pub enum FlagOp { pub enum FlagOp {
Eager, // precomputed into result, for e.g. POPF? (Anything else?) Eager, // precomputed into result, for POPF or anything that changes only some flags
DEC, DEC,
INC, INC,
SHIFT, SHIFT,

View File

@@ -520,16 +520,24 @@ impl i8088 {
0xBF => mov[reg=di, d16] / 4, 0xBF => mov[reg=di, d16] / 4,
0xC3 => pop[bus, regval=ss, reg=sp, reg=ip] / 20, // RET 0xC3 => pop[bus, regval=ss, reg=sp, reg=ip] / 20, // RET
0xCD => int[cpu, bus, d8] / 71, 0xCD => int[cpu, bus, d8] / 71,
0xD0: { 0x20 => shl[form=byte3, flags, modrm8, const=1u8] / "2/23+", // SHL r/m8, 1 0xD0: { 0x00 => rol[form=byte3, flags, modrm8, const=1u8] / "2/23+", // ROL r/m16, 1
0x08 => ror[form=byte3, flags, modrm8, const=1u8] / "2/23+", // ROR r/m16, 1
0x20 => shl[form=byte3, flags, modrm8, const=1u8] / "2/23+", // SHL r/m8, 1
0x28 => shr[form=byte3, flags, modrm8, const=1u8] / "2/23+", // SHR r/m8, 1 0x28 => shr[form=byte3, flags, modrm8, const=1u8] / "2/23+", // SHR r/m8, 1
0x38 => sar[form=byte3, flags, modrm8, const=1u8] / "2/23+" }, // SAR r/m8, 1 0x38 => sar[form=byte3, flags, modrm8, const=1u8] / "2/23+" }, // SAR r/m8, 1
0xD1: { 0x20 => shl[form=word3, flags, modrm16, const=1u16] / "2/23+", // SHL r/m16, 1 0xD1: { 0x00 => rol[form=word3, flags, modrm16, const=1u16] / "2/23+", // ROL r/m16, 1
0x08 => ror[form=word3, flags, modrm16, const=1u16] / "2/23+", // ROR r/m16, 1
0x20 => shl[form=word3, flags, modrm16, const=1u16] / "2/23+", // SHL r/m16, 1
0x28 => shr[form=word3, flags, modrm16, const=1u16] / "2/23+", // SHR r/m16, 1 0x28 => shr[form=word3, flags, modrm16, const=1u16] / "2/23+", // SHR r/m16, 1
0x38 => sar[form=word3, flags, modrm16, const=1u16] / "2/23+" }, // SAR r/m16, 1 0x38 => sar[form=word3, flags, modrm16, const=1u16] / "2/23+" }, // SAR r/m16, 1
0xD2: { 0x20 => shl[form=byte3, flags, modrm8, reglo=c] / "2/23+", // SHL r/m8, CL 0xD2: { 0x00 => rol[form=byte3, flags, modrm8, reglo=c] / "8/28++4n", // ROL r/m8, CL
0x08 => ror[form=byte3, flags, modrm8, reglo=c] / "8/28++4n", // ROR r/m8, CL
0x20 => shl[form=byte3, flags, modrm8, reglo=c] / "2/23+", // SHL r/m8, CL
0x28 => shr[form=byte3, flags, modrm8, reglo=c] / "2/23+", // SHR r/m8, CL 0x28 => shr[form=byte3, flags, modrm8, reglo=c] / "2/23+", // SHR r/m8, CL
0x38 => sar[form=byte3, flags, modrm8, reglo=c] / "2/23+" }, // SAR r/m8, CL 0x38 => sar[form=byte3, flags, modrm8, reglo=c] / "2/23+" }, // SAR r/m8, CL
0xD3: { 0x20 => shl[form=word3, flags, modrm16, reglo=c] / "2/23+", // SHL r/m16, CL 0xD3: { 0x00 => rol[form=word3, flags, modrm16, reglo=c] / "8/28++4n", // ROL r/m16, CL
0x08 => ror[form=word3, flags, modrm16, reglo=c] / "8/28++4n", // ROR r/m16, CL
0x20 => shl[form=word3, flags, modrm16, reglo=c] / "2/23+", // SHL r/m16, CL
0x28 => shr[form=word3, flags, modrm16, reglo=c] / "2/23+", // SHR r/m16, CL 0x28 => shr[form=word3, flags, modrm16, reglo=c] / "2/23+", // SHR r/m16, CL
0x38 => sar[form=word3, flags, modrm16, reglo=c] / "2/23+" }, // SAR r/m16, CL 0x38 => sar[form=word3, flags, modrm16, reglo=c] / "2/23+" }, // SAR r/m16, CL
0xE3 => jcxz[reg=ip, reg=c, rel8] / "18/6", // JCXZ rel8 0xE3 => jcxz[reg=ip, reg=c, rel8] / "18/6", // JCXZ rel8

View File

@@ -8,20 +8,19 @@ use emu::pc::Bus;
pub trait Operand: Copy + 'static + pub trait Operand: Copy + 'static +
std::convert::Into<u16> + std::convert::Into<u16> +
nt::Num + nt::int::PrimInt +
nt::Bounded +
nt::ops::checked::CheckedShl<Output = Self> + nt::ops::checked::CheckedShl<Output = Self> +
nt::ops::checked::CheckedShr<Output = Self> + nt::ops::checked::CheckedShr<Output = Self> +
nt::ops::overflowing::OverflowingAdd +
nt::ops::overflowing::OverflowingSub + nt::ops::overflowing::OverflowingSub +
nt::ops::wrapping::WrappingAdd + nt::ops::wrapping::WrappingAdd +
nt::ops::wrapping::WrappingSub + nt::ops::wrapping::WrappingSub +
std::ops::BitAnd<Output = Self> + std::ops::Shl<Output = Self> +
std::ops::BitXor<Output = Self> std::ops::Shr<Output = Self>
{ {
type Signed: nt::ops::checked::CheckedShr<Output = Self::Signed>; type Signed: nt::ops::checked::CheckedShr<Output = Self::Signed>;
const WIDTH: OperandWidth; const WIDTH: OperandWidth;
const HI_BIT_MASK: Self; const HI_BIT_MASK: Self;
const BITS: Self;
fn hi_bit(self) -> bool; fn hi_bit(self) -> bool;
fn as_signed(self) -> Self::Signed; fn as_signed(self) -> Self::Signed;
@@ -37,6 +36,7 @@ impl Operand for u8 {
type Signed = i8; type Signed = i8;
const WIDTH: OperandWidth = OperandWidth::Byte; const WIDTH: OperandWidth = OperandWidth::Byte;
const HI_BIT_MASK: u8 = 0x80; const HI_BIT_MASK: u8 = 0x80;
const BITS: u8 = 8;
fn hi_bit(self) -> bool { fn hi_bit(self) -> bool {
self >> 7 == 1 self >> 7 == 1
@@ -55,6 +55,7 @@ impl Operand for u16 {
type Signed = i16; type Signed = i16;
const WIDTH: OperandWidth = OperandWidth::Word; const WIDTH: OperandWidth = OperandWidth::Word;
const HI_BIT_MASK: u16 = 0x8000; const HI_BIT_MASK: u16 = 0x8000;
const BITS: u16 = 16;
fn hi_bit(self) -> bool { fn hi_bit(self) -> bool {
self >> 15 == 1 self >> 15 == 1

View File

@@ -327,6 +327,40 @@ pub fn push_modrm<'a>(ss: u16, sp: Reg, src: DynLValue<'a>, bus: &mut Bus) {
} }
} }
pub fn rol<T, U, LVal, RVal>(flags: &mut Flags,
mut dst: LVal,
src: RVal)
where T: Operand + From<U>,
U: Operand + AsPrimitive<u32>,
LVal: LValue<T>,
RVal: RValue<U>
{
let dst_before = dst.read();
let src_before = src.read(); // may alias dst
if src_before == U::zero() { return } // 286 and beyond probably masks shamt before this check?
let res = dst_before.rotate_left(src_before.as_());
dst.write(res);
flags.cf = T::zero() != dst_before & (T::HI_BIT_MASK >> (<T as From<U>>::from(src_before - U::one()) % T::BITS));
flags.update_of(T::zero() != T::HI_BIT_MASK & (dst_before ^ res));
}
pub fn ror<T, U, LVal, RVal>(flags: &mut Flags,
mut dst: LVal,
src: RVal)
where T: Operand + From<U>,
U: Operand + Into<T> + AsPrimitive<u32>,
LVal: LValue<T>,
RVal: RValue<U>
{
let dst_before = dst.read();
let src_before = src.read(); // may alias dst
if src_before == U::zero() { return } // 286 and beyond probably masks shamt before this check?
let res = dst_before.rotate_right(src_before.as_());
dst.write(res);
flags.cf = T::zero() != dst_before & (T::one() << (<T as From<U>>::from(src_before - U::one()) % T::BITS));
flags.update_of(T::zero() != T::HI_BIT_MASK & (dst_before ^ res));
}
pub fn sar<T, U, LVal, RVal>(flags: &mut Flags, mut dst: LVal, src: RVal) pub fn sar<T, U, LVal, RVal>(flags: &mut Flags, mut dst: LVal, src: RVal)
where T: Operand, where T: Operand,
U: Operand + AsPrimitive<u32>, U: Operand + AsPrimitive<u32>,