| describe("MOSCIA Tests...", function(){ | describe("MOSCIA Tests...", function(){ | ||||
| //var cia = new MOSCIA(); | //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(){ | it("PD*/DD* Masking", function(){ | ||||
| let cia = new MOSCIA(); | let cia = new MOSCIA(); | ||||
| Input(1); | Input(1); | ||||
| expect(cia.DATA).to.be.equal(0xCD); | expect(cia.DATA).to.be.equal(0xCD); | ||||
| cia.RS = 0x0D; | 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 | // Reading from RS = 0x0D should clear the interrupt values. Checking this | ||||
| expect(cia.DATA).to.be.equal(0); | expect(cia.DATA).to.be.equal(0); | ||||
| expect((cia.DATA & 0x08) >> 3).to.be.equal(1); | expect((cia.DATA & 0x08) >> 3).to.be.equal(1); | ||||
| expect(cia.DATA).to.be.equal(0); | 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); | |||||
| }); | |||||
| }); | }); | ||||