UNPKG

nes-js

Version:
1,408 lines (1,153 loc) 168 kB
/******/ (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