Added IM, IFF1, and IFF2 checking to Z80 tests, and fixed issues with Z80 impl

This commit is contained in:
transistor 2023-05-13 19:41:20 -07:00
parent e61e0cfe8f
commit f3d1fd0ae2
7 changed files with 70 additions and 21 deletions

View File

@ -461,7 +461,7 @@ impl Z80Decoder {
6 => { 6 => {
match get_ins_y(ins) & 0x03 { match get_ins_y(ins) & 0x03 {
0 => Ok(Instruction::IM(InterruptMode::Mode0)), 0 => Ok(Instruction::IM(InterruptMode::Mode0)),
1 => Ok(Instruction::IM(InterruptMode::Mode01)), 1 => Ok(Instruction::IM(InterruptMode::Mode0)),
2 => Ok(Instruction::IM(InterruptMode::Mode1)), 2 => Ok(Instruction::IM(InterruptMode::Mode1)),
3 => Ok(Instruction::IM(InterruptMode::Mode2)), 3 => Ok(Instruction::IM(InterruptMode::Mode2)),
_ => panic!("InternalError: impossible value"), _ => panic!("InternalError: impossible value"),

View File

@ -211,7 +211,8 @@ impl Z80 {
self.set_target_value(target, result)?; self.set_target_value(target, result)?;
}, },
Instruction::DI => { Instruction::DI => {
self.state.interrupts_enabled = false; self.state.iff1 = false;
self.state.iff2 = false;
}, },
Instruction::DJNZ(offset) => { Instruction::DJNZ(offset) => {
let value = self.get_register_value(Register::B); let value = self.get_register_value(Register::B);
@ -223,7 +224,8 @@ impl Z80 {
} }
}, },
Instruction::EI => { Instruction::EI => {
self.state.interrupts_enabled = true; self.state.iff1 = true;
self.state.iff2 = true;
}, },
Instruction::EXX => { Instruction::EXX => {
for i in 0..6 { for i in 0..6 {
@ -256,7 +258,7 @@ impl Z80 {
self.state.pc -= 1; self.state.pc -= 1;
}, },
Instruction::IM(mode) => { Instruction::IM(mode) => {
self.state.interrupt_mode = mode; self.state.im = mode;
}, },
Instruction::INC16(regpair) => { Instruction::INC16(regpair) => {
let value = self.get_register_pair_value(regpair); let value = self.get_register_pair_value(regpair);
@ -335,6 +337,11 @@ impl Z80 {
Direction::FromAcc => { *addr = self.state.reg[Register::A as usize]; }, Direction::FromAcc => { *addr = self.state.reg[Register::A as usize]; },
Direction::ToAcc => { self.state.reg[Register::A as usize] = *addr; }, Direction::ToAcc => { self.state.reg[Register::A as usize] = *addr; },
} }
let value = self.state.reg[Register::A as usize];
self.set_numeric_flags(value as u16, Size::Byte);
self.set_flag(Flags::Parity, self.state.iff2);
self.set_flag(Flags::AddSubtract, false);
self.set_flag(Flags::HalfCarry, false);
} }
Instruction::LDD | Instruction::LDDR | Instruction::LDI | Instruction::LDIR => { Instruction::LDD | Instruction::LDDR | Instruction::LDI | Instruction::LDIR => {
let diff = if self.decoder.instruction == Instruction::LDI || self.decoder.instruction == Instruction::LDIR { let diff = if self.decoder.instruction == Instruction::LDI || self.decoder.instruction == Instruction::LDIR {
@ -416,9 +423,11 @@ impl Z80 {
}, },
Instruction::RETI => { Instruction::RETI => {
self.state.pc = self.pop_word()?; self.state.pc = self.pop_word()?;
self.state.iff1 = self.state.iff2;
}, },
Instruction::RETN => { Instruction::RETN => {
self.state.pc = self.pop_word()?; self.state.pc = self.pop_word()?;
self.state.iff1 = self.state.iff2;
}, },
Instruction::RETcc(cond) => { Instruction::RETcc(cond) => {
if self.get_current_condition(cond) { if self.get_current_condition(cond) {

View File

@ -5,4 +5,5 @@ pub mod execute;
pub mod debugger; pub mod debugger;
pub use self::state::{Z80, Z80Type}; pub use self::state::{Z80, Z80Type};
pub use self::state::InterruptMode;

View File

@ -22,9 +22,20 @@ pub enum Status {
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InterruptMode { pub enum InterruptMode {
Mode0, Mode0,
Mode01,
Mode1, Mode1,
Mode2, Mode2,
Unknown(u8),
}
impl From<u8> for InterruptMode {
fn from(im: u8) -> Self {
match im {
0 => InterruptMode::Mode0,
1 => InterruptMode::Mode1,
2 => InterruptMode::Mode2,
_ => InterruptMode::Unknown(im),
}
}
} }
#[repr(u8)] #[repr(u8)]
@ -58,8 +69,6 @@ pub enum Register {
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct Z80State { pub struct Z80State {
pub status: Status, pub status: Status,
pub interrupts_enabled: bool,
pub interrupt_mode: InterruptMode,
pub pc: u16, pub pc: u16,
pub sp: u16, pub sp: u16,
@ -71,14 +80,16 @@ pub struct Z80State {
pub i: u8, pub i: u8,
pub r: u8, pub r: u8,
pub iff1: bool,
pub iff2: bool,
pub im: InterruptMode,
} }
impl Default for Z80State { impl Default for Z80State {
fn default() -> Self { fn default() -> Self {
Self { Self {
status: Status::Init, status: Status::Init,
interrupts_enabled: false,
interrupt_mode: InterruptMode::Mode0,
pc: 0, pc: 0,
sp: 0, sp: 0,
@ -90,6 +101,10 @@ impl Default for Z80State {
i: 0, i: 0,
r: 0, r: 0,
iff1: false,
iff2: false,
im: InterruptMode::Mode0,
} }
} }
} }
@ -153,6 +168,9 @@ impl Z80 {
println!("D: {:#04x} E: {:#04x} D': {:#04x} E': {:#04x}", self.state.reg[Register::D as usize], self.state.reg[Register::E as usize], self.state.shadow_reg[Register::D as usize], self.state.shadow_reg[Register::E as usize]); println!("D: {:#04x} E: {:#04x} D': {:#04x} E': {:#04x}", self.state.reg[Register::D as usize], self.state.reg[Register::E as usize], self.state.shadow_reg[Register::D as usize], self.state.shadow_reg[Register::E as usize]);
println!("H: {:#04x} L: {:#04x} H': {:#04x} L': {:#04x}", self.state.reg[Register::H as usize], self.state.reg[Register::L as usize], self.state.shadow_reg[Register::H as usize], self.state.shadow_reg[Register::L as usize]); println!("H: {:#04x} L: {:#04x} H': {:#04x} L': {:#04x}", self.state.reg[Register::H as usize], self.state.reg[Register::L as usize], self.state.shadow_reg[Register::H as usize], self.state.shadow_reg[Register::L as usize]);
println!("I: {:#04x} R: {:#04x}", self.state.i, self.state.r);
println!("IM: {:?} IFF1: {:?} IFF2: {:?}", self.state.im, self.state.iff1, self.state.iff2);
println!("Current Instruction: {} {:?}", self.decoder.format_instruction_bytes(&mut self.port), self.decoder.instruction); println!("Current Instruction: {} {:?}", self.decoder.format_instruction_bytes(&mut self.port), self.decoder.instruction);
println!(); println!();
self.port.dump_memory(clock, self.state.sp as Address, 0x40); self.port.dump_memory(clock, self.state.sp as Address, 0x40);

View File

@ -1,4 +1,4 @@
Last run on 2023-05-13 at commit f0cbf5f2cac41f03df031d136296e95fa1968e31 Last run on 2023-05-13 at commit e61e0cfe8f79c42b3ec232ddb3c97e63dbb40864
00.json completed, all passed! 00.json completed, all passed!
01.json completed, all passed! 01.json completed, all passed!
@ -524,7 +524,7 @@ ed 43.json completed, all passed!
ed 44.json completed, all passed! ed 44.json completed, all passed!
ed 45.json completed, all passed! ed 45.json completed, all passed!
ed 46.json completed, all passed! ed 46.json completed, all passed!
ed 47.json completed, all passed! ed 47.json completed: 34 passed, 966 FAILED
ed 48.json completed, all passed! ed 48.json completed, all passed!
ed 49.json completed, all passed! ed 49.json completed, all passed!
ed 4a.json completed, all passed! ed 4a.json completed, all passed!
@ -532,7 +532,7 @@ ed 4b.json completed, all passed!
ed 4c.json completed, all passed! ed 4c.json completed, all passed!
ed 4d.json completed, all passed! ed 4d.json completed, all passed!
ed 4e.json completed, all passed! ed 4e.json completed, all passed!
ed 4f.json completed, all passed! ed 4f.json completed: 36 passed, 964 FAILED
ed 50.json completed, all passed! ed 50.json completed, all passed!
ed 51.json completed, all passed! ed 51.json completed, all passed!
ed 52.json completed, all passed! ed 52.json completed, all passed!
@ -540,7 +540,7 @@ ed 53.json completed, all passed!
ed 54.json completed, all passed! ed 54.json completed, all passed!
ed 55.json completed, all passed! ed 55.json completed, all passed!
ed 56.json completed, all passed! ed 56.json completed, all passed!
ed 57.json completed: 0 passed, 1000 FAILED ed 57.json completed, all passed!
ed 58.json completed, all passed! ed 58.json completed, all passed!
ed 59.json completed, all passed! ed 59.json completed, all passed!
ed 5a.json completed, all passed! ed 5a.json completed, all passed!
@ -643,5 +643,5 @@ fd f9.json completed, all passed!
fe.json completed, all passed! fe.json completed, all passed!
ff.json completed, all passed! ff.json completed, all passed!
passed: 624998, failed: 17002, total 97% passed: 624068, failed: 17932, total 97%
completed in 0m 30s completed in 0m 31s

View File

@ -15,7 +15,7 @@ use serde_derive::Deserialize;
use moa_core::{System, Error, MemoryBlock, Bus, BusPort, Frequency, Address, Addressable, Steppable, wrap_transmutable}; use moa_core::{System, Error, MemoryBlock, Bus, BusPort, Frequency, Address, Addressable, Steppable, wrap_transmutable};
use moa_z80::{Z80, Z80Type}; use moa_z80::{Z80, Z80Type, InterruptMode};
use moa_z80::state::Flags; use moa_z80::state::Flags;
use moa_z80::state::Status; use moa_z80::state::Status;
@ -71,8 +71,8 @@ struct TestState {
f: u8, f: u8,
h: u8, h: u8,
l: u8, l: u8,
//i: u8, i: u8,
//r: u8, r: u8,
//ei: u8, //ei: u8,
//wz: u8, //wz: u8,
ix: u16, ix: u16,
@ -81,11 +81,11 @@ struct TestState {
bc_: u16, bc_: u16,
de_: u16, de_: u16,
hl_: u16, hl_: u16,
//im: u8, im: u8,
//p: u8, //p: u8,
//q: u8, //q: u8,
//iff1: u8, iff1: u8,
//iff2: u8, iff2: u8,
ram: Vec<(u16, u8)>, ram: Vec<(u16, u8)>,
} }
@ -119,6 +119,8 @@ impl TestState {
println!(" l: {:02x} l': {:02x}", self.l, self.hl_ & 0xff); println!(" l: {:02x} l': {:02x}", self.l, self.hl_ & 0xff);
println!("pc: {:04x} sp: {:04x}", self.pc, self.sp); println!("pc: {:04x} sp: {:04x}", self.pc, self.sp);
println!("ix: {:04x} iy: {:04x}", self.ix, self.iy); println!("ix: {:04x} iy: {:04x}", self.ix, self.iy);
println!(" i: {:02x} r: {:02x}", self.i, self.r);
println!("im: {:02x} iff1: {:02x} iff2: {:02x}", self.im, self.iff1, self.iff2);
println!("ram: "); println!("ram: ");
for (addr, byte) in self.ram.iter() { for (addr, byte) in self.ram.iter() {
@ -199,6 +201,11 @@ fn load_state(cpu: &mut Z80, system: &mut System, io_bus: Rc<RefCell<Bus>>, init
cpu.state.iy = initial.iy; cpu.state.iy = initial.iy;
cpu.state.sp = initial.sp; cpu.state.sp = initial.sp;
cpu.state.pc = initial.pc; cpu.state.pc = initial.pc;
cpu.state.i = initial.i;
cpu.state.r = initial.r;
cpu.state.im = initial.im.into();
cpu.state.iff1 = initial.iff1 != 0;
cpu.state.iff2 = initial.iff2 != 0;
// Load data bytes into memory // Load data bytes into memory
for (addr, byte) in initial.ram.iter() { for (addr, byte) in initial.ram.iter() {
@ -241,6 +248,16 @@ fn assert_state(cpu: &Z80, system: &System, io_bus: Rc<RefCell<Bus>>, expected:
assert_value(cpu.state.iy, expected.iy, "iy")?; assert_value(cpu.state.iy, expected.iy, "iy")?;
assert_value(cpu.state.sp, expected.sp, "sp")?; assert_value(cpu.state.sp, expected.sp, "sp")?;
assert_value(cpu.state.pc, expected.pc, "pc")?; assert_value(cpu.state.pc, expected.pc, "pc")?;
assert_value(cpu.state.i, expected.i, "i")?;
// TODO this isn't emulated yet, so it will cause all the tests to fail
//assert_value(cpu.state.r, expected.r, "r")?;
let expected_im: InterruptMode = expected.im.into();
if cpu.state.im != expected_im {
return Err(Error::assertion(&format!("{:?} != {:?}, im", cpu.state.im, expected_im)));
}
assert_value(cpu.state.iff1 as u8, expected.iff1, "iff1")?;
assert_value(cpu.state.iff2 as u8, expected.iff2, "iff2")?;
let addr_mask = cpu.port.address_mask(); let addr_mask = cpu.port.address_mask();

View File

@ -3,6 +3,10 @@
* you could have busport take a closure or something which translates the address, and returns an error that will be passed up if it occurs * you could have busport take a closure or something which translates the address, and returns an error that will be passed up if it occurs
in order to implement the correct behaviour for address exceptions in 68k, transparently in order to implement the correct behaviour for address exceptions in 68k, transparently
* go through Z80 and see if you can replace functions with From<>/Into
* go through flags on m68k and see if you can fix the remaining ones and/or clean up the implementation
* should you make Address a newtype and add From impls for each type of numeric, and add utils to wrap address at certain boundaries and such * should you make Address a newtype and add From impls for each type of numeric, and add utils to wrap address at certain boundaries and such
* should you make a means of storing different kinds of buses? * should you make a means of storing different kinds of buses?
* should you make buses hide their RcRefCell? * should you make buses hide their RcRefCell?