moa/emulator/cpus/z80/tests/decode_tests.rs

72 lines
2.9 KiB
Rust
Raw Normal View History

2023-03-26 04:31:44 +00:00
use moa_core::{System, MemoryBlock, BusPort, Frequency, Address, Addressable, wrap_transmutable};
2023-03-26 04:31:44 +00:00
use moa_z80::{Z80, Z80Type};
use moa_z80::instructions::{Instruction, LoadTarget, Target, Register, RegisterPair, IndexRegister, IndexRegisterHalf};
2023-03-26 04:31:44 +00:00
fn init_decode_test() -> (Z80, System) {
let mut system = System::default();
// Insert basic initialization
let data = vec![0; 0x10000];
let mem = MemoryBlock::new(data);
system.add_addressable_device(0x0000, wrap_transmutable(mem)).unwrap();
// Initialize the CPU and make sure it's in the expected state
let mut cpu = Z80::new(Z80Type::Z80, Frequency::from_mhz(4), BusPort::new(0, 16, 8, system.bus.clone()), None);
2023-03-26 04:31:44 +00:00
cpu.init().unwrap();
(cpu, system)
}
fn load_memory(system: &System, data: &[u8]) {
for i in 0..data.len() {
system.get_bus().write_u8(system.clock, i as Address, data[i]).unwrap();
2023-03-26 04:31:44 +00:00
}
}
fn run_decode_test(data: &[u8]) -> Instruction {
let (mut cpu, system) = init_decode_test();
load_memory(&system, data);
cpu.decode_next().unwrap();
cpu.decoder.instruction
}
#[test]
fn run_all_decode_tests() {
let mut failures = vec![];
for (data, expected_instruction) in DECODE_TESTS {
let instruction = run_decode_test(data);
if instruction != *expected_instruction {
failures.push((data, instruction, expected_instruction));
}
}
let fails = failures.len();
for (data, instruction, expected_instruction) in failures {
println!("for {:?}\nexpected:\t{:?}\nreceived:\t{:?}\n", data, instruction, expected_instruction);
}
if fails > 0 {
panic!("{} decode tests failed", fails);
}
}
const DECODE_TESTS: &'static [(&[u8], Instruction)] = &[
(&[0x00], Instruction::NOP),
(&[0x01, 0x01, 0x02], Instruction::LD(LoadTarget::DirectRegWord(RegisterPair::BC), LoadTarget::ImmediateWord(0x0201))),
(&[0x02], Instruction::LD(LoadTarget::IndirectRegByte(RegisterPair::BC), LoadTarget::DirectRegByte(Register::A))),
(&[0x03], Instruction::INC16(RegisterPair::BC)),
(&[0x04], Instruction::INC8(Target::DirectReg(Register::B))),
(&[0x05], Instruction::DEC8(Target::DirectReg(Register::B))),
(&[0xDD, 0x09], Instruction::ADD16(RegisterPair::IX, RegisterPair::BC)),
(&[0xDD, 0x44], Instruction::LD(LoadTarget::DirectRegByte(Register::B), LoadTarget::DirectRegHalfByte(IndexRegisterHalf::IXH))),
(&[0xDD, 0x66, 0x12], Instruction::LD(LoadTarget::DirectRegByte(Register::H), LoadTarget::IndirectOffsetByte(IndexRegister::IX, 0x12))),
(&[0xDD, 0x6E, 0x12], Instruction::LD(LoadTarget::DirectRegByte(Register::L), LoadTarget::IndirectOffsetByte(IndexRegister::IX, 0x12))),
(&[0xDD, 0x84], Instruction::ADDa(Target::DirectRegHalf(IndexRegisterHalf::IXH))),
(&[0xDD, 0x85], Instruction::ADDa(Target::DirectRegHalf(IndexRegisterHalf::IXL))),
];