Classic NES Series Anti-Emulation Measures
endrift.com
endrift.com
I know why!
If went to bazaar in 90s Russia you would see these '40-in-one' video-game cartridges which were a bunch of normal bootleg games linked together by a bootscreen. You could imagine the NES emulator falling under the same category. Sometimes emulators were sold on CDs.
#1 - memory mirroring - accidental bug that doesn't matter since hardware ignores those bits
#2 - code in vram - possible technique to save memory in another memory area?
#3 - STM to DMA - shortcut to DMA that "just worked" without the original developers knowing the CPU write ordering
#4 - save type faking - just a library bug that breaks the emulator heuristics?
#5 - prefetch abuse - idk, maybe a legit attempt to prevent reverse engineering? Don't really know enough to comment if there's a reasonable purpose for it
#6 - audio FIFO irregularities - just a bug in the emulator?
How many C/C++ devs accidentaly rely on undefined behavior or specific x86 quirks? It's really easy to do, and doubly so if you're targeting a single exact hardware configuration. I'm sure it's easy to see these as hostile attempts to make emulator developer's lives harder, but I think they could just as easily be accidents, especially with a complex project like porting NES games to GBA hardware.
On the other hand, I dunno, maybe Nintendo pull out all the stops to try to prevent reverse engineering and deliberately use these kind of tricks, but really, they'd go the extra mile for old NES game ports?
Having said that, still a great article for covering some fascinating hardware quirks and the challenges of writing a bug-compatible emulator!
If it were one thing, maybe, but six things done in almost no or no other games repeated across (presumably) thirty ported games? Infinitesimally unlikely.
Also, these were done by Nintendo Japan - how likely is it that they're "relatively inexperienced developers writing hasty ports". These tricks would seem the hallmark of very experienced developers who know the hardware intimately.
#1. The memory mirroring is IIRC a normal part of the hardware involved. Executing mirrored code? I can't think of a good reason to do it other than to trip someone up.
#2. You might do this in earnest, but only if you're decompressing the code or otherwise generating it and just can't stick it in main RAM. GBA ROMs make up part of the global address space. There's simply no need to copy existing code around.
#3. I'm not familiar with it enough to comment. Sounds like it could be innocent.
#4. Seems unlikely you would include an unnecessary code path, and then intentionally kill the game if it happened to work. This is actually your typical anti-debugging technique: trick the environment into to doing something you can detect, then disable.
#5. Prefetch games usually combine the detect and disable steps mentioned in #4. #1 and #2 are also related. This is a good contender for "oldest trick in the book."
#6. Probably a bug.
Source for GBA-specific stuff: http://problemkaputt.de/gbatek.htm
As for copying data around, yeah, if your emu can't copy data to/from VRAM in a sensible manner it's just not going to work out.
/* Returns a bitwise-OR'ed number showing
all the possible places you can save to */
int get_available_save_locations();
[...]
int save_locations = get_available_save_locations();
if (save_locations != SAVELOC_NVRAM) {
goto FATAL_ERROR;
}#4, If they did a SRAM write, then a EEPROM write and only raised an error when the EEPROM write failed, your suggestion would seem plausible, but since they do an SRAM write, then raise an error because the SRAM write worked, it is hard to believe this isn't an intentional protection feature.
DS games also come with copy protection to stop people from running it in cartridges that run gmaes off of images, like the R4. In that case, the product the pirates offered was actually better than buying an original cartridge: I could buy 20 games and carry a case of games, or keep them al in a single micro SSD card, and switch games at will from the boot menu.
2) Code in VRAM was sometimes faster than executing code from the ROM, due to waitstates. This was used on the Nintendo DS as well. There was a lot of VRAM, and it was 0-waitstate, while your instruction cache was tiny.
3) STM to DMA registers was an optimization that was used fairly commonly, at least in homebrew games
5) This is definitely anti-emulator code :)
I always find these things really interesting.
But considering it either hasn't been used in other games, or at least infrequently enough this emulators author has never seen it before, I'm leaning towards it being another protection.
Combining sequential writes into an STM is a standard optimization.
Incidentally, the note "Since the write is done with one instruction, a DMA cannot preempt the CPU in the middle of the writes" from the article is likely not correct. The STM may be only one insn but it may generate multiple memory accesses to the bus, so it's quite plausible that a DMA device might get accesses in between words. (Of course RAM is usually mapped Normal in which case caches and store buffers will be heavily reordering it anyhow, so nobody relies on ldm/stm ordering here.)