Add "yaps2 Dev Team" copyright to the files we authored. Net-new files
(all 42 pcsx2/arm64/ codegen/ProgCache/persist sources, the recompiler
test suite + harness, and the vurunner/eerunner tools) never existed
upstream, so they carry yaps2 sole credit. RecStubs.cpp predates the
fork and was heavily extended, so it keeps PCSX2 credit and adds yaps2.
The five pre-existing arm64 files we only lightly touched (AsmHelpers,
Vif_Dynarec, Vif_UnpackNEON) stay PCSX2-only. GPL-3.0+ license lines are
unchanged throughout; this is authorship attribution only.
The live emulator compiles VU code under defaults + GameDB + user INI; the
replay harness pins a deterministic subset. CHECK_XGKICKHACK, the VU clamp
bools, and the VU FPCRs change the COMPILED SHAPE of every block, so replaying
a capture under the pinned config validates different code than the game ran.
That exact blindness hid the Crash Twinsanity mVU_XGKICK_SYNC lost-write bug
(9ee69fc23) for weeks: GameDB forces XGKickHack=true for that game, and every
offline oracle pinned it false.
Close the class, not the instance:
- vucap v2: CapturedConfig block (44 bytes) after the FileHeader — disc
serial + CRC provenance, gamefixes bitmask (GamefixId order now frozen,
pinned by test), the six VU clamp bools, and a PORTABLE per-VU FPCR
encoding (round|ftz|daz — the raw FPControlRegister bitmask is MXCSR on
x86 / FPCR on aarch64 and captures must replay cross-arch). The probe
snapshots the live EmuConfig into every capture. Reader accepts v1
forever (zeroed, not-valid config).
- vurunner applies the recorded snapshot BY DEFAULT, per record (safe:
PrimeFromCapture resets the block cache). Precedence: harness baseline <
snapshot / --game <serial> (GameDB entry synthesized once via
applyGameFixes + SnapshotConfig — covers the legacy v1 corpus) <
--vu-clamp-mode / PCSX2_VU_XGKICKHACK. vuThread/vu1Instant/vuFlagHack are
always re-pinned false (single-threaded harness, full-flag interp
reference); dropping a game-requested one warns once. One stderr line per
distinct effective config keeps batch stdout diffable. --no-game-config
restores pre-v2 behavior.
pcsx2-eerunner needs nothing: it boots a full VM (EnableGameFixes defaults
true), so VMManager already applies GameDB there.
Verified: recompiler_tests 1127/1127 (v2 round-trip, v1 legacy read, 44-byte
+ gamefix-bit-order pins, SnapshotConfig mapping); Twinsanity wedge cap
--dump-asm grows 172→266 lines under --game SLES-52568 (the XGKICK sync
blocks) and an env-hack-ON re-capture replayed flag-free reproduces the
identical hack-ON shape from its recorded snapshot alone; 50-cap v1 corpus
slice byte-identical to pre-change behavior.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Widen HashArchSurface/DumpArchRaw with the one carried XGKICK *timing*
field, xgkicklastcycle (u64, both halves), gated under --hash-pipeline
alongside the flag pipeline. It is serialized by vu_capture and re-primed
by VuSnapshot::Restore, yet DiffVu's compare set omits it — a genuine
blind spot on XGKICK-in-loop programs (pc0x1748), where it is the one
cross-dispatch quantity the per-op architectural surface hides. Inert on
XGKICK-free programs (carries the primed value untouched), so it adds no
noise to the bulk of the corpus.
Verified participating: on the twinsanity pc1748 XGKICK loop the default
digest (a5253d62...) diverges from --no-hash-pipeline (7239f2bb...), with
lastcyc=0xfaad0eaf visible in the raw dump — and another implementation
agrees with it bit-for-bit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
--dump-jit-state's HashArchSurface hashed only the per-op architectural
surface (VF/VI/ACC + xgkick), not the carried microVU flag pipeline
(micro_{mac,clip,status}flags[4], pending_q/p). Those are serialized by
vu_capture and re-primed by VuSnapshot::Restore, so two JITs that agree on
VF/VI/ACC can still hand DIFFERENT carried state to the next dispatch —
exactly the blind spot that let the cross-JIT oracle stay green over an
E-bit STATUS-broadcast clobber (fixed in the preceding commit).
Add --hash-pipeline (default on) / --no-hash-pipeline to include/exclude
those fields in the reghash, and print them under --dump-jit-state-raw.
--no-hash-pipeline reproduces the old narrow digest (needed for
XGKICK-bearing/non-terminating caps run in batch, where the JIT leaks
carried state cross-cap — run those per-process). Mirrors DiffVu's
Strict-mode DiffPipeline().
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Step 0 of the `neither` cherry-pick funnel: a repeatable, attributable,
wallclock-anchored CPU bottleneck baseline for our own ARM64 port, since the
RK3562-era numbers are stale and the target has shifted to Snapdragon 865.
Built and validated on M2 Max / Asahi first; the same scripts run on SD865 with
a new devices/<label>.env and no code change.
Test-harness change (no production code path, no shipped env gate):
- pcsx2-eerunner --perf-jitdump: emit a Linux perf jitdump under EmuFolders::Cache
so `perf inject --jit` resolves EE_/VU0_/VU1_/IOP_/VIF_ block symbols. The enable
is driven through the EmuCore/Profiler EnablePerfDump config bool (ApplySettings ->
LoadSettings re-applies Perf::SetJitDumpEnabled every apply, so a manual enable
would be reset). SetJitDumpDir is set before the first block compiles. Also honors
an explicit `--renderer null` under --perf-jitdump for the CPU-only diagnostic.
- pcsx2-vurunner --perf-jitdump: same flag for VU-only captures (manual enable; the
runner doesn't go through ApplySettings).
Tooling (pure stdlib + bash):
- tools/perf/bucket_perf.py: parse a `perf report --stdio` dump into a PCSX2
subsystem ranking. Buckets tuned against real M2 R&C UYA / Katamari captures:
JIT-by-prefix (EE/VU0/VU1/IOP/VIF) + VU-glue (mVUlookupProg / dispatch envelope) +
native VIF + GS (incl. GIF decode + XXH3) + a GPU-driver bucket that quarantines
the host Asahi/Vulkan/DRM stack (host-specific, NOT an SD865 proxy) + JIT-other
(unsymbolized continuation blocks) + startup/io + a visible `unattributed`.
- tools/perf/profile_run.sh: one-command wrapper (precondition gate -> perf record
-> inject --jit -> single report dump -> bucket -> median wallclock + median
per-bucket share -> summary.md). Device/scene parameterized.
- tools/perf/devices/m2max-asahi.env: the working M2 incantation (P-core PMU
apple_avalanche_pmu/cycles/, -F 999).
- tools/perf/scenes/*.env: R&C UYA + Katamari cinematic/gameplay scenes (assets are
copyrighted, not checked in; paths reflect this dev box).
Validated on M2: go/no-go #1 (perf+jitdump resolves 277 JIT symbols) and go/no-go #2
(per-bucket shares stable across 3 runs) both green. First finding: on M2 the `vk`
profile is dominated by the Asahi GPU stack (GS thread ~57% of samples) — the CPU
shape comes from `--renderer null`, where VU (bodies+glue) is the largest emulation
cost.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tooling to localize arch-specific VU codegen bugs by comparing arm64-rec
against the mature x86-rec over the same vu_capture corpus.
- --dump-jit-state[-raw]: per-capture FNV digest of the JIT architectural
post-state (VF/VI/ACC/[VU1 xgkick]/VU-mem), basename-keyed so cross-machine
path prefixes don't pollute a `diff`. Both microVU backends share a
byte-identical cycle model, so the same capture+budget stops at the same
guest insn on either arch -- post-states are directly comparable even for
budget-truncated programs, the class JIT-vs-interp is structurally blind to.
- --vu-clamp-mode N: force EmuConfig VU clamp mode 0..3 (mirrors
GameDatabase.cpp vuClampMode). The harness otherwise stays at default mode 1
(vu0Overflow only), which never exercises the extra-overflow per-op operand
clamp real games request via gamedb (e.g. SoulCalibur III vuClampMode:2).
- RunDiff also reports consumed-cycle divergence (gated on both engines
hitting the E-bit) -- the EE<->VU0 timing quantity the reg/mem diff can't see.
- VuReplay records jit_cycles/interp_cycles deltas.
- x86 portability: guard the arm64-only progcache/persist includes+calls so
the same source builds a native x86 vurunner for the cross-arch reference.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>