GP2X Dynamic Recompilation


Julius

Well-Known Member
Joined
Jan 20, 2004
Messages
1,128
Location
Germany
Website
freegamearts.tuxfamily.org
http://en.wikipedia.org/wiki/Dynamic_recompilation

This has been a topic several times now, and I know that there is currently some work beeing done to implement some MIPS->ARM9 dynarec into GP2PSX.

That got me thinking... since the ARM7 instructionset is very close to the ARM9 one it should be possible to do a really quick dynarec if I am not completely mistaken (sorry not a expert on this topic, so that's why I am asking).
Possible uses for this would of course be a GBA emu (moral issues aside)...

Maybe this DS emulator could be helpfull in getting something like that running? It has some preliminary dynarec functions (ARM7/ARM9->x86) but I bet at least the funtions for instruction-interception should be usable for a ARM7->ARM9 dynarec too, right?
http://dsemu.oopsilon.com/

Oh and I can't exactly remember why the GP32 GBA emu didn't use this approach and instead tryed to 'hack' the ARM9 into a ARM7, but any insights into this topic would be nice.
 
I don't think they used Dyanrec for the reason of speed and also that there was no real need to - you could use the MMU to map all the GBA's memory, and a spare interrupt to stop the processor and "do your own stuff" (like graphics emulation/etc).

If anyone wants to do a GBA emu for the GP2X and get it running under Linux, then they will need to use Dynarec, otherwise they'll have to throw out Linux first. It's obvious which would be the quickest in speed, but certainly not obvious which would be quicker to implement and debug.
 
Using the MMU allows for using a single memory image of the game's RAM and code, and very fast emulation, but it could potentially be incompatible (say the game uses an undocumented opcode that does one thing or nothing on ARM7, but maps to a real instruction on ARM9...) - if something like this happens, there's no way to fix it other than maintaining a set of code patches against different ROMs.

At least with dynamic recompilation, you can fine tune the emulation as much as necessary, but it's not going to be as efficient memory or speed wise (you still need to keep an original copy of the whole RAM/ROM, as well as creating emulation code and caching it at least for some time). There's lots of little gotchas involved - code running from RAM presents challenges in that you need to know if a memory write changed some code that you've dynamically recompiled. At least on a ROM based system like GBA, you have assurance that the ROM won't change... on PSX, everything is loaded in RAM so you can't be sure without making assumptions.

And then the real kicker: cycle counting. Want the emulated CPU speed to be right? All of the dynamically recompiled code needs to adjust a cycle counter to keep track of how far along it is in emulation, and I imagine this could get hairy to implement for loops, and on emulated chips with cache, it'll probably never be very accurate.
 
Also, don't forget that a lot of demos and commercial games use various speedup methods that the emulator must support.

For example, the interface to the GBA ROM cartridge is only 16 bits wide, so a lot of code runs in Thumb, but ARM code is run also, so you need to support both instruction sets.

Copying chunks of code from ROM into RAM, and running them from there gives huge speedups, as the RAM is fully 32-bit. This can be a real pain to emulate, as you need to know exactly when the data has changed, as you have not only got to worry about new chunks being copied from rom to ram, but some demos & games place self-modifying code here. Can get really hairy, as you've got the recompiled code + arm9's instruction caches + prefetch to worry about.
 
And then the real kicker: cycle counting. Want the emulated CPU speed to be right? All of the dynamically recompiled code needs to adjust a cycle counter to keep track of how far along it is in emulation, and I imagine this could get hairy to implement for loops, and on emulated chips with cache, it'll probably never be very accurate.

It's not that hard for the processor I'm making an emulator for, I don't think it is that much harder for others. I don't see how the cache effects it, in my case it's no biggie.

btw, I'm not used to this whole ARM thing. Where can I get a list of instructions with their corresponding opcodes? I looked around the ARM site and I haven't been able to find it. Do all these processors execute the same (or somewhat similar) binary code?
 
Well the cache problem is that you don't know how long a memory access will take on the emulated system without knowing if its data would have been in the cache - but on the bright side, programs for these sorts of systems usually aren't very dependent on precise timing anyway, since not only is it hard to emulate properly, it's hard to make assumptions about when coding as well.

In general the cycle counting problem is a little more complex with dynamic recompilation... with interpreter style emulation, you just adjust the cycle count with each emulated opcode, whereas in dynamic recompilation, you need to find how many an entire group of instructions takes and adjust the count based on that. It's the same approximate difficulty unless you want to try to pull cycle counting code out of inner loops to improve performance, and at that point a significantly more advanced recompiler is needed.

The kind of code where dynamic recompilation really shines is with long stretches of instructions that have no jumps in or out of them, and few memory writes to cause code overwriting concerns.

One plus with dynamic recompilation is that one can add manual tweaks to speed up code sequences that are frequently encountered, so if some game runs terribly slowly, it may be possible to isolate the code sequences causing problems and create faster emulation for them, possibly improving performance in other games too.
 
In general the cycle counting problem is a little more complex with dynamic recompilation... with interpreter style emulation, you just adjust the cycle count with each emulated opcode, whereas in dynamic recompilation, you need to find how many an entire group of instructions takes and adjust the count based on that
Well, with each dynarec'd instruction you could increment a cycles counter, which would be much easier, inefficient but still better than the interpretor.

The kind of code where dynamic recompilation really shines is with long stretches of instructions that have no jumps in or out of them, and few memory writes to cause code overwriting concerns.
memory writes isn't much of a concern, I just flag that address as invalid. If that address ever needs to be executed, the flag is checked and an entire block (entry point to exiting ret or jmp) is translated. I'm still in early stages in my project so I have no idea if my code is fast enough, but that is part of the learning process.

Rather than CPU emulation, I'm more worried about memory emulation. Some emulators use a function pointer to determin how banks of memory should be handled (A function for RAM, another for VideoRAM, BIOS, etc. all registered in a table). I haven't experimented with this yet, but the thought of calling a function pointer on each and every memory read/write is scary. Anybody have any ideas on a faster way of doing this? I think a switch() or two on each access would do a better job than function pointers followed by switches.
 
Why not take a look at gpadvanced, instead of using a dynarec or other method it uses simulation because the ARM9 is supposed to be somewhat backward compatible with the arm7 or something to that effect...
 
Imho the hardest part about GBA's emulting is its hardware not a cpu. It isn't less complicated (and powerfull) than the SNES and we know how it's hard...
 
Why not take a look at gpadvanced, instead of using a dynarec or other method it uses simulation because the ARM9 is supposed to be somewhat backward compatible with the arm7 or something to that effect...

Simulation is the slowest form of system emulation, so slow it's normally for academic purposes only. Unless you have some other definition for the term. o_O
 
Hooka posted on Feb 4 2006 at 12:01 AM said:
Why not take a look at gpadvanced, instead of using a dynarec or other method it uses simulation because the ARM9 is supposed to be somewhat backward compatible with the arm7 or something to that effect...

Squidge posted on Feb3 2006 at 02:27 PM said:
I don't think they used Dyanrec for the reason of speed and also that there was no real need to - you could use the MMU to map all the GBA's memory, and a spare interrupt to stop the processor and "do your own stuff" (like graphics emulation/etc).

If anyone wants to do a GBA emu for the GP2X and get it running under Linux, then they will need to use Dynarec, otherwise they'll have to throw out Linux first. It's obvious which would be the quickest in speed, but certainly not obvious which would be quicker to implement and debug.
 
Last edited by a moderator:
Back
Top