|
|
@@ -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. |