emu: segment prefix, addr Arg decoder, Addr arg trait, NOP opcode
This commit is contained in:
174
src/emu/i8088.rs
174
src/emu/i8088.rs
@@ -53,16 +53,14 @@ pub struct Flags {
|
|||||||
mod ops {
|
mod ops {
|
||||||
use emu::byteorder::{ByteOrder, LittleEndian};
|
use emu::byteorder::{ByteOrder, LittleEndian};
|
||||||
use emu::dos;
|
use emu::dos;
|
||||||
use emu::i8088::{Bus, LValue, Reg, RValue, i8088, segoff_to_addr};
|
use emu::i8088::{Address, Bus, LValue, Reg, RValue, i8088, segoff_to_addr};
|
||||||
|
|
||||||
pub fn show(cpu: &mut i8088) {
|
pub fn show(cpu: &mut i8088) {
|
||||||
println!("{:#X?}", cpu);
|
println!("{:#X?}", cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peek(cpu: &mut i8088, bus: &mut Bus, addr: &u16) {
|
pub fn peek(addr: &(impl Address + RValue<u8>)) {
|
||||||
let addr = segoff_to_addr(cpu.ds.get(), *addr);
|
println!("PEEK: @{:#X} = {:#X} ({})", addr.addr(), addr.read(), addr.read());
|
||||||
let val = bus.ram[addr];
|
|
||||||
println!("PEEK: @{:#X} = {:#X} ({})", addr, val, val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call(ip: &mut Reg, ss: u16, sp: &mut Reg, mem: &mut [u8], addr: i16) {
|
pub fn call(ip: &mut Reg, ss: u16, sp: &mut Reg, mem: &mut [u8], addr: i16) {
|
||||||
@@ -82,6 +80,8 @@ mod ops {
|
|||||||
dst.write(src.read());
|
dst.write(src.read());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn nop() {}
|
||||||
|
|
||||||
pub fn pop16(ss: u16, sp: &mut Reg, mem: &[u8]) -> u16 {
|
pub fn pop16(ss: u16, sp: &mut Reg, mem: &[u8]) -> u16 {
|
||||||
let val = LittleEndian::read_u16(&mem[segoff_to_addr(ss.read(), sp.read())..]);
|
let val = LittleEndian::read_u16(&mem[segoff_to_addr(ss.read(), sp.read())..]);
|
||||||
sp.write(sp.read() + 2);
|
sp.write(sp.read() + 2);
|
||||||
@@ -107,6 +107,10 @@ pub trait RValue<T> {
|
|||||||
fn read(&self) -> T;
|
fn read(&self) -> T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Address {
|
||||||
|
fn addr(&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
impl RValue<u8> for u8 {
|
impl RValue<u8> for u8 {
|
||||||
fn read(&self) -> u8 {
|
fn read(&self) -> u8 {
|
||||||
*self
|
*self
|
||||||
@@ -129,13 +133,13 @@ pub struct Reg<'a> {
|
|||||||
reg: &'a Cell<u16>
|
reg: &'a Cell<u16>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LValue<u16> for Reg<'a> {
|
impl LValue<u16> for Reg<'_> {
|
||||||
fn write(&mut self, val: u16) {
|
fn write(&mut self, val: u16) {
|
||||||
self.reg.set(val);
|
self.reg.set(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RValue<u16> for Reg<'a> {
|
impl RValue<u16> for Reg<'_> {
|
||||||
fn read(&self) -> u16 {
|
fn read(&self) -> u16 {
|
||||||
self.reg.get()
|
self.reg.get()
|
||||||
}
|
}
|
||||||
@@ -145,29 +149,52 @@ struct RegHi<'a> {
|
|||||||
reg: &'a Cell<u16>
|
reg: &'a Cell<u16>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LValue<u8> for RegHi<'a> {
|
impl LValue<u8> for RegHi<'_> {
|
||||||
fn write(&mut self, val: u8) {
|
fn write(&mut self, val: u8) {
|
||||||
write_hi(&mut self.reg, val);
|
write_hi(&mut self.reg, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RValue<u8> for RegHi<'a> {
|
impl RValue<u8> for RegHi<'_> {
|
||||||
fn read(&self) -> u8 {
|
fn read(&self) -> u8 {
|
||||||
read_hi(self.reg)
|
read_hi(self.reg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Addr<'a> {
|
||||||
|
bus: &'a mut Bus,
|
||||||
|
addr: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Address for Addr<'_> {
|
||||||
|
fn addr(&self) -> usize {
|
||||||
|
self.addr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LValue<u8> for Addr<'_> {
|
||||||
|
fn write(&mut self, val: u8) {
|
||||||
|
self.bus.write(self.addr, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RValue<u8> for Addr<'_> {
|
||||||
|
fn read(&self) -> u8 {
|
||||||
|
self.bus.read(self.addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct RegLo<'a> {
|
struct RegLo<'a> {
|
||||||
reg: &'a Cell<u16>
|
reg: &'a Cell<u16>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LValue<u8> for RegLo<'a> {
|
impl LValue<u8> for RegLo<'_> {
|
||||||
fn write(&mut self, val: u8) {
|
fn write(&mut self, val: u8) {
|
||||||
write_lo(&mut self.reg, val);
|
write_lo(&mut self.reg, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RValue<u8> for RegLo<'a> {
|
impl RValue<u8> for RegLo<'_> {
|
||||||
fn read(&self) -> u8 {
|
fn read(&self) -> u8 {
|
||||||
read_lo(self.reg)
|
read_lo(self.reg)
|
||||||
}
|
}
|
||||||
@@ -176,59 +203,64 @@ impl<'a> RValue<u8> for RegLo<'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 ( $($done:tt)* ),
|
(@code ( $($done:tt)* ),
|
||||||
$cpu:expr, $bus:expr, $modrm:tt, $name:ident, $cycles:literal,
|
$cpu:expr, $bus:expr, $prefix:tt, $modrm:tt, $name:ident, $cycles:literal,
|
||||||
()) => {
|
()) => {
|
||||||
ops::$name($($done),*);
|
ops::$name($($done),*);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Inductive case: decode next arg to be placed in list
|
// Inductive case: decode next arg to be placed in list
|
||||||
(@code ( $($done:tt)* ),
|
(@code ( $($done:tt)* ),
|
||||||
$cpu:expr, $bus:expr, $modrm:tt, $name:ident, $cycles:literal,
|
$cpu:expr, $bus:expr, $prefix:tt, $modrm:tt, $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)?
|
||||||
// "cookie" tt to be passed thru to @arg so we have all the args for the recursive step
|
// "cookie" tt to be passed thru to @arg so we have all the args for the recursive step
|
||||||
( ($($done)*), $cpu, $bus, $modrm, $name, $cycles, ($($rest $(= $restrhs)?)*) ),
|
( ($($done)*), $cpu, $bus, $prefix, $modrm, $name, $cycles, ($($rest $(= $restrhs)?)*) ),
|
||||||
$cpu, $bus, $modrm)
|
$cpu, $bus, $prefix, $modrm)
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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 ( ($($done:tt)*), $cpu:expr, $bus:expr, $modrm:tt, $name:ident, $cycles:literal, $rest:tt ),
|
(@arg ( ($($done:tt)*), $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt,
|
||||||
$arg:expr) => {
|
$name:ident, $cycles:literal, $rest:tt )
|
||||||
step!(@code ($($done)* $arg), $cpu, $bus, $modrm, $name, $cycles, $rest)
|
$(, $arg:expr)?) => {
|
||||||
|
step!(@code ($($done)* $($arg)?), $cpu, $bus, $prefix, $modrm, $name, $cycles, $rest)
|
||||||
};
|
};
|
||||||
|
|
||||||
// decoder deferring to sub-decoders, push them onto the decoder stack to process next
|
// decoder deferring to sub-decoders, push them onto the decoder stack to process next
|
||||||
(@push ( $done:tt, $cpu:expr, $bus:expr, $modrm:tt, $name:ident, $cycles:literal, ( $($rest:tt)* ) ),
|
(@push ( $done:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt, $name:ident, $cycles:literal, ( $($rest:tt)* ) ),
|
||||||
( $($args:tt)* )) => {
|
( $($args:tt)* )) => {
|
||||||
step!(@code $done, $cpu, $bus, $modrm, $name, $cycles, ( $($args)* $($rest)* ))
|
step!(@code $done, $cpu, $bus, $prefix, $modrm, $name, $cycles, ( $($args)* $($rest)* ))
|
||||||
};
|
};
|
||||||
// Argument Decoders
|
// Argument Decoders
|
||||||
|
|
||||||
(@bus $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => { {
|
(@addr $cookie:tt, $cpu:expr, $bus:expr, ($segment:ident, $prefix_loop:lifetime), $modrm:tt) => { {
|
||||||
|
let a16 = i8088::next_ip16($cpu.cs.get(), &mut $cpu.ip, $bus);
|
||||||
|
let addr = segoff_to_addr($segment.unwrap(), a16);
|
||||||
|
step!(@arg $cookie, &mut Addr { bus: $bus, addr: addr } )
|
||||||
|
} };
|
||||||
|
|
||||||
|
(@bus $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => {
|
||||||
step!(@arg $cookie, $bus)
|
step!(@arg $cookie, $bus)
|
||||||
} };
|
};
|
||||||
|
|
||||||
(@cpu $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => { {
|
(@cpu $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => {
|
||||||
step!(@arg $cookie, $cpu)
|
step!(@arg $cookie, $cpu)
|
||||||
} };
|
};
|
||||||
|
|
||||||
(@d8 $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => { {
|
(@d8 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => { {
|
||||||
let d8 = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus);
|
let d8 = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus);
|
||||||
step!(@arg $cookie, &d8)
|
step!(@arg $cookie, &d8)
|
||||||
} };
|
} };
|
||||||
|
|
||||||
(@d16 $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => { {
|
(@d16 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => { {
|
||||||
let mut buf = [0; 2];
|
let d16 = i8088::next_ip16($cpu.cs.get(), &mut $cpu.ip, $bus);
|
||||||
buf[0] = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus);
|
step!(@arg $cookie, &d16)
|
||||||
buf[1] = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus);
|
|
||||||
step!(@arg $cookie, &LittleEndian::read_u16(&buf))
|
|
||||||
} };
|
} };
|
||||||
|
|
||||||
(@mem $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => {
|
(@mem $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => {
|
||||||
step!(@arg $cookie, &mut $bus.ram)
|
step!(@arg $cookie, &mut $bus.ram)
|
||||||
};
|
};
|
||||||
|
|
||||||
(@modrm16 $cookie:tt, $cpu:expr, $bus:expr,
|
(@modrm16 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt,
|
||||||
($modrm_val:ident, { $($val:literal => $($args:ident = $argrhs:tt),*),*$(,)? }, $modrm8:tt)) => { {
|
($modrm_val:ident, { $($val:literal => $($args:ident = $argrhs:tt),*),*$(,)? }, $modrm8:tt)) => { {
|
||||||
let modrm_val = $modrm_val & !0x38;
|
let modrm_val = $modrm_val & !0x38;
|
||||||
match modrm_val {
|
match modrm_val {
|
||||||
@@ -237,7 +269,9 @@ macro_rules! step {
|
|||||||
}
|
}
|
||||||
} };
|
} };
|
||||||
|
|
||||||
(@r16 $cookie:tt, $cpu:expr, $bus:expr, ($modrm:ident, $modrm16:tt, $modrm8:tt)) => {
|
(@prefix $cookie:tt, $cpu:expr, $bus:expr, ($segment:ident, $prefix_loop:lifetime), $modrm:tt) => { continue $prefix_loop; };
|
||||||
|
|
||||||
|
(@r16 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, ($modrm:ident, $modrm16:tt, $modrm8:tt)) => {
|
||||||
// TODO: Should these also be passed into the macro like the modrm specs?
|
// TODO: Should these also be passed into the macro like the modrm specs?
|
||||||
match $modrm >> 3 & 0x7 {
|
match $modrm >> 3 & 0x7 {
|
||||||
0 => step!(@arg $cookie, &mut Reg { reg: &$cpu.a } ),
|
0 => step!(@arg $cookie, &mut Reg { reg: &$cpu.a } ),
|
||||||
@@ -252,7 +286,7 @@ macro_rules! step {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
(@r8 $cookie:tt, $cpu:expr, $bus:expr, ($modrm:ident, $modrm16:tt, $modrm8:tt)) => {
|
(@r8 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, ($modrm:ident, $modrm16:tt, $modrm8:tt)) => {
|
||||||
// TODO: Should these also be passed into the macro like the modrm specs?
|
// TODO: Should these also be passed into the macro like the modrm specs?
|
||||||
match $modrm >> 3 & 0x7 {
|
match $modrm >> 3 & 0x7 {
|
||||||
0 => step!(@arg $cookie, &mut RegHi { reg: &$cpu.a } ),
|
0 => step!(@arg $cookie, &mut RegHi { reg: &$cpu.a } ),
|
||||||
@@ -267,36 +301,41 @@ macro_rules! step {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
(@reg=$reg:ident $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => {
|
(@reg=$reg:ident $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => {
|
||||||
step!(@arg $cookie, &mut Reg { reg: &$cpu.$reg });
|
step!(@arg $cookie, &mut Reg { reg: &$cpu.$reg });
|
||||||
};
|
};
|
||||||
|
|
||||||
(@reghi=$reg:ident $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => {
|
(@reghi=$reg:ident $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => {
|
||||||
step!(@arg $cookie, &mut RegHi { reg: &$cpu.$reg });
|
step!(@arg $cookie, &mut RegHi { reg: &$cpu.$reg });
|
||||||
};
|
};
|
||||||
|
|
||||||
(@reglo=$reg:ident $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => {
|
(@reglo=$reg:ident $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => {
|
||||||
step!(@arg $cookie, &mut RegLo { reg: &$cpu.$reg });
|
step!(@arg $cookie, &mut RegLo { reg: &$cpu.$reg });
|
||||||
};
|
};
|
||||||
|
|
||||||
(@regval=$reg:ident $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => {
|
(@regval=$reg:ident $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => {
|
||||||
step!(@arg $cookie, $cpu.$reg.get());
|
step!(@arg $cookie, $cpu.$reg.get());
|
||||||
};
|
};
|
||||||
|
|
||||||
(@rel16 $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => { {
|
(@rel16 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => { {
|
||||||
let mut buf = [0; 2];
|
let mut buf = [0; 2];
|
||||||
buf[0] = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus);
|
buf[0] = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus);
|
||||||
buf[1] = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus);
|
buf[1] = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus);
|
||||||
step!(@arg $cookie, LittleEndian::read_i16(&buf))
|
step!(@arg $cookie, LittleEndian::read_i16(&buf))
|
||||||
} };
|
} };
|
||||||
|
|
||||||
|
(@seg=$seg:ident $cookie:tt, $cpu:expr, $bus:expr, ($segment:ident, $prefix_loop:lifetime), $modrm:tt) => { {
|
||||||
|
$segment = $segment.or(Some($cpu.$seg.get()));
|
||||||
|
step!(@arg $cookie)
|
||||||
|
} };
|
||||||
|
|
||||||
// Group Decoder
|
// Group Decoder
|
||||||
(@group $cpu:expr, $bus:expr, ($modrm:ident, $modrm16:tt, $modrm8:tt), $code:literal,
|
(@group $cpu:expr, $bus:expr, $prefix:tt, ($modrm:ident, $modrm16:tt, $modrm8:tt), $code:literal,
|
||||||
{ $( $subcode:literal =>
|
{ $( $subcode:literal =>
|
||||||
$name:ident[$($args:ident $(= $argrhs:ident)?),*] / $cycles:literal),*$(,)? } ) => { {
|
$name:ident[$($args:ident $(= $argrhs:ident)?),*] / $cycles:literal),*$(,)? } ) => { {
|
||||||
let subcode = $modrm & 0x38;
|
let subcode = $modrm & 0x38;
|
||||||
match subcode {
|
match subcode {
|
||||||
$( $subcode => step!(@code (), $cpu, $bus, ($modrm, $modrm16, $modrm8), $name, $cycles, ($($args $(= $argrhs)?)*)) ),*,
|
$( $subcode => step!(@code (), $cpu, $bus, $prefix, ($modrm, $modrm16, $modrm8), $name, $cycles, ($($args $(= $argrhs)?)*)) ),*,
|
||||||
_ => unimplemented!("opcode: {:02X} {:02X}({:02X})\ncpu: {:#X?}", $code, $modrm, subcode, $cpu)
|
_ => unimplemented!("opcode: {:02X} {:02X}({:02X})\ncpu: {:#X?}", $code, $modrm, subcode, $cpu)
|
||||||
} }
|
} }
|
||||||
};
|
};
|
||||||
@@ -319,22 +358,27 @@ macro_rules! step {
|
|||||||
modrm8: $modrm8:tt
|
modrm8: $modrm8:tt
|
||||||
) => {
|
) => {
|
||||||
{
|
{
|
||||||
let opcode = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus);
|
let mut segment = None;
|
||||||
let modrm: u8; // Type ascription unnecessary but gives better err messages when missing $ext
|
let modrm: u8; // Type ascription unnecessary but gives better err messages when missing $ext
|
||||||
match(opcode) {
|
'prefix_loop: loop {
|
||||||
$( $( $code => {
|
let opcode = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus);
|
||||||
$( let $ext = (); /* No-op just to trigger expansion. */
|
match(opcode) {
|
||||||
modrm = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus); )?
|
$( $( $code => {
|
||||||
step!(@code (), $cpu, $bus, (modrm, $modrm16, $modrm8), $name, $cycles, ($($args $(= $argrhs)?)*))
|
$( let $ext = (); /* No-op just to trigger expansion. */
|
||||||
}
|
modrm = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus); )?
|
||||||
)?
|
step!(@code (), $cpu, $bus, (segment, 'prefix_loop), (modrm, $modrm16, $modrm8), $name, $cycles, ($($args $(= $argrhs)?)*))
|
||||||
$( $code => {
|
}
|
||||||
modrm = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus);
|
)?
|
||||||
step!(@group $cpu, $bus, (modrm, $modrm16, $modrm8), $code, $subcodes)
|
$( $code => {
|
||||||
}
|
modrm = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus);
|
||||||
)?
|
step!(@group $cpu, $bus, (segment, 'prefix_loop), (modrm, $modrm16, $modrm8), $code, $subcodes)
|
||||||
),*,
|
}
|
||||||
_ => unimplemented!("opcode: {:02X}\ncpu: {:#X?}", opcode, $cpu)
|
)?
|
||||||
|
),*,
|
||||||
|
_ => unimplemented!("opcode: {:02X}\ncpu: {:#X?}", opcode, $cpu)
|
||||||
|
}
|
||||||
|
// Only prefixes loop and they do so with an explicit continue statement
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -376,11 +420,16 @@ impl i8088 {
|
|||||||
loop {
|
loop {
|
||||||
step!((self, bus) =>
|
step!((self, bus) =>
|
||||||
opcodes: {
|
opcodes: {
|
||||||
|
0x26 => nop[seg=es, prefix] / 2,
|
||||||
|
0x2e => nop[seg=cs, prefix] / 2,
|
||||||
|
0x36 => nop[seg=ss, prefix] / 2,
|
||||||
|
0x3e => nop[seg=ds, prefix] / 2,
|
||||||
0x60 => show[cpu] / 0, // Fake opcode for debugging
|
0x60 => show[cpu] / 0, // Fake opcode for debugging
|
||||||
0x61 => peek[cpu, bus, d16] / 0, // Fake opcode for debugging
|
0x61 => peek[seg=ds, addr] / 0, // Fake opcode for debugging
|
||||||
0x8B _ => mov[r16, modrm16] / "2/12+",
|
0x8B _ => mov[r16, modrm16] / "2/12+",
|
||||||
0x8C: { 0x08 => mov[modrm16, reg=cs] / "2/13+", },
|
0x8C: { 0x08 => mov[modrm16, reg=cs] / "2/13+", },
|
||||||
0x8E: { 0x18 => mov[reg=ds, modrm16] / "2/12+", },
|
0x8E: { 0x18 => mov[reg=ds, modrm16] / "2/12+", },
|
||||||
|
0x90 => nop[] / 3,
|
||||||
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,
|
||||||
@@ -419,6 +468,17 @@ impl i8088 {
|
|||||||
// should loop within the segment if it did)
|
// should loop within the segment if it did)
|
||||||
bus.ram[eip - Bus::RAM_LOCATION]
|
bus.ram[eip - Bus::RAM_LOCATION]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn next_ip16<'a>(cs: u16, ip: &mut Cell<u16>, bus: &Bus) -> u16 {
|
||||||
|
let eip = segoff_to_addr(cs, ip.get());
|
||||||
|
ip.set(ip.get() + 2);
|
||||||
|
|
||||||
|
// We'll assume cpu is always executing in RAM. Also assume the
|
||||||
|
// IP doesn't reach the end of the segment (My guess is that it
|
||||||
|
// should loop within the segment if it did)
|
||||||
|
let buf = &bus.ram[eip - Bus::RAM_LOCATION .. eip + 2 - Bus::RAM_LOCATION];
|
||||||
|
LittleEndian::read_u16(buf)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,13 @@ impl Bus {
|
|||||||
pub const RAM_LOCATION: usize = 0x0000_0000;
|
pub const RAM_LOCATION: usize = 0x0000_0000;
|
||||||
//const EGA_LOCATION: usize = 0x000A_0000;
|
//const EGA_LOCATION: usize = 0x000A_0000;
|
||||||
|
|
||||||
|
pub fn read(&self, addr: usize) -> u8 {
|
||||||
|
self.ram[addr]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&mut self, addr: usize, val: u8) {
|
||||||
|
self.ram[addr] = val;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PC {
|
impl PC {
|
||||||
|
|||||||
Reference in New Issue
Block a user