ft: abstract and implement ADD::* interpretation
This commit is contained in:
@@ -1,14 +1,21 @@
|
||||
use core::fmt;
|
||||
|
||||
use crate::operands::Byte;
|
||||
use crate::operands::{ModRmTarget, Operand};
|
||||
|
||||
use super::{flags::Flags, register::Register};
|
||||
use super::{flags::Flags, memory::Memory, register::Register};
|
||||
|
||||
/// Wrapper for easier argument passing of arithmetic operations.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Argument {
|
||||
Operand(crate::operands::Operand),
|
||||
ModRmTarget(ModRmTarget),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Computer {
|
||||
pub regs: Register,
|
||||
pub flags: Flags,
|
||||
pub memory: [Byte; 65536],
|
||||
pub memory: Memory,
|
||||
}
|
||||
|
||||
impl Computer {
|
||||
@@ -16,7 +23,79 @@ impl Computer {
|
||||
Self {
|
||||
regs: Register::new(),
|
||||
flags: Flags::new(),
|
||||
memory: [0; 65536],
|
||||
memory: Memory::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds 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
|
||||
/// be a [`ModRmTarget`].
|
||||
pub fn add(&mut self, dest: ModRmTarget, src: Argument) {
|
||||
match src {
|
||||
Argument::ModRmTarget(src_target) => self.add_modrm(dest, src_target),
|
||||
Argument::Operand(src_operand) => self.add_imm(dest, src_operand),
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds two [`ModRmTarget`]s togeher, saves it to `dest` and sets flags, if necessary.
|
||||
fn add_modrm(&mut self, dest: ModRmTarget, src: ModRmTarget) {
|
||||
match dest {
|
||||
ModRmTarget::Memory(dest_memory_idx) => match src {
|
||||
// mem, mem
|
||||
ModRmTarget::Memory(_) => panic!("Cannot add Memory to Memory!"),
|
||||
// mem, reg
|
||||
ModRmTarget::Register(src_register) => {
|
||||
let lhs = self.memory.read_from_memidx(&self.regs, dest_memory_idx);
|
||||
let rhs = self.regs.read(src_register);
|
||||
let result = lhs + rhs;
|
||||
self.memory
|
||||
.write_from_memidx(&self.regs, dest_memory_idx, result);
|
||||
// unsigned overflow
|
||||
self.flags.of = result < rhs;
|
||||
}
|
||||
},
|
||||
ModRmTarget::Register(dest_register) => match src {
|
||||
// reg, mem
|
||||
ModRmTarget::Memory(src_memory_index) => {
|
||||
let lhs = self.regs.read(dest_register);
|
||||
let rhs = self.memory.read_from_memidx(&self.regs, src_memory_index);
|
||||
let result = lhs + rhs;
|
||||
self.regs.write(dest_register, result);
|
||||
// unsigned overflow
|
||||
self.flags.of = result < rhs;
|
||||
}
|
||||
// reg, reg
|
||||
ModRmTarget::Register(src_register) => {
|
||||
let lhs = self.regs.read(dest_register);
|
||||
let rhs = self.regs.read(src_register);
|
||||
let result = lhs + rhs;
|
||||
self.regs.write(dest_register, result);
|
||||
|
||||
// unsigned overflow
|
||||
self.flags.of = result < rhs
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds an immediate [`Operand`] to a location pointed to by a
|
||||
/// [`ModRmTarget`], saves it to dest and sets flags, if necessary.
|
||||
fn add_imm(&mut self, dest: ModRmTarget, src: Operand) {
|
||||
match dest {
|
||||
ModRmTarget::Memory(dest_mem) => {
|
||||
let lhs = self.memory.read_from_memidx(&self.regs, dest_mem);
|
||||
let result = lhs + src;
|
||||
// unsigned overflow
|
||||
self.flags.of = result < src;
|
||||
self.memory.write_from_memidx(&self.regs, dest_mem, result);
|
||||
}
|
||||
ModRmTarget::Register(dest_reg) => {
|
||||
let lhs = self.regs.read(dest_reg);
|
||||
let result = lhs + src;
|
||||
// unsigned overflow
|
||||
self.flags.of = result < src;
|
||||
self.regs.write(dest_reg, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user