ft(interpreter): impl push/pop
This commit is contained in:
@@ -1,16 +1,23 @@
|
|||||||
use core::fmt;
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Operand {
|
pub enum Operand {
|
||||||
Immediate(crate::operands::ImmediateOperand),
|
Immediate(crate::operands::ImmediateOperand),
|
||||||
ModRmTarget(ModRmTarget),
|
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 ArithmeticResult = ImmediateOperand;
|
||||||
type Lhs = ImmediateOperand;
|
type Lhs = ImmediateOperand;
|
||||||
type Rhs = 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.
|
/// Perform binary `dest` = `dest` + `src`. Sets flags.
|
||||||
pub fn add(&mut self, dest: ModRmTarget, src: Operand) {
|
pub fn add(&mut self, dest: ModRmTarget, src: Operand) {
|
||||||
let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs + rhs;
|
let op: fn(Lhs, Rhs) -> ArithmeticResult = |lhs, rhs| lhs + rhs;
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ use std::{fmt::Debug, process::exit};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
instructions::{Instruction, Mnemonic},
|
instructions::{Instruction, Mnemonic},
|
||||||
interpreter::{interrupt::Mess1, memory::Memory},
|
interpreter::{computer::PopTarget, interrupt::Mess1, memory::Memory},
|
||||||
operands::{Byte, ImmediateOperand, ModRmTarget},
|
operands::{Byte, ImmediateOperand, ModRmTarget, Word},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
@@ -17,8 +17,10 @@ type InstructionPointer<'a> = std::slice::Iter<'a, Instruction>;
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum InterpreterError {
|
pub enum InterpreterError {
|
||||||
EndOfData,
|
EndOfData,
|
||||||
InvalidSyscall(u8),
|
InvalidSyscall(Byte),
|
||||||
InstructionNotFound(usize),
|
InstructionNotFound(Word),
|
||||||
|
MemoryOutOfBound(Word),
|
||||||
|
InvalidRegisterState(crate::interpreter::register::Register),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for InterpreterError {
|
impl fmt::Display for InterpreterError {
|
||||||
@@ -31,6 +33,15 @@ impl fmt::Display for InterpreterError {
|
|||||||
InterpreterError::InstructionNotFound(addr) => {
|
InterpreterError::InstructionNotFound(addr) => {
|
||||||
write!(f, "IP({addr}) points at invalid instruction")
|
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
|
* 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
|
* 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
|
* OR
|
||||||
|
|||||||
@@ -1,16 +1,47 @@
|
|||||||
use crate::operands::{Byte, Displacement, ImmediateOperand, MemoryIndex, Word};
|
use crate::operands::{Byte, Displacement, ImmediateOperand, MemoryIndex, Word};
|
||||||
|
|
||||||
|
use super::interpreter::InterpreterError;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Memory {
|
pub struct Memory {
|
||||||
memory: [Byte; 65536],
|
memory: [Byte; Word::MAX as usize],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Memory {
|
impl Memory {
|
||||||
pub fn new() -> Self {
|
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(
|
pub fn write(
|
||||||
&mut self,
|
&mut self,
|
||||||
regs: &crate::interpreter::register::Register,
|
regs: &crate::interpreter::register::Register,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
use crate::operands::{Byte, ImmediateOperand, Word};
|
use crate::operands::{Byte, ImmediateOperand, Word};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
|
use super::interpreter::InterpreterError;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Register {
|
pub struct Register {
|
||||||
pub ax: AX,
|
pub ax: AX,
|
||||||
@@ -20,13 +22,33 @@ impl Register {
|
|||||||
bx: BX::new(),
|
bx: BX::new(),
|
||||||
cx: CX::new(),
|
cx: CX::new(),
|
||||||
dx: DX::new(),
|
dx: DX::new(),
|
||||||
sp: 0,
|
sp: 0xffff,
|
||||||
bp: 0,
|
bp: 0,
|
||||||
si: 0,
|
si: 0,
|
||||||
di: 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`].
|
/// Read value from a [`crate::register::Register`].
|
||||||
pub fn read(&self, reg: crate::register::Register) -> ImmediateOperand {
|
pub fn read(&self, reg: crate::register::Register) -> ImmediateOperand {
|
||||||
match reg {
|
match reg {
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ impl ImmediateOperand {
|
|||||||
match self {
|
match self {
|
||||||
Self::Byte(_) => {
|
Self::Byte(_) => {
|
||||||
return if self.msb() {
|
return if self.msb() {
|
||||||
self.flip_sign().as_word().flip_sign()
|
self.flip_sign().word().flip_sign()
|
||||||
} else {
|
} else {
|
||||||
self.as_word()
|
self.word()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Self::Word(_) => self,
|
Self::Word(_) => self,
|
||||||
@@ -46,7 +46,7 @@ impl ImmediateOperand {
|
|||||||
/// Interprets [`Self::Byte`] as [`Self::Word`].
|
/// Interprets [`Self::Byte`] as [`Self::Word`].
|
||||||
/// Returns word, if already a [`Self::Word`].
|
/// Returns word, if already a [`Self::Word`].
|
||||||
/// CAUTION: You probably want to use [`Self::sign_extend()`] instead.
|
/// CAUTION: You probably want to use [`Self::sign_extend()`] instead.
|
||||||
fn as_word(self) -> Self {
|
fn word(self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Byte(b) => Self::Word(b as Word),
|
Self::Byte(b) => Self::Word(b as Word),
|
||||||
Self::Word(_) => self,
|
Self::Word(_) => self,
|
||||||
@@ -566,7 +566,7 @@ mod tests {
|
|||||||
let b: u8 = 5;
|
let b: u8 = 5;
|
||||||
let byte = ImmediateOperand::Byte(b);
|
let byte = ImmediateOperand::Byte(b);
|
||||||
let word = ImmediateOperand::Word(b as Word);
|
let word = ImmediateOperand::Word(b as Word);
|
||||||
assert_eq!(byte.as_word(), word);
|
assert_eq!(byte.word(), word);
|
||||||
assert_eq!(word, word);
|
assert_eq!(word, word);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user