|
|
|
|
|
|
|
|
const BITM = require('../../utils/bitman.js'); |
|
|
const BITM = require('../../utils/bitman.js'); |
|
|
var Memory = require('../../common/memory.js'); |
|
|
var Memory = require('../../common/memory.js'); |
|
|
|
|
|
|
|
|
|
|
|
// mode = 0 - Immediate |
|
|
|
|
|
// mode = 1 - Zero Page |
|
|
|
|
|
// mode = 2 - Zero Page, X |
|
|
|
|
|
// mode = 3 - Zero Page, Y |
|
|
|
|
|
// mode = 4 - Absolute |
|
|
|
|
|
// mode = 5 - Absolute, X |
|
|
|
|
|
// mode = 6 - Absolute, Y |
|
|
|
|
|
// mode = 7 - Indirect, X |
|
|
|
|
|
// mode = 8 - Indirect, Y |
|
|
|
|
|
function ProcessOp(cpu, mode){ |
|
|
|
|
|
switch(cpu.__cycle){ |
|
|
|
|
|
case 0: |
|
|
|
|
|
cpu.__mem.address = cpu.__PC; |
|
|
|
|
|
PCUp(cpu, 1); |
|
|
|
|
|
cpu.__opv = cpu.__mem.byte; |
|
|
|
|
|
return (mode === 0); |
|
|
|
|
|
case 1: |
|
|
|
|
|
switch(mode){ |
|
|
|
|
|
case 1: // Zero Page |
|
|
|
|
|
cpu.__mem.address = cpu.__opv; |
|
|
|
|
|
cpu.__opv = cpu.__mem.byte; |
|
|
|
|
|
return true; |
|
|
|
|
|
case 2: // Zero Page, X |
|
|
|
|
|
case 3: // Zero Page, Y |
|
|
|
|
|
cpu.__opv = (cpu.__opv + ((mode === 2) ? cpu.__XR : cpu.__YR)) & 0xFF; break; |
|
|
|
|
|
case 4: // Absolute |
|
|
|
|
|
case 5: // Absolute, X |
|
|
|
|
|
case 6: // Absolute, Y |
|
|
|
|
|
cpu.__mem.address = cpu.__PC; |
|
|
|
|
|
PCUp(cpu, 1); |
|
|
|
|
|
cpu.__opv |= cpu.__mem.byte << 8; |
|
|
|
|
|
break; |
|
|
|
|
|
case 7: // Indirect, X |
|
|
|
|
|
cpu.__opv = (cpu.__opv + cpu.__XR) & 0xFF; break; |
|
|
|
|
|
case 8: // Indirect, Y |
|
|
|
|
|
cpu.__mem.address = cpu.__opv; |
|
|
|
|
|
cpu.__opv = cpu.__mem.byte; |
|
|
|
|
|
break; |
|
|
|
|
|
} break; |
|
|
|
|
|
case 2: |
|
|
|
|
|
switch(mode){ |
|
|
|
|
|
case 2: // Zero Page, X |
|
|
|
|
|
case 3: // Zero Page, Y |
|
|
|
|
|
case 4: // Absolute |
|
|
|
|
|
cpu.__mem.address = cpu.__opv; |
|
|
|
|
|
cpu.__opv = cpu.__mem.byte; |
|
|
|
|
|
return true; |
|
|
|
|
|
case 5: // Absolute, X |
|
|
|
|
|
case 6: // Absolute, Y |
|
|
|
|
|
let s = (mode === 5) ? 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; |
|
|
|
|
|
cpu.__opv = cpu.__mem.byte; |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
break; |
|
|
|
|
|
case 7: // Indirect, X |
|
|
|
|
|
cpu.__mem.address = cpu.__opv; |
|
|
|
|
|
cpu.__opv = cpu.__mem.byte; |
|
|
|
|
|
break; |
|
|
|
|
|
case 8: // Indirect, Y |
|
|
|
|
|
cpu.__mem.address += 1; |
|
|
|
|
|
cpu.__opv |= cpu.__mem.byte << 8; |
|
|
|
|
|
break; |
|
|
|
|
|
} break; |
|
|
|
|
|
case 3: |
|
|
|
|
|
switch(mode){ |
|
|
|
|
|
case 5: // Absolute, X |
|
|
|
|
|
case 6: // Absolute, Y |
|
|
|
|
|
let h = (cpu.__opv >> 8) + 1; |
|
|
|
|
|
cpu.__mem.address = (cpu.__opv & 0xFF) | (h << 8); |
|
|
|
|
|
cpu.__opv = cpu.__mem.byte; |
|
|
|
|
|
return true; |
|
|
|
|
|
case 7: // Indirect, X |
|
|
|
|
|
cpu.__mem.address += 1; |
|
|
|
|
|
cpu.__opv |= cpu.__mem.byte << 8; |
|
|
|
|
|
break; |
|
|
|
|
|
case 8: // Indirect, Y |
|
|
|
|
|
let l = (cpu.__opv & 0xFF) + cpu.__YR; |
|
|
|
|
|
cpu.__opv = (cpu.__opv & 0xFF00) | (l & 0xFF); |
|
|
|
|
|
if (l <= 255){ |
|
|
|
|
|
cpu.__mem.address = cpu.__opv; |
|
|
|
|
|
cpu.__opv = cpu.__mem.byte; |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
break; |
|
|
|
|
|
} break; |
|
|
|
|
|
case 4: |
|
|
|
|
|
if (mode === 8){ |
|
|
|
|
|
let h = (cpu.__opv >> 8) + 1; |
|
|
|
|
|
cpu.__opv = (cpu.__opv & 0x00FF) | (h << 8); |
|
|
|
|
|
} |
|
|
|
|
|
cpu.__mem.address = cpu.__opv; |
|
|
|
|
|
cpu.__opv = cpu.__mem.byte; |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
cpu.__cycle += 1; |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function MATHC(cpu, m){ // 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); |
|
|
|
|
|
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 == 0 - Add |
|
|
// m == 1 - Subtract |
|
|
// m == 1 - Subtract |
|
|
switch(cpu.__step){ |
|
|
switch(cpu.__step){ |
|
|
|
|
|
|
|
|
cpu.__op = -1; break; |
|
|
cpu.__op = -1; break; |
|
|
} |
|
|
} |
|
|
cpu.__step += 1; |
|
|
cpu.__step += 1; |
|
|
} |
|
|
|
|
|
|
|
|
}*/ |
|
|
|
|
|
|
|
|
function AND(cpu){ |
|
|
function AND(cpu){ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function BRANCH(cpu){ |
|
|
function BRANCH(cpu){ |
|
|
switch(cpu.__step){ |
|
|
|
|
|
|
|
|
switch(cpu.__cycle){ |
|
|
case 0: |
|
|
case 0: |
|
|
let branch = false; |
|
|
let branch = false; |
|
|
switch(cpu.__op){ |
|
|
switch(cpu.__op){ |
|
|
|
|
|
|
|
|
if (branch === false) |
|
|
if (branch === false) |
|
|
PCUp(cpu, 1); |
|
|
PCUp(cpu, 1); |
|
|
case 1: |
|
|
case 1: |
|
|
if (cpu.__step === 1){ |
|
|
|
|
|
|
|
|
if (cpu.__cycle === 1){ // TODO: Huh??? |
|
|
cpu.__mem.address = this.__PC; |
|
|
cpu.__mem.address = this.__PC; |
|
|
let v = cpu.__mem.byte; |
|
|
let v = cpu.__mem.byte; |
|
|
if (v > 128){ |
|
|
if (v > 128){ |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
cpu.__op = -1; |
|
|
cpu.__op = -1; |
|
|
} |
|
|
} |
|
|
cpu.__step += 1; |
|
|
|
|
|
|
|
|
cpu.__cycle += 1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function BRK(cpu){ |
|
|
function BRK(cpu){ |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function SBC(cpu){ |
|
|
function SBC(cpu){ |
|
|
|
|
|
|
|
|
|
|
|
let pmode = [0xE9, 0xE5, 0xF5, null, 0xED, 0xFD, 0xF9, 0xE1, 0xF1].indexOf(cpu.__op); |
|
|
|
|
|
if (ProcessOp(cpu, pmode) === true){ |
|
|
|
|
|
cpu.__op = -1; |
|
|
|
|
|
ALU(cpu, 1, cpu.__opv); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function STA(cpu){ |
|
|
function STA(cpu){ |
|
|
|
|
|
|
|
|
cpu.__op = -1; |
|
|
cpu.__op = -1; |
|
|
break; |
|
|
break; |
|
|
case 0x48: // PHA |
|
|
case 0x48: // PHA |
|
|
if (cpu.__step === 0){ |
|
|
|
|
|
|
|
|
if (cpu.__cycle === 0){ |
|
|
cpu.__mem.address = 0x0100 | cpu.__SP; |
|
|
cpu.__mem.address = 0x0100 | cpu.__SP; |
|
|
} else if (cpu.__step === 1){ |
|
|
|
|
|
|
|
|
} else if (cpu.__cycle === 1){ |
|
|
cpu.__mem.byte = cpu.__AR; |
|
|
cpu.__mem.byte = cpu.__AR; |
|
|
cpu.__SP = (cpu.__SP === 0) ? 255 : cpu.__SP - 1; |
|
|
cpu.__SP = (cpu.__SP === 0) ? 255 : cpu.__SP - 1; |
|
|
cpu.__op = -1; |
|
|
cpu.__op = -1; |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
|
case 0x68: // PLA |
|
|
case 0x68: // PLA |
|
|
if (cpu.__step === 0){ |
|
|
|
|
|
|
|
|
if (cpu.__cycle === 0){ |
|
|
cpu.__mem.address = 0x0100 | cpu.__SP; |
|
|
cpu.__mem.address = 0x0100 | cpu.__SP; |
|
|
} else if (cpu.__step === 1){ |
|
|
|
|
|
|
|
|
} else if (cpu.__cycle === 1){ |
|
|
cpu.__AR = cpu.__mem.byte; |
|
|
cpu.__AR = cpu.__mem.byte; |
|
|
cpu.Z = (cpu.__AR === 0); |
|
|
cpu.Z = (cpu.__AR === 0); |
|
|
cpu.N = BITM.isOn(cpu.__AR, 7); |
|
|
cpu.N = BITM.isOn(cpu.__AR, 7); |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
|
case 0x08: // PHP |
|
|
case 0x08: // PHP |
|
|
if (cpu.__step === 0){ |
|
|
|
|
|
|
|
|
if (cpu.__cycle === 0){ |
|
|
cpu.__mem.address = 0x0100 | cpu.__SP; |
|
|
cpu.__mem.address = 0x0100 | cpu.__SP; |
|
|
} else if (cpu.__step === 1){ |
|
|
|
|
|
|
|
|
} else if (cpu.__cycle === 1){ |
|
|
cpu.__mem.byte = cpu.__PR; |
|
|
cpu.__mem.byte = cpu.__PR; |
|
|
cpu.__SP = (cpu.__SP === 0) ? 255 : cpu.__SP - 1; |
|
|
cpu.__SP = (cpu.__SP === 0) ? 255 : cpu.__SP - 1; |
|
|
cpu.__op = -1; |
|
|
cpu.__op = -1; |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
|
case 0x28: // PLP |
|
|
case 0x28: // PLP |
|
|
if (cpu.__step === 0){ |
|
|
|
|
|
|
|
|
if (cpu.__cycle === 0){ |
|
|
cpu.__mem.address = 0x0100 | cpu.__SP; |
|
|
cpu.__mem.address = 0x0100 | cpu.__SP; |
|
|
} else if (cpu.__step === 1){ |
|
|
|
|
|
|
|
|
} else if (cpu.__cycle === 1){ |
|
|
cpu.__SP = cpu.__mem.byte; |
|
|
cpu.__SP = cpu.__mem.byte; |
|
|
} else if (cpu.__step === 2){ |
|
|
|
|
|
|
|
|
} else if (cpu.__cycle === 2){ |
|
|
cpu.__SP = (cpu.__SP === 255) ? 0 : cpu.__SP + 1; |
|
|
cpu.__SP = (cpu.__SP === 255) ? 0 : cpu.__SP + 1; |
|
|
cpu.__op = -1; |
|
|
cpu.__op = -1; |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
cpu.__step += 1; |
|
|
|
|
|
|
|
|
cpu.__cycle += 1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function STX(cpu){ |
|
|
function STX(cpu){ |
|
|
|
|
|
|
|
|
this.__op = -1; |
|
|
this.__op = -1; |
|
|
this.__opmem = 0; |
|
|
this.__opmem = 0; |
|
|
this.__opv = 0; |
|
|
this.__opv = 0; |
|
|
this.__step = 0; |
|
|
|
|
|
|
|
|
this.__cycle = 0; |
|
|
this.__pcc = 0; // Program Counter Carry. |
|
|
this.__pcc = 0; // Program Counter Carry. |
|
|
|
|
|
|
|
|
// Memory module or controller. |
|
|
// Memory module or controller. |
|
|
|
|
|
|
|
|
// TODO: Handle IRQ Interrupt. |
|
|
// TODO: Handle IRQ Interrupt. |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
this.__step = 0; |
|
|
|
|
|
|
|
|
this.__cycle = 0; |
|
|
this.__mem.address = this.__PC; |
|
|
this.__mem.address = this.__PC; |
|
|
this.__op = this.__mem.byte; |
|
|
this.__op = this.__mem.byte; |
|
|
PCUp(this, 1); |
|
|
PCUp(this, 1); |
|
|
|
|
|
|
|
|
} else { |
|
|
} else { |
|
|
switch(this.__op){ |
|
|
switch(this.__op){ |
|
|
case 0x69: case 0x65: case 0x75: case 0x6D: case 0x7D: case 0x79: case 0x61: case 0x71: |
|
|
case 0x69: case 0x65: case 0x75: case 0x6D: case 0x7D: case 0x79: case 0x61: case 0x71: |
|
|
MATHC(this, 0); break; |
|
|
|
|
|
|
|
|
ADC(this); break; |
|
|
case 0x29: case 0x25: case 0x35: case 0x2D: case 0x3D: case 0x39: case 0x21: case 0x31: |
|
|
case 0x29: case 0x25: case 0x35: case 0x2D: case 0x3D: case 0x39: case 0x21: case 0x31: |
|
|
AND(this); break; |
|
|
AND(this); break; |
|
|
case 0x0A: case 0x06: case 0x16: case 0x0E: case 0x1E: |
|
|
case 0x0A: case 0x06: case 0x16: case 0x0E: case 0x1E: |
|
|
|
|
|
|
|
|
case 0x60: |
|
|
case 0x60: |
|
|
RTS(this); break; |
|
|
RTS(this); break; |
|
|
case 0xE9: case 0xE5: case 0xF5: case 0xED: case 0xFD: case 0xF9: case 0xE1: case 0xF1: |
|
|
case 0xE9: case 0xE5: case 0xF5: case 0xED: case 0xFD: case 0xF9: case 0xE1: case 0xF1: |
|
|
MATHC(this, 1); break; |
|
|
|
|
|
|
|
|
SBC(this); break; |
|
|
case 0x85: case 0x95: case 0x8D: case 0x9D: case 0x99: case 0x81: case 0x91: |
|
|
case 0x85: case 0x95: case 0x8D: case 0x9D: case 0x99: case 0x81: case 0x91: |
|
|
STA(this); break; |
|
|
STA(this); break; |
|
|
case 0x9A: case 0xBA: case 0x48: case 0x68: case 0x08: case 0x28: |
|
|
case 0x9A: case 0xBA: case 0x48: case 0x68: case 0x08: case 0x28: |