Emulators are no different from regular programs when it comes to debugging. The only added difficulty is that one must be able to debug the emulator itself by figuring out what’s going wrong in the system being emulated. This can be quite challenging indeed when one does not have access to the source code of a game and must look through a disassembly of the compiled ROM in order to figure out what’s going on. Nevertheless, debugging is very much possible with a great deal of perseverance.

A bug I fixed today as of writing this article seemed quite simple: certain commercial games were failing to read touchscreen output. The problem is that the emulated touchscreen does work; for example, the firmware and the Digimon games read it perfectly fine. For some reason though, games like Harvest Moon DS and Super Mario 64 DS weren’t even attempting to read from the touchscreen. In fact, code that was being called according to NO$GBA was being completely skipped over by CorgiDS! Over the course of several weeks, I halfheartedly attempted to fix this problem to no avail. It wasn’t a large priority until I tested Pokemon Diamond, which hung in an infinite loop just before reaching the title screen. Thinking that the touchscreen issue was related to this, I finally decided to put in some effort. (Spoiler: It wasn’t! Pokemon Diamond still remains to be fixed.)

I first suspected an issue with the IPCFIFO. The FIFO is a pair of two queues that both the ARM9 and ARM7 use to communicate with each other. For example, when the ARM7 reads touchscreen input, it can then send this information to the ARM9’s FIFO, which will trigger an IRQ (interrupt request) for it to handle. In the case of something like Harvest Moon DS, no FIFO communication was happening at all once the intro screens were pulled up, which is when the game is supposed to start reading touchscreen input. Inspecting the code, however, didn’t reveal any issues, and I was back to square one.

After a while, my next idea was to figure out where exactly the touchscreen code was in the ARM7 binary and work my way backwards to see which functions called it. Using the stack trace in NO$GBA and strategically-placed breakpoints, I backtracked all the way to the main loop in the ARM7 binary. I saw that the loop consists of calls to many different functions throughout the binary, so I placed breakpoints on each of them to determine which one would lead to the touchscreen code.

I found something odd: it looked like every single function would call the touchscreen code in NO$GBA! From a DS programming perspective, this doesn’t make much sense; user input only needs to be called once every frame. It didn’t take long for me to figure out what was happening: the touchscreen code was being called within an IRQ handler. This makes more sense because an IRQ can be called at any point during code execution, assuming they’re enabled of course.

The DS has a plethora of IRQ options available. Some of them are vital, such as V-Blank, which signals that the game can start accessing VRAM without interfering with the graphics engine. Others are almost never used by games, such as real-time clock IRQs. Regardless, every game will make use of several kinds of IRQs, and not processing them properly can lead to severe issues. I decided to place a breakpoint in the BIOS code responsible for jumping to whatever IRQ handler the game has so that I could check which IRQs were being called. I saw that one IRQ in particular, V-Counter Match, was indeed calling the touchscreen code. V-Counter Match is simple: if the current scanline that the graphics engine is drawing matches a variable called V-Counter, an IRQ is requested. On the ARM9 side, this can be used for special mid-frame graphical effects that require extra timing precision. I was surprised to see that the ARM7 touchscreen code relied on it, however.

I looked in my GPU code and saw that V-Counter was being set correctly to a value of 0 (it would be triggered at the very beginning of each frame then). Then I looked at the code responsible for calling the V-Counter Match IRQ, and I facepalmed hard. CorgiDS was incrementing V-Count (the current scanline position) before checking if the IRQ could be called. Because V-Count is never less than 0, this means that the IRQ would never be called if V-Counter was set to 0, which certain games would set it to. Making V-Count increment AFTER the IRQ check fixed all the touchscreen issues I was having.

What a ride that was. Hope you enjoyed reading about my struggles!