chore(interpreter): move memory access functions to computer
This is mainly to ease the usage of memory access functions, meaning leaner access of memory with general resulution of memory accesses via the MemoryIndex struct.
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
It includes:
|
||||
- a.out Parser to parse legacy MINIX 1.x executables.
|
||||
- 8086 disassembler to parse the 16-bit instructions into an IR and prints them in a `objdump(1)`-style fashion.
|
||||
- 8086 interpreter which interprets the instructions with MINIX 1.x conventions (e.g. interrupts, memory layout, ...) in mind.
|
||||
- 8086 interpreter which interprets the instructions with MINIX 1.x conventions (e.g. interrupts, memory layout, ...) in mind and obeys segment register indirection, which enables the usage of the entire 20-bit memory bus.
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use core::fmt;
|
||||
|
||||
use crate::operands::{ImmediateOperand, ModRmTarget, Word};
|
||||
use crate::operands::{ImmediateOperand, ImmediateOperandSigned, MemoryIndex, ModRmTarget, Word};
|
||||
|
||||
use super::{
|
||||
flags::Flags, interpreter::InterpreterError, memory::Memory, register::Register,
|
||||
@@ -38,20 +38,32 @@ impl Computer {
|
||||
|
||||
/// Decrement stack pointer and write `val` onto the stack.
|
||||
pub fn push_stack(&mut self, val: ImmediateOperand) -> Result<(), InterpreterError> {
|
||||
self.regs.push()?;
|
||||
self.memory
|
||||
.write_raw(&self.sregs.ss * 16 + self.regs.sp, val.into())
|
||||
self.regs.push_sp()?;
|
||||
self.memory.write_raw(
|
||||
self.mem_addr(
|
||||
ImmediateOperand::from(self.regs.sp).into(),
|
||||
&crate::register::SegmentRegister::SS,
|
||||
),
|
||||
val.into(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Retrieve value from stack and increment stack pointer.
|
||||
pub fn pop_stack(&mut self) -> Result<Word, InterpreterError> {
|
||||
let word = self.memory.read_raw(&self.sregs.ss * 16 + self.regs.sp)?;
|
||||
self.regs.pop()?;
|
||||
let word = self.memory.read_raw(self.mem_addr(
|
||||
ImmediateOperand::from(self.regs.sp).into(),
|
||||
&crate::register::SegmentRegister::SS,
|
||||
))?;
|
||||
self.regs.pop_sp()?;
|
||||
Ok(word)
|
||||
}
|
||||
|
||||
/// Perform binary `dest` = `dest` + `src`. Sets flags.
|
||||
pub fn add(&mut self, dest: ModRmTarget, src: ArithmeticOperand) {
|
||||
pub fn add(
|
||||
&mut self,
|
||||
dest: ModRmTarget,
|
||||
src: ArithmeticOperand,
|
||||
) -> Result<(), InterpreterError> {
|
||||
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;
|
||||
@@ -60,11 +72,15 @@ impl Computer {
|
||||
flags.sf = result.msb();
|
||||
flags.pf = result.parity();
|
||||
};
|
||||
self.op(op, flag_set, true, dest, src);
|
||||
self.op(op, flag_set, true, dest, src)
|
||||
}
|
||||
|
||||
/// Perform binary `dest` = `dest` - `src`. Sets flags.
|
||||
pub fn sub(&mut self, dest: ModRmTarget, src: ArithmeticOperand) {
|
||||
pub fn sub(
|
||||
&mut self,
|
||||
dest: ModRmTarget,
|
||||
src: ArithmeticOperand,
|
||||
) -> Result<(), InterpreterError> {
|
||||
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;
|
||||
@@ -73,11 +89,15 @@ impl Computer {
|
||||
flags.sf = result.msb();
|
||||
flags.pf = result.parity();
|
||||
};
|
||||
self.op(op, flag_set, true, dest, src);
|
||||
self.op(op, flag_set, true, dest, src)
|
||||
}
|
||||
|
||||
/// Perform binary `dest` = `dest` | `src`. Sets flags.
|
||||
pub fn or(&mut self, dest: ModRmTarget, src: ArithmeticOperand) {
|
||||
pub fn or(
|
||||
&mut self,
|
||||
dest: ModRmTarget,
|
||||
src: ArithmeticOperand,
|
||||
) -> Result<(), InterpreterError> {
|
||||
let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs | rhs;
|
||||
let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, _, _| {
|
||||
flags.cf = false;
|
||||
@@ -86,11 +106,15 @@ impl Computer {
|
||||
flags.sf = result.msb();
|
||||
flags.pf = result.parity();
|
||||
};
|
||||
self.op(op, flag_set, true, dest, src);
|
||||
self.op(op, flag_set, true, dest, src)
|
||||
}
|
||||
|
||||
/// Perform binary `dest` = `dest` & `src`. Sets flags.
|
||||
pub fn and(&mut self, dest: ModRmTarget, src: ArithmeticOperand) {
|
||||
pub fn and(
|
||||
&mut self,
|
||||
dest: ModRmTarget,
|
||||
src: ArithmeticOperand,
|
||||
) -> Result<(), InterpreterError> {
|
||||
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;
|
||||
@@ -99,11 +123,15 @@ impl Computer {
|
||||
flags.sf = result.msb();
|
||||
flags.pf = result.parity();
|
||||
};
|
||||
self.op(op, flag_set, true, dest, src);
|
||||
self.op(op, flag_set, true, dest, src)
|
||||
}
|
||||
|
||||
/// Perform binary `dest` = `dest` ^ `src`. Sets flags.
|
||||
pub fn xor(&mut self, dest: ModRmTarget, src: ArithmeticOperand) {
|
||||
pub fn xor(
|
||||
&mut self,
|
||||
dest: ModRmTarget,
|
||||
src: ArithmeticOperand,
|
||||
) -> Result<(), InterpreterError> {
|
||||
let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs ^ rhs;
|
||||
let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, _, _| {
|
||||
flags.cf = false;
|
||||
@@ -112,12 +140,16 @@ impl Computer {
|
||||
flags.sf = result.msb();
|
||||
flags.pf = result.parity();
|
||||
};
|
||||
self.op(op, flag_set, true, dest, src);
|
||||
self.op(op, flag_set, true, dest, src)
|
||||
}
|
||||
|
||||
/// 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: ArithmeticOperand) {
|
||||
pub fn cmp(
|
||||
&mut self,
|
||||
dest: ModRmTarget,
|
||||
src: ArithmeticOperand,
|
||||
) -> Result<(), InterpreterError> {
|
||||
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;
|
||||
@@ -126,12 +158,16 @@ impl Computer {
|
||||
flags.sf = result.msb();
|
||||
flags.pf = result.parity();
|
||||
};
|
||||
self.op(op, flag_set, false, dest, src);
|
||||
self.op(op, flag_set, false, dest, src)
|
||||
}
|
||||
|
||||
/// Perform test operation, which acts like [`Self::and()`], but without
|
||||
/// saving the result and only setting [`Self::flags`].
|
||||
pub fn test(&mut self, dest: ModRmTarget, src: ArithmeticOperand) {
|
||||
pub fn test(
|
||||
&mut self,
|
||||
dest: ModRmTarget,
|
||||
src: ArithmeticOperand,
|
||||
) -> Result<(), InterpreterError> {
|
||||
let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs & rhs;
|
||||
let flag_set: fn(&mut Flags, ArithmeticResult, Lhs, Rhs) = |flags, result, _, _| {
|
||||
flags.cf = false;
|
||||
@@ -140,11 +176,15 @@ impl Computer {
|
||||
flags.sf = result.msb();
|
||||
flags.pf = result.parity();
|
||||
};
|
||||
self.op(op, flag_set, false, dest, src);
|
||||
self.op(op, flag_set, false, dest, src)
|
||||
}
|
||||
|
||||
/// Perform `dest` = `dest` + `src` + CF. Sets flags.
|
||||
pub fn adc(&mut self, dest: ModRmTarget, src: ArithmeticOperand) {
|
||||
pub fn adc(
|
||||
&mut self,
|
||||
dest: ModRmTarget,
|
||||
src: ArithmeticOperand,
|
||||
) -> Result<(), InterpreterError> {
|
||||
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 {
|
||||
@@ -153,9 +193,7 @@ impl Computer {
|
||||
}
|
||||
ArithmeticOperand::ModRmTarget(mod_rm_target) => {
|
||||
ArithmeticOperand::Immediate(match mod_rm_target {
|
||||
ModRmTarget::Memory(idx) => {
|
||||
(self.memory.read(&self.regs, &self.sregs, idx) + cf as u16).into()
|
||||
}
|
||||
ModRmTarget::Memory(idx) => (self.read(idx).unwrap() + cf as u16).into(),
|
||||
ModRmTarget::Register(reg) => self.regs.read(reg) + cf,
|
||||
})
|
||||
}
|
||||
@@ -168,11 +206,15 @@ impl Computer {
|
||||
flags.sf = result.msb();
|
||||
flags.pf = result.parity();
|
||||
};
|
||||
self.op(op, flag_set, true, dest, src_with_carry);
|
||||
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: ArithmeticOperand) {
|
||||
pub fn sbb(
|
||||
&mut self,
|
||||
dest: ModRmTarget,
|
||||
src: ArithmeticOperand,
|
||||
) -> Result<(), InterpreterError> {
|
||||
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 {
|
||||
@@ -181,9 +223,7 @@ impl Computer {
|
||||
}
|
||||
ArithmeticOperand::ModRmTarget(mod_rm_target) => {
|
||||
ArithmeticOperand::Immediate(match mod_rm_target {
|
||||
ModRmTarget::Memory(idx) => {
|
||||
(self.memory.read(&self.regs, &self.sregs, idx) + cf as u16).into()
|
||||
}
|
||||
ModRmTarget::Memory(idx) => (self.read(idx)? + cf as u16).into(),
|
||||
ModRmTarget::Register(reg) => self.regs.read(reg) + cf,
|
||||
})
|
||||
}
|
||||
@@ -196,7 +236,7 @@ impl Computer {
|
||||
flags.sf = result.msb();
|
||||
flags.pf = result.parity();
|
||||
};
|
||||
self.op(op, flag_set, true, dest, src_with_carry);
|
||||
self.op(op, flag_set, true, dest, src_with_carry)
|
||||
}
|
||||
|
||||
/// Applies a binary operator [`O`] to the value of two [`Operand`]s, saves
|
||||
@@ -210,46 +250,102 @@ impl Computer {
|
||||
write: bool,
|
||||
dest: ModRmTarget,
|
||||
src: ArithmeticOperand,
|
||||
) where
|
||||
) -> Result<(), InterpreterError>
|
||||
where
|
||||
O: Fn(Lhs, Rhs) -> ArithmeticResult,
|
||||
F: Fn(&mut Flags, ArithmeticResult, Lhs, Rhs),
|
||||
{
|
||||
let lhs = self.read_modrm(dest);
|
||||
let lhs = self.read_modrm(dest)?;
|
||||
let rhs = match src {
|
||||
ArithmeticOperand::Immediate(imm) => imm,
|
||||
ArithmeticOperand::ModRmTarget(target) => self.read_modrm(target),
|
||||
ArithmeticOperand::ModRmTarget(target) => self.read_modrm(target)?,
|
||||
};
|
||||
let result = op(lhs, rhs);
|
||||
if write {
|
||||
self.write_modrm(dest, result);
|
||||
self.write_modrm(dest, result)?;
|
||||
}
|
||||
flag_set(&mut self.flags, result, lhs, rhs);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Finds the memory address to a [`MemoryIndex`], obeying either the `DS`
|
||||
/// or `SS` segment register.
|
||||
pub fn mem_addr(
|
||||
&self,
|
||||
idx: MemoryIndex,
|
||||
segment_selector: &crate::register::SegmentRegister,
|
||||
) -> Word {
|
||||
let mut base = ImmediateOperand::Word(0);
|
||||
let mut index = ImmediateOperand::Word(0);
|
||||
let mut disp = ImmediateOperandSigned::Word(0);
|
||||
|
||||
if let Some(base_reg) = idx.base {
|
||||
base = self.regs.read(base_reg);
|
||||
};
|
||||
if let Some(index_reg) = idx.index {
|
||||
index = self.regs.read(index_reg);
|
||||
};
|
||||
if let Some(displacement) = idx.displacement {
|
||||
disp = ImmediateOperandSigned::from(displacement);
|
||||
}
|
||||
|
||||
let factor = match segment_selector {
|
||||
crate::register::SegmentRegister::DS => self.sregs.ds * 16,
|
||||
crate::register::SegmentRegister::SS => self.sregs.ss * 16,
|
||||
_ => 0,
|
||||
};
|
||||
(ImmediateOperand::from(factor) + base + index + disp).into()
|
||||
}
|
||||
|
||||
/// Write an [`ImmediateOperand`] into memory, index by an [`MemoryIndex`], accessed at `DS:idx`
|
||||
pub fn write(
|
||||
&mut self,
|
||||
val: ImmediateOperand,
|
||||
idx: MemoryIndex,
|
||||
) -> Result<(), InterpreterError> {
|
||||
let addr = self.mem_addr(idx, &crate::register::SegmentRegister::DS);
|
||||
self.memory.write_raw(addr, val)
|
||||
}
|
||||
|
||||
/// Read into memory, index by a [`MemoryIndex`], accessed at `DS:idx`
|
||||
/// Always reads a whole word.
|
||||
pub fn read(&self, idx: MemoryIndex) -> Result<Word, InterpreterError> {
|
||||
let addr = self.mem_addr(idx, &crate::register::SegmentRegister::DS);
|
||||
self.memory.read_raw(addr)
|
||||
}
|
||||
|
||||
/// Write an [`ImmediateOperand`] into [`Self::memory`] or [`Self::regs`].
|
||||
pub fn write_modrm(&mut self, target: ModRmTarget, val: ImmediateOperand) {
|
||||
pub fn write_modrm(
|
||||
&mut self,
|
||||
target: ModRmTarget,
|
||||
val: ImmediateOperand,
|
||||
) -> Result<(), InterpreterError> {
|
||||
match target {
|
||||
ModRmTarget::Memory(idx) => self.memory.write(&self.regs, &self.sregs, idx, val),
|
||||
ModRmTarget::Memory(idx) => self.write(val.into(), idx)?,
|
||||
ModRmTarget::Register(reg) => self.regs.write(reg, val),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Read an [`ImmediateOperand`] from [`Self::memory`] or [`Self::regs`].
|
||||
pub fn read_modrm(&self, target: ModRmTarget) -> ImmediateOperand {
|
||||
match target {
|
||||
ModRmTarget::Memory(idx) => self.memory.read(&self.regs, &self.sregs, idx).into(),
|
||||
pub fn read_modrm(&self, target: ModRmTarget) -> Result<ImmediateOperand, InterpreterError> {
|
||||
let imm = match target {
|
||||
ModRmTarget::Memory(idx) => self.read(idx)?.into(),
|
||||
ModRmTarget::Register(reg) => self.regs.read(reg),
|
||||
}
|
||||
};
|
||||
Ok(imm)
|
||||
}
|
||||
|
||||
/// Rotate bits of data, pointed to from a [`ModRmTarget`].
|
||||
pub fn rotate(
|
||||
&mut self,
|
||||
target: ModRmTarget,
|
||||
rotations: usize, // how many rotations
|
||||
carry_usage: CarryUsage, // if carry should be included, or should just receive a copy
|
||||
rotation_direction: RotationDirection, // direction of rotation
|
||||
) {
|
||||
let mut bits = self.read_modrm(target).bits();
|
||||
) -> Result<(), InterpreterError> {
|
||||
let mut bits = self.read_modrm(target)?.bits();
|
||||
match carry_usage {
|
||||
CarryUsage::FullRotation => bits.push(self.flags.cf),
|
||||
_ => {}
|
||||
@@ -270,7 +366,7 @@ impl Computer {
|
||||
}
|
||||
}
|
||||
}
|
||||
self.write_modrm(target, ImmediateOperand::from(bits));
|
||||
self.write_modrm(target, ImmediateOperand::from(bits))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ use crate::{
|
||||
interpreter::{
|
||||
computer::{CarryUsage, RotationDirection},
|
||||
interrupt::Mess1,
|
||||
memory::Memory,
|
||||
register::SegmentRegister,
|
||||
},
|
||||
operands::{Byte, ImmediateOperand, ModRmTarget, Word},
|
||||
@@ -86,56 +85,60 @@ impl Interpreter {
|
||||
Mnemonic::ADD_FromReg(dest, src) => self.computer.add(
|
||||
dest,
|
||||
ArithmeticOperand::ModRmTarget(ModRmTarget::Register(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::ADD_ToReg(src, dest) => self.computer.add(
|
||||
ModRmTarget::Register(dest),
|
||||
ArithmeticOperand::ModRmTarget(src),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::ADD_Ib(dest, src) => self.computer.add(
|
||||
dest,
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::ADD_Iv(dest, src) => self.computer.add(
|
||||
dest,
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Word(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::ADD_ALIb(src_byte) => self.computer.add(
|
||||
ModRmTarget::Register(crate::register::Register::AL),
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(src_byte)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::ADD_AXIv(src_word) => self.computer.add(
|
||||
ModRmTarget::Register(crate::register::Register::AX),
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Word(src_word)),
|
||||
),
|
||||
)?,
|
||||
/*
|
||||
* PUSH
|
||||
*/
|
||||
Mnemonic::PUSH_R(reg) => self.computer.push_stack(self.computer.regs.read(reg))?,
|
||||
Mnemonic::PUSH_Mod(target) => {
|
||||
self.computer.push_stack(self.computer.read_modrm(target))?
|
||||
}
|
||||
Mnemonic::PUSH_Mod(target) => self
|
||||
.computer
|
||||
.push_stack(self.computer.read_modrm(target)?)?,
|
||||
Mnemonic::PUSH_S(_) => todo!(),
|
||||
|
||||
/*
|
||||
* POP
|
||||
*/
|
||||
Mnemonic::POP_R(reg) => {
|
||||
let val = self.computer.pop_stack()?.into();
|
||||
self.computer.regs.write(reg, val);
|
||||
let val = self.computer.pop_stack()?;
|
||||
self.computer.regs.write(reg, val.into());
|
||||
}
|
||||
Mnemonic::POP_M(idx) => {
|
||||
let val = self.computer.pop_stack()?.into();
|
||||
let val = self.computer.pop_stack()?;
|
||||
self.computer.memory.write_raw(
|
||||
Memory::absolute_addr_from_idx(
|
||||
&self.computer.regs,
|
||||
&self.computer.sregs,
|
||||
idx,
|
||||
)
|
||||
.into(),
|
||||
val,
|
||||
self.computer
|
||||
.mem_addr(idx, &crate::register::SegmentRegister::SS),
|
||||
val.into(),
|
||||
)?
|
||||
}
|
||||
Mnemonic::POP_S(_) => todo!(),
|
||||
Mnemonic::POP_S(sreg) => {
|
||||
let val = self.computer.pop_stack()?;
|
||||
match sreg {
|
||||
crate::register::SegmentRegister::DS => self.computer.sregs.ds = val,
|
||||
crate::register::SegmentRegister::ES => self.computer.sregs.es = val,
|
||||
crate::register::SegmentRegister::SS => self.computer.sregs.ss = val,
|
||||
crate::register::SegmentRegister::CS => self.computer.sregs.cs = val,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* OR
|
||||
@@ -143,27 +146,27 @@ impl Interpreter {
|
||||
Mnemonic::OR_FromReg(dest, src) => self.computer.or(
|
||||
dest,
|
||||
ArithmeticOperand::ModRmTarget(ModRmTarget::Register(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::OR_ToReg(src, dest) => self.computer.or(
|
||||
ModRmTarget::Register(dest),
|
||||
ArithmeticOperand::ModRmTarget(src),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::OR_Ib(dest, src) => self.computer.or(
|
||||
dest,
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::OR_Iv(dest, src) => self.computer.or(
|
||||
dest,
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Word(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::OR_ALIb(src_byte) => self.computer.or(
|
||||
ModRmTarget::Register(crate::register::Register::AL),
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(src_byte)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::OR_AXIv(src_word) => self.computer.or(
|
||||
ModRmTarget::Register(crate::register::Register::AX),
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Word(src_word)),
|
||||
),
|
||||
)?,
|
||||
|
||||
/*
|
||||
* ADC - add with carry
|
||||
@@ -171,27 +174,27 @@ impl Interpreter {
|
||||
Mnemonic::ADC_FromReg(dest, src) => self.computer.adc(
|
||||
dest,
|
||||
ArithmeticOperand::ModRmTarget(ModRmTarget::Register(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::ADC_ToReg(src, dest) => self.computer.adc(
|
||||
ModRmTarget::Register(dest),
|
||||
ArithmeticOperand::ModRmTarget(src),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::ADC_Ib(dest, src) => self.computer.adc(
|
||||
dest,
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::ADC_Iv(dest, src) => self.computer.adc(
|
||||
dest,
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Word(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::ADC_ALIb(src_byte) => self.computer.adc(
|
||||
ModRmTarget::Register(crate::register::Register::AL),
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(src_byte)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::ADC_AXIv(src_word) => self.computer.adc(
|
||||
ModRmTarget::Register(crate::register::Register::AX),
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Word(src_word)),
|
||||
),
|
||||
)?,
|
||||
|
||||
/*
|
||||
* SBB - subtract with borrow
|
||||
@@ -199,27 +202,27 @@ impl Interpreter {
|
||||
Mnemonic::SBB_FromReg(dest, src) => self.computer.sbb(
|
||||
dest,
|
||||
ArithmeticOperand::ModRmTarget(ModRmTarget::Register(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::SBB_ToReg(src, dest) => self.computer.sbb(
|
||||
ModRmTarget::Register(dest),
|
||||
ArithmeticOperand::ModRmTarget(src),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::SBB_Ib(dest, src) => self.computer.sbb(
|
||||
dest,
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::SBB_Iv(dest, src) => self.computer.sbb(
|
||||
dest,
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Word(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::SBB_ALIb(src_byte) => self.computer.sbb(
|
||||
ModRmTarget::Register(crate::register::Register::AL),
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(src_byte)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::SBB_AXIv(src_word) => self.computer.sbb(
|
||||
ModRmTarget::Register(crate::register::Register::AX),
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Word(src_word)),
|
||||
),
|
||||
)?,
|
||||
|
||||
/*
|
||||
* AND
|
||||
@@ -227,27 +230,27 @@ impl Interpreter {
|
||||
Mnemonic::AND_FromReg(dest, src) => self.computer.and(
|
||||
dest,
|
||||
ArithmeticOperand::ModRmTarget(ModRmTarget::Register(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::AND_ToReg(src, dest) => self.computer.and(
|
||||
ModRmTarget::Register(dest),
|
||||
ArithmeticOperand::ModRmTarget(src),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::AND_Ib(dest, src) => self.computer.and(
|
||||
dest,
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::AND_Iv(dest, src) => self.computer.and(
|
||||
dest,
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Word(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::AND_ALIb(src_byte) => self.computer.and(
|
||||
ModRmTarget::Register(crate::register::Register::AL),
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(src_byte)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::AND_AXIv(src_word) => self.computer.and(
|
||||
ModRmTarget::Register(crate::register::Register::AX),
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Word(src_word)),
|
||||
),
|
||||
)?,
|
||||
/*
|
||||
* Override
|
||||
*/
|
||||
@@ -262,27 +265,27 @@ impl Interpreter {
|
||||
Mnemonic::SUB_FromReg(dest, src) => self.computer.sub(
|
||||
dest,
|
||||
ArithmeticOperand::ModRmTarget(ModRmTarget::Register(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::SUB_ToReg(src, dest) => self.computer.sub(
|
||||
ModRmTarget::Register(dest),
|
||||
ArithmeticOperand::ModRmTarget(src),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::SUB_Ib(dest, src) => self.computer.sub(
|
||||
dest,
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::SUB_Iv(dest, src) => self.computer.sub(
|
||||
dest,
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Word(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::SUB_ALIb(src_byte) => self.computer.sub(
|
||||
ModRmTarget::Register(crate::register::Register::AL),
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(src_byte)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::SUB_AXIv(src_word) => self.computer.sub(
|
||||
ModRmTarget::Register(crate::register::Register::AX),
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Word(src_word)),
|
||||
),
|
||||
)?,
|
||||
|
||||
/*
|
||||
* XOR
|
||||
@@ -290,27 +293,27 @@ impl Interpreter {
|
||||
Mnemonic::XOR_FromReg(dest, src) => self.computer.xor(
|
||||
dest,
|
||||
ArithmeticOperand::ModRmTarget(ModRmTarget::Register(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::XOR_ToReg(src, dest) => self.computer.xor(
|
||||
ModRmTarget::Register(dest),
|
||||
ArithmeticOperand::ModRmTarget(src),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::XOR_Ib(dest, src) => self.computer.xor(
|
||||
dest,
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::XOR_Iv(dest, src) => self.computer.xor(
|
||||
dest,
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Word(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::XOR_ALIb(src_byte) => self.computer.xor(
|
||||
ModRmTarget::Register(crate::register::Register::AL),
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(src_byte)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::XOR_AXIv(src_word) => self.computer.xor(
|
||||
ModRmTarget::Register(crate::register::Register::AX),
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Word(src_word)),
|
||||
),
|
||||
)?,
|
||||
|
||||
/*
|
||||
* CMP
|
||||
@@ -318,27 +321,27 @@ impl Interpreter {
|
||||
Mnemonic::CMP_FromReg(dest, src) => self.computer.cmp(
|
||||
dest,
|
||||
ArithmeticOperand::ModRmTarget(ModRmTarget::Register(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::CMP_ToReg(src, dest) => self.computer.cmp(
|
||||
ModRmTarget::Register(dest),
|
||||
ArithmeticOperand::ModRmTarget(src),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::CMP_Ib(dest, src) => self.computer.cmp(
|
||||
dest,
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::CMP_Iv(dest, src) => self.computer.cmp(
|
||||
dest,
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Word(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::CMP_ALIb(src_byte) => self.computer.cmp(
|
||||
ModRmTarget::Register(crate::register::Register::AL),
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(src_byte)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::CMP_AXIv(src_word) => self.computer.cmp(
|
||||
ModRmTarget::Register(crate::register::Register::AX),
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Word(src_word)),
|
||||
),
|
||||
)?,
|
||||
|
||||
/*
|
||||
* INC
|
||||
@@ -348,8 +351,8 @@ impl Interpreter {
|
||||
.regs
|
||||
.write(reg, self.computer.regs.read(reg) + 1),
|
||||
Mnemonic::INC_Mod(target) => {
|
||||
let val = self.computer.read_modrm(target);
|
||||
self.computer.write_modrm(target, val + 1);
|
||||
let val = self.computer.read_modrm(target)?;
|
||||
self.computer.write_modrm(target, val + 1)?
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -360,8 +363,8 @@ impl Interpreter {
|
||||
.regs
|
||||
.write(reg, self.computer.regs.read(reg) - 1),
|
||||
Mnemonic::DEC_Mod(target) => {
|
||||
let val = self.computer.read_modrm(target);
|
||||
self.computer.write_modrm(target, val - 1);
|
||||
let val = self.computer.read_modrm(target)?;
|
||||
self.computer.write_modrm(target, val - 1)?
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -431,23 +434,12 @@ impl Interpreter {
|
||||
ptr.word.into(),
|
||||
);
|
||||
}
|
||||
Mnemonic::JMP_Mod(target) => match target {
|
||||
ModRmTarget::Memory(idx) => Self::ip_jump(
|
||||
Mnemonic::JMP_Mod(target) => Self::ip_jump(
|
||||
&self.instructions,
|
||||
&mut ip,
|
||||
&self.computer.sregs,
|
||||
self.computer
|
||||
.memory
|
||||
.read(&self.computer.regs, &self.computer.sregs, idx)
|
||||
.into(),
|
||||
self.computer.read_modrm(target)?.into(),
|
||||
),
|
||||
ModRmTarget::Register(register) => Self::ip_jump(
|
||||
&self.instructions,
|
||||
&mut ip,
|
||||
&self.computer.sregs,
|
||||
self.computer.regs.read(register).into(),
|
||||
),
|
||||
},
|
||||
Mnemonic::CALL_p(ptr) => {
|
||||
if let Some(next_instr) = ip.next() {
|
||||
self.computer.push_stack(next_instr.addr.into())?;
|
||||
@@ -474,7 +466,7 @@ impl Interpreter {
|
||||
&self.instructions,
|
||||
&mut ip,
|
||||
&self.computer.sregs,
|
||||
self.computer.read_modrm(target).into(),
|
||||
self.computer.read_modrm(target)?.into(),
|
||||
);
|
||||
}
|
||||
Mnemonic::CALL_Mp(ptr) => {
|
||||
@@ -495,31 +487,31 @@ impl Interpreter {
|
||||
Mnemonic::TEST(dest, src) => self.computer.test(
|
||||
dest,
|
||||
ArithmeticOperand::ModRmTarget(ModRmTarget::Register(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::TEST_Ib(dest, src) => self.computer.test(
|
||||
dest,
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::TEST_Iv(dest, src) => self.computer.test(
|
||||
dest,
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Word(src)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::TEST_ALIb(src_byte) => self.computer.test(
|
||||
ModRmTarget::Register(crate::register::Register::AL),
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(src_byte)),
|
||||
),
|
||||
)?,
|
||||
Mnemonic::TEST_AXIv(src_word) => self.computer.test(
|
||||
ModRmTarget::Register(crate::register::Register::AX),
|
||||
ArithmeticOperand::Immediate(ImmediateOperand::Word(src_word)),
|
||||
),
|
||||
)?,
|
||||
|
||||
/*
|
||||
* XCHG
|
||||
*/
|
||||
Mnemonic::XCHG(target, reg) => {
|
||||
let tmp = self.computer.read_modrm(target);
|
||||
let tmp = self.computer.read_modrm(target)?;
|
||||
self.computer
|
||||
.write_modrm(target, self.computer.regs.read(reg));
|
||||
.write_modrm(target, self.computer.regs.read(reg))?;
|
||||
self.computer.regs.write(reg, tmp);
|
||||
}
|
||||
Mnemonic::XCHG_AX(reg) => {
|
||||
@@ -535,15 +527,15 @@ impl Interpreter {
|
||||
*/
|
||||
Mnemonic::MOV_FromReg(target, reg) => self
|
||||
.computer
|
||||
.write_modrm(target, self.computer.regs.read(reg)),
|
||||
.write_modrm(target, self.computer.regs.read(reg))?,
|
||||
Mnemonic::MOV_ToReg(target, reg) => self
|
||||
.computer
|
||||
.regs
|
||||
.write(reg, self.computer.read_modrm(target)),
|
||||
.write(reg, self.computer.read_modrm(target)?),
|
||||
Mnemonic::MOV_FromSReg(_, _) => todo!(),
|
||||
Mnemonic::MOV_ToSReg(_, _) => todo!(),
|
||||
Mnemonic::MOV_Ib(target, val) => self.computer.write_modrm(target, val.into()),
|
||||
Mnemonic::MOV_Iv(target, val) => self.computer.write_modrm(target, val.into()),
|
||||
Mnemonic::MOV_Ib(target, val) => self.computer.write_modrm(target, val.into())?,
|
||||
Mnemonic::MOV_Iv(target, val) => self.computer.write_modrm(target, val.into())?,
|
||||
|
||||
Mnemonic::MOV_AL0b(val) => self.computer.regs.ax.lower = val,
|
||||
Mnemonic::MOV_AX0v(val) => self.computer.regs.ax.write(val),
|
||||
@@ -572,11 +564,9 @@ impl Interpreter {
|
||||
*/
|
||||
Mnemonic::LEA(target, reg) => {
|
||||
let val = match target {
|
||||
ModRmTarget::Memory(idx) => Memory::absolute_addr_from_idx(
|
||||
&self.computer.regs,
|
||||
&self.computer.sregs,
|
||||
idx,
|
||||
)
|
||||
ModRmTarget::Memory(idx) => self
|
||||
.computer
|
||||
.mem_addr(idx, &crate::register::SegmentRegister::DS)
|
||||
.into(),
|
||||
ModRmTarget::Register(reg) => self.computer.regs.read(reg),
|
||||
};
|
||||
@@ -632,28 +622,16 @@ impl Interpreter {
|
||||
* Load ES/DS Register
|
||||
*/
|
||||
Mnemonic::LES(reg, ptr) => {
|
||||
let offset = self
|
||||
.computer
|
||||
.memory
|
||||
.read_raw(self.computer.sregs.ds * 16 + ptr.word)?;
|
||||
let segment = self
|
||||
.computer
|
||||
.memory
|
||||
.read_raw(self.computer.sregs.ds * 16 + ptr.word + 2)?;
|
||||
let offset = self.computer.read(ptr.into())?;
|
||||
let segment = self.computer.read((ptr + 2).into())?;
|
||||
self.computer.sregs.es = segment;
|
||||
self.computer
|
||||
.regs
|
||||
.write(reg, ImmediateOperand::from(offset));
|
||||
}
|
||||
Mnemonic::LDS(reg, ptr) => {
|
||||
let offset = self
|
||||
.computer
|
||||
.memory
|
||||
.read_raw(self.computer.sregs.ds * 16 + ptr.word)?;
|
||||
let segment = self
|
||||
.computer
|
||||
.memory
|
||||
.read_raw(self.computer.sregs.ds * 16 + ptr.word + 2)?;
|
||||
let offset = self.computer.read(ptr.into())?;
|
||||
let segment = self.computer.read((ptr + 2).into())?;
|
||||
self.computer.sregs.ds = segment;
|
||||
self.computer
|
||||
.regs
|
||||
@@ -665,11 +643,11 @@ impl Interpreter {
|
||||
*/
|
||||
Mnemonic::NOT(target) => {
|
||||
self.computer
|
||||
.write_modrm(target, !self.computer.read_modrm(target));
|
||||
.write_modrm(target, !self.computer.read_modrm(target)?)?;
|
||||
}
|
||||
Mnemonic::NEG(target) => {
|
||||
let val = !self.computer.read_modrm(target);
|
||||
self.computer.write_modrm(target, val + 0b1);
|
||||
let val = !self.computer.read_modrm(target)?;
|
||||
self.computer.write_modrm(target, val + 0b1)?;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -696,68 +674,68 @@ impl Interpreter {
|
||||
b.into(),
|
||||
CarryUsage::ReceiveCopy,
|
||||
RotationDirection::Left,
|
||||
),
|
||||
)?,
|
||||
Mnemonic::ROR_b(target, b) => self.computer.rotate(
|
||||
target,
|
||||
b.into(),
|
||||
CarryUsage::ReceiveCopy,
|
||||
RotationDirection::Right,
|
||||
),
|
||||
)?,
|
||||
Mnemonic::RCL_b(target, b) => self.computer.rotate(
|
||||
target,
|
||||
b.into(),
|
||||
CarryUsage::FullRotation,
|
||||
RotationDirection::Left,
|
||||
),
|
||||
)?,
|
||||
Mnemonic::RCR_b(target, b) => self.computer.rotate(
|
||||
target,
|
||||
b.into(),
|
||||
CarryUsage::FullRotation,
|
||||
RotationDirection::Right,
|
||||
),
|
||||
)?,
|
||||
Mnemonic::ROL_fromReg(target, reg) => self.computer.rotate(
|
||||
target,
|
||||
self.computer.regs.read(reg).into(),
|
||||
CarryUsage::ReceiveCopy,
|
||||
RotationDirection::Left,
|
||||
),
|
||||
)?,
|
||||
Mnemonic::ROR_fromReg(target, reg) => self.computer.rotate(
|
||||
target,
|
||||
self.computer.regs.read(reg).into(),
|
||||
CarryUsage::ReceiveCopy,
|
||||
RotationDirection::Right,
|
||||
),
|
||||
)?,
|
||||
Mnemonic::RCL_fromReg(target, reg) => self.computer.rotate(
|
||||
target,
|
||||
self.computer.regs.read(reg).into(),
|
||||
CarryUsage::FullRotation,
|
||||
RotationDirection::Left,
|
||||
),
|
||||
)?,
|
||||
Mnemonic::RCR_fromReg(target, reg) => self.computer.rotate(
|
||||
target,
|
||||
self.computer.regs.read(reg).into(),
|
||||
CarryUsage::FullRotation,
|
||||
RotationDirection::Right,
|
||||
),
|
||||
)?,
|
||||
|
||||
/*
|
||||
* Shfit
|
||||
*/
|
||||
Mnemonic::SHL_b(target, b) => self
|
||||
.computer
|
||||
.write_modrm(target, self.computer.read_modrm(target) << b),
|
||||
.write_modrm(target, self.computer.read_modrm(target)? << b)?,
|
||||
Mnemonic::SHR_b(target, b) => self
|
||||
.computer
|
||||
.write_modrm(target, self.computer.read_modrm(target) >> b),
|
||||
.write_modrm(target, self.computer.read_modrm(target)? >> b)?,
|
||||
Mnemonic::SAR_b(_, _) => todo!(),
|
||||
Mnemonic::SHL_fromReg(target, reg) => self.computer.write_modrm(
|
||||
target,
|
||||
self.computer.read_modrm(target) << self.computer.regs.read(reg),
|
||||
),
|
||||
self.computer.read_modrm(target)? << self.computer.regs.read(reg),
|
||||
)?,
|
||||
Mnemonic::SHR_fromReg(target, reg) => self.computer.write_modrm(
|
||||
target,
|
||||
self.computer.read_modrm(target) >> self.computer.regs.read(reg),
|
||||
),
|
||||
self.computer.read_modrm(target)? >> self.computer.regs.read(reg),
|
||||
)?,
|
||||
Mnemonic::SAR_fromReg(_, _) => todo!(),
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use crate::operands::{Byte, ImmediateOperand, ImmediateOperandSigned, MemoryIndex, Word};
|
||||
use crate::operands::{Byte, ImmediateOperand, Word};
|
||||
|
||||
use super::interpreter::InterpreterError;
|
||||
use crate::interpreter::register::{Register, SegmentRegister};
|
||||
|
||||
/// 2*20 = 1MiB
|
||||
const MEMORY_SIZE: usize = 1048576;
|
||||
@@ -18,18 +17,25 @@ impl Memory {
|
||||
}
|
||||
}
|
||||
|
||||
/// Safely writes a [`Word`] into an index of memory.
|
||||
/// Safely writes a [`ImmediateOperand`] into an index of memory.
|
||||
/// Warning: Does access at `addr`, not `DS:addr`!
|
||||
pub fn write_raw(&mut self, addr: Word, val: Word) -> Result<(), InterpreterError> {
|
||||
pub fn write_raw(&mut self, addr: Word, val: ImmediateOperand) -> Result<(), InterpreterError> {
|
||||
if (addr + 1) as usize > MEMORY_SIZE {
|
||||
return Err(InterpreterError::MemoryOutOfBound(addr));
|
||||
} else {
|
||||
let [low, high] = val.to_le_bytes();
|
||||
match val {
|
||||
ImmediateOperand::Byte(b) => {
|
||||
self.memory[addr as usize] = b;
|
||||
}
|
||||
ImmediateOperand::Word(w) => {
|
||||
let [low, high] = w.to_le_bytes();
|
||||
self.memory[addr as usize] = low;
|
||||
self.memory[(addr + 1) as usize] = high;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Safely reads a [`Word`] from an index of memory.
|
||||
/// Warning: Does access at `addr`, not `DS:addr`!
|
||||
@@ -46,69 +52,4 @@ impl Memory {
|
||||
.to_owned();
|
||||
Ok(Word::from_be_bytes([b2, b1]))
|
||||
}
|
||||
|
||||
/// Write an [`ImmediateOperand`] to a memory location indexed by a [`MemoryIndex`].
|
||||
pub fn write(
|
||||
&mut self,
|
||||
regs: &Register,
|
||||
sregs: &SegmentRegister,
|
||||
idx: MemoryIndex,
|
||||
val: ImmediateOperand,
|
||||
) {
|
||||
let idx = Memory::absolute_addr_from_idx(regs, sregs, idx);
|
||||
match val {
|
||||
ImmediateOperand::Byte(b) => {
|
||||
log::debug!("Writing byte {b:#04x} to memory location {idx:#04x}");
|
||||
self.memory[idx as usize] = b
|
||||
}
|
||||
ImmediateOperand::Word(value) => {
|
||||
let byte1 = idx / 2;
|
||||
let byte2 = idx / 2 + 1;
|
||||
let [low, high]: [u8; 2] = value.to_le_bytes();
|
||||
log::debug!(
|
||||
"Writing bytes {low:#04x} and {high:#04x} to memory location {byte1:#04x} and {byte2:#04x}"
|
||||
);
|
||||
self.memory[byte1 as usize] = low;
|
||||
self.memory[byte1 as usize] = high;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Read into memory with a [`MemoryIndex`] as index.
|
||||
/// Always reads a whole word.
|
||||
pub fn read(&self, regs: &Register, sregs: &SegmentRegister, idx: MemoryIndex) -> Word {
|
||||
let idx = Self::absolute_addr_from_idx(regs, sregs, idx);
|
||||
let byte1 = idx / 2;
|
||||
let byte2 = idx / 2 + 1;
|
||||
log::debug!("Reading bytes {byte1:#04x} and {byte2:#04x} from memory");
|
||||
Word::from_le_bytes([self.memory[byte1 as usize], self.memory[byte2 as usize]])
|
||||
}
|
||||
|
||||
/// Memory is always accessed with the data segment `ds` register as an offset.
|
||||
fn addr_offset(addr: Word, sregs: &crate::interpreter::register::SegmentRegister) -> Word {
|
||||
sregs.ds * 16 + addr
|
||||
}
|
||||
|
||||
/// Calculate the absolute memory address from a [`MemoryIndex`] struct.
|
||||
pub fn absolute_addr_from_idx(
|
||||
regs: &Register,
|
||||
sregs: &SegmentRegister,
|
||||
idx: MemoryIndex,
|
||||
) -> Word {
|
||||
let mut base = ImmediateOperand::Word(0);
|
||||
let mut index = ImmediateOperand::Word(0);
|
||||
let mut disp = ImmediateOperandSigned::Word(0);
|
||||
|
||||
if let Some(base_reg) = idx.base {
|
||||
base = regs.read(base_reg);
|
||||
};
|
||||
if let Some(index_reg) = idx.index {
|
||||
index = regs.read(index_reg);
|
||||
};
|
||||
if let Some(displacement) = idx.displacement {
|
||||
disp = ImmediateOperandSigned::from(displacement);
|
||||
}
|
||||
|
||||
Self::addr_offset((base + index + disp).into(), sregs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ impl Register {
|
||||
}
|
||||
|
||||
/// Decrement stack pointer
|
||||
pub fn push(&mut self) -> Result<(), InterpreterError> {
|
||||
pub fn push_sp(&mut self) -> Result<(), InterpreterError> {
|
||||
if self.sp < 2 {
|
||||
return Err(InterpreterError::InvalidRegisterState(*self));
|
||||
} else {
|
||||
@@ -40,7 +40,7 @@ impl Register {
|
||||
}
|
||||
|
||||
/// Increment stack pointer
|
||||
pub fn pop(&mut self) -> Result<(), InterpreterError> {
|
||||
pub fn pop_sp(&mut self) -> Result<(), InterpreterError> {
|
||||
if self.sp > 0xffff - 2 {
|
||||
return Err(InterpreterError::InvalidRegisterState(*self));
|
||||
} else {
|
||||
|
||||
@@ -148,6 +148,16 @@ impl From<usize> for ImmediateOperand {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<MemoryIndex> for ImmediateOperand {
|
||||
fn into(self) -> MemoryIndex {
|
||||
MemoryIndex {
|
||||
base: None,
|
||||
index: None,
|
||||
displacement: Some(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Word> for ImmediateOperand {
|
||||
fn into(self) -> u16 {
|
||||
match self {
|
||||
@@ -529,26 +539,6 @@ pub struct MemoryIndex {
|
||||
pub displacement: Option<ImmediateOperand>,
|
||||
}
|
||||
|
||||
impl MemoryIndex {
|
||||
/// Creates a [`MemoryIndex`] with just a single [`Register`]
|
||||
pub fn reg(reg: Register) -> Self {
|
||||
Self {
|
||||
base: Some(reg),
|
||||
index: None,
|
||||
displacement: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a [`MemoryIndex`] with an [`ImmediateOperand`]
|
||||
pub fn disp(disp: ImmediateOperand) -> Self {
|
||||
Self {
|
||||
base: None,
|
||||
index: None,
|
||||
displacement: Some(disp),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for MemoryIndex {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match &self.base {
|
||||
@@ -607,6 +597,26 @@ pub struct Pointer16 {
|
||||
pub word: Word,
|
||||
}
|
||||
|
||||
impl Into<MemoryIndex> for Pointer16 {
|
||||
fn into(self) -> MemoryIndex {
|
||||
MemoryIndex {
|
||||
base: None,
|
||||
index: None,
|
||||
displacement: Some(self.word.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<u16> for Pointer16 {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: u16) -> Self::Output {
|
||||
Self {
|
||||
word: self.word + rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Pointer16 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "ptr word [{:#04x}]", self.word)
|
||||
|
||||
Reference in New Issue
Block a user