ral1243/
bus.rs

1/*
2    ral1243: Emulator program as an example implementation for the z80emu library.
3    Copyright (C) 2019-2024  Rafal Michalski
4
5    For the full copyright notice, see the lib.rs file.
6*/
7//! System `BUS` organization traits and structs.
8#[allow(unused_imports)]
9use super::vec::Vec;
10use core::num::NonZeroU16;
11use core::ops::Range;
12use core::marker::PhantomData;
13use z80emu::{Io, Memory};
14
15/// A terminator peripheral device.
16///
17/// Should be inserted as a last peripheral device in a daisy chain.
18#[derive(Default)]
19pub struct Terminator<T: Copy>(PhantomData<T>);
20
21/// Return an 8-bit mask from a given bit number.
22pub const fn bit8(n: u32) -> u8 {
23    1 << n
24}
25
26/// A helper trait that allows debugging the memory content.
27pub trait BusMemory {
28    /// Return a copy of the system memory view of the given address range.
29    fn memory_debug(&self, addr: Range<u16>) -> Vec<u8>;
30}
31
32/// A trait that all emulated devices must implement.
33pub trait BusDevice {
34    /// The timestamp type used.
35    type Timestamp: Copy;
36    /// The next device type in a daisy chain.
37    type NextDevice: BusDevice;
38    /// This method is called on hard reset.
39    fn reset(&mut self, ts: Self::Timestamp);
40    /// This method is called once at the end of an emulated frame,
41    //  so devices can update themselves.
42    fn frame_end(&mut self, ts: Self::Timestamp);
43    /// This method will be called whenever [`Memory::read_opcode`]
44    /// is being called from the `CPU` emulator.
45    fn m1(&mut self, ts: Self::Timestamp);
46    /// Provide a mutable access to the next device in a daisy chain.
47    fn next_device(&mut self) -> &mut Self::NextDevice;
48    /// Implementations should decrease all stored timestamps by the provided interval.
49    fn next_second(&mut self, delta: Self::Timestamp);
50}
51
52/// A trait implementing `Ral1243` I/O memory control port.
53pub trait MemoryControl {
54    /// Read the current memory control data.
55    fn read_ctrl(&self) -> u8;
56    /// Write a control data into the memory I/O port.
57    fn write_ctrl(&mut self, data: u8);
58    /// Return a copy of the system memory view of the given address range.
59    fn memory_debug(&self, addr: Range<u16>) -> Vec<u8>;
60}
61
62/// This struct organizes the peripheral device chain of the `Ral1243`.
63pub struct Bus<D, M> {
64    port_match_mask: u16,
65    port_match_bits: u16,
66    device: D,
67    memory: M,
68}
69
70impl <T: Copy, D, M: MemoryControl> BusMemory for Bus<D, M>
71where D: BusDevice<Timestamp=T>
72{
73    fn memory_debug(&self, addrs: Range<u16>) -> Vec<u8> {
74        self.memory.memory_debug(addrs)
75    }
76}
77
78impl <T: Copy, D, M> BusDevice for Bus<D, M>
79where D: BusDevice<Timestamp=T>
80{
81    type Timestamp = T;
82    type NextDevice = D;
83    fn reset(&mut self, ts: T) {
84        self.device.reset(ts)
85    }
86    fn frame_end(&mut self, ts: Self::Timestamp) {
87        self.device.frame_end(ts)
88    }
89    fn m1(&mut self, ts: T) {
90        self.device.m1(ts)
91    }
92    fn next_device(&mut self) -> &mut D {
93        &mut self.device
94    }
95    fn next_second(&mut self, delta: T) {
96        self.device.next_second(delta);
97    }
98}
99
100impl<D, M> Bus<D, M> {
101    /// Create a new instance of the device chain from the given `device` and
102    /// `memory` instances.
103    pub fn new(device: D, memory: M) -> Self {
104        Bus { port_match_mask: 0, port_match_bits: 0, device, memory }
105    }
106
107    /// Configure the mask and the address of the memory control I/O port.
108    pub fn with_port_bits(mut self, port_match_mask: u16, port_match_bits: u16) -> Self {
109        assert_eq!(port_match_mask & port_match_bits, port_match_bits);
110        self.port_match_mask = port_match_mask;
111        self.port_match_bits = port_match_bits;
112        self
113    }
114    /// Provide a reference to the instance of memory.
115    pub fn memory_ref(&self) -> &M {
116        &self.memory
117    }
118    /// Provide a mutable reference to the instance of memory.
119    pub fn memory_mut(&mut self) -> &mut M {
120        &mut self.memory
121    }
122    /// Destruct `Bus` and return a pair of a `device` chain and a `memory`.
123    pub fn into_inner(self) -> (D, M) {
124        (self.device, self.memory)
125    }
126}
127
128impl<T, D, M> Io for Bus<D, M>
129where T: Copy,
130      D: BusDevice + Io<Timestamp=T,WrIoBreak=(),RetiBreak=()>,
131      M: Memory<Timestamp=T> + MemoryControl
132{
133    type Timestamp = T;
134    type WrIoBreak = ();
135    type RetiBreak = ();
136
137    #[inline(always)]
138    fn write_io(&mut self, port: u16, data: u8, ts: T) -> (Option<()>, Option<NonZeroU16>) {
139        if port & self.port_match_mask == self.port_match_bits {
140            self.memory.write_ctrl(data);
141            (None, None)
142        }
143        else {
144            self.device.write_io(port, data, ts)
145        }
146    }
147
148    #[inline(always)]
149    fn read_io(&mut self, port: u16, ts: T) -> (u8, Option<NonZeroU16>) {
150        if port & self.port_match_mask == self.port_match_bits {
151            (self.memory.read_ctrl(), None)
152        }
153        else {
154            self.device.read_io(port, ts)
155        }
156    }
157
158    #[inline(always)]
159    fn is_irq(&mut self, ts: Self::Timestamp) -> bool {
160        self.device.is_irq(ts)
161    }
162
163    #[inline(always)]
164    fn irq_data(&mut self, pc: u16, ts: Self::Timestamp) -> (u8, Option<NonZeroU16>) {
165        self.device.irq_data(pc, ts)
166    }
167
168    #[inline(always)]
169    fn reti(&mut self, addr: u16, ts: Self::Timestamp) -> Option<()> {
170        self.device.reti(addr, ts)
171    }
172}
173
174impl<T, D, M> Memory for Bus<D, M>
175where T: Copy,
176      D: BusDevice<Timestamp=T> + Io<Timestamp=T>,
177      M: Memory<Timestamp=T>
178{
179    type Timestamp = T;
180    #[inline(always)]
181    fn read_opcode(&mut self, pc: u16, ir: u16, ts: T) -> u8 {
182        self.device.m1(ts);
183        self.memory.read_opcode(pc, ir, ts)
184    }
185    #[inline(always)]
186    fn read_mem(&self, addr: u16, ts: T) -> u8 {
187        self.memory.read_mem(addr, ts)
188    }
189    #[inline(always)]
190    fn read_mem16(&self, addr: u16, ts: T) -> u16 {
191        self.memory.read_mem16(addr, ts)
192    }
193    #[inline(always)]
194    fn write_mem(&mut self, addr: u16, data: u8, ts: T) {
195        self.memory.write_mem(addr, data, ts);
196    }
197    #[inline(always)]
198    fn read_debug(&self, addr: u16) -> u8 {
199        self.memory.read_debug(addr)
200    }
201}
202
203impl<T: Copy> BusDevice for Terminator<T> {
204    type Timestamp = T;
205    type NextDevice = Self;
206    #[inline(always)]
207    fn reset(&mut self, _ts: T) {}
208    #[inline(always)]
209    fn frame_end(&mut self, _ts: Self::Timestamp) {}
210    #[inline(always)]
211    fn m1(&mut self, _ts: T) {}
212    #[inline(always)]
213    fn next_device(&mut self) -> &mut Self {
214        self
215    }
216    #[inline(always)]
217    fn next_second(&mut self, _delta: T) {}
218}
219
220impl<T: Copy> Terminator<T> {
221    pub fn new() -> Self {
222        Terminator(PhantomData)
223    }
224}
225
226impl<T: Copy> Io for Terminator<T> {
227    type Timestamp = T;
228    type WrIoBreak = ();
229    type RetiBreak = ();
230
231    #[inline(always)]
232    fn write_io(&mut self, _port: u16, _data: u8, _ts: T) -> (Option<()>, Option<NonZeroU16>) {
233        (None, None)
234    }
235    #[inline(always)]
236    fn read_io(&mut self, _port: u16, _ts: T) -> (u8, Option<NonZeroU16>) {
237        (u8::max_value(), None)
238    }
239    #[inline(always)]
240    fn is_irq(&mut self, _ts: Self::Timestamp) -> bool {
241        false
242    }
243    #[inline(always)]
244    fn irq_data(&mut self, _pc: u16, _ts: Self::Timestamp) -> (u8, Option<NonZeroU16>) {
245        (u8::max_value(), None)
246    }
247    #[inline(always)]
248    fn reti(&mut self, _addr: u16, _ts: Self::Timestamp) -> Option<()> {
249        None
250    }
251}