rustzx-z80 0.15.0

Z80 CPU emulator library
Documentation
use crate::{
    opcode::{Opcode, Prefix},
    CodegenMemorySpace,
};

/// Z80 processor System bus
/// Implement it for communication with CPU.
pub trait Z80Bus {
    /// Required method for reading byte without waiting
    /// pass `self` as mut, because method can change state of
    /// bus or something
    fn read_internal(&mut self, addr: u16) -> u8;
    /// Required method for write byte to bus without waiting
    fn write_internal(&mut self, addr: u16, data: u8);
    /// Wait some clocks
    fn wait_mreq(&mut self, addr: u16, clk: usize);
    /// Wait while mreq is not active (can be different from
    /// active mreq contention as it works in ZX Spectrum 2+/3)
    fn wait_no_mreq(&mut self, addr: u16, clk: usize);
    /// Internal wait, avoiding contentions
    fn wait_internal(&mut self, clk: usize);
    /// Any single clock (t-state) can cause contention on ULA
    /// or any other chipm which not detects MREQ signal
    fn wait_loop(&mut self, addr: u16, clk: usize) {
        for _ in 0..clk {
            self.wait_no_mreq(addr, 1);
        }
    }
    // Normal read from memory, contention may be applied
    fn read(&mut self, addr: u16, clk: usize) -> u8 {
        self.wait_mreq(addr, clk);
        self.read_internal(addr)
    }
    // Normal write to memory, contention may be applied
    fn write(&mut self, addr: u16, value: u8, clk: usize) {
        self.wait_mreq(addr, clk);
        self.write_internal(addr, value)
    }
    // Method for reading from io port.
    fn read_io(&mut self, port: u16) -> u8;
    // Method for writing to io port.
    fn write_io(&mut self, port: u16, data: u8);
    /// Provided metod to write word, LSB first (clk - clocks per byte)
    fn write_word(&mut self, addr: u16, data: u16, clk: usize) {
        let [l, h] = data.to_le_bytes();
        self.write(addr, l, clk);
        self.write(addr.wrapping_add(1), h, clk);
    }
    /// Provided method to read word (clk - clocks per byte)
    fn read_word(&mut self, addr: u16, clk: usize) -> u16 {
        let l = self.read(addr, clk);
        let h = self.read(addr.wrapping_add(1), clk);
        u16::from_le_bytes([l, h])
    }
    /// Reads value from bus during interrupt.
    /// mutable bacause on interrupt read some internal system attributes may be changed
    fn read_interrupt(&mut self) -> u8;
    /// Method, invoked by Z80 in case of RETI instruction. Default implementation is empty
    fn reti(&mut self);
    /// Method, invoked by Z80 in case of HALT line change
    fn halt(&mut self, halted: bool);
    /// Checks int signal
    fn int_active(&self) -> bool;
    /// Checks nmi signal
    fn nmi_active(&self) -> bool;
    /// invokes breakpoints check on bus device
    fn pc_callback(&mut self, addr: u16);
    fn process_unknown_opcode(&mut self, _prefix: Prefix, _opcode: Opcode) {}
}

impl<T> CodegenMemorySpace for T
where
    T: Z80Bus,
{
    fn write_byte(&mut self, addr: u16, byte: u8) {
        // write, but does not perform any processing (zero clock cycles)
        self.write(addr, byte, 0);
    }
}