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