feat(pif): report "no device" on empty ports — SM64 renders its title screen (R-18) - #190
Conversation
…e screen Super Mario 64 renders its title screen (screenshots/super-mario-64-title.png): Mario's head, textured cap with the M logo, over the tiled SUPER MARIO 64 background. 125,278 RDP commands, 138,474/148,125 pixels lit at 625x237, through the full LLE path. Viewed and confirmed, not counted. The unblocking defect was in the PIF, not the RDP. SM64 was halting in its own assert path -- a B -1 self-loop at 0x80246DD8, reached by falling through BNE t1, zero, +4 where t1 is a byte at 0x8032D590 that is never written -- immediately after an osCreateThread call. Our PIF answered the 0x00/0xFF info command as a connected controller on ALL FOUR joybus channels, so osContInit reported four pads on a one-pad console. PIF-NUS.md, RX byte: special flags, is explicit: bit 7 (0x80) is "set if the handshake failed because no device appears to be connected to the joybus channel". We never set it. A second, pre-existing defect sat next to it. mark_no_device wrote the flag to resp - 1, which for a block laid out TX RX tt[tx_len] rr[rx_len] with resp = i + 2 + tx_len is the LAST TX DATA BYTE, not the RX byte at i + 1. Since run_channel returns early on tx_len == 0 the two offsets could never coincide, so the flag had never once landed where software reads it -- while a doc comment asserted it did. Both fixed and separately mutation-checked. The second test exists only because the first mutation PASSED: the empty-port guard short-circuits before run_channel, so nothing exercised mark_no_device at all until a test was written for a connected channel given an unsupported command. Measured effect: Super Mario 64 0 -> 125,278 RDP commands and a title screen; Banjo-Kazooie 0 -> 133,625 commands and real 3D geometry, committed as a known-imperfect frame (geometry, textures and depth right; colours carry a blue/yellow cast, an open combiner/texel-format issue). A measurement trap is recorded with it: a 240-frame sample reported SM64 at scanout 0x0 and looked like a geometry failure. It was a transient -- one frame with H_VIDEO = 0 mid-reprogram of the VI. Sampling at 60/120/180/300 shows a stable 625x237 throughout. Still open: Jet Force Gemini and Banjo-Tooie remain at 0 RDP commands, and 1080 Snowboarding still faults in IPL3 on an odd DMEM address. Gates: fmt, clippy -D warnings, cargo test --workspace, rustdoc -D warnings, markdownlint, n64-systemtest (Phase 1 Failed: 0, suite-wide 90) -- all green. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
📝 WalkthroughSummary by CodeRabbit
WalkthroughPIF now tracks connected controller ports and reports absent devices through the correct RX-byte flag. Tests cover the corrected response layout and dispatch behaviour. R-18 records and screenshot documentation now include commercial-title rendering evidence and related accuracy findings. ChangesPIF controller handling and R-18 evidence
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant PifExecute
participant ControllerPort
participant ResponseBuffer
PifExecute->>ControllerPort: inspect connected state
ControllerPort->>ResponseBuffer: set RX_NO_DEVICE on RX byte
ResponseBuffer-->>PifExecute: return channel response
🚥 Pre-merge checks | ✅ 7 | ❌ 3❌ Failed checks (3 warnings)
✅ Passed checks (7 passed)
Comment |
Adopts three Antigravity suggestions. set_controllers_connected / controllers_connected replace the hardcoded private field, so a frontend can attach pads to ports 2-4 instead of the PIF permanently reporting single-player. The empty-port path now delegates to mark_no_device(i + 1) rather than poking ram directly, centralising the bounds check. This also strengthened the mutation check: reverting the offset now turns BOTH no-device tests red rather than one, because the two paths share the write. The tests derive the RX-byte offset from the documented frame layout (SKIPS + 1) instead of counting backwards from resp with magic subtraction, and assert the layout itself so the derivation cannot drift silently. Gates: fmt, clippy -D warnings, cargo test --workspace, rustdoc -D warnings -- all green. Both mutations re-checked after the refactor. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adjudication — Antigravity reviewNo blocking issues. All three suggestions adopted. 1. No API to configure connected controllers — adoptedCorrect, and it would have been a real limitation: 2. Bypassing the
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/rustyn64-cart/src/pif.rs`:
- Around line 521-528: Update the documentation around Pif::mark_no_device to
remove the claim that the connected unsupported-command path is its only route.
Describe it specifically as the connected-controller unsupported-command route,
while acknowledging that the missing-EEPROM path also reaches mark_no_device.
- Around line 116-133: Add a controller dispatch test covering
set_controllers_connected: enable port 1, send its info handshake through the
PIF dispatch path, and assert the expected controller ID plus an RX byte without
error flags. Ensure the test fails when the configured presence mask is ignored,
while preserving the default controller behavior for existing tests.
In `@docs/accuracy-ledger.md`:
- Line 413: Update the later historical passage about `tlut_en` so it no longer
says the field remains undecoded; preserve the surrounding historical wording
and clarify that `tlut_en` is decoded while retaining the documented limitation
that the committed vector does not independently validate its gating behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: ad312a15-8e34-4520-a890-ed73e378b068
⛔ Files ignored due to path filters (2)
screenshots/banjo-kazooie-first-3d-scene.pngis excluded by!**/*.pngscreenshots/super-mario-64-title.pngis excluded by!**/*.png
📒 Files selected for processing (4)
CHANGELOG.mdcrates/rustyn64-cart/src/pif.rsdocs/accuracy-ledger.mdscreenshots/README.md
Adopts three CodeRabbit findings. set_controllers_connected had no test -- every controller test ran on the default mask, so a no-op setter would have passed. the_configured_port_mask_ reaches_the_joybus_dispatch inverts the default (port 0 empty, port 1 populated) and asserts BOTH directions from one setter call, so a setter writing a constant cannot satisfy it. Mutation-checked: stubbing the setter to a no-op turns it red. mark_no_device's doc claimed the connected/unsupported-command path was its ONLY route; a missing EEPROM on channel 4 reaches it too. Corrected to say what is actually true -- it is the route this test drives, and it was the only route any test could take before the empty-port guard was refactored to delegate. Ledger R-18 said "tlut_en remains undecoded" in one clause while recording it as FIXED in #185 in another. Labelled as the historical statement it was, rather than rewritten, per the append-only rule the row follows. Gates: fmt, clippy -D warnings, cargo test --workspace, rustdoc -D warnings, markdownlint -- all green. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Antigravity review (Gemini via Ultra)This PR configures joybus channels 2–4 as disconnected by default in the PIF and fixes Blocking issuesNone found. Suggestions
Nitpicks
Automated first-pass review by |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/rustyn64-cart/src/pif.rs (1)
292-310: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winUpdate the cart/PIF spec and oracle note
crates/rustyn64-cart/src/pif.rschanges behaviour, but this commit only editsdocs/accuracy-ledger.mdfor R-18.docs/cart.mdis still untouched, and there is no PIF-specificn64-systemtestimpact note here (or an explicit “not measured” entry) for this change.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/rustyn64-cart/src/pif.rs` around lines 292 - 310, Update the documentation alongside the PIF behavior change in `pif.rs`: document the empty-controller-channel handling and channel 4 exception in `docs/cart.md`, and add a PIF-specific `n64-systemtest` impact note in the relevant accuracy documentation, explicitly marking it as not measured if no result is available.Sources: Coding guidelines, Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/accuracy-ledger.md`:
- Line 413: Remove the unreleased “v0.6.0” version reference from the R-18 entry
in the accuracy ledger. Replace it with an unversioned description of shipping
based on the committable gates and honest “boots and executes” capstone,
preserving the surrounding historical context.
---
Outside diff comments:
In `@crates/rustyn64-cart/src/pif.rs`:
- Around line 292-310: Update the documentation alongside the PIF behavior
change in `pif.rs`: document the empty-controller-channel handling and channel 4
exception in `docs/cart.md`, and add a PIF-specific `n64-systemtest` impact note
in the relevant accuracy documentation, explicitly marking it as not measured if
no result is available.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 6173be44-3899-4d1a-9b66-44abfc524652
📒 Files selected for processing (2)
crates/rustyn64-cart/src/pif.rsdocs/accuracy-ledger.md
* chore(release): v0.8.0 "Breadth" -- Phase 7 Cuts the Phase 7 release. Both cut criteria from to-dos/VERSION-PLAN.md are met and were verified rather than assumed: - The battery reports a real pass rate: 54 probes, 100%, across two Angrylion oracle suites (41 RDP rasteriser vectors + 13 VI scan-out vectors). - Every residual R-1 through R-23 carries a ledger disposition, and no residual is referenced anywhere in docs/ or to-dos/ without a ledger entry. The headline is that commercial cartridges render. Super Mario 64 draws its title screen and 29 of 66 staged titles render through their own graphics microcode. Both defects that unblocked that were in the CPU and the PIF, not the RDP where R-18 had been looking: - an interrupt taken across an ERET was charged to the ERET, overwriting EPC with the ERET's own address and livelocking the CPU (#189); - the PIF answered as a connected controller on all four joybus channels, so osContInit reported four pads on a one-pad console and Super Mario 64 halted in its own assert (#190). T-71-003 -- the one cut criterion CI can never run, because F3DEX ships inside ROMs ADR 0008 forbids committing -- closes on a committed local census plus 14 viewed screenshots, recorded in VERSION-PLAN as the single documented exception rather than an unstated weakening of the gate. Version bumped 0.7.0 -> 0.8.0 across the workspace and all path dependencies; CHANGELOG [Unreleased] cut to [0.8.0]; STATUS records Phase 7 complete and the release history through v0.8.0. Pre-release gate: clean tree, version consistent (Cargo == CHANGELOG), no stale 0.7.0 in manifests, v0.8.0 tag free, no ROMs staged, no conflict markers, CHANGELOG entry present, no_std build green. Plus fmt, clippy -D warnings, cargo test --workspace, rustdoc -D warnings, markdownlint. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(changelog): 'unblocked it', not 'unblocked that' Adopts a CodeRabbit wording fix in the v0.8.0 release note. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Super Mario 64 renders its title screen. Mario's head, textured cap with the M logo, over the tiled SUPER MARIO 64 background —
screenshots/super-mario-64-title.png. 125,278 RDP commands, 138,474/148,125 pixels lit at 625×237, through the full LLE path. Viewed and confirmed, not counted.The unblocking defect was in the PIF, not the RDP
SM64 was halting in its own assert path — a
B -1self-loop at0x80246DD8, reached by falling throughBNE t1, zero, +4wheret1is a byte at0x8032D590that is never written — immediately after anosCreateThread(..., pri=100)call.Cause: our PIF answered the
0x00/0xFFinfo command as a connected controller on all four joybus channels, soosContInitreported four pads on a one-pad console.n64brew_wiki/markdown/PIF-NUS.md§RX byte: special flags is explicit:We never set it.
A second, pre-existing defect sat next to it
mark_no_devicewrote the flag toresp - 1. For a block laid outTX RX tt[tx_len] rr[rx_len]withresp = i + 2 + tx_len, that is the last TX data byte, not the RX byte ati + 1. Sincerun_channelreturns early ontx_len == 0, the two offsets could never coincide — so the flag had never once landed where software reads it, while a doc comment asserted it did.Mutation-checked — and the second test exists because the first mutation PASSED
mark_no_deviceoffsetThe empty-port guard short-circuits before
run_channel, so nothing exercisedmark_no_deviceat all.mark_no_device_flags_the_rx_byte_not_the_tx_payloadreaches it via a connected channel given an unsupported command, and uses a two-byte TX soresp - 1and the RX byte are two apart — with a one-byte TX an off-by-one is indistinguishable from a correct write. Both mutations are now caught.Measured effect
Banjo-Kazooie is committed as a known-imperfect frame: geometry, textures and depth ordering are right; colours carry a heavy blue/yellow cast (open combiner/texel-format issue). It is evidence of what currently happens, not a correctness target.
Oracle unchanged: n64-systemtest Phase 1
Failed: 0, suite-wide 90.A measurement trap, recorded
A 240-frame sample reported SM64 at
scanout = 0x0and looked like a geometry failure. It was a transient — one frame withH_VIDEO = 0mid-reprogram of the VI. Sampling at 60/120/180/300 shows a stable 625×237 throughout. A single-point sample of a value the guest rewrites can land on the rewrite.Still open
Jet Force Gemini and Banjo-Tooie remain at 0 RDP commands; 1080 Snowboarding still faults in IPL3 on an odd DMEM address. Separate causes, recorded in R-18.
Gates
fmt · clippy
-D warnings·cargo test --workspace· rustdoc-D warnings· markdownlint · n64-systemtest — all green. No ROMs committed; only rendered output, which thecommercial-romspolicy permits.