From 5c39f3b5af4f2814505163adf62b40b5e42673ab Mon Sep 17 00:00:00 2001 From: Jared Burce Date: Fri, 5 Mar 2021 05:06:15 -0800 Subject: [PATCH] emu ops can get multiple args, mem no longer implicit, implement RET --- src/emu/i8088.rs | 48 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/src/emu/i8088.rs b/src/emu/i8088.rs index e9bff09..52a259f 100644 --- a/src/emu/i8088.rs +++ b/src/emu/i8088.rs @@ -56,26 +56,53 @@ mod ops { cpu.push16(mem, cpu.ip); cpu.ip = target; } + + pub fn ret(cpu: &mut super::i8088, mem: &[u8]) { + trace!("RET"); + cpu.ip = cpu.pop16(mem) + } } macro_rules! step { - (@code $cpu:ident, $bus:ident, ($name:ident, $cycles:literal, $arg:tt)) => { - step!(@$arg $name $cpu, $bus) + // Base case: all args processed and ready to call op + (@code ( $($args:tt)* ), + $cpu:ident, $bus:ident, $name:ident, $cycles:literal, + ()) => { + ops::$name($($args),*); }; - (@rel16 $name:ident $cpu:ident, $bus:ident) => { { + // Inductive case: decode next arg to be placed in list + (@code ( $($args:tt)* ), + $cpu:ident, $bus:ident, $name:ident, $cycles:literal, + ($next:tt $($rest:tt)*)) => { + step!(@$next ( ($($args)*), $cpu, $bus, $name, $cycles, ($($rest)*) ), $cpu, $bus) + }; + + // accept an argument from a decoder and recur to look for next arg + (@arg ( ($($args:tt)*), $cpu:ident, $bus:ident, $name:ident, $cycles:literal, ( $($rest:tt)* ) ), + $arg:expr) => { + step!(@code ($($args)* $arg), $cpu, $bus, $name, $cycles, ( $($rest)* )) + }; + + // Argument Decoders + + (@mem $cookie:tt, $cpu:ident, $bus:ident) => { + step!(@arg $cookie, &mut $bus.ram) + }; + + (@rel16 $cookie:tt, $cpu:ident, $bus:ident) => { { let mut buf = [0; 2]; buf[0] = $cpu.next_ip($bus); buf[1] = $cpu.next_ip($bus); - ops::$name($cpu, &mut $bus.ram, LittleEndian::read_i16(&buf)); + step!(@arg $cookie, LittleEndian::read_i16(&buf)) } }; // Entry Point - (($cpu:ident, $bus:ident) => { $( $code:literal => $impl:tt ),* } ) => { + (($cpu:ident, $bus:ident) => { $( $code:literal => $name:ident[$($args:tt),*] / $cycles:literal ),*$(,)? } ) => { { let opcode = $cpu.next_ip($bus); match(opcode) { - $( $code => step!(@code $cpu, $bus, $impl) )*, + $( $code => step!(@code ($cpu), $cpu, $bus, $name, $cycles, ($($args)*)) ),*, _ => unimplemented!("opcode: {:02X}", opcode) } } @@ -91,7 +118,8 @@ impl i8088 { pub fn run(&mut self, bus: &mut Bus) { loop { step!((self, bus) => { - 0xE8 => (call, 23, rel16) + 0xC3 => ret[mem] / 20, + 0xE8 => call[mem, rel16] / 23, }) } } @@ -102,6 +130,12 @@ impl i8088 { LittleEndian::write_u16(&mut mem[segoff_to_addr(self.ss, self.sp)..], val); } + fn pop16(&mut self, mem: &[u8]) -> u16 { + let val = LittleEndian::read_u16(&mem[segoff_to_addr(self.ss, self.sp)..]); + self.sp += 2; + val + } + fn next_ip<'a>(&mut self, bus: &Bus) -> u8 { let eip = segoff_to_addr(self.cs, self.ip); self.ip += 1;