emu: Operand trait over u8/u16, d8_as_d16 argtype
This commit is contained in:
@@ -4,7 +4,7 @@ use emu::byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
use emu::dos;
|
||||
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::util::segoff_to_addr;
|
||||
|
||||
@@ -55,30 +55,30 @@ macro_rules! string_op {
|
||||
// Decide if this can realistically be generalized
|
||||
macro_rules! update_flags {
|
||||
// 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 */ };
|
||||
(@cf $flags:expr, $dst:ident, $carry:ident) => { $flags.cf = $carry };
|
||||
(@of $flags:expr, $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 */ };
|
||||
(@sf $flags:expr, $dst:ident, $carry:ident) => { $flags.sf = $dst.hi_bit(); };
|
||||
(@zf $flags:expr, $dst:ident, $carry:ident) => { $flags.zf = $dst == 0; };
|
||||
(@af $flags:expr, $t:ty, $dst:ident, $carry:ident) => { /* XXX: Adjust/AuxCarry esoteric? (mostly for BCD?), might not need */ };
|
||||
(@cf $flags:expr, $t:ty, $dst:ident, $carry:ident) => { $flags.cf = $carry };
|
||||
(@of $flags:expr, $t:ty, $dst:ident, $carry:ident) => { compile_error!("compute flags.of outside macro"); };
|
||||
(@pf $flags:expr, $t:ty, $dst:ident, $carry:ident) => { /* XXX: parity looks esoteric, might not need */ };
|
||||
(@sf $flags:expr, $t:ty, $dst:ident, $carry:ident) => { $flags.sf = $dst.hi_bit(); };
|
||||
(@zf $flags:expr, $t:ty, $dst:ident, $carry:ident) => { $flags.zf = $dst == <$t>::zero(); };
|
||||
|
||||
// Recursive step
|
||||
(@recur $flags:expr, $dst:ident, $carry:ident, $next:ident $(, $rest:ident)* ) => {
|
||||
update_flags!(@$next $flags, $dst, $carry);
|
||||
update_flags!(@recur $flags, $dst, $carry $(, $rest)*);
|
||||
(@recur $flags:expr, $t:ty, $dst:ident, $carry:ident, $next:ident $(, $rest:ident)* ) => {
|
||||
update_flags!(@$next $flags, $t, $dst, $carry);
|
||||
update_flags!(@recur $flags, $t, $dst, $carry $(, $rest)*);
|
||||
};
|
||||
|
||||
// Entry Point
|
||||
($flags:expr, $eval:expr $(, $flagnames:ident)* ) => { {
|
||||
($flags:expr, $t:ty, $eval:expr $(, $flagnames:ident)* ) => { {
|
||||
let (dst, carry) = $eval;
|
||||
update_flags!(@recur $flags, dst, carry $(, $flagnames)*);
|
||||
update_flags!(@recur $flags, $t, dst, carry $(, $flagnames)*);
|
||||
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 instruction failed: {:#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);
|
||||
}
|
||||
|
||||
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 after = update_flags!(flags, dst.overflowing_sub(src), af, cf, pf, sf, zf);
|
||||
flags.of = 0 != 0x80 & // In the 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...
|
||||
let after = update_flags!(flags, T, dst.overflowing_sub(&src), af, cf, pf, sf, zf);
|
||||
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
|
||||
}
|
||||
@@ -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 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 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>) {
|
||||
string_op!((u8, flags, rep, cx, di=di, zf=flags.zf), {
|
||||
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>) {
|
||||
string_op!((u16, flags, rep, cx, di=di, zf=flags.zf), {
|
||||
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