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

cpu.__cycle += 1; cpu.__cycle += 1;
} }


function BRK(cpu){
function BRK(cpu, nmi){
nmi = (nmi === true);
switch(cpu.__cycle){ switch(cpu.__cycle){
case 0: case 0:
PCUp(cpu, 1); PCUp(cpu, 1);
case 3: case 3:
StackPush(cpu, cpu.__SP); break; StackPush(cpu, cpu.__SP); break;
case 4: case 4:
cpu.__mem.address = 0xFFFE;
cpu.__mem.address = (nmi) ? 0xFFFC : 0xFFFE;
cpu.__PC = cpu.__mem.byte; cpu.__PC = cpu.__mem.byte;
break; break;
case 5: case 5:
cpu.__mem.address = 0xFFFF;
cpu.__mem.address = (nmi) ? 0xFFFD : 0xFFFF;
cpu.__PC |= cpu.__mem.byte << 8; cpu.__PC |= cpu.__mem.byte << 8;
cpu.B = 1; cpu.B = 1;
cpu.__op = -1; cpu.__op = -1;
// Variables to watch for Hardware Interrupts. // Variables to watch for Hardware Interrupts.
this.__nmi = false; this.__nmi = false;
this.__irq = false; this.__irq = false;
this.__rst = true;
this.__iinit = false;


// Variable for tracking tick operations. // Variable for tracking tick operations.
this.__op = -1; this.__op = -1;
// Hardware interrupt triggers. Settable only. // Hardware interrupt triggers. Settable only.
set NMI(n){ set NMI(n){
this.__nmi = (n === true); this.__nmi = (n === true);
this.__iinit = true;
} }


set IRQ(q){ 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);
} }


// ----------------------------------------- // -----------------------------------------
PCDown(this, 1); PCDown(this, 1);
} }
} else if (this.__op < 0){ } 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) { } 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 { } else {
this.__cycle = 0; this.__cycle = 0;

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

cpu.memory.load(0xFFFC, [0x00, 0x00]); cpu.memory.load(0xFFFC, [0x00, 0x00]);
it("Resetting (IRQ Disabled flag must be on", function(){ 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.I).to.equal(1);
expect(cpu.PC).to.equal(0); // Test program counter set to the vector stored at 0xFFFC - 0xFFFD expect(cpu.PC).to.equal(0); // Test program counter set to the vector stored at 0xFFFC - 0xFFFD
}); });
it("CLC / SEC", function(){ it("CLC / SEC", function(){
cpu.memory.clearPage(0); cpu.memory.clearPage(0);
cpu.memory.load(0, [0x18, 0x38]); cpu.memory.load(0, [0x18, 0x38]);
cpu.reset();
cpu.reset = true;
tick(); // reset.
tick(); tick(); // Two ticks to process opcode. tick(); tick(); // Two ticks to process opcode.
expect(cpu.C).to.equal(0); expect(cpu.C).to.equal(0);
tick(); tick(); tick(); tick();
it("CLI / SEI", function(){ it("CLI / SEI", function(){
cpu.memory.clearPage(0); cpu.memory.clearPage(0);
cpu.memory.load(0, [0x58, 0x78]); cpu.memory.load(0, [0x58, 0x78]);
cpu.reset();
cpu.reset = true;
tick();
tick(); tick(); tick(); tick();
expect(cpu.I).to.equal(0); expect(cpu.I).to.equal(0);
tick(); tick(); tick(); tick();
it("CLD / SED", function(){ it("CLD / SED", function(){
cpu.memory.clearPage(0); cpu.memory.clearPage(0);
cpu.memory.load(0, [0xD8, 0xF8]); cpu.memory.load(0, [0xD8, 0xF8]);
cpu.reset();
cpu.reset = true;
tick();
tick(); tick(); tick(); tick();
expect(cpu.D).to.equal(0); expect(cpu.D).to.equal(0);
tick(); tick(); tick(); tick();
it("CLV", function(){ it("CLV", function(){
cpu.memory.clearPage(0); cpu.memory.clearPage(0);
cpu.memory.load(0, [0xB8]); cpu.memory.load(0, [0xB8]);
cpu.reset();
cpu.reset = true;
tick();
tick(); tick(); tick(); tick();
expect(cpu.V).to.equal(0); expect(cpu.V).to.equal(0);
}); });
it("LDA Immediate", function(){ it("LDA Immediate", function(){
cpu.memory.clearPage(0); cpu.memory.clearPage(0);
cpu.memory.load(0, [0xA9, 0x01, 0xA9, 0xBB]); cpu.memory.load(0, [0xA9, 0x01, 0xA9, 0xBB]);
cpu.reset();
cpu.reset = true;
tick();
tick(); tick();
tick(); tick();
expect(cpu.A).to.equal(0x01); expect(cpu.A).to.equal(0x01);
// ADC $01 // ADC $01
// ADC $01 // ADC $01
cpu.memory.load(0, [0x18, 0xB8, 0xD8, 0x58, 0xA9, 0x00, 0x69, 0x01, 0x69, 0x01]); 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. // Getting through the 4 clear flag calls. Each should take 2 ticks.
tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick();
// Next two ticks for the LDA call // Next two ticks for the LDA call
// SBC $01 // SBC $01
// SBC $01 // SBC $01
cpu.memory.load(0, [0x38, 0xB8, 0xD8, 0x58, 0xA9, 0x00, 0xE9, 0x01, 0xE9, 0x01]); 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. // Getting through the 1 set and 3 clear flag calls. Each should take 2 ticks.
tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick(); tick();
// Next two ticks for the LDA call // Next two ticks for the LDA call

Loading…
Cancel
Save