1533 lines
40 KiB
JavaScript
1533 lines
40 KiB
JavaScript
/*
|
|
* 6502 Based Virtual Computer
|
|
* Copyright (C) 2011 Scott C. Duensing <scott@jaegertech.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
// 6502 CPU Core - based on http://www.6502asm.com
|
|
function cpu6502() {
|
|
|
|
// --- Private variables.
|
|
|
|
var self = this;
|
|
|
|
// Memory Pointer.
|
|
var MEMORY = null;
|
|
|
|
// Default Program Counter.
|
|
var DEFAULT_PC = 0x600;
|
|
|
|
// Registers.
|
|
var REG_A = 0;
|
|
var REG_X = 0;
|
|
var REG_Y = 0;
|
|
var REG_P = 0;
|
|
var REG_PC = DEFAULT_PC;
|
|
var REG_SP = 0x100;
|
|
|
|
// Internal CPU Status.
|
|
var CODE_RUNNING = false;
|
|
|
|
// CPU Event Callback.
|
|
var CALLBACK = null;
|
|
|
|
// Instruction Function "Pointers".
|
|
var INSTRUCTION_POINTERS = null;
|
|
|
|
|
|
// --- Public variables, enums.
|
|
|
|
this.E_HALT = 0;
|
|
this.E_UNKNOWN_OPCODE = 1;
|
|
this.E_STACK_OVERFLOW = 2;
|
|
this.E_STACK_UNDERFLOW = 3;
|
|
|
|
|
|
// --- Private methods, general.
|
|
|
|
var doCompare = function(reg, val) {
|
|
if (reg >= val)
|
|
REG_P |= 1;
|
|
else
|
|
REG_P &= 0xfe;
|
|
val = (reg - val);
|
|
if (val)
|
|
REG_P &= 0xfd;
|
|
else
|
|
REG_P |= 0x02;
|
|
if (val & 0x80)
|
|
REG_P |= 0x80;
|
|
else
|
|
REG_P &= 0x7f;
|
|
}
|
|
|
|
// Might as well Jump... JUMP!
|
|
var jumpBranch = function(offset) {
|
|
if (offset > 0x7f)
|
|
REG_PC = (REG_PC - (0x100 - offset));
|
|
else
|
|
REG_PC = (REG_PC + offset);
|
|
};
|
|
|
|
// Fetch the next byte pointed to by the program counter.
|
|
var popByte = function() {
|
|
return (MEMORY.readByte(REG_PC++) & 0xff);
|
|
};
|
|
|
|
// Fetch the next word pointed to by the program counter.
|
|
var popWord = function() {
|
|
return popByte() + (popByte() << 8);
|
|
};
|
|
|
|
// Run a block of instructions. This is used by 'run' to avoid blocking the browser event queue.
|
|
var runBlock = function() {
|
|
var instructions = 100;
|
|
while ((instructions-- > 0) && (CODE_RUNNING))
|
|
self.execute();
|
|
if (CODE_RUNNING)
|
|
setTimeout(runBlock, 0);
|
|
};
|
|
|
|
// Pop a value off the stack.
|
|
var stackPop = function() {
|
|
if (REG_SP < 0x100) {
|
|
var value = MEMORY.readByte(REG_SP + 0x100);
|
|
REG_SP++;
|
|
return value;
|
|
} else {
|
|
CODE_RUNNING = false;
|
|
CALLBACK(self.E_STACK_UNDERFLOW);
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
// Push a value onto the stack.
|
|
var stackPush = function(value) {
|
|
if (REG_SP >= 0) {
|
|
REG_SP--;
|
|
MEMORY.writeByte((REG_SP & 0xff) + 0x100, value & 0xff);
|
|
} else {
|
|
CODE_RUNNING = false;
|
|
CALLBACK(self.E_STACK_OVERFLOW);
|
|
}
|
|
};
|
|
|
|
var testSBC = function(value) {
|
|
var vflag = 0;
|
|
var tmp = 0;
|
|
var w = 0;
|
|
if ((REG_A ^ value) & 0x80)
|
|
vflag = 1;
|
|
if (REG_P & 8) {
|
|
tmp = 0xf + (REG_A & 0xf) - (value & 0xf) + (REG_P & 1);
|
|
if (tmp < 0x10) {
|
|
w = 0;
|
|
tmp -= 6;
|
|
} else {
|
|
w = 0x10;
|
|
tmp -= 0x10;
|
|
}
|
|
w += 0xf0 + (REG_A & 0xf0) - (value & 0xf0);
|
|
if (w < 0x100) {
|
|
REG_P &= 0xfe;
|
|
if ((REG_P & 0xbf) && w < 0x80)
|
|
REG_P &= 0xbf;
|
|
w -= 0x60;
|
|
} else {
|
|
REG_P |= 1;
|
|
if ((REG_P & 0xbf) && w >= 0x180)
|
|
REG_P &= 0xbf;
|
|
}
|
|
w += tmp;
|
|
} else {
|
|
w = 0xff + REG_A - value + (REG_P & 1);
|
|
if (w<0x100) {
|
|
REG_P &= 0xfe;
|
|
if ((REG_P & 0xbf) && w < 0x80)
|
|
REG_P &= 0xbf;
|
|
} else {
|
|
REG_P |= 1;
|
|
if ((REG_P & 0xbf) && w >= 0x180)
|
|
REG_P &= 0xbf;
|
|
}
|
|
}
|
|
REG_A = w & 0xff;
|
|
if (REG_A)
|
|
REG_P &= 0xfd;
|
|
else
|
|
REG_P |= 0x02;
|
|
if (REG_A & 0x80)
|
|
REG_P |= 0x80;
|
|
else
|
|
REG_P &= 0x7f;
|
|
}
|
|
|
|
var testADC = function(value) {
|
|
var tmp = 0;
|
|
if ((REG_A ^ value) & 0x80)
|
|
REG_P &= 0xbf;
|
|
else
|
|
REG_P |= 0x40;
|
|
if (REG_P & 8) {
|
|
tmp = (REG_A & 0xf) + (value & 0xf) + (REG_P & 1);
|
|
if (tmp >= 10)
|
|
tmp = 0x10 | ((tmp + 6) & 0xf);
|
|
tmp += (REG_A & 0xf0) + (value & 0xf0);
|
|
if (tmp >= 160) {
|
|
REG_P |= 1;
|
|
if ((REG_P & 0xbf) && tmp >= 0x180)
|
|
REG_P &= 0xbf;
|
|
tmp += 0x60;
|
|
} else {
|
|
REG_P &= 0xfe;
|
|
if ((REG_P & 0xbf) && tmp < 0x80)
|
|
REG_P &= 0xbf;
|
|
}
|
|
} else {
|
|
tmp = REG_A + value + (REG_P & 1);
|
|
if (tmp >= 0x100) {
|
|
REG_P |= 1;
|
|
if ((REG_P & 0xbf) && tmp >= 0x180)
|
|
REG_P &= 0xbf;
|
|
} else {
|
|
REG_P &= 0xfe;
|
|
if ((REG_P & 0xbf) && tmp < 0x80)
|
|
REG_P &= 0xbf;
|
|
}
|
|
}
|
|
REG_A = tmp & 0xff;
|
|
if (REG_A)
|
|
REG_P &= 0xfd;
|
|
else
|
|
REG_P |= 0x02;
|
|
if (REG_A & 0x80)
|
|
REG_P |= 0x80;
|
|
else
|
|
REG_P &= 0x7f;
|
|
}
|
|
|
|
|
|
// --- Private methods, CPU core.
|
|
|
|
var i00 = function() {
|
|
CODE_RUNNING = false;
|
|
};
|
|
|
|
var i01 = function() {
|
|
var addr = popByte() + REG_X;
|
|
var value = MEMORY.readByte(addr) + (MEMORY.readByte(addr + 1) << 8);
|
|
REG_A |= value;
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i05 = function() {
|
|
var zp = popByte();
|
|
REG_A |= MEMORY.readByte(zp);
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i06 = function() {
|
|
var zp = popByte();
|
|
var value = MEMORY.readByte(zp);
|
|
REG_P = (REG_P & 0xfe) | ((value >> 7) & 1);
|
|
value = value << 1;
|
|
MEMORY.writeByte(zp, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i08 = function() {
|
|
stackPush(REG_P);
|
|
};
|
|
|
|
var i09 = function() {
|
|
REG_A |= popByte();
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i0a = function() {
|
|
REG_P = (REG_P & 0xfe) | ((REG_A >> 7) & 1);
|
|
REG_A = REG_A << 1;
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i0d = function() {
|
|
REG_A |= MEMORY.readByte(popWord());
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i0e = function() {
|
|
var addr = popWord();
|
|
var value = MEMORY.readByte(addr);
|
|
REG_P = (REG_P & 0xfe) | ((value >> 7) & 1);
|
|
value = value << 1;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 2;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i10 = function() {
|
|
var offset = popByte();
|
|
if ((REG_P & 0x80) == 0) jumpBranch(offset);
|
|
};
|
|
|
|
var i11 = function() {
|
|
var zp = popByte();
|
|
var value = MEMORY.readByte(zp) + (MEMORY.readByte(zp + 1) << 8) + REG_Y;
|
|
REG_A |= MEMORY.readByte(value);
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i15 = function() {
|
|
var addr = (popByte() + REG_X) & 0xff;
|
|
REG_A |= MEMORY.readByte(addr);
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i16 = function() {
|
|
var addr = (popByte() + REG_X) & 0xff;
|
|
var value = MEMORY.readByte(addr);
|
|
REG_P = (REG_P & 0xfe) | ((value >> 7) & 1);
|
|
value = value << 1;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i18 = function() {
|
|
REG_P &= 0xfe;
|
|
};
|
|
|
|
var i19 = function() {
|
|
addr = popWord() + REG_Y;
|
|
REG_A |= MEMORY.readByte(addr);
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i1d = function() {
|
|
var addr = popWord() + REG_X;
|
|
REG_A |= MEMORY.readByte(addr);
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i1e = function() {
|
|
var addr = popWord() + REG_X;
|
|
var value = MEMORY.readByte(addr);
|
|
REG_P = (REG_P & 0xfe) | ((value >> 7) & 1);
|
|
value = value << 1;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i20 = function() {
|
|
var addr = popWord();
|
|
var currAddr = REG_PC - 1;
|
|
stackPush(((currAddr >> 8) & 0xff));
|
|
stackPush((currAddr & 0xff));
|
|
REG_PC = addr;
|
|
};
|
|
|
|
var i21 = function() {
|
|
var addr = (popByte() + REG_X) & 0xff;
|
|
var value = MEMORY.readByte(addr) + (MEMORY.readByte(addr + 1) << 8);
|
|
REG_A &= value;
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i24 = function() {
|
|
var zp = popByte();
|
|
var value = MEMORY.readByte(zp);
|
|
if (value & REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
REG_P = (REG_P & 0x3f) | (value & 0xc0);
|
|
};
|
|
|
|
var i25 = function() {
|
|
var zp = popByte();
|
|
REG_A &= MEMORY.readByte(zp);
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 2;
|
|
if (REG_A & 0x80) REG_P &= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i26 = function() {
|
|
var sf = (REG_P & 1);
|
|
var addr = popByte();
|
|
var value = MEMORY.readByte(addr);
|
|
REG_P = (REG_P & 0xfe) | ((value >> 7) & 1);
|
|
value = value << 1;
|
|
value |= sf;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i28 = function() {
|
|
REG_P = stackPop() | 0x20;
|
|
};
|
|
|
|
var i29 = function() {
|
|
REG_A &= popByte();
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i2a = function() {
|
|
var sf = (REG_P & 1);
|
|
REG_P = (REG_P & 0xfe) | ((REG_A >> 7) & 1);
|
|
REG_A = REG_A << 1;
|
|
REG_A |= sf;
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i2c = function() {
|
|
var value = MEMORY.readByte(popWord());
|
|
if (value & REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
REG_P = (REG_P & 0x3f) | (value & 0xc0);
|
|
};
|
|
|
|
var i2d = function() {
|
|
var value = MEMORY.readByte(popWord());
|
|
REG_A &= value;
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i2e = function() {
|
|
var sf = REG_P & 1;
|
|
var addr = popWord();
|
|
var value = MEMORY.readByte(addr);
|
|
REG_P = (REG_P & 0xfe) | ((value >> 7) & 1);
|
|
value = value << 1;
|
|
value |= sf;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i30 = function() {
|
|
var offset = popByte();
|
|
if (REG_P & 0x80) jumpBranch(offset);
|
|
};
|
|
|
|
var i31 = function() {
|
|
var zp = popByte();
|
|
var value = MEMORY.readByte(zp) + (MEMORY.readByte(zp + 1) << 8) + REG_Y;
|
|
REG_A &= MEMORY.readByte(value);
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i35 = function() {
|
|
var zp = popByte();
|
|
var value = MEMORY.readByte(zp) + (MEMORY.readByte(zp + 1) << 8) + REG_X;
|
|
REG_A &= MEMORY.readByte(value);
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i36 = function() {
|
|
var sf = REG_P & 1;
|
|
var addr = (popByte() + REG_X) & 0xff;
|
|
var value = MEMORY.readByte(addr);
|
|
REG_P = (REG_P & 0xfe) | ((value >> 7) & 1);
|
|
value = value << 1;
|
|
value |= sf;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i38 = function() {
|
|
REG_P |= 1;
|
|
};
|
|
|
|
var i39 = function() {
|
|
var addr = popWord() + REG_Y;
|
|
var value = MEMORY.readByte(addr);
|
|
REG_A &= value;
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i3d = function() {
|
|
var addr = popWord() + REG_X;
|
|
var value = MEMORY.readByte(addr);
|
|
REG_A &= value;
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i3e = function() {
|
|
var sf = REG_P & 1;
|
|
var addr = popWord() + REG_X;
|
|
var value = MEMORY.readByte(addr);
|
|
REG_P = (REG_P & 0xfe) | ((value >> 7) & 1);
|
|
value = value << 1;
|
|
value |= sf;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i40 = function() {
|
|
};
|
|
|
|
var i41 = function() {
|
|
var zp = (popByte() + REG_X) & 0xff;
|
|
var value = MEMORY.readByte(zp) + (MEMORY.readByte(zp + 1) << 8);
|
|
REG_A ^= MEMORY.readByte(value);
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i45 = function() {
|
|
var addr = (popByte() + REG_X) & 0xff;
|
|
var value = MEMORY.readByte(addr);
|
|
REG_A ^= value;
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i46 = function() {
|
|
var addr = popByte() & 0xff;
|
|
var value = MEMORY.readByte(addr);
|
|
REG_P = (REG_P & 0xfe) | (value & 1);
|
|
value = value >> 1;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value != 0) REG_P &= 0xfd; else REG_P |= 2;
|
|
if ((value & 0x80) == 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i48 = function() {
|
|
stackPush(REG_A);
|
|
};
|
|
|
|
var i49 = function() {
|
|
REG_A ^= popByte();
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i4a = function() {
|
|
REG_P = (REG_P & 0xfe) | (REG_A & 1);
|
|
REG_A = REG_A >> 1;
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i4c = function() {
|
|
REG_PC = popWord();
|
|
};
|
|
|
|
var i4d = function() {
|
|
var addr = popWord();
|
|
var value = MEMORY.readByte(addr);
|
|
REG_A ^= value;
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i4e = function() {
|
|
var addr = popWord();
|
|
var value = MEMORY.readByte(addr);
|
|
REG_P = (REG_P & 0xfe) | (value & 1);
|
|
value = value >> 1;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i50 = function() {
|
|
var offset = popByte();
|
|
if ((REG_P & 0x40) == 0) jumpBranch(offset);
|
|
};
|
|
|
|
var i51 = function() {
|
|
var zp = popByte();
|
|
var value = MEMORY.readByte(zp) + (MEMORY.readByte(zp + 1) << 8) + REG_Y;
|
|
REG_A ^= MEMORY.readByte(value);
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i55 = function() {
|
|
var addr = (popByte() + REG_X) & 0xff;
|
|
REG_A ^= MEMORY.readByte(addr);
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i56 = function() {
|
|
var addr = (popByte() + REG_X) & 0xff;
|
|
var value = MEMORY.readByte(addr);
|
|
REG_P = (REG_P & 0xfe) | (value & 1);
|
|
value = value >> 1;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i58 = function() {
|
|
};
|
|
|
|
var i59 = function() {
|
|
var addr = popWord() + REG_Y;
|
|
var value = MEMORY.readByte(addr);
|
|
REG_A ^= value;
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i5d = function() {
|
|
var addr = popWord() + REG_X;
|
|
var value = MEMORY.readByte(addr);
|
|
REG_A ^= value;
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i5e = function() {
|
|
var addr = popWord() + REG_X;
|
|
var value = MEMORY.readByte(addr);
|
|
REG_P = (REG_P & 0xfe) | (value & 1);
|
|
value = value >> 1;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i60 = function() {
|
|
REG_PC = (stackPop() + 1) | (stackPop() << 8);
|
|
};
|
|
|
|
var i61 = function() {
|
|
var zp = (popByte() + REG_X) & 0xff;
|
|
var addr = MEMORY.readByte(zp) + (MEMORY.readByte(zp + 1) << 8);
|
|
value = MEMORY.readByte(addr);
|
|
testADC(value);
|
|
};
|
|
|
|
var i65 = function() {
|
|
var addr = popByte();
|
|
var value = MEMORY.readByte(addr);
|
|
testADC(value);
|
|
};
|
|
|
|
var i66 = function() {
|
|
var sf = REG_P & 1;
|
|
var addr = popByte();
|
|
var value = MEMORY.readByte(addr);
|
|
REG_P = (REG_P & 0xfe) | (value & 1);
|
|
value = value >> 1;
|
|
if (sf) value |= 0x80;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i68 = function() {
|
|
REG_A = stackPop();
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i69 = function() {
|
|
var value = popByte();
|
|
testADC(value);
|
|
};
|
|
|
|
var i6a = function() {
|
|
var sf = REG_P & 1;
|
|
REG_P = (REG_P & 0xfe) | (REG_A & 1);
|
|
REG_A = REG_A >> 1;
|
|
if (sf) REG_A |= 0x80;
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i6c = function() {
|
|
};
|
|
|
|
var i6d = function() {
|
|
var addr = popWord();
|
|
var value = MEMORY.readByte(addr);
|
|
testADC(value);
|
|
};
|
|
|
|
var i6e = function() {
|
|
var sf = REG_P & 1;
|
|
var addr = popWord();
|
|
var value = MEMORY.readByte(addr);
|
|
REG_P = (REG_P & 0xfe) | (value & 1);
|
|
value = value >> 1;
|
|
if (sf) value |= 0x80;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i70 = function() {
|
|
var offset = popByte();
|
|
if (REG_P & 0x40) jumpBranch(offset);
|
|
};
|
|
|
|
var i71 = function() {
|
|
var zp = popByte();
|
|
var addr = MEMORY.readByte(zp) + (MEMORY.readByte(zp + 1) << 8);
|
|
var value = MEMORY.readByte(addr + REG_Y);
|
|
testADC(value);
|
|
};
|
|
|
|
var i75 = function() {
|
|
var addr = (popByte() + REG_X) & 0xff;
|
|
var value = MEMORY.readByte(addr);
|
|
REG_P = (REG_P & 0xfe) | (value & 1);
|
|
testADC(value);
|
|
};
|
|
|
|
var i76 = function() {
|
|
var sf = (REG_P & 1);
|
|
var addr = (popByte() + REG_X) & 0xff;
|
|
var value = MEMORY.readByte(addr);
|
|
REG_P = (REG_P & 0xfe) | (value & 1);
|
|
value = value >> 1;
|
|
if (sf) value |= 0x80;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i78 = function() {
|
|
};
|
|
|
|
var i79 = function() {
|
|
var addr = popWord();
|
|
var value = MEMORY.readByte(addr + REG_Y);
|
|
testADC(value);
|
|
};
|
|
|
|
var i7d = function() {
|
|
var addr = popWord();
|
|
var value = MEMORY.readByte(addr + REG_X);
|
|
testADC(value);
|
|
};
|
|
|
|
var i7e = function() {
|
|
//var sf = REG_P & 1;
|
|
var addr = popWord() + REG_X;
|
|
var value = MEMORY.readByte(addr);
|
|
REG_P = (REG_P & 0xfe) | (value & 1);
|
|
value = value >> 1;
|
|
if (value) value |= 0x80;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i81 = function() {
|
|
var zp = (popByte() + REG_X) & 0xff;
|
|
var addr = MEMORY.readByte(zp) + (MEMORY.readByte(zp + 1) << 8);
|
|
MEMORY.writeByte(addr, REG_A);
|
|
};
|
|
|
|
var i84 = function() {
|
|
MEMORY.writeByte(popByte(), REG_Y);
|
|
};
|
|
|
|
var i85 = function() {
|
|
MEMORY.writeByte(popByte(), REG_A);
|
|
};
|
|
|
|
var i86 = function() {
|
|
MEMORY.writeByte(popByte(), REG_X);
|
|
};
|
|
|
|
var i88 = function() {
|
|
REG_Y = (REG_Y - 1) & 0xff;
|
|
if (REG_Y) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_Y & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i8a = function() {
|
|
REG_A = REG_X & 0xff;
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i8c = function() {
|
|
MEMORY.writeByte(popWord(), REG_Y);
|
|
};
|
|
|
|
var i8d = function() {
|
|
MEMORY.writeByte(popWord(), REG_A);
|
|
};
|
|
|
|
var i8e = function() {
|
|
MEMORY.writeByte(popWord(), REG_X);
|
|
};
|
|
|
|
var i90 = function() {
|
|
var offset = popByte();
|
|
if ((REG_P & 1) == 0) jumpBranch(offset);
|
|
};
|
|
|
|
var i91 = function() {
|
|
var zp = popByte();
|
|
var addr = MEMORY.readByte(zp) + (MEMORY.readByte(zp + 1) << 8) + REG_Y;
|
|
MEMORY.writeByte(addr, REG_A);
|
|
};
|
|
|
|
var i94 = function() {
|
|
MEMORY.writeByte(popByte() + REG_X, REG_Y);
|
|
};
|
|
|
|
var i95 = function() {
|
|
MEMORY.writeByte(popByte() + REG_X, REG_A);
|
|
};
|
|
|
|
var i96 = function() {
|
|
MEMORY.writeByte(popByte() + REG_Y, REG_X);
|
|
};
|
|
|
|
var i98 = function() {
|
|
REG_A = REG_Y & 0xff;
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var i99 = function() {
|
|
MEMORY.writeByte(popWord() + REG_Y, REG_A);
|
|
};
|
|
|
|
var i9a = function() {
|
|
REG_SP = REG_X & 0xff;
|
|
};
|
|
|
|
var i9d = function() {
|
|
var addr = popWord();
|
|
MEMORY.writeByte(addr + REG_X, REG_A);
|
|
};
|
|
|
|
var ia0 = function() {
|
|
REG_Y = popByte();
|
|
if (REG_Y) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_Y & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ia1 = function() {
|
|
var zp = (popByte() + REG_X) & 0xff;
|
|
var addr = MEMORY.readByte(zp) + (MEMORY.readByte(zp + 1) << 8);
|
|
REG_A = MEMORY.readByte(addr);
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ia2 = function() {
|
|
REG_X = popByte();
|
|
if (REG_X) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_X & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ia4 = function() {
|
|
REG_Y = MEMORY.readByte(popByte());
|
|
if (REG_Y) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_Y & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ia5 = function() {
|
|
REG_A = MEMORY.readByte(popByte());
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ia6 = function() {
|
|
REG_X = MEMORY.readByte(popByte());
|
|
if (REG_X) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_X & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ia8 = function() {
|
|
REG_Y = REG_A & 0xff;
|
|
if (REG_Y) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_Y & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ia9 = function() {
|
|
REG_A = popByte();
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var iaa = function() {
|
|
REG_X = REG_A & 0xff;
|
|
if (REG_X) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_X & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var iac = function() {
|
|
REG_Y = MEMORY.readByte(popWord());
|
|
if (REG_Y) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_Y & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var iad = function() {
|
|
REG_A = MEMORY.readByte(popWord());
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var iae = function() {
|
|
REG_X = MEMORY.readByte(popWord());
|
|
if (REG_X) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_X & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ib0 = function() {
|
|
var offset = popByte();
|
|
if (REG_P & 1) jumpBranch(offset);
|
|
};
|
|
|
|
var ib1 = function() {
|
|
var zp = popByte();
|
|
var addr = MEMORY.readByte(zp) + (MEMORY.readByte(zp + 1) << 8) + REG_Y;
|
|
REG_A = MEMORY.readByte(addr);
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ib4 = function() {
|
|
REG_Y = MEMORY.readByte(popByte() + REG_X);
|
|
if (REG_Y) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_Y & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ib5 = function() {
|
|
REG_A = MEMORY.readByte((popByte() + REG_X) & 0xff);
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ib6 = function() {
|
|
REG_X = MEMORY.readByte(popByte() + REG_Y);
|
|
if (REG_X) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_X & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ib8 = function() {
|
|
REG_P &= 0xbf;
|
|
};
|
|
|
|
var ib9 = function() {
|
|
var addr = popWord() + REG_Y;
|
|
REG_A = MEMORY.readByte(addr);
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var iba = function() {
|
|
REG_X = REG_SP & 0xff;
|
|
};
|
|
|
|
var ibc = function() {
|
|
var addr = popWord() + REG_X;
|
|
REG_Y = MEMORY.readByte(addr);
|
|
if (REG_Y) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_Y & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ibd = function() {
|
|
var addr = popWord() + REG_X;
|
|
REG_A = MEMORY.readByte(addr);
|
|
if (REG_A) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_A & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ibe = function() {
|
|
var addr = popWord() + REG_Y;
|
|
REG_X = MEMORY.readByte(addr);
|
|
if (REG_X) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_X & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ic0 = function() {
|
|
var value = popByte();
|
|
if ((REG_Y + value) > 0xff) REG_P |= 1; else REG_P &= 0xfe;
|
|
//var ov = value;
|
|
value = (REG_Y-value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ic1 = function() {
|
|
var zp = popByte();
|
|
var addr = MEMORY.readByte(zp) + (MEMORY.readByte(zp + 1) << 8) + REG_Y;
|
|
var value = MEMORY.readByte(addr);
|
|
doCompare(REG_A, value);
|
|
};
|
|
|
|
var ic4 = function() {
|
|
var value = MEMORY.readByte(popByte());
|
|
doCompare(REG_Y, value);
|
|
};
|
|
|
|
var ic5 = function() {
|
|
var value = MEMORY.readByte(popByte());
|
|
doCompare(REG_A, value);
|
|
};
|
|
|
|
var ic6 = function() {
|
|
var zp = popByte();
|
|
var value = MEMORY.readByte(zp);
|
|
--value;
|
|
MEMORY.writeByte(zp, value & 0xff);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ic8 = function() {
|
|
REG_Y = (REG_Y + 1) & 0xff;
|
|
if (REG_Y) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_Y & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ic9 = function() {
|
|
var value = popByte();
|
|
doCompare(REG_A, value);
|
|
};
|
|
|
|
var ica = function() {
|
|
REG_X = (REG_X - 1) & 0xff;
|
|
if (REG_X) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_X & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var icc = function() {
|
|
var value = MEMORY.readByte(popWord());
|
|
doCompare(REG_Y, value);
|
|
};
|
|
|
|
var icd = function() {
|
|
var value = MEMORY.readByte(popWord());
|
|
doCompare(REG_A, value);
|
|
};
|
|
|
|
/*
|
|
var ice = function() {
|
|
var addr = popWord();
|
|
var value = MEMORY.readByte(addr);
|
|
--value;
|
|
value = value & 0xff;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
*/
|
|
|
|
var id0 = function() {
|
|
var offset = popByte();
|
|
if ((REG_P & 2) == 0) jumpBranch(offset);
|
|
};
|
|
|
|
var id1 = function() {
|
|
var zp = popByte();
|
|
var addr = MEMORY.readByte(zp) + (MEMORY.readByte(zp + 1) << 8) + REG_Y;
|
|
var value = MEMORY.readByte(addr);
|
|
doCompare(REG_A, value);
|
|
};
|
|
|
|
var id5 = function() {
|
|
var value = MEMORY.readByte(popByte() + REG_X);
|
|
doCompare(REG_A, value);
|
|
};
|
|
|
|
var id6 = function() {
|
|
var addr = popByte() + REG_X;
|
|
var value = MEMORY.readByte(addr);
|
|
--value;
|
|
value = value & 0xff;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var id8 = function() {
|
|
REG_P &= 0xf7;
|
|
};
|
|
|
|
var id9 = function() {
|
|
var addr = popWord() + REG_Y;
|
|
var value = MEMORY.readByte(addr);
|
|
doCompare(REG_A, value);
|
|
};
|
|
|
|
var idd = function() {
|
|
var addr = popWord() + REG_X;
|
|
var value = MEMORY.readByte(addr);
|
|
doCompare(REG_A, value);
|
|
};
|
|
|
|
var ide = function() {
|
|
var addr = popWord() + REG_X;
|
|
var value = MEMORY.readByte(addr);
|
|
--value;
|
|
value = value&0xff;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ie0 = function() {
|
|
var value = popByte();
|
|
doCompare(REG_X, value);
|
|
};
|
|
|
|
var ie1 = function() {
|
|
var zp = (popByte()+REG_X)&0xff;
|
|
var addr = MEMORY.readByte(zp) + (MEMORY.readByte(zp + 1) << 8);
|
|
var value = MEMORY.readByte(addr);
|
|
testSBC(value);
|
|
};
|
|
|
|
var ie4 = function() {
|
|
var value = MEMORY.readByte(popByte());
|
|
doCompare(REG_X, value);
|
|
};
|
|
|
|
var ie5 = function() {
|
|
var addr = popByte();
|
|
var value = MEMORY.readByte(addr);
|
|
testSBC(value);
|
|
};
|
|
|
|
var ie6 = function() {
|
|
var zp = popByte();
|
|
var value = MEMORY.readByte(zp);
|
|
++value;
|
|
value = value & 0xff;
|
|
MEMORY.writeByte(zp, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ie8 = function() {
|
|
REG_X = (REG_X + 1) & 0xff;
|
|
if (REG_X) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (REG_X & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ie9 = function() {
|
|
var value = popByte();
|
|
testSBC(value);
|
|
};
|
|
|
|
var iea = function() {
|
|
};
|
|
|
|
var iec = function() {
|
|
var value = MEMORY.readByte(popWord());
|
|
doCompare(REG_X, value);
|
|
};
|
|
|
|
var ied = function() {
|
|
var addr = popWord();
|
|
var value = MEMORY.readByte(addr);
|
|
testSBC(value);
|
|
};
|
|
|
|
var iee = function() {
|
|
var addr = popWord();
|
|
var value = MEMORY.readByte(addr);
|
|
++value;
|
|
value = value & 0xff;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var if0 = function() {
|
|
var offset = popByte();
|
|
if (REG_P & 2) jumpBranch(offset);
|
|
};
|
|
|
|
var if1 = function() {
|
|
var zp = popByte();
|
|
var addr = MEMORY.readByte(zp) + (MEMORY.readByte(zp + 1) << 8);
|
|
var value = MEMORY.readByte(addr + REG_Y);
|
|
testSBC(value);
|
|
};
|
|
|
|
var if5 = function() {
|
|
var addr = (popByte() + REG_X) & 0xff;
|
|
var value = MEMORY.readByte(addr);
|
|
REG_P = (REG_P & 0xfe) | (value & 1);
|
|
testSBC(value);
|
|
};
|
|
|
|
var if6 = function() {
|
|
var addr = popByte() + REG_X;
|
|
var value = MEMORY.readByte(addr);
|
|
++value;
|
|
value = value & 0xff;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var if8 = function() {
|
|
REG_P |= 8;
|
|
};
|
|
|
|
var if9 = function() {
|
|
var addr = popWord();
|
|
var value = MEMORY.readByte(addr + REG_Y);
|
|
testSBC(value);
|
|
};
|
|
|
|
var ifd = function() {
|
|
var addr = popWord();
|
|
var value = MEMORY.readByte(addr + REG_X);
|
|
testSBC(value);
|
|
};
|
|
|
|
var ife = function() {
|
|
var addr = popWord() + REG_X;
|
|
var value = MEMORY.readByte(addr);
|
|
++value;
|
|
value = value & 0xff;
|
|
MEMORY.writeByte(addr, value);
|
|
if (value) REG_P &= 0xfd; else REG_P |= 0x02;
|
|
if (value & 0x80) REG_P |= 0x80; else REG_P &= 0x7f;
|
|
};
|
|
|
|
var ierr = function() {
|
|
CODE_RUNNING = false;
|
|
CALLBACK(self.E_UNKNOWN_OPCODE);
|
|
};
|
|
|
|
|
|
// --- Public methods.
|
|
|
|
// Attach the CPU to the VM.
|
|
this.attach = function(newMemory, newPC, newCallback) {
|
|
MEMORY = newMemory;
|
|
DEFAULT_PC = newPC;
|
|
CALLBACK = newCallback;
|
|
INSTRUCTION_POINTERS = [
|
|
i00, //00
|
|
i01, //01
|
|
ierr, //02
|
|
ierr, //03
|
|
ierr, //04
|
|
i05, //05
|
|
i06, //06
|
|
ierr, //07
|
|
i08, //08
|
|
i09, //09
|
|
i0a, //0a
|
|
ierr, //0b
|
|
ierr, //0c
|
|
i0d, //0d
|
|
i0e, //0e
|
|
ierr, //0f
|
|
i10, //10
|
|
i11, //11
|
|
ierr, //12
|
|
ierr, //13
|
|
ierr, //14
|
|
i15, //15
|
|
i16, //16
|
|
ierr, //17
|
|
i18, //18
|
|
i19, //19
|
|
ierr, //1a
|
|
ierr, //1b
|
|
ierr, //1c
|
|
i1d, //1d
|
|
i1e, //1e
|
|
ierr, //1f
|
|
i20, //20
|
|
i21, //21
|
|
ierr, //22
|
|
ierr, //23
|
|
i24, //24
|
|
i25, //25
|
|
i26, //26
|
|
ierr, //27
|
|
i28, //28
|
|
i29, //29
|
|
i2a, //2a
|
|
ierr, //2b
|
|
i2c, //2c
|
|
i2d, //2d
|
|
i2e, //2e
|
|
ierr, //2f
|
|
i30, //30
|
|
i31, //31
|
|
ierr, //32
|
|
ierr, //33
|
|
ierr, //34
|
|
i35, //35
|
|
i36, //36
|
|
ierr, //37
|
|
i38, //38
|
|
i39, //39
|
|
ierr, //3a
|
|
ierr, //3b
|
|
ierr, //3c
|
|
i3d, //3d
|
|
i3e, //3e
|
|
ierr, //3f
|
|
i40, //40
|
|
i41, //41
|
|
ierr, //42
|
|
ierr, //43
|
|
ierr, //44
|
|
i45, //45
|
|
i46, //46
|
|
ierr, //47
|
|
i48, //48
|
|
i49, //49
|
|
i4a, //4a
|
|
ierr, //4b
|
|
i4c, //4c
|
|
i4d, //4d
|
|
i4e, //4e
|
|
ierr, //4f
|
|
i50, //50
|
|
i51, //51
|
|
ierr, //52
|
|
ierr, //53
|
|
ierr, //54
|
|
i55, //55
|
|
i56, //56
|
|
ierr, //57
|
|
i58, //58
|
|
i59, //59
|
|
ierr, //5a
|
|
ierr, //5b
|
|
ierr, //5c
|
|
i5d, //5d
|
|
i5e, //5e
|
|
ierr, //5f
|
|
i60, //60
|
|
i61, //61
|
|
ierr, //62
|
|
ierr, //63
|
|
ierr, //64
|
|
i65, //65
|
|
i66, //66
|
|
ierr, //67
|
|
i68, //68
|
|
i69, //69
|
|
i6a, //6a
|
|
ierr, //6b
|
|
i6c, //6c
|
|
i6d, //6d
|
|
i6e, //6e
|
|
ierr, //6f
|
|
i70, //70
|
|
i71, //71
|
|
ierr, //72
|
|
ierr, //73
|
|
ierr, //74
|
|
i75, //75
|
|
i76, //76
|
|
ierr, //77
|
|
i78, //78
|
|
i79, //79
|
|
ierr, //7a
|
|
ierr, //7b
|
|
ierr, //7c
|
|
i7d, //7d
|
|
i7e, //7e
|
|
ierr, //7f
|
|
ierr, //80
|
|
i81, //81
|
|
ierr, //82
|
|
ierr, //83
|
|
i84, //84
|
|
i85, //85
|
|
i86, //86
|
|
ierr, //87
|
|
i88, //88
|
|
ierr, //89
|
|
i8a, //8a
|
|
ierr, //8b
|
|
i8c, //8c
|
|
i8d, //8d
|
|
i8e, //8e
|
|
ierr, //8f
|
|
i90, //90
|
|
i91, //91
|
|
ierr, //92
|
|
ierr, //93
|
|
i94, //94
|
|
i95, //95
|
|
i96, //96
|
|
ierr, //97
|
|
i98, //98
|
|
i99, //99
|
|
i9a, //9a
|
|
ierr, //9b
|
|
ierr, //9c
|
|
i9d, //9d
|
|
ierr, //9e
|
|
ierr, //9f
|
|
ia0, //a0
|
|
ia1, //a1
|
|
ia2, //a2
|
|
ierr, //a3
|
|
ia4, //a4
|
|
ia5, //a5
|
|
ia6, //a6
|
|
ierr, //a7
|
|
ia8, //a8
|
|
ia9, //a9
|
|
iaa, //aa
|
|
ierr, //ab
|
|
iac, //ac
|
|
iad, //ad
|
|
iae, //ae
|
|
ierr, //af
|
|
ib0, //b0
|
|
ib1, //b1
|
|
ierr, //b2
|
|
ierr, //b3
|
|
ib4, //b4
|
|
ib5, //b5
|
|
ib6, //b6
|
|
ierr, //b7
|
|
ib8, //b8
|
|
ib9, //b9
|
|
iba, //ba
|
|
ierr, //bb
|
|
ibc, //bc
|
|
ibd, //bd
|
|
ibe, //be
|
|
ierr, //bf
|
|
ic0, //c0
|
|
ic1, //c1
|
|
ierr, //c2
|
|
ierr, //c3
|
|
ic4, //c4
|
|
ic5, //c5
|
|
ic6, //c6
|
|
ierr, //c7
|
|
ic8, //c8
|
|
ic9, //c9
|
|
ica, //ca
|
|
ierr, //cb
|
|
icc, //cc
|
|
icd, //cd
|
|
ierr, //ce
|
|
ierr, //cf
|
|
id0, //d0
|
|
id1, //d1
|
|
ierr, //d2
|
|
ierr, //d3
|
|
ierr, //d4
|
|
id5, //d5
|
|
id6, //d6
|
|
ierr, //d7
|
|
id8, //d8
|
|
id9, //d9
|
|
ierr, //da
|
|
ierr, //db
|
|
ierr, //dc
|
|
idd, //dd
|
|
ide, //de
|
|
ierr, //df
|
|
ie0, //e0
|
|
ie1, //e1
|
|
ierr, //e2
|
|
ierr, //e3
|
|
ie4, //e4
|
|
ie5, //e5
|
|
ie6, //e6
|
|
ierr, //e7
|
|
ie8, //e8
|
|
ie9, //e9
|
|
iea, //ea
|
|
ierr, //eb
|
|
iec, //ec
|
|
ied, //ed
|
|
iee, //ee
|
|
ierr, //ef
|
|
if0, //f0
|
|
if1, //f1
|
|
ierr, //f2
|
|
ierr, //f3
|
|
ierr, //f4
|
|
if5, //f5
|
|
if6, //f6
|
|
ierr, //f7
|
|
if8, //f8
|
|
if9, //f9
|
|
ierr, //fa
|
|
ierr, //fb
|
|
ierr, //fc
|
|
ifd, //fd
|
|
ife, //fe
|
|
ierr //ff
|
|
];
|
|
this.reset();
|
|
};
|
|
|
|
// Execute a single instruction.
|
|
this.execute = function() {
|
|
if (!CODE_RUNNING) return;
|
|
var opcode = popByte();
|
|
//console.log("PC = 0x" + (REG_PC - 1).toString(16) + " OP = 0x" + opcode.toString(16));
|
|
INSTRUCTION_POINTERS[opcode]();
|
|
if ((REG_PC == 0) || (!CODE_RUNNING)) {
|
|
CODE_RUNNING = false;
|
|
CALLBACK(self.E_HALT);
|
|
}
|
|
};
|
|
|
|
// Get PC.
|
|
this.getPC = function() {
|
|
return REG_PC;
|
|
};
|
|
|
|
// Reset CPU.
|
|
this.reset = function() {
|
|
REG_A = 0;
|
|
REG_X = 0;
|
|
REG_Y = 0;
|
|
REG_P = 0;
|
|
REG_PC = DEFAULT_PC;
|
|
REG_SP = 0x100;
|
|
};
|
|
|
|
// Run until we die.
|
|
this.run = function() {
|
|
console.log("Starting CPU.");
|
|
CODE_RUNNING = true;
|
|
setTimeout(runBlock, 0);
|
|
};
|
|
}
|