|
- const BCD = require('./utils/bcd.js');
- const BITM = require('./utils/bitman.js');
-
- function ChangeICBit(cia, v, pos){
- let mask = ~(1 << pos);
- v = ((v === true || v === 1) ? 1 : 0) << pos;
- cia.__IC = (cia.__IC & mask) | v;
- }
-
-
- function TODTick(cia){
- cia.__TODTick += 1;
- if (cia.__TODTick === 6){
- cia.__TODTick = cia.__CTA & 0x01;
- if (cia.__TOD[0] == 0x09){
- cia.__TOD[0] = 0;
- if (cia.__TOD[1] == 0x59){
- cia.__TOD[1] = 0;
- if (cia.__TOD[2] == 0x59){
- cia.__TOD[2] = 0;
- if (cia.__TOD[3] == 0x11 || cia.__TOD[3] == 0x91){
- cia.__TOD[3] = (cia.__TOD[3] == 0x91) ? 0x00 : 0x10;
- } else {
- let pm = cia.__TOD[3] & 0x80;
- cia.__TOD[3] = BCD.add(cia.__TOD[3] & 0x7F, 0x01, 2) | pm;
- }
- } else {cia.__TOD[2] = BCD.add(cia.__TOD[2], 0x01, 2);}
- } else {cia.__TOD[1] = BCD.add(cia.__TOD[1], 0x01, 2);}
- } else {cia.__TOD[0] = BCD.add(cia.__TOD[0], 0x01, 2);}
- }
-
- if (cia.__TOD[0] == cia.__ALTOD[0] && cia.__TOD[1] == cia.__ALTOD[1] && cia.__TOD[2] == cia.__ALTOD[2] && cia.__TOD[3] == cia.__ALTOD[3]){
- ChangeICBit(cia, 1, 2);
- }
- }
-
- function TODLatch(cia){
- if (cia.__TODLatch === 0){
- cia.__TODLatch = 1;
- cia.__LTOD[0] = cia.__TOD[0];
- cia.__LTOD[1] = cia.__TOD[1];
- cia.__LTOD[2] = cia.__TOD[2];
- cia.__LTOD[3] = cia.__TOD[3];
- }
- }
-
-
- 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);
- }
-
- // Setting the interrupt bit for timer A
- cia.__IC = BITM.set(cia.__IC, 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);
- }
-
- cia.__IC = BITM.set(cia.__IC, 1);
-
- if (BITM.isOn(cia.__CTB, 1))
- cia.__PDB = (BITM.isOn(cia.__CTB, 2) === 0) ? BITM.set(cia.__PDB, 7) : BITM.toggle(cia.__PDB, 7);
- }
- }
-
-
- function Tick(cia){
- if (BITM.isOn(cia.__CTA, 0)){
- if (BITM.isOn(cia.__CTA, 1) && !BITM.isOn(cia.__CTA, 2))
- cia.__PDB = BITM.clear(cia.__PDB, 6);
-
- if (!BITM.isOn(cia.__CTA, 5))
- TimerATick(cia);
- }
- if (BITM.isOn(cia.__CTB, 0)){
- if (BITM.isOn(cia.__CTB, 1) && !BITM.isOn(cia.__CTB, 2))
- cia.__PDB = BITM.clear(cia.__PDB, 7);
-
- let cs = (cia.__CTB & 0x60) >> 5;
- if (cs === 0)
- TimerBTick(cia);
- }
-
- if (cia.__CNT === 1){
- if (BITM.isOn(cia.__CTA, 0) && BITM.isOn(cia.__CTA, 5))
- TimerATick(cia);
-
- if (BITM.isOn(cia.__CTB, 0)){
- let cs = (cia.__CTB & 0x60) >> 5;
- if (cs === 1)
- TimerBTick(cia);
- }
-
- if (BITM.isOn(cia.__CTA, 6)){
- if (cia.__SPi > 0){
- cia.__SP = BITM.val(cia.__SData, 7);
- cia.__SData = (cia.__SData << 1) & 0xFF;
- cia.__SPi -= 1;
- if (cia.__SPi === 0)
- cia.__IC = BITM.set(cia.__IC, 3);
- }
- } else {
- if (cia.__SPi < 8){
- cia.__SData = (cia.__SData << 1) | cia.__SP;
- cia.__SPi += 1;
- if (cia.__SPi === 8)
- cia.__IC = BITM.set(cia.__IC, 3);
- }
- }
- }
- cia.__CNT = 0;
- }
-
-
- class MOSCIA{
- constructor(){
- this.__regsel = 0;
- this.__RW = 0;
-
- this.__CNT = 0;
-
- this.__SP = 0;
- this.__SPi = 0;
- this.__SData = 0;
-
- this.__PDA = 0;
- this.__PDB = 0;
- this.__DDA = 0;
- this.__DDB = 0;
-
- this.__CTA = 0;
- this.__CTB = 0;
-
- this.__IC = 0;
- this.__ICMask = 0;
-
- this.__timerA = 0;
- this.__timerALatch = 1;
- this.__timerB = 0;
- this.__timerBLatch = 1;
-
- // Time Of Day
- this.__TODLatch = 0;
- this.__TODTick = 0;
- this.__TOD = [0,0,0,0];
- this.__LTOD = [0,0,0,0];
- this.__ALTOD = [0,0,0,0];
- }
-
- get RS(){return this.__regsel;}
- set RS(rs){this.__regsel = rs & 0x0F;}
-
- get RW(){return this.__RW;}
- set RW(rw){this.__RW = (rw === true || rw === 1) ? 1 : 0;}
-
- get DATA(){
- let val = 0;
- switch(this.__regsel){
- case 0x00: // Peripheral Data A
- break;
- case 0x01: // Peripheral Data B
- break;
- case 0x02: // Data Direction Reg A
- break;
- case 0x03: // Data Direction Reg B
- break;
- case 0x04: // Timer A Low
- val = (this.__timerA & 0x00FF); break;
- case 0x05: // Timer A High
- val = ((this.__timerA & 0xFF00) >> 4); break;
- case 0x06: // Timer B Low
- val = (this.__timerB & 0x00FF); break;
- case 0x07: // Timer B High
- val = ((this.__timerB & 0xFF00) >> 4); break;
- case 0x08: // 10th of Sec Reg
- this.__TODLatch = 0;
- val = this.__TOD[0]; break;
- case 0x09: // Seconds Reg
- val = (this.__TODLatch > 0) ? this.__LTOD[1] : this.__TOD[1]; break;
- case 0x0A: // Minutes Reg
- val = (this.__TODLatch > 0) ? this.__LTOD[2] : this.__TOD[2]; break;
- case 0x0B: // Hours AM/PM Reg
- TODLatch(this);
- val = this.__LTOD[3]; break;
- case 0x0C: // Serial Data
- val = this.__SData; break;
- case 0x0D: // Interrupt Control
- let v = this.__IC;
- this.__IC = 0;
- return v; break;
- case 0x0E: // Control Timer Reg A
- val = this.__CTA; break;
- case 0x0F: // Control Timer Reg B
- val = this.__CTB; break;
- }
- return val;
- }
-
- set DATA(d){
- if (this.__RW === 1){return;}
- let tod = 0;
- switch(this.__regsel){
- case 0x00: // Peripheral Data A
- break;
- case 0x01: // Peripheral Data B
- break;
- case 0x02: // Data Direction Reg A
- break;
- 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);
- this.__TODLatch = 2;
- tod = (BITM.isOn(this.__CTB, 7)) ? this.__ALTOD : this.__TOD;
- tod[0] = d & 0xFF;
- break;
- case 0x09: // Seconds Reg
- TODLatch(this);
- this.__TODLatch = 2;
- tod = (BITM.isOn(this.__CTB, 7)) ? this.__ALTOD : this.__TOD;
- tod[1] = d & 0xFF;
- break;
- case 0x0A: // Minutes Reg
- TODLatch(this);
- this.__TODLatch = 2;
- tod = (BITM.isOn(this.__CTB, 7)) ? this.__ALTOD : this.__TOD;
- tod[2] = d & 0xFF;
- break;
- case 0x0B: // Hours AM/PM Reg
- TODLatch(this);
- this.__TODLatch = 2;
- tod = (BITM.isOn(this.__CTB, 7)) ? this.__ALTOD : this.__TOD;
- tod[3] = d & 0xFF;
- break;
- case 0x0C: // Serial Data
- break;
- case 0x0D: // Interrupt Control
- if (BITM.isOn(d & 0xFF, 7)){
- for (let i=0; i < 5; i++){
- if (BITM.isOn(d & 0xFF, i))
- this.__ICMask = BITM.set(this.__ICMask, i);
- }
- } else {
- for (let i=0; i < 5; i++){
- if (BITM.isOn(d & 0xFF, i))
- this.__ICMask = BITM.clear(this.__ICMask, i);
- }
- }
- 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 this.__CNT;}
- set CNT(c){
- this.__CNT = (c >= 1) ? 1 : 0;
- }
-
- get SP(){return this.__SP;}
- set SP(sp){
- this.__SP = (sp === true || sp === 1) ? 1 : 0;
- }
-
- get TOD(){return 0;}
- set TOD(b){
- if (b > 0 || this.__TODLatch < 2)
- TODTick(this);
- }
-
- get phi2(){return 0;}
- set phi2(p){
- if (p === true || p === 1){
- Tick(this);
- }
- }
-
-
- reset(){
- this.__CNT = 0;
-
- this.__PDA = 0;
- this.__PDB = 0;
- this.__DDA = 0;
- this.__DDB = 0;
-
- this.__CTA = 0;
- this.__CTB = 0;
-
- this.__IC = 0;
- this.__ICMask = 0;
-
- this.__timerA = 0;
- this.__timerALatch = 1;
- this.__timerB = 0;
- this.__timerBLatch = 1;
-
- // Time Of Day
- this.__TODLatch = 0;
- this.__TODTick = 0;
- this.__TOD = [0,0,0,0];
- this.__LTOD = [0,0,0,0];
- this.__ALTOD = [0,0,0,0];
- }
- }
-
-
- module.exports = MOSCIA;
-
|