# Independent hardware and playback review

Reviewed 14 September 2026. Scope: the blog's hardware, schematic and recorded-event JSON plus `MashExperience.tsx` and `MashBoardExplorer.tsx`. The exact reviewed source hashes and pinned schematic source hashes are recorded in `hardware-review.json`. The initial review made no blog edits. A subsequent authorized addition appended three exact recorded-instruction samples to the three hardware mapping JSON copies; every pre-existing field and sample was preserved.

## Findings — both resolved in follow-up

1. **P2 — distinguish the inspected chip from the recorded location.** `src/components/mdx/MashBoardExplorer.tsx:299` renders `CODE LOCATION / ROM {chip}` with the manually inspected chip, but renders the supplied recorded PC beneath it. In recorded mode, select ROM04 while viewing the first event at PC`$0136C0`: the readout then pairs ROM04 with an instruction that resides in ROM03. The cyan highlights and the separate line323 correctly retain ROM03; this is a misleading readout label, not corrupt address arithmetic. Recommended change: label the selected device “Inspected ROM” and keep the recorded PC/chip relationship separate. The same distinction should remain visible when inspecting a static reference on another chip.

2. **P3 — eligibility is not move acceptance after credits reach zero.** `src/components/mdx/MashExperience.tsx:31` computes `accepted` solely from the fresh-button mask, while line32 correctly stops spending when the allowance is empty. Line115 nevertheless reports “One accepted button event” on each subsequent fresh press. Native Kikosho tests the credit word at`$04E2F4` and branches directly to return at`$04E318` when it is zero, before calling the common helper. Recommended change: call that indicator an “eligible new edge”, or distinguish eligible input from an event accepted by the move. The displayed credits/repeat arithmetic itself is correct and never exceeds four additional repeats.

Neither finding changes the recorded four-event fixture or the measured game results. This review did not find a wrong byte, raw offset, CPU location or board assignment in the current datasets.

## Direct falsification checks that passed

- Reopened the stock Euro980123 ZIP and verified all eight program member sizes, CRCs and SHA-256 hashes against the hardware JSON. Verified contiguous512KiB CPU windows from`$000000` through`$3FFFFF`, with262144 sixteen-bit words per chip.
- Independently recalculated all sixteen samples: chip index, CPU byte offset within the member, raw file offset via XOR1, eighteen-bit word index, raw aligned bytes, ordinary CPU-order bytes, decrypted bytes and both16-bit binary strings. All match the actual member data and the pinned research views.
- Verified the original ZIP digest and both4MiB research-view digests. The CPU-addressed byte versus raw member byte distinction is correct; word swapping and decryption are not conflated. ROM04 child examples correctly subtract`$080000` before computing member offsets.
- Rejoined all four published Ryu events with trial7 events48,49,61 and62 from `mame/ryu-spider-near/events.jsonl`. PCs, RAM addresses, before/after values, observer indices, native sample indices and every displayed register match. The changed displayed field is deliberately replaced by the actual post-write value, as the fixture says.
- Inspected Kikosho instructions`$04E2F4..$04E318`: a successful eligible event decrements`+$398`; when the new count is even, it follows the child pointer at`+$392` and increments child`+$50`. Eight credits therefore buy four additional repeat opportunities. The child's initial8 at`$0986FA` and decrement/underflow loop at`$0987CA` are distinct from the UI's count of additional repeats. The rule model does not claim those opportunities always connect.
- Tested the mathematical reducer cases against that instruction rule: held input produces one edge then none; releasing and pressing produces another edge; six simultaneous eligible bits produce one event; directions produce none under`$0770`; eight valid events exhaust the budget and add four repeats. The original exhausted-budget label mismatch identified above is now fixed by requiring a positive credit balance in the pure sampler.

## A-board working memory versus B-board sprite-object memory

The current assignment is supported by the pinned primary schematic, rather than a generic motherboard/cartridge analogy:

- [`93646A/ram.sch`](https://gitlab.com/loic.petit/cps2-reverse/-/blob/cbd37b3820179496027cc2ccb29f65696096ce93/93646A/ram.sch): UR14/UR13 are HM658128, with the low/high main-data-bus lanes respectively, and shared address/control buses.
- [`93646A/bus-control.sch`](https://gitlab.com/loic.petit/cps2-reverse/-/blob/cbd37b3820179496027cc2ccb29f65696096ce93/93646A/bus-control.sch): the author's decoded RAM-enable expression explicitly includes`ADDR=FFxxxx` together with the video-RAM enable. Thus these physical devices serve working **and video** RAM; the UI correctly identifies the fighter fields' decoded`$FFxxxx` region without needing to claim that the whole pair is exclusively64KiB working RAM.
- [`93646A/io-bus.sch`](https://gitlab.com/loic.petit/cps2-reverse/-/blob/cbd37b3820179496027cc2ccb29f65696096ce93/93646A/io-bus.sch): UD6 is DL-1123 with the physical input groups and main-bus signals. Cabinet input groups are correctly distinguished from the game's later normalized fighter word.
- [`93646B/SRAM.sch`](https://gitlab.com/loic.petit/cps2-reverse/-/blob/cbd37b3820179496027cc2ccb29f65696096ce93/93646B/SRAM.sch): UA4/UA3 are HM6264 on the separate SRAM interface. [`93646B/processor.sch`](https://gitlab.com/loic.petit/cps2-reverse/-/blob/cbd37b3820179496027cc2ccb29f65696096ce93/93646B/processor.sch) identifies the DL-1525 OBJRAM bus. These are not the physical RAM devices behind fighter`+$D4` or`+$398`.
- The physical decapsulation evidence independently identifies the68000 core inside B-board DL-1525. [Eduardo Cruz's primary investigation](https://arcadehacker.blogspot.com/2018/01/a-journey-into-capcoms-cps2-silicon.html). The pinned MAME CPU map likewise separates`$FF0000..$FFFFFF` from the`$700000`/`$708000` object-RAM ranges. [Pinned driver](https://github.com/mamedev/mame/blob/774a180df2b6ef9c53e48337792256817c50f768/src/mame/capcom/cps2.cpp#L1275).

The reference photograph's03D/04D labels are explicitly distinguished from tested Euro`mvce.03a`/`mvce.04a`. The eighteen-bit index grid models an address; it does not claim a die coordinate. The Meshy textures, authored overlays, illustrative layer separation and simplified signal links are explicitly not component or measured-electrical evidence. These qualifications are correctly placed in the component.

## Recorded versus explanatory execution

`MashExperience.tsx:78–80` derives recorded highlights only from supplied PC and RAM accesses. Each supplied PC lies in ROM03 and each access lies in A-board working RAM. The recorded input-word store does **not** illuminate UD6 as though an electrical input-port read had been recorded. No fabricated helper-call event fills the gap between selected moments. The event-specific text and trace label keep Ryu's12-credit recorded example distinct from Kikosho's8-credit explanatory model.

`MashBoardExplorer.tsx:323` explicitly separates the recorded instruction address from the independently selected static binary receipt. The original recorded hit-store event could leave the static mask example available without assigning that mask's bytes to the hit-store PC; the follow-up now also provides its exact instruction sample for direct selection. Missing recorded PCs are explicitly unreported; missing repeated/timer values are displayed as absent. Current recorded highlights do not imply per-pin measurements or continuous/cycle-exact playback.

The recorded event sequence is correctly qualified as selected moments, not proof that a particular press caused a particular later connection. Broad object-owner tracing, arbitrary event datasets containing execution outside the program-ROM range, and electrical-net timing were not part of this audit. Current inputs all lie inside the mapped program range. The readout's unconditional ROM-number formula should be guarded if such outside-ROM PCs are supported later.

## Receipt boundaries

The audit read ROM and instruction data locally but does not publish it. `hardware-review.json` contains checksums and findings only. No gameplay trials or ROM changes were made for this review. UI fixes were implemented by the parent task and independently read back; the only blog changes owned by this reviewer are the three appended hardware samples. Dynamic WebGL appearance was not re-tested here; the manual-selection readout finding follows directly from the reviewed state/data flow. Fixes should be followed by a small UI check selecting a different ROM while paused on a recorded event.

## Follow-up: exact instructions for all recorded moments

The three mapping copies (`src/data/mvsc-mash-hardware.json`, `public/blog/mvsc-mash/hardware-map.json`, `docs/research/mvsc-mash-hardware-map.json`) are byte-identical and now contain16 verified samples. Their SHA-256 is `837cc4a8ccc7ed6ad30f0b36fa1880c694cf0be88d601d8a39c2387941bca69d`. The original13 samples and every other field are unchanged.

| Sample ID | CPU PC | First CPU byte's raw offset | Raw aligned bytes | CPU-order bytes | Decrypted instruction |
| --- | --- | --- | --- | --- | --- |
| `ryu-credit-store` | `$047ABE` | `$047ABF` | `FD 5E 73 6E` | `5E FD 6E 73` | `53 6E 03 82` — `subq.w #1,$382(a6)` |
| `ryu-timer-store` | `$047AC4` | `$047AC5` | `68 CB C2 44` | `CB 68 44 C2` | `53 6E 00 4E` — `subq.w #1,$4e(a6)` |
| `combo-hit-store` | `$01D1A8` | `$01D1A9` | `C7 28 18 2E` | `28 C7 2E 18` | `11 40 01 20` — `move.b d0,$120(a0)` |

All three reside in tested member`mvce.03a`. Exact four-byte lengths and instruction decodes were independently checked with Capstone against the pinned opcode view, and byte order with the original ZIP member and ordinary CPU data view. The PC, raw-offset XOR1 and eighteen-bit word-index arithmetic was rechecked across all16 samples. Wiring those sample IDs into the recorded-event selector belongs to the parent task.

The parent also resolved both original findings: the board now says “INSPECTED ROM,” and `sampleKikosho` requires credits greater than zero before declaring an input accepted. The updated receipt hashes the read-back code and marks both findings resolved.
