emu: Use type arguments instead of PhantomData to disambiguate

Allows elision of op directive when operands are of unambiguous width
This commit is contained in:
2021-03-24 20:34:08 -07:00
parent 88166c5a85
commit 8c359d2c70
2 changed files with 51 additions and 46 deletions

View File

@@ -1,6 +1,5 @@
use std::cell::Cell;
use std::fmt::{Debug, Formatter};
use std::marker::PhantomData;
use super::byteorder::{ByteOrder, LittleEndian};
@@ -63,34 +62,45 @@ pub enum RepPrefix {
macro_rules! step {
// Base case: all args processed and ready to call op
(@code ( $($done:tt)* ),
(@code $(form=($($tyargs:tt),*),)? ( $($done:tt)* ),
$cpu:expr, $bus:expr, $prefix:tt, $modrm:tt, $name:ident, $cycles:literal,
()) => {
ops::$name($($done),*);
ops::$name$(::<$($tyargs),*>)?($($done),*);
};
// Inductive case: decode next arg to be placed in list
(@code ( $($done:tt)* ),
(@code $(form=$form:tt,)? ( $($done:tt)* ),
$cpu:expr, $bus:expr, $prefix:tt, $modrm:tt, $name:ident, $cycles:literal,
($next:ident $(= $nextrhs:tt)? $($rest:ident $(= $restrhs:tt)?)*)) => {
step!(@$next$(= $nextrhs)?
// "cookie" tt to be passed thru to @arg so we have all the args for the recursive step
( ($($done)*), $cpu, $bus, $prefix, $modrm, $name, $cycles, ($($rest $(= $restrhs)?)*) ),
( $(form=$form,)? ($($done)*), $cpu, $bus, $prefix, $modrm, $name, $cycles, ($($rest $(= $restrhs)?)*) ),
$cpu, $bus, $prefix, $modrm)
};
// accept an argument from a decoder and recur to look for next arg
(@arg ( ($($done:tt)*), $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt,
$name:ident, $cycles:literal, $rest:tt )
(@arg ( $(form=$form:tt,)? ($($done:tt)*),
$cpu:expr, $bus:expr, $prefix:tt, $modrm:tt, $name:ident, $cycles:literal,
$rest:tt )
$(, $arg:expr)?) => {
step!(@code ($($done)* $($arg)?), $cpu, $bus, $prefix, $modrm, $name, $cycles, $rest)
step!(@code $(form=$form,)? ($($done)* $($arg)?), $cpu, $bus, $prefix, $modrm, $name, $cycles, $rest)
};
// decoder deferring to sub-decoders, push them onto the decoder stack to process next
(@push ( $done:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt, $name:ident, $cycles:literal, ( $($rest:tt)* ) ),
( $($args:tt)* )) => {
step!(@code $done, $cpu, $bus, $prefix, $modrm, $name, $cycles, ( $($args)* $($rest)* ))
(@push ( $(form=$form:tt,)? ($($done:tt)*),
$cpu:expr, $bus:expr, $prefix:tt, $modrm:tt, $name:ident, $cycles:literal, ( $($rest:tt)* ) ),
( $($args:tt)* )) => {
step!(@code $(form=$form,)? ($($done)*), $cpu, $bus, $prefix, $modrm, $name, $cycles, ( $($args)* $($rest)* ))
};
// Set the type arguments for operations that cannot infer width
(@form ( $done:tt,
$cpu:expr, $bus:expr, $prefix:tt, $modrm:tt, $name:ident, $cycles:literal,
$rest:tt ),
form=$form:tt) => {
step!(@code form=$form, $done, $cpu, $bus, $prefix, $modrm, $name, $cycles, $rest)
};
// Argument Decoders
(@addr $cookie:tt, $cpu:expr, $bus:expr,
@@ -192,6 +202,14 @@ macro_rules! step {
step!(@arg $cookie, &mut $cpu.flags)
};
(@form=unary_byte $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => {
step!(@form $cookie, form=(u8, _));
};
(@form=unary_word $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => {
step!(@form $cookie, form=(u16, _));
};
(@mem $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => {
step!(@arg $cookie, &mut $bus.ram)
};
@@ -327,14 +345,6 @@ 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),
@@ -416,22 +426,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,
0x40 => inc[flags, reg=a] / 3,
0x41 => inc[flags, reg=c] / 3,
0x42 => inc[flags, reg=d] / 3,
0x43 => inc[flags, reg=b] / 3,
0x44 => inc[flags, reg=sp] / 3,
0x45 => inc[flags, reg=bp] / 3,
0x46 => inc[flags, reg=si] / 3,
0x47 => inc[flags, reg=di] / 3,
0x48 => dec[flags, reg=a] / 3,
0x49 => dec[flags, reg=c] / 3,
0x4A => dec[flags, reg=d] / 3,
0x4B => dec[flags, reg=b] / 3,
0x4C => dec[flags, reg=sp] / 3,
0x4D => dec[flags, reg=bp] / 3,
0x4E => dec[flags, reg=si] / 3,
0x4F => dec[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,
@@ -524,10 +534,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
0xFE: { 00 => inc[form=unary_byte, flags, modrm8] / "3/23+", // INC r/m8
08 => dec[form=unary_byte, flags, modrm8] / "3/23+", }, // DEC r/m8
0xFF: { 00 => inc[form=unary_word, flags, modrm16] / "3/23+", // INC r/m16
08 => dec[form=unary_word, flags, modrm16] / "3/23+", // DEC r/m16
30 => push_modrm[unsafe_bus_maybe, regval=ss, reg=sp, modrm16] / "15/24+" },
},
modrm: {

View File

@@ -1,6 +1,5 @@
use std::convert::Into;
use std::fmt::Debug;
use std::marker::PhantomData;
use emu::dos;
use emu::i8088::{Flags, RepPrefix, i8088};
@@ -137,17 +136,13 @@ 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,
mut dst: impl LValue<T>) {
pub fn dec<T: Operand, LVal: LValue<T>>(flags: &mut Flags, mut dst: LVal) {
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,
mut dst: impl LValue<T>) {
pub fn inc<T: Operand, LVal: LValue<T>>(flags: &mut Flags, mut dst: LVal) {
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);