ft(interpreter): impl adc and sbb
This commit is contained in:
@@ -11,7 +11,7 @@ pub enum Operand {
|
||||
ModRmTarget(ModRmTarget),
|
||||
}
|
||||
|
||||
type Result = ImmediateOperand;
|
||||
type ArithmeticResult = ImmediateOperand;
|
||||
type Lhs = ImmediateOperand;
|
||||
type Rhs = ImmediateOperand;
|
||||
|
||||
@@ -33,8 +33,8 @@ impl Computer {
|
||||
|
||||
/// Perform binary `dest` = `dest` + `src`. Sets flags.
|
||||
pub fn add(&mut self, dest: ModRmTarget, src: Operand) {
|
||||
let op: fn(Lhs, Rhs) -> Result = |lhs, rhs| lhs + rhs;
|
||||
let flag_set: fn(&mut Flags, Result, Lhs, Rhs) = |flags, result, lhs, rhs| {
|
||||
let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs + rhs;
|
||||
let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, lhs, rhs| {
|
||||
flags.cf = result < rhs;
|
||||
flags.of = lhs.msb() && rhs.msb() != result.msb();
|
||||
flags.zf = result.zero();
|
||||
@@ -46,8 +46,8 @@ impl Computer {
|
||||
|
||||
/// Perform binary `dest` = `dest` - `src`. Sets flags.
|
||||
pub fn sub(&mut self, dest: ModRmTarget, src: Operand) {
|
||||
let op: fn(Lhs, Rhs) -> Result = |lhs, rhs| lhs - rhs;
|
||||
let flag_set: fn(&mut Flags, Result, Lhs, Rhs) = |flags, result, lhs, rhs| {
|
||||
let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs - rhs;
|
||||
let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, lhs, rhs| {
|
||||
flags.cf = lhs < rhs;
|
||||
flags.of = lhs.msb() != rhs.msb() && lhs.msb() != result.msb();
|
||||
flags.zf = result.zero();
|
||||
@@ -59,8 +59,8 @@ impl Computer {
|
||||
|
||||
/// Perform binary `dest` = `dest` | `src`. Sets flags.
|
||||
pub fn or(&mut self, dest: ModRmTarget, src: Operand) {
|
||||
let op: fn(Lhs, Rhs) -> Result = |lhs, rhs| lhs | rhs;
|
||||
let flag_set: fn(&mut Flags, Result, Lhs, Rhs) = |flags, result, _, _| {
|
||||
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();
|
||||
@@ -72,8 +72,8 @@ impl Computer {
|
||||
|
||||
/// Perform binary `dest` = `dest` & `src`. Sets flags.
|
||||
pub fn and(&mut self, dest: ModRmTarget, src: Operand) {
|
||||
let op: fn(Lhs, Rhs) -> Result = |lhs, rhs| lhs & rhs;
|
||||
let flag_set: fn(&mut Flags, Result, Lhs, Rhs) = |flags, result, _, _rhs| {
|
||||
let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs & rhs;
|
||||
let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, _, _rhs| {
|
||||
flags.cf = false;
|
||||
flags.of = false;
|
||||
flags.zf = result.zero();
|
||||
@@ -85,8 +85,8 @@ impl Computer {
|
||||
|
||||
/// Perform binary `dest` = `dest` ^ `src`. Sets flags.
|
||||
pub fn xor(&mut self, dest: ModRmTarget, src: Operand) {
|
||||
let op: fn(Lhs, Rhs) -> Result = |lhs, rhs| lhs ^ rhs;
|
||||
let flag_set: fn(&mut Flags, Result, Lhs, Rhs) = |flags, result, _, _| {
|
||||
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();
|
||||
@@ -99,8 +99,8 @@ impl Computer {
|
||||
/// Perform compare operation, which acts like [`Self::sub()`], but without
|
||||
/// saving the result and only setting [`Self::flags`].
|
||||
pub fn cmp(&mut self, dest: ModRmTarget, src: Operand) {
|
||||
let op: fn(Lhs, Rhs) -> Result = |lhs, rhs| lhs - rhs;
|
||||
let flag_set: fn(&mut Flags, Result, Lhs, Rhs) = |flags, result, lhs, rhs| {
|
||||
let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs - rhs;
|
||||
let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, lhs, rhs| {
|
||||
flags.cf = lhs < rhs;
|
||||
flags.of = lhs.msb() != rhs.msb() && lhs.msb() != result.msb();
|
||||
flags.zf = result.zero();
|
||||
@@ -110,14 +110,58 @@ impl Computer {
|
||||
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;
|
||||
// cheating, by flattening into immediates, but this allows to easily add the opt. carry
|
||||
let src_with_carry = match src {
|
||||
Operand::Immediate(immediate_operand) => Operand::Immediate(immediate_operand + cf),
|
||||
Operand::ModRmTarget(mod_rm_target) => Operand::Immediate(match mod_rm_target {
|
||||
ModRmTarget::Memory(idx) => self.memory.read(&self.regs, idx) + cf,
|
||||
ModRmTarget::Register(reg) => self.regs.read(reg) + cf,
|
||||
}),
|
||||
};
|
||||
let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs + rhs;
|
||||
let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, lhs, rhs| {
|
||||
flags.cf = result < rhs;
|
||||
flags.of = lhs.msb() && rhs.msb() != result.msb();
|
||||
flags.zf = result.zero();
|
||||
flags.sf = result.msb();
|
||||
flags.pf = result.parity();
|
||||
};
|
||||
self.op(op, flag_set, true, dest, src_with_carry);
|
||||
}
|
||||
|
||||
/// Perform `dest` = `dest` - (`src` + CF). Sets flags.
|
||||
pub fn sbb(&mut self, dest: ModRmTarget, src: Operand) {
|
||||
let cf = self.flags.cf as u8;
|
||||
// cheating, by flattening into immediates, but this allows to easily add the opt. carry
|
||||
let src_with_carry = match src {
|
||||
Operand::Immediate(immediate_operand) => Operand::Immediate(immediate_operand + cf),
|
||||
Operand::ModRmTarget(mod_rm_target) => Operand::Immediate(match mod_rm_target {
|
||||
ModRmTarget::Memory(idx) => self.memory.read(&self.regs, idx) + cf,
|
||||
ModRmTarget::Register(reg) => self.regs.read(reg) + cf,
|
||||
}),
|
||||
};
|
||||
let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs - rhs;
|
||||
let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, lhs, rhs| {
|
||||
flags.cf = result < rhs;
|
||||
flags.of = lhs.msb() && rhs.msb() != result.msb();
|
||||
flags.zf = result.zero();
|
||||
flags.sf = result.msb();
|
||||
flags.pf = result.parity();
|
||||
};
|
||||
self.op(op, flag_set, true, dest, src_with_carry);
|
||||
}
|
||||
|
||||
/// Applies a binary operator [`O`] to the value of two [`Operand`]s, saves
|
||||
/// it to `dest`, if `write` is set, and sets flags, according to [`F`].
|
||||
/// A result can never be saved to an immediate Operand, so `dest` can only
|
||||
/// be a [`ModRmTarget`].
|
||||
fn op<O, F>(&mut self, op: O, flag_set: F, write: bool, dest: ModRmTarget, src: Operand)
|
||||
where
|
||||
O: Fn(Lhs, Rhs) -> Result,
|
||||
F: Fn(&mut Flags, Result, Lhs, Rhs),
|
||||
O: Fn(Lhs, Rhs) -> ArithmeticResult,
|
||||
F: Fn(&mut Flags, ArithmeticResult, Lhs, Rhs),
|
||||
{
|
||||
match src {
|
||||
Operand::ModRmTarget(src_target) => {
|
||||
@@ -138,8 +182,8 @@ impl Computer {
|
||||
dest: ModRmTarget,
|
||||
src: ModRmTarget,
|
||||
) where
|
||||
O: Fn(Lhs, Rhs) -> Result,
|
||||
F: Fn(&mut Flags, Result, Lhs, Rhs),
|
||||
O: Fn(Lhs, Rhs) -> ArithmeticResult,
|
||||
F: Fn(&mut Flags, ArithmeticResult, Lhs, Rhs),
|
||||
{
|
||||
match dest {
|
||||
ModRmTarget::Memory(dest_memory_idx) => match src {
|
||||
@@ -194,8 +238,8 @@ impl Computer {
|
||||
dest: ModRmTarget,
|
||||
src: ImmediateOperand,
|
||||
) where
|
||||
O: Fn(Lhs, Rhs) -> Result,
|
||||
F: Fn(&mut Flags, Result, Lhs, Rhs),
|
||||
O: Fn(Lhs, Rhs) -> ArithmeticResult,
|
||||
F: Fn(&mut Flags, ArithmeticResult, Lhs, Rhs),
|
||||
{
|
||||
match dest {
|
||||
ModRmTarget::Memory(dest_mem) => {
|
||||
|
||||
@@ -118,13 +118,54 @@ impl Interpreter {
|
||||
ModRmTarget::Register(crate::register::Register::AX),
|
||||
Operand::Immediate(ImmediateOperand::Word(src_word)),
|
||||
),
|
||||
/*
|
||||
* ADC
|
||||
*/
|
||||
|
||||
/*
|
||||
* SBB
|
||||
* ADC - add with carry
|
||||
*/
|
||||
Mnemonic::ADC_FromReg(dest, src) => self
|
||||
.computer
|
||||
.adc(dest, Operand::ModRmTarget(ModRmTarget::Register(src))),
|
||||
Mnemonic::ADC_ToReg(src, dest) => self
|
||||
.computer
|
||||
.adc(ModRmTarget::Register(dest), Operand::ModRmTarget(src)),
|
||||
Mnemonic::ADC_Ib(dest, src) => self
|
||||
.computer
|
||||
.adc(dest, Operand::Immediate(ImmediateOperand::Byte(src))),
|
||||
Mnemonic::ADC_Iv(dest, src) => self
|
||||
.computer
|
||||
.adc(dest, Operand::Immediate(ImmediateOperand::Word(src))),
|
||||
Mnemonic::ADC_ALIb(src_byte) => self.computer.adc(
|
||||
ModRmTarget::Register(crate::register::Register::AL),
|
||||
Operand::Immediate(ImmediateOperand::Byte(src_byte)),
|
||||
),
|
||||
Mnemonic::ADC_AXIv(src_word) => self.computer.adc(
|
||||
ModRmTarget::Register(crate::register::Register::AX),
|
||||
Operand::Immediate(ImmediateOperand::Word(src_word)),
|
||||
),
|
||||
|
||||
/*
|
||||
* SBB - subtract with borrow
|
||||
*/
|
||||
Mnemonic::SBB_FromReg(dest, src) => self
|
||||
.computer
|
||||
.sbb(dest, Operand::ModRmTarget(ModRmTarget::Register(src))),
|
||||
Mnemonic::SBB_ToReg(src, dest) => self
|
||||
.computer
|
||||
.sbb(ModRmTarget::Register(dest), Operand::ModRmTarget(src)),
|
||||
Mnemonic::SBB_Ib(dest, src) => self
|
||||
.computer
|
||||
.sbb(dest, Operand::Immediate(ImmediateOperand::Byte(src))),
|
||||
Mnemonic::SBB_Iv(dest, src) => self
|
||||
.computer
|
||||
.sbb(dest, Operand::Immediate(ImmediateOperand::Word(src))),
|
||||
Mnemonic::SBB_ALIb(src_byte) => self.computer.sbb(
|
||||
ModRmTarget::Register(crate::register::Register::AL),
|
||||
Operand::Immediate(ImmediateOperand::Byte(src_byte)),
|
||||
),
|
||||
Mnemonic::SBB_AXIv(src_word) => self.computer.sbb(
|
||||
ModRmTarget::Register(crate::register::Register::AX),
|
||||
Operand::Immediate(ImmediateOperand::Word(src_word)),
|
||||
),
|
||||
|
||||
/*
|
||||
* AND
|
||||
|
||||
Reference in New Issue
Block a user