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:
@@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 },
|
||||
|
||||
Reference in New Issue
Block a user