From dcf96ec5b31321c87c383082777f451b2fea26c9 Mon Sep 17 00:00:00 2001 From: Jared Burce Date: Wed, 17 Mar 2021 21:38:13 -0700 Subject: [PATCH] emu: Operand trait over u8/u16, d8_as_d16 argtype --- Cargo.toml | 1 + src/emu/i8088.rs | 23 ++++++++++++-------- src/emu/mod.rs | 1 + src/emu/operands.rs | 44 +++++++++++++++++++++---------------- src/emu/operations.rs | 50 ++++++++++++++++++------------------------- 5 files changed, 63 insertions(+), 56 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ad9ad13..27b1493 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ gfx_device_gl = "0.15" image = "0.19" lzw = "0.10" nalgebra = "0.16" +num-traits = "0.2.14" openvr = "0.6.0" openvr_sys = "2" piston = "0.37" diff --git a/src/emu/i8088.rs b/src/emu/i8088.rs index 0889f19..a28d562 100644 --- a/src/emu/i8088.rs +++ b/src/emu/i8088.rs @@ -112,6 +112,11 @@ macro_rules! step { 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) => { { let d16 = i8088::next_ip16($cpu.cs.get(), &mut $cpu.ip, $bus); step!(@arg $cookie, &d16) @@ -350,20 +355,20 @@ impl i8088 { 0x26 => nop[seg=es, prefix] / 2, 0x2E => nop[seg=cs, prefix] / 2, 0x36 => nop[seg=ss, prefix] / 2, - 0x38 _ => cmpb[flags, modrm8, r8] / "3/24+", - 0x39 _ => cmpw[flags, modrm16, r16] / "3/24+", - 0x3A _ => cmpb[flags, r8, modrm8] / "3/24+", - 0x3B _ => cmpw[flags, r16, modrm16] / "3/24+", - 0x3C => cmpb[flags, reglo=a, d8] / "3/24+", - 0x3D => cmpw[flags, reg=a, d16] / "3/24+", + 0x38 _ => cmp[flags, modrm8, r8] / "3/24+", + 0x39 _ => cmp[flags, modrm16, r16] / "3/24+", + 0x3A _ => cmp[flags, r8, modrm8] / "3/24+", + 0x3B _ => cmp[flags, r16, modrm16] / "3/24+", + 0x3C => cmp[flags, reglo=a, d8] / "3/24+", + 0x3D => cmp[flags, reg=a, d16] / "3/24+", 0x3E => nop[seg=ds, prefix] / 2, 0x60 => show[cpu] / 0, // Fake opcode for debugging 0x61 => peek[seg=ds, addr] / 0, // Fake opcode for debugging 0x62 _ => assert[modrm8, d8] / 0, // Fake opcode for debugging 0x63 _ => assert[modrm16, d16] / 0, // Fake opcode for debugging - 0x80: { 0x38 => cmpb[flags, modrm8, d8] / "4/23+", }, - 0x81: { 0x38 => cmpw[flags, modrm16, d16] / "4/23+", }, - //0x83: { 0x38 => cmp?[flags, modrm16, d8] / "4/23+", }, + 0x80: { 0x38 => cmp[flags, modrm8, d8] / "4/23+", }, + 0x81: { 0x38 => cmp[flags, modrm16, d16] / "4/23+", }, + 0x83: { 0x38 => cmp[flags, modrm16, d8_as_d16] / "4/23+", }, 0x88 _ => mov[modrm8, r8] / "2/13+", 0x89 _ => mov[modrm16, r16] / "2/13+", 0x8A _ => mov[r8, modrm8] / "2/12+", diff --git a/src/emu/mod.rs b/src/emu/mod.rs index 7f6a034..8c5f47f 100644 --- a/src/emu/mod.rs +++ b/src/emu/mod.rs @@ -1,4 +1,5 @@ extern crate byteorder; +extern crate num_traits; pub mod dos; pub mod i8088; diff --git a/src/emu/operands.rs b/src/emu/operands.rs index 76b681b..4c3c253 100644 --- a/src/emu/operands.rs +++ b/src/emu/operands.rs @@ -1,9 +1,33 @@ -use emu::util::segoff_to_addr; 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; +pub trait Operand: Copy + + nt::Num + + nt::ops::overflowing::OverflowingSub + + std::ops::BitAnd + + std::ops::BitXor { + 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 { fn write(&mut self, val: T); } @@ -16,22 +40,6 @@ pub trait Address { 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 for u8 { fn read(&self) -> u8 { *self diff --git a/src/emu/operations.rs b/src/emu/operations.rs index 6df06bb..604465f 100644 --- a/src/emu/operations.rs +++ b/src/emu/operations.rs @@ -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(loc: &impl RValue, val: &impl RValue) { +pub fn assert(loc: &impl RValue, val: &impl RValue) { 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, src: &impl RValue) { +pub fn cmp(flags: &mut Flags, dst: &impl RValue, src: &impl RValue) { 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, src: &impl RValue) { - 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 = >::read(&Addr { bus: bus, segment: seg, offset: si.read() }); let dst = >::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 = >::read(&Addr { bus: bus, segment: seg, offset: si.read() }); let dst = >::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) { 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) { 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); }); }