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 => {
|
||||
match get_ins_y(ins) & 0x03 {
|
||||
0 => Ok(Instruction::IM(InterruptMode::Mode0)),
|
||||
1 => Ok(Instruction::IM(InterruptMode::Mode01)),
|
||||
1 => Ok(Instruction::IM(InterruptMode::Mode0)),
|
||||
2 => Ok(Instruction::IM(InterruptMode::Mode1)),
|
||||
3 => Ok(Instruction::IM(InterruptMode::Mode2)),
|
||||
_ => panic!("InternalError: impossible value"),
|
||||
|
@ -211,7 +211,8 @@ impl Z80 {
|
||||
self.set_target_value(target, result)?;
|
||||
},
|
||||
Instruction::DI => {
|
||||
self.state.interrupts_enabled = false;
|
||||
self.state.iff1 = false;
|
||||
self.state.iff2 = false;
|
||||
},
|
||||
Instruction::DJNZ(offset) => {
|
||||
let value = self.get_register_value(Register::B);
|
||||
@ -223,7 +224,8 @@ impl Z80 {
|
||||
}
|
||||
},
|
||||
Instruction::EI => {
|
||||
self.state.interrupts_enabled = true;
|
||||
self.state.iff1 = true;
|
||||
self.state.iff2 = true;
|
||||
},
|
||||
Instruction::EXX => {
|
||||
for i in 0..6 {
|
||||
@ -256,7 +258,7 @@ impl Z80 {
|
||||
self.state.pc -= 1;
|
||||
},
|
||||
Instruction::IM(mode) => {
|
||||
self.state.interrupt_mode = mode;
|
||||
self.state.im = mode;
|
||||
},
|
||||
Instruction::INC16(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::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 => {
|
||||
let diff = if self.decoder.instruction == Instruction::LDI || self.decoder.instruction == Instruction::LDIR {
|
||||
@ -416,9 +423,11 @@ impl Z80 {
|
||||
},
|
||||
Instruction::RETI => {
|
||||
self.state.pc = self.pop_word()?;
|
||||
self.state.iff1 = self.state.iff2;
|
||||
},
|
||||
Instruction::RETN => {
|
||||
self.state.pc = self.pop_word()?;
|
||||
self.state.iff1 = self.state.iff2;
|
||||
},
|
||||
Instruction::RETcc(cond) => {
|
||||
if self.get_current_condition(cond) {
|
||||
|
@ -5,4 +5,5 @@ pub mod execute;
|
||||
pub mod debugger;
|
||||
|
||||
pub use self::state::{Z80, Z80Type};
|
||||
pub use self::state::InterruptMode;
|
||||
|
||||
|
@ -22,9 +22,20 @@ pub enum Status {
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum InterruptMode {
|
||||
Mode0,
|
||||
Mode01,
|
||||
Mode1,
|
||||
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)]
|
||||
@ -58,8 +69,6 @@ pub enum Register {
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Z80State {
|
||||
pub status: Status,
|
||||
pub interrupts_enabled: bool,
|
||||
pub interrupt_mode: InterruptMode,
|
||||
|
||||
pub pc: u16,
|
||||
pub sp: u16,
|
||||
@ -71,14 +80,16 @@ pub struct Z80State {
|
||||
|
||||
pub i: u8,
|
||||
pub r: u8,
|
||||
|
||||
pub iff1: bool,
|
||||
pub iff2: bool,
|
||||
pub im: InterruptMode,
|
||||
}
|
||||
|
||||
impl Default for Z80State {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
status: Status::Init,
|
||||
interrupts_enabled: false,
|
||||
interrupt_mode: InterruptMode::Mode0,
|
||||
|
||||
pc: 0,
|
||||
sp: 0,
|
||||
@ -90,6 +101,10 @@ impl Default for Z80State {
|
||||
|
||||
i: 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!("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!();
|
||||
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!
|
||||
01.json completed, all passed!
|
||||
@ -524,7 +524,7 @@ ed 43.json completed, all passed!
|
||||
ed 44.json completed, all passed!
|
||||
ed 45.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 49.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 4d.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 51.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 55.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 59.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!
|
||||
ff.json completed, all passed!
|
||||
|
||||
passed: 624998, failed: 17002, total 97%
|
||||
completed in 0m 30s
|
||||
passed: 624068, failed: 17932, total 97%
|
||||
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_z80::{Z80, Z80Type};
|
||||
use moa_z80::{Z80, Z80Type, InterruptMode};
|
||||
use moa_z80::state::Flags;
|
||||
use moa_z80::state::Status;
|
||||
|
||||
@ -71,8 +71,8 @@ struct TestState {
|
||||
f: u8,
|
||||
h: u8,
|
||||
l: u8,
|
||||
//i: u8,
|
||||
//r: u8,
|
||||
i: u8,
|
||||
r: u8,
|
||||
//ei: u8,
|
||||
//wz: u8,
|
||||
ix: u16,
|
||||
@ -81,11 +81,11 @@ struct TestState {
|
||||
bc_: u16,
|
||||
de_: u16,
|
||||
hl_: u16,
|
||||
//im: u8,
|
||||
im: u8,
|
||||
//p: u8,
|
||||
//q: u8,
|
||||
//iff1: u8,
|
||||
//iff2: u8,
|
||||
iff1: u8,
|
||||
iff2: u8,
|
||||
ram: Vec<(u16, u8)>,
|
||||
}
|
||||
|
||||
@ -119,6 +119,8 @@ impl TestState {
|
||||
println!(" l: {:02x} l': {:02x}", self.l, self.hl_ & 0xff);
|
||||
println!("pc: {:04x} sp: {:04x}", self.pc, self.sp);
|
||||
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: ");
|
||||
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.sp = initial.sp;
|
||||
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
|
||||
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.sp, expected.sp, "sp")?;
|
||||
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();
|
||||
|
||||
|
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
|
||||
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 a means of storing different kinds of buses?
|
||||
* should you make buses hide their RcRefCell?
|
||||
|
Loading…
Reference in New Issue
Block a user