use std::cell::RefCell;
use std::num::Wrapping;
use std::rc::Rc;
use crate::cpu::instruction::{Instruction, InstructionInfo, ModRegRm, RepeatMode};
use crate::cpu::parameter::{Parameter, ParameterSet};
use crate::cpu::op::{Op, Invalid};
use crate::cpu::register::{R, r8, r16, r32, sr};
use crate::cpu::segment::Segment;
use crate::memory::{MMU, MemoryAddress};
const DEBUG_DECODER: bool = false;
#[cfg(test)]
#[path = "./decoder_test.rs"]
mod decoder_test;
#[derive(Clone, Debug, PartialEq)]
pub enum OperandSize {
_16bit, _32bit,
}
#[derive(Clone, Debug, PartialEq)]
pub enum AddressSize {
_16bit, _32bit,
}
#[derive(Clone, Default)]
pub struct Decoder {
current_seg: u16,
current_offset: u16,
}
impl Decoder {
pub fn decode_to_block(&mut self, mut mmu: &mut MMU, seg: u16, offset: u16, n: usize) -> Vec<InstructionInfo> {
let mut ops: Vec<InstructionInfo> = Vec::new();
let mut inst_offset = 0;
for _ in 0..n {
let op = self.get_instruction_info(&mut mmu, seg, offset+inst_offset);
inst_offset += op.bytes.len() as u16;
ops.push(op);
}
ops
}
pub fn disassemble_block_to_str(&mut self, mut mmu: &mut MMU, seg: u16, offset: u16, n: usize) -> String {
let ops = self.decode_to_block(&mut mmu, seg, offset, n);
instruction_info_to_str(&ops)
}
pub fn get_instruction_info(&mut self, mut mmu: &mut MMU, seg: u16, offset: u16) -> InstructionInfo {
let instr = self.get_instruction(&mut mmu, seg, offset);
if DEBUG_DECODER {
println!("get_instruction_info at {}: {}", MemoryAddress::RealSegmentOffset(seg, offset), instr);
}
InstructionInfo {
segment: seg as usize,
offset: offset as usize,
bytes: mmu.read(seg, offset, instr.length as usize),
instruction: instr,
}
}
pub fn get_instruction(&mut self, mut mmu: &mut MMU, segment: u16, offset: u16) -> Instruction {
self.current_seg = segment;
self.current_offset = offset;
let mut op = Instruction::new(Op::Uninitialized);
self.decode(&mut mmu, &mut op);
op
}
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cyclomatic_complexity))]
fn decode(&mut self, mut mmu: &mut MMU, mut op: &mut Instruction) {
let start_offset = self.current_offset;
let b = self.read_u8(mmu);
if DEBUG_DECODER {
}
match b {
0x00 => {
op.command = Op::Add8;
op.params = self.rm8_r8(&mut mmu, op.segment_prefix);
}
0x01 => {
self.prefixed_16_32_rm_r(&mut mmu, &mut op, Op::Add16, Op::Add32)
}
0x02 => {
op.command = Op::Add8;
op.params = self.r8_rm8(&mut mmu, op.segment_prefix);
}
0x03 => {
self.prefixed_16_32_r_rm(&mut mmu, &mut op, Op::Add16, Op::Add32)
}
0x04 => {
op.command = Op::Add8;
op.params.dst = Parameter::Reg8(R::AL);
op.params.src = Parameter::Imm8(self.read_u8(mmu));
}
0x05 => {
match op.op_size {
OperandSize::_16bit => {
op.command = Op::Add16;
op.params.dst = Parameter::Reg16(R::AX);
op.params.src = Parameter::Imm16(self.read_u16(mmu));
}
OperandSize::_32bit => {
op.command = Op::Add32;
op.params.dst = Parameter::Reg32(R::EAX);
op.params.src = Parameter::Imm32(self.read_u32(mmu));
}
}
}
0x06 => {
op.command = Op::Push16;
op.params.dst = Parameter::SReg16(R::ES);
}
0x07 => {
op.command = Op::Pop16;
op.params.dst = Parameter::SReg16(R::ES);
}
0x08 => {
op.command = Op::Or8;
op.params = self.rm8_r8(&mut mmu, op.segment_prefix);
}
0x09 => {
op.command = Op::Or16;
op.params = self.rm16_r16(&mut mmu, op);
}
0x0A => {
op.command = Op::Or8;
op.params = self.r8_rm8(&mut mmu, op.segment_prefix);
}
0x0B => {
op.command = Op::Or16;
op.params = self.r16_rm16(&mut mmu, op);
}
0x0C => {
op.command = Op::Or8;
op.params.dst = Parameter::Reg8(R::AL);
op.params.src = Parameter::Imm8(self.read_u8(mmu));
}
0x0D => {
op.command = Op::Or16;
op.params.dst = Parameter::Reg16(R::AX);
op.params.src = Parameter::Imm16(self.read_u16(mmu));
}
0x0E => {
op.command = Op::Push16;
op.params.dst = Parameter::SReg16(R::CS);
}
0x0F => {
let b2 = self.read_u8(mmu);
match b2 {
0x00 => {
let x = self.read_mod_reg_rm(mmu);
op.params.dst = self.rm16(&mut mmu, op, x.rm, x.md);
op.command = match x.reg {
0 => Op::Sldt,
_ => Op::Invalid(vec!(b, b2), Invalid::Reg(x.reg)),
};
}
0x82 => {
op.command = Op::Jc;
op.params.dst = Parameter::Imm16(self.read_rel16(mmu));
}
0x83 => {
op.command = Op::Jnc;
op.params.dst = Parameter::Imm16(self.read_rel16(mmu));
}
0x84 => {
op.command = Op::Jz;
op.params.dst = Parameter::Imm16(self.read_rel16(mmu));
}
0x85 => {
op.command = Op::Jnz;
op.params.dst = Parameter::Imm16(self.read_rel16(mmu));
}
0x86 => {
op.command = Op::Jna;
op.params.dst = Parameter::Imm16(self.read_rel16(mmu));
}
0x87 => {
op.command = Op::Ja;
op.params.dst = Parameter::Imm16(self.read_rel16(mmu));
}
0x89 => {
op.command = Op::Jns;
op.params.dst = Parameter::Imm16(self.read_rel16(mmu));
}
0x8C => {
op.command = Op::Jl;
op.params.dst = Parameter::Imm16(self.read_rel16(mmu));
}
0x8D => {
op.command = Op::Jnl;
op.params.dst = Parameter::Imm16(self.read_rel16(mmu));
}
0x8E => {
op.command = Op::Jng;
op.params.dst = Parameter::Imm16(self.read_rel16(mmu));
}
0x8F => {
op.command = Op::Jg;
op.params.dst = Parameter::Imm16(self.read_rel16(mmu));
}
0x92 => {
let x = self.read_mod_reg_rm(mmu);
op.command = Op::Setc;
op.params.dst = self.rm8(&mut mmu, op.segment_prefix, x.rm, x.md);
}
0x95 => {
let x = self.read_mod_reg_rm(mmu);
op.command = Op::Setnz;
op.params.dst = self.rm8(&mut mmu, op.segment_prefix, x.rm, x.md);
}
0x9F => {
let x = self.read_mod_reg_rm(mmu);
op.command = Op::Setg;
op.params.dst = self.rm8(&mut mmu, op.segment_prefix, x.rm, x.md);
}
0xA0 => {
op.command = Op::Push16;
op.params.dst = Parameter::SReg16(R::FS);
}
0xA1 => {
op.command = Op::Pop16;
op.params.dst = Parameter::SReg16(R::FS);
}
0xA3 => {
op.command = Op::Bt;
op.params = self.rm16_r16(&mut mmu, op);
}
0xA4 =>{
op.command = Op::Shld;
op.params = self.rm16_r16(&mut mmu, op);
op.params.src2 = Parameter::Imm8(self.read_u8(mmu));
}
0xA8 => {
op.command = Op::Push16;
op.params.dst = Parameter::SReg16(R::GS);
}
0xA9 => {
op.command = Op::Pop16;
op.params.dst = Parameter::SReg16(R::GS);
}
0xAC => {
op.command = Op::Shrd;
op.params = self.rm16_r16(&mut mmu, op);
op.params.src2 = Parameter::Imm8(self.read_u8(mmu));
}
0xAF => {
self.prefixed_16_32_r_rm(&mut mmu, &mut op, Op::Imul16, Op::Imul32)
}
0xB6 => {
match op.op_size {
OperandSize::_16bit => {
op.command = Op::Movzx16;
op.params = self.r16_rm8(&mut mmu, op.segment_prefix);
}
OperandSize::_32bit => {
op.command = Op::Movzx32;
op.params = self.r32_rm8(&mut mmu, op.segment_prefix);
}
}
}
0xBA => {
let x = self.read_mod_reg_rm(mmu);
op.command = Op::Bts;
op.params.dst = self.rm16(&mut mmu, op, x.rm, x.md);
op.params.src = Parameter::Imm8(self.read_u8(mmu));
}
0xBC => {
op.command = Op::Bsf;
op.params = self.r16_rm16(&mut mmu, op);
}
0xBE => {
match op.op_size {
OperandSize::_16bit => {
op.command = Op::Movsx16;
op.params = self.r16_rm8(&mut mmu, op.segment_prefix);
}
OperandSize::_32bit => {
op.command = Op::Movsx32;
op.params = self.r32_rm8(&mut mmu, op.segment_prefix);
}
}
}
0xBF => {
match op.op_size {
OperandSize::_16bit => op.command = Op::Invalid(vec!(b, b2), Invalid::Op),
OperandSize::_32bit => {
op.command = Op::Movsx32;
op.params = self.r32_rm16(&mut mmu, op);
}
}
}
_ => op.command = Op::Invalid(vec!(b, b2), Invalid::Op),
}
}
0x10 => {
op.command = Op::Adc8;
op.params = self.rm8_r8(&mut mmu, op.segment_prefix);
}
0x11 => {
op.command = Op::Adc16;
op.params = self.rm16_r16(&mut mmu, op);
}
0x12 => {
op.command = Op::Adc8;
op.params = self.r8_rm8(&mut mmu, op.segment_prefix);
}
0x13 => {
op.command = Op::Adc16;
op.params = self.r16_rm16(&mut mmu, op);
}
0x14 => {
op.command = Op::Adc8;
op.params.dst = Parameter::Reg8(R::AL);
op.params.src = Parameter::Imm8(self.read_u8(mmu));
}
0x15 => {
op.command = Op::Adc16;
op.params.dst = Parameter::Reg16(R::AX);
op.params.src = Parameter::Imm16(self.read_u16(mmu));
}
0x16 => {
op.command = Op::Push16;
op.params.dst = Parameter::SReg16(R::SS);
}
0x17 => {
op.command = Op::Pop16;
op.params.dst = Parameter::SReg16(R::SS);
}
0x18 => {
op.command = Op::Sbb8;
op.params = self.rm8_r8(&mut mmu, op.segment_prefix);
}
0x19 => {
op.command = Op::Sbb16;
op.params = self.rm16_r16(&mut mmu, op);
}
0x1A => {
op.command = Op::Sbb8;
op.params = self.r8_rm8(&mut mmu, op.segment_prefix);
}
0x1B => {
op.command = Op::Sbb16;
op.params = self.r16_rm16(&mut mmu, op);
}
0x1C => {
op.command = Op::Sbb8;
op.params.dst = Parameter::Reg8(R::AL);
op.params.src = Parameter::Imm8(self.read_u8(mmu));
}
0x1D => {
op.command = Op::Sbb16;
op.params.dst = Parameter::Reg16(R::AX);
op.params.src = Parameter::Imm16(self.read_u16(mmu));
}
0x1E => {
op.command = Op::Push16;
op.params.dst = Parameter::SReg16(R::DS);
}
0x1F => {
op.command = Op::Pop16;
op.params.dst = Parameter::SReg16(R::DS);
}
0x20 => {
op.command = Op::And8;
op.params = self.rm8_r8(&mut mmu, op.segment_prefix);
}
0x21 => {
op.command = Op::And16;
op.params = self.rm16_r16(&mut mmu, op);
}
0x22 => {
op.command = Op::And8;
op.params = self.r8_rm8(&mut mmu, op.segment_prefix);
}
0x23 => {
op.command = Op::And16;
op.params = self.r16_rm16(&mut mmu, op);
}
0x24 => {
op.command = Op::And8;
op.params.dst = Parameter::Reg8(R::AL);
op.params.src = Parameter::Imm8(self.read_u8(mmu));
}
0x25 => {
op.command = Op::And16;
op.params.dst = Parameter::Reg16(R::AX);
op.params.src = Parameter::Imm16(self.read_u16(mmu));
}
0x26 => {
op.segment_prefix = Segment::ES;
self.decode(&mut mmu, &mut op);
op.length += 1;
return;
}
0x27 => op.command = Op::Daa,
0x28 => {
op.command = Op::Sub8;
op.params = self.rm8_r8(&mut mmu, op.segment_prefix);
}
0x29 => {
op.command = Op::Sub16;
op.params = self.rm16_r16(&mut mmu, op);
}
0x2A => {
op.command = Op::Sub8;
op.params = self.r8_rm8(&mut mmu, op.segment_prefix);
}
0x2B => {
self.prefixed_16_32_r_rm(&mut mmu, &mut op, Op::Sub16, Op::Sub32)
}
0x2C => {
op.command = Op::Sub8;
op.params.dst = Parameter::Reg8(R::AL);
op.params.src = Parameter::Imm8(self.read_u8(mmu));
}
0x2D => {
match op.op_size {
OperandSize::_16bit => {
op.command = Op::Sub16;
op.params.dst = Parameter::Reg16(R::AX);
op.params.src = Parameter::Imm16(self.read_u16(mmu));
}
OperandSize::_32bit => {
op.command = Op::Sub32;
op.params.dst = Parameter::Reg32(R::EAX);
op.params.src = Parameter::Imm32(self.read_u32(mmu));
}
}
}
0x2E => {
op.segment_prefix = Segment::CS;
self.decode(&mut mmu, &mut op);
op.length += 1;
return;
}
0x2F => op.command = Op::Das,
0x30 => {
op.command = Op::Xor8;
op.params = self.rm8_r8(&mut mmu, op.segment_prefix);
}
0x31 => {
self.prefixed_16_32_rm_r(&mut mmu, &mut op, Op::Xor16, Op::Xor32)
}
0x32 => {
op.command = Op::Xor8;
op.params = self.r8_rm8(&mut mmu, op.segment_prefix);
}
0x33 => {
self.prefixed_16_32_r_rm(&mut mmu, &mut op, Op::Xor16, Op::Xor32)
}
0x34 => {
op.command = Op::Xor8;
op.params.dst = Parameter::Reg8(R::AL);
op.params.src = Parameter::Imm8(self.read_u8(mmu));
}
0x35 => {
op.command = Op::Xor16;
op.params.dst = Parameter::Reg16(R::AX);
op.params.src = Parameter::Imm16(self.read_u16(mmu));
}
0x36 => {
op.segment_prefix = Segment::SS;
self.decode(&mut mmu, &mut op);
op.length += 1;
return;
}
0x37 => op.command = Op::Aaa,
0x38 => {
op.command = Op::Cmp8;
op.params = self.rm8_r8(&mut mmu, op.segment_prefix);
}
0x39 => {
op.command = Op::Cmp16;
op.params = self.rm16_r16(&mut mmu, op);
}
0x3A => {
op.command = Op::Cmp8;
op.params = self.r8_rm8(&mut mmu, op.segment_prefix);
}
0x3B => {
self.prefixed_16_32_r_rm(&mut mmu, &mut op, Op::Cmp16, Op::Cmp32)
}
0x3C => {
op.command = Op::Cmp8;
op.params.dst = Parameter::Reg8(R::AL);
op.params.src = Parameter::Imm8(self.read_u8(mmu));
}
0x3D => {
match op.op_size {
OperandSize::_16bit => {
op.command = Op::Cmp16;
op.params.dst = Parameter::Reg16(R::AX);
op.params.src = Parameter::Imm16(self.read_u16(mmu));
}
OperandSize::_32bit => {
op.command = Op::Cmp32;
op.params.dst = Parameter::Reg32(R::EAX);
op.params.src = Parameter::Imm32(self.read_u32(mmu));
}
}
}
0x3E => {
op.segment_prefix = Segment::DS;
self.decode(&mut mmu, &mut op);
op.length += 1;
return;
}
0x3F => op.command = Op::Aas,
0x40..=0x47 => match op.op_size {
OperandSize::_16bit => {
op.command = Op::Inc16;
op.params.dst = Parameter::Reg16(r16(b & 7));
}
OperandSize::_32bit => {
op.command = Op::Inc32;
op.params.dst = Parameter::Reg32(r32(b & 7));
}
},
0x48..=0x4F => match op.op_size {
OperandSize::_16bit => {
op.command = Op::Dec16;
op.params.dst = Parameter::Reg16(r16(b & 7));
}
OperandSize::_32bit => {
op.command = Op::Dec32;
op.params.dst = Parameter::Reg32(r32(b & 7));
}
},
0x50..=0x57 => match op.op_size {
OperandSize::_16bit => {
op.command = Op::Push16;
op.params.dst = Parameter::Reg16(r16(b & 7));
}
OperandSize::_32bit => {
op.command = Op::Push32;
op.params.dst = Parameter::Reg32(r32(b & 7));
}
},
0x58..=0x5F => match op.op_size {
OperandSize::_16bit => {
op.command = Op::Pop16;
op.params.dst = Parameter::Reg16(r16(b & 7));
}
OperandSize::_32bit => {
op.command = Op::Pop32;
op.params.dst = Parameter::Reg32(r32(b & 7));
}
},
0x60 => op.command = match op.op_size {
OperandSize::_16bit => Op::Pusha16,
OperandSize::_32bit => Op::Pushad32,
},
0x61 => op.command = match op.op_size {
OperandSize::_16bit => Op::Popa16,
OperandSize::_32bit => Op::Popad32,
},
0x62 => {
op.command = Op::Bound;
op.params = self.r16_rm16(&mut mmu, op);
}
0x63 => {
op.command = Op::Arpl;
op.params = self.rm16_r16(&mut mmu, op);
}
0x64 => {
op.segment_prefix = Segment::FS;
self.decode(&mut mmu, &mut op);
op.length += 1;
return;
}
0x65 => {
op.segment_prefix = Segment::GS;
self.decode(&mut mmu, &mut op);
op.length += 1;
return;
}
0x66 => {
op.op_size = OperandSize::_32bit;
self.decode(&mut mmu, &mut op);
op.length += 1;
return;
}
0x67 => {
op.address_size = AddressSize::_32bit;
self.decode(&mut mmu, &mut op);
op.length += 1;
return;
}
0x68 => {
op.command = Op::Push16;
op.params.dst = Parameter::Imm16(self.read_u16(mmu));
}
0x69 => match op.op_size {
OperandSize::_16bit => {
op.command = Op::Imul16;
op.params = self.r16_rm16(&mut mmu, op);
op.params.src2 = Parameter::Imm16(self.read_u16(mmu));
}
OperandSize::_32bit => {
op.command = Op::Imul32;
op.params = self.r32_rm32(&mut mmu, op);
op.params.src2 = Parameter::Imm32(self.read_u32(mmu));
}
},
0x6A => {
op.command = Op::Push16;
op.params.dst = Parameter::ImmS8(self.read_s8(mmu));
}
0x6B => match op.op_size {
OperandSize::_16bit => {
op.command = Op::Imul16;
op.params = self.r16_rm16(&mut mmu, op);
op.params.src2 = Parameter::Imm8(self.read_u8(mmu));
}
OperandSize::_32bit => {
op.command = Op::Imul32;
op.params = self.r32_rm32(&mut mmu, op);
op.params.src2 = Parameter::Imm8(self.read_u8(mmu));
}
},
0x6C => op.command = Op::Insb,
0x6D => op.command = Op::Insw,
0x6E => op.command = Op::Outsb,
0x6F => op.command = Op::Outsw,
0x70 => {
op.command = Op::Jo;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0x71 => {
op.command = Op::Jno;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0x72 => {
op.command = Op::Jc;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0x73 => {
op.command = Op::Jnc;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0x74 => {
op.command = Op::Jz;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0x75 => {
op.command = Op::Jnz;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0x76 => {
op.command = Op::Jna;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0x77 => {
op.command = Op::Ja;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0x78 => {
op.command = Op::Js;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0x79 => {
op.command = Op::Jns;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0x7A => {
op.command = Op::Jpe;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0x7B => {
op.command = Op::Jpo;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0x7C => {
op.command = Op::Jl;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0x7D => {
op.command = Op::Jnl;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0x7E => {
op.command = Op::Jng;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0x7F => {
op.command = Op::Jg;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0x80 | 0x82 => {
let x = self.read_mod_reg_rm(mmu);
op.params.dst = self.rm8(&mut mmu, op.segment_prefix, x.rm, x.md);
op.params.src = Parameter::Imm8(self.read_u8(mmu));
op.command = match x.reg {
0 => Op::Add8,
1 => Op::Or8,
2 => Op::Adc8,
3 => Op::Sbb8,
4 => Op::And8,
5 => Op::Sub8,
6 => Op::Xor8,
7 => Op::Cmp8,
_ => unreachable!(),
};
}
0x81 => {
let x = self.read_mod_reg_rm(mmu);
match op.op_size {
OperandSize::_16bit => {
op.params.dst = self.rm16(&mut mmu, op, x.rm, x.md);
op.params.src = Parameter::Imm16(self.read_u16(mmu));
op.command = match x.reg {
0 => Op::Add16,
1 => Op::Or16,
2 => Op::Adc16,
3 => Op::Sbb16,
4 => Op::And16,
5 => Op::Sub16,
6 => Op::Xor16,
7 => Op::Cmp16,
_ => unreachable!(),
};
}
OperandSize::_32bit => {
op.params.dst = self.rm32(&mut mmu, op, x.rm, x.md);
op.params.src = Parameter::Imm32(self.read_u32(mmu));
op.command = match x.reg {
0 => Op::Add32,
1 => Op::Or32,
2 => Op::Adc32,
3 => Op::Sbb32,
4 => Op::And32,
5 => Op::Sub32,
6 => Op::Xor32,
7 => Op::Cmp32,
_ => Op::Invalid(vec!(b), Invalid::Reg(x.reg)),
};
}
}
}
0x83 => {
let x = self.read_mod_reg_rm(mmu);
match op.op_size {
OperandSize::_16bit => {
op.params.dst = self.rm16(&mut mmu, op, x.rm, x.md);
op.params.src = Parameter::ImmS8(self.read_s8(mmu));
op.command = match x.reg {
0 => Op::Add16,
1 => Op::Or16,
2 => Op::Adc16,
3 => Op::Sbb16,
4 => Op::And16,
5 => Op::Sub16,
6 => Op::Xor16,
7 => Op::Cmp16,
_ => unreachable!(),
};
}
OperandSize::_32bit => {
op.params.dst = self.rm32(&mut mmu, op, x.rm, x.md);
op.params.src = Parameter::ImmS8(self.read_s8(mmu));
op.command = match x.reg {
0 => Op::Add32,
1 => Op::Or32,
2 => Op::Adc32,
3 => Op::Sbb32,
4 => Op::And32,
5 => Op::Sub32,
6 => Op::Xor32,
7 => Op::Cmp32,
_ => Op::Invalid(vec!(b), Invalid::Reg(x.reg)),
};
}
}
}
0x84 => {
op.command = Op::Test8;
op.params = self.rm8_r8(&mut mmu, op.segment_prefix);
}
0x85 => {
op.command = Op::Test16;
op.params = self.rm16_r16(&mut mmu, op);
}
0x86 => {
op.command = Op::Xchg8;
op.params = self.rm8_r8(&mut mmu, op.segment_prefix);
}
0x87 => {
op.command = Op::Xchg16;
op.params = self.rm16_r16(&mut mmu, op);
}
0x88 => {
op.command = Op::Mov8;
op.params = self.rm8_r8(&mut mmu, op.segment_prefix);
}
0x89 => {
self.prefixed_16_32_rm_r(&mut mmu, &mut op, Op::Mov16, Op::Mov32)
}
0x8A => {
op.command = Op::Mov8;
op.params = self.r8_rm8(&mut mmu, op.segment_prefix);
}
0x8B => {
self.prefixed_16_32_r_rm(&mut mmu, &mut op, Op::Mov16, Op::Mov32)
}
0x8C => {
op.command = Op::Mov16;
op.params = self.rm16_sreg(&mut mmu, op);
}
0x8D => {
op.command = Op::Lea16;
op.params = self.r16_m16(&mut mmu, op);
}
0x8E => {
op.command = Op::Mov16;
op.params = self.sreg_rm16(&mut mmu, op);
}
0x8F => {
let x = self.read_mod_reg_rm(mmu);
op.params.dst = self.rm16(&mut mmu, op, x.rm, x.md);
op.command = match x.reg {
0 => Op::Pop16,
_ => Op::Invalid(vec!(b), Invalid::FPUOp),
};
}
0x90 => op.command = Op::Nop,
0x91..=0x97 => match op.op_size {
OperandSize::_16bit => {
op.command = Op::Xchg16;
op.params.dst = Parameter::Reg16(R::AX);
op.params.src = Parameter::Reg16(r16(b & 7));
}
OperandSize::_32bit => {
op.command = Op::Xchg32;
op.params.dst = Parameter::Reg32(R::EAX);
op.params.src = Parameter::Reg32(r32(b & 7));
}
},
0x98 => {
op.command = match op.op_size {
OperandSize::_16bit => Op::Cbw,
OperandSize::_32bit => Op::Cwde32,
};
}
0x99 => op.command = Op::Cwd16,
0x9A => {
op.command = Op::CallFar;
let imm = self.read_u16(mmu);
let seg = self.read_u16(mmu);
op.params.dst = Parameter::Ptr16Imm(seg, imm);
}
0x9B => {
op.command = Op::Invalid(vec!(b), Invalid::FPUOp);
}
0x9C => op.command = Op::Pushf,
0x9D => op.command = Op::Popf,
0x9E => op.command = Op::Sahf,
0x9F => op.command = Op::Lahf,
0xA0 => {
op.command = Op::Mov8;
op.params.dst = Parameter::Reg8(R::AL);
op.params.src = Parameter::Ptr8(op.segment_prefix, self.read_u16(mmu));
}
0xA1 => match op.op_size {
OperandSize::_16bit => {
op.command = Op::Mov16;
op.params.dst = Parameter::Reg16(R::AX);
op.params.src = Parameter::Ptr16(op.segment_prefix, self.read_u16(mmu));
}
OperandSize::_32bit => {
op.command = Op::Mov32;
op.params.dst = Parameter::Reg32(R::EAX);
op.params.src = Parameter::Ptr32(op.segment_prefix, self.read_u16(mmu));
}
},
0xA2 => {
op.command = Op::Mov8;
op.params.dst = Parameter::Ptr8(op.segment_prefix, self.read_u16(mmu));
op.params.src = Parameter::Reg8(R::AL);
}
0xA3 => match op.op_size {
OperandSize::_16bit => {
op.command = Op::Mov16;
op.params.dst = Parameter::Ptr16(op.segment_prefix, self.read_u16(mmu));
op.params.src = Parameter::Reg16(R::AX);
}
OperandSize::_32bit => {
op.command = Op::Mov32;
op.params.dst = Parameter::Ptr32(op.segment_prefix, self.read_u16(mmu));
op.params.src = Parameter::Reg32(R::EAX);
}
},
0xA4 => op.command = Op::Movsb,
0xA5 => op.command = match op.op_size {
OperandSize::_16bit => Op::Movsw,
OperandSize::_32bit => Op::Movsd,
},
0xA6 => op.command = Op::Cmpsb,
0xA7 => op.command = Op::Cmpsw,
0xA8 => {
op.command = Op::Test8;
op.params.dst = Parameter::Reg8(R::AL);
op.params.src = Parameter::Imm8(self.read_u8(mmu));
}
0xA9 => {
op.command = Op::Test16;
op.params.dst = Parameter::Reg16(R::AX);
op.params.src = Parameter::Imm16(self.read_u16(mmu));
}
0xAA => op.command = Op::Stosb,
0xAB => op.command = match op.op_size {
OperandSize::_16bit => Op::Stosw,
OperandSize::_32bit => Op::Stosd,
},
0xAC => op.command = Op::Lodsb,
0xAD => op.command = match op.op_size {
OperandSize::_16bit => Op::Lodsw,
OperandSize::_32bit => Op::Lodsd,
},
0xAE => op.command = Op::Scasb,
0xAF => op.command = Op::Scasw,
0xB0..=0xB7 => {
op.command = Op::Mov8;
op.params.dst = Parameter::Reg8(r8(b & 7));
op.params.src = Parameter::Imm8(self.read_u8(mmu));
}
0xB8..=0xBF => match op.op_size {
OperandSize::_16bit => {
op.command = Op::Mov16;
op.params.dst = Parameter::Reg16(r16(b & 7));
op.params.src = Parameter::Imm16(self.read_u16(mmu));
}
OperandSize::_32bit => {
op.command = Op::Mov32;
op.params.dst = Parameter::Reg32(r32(b & 7));
op.params.src = Parameter::Imm32(self.read_u32(mmu));
}
},
0xC0 => {
let x = self.read_mod_reg_rm(mmu);
op.command = match x.reg {
0 => Op::Rol8,
1 => Op::Ror8,
2 => Op::Rcl8,
3 => Op::Rcr8,
4 => Op::Shl8,
5 => Op::Shr8,
7 => Op::Sar8,
_ => Op::Invalid(vec!(b), Invalid::Reg(x.reg)),
};
op.params.dst = self.rm8(&mut mmu, op.segment_prefix, x.rm, x.md);
op.params.src = Parameter::Imm8(self.read_u8(mmu));
}
0xC1 => {
let x = self.read_mod_reg_rm(mmu);
match op.op_size {
OperandSize::_16bit => {
op.command = match x.reg {
0 => Op::Rol16,
1 => Op::Ror16,
2 => Op::Rcl16,
3 => Op::Rcr16,
4 => Op::Shl16,
5 => Op::Shr16,
7 => Op::Sar16,
_ => Op::Invalid(vec!(b), Invalid::Reg(x.reg)),
};
op.params.dst = self.rm16(&mut mmu, op, x.rm, x.md);
op.params.src = Parameter::Imm8(self.read_u8(mmu));
}
OperandSize::_32bit => {
op.command = match x.reg {
0 => Op::Rol32,
1 => Op::Ror32,
2 => Op::Rcl32,
3 => Op::Rcr32,
4 => Op::Shl32,
5 => Op::Shr32,
7 => Op::Sar32,
_ => Op::Invalid(vec!(b), Invalid::Reg(x.reg)),
};
op.params.dst = self.rm32(&mut mmu, op, x.rm, x.md);
op.params.src = Parameter::Imm8(self.read_u8(mmu));
}
}
}
0xC2 => {
op.command = Op::Retn;
op.params.dst = Parameter::Imm16(self.read_u16(mmu));
}
0xC3 => op.command = Op::Retn,
0xC4 => {
op.command = Op::Les;
op.params = self.r16_m16(&mut mmu, op);
}
0xC5 => {
op.command = Op::Lds;
op.params = self.r16_m16(&mut mmu, op);
}
0xC6 => {
let x = self.read_mod_reg_rm(mmu);
op.params.dst = self.rm8(&mut mmu, op.segment_prefix, x.rm, x.md);
op.params.src = Parameter::Imm8(self.read_u8(mmu));
op.command = match x.reg {
0 => Op::Mov8,
_ => Op::Invalid(vec!(b), Invalid::Reg(x.reg)),
};
}
0xC7 => {
let x = self.read_mod_reg_rm(mmu);
match op.op_size {
OperandSize::_16bit => {
op.params.dst = self.rm16(&mut mmu, op, x.rm, x.md);
op.params.src = Parameter::Imm16(self.read_u16(mmu));
op.command = match x.reg {
0 => Op::Mov16,
_ => Op::Invalid(vec!(b), Invalid::Reg(x.reg)),
};
}
OperandSize::_32bit => {
op.params.dst = self.rm32(&mut mmu, op, x.rm, x.md);
op.params.src = Parameter::Imm32(self.read_u32(mmu));
op.command = match x.reg {
0 => Op::Mov32,
_ => Op::Invalid(vec!(b), Invalid::Reg(x.reg)),
};
}
}
}
0xC8 => {
op.command = Op::Enter;
op.params.dst = Parameter::Imm16(self.read_u16(mmu));
op.params.src = Parameter::Imm8(self.read_u8(mmu));
}
0xC9 => op.command = Op::Leave,
0xCA => {
op.command = Op::Retf;
op.params.dst = Parameter::Imm16(self.read_u16(mmu));
}
0xCB => op.command = Op::Retf,
0xCC => {
op.command = Op::Int;
op.params.dst = Parameter::Imm8(3);
}
0xCD => {
op.command = Op::Int;
op.params.dst = Parameter::Imm8(self.read_u8(mmu));
}
0xCE => op.command = Op::Into,
0xCF => op.command = Op::Iret,
0xD0 => {
let x = self.read_mod_reg_rm(mmu);
op.command = match x.reg {
0 => Op::Rol8,
1 => Op::Ror8,
2 => Op::Rcl8,
3 => Op::Rcr8,
4 => Op::Shl8,
5 => Op::Shr8,
7 => Op::Sar8,
_ => Op::Invalid(vec!(b), Invalid::Reg(x.reg)),
};
op.params.dst = self.rm8(&mut mmu, op.segment_prefix, x.rm, x.md);
op.params.src = Parameter::Imm8(1);
}
0xD1 => {
let x = self.read_mod_reg_rm(mmu);
op.command = match x.reg {
0 => Op::Rol16,
1 => Op::Ror16,
2 => Op::Rcl16,
3 => Op::Rcr16,
4 => Op::Shl16,
5 => Op::Shr16,
7 => Op::Sar16,
_ => Op::Invalid(vec!(b), Invalid::Reg(x.reg)),
};
op.params.dst = self.rm16(&mut mmu, op, x.rm, x.md);
op.params.src = Parameter::Imm16(1);
}
0xD2 => {
let x = self.read_mod_reg_rm(mmu);
op.command = match x.reg {
0 => Op::Rol8,
1 => Op::Ror8,
2 => Op::Rcl8,
3 => Op::Rcr8,
4 => Op::Shl8,
5 => Op::Shr8,
7 => Op::Sar8,
_ => Op::Invalid(vec!(b), Invalid::Reg(x.reg)),
};
op.params.dst = self.rm8(&mut mmu, op.segment_prefix, x.rm, x.md);
op.params.src = Parameter::Reg8(R::CL);
}
0xD3 => {
let x = self.read_mod_reg_rm(mmu);
op.command = match x.reg {
0 => Op::Rol16,
1 => Op::Ror16,
2 => Op::Rcl16,
3 => Op::Rcr16,
4 => Op::Shl16,
5 => Op::Shr16,
7 => Op::Sar16,
_ => Op::Invalid(vec!(b), Invalid::Reg(x.reg)),
};
op.params.dst = self.rm16(&mut mmu, op, x.rm, x.md);
op.params.src = Parameter::Reg8(R::CL);
}
0xD4 => {
op.command = Op::Aam;
op.params.dst = Parameter::Imm8(self.read_u8(mmu));
}
0xD5 => {
op.command = Op::Aad;
op.params.dst = Parameter::Imm8(self.read_u8(mmu));
}
0xD6 => op.command = Op::Salc,
0xD7 => op.command = Op::Xlatb,
0xD8..=0xDF => {
op.command = Op::Invalid(vec!(b), Invalid::FPUOp);
}
0xE0 => {
op.command = Op::Loopne;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0xE1 => {
op.command = Op::Loope;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0xE2 => {
op.command = Op::Loop;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0xE3 => {
op.command = Op::Jcxz;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0xE4 => {
op.command = Op::In8;
op.params.dst = Parameter::Reg8(R::AL);
op.params.src = Parameter::Imm8(self.read_u8(mmu));
}
0xE5 => {
op.command = Op::In16;
op.params.dst = Parameter::Reg16(R::AX);
op.params.src = Parameter::Imm8(self.read_u8(mmu));
}
0xE6 => {
op.command = Op::Out8;
op.params.dst = Parameter::Imm8(self.read_u8(mmu));
op.params.src = Parameter::Reg8(R::AL);
}
0xE7 => {
op.command = Op::Out16;
op.params.dst = Parameter::Imm8(self.read_u8(mmu));
op.params.src = Parameter::Reg16(R::AX);
}
0xE8 => {
op.command = Op::CallNear;
op.params.dst = Parameter::Imm16(self.read_rel16(mmu));
}
0xE9 => {
op.command = Op::JmpNear;
op.params.dst = Parameter::Imm16(self.read_rel16(mmu));
}
0xEA => {
op.command = Op::JmpFar;
let imm = self.read_u16(mmu);
let seg = self.read_u16(mmu);
op.params.dst = Parameter::Ptr16Imm(seg, imm);
}
0xEB => {
op.command = Op::JmpShort;
op.params.dst = Parameter::Imm16(self.read_rel8(mmu));
}
0xEC => {
op.command = Op::In8;
op.params.dst = Parameter::Reg8(R::AL);
op.params.src = Parameter::Reg16(R::DX);
}
0xED => {
op.command = Op::In16;
op.params.dst = Parameter::Reg16(R::AX);
op.params.src = Parameter::Reg16(R::DX);
}
0xEE => {
op.command = Op::Out8;
op.params.dst = Parameter::Reg16(R::DX);
op.params.src = Parameter::Reg8(R::AL);
}
0xEF => {
op.command = Op::Out16;
op.params.dst = Parameter::Reg16(R::DX);
op.params.src = Parameter::Reg16(R::AX);
}
0xF0 => {
op.lock = true;
self.decode(&mut mmu, &mut op);
op.length += 1;
return;
}
0xF1 => {
op.command = Op::Int;
op.params.dst = Parameter::Imm8(1);
}
0xF2 => {
op.repeat = RepeatMode::Repne;
self.decode(&mut mmu, &mut op);
op.length += 1;
return;
}
0xF3 => {
self.decode(&mut mmu, &mut op);
op.length += 1;
match op.command {
Op::Insb | Op::Insw |
Op::Outsb | Op::Outsw |
Op::Movsb | Op::Movsw | Op::Movsd |
Op::Stosb | Op::Stosw | Op::Stosd |
Op::Lodsb | Op::Lodsw | Op::Lodsd => {
op.repeat = RepeatMode::Rep;
}
Op::Cmpsb | Op::Cmpsw |
Op::Scasb | Op::Scasw => {
op.repeat = RepeatMode::Repe;
}
_ => op.command = Op::Invalid(vec!(b), Invalid::Op),
}
return;
}
0xF4 => op.command = Op::Hlt,
0xF5 => op.command = Op::Cmc,
0xF6 => {
let x = self.read_mod_reg_rm(mmu);
op.params.dst = self.rm8(&mut mmu, op.segment_prefix, x.rm, x.md);
match x.reg {
0 | 1 => {
op.command = Op::Test8;
op.params.src = Parameter::Imm8(self.read_u8(mmu));
}
2 => op.command = Op::Not8,
3 => op.command = Op::Neg8,
4 => op.command = Op::Mul8,
5 => op.command = Op::Imul8,
6 => op.command = Op::Div8,
7 => op.command = Op::Idiv8,
_ => unreachable!(),
}
}
0xF7 => {
let x = self.read_mod_reg_rm(mmu);
match op.op_size {
OperandSize::_16bit => {
op.params.dst = self.rm16(&mut mmu, op, x.rm, x.md);
match x.reg {
0 | 1 => {
op.command = Op::Test16;
op.params.src = Parameter::Imm16(self.read_u16(mmu));
}
2 => op.command = Op::Not16,
3 => op.command = Op::Neg16,
4 => op.command = Op::Mul16,
5 => op.command = Op::Imul16,
6 => op.command = Op::Div16,
7 => op.command = Op::Idiv16,
_ => unreachable!(),
}
}
OperandSize::_32bit => {
op.params.dst = self.rm32(&mut mmu, op, x.rm, x.md);
op.command = match x.reg {
0 | 1 => {
op.command = Op::Test32;
op.params.src = Parameter::Imm32(self.read_u32(mmu));
panic!("XXX 32bit verify params: {}", op);
}
2 => Op::Not32,
3 => Op::Neg32,
4 => Op::Mul32,
5 => Op::Imul32,
6 => Op::Div32,
7 => Op::Idiv32,
_ => Op::Invalid(vec!(b), Invalid::Reg(x.reg)),
};
}
}
}
0xF8 => op.command = Op::Clc,
0xF9 => op.command = Op::Stc,
0xFA => op.command = Op::Cli,
0xFB => op.command = Op::Sti,
0xFC => op.command = Op::Cld,
0xFD => op.command = Op::Std,
0xFE => {
let x = self.read_mod_reg_rm(mmu);
op.params.dst = self.rm8(&mut mmu, op.segment_prefix, x.rm, x.md);
op.command = match x.reg {
0 | 2 => Op::Inc8,
1 => Op::Dec8,
_ => Op::Invalid(vec!(b), Invalid::Reg(x.reg)),
};
}
0xFF => {
let x = self.read_mod_reg_rm(mmu);
match op.op_size {
OperandSize::_16bit => {
op.params.dst = self.rm16(&mut mmu, op, x.rm, x.md);
op.command = match x.reg {
0 => Op::Inc16,
1 => Op::Dec16,
2 => Op::CallNear,
3 => Op::CallFar,
4 => Op::JmpNear,
5 => Op::JmpFar,
6 => Op::Push16,
_ => Op::Invalid(vec!(b), Invalid::Reg(x.reg)),
};
}
OperandSize::_32bit => {
op.params.dst = self.rm32(&mut mmu, op, x.rm, x.md);
op.command = match x.reg {
0 => Op::Inc32,
1 => Op::Dec32,
_ => Op::Invalid(vec!(b), Invalid::Reg(x.reg)),
};
}
}
}
}
op.length = (Wrapping(u16::from(op.length)) + Wrapping(self.current_offset) - Wrapping(start_offset)).0 as u8;
if DEBUG_DECODER {
}
}
fn prefixed_16_32_rm_r(&mut self, mut mmu: &mut MMU, op: &mut Instruction, op16: Op, op32: Op) {
match op.op_size {
OperandSize::_16bit => {
op.command = op16;
op.params = self.rm16_r16(&mut mmu, op);
}
OperandSize::_32bit => {
op.command = op32;
op.params = self.rm32_r32(&mut mmu, op);
}
}
}
fn prefixed_16_32_r_rm(&mut self, mut mmu: &mut MMU, op: &mut Instruction, op16: Op, op32: Op) {
match op.op_size {
OperandSize::_16bit => {
op.command = op16;
op.params = self.r16_rm16(&mut mmu, op);
}
OperandSize::_32bit => {
op.command = op32;
op.params = self.r32_rm32(&mut mmu, op);
}
}
}
fn rm8(&mut self, mmu: &mut MMU, seg: Segment, rm: u8, md: u8) -> Parameter {
let adr_size = AddressSize::_16bit;
match md {
0 => {
if rm == 6 {
Parameter::Ptr8(seg, self.read_u16(mmu))
} else {
Parameter::Ptr8Amode(seg, adr_size.amode_from(rm))
}
}
1 => Parameter::Ptr8AmodeS8(seg, adr_size.amode_from(rm), self.read_s8(mmu)),
2 => Parameter::Ptr8AmodeS16(seg, adr_size.amode_from(rm), self.read_s16(mmu)),
3 => Parameter::Reg8(r8(rm)),
_ => unreachable!(),
}
}
fn rm16(&mut self, mmu: &mut MMU, op: &Instruction, rm: u8, md: u8) -> Parameter {
match md {
0 => {
if rm == 6 {
Parameter::Ptr16(op.segment_prefix, self.read_u16(mmu))
} else {
Parameter::Ptr16Amode(op.segment_prefix, op.address_size.amode_from(rm))
}
}
1 => Parameter::Ptr16AmodeS8(op.segment_prefix, op.address_size.amode_from(rm), self.read_s8(mmu)),
2 => Parameter::Ptr16AmodeS16(op.segment_prefix, op.address_size.amode_from(rm), self.read_s16(mmu)),
3 => Parameter::Reg16(r16(rm)),
_ => unreachable!(),
}
}
fn rm32(&mut self, mmu: &mut MMU, op: &Instruction, rm: u8, md: u8) -> Parameter {
match md {
0 => {
if rm == 6 {
Parameter::Ptr32(op.segment_prefix, self.read_u16(mmu))
} else {
Parameter::Ptr32Amode(op.segment_prefix, op.address_size.amode_from(rm))
}
}
1 => Parameter::Ptr32AmodeS8(op.segment_prefix, op.address_size.amode_from(rm), self.read_s8(mmu)),
2 => Parameter::Ptr32AmodeS16(op.segment_prefix, op.address_size.amode_from(rm), self.read_s16(mmu)),
3 => Parameter::Reg32(r32(rm)),
_ => unreachable!(),
}
}
fn r8_rm8(&mut self, mut mmu: &mut MMU, seg: Segment) -> ParameterSet {
let x = self.read_mod_reg_rm(mmu);
ParameterSet {
dst: Parameter::Reg8(r8(x.reg)),
src: self.rm8(&mut mmu, seg, x.rm, x.md),
src2: Parameter::None,
}
}
fn rm8_r8(&mut self, mut mmu: &mut MMU, seg: Segment) -> ParameterSet {
let x = self.read_mod_reg_rm(mmu);
ParameterSet {
dst: self.rm8(&mut mmu, seg, x.rm, x.md),
src: Parameter::Reg8(r8(x.reg)),
src2: Parameter::None,
}
}
fn sreg_rm16(&mut self, mut mmu: &mut MMU, op: &Instruction) -> ParameterSet {
let x = self.read_mod_reg_rm(mmu);
ParameterSet {
dst: Parameter::SReg16(sr(x.reg)),
src: self.rm16(&mut mmu, op, x.rm, x.md),
src2: Parameter::None,
}
}
fn rm16_sreg(&mut self, mut mmu: &mut MMU, op: &Instruction) -> ParameterSet {
let x = self.read_mod_reg_rm(mmu);
ParameterSet {
dst: self.rm16(&mut mmu, op, x.rm, x.md),
src: Parameter::SReg16(sr(x.reg)),
src2: Parameter::None,
}
}
fn r16_rm8(&mut self, mut mmu: &mut MMU, seg: Segment) -> ParameterSet {
let x = self.read_mod_reg_rm(mmu);
ParameterSet {
dst: Parameter::Reg16(r16(x.reg)),
src: self.rm8(&mut mmu, seg, x.rm, x.md),
src2: Parameter::None,
}
}
fn r32_rm8(&mut self, mut mmu: &mut MMU, seg: Segment) -> ParameterSet {
let x = self.read_mod_reg_rm(mmu);
ParameterSet {
dst: Parameter::Reg32(r32(x.reg)),
src: self.rm8(&mut mmu, seg, x.rm, x.md),
src2: Parameter::None,
}
}
fn r32_rm16(&mut self, mut mmu: &mut MMU, op: &Instruction) -> ParameterSet {
let x = self.read_mod_reg_rm(mmu);
ParameterSet {
dst: Parameter::Reg32(r32(x.reg)),
src: self.rm16(&mut mmu, op, x.rm, x.md),
src2: Parameter::None,
}
}
fn r16_rm16(&mut self, mut mmu: &mut MMU, op: &Instruction) -> ParameterSet {
let x = self.read_mod_reg_rm(mmu);
ParameterSet {
dst: Parameter::Reg16(r16(x.reg)),
src: self.rm16(&mut mmu, op, x.rm, x.md),
src2: Parameter::None,
}
}
fn rm16_r16(&mut self, mut mmu: &mut MMU, op: &Instruction) -> ParameterSet {
let x = self.read_mod_reg_rm(mmu);
ParameterSet {
dst: self.rm16(&mut mmu, op, x.rm, x.md),
src: Parameter::Reg16(r16(x.reg)),
src2: Parameter::None,
}
}
fn r16_m16(&mut self, mut mmu: &mut MMU, op: &Instruction) -> ParameterSet {
let x = self.read_mod_reg_rm(mmu);
if x.md == 3 {
println!("r16_m16 error: invalid encoding, ip={:04X}", self.current_offset);
}
ParameterSet {
dst: Parameter::Reg16(r16(x.reg)),
src: self.rm16(&mut mmu, op, x.rm, x.md),
src2: Parameter::None,
}
}
fn r32_rm32(&mut self, mut mmu: &mut MMU, op: &Instruction) -> ParameterSet {
let x = self.read_mod_reg_rm(mmu);
ParameterSet {
dst: Parameter::Reg32(r32(x.reg)),
src: self.rm32(&mut mmu, op, x.rm, x.md),
src2: Parameter::None,
}
}
fn rm32_r32(&mut self, mut mmu: &mut MMU, op: &Instruction) -> ParameterSet {
let x = self.read_mod_reg_rm(mmu);
ParameterSet {
dst: self.rm32(&mut mmu, op, x.rm, x.md),
src: Parameter::Reg32(r32(x.reg)),
src2: Parameter::None,
}
}
fn read_mod_reg_rm(&mut self, mmu: &MMU) -> ModRegRm {
let b = mmu.read_u8(self.current_seg, self.current_offset);
self.current_offset += 1;
let res = ModRegRm {
md: b >> 6,
reg: (b >> 3) & 7,
rm: b & 7,
};
if DEBUG_DECODER {
}
res
}
fn read_rel8(&mut self, mmu: &MMU) -> u16 {
let val = self.read_s8(mmu);
(self.current_offset as isize + val as isize) as u16
}
fn read_rel16(&mut self, mmu: &MMU) -> u16 {
let val = self.read_s16(mmu);
(self.current_offset as isize + val as isize) as u16
}
fn read_u8(&mut self, mmu: &MMU) -> u8 {
let b = mmu.read_u8(self.current_seg, self.current_offset);
self.current_offset = (Wrapping(self.current_offset) + Wrapping(1)).0;
b
}
fn read_s8(&mut self, mmu: &MMU) -> i8 {
self.read_u8(mmu) as i8
}
fn read_u16(&mut self, mmu: &MMU) -> u16 {
let lo = self.read_u8(mmu);
let hi = self.read_u8(mmu);
u16::from(hi) << 8 | u16::from(lo)
}
fn read_u32(&mut self, mmu: &MMU) -> u32 {
let lo = self.read_u16(mmu);
let hi = self.read_u16(mmu);
u32::from(hi) << 16 | u32::from(lo)
}
fn read_s16(&mut self, mmu: &MMU) -> i16 {
self.read_u16(mmu) as i16
}
fn current_flat(&self) -> u32 {
MemoryAddress::RealSegmentOffset(self.current_seg, self.current_offset).value()
}
}
pub fn instruction_info_to_str(ops: &[InstructionInfo]) -> String {
let mut lines = Vec::new();
for op in ops {
lines.push(op.to_string())
}
lines.join("\n")
}
pub fn instructions_to_str(ops: &[Instruction]) -> String {
let mut lines = Vec::new();
for op in ops {
lines.push(op.to_string())
}
lines.join("\n")
}