use super::{Cpu, Wide, high_byte, low_byte};
use crate::Z80nCommand;
use crate::mcode::IndexState;
use std::prelude::rust_2024::*;
mod blocks;
mod bus;
mod flags;
mod instructions;
mod interrupts;
mod registers;
mod z80n;
fn loaded() -> Cpu {
let mut cpu = Cpu::new();
let registers = cpu.registers_mut();
registers.af = 0xA1F2;
registers.bc = 0xB0C0;
registers.de = 0xD0E0;
registers.hl = 0x4050;
registers.ix = 0x1122;
registers.iy = 0x3344;
registers.sp = 0x8090;
registers.pc = 0x1234;
cpu.data_latch = 0x5A;
cpu
}
struct Ram {
bytes: Box<[u8; 0x10000]>,
ports: Box<[u8; 0x10000]>,
written: Vec<(u16, u8)>,
seen: Vec<crate::BusRequest>,
commands: Vec<(crate::Z80nCommand, u16)>,
returns: usize,
}
impl Ram {
fn with(program: &[u8]) -> Self {
let mut bytes = vec![0u8; 0x10000].into_boxed_slice();
bytes[..program.len()].copy_from_slice(program);
Self {
bytes: bytes.try_into().unwrap(),
ports: vec![0xFF; 0x10000].into_boxed_slice().try_into().unwrap(),
written: Vec::new(),
seen: Vec::new(),
commands: Vec::new(),
returns: 0,
}
}
}
impl crate::Host for Ram {
fn read(&mut self, address: u16, _at: u32) -> u8 {
self.bytes[address as usize]
}
fn write(&mut self, address: u16, value: u8, _at: u32) {
self.bytes[address as usize] = value;
self.written.push((address, value));
}
fn input(&mut self, port: u16, _at: u32) -> u8 {
self.ports[port as usize]
}
fn output(&mut self, port: u16, value: u8, _at: u32) {
self.ports[port as usize] = value;
}
fn z80n_command(&mut self, command: crate::Z80nCommand, data: u16) {
self.commands.push((command, data));
}
fn return_from_interrupt(&mut self) {
self.returns += 1;
}
fn bus_edge(&mut self, request: &crate::BusRequest) {
if self.seen.last() != Some(request) {
self.seen.push(*request);
}
}
}
fn run(program: &[u8], instructions: usize) -> (Cpu, Ram, u32) {
run_from(program, |_| {}, instructions)
}
fn run_from(program: &[u8], setup: impl FnOnce(&mut Cpu), instructions: usize) -> (Cpu, Ram, u32) {
let mut cpu = Cpu::new();
cpu.reset();
setup(&mut cpu);
let mut ram = Ram::with(program);
let mut total = 0;
for _ in 0..instructions {
total += cpu.step_by_edges(&mut ram);
}
(cpu, ram, total)
}
struct Stackless {
bytes: Box<[u8; 0x10000]>,
captured: Option<u16>,
taking: Option<Z80nCommand>,
supplying: Option<Z80nCommand>,
writes: usize,
reads_of_the_stack: usize,
}
impl Stackless {
fn new(program: &[u8]) -> Self {
let mut bytes = vec![0u8; 0x10000].into_boxed_slice();
bytes[..program.len()].copy_from_slice(program);
bytes[0x0066] = 0xED;
bytes[0x0067] = 0x45;
Self {
bytes: bytes.try_into().unwrap(),
captured: None,
taking: None,
supplying: None,
writes: 0,
reads_of_the_stack: 0,
}
}
}
impl crate::Host for Stackless {
fn read(&mut self, address: u16, _at: u32) -> u8 {
match self.supplying.take() {
Some(Z80nCommand::ReturnFromNmiLow) => {
self.reads_of_the_stack += 1;
low_byte(self.captured.unwrap_or_default())
}
Some(Z80nCommand::ReturnFromNmiHigh) => {
self.reads_of_the_stack += 1;
let value = high_byte(self.captured.unwrap_or_default());
self.captured = None;
value
}
_ => self.bytes[address as usize],
}
}
fn write(&mut self, address: u16, value: u8, _at: u32) {
match self.taking.take() {
Some(Z80nCommand::NmiAcknowledgeHigh) => {
self.captured = Some(u16::from(value) << 8);
}
Some(Z80nCommand::NmiAcknowledgeLow) => {
self.captured = Some(self.captured.unwrap_or_default() | u16::from(value));
}
_ => {
self.bytes[address as usize] = value;
self.writes += 1;
}
}
}
fn input(&mut self, _port: u16, _at: u32) -> u8 {
0xFF
}
fn output(&mut self, _port: u16, _value: u8, _at: u32) {}
fn z80n_command(&mut self, command: Z80nCommand, _data: u16) {
match command {
Z80nCommand::NmiAcknowledgeHigh | Z80nCommand::NmiAcknowledgeLow => {
self.taking = Some(command);
}
Z80nCommand::ReturnFromNmiLow | Z80nCommand::ReturnFromNmiHigh
if self.captured.is_some() =>
{
self.supplying = Some(command);
}
_ => {}
}
}
}
fn take_a_non_maskable_interrupt<H: crate::Host>(cpu: &mut Cpu, host: &mut H) -> u32 {
cpu.request_nmi();
let mut t_states = cpu.step_by_edges(host);
t_states += cpu.step_by_edges(host);
t_states
}
fn extended(program: &[u8], setup: impl FnOnce(&mut Cpu)) -> (Cpu, u32) {
let mut cpu = Cpu::new();
cpu.reset();
cpu.set_z80n_enabled(true);
setup(&mut cpu);
let mut ram = Ram::with(program);
let t = cpu.step_by_edges(&mut ram);
(cpu, t)
}
fn extended_block(program: &[u8], setup: impl FnOnce(&mut Cpu), steps: usize) -> (Cpu, Ram, u32) {
let mut cpu = Cpu::new();
cpu.reset();
cpu.set_z80n_enabled(true);
setup(&mut cpu);
let mut ram = Ram::with(program);
let mut total = 0;
for _ in 0..steps {
total += cpu.step_by_edges(&mut ram);
}
(cpu, ram, total)
}
fn pattern(opcode: u8) -> Vec<u8> {
let mut program = vec![0xED, opcode, 0x76];
program.resize(0x40, 0);
program[0x30] = 0x11;
program[0x31] = 0x22;
program
}
fn loaded_extended(opcode: u8, operands: &[u8]) -> (Cpu, Ram, u32) {
let mut program = vec![0xED, opcode];
program.extend_from_slice(operands);
program.resize(0x80, 0);
program[0x30] = 0x11;
program[0x31] = 0x22;
let mut cpu = Cpu::new();
cpu.reset();
cpu.set_z80n_enabled(true);
{
let registers = cpu.registers_mut();
registers.af = 0x0A5A;
registers.bc = 0x0401;
registers.de = 0x0038;
registers.hl = 0x0030;
registers.sp = 0x0100;
}
let mut ram = Ram::with(&program);
let t = cpu.step_by_edges(&mut ram);
(cpu, ram, t)
}