mirror of
https://git.sr.ht/~asya/copycat
synced 2024-11-25 08:08:42 -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:
parent
d095cd4055
commit
03055b819d
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
/target
|
/target
|
||||||
|
/roms
|
||||||
|
|
46
Cargo.lock
generated
46
Cargo.lock
generated
|
@ -2,15 +2,61 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
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]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.4.0"
|
version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "copycat"
|
name = "copycat"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"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"
|
||||||
|
|
|
@ -7,3 +7,4 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitflags = "2.4.0"
|
bitflags = "2.4.0"
|
||||||
|
hashbrown = "0.14.0"
|
||||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -4,12 +4,16 @@
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use copycat::memory::{Memory, MiB};
|
use copycat::memory::{Memory, KiB};
|
||||||
use processor::{Instruction, Processor};
|
use copycat::processor::{Instruction, Processor};
|
||||||
|
|
||||||
|
static BIOS_ROM: &[u8; 8 * KiB as usize] = include_bytes!("../roms/BIOS_IBM5150_24APR81_5700051_U33.BIN");
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut mem = Memory::new(1 * MiB);
|
let mut mem = Memory::new(64 * KiB);
|
||||||
mem.write(0xffff0, [0x90, 0x04, 0x69, 0xF4]);
|
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();
|
let mut cpu = Processor::default();
|
||||||
cpu.registers.dump();
|
cpu.registers.dump();
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,12 @@ mod consts {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use consts::*;
|
pub use consts::*;
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
pub struct Memory {
|
pub struct Memory {
|
||||||
memory: *mut u8,
|
memory: *mut u8,
|
||||||
memory_size: u64,
|
memory_size: u64,
|
||||||
|
tlb: HashMap<u64, *mut u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Memory {
|
impl Memory {
|
||||||
|
@ -26,20 +28,39 @@ impl Memory {
|
||||||
alloc(Layout::from_size_align(size.try_into().unwrap(), 1 * MiB as usize).expect("layout error"))
|
alloc(Layout::from_size_align(size.try_into().unwrap(), 1 * MiB as usize).expect("layout error"))
|
||||||
},
|
},
|
||||||
memory_size: size,
|
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] {
|
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 {
|
if address >= self.memory_size {
|
||||||
return [0; N];
|
return [0; N];
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
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]) {
|
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 {
|
if address >= self.memory_size {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ impl Instruction {
|
||||||
let mut opcode = memory.read_u8(address);
|
let mut opcode = memory.read_u8(address);
|
||||||
let mut size: u8 = 1;
|
let mut size: u8 = 1;
|
||||||
let mut segment_override = SegmentOverride::None;
|
let mut segment_override = SegmentOverride::None;
|
||||||
|
let mut modrm = None;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// FIXME: handle lock and rep
|
// FIXME: handle lock and rep
|
||||||
|
@ -48,6 +49,12 @@ impl Instruction {
|
||||||
0x03 => (Mnemonic::Add, OperandFormat::Reg16, OperandFormat::RM16),
|
0x03 => (Mnemonic::Add, OperandFormat::Reg16, OperandFormat::RM16),
|
||||||
0x04 => (Mnemonic::Add, OperandFormat::AL, OperandFormat::Imm8),
|
0x04 => (Mnemonic::Add, OperandFormat::AL, OperandFormat::Imm8),
|
||||||
0x05 => (Mnemonic::Add, OperandFormat::AX, OperandFormat::Imm16),
|
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),
|
0x10 => (Mnemonic::Adc, OperandFormat::RM8, OperandFormat::Reg8),
|
||||||
0x11 => (Mnemonic::Adc, OperandFormat::RM16, OperandFormat::Reg16),
|
0x11 => (Mnemonic::Adc, OperandFormat::RM16, OperandFormat::Reg16),
|
||||||
0x12 => (Mnemonic::Adc, OperandFormat::Reg8, OperandFormat::RM8),
|
0x12 => (Mnemonic::Adc, OperandFormat::Reg8, OperandFormat::RM8),
|
||||||
|
@ -88,14 +95,79 @@ impl Instruction {
|
||||||
0x4D => (Mnemonic::Dec, OperandFormat::BP, OperandFormat::NoOperand),
|
0x4D => (Mnemonic::Dec, OperandFormat::BP, OperandFormat::NoOperand),
|
||||||
0x4E => (Mnemonic::Dec, OperandFormat::SI, OperandFormat::NoOperand),
|
0x4E => (Mnemonic::Dec, OperandFormat::SI, OperandFormat::NoOperand),
|
||||||
0x4F => (Mnemonic::Dec, OperandFormat::DI, 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),
|
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),
|
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),
|
_ => (Mnemonic::Invalid, OperandFormat::NoOperand, OperandFormat::NoOperand),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut modrm = None;
|
if modrm.is_none() &&
|
||||||
if matches!(op1ty, OperandFormat::RM8 | OperandFormat::RM16 | OperandFormat::Reg8 | OperandFormat::Reg16)
|
(matches!(op1ty, OperandFormat::RM8 | OperandFormat::RM16 | OperandFormat::Reg8 | OperandFormat::Reg16)
|
||||||
|| matches!(op2ty, 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));
|
modrm = ModRM::from_bits(memory.read_u8(address + size as u64));
|
||||||
size += 1;
|
size += 1;
|
||||||
|
@ -243,6 +315,13 @@ impl Instruction {
|
||||||
ModRM::REG_7 => OperandType::DI,
|
ModRM::REG_7 => OperandType::DI,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}, OperandSize::Word),
|
}, 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 => {
|
OperandFormat::Imm8 => {
|
||||||
let op = Operand(OperandType::Imm8(memory.read_u8(address + size as u64)), OperandSize::Byte);
|
let op = Operand(OperandType::Imm8(memory.read_u8(address + size as u64)), OperandSize::Byte);
|
||||||
size += 1;
|
size += 1;
|
||||||
|
@ -253,7 +332,21 @@ impl Instruction {
|
||||||
size += 2;
|
size += 2;
|
||||||
op
|
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::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::AX => Operand(OperandType::AX, OperandSize::Word),
|
||||||
OperandFormat::CX => Operand(OperandType::CX, OperandSize::Word),
|
OperandFormat::CX => Operand(OperandType::CX, OperandSize::Word),
|
||||||
OperandFormat::DX => Operand(OperandType::DX, OperandSize::Word),
|
OperandFormat::DX => Operand(OperandType::DX, OperandSize::Word),
|
||||||
|
@ -294,11 +387,40 @@ pub enum Mnemonic {
|
||||||
Invalid,
|
Invalid,
|
||||||
Adc,
|
Adc,
|
||||||
Add,
|
Add,
|
||||||
|
Clc,
|
||||||
|
Cld,
|
||||||
|
Cli,
|
||||||
Dec,
|
Dec,
|
||||||
Hlt,
|
Hlt,
|
||||||
Inc,
|
Inc,
|
||||||
|
Ja,
|
||||||
|
Jc,
|
||||||
|
Jg,
|
||||||
|
Jl,
|
||||||
|
Jmp,
|
||||||
|
Jna,
|
||||||
|
Jnc,
|
||||||
|
Jng,
|
||||||
|
Jnl,
|
||||||
|
Jno,
|
||||||
|
Jnp,
|
||||||
|
Jns,
|
||||||
|
Jnz,
|
||||||
|
Jo,
|
||||||
|
Jp,
|
||||||
|
Js,
|
||||||
|
Jz,
|
||||||
|
Lahf,
|
||||||
|
Mov,
|
||||||
Nop,
|
Nop,
|
||||||
|
Or,
|
||||||
|
Sahf,
|
||||||
Sbb,
|
Sbb,
|
||||||
|
Shl,
|
||||||
|
Shr,
|
||||||
|
Stc,
|
||||||
|
Std,
|
||||||
|
Sti,
|
||||||
Sub,
|
Sub,
|
||||||
Xor,
|
Xor,
|
||||||
}
|
}
|
||||||
|
@ -310,9 +432,19 @@ enum OperandFormat {
|
||||||
RM16,
|
RM16,
|
||||||
Reg8,
|
Reg8,
|
||||||
Reg16,
|
Reg16,
|
||||||
|
Sreg,
|
||||||
Imm8,
|
Imm8,
|
||||||
Imm16,
|
Imm16,
|
||||||
|
Ptr16_16,
|
||||||
|
One,
|
||||||
AL,
|
AL,
|
||||||
|
CL,
|
||||||
|
DL,
|
||||||
|
BL,
|
||||||
|
AH,
|
||||||
|
CH,
|
||||||
|
DH,
|
||||||
|
BH,
|
||||||
AX,
|
AX,
|
||||||
CX,
|
CX,
|
||||||
DX,
|
DX,
|
||||||
|
@ -338,28 +470,28 @@ pub enum OperandType {
|
||||||
NoOperand,
|
NoOperand,
|
||||||
Imm8(u8),
|
Imm8(u8),
|
||||||
Imm16(u16),
|
Imm16(u16),
|
||||||
|
Ptr16_16(u16, u16),
|
||||||
Indirect(AddressingMode),
|
Indirect(AddressingMode),
|
||||||
AL,
|
AL,
|
||||||
AH,
|
|
||||||
AX,
|
|
||||||
BL,
|
|
||||||
BH,
|
|
||||||
BX,
|
|
||||||
CL,
|
CL,
|
||||||
CH,
|
|
||||||
CX,
|
|
||||||
DL,
|
DL,
|
||||||
|
BL,
|
||||||
|
AH,
|
||||||
|
CH,
|
||||||
DH,
|
DH,
|
||||||
|
BH,
|
||||||
|
AX,
|
||||||
|
CX,
|
||||||
DX,
|
DX,
|
||||||
|
BX,
|
||||||
|
SP,
|
||||||
|
BP,
|
||||||
SI,
|
SI,
|
||||||
DI,
|
DI,
|
||||||
BP,
|
|
||||||
SP,
|
|
||||||
IP,
|
|
||||||
CS,
|
|
||||||
DS,
|
|
||||||
ES,
|
ES,
|
||||||
|
CS,
|
||||||
SS,
|
SS,
|
||||||
|
DS,
|
||||||
FLAGS,
|
FLAGS,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,10 @@ pub struct Processor {
|
||||||
impl Processor {
|
impl Processor {
|
||||||
pub fn exec(&mut self, memory: &mut Memory, instruction: &Instruction) {
|
pub fn exec(&mut self, memory: &mut Memory, instruction: &Instruction) {
|
||||||
use Mnemonic::*;
|
use Mnemonic::*;
|
||||||
match (instruction.mnemonic, instruction.op1.1, instruction.op2.1) {
|
match (instruction.mnemonic, instruction.op1, instruction.op2) {
|
||||||
(Add, OperandSize::Byte, _) => {
|
(Add, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::Byte)) => {
|
||||||
let dst = self.operand8(memory, instruction.op1.0, instruction.segment_override);
|
let dst = self.operand8(memory, op1, instruction.segment_override);
|
||||||
let src = self.operand8(memory, instruction.op2.0, instruction.segment_override);
|
let src = self.operand8(memory, op2, instruction.segment_override);
|
||||||
let (value, carry) = dst.overflowing_add(src);
|
let (value, carry) = dst.overflowing_add(src);
|
||||||
|
|
||||||
// FIXME: AF, PF, OF
|
// FIXME: AF, PF, OF
|
||||||
|
@ -32,11 +32,11 @@ impl Processor {
|
||||||
self.registers.set_sf(value >> 7 != 0);
|
self.registers.set_sf(value >> 7 != 0);
|
||||||
self.registers.set_zf(value == 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, _) => {
|
(Add, Operand(op1, OperandSize::Word), Operand(op2, OperandSize::Word)) => {
|
||||||
let dst = self.operand16(memory, instruction.op1.0, instruction.segment_override);
|
let dst = self.operand16(memory, op1, instruction.segment_override);
|
||||||
let src = self.operand16(memory, instruction.op2.0, instruction.segment_override);
|
let src = self.operand16(memory, op2, instruction.segment_override);
|
||||||
let (value, carry) = dst.overflowing_add(src);
|
let (value, carry) = dst.overflowing_add(src);
|
||||||
|
|
||||||
// FIXME: AF, PF, OF
|
// FIXME: AF, PF, OF
|
||||||
|
@ -44,11 +44,37 @@ impl Processor {
|
||||||
self.registers.set_sf(value >> 15 != 0);
|
self.registers.set_sf(value >> 15 != 0);
|
||||||
self.registers.set_zf(value == 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, _) => {
|
(Or, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::Byte)) => {
|
||||||
let dst = self.operand8(memory, instruction.op1.0, instruction.segment_override);
|
let dst = self.operand8(memory, op1, instruction.segment_override);
|
||||||
let src = self.operand8(memory, instruction.op2.0, 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());
|
let (value, carry) = dst.carrying_add(src, self.registers.cf());
|
||||||
|
|
||||||
// FIXME: AF, PF, OF
|
// FIXME: AF, PF, OF
|
||||||
|
@ -56,11 +82,11 @@ impl Processor {
|
||||||
self.registers.set_sf(value >> 7 != 0);
|
self.registers.set_sf(value >> 7 != 0);
|
||||||
self.registers.set_zf(value == 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, _) => {
|
(Adc, Operand(op1, OperandSize::Word), Operand(op2, OperandSize::Word)) => {
|
||||||
let dst = self.operand16(memory, instruction.op1.0, instruction.segment_override);
|
let dst = self.operand16(memory, op1, instruction.segment_override);
|
||||||
let src = self.operand16(memory, instruction.op2.0, instruction.segment_override);
|
let src = self.operand16(memory, op2, instruction.segment_override);
|
||||||
let (value, carry) = dst.carrying_add(src, self.registers.cf());
|
let (value, carry) = dst.carrying_add(src, self.registers.cf());
|
||||||
|
|
||||||
// FIXME: AF, PF, OF
|
// FIXME: AF, PF, OF
|
||||||
|
@ -68,11 +94,11 @@ impl Processor {
|
||||||
self.registers.set_sf(value >> 15 != 0);
|
self.registers.set_sf(value >> 15 != 0);
|
||||||
self.registers.set_zf(value == 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, _) => {
|
(Sbb, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::Byte)) => {
|
||||||
let dst = self.operand8(memory, instruction.op1.0, instruction.segment_override);
|
let dst = self.operand8(memory, op1, instruction.segment_override);
|
||||||
let src = self.operand8(memory, instruction.op2.0, instruction.segment_override);
|
let src = self.operand8(memory, op2, instruction.segment_override);
|
||||||
let (value, borrow) = dst.borrowing_sub(src, self.registers.cf());
|
let (value, borrow) = dst.borrowing_sub(src, self.registers.cf());
|
||||||
|
|
||||||
// FIXME: AF, PF, OF
|
// FIXME: AF, PF, OF
|
||||||
|
@ -80,11 +106,11 @@ impl Processor {
|
||||||
self.registers.set_sf(value >> 7 != 0);
|
self.registers.set_sf(value >> 7 != 0);
|
||||||
self.registers.set_zf(value == 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, _) => {
|
(Sbb, Operand(op1, OperandSize::Word), Operand(op2, OperandSize::Word)) => {
|
||||||
let dst = self.operand16(memory, instruction.op1.0, instruction.segment_override);
|
let dst = self.operand16(memory, op1, instruction.segment_override);
|
||||||
let src = self.operand16(memory, instruction.op2.0, instruction.segment_override);
|
let src = self.operand16(memory, op2, instruction.segment_override);
|
||||||
let (value, borrow) = dst.borrowing_sub(src, self.registers.cf());
|
let (value, borrow) = dst.borrowing_sub(src, self.registers.cf());
|
||||||
|
|
||||||
// FIXME: AF, PF, OF
|
// FIXME: AF, PF, OF
|
||||||
|
@ -92,11 +118,11 @@ impl Processor {
|
||||||
self.registers.set_sf(value >> 15 != 0);
|
self.registers.set_sf(value >> 15 != 0);
|
||||||
self.registers.set_zf(value == 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, _) => {
|
(Sub, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::Byte)) => {
|
||||||
let dst = self.operand8(memory, instruction.op1.0, instruction.segment_override);
|
let dst = self.operand8(memory, op1, instruction.segment_override);
|
||||||
let src = self.operand8(memory, instruction.op2.0, instruction.segment_override);
|
let src = self.operand8(memory, op2, instruction.segment_override);
|
||||||
let (value, borrow) = dst.overflowing_sub(src);
|
let (value, borrow) = dst.overflowing_sub(src);
|
||||||
|
|
||||||
// FIXME: AF, PF, OF
|
// FIXME: AF, PF, OF
|
||||||
|
@ -104,11 +130,11 @@ impl Processor {
|
||||||
self.registers.set_sf(value >> 7 != 0);
|
self.registers.set_sf(value >> 7 != 0);
|
||||||
self.registers.set_zf(value == 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, _) => {
|
(Sub, Operand(op1, OperandSize::Word), Operand(op2, OperandSize::Word)) => {
|
||||||
let dst = self.operand16(memory, instruction.op1.0, instruction.segment_override);
|
let dst = self.operand16(memory, op1, instruction.segment_override);
|
||||||
let src = self.operand16(memory, instruction.op2.0, instruction.segment_override);
|
let src = self.operand16(memory, op2, instruction.segment_override);
|
||||||
let (value, borrow) = dst.overflowing_sub(src);
|
let (value, borrow) = dst.overflowing_sub(src);
|
||||||
|
|
||||||
// FIXME: AF, PF, OF
|
// FIXME: AF, PF, OF
|
||||||
|
@ -116,10 +142,36 @@ impl Processor {
|
||||||
self.registers.set_sf(value >> 15 != 0);
|
self.registers.set_sf(value >> 15 != 0);
|
||||||
self.registers.set_zf(value == 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, _) => {
|
(Xor, Operand(op1, OperandSize::Byte), Operand(op2, OperandSize::Byte)) => {
|
||||||
let dst = self.operand16(memory, instruction.op1.0, instruction.segment_override);
|
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);
|
let value = dst.wrapping_add(1);
|
||||||
|
|
||||||
// FIXME: AF, PF, OF
|
// FIXME: AF, PF, OF
|
||||||
|
@ -127,10 +179,10 @@ impl Processor {
|
||||||
self.registers.set_sf(value >> 15 != 0);
|
self.registers.set_sf(value >> 15 != 0);
|
||||||
self.registers.set_zf(value == 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, _) => {
|
(Dec, Operand(op1, OperandSize::Word), _) => {
|
||||||
let dst = self.operand16(memory, instruction.op1.0, instruction.segment_override);
|
let dst = self.operand16(memory, op1, instruction.segment_override);
|
||||||
let value = dst.wrapping_sub(1);
|
let value = dst.wrapping_sub(1);
|
||||||
|
|
||||||
// FIXME: AF, PF, OF
|
// FIXME: AF, PF, OF
|
||||||
|
@ -138,10 +190,117 @@ impl Processor {
|
||||||
self.registers.set_sf(value >> 15 != 0);
|
self.registers.set_sf(value >> 15 != 0);
|
||||||
self.registers.set_zf(value == 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, _, _) => {},
|
(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,
|
(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"),
|
_ => unimplemented!("instruction {instruction:?} not implemented"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,6 +348,10 @@ impl Processor {
|
||||||
OperandType::BP => self.registers.bp(),
|
OperandType::BP => self.registers.bp(),
|
||||||
OperandType::SI => self.registers.si(),
|
OperandType::SI => self.registers.si(),
|
||||||
OperandType::DI => self.registers.di(),
|
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!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,6 +367,10 @@ impl Processor {
|
||||||
OperandType::BP => self.registers.set_bp(value),
|
OperandType::BP => self.registers.set_bp(value),
|
||||||
OperandType::SI => self.registers.set_si(value),
|
OperandType::SI => self.registers.set_si(value),
|
||||||
OperandType::DI => self.registers.set_di(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!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,7 +205,9 @@ impl Registers {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_flags(&mut self, value: u16) {
|
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 {
|
pub fn cf(&self) -> bool {
|
||||||
|
@ -315,32 +317,6 @@ impl Registers {
|
||||||
self.flags &= !(1 << 11);
|
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 {
|
impl fmt::Display for Registers {
|
||||||
|
|
Loading…
Reference in a new issue