emu: INC/DEC opcodes. width={byte,word} argtypes for disambig
Also made all LValues also RValues for brevity (so INC/DEC don't have to bound their destination arguments by both, but this is not required if it causes problems for some reason down the road).
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
use std::cell::Cell;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use super::byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
@@ -297,6 +298,14 @@ macro_rules! step {
|
||||
step!(@arg $cookie, $segment.unwrap())
|
||||
} };
|
||||
|
||||
(@width=byte $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => {
|
||||
step!(@arg $cookie, PhantomData::<u8>);
|
||||
};
|
||||
|
||||
(@width=word $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => {
|
||||
step!(@arg $cookie, PhantomData::<u16>);
|
||||
};
|
||||
|
||||
// Group Decoder
|
||||
(@group $cpu:expr, $bus:expr, $prefix:tt,
|
||||
($modrm_val:ident, $modrm:tt, $modrm16:tt, $modrm8:tt),
|
||||
@@ -378,6 +387,22 @@ impl i8088 {
|
||||
0x3C => cmp[flags, reglo=a, d8] / "3/24+",
|
||||
0x3D => cmp[flags, reg=a, d16] / "3/24+",
|
||||
0x3E => nop[seg=ds, prefix] / 2,
|
||||
0x40 => inc[width=word, flags, reg=a] / 3,
|
||||
0x41 => inc[width=word, flags, reg=c] / 3,
|
||||
0x42 => inc[width=word, flags, reg=d] / 3,
|
||||
0x43 => inc[width=word, flags, reg=b] / 3,
|
||||
0x44 => inc[width=word, flags, reg=sp] / 3,
|
||||
0x45 => inc[width=word, flags, reg=bp] / 3,
|
||||
0x46 => inc[width=word, flags, reg=si] / 3,
|
||||
0x47 => inc[width=word, flags, reg=di] / 3,
|
||||
0x48 => dec[width=word, flags, reg=a] / 3,
|
||||
0x49 => dec[width=word, flags, reg=c] / 3,
|
||||
0x4A => dec[width=word, flags, reg=d] / 3,
|
||||
0x4B => dec[width=word, flags, reg=b] / 3,
|
||||
0x4C => dec[width=word, flags, reg=sp] / 3,
|
||||
0x4D => dec[width=word, flags, reg=bp] / 3,
|
||||
0x4E => dec[width=word, flags, reg=si] / 3,
|
||||
0x4F => dec[width=word, flags, reg=di] / 3,
|
||||
0x50 => push[bus, regval=ss, reg=sp, regval=a] / 15,
|
||||
0x51 => push[bus, regval=ss, reg=sp, regval=c] / 15,
|
||||
0x52 => push[bus, regval=ss, reg=sp, regval=d] / 15,
|
||||
@@ -469,6 +494,10 @@ impl i8088 {
|
||||
0xE8 => call[reg=ip, bus, regval=ss, reg=sp, rel16] / 23,
|
||||
0xF2 => nop[rep=NotEqual, prefix] / 0, // REPNE/REPNZ
|
||||
0xF3 => nop[rep=Equal, prefix] / 0, // REP/REPE/REPZ
|
||||
0xFE: { 00 => inc[width=byte, flags, modrm8] / "3/23+", // INC r/m8
|
||||
08 => dec[width=byte, flags, modrm8] / "3/23+", }, // DEC r/m8
|
||||
0xFF: { 00 => inc[width=word, flags, modrm16] / "3/23+", // INC r/m16
|
||||
08 => dec[width=word, flags, modrm16] / "3/23+", }, // DEC r/m16
|
||||
},
|
||||
modrm: {
|
||||
0x00 => seg=ds, displace0=(b+si) / M 7,
|
||||
|
||||
@@ -7,6 +7,7 @@ use emu::pc::Bus;
|
||||
|
||||
pub trait Operand: Copy +
|
||||
nt::Num +
|
||||
nt::ops::overflowing::OverflowingAdd +
|
||||
nt::ops::overflowing::OverflowingSub +
|
||||
std::ops::BitAnd<Output = Self> +
|
||||
std::ops::BitXor<Output = Self> {
|
||||
@@ -28,7 +29,7 @@ impl Operand for u16 {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait LValue<T> {
|
||||
pub trait LValue<T>: RValue<T> {
|
||||
fn write(&mut self, val: T);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::fmt::Debug;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use emu::dos;
|
||||
use emu::i8088::{Flags, RepPrefix, i8088};
|
||||
@@ -69,8 +70,8 @@ macro_rules! update_flags {
|
||||
|
||||
// Entry Point
|
||||
($flags:expr, $t:ty, $eval:expr $(, $flagnames:ident)* ) => { {
|
||||
let (dst, carry) = $eval;
|
||||
update_flags!(@recur $flags, $t, dst, carry $(, $flagnames)*);
|
||||
let (dst, _carry) = $eval; // _carry used iff CF flag being updated
|
||||
update_flags!(@recur $flags, $t, dst, _carry $(, $flagnames)*);
|
||||
dst
|
||||
} }
|
||||
}
|
||||
@@ -135,6 +136,22 @@ pub fn cmpsw(flags: &mut Flags,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn dec<T: Operand>(_width: PhantomData<T>, // Needed to disambiguate when dst is a FarPtr
|
||||
flags: &mut Flags,
|
||||
dst: &mut impl LValue<T>) {
|
||||
let res = update_flags!(flags, T, dst.read().overflowing_sub(&T::one()), sf, zf, af, pf);
|
||||
flags.of = res == T::HI_BIT_MASK - T::one();
|
||||
dst.write(res);
|
||||
}
|
||||
|
||||
pub fn inc<T: Operand>(_width: PhantomData<T>, // Needed to disambiguate when dst is a FarPtr
|
||||
flags: &mut Flags,
|
||||
dst: &mut impl LValue<T>) {
|
||||
let res = update_flags!(flags, T, dst.read().overflowing_add(&T::one()), sf, zf, af, pf);
|
||||
flags.of = res == T::HI_BIT_MASK;
|
||||
dst.write(res);
|
||||
}
|
||||
|
||||
pub fn int(cpu: &mut i8088, bus: &mut Bus, num: &u8) {
|
||||
match num {
|
||||
0x21 => dos::interrupt(cpu, bus),
|
||||
|
||||
Reference in New Issue
Block a user