emu: PUSH/POP opcodes, reimpl RET as just "POP IP"
This also promotes CALL/RET to actually using the bus for addressing (because it goes through the generic PUSH/POP code), which is probably more correct anyway.
This commit is contained in:
@@ -352,6 +352,13 @@ impl i8088 {
|
||||
loop {
|
||||
step!((self, bus) =>
|
||||
opcodes: {
|
||||
0x06 => push[bus, regval=ss, reg=sp, regval=es] / 14,
|
||||
0x07 => pop[bus, regval=ss, reg=sp, reg=es] / 12,
|
||||
0x0E => push[bus, regval=ss, reg=sp, regval=cs] / 14,
|
||||
0x16 => push[bus, regval=ss, reg=sp, regval=ss] / 14,
|
||||
0x17 => pop[bus, regval=ss, reg=sp, reg=ss] / 12,
|
||||
0x1E => push[bus, regval=ss, reg=sp, regval=ds] / 14,
|
||||
0x1F => pop[bus, regval=ss, reg=sp, reg=ds] / 12,
|
||||
0x26 => nop[seg=es, prefix] / 2,
|
||||
0x2E => nop[seg=cs, prefix] / 2,
|
||||
0x36 => nop[seg=ss, prefix] / 2,
|
||||
@@ -362,6 +369,22 @@ impl i8088 {
|
||||
0x3C => cmp[flags, reglo=a, d8] / "3/24+",
|
||||
0x3D => cmp[flags, reg=a, d16] / "3/24+",
|
||||
0x3E => nop[seg=ds, prefix] / 2,
|
||||
0x50 => push[bus, regval=ss, reg=sp, regval=a] / 15,
|
||||
0x51 => push[bus, regval=ss, reg=sp, regval=c] / 15,
|
||||
0x52 => push[bus, regval=ss, reg=sp, regval=d] / 15,
|
||||
0x53 => push[bus, regval=ss, reg=sp, regval=b] / 15,
|
||||
0x54 => push[bus, regval=ss, reg=sp, regval=sp] / 15,
|
||||
0x55 => push[bus, regval=ss, reg=sp, regval=bp] / 15,
|
||||
0x56 => push[bus, regval=ss, reg=sp, regval=si] / 15,
|
||||
0x57 => push[bus, regval=ss, reg=sp, regval=di] / 15,
|
||||
0x58 => pop[bus, regval=ss, reg=sp, reg=a] / 12,
|
||||
0x59 => pop[bus, regval=ss, reg=sp, reg=c] / 12,
|
||||
0x5A => pop[bus, regval=ss, reg=sp, reg=d] / 12,
|
||||
0x5B => pop[bus, regval=ss, reg=sp, reg=b] / 12,
|
||||
0x5C => pop[bus, regval=ss, reg=sp, reg=sp] / 12,
|
||||
0x5D => pop[bus, regval=ss, reg=sp, reg=bp] / 12,
|
||||
0x5E => pop[bus, regval=ss, reg=sp, reg=si] / 12,
|
||||
0x5F => pop[bus, regval=ss, reg=sp, reg=di] / 12,
|
||||
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
|
||||
@@ -413,9 +436,9 @@ impl i8088 {
|
||||
0xBD => mov[reg=bp, d16] / 4,
|
||||
0xBE => mov[reg=si, d16] / 4,
|
||||
0xBF => mov[reg=di, d16] / 4,
|
||||
0xC3 => ret[reg=ip, regval=ss, reg=sp, mem] / 20,
|
||||
0xC3 => pop[bus, regval=ss, reg=sp, reg=ip] / 20, // RET
|
||||
0xCD => int[cpu, bus, d8] / 71,
|
||||
0xE8 => call[reg=ip, regval=ss, reg=sp, mem, rel16] / 23,
|
||||
0xE8 => call[reg=ip, bus, regval=ss, reg=sp, rel16] / 23,
|
||||
0xF2 => nop[rep=NotEqual, prefix] / 0, // REPNE/REPNZ
|
||||
0xF3 => nop[rep=Equal, prefix] / 0, // REP/REPE/REPZ
|
||||
},
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use emu::byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
use emu::dos;
|
||||
use emu::i8088::{Flags, RepPrefix, i8088};
|
||||
use emu::operands::{Addr, Address, LValue, Operand, Reg, RValue};
|
||||
use emu::pc::Bus;
|
||||
use emu::util::segoff_to_addr;
|
||||
|
||||
macro_rules! string_op {
|
||||
( ($type:ty,
|
||||
@@ -92,9 +89,9 @@ pub fn peek(addr: &(impl Address + RValue<u8>)) {
|
||||
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) {
|
||||
pub fn call(ip: &mut Reg, bus: &mut Bus, ss: u16, sp: &mut Reg, addr: i16) {
|
||||
let target = ip.read().wrapping_add(addr as u16);
|
||||
push16(ss, sp, mem, ip.read());
|
||||
push(bus, ss, sp, ip.read());
|
||||
ip.write(target);
|
||||
}
|
||||
|
||||
@@ -209,20 +206,17 @@ pub fn movsw(flags: &Flags,
|
||||
|
||||
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())..]);
|
||||
pub fn pop(bus: &mut Bus, ss: u16, sp: &mut Reg, dst: &mut Reg) {
|
||||
let ptr = Addr { bus: bus, segment: ss, offset: sp.read() };
|
||||
dst.write(ptr.read());
|
||||
sp.write(sp.read() + 2);
|
||||
val
|
||||
}
|
||||
|
||||
pub fn push16(ss: u16, sp: &mut Reg, mem: &mut [u8], val: u16) {
|
||||
pub fn push(bus: &mut Bus, ss: u16, sp: &mut Reg, 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));
|
||||
let mut ptr = Addr { bus: bus, segment: ss, offset: sp.read() };
|
||||
ptr.write(val);
|
||||
}
|
||||
|
||||
pub fn scasb(flags: &mut Flags,
|
||||
|
||||
Reference in New Issue
Block a user