ft(interpreter): impl short jumps
This commit is contained in:
@@ -184,32 +184,34 @@ impl Disassembler {
|
|||||||
/// offset.
|
/// offset.
|
||||||
/// Returns the read byte added to the address of the subsequent instruction
|
/// Returns the read byte added to the address of the subsequent instruction
|
||||||
/// to act as a relative offset (Intel Jb operand).
|
/// to act as a relative offset (Intel Jb operand).
|
||||||
fn parse_j_byte(&mut self) -> Result<isize, DisasmError> {
|
/// The returned `usize` will be the subsequent instruction to jump to.
|
||||||
|
fn parse_j_byte(&mut self) -> Result<usize, DisasmError> {
|
||||||
log::debug!("Attempting to parse Jb at {:#04x} ...", self.offset);
|
log::debug!("Attempting to parse Jb at {:#04x} ...", self.offset);
|
||||||
// first interpret as 2-complement, then cast for addition
|
// first interpret as 2-complement, then cast for addition
|
||||||
let byte = self.parse_byte()? as IByte as isize;
|
let byte = self.parse_byte()? as IByte as isize;
|
||||||
let next_addr = (self.offset + 1) as isize;
|
let next_addr = (self.offset + 1) as isize;
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Parsed Jb consists of {byte:#04x} + {next_addr:#04x} = {:#04x}",
|
"Parsed Jb consists of {byte:#04x} + {next_addr:#04x} = {:#04x}",
|
||||||
byte + next_addr
|
(byte + next_addr) as usize
|
||||||
);
|
);
|
||||||
Ok(byte + next_addr)
|
Ok((byte + next_addr) as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a word of the binary, interpret it as signed and advance the
|
/// Parse a word of the binary, interpret it as signed and advance the
|
||||||
/// offset.
|
/// offset.
|
||||||
/// Returns the read word added to the address of the subsequent instruction
|
/// Returns the read word added to the address of the subsequent instruction
|
||||||
/// to act as a relative offset (Intel Jw/Jv operand).
|
/// to act as a relative offset (Intel Jw/Jv operand).
|
||||||
pub fn parse_j_word(&mut self) -> Result<isize, DisasmError> {
|
/// The returned `usize` will be the subsequent instruction to jump to.
|
||||||
|
pub fn parse_j_word(&mut self) -> Result<usize, DisasmError> {
|
||||||
log::debug!("Attempting to parse Jv at {:#04x} ...", self.offset);
|
log::debug!("Attempting to parse Jv at {:#04x} ...", self.offset);
|
||||||
// first interpret as 2-complement, then cast for addition
|
// first interpret as 2-complement, then cast for addition
|
||||||
let word = self.parse_word()? as IWord as isize;
|
let word = self.parse_word()? as IWord as isize;
|
||||||
let next_addr = (self.offset + 1) as isize;
|
let next_addr = (self.offset + 1) as isize;
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Parsed Jv consists of {word:#04x} + {next_addr:#04x} = {:#04x}",
|
"Parsed Jv consists of {word:#04x} + {next_addr:#04x} = {:#04x}",
|
||||||
word + next_addr
|
(word + next_addr) as usize
|
||||||
);
|
);
|
||||||
Ok(word + next_addr)
|
Ok((word + next_addr) as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a single pointer of the binary and advance the offset.
|
/// Parse a single pointer of the binary and advance the offset.
|
||||||
|
|||||||
@@ -136,27 +136,27 @@ pub enum Mnemonic {
|
|||||||
// DEC
|
// DEC
|
||||||
DEC_Reg(Register),
|
DEC_Reg(Register),
|
||||||
DEC_Mod(ModRmTarget),
|
DEC_Mod(ModRmTarget),
|
||||||
// Jumps
|
// Jumps conditional
|
||||||
JO(isize),
|
JO(usize),
|
||||||
JNO(isize),
|
JNO(usize),
|
||||||
JB(isize),
|
JB(usize),
|
||||||
JNB(isize),
|
JNB(usize),
|
||||||
JZ(isize),
|
JZ(usize),
|
||||||
JNZ(isize),
|
JNZ(usize),
|
||||||
JBE(isize),
|
JBE(usize),
|
||||||
JA(isize),
|
JA(usize),
|
||||||
JS(isize),
|
JS(usize),
|
||||||
JNS(isize),
|
JNS(usize),
|
||||||
JPE(isize),
|
JPE(usize),
|
||||||
JPO(isize),
|
JPO(usize),
|
||||||
JL(isize),
|
JL(usize),
|
||||||
JGE(isize),
|
JGE(usize),
|
||||||
JLE(isize),
|
JLE(usize),
|
||||||
JG(isize),
|
JG(usize),
|
||||||
LOOPNZ(isize),
|
LOOPNZ(usize),
|
||||||
LOOPZ(isize),
|
LOOPZ(usize),
|
||||||
LOOP(isize),
|
LOOP(usize),
|
||||||
JCXZ(isize),
|
JCXZ(usize),
|
||||||
|
|
||||||
// TEST
|
// TEST
|
||||||
TEST(ModRmTarget, Register),
|
TEST(ModRmTarget, Register),
|
||||||
@@ -203,13 +203,13 @@ pub enum Mnemonic {
|
|||||||
CWD,
|
CWD,
|
||||||
// CALL
|
// CALL
|
||||||
CALL_p(Pointer32),
|
CALL_p(Pointer32),
|
||||||
CALL_v(isize),
|
CALL_v(usize),
|
||||||
CALL_Mod(ModRmTarget),
|
CALL_Mod(ModRmTarget),
|
||||||
CALL_Mp(Pointer16),
|
CALL_Mp(Pointer16),
|
||||||
// JUMP
|
// JUMP
|
||||||
JMP_p(Pointer32),
|
JMP_p(Pointer32),
|
||||||
JMP_b(isize), // parses IByte, but stores as isize
|
JMP_b(usize), // parses IByte, but stores as isize
|
||||||
JMP_v(isize), // parwses IWord, but stores as isize
|
JMP_v(usize), // parwses IWord, but stores as isize
|
||||||
JMP_Mod(ModRmTarget),
|
JMP_Mod(ModRmTarget),
|
||||||
JMP_Mp(Pointer16),
|
JMP_Mp(Pointer16),
|
||||||
// WAIT
|
// WAIT
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ impl Computer {
|
|||||||
|
|
||||||
impl fmt::Display for Computer {
|
impl fmt::Display for Computer {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{} | {}", self.regs, self.flags)
|
write!(f, "{} {}", self.regs, self.flags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,16 +33,16 @@ impl fmt::Display for Flags {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"OF({}) DF({}) IF({}) TF({}) SF({}) ZF({}) NF({}) PF({}) CF({})",
|
"{}{}{}{}{}{}{}{}{}",
|
||||||
self.of as i32,
|
if self.of { "O" } else { "-" },
|
||||||
self.df as i32,
|
if self.df { "D" } else { "-" },
|
||||||
self.r#if as i32,
|
if self.r#if { "I" } else { "-" },
|
||||||
self.tf as i32,
|
if self.tf { "T" } else { "-" },
|
||||||
self.sf as i32,
|
if self.sf { "S" } else { "-" },
|
||||||
self.zf as i32,
|
if self.zf { "Z" } else { "-" },
|
||||||
self.nf as i32,
|
if self.nf { "N" } else { "-" },
|
||||||
self.pf as i32,
|
if self.pf { "P" } else { "-" },
|
||||||
self.cf as i32,
|
if self.cf { "C" } else { "-" },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use core::fmt;
|
use core::fmt;
|
||||||
use std::{fmt::Debug, process::exit};
|
use std::{fmt::Debug, process::exit, slice::Iter};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
instructions::{Instruction, Mnemonic},
|
instructions::{Instruction, Mnemonic},
|
||||||
@@ -12,10 +12,13 @@ use super::{
|
|||||||
interrupt::InterruptMessage,
|
interrupt::InterruptMessage,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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(u8),
|
||||||
|
InstructionNotFound(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for InterpreterError {
|
impl fmt::Display for InterpreterError {
|
||||||
@@ -25,6 +28,9 @@ impl fmt::Display for InterpreterError {
|
|||||||
InterpreterError::InvalidSyscall(id) => {
|
InterpreterError::InvalidSyscall(id) => {
|
||||||
write!(f, "The syscall with ID {} is unknown", 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> {
|
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!(
|
log::info!(
|
||||||
"IP({:04x})\t {:<30} | {}",
|
"{} IP({:04x})\t {:<32}",
|
||||||
instr.start,
|
self.computer,
|
||||||
instr.opcode.to_string(),
|
cur_instr.start,
|
||||||
self.computer
|
cur_instr.opcode.to_string(),
|
||||||
);
|
);
|
||||||
|
|
||||||
match instr.opcode {
|
match cur_instr.opcode {
|
||||||
/*
|
/*
|
||||||
* ADD
|
* 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
|
* Test
|
||||||
@@ -285,14 +359,6 @@ impl Interpreter {
|
|||||||
* Sign extensions
|
* Sign extensions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Call
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Jump
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait
|
* Wait
|
||||||
*/
|
*/
|
||||||
@@ -416,4 +482,30 @@ impl Interpreter {
|
|||||||
|
|
||||||
Ok(())
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,6 +95,15 @@ impl ImmediateOperand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Into<usize> for ImmediateOperand {
|
||||||
|
fn into(self) -> usize {
|
||||||
|
match self {
|
||||||
|
ImmediateOperand::Byte(b) => b as usize,
|
||||||
|
ImmediateOperand::Word(w) => w as usize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Add for ImmediateOperand {
|
impl Add for ImmediateOperand {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user