ft(interpreter): generalize binary operations

This commit is contained in:
2025-06-10 10:59:35 +09:00
parent 2b37884a60
commit 35fefb7625
3 changed files with 110 additions and 27 deletions

View File

@@ -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
/// 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 {
Operand::ModRmTarget(src_target) => self.add_modrm(dest, src_target),
Operand::Immediate(src_operand) => self.add_imm(dest, src_operand),
Operand::ModRmTarget(src_target) => self.op_modrm(op, dest, src_target),
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.
fn add_modrm(&mut self, dest: ModRmTarget, src: ModRmTarget) {
/// Applies a binary operator [`O`] to two [`ModRmTargets`]s, saves it to
/// 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 {
ModRmTarget::Memory(dest_memory_idx) => match src {
// mem, mem
ModRmTarget::Memory(_) => panic!("Cannot add Memory to Memory!"),
ModRmTarget::Memory(_) => {
panic!("Cannot apply binary operator from Memory to Memory!")
}
// mem, reg
ModRmTarget::Register(src_register) => {
let lhs = self.memory.read(&self.regs, dest_memory_idx);
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);
// unsigned overflow
self.flags.of = result < rhs;
// flag_check(&mut self.flags);
}
},
ModRmTarget::Register(dest_register) => match src {
@@ -58,42 +80,42 @@ impl Computer {
ModRmTarget::Memory(src_memory_index) => {
let lhs = self.regs.read(dest_register);
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);
// unsigned overflow
self.flags.of = result < rhs;
// flag_check(&mut self.flags);
}
// reg, reg
ModRmTarget::Register(src_register) => {
let lhs = self.regs.read(dest_register);
let rhs = self.regs.read(src_register);
let result = lhs + rhs;
let result = op(lhs, rhs);
self.regs.write(dest_register, result);
// unsigned overflow
self.flags.of = result < rhs
// flag_check(&mut self.flags);
}
},
}
}
/// Adds an [`ImmediateOperand`] 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: ImmediateOperand) {
/// Applies a binary operator [`O`] to [`ImmediateOperand`] and a location
/// pointed to by a [`ModRmTarget`], saves it to dest and sets flags,
/// 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 {
ModRmTarget::Memory(dest_mem) => {
let lhs = self.memory.read(&self.regs, dest_mem);
let result = lhs + src;
// unsigned overflow
self.flags.of = result < src;
let result = op(lhs, src);
self.memory.write(&self.regs, dest_mem, result);
// flag_check(&mut self.flags);
}
ModRmTarget::Register(dest_reg) => {
let lhs = self.regs.read(dest_reg);
let result = lhs + src;
// unsigned overflow
self.flags.of = result < src;
let result = op(lhs, src);
self.regs.write(dest_reg, result);
// flag_check(&mut self.flags);
}
}
}