use alloc::vec::Vec;
use crate::core::space::{AddressSpace, MemAttrs};
use crate::core::value::Width;
use super::isa::{self, Arg, Fields, Op, Rep, seg};
use super::{Config, Lines, Model, Regs, flags, linear};
const BUS_CLOCKS: u32 = 4;
const RESET_CLOCKS: u32 = 7;
const VEC_DIVIDE: u8 = 0;
const VEC_SINGLE_STEP: u8 = 1;
const VEC_NMI: u8 = 2;
const VEC_BREAKPOINT: u8 = 3;
const VEC_OVERFLOW: u8 = 4;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) struct Queue {
bytes: [u8; 6],
len: u8,
depth: u8,
}
impl Queue {
pub(super) const fn new(model: Model) -> Queue {
Queue {
bytes: [0; 6],
len: 0,
depth: model.queue_bytes(),
}
}
pub(super) const fn flush(&mut self) {
self.len = 0;
}
pub(super) const fn len(&self) -> u8 {
self.len
}
pub(super) const fn depth(&self) -> u8 {
self.depth
}
fn push(&mut self, byte: u8) {
if self.len < self.depth {
self.bytes[self.len as usize] = byte;
self.len += 1;
}
}
fn pop(&mut self) -> Option<u8> {
if self.len == 0 {
return None;
}
let byte = self.bytes[0];
let mut i = 1usize;
while i < self.len as usize {
self.bytes[i - 1] = self.bytes[i];
i += 1;
}
self.len -= 1;
Some(byte)
}
pub(super) fn contents(&self) -> Vec<u8> {
self.bytes[..self.len as usize].to_vec()
}
pub(super) fn install(&mut self, bytes: &[u8]) -> Result<(), ()> {
if bytes.len() > self.depth as usize {
return Err(());
}
self.len = bytes.len() as u8;
self.bytes[..bytes.len()].copy_from_slice(bytes);
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) struct State {
pub regs: Regs,
pub cycles: u64,
pub halted: bool,
pub reset_pending: bool,
pub int_shadow: bool,
pub queue: Queue,
pub open_bus: u8,
pub faults: u64,
pub last_fault: u32,
}
impl State {
pub(super) const fn new(model: Model) -> State {
State {
regs: Regs::new(),
cycles: 0,
halted: false,
reset_pending: true,
int_shadow: false,
queue: Queue::new(model),
open_bus: 0,
faults: 0,
last_fault: 0,
}
}
}
pub(super) struct Exec<'a> {
state: &'a mut State,
mem: &'a AddressSpace,
io: Option<&'a AddressSpace>,
cfg: &'a Config,
lines: &'a Lines,
attrs: MemAttrs,
ea: Option<(u8, u16)>,
start_ip: u16,
used: u64,
}
impl<'a> Exec<'a> {
pub(super) fn new(
state: &'a mut State,
mem: &'a AddressSpace,
io: Option<&'a AddressSpace>,
cfg: &'a Config,
lines: &'a Lines,
) -> Exec<'a> {
let attrs = MemAttrs::DEFAULT.with_requester(cfg.requester);
Exec {
state,
mem,
io,
cfg,
lines,
attrs,
ea: None,
start_ip: 0,
used: 0,
}
}
pub(super) fn step(&mut self) -> u64 {
if self.state.reset_pending {
self.reset_sequence();
return self.used;
}
let shadow = self.state.int_shadow;
if !shadow {
if self.lines.take_nmi_pending() {
self.state.halted = false;
self.charge(Op::INT.clocks());
self.service(VEC_NMI);
return self.used;
}
if self.flag(flags::IF) && self.lines.intr_pending() {
self.state.halted = false;
self.charge(2 * BUS_CLOCKS + Op::INT.clocks());
let vector = self.lines.intr_vector();
self.service(vector);
return self.used;
}
}
if self.state.halted {
return 0;
}
let trap = self.flag(flags::TF) && !shadow;
self.state.int_shadow = false;
self.instruction();
if trap && !self.state.int_shadow {
self.charge(Op::INT.clocks());
self.service(VEC_SINGLE_STEP);
}
self.used
}
fn charge(&mut self, clocks: u32) {
let clocks = u64::from(clocks);
self.used += clocks;
self.state.cycles = self.state.cycles.wrapping_add(clocks);
}
fn bus_read8(&mut self, addr: u32) -> u8 {
self.charge(BUS_CLOCKS);
match self.mem.read(u64::from(addr), Width::U8, self.attrs) {
Ok(value) => {
let byte = value as u8;
self.state.open_bus = byte;
byte
}
Err(_) => {
self.state.faults = self.state.faults.wrapping_add(1);
self.state.last_fault = addr;
self.state.open_bus
}
}
}
fn bus_write8(&mut self, addr: u32, value: u8) {
self.charge(BUS_CLOCKS);
self.state.open_bus = value;
if self
.mem
.write(u64::from(addr), Width::U8, u64::from(value), self.attrs)
.is_err()
{
self.state.faults = self.state.faults.wrapping_add(1);
self.state.last_fault = addr;
}
}
fn word_is_one_cycle(&self, base: u32, offset: u16) -> bool {
self.cfg.model.bus_bytes() == 2 && base.is_multiple_of(2) && offset != 0xffff
}
fn read16_seg(&mut self, segment: u16, offset: u16) -> u16 {
let base = linear(segment, offset);
if self.word_is_one_cycle(base, offset) {
self.charge(BUS_CLOCKS);
return match self.mem.read(u64::from(base), Width::U16, self.attrs) {
Ok(value) => {
self.state.open_bus = (value >> 8) as u8;
value as u16
}
Err(_) => {
self.state.faults = self.state.faults.wrapping_add(1);
self.state.last_fault = base;
let byte = u16::from(self.state.open_bus);
byte | (byte << 8)
}
};
}
let lo = self.bus_read8(base);
let hi = self.bus_read8(linear(segment, offset.wrapping_add(1)));
u16::from(lo) | (u16::from(hi) << 8)
}
fn write16_seg(&mut self, segment: u16, offset: u16, value: u16) {
let base = linear(segment, offset);
if self.word_is_one_cycle(base, offset) {
self.charge(BUS_CLOCKS);
self.state.open_bus = (value >> 8) as u8;
if self
.mem
.write(u64::from(base), Width::U16, u64::from(value), self.attrs)
.is_err()
{
self.state.faults = self.state.faults.wrapping_add(1);
self.state.last_fault = base;
}
return;
}
self.bus_write8(base, value as u8);
self.bus_write8(linear(segment, offset.wrapping_add(1)), (value >> 8) as u8);
}
fn read8(&mut self, sr: u8, offset: u16) -> u8 {
let segment = self.state.regs.segment(sr);
self.bus_read8(linear(segment, offset))
}
fn write8(&mut self, sr: u8, offset: u16, value: u8) {
let segment = self.state.regs.segment(sr);
self.bus_write8(linear(segment, offset), value);
}
fn read16(&mut self, sr: u8, offset: u16) -> u16 {
let segment = self.state.regs.segment(sr);
self.read16_seg(segment, offset)
}
fn write16(&mut self, sr: u8, offset: u16, value: u16) {
let segment = self.state.regs.segment(sr);
self.write16_seg(segment, offset, value);
}
fn io_read8(&mut self, port: u16) -> u8 {
self.charge(BUS_CLOCKS);
let Some(io) = self.io else {
return 0xff;
};
match io.read(u64::from(port), Width::U8, self.attrs) {
Ok(value) => value as u8,
Err(_) => {
self.state.faults = self.state.faults.wrapping_add(1);
self.state.last_fault = u32::from(port);
0xff
}
}
}
fn io_write8(&mut self, port: u16, value: u8) {
self.charge(BUS_CLOCKS);
let Some(io) = self.io else {
return;
};
if io
.write(u64::from(port), Width::U8, u64::from(value), self.attrs)
.is_err()
{
self.state.faults = self.state.faults.wrapping_add(1);
self.state.last_fault = u32::from(port);
}
}
fn fill_queue(&mut self) {
while self.state.queue.len() < self.state.queue.depth() {
let offset = self
.state
.regs
.ip
.wrapping_add(u16::from(self.state.queue.len()));
let byte = self.read8(seg::CS, offset);
self.state.queue.push(byte);
}
}
fn fetch_byte(&mut self) -> u8 {
if self.state.queue.len() == 0 {
let offset = self.state.regs.ip;
let byte = self.read8(seg::CS, offset);
self.state.queue.push(byte);
}
let byte = self.state.queue.pop().unwrap_or(self.state.open_bus);
self.state.regs.ip = self.state.regs.ip.wrapping_add(1);
byte
}
fn flag(&self, mask: u16) -> bool {
self.state.regs.flags & mask != 0
}
fn set_flag(&mut self, mask: u16, on: bool) {
if on {
self.state.regs.flags |= mask;
} else {
self.state.regs.flags &= !mask;
}
}
const fn parity(value: u8) -> bool {
(value.count_ones() & 1) == 0
}
fn set_szp8(&mut self, value: u8) {
self.set_flag(flags::ZF, value == 0);
self.set_flag(flags::SF, value & 0x80 != 0);
self.set_flag(flags::PF, Self::parity(value));
}
fn set_szp16(&mut self, value: u16) {
self.set_flag(flags::ZF, value == 0);
self.set_flag(flags::SF, value & 0x8000 != 0);
self.set_flag(flags::PF, Self::parity(value as u8));
}
fn add8(&mut self, a: u8, b: u8, carry: bool) -> u8 {
let sum = u16::from(a) + u16::from(b) + u16::from(carry);
let r = sum as u8;
self.set_flag(flags::CF, sum > 0xff);
self.set_flag(flags::AF, (a ^ b ^ r) & 0x10 != 0);
self.set_flag(flags::OF, (!(a ^ b)) & (a ^ r) & 0x80 != 0);
self.set_szp8(r);
r
}
fn add16(&mut self, a: u16, b: u16, carry: bool) -> u16 {
let sum = u32::from(a) + u32::from(b) + u32::from(carry);
let r = sum as u16;
self.set_flag(flags::CF, sum > 0xffff);
self.set_flag(flags::AF, (a ^ b ^ r) & 0x10 != 0);
self.set_flag(flags::OF, (!(a ^ b)) & (a ^ r) & 0x8000 != 0);
self.set_szp16(r);
r
}
fn sub8(&mut self, a: u8, b: u8, borrow: bool) -> u8 {
let rhs = u16::from(b) + u16::from(borrow);
let diff = u16::from(a).wrapping_sub(rhs);
let r = diff as u8;
self.set_flag(flags::CF, u16::from(a) < rhs);
self.set_flag(flags::AF, (a ^ b ^ r) & 0x10 != 0);
self.set_flag(flags::OF, (a ^ b) & (a ^ r) & 0x80 != 0);
self.set_szp8(r);
r
}
fn sub16(&mut self, a: u16, b: u16, borrow: bool) -> u16 {
let rhs = u32::from(b) + u32::from(borrow);
let diff = u32::from(a).wrapping_sub(rhs);
let r = diff as u16;
self.set_flag(flags::CF, u32::from(a) < rhs);
self.set_flag(flags::AF, (a ^ b ^ r) & 0x10 != 0);
self.set_flag(flags::OF, (a ^ b) & (a ^ r) & 0x8000 != 0);
self.set_szp16(r);
r
}
fn logic_flags8(&mut self, r: u8) {
self.set_flag(flags::CF | flags::OF | flags::AF, false);
self.set_szp8(r);
}
fn logic_flags16(&mut self, r: u16) {
self.set_flag(flags::CF | flags::OF | flags::AF, false);
self.set_szp16(r);
}
fn reset_sequence(&mut self) {
self.state.reset_pending = false;
self.state.halted = false;
self.state.int_shadow = false;
let regs = &mut self.state.regs;
regs.cs = 0xffff;
regs.ip = 0;
regs.ds = 0;
regs.es = 0;
regs.ss = 0;
regs.flags = flags::RESERVED_SET;
self.state.queue.flush();
self.charge(RESET_CLOCKS);
}
fn service(&mut self, vector: u8) {
let base = u16::from(vector) << 2;
let target_ip = self.read16_seg(0, base);
let target_cs = self.read16_seg(0, base.wrapping_add(2));
let saved = self.state.regs.flags;
self.push_word(saved);
self.set_flag(flags::IF | flags::TF, false);
self.push_word(self.state.regs.cs);
self.push_word(self.state.regs.ip);
self.state.regs.cs = target_cs;
self.state.regs.ip = target_ip;
self.state.queue.flush();
self.state.halted = false;
}
fn push_word(&mut self, value: u16) {
let sp = self.state.regs.sp.wrapping_sub(2);
self.state.regs.sp = sp;
self.write16(seg::SS, sp, value);
}
fn pop_word(&mut self) -> u16 {
let sp = self.state.regs.sp;
let value = self.read16(seg::SS, sp);
self.state.regs.sp = sp.wrapping_add(2);
value
}
fn instruction(&mut self) {
self.start_ip = self.state.regs.ip;
self.fill_queue();
let fields = isa::decode_stream(&mut || Some(self.fetch_byte()));
self.prepare_ea(&fields);
self.charge(fields.insn.op.clocks());
self.execute(&fields);
}
fn prepare_ea(&mut self, f: &Fields) {
self.ea = None;
let insn = f.insn;
if let Some(m) = f.modrm
&& !m.is_register()
&& [insn.dst, insn.src]
.iter()
.any(|a| matches!(a, Arg::Eb | Arg::Ev | Arg::M | Arg::Mp))
{
let regs = &self.state.regs;
let terms = match m.rm {
0 => regs.bx.wrapping_add(regs.si),
1 => regs.bx.wrapping_add(regs.di),
2 => regs.bp.wrapping_add(regs.si),
3 => regs.bp.wrapping_add(regs.di),
4 => regs.si,
5 => regs.di,
6 if m.md == 0 => 0,
6 => regs.bp,
_ => regs.bx,
};
let offset = if m.md == 0 && m.rm == 6 {
f.disp
} else {
terms.wrapping_add(f.disp)
};
self.ea = Some((f.segment(m.default_segment()), offset));
self.charge(isa::ea_clocks(m.md, m.rm, f.seg_override.is_some()));
} else if [insn.dst, insn.src]
.iter()
.any(|a| matches!(a, Arg::Ob | Arg::Ov))
{
self.ea = Some((f.segment(seg::DS), f.imm16()));
}
}
fn ea(&self) -> (u8, u16) {
self.ea.unwrap_or((seg::DS, 0))
}
fn read_arg8(&mut self, f: &Fields, arg: Arg) -> u8 {
match arg {
Arg::Eb => match f.modrm {
Some(m) if m.is_register() => self.state.regs.byte(m.rm),
_ => {
let (sr, off) = self.ea();
self.read8(sr, off)
}
},
Arg::Gb => self.state.regs.byte(f.modrm.map_or(0, |m| m.reg)),
Arg::Ib => f.imm as u8,
Arg::Rb => self.state.regs.byte(f.opcode & 7),
Arg::Al => self.state.regs.ax as u8,
Arg::Cl => self.state.regs.cx as u8,
Arg::One => 1,
Arg::Ob => {
let (sr, off) = self.ea();
self.read8(sr, off)
}
_ => 0,
}
}
fn write_arg8(&mut self, f: &Fields, arg: Arg, value: u8) {
match arg {
Arg::Eb => match f.modrm {
Some(m) if m.is_register() => self.state.regs.set_byte(m.rm, value),
_ => {
let (sr, off) = self.ea();
self.write8(sr, off, value);
}
},
Arg::Gb => self
.state
.regs
.set_byte(f.modrm.map_or(0, |m| m.reg), value),
Arg::Rb => self.state.regs.set_byte(f.opcode & 7, value),
Arg::Al => self.state.regs.set_byte(0, value),
Arg::Cl => self.state.regs.set_byte(1, value),
Arg::Ob => {
let (sr, off) = self.ea();
self.write8(sr, off, value);
}
_ => {}
}
}
fn read_arg16(&mut self, f: &Fields, arg: Arg) -> u16 {
match arg {
Arg::Ev => match f.modrm {
Some(m) if m.is_register() => self.state.regs.word(m.rm),
_ => {
let (sr, off) = self.ea();
self.read16(sr, off)
}
},
Arg::Gv => self.state.regs.word(f.modrm.map_or(0, |m| m.reg)),
Arg::Sw => self.state.regs.segment(f.modrm.map_or(0, |m| m.reg) & 3),
Arg::Sr => self.state.regs.segment((f.opcode >> 3) & 3),
Arg::Iv | Arg::Ibs => f.imm16(),
Arg::Rv => self.state.regs.word(f.opcode & 7),
Arg::Ax => self.state.regs.ax,
Arg::Dx => self.state.regs.dx,
Arg::M => self.ea().1,
Arg::Ov => {
let (sr, off) = self.ea();
self.read16(sr, off)
}
_ => 0,
}
}
fn write_arg16(&mut self, f: &Fields, arg: Arg, value: u16) {
match arg {
Arg::Ev => match f.modrm {
Some(m) if m.is_register() => self.state.regs.set_word(m.rm, value),
_ => {
let (sr, off) = self.ea();
self.write16(sr, off, value);
}
},
Arg::Gv => self
.state
.regs
.set_word(f.modrm.map_or(0, |m| m.reg), value),
Arg::Sw => {
let sr = f.modrm.map_or(0, |m| m.reg) & 3;
self.load_segment(sr, value);
}
Arg::Sr => {
let sr = (f.opcode >> 3) & 3;
self.load_segment(sr, value);
}
Arg::Rv => self.state.regs.set_word(f.opcode & 7, value),
Arg::Ax => self.state.regs.ax = value,
Arg::Dx => self.state.regs.dx = value,
Arg::Ov => {
let (sr, off) = self.ea();
self.write16(sr, off, value);
}
_ => {}
}
}
fn load_segment(&mut self, sr: u8, value: u16) {
self.state.regs.set_segment(sr, value);
if sr == seg::SS {
self.state.int_shadow = true;
}
}
fn width(f: &Fields) -> u8 {
f.insn.width_bytes().unwrap_or(2)
}
#[allow(clippy::too_many_lines)]
fn execute(&mut self, f: &Fields) {
let insn = f.insn;
match insn.op {
Op::ADD | Op::ADC | Op::SUB | Op::SBB | Op::CMP | Op::AND | Op::OR | Op::XOR => {
self.arith(f);
}
Op::TEST => self.test(f),
Op::INC | Op::DEC => self.inc_dec(f),
Op::NOT => {
if Self::width(f) == 1 {
let a = self.read_arg8(f, insn.dst);
self.write_arg8(f, insn.dst, !a);
} else {
let a = self.read_arg16(f, insn.dst);
self.write_arg16(f, insn.dst, !a);
}
}
Op::NEG => {
if Self::width(f) == 1 {
let a = self.read_arg8(f, insn.dst);
let r = self.sub8(0, a, false);
self.write_arg8(f, insn.dst, r);
} else {
let a = self.read_arg16(f, insn.dst);
let r = self.sub16(0, a, false);
self.write_arg16(f, insn.dst, r);
}
}
Op::MOV => {
if Self::width(f) == 1 {
let v = self.read_arg8(f, insn.src);
self.write_arg8(f, insn.dst, v);
} else {
let v = self.read_arg16(f, insn.src);
self.write_arg16(f, insn.dst, v);
}
}
Op::XCHG => self.xchg(f),
Op::LEA => {
let offset = self.ea().1;
self.write_arg16(f, insn.dst, offset);
}
Op::LES | Op::LDS => {
let (sr, off) = self.ea();
let value = self.read16(sr, off);
let segment = self.read16(sr, off.wrapping_add(2));
self.write_arg16(f, insn.dst, value);
let target = if insn.op == Op::LES { seg::ES } else { seg::DS };
self.load_segment(target, segment);
}
Op::PUSH => {
let sp = self.state.regs.sp.wrapping_sub(2);
self.state.regs.sp = sp;
let value = self.read_arg16(f, insn.dst);
self.write16(seg::SS, sp, value);
}
Op::POP => {
let value = self.pop_word();
self.write_arg16(f, insn.dst, value);
}
Op::PUSHF => {
let value = self.state.regs.flags;
self.push_word(value);
}
Op::POPF => {
let value = self.pop_word();
self.state.regs.flags = Regs::normalise_flags(value);
}
Op::SAHF => {
let ah = (self.state.regs.ax >> 8) & 0xff;
let kept = self.state.regs.flags & !flags::LOW_BYTE;
self.state.regs.flags = Regs::normalise_flags(kept | (ah & flags::LOW_BYTE));
}
Op::LAHF => {
let low = (self.state.regs.flags & 0xff) as u8;
self.state.regs.set_byte(4, low);
}
Op::CBW => {
let al = self.state.regs.ax as u8;
self.state.regs.ax = i16::from(al as i8) as u16;
}
Op::CWD => {
self.state.regs.dx = if self.state.regs.ax & 0x8000 != 0 {
0xffff
} else {
0
};
}
Op::ROL | Op::ROR | Op::RCL | Op::RCR | Op::SHL | Op::SHR | Op::SAR | Op::SETMO => {
self.shift(f);
}
Op::MUL | Op::IMUL => self.multiply(f),
Op::DIV | Op::IDIV => self.divide(f),
Op::AAM => self.aam(f),
Op::AAD => self.aad(f),
Op::DAA => self.daa(),
Op::DAS => self.das(),
Op::AAA => self.aaa(),
Op::AAS => self.aas(),
Op::CLC => self.set_flag(flags::CF, false),
Op::STC => self.set_flag(flags::CF, true),
Op::CMC => {
let cf = self.flag(flags::CF);
self.set_flag(flags::CF, !cf);
}
Op::CLD => self.set_flag(flags::DF, false),
Op::STD => self.set_flag(flags::DF, true),
Op::CLI => self.set_flag(flags::IF, false),
Op::STI => {
self.set_flag(flags::IF, true);
self.state.int_shadow = true;
}
Op::NOP | Op::WAIT | Op::LOCK | Op::REP | Op::REPNE | Op::SEG => {}
Op::HLT => self.state.halted = true,
Op::ESC => {
if matches!(f.modrm, Some(m) if !m.is_register()) {
let (sr, off) = self.ea();
let _ = self.read16(sr, off);
}
}
Op::SALC => {
let value = if self.flag(flags::CF) { 0xff } else { 0x00 };
self.state.regs.set_byte(0, value);
}
Op::XLAT => {
let sr = f.segment(seg::DS);
let al = self.state.regs.ax as u8;
let offset = self.state.regs.bx.wrapping_add(u16::from(al));
let value = self.read8(sr, offset);
self.state.regs.set_byte(0, value);
}
Op::IN => {
let port = self.port(f, insn.src);
if insn.dst == Arg::Al {
let value = self.io_read8(port);
self.state.regs.set_byte(0, value);
} else {
let lo = self.io_read8(port);
let hi = self.io_read8(port.wrapping_add(1));
self.state.regs.ax = u16::from(lo) | (u16::from(hi) << 8);
}
}
Op::OUT => {
let port = self.port(f, insn.dst);
if insn.src == Arg::Al {
let value = self.state.regs.ax as u8;
self.io_write8(port, value);
} else {
let value = self.state.regs.ax;
self.io_write8(port, value as u8);
self.io_write8(port.wrapping_add(1), (value >> 8) as u8);
}
}
Op::CALL => {
let target = match insn.dst {
Arg::Jv | Arg::Jb => self.state.regs.ip.wrapping_add(f.imm16()),
_ => self.read_arg16(f, insn.dst),
};
let ret = self.state.regs.ip;
self.push_word(ret);
self.state.regs.ip = target;
self.state.queue.flush();
}
Op::CALLF => {
let (offset, segment) = self.far_target(f);
let cs = self.state.regs.cs;
let ip = self.state.regs.ip;
self.push_word(cs);
self.push_word(ip);
self.state.regs.cs = segment;
self.state.regs.ip = offset;
self.state.queue.flush();
}
Op::JMP => {
let target = match insn.dst {
Arg::Jv | Arg::Jb => self.state.regs.ip.wrapping_add(f.imm16()),
_ => self.read_arg16(f, insn.dst),
};
self.state.regs.ip = target;
self.state.queue.flush();
}
Op::JMPF => {
let (offset, segment) = self.far_target(f);
self.state.regs.cs = segment;
self.state.regs.ip = offset;
self.state.queue.flush();
}
Op::RET => {
let ip = self.pop_word();
self.state.regs.ip = ip;
if insn.dst == Arg::Iv {
self.state.regs.sp = self.state.regs.sp.wrapping_add(f.imm16());
}
self.state.queue.flush();
}
Op::RETF => {
let ip = self.pop_word();
let cs = self.pop_word();
self.state.regs.ip = ip;
self.state.regs.cs = cs;
if insn.dst == Arg::Iv {
self.state.regs.sp = self.state.regs.sp.wrapping_add(f.imm16());
}
self.state.queue.flush();
}
Op::IRET => {
let ip = self.pop_word();
let cs = self.pop_word();
let fl = self.pop_word();
self.state.regs.ip = ip;
self.state.regs.cs = cs;
self.state.regs.flags = Regs::normalise_flags(fl);
self.state.queue.flush();
}
Op::INT => {
let vector = f.imm as u8;
self.service(vector);
}
Op::INT3 => self.service(VEC_BREAKPOINT),
Op::INTO => {
if self.flag(flags::OF) {
self.service(VEC_OVERFLOW);
}
}
Op::LOOP | Op::LOOPE | Op::LOOPNE => {
let cx = self.state.regs.cx.wrapping_sub(1);
self.state.regs.cx = cx;
let zf = self.flag(flags::ZF);
let take = cx != 0
&& match insn.op {
Op::LOOPE => zf,
Op::LOOPNE => !zf,
_ => true,
};
if take {
self.state.regs.ip = self.state.regs.ip.wrapping_add(f.imm16());
self.state.queue.flush();
}
}
Op::JCXZ => {
if self.state.regs.cx == 0 {
self.state.regs.ip = self.state.regs.ip.wrapping_add(f.imm16());
self.state.queue.flush();
}
}
op if op.is_conditional_jump() => {
if self.condition(op) {
self.state.regs.ip = self.state.regs.ip.wrapping_add(f.imm16());
self.state.queue.flush();
}
}
op if op.is_string() => self.string(f),
_ => {}
}
}
fn port(&self, f: &Fields, arg: Arg) -> u16 {
match arg {
Arg::Dx => self.state.regs.dx,
_ => u16::from(f.imm as u8),
}
}
fn far_target(&mut self, f: &Fields) -> (u16, u16) {
if f.insn.dst == Arg::Ap {
(f.imm16(), f.imm_seg())
} else {
let (sr, off) = self.ea();
let offset = self.read16(sr, off);
let segment = self.read16(sr, off.wrapping_add(2));
(offset, segment)
}
}
fn condition(&self, op: Op) -> bool {
let cf = self.flag(flags::CF);
let zf = self.flag(flags::ZF);
let sf = self.flag(flags::SF);
let of = self.flag(flags::OF);
let pf = self.flag(flags::PF);
match op {
Op::JO => of,
Op::JNO => !of,
Op::JB => cf,
Op::JNB => !cf,
Op::JZ => zf,
Op::JNZ => !zf,
Op::JBE => cf || zf,
Op::JA => !cf && !zf,
Op::JS => sf,
Op::JNS => !sf,
Op::JP => pf,
Op::JNP => !pf,
Op::JL => sf != of,
Op::JGE => sf == of,
Op::JLE => zf || (sf != of),
_ => !zf && (sf == of),
}
}
fn arith(&mut self, f: &Fields) {
let insn = f.insn;
let carry = self.flag(flags::CF);
if Self::width(f) == 1 {
let a = self.read_arg8(f, insn.dst);
let b = self.read_arg8(f, insn.src);
let r = match insn.op {
Op::ADD => self.add8(a, b, false),
Op::ADC => self.add8(a, b, carry),
Op::SUB | Op::CMP => self.sub8(a, b, false),
Op::SBB => self.sub8(a, b, carry),
Op::AND => {
let r = a & b;
self.logic_flags8(r);
r
}
Op::OR => {
let r = a | b;
self.logic_flags8(r);
r
}
_ => {
let r = a ^ b;
self.logic_flags8(r);
r
}
};
if insn.op != Op::CMP {
self.write_arg8(f, insn.dst, r);
}
} else {
let a = self.read_arg16(f, insn.dst);
let b = self.read_arg16(f, insn.src);
let r = match insn.op {
Op::ADD => self.add16(a, b, false),
Op::ADC => self.add16(a, b, carry),
Op::SUB | Op::CMP => self.sub16(a, b, false),
Op::SBB => self.sub16(a, b, carry),
Op::AND => {
let r = a & b;
self.logic_flags16(r);
r
}
Op::OR => {
let r = a | b;
self.logic_flags16(r);
r
}
_ => {
let r = a ^ b;
self.logic_flags16(r);
r
}
};
if insn.op != Op::CMP {
self.write_arg16(f, insn.dst, r);
}
}
}
fn test(&mut self, f: &Fields) {
let insn = f.insn;
if Self::width(f) == 1 {
let a = self.read_arg8(f, insn.dst);
let b = self.read_arg8(f, insn.src);
self.logic_flags8(a & b);
} else {
let a = self.read_arg16(f, insn.dst);
let b = self.read_arg16(f, insn.src);
self.logic_flags16(a & b);
}
}
fn inc_dec(&mut self, f: &Fields) {
let insn = f.insn;
let carry = self.flag(flags::CF);
if Self::width(f) == 1 {
let a = self.read_arg8(f, insn.dst);
let r = if insn.op == Op::INC {
self.add8(a, 1, false)
} else {
self.sub8(a, 1, false)
};
self.write_arg8(f, insn.dst, r);
} else {
let a = self.read_arg16(f, insn.dst);
let r = if insn.op == Op::INC {
self.add16(a, 1, false)
} else {
self.sub16(a, 1, false)
};
self.write_arg16(f, insn.dst, r);
}
self.set_flag(flags::CF, carry);
}
fn xchg(&mut self, f: &Fields) {
let insn = f.insn;
if Self::width(f) == 1 {
let a = self.read_arg8(f, insn.dst);
let b = self.read_arg8(f, insn.src);
self.write_arg8(f, insn.dst, b);
self.write_arg8(f, insn.src, a);
} else {
let a = self.read_arg16(f, insn.dst);
let b = self.read_arg16(f, insn.src);
self.write_arg16(f, insn.dst, b);
self.write_arg16(f, insn.src, a);
}
}
fn shift(&mut self, f: &Fields) {
let insn = f.insn;
let count = if insn.src == Arg::One {
1
} else {
self.state.regs.cx as u8
};
if Self::width(f) == 1 {
let a = self.read_arg8(f, insn.dst);
let r = self.shift8(insn.op, a, count);
self.write_arg8(f, insn.dst, r);
} else {
let a = self.read_arg16(f, insn.dst);
let r = self.shift16(insn.op, a, count);
self.write_arg16(f, insn.dst, r);
}
}
fn shift8(&mut self, op: Op, value: u8, count: u8) -> u8 {
if count == 0 {
return value;
}
if op == Op::SETMO {
self.logic_flags8(0xff);
return 0xff;
}
let mut v = value;
let mut cf = self.flag(flags::CF);
let mut of = self.flag(flags::OF);
for _ in 0..count {
match op {
Op::ROL => {
cf = v & 0x80 != 0;
v = (v << 1) | u8::from(cf);
of = (v & 0x80 != 0) != cf;
}
Op::ROR => {
cf = v & 1 != 0;
v = (v >> 1) | (u8::from(cf) << 7);
of = ((v >> 7) ^ (v >> 6)) & 1 != 0;
}
Op::RCL => {
let carry_in = cf;
cf = v & 0x80 != 0;
v = (v << 1) | u8::from(carry_in);
of = (v & 0x80 != 0) != cf;
}
Op::RCR => {
let carry_in = cf;
of = (v & 0x80 != 0) != carry_in;
cf = v & 1 != 0;
v = (v >> 1) | (u8::from(carry_in) << 7);
}
Op::SHL => {
cf = v & 0x80 != 0;
v <<= 1;
of = (v & 0x80 != 0) != cf;
}
Op::SHR => {
of = v & 0x80 != 0;
cf = v & 1 != 0;
v >>= 1;
}
_ => {
of = false;
cf = v & 1 != 0;
v = ((v as i8) >> 1) as u8;
}
}
}
self.set_flag(flags::CF, cf);
self.set_flag(flags::OF, of);
if matches!(op, Op::SHL | Op::SHR | Op::SAR) {
self.set_szp8(v);
self.set_flag(flags::AF, op == Op::SHL && v & 0x10 != 0);
}
v
}
fn shift16(&mut self, op: Op, value: u16, count: u8) -> u16 {
if count == 0 {
return value;
}
if op == Op::SETMO {
self.logic_flags16(0xffff);
return 0xffff;
}
let mut v = value;
let mut cf = self.flag(flags::CF);
let mut of = self.flag(flags::OF);
for _ in 0..count {
match op {
Op::ROL => {
cf = v & 0x8000 != 0;
v = (v << 1) | u16::from(cf);
of = (v & 0x8000 != 0) != cf;
}
Op::ROR => {
cf = v & 1 != 0;
v = (v >> 1) | (u16::from(cf) << 15);
of = ((v >> 15) ^ (v >> 14)) & 1 != 0;
}
Op::RCL => {
let carry_in = cf;
cf = v & 0x8000 != 0;
v = (v << 1) | u16::from(carry_in);
of = (v & 0x8000 != 0) != cf;
}
Op::RCR => {
let carry_in = cf;
of = (v & 0x8000 != 0) != carry_in;
cf = v & 1 != 0;
v = (v >> 1) | (u16::from(carry_in) << 15);
}
Op::SHL => {
cf = v & 0x8000 != 0;
v <<= 1;
of = (v & 0x8000 != 0) != cf;
}
Op::SHR => {
of = v & 0x8000 != 0;
cf = v & 1 != 0;
v >>= 1;
}
_ => {
of = false;
cf = v & 1 != 0;
v = ((v as i16) >> 1) as u16;
}
}
}
self.set_flag(flags::CF, cf);
self.set_flag(flags::OF, of);
if matches!(op, Op::SHL | Op::SHR | Op::SAR) {
self.set_szp16(v);
self.set_flag(flags::AF, op == Op::SHL && v & 0x10 != 0);
}
v
}
fn mul_flags(&mut self, high: u16, overflow: bool) {
self.set_flag(flags::ZF, high == 0);
self.set_flag(flags::SF, high & 0x8000 != 0);
self.set_flag(flags::PF, Self::parity(high as u8));
self.set_flag(flags::AF, false);
self.set_flag(flags::CF | flags::OF, overflow);
}
fn multiply(&mut self, f: &Fields) {
let insn = f.insn;
let signed = insn.op == Op::IMUL;
if Self::width(f) == 1 {
let src = self.read_arg8(f, insn.dst);
let al = self.state.regs.ax as u8;
let product = if signed {
(i16::from(al as i8) * i16::from(src as i8)) as u16
} else {
u16::from(al) * u16::from(src)
};
self.state.regs.ax = product;
let high = (product >> 8) as u8;
let overflow = if signed {
high != if product & 0x80 != 0 { 0xff } else { 0x00 }
} else {
high != 0
};
self.mul_flags(u16::from(high) << 8, overflow);
self.set_flag(flags::PF, Self::parity(high));
} else {
let src = self.read_arg16(f, insn.dst);
let ax = self.state.regs.ax;
let product = if signed {
(i32::from(ax as i16) * i32::from(src as i16)) as u32
} else {
u32::from(ax) * u32::from(src)
};
self.state.regs.ax = product as u16;
self.state.regs.dx = (product >> 16) as u16;
let high = (product >> 16) as u16;
let overflow = if signed {
high != if product & 0x8000 != 0 {
0xffff
} else {
0x0000
}
} else {
high != 0
};
self.mul_flags(high, overflow);
}
}
fn divide(&mut self, f: &Fields) {
let insn = f.insn;
let signed = insn.op == Op::IDIV;
let negate = signed && f.rep.is_some();
let bits = if Self::width(f) == 1 { 8 } else { 16 };
let (source, dividend) = if bits == 8 {
(
u32::from(self.read_arg8(f, insn.dst)),
u32::from(self.state.regs.ax),
)
} else {
let src = u32::from(self.read_arg16(f, insn.dst));
let dividend = (u32::from(self.state.regs.dx) << 16) | u32::from(self.state.regs.ax);
(src, dividend)
};
let (magnitude, divisor_magnitude) = if signed {
(
Self::sign_extend(dividend, bits * 2).unsigned_abs(),
Self::sign_extend(source, bits).unsigned_abs(),
)
} else {
(u64::from(dividend), u64::from(source))
};
let (quotient_magnitude, remainder_magnitude) =
self.cord(magnitude, divisor_magnitude, bits);
let mask = (1u64 << bits) - 1;
let (quotient, remainder, fault) = if divisor_magnitude == 0 {
(0, 0, true)
} else if signed {
let n = Self::sign_extend(dividend, bits * 2);
let d = Self::sign_extend(source, bits);
let mut q = n / d;
if negate {
q = q.wrapping_neg();
}
let limit = 1i64 << (bits - 1);
(
(q as u64) & mask,
((n % d) as u64) & mask,
!(-limit..limit).contains(&q),
)
} else {
let q = u64::from(dividend) / divisor_magnitude;
debug_assert!(q > mask || q == quotient_magnitude);
(
quotient_magnitude & mask,
remainder_magnitude & mask,
q > mask,
)
};
if fault {
self.divide_error();
return;
}
self.set_flag(flags::CF, quotient & (1 << (bits - 1)) == 0);
if bits == 8 {
self.state.regs.ax = ((quotient as u16) & 0xff) | (((remainder as u16) & 0xff) << 8);
} else {
self.state.regs.ax = quotient as u16;
self.state.regs.dx = remainder as u16;
}
}
const fn sign_extend(value: u32, bits: u32) -> i64 {
let shift = 64 - bits;
((value as i64) << shift) >> shift
}
fn cord(&mut self, dividend: u64, divisor: u64, bits: u32) -> (u64, u64) {
let mask = (1u64 << bits) - 1;
let top = 1u64 << (bits - 1);
let mut remainder = (dividend >> bits) & mask;
let mut quotient = dividend & mask;
for _ in 0..bits {
let carried = (quotient >> (bits - 1)) & 1;
quotient = (quotient << 1) & mask;
let overflowed = remainder & top != 0;
let shifted = ((remainder << 1) | carried) & mask;
let difference = shifted.wrapping_sub(divisor) & mask;
let borrow = shifted < divisor;
self.set_flag(flags::CF, borrow);
self.set_flag(flags::AF, (shifted ^ divisor ^ difference) & 0x10 != 0);
self.set_flag(
flags::OF,
(shifted ^ divisor) & (shifted ^ difference) & top != 0,
);
self.set_flag(flags::SF, difference & top != 0);
self.set_flag(flags::ZF, difference == 0);
self.set_flag(flags::PF, Self::parity(difference as u8));
if overflowed || !borrow {
remainder = difference;
quotient |= 1;
} else {
remainder = shifted;
}
}
(quotient, remainder)
}
fn divide_error(&mut self) {
self.service(VEC_DIVIDE);
}
fn aam(&mut self, f: &Fields) {
let base = f.imm as u8;
if base == 0 {
self.set_flag(flags::CF | flags::OF | flags::AF, false);
self.set_szp8(0);
self.divide_error();
return;
}
let al = self.state.regs.ax as u8;
let quotient = al / base;
let remainder = al % base;
self.state.regs.ax = u16::from(remainder) | (u16::from(quotient) << 8);
self.set_szp8(remainder);
self.set_flag(flags::CF | flags::OF | flags::AF, false);
}
fn aad(&mut self, f: &Fields) {
let base = f.imm as u8;
let al = self.state.regs.ax as u8;
let ah = (self.state.regs.ax >> 8) as u8;
let product = ah.wrapping_mul(base);
let r = self.add8(product, al, false);
self.state.regs.ax = u16::from(r);
}
fn daa(&mut self) {
self.decimal_adjust(false);
}
fn das(&mut self) {
self.decimal_adjust(true);
}
fn decimal_adjust(&mut self, subtract: bool) {
let al = self.state.regs.ax as u8;
let auxiliary = self.flag(flags::AF);
let low = (al & 0x0f) > 9 || auxiliary;
let threshold = if auxiliary { 0x9f } else { 0x99 };
let high = self.flag(flags::CF) || al > threshold;
let correction = if low { 0x06 } else { 0x00 } + if high { 0x60 } else { 0x00 };
let adjusted = if subtract {
self.sub8(al, correction, false)
} else {
self.add8(al, correction, false)
};
self.state.regs.set_byte(0, adjusted);
self.set_flag(flags::CF, high);
self.set_flag(flags::AF, low);
}
fn aaa(&mut self) {
self.ascii_adjust(false);
}
fn aas(&mut self) {
self.ascii_adjust(true);
}
fn ascii_adjust(&mut self, subtract: bool) {
let al = self.state.regs.ax as u8;
let adjust = (al & 0x0f) > 9 || self.flag(flags::AF);
let operand = if adjust { 6 } else { 0 };
let adjusted = if subtract {
self.sub8(al, operand, false)
} else {
self.add8(al, operand, false)
};
let ah = (self.state.regs.ax >> 8) as u8;
let ah = match (adjust, subtract) {
(true, false) => ah.wrapping_add(1),
(true, true) => ah.wrapping_sub(1),
(false, _) => ah,
};
self.state.regs.ax = (u16::from(ah) << 8) | u16::from(adjusted & 0x0f);
self.set_flag(flags::CF | flags::AF, adjust);
}
fn string(&mut self, f: &Fields) {
let op = f.insn.op;
let width = u16::from(Self::width(f));
let delta = if self.flag(flags::DF) {
width.wrapping_neg()
} else {
width
};
let Some(rep) = f.rep else {
self.string_step(f, delta);
return;
};
while self.state.regs.cx != 0 {
self.string_step(f, delta);
self.state.regs.cx = self.state.regs.cx.wrapping_sub(1);
if matches!(op, Op::CMPSB | Op::CMPSW | Op::SCASB | Op::SCASW) {
let zf = self.flag(flags::ZF);
let stop = match rep {
Rep::While => !zf,
Rep::WhileNot => zf,
};
if stop {
break;
}
}
if self.state.regs.cx == 0 {
break;
}
self.charge(op.clocks());
if self.lines.nmi_pending() || (self.flag(flags::IF) && self.lines.intr_pending()) {
self.state.regs.ip = self.start_ip;
self.state.queue.flush();
return;
}
}
}
fn string_step(&mut self, f: &Fields, delta: u16) {
let op = f.insn.op;
let src_seg = f.segment(seg::DS);
let regs = self.state.regs;
match op {
Op::MOVSB => {
let value = self.read8(src_seg, regs.si);
self.write8(seg::ES, regs.di, value);
self.advance_si_di(delta, true, true);
}
Op::MOVSW => {
let value = self.read16(src_seg, regs.si);
self.write16(seg::ES, regs.di, value);
self.advance_si_di(delta, true, true);
}
Op::CMPSB => {
let a = self.read8(src_seg, regs.si);
let b = self.read8(seg::ES, regs.di);
self.sub8(a, b, false);
self.advance_si_di(delta, true, true);
}
Op::CMPSW => {
let a = self.read16(src_seg, regs.si);
let b = self.read16(seg::ES, regs.di);
self.sub16(a, b, false);
self.advance_si_di(delta, true, true);
}
Op::STOSB => {
let value = regs.ax as u8;
self.write8(seg::ES, regs.di, value);
self.advance_si_di(delta, false, true);
}
Op::STOSW => {
let value = regs.ax;
self.write16(seg::ES, regs.di, value);
self.advance_si_di(delta, false, true);
}
Op::LODSB => {
let value = self.read8(src_seg, regs.si);
self.state.regs.set_byte(0, value);
self.advance_si_di(delta, true, false);
}
Op::LODSW => {
let value = self.read16(src_seg, regs.si);
self.state.regs.ax = value;
self.advance_si_di(delta, true, false);
}
Op::SCASB => {
let b = self.read8(seg::ES, regs.di);
let a = self.state.regs.ax as u8;
self.sub8(a, b, false);
self.advance_si_di(delta, false, true);
}
_ => {
let b = self.read16(seg::ES, regs.di);
let a = self.state.regs.ax;
self.sub16(a, b, false);
self.advance_si_di(delta, false, true);
}
}
}
fn advance_si_di(&mut self, delta: u16, si: bool, di: bool) {
if si {
self.state.regs.si = self.state.regs.si.wrapping_add(delta);
}
if di {
self.state.regs.di = self.state.regs.di.wrapping_add(delta);
}
}
}