nes-js
Version:
JavaScript NES emulator
1,408 lines (1,153 loc) • 168 kB
JavaScript
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 3);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return Register8bit; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Register16bit; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Utility_js__ = __webpack_require__(1);
/**
* General Register implementation.
* Specific register for CPU and PPU are implemented in each class.
*/
/**
*
*/
function Register(type) {
this.data = new type(1); // Uint8Array or Uint16Array
this.data[0] = 0;
}
Register.TYPE_8BIT = Uint8Array;
Register.TYPE_16BIT = Uint16Array;
Object.assign(Register.prototype, {
isRegister: true,
/**
*
*/
getWidth: function() {
return this.data.byteLength * 8;
},
/**
*
*/
load: function() {
return this.data[0];
},
/**
*
*/
loadBit: function(pos) {
return (this.data[0] >> pos) & 1;
},
/**
*
*/
loadBits: function(offset, size) {
return (this.data[0] >> offset) & ((1 << size) - 1);
},
/**
*
*/
store: function(value) {
this.data[0] = value;
},
/**
*
*/
storeBit: function(pos, value) {
value = value & 1; // just in case
this.data[0] = this.data[0] & ~(1 << pos) | (value << pos);
},
/**
*
*/
storeBits: function(offset, size, value) {
var mask = (1 << size) - 1;
value = value & mask; // just in case
this.data[0] = this.data[0] & ~(mask << offset) | (value << offset);
},
/**
*
*/
clear: function() {
this.data[0] = 0;
},
/**
*
*/
setBit: function(pos) {
this.storeBit(pos, 1);
},
/**
*
*/
clearBit: function(pos) {
this.storeBit(pos, 0);
},
/**
*
*/
isBitSet: function(pos) {
return this.loadBit(pos) === 1;
},
/**
*
*/
increment: function() {
this.data[0]++;
},
/**
*
*/
incrementBy2: function() {
this.data[0] += 2;
},
/**
*
*/
add: function(value) {
this.data[0] += value;
},
/**
*
*/
decrement: function() {
this.data[0]--;
},
/**
*
*/
decrementBy2: function() {
this.data[0] -= 2;
},
/**
*
*/
sub: function(value) {
this.data[0] -= value;
},
/**
*
*/
shift: function(value) {
value = value & 1; // just in case
var carry = this.loadBit(this.getWidth() - 1);
this.data[0] = (this.data[0] << 1) | value;
return carry;
},
/**
*
*/
dump: function() {
return __WEBPACK_IMPORTED_MODULE_0__Utility_js__["a" /* Utility */].convertDecToHexString(this.load(), this.getWidth() / 4);
}
});
/**
*
*/
function Register8bit() {
Register.call(this, Register.TYPE_8BIT);
}
Register8bit.prototype = Object.assign(Object.create(Register.prototype), {
isRegister8bit: true
});
/**
*
*/
function Register16bit() {
Register.call(this, Register.TYPE_16BIT);
this.bytes = new Uint8Array(this.data.buffer);
}
Register16bit.prototype = Object.assign(Object.create(Register.prototype), {
isRegister16bit: true,
/**
*
*/
loadHigherByte: function() {
return this.bytes[1];
},
/**
*
*/
loadLowerByte: function() {
return this.bytes[0];
},
/**
*
*/
storeHigherByte: function(value) {
this.bytes[1] = value;
},
/**
*
*/
storeLowerByte: function(value) {
this.bytes[0] = value;
}
});
/***/ }),
/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Utility; });
function Utility() {
}
/**
*
*/
Utility.convertDecToHexString = function(num, width, noPrefix) {
var str = num.toString(16);
var prefix = '';
if(num < 0)
prefix += '-';
if(noPrefix !== true)
prefix += '0x';
if(width === undefined)
return prefix + str;
var base = '';
for(var i = 0; i < width; i++)
base += '0';
return prefix + (base + str).substr(-1 * width);
};
/***/ }),
/* 2 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Memory; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Utility_js__ = __webpack_require__(1);
/**
* Generic 8bit-word Memory.
*/
/**
* @param {ArrayBuffer|integer} arg -
*/
function Memory(arg) {
this.data = new Uint8Array(arg);
}
Object.assign(Memory.prototype, {
isMemory: true,
/**
*
*/
clear: function() {
for(var i = 0, il = this.getCapacity(); i < il; i++)
this.storeWithoutMapping(i, 0);
},
/**
*
*/
getCapacity: function() {
return this.data.byteLength;
},
/**
*
*/
load: function(address) {
return this.data[address];
},
/**
*
*/
loadWithoutMapping: function(address) {
return this.data[address];
},
/**
*
*/
store: function(address, value) {
this.data[address] = value;
},
/**
*
*/
storeWithoutMapping: function(address, value) {
this.data[address] = value;
},
/**
*
*/
dump: function() {
var buffer = '';
var previousIsZeroLine = false;
var offset = this._getStartDumpAddress();
var end = this._getEndDumpAddress();
for(var i = offset; i < end; i++) {
if(i % 0x10 === 0) {
if(previousIsZeroLine) {
var skipZero = false;
while(this._checkNext16BytesIsZero(i+0x10)) {
i += 0x10;
skipZero = true;
}
if(skipZero)
buffer += '...\n';
}
buffer += __WEBPACK_IMPORTED_MODULE_0__Utility_js__["a" /* Utility */].convertDecToHexString(i-offset, 4) + ' ';
previousIsZeroLine = true;
}
var value = this._loadForDump(i);
buffer += __WEBPACK_IMPORTED_MODULE_0__Utility_js__["a" /* Utility */].convertDecToHexString(value, 2, true) + ' ';
if(value != 0)
previousIsZeroLine = false;
if(i % 0x10 === 0xf)
buffer += '\n';
}
return buffer;
},
/**
*
*/
_loadForDump: function(address) {
return this.loadWithoutMapping(address);
},
/**
*
*/
_getStartDumpAddress: function() {
return 0;
},
/**
*
*/
_getEndDumpAddress: function() {
return this.getCapacity();
},
/**
*
*/
_checkNext16BytesIsZero: function(offset) {
if(offset + 0x10 >= this._getEndDumpAddress())
return false;
var sum = 0;
for(var i = offset; i < offset + 0x10; i++) {
sum += this._loadForDump(i);
}
return sum === 0;
}
});
/***/ }),
/* 3 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__src_Nes_js__ = __webpack_require__(4);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__src_Rom_js__ = __webpack_require__(9);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__src_Audio_js__ = __webpack_require__(11);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__src_Display_js__ = __webpack_require__(12);
function NesJs() {}
NesJs.Nes = __WEBPACK_IMPORTED_MODULE_0__src_Nes_js__["a" /* Nes */];
NesJs.Rom = __WEBPACK_IMPORTED_MODULE_1__src_Rom_js__["a" /* Rom */];
NesJs.Audio = __WEBPACK_IMPORTED_MODULE_2__src_Audio_js__["a" /* Audio */];
NesJs.Display = __WEBPACK_IMPORTED_MODULE_3__src_Display_js__["a" /* Display */];
if(window !== undefined)
window.NesJs = NesJs;
/***/ }),
/* 4 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Nes; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Cpu_js__ = __webpack_require__(5);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Ppu_js__ = __webpack_require__(6);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Apu_js__ = __webpack_require__(7);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Joypad_js__ = __webpack_require__(8);
/**
*
*/
function Nes() {
this.ppu = new __WEBPACK_IMPORTED_MODULE_1__Ppu_js__["a" /* Ppu */]();
this.cpu = new __WEBPACK_IMPORTED_MODULE_0__Cpu_js__["a" /* Cpu */]();
this.apu = new __WEBPACK_IMPORTED_MODULE_2__Apu_js__["a" /* Apu */]();
this.pad1 = new __WEBPACK_IMPORTED_MODULE_3__Joypad_js__["a" /* Joypad */]();
this.pad2 = new __WEBPACK_IMPORTED_MODULE_3__Joypad_js__["a" /* Joypad */]();
this.rom = null; // set by .setRom()
//
this.cpu.setPpu(this.ppu);
this.cpu.setApu(this.apu);
this.cpu.setJoypad1(this.pad1);
this.cpu.setJoypad2(this.pad2);
this.ppu.setCpu(this.cpu);
this.apu.setCpu(this.cpu);
//
this.state = this.STATES.POWER_OFF;
//
this.audioEnabled = false;
// for requestAnimationFrame()
var self = this;
this.runFunc = function() { self.run(); };
// event listeners
this.onFpsUpdates = [];
}
Object.assign(Nes.prototype, {
isNes: true,
//
STATES: {
POWER_OFF: 0,
RUN: 1,
STOP: 2
},
KEY_TO_PAD_BUTTONS: {
13: __WEBPACK_IMPORTED_MODULE_3__Joypad_js__["a" /* Joypad */].BUTTONS.START, // enter
32: __WEBPACK_IMPORTED_MODULE_3__Joypad_js__["a" /* Joypad */].BUTTONS.SELECT, // space
37: __WEBPACK_IMPORTED_MODULE_3__Joypad_js__["a" /* Joypad */].BUTTONS.LEFT, // left arrow
38: __WEBPACK_IMPORTED_MODULE_3__Joypad_js__["a" /* Joypad */].BUTTONS.UP, // up arrow
39: __WEBPACK_IMPORTED_MODULE_3__Joypad_js__["a" /* Joypad */].BUTTONS.RIGHT, // right arrow
40: __WEBPACK_IMPORTED_MODULE_3__Joypad_js__["a" /* Joypad */].BUTTONS.DOWN, // down arrow
88: __WEBPACK_IMPORTED_MODULE_3__Joypad_js__["a" /* Joypad */].BUTTONS.A, // x
90: __WEBPACK_IMPORTED_MODULE_3__Joypad_js__["a" /* Joypad */].BUTTONS.B // z
},
// event listeners
/**
* Registered callbacks will be invoked when
* 'fps': FPS number is updated
*/
addEventListener: function(type, func) {
switch(type) {
case 'fps':
this.onFpsUpdates.push(func);
break;
default:
throw new Error('Nes.addEventListener: unknown type ' + type);
}
},
invokeFpsUpdateListeners: function(fps) {
for(var i = 0, il = this.onFpsUpdates.length; i < il; i++) {
this.onFpsUpdates[i](fps);
}
},
//
/**
*
*/
setRom: function(rom) {
this.rom = rom;
this.cpu.setRom(rom);
this.ppu.setRom(rom);
},
/**
*
*/
setDisplay: function(display) {
this.ppu.setDisplay(display);
},
/**
*
*/
setAudio: function(audio) {
this.apu.setAudio(audio);
this.audioEnabled = true;
},
/**
*
*/
bootup: function() {
this.cpu.bootup();
this.ppu.bootup();
this.apu.bootup();
this.state = this.STATES.RUN;
},
/**
*
*/
reset: function() {
this.cpu.reset();
this.ppu.reset();
this.apu.reset();
},
/**
*
*/
stop: function() {
this.state = this.STATES.STOP;
},
/**
*
*/
resume: function() {
this.state = this.STATES.RUN;
this.run();
},
/**
*
*/
run: function() {
this.measureFps();
var cycles = (341 * 262 / 3) | 0; // TODO: temporal
for(var i = 0; i < cycles; i++) {
this.runCycle();
}
if(this.state === this.STATES.RUN)
requestAnimationFrame(this.runFunc);
},
/**
*
*/
runCycle: function() {
this.cpu.runCycle();
this.ppu.runCycle();
this.ppu.runCycle();
this.ppu.runCycle();
if(this.audioEnabled === true)
this.apu.runCycle();
},
/**
*
*/
runStep: function() {
if(this.state !== this.STATES.STOP)
return;
do {
this.runCycle();
} while(this.cpu.isStall())
},
// key input handlers
handleKeyDown: function(e) {
if(this.KEY_TO_PAD_BUTTONS[e.keyCode] !== undefined)
this.pad1.pressButton(this.KEY_TO_PAD_BUTTONS[e.keyCode]);
e.preventDefault();
},
handleKeyUp: function(e) {
if(this.KEY_TO_PAD_BUTTONS[e.keyCode] !== undefined)
this.pad1.releaseButton(this.KEY_TO_PAD_BUTTONS[e.keyCode]);
e.preventDefault();
},
//
measureFps: function() {
var oldTime = null;
var frame = 0;
return function measureFps() {
if(frame === 60) {
var newTime = performance.now();
if (oldTime !== null)
this.invokeFpsUpdateListeners(60000 / (newTime - oldTime));
oldTime = newTime;
frame = 0;
}
frame++;
};
}(),
// dump methods
dumpCpu: function() {
return this.cpu.dump();
},
dumpRam: function() {
return this.cpu.dumpRAM();
},
dumpRom: function() {
var buffer = '';
buffer += this.rom.dumpHeader();
buffer += '\n';
buffer += this.rom.dump();
buffer += '\n';
buffer += this.cpu.disassembleROM();
buffer += '\n';
return buffer;
},
dumpPpu: function() {
return this.ppu.dump();
},
dumpVRam: function() {
return this.ppu.dumpVRAM();
},
dumpSprRam: function() {
return this.ppu.dumpSPRRAM();
}
});
/***/ }),
/* 5 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Cpu; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Register_js__ = __webpack_require__(0);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Memory_js__ = __webpack_require__(2);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Utility_js__ = __webpack_require__(1);
/**
* Ricoh 6502
* Refer to https://wiki.nesdev.com/w/index.php/CPU
*/
function Cpu() {
// registers
this.pc = new __WEBPACK_IMPORTED_MODULE_0__Register_js__["a" /* Register16bit */]();
this.sp = new __WEBPACK_IMPORTED_MODULE_0__Register_js__["b" /* Register8bit */]();
this.a = new __WEBPACK_IMPORTED_MODULE_0__Register_js__["b" /* Register8bit */]();
this.x = new __WEBPACK_IMPORTED_MODULE_0__Register_js__["b" /* Register8bit */]();
this.y = new __WEBPACK_IMPORTED_MODULE_0__Register_js__["b" /* Register8bit */]();
this.p = new CpuStatusRegister();
// CPU inside RAM
this.ram = new __WEBPACK_IMPORTED_MODULE_1__Memory_js__["a" /* Memory */](64 * 1024); // 64KB
// other devices
this.ppu = null; // set by setPpu()
this.apu = null; // set by setApu()
this.pad1 = null; // set by setJoypad1()
this.pad2 = null; // set by setJoypad2()
// cartridge ROM
this.rom = null; // set by setRom()
// Executing an instruction takes 1, 2, or more cycles.
// .stallCycle represents the number of cycles left to
// complete the currently executed instruction.
this.stallCycle = 0;
}
// Interrups
Cpu.INTERRUPTS = {
NMI: 0,
RESET: 1,
IRQ: 2,
BRK: 3 // not interrupt but instruction
};
Cpu.INTERRUPT_HANDLER_ADDRESSES = [];
Cpu.INTERRUPT_HANDLER_ADDRESSES[Cpu.INTERRUPTS.NMI] = 0xFFFA;
Cpu.INTERRUPT_HANDLER_ADDRESSES[Cpu.INTERRUPTS.RESET] = 0xFFFC;
Cpu.INTERRUPT_HANDLER_ADDRESSES[Cpu.INTERRUPTS.IRQ] = 0xFFFE;
Cpu.INTERRUPT_HANDLER_ADDRESSES[Cpu.INTERRUPTS.BRK] = 0xFFFE;
// Instructions
Cpu.INSTRUCTIONS = {
INV: {'id': 0, 'name': 'inv'}, // Invalid
ADC: {'id': 1, 'name': 'adc'},
AND: {'id': 2, 'name': 'and'},
ASL: {'id': 3, 'name': 'asl'},
BCC: {'id': 4, 'name': 'bcc'},
BCS: {'id': 5, 'name': 'bcs'},
BEQ: {'id': 6, 'name': 'beq'},
BIT: {'id': 7, 'name': 'bit'},
BMI: {'id': 8, 'name': 'bmi'},
BNE: {'id': 9, 'name': 'bne'},
BPL: {'id': 10, 'name': 'bpl'},
BRK: {'id': 11, 'name': 'brk'},
BVC: {'id': 12, 'name': 'bvc'},
BVS: {'id': 13, 'name': 'bvs'},
CLC: {'id': 14, 'name': 'clc'},
CLD: {'id': 15, 'name': 'cld'},
CLI: {'id': 16, 'name': 'cli'},
CLV: {'id': 17, 'name': 'clv'},
CMP: {'id': 18, 'name': 'cmp'},
CPX: {'id': 19, 'name': 'cpx'},
CPY: {'id': 20, 'name': 'cpy'},
DEC: {'id': 21, 'name': 'dec'},
DEX: {'id': 22, 'name': 'dex'},
DEY: {'id': 23, 'name': 'dey'},
EOR: {'id': 24, 'name': 'eor'},
INC: {'id': 25, 'name': 'inc'},
INX: {'id': 26, 'name': 'inx'},
INY: {'id': 27, 'name': 'iny'},
JMP: {'id': 28, 'name': 'jmp'},
JSR: {'id': 29, 'name': 'jsr'},
LDA: {'id': 30, 'name': 'lda'},
LDX: {'id': 31, 'name': 'ldx'},
LDY: {'id': 32, 'name': 'ldy'},
LSR: {'id': 33, 'name': 'lsr'},
NOP: {'id': 34, 'name': 'nop'},
ORA: {'id': 35, 'name': 'ora'},
PHA: {'id': 36, 'name': 'pha'},
PHP: {'id': 37, 'name': 'php'},
PLA: {'id': 38, 'name': 'pla'},
PLP: {'id': 39, 'name': 'plp'},
ROL: {'id': 40, 'name': 'rol'},
ROR: {'id': 41, 'name': 'ror'},
RTI: {'id': 42, 'name': 'rti'},
RTS: {'id': 43, 'name': 'rts'},
SBC: {'id': 44, 'name': 'sbc'},
SEC: {'id': 45, 'name': 'sec'},
SED: {'id': 46, 'name': 'sed'},
SEI: {'id': 47, 'name': 'sei'},
STA: {'id': 48, 'name': 'sta'},
STX: {'id': 49, 'name': 'stx'},
STY: {'id': 50, 'name': 'sty'},
TAX: {'id': 51, 'name': 'tax'},
TAY: {'id': 52, 'name': 'tay'},
TSX: {'id': 53, 'name': 'tsx'},
TXA: {'id': 54, 'name': 'txa'},
TXS: {'id': 55, 'name': 'txs'},
TYA: {'id': 56, 'name': 'tya'}
};
// Addressing modes
Cpu.ADDRESSINGS = {
IMMEDIATE: {'id': 0, 'pc': 2, 'name': 'immediate'},
ABSOLUTE: {'id': 1, 'pc': 3, 'name': 'absolute'},
INDEXED_ABSOLUTE_X: {'id': 2, 'pc': 3, 'name': 'indexed_absolute_x'},
INDEXED_ABSOLUTE_Y: {'id': 3, 'pc': 3, 'name': 'indexed_absolute_y'},
ZERO_PAGE: {'id': 4, 'pc': 2, 'name': 'zero_page'},
INDEXED_ZERO_PAGE_X: {'id': 5, 'pc': 2, 'name': 'indexed_zero_page_x'},
INDEXED_ZERO_PAGE_Y: {'id': 6, 'pc': 2, 'name': 'indexed_zero_page_y'},
IMPLIED: {'id': 7, 'pc': 1, 'name': 'implied'},
ACCUMULATOR: {'id': 8, 'pc': 1, 'name': 'accumulator'},
INDIRECT: {'id': 9, 'pc': 3, 'name': 'indirect'},
INDEXED_INDIRECT_X: {'id': 10, 'pc': 2, 'name': 'indexed_indirect_x'},
INDEXED_INDIRECT_Y: {'id': 11, 'pc': 2, 'name': 'indexed_indirect_y'},
RELATIVE: {'id': 12, 'pc': 2, 'name': 'relative'}
};
// Operations (the combinations of interuction and addressing mode)
// Decoding in advance because it's much easier than implementing decoder.
Cpu.OPS = [
/* 0x00 */ {'instruction': Cpu.INSTRUCTIONS.BRK, 'cycle': 7, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0x01 */ {'instruction': Cpu.INSTRUCTIONS.ORA, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.INDEXED_INDIRECT_X},
/* 0x02 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x03 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x04 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x05 */ {'instruction': Cpu.INSTRUCTIONS.ORA, 'cycle': 3, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0x06 */ {'instruction': Cpu.INSTRUCTIONS.ASL, 'cycle': 5, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0x07 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x08 */ {'instruction': Cpu.INSTRUCTIONS.PHP, 'cycle': 3, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0x09 */ {'instruction': Cpu.INSTRUCTIONS.ORA, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMMEDIATE},
/* 0x0A */ {'instruction': Cpu.INSTRUCTIONS.ASL, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.ACCUMULATOR},
/* 0x0B */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x0C */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x0D */ {'instruction': Cpu.INSTRUCTIONS.ORA, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0x0E */ {'instruction': Cpu.INSTRUCTIONS.ASL, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0x0F */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x10 */ {'instruction': Cpu.INSTRUCTIONS.BPL, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.RELATIVE},
/* 0x11 */ {'instruction': Cpu.INSTRUCTIONS.ORA, 'cycle': 5, 'mode': Cpu.ADDRESSINGS.INDEXED_INDIRECT_Y},
/* 0x12 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x13 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x14 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x15 */ {'instruction': Cpu.INSTRUCTIONS.ORA, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ZERO_PAGE_X},
/* 0x16 */ {'instruction': Cpu.INSTRUCTIONS.ASL, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.INDEXED_ZERO_PAGE_X},
/* 0x17 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x18 */ {'instruction': Cpu.INSTRUCTIONS.CLC, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0x19 */ {'instruction': Cpu.INSTRUCTIONS.ORA, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_Y},
/* 0x1A */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x1B */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x1C */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x1D */ {'instruction': Cpu.INSTRUCTIONS.ORA, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_X},
/* 0x1E */ {'instruction': Cpu.INSTRUCTIONS.ASL, 'cycle': 7, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_X},
/* 0x1F */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x20 */ {'instruction': Cpu.INSTRUCTIONS.JSR, 'cycle': 0, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0x21 */ {'instruction': Cpu.INSTRUCTIONS.AND, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.INDEXED_INDIRECT_X},
/* 0x22 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x23 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x24 */ {'instruction': Cpu.INSTRUCTIONS.BIT, 'cycle': 3, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0x25 */ {'instruction': Cpu.INSTRUCTIONS.AND, 'cycle': 3, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0x26 */ {'instruction': Cpu.INSTRUCTIONS.ROL, 'cycle': 5, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0x27 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x28 */ {'instruction': Cpu.INSTRUCTIONS.PLP, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0x29 */ {'instruction': Cpu.INSTRUCTIONS.AND, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMMEDIATE},
/* 0x2A */ {'instruction': Cpu.INSTRUCTIONS.ROL, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.ACCUMULATOR},
/* 0x2B */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x2C */ {'instruction': Cpu.INSTRUCTIONS.BIT, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0x2D */ {'instruction': Cpu.INSTRUCTIONS.AND, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0x2E */ {'instruction': Cpu.INSTRUCTIONS.ROL, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0x2F */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x30 */ {'instruction': Cpu.INSTRUCTIONS.BMI, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.RELATIVE},
/* 0x31 */ {'instruction': Cpu.INSTRUCTIONS.AND, 'cycle': 5, 'mode': Cpu.ADDRESSINGS.INDEXED_INDIRECT_Y},
/* 0x32 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x33 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x34 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x35 */ {'instruction': Cpu.INSTRUCTIONS.AND, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ZERO_PAGE_X},
/* 0x36 */ {'instruction': Cpu.INSTRUCTIONS.ROL, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.INDEXED_ZERO_PAGE_X},
/* 0x37 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x38 */ {'instruction': Cpu.INSTRUCTIONS.SEC, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0x39 */ {'instruction': Cpu.INSTRUCTIONS.AND, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_Y},
/* 0x3A */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x3B */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x3C */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x3D */ {'instruction': Cpu.INSTRUCTIONS.AND, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_X},
/* 0x3E */ {'instruction': Cpu.INSTRUCTIONS.ROL, 'cycle': 7, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_X},
/* 0x3F */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x40 */ {'instruction': Cpu.INSTRUCTIONS.RTI, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0x41 */ {'instruction': Cpu.INSTRUCTIONS.EOR, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.INDEXED_INDIRECT_X},
/* 0x42 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x43 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x44 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x45 */ {'instruction': Cpu.INSTRUCTIONS.EOR, 'cycle': 3, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0x46 */ {'instruction': Cpu.INSTRUCTIONS.LSR, 'cycle': 5, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0x47 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x48 */ {'instruction': Cpu.INSTRUCTIONS.PHA, 'cycle': 3, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0x49 */ {'instruction': Cpu.INSTRUCTIONS.EOR, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMMEDIATE},
/* 0x4A */ {'instruction': Cpu.INSTRUCTIONS.LSR, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.ACCUMULATOR},
/* 0x4B */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x4C */ {'instruction': Cpu.INSTRUCTIONS.JMP, 'cycle': 0, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0x4D */ {'instruction': Cpu.INSTRUCTIONS.EOR, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0x4E */ {'instruction': Cpu.INSTRUCTIONS.LSR, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0x4F */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x50 */ {'instruction': Cpu.INSTRUCTIONS.BVC, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.RELATIVE},
/* 0x51 */ {'instruction': Cpu.INSTRUCTIONS.EOR, 'cycle': 5, 'mode': Cpu.ADDRESSINGS.INDEXED_INDIRECT_Y},
/* 0x52 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x53 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x54 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x55 */ {'instruction': Cpu.INSTRUCTIONS.EOR, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ZERO_PAGE_X},
/* 0x56 */ {'instruction': Cpu.INSTRUCTIONS.LSR, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.INDEXED_ZERO_PAGE_X},
/* 0x57 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x58 */ {'instruction': Cpu.INSTRUCTIONS.CLI, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0x59 */ {'instruction': Cpu.INSTRUCTIONS.EOR, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_Y},
/* 0x5A */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x5B */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x5C */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x5D */ {'instruction': Cpu.INSTRUCTIONS.EOR, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_X},
/* 0x5E */ {'instruction': Cpu.INSTRUCTIONS.LSR, 'cycle': 7, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_X},
/* 0x5F */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x60 */ {'instruction': Cpu.INSTRUCTIONS.RTS, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0x61 */ {'instruction': Cpu.INSTRUCTIONS.ADC, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.INDEXED_INDIRECT_X},
/* 0x62 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x63 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x64 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x65 */ {'instruction': Cpu.INSTRUCTIONS.ADC, 'cycle': 3, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0x66 */ {'instruction': Cpu.INSTRUCTIONS.ROR, 'cycle': 5, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0x67 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x68 */ {'instruction': Cpu.INSTRUCTIONS.PLA, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0x69 */ {'instruction': Cpu.INSTRUCTIONS.ADC, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMMEDIATE},
/* 0x6A */ {'instruction': Cpu.INSTRUCTIONS.ROR, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.ACCUMULATOR},
/* 0x6B */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x6C */ {'instruction': Cpu.INSTRUCTIONS.JMP, 'cycle': 0, 'mode': Cpu.ADDRESSINGS.INDIRECT},
/* 0x6D */ {'instruction': Cpu.INSTRUCTIONS.ADC, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0x6E */ {'instruction': Cpu.INSTRUCTIONS.ROR, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0x6F */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x70 */ {'instruction': Cpu.INSTRUCTIONS.BVS, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.RELATIVE},
/* 0x71 */ {'instruction': Cpu.INSTRUCTIONS.ADC, 'cycle': 5, 'mode': Cpu.ADDRESSINGS.INDEXED_INDIRECT_Y},
/* 0x72 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x73 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x74 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x75 */ {'instruction': Cpu.INSTRUCTIONS.ADC, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ZERO_PAGE_X},
/* 0x76 */ {'instruction': Cpu.INSTRUCTIONS.ROR, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.INDEXED_ZERO_PAGE_X},
/* 0x77 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x78 */ {'instruction': Cpu.INSTRUCTIONS.SEI, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0x79 */ {'instruction': Cpu.INSTRUCTIONS.ADC, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_Y},
/* 0x7A */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x7B */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x7C */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x7D */ {'instruction': Cpu.INSTRUCTIONS.ADC, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_X},
/* 0x7E */ {'instruction': Cpu.INSTRUCTIONS.ROR, 'cycle': 7, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_X},
/* 0x7F */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x80 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x81 */ {'instruction': Cpu.INSTRUCTIONS.STA, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.INDEXED_INDIRECT_X},
/* 0x82 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x83 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x84 */ {'instruction': Cpu.INSTRUCTIONS.STY, 'cycle': 3, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0x85 */ {'instruction': Cpu.INSTRUCTIONS.STA, 'cycle': 3, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0x86 */ {'instruction': Cpu.INSTRUCTIONS.STX, 'cycle': 3, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0x87 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x88 */ {'instruction': Cpu.INSTRUCTIONS.DEY, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0x89 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x8A */ {'instruction': Cpu.INSTRUCTIONS.TXA, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0x8B */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x8C */ {'instruction': Cpu.INSTRUCTIONS.STY, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0x8D */ {'instruction': Cpu.INSTRUCTIONS.STA, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0x8E */ {'instruction': Cpu.INSTRUCTIONS.STX, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0x8F */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x90 */ {'instruction': Cpu.INSTRUCTIONS.BCC, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.RELATIVE},
/* 0x91 */ {'instruction': Cpu.INSTRUCTIONS.STA, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.INDEXED_INDIRECT_Y},
/* 0x92 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x93 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x94 */ {'instruction': Cpu.INSTRUCTIONS.STY, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ZERO_PAGE_X},
/* 0x95 */ {'instruction': Cpu.INSTRUCTIONS.STA, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ZERO_PAGE_X},
/* 0x96 */ {'instruction': Cpu.INSTRUCTIONS.STX, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ZERO_PAGE_Y},
/* 0x97 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x98 */ {'instruction': Cpu.INSTRUCTIONS.TYA, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0x99 */ {'instruction': Cpu.INSTRUCTIONS.STA, 'cycle': 5, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_Y},
/* 0x9A */ {'instruction': Cpu.INSTRUCTIONS.TXS, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0x9B */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x9C */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x9D */ {'instruction': Cpu.INSTRUCTIONS.STA, 'cycle': 5, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_X},
/* 0x9E */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0x9F */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xA0 */ {'instruction': Cpu.INSTRUCTIONS.LDY, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMMEDIATE},
/* 0xA1 */ {'instruction': Cpu.INSTRUCTIONS.LDA, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.INDEXED_INDIRECT_X},
/* 0xA2 */ {'instruction': Cpu.INSTRUCTIONS.LDX, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMMEDIATE},
/* 0xA3 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xA4 */ {'instruction': Cpu.INSTRUCTIONS.LDY, 'cycle': 3, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0xA5 */ {'instruction': Cpu.INSTRUCTIONS.LDA, 'cycle': 3, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0xA6 */ {'instruction': Cpu.INSTRUCTIONS.LDX, 'cycle': 3, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0xA7 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xA8 */ {'instruction': Cpu.INSTRUCTIONS.TAY, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0xA9 */ {'instruction': Cpu.INSTRUCTIONS.LDA, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMMEDIATE},
/* 0xAA */ {'instruction': Cpu.INSTRUCTIONS.TAX, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0xAB */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xAC */ {'instruction': Cpu.INSTRUCTIONS.LDY, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0xAD */ {'instruction': Cpu.INSTRUCTIONS.LDA, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0xAE */ {'instruction': Cpu.INSTRUCTIONS.LDX, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0xAF */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xB0 */ {'instruction': Cpu.INSTRUCTIONS.BCS, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.RELATIVE},
/* 0xB1 */ {'instruction': Cpu.INSTRUCTIONS.LDA, 'cycle': 5, 'mode': Cpu.ADDRESSINGS.INDEXED_INDIRECT_Y},
/* 0xB2 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xB3 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xB4 */ {'instruction': Cpu.INSTRUCTIONS.LDY, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ZERO_PAGE_X},
/* 0xB5 */ {'instruction': Cpu.INSTRUCTIONS.LDA, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ZERO_PAGE_X},
/* 0xB6 */ {'instruction': Cpu.INSTRUCTIONS.LDX, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ZERO_PAGE_Y},
/* 0xB7 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xB8 */ {'instruction': Cpu.INSTRUCTIONS.CLV, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0xB9 */ {'instruction': Cpu.INSTRUCTIONS.LDA, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_Y},
/* 0xBA */ {'instruction': Cpu.INSTRUCTIONS.TSX, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0xBB */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xBC */ {'instruction': Cpu.INSTRUCTIONS.LDY, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_X},
/* 0xBD */ {'instruction': Cpu.INSTRUCTIONS.LDA, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_X},
/* 0xBE */ {'instruction': Cpu.INSTRUCTIONS.LDX, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_Y},
/* 0xBF */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xC0 */ {'instruction': Cpu.INSTRUCTIONS.CPY, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMMEDIATE},
/* 0xC1 */ {'instruction': Cpu.INSTRUCTIONS.CMP, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.INDEXED_INDIRECT_X},
/* 0xC2 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xC3 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xC4 */ {'instruction': Cpu.INSTRUCTIONS.CPY, 'cycle': 3, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0xC5 */ {'instruction': Cpu.INSTRUCTIONS.CMP, 'cycle': 3, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0xC6 */ {'instruction': Cpu.INSTRUCTIONS.DEC, 'cycle': 5, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0xC7 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xC8 */ {'instruction': Cpu.INSTRUCTIONS.INY, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0xC9 */ {'instruction': Cpu.INSTRUCTIONS.CMP, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMMEDIATE},
/* 0xCA */ {'instruction': Cpu.INSTRUCTIONS.DEX, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0xCB */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xCC */ {'instruction': Cpu.INSTRUCTIONS.CPY, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0xCD */ {'instruction': Cpu.INSTRUCTIONS.CMP, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0xCE */ {'instruction': Cpu.INSTRUCTIONS.DEC, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0xCF */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xD0 */ {'instruction': Cpu.INSTRUCTIONS.BNE, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.RELATIVE},
/* 0xD1 */ {'instruction': Cpu.INSTRUCTIONS.CMP, 'cycle': 5, 'mode': Cpu.ADDRESSINGS.INDEXED_INDIRECT_Y},
/* 0xD2 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xD3 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xD4 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xD5 */ {'instruction': Cpu.INSTRUCTIONS.CMP, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ZERO_PAGE_X},
/* 0xD6 */ {'instruction': Cpu.INSTRUCTIONS.DEC, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.INDEXED_ZERO_PAGE_X},
/* 0xD7 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xD8 */ {'instruction': Cpu.INSTRUCTIONS.CLD, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0xD9 */ {'instruction': Cpu.INSTRUCTIONS.CMP, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_Y},
/* 0xDA */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xDB */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xDC */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xDD */ {'instruction': Cpu.INSTRUCTIONS.CMP, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_X},
/* 0xDE */ {'instruction': Cpu.INSTRUCTIONS.DEC, 'cycle': 7, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_X},
/* 0xDF */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xE0 */ {'instruction': Cpu.INSTRUCTIONS.CPX, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMMEDIATE},
/* 0xE1 */ {'instruction': Cpu.INSTRUCTIONS.SBC, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.INDEXED_INDIRECT_X},
/* 0xE2 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xE3 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xE4 */ {'instruction': Cpu.INSTRUCTIONS.CPX, 'cycle': 3, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0xE5 */ {'instruction': Cpu.INSTRUCTIONS.SBC, 'cycle': 3, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0xE6 */ {'instruction': Cpu.INSTRUCTIONS.INC, 'cycle': 5, 'mode': Cpu.ADDRESSINGS.ZERO_PAGE},
/* 0xE7 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xE8 */ {'instruction': Cpu.INSTRUCTIONS.INX, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0xE9 */ {'instruction': Cpu.INSTRUCTIONS.SBC, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMMEDIATE},
/* 0xEA */ {'instruction': Cpu.INSTRUCTIONS.NOP, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0xEB */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xEC */ {'instruction': Cpu.INSTRUCTIONS.CPX, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0xED */ {'instruction': Cpu.INSTRUCTIONS.SBC, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0xEE */ {'instruction': Cpu.INSTRUCTIONS.INC, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.ABSOLUTE},
/* 0xEF */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xF0 */ {'instruction': Cpu.INSTRUCTIONS.BEQ, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.RELATIVE},
/* 0xF1 */ {'instruction': Cpu.INSTRUCTIONS.SBC, 'cycle': 5, 'mode': Cpu.ADDRESSINGS.INDEXED_INDIRECT_Y},
/* 0xF2 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xF3 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xF4 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xF5 */ {'instruction': Cpu.INSTRUCTIONS.SBC, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ZERO_PAGE_X},
/* 0xF6 */ {'instruction': Cpu.INSTRUCTIONS.INC, 'cycle': 6, 'mode': Cpu.ADDRESSINGS.INDEXED_ZERO_PAGE_X},
/* 0xF7 */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xF8 */ {'instruction': Cpu.INSTRUCTIONS.SED, 'cycle': 2, 'mode': Cpu.ADDRESSINGS.IMPLIED},
/* 0xF9 */ {'instruction': Cpu.INSTRUCTIONS.SBC, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_Y},
/* 0xFA */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xFB */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xFC */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null},
/* 0xFD */ {'instruction': Cpu.INSTRUCTIONS.SBC, 'cycle': 4, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_X},
/* 0xFE */ {'instruction': Cpu.INSTRUCTIONS.INC, 'cycle': 7, 'mode': Cpu.ADDRESSINGS.INDEXED_ABSOLUTE_X},
/* 0xFF */ {'instruction': Cpu.INSTRUCTIONS.INV, 'cycle': 0, 'mode': null}
];
Object.assign(Cpu.prototype, {
isCpu: true,
//
INTERRUPTS: Cpu.INTERRUPTS,
INTERRUPT_HANDLER_ADDRESSES: Cpu.INTERRUPT_HANDLER_ADDRESSES,
ADDRESSINGS: Cpu.ADDRESSINGS,
INSTRUCTIONS: Cpu.INSTRUCTIONS,
OPS: Cpu.OPS,
// public methods
// set methods
/**
*
*/
setPpu: function(ppu) {
this.ppu = ppu;
},
/**
*
*/
setApu: function(apu) {
this.apu = apu;
},
/**
*
*/
setJoypad1: function(pad1) {
this.pad1 = pad1;
},
/**
*
*/
setJoypad2: function(pad2) {
this.pad2 = pad2;
},
/**
*
*/
setRom: function(rom) {
this.rom = rom;
},
//
/**
* Refer to https://wiki.nesdev.com/w/index.php/CPU_power_up_state
*/
bootup: function() {
this.p.store(0x34);
this.a.clear();
this.x.clear();
this.y.clear();
this.sp.store(0xFD);
for(var i = 0; i < 0xF; i++)
this.store(0x4000 + i, 0);
this.store(0x4015, 0);
this.store(0x4017, 0);
this.interrupt(this.INTERRUPTS.RESET);
},
/**
* Refer to https://wiki.nesdev.com/w/index.php/CPU_power_up_state
*/
reset: function() {
this.sp.sub(3);
this.p.setI();
this.interrupt(this.INTERRUPTS.RESET);
},
/**
*
*/
runCycle: function() {
if(this.isStall() !== true) {
var opc = this.fetch();
var op = this.decode(opc);
this.operate(op, opc);
this.stallCycle = op.cycle;
}
this.stallCycle--;
},
/**
*
*/
isStall: function() {
return this.stallCycle > 0;
},
/**
*
*/
interrupt: function(type) {
if(type === this.INTERRUPTS.IRQ && this.p.isI() === true)
return;
if(type !== this.INTERRUPTS.RESET) {
if(type !== this.INTERRUPTS.BRK)
this.p.clearB();
this.p.setA();
this.pushStack2Bytes(this.pc.load());
this.pushStack(this.p.load());
this.p.setI();
}
this.jumpToInterruptHandler(type);
},
// load/store methods
/**
*
*/
load: function(address) {
address = address & 0xFFFF; // just in case
// 0x0000 - 0x07FF: 2KB internal RAM
// 0x0800 - 0x1FFF: Mirrors of 0x0000 - 0x07FF (repeats every 0x800 bytes)
if(address >= 0 && address < 0x2000)
return this.ram.load(address & 0x07FF);
// 0x2000 - 0x2007: PPU registers
// 0x2008 - 0x3FFF: Mirrors of 0x2000 - 0x2007 (repeats every 8 bytes)
if(address >= 0x2000 && address < 0x4000)
return this.ppu.loadRegister(address & 0x2007);
// 0x4000 - 0x4017: APU, PPU and I/O registers
// 0x4018 - 0x401F: APU and I/O functionality that is normally disabled
if(address >= 0x4000 && address < 0x4014)
return this.apu.loadRegister(address);
if(address === 0x4014)
return this.ppu.loadRegister(address);
if(address === 0x4015)
return this.apu.loadRegister(address);
if(address === 0x4016)
return this.pad1.loadRegister();
if(address >= 0x4017 && address < 0x4020)
return this.apu.loadRegister(address);
// cartridge space
if(address >= 0x4020 && address < 0x6000)
return this.ram.load(address);
// 0x6000 - 0x7FFF: Battery Backed Save or Work RAM
if(address >= 0x6000 && address < 0x8000)
return this.ram.load(address);
// 0x8000 - 0xFFFF: ROM
if(address >= 0x8000 && address < 0x10000)
return this.rom.load(address);
},
/**
*
*/
store: function(address, value) {
address = address & 0xFFFF; // just in case
// 0x0000 - 0x07FF: 2KB internal RAM
// 0x0800 - 0x1FFF: Mirrors of 0x0000 - 0x07FF (repeats every 0x800 bytes)
if(address >= 0 && address < 0x2000)
return this.ram.store(address & 0x07FF, value);
// 0x2000 - 0x2007: PPU registers
// 0x2008 - 0x3FFF: Mirrors of 0x2000 - 0x2007 (repeats every 8 bytes)
if(address >= 0x2000 && address < 0x4000)
return this.ppu.storeRegister(address & 0x2007, value);
// 0x4000 - 0x4017: APU, PPU and I/O registers
// 0x4018 - 0x401F: APU and I/O functionality that is normally disabled
if(address >= 0x4000 && address < 0x4014)
return this.apu.storeRegister(address, value);
if(address === 0x4014)
return thi