Skip to main content

game_toolkit_dosbus/
device.rs

1use crate::{DmaRequest, IrqRequest, PortRange, Tick};
2
3/// A device on the host's timestamped, byte-wide I/O bus.
4///
5/// The host charges bus time before calling a device and dispatches only ports
6/// advertised by [`Self::ports`]. Devices synchronize to `at` before observing
7/// or changing hardware state, so a write cannot affect earlier output.
8///
9/// Timestamps supplied to a device must be nondecreasing across all calls;
10/// multiple accesses at the same timestamp take effect in call order. The host
11/// owns this invariant. Implementations may reject a backwards timestamp.
12///
13/// Hosts call [`Self::advance_to`] when time passes without port I/O, so DMA,
14/// timers and other externally observable state can progress. Request queries
15/// observe state at `at` without acknowledging it. A device may calculate that
16/// state analytically; otherwise the host must first call `advance_to(at)`.
17///
18/// Port decoding, overlapping port arbitration (such as the PIT control port),
19/// unmapped read values and bus costs belong to the host. The trait does not
20/// allocate or require an allocator, but implementations may use one.
21pub trait IoDevice: Send {
22    /// Ports decoded by this device. Keep this map stable while attached.
23    fn ports(&self) -> &[PortRange];
24
25    /// Progress autonomous hardware activity up to `at` without accessing a port.
26    ///
27    /// The default is suitable for devices with no autonomous activity.
28    fn advance_to(&mut self, _at: Tick) {}
29
30    /// Write a byte after synchronizing hardware state to `at`.
31    fn outb(&mut self, at: Tick, port: u16, value: u8);
32
33    /// Read a byte after synchronizing hardware state to `at`.
34    fn inb(&mut self, at: Tick, port: u16) -> u8;
35
36    /// Current IRQ line and level, or `None` if the device has no IRQ output.
37    ///
38    /// A device with an IRQ output returns `Some` with `asserted: false` when
39    /// deasserted, so a host can clear its contribution to a shared line.
40    fn irq_request(&self, _at: Tick) -> Option<IrqRequest> {
41        None
42    }
43
44    /// Whether this device is asserting its IRQ output at `at`.
45    fn irq_pending(&self, at: Tick) -> bool {
46        self.irq_request(at).is_some_and(|request| request.asserted)
47    }
48
49    /// Current asserted DRQ, or `None` when no DMA transfer is requested.
50    ///
51    /// The descriptor carries no transfer implementation. The host and its
52    /// concrete DMA-capable devices agree on how to exchange transfer units.
53    fn dma_request(&self, _at: Tick) -> Option<DmaRequest> {
54        None
55    }
56}