Fantasy 8Bit system (F8), is a fantasy 8bit console and a set of libraries for creating fantasy 8bit consoles.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

360 lines
9.1KB

  1. const BCD = require('./utils/bcd.js');
  2. const BITM = require('./utils/bitman.js');
  3. function ChangeICBit(cia, v, pos){
  4. let mask = ~(1 << pos);
  5. v = ((v === true || v === 1) ? 1 : 0) << pos;
  6. cia.__IC = (cia.__IC & mask) | v;
  7. }
  8. function TODTick(cia){
  9. cia.__TODTick += 1;
  10. if (cia.__TODTick === 6){
  11. cia.__TODTick = cia.__CTA & 0x01;
  12. if (cia.__TOD[0] == 0x09){
  13. cia.__TOD[0] = 0;
  14. if (cia.__TOD[1] == 0x59){
  15. cia.__TOD[1] = 0;
  16. if (cia.__TOD[2] == 0x59){
  17. cia.__TOD[2] = 0;
  18. if (cia.__TOD[3] == 0x11 || cia.__TOD[3] == 0x91){
  19. cia.__TOD[3] = (cia.__TOD[3] == 0x91) ? 0x00 : 0x10;
  20. } else {
  21. let pm = cia.__TOD[3] & 0x80;
  22. cia.__TOD[3] = BCD.add(cia.__TOD[3] & 0x7F, 0x01, 2) | pm;
  23. }
  24. } else {cia.__TOD[2] = BCD.add(cia.__TOD[2], 0x01, 2);}
  25. } else {cia.__TOD[1] = BCD.add(cia.__TOD[1], 0x01, 2);}
  26. } else {cia.__TOD[0] = BCD.add(cia.__TOD[0], 0x01, 2);}
  27. }
  28. 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]){
  29. ChangeICBit(cia, 1, 2);
  30. }
  31. }
  32. function TODLatch(cia){
  33. if (cia.__TODLatch === 0){
  34. cia.__TODLatch = 1;
  35. cia.__LTOD[0] = cia.__TOD[0];
  36. cia.__LTOD[1] = cia.__TOD[1];
  37. cia.__LTOD[2] = cia.__TOD[2];
  38. cia.__LTOD[3] = cia.__TOD[3];
  39. }
  40. }
  41. function TimerATick(cia){
  42. if (cia.__timerA > 0){
  43. cia.__timerA -= 1;
  44. } else {
  45. // Check if Timer A is continuous
  46. if (BITM.isOn(cia.__CTA, 3) === 0){
  47. cia.__timerA = cia.__timerALatch;
  48. } else {
  49. // Not continuous, so clear bit 0 (stop timer).
  50. cia.__CTA = BITM.clear(cia.__CTA, 0);
  51. }
  52. // Setting the interrupt bit for timer A
  53. cia.__IC = BITM.set(cia.__IC, 0);
  54. // Check to see if timer modifies the PORT B bit 6.
  55. // If so, determine if it's a pulse or an toggle.
  56. if (BITM.isOn(cia.__CTA, 1))
  57. cia.__PDB = (BITM.isOn(cia.__CTA, 2) === 0) ? BITM.set(cia.__PDB, 6) : BITM.toggle(cia.__PDB, 6);
  58. // If timer B is running, and timer B tracks timer A underflows
  59. // tick timer B (or, tick it if CNT is positive)
  60. if (BITM.isOn(cia.__CTB, 0)){
  61. let cs = (this.__CTB & 0x60) >> 5;
  62. if (cs === 2 || (cs === 3 && cia.__CNT === 1))
  63. TimerBTick(cia);
  64. }
  65. }
  66. }
  67. function TimerBTick(cia){
  68. if (cia.__timerB > 0){
  69. cia.__timerB -= 1;
  70. } else {
  71. if (BITM.isOn(cia.__CTB, 3) === 0){
  72. cia.__timerB = cia.__timerBLatch;
  73. } else {
  74. cia.__CTB = BITM.clear(cia.__CTB, 0);
  75. }
  76. cia.__IC = BITM.set(cia.__IC, 1);
  77. if (BITM.isOn(cia.__CTB, 1))
  78. cia.__PDB = (BITM.isOn(cia.__CTB, 2) === 0) ? BITM.set(cia.__PDB, 7) : BITM.toggle(cia.__PDB, 7);
  79. }
  80. }
  81. function Tick(cia){
  82. if (BITM.isOn(cia.__CTA, 0)){
  83. if (BITM.isOn(cia.__CTA, 1) && !BITM.isOn(cia.__CTA, 2))
  84. cia.__PDB = BITM.clear(cia.__PDB, 6);
  85. if (!BITM.isOn(cia.__CTA, 5))
  86. TimerATick(cia);
  87. }
  88. if (BITM.isOn(cia.__CTB, 0)){
  89. if (BITM.isOn(cia.__CTB, 1) && !BITM.isOn(cia.__CTB, 2))
  90. cia.__PDB = BITM.clear(cia.__PDB, 7);
  91. let cs = (cia.__CTB & 0x60) >> 5;
  92. if (cs === 0)
  93. TimerBTick(cia);
  94. }
  95. if (cia.__CNT === 1){
  96. if (BITM.isOn(cia.__CTA, 0) && BITM.isOn(cia.__CTA, 5))
  97. TimerATick(cia);
  98. if (BITM.isOn(cia.__CTB, 0)){
  99. let cs = (cia.__CTB & 0x60) >> 5;
  100. if (cs === 1)
  101. TimerBTick(cia);
  102. }
  103. if (BITM.isOn(cia.__CTA, 6)){
  104. if (cia.__SPi > 0){
  105. cia.__SP = BITM.val(cia.__SData, 7);
  106. cia.__SData = (cia.__SData << 1) & 0xFF;
  107. cia.__SPi -= 1;
  108. if (cia.__SPi === 0)
  109. cia.__IC = BITM.set(cia.__IC, 3);
  110. }
  111. } else {
  112. if (cia.__SPi < 8){
  113. cia.__SData = (cia.__SData << 1) | cia.__SP;
  114. cia.__SPi += 1;
  115. if (cia.__SPi === 8)
  116. cia.__IC = BITM.set(cia.__IC, 3);
  117. }
  118. }
  119. }
  120. cia.__CNT = 0;
  121. }
  122. class MOSCIA{
  123. constructor(){
  124. this.__regsel = 0;
  125. this.__RW = 0;
  126. this.__CNT = 0;
  127. this.__SP = 0;
  128. this.__SPi = 0;
  129. this.__SData = 0;
  130. this.__PDA = 0;
  131. this.__PDB = 0;
  132. this.__DDA = 0;
  133. this.__DDB = 0;
  134. this.__CTA = 0;
  135. this.__CTB = 0;
  136. this.__IC = 0;
  137. this.__ICMask = 0;
  138. this.__timerA = 0;
  139. this.__timerALatch = 1;
  140. this.__timerB = 0;
  141. this.__timerBLatch = 1;
  142. // Time Of Day
  143. this.__TODLatch = 0;
  144. this.__TODTick = 0;
  145. this.__TOD = [0,0,0,0];
  146. this.__LTOD = [0,0,0,0];
  147. this.__ALTOD = [0,0,0,0];
  148. }
  149. get RS(){return this.__regsel;}
  150. set RS(rs){this.__regsel = rs & 0x0F;}
  151. get RW(){return this.__RW;}
  152. set RW(rw){this.__RW = (rw === true || rw === 1) ? 1 : 0;}
  153. get DATA(){
  154. let val = 0;
  155. switch(this.__regsel){
  156. case 0x00: // Peripheral Data A
  157. break;
  158. case 0x01: // Peripheral Data B
  159. break;
  160. case 0x02: // Data Direction Reg A
  161. break;
  162. case 0x03: // Data Direction Reg B
  163. break;
  164. case 0x04: // Timer A Low
  165. val = (this.__timerA & 0x00FF); break;
  166. case 0x05: // Timer A High
  167. val = ((this.__timerA & 0xFF00) >> 4); break;
  168. case 0x06: // Timer B Low
  169. val = (this.__timerB & 0x00FF); break;
  170. case 0x07: // Timer B High
  171. val = ((this.__timerB & 0xFF00) >> 4); break;
  172. case 0x08: // 10th of Sec Reg
  173. this.__TODLatch = 0;
  174. val = this.__TOD[0]; break;
  175. case 0x09: // Seconds Reg
  176. val = (this.__TODLatch > 0) ? this.__LTOD[1] : this.__TOD[1]; break;
  177. case 0x0A: // Minutes Reg
  178. val = (this.__TODLatch > 0) ? this.__LTOD[2] : this.__TOD[2]; break;
  179. case 0x0B: // Hours AM/PM Reg
  180. TODLatch(this);
  181. val = this.__LTOD[3]; break;
  182. case 0x0C: // Serial Data
  183. val = this.__SData; break;
  184. case 0x0D: // Interrupt Control
  185. let v = this.__IC;
  186. this.__IC = 0;
  187. return v; break;
  188. case 0x0E: // Control Timer Reg A
  189. val = this.__CTA; break;
  190. case 0x0F: // Control Timer Reg B
  191. val = this.__CTB; break;
  192. }
  193. return val;
  194. }
  195. set DATA(d){
  196. if (this.__RW === 1){return;}
  197. let tod = 0;
  198. switch(this.__regsel){
  199. case 0x00: // Peripheral Data A
  200. break;
  201. case 0x01: // Peripheral Data B
  202. break;
  203. case 0x02: // Data Direction Reg A
  204. break;
  205. case 0x03: // Data Direction Reg B
  206. break;
  207. case 0x04: // Timer A Low
  208. this.__timerALatch = (this.__timerALatch & 0xFF00) | (d & 0xFF);
  209. break;
  210. case 0x05: // Timer A High
  211. this.__timerALatch = (this.__timerALatch & 0x00FF) | ((d & 0xFF) << 4);
  212. break
  213. case 0x06: // Timer B Low
  214. this.__timerBLatch = (this.__timerBLatch & 0xFF00) | (d & 0xFF);
  215. break;
  216. case 0x07: // Timer B High
  217. this.__timerBLatch = (this.__timerBLatch & 0x00FF) | ((d & 0xFF) << 4);
  218. break;
  219. case 0x08: // 10th of Sec Reg
  220. TODLatch(this);
  221. this.__TODLatch = 2;
  222. tod = (BITM.isOn(this.__CTB, 7)) ? this.__ALTOD : this.__TOD;
  223. tod[0] = d & 0xFF;
  224. break;
  225. case 0x09: // Seconds Reg
  226. TODLatch(this);
  227. this.__TODLatch = 2;
  228. tod = (BITM.isOn(this.__CTB, 7)) ? this.__ALTOD : this.__TOD;
  229. tod[1] = d & 0xFF;
  230. break;
  231. case 0x0A: // Minutes Reg
  232. TODLatch(this);
  233. this.__TODLatch = 2;
  234. tod = (BITM.isOn(this.__CTB, 7)) ? this.__ALTOD : this.__TOD;
  235. tod[2] = d & 0xFF;
  236. break;
  237. case 0x0B: // Hours AM/PM Reg
  238. TODLatch(this);
  239. this.__TODLatch = 2;
  240. tod = (BITM.isOn(this.__CTB, 7)) ? this.__ALTOD : this.__TOD;
  241. tod[3] = d & 0xFF;
  242. break;
  243. case 0x0C: // Serial Data
  244. break;
  245. case 0x0D: // Interrupt Control
  246. if (BITM.isOn(d & 0xFF, 7)){
  247. for (let i=0; i < 5; i++){
  248. if (BITM.isOn(d & 0xFF, i))
  249. this.__ICMask = BITM.set(this.__ICMask, i);
  250. }
  251. } else {
  252. for (let i=0; i < 5; i++){
  253. if (BITM.isOn(d & 0xFF, i))
  254. this.__ICMask = BITM.clear(this.__ICMask, i);
  255. }
  256. }
  257. break;
  258. case 0x0E: // Control Timer Reg A
  259. this.__CTA = d & 0xFF;
  260. if (BITM.isOn(this.__CTA, 4))
  261. this.__timerA = this.__timerALatch;
  262. break;
  263. case 0x0F: // Control Timer Reg B
  264. this.__CTB = d & 0xFF;
  265. if (BITM.isOn(this.__CTB, 4))
  266. this.__timerB = this.__timerBLatch;
  267. break;
  268. }
  269. }
  270. get CNT(){return this.__CNT;}
  271. set CNT(c){
  272. this.__CNT = (c >= 1) ? 1 : 0;
  273. }
  274. get SP(){return this.__SP;}
  275. set SP(sp){
  276. this.__SP = (sp === true || sp === 1) ? 1 : 0;
  277. }
  278. get TOD(){return 0;}
  279. set TOD(b){
  280. if (b > 0 || this.__TODLatch < 2)
  281. TODTick(this);
  282. }
  283. get phi2(){return 0;}
  284. set phi2(p){
  285. if (p === true || p === 1){
  286. Tick(this);
  287. }
  288. }
  289. reset(){
  290. this.__CNT = 0;
  291. this.__PDA = 0;
  292. this.__PDB = 0;
  293. this.__DDA = 0;
  294. this.__DDB = 0;
  295. this.__CTA = 0;
  296. this.__CTB = 0;
  297. this.__IC = 0;
  298. this.__ICMask = 0;
  299. this.__timerA = 0;
  300. this.__timerALatch = 1;
  301. this.__timerB = 0;
  302. this.__timerBLatch = 1;
  303. // Time Of Day
  304. this.__TODLatch = 0;
  305. this.__TODTick = 0;
  306. this.__TOD = [0,0,0,0];
  307. this.__LTOD = [0,0,0,0];
  308. this.__ALTOD = [0,0,0,0];
  309. }
  310. }
  311. module.exports = MOSCIA;