| @@ -4,6 +4,44 @@ const MOSCIA = require('../src/MOSCIA.js'); | |||
| describe("MOSCIA Tests...", function(){ | |||
| //var cia = new MOSCIA(); | |||
| it("R/W Pin", function(){ | |||
| let cia = new MOSCIA(); | |||
| // The RW pin is default low, so writting should be enabled. | |||
| cia.RS = 0x02; | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| cia.DATA = 0xFF; | |||
| expect(cia.DATA).to.be.equal(0xFF); | |||
| // Set RW high to disable writting! | |||
| cia.RW = 1; | |||
| cia.DATA = 0x00; | |||
| expect(cia.DATA).to.be.equal(0xFF); | |||
| // Set it low once more | |||
| cia.RW = 0; | |||
| cia.DATA = 0x00; | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| }); | |||
| it("Interrupts (via FLAG)", function(){ | |||
| let cia = new MOSCIA(); | |||
| cia.FLAG = 1; | |||
| cia.RS = 0x0D; | |||
| let IC = cia.DATA; | |||
| expect(IC & 0x10).to.be.equal(0x10); | |||
| expect(IC & 0x80).to.be.equal(0x80); | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| // Setting data changes the interrupt mask. This should mask the | |||
| // FLAG interrupt. | |||
| cia.DATA = 0x90; | |||
| cia.FLAG = 1; | |||
| IC = cia.DATA; | |||
| expect(IC).to.be.equal(0x00); | |||
| }); | |||
| it("PD*/DD* Masking", function(){ | |||
| let cia = new MOSCIA(); | |||
| @@ -67,7 +105,9 @@ describe("MOSCIA Tests...", function(){ | |||
| Input(1); | |||
| expect(cia.DATA).to.be.equal(0xCD); | |||
| cia.RS = 0x0D; | |||
| expect((cia.DATA & 0x08) >> 3).to.be.equal(1); | |||
| let IC = cia.DATA; | |||
| expect(IC & 0x08).to.be.equal(0x08); | |||
| expect(IC & 0x80).to.be.equal(0x80); | |||
| // Reading from RS = 0x0D should clear the interrupt values. Checking this | |||
| expect(cia.DATA).to.be.equal(0); | |||
| @@ -91,4 +131,238 @@ describe("MOSCIA Tests...", function(){ | |||
| expect((cia.DATA & 0x08) >> 3).to.be.equal(1); | |||
| expect(cia.DATA).to.be.equal(0); | |||
| }); | |||
| it("TOD 60hz", function(){ | |||
| // NOTE: The TOD clock doesn't actually enforce the frequency. | |||
| // The TOD 'pin' is expected to be attached to a clock pulsing at the | |||
| // designated frequency. | |||
| // As such, this test will run MUCH MUCH faster than the 1.1 seconds | |||
| // actually being checked (because I'm not using a clock here). | |||
| let cia = new MOSCIA(); | |||
| let tick60 = () => { | |||
| for (let i=0; i < 6; i++) | |||
| cia.TOD = 1; | |||
| }; | |||
| // NOTE: The CIA defaults to 60hz TOD clock. Nothing needs to be set. | |||
| // Check that seconds is at 0 (we'll test this again later) | |||
| cia.RS = 0x09; | |||
| expect(cia.DATA).to.be.equal(0); | |||
| // Switch to 10ths of a second and go! | |||
| cia.RS = 0x08; | |||
| expect(cia.DATA).to.be.equal(0); | |||
| tick60(); | |||
| expect(cia.DATA).to.be.equal(0x01); | |||
| tick60(); | |||
| expect(cia.DATA).to.be.equal(0x02); | |||
| tick60(); | |||
| expect(cia.DATA).to.be.equal(0x03); | |||
| for (let i=0; i < 8; i++) | |||
| tick60(); | |||
| // Should have looped back around a little at this point! | |||
| expect(cia.DATA).to.be.equal(0x01); | |||
| // Check seconds again. This should have gone up once! | |||
| cia.RS = 0x09; | |||
| expect(cia.DATA).to.be.equal(0x01); | |||
| }); | |||
| it("TOD 50hz", function(){ | |||
| // NOTE: The TOD clock doesn't actually enforce the frequency. | |||
| // The TOD 'pin' is expected to be attached to a clock pulsing at the | |||
| // designated frequency. | |||
| // As such, this test will run MUCH MUCH faster than the 1.1 seconds | |||
| // actually being checked (because I'm not using a clock here). | |||
| let cia = new MOSCIA(); | |||
| let tick50 = () => { | |||
| for (let i=0; i < 5; i++) | |||
| cia.TOD = 1; | |||
| }; | |||
| // enabling 50 hz mode. | |||
| cia.RS = 0x0E; | |||
| cia.DATA = cia.DATA | 0x80; | |||
| // Check that seconds is at 0 (we'll test this again later) | |||
| cia.RS = 0x09; | |||
| expect(cia.DATA).to.be.equal(0); | |||
| // Switch to 10ths of a second and go! | |||
| cia.RS = 0x08; | |||
| expect(cia.DATA).to.be.equal(0); | |||
| tick50(); | |||
| expect(cia.DATA).to.be.equal(0x01); | |||
| tick50(); | |||
| expect(cia.DATA).to.be.equal(0x02); | |||
| tick50(); | |||
| expect(cia.DATA).to.be.equal(0x03); | |||
| for (let i=0; i < 8; i++) | |||
| tick50(); | |||
| // Should have looped back around a little at this point! | |||
| expect(cia.DATA).to.be.equal(0x01); | |||
| // Check seconds again. This should have gone up once! | |||
| cia.RS = 0x09; | |||
| expect(cia.DATA).to.be.equal(0x01); | |||
| }); | |||
| it("TOD Latching", function(){ | |||
| let cia = new MOSCIA(); | |||
| let tick = (cycles) => { | |||
| let ccount = cycles * 6; | |||
| for (let i=0; i < ccount; i++) | |||
| cia.TOD = 1; | |||
| }; | |||
| cia.setTOD(0x03, 0x59, 0x58, 0x00); | |||
| // Copying current clock values for later reference. | |||
| let TOD = [0,0,0,0]; | |||
| cia.RS = 0x08; | |||
| TOD[0] = cia.DATA; | |||
| cia.RS = 0x09; | |||
| TOD[1] = cia.DATA; | |||
| cia.RS = 0x0A; | |||
| TOD[2] = cia.DATA; | |||
| cia.RS = 0x0B; | |||
| TOD[3] = cia.DATA; // This should latch the timer!! | |||
| tick(11); // Simulate 1.1 second time passing. | |||
| // TOD Latch shouldn't be released until next read from RS=0x08, so... | |||
| expect(cia.DATA).to.be.equal(TOD[3]); | |||
| cia.RS = 0x0A; | |||
| expect(cia.DATA).to.be.equal(TOD[2]); | |||
| cia.RS = 0x09; | |||
| expect(cia.DATA).to.be.equal(TOD[1]); | |||
| cia.RS = 0x08; | |||
| expect(cia.DATA).to.be.equal(TOD[0]); // Should release the TOD latch | |||
| // With latch released, we should be able to read the new time... | |||
| expect(cia.DATA).to.be.equal(0x01); | |||
| cia.RS = 0x09; | |||
| expect(cia.DATA).to.be.equal(0x59); | |||
| }); | |||
| it("TOD Time Rollover with AM/PM change", function(){ | |||
| let cia = new MOSCIA(); | |||
| let tick = () => { | |||
| for (let i=0; i < 6; i++) | |||
| cia.TOD = 1; | |||
| }; | |||
| cia.setTOD(0x11, 0x59, 0x59, 0x09); | |||
| tick(); | |||
| cia.RS = 0x0B; | |||
| expect(cia.DATA).to.be.equal(0x80); | |||
| cia.RS = 0x0A; | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| cia.RS = 0x09; | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| cia.RS = 0x08; | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| cia.setTOD(0x91, 0x59, 0x59, 0x09); | |||
| tick(); | |||
| cia.RS = 0x0B; | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| cia.RS = 0x0A; | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| cia.RS = 0x09; | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| cia.RS = 0x08; | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| }); | |||
| it("TOD Write Time and Cycle Stop on Write", function(){ | |||
| let cia = new MOSCIA(); | |||
| let tick = (cycles) => { | |||
| let ccount = cycles * 6; | |||
| for (let i=0; i < ccount; i++) | |||
| cia.TOD = 1; | |||
| }; | |||
| cia.RS = 0x0B; | |||
| cia.DATA = 0x11; | |||
| cia.RS = 0x0A; | |||
| cia.DATA = 0x30; | |||
| cia.RS = 0x09; | |||
| cia.DATA = 0x20; | |||
| // The lock on the timer isn't released until a write to RS=0x08 | |||
| // so running a few ticks should NOT change the current values! | |||
| tick(10); | |||
| cia.RS = 0x0B; | |||
| expect(cia.DATA).to.be.equal(0x11); | |||
| cia.RS = 0x0A; | |||
| expect(cia.DATA).to.be.equal(0x30); | |||
| cia.RS = 0x09; | |||
| expect(cia.DATA).to.be.equal(0x20); | |||
| cia.RS = 0x08; | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| // Write to RS=0x08 and cycle again! | |||
| cia.DATA = 0x08; // <= 8/10ths a second. | |||
| tick(8); | |||
| expect(cia.DATA).to.be.equal(0x06); | |||
| cia.RS = 0x09; | |||
| expect(cia.DATA).to.be.equal(0x21); | |||
| // Check if writing is prevented unless Hours (0x0B) is written to first | |||
| cia.DATA = 0x44; | |||
| expect(cia.DATA).to.be.equal(0x21); | |||
| cia.RS = 0x08; | |||
| cia.DATA = 0x04; | |||
| expect(cia.DATA).to.be.equal(0x06); | |||
| }); | |||
| it("Set and Trigger TOD Alarm", function(){ | |||
| let cia = new MOSCIA(); | |||
| let tick = (cycles) => { | |||
| let ccount = cycles * 6; | |||
| for (let i=0; i < ccount; i++) | |||
| cia.TOD = 1; | |||
| }; | |||
| // Setting up the alarm interrupts! | |||
| cia.RS = 0x0D; | |||
| cia.DATA = 0x84; | |||
| // Setting alarm values. | |||
| cia.RS = 0x0F; | |||
| cia.DATA = cia.DATA | 0x80; | |||
| cia.RS = 0x0B; | |||
| cia.DATA = 0x01; | |||
| cia.RS = 0x0A; | |||
| cia.DATA = 0x01; | |||
| cia.RS = 0x09; | |||
| cia.DATA = 0x01; | |||
| cia.RS = 0x08; | |||
| cia.DATA = 0x04; | |||
| // Testing that all TOD values remain unchanged. | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| cia.RS = 0x09; | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| cia.RS = 0x0A; | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| cia.RS = 0x0B; | |||
| expect(cia.DATA).to.be.equal(0x00); | |||
| // Forcing TOD to be 4/10ths a second from triggering the alarm. | |||
| cia.setTOD(0x01, 0x01, 0x01, 0x00); | |||
| tick(4); | |||
| cia.RS = 0x0D; | |||
| // Hold the value as the IC clears after a read. | |||
| let IC = cia.DATA; | |||
| expect(IC & 0x04).to.be.equal(0x04); | |||
| expect(IC & 0x80).to.be.equal(0x80); | |||
| }); | |||
| }); | |||