spectrusty_core/bus/
dynbus.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*/
8use core::mem;
9use core::num::NonZeroU16;
10use core::fmt::{Display, Debug};
11use core::iter::IntoIterator;
12use core::ops::{Index, IndexMut};
13
14#[cfg(feature = "snapshot")]
15use ::serde::{Serialize, Deserialize};
16
17#[cfg(feature = "snapshot")]
18mod serde;
19
20#[cfg(feature = "snapshot")]
21pub use self::serde::*;
22
23use super::{BusDevice, VFNullDevice, NullDevice};
24
25/// A trait for dynamic bus devices, which currently includes methods from [Display] and [BusDevice].
26/// Devices implementing this trait can be used with a [DynamicBus].
27///
28/// Implemented for all types that implement dependent traits.
29pub trait NamedBusDevice<T>: Display + BusDevice<Timestamp=T, NextDevice=NullDevice<T>>{}
30
31impl<T, D> NamedBusDevice<T> for D where D: Display + BusDevice<Timestamp=T, NextDevice=NullDevice<T>>{}
32
33/// A type of a dynamic [NamedBusDevice].
34pub type NamedDynDevice<T> = dyn NamedBusDevice<T>;
35/// A type of a boxed dynamic [NamedBusDevice].
36///
37/// This is a type of items stored by [DynamicBus].
38pub type BoxNamedDynDevice<T> = Box<dyn NamedBusDevice<T>>;
39
40/// A terminated [DynamicBus] pseudo-device with [`VFNullDevice<V>`][VFNullDevice].
41pub type DynamicVBus<V> = DynamicBus<VFNullDevice<V>>;
42
43/// A pseudo bus device that allows for adding and removing devices of different types at run time.
44///
45/// The penalty is that the access to the devices must be done using a virtual call dispatch.
46/// Also the device of this type can't be cloned (nor the [ControlUnit][crate::chip::ControlUnit]
47/// with this device attached).
48///
49/// `DynamicBus<D>` implements [BusDevice] itself, so obviously it's possible to declare a statically
50/// dispatched downstream [BusDevice] as its parameter `D`.
51///
52/// Currently only types implementing [BusDevice] that are directly terminated with [NullDevice]
53/// can be attached as dynamically dispatched objects.
54#[derive(Default, Debug)]
55#[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
56pub struct DynamicBus<D: BusDevice> {
57    #[cfg_attr(feature = "snapshot", serde(default))]
58    bus: D,
59    #[cfg_attr(feature = "snapshot", serde(skip))]
60    devices: Vec<BoxNamedDynDevice<D::Timestamp>>
61}
62
63impl<'a, T, D: 'a> From<D> for Box<dyn NamedBusDevice<T> + 'a>
64    where D: BusDevice<Timestamp=T, NextDevice=NullDevice<T>> + Display
65{
66    fn from(dev: D) -> Self {
67        Box::new(dev)
68    }
69}
70
71impl<D: BusDevice> AsRef<[BoxNamedDynDevice<D::Timestamp>]> for DynamicBus<D> {
72    fn as_ref(&self) -> &[BoxNamedDynDevice<D::Timestamp>] {
73        self.devices.as_slice()
74    }
75}
76
77impl<D: BusDevice> AsMut<[BoxNamedDynDevice<D::Timestamp>]> for DynamicBus<D> {
78    fn as_mut(&mut self) -> &mut[BoxNamedDynDevice<D::Timestamp>] {
79        self.devices.as_mut_slice()
80    }
81}
82
83impl<D> DynamicBus<D>
84    where D: BusDevice
85{
86    /// Returns the number of attached devices.
87    pub fn len(&self) -> usize {
88        self.devices.len()
89    }
90    /// Returns `true` if there are no devices in the dynamic chain. Otherwise returns `false`.
91    pub fn is_empty(&self) -> bool {
92        self.len() == 0
93    }
94    /// Appends an instance of a `device` at the end of the daisy-chain.
95    /// Returns its index position in the dynamic device chain.
96    pub fn append_device<B>(&mut self, device: B) -> usize
97        where B: Into<BoxNamedDynDevice<D::Timestamp>>
98    {
99        self.devices.push(device.into());
100        self.devices.len() - 1
101    }
102    /// Removes the last device from the dynamic daisy-chain and returns an instance of the boxed
103    /// dynamic object.
104    pub fn remove_device(&mut self) -> Option<BoxNamedDynDevice<D::Timestamp>> {
105        self.devices.pop()
106    }
107    /// Replaces a device at the given `index` position and returns it.
108    /// 
109    /// The removed device is replaced by the last device of the chain.
110    ///
111    /// # Panics
112    /// Panics if a device doesn't exist at `index`.
113    pub fn swap_remove_device(&mut self, index: usize) -> BoxNamedDynDevice<D::Timestamp> {
114        self.devices.swap_remove(index)
115    }
116    /// Replaces a device at the given `index` position. Returns the previous device occupying the replaced spot.
117    ///
118    /// # Panics
119    /// Panics if a device doesn't exist at `index`.
120    pub fn replace_device<B>(&mut self, index: usize, device: B) -> BoxNamedDynDevice<D::Timestamp>
121        where B: Into<BoxNamedDynDevice<D::Timestamp>>
122    {
123        mem::replace(&mut self.devices[index], device.into())
124    }
125    /// Removes all dynamic devices from the dynamic daisy-chain.
126    pub fn clear(&mut self) {
127        self.devices.clear();
128    }
129    /// Returns a reference to a dynamic device at `index` position in the dynamic daisy-chain.
130    #[inline]
131    pub fn get_device_ref(&self, index: usize) -> Option<&NamedDynDevice<D::Timestamp>> {
132        // self.devices[index].as_ref()
133        self.devices.get(index).map(|d| d.as_ref())
134    }
135    /// Returns a mutable reference to a dynamic device at `index` position in the dynamic daisy-chain.
136    #[inline]
137    pub fn get_device_mut(&mut self, index: usize) -> Option<&mut NamedDynDevice<D::Timestamp>> {
138        self.devices.get_mut(index).map(|d| d.as_mut())
139    }
140}
141
142impl<D> DynamicBus<D>
143    where D: BusDevice,
144          D::Timestamp: 'static
145{
146    /// Removes the last device from the dynamic daisy-chain.
147    ///
148    /// # Panics
149    /// Panics if a device is not of a type given as parameter `B`.
150    pub fn remove_as_device<B>(&mut self) -> Option<Box<B>>
151        where B: NamedBusDevice<D::Timestamp> + 'static
152    {
153        self.remove_device().map(|boxdev|
154            boxdev.downcast::<B>().expect("wrong dynamic device type removed")
155        )
156    }
157    /// Replaces a device at the given `index` and returns it.
158    /// 
159    /// The removed device is replaced by the last device of the chain.
160    ///
161    /// # Panics
162    /// Panics if a device doesn't exist at `index` or if a device is not of a type given as parameter `B`.
163    pub fn swap_remove_as_device<B>(&mut self, index: usize) -> Box<B>
164        where B: NamedBusDevice<D::Timestamp> + 'static
165    {
166        self.swap_remove_device(index).downcast::<B>().expect("wrong dynamic device type removed")
167    }
168    /// Returns a reference to a device of a type `B` at `index` in the dynamic daisy-chain.
169    ///
170    /// # Panics
171    /// Panics if a device doesn't exist at `index` or if a device is not of a type given as parameter `B`.
172    #[inline]
173    pub fn as_device_ref<B>(&self, index: usize) -> &B
174        where B: NamedBusDevice<D::Timestamp> + 'static
175    {
176        self.devices[index].downcast_ref::<B>().expect("wrong dynamic device type")
177    }
178    /// Returns a mutable reference to a device of a type `B` at `index` in the dynamic daisy-chain.
179    ///
180    /// # Panics
181    /// Panics if a device doesn't exist at `index` or if a device is not of a type given as parameter `B`.
182    #[inline]
183    pub fn as_device_mut<B>(&mut self, index: usize) -> &mut B
184        where B: NamedBusDevice<D::Timestamp> + 'static
185    {
186        self.devices[index].downcast_mut::<B>().expect("wrong dynamic device type")
187    }
188    /// Returns `true` if a device at `index` is of a type given as parameter `B`.
189    #[inline]
190    pub fn is_device<B>(&self, index: usize) -> bool
191        where B: NamedBusDevice<D::Timestamp> + 'static
192    {
193        self.devices.get(index).map(|d| d.is::<B>()).unwrap_or(false)
194    }
195    /// Searches for a first device of a type given as parameter `B`, returning its index.
196    #[inline]
197    pub fn position_device<B>(&self) -> Option<usize>
198        where B: NamedBusDevice<D::Timestamp> + 'static
199    {
200        self.devices.iter().position(|d| d.is::<B>())
201    }
202    /// Searches for a first device of a type given as parameter `B`, returning a reference to a device.
203    #[inline]
204    pub fn find_device_ref<B>(&self) -> Option<&B>
205        where B: NamedBusDevice<D::Timestamp> + 'static
206    {
207        self.devices.iter().find_map(|d| d.downcast_ref::<B>())
208    }
209    /// Searches for a first device of a type given as parameter `B`, returning a mutable reference to a device.
210    #[inline]
211    pub fn find_device_mut<B>(&mut self) -> Option<&mut B>
212        where B: NamedBusDevice<D::Timestamp> + 'static
213    {
214        self.devices.iter_mut().find_map(|d| d.downcast_mut::<B>())
215    }
216}
217
218impl<D: BusDevice> Index<usize> for DynamicBus<D> {
219    type Output = NamedDynDevice<D::Timestamp>;
220    #[inline]
221    fn index(&self, index: usize) -> &Self::Output {
222        self.devices[index].as_ref()
223    }
224}
225
226impl<D: BusDevice> IndexMut<usize> for DynamicBus<D> {
227    #[inline]
228    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
229        self.devices[index].as_mut()
230    }
231}
232
233impl<'a, D: BusDevice> IntoIterator for &'a DynamicBus<D> {
234    type Item = &'a BoxNamedDynDevice<D::Timestamp>;
235    type IntoIter = core::slice::Iter<'a, BoxNamedDynDevice<D::Timestamp>>;
236    #[inline]
237    fn into_iter(self) -> Self::IntoIter {
238        self.devices.iter()
239    }
240}
241
242impl<'a, D: BusDevice> IntoIterator for &'a mut DynamicBus<D> {
243    type Item = &'a mut BoxNamedDynDevice<D::Timestamp>;
244    type IntoIter = core::slice::IterMut<'a, BoxNamedDynDevice<D::Timestamp>>;
245    #[inline]
246    fn into_iter(self) -> Self::IntoIter {
247        self.devices.iter_mut()
248    }
249}
250
251impl<D: BusDevice> IntoIterator for DynamicBus<D> {
252    type Item = BoxNamedDynDevice<D::Timestamp>;
253    type IntoIter = std::vec::IntoIter<BoxNamedDynDevice<D::Timestamp>>;
254    #[inline]
255    fn into_iter(self) -> Self::IntoIter {
256        self.devices.into_iter()
257    }
258}
259
260impl<D> BusDevice for DynamicBus<D>
261    where D: BusDevice,
262          D::Timestamp: Debug + Copy
263{
264    type Timestamp = D::Timestamp;
265    type NextDevice = D;
266
267    #[inline]
268    fn next_device_mut(&mut self) -> &mut Self::NextDevice {
269        &mut self.bus
270    }
271    #[inline]
272    fn next_device_ref(&self) -> &Self::NextDevice {
273        &self.bus
274    }
275    #[inline]
276    fn into_next_device(self) -> Self::NextDevice {
277        self.bus
278    }
279    #[inline]
280    fn reset(&mut self, timestamp: Self::Timestamp) {
281        for dev in self.devices.iter_mut() {
282            dev.reset(timestamp);
283        }
284        self.bus.reset(timestamp);
285    }
286
287    #[inline]
288    fn update_timestamp(&mut self, timestamp: Self::Timestamp) {
289        for dev in self.devices.iter_mut() {
290            dev.update_timestamp(timestamp);
291        }
292        self.bus.update_timestamp(timestamp);
293    }
294
295    #[inline]
296    fn next_frame(&mut self, timestamp: Self::Timestamp) {
297        for dev in self.devices.iter_mut() {
298            dev.next_frame(timestamp);
299        }
300        self.bus.next_frame(timestamp);
301    }
302
303    #[inline]
304    fn read_io(&mut self, port: u16, timestamp: Self::Timestamp) -> Option<(u8, Option<NonZeroU16>)> {
305        let mut bus_data = None;
306        for dev in self.devices.iter_mut() {
307            if let Some((data, ws)) = dev.read_io(port, timestamp) {
308                let data = data & bus_data.unwrap_or(!0);
309                if ws.is_some() {
310                    return Some((data, ws));
311                }
312                bus_data = Some(data);
313            }
314        }
315        if let Some((data, ws)) = self.bus.read_io(port, timestamp) {
316            return Some((data & bus_data.unwrap_or(!0), ws))
317        }
318        bus_data.map(|data| (data, None))
319    }
320
321    #[inline]
322    fn write_io(&mut self, port: u16, data: u8, timestamp: Self::Timestamp) -> Option<u16> {
323        for dev in self.devices.iter_mut() {
324            if let Some(res) = dev.write_io(port, data, timestamp) {
325                return Some(res);
326            }
327        }
328        self.bus.write_io(port, data, timestamp)
329    }
330}
331
332#[cfg(test)]
333mod tests {
334    use core::fmt;
335    use super::*;
336
337    #[derive(Default, Clone, PartialEq, Debug)]
338    struct TestDevice {
339        foo: i32,
340        data: u8,
341        bus: NullDevice<i32>
342    }
343
344    impl fmt::Display for TestDevice {
345        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
346            f.write_str("Test Device")
347        }
348    }
349
350    impl BusDevice for TestDevice {
351        type Timestamp = i32;
352        type NextDevice = NullDevice<i32>;
353
354        fn next_device_mut(&mut self) -> &mut Self::NextDevice {
355            &mut self.bus
356        }
357        fn next_device_ref(&self) -> &Self::NextDevice {
358            &self.bus
359        }
360        fn into_next_device(self) -> Self::NextDevice {
361            self.bus
362        }
363        fn reset(&mut self, timestamp: Self::Timestamp) {
364            self.foo = i32::min_value() + timestamp;
365        }
366        fn update_timestamp(&mut self, timestamp: Self::Timestamp) {
367            self.foo = timestamp
368        }
369        fn read_io(&mut self, _port: u16, timestamp: Self::Timestamp) -> Option<(u8, Option<NonZeroU16>)> {
370            if self.foo == timestamp {
371                Some((self.data, None))
372            }
373            else {
374                None
375            }
376        }
377        fn write_io(&mut self, _port: u16, data: u8, timestamp: Self::Timestamp) -> Option<u16> {
378            self.data = data;
379            self.foo = timestamp;
380            Some(0)
381        }
382    }
383
384    #[test]
385    fn dynamic_bus_device_works() {
386        let mut dchain: DynamicBus<NullDevice<i32>> = Default::default();
387        assert_eq!(dchain.len(), 0);
388        assert_eq!(dchain.write_io(0, 0, 0), None);
389        assert_eq!(dchain.read_io(0, 0), None);
390        let test_dev: Box<dyn NamedBusDevice<_>> = Box::new(TestDevice::default());
391        let index = dchain.append_device(test_dev);
392        assert_eq!(dchain.is_device::<TestDevice>(index), true);
393        assert_eq!(index, 0);
394        assert_eq!(dchain.len(), 1);
395        let device = dchain.remove_device().unwrap();
396        assert_eq!(device.is::<TestDevice>(), true);
397        assert_eq!(dchain.len(), 0);
398
399        let index0 = dchain.append_device(NullDevice::default());
400        assert_eq!(index0, 0);
401        assert_eq!(dchain.is_device::<TestDevice>(index0), false);
402        assert_eq!(dchain.is_device::<NullDevice<_>>(index0), true);
403        assert_eq!(dchain.len(), 1);
404        let dev: &NullDevice<_> = dchain.as_device_ref(index0);
405        assert_eq!(dev, &NullDevice::default());
406
407        let index1 = dchain.append_device(TestDevice::default());
408        assert_eq!(index1, 1);
409        assert_eq!(dchain.is_device::<TestDevice>(index1), true);
410        assert_eq!(dchain.is_device::<TestDevice>(index0), false);
411        assert_eq!(dchain.is_device::<TestDevice>(usize::max_value()), false);
412        assert_eq!(dchain.is_device::<NullDevice<_>>(index0), true);
413        assert_eq!(dchain.is_device::<NullDevice<_>>(index1), false);
414        assert_eq!(dchain.is_device::<NullDevice<_>>(usize::max_value()), false);
415        let dev = dchain.get_device_ref(index1).unwrap();
416        assert_eq!(dev.is::<TestDevice>(), true);
417        assert_eq!(dev.is::<NullDevice<_>>(), false);
418        assert_eq!(format!("{}", dev), "Test Device");
419        if let Some(dev) = dchain.get_device_mut(index1) {
420            dev.update_timestamp(777);
421            assert_eq!(dev.read_io(0, 0), None);
422            assert_eq!(dev.read_io(0, 777), Some((0, None)));
423        }
424        assert_eq!(dchain.len(), 2);
425        assert_eq!(dchain.write_io(0, 42, 131999), Some(0));
426        assert_eq!(dchain.read_io(0, 0), None);
427        assert_eq!(dchain.read_io(0, 131999), Some((42, None)));
428        let dev: &TestDevice = dchain.as_device_ref(index1);
429        assert_eq!(dev.data, 42);
430        assert_eq!(dev.foo, 131999);
431        let dev: &mut TestDevice = dchain.as_device_mut(index1);
432        dev.data = 199;
433        dev.foo = -1;
434        let dev: &TestDevice = dchain.as_device_ref(index1);
435        assert_eq!(dev.data, 199);
436        assert_eq!(dev.foo, -1);
437        let device: TestDevice = *dchain.remove_as_device().unwrap();
438        assert_eq!(dchain.len(), 1);
439        assert_eq!(device, TestDevice {
440            foo: -1,
441            data: 199,
442            bus: NullDevice::<i32>::default()
443        });
444    }
445}