emu ops can get multiple args, mem no longer implicit, implement RET
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user