From 7b00a8e708ffd64ed7f57bfcacae661d3382e3d3 Mon Sep 17 00:00:00 2001 From: Jared Burce Date: Tue, 13 Apr 2021 14:39:10 -0700 Subject: [PATCH] emu: don't macro recur on every @r8/r16 value Avoids O(M*N) codegen blowup when paired with a modrm arg. Probably want to do the same thing to the modrm op directives but those cases are little more tricky and this alone gets rid of much of the pain. --- src/emu/i8088.rs | 70 +++++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/src/emu/i8088.rs b/src/emu/i8088.rs index 071069b..5ffeffb 100644 --- a/src/emu/i8088.rs +++ b/src/emu/i8088.rs @@ -179,27 +179,27 @@ macro_rules! step { }; (@form=byte0 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => { - step!(@form $cookie, form=(u8)); + step!(@form $cookie, form=(u8)) }; (@form=byte1 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => { - step!(@form $cookie, form=(u8, _)); + step!(@form $cookie, form=(u8, _)) }; (@form=byte3 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => { - step!(@form $cookie, form=(u8, _, _, _)); + step!(@form $cookie, form=(u8, _, _, _)) }; (@form=word0 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => { - step!(@form $cookie, form=(u16)); + step!(@form $cookie, form=(u16)) }; (@form=word1 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => { - step!(@form $cookie, form=(u16, _)); + step!(@form $cookie, form=(u16, _)) }; (@form=word3 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => { - step!(@form $cookie, form=(u16, _, _, _)); + step!(@form $cookie, form=(u16, _, _, _)) }; (@mem $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => { @@ -253,35 +253,45 @@ macro_rules! step { continue $prefix_loop; }; - (@r16 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, ($modrm_val:ident, $modrm:tt, $modrm16:tt, $modrm8:tt)) => { + (@r16 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, ($modrm_val:ident, $($modrm_rest:tt),*)) => { { // TODO: Should these also be passed into the macro like the modrm specs? - match $modrm_val >> 3 & 0x7 { - 0 => step!(@arg $cookie, Reg { reg: &$cpu.a } ), - 1 => step!(@arg $cookie, Reg { reg: &$cpu.c } ), - 2 => step!(@arg $cookie, Reg { reg: &$cpu.d } ), - 3 => step!(@arg $cookie, Reg { reg: &$cpu.b } ), - 4 => step!(@arg $cookie, Reg { reg: &$cpu.sp } ), - 5 => step!(@arg $cookie, Reg { reg: &$cpu.bp } ), - 6 => step!(@arg $cookie, Reg { reg: &$cpu.si } ), - 7 => step!(@arg $cookie, Reg { reg: &$cpu.di } ), + let reg = match $modrm_val >> 3 & 0x7 { + 0 => Reg { reg: &$cpu.a }, + 1 => Reg { reg: &$cpu.c }, + 2 => Reg { reg: &$cpu.d }, + 3 => Reg { reg: &$cpu.b }, + 4 => Reg { reg: &$cpu.sp }, + 5 => Reg { reg: &$cpu.bp }, + 6 => Reg { reg: &$cpu.si }, + 7 => Reg { reg: &$cpu.di }, _ => unreachable!() }; - }; + step!(@arg $cookie, reg) + } }; - (@r8 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, ($modrm_val:ident, $modrm:tt, $modrm16:tt, $modrm8:tt)) => { + (@r8 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, ($modrm_val:ident, $($modrm_rest:tt),*)) => { { + let modrm_shift = $modrm_val >> 3; // TODO: Should these also be passed into the macro like the modrm specs? - match $modrm_val >> 3 & 0x7 { - 0 => step!(@arg $cookie, RegLo { reg: &$cpu.a } ), - 1 => step!(@arg $cookie, RegLo { reg: &$cpu.c } ), - 2 => step!(@arg $cookie, RegLo { reg: &$cpu.d } ), - 3 => step!(@arg $cookie, RegLo { reg: &$cpu.b } ), - 4 => step!(@arg $cookie, RegHi { reg: &$cpu.a } ), - 5 => step!(@arg $cookie, RegHi { reg: &$cpu.c } ), - 6 => step!(@arg $cookie, RegHi { reg: &$cpu.d } ), - 7 => step!(@arg $cookie, RegHi { reg: &$cpu.b } ), - _ => unreachable!() - }; - }; + if modrm_shift & 0x4 == 0 { + let reg = match modrm_shift & 0x3 { + 0 => RegLo { reg: &$cpu.a }, + 1 => RegLo { reg: &$cpu.c }, + 2 => RegLo { reg: &$cpu.d }, + 3 => RegLo { reg: &$cpu.b }, + _ => unreachable!() + }; + step!(@arg $cookie, reg) + } else { + let reg = match modrm_shift & 0x3 { + 0 => RegHi { reg: &$cpu.a }, + 1 => RegHi { reg: &$cpu.c }, + 2 => RegHi { reg: &$cpu.d }, + 3 => RegHi { reg: &$cpu.b }, + _ => unreachable!() + }; + step!(@arg $cookie, reg) + } + } }; (@reg=$reg:ident $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => { step!(@arg $cookie, Reg { reg: &$cpu.$reg });