SCbranchCdbg decodes SOPP 0x17-0x1a and STtracedata decodes 0x16 and 0x28,
so S_CBRANCH_CDBGSYS, S_CBRANCH_CDBGUSER, S_CBRANCH_CDBGSYS_OR_USER,
S_CBRANCH_CDBGSYS_AND_USER and S_TTRACEDATA_IMM were reported as missing
although the decoder handles them and existing tests cover them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Decode VOP3 0x15a, 0x15b, 0x15c and 0x171 and translate them as the
unsigned sum of absolute differences over the byte or word fields of
the first two sources, accumulated into the third. v_sad_hi_u8 shifts
the sum into the high half first, v_msad_u8 skips the fields whose
reference byte in the second source is zero.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
open, _open, stat, unlink and rmdir forwarded the result of their sceKernel
twin, so a failure returned 0x8002xxxx instead of -1 and errno was never set
to the guest error. They now return -1 with errno set to the code carried by
the sce error, and report a null pointer as EFAULT and an empty path as
ENOENT.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
s_wakeup (SOPP 0x03) threw "unsupported SOPP opcode 3" in the decoder. It
pings the other waves of the thread group so they leave s_sleep early.
s_sleep already translates to nothing, so no wave is ever asleep and the
ping has nothing to wake: s_wakeup translates like s_sleep. It carries no
operand.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SMEM opcode 0x2a threw in the decoder. It carries only a scalar destination
and returns the index of the current wave in its workgroup. A compute
workgroup fills its waves in local invocation index order, the mapping the
compute prologue already uses for the tg_size wave id, so the result is the
local invocation index divided by the wave size. Other stages throw.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scePthreadAttrGet wrote priority 700 and left the affinity of the
destination untouched, whatever the thread was created with or set to
afterwards. It now reports the values the thread holds, as
pthread_attr_get_np already does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the windowless device is replaced at the first present, its unit
shadows were published but stayed registered. Lookups take the shadow
whose import starts nearest below an address, so such a stale entry
could hide the live import's shadow. The write-back results it held then
looked absent, and an upload read the import's stale bytes instead.
The replaced device's shadows are now dropped once it is idle.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The VOP3 form of v_nop now decodes without operands, and no test looked at
it. agc_vop1_control_decode decodes the three instructions in VOP1 and VOP3
form and checks the opcode, the length, the null destination and the absence
of sources. agc_driver_vop1_control also runs v_nop in both forms.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Decode MIMG image_atomic_cmpswap, sub, smin, smax, inc and dec and
recompile them on the image texel pointer. sub, smin and smax map to
the SPIR-V atomic of the same name. cmpswap takes the new value from
VDATA[0] and the comparand from VDATA[1] (dmask 0x3) and returns the
previous value in VDATA[0]. inc and dec use the compare-exchange loop
of ds_inc/ds_dec, whose replacement helpers are now shared.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v_pipeflush (VOP1 0x1b) and v_clrexcp (VOP1 0x41) threw in the decoder, as did
their VOP3 forms. SPIR-V has no ALU pipeline to flush, and the recompiler keeps
no exception flags for v_clrexcp to clear, so both translate like v_nop, which
emits nothing. Neither has operands: they decode with a null destination and no
sources. The VOP3 form of v_nop decoded a destination and a source it does not
have and now takes the same path.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Decode v_cmp_*_f64, v_cmpx_*_f64 and v_cmp(x)_class_f64 in their VOPC and VOP3 encodings and translate them as exact IEEE-754 compares on the 64-bit pattern with the existing 64-bit integer IR, so no Float64 capability is needed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pthread_barrier_init threw for any non-null attributes object, and no
function could create one. Add pthread_barrierattr_init, _destroy,
_getpshared and _setpshared after FreeBSD libthr, and let
pthread_barrier_init take the object.
PTHREAD_PROCESS_SHARED still throws in pthread_barrierattr_setpshared:
FreeBSD 9.0 rejects it and 11.0 accepts it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sceKernelSyncOnAddressWait parks the calling thread while the 32-bit word
at the address still holds the expected value, until
sceKernelSyncOnAddressWake releases it or the timeout expires.
sceKernelSyncOnAddressWake releases up to the requested number of threads
parked on the address, in arrival order.
The libc.prx bundled with SDK 9 titles imports both for its once
primitive, so those titles stopped at load with an unresolved import.
# Conflicts:
# docs/dev/TechnicalDebt.md
libkernel did not export sceKernelMapNamedFlexibleMemoryInternal, which
the libc bundled with SDK 9 titles imports. It now forwards to
sceKernelMapNamedFlexibleMemory: the mapping counts against the flexible
budget, gets the range name and is released by sceKernelMunmap. Older
libc builds call the public function at the same sites with the same
arguments and result handling.
The known callers pass flag 0x8000, whose meaning is unknown. It is
still rejected as an unsupported mapping flag and is recorded in
TechnicalDebt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sceKernelCancelSema was a throwing stub. It now releases every thread
blocked in sceKernelWaitSema with SCE_KERNEL_ERROR_ECANCELED without
consuming tokens, sets the count to setCount (the initial count when
setCount is negative) and reports how many threads were waiting. A
setCount above the maximum returns SCE_KERNEL_ERROR_EINVAL and changes
nothing.
Waiters are counted separately from waiterCount, which is only
decremented when a waiter leaves, so two cancels in a row do not report
the same thread twice.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CLOCK_THREAD_CPUTIME_ID (14) and CLOCK_PROCESS_CPUTIME_ID (15) threw
"unsupported clock_id" on Windows while the Linux branch already maps
them to the native clocks. clock_gettime now returns the user + kernel
time from GetThreadTimes / GetProcessTimes, and clock_getres reports the
clock interrupt period from GetSystemTimeAdjustment, which is the step
those counters actually advance by.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Returns 1 when the address lies in an executable PT_LOAD segment of the
given dl_phdr_info, following FreeBSD lib/libc/gen/elf_utils.c (9.x and
11.x branches). The stub parameters become (dl_phdr_info*, void*) to
match the FreeBSD declaration; a null dl_phdr_info throws.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sceKernelGetEventId, sceKernelGetEventFilter, sceKernelGetEventFflags,
sceKernelGetEventData and sceKernelGetEventUserData return the matching
field of the KernelEvent filled by sceKernelWaitEqueue and throw on a
null event. sceKernelGetEventError still throws NotImplemented.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A pixel wave starts with EXEC holding its covered pixels. The other lanes of
a partly covered quad run as helpers outside EXEC until the shader asks for
whole quads with s_wqm. Pixel shaders started with every invocation in EXEC,
Vulkan's helper invocations included. Those take part in subgroup
operations, so they counted in ballots (v_mbcnt, s_bcnt1 of EXEC,
v_readfirstlane), and a wave's single ds_append or atomic could be performed
by one of them: an atomic in a helper invocation does nothing and returns an
undefined value.
The entry prologue now starts a pixel shader's EXEC as !gl_HelperInvocation,
through a new StageInputKind::HelperInvocation builtin input. s_wqm still
adds the helpers of every quad with a covered pixel, so derivative code keeps
them.
The agc_driver_pixel_helper_lanes execution test draws triangles that leave
partly covered quads across the target with a pixel shader that stores each
covered pixel's v_mbcnt rank in EXEC, the s_bcnt1 count of EXEC and the
v_readfirstlane of a pixel id. Every wave's covered pixels must be lanes
0..n-1 of an n-lane EXEC whose first lane is one of them, in wave64 and
wave32. It skips on a subgroup narrower than 32, such as lavapipe's.
and throws for any non-zero word after it. Its layout matches shadPS4's
ServiceThreadParams instead: an unknown first word (16), a set-priority flag
and a priority (256..767), a set-affinity flag and a 64-bit CPU mask at
offset 16. PPSA21564 passes 16, 1, 0x100, 1 and 0x1FFF, so it stops at
startup on main.
sceVideoOutOpen now validates each field and reads the mask only when its
flag is set, so a 16-byte param with both flags clear still works. The
priority and affinity are not applied, since the present and vblank threads
are host threads; this and the unknown first word are listed in the
technical debt.
scePngEncQueryMemorySize, scePngEncCreate, scePngEncEncode and
scePngEncDelete encode R8G8B8A8 and B8G8R8A8 images with a pitch into
RGB or RGBA PNGs using the shared encoder in core/Decoder/Png.
Decoder::Png::Encode takes optional compression level and filter
options so the encode parameters are honoured.
Co-Authored-By: Claude <noreply@anthropic.com>
s_movrels reads SGPR[src + M0] and s_movreld writes SGPR[dst + M0].
The 64-bit forms align the offset down to even (M0 & ~1), and
s_movrelsd_2_b32 takes the source offset from M0[9:0] and the
destination offset from M0[25:16], as measured on hardware. They use
the same select-over-registers lowering as the vector forms, over the
106 SGPRs. The embedded vertex-fetch scan forgets every tracked SGPR on
a relative write.
Co-Authored-By: Claude <noreply@anthropic.com>
The decoder threw for these SOP1 opcodes. The 64-bit find-first-zero and
signed leading-bit counts reuse the existing 64-bit helpers with a flag;
s_quadmask_b32 is the 32-bit half of s_quadmask_b64. s_bcnt0 and s_quadmask
set SCC to result != 0; the find and leading-bit forms leave it.
Co-Authored-By: Claude <noreply@anthropic.com>
The WriteLane IR takes {value, lane, previous}, as the translation and the
read-lane eliminator use it, but the SPIR-V emitter compared the lane id with
the previous value and selected between the lane index and the value. Every
v_writelane therefore wrote its value to all lanes (or the lane index to the
lane whose old value happened to equal its id).
Co-Authored-By: Claude <noreply@anthropic.com>