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::cell::Cell;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use super::byteorder::{ByteOrder, LittleEndian};
|
use super::byteorder::{ByteOrder, LittleEndian};
|
||||||
|
|
||||||
@@ -297,6 +298,14 @@ macro_rules! step {
|
|||||||
step!(@arg $cookie, $segment.unwrap())
|
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 Decoder
|
||||||
(@group $cpu:expr, $bus:expr, $prefix:tt,
|
(@group $cpu:expr, $bus:expr, $prefix:tt,
|
||||||
($modrm_val:ident, $modrm:tt, $modrm16:tt, $modrm8:tt),
|
($modrm_val:ident, $modrm:tt, $modrm16:tt, $modrm8:tt),
|
||||||
@@ -378,6 +387,22 @@ impl i8088 {
|
|||||||
0x3C => cmp[flags, reglo=a, d8] / "3/24+",
|
0x3C => cmp[flags, reglo=a, d8] / "3/24+",
|
||||||
0x3D => cmp[flags, reg=a, d16] / "3/24+",
|
0x3D => cmp[flags, reg=a, d16] / "3/24+",
|
||||||
0x3E => nop[seg=ds, prefix] / 2,
|
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,
|
0x50 => push[bus, regval=ss, reg=sp, regval=a] / 15,
|
||||||
0x51 => push[bus, regval=ss, reg=sp, regval=c] / 15,
|
0x51 => push[bus, regval=ss, reg=sp, regval=c] / 15,
|
||||||
0x52 => push[bus, regval=ss, reg=sp, regval=d] / 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,
|
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
|
||||||
|
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: {
|
modrm: {
|
||||||
0x00 => seg=ds, displace0=(b+si) / M 7,
|
0x00 => seg=ds, displace0=(b+si) / M 7,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use emu::pc::Bus;
|
|||||||
|
|
||||||
pub trait Operand: Copy +
|
pub trait Operand: Copy +
|
||||||
nt::Num +
|
nt::Num +
|
||||||
|
nt::ops::overflowing::OverflowingAdd +
|
||||||
nt::ops::overflowing::OverflowingSub +
|
nt::ops::overflowing::OverflowingSub +
|
||||||
std::ops::BitAnd<Output = Self> +
|
std::ops::BitAnd<Output = Self> +
|
||||||
std::ops::BitXor<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);
|
fn write(&mut self, val: T);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use emu::dos;
|
use emu::dos;
|
||||||
use emu::i8088::{Flags, RepPrefix, i8088};
|
use emu::i8088::{Flags, RepPrefix, i8088};
|
||||||
@@ -69,8 +70,8 @@ macro_rules! update_flags {
|
|||||||
|
|
||||||
// Entry Point
|
// Entry Point
|
||||||
($flags:expr, $t:ty, $eval:expr $(, $flagnames:ident)* ) => { {
|
($flags:expr, $t:ty, $eval:expr $(, $flagnames:ident)* ) => { {
|
||||||
let (dst, carry) = $eval;
|
let (dst, _carry) = $eval; // _carry used iff CF flag being updated
|
||||||
update_flags!(@recur $flags, $t, dst, carry $(, $flagnames)*);
|
update_flags!(@recur $flags, $t, dst, _carry $(, $flagnames)*);
|
||||||
dst
|
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) {
|
pub fn int(cpu: &mut i8088, bus: &mut Bus, num: &u8) {
|
||||||
match num {
|
match num {
|
||||||
0x21 => dos::interrupt(cpu, bus),
|
0x21 => dos::interrupt(cpu, bus),
|
||||||
|
|||||||
Reference in New Issue
Block a user