mirror of
https://github.com/transistorfet/moa.git
synced 2024-11-24 23:32:46 +00:00
Added IM, IFF1, and IFF2 checking to Z80 tests, and fixed issues with Z80 impl
This commit is contained in:
parent
e61e0cfe8f
commit
f3d1fd0ae2
@ -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"),
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
4
todo.txt
4
todo.txt
@ -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?
|
||||||
|
Loading…
Reference in New Issue
Block a user