mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-01-23 12:29:53 +00:00
2116 lines
66 KiB
JavaScript
2116 lines
66 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.MOS6502 = exports.MOS6502Interrupts = exports._MOS6502 = void 0;
|
|
// Copyright 2015 by Paulo Augusto Peccin. See license.txt distributed with this file.
|
|
var _MOS6502 = function () {
|
|
var self = this;
|
|
this.powerOn = function () {
|
|
this.reset();
|
|
};
|
|
this.powerOff = function () {
|
|
};
|
|
this.clockPulse = function () {
|
|
if (!RDY)
|
|
return; // TODO Should be ignored in the last cycle of the instruction
|
|
T++;
|
|
instruction[T]();
|
|
};
|
|
this.connectBus = function (aBus) {
|
|
bus = aBus;
|
|
};
|
|
this.setRDY = function (boo) {
|
|
RDY = boo;
|
|
};
|
|
this.isRDY = function () {
|
|
return RDY;
|
|
};
|
|
this.reset = function () {
|
|
I = 1;
|
|
T = -1;
|
|
instruction = [fetchOpcodeAndDecodeInstruction]; // Bootstrap instruction
|
|
PC = bus.read(RESET_VECTOR) | (bus.read(RESET_VECTOR + 1) << 8);
|
|
this.setRDY(true);
|
|
};
|
|
// Interfaces
|
|
var bus;
|
|
var RDY = false;
|
|
// Registers
|
|
var PC = 0;
|
|
var SP = 0;
|
|
var A = 0;
|
|
var X = 0;
|
|
var Y = 0;
|
|
// Status Bits
|
|
var N = 0;
|
|
var V = 0;
|
|
var D = 0;
|
|
var I = 0;
|
|
var Z = 0;
|
|
var C = 0;
|
|
// Internal decoding registers
|
|
var T = -1;
|
|
var opcode = -1;
|
|
var instruction;
|
|
var data = 0;
|
|
var AD = 0;
|
|
var BA = 0;
|
|
var BALCrossed = false;
|
|
var IA = 0;
|
|
var branchOffset = 0;
|
|
var branchOffsetCrossAdjust = 0;
|
|
// Vectors
|
|
const NMI_VECTOR = 0xfffa;
|
|
const RESET_VECTOR = 0xfffc;
|
|
const IRQ_VECTOR = 0xfffe;
|
|
// Index registers names
|
|
const rX = 0;
|
|
const rY = 1;
|
|
// Status bits names
|
|
const bN = 7;
|
|
const bV = 6;
|
|
// const bE = 5; // Not used
|
|
// const bB = 4; // Not used
|
|
// const bD = 3; // Not used
|
|
// const bI = 2; // Not used
|
|
const bZ = 1;
|
|
const bC = 0;
|
|
// Auxiliary variables
|
|
// TODO
|
|
//noinspection JSUnusedGlobalSymbols
|
|
this.debug = false;
|
|
//noinspection JSUnusedGlobalSymbols
|
|
this.trace = false;
|
|
// Internal operations
|
|
var fetchOpcodeAndDecodeInstruction = function () {
|
|
opcode = bus.read(PC);
|
|
instruction = instructions[opcode];
|
|
T = 0;
|
|
// if (self.trace) self.breakpoint("TRACE");
|
|
// console.log("PC: " + PC + ", op: " + opcode + ": " + opcodes[opcode]);
|
|
PC++;
|
|
};
|
|
var fetchNextOpcode = fetchOpcodeAndDecodeInstruction;
|
|
var fetchOpcodeAndDiscard = function () {
|
|
bus.read(PC);
|
|
};
|
|
var fetchBranchOffset = function () {
|
|
branchOffset = bus.read(PC);
|
|
PC++;
|
|
};
|
|
var fetchADL = function () {
|
|
AD = bus.read(PC);
|
|
PC++;
|
|
};
|
|
var fetchADH = function () {
|
|
AD |= bus.read(PC) << 8;
|
|
PC++;
|
|
};
|
|
var fetchADLFromBA = function () {
|
|
AD = bus.read(BA);
|
|
};
|
|
var fetchADHFromBA = function () {
|
|
AD |= bus.read(BA) << 8;
|
|
};
|
|
var fetchBAL = function () {
|
|
BA = bus.read(PC);
|
|
PC++;
|
|
};
|
|
var fetchBAH = function () {
|
|
BA |= bus.read(PC) << 8;
|
|
PC++;
|
|
};
|
|
var fetchBALFromIA = function () {
|
|
BA = bus.read(IA);
|
|
};
|
|
var fetchBAHFromIA = function () {
|
|
BA |= bus.read(IA) << 8;
|
|
};
|
|
var addXtoBAL = function () {
|
|
var low = (BA & 255) + X;
|
|
BALCrossed = low > 255;
|
|
BA = (BA & 0xff00) | (low & 255);
|
|
};
|
|
var addYtoBAL = function () {
|
|
var low = (BA & 255) + Y;
|
|
BALCrossed = low > 255;
|
|
BA = (BA & 0xff00) | (low & 255);
|
|
};
|
|
var add1toBAL = function () {
|
|
var low = (BA & 255) + 1;
|
|
BALCrossed = low > 255;
|
|
BA = (BA & 0xff00) | (low & 255);
|
|
};
|
|
var add1toBAHifBALCrossed = function () {
|
|
if (BALCrossed)
|
|
BA = (BA + 0x0100) & 0xffff;
|
|
};
|
|
var fetchIAL = function () {
|
|
IA = bus.read(PC);
|
|
PC++;
|
|
};
|
|
var fetchIAH = function () {
|
|
IA |= bus.read(PC) << 8;
|
|
PC++;
|
|
};
|
|
var add1toIAL = function () {
|
|
var low = (IA & 255) + 1;
|
|
IA = (IA & 0xff00) | (low & 255);
|
|
};
|
|
var fetchDataFromImmediate = function () {
|
|
data = bus.read(PC);
|
|
PC++;
|
|
};
|
|
var fetchDataFromAD = function () {
|
|
data = bus.read(AD);
|
|
};
|
|
var fetchDataFromBA = function () {
|
|
data = bus.read(BA);
|
|
};
|
|
var writeDataToAD = function () {
|
|
bus.write(AD, data);
|
|
};
|
|
var writeDataToBA = function () {
|
|
bus.write(BA, data);
|
|
};
|
|
var addBranchOffsetToPCL = function () {
|
|
var oldLow = (PC & 0x00ff);
|
|
var newLow = (oldLow + branchOffset) & 255;
|
|
// Negative offset?
|
|
if (branchOffset > 127)
|
|
branchOffsetCrossAdjust = (newLow > oldLow) ? -0x0100 : 0;
|
|
else
|
|
branchOffsetCrossAdjust = (newLow < oldLow) ? 0x0100 : 0;
|
|
PC = (PC & 0xff00) | newLow;
|
|
};
|
|
var adjustPCHForBranchOffsetCross = function () {
|
|
PC = (PC + branchOffsetCrossAdjust) & 0xffff;
|
|
};
|
|
var setZ = function (val) {
|
|
Z = (val === 0) ? 1 : 0;
|
|
};
|
|
var setN = function (val) {
|
|
N = (val & 0x080) ? 1 : 0;
|
|
};
|
|
var setV = function (boo) {
|
|
V = boo ? 1 : 0;
|
|
};
|
|
var setC = function (boo) {
|
|
C = boo ? 1 : 0;
|
|
};
|
|
var popFromStack = function () {
|
|
SP = (SP + 1) & 255;
|
|
return bus.read(0x0100 + SP);
|
|
};
|
|
var peekFromStack = function () {
|
|
return bus.read(0x0100 + SP);
|
|
};
|
|
var pushToStack = function (val) {
|
|
bus.write(0x0100 + SP, val);
|
|
SP = (SP - 1) & 255;
|
|
};
|
|
var getStatusBits = function () {
|
|
return N << 7 | V << 6 | 0x30 // Always push with E (bit 5) and B (bit 4) ON
|
|
| D << 3 | I << 2 | Z << 1 | C;
|
|
};
|
|
var setStatusBits = function (val) {
|
|
N = val >>> 7;
|
|
V = val >>> 6 & 1; // E and B flags actually do not exist as real flags, so ignore
|
|
D = val >>> 3 & 1;
|
|
I = val >>> 2 & 1;
|
|
Z = val >>> 1 & 1;
|
|
C = val & 1;
|
|
};
|
|
var illegalOpcode = function (op) {
|
|
if (self.debug)
|
|
self.breakpoint("Illegal Opcode: " + op);
|
|
};
|
|
// Addressing routines
|
|
var implied = function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchOpcodeAndDiscard,
|
|
function () {
|
|
operation();
|
|
fetchNextOpcode();
|
|
}
|
|
];
|
|
};
|
|
var immediateRead = function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchDataFromImmediate,
|
|
function () {
|
|
operation();
|
|
fetchNextOpcode();
|
|
}
|
|
];
|
|
};
|
|
var zeroPageRead = function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchADL, // ADH will be zero
|
|
fetchDataFromAD,
|
|
function () {
|
|
operation();
|
|
fetchNextOpcode();
|
|
}
|
|
];
|
|
};
|
|
var absoluteRead = function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchADL,
|
|
fetchADH,
|
|
fetchDataFromAD,
|
|
function () {
|
|
operation();
|
|
fetchNextOpcode();
|
|
}
|
|
];
|
|
};
|
|
var indirectXRead = function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchBAL, // BAH will be zero
|
|
fetchDataFromBA,
|
|
function () {
|
|
addXtoBAL();
|
|
fetchADLFromBA();
|
|
},
|
|
function () {
|
|
add1toBAL();
|
|
fetchADHFromBA();
|
|
},
|
|
fetchDataFromAD,
|
|
function () {
|
|
operation();
|
|
fetchNextOpcode();
|
|
}
|
|
];
|
|
};
|
|
var absoluteIndexedRead = function (index) {
|
|
var addIndex = index === rX ? addXtoBAL : addYtoBAL;
|
|
return function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchBAL,
|
|
fetchBAH,
|
|
function () {
|
|
addIndex();
|
|
fetchDataFromBA();
|
|
add1toBAHifBALCrossed();
|
|
},
|
|
function () {
|
|
if (BALCrossed) {
|
|
fetchDataFromBA();
|
|
}
|
|
else {
|
|
operation();
|
|
fetchNextOpcode();
|
|
}
|
|
},
|
|
function () {
|
|
operation();
|
|
fetchNextOpcode();
|
|
}
|
|
];
|
|
};
|
|
};
|
|
var zeroPageIndexedRead = function (index) {
|
|
var addIndex = index === rX ? addXtoBAL : addYtoBAL;
|
|
return function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchBAL, // BAH will be zero
|
|
fetchDataFromBA,
|
|
function () {
|
|
addIndex();
|
|
fetchDataFromBA();
|
|
},
|
|
function () {
|
|
operation();
|
|
fetchNextOpcode();
|
|
}
|
|
];
|
|
};
|
|
};
|
|
var indirectYRead = function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchIAL, // IAH will be zero
|
|
fetchBALFromIA,
|
|
function () {
|
|
add1toIAL();
|
|
fetchBAHFromIA();
|
|
},
|
|
function () {
|
|
addYtoBAL();
|
|
fetchDataFromBA();
|
|
add1toBAHifBALCrossed();
|
|
},
|
|
function () {
|
|
if (BALCrossed) {
|
|
fetchDataFromBA();
|
|
}
|
|
else {
|
|
operation();
|
|
fetchNextOpcode();
|
|
}
|
|
},
|
|
function () {
|
|
operation();
|
|
fetchNextOpcode();
|
|
}
|
|
];
|
|
};
|
|
var zeroPageWrite = function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchADL, // ADH will be zero
|
|
function () {
|
|
operation();
|
|
writeDataToAD();
|
|
},
|
|
fetchNextOpcode
|
|
];
|
|
};
|
|
var absoluteWrite = function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchADL,
|
|
fetchADH,
|
|
function () {
|
|
operation();
|
|
writeDataToAD();
|
|
},
|
|
fetchNextOpcode
|
|
];
|
|
};
|
|
var indirectXWrite = function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchBAL, // BAH will be zero
|
|
fetchDataFromBA,
|
|
function () {
|
|
addXtoBAL();
|
|
fetchADLFromBA();
|
|
},
|
|
function () {
|
|
add1toBAL();
|
|
fetchADHFromBA();
|
|
},
|
|
function () {
|
|
operation();
|
|
writeDataToAD();
|
|
},
|
|
fetchNextOpcode
|
|
];
|
|
};
|
|
var absoluteIndexedWrite = function (index) {
|
|
var addIndex = index === rX ? addXtoBAL : addYtoBAL;
|
|
return function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchBAL,
|
|
fetchBAH,
|
|
function () {
|
|
addIndex();
|
|
fetchDataFromBA();
|
|
add1toBAHifBALCrossed();
|
|
},
|
|
function () {
|
|
operation();
|
|
writeDataToBA();
|
|
},
|
|
fetchNextOpcode
|
|
];
|
|
};
|
|
};
|
|
var zeroPageIndexedWrite = function (index) {
|
|
var addIndex = index === rX ? addXtoBAL : addYtoBAL;
|
|
return function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchBAL, // BAH will be zero
|
|
fetchDataFromBA,
|
|
function () {
|
|
addIndex();
|
|
operation();
|
|
writeDataToBA();
|
|
},
|
|
fetchNextOpcode
|
|
];
|
|
};
|
|
};
|
|
var indirectYWrite = function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchIAL, // IAH will be zero
|
|
fetchBALFromIA,
|
|
function () {
|
|
add1toIAL();
|
|
fetchBAHFromIA();
|
|
},
|
|
function () {
|
|
addYtoBAL();
|
|
fetchDataFromBA();
|
|
add1toBAHifBALCrossed();
|
|
},
|
|
function () {
|
|
operation();
|
|
writeDataToBA();
|
|
},
|
|
fetchNextOpcode
|
|
];
|
|
};
|
|
var zeroPageReadModifyWrite = function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchADL, // ADH will be zero
|
|
fetchDataFromAD,
|
|
writeDataToAD,
|
|
function () {
|
|
operation();
|
|
writeDataToAD();
|
|
},
|
|
fetchNextOpcode
|
|
];
|
|
};
|
|
var absoluteReadModifyWrite = function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchADL,
|
|
fetchADH,
|
|
fetchDataFromAD,
|
|
writeDataToAD,
|
|
function () {
|
|
operation();
|
|
writeDataToAD();
|
|
},
|
|
fetchNextOpcode
|
|
];
|
|
};
|
|
var zeroPageIndexedReadModifyWrite = function (index) {
|
|
var addIndex = index === rX ? addXtoBAL : addYtoBAL;
|
|
return function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchBAL, // BAH will be zero
|
|
fetchDataFromBA,
|
|
function () {
|
|
addIndex();
|
|
fetchDataFromBA();
|
|
},
|
|
writeDataToBA,
|
|
function () {
|
|
operation();
|
|
writeDataToBA();
|
|
},
|
|
fetchNextOpcode
|
|
];
|
|
};
|
|
};
|
|
var absoluteIndexedReadModifyWrite = function (index) {
|
|
var addIndex = index === rX ? addXtoBAL : addYtoBAL;
|
|
return function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchBAL,
|
|
fetchBAH,
|
|
function () {
|
|
addIndex();
|
|
fetchDataFromBA();
|
|
add1toBAHifBALCrossed();
|
|
},
|
|
fetchDataFromBA,
|
|
writeDataToBA,
|
|
function () {
|
|
operation();
|
|
writeDataToBA();
|
|
},
|
|
fetchNextOpcode
|
|
];
|
|
};
|
|
};
|
|
var indirectXReadModifyWrite = function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchBAL, // BAH will be zero
|
|
fetchDataFromBA,
|
|
function () {
|
|
addXtoBAL();
|
|
fetchADLFromBA();
|
|
},
|
|
function () {
|
|
add1toBAL();
|
|
fetchADHFromBA();
|
|
},
|
|
fetchDataFromAD,
|
|
writeDataToAD,
|
|
function () {
|
|
operation();
|
|
writeDataToAD();
|
|
},
|
|
fetchNextOpcode
|
|
];
|
|
};
|
|
var indirectYReadModifyWrite = function (operation) {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchIAL, // IAH will be zero
|
|
fetchBALFromIA,
|
|
function () {
|
|
add1toIAL();
|
|
fetchBAHFromIA();
|
|
},
|
|
function () {
|
|
addYtoBAL();
|
|
fetchDataFromBA();
|
|
add1toBAHifBALCrossed();
|
|
},
|
|
fetchDataFromBA,
|
|
writeDataToBA,
|
|
function () {
|
|
operation();
|
|
writeDataToBA();
|
|
},
|
|
fetchNextOpcode
|
|
];
|
|
};
|
|
// Instructions ========================================================================================
|
|
// Complete instruction set
|
|
var opcodes = new Array(256);
|
|
var instructions = new Array(256);
|
|
opcodes[0x00] = "BRK";
|
|
instructions[0x00] = BRK();
|
|
opcodes[0x01] = "ORA";
|
|
instructions[0x01] = ORA(indirectXRead);
|
|
opcodes[0x02] = "uKIL";
|
|
instructions[0x02] = uKIL();
|
|
opcodes[0x03] = "uSLO";
|
|
instructions[0x03] = uSLO(indirectXReadModifyWrite);
|
|
opcodes[0x04] = "uNOP";
|
|
instructions[0x04] = uNOP(zeroPageRead);
|
|
opcodes[0x05] = "ORA";
|
|
instructions[0x05] = ORA(zeroPageRead);
|
|
opcodes[0x06] = "ASL";
|
|
instructions[0x06] = ASL(zeroPageReadModifyWrite);
|
|
opcodes[0x07] = "uSLO";
|
|
instructions[0x07] = uSLO(zeroPageReadModifyWrite);
|
|
opcodes[0x08] = "PHP";
|
|
instructions[0x08] = PHP();
|
|
opcodes[0x09] = "ORA";
|
|
instructions[0x09] = ORA(immediateRead);
|
|
opcodes[0x0a] = "ASL";
|
|
instructions[0x0a] = ASL_ACC();
|
|
opcodes[0x0b] = "uANC";
|
|
instructions[0x0b] = uANC(immediateRead);
|
|
opcodes[0x0c] = "uNOP";
|
|
instructions[0x0c] = uNOP(absoluteRead);
|
|
opcodes[0x0d] = "ORA";
|
|
instructions[0x0d] = ORA(absoluteRead);
|
|
opcodes[0x0e] = "ASL";
|
|
instructions[0x0e] = ASL(absoluteReadModifyWrite);
|
|
opcodes[0x0f] = "uSLO";
|
|
instructions[0x0f] = uSLO(absoluteReadModifyWrite);
|
|
opcodes[0x10] = "BPL";
|
|
instructions[0x10] = Bxx(bN, 0); // BPL
|
|
opcodes[0x11] = "ORA";
|
|
instructions[0x11] = ORA(indirectYRead);
|
|
opcodes[0x12] = "uKIL";
|
|
instructions[0x12] = uKIL();
|
|
opcodes[0x13] = "uSLO";
|
|
instructions[0x13] = uSLO(indirectYReadModifyWrite);
|
|
opcodes[0x14] = "uNOP";
|
|
instructions[0x14] = uNOP(zeroPageIndexedRead(rX));
|
|
opcodes[0x15] = "ORA";
|
|
instructions[0x15] = ORA(zeroPageIndexedRead(rX));
|
|
opcodes[0x16] = "ASL";
|
|
instructions[0x16] = ASL(zeroPageIndexedReadModifyWrite(rX));
|
|
opcodes[0x17] = "uSLO";
|
|
instructions[0x17] = uSLO(zeroPageIndexedReadModifyWrite(rX));
|
|
opcodes[0x18] = "CLC";
|
|
instructions[0x18] = CLC();
|
|
opcodes[0x19] = "ORA";
|
|
instructions[0x19] = ORA(absoluteIndexedRead(rY));
|
|
opcodes[0x1a] = "uNOP";
|
|
instructions[0x1a] = uNOP(implied);
|
|
opcodes[0x1b] = "uSLO";
|
|
instructions[0x1b] = uSLO(absoluteIndexedReadModifyWrite(rY));
|
|
opcodes[0x1c] = "uNOP";
|
|
instructions[0x1c] = uNOP(absoluteIndexedRead(rX));
|
|
opcodes[0x1d] = "ORA";
|
|
instructions[0x1d] = ORA(absoluteIndexedRead(rX));
|
|
opcodes[0x1e] = "ASL";
|
|
instructions[0x1e] = ASL(absoluteIndexedReadModifyWrite(rX));
|
|
opcodes[0x1f] = "uSLO";
|
|
instructions[0x1f] = uSLO(absoluteIndexedReadModifyWrite(rX));
|
|
opcodes[0x20] = "JSR";
|
|
instructions[0x20] = JSR();
|
|
opcodes[0x21] = "AND";
|
|
instructions[0x21] = AND(indirectXRead);
|
|
opcodes[0x22] = "uKIL";
|
|
instructions[0x22] = uKIL();
|
|
opcodes[0x23] = "uRLA";
|
|
instructions[0x23] = uRLA(indirectXReadModifyWrite);
|
|
opcodes[0x24] = "BIT";
|
|
instructions[0x24] = BIT(zeroPageRead);
|
|
opcodes[0x25] = "AND";
|
|
instructions[0x25] = AND(zeroPageRead);
|
|
opcodes[0x26] = "ROL";
|
|
instructions[0x26] = ROL(zeroPageReadModifyWrite);
|
|
opcodes[0x27] = "uRLA";
|
|
instructions[0x27] = uRLA(zeroPageReadModifyWrite);
|
|
opcodes[0x28] = "PLP";
|
|
instructions[0x28] = PLP();
|
|
opcodes[0x29] = "AND";
|
|
instructions[0x29] = AND(immediateRead);
|
|
opcodes[0x2a] = "ROL";
|
|
instructions[0x2a] = ROL_ACC();
|
|
opcodes[0x2b] = "uANC";
|
|
instructions[0x2b] = uANC(immediateRead);
|
|
opcodes[0x2c] = "BIT";
|
|
instructions[0x2c] = BIT(absoluteRead);
|
|
opcodes[0x2d] = "AND";
|
|
instructions[0x2d] = AND(absoluteRead);
|
|
opcodes[0x2e] = "ROL";
|
|
instructions[0x2e] = ROL(absoluteReadModifyWrite);
|
|
opcodes[0x2f] = "uRLA";
|
|
instructions[0x2f] = uRLA(absoluteReadModifyWrite);
|
|
opcodes[0x30] = "BMI";
|
|
instructions[0x30] = Bxx(bN, 1); // BMI
|
|
opcodes[0x31] = "AND";
|
|
instructions[0x31] = AND(indirectYRead);
|
|
opcodes[0x32] = "uKIL";
|
|
instructions[0x32] = uKIL();
|
|
opcodes[0x33] = "uRLA";
|
|
instructions[0x33] = uRLA(indirectYReadModifyWrite);
|
|
opcodes[0x34] = "uNOP";
|
|
instructions[0x34] = uNOP(zeroPageIndexedRead(rX));
|
|
opcodes[0x35] = "AND";
|
|
instructions[0x35] = AND(zeroPageIndexedRead(rX));
|
|
opcodes[0x36] = "ROL";
|
|
instructions[0x36] = ROL(zeroPageIndexedReadModifyWrite(rX));
|
|
opcodes[0x37] = "uRLA";
|
|
instructions[0x37] = uRLA(zeroPageIndexedReadModifyWrite(rX));
|
|
opcodes[0x38] = "SEC";
|
|
instructions[0x38] = SEC();
|
|
opcodes[0x39] = "AND";
|
|
instructions[0x39] = AND(absoluteIndexedRead(rY));
|
|
opcodes[0x3a] = "uNOP";
|
|
instructions[0x3a] = uNOP(implied);
|
|
opcodes[0x3b] = "uRLA";
|
|
instructions[0x3b] = uRLA(absoluteIndexedReadModifyWrite(rY));
|
|
opcodes[0x3c] = "uNOP";
|
|
instructions[0x3c] = uNOP(absoluteIndexedRead(rX));
|
|
opcodes[0x3d] = "AND";
|
|
instructions[0x3d] = AND(absoluteIndexedRead(rX));
|
|
opcodes[0x3e] = "ROL";
|
|
instructions[0x3e] = ROL(absoluteIndexedReadModifyWrite(rX));
|
|
opcodes[0x3f] = "uRLA";
|
|
instructions[0x3f] = uRLA(absoluteIndexedReadModifyWrite(rX));
|
|
opcodes[0x40] = "RTI";
|
|
instructions[0x40] = RTI();
|
|
opcodes[0x41] = "EOR";
|
|
instructions[0x41] = EOR(indirectXRead);
|
|
opcodes[0x42] = "uKIL";
|
|
instructions[0x42] = uKIL();
|
|
opcodes[0x43] = "uSRE";
|
|
instructions[0x43] = uSRE(indirectXReadModifyWrite);
|
|
opcodes[0x44] = "uNOP";
|
|
instructions[0x44] = uNOP(zeroPageRead);
|
|
opcodes[0x45] = "EOR";
|
|
instructions[0x45] = EOR(zeroPageRead);
|
|
opcodes[0x46] = "LSR";
|
|
instructions[0x46] = LSR(zeroPageReadModifyWrite);
|
|
opcodes[0x47] = "uSRE";
|
|
instructions[0x47] = uSRE(zeroPageReadModifyWrite);
|
|
opcodes[0x48] = "PHA";
|
|
instructions[0x48] = PHA();
|
|
opcodes[0x49] = "EOR";
|
|
instructions[0x49] = EOR(immediateRead);
|
|
opcodes[0x4a] = "LSR";
|
|
instructions[0x4a] = LSR_ACC();
|
|
opcodes[0x4b] = "uASR";
|
|
instructions[0x4b] = uASR(immediateRead);
|
|
opcodes[0x4c] = "JMP";
|
|
instructions[0x4c] = JMP_ABS();
|
|
opcodes[0x4d] = "EOR";
|
|
instructions[0x4d] = EOR(absoluteRead);
|
|
opcodes[0x4e] = "LSR";
|
|
instructions[0x4e] = LSR(absoluteReadModifyWrite);
|
|
opcodes[0x4f] = "uSRE";
|
|
instructions[0x4f] = uSRE(absoluteReadModifyWrite);
|
|
opcodes[0x50] = "BVC";
|
|
instructions[0x50] = Bxx(bV, 0); // BVC
|
|
opcodes[0x51] = "EOR";
|
|
instructions[0x51] = EOR(indirectYRead);
|
|
opcodes[0x52] = "uKIL";
|
|
instructions[0x52] = uKIL();
|
|
opcodes[0x53] = "uSRE";
|
|
instructions[0x53] = uSRE(indirectYReadModifyWrite);
|
|
opcodes[0x54] = "uNOP";
|
|
instructions[0x54] = uNOP(zeroPageIndexedRead(rX));
|
|
opcodes[0x55] = "EOR";
|
|
instructions[0x55] = EOR(zeroPageIndexedRead(rX));
|
|
opcodes[0x56] = "LSR";
|
|
instructions[0x56] = LSR(zeroPageIndexedReadModifyWrite(rX));
|
|
opcodes[0x57] = "uSRE";
|
|
instructions[0x57] = uSRE(zeroPageIndexedReadModifyWrite(rX));
|
|
opcodes[0x58] = "CLI";
|
|
instructions[0x58] = CLI();
|
|
opcodes[0x59] = "EOR";
|
|
instructions[0x59] = EOR(absoluteIndexedRead(rY));
|
|
opcodes[0x5a] = "uNOP";
|
|
instructions[0x5a] = uNOP(implied);
|
|
opcodes[0x5b] = "uSRE";
|
|
instructions[0x5b] = uSRE(absoluteIndexedReadModifyWrite(rY));
|
|
opcodes[0x5c] = "uNOP";
|
|
instructions[0x5c] = uNOP(absoluteIndexedRead(rX));
|
|
opcodes[0x5d] = "EOR";
|
|
instructions[0x5d] = EOR(absoluteIndexedRead(rX));
|
|
opcodes[0x5e] = "LSR";
|
|
instructions[0x5e] = LSR(absoluteIndexedReadModifyWrite(rX));
|
|
opcodes[0x5f] = "uSRE";
|
|
instructions[0x5f] = uSRE(absoluteIndexedReadModifyWrite(rX));
|
|
opcodes[0x60] = "RTS";
|
|
instructions[0x60] = RTS();
|
|
opcodes[0x61] = "ADC";
|
|
instructions[0x61] = ADC(indirectXRead);
|
|
opcodes[0x62] = "uKIL";
|
|
instructions[0x62] = uKIL();
|
|
opcodes[0x63] = "uRRA";
|
|
instructions[0x63] = uRRA(indirectXReadModifyWrite);
|
|
opcodes[0x64] = "uNOP";
|
|
instructions[0x64] = uNOP(zeroPageRead);
|
|
opcodes[0x65] = "ADC";
|
|
instructions[0x65] = ADC(zeroPageRead);
|
|
opcodes[0x66] = "ROR";
|
|
instructions[0x66] = ROR(zeroPageReadModifyWrite);
|
|
opcodes[0x67] = "uRRA";
|
|
instructions[0x67] = uRRA(zeroPageReadModifyWrite);
|
|
opcodes[0x68] = "PLA";
|
|
instructions[0x68] = PLA();
|
|
opcodes[0x69] = "ADC";
|
|
instructions[0x69] = ADC(immediateRead);
|
|
opcodes[0x6a] = "ROR";
|
|
instructions[0x6a] = ROR_ACC();
|
|
opcodes[0x6b] = "uARR";
|
|
instructions[0x6b] = uARR(immediateRead);
|
|
opcodes[0x6c] = "JMP";
|
|
instructions[0x6c] = JMP_IND();
|
|
opcodes[0x6d] = "ADC";
|
|
instructions[0x6d] = ADC(absoluteRead);
|
|
opcodes[0x6e] = "ROR";
|
|
instructions[0x6e] = ROR(absoluteReadModifyWrite);
|
|
opcodes[0x6f] = "uRRA";
|
|
instructions[0x6f] = uRRA(absoluteReadModifyWrite);
|
|
opcodes[0x70] = "BVS";
|
|
instructions[0x70] = Bxx(bV, 1); // BVS
|
|
opcodes[0x71] = "ADC";
|
|
instructions[0x71] = ADC(indirectYRead);
|
|
opcodes[0x72] = "uKIL";
|
|
instructions[0x72] = uKIL();
|
|
opcodes[0x73] = "uRRA";
|
|
instructions[0x73] = uRRA(indirectYReadModifyWrite);
|
|
opcodes[0x74] = "uNOP";
|
|
instructions[0x74] = uNOP(zeroPageIndexedRead(rX));
|
|
opcodes[0x75] = "ADC";
|
|
instructions[0x75] = ADC(zeroPageIndexedRead(rX));
|
|
opcodes[0x76] = "ROR";
|
|
instructions[0x76] = ROR(zeroPageIndexedReadModifyWrite(rX));
|
|
opcodes[0x77] = "uRRA";
|
|
instructions[0x77] = uRRA(zeroPageIndexedReadModifyWrite(rX));
|
|
opcodes[0x78] = "SEI";
|
|
instructions[0x78] = SEI();
|
|
opcodes[0x79] = "ADC";
|
|
instructions[0x79] = ADC(absoluteIndexedRead(rY));
|
|
opcodes[0x7a] = "uNOP";
|
|
instructions[0x7a] = uNOP(implied);
|
|
opcodes[0x7b] = "uRRA";
|
|
instructions[0x7b] = uRRA(absoluteIndexedReadModifyWrite(rY));
|
|
opcodes[0x7c] = "uNOP";
|
|
instructions[0x7c] = uNOP(absoluteIndexedRead(rX));
|
|
opcodes[0x7d] = "ADC";
|
|
instructions[0x7d] = ADC(absoluteIndexedRead(rX));
|
|
opcodes[0x7e] = "ROR";
|
|
instructions[0x7e] = ROR(absoluteIndexedReadModifyWrite(rX));
|
|
opcodes[0x7f] = "uRRA";
|
|
instructions[0x7f] = uRRA(absoluteIndexedReadModifyWrite(rX));
|
|
opcodes[0x80] = "uNOP";
|
|
instructions[0x80] = uNOP(immediateRead);
|
|
opcodes[0x81] = "STA";
|
|
instructions[0x81] = STA(indirectXWrite);
|
|
opcodes[0x82] = "uNOP";
|
|
instructions[0x82] = uNOP(immediateRead);
|
|
opcodes[0x83] = "uSAX";
|
|
instructions[0x83] = uSAX(indirectXWrite);
|
|
opcodes[0x84] = "STY";
|
|
instructions[0x84] = STY(zeroPageWrite);
|
|
opcodes[0x85] = "STA";
|
|
instructions[0x85] = STA(zeroPageWrite);
|
|
opcodes[0x86] = "STX";
|
|
instructions[0x86] = STX(zeroPageWrite);
|
|
opcodes[0x87] = "uSAX";
|
|
instructions[0x87] = uSAX(zeroPageWrite);
|
|
opcodes[0x88] = "DEY";
|
|
instructions[0x88] = DEY();
|
|
opcodes[0x89] = "uNOP";
|
|
instructions[0x89] = uNOP(immediateRead);
|
|
opcodes[0x8a] = "TXA";
|
|
instructions[0x8a] = TXA();
|
|
opcodes[0x8b] = "uANE";
|
|
instructions[0x8b] = uANE(immediateRead);
|
|
opcodes[0x8c] = "STY";
|
|
instructions[0x8c] = STY(absoluteWrite);
|
|
opcodes[0x8d] = "STA";
|
|
instructions[0x8d] = STA(absoluteWrite);
|
|
opcodes[0x8e] = "STX";
|
|
instructions[0x8e] = STX(absoluteWrite);
|
|
opcodes[0x8f] = "uSAX";
|
|
instructions[0x8f] = uSAX(absoluteWrite);
|
|
opcodes[0x90] = "BCC";
|
|
instructions[0x90] = Bxx(bC, 0); // BCC
|
|
opcodes[0x91] = "STA";
|
|
instructions[0x91] = STA(indirectYWrite);
|
|
opcodes[0x92] = "uKIL";
|
|
instructions[0x92] = uKIL();
|
|
opcodes[0x93] = "uSHA";
|
|
instructions[0x93] = uSHA(indirectYWrite);
|
|
opcodes[0x94] = "STY";
|
|
instructions[0x94] = STY(zeroPageIndexedWrite(rX));
|
|
opcodes[0x95] = "STA";
|
|
instructions[0x95] = STA(zeroPageIndexedWrite(rX));
|
|
opcodes[0x96] = "STX";
|
|
instructions[0x96] = STX(zeroPageIndexedWrite(rY));
|
|
opcodes[0x97] = "uSAX";
|
|
instructions[0x97] = uSAX(zeroPageIndexedWrite(rY));
|
|
opcodes[0x98] = "TYA";
|
|
instructions[0x98] = TYA();
|
|
opcodes[0x99] = "STA";
|
|
instructions[0x99] = STA(absoluteIndexedWrite(rY));
|
|
opcodes[0x9a] = "TXS";
|
|
instructions[0x9a] = TXS();
|
|
opcodes[0x9b] = "uSHS";
|
|
instructions[0x9b] = uSHS(absoluteIndexedWrite(rY));
|
|
opcodes[0x9c] = "uSHY";
|
|
instructions[0x9c] = uSHY(absoluteIndexedWrite(rX));
|
|
opcodes[0x9d] = "STA";
|
|
instructions[0x9d] = STA(absoluteIndexedWrite(rX));
|
|
opcodes[0x9e] = "uSHX";
|
|
instructions[0x9e] = uSHX(absoluteIndexedWrite(rY));
|
|
opcodes[0x9f] = "uSHA";
|
|
instructions[0x9f] = uSHA(absoluteIndexedWrite(rY));
|
|
opcodes[0xa0] = "LDY";
|
|
instructions[0xa0] = LDY(immediateRead);
|
|
opcodes[0xa1] = "LDA";
|
|
instructions[0xa1] = LDA(indirectXRead);
|
|
opcodes[0xa2] = "LDX";
|
|
instructions[0xa2] = LDX(immediateRead);
|
|
opcodes[0xa3] = "uLAX";
|
|
instructions[0xa3] = uLAX(indirectXRead);
|
|
opcodes[0xa4] = "LDY";
|
|
instructions[0xa4] = LDY(zeroPageRead);
|
|
opcodes[0xa5] = "LDA";
|
|
instructions[0xa5] = LDA(zeroPageRead);
|
|
opcodes[0xa6] = "LDX";
|
|
instructions[0xa6] = LDX(zeroPageRead);
|
|
opcodes[0xa7] = "uLAX";
|
|
instructions[0xa7] = uLAX(zeroPageRead);
|
|
opcodes[0xa8] = "TAY";
|
|
instructions[0xa8] = TAY();
|
|
opcodes[0xa9] = "LDA";
|
|
instructions[0xa9] = LDA(immediateRead);
|
|
opcodes[0xaa] = "TAX";
|
|
instructions[0xaa] = TAX();
|
|
opcodes[0xab] = "uLXA";
|
|
instructions[0xab] = uLXA(immediateRead);
|
|
opcodes[0xac] = "LDY";
|
|
instructions[0xac] = LDY(absoluteRead);
|
|
opcodes[0xad] = "LDA";
|
|
instructions[0xad] = LDA(absoluteRead);
|
|
opcodes[0xae] = "LDX";
|
|
instructions[0xae] = LDX(absoluteRead);
|
|
opcodes[0xaf] = "uLAX";
|
|
instructions[0xaf] = uLAX(absoluteRead);
|
|
opcodes[0xb0] = "BCS";
|
|
instructions[0xb0] = Bxx(bC, 1); // BCS
|
|
opcodes[0xb1] = "LDA";
|
|
instructions[0xb1] = LDA(indirectYRead);
|
|
opcodes[0xb2] = "uKIL";
|
|
instructions[0xb2] = uKIL();
|
|
opcodes[0xb3] = "uLAX";
|
|
instructions[0xb3] = uLAX(indirectYRead);
|
|
opcodes[0xb4] = "LDY";
|
|
instructions[0xb4] = LDY(zeroPageIndexedRead(rX));
|
|
opcodes[0xb5] = "LDA";
|
|
instructions[0xb5] = LDA(zeroPageIndexedRead(rX));
|
|
opcodes[0xb6] = "LDX";
|
|
instructions[0xb6] = LDX(zeroPageIndexedRead(rY));
|
|
opcodes[0xb7] = "uLAX";
|
|
instructions[0xb7] = uLAX(zeroPageIndexedRead(rY));
|
|
opcodes[0xb8] = "CLV";
|
|
instructions[0xb8] = CLV();
|
|
opcodes[0xb9] = "LDA";
|
|
instructions[0xb9] = LDA(absoluteIndexedRead(rY));
|
|
opcodes[0xba] = "TSX";
|
|
instructions[0xba] = TSX();
|
|
opcodes[0xbb] = "uLAS";
|
|
instructions[0xbb] = uLAS(absoluteIndexedRead(rY));
|
|
opcodes[0xbc] = "LDY";
|
|
instructions[0xbc] = LDY(absoluteIndexedRead(rX));
|
|
opcodes[0xbd] = "LDA";
|
|
instructions[0xbd] = LDA(absoluteIndexedRead(rX));
|
|
opcodes[0xbe] = "LDX";
|
|
instructions[0xbe] = LDX(absoluteIndexedRead(rY));
|
|
opcodes[0xbf] = "uLAX";
|
|
instructions[0xbf] = uLAX(absoluteIndexedRead(rY));
|
|
opcodes[0xc0] = "CPY";
|
|
instructions[0xc0] = CPY(immediateRead);
|
|
opcodes[0xc1] = "CMP";
|
|
instructions[0xc1] = CMP(indirectXRead);
|
|
opcodes[0xc2] = "uNOP";
|
|
instructions[0xc2] = uNOP(immediateRead);
|
|
opcodes[0xc3] = "uDCP";
|
|
instructions[0xc3] = uDCP(indirectXReadModifyWrite);
|
|
opcodes[0xc4] = "CPY";
|
|
instructions[0xc4] = CPY(zeroPageRead);
|
|
opcodes[0xc5] = "CMP";
|
|
instructions[0xc5] = CMP(zeroPageRead);
|
|
opcodes[0xc6] = "DEC";
|
|
instructions[0xc6] = DEC(zeroPageReadModifyWrite);
|
|
opcodes[0xc7] = "uDCP";
|
|
instructions[0xc7] = uDCP(zeroPageReadModifyWrite);
|
|
opcodes[0xc8] = "INY";
|
|
instructions[0xc8] = INY();
|
|
opcodes[0xc9] = "CMP";
|
|
instructions[0xc9] = CMP(immediateRead);
|
|
opcodes[0xca] = "DEX";
|
|
instructions[0xca] = DEX();
|
|
opcodes[0xcb] = "uSBX";
|
|
instructions[0xcb] = uSBX(immediateRead);
|
|
opcodes[0xcc] = "CPY";
|
|
instructions[0xcc] = CPY(absoluteRead);
|
|
opcodes[0xcd] = "CMP";
|
|
instructions[0xcd] = CMP(absoluteRead);
|
|
opcodes[0xce] = "DEC";
|
|
instructions[0xce] = DEC(absoluteReadModifyWrite);
|
|
opcodes[0xcf] = "uDCP";
|
|
instructions[0xcf] = uDCP(absoluteReadModifyWrite);
|
|
opcodes[0xd0] = "BNE";
|
|
instructions[0xd0] = Bxx(bZ, 0); // BNE
|
|
opcodes[0xd1] = "CMP";
|
|
instructions[0xd1] = CMP(indirectYRead);
|
|
opcodes[0xd2] = "uKIL";
|
|
instructions[0xd2] = uKIL();
|
|
opcodes[0xd3] = "uDCP";
|
|
instructions[0xd3] = uDCP(indirectYReadModifyWrite);
|
|
opcodes[0xd4] = "uNOP";
|
|
instructions[0xd4] = uNOP(zeroPageIndexedRead(rX));
|
|
opcodes[0xd5] = "CMP";
|
|
instructions[0xd5] = CMP(zeroPageIndexedRead(rX));
|
|
opcodes[0xd6] = "DEC";
|
|
instructions[0xd6] = DEC(zeroPageIndexedReadModifyWrite(rX));
|
|
opcodes[0xd7] = "uDCP";
|
|
instructions[0xd7] = uDCP(zeroPageIndexedReadModifyWrite(rX));
|
|
opcodes[0xd8] = "CLD";
|
|
instructions[0xd8] = CLD();
|
|
opcodes[0xd9] = "CMP";
|
|
instructions[0xd9] = CMP(absoluteIndexedRead(rY));
|
|
opcodes[0xda] = "uNOP";
|
|
instructions[0xda] = uNOP(implied);
|
|
opcodes[0xdb] = "uDCP";
|
|
instructions[0xdb] = uDCP(absoluteIndexedReadModifyWrite(rY));
|
|
opcodes[0xdc] = "uNOP";
|
|
instructions[0xdc] = uNOP(absoluteIndexedRead(rX));
|
|
opcodes[0xdd] = "CMP";
|
|
instructions[0xdd] = CMP(absoluteIndexedRead(rX));
|
|
opcodes[0xde] = "DEC";
|
|
instructions[0xde] = DEC(absoluteIndexedReadModifyWrite(rX));
|
|
opcodes[0xdf] = "uDCP";
|
|
instructions[0xdf] = uDCP(absoluteIndexedReadModifyWrite(rX));
|
|
opcodes[0xe0] = "CPX";
|
|
instructions[0xe0] = CPX(immediateRead);
|
|
opcodes[0xe1] = "SBC";
|
|
instructions[0xe1] = SBC(indirectXRead);
|
|
opcodes[0xe2] = "uNOP";
|
|
instructions[0xe2] = uNOP(immediateRead);
|
|
opcodes[0xe3] = "uISB";
|
|
instructions[0xe3] = uISB(indirectXReadModifyWrite);
|
|
opcodes[0xe4] = "CPX";
|
|
instructions[0xe4] = CPX(zeroPageRead);
|
|
opcodes[0xe5] = "SBC";
|
|
instructions[0xe5] = SBC(zeroPageRead);
|
|
opcodes[0xe6] = "INC";
|
|
instructions[0xe6] = INC(zeroPageReadModifyWrite);
|
|
opcodes[0xe7] = "uISB";
|
|
instructions[0xe7] = uISB(zeroPageReadModifyWrite);
|
|
opcodes[0xe8] = "INX";
|
|
instructions[0xe8] = INX();
|
|
opcodes[0xe9] = "SBC";
|
|
instructions[0xe9] = SBC(immediateRead);
|
|
opcodes[0xea] = "NOP";
|
|
instructions[0xea] = NOP();
|
|
opcodes[0xeb] = "SBC";
|
|
instructions[0xeb] = SBC(immediateRead);
|
|
opcodes[0xec] = "CPX";
|
|
instructions[0xec] = CPX(absoluteRead);
|
|
opcodes[0xed] = "SBC";
|
|
instructions[0xed] = SBC(absoluteRead);
|
|
opcodes[0xee] = "INC";
|
|
instructions[0xee] = INC(absoluteReadModifyWrite);
|
|
opcodes[0xef] = "uISB";
|
|
instructions[0xef] = uISB(absoluteReadModifyWrite);
|
|
opcodes[0xf0] = "BEQ";
|
|
instructions[0xf0] = Bxx(bZ, 1); // BEQ
|
|
opcodes[0xf1] = "SBC";
|
|
instructions[0xf1] = SBC(indirectYRead);
|
|
opcodes[0xf2] = "uKIL";
|
|
instructions[0xf2] = uKIL();
|
|
opcodes[0xf3] = "uISB";
|
|
instructions[0xf3] = uISB(indirectYReadModifyWrite);
|
|
opcodes[0xf4] = "uNOP";
|
|
instructions[0xf4] = uNOP(zeroPageIndexedRead(rX));
|
|
opcodes[0xf5] = "SBC";
|
|
instructions[0xf5] = SBC(zeroPageIndexedRead(rX));
|
|
opcodes[0xf6] = "INC";
|
|
instructions[0xf6] = INC(zeroPageIndexedReadModifyWrite(rX));
|
|
opcodes[0xf7] = "uISB";
|
|
instructions[0xf7] = uISB(zeroPageIndexedReadModifyWrite(rX));
|
|
opcodes[0xf8] = "SED";
|
|
instructions[0xf8] = SED();
|
|
opcodes[0xf9] = "SBC";
|
|
instructions[0xf9] = SBC(absoluteIndexedRead(rY));
|
|
opcodes[0xfa] = "uNOP";
|
|
instructions[0xfa] = uNOP(implied);
|
|
opcodes[0xfb] = "uISB";
|
|
instructions[0xfb] = uISB(absoluteIndexedReadModifyWrite(rY));
|
|
opcodes[0xfc] = "uNOP";
|
|
instructions[0xfc] = uNOP(absoluteIndexedRead(rX));
|
|
opcodes[0xfd] = "SBC";
|
|
instructions[0xfd] = SBC(absoluteIndexedRead(rX));
|
|
opcodes[0xfe] = "INC";
|
|
instructions[0xfe] = INC(absoluteIndexedReadModifyWrite(rX));
|
|
opcodes[0xff] = "uISB";
|
|
instructions[0xff] = uISB(absoluteIndexedReadModifyWrite(rX));
|
|
// Single Byte instructions
|
|
function ASL_ACC() {
|
|
return implied(function () {
|
|
setC(A > 127);
|
|
A = (A << 1) & 255;
|
|
setZ(A);
|
|
setN(A);
|
|
});
|
|
}
|
|
function CLC() {
|
|
return implied(function () {
|
|
C = 0;
|
|
});
|
|
}
|
|
function CLD() {
|
|
return implied(function () {
|
|
D = 0;
|
|
});
|
|
}
|
|
function CLI() {
|
|
return implied(function () {
|
|
I = 0;
|
|
});
|
|
}
|
|
function CLV() {
|
|
return implied(function () {
|
|
V = 0;
|
|
});
|
|
}
|
|
function DEX() {
|
|
return implied(function () {
|
|
X = (X - 1) & 255;
|
|
setZ(X);
|
|
setN(X);
|
|
});
|
|
}
|
|
function DEY() {
|
|
return implied(function () {
|
|
Y = (Y - 1) & 255;
|
|
setZ(Y);
|
|
setN(Y);
|
|
});
|
|
}
|
|
function INX() {
|
|
return implied(function () {
|
|
X = (X + 1) & 255;
|
|
setZ(X);
|
|
setN(X);
|
|
});
|
|
}
|
|
function INY() {
|
|
return implied(function () {
|
|
Y = (Y + 1) & 255;
|
|
setZ(Y);
|
|
setN(Y);
|
|
});
|
|
}
|
|
function LSR_ACC() {
|
|
return implied(function () {
|
|
C = A & 0x01;
|
|
A >>>= 1;
|
|
setZ(A);
|
|
N = 0;
|
|
});
|
|
}
|
|
function NOP() {
|
|
return implied(function () {
|
|
// nothing
|
|
});
|
|
}
|
|
function ROL_ACC() {
|
|
return implied(function () {
|
|
var newC = A > 127;
|
|
A = ((A << 1) | C) & 255;
|
|
setC(newC);
|
|
setZ(A);
|
|
setN(A);
|
|
});
|
|
}
|
|
function ROR_ACC() {
|
|
return implied(function () {
|
|
var newC = A & 0x01;
|
|
A = (A >>> 1) | (C << 7);
|
|
setC(newC);
|
|
setZ(A);
|
|
setN(A);
|
|
});
|
|
}
|
|
function SEC() {
|
|
return implied(function () {
|
|
C = 1;
|
|
});
|
|
}
|
|
function SED() {
|
|
return implied(function () {
|
|
D = 1;
|
|
});
|
|
}
|
|
function SEI() {
|
|
return implied(function () {
|
|
I = 1;
|
|
});
|
|
}
|
|
function TAX() {
|
|
return implied(function () {
|
|
X = A;
|
|
setZ(X);
|
|
setN(X);
|
|
});
|
|
}
|
|
function TAY() {
|
|
return implied(function () {
|
|
Y = A;
|
|
setZ(Y);
|
|
setN(Y);
|
|
});
|
|
}
|
|
function TSX() {
|
|
return implied(function () {
|
|
X = SP;
|
|
setZ(X);
|
|
setN(X);
|
|
});
|
|
}
|
|
function TXA() {
|
|
return implied(function () {
|
|
A = X;
|
|
setZ(A);
|
|
setN(A);
|
|
});
|
|
}
|
|
function TXS() {
|
|
return implied(function () {
|
|
SP = X;
|
|
});
|
|
}
|
|
function TYA() {
|
|
return implied(function () {
|
|
A = Y;
|
|
setZ(A);
|
|
setN(A);
|
|
});
|
|
}
|
|
function uKIL() {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
function () {
|
|
illegalOpcode("KIL/HLT/JAM");
|
|
},
|
|
function () {
|
|
T--; // Causes the processor to be stuck in this instruction forever
|
|
}
|
|
];
|
|
}
|
|
function uNOP(addressing) {
|
|
return addressing(function () {
|
|
illegalOpcode("NOP/DOP");
|
|
// nothing
|
|
});
|
|
}
|
|
// Internal Execution on Memory Data
|
|
function ADC(addressing) {
|
|
return addressing(function () {
|
|
if (D) {
|
|
var operand = data;
|
|
var AL = (A & 15) + (operand & 15) + C;
|
|
if (AL > 9) {
|
|
AL += 6;
|
|
}
|
|
var AH = ((A >> 4) + (operand >> 4) + ((AL > 15) ? 1 : 0)) << 4;
|
|
setZ((A + operand + C) & 255);
|
|
setN(AH);
|
|
setV(((A ^ AH) & ~(A ^ operand)) & 128);
|
|
if (AH > 0x9f) {
|
|
AH += 0x60;
|
|
}
|
|
setC(AH > 255);
|
|
A = (AH | (AL & 15)) & 255;
|
|
}
|
|
else {
|
|
var add = A + data + C;
|
|
setC(add > 255);
|
|
setV(((A ^ add) & (data ^ add)) & 0x80);
|
|
A = add & 255;
|
|
setZ(A);
|
|
setN(A);
|
|
}
|
|
});
|
|
}
|
|
function AND(addressing) {
|
|
return addressing(function () {
|
|
A &= data;
|
|
setZ(A);
|
|
setN(A);
|
|
});
|
|
}
|
|
function BIT(addressing) {
|
|
return addressing(function () {
|
|
var par = data;
|
|
setZ(A & par);
|
|
setV(par & 0x40);
|
|
setN(par);
|
|
});
|
|
}
|
|
function CMP(addressing) {
|
|
return addressing(function () {
|
|
var val = (A - data) & 255;
|
|
setC(A >= data);
|
|
setZ(val);
|
|
setN(val);
|
|
});
|
|
}
|
|
function CPX(addressing) {
|
|
return addressing(function () {
|
|
var val = (X - data) & 255;
|
|
setC(X >= data);
|
|
setZ(val);
|
|
setN(val);
|
|
});
|
|
}
|
|
function CPY(addressing) {
|
|
return addressing(function () {
|
|
var val = (Y - data) & 255;
|
|
setC(Y >= data);
|
|
setZ(val);
|
|
setN(val);
|
|
});
|
|
}
|
|
function EOR(addressing) {
|
|
return addressing(function () {
|
|
A ^= data;
|
|
setZ(A);
|
|
setN(A);
|
|
});
|
|
}
|
|
function LDA(addressing) {
|
|
return addressing(function () {
|
|
A = data;
|
|
setZ(A);
|
|
setN(A);
|
|
});
|
|
}
|
|
function LDX(addressing) {
|
|
return addressing(function () {
|
|
X = data;
|
|
setZ(X);
|
|
setN(X);
|
|
});
|
|
}
|
|
function LDY(addressing) {
|
|
return addressing(function () {
|
|
Y = data;
|
|
setZ(Y);
|
|
setN(Y);
|
|
});
|
|
}
|
|
function ORA(addressing) {
|
|
return addressing(function () {
|
|
A |= data;
|
|
setZ(A);
|
|
setN(A);
|
|
});
|
|
}
|
|
function SBC(addressing) {
|
|
return addressing(function () {
|
|
if (D) {
|
|
var operand = data;
|
|
var AL = (A & 15) - (operand & 15) - (1 - C);
|
|
var AH = (A >> 4) - (operand >> 4) - ((AL < 0) ? 1 : 0);
|
|
if (AL < 0) {
|
|
AL -= 6;
|
|
}
|
|
if (AH < 0) {
|
|
AH -= 6;
|
|
}
|
|
var sub = A - operand - (1 - C);
|
|
setC(~sub & 256);
|
|
setV(((A ^ operand) & (A ^ sub)) & 128);
|
|
setZ(sub & 255);
|
|
setN(sub);
|
|
A = ((AH << 4) | (AL & 15)) & 255;
|
|
}
|
|
else {
|
|
operand = (~data) & 255;
|
|
sub = A + operand + C;
|
|
setC(sub > 255);
|
|
setV(((A ^ sub) & (operand ^ sub) & 0x80));
|
|
A = sub & 255;
|
|
setZ(A);
|
|
setN(A);
|
|
}
|
|
});
|
|
}
|
|
function uANC(addressing) {
|
|
return addressing(function () {
|
|
illegalOpcode("ANC");
|
|
A &= data;
|
|
setZ(A);
|
|
N = C = (A & 0x080) ? 1 : 0;
|
|
});
|
|
}
|
|
function uANE(addressing) {
|
|
return addressing(function () {
|
|
illegalOpcode("ANE");
|
|
// Exact operation unknown. Do nothing
|
|
});
|
|
}
|
|
function uARR(addressing) {
|
|
// Some sources say flags are affected per ROR, others say its more complex. The complex one is chosen
|
|
return addressing(function () {
|
|
illegalOpcode("ARR");
|
|
var val = A & data;
|
|
var oldC = C ? 0x80 : 0;
|
|
val = (val >>> 1) | oldC;
|
|
A = val;
|
|
setZ(val);
|
|
setN(val);
|
|
var comp = A & 0x60;
|
|
if (comp == 0x60) {
|
|
C = 1;
|
|
V = 0;
|
|
}
|
|
else if (comp == 0x00) {
|
|
C = 0;
|
|
V = 0;
|
|
}
|
|
else if (comp == 0x20) {
|
|
C = 0;
|
|
V = 1;
|
|
}
|
|
else if (comp == 0x40) {
|
|
C = 1;
|
|
V = 1;
|
|
}
|
|
});
|
|
}
|
|
function uASR(addressing) {
|
|
return addressing(function () {
|
|
illegalOpcode("ASR");
|
|
var val = A & data;
|
|
C = (val & 0x01); // bit 0
|
|
val = val >>> 1;
|
|
A = val;
|
|
setZ(val);
|
|
N = 0;
|
|
});
|
|
}
|
|
function uLAS(addressing) {
|
|
return addressing(function () {
|
|
illegalOpcode("LAS");
|
|
var val = SP & data;
|
|
A = val;
|
|
X = val;
|
|
SP = val;
|
|
setZ(val);
|
|
setN(val);
|
|
});
|
|
}
|
|
function uLAX(addressing) {
|
|
return addressing(function () {
|
|
illegalOpcode("LAX");
|
|
var val = data;
|
|
A = val;
|
|
X = val;
|
|
setZ(val);
|
|
setN(val);
|
|
});
|
|
}
|
|
function uLXA(addressing) {
|
|
return addressing(function () {
|
|
// Some sources say its an OR with $EE then AND with IMM, others exclude the OR,
|
|
// others exclude both the OR and the AND. Excluding just the OR...
|
|
illegalOpcode("LXA");
|
|
var val = A /* | 0xEE) */ & data;
|
|
A = val;
|
|
X = val;
|
|
setZ(val);
|
|
setN(val);
|
|
});
|
|
}
|
|
function uSBX(addressing) {
|
|
return addressing(function () {
|
|
illegalOpcode("SBX");
|
|
var par = A & X;
|
|
var val = data;
|
|
var newX = (par - val) & 255;
|
|
X = newX;
|
|
setC(par >= val);
|
|
setZ(newX);
|
|
setN(newX);
|
|
});
|
|
}
|
|
// Store operations
|
|
function STA(addressing) {
|
|
return addressing(function () {
|
|
data = A;
|
|
});
|
|
}
|
|
function STX(addressing) {
|
|
return addressing(function () {
|
|
data = X;
|
|
});
|
|
}
|
|
function STY(addressing) {
|
|
return addressing(function () {
|
|
data = Y;
|
|
});
|
|
}
|
|
function uSAX(addressing) {
|
|
return addressing(function () {
|
|
// Some sources say it would affect N and Z flags, some say it wouldn't. Chose not to affect
|
|
illegalOpcode("SAX");
|
|
data = A & X;
|
|
});
|
|
}
|
|
function uSHA(addressing) {
|
|
return addressing(function () {
|
|
illegalOpcode("SHA");
|
|
data = A & X & ((BA >>> 8) + 1) & 255; // A & X & (High byte of effective address + 1) !!!
|
|
// data would also be stored BAH if page boundary is crossed. Unobservable, not needed here
|
|
});
|
|
}
|
|
function uSHS(addressing) {
|
|
return addressing(function () {
|
|
illegalOpcode("SHS");
|
|
var val = A & X;
|
|
SP = val;
|
|
data = val & ((BA >>> 8) + 1) & 255; // A & X & (High byte of effective address + 1) !!!
|
|
// data would also be stored BAH if page boundary is crossed. Unobservable, not needed here
|
|
});
|
|
}
|
|
function uSHX(addressing) {
|
|
return addressing(function () {
|
|
illegalOpcode("SHX");
|
|
data = X & ((BA >>> 8) + 1) & 255; // X & (High byte of effective address + 1) !!!
|
|
// data would also be stored BAH if page boundary is crossed. Unobservable, not needed here
|
|
});
|
|
}
|
|
function uSHY(addressing) {
|
|
return addressing(function () {
|
|
illegalOpcode("SHY");
|
|
data = Y & ((BA >>> 8) + 1) & 255; // Y & (High byte of effective address + 1) !!!
|
|
// data would also be stored BAH if page boundary is crossed. Unobservable, not needed here
|
|
});
|
|
}
|
|
// Read-Modify-Write operations
|
|
function ASL(addressing) {
|
|
return addressing(function () {
|
|
setC(data > 127);
|
|
var par = (data << 1) & 255;
|
|
data = par;
|
|
setZ(par);
|
|
setN(par);
|
|
});
|
|
}
|
|
function DEC(addressing) {
|
|
return addressing(function () {
|
|
var par = (data - 1) & 255;
|
|
data = par;
|
|
setZ(par);
|
|
setN(par);
|
|
});
|
|
}
|
|
function INC(addressing) {
|
|
return addressing(function () {
|
|
var par = (data + 1) & 255;
|
|
data = par;
|
|
setZ(par);
|
|
setN(par);
|
|
});
|
|
}
|
|
function LSR(addressing) {
|
|
return addressing(function () {
|
|
C = data & 0x01;
|
|
data >>>= 1;
|
|
setZ(data);
|
|
N = 0;
|
|
});
|
|
}
|
|
function ROL(addressing) {
|
|
return addressing(function () {
|
|
var newC = data > 127;
|
|
var par = ((data << 1) | C) & 255;
|
|
data = par;
|
|
setC(newC);
|
|
setZ(par);
|
|
setN(par);
|
|
});
|
|
}
|
|
function ROR(addressing) {
|
|
return addressing(function () {
|
|
var newC = data & 0x01;
|
|
var par = (data >>> 1) | (C << 7);
|
|
data = par;
|
|
setC(newC);
|
|
setZ(par);
|
|
setN(par);
|
|
});
|
|
}
|
|
function uDCP(addressing) {
|
|
return addressing(function () {
|
|
illegalOpcode("DCP");
|
|
var par = (data - 1) & 255;
|
|
data = par;
|
|
par = A - par;
|
|
setC(par >= 0);
|
|
setZ(par);
|
|
setN(par);
|
|
});
|
|
}
|
|
function uISB(addressing) {
|
|
return addressing(function () {
|
|
illegalOpcode("ISB");
|
|
data = (data + 1) & 255; // ISB is the same as SBC but incs the operand first
|
|
if (D) {
|
|
var operand = data;
|
|
var AL = (A & 15) - (operand & 15) - (1 - C);
|
|
var AH = (A >> 4) - (operand >> 4) - ((AL < 0) ? 1 : 0);
|
|
if (AL < 0) {
|
|
AL -= 6;
|
|
}
|
|
if (AH < 0) {
|
|
AH -= 6;
|
|
}
|
|
var sub = A - operand - (1 - C);
|
|
setC(~sub & 256);
|
|
setV(((A ^ operand) & (A ^ sub)) & 128);
|
|
setZ(sub & 255);
|
|
setN(sub);
|
|
A = ((AH << 4) | (AL & 15)) & 255;
|
|
}
|
|
else {
|
|
operand = (~data) & 255;
|
|
sub = A + operand + C;
|
|
setC(sub > 255);
|
|
setV(((A ^ sub) & (operand ^ sub) & 0x80));
|
|
A = sub & 255;
|
|
setZ(A);
|
|
setN(A);
|
|
}
|
|
});
|
|
}
|
|
function uRLA(addressing) {
|
|
return addressing(function () {
|
|
illegalOpcode("RLA");
|
|
var val = data;
|
|
var oldC = C;
|
|
setC(val & 0x80); // bit 7 was set
|
|
val = ((val << 1) | oldC) & 255;
|
|
data = val;
|
|
A &= val;
|
|
setZ(val); // TODO Verify. May be A instead of val in the flags setting
|
|
setN(val);
|
|
});
|
|
}
|
|
function uRRA(addressing) {
|
|
return addressing(function () {
|
|
illegalOpcode("RRA");
|
|
var val = data;
|
|
var oldC = C ? 0x80 : 0;
|
|
setC(val & 0x01); // bit 0 was set
|
|
val = (val >>> 1) | oldC;
|
|
data = val;
|
|
// RRA is the same as ADC from here
|
|
if (D) {
|
|
var operand = data;
|
|
var AL = (A & 15) + (operand & 15) + C;
|
|
if (AL > 9) {
|
|
AL += 6;
|
|
}
|
|
var AH = ((A >> 4) + (operand >> 4) + ((AL > 15) ? 1 : 0)) << 4;
|
|
setZ((A + operand + C) & 255);
|
|
setN(AH);
|
|
setV(((A ^ AH) & ~(A ^ operand)) & 128);
|
|
if (AH > 0x9f) {
|
|
AH += 0x60;
|
|
}
|
|
setC(AH > 255);
|
|
A = (AH | (AL & 15)) & 255;
|
|
}
|
|
else {
|
|
var add = A + data + C;
|
|
setC(add > 255);
|
|
setV(((A ^ add) & (data ^ add)) & 0x80);
|
|
A = add & 255;
|
|
setZ(A);
|
|
setN(A);
|
|
}
|
|
});
|
|
}
|
|
function uSLO(addressing) {
|
|
return addressing(function () {
|
|
illegalOpcode("SLO");
|
|
var val = data;
|
|
setC(val & 0x80); // bit 7 was set
|
|
val = (val << 1) & 255;
|
|
data = val;
|
|
val = A | val;
|
|
A = val;
|
|
setZ(val);
|
|
setN(val);
|
|
});
|
|
}
|
|
function uSRE(addressing) {
|
|
return addressing(function () {
|
|
illegalOpcode("SRE");
|
|
var val = data;
|
|
setC(val & 0x01); // bit 0 was set
|
|
val = val >>> 1;
|
|
data = val;
|
|
val = (A ^ val) & 255;
|
|
A = val;
|
|
setZ(val);
|
|
setN(val);
|
|
});
|
|
}
|
|
// Miscellaneous operations
|
|
function PHA() {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchOpcodeAndDiscard,
|
|
function () { pushToStack(A); },
|
|
fetchNextOpcode
|
|
];
|
|
}
|
|
function PHP() {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchOpcodeAndDiscard,
|
|
function () { pushToStack(getStatusBits()); },
|
|
fetchNextOpcode
|
|
];
|
|
}
|
|
function PLA() {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchOpcodeAndDiscard,
|
|
peekFromStack,
|
|
function () {
|
|
A = popFromStack();
|
|
setZ(A);
|
|
setN(A);
|
|
},
|
|
fetchNextOpcode
|
|
];
|
|
}
|
|
function PLP() {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchOpcodeAndDiscard,
|
|
peekFromStack,
|
|
function () { setStatusBits(popFromStack()); },
|
|
fetchNextOpcode
|
|
];
|
|
}
|
|
function JSR() {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchADL,
|
|
peekFromStack,
|
|
function () { pushToStack((PC >>> 8) & 0xff); },
|
|
function () { pushToStack(PC & 0xff); },
|
|
fetchADH,
|
|
function () { PC = AD; fetchNextOpcode(); }
|
|
];
|
|
}
|
|
function BRK() {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchDataFromImmediate, // For debugging purposes, use operand as an arg for BRK!
|
|
function () {
|
|
if (self.debug)
|
|
self.breakpoint("BRK " + data);
|
|
pushToStack((PC >>> 8) & 0xff);
|
|
},
|
|
function () { pushToStack(PC & 0xff); },
|
|
function () { pushToStack(getStatusBits()); }, // set B flag
|
|
function () { AD = bus.read(IRQ_VECTOR); },
|
|
function () { AD |= bus.read(IRQ_VECTOR + 1) << 8; },
|
|
function () { PC = AD; I = 1; fetchNextOpcode(); }
|
|
];
|
|
}
|
|
function IRQ() {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchDataFromImmediate, // For debugging purposes, use operand as an arg for BRK!
|
|
function () {
|
|
if (self.debug)
|
|
self.breakpoint("IRQ " + data);
|
|
pushToStack((PC >>> 8) & 0xff);
|
|
},
|
|
function () { pushToStack(PC & 0xff); },
|
|
function () { pushToStack(getStatusBits() & ~0x10); }, // no BRK flag
|
|
function () { AD = bus.read(IRQ_VECTOR); },
|
|
function () { AD |= bus.read(IRQ_VECTOR + 1) << 8; },
|
|
function () { PC = AD; fetchNextOpcode(); }
|
|
];
|
|
}
|
|
function NMI() {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchDataFromImmediate,
|
|
function () {
|
|
if (self.debug)
|
|
self.breakpoint("NMI " + data);
|
|
pushToStack((PC >>> 8) & 0xff);
|
|
},
|
|
function () { pushToStack(PC & 0xff); },
|
|
function () { pushToStack(getStatusBits() & ~0x10); }, // no BRK flag
|
|
function () { AD = bus.read(NMI_VECTOR); },
|
|
function () { AD |= bus.read(NMI_VECTOR + 1) << 8; },
|
|
function () { PC = AD; fetchNextOpcode(); }
|
|
];
|
|
}
|
|
function RTI() {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchOpcodeAndDiscard,
|
|
peekFromStack,
|
|
function () { setStatusBits(popFromStack()); },
|
|
function () { AD = popFromStack(); },
|
|
function () { AD |= popFromStack() << 8; },
|
|
function () { PC = AD; fetchNextOpcode(); }
|
|
];
|
|
}
|
|
function RTS() {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchOpcodeAndDiscard,
|
|
peekFromStack,
|
|
function () { AD = popFromStack(); },
|
|
function () { AD |= popFromStack() << 8; },
|
|
function () { PC = AD; fetchDataFromImmediate(); },
|
|
fetchNextOpcode
|
|
];
|
|
}
|
|
function JMP_ABS() {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchADL,
|
|
fetchADH,
|
|
function () { PC = AD; fetchNextOpcode(); }
|
|
];
|
|
}
|
|
function JMP_IND() {
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchIAL, // IAH will be zero
|
|
fetchIAH,
|
|
fetchBALFromIA,
|
|
function () {
|
|
add1toIAL();
|
|
fetchBAHFromIA();
|
|
},
|
|
function () { PC = BA; fetchNextOpcode(); }
|
|
];
|
|
}
|
|
function Bxx(reg, cond) {
|
|
var branchTaken;
|
|
if (reg === bZ)
|
|
branchTaken = function () { return Z === cond; };
|
|
else if (reg === bN)
|
|
branchTaken = function () { return N === cond; };
|
|
else if (reg === bC)
|
|
branchTaken = function () { return C === cond; };
|
|
else
|
|
branchTaken = function () { return V === cond; };
|
|
return [
|
|
fetchOpcodeAndDecodeInstruction,
|
|
fetchBranchOffset,
|
|
function () {
|
|
if (branchTaken()) {
|
|
fetchOpcodeAndDiscard();
|
|
addBranchOffsetToPCL();
|
|
}
|
|
else {
|
|
fetchNextOpcode();
|
|
}
|
|
},
|
|
function () {
|
|
if (branchOffsetCrossAdjust) {
|
|
fetchOpcodeAndDiscard();
|
|
adjustPCHForBranchOffsetCross();
|
|
}
|
|
else {
|
|
fetchNextOpcode();
|
|
}
|
|
},
|
|
fetchNextOpcode
|
|
];
|
|
}
|
|
// Savestate -------------------------------------------
|
|
this.saveState = function () {
|
|
return {
|
|
PC: (PC - 1) & 0xffff,
|
|
A: A, X: X, Y: Y, SP: SP,
|
|
N: N, V: V, D: D, I: I, Z: Z, C: C,
|
|
T: T, o: opcode, R: RDY ? 1 : 0,
|
|
d: data, AD: AD, BA: BA, BC: BALCrossed ? 1 : 0, IA: IA,
|
|
bo: branchOffset, boa: branchOffsetCrossAdjust
|
|
};
|
|
};
|
|
this.loadState = function (state) {
|
|
PC = (state.PC + 1) & 0xffff;
|
|
A = state.A;
|
|
X = state.X;
|
|
Y = state.Y;
|
|
SP = state.SP;
|
|
N = state.N;
|
|
V = state.V;
|
|
D = state.D;
|
|
I = state.I;
|
|
Z = state.Z;
|
|
C = state.C;
|
|
T = state.T;
|
|
opcode = state.o;
|
|
RDY = !!state.R;
|
|
data = state.d;
|
|
AD = state.AD;
|
|
BA = state.BA;
|
|
BALCrossed = !!state.BC;
|
|
IA = state.IA;
|
|
branchOffset = state.bo;
|
|
branchOffsetCrossAdjust = state.boa;
|
|
instruction = opcode < 0 ? [fetchOpcodeAndDecodeInstruction] : instructions[opcode];
|
|
};
|
|
// Accessory methods
|
|
this.toString = function () {
|
|
return "CPU " +
|
|
" PC: " + PC.toString(16) + " op: " + opcode.toString() + " T: " + T + " data: " + data + "\n" +
|
|
" A: " + A.toString(16) + " X: " + X.toString(16) + " Y: " + Y.toString(16) + " SP: " + SP.toString(16) + " " +
|
|
"N" + N + " " + "V" + V + " " + "D" + D + " " + "I" + I + " " + "Z" + Z + " " + "C" + C + " ";
|
|
};
|
|
this.breakpoint = function (mes) {
|
|
//jt.Util.log(mes);
|
|
if (this.trace) {
|
|
var text = "CPU Breakpoint! " + (mes ? "(" + mes + ")" : "") + "\n\n" + this.toString();
|
|
//jt.Util.message(text);
|
|
}
|
|
};
|
|
var cycletime = [
|
|
7, 6, 0, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6,
|
|
2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 0, 7, 4, 4, 7, 7,
|
|
6, 6, 0, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6,
|
|
2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 0, 7, 4, 4, 7, 7,
|
|
6, 6, 0, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6,
|
|
2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 0, 7, 4, 4, 7, 7,
|
|
6, 6, 0, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6,
|
|
2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 0, 7, 4, 4, 7, 7,
|
|
0, 6, 0, 6, 3, 3, 3, 3, 2, 0, 2, 0, 4, 4, 4, 4,
|
|
2, 6, 0, 0, 4, 4, 4, 4, 2, 5, 2, 0, 0, 5, 0, 0,
|
|
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 0, 4, 4, 4, 4,
|
|
2, 5, 0, 5, 4, 4, 4, 4, 2, 4, 2, 0, 4, 4, 4, 4,
|
|
2, 6, 0, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6,
|
|
2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 0, 7, 4, 4, 7, 7,
|
|
2, 6, 0, 8, 3, 3, 5, 5, 2, 2, 2, 0, 4, 4, 6, 6,
|
|
2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 0, 7, 4, 4, 7, 7
|
|
];
|
|
var extracycles = [
|
|
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1,
|
|
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1,
|
|
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1,
|
|
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1,
|
|
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1,
|
|
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1,
|
|
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1
|
|
];
|
|
var insnlengths = [
|
|
1, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1, 2, 3, 3, 3, 3,
|
|
2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 0, 3, 3, 3, 3, 3,
|
|
3, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1, 2, 3, 3, 3, 3,
|
|
2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 0, 3, 3, 3, 3, 3,
|
|
1, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1, 2, 3, 3, 3, 3,
|
|
2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 0, 3, 3, 3, 3, 3,
|
|
1, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1, 2, 3, 3, 3, 3,
|
|
2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 0, 3, 3, 3, 3, 3,
|
|
0, 2, 0, 2, 2, 2, 2, 2, 1, 0, 1, 0, 3, 3, 3, 3,
|
|
2, 2, 0, 0, 2, 2, 2, 3, 1, 3, 1, 0, 0, 3, 0, 0,
|
|
2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 0, 3, 3, 3, 3,
|
|
2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 1, 0, 3, 3, 3, 3,
|
|
2, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1, 2, 3, 3, 3, 3,
|
|
2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 0, 3, 3, 3, 3, 3,
|
|
2, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1, 0, 3, 3, 3, 3,
|
|
2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 0, 3, 3, 3, 3, 3
|
|
];
|
|
var validinsns = [
|
|
1, 2, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 0, 3, 3, 0,
|
|
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0,
|
|
3, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0,
|
|
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0,
|
|
1, 2, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0,
|
|
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0,
|
|
1, 2, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0,
|
|
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0,
|
|
0, 2, 0, 0, 2, 2, 2, 0, 1, 0, 1, 0, 3, 3, 3, 0,
|
|
2, 2, 0, 0, 2, 2, 2, 0, 1, 3, 1, 0, 0, 3, 0, 0,
|
|
2, 2, 2, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0,
|
|
2, 2, 0, 0, 2, 2, 2, 0, 1, 3, 1, 0, 3, 3, 3, 0,
|
|
2, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0,
|
|
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0,
|
|
2, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0,
|
|
2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0
|
|
];
|
|
this.getOpcodeMetadata = function (opcode, address) {
|
|
// TODO: more intelligent maximum cycles
|
|
//var i = instructions[opcode];
|
|
return {
|
|
opcode: opcode,
|
|
mnenomic: opcodes[opcode],
|
|
minCycles: cycletime[opcode],
|
|
maxCycles: cycletime[opcode] + extracycles[opcode],
|
|
insnlength: insnlengths[opcode]
|
|
};
|
|
};
|
|
// only call when isPCStable() is true
|
|
this.setNMI = function () {
|
|
instruction = NMI();
|
|
T = 1;
|
|
PC = (PC - 1) & 0xffff;
|
|
};
|
|
this.setIRQ = function () {
|
|
if (!I) { // only if not disabled
|
|
instruction = IRQ();
|
|
T = 1;
|
|
PC = (PC - 1) & 0xffff;
|
|
}
|
|
};
|
|
this.getSP = function () { return SP; };
|
|
this.getPC = function () { return (PC - 1) & 0xffff; };
|
|
this.getT = function () { return T; };
|
|
this.isHalted = function () { return opcodes[opcode] == "uKIL"; };
|
|
this.isPCStable = function () {
|
|
return T == 0;
|
|
};
|
|
};
|
|
exports._MOS6502 = _MOS6502;
|
|
var MOS6502Interrupts;
|
|
(function (MOS6502Interrupts) {
|
|
MOS6502Interrupts[MOS6502Interrupts["None"] = 0] = "None";
|
|
MOS6502Interrupts[MOS6502Interrupts["NMI"] = 1] = "NMI";
|
|
MOS6502Interrupts[MOS6502Interrupts["IRQ"] = 2] = "IRQ";
|
|
})(MOS6502Interrupts || (exports.MOS6502Interrupts = MOS6502Interrupts = {}));
|
|
;
|
|
class MOS6502 {
|
|
constructor() {
|
|
this.cpu = new exports._MOS6502();
|
|
this.interruptType = MOS6502Interrupts.None;
|
|
}
|
|
connectMemoryBus(bus) {
|
|
this.cpu.connectBus(bus);
|
|
}
|
|
advanceClock() {
|
|
if (this.interruptType && this.isStable()) {
|
|
switch (this.interruptType) {
|
|
case MOS6502Interrupts.NMI:
|
|
this.cpu.setNMI();
|
|
break;
|
|
case MOS6502Interrupts.IRQ:
|
|
this.cpu.setIRQ();
|
|
break;
|
|
}
|
|
this.interruptType = 0;
|
|
}
|
|
this.cpu.clockPulse();
|
|
}
|
|
advanceInsn() {
|
|
do {
|
|
this.advanceClock();
|
|
} while (!this.isStable());
|
|
}
|
|
reset() {
|
|
this.cpu.reset();
|
|
this.interruptType = 0;
|
|
}
|
|
interrupt(itype) {
|
|
if (this.interruptType != MOS6502Interrupts.NMI) {
|
|
this.interruptType = itype;
|
|
}
|
|
}
|
|
NMI() {
|
|
this.interrupt(MOS6502Interrupts.NMI);
|
|
}
|
|
IRQ() {
|
|
this.interrupt(MOS6502Interrupts.IRQ);
|
|
}
|
|
getSP() {
|
|
return this.cpu.getSP();
|
|
}
|
|
getPC() {
|
|
return this.cpu.getPC();
|
|
}
|
|
isHalted() {
|
|
return this.cpu.isHalted();
|
|
}
|
|
saveState() {
|
|
var s = this.cpu.saveState();
|
|
s.it = this.interruptType;
|
|
return s;
|
|
}
|
|
loadState(s) {
|
|
this.cpu.loadState(s);
|
|
this.interruptType = s.it;
|
|
}
|
|
isStable() {
|
|
return this.cpu.isPCStable();
|
|
}
|
|
getOpcodeMetadata(op) {
|
|
return this.cpu.getOpcodeMetadata(op);
|
|
}
|
|
}
|
|
exports.MOS6502 = MOS6502;
|
|
//# sourceMappingURL=MOS6502.js.map
|