Skip to content

Crash Bandicoot: boots, plays and reaches level 3 - #2

Merged
Dellareti merged 29 commits into
mainfrom
feature/missing-functions
Sep 21, 2026
Merged

Dellareti merged 29 commits into
mainfrom
feature/missing-functions

Conversation

@Dellareti

Copy link
Copy Markdown
Member

Crash Bandicoot now boots, plays and reaches level 3. This branch collects the
recompiler, runtime and tooling work that got it there, plus the fixes found by
playing it.

What changed

Recompiler. Computed in-function jumps now resolve against local labels,
including the 8-byte stride form and the case where the stride is unrecoverable
from the code near the jump. A function whose $ra is hijacked resumes inside
itself instead of unwinding past its own epilogue. Every indirect jump and call
carries its originating guest address, and an unresolved dispatch prints that
address plus a host stack: the guest $ra is stale on direct-JAL paths and had
sent more than one investigation to the wrong function.

Analyzer. A PsyQ hash match is only marked HLE when the runtime actually
registers a body for it, so detection stays broad while substitution stays
narrow. Linear sweep with validation recovers functions the prologue scan
misses, and computed jump-array slots are treated as entry points.

Runtime. Three defects that each blocked play:

  • The CD-ROM state machine ticked on the render thread while the game thread
    read its sector buffer, so a sector could be spliced from two reads. That fed
    the LZ decompressor a corrupt page, its terminating count was never reached,
    and it wrote bytes until it had wrapped 2 MB of guest RAM. Measured: 10
    crashes in 38 runs before, 0 in 16 after serialising the hand-off. The
    decompressor drain suppression that had been papering over this is gone.
  • The hardware tick ran once per presented frame, which tied the root counters
    to the compositor. Play sessions measured between 32 and 54 presented frames
    per second, so the clock Crash reads for velocity lost up to a third of its
    rate and the game moved in slow motion. It now runs off the wall clock:
    measured 58.5 hardware ticks per second across runs presenting between 21.8
    and 56.5 frames per second.
  • The GTE perspective divide skipped both Newton-Raphson refinement steps, so
    every projected vertex collapsed onto the origin. Measured: 99.6% of ~800k
    triangles degenerate.

Sound effects work: the SPU transfer address register now reads back, which is
what the driver polls before programming DMA, and the DMA writes through that
address instead of restarting every upload at sound RAM zero.

Memory card. Implemented against the psx-spx protocol: read, write and get
ID, with the acknowledge bytes, the confirmed address echo, checksum rejection
and the directory-unread flag. A fresh card is formatted as a real one is.
Cards live in memcards/ and a written sector is flushed immediately, because
shutdown skips destructors.

Diagnostics. A write guard that reports every distinct writer to a span of
guest RAM with the value written, a stall sampler that names the function the
game thread is stuck in, per-voice SPU counters and callback-registration
counters. All are off unless their environment variable is set.

Testing

707 tests pass. New coverage for the GTE divide, pad polarity, the memory card
protocol byte by byte, the SPU transfer address and key latch, the CD-ROM
sector hand-off, and the indirect-site reporting.

Play-tested to level 3, including the bonus round and the save point.

Known gaps

  • No background music. The sequencer tick is never installed, so voices 0-15
    are never keyed on while effects on 16-19 work.
  • The attract-mode video decodes to noise; the MDEC decoder is still open.
  • Load game shows a black screen. Measured: the game issues no memory card
    command at all, so the call never reaches the card.
  • Occasional freezes during play, not yet localised.

@Dellareti
Dellareti merged commit ab4f0e0 into main Sep 21, 2026
2 checks passed
@Dellareti
Dellareti deleted the feature/missing-functions branch September 21, 2026 02:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant