RE-NES

Notepad time! (This is where I just use this blog as a piece of scratch paper for random investigations.)


Solar Jetman password screen
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.

5 thoughts on “RE-NES

  1. VAG

    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.

  2. Multimedia Mike Post author

    That pretty well brings that expedition to a close. :) Thanks for the research.

  3. PolishedTurd

    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?

Comments are closed.