diff --git a/.eslintrc.json b/.eslintrc.json index 558111b..f59848f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -56,7 +56,7 @@ } }, { - "files": [ "js/entry2.js", "js/entry2e.js"], + "files": [ "js/entry2.js", "js/entry2e.js", "jest.config.js"], "env": { "commonjs": true } diff --git a/jest.config.js b/jest.config.js index 722e102..0d8d37c 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,13 +1,13 @@ module.exports = { - "roots": [ - "js/", - "test/", - ], - "testMatch": [ - "**/?(*.)+(spec|test).+(ts|js)" - ], - "transform": { - "^.+\\.js$": "babel-jest", - "^.+\\.ts$": "ts-jest" - }, -} \ No newline at end of file + 'roots': [ + 'js/', + 'test/', + ], + 'testMatch': [ + '**/?(*.)+(spec|test).+(ts|js)' + ], + 'transform': { + '^.+\\.js$': 'babel-jest', + '^.+\\.ts$': 'ts-jest' + }, +}; \ No newline at end of file diff --git a/js/cpu6502.ts b/js/cpu6502.ts index 56eefa5..a8c5e91 100644 --- a/js/cpu6502.ts +++ b/js/cpu6502.ts @@ -20,68 +20,64 @@ export interface CpuOptions { } export interface CpuState { - a: byte, - x: byte, - y: byte, - s: byte, - pc: word, - sp: byte, - cycles: number + a: byte, + x: byte, + y: byte, + s: byte, + pc: word, + sp: byte, + cycles: number } -/** Range of mode numbers. */ -type mode = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15; +type Mode = + 'accumulator' | // A (Accumulator) + 'implied' | // Implied + 'immediate' | // # Immediate + 'absolute' | // a Absolute + 'zeroPage' | // zp Zero Page + 'relative' | // r Relative + 'absoluteX' | // a,X Absolute, X + 'absoluteY' | // a,Y Absolute, Y + 'zeroPageX' | // zp,X Zero Page, X + 'zeroPageY' | // zp,Y Zero Page, Y + 'absoluteIndirect' | // (a) Indirect + 'zeroPageXIndirect' | // (zp,X) Zero Page Indexed Indirect + 'zeroPageIndirectY' | // (zp),Y Zero Page Indexed with Y + 'zeroPageIndirect' | // (zp), + 'absoluteXIndirect' | // (a, X), + 'zeroPage_relative'; // zp, Relative -/** Addressing mode name to number mapping. */ -const modes: { [key: string]: mode } = { - accumulator: 0, // A (Accumulator) - implied: 1, // Implied - immediate: 2, // # Immediate - absolute: 3, // a Absolute - zeroPage: 4, // zp Zero Page - relative: 5, // r Relative +type Modes = Record; - absoluteX: 6, // a,X Absolute, X - absoluteY: 7, // a,Y Absolute, Y - zeroPageX: 8, // zp,X Zero Page, X - zeroPageY: 9, // zp,Y Zero Page, Y +/** Addressing mode name to instruction size mapping. */ +const sizes: Modes = { + accumulator: 1, + implied: 1, + immediate: 2, + absolute: 3, + zeroPage: 2, + relative: 2, - absoluteIndirect: 10, // (a) Indirect - zeroPageXIndirect: 11, // (zp,X) Zero Page Indexed Indirect - zeroPageIndirectY: 12, // (zp),Y Zero Page Indexed with Y + absoluteX: 3, + absoluteY: 3, + zeroPageX: 2, + zeroPageY: 2, + + absoluteIndirect: 3, + zeroPageXIndirect: 2, + zeroPageIndirectY: 2, /* 65c02 */ - zeroPageIndirect: 13, // (zp), - absoluteXIndirect: 14, // (a, X), - zeroPage_relative: 15 // zp, Relative -}; - -/** Instruction size by addressing mode. */ -const sizes = { - 0 /* modes.accumulator */: 1, - 1 /* modes.implied */: 1, - 2 /* modes.immediate */: 2, - 3 /* modes.absolute */: 3, - 4 /* modes.zeroPage */: 2, - 5 /* modes.relative */: 2, - 6 /* modes.absoluteX */: 3, - 7 /* modes.absoluteY */: 3, - 8 /* modes.zeroPageX */: 2, - 9 /* modes.zeroPageY */: 2, - 10 /* modes.indirect */: 3, - 11 /* modes.zeroPageXIndirect */: 2, - 12 /* modes.zeroPageYIndirect */: 2, - - 13 /* mode.zeroPageIndirect */: 2, - 14 /* mode.absoluteXIndirect */: 3, - 15 /* mode.zeroPage_relative */: 3 + zeroPageIndirect: 2, + absoluteXIndirect: 3, + zeroPage_relative: 3 }; /** Status register flag numbers. */ -type flag = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7; +type flag = 0x80 | 0x40 | 0x20 | 0x10 | 0x08 | 0x04 | 0x02 | 0x01; /** Flags to status byte mask. */ -const flags = { +const flags: {[key: string]: flag} = { N: 0x80, // Negative V: 0x40, // oVerflow B: 0x10, // Break @@ -99,7 +95,7 @@ const loc = { BRK: 0xFFFE }; -interface ReadablePage { +export interface ReadablePage { read(page: byte, offset: byte): byte; } @@ -107,7 +103,7 @@ function isReadablePage(page: ReadablePage | any): page is ReadablePage { return (page as ReadablePage).read !== undefined; } -interface WriteablePage { +export interface WriteablePage { write(page: byte, offset: byte, value: byte): void; } @@ -115,7 +111,7 @@ function isWriteablePage(page: WriteablePage | any): page is WriteablePage { return (page as WriteablePage).write !== undefined; } -interface PageHandler { +export interface PageHandler { start(): byte; end(): byte; } @@ -140,62 +136,23 @@ interface Opts { type ReadFn = () => byte; type WriteFn = (val: byte) => void; type ReadAddrFn = (opts?: Opts) => word; +type ImpliedFn = () => void -type readInstruction = [ - desc: string, - op: (readFn: ReadFn) => void, - modeFn: ReadFn, - mode: mode, // really 0-15 - cycles: number, -]; +interface Op { + name: string + mode: keyof Modes + op: (fn: T) => void + modeFn: T +} -type writeInstruction = [ - desc: string, - op: (writeFn: WriteFn) => void, - modeFn: WriteFn, - mode: mode, // really 0-15 - cycles: number, -]; - -type impliedInstruction = [ - desc: string, - op: () => void, - modeFn: null, - mode: mode, // really 0-15 - cycles: number, -]; - -type relativeInstruction = [ - desc: string, - op: (f: byte) => void, - modeFn: byte, - mode: mode, // really 0-15 - cycles: number, -]; - -type noopInstruction = [ - desc: string, - op: (readAddrFn: ReadAddrFn) => void, - modeFn: () => void, - mode: mode, // really 0-15 - cycles: number, -]; - -type instruction = - readInstruction | writeInstruction | - impliedInstruction | relativeInstruction | noopInstruction; +type Instruction = Op interface Instructions { - [key: number]: instruction; + [key: number]: Instruction; } type callback = (cpu: any) => void; // TODO(flan): Hack until there is better typing. -function bind(op: instruction, o: CPU6502): instruction { - let op2: instruction[2] = typeof op[2] === "function" ? op[2].bind(o) : op[2]; - return [op[0], op[1].bind(o), op2, op[3], op[4]]; -} - export default class CPU6502 { private readonly is65C02; @@ -214,7 +171,7 @@ export default class CPU6502 { private sync = false; private readonly ops: Instructions; - private readonly opary: instruction[]; + private readonly opary: Instruction[]; constructor(options: CpuOptions = {}) { this.is65C02 = options['65C02'] ? true : false; @@ -225,18 +182,18 @@ export default class CPU6502 { } // Create this CPU's instruction table - let ops: Instructions = []; - Object.assign(ops, OPS_6502); + + let ops: Instructions = { ...this.OPS_6502 }; if (this.is65C02) { - Object.assign(ops, OPS_65C02); + ops = { ...ops, ...this.OPS_65C02 }; } this.ops = ops; // Certain browsers benefit from using arrays over maps - let opary: instruction[] = []; + const opary: Instruction[] = []; for (let idx = 0; idx < 0x100; idx++) { - opary[idx] = bind(ops[idx] || this.unknown(idx), this); + opary[idx] = ops[idx] || this.unknown(idx) } this.opary = opary; } @@ -400,30 +357,34 @@ export default class CPU6502 { return (msb << 8) | lsb; } + /* + * Implied function + */ + + implied() { + } + /* * Read functions */ - readImplied() { - } - // #$00 - readImmediate(): byte { + readImmediate = (): byte => { return this.readBytePC(); } // $0000 - readAbsolute(): byte { + readAbsolute = (): byte => { return this.readByte(this.readWordPC()); } // $00 - readZeroPage(): byte { + readZeroPage= (): byte => { return this.readByte(this.readBytePC()); } // $0000,X - readAbsoluteX(): byte { + readAbsoluteX= (): byte => { var addr = this.readWordPC(); var oldPage = addr >> 8; addr = (addr + this.xr) & 0xffff; @@ -436,7 +397,7 @@ export default class CPU6502 { } // $0000,Y - readAbsoluteY(): byte { + readAbsoluteY = (): byte => { var addr = this.readWordPC(); var oldPage = addr >> 8; addr = (addr + this.yr) & 0xffff; @@ -449,21 +410,21 @@ export default class CPU6502 { } // $00,X - readZeroPageX(): byte { + readZeroPageX = (): byte => { var zpAddr = this.readBytePC(); this.readByte(zpAddr); return this.readByte((zpAddr + this.xr) & 0xff); } // $00,Y - readZeroPageY(): byte { + readZeroPageY = (): byte => { var zpAddr = this.readBytePC(); this.readByte(zpAddr); return this.readByte((zpAddr + this.yr) & 0xff); } // ($00,X) - readZeroPageXIndirect(): byte { + readZeroPageXIndirect = (): byte => { var zpAddr = this.readBytePC(); this.readByte(zpAddr); var addr = this.readZPWord((zpAddr + this.xr) & 0xff); @@ -471,7 +432,7 @@ export default class CPU6502 { } // ($00),Y - readZeroPageIndirectY(): byte { + readZeroPageIndirectY = (): byte => { var addr = this.readZPWord(this.readBytePC()); var oldPage = addr >> 8; addr = (addr + this.yr) & 0xffff; @@ -484,7 +445,7 @@ export default class CPU6502 { } // ($00) (65C02) - readZeroPageIndirect(): byte { + readZeroPageIndirect = (): byte => { return this.readByte(this.readZPWord(this.readBytePC())); } @@ -493,17 +454,17 @@ export default class CPU6502 { */ // $0000 - writeAbsolute(val: byte) { + writeAbsolute = (val: byte) => { this.writeByte(this.readWordPC(), val); } // $00 - writeZeroPage(val: byte) { + writeZeroPage = (val: byte) => { this.writeByte(this.readBytePC(), val); } // $0000,X - writeAbsoluteX(val: byte) { + writeAbsoluteX = (val: byte) => { var addr = this.readWordPC(), oldPage = addr >> 8; addr = (addr + this.xr) & 0xffff; var off = addr & 0xff; @@ -512,7 +473,7 @@ export default class CPU6502 { } // $0000,Y - writeAbsoluteY(val: byte) { + writeAbsoluteY = (val: byte) => { var addr = this.readWordPC(), oldPage = addr >> 8; addr = (addr + this.yr) & 0xffff; var off = addr & 0xff; @@ -521,21 +482,21 @@ export default class CPU6502 { } // $00,X - writeZeroPageX(val: byte) { + writeZeroPageX = (val: byte) => { var zpAddr = this.readBytePC(); this.readByte(zpAddr); this.writeByte((zpAddr + this.xr) & 0xff, val); } // $00,Y - writeZeroPageY(val: byte) { + writeZeroPageY = (val: byte) => { var zpAddr = this.readBytePC(); this.readByte(zpAddr); this.writeByte((zpAddr + this.yr) & 0xff, val); } // ($00,X) - writeZeroPageXIndirect(val: byte) { + writeZeroPageXIndirect = (val: byte) => { var zpAddr = this.readBytePC(); this.readByte(zpAddr); var addr = this.readZPWord((zpAddr + this.xr) & 0xff); @@ -543,7 +504,7 @@ export default class CPU6502 { } // ($00),Y - writeZeroPageIndirectY(val: byte) { + writeZeroPageIndirectY = (val: byte) => { var addr = this.readZPWord(this.readBytePC()), oldPage = addr >> 8; addr = (addr + this.yr) & 0xffff; var off = addr & 0xff; @@ -552,29 +513,29 @@ export default class CPU6502 { } // ($00) (65C02) - writeZeroPageIndirect(val: byte) { + writeZeroPageIndirect = (val: byte) => { this.writeByte(this.readZPWord(this.readBytePC()), val); } // $00 - readAddrZeroPage(): byte { + readAddrZeroPage = (): byte => { return this.readBytePC(); } // $00,X - readAddrZeroPageX() { + readAddrZeroPageX = () => { var zpAddr = this.readBytePC(); this.readByte(zpAddr); return (zpAddr + this.xr) & 0xff; } // $0000 (65C02) - readAddrAbsolute(): word { + readAddrAbsolute = (): word => { return this.readWordPC(); } // ($0000) (6502) - readAddrAbsoluteIndirectBug(): word { + readAddrAbsoluteIndirectBug = (): word => { var addr = this.readWordPC(); var page = addr & 0xff00; var off = addr & 0x00ff; @@ -584,7 +545,7 @@ export default class CPU6502 { } // ($0000) (65C02) - readAddrAbsoluteIndirect(): word { + readAddrAbsoluteIndirect = (): word => { var lsb = this.readBytePC(); var msb = this.readBytePC(); this.readByte(this.pc); @@ -592,7 +553,7 @@ export default class CPU6502 { } // $0000,X - readAddrAbsoluteX(opts: Opts = {}): word { + readAddrAbsoluteX = (opts: Opts = {}): word => { var addr = this.readWordPC(); if (!this.is65C02 || opts.rwm) { this.readByte(addr); @@ -603,14 +564,14 @@ export default class CPU6502 { } // $(0000,X) (65C02) - readAddrAbsoluteXIndirect(): word { + readAddrAbsoluteXIndirect = (): word => { var address = this.readWordPC(); this.readByte(this.pc); return this.readWord((address + this.xr) & 0xffff); } /* Break */ - brk(readFn: ReadFn) { + brk = (readFn: ReadFn) => { readFn(); this.pushWord(this.pc); this.pushByte(this.sr | flags.B); @@ -622,57 +583,57 @@ export default class CPU6502 { } /* Load Accumulator */ - lda(readFn: ReadFn) { + lda = (readFn: ReadFn) => { this.ar = this.testNZ(readFn()); } /* Load X Register */ - ldx(readFn: ReadFn) { + ldx = (readFn: ReadFn) => { this.xr = this.testNZ(readFn()); } /* Load Y Register */ - ldy(readFn: ReadFn) { + ldy = (readFn: ReadFn) => { this.yr = this.testNZ(readFn()); } /* Store Accumulator */ - sta(writeFn: WriteFn) { + sta = (writeFn: WriteFn) => { writeFn(this.ar); } /* Store X Register */ - stx(writeFn: WriteFn) { + stx = (writeFn: WriteFn) => { writeFn(this.xr); } /* Store Y Register */ - sty(writeFn: WriteFn) { + sty = (writeFn: WriteFn) => { writeFn(this.yr); } /* Store Zero */ - stz(writeFn: WriteFn) { + stz = (writeFn: WriteFn) => { writeFn(0); } /* Add with Carry */ - adc(readFn: ReadFn) { + adc = (readFn: ReadFn) => { this.ar = this.add(this.ar, readFn(), /* sub= */ false); } /* Subtract with Carry */ - sbc(readFn: ReadFn) { + sbc = (readFn: ReadFn) => { this.ar = this.add(this.ar, readFn(), /* sub= */ true); } /* Increment Memory */ - incA() { + incA = () => { this.readByte(this.pc); this.ar = this.increment(this.ar); } - inc(readAddrFn: ReadAddrFn) { + inc = (readAddrFn: ReadAddrFn) => { var addr = readAddrFn({rwm: true}); var oldVal = this.readByte(addr); this.writeByte(addr, oldVal); @@ -681,24 +642,24 @@ export default class CPU6502 { } /* Increment X */ - inx() { + inx = () => { this.readByte(this.pc); this.xr = this.increment(this.xr); } /* Increment Y */ - iny() { + iny = () => { this.readByte(this.pc); this.yr = this.increment(this.yr); } /* Decrement Memory */ - decA() { + decA = () => { this.readByte(this.pc); this.ar = this.decrement(this.ar); } - dec(readAddrFn: ReadAddrFn) { + dec = (readAddrFn: ReadAddrFn) => { var addr = readAddrFn({rwm: true}); var oldVal = this.readByte(addr); this.writeByte(addr, oldVal); @@ -707,29 +668,29 @@ export default class CPU6502 { } /* Decrement X */ - dex() { + dex = () => { this.readByte(this.pc); this.xr = this.decrement(this.xr); } /* Decrement Y */ - dey() { + dey = () => { this.readByte(this.pc); this.yr = this.decrement(this.yr); } - shiftLeft(val: byte) { + shiftLeft = (val: byte) => { this.setFlag(flags.C, !!(val & 0x80)); return this.testNZ((val << 1) & 0xff); } /* Arithmetic Shift Left */ - aslA() { + aslA = () => { this.readByte(this.pc); this.ar = this.shiftLeft(this.ar); } - asl(readAddrFn: ReadAddrFn) { + asl = (readAddrFn: ReadAddrFn) => { var addr = readAddrFn({rwm: true}); var oldVal = this.readByte(addr); this.writeByte(addr, oldVal); @@ -737,18 +698,18 @@ export default class CPU6502 { this.writeByte(addr, val); } - shiftRight(val: byte) { + shiftRight = (val: byte) => { this.setFlag(flags.C, !!(val & 0x01)); return this.testNZ(val >> 1); } /* Logical Shift Right */ - lsrA() { + lsrA = () => { this.readByte(this.pc); this.ar = this.shiftRight(this.ar); } - lsr(readAddrFn: ReadAddrFn) { + lsr = (readAddrFn: ReadAddrFn) => { var addr = readAddrFn({rwm: true}); var oldVal = this.readByte(addr); this.writeByte(addr, oldVal); @@ -756,19 +717,19 @@ export default class CPU6502 { this.writeByte(addr, val); } - rotateLeft(val: byte) { + rotateLeft = (val: byte) => { var c = (this.sr & flags.C); this.setFlag(flags.C, !!(val & 0x80)); return this.testNZ(((val << 1) | (c ? 0x01 : 0x00)) & 0xff); } /* Rotate Left */ - rolA() { + rolA = () => { this.readByte(this.pc); this.ar = this.rotateLeft(this.ar); } - rol(readAddrFn: ReadAddrFn) { + rol = (readAddrFn: ReadAddrFn) => { var addr = readAddrFn({rwm: true}); var oldVal = this.readByte(addr); this.writeByte(addr, oldVal); @@ -783,12 +744,12 @@ export default class CPU6502 { } /* Rotate Right */ - rorA() { + rorA = () => { this.readByte(this.pc); this.ar = this.rotateRight(this.ar); } - ror(readAddrFn: ReadAddrFn) { + ror = (readAddrFn: ReadAddrFn) => { var addr = readAddrFn({rwm: true}); var oldVal = this.readByte(addr); this.writeByte(addr, oldVal); @@ -797,23 +758,23 @@ export default class CPU6502 { } /* Logical And Accumulator */ - and(readFn: ReadFn) { + and = (readFn: ReadFn) => { this.ar = this.testNZ(this.ar & readFn()); } /* Logical Or Accumulator */ - ora(readFn: ReadFn) { + ora = (readFn: ReadFn) => { this.ar = this.testNZ(this.ar | readFn()); } /* Logical Exclusive Or Accumulator */ - eor(readFn: ReadFn) { + eor = (readFn: ReadFn) => { this.ar = this.testNZ(this.ar ^ readFn()); } /* Reset Bit */ - rmb(b: byte) { + rmb = (b: byte) => { var bit = (0x1 << b) ^ 0xFF; var addr = this.readBytePC(); var val = this.readByte(addr); @@ -824,7 +785,7 @@ export default class CPU6502 { /* Set Bit */ - smb(b: byte) { + smb = (b: byte) => { var bit = 0x1 << b; var addr = this.readBytePC(); var val = this.readByte(addr); @@ -834,7 +795,7 @@ export default class CPU6502 { } /* Test and Reset Bits */ - trb(readAddrFn: ReadAddrFn) { + trb = (readAddrFn: ReadAddrFn) => { var addr = readAddrFn(); var val = this.readByte(addr); this.testZ(val & this.ar); @@ -843,7 +804,7 @@ export default class CPU6502 { } /* Test and Set Bits */ - tsb(readAddrFn: ReadAddrFn) { + tsb = (readAddrFn: ReadAddrFn) => { var addr = readAddrFn(); var val = this.readByte(addr); this.testZ(val & this.ar); @@ -852,7 +813,7 @@ export default class CPU6502 { } /* Bit */ - bit(readFn: ReadFn) { + bit = (readFn: ReadFn) => { var val = readFn(); this.setFlag(flags.Z, (val & this.ar) === 0); this.setFlag(flags.N, !!(val & 0x80)); @@ -860,7 +821,7 @@ export default class CPU6502 { } /* Bit Immediate*/ - bitI(readFn: ReadFn) { + bitI = (readFn: ReadFn) => { var val = readFn(); this.setFlag(flags.Z, (val & this.ar) === 0); } @@ -872,20 +833,20 @@ export default class CPU6502 { this.testNZ(c & 0xff); } - cmp(readFn: ReadFn) { + cmp = (readFn: ReadFn) => { this.compare(this.ar, readFn()); } - cpx(readFn: ReadFn) { + cpx = (readFn: ReadFn) => { this.compare(this.xr, readFn()); } - cpy(readFn: ReadFn) { + cpy = (readFn: ReadFn) => { this.compare(this.yr, readFn()); } /* Branches */ - brs(f: flag) { + brs = (f: flag) => { let off = this.readBytePC(); // changes pc if ((f & this.sr) !== 0) { this.readByte(this.pc); @@ -897,7 +858,7 @@ export default class CPU6502 { } } - brc(f: flag) { + brc = (f: flag) => { let off = this.readBytePC(); // changes pc if ((f & this.sr) === 0) { this.readByte(this.pc); @@ -911,7 +872,7 @@ export default class CPU6502 { /* WDC 65C02 branches */ - bbr(b: flag) { + bbr = (b: flag) => { let zpAddr = this.readBytePC(); let val = this.readByte(zpAddr); this.readByte(zpAddr); @@ -929,7 +890,7 @@ export default class CPU6502 { } } - bbs(b: flag) { + bbs = (b: flag) => { let zpAddr = this.readBytePC(); let val = this.readByte(zpAddr); this.readByte(zpAddr); @@ -948,41 +909,41 @@ export default class CPU6502 { } /* Transfers and stack */ - tax() { this.readByte(this.pc); this.testNZ(this.xr = this.ar); } + tax = () => { this.readByte(this.pc); this.testNZ(this.xr = this.ar); } - txa() { this.readByte(this.pc); this.testNZ(this.ar = this.xr); } + txa = () => { this.readByte(this.pc); this.testNZ(this.ar = this.xr); } - tay() { this.readByte(this.pc); this.testNZ(this.yr = this.ar); } - - tya() { this.readByte(this.pc); this.testNZ(this.ar = this.yr); } + tay = () => { this.readByte(this.pc); this.testNZ(this.yr = this.ar); } - tsx() { this.readByte(this.pc); this.testNZ(this.xr = this.sp); } + tya = () => { this.readByte(this.pc); this.testNZ(this.ar = this.yr); } - txs() { this.readByte(this.pc); this.sp = this.xr; } + tsx = () => { this.readByte(this.pc); this.testNZ(this.xr = this.sp); } - pha() { this.readByte(this.pc); this.pushByte(this.ar); } + txs = () => { this.readByte(this.pc); this.sp = this.xr; } - pla() { this.readByte(this.pc); this.readByte(0x0100 | this.sp); this.testNZ(this.ar = this.pullByte()); } + pha = () => { this.readByte(this.pc); this.pushByte(this.ar); } - phx() { this.readByte(this.pc); this.pushByte(this.xr); } + pla = () => { this.readByte(this.pc); this.readByte(0x0100 | this.sp); this.testNZ(this.ar = this.pullByte()); } - plx() { this.readByte(this.pc); this.readByte(0x0100 | this.sp);this.testNZ(this.xr = this.pullByte()); } + phx = () => { this.readByte(this.pc); this.pushByte(this.xr); } - phy() { this.readByte(this.pc); this.pushByte(this.yr); } + plx = () => { this.readByte(this.pc); this.readByte(0x0100 | this.sp);this.testNZ(this.xr = this.pullByte()); } - ply() { this.readByte(this.pc); this.readByte(0x0100 | this.sp); this.testNZ(this.yr = this.pullByte()); } + phy = () => { this.readByte(this.pc); this.pushByte(this.yr); } - php() { this.readByte(this.pc); this.pushByte(this.sr | flags.B); } + ply = () => { this.readByte(this.pc); this.readByte(0x0100 | this.sp); this.testNZ(this.yr = this.pullByte()); } - plp() { this.readByte(this.pc); this.readByte(0x0100 | this.sp); this.sr = (this.pullByte() & ~flags.B) | 0x20; } + php = () => { this.readByte(this.pc); this.pushByte(this.sr | flags.B); } + + plp = () => { this.readByte(this.pc); this.readByte(0x0100 | this.sp); this.sr = (this.pullByte() & ~flags.B) | 0x20; } /* Jump */ - jmp(readAddrFn: ReadAddrFn) { + jmp = (readAddrFn: ReadAddrFn) => { this.pc = readAddrFn(); } /* Jump Subroutine */ - jsr() { + jsr = () => { let lsb = this.readBytePC(); this.readByte(0x0100 | this.sp); this.pushWord(this.pc); @@ -991,7 +952,7 @@ export default class CPU6502 { } /* Return from Subroutine */ - rts() { + rts = () => { this.readByte(this.pc); this.readByte(0x0100 | this.sp); let addr = this.pullWordRaw(); @@ -1000,7 +961,7 @@ export default class CPU6502 { } /* Return from Interrupt */ - rti() { + rti = () => { this.readByte(this.pc); this.readByte(0x0100 | this.sp); this.sr = this.pullByte() & ~flags.B; @@ -1008,50 +969,48 @@ export default class CPU6502 { } /* Set and Clear */ - set(flag: flag) { + set = (flag: flag) => { this.readByte(this.pc); this.sr |= flag; } - clr(flag: flag) { + clr = (flag: flag) => { this.readByte(this.pc); this.sr &= ~flag; } /* No-Op */ - nop(readAddrFn: ReadAddrFn) { + nop = (readAddrFn: ReadAddrFn) => { this.readByte(this.pc); readAddrFn(); } private unknown(b: byte) { - let unk: noopInstruction; + let unk: Instruction; if (this.is65C02) { - unk = [ - 'NOP', - this.nop, - this.readImplied, - modes.implied, - 2 - ]; + unk = { + name: 'NOP', + op: this.nop, + modeFn: this.implied, + mode: 'implied', + } } else { - unk = [ - '???', - function() { - debug('Unknown OpCode: ' + toHex(b) + - ' at ' + toHex(this.pc - 1, 4)); + unk = { + name: '???', + op: function() { + debug('Unknown OpCode: ' + toHex(b) + + ' at ' + toHex(this.pc - 1, 4)); }, - this.readImplied, - modes.implied, - 1 - ]; + modeFn: this.implied, + mode: 'implied' + } } this.ops[b] = unk; return unk; } - private dumpArgs(addr: word, m: mode, symbols: symbols) { + private dumpArgs(addr: word, m: Mode, symbols: symbols) { function toHexOrSymbol(v: word, n?: number) { if (symbols && symbols[v]) { return symbols[v]; @@ -1062,18 +1021,18 @@ export default class CPU6502 { let result = ''; switch (m) { - case modes.implied: + case 'implied': break; - case modes.immediate: + case 'immediate': result = '#' + toHexOrSymbol(this.readByteDebug(addr)); break; - case modes.absolute: + case 'absolute': result = '' + toHexOrSymbol(this.readWordDebug(addr), 4); break; - case modes.zeroPage: + case 'zeroPage': result = '' + toHexOrSymbol(this.readByteDebug(addr)); break; - case modes.relative: + case 'relative': { let off = this.readByteDebug(addr); if (off > 127) { @@ -1083,37 +1042,37 @@ export default class CPU6502 { result = '' + toHexOrSymbol(addr, 4) + ' (' + off + ')'; } break; - case modes.absoluteX: + case 'absoluteX': result = '' + toHexOrSymbol(this.readWordDebug(addr), 4) + ',X'; break; - case modes.absoluteY: + case 'absoluteY': result = '' + toHexOrSymbol(this.readWordDebug(addr), 4) + ',Y'; break; - case modes.zeroPageX: + case 'zeroPageX': result = '' + toHexOrSymbol(this.readByteDebug(addr)) + ',X'; break; - case modes.zeroPageY: + case 'zeroPageY': result = '' + toHexOrSymbol(this.readByteDebug(addr)) + ',Y'; break; - case modes.absoluteIndirect: + case 'absoluteIndirect': result = '(' + toHexOrSymbol(this.readWordDebug(addr), 4) + ')'; break; - case modes.zeroPageXIndirect: + case 'zeroPageXIndirect': result = '(' + toHexOrSymbol(this.readByteDebug(addr)) + ',X)'; break; - case modes.zeroPageIndirectY: + case 'zeroPageIndirectY': result = '(' + toHexOrSymbol(this.readByteDebug(addr)) + '),Y'; break; - case modes.accumulator: + case 'accumulator': result = 'A'; break; - case modes.zeroPageIndirect: + case 'zeroPageIndirect': result = '(' + toHexOrSymbol(this.readByteDebug(addr)) + ')'; break; - case modes.absoluteXIndirect: + case 'absoluteXIndirect': result = '(' + toHexOrSymbol(this.readWordDebug(addr), 4) + ',X)'; break; - case modes.zeroPage_relative: + case 'zeroPage_relative': let val = this.readByteDebug(addr); let off = this.readByteDebug(addr + 1); if (off > 127) { @@ -1132,7 +1091,7 @@ export default class CPU6502 { this.sync = true; let op = this.opary[this.readBytePC()]; this.sync = false; - op[1](op[2] as any); // TODO(flan): Hack until there is better typing. + op.op(op.modeFn); if (cb) { cb(this); @@ -1144,7 +1103,7 @@ export default class CPU6502 { this.sync = true; let op = this.opary[this.readBytePC()]; this.sync = false; - op[1](op[2] as any); // TODO(flan): Hack until there is better typing. + op.op(op.modeFn); if (cb) { cb(this); @@ -1159,7 +1118,7 @@ export default class CPU6502 { this.sync = true; let op = this.opary[this.readBytePC()]; this.sync = false; - op[1](op[2] as any); // TODO(flan): Hack until there is better typing. + op.op(op.modeFn); } } @@ -1170,7 +1129,7 @@ export default class CPU6502 { this.sync = true; op = this.opary[this.readBytePC()]; this.sync = false; - op[1](op[2] as any); // TODO(flan): Hack until there is better typing. + op.op(op.modeFn); if (cb) { cb(this); @@ -1241,7 +1200,7 @@ export default class CPU6502 { } let b = this.readByte(pc), op = this.ops[b], - size = sizes[op[3]], + size = sizes[op.mode], result = toHex(pc, 4) + '- '; if (symbols) { @@ -1264,7 +1223,7 @@ export default class CPU6502 { if (op === undefined) result += '??? (' + toHex(b) + ')'; else - result += op[0] + ' ' + this.dumpArgs(pc + 1, op[3], symbols); + result += op.name + ' ' + this.dumpArgs(pc + 1, op.mode, symbols); return result; } @@ -1308,7 +1267,7 @@ export default class CPU6502 { for (var jdx = 0; jdx < 20; jdx++) { var b = this.readByte(_pc), op = this.ops[b]; results.push(this.dumpPC(_pc, symbols)); - _pc += sizes[op[3]]; + _pc += sizes[op.mode]; } return results; } @@ -1372,388 +1331,387 @@ export default class CPU6502 { public write(page: byte, off: byte, val: byte) { this.writePages[page].write(page, off, val); } -} -const c = CPU6502.prototype; -const OPS_6502: Instructions = { - // LDA - 0xa9: ['LDA', c.lda, c.readImmediate, modes.immediate, 2], - 0xa5: ['LDA', c.lda, c.readZeroPage, modes.zeroPage, 3], - 0xb5: ['LDA', c.lda, c.readZeroPageX, modes.zeroPageX, 4], - 0xad: ['LDA', c.lda, c.readAbsolute, modes.absolute, 4], - 0xbd: ['LDA', c.lda, c.readAbsoluteX, modes.absoluteX, 4], - 0xb9: ['LDA', c.lda, c.readAbsoluteY, modes.absoluteY, 4], - 0xa1: ['LDA', c.lda, c.readZeroPageXIndirect, modes.zeroPageXIndirect, 6], - 0xb1: ['LDA', c.lda, c.readZeroPageIndirectY, modes.zeroPageIndirectY, 5], + OPS_6502: Instructions = { + // LDA + 0xa9: { name: 'LDA', op: this.lda, modeFn: this.readImmediate, mode: 'immediate' }, + 0xa5: { name: 'LDA', op: this.lda, modeFn: this.readZeroPage, mode: 'zeroPage' }, + 0xb5: { name: 'LDA', op: this.lda, modeFn: this.readZeroPageX, mode: 'zeroPageX' }, + 0xad: { name: 'LDA', op: this.lda, modeFn: this.readAbsolute, mode: 'absolute' }, + 0xbd: { name: 'LDA', op: this.lda, modeFn: this.readAbsoluteX, mode: 'absoluteX' }, + 0xb9: { name: 'LDA', op: this.lda, modeFn: this.readAbsoluteY, mode: 'absoluteY' }, + 0xa1: { name: 'LDA', op: this.lda, modeFn: this.readZeroPageXIndirect, mode: 'zeroPageXIndirect' }, + 0xb1: { name: 'LDA', op: this.lda, modeFn: this.readZeroPageIndirectY, mode: 'zeroPageIndirectY' }, - // LDX - 0xa2: ['LDX', c.ldx, c.readImmediate, modes.immediate, 2], - 0xa6: ['LDX', c.ldx, c.readZeroPage, modes.zeroPage, 3], - 0xb6: ['LDX', c.ldx, c.readZeroPageY, modes.zeroPageY, 4], - 0xae: ['LDX', c.ldx, c.readAbsolute, modes.absolute, 4], - 0xbe: ['LDX', c.ldx, c.readAbsoluteY, modes.absoluteY, 4], + // LDX + 0xa2: { name: 'LDX', op: this.ldx, modeFn: this.readImmediate, mode: 'immediate' }, + 0xa6: { name: 'LDX', op: this.ldx, modeFn: this.readZeroPage, mode: 'zeroPage' }, + 0xb6: { name: 'LDX', op: this.ldx, modeFn: this.readZeroPageY, mode: 'zeroPageY' }, + 0xae: { name: 'LDX', op: this.ldx, modeFn: this.readAbsolute, mode: 'absolute' }, + 0xbe: { name: 'LDX', op: this.ldx, modeFn: this.readAbsoluteY, mode: 'absoluteY' }, - // LDY - 0xa0: ['LDY', c.ldy, c.readImmediate, modes.immediate, 2], - 0xa4: ['LDY', c.ldy, c.readZeroPage, modes.zeroPage, 3], - 0xb4: ['LDY', c.ldy, c.readZeroPageX, modes.zeroPageX, 4], - 0xac: ['LDY', c.ldy, c.readAbsolute, modes.absolute, 4], - 0xbc: ['LDY', c.ldy, c.readAbsoluteX, modes.absoluteX, 4], + // LDY + 0xa0: { name: 'LDY', op: this.ldy, modeFn: this.readImmediate, mode: 'immediate' }, + 0xa4: { name: 'LDY', op: this.ldy, modeFn: this.readZeroPage, mode: 'zeroPage' }, + 0xb4: { name: 'LDY', op: this.ldy, modeFn: this.readZeroPageX, mode: 'zeroPageX' }, + 0xac: { name: 'LDY', op: this.ldy, modeFn: this.readAbsolute, mode: 'absolute' }, + 0xbc: { name: 'LDY', op: this.ldy, modeFn: this.readAbsoluteX, mode: 'absoluteX' }, - // STA - 0x85: ['STA', c.sta, c.writeZeroPage, modes.zeroPage, 3], - 0x95: ['STA', c.sta, c.writeZeroPageX, modes.zeroPageX, 4], - 0x8d: ['STA', c.sta, c.writeAbsolute, modes.absolute, 4], - 0x9d: ['STA', c.sta, c.writeAbsoluteX, modes.absoluteX, 5], - 0x99: ['STA', c.sta, c.writeAbsoluteY, modes.absoluteY, 5], - 0x81: ['STA', c.sta, c.writeZeroPageXIndirect, modes.zeroPageXIndirect, 6], - 0x91: ['STA', c.sta, c.writeZeroPageIndirectY, modes.zeroPageIndirectY, 6], + // STA + 0x85: { name: 'STA', op: this.sta, modeFn: this.writeZeroPage, mode: 'zeroPage' }, + 0x95: { name: 'STA', op: this.sta, modeFn: this.writeZeroPageX, mode: 'zeroPageX' }, + 0x8d: { name: 'STA', op: this.sta, modeFn: this.writeAbsolute, mode: 'absolute' }, + 0x9d: { name: 'STA', op: this.sta, modeFn: this.writeAbsoluteX, mode: 'absoluteX' }, + 0x99: { name: 'STA', op: this.sta, modeFn: this.writeAbsoluteY, mode: 'absoluteY' }, + 0x81: { name: 'STA', op: this.sta, modeFn: this.writeZeroPageXIndirect, mode: 'zeroPageXIndirect' }, + 0x91: { name: 'STA', op: this.sta, modeFn: this.writeZeroPageIndirectY, mode: 'zeroPageIndirectY' }, - // STX - 0x86: ['STX', c.stx, c.writeZeroPage, modes.zeroPage, 3], - 0x96: ['STX', c.stx, c.writeZeroPageY, modes.zeroPageY, 4], - 0x8e: ['STX', c.stx, c.writeAbsolute, modes.absolute, 4], + // STX + 0x86: { name: 'STX', op: this.stx, modeFn: this.writeZeroPage, mode: 'zeroPage' }, + 0x96: { name: 'STX', op: this.stx, modeFn: this.writeZeroPageY, mode: 'zeroPageY' }, + 0x8e: { name: 'STX', op: this.stx, modeFn: this.writeAbsolute, mode: 'absolute' }, - // STY - 0x84: ['STY', c.sty, c.writeZeroPage, modes.zeroPage, 3], - 0x94: ['STY', c.sty, c.writeZeroPageX, modes.zeroPageX, 4], - 0x8c: ['STY', c.sty, c.writeAbsolute, modes.absolute, 4], + // STY + 0x84: { name: 'STY', op: this.sty, modeFn: this.writeZeroPage, mode: 'zeroPage' }, + 0x94: { name: 'STY', op: this.sty, modeFn: this.writeZeroPageX, mode: 'zeroPageX' }, + 0x8c: { name: 'STY', op: this.sty, modeFn: this.writeAbsolute, mode: 'absolute' }, - // ADC - 0x69: ['ADC', c.adc, c.readImmediate, modes.immediate, 2], - 0x65: ['ADC', c.adc, c.readZeroPage, modes.zeroPage, 3], - 0x75: ['ADC', c.adc, c.readZeroPageX, modes.zeroPageX, 4], - 0x6D: ['ADC', c.adc, c.readAbsolute, modes.absolute, 4], - 0x7D: ['ADC', c.adc, c.readAbsoluteX, modes.absoluteX, 4], - 0x79: ['ADC', c.adc, c.readAbsoluteY, modes.absoluteY, 4], - 0x61: ['ADC', c.adc, c.readZeroPageXIndirect, modes.zeroPageXIndirect, 6], - 0x71: ['ADC', c.adc, c.readZeroPageIndirectY, modes.zeroPageIndirectY, 5], + // ADC + 0x69: { name: 'ADC', op: this.adc, modeFn: this.readImmediate, mode: 'immediate' }, + 0x65: { name: 'ADC', op: this.adc, modeFn: this.readZeroPage, mode: 'zeroPage' }, + 0x75: { name: 'ADC', op: this.adc, modeFn: this.readZeroPageX, mode: 'zeroPageX' }, + 0x6D: { name: 'ADC', op: this.adc, modeFn: this.readAbsolute, mode: 'absolute' }, + 0x7D: { name: 'ADC', op: this.adc, modeFn: this.readAbsoluteX, mode: 'absoluteX' }, + 0x79: { name: 'ADC', op: this.adc, modeFn: this.readAbsoluteY, mode: 'absoluteY' }, + 0x61: { name: 'ADC', op: this.adc, modeFn: this.readZeroPageXIndirect, mode: 'zeroPageXIndirect' }, + 0x71: { name: 'ADC', op: this.adc, modeFn: this.readZeroPageIndirectY, mode: 'zeroPageIndirectY' }, - // SBC - 0xe9: ['SBC', c.sbc, c.readImmediate, modes.immediate, 2], - 0xe5: ['SBC', c.sbc, c.readZeroPage, modes.zeroPage, 3], - 0xf5: ['SBC', c.sbc, c.readZeroPageX, modes.zeroPageX, 4], - 0xeD: ['SBC', c.sbc, c.readAbsolute, modes.absolute, 4], - 0xfD: ['SBC', c.sbc, c.readAbsoluteX, modes.absoluteX, 4], - 0xf9: ['SBC', c.sbc, c.readAbsoluteY, modes.absoluteY, 4], - 0xe1: ['SBC', c.sbc, c.readZeroPageXIndirect, modes.zeroPageXIndirect, 6], - 0xf1: ['SBC', c.sbc, c.readZeroPageIndirectY, modes.zeroPageIndirectY, 5], + // SBC + 0xe9: { name: 'SBC', op: this.sbc, modeFn: this.readImmediate, mode: 'immediate' }, + 0xe5: { name: 'SBC', op: this.sbc, modeFn: this.readZeroPage, mode: 'zeroPage' }, + 0xf5: { name: 'SBC', op: this.sbc, modeFn: this.readZeroPageX, mode: 'zeroPageX' }, + 0xeD: { name: 'SBC', op: this.sbc, modeFn: this.readAbsolute, mode: 'absolute' }, + 0xfD: { name: 'SBC', op: this.sbc, modeFn: this.readAbsoluteX, mode: 'absoluteX' }, + 0xf9: { name: 'SBC', op: this.sbc, modeFn: this.readAbsoluteY, mode: 'absoluteY' }, + 0xe1: { name: 'SBC', op: this.sbc, modeFn: this.readZeroPageXIndirect, mode: 'zeroPageXIndirect' }, + 0xf1: { name: 'SBC', op: this.sbc, modeFn: this.readZeroPageIndirectY, mode: 'zeroPageIndirectY' }, - // INC - 0xe6: ['INC', c.inc, c.readAddrZeroPage, modes.zeroPage, 5], - 0xf6: ['INC', c.inc, c.readAddrZeroPageX, modes.zeroPageX, 6], - 0xee: ['INC', c.inc, c.readAddrAbsolute, modes.absolute, 6], - 0xfe: ['INC', c.inc, c.readAddrAbsoluteX, modes.absoluteX, 7], + // INC + 0xe6: { name: 'INC', op: this.inc, modeFn: this.readAddrZeroPage, mode: 'zeroPage' }, + 0xf6: { name: 'INC', op: this.inc, modeFn: this.readAddrZeroPageX, mode: 'zeroPageX' }, + 0xee: { name: 'INC', op: this.inc, modeFn: this.readAddrAbsolute, mode: 'absolute' }, + 0xfe: { name: 'INC', op: this.inc, modeFn: this.readAddrAbsoluteX, mode: 'absoluteX' }, - // INX - 0xe8: ['INX', c.inx, null, modes.implied, 2], + // INX + 0xe8: { name: 'INX', op: this.inx, modeFn: this.implied, mode: 'implied' }, - // INY - 0xc8: ['INY', c.iny, null, modes.implied, 2], + // INY + 0xc8: { name: 'INY', op: this.iny, modeFn: this.implied, mode: 'implied' }, - // DEC - 0xc6: ['DEC', c.dec, c.readAddrZeroPage, modes.zeroPage, 5], - 0xd6: ['DEC', c.dec, c.readAddrZeroPageX, modes.zeroPageX, 6], - 0xce: ['DEC', c.dec, c.readAddrAbsolute, modes.absolute, 6], - 0xde: ['DEC', c.dec, c.readAddrAbsoluteX, modes.absoluteX, 7], + // DEC + 0xc6: { name: 'DEC', op: this.dec, modeFn: this.readAddrZeroPage, mode: 'zeroPage' }, + 0xd6: { name: 'DEC', op: this.dec, modeFn: this.readAddrZeroPageX, mode: 'zeroPageX' }, + 0xce: { name: 'DEC', op: this.dec, modeFn: this.readAddrAbsolute, mode: 'absolute' }, + 0xde: { name: 'DEC', op: this.dec, modeFn: this.readAddrAbsoluteX, mode: 'absoluteX' }, - // DEX - 0xca: ['DEX', c.dex, null, modes.implied, 2], + // DEX + 0xca: { name: 'DEX', op: this.dex, modeFn: this.implied, mode: 'implied' }, - // DEY - 0x88: ['DEY', c.dey, null, modes.implied, 2], + // DEY + 0x88: { name: 'DEY', op: this.dey, modeFn: this.implied, mode: 'implied' }, - // ASL - 0x0A: ['ASL', c.aslA, null, modes.accumulator, 2], - 0x06: ['ASL', c.asl, c.readAddrZeroPage, modes.zeroPage, 5], - 0x16: ['ASL', c.asl, c.readAddrZeroPageX, modes.zeroPageX, 6], - 0x0E: ['ASL', c.asl, c.readAddrAbsolute, modes.absolute, 6], - 0x1E: ['ASL', c.asl, c.readAddrAbsoluteX, modes.absoluteX, 7], + // ASL + 0x0A: { name: 'ASL', op: this.aslA, modeFn: this.implied, mode: 'accumulator' }, + 0x06: { name: 'ASL', op: this.asl, modeFn: this.readAddrZeroPage, mode: 'zeroPage' }, + 0x16: { name: 'ASL', op: this.asl, modeFn: this.readAddrZeroPageX, mode: 'zeroPageX' }, + 0x0E: { name: 'ASL', op: this.asl, modeFn: this.readAddrAbsolute, mode: 'absolute' }, + 0x1E: { name: 'ASL', op: this.asl, modeFn: this.readAddrAbsoluteX, mode: 'absoluteX' }, - // LSR - 0x4A: ['LSR', c.lsrA, null, modes.accumulator, 2], - 0x46: ['LSR', c.lsr, c.readAddrZeroPage, modes.zeroPage, 5], - 0x56: ['LSR', c.lsr, c.readAddrZeroPageX, modes.zeroPageX, 6], - 0x4E: ['LSR', c.lsr, c.readAddrAbsolute, modes.absolute, 6], - 0x5E: ['LSR', c.lsr, c.readAddrAbsoluteX, modes.absoluteX, 7], + // LSR + 0x4A: { name: 'LSR', op: this.lsrA, modeFn: this.implied, mode: 'accumulator' }, + 0x46: { name: 'LSR', op: this.lsr, modeFn: this.readAddrZeroPage, mode: 'zeroPage' }, + 0x56: { name: 'LSR', op: this.lsr, modeFn: this.readAddrZeroPageX, mode: 'zeroPageX' }, + 0x4E: { name: 'LSR', op: this.lsr, modeFn: this.readAddrAbsolute, mode: 'absolute' }, + 0x5E: { name: 'LSR', op: this.lsr, modeFn: this.readAddrAbsoluteX, mode: 'absoluteX' }, - // ROL - 0x2A: ['ROL', c.rolA, null, modes.accumulator, 2], - 0x26: ['ROL', c.rol, c.readAddrZeroPage, modes.zeroPage, 5], - 0x36: ['ROL', c.rol, c.readAddrZeroPageX, modes.zeroPageX, 6], - 0x2E: ['ROL', c.rol, c.readAddrAbsolute, modes.absolute, 6], - 0x3E: ['ROL', c.rol, c.readAddrAbsoluteX, modes.absoluteX, 7], + // ROL + 0x2A: { name: 'ROL', op: this.rolA, modeFn: this.implied, mode: 'accumulator' }, + 0x26: { name: 'ROL', op: this.rol, modeFn: this.readAddrZeroPage, mode: 'zeroPage' }, + 0x36: { name: 'ROL', op: this.rol, modeFn: this.readAddrZeroPageX, mode: 'zeroPageX' }, + 0x2E: { name: 'ROL', op: this.rol, modeFn: this.readAddrAbsolute, mode: 'absolute' }, + 0x3E: { name: 'ROL', op: this.rol, modeFn: this.readAddrAbsoluteX, mode: 'absoluteX' }, - // ROR - 0x6A: ['ROR', c.rorA, null, modes.accumulator, 2], - 0x66: ['ROR', c.ror, c.readAddrZeroPage, modes.zeroPage, 5], - 0x76: ['ROR', c.ror, c.readAddrZeroPageX, modes.zeroPageX, 6], - 0x6E: ['ROR', c.ror, c.readAddrAbsolute, modes.absolute, 6], - 0x7E: ['ROR', c.ror, c.readAddrAbsoluteX, modes.absoluteX, 7], + // ROR + 0x6A: { name: 'ROR', op: this.rorA, modeFn: this.implied, mode: 'accumulator' }, + 0x66: { name: 'ROR', op: this.ror, modeFn: this.readAddrZeroPage, mode: 'zeroPage' }, + 0x76: { name: 'ROR', op: this.ror, modeFn: this.readAddrZeroPageX, mode: 'zeroPageX' }, + 0x6E: { name: 'ROR', op: this.ror, modeFn: this.readAddrAbsolute, mode: 'absolute' }, + 0x7E: { name: 'ROR', op: this.ror, modeFn: this.readAddrAbsoluteX, mode: 'absoluteX' }, - // AND - 0x29: ['AND', c.and, c.readImmediate, modes.immediate, 2], - 0x25: ['AND', c.and, c.readZeroPage, modes.zeroPage, 3], - 0x35: ['AND', c.and, c.readZeroPageX, modes.zeroPageX, 4], - 0x2D: ['AND', c.and, c.readAbsolute, modes.absolute, 4], - 0x3D: ['AND', c.and, c.readAbsoluteX, modes.absoluteX, 4], - 0x39: ['AND', c.and, c.readAbsoluteY, modes.absoluteY, 4], - 0x21: ['AND', c.and, c.readZeroPageXIndirect, modes.zeroPageXIndirect, 6], - 0x31: ['AND', c.and, c.readZeroPageIndirectY, modes.zeroPageIndirectY, 5], + // AND + 0x29: { name: 'AND', op: this.and, modeFn: this.readImmediate, mode: 'immediate' }, + 0x25: { name: 'AND', op: this.and, modeFn: this.readZeroPage, mode: 'zeroPage' }, + 0x35: { name: 'AND', op: this.and, modeFn: this.readZeroPageX, mode: 'zeroPageX' }, + 0x2D: { name: 'AND', op: this.and, modeFn: this.readAbsolute, mode: 'absolute' }, + 0x3D: { name: 'AND', op: this.and, modeFn: this.readAbsoluteX, mode: 'absoluteX' }, + 0x39: { name: 'AND', op: this.and, modeFn: this.readAbsoluteY, mode: 'absoluteY' }, + 0x21: { name: 'AND', op: this.and, modeFn: this.readZeroPageXIndirect, mode: 'zeroPageXIndirect' }, + 0x31: { name: 'AND', op: this.and, modeFn: this.readZeroPageIndirectY, mode: 'zeroPageIndirectY' }, - // ORA - 0x09: ['ORA', c.ora, c.readImmediate, modes.immediate, 2], - 0x05: ['ORA', c.ora, c.readZeroPage, modes.zeroPage, 3], - 0x15: ['ORA', c.ora, c.readZeroPageX, modes.zeroPageX, 4], - 0x0D: ['ORA', c.ora, c.readAbsolute, modes.absolute, 4], - 0x1D: ['ORA', c.ora, c.readAbsoluteX, modes.absoluteX, 4], - 0x19: ['ORA', c.ora, c.readAbsoluteY, modes.absoluteY, 4], - 0x01: ['ORA', c.ora, c.readZeroPageXIndirect, modes.zeroPageXIndirect, 6], - 0x11: ['ORA', c.ora, c.readZeroPageIndirectY, modes.zeroPageIndirectY, 5], + // ORA + 0x09: { name: 'ORA', op: this.ora, modeFn: this.readImmediate, mode: 'immediate' }, + 0x05: { name: 'ORA', op: this.ora, modeFn: this.readZeroPage, mode: 'zeroPage' }, + 0x15: { name: 'ORA', op: this.ora, modeFn: this.readZeroPageX, mode: 'zeroPageX' }, + 0x0D: { name: 'ORA', op: this.ora, modeFn: this.readAbsolute, mode: 'absolute' }, + 0x1D: { name: 'ORA', op: this.ora, modeFn: this.readAbsoluteX, mode: 'absoluteX' }, + 0x19: { name: 'ORA', op: this.ora, modeFn: this.readAbsoluteY, mode: 'absoluteY' }, + 0x01: { name: 'ORA', op: this.ora, modeFn: this.readZeroPageXIndirect, mode: 'zeroPageXIndirect' }, + 0x11: { name: 'ORA', op: this.ora, modeFn: this.readZeroPageIndirectY, mode: 'zeroPageIndirectY' }, - // EOR - 0x49: ['EOR', c.eor, c.readImmediate, modes.immediate, 2], - 0x45: ['EOR', c.eor, c.readZeroPage, modes.zeroPage, 3], - 0x55: ['EOR', c.eor, c.readZeroPageX, modes.zeroPageX, 4], - 0x4D: ['EOR', c.eor, c.readAbsolute, modes.absolute, 4], - 0x5D: ['EOR', c.eor, c.readAbsoluteX, modes.absoluteX, 4], - 0x59: ['EOR', c.eor, c.readAbsoluteY, modes.absoluteY, 4], - 0x41: ['EOR', c.eor, c.readZeroPageXIndirect, modes.zeroPageXIndirect, 6], - 0x51: ['EOR', c.eor, c.readZeroPageIndirectY, modes.zeroPageIndirectY, 5], + // EOR + 0x49: { name: 'EOR', op: this.eor, modeFn: this.readImmediate, mode: 'immediate' }, + 0x45: { name: 'EOR', op: this.eor, modeFn: this.readZeroPage, mode: 'zeroPage' }, + 0x55: { name: 'EOR', op: this.eor, modeFn: this.readZeroPageX, mode: 'zeroPageX' }, + 0x4D: { name: 'EOR', op: this.eor, modeFn: this.readAbsolute, mode: 'absolute' }, + 0x5D: { name: 'EOR', op: this.eor, modeFn: this.readAbsoluteX, mode: 'absoluteX' }, + 0x59: { name: 'EOR', op: this.eor, modeFn: this.readAbsoluteY, mode: 'absoluteY' }, + 0x41: { name: 'EOR', op: this.eor, modeFn: this.readZeroPageXIndirect, mode: 'zeroPageXIndirect' }, + 0x51: { name: 'EOR', op: this.eor, modeFn: this.readZeroPageIndirectY, mode: 'zeroPageIndirectY' }, - // CMP - 0xc9: ['CMP', c.cmp, c.readImmediate, modes.immediate, 2], - 0xc5: ['CMP', c.cmp, c.readZeroPage, modes.zeroPage, 3], - 0xd5: ['CMP', c.cmp, c.readZeroPageX, modes.zeroPageX, 4], - 0xcD: ['CMP', c.cmp, c.readAbsolute, modes.absolute, 4], - 0xdD: ['CMP', c.cmp, c.readAbsoluteX, modes.absoluteX, 4], - 0xd9: ['CMP', c.cmp, c.readAbsoluteY, modes.absoluteY, 4], - 0xc1: ['CMP', c.cmp, c.readZeroPageXIndirect, modes.zeroPageXIndirect, 6], - 0xd1: ['CMP', c.cmp, c.readZeroPageIndirectY, modes.zeroPageIndirectY, 5], + // CMP + 0xc9: { name: 'CMP', op: this.cmp, modeFn: this.readImmediate, mode: 'immediate' }, + 0xc5: { name: 'CMP', op: this.cmp, modeFn: this.readZeroPage, mode: 'zeroPage' }, + 0xd5: { name: 'CMP', op: this.cmp, modeFn: this.readZeroPageX, mode: 'zeroPageX' }, + 0xcD: { name: 'CMP', op: this.cmp, modeFn: this.readAbsolute, mode: 'absolute' }, + 0xdD: { name: 'CMP', op: this.cmp, modeFn: this.readAbsoluteX, mode: 'absoluteX' }, + 0xd9: { name: 'CMP', op: this.cmp, modeFn: this.readAbsoluteY, mode: 'absoluteY' }, + 0xc1: { name: 'CMP', op: this.cmp, modeFn: this.readZeroPageXIndirect, mode: 'zeroPageXIndirect' }, + 0xd1: { name: 'CMP', op: this.cmp, modeFn: this.readZeroPageIndirectY, mode: 'zeroPageIndirectY' }, - // CPX - 0xE0: ['CPX', c.cpx, c.readImmediate, modes.immediate, 2], - 0xE4: ['CPX', c.cpx, c.readZeroPage, modes.zeroPage, 3], - 0xEC: ['CPX', c.cpx, c.readAbsolute, modes.absolute, 4], + // CPX + 0xE0: { name: 'CPX', op: this.cpx, modeFn: this.readImmediate, mode: 'immediate' }, + 0xE4: { name: 'CPX', op: this.cpx, modeFn: this.readZeroPage, mode: 'zeroPage' }, + 0xEC: { name: 'CPX', op: this.cpx, modeFn: this.readAbsolute, mode: 'absolute' }, - // CPY - 0xC0: ['CPY', c.cpy, c.readImmediate, modes.immediate, 2], - 0xC4: ['CPY', c.cpy, c.readZeroPage, modes.zeroPage, 3], - 0xCC: ['CPY', c.cpy, c.readAbsolute, modes.absolute, 4], + // CPY + 0xC0: { name: 'CPY', op: this.cpy, modeFn: this.readImmediate, mode: 'immediate' }, + 0xC4: { name: 'CPY', op: this.cpy, modeFn: this.readZeroPage, mode: 'zeroPage' }, + 0xCC: { name: 'CPY', op: this.cpy, modeFn: this.readAbsolute, mode: 'absolute' }, - // BIT - 0x24: ['BIT', c.bit, c.readZeroPage, modes.zeroPage, 3], - 0x2C: ['BIT', c.bit, c.readAbsolute, modes.absolute, 4], + // BIT + 0x24: { name: 'BIT', op: this.bit, modeFn: this.readZeroPage, mode: 'zeroPage' }, + 0x2C: { name: 'BIT', op: this.bit, modeFn: this.readAbsolute, mode: 'absolute' }, - // BCC - 0x90: ['BCC', c.brc, flags.C, modes.relative, 2], + // BCC + 0x90: { name: 'BCC', op: this.brc, modeFn: flags.C, mode: 'relative' }, - // BCS - 0xB0: ['BCS', c.brs, flags.C, modes.relative, 2], + // BCS + 0xB0: { name: 'BCS', op: this.brs, modeFn: flags.C, mode: 'relative' }, - // BEQ - 0xF0: ['BEQ', c.brs, flags.Z, modes.relative, 2], + // BEQ + 0xF0: { name: 'BEQ', op: this.brs, modeFn: flags.Z, mode: 'relative' }, - // BMI - 0x30: ['BMI', c.brs, flags.N, modes.relative, 2], + // BMI + 0x30: { name: 'BMI', op: this.brs, modeFn: flags.N, mode: 'relative' }, - // BNE - 0xD0: ['BNE', c.brc, flags.Z, modes.relative, 2], + // BNE + 0xD0: { name: 'BNE', op: this.brc, modeFn: flags.Z, mode: 'relative' }, - // BPL - 0x10: ['BPL', c.brc, flags.N, modes.relative, 2], + // BPL + 0x10: { name: 'BPL', op: this.brc, modeFn: flags.N, mode: 'relative' }, - // BVC - 0x50: ['BVC', c.brc, flags.V, modes.relative, 2], + // BVC + 0x50: { name: 'BVC', op: this.brc, modeFn: flags.V, mode: 'relative' }, - // BVS - 0x70: ['BVS', c.brs, flags.V, modes.relative, 2], + // BVS + 0x70: { name: 'BVS', op: this.brs, modeFn: flags.V, mode: 'relative' }, - // TAX - 0xAA: ['TAX', c.tax, null, modes.implied, 2], + // TAX + 0xAA: { name: 'TAX', op: this.tax, modeFn: this.implied, mode: 'implied' }, - // TXA - 0x8A: ['TXA', c.txa, null, modes.implied, 2], + // TXA + 0x8A: { name: 'TXA', op: this.txa, modeFn: this.implied, mode: 'implied' }, - // TAY - 0xA8: ['TAY', c.tay, null, modes.implied, 2], + // TAY + 0xA8: { name: 'TAY', op: this.tay, modeFn: this.implied, mode: 'implied' }, - // TYA - 0x98: ['TYA', c.tya, null, modes.implied, 2], + // TYA + 0x98: { name: 'TYA', op: this.tya, modeFn: this.implied, mode: 'implied' }, - // TSX - 0xBA: ['TSX', c.tsx, null, modes.implied, 2], + // TSX + 0xBA: { name: 'TSX', op: this.tsx, modeFn: this.implied, mode: 'implied' }, - // TXS - 0x9A: ['TXS', c.txs, null, modes.implied, 2], + // TXS + 0x9A: { name: 'TXS', op: this.txs, modeFn: this.implied, mode: 'implied' }, - // PHA - 0x48: ['PHA', c.pha, null, modes.implied, 3], + // PHA + 0x48: { name: 'PHA', op: this.pha, modeFn: this.implied, mode: 'implied' }, - // PLA - 0x68: ['PLA', c.pla, null, modes.implied, 4], + // PLA + 0x68: { name: 'PLA', op: this.pla, modeFn: this.implied, mode: 'implied' }, - // PHP - 0x08: ['PHP', c.php, null, modes.implied, 3], + // PHP + 0x08: { name: 'PHP', op: this.php, modeFn: this.implied, mode: 'implied' }, - // PLP - 0x28: ['PLP', c.plp, null, modes.implied, 4], + // PLP + 0x28: { name: 'PLP', op: this.plp, modeFn: this.implied, mode: 'implied' }, - // JMP - 0x4C: [ - 'JMP', c.jmp, c.readAddrAbsolute, modes.absolute, 3 - ], - 0x6C: [ - 'JMP', c.jmp, c.readAddrAbsoluteIndirectBug, modes.absoluteIndirect, 5 - ], - // JSR - 0x20: ['JSR', c.jsr, c.readAddrAbsolute, modes.absolute, 6], + // JMP + 0x4C: { + name: 'JMP', op: this.jmp, modeFn: this.readAddrAbsolute, mode: 'absolute' + }, + 0x6C: { + name: 'JMP', op: this.jmp, modeFn: this.readAddrAbsoluteIndirectBug, mode: 'absoluteIndirect' + }, + // JSR + 0x20: { name: 'JSR', op: this.jsr, modeFn: this.readAddrAbsolute, mode: 'absolute' }, - // RTS - 0x60: ['RTS', c.rts, null, modes.implied, 6], + // RTS + 0x60: { name: 'RTS', op: this.rts, modeFn: this.implied, mode: 'implied' }, - // RTI - 0x40: ['RTI', c.rti, null, modes.implied, 6], + // RTI + 0x40: { name: 'RTI', op: this.rti, modeFn: this.implied, mode: 'implied' }, - // SEC - 0x38: ['SEC', c.set, flags.C, modes.implied, 2], + // SEC + 0x38: { name: 'SEC', op: this.set, modeFn: flags.C, mode: 'implied' }, - // SED - 0xF8: ['SED', c.set, flags.D, modes.implied, 2], + // SED + 0xF8: { name: 'SED', op: this.set, modeFn: flags.D, mode: 'implied' }, - // SEI - 0x78: ['SEI', c.set, flags.I, modes.implied, 2], + // SEI + 0x78: { name: 'SEI', op: this.set, modeFn: flags.I, mode: 'implied' }, - // CLC - 0x18: ['CLC', c.clr, flags.C, modes.implied, 2], + // CLC + 0x18: { name: 'CLC', op: this.clr, modeFn: flags.C, mode: 'implied' }, - // CLD - 0xD8: ['CLD', c.clr, flags.D, modes.implied, 2], + // CLD + 0xD8: { name: 'CLD', op: this.clr, modeFn: flags.D, mode: 'implied' }, - // CLI - 0x58: ['CLI', c.clr, flags.I, modes.implied, 2], + // CLI + 0x58: { name: 'CLI', op: this.clr, modeFn: flags.I, mode: 'implied' }, - // CLV - 0xB8: ['CLV', c.clr, flags.V, modes.implied, 2], + // CLV + 0xB8: { name: 'CLV', op: this.clr, modeFn: flags.V, mode: 'implied' }, - // NOP - 0xea: ['NOP', c.nop, c.readImplied, modes.implied, 2], + // NOP + 0xea: { name: 'NOP', op: this.nop, modeFn: this.implied, mode: 'implied' }, - // BRK - 0x00: ['BRK', c.brk, c.readImmediate, modes.immediate, 7] -}; + // BRK + 0x00: { name: 'BRK', op: this.brk, modeFn: this.readImmediate, mode: 'immediate' } + }; /* 65C02 Instructions */ -const OPS_65C02: Instructions = { - // INC / DEC A - 0x1A: ['INC', c.incA, null, modes.accumulator, 2], - 0x3A: ['DEC', c.decA, null, modes.accumulator, 2], + OPS_65C02: Instructions = { + // INC / DEC A + 0x1A: { name: 'INC', op: this.incA, modeFn: this.implied, mode: 'accumulator' }, + 0x3A: { name: 'DEC', op: this.decA, modeFn: this.implied, mode: 'accumulator' }, - // Indirect Zero Page for the masses - 0x12: ['ORA', c.ora, c.readZeroPageIndirect, modes.zeroPageIndirect, 5], - 0x32: ['AND', c.and, c.readZeroPageIndirect, modes.zeroPageIndirect, 5], - 0x52: ['EOR', c.eor, c.readZeroPageIndirect, modes.zeroPageIndirect, 5], - 0x72: ['ADC', c.adc, c.readZeroPageIndirect, modes.zeroPageIndirect, 5], - 0x92: ['STA', c.sta, c.writeZeroPageIndirect, modes.zeroPageIndirect, 5], - 0xB2: ['LDA', c.lda, c.readZeroPageIndirect, modes.zeroPageIndirect, 5], - 0xD2: ['CMP', c.cmp, c.readZeroPageIndirect, modes.zeroPageIndirect, 5], - 0xF2: ['SBC', c.sbc, c.readZeroPageIndirect, modes.zeroPageIndirect, 5], + // Indirect Zero Page for the masses + 0x12: { name: 'ORA', op: this.ora, modeFn: this.readZeroPageIndirect, mode: 'zeroPageIndirect' }, + 0x32: { name: 'AND', op: this.and, modeFn: this.readZeroPageIndirect, mode: 'zeroPageIndirect' }, + 0x52: { name: 'EOR', op: this.eor, modeFn: this.readZeroPageIndirect, mode: 'zeroPageIndirect' }, + 0x72: { name: 'ADC', op: this.adc, modeFn: this.readZeroPageIndirect, mode: 'zeroPageIndirect' }, + 0x92: { name: 'STA', op: this.sta, modeFn: this.writeZeroPageIndirect, mode: 'zeroPageIndirect' }, + 0xB2: { name: 'LDA', op: this.lda, modeFn: this.readZeroPageIndirect, mode: 'zeroPageIndirect' }, + 0xD2: { name: 'CMP', op: this.cmp, modeFn: this.readZeroPageIndirect, mode: 'zeroPageIndirect' }, + 0xF2: { name: 'SBC', op: this.sbc, modeFn: this.readZeroPageIndirect, mode: 'zeroPageIndirect' }, - // Better BIT - 0x34: ['BIT', c.bit, c.readZeroPageX, modes.zeroPageX, 4], - 0x3C: ['BIT', c.bit, c.readAbsoluteX, modes.absoluteX, 4], - 0x89: ['BIT', c.bitI, c.readImmediate, modes.immediate, 2], + // Better BIT + 0x34: { name: 'BIT', op: this.bit, modeFn: this.readZeroPageX, mode: 'zeroPageX' }, + 0x3C: { name: 'BIT', op: this.bit, modeFn: this.readAbsoluteX, mode: 'absoluteX' }, + 0x89: { name: 'BIT', op: this.bitI, modeFn: this.readImmediate, mode: 'immediate' }, - // JMP absolute indirect indexed - 0x6C: [ - 'JMP', c.jmp, c.readAddrAbsoluteIndirect, modes.absoluteIndirect, 6 - ], - 0x7C: [ - 'JMP', c.jmp, c.readAddrAbsoluteXIndirect, modes.absoluteXIndirect, 6 - ], + // JMP absolute indirect indexed + 0x6C: { + name: 'JMP', op: this.jmp, modeFn: this.readAddrAbsoluteIndirect, mode: 'absoluteIndirect' + }, + 0x7C: { + name: 'JMP', op: this.jmp, modeFn: this.readAddrAbsoluteXIndirect, mode: 'absoluteXIndirect' + }, - // BBR/BBS - 0x0F: ['BBR0', c.bbr, 0, modes.zeroPage_relative, 5], - 0x1F: ['BBR1', c.bbr, 1, modes.zeroPage_relative, 5], - 0x2F: ['BBR2', c.bbr, 2, modes.zeroPage_relative, 5], - 0x3F: ['BBR3', c.bbr, 3, modes.zeroPage_relative, 5], - 0x4F: ['BBR4', c.bbr, 4, modes.zeroPage_relative, 5], - 0x5F: ['BBR5', c.bbr, 5, modes.zeroPage_relative, 5], - 0x6F: ['BBR6', c.bbr, 6, modes.zeroPage_relative, 5], - 0x7F: ['BBR7', c.bbr, 7, modes.zeroPage_relative, 5], + // BBR/BBS + 0x0F: { name: 'BBR0', op: this.bbr, modeFn: 0, mode: 'zeroPage_relative' }, + 0x1F: { name: 'BBR1', op: this.bbr, modeFn: 1, mode: 'zeroPage_relative' }, + 0x2F: { name: 'BBR2', op: this.bbr, modeFn: 2, mode: 'zeroPage_relative' }, + 0x3F: { name: 'BBR3', op: this.bbr, modeFn: 3, mode: 'zeroPage_relative' }, + 0x4F: { name: 'BBR4', op: this.bbr, modeFn: 4, mode: 'zeroPage_relative' }, + 0x5F: { name: 'BBR5', op: this.bbr, modeFn: 5, mode: 'zeroPage_relative' }, + 0x6F: { name: 'BBR6', op: this.bbr, modeFn: 6, mode: 'zeroPage_relative' }, + 0x7F: { name: 'BBR7', op: this.bbr, modeFn: 7, mode: 'zeroPage_relative' }, - 0x8F: ['BBS0', c.bbs, 0, modes.zeroPage_relative, 5], - 0x9F: ['BBS1', c.bbs, 1, modes.zeroPage_relative, 5], - 0xAF: ['BBS2', c.bbs, 2, modes.zeroPage_relative, 5], - 0xBF: ['BBS3', c.bbs, 3, modes.zeroPage_relative, 5], - 0xCF: ['BBS4', c.bbs, 4, modes.zeroPage_relative, 5], - 0xDF: ['BBS5', c.bbs, 5, modes.zeroPage_relative, 5], - 0xEF: ['BBS6', c.bbs, 6, modes.zeroPage_relative, 5], - 0xFF: ['BBS7', c.bbs, 7, modes.zeroPage_relative, 5], + 0x8F: { name: 'BBS0', op: this.bbs, modeFn: 0, mode: 'zeroPage_relative' }, + 0x9F: { name: 'BBS1', op: this.bbs, modeFn: 1, mode: 'zeroPage_relative' }, + 0xAF: { name: 'BBS2', op: this.bbs, modeFn: 2, mode: 'zeroPage_relative' }, + 0xBF: { name: 'BBS3', op: this.bbs, modeFn: 3, mode: 'zeroPage_relative' }, + 0xCF: { name: 'BBS4', op: this.bbs, modeFn: 4, mode: 'zeroPage_relative' }, + 0xDF: { name: 'BBS5', op: this.bbs, modeFn: 5, mode: 'zeroPage_relative' }, + 0xEF: { name: 'BBS6', op: this.bbs, modeFn: 6, mode: 'zeroPage_relative' }, + 0xFF: { name: 'BBS7', op: this.bbs, modeFn: 7, mode: 'zeroPage_relative' }, - // BRA - 0x80: ['BRA', c.brc, 0, modes.relative, 2], + // BRA + 0x80: { name: 'BRA', op: this.brc, modeFn: 0, mode: 'relative' }, - // NOP - 0x02: ['NOP', c.nop, c.readImmediate, modes.immediate, 2], - 0x22: ['NOP', c.nop, c.readImmediate, modes.immediate, 2], - 0x42: ['NOP', c.nop, c.readImmediate, modes.immediate, 2], - 0x44: ['NOP', c.nop, c.readImmediate, modes.immediate, 3], - 0x54: ['NOP', c.nop, c.readImmediate, modes.immediate, 4], - 0x62: ['NOP', c.nop, c.readImmediate, modes.immediate, 2], - 0x82: ['NOP', c.nop, c.readImmediate, modes.immediate, 2], - 0xC2: ['NOP', c.nop, c.readImmediate, modes.immediate, 2], - 0xD4: ['NOP', c.nop, c.readImmediate, modes.immediate, 4], - 0xE2: ['NOP', c.nop, c.readImmediate, modes.immediate, 2], - 0xF4: ['NOP', c.nop, c.readImmediate, modes.immediate, 4], - 0x5C: ['NOP', c.nop, c.readAbsolute, modes.absolute, 8], - 0xDC: ['NOP', c.nop, c.readAbsolute, modes.absolute, 4], - 0xFC: ['NOP', c.nop, c.readAbsolute, modes.absolute, 4], + // NOP + 0x02: { name: 'NOP', op: this.nop, modeFn: this.readImmediate, mode: 'immediate' }, + 0x22: { name: 'NOP', op: this.nop, modeFn: this.readImmediate, mode: 'immediate' }, + 0x42: { name: 'NOP', op: this.nop, modeFn: this.readImmediate, mode: 'immediate' }, + 0x44: { name: 'NOP', op: this.nop, modeFn: this.readImmediate, mode: 'immediate' }, + 0x54: { name: 'NOP', op: this.nop, modeFn: this.readImmediate, mode: 'immediate' }, + 0x62: { name: 'NOP', op: this.nop, modeFn: this.readImmediate, mode: 'immediate' }, + 0x82: { name: 'NOP', op: this.nop, modeFn: this.readImmediate, mode: 'immediate' }, + 0xC2: { name: 'NOP', op: this.nop, modeFn: this.readImmediate, mode: 'immediate' }, + 0xD4: { name: 'NOP', op: this.nop, modeFn: this.readImmediate, mode: 'immediate' }, + 0xE2: { name: 'NOP', op: this.nop, modeFn: this.readImmediate, mode: 'immediate' }, + 0xF4: { name: 'NOP', op: this.nop, modeFn: this.readImmediate, mode: 'immediate' }, + 0x5C: { name: 'NOP', op: this.nop, modeFn: this.readAbsolute, mode: 'absolute' }, + 0xDC: { name: 'NOP', op: this.nop, modeFn: this.readAbsolute, mode: 'absolute' }, + 0xFC: { name: 'NOP', op: this.nop, modeFn: this.readAbsolute, mode: 'absolute' }, - // PHX - 0xDA: ['PHX', c.phx, null, modes.implied, 3], + // PHX + 0xDA: { name: 'PHX', op: this.phx, modeFn: this.implied, mode: 'implied' }, - // PHY - 0x5A: ['PHY', c.phy, null, modes.implied, 3], + // PHY + 0x5A: { name: 'PHY', op: this.phy, modeFn: this.implied, mode: 'implied' }, - // PLX - 0xFA: ['PLX', c.plx, null, modes.implied, 4], + // PLX + 0xFA: { name: 'PLX', op: this.plx, modeFn: this.implied, mode: 'implied' }, - // PLY - 0x7A: ['PLY', c.ply, null, modes.implied, 4], + // PLY + 0x7A: { name: 'PLY', op: this.ply, modeFn: this.implied, mode: 'implied' }, - // RMB/SMB + // RMB/SMB - 0x07: ['RMB0', c.rmb, 0, modes.zeroPage, 5], - 0x17: ['RMB1', c.rmb, 1, modes.zeroPage, 5], - 0x27: ['RMB2', c.rmb, 2, modes.zeroPage, 5], - 0x37: ['RMB3', c.rmb, 3, modes.zeroPage, 5], - 0x47: ['RMB4', c.rmb, 4, modes.zeroPage, 5], - 0x57: ['RMB5', c.rmb, 5, modes.zeroPage, 5], - 0x67: ['RMB6', c.rmb, 6, modes.zeroPage, 5], - 0x77: ['RMB7', c.rmb, 7, modes.zeroPage, 5], + 0x07: { name: 'RMB0', op: this.rmb, modeFn: 0, mode: 'zeroPage' }, + 0x17: { name: 'RMB1', op: this.rmb, modeFn: 1, mode: 'zeroPage' }, + 0x27: { name: 'RMB2', op: this.rmb, modeFn: 2, mode: 'zeroPage' }, + 0x37: { name: 'RMB3', op: this.rmb, modeFn: 3, mode: 'zeroPage' }, + 0x47: { name: 'RMB4', op: this.rmb, modeFn: 4, mode: 'zeroPage' }, + 0x57: { name: 'RMB5', op: this.rmb, modeFn: 5, mode: 'zeroPage' }, + 0x67: { name: 'RMB6', op: this.rmb, modeFn: 6, mode: 'zeroPage' }, + 0x77: { name: 'RMB7', op: this.rmb, modeFn: 7, mode: 'zeroPage' }, - 0x87: ['SMB0', c.smb, 0, modes.zeroPage, 5], - 0x97: ['SMB1', c.smb, 1, modes.zeroPage, 5], - 0xA7: ['SMB2', c.smb, 2, modes.zeroPage, 5], - 0xB7: ['SMB3', c.smb, 3, modes.zeroPage, 5], - 0xC7: ['SMB4', c.smb, 4, modes.zeroPage, 5], - 0xD7: ['SMB5', c.smb, 5, modes.zeroPage, 5], - 0xE7: ['SMB6', c.smb, 6, modes.zeroPage, 5], - 0xF7: ['SMB7', c.smb, 7, modes.zeroPage, 5], + 0x87: { name: 'SMB0', op: this.smb, modeFn: 0, mode: 'zeroPage' }, + 0x97: { name: 'SMB1', op: this.smb, modeFn: 1, mode: 'zeroPage' }, + 0xA7: { name: 'SMB2', op: this.smb, modeFn: 2, mode: 'zeroPage' }, + 0xB7: { name: 'SMB3', op: this.smb, modeFn: 3, mode: 'zeroPage' }, + 0xC7: { name: 'SMB4', op: this.smb, modeFn: 4, mode: 'zeroPage' }, + 0xD7: { name: 'SMB5', op: this.smb, modeFn: 5, mode: 'zeroPage' }, + 0xE7: { name: 'SMB6', op: this.smb, modeFn: 6, mode: 'zeroPage' }, + 0xF7: { name: 'SMB7', op: this.smb, modeFn: 7, mode: 'zeroPage' }, - // STZ - 0x64: ['STZ', c.stz, c.writeZeroPage, modes.zeroPage, 3], - 0x74: ['STZ', c.stz, c.writeZeroPageX, modes.zeroPageX, 4], - 0x9C: ['STZ', c.stz, c.writeAbsolute, modes.absolute, 4], - 0x9E: ['STZ', c.stz, c.writeAbsoluteX, modes.absoluteX, 5], + // STZ + 0x64: { name: 'STZ', op: this.stz, modeFn: this.writeZeroPage, mode: 'zeroPage' }, + 0x74: { name: 'STZ', op: this.stz, modeFn: this.writeZeroPageX, mode: 'zeroPageX' }, + 0x9C: { name: 'STZ', op: this.stz, modeFn: this.writeAbsolute, mode: 'absolute' }, + 0x9E: { name: 'STZ', op: this.stz, modeFn: this.writeAbsoluteX, mode: 'absoluteX' }, - // TRB - 0x14: ['TRB', c.trb, c.readAddrZeroPage, modes.zeroPage, 5], - 0x1C: ['TRB', c.trb, c.readAddrAbsolute, modes.absolute, 6], + // TRB + 0x14: { name: 'TRB', op: this.trb, modeFn: this.readAddrZeroPage, mode: 'zeroPage' }, + 0x1C: { name: 'TRB', op: this.trb, modeFn: this.readAddrAbsolute, mode: 'absolute' }, - // TSB - 0x04: ['TSB', c.tsb, c.readAddrZeroPage, modes.zeroPage, 5], - 0x0C: ['TSB', c.tsb, c.readAddrAbsolute, modes.absolute, 6] + // TSB + 0x04: { name: 'TSB', op: this.tsb, modeFn: this.readAddrZeroPage, mode: 'zeroPage' }, + 0x0C: { name: 'TSB', op: this.tsb, modeFn: this.readAddrAbsolute, mode: 'absolute' } + } }; diff --git a/js/symbols.js b/js/symbols.js index 805f843..d6701c1 100644 --- a/js/symbols.js +++ b/js/symbols.js @@ -1,4 +1,4 @@ -SYMBOLS = { +const SYMBOLS = { /* 0x00: 'GOWARM', 0x03: 'GOSTROUT', diff --git a/js/ui/printer.js b/js/ui/printer.js index 44957ee..42457c8 100644 --- a/js/ui/printer.js +++ b/js/ui/printer.js @@ -9,7 +9,7 @@ * implied warranty. */ - /** +/** * Printer UI. The "paper" is bound to the element selected by the input. * * Every line that is output to the printer is added as a
to the paper. @@ -69,7 +69,7 @@ export default function Printer(el) { clear: function() { _lineBuffer = ''; - paper.innerHTML = ""; + paper.innerHTML = ''; newLine(); _raw = new Uint8Array(1024); _rawLen = 0; diff --git a/test/cpu.spec.js b/test/cpu.spec.ts similarity index 94% rename from test/cpu.spec.js rename to test/cpu.spec.ts index ac1afd2..38061f6 100644 --- a/test/cpu.spec.js +++ b/test/cpu.spec.ts @@ -6,9 +6,9 @@ import Test65C02 from './roms/65C02test'; import { toHex } from '../js/util'; describe('CPU', function () { - var cpu; - var lastPC = 0; - var done = false; + let cpu: CPU6502; + let lastPC = 0; + let done = false; function traceCB() { var pc = cpu.getPC(); diff --git a/test/roms/6502test.js b/test/roms/6502test.js deleted file mode 100644 index 1fdeffd..0000000 --- a/test/roms/6502test.js +++ /dev/null @@ -1,23 +0,0 @@ -// From https://github.com/Klaus2m5/6502_65C02_functional_tests - -import fs from 'fs'; -import path from 'path'; - -export default function Test6502() { - var data = fs.readFileSync(path.join(__dirname, '6502_functional_test.bin')); - - return { - start: function() { - return 0x00; - }, - end: function() { - return 0xff; - }, - read: function(page, off) { - return data[page << 8 | off]; - }, - write: function(page, off, val) { - data[page << 8 | off] = val; - } - }; -} diff --git a/test/roms/6502test.ts b/test/roms/6502test.ts new file mode 100644 index 0000000..ec9cb13 --- /dev/null +++ b/test/roms/6502test.ts @@ -0,0 +1,27 @@ +// From https://github.com/Klaus2m5/6502_65C02_functional_tests + +import fs from 'fs'; +import path from 'path'; +import { PageHandler } from '../../js/cpu6502' +import { byte } from '../../js/types' + +const data = fs.readFileSync(path.join(__dirname, '6502_functional_test.bin')); +export default class Test6502 implements PageHandler { + private data: Buffer + + start = () => { + return 0x00; + } + + end = () => { + return 0xff; + } + + read = (page: byte, off: byte) => { + return data[page << 8 | off]; + } + + write = (page: byte, off: byte, val: byte) => { + data[page << 8 | off] = val; + } +} diff --git a/test/roms/65C02test.js b/test/roms/65C02test.js deleted file mode 100644 index b40f0e8..0000000 --- a/test/roms/65C02test.js +++ /dev/null @@ -1,23 +0,0 @@ -// From https://github.com/Klaus2m5/6502_65C02_functional_tests - -import fs from 'fs'; -import path from 'path'; - -export default function Test65C02() { - var data = fs.readFileSync(path.join(__dirname, '65C02_extended_opcodes_test.bin')); - - return { - start: function() { - return 0x00; - }, - end: function() { - return 0xff; - }, - read: function(page, off) { - return data[page << 8 | off]; - }, - write: function(page, off, val) { - data[page << 8 | off] = val; - } - }; -} diff --git a/test/roms/65C02test.ts b/test/roms/65C02test.ts new file mode 100644 index 0000000..5a8f1bf --- /dev/null +++ b/test/roms/65C02test.ts @@ -0,0 +1,31 @@ +// From https://github.com/Klaus2m5/6502_65C02_functional_tests + +import fs from 'fs'; +import path from 'path'; +import { PageHandler } from '../../js/cpu6502' +import { byte } from '../../js/types' + +const data = fs.readFileSync(path.join(__dirname, '65C02_extended_opcodes_test.bin')); + +export default class Test65C02 implements PageHandler { + private data: Buffer + + constructor() { + } + + start = function() { + return 0x00; + } + + end = function() { + return 0xff; + } + + read = function(page: byte, off: byte) { + return data[page << 8 | off]; + } + + write = function(page: byte, off: byte, val: byte) { + data[page << 8 | off] = val; + } +}