#include #include #include "6502.h" byte regA, regX, regY, regP, regS; word regPC; byte mem[65536], memt[65536]; enum { flagC = 1, flagZ = 2, flagI = 4, flagD = 8, flagB = 16, flagV = 64, flagN = 128 }; int readhandler(int addr); void writehandler(int val, int addr); void undefined(void); void push(byte b) { mem[0x100 + regS--] = b; } void pop(byte *b) { *b = mem[0x100 + ++regS]; } word adimm(void) { return regPC++; } word adabs(void) { word r = mem[regPC] | (mem[regPC+1] << 8); regPC += 2; return r; } word adabsx(void) { return adabs() + regX; } word adabsy(void) { return adabs() + regY; } word adzp(void) { return mem[regPC++]; } word adzpx(void) { return (adzp() + regX) & 0xFF; } word adindzpx(void) { word a = adzpx(); word b = mem[a] | (mem[a+1] << 8); return b; } word adindzpy(void) { word a = adzp(); word b = (mem[a] | (mem[a+1] << 8)) + regY; return b; } void branch(void) { signed char b = mem[adimm()]; regPC += b; } byte memread(word w) { if(memt[w] & 1) return mem[w]; return readhandler(w); } void memwrite(word w, byte b) { if(memt[w] & 2) mem[w] = b; else writehandler(b, w); } void szflag(byte v) { regP &= ~(flagN | flagZ); regP |= v & flagN; if(v == 0) regP |= flagZ; } void setcarry(byte i) { regP &= ~flagC; if(i) regP |= flagC; } void compare(byte a, byte b) { regP &= ~(flagN | flagZ | flagC); if(a == b) regP |= flagZ; regP |= a & 0x80; if(a >= b) regP |= flagC; } void step(void) { byte opcode = mem[regPC++], a, b, c, r; word w; switch(opcode) { case 0x00: regP |= flagB; irq(); break; case 0x08: push(regP); break; case 0x0A: setcarry(regA & 128); regA <<= 1; szflag(regA); break; case 0x10: if(!(regP & flagN)) branch(); else regPC++; break; case 0x18: regP &= ~flagC; break; case 0x20: w = adabs(); regPC--; push(regPC >> 8); push(regPC & 0xFF); regPC = w; break; case 0x28: pop(®P); break; case 0x30: if(regP & flagN) branch(); else regPC++; break; case 0x38: regP |= flagC; break; case 0x48: push(regA); break; case 0x4A: setcarry(regA & 1); regA >>= 1; szflag(regA); break; case 0x4C: regPC = adabs(); break; case 0x50: if(!(regP & flagV)) branch(); else regPC++; break; case 0x60: pop((byte*) (®PC)); pop((byte*) (®PC) + 1); regPC++; break; case 0x58: regP &= ~flagI; break; case 0x68: pop(®A); break; case 0x70: if(regP & flagV) branch(); else regPC++; break; case 0x78: regP |= flagI; break; case 0x88: regY--; break; case 0x89: undefined(); break; /* would be considered STA # */ case 0x8A: regA = regX; break; case 0x90: if(!(regP & flagC)) branch(); else regPC++; break; case 0x98: regA = regY; break; case 0x9A: regS = regX; break; case 0xA2: regX = memread(adimm()); szflag(regX); break; case 0xA8: regY = regA; break; case 0xAA: regX = regA; break; case 0xB0: if(regP & flagC) branch(); else regPC++; break; case 0xB8: regP &= ~flagV; break; case 0xBA: regX = regS; break; case 0xC8: regY++; break; case 0xCA: regX--; break; case 0xD0: if(!(regP & flagZ)) branch(); else regPC++; break; case 0xD4: undefined(); break; /* would be considered CPY zp, X */ case 0xD8: regP &= ~flagD; break; case 0xDC: undefined(); break; /* would be considered CPY abs, X */ case 0xE8: regX++; break; case 0xEA: break; case 0xF0: if(regP & flagZ) branch(); else regPC++; break; case 0xF4: undefined(); break; /* would be considered CPX zp, X */ case 0xFC: undefined(); break; /* would be considered CPX abs, X */ case 0xF8: regP |= flagD; break; default: goto undecoded; } return; undecoded: a = opcode >> 5; b = (opcode >> 2) & 7;; c = opcode & 3; if(c == 1) { word (*ad[8])(void) = {adindzpx, adzp, adimm, adabs, adindzpy, adzpx, adabsy, adabsx}; switch(a) { case 0: regA |= memread(ad[b]()); szflag(regA); break; case 1: regA &= memread(ad[b]()); szflag(regA); break; case 2: regA ^= memread(ad[b]()); szflag(regA); break; case 4: memwrite(ad[b](), regA); break; case 5: regA = memread(ad[b]()); szflag(regA); break; case 6: compare(regA, memread(ad[b]())); break; case 7: w = regA - memread(ad[b]()) - 1 + (regP & flagC); regP &= ~flagC; if(w < 0x100) regP |= flagC; regA = w & 0xFF; szflag(regA); break; default: undefined(); } } else if(c == 2) { word (*ad[8])(void) = {0, adzp, 0, adabs, 0, adzpx, 0, adabsx}; if(ad[b] == 0) undefined(); switch(a) { case 5: regX = memread(ad[b]()); szflag(regX); break; case 6: w = ad[b](); r = memread(w) - 1; memwrite(w, r); szflag(r); break; case 7: w = ad[b](); r = memread(w) + 1; memwrite(w, r); szflag(r); break; default: undefined(); } } else if(c == 0) { word (*ad[8])(void) = {adimm, adzp, 0, adabs, 0, adzpx, 0, adabsx}; if(ad[b] == 0) undefined(); switch(a) { case 5: regY = memread(ad[b]()); szflag(regY); break; case 6: compare(regY, memread(ad[b]())); break; case 7: compare(regX, memread(ad[b]())); break; default: undefined(); } } else undefined(); } void nmi(void) { push(regPC & 0xFF); push(regPC >> 8); push(regP); regPC = mem[0xFFFA] | (mem[0xFFFB] << 8); } void irq(void) { push(regPC & 0xFF); push(regPC >> 8); push(regP); regPC = mem[0xFFFE] | (mem[0xFFFF] << 8); }