emu: modrm16 arg decoder

This commit is contained in:
2021-03-08 06:10:39 -08:00
parent 3f2c12a83c
commit 20bfc45dae

View File

@@ -148,58 +148,69 @@ impl<'a> RValue<u8> for RegLo<'a> {
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 ( $($args:tt)* ), (@code ( $($done:tt)* ),
$cpu:expr, $bus:expr, $modrm:ident, $name:ident, $cycles:literal, $cpu:expr, $bus:expr, $modrm:tt, $name:ident, $cycles:literal,
()) => { ()) => {
ops::$name($($args),*); ops::$name($($done),*);
}; };
// Inductive case: decode next arg to be placed in list // Inductive case: decode next arg to be placed in list
(@code ( $($args:tt)* ), (@code ( $($done:tt)* ),
$cpu:expr, $bus:expr, $modrm:ident, $name:ident, $cycles:literal, $cpu:expr, $bus:expr, $modrm:tt, $name:ident, $cycles:literal,
($next:ident $(= $nextrhs:ident)? $($rest:ident $(= $restrhs:ident)?)*)) => { ($next:ident $(= $nextrhs:ident)? $($rest:ident $(= $restrhs:ident)?)*)) => {
step!(@$next$(= $nextrhs)? step!(@$next$(= $nextrhs)?
( ($($args)*), $cpu, $bus, $modrm, $name, $cycles, ($($rest $(= $restrhs)?)*) ), // "cookie" tt to be passed thru to @arg so we have all the args for the recursive step
( ($($done)*), $cpu, $bus, $modrm, $name, $cycles, ($($rest $(= $restrhs)?)*) ),
$cpu, $bus, $modrm) $cpu, $bus, $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 ( ($($args:tt)*), $cpu:expr, $bus:expr, $modrm:ident, $name:ident, $cycles:literal, ( $($rest:tt)* ) ), (@arg ( ($($done:tt)*), $cpu:expr, $bus:expr, $modrm:tt, $name:ident, $cycles:literal, $rest:tt ),
$arg:expr) => { $arg:expr) => {
step!(@code ($($args)* $arg), $cpu, $bus, $modrm, $name, $cycles, ( $($rest)* )) step!(@code ($($done)* $arg), $cpu, $bus, $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, $modrm:tt, $name:ident, $cycles:literal, ( $($rest:tt)* ) ),
( $($args:tt)* )) => {
step!(@code $done, $cpu, $bus, $modrm, $name, $cycles, ( $($args)* $($rest)* ))
};
// Argument Decoders // Argument Decoders
(@bus $cookie:tt, $cpu:expr, $bus:expr, $modrm:ident) => { { (@bus $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => { {
step!(@arg $cookie, $bus) step!(@arg $cookie, $bus)
} }; } };
(@cpu $cookie:tt, $cpu:expr, $bus:expr, $modrm:ident) => { { (@cpu $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => { {
step!(@arg $cookie, $cpu) step!(@arg $cookie, $cpu)
} }; } };
(@d8 $cookie:tt, $cpu:expr, $bus:expr, $modrm:ident) => { { (@d8 $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => { {
let d8 = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus); let d8 = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
step!(@arg $cookie, &d8) step!(@arg $cookie, &d8)
} }; } };
(@d16 $cookie:tt, $cpu:expr, $bus:expr, $modrm:ident) => { { (@d16 $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => { {
let mut buf = [0; 2]; let mut buf = [0; 2];
buf[0] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus); buf[0] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
buf[1] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus); buf[1] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
step!(@arg $cookie, &LittleEndian::read_u16(&buf)) step!(@arg $cookie, &LittleEndian::read_u16(&buf))
} }; } };
(@mem $cookie:tt, $cpu:expr, $bus:expr, $modrm:ident) => { (@mem $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => {
step!(@arg $cookie, &mut $bus.ram) step!(@arg $cookie, &mut $bus.ram)
}; };
(@modrm16 $cookie:tt, $cpu:expr, $bus:expr, $modrm:ident) => { { (@modrm16 $cookie:tt, $cpu:expr, $bus:expr,
unimplemented!("step!(@arg $cookie, &mut ...)") ($modrm_val:ident, { $($val:literal => $($args:ident = $argrhs:tt),*),*$(,)? }, $modrm8:tt)) => { {
} }; let modrm_val = $modrm_val & !0x38;
match modrm_val {
$( $val => step!(@push $cookie, ($($args = $argrhs)* ) ) ),*,
_ => unimplemented!("modrm: {:02X}({:02X})\ncpu: {:#X?}", $modrm_val, modrm_val, $cpu)
}
} };
(@r16 $cookie:tt, $cpu:expr, $bus:expr, $modrm:ident) => { { (@r16 $cookie:tt, $cpu:expr, $bus:expr, ($modrm:ident, $modrm16:tt, $modrm8:tt)) => { {
let reg = match $modrm >> 3 & 0x7 { let reg = match $modrm >> 3 & 0x7 {
0 => &mut $cpu.a, 0 => &mut $cpu.a,
1 => &mut $cpu.c, 1 => &mut $cpu.c,
@@ -214,7 +225,7 @@ macro_rules! step {
step!(@arg $cookie, reg) step!(@arg $cookie, reg)
} }; } };
(@r8 $cookie:tt, $cpu:expr, $bus:expr, $modrm:ident) => { (@r8 $cookie:tt, $cpu:expr, $bus:expr, ($modrm:ident, $modrm16:tt, $modrm8:tt)) => {
match $modrm >> 3 & 0x7 { match $modrm >> 3 & 0x7 {
0 => step!(@arg $cookie, &mut RegHi { reg: &mut $cpu.a } ), 0 => step!(@arg $cookie, &mut RegHi { reg: &mut $cpu.a } ),
1 => step!(@arg $cookie, &mut RegHi { reg: &mut $cpu.c } ), 1 => step!(@arg $cookie, &mut RegHi { reg: &mut $cpu.c } ),
@@ -228,19 +239,23 @@ macro_rules! step {
}; };
}; };
(@reg=$reg:ident $cookie:tt, $cpu:expr, $bus:expr, $modrm:ident) => { (@reg=$reg:ident $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => {
step!(@arg $cookie, &mut $cpu.$reg); step!(@arg $cookie, &mut $cpu.$reg);
}; };
(@reghi=$reg:ident $cookie:tt, $cpu:expr, $bus:expr, $modrm:ident) => { (@reghi=$reg:ident $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => {
step!(@arg $cookie, &mut RegHi { reg: &mut $cpu.$reg }); step!(@arg $cookie, &mut RegHi { reg: &mut $cpu.$reg });
}; };
(@regval=$reg:ident $cookie:tt, $cpu:expr, $bus:expr, $modrm:ident) => { (@reglo=$reg:ident $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => {
step!(@arg $cookie, &mut RegLo { reg: &mut $cpu.$reg });
};
(@regval=$reg:ident $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => {
step!(@arg $cookie, $cpu.$reg); step!(@arg $cookie, $cpu.$reg);
}; };
(@rel16 $cookie:tt, $cpu:expr, $bus:expr, $modrm:ident) => { { (@rel16 $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => { {
let mut buf = [0; 2]; let mut buf = [0; 2];
buf[0] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus); buf[0] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
buf[1] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus); buf[1] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
@@ -248,19 +263,19 @@ macro_rules! step {
} }; } };
// Group Decoder // Group Decoder
(@group $cpu:expr, $bus:expr, $modrm:ident, $code:literal, (@group $cpu:expr, $bus:expr, ($modrm:ident, $modrm16:tt, $modrm8:tt), $code:literal,
{ $( $subcode:literal => { $( $subcode:literal =>
$name:ident[$($args:ident $(= $argrhs:ident)?),*] / $cycles:literal),*$(,)? } ) => { { $name:ident[$($args:ident $(= $argrhs:ident)?),*] / $cycles:literal),*$(,)? } ) => { {
let subcode = $modrm & 0x38; let subcode = $modrm & 0x38;
match subcode { match subcode {
$( $subcode => step!(@code (), $cpu, $bus, $modrm, $name, $cycles, ($($args $(= $argrhs)?)*)) ),*, $( $subcode => step!(@code (), $cpu, $bus, ($modrm, $modrm16, $modrm8), $name, $cycles, ($($args $(= $argrhs)?)*)) ),*,
_ => unimplemented!("opcode: {:02X} {:02X}({:02X})\ncpu: {:#X?}", $code, $modrm, subcode, $cpu) _ => unimplemented!("opcode: {:02X} {:02X}({:02X})\ncpu: {:#X?}", $code, $modrm, subcode, $cpu)
} } } }
}; };
// Entry Point // Entry Point
(($cpu:expr, $bus:expr) => (($cpu:expr, $bus:expr) =>
{ $( opcodes: { $(
$code:literal $code:literal
// Non-group opcodes // Non-group opcodes
@@ -271,7 +286,10 @@ macro_rules! step {
// Group opcodes // Group opcodes
$( : $subcodes:tt )? $( : $subcodes:tt )?
),* ),*
$(,)? } ) => { $(,)? },
modrm16: $modrm16:tt,
modrm8: $modrm8:tt
) => {
{ {
let opcode = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus); let opcode = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
let modrm: u8; // Type ascription unnecessary but gives better err messages when missing $ext let modrm: u8; // Type ascription unnecessary but gives better err messages when missing $ext
@@ -279,12 +297,12 @@ macro_rules! step {
$( $( $code => { $( $( $code => {
$( let $ext = (); /* No-op just to trigger expansion. */ $( let $ext = (); /* No-op just to trigger expansion. */
modrm = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus); )? modrm = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus); )?
step!(@code (), $cpu, $bus, modrm, $name, $cycles, ($($args $(= $argrhs)?)*)) step!(@code (), $cpu, $bus, (modrm, $modrm16, $modrm8), $name, $cycles, ($($args $(= $argrhs)?)*))
} }
)? )?
$( $code => { $( $code => {
modrm = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus); modrm = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
step!(@group $cpu, $bus, modrm, $code, $subcodes) step!(@group $cpu, $bus, (modrm, $modrm16, $modrm8), $code, $subcodes)
} }
)? )?
),*, ),*,
@@ -328,15 +346,36 @@ pub fn write_lo(reg: &mut u16, val: u8) {
impl i8088 { impl i8088 {
pub fn run(&mut self, bus: &mut Bus) { pub fn run(&mut self, bus: &mut Bus) {
loop { loop {
step!((self, bus) => { step!((self, bus) =>
0x8B _ => mov[r16, modrm16] / "2/12+", opcodes: {
0x8C: { 0x08 => mov[modrm16, reg=cs] / "2/13+", }, //0x8B _ => mov[r16, modrm16] / "2/12+",
0x8E: { 0x18 => mov[reg=ds, modrm16] / "2/12+", }, 0x8C: { 0x08 => mov[modrm16, reg=cs] / "2/13+", },
0xB4 => mov[reghi=a, d8] / 4, 0x8E: { 0x18 => mov[reg=ds, modrm16] / "2/12+", },
0xBA => mov[reg=d, d16] / 4, 0xB4 => mov[reghi=a, d8] / 4,
0xC3 => ret[reg=ip, regval=ss, reg=sp, mem] / 20, 0xBA => mov[reg=d, d16] / 4,
0xCD => int[cpu, bus, d8] / 71, 0xC3 => ret[reg=ip, regval=ss, reg=sp, mem] / 20,
0xE8 => call[reg=ip, regval=ss, reg=sp, mem, rel16] / 23, 0xCD => int[cpu, bus, d8] / 71,
0xE8 => call[reg=ip, regval=ss, reg=sp, mem, rel16] / 23,
},
modrm16: {
0xC0 => reg=a,
0xC1 => reg=c,
0xC2 => reg=d,
0xC3 => reg=b,
0xC4 => reg=sp,
0xC5 => reg=bp,
0xC6 => reg=si,
0xC7 => reg=di,
},
modrm8: {
0xC0 => reglo=a,
0xC1 => reglo=c,
0xC2 => reglo=d,
0xC3 => reglo=b,
0xC4 => reghi=a,
0xC5 => reghi=c,
0xC6 => reghi=d,
0xC7 => reghi=b,
}) })
} }
} }