| @@ -46,10 +46,55 @@ function TODLatch(cia){ | |||
| } | |||
| function TimerATick(cia){ | |||
| if (cia.__timerA > 0){ | |||
| cia.__timerA -= 1; | |||
| } else { | |||
| // Check if Timer A is continuous | |||
| if (BITM.isOn(cia.__CTA, 3) === 0){ | |||
| cia.__timerA = cia.__timerALatch; | |||
| } else { | |||
| // Not continuous, so clear bit 0 (stop timer). | |||
| cia.__CTA = BITM.clear(cia.__CTA, 0); | |||
| } | |||
| // Check to see if timer modifies the PORT B bit 6. | |||
| // If so, determine if it's a pulse or an toggle. | |||
| if (BITM.isOn(cia.__CTA, 1)) | |||
| cia.__PDB = (BITM.isOn(cia.__CTA, 2) === 0) ? BITM.set(cia.__PDB, 6) : BITM.toggle(cia.__PDB, 6); | |||
| // If timer B is running, and timer B tracks timer A underflows | |||
| // tick timer B (or, tick it if CNT is positive) | |||
| if (BITM.isOn(cia.__CTB, 0)){ | |||
| let cs = (this.__CTB & 0x60) >> 5; | |||
| if (cs === 2 || (cs === 3 && cia.__CNT === 1)) | |||
| TimerBTick(cia); | |||
| } | |||
| } | |||
| } | |||
| function TimerBTick(cia){ | |||
| if (cia.__timerB > 0){ | |||
| cia.__timerB -= 1; | |||
| } else { | |||
| if (BITM.isOn(cia.__CTB, 3) === 0){ | |||
| cia.__timerB = cia.__timerBLatch; | |||
| } else { | |||
| cia.__CTB = BITM.clear(cia.__CTB, 0); | |||
| } | |||
| if (BITM.isOn(cia.__CTB, 1)) | |||
| cia.__PDB = (BITM.isOn(cia.__CTB, 2) === 0) ? BITM.set(cia.__PDB, 7) : BITM.toggle(cia.__PDB, 7); | |||
| } | |||
| } | |||
| class MOSCIA{ | |||
| constructor(){ | |||
| this.__regsel = 0; | |||
| this.__CNT = 0; | |||
| this.__PDA = 0; | |||
| this.__PDB = 0; | |||
| this.__DDA = 0; | |||
| @@ -87,31 +132,31 @@ class MOSCIA{ | |||
| case 0x03: // Data Direction Reg B | |||
| break; | |||
| case 0x04: // Timer A Low | |||
| break; | |||
| val = (this.__timerA & 0x00FF); break; | |||
| case 0x05: // Timer A High | |||
| break | |||
| val = ((this.__timerA & 0xFF00) >> 4); break; | |||
| case 0x06: // Timer B Low | |||
| break; | |||
| val = (this.__timerB & 0x00FF); break; | |||
| case 0x07: // Timer B High | |||
| break; | |||
| val = ((this.__timerB & 0xFF00) >> 4); break; | |||
| case 0x08: // 10th of Sec Reg | |||
| this.__TODLatch = 0; | |||
| return this.__TOD[0]; break; | |||
| val = this.__TOD[0]; break; | |||
| case 0x09: // Seconds Reg | |||
| return (this.__TODLatch > 0) ? this.__LTOD[1] : this.__TOD[1]; break; | |||
| val = (this.__TODLatch > 0) ? this.__LTOD[1] : this.__TOD[1]; break; | |||
| case 0x0A: // Minutes Reg | |||
| return (this.__TODLatch > 0) ? this.__LTOD[2] : this.__TOD[2]; break; | |||
| val = (this.__TODLatch > 0) ? this.__LTOD[2] : this.__TOD[2]; break; | |||
| case 0x0B: // Hours AM/PM Reg | |||
| TODLatch(this); | |||
| return this.__LTOD[3]; break; | |||
| val = this.__LTOD[3]; break; | |||
| case 0x0C: // Serial Data | |||
| break; | |||
| case 0x0D: // Interrupt Control | |||
| break; | |||
| case 0x0E: // Control Timer Reg A | |||
| break; | |||
| val = this.__CTA; break; | |||
| case 0x0F: // Control Timer Reg B | |||
| break; | |||
| val = this.__CTB; break; | |||
| } | |||
| return val; | |||
| } | |||
| @@ -127,12 +172,16 @@ class MOSCIA{ | |||
| case 0x03: // Data Direction Reg B | |||
| break; | |||
| case 0x04: // Timer A Low | |||
| this.__timerALatch = (this.__timerALatch & 0xFF00) | (d & 0xFF); | |||
| break; | |||
| case 0x05: // Timer A High | |||
| this.__timerALatch = (this.__timerALatch & 0x00FF) | ((d & 0xFF) << 4); | |||
| break | |||
| case 0x06: // Timer B Low | |||
| this.__timerBLatch = (this.__timerBLatch & 0xFF00) | (d & 0xFF); | |||
| break; | |||
| case 0x07: // Timer B High | |||
| this.__timerBLatch = (this.__timerBLatch & 0x00FF) | ((d & 0xFF) << 4); | |||
| break; | |||
| case 0x08: // 10th of Sec Reg | |||
| TODLatch(this); | |||
| @@ -163,14 +212,32 @@ class MOSCIA{ | |||
| case 0x0D: // Interrupt Control | |||
| break; | |||
| case 0x0E: // Control Timer Reg A | |||
| this.__CTA = d & 0xFF; | |||
| if (BITM.isOn(this.__CTA, 4)) | |||
| this.__timerA = this.__timerALatch; | |||
| break; | |||
| case 0x0F: // Control Timer Reg B | |||
| this.__CTB = d & 0xFF; | |||
| if (BITM.isOn(this.__CTB, 4)) | |||
| this.__timerB = this.__timerBLatch; | |||
| break; | |||
| } | |||
| } | |||
| get CNT(){return 0;} | |||
| set CNT(c){} | |||
| get CNT(){return this.__CNT;} | |||
| set CNT(c){ | |||
| this.__CNT = (c >= 1) ? 1 : 0; | |||
| if (this.__CNT === 1){ | |||
| if (BITM.isOn(this.__CTA, 0) && BITM.isOn(this.__CTA, 5)) | |||
| TimerATick(this); | |||
| if (BITM.isOn(this.__CTB, 0){ | |||
| let cs = (this.__CTB & 0x60) >> 5; | |||
| if (cs === 1) | |||
| TimerBTick(this); | |||
| } | |||
| } | |||
| } | |||
| get SP(){return 0;} | |||
| set SP(b){} | |||
| @@ -180,6 +247,20 @@ class MOSCIA{ | |||
| if (b > 0 || this.__TODLatch < 2) | |||
| TODTick(this); | |||
| } | |||
| get phi2(){return 0;} | |||
| set phi2(p){ | |||
| if (p >= 1){ | |||
| if (BITM.isOn(this.__CTA, 0) && !BITM.isOn(this.__CTA, 5)){ | |||
| TimerATick(this); | |||
| } | |||
| if (BITM.isOn(this.__CTB, 0)){ | |||
| let cs = (this.__CTB & 0x60) >> 5; | |||
| if (cs === 0) | |||
| TimerBTick(this); | |||
| } | |||
| } | |||
| } | |||
| } | |||