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

Crate psx_cdstream

Crate psx_cdstream 

Source
Expand description

Interrupt-driven CD-ROM sector streaming.

The SDK’s SectorReader reads a disc by waiting: fine at boot, wrong in the middle of a game, where the drive delivers a sector every 6.5 ms and a frame loop that looks once per frame loses most of them. This crate reads the way a streamer has to: you queue Requests, the CD interrupt handler pops one sector per interrupt straight into the request’s destination, and the foreground only submits, cancels and asks how far a request has got. Nothing busy-waits for the drive.

§What it does

  • PIO, one sector per interrupt. The sector is popped from the data FIFO by the CPU. Chopped CD DMA (channel 3) is unreliable on a console; the PIO path is the one that has loaded byte-perfect streams there. The price is CPU time while a read runs (about 1.3 ms per sector more than a working DMA is the figure on record), so read in bursts when there is work, not continuously.
  • Seek first. Every transfer is Setloc, SeekL, Setmode (double speed), ReadN: the bracket the BIOS uses. A bare Setloc plus ReadN starts delivering while the mechanism is still settling and corrupts a long stream on a console.
  • Abort at the next sector. Engine::cancel only sets a flag; the handler drops the next sector and pauses the drive itself. (A Pause sent from the foreground while sectors were arriving lost its acknowledge on silicon.) The request ends Outcome::Cancelled with the sectors that had landed; Request::remaining_after builds the request that continues it.
  • A small priority queue. QUEUE_DEPTH requests wait behind the active one, most urgent Priority first.
  • Contiguous chaining. A queued request that starts at the sector after the active one’s last continues without a Pause or a seek: the handler swaps the destination and keeps popping. A layout-ordered group of regions costs one seek.
  • Resume. A request can carry a resume budget (Request::with_resumes): after a drive error the transport pauses, seeks back to lba + received and carries on.
  • A drive arbiter. CD-DA and XA playback and data reads cannot share the laser. Engine::request_audio_lease stops the read in flight, waits for the drive to stop, closes the CD interrupt source and (on the console) hands the controller token to the audio code; releasing the lease takes it back and queued reads carry on. End audio with Pause, never Stop: after Stop the motor spins down, reports status 0 for a second or two, and reads started then failed on a console. A lease that is asked for and left pending is granted the moment the drive stops, ahead of any read queued meanwhile. Audio that must not hold up reads uses Engine::try_audio_lease, which takes the drive only if it is free and leaves nothing pending, or ends the pending request with Engine::withdraw_audio_lease.

§Use

ⓘ
// After the polled boot reads are done (SectorReader::release gives the
// token back):
psx_cdstream::install(cd, psx_cdstream::Config::DEFAULT).ok();

// SAFETY: ROOM is not touched until the request has finished.
let request = unsafe { Request::new_raw(lba, sectors, ROOM.as_mut_ptr().cast()) };
let ticket = psx_cdstream::submit(request.with_priority(Priority::URGENT))?;

// Each frame:
if let RequestState::Finished(done) = psx_cdstream::state(ticket) {
    // done.outcome, done.received
}

§How it is built

Engine is the whole state machine, generic over CdHw, the controller as it sees it. On the console install puts an exception wrapper in front of psx-rt’s handler that calls the one global engine once per CD interrupt, and the free functions (submit, state, …) reach it with the CD source closed. On the host the tests drive the same engine against a scripted drive, so every phase, cancel point, error path, chaining rule and lease transition is exercised without hardware. The counters are published as PSX_CD_STATS (StreamStats) for tools that read guest memory.

Boot-time and blocking loads still use psx_io::cd::reader::SectorReader (or psx_pack::cd): it needs the controller token, and so does install, so the compiler keeps the two from sharing the drive. uninstall hands the token back.

Structs§

Completion
A finished request.
Config
How the engine behaves.
Engine
The CD transport.
Failure
A transfer failure, as the code the transport records for it.
Mmio
The CD-ROM controller, through the SDK’s register steps.
Priority
How urgent a request is. Lower numbers are served first.
Request
A run of sectors to read into memory.
StreamStats
Counters, published as one block (PSX_CD_STATS) for tools that read guest memory. All wrap at 2^32.
Ticket
Names a submitted request.

Enums§

FailureKind
What a Failure code says.
IrqMaskPolicy
Whether the CD interrupt source stays open between transfers.
LeaseState
Where an audio lease request stands.
Outcome
How a request ended.
Owner
Who may program the controller.
Phase
Where the controller is in a transfer. The numbers are published in PSX_CD_STATS and match the earlier game-local transports.
RequestState
Where a request is in its life.
SubmitError
Why a request was not accepted.

Constants§

HANDLER_STACK_BYTES
Bytes of private stack the handler runs on.
QUEUE_DEPTH
Requests that can wait behind the active one.
RECENT_RESULTS
Finished requests whose results Engine::state still remembers.
SECTOR_BYTES
Bytes in one data sector.
SECTOR_WORDS
Words in one data sector.

Statics§

PSX_CD_STATS
The counters, as one block for tools that read guest memory: StreamStats with its field order. Updated after every interrupt and every foreground call.
PSX_CD_TRACE
The last 128 controller events (feature trace): kind << 24 | phase << 16 | (flag or command) << 8 | received & 0xff.
PSX_CD_TRACE_N
Events recorded so far (feature trace); the next slot is n & 127.

Traits§

CdHw
Controller steps and system services the state machine needs.

Functions§

cancel
Cancel a read. See Engine::cancel.
cancel_all
Cancel everything. See Engine::cancel_all.
configure
Change the configuration; it applies from the next event. See Engine::configure. (Config::time_handler is only read by install.)
handler_stack_unused_bytes
Bytes of the handler’s private stack never touched since install painted it. The handler’s own frames plus the saved-context area must fit in the rest; a value near 0 means it overflowed.
install
Take over the CD-ROM controller: put the exception wrapper in front of psx-rt’s handler and start serving requests.
is_idle
Whether the drive is stopped and no read holds it.
lease_state
Where the lease stands.
owner
Who may program the controller.
phase
The controller phase.
queued_count
Reads waiting behind the active one.
release_audio_lease
End the lease: hand the controller back after the audio code has ended playback with Pause (not Stop). Gives the token back if there was no lease to end.
request_audio_lease
Ask for the drive on behalf of CD-DA or XA playback. See Engine::request_audio_lease; once this reads Granted, collect the controller token with take_audio_lease.
reset_max_irq_ticks
Start the longest-handler measurement over. See Engine::reset_max_irq_ticks.
service
Check for a stalled transfer. See Engine::service.
state
Where a read is. See Engine::state.
stats
A copy of the counters.
submit
Queue a read. See Engine::submit.
take_audio_lease
The controller token, once the lease is granted (and not yet taken). The audio code programs the controller through it until it hands it back with release_audio_lease; the CD interrupt source stays closed meanwhile.
try_take_audio_lease
Take the drive for audio only if it is free right now, in one step: the controller token if the lease was granted, None if a read is in flight. Nothing is left pending and the read is not aborted, so a read submitted afterwards is never parked behind a lease granted later. See Engine::try_audio_lease; end the lease with release_audio_lease.
uninstall
Give the controller back to polled code. Succeeds only when the transport is idle with nothing queued; call cancel_all and poll is_idle first. The wrapper stays in the exception vector (a few instructions per exception) but the CD source is closed.
withdraw_audio_lease
Withdraw a lease that was asked for and has not been granted. Returns whether one was pending. See Engine::withdraw_audio_lease.