Notepad time! (This is where I just use this blog as a piece of scratch paper for random investigations.)
Solar Jetman’s password entry screen
Reverse engineering the password system from an old NES game…
I’m interested in the password system for Solar Jetman. What for? I started this quest about 15 years ago on pen and paper and…hey, since when do I need a good reason to engage in such worthless exercises? And who knows? Maybe the game will find a new fanbase thanks to the backwards compatibility feature of Nintendo’s upcoming console.
The password, as shown in the screenshot above, is 12 characters long. Each character is selected from the 26-character English alphabet.
NES games are cartridges containing printed circuit boards with ROMs for game data and occasionally video RAM, backup RAM, batteries and other circuitry. The NES is based on an 8-bit 6502 CPU (modified such that it did not support the BCD arithmetic mode). The CPU has a 16-bit address space. In the organization of the address space, there are 2 kilobytes of work RAM at the bottom of the address space (mirrored 4 times in a row). The top half of the address space (32K from $8000 -> $FFFF) is used for the code (PRG ROM). 32K is not much to work with, even in the 1985-1995 timeframe when the NES was popular. Thus, many games came up with various types of mapper hardware that effectively expanded the amount of memory available via bank-switching hardware. This is Rare’s Solar Jetman PCB. It has a Philips 74HC161 TTL component as a mapper which the Philips website lists as a 4-bit counter. According to the big mapper document from the authoritative NES development site, Rare’s PCB layout is dubbed AOROM. From a software perspective, writing anywhere in the upper 32K of the 6502 address space selects a new ROM bank to occupy the entire upper 32K space.
Next, dump the ROM data from the cartridge to your computer. Somehow. If you don’t have those facilities you will need to procure an investigative copy some other way. It will most likely be in the iNES .nes format. This is a 16-byte header followed by ROM data. Since this is an AOROM dump, it will be a series of 32K PRG banks. There are no CHR banks (data that resides in the picture processing unit’s address space) because AOROM PCBs use RAM in this space.
Next, take apart the banks. I use the Unix ‘dd’ command to split the banks. Then, it’s time to disassemble. There are more than a few 6502 disassemblers available. However, there is at least one by a talented NES hacker named Tennessee Carmel-Veilleux that is designed with the NES in mind. It is called dcc6502 and I found a copy here. You may need to fix up a string in the source code; otherwise it compiles just fine with gcc. This disassembler bases the code at address $8000 unless specified otherwise. It has a switch that treats the code as being from the NES and helpfully comments the code when it writes to the NES-specific, memory-mapped registers. For example:
$8022 STX $2001 ; [NES] PPU setup reg #2 $8025 STX $2000 ; [NES] PPU setup reg #1 $8028 BIT $2002 ; [NES] PPU status reg
I just remembered– I sort of need a refresher course on those instructions. Here’s a great, simple reference. One more important thing for getting started– the 6502 reset vector is at $FFFC. The 2 bytes there (little endian) define the starting address at startup. The first ROM bank defines what this is (and it appears to be the same in all banks, perhaps in case of spurious reset).
So the only thing I have sorted out so far is that the game keeps its mapper state at RAM address $75. And that it consistently uses address $FFCB when it wants to alter the mapper state (which includes not only the PRG bank number but also a configuration setting of the PPU hardware also controlled by the 74HC161 chip).
I’m theorizing that there is code in the second bank to interact with the password screen because that’s where I see the string “ENTER PASSWORD OR PRESS START TO PLAY”. I’m thinking that the game will take the input and run it through a verification check and then a decoding process and initialize a bunch of values in the RAM area. After understanding the validation and decoding processes, I should be able to build a password generator that allows the user to select various values and generate new passwords. Plug those passwords into the game and see which things change at game startup.
That’s the theory. Maybe if I’m successful at that I’ll study what made the ship move in the game; Solar Jetman had a physics engine that was way ahead of its time.
Here is my one-hour rom digging results:
#include
#include
char input[20];
unsigned char scratch[6];
char charmap[] = “BDGHKLMNPQRTVWXZ”;
int c2b(char c)
{
c &= ~’ ‘;
for(int i = 0;i > 8); // +carry
if(scratch[3] != (checksum & 0xFF))
printf(“Checksum bad (my %d need %d)\n”, checksum, scratch[3]);
int state_CC = (scratch[1] & 0xF);
int state_D0 = (scratch[1] >> 4) & 0xF;
int state_CB = (scratch[5] & 0xF);
int state_CF = (scratch[5] >> 4) & 0xF;
int state_CD = (scratch[0] & 0xF);
int state_3E = (scratch[0] >> 4) & 0xF;
int state_60D = (scratch[2] & 0x1);
int state_60C = (scratch[2] >> 1) & 0x1;
int state_3B = (scratch[2] >> 2) & 0x3F;
// scratch[4] always assumed 8 during decoding…
int state_DC = ((scratch[4] & 3) > 4) & 0xF;
printf(“CB-D0 %d%d%d%d%d%d\n”, state_CB, state_CC, state_CD, state_CE, state_CF, state_D0);
printf(“3E %d\n”, state_3E);
printf(“3B %d\n”, state_3B);
printf(“DC %d\n”, state_DC);
printf(“60D %d\n”, state_60D);
printf(“60C %d\n”, state_60C);
printf(“ok\n”);
}
else
printf(“Bad password length\n”);
return 0;
}
Furthermore, wikipedia’s page about SJ have link to fansite with online password generator.
Ahem, looks like formatting ruined the code. I’ll mail it.
That pretty well brings that expedition to a close. :) Thanks for the research.
Cool
How did you generate C code from the ROM data? Also, I don’t understand where your scratch array is initialized. And how do you know what ship powerups, lives, score, starting planet, etc. will be generated?