ft(interpreter): impl all low-hanging fruit instructions
This commit is contained in:
@@ -110,6 +110,20 @@ impl Computer {
|
|||||||
self.op(op, flag_set, false, dest, src);
|
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.
|
/// Perform `dest` = `dest` + `src` + CF. Sets flags.
|
||||||
pub fn adc(&mut self, dest: ModRmTarget, src: Operand) {
|
pub fn adc(&mut self, dest: ModRmTarget, src: Operand) {
|
||||||
let cf = self.flags.cf as u8;
|
let cf = self.flags.cf as u8;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::{fmt::Debug, process::exit};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
instructions::{Instruction, Mnemonic},
|
instructions::{Instruction, Mnemonic},
|
||||||
interpreter::interrupt::Mess1,
|
interpreter::{interrupt::Mess1, memory::Memory},
|
||||||
operands::{Byte, ImmediateOperand, ModRmTarget},
|
operands::{Byte, ImmediateOperand, ModRmTarget},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -366,10 +366,40 @@ impl Interpreter {
|
|||||||
/*
|
/*
|
||||||
* Test
|
* 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
|
* 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
|
* MOV
|
||||||
@@ -411,14 +441,37 @@ impl Interpreter {
|
|||||||
/*
|
/*
|
||||||
* LEA
|
* 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
|
* 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
|
* Wait
|
||||||
*/
|
*/
|
||||||
|
Mnemonic::WAIT => {
|
||||||
|
log::info!("wait");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Push/Pop Flags
|
* Push/Pop Flags
|
||||||
@@ -439,6 +492,14 @@ impl Interpreter {
|
|||||||
/*
|
/*
|
||||||
* Not/Neg
|
* 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
|
* MUL
|
||||||
@@ -451,6 +512,10 @@ impl Interpreter {
|
|||||||
/*
|
/*
|
||||||
* HLT
|
* HLT
|
||||||
*/
|
*/
|
||||||
|
Mnemonic::HLT => {
|
||||||
|
eprintln!("Processor halted... exiting.");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shift and Rotate
|
* Shift and Rotate
|
||||||
@@ -472,6 +537,13 @@ impl Interpreter {
|
|||||||
/*
|
/*
|
||||||
* Flag manipulation
|
* 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
|
* Repeat prefixes
|
||||||
@@ -484,6 +556,10 @@ impl Interpreter {
|
|||||||
/*
|
/*
|
||||||
* Misc
|
* Misc
|
||||||
*/
|
*/
|
||||||
|
Mnemonic::LOCK => {
|
||||||
|
log::info!("lock#");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
_ => log::info!("no action done"),
|
_ => log::info!("no action done"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,8 +66,8 @@ impl Memory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate the absolute Memory Index from a [`MemoryIndex`] struct.
|
/// Calculate the absolute memory address from a [`MemoryIndex`] struct.
|
||||||
fn calc_memidx(
|
pub fn calc_memidx(
|
||||||
regs: &crate::interpreter::register::Register,
|
regs: &crate::interpreter::register::Register,
|
||||||
idx: MemoryIndex,
|
idx: MemoryIndex,
|
||||||
) -> ImmediateOperand {
|
) -> ImmediateOperand {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use crate::register::SegmentRegister;
|
|||||||
|
|
||||||
use crate::{disasm::DisasmError, register::Register};
|
use crate::{disasm::DisasmError, register::Register};
|
||||||
use core::fmt;
|
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 Byte = u8; // b
|
||||||
pub type IByte = i8; // used for displacements of memory access
|
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 {
|
impl fmt::Display for ImmediateOperand {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
|||||||
Reference in New Issue
Block a user