-i, -j, -r, -J, --ir and --jit-ir are gone. -r was also --root's short form,
and --root won, so -r took the next argument as the root path and nothing
booted (test.py -r failed every test).
-i, -j and -J now fail with an error pointing at --cpu= instead of quietly
running on the default core. Docs and test.py updated.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The audio block's FIFO, measured from the ME on a PSP-1000. In the next
set: it needs the ME on, and Sony's ME firmware to hand the ME back to.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
PMDVIS ships a kcall.prx that ends where its relocation sections begin.
On a PSP-1000 (6.61) such a module loads unrelocated if syslib is its only
export library, but with another library the load hangs the PSP
(pspautotests modules/cutrel and modules/cutrel/kernel, which leave that
case out). We loaded it unrelocated, and PMDVIS then crashed on its
garbage export table. Now the load fails with 80020148, the error
PSPLink's modload gave for that file, and PMDVIS carries on without the
ME.
Also ModuleMgrForKernel's 6.61 NID for sceKernelUnloadModule, which the
kernel test uses.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
What the ME sees at VRAM's addresses, recorded on a PSP-1000. In the
next set: it needs the ME on, and Sony's ME firmware to hand the ME back
to at the end.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The calls a PSP-2000 and later switch to their 4MB of VRAM with. We have
the PSP-1000's 2MB, and answer as it does, recorded in the new
gpu/ge/kernel/edramsize. Tanaka's Touhou ports import them in their GE4
wrapper module, and fall back to 2MB.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
User modules stay at 0x08-0x77. Recorded on a PSP-1000 in the new
threads/threads/kernel/priority. ProTrekkr's ME test, a kernel module,
creates its audio thread at priority 2.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
cpu/cop0/eret, recorded on firmware 6.61, has eret go to ErrorEPC and clear
only ERL with Status.ERL set, otherwise to EPC clearing EXL, with no delay
slot. Int_Eret already does that; the test joins tests_good.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
sceKernelRegisterIntrHandler, sceKernelReleaseIntrHandler,
sceKernelEnableIntr and sceKernelDisableIntr now keep a base handler per
interrupt, and return what tests/intr/kernel/intrhandler recorded on a PSP:
80020065 for an interrupt number out of range (or no handler), 80020067 for
a second handler, 80020068 for one that isn't there.
Faking success for these used to stall the VSH boot, which is why they were
left unresolved. It doesn't anymore: the firmware's drivers make the same 31
calls (interrupts 4, 12, 15-18, 20-24 and 31), and 6.61 reaches the XMB on the
JIT and the interpreter. Nothing raises those interrupts yet, so the handlers
are only kept, and saved in savestates (IntrHandler section version 2).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Fixes#22647
sceNetInetBind rewrote the address whenever the ad hoc server was set to
localhost (to 127.0.0.x, even an explicit address) or the built-in ad hoc
server was enabled (INADDR_ANY to the address facing the ad hoc server),
breaking infrastructure sockets. Both rewrites now only apply while
adhocctl is initialized, which keeps ad hoc as it was.
sceNetApctlGetInfo reported its IP from the same ad hoc-relative
getLocalIp(), so a localhost ad hoc server told infrastructure games their
IP was 127.0.0.x. It now uses the host interface's IP (getHostLocalIp(),
split out of getLocalIp()).
Adds the net/inet/bind test, which failed every bind under headless (whose
ad hoc server is localhost).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Each due alarm or vtimer queues its id next to a pending interrupt, which
pops it when it runs. An alarm cancelled with its interrupt pending was
never popped, so every later alarm interrupt found the cancelled one at
the front and was dropped: no alarm ran again. Deleting a vtimer erased
its id instead, leaving the last pending interrupt with an empty list.
Both now pop a timer that's gone when its interrupt comes, as
threads/alarm/pending and threads/vtimers/pending show the PSP still runs
the rest, in order.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Add the audio/atrac/headerfields and audio/audiocodec/at3errors tests
Add the audio/audiocodec/context test
Add the utility/savedata/noupdate and initstatus tests
headerfields already passes: SetData's end sample limit and a sample
offset of 0 counting as a frame match hardware.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Headless used ~/.ppsspp, which nothing else uses, while the app uses
~/.config/ppsspp (or $XDG_CONFIG_HOME/ppsspp on Linux). The derivation
is now shared, and the app's default is unchanged. Windows and iOS keep
their own.
test.py and frametests.py pass a memory stick next to the binary, as
Windows headless already defaulted to, so the tests still don't write
into the user's memory stick or see its firmware.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The PSP's AVC decoder follows the H.264 output process (Annex C),
measured in the new pspautotests video/mp4/avchold on streams that
differ only in their headers, and video/mpeg/decodeend. With HRD
parameters and picture timing SEI, a picture comes out dpb_output_delay
after its access unit; Sony's movies have a one frame delay. Without, it
is bumped out of a buffer three frames deep, whatever the stream
declares. sceMpegAvcDecodeStop hands back what's left, and streams with
more than three reference frames are refused with 0x80628002.
We handed each picture back as soon as it was decoded. MGS Peace
Walker's movie player only checks for the end of a movie while its
clock is short of the movie's length, so its last picture landed right
on that limit and the game hung on a black screen after the cutscene.
ffmpeg still decodes the pixels, in display order; each access unit is
tagged with its index so frames can be matched back, and ffmpeg's H.264
parser supplies the picture timing. A call can now hand back several
pictures, as consecutive 0x2C byte descriptors the way mpeg.prx's
sceMpegAvcDecodeStop reads them, each in a frame buffer slot of its own
(reallocated when a savestate brings a block too small for that).
Not followed: with B-frames and no picture timing, the PSP can complete
several pictures in one call; here they come out one a call. All of
the game movies checked have picture timing.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
When the input starts with something it can't decode, each of the six
string converters returns 0 on the PSP and writes only the terminator
(ccc/convertstring, all six "Invalid data" cases). We decoded on
regardless and wrote replacement or garbage characters for every unit.
Stop at the first invalid character instead: for UTF-8, a byte that can't
start a sequence (UTF8::invalid()); for UTF-16 and Shift-JIS, INVALID from
the decoder. Valid characters the tables can't map still get the error
character, as before.
ccc/convertstring passes now and moves to tests_good.
As on hardware (cpu/cpu_alu/branch_link_ra), with ra as rs the branch
sees its old value, not the return address. Every core linked first.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
As on hardware (cpu/vfpu/vfim), a denormal half becomes a signed zero,
and inf and NaN keep their mantissa bits in place. The interpreter got
denormals half their value, the IR the IEEE one.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
As on hardware (cpu/vfpu/prefix_load), lv.q, lvl.q and lvr.q write every
lane whatever mask a pending D prefix has, and leave the prefix pending,
like lv.s and mtv already did. The IR cores fall back to the interpreter
for lvl.q and lvr.q, so they get this too.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
On the PSP, lanes past the vector size where both the S and T prefixes are
constants add their product to vdot, and an S constant there is added in by vfad
and vavg (cpu/vfpu/prefix_lanes). The interpreter does that; the IR dropped those
lanes. Such prefixes are rare, so the IR leaves them to the interpreter.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
./b.sh --armhf builds headless and the unit tests for 32-bit ARM, which run under qemu-arm the
way the loongarch64 and riscv64 builds do. setup-cross.sh learns the target (it also needs an
EGL stub), and the docs cover setting it up without root.
hash/hash dies with a bus error under qemu-arm on every CPU core, so it goes in a known-failures
list for the target.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Fixes#7395
The GE has two return address registers, and a CALL beyond them does
nothing: the list carries on after it. A signal CALL is done by the
firmware, which saves and clears them, so it starts the count over,
and the signal RET restores it. Shown on a PSP by the new
gpu/callstack/depth test.
Soul Calibur: Broken Destiny turns lighting on for its weapon trails
from a third-level CALL, so on hardware the trails stay unlit and take
their colors from the vertices. We ran that CALL and drew them white.
Plain CALLs now store a 0 base address in their stack entry, which a
signal CALL never does, so the depth can be counted without changing
the savestate layout.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
With "Memory Stick inserted" off, the savedata modes that show no dialog now
fail with their own "no memory stick" error, as recorded on a PSP with the
stick pulled out (pspautotests utility/savedata/nomemstick). ms0: opens, stats
and directory opens fail with SCE_KERNEL_ERROR_NODEV.
SOCOM: Fireteam Bravo 2's boot-time AUTOLOAD loaded its save anyway, or said
there was no data rather than no memory stick.
test.py gets a test_flags table for tests that need their own headless flags;
this one runs with --no-memstick.
Fixes#21846
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
We copied the module into memory at the start of the call, then made the caller
wait for the read. On hardware the module's bytes only arrive at the end, and
until then other threads can use that memory (pspautotests modules/loadrace).
SOCOM: Fireteam Bravo 2 EU (UCES00543) relies on this. Its loader EBOOT loads
SOCOMPSP.PRX on one thread while another builds a GU display list in a 0x40-byte
buffer at the end of its .bss. That list overruns into the free memory right after
it, which is where the game module goes. On hardware the module load later
overwrites the overrun; for us, the overrun overwrote the module's first
instructions, and the game crashed as soon as it started.
The load now runs from a CoreTiming event at the end of the wait. Pending loads
are saved in savestates.
Fixes#18842
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both in tests_next. unloadfill's fill matches (text becomes break 1,
data and bss 0xFFFFFFFF, as we already do), but sceKernelQueryModuleInfo
reports a text_size 6 words larger than the PSP's. deletetiming's
sceMpegDelete timing matches (it reschedules, in the 20-60 ms range); the
rest of the mpeg setup has older differences.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gpu/vertices/carry, recorded on a PSP: a draw whose format has no UVs uses the last ones read, by any
earlier draw in draw order, textured or not. They're kept as read and get the scale and offset of the
draw that uses them. Normals carry over the same way.
We kept the UVs after scaling, only read them with texturing on, and after a cached indexed draw
carried the highest vertex instead of the last one drawn. The carried values move from statics in
ReadVertex to TransformUnit.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The x86 sampler JIT returned zero for a whole sample when a texture level
pointer was null, and for a mipmapped texture it checked the next level
too, even when it isn't blended in. Tactics Ogre draws its font from a
mipmapped texture whose next level has an invalid address, at level 0,
so all its text was missing on x86-64. The generic samplers read a null
level's texels as zero only where they use that level, and still apply
the texture function. Now samplers for such textures aren't compiled,
and the JIT's null checks are gone. Test: gpu/textures/mipinvalid.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
sceKernelStartModule, sceKernelStopModule and the self-stop calls now
check their option first: with SDK 2.08 or later its size must be 0x14,
and attribute bits outside 0x00F06000 are an error.
The option's attribute is added to the module's thread attribute rather
than ignored (or, when stopping, replacing it), and the default attribute
is 0 rather than the module's own attribute. A nonzero mpidstack puts the
stack in that partition, which has to be user-accessible for a user
module and kernel-only for a kernel module.
A failed thread creation is now returned instead of asserting.
Hardware test: modules/startoptions.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Nine tests of GE probe jobs that the software renderer reproduces bit for
bit (transform, planes, coverage, lines, texture, lighting, curves, nearclip,
pixel), recorded on a PSP.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
hleDelayResult and Sas's delay put the wait on whatever thread was
current, which in an interrupt handler is the idle thread it runs on.
With both idle threads waiting there's nothing left to schedule, the
same crash as sceDisplaySetMode in Gods Eater Burst's vblank handler.
Where pspautotests intr/delays shows what hardware returns there,
match it: sceIoOpen and __sceSasCore fail with ILLEGAL_CONTEXT,
sceMpegCreate with 80618008, and sceAtracReinit can deinit but not set
up the codec (807f00fd).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Without SSE or NEON, triangle pixels got the secondary color in place of
the primary one plus it, so lit triangles came out black. It showed as
the "unexplained" known failures on riscv64 and loongarch64, and broke
the new gpu/lighting/shademap there. Reproduced on arm64 by building
without NEON.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Recorded on hardware (pspautotests threads/tls/timeout), a Tlspl
allocation follows the same timeout rule as the other waits, including
failing at once for 0 and 1us without writing the timeout back, which the
shared rule it moved to in the last commits didn't give it yet. Before
that it waited the raw timeout, ~30us short.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
On hardware a thread waiting for vblank returns ~53us after it, where we
had it back in ~5us, and the first of four waiters runs after ~85us: each
waiter beyond the first adds ~9us (pspautotests threads/scheduling/
vblankwake). The waiters are now released by a separate event 48us + 9us
per extra waiter after the vblank. Which vblank a wait is for is still
decided at the vblank, so a thread that starts waiting in between still
waits a whole frame (sceDisplay section version 8).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Timed on a PSP, each way of handing the CPU to another thread (the call
and the switch together):
hardware before now
rotate to an equal thread 7 14 7
signal, better thread runs 10 17 10
it waits again, back to caller 10 19 12
wakeup, better thread runs 8 13 6
it sleeps again, back to caller 7 12 6
start a better thread, entry 30 28 30
thread ends, back to its waiter 21 13 20
notify, better thread's callback 14 13 14
A switch between two threads now costs 1150 cycles instead of 2700.
Starting a better thread costs 2000 cycles more, ending a thread 3300,
and setting up a callback 1800.
Also splits a wait timeout's ~30us into the deadline being taken 12us
into the call and the timeout going off 18us after it. That only changes
the time left written back, which threads/semaphores/wait and
threads/fpl/cancel pin between them. intr/vblank is re-recorded so it
no longer depends on the phase of the frame.
threads/callbacks/combos now passes.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
On hardware, notifying a callback of a thread in a CB wait takes it out of
the wait at once, even though the callback only runs when the thread would
get the CPU. A semaphore signalled in between doesn't end the wait: the
callback runs first, then the wait resumes and takes it (pspautotests
threads/callbacks/combos). We left the thread on the wait list until the
callback started, so the signal ended the wait and the callback didn't
run.
The notify now pauses the wait, as starting a callback used to. If the
callbacks are canceled before the thread's turn comes, the wait just
resumes (Thread savestate section version 7).
threads/callbacks/combos goes in the to-do list: a callback returning to
the thread that notified it still takes ~13us where hardware takes ~9,
part of the context switch cost.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Every wait with a timeout behaves the same on hardware (pspautotests
threads/scheduling/waittimeouts). The deadline is taken, and the alarm set
up a moment later. If the deadline has passed by then, the wait fails with
WAIT_TIMEOUT at once, without yielding or writing the timeout back. That's
usual for 0us, half the time for 1us, and rare after; AllocateVpl does more
first. Otherwise it ends max(t, 205us) + ~35us after the call. Each object
had its own guess (24/245, 25/250, 20/250 and so on), and only MsgPipe had
the immediate case.
__KernelWaitTimesOutAtOnce() and __KernelWaitTimeoutUs() now do it for
semaphores, event flags, mutexes, lwmutexes, mbx, msgpipes, fpl, vpl and
WaitThreadEnd. The latency past the deadline isn't counted in the time
left written back.
Outcomes that hardware decides by the clock's phase (these, and
sceKernelDelayThread returning at once) go with the likelier one. Ones
between 50% and certain are instead spread evenly over calls, so a polling
loop can't lock into never yielding (sceKernelThread section version 7).
This replaces the pseudo-random choice for delays.
Also adds threads/scheduling/readyqueue, which already passes.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
On hardware sceVaudioChReserve takes ~260us once it gets past the busy
check, succeed or fail, and worse threads can run meanwhile. Releasing
takes ~25us and doesn't wait. We returned at once, which is what
audio/sceaudio/reserve's [r] markers showed; it now passes.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A delay's deadline is now + usec, and the clock is read again when the
alarm is set. If the deadline has passed by then, the call returns 0 at
once without giving up the CPU. On hardware that makes
sceKernelDelayThread(0) return at once about 60% of the time. On a thread's
first wait after it starts, a delay of 1 does so about two times in three
as well (pspautotests threads/scheduling/delayzero). We always waited at
least 210us.
The choice is pseudo-random off the tick count, not the tick phase, since
our cycle counts are regular enough for a polling loop to lock into never
yielding. Threads remember whether they've waited since starting (Thread
savestate section version 6).
Also moves threads/vpl/create into the passing tests: re-recorded on 6.61,
it agrees with what we do for partitions 8 and 9.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>