My screen is the Blue Screen of Death
To aid in the development of Lizard, I programmed a Blue Screen of Death into the NES version of the game.
This is a screen that appears in case of a crash. If the game does something that it really shouldn't have, this will pop up with information about it. The numbers on there tell me the current state of the machine. By reading this screen I can tell exactly where in the code the crash was reached, and it can give me insight as to what may have caused it.
Since trying it out on a real NES, though, I have come to realize that it's often possible to create a BSOD just by accidentally bumping the cartridge. I suppose this is normal; on most games it would probably just hang or do something weird when this happened anyway, but because this game has a crash handler built in, sometimes you'll get the BSOD. It's not really a useful report if it was caused by a physical failure of the NES, but at least it will safely reset the game and you can resume your last save from the continue screen. (The continue password is preserved on reset, by the way.)
How was this implemented on an NES?
The CPU inside the NES, a variant of the MOS Technology 6502, has a pin on it that will cause an "interrupt" if an electrical signal is sent. This pin is connected to the cartridge so that game developers would have the option to build special hardware inside the cart that can interface with the CPU directly. This was particularly useful for timers, since the NES did not have very good built-in timing capabilities.
My game deliberately targets a very simple cartridge type. I didn't want to be adding anything above and beyond the stock NES' capabilities, except extending the accessible ROM size up to 256k. Part of my motivation for this is how technically impressive Battletoads managed to be with a very similar, simple cartridge form. My cartridge doesn't use the interrupt pin, so this was an unused feature for Lizard.
The 6502 has an instruction called BRK which can generate a false interrupt from software. This is conveniently represented by the number 0. This means that I can just stick a BRK instruction wherever I might want to signal a crash, similar to how a C programmer might use an assert. It also means that if I fill empty space in the ROM with the number 0, any rogue execution that happens to try to run in these areas will also create an interrupt.
What an interrupt does is stop the CPU from doing what it is currently doing, and begins executing your software's interrupt handler routine. When finished, the software can return the CPU to its previous state and resume execution from where it left off. This can be used for many different things, but a few examples might be: reading a keyboard peripheral in response to a keypress, or playing a PCM sample in response to a playback timer.
In my case, I don't let it resume after the interrupt. My interrupt handler gathers what information it can from the CPU, and displays it to the screen. Instead of returning from the interrupt, it simply "resets" the system when you press the start button. It's not actually a hardware reset, it just jumps to the code location that would normally be run on startup/reset.
This screen has already helped me find and fix a problem on a couple of occasions. Hopefully, it will help me keep the bugs out of Lizard!
Another game you might be interested in...
Americana Dawn is a JRPG with a rather unique setting. Its stories span 200 years of early American history, told with a beautiful visual style, exploration and turn-based combat, and even large scale strategic battles.
This project has already been in development for a long time, so there is a lot to see and hear already. I've been especially interested in the wonderful soundtrack that Samuel Ascher-Weiss has been composing for it.
I'd love to see it finished someday. Maybe you would too? Check it out!