| @@ -14,12 +14,16 @@ var Memory = require('../../common/memory.js'); | |||
| // mode = 7 - Indirect, X | |||
| // mode = 8 - Indirect, Y | |||
| function ProcessOp(cpu, mode){ | |||
| if (mode < 0 || mode > 9){return false;} | |||
| switch(cpu.__cycle){ | |||
| 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: | |||
| switch(mode){ | |||
| case 1: // Zero Page | |||
| @@ -108,119 +112,55 @@ function ProcessOp(cpu, mode){ | |||
| 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){ | |||
| cpu.__op = -1; | |||
| 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){ | |||
| 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){ | |||
| 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){ | |||
| 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){ | |||
| @@ -263,27 +203,98 @@ function BRANCH(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){ | |||
| 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){ | |||
| 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){ | |||
| 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){ | |||
| 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){ | |||
| 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){ | |||
| @@ -307,19 +318,79 @@ function FLAG(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){ | |||
| 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){ | |||
| 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){ | |||
| 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){ | |||
| cpu.__op = -1; | |||
| cpu.__AR = cpu.__opv; | |||
| @@ -329,19 +400,57 @@ function LDA(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){ | |||
| 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){ | |||
| 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){ | |||
| 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){ | |||
| @@ -484,6 +593,13 @@ function SamePage(a, b){ | |||
| 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){ | |||
| cpu.__PC = (cpu.__PC & 0x00FF) | (b << 8); | |||
| } | |||
| @@ -566,7 +682,7 @@ class CPU{ | |||
| // Variable for tracking tick operations. | |||
| this.__op = -1; | |||
| this.__opmem = 0; | |||
| this.__ophold = 0; | |||
| this.__opv = 0; | |||
| this.__cycle = 0; | |||
| this.__pcc = 0; // Program Counter Carry. | |||