spectrusty_peripherals/bus/
mouse.rs

1/*
2    Copyright (C) 2020-2022  Rafal Michalski
3
4    This file is part of SPECTRUSTY, a Rust library for building emulators.
5
6    For the full copyright notice, see the lib.rs file.
7*/
8//! A bus device for connecting pointing devices / mouses.
9use core::num::NonZeroU16;
10use core::fmt::{self, Debug};
11use core::marker::PhantomData;
12use core::ops::{Deref, DerefMut};
13
14#[cfg(feature = "snapshot")]
15use serde::{Serialize, Deserialize};
16
17use spectrusty_core::{
18    bus::{BusDevice, PortAddress}
19};
20
21use super::ay::PassByAyAudioBusDevice;
22
23pub use crate::mouse::{
24    MouseDevice, MouseInterface, NullMouseDevice,
25    kempston::*
26};
27
28/// A convenient Kempston Mouse [BusDevice] type.
29pub type KempstonMouse<D> = MouseBusDevice<
30                                            KempstonMousePortAddress,
31                                            KempstonMouseDevice,
32                                            D>;
33
34impl<D> fmt::Display for KempstonMouse<D> {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        f.write_str("Kempston Mouse")
37    }
38}
39/// A mouse controller, providing a [BusDevice] implementation that can be used with [mouse devices][MouseDevice].
40#[derive(Clone, Default, Debug)]
41#[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
42pub struct MouseBusDevice<P, M, D> {
43    /// A [MouseDevice] implementation, which may also implement [MouseInterface] trait
44    /// for providing user input.
45    #[cfg_attr(feature = "snapshot", serde(default))]
46    pub mouse: M,
47    #[cfg_attr(feature = "snapshot", serde(default))]
48    bus: D,
49    #[cfg_attr(feature = "snapshot", serde(skip))]
50    _port_decode: PhantomData<P>,
51}
52
53/// Kempston Mouse [PortAddress].
54#[derive(Clone, Copy, Default, Debug)]
55pub struct KempstonMousePortAddress;
56impl PortAddress for KempstonMousePortAddress {
57    const ADDRESS_MASK: u16 = 0b0000_0000_0010_0000;
58    const ADDRESS_BITS: u16 = 0b1111_1010_1101_1111;
59}
60
61impl<P, M: MouseInterface, D> Deref for MouseBusDevice<P, M, D> {
62    type Target = M;
63    fn deref(&self) -> &Self::Target {
64        &self.mouse
65    }
66}
67
68impl<P, M: MouseInterface, D> DerefMut for MouseBusDevice<P, M, D> {
69    fn deref_mut(&mut self) -> &mut Self::Target {
70        &mut self.mouse
71    }
72}
73
74impl<P, M, D> PassByAyAudioBusDevice for MouseBusDevice<P, M, D> {}
75
76impl<P, M, D> BusDevice for MouseBusDevice<P, M, D>
77    where P: PortAddress,
78          D: BusDevice,
79          M: MouseDevice
80{
81    type Timestamp = D::Timestamp;
82    type NextDevice = D;
83
84    #[inline]
85    fn next_device_mut(&mut self) -> &mut Self::NextDevice {
86        &mut self.bus
87    }
88
89    #[inline]
90    fn next_device_ref(&self) -> &Self::NextDevice {
91        &self.bus
92    }
93
94    #[inline]
95    fn into_next_device(self) -> Self::NextDevice {
96        self.bus
97    }
98
99    #[inline]
100    fn read_io(&mut self, port: u16, timestamp: Self::Timestamp) -> Option<(u8, Option<NonZeroU16>)> {
101        let bus_data = self.bus.read_io(port, timestamp);
102        if P::match_port(port) {
103            let mouse_data = self.mouse.port_read(port);
104            if let Some((data, ws)) = bus_data {
105                return Some((data & mouse_data, ws))
106            }
107            return Some((mouse_data, None))
108        }
109        bus_data
110    }
111
112    #[inline]
113    fn write_io(&mut self, port: u16, data: u8, timestamp: Self::Timestamp) -> Option<u16> {
114        if P::match_port(port) && self.mouse.port_write(port, data) {
115            return Some(0);
116        }
117        self.bus.write_io(port, data, timestamp)
118    }
119}