The State of: Wii64 Dynarec

Since this is my first post on the blog discussing the dynarec, I’d like to first explain what a dynarec is and why we’re going to need one to accomplish full speed emulation on the Wii.  Then I’d like to describe the history of the dynarec in our emulator, where its at now, and what needs to be done to get it working.

First of all, dynarec stands for dynamic recompiler, which is actually a bit of misnomer in the console emulation world: usually its not accomplished by creating an abstract syntax tree or control flow graph from the emulated machine code and running a target machine code compiler over it, which is what recompilation would really entail.  The proper term would be binary translation: for each emulated instruction, I convert it to an equivalent target instruction.  Since the N64 is a MIPS architecture machine, I take a MIPS instruction, decode it (determine what kind of instruction it is and what operands it operates on), and then generate equivalent PowerPC (GC/Wii use PPC) instructions to perform the operation that the MIPS instruction intends to.  What we try to do is take a block of code that needs to be run, and fill out a new block with PowerPC code that was created by converting each of the MIPS instructions in the block.  The emulator then runs the block of code as a function: it will return when a different section of code needs to run and the process repeats for the next block of code.

What we’re doing now is running an interpreter: instead of translating the MIPS code we want to run, we just decode each instruction and run a function written in C which performs what the MIPS instruction would do.  Though this may seem like less work: we don’t have to translate all the code and then run it; we just run it, but because the code is ran so many times and running the translated code is much faster than running each instruction through the interpreter, the extra time translating is made up for my the faster time running through long loops.

The dynarec was the first thing I started working on with the emulator: it seemed like the most interesting aspect and the most crucial for such a port (besides the graphics which I didn’t understand well enough at the time to do much useful work besides porting a software renderer).  It’s gone through a few different stages different stages: 1-to-1 register mapping binary translator, quickly dropped attempt at reworking the translator to be object oriented, slightly further progressed attempt at a MIPS to Scheme translator, and where I’m currently at: the first binary translator without 1-1 register mapping, confirming to the EABI (Embedded Application-Binary Interface).

I was concerned about performance initially, and I got a little greedy: I decided that since both MIPS and PowerPC had 32 general purpose registers, and MIPS has one hardwired to 0, and PowerPC has an extra register (ctr) I could move values into for temporary storage, I could do a simple translation of most of the instructions by using all the same registers as the MIPS would use on the PPC.  The idea was that I wouldn’t have to shuffle things in and out of registers; I would load the whole MIPS register set values into the PPC registers, run the recompiled code which would operate on those values, and then when its done with a block, store those values back and restore the emulator’s registers.  This was a bad idea for several reasons: small blocks that only fiddled with one or two registers still had every single register stored, loaded, and then stored and loaded again for each block, I had to disable interrupts because I destroyed the stack and environment pointers that were expected if any interrupts were taken, and because I couldn’t take interrupts, it was very difficult to debug because I couldn’t run gdb in the recompiled code.  I had developed a pretty large code base and a somewhat working recompiler before I truly came to realize all the drawbacks of the method: it ran some simple hand-crafted demos I had written in MIPS which computed factorial and a few other simple things, but overall it was too unweildy and inefficient to continue to debug.

My attempt at refactoring the code I had written in a OOP way was soon abandoned, but it did inspire some improvement to the way I generated instructions.  Instead of piecing together the machine code from all the different parts, I wrote new macros which would do that for me for specific instructions thus reducing some major code clutter in the translator functions.

I was unimpressed by the improvements I predicted I would see by refactoring the code in C++, and inspired by Daeken’s work on IronBabel to start the dynarec from scratch using a high-level language.  The idea and the code was much simpler: decode the instructions using high-level magic and instead of generating low-level machine code, generate high-level code to execute each instruction, collect all the code together, and run it as a function for each basic block.  I chose Scheme because how easy it is to generate and run code on the fly (since in Lisp, code and data are only differentiated by how they’re used).  The recompiler was a breeze to write, but interfacing with the C code proved troublesome.  Although I eventually got the code to run, I ran into issues with the unlimited precision numbers in MzScheme, and my other choice of Scheme, Tiny Scheme, didn’t support some bitwise operations and I never got around to adding them.

Finally, I decided to go back to the old code base and improve on it with respect to the issues I had discovered along the way.  I wrote more macros to clean up the code generation, I did away with 1-1 register mappings, and worked on compliance with the EABI so that I wouldn’t have any issues with interrupts and calling the recompiled code as a C function.  Now, instead of loading and saving 31 registers for each dynarec block, I load each register as its used, and I store their values at the end of the block or if I used up the alloted registers for storing MIPS registers (I use volatile registers so I don’t have to worrying about saving their values).  It’s not much more complicated to translate the instructions with the new mappings because for each block, the mappings are static and are kept track of while recompiling so I simply build up a table of mappings while recompiling which I flush at the end of each block.  EABI compliance was a matter of creating a proper stack frame for the recompiled code, and not touching certain registers; since I have a few special values (base address of MIPS registers in memory, address of interpreter function, zero, and a running count of instructions) that I need to be maintained to any other calls, I needed to save those registers on the stack in the proper locations and restore them when I returned to the emulator.  EABI compliance allows me to leave interrupts enabled while the recompiled code is running (in general, leaving interrupts disabled for extended periods of time is a bad idea) and allows me to step through recompiled code in gdb which greatly improves my ability to debug the dynarec.

The new format allowed me to debug things much easier: I could much more easily compare the original code and the effects of the recompiled code by stepping through.  Soon after the reworked dynarec was completed, I pushed through all the obvious bugs in the apploader (I had some issues with the calculation of the checksum of the ROM and invalidating recompiled code that was overwritten with new code).  Now the dynarec executes the standard apploader successfully, and begins running the code unique to each game.  However, I still haven’t seen anything much happen after that point as far as any graphics showing up or anything like that except for in a demo I wrote that blits an image to the screen after running some unit tests.

As I’ve recently purchased a PS3 and installed Linux on it, I have a full environment to test the recompiler under without the hassle of running on the Wii.  I’ve already made a quick port of my dynarec to run under PPC Linux, and I believe its breaking at the same points it was on the Wii.  Running in a full OS gives me access to more tools such as valgrind and better support in gdb which helps improve the rate at which I can narrow down and fix bugs especially as the progress further into the execution of the games.

Barring some issues dealing with interrupts and exceptions, I believe the dynarec is feature-complete at this point and there are some lingering bugs (possibly dealing with some instructions which I haven’t previously seen in action or some edge cases dealing with translation or execution) which need to be resolved in order to get the recompiler working.  There are a few instructions not recompiled which I intend to support after I have the basic integer instructions working: floating point instruction, 64-bit instructions, and loads/stores from/to the stack which will hopefully improve the performance of the dynarec once its running.  Of course, finding these bugs take time, and its hard to put any kind of ETA on finding and fixing them because I don’t know how many issues are lurking behind the one I’m currently stuck on, and its not always easy to track down the source of the issue so please be patient as we work to resolve these issues as its hard to get this all right.  However, I believe that with the dynarec running and the hardware accelerated graphics we have now, we can accomplish smooth, full speed emulation of most titles, and possibly even support some extras like high-resolution textures.  As things progress, I hope to keep everyone informed of how things are going, so look for more posts on this topic later on.  In the mean time, emu_kidid has made a video demonstrating the emulator in its current state on the GC so check it out.

16 thoughts on “The State of: Wii64 Dynarec

  1. Please guys keep the good work!
    I anxiously await your next release and I hope you will achieve full speed.
    I have two questions.
    1)When are you planning to release the next version?Are there any chances before Christmas?
    2)Are you planning to emulate the expansion pack games like Donkey Kong 64 and Perfect Dark?

    Thanks again for keep the dream alive!!! :-)

  2. @Damien:

    1) Its hard to say. If there’s anything we’ve learned, we can’t put a date on when the dynarec will be done because we don’t fully understand a lot of the issues, but once it starts running code, improvements to it will come much quicker.

    2) We plan to, but first we need to find a good balance between memory consumption and speed for the dynarec (which requires it getting working first) before we can consider eating up a whole other 4MB of RAM for expansion support. Please see our project goals page (there’s a link on the right of the main page).

  3. Hi !
    I follow your project since the beginning of your work and I’m very surprised of what your did fast. I thought you gave up this project to work on the PS1 Emulator but I’m reassured now ^^
    I can’t wait to play game like Banjo and Kazooie or Shadowman :)

    Thanks !

  4. Howdy!
    If I may, could I ask what sort of higher education you have received to be able to accomplish this sort of thing? I could barely keep up with your blog. YOU’RE A HERO TO MILLIONS… well, soon enough!

  5. @boyzinho666:
    That’s something we plan on doing eventually, but since that controller scheme lacks the right buttons in the right places, we’re going to wait until we’ve implemented user-configurable controls in the menu before we add support for wiimote + nunchuk since we assume that every person and every game will have different controls that work best for them.

    @Ken:
    I’ll take that as a compliment. I’m a senior in college going for my BS in CS, but I’ve been interested in computer programming since middle school. I certainly couldn’t do the emulator without sepp256 and emu_kidid though, they’ve contributed a lot to this project.

  6. Hey, I think this project is brilliant, it’s the most “wanted” Emu for the wii, people really just want it for the “main games” but there are some dam good games on the n64, I’m personally looking forward to your side project psx, my latest revision, plays GTA1 perfect, just controls are buggy “badly” but I’m a patient person, can’t rush good things, good things come to those that wait!
    +++Respect
    Thankyou and good look!

  7. Great stuff mn this is sounding and looking awesome.
    I’m not all that good with code and programming in general but that was a really interesting read and from what i could understand, it sounds like a HUGE undertaking.

    Good luck and Thanks, i’m really looking forward to being able to try out your hard work =)

  8. Merry Christmas to all the Wii64 team!
    Everything you wish may come true!
    And soon I wish we can enjoy your excellent work!

  9. Man, what you guys are doing is something really amazing. This emulator is one of THE reasons to own a Wii, for me at least, and I can’t wait to play some of my favourite games of all time on it. I just wanted to thank you guys for your hard work. Keep it up! :)

  10. Thanks for filling us in on this. I really enjoy these types of posts about the trials and thought processes that goes on in these projects. It speaks volumes of your (all three of you) dedication, creativity and intelligence.

    You guys should be proud of what you have already accomplished.

  11. Hey keep up your effort! The Wii64 has come so far and i can’t wait for the next release. Do you know when your next release could be? Thanks, Adam

  12. you guys rock, first you make so many emulaters with noting in retern then you go and do this (I just wish it wil start working (cant stand not having it working))honistly you guys are the rock stars of the wii hacking world, sorry i cant spell eather.