rustzx_z80/
bus.rs

1use crate::{
2    opcode::{Opcode, Prefix},
3    CodegenMemorySpace,
4};
5
6/// Z80 processor System bus
7/// Implement it for communication with CPU.
8pub trait Z80Bus {
9    /// Required method for reading byte without waiting
10    /// pass `self` as mut, because method can change state of
11    /// bus or something
12    fn read_internal(&mut self, addr: u16) -> u8;
13    /// Required method for write byte to bus without waiting
14    fn write_internal(&mut self, addr: u16, data: u8);
15    /// Wait some clocks
16    fn wait_mreq(&mut self, addr: u16, clk: usize);
17    /// Wait while mreq is not active (can be different from
18    /// active mreq contention as it works in ZX Spectrum 2+/3)
19    fn wait_no_mreq(&mut self, addr: u16, clk: usize);
20    /// Internal wait, avoiding contentions
21    fn wait_internal(&mut self, clk: usize);
22    /// Any single clock (t-state) can cause contention on ULA
23    /// or any other chipm which not detects MREQ signal
24    fn wait_loop(&mut self, addr: u16, clk: usize) {
25        for _ in 0..clk {
26            self.wait_no_mreq(addr, 1);
27        }
28    }
29    // Normal read from memory, contention may be applied
30    fn read(&mut self, addr: u16, clk: usize) -> u8 {
31        self.wait_mreq(addr, clk);
32        self.read_internal(addr)
33    }
34    // Normal write to memory, contention may be applied
35    fn write(&mut self, addr: u16, value: u8, clk: usize) {
36        self.wait_mreq(addr, clk);
37        self.write_internal(addr, value)
38    }
39    // Method for reading from io port.
40    fn read_io(&mut self, port: u16) -> u8;
41    // Method for writing to io port.
42    fn write_io(&mut self, port: u16, data: u8);
43    /// Provided method to write word, LSB first (clk - clocks per byte)
44    fn write_word(&mut self, addr: u16, data: u16, clk: usize) {
45        let [l, h] = data.to_le_bytes();
46        self.write(addr, l, clk);
47        self.write(addr.wrapping_add(1), h, clk);
48    }
49    /// Provided method to read word (clk - clocks per byte)
50    fn read_word(&mut self, addr: u16, clk: usize) -> u16 {
51        let l = self.read(addr, clk);
52        let h = self.read(addr.wrapping_add(1), clk);
53        u16::from_le_bytes([l, h])
54    }
55    /// Reads value from bus during interrupt.
56    /// mutable because on interrupt read some internal system attributes may be changed
57    fn read_interrupt(&mut self) -> u8;
58    /// Method, invoked by Z80 in case of RETI instruction. Default implementation is empty
59    fn reti(&mut self);
60    /// Method, invoked by Z80 in case of HALT line change
61    fn halt(&mut self, halted: bool);
62    /// Checks int signal
63    fn int_active(&self) -> bool;
64    /// Checks nmi signal
65    fn nmi_active(&self) -> bool;
66    /// invokes breakpoints check on bus device
67    fn pc_callback(&mut self, addr: u16);
68    fn process_unknown_opcode(&mut self, _prefix: Prefix, _opcode: Opcode) {}
69}
70
71impl<T> CodegenMemorySpace for T
72where
73    T: Z80Bus,
74{
75    fn write_byte(&mut self, addr: u16, byte: u8) {
76        // write, but does not perform any processing (zero clock cycles)
77        self.write(addr, byte, 0);
78    }
79}