Browse Source

Added interrupt handlers (by way of psuedo hijacking BRK) and make reset a property. Updated tests accordingly.

master
Bryan Miller 5 years ago
parent
commit
5781e7617a
2 changed files with 59 additions and 28 deletions
  1. +43
    -20
      src/chip/MOS6502/cpu.js
  2. +16
    -8
      test/unit.src.chip.MOS6502.cpu.spec.js

+ 43
- 20
src/chip/MOS6502/cpu.js View File

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

+ 16
- 8
test/unit.src.chip.MOS6502.cpu.spec.js View File

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

Loading…
Cancel
Save