From 911d6e844bd2198abd17abe2f5aea14cb7658ff3 Mon Sep 17 00:00:00 2001 From: AsyaTheAbove Date: Wed, 27 Sep 2023 18:17:16 +0300 Subject: [PATCH] Implement a basic IO bus Implemented in this patch is also more jumps, loop instructions, and the `out` instruction. With this patch, the 5150 BIOS can now checksum itself. Signed-off-by: AsyaTheAbove --- src/io.rs | 73 +++++++++++ src/lib.rs | 1 + src/main.rs | 4 +- src/processor/instruction.rs | 248 ++++++++++++++++++++--------------- src/processor/mod.rs | 146 ++++++++++++++++----- 5 files changed, 328 insertions(+), 144 deletions(-) create mode 100644 src/io.rs diff --git a/src/io.rs b/src/io.rs new file mode 100644 index 0000000..6cb13b6 --- /dev/null +++ b/src/io.rs @@ -0,0 +1,73 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +use hashbrown::HashMap; + +#[derive(Default)] +pub struct IoBus { + handlers: HashMap, +} + +impl IoBus { + pub fn read(&mut self, address: u16) -> [u8; N] { + let mut buffer = [0; N]; + for i in 0..N { + buffer[i] = unsafe { (*self.handler(address + i as u16)).read(address + i as u16) }; + } + buffer + } + + pub fn write(&mut self, address: u16, value: [u8; N]) { + for i in 0..N { + unsafe { + (*self.handler(address + i as u16)).write(address + i as u16, value[i]); + } + } + } + + pub fn read_u8(&mut self, address: u16) -> u8 { + self.read::<1>(address)[0] + } + + pub fn write_u8(&mut self, address: u16, value: u8) { + self.write::<1>(address, [value]); + } + + pub fn read_u16(&mut self, address: u16) -> u16 { + u16::from_le_bytes(self.read::<2>(address)) + } + + pub fn write_u16(&mut self, address: u16, value: u16) { + self.write::<2>(address, value.to_le_bytes()); + } + + pub fn handler(&self, address: u16) -> *mut dyn IoHandler { + static mut DEFAULT_IO_HANDLER: DefaultIoHandler = DefaultIoHandler; + self.handlers.get(&address) + .cloned() + .unwrap_or(unsafe { &mut DEFAULT_IO_HANDLER }) + } + + pub fn set_handler(&mut self, address: u16, size: u16, handler: *mut dyn IoHandler) { + for i in address..address + size { + self.handlers.insert(address + i, handler); + } + } +} + +struct DefaultIoHandler; +impl IoHandler for DefaultIoHandler {} + +pub trait IoHandler { + fn read(&mut self, address: u16) -> u8 { + u8::MAX + } + + #[allow(unused_variables)] + fn write(&mut self, address: u16, value: u8) { + // ignored + } +} diff --git a/src/lib.rs b/src/lib.rs index 05972f5..e14bf3c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ #![feature(bigint_helper_methods)] +pub mod io; pub mod machine; pub mod memory; pub mod processor; diff --git a/src/main.rs b/src/main.rs index b57af0f..ec0c8a2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ use copycat::memory::{Memory, KiB}; use copycat::processor::{Instruction, Processor}; +use copycat::io::IoBus; static BIOS_ROM: &[u8; 8 * KiB as usize] = include_bytes!("../roms/BIOS_IBM5150_24APR81_5700051_U33.BIN"); @@ -14,13 +15,14 @@ fn main() { mem.add_tlb_entry(0xfe, BIOS_ROM.as_ptr().cast_mut().cast()); mem.add_tlb_entry(0xff, unsafe { BIOS_ROM.as_ptr().add(4 * KiB as usize) }.cast_mut().cast()); // mem.write(0xffff0, [0x90, 0x04, 0x69, 0xF4]); + let mut io = IoBus::default(); let mut cpu = Processor::default(); cpu.registers.dump(); while !cpu.halted { let instr = Instruction::decode(&mem, &mut cpu.registers); println!("{instr:?}"); - cpu.exec(&mut mem, &instr); + cpu.exec(&mut mem, &mut io, &instr); cpu.registers.dump(); } } diff --git a/src/processor/instruction.rs b/src/processor/instruction.rs index d0d4066..3ff0387 100644 --- a/src/processor/instruction.rs +++ b/src/processor/instruction.rs @@ -22,6 +22,9 @@ pub struct Instruction { impl Instruction { pub fn decode(memory: &Memory, registers: &mut Registers) -> Instruction { + use Mnemonic::*; + use OperandFormat::*; + let address = ((registers.cs() as u64) << 4) + registers.ip() as u64; let mut opcode = memory.read_u8(address); let mut size: u8 = 1; @@ -43,126 +46,153 @@ impl Instruction { } let (mnemonic, op1ty, op2ty) = match opcode { - 0x00 => (Mnemonic::Add, OperandFormat::RM8, OperandFormat::Reg8), - 0x01 => (Mnemonic::Add, OperandFormat::RM16, OperandFormat::Reg16), - 0x02 => (Mnemonic::Add, OperandFormat::Reg8, OperandFormat::RM8), - 0x03 => (Mnemonic::Add, OperandFormat::Reg16, OperandFormat::RM16), - 0x04 => (Mnemonic::Add, OperandFormat::AL, OperandFormat::Imm8), - 0x05 => (Mnemonic::Add, OperandFormat::AX, OperandFormat::Imm16), - 0x08 => (Mnemonic::Or, OperandFormat::RM8, OperandFormat::Reg8), - 0x09 => (Mnemonic::Or, OperandFormat::RM16, OperandFormat::Reg16), - 0x0A => (Mnemonic::Or, OperandFormat::Reg8, OperandFormat::RM8), - 0x0B => (Mnemonic::Or, OperandFormat::Reg16, OperandFormat::RM16), - 0x0C => (Mnemonic::Or, OperandFormat::AL, OperandFormat::Imm8), - 0x0D => (Mnemonic::Or, OperandFormat::AX, OperandFormat::Imm16), - 0x10 => (Mnemonic::Adc, OperandFormat::RM8, OperandFormat::Reg8), - 0x11 => (Mnemonic::Adc, OperandFormat::RM16, OperandFormat::Reg16), - 0x12 => (Mnemonic::Adc, OperandFormat::Reg8, OperandFormat::RM8), - 0x13 => (Mnemonic::Adc, OperandFormat::Reg16, OperandFormat::RM16), - 0x14 => (Mnemonic::Adc, OperandFormat::AL, OperandFormat::Imm8), - 0x15 => (Mnemonic::Adc, OperandFormat::AX, OperandFormat::Imm16), - 0x18 => (Mnemonic::Sbb, OperandFormat::RM8, OperandFormat::Reg8), - 0x19 => (Mnemonic::Sbb, OperandFormat::RM16, OperandFormat::Reg16), - 0x1A => (Mnemonic::Sbb, OperandFormat::Reg8, OperandFormat::RM8), - 0x1B => (Mnemonic::Sbb, OperandFormat::Reg16, OperandFormat::RM16), - 0x1C => (Mnemonic::Sbb, OperandFormat::AL, OperandFormat::Imm8), - 0x1D => (Mnemonic::Sbb, OperandFormat::AX, OperandFormat::Imm16), - 0x28 => (Mnemonic::Sub, OperandFormat::RM8, OperandFormat::Reg8), - 0x29 => (Mnemonic::Sub, OperandFormat::RM16, OperandFormat::Reg16), - 0x2A => (Mnemonic::Sub, OperandFormat::Reg8, OperandFormat::RM8), - 0x2B => (Mnemonic::Sub, OperandFormat::Reg16, OperandFormat::RM16), - 0x2C => (Mnemonic::Sub, OperandFormat::AL, OperandFormat::Imm8), - 0x2D => (Mnemonic::Sub, OperandFormat::AX, OperandFormat::Imm16), - 0x30 => (Mnemonic::Xor, OperandFormat::RM8, OperandFormat::Reg8), - 0x31 => (Mnemonic::Xor, OperandFormat::RM16, OperandFormat::Reg16), - 0x32 => (Mnemonic::Xor, OperandFormat::Reg8, OperandFormat::RM8), - 0x33 => (Mnemonic::Xor, OperandFormat::Reg16, OperandFormat::RM16), - 0x34 => (Mnemonic::Xor, OperandFormat::AL, OperandFormat::Imm8), - 0x35 => (Mnemonic::Xor, OperandFormat::AX, OperandFormat::Imm16), - 0x40 => (Mnemonic::Inc, OperandFormat::AX, OperandFormat::NoOperand), - 0x41 => (Mnemonic::Inc, OperandFormat::CX, OperandFormat::NoOperand), - 0x42 => (Mnemonic::Inc, OperandFormat::DX, OperandFormat::NoOperand), - 0x43 => (Mnemonic::Inc, OperandFormat::BX, OperandFormat::NoOperand), - 0x44 => (Mnemonic::Inc, OperandFormat::SP, OperandFormat::NoOperand), - 0x45 => (Mnemonic::Inc, OperandFormat::BP, OperandFormat::NoOperand), - 0x46 => (Mnemonic::Inc, OperandFormat::SI, OperandFormat::NoOperand), - 0x47 => (Mnemonic::Inc, OperandFormat::DI, OperandFormat::NoOperand), - 0x48 => (Mnemonic::Dec, OperandFormat::AX, OperandFormat::NoOperand), - 0x49 => (Mnemonic::Dec, OperandFormat::CX, OperandFormat::NoOperand), - 0x4A => (Mnemonic::Dec, OperandFormat::DX, OperandFormat::NoOperand), - 0x4B => (Mnemonic::Dec, OperandFormat::BX, OperandFormat::NoOperand), - 0x4C => (Mnemonic::Dec, OperandFormat::SP, OperandFormat::NoOperand), - 0x4D => (Mnemonic::Dec, OperandFormat::BP, OperandFormat::NoOperand), - 0x4E => (Mnemonic::Dec, OperandFormat::SI, OperandFormat::NoOperand), - 0x4F => (Mnemonic::Dec, OperandFormat::DI, OperandFormat::NoOperand), - 0x70 => (Mnemonic::Jo, OperandFormat::Imm8, OperandFormat::NoOperand), - 0x71 => (Mnemonic::Jno, OperandFormat::Imm8, OperandFormat::NoOperand), - 0x72 => (Mnemonic::Jc, OperandFormat::Imm8, OperandFormat::NoOperand), - 0x73 => (Mnemonic::Jnc, OperandFormat::Imm8, OperandFormat::NoOperand), - 0x74 => (Mnemonic::Jz, OperandFormat::Imm8, OperandFormat::NoOperand), - 0x75 => (Mnemonic::Jnz, OperandFormat::Imm8, OperandFormat::NoOperand), - 0x76 => (Mnemonic::Jna, OperandFormat::Imm8, OperandFormat::NoOperand), - 0x77 => (Mnemonic::Ja, OperandFormat::Imm8, OperandFormat::NoOperand), - 0x78 => (Mnemonic::Js, OperandFormat::Imm8, OperandFormat::NoOperand), - 0x79 => (Mnemonic::Jns, OperandFormat::Imm8, OperandFormat::NoOperand), - 0x7A => (Mnemonic::Jp, OperandFormat::Imm8, OperandFormat::NoOperand), - 0x7B => (Mnemonic::Jnp, OperandFormat::Imm8, OperandFormat::NoOperand), - 0x7C => (Mnemonic::Jl, OperandFormat::Imm8, OperandFormat::NoOperand), - 0x7D => (Mnemonic::Jnl, OperandFormat::Imm8, OperandFormat::NoOperand), - 0x7E => (Mnemonic::Jng, OperandFormat::Imm8, OperandFormat::NoOperand), - 0x7F => (Mnemonic::Jg, OperandFormat::Imm8, OperandFormat::NoOperand), - 0x88 => (Mnemonic::Mov, OperandFormat::RM8, OperandFormat::Reg8), - 0x89 => (Mnemonic::Mov, OperandFormat::RM16, OperandFormat::Reg16), - 0x8A => (Mnemonic::Mov, OperandFormat::Reg8, OperandFormat::RM8), - 0x8B => (Mnemonic::Mov, OperandFormat::Reg16, OperandFormat::RM16), - 0x8C => (Mnemonic::Mov, OperandFormat::RM16, OperandFormat::Sreg), - 0x8E => (Mnemonic::Mov, OperandFormat::Sreg, OperandFormat::RM16), - 0x90 => (Mnemonic::Nop, OperandFormat::NoOperand, OperandFormat::NoOperand), - 0x9E => (Mnemonic::Sahf, OperandFormat::NoOperand, OperandFormat::NoOperand), - 0x9F => (Mnemonic::Lahf, OperandFormat::NoOperand, OperandFormat::NoOperand), - 0xB0 => (Mnemonic::Mov, OperandFormat::AL, OperandFormat::Imm8), - 0xB1 => (Mnemonic::Mov, OperandFormat::CL, OperandFormat::Imm8), - 0xB2 => (Mnemonic::Mov, OperandFormat::DL, OperandFormat::Imm8), - 0xB3 => (Mnemonic::Mov, OperandFormat::BL, OperandFormat::Imm8), - 0xB4 => (Mnemonic::Mov, OperandFormat::AH, OperandFormat::Imm8), - 0xB5 => (Mnemonic::Mov, OperandFormat::CH, OperandFormat::Imm8), - 0xB6 => (Mnemonic::Mov, OperandFormat::DH, OperandFormat::Imm8), - 0xB7 => (Mnemonic::Mov, OperandFormat::BH, OperandFormat::Imm8), - 0xB8 => (Mnemonic::Mov, OperandFormat::AX, OperandFormat::Imm16), - 0xB9 => (Mnemonic::Mov, OperandFormat::CX, OperandFormat::Imm16), - 0xBA => (Mnemonic::Mov, OperandFormat::DX, OperandFormat::Imm16), - 0xBB => (Mnemonic::Mov, OperandFormat::BX, OperandFormat::Imm16), - 0xBC => (Mnemonic::Mov, OperandFormat::SP, OperandFormat::Imm16), - 0xBD => (Mnemonic::Mov, OperandFormat::BP, OperandFormat::Imm16), - 0xBE => (Mnemonic::Mov, OperandFormat::SI, OperandFormat::Imm16), - 0xBF => (Mnemonic::Mov, OperandFormat::DI, OperandFormat::Imm16), + 0x00 => (Add, RM8, Reg8), + 0x01 => (Add, RM16, Reg16), + 0x02 => (Add, Reg8, RM8), + 0x03 => (Add, Reg16, RM16), + 0x04 => (Add, AL, Imm8), + 0x05 => (Add, AX, Imm16), + 0x08 => (Or, RM8, Reg8), + 0x09 => (Or, RM16, Reg16), + 0x0A => (Or, Reg8, RM8), + 0x0B => (Or, Reg16, RM16), + 0x0C => (Or, AL, Imm8), + 0x0D => (Or, AX, Imm16), + 0x10 => (Adc, RM8, Reg8), + 0x11 => (Adc, RM16, Reg16), + 0x12 => (Adc, Reg8, RM8), + 0x13 => (Adc, Reg16, RM16), + 0x14 => (Adc, AL, Imm8), + 0x15 => (Adc, AX, Imm16), + 0x18 => (Sbb, RM8, Reg8), + 0x19 => (Sbb, RM16, Reg16), + 0x1A => (Sbb, Reg8, RM8), + 0x1B => (Sbb, Reg16, RM16), + 0x1C => (Sbb, AL, Imm8), + 0x1D => (Sbb, AX, Imm16), + 0x28 => (Sub, RM8, Reg8), + 0x29 => (Sub, RM16, Reg16), + 0x2A => (Sub, Reg8, RM8), + 0x2B => (Sub, Reg16, RM16), + 0x2C => (Sub, AL, Imm8), + 0x2D => (Sub, AX, Imm16), + 0x30 => (Xor, RM8, Reg8), + 0x31 => (Xor, RM16, Reg16), + 0x32 => (Xor, Reg8, RM8), + 0x33 => (Xor, Reg16, RM16), + 0x34 => (Xor, AL, Imm8), + 0x35 => (Xor, AX, Imm16), + 0x40 => (Inc, AX, NoOperand), + 0x41 => (Inc, CX, NoOperand), + 0x42 => (Inc, DX, NoOperand), + 0x43 => (Inc, BX, NoOperand), + 0x44 => (Inc, SP, NoOperand), + 0x45 => (Inc, BP, NoOperand), + 0x46 => (Inc, SI, NoOperand), + 0x47 => (Inc, DI, NoOperand), + 0x48 => (Dec, AX, NoOperand), + 0x49 => (Dec, CX, NoOperand), + 0x4A => (Dec, DX, NoOperand), + 0x4B => (Dec, BX, NoOperand), + 0x4C => (Dec, SP, NoOperand), + 0x4D => (Dec, BP, NoOperand), + 0x4E => (Dec, SI, NoOperand), + 0x4F => (Dec, DI, NoOperand), + 0x70 => (Jo, Imm8, NoOperand), + 0x71 => (Jno, Imm8, NoOperand), + 0x72 => (Jc, Imm8, NoOperand), + 0x73 => (Jnc, Imm8, NoOperand), + 0x74 => (Jz, Imm8, NoOperand), + 0x75 => (Jnz, Imm8, NoOperand), + 0x76 => (Jna, Imm8, NoOperand), + 0x77 => (Ja, Imm8, NoOperand), + 0x78 => (Js, Imm8, NoOperand), + 0x79 => (Jns, Imm8, NoOperand), + 0x7A => (Jp, Imm8, NoOperand), + 0x7B => (Jnp, Imm8, NoOperand), + 0x7C => (Jl, Imm8, NoOperand), + 0x7D => (Jnl, Imm8, NoOperand), + 0x7E => (Jng, Imm8, NoOperand), + 0x7F => (Jg, Imm8, NoOperand), + 0x88 => (Mov, RM8, Reg8), + 0x89 => (Mov, RM16, Reg16), + 0x8A => (Mov, Reg8, RM8), + 0x8B => (Mov, Reg16, RM16), + 0x8C => (Mov, RM16, Sreg), + 0x8E => (Mov, Sreg, RM16), + 0x90 => (Nop, NoOperand, NoOperand), + 0x9E => (Sahf, NoOperand, NoOperand), + 0x9F => (Lahf, NoOperand, NoOperand), + 0xB0 => (Mov, AL, Imm8), + 0xB1 => (Mov, CL, Imm8), + 0xB2 => (Mov, DL, Imm8), + 0xB3 => (Mov, BL, Imm8), + 0xB4 => (Mov, AH, Imm8), + 0xB5 => (Mov, CH, Imm8), + 0xB6 => (Mov, DH, Imm8), + 0xB7 => (Mov, BH, Imm8), + 0xB8 => (Mov, AX, Imm16), + 0xB9 => (Mov, CX, Imm16), + 0xBA => (Mov, DX, Imm16), + 0xBB => (Mov, BX, Imm16), + 0xBC => (Mov, SP, Imm16), + 0xBD => (Mov, BP, Imm16), + 0xBE => (Mov, SI, Imm16), + 0xBF => (Mov, DI, Imm16), 0xD0 => { modrm = ModRM::from_bits(memory.read_u8(address + size as u64)); size += 1; match modrm.unwrap() & ModRM::REG_MASK { - ModRM::REG_4 => (Mnemonic::Shl, OperandFormat::RM8, OperandFormat::One), - ModRM::REG_5 => (Mnemonic::Shr, OperandFormat::RM8, OperandFormat::One), + ModRM::REG_4 => (Shl, RM8, One), + ModRM::REG_5 => (Shr, RM8, One), _ => unimplemented!(), } - } + }, 0xD2 => { modrm = ModRM::from_bits(memory.read_u8(address + size as u64)); size += 1; match modrm.unwrap() & ModRM::REG_MASK { - ModRM::REG_4 => (Mnemonic::Shl, OperandFormat::RM8, OperandFormat::CL), - ModRM::REG_5 => (Mnemonic::Shr, OperandFormat::RM8, OperandFormat::CL), + ModRM::REG_4 => (Shl, RM8, CL), + ModRM::REG_5 => (Shr, RM8, CL), _ => unimplemented!(), } }, - 0xEA => (Mnemonic::Jmp, OperandFormat::Ptr16_16, OperandFormat::NoOperand), - 0xF4 => (Mnemonic::Hlt, OperandFormat::NoOperand, OperandFormat::NoOperand), - 0xF8 => (Mnemonic::Clc, OperandFormat::NoOperand, OperandFormat::NoOperand), - 0xF9 => (Mnemonic::Stc, OperandFormat::NoOperand, OperandFormat::NoOperand), - 0xFA => (Mnemonic::Cli, OperandFormat::NoOperand, OperandFormat::NoOperand), - 0xFB => (Mnemonic::Sti, OperandFormat::NoOperand, OperandFormat::NoOperand), - 0xFC => (Mnemonic::Cld, OperandFormat::NoOperand, OperandFormat::NoOperand), - 0xFD => (Mnemonic::Std, OperandFormat::NoOperand, OperandFormat::NoOperand), - _ => (Mnemonic::Invalid, OperandFormat::NoOperand, OperandFormat::NoOperand), + 0xE0 => (Loopne, Imm8, NoOperand), + 0xE1 => (Loope, Imm8, NoOperand), + 0xE2 => (Loop, Imm8, NoOperand), + 0xE6 => (Out, Imm8, AL), + 0xE7 => (Out, Imm8, AX), + 0xE9 => (Jmp, Imm16, NoOperand), + 0xEA => (Jmp, Ptr16_16, NoOperand), + 0xEB => (Jmp, Imm8, NoOperand), + 0xEE => (Out, DX, AL), + 0xEF => (Out, DX, AX), + 0xF4 => (Hlt, NoOperand, NoOperand), + 0xF8 => (Clc, NoOperand, NoOperand), + 0xF9 => (Stc, NoOperand, NoOperand), + 0xFA => (Cli, NoOperand, NoOperand), + 0xFB => (Sti, NoOperand, NoOperand), + 0xFC => (Cld, NoOperand, NoOperand), + 0xFD => (Std, NoOperand, NoOperand), + 0xFE => { + modrm = ModRM::from_bits(memory.read_u8(address + size as u64)); + size += 1; + match modrm.unwrap() & ModRM::REG_MASK { + ModRM::REG_0 => (Inc, RM8, NoOperand), + ModRM::REG_1 => (Dec, RM8, NoOperand), + _ => unimplemented!(), + } + }, + 0xFF => { + modrm = ModRM::from_bits(memory.read_u8(address + size as u64)); + size += 1; + match modrm.unwrap() & ModRM::REG_MASK { + ModRM::REG_0 => (Inc, RM16, NoOperand), + ModRM::REG_1 => (Dec, RM16, NoOperand), + _ => unimplemented!(), + } + }, + _ => (Invalid, NoOperand, NoOperand), }; if modrm.is_none() && @@ -411,9 +441,13 @@ pub enum Mnemonic { Js, Jz, Lahf, + Loop, + Loope, + Loopne, Mov, Nop, Or, + Out, Sahf, Sbb, Shl, diff --git a/src/processor/mod.rs b/src/processor/mod.rs index 41a1061..8b94895 100644 --- a/src/processor/mod.rs +++ b/src/processor/mod.rs @@ -11,6 +11,7 @@ pub use instruction::*; pub use register::Registers; use crate::memory::Memory; +use crate::io::IoBus; #[derive(Default)] pub struct Processor { @@ -19,10 +20,12 @@ pub struct Processor { } impl Processor { - pub fn exec(&mut self, memory: &mut Memory, instruction: &Instruction) { + pub fn exec(&mut self, memory: &mut Memory, io: &mut IoBus, instruction: &Instruction) { use Mnemonic::*; + use OperandType::*; + use OperandSize::*; match (instruction.mnemonic, instruction.op1, instruction.op2) { - (Add, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::Byte)) => { + (Add, Operand(op1, Byte), Operand(op2, Byte)) => { let dst = self.operand8(memory, op1, instruction.segment_override); let src = self.operand8(memory, op2, instruction.segment_override); let (value, carry) = dst.overflowing_add(src); @@ -34,7 +37,7 @@ impl Processor { self.set_operand8(value, memory, op1, instruction.segment_override); }, - (Add, Operand(op1, OperandSize::Word), Operand(op2, OperandSize::Word)) => { + (Add, Operand(op1, Word), Operand(op2, Word)) => { let dst = self.operand16(memory, op1, instruction.segment_override); let src = self.operand16(memory, op2, instruction.segment_override); let (value, carry) = dst.overflowing_add(src); @@ -46,7 +49,7 @@ impl Processor { self.set_operand16(value, memory, op1, instruction.segment_override); }, - (Or, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::Byte)) => { + (Or, Operand(op1, Byte), Operand(op2, Byte)) => { let dst = self.operand8(memory, op1, instruction.segment_override); let src = self.operand8(memory, op2, instruction.segment_override); let value = dst | src; @@ -59,7 +62,7 @@ impl Processor { self.set_operand8(value, memory, op1, instruction.segment_override); }, - (Or, Operand(op1, OperandSize::Word), Operand(op2, OperandSize::Word)) => { + (Or, Operand(op1, Word), Operand(op2, Word)) => { let dst = self.operand16(memory, op1, instruction.segment_override); let src = self.operand16(memory, op2, instruction.segment_override); let value = dst | src; @@ -72,7 +75,7 @@ impl Processor { self.set_operand16(value, memory, op1, instruction.segment_override); }, - (Adc, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::Byte)) => { + (Adc, Operand(op1, Byte), Operand(op2, Byte)) => { let dst = self.operand8(memory, op1, instruction.segment_override); let src = self.operand8(memory, op2, instruction.segment_override); let (value, carry) = dst.carrying_add(src, self.registers.cf()); @@ -84,7 +87,7 @@ impl Processor { self.set_operand8(value, memory, op1, instruction.segment_override); }, - (Adc, Operand(op1, OperandSize::Word), Operand(op2, OperandSize::Word)) => { + (Adc, Operand(op1, Word), Operand(op2, Word)) => { let dst = self.operand16(memory, op1, instruction.segment_override); let src = self.operand16(memory, op2, instruction.segment_override); let (value, carry) = dst.carrying_add(src, self.registers.cf()); @@ -96,7 +99,7 @@ impl Processor { self.set_operand16(value, memory, op1, instruction.segment_override); }, - (Sbb, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::Byte)) => { + (Sbb, Operand(op1, Byte), Operand(op2, Byte)) => { let dst = self.operand8(memory, op1, instruction.segment_override); let src = self.operand8(memory, op2, instruction.segment_override); let (value, borrow) = dst.borrowing_sub(src, self.registers.cf()); @@ -108,7 +111,7 @@ impl Processor { self.set_operand8(value, memory, op1, instruction.segment_override); }, - (Sbb, Operand(op1, OperandSize::Word), Operand(op2, OperandSize::Word)) => { + (Sbb, Operand(op1, Word), Operand(op2, Word)) => { let dst = self.operand16(memory, op1, instruction.segment_override); let src = self.operand16(memory, op2, instruction.segment_override); let (value, borrow) = dst.borrowing_sub(src, self.registers.cf()); @@ -120,7 +123,7 @@ impl Processor { self.set_operand16(value, memory, op1, instruction.segment_override); }, - (Sub, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::Byte)) => { + (Sub, Operand(op1, Byte), Operand(op2, Byte)) => { let dst = self.operand8(memory, op1, instruction.segment_override); let src = self.operand8(memory, op2, instruction.segment_override); let (value, borrow) = dst.overflowing_sub(src); @@ -132,7 +135,7 @@ impl Processor { self.set_operand8(value, memory, op1, instruction.segment_override); }, - (Sub, Operand(op1, OperandSize::Word), Operand(op2, OperandSize::Word)) => { + (Sub, Operand(op1, Word), Operand(op2, Word)) => { let dst = self.operand16(memory, op1, instruction.segment_override); let src = self.operand16(memory, op2, instruction.segment_override); let (value, borrow) = dst.overflowing_sub(src); @@ -144,7 +147,7 @@ impl Processor { self.set_operand16(value, memory, op1, instruction.segment_override); }, - (Xor, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::Byte)) => { + (Xor, Operand(op1, Byte), Operand(op2, Byte)) => { let dst = self.operand8(memory, op1, instruction.segment_override); let src = self.operand8(memory, op2, instruction.segment_override); let value = dst ^ src; @@ -157,7 +160,7 @@ impl Processor { self.set_operand8(value, memory, op1, instruction.segment_override); }, - (Xor, Operand(op1, OperandSize::Word), Operand(op2, OperandSize::Word)) => { + (Xor, Operand(op1, Word), Operand(op2, Word)) => { let dst = self.operand16(memory, op1, instruction.segment_override); let src = self.operand16(memory, op2, instruction.segment_override); let value = dst ^ src; @@ -170,7 +173,7 @@ impl Processor { self.set_operand16(value, memory, op1, instruction.segment_override); }, - (Inc, Operand(op1, OperandSize::Word), _) => { + (Inc, Operand(op1, Word), _) => { let dst = self.operand16(memory, op1, instruction.segment_override); let value = dst.wrapping_add(1); @@ -181,7 +184,7 @@ impl Processor { self.set_operand16(value, memory, op1, instruction.segment_override); }, - (Dec, Operand(op1, OperandSize::Word), _) => { + (Dec, Operand(op1, Word), _) => { let dst = self.operand16(memory, op1, instruction.segment_override); let value = dst.wrapping_sub(1); @@ -192,50 +195,50 @@ impl Processor { self.set_operand16(value, memory, op1, instruction.segment_override); }, - (Jo, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + (Jo, Operand(Imm8(op1), Byte), _) => if self.registers.of() { self.registers.add_ip(op1 as i8 as i16) }, - (Jno, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + (Jno, Operand(Imm8(op1), Byte), _) => if !self.registers.of() { self.registers.add_ip(op1 as i8 as i16) }, - (Jc, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + (Jc, Operand(Imm8(op1), Byte), _) => if self.registers.cf() { self.registers.add_ip(op1 as i8 as i16) }, - (Jnc, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + (Jnc, Operand(Imm8(op1), Byte), _) => if !self.registers.cf() { self.registers.add_ip(op1 as i8 as i16) }, - (Jz, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + (Jz, Operand(Imm8(op1), Byte), _) => if self.registers.zf() { self.registers.add_ip(op1 as i8 as i16) }, - (Jnz, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + (Jnz, Operand(Imm8(op1), Byte), _) => if !self.registers.zf() { self.registers.add_ip(op1 as i8 as i16) }, - (Jna, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + (Jna, Operand(Imm8(op1), Byte), _) => if self.registers.cf() || self.registers.zf() { self.registers.add_ip(op1 as i8 as i16) }, - (Ja, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + (Ja, Operand(Imm8(op1), Byte), _) => if !(self.registers.cf() || self.registers.zf()) { self.registers.add_ip(op1 as i8 as i16) }, - (Js, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + (Js, Operand(Imm8(op1), Byte), _) => if self.registers.sf() { self.registers.add_ip(op1 as i8 as i16) }, - (Jns, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + (Jns, Operand(Imm8(op1), Byte), _) => if !self.registers.sf() { self.registers.add_ip(op1 as i8 as i16) }, - (Jp, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + (Jp, Operand(Imm8(op1), Byte), _) => if self.registers.pf() { self.registers.add_ip(op1 as i8 as i16) }, - (Jnp, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + (Jnp, Operand(Imm8(op1), Byte), _) => if !self.registers.pf() { self.registers.add_ip(op1 as i8 as i16) }, - (Jl, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + (Jl, Operand(Imm8(op1), Byte), _) => if self.registers.sf() != self.registers.of() { self.registers.add_ip(op1 as i8 as i16) }, - (Jnl, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + (Jnl, Operand(Imm8(op1), Byte), _) => if self.registers.sf() == self.registers.of() { self.registers.add_ip(op1 as i8 as i16) }, - (Jng, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + (Jng, Operand(Imm8(op1), Byte), _) => if self.registers.zf() || (self.registers.sf() != self.registers.of()) { self.registers.add_ip(op1 as i8 as i16) }, - (Jg, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + (Jg, Operand(Imm8(op1), Byte), _) => if !self.registers.zf() && (self.registers.sf() == self.registers.of()) { self.registers.add_ip(op1 as i8 as i16) }, (Nop, _, _) => {}, (Sahf, _, _) => self.registers.set_flags(self.registers.ah().into()), (Lahf, _, _) => self.registers.set_ah(self.registers.flags() as u8), - (Mov, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::Byte)) => + (Mov, Operand(op1, Byte), Operand(op2, Byte)) => self.set_operand8(self.operand8(memory, op2, instruction.segment_override), memory, op1, instruction.segment_override), - (Mov, Operand(op1, OperandSize::Word), Operand(op2, OperandSize::Word)) => + (Mov, Operand(op1, Word), Operand(op2, Word)) => self.set_operand16(self.operand16(memory, op2, instruction.segment_override), memory, op1, instruction.segment_override), - (Shl, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::Byte)) => 'shl: { + (Shl, Operand(op1, Byte), Operand(op2, Byte)) => 'shl: { let dst = self.operand8(memory, op1, instruction.segment_override); let shift = self.operand8(memory, op2, instruction.segment_override); let shift = shift & 0b11111; @@ -264,7 +267,7 @@ impl Processor { self.registers.set_sf(result >> 7 != 0); self.registers.set_zf(result == 0); }, - (Shr, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::Byte)) => 'shr: { + (Shr, Operand(op1, Byte), Operand(op2, Byte)) => 'shr: { let dst = self.operand8(memory, op1, instruction.segment_override); let shift = self.operand8(memory, op2, instruction.segment_override); let shift = shift & 0b11111; @@ -289,10 +292,58 @@ impl Processor { self.registers.set_sf(result >> 7 != 0); self.registers.set_zf(result == 0); }, - (Jmp, Operand(OperandType::Ptr16_16(base, offset), _), _) => { + (Loopne, Operand(Imm8(offset), _), _) => { + self.registers.set_cx(self.registers.cx().wrapping_sub(1)); + if !self.registers.zf() && self.registers.cx() != 0 { + self.registers.add_ip(offset as i8 as i16); + } + }, + (Loope, Operand(Imm8(offset), _), _) => { + self.registers.set_cx(self.registers.cx().wrapping_sub(1)); + if self.registers.zf() && self.registers.cx() != 0 { + self.registers.add_ip(offset as i8 as i16); + } + }, + (Loop, Operand(Imm8(offset), _), _) => { + self.registers.set_cx(self.registers.cx().wrapping_sub(1)); + if self.registers.cx() != 0 { + self.registers.add_ip(offset as i8 as i16); + } + }, + (Out, Operand(op1, Byte), Operand(op2, Byte)) => { + io.write_u8( + self.operand8(memory, op1, instruction.segment_override) as u16, + self.operand8(memory, op2, instruction.segment_override), + ); + }, + (Out, Operand(op1, Byte), Operand(op2, Word)) => { + io.write_u16( + self.operand8(memory, op1, instruction.segment_override) as u16, + self.operand16(memory, op2, instruction.segment_override), + ); + }, + (Out, Operand(op1, Word), Operand(op2, Byte)) => { + io.write_u8( + self.operand16(memory, op1, instruction.segment_override), + self.operand8(memory, op2, instruction.segment_override), + ); + }, + (Out, Operand(op1, Word), Operand(op2, Word)) => { + io.write_u16( + self.operand16(memory, op1, instruction.segment_override), + self.operand16(memory, op2, instruction.segment_override), + ); + }, + (Jmp, Operand(Imm16(offset), _), _) => { + self.registers.add_ip(offset as i16); + }, + (Jmp, Operand(Ptr16_16(base, offset), _), _) => { self.registers.set_cs(base); self.registers.set_ip(offset); }, + (Jmp, Operand(Imm8(offset), _), _) => { + self.registers.add_ip(offset as i8 as i16); + }, (Hlt, _, _) => self.halted = true, (Clc, _, _) => self.registers.set_cf(false), (Stc, _, _) => self.registers.set_cf(true), @@ -301,6 +352,29 @@ impl Processor { (Sti, _, _) => self.registers.set_if(true), (Cld, _, _) => self.registers.set_df(false), (Std, _, _) => self.registers.set_df(true), + (Inc, Operand(op1, Byte), _) => { + let dst = self.operand8(memory, op1, instruction.segment_override); + let value = dst.wrapping_add(1); + + // FIXME: AF, PF, OF + // preserves CF + self.registers.set_sf(value >> 7 != 0); + self.registers.set_zf(value == 0); + + self.set_operand8(value, memory, op1, instruction.segment_override); + }, + (Dec, Operand(op1, Byte), _) => { + let dst = self.operand8(memory, op1, instruction.segment_override); + let value = dst.wrapping_sub(1); + + // FIXME: AF, PF, OF + // preserves CF + self.registers.set_sf(value >> 7 != 0); + self.registers.set_zf(value == 0); + + self.set_operand8(value, memory, op1, instruction.segment_override); + }, + _ => unimplemented!("instruction {instruction:?} not implemented"), } }