diff --git a/src/emu/i8088.rs b/src/emu/i8088.rs index 7275958..56c974c 100644 --- a/src/emu/i8088.rs +++ b/src/emu/i8088.rs @@ -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, }) } } diff --git a/src/emu/operands.rs b/src/emu/operands.rs index 082db61..7f3697d 100644 --- a/src/emu/operands.rs +++ b/src/emu/operands.rs @@ -178,15 +178,15 @@ impl RValue for RegLo<'_> { } pub enum RegHalf<'a> { - Hi(RegHi<'a>), - Lo(RegLo<'a>) + Lo(RegLo<'a>), + Hi(RegHi<'a>) } impl LValue 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 for RegHalf<'_> { impl RValue 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> for RegHalf<'a> { + fn from(reg: RegHi) -> RegHalf { + RegHalf::Hi(reg) + } +} + +impl<'a> From> for RegHalf<'a> { + fn from(reg: RegLo) -> RegHalf { + RegHalf::Lo(reg) + } +} + pub enum DynLValue<'a> { Reg(Reg<'a>), FarPtr { segment: u16, offset: u16 },