emu: INT instruction, standalone dos function for now
This commit is contained in:
9
src/emu/dos.rs
Normal file
9
src/emu/dos.rs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
use emu::pc::Bus;
|
||||||
|
use emu::i8088::i8088;
|
||||||
|
|
||||||
|
pub fn interrupt(cpu: &mut i8088, _bus: &mut Bus) {
|
||||||
|
let svc = cpu.a;
|
||||||
|
match svc {
|
||||||
|
_ => unimplemented!("dos service: {:#02X}\ncpu: {:#X?}", svc, cpu)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,8 +50,9 @@ pub struct Flags {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod ops {
|
mod ops {
|
||||||
use emu::i8088::{LValue, RValue, segoff_to_addr};
|
|
||||||
use emu::byteorder::{ByteOrder, LittleEndian};
|
use emu::byteorder::{ByteOrder, LittleEndian};
|
||||||
|
use emu::dos;
|
||||||
|
use emu::i8088::{Bus, LValue, RValue, i8088, segoff_to_addr};
|
||||||
|
|
||||||
pub fn call(ip: &mut u16, ss: u16, sp: &mut u16, mem: &mut [u8], addr: i16) {
|
pub fn call(ip: &mut u16, ss: u16, sp: &mut u16, mem: &mut [u8], addr: i16) {
|
||||||
let target = ip.wrapping_add(addr as u16);
|
let target = ip.wrapping_add(addr as u16);
|
||||||
@@ -59,6 +60,13 @@ mod ops {
|
|||||||
*ip = target;
|
*ip = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn int(cpu: &mut i8088, bus: &mut Bus, num: &u8) {
|
||||||
|
match num {
|
||||||
|
0x21 => dos::interrupt(cpu, bus),
|
||||||
|
_ => unimplemented!("interrupt: {:02X}\ncpu: {:#X?}", num, cpu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mov<T>(dst: &mut impl LValue<T>, src: &impl RValue<T>) {
|
pub fn mov<T>(dst: &mut impl LValue<T>, src: &impl RValue<T>) {
|
||||||
dst.write(src.read());
|
dst.write(src.read());
|
||||||
}
|
}
|
||||||
@@ -130,14 +138,14 @@ impl<'a> RValue<u8> for RegHi<'a> {
|
|||||||
macro_rules! step {
|
macro_rules! step {
|
||||||
// Base case: all args processed and ready to call op
|
// Base case: all args processed and ready to call op
|
||||||
(@code ( $($args:tt)* ),
|
(@code ( $($args:tt)* ),
|
||||||
$cpu:ident, $bus:ident, $name:ident, $cycles:literal,
|
$cpu:expr, $bus:expr, $name:ident, $cycles:literal,
|
||||||
()) => {
|
()) => {
|
||||||
ops::$name($($args),*);
|
ops::$name($($args),*);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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:expr, $bus:expr, $name:ident, $cycles:literal,
|
||||||
($next:ident $(= $nextrhs:ident)? $($rest:ident $(= $restrhs:ident)?)*)) => {
|
($next:ident $(= $nextrhs:ident)? $($rest:ident $(= $restrhs:ident)?)*)) => {
|
||||||
step!(@$next$(= $nextrhs)?
|
step!(@$next$(= $nextrhs)?
|
||||||
( ($($args)*), $cpu, $bus, $name, $cycles, ($($rest $(= $restrhs)?)*) ),
|
( ($($args)*), $cpu, $bus, $name, $cycles, ($($rest $(= $restrhs)?)*) ),
|
||||||
@@ -145,41 +153,50 @@ macro_rules! step {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 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
|
||||||
(@arg ( ($($args:tt)*), $cpu:ident, $bus:ident, $name:ident, $cycles:literal, ( $($rest:tt)* ) ),
|
(@arg ( ($($args:tt)*), $cpu:expr, $bus:expr, $name:ident, $cycles:literal, ( $($rest:tt)* ) ),
|
||||||
$arg:expr) => {
|
$arg:expr) => {
|
||||||
step!(@code ($($args)* $arg), $cpu, $bus, $name, $cycles, ( $($rest)* ))
|
step!(@code ($($args)* $arg), $cpu, $bus, $name, $cycles, ( $($rest)* ))
|
||||||
};
|
};
|
||||||
|
|
||||||
// Argument Decoders
|
// Argument Decoders
|
||||||
|
|
||||||
(@d8 $cookie:tt, $cpu:ident, $bus:ident) => { {
|
(@bus $cookie:tt, $cpu:expr, $bus:expr) => { {
|
||||||
step!(@arg $cookie, &i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus))
|
step!(@arg $cookie, $bus)
|
||||||
} };
|
} };
|
||||||
|
|
||||||
(@d16 $cookie:tt, $cpu:ident, $bus:ident) => { {
|
(@cpu $cookie:tt, $cpu:expr, $bus:expr) => { {
|
||||||
|
step!(@arg $cookie, $cpu)
|
||||||
|
} };
|
||||||
|
|
||||||
|
(@d8 $cookie:tt, $cpu:expr, $bus:expr) => { {
|
||||||
|
let d8 = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
|
||||||
|
step!(@arg $cookie, &d8)
|
||||||
|
} };
|
||||||
|
|
||||||
|
(@d16 $cookie:tt, $cpu:expr, $bus:expr) => { {
|
||||||
let mut buf = [0; 2];
|
let mut buf = [0; 2];
|
||||||
buf[0] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
|
buf[0] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
|
||||||
buf[1] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
|
buf[1] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
|
||||||
step!(@arg $cookie, &LittleEndian::read_u16(&buf))
|
step!(@arg $cookie, &LittleEndian::read_u16(&buf))
|
||||||
} };
|
} };
|
||||||
|
|
||||||
(@mem $cookie:tt, $cpu:ident, $bus:ident) => {
|
(@mem $cookie:tt, $cpu:expr, $bus:expr) => {
|
||||||
step!(@arg $cookie, &mut $bus.ram)
|
step!(@arg $cookie, &mut $bus.ram)
|
||||||
};
|
};
|
||||||
|
|
||||||
(@reg=$reg:ident $cookie:tt, $cpu:ident, $bus:ident) => {
|
(@reg=$reg:ident $cookie:tt, $cpu:expr, $bus:expr) => {
|
||||||
step!(@arg $cookie, &mut $cpu.$reg);
|
step!(@arg $cookie, &mut $cpu.$reg);
|
||||||
};
|
};
|
||||||
|
|
||||||
(@reghi=$reg:ident $cookie:tt, $cpu:ident, $bus:ident) => {
|
(@reghi=$reg:ident $cookie:tt, $cpu:expr, $bus:expr) => {
|
||||||
step!(@arg $cookie, &mut RegHi { reg: &mut $cpu.$reg });
|
step!(@arg $cookie, &mut RegHi { reg: &mut $cpu.$reg });
|
||||||
};
|
};
|
||||||
|
|
||||||
(@regval=$reg:ident $cookie:tt, $cpu:ident, $bus:ident) => {
|
(@regval=$reg:ident $cookie:tt, $cpu:expr, $bus:expr) => {
|
||||||
step!(@arg $cookie, $cpu.$reg);
|
step!(@arg $cookie, $cpu.$reg);
|
||||||
};
|
};
|
||||||
|
|
||||||
(@rel16 $cookie:tt, $cpu:ident, $bus:ident) => { {
|
(@rel16 $cookie:tt, $cpu:expr, $bus:expr) => { {
|
||||||
let mut buf = [0; 2];
|
let mut buf = [0; 2];
|
||||||
buf[0] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
|
buf[0] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
|
||||||
buf[1] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
|
buf[1] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
|
||||||
@@ -187,7 +204,7 @@ macro_rules! step {
|
|||||||
} };
|
} };
|
||||||
|
|
||||||
// Entry Point
|
// Entry Point
|
||||||
(($cpu:ident, $bus:ident) => { $( $code:literal => $name:ident[$($args:ident $(= $argrhs:ident)?),*] / $cycles:literal ),*$(,)? } ) => {
|
(($cpu:expr, $bus:expr) => { $( $code:literal => $name:ident[$($args:ident $(= $argrhs:ident)?),*] / $cycles:literal ),*$(,)? } ) => {
|
||||||
{
|
{
|
||||||
let opcode = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
|
let opcode = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
|
||||||
match(opcode) {
|
match(opcode) {
|
||||||
@@ -210,6 +227,7 @@ impl i8088 {
|
|||||||
0xB4 => mov[reghi=a, d8] / 4,
|
0xB4 => mov[reghi=a, d8] / 4,
|
||||||
0xBA => mov[reg=d, d16] / 4,
|
0xBA => mov[reg=d, d16] / 4,
|
||||||
0xC3 => ret[reg=ip, regval=ss, reg=sp, mem] / 20,
|
0xC3 => ret[reg=ip, regval=ss, reg=sp, mem] / 20,
|
||||||
|
0xCD => int[cpu, bus, d8] / 71,
|
||||||
0xE8 => call[reg=ip, regval=ss, reg=sp, mem, rel16] / 23,
|
0xE8 => call[reg=ip, regval=ss, reg=sp, mem, rel16] / 23,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
|
|
||||||
pub mod pc;
|
pub mod dos;
|
||||||
pub mod i8088;
|
pub mod i8088;
|
||||||
|
pub mod pc;
|
||||||
|
|||||||
Reference in New Issue
Block a user