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:
@@ -1,6 +1,5 @@
|
|||||||
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};
|
||||||
|
|
||||||
@@ -63,34 +62,45 @@ pub enum RepPrefix {
|
|||||||
|
|
||||||
macro_rules! step {
|
macro_rules! step {
|
||||||
// Base case: all args processed and ready to call op
|
// 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,
|
$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
|
// 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,
|
$cpu:expr, $bus:expr, $prefix:tt, $modrm:tt, $name:ident, $cycles:literal,
|
||||||
($next:ident $(= $nextrhs:tt)? $($rest:ident $(= $restrhs:tt)?)*)) => {
|
($next:ident $(= $nextrhs:tt)? $($rest:ident $(= $restrhs:tt)?)*)) => {
|
||||||
step!(@$next$(= $nextrhs)?
|
step!(@$next$(= $nextrhs)?
|
||||||
// "cookie" tt to be passed thru to @arg so we have all the args for the recursive step
|
// "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)
|
$cpu, $bus, $prefix, $modrm)
|
||||||
};
|
};
|
||||||
|
|
||||||
// accept an argument from a decoder and recur to look for next arg
|
// accept an argument from a decoder and recur to look for next arg
|
||||||
(@arg ( ($($done:tt)*), $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt,
|
(@arg ( $(form=$form:tt,)? ($($done:tt)*),
|
||||||
$name:ident, $cycles:literal, $rest:tt )
|
$cpu:expr, $bus:expr, $prefix:tt, $modrm:tt, $name:ident, $cycles:literal,
|
||||||
|
$rest:tt )
|
||||||
$(, $arg:expr)?) => {
|
$(, $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
|
// 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)* ) ),
|
(@push ( $(form=$form:tt,)? ($($done:tt)*),
|
||||||
( $($args:tt)* )) => {
|
$cpu:expr, $bus:expr, $prefix:tt, $modrm:tt, $name:ident, $cycles:literal, ( $($rest:tt)* ) ),
|
||||||
step!(@code $done, $cpu, $bus, $prefix, $modrm, $name, $cycles, ( $($args)* $($rest)* ))
|
( $($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
|
// Argument Decoders
|
||||||
|
|
||||||
(@addr $cookie:tt, $cpu:expr, $bus:expr,
|
(@addr $cookie:tt, $cpu:expr, $bus:expr,
|
||||||
@@ -192,6 +202,14 @@ macro_rules! step {
|
|||||||
step!(@arg $cookie, &mut $cpu.flags)
|
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) => {
|
(@mem $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => {
|
||||||
step!(@arg $cookie, &mut $bus.ram)
|
step!(@arg $cookie, &mut $bus.ram)
|
||||||
};
|
};
|
||||||
@@ -327,14 +345,6 @@ 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),
|
||||||
@@ -416,22 +426,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,
|
0x40 => inc[flags, reg=a] / 3,
|
||||||
0x41 => inc[width=word, flags, reg=c] / 3,
|
0x41 => inc[flags, reg=c] / 3,
|
||||||
0x42 => inc[width=word, flags, reg=d] / 3,
|
0x42 => inc[flags, reg=d] / 3,
|
||||||
0x43 => inc[width=word, flags, reg=b] / 3,
|
0x43 => inc[flags, reg=b] / 3,
|
||||||
0x44 => inc[width=word, flags, reg=sp] / 3,
|
0x44 => inc[flags, reg=sp] / 3,
|
||||||
0x45 => inc[width=word, flags, reg=bp] / 3,
|
0x45 => inc[flags, reg=bp] / 3,
|
||||||
0x46 => inc[width=word, flags, reg=si] / 3,
|
0x46 => inc[flags, reg=si] / 3,
|
||||||
0x47 => inc[width=word, flags, reg=di] / 3,
|
0x47 => inc[flags, reg=di] / 3,
|
||||||
0x48 => dec[width=word, flags, reg=a] / 3,
|
0x48 => dec[flags, reg=a] / 3,
|
||||||
0x49 => dec[width=word, flags, reg=c] / 3,
|
0x49 => dec[flags, reg=c] / 3,
|
||||||
0x4A => dec[width=word, flags, reg=d] / 3,
|
0x4A => dec[flags, reg=d] / 3,
|
||||||
0x4B => dec[width=word, flags, reg=b] / 3,
|
0x4B => dec[flags, reg=b] / 3,
|
||||||
0x4C => dec[width=word, flags, reg=sp] / 3,
|
0x4C => dec[flags, reg=sp] / 3,
|
||||||
0x4D => dec[width=word, flags, reg=bp] / 3,
|
0x4D => dec[flags, reg=bp] / 3,
|
||||||
0x4E => dec[width=word, flags, reg=si] / 3,
|
0x4E => dec[flags, reg=si] / 3,
|
||||||
0x4F => dec[width=word, flags, reg=di] / 3,
|
0x4F => dec[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,
|
||||||
@@ -524,10 +534,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
|
0xFE: { 00 => inc[form=unary_byte, flags, modrm8] / "3/23+", // INC r/m8
|
||||||
08 => dec[width=byte, flags, modrm8] / "3/23+", }, // DEC r/m8
|
08 => dec[form=unary_byte, flags, modrm8] / "3/23+", }, // DEC r/m8
|
||||||
0xFF: { 00 => inc[width=word, flags, modrm16] / "3/23+", // INC r/m16
|
0xFF: { 00 => inc[form=unary_word, flags, modrm16] / "3/23+", // INC r/m16
|
||||||
08 => dec[width=word, flags, modrm16] / "3/23+", // DEC 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+" },
|
30 => push_modrm[unsafe_bus_maybe, regval=ss, reg=sp, modrm16] / "15/24+" },
|
||||||
},
|
},
|
||||||
modrm: {
|
modrm: {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use std::convert::Into;
|
use std::convert::Into;
|
||||||
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};
|
||||||
@@ -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
|
pub fn dec<T: Operand, LVal: LValue<T>>(flags: &mut Flags, mut dst: LVal) {
|
||||||
flags: &mut Flags,
|
|
||||||
mut dst: impl LValue<T>) {
|
|
||||||
let res = update_flags!(flags, T, dst.read().overflowing_sub(&T::one()), sf, zf, af, pf);
|
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();
|
flags.of = res == T::HI_BIT_MASK - T::one();
|
||||||
dst.write(res);
|
dst.write(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inc<T: Operand>(_width: PhantomData<T>, // Needed to disambiguate when dst is a FarPtr
|
pub fn inc<T: Operand, LVal: LValue<T>>(flags: &mut Flags, mut dst: LVal) {
|
||||||
flags: &mut Flags,
|
|
||||||
mut dst: impl LValue<T>) {
|
|
||||||
let res = update_flags!(flags, T, dst.read().overflowing_add(&T::one()), sf, zf, af, pf);
|
let res = update_flags!(flags, T, dst.read().overflowing_add(&T::one()), sf, zf, af, pf);
|
||||||
flags.of = res == T::HI_BIT_MASK;
|
flags.of = res == T::HI_BIT_MASK;
|
||||||
dst.write(res);
|
dst.write(res);
|
||||||
|
|||||||
Reference in New Issue
Block a user