diff --git a/src/interpreter/computer.rs b/src/interpreter/computer.rs index c2a1618..3487113 100644 --- a/src/interpreter/computer.rs +++ b/src/interpreter/computer.rs @@ -110,6 +110,20 @@ impl Computer { self.op(op, flag_set, false, dest, src); } + /// Perform test operation, which acts like [`Self::and()`], but without + /// saving the result and only setting [`Self::flags`]. + pub fn test(&mut self, dest: ModRmTarget, src: Operand) { + let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs & rhs; + let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, _, _| { + flags.cf = false; + flags.of = false; + flags.zf = result.zero(); + flags.sf = result.msb(); + flags.pf = result.parity(); + }; + self.op(op, flag_set, false, dest, src); + } + /// Perform `dest` = `dest` + `src` + CF. Sets flags. pub fn adc(&mut self, dest: ModRmTarget, src: Operand) { let cf = self.flags.cf as u8; diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index 279feef..ec705a3 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -3,7 +3,7 @@ use std::{fmt::Debug, process::exit}; use crate::{ instructions::{Instruction, Mnemonic}, - interpreter::interrupt::Mess1, + interpreter::{interrupt::Mess1, memory::Memory}, operands::{Byte, ImmediateOperand, ModRmTarget}, }; @@ -366,10 +366,40 @@ impl Interpreter { /* * Test */ + Mnemonic::TEST(dest, src) => self + .computer + .test(dest, Operand::ModRmTarget(ModRmTarget::Register(src))), + Mnemonic::TEST_Ib(dest, src) => self + .computer + .test(dest, Operand::Immediate(ImmediateOperand::Byte(src))), + Mnemonic::TEST_Iv(dest, src) => self + .computer + .test(dest, Operand::Immediate(ImmediateOperand::Word(src))), + Mnemonic::TEST_ALIb(src_byte) => self.computer.test( + ModRmTarget::Register(crate::register::Register::AL), + Operand::Immediate(ImmediateOperand::Byte(src_byte)), + ), + Mnemonic::TEST_AXIv(src_word) => self.computer.test( + ModRmTarget::Register(crate::register::Register::AX), + Operand::Immediate(ImmediateOperand::Word(src_word)), + ), /* * XCHG */ + Mnemonic::XCHG(target, reg) => { + let tmp = self.computer.read_modrm(target); + self.computer + .write_modrm(target, self.computer.regs.read(reg)); + self.computer.regs.write(reg, tmp); + } + Mnemonic::XCHG_AX(reg) => { + let tmp = self.computer.regs.read(reg); + self.computer + .regs + .write(reg, self.computer.regs.ax.read().into()); + self.computer.regs.write(reg, tmp); + } /* * MOV @@ -411,14 +441,37 @@ impl Interpreter { /* * LEA */ + Mnemonic::LEA(target, reg) => { + let val = match target { + ModRmTarget::Memory(idx) => Memory::calc_memidx(&self.computer.regs, idx), + ModRmTarget::Register(reg) => self.computer.regs.read(reg), + }; + self.computer.regs.write(reg, val); + } /* * Sign extensions */ + Mnemonic::CBW => { + if ImmediateOperand::Byte(self.computer.regs.ax.lower).msb() { + // extend sign bit into AX, i.e. all bits set + self.computer.regs.ax.upper = 0xff; + } + } + Mnemonic::CWD => { + if ImmediateOperand::Word(self.computer.regs.ax.read()).msb() { + // extend sign bit into DX, i.e. all bits set + self.computer.regs.dx.write(0xffff); + } + } /* * Wait */ + Mnemonic::WAIT => { + log::info!("wait"); + continue; + } /* * Push/Pop Flags @@ -439,6 +492,14 @@ impl Interpreter { /* * Not/Neg */ + Mnemonic::NOT(target) => { + self.computer + .write_modrm(target, !self.computer.read_modrm(target)); + } + Mnemonic::NEG(target) => { + let val = !self.computer.read_modrm(target); + self.computer.write_modrm(target, val + 0b1); + } /* * MUL @@ -451,6 +512,10 @@ impl Interpreter { /* * HLT */ + Mnemonic::HLT => { + eprintln!("Processor halted... exiting."); + exit(1); + } /* * Shift and Rotate @@ -472,6 +537,13 @@ impl Interpreter { /* * Flag manipulation */ + Mnemonic::CLC => self.computer.flags.cf = false, + Mnemonic::STC => self.computer.flags.cf = true, + Mnemonic::CLI => self.computer.flags.r#if = false, + Mnemonic::STI => self.computer.flags.r#if = true, + Mnemonic::CLD => self.computer.flags.df = false, + Mnemonic::STD => self.computer.flags.df = true, + Mnemonic::CMC => self.computer.flags.cf = !self.computer.flags.cf, /* * Repeat prefixes @@ -484,6 +556,10 @@ impl Interpreter { /* * Misc */ + Mnemonic::LOCK => { + log::info!("lock#"); + continue; + } _ => log::info!("no action done"), } } diff --git a/src/interpreter/memory.rs b/src/interpreter/memory.rs index 2578f17..c13c447 100644 --- a/src/interpreter/memory.rs +++ b/src/interpreter/memory.rs @@ -66,8 +66,8 @@ impl Memory { } } - /// Calculate the absolute Memory Index from a [`MemoryIndex`] struct. - fn calc_memidx( + /// Calculate the absolute memory address from a [`MemoryIndex`] struct. + pub fn calc_memidx( regs: &crate::interpreter::register::Register, idx: MemoryIndex, ) -> ImmediateOperand { diff --git a/src/operands.rs b/src/operands.rs index 109ef66..7185748 100644 --- a/src/operands.rs +++ b/src/operands.rs @@ -7,7 +7,7 @@ use crate::register::SegmentRegister; use crate::{disasm::DisasmError, register::Register}; use core::fmt; -use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Sub}; +use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Not, Sub}; pub type Byte = u8; // b pub type IByte = i8; // used for displacements of memory access @@ -334,6 +334,17 @@ impl BitXor for ImmediateOperand { } } +impl Not for ImmediateOperand { + type Output = Self; + + fn not(self) -> Self::Output { + match self { + ImmediateOperand::Byte(b) => ImmediateOperand::Byte(!b), + ImmediateOperand::Word(w) => ImmediateOperand::Word(!w), + } + } +} + impl fmt::Display for ImmediateOperand { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self {