On Backwards Compatibility

I'm certain that many of you have been waiting for us to say something about how backwards compatibility works on Xbox 360. It is a very complex topic, to say the least. Thanks to XboxFan, a member of the backwards compatibility development team here for providing a lot of these details.

Xbox is based on a Pentium III processor, while Xbox 360 is based on a custom triple-core PowerPC processor co-developed with IBM. This is but one of many differences between the platforms, but one people are familiar with. Digging deeper, you would find that nearly everything has changed. Graphics, audio, networking, etc. have all been replaced with different subsystems.

Xbox games all run on the assumption they are being run on the exact set of original hardware. Changing anything usually means breaking some kind of behavior games depend upon. Therefore, Xbox 360's backwards compatibility had to emulate the exact configuration of an original Xbox.

One way to do this is embed the parts of an original Xbox into an Xbox 360. This was the path Sony chose to use in PlayStation 2's compatibility. However, Microsoft doesn't own the intellectual property in Xbox: it's owned by various other companies including Intel. Microsoft wouldn't have the freedom to take the parts needed for compatibility, shrink them down, and put them inside Xbox 360. And no one would want a bigger power supply any way :)

Another option is software emulation. Many of you already know this is the path Microsoft has chosen. Our software emulator works much like emulators for other platforms like SNES and Genesis. However, one key difference to keep in mind is that the Xbox emulator is emulating the immediate previous generation of games. Most emulators come out many years after a console has launched and run on PCs that represent quantum leaps in performance.

Writing an emulator isn't the same as writing other pieces of software. Other software has a lot of top-down process to it: design, prototype, revise, etc. The goal and design of emulation is pre-ordained: do whatever it takes to act like what you're emulating.

At some point, your first attempt at emulation acts like the old hardware as well as it can. At that point, you try your luck: does Halo run? The answer is both yes and no at this stage. Yes, the executable loads and starts running some x86 code, but no you don't see anything on the screen. Then it promptly crashes.

Debugging

Traditionally, when your software crashes, you fire up a debugger, step through code, and analyze the logic. Usually, source code accompanies your debugging to help you track stuff. It's quite different when you're debugging emulated software - especially software you had no hand in writing. Is the problem due to code in the emulator? Or is the code inside the emulated stuff just plain wrong? Here's what XboxFan had to say about debugging:

Debugging BC ["backwards compatibility"] is much like debugging any other software, but there are a few things that make it harder: We typically have neither source code nor symbolic information for the games we’re debugging, so we’re just looking at raw assembly code with no external clues as to what it’s doing (or what it’s supposed to do). Obviously debugging code others wrote is always harder than debugging code you wrote yourself. It’s hard to know what the code normally does, and indeed some games already have a few bugs of their own. Debugging a mixed environment -- both the emulated Xbox (x86 assembly in one address space) and the translated native code and emulator runtime (PPC code in another address space) – can also be challenging. You have to master a lot of aspects of both the original Xbox (hardware, compiler, and operating system) and the Xbox 360.

Debugging software in general is hard work. Unlike feature work, which can be meticulously planned out, estimating schedules and distributing the work among many different people, debugging can usually only be done by one person at a time and there’s no way to know up front how long the process will take. Perhaps you’ll find the bug quickly and fix it quickly. Or perhaps it will take a week to find. And while you work on it you may uncover additional bugs.

Most software developers don’t actually debug software – we troubleshoot. If a system link game is disconnecting sometimes, then it must be a problem with the networking code, right? We first look at the code that handles networking. If system link worked fine a few days ago, then we look for code changes that happened around the time it stopped working. Usually in this way it’s possible to quickly narrow down where the problem is and fix it. In contrast, debugging involves stepping through the code one instruction at a time to see exactly what it’s doing.

For BC, debugging is especially challenging. Although sometimes during our daily work we make a bad code change that temporarily causes something that previously worked to stop working, the vast majority of the time you’re debugging something that has never worked. There is no way to troubleshoot this; you have to debug the code step by step until you uncover what’s missing or wrong.

So for example, during BC development we sometimes had problems with system link games. Once it was caused by the emulator missing a cryptographic key. Another time, it was caused by a very small precision error in floating point. Yet another time, it was caused by a subtle bug in the CPU emulator that caused it to take the wrong branch in the game’s internal state machine and ultimately (millions of instructions later) disconnect.

Performance

Once you've got a game up and running, it may not perform very well at all. If you're a computer science student, you most likely understand the idea of coding a horribly performing, but correct, implementation of an algorithm - only to completely rewrite it a different way later. The same thing happens in emulation, only we get to take some shortcuts.

Luckily, backwards compatibility doesn't need to emulate things exactly right. One of the biggest problems in emulation are exceptions. Exceptions are interrupts that occur when something unexpected happens. For instance, dividing by zero, accessing memory you're not supposed to, etc. all raise exceptions. There are very few exceptions that video games care about. Many times, they will completely ignore them. When an exception occurs, many games simply crash or exit. Backwards compatibility on Xbox 360 exploits this common behavior - as well as other common patterns.

Here's some more from XboxFan:

Performance work is even harder. Once you’ve eliminated all the “obvious” performance bottlenecks, you’re left with possibilities that are neither certain nor absolute. You could change the code in this way, but it might not be faster – you won’t know until you try it. There might be several different ways to improve performance, and each way might improve some scenarios while degrading others.

When debugging, the correctness of each individual part is what matters. However, it’s not the raw performance of each individual part that matters, but the performance of the system as a whole. Individual code routines might have excellent performance on their own, but when used together one part can interfere with another in many ways (including cache effects, CPU pipeline effects, lock contention, etc.). There are so many variables and so many different things that can be measured, and the act of measuring performance affects the performance of what you’re measuring.

BC performance work differs from typical software performance work in only two ways. First of all, emulators do some highly specialized things -- like interrupt handling and very low-level memory management -- that most software programs (other than operating systems) never do. Secondly, it’s not usually the performance of the emulator itself that matters, but rather the overall performance as perceived by the emulated Xbox game. Most of our work isn’t to improve the performance of the code we wrote, but rather to improve the performance of the emulated games. Overall, we approach performance in the same way that all software developers do: Measure, make a change, and measure some more.

I wanted to speculate a little on what PS3 might be doing for backwards compatibility. Sony hasn't announced that PS2 hardware will be die-shrunk and placed inside PS2. If that's the case, there must at least be some software support for backwards compatibility. As Major Nelson noted in his podcast, Ken Kutaragi noted in a previous presentation that backwards compatibility was gated on games following TRCs (or TCRs as Xbox folk call them). I hope Sony doesn't alienate gamers based on an excuse like technical requirements. More on that in a future post, I think, since it's getting pretty late.