From 27bc36f9d28e0939f4fa05a4fad4682f1ed55bd5 Mon Sep 17 00:00:00 2001 From: Jared Burce Date: Thu, 11 Mar 2021 22:55:51 -0800 Subject: [PATCH] emu: factor out operations and operands into own module --- src/emu/i8088.rs | 213 +++++++----------------------------------- src/emu/mod.rs | 2 + src/emu/operands.rs | 104 +++++++++++++++++++++ src/emu/operations.rs | 48 ++++++++++ 4 files changed, 186 insertions(+), 181 deletions(-) create mode 100644 src/emu/operands.rs create mode 100644 src/emu/operations.rs diff --git a/src/emu/i8088.rs b/src/emu/i8088.rs index ebeba2a..ffc23c3 100644 --- a/src/emu/i8088.rs +++ b/src/emu/i8088.rs @@ -3,6 +3,8 @@ use std::fmt::{Debug, Formatter}; use super::byteorder::{ByteOrder, LittleEndian}; +use emu::operands::{Addr, Reg, RegHi}; +use emu::operations as ops; use emu::pc::Bus; #[allow(non_camel_case_types)] @@ -50,156 +52,6 @@ pub struct Flags { // bits 12-15 always 1 } -mod ops { - use emu::byteorder::{ByteOrder, LittleEndian}; - use emu::dos; - use emu::i8088::{Address, Bus, LValue, Reg, RValue, i8088, segoff_to_addr}; - - pub fn show(cpu: &mut i8088) { - println!("{:#X?}", cpu); - } - - pub fn peek(addr: &(impl Address + RValue)) { - println!("PEEK: @{:#X} = {:#X} ({})", addr.addr(), addr.read(), addr.read()); - } - - pub fn call(ip: &mut Reg, ss: u16, sp: &mut Reg, mem: &mut [u8], addr: i16) { - let target = ip.read().wrapping_add(addr as u16); - push16(ss, sp, mem, ip.read()); - ip.write(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(dst: &mut impl LValue, src: &impl RValue) { - dst.write(src.read()); - } - - pub fn nop() {} - - pub fn pop16(ss: u16, sp: &mut Reg, mem: &[u8]) -> u16 { - let val = LittleEndian::read_u16(&mem[segoff_to_addr(ss.read(), sp.read())..]); - sp.write(sp.read() + 2); - val - } - - pub fn push16(ss: u16, sp: &mut Reg, mem: &mut [u8], val: u16) { - // XXX: Not checking for stack faults or anything - sp.write(sp.read() - 2); - LittleEndian::write_u16(&mut mem[segoff_to_addr(ss.read(), sp.read())..], val); - } - - pub fn ret(ip: &mut Reg, ss: u16, sp: &mut Reg, mem: &[u8]) { - ip.write(pop16(ss, sp, mem)); - } -} - -pub trait LValue { - fn write(&mut self, val: T); -} - -pub trait RValue { - fn read(&self) -> T; -} - -pub trait Address { - fn addr(&self) -> usize; -} - -impl RValue for u8 { - fn read(&self) -> u8 { - *self - } -} - -impl LValue for u16 { - fn write(&mut self, val: u16) { - *self = val; - } -} - -impl RValue for u16 { - fn read(&self) -> u16 { - *self - } -} - -pub struct Reg<'a> { - reg: &'a Cell -} - -impl LValue for Reg<'_> { - fn write(&mut self, val: u16) { - self.reg.set(val); - } -} - -impl RValue for Reg<'_> { - fn read(&self) -> u16 { - self.reg.get() - } -} - -struct RegHi<'a> { - reg: &'a Cell -} - -impl LValue for RegHi<'_> { - fn write(&mut self, val: u8) { - write_hi(&mut self.reg, val); - } -} - -impl RValue for RegHi<'_> { - fn read(&self) -> u8 { - 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 for Addr<'_> { - fn write(&mut self, val: u8) { - self.bus.write(self.addr, val); - } -} - -impl RValue for Addr<'_> { - fn read(&self) -> u8 { - self.bus.read(self.addr) - } -} - -struct RegLo<'a> { - reg: &'a Cell -} - -impl LValue for RegLo<'_> { - fn write(&mut self, val: u8) { - write_lo(&mut self.reg, val); - } -} - -impl RValue for RegLo<'_> { - fn read(&self) -> u8 { - read_lo(self.reg) - } -} - macro_rules! step { // Base case: all args processed and ready to call op (@code ( $($done:tt)* ), @@ -384,37 +236,6 @@ macro_rules! step { } } -pub const fn segoff_to_addr(segment: u16, offset: u16) -> usize { - let segaddr = (segment as usize) << 4; - segaddr + offset as usize -} - -pub fn read_hi(val: &Cell) -> u8 { - let mut buf = [0; 2]; - LittleEndian::write_u16(&mut buf, val.get()); - buf[1] as u8 -} - -pub fn read_lo(val: &Cell) -> u8 { - let mut buf = [0; 2]; - LittleEndian::write_u16(&mut buf, val.get()); - buf[0] as u8 -} - -pub fn write_hi(reg: &Cell, val: u8) { - let mut buf = [0; 2]; - LittleEndian::write_u16(&mut buf, reg.get()); - buf[1] = val; - reg.set(LittleEndian::read_u16(&buf)) -} - -pub fn write_lo(reg: &Cell, val: u8) { - let mut buf = [0; 2]; - LittleEndian::write_u16(&mut buf, reg.get()); - buf[1] = val; - reg.set(LittleEndian::read_u16(&buf)); -} - impl i8088 { pub fn run(&mut self, bus: &mut Bus) { loop { @@ -481,6 +302,36 @@ impl i8088 { } } +pub const fn segoff_to_addr(segment: u16, offset: u16) -> usize { + let segaddr = (segment as usize) << 4; + segaddr + offset as usize +} + +pub fn read_hi(val: &Cell) -> u8 { + let mut buf = [0; 2]; + LittleEndian::write_u16(&mut buf, val.get()); + buf[1] as u8 +} + +pub fn read_lo(val: &Cell) -> u8 { + let mut buf = [0; 2]; + LittleEndian::write_u16(&mut buf, val.get()); + buf[0] as u8 +} + +pub fn write_hi(reg: &Cell, val: u8) { + let mut buf = [0; 2]; + LittleEndian::write_u16(&mut buf, reg.get()); + buf[1] = val; + reg.set(LittleEndian::read_u16(&buf)) +} + +pub fn write_lo(reg: &Cell, val: u8) { + let mut buf = [0; 2]; + LittleEndian::write_u16(&mut buf, reg.get()); + buf[1] = val; + reg.set(LittleEndian::read_u16(&buf)); +} impl From for Flags { fn from(flags: u16) -> Self { diff --git a/src/emu/mod.rs b/src/emu/mod.rs index 66dbcf2..5c3d6c5 100644 --- a/src/emu/mod.rs +++ b/src/emu/mod.rs @@ -2,4 +2,6 @@ extern crate byteorder; pub mod dos; pub mod i8088; +mod operands; +mod operations; pub mod pc; diff --git a/src/emu/operands.rs b/src/emu/operands.rs new file mode 100644 index 0000000..009c446 --- /dev/null +++ b/src/emu/operands.rs @@ -0,0 +1,104 @@ +use std::cell::Cell; +use emu::i8088::{read_hi, read_lo, write_hi, write_lo}; +use emu::pc::Bus; + +pub trait LValue { + fn write(&mut self, val: T); +} + +pub trait RValue { + fn read(&self) -> T; +} + +pub trait Address { + fn addr(&self) -> usize; +} + +impl RValue for u8 { + fn read(&self) -> u8 { + *self + } +} + +impl LValue for u16 { + fn write(&mut self, val: u16) { + *self = val; + } +} + +impl RValue for u16 { + fn read(&self) -> u16 { + *self + } +} + +pub struct Addr<'a> { + pub bus: &'a mut Bus, + pub addr: usize +} + +impl Address for Addr<'_> { + fn addr(&self) -> usize { + self.addr + } +} + +impl LValue for Addr<'_> { + fn write(&mut self, val: u8) { + self.bus.write(self.addr, val); + } +} + +impl RValue for Addr<'_> { + fn read(&self) -> u8 { + self.bus.read(self.addr) + } +} + +pub struct Reg<'a> { + pub reg: &'a Cell +} + +impl LValue for Reg<'_> { + fn write(&mut self, val: u16) { + self.reg.set(val); + } +} + +impl RValue for Reg<'_> { + fn read(&self) -> u16 { + self.reg.get() + } +} + +pub struct RegHi<'a> { + pub reg: &'a Cell +} + +impl LValue for RegHi<'_> { + fn write(&mut self, val: u8) { + write_hi(&mut self.reg, val); + } +} + +impl RValue for RegHi<'_> { + fn read(&self) -> u8 { + read_hi(self.reg) + } +} + +pub struct RegLo<'a> { + pub reg: &'a Cell +} + +impl LValue for RegLo<'_> { + fn write(&mut self, val: u8) { + write_lo(&mut self.reg, val); + } +} + +impl RValue for RegLo<'_> { + fn read(&self) -> u8 { + read_lo(self.reg) + } +} diff --git a/src/emu/operations.rs b/src/emu/operations.rs new file mode 100644 index 0000000..ebf7112 --- /dev/null +++ b/src/emu/operations.rs @@ -0,0 +1,48 @@ +use emu::byteorder::{ByteOrder, LittleEndian}; +use emu::dos; +use emu::i8088::{i8088, segoff_to_addr}; +use emu::operands::{Address, LValue, Reg, RValue}; +use emu::pc::Bus; + +pub fn show(cpu: &mut i8088) { + println!("{:#X?}", cpu); +} + +pub fn peek(addr: &(impl Address + RValue)) { + println!("PEEK: @{:#X} = {:#X} ({})", addr.addr(), addr.read(), addr.read()); +} + +pub fn call(ip: &mut Reg, ss: u16, sp: &mut Reg, mem: &mut [u8], addr: i16) { + let target = ip.read().wrapping_add(addr as u16); + push16(ss, sp, mem, ip.read()); + ip.write(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(dst: &mut impl LValue, src: &impl RValue) { + dst.write(src.read()); +} + +pub fn nop() {} + +pub fn pop16(ss: u16, sp: &mut Reg, mem: &[u8]) -> u16 { + let val = LittleEndian::read_u16(&mem[segoff_to_addr(ss.read(), sp.read())..]); + sp.write(sp.read() + 2); + val +} + +pub fn push16(ss: u16, sp: &mut Reg, mem: &mut [u8], val: u16) { + // XXX: Not checking for stack faults or anything + sp.write(sp.read() - 2); + LittleEndian::write_u16(&mut mem[segoff_to_addr(ss.read(), sp.read())..], val); +} + +pub fn ret(ip: &mut Reg, ss: u16, sp: &mut Reg, mem: &[u8]) { + ip.write(pop16(ss, sp, mem)); +}