Skip to main content
← PSoXide SDK guides and examples · SDK f2fec1c301f1 · All Cargo features enabled; check feature gates before use.

psx_cdstream/
hw.rs

1//! The drive as the transport state machine sees it.
2//!
3//! [`CdHw`] is everything [`Engine`](crate::Engine) asks of the CD-ROM
4//! controller and the system around it. The real implementation
5//! (`Mmio`, target only) is a thin layer over `psx_io::periph::Cd`; the tests
6//! use a scripted fake drive. The methods are the controller steps whose
7//! *order* matters on silicon, grouped so that order lives in one place
8//! (the implementation) and the state machine only decides which step comes
9//! next.
10
11/// Controller steps and system services the state machine needs.
12///
13/// Nothing here blocks beyond a short bounded poll: every method is called
14/// from the CD interrupt handler or from a foreground section that has the
15/// CD source masked.
16pub trait CdHw {
17    /// Whether to record controller events through [`trace`](Self::trace).
18    /// Constant per implementation so the unused event words fold away.
19    const TRACE: bool = false;
20
21    /// Send one drive command and arm the controller to interrupt for its
22    /// responses. Returns `false` when the parameter FIFO never had room (the
23    /// command is not sent).
24    ///
25    /// The order is: mask the controller's interrupt output, acknowledge
26    /// every pending flag and the CPU-side pending bit, discard any response
27    /// bytes, empty the parameter FIFO, push the parameters, write the
28    /// command byte, then enable the controller's interrupt output. Silicon
29    /// is picky about it (the SDK's polled reader does the same).
30    fn issue(&mut self, command: u8, params: &[u8]) -> bool;
31
32    /// The controller's current interrupt flag (0 none, 1 data ready, 2
33    /// complete, 3 acknowledge, 5 error).
34    fn interrupt_code(&mut self) -> u8;
35
36    /// The first two response bytes of a drive error: status and error code.
37    fn error_response(&mut self) -> (u8, u8);
38
39    /// Pop and discard the response FIFO.
40    fn discard_response(&mut self);
41
42    /// Acknowledge interrupt flag `bits` on the controller and the CPU-side
43    /// pending bit. `acknowledge(0)` only clears the CPU-side bit.
44    fn acknowledge(&mut self, bits: u8);
45
46    /// Mask the controller's interrupt output, so nothing more is raised
47    /// until the next [`issue`](Self::issue).
48    fn silence_output(&mut self);
49
50    /// Drop a data request left armed by the previous transfer. Called
51    /// before the first command of a transfer that did not start from a
52    /// recovery pause.
53    fn drop_data_request(&mut self);
54
55    /// Pop one sector's 2048 bytes from the data FIFO as 512 little-endian
56    /// words, storing the first `store_words` of them at `destination`.
57    /// The rest are popped and dropped (the FIFO has to be emptied either
58    /// way). Arms the data request and waits a bounded time for the FIFO to
59    /// fill; `false` if it never does.
60    ///
61    /// # Safety
62    ///
63    /// `destination` must be valid for `store_words` word writes (it is not
64    /// used when `store_words` is 0).
65    unsafe fn pop_sector(&mut self, destination: *mut u32, store_words: usize) -> bool;
66
67    /// Let the CD interrupt source reach the CPU (or not).
68    ///
69    /// This only moves the mask. It must not acknowledge the CPU-side pending
70    /// bit: the foreground closes the source around every call, and an
71    /// interrupt that arrived meanwhile has to fire when the source opens.
72    /// Stale flags are cleared by [`acknowledge`](Self::acknowledge) and by
73    /// [`issue`](Self::issue).
74    fn set_source_enabled(&mut self, enabled: bool);
75
76    /// Monotonic VBlank count, the clock the no-progress timeout runs on.
77    fn vblank_count(&mut self) -> u32;
78
79    /// A free-running timestamp for measuring the handler, wrapping at 16
80    /// bits. Implementations that do not measure return a constant.
81    fn clock(&mut self) -> u16 {
82        0
83    }
84
85    /// Record one trace word (only called when [`TRACE`](Self::TRACE) is set).
86    fn trace(&mut self, _word: u32) {}
87}