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}