ft(interpreter): impl short jumps

This commit is contained in:
2025-06-11 15:44:42 +09:00
parent a4dc420d60
commit c9bf8fdc46
6 changed files with 160 additions and 57 deletions

View File

@@ -190,7 +190,7 @@ impl Computer {
impl fmt::Display for Computer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} | {}", self.regs, self.flags)
write!(f, "{} {}", self.regs, self.flags)
}
}

View File

@@ -33,16 +33,16 @@ 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,
"{}{}{}{}{}{}{}{}{}",
if self.of { "O" } else { "-" },
if self.df { "D" } else { "-" },
if self.r#if { "I" } else { "-" },
if self.tf { "T" } else { "-" },
if self.sf { "S" } else { "-" },
if self.zf { "Z" } else { "-" },
if self.nf { "N" } else { "-" },
if self.pf { "P" } else { "-" },
if self.cf { "C" } else { "-" },
)
}
}

View File

@@ -1,5 +1,5 @@
use core::fmt;
use std::{fmt::Debug, process::exit};
use std::{fmt::Debug, process::exit, slice::Iter};
use crate::{
instructions::{Instruction, Mnemonic},
@@ -12,10 +12,13 @@ use super::{
interrupt::InterruptMessage,
};
type InstructionPointer<'a> = std::slice::Iter<'a, Instruction>;
#[derive(Debug, Clone)]
pub enum InterpreterError {
EndOfData,
InvalidSyscall(u8),
InstructionNotFound(usize),
}
impl fmt::Display for InterpreterError {
@@ -25,6 +28,9 @@ impl fmt::Display for InterpreterError {
InterpreterError::InvalidSyscall(id) => {
write!(f, "The syscall with ID {} is unknown", id)
}
InterpreterError::InstructionNotFound(addr) => {
write!(f, "IP({addr}) points at invalid instruction")
}
}
}
}
@@ -46,15 +52,18 @@ impl Interpreter {
}
pub fn interpret(&mut self) -> Result<(), InterpreterError> {
for instr in self.instructions.iter() {
let mut ip = Self::find_instruction(&self.instructions, 0)
.ok_or(InterpreterError::InstructionNotFound(0))?;
while let Some(cur_instr) = ip.next() {
log::info!(
"IP({:04x})\t {:<30} | {}",
instr.start,
instr.opcode.to_string(),
self.computer
"{} IP({:04x})\t {:<32}",
self.computer,
cur_instr.start,
cur_instr.opcode.to_string(),
);
match instr.opcode {
match cur_instr.opcode {
/*
* ADD
*/
@@ -261,8 +270,73 @@ impl Interpreter {
},
/*
* Jumps
* Conditional short jumps
*/
Mnemonic::JO(offset)
| Mnemonic::JNO(offset)
| Mnemonic::JB(offset)
| Mnemonic::JNB(offset)
| Mnemonic::JZ(offset)
| Mnemonic::JNZ(offset)
| Mnemonic::JBE(offset)
| Mnemonic::JA(offset)
| Mnemonic::JS(offset)
| Mnemonic::JNS(offset)
| Mnemonic::JPE(offset)
| Mnemonic::JPO(offset)
| Mnemonic::JL(offset)
| Mnemonic::JGE(offset)
| Mnemonic::JLE(offset)
| Mnemonic::JG(offset)
| Mnemonic::JMP_b(offset)
| Mnemonic::JMP_v(offset) => {
let flags = self.computer.flags.clone();
let flag = match cur_instr.opcode {
Mnemonic::JO(_) => flags.of,
Mnemonic::JNO(_) => !flags.of,
Mnemonic::JB(_) => flags.cf,
Mnemonic::JNB(_) => !flags.cf,
Mnemonic::JZ(_) => flags.zf,
Mnemonic::JNZ(_) => !flags.zf,
Mnemonic::JBE(_) => flags.cf || flags.zf,
Mnemonic::JA(_) => !flags.cf && !flags.zf,
Mnemonic::JS(_) => flags.sf,
Mnemonic::JNS(_) => !flags.sf,
Mnemonic::JPE(_) => flags.pf,
Mnemonic::JPO(_) => !flags.pf,
Mnemonic::JL(_) => flags.sf != flags.of,
Mnemonic::JLE(_) => flags.zf || (flags.sf != flags.of),
Mnemonic::JGE(_) => flags.sf == flags.of,
Mnemonic::JG(_) => !flags.zf || (flags.sf == flags.of),
Mnemonic::JMP_b(_) | Mnemonic::JMP_v(_) => true,
_ => panic!("unreachable"),
};
if flag {
Self::ip_jump(&self.instructions, &mut ip, offset);
}
}
/*
* Long jumps and calls
*/
Mnemonic::JMP_p(ptr) => {
todo!()
}
Mnemonic::JMP_Mp(ptr) => {
todo!()
}
Mnemonic::JMP_Mod(target) => match target {
ModRmTarget::Memory(idx) => Self::ip_jump(
&self.instructions,
&mut ip,
self.computer.memory.read(&self.computer.regs, idx).into(),
),
ModRmTarget::Register(register) => Self::ip_jump(
&self.instructions,
&mut ip,
self.computer.regs.read(register).into(),
),
},
/*
* Test
@@ -285,14 +359,6 @@ impl Interpreter {
* Sign extensions
*/
/*
* Call
*/
/*
* Jump
*/
/*
* Wait
*/
@@ -416,4 +482,30 @@ impl Interpreter {
Ok(())
}
/// Find the starting addr of an instruction in the list of all parsed
/// instructions and return the iterator to that matching instruction, to
/// allow for further traversal from that point on.
/// I bet, that this is not really fast, but I could'nt come up with a
/// better idea so far.
fn find_instruction<'a>(
items: &'a Vec<Instruction>,
addr: usize,
) -> Option<InstructionPointer> {
items
.iter()
.position(|i| i.start == addr)
.map(|index| items[index..].iter())
}
/// Jump [`InstructionPointer`] `ip` to an `offset`.
fn ip_jump<'a>(
instructions: &'a Vec<Instruction>,
ip: &mut InstructionPointer<'a>,
offset: usize,
) {
if let Some(next_instr) = Self::find_instruction(&instructions, offset) {
*ip = next_instr;
}
}
}