Skip to content

fix(recomp): EE LQ/SQ force 16-byte alignment as the hardware does - #400

Open
LeandroSSB wants to merge 1 commit into
ran-j:mainfrom
LeandroSSB:pr-06-lsq-align16
Open

LeandroSSB wants to merge 1 commit into
ran-j:mainfrom
LeandroSSB:pr-06-lsq-align16

Conversation

@LeandroSSB

Copy link
Copy Markdown

Root cause

The EE Core truncates the low 4 bits of LQ/SQ effective addresses — 16-byte alignment is forced, not faulted (EE Core User's Manual, memory access semantics). The runtime did byte-exact unaligned access instead:

  • Ps2FastRead128 / Ps2FastWrite128 masked only with PS2_RAM_MASK (no ~0xF), so the fast path silently computed with the unaligned address.
  • PS2Memory::read128 / write128 threw "Unaligned 128-bit ..." on address & 15.

Any game whose SIMD code relies on the truncation semantics copies data shifted by the misalignment. Sony's libc is the canonical case: memcpy/memmove load the source with LQ at src+0x00/0x10/0x20/0x30 and repair the lanes with QFSRV via MTSAB — with the throw in place every such copy either aborted or left corrupted.

Measured (MOH:Vanguard, before the fix)

A stream-manager state reload read its blob 8 bytes ahead of the requested offset; a final memcpy left with n = -1784 (0xFFFFF908) and smeared ~4 GB over SDK handler slots every ~1.5 s. After the fix the same memcpy leaves with n = 0x38 and the smear is extinct (0 changes in watched slots).

Fix

addr &= ~0xF (truncate instead of throw / mis-mask) in all four points: Ps2FastRead128, Ps2FastWrite128, PS2Memory::read128, PS2Memory::write128.

Test

ps2_memory_tests: base+8 reads and writes hitting only the aligned quadword, on all four paths (fast read, fast write, read128, write128).

Note: #396 masks LQ/SQ addresses in the codegen layer; this PR is the runtime-layer counterpart — any non-generated path (read128/write128 called from runtime code) still needs the truncation, so the two are complementary.

🤖 Generated with Claude Code

Suite evidence

Fresh configure+build of ps2x_tests on this branch (VS 2022, Release): 448/448 passed, 0 failed.

The EE core ignores the low 4 bits of the effective address of LQ/SQ
(16-byte alignment is forced, not faulted). The runtime performed
byte-exact unaligned 128-bit accesses instead:

- Ps2FastRead128/Ps2FastWrite128 (the gen fast path) masked only with
  PS2_RAM_MASK;
- PS2Memory::read128/write128 threw "Unaligned 128-bit ...".

Vanguard (SLUS_215.97) regression, measured end to end: Sony's libc
memcpy (sub_003553F0) copies a misaligned source with LQ at
src+0x00/0x10/0x20/0x30 plus QFSRV repair via MTSAB (sa = (src&0xF)*8).
With byte-exact LQ every 64-byte block lands 8 bytes late. The
stream-manager state reload (sub_0011F0E0) then reads its BRGR blob 8
bytes ahead of the requested offset 0x18, its record walk consumes
8+16*116 bytes out of an 80-byte section, and the final memcpy is issued
with n = -1784 (0xFFFFF908), smearing 4 GB over the SDK handler slots,
the heap sentinel and the engine gate every ~1.5 s.

- probe chain (opt-in PS2X_ENABLE_T11_BLOB, default off) pinned the
  serve: sceCdRead lbn=0x8c0f1 into the driver staging 0x642E40, header
  copy correct, data copy from staging+0x20 instead of +0x18;
- copy call site 0x33EB5C logs dst=0x1f18e00 from=0x642e58 n=0x50 —
  the shift is inside the LQ+QFSRV sequence, not the driver fields.

Tests: read128/write128 and Ps2FastRead128/Ps2FastWrite128 at base+8
must return/overwrite the aligned base quadword and leave the next one
untouched (RED: read128 threw, fast write landed at +8; GREEN).

Co-Authored-By: Claude Code <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