ft: initial work in interpreter

This commit is contained in:
2025-06-03 21:31:28 +09:00
parent 5ee80c9364
commit ac69d75273
8 changed files with 344 additions and 51 deletions

View File

@@ -0,0 +1,28 @@
use core::fmt;
use crate::operands::Byte;
use super::{flags::Flags, register::Register};
#[derive(Debug, Clone)]
pub struct Computer {
pub regs: Register,
pub flags: Flags,
pub memory: [Byte; 65536],
}
impl Computer {
pub fn new() -> Self {
Self {
regs: Register::new(),
flags: Flags::new(),
memory: [0; 65536],
}
}
}
impl fmt::Display for Computer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} | {}", self.regs, self.flags)
}
}

48
src/interpreter/flags.rs Normal file
View File

@@ -0,0 +1,48 @@
use core::fmt;
#[derive(Debug, Clone)]
pub struct Flags {
pub of: bool,
pub df: bool,
pub r#if: bool,
pub tf: bool,
pub sf: bool,
pub zf: bool,
pub nf: bool,
pub pf: bool,
pub cf: bool,
}
impl Flags {
pub fn new() -> Self {
Self {
of: false,
df: false,
r#if: false,
tf: false,
sf: false,
zf: false,
nf: false,
pf: false,
cf: false,
}
}
}
impl fmt::Display for Flags {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"OF({}) DF({}) IF({}) TF({}) SF({}) ZF({}) NF({}) PF({}) CF({})",
self.of as i32,
self.df as i32,
self.r#if as i32,
self.tf as i32,
self.sf as i32,
self.zf as i32,
self.nf as i32,
self.pf as i32,
self.cf as i32,
)
}
}

View File

@@ -0,0 +1,129 @@
use core::fmt;
use std::{fmt::Debug, process::exit};
use crate::{
instructions::{Instruction, Mnemonic},
operands::{Byte, Word},
};
use super::computer::Computer;
#[derive(Debug, Clone)]
pub enum InterpreterError {
EndOfData,
InvalidSyscall(u8),
}
impl fmt::Display for InterpreterError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
InterpreterError::EndOfData => write!(f, "Read beyond the available data section"),
InterpreterError::InvalidSyscall(id) => {
write!(f, "The syscall with ID {} is unknown", id)
}
}
}
}
#[derive(Debug, Clone)]
pub struct Interpreter {
computer: Computer,
instructions: Vec<Instruction>,
data: Vec<Byte>,
}
impl Interpreter {
pub fn new(instructions: Vec<Instruction>, data: Vec<Byte>) -> Self {
Self {
computer: Computer::new(),
instructions,
data,
}
}
pub fn interpret(&mut self) -> Result<(), InterpreterError> {
for instr in self.instructions.iter() {
log::info!(
"IP({:04x})\t {:<15} | {}",
instr.start,
instr.opcode.to_string(),
self.computer
);
match instr.opcode {
Mnemonic::MOV_BXIv(word) => self.computer.regs.bx.write(word),
Mnemonic::INT(id) => self.handle_int(id)?,
_ => todo!(),
}
}
Ok(())
}
fn handle_int(&self, id: u8) -> Result<(), InterpreterError> {
let bx = self.computer.regs.bx.read() as usize;
// a message is always 8 words aligned
let len = 2 * 8;
let data = self
.data
.get(bx..bx + len)
.ok_or(InterpreterError::EndOfData)?
.to_owned();
let interrupt_data = InterruptData::new(data);
// simulate interrupt handler code of MINIX
match id {
// sofware interrupts
0x20 => {
match interrupt_data.interrupt_id {
0x04 => {
let fd = interrupt_data.m_type;
let location = interrupt_data.data_position;
let len = interrupt_data.count;
log::info!("executing write({}, {}, {})", fd, location, len);
for byte in &self.data[location as usize..] {
if *byte == 0x00 {
break;
} else {
print!("{}", *byte as char);
}
}
}
0x01 => {
let exit_code = interrupt_data.data_position;
log::info!("executing exit({})", exit_code);
exit(exit_code.into())
}
_ => todo!(),
};
}
_ => return Err(InterpreterError::InvalidSyscall(id)),
}
Ok(())
}
}
#[derive(Debug, Clone)]
// https://cse.unl.edu/~goddard/Courses/CSCE351/Lectures/Lecture8.pdf
pub struct InterruptData {
pub m_type: Word, // Operation requested
pub interrupt_id: Word, // Minor device to use
pub proc_nr: Word, // Process requesting the I/O
pub count: Word, // Word count or ioctl code
pub position: Word, // Position on device
pub data_position: Word, // Minor device to use
}
impl InterruptData {
pub fn new(data: Vec<u8>) -> Self {
Self {
m_type: Word::from_le_bytes([data[0], data[1]]),
interrupt_id: Word::from_le_bytes([data[2], data[3]]),
proc_nr: Word::from_le_bytes([data[4], data[5]]),
count: Word::from_le_bytes([data[6], data[7]]),
position: Word::from_le_bytes([data[8], data[9]]),
data_position: Word::from_le_bytes([data[10], data[11]]),
}
}
}

4
src/interpreter/mod.rs Normal file
View File

@@ -0,0 +1,4 @@
mod computer;
mod flags;
pub mod interpreter;
mod register;

View File

@@ -0,0 +1,75 @@
use crate::operands::{Byte, Word};
use core::fmt;
#[derive(Debug, Clone, Copy)]
pub struct Register {
pub ax: AX,
pub bx: BX,
pub cx: CX,
pub dx: DX,
pub sp: Word,
pub bp: Word,
pub si: Word,
pub di: Word,
}
impl Register {
pub fn new() -> Self {
Self {
ax: AX::new(),
bx: BX::new(),
cx: CX::new(),
dx: DX::new(),
sp: 0,
bp: 0,
si: 0,
di: 0,
}
}
}
impl fmt::Display for Register {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"AX({}) BX({}) CX({}) DX({}) SP({:04x}) BP({:04x}) SI({:04x}) DI({:04x})",
self.ax, self.bx, self.cx, self.dx, self.sp, self.bp, self.si, self.di
)
}
}
macro_rules! gen_regs {
($ident:ident) => {
#[derive(Debug, Clone, Copy)]
pub struct $ident {
upper: Byte,
lower: Byte,
}
impl $ident {
pub fn new() -> Self {
Self { upper: 0, lower: 0 }
}
pub fn read(self) -> Word {
Word::from_le_bytes([self.lower, self.upper])
}
pub fn write(&mut self, word: Word) {
let [low, high]: [u8; 2] = word.to_le_bytes();
self.lower = low;
self.upper = high;
}
}
impl fmt::Display for $ident {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:04x}", Word::from_le_bytes([self.lower, self.upper]))
}
}
};
}
gen_regs!(AX);
gen_regs!(BX);
gen_regs!(CX);
gen_regs!(DX);