Fantasy 8Bit system (F8), is a fantasy 8bit console and a set of libraries for creating fantasy 8bit consoles.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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;