spectrusty_peripherals/bus/
zxinterface1.rs1use core::num::NonZeroU16;
55use core::fmt;
56use std::io;
57
58#[cfg(feature = "snapshot")]
59use serde::{Serialize, Deserialize};
60
61use spectrusty_core::{
62 clock::TimestampOps,
63 bus::BusDevice
64};
65
66use super::ay::PassByAyAudioBusDevice;
67
68pub use crate::{
69 storage::microdrives::*,
70 serial::{SerialPortDevice, DataState, ControlState, Rs232Io, BAUD_RATES, DEFAULT_BAUD_RATE},
71 network::zxnet::*
72};
73
74impl<R, W, N, D: BusDevice> fmt::Display for ZxInterface1BusDevice<R, W, N, D> {
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 f.write_str("ZX Interface I")
77 }
78}
79
80#[derive(Default, Debug)]
85#[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
86#[cfg_attr(feature = "snapshot", serde(bound(deserialize = "
87 R: Deserialize<'de> + Default,
88 W: Deserialize<'de> + Default,
89 N: Default,
90 D: Deserialize<'de> + Default,
91 D::Timestamp: Deserialize<'de> + Default",
92serialize = "
93 R: Serialize,
94 W: Serialize,
95 D: Serialize,
96 D::Timestamp: Serialize")))]
97#[cfg_attr(feature = "snapshot", serde(rename_all = "camelCase"))]
98pub struct ZxInterface1BusDevice<R, W, N, D: BusDevice>
99{
100 #[cfg_attr(feature = "snapshot", serde(default))]
102 pub microdrives: ZxMicrodrives<D::Timestamp>,
103 #[cfg_attr(feature = "snapshot", serde(default))]
105 pub serial: Rs232Io<D::Timestamp, R, W>,
106 #[cfg_attr(feature = "snapshot", serde(skip))]
108 pub network: ZxNet<D::Timestamp, N>,
109 sernet: If1SerNetIo,
110 ctrl_in: If1ControlIn,
111 ctrl_out: If1ControlOut,
112 #[cfg_attr(feature = "snapshot", serde(default))]
113 bus: D
114}
115
116bitflags! {
117 #[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
118 struct If1SerNetIo: u8 {
119 const RXD = 0b0000_0001;
120 const TXD = 0b1000_0000;
121 const NET = 0b0000_0001;
122 const DEFAULT = 0b0111_1110;
123 }
124}
125
126bitflags! {
127 #[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
128 struct If1ControlIn: u8 {
129 const MD_MASK = 0b0000_0111;
130 const MD_PROT = 0b0000_0001;
131 const MD_SYN = 0b0000_0010;
132 const MD_GAP = 0b0000_0100;
133 const SER_DTR = 0b0000_1000;
134 const NET_BUSY = 0b0001_0000;
135 const DEFAULT = 0b1110_0111;
136 }
137}
138
139bitflags! {
140 #[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
141 struct If1ControlOut: u8 {
142 const MD_MASK = 0b0000_1111;
143 const COMMS_OUT = 0b0000_0001;
144 const COMMS_CLK = 0b0000_0010;
145 const MD_R_W = 0b0000_0100;
146 const MD_ERASE = 0b0000_1000;
147 const SER_CTS = 0b0001_0000;
148 const NET_WAIT = 0b0010_0000;
149 const DEFAULT = 0b1110_1110;
150 }
151}
152
153macro_rules! default_io {
154 ($($ty:ty),*) => {$(
155 impl Default for $ty {
156 fn default() -> Self {
157 <$ty>::DEFAULT
158 }
159 }
160 )*};
161}
162
163default_io!(If1ControlOut, If1ControlIn, If1SerNetIo);
164
165impl If1SerNetIo {
166 #[inline(always)]
167 fn rxd(self) -> DataState {
168 DataState::from(!self.intersects(If1SerNetIo::RXD))
169 }
170 #[inline(always)]
171 fn net(self) -> bool {
172 !self.intersects(If1SerNetIo::NET)
173 }
174 #[inline(always)]
175 fn set_txd(&mut self, txd: DataState) {
176 self.set(If1SerNetIo::TXD, !bool::from(txd))
177 }
178 #[inline(always)]
179 fn set_net(&mut self, net: bool) {
180 self.set(If1SerNetIo::NET, net)
181 }
182}
183
184impl If1ControlIn {
185 #[inline(always)]
186 fn set_md_state(&mut self, CartridgeState { gap, syn, write_protect }: CartridgeState) {
187 self.insert(If1ControlIn::MD_MASK);
188 if gap {
189 self.remove(If1ControlIn::MD_GAP);
190 }
191 if syn {
192 self.remove(If1ControlIn::MD_SYN);
193 }
194 if write_protect {
195 self.remove(If1ControlIn::MD_PROT);
196 }
197 }
198 #[inline(always)]
199 fn set_dtr(&mut self, dtr: ControlState) {
200 self.set(If1ControlIn::SER_DTR, !bool::from(dtr))
201 }
202}
203
204impl If1ControlOut {
205 #[inline(always)]
206 fn is_comms_out_ser(self) -> bool {
207 self.intersects(If1ControlOut::COMMS_OUT)
208 }
209 #[inline(always)]
210 fn erase(self) -> bool {
211 !self.intersects(If1ControlOut::MD_ERASE)
212 }
213 #[inline(always)]
214 fn write(self) -> bool {
215 !self.intersects(If1ControlOut::MD_R_W)
216 }
217 #[inline(always)]
218 fn comms_clk(self) -> bool {
219 !self.intersects(If1ControlOut::COMMS_CLK)
220 }
221 #[inline(always)]
222 fn comms_out(self) -> bool {
223 !self.intersects(If1ControlOut::COMMS_OUT)
224 }
225 #[inline(always)]
226 fn cts(self) -> ControlState {
227 ControlState::from(!self.intersects(If1ControlOut::SER_CTS))
228 }
229 #[inline(always)]
230 fn wait(self) -> bool {
231 !self.intersects(If1ControlOut::NET_WAIT)
232 }
233}
234
235const IF1_MASK: u16 = 0b0000_0000_0001_1000;
236const IF1_SERN_BITS: u16 = 0b0000_0000_0001_0000;
237const IF1_CTRL_BITS: u16 = 0b0000_0000_0000_1000;
238const IF1_DATA_BITS: u16 = 0b0000_0000_0000_0000;
239
240impl<R, W, N, D: BusDevice> PassByAyAudioBusDevice for ZxInterface1BusDevice<R, W, N, D> {}
241
242impl<R, W, N, D> BusDevice for ZxInterface1BusDevice<R, W, N, D>
243 where R: io::Read + fmt::Debug,
244 W: io::Write + fmt::Debug,
245 N: ZxNetSocket + fmt::Debug,
246 D: BusDevice,
247 D::Timestamp: TimestampOps
248{
249 type Timestamp = D::Timestamp;
250 type NextDevice = D;
251
252 #[inline]
253 fn next_device_mut(&mut self) -> &mut Self::NextDevice {
254 &mut self.bus
255 }
256
257 #[inline]
258 fn next_device_ref(&self) -> &Self::NextDevice {
259 &self.bus
260 }
261
262 #[inline]
263 fn into_next_device(self) -> Self::NextDevice {
264 self.bus
265 }
266
267 #[inline]
268 fn reset(&mut self, timestamp: Self::Timestamp) {
269 self.microdrives.reset(timestamp);
270 self.bus.reset(timestamp);
271 }
272
273 #[inline]
274 fn update_timestamp(&mut self, timestamp: Self::Timestamp) {
275 self.microdrives.update_timestamp(timestamp);
276 self.ctrl_in.set_dtr(self.serial.poll_ready(timestamp));
277 }
278
279 #[inline]
280 fn next_frame(&mut self, eof_timestamp: Self::Timestamp) {
281 self.microdrives.next_frame(eof_timestamp);
283 self.serial.next_frame(eof_timestamp);
284 self.network.next_frame(eof_timestamp);
285 self.bus.next_frame(eof_timestamp)
286 }
287
288 #[inline]
289 fn read_io(&mut self, port: u16, timestamp: Self::Timestamp) -> Option<(u8, Option<NonZeroU16>)> {
290 match port & IF1_MASK {
291 IF1_SERN_BITS => {
292 self.sernet.set_txd(self.serial.read_data(timestamp));
293 if self.ctrl_out.cts().is_inactive() {
294 self.sernet.set_net(self.network.poll_state(timestamp));
295 }
296 Some((self.sernet.bits(), None))
298 }
299 IF1_CTRL_BITS => {
300 self.ctrl_in.set_md_state(self.microdrives.read_state(timestamp));
301 Some((self.ctrl_in.bits(), None))
304 }
305 IF1_DATA_BITS => {
306 Some(self.microdrives.read_data(timestamp))
307 }
308 _ => self.bus.read_io(port, timestamp)
309 }
310 }
311
312 #[inline]
313 fn write_io(&mut self, port: u16, data: u8, timestamp: Self::Timestamp) -> Option<u16> {
314 match port & IF1_MASK {
315 IF1_SERN_BITS => {
316 let data = If1SerNetIo::from_bits_truncate(data);
317 if self.ctrl_out.is_comms_out_ser() {
318 self.ctrl_in.set_dtr(self.serial.write_data(data.rxd(), timestamp));
319 }
320 else {
321 self.network.send_state(data.net(), timestamp);
323 }
325 Some(0)
326 }
327 IF1_CTRL_BITS => {
328 let data = If1ControlOut::from_bits_truncate(data);
329 let diff = self.ctrl_out ^ data;
330 self.ctrl_out ^= diff;
332 if !(diff & If1ControlOut::MD_MASK).is_empty() {
333 self.microdrives.write_control(timestamp,
334 data.erase(), data.write(), data.comms_clk(), data.comms_out());
335 }
336 if !(diff & If1ControlOut::SER_CTS).is_empty() {
337 self.serial.update_cts(data.cts(), timestamp);
338 }
339 if data.wait() {
340 self.network.wait_data(timestamp);
341 }
343 Some(0)
344 }
345 IF1_DATA_BITS => Some(self.microdrives.write_data(data, timestamp)),
346 _ => self.bus.write_io(port, data, timestamp)
347 }
348 }
349}