/* * 6502 assembler and emulator in Javascript * (C)2006-2007 Stian Soreng - www.6502asm.com * * Released under the GNU General Public License * see http://gnu.org/licenses/gpl.html * */ var MAX_MEM = ((32*32)-1); var codeCompiledOK = false; var regA = 0; var regX = 0; var regY = 0; var regP = 0; var regPC = 0x600; var regSP = 0x100; var memory = new Array( 0x600 ); var runForever = false; var labelIndex = new Array(); var labelPtr = 0; var codeRunning = false; var xmlhttp; var myInterval; var display = new Array( 0x400 ); var defaultCodePC = 0x600; var palette = new Array( "#000000", "#ffffff", "#880000", "#aaffee", "#cc44cc", "#00cc55", "#0000aa", "#eeee77", "#dd8855", "#664400", "#ff7777", "#333333", "#777777", "#aaff66", "#0088ff", "#bbbbbb" ); var Opcodes = new Array( /* Name, Imm, ZP, ZPX, ZPY, ABS, ABSX, ABSY, INDX, INDY, SNGL, BRA */ Array("ADC", 0x69, 0x65, 0x75, 0x00, 0x6d, 0x7d, 0x79, 0x61, 0x71, 0x00, 0x00), Array("AND", 0x29, 0x25, 0x35, 0x31, 0x2d, 0x3d, 0x39, 0x21, 0x00, 0x00, 0x00), Array("ASL", 0x00, 0x06, 0x16, 0x00, 0x0e, 0x1e, 0x00, 0x00, 0x00, 0x0a, 0x00), Array("BIT", 0x00, 0x24, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), Array("BPL", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10), Array("BMI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30), Array("BVC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50), Array("BVS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70), Array("BCC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90), Array("BCS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0), Array("BNE", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0), Array("BEQ", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0), Array("CMP", 0xc9, 0xc5, 0xd5, 0x00, 0xcd, 0xdd, 0xd9, 0xc1, 0xd1, 0x00, 0x00), Array("CPX", 0xe0, 0xe4, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), Array("CPY", 0xc0, 0xc4, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), Array("DEC", 0x00, 0xc6, 0xd6, 0x00, 0xce, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00), Array("EOR", 0x49, 0x45, 0x55, 0x00, 0x4d, 0x5d, 0x59, 0x41, 0x51, 0x00, 0x00), Array("CLC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00), Array("SEC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00), Array("CLI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00), Array("SEI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00), Array("CLV", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00), Array("CLD", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00), Array("SED", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00), Array("INC", 0x00, 0xe6, 0xf6, 0x00, 0xee, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00), Array("JMP", 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), Array("JSR", 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), Array("LDA", 0xa9, 0xa5, 0xb5, 0x00, 0xad, 0xbd, 0xb9, 0xa1, 0xb1, 0x00, 0x00), Array("LDX", 0xa2, 0xa6, 0x00, 0xb6, 0xae, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00), Array("LDY", 0xa0, 0xa4, 0xb4, 0x00, 0xac, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00), Array("LSR", 0x00, 0x46, 0x56, 0x00, 0x4e, 0x5e, 0x00, 0x00, 0x00, 0x4a, 0x00), Array("NOP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x00), Array("ORA", 0x09, 0x05, 0x15, 0x00, 0x0d, 0x1d, 0x19, 0x01, 0x11, 0x00, 0x00), Array("TAX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00), Array("TXA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00), Array("DEX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x00), Array("INX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x00), Array("TAY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00), Array("TYA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00), Array("DEY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00), Array("INY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00), Array("ROR", 0x00, 0x66, 0x76, 0x00, 0x6e, 0x7e, 0x00, 0x00, 0x00, 0x6a, 0x00), Array("ROL", 0x00, 0x26, 0x36, 0x00, 0x2e, 0x3e, 0x00, 0x00, 0x00, 0x2a, 0x00), Array("RTI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00), Array("RTS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00), Array("SBC", 0xe9, 0xe5, 0xf5, 0x00, 0xed, 0xfd, 0xf9, 0xe1, 0xf1, 0x00, 0x00), Array("STA", 0x00, 0x85, 0x95, 0x00, 0x8d, 0x9d, 0x99, 0x81, 0x91, 0x00, 0x00), Array("TXS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00), Array("TSX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00), Array("PHA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00), Array("PLA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00), Array("PHP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00), Array("PLP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00), Array("STX", 0x00, 0x86, 0x00, 0x96, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), Array("STY", 0x00, 0x84, 0x94, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), Array("---", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) ); // Initialize everything. document.getElementById( "compileButton" ).disabled = false; document.getElementById( "runButton" ).disabled = true; document.getElementById( "hexdumpButton" ).disabled = true; document.getElementById( "fileSelect" ).disabled = false; document.addEventListener( "keypress", keyPress, true ); // Paint the "display" html = '
| '; } html += " |
";
for( x=0; x ";
n = (0x600+x);
html += num2hex( ((n>>8)&0xff) );
html += num2hex( (n&0xff) );
html += ": ";
}
html += num2hex( memory[0x600+x] );
if( x&1 ) html += " ";
}
if( (x&1) ) html += "-- [END]";
html += "";
w.document.write( html );
w.document.close();
}
/*
* runBinary() - Executes the compiled code
*
*/
function runBinary() {
if( codeRunning ) {
codeRunning = false;
document.getElementById( "runButton" ).value = "Run";
document.getElementById( "hexdumpButton" ).disabled = false;
document.getElementById( "fileSelect" ).disabled = false;
clearInterval( myInterval );
} else {
reset();
document.getElementById( "runButton" ).value = "Stop";
document.getElementById( "fileSelect" ).disabled = true;
document.getElementById( "hexdumpButton" ).disabled = true;
codeRunning = true;
myInterval = setInterval( "multiexecute()", 1 );
//execute();
}
}
/*
* readZeroPage() - Get value from ZP
*
*/
function jumpBranch( offset ) {
if( offset > 0x7f )
regPC = (regPC - (0x100 - offset));
else
regPC = (regPC + offset );
}
function doCompare( reg, val ) {
if( (reg+val) > 0xff ) regP |= 1; else regP &= 0xfe;
val = (reg-val);
// if( reg+0x100-val > 0xff ) regP |= 1; else regP &= 0xfe;
// val = reg+0x100-val;
if( val ) regP &= 0xfd; else regP |= 0x02;
if( val & 0x80 ) regP |= 0x80; else regP &= 0x7f;
}
function testSBC( value ) {
if( (regA ^ value ) & 0x80 )
vflag = 1;
else
vflag = 0;
if( regP & 8 ) {
tmp = 0xf + (regA & 0xf) - (value & 0xf) + (regP&1);
if( tmp < 0x10 ) {
w = 0;
tmp -= 6;
} else {
w = 0x10;
tmp -= 0x10;
}
w += 0xf0 + (regA & 0xf0) - (value & 0xf0);
if( w < 0x100 ) {
regP &= 0xfe;
if( (regP&0xbf) && w<0x80) regP&=0xbf;
w -= 0x60;
} else {
regP |= 1;
if( (regP&0xbf) && w>=0x180) regP&=0xbf;
}
w += tmp;
} else {
w = 0xff + regA - value + (regP&1);
if( w<0x100 ) {
regP &= 0xfe;
if( (regP&0xbf) && w<0x80 ) regP&=0xbf;
} else {
regP |= 1;
if( (regP&0xbf) && w>= 0x180) regP&=0xbf;
}
}
regA = w & 0xff;
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
}
function testADC( value ) {
if( (regA ^ value) & 0x80 ) {
regP &= 0xbf;
} else {
regP |= 0x40;
}
if( regP & 8 ) {
tmp = (regA & 0xf) + (value & 0xf) + (regP&1);
if( tmp >= 10 ) {
tmp = 0x10 | ((tmp+6)&0xf);
}
tmp += (regA & 0xf0) + (value & 0xf0);
if( tmp >= 160) {
regP |= 1;
if( (regP&0xbf) && tmp >= 0x180 ) regP &= 0xbf;
tmp += 0x60;
} else {
regP &= 0xfe;
if( (regP&0xbf) && tmp<0x80 ) regP &= 0xbf;
}
} else {
tmp = regA + value + (regP&1);
if( tmp >= 0x100 ) {
regP |= 1;
if( (regP&0xbf) && tmp>=0x180) regP &= 0xbf;
} else {
regP &= 0xfe;
if( (regP&0xbf) && tmp<0x80) regP &= 0xbf;
}
}
regA = tmp & 0xff;
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
}
function multiexecute() {
for( w=0; w<128; w++ ) execute();
}
/*
* execute() - Executes one instruction.
* This is the main part of the CPU emulator.
*
*/
function execute() {
if( ! codeRunning ) return;
opcode = popByte();
// message( "PC=" + addr2hex(regPC-1) + " opcode=" + opcode + " X="+regX + " Y=" + regY + " A=" + regA );
switch( opcode ) {
case 0x00: // BRK implied
codeRunning = false;
break;
case 0x01: // ORA INDX
addr = popByte() + regX;
value = memReadByte( addr ) + (memReadByte( addr+1) << 8);
regA |= value;
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x05: // ORA ZP
zp = popByte();
regA |= memReadByte( zp );
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x06: // ASL ZP
zp = popByte();
value = memReadByte( zp );
regP = (regP & 0xfe) | ((value>>7)&1);
value = value << 1;
memStoreByte( zp, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x08: // PHP
stackPush( regP );
break;
case 0x09: // ORA IMM
regA |= popByte();
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x0a: // ASL IMPL
regP = (regP & 0xfe) | ((regA>>7)&1);
regA = regA<<1;
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x0d: // ORA ABS
regA |= memReadByte( popWord() );
break;
case 0x0e: // ASL ABS
addr = popWord();
value = memReadByte( addr );
regP = (regP & 0xfe) | ((value>>7)&1);
value = value << 1;
memStoreByte( addr, value );
break;
case 0x10: // BPL
offset = popByte();
if( (regP & 0x80) == 0 ) jumpBranch( offset );
break;
case 0x11: // ORA INDY
zp = popByte();
value = memReadByte(zp) + (memReadByte(zp+1)<<8) + regY;
regA |= memReadByte(value);
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x15: // ORA ZPX
addr = (popByte() + regX) & 0xff;
regA |= memReadByte(addr);
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x16: // ASL ZPX
addr = (popByte() + regX) & 0xff;
value = memReadByte(addr);
regP = (regP & 0xfe) | ((value>>7)&1);
value = value << 1;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x18: // CLC
regP &= 0xfe;
break;
case 0x19: // ORA ABSY
addr = popWord() + regY;
regA |= memReadByte( addr );
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x1d: // ORA ABSX
addr = popWord() + regX;
regA |= memReadByte( addr );
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x1e: // ASL ABSX
addr = popWord() + regX;
value = memReadByte( addr );
regP = (regP & 0xfe) | ((value>>7)&1);
value = value << 1;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x20: // JSR ABS
addr = popWord();
currAddr = regPC-1;
stackPush( ((currAddr >> 8) & 0xff) );
stackPush( (currAddr & 0xff) );
regPC = addr;
break;
case 0x21: // AND INDX
addr = (popByte() + regX)&0xff;
value = memReadByte( addr ) + (memReadByte( addr+1) << 8);
regA &= value;
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x24: // BIT ZP
zp = popByte();
value = memReadByte( zp );
if( value & regA ) regP &= 0xfd; else regP |= 0x02;
regP = (regP & 0x3f) | (value & 0xc0);
break;
case 0x25: // AND ZP
zp = popByte();
value = memReadByte( zp ) & regA;
memStoreByte( zp, value );
break;
case 0x26: // ROL ZP
sf = (regP & 1);
addr = popByte();
value = memReadByte( addr ) & regA;
regP = (regP & 0xfe) | ((value>>7)&1);
value = value << 1;
value |= sf;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x28: // PLP
regP = stackPop() | 0x20;
break;
case 0x29: // AND IMM
regA &= popByte();
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x2a: // ROL A
sf = (regP&1);
regP = (regP&0xfe) | ((regA>>7)&1);
regA = regA << 1;
regA |= sf;
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x2c: // BIT ABS
value = memReadByte( popWord() );
if( value & regA ) regP &= 0xfd; else regP |= 0x02;
regP = (regP & 0x3f) | (value & 0xc0);
break;
case 0x2d: // AND ABS
value = memReadByte( popWord() );
regA &= value;
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x2e: // ROL ABS
sf = regP & 1;
addr = popWord();
value = memReadByte( addr );
regP = (regP & 0xfe) | ((value>>7)&1);
value = value << 1;
value |= sf;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x30: // BMI
offset = popByte();
if( regP & 0x80 ) jumpBranch( offset );
break;
case 0x31: // AND INDY
zp = popByte();
value = memReadByte(zp) + (memReadByte(zp+1)<<8) + regY;
regA &= memReadByte(value);
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x35: // AND INDX
zp = popByte();
value = memReadByte(zp) + (memReadByte(zp+1)<<8) + regX;
regA &= memReadByte(value);
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x36: // ROL ZPX
sf = regP & 1;
addr = (popByte() + regX) & 0xff;
value = memReadByte( addr );
regP = (regP & 0xfe) | ((value>>7)&1);
value = value << 1;
value |= sf;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x38: // SEC
regP |= 1;
break;
case 0x39: // AND ABSY
addr = popWord() + regY;
value = memReadByte( addr );
regA &= value;
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x3d: // AND ABSX
addr = popWord() + regX;
value = memReadByte( addr );
regA &= value;
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x3e: // ROL ABSX
sf = regP&1;
addr = popWord() + regX;
value = memReadByte( addr );
regP = (regP & 0xfe) | ((value>>7)&1);
value = value << 1;
value |= sf;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x40: // RTI (unsupported, =NOP)
break;
case 0x41: // EOR INDX
zp = (popByte() + regX)&0xff;
value = memReadByte(zp) + (memReadByte(zp+1)<<8);
regA ^= memReadByte(value);
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x45: // EOR ZPX
addr = (popByte() + regX) & 0xff;
value = memReadByte( addr );
regA ^= value;
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x46: // LSR ZP
addr = popByte() & 0xff;
value = memReadByte( addr );
regP = (regP & 0xfe) | (value&1);
value = value >> 1;
memStoreByte( addr, value );
if( value != 0 ) regP &= 0xfd; else regP |= 2;
if( (value&0x80) == 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x48: // PHA
stackPush( regA );
break;
case 0x49: // EOR IMM
regA ^= popByte();
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x4a: // LSR
regP = (regP&0xfe) | (regA&1);
regA = regA >> 1;
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x4c: // JMP abs
regPC = popWord();
break;
case 0x4d: // EOR abs
addr = popWord();
value = memReadByte( addr );
regA ^= value;
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x4e: // LSR abs
addr = popWord();
value = memReadByte( addr );
regP = (regP&0xfe)|(value&1);
value = value >> 1;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x50: // BVC (on overflow clear)
offset = popByte();
if( (regP & 0x40) == 0 ) jumpBranch( offset );
break;
case 0x51: // EOR INDY
zp = popByte();
value = memReadByte(zp) + (memReadByte(zp+1)<<8) + regY;
regA ^= memReadByte(value);
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x55: // EOR ZPX
addr = (popByte() + regX) & 0xff;
regA ^= memReadByte( addr );
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x56: // LSR ZPX
addr = (popByte() + regX) & 0xff;
value = memReadByte( addr );
regP = (regP&0xfe) | (value&1);
value = value >> 1;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x58: // CLI (does nothing)
break;
case 0x59: // EOR ABSY
addr = popWord() + regY;
value = memReadByte( addr );
regA ^= value;
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x5d: // EOR ABSX
addr = popWord() + regX;
value = memReadByte( addr );
regA ^= value;
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x5e: // LSR ABSX
addr = popWord() + regX;
value = memReadByte( addr );
regP = (regP&0xfe) | (value&1);
value = value >> 1;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x60: // RTS
regPC = (stackPop()+1) | (stackPop()<<8);
break;
case 0x61: // ADC INDX
zp = (popByte() + regX)&0xff;
addr = memReadByte(zp) + (memReadByte(zp+1)<<8);
value = memReadByte( addr );
testADC( value );
break;
case 0x65: // ADC ZP
addr = popByte();
value = memReadByte( addr );
testADC( value );
break;
case 0x66: // ROR ZP
sf = regP&1;
addr = popByte();
value = memReadByte( addr );
regP = (regP&0xfe)|(value&1);
value = value >> 1;
if( sf ) value |= 0x80;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x68: // PLA
regA = stackPop();
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x69: // ADC IMM
value = popByte();
testADC( value );
break;
case 0x6a: // ROR A
sf = regP&1;
regP = (regP&0xfe) | (regA&1);
regA = regA >> 1;
if( sf ) regA |= 0x80;
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x6c: // JMP INDIR
// regPC = memReadByte(popByte()) + (memReadByte(popByte())<<8);
break;
case 0x6d: // ADC ABS
addr = popWord();
value = memReadByte( addr );
testADC( value );
break;
case 0x6e: // ROR ABS
sf = regP&1;
addr = popWord();
value = memReadByte( addr );
regP = (regP&0xfe)|(value&1);
value = value >> 1;
if( sf ) value |= 0x80;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x70: // BVS (branch on overflow set)
offset = popByte();
if( regP & 0x40 ) jumpBranch( offset );
break;
case 0x71: // ADC INY
zp = popByte();
addr = memReadByte(zp) + (memReadByte(zp+1)<<8);
value = memReadByte( addr + regY );
testADC( value );
break;
case 0x75: // ADC ZPX
addr = (popByte() + regX) & 0xff;
value = memReadByte( addr );
regP = (regP&0xfe) | (value&1);
testADC( value );
break;
case 0x76: // ROR ZPX
sf = (regP&1);
addr = (popByte() + regX) & 0xff;
value = memReadByte( addr );
regP = (regP&0xfe) | (value&1);
value = value >> 1;
if( sf ) value |= 0x80;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x78: // SEI (does nothing)
break;
case 0x79: // ADC ABSY
addr = popWord();
value = memReadByte( addr + regY );
testADC( value );
break;
case 0x7d: // ADC ABSX
addr = popWord();
value = memReadByte( addr + regX );
testADC( value );
break;
case 0x7e: // ROR ABSX
sf = regP&1;
addr = popWord() + regX;
value = memReadByte( addr );
regP = (regP&0xfe) | (value&1);
value = value >> 1;
if( value ) value |= 0x80;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x81: // STA INDX
zp = (popByte()+regX)&0xff;
addr = memReadByte(zp) + (memReadByte(zp+1)<<8);
memStoreByte( addr, regA );
break;
case 0x84: // STY ZP
memStoreByte( popByte(), regY );
break;
case 0x85: // STA ZP
memStoreByte( popByte(), regA );
break;
case 0x86: // STX ZP
memStoreByte( popByte(), regX );
break;
case 0x88: // DEY (1 byte)
regY = (regY-1) & 0xff;
if( regY ) regP &= 0xfd; else regP |= 0x02;
if( regY & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x8a: // TXA (1 byte);
regA = regX & 0xff;
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x8c: // STY abs
memStoreByte( popWord(), regY );
break;
case 0x8d: // STA ABS (3 bytes)
memStoreByte( popWord(), regA );
break;
case 0x8e: // STX abs
memStoreByte( popWord(), regX );
break;
case 0x90: // BCC (branch on carry clear)
offset = popByte();
if( ( regP & 1 ) == 0 ) jumpBranch( offset );
break;
case 0x91: // STA INDY
zp = popByte();
addr = memReadByte(zp) + (memReadByte(zp+1)<<8) + regY;
memStoreByte( addr, regA );
break;
case 0x94: // STY ZPX
memStoreByte( popByte() + regX, regY );
break;
case 0x95: // STA ZPX
memStoreByte( popByte() + regX, regA );
break;
case 0x96: // STX ZPY
memStoreByte( popByte() + regY, regX );
break;
case 0x98: // TYA
regA = regY & 0xff;
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0x99: // STA ABSY
memStoreByte( popWord() + regY, regA );
break;
case 0x9a: // TXS
regSP = regX & 0xff;
break;
case 0x9d: // STA ABSX
addr = popWord();
memStoreByte( addr + regX, regA );
break;
case 0xa0: // LDY IMM
regY = popByte();
if( regY ) regP &= 0xfd; else regP |= 0x02;
if( regY & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xa1: // LDA INDX
zp = (popByte()+regX)&0xff;
addr = memReadByte(zp) + (memReadByte(zp+1)<<8);
regA = memReadByte( addr );
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xa2: // LDX IMM
regX = popByte();
if( regX ) regP &= 0xfd; else regP |= 0x02;
if( regX & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xa4: // LDY ZP
regY = memReadByte( popByte() );
if( regY ) regP &= 0xfd; else regP |= 0x02;
if( regY & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xa5: // LDA ZP
regA = memReadByte( popByte() );
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xa6: // LDX ZP
regX = memReadByte( popByte() );
if( regX ) regP &= 0xfd; else regP |= 0x02;
if( regX & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xa8: // TAY
regY = regA & 0xff;
if( regY ) regP &= 0xfd; else regP |= 0x02;
if( regY & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xa9: // LDA IMM
regA = popByte();
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xaa: // TAX
regX = regA & 0xff;
if( regX ) regP &= 0xfd; else regP |= 0x02;
if( regX & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xac: // LDY ABS
regY = memReadByte( popWord() );
if( regY ) regP &= 0xfd; else regP |= 0x02;
if( regY & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xad: // LDA ABS
regA = memReadByte( popWord() );
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xae: // LDX ABS
regX = memReadByte( popWord() );
if( regX ) regP &= 0xfd; else regP |= 0x02;
if( regX & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xb0: // BCS
offset = popByte();
if( regP & 1 ) jumpBranch( offset );
break;
case 0xb1: // LDA INDY
zp = popByte();
addr = memReadByte(zp) + (memReadByte(zp+1)<<8) + regY;
regA = memReadByte( addr );
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xb4: // LDY ZPX
regY = memReadByte( popByte() + regX );
if( regY ) regP &= 0xfd; else regP |= 0x02;
if( regY & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xb5: // LDA ZPX
regA = memReadByte( (popByte() + regX) & 0xff );
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xb6: // LDX ZPY
regX = memReadByte( popByte() + regY );
if( regX ) regP &= 0xfd; else regP |= 0x02;
if( regX & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xb8: // CLV
regP &= 0xbf;
break;
case 0xb9: // LDA ABSY
addr = popWord() + regY;
regA = memReadByte( addr );
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xba: // TSX
regX = regSP & 0xff;
break;
case 0xbc: // LDY ABSX
addr = popWord() + regX;
regY = memReadByte( addr );
if( regY ) regP &= 0xfd; else regP |= 0x02;
if( regY & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xbd: // LDA ABSX
addr = popWord() + regX;
regA = memReadByte( addr );
if( regA ) regP &= 0xfd; else regP |= 0x02;
if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xbe: // LDX ABSY
addr = popWord() + regY;
regX = memReadByte( addr );
if( regX ) regP &= 0xfd; else regP |= 0x02;
if( regX & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xc0: // CPY IMM
value = popByte();
if( (regY+value) > 0xff ) regP |= 1; else regP &= 0xfe;
ov = value;
value = (regY-value);
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xc1: // CMP INDY
zp = popByte();
addr = memReadByte(zp) + (memReadByte(zp+1)<<8) + regY;
value = memReadByte( addr );
doCompare( regA, value );
break;
case 0xc4: // CPY ZP
value = memReadByte( popByte() );
doCompare( regY, value );
break;
case 0xc5: // CMP ZP
value = memReadByte( popByte() );
doCompare( regA, value );
break;
case 0xc6: // DEC ZP
zp = popByte();
value = memReadByte( zp );
--value;
memStoreByte( zp, value&0xff );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xc8: // INY
regY = (regY + 1) & 0xff;
if( regY ) regP &= 0xfd; else regP |= 0x02;
if( regY & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xc9: // CMP IMM
value = popByte();
doCompare( regA, value );
break;
case 0xca: // DEX
regX = (regX-1) & 0xff;
if( regX ) regP &= 0xfd; else regP |= 0x02;
if( regX & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xcc: // CPY ABS
value = memReadByte( popWord() );
doCompare( regY, value );
break;
case 0xcd: // CMP ABS
value = memReadByte( popWord() );
doCompare( regA, value );
break;
case 0xce: // DEC ABS
addr = popWord();
value = memReadByte( addr );
--value;
value = value&0xff;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xd0: // BNE
offset = popByte();
// if( (regP&2)==0 ) { oldPC = regPC; jumpBranch( offset ); message( "Jumping from " + addr2hex(oldPC) + " to " + addr2hex(regPC) ); } else { message( "NOT jumping!" ); }
if( (regP&2)==0 ) jumpBranch( offset );
break;
case 0xd1: // CMP INDY
zp = popByte();
addr = memReadByte(zp) + (memReadByte(zp+1)<<8) + regY;
value = memReadByte( addr );
doCompare( regA, value );
break;
case 0xd5: // CMP ZPX
value = memReadByte( popByte() + regX );
doCompare( regA, value );
break;
case 0xd6: // DEC ZPX
addr = popByte() + regX;
value = memReadByte( addr );
--value;
value = value&0xff;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xd8: // CLD (CLear Decimal)
regP &= 0xf7;
break;
case 0xd9: // CMP ABSY
addr = popWord() + regY;
value = memReadByte( addr );
doCompare( regA, value );
break;
case 0xdd: // CMP ABSX
addr = popWord() + regX;
value = memReadByte( addr );
doCompare( regA, value );
break;
case 0xde: // DEC ABSX
addr = popWord() + regX;
value = memReadByte( addr );
--value;
value = value&0xff;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xe0: // CPX IMM
value = popByte();
doCompare( regX, value );
break;
case 0xe1: // SBC INDX
zp = (popByte()+regX)&0xff;
addr = memReadByte(zp) + (memReadByte(zp+1)<<8);
value = memReadByte( addr );
testSBC( value );
break;
case 0xe4: // CPX ZP
value = memReadByte( popByte() );
doCompare( regX, value );
break;
case 0xe5: // SBC ZP
addr = popByte();
value = memReadByte( addr );
testSBC( value );
break;
case 0xe6: // INC ZP
zp = popByte();
value = memReadByte( zp );
++value;
value = (value)&0xff;
memStoreByte( zp, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xe8: // INX
regX = (regX + 1) & 0xff;
if( regX ) regP &= 0xfd; else regP |= 0x02;
if( regX & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xe9: // SBC IMM
value = popByte();
testSBC( value );
break;
case 0xea: // NOP
break;
case 0xec: // CPX ABS
value = memReadByte( popWord() );
doCompare( regX, value );
break;
case 0xed: // SBC ABS
addr = popWord();
value = memReadByte( addr );
testSBC( value );
break;
case 0xee: // INC ABS
addr = popWord();
value = memReadByte( addr );
++value;
value = (value)&0xff;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xf0: // BEQ
offset = popByte();
if( regP&2 ) jumpBranch( offset );
break;
case 0xf1: // SBC INDY
zp = popByte();
addr = memReadByte(zp) + (memReadByte(zp+1)<<8);
value = memReadByte( addr + regY );
testSBC( value );
break;
case 0xf5: // SBC ZPX
addr = (popByte() + regX)&0xff;
value = memReadByte( addr );
regP = (regP&0xfe)|(value&1);
testSBC( value );
break;
case 0xf6: // INC ZPX
addr = popByte() + regX;
value = memReadByte( addr );
++value;
value=value&0xff;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
case 0xf8: // SED
regP |= 8;
break;
case 0xf9: // SBC ABSY
addr = popWord();
value = memReadByte( addr + regY );
testSBC( value );
break;
case 0xfd: // SBC ABSX
addr = popWord();
value = memReadByte( addr + regX );
testSBC( value );
break;
case 0xfe: // INC ABSX
addr = popWord() + regX;
value = memReadByte( addr );
++value;
value=value&0xff;
memStoreByte( addr, value );
if( value ) regP &= 0xfd; else regP |= 0x02;
if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f;
break;
default:
message( "Address $" + addr2hex(regPC) + " - unknown opcode " + opcode );
codeRunning = false;
break;
}
if( (regPC == 0) || (!codeRunning) ) {
clearInterval( myInterval );
message( "Program end at PC=$" + addr2hex( regPC-1 ) );
codeRunning = false;
document.getElementById( "runButton" ).value = "Run";
document.getElementById( "fileSelect" ).disabled = false;
document.getElementById( "hexdumpButton" ).disabled = false;
// updateDisplayFull();
}
}
/*
* updatePixelDisplay() - Updates the display at one pixel position
*
*/
function updateDisplayPixel( addr ) {
display[addr-0x200].background = palette[memory[addr] & 0x0f];
}
/*
* updateDisplayFull() - Simply redraws the entire display according to memory
* The colors are supposed to be identical with the C64's palette.
*
*/
function updateDisplayFull() {
for( y=0; y<32; y++ ) {
for( x=0; x<32; x++ ) {
updateDisplayPixel( ((y<<5)+x) + 0x200 );
}
}
}