ft(interpreter): generalize binary operations
This commit is contained in:
@@ -27,30 +27,52 @@ impl Computer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds two [`Argument`]s, saves it to `dest` and sets flags, if necessary.
|
pub fn add(&mut self, dest: ModRmTarget, src: Operand) {
|
||||||
|
let op = |lhs, rhs| lhs + rhs;
|
||||||
|
// TODO let flag_check = |_| ();
|
||||||
|
self.op(op, dest, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sub(&mut self, dest: ModRmTarget, src: Operand) {
|
||||||
|
let op = |lhs, rhs| lhs - rhs;
|
||||||
|
// TODO let flag_check = |_| ();
|
||||||
|
self.op(op, dest, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Applies a binary operator [`O`] to two [`Argument`]s, saves it to `dest`
|
||||||
|
/// and sets flags, if necessary.
|
||||||
/// A value can never be saved to an immediate Operand, so `dest` can only
|
/// A value can never be saved to an immediate Operand, so `dest` can only
|
||||||
/// be a [`ModRmTarget`].
|
/// be a [`ModRmTarget`].
|
||||||
pub fn add(&mut self, dest: ModRmTarget, src: Operand) {
|
fn op<O>(&mut self, op: O, dest: ModRmTarget, src: Operand)
|
||||||
|
where
|
||||||
|
O: Fn(ImmediateOperand, ImmediateOperand) -> ImmediateOperand,
|
||||||
|
// F: Fn(&mut Flags);
|
||||||
|
{
|
||||||
match src {
|
match src {
|
||||||
Operand::ModRmTarget(src_target) => self.add_modrm(dest, src_target),
|
Operand::ModRmTarget(src_target) => self.op_modrm(op, dest, src_target),
|
||||||
Operand::Immediate(src_operand) => self.add_imm(dest, src_operand),
|
Operand::Immediate(src_operand) => self.op_imm(op, dest, src_operand),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds two [`ModRmTarget`]s togeher, saves it to `dest` and sets flags, if necessary.
|
/// Applies a binary operator [`O`] to two [`ModRmTargets`]s, saves it to
|
||||||
fn add_modrm(&mut self, dest: ModRmTarget, src: ModRmTarget) {
|
/// dest and sets flags, if necessary.
|
||||||
|
fn op_modrm<O>(&mut self, op: O, dest: ModRmTarget, src: ModRmTarget)
|
||||||
|
where
|
||||||
|
O: Fn(ImmediateOperand, ImmediateOperand) -> ImmediateOperand,
|
||||||
|
{
|
||||||
match dest {
|
match dest {
|
||||||
ModRmTarget::Memory(dest_memory_idx) => match src {
|
ModRmTarget::Memory(dest_memory_idx) => match src {
|
||||||
// mem, mem
|
// mem, mem
|
||||||
ModRmTarget::Memory(_) => panic!("Cannot add Memory to Memory!"),
|
ModRmTarget::Memory(_) => {
|
||||||
|
panic!("Cannot apply binary operator from Memory to Memory!")
|
||||||
|
}
|
||||||
// mem, reg
|
// mem, reg
|
||||||
ModRmTarget::Register(src_register) => {
|
ModRmTarget::Register(src_register) => {
|
||||||
let lhs = self.memory.read(&self.regs, dest_memory_idx);
|
let lhs = self.memory.read(&self.regs, dest_memory_idx);
|
||||||
let rhs = self.regs.read(src_register);
|
let rhs = self.regs.read(src_register);
|
||||||
let result = lhs + rhs;
|
let result = op(lhs, rhs);
|
||||||
self.memory.write(&self.regs, dest_memory_idx, result);
|
self.memory.write(&self.regs, dest_memory_idx, result);
|
||||||
// unsigned overflow
|
// flag_check(&mut self.flags);
|
||||||
self.flags.of = result < rhs;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ModRmTarget::Register(dest_register) => match src {
|
ModRmTarget::Register(dest_register) => match src {
|
||||||
@@ -58,42 +80,42 @@ impl Computer {
|
|||||||
ModRmTarget::Memory(src_memory_index) => {
|
ModRmTarget::Memory(src_memory_index) => {
|
||||||
let lhs = self.regs.read(dest_register);
|
let lhs = self.regs.read(dest_register);
|
||||||
let rhs = self.memory.read(&self.regs, src_memory_index);
|
let rhs = self.memory.read(&self.regs, src_memory_index);
|
||||||
let result = lhs + rhs;
|
let result = op(lhs, rhs);
|
||||||
self.regs.write(dest_register, result);
|
self.regs.write(dest_register, result);
|
||||||
// unsigned overflow
|
// flag_check(&mut self.flags);
|
||||||
self.flags.of = result < rhs;
|
|
||||||
}
|
}
|
||||||
// reg, reg
|
// reg, reg
|
||||||
ModRmTarget::Register(src_register) => {
|
ModRmTarget::Register(src_register) => {
|
||||||
let lhs = self.regs.read(dest_register);
|
let lhs = self.regs.read(dest_register);
|
||||||
let rhs = self.regs.read(src_register);
|
let rhs = self.regs.read(src_register);
|
||||||
let result = lhs + rhs;
|
let result = op(lhs, rhs);
|
||||||
self.regs.write(dest_register, result);
|
self.regs.write(dest_register, result);
|
||||||
|
// flag_check(&mut self.flags);
|
||||||
// unsigned overflow
|
|
||||||
self.flags.of = result < rhs
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds an [`ImmediateOperand`] to a location pointed to by a
|
/// Applies a binary operator [`O`] to [`ImmediateOperand`] and a location
|
||||||
/// [`ModRmTarget`], saves it to dest and sets flags, if necessary.
|
/// pointed to by a [`ModRmTarget`], saves it to dest and sets flags,
|
||||||
fn add_imm(&mut self, dest: ModRmTarget, src: ImmediateOperand) {
|
/// if necessary.
|
||||||
|
fn op_imm<O>(&mut self, op: O, dest: ModRmTarget, src: ImmediateOperand)
|
||||||
|
where
|
||||||
|
O: Fn(ImmediateOperand, ImmediateOperand) -> ImmediateOperand,
|
||||||
|
// F: for<'F> Fn(&'F mut Flags),
|
||||||
|
{
|
||||||
match dest {
|
match dest {
|
||||||
ModRmTarget::Memory(dest_mem) => {
|
ModRmTarget::Memory(dest_mem) => {
|
||||||
let lhs = self.memory.read(&self.regs, dest_mem);
|
let lhs = self.memory.read(&self.regs, dest_mem);
|
||||||
let result = lhs + src;
|
let result = op(lhs, src);
|
||||||
// unsigned overflow
|
|
||||||
self.flags.of = result < src;
|
|
||||||
self.memory.write(&self.regs, dest_mem, result);
|
self.memory.write(&self.regs, dest_mem, result);
|
||||||
|
// flag_check(&mut self.flags);
|
||||||
}
|
}
|
||||||
ModRmTarget::Register(dest_reg) => {
|
ModRmTarget::Register(dest_reg) => {
|
||||||
let lhs = self.regs.read(dest_reg);
|
let lhs = self.regs.read(dest_reg);
|
||||||
let result = lhs + src;
|
let result = op(lhs, src);
|
||||||
// unsigned overflow
|
|
||||||
self.flags.of = result < src;
|
|
||||||
self.regs.write(dest_reg, result);
|
self.regs.write(dest_reg, result);
|
||||||
|
// flag_check(&mut self.flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,29 @@ impl Interpreter {
|
|||||||
ModRmTarget::Register(crate::register::Register::AX),
|
ModRmTarget::Register(crate::register::Register::AX),
|
||||||
Operand::Immediate(ImmediateOperand::Word(src_word)),
|
Operand::Immediate(ImmediateOperand::Word(src_word)),
|
||||||
),
|
),
|
||||||
|
/*
|
||||||
|
* SUB
|
||||||
|
*/
|
||||||
|
Mnemonic::SUB_FromReg(dest, src) => self
|
||||||
|
.computer
|
||||||
|
.sub(dest, Operand::ModRmTarget(ModRmTarget::Register(src))),
|
||||||
|
Mnemonic::SUB_ToReg(src, dest) => self
|
||||||
|
.computer
|
||||||
|
.sub(ModRmTarget::Register(dest), Operand::ModRmTarget(src)),
|
||||||
|
Mnemonic::SUB_Ib(dest, src) => self
|
||||||
|
.computer
|
||||||
|
.sub(dest, Operand::Immediate(ImmediateOperand::Byte(src))),
|
||||||
|
Mnemonic::SUB_Iv(dest, src) => self
|
||||||
|
.computer
|
||||||
|
.sub(dest, Operand::Immediate(ImmediateOperand::Word(src))),
|
||||||
|
Mnemonic::SUB_ALIb(src_byte) => self.computer.sub(
|
||||||
|
ModRmTarget::Register(crate::register::Register::AL),
|
||||||
|
Operand::Immediate(ImmediateOperand::Byte(src_byte)),
|
||||||
|
),
|
||||||
|
Mnemonic::SUB_AXIv(src_word) => self.computer.sub(
|
||||||
|
ModRmTarget::Register(crate::register::Register::AX),
|
||||||
|
Operand::Immediate(ImmediateOperand::Word(src_word)),
|
||||||
|
),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MOV
|
* MOV
|
||||||
|
|||||||
@@ -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, Sub};
|
use std::ops::{Add, Div, Mul, 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
|
||||||
@@ -88,6 +88,44 @@ impl Sub for ImmediateOperand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Mul for ImmediateOperand {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, other: Self) -> Self {
|
||||||
|
match self {
|
||||||
|
ImmediateOperand::Byte(lhsb) => match other {
|
||||||
|
ImmediateOperand::Byte(rhsb) => ImmediateOperand::Byte(lhsb.wrapping_mul(rhsb)),
|
||||||
|
_ => panic!("Cannot multiply Byte with Word"),
|
||||||
|
},
|
||||||
|
ImmediateOperand::Word(lhsw) => match other {
|
||||||
|
ImmediateOperand::Word(rhsw) => ImmediateOperand::Word(lhsw.wrapping_mul(rhsw)),
|
||||||
|
ImmediateOperand::Byte(rhsb) => {
|
||||||
|
ImmediateOperand::Word(lhsw.wrapping_mul(rhsb as Word))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div for ImmediateOperand {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn div(self, other: Self) -> Self {
|
||||||
|
match self {
|
||||||
|
ImmediateOperand::Byte(lhsb) => match other {
|
||||||
|
ImmediateOperand::Byte(rhsb) => ImmediateOperand::Byte(lhsb.wrapping_div(rhsb)),
|
||||||
|
_ => panic!("Cannot divide Byte with Word"),
|
||||||
|
},
|
||||||
|
ImmediateOperand::Word(lhsw) => match other {
|
||||||
|
ImmediateOperand::Word(rhsw) => ImmediateOperand::Word(lhsw.wrapping_div(rhsw)),
|
||||||
|
ImmediateOperand::Byte(rhsb) => {
|
||||||
|
ImmediateOperand::Word(lhsw.wrapping_div(rhsb as Word))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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