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.

402 lines
10KB

  1. const expect = require('chai').expect;
  2. const MOSCIA = require('../src/MOSCIA.js');
  3. describe("MOSCIA Tests...", function(){
  4. //var cia = new MOSCIA();
  5. it("R/W Pin", function(){
  6. let cia = new MOSCIA();
  7. // The RW pin is default low, so writting should be enabled.
  8. cia.RS = 0x02;
  9. expect(cia.DATA).to.be.equal(0x00);
  10. cia.DATA = 0xFF;
  11. expect(cia.DATA).to.be.equal(0xFF);
  12. // Set RW high to disable writting!
  13. cia.RW = 1;
  14. cia.DATA = 0x00;
  15. expect(cia.DATA).to.be.equal(0xFF);
  16. // Set it low once more
  17. cia.RW = 0;
  18. cia.DATA = 0x00;
  19. expect(cia.DATA).to.be.equal(0x00);
  20. });
  21. it("Interrupts (via FLAG)", function(){
  22. let cia = new MOSCIA();
  23. cia.FLAG = 1;
  24. cia.RS = 0x0D;
  25. let IC = cia.DATA;
  26. expect(IC & 0x10).to.be.equal(0x10);
  27. expect(IC & 0x80).to.be.equal(0x80);
  28. expect(cia.DATA).to.be.equal(0x00);
  29. // Setting data changes the interrupt mask. This should mask the
  30. // FLAG interrupt.
  31. cia.DATA = 0x90;
  32. cia.FLAG = 1;
  33. IC = cia.DATA;
  34. expect(IC).to.be.equal(0x00);
  35. });
  36. it("PD*/DD* Masking", function(){
  37. let cia = new MOSCIA();
  38. let pdaVal = 0x3C;
  39. let pdbVal = 0xC3;
  40. cia.onRead("PDA", (name, dda) => {
  41. if (dda < 255)
  42. cia.setPDA(pdaVal);
  43. });
  44. cia.onRead("PDB", (name, ddb) => {
  45. if (ddb < 255)
  46. cia.setPDB(pdbVal);
  47. });
  48. cia.RS = 0x02;
  49. cia.DATA = 0x00;
  50. cia.RS = 0x00;
  51. expect(cia.DATA).to.be.equal(pdaVal);
  52. cia.RS = 0x03;
  53. cia.DATA = 0x00;
  54. cia.RS = 0x01;
  55. expect(cia.DATA).to.be.equal(pdbVal);
  56. cia.RS = 0x02;
  57. cia.DATA = pdbVal;
  58. cia.RS = 0x00;
  59. cia.DATA = pdbVal;
  60. expect(cia.DATA).to.be.equal(0xFF);
  61. cia.RS = 0x03;
  62. cia.DATA = pdaVal;
  63. cia.RS = 0x01;
  64. cia.DATA = pdaVal;
  65. expect(cia.DATA).to.be.equal(0xFF);
  66. });
  67. it("Serial IO", function(){
  68. let cia = new MOSCIA();
  69. let Input = (i) => {
  70. cia.SP = i;
  71. cia.CNT = 1;
  72. cia.phi2 = 1;
  73. };
  74. var outval = 0;
  75. let Output = () => {
  76. cia.CNT = 1;
  77. cia.phi2 = 1;
  78. outval = (outval << 1) | cia.SP;
  79. }
  80. cia.RS = 0x0C;
  81. Input(1);
  82. expect(cia.DATA).to.be.equal(1);
  83. Input(1);
  84. expect(cia.DATA).to.be.equal(3);
  85. Input(0);
  86. expect(cia.DATA).to.be.equal(6);
  87. Input(0);
  88. Input(1);
  89. Input(1);
  90. Input(0);
  91. Input(1);
  92. expect(cia.DATA).to.be.equal(0xCD);
  93. cia.RS = 0x0D;
  94. let IC = cia.DATA;
  95. expect(IC & 0x08).to.be.equal(0x08);
  96. expect(IC & 0x80).to.be.equal(0x80);
  97. // Reading from RS = 0x0D should clear the interrupt values. Checking this
  98. expect(cia.DATA).to.be.equal(0);
  99. cia.RS = 0x0E;
  100. cia.DATA = 0x40; // Enable serial output.
  101. Output();
  102. expect(outval).to.be.equal(1);
  103. Output();
  104. expect(outval).to.be.equal(3);
  105. Output();
  106. expect(outval).to.be.equal(6);
  107. Output();
  108. Output();
  109. Output();
  110. Output();
  111. Output();
  112. expect(outval).to.be.equal(0xCD);
  113. cia.RS = 0x0C;
  114. expect(cia.DATA).to.be.equal(0);
  115. cia.RS = 0x0D;
  116. expect((cia.DATA & 0x08) >> 3).to.be.equal(1);
  117. expect(cia.DATA).to.be.equal(0);
  118. });
  119. it("TOD 60hz", function(){
  120. // NOTE: The TOD clock doesn't actually enforce the frequency.
  121. // The TOD 'pin' is expected to be attached to a clock pulsing at the
  122. // designated frequency.
  123. // As such, this test will run MUCH MUCH faster than the 1.1 seconds
  124. // actually being checked (because I'm not using a clock here).
  125. let cia = new MOSCIA();
  126. let tick60 = () => {
  127. for (let i=0; i < 6; i++)
  128. cia.TOD = 1;
  129. };
  130. // NOTE: The CIA defaults to 60hz TOD clock. Nothing needs to be set.
  131. // Check that seconds is at 0 (we'll test this again later)
  132. cia.RS = 0x09;
  133. expect(cia.DATA).to.be.equal(0);
  134. // Switch to 10ths of a second and go!
  135. cia.RS = 0x08;
  136. expect(cia.DATA).to.be.equal(0);
  137. tick60();
  138. expect(cia.DATA).to.be.equal(0x01);
  139. tick60();
  140. expect(cia.DATA).to.be.equal(0x02);
  141. tick60();
  142. expect(cia.DATA).to.be.equal(0x03);
  143. for (let i=0; i < 8; i++)
  144. tick60();
  145. // Should have looped back around a little at this point!
  146. expect(cia.DATA).to.be.equal(0x01);
  147. // Check seconds again. This should have gone up once!
  148. cia.RS = 0x09;
  149. expect(cia.DATA).to.be.equal(0x01);
  150. });
  151. it("TOD 50hz", function(){
  152. // NOTE: The TOD clock doesn't actually enforce the frequency.
  153. // The TOD 'pin' is expected to be attached to a clock pulsing at the
  154. // designated frequency.
  155. // As such, this test will run MUCH MUCH faster than the 1.1 seconds
  156. // actually being checked (because I'm not using a clock here).
  157. let cia = new MOSCIA();
  158. let tick50 = () => {
  159. for (let i=0; i < 5; i++)
  160. cia.TOD = 1;
  161. };
  162. // enabling 50 hz mode.
  163. cia.RS = 0x0E;
  164. cia.DATA = cia.DATA | 0x80;
  165. // Check that seconds is at 0 (we'll test this again later)
  166. cia.RS = 0x09;
  167. expect(cia.DATA).to.be.equal(0);
  168. // Switch to 10ths of a second and go!
  169. cia.RS = 0x08;
  170. expect(cia.DATA).to.be.equal(0);
  171. tick50();
  172. expect(cia.DATA).to.be.equal(0x01);
  173. tick50();
  174. expect(cia.DATA).to.be.equal(0x02);
  175. tick50();
  176. expect(cia.DATA).to.be.equal(0x03);
  177. for (let i=0; i < 8; i++)
  178. tick50();
  179. // Should have looped back around a little at this point!
  180. expect(cia.DATA).to.be.equal(0x01);
  181. // Check seconds again. This should have gone up once!
  182. cia.RS = 0x09;
  183. expect(cia.DATA).to.be.equal(0x01);
  184. });
  185. it("TOD Latching", function(){
  186. let cia = new MOSCIA();
  187. let tick = (cycles) => {
  188. let ccount = cycles * 6;
  189. for (let i=0; i < ccount; i++)
  190. cia.TOD = 1;
  191. };
  192. cia.setTOD(0x03, 0x59, 0x58, 0x00);
  193. // Copying current clock values for later reference.
  194. let TOD = [0,0,0,0];
  195. cia.RS = 0x08;
  196. TOD[0] = cia.DATA;
  197. cia.RS = 0x09;
  198. TOD[1] = cia.DATA;
  199. cia.RS = 0x0A;
  200. TOD[2] = cia.DATA;
  201. cia.RS = 0x0B;
  202. TOD[3] = cia.DATA; // This should latch the timer!!
  203. tick(11); // Simulate 1.1 second time passing.
  204. // TOD Latch shouldn't be released until next read from RS=0x08, so...
  205. expect(cia.DATA).to.be.equal(TOD[3]);
  206. cia.RS = 0x0A;
  207. expect(cia.DATA).to.be.equal(TOD[2]);
  208. cia.RS = 0x09;
  209. expect(cia.DATA).to.be.equal(TOD[1]);
  210. cia.RS = 0x08;
  211. expect(cia.DATA).to.be.equal(TOD[0]); // Should release the TOD latch
  212. // With latch released, we should be able to read the new time...
  213. expect(cia.DATA).to.be.equal(0x01);
  214. cia.RS = 0x09;
  215. expect(cia.DATA).to.be.equal(0x59);
  216. });
  217. it("TOD Time Rollover with AM/PM change", function(){
  218. let cia = new MOSCIA();
  219. let tick = () => {
  220. for (let i=0; i < 6; i++)
  221. cia.TOD = 1;
  222. };
  223. cia.setTOD(0x11, 0x59, 0x59, 0x09);
  224. tick();
  225. cia.RS = 0x0B;
  226. expect(cia.DATA).to.be.equal(0x80);
  227. cia.RS = 0x0A;
  228. expect(cia.DATA).to.be.equal(0x00);
  229. cia.RS = 0x09;
  230. expect(cia.DATA).to.be.equal(0x00);
  231. cia.RS = 0x08;
  232. expect(cia.DATA).to.be.equal(0x00);
  233. cia.setTOD(0x91, 0x59, 0x59, 0x09);
  234. tick();
  235. cia.RS = 0x0B;
  236. expect(cia.DATA).to.be.equal(0x00);
  237. cia.RS = 0x0A;
  238. expect(cia.DATA).to.be.equal(0x00);
  239. cia.RS = 0x09;
  240. expect(cia.DATA).to.be.equal(0x00);
  241. cia.RS = 0x08;
  242. expect(cia.DATA).to.be.equal(0x00);
  243. });
  244. it("TOD Write Time and Cycle Stop on Write", function(){
  245. let cia = new MOSCIA();
  246. let tick = (cycles) => {
  247. let ccount = cycles * 6;
  248. for (let i=0; i < ccount; i++)
  249. cia.TOD = 1;
  250. };
  251. cia.RS = 0x0B;
  252. cia.DATA = 0x11;
  253. cia.RS = 0x0A;
  254. cia.DATA = 0x30;
  255. cia.RS = 0x09;
  256. cia.DATA = 0x20;
  257. // The lock on the timer isn't released until a write to RS=0x08
  258. // so running a few ticks should NOT change the current values!
  259. tick(10);
  260. cia.RS = 0x0B;
  261. expect(cia.DATA).to.be.equal(0x11);
  262. cia.RS = 0x0A;
  263. expect(cia.DATA).to.be.equal(0x30);
  264. cia.RS = 0x09;
  265. expect(cia.DATA).to.be.equal(0x20);
  266. cia.RS = 0x08;
  267. expect(cia.DATA).to.be.equal(0x00);
  268. // Write to RS=0x08 and cycle again!
  269. cia.DATA = 0x08; // <= 8/10ths a second.
  270. tick(8);
  271. expect(cia.DATA).to.be.equal(0x06);
  272. cia.RS = 0x09;
  273. expect(cia.DATA).to.be.equal(0x21);
  274. // Check if writing is prevented unless Hours (0x0B) is written to first
  275. cia.DATA = 0x44;
  276. expect(cia.DATA).to.be.equal(0x21);
  277. cia.RS = 0x08;
  278. cia.DATA = 0x04;
  279. expect(cia.DATA).to.be.equal(0x06);
  280. });
  281. it("TOD Alarm Set and Trigger", function(){
  282. let cia = new MOSCIA();
  283. let tick = (cycles) => {
  284. let ccount = cycles * 6;
  285. for (let i=0; i < ccount; i++)
  286. cia.TOD = 1;
  287. };
  288. // Setting alarm values.
  289. cia.RS = 0x0F;
  290. cia.DATA = cia.DATA | 0x80;
  291. cia.RS = 0x0B;
  292. cia.DATA = 0x01;
  293. cia.RS = 0x0A;
  294. cia.DATA = 0x01;
  295. cia.RS = 0x09;
  296. cia.DATA = 0x01;
  297. cia.RS = 0x08;
  298. cia.DATA = 0x04;
  299. // Testing that all TOD values remain unchanged.
  300. expect(cia.DATA).to.be.equal(0x00);
  301. cia.RS = 0x09;
  302. expect(cia.DATA).to.be.equal(0x00);
  303. cia.RS = 0x0A;
  304. expect(cia.DATA).to.be.equal(0x00);
  305. cia.RS = 0x0B;
  306. expect(cia.DATA).to.be.equal(0x00);
  307. // Forcing TOD to be 4/10ths a second from triggering the alarm.
  308. cia.setTOD(0x01, 0x01, 0x01, 0x00);
  309. tick(4);
  310. cia.RS = 0x0D;
  311. // Hold the value as the IC clears after a read.
  312. let IC = cia.DATA;
  313. expect(IC & 0x04).to.be.equal(0x04);
  314. expect(IC & 0x80).to.be.equal(0x80);
  315. });
  316. it("Timer A", function(){
  317. let cia = new MOSCIA();
  318. let tick = (cycles) => {
  319. for (let i=0; i < cycles; i++)
  320. cia.phi2 = 1;
  321. };
  322. cia.RS = 0x04;
  323. cia.DATA = 0xFF;
  324. cia.RS = 0x05;
  325. cia.DATA = 0x01;
  326. cia.RS = 0x0E;
  327. // Force latch load into Timer A and activate Timer A
  328. cia.DATA = cia.DATA | 0x11;
  329. cia.RS = 0x04;
  330. expect(cia.DATA).to.be.equal(0xFF);
  331. tick(1);
  332. expect(cia.DATA).to.be.equal(0xFE);
  333. tick(1);
  334. expect(cia.DATA).to.be.equal(0xFD);
  335. tick(0x0200 - 3);
  336. expect(cia.DATA).to.be.equal(0x00);
  337. cia.RS = 0x05;
  338. expect(cia.DATA).to.be.equal(0x00);
  339. tick(1);
  340. expect(cia.DATA).to.be.equal(0x01);
  341. cia.RS = 0x04;
  342. expect(cia.DATA).to.be.equal(0xFF);
  343. cia.RS = 0x0D;
  344. let IC = cia.DATA;
  345. expect(IC & 0x01).to.be.equal(0x01);
  346. expect(IC & 0x80).to.be.equal(0x80);
  347. });
  348. });