diff --git a/src/aout.rs b/src/aout.rs index 9959e9a..9642564 100644 --- a/src/aout.rs +++ b/src/aout.rs @@ -3,7 +3,7 @@ use core::fmt; use std::ffi::{c_uchar, c_ushort}; -use crate::operands::{Byte, Word}; +use crate::operands::Byte; #[allow(non_camel_case_types)] pub type c_long = i32; // we use a a.out with 32 byte diff --git a/src/instructions.rs b/src/instructions.rs index 8b59c5d..686483e 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -45,7 +45,7 @@ impl fmt::Display for Instruction { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Copy)] #[allow(non_camel_case_types)] /// All possible mnemonic variantions. /// These are sorted by type and are not in hex-encoding order. diff --git a/src/interpreter/computer.rs b/src/interpreter/computer.rs index 4cd2d9a..a04609c 100644 --- a/src/interpreter/computer.rs +++ b/src/interpreter/computer.rs @@ -1,14 +1,21 @@ use core::fmt; -use crate::operands::Byte; +use crate::operands::{ModRmTarget, Operand}; -use super::{flags::Flags, register::Register}; +use super::{flags::Flags, memory::Memory, register::Register}; + +/// Wrapper for easier argument passing of arithmetic operations. +#[derive(Debug, Clone)] +pub enum Argument { + Operand(crate::operands::Operand), + ModRmTarget(ModRmTarget), +} #[derive(Debug, Clone)] pub struct Computer { pub regs: Register, pub flags: Flags, - pub memory: [Byte; 65536], + pub memory: Memory, } impl Computer { @@ -16,7 +23,79 @@ impl Computer { Self { regs: Register::new(), flags: Flags::new(), - memory: [0; 65536], + memory: Memory::new(), + } + } + + /// Adds two [`Argument`]s, saves it to `dest` and sets flags, if necessary. + /// A value can never be saved to an immediate Operand, so `dest` can only + /// be a [`ModRmTarget`]. + pub fn add(&mut self, dest: ModRmTarget, src: Argument) { + match src { + Argument::ModRmTarget(src_target) => self.add_modrm(dest, src_target), + Argument::Operand(src_operand) => self.add_imm(dest, src_operand), + } + } + + /// Adds two [`ModRmTarget`]s togeher, saves it to `dest` and sets flags, if necessary. + fn add_modrm(&mut self, dest: ModRmTarget, src: ModRmTarget) { + match dest { + ModRmTarget::Memory(dest_memory_idx) => match src { + // mem, mem + ModRmTarget::Memory(_) => panic!("Cannot add Memory to Memory!"), + // mem, reg + ModRmTarget::Register(src_register) => { + let lhs = self.memory.read_from_memidx(&self.regs, dest_memory_idx); + let rhs = self.regs.read(src_register); + let result = lhs + rhs; + self.memory + .write_from_memidx(&self.regs, dest_memory_idx, result); + // unsigned overflow + self.flags.of = result < rhs; + } + }, + ModRmTarget::Register(dest_register) => match src { + // reg, mem + ModRmTarget::Memory(src_memory_index) => { + let lhs = self.regs.read(dest_register); + let rhs = self.memory.read_from_memidx(&self.regs, src_memory_index); + let result = lhs + rhs; + self.regs.write(dest_register, result); + // unsigned overflow + self.flags.of = result < rhs; + } + // reg, reg + ModRmTarget::Register(src_register) => { + let lhs = self.regs.read(dest_register); + let rhs = self.regs.read(src_register); + let result = lhs + rhs; + self.regs.write(dest_register, result); + + // unsigned overflow + self.flags.of = result < rhs + } + }, + } + } + + /// Adds an immediate [`Operand`] to a location pointed to by a + /// [`ModRmTarget`], saves it to dest and sets flags, if necessary. + fn add_imm(&mut self, dest: ModRmTarget, src: Operand) { + match dest { + ModRmTarget::Memory(dest_mem) => { + let lhs = self.memory.read_from_memidx(&self.regs, dest_mem); + let result = lhs + src; + // unsigned overflow + self.flags.of = result < src; + self.memory.write_from_memidx(&self.regs, dest_mem, result); + } + ModRmTarget::Register(dest_reg) => { + let lhs = self.regs.read(dest_reg); + let result = lhs + src; + // unsigned overflow + self.flags.of = result < src; + self.regs.write(dest_reg, result); + } } } } diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index 62ca3c4..fc941a0 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -3,10 +3,10 @@ use std::{fmt::Debug, process::exit}; use crate::{ instructions::{Instruction, Mnemonic}, - operands::{Byte, Word}, + operands::{Byte, ModRmTarget, Operand, Word}, }; -use super::computer::Computer; +use super::computer::{Argument, Computer}; #[derive(Debug, Clone)] pub enum InterpreterError { @@ -44,16 +44,43 @@ impl Interpreter { pub fn interpret(&mut self) -> Result<(), InterpreterError> { for instr in self.instructions.iter() { log::info!( - "IP({:04x})\t {:<15} | {}", + "IP({:04x})\t {:<30} | {}", instr.start, instr.opcode.to_string(), self.computer ); match instr.opcode { + /* + * ADD + */ + Mnemonic::ADD_FromReg(dest, src) => self + .computer + .add(dest, Argument::ModRmTarget(ModRmTarget::Register(src))), + Mnemonic::ADD_ToReg(src, dest) => self + .computer + .add(ModRmTarget::Register(dest), Argument::ModRmTarget(src)), + Mnemonic::ADD_Ib(dest, src) => self + .computer + .add(dest, Argument::Operand(Operand::Byte(src))), + Mnemonic::ADD_Iv(dest, src) => self + .computer + .add(dest, Argument::Operand(Operand::Word(src))), + Mnemonic::ADD_ALIb(src_byte) => self.computer.add( + ModRmTarget::Register(crate::register::Register::AL), + Argument::Operand(Operand::Byte(src_byte)), + ), + Mnemonic::ADD_AXIv(src_word) => self.computer.add( + ModRmTarget::Register(crate::register::Register::AX), + Argument::Operand(Operand::Word(src_word)), + ), + + /* + * MOV + */ Mnemonic::MOV_BXIv(word) => self.computer.regs.bx.write(word), Mnemonic::INT(id) => self.handle_int(id)?, - _ => todo!(), + _ => log::info!("no action done"), } } @@ -127,3 +154,18 @@ impl InterruptData { } } } + +impl fmt::Display for InterruptData { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "Interrupt({}, {}, {}, {}, {}, {})", + self.m_type, + self.interrupt_id, + self.proc_nr, + self.count, + self.position, + self.data_position + ) + } +} diff --git a/src/interpreter/memory.rs b/src/interpreter/memory.rs new file mode 100644 index 0000000..0b990c6 --- /dev/null +++ b/src/interpreter/memory.rs @@ -0,0 +1,83 @@ +use crate::operands::{Byte, Displacement, MemoryIndex, Operand, Word}; + +#[derive(Debug, Clone, Copy)] +pub struct Memory { + memory: [Byte; 65536], +} + +impl Memory { + pub fn new() -> Self { + Self { memory: [0; 65536] } + } + + // Write an [`Operand`] to a memory location indexed by a [`MemoryIndex`]. + pub fn write( + &mut self, + regs: &crate::interpreter::register::Register, + idx: MemoryIndex, + val: Operand, + ) { + match Memory::calc_memidx(regs, idx) { + Operand::Byte(idx_byte) => match val { + Operand::Byte(value) => { + log::debug!("Writing byte {value:#04x} to memory location {idx_byte:#04x}"); + self.memory[idx_byte as usize] = value + } + Operand::Word(_) => panic!("Cannot add Word to Byte Memory Index"), + }, + Operand::Word(idx_word) => match val { + Operand::Word(value) => { + let byte1 = idx_word / 2; + let byte2 = idx_word / 2 + 1; + let [low, high]: [u8; 2] = value.to_le_bytes(); + log::debug!( + "Writing bytes {low:#04x} and {high:#04x} to memory location {byte1:#04x} and {byte2:#04x}" + ); + self.memory[byte1 as usize] = low; + self.memory[byte1 as usize] = high; + } + Operand::Byte(value) => { + self.memory[(idx_word * 2) as usize] = value; + } + }, + } + } + + /// Read into memory with a [`MemoryIndex`] as index. + pub fn read(&self, regs: &crate::interpreter::register::Register, idx: MemoryIndex) -> Operand { + match Memory::calc_memidx(regs, idx) { + Operand::Byte(byte) => { + log::debug!("Reading byte {byte:#04x} from memory"); + Operand::Byte(self.memory[byte as usize]) + } + Operand::Word(word) => { + let byte1 = word / 2; + let byte2 = word / 2 + 1; + log::debug!("Reading bytes {byte1:#04x} and {byte2:#04x} from memory"); + Operand::Word(Word::from_le_bytes([ + self.memory[byte1 as usize], + self.memory[byte2 as usize], + ])) + } + } + } + + /// Calculate the absolute Memory Index from a [`MemoryIndex`] struct. + fn calc_memidx(regs: &crate::interpreter::register::Register, idx: MemoryIndex) -> Operand { + let mut base = Operand::Word(0); + let mut index = Operand::Word(0); + let mut disp = Displacement::IWord(0); + + if let Some(base_reg) = idx.base { + base = regs.read(base_reg); + }; + if let Some(index_reg) = idx.index { + index = regs.read(index_reg); + }; + if let Some(displacement) = idx.displacement { + disp = displacement; + } + + base + index + disp + } +} diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index ae194ac..9dd6495 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -1,4 +1,5 @@ mod computer; mod flags; pub mod interpreter; +mod memory; mod register; diff --git a/src/interpreter/register.rs b/src/interpreter/register.rs index e6c455c..e91a22f 100644 --- a/src/interpreter/register.rs +++ b/src/interpreter/register.rs @@ -1,6 +1,8 @@ -use crate::operands::{Byte, Word}; +use crate::operands::{Byte, Operand, Word}; use core::fmt; +use super::flags::Flags; + #[derive(Debug, Clone, Copy)] pub struct Register { pub ax: AX, @@ -26,6 +28,73 @@ impl Register { di: 0, } } + + /// Read value from a [`crate::register::Register`]. + pub fn read(&self, reg: crate::register::Register) -> Operand { + match reg { + crate::register::Register::AX => Operand::Word(self.ax.read()), + crate::register::Register::BX => Operand::Word(self.bx.read()), + crate::register::Register::CX => Operand::Word(self.cx.read()), + crate::register::Register::DX => Operand::Word(self.dx.read()), + crate::register::Register::AH => Operand::Byte(self.ax.upper), + crate::register::Register::AL => Operand::Byte(self.ax.lower), + crate::register::Register::BH => Operand::Byte(self.bx.upper), + crate::register::Register::BL => Operand::Byte(self.bx.lower), + crate::register::Register::CH => Operand::Byte(self.cx.upper), + crate::register::Register::CL => Operand::Byte(self.cx.lower), + crate::register::Register::DH => Operand::Byte(self.dx.upper), + crate::register::Register::DL => Operand::Byte(self.dx.lower), + crate::register::Register::DI => Operand::Word(self.di), + crate::register::Register::SI => Operand::Word(self.si), + crate::register::Register::BP => Operand::Word(self.bp), + crate::register::Register::SP => Operand::Word(self.sp), + } + } + + /// Write an [`Operand`] to a [`crate::register::Register`]. + pub fn write(&mut self, reg: crate::register::Register, op: Operand) { + match op { + Operand::Byte(byte) => match reg { + crate::register::Register::AX => self.ax.lower = byte, + crate::register::Register::BX => self.bx.lower = byte, + crate::register::Register::CX => self.cx.lower = byte, + crate::register::Register::DX => self.dx.lower = byte, + crate::register::Register::AH => self.ax.upper = byte, + crate::register::Register::AL => self.ax.lower = byte, + crate::register::Register::BH => self.bx.upper = byte, + crate::register::Register::BL => self.bx.lower = byte, + crate::register::Register::CH => self.cx.upper = byte, + crate::register::Register::CL => self.cx.lower = byte, + crate::register::Register::DH => self.dx.upper = byte, + crate::register::Register::DL => self.dx.lower = byte, + crate::register::Register::DI => self.di = Word::from_le_bytes([0x0, byte]), + crate::register::Register::SI => self.si = Word::from_le_bytes([0x0, byte]), + crate::register::Register::BP => self.bp = Word::from_le_bytes([0x0, byte]), + crate::register::Register::SP => self.sp = Word::from_le_bytes([0x0, byte]), + }, + Operand::Word(word) => { + match reg { + crate::register::Register::AX => self.ax.write(word), + crate::register::Register::BX => self.bx.write(word), + crate::register::Register::CX => self.cx.write(word), + crate::register::Register::DX => self.dx.write(word), + // crate::register::Register::AH => {} + // crate::register::Register::AL => {} + // crate::register::Register::BL => {} + // crate::register::Register::BH => {} + // crate::register::Register::CH => {} + // crate::register::Register::CL => {} + // crate::register::Register::DH => {} + // crate::register::Register::DL => {} + crate::register::Register::DI => self.di = word, + crate::register::Register::SI => self.si = word, + crate::register::Register::BP => self.bp = word, + crate::register::Register::SP => self.sp = word, + _ => panic!("Tried writing Word to Byte-sized register"), + } + } + } + } } impl fmt::Display for Register { diff --git a/src/operands.rs b/src/operands.rs index da22a72..9654d90 100644 --- a/src/operands.rs +++ b/src/operands.rs @@ -7,6 +7,7 @@ use crate::register::SegmentRegister; use crate::{disasm::DisasmError, register::Register}; use core::fmt; +use std::ops::{Add, Sub}; pub type Byte = u8; // b pub type IByte = i8; // used for displacements of memory access @@ -14,7 +15,7 @@ pub type Word = u16; // w or v pub type IWord = i16; // used for displacement of memory access pub type DWord = u32; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Ord, Eq, PartialEq, PartialOrd, Copy)] /// Encodes either Byte- or Word-sized operands. /// Also sometimes used to decide if an instruction is Byte- or Word-sized, /// which is usually indicated by using a value of 0 and the disregarding @@ -24,6 +25,64 @@ pub enum Operand { Word(Word), } +impl Add for Operand { + type Output = Self; + + fn add(self, other: Self) -> Self { + match self { + Operand::Byte(lhsb) => match other { + Operand::Byte(rhsb) => Operand::Byte(lhsb.wrapping_add(rhsb)), + _ => panic!("Cannot add Word to Byte"), + }, + Operand::Word(lhsw) => match other { + Operand::Word(rhsw) => Operand::Word(lhsw.wrapping_add(rhsw)), + Operand::Byte(rhsb) => Operand::Word(lhsw.wrapping_add(rhsb as Word)), + }, + } + } +} + +impl Add for Operand { + type Output = Operand; + + fn add(self, disp: Displacement) -> Self::Output { + // XXX: ugly hack to add Operand with Displacement + match disp { + Displacement::IByte(byte) => { + if byte < 0 { + return self - Operand::Byte((byte * -1) as Byte); + } else { + return self + Operand::Byte(byte as Byte); + } + } + Displacement::IWord(word) => { + if word < 0 { + return self - Operand::Word((word * -1) as Word); + } else { + return self + Operand::Word(word as Word); + } + } + } + } +} + +impl Sub for Operand { + type Output = Self; + + fn sub(self, other: Self) -> Self { + match self { + Operand::Byte(lhsb) => match other { + Operand::Byte(rhsb) => Operand::Byte(lhsb.wrapping_sub(rhsb)), + _ => panic!("Cannot substract Word from Byte"), + }, + Operand::Word(lhsw) => match other { + Operand::Word(rhsw) => Operand::Word(lhsw.wrapping_sub(rhsw)), + Operand::Byte(rhsb) => Operand::Word(lhsw.wrapping_sub(rhsb as Word)), + }, + } + } +} + impl fmt::Display for Operand { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -42,7 +101,7 @@ impl fmt::LowerHex for Operand { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Copy)] /// ModRM byte can either target a [`MemoryIndex`] (location in memory) or some /// [`Register`]. pub enum ModRmTarget { @@ -59,7 +118,7 @@ impl std::fmt::Display for ModRmTarget { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Copy)] /// Memory displacements are signed versions of Byte and Word operands. /// Encodes either Byte- or Word-sized operands. /// Generally, a [`Displacement`] is the result of a ModRM byte parse and @@ -105,7 +164,7 @@ impl std::fmt::Display for Displacement { /// A memory index operand is usually created by ModRM bytes or words. /// e.g. [bx+si] -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Copy)] pub struct MemoryIndex { pub base: Option, pub index: Option, @@ -141,7 +200,7 @@ impl fmt::Display for MemoryIndex { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Copy)] /// 16-bit pointer for access, usually with a [`SegmentRegister`] as segment /// and [`Pointer16`] as offset. /// Generally, this type only gets constructed in rare scenarios, when the @@ -185,7 +244,7 @@ impl TryFrom for Pointer16 { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Copy)] /// 32-bit segment:offset pointer for long jumps. /// Both [`Word`]s are immediately encoded after the instruction pub struct Pointer32 { diff --git a/src/register.rs b/src/register.rs index 8af5586..d730bfd 100644 --- a/src/register.rs +++ b/src/register.rs @@ -3,7 +3,7 @@ use crate::{disasm::DisasmError, operands::Operand}; use core::fmt; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Copy)] /// Registers of a 8086 processor pub enum Register { // 8 bit @@ -86,7 +86,7 @@ impl fmt::Display for Register { } /// Segment Registers of a 8086 processor -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Copy)] pub enum SegmentRegister { DS, ES,