Skip to content
This repository has been archived by the owner on Aug 30, 2024. It is now read-only.

Commit

Permalink
feat: flags handling, errors
Browse files Browse the repository at this point in the history
  • Loading branch information
julio4 committed Jul 9, 2024
1 parent ee23342 commit a354535
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 33 deletions.
14 changes: 14 additions & 0 deletions src/interpreter/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#[derive(Debug, PartialEq)]
pub enum InterpreterError {
InvalidArgs,
CycleLimitExceeded,
}

impl std::fmt::Display for InterpreterError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
InterpreterError::InvalidArgs => write!(f, "Invalid arguments"),
InterpreterError::CycleLimitExceeded => write!(f, "Cycle limit exceeded"),
}
}
}
15 changes: 15 additions & 0 deletions src/interpreter/flag_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ impl Flag {
.iter()
.copied()
}

pub fn result(&self, value: i16) -> bool {
match self {
Flag::Zero => value == 0,
Flag::Sign => value < 0,
Flag::Parity => value.count_ones() % 2 == 0,
_ => unreachable!("Flag not supported"),
}
}
}

#[derive(Debug)]
Expand All @@ -57,6 +66,12 @@ impl FlagSet {
}
}

pub fn set_szp(&mut self, value: i16) {
self.set(Flag::Zero, Flag::Zero.result(value));
self.set(Flag::Sign, Flag::Sign.result(value));
self.set(Flag::Parity, Flag::Parity.result(value));
}

pub fn clear(&mut self, flag: Flag) {
self.set(flag, false);
}
Expand Down
1 change: 1 addition & 0 deletions src/interpreter/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod error;
mod flag_set;
mod memory;
mod register_set;
Expand Down
22 changes: 14 additions & 8 deletions src/interpreter/vm.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use super::error::InterpreterError;
use super::flag_set::FlagSet;
use super::memory::Memory;
use super::register_set::RegisterSet;
Expand Down Expand Up @@ -74,7 +75,7 @@ pub trait VmIrExecutable: OpcodeExecutable {
// + Implicit store
fn execute(&mut self, ir: IR);
// Run the VM from the program loaded in memory
fn run(&mut self);
fn run(&mut self) -> Result<(), InterpreterError>;
}

const MAX_INSTRUCTION_SIZE: usize = 15;
Expand Down Expand Up @@ -159,8 +160,9 @@ impl VmIrExecutable for VM {
}
}

fn run(&mut self) {
fn run(&mut self) -> Result<(), InterpreterError> {
trace!(" AX BX CX DX SP BP SI DI FLAGS IP");
let mut cycle_count = 0;
while let Some(ir) = self.fetch() {
let (decoded_ir, ir_len) = self.decode(ir);

Expand Down Expand Up @@ -223,17 +225,25 @@ impl VmIrExecutable for VM {

// Increment the instruction pointer (ip) appropriately
self.ip += ir_len as u16;

// Check cycle count
cycle_count += 1;
if cycle_count > 10000 {
return Err(InterpreterError::CycleLimitExceeded);
}
}

// trace!("Execution finished:\n{}", self);
Ok(())
}
}

pub trait Interpretable {
fn interpret(self);
fn interpret(self) -> Result<(), InterpreterError>;
}

impl Interpretable for Program {
fn interpret(self) {
fn interpret(self) -> Result<(), InterpreterError> {
VM::from(self).run()
}
}
Expand Down Expand Up @@ -300,7 +310,3 @@ impl std::fmt::Display for VM {
Ok(())
}
}

// #[cfg(test)]
// mod tests {
// }
41 changes: 17 additions & 24 deletions src/interpreter/vm/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,10 @@ impl OpcodeExecutable for VM {
self.write_value(&dest, result as u16);

self.flags.set(Flag::Overflow, overflow);
self.flags.set(Flag::Sign, result < 0);
self.flags.set(Flag::Zero, result == 0);
self.flags.set(Flag::Carry, result < src_value);
self.flags.set_szp(result);
self.flags
.set(Flag::Aux, (target_value & 0xf) + (src_value & 0xf) > 0xf);
self.flags.set(Flag::Carry, result < src_value);
self.flags.set(Flag::PageFault, false); // todo?
}
fn xor(&mut self, dest: Operand, src: Operand) {
let src_value = self.read_value(&src);
Expand All @@ -97,9 +95,7 @@ impl OpcodeExecutable for VM {
self.flags.clear(Flag::Overflow);
self.flags.clear(Flag::Carry);
// SF, ZF and PF based on result
self.flags.set(Flag::Sign, result < 0);
self.flags.set(Flag::Zero, result == 0);
self.flags.set(Flag::Parity, result.count_ones() % 2 == 0);
self.flags.set_szp(result);
}
fn lea(&mut self, dest: Operand, src: Operand) {
let address = match src {
Expand All @@ -121,11 +117,9 @@ impl OpcodeExecutable for VM {

self.flags.set(Flag::Carry, dest_value < src_value);
self.flags.set(Flag::Overflow, overflow);
self.flags.set(Flag::Sign, result < 0);
self.flags.set(Flag::Zero, result == 0);
self.flags.set_szp(result);
self.flags
.set(Flag::Aux, (dest_value & 0xf) < (src_value & 0xf));
self.flags.set(Flag::PageFault, false); // todo?
}
fn jnb(&mut self, dest: Operand) {
if !self.flags.get(Flag::Carry) {
Expand All @@ -151,9 +145,7 @@ impl OpcodeExecutable for VM {
self.flags.clear(Flag::Carry);
self.flags.clear(Flag::Overflow);
// SF, ZF, PF
self.flags.set(Flag::Sign, result < 0);
self.flags.set(Flag::Zero, result == 0);
self.flags.set(Flag::PageFault, false); // todo? BitwiseXNOR(result[0:7]);
self.flags.set_szp(result);
}
fn sub(&mut self, dest: Operand, src: Operand) {
let src_value = self.read_value(&src);
Expand All @@ -166,9 +158,7 @@ impl OpcodeExecutable for VM {
self.flags.clear(Flag::Carry);
self.flags.clear(Flag::Overflow);
// SF, ZF, PF
self.flags.set(Flag::Sign, result < 0);
self.flags.set(Flag::Zero, result == 0);
self.flags.set(Flag::PageFault, false); // todo? BitwiseXNOR(result[0:7]);
self.flags.set_szp(result);
}
fn push(&mut self, src: Operand) {
let value = self.read_value(&src) as u16;
Expand Down Expand Up @@ -216,13 +206,16 @@ impl OpcodeExecutable for VM {
}
}
fn or(&mut self, dest: Operand, src: Operand) {
let value = self.read_value(&src);
match dest {
Operand::Register(reg) => {
let current = self.regs.get(reg) as i16;
self.regs.set(reg, (current | value) as u16);
}
_ => unimplemented!(),
}
let src_value = self.read_value(&src);
let dest_value = self.read_value(&dest);
let result = dest_value | src_value;

self.write_value(&dest, result as u16);

// Clear
self.flags.clear(Flag::Overflow);
self.flags.clear(Flag::Carry);
// SF, ZF and PF based on result
self.flags.set_szp(result);
}
}
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ fn main() {
// println!("{}", disassembled);

// Interpreter
program.interpret();
program.interpret().unwrap();
}

0 comments on commit a354535

Please sign in to comment.