Alexander Dickson

Write a NES Emulator with JavaScript - Part 2

I hope you have read part one first, so we all know what a CPU is and how it behaves. I’ll wait for you here if you missed it.Before we write any more code, I want to go over some extra concepts.

Get in with the program

We need to load a program/ROM into our emulator in order to have something to execute. Programs floating around the internet are usually in the iNES format, a format developed by Marat Fayzullin. Let’s take a look at the information that the iNES format contains.

The first 16 bytes of the iNES format is known as the header and it contains information about the program. The first 4 bytes are the literal string "NES" followed by a \n, which is used to validate the format. You can reject the program if this string does not appear at the start of the file.

The rest of the header describe how big the program is (in 16kB units), how big the tile data is (in 8kB units) and a bunch of flags, some of which describe which mirroring used and the mapper used. We will look into mappers later (hopefully not as long as between part 1 and 2 of this blog ;).

Repeating the exact in-depth definition of the iNES format here wouldn’t be that useful, so I invite you to read the in-depth article about the iNES format over on the NESdev wiki. It’s good to be very familiar with the format, as the first task of writing your emulator is to parse the information out of the ROM to make it available to the CPU and PPU.

Moar codes

We can flesh out our stubs we wrote in part one, expanding on the nes.js file and creating a new file, named cpu.js. Make sure these files are siblings. Their interfaces (which will be constructors) will be exposed via the reference returned from the require() calls and assigned to the variables.

Since we’re not building a PPU or anything like that yet, we are keeping our entry point very simple, with a simple interface to reset and then emulate a cycle.

Our NES file will have all the bits and pieces required to kick off the PPU and other assorted bits. It will be the bootstrap file for this app.

(function() {
  var CPU = require("./cpu");
  var Program = require("./program");

  function NES() {
    this.cpu = new CPU(this);
    this.program = null;
  }

  NES.prototype.loadProgram = function(data) {
    this.program = new Program(this);
    this.program.load(data);
    this.reset();
  };

  NES.prototype.emulateCycle = function() {
    this.cpu.emulateCycle();
  };

  NES.prototype.reset = function() {
    this.cpu.reset();
  };

  module.exports = NES;
})();

The way I have written this isn’t necessarily the best design for a real-world emulator, but it will be useful for a simple design to watch the CPU (firstly) execute.

Do the CPU

The CPU will be tedious to develop, simply because you need to re-implement every 6502 opcode (and its extra opcodes) in JavaScript. Before we begin putting code to… screen, let’s think through the design for this component.

We need to store a reference to the instantiated NES object (loosely-coupled designs, I’m sorry) as well as the state of all the registers and the addressable memory. We also need to store an exploded version of the Processor Status register, which makes setting the individual flags much easier than constantly performing bit operations for each update.

We also need to list out every single opcode, and a way to look up the addressing mode of each one, how many bytes the opcode is, and how many cycles should pass while the opcode is being executed.

In my Chip-8 emulator, I used a huge switch() case to determine each opcode. While it should execute very quickly, it gets very messy and in my opinion is very difficult to follow. For a better solution, I decided to list out opcode in a giant object, with the opcode name as the key, and an object describing the opcode as its value.

I know what you’re probably thinking, and if it’s that will be heaps slow(!), you’re right. It would be slow to iterate over each property to determine what the current opcode is. To combat this, I have a loop that makes a lookup table (another object) from opcode to description. I like this design as it makes the list of opcodes and implementations very easy to read and modify, but gives the performance required by outputting an optimised variant.

Start the CPU

Let’s write a new stub for our cpu.js file. Seeing as the NES CPU is very complicated and there is a lot of information one simply can’t keep in their head all at once, we will comment liberally. If any of the registers or memory comments look confusing, brush up on them in part one.

function CPU(nes) {
  this.nes = nes;

  // Memory
  // ======
  // 0x100 => Zero Page
  // 0x200 => Stack
  // 0x800 => RAM
  // 0x2000 => Mirrors (0-0x7FF)
  // 0x2008 => I/O Registers
  // 0x4000 => Mirrors (0x2000-0x2007)
  // 0x4020 => I/O Registers
  // 0x6000 => Expansion ROM
  // 0x8000 => SRAM
  // 0xC000 => PRG-ROM (Lower Bank)
  // 0x10000 => PRG-ROM (Upper Bank)
  this.memory = Array(0x10000);

  // Registers
  // =========
  // Program Counter (16bit)
  this.pc = null;

  // Stack Pointer (8bit)
  this.sp = null;

  // Accumulator (8bit)
  this.a = null;

  // Index Register X (8bit)
  this.x = null;

  // Index Register Y (8bit)
  this.y = null;

  // Processor Status
  // 0 => Carry (if last instruction resulted in under/overflow)
  // 1 => Zero (if last instruction's result was 0)
  // 2 => Interrupt Disable (Enable to prevent system from responding to interrupts)
  // 3 => Decimal mode (unsupported on this chip variant)
  // 4 => Empty
  // 5 => Empty
  // 6 => Overflow (if previous instruction resulted in an invalid two's complement)
  // 7 => Negative
  this.p = null;

  // Part of the Processor Status register
  // Separated for convenience.
  this.carryFlag = false;
  this.zeroFlag = true;
  this.interruptDisable = true;
  this.decimalModeFlag = false;
  this.breakCommand = false;
  this.overflowFlag = false;
  this.negativeFlag = false;

  // Maskable Interrupt
  // One of "irq/brk", "nmi", "reset"
  this.interrupt = null;

  // Addressing Modes
  // ================
  this.addressingMode = {
      ZERO_PAGE: 0,
      INDEXED_ZERO_PAGE_X: 1,
      INDEXED_ZERO_PAGE_Y: 2,
      ABSOLUTE: 3,
      INDEXED_ABSOLUTE_X: 4,
      INDEXED_ABSOLUTE_Y: 5,
      IMPLIED: 6,
      ACCUMULATOR: 7,
      IMMEDIATE: 8,
      RELATIVE: 9,
      INDEXED_INDIRECT: 10,
      INDIRECT_INDEXED: 11,
      INDIRECT: 12
  };

  // Operations
  // ==========
  // A nice human-readable format that is
  // converted for performance on object
  // instantiation.    
  this.operations = {);

  this.reset();

}

// When the CPU is reset.
CPU.prototype.reset = function() {

    this.memory = Array(0x10000);

    this.carryFlag = false;
    this.zeroFlag = false;
    this.interruptDisable = true;
    this.decimalModeFlag = false;
    this.breakCommand = false;
    this.overflowFlag = false;
    this.negativeFlag = false;

    var programRom = this.nes.program.getPrgRom();
    var i;

    // 2kb Internal RAM
    for (i = 0; i <= 0x2000; i++) {
        this.memory[i] = 0xFF;
    }

    // All others set to 0.
    for (i = 0x2000; i <= 0x8000; i++) {
        this.memory[i] = 0;
    }

    this.pc = this.getResetVector();

    this.sp = 0xFD;

    this.a = 0;
    this.x = 0;
    this.y = 0;

    this.carryFlag = false;
    this.zeroFlag = false;
    this.interruptDisable = true;
    this.decimalModeFlag = false
    this.breakCommand = false;
    this.overflowFlag = false;
    this.negativeFlag = false;

    this.p = this.getProcessorFlags();

};    

// Serialise the list of individual processor flags into the register's value.
CPU.prototype.getProcessorFlags = function() {
    return +this.carryFlag | +this.zeroFlag << 1 | +this.interruptDisable << 2 | +this.decimalModeFlag << 3 | +this.breakCommand << 4 | 0x20 | +this.overflowFlag << 6 | +this.negativeFlag << 7;
};  

// Find where the program begins.
CPU.prototype.getResetVector = function() {
    return this.loadMemory(0xfffc, true);
};

// Load memory, with an optional double read for 2 bytes.
CPU.prototype.loadMemory = function(address, double) {
    if (!double) {
        return this.nes.mapper.load(address);
    }

    return this.nes.mapper.load(address) | (this.nes.mapper.load(address + 1) << 8)
};

module.exports = NES;

There’s a fair bit of code, and that’s not nearly the whole of it! It’s okay to be going WTF right now, as I have left some parts out, and it’s not straightforward code as emulators ain’t easy (well, not for me).

In the next part, we will look at loading the program into memory, and how to write the opcodes out and process them. Stay tuned!

Disclaimer: It has been over 2 years since I wrote part 1, so I am a little rusty with my NES emulation concepts, so please let me know if I have gotten anything incorrect.


Want to discuss this post? Just mention me @alexdickson.