emu: don't branch from each modrm calculation

modrm calculation still done inline on each opcode, but later op
directives don't branch from each modrm outcome anymore. Speeds
compilation by about 30%, and decreases release binary size by about
300K currently (and presumably more when the rest of the opcodes are done)
This commit is contained in:
2021-04-20 01:24:31 -07:00
parent 19d686e7ad
commit 940f2d1d1e
2 changed files with 71 additions and 42 deletions

View File

@@ -73,13 +73,13 @@ macro_rules! step {
step!(@code ($($done)* $($arg)?), $cpu, $bus, $prefix, $modrm, $(name=$name$(<$($tyargs),*>)?,)? $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=$name:ident$(<$($tyargs:tt),*>)?,)? $cycles:literal,
( $($rest:tt)* ) ),
( $($args:tt)* )) => {
step!(@code ($($done)*), $cpu, $bus, $prefix, $modrm, $(name=$name$(<$($tyargs),*>)?,)? $cycles, ( $($args)* $($rest)* ))
// directive contains sub-directives, process them separately
(@sub ( ($($_done:tt)*),
$cpu:expr, $bus:expr, $prefix:tt, $modrm:tt,
$(name=$_name:ident$(<$($_tyargs:tt),*>)?,)? $cycles:literal,
( $($_rest:tt)* ) ),
( $($dirs:tt)* )) => {
step!(@code (/* omit done */), $cpu, $bus, $prefix, $modrm, /* omit name */ $cycles, ( $($dirs)* ))
};
// Set the type arguments for operations that cannot infer width
@@ -158,27 +158,23 @@ macro_rules! step {
(@displace0=($reg1:ident $(+ $reg2:ident)? ) $cookie:tt, $cpu:expr, $bus:expr,
($segment:ident, $repeat:ident, $prefix_loop:lifetime),
$modrm:tt) => {
step!(@arg $cookie, FarPtr { bus: $bus,
segment: $segment.unwrap(),
offset: $cpu.$reg1.get() $(+ $cpu.$reg2.get())? })
step!(@arg $cookie, ($segment.unwrap(), $cpu.$reg1.get() $(+ $cpu.$reg2.get())?) )
};
(@displace8=($reg1:ident $(+ $reg2:ident)? ) $cookie:tt, $cpu:expr, $bus:expr,
($segment:ident, $repeat:ident, $prefix_loop:lifetime),
$modrm:tt) => { {
let rel8 = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus) as i8 as u16;
step!(@arg $cookie, FarPtr { bus: $bus,
segment: $segment.unwrap(),
offset: ($cpu.$reg1.get() $(+ $cpu.$reg2.get())?).wrapping_add(rel8) })
step!(@arg $cookie, ($segment.unwrap(),
($cpu.$reg1.get() $(+ $cpu.$reg2.get())?).wrapping_add(rel8)) )
} };
(@displace16=($reg1:ident $(+ $reg2:ident)? ) $cookie:tt, $cpu:expr, $bus:expr,
($segment:ident, $repeat:ident, $prefix_loop:lifetime),
$modrm:tt) => { {
let rel16 = i8088::next_ip16($cpu.cs.get(), &mut $cpu.ip, $bus);
step!(@arg $cookie, FarPtr { bus: $bus,
segment: $segment.unwrap(),
offset: ($cpu.$reg1.get() $(+ $cpu.$reg2.get())?).wrapping_add(rel16) })
step!(@arg $cookie, ($segment.unwrap(),
($cpu.$reg1.get() $(+ $cpu.$reg2.get())?).wrapping_add(rel16)) )
} };
(@flags $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => {
@@ -220,10 +216,11 @@ macro_rules! step {
$modrm8:tt
)) => { {
let modrm_val = $modrm_val & !0x38;
match modrm_val {
$( $val => step!(@push $cookie, ($($args $(= $argrhs)?)* ) ) ),*,
let (seg, addr) = match modrm_val {
$( $val => step!(@sub $cookie, ($($args $(= $argrhs)?)* ) ) ),*,
_ => unimplemented!("modrm: {:02X}({:02X})\ncpu: {:#X?}", $modrm_val, modrm_val, $cpu)
}
};
step!(@arg $cookie, FarPtr { bus: $bus, segment: seg, offset: addr })
} };
(@modrm16 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt,
@@ -233,10 +230,20 @@ macro_rules! step {
$modrm8:tt
)) => { {
let modrm_val = $modrm_val & !0x38;
match modrm_val {
$( $val => step!(@push $cookie, ($($args $(= $argrhs)?)* ) ) ),*,
$( $val16 => step!(@push $cookie, ($($args16 $(= $argrhs16)?)* ) ) ),*,
_ => unimplemented!("modrm: {:02X}({:02X})\ncpu: {:#X?}", $modrm_val, modrm_val, $cpu)
if modrm_val & 0xC0 != 0xC0 {
// argument is a FarPtr
let (seg, addr) = match modrm_val {
$( $val => step!(@sub $cookie, ($($args $(= $argrhs)?)* ) ) ),*,
_ => unimplemented!("modrm: {:02X}({:02X})\ncpu: {:#X?}", $modrm_val, modrm_val, $cpu)
};
step!(@arg $cookie, FarPtr { bus: $bus, segment: seg, offset: addr })
} else {
// mod=11, argument is a register
let reg = match modrm_val {
$( $val16 => step!(@sub $cookie, ($($args16 $(= $argrhs16)?)* ) ) ),*,
_ => unimplemented!("modrm mod=11: {:02X}({:02X})\ncpu: {:#X?}", $modrm_val, modrm_val, $cpu)
};
step!(@arg $cookie, reg)
}
} };
@@ -247,10 +254,20 @@ macro_rules! step {
{ $($val8:literal => $($args8:ident $(= $argrhs8:tt)?),* / $mode8:ident $cycles8:literal),*$(,)? }
)) => { {
let modrm_val = $modrm_val & !0x38;
match modrm_val {
$( $val => step!(@push $cookie, ($($args $(= $argrhs)?)* ) ) ),*,
$( $val8 => step!(@push $cookie, ($($args8 $(= $argrhs8)?)* ) ) ),*,
_ => unimplemented!("modrm: {:02X}({:02X})\ncpu: {:#X?}", $modrm_val, modrm_val, $cpu)
if modrm_val & 0xC0 != 0xC0 {
// argument is a FarPtr
let (seg, addr) = match modrm_val {
$( $val => step!(@sub $cookie, ($($args $(= $argrhs)?)* ) ) ),*,
_ => unimplemented!("modrm: {:02X}({:02X})\ncpu: {:#X?}", $modrm_val, modrm_val, $cpu)
};
step!(@arg $cookie, FarPtr { bus: $bus, segment: seg, offset: addr })
} else {
// mod=11, argument is a register
let reg: RegHalf = match modrm_val {
$( $val8 => step!(@sub $cookie, ($($args8 $(= $argrhs8)?)* ) ) ),*,
_ => unimplemented!("modrm mod=11: {:02X}({:02X})\ncpu: {:#X?}", $modrm_val, modrm_val, $cpu)
};
step!(@arg $cookie, reg)
}
} };
@@ -636,7 +653,7 @@ impl i8088 {
0x03 => seg=ss, displace0=(bp+di) / M 7,
0x04 => seg=ds, displace0=(si) / M 5,
0x05 => seg=ds, displace0=(di) / M 5,
0x06 => seg=ds, addr / M 6,
0x06 => seg=ds, seg, d16 / M 6,
0x07 => seg=ds, displace0=(b) / M 5,
0x40 => seg=ds, displace8=(b+si) / M 11,
0x41 => seg=ds, displace8=(b+di) / M 12,
@@ -666,14 +683,14 @@ impl i8088 {
0xC7 => reg=di / R 0,
},
modrm8: {
0xC0 => reglo=a / R 0,
0xC1 => reglo=c / R 0,
0xC2 => reglo=d / R 0,
0xC3 => reglo=b / R 0,
0xC4 => reghi=a / R 0,
0xC5 => reghi=c / R 0,
0xC6 => reghi=d / R 0,
0xC7 => reghi=b / R 0,
0xC0 => reglo=a, convert / R 0,
0xC1 => reglo=c, convert / R 0,
0xC2 => reglo=d, convert / R 0,
0xC3 => reglo=b, convert / R 0,
0xC4 => reghi=a, convert / R 0,
0xC5 => reghi=c, convert / R 0,
0xC6 => reghi=d, convert / R 0,
0xC7 => reghi=b, convert / R 0,
})
}
}

View File

@@ -178,15 +178,15 @@ impl RValue<u8> for RegLo<'_> {
}
pub enum RegHalf<'a> {
Hi(RegHi<'a>),
Lo(RegLo<'a>)
Lo(RegLo<'a>),
Hi(RegHi<'a>)
}
impl LValue<u8> for RegHalf<'_> {
fn write(&mut self, val: u8) {
match self {
RegHalf::Hi(hi) => hi.write(val),
RegHalf::Lo(lo) => lo.write(val)
RegHalf::Lo(lo) => lo.write(val),
RegHalf::Hi(hi) => hi.write(val)
}
}
}
@@ -194,12 +194,24 @@ impl LValue<u8> for RegHalf<'_> {
impl RValue<u8> for RegHalf<'_> {
fn read(&self) -> u8 {
match self {
RegHalf::Hi(hi) => hi.read(),
RegHalf::Lo(lo) => lo.read()
RegHalf::Lo(lo) => lo.read(),
RegHalf::Hi(hi) => hi.read()
}
}
}
impl<'a> From<RegHi<'a>> for RegHalf<'a> {
fn from(reg: RegHi) -> RegHalf {
RegHalf::Hi(reg)
}
}
impl<'a> From<RegLo<'a>> for RegHalf<'a> {
fn from(reg: RegLo) -> RegHalf {
RegHalf::Lo(reg)
}
}
pub enum DynLValue<'a> {
Reg(Reg<'a>),
FarPtr { segment: u16, offset: u16 },