ft: impl flag setting closure for binary operations
This commit is contained in:
@@ -4,13 +4,17 @@ use crate::operands::{ImmediateOperand, ModRmTarget};
|
|||||||
|
|
||||||
use super::{flags::Flags, memory::Memory, register::Register};
|
use super::{flags::Flags, memory::Memory, register::Register};
|
||||||
|
|
||||||
/// Wrapper for easier argument passing of arithmetic operations.
|
/// Wrapper for easier argument passing of multi-type operations.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Operand {
|
pub enum Operand {
|
||||||
Immediate(crate::operands::ImmediateOperand),
|
Immediate(crate::operands::ImmediateOperand),
|
||||||
ModRmTarget(ModRmTarget),
|
ModRmTarget(ModRmTarget),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Result = ImmediateOperand;
|
||||||
|
type Lhs = ImmediateOperand;
|
||||||
|
type Rhs = ImmediateOperand;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Computer {
|
pub struct Computer {
|
||||||
pub regs: Register,
|
pub regs: Register,
|
||||||
@@ -27,38 +31,48 @@ impl Computer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform binary `dest` = `dest` + `src`. Sets flags.
|
||||||
pub fn add(&mut self, dest: ModRmTarget, src: Operand) {
|
pub fn add(&mut self, dest: ModRmTarget, src: Operand) {
|
||||||
let op = |lhs, rhs| lhs + rhs;
|
let op: fn(Lhs, Rhs) -> Result = |lhs, rhs| lhs + rhs;
|
||||||
// TODO let flag_check = |_| ();
|
let flag_set: fn(&mut Flags, Result, Lhs, Rhs) = |flags, result, lhs, rhs| {
|
||||||
self.op(op, dest, src);
|
flags.cf = result < rhs;
|
||||||
|
flags.of = lhs.msb() && rhs.msb() != result.msb();
|
||||||
|
flags.zf = result.zero();
|
||||||
|
flags.sf = result.msb();
|
||||||
|
flags.pf = result.parity();
|
||||||
|
// flags.af =
|
||||||
|
};
|
||||||
|
self.op(op, flag_set, dest, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform binary `dest` = `dest` - `src`. Sets flags.
|
||||||
pub fn sub(&mut self, dest: ModRmTarget, src: Operand) {
|
pub fn sub(&mut self, dest: ModRmTarget, src: Operand) {
|
||||||
let op = |lhs, rhs| lhs - rhs;
|
let op: fn(Lhs, Rhs) -> Result = |lhs, rhs| lhs - rhs;
|
||||||
// TODO let flag_check = |_| ();
|
let flag_set: fn(&mut Flags, Result, Lhs, Rhs) = |_, _, _, _| ();
|
||||||
self.op(op, dest, src);
|
self.op(op, flag_set, dest, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies a binary operator [`O`] to two [`Argument`]s, saves it to `dest`
|
/// Applies a binary operator [`O`] to the value of two [`Operand`]s, saves
|
||||||
/// and sets flags, if necessary.
|
/// it to `dest` and sets flags, according to [`F`].
|
||||||
/// A value can never be saved to an immediate Operand, so `dest` can only
|
/// A result can never be saved to an immediate Operand, so `dest` can only
|
||||||
/// be a [`ModRmTarget`].
|
/// be a [`ModRmTarget`].
|
||||||
fn op<O>(&mut self, op: O, dest: ModRmTarget, src: Operand)
|
fn op<O, F>(&mut self, op: O, flag_set: F, dest: ModRmTarget, src: Operand)
|
||||||
where
|
where
|
||||||
O: Fn(ImmediateOperand, ImmediateOperand) -> ImmediateOperand,
|
O: Fn(Lhs, Rhs) -> Result,
|
||||||
// F: Fn(&mut Flags);
|
F: Fn(&mut Flags, Result, Lhs, Rhs),
|
||||||
{
|
{
|
||||||
match src {
|
match src {
|
||||||
Operand::ModRmTarget(src_target) => self.op_modrm(op, dest, src_target),
|
Operand::ModRmTarget(src_target) => self.op_modrm(op, flag_set, dest, src_target),
|
||||||
Operand::Immediate(src_operand) => self.op_imm(op, dest, src_operand),
|
Operand::Immediate(src_operand) => self.op_imm(op, flag_set, dest, src_operand),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies a binary operator [`O`] to two [`ModRmTargets`]s, saves it to
|
/// Applies a binary operator [`O`] to two memory locations, pointed to by a
|
||||||
/// dest and sets flags, if necessary.
|
/// [`ModRmTargets`]s, saves it to dest and sets flags, according to [`F`].
|
||||||
fn op_modrm<O>(&mut self, op: O, dest: ModRmTarget, src: ModRmTarget)
|
fn op_modrm<O, F>(&mut self, op: O, flag_set: F, dest: ModRmTarget, src: ModRmTarget)
|
||||||
where
|
where
|
||||||
O: Fn(ImmediateOperand, ImmediateOperand) -> ImmediateOperand,
|
O: Fn(Lhs, Rhs) -> Result,
|
||||||
|
F: Fn(&mut Flags, Result, Lhs, Rhs),
|
||||||
{
|
{
|
||||||
match dest {
|
match dest {
|
||||||
ModRmTarget::Memory(dest_memory_idx) => match src {
|
ModRmTarget::Memory(dest_memory_idx) => match src {
|
||||||
@@ -72,7 +86,7 @@ impl Computer {
|
|||||||
let rhs = self.regs.read(src_register);
|
let rhs = self.regs.read(src_register);
|
||||||
let result = op(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);
|
||||||
// flag_check(&mut self.flags);
|
flag_set(&mut self.flags, result, lhs, rhs);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ModRmTarget::Register(dest_register) => match src {
|
ModRmTarget::Register(dest_register) => match src {
|
||||||
@@ -82,7 +96,7 @@ impl Computer {
|
|||||||
let rhs = self.memory.read(&self.regs, src_memory_index);
|
let rhs = self.memory.read(&self.regs, src_memory_index);
|
||||||
let result = op(lhs, rhs);
|
let result = op(lhs, rhs);
|
||||||
self.regs.write(dest_register, result);
|
self.regs.write(dest_register, result);
|
||||||
// flag_check(&mut self.flags);
|
flag_set(&mut self.flags, result, lhs, rhs);
|
||||||
}
|
}
|
||||||
// reg, reg
|
// reg, reg
|
||||||
ModRmTarget::Register(src_register) => {
|
ModRmTarget::Register(src_register) => {
|
||||||
@@ -90,7 +104,7 @@ impl Computer {
|
|||||||
let rhs = self.regs.read(src_register);
|
let rhs = self.regs.read(src_register);
|
||||||
let result = op(lhs, rhs);
|
let result = op(lhs, rhs);
|
||||||
self.regs.write(dest_register, result);
|
self.regs.write(dest_register, result);
|
||||||
// flag_check(&mut self.flags);
|
flag_set(&mut self.flags, result, lhs, rhs);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -98,24 +112,24 @@ impl Computer {
|
|||||||
|
|
||||||
/// Applies a binary operator [`O`] to [`ImmediateOperand`] and a location
|
/// Applies a binary operator [`O`] to [`ImmediateOperand`] and a location
|
||||||
/// pointed to by a [`ModRmTarget`], saves it to dest and sets flags,
|
/// pointed to by a [`ModRmTarget`], saves it to dest and sets flags,
|
||||||
/// if necessary.
|
/// according to [`F`].
|
||||||
fn op_imm<O>(&mut self, op: O, dest: ModRmTarget, src: ImmediateOperand)
|
fn op_imm<O, F>(&mut self, op: O, flag_set: F, dest: ModRmTarget, src: ImmediateOperand)
|
||||||
where
|
where
|
||||||
O: Fn(ImmediateOperand, ImmediateOperand) -> ImmediateOperand,
|
O: Fn(Lhs, Rhs) -> Result,
|
||||||
// F: for<'F> Fn(&'F mut Flags),
|
F: Fn(&mut Flags, Result, Lhs, Rhs),
|
||||||
{
|
{
|
||||||
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 = op(lhs, src);
|
let result = op(lhs, src);
|
||||||
self.memory.write(&self.regs, dest_mem, result);
|
self.memory.write(&self.regs, dest_mem, result);
|
||||||
// flag_check(&mut self.flags);
|
flag_set(&mut self.flags, result, lhs, src);
|
||||||
}
|
}
|
||||||
ModRmTarget::Register(dest_reg) => {
|
ModRmTarget::Register(dest_reg) => {
|
||||||
let lhs = self.regs.read(dest_reg);
|
let lhs = self.regs.read(dest_reg);
|
||||||
let result = op(lhs, src);
|
let result = op(lhs, src);
|
||||||
self.regs.write(dest_reg, result);
|
self.regs.write(dest_reg, result);
|
||||||
// flag_check(&mut self.flags);
|
flag_set(&mut self.flags, result, lhs, src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,18 @@ 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)),
|
||||||
),
|
),
|
||||||
|
/*
|
||||||
|
* PUSH
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* POP
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OR
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SUB
|
* SUB
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -16,15 +16,53 @@ pub type IWord = i16; // used for displacement of memory access
|
|||||||
pub type DWord = u32;
|
pub type DWord = u32;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Ord, Eq, PartialEq, PartialOrd, Copy)]
|
#[derive(Debug, Clone, Ord, Eq, PartialEq, PartialOrd, Copy)]
|
||||||
/// Encodes either Byte- or Word-sized operands.
|
/// Encodes either Byte- or Word-sized immediate operands.
|
||||||
/// Also sometimes used to decide if an instruction is Byte- or Word-sized,
|
/// Also sometimes used to decide if an instruction is Byte- or Word-sized,
|
||||||
/// which is usually indicated by using a value of 0 and the disregarding
|
/// which is usually indicated by using a value of 0 and the disregarding
|
||||||
/// the value when read.
|
/// the value when read.
|
||||||
|
/// Can either be interpreted as signed or unsigned, depending on the context.
|
||||||
pub enum ImmediateOperand {
|
pub enum ImmediateOperand {
|
||||||
Byte(Byte),
|
Byte(Byte),
|
||||||
Word(Word),
|
Word(Word),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ImmediateOperand {
|
||||||
|
// Check if value is zero.
|
||||||
|
pub fn zero(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Byte(byte) => return *byte == 0,
|
||||||
|
Self::Word(word) => return *word == 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if leasy significant byte has even number of 1's.
|
||||||
|
pub fn parity(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Byte(byte) => return byte.count_ones() % 2 != 0,
|
||||||
|
Self::Word(word) => {
|
||||||
|
let [low, _]: [u8; 2] = word.to_le_bytes();
|
||||||
|
return low.count_ones() % 2 != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if least significant bit is set.
|
||||||
|
pub fn lsb(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Byte(byte) => return byte & 1 == 1,
|
||||||
|
Self::Word(word) => return word & 1 == 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if most significant bit is set.
|
||||||
|
pub fn msb(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Byte(byte) => return byte & (1 << 3) == 1,
|
||||||
|
Self::Word(word) => return word & (1 << 7) == 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Add for ImmediateOperand {
|
impl Add for ImmediateOperand {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
@@ -162,7 +200,7 @@ impl std::fmt::Display for ModRmTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
|
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
|
||||||
/// Memory displacements are signed versions of Byte and Word operands.
|
/// Memory displacements are concrete signed versions of Byte and Word operands.
|
||||||
/// Encodes either Byte- or Word-sized operands.
|
/// Encodes either Byte- or Word-sized operands.
|
||||||
/// Generally, a [`Displacement`] is the result of a ModRM byte parse and
|
/// Generally, a [`Displacement`] is the result of a ModRM byte parse and
|
||||||
/// usually really is the signed displacement of a [`MemoryIndex`] for memory
|
/// usually really is the signed displacement of a [`MemoryIndex`] for memory
|
||||||
|
|||||||
Reference in New Issue
Block a user