In 2026 anyone can play a 1996 title on a laptop, on a phone or even inside a browser. And there is a detail that rarely gets told: that machine does not understand the game’s code. It is not that the code is old, it is that it is written in a language its processor cannot read. Between old software and new hardware there has to be someone translating, instruction by instruction, in real time. That is an emulator, and its engineering is far more interesting than the game it runs.
The word is used for everything, so it pays to start by separating two things that have nothing to do with each other: emulating and virtualising.
Emulating is not virtualising
A hypervisor such as KVM, Hyper-V or Xen splits one physical server into several virtual machines, but the guest processor is the same as the host’s. Instructions run directly on silicon at native speed; the hypervisor only steps in when the guest touches something privileged — writes to a control register, reaches for a device — and triggers a VM exit. To make memory isolation free in hardware, nested page tables are used (EPT on Intel, NPT on AMD). The result: between 95% and 100% of native performance.
Emulating is something else: the instruction set architecture (ISA, the catalogue of commands a processor understands) is different. x86 and ARM64 share almost nothing: not the registers, not the flags, not the memory model. There is no hardware shortcut, so every foreign instruction must become one or several of its own. And performance is paid for in orders of magnitude.
The interpreter: read, decide and jump
The first strategy, the most intuitive one, is an interpreter loop: read the byte of the guest instruction, decode it, look up in a table the piece of code that implements it, and jump to it. It is the pattern used by 8- and 16-bit console emulators, and it works surprisingly well. The problem is the cost per instruction: an indirect jump, a table lookup and the bookkeeping of the guest processor state — registers, flags, program counter — which usually lives in memory instead of in real registers. Every guest instruction costs dozens of host instructions. A factor of 10 to 100 times slower, measured raw.
Classic emulators soften this with C tricks: compiler extensions such as the computed goto, which turns the table lookup into a direct jump, or duplicating the execution loop per addressing mode. Even so, the ceiling is clear.
Dynamic recompilation: the translator that learns
The modern answer is not to interpret but to translate code and keep it. That is dynamic recompilation (dynarec), and it is a just-in-time compiler tucked inside the emulator. The procedure is always similar:
First, the guest code is split into basic blocks: fragments that start at a jump target and end in a jump, a call or a return instruction. Each block is translated once into host instructions and stored in a translation cache. The next time the guest passes through, there is nothing to decode: the already translated block simply runs.
The interesting part is in the details. Guest registers are mapped onto real host registers — x86-64 has 16 general-purpose registers; ARM64 has 31 — which avoids much of the shuttling to memory. Flags are a case apart: on x86 almost every addition updates the flags register (carry, zero, sign…), but in practice only a conditional jump ever reads it. A serious emulator does not compute them on the spot: it saves the operands and evaluates them lazily, only when somebody asks. And code that modifies itself — common in old games that decompress routines into memory — forces blocks to be invalidated: pages are protected read-only and, when the guest writes, the page fault tells the translator that its cache is stale. QEMU does exactly that in its TCG (Tiny Code Generator), the translation engine it shares across architectures ranging from a microcontroller to a mainframe.
The outcome: going from a 10-100x loss to one of 1.5-5x depending on the quality of the translator. And a curious consequence: the emulator spends its day compiling, so the first pass through a region of code is slow and the following ones are fast. That is the real reason behind the slowdowns when many emulators start up.
The devil is in the details
Translating instructions is the easy part. The hard part is making the guest’s world behave like the host’s.
The memory model is the biggest headache. x86 has a strong model, TSO (Total Store Order): a core’s writes are seen in the order they were made. ARM is weakly ordered: the hardware may reorder reads and writes as long as there are no explicit barriers. An x86 program translated to ARM as-is would execute sequences its author never imagined. There are two solutions: insert memory barriers on every shared access, which is expensive, or take advantage of the fact that Apple silicon cores include a hardware TSO mode that replicates x86’s strict behaviour and that Rosetta switches on when running translated code. It is one of the reasons that translation is so fast.
Then come the vector extensions. A 128-bit SSE fits neatly into an ARM NEON register, but a 256-bit AVX2 does not: it has to be split across two registers and the results stitched back together with extra code, and operations such as cross-lane permutations or gathers have no clean equivalent. Entire islands of the architecture are also left out: the 80-bit x87 floating point, repeat-prefixed string operations, certain decimal arithmetic instructions. Rosetta 2, for instance, has never emulated AVX: an application that requires it simply does not launch.
That is the ground where the 2026 game is being played. Windows on Arm’s x86 and x64 translation, christened Prism, added support for AVX and AVX2 late in 2025, plus BMI, FMA and F16C — precisely what video games and scientific software were asking for. Independent measurements published this year suggest that path is less optimised than the older routes: in some cases the same computation in AVX2, translated, turns out slower than doing it with SSE, because every 256-bit vector instruction becomes several. It is compatibility support, not yet equivalent performance.
Accuracy or speed: when one cycle decides the game
Emulation is a spectrum. You can be accurate at instruction level, accepting that internal timing does not match, or you can aim for cycle accuracy, or even fractions of a cycle. It sounds like purism, but it is not: games from the eighties and nineties were programmed by counting cycles. A background effect across scanlines depends on a video register being written at the exact moment the beam draws that line. If the emulator runs half a cycle early or late, the effect disappears and glitches appear that were not on the original machine.
There is also a requirement that is often forgotten: determinism. Games with lockstep online multiplayer — and modern rollback systems — do not send the game state, they send button presses, and they demand that every machine computes exactly the same thing. A single bit of divergence between two emulators is enough to desynchronise the match.
Out of that come two emulation philosophies, which emulator authors call LLE and HLE. The first also translates the original firmware — the BIOS, the boot ROM, the audio DSP microcode — and is slow but faithful. The second reimplements those functions in native code: it boots sooner and runs faster, but breaks as soon as a game uses the library in a way nobody had seen. Many modern emulators offer both and let you choose.
The GPU also speaks another language
In a console, the graphics chip does not draw: it executes command lists. The emulator has to read those lists — sometimes in a proprietary format with hand-written register writes, line by line — and translate them into a modern API such as Vulkan, Metal or Direct3D 12. Shaders, the small programs that run per pixel, are in turn translated from the original graphics ISA into SPIR-V, Vulkan’s intermediate format.
And a very visible problem shows up: compilation stutter. Every combination of graphics state (shader, blending, texture format) needs its own compiled program, and the emulator cannot know which ones it will need until the game uses them. The first time, the image freezes for a few milliseconds. Two well-known solutions exist: store on disk a cache of already compiled shaders — those files that take ages to build the first time you install an emulator — or generate ubershaders in advance, giant programs that cover every variant with internal branches. Dolphin, the GameCube and Wii emulator, popularised the second route and cut the stutter at the cost of slightly more work per frame.
Latency: what the benchmarks do not show
One detail remains that annoys players the most: input delay. Emulating adds layers — input loop, frame queue, vertical sync — and every layer adds milliseconds. The most aggressive technique to fight it is called run-ahead: instead of drawing the current state, the emulator simulates two or three frames ahead and, just before showing them, rewinds using an instant save state. The result is a response that feels better than the original console’s. The price is burning CPU on frames that will never be seen, plus an awkward requirement: emulation has to be perfectly deterministic to be able to rewind without breaking anything.
2026: binary translation is back at the centre
For years, emulating was a hobby for nostalgic people. Today it is front-line infrastructure, and this month’s news confirms it from the bitter side: Apple has detailed that Rosetta, the Intel app translator that has propped up the move to its own silicon since 2020, will remain available on macOS 27 and will be restricted from macOS 28 onwards to a handful of older games that depend on Intel frameworks. The world’s most widely used binary translation layer is being switched off.
At the same time, emulation remains the last line of defence for digital heritage. MAME keeps thousands of machines documented at register level; the Internet Archive preserves software from the floppy disk era; and the Video Game History Foundation’s 2023 study concluded that 87% of video games released in the United States before 2010 are no longer commercially available. Without emulators, that figure would be close to 100%.
And it is not only games. There are banking, industrial and administrative systems still running on instructions that are no longer manufactured, held up by software mainframe emulators such as Hercules, which implements System/370 and z/Architecture in C. Emulation is also the substrate of malware analysis labs, where suspicious code runs on an instrumented fake machine — and where the malware itself tries to detect the emulator by timing instructions that should take an exact number of cycles.
A contract with machines that no longer exist
Seen that way, an emulator is not a plagiarism of the hardware: it is a contract written on a specification. As long as the ISA is documented, the machine stays alive even if not a single chip is left. That is why x86, with four decades behind it, can run today on a phone, and why ARM or RISC-V processors will have their own Rosetta in thirty years’ time. The emulator does not preserve the devices: it preserves the only thing needed to bring them back, the precise definition of what they did, instruction by instruction.





