emu: Operand trait over u8/u16, d8_as_d16 argtype
This commit is contained in:
@@ -15,6 +15,7 @@ gfx_device_gl = "0.15"
|
|||||||
image = "0.19"
|
image = "0.19"
|
||||||
lzw = "0.10"
|
lzw = "0.10"
|
||||||
nalgebra = "0.16"
|
nalgebra = "0.16"
|
||||||
|
num-traits = "0.2.14"
|
||||||
openvr = "0.6.0"
|
openvr = "0.6.0"
|
||||||
openvr_sys = "2"
|
openvr_sys = "2"
|
||||||
piston = "0.37"
|
piston = "0.37"
|
||||||
|
|||||||
@@ -112,6 +112,11 @@ macro_rules! step {
|
|||||||
step!(@arg $cookie, &d8)
|
step!(@arg $cookie, &d8)
|
||||||
} };
|
} };
|
||||||
|
|
||||||
|
(@d8_as_d16 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => { {
|
||||||
|
let d8 = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus);
|
||||||
|
step!(@arg $cookie, &(d8 as u16))
|
||||||
|
} };
|
||||||
|
|
||||||
(@d16 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => { {
|
(@d16 $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => { {
|
||||||
let d16 = i8088::next_ip16($cpu.cs.get(), &mut $cpu.ip, $bus);
|
let d16 = i8088::next_ip16($cpu.cs.get(), &mut $cpu.ip, $bus);
|
||||||
step!(@arg $cookie, &d16)
|
step!(@arg $cookie, &d16)
|
||||||
@@ -350,20 +355,20 @@ impl i8088 {
|
|||||||
0x26 => nop[seg=es, prefix] / 2,
|
0x26 => nop[seg=es, prefix] / 2,
|
||||||
0x2E => nop[seg=cs, prefix] / 2,
|
0x2E => nop[seg=cs, prefix] / 2,
|
||||||
0x36 => nop[seg=ss, prefix] / 2,
|
0x36 => nop[seg=ss, prefix] / 2,
|
||||||
0x38 _ => cmpb[flags, modrm8, r8] / "3/24+",
|
0x38 _ => cmp[flags, modrm8, r8] / "3/24+",
|
||||||
0x39 _ => cmpw[flags, modrm16, r16] / "3/24+",
|
0x39 _ => cmp[flags, modrm16, r16] / "3/24+",
|
||||||
0x3A _ => cmpb[flags, r8, modrm8] / "3/24+",
|
0x3A _ => cmp[flags, r8, modrm8] / "3/24+",
|
||||||
0x3B _ => cmpw[flags, r16, modrm16] / "3/24+",
|
0x3B _ => cmp[flags, r16, modrm16] / "3/24+",
|
||||||
0x3C => cmpb[flags, reglo=a, d8] / "3/24+",
|
0x3C => cmp[flags, reglo=a, d8] / "3/24+",
|
||||||
0x3D => cmpw[flags, reg=a, d16] / "3/24+",
|
0x3D => cmp[flags, reg=a, d16] / "3/24+",
|
||||||
0x3E => nop[seg=ds, 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[seg=ds, addr] / 0, // Fake opcode for debugging
|
0x61 => peek[seg=ds, addr] / 0, // Fake opcode for debugging
|
||||||
0x62 _ => assert[modrm8, d8] / 0, // Fake opcode for debugging
|
0x62 _ => assert[modrm8, d8] / 0, // Fake opcode for debugging
|
||||||
0x63 _ => assert[modrm16, d16] / 0, // Fake opcode for debugging
|
0x63 _ => assert[modrm16, d16] / 0, // Fake opcode for debugging
|
||||||
0x80: { 0x38 => cmpb[flags, modrm8, d8] / "4/23+", },
|
0x80: { 0x38 => cmp[flags, modrm8, d8] / "4/23+", },
|
||||||
0x81: { 0x38 => cmpw[flags, modrm16, d16] / "4/23+", },
|
0x81: { 0x38 => cmp[flags, modrm16, d16] / "4/23+", },
|
||||||
//0x83: { 0x38 => cmp?[flags, modrm16, d8] / "4/23+", },
|
0x83: { 0x38 => cmp[flags, modrm16, d8_as_d16] / "4/23+", },
|
||||||
0x88 _ => mov[modrm8, r8] / "2/13+",
|
0x88 _ => mov[modrm8, r8] / "2/13+",
|
||||||
0x89 _ => mov[modrm16, r16] / "2/13+",
|
0x89 _ => mov[modrm16, r16] / "2/13+",
|
||||||
0x8A _ => mov[r8, modrm8] / "2/12+",
|
0x8A _ => mov[r8, modrm8] / "2/12+",
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
|
extern crate num_traits;
|
||||||
|
|
||||||
pub mod dos;
|
pub mod dos;
|
||||||
pub mod i8088;
|
pub mod i8088;
|
||||||
|
|||||||
@@ -1,9 +1,33 @@
|
|||||||
use emu::util::segoff_to_addr;
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
|
||||||
use emu::util::{read_hi, read_lo, write_hi, write_lo};
|
use emu::num_traits as nt;
|
||||||
|
|
||||||
|
use emu::util::{read_hi, read_lo, segoff_to_addr, write_hi, write_lo};
|
||||||
use emu::pc::Bus;
|
use emu::pc::Bus;
|
||||||
|
|
||||||
|
pub trait Operand: Copy +
|
||||||
|
nt::Num +
|
||||||
|
nt::ops::overflowing::OverflowingSub +
|
||||||
|
std::ops::BitAnd<Output = Self> +
|
||||||
|
std::ops::BitXor<Output = Self> {
|
||||||
|
const HI_BIT_MASK: Self;
|
||||||
|
fn hi_bit(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Operand for u8 {
|
||||||
|
const HI_BIT_MASK: u8 = 0x80;
|
||||||
|
fn hi_bit(&self) -> bool {
|
||||||
|
self >> 7 == 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Operand for u16 {
|
||||||
|
const HI_BIT_MASK: u16 = 0x8000;
|
||||||
|
fn hi_bit(&self) -> bool {
|
||||||
|
self >> 15 == 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait LValue<T> {
|
pub trait LValue<T> {
|
||||||
fn write(&mut self, val: T);
|
fn write(&mut self, val: T);
|
||||||
}
|
}
|
||||||
@@ -16,22 +40,6 @@ pub trait Address {
|
|||||||
fn addr(&self) -> usize;
|
fn addr(&self) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait HiBit {
|
|
||||||
fn hi_bit(&self) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HiBit for u8 {
|
|
||||||
fn hi_bit(&self) -> bool {
|
|
||||||
self >> 7 == 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HiBit for u16 {
|
|
||||||
fn hi_bit(&self) -> bool {
|
|
||||||
self >> 15 == 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RValue<u8> for u8 {
|
impl RValue<u8> for u8 {
|
||||||
fn read(&self) -> u8 {
|
fn read(&self) -> u8 {
|
||||||
*self
|
*self
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use emu::byteorder::{ByteOrder, LittleEndian};
|
|||||||
|
|
||||||
use emu::dos;
|
use emu::dos;
|
||||||
use emu::i8088::{Flags, RepPrefix, i8088};
|
use emu::i8088::{Flags, RepPrefix, i8088};
|
||||||
use emu::operands::{Addr, Address, HiBit, LValue, Reg, RValue};
|
use emu::operands::{Addr, Address, LValue, Operand, Reg, RValue};
|
||||||
use emu::pc::Bus;
|
use emu::pc::Bus;
|
||||||
use emu::util::segoff_to_addr;
|
use emu::util::segoff_to_addr;
|
||||||
|
|
||||||
@@ -55,30 +55,30 @@ macro_rules! string_op {
|
|||||||
// Decide if this can realistically be generalized
|
// Decide if this can realistically be generalized
|
||||||
macro_rules! update_flags {
|
macro_rules! update_flags {
|
||||||
// Base Case
|
// Base Case
|
||||||
(@recur $flags:expr, $dst:ident, $carry:ident) => {};
|
(@recur $flags:expr, $t:ty, $dst:ident, $carry:ident) => {};
|
||||||
|
|
||||||
(@af $flags:expr, $dst:ident, $carry:ident) => { /* XXX: Adjust/AuxCarry esoteric? (mostly for BCD?), might not need */ };
|
(@af $flags:expr, $t:ty, $dst:ident, $carry:ident) => { /* XXX: Adjust/AuxCarry esoteric? (mostly for BCD?), might not need */ };
|
||||||
(@cf $flags:expr, $dst:ident, $carry:ident) => { $flags.cf = $carry };
|
(@cf $flags:expr, $t:ty, $dst:ident, $carry:ident) => { $flags.cf = $carry };
|
||||||
(@of $flags:expr, $dst:ident, $carry:ident) => { compile_error!("compute flags.of outside macro"); };
|
(@of $flags:expr, $t:ty, $dst:ident, $carry:ident) => { compile_error!("compute flags.of outside macro"); };
|
||||||
(@pf $flags:expr, $dst:ident, $carry:ident) => { /* XXX: parity looks esoteric, might not need */ };
|
(@pf $flags:expr, $t:ty, $dst:ident, $carry:ident) => { /* XXX: parity looks esoteric, might not need */ };
|
||||||
(@sf $flags:expr, $dst:ident, $carry:ident) => { $flags.sf = $dst.hi_bit(); };
|
(@sf $flags:expr, $t:ty, $dst:ident, $carry:ident) => { $flags.sf = $dst.hi_bit(); };
|
||||||
(@zf $flags:expr, $dst:ident, $carry:ident) => { $flags.zf = $dst == 0; };
|
(@zf $flags:expr, $t:ty, $dst:ident, $carry:ident) => { $flags.zf = $dst == <$t>::zero(); };
|
||||||
|
|
||||||
// Recursive step
|
// Recursive step
|
||||||
(@recur $flags:expr, $dst:ident, $carry:ident, $next:ident $(, $rest:ident)* ) => {
|
(@recur $flags:expr, $t:ty, $dst:ident, $carry:ident, $next:ident $(, $rest:ident)* ) => {
|
||||||
update_flags!(@$next $flags, $dst, $carry);
|
update_flags!(@$next $flags, $t, $dst, $carry);
|
||||||
update_flags!(@recur $flags, $dst, $carry $(, $rest)*);
|
update_flags!(@recur $flags, $t, $dst, $carry $(, $rest)*);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Entry Point
|
// Entry Point
|
||||||
($flags:expr, $eval:expr $(, $flagnames:ident)* ) => { {
|
($flags:expr, $t:ty, $eval:expr $(, $flagnames:ident)* ) => { {
|
||||||
let (dst, carry) = $eval;
|
let (dst, carry) = $eval;
|
||||||
update_flags!(@recur $flags, dst, carry $(, $flagnames)*);
|
update_flags!(@recur $flags, $t, dst, carry $(, $flagnames)*);
|
||||||
dst
|
dst
|
||||||
} }
|
} }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assert<T: Debug + Eq>(loc: &impl RValue<T>, val: &impl RValue<T>) {
|
pub fn assert<T: Operand + Debug>(loc: &impl RValue<T>, val: &impl RValue<T>) {
|
||||||
assert_eq!(loc.read(), val.read(),
|
assert_eq!(loc.read(), val.read(),
|
||||||
"ASSERT instruction failed: {:#2X?} != {:#2X?}", loc.read(), val.read());
|
"ASSERT instruction failed: {:#2X?} != {:#2X?}", loc.read(), val.read());
|
||||||
println!("ASSERT pass: {:#2X?} == {:#2X?}", loc.read(), val.read());
|
println!("ASSERT pass: {:#2X?} == {:#2X?}", loc.read(), val.read());
|
||||||
@@ -98,18 +98,10 @@ pub fn call(ip: &mut Reg, ss: u16, sp: &mut Reg, mem: &mut [u8], addr: i16) {
|
|||||||
ip.write(target);
|
ip.write(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cmpb(flags: &mut Flags, dst: &impl RValue<u8>, src: &impl RValue<u8>) {
|
pub fn cmp<T: Operand>(flags: &mut Flags, dst: &impl RValue<T>, src: &impl RValue<T>) {
|
||||||
let (dst, src) = (dst.read(), src.read());
|
let (dst, src) = (dst.read(), src.read());
|
||||||
let after = update_flags!(flags, dst.overflowing_sub(src), af, cf, pf, sf, zf);
|
let after = update_flags!(flags, T, dst.overflowing_sub(&src), af, cf, pf, sf, zf);
|
||||||
flags.of = 0 != 0x80 & // In the sign bit...
|
flags.of = T::zero() != T::HI_BIT_MASK & // In the (maybe) sign bit...
|
||||||
(src ^ dst) & // ...operands have different signs...
|
|
||||||
(dst ^ after); // ...and destination sign-bit changed
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cmpw(flags: &mut Flags, dst: &impl RValue<u16>, src: &impl RValue<u16>) {
|
|
||||||
let (dst, src) = (dst.read(), src.read());
|
|
||||||
let after = update_flags!(flags, dst.overflowing_sub(src), af, cf, pf, sf, zf);
|
|
||||||
flags.of = 0 != 0x8000 & // In the sign bit...
|
|
||||||
(src ^ dst) & // ...operands have different signs...
|
(src ^ dst) & // ...operands have different signs...
|
||||||
(dst ^ after); // ...and destination sign-bit changed
|
(dst ^ after); // ...and destination sign-bit changed
|
||||||
}
|
}
|
||||||
@@ -126,7 +118,7 @@ pub fn cmpsb(flags: &mut Flags,
|
|||||||
let src = <Addr as RValue<u8>>::read(&Addr { bus: bus, segment: seg, offset: si.read() });
|
let src = <Addr as RValue<u8>>::read(&Addr { bus: bus, segment: seg, offset: si.read() });
|
||||||
let dst = <Addr as RValue<u8>>::read(&Addr { bus: bus, segment: es.read(), offset: di.read() });
|
let dst = <Addr as RValue<u8>>::read(&Addr { bus: bus, segment: es.read(), offset: di.read() });
|
||||||
|
|
||||||
cmpb(flags, &dst, &src);
|
cmp(flags, &dst, &src);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +134,7 @@ pub fn cmpsw(flags: &mut Flags,
|
|||||||
let src = <Addr as RValue<u16>>::read(&Addr { bus: bus, segment: seg, offset: si.read() });
|
let src = <Addr as RValue<u16>>::read(&Addr { bus: bus, segment: seg, offset: si.read() });
|
||||||
let dst = <Addr as RValue<u16>>::read(&Addr { bus: bus, segment: es.read(), offset: di.read() });
|
let dst = <Addr as RValue<u16>>::read(&Addr { bus: bus, segment: es.read(), offset: di.read() });
|
||||||
|
|
||||||
cmpw(flags, &dst, &src);
|
cmp(flags, &dst, &src);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,7 +234,7 @@ pub fn scasb(flags: &mut Flags,
|
|||||||
needle: &impl RValue<u8>) {
|
needle: &impl RValue<u8>) {
|
||||||
string_op!((u8, flags, rep, cx, di=di, zf=flags.zf), {
|
string_op!((u8, flags, rep, cx, di=di, zf=flags.zf), {
|
||||||
let elem = Addr { bus: bus, segment: es.read(), offset: di.read() };
|
let elem = Addr { bus: bus, segment: es.read(), offset: di.read() };
|
||||||
cmpb(flags, &elem, needle);
|
cmp(flags, &elem, needle);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +247,7 @@ pub fn scasw(flags: &mut Flags,
|
|||||||
needle: &impl RValue<u16>) {
|
needle: &impl RValue<u16>) {
|
||||||
string_op!((u16, flags, rep, cx, di=di, zf=flags.zf), {
|
string_op!((u16, flags, rep, cx, di=di, zf=flags.zf), {
|
||||||
let elem = Addr { bus: bus, segment: es.read(), offset: di.read() };
|
let elem = Addr { bus: bus, segment: es.read(), offset: di.read() };
|
||||||
cmpw(flags, &elem, needle);
|
cmp(flags, &elem, needle);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user