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}