diff --git a/.gitignore b/.gitignore index ea8c4bf..507b1e4 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/roms diff --git a/Cargo.lock b/Cargo.lock index ff52d4d..b696ec7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,61 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "bitflags" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "copycat" version = "0.1.0" dependencies = [ "bitflags", + "hashbrown", ] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" diff --git a/Cargo.toml b/Cargo.toml index 4151aca..970c365 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,4 @@ edition = "2021" [dependencies] bitflags = "2.4.0" +hashbrown = "0.14.0" diff --git a/src/main.rs b/src/main.rs index d4e7195..b57af0f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,12 +4,16 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use copycat::memory::{Memory, MiB}; -use processor::{Instruction, Processor}; +use copycat::memory::{Memory, KiB}; +use copycat::processor::{Instruction, Processor}; + +static BIOS_ROM: &[u8; 8 * KiB as usize] = include_bytes!("../roms/BIOS_IBM5150_24APR81_5700051_U33.BIN"); fn main() { - let mut mem = Memory::new(1 * MiB); - mem.write(0xffff0, [0x90, 0x04, 0x69, 0xF4]); + let mut mem = Memory::new(64 * KiB); + 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 cpu = Processor::default(); cpu.registers.dump(); diff --git a/src/memory.rs b/src/memory.rs index 1169706..7978373 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -13,10 +13,12 @@ mod consts { } pub use consts::*; +use hashbrown::HashMap; pub struct Memory { memory: *mut u8, memory_size: u64, + tlb: HashMap, } impl Memory { @@ -26,20 +28,39 @@ impl Memory { alloc(Layout::from_size_align(size.try_into().unwrap(), 1 * MiB as usize).expect("layout error")) }, memory_size: size, + tlb: HashMap::new(), } } + pub fn add_tlb_entry(&mut self, page_num: u64, page: *mut ()) { + self.tlb.insert(page_num, page.cast()); + } + pub fn read(&self, address: u64) -> [u8; N] { + let page_num = address >> 12; + if let Some(page) = self.tlb.get(&page_num) { + unsafe { + return page.add(address as usize & 0xFFF).cast::<[u8; N]>().read_unaligned(); + } + } + if address >= self.memory_size { return [0; N]; } unsafe { - self.memory.offset(address.try_into().unwrap()).cast::<[u8; N]>().read_unaligned() + self.memory.add(address.try_into().unwrap()).cast::<[u8; N]>().read_unaligned() } } pub fn write(&mut self, address: u64, value: [u8; N]) { + let page_num = address >> 12; + if let Some(page) = self.tlb.get(&page_num) { + unsafe { + return page.add(address as usize & 0xFFF).cast::<[u8; N]>().write_unaligned(value); + } + } + if address >= self.memory_size { return; } diff --git a/src/processor/instruction.rs b/src/processor/instruction.rs index c56471a..d0d4066 100644 --- a/src/processor/instruction.rs +++ b/src/processor/instruction.rs @@ -26,6 +26,7 @@ impl Instruction { let mut opcode = memory.read_u8(address); let mut size: u8 = 1; let mut segment_override = SegmentOverride::None; + let mut modrm = None; loop { // FIXME: handle lock and rep @@ -48,6 +49,12 @@ impl Instruction { 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), @@ -88,14 +95,79 @@ impl Instruction { 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), + 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), + _ => 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), + _ => 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), }; - let mut modrm = None; - if matches!(op1ty, OperandFormat::RM8 | OperandFormat::RM16 | OperandFormat::Reg8 | OperandFormat::Reg16) - || matches!(op2ty, OperandFormat::RM8 | OperandFormat::RM16 | OperandFormat::Reg8 | OperandFormat::Reg16) + if modrm.is_none() && + (matches!(op1ty, OperandFormat::RM8 | OperandFormat::RM16 | OperandFormat::Reg8 | OperandFormat::Reg16) + || matches!(op2ty, OperandFormat::RM8 | OperandFormat::RM16 | OperandFormat::Reg8 | OperandFormat::Reg16)) { modrm = ModRM::from_bits(memory.read_u8(address + size as u64)); size += 1; @@ -243,6 +315,13 @@ impl Instruction { ModRM::REG_7 => OperandType::DI, _ => unreachable!(), }, OperandSize::Word), + OperandFormat::Sreg => Operand(match modrm.unwrap() & ModRM::REG_MASK { + ModRM::REG_0 => OperandType::ES, + ModRM::REG_1 => OperandType::CS, + ModRM::REG_2 => OperandType::SS, + ModRM::REG_3 => OperandType::DS, + _ => unreachable!(), + }, OperandSize::Word), OperandFormat::Imm8 => { let op = Operand(OperandType::Imm8(memory.read_u8(address + size as u64)), OperandSize::Byte); size += 1; @@ -253,7 +332,21 @@ impl Instruction { size += 2; op }, + OperandFormat::Ptr16_16 => { + let base = memory.read_u16(address + size as u64 + 2); + let offset = memory.read_u16(address + size as u64); + size += 4; + Operand(OperandType::Ptr16_16(base, offset), OperandSize::Word) + }, + OperandFormat::One => Operand(OperandType::Imm8(1), OperandSize::Byte), OperandFormat::AL => Operand(OperandType::AL, OperandSize::Byte), + OperandFormat::CL => Operand(OperandType::CL, OperandSize::Byte), + OperandFormat::DL => Operand(OperandType::DL, OperandSize::Byte), + OperandFormat::BL => Operand(OperandType::BL, OperandSize::Byte), + OperandFormat::AH => Operand(OperandType::AH, OperandSize::Byte), + OperandFormat::CH => Operand(OperandType::CH, OperandSize::Byte), + OperandFormat::DH => Operand(OperandType::DH, OperandSize::Byte), + OperandFormat::BH => Operand(OperandType::BH, OperandSize::Byte), OperandFormat::AX => Operand(OperandType::AX, OperandSize::Word), OperandFormat::CX => Operand(OperandType::CX, OperandSize::Word), OperandFormat::DX => Operand(OperandType::DX, OperandSize::Word), @@ -294,11 +387,40 @@ pub enum Mnemonic { Invalid, Adc, Add, + Clc, + Cld, + Cli, Dec, Hlt, Inc, + Ja, + Jc, + Jg, + Jl, + Jmp, + Jna, + Jnc, + Jng, + Jnl, + Jno, + Jnp, + Jns, + Jnz, + Jo, + Jp, + Js, + Jz, + Lahf, + Mov, Nop, + Or, + Sahf, Sbb, + Shl, + Shr, + Stc, + Std, + Sti, Sub, Xor, } @@ -310,9 +432,19 @@ enum OperandFormat { RM16, Reg8, Reg16, + Sreg, Imm8, Imm16, + Ptr16_16, + One, AL, + CL, + DL, + BL, + AH, + CH, + DH, + BH, AX, CX, DX, @@ -338,28 +470,28 @@ pub enum OperandType { NoOperand, Imm8(u8), Imm16(u16), + Ptr16_16(u16, u16), Indirect(AddressingMode), AL, - AH, - AX, - BL, - BH, - BX, CL, - CH, - CX, DL, + BL, + AH, + CH, DH, + BH, + AX, + CX, DX, + BX, + SP, + BP, SI, DI, - BP, - SP, - IP, - CS, - DS, ES, + CS, SS, + DS, FLAGS, } diff --git a/src/processor/mod.rs b/src/processor/mod.rs index 0251195..5e92334 100644 --- a/src/processor/mod.rs +++ b/src/processor/mod.rs @@ -21,10 +21,10 @@ pub struct Processor { impl Processor { pub fn exec(&mut self, memory: &mut Memory, instruction: &Instruction) { use Mnemonic::*; - match (instruction.mnemonic, instruction.op1.1, instruction.op2.1) { - (Add, OperandSize::Byte, _) => { - let dst = self.operand8(memory, instruction.op1.0, instruction.segment_override); - let src = self.operand8(memory, instruction.op2.0, instruction.segment_override); + match (instruction.mnemonic, instruction.op1, instruction.op2) { + (Add, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::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); // FIXME: AF, PF, OF @@ -32,11 +32,11 @@ impl Processor { self.registers.set_sf(value >> 7 != 0); self.registers.set_zf(value == 0); - self.set_operand8(value, memory, instruction.op1.0, instruction.segment_override); + self.set_operand8(value, memory, op1, instruction.segment_override); }, - (Add, OperandSize::Word, _) => { - let dst = self.operand16(memory, instruction.op1.0, instruction.segment_override); - let src = self.operand16(memory, instruction.op2.0, instruction.segment_override); + (Add, Operand(op1, OperandSize::Word), Operand(op2, OperandSize::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); // FIXME: AF, PF, OF @@ -44,11 +44,37 @@ impl Processor { self.registers.set_sf(value >> 15 != 0); self.registers.set_zf(value == 0); - self.set_operand16(value, memory, instruction.op1.0, instruction.segment_override); + self.set_operand16(value, memory, op1, instruction.segment_override); }, - (Adc, OperandSize::Byte, _) => { - let dst = self.operand8(memory, instruction.op1.0, instruction.segment_override); - let src = self.operand8(memory, instruction.op2.0, instruction.segment_override); + (Or, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::Byte)) => { + let dst = self.operand8(memory, op1, instruction.segment_override); + let src = self.operand8(memory, op2, instruction.segment_override); + let value = dst | src; + + // FIXME: PF + self.registers.set_cf(false); + self.registers.set_of(false); + self.registers.set_sf(value >> 7 != 0); + self.registers.set_zf(value == 0); + + self.set_operand8(value, memory, op1, instruction.segment_override); + }, + (Or, Operand(op1, OperandSize::Word), Operand(op2, OperandSize::Word)) => { + let dst = self.operand16(memory, op1, instruction.segment_override); + let src = self.operand16(memory, op2, instruction.segment_override); + let value = dst | src; + + // FIXME: PF + self.registers.set_cf(false); + self.registers.set_of(false); + self.registers.set_sf(value >> 15 != 0); + self.registers.set_zf(value == 0); + + self.set_operand16(value, memory, op1, instruction.segment_override); + }, + (Adc, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::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()); // FIXME: AF, PF, OF @@ -56,11 +82,11 @@ impl Processor { self.registers.set_sf(value >> 7 != 0); self.registers.set_zf(value == 0); - self.set_operand8(value, memory, instruction.op1.0, instruction.segment_override); + self.set_operand8(value, memory, op1, instruction.segment_override); }, - (Adc, OperandSize::Word, _) => { - let dst = self.operand16(memory, instruction.op1.0, instruction.segment_override); - let src = self.operand16(memory, instruction.op2.0, instruction.segment_override); + (Adc, Operand(op1, OperandSize::Word), Operand(op2, OperandSize::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()); // FIXME: AF, PF, OF @@ -68,11 +94,11 @@ impl Processor { self.registers.set_sf(value >> 15 != 0); self.registers.set_zf(value == 0); - self.set_operand16(value, memory, instruction.op1.0, instruction.segment_override); + self.set_operand16(value, memory, op1, instruction.segment_override); }, - (Sbb, OperandSize::Byte, _) => { - let dst = self.operand8(memory, instruction.op1.0, instruction.segment_override); - let src = self.operand8(memory, instruction.op2.0, instruction.segment_override); + (Sbb, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::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()); // FIXME: AF, PF, OF @@ -80,11 +106,11 @@ impl Processor { self.registers.set_sf(value >> 7 != 0); self.registers.set_zf(value == 0); - self.set_operand8(value, memory, instruction.op1.0, instruction.segment_override); + self.set_operand8(value, memory, op1, instruction.segment_override); }, - (Sbb, OperandSize::Word, _) => { - let dst = self.operand16(memory, instruction.op1.0, instruction.segment_override); - let src = self.operand16(memory, instruction.op2.0, instruction.segment_override); + (Sbb, Operand(op1, OperandSize::Word), Operand(op2, OperandSize::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()); // FIXME: AF, PF, OF @@ -92,11 +118,11 @@ impl Processor { self.registers.set_sf(value >> 15 != 0); self.registers.set_zf(value == 0); - self.set_operand16(value, memory, instruction.op1.0, instruction.segment_override); + self.set_operand16(value, memory, op1, instruction.segment_override); }, - (Sub, OperandSize::Byte, _) => { - let dst = self.operand8(memory, instruction.op1.0, instruction.segment_override); - let src = self.operand8(memory, instruction.op2.0, instruction.segment_override); + (Sub, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::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); // FIXME: AF, PF, OF @@ -104,11 +130,11 @@ impl Processor { self.registers.set_sf(value >> 7 != 0); self.registers.set_zf(value == 0); - self.set_operand8(value, memory, instruction.op1.0, instruction.segment_override); + self.set_operand8(value, memory, op1, instruction.segment_override); }, - (Sub, OperandSize::Word, _) => { - let dst = self.operand16(memory, instruction.op1.0, instruction.segment_override); - let src = self.operand16(memory, instruction.op2.0, instruction.segment_override); + (Sub, Operand(op1, OperandSize::Word), Operand(op2, OperandSize::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); // FIXME: AF, PF, OF @@ -116,10 +142,36 @@ impl Processor { self.registers.set_sf(value >> 15 != 0); self.registers.set_zf(value == 0); - self.set_operand16(value, memory, instruction.op1.0, instruction.segment_override); + self.set_operand16(value, memory, op1, instruction.segment_override); }, - (Inc, OperandSize::Word, _) => { - let dst = self.operand16(memory, instruction.op1.0, instruction.segment_override); + (Xor, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::Byte)) => { + let dst = self.operand8(memory, op1, instruction.segment_override); + let src = self.operand8(memory, op2, instruction.segment_override); + let value = dst ^ src; + + // FIXME: PF + self.registers.set_cf(false); + self.registers.set_of(false); + self.registers.set_sf(value >> 7 != 0); + self.registers.set_zf(value == 0); + + self.set_operand8(value, memory, op1, instruction.segment_override); + }, + (Xor, Operand(op1, OperandSize::Word), Operand(op2, OperandSize::Word)) => { + let dst = self.operand16(memory, op1, instruction.segment_override); + let src = self.operand16(memory, op2, instruction.segment_override); + let value = dst ^ src; + + // FIXME: PF + self.registers.set_cf(false); + self.registers.set_of(false); + self.registers.set_sf(value >> 15 != 0); + self.registers.set_zf(value == 0); + + self.set_operand16(value, memory, op1, instruction.segment_override); + }, + (Inc, Operand(op1, OperandSize::Word), _) => { + let dst = self.operand16(memory, op1, instruction.segment_override); let value = dst.wrapping_add(1); // FIXME: AF, PF, OF @@ -127,10 +179,10 @@ impl Processor { self.registers.set_sf(value >> 15 != 0); self.registers.set_zf(value == 0); - self.set_operand16(value, memory, instruction.op1.0, instruction.segment_override); + self.set_operand16(value, memory, op1, instruction.segment_override); }, - (Dec, OperandSize::Word, _) => { - let dst = self.operand16(memory, instruction.op1.0, instruction.segment_override); + (Dec, Operand(op1, OperandSize::Word), _) => { + let dst = self.operand16(memory, op1, instruction.segment_override); let value = dst.wrapping_sub(1); // FIXME: AF, PF, OF @@ -138,10 +190,117 @@ impl Processor { self.registers.set_sf(value >> 15 != 0); self.registers.set_zf(value == 0); - self.set_operand16(value, memory, instruction.op1.0, instruction.segment_override); + self.set_operand16(value, memory, op1, instruction.segment_override); }, + (Jo, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + if self.registers.of() { self.registers.add_ip(op1 as i8 as i16) }, + (Jno, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + if !self.registers.of() { self.registers.add_ip(op1 as i8 as i16) }, + (Jc, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + if self.registers.cf() { self.registers.add_ip(op1 as i8 as i16) }, + (Jnc, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + if !self.registers.cf() { self.registers.add_ip(op1 as i8 as i16) }, + (Jz, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + if self.registers.zf() { self.registers.add_ip(op1 as i8 as i16) }, + (Jnz, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + if !self.registers.zf() { self.registers.add_ip(op1 as i8 as i16) }, + (Jna, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + if self.registers.cf() || self.registers.zf() { self.registers.add_ip(op1 as i8 as i16) }, + (Ja, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + if !(self.registers.cf() || self.registers.zf()) { self.registers.add_ip(op1 as i8 as i16) }, + (Js, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + if self.registers.sf() { self.registers.add_ip(op1 as i8 as i16) }, + (Jns, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + if !self.registers.sf() { self.registers.add_ip(op1 as i8 as i16) }, + (Jp, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + if self.registers.pf() { self.registers.add_ip(op1 as i8 as i16) }, + (Jnp, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + if !self.registers.pf() { self.registers.add_ip(op1 as i8 as i16) }, + (Jl, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + if self.registers.sf() != self.registers.of() { self.registers.add_ip(op1 as i8 as i16) }, + (Jnl, Operand(OperandType::Imm8(op1), OperandSize::Byte), _) => + if self.registers.sf() == self.registers.of() { self.registers.add_ip(op1 as i8 as i16) }, + (Jng, Operand(OperandType::Imm8(op1), OperandSize::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), _) => + 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)) => + self.set_operand8(self.operand8(memory, op2, instruction.segment_override), memory, op1, instruction.segment_override), + (Mov, Operand(op1, OperandSize::Word), Operand(op2, OperandSize::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: { + let dst = self.operand8(memory, op1, instruction.segment_override); + let shift = self.operand8(memory, op2, instruction.segment_override); + let shift = shift & 0b11111; + + let (result, carry, overflow) = match shift { + 9.. => (0, false, false), + 8 => (0, dst & 1 == 1, false), + _ => { + let result = dst << shift; + let carry = dst.overflowing_shr(8 - shift as u32).0 & 1 == 1; + (result, carry, (result >> 7 != 0) ^ carry) + }, + }; + + self.set_operand8(result, memory, op1, instruction.segment_override); + if shift == 0 { + break 'shl; + } + + if shift == 1 { + self.registers.set_of(overflow); + } + + // FIXME: PF + self.registers.set_cf(carry); + self.registers.set_sf(result >> 7 != 0); + self.registers.set_zf(result == 0); + }, + (Shr, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::Byte)) => 'shr: { + let dst = self.operand8(memory, op1, instruction.segment_override); + let shift = self.operand8(memory, op2, instruction.segment_override); + let shift = shift & 0b11111; + + let (result, carry, overflow) = match shift { + 9.. => (0, false, false), + 8 => (0, dst & 0x80 == 0x80, false), + _ => (dst >> shift, dst.overflowing_shr(shift as u32 - 1).0 & 1 == 1, dst & 0x80 == 0x80), + }; + + self.set_operand8(result, memory, op1, instruction.segment_override); + if shift == 0 { + break 'shr; + } + + if shift == 1 { + self.registers.set_of(overflow); + } + + // FIXME: PF + self.registers.set_cf(carry); + self.registers.set_sf(result >> 7 != 0); + self.registers.set_zf(result == 0); + }, + (Jmp, Operand(OperandType::Ptr16_16(base, offset), _), _) => { + self.registers.set_cs(base); + self.registers.set_ip(offset); + }, (Hlt, _, _) => self.halted = true, + (Clc, _, _) => self.registers.set_cf(false), + (Stc, _, _) => self.registers.set_cf(true), + (Cli, _, _) => self.registers.set_if(false), + // FIXME: set delay interrupts flag + (Sti, _, _) => self.registers.set_if(true), + (Cld, _, _) => self.registers.set_df(false), + (Std, _, _) => self.registers.set_df(true), _ => unimplemented!("instruction {instruction:?} not implemented"), } } @@ -189,6 +348,10 @@ impl Processor { OperandType::BP => self.registers.bp(), OperandType::SI => self.registers.si(), OperandType::DI => self.registers.di(), + OperandType::ES => self.registers.es(), + OperandType::CS => self.registers.cs(), + OperandType::SS => self.registers.ss(), + OperandType::DS => self.registers.ds(), _ => unreachable!(), } } @@ -204,6 +367,10 @@ impl Processor { OperandType::BP => self.registers.set_bp(value), OperandType::SI => self.registers.set_si(value), OperandType::DI => self.registers.set_di(value), + OperandType::ES => self.registers.set_es(value), + OperandType::CS => self.registers.set_cs(value), + OperandType::SS => self.registers.set_ss(value), + OperandType::DS => self.registers.set_ds(value), _ => unreachable!(), } } diff --git a/src/processor/register.rs b/src/processor/register.rs index 3dc0c9d..4dcbd25 100644 --- a/src/processor/register.rs +++ b/src/processor/register.rs @@ -205,7 +205,9 @@ impl Registers { } pub fn set_flags(&mut self, value: u16) { - self.flags = value; + // ignore reserved bits + // FIXME: bits 12-15 are always 1 on 8086 and 186 + self.flags = (value & 0xFFD7) | 0b10; } pub fn cf(&self) -> bool { @@ -315,32 +317,6 @@ impl Registers { self.flags &= !(1 << 11); } } - - // pub fn sreg(&self, modrm: ModRM) -> u16 { - // match modrm & ModRM::REG_MASK { - // ModRM::REG_0 => self.es(), - // ModRM::REG_1 => self.cs(), - // ModRM::REG_2 => self.ss(), - // ModRM::REG_3 => self.ds(), - // // 8086 doesn't have FS or GS - // // ModRM::REG_4 => self.fs(), - // // ModRM::REG_5 => self.gs(), - // _ => unimplemented!("invalid segment register"), - // } - // } - - // pub fn set_sreg(&mut self, modrm: ModRM, value: u16) { - // match modrm & ModRM::REG_MASK { - // ModRM::REG_0 => self.set_es(value), - // ModRM::REG_1 => self.set_cs(value), - // ModRM::REG_2 => self.set_ss(value), - // ModRM::REG_3 => self.set_ds(value), - // // 8086 doesn't have FS or GS - // // ModRM::REG_4 => self.set_fs(value), - // // ModRM::REG_5 => self.set_gs(value), - // _ => unimplemented!("invalid segment register"), - // } - // } } impl fmt::Display for Registers {