How Dolphin finally cracked the code on Star Wars: Clone Wars, now emulates every GameCube title

Emulating consoles on modern
PCs is a complicated business. There are significant low-level
differences between the architecture of a console and that of a PC.
While some of these issues can be brute-forced by raw computational
horsepower, others heavily resist this kind of solution. Dolphin, the
popular emulator for GameCube and Wii titles, recently released a major
update to its own source code that finally enables emulation on the last
title standing: Star Wars: The Clone Wars.

The team published a blog post
detailing how it accomplished this task. It’s an interesting example of
how the original developer’s decision to take advantage of some
rarely-used GameCube capabilities prevented their game from being
emulated for over a decade. In this case, the problem boiled down to the
GC’s memory management unit, or MMU.

The MMU inside the GameCube provides games
with virtual memory addresses that it maps internally to physical memory
locations. The MMU is capable of providing either a Block Address
Translation (BAT), which remaps a large chunk of memory, or with
finer-grained page tables for small amounts of memory. The GameCube used
an MMU in the first place because it allowed the CPU to cache memory
accesses, and because there’s only 24MB of RAM in the system, despite
having a 4GB maximum addressable space. The diagram below shows how MMUs
work, in general terms.

Image by Wikipedia

Dolphin was already capable of emulating the
GameCube’s MMU in several ways. Most games just use the default BAT
mappings provided by Nintendo. Support for this mode is hard-coded into
Dolphin. The emulated console doesn’t “know” that its data requests are
being filled from a very different memory subsystem than the one the GameCube
shipped with. In this mode, the MMU isn’t actually doing any address
translation — it knows where the GameCube expects to find memory based
on the address passed to it, and it retrieves the corresponding block of
information from the PC’s RAM.

The second form of emulation that Dolphin supports is predictable invalid memory
requests. The GameCube included 16MB of RAM that was mapped to the
audio DSP, but many games use this pool for additional memory. Provided
they do so in predictable fashion, Dolphin can grab those addresses
(even though they’re invalid) and hand the game the data its requesting —
provided it always requests information from the same set of invalid
memory addresses.

But what happens when the addresses are both invalid and
unpredictable? In the past, this killed game performance. Actually
emulating the MMU takes thousands of CPU cycles, and the pace of
improvement in CPU clock speed has all but stopped. The GameCube CPU
might have only run at 485MHz, but our modern chips are just 10x faster
in terms of raw clock speed — and there are functions that simply can’t
be emulated effectively when doing so costs thousands of CPU cycles.

Custom-defined BATs are much harder to emulate.

From the Dolphin team’s blog post:

Handling memory checks (memchecks)
is slower because it harms the performance optimization “fastmem”.
Fastmem maps the GameCube/Wii address space to host memory and then
marks all of the emulated invalid memory as allocated for the host PC.
This allows Dolphin to use the host CPU’s exception handler to do the
dirty work when catching exceptions. When it does catch an exception,
Dolphin has to fallback from fastmem to slowmem in order to handle the
address, which can be a huge performance dilemma.

Memchecks are the core of what Enable MMU
does, and it’s the key reason why MMU Enabled titles have been so slow
in Dolphin. There are cases that require falling back to the
interpreter, it doesn’t work with fastmem, and they’re even slower than
normal memory accesses on console!

Recent code contributions by Fiora boosted
performance in one MMU title (Star Wars: Rogue Squadron) by 10x and in
most others by an average of 100%, but that wasn’t enough to solve the
problem of Star Wars: The Clone Wars. This
particular title actually defined its own BAT — the only game known to
exist that did so. Because Dolphin fundamentally relied on the idea of a
hardcoded BAT, there was no way to address this edge case without
rewriting the entire memory emulator subsystem, and possibly not without
ruining performance in a great many other games in the process.

One of the Dolphin contributors, magumagu,
evidently came up with a way to rewrite Dolphin to support The Clone
Wars’ custom BAT mapping without compromising performance in any other
title. According to the Dolphin team, previous attempts to support the
game had the side effect of reducing performance in other games by up to
30%. While the team has taken an 8-15% hit in other MMU titles, it
believes it can recover this loss through further tweaks and
improvements. Other games should actually see improved performance and
fewer bugs as a result of the rewrite, so the gains should be well worth
it in the longer term.