1
0
Fork 0
mirror of https://git.sr.ht/~asya/copycat synced 2024-11-21 16:18:44 -06:00

Load 5150 BIOS and pass 8088 processor test

This patch loads and runs the 5150 BIOS, and implements the instructions
necessary to pass the 8088 processor test done by the BIOS on boot.

The 5150 BIOS ROM is loaded with a TLB-like address lookup buffer that
is prefilled with entries that point to BIOS ROM in the host memory.
This TLB-like buffer will likely evolve to a full TLB in the far future
when we implement paging.

Signed-off-by: AsyaTheAbove <asya@waifu.club>
This commit is contained in:
AsyaTheAbove 2023-08-29 13:34:46 +03:00
parent d095cd4055
commit 03055b819d
8 changed files with 434 additions and 86 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
/target
/roms

46
Cargo.lock generated
View file

@ -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"

View file

@ -7,3 +7,4 @@ edition = "2021"
[dependencies]
bitflags = "2.4.0"
hashbrown = "0.14.0"

View file

@ -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();

View file

@ -13,10 +13,12 @@ mod consts {
}
pub use consts::*;
use hashbrown::HashMap;
pub struct Memory {
memory: *mut u8,
memory_size: u64,
tlb: HashMap<u64, *mut u8>,
}
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<const N: usize>(&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<const N: usize>(&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;
}

View file

@ -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,
}

View file

@ -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!(),
}
}

View file

@ -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 {