Commit Graph
48 Commits
Author SHA1 Message Date
Henrik RydgårdandClaude Opus 5.5 8560a2df75 IR: Log compiled jumps to invalid addresses at debug level
A block that jumps to an invalid address is usually code that never runs,
such as a call through an import that isn't linked yet, and the error-level
"Jump to invalid address" sent people chasing it. A jump that actually runs
still fails as before.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 17:32:43 +02:00
Henrik RydgårdandClaude Opus 5.5 bafdb45128 ME: Syscalls to the firmware's cache functions do nothing
Kernel code the ME runs calls a few firmware functions directly: POPS's
ME loop calls sceKernelDcacheWritebackInvalidateAll for every sample. On
a PSP the loader links kernel imports as direct jumps, so the ME runs
the function's code; here they're HLE syscall stubs. The cache functions
only work on the calling CPU's caches, and the ME's aren't emulated,
so they return 0 and do nothing, as does an unresolved import (as on
the main CPU). Others are still an error, now naming the function.

The IR ends the block after one, as for a syscall on the main CPU: a jr
with it in its delay slot leaves the exit to it, and the ME ran on into
the next stub.

A syscall instruction of the ME's own should take its exception vector
(ExcCode 8); none has come up yet.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 12:50:46 +02:00
Henrik RydgårdandClaude Opus 5.5 090e215a0a ME: Boot Sony's ME firmware, as me_wrapper does
Instead of only putting the image's code at 0x88300000, the ME now runs
it to where a PSP's ME is after boot: idle in its main loop's halt,
waiting for commands. As me_wrapper's boot (6.61, sceMeCore_driver
5dff5c50 and 0x1c30) and its ME stub leave things: the code at
0x88300000, the image's second stream still compressed after it, the
boot page's parameters (0x70C, 0x710 the CPU clock in MHz, 0x714), and
the ME at 0x88300000 with a0 at the second stream, which the code
decompresses into eDRAM itself. The stub's part (KL4E, caches) is done
here, since it runs main CPU kernel routines.

On a PSP the firmware has long since booted when a game starts, so it
runs to its idle halt the first time the ME runs, outside emulated time
(the JIT can't run earlier, at kernel init). About 80ms of startup in a
Debug build.

The compressed copy and the starting stack go below our idle threads'
stacks at the top of kernel memory, where a PSP has them higher up.

The firmware also needs:
- the ME to ignore the low two bits of jr/jalr targets: its command
  table keeps flags there (interpreter, and the IR, for the ME only)
- source 5 of the ME's interrupt controller, the codec hardware it
  starts and waits for in halt during init, which isn't emulated, so it
  finishes at once
- sysreg 0x54 and 0x5C kept

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 12:06:11 +02:00
Henrik RydgårdandClaude Opus 5.5 fa49876414 ME: Run the Media Engine on the IR interpreter
Unless the interpreter is selected, the ME gets its own IRInterpreterJit,
with its own block shadow, and runs it without CoreTiming
(RunDowncount, split out of the dispatcher loop). Its MIPSState never
touches the main CPU's replacement hook.

The IR frontend compiles through the CPU's address space: instructions
read as they are in the ME's memory (no main CPU replacements or hooks),
kernel mode always, jump targets and block bookkeeping checked against
its rules, syscall left to the interpreter (which traps it). An
interpreted instruction that ends a block now gets its own pc first, so
halt goes on from the right place.

The main CPU's icache invalidations are passed on to the ME, which runs
code from the same RAM.

The unit tests run the ME on both cores. mcidclan's me-soft-interrupt
runs about four times as fast.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 10:28:50 +02:00
Henrik RydgårdandClaude Opus 5.5 5631c3c9b6 Interpreter: Continue past branches where the IR cores do
The IR frontend compiles on past a conditional branch that isn't taken,
so the IR cores don't check downcount there, while the interpreter
ended its block at every branch. Events then landed on different
instructions, and a game's trace left the interpreter's within a few
hundred syscalls.

The interpreter now applies the same rule at run time: not likely, the
operands not decided by their registers, no branch in the delay slot,
no prefix pending after the delay slot, and the same instruction and
branch limits, counted the same way. It also goes on past a beql/bnel
over a break, which the IR frontend drops. The limits move to IRInst.h
so both use them.

With it, the interpreter, IR interpreter and ARM64 JIT produce the same
trace of syscalls and thread switches over 5 emulated seconds of God of
War, Tekken 6 and Daxter.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-15 17:43:31 +02:00
Henrik RydgårdandClaude Opus 5.5 6a2fa313e6 CPU: Make the interpreter and IR cores agree on timing
The cores charged cycles differently and checked downcount at different
places, so interrupts and thread switches landed on different
instructions, and a game could take a different path on each core.

- IR: j, jal, bc1t and bc1f now charge their delay slot.
- IR: a syscall sees every earlier instruction charged, including a
  branch it's the delay slot of, and is charged once it returns. It used
  to charge itself first, or, in a delay slot, never.
- Interpreter: a skipped likely delay slot costs what the instruction
  would, as in the IR cores, instead of 1.
- Interpreter: both run loops go on to the end of what the IR cores run
  as a block before checking downcount, and charge each instruction as
  it runs.

The CPUEquivalence fuzzer now compares the cycles up to its terminating
syscall. With continueBranches off, the three cores now produce the same
trace of syscalls and thread switches, ticks included, over several
emulated seconds of commercial games. With it on, the IR cores leave the
interpreter within a few hundred syscalls, as it moves block ends.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-15 17:43:21 +02:00
Henrik RydgårdandClaude Opus 5.5 f247df5e4d IR: Compile on past conditional branches
A non-likely conditional branch now exits to its target when taken, and
the block goes on with the not-taken path, up to 8 branches and 96
instructions. Loops written as a few blocks become one with one exit per
iteration, and code around branches gets optimized together. Branches
decided by their operands, like b, still end the block.

Not with a prefix pending, as blocks assume default prefixes on entry
and only the end of a block checks that it leaves them so.

10 emulated seconds, Vulkan, ARM64: cycles -4.6% in God of War, -3.5%
Killzone, -3.0% God Eater, -2.8% Daxter, -2.3% Tekken 6, -2.2% GTA,
-2.1% ATV, about -1% in the rest.

docs/cpu-equivalence.md gets the fuzzer's new classes and what it found
on this branch and in #22576.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-15 11:02:17 +02:00
Henrik RydgårdandClaude Opus 5.5 9de0f6e45d bltzal and friends test rs from before they link
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>
2026-10-15 09:55:35 +02:00
Henrik RydgårdandClaude Opus 5.5 a361dfc490 Drop unused Config.h and SmallDataConvert.h includes
Config.h is edited about 100 times a year and each edit recompiled 198
files; now 172. SmallDataConvert.h pulls in arm_neon.h and was included by
headers that don't use it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 12:13:42 +02:00
Henrik Rydgård 67ddf899ba Plumb through the PC value for syscalls, so we can get better diagnostics for unresolved ones. 2026-08-15 19:14:13 +02:00
Henrik Rydgård ae14ebb6ac IRWriter: Remove the confusing and inefficient AddConstant 2026-08-15 18:31:20 +02:00
Henrik Rydgård ba148e5ec7 JIT/IRJit: Delete an old "function preloading" experiment
This caused some confusion while trying to debug #20502
2025-06-11 15:45:18 +02:00
Henrik Rydgård 962bd8239d Remove more excessive error reporting. 2025-03-02 02:28:45 +01:00
Henrik Rydgård e01ca5b057 Logging API change (refactor) (#19324)
* Rename LogType to Log

* Explicitly use the Log:: enum when logging. Allows for autocomplete when editing.

* Mac/ARM64 buildfix

* Do the same with the hle result log macros

* Rename the log names to mixed case while at it.

* iOS buildfix

* Qt buildfix attempt, ARM32 buildfix
2024-07-14 14:42:59 +02:00
Unknown W. Brackets a8edf5fa24 riscv: Reduce bloat in jit fallbacks. 2023-07-25 19:42:04 -07:00
Unknown W. Brackets bac36df453 x86jit: Refactor and fix jump in branch delay slot.
This seems cleaner, instead of the duplication of lines for each branch
type.
2022-09-03 19:58:46 -07:00
Unknown W. Brackets d08ee44cf4 irjit: Handle branch/jump in branch delay slots.
See #15952 for more detail.
2022-09-03 19:05:31 -07:00
Unknown W. Brackets bc16a55028 jit: Count delay slot cycles separately.
This makes it easier to count cycles per instruction, instead of ignoring
the delay slot's instruction for cycle count.
2021-04-12 07:04:22 -07:00
Unknown W. Brackets 5d60fa0d0d Common: Maintain C++11 support in sign extend. 2021-01-31 08:44:02 -08:00
Unknown W. Brackets 1b00da2f3a Common: Sign extend w/func not chained casts.
Should be clearer to read and easier to get right.
2021-01-31 01:25:52 -08:00
Unknown W. Brackets e99c69f19e jit: Be very clear on sign extension. 2021-01-30 11:41:30 -08:00
Unknown W. Brackets c179cad5c2 jit: Make branch shift more obvious.
And also not technically undefined behavior.
2021-01-29 20:53:41 -08:00
Henrik Rydgård 821817e6d4 Move the profiler to Common 2020-10-04 11:42:16 +02:00
Henrik Rydgård c5e0b799d9 Remove category from _assert_msg_ functions. We don't filter these by category anyway.
Fixes the inconsistency where we _assert_ didn't take a category but
_assert_msg_ did.
2020-07-19 20:33:25 +02:00
Unknown W. Brackets 3c34c7c456 irjit: Add jump crash checks.
Doesn't seem to have any significant impact on performance.
2020-07-12 22:17:36 -07:00
Unknown W. Brackets 97674b80bd irjit: Skip preloading blocks with jump to 0.
These will be changed before executing anyway.
2018-01-06 17:23:53 -08:00
Unknown W. Brackets bc541bd020 irjit: Encode downcount directly as a constant.
Simpler this way, now.
2018-01-03 23:32:31 -08:00
Unknown W. Brackets b11858d9a0 irjit: Properly account for delay slots in size.
Otherwise we think blocks are 4 bytes too short, which can affect
invalidation.
2018-01-01 22:54:40 -08:00
Unknown W. Brackets 33b073c545 Jit: Fix syscall outside delay slot.
Doesn't happen in real games, but useful in debug code.
2017-06-04 10:39:01 -07:00
Unknown W. Brackets 7cd666c351 jit-ir: Decrease downcount after delayslot.
Except for likely delay slots.  This makes breakpoints work more
correctly when they trigger within a delay slot.
2016-07-02 16:35:56 -07:00
Henrik Rydgard 0541fe36df Symbian buildfix, fix for fpu test 2016-05-14 15:26:43 +02:00
Henrik Rydgard 64eda6a4ec IR: Split Syscall into Syscall and ExitToPC, so we can put ApplyRoundingMode in between. 2016-05-14 14:32:22 +02:00
Unknown W. Brackets efc8a8e353 Hack to make Symbian build. 2016-05-13 23:56:17 -07:00
Henrik Rydgard f636b2a315 Minor build and other fixes 2016-05-13 19:31:27 +02:00
Unknown W. Brackets 066b0b7fdf jit-ir: Optimize out beql; break; sequences.
These are often used following divs, and are harmless.  Things get a bit
easier if we just never compile them.
2016-05-13 07:59:39 -07:00
Unknown W. Brackets 29ed8d2201 jit-ir: ExitToReg doesn't write to registers. 2016-05-12 18:34:27 -07:00
Henrik Rydgard 558bb197c7 More VFPU 2016-05-09 23:47:56 +02:00
Henrik Rydgard e806c369b2 Separate the IR frontend from the IR "Jit" 2016-05-09 19:57:18 +02:00
Unknown W. Brackets eb6551d72a jit-ir: Correct downcount handling.
Oops, was wrong - already accounted for delay slots.  Clear so we don't
double count when emitting a syscall.

Fixes FF4 utility msg flickering.
2016-05-09 01:13:53 -07:00
Henrik Rydgard 492ea5fac4 Address a bunch of comments, thanks for the review 2016-05-08 21:38:03 +02:00
Henrik Rydgard 14df39d7c9 Fix IRTEMP clash bug. Add more cases to the constant propagation pass. 2016-05-08 10:36:37 +02:00
Henrik Rydgard aae32bd929 ir-jit: Re-enable mult. Fix bvf/bvt 2016-05-08 02:47:19 +02:00
Henrik Rydgard ce8aae5ed1 Make the IRJit core selectable in developer tools 2016-05-08 01:43:27 +02:00
Henrik Rydgard a33f8b68c6 ir-jit: Get rid of the regcache. Should be replaced with optimization passes. 2016-05-07 23:12:53 +02:00
Henrik Rydgard 750d520cc7 Initial work on mult and friends. Fix another bug. 2016-05-07 22:27:58 +02:00
Henrik Rydgard 12edfcea5a Enough to run cpu_alu.prx. 2016-05-07 21:00:30 +02:00
Henrik Rydgard 4acf85aa06 It's kind of starting to run 2016-05-07 17:37:19 +02:00
Henrik Rydgard d399c4a470 Initial commit for IRJit 2016-05-07 13:58:29 +02:00