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.

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. });