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

Commit

Permalink
feat: flag sets + opcodes
Browse files Browse the repository at this point in the history
  • Loading branch information
julio4 committed Jun 25, 2024
1 parent e170080 commit 95c03ab
Show file tree
Hide file tree
Showing 5 changed files with 279 additions and 27 deletions.
66 changes: 66 additions & 0 deletions src/interpreter/flag_set.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use log::trace;
use std::collections::HashMap;

#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Hash)]
pub enum Flag {
Zero,
Sign,
Parity,
Carry,
Overflow,
Direction,
Interrupt,
Trap,
}

impl Flag {
pub fn iter() -> impl Iterator<Item = Flag> {
[
Flag::Zero,
Flag::Sign,
Flag::Parity,
Flag::Carry,
Flag::Overflow,
Flag::Direction,
Flag::Interrupt,
Flag::Trap,
]
.iter()
.copied()
}
}

#[derive(Debug)]
pub struct FlagSet {
flags: HashMap<Flag, bool>,
}

impl FlagSet {
pub fn new() -> Self {
let mut flags = HashMap::new();
for flag in Flag::iter() {
flags.insert(flag, false);
}
Self { flags }
}

pub fn get(&self, flag: Flag) -> bool {
*self.flags.get(&flag).expect("Unknown flag")
}

pub fn set(&mut self, flag: Flag, value: bool) {
if let Some(val) = self.flags.get_mut(&flag) {
trace!("Set {:?}: {} (previous: {})", flag, value, *val);
*val = value;
}
}
}

impl std::fmt::Display for FlagSet {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for flag in Flag::iter() {
write!(f, "{:?}: {}\n", flag, self.get(flag))?;
}
Ok(())
}
}
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 flag_set;
mod memory;
mod register_set;
mod vm;
Expand Down
89 changes: 75 additions & 14 deletions src/interpreter/vm.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use super::flag_set::FlagSet;
use super::memory::Memory;
use super::register_set::RegisterSet;
use crate::interpreter::flag_set::Flag;
use crate::utils::{min, HexdumpFormatter};
use crate::x86::{Address, Displacement, Register};
use crate::x86::{Address, Displacement, Operand, Register};
use crate::{minix::Program, x86::IR};

use log::trace;
Expand All @@ -10,23 +12,29 @@ use log::trace;
mod opcodes;
use opcodes::OpcodeExecutable;

#[allow(dead_code)]
struct VM {
// cpu
pub ip: u16,
// memory
pub text: Memory,
pub data: Memory,
// registers
// registers, flags
pub regs: RegisterSet,
pub flags: u16,
pub flags: FlagSet,
}

impl From<Program> for VM {
fn from(program: Program) -> Self {
let text = Memory::from(program.text_segment.data);
let data = Memory::from(program.data_segment.data);
let regs = RegisterSet::new();
let flags = 0;

let size = 0x1000;
let mut data = Memory::new(size);
data.write_bytes(0, &program.data_segment.data);

let mut regs = RegisterSet::new();
regs.set(Register::SP, (data.len() - 2) as i16);
let flags = FlagSet::new();
let ip = 0;
VM {
ip,
Expand Down Expand Up @@ -83,21 +91,56 @@ impl VmIrExecutable for VM {
IR::Add { dest, src } => {
self.add(dest, src);
}
// pop, push, ...
_ => panic!("Not implemented"),
IR::Xor { dest, src } => {
self.xor(dest, src);
}
IR::Lea { dest, src } => {
self.lea(dest, src);
}
IR::Cmp { dest, src, byte: _ } => {
self.cmp(dest, src);
}
IR::Jnb { dest } => {
self.jnb(dest);
}
IR::Jne { dest } => {
self.jne(dest);
}
IR::Je { dest } => {
self.je(dest);
}
IR::Test { dest, src, byte: _ } => {
self.test(dest, src);
}
IR::Push { src } => {
self.push(src);
}
IR::Call { dest } => {
self.call(dest);
}
IR::In { dest, src } => {
self.in_(dest, src);
}
IR::Loopnz { dest } => {
self.loopnz(dest);
}
IR::Or { dest, src } => {
self.or(dest, src);
}
_ => panic!("{}: Not implemented", ir),
}
}

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

// Trace with format:
// AX BX CX DX SP BP SI DI FLAGS IP
// 0000 0000 0000 0000 0000 0000 0000 0000 ---- 0000:bb0000 mov bx, 000
trace!(
"{} \t{}",
"{} \t{}",
{
let mut regs = String::new();
for reg in vec![
Expand All @@ -112,10 +155,14 @@ impl VmIrExecutable for VM {
] {
regs.push_str(&format!("{:04x} ", self.regs.get(reg)));
}
let mut flags = String::new();
for flag in Flag::iter() {
flags.push_str(&format!("{}", self.flags.get(flag) as u8));
}
format!(
"{} {:04x} {:04x}:{}",
"{} {} {:04x}:{}",
regs,
self.flags,
flags,
self.ip,
&ir[..ir_len]
.iter()
Expand All @@ -131,7 +178,7 @@ impl VmIrExecutable for VM {
// Increment the instruction pointer (ip) appropriately
self.ip += ir_len as u16;
}
trace!("Execution finished:\n{}", self);
// trace!("Execution finished:\n{}", self);
}
}

Expand Down Expand Up @@ -165,12 +212,26 @@ impl VM {

base.wrapping_add(index).wrapping_add(disp) as u16
}

fn into_value(&self, operand: Operand) -> i16 {
match operand {
Operand::Register(reg) => self.regs.get(reg),
Operand::Immediate(value) => value as i16,
Operand::LongImmediate(value) => value as i16,
Operand::SignExtendedImmediate(value) => value as i16,
Operand::MemoryAddress(address) => {
let ea = self.get_effective_address(address);
self.data.read_word(ea) as i16
}
Operand::Displacement(value) => self.ip.wrapping_add(value.into()) as i16,
}
}
}

impl std::fmt::Display for VM {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "IP: {:04x}", self.ip)?;
writeln!(f, "FLAGS: {:04x}", self.flags)?;
writeln!(f, "FLAGS: {}", self.flags)?;
writeln!(f, "TEXT:")?;
write!(f, "{:?}", HexdumpFormatter(&self.text.data))?;
writeln!(f, "DATA:")?;
Expand Down
Loading

0 comments on commit 95c03ab

Please sign in to comment.