8bitworkshop/src/disasm.js

251 lines
12 KiB
JavaScript

var Disassembler6502 = function() {
this.disassemble = function(mem, start, end, ips) {
var i;
var lines = [];
function print_func(s) {
lines[i] = s;
}
for (i = start; i < end;) {
var opcode = OPS[mem[i]];
if (!opcode) {
print_func("#" + formatHex(mem[i], 2));
i += 1;
} else {
var bytes = opcode.bytes;
var args = mem.slice(i+1, i+1+bytes);
//console.log(opcode, bytes, args);
print_func(opcode.toString.call(opcode, args));
i += bytes;
}
}
return lines;
};
function formatHex(number, len) {
if (typeof number === "undefined" || number === null || isNaN(number)) {
throw new Error("Invalid value \"" + number + "\" passed to formatHex()");
}
var str = number.toString(16).toUpperCase();
if (!len) {
if (str.length % 2 == 1) {
len = str.length+1;
}
}
while (str.length < len) {
str = "0" + str;
}
return str;
}
function formatImmediate (args) {
return this.name + " #$" + formatHex(args[0]);
}
function formatZeroPage (args) {
return this.name + " $" + formatHex(args[0]);
}
function formatZeroPageIndexedX (args) {
return formatZeroPage.call(this, args) + ",X";
}
function formatZeroPageIndexedY (args) {
return formatZeroPage.call(this, args) + ",Y";
}
function formatAbsolute (args) {
return this.name + " $" + formatHex(args[1], 2) + formatHex(args[0], 2);
}
function formatAbsoluteIndexedX (args) {
return formatAbsolute.call(this, args) + ",X";
}
function formatAbsoluteIndexedY (args) {
return formatAbsolute.call(this, args) + ",Y";
}
function formatIndirect (args) {
return this.name + " ($" + formatHex(args[1], 2) + formatHex(args[0], 2) + ")";
}
function formatIndirectIndexedX (args) {
return this.name + " ($" + formatHex(args[0], 2) + ",X)";
}
function formatIndirectIndexedY (args) {
return this.name + " ($" + formatHex(args[0], 2) + "),Y";
}
function formatName() {
return this.name;
}
function formatRelative (args) {
return this.name + " $" + formatHex(args[0], 2);
}
function formatAccumulator (args) {
return this.name + " A";
}
var OPS = {
0xA0 : { name: "LDY", bytes: 2, toString: formatImmediate },
0xA4 : { name: "LDY", bytes: 2, toString: formatZeroPage },
0xB4 : { name: "LDY", bytes: 2, toString: formatZeroPageIndexedX },
0xAC : { name: "LDY", bytes: 3, toString: formatAbsolute },
0xBC : { name: "LDY", bytes: 3, toString: formatAbsoluteIndexedX },
0xA2 : { name: "LDX", bytes: 2, toString: formatImmediate },
0xA6 : { name: "LDX", bytes: 2, toString: formatZeroPage },
0xB6 : { name: "LDX", bytes: 2, toString: formatZeroPageIndexedY },
0xAE : { name: "LDX", bytes: 3, toString: formatAbsolute },
0xBE : { name: "LDX", bytes: 3, toString: formatAbsoluteIndexedY },
0xA9 : { name: "LDA", bytes: 2, toString: formatImmediate },
0xA5 : { name: "LDA", bytes: 2, toString: formatZeroPage },
0xB5 : { name: "LDA", bytes: 2, toString: formatZeroPageIndexedX },
0xAD : { name: "LDA", bytes: 3, toString: formatAbsolute },
0xBD : { name: "LDA", bytes: 3, toString: formatAbsoluteIndexedX },
0xB9 : { name: "LDA", bytes: 3, toString: formatAbsoluteIndexedY },
0xA1 : { name: "LDA", bytes: 2, toString: formatIndirectIndexedX },
0xB1 : { name: "LDA", bytes: 2, toString: formatIndirectIndexedY },
0x86 : { name: "STX", bytes: 2, toString: formatZeroPage },
0x96 : { name: "STX", bytes: 2, toString: formatZeroPageIndexedY },
0x8E : { name: "STX", bytes: 3, toString: formatAbsolute },
0x84 : { name: "STY", bytes: 2, toString: formatZeroPage },
0x94 : { name: "STY", bytes: 2, toString: formatZeroPageIndexedX },
0x8C : { name: "STY", bytes: 3, toString: formatAbsolute },
0x85 : { name: "STA", bytes: 2, toString: formatZeroPage },
0x95 : { name: "STA", bytes: 2, toString: formatZeroPageIndexedX },
0x8D : { name: "STA", bytes: 3, toString: formatAbsolute },
0x9D : { name: "STA", bytes: 3, toString: formatAbsoluteIndexedX },
0x99 : { name: "STA", bytes: 3, toString: formatAbsoluteIndexedY },
0x81 : { name: "STA", bytes: 2, toString: formatIndirectIndexedX },
0x91 : { name: "STA", bytes: 2, toString: formatIndirectIndexedY },
0xE8 : { name: "INX", bytes: 1, toString: formatName },
0xC8 : { name: "INY", bytes: 1, toString: formatName },
0xCA : { name: "DEX", bytes: 1, toString: formatName },
0x88 : { name: "DEY", bytes: 1, toString: formatName },
0xE6 : { name: "INC", bytes: 2, toString: formatZeroPage },
0xF6 : { name: "INC", bytes: 2, toString: formatZeroPageIndexedX },
0xEE : { name: "INC", bytes: 3, toString: formatAbsolute },
0xFE : { name: "INC", bytes: 3, toString: formatAbsoluteIndexedX },
0xC6 : { name: "DEC", bytes: 2, toString: formatZeroPage },
0xD6 : { name: "DEC", bytes: 2, toString: formatZeroPageIndexedX },
0xCE : { name: "DEC", bytes: 3, toString: formatAbsolute },
0xDE : { name: "DEC", bytes: 3, toString: formatAbsoluteIndexedX },
0x38 : { name: "SEC", bytes: 1, toString: formatName },
0xF8 : { name: "SED", bytes: 1, toString: formatName },
0x78 : { name: "SEI", bytes: 1, toString: formatName },
0x18 : { name: "CLC", bytes: 1, toString: formatName },
0xD8 : { name: "CLD", bytes: 1, toString: formatName },
0x58 : { name: "CLI", bytes: 1, toString: formatName },
0xB8 : { name: "CLV", bytes: 1, toString: formatName },
0xAA : { name: "TAX", bytes: 1, toString: formatName },
0x8A : { name: "TXA", bytes: 1, toString: formatName },
0xA8 : { name: "TAY", bytes: 1, toString: formatName },
0x98 : { name: "TYA", bytes: 1, toString: formatName },
0xBA : { name: "TSX", bytes: 1, toString: formatName },
0x9A : { name: "TXS", bytes: 1, toString: formatName },
0x48 : { name: "PHA", bytes: 1, toString: formatName },
0x08 : { name: "PHP", bytes: 1, toString: formatName },
0x68 : { name: "PLA", bytes: 1, toString: formatName },
0x28 : { name: "PLP", bytes: 1, toString: formatName },
0x29 : { name: "AND", bytes: 2, toString: formatImmediate },
0x25 : { name: "AND", bytes: 2, toString: formatZeroPage },
0x35 : { name: "AND", bytes: 2, toString: formatZeroPageIndexedX },
0x2D : { name: "AND", bytes: 3, toString: formatAbsolute },
0x3D : { name: "AND", bytes: 3, toString: formatAbsoluteIndexedX },
0x39 : { name: "AND", bytes: 3, toString: formatAbsoluteIndexedY },
0x21 : { name: "AND", bytes: 2, toString: formatIndirectIndexedX },
0x31 : { name: "AND", bytes: 2, toString: formatIndirectIndexedY },
0x09 : { name: "ORA", bytes: 2, toString: formatImmediate },
0x05 : { name: "ORA", bytes: 2, toString: formatZeroPage },
0x15 : { name: "ORA", bytes: 2, toString: formatZeroPageIndexedX },
0x0D : { name: "ORA", bytes: 3, toString: formatAbsolute },
0x1D : { name: "ORA", bytes: 3, toString: formatAbsoluteIndexedX },
0x19 : { name: "ORA", bytes: 3, toString: formatAbsoluteIndexedY },
0x01 : { name: "ORA", bytes: 2, toString: formatIndirectIndexedX },
0x11 : { name: "ORA", bytes: 2, toString: formatIndirectIndexedY },
0x49 : { name: "EOR", bytes: 2, toString: formatImmediate },
0x45 : { name: "EOR", bytes: 2, toString: formatZeroPage },
0x55 : { name: "EOR", bytes: 2, toString: formatZeroPageIndexedX },
0x4D : { name: "EOR", bytes: 3, toString: formatAbsolute },
0x5D : { name: "EOR", bytes: 3, toString: formatAbsoluteIndexedX },
0x59 : { name: "EOR", bytes: 3, toString: formatAbsoluteIndexedY },
0x41 : { name: "EOR", bytes: 2, toString: formatIndirectIndexedX },
0x51 : { name: "EOR", bytes: 2, toString: formatIndirectIndexedY },
0x4C : { name: "JMP", bytes: 3, toString: formatAbsolute },
0x6C : { name: "JMP", bytes: 3, toString: formatIndirect },
0x20 : { name: "JSR", bytes: 3, toString: formatAbsolute },
0x60 : { name: "RTS", bytes: 1, toString: formatName },
0x40 : { name: "RTI", bytes: 1, toString: formatName },
0x90 : { name: "BCC", bytes: 2, toString: formatRelative },
0xB0 : { name: "BCS", bytes: 2, toString: formatRelative },
0xF0 : { name: "BEQ", bytes: 2, toString: formatRelative },
0xD0 : { name: "BNE", bytes: 2, toString: formatRelative },
0x10 : { name: "BPL", bytes: 2, toString: formatRelative },
0x30 : { name: "BMI", bytes: 2, toString: formatRelative },
0x50 : { name: "BVC", bytes: 2, toString: formatRelative },
0x70 : { name: "BVS", bytes: 2, toString: formatRelative },
0x2A : { name: "ROL", bytes: 1, toString: formatAccumulator },
0x26 : { name: "ROL", bytes: 2, toString: formatZeroPage },
0x36 : { name: "ROL", bytes: 2, toString: formatZeroPageIndexedX },
0x2E : { name: "ROL", bytes: 3, toString: formatAbsolute },
0x3E : { name: "ROL", bytes: 3, toString: formatAbsoluteIndexedX },
0x6A : { name: "ROR", bytes: 1, toString: formatAccumulator },
0x66 : { name: "ROR", bytes: 2, toString: formatZeroPage },
0x76 : { name: "ROR", bytes: 2, toString: formatZeroPageIndexedX },
0x6E : { name: "ROR", bytes: 3, toString: formatAbsolute },
0x7E : { name: "ROR", bytes: 3, toString: formatAbsoluteIndexedX },
0x4A : { name: "LSR", bytes: 1, toString: formatAccumulator },
0x46 : { name: "LSR", bytes: 2, toString: formatZeroPage },
0x56 : { name: "LSR", bytes: 2, toString: formatZeroPageIndexedX },
0x4E : { name: "LSR", bytes: 3, toString: formatAbsolute },
0x5E : { name: "LSR", bytes: 3, toString: formatAbsoluteIndexedX },
0x0A : { name: "ASL", bytes: 1, toString: formatAccumulator },
0x06 : { name: "ASL", bytes: 2, toString: formatZeroPage },
0x16 : { name: "ASL", bytes: 2, toString: formatZeroPageIndexedX },
0x0E : { name: "ASL", bytes: 3, toString: formatAbsolute },
0x1E : { name: "ASL", bytes: 3, toString: formatAbsoluteIndexedX },
0xC9 : { name: "CMP", bytes: 2, toString: formatImmediate },
0xC5 : { name: "CMP", bytes: 2, toString: formatZeroPage },
0xD5 : { name: "CMP", bytes: 2, toString: formatZeroPageIndexedX },
0xCD : { name: "CMP", bytes: 3, toString: formatAbsolute },
0xDD : { name: "CMP", bytes: 3, toString: formatAbsoluteIndexedX },
0xD9 : { name: "CMP", bytes: 3, toString: formatAbsoluteIndexedY },
0xC1 : { name: "CMP", bytes: 2, toString: formatIndirectIndexedX },
0xD1 : { name: "CMP", bytes: 2, toString: formatIndirectIndexedY },
0xE0 : { name: "CPX", bytes: 2, toString: formatImmediate },
0xE4 : { name: "CPX", bytes: 2, toString: formatZeroPage },
0xEC : { name: "CPX", bytes: 3, toString: formatAbsolute },
0xC0 : { name: "CPY", bytes: 2, toString: formatImmediate },
0xC4 : { name: "CPY", bytes: 2, toString: formatZeroPage },
0xCC : { name: "CPY", bytes: 3, toString: formatAbsolute },
0x24 : { name: "BIT", bytes: 2, toString: formatZeroPage },
0x2C : { name: "BIT", bytes: 3, toString: formatAbsolute },
0x69 : { name: "ADC", bytes: 2, toString: formatImmediate },
0x65 : { name: "ADC", bytes: 2, toString: formatZeroPage },
0x75 : { name: "ADC", bytes: 2, toString: formatZeroPageIndexedX },
0x6D : { name: "ADC", bytes: 3, toString: formatAbsolute },
0x7D : { name: "ADC", bytes: 3, toString: formatAbsoluteIndexedX },
0x79 : { name: "ADC", bytes: 3, toString: formatAbsoluteIndexedY },
0x61 : { name: "ADC", bytes: 2, toString: formatIndirectIndexedX },
0x71 : { name: "ADC", bytes: 2, toString: formatIndirectIndexedY },
0xE9 : { name: "SBC", bytes: 2, toString: formatImmediate },
0xE5 : { name: "SBC", bytes: 2, toString: formatZeroPage },
0xF5 : { name: "SBC", bytes: 2, toString: formatZeroPageIndexedX },
0xED : { name: "SBC", bytes: 3, toString: formatAbsolute },
0xFD : { name: "SBC", bytes: 3, toString: formatAbsoluteIndexedX },
0xF9 : { name: "SBC", bytes: 3, toString: formatAbsoluteIndexedY },
0xE1 : { name: "SBC", bytes: 2, toString: formatIndirectIndexedX },
0xF1 : { name: "SBC", bytes: 2, toString: formatIndirectIndexedY },
0xEA : { name: "NOP", bytes: 1, toString: formatName },
0x00 : { name: "BRK", bytes: 1, toString: formatName },
};
}