Search code examples
testingrom6502nintendo

How do I load nestest ROM?


I finished writing my 6502 emulator and I'm ready to start testing it. I found the nestest ROM with some documentation, but I'm not sure, what the proper way of loading the ROM is. The author says, that emulators should start at 0xC000, which contains 0 when I load the ROM, so I must be doing something wrong.

So right now my loading procedure looks something like this:

clear memory
set PC to 0x8000
open the file
skip first 16 bytes (iNES header)
load the rest of the file into RAM (starting at 0x8000)
set PC to 0xC000

Solution

  • As per Nick Westgate's comment (hence the instant community wiki), the loading procedure is a bit more complicated than you might naively guess:

    For now, you can load 0x4000 bytes starting at offset 0x0010, and map that as ROM into both $8000-$BFFF and $C000-$FFFF of the emulated 6502's memory map.

    The 'for now' assumes you're going to write a NES emulator and therefore one day will properly parse the NES-related file format that test is stored in and emulate the NES-specific memory mapping scheme that leads to the mirroring of contents.

    Ignore the comment in the post before that you should "[log] your PC (and registers) on every cycle", and the implication of the same in that post and onwards; he means that:

    1. before fetching the first operation code byte, make an internal record of the program counter and other registers;
    2. after reading the final operand byte, log all the values you stored back in step (1) plus the full instruction and its disassembly.

    If you've simplified things in your emulator to read and execute each operation atomically and then skip time ahead by the number of cycles you should have spent working then you can probably omit the temporary storage. I suspect the author that generated the sample log had implemented such an emulation. Key clues will be a switch table indexed by opcode that is not in some way a coroutine, and/or a lookup table of instruction lengths.

    Further advice:

    The NES doesn't actually use a 6502. It uses a clone that omits decimal mode — the decimal flag simply has no effect. So if you're emulating a 6502, expect test results to vary there.

    For other good 6502 tests, see:

    • AllSuiteA (tests a whole bunch of things and gives you a pass or fail);
    • Klaus Dormann's tests (slightly more of a hassle; will simply enter an infinite loop somewhere if a particular test fails. You'll need to inspect the source to find out which failure you've got); and
    • Wolfgang Lorenz's tests (a whole bunch of separate tests, originally for running separately on a C64 but easy enough to run without anything implemented beyond a 6502 other than that it'll provide text output of status in PETSCII, so you'll also need a quick lookup table to map that to ASCII).

    I used all three of those to bootstrap my most recent 6502 emulator, plus some self-written cycle-by-cycle tests for things like interrupts that you wouldn't expect code that sits inside a 6502's address space to be able to handle.

    I found out a lot later that I had a very minor deviation in decimal handling — minor enough to pass all those tests, but not sufficient to pass an exhaustive 6502 comparison. I conveniently found a better test in the Acorn BBC community, within the archive attached to this post. I elected to run that by:

    • load the contents of BCDTEST_beeb at 0x2900;
    • write JSR 2900h to address 0x200;
    • put an RTS at 0xffee, but also make sure you can trap that address;
    • set the program counter to 0x200 and keep running until it is at 0x203;
    • then test that the value at 0x84 is 0. If it is something else, that indicates failure.

    To get more feedback, any time the PC goes to 0xffee, output the ASCII character in the A register.