note_bda_write unrolled its 8 compare-exchange probes, and drivers inline it at every BDA store and atomic. The probes now run in a loop that tries the same slots in the same order and stops at the same slot, so the recorded pages and the overflow flag are unchanged. With the byte store helper, the agc_driver_flat_store binaries on an RTX 3060 go from 138,240 to 75,648 bytes (wave32) and from 225,152 to 130,560 bytes (wave64), and the cold run from 2.2 s to 1.2 s.
Every 8- and 16-bit BDA store and the unaligned path of every 32-bit store emitted one get_bda_write_pointer lookup and one note_bda_write per byte at the store site, five write lookups per 32-bit store. They now call write_bda_bytes, which loops over the bytes and does, per byte and in order, the same lookup, the store when it is mapped and the write note, so faults are recorded exactly as before. On an RTX 3060 the agc_driver_flat_store binaries shrink from 496,256 to 138,240 bytes (wave32) and from 928,384 to 225,152 bytes (wave64), and the cold run from 19.7 s to 2.2 s.
A captured grain stored only the port slot and data pointer, so a port
created in a destroyed port's slot before the next push mixed the old
pointer with its own format. Ports now carry a generation that the
capture records. TechnicalDebt notes that the last grain pushed before a
title stops is never played.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A wave64 graphics program on a 32-lane host runs one guest lane per
invocation, yet an EXEC written as a value keeps all 64 bits: the NGG
prologue's s_lshr_b64 exec, -1, 64 - count reads count 0 and sets -1.
A waterfall loop that copies EXEC with s_mov_b64 and retires one key
per pass then never empties its copy, since no ballot sets the lanes
the host lacks, and its v_readlane picks lane 32 and up.
readRawU32 now ANDs EXEC with a ballot of true when it is read as a
value (s_mov_b64, ALU sources, src_execz), and s_*_saveexec and
s_*_wrexec store that masked copy. EXEC's own words, threadBit and the
saveexec combination keep the raw words, so s_orn2_saveexec_b64 vcc,
exec still sets all 64 bits. On subgroups under 32 lanes the EXEC_LO
copies of agc_driver_scalar_sop1 now hold only the subgroup's lanes.
A raise that suspends the thread after its wait returned but before the
wait count drops queued an APC that only ran at the next alertable wait.
Pending APCs are now run right after the count drops. The 0 ms poll in
Condition::waitSignalUntil runs under queueLock and is no longer
alertable, and a target that exits during the raise returns ESRCH.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Counters are set with DMA_DATA immediate to GDS and read back with
DMA_DATA GDS to memory around two dispatches each of wave32, wave32 with
a partial EXEC, two wave32 waves in one group and wave64 with a partial
EXEC across both halves.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The Smurfs Dreams imports both and no library exports them, so eager
binding stops the title before it starts. sceAudioInAsyncOpen throws
like the other AudioIn opens that have no implementation;
sceHttp2SetMinSslVersion returns success like the other Http2 SSL
setters, as no request reaches the network.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Shader GDS accesses bind the same 64 KiB guest range that DMA_DATA packets
read and write, so both go through the existing CPU/GPU coherence tracking.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The host mixes without the console's mastering stage, so the mastering
parameters have nothing to configure, as with sceAudioOut2MasteringInit.
Accept them instead of aborting, keep throwing for a null parameter
block, and record SetParam next to MasteringInit in TechnicalDebt.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
sceAgcDriverGetEqContextId is now checked with a misaligned event like
sceAgcDriverGetEqEventType, and on the end-of-pipe events the submit
test delivers: a graphics interrupt reports context 0 and a compute
interrupt context 0x20, the queues that raised them. The TechnicalDebt
line says why ident is returned and that KytyPS5 returns the event's
data instead.
AI-assisted: yes
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Return the id a graphics event was registered with in
sceAgcDriverAddEqEvent, which titles derive from their context
(PPSA12544: 0 or 1 for graphics, 0x20 + 8 * pipe + queue for compute) and
read back to dispatch the event. Other event filters, a null or
misaligned event and an id above 32 bits throw. The meaning is an
assumption and recorded in the technical debt.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
GuestAppContent now writes a param.json that declares downloadDataSize 0
and checks that sceAppContentDownloadDataGetAvailableSpaceKb returns OK
with 0 KB for /download0 (it threw before), and PARAMETER for a null
result. TechnicalDebt records that the console's behaviour for such a
title is unverified.
AI-assisted: yes
Co-Authored-By: Claude Opus 5.5 <[email protected]>
sceAppContentDownloadDataGetAvailableSpaceKb threw when param.json declares
no download data area. A title without one has no space there: Unity's
player (PPSA12544) queries it at startup, treats an error or 0 as no space
and logs 'persistentDataPath / DownloadData has no space available, check
"Download Data Area Size" in SDK Param Editor'. It now reports 0.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
check_conventions.py normalized link targets with os.path.normpath, which gives backslash paths on Windows, so every link added in docs failed the doc-link check and a silent stub listed in TechnicalDebt was not found. Links are repository-relative POSIX paths, so they are normalized with posixpath.
Address review: read a grain's buffers at the next push without spinning
under the context lock, keep the no-device model mixing at push time,
size the pad queue from the unplayed main grains again, use generic
names in comments and TechnicalDebt, and add audio_out2_timing (next-push
read, queue level beyond the cushion, priming after running dry).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The APC delivery was allocated after SuspendThread, so a target holding
the allocator lock deadlocked the raising thread; it is now allocated
before the suspend. The wait count a raise checks lived in the target's
thread_local storage and dangled once the thread exited; it is now a
member of PthreadPrivate, which TimedWait counts into through a
thread-local pointer bound when the thread starts, and a raise on a
thread that already finished returns ESRCH. TechnicalDebt gets one line
per unverified choice: Windows only, the FreeBSD ucontext layout, the
signal mask, the YMM upper halves, and delivery to threads outside
TimedWait.
AI-assisted: yes
Co-Authored-By: Claude Opus 5.5 <[email protected]>
ReadProgramHeaders stepped through the table by e_phentsize without
checking it. With 0 it read the first header e_phnum times, and with
any other size it read misaligned fields, so a damaged header failed
much later as "No PT_DYNAMIC segment found", after building up to
65535 copies of one segment. A non-empty table must now use 56-byte
entries, as the guest module reader already requires.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
PPSA03306 (Silt) loads the Unity plugin Media/Plugins/PSNCore.prx, which
imports scePlayerReviewDialogInitialize, Open, UpdateStatus, GetResult and
Terminate from libSceCdlgPlayerReview. No library provided it, so loading
the plugin failed with "Failed to load module ...\libs\libSceCdlgPlayerReview.prx".
The library follows libSceWebBrowserDialog: the dialog shows nothing, Open
finishes at once and GetResult reports that the user canceled. Terminate
also accepts a finished dialog. GetStatus and Close are added as well.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
WindowsLoadImage sized its data and page table from the end of the last
segment and checked for overlap while copying. A segment whose memory
size reached past the last segment's end wrote page flags past the
table before its overlap was found; the relinker crashed with SIGSEGV
on such an input. Overlap is now checked in a pass before sizing.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A guest range mapped again at the same base and size (a fixed remap into
a registered range) kept its import, which still shows the pages pinned
or aliased before the remap. The GPU then read stale memory. Each import
now remembers its registry range (weakly, since a held range is a lease
the remap waits for) and is retired when the registry has a different
range at its base.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
tls_function_coverage ran its execution cases only on Windows; on
Linux it checked bytes. windows_image_runner.py maps the relinked PE,
points GS at a TEB whose TLS slot holds a block copied from the
template, runs the TLS callbacks for process attach with the Windows
argument registers and calls the guest entry. convert() uses it on
Linux x86-64 and expects 42, as on Windows.
Co-Authored-By: Claude Opus 5.5 <[email protected]>