diff --git a/js/canvas1.ts b/js/canvas1.ts index 37d5f27..4ddcd90 100644 --- a/js/canvas1.ts +++ b/js/canvas1.ts @@ -22,8 +22,8 @@ import type { byte } from './types'; */ export class TextPage { - _page: ImageData; - _context: CanvasRenderingContext2D; + _page: ImageData | undefined; + _context: CanvasRenderingContext2D | undefined; _buffer: byte[][] = []; _greenMode = false; @@ -98,6 +98,9 @@ export class TextPage { this.refresh(); } writeAt(row: byte, col: byte, val: byte): void { + if (!this._page) { + return; + } this._buffer[row][col] = val; const data = this._page.data; let color; @@ -169,6 +172,9 @@ export class TextPage { this.refresh(); } blit() { + if (!this._page || !this._context) { + return; + } if (this._dirty) { this._context.putImageData( this._page, diff --git a/js/cpu6502.ts b/js/cpu6502.ts index 484138d..c6c66a5 100644 --- a/js/cpu6502.ts +++ b/js/cpu6502.ts @@ -147,23 +147,13 @@ type WriteFn = (val: byte) => void; type ReadAddrFn = (opts?: Opts) => word; type ImpliedFn = () => void; -interface Instruction { +interface Instruction { name: string; mode: Mode; - op: (fn: T) => void; - modeFn: T; + fn: () => void; } -type StrictInstruction = - | Instruction - | Instruction - | Instruction - | Instruction - | Instruction - | Instruction - | Instruction; - -type Instructions = Record; +type Instructions = Record; type callback = (cpu: CPU6502) => boolean | void; @@ -191,7 +181,7 @@ export default class CPU6502 { private sp: byte = 0xff; /** Current instruction */ - private op: Instruction; + private op: Instruction | undefined; /** Last accessed memory address */ private addr: word = 0; @@ -303,7 +293,7 @@ export default class CPU6502 { const bin = c & 0xff; n = bin >> 7; z = !bin; - if (this.op.mode === 'immediate') { + if (this.op?.mode === 'immediate') { if (this.flavor === FLAVOR_WDC_65C02) { this.readByte(sub ? 0xb8 : 0x7f); } else { @@ -1391,14 +1381,13 @@ export default class CPU6502 { this.stop = true; }; - private unknown(b: byte) { - let unk: StrictInstruction; + private unknown(b: byte): Instruction { + let unk: Instruction; if (this.is65C02) { // Default behavior is a 1 cycle NOP unk = { name: 'NOP', - op: this.nop, - modeFn: this.readNopImplied, + fn: () => this.nop(this.readNopImplied), mode: 'implied', }; } else { @@ -1412,7 +1401,7 @@ export default class CPU6502 { this.sync = true; this.op = this.opary[this.readBytePC()]; this.sync = false; - this.op.op(this.op.modeFn); + this.op.fn(); cb?.(this); } @@ -1422,7 +1411,7 @@ export default class CPU6502 { this.sync = true; this.op = this.opary[this.readBytePC()]; this.sync = false; - this.op.op(this.op.modeFn); + this.op.fn(); if (cb?.(this)) { return; @@ -1437,7 +1426,7 @@ export default class CPU6502 { this.sync = true; this.op = this.opary[this.readBytePC()]; this.sync = false; - this.op.op(this.op.modeFn); + this.op.fn(); } } @@ -1448,7 +1437,7 @@ export default class CPU6502 { this.sync = true; this.op = this.opary[this.readBytePC()]; this.sync = false; - this.op.op(this.op.modeFn); + this.op.fn(); if (cb?.(this)) { return; @@ -1612,857 +1601,770 @@ export default class CPU6502 { // LDA 0xa9: { name: 'LDA', - op: this.lda, - modeFn: this.readImmediate, + fn: () => this.lda(this.readImmediate), mode: 'immediate', }, 0xa5: { name: 'LDA', - op: this.lda, - modeFn: this.readZeroPage, + fn: () => this.lda(this.readZeroPage), mode: 'zeroPage', }, 0xb5: { name: 'LDA', - op: this.lda, - modeFn: this.readZeroPageX, + fn: () => this.lda(this.readZeroPageX), mode: 'zeroPageX', }, 0xad: { name: 'LDA', - op: this.lda, - modeFn: this.readAbsolute, + fn: () => this.lda(this.readAbsolute), mode: 'absolute', }, 0xbd: { name: 'LDA', - op: this.lda, - modeFn: this.readAbsoluteX, + fn: () => this.lda(this.readAbsoluteX), mode: 'absoluteX', }, 0xb9: { name: 'LDA', - op: this.lda, - modeFn: this.readAbsoluteY, + fn: () => this.lda(this.readAbsoluteY), mode: 'absoluteY', }, 0xa1: { name: 'LDA', - op: this.lda, - modeFn: this.readZeroPageXIndirect, + fn: () => this.lda(this.readZeroPageXIndirect), mode: 'zeroPageXIndirect', }, 0xb1: { name: 'LDA', - op: this.lda, - modeFn: this.readZeroPageIndirectY, + fn: () => this.lda(this.readZeroPageIndirectY), mode: 'zeroPageIndirectY', }, // LDX 0xa2: { name: 'LDX', - op: this.ldx, - modeFn: this.readImmediate, + fn: () => this.ldx(this.readImmediate), mode: 'immediate', }, 0xa6: { name: 'LDX', - op: this.ldx, - modeFn: this.readZeroPage, + fn: () => this.ldx(this.readZeroPage), mode: 'zeroPage', }, 0xb6: { name: 'LDX', - op: this.ldx, - modeFn: this.readZeroPageY, + fn: () => this.ldx(this.readZeroPageY), mode: 'zeroPageY', }, 0xae: { name: 'LDX', - op: this.ldx, - modeFn: this.readAbsolute, + fn: () => this.ldx(this.readAbsolute), mode: 'absolute', }, 0xbe: { name: 'LDX', - op: this.ldx, - modeFn: this.readAbsoluteY, + fn: () => this.ldx(this.readAbsoluteY), mode: 'absoluteY', }, // LDY 0xa0: { name: 'LDY', - op: this.ldy, - modeFn: this.readImmediate, + fn: () => this.ldy(this.readImmediate), mode: 'immediate', }, 0xa4: { name: 'LDY', - op: this.ldy, - modeFn: this.readZeroPage, + fn: () => this.ldy(this.readZeroPage), mode: 'zeroPage', }, 0xb4: { name: 'LDY', - op: this.ldy, - modeFn: this.readZeroPageX, + fn: () => this.ldy(this.readZeroPageX), mode: 'zeroPageX', }, 0xac: { name: 'LDY', - op: this.ldy, - modeFn: this.readAbsolute, + fn: () => this.ldy(this.readAbsolute), mode: 'absolute', }, 0xbc: { name: 'LDY', - op: this.ldy, - modeFn: this.readAbsoluteX, + fn: () => this.ldy(this.readAbsoluteX), mode: 'absoluteX', }, // STA 0x85: { name: 'STA', - op: this.sta, - modeFn: this.writeZeroPage, + fn: () => this.sta(this.writeZeroPage), mode: 'zeroPage', }, 0x95: { name: 'STA', - op: this.sta, - modeFn: this.writeZeroPageX, + fn: () => this.sta(this.writeZeroPageX), mode: 'zeroPageX', }, 0x8d: { name: 'STA', - op: this.sta, - modeFn: this.writeAbsolute, + fn: () => this.sta(this.writeAbsolute), mode: 'absolute', }, 0x9d: { name: 'STA', - op: this.sta, - modeFn: this.writeAbsoluteX, + fn: () => this.sta(this.writeAbsoluteX), mode: 'absoluteX', }, 0x99: { name: 'STA', - op: this.sta, - modeFn: this.writeAbsoluteY, + fn: () => this.sta(this.writeAbsoluteY), mode: 'absoluteY', }, 0x81: { name: 'STA', - op: this.sta, - modeFn: this.writeZeroPageXIndirect, + fn: () => this.sta(this.writeZeroPageXIndirect), mode: 'zeroPageXIndirect', }, 0x91: { name: 'STA', - op: this.sta, - modeFn: this.writeZeroPageIndirectY, + fn: () => this.sta(this.writeZeroPageIndirectY), mode: 'zeroPageIndirectY', }, // STX 0x86: { name: 'STX', - op: this.stx, - modeFn: this.writeZeroPage, + fn: () => this.stx(this.writeZeroPage), mode: 'zeroPage', }, 0x96: { name: 'STX', - op: this.stx, - modeFn: this.writeZeroPageY, + fn: () => this.stx(this.writeZeroPageY), mode: 'zeroPageY', }, 0x8e: { name: 'STX', - op: this.stx, - modeFn: this.writeAbsolute, + fn: () => this.stx(this.writeAbsolute), mode: 'absolute', }, // STY 0x84: { name: 'STY', - op: this.sty, - modeFn: this.writeZeroPage, + fn: () => this.sty(this.writeZeroPage), mode: 'zeroPage', }, 0x94: { name: 'STY', - op: this.sty, - modeFn: this.writeZeroPageX, + fn: () => this.sty(this.writeZeroPageX), mode: 'zeroPageX', }, 0x8c: { name: 'STY', - op: this.sty, - modeFn: this.writeAbsolute, + fn: () => this.sty(this.writeAbsolute), mode: 'absolute', }, // ADC 0x69: { name: 'ADC', - op: this.adc, - modeFn: this.readImmediate, + fn: () => this.adc(this.readImmediate), mode: 'immediate', }, 0x65: { name: 'ADC', - op: this.adc, - modeFn: this.readZeroPage, + fn: () => this.adc(this.readZeroPage), mode: 'zeroPage', }, 0x75: { name: 'ADC', - op: this.adc, - modeFn: this.readZeroPageX, + fn: () => this.adc(this.readZeroPageX), mode: 'zeroPageX', }, 0x6d: { name: 'ADC', - op: this.adc, - modeFn: this.readAbsolute, + fn: () => this.adc(this.readAbsolute), mode: 'absolute', }, 0x7d: { name: 'ADC', - op: this.adc, - modeFn: this.readAbsoluteX, + fn: () => this.adc(this.readAbsoluteX), mode: 'absoluteX', }, 0x79: { name: 'ADC', - op: this.adc, - modeFn: this.readAbsoluteY, + fn: () => this.adc(this.readAbsoluteY), mode: 'absoluteY', }, 0x61: { name: 'ADC', - op: this.adc, - modeFn: this.readZeroPageXIndirect, + fn: () => this.adc(this.readZeroPageXIndirect), mode: 'zeroPageXIndirect', }, 0x71: { name: 'ADC', - op: this.adc, - modeFn: this.readZeroPageIndirectY, + fn: () => this.adc(this.readZeroPageIndirectY), mode: 'zeroPageIndirectY', }, // SBC 0xe9: { name: 'SBC', - op: this.sbc, - modeFn: this.readImmediate, + fn: () => this.sbc(this.readImmediate), mode: 'immediate', }, 0xe5: { name: 'SBC', - op: this.sbc, - modeFn: this.readZeroPage, + fn: () => this.sbc(this.readZeroPage), mode: 'zeroPage', }, 0xf5: { name: 'SBC', - op: this.sbc, - modeFn: this.readZeroPageX, + fn: () => this.sbc(this.readZeroPageX), mode: 'zeroPageX', }, 0xed: { name: 'SBC', - op: this.sbc, - modeFn: this.readAbsolute, + fn: () => this.sbc(this.readAbsolute), mode: 'absolute', }, 0xfd: { name: 'SBC', - op: this.sbc, - modeFn: this.readAbsoluteX, + fn: () => this.sbc(this.readAbsoluteX), mode: 'absoluteX', }, 0xf9: { name: 'SBC', - op: this.sbc, - modeFn: this.readAbsoluteY, + fn: () => this.sbc(this.readAbsoluteY), mode: 'absoluteY', }, 0xe1: { name: 'SBC', - op: this.sbc, - modeFn: this.readZeroPageXIndirect, + fn: () => this.sbc(this.readZeroPageXIndirect), mode: 'zeroPageXIndirect', }, 0xf1: { name: 'SBC', - op: this.sbc, - modeFn: this.readZeroPageIndirectY, + fn: () => this.sbc(this.readZeroPageIndirectY), mode: 'zeroPageIndirectY', }, // INC 0xe6: { name: 'INC', - op: this.inc, - modeFn: this.readAddrZeroPage, + fn: () => this.inc(this.readAddrZeroPage), mode: 'zeroPage', }, 0xf6: { name: 'INC', - op: this.inc, - modeFn: this.readAddrZeroPageX, + fn: () => this.inc(this.readAddrZeroPageX), mode: 'zeroPageX', }, 0xee: { name: 'INC', - op: this.inc, - modeFn: this.readAddrAbsolute, + fn: () => this.inc(this.readAddrAbsolute), mode: 'absolute', }, 0xfe: { name: 'INC', - op: this.inc, - modeFn: this.readAddrAbsoluteX, + fn: () => this.inc(this.readAddrAbsoluteX), mode: 'absoluteX', }, // INX - 0xe8: { name: 'INX', op: this.inx, modeFn: this.implied, mode: 'implied' }, + 0xe8: { name: 'INX', fn: () => this.inx(), mode: 'implied' }, // INY - 0xc8: { name: 'INY', op: this.iny, modeFn: this.implied, mode: 'implied' }, + 0xc8: { name: 'INY', fn: () => this.iny(), mode: 'implied' }, // DEC 0xc6: { name: 'DEC', - op: this.dec, - modeFn: this.readAddrZeroPage, + fn: () => this.dec(this.readAddrZeroPage), mode: 'zeroPage', }, 0xd6: { name: 'DEC', - op: this.dec, - modeFn: this.readAddrZeroPageX, + fn: () => this.dec(this.readAddrZeroPageX), mode: 'zeroPageX', }, 0xce: { name: 'DEC', - op: this.dec, - modeFn: this.readAddrAbsolute, + fn: () => this.dec(this.readAddrAbsolute), mode: 'absolute', }, 0xde: { name: 'DEC', - op: this.dec, - modeFn: this.readAddrAbsoluteX, + fn: () => this.dec(this.readAddrAbsoluteX), mode: 'absoluteX', }, // DEX - 0xca: { name: 'DEX', op: this.dex, modeFn: this.implied, mode: 'implied' }, + 0xca: { name: 'DEX', fn: () => this.dex(), mode: 'implied' }, // DEY - 0x88: { name: 'DEY', op: this.dey, modeFn: this.implied, mode: 'implied' }, + 0x88: { name: 'DEY', fn: () => this.dey(), mode: 'implied' }, // ASL 0x0a: { name: 'ASL', - op: this.aslA, - modeFn: this.implied, + fn: () => this.aslA(), mode: 'accumulator', }, 0x06: { name: 'ASL', - op: this.asl, - modeFn: this.readAddrZeroPage, + fn: () => this.asl(this.readAddrZeroPage), mode: 'zeroPage', }, 0x16: { name: 'ASL', - op: this.asl, - modeFn: this.readAddrZeroPageX, + fn: () => this.asl(this.readAddrZeroPageX), mode: 'zeroPageX', }, 0x0e: { name: 'ASL', - op: this.asl, - modeFn: this.readAddrAbsolute, + fn: () => this.asl(this.readAddrAbsolute), mode: 'absolute', }, 0x1e: { name: 'ASL', - op: this.asl, - modeFn: this.readAddrAbsoluteX, + fn: () => this.asl(this.readAddrAbsoluteX), mode: 'absoluteX', }, // LSR 0x4a: { name: 'LSR', - op: this.lsrA, - modeFn: this.implied, + fn: () => this.lsrA(), mode: 'accumulator', }, 0x46: { name: 'LSR', - op: this.lsr, - modeFn: this.readAddrZeroPage, + fn: () => this.lsr(this.readAddrZeroPage), mode: 'zeroPage', }, 0x56: { name: 'LSR', - op: this.lsr, - modeFn: this.readAddrZeroPageX, + fn: () => this.lsr(this.readAddrZeroPageX), mode: 'zeroPageX', }, 0x4e: { name: 'LSR', - op: this.lsr, - modeFn: this.readAddrAbsolute, + fn: () => this.lsr(this.readAddrAbsolute), mode: 'absolute', }, 0x5e: { name: 'LSR', - op: this.lsr, - modeFn: this.readAddrAbsoluteX, + fn: () => this.lsr(this.readAddrAbsoluteX), mode: 'absoluteX', }, // ROL 0x2a: { name: 'ROL', - op: this.rolA, - modeFn: this.implied, + fn: () => this.rolA(), mode: 'accumulator', }, 0x26: { name: 'ROL', - op: this.rol, - modeFn: this.readAddrZeroPage, + fn: () => this.rol(this.readAddrZeroPage), mode: 'zeroPage', }, 0x36: { name: 'ROL', - op: this.rol, - modeFn: this.readAddrZeroPageX, + fn: () => this.rol(this.readAddrZeroPageX), mode: 'zeroPageX', }, 0x2e: { name: 'ROL', - op: this.rol, - modeFn: this.readAddrAbsolute, + fn: () => this.rol(this.readAddrAbsolute), mode: 'absolute', }, 0x3e: { name: 'ROL', - op: this.rol, - modeFn: this.readAddrAbsoluteX, + fn: () => this.rol(this.readAddrAbsoluteX), mode: 'absoluteX', }, // ROR 0x6a: { name: 'ROR', - op: this.rorA, - modeFn: this.implied, + fn: () => this.rorA(), mode: 'accumulator', }, 0x66: { name: 'ROR', - op: this.ror, - modeFn: this.readAddrZeroPage, + fn: () => this.ror(this.readAddrZeroPage), mode: 'zeroPage', }, 0x76: { name: 'ROR', - op: this.ror, - modeFn: this.readAddrZeroPageX, + fn: () => this.ror(this.readAddrZeroPageX), mode: 'zeroPageX', }, 0x6e: { name: 'ROR', - op: this.ror, - modeFn: this.readAddrAbsolute, + fn: () => this.ror(this.readAddrAbsolute), mode: 'absolute', }, 0x7e: { name: 'ROR', - op: this.ror, - modeFn: this.readAddrAbsoluteX, + fn: () => this.ror(this.readAddrAbsoluteX), mode: 'absoluteX', }, // AND 0x29: { name: 'AND', - op: this.and, - modeFn: this.readImmediate, + fn: () => this.and(this.readImmediate), mode: 'immediate', }, 0x25: { name: 'AND', - op: this.and, - modeFn: this.readZeroPage, + fn: () => this.and(this.readZeroPage), mode: 'zeroPage', }, 0x35: { name: 'AND', - op: this.and, - modeFn: this.readZeroPageX, + fn: () => this.and(this.readZeroPageX), mode: 'zeroPageX', }, 0x2d: { name: 'AND', - op: this.and, - modeFn: this.readAbsolute, + fn: () => this.and(this.readAbsolute), mode: 'absolute', }, 0x3d: { name: 'AND', - op: this.and, - modeFn: this.readAbsoluteX, + fn: () => this.and(this.readAbsoluteX), mode: 'absoluteX', }, 0x39: { name: 'AND', - op: this.and, - modeFn: this.readAbsoluteY, + fn: () => this.and(this.readAbsoluteY), mode: 'absoluteY', }, 0x21: { name: 'AND', - op: this.and, - modeFn: this.readZeroPageXIndirect, + fn: () => this.and(this.readZeroPageXIndirect), mode: 'zeroPageXIndirect', }, 0x31: { name: 'AND', - op: this.and, - modeFn: this.readZeroPageIndirectY, + fn: () => this.and(this.readZeroPageIndirectY), mode: 'zeroPageIndirectY', }, // ORA 0x09: { name: 'ORA', - op: this.ora, - modeFn: this.readImmediate, + fn: () => this.ora(this.readImmediate), mode: 'immediate', }, 0x05: { name: 'ORA', - op: this.ora, - modeFn: this.readZeroPage, + fn: () => this.ora(this.readZeroPage), mode: 'zeroPage', }, 0x15: { name: 'ORA', - op: this.ora, - modeFn: this.readZeroPageX, + fn: () => this.ora(this.readZeroPageX), mode: 'zeroPageX', }, 0x0d: { name: 'ORA', - op: this.ora, - modeFn: this.readAbsolute, + fn: () => this.ora(this.readAbsolute), mode: 'absolute', }, 0x1d: { name: 'ORA', - op: this.ora, - modeFn: this.readAbsoluteX, + fn: () => this.ora(this.readAbsoluteX), mode: 'absoluteX', }, 0x19: { name: 'ORA', - op: this.ora, - modeFn: this.readAbsoluteY, + fn: () => this.ora(this.readAbsoluteY), mode: 'absoluteY', }, 0x01: { name: 'ORA', - op: this.ora, - modeFn: this.readZeroPageXIndirect, + fn: () => this.ora(this.readZeroPageXIndirect), mode: 'zeroPageXIndirect', }, 0x11: { name: 'ORA', - op: this.ora, - modeFn: this.readZeroPageIndirectY, + fn: () => this.ora(this.readZeroPageIndirectY), mode: 'zeroPageIndirectY', }, // EOR 0x49: { name: 'EOR', - op: this.eor, - modeFn: this.readImmediate, + fn: () => this.eor(this.readImmediate), mode: 'immediate', }, 0x45: { name: 'EOR', - op: this.eor, - modeFn: this.readZeroPage, + fn: () => this.eor(this.readZeroPage), mode: 'zeroPage', }, 0x55: { name: 'EOR', - op: this.eor, - modeFn: this.readZeroPageX, + fn: () => this.eor(this.readZeroPageX), mode: 'zeroPageX', }, 0x4d: { name: 'EOR', - op: this.eor, - modeFn: this.readAbsolute, + fn: () => this.eor(this.readAbsolute), mode: 'absolute', }, 0x5d: { name: 'EOR', - op: this.eor, - modeFn: this.readAbsoluteX, + fn: () => this.eor(this.readAbsoluteX), mode: 'absoluteX', }, 0x59: { name: 'EOR', - op: this.eor, - modeFn: this.readAbsoluteY, + fn: () => this.eor(this.readAbsoluteY), mode: 'absoluteY', }, 0x41: { name: 'EOR', - op: this.eor, - modeFn: this.readZeroPageXIndirect, + fn: () => this.eor(this.readZeroPageXIndirect), mode: 'zeroPageXIndirect', }, 0x51: { name: 'EOR', - op: this.eor, - modeFn: this.readZeroPageIndirectY, + fn: () => this.eor(this.readZeroPageIndirectY), mode: 'zeroPageIndirectY', }, // CMP 0xc9: { name: 'CMP', - op: this.cmp, - modeFn: this.readImmediate, + fn: () => this.cmp(this.readImmediate), mode: 'immediate', }, 0xc5: { name: 'CMP', - op: this.cmp, - modeFn: this.readZeroPage, + fn: () => this.cmp(this.readZeroPage), mode: 'zeroPage', }, 0xd5: { name: 'CMP', - op: this.cmp, - modeFn: this.readZeroPageX, + fn: () => this.cmp(this.readZeroPageX), mode: 'zeroPageX', }, 0xcd: { name: 'CMP', - op: this.cmp, - modeFn: this.readAbsolute, + fn: () => this.cmp(this.readAbsolute), mode: 'absolute', }, 0xdd: { name: 'CMP', - op: this.cmp, - modeFn: this.readAbsoluteX, + fn: () => this.cmp(this.readAbsoluteX), mode: 'absoluteX', }, 0xd9: { name: 'CMP', - op: this.cmp, - modeFn: this.readAbsoluteY, + fn: () => this.cmp(this.readAbsoluteY), mode: 'absoluteY', }, 0xc1: { name: 'CMP', - op: this.cmp, - modeFn: this.readZeroPageXIndirect, + fn: () => this.cmp(this.readZeroPageXIndirect), mode: 'zeroPageXIndirect', }, 0xd1: { name: 'CMP', - op: this.cmp, - modeFn: this.readZeroPageIndirectY, + fn: () => this.cmp(this.readZeroPageIndirectY), mode: 'zeroPageIndirectY', }, // CPX 0xe0: { name: 'CPX', - op: this.cpx, - modeFn: this.readImmediate, + fn: () => this.cpx(this.readImmediate), mode: 'immediate', }, 0xe4: { name: 'CPX', - op: this.cpx, - modeFn: this.readZeroPage, + fn: () => this.cpx(this.readZeroPage), mode: 'zeroPage', }, 0xec: { name: 'CPX', - op: this.cpx, - modeFn: this.readAbsolute, + fn: () => this.cpx(this.readAbsolute), mode: 'absolute', }, // CPY 0xc0: { name: 'CPY', - op: this.cpy, - modeFn: this.readImmediate, + fn: () => this.cpy(this.readImmediate), mode: 'immediate', }, 0xc4: { name: 'CPY', - op: this.cpy, - modeFn: this.readZeroPage, + fn: () => this.cpy(this.readZeroPage), mode: 'zeroPage', }, 0xcc: { name: 'CPY', - op: this.cpy, - modeFn: this.readAbsolute, + fn: () => this.cpy(this.readAbsolute), mode: 'absolute', }, // BIT 0x24: { name: 'BIT', - op: this.bit, - modeFn: this.readZeroPage, + fn: () => this.bit(this.readZeroPage), mode: 'zeroPage', }, 0x2c: { name: 'BIT', - op: this.bit, - modeFn: this.readAbsolute, + fn: () => this.bit(this.readAbsolute), mode: 'absolute', }, // BCC - 0x90: { name: 'BCC', op: this.brc, modeFn: flags.C, mode: 'relative' }, + 0x90: { + name: 'BCC', + fn: () => this.brc(flags.C), + mode: 'relative', + }, // BCS - 0xb0: { name: 'BCS', op: this.brs, modeFn: flags.C, mode: 'relative' }, + 0xb0: { + name: 'BCS', + fn: () => this.brs(flags.C), + mode: 'relative', + }, // BEQ - 0xf0: { name: 'BEQ', op: this.brs, modeFn: flags.Z, mode: 'relative' }, + 0xf0: { + name: 'BEQ', + fn: () => this.brs(flags.Z), + mode: 'relative', + }, // BMI - 0x30: { name: 'BMI', op: this.brs, modeFn: flags.N, mode: 'relative' }, + 0x30: { + name: 'BMI', + fn: () => this.brs(flags.N), + mode: 'relative', + }, // BNE - 0xd0: { name: 'BNE', op: this.brc, modeFn: flags.Z, mode: 'relative' }, + 0xd0: { + name: 'BNE', + fn: () => this.brc(flags.Z), + mode: 'relative', + }, // BPL - 0x10: { name: 'BPL', op: this.brc, modeFn: flags.N, mode: 'relative' }, + 0x10: { + name: 'BPL', + fn: () => this.brc(flags.N), + mode: 'relative', + }, // BVC - 0x50: { name: 'BVC', op: this.brc, modeFn: flags.V, mode: 'relative' }, + 0x50: { + name: 'BVC', + fn: () => this.brc(flags.V), + mode: 'relative', + }, // BVS - 0x70: { name: 'BVS', op: this.brs, modeFn: flags.V, mode: 'relative' }, + 0x70: { + name: 'BVS', + fn: () => this.brs(flags.V), + mode: 'relative', + }, // TAX - 0xaa: { name: 'TAX', op: this.tax, modeFn: this.implied, mode: 'implied' }, + 0xaa: { name: 'TAX', fn: () => this.tax(), mode: 'implied' }, // TXA - 0x8a: { name: 'TXA', op: this.txa, modeFn: this.implied, mode: 'implied' }, + 0x8a: { name: 'TXA', fn: () => this.txa(), mode: 'implied' }, // TAY - 0xa8: { name: 'TAY', op: this.tay, modeFn: this.implied, mode: 'implied' }, + 0xa8: { name: 'TAY', fn: () => this.tay(), mode: 'implied' }, // TYA - 0x98: { name: 'TYA', op: this.tya, modeFn: this.implied, mode: 'implied' }, + 0x98: { name: 'TYA', fn: () => this.tya(), mode: 'implied' }, // TSX - 0xba: { name: 'TSX', op: this.tsx, modeFn: this.implied, mode: 'implied' }, + 0xba: { name: 'TSX', fn: () => this.tsx(), mode: 'implied' }, // TXS - 0x9a: { name: 'TXS', op: this.txs, modeFn: this.implied, mode: 'implied' }, + 0x9a: { name: 'TXS', fn: () => this.txs(), mode: 'implied' }, // PHA - 0x48: { name: 'PHA', op: this.pha, modeFn: this.implied, mode: 'implied' }, + 0x48: { name: 'PHA', fn: () => this.pha(), mode: 'implied' }, // PLA - 0x68: { name: 'PLA', op: this.pla, modeFn: this.implied, mode: 'implied' }, + 0x68: { name: 'PLA', fn: () => this.pla(), mode: 'implied' }, // PHP - 0x08: { name: 'PHP', op: this.php, modeFn: this.implied, mode: 'implied' }, + 0x08: { name: 'PHP', fn: () => this.php(), mode: 'implied' }, // PLP - 0x28: { name: 'PLP', op: this.plp, modeFn: this.implied, mode: 'implied' }, + 0x28: { name: 'PLP', fn: () => this.plp(), mode: 'implied' }, // JMP 0x4c: { name: 'JMP', - op: this.jmp, - modeFn: this.readAddrAbsolute, + fn: () => this.jmp(this.readAddrAbsolute), mode: 'absolute', }, 0x6c: { name: 'JMP', - op: this.jmp, - modeFn: this.readAddrAbsoluteIndirectBug, + fn: () => this.jmp(this.readAddrAbsoluteIndirectBug), mode: 'absoluteIndirect', }, // JSR 0x20: { name: 'JSR', - op: this.jsr, - modeFn: this.readAddrAbsolute, + fn: () => this.jsr(), mode: 'absolute', }, // RTS - 0x60: { name: 'RTS', op: this.rts, modeFn: this.implied, mode: 'implied' }, + 0x60: { name: 'RTS', fn: () => this.rts(), mode: 'implied' }, // RTI - 0x40: { name: 'RTI', op: this.rti, modeFn: this.implied, mode: 'implied' }, + 0x40: { name: 'RTI', fn: () => this.rti(), mode: 'implied' }, // SEC - 0x38: { name: 'SEC', op: this.set, modeFn: flags.C, mode: 'implied' }, + 0x38: { name: 'SEC', fn: () => this.set(flags.C), mode: 'implied' }, // SED - 0xf8: { name: 'SED', op: this.set, modeFn: flags.D, mode: 'implied' }, + 0xf8: { name: 'SED', fn: () => this.set(flags.D), mode: 'implied' }, // SEI - 0x78: { name: 'SEI', op: this.set, modeFn: flags.I, mode: 'implied' }, + 0x78: { name: 'SEI', fn: () => this.set(flags.I), mode: 'implied' }, // CLC - 0x18: { name: 'CLC', op: this.clr, modeFn: flags.C, mode: 'implied' }, + 0x18: { name: 'CLC', fn: () => this.clr(flags.C), mode: 'implied' }, // CLD - 0xd8: { name: 'CLD', op: this.clr, modeFn: flags.D, mode: 'implied' }, + 0xd8: { name: 'CLD', fn: () => this.clr(flags.D), mode: 'implied' }, // CLI - 0x58: { name: 'CLI', op: this.clr, modeFn: flags.I, mode: 'implied' }, + 0x58: { name: 'CLI', fn: () => this.clr(flags.I), mode: 'implied' }, // CLV - 0xb8: { name: 'CLV', op: this.clr, modeFn: flags.V, mode: 'implied' }, + 0xb8: { name: 'CLV', fn: () => this.clr(flags.V), mode: 'implied' }, // NOP - 0xea: { name: 'NOP', op: this.nop, modeFn: this.implied, mode: 'implied' }, + 0xea: { name: 'NOP', fn: () => this.nop(this.implied), mode: 'implied' }, // BRK 0x00: { name: 'BRK', - op: this.brk, - modeFn: this.readImmediate, + fn: () => this.brk(this.readImmediate), mode: 'immediate', }, }; @@ -2473,277 +2375,311 @@ export default class CPU6502 { // INC / DEC A 0x1a: { name: 'INC', - op: this.incA, - modeFn: this.implied, + fn: () => this.incA(), mode: 'accumulator', }, 0x3a: { name: 'DEC', - op: this.decA, - modeFn: this.implied, + fn: () => this.decA(), mode: 'accumulator', }, // Indirect Zero Page for the masses 0x12: { name: 'ORA', - op: this.ora, - modeFn: this.readZeroPageIndirect, + fn: () => this.ora(this.readZeroPageIndirect), mode: 'zeroPageIndirect', }, 0x32: { name: 'AND', - op: this.and, - modeFn: this.readZeroPageIndirect, + fn: () => this.and(this.readZeroPageIndirect), mode: 'zeroPageIndirect', }, 0x52: { name: 'EOR', - op: this.eor, - modeFn: this.readZeroPageIndirect, + fn: () => this.eor(this.readZeroPageIndirect), mode: 'zeroPageIndirect', }, 0x72: { name: 'ADC', - op: this.adc, - modeFn: this.readZeroPageIndirect, + fn: () => this.adc(this.readZeroPageIndirect), mode: 'zeroPageIndirect', }, 0x92: { name: 'STA', - op: this.sta, - modeFn: this.writeZeroPageIndirect, + fn: () => this.sta(this.writeZeroPageIndirect), mode: 'zeroPageIndirect', }, 0xb2: { name: 'LDA', - op: this.lda, - modeFn: this.readZeroPageIndirect, + fn: () => this.lda(this.readZeroPageIndirect), mode: 'zeroPageIndirect', }, 0xd2: { name: 'CMP', - op: this.cmp, - modeFn: this.readZeroPageIndirect, + fn: () => this.cmp(this.readZeroPageIndirect), mode: 'zeroPageIndirect', }, 0xf2: { name: 'SBC', - op: this.sbc, - modeFn: this.readZeroPageIndirect, + fn: () => this.sbc(this.readZeroPageIndirect), mode: 'zeroPageIndirect', }, // Better BIT 0x34: { name: 'BIT', - op: this.bit, - modeFn: this.readZeroPageX, + fn: () => this.bit(this.readZeroPageX), mode: 'zeroPageX', }, 0x3c: { name: 'BIT', - op: this.bit, - modeFn: this.readAbsoluteX, + fn: () => this.bit(this.readAbsoluteX), mode: 'absoluteX', }, 0x89: { name: 'BIT', - op: this.bitI, - modeFn: this.readImmediate, + fn: () => this.bitI(this.readImmediate), mode: 'immediate', }, // JMP absolute indirect indexed 0x6c: { name: 'JMP', - op: this.jmp, - modeFn: this.readAddrAbsoluteIndirect, + fn: () => this.jmp(this.readAddrAbsoluteIndirect), mode: 'absoluteIndirect', }, 0x7c: { name: 'JMP', - op: this.jmp, - modeFn: this.readAddrAbsoluteXIndirect, + fn: () => this.jmp(this.readAddrAbsoluteXIndirect), mode: 'absoluteXIndirect', }, // 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' }, + 0x0f: { + name: 'BBR0', + fn: () => this.bbr(0), + mode: 'zeroPage_relative', + }, + 0x1f: { + name: 'BBR1', + fn: () => this.bbr(1), + mode: 'zeroPage_relative', + }, + 0x2f: { + name: 'BBR2', + fn: () => this.bbr(2), + mode: 'zeroPage_relative', + }, + 0x3f: { + name: 'BBR3', + fn: () => this.bbr(3), + mode: 'zeroPage_relative', + }, + 0x4f: { + name: 'BBR4', + fn: () => this.bbr(4), + mode: 'zeroPage_relative', + }, + 0x5f: { + name: 'BBR5', + fn: () => this.bbr(5), + mode: 'zeroPage_relative', + }, + 0x6f: { + name: 'BBR6', + fn: () => this.bbr(6), + mode: 'zeroPage_relative', + }, + 0x7f: { + name: 'BBR7', + fn: () => this.bbr(7), + mode: 'zeroPage_relative', + }, - 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' }, + 0x8f: { + name: 'BBS0', + fn: () => this.bbs(0), + mode: 'zeroPage_relative', + }, + 0x9f: { + name: 'BBS1', + fn: () => this.bbs(1), + mode: 'zeroPage_relative', + }, + 0xaf: { + name: 'BBS2', + fn: () => this.bbs(2), + mode: 'zeroPage_relative', + }, + 0xbf: { + name: 'BBS3', + fn: () => this.bbs(3), + mode: 'zeroPage_relative', + }, + 0xcf: { + name: 'BBS4', + fn: () => this.bbs(4), + mode: 'zeroPage_relative', + }, + 0xdf: { + name: 'BBS5', + fn: () => this.bbs(5), + mode: 'zeroPage_relative', + }, + 0xef: { + name: 'BBS6', + fn: () => this.bbs(6), + mode: 'zeroPage_relative', + }, + 0xff: { + name: 'BBS7', + fn: () => this.bbs(7), + mode: 'zeroPage_relative', + }, // BRA - 0x80: { name: 'BRA', op: this.brc, modeFn: 0, mode: 'relative' }, + 0x80: { + name: 'BRA', + fn: () => this.brc(0), + mode: 'relative', + }, // NOP 0x02: { name: 'NOP', - op: this.nop, - modeFn: this.readImmediate, + fn: () => this.nop(this.readImmediate), mode: 'immediate', }, 0x22: { name: 'NOP', - op: this.nop, - modeFn: this.readImmediate, + fn: () => this.nop(this.readImmediate), mode: 'immediate', }, 0x42: { name: 'NOP', - op: this.nop, - modeFn: this.readImmediate, + fn: () => this.nop(this.readImmediate), mode: 'immediate', }, 0x44: { name: 'NOP', - op: this.nop, - modeFn: this.readZeroPage, + fn: () => this.nop(this.readZeroPage), mode: 'immediate', }, 0x54: { name: 'NOP', - op: this.nop, - modeFn: this.readZeroPageX, + fn: () => this.nop(this.readZeroPageX), mode: 'immediate', }, 0x62: { name: 'NOP', - op: this.nop, - modeFn: this.readImmediate, + fn: () => this.nop(this.readImmediate), mode: 'immediate', }, 0x82: { name: 'NOP', - op: this.nop, - modeFn: this.readImmediate, + fn: () => this.nop(this.readImmediate), mode: 'immediate', }, 0xc2: { name: 'NOP', - op: this.nop, - modeFn: this.readImmediate, + fn: () => this.nop(this.readImmediate), mode: 'immediate', }, 0xd4: { name: 'NOP', - op: this.nop, - modeFn: this.readZeroPageX, + fn: () => this.nop(this.readZeroPageX), mode: 'immediate', }, 0xe2: { name: 'NOP', - op: this.nop, - modeFn: this.readImmediate, + fn: () => this.nop(this.readImmediate), mode: 'immediate', }, 0xf4: { name: 'NOP', - op: this.nop, - modeFn: this.readZeroPageX, + fn: () => this.nop(this.readZeroPageX), mode: 'immediate', }, - 0x5c: { name: 'NOP', op: this.nop, modeFn: this.readNop, mode: 'absolute' }, - 0xdc: { name: 'NOP', op: this.nop, modeFn: this.readNop, mode: 'absolute' }, - 0xfc: { name: 'NOP', op: this.nop, modeFn: this.readNop, mode: 'absolute' }, + 0x5c: { name: 'NOP', fn: () => this.nop(this.readNop), mode: 'absolute' }, + 0xdc: { name: 'NOP', fn: () => this.nop(this.readNop), mode: 'absolute' }, + 0xfc: { name: 'NOP', fn: () => this.nop(this.readNop), mode: 'absolute' }, // PHX - 0xda: { name: 'PHX', op: this.phx, modeFn: this.implied, mode: 'implied' }, + 0xda: { name: 'PHX', fn: () => this.phx(), mode: 'implied' }, // PHY - 0x5a: { name: 'PHY', op: this.phy, modeFn: this.implied, mode: 'implied' }, + 0x5a: { name: 'PHY', fn: () => this.phy(), mode: 'implied' }, // PLX - 0xfa: { name: 'PLX', op: this.plx, modeFn: this.implied, mode: 'implied' }, + 0xfa: { name: 'PLX', fn: () => this.plx(), mode: 'implied' }, // PLY - 0x7a: { name: 'PLY', op: this.ply, modeFn: this.implied, mode: 'implied' }, + 0x7a: { name: 'PLY', fn: () => this.ply(), mode: 'implied' }, // RMB/SMB - 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' }, + 0x07: { name: 'RMB0', fn: () => this.rmb(0), mode: 'zeroPage' }, + 0x17: { name: 'RMB1', fn: () => this.rmb(1), mode: 'zeroPage' }, + 0x27: { name: 'RMB2', fn: () => this.rmb(2), mode: 'zeroPage' }, + 0x37: { name: 'RMB3', fn: () => this.rmb(3), mode: 'zeroPage' }, + 0x47: { name: 'RMB4', fn: () => this.rmb(4), mode: 'zeroPage' }, + 0x57: { name: 'RMB5', fn: () => this.rmb(5), mode: 'zeroPage' }, + 0x67: { name: 'RMB6', fn: () => this.rmb(6), mode: 'zeroPage' }, + 0x77: { name: 'RMB7', fn: () => this.rmb(7), mode: 'zeroPage' }, - 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' }, + 0x87: { name: 'SMB0', fn: () => this.smb(0), mode: 'zeroPage' }, + 0x97: { name: 'SMB1', fn: () => this.smb(1), mode: 'zeroPage' }, + 0xa7: { name: 'SMB2', fn: () => this.smb(2), mode: 'zeroPage' }, + 0xb7: { name: 'SMB3', fn: () => this.smb(3), mode: 'zeroPage' }, + 0xc7: { name: 'SMB4', fn: () => this.smb(4), mode: 'zeroPage' }, + 0xd7: { name: 'SMB5', fn: () => this.smb(5), mode: 'zeroPage' }, + 0xe7: { name: 'SMB6', fn: () => this.smb(6), mode: 'zeroPage' }, + 0xf7: { name: 'SMB7', fn: () => this.smb(7), mode: 'zeroPage' }, // STZ 0x64: { name: 'STZ', - op: this.stz, - modeFn: this.writeZeroPage, + fn: () => this.stz(this.writeZeroPage), mode: 'zeroPage', }, 0x74: { name: 'STZ', - op: this.stz, - modeFn: this.writeZeroPageX, + fn: () => this.stz(this.writeZeroPageX), mode: 'zeroPageX', }, 0x9c: { name: 'STZ', - op: this.stz, - modeFn: this.writeAbsolute, + fn: () => this.stz(this.writeAbsolute), mode: 'absolute', }, 0x9e: { name: 'STZ', - op: this.stz, - modeFn: this.writeAbsoluteX, + fn: () => this.stz(this.writeAbsoluteX), mode: 'absoluteX', }, // TRB 0x14: { name: 'TRB', - op: this.trb, - modeFn: this.readAddrZeroPage, + fn: () => this.trb(this.readAddrZeroPage), mode: 'zeroPage', }, 0x1c: { name: 'TRB', - op: this.trb, - modeFn: this.readAddrAbsolute, + fn: () => this.trb(this.readAddrAbsolute), mode: 'absolute', }, // TSB 0x04: { name: 'TSB', - op: this.tsb, - modeFn: this.readAddrZeroPage, + fn: () => this.tsb(this.readAddrZeroPage), mode: 'zeroPage', }, 0x0c: { name: 'TSB', - op: this.tsb, - modeFn: this.readAddrAbsolute, + fn: () => this.tsb(this.readAddrAbsolute), mode: 'absolute', }, }; @@ -2752,658 +2688,558 @@ export default class CPU6502 { // ASO 0x0f: { name: 'ASO', - op: this.aso, - modeFn: this.readAddrAbsolute, + fn: () => this.aso(this.readAddrAbsolute), mode: 'absolute', }, 0x1f: { name: 'ASO', - op: this.aso, - modeFn: this.readAddrAbsoluteX, + fn: () => this.aso(this.readAddrAbsoluteX), mode: 'absoluteX', }, 0x1b: { name: 'ASO', - op: this.aso, - modeFn: this.readAddrAbsoluteY, + fn: () => this.aso(this.readAddrAbsoluteY), mode: 'absoluteY', }, 0x07: { name: 'ASO', - op: this.aso, - modeFn: this.readAddrZeroPage, + fn: () => this.aso(this.readAddrZeroPage), mode: 'zeroPage', }, 0x17: { name: 'ASO', - op: this.aso, - modeFn: this.readAddrZeroPageX, + fn: () => this.aso(this.readAddrZeroPageX), mode: 'zeroPageX', }, 0x03: { name: 'ASO', - op: this.aso, - modeFn: this.readAddrZeroPageXIndirect, + fn: () => this.aso(this.readAddrZeroPageXIndirect), mode: 'zeroPageXIndirect', }, 0x13: { name: 'ASO', - op: this.aso, - modeFn: this.readAddrZeroPageIndirectY, + fn: () => this.aso(this.readAddrZeroPageIndirectY), mode: 'zeroPageIndirectY', }, // RLA 0x2f: { name: 'RLA', - op: this.rla, - modeFn: this.readAddrAbsolute, + fn: () => this.rla(this.readAddrAbsolute), mode: 'absolute', }, 0x3f: { name: 'RLA', - op: this.rla, - modeFn: this.readAddrAbsoluteX, + fn: () => this.rla(this.readAddrAbsoluteX), mode: 'absoluteX', }, 0x3b: { name: 'RLA', - op: this.rla, - modeFn: this.readAddrAbsoluteY, + fn: () => this.rla(this.readAddrAbsoluteY), mode: 'absoluteY', }, 0x27: { name: 'RLA', - op: this.rla, - modeFn: this.readAddrZeroPage, + fn: () => this.rla(this.readAddrZeroPage), mode: 'zeroPage', }, 0x37: { name: 'RLA', - op: this.rla, - modeFn: this.readAddrZeroPageX, + fn: () => this.rla(this.readAddrZeroPageX), mode: 'zeroPageX', }, 0x23: { name: 'RLA', - op: this.rla, - modeFn: this.readAddrZeroPageXIndirect, + fn: () => this.rla(this.readAddrZeroPageXIndirect), mode: 'zeroPageXIndirect', }, 0x33: { name: 'RLA', - op: this.rla, - modeFn: this.readAddrZeroPageIndirectY, + fn: () => this.rla(this.readAddrZeroPageIndirectY), mode: 'zeroPageIndirectY', }, // LSE 0x4f: { name: 'LSE', - op: this.lse, - modeFn: this.readAddrAbsolute, + fn: () => this.lse(this.readAddrAbsolute), mode: 'absolute', }, 0x5f: { name: 'LSE', - op: this.lse, - modeFn: this.readAddrAbsoluteX, + fn: () => this.lse(this.readAddrAbsoluteX), mode: 'absoluteX', }, 0x5b: { name: 'LSE', - op: this.lse, - modeFn: this.readAddrAbsoluteY, + fn: () => this.lse(this.readAddrAbsoluteY), mode: 'absoluteY', }, 0x47: { name: 'LSE', - op: this.lse, - modeFn: this.readAddrZeroPage, + fn: () => this.lse(this.readAddrZeroPage), mode: 'zeroPage', }, 0x57: { name: 'LSE', - op: this.lse, - modeFn: this.readAddrZeroPageX, + fn: () => this.lse(this.readAddrZeroPageX), mode: 'zeroPageX', }, 0x43: { name: 'LSE', - op: this.lse, - modeFn: this.readAddrZeroPageXIndirect, + fn: () => this.lse(this.readAddrZeroPageXIndirect), mode: 'zeroPageXIndirect', }, 0x53: { name: 'LSE', - op: this.lse, - modeFn: this.readAddrZeroPageIndirectY, + fn: () => this.lse(this.readAddrZeroPageIndirectY), mode: 'zeroPageIndirectY', }, // RRA 0x6f: { name: 'RRA', - op: this.rra, - modeFn: this.readAddrAbsolute, + fn: () => this.rra(this.readAddrAbsolute), mode: 'absolute', }, 0x7f: { name: 'RRA', - op: this.rra, - modeFn: this.readAddrAbsoluteX, + fn: () => this.rra(this.readAddrAbsoluteX), mode: 'absoluteX', }, 0x7b: { name: 'RRA', - op: this.rra, - modeFn: this.readAddrAbsoluteY, + fn: () => this.rra(this.readAddrAbsoluteY), mode: 'absoluteY', }, 0x67: { name: 'RRA', - op: this.rra, - modeFn: this.readAddrZeroPage, + fn: () => this.rra(this.readAddrZeroPage), mode: 'zeroPage', }, 0x77: { name: 'RRA', - op: this.rra, - modeFn: this.readAddrZeroPageX, + fn: () => this.rra(this.readAddrZeroPageX), mode: 'zeroPageX', }, 0x63: { name: 'RRA', - op: this.rra, - modeFn: this.readAddrZeroPageXIndirect, + fn: () => this.rra(this.readAddrZeroPageXIndirect), mode: 'zeroPageXIndirect', }, 0x73: { name: 'RRA', - op: this.rra, - modeFn: this.readAddrZeroPageIndirectY, + fn: () => this.rra(this.readAddrZeroPageIndirectY), mode: 'zeroPageIndirectY', }, // AXS 0x8f: { name: 'AXS', - op: this.axs, - modeFn: this.writeAbsolute, + fn: () => this.axs(this.writeAbsolute), mode: 'absolute', }, 0x87: { name: 'AXS', - op: this.axs, - modeFn: this.writeZeroPage, + fn: () => this.axs(this.writeZeroPage), mode: 'zeroPage', }, 0x97: { name: 'AXS', - op: this.axs, - modeFn: this.writeZeroPageY, + fn: () => this.axs(this.writeZeroPageY), mode: 'zeroPageY', }, 0x83: { name: 'AXS', - op: this.axs, - modeFn: this.writeZeroPageXIndirect, + fn: () => this.axs(this.writeZeroPageXIndirect), mode: 'zeroPageXIndirect', }, // LAX 0xaf: { name: 'LAX', - op: this.lax, - modeFn: this.readAbsolute, + fn: () => this.lax(this.readAbsolute), mode: 'absolute', }, 0xbf: { name: 'LAX', - op: this.lax, - modeFn: this.readAbsoluteY, + fn: () => this.lax(this.readAbsoluteY), mode: 'absoluteY', }, 0xa7: { name: 'LAX', - op: this.lax, - modeFn: this.readZeroPage, + fn: () => this.lax(this.readZeroPage), mode: 'zeroPage', }, 0xb7: { name: 'LAX', - op: this.lax, - modeFn: this.readZeroPageY, + fn: () => this.lax(this.readZeroPageY), mode: 'zeroPageY', }, 0xa3: { name: 'LAX', - op: this.lax, - modeFn: this.readZeroPageXIndirect, + fn: () => this.lax(this.readZeroPageXIndirect), mode: 'zeroPageXIndirect', }, 0xb3: { name: 'LAX', - op: this.lax, - modeFn: this.readZeroPageIndirectY, + fn: () => this.lax(this.readZeroPageIndirectY), mode: 'zeroPageIndirectY', }, // DCM 0xcf: { name: 'DCM', - op: this.dcm, - modeFn: this.readAddrAbsolute, + fn: () => this.dcm(this.readAddrAbsolute), mode: 'absolute', }, 0xdf: { name: 'DCM', - op: this.dcm, - modeFn: this.readAddrAbsoluteX, + fn: () => this.dcm(this.readAddrAbsoluteX), mode: 'absoluteX', }, 0xdb: { name: 'DCM', - op: this.dcm, - modeFn: this.readAddrAbsoluteY, + fn: () => this.dcm(this.readAddrAbsoluteY), mode: 'absoluteY', }, 0xc7: { name: 'DCM', - op: this.dcm, - modeFn: this.readAddrZeroPage, + fn: () => this.dcm(this.readAddrZeroPage), mode: 'zeroPage', }, 0xd7: { name: 'DCM', - op: this.dcm, - modeFn: this.readAddrZeroPageX, + fn: () => this.dcm(this.readAddrZeroPageX), mode: 'zeroPageX', }, 0xc3: { name: 'DCM', - op: this.dcm, - modeFn: this.readAddrZeroPageXIndirect, + fn: () => this.dcm(this.readAddrZeroPageXIndirect), mode: 'zeroPageXIndirect', }, 0xd3: { name: 'DCM', - op: this.dcm, - modeFn: this.readAddrZeroPageIndirectY, + fn: () => this.dcm(this.readAddrZeroPageIndirectY), mode: 'zeroPageIndirectY', }, // INS 0xef: { name: 'INS', - op: this.ins, - modeFn: this.readAddrAbsolute, + fn: () => this.ins(this.readAddrAbsolute), mode: 'absolute', }, 0xff: { name: 'INS', - op: this.ins, - modeFn: this.readAddrAbsoluteX, + fn: () => this.ins(this.readAddrAbsoluteX), mode: 'absoluteX', }, 0xfb: { name: 'INS', - op: this.ins, - modeFn: this.readAddrAbsoluteY, + fn: () => this.ins(this.readAddrAbsoluteY), mode: 'absoluteY', }, 0xe7: { name: 'INS', - op: this.ins, - modeFn: this.readAddrZeroPage, + fn: () => this.ins(this.readAddrZeroPage), mode: 'zeroPage', }, 0xf7: { name: 'INS', - op: this.ins, - modeFn: this.readAddrZeroPageX, + fn: () => this.ins(this.readAddrZeroPageX), mode: 'zeroPageX', }, 0xe3: { name: 'INS', - op: this.ins, - modeFn: this.readAddrZeroPageXIndirect, + fn: () => this.ins(this.readAddrZeroPageXIndirect), mode: 'zeroPageXIndirect', }, 0xf3: { name: 'INS', - op: this.ins, - modeFn: this.readAddrZeroPageIndirectY, + fn: () => this.ins(this.readAddrZeroPageIndirectY), mode: 'zeroPageIndirectY', }, // ALR 0x4b: { name: 'ALR', - op: this.alr, - modeFn: this.readImmediate, + fn: () => this.alr(this.readImmediate), mode: 'immediate', }, // ARR 0x6b: { name: 'ARR', - op: this.arr, - modeFn: this.readImmediate, + fn: () => this.arr(this.readImmediate), mode: 'immediate', }, // XAA 0x8b: { name: 'XAA', - op: this.xaa, - modeFn: this.readImmediate, + fn: () => this.xaa(this.readImmediate), mode: 'immediate', }, // OAL 0xab: { name: 'OAL', - op: this.oal, - modeFn: this.readImmediate, + fn: () => this.oal(this.readImmediate), mode: 'immediate', }, // SAX 0xcb: { name: 'SAX', - op: this.sax, - modeFn: this.readImmediate, + fn: () => this.sax(this.readImmediate), mode: 'immediate', }, // NOP - 0x1a: { name: 'NOP', op: this.nop, modeFn: this.implied, mode: 'implied' }, - 0x3a: { name: 'NOP', op: this.nop, modeFn: this.implied, mode: 'implied' }, - 0x5a: { name: 'NOP', op: this.nop, modeFn: this.implied, mode: 'implied' }, - 0x7a: { name: 'NOP', op: this.nop, modeFn: this.implied, mode: 'implied' }, - 0xda: { name: 'NOP', op: this.nop, modeFn: this.implied, mode: 'implied' }, - 0xfa: { name: 'NOP', op: this.nop, modeFn: this.implied, mode: 'implied' }, + 0x1a: { name: 'NOP', fn: () => this.nop(this.implied), mode: 'implied' }, + 0x3a: { name: 'NOP', fn: () => this.nop(this.implied), mode: 'implied' }, + 0x5a: { name: 'NOP', fn: () => this.nop(this.implied), mode: 'implied' }, + 0x7a: { name: 'NOP', fn: () => this.nop(this.implied), mode: 'implied' }, + 0xda: { name: 'NOP', fn: () => this.nop(this.implied), mode: 'implied' }, + 0xfa: { name: 'NOP', fn: () => this.nop(this.implied), mode: 'implied' }, // SKB 0x80: { name: 'SKB', - op: this.skp, - modeFn: this.readImmediate, + fn: () => this.skp(this.readImmediate), mode: 'immediate', }, 0x82: { name: 'SKB', - op: this.skp, - modeFn: this.readImmediate, + fn: () => this.skp(this.readImmediate), mode: 'immediate', }, 0x89: { name: 'SKB', - op: this.skp, - modeFn: this.readImmediate, + fn: () => this.skp(this.readImmediate), mode: 'immediate', }, 0xc2: { name: 'SKB', - op: this.skp, - modeFn: this.readImmediate, + fn: () => this.skp(this.readImmediate), mode: 'immediate', }, 0xe2: { name: 'SKB', - op: this.skp, - modeFn: this.readImmediate, + fn: () => this.skp(this.readImmediate), mode: 'immediate', }, 0x04: { name: 'SKB', - op: this.skp, - modeFn: this.readZeroPage, + fn: () => this.skp(this.readZeroPage), mode: 'zeroPage', }, 0x14: { name: 'SKB', - op: this.skp, - modeFn: this.readZeroPageX, + fn: () => this.skp(this.readZeroPageX), mode: 'zeroPageX', }, 0x34: { name: 'SKB', - op: this.skp, - modeFn: this.readZeroPageX, + fn: () => this.skp(this.readZeroPageX), mode: 'zeroPageX', }, 0x44: { name: 'SKB', - op: this.skp, - modeFn: this.readZeroPage, + fn: () => this.skp(this.readZeroPage), mode: 'zeroPage', }, 0x54: { name: 'SKB', - op: this.skp, - modeFn: this.readZeroPageX, + fn: () => this.skp(this.readZeroPageX), mode: 'zeroPageX', }, 0x64: { name: 'SKB', - op: this.skp, - modeFn: this.readZeroPage, + fn: () => this.skp(this.readZeroPage), mode: 'zeroPage', }, 0x74: { name: 'SKB', - op: this.skp, - modeFn: this.readZeroPageX, + fn: () => this.skp(this.readZeroPageX), mode: 'zeroPageX', }, 0xd4: { name: 'SKB', - op: this.skp, - modeFn: this.readZeroPageX, + fn: () => this.skp(this.readZeroPageX), mode: 'zeroPageX', }, 0xf4: { name: 'SKB', - op: this.skp, - modeFn: this.readZeroPageX, + fn: () => this.skp(this.readZeroPageX), mode: 'zeroPageX', }, // SKW 0x0c: { name: 'SKW', - op: this.skp, - modeFn: this.readAddrAbsolute, + fn: () => this.skp(this.readAddrAbsolute), mode: 'absolute', }, 0x1c: { name: 'SKW', - op: this.skp, - modeFn: this.readAddrAbsoluteX, + fn: () => this.skp(this.readAddrAbsoluteX), mode: 'absoluteX', }, 0x3c: { name: 'SKW', - op: this.skp, - modeFn: this.readAddrAbsoluteX, + fn: () => this.skp(this.readAddrAbsoluteX), mode: 'absoluteX', }, 0x5c: { name: 'SKW', - op: this.skp, - modeFn: this.readAddrAbsoluteX, + fn: () => this.skp(this.readAddrAbsoluteX), mode: 'absoluteX', }, 0x7c: { name: 'SKW', - op: this.skp, - modeFn: this.readAddrAbsoluteX, + fn: () => this.skp(this.readAddrAbsoluteX), mode: 'absoluteX', }, 0xdc: { name: 'SKW', - op: this.skp, - modeFn: this.readAddrAbsoluteX, + fn: () => this.skp(this.readAddrAbsoluteX), mode: 'absoluteX', }, 0xfc: { name: 'SKW', - op: this.skp, - modeFn: this.readAddrAbsoluteX, + fn: () => this.skp(this.readAddrAbsoluteX), mode: 'absoluteX', }, // HLT 0x02: { name: 'HLT', - op: this.hlt, - modeFn: this.readNopImplied, + fn: () => this.hlt(this.readNopImplied), mode: 'implied', }, 0x12: { name: 'HLT', - op: this.hlt, - modeFn: this.readNopImplied, + fn: () => this.hlt(this.readNopImplied), mode: 'implied', }, 0x22: { name: 'HLT', - op: this.hlt, - modeFn: this.readNopImplied, + fn: () => this.hlt(this.readNopImplied), mode: 'implied', }, 0x32: { name: 'HLT', - op: this.hlt, - modeFn: this.readNopImplied, + fn: () => this.hlt(this.readNopImplied), mode: 'implied', }, 0x42: { name: 'HLT', - op: this.hlt, - modeFn: this.readNopImplied, + fn: () => this.hlt(this.readNopImplied), mode: 'implied', }, 0x52: { name: 'HLT', - op: this.hlt, - modeFn: this.readNopImplied, + fn: () => this.hlt(this.readNopImplied), mode: 'implied', }, 0x62: { name: 'HLT', - op: this.hlt, - modeFn: this.readNopImplied, + fn: () => this.hlt(this.readNopImplied), mode: 'implied', }, 0x72: { name: 'HLT', - op: this.hlt, - modeFn: this.readNopImplied, + fn: () => this.hlt(this.readNopImplied), mode: 'implied', }, 0x92: { name: 'HLT', - op: this.hlt, - modeFn: this.readNopImplied, + fn: () => this.hlt(this.readNopImplied), mode: 'implied', }, 0xb2: { name: 'HLT', - op: this.hlt, - modeFn: this.readNopImplied, + fn: () => this.hlt(this.readNopImplied), mode: 'implied', }, 0xd2: { name: 'HLT', - op: this.hlt, - modeFn: this.readNopImplied, + fn: () => this.hlt(this.readNopImplied), mode: 'implied', }, 0xf2: { name: 'HLT', - op: this.hlt, - modeFn: this.readNopImplied, + fn: () => this.hlt(this.readNopImplied), mode: 'implied', }, // TAS 0x9b: { name: 'TAS', - op: this.tas, - modeFn: this.readAddrAbsoluteY, + fn: () => this.tas(this.readAddrAbsoluteY), mode: 'absoluteY', }, // SAY 0x9c: { name: 'SAY', - op: this.say, - modeFn: this.readAddrAbsoluteX, + fn: () => this.say(this.readAddrAbsoluteX), mode: 'absoluteX', }, // XAS 0x9e: { name: 'XAS', - op: this.xas, - modeFn: this.readAddrAbsoluteY, + fn: () => this.xas(this.readAddrAbsoluteY), mode: 'absoluteY', }, // AXA 0x9f: { name: 'AXA', - op: this.axa, - modeFn: this.readAddrAbsoluteY, + fn: () => this.axa(this.readAddrAbsoluteY), mode: 'absoluteY', }, 0x93: { name: 'AXA', - op: this.axa, - modeFn: this.readAddrZeroPageIndirectY, + fn: () => this.axa(this.readAddrZeroPageIndirectY), mode: 'zeroPageIndirectY', }, // ANC 0x2b: { name: 'ANC', - op: this.anc, - modeFn: this.readImmediate, + fn: () => this.anc(this.readImmediate), mode: 'immediate', }, 0x0b: { name: 'ANC', - op: this.anc, - modeFn: this.readImmediate, + fn: () => this.anc(this.readImmediate), mode: 'immediate', }, // LAS 0xbb: { name: 'LAS', - op: this.las, - modeFn: this.readAbsoluteY, + fn: () => this.las(this.readAbsoluteY), mode: 'absoluteY', }, // SBC 0xeb: { name: 'SBC', - op: this.sbc, - modeFn: this.readImmediate, + fn: () => this.sbc(this.readImmediate), mode: 'immediate', }, }; OPS_ROCKWELL_65C02: Instructions = { - 0xcb: { name: 'NOP', op: this.nop, modeFn: this.implied, mode: 'implied' }, + 0xcb: { name: 'NOP', fn: () => this.nop(this.implied), mode: 'implied' }, 0xdb: { name: 'NOP', - op: this.nop, - modeFn: this.readZeroPageX, + fn: () => this.nop(this.readZeroPageX), mode: 'immediate', }, }; @@ -3411,7 +3247,7 @@ export default class CPU6502 { /* WDC 65C02 Instructions */ OPS_WDC_65C02: Instructions = { - 0xcb: { name: 'WAI', op: this.wai, modeFn: this.implied, mode: 'implied' }, - 0xdb: { name: 'STP', op: this.stp, modeFn: this.implied, mode: 'implied' }, + 0xcb: { name: 'WAI', fn: () => this.wai(), mode: 'implied' }, + 0xdb: { name: 'STP', fn: () => this.stp(), mode: 'implied' }, }; } diff --git a/js/ui/keyboard.ts b/js/ui/keyboard.ts index d4c1985..a75a2ce 100644 --- a/js/ui/keyboard.ts +++ b/js/ui/keyboard.ts @@ -214,19 +214,17 @@ export class KeyBoard { return span; } - const _mouseup = ( - event: MouseEvent & { - currentTarget: HTMLElement; + const _mouseup = (event: Event) => { + if (!(event.currentTarget instanceof HTMLElement)) { + return; } - ) => { event.currentTarget.classList.remove('pressed'); }; - const _mousedown = ( - event: MouseEvent & { - currentTarget: HTMLElement; + const _mousedown = (event: Event) => { + if (!(event.currentTarget instanceof HTMLElement)) { + return; } - ) => { event.currentTarget.classList.add('pressed'); let key = event.currentTarget.dataset[this.shifted ? 'key2' : 'key1']; if (!key) { @@ -262,7 +260,7 @@ export class KeyBoard { case 'SHIFT': this.shifted = !this.shifted; this.kb - .querySelectorAll('.key-SHIFT') + .querySelectorAll('.key-SHIFT') .forEach(function (el: HTMLElement) { el.classList.toggle('active'); }); diff --git a/tsconfig.json b/tsconfig.json index c394e48..ad68421 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,15 +8,13 @@ "allowSyntheticDefaultImports": true, "target": "es6", "lib": ["DOM", "ES6"], - "noImplicitAny": true, - "noImplicitThis": true, + "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "exactOptionalPropertyTypes": true, "moduleResolution": "node", "resolveJsonModule": true, "sourceMap": true, - "strictNullChecks": true, "outDir": "dist", "baseUrl": ".", "allowJs": true,