Step 07 · Emulation foundations

Why there's no CPU emulator

Search the repository for a general guest-CPU interpreter or dynamic translator and you'll find neither. This is the single idea that explains the shape of the entire project — get it now and most of the rest follows.

Before this page: What an emulator is. View the learning route.

Read

KytyPS5 has no general guest-CPU interpreter or dynamic binary translator. It does generate ABI stubs and instruction trampolines, and it has a separate GPU shader compiler. This chapter explains how native guest-CPU execution fits those pieces together.

The instruction sets are the same

A PS5 game contains x86-64 machine code. In a compatible x86-64 host environment, most instructions can execute directly. Kyty handles specific instruction-feature gaps separately. The emulator:

  1. Allocates memory at the address the executable wants,
  2. Copies the code segments into it,
  3. Marks those pages executable,
  4. Sets up a stack and jumps to the entry point.

From that instruction onwards the CPU executes ordinary game instructions directly. The emulator is not "in the loop" at all — it only regains control when the game calls a function the emulator provides, or when the hardware raises a fault.

The mental model that matters

KytyPS5 is not a simulator that steps through the game. It is a host environment that the game runs inside. It is closer in spirit to Wine — which runs Windows programs on Linux — than to an emulator like Dolphin. Everything the emulator does is reactive: it responds to calls, to page faults, and to command buffers.

What that buys, and what it costs

ConsequenceDetail
good Full CPU speedNo translation overhead. CPU-bound games can in principle exceed console performance on a fast PC.
good Vastly less codeA competent x86-64 JIT is tens of thousands of lines on its own. Kyty spends that budget on graphics instead.
hard No general instruction-level controlThere is no general translator through which every memory instruction passes. Kyty uses hardware page protection for coherency and targeted rewriting for specific host incompatibilities, so the exception handler remains essential.
hard Crashes are real crashesA guest bug corrupts the emulator's own process. There is no sandbox. Hence the forensic crash dump: the faulting guest thread, all registers, the code bytes around the fault, the top of the stack.
hard Host CPU features must matchKyty patches or handles selected instruction-feature gaps. Unsupported forms can still fault; it is not a general instruction emulator — see Page faults & CPU/GPU coherency.
hard ABI and OS assumptions leakGuest code assumes System V registers, a working fs segment, 16 KB pages, and a FreeBSD kernel. None of that is true on Windows. Calling conventions & the ABI wall, Patching guest instructions and The guest address space are about closing those gaps.

The path a frame actually takes

Before any of the detail, here is the whole system in one animation. Every chapter from 25 onwards is an expansion of one of these eight boxes.

Where the difficulty actually went

Measured in lines of C++ in src/:

Where the code is158,608 lines · 391 files
libs — HLE system libraries
52,039
graphics/shader — recompiler
34,843
graphics/host_gpu — Vulkan
18,355
kernel — threads, memory, files
13,148
graphics/guest_gpu — PM4
10,650
common — platform layer
8,148
loader — ELF, linking
7,366
graphics/presentation
7,418
launcher — Qt front end
5,880

Counts are physical lines in .cpp and .h files under src/ at d2413fc2, including blank lines. The total includes the three entry-point files; the bars show the nine subsystem directories. Graphics accounts for 71,266 lines.

Current compatibility paths

Optional AMD patches and host instruction gaps

--amd-cpu enables the shared guestInstructionPatcher.cpp path on Windows, Linux and x86-64 macOS. PatchGuestInstructions(..., protect_memory, emulate_amd, host_features) uses function boundaries from .eh_frame and registered trampoline space. It patches supported VRSQRTPS forms and fills host-feature gaps for EXTRQ, INSERTQ, RDPID and CLWB, preferring native trampolines with safe trap fallbacks. Windows red-zone protection is controlled separately by --redzone.

The patch result records per-family counts for reciprocal square root, EXTRQ, INSERTQ, RDPID and CLWB, distinguishing native patches from trap fallback. Host features decide which compatibility path is needed; x86-64 macOS signal handling also preserves the SSE4a context. Native TLS keeps fiber context valid across host-thread migration, and fiber ownership preserves small guest stacks.

Watch

An interpreter grinds through a fetch–decode–execute loop for every single instruction. KytyPS5 does none of that. Step this to see the difference in where the time goes.

Try

Now drive it yourself. Run instructions through both models and watch the cost diverge — then note what the native path gives up: there is no hook, no instrumentation point, no place to inspect. That absence is what the rest of the emulator has to work around.

Do

Prove it to yourself in the source. Each of these takes a couple of minutes; tick them off and this topic is marked complete.

Checkpoint

Where this goes next

Because guest code runs natively, it arrives carrying assumptions the host doesn't satisfy: System V registers, a working fs segment, 16 KB pages, a FreeBSD kernel. The next three topics are each about closing one of those gaps.