@@ -202,7 +202,8 @@ function BRANCH(cpu){ | |||
cpu.__cycle += 1; | |||
} | |||
function BRK(cpu){ | |||
function BRK(cpu, nmi){ | |||
nmi = (nmi === true); | |||
switch(cpu.__cycle){ | |||
case 0: | |||
PCUp(cpu, 1); | |||
@@ -213,11 +214,11 @@ function BRK(cpu){ | |||
case 3: | |||
StackPush(cpu, cpu.__SP); break; | |||
case 4: | |||
cpu.__mem.address = 0xFFFE; | |||
cpu.__mem.address = (nmi) ? 0xFFFC : 0xFFFE; | |||
cpu.__PC = cpu.__mem.byte; | |||
break; | |||
case 5: | |||
cpu.__mem.address = 0xFFFF; | |||
cpu.__mem.address = (nmi) ? 0xFFFD : 0xFFFF; | |||
cpu.__PC |= cpu.__mem.byte << 8; | |||
cpu.B = 1; | |||
cpu.__op = -1; | |||
@@ -758,6 +759,8 @@ class CPU{ | |||
// Variables to watch for Hardware Interrupts. | |||
this.__nmi = false; | |||
this.__irq = false; | |||
this.__rst = true; | |||
this.__iinit = false; | |||
// Variable for tracking tick operations. | |||
this.__op = -1; | |||
@@ -809,23 +812,18 @@ class CPU{ | |||
// Hardware interrupt triggers. Settable only. | |||
set NMI(n){ | |||
this.__nmi = (n === true); | |||
this.__iinit = true; | |||
} | |||
set IRQ(q){ | |||
// TODO: Verify this. | |||
// TODO: Do not set if the interrupt flag is off. | |||
this.__irq = (q === true); | |||
if (BITM.val(this.__PR, 2) === 0 && this.__nmi === false){ | |||
this.__irq = (q === true); | |||
this.__iinit = true; | |||
} | |||
} | |||
reset(){ | |||
this.__mem.address = 0xFFFC; | |||
this.__PC = this.__mem.byte; | |||
this.__mem.address = 0xFFFD; | |||
this.__PC |= this.__mem.byte << 8; | |||
// Disabling the IRQ interrupts is the ONLY flag that must be set | |||
// during reset. The others are random. | |||
this.I = 1; | |||
set reset(r){ | |||
this.__rst = (r === true); | |||
} | |||
// ----------------------------------------- | |||
@@ -850,12 +848,37 @@ class CPU{ | |||
PCDown(this, 1); | |||
} | |||
} else if (this.__op < 0){ | |||
if (this.__nmi) { | |||
// TODO: Handle NMI Interrupt. | |||
if (this.__rst){ | |||
this.__rst = false; | |||
this.__mem.address = 0xFFFC; | |||
this.__PC = this.__mem.byte; | |||
this.__mem.address = 0xFFFD; | |||
this.__PC |= this.__mem.byte << 8; | |||
// Disabling the IRQ interrupts is the ONLY flag that must be set | |||
// during reset. The others are random. | |||
this.I = 1; | |||
} else if (this.__nmi) { | |||
if (this.__iinit){ | |||
this.__cycle = 0; | |||
this.__iinit = false; | |||
} | |||
BRK(this, true); // BRK does all of the interrupt work. The 'true' tells BRK to use the nmi vectors. | |||
if (this.__cycle === 6) | |||
this.__nmi = false; | |||
} else if (this.__irq) { | |||
this.__irq = false; | |||
if (!BITM.isOn(this.__PR, 5)){ | |||
// TODO: Handle IRQ Interrupt. | |||
if (this.I === 0){ | |||
if (this.__iinit){ | |||
this.__cycle = 0; | |||
this.__iinit = false; | |||
} | |||
BRK(this); // Because both the BRK opcode and an IRQ interrupt do the same things! | |||
if (this.__cycle === 6) | |||
this.__irq = false; | |||
} else { | |||
// NOPE... try again! | |||
this.__irq = false; | |||
this.__clkfn(); | |||
} | |||
} else { | |||
this.__cycle = 0; |
@@ -10,7 +10,8 @@ describe("Testing MOS6502 CPU...", function(){ | |||
cpu.memory.load(0xFFFC, [0x00, 0x00]); | |||
it("Resetting (IRQ Disabled flag must be on", function(){ | |||
cpu.reset(); | |||
cpu.reset = true; | |||
tick(); // One tick to handle resets. | |||
expect(cpu.I).to.equal(1); | |||
expect(cpu.PC).to.equal(0); // Test program counter set to the vector stored at 0xFFFC - 0xFFFD | |||
}); | |||
@@ -19,7 +20,8 @@ describe("Testing MOS6502 CPU...", function(){ | |||
it("CLC / SEC", function(){ | |||
cpu.memory.clearPage(0); | |||
cpu.memory.load(0, [0x18, 0x38]); | |||
cpu.reset(); | |||
cpu.reset = true; | |||
tick(); // reset. | |||
tick(); tick(); // Two ticks to process opcode. | |||
expect(cpu.C).to.equal(0); | |||
tick(); tick(); | |||
@@ -29,7 +31,8 @@ describe("Testing MOS6502 CPU...", function(){ | |||
it("CLI / SEI", function(){ | |||
cpu.memory.clearPage(0); | |||
cpu.memory.load(0, [0x58, 0x78]); | |||
cpu.reset(); | |||
cpu.reset = true; | |||
tick(); | |||
tick(); tick(); | |||
expect(cpu.I).to.equal(0); | |||
tick(); tick(); | |||
@@ -39,7 +42,8 @@ describe("Testing MOS6502 CPU...", function(){ | |||
it("CLD / SED", function(){ | |||
cpu.memory.clearPage(0); | |||
cpu.memory.load(0, [0xD8, 0xF8]); | |||
cpu.reset(); | |||
cpu.reset = true; | |||
tick(); | |||
tick(); tick(); | |||
expect(cpu.D).to.equal(0); | |||
tick(); tick(); | |||
@@ -49,7 +53,8 @@ describe("Testing MOS6502 CPU...", function(){ | |||
it("CLV", function(){ | |||
cpu.memory.clearPage(0); | |||
cpu.memory.load(0, [0xB8]); | |||
cpu.reset(); | |||
cpu.reset = true; | |||
tick(); | |||
tick(); tick(); | |||
expect(cpu.V).to.equal(0); | |||
}); | |||
@@ -59,7 +64,8 @@ describe("Testing MOS6502 CPU...", function(){ | |||
it("LDA Immediate", function(){ | |||
cpu.memory.clearPage(0); | |||
cpu.memory.load(0, [0xA9, 0x01, 0xA9, 0xBB]); | |||
cpu.reset(); | |||
cpu.reset = true; | |||
tick(); | |||
tick(); | |||
tick(); | |||
expect(cpu.A).to.equal(0x01); | |||
@@ -89,7 +95,8 @@ describe("Testing MOS6502 CPU...", function(){ | |||
// ADC $01 | |||
// ADC $01 | |||
cpu.memory.load(0, [0x18, 0xB8, 0xD8, 0x58, 0xA9, 0x00, 0x69, 0x01, 0x69, 0x01]); | |||
cpu.reset(); | |||
cpu.reset = true; | |||
tick(); | |||
// Getting through the 4 clear flag calls. Each should take 2 ticks. | |||
tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick(); | |||
// Next two ticks for the LDA call | |||
@@ -143,7 +150,8 @@ describe("Testing MOS6502 CPU...", function(){ | |||
// SBC $01 | |||
// SBC $01 | |||
cpu.memory.load(0, [0x38, 0xB8, 0xD8, 0x58, 0xA9, 0x00, 0xE9, 0x01, 0xE9, 0x01]); | |||
cpu.reset(); | |||
cpu.reset = true; | |||
tick(); | |||
// Getting through the 1 set and 3 clear flag calls. Each should take 2 ticks. | |||
tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick(); | |||
// Next two ticks for the LDA call |