From 20bfc45daee7c94f9df0a59ee8f41efdd0a6a5bf Mon Sep 17 00:00:00 2001 From: Jared Burce Date: Mon, 8 Mar 2021 06:10:39 -0800 Subject: [PATCH] emu: modrm16 arg decoder --- src/emu/i8088.rs | 113 +++++++++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 37 deletions(-) diff --git a/src/emu/i8088.rs b/src/emu/i8088.rs index d2c84d6..d216a65 100644 --- a/src/emu/i8088.rs +++ b/src/emu/i8088.rs @@ -148,58 +148,69 @@ impl<'a> RValue for RegLo<'a> { macro_rules! step { // Base case: all args processed and ready to call op - (@code ( $($args:tt)* ), - $cpu:expr, $bus:expr, $modrm:ident, $name:ident, $cycles:literal, + (@code ( $($done:tt)* ), + $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 - (@code ( $($args:tt)* ), - $cpu:expr, $bus:expr, $modrm:ident, $name:ident, $cycles:literal, + (@code ( $($done:tt)* ), + $cpu:expr, $bus:expr, $modrm:tt, $name:ident, $cycles:literal, ($next:ident $(= $nextrhs:ident)? $($rest:ident $(= $restrhs:ident)?)*)) => { 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) }; // 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) => { - 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 - (@bus $cookie:tt, $cpu:expr, $bus:expr, $modrm:ident) => { { + (@bus $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => { { 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) } }; - (@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); 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]; buf[0] = 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)) } }; - (@mem $cookie:tt, $cpu:expr, $bus:expr, $modrm:ident) => { + (@mem $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => { step!(@arg $cookie, &mut $bus.ram) }; - (@modrm16 $cookie:tt, $cpu:expr, $bus:expr, $modrm:ident) => { { - unimplemented!("step!(@arg $cookie, &mut ...)") - } }; + (@modrm16 $cookie:tt, $cpu:expr, $bus:expr, + ($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 { 0 => &mut $cpu.a, 1 => &mut $cpu.c, @@ -214,7 +225,7 @@ macro_rules! step { 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 { 0 => step!(@arg $cookie, &mut RegHi { reg: &mut $cpu.a } ), 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); }; - (@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 }); }; - (@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); }; - (@rel16 $cookie:tt, $cpu:expr, $bus:expr, $modrm:ident) => { { + (@rel16 $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => { { let mut buf = [0; 2]; buf[0] = 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 $cpu:expr, $bus:expr, $modrm:ident, $code:literal, + (@group $cpu:expr, $bus:expr, ($modrm:ident, $modrm16:tt, $modrm8:tt), $code:literal, { $( $subcode:literal => $name:ident[$($args:ident $(= $argrhs:ident)?),*] / $cycles:literal),*$(,)? } ) => { { let subcode = $modrm & 0x38; 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) } } }; // Entry Point (($cpu:expr, $bus:expr) => - { $( + opcodes: { $( $code:literal // Non-group opcodes @@ -271,7 +286,10 @@ macro_rules! step { // Group opcodes $( : $subcodes:tt )? ),* - $(,)? } ) => { + $(,)? }, + modrm16: $modrm16:tt, + modrm8: $modrm8:tt + ) => { { 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 @@ -279,12 +297,12 @@ macro_rules! step { $( $( $code => { $( let $ext = (); /* No-op just to trigger expansion. */ 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 => { 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 { pub fn run(&mut self, bus: &mut Bus) { loop { - step!((self, bus) => { - 0x8B _ => mov[r16, modrm16] / "2/12+", - 0x8C: { 0x08 => mov[modrm16, reg=cs] / "2/13+", }, - 0x8E: { 0x18 => mov[reg=ds, modrm16] / "2/12+", }, - 0xB4 => mov[reghi=a, d8] / 4, - 0xBA => mov[reg=d, d16] / 4, - 0xC3 => ret[reg=ip, regval=ss, reg=sp, mem] / 20, - 0xCD => int[cpu, bus, d8] / 71, - 0xE8 => call[reg=ip, regval=ss, reg=sp, mem, rel16] / 23, + step!((self, bus) => + opcodes: { + //0x8B _ => mov[r16, modrm16] / "2/12+", + 0x8C: { 0x08 => mov[modrm16, reg=cs] / "2/13+", }, + 0x8E: { 0x18 => mov[reg=ds, modrm16] / "2/12+", }, + 0xB4 => mov[reghi=a, d8] / 4, + 0xBA => mov[reg=d, d16] / 4, + 0xC3 => ret[reg=ip, regval=ss, reg=sp, mem] / 20, + 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, }) } }