Skip to content

Phase 2 Sprint 1: the RSP scalar unit executes (T-21-002/004/005) - #36

Merged
doublegate merged 4 commits into
mainfrom
feat/rsp-sp-interface
Jul 21, 2026
Merged

Phase 2 Sprint 1: the RSP scalar unit executes (T-21-002/004/005)#36
doublegate merged 4 commits into
mainfrom
feat/rsp-sp-interface

Conversation

@doublegate

Copy link
Copy Markdown
Owner

Motivation

Phase 2 Sprint 1: the RSP executes code. T-21-002 (SP interface registers), T-21-004 (the scalar ISA) and T-21-005 (BREAK, halt, and the MI path).

before after
n64-systemtest, suite-wide 409 250
n64-systemtest, spmem 13 0
n64-systemtest, SP 15 0
Phase 1 categories 0 0
Golden log vs ares 0-diff 0-diff
Suite runtime 134s 87s

The run is a full 917 tests — see the note on truncation below, which is the most interesting thing in this PR.

The scalar unit

The documented MIPS subset, with the absences that matter: no multiply/divide unit at all (MULT, DIV, MFHI, … and HI/LO themselves), no 64-bit anything, no LWL/LWR, no traps, no likely branches. There is no exception mechanism, which has a consequence worth stating rather than leaving implicit: ADD and ADDI cannot trap on overflow, so they are the same instruction as ADDU/ADDIU.

Two rules separate this from a CPU core reused wholesale, and both are pinned against the suite's own cases:

  • The PC is 12 bits and wraps. Targets lose every high bit; running past 0xFFC continues at 0x000. RSP Wrap around puts nops at 0xFF8 and a BREAK at 0x000 and expects to stop at 0x4.
  • Misaligned data accesses are correct, not faults. LW at 0x001 returns the bytes at 0x1..=0x4, and each byte address wraps inside DMEM independently, so a word read at 0xFFE takes two bytes from the end and two from the start. The identical access on the VR4300 is an AddressError — the easiest place to get the RSP wrong.

The SP interface

SP_STATUS reads as a flag word and writes as set/clear command pairs. That asymmetry is the design, not an encoding quirk: it lets either processor change one flag with a single store, with no read-modify-write to race the other. The rule that falls out is the one a "clear then set" implementation silently gets wrong — writing a flag's set and clear bits together leaves it unchanged.

The DMA engine moved into the RSP crate and returns a description the Bus executes, matching the PI, since the RSP does not own RDRAM. That move surfaced two bugs: the length field rounded down (hardware transfers 8 bytes for any value 0–7, so the suite's length = 11 case lost its tail), and the address registers were not double-buffered.

Three finds, none of them in the RSP itself

1. SP_SEMAPHORE was taken four times per word read. It acquires the mutex on read, and read_u32 composed a word from four byte reads — the first saw 0, the rest saw 1, and the word came back as 1 where hardware returns 0. On hardware the RCP returns the whole aligned word for one access regardless of size, so one access is the correct model.

2. The MI register block did not exist. MI_INTERRUPT was unreadable, so a guest could raise the SP line and never observe it — which is why SP Set/Clear Interrupt failed even though the line was being set correctly all along. MODE/VERSION/INTERRUPT/MASK are implemented with their documented 4-bit mirroring.

3. A hot-path allocation, caught because its own comment was wrong. rsp_tick moved the chip out of the Bus with core::mem::take under a comment reading "No allocation" — but take needs Default, and constructing an Rsp allocates DMEM and IMEM. Every RCP step allocated and freed 8 KiB. Rsp::tick now returns what it wants done instead of borrowing its owner, so there is nothing to move. That supersedes the RspBus trait, deleted rather than left unused.

The truncation, which is the point

Committing T-21-002 alone dropped the failure count from 409 to 96 — and that was not progress. The old SP_STATUS was a stub that always read HALTED, so the suite's wait_until_rsp_is_halted() returned instantly every time. Once clearing HALT actually cleared it, and nothing set it back because the RSP still executed nothing, the suite span forever at the first test that starts the RSP.

The committed runner caught it: 635 of 917 tests started. Had it only counted failures, this would have looked like a 313-test improvement and been reported as one. That intermediate commit is kept, with the diagnosis in its message, because the failure mode is more useful recorded than reconstructed.

Deliberately not done

  • MI_MODE's RDRAM repeat-write mode. The five MI Repeat failures are its; that is RI-domain transfer behaviour, not the RSP's.
  • The vector unit. COP2 retires inertly, which is why 156 RSP failures remain. Sprint 2.
  • MI_MASK set-and-clear-together. Unlike SP_STATUS, the wiki does not state what that does, so the code applies clear before set rather than inventing a rule, and says so.

Verification

Gates on the final commit: cargo fmt --all --check, cargo clippy --workspace --all-targets -- -D warnings, cargo test --workspace (421 tests), RUSTDOCFLAGS="-D warnings" cargo doc, the no_std build, pre-commit run markdownlint --all-files, plus both #[ignore]d oracles.

🤖 Generated with Claude Code

doublegate and others added 2 commits July 21, 2026 10:39
Eight registers at 0x0404_0000 plus SP_PC at 0x0408_0000 -- which is in its own
window, not the ninth slot of the block. The same physical registers are exposed
to the RSP as COP0 c0-c7, so `sp.rs` holds one copy and both views reach it.

`SP_STATUS` reads as a flag word and writes as set/clear command pairs. That
asymmetry is the design rather than an encoding quirk: it lets either processor
change one flag with a single store, with no read-modify-write to race the
other. The rule that falls out is the one that catches naive implementations --
writing a flag's set and clear bits **together leaves it unchanged**, which a
"clear then set" implementation silently turns into a set. n64-systemtest checks
it for every reachable flag, including all eight signal bits, whose commands sit
at 9 + 2n / 10 + 2n while the flags themselves are at 7 + n.

The interrupt commands are not a `SP_STATUS` flag at all: they raise and
acknowledge the MI's SP line. The register file reports the change and the Bus
applies it, kept separate from the DMA return because one write can do both.

Semantics taken from n64-systemtest's own header comment where the wiki is
thinner -- the semaphore is released by a write *whatever value is written*, and
a read returns the current value then takes it, so the sequence is write, 0, then
1 for ever.

The DMA engine moves into the RSP crate and returns a description the Bus
executes, matching the PI: the RSP does not own RDRAM, and a chip reaching back
into its owner is the cycle the architecture exists to prevent. Two bugs fixed
in the move: the length field now rounds **up** to a multiple of 8 (hardware
transfers 8 bytes for any value 0..=7, and rounding down turned the suite's
`length = 11` case into 8 bytes and dropped the tail), and the address registers
are double-buffered, so reads report the ongoing or last-completed transfer
rather than a pending write.

**This truncates the n64-systemtest run, and that is the point of committing it
with the SU still missing.** The old `SP_STATUS` was a stub that always read
HALTED, so the suite's `wait_until_rsp_is_halted()` returned instantly every
time. Now that clearing HALT actually clears it -- and nothing sets it back,
because the RSP still executes nothing -- the suite spins at the first test that
starts the RSP: 635 of 917 tests start, against 917 before. The committed gate
catches this and fails rather than reporting the resulting lower failure count
as progress, which is exactly what it was written for.

T-21-004 and T-21-005 (the scalar unit and BREAK) are what restore completion.
No PR until they land and the suite runs to 917 again.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…21-005)

The RSP runs code. The SU implements the documented MIPS subset, `BREAK` halts
and latches BROKE, `MFC0`/`MTC0` reach the SP registers, and the MI register
block exists so the CPU can see the SP interrupt line at all.

n64-systemtest: **409 -> 250 failures across a full 917-test run.** The `spmem`
and `SP` categories are now at **zero**; the remaining RSP failures are the
vector unit (Sprint 2). Phase 1 categories stay at 0 and the golden log holds
its 0-diff.

Two rules separate this from a reused CPU core, and both are pinned:

  - The PC is 12 bits and **wraps**. Targets lose every high bit and running
    past 0xFFC continues at 0x000 -- the suite's `RSP Wrap around` puts nops at
    0xFF8 and a BREAK at 0x000 and expects to stop at 0x4.
  - Misaligned data accesses are **correct, not faults**. `LW` at 0x001 returns
    the bytes at 0x1..=0x4, and each byte address wraps inside DMEM
    independently, so a word read at 0xFFE takes two bytes from the end and two
    from the start. The identical access on the VR4300 is an AddressError.

There is no exception mechanism at all on this core, which has a consequence
worth stating rather than leaving implicit: `ADD` and `ADDI` cannot trap on
overflow, so they are the same instruction as `ADDU`/`ADDIU`.

**Two bugs found by the oracle, both in the CPU-side plumbing rather than the
RSP:**

`SP_SEMAPHORE` was being taken four times per word read. It has a side effect on
read -- it acquires the mutex -- and `read_u32` composed a word out of four byte
reads, so the first byte saw 0 and the rest saw 1 and the assembled word came
back as 1 where hardware returns 0. On hardware the RCP returns the whole
aligned word for one access regardless of size, so one access is the right
model. Registers with read side effects now take exactly one.

The MI register block did not exist. `MI_INTERRUPT` was unreadable, so a guest
could raise the SP line and never observe it -- which is why `SP Set/Clear
Interrupt` failed even though the line was being set correctly. MODE/VERSION/
INTERRUPT/MASK are implemented with their documented 4-bit mirroring. `MI_MODE`'s
RDRAM **repeat mode** is deliberately not modelled: it is an RI-domain transfer
feature, and the five `MI Repeat` failures are its, not the RSP's.

**And one performance trap, caught by its own comment being wrong.** `rsp_tick`
moved the whole chip out of the Bus with `core::mem::take` under a comment
reading "No allocation" -- but `take` needs `Default`, and constructing an `Rsp`
allocates DMEM and IMEM, so every RCP step allocated and freed 8 KiB. `Rsp::tick`
now returns what it wants done instead of borrowing its owner, so there is
nothing to move. The suite run dropped from 134s to 87s.

That change supersedes the `RspBus` trait, which is deleted rather than left
unused: the DMA path returns a description and the interrupt is reported, so
nothing implemented it any more.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: cb6d39a8-015a-4df7-a760-81941d05dfb0

📥 Commits

Reviewing files that changed from the base of the PR and between 280d3e0 and 6ffc846.

📒 Files selected for processing (1)
  • crates/rustyn64-rsp/src/su.rs

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added RSP scalar-unit emulation with instruction stepping, delay-slot branching, BREAK/BROKE handling, and COP0 SP register access.
    • Implemented a richer SP interface register model, including semaphore “first-read” acquisition, SP interrupt command behavior, and DMA descriptors.
  • Bug Fixes
    • Improved SP/MI register read/write semantics, interrupt-change reporting, and DMA completion/status behavior.
    • Corrected PC wraparound and DMEM misaligned/edge access behavior.
  • Documentation
    • Expanded RSP and SP interface/su behavior specification.
  • Tests
    • Updated and extended RSP/SP DMA and semaphore-related tests to match the new register/DMA semantics.

Walkthrough

The RSP now owns SP register state and scalar execution returns DMA and interrupt actions. The core bus consumes those actions, models SP and MI register accesses, performs banked DMA transfers, and updates interrupt state. Documentation and tests cover the revised semantics and accuracy results.

Changes

RSP execution and bus integration

Layer / File(s) Summary
SP register and DMA contract
crates/rustyn64-rsp/src/sp.rs, docs/rsp.md
SP status, semaphore, PC, DMA staging, interrupt commands, transfer geometry, and completion readback are implemented with unit coverage and documented behaviour.
Scalar execution and side-effect reporting
crates/rustyn64-rsp/src/lib.rs, crates/rustyn64-rsp/src/su.rs, docs/rsp.md
The RSP executes the implemented scalar instruction subset, including delayed branches, wrapped DMEM access, COP0 SP access, and BREAK, returning DMA or interrupt actions.
Bus register, interrupt, and DMA integration
crates/rustyn64-core/src/bus.rs
The bus consumes RSP step results, handles mirrored SP and MI register accesses, models read-once semaphore behaviour, updates MI interrupts, and executes banked two-dimensional DMA transfers.
Status and accuracy records
docs/STATUS.md
Project status records the implemented scalar unit, remaining vector-unit stub, revised system-test totals, and golden-log accuracy result.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Rsp
  participant SpRegs
  participant Bus
  participant RDRAM
  Rsp->>SpRegs: execute scalar step and update SP state
  SpRegs-->>Rsp: return DMA or interrupt action
  Rsp->>Bus: return StepResult
  Bus->>RDRAM: perform DMA transfer
  Bus->>Bus: update MI SP interrupt state
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 7 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title is relevant, but it violates the Conventional Commits format required by the title rule: type(scope): subject. Rewrite it as a Conventional Commit, e.g. "feat(rsp): implement the scalar unit and SP interface".
Changelog Entry For User-Visible Changes ⚠️ Warning CHANGELOG.md still has only the [Unreleased] heading note; HEAD~1..HEAD shows no changelog update for these user-visible RSP/SP/MI changes. Add a bullet under [Unreleased] in CHANGELOG.md summarising the RSP/SP interface, scalar ISA, and MI-path user-facing changes.
Measured, Never Tuned ⚠️ Warning FAIL: 'Measured, never tuned' is violated by SP_SEMAPHORE and the 0xFF8 DMA readback rule; neither has a manual/wiki citation or an accuracy-ledger entry. Add a source citation to the exact wiki/manual section, or add a ledger entry with how each was measured and the ROMs used.
✅ Passed checks (7 passed)
Check name Status Explanation
Description check ✅ Passed The description is clearly about the RSP scalar unit, SP interface, and MI path, so it matches the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Oracle Number Is Stated ✅ Passed PASS — the PR text states n64-systemtest suite-wide failures dropped 409→250, and docs/STATUS.md records 250 as the current oracle figure.
Docs-As-Spec Sync ✅ Passed PASS: the observable RSP/SP changes are mirrored in docs/rsp.md (SP interface, semaphore, DMA, BREAK/halt, scalar unit) and docs/STATUS.md; no separate docs/core.md exists.
Unsafe Stays Out Of The Chip Crates ✅ Passed No real unsafe syntax appears in the PR diff; the only hit is a comment, and no #![forbid(unsafe_code)] gate was removed.

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements the RSP scalar unit and the SP interface registers, replacing the previous stubs and eliminating costly allocations during RSP ticks. The SP interface registers (including status, semaphore, and double-buffered DMA) and the MIPS-like scalar unit are fully modeled and tested. The review feedback suggests improving the interrupt signaling mechanism by replacing the simple boolean raise_interrupt with an Option<bool> to support both raising and clearing the SP interrupt line. Additionally, it is recommended to mask the SP DMA skip parameter with !7 to enforce the hardware's 8-byte alignment contract.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread crates/rustyn64-rsp/src/su.rs Outdated
Comment thread crates/rustyn64-rsp/src/su.rs Outdated
Comment thread crates/rustyn64-rsp/src/su.rs Outdated
Comment thread crates/rustyn64-core/src/bus.rs Outdated
Comment thread crates/rustyn64-rsp/src/sp.rs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 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-rsp/src/sp.rs`:
- Around line 128-140: Update SpRegs::new() to initialize semaphore as taken so
the first un-written semaphore read returns 1. Add a test covering a read
immediately after construction, while preserving the existing behavior that a
semaphore write clears it for the next read.

In `@crates/rustyn64-rsp/src/su.rs`:
- Around line 330-344: Update cop0_write to propagate both interrupt raise and
clear results from SpRegs::interrupt_change through StepResult, including
Some(false) for CLR_INTR, so Bus::rsp_tick can lower mi_intr.sp consistently
with Bus::sp_register_write. Remove the raise-only handling while preserving
existing SP register writes and invalid-index behavior.
- Around line 41-47: Update Bus::rsp_tick() to propagate the result of
SpRegs::interrupt_change(), assigning the MI SP interrupt line from its returned
boolean for both Some(true) and Some(false). Preserve the existing
sp_register_write() behavior so CLR_INTR acknowledgements clear mi_intr.sp as
required by the SP_STATUS contract.

In `@docs/STATUS.md`:
- Line 13: Update both affected rows in docs/STATUS.md to report Phase 1
category failures and suite-wide failures as separate counts, using wording that
states 0 Phase 1 failures and 250 suite-wide failures across 917 tests started.
Replace each command with the canonical runner including --ignored --nocapture,
while preserving docs/STATUS.md as the source of truth for these counts.
- Line 187: Update the stale status statements in docs/STATUS.md, especially the
claims around lines 95-96 and 192-194, to reflect that n64-systemtest now
executes and reports 917 started tests with the documented failure count. Keep
the existing line 187 gate result and oracle counts consistent, removing
obsolete claims that COP0/COP1/exceptions are required before counts can be
reported or that the emulator cannot execute the ROM.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e07620aa-a162-4a49-ad63-510283f62bbb

📥 Commits

Reviewing files that changed from the base of the PR and between ea62e64 and bba2839.

📒 Files selected for processing (6)
  • crates/rustyn64-core/src/bus.rs
  • crates/rustyn64-rsp/src/lib.rs
  • crates/rustyn64-rsp/src/sp.rs
  • crates/rustyn64-rsp/src/su.rs
  • docs/STATUS.md
  • docs/rsp.md

Comment thread crates/rustyn64-rsp/src/sp.rs
Comment thread crates/rustyn64-rsp/src/su.rs
Comment thread crates/rustyn64-rsp/src/su.rs
Comment thread docs/STATUS.md
Comment thread docs/STATUS.md
Adopted from Gemini Code Assist review comments on #36.

`StepResult.raise_interrupt` was a `bool`, so "clear the line" and "this step
said nothing about the line" were the same value. An RSP acknowledging its own
interrupt with `MTC0 SP_STATUS` + `CLR_INTR` had that dropped: `cop0_write`
assigned false, the Bus tested `if out.raise_interrupt`, and nothing happened --
`IP2` would stay asserted for ever. The information was computed correctly by
`SpRegs::interrupt_change` and then thrown away by a lossy conversion one line
later, which is the more interesting shape of the bug.

Invisible to every test that only raises: `SP Set/Clear Interrupt` passes
because the CPU clears through its own memory-mapped path, which never went
through `StepResult` at all.

`BREAK` now reports `None` rather than false when `INTBREAK` is clear, so a
previously-raised interrupt survives a later break.

Separately, the DMA `SKIP` field is 8-byte aligned -- its low three bits "are
always 0" -- and applying that surfaced a second gap the comment did not
mention: `SKIP` was never stored, so a read-back of `SP_DMA_RDLEN` reported 0
regardless of what was programmed, against a wiki that says it survives the
transfer unchanged. Both halves now tested; the survival half is unfalsified
rather than verified, since every DMA test in the suite uses skip 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-core/src/bus.rs (1)

310-318: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Implement MI_MODE init and EBUS command pairs.

Bits 7/8 and 9/10 are documented clear/set commands for the init and EBUS state, but this path drops them; reads can therefore never report bits 7/8. Keep the explicitly deferred RDRAM mode separate, and add set/clear readback tests. (ultra64.ca)

As per path instructions, “Do not invent values/side-effects not supported by docs/tests”; model this documented register contract and cover it with a regression test.

🤖 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-core/src/bus.rs` around lines 310 - 318, Update the MI_MODE
write handling in the bus access match arm to implement the documented init and
EBUS clear/set command pairs, preserving their state for subsequent reads while
keeping deferred RDRAM-transfer modes separate. Retain ClearDP behavior, and add
regression coverage that verifies both set and clear commands update the
corresponding readback bits without introducing undocumented side effects.

Source: Path instructions

♻️ Duplicate comments (1)
crates/rustyn64-rsp/src/sp.rs (1)

127-137: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Initialise SP_SEMAPHORE as taken.

Reset currently makes the first unwritten read return 0; the documented register contract requires 1. The existing test writes first, masking the defect.

  • crates/rustyn64-rsp/src/sp.rs#L127-L137: initialise semaphore as taken.
  • crates/rustyn64-rsp/src/sp.rs#L428-L443: add a no-write read assertion before the release-on-write cases.

As per path instructions, “A comment that asserts what the code does but disagrees with it” must be treated as an independent defect.

🤖 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-rsp/src/sp.rs` around lines 127 - 137, Initialize SpRegs::new
so semaphore starts as taken, matching the documented reset contract and the
existing comment. In crates/rustyn64-rsp/src/sp.rs lines 127-137, update the
semaphore initialization; in lines 428-443, add a no-write read assertion before
the release-on-write cases to verify the initial value is 1.

Source: 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 `@crates/rustyn64-rsp/src/su.rs`:
- Around line 532-547: Update break_raises_the_interrupt_only_when_enabled to
retain the StepResult from executing BREAK with the default, disabled INTBREAK
state and assert its interrupt_change is None. Keep the existing halted
assertion and enabled INTBREAK case, ensuring both disabled and enabled paths
validate the interrupt behavior.

---

Outside diff comments:
In `@crates/rustyn64-core/src/bus.rs`:
- Around line 310-318: Update the MI_MODE write handling in the bus access match
arm to implement the documented init and EBUS clear/set command pairs,
preserving their state for subsequent reads while keeping deferred
RDRAM-transfer modes separate. Retain ClearDP behavior, and add regression
coverage that verifies both set and clear commands update the corresponding
readback bits without introducing undocumented side effects.

---

Duplicate comments:
In `@crates/rustyn64-rsp/src/sp.rs`:
- Around line 127-137: Initialize SpRegs::new so semaphore starts as taken,
matching the documented reset contract and the existing comment. In
crates/rustyn64-rsp/src/sp.rs lines 127-137, update the semaphore
initialization; in lines 428-443, add a no-write read assertion before the
release-on-write cases to verify the initial value is 1.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: cb9a9eca-0480-418e-9f58-e5a377136bfe

📥 Commits

Reviewing files that changed from the base of the PR and between bba2839 and 280d3e0.

📒 Files selected for processing (3)
  • crates/rustyn64-core/src/bus.rs
  • crates/rustyn64-rsp/src/sp.rs
  • crates/rustyn64-rsp/src/su.rs

Comment thread crates/rustyn64-rsp/src/su.rs Outdated
Adopted from a CodeRabbit review comment on #36. The disabled path ran through
the `run` helper, which throws the `StepResult` away, so the only thing checked
was that the core halted -- the half of the test named in its own title was not
asserted at all.

Both configurations now execute the same single BREAK through the same helper
and differ only in the flag, so the differing `interrupt_change` is attributable
to nothing else. The disabled case asserts `None` rather than "not raised":
`Some(false)` would acknowledge an interrupt this instruction never raised,
clearing a previously-raised line.

Mutation-checked -- reporting `Some(status & INTBREAK != 0)` unconditionally,
the natural-looking simplification, turns it red.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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