| @@ -486,9 +486,251 @@ describe("MOSCIA Tests...", function(){ | |||
| cia.RS = 0x01; | |||
| expect(cia.DATA & 0x40).to.be.equal(0x00); | |||
| }); | |||
| it("Timer B, phi2 Triggered, Interrupt Verification", function(){ | |||
| let cia = new MOSCIA(); | |||
| let tick = (cycles) => { | |||
| for (let i=0; i < cycles; i++) | |||
| cia.phi2 = 1; | |||
| }; | |||
| cia.RS = 0x06; | |||
| cia.DATA = 0xFF; | |||
| cia.RS = 0x07; | |||
| cia.DATA = 0x01; | |||
| cia.RS = 0x0F; | |||
| // Force latch load into Timer B and activate Timer B | |||
| cia.DATA = cia.DATA | 0x11; | |||
| cia.RS = 0x06; | |||
| expect(cia.DATA).to.be.equal(0xFF); | |||
| tick(1); | |||
| expect(cia.DATA).to.be.equal(0xFE); | |||
| tick(1); | |||
| expect(cia.DATA).to.be.equal(0xFD); | |||
| tick(0x0200 - 3); | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| cia.RS = 0x07; | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| tick(1); | |||
| expect(cia.DATA).to.be.equal(0x01); | |||
| cia.RS = 0x06; | |||
| expect(cia.DATA).to.be.equal(0xFF); | |||
| cia.RS = 0x0D; | |||
| let IC = cia.DATA; | |||
| expect(IC & 0x02).to.be.equal(0x02); | |||
| expect(IC & 0x80).to.be.equal(0x80); | |||
| }); | |||
| it("Timer B, CNT Triggered, Underflow report to Port B", function(){ | |||
| let cia = new MOSCIA(); | |||
| let tick = (cycles, cnt) => { | |||
| cnt = (cnt === true); | |||
| for (let i=0; i < cycles; i++){ | |||
| if (cnt) | |||
| cia.CNT = 1; | |||
| cia.phi2 = 1; | |||
| if (cnt) | |||
| cia.CNT = 0; | |||
| } | |||
| }; | |||
| cia.RS = 0x06; | |||
| cia.DATA = 0x08; | |||
| cia.RS = 0x07; | |||
| cia.DATA = 0x00; | |||
| cia.RS = 0x0F; | |||
| // Force latch load into Timer B, | |||
| // enable underflow reporting on Port B bit 7, | |||
| // set Timer B to trigger on CNT, | |||
| // and activate Timer B | |||
| cia.DATA = 0x33; | |||
| cia.RS = 0x06; | |||
| // First, test a few ticks where CNT is not high. | |||
| expect(cia.DATA).to.be.equal(0x08); // Validate inital timer value. | |||
| tick(1); | |||
| tick(1); | |||
| tick(1); | |||
| tick(1); | |||
| expect(cia.DATA).to.be.equal(0x08); | |||
| // Now verify CNT triggers! | |||
| tick(1, true); | |||
| expect(cia.DATA).to.be.equal(0x07); | |||
| tick(1, true); | |||
| expect(cia.DATA).to.be.equal(0x06); | |||
| tick(1, true); | |||
| tick(1, true); | |||
| tick(1, true); | |||
| tick(1, true); | |||
| tick(1, true); | |||
| tick(1, true); | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| tick(1, true); | |||
| // Double check that timer has reset to latch value... | |||
| expect(cia.DATA).to.be.equal(0x08); | |||
| // Verify Interrupt (again... but it doesn't hurt!) | |||
| cia.RS = 0x0D; | |||
| let IC = cia.DATA; | |||
| expect(IC & 0x02).to.be.equal(0x02); | |||
| expect(IC & 0x80).to.be.equal(0x80); | |||
| // Checking Port B bit 7 which should only go high for 1 cycle! | |||
| cia.RS = 0x01; | |||
| expect(cia.DATA & 0x80).to.be.equal(0x80); | |||
| tick(1, true); | |||
| expect(cia.DATA & 0x80).to.be.equal(0x00); | |||
| // Check Port B bit 7 toggling... | |||
| // ------------------------------------------- | |||
| // Force latch load into Timer B, | |||
| // enable underflow reporting on Port B bit 7, | |||
| // setup Port B bit 7 to invert, | |||
| // set Timer B to trigger on CNT, | |||
| // and activate Timer B | |||
| cia.RS = 0x0F; | |||
| cia.DATA = 0x37; | |||
| for (let i=0; i < 9; i++) | |||
| tick(1, true); | |||
| cia.RS = 0x06; | |||
| expect(cia.DATA).to.be.equal(0x08); | |||
| cia.RS = 0x01; | |||
| expect(cia.DATA & 0x80).to.be.equal(0x80); | |||
| tick(1, true); | |||
| expect(cia.DATA & 0x80).to.be.equal(0x80); | |||
| cia.RS = 0x06; | |||
| expect(cia.DATA).to.be.equal(0x07); | |||
| for (let i=0; i < 8; i++) | |||
| tick(1, true); | |||
| expect(cia.DATA).to.be.equal(0x08); | |||
| cia.RS = 0x01; | |||
| expect(cia.DATA & 0x80).to.be.equal(0x00); | |||
| }); | |||
| it("Timer B tick on Timer A Underflow (phi2 Triggered)", function(){ | |||
| let cia = new MOSCIA(); | |||
| let tick = (cycle) => { | |||
| for (let i=0; i < cycle; i++) | |||
| cia.phi2 = 1; | |||
| }; | |||
| // Setting up Timer A | |||
| cia.RS = 0x04; | |||
| cia.DATA = 0x02; | |||
| cia.RS = 0x0E; | |||
| cia.DATA = 0x11; | |||
| // Setting up Timer B | |||
| cia.RS = 0x06; | |||
| cia.DATA = 0x01; | |||
| cia.RS = 0x0F; | |||
| cia.DATA = 0x51; | |||
| cia.RS = 0x06; | |||
| // Verify Timer B Low Byte Value | |||
| expect(cia.DATA).to.be.equal(0x01); | |||
| tick(1); | |||
| // Timer B should not have changed. | |||
| expect(cia.DATA).to.be.equal(0x01); | |||
| // Timer A should have ticked down by 1. | |||
| cia.RS = 0x04; | |||
| expect(cia.DATA).to.be.equal(0x01); | |||
| tick(1); tick(1); | |||
| // Timer A should have underflowed and Timer B ticked down by 1 | |||
| expect(cia.DATA).to.be.equal(0x02); | |||
| cia.RS = 0x06; | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| // Check that Timer A triggered interrupt... but Timer B did not! | |||
| cia.RS = 0x0D; | |||
| let IC = cia.DATA; | |||
| expect(IC & 0x01).to.be.equal(0x01); | |||
| expect(IC & 0x02).to.be.equal(0x00); | |||
| tick(3); // Run through Timer A once more. | |||
| // Check that both Timer A & B triggered interrupt! | |||
| IC = cia.DATA; | |||
| expect(IC & 0x01).to.be.equal(0x01); | |||
| expect(IC & 0x02).to.be.equal(0x02); | |||
| // Both timers should have latched back to their starting values. | |||
| cia.RS = 0x04; | |||
| expect(cia.DATA).to.be.equal(0x02); | |||
| cia.RS = 0x06; | |||
| expect(cia.DATA).to.be.equal(0x01); | |||
| }); | |||
| it("Timer B ticks on Timer A Underflow (CNT Triggered for B only)", function(){ | |||
| let cia = new MOSCIA(); | |||
| let tick = (cycle) => { | |||
| for (let i=0; i < cycle; i++) | |||
| cia.phi2 = 1; | |||
| }; | |||
| // Setup Timer A (trigger on phi2 only) | |||
| cia.RS = 0x04; | |||
| cia.DATA = 0x02; | |||
| cia.RS = 0x0E; | |||
| cia.DATA = 0x11; | |||
| // Setup Timer B (trigger on A underflow and CNT high) | |||
| cia.RS = 0x06; | |||
| cia.DATA = 0x01; | |||
| cia.RS = 0x0F; | |||
| cia.DATA = 0x71; | |||
| // Keep CNT low, check that underflowing A *does NOT* tick B. | |||
| cia.CNT = 0; // <-- Just to be sure. | |||
| tick(2); | |||
| // Just make sure we're ticking A | |||
| cia.RS = 0x04; | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| tick(1); | |||
| expect(cia.DATA).to.be.equal(0x02); | |||
| // Make sure B did not tick! | |||
| cia.RS = 0x06; | |||
| expect(cia.DATA).to.be.equal(0x01); | |||
| // Clear interrupt flags | |||
| cia.RS = 0x0D; | |||
| let IC = cia.DATA; | |||
| // NOW tick with CNT high! | |||
| cia.CNT = 1; | |||
| tick(3); | |||
| // Checking A rolled over | |||
| cia.RS = 0x04; | |||
| expect(cia.DATA).to.be.equal(0x02); | |||
| // Now checking B ticked... | |||
| cia.RS = 0x06; | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| // Double check CNT is high | |||
| expect(cia.CNT).to.be.equal(1); | |||
| // One more A cycle to check B rolls over! | |||
| tick(3); | |||
| expect(cia.DATA).to.be.equal(0x01); | |||
| cia.RS = 0x04; | |||
| expect(cia.DATA).to.be.equal(0x02); | |||
| }); | |||
| }); | |||