ft(interpreter): impl push/pop

This commit is contained in:
2025-06-17 10:39:49 +09:00
parent d1ea96edd8
commit 5fab099cd8
5 changed files with 116 additions and 15 deletions

View File

@@ -1,16 +1,23 @@
use core::fmt;
use crate::operands::{ImmediateOperand, ModRmTarget};
use crate::operands::{ImmediateOperand, MemoryIndex, ModRmTarget};
use super::{flags::Flags, memory::Memory, register::Register};
use super::{flags::Flags, interpreter::InterpreterError, memory::Memory, register::Register};
/// Wrapper for easier argument passing of multi-type operations.
/// Wrapper for easier argument passing of polymorph arithmetic operations.
#[derive(Debug, Clone)]
pub enum Operand {
Immediate(crate::operands::ImmediateOperand),
ModRmTarget(ModRmTarget),
}
/// Wrapper for easier argument passing of polymorph pop operations.
#[derive(Debug, Clone)]
pub enum PopTarget {
Register(crate::register::Register),
MemoryIndex(MemoryIndex),
}
type ArithmeticResult = ImmediateOperand;
type Lhs = ImmediateOperand;
type Rhs = ImmediateOperand;
@@ -31,6 +38,28 @@ 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.regs.sp, val.into())
}
/// Retrieve value from stack and increment stack pointer.
pub fn pop_stack(&mut self, target: PopTarget) -> Result<(), InterpreterError> {
let word = self.memory.read_raw(self.regs.sp)?;
match target {
PopTarget::Register(reg) => self.regs.write(reg, word.into()),
PopTarget::MemoryIndex(mem_idx) => self
.memory
.write_raw(Memory::calc_memidx(&self.regs, mem_idx).into(), word.into())?,
}
self.regs.pop()?;
Ok(())
}
/// Perform binary `dest` = `dest` + `src`. Sets flags.
pub fn add(&mut self, dest: ModRmTarget, src: Operand) {
let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs + rhs;

View File

@@ -3,8 +3,8 @@ use std::{fmt::Debug, process::exit};
use crate::{
instructions::{Instruction, Mnemonic},
interpreter::{interrupt::Mess1, memory::Memory},
operands::{Byte, ImmediateOperand, ModRmTarget},
interpreter::{computer::PopTarget, interrupt::Mess1, memory::Memory},
operands::{Byte, ImmediateOperand, ModRmTarget, Word},
};
use super::{
@@ -17,8 +17,10 @@ type InstructionPointer<'a> = std::slice::Iter<'a, Instruction>;
#[derive(Debug, Clone)]
pub enum InterpreterError {
EndOfData,
InvalidSyscall(u8),
InstructionNotFound(usize),
InvalidSyscall(Byte),
InstructionNotFound(Word),
MemoryOutOfBound(Word),
InvalidRegisterState(crate::interpreter::register::Register),
}
impl fmt::Display for InterpreterError {
@@ -31,6 +33,15 @@ impl fmt::Display for InterpreterError {
InterpreterError::InstructionNotFound(addr) => {
write!(f, "IP({addr}) points at invalid instruction")
}
InterpreterError::MemoryOutOfBound(addr) => {
write!(
f,
"Attempted memory write out of physical bounds: ({addr:#04x})"
)
}
InterpreterError::InvalidRegisterState(reg) => {
write!(f, "Invalid Register State: {reg:?}")
}
}
}
}
@@ -90,10 +101,18 @@ impl Interpreter {
/*
* 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_S(_) => todo!(),
/*
* POP
*/
Mnemonic::POP_R(reg) => self.computer.pop_stack(PopTarget::Register(reg))?,
Mnemonic::POP_M(idx) => self.computer.pop_stack(PopTarget::MemoryIndex(idx))?,
Mnemonic::POP_S(_) => todo!(),
/*
* OR

View File

@@ -1,16 +1,47 @@
use crate::operands::{Byte, Displacement, ImmediateOperand, MemoryIndex, Word};
use super::interpreter::InterpreterError;
#[derive(Debug, Clone, Copy)]
pub struct Memory {
memory: [Byte; 65536],
memory: [Byte; Word::MAX as usize],
}
impl Memory {
pub fn new() -> Self {
Self { memory: [0; 65536] }
Self {
memory: [0; Word::MAX as usize],
}
}
// Write an [`ImmediateOperand`] to a memory location indexed by a [`MemoryIndex`].
/// Safely writes a [`Word`] into an index of memory.
pub fn write_raw(&mut self, idx: Word, val: Word) -> Result<(), InterpreterError> {
if idx + 1 > Word::MAX {
return Err(InterpreterError::MemoryOutOfBound(idx));
} else {
let [low, high] = val.to_le_bytes();
self.memory[idx as usize] = low;
self.memory[(idx + 1) as usize] = high;
Ok(())
}
}
/// Safely reads a [`Word`] from an index of memory
pub fn read_raw(&self, idx: Word) -> Result<Word, InterpreterError> {
let b1 = self
.memory
.get(idx as usize)
.ok_or(InterpreterError::MemoryOutOfBound(idx))?
.to_owned();
let b2 = self
.memory
.get((idx + 1) as usize)
.ok_or(InterpreterError::MemoryOutOfBound(idx))?
.to_owned();
Ok(Word::from_be_bytes([b1, b2]))
}
/// Write an [`ImmediateOperand`] to a memory location indexed by a [`MemoryIndex`].
pub fn write(
&mut self,
regs: &crate::interpreter::register::Register,

View File

@@ -1,6 +1,8 @@
use crate::operands::{Byte, ImmediateOperand, Word};
use core::fmt;
use super::interpreter::InterpreterError;
#[derive(Debug, Clone, Copy)]
pub struct Register {
pub ax: AX,
@@ -20,13 +22,33 @@ impl Register {
bx: BX::new(),
cx: CX::new(),
dx: DX::new(),
sp: 0,
sp: 0xffff,
bp: 0,
si: 0,
di: 0,
}
}
/// Decrement stack pointer
pub fn push(&mut self) -> Result<(), InterpreterError> {
if self.sp <= 2 {
return Err(InterpreterError::InvalidRegisterState(*self));
} else {
self.sp -= 2;
Ok(())
}
}
/// Increment stack pointer
pub fn pop(&mut self) -> Result<(), InterpreterError> {
if self.sp >= 0xffff - 2 {
return Err(InterpreterError::InvalidRegisterState(*self));
} else {
self.sp += 2;
Ok(())
}
}
/// Read value from a [`crate::register::Register`].
pub fn read(&self, reg: crate::register::Register) -> ImmediateOperand {
match reg {

View File

@@ -34,9 +34,9 @@ impl ImmediateOperand {
match self {
Self::Byte(_) => {
return if self.msb() {
self.flip_sign().as_word().flip_sign()
self.flip_sign().word().flip_sign()
} else {
self.as_word()
self.word()
};
}
Self::Word(_) => self,
@@ -46,7 +46,7 @@ impl ImmediateOperand {
/// Interprets [`Self::Byte`] as [`Self::Word`].
/// Returns word, if already a [`Self::Word`].
/// CAUTION: You probably want to use [`Self::sign_extend()`] instead.
fn as_word(self) -> Self {
fn word(self) -> Self {
match self {
Self::Byte(b) => Self::Word(b as Word),
Self::Word(_) => self,
@@ -566,7 +566,7 @@ mod tests {
let b: u8 = 5;
let byte = ImmediateOperand::Byte(b);
let word = ImmediateOperand::Word(b as Word);
assert_eq!(byte.as_word(), word);
assert_eq!(byte.word(), word);
assert_eq!(word, word);
}