calc84maniac said:
Why not dynarec though? You'd think it would be easier to write a dynarec for an ARM on an ARM than a MIPS on an ARM.
Actually, I would say doing ARM on ARM is harder than doing MIPS on ARM, because ARM is just generally harder than MIPS. When performing software memory emulation and cycle counting you have to dance around the emulated flag state; MIPS doesn't have this problem since it doesn't have flags. You also have to contend with PC being a general purpose register, and predicated execution that jams up control flow. Oh, and the whole Thumb mode, which sadly DS games still use.
It's not an enormous difference, but doing a fast recompiler, or even any recompiler is still a pretty good workload. The frontend alone, ie tracking blocks, and dealing with modified code is at least somewhat non-trivial.
I've mentioned several obstacles and disadvantages to any kind of virtualization approach that I won't go over again. Having said that, recompilation (and probably virtualization in this context, for that matter) has a lot of overhead that isn't readily apparent. Doing memory emulation w/o MMU assistance is going to cost you, especially on a platform like DS with a relatively complex memory map. Using the MMU has its own tradeoffs - any trapped accesses become a lot slower. Games do at the very least occasionally bang I/O ports for reading off the gamecard, in other words they don't always use DMA even when they can. Write protection for code also becomes page-granular at best and you pay a lot for false positives. The other downside is that switching address spaces becomes much more expensive (TLB flush), and so long as you're emulating ARM7 at a low level you'll have to interleave it and ARM9 pretty tightly at times to get through some areas. High level emulation of ARM7 routines might be possible but it's pretty unproven.
So to recap, for dynarec you have to pay for:
- Scratch registers to store things, meaning spills to/from memory here and there
- Saving/restoring flags when necessary
- Cycle counting, and more expensive, cycle checking
- Higher cache pressure
- PC loads generate big constants
- Indirect branches are relatively expensive
- Stores have to be checked for self-modifying code
- Memory in general has a lot of cycles if done w/o MMU
- You won't want to keep Thumb as Thumb, worsening cache pressure (but you might be able to generate nicer code with optimizations)
Cortex-A8's performance is high, but part of it comes from code being properly scheduled and avoiding cache and BTB thrashing and poor predictability situations. Code written for earlier ARM CPUs won't necessarily fit this model very well.
Anyway, you could spend all day talking about how the CPUs can be emulated but you can't reach an answer about how DS can be emulated until you account for everything else you have to emulate, including very powerful 2D and pretty esoteric 3D and geometry engine.