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