emu: arg=rhs parsing. d16, reg, regval argtypes. non-generic MOV.
This commit is contained in:
@@ -50,17 +50,37 @@ pub struct Flags {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod ops {
|
mod ops {
|
||||||
pub fn call(cpu: &mut super::i8088, mem: &mut [u8], addr: i16) {
|
use emu::i8088::segoff_to_addr;
|
||||||
let target = cpu.ip.wrapping_add(addr as u16);
|
use emu::byteorder::{ByteOrder, LittleEndian};
|
||||||
|
|
||||||
|
pub fn call(ip: &mut u16, ss: u16, sp: &mut u16, mem: &mut [u8], addr: i16) {
|
||||||
|
let target = ip.wrapping_add(addr as u16);
|
||||||
trace!("CALL 0x{:04X}", target);
|
trace!("CALL 0x{:04X}", target);
|
||||||
cpu.push16(mem, cpu.ip);
|
push16(ss, sp, mem, *ip);
|
||||||
cpu.ip = target;
|
*ip = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ret(cpu: &mut super::i8088, mem: &[u8]) {
|
pub fn mov(reg: &mut super::Reg16, val: u16) {
|
||||||
trace!("RET");
|
reg.x = val;
|
||||||
cpu.ip = cpu.pop16(mem)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pop16(ss: u16, sp: &mut u16, mem: &[u8]) -> u16 {
|
||||||
|
let val = LittleEndian::read_u16(&mem[segoff_to_addr(ss, *sp)..]);
|
||||||
|
*sp += 2;
|
||||||
|
val
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push16(ss: u16, sp: &mut u16, mem: &mut [u8], val: u16) {
|
||||||
|
// XXX: Not checking for stack faults or anything
|
||||||
|
*sp -= 2;
|
||||||
|
LittleEndian::write_u16(&mut mem[segoff_to_addr(ss, *sp)..], val);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ret(ip: &mut u16, ss: u16, sp: &mut u16, mem: &[u8]) {
|
||||||
|
trace!("RET");
|
||||||
|
*ip = pop16(ss, sp, mem);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! step {
|
macro_rules! step {
|
||||||
@@ -74,8 +94,8 @@ macro_rules! step {
|
|||||||
// Inductive case: decode next arg to be placed in list
|
// Inductive case: decode next arg to be placed in list
|
||||||
(@code ( $($args:tt)* ),
|
(@code ( $($args:tt)* ),
|
||||||
$cpu:ident, $bus:ident, $name:ident, $cycles:literal,
|
$cpu:ident, $bus:ident, $name:ident, $cycles:literal,
|
||||||
($next:tt $($rest:tt)*)) => {
|
($next:ident $(= $nextrhs:ident)? $($rest:ident $(= $restrhs:ident)?)*)) => {
|
||||||
step!(@$next ( ($($args)*), $cpu, $bus, $name, $cycles, ($($rest)*) ), $cpu, $bus)
|
step!(@$next$(= $nextrhs)? ( ($($args)*), $cpu, $bus, $name, $cycles, ($($rest $(= $restrhs)?)*) ), $cpu, $bus)
|
||||||
};
|
};
|
||||||
|
|
||||||
// accept an argument from a decoder and recur to look for next arg
|
// accept an argument from a decoder and recur to look for next arg
|
||||||
@@ -86,10 +106,25 @@ macro_rules! step {
|
|||||||
|
|
||||||
// Argument Decoders
|
// Argument Decoders
|
||||||
|
|
||||||
|
(@d16 $cookie:tt, $cpu:ident, $bus:ident) => { {
|
||||||
|
let mut buf = [0; 2];
|
||||||
|
buf[0] = $cpu.next_ip($bus);
|
||||||
|
buf[1] = $cpu.next_ip($bus);
|
||||||
|
step!(@arg $cookie, LittleEndian::read_u16(&buf))
|
||||||
|
} };
|
||||||
|
|
||||||
(@mem $cookie:tt, $cpu:ident, $bus:ident) => {
|
(@mem $cookie:tt, $cpu:ident, $bus:ident) => {
|
||||||
step!(@arg $cookie, &mut $bus.ram)
|
step!(@arg $cookie, &mut $bus.ram)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
(@reg=$reg:ident $cookie:tt, $cpu:ident, $bus:ident) => {
|
||||||
|
step!(@arg $cookie, &mut $cpu.$reg);
|
||||||
|
};
|
||||||
|
|
||||||
|
(@regval=$reg:ident $cookie:tt, $cpu:ident, $bus:ident) => {
|
||||||
|
step!(@arg $cookie, $cpu.$reg);
|
||||||
|
};
|
||||||
|
|
||||||
(@rel16 $cookie:tt, $cpu:ident, $bus:ident) => { {
|
(@rel16 $cookie:tt, $cpu:ident, $bus:ident) => { {
|
||||||
let mut buf = [0; 2];
|
let mut buf = [0; 2];
|
||||||
buf[0] = $cpu.next_ip($bus);
|
buf[0] = $cpu.next_ip($bus);
|
||||||
@@ -98,11 +133,11 @@ macro_rules! step {
|
|||||||
} };
|
} };
|
||||||
|
|
||||||
// Entry Point
|
// Entry Point
|
||||||
(($cpu:ident, $bus:ident) => { $( $code:literal => $name:ident[$($args:tt),*] / $cycles:literal ),*$(,)? } ) => {
|
(($cpu:ident, $bus:ident) => { $( $code:literal => $name:ident[$($args:ident $(= $argrhs:ident)?),*] / $cycles:literal ),*$(,)? } ) => {
|
||||||
{
|
{
|
||||||
let opcode = $cpu.next_ip($bus);
|
let opcode = $cpu.next_ip($bus);
|
||||||
match(opcode) {
|
match(opcode) {
|
||||||
$( $code => step!(@code ($cpu), $cpu, $bus, $name, $cycles, ($($args)*)) ),*,
|
$( $code => step!(@code (), $cpu, $bus, $name, $cycles, ($($args $(= $argrhs)?)*)) ),*,
|
||||||
_ => unimplemented!("opcode: {:02X}", opcode)
|
_ => unimplemented!("opcode: {:02X}", opcode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,24 +153,13 @@ impl i8088 {
|
|||||||
pub fn run(&mut self, bus: &mut Bus) {
|
pub fn run(&mut self, bus: &mut Bus) {
|
||||||
loop {
|
loop {
|
||||||
step!((self, bus) => {
|
step!((self, bus) => {
|
||||||
0xC3 => ret[mem] / 20,
|
0xBA => mov[reg=d, d16] / 4,
|
||||||
0xE8 => call[mem, rel16] / 23,
|
0xC3 => ret[reg=ip, regval=ss, reg=sp, mem] / 20,
|
||||||
|
0xE8 => call[reg=ip, regval=ss, reg=sp, mem, rel16] / 23,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push16(&mut self, mem: &mut [u8], val: u16) {
|
|
||||||
// XXX: Not checking for stack faults or anything
|
|
||||||
self.sp -= 2;
|
|
||||||
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 {
|
fn next_ip<'a>(&mut self, bus: &Bus) -> u8 {
|
||||||
let eip = segoff_to_addr(self.cs, self.ip);
|
let eip = segoff_to_addr(self.cs, self.ip);
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user