emu: wrap cpu regs in Cell. r16 addr mode.
r16 + modrm16 allowed cpu regs to alias. Wrap them in Cell to allow this. We also create a Reg wrapper when passing regs so that we can pass as &mut while simultaneously having other references to the same reg.
This commit is contained in:
@@ -2,16 +2,16 @@ use emu::pc::Bus;
|
|||||||
use emu::i8088::{i8088, read_hi, read_lo, segoff_to_addr};
|
use emu::i8088::{i8088, read_hi, read_lo, segoff_to_addr};
|
||||||
|
|
||||||
pub fn interrupt(cpu: &mut i8088, bus: &mut Bus) {
|
pub fn interrupt(cpu: &mut i8088, bus: &mut Bus) {
|
||||||
let svc = read_hi(cpu.a);
|
let svc = read_hi(&cpu.a);
|
||||||
match svc {
|
match svc {
|
||||||
0x09 => print_string(cpu, bus),
|
0x09 => print_string(cpu, bus),
|
||||||
0x4C => exit(read_lo(cpu.a)),
|
0x4C => exit(read_lo(&cpu.a)),
|
||||||
_ => unimplemented!("dos service: AH={:02X}h\ncpu: {:#X?}", svc, cpu)
|
_ => unimplemented!("dos service: AH={:02X}h\ncpu: {:#X?}", svc, cpu)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_string(cpu: &i8088, bus: &Bus) {
|
fn print_string(cpu: &i8088, bus: &Bus) {
|
||||||
let addr = segoff_to_addr(cpu.ds, cpu.d);
|
let addr = segoff_to_addr(cpu.ds.get(), cpu.d.get());
|
||||||
for byte in bus.ram[addr..].iter().take_while(|byte| **byte as char != '$') {
|
for byte in bus.ram[addr..].iter().take_while(|byte| **byte as char != '$') {
|
||||||
print!("{}", *byte as char);
|
print!("{}", *byte as char);
|
||||||
}
|
}
|
||||||
|
|||||||
172
src/emu/i8088.rs
172
src/emu/i8088.rs
@@ -1,3 +1,4 @@
|
|||||||
|
use std::cell::Cell;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
|
|
||||||
use super::byteorder::{ByteOrder, LittleEndian};
|
use super::byteorder::{ByteOrder, LittleEndian};
|
||||||
@@ -5,28 +6,28 @@ use super::byteorder::{ByteOrder, LittleEndian};
|
|||||||
use emu::pc::Bus;
|
use emu::pc::Bus;
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct i8088 {
|
pub struct i8088 {
|
||||||
// Data Registers
|
// Data Registers
|
||||||
pub a: u16,
|
pub a: Cell<u16>,
|
||||||
pub b: u16,
|
pub b: Cell<u16>,
|
||||||
pub c: u16,
|
pub c: Cell<u16>,
|
||||||
pub d: u16,
|
pub d: Cell<u16>,
|
||||||
|
|
||||||
// Index Registers
|
// Index Registers
|
||||||
pub si: u16, // Source Index
|
pub si: Cell<u16>, // Source Index
|
||||||
pub di: u16, // Dest Index
|
pub di: Cell<u16>, // Dest Index
|
||||||
pub bp: u16, // Base Pointer
|
pub bp: Cell<u16>, // Base Pointer
|
||||||
pub sp: u16, // Stack Pointer
|
pub sp: Cell<u16>, // Stack Pointer
|
||||||
|
|
||||||
// Segment Registers
|
// Segment Registers
|
||||||
pub cs: u16, // Code Segment
|
pub cs: Cell<u16>, // Code Segment
|
||||||
pub ds: u16, // Data Segment
|
pub ds: Cell<u16>, // Data Segment
|
||||||
pub es: u16, // Extra Segment
|
pub es: Cell<u16>, // Extra Segment
|
||||||
pub ss: u16, // Stack Segment
|
pub ss: Cell<u16>, // Stack Segment
|
||||||
|
|
||||||
// Pointer Register
|
// Pointer Register
|
||||||
pub ip: u16,
|
pub ip: Cell<u16>,
|
||||||
|
|
||||||
// Status Register
|
// Status Register
|
||||||
pub flags: Flags,
|
pub flags: Flags,
|
||||||
@@ -52,22 +53,22 @@ 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, RValue, i8088, segoff_to_addr};
|
use emu::i8088::{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(cpu: &mut i8088, bus: &mut Bus, addr: &u16) {
|
||||||
let addr = segoff_to_addr(cpu.ds, *addr);
|
let addr = segoff_to_addr(cpu.ds.get(), *addr);
|
||||||
let val = bus.ram[addr];
|
let val = bus.ram[addr];
|
||||||
println!("PEEK: @{:#X} = {:#X} ({})", addr, val, val);
|
println!("PEEK: @{:#X} = {:#X} ({})", addr, val, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call(ip: &mut u16, ss: u16, sp: &mut u16, mem: &mut [u8], addr: i16) {
|
pub fn call(ip: &mut Reg, ss: u16, sp: &mut Reg, mem: &mut [u8], addr: i16) {
|
||||||
let target = ip.wrapping_add(addr as u16);
|
let target = ip.read().wrapping_add(addr as u16);
|
||||||
push16(ss, sp, mem, *ip);
|
push16(ss, sp, mem, ip.read());
|
||||||
*ip = target;
|
ip.write(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn int(cpu: &mut i8088, bus: &mut Bus, num: &u8) {
|
pub fn int(cpu: &mut i8088, bus: &mut Bus, num: &u8) {
|
||||||
@@ -81,20 +82,20 @@ mod ops {
|
|||||||
dst.write(src.read());
|
dst.write(src.read());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop16(ss: u16, sp: &mut u16, mem: &[u8]) -> u16 {
|
pub fn pop16(ss: u16, sp: &mut Reg, mem: &[u8]) -> u16 {
|
||||||
let val = LittleEndian::read_u16(&mem[segoff_to_addr(ss, *sp)..]);
|
let val = LittleEndian::read_u16(&mem[segoff_to_addr(ss.read(), sp.read())..]);
|
||||||
*sp += 2;
|
sp.write(sp.read() + 2);
|
||||||
val
|
val
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push16(ss: u16, sp: &mut u16, mem: &mut [u8], val: u16) {
|
pub fn push16(ss: u16, sp: &mut Reg, mem: &mut [u8], val: u16) {
|
||||||
// XXX: Not checking for stack faults or anything
|
// XXX: Not checking for stack faults or anything
|
||||||
*sp -= 2;
|
sp.write(sp.read() - 2);
|
||||||
LittleEndian::write_u16(&mut mem[segoff_to_addr(ss, *sp)..], val);
|
LittleEndian::write_u16(&mut mem[segoff_to_addr(ss.read(), sp.read())..], val);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ret(ip: &mut u16, ss: u16, sp: &mut u16, mem: &[u8]) {
|
pub fn ret(ip: &mut Reg, ss: u16, sp: &mut Reg, mem: &[u8]) {
|
||||||
*ip = pop16(ss, sp, mem);
|
ip.write(pop16(ss, sp, mem));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,8 +125,24 @@ impl RValue<u16> for u16 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Reg<'a> {
|
||||||
|
reg: &'a Cell<u16>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LValue<u16> for Reg<'a> {
|
||||||
|
fn write(&mut self, val: u16) {
|
||||||
|
self.reg.set(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> RValue<u16> for Reg<'a> {
|
||||||
|
fn read(&self) -> u16 {
|
||||||
|
self.reg.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct RegHi<'a> {
|
struct RegHi<'a> {
|
||||||
reg: &'a mut u16
|
reg: &'a Cell<u16>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LValue<u8> for RegHi<'a> {
|
impl<'a> LValue<u8> for RegHi<'a> {
|
||||||
@@ -136,12 +153,12 @@ impl<'a> LValue<u8> for RegHi<'a> {
|
|||||||
|
|
||||||
impl<'a> RValue<u8> for RegHi<'a> {
|
impl<'a> RValue<u8> for RegHi<'a> {
|
||||||
fn read(&self) -> u8 {
|
fn read(&self) -> u8 {
|
||||||
read_hi(*self.reg)
|
read_hi(self.reg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RegLo<'a> {
|
struct RegLo<'a> {
|
||||||
reg: &'a mut u16
|
reg: &'a Cell<u16>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LValue<u8> for RegLo<'a> {
|
impl<'a> LValue<u8> for RegLo<'a> {
|
||||||
@@ -152,7 +169,7 @@ impl<'a> LValue<u8> for RegLo<'a> {
|
|||||||
|
|
||||||
impl<'a> RValue<u8> for RegLo<'a> {
|
impl<'a> RValue<u8> for RegLo<'a> {
|
||||||
fn read(&self) -> u8 {
|
fn read(&self) -> u8 {
|
||||||
read_lo(*self.reg)
|
read_lo(self.reg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,14 +213,14 @@ macro_rules! step {
|
|||||||
} };
|
} };
|
||||||
|
|
||||||
(@d8 $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => { {
|
(@d8 $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => { {
|
||||||
let d8 = i8088::next_ip($cpu.cs, &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, $modrm:tt) => { {
|
||||||
let mut buf = [0; 2];
|
let mut buf = [0; 2];
|
||||||
buf[0] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
|
buf[0] = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus);
|
||||||
buf[1] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
|
buf[1] = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus);
|
||||||
step!(@arg $cookie, &LittleEndian::read_u16(&buf))
|
step!(@arg $cookie, &LittleEndian::read_u16(&buf))
|
||||||
} };
|
} };
|
||||||
|
|
||||||
@@ -220,57 +237,56 @@ macro_rules! step {
|
|||||||
}
|
}
|
||||||
} };
|
} };
|
||||||
|
|
||||||
(@r16 $cookie:tt, $cpu:expr, $bus:expr, ($modrm:ident, $modrm16:tt, $modrm8:tt)) => { {
|
(@r16 $cookie:tt, $cpu:expr, $bus:expr, ($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?
|
||||||
let reg = match $modrm >> 3 & 0x7 {
|
match $modrm >> 3 & 0x7 {
|
||||||
0 => &mut $cpu.a,
|
0 => step!(@arg $cookie, &mut Reg { reg: &$cpu.a } ),
|
||||||
1 => &mut $cpu.c,
|
1 => step!(@arg $cookie, &mut Reg { reg: &$cpu.c } ),
|
||||||
2 => &mut $cpu.d,
|
2 => step!(@arg $cookie, &mut Reg { reg: &$cpu.d } ),
|
||||||
3 => &mut $cpu.b,
|
3 => step!(@arg $cookie, &mut Reg { reg: &$cpu.b } ),
|
||||||
4 => &mut $cpu.sp,
|
4 => step!(@arg $cookie, &mut Reg { reg: &$cpu.sp } ),
|
||||||
5 => &mut $cpu.bp,
|
5 => step!(@arg $cookie, &mut Reg { reg: &$cpu.bp } ),
|
||||||
6 => &mut $cpu.si,
|
6 => step!(@arg $cookie, &mut Reg { reg: &$cpu.si } ),
|
||||||
7 => &mut $cpu.di,
|
7 => step!(@arg $cookie, &mut Reg { reg: &$cpu.di } ),
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
};
|
};
|
||||||
step!(@arg $cookie, reg)
|
};
|
||||||
} };
|
|
||||||
|
|
||||||
(@r8 $cookie:tt, $cpu:expr, $bus:expr, ($modrm:ident, $modrm16:tt, $modrm8:tt)) => {
|
(@r8 $cookie:tt, $cpu:expr, $bus:expr, ($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: &mut $cpu.a } ),
|
0 => step!(@arg $cookie, &mut RegHi { reg: &$cpu.a } ),
|
||||||
1 => step!(@arg $cookie, &mut RegHi { reg: &mut $cpu.c } ),
|
1 => step!(@arg $cookie, &mut RegHi { reg: &$cpu.c } ),
|
||||||
2 => step!(@arg $cookie, &mut RegHi { reg: &mut $cpu.d } ) ,
|
2 => step!(@arg $cookie, &mut RegHi { reg: &$cpu.d } ),
|
||||||
3 => step!(@arg $cookie, &mut RegHi { reg: &mut $cpu.b } ),
|
3 => step!(@arg $cookie, &mut RegHi { reg: &$cpu.b } ),
|
||||||
4 => step!(@arg $cookie, &mut RegLo { reg: &mut $cpu.a } ),
|
4 => step!(@arg $cookie, &mut RegLo { reg: &$cpu.a } ),
|
||||||
5 => step!(@arg $cookie, &mut RegLo { reg: &mut $cpu.c } ),
|
5 => step!(@arg $cookie, &mut RegLo { reg: &$cpu.c } ),
|
||||||
6 => step!(@arg $cookie, &mut RegLo { reg: &mut $cpu.d } ),
|
6 => step!(@arg $cookie, &mut RegLo { reg: &$cpu.d } ),
|
||||||
7 => step!(@arg $cookie, &mut RegLo { reg: &mut $cpu.b } ),
|
7 => step!(@arg $cookie, &mut RegLo { reg: &$cpu.b } ),
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
(@reg=$reg:ident $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => {
|
(@reg=$reg:ident $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => {
|
||||||
step!(@arg $cookie, &mut $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, $modrm:tt) => {
|
||||||
step!(@arg $cookie, &mut RegHi { reg: &mut $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, $modrm:tt) => {
|
||||||
step!(@arg $cookie, &mut RegLo { reg: &mut $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, $modrm:tt) => {
|
||||||
step!(@arg $cookie, $cpu.$reg);
|
step!(@arg $cookie, $cpu.$reg.get());
|
||||||
};
|
};
|
||||||
|
|
||||||
(@rel16 $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => { {
|
(@rel16 $cookie:tt, $cpu:expr, $bus:expr, $modrm:tt) => { {
|
||||||
let mut buf = [0; 2];
|
let mut buf = [0; 2];
|
||||||
buf[0] = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
|
buf[0] = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus);
|
||||||
buf[1] = i8088::next_ip($cpu.cs, &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))
|
||||||
} };
|
} };
|
||||||
|
|
||||||
@@ -303,17 +319,17 @@ macro_rules! step {
|
|||||||
modrm8: $modrm8:tt
|
modrm8: $modrm8:tt
|
||||||
) => {
|
) => {
|
||||||
{
|
{
|
||||||
let opcode = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
|
let opcode = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus);
|
||||||
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) {
|
match(opcode) {
|
||||||
$( $( $code => {
|
$( $( $code => {
|
||||||
$( let $ext = (); /* No-op just to trigger expansion. */
|
$( let $ext = (); /* No-op just to trigger expansion. */
|
||||||
modrm = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus); )?
|
modrm = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus); )?
|
||||||
step!(@code (), $cpu, $bus, (modrm, $modrm16, $modrm8), $name, $cycles, ($($args $(= $argrhs)?)*))
|
step!(@code (), $cpu, $bus, (modrm, $modrm16, $modrm8), $name, $cycles, ($($args $(= $argrhs)?)*))
|
||||||
}
|
}
|
||||||
)?
|
)?
|
||||||
$( $code => {
|
$( $code => {
|
||||||
modrm = i8088::next_ip($cpu.cs, &mut $cpu.ip, $bus);
|
modrm = i8088::next_ip($cpu.cs.get(), &mut $cpu.ip, $bus);
|
||||||
step!(@group $cpu, $bus, (modrm, $modrm16, $modrm8), $code, $subcodes)
|
step!(@group $cpu, $bus, (modrm, $modrm16, $modrm8), $code, $subcodes)
|
||||||
}
|
}
|
||||||
)?
|
)?
|
||||||
@@ -329,30 +345,30 @@ pub const fn segoff_to_addr(segment: u16, offset: u16) -> usize {
|
|||||||
segaddr + offset as usize
|
segaddr + offset as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_hi(val: u16) -> u8 {
|
pub fn read_hi(val: &Cell<u16>) -> u8 {
|
||||||
let mut buf = [0; 2];
|
let mut buf = [0; 2];
|
||||||
LittleEndian::write_u16(&mut buf, val);
|
LittleEndian::write_u16(&mut buf, val.get());
|
||||||
buf[1] as u8
|
buf[1] as u8
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_lo(val: u16) -> u8 {
|
pub fn read_lo(val: &Cell<u16>) -> u8 {
|
||||||
let mut buf = [0; 2];
|
let mut buf = [0; 2];
|
||||||
LittleEndian::write_u16(&mut buf, val);
|
LittleEndian::write_u16(&mut buf, val.get());
|
||||||
buf[0] as u8
|
buf[0] as u8
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_hi(reg: &mut u16, val: u8) {
|
pub fn write_hi(reg: &Cell<u16>, val: u8) {
|
||||||
let mut buf = [0; 2];
|
let mut buf = [0; 2];
|
||||||
LittleEndian::write_u16(&mut buf, *reg);
|
LittleEndian::write_u16(&mut buf, reg.get());
|
||||||
buf[1] = val;
|
buf[1] = val;
|
||||||
*reg = LittleEndian::read_u16(&buf);
|
reg.set(LittleEndian::read_u16(&buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_lo(reg: &mut u16, val: u8) {
|
pub fn write_lo(reg: &Cell<u16>, val: u8) {
|
||||||
let mut buf = [0; 2];
|
let mut buf = [0; 2];
|
||||||
LittleEndian::write_u16(&mut buf, *reg);
|
LittleEndian::write_u16(&mut buf, reg.get());
|
||||||
buf[1] = val;
|
buf[1] = val;
|
||||||
*reg = LittleEndian::read_u16(&buf);
|
reg.set(LittleEndian::read_u16(&buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
impl i8088 {
|
impl i8088 {
|
||||||
@@ -362,7 +378,7 @@ impl i8088 {
|
|||||||
opcodes: {
|
opcodes: {
|
||||||
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[cpu, bus, d16] / 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+", },
|
||||||
0xB4 => mov[reghi=a, d8] / 4,
|
0xB4 => mov[reghi=a, d8] / 4,
|
||||||
@@ -394,9 +410,9 @@ impl i8088 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_ip<'a>(cs: u16, ip: &mut u16, bus: &Bus) -> u8 {
|
fn next_ip<'a>(cs: u16, ip: &mut Cell<u16>, bus: &Bus) -> u8 {
|
||||||
let eip = segoff_to_addr(cs, *ip);
|
let eip = segoff_to_addr(cs, ip.get());
|
||||||
*ip += 1;
|
ip.set(ip.get() + 1);
|
||||||
|
|
||||||
// We'll assume cpu is always executing in RAM. Also assume the
|
// 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
|
// IP doesn't reach the end of the segment (My guess is that it
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use std::cell::Cell;
|
||||||
use emu::i8088::{i8088, segoff_to_addr};
|
use emu::i8088::{i8088, segoff_to_addr};
|
||||||
|
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
@@ -32,12 +33,12 @@ impl PC {
|
|||||||
"No memory for loading COM file");
|
"No memory for loading COM file");
|
||||||
|
|
||||||
let mut pc = PC {
|
let mut pc = PC {
|
||||||
cpu: { i8088 { cs: LOAD_SEGMENT, // COMs always uses Tiny memory model
|
cpu: { i8088 { cs: Cell::new(LOAD_SEGMENT), // COMs always uses Tiny memory model
|
||||||
ds: LOAD_SEGMENT, // COMs always uses Tiny memory model
|
ds: Cell::new(LOAD_SEGMENT), // COMs always uses Tiny memory model
|
||||||
es: LOAD_SEGMENT, // COMs always uses Tiny memory model
|
es: Cell::new(LOAD_SEGMENT), // COMs always uses Tiny memory model
|
||||||
ss: LOAD_SEGMENT, // COMs always uses Tiny memory model
|
ss: Cell::new(LOAD_SEGMENT), // COMs always uses Tiny memory model
|
||||||
sp: 0xFFFE,
|
sp: Cell::new(0xFFFE),
|
||||||
ip: LOAD_OFFSET,
|
ip: Cell::new(LOAD_OFFSET),
|
||||||
..i8088::default() } },
|
..i8088::default() } },
|
||||||
bus: Bus { ram: [0; RAM_SIZE] }
|
bus: Bus { ram: [0; RAM_SIZE] }
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user