| // mode = 7 - Indirect, X | // mode = 7 - Indirect, X | ||||
| // mode = 8 - Indirect, Y | // mode = 8 - Indirect, Y | ||||
| function ProcessOp(cpu, mode){ | function ProcessOp(cpu, mode){ | ||||
| if (mode < 0 || mode > 9){return false;} | |||||
| switch(cpu.__cycle){ | switch(cpu.__cycle){ | ||||
| case 0: | case 0: | ||||
| cpu.__mem.address = cpu.__PC; | |||||
| PCUp(cpu, 1); | |||||
| cpu.__opv = cpu.__mem.byte; | |||||
| return (mode === 0); | |||||
| if (mode === 0){ | |||||
| cpu.__mem.address = cpu.__PC; | |||||
| PCUp(cpu, 1); | |||||
| cpu.__opv = cpu.__mem.byte; | |||||
| } | |||||
| return (mode === 0 || mode === 9); | |||||
| case 1: | case 1: | ||||
| switch(mode){ | switch(mode){ | ||||
| case 1: // Zero Page | case 1: // Zero Page | ||||
| function ADC(cpu){ // To be used by both the ADC and SBC op codes. | function ADC(cpu){ // To be used by both the ADC and SBC op codes. | ||||
| let pmode = [0x69, 0x65, 0x75, null, 0x6D, 0x7D, 0x79, 0x61, 0x71].indexOf(cpu.__op); | |||||
| let pmode = [0x69, 0x65, 0x75, null, 0x6D, 0x7D, 0x79, 0x61, 0x71, null].indexOf(cpu.__op); | |||||
| if (ProcessOp(cpu, pmode) === true){ | if (ProcessOp(cpu, pmode) === true){ | ||||
| cpu.__op = -1; | cpu.__op = -1; | ||||
| ALU(cpu, 0, cpu.__opv); | ALU(cpu, 0, cpu.__opv); | ||||
| } | } | ||||
| } | } | ||||
| /*function MATHC(cpu, m){ // To be used by both the ADC and SBC op codes. | |||||
| // m == 0 - Add | |||||
| // m == 1 - Subtract | |||||
| switch(cpu.__step){ | |||||
| case 0: | |||||
| cpu.__mem.address = cpu.__PC; | |||||
| PCUp(cpu, 1); | |||||
| cpu.__opv = cpu.__mem.byte; | |||||
| if (cpu.__op == 0x69){ // Immediate | |||||
| ALU(cpu, m, cpu.__opv); | |||||
| cpu.__op = -1; break; | |||||
| } | |||||
| case 1: | |||||
| switch (cpu.__op){ | |||||
| case 0x65: // Zero Page | |||||
| cpu.__mem.address = cpu.__opv; | |||||
| ALU(cpu, m, cpu.__mem.byte); | |||||
| cpu.__op = -1; break; | |||||
| case 0x75: // Zero Page, X | |||||
| cpu.__opv = (cpu.__opv + cpu.__XR) & 0xFF; break; | |||||
| case 0x6D: // Absolute | |||||
| case 0x7D: // Absolute, X | |||||
| case 0x79: // Absolute, Y | |||||
| cpu.__mem.address = cpu.__PC; | |||||
| PCUp(cpu, 1); | |||||
| cpu.__opv |= cpu.__mem.byte << 8; break; | |||||
| case 0x61: // Indirect, X | |||||
| cpu.__opv = (cpu.__opv + cpu.__XR) & 0xFF; break; | |||||
| case 0x71: // Indirect, Y | |||||
| cpu.__mem.address = cpu.__opv; | |||||
| cpu.__opv = cpu.__mem.byte; | |||||
| break; | |||||
| } | |||||
| break; | |||||
| case 2: | |||||
| switch (cpu.__op){ | |||||
| case 0x75: // Zero Page, X | |||||
| case 0x6D: // Absolute | |||||
| cpu.__mem.address = cpu.__opv; | |||||
| ALU(cpu, m, cpu.__mem.byte); | |||||
| cpu.__op = -1; break; | |||||
| case 0x7D: // Absolute, X | |||||
| case 0x79: // Absolute, Y | |||||
| let s = (cpu.__op === 0x7D) ? cpu.__XR : cpu.__YR; | |||||
| let l = (cpu.__opv & 0xFF) + s; | |||||
| cpu.__opv = (cpu.__opv & 0xFF00) | (l & 0xFF); | |||||
| if (l < 255){ | |||||
| cpu.__mem.address = cpu.__opv; | |||||
| ALU(cpu, m, cpu.__mem.byte); | |||||
| cpu.__op = -1; | |||||
| } | |||||
| break; | |||||
| case 0x61: // Indirect, X | |||||
| cpu.__mem.address = cpu.__opv; | |||||
| cpu.__opv = cpu.__mem.byte; | |||||
| break; | |||||
| case 0x71: // Indirect, Y | |||||
| cpu.__mem.address += 1; | |||||
| cpu.__opv |= cpu.__mem.byte << 8; | |||||
| break; | |||||
| } | |||||
| break; | |||||
| case 3: | |||||
| switch (cpu.__op){ | |||||
| case 0x7D: // Absolute, X | |||||
| case 0x79: // Absolute, Y | |||||
| let h = (cpu.__opv >> 8) + 1; | |||||
| cpu.__mem.address = (cpu.__opv & 0xFF) | (h << 8); | |||||
| ALU(cpu, m, cpu.__mem.byte); | |||||
| cpu.__op = -1; break; | |||||
| case 0x61: // Indirect, X | |||||
| cpu.__mem.address += 1; | |||||
| cpu.__opv |= cpu.__mem.byte << 8; | |||||
| break; | |||||
| case 0x71: // Indirect, Y | |||||
| let l = (cpu.__opv & 0xFF) + cpu.__YR; | |||||
| cpu.__opv = (cpu.__opv & 0xFF00) | (l & 0xFF); | |||||
| if (l <= 255){ | |||||
| cpu.__mem.address = cpu.__opv; | |||||
| ALU(cpu, m, cpu.__mem.byte); | |||||
| cpu.__op = -1; break; | |||||
| } | |||||
| } | |||||
| break; | |||||
| case 4: | |||||
| if (cpu.__op === 0x71){ | |||||
| let h = (cpu.__opv >> 8) + 1; | |||||
| cpu.__opv = (cpu.__opv & 0x00FF) | (h << 8); | |||||
| } | |||||
| cpu.__mem.address = cpu.__opv; | |||||
| ALU(cpu, m, cpu.__mem.byte); | |||||
| cpu.__op = -1; break; | |||||
| } | |||||
| cpu.__step += 1; | |||||
| }*/ | |||||
| function AND(cpu){ | function AND(cpu){ | ||||
| let pmode = [0x29, 0x25, 0x35, null, 0x2D, 0x3D, 0x39, 0x21, 0x31, null].indexOf(cpu.__op); | |||||
| if (ProcessOp(cpu, pmode) === true){ | |||||
| cpu.__op = -1; | |||||
| this.__AR &= this.__opv; | |||||
| cpu.Z = (this.__AR === 0); | |||||
| cpu.N = BITM.val(this.__AR, 7); | |||||
| } | |||||
| } | } | ||||
| function ASL(cpu){ | function ASL(cpu){ | ||||
| let pmode = [null, 0x06, 0x16, null, 0x0E, 0x1E, null, null, null, 0x0A].indexOf(cpu.__op); | |||||
| if (cpu.__ophold === 1){pmode = -1;} | |||||
| if (cpu.__ophold === 1 || ProcessOp(cpu, pmode) === true){ | |||||
| if (cpu.__ophold === 0){ | |||||
| cpu.__opv = (mode === 9) ? cpu.__AR : cpu.__opv; | |||||
| cpu.C = BITM.val(cpu.__opv, 7); | |||||
| cpu.__opv = cpu.__opv << 1; | |||||
| cpu.__ophold = 1; | |||||
| } else { | |||||
| if (mode === 9){ | |||||
| cpu.__AR = cpu.__opv; | |||||
| } else { | |||||
| cpu.__mem.byte = cpu.__opv; | |||||
| } | |||||
| cpu.Z = (this.__opv === 0); | |||||
| cpu.N = BITM.val(this.__opv, 7); | |||||
| cpu.__op = -1; | |||||
| cpu.__ophold = 0; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| function BIT(cpu){ | function BIT(cpu){ | ||||
| let pmode = [null, 0x24, null, null, 0x2C, null, null, null, null, null].indexOf(cpu.__op); | |||||
| if (ProcessOp(cpu, pmode) === true){ | |||||
| cpu.__op = -1; | |||||
| let v = this.__AR & this.__opv; | |||||
| cpu.Z = (v === 0); | |||||
| cpu.N = BITM.val(this.__opv, 7); | |||||
| cpu.V = BITM.val(this.__opv, 6); | |||||
| } | |||||
| } | } | ||||
| function BRANCH(cpu){ | function BRANCH(cpu){ | ||||
| } | } | ||||
| function BRK(cpu){ | function BRK(cpu){ | ||||
| switch(cpu.__cycle){ | |||||
| case 0: | |||||
| PCUp(cpu, 1); | |||||
| case 1: | |||||
| cpu.__mem.address = cpu.__SP; | |||||
| cpu.__mem.byte = cpu.__PC & 0xFF; | |||||
| cpu.__SP = ByteWrap(cpu.__SP, -1); | |||||
| break; | |||||
| case 2: | |||||
| cpu.__mem.address += 1; | |||||
| cpu.__mem.byte = cpu.__PC >> 8; | |||||
| cpu.__SP = ByteWrap(cpu.__SP, -1); | |||||
| break; | |||||
| case 3: | |||||
| cpu.__mem.address += 1; | |||||
| cpu.__mem.byte = cpu.__PR; | |||||
| cpu.__SP = ByteWrap(cpu.__SP, -1); | |||||
| case 4: | |||||
| cpu.__mem.address = 0xFFFE; | |||||
| cpu.__PC = cpu.__mem.byte; | |||||
| break; | |||||
| case 5: | |||||
| cpu.__mem.address = 0xFFFF; | |||||
| cpu.__PC |= cpu.__mem.byte << 8; | |||||
| cpu.B = 1; | |||||
| cpu.__op = -1; | |||||
| break; | |||||
| } | |||||
| cpu.__cycle += 1; | |||||
| } | } | ||||
| function CMP(cpu){ | function CMP(cpu){ | ||||
| let pmode = [0xC9, 0xC5, 0xD5, null, 0xCD, 0xDD, 0xD9, 0xC1, 0xD1, null].indexOf(cpu.__op); | |||||
| if (ProcessOp(cpu, pmode) === true){ | |||||
| cpu.__op = -1; | |||||
| cpu.C = (cpu.__AR >= cpu.__opv); | |||||
| cpu.Z = (this.__AR === cpu.__opv); | |||||
| let v = this.__AR - cpu.__opv; | |||||
| if (v < 0){v += 256;} | |||||
| cpu.N = BITM.val(v, 7); | |||||
| } | |||||
| } | } | ||||
| function CPX(cpu){ | function CPX(cpu){ | ||||
| let pmode = [0xE0, 0xE4, null, null, 0xEC, null, null, null, null, null].indexOf(cpu.__op); | |||||
| if (ProcessOp(cpu, pmode) === true){ | |||||
| cpu.__op = -1; | |||||
| cpu.C = (cpu.__XR >= cpu.__opv); | |||||
| cpu.Z = (this.__XR === cpu.__opv); | |||||
| let v = this.__XR - cpu.__opv; | |||||
| if (v < 0){v += 256;} | |||||
| cpu.N = BITM.val(v, 7); | |||||
| } | |||||
| } | } | ||||
| function CPY(cpu){ | function CPY(cpu){ | ||||
| let pmode = [0xC0, 0xC4, null, null, 0xCC, null, null, null, null, null].indexOf(cpu.__op); | |||||
| if (ProcessOp(cpu, pmode) === true){ | |||||
| cpu.__op = -1; | |||||
| cpu.C = (cpu.__YR >= cpu.__opv); | |||||
| cpu.Z = (this.__YR === cpu.__opv); | |||||
| let v = this.__YR - cpu.__opv; | |||||
| if (v < 0){v += 256;} | |||||
| cpu.N = BITM.val(v, 7); | |||||
| } | |||||
| } | } | ||||
| function DEC(cpu){ | function DEC(cpu){ | ||||
| let pmode = [null, 0xC6, 0xD6, null, 0xCE, 0xDE, null, null, null, null].indexOf(cpu.__op); | |||||
| if (cpu.__ophold === 1){pmode = -1;} | |||||
| if (cpu.__ophold === 1 || ProcessOp(cpu, pmode) === true){ | |||||
| if (cpu.__ophold === 0){ | |||||
| cpu.__opv = ByteWrap(cpu.__opv, -1); | |||||
| cpu.__ophold = 1; | |||||
| } else { | |||||
| cpu.__mem.byte = cpu.__opv; | |||||
| cpu.Z = (this.__opv === 0); | |||||
| cpu.N = BITM.val(this.__opv, 7); | |||||
| cpu.__op = -1; | |||||
| cpu.__ophold = 0; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| function EOR(cpu){ | function EOR(cpu){ | ||||
| let pmode = [0x49, 0x45, 0x55, null, 0x4D, 0x5D, 0x59, 0x41, 0x51, null].indexOf(cpu.__op); | |||||
| if (ProcessOp(cpu, pmode) === true){ | |||||
| cpu.__op = -1; | |||||
| cpu.__AR ^= cpu.__opv; | |||||
| cpu.Z = (cpu.__AR === 0); | |||||
| cpu.N = BITM.val(cpu.__AR, 7); | |||||
| } | |||||
| } | } | ||||
| function FLAG(cpu){ | function FLAG(cpu){ | ||||
| } | } | ||||
| function INC(cpu){ | function INC(cpu){ | ||||
| let pmode = [null, 0xE6, 0xF6, null, 0xEE, 0xFE, null, null, null, null].indexOf(cpu.__op); | |||||
| if (cpu.__ophold === 1){pmode = -1;} | |||||
| if (cpu.__ophold === 1 || ProcessOp(cpu, pmode) === true){ | |||||
| if (cpu.__ophold === 0){ | |||||
| cpu.__opv = ByteWrap(cpu.__opv, 1); | |||||
| cpu.__ophold = 1; | |||||
| } else { | |||||
| cpu.__mem.byte = cpu.__opv; | |||||
| cpu.Z = (this.__opv === 0); | |||||
| cpu.N = BITM.val(this.__opv, 7); | |||||
| cpu.__op = -1; | |||||
| cpu.__ophold = 0; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| function JMP(cpu){ | function JMP(cpu){ | ||||
| switch(cpu.__cycle){ | |||||
| case 0: | |||||
| cpu.__mem.address = cpu.__PC; | |||||
| cpu.__opv = cpu.__mem.byte; | |||||
| PCUp(cpu, 1); break; | |||||
| case 1: | |||||
| cpu.__mem.address = cpu.__PC; | |||||
| cpu.__opv |= cpu.__mem.byte << 8; | |||||
| if (cpu.__op === 0x4C){ | |||||
| cpu.__PC = cpu.__opv; | |||||
| cpu.__op = -1; | |||||
| } | |||||
| break; | |||||
| case 2: | |||||
| cpu.__mem.address = cpu.__opv; | |||||
| cpu.__PC = cpu.__mem.byte; | |||||
| break; | |||||
| case 3: | |||||
| cpu.__mem.address += 1; | |||||
| cpu.__PC |= cpu.__mem.byte << 8; | |||||
| cpu.__op = -1; | |||||
| break; | |||||
| } | |||||
| cpu.__cycle += 1; | |||||
| } | } | ||||
| function JRS(cpu){ | function JRS(cpu){ | ||||
| switch(cpu.__cycle){ | |||||
| case 0: | |||||
| cpu.__mem.address = cpu.__PC; | |||||
| cpu.__opv = cpu.__mem.byte; | |||||
| PCUp(cpu, 1); break; | |||||
| case 1: | |||||
| // Discard stack data (or... No Op) | |||||
| break; | |||||
| case 2: | |||||
| cpu.__mem.address = cpu.__SP; | |||||
| cpu.__mem.byte = cpu.__PC & 0xFF; | |||||
| cpu.__SP = ByteWrap(cpu.__SP, -1); | |||||
| break; | |||||
| case 3: | |||||
| cpu.__mem.address -= 1; | |||||
| cpu.__mem.byte = cpu.__PC >> 8; | |||||
| cpu.__SP = ByteWrap(cpu.__SP, -1); | |||||
| break; | |||||
| case 4: | |||||
| cpu.__mem.address = cpu.__PC; | |||||
| cpu.__PC = cpu.__opv | (cpu.__mem.byte << 8) | |||||
| cpu.__op = -1; | |||||
| break; | |||||
| } | |||||
| cpu.__cycle += 1; | |||||
| } | } | ||||
| function LDA(cpu){ | function LDA(cpu){ | ||||
| let pmode = [0xA9, 0xA5, 0xB5, null, 0xAD, 0xBD, 0xB9, 0xA1, 0xB1].indexOf(cpu.__op); | |||||
| let pmode = [0xA9, 0xA5, 0xB5, null, 0xAD, 0xBD, 0xB9, 0xA1, 0xB1, null].indexOf(cpu.__op); | |||||
| if (ProcessOp(cpu, pmode) === true){ | if (ProcessOp(cpu, pmode) === true){ | ||||
| cpu.__op = -1; | cpu.__op = -1; | ||||
| cpu.__AR = cpu.__opv; | cpu.__AR = cpu.__opv; | ||||
| } | } | ||||
| function LDX(cpu){ | function LDX(cpu){ | ||||
| let pmode = [0xA2, 0xA6, null, 0xB6, 0xAE, null, 0xBE, null, null, null].indexOf(cpu.__op); | |||||
| if (ProcessOp(cpu, pmode) === true){ | |||||
| cpu.__op = -1; | |||||
| cpu.__XR = cpu.__opv; | |||||
| cpu.Z = (cpu.__XR === 0); | |||||
| cpu.N = (cpu.__XR >= 0x80); | |||||
| } | |||||
| } | } | ||||
| function LDY(cpu){ | function LDY(cpu){ | ||||
| let pmode = [0xA0, 0xA4, 0xB4, null, 0xAC, 0xBC, null, null, null, null].indexOf(cpu.__op); | |||||
| if (ProcessOp(cpu, pmode) === true){ | |||||
| cpu.__op = -1; | |||||
| cpu.__YR = cpu.__opv; | |||||
| cpu.Z = (cpu.__YR === 0); | |||||
| cpu.N = (cpu.__YR >= 0x80); | |||||
| } | |||||
| } | } | ||||
| function LSR(cpu){ | function LSR(cpu){ | ||||
| let pmode = [null, 0x46, 0x56, null, 0x4E, 0x5E, null, null, null, 0x4A].indexOf(cpu.__op); | |||||
| if (cpu.__ophold === 1){pmode = -1;} | |||||
| if (cpu.__ophold === 1 || ProcessOp(cpu, pmode) === true){ | |||||
| if (cpu.__ophold === 0){ | |||||
| cpu.__opv = (mode === 9) ? cpu.__AR : cpu.__opv; | |||||
| cpu.C = BITM.val(cpu.__opv, 0); | |||||
| cpu.__opv = cpu.__opv >> 1; | |||||
| cpu.__ophold = 1; | |||||
| } else { | |||||
| if (mode === 9){ | |||||
| cpu.__AR = cpu.__opv; | |||||
| } else { | |||||
| cpu.__mem.byte = cpu.__opv; | |||||
| } | |||||
| // TODO: Is Z and N effected by the A register, or by the resulting value? I think the latter. | |||||
| cpu.Z = (this.__opv === 0); | |||||
| cpu.N = BITM.val(this.__opv, 7); | |||||
| cpu.__op = -1; | |||||
| cpu.__ophold = 0; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| function ORA(cpu){ | function ORA(cpu){ | ||||
| let pmode = [0x09, 0x05, 0x15, null, 0x0D, 0x1D, 0x19, 0x01, 0x11, null].indexOf(cpu.__op); | |||||
| if (ProcessOp(cpu, pmode) === true){ | |||||
| cpu.__op = -1; | |||||
| cpu.__AR |= cpu.__opv; | |||||
| cpu.Z = (cpu.__AR === 0); | |||||
| cpu.N = BITM.val(cpu.__AR, 7); | |||||
| } | |||||
| } | } | ||||
| function REGISTER(cpu){ | function REGISTER(cpu){ | ||||
| return ((a >> 8) == (b >> 8)); | return ((a >> 8) == (b >> 8)); | ||||
| } | } | ||||
| function ByteWrap(v, a){ | |||||
| v += a; | |||||
| if (v < 0){v += 256;} | |||||
| else if (v > 255){v -= 256;} | |||||
| return v; | |||||
| } | |||||
| function PCHI(cpu, b){ | function PCHI(cpu, b){ | ||||
| cpu.__PC = (cpu.__PC & 0x00FF) | (b << 8); | cpu.__PC = (cpu.__PC & 0x00FF) | (b << 8); | ||||
| } | } | ||||
| // Variable for tracking tick operations. | // Variable for tracking tick operations. | ||||
| this.__op = -1; | this.__op = -1; | ||||
| this.__opmem = 0; | |||||
| this.__ophold = 0; | |||||
| this.__opv = 0; | this.__opv = 0; | ||||
| this.__cycle = 0; | this.__cycle = 0; | ||||
| this.__pcc = 0; // Program Counter Carry. | this.__pcc = 0; // Program Counter Carry. |