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.

unit.src.MOS.CIA.spec.js 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. const expect = require('chai').expect;
  2. const MOSCIA = require('../src/MOS/CIA.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, phi2 Triggered, Interrupt Verification", 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. it("Timer A, CNT Triggered, Underflow report to Port B", function(){
  349. let cia = new MOSCIA();
  350. let tick = (cycles, cnt) => {
  351. cnt = (cnt === true);
  352. for (let i=0; i < cycles; i++){
  353. if (cnt)
  354. cia.CNT = 1;
  355. cia.phi2 = 1;
  356. if (cnt)
  357. cia.CNT = 0;
  358. }
  359. };
  360. cia.RS = 0x04;
  361. cia.DATA = 0x08;
  362. cia.RS = 0x05;
  363. cia.DATA = 0x00;
  364. cia.RS = 0x0E;
  365. // Force latch load into Timer A,
  366. // enable underflow reporting on Port B bit 6,
  367. // set Timer A to trigger on CNT,
  368. // and activate Timer A
  369. cia.DATA = 0x33;
  370. cia.RS = 0x04;
  371. // First, test a few ticks where CNT is not high.
  372. expect(cia.DATA).to.be.equal(0x08); // Validate inital timer value.
  373. tick(1);
  374. tick(1);
  375. tick(1);
  376. tick(1);
  377. expect(cia.DATA).to.be.equal(0x08);
  378. // Now verify CNT triggers!
  379. tick(1, true);
  380. expect(cia.DATA).to.be.equal(0x07);
  381. tick(1, true);
  382. expect(cia.DATA).to.be.equal(0x06);
  383. tick(1, true);
  384. tick(1, true);
  385. tick(1, true);
  386. tick(1, true);
  387. tick(1, true);
  388. tick(1, true);
  389. expect(cia.DATA).to.be.equal(0x00);
  390. tick(1, true);
  391. // Double check that timer has reset to latch value...
  392. expect(cia.DATA).to.be.equal(0x08);
  393. // Verify Interrupt (again... but it doesn't hurt!)
  394. cia.RS = 0x0D;
  395. let IC = cia.DATA;
  396. expect(IC & 0x01).to.be.equal(0x01);
  397. expect(IC & 0x80).to.be.equal(0x80);
  398. // Checking Port B bit 6 which should only go high for 1 cycle!
  399. cia.RS = 0x01;
  400. expect(cia.DATA & 0x40).to.be.equal(0x40);
  401. tick(1, true);
  402. expect(cia.DATA & 0x40).to.be.equal(0x00);
  403. // Check Port B bit 6 toggling...
  404. // -------------------------------------------
  405. // Force latch load into Timer A,
  406. // enable underflow reporting on Port B bit 6,
  407. // setup Port B bit 6 to invert,
  408. // set Timer A to trigger on CNT,
  409. // and activate Timer A
  410. cia.RS = 0x0E;
  411. cia.DATA = 0x37;
  412. for (let i=0; i < 9; i++)
  413. tick(1, true);
  414. cia.RS = 0x04;
  415. expect(cia.DATA).to.be.equal(0x08);
  416. cia.RS = 0x01;
  417. expect(cia.DATA & 0x40).to.be.equal(0x40);
  418. tick(1, true);
  419. expect(cia.DATA & 0x40).to.be.equal(0x40);
  420. cia.RS = 0x04;
  421. expect(cia.DATA).to.be.equal(0x07);
  422. for (let i=0; i < 8; i++)
  423. tick(1, true);
  424. expect(cia.DATA).to.be.equal(0x08);
  425. cia.RS = 0x01;
  426. expect(cia.DATA & 0x40).to.be.equal(0x00);
  427. });
  428. it("Timer B, phi2 Triggered, Interrupt Verification", function(){
  429. let cia = new MOSCIA();
  430. let tick = (cycles) => {
  431. for (let i=0; i < cycles; i++)
  432. cia.phi2 = 1;
  433. };
  434. cia.RS = 0x06;
  435. cia.DATA = 0xFF;
  436. cia.RS = 0x07;
  437. cia.DATA = 0x01;
  438. cia.RS = 0x0F;
  439. // Force latch load into Timer B and activate Timer B
  440. cia.DATA = cia.DATA | 0x11;
  441. cia.RS = 0x06;
  442. expect(cia.DATA).to.be.equal(0xFF);
  443. tick(1);
  444. expect(cia.DATA).to.be.equal(0xFE);
  445. tick(1);
  446. expect(cia.DATA).to.be.equal(0xFD);
  447. tick(0x0200 - 3);
  448. expect(cia.DATA).to.be.equal(0x00);
  449. cia.RS = 0x07;
  450. expect(cia.DATA).to.be.equal(0x00);
  451. tick(1);
  452. expect(cia.DATA).to.be.equal(0x01);
  453. cia.RS = 0x06;
  454. expect(cia.DATA).to.be.equal(0xFF);
  455. cia.RS = 0x0D;
  456. let IC = cia.DATA;
  457. expect(IC & 0x02).to.be.equal(0x02);
  458. expect(IC & 0x80).to.be.equal(0x80);
  459. });
  460. it("Timer B, CNT Triggered, Underflow report to Port B", function(){
  461. let cia = new MOSCIA();
  462. let tick = (cycles, cnt) => {
  463. cnt = (cnt === true);
  464. for (let i=0; i < cycles; i++){
  465. if (cnt)
  466. cia.CNT = 1;
  467. cia.phi2 = 1;
  468. if (cnt)
  469. cia.CNT = 0;
  470. }
  471. };
  472. cia.RS = 0x06;
  473. cia.DATA = 0x08;
  474. cia.RS = 0x07;
  475. cia.DATA = 0x00;
  476. cia.RS = 0x0F;
  477. // Force latch load into Timer B,
  478. // enable underflow reporting on Port B bit 7,
  479. // set Timer B to trigger on CNT,
  480. // and activate Timer B
  481. cia.DATA = 0x33;
  482. cia.RS = 0x06;
  483. // First, test a few ticks where CNT is not high.
  484. expect(cia.DATA).to.be.equal(0x08); // Validate inital timer value.
  485. tick(1);
  486. tick(1);
  487. tick(1);
  488. tick(1);
  489. expect(cia.DATA).to.be.equal(0x08);
  490. // Now verify CNT triggers!
  491. tick(1, true);
  492. expect(cia.DATA).to.be.equal(0x07);
  493. tick(1, true);
  494. expect(cia.DATA).to.be.equal(0x06);
  495. tick(1, true);
  496. tick(1, true);
  497. tick(1, true);
  498. tick(1, true);
  499. tick(1, true);
  500. tick(1, true);
  501. expect(cia.DATA).to.be.equal(0x00);
  502. tick(1, true);
  503. // Double check that timer has reset to latch value...
  504. expect(cia.DATA).to.be.equal(0x08);
  505. // Verify Interrupt (again... but it doesn't hurt!)
  506. cia.RS = 0x0D;
  507. let IC = cia.DATA;
  508. expect(IC & 0x02).to.be.equal(0x02);
  509. expect(IC & 0x80).to.be.equal(0x80);
  510. // Checking Port B bit 7 which should only go high for 1 cycle!
  511. cia.RS = 0x01;
  512. expect(cia.DATA & 0x80).to.be.equal(0x80);
  513. tick(1, true);
  514. expect(cia.DATA & 0x80).to.be.equal(0x00);
  515. // Check Port B bit 7 toggling...
  516. // -------------------------------------------
  517. // Force latch load into Timer B,
  518. // enable underflow reporting on Port B bit 7,
  519. // setup Port B bit 7 to invert,
  520. // set Timer B to trigger on CNT,
  521. // and activate Timer B
  522. cia.RS = 0x0F;
  523. cia.DATA = 0x37;
  524. for (let i=0; i < 9; i++)
  525. tick(1, true);
  526. cia.RS = 0x06;
  527. expect(cia.DATA).to.be.equal(0x08);
  528. cia.RS = 0x01;
  529. expect(cia.DATA & 0x80).to.be.equal(0x80);
  530. tick(1, true);
  531. expect(cia.DATA & 0x80).to.be.equal(0x80);
  532. cia.RS = 0x06;
  533. expect(cia.DATA).to.be.equal(0x07);
  534. for (let i=0; i < 8; i++)
  535. tick(1, true);
  536. expect(cia.DATA).to.be.equal(0x08);
  537. cia.RS = 0x01;
  538. expect(cia.DATA & 0x80).to.be.equal(0x00);
  539. });
  540. it("Timer B tick on Timer A Underflow (phi2 Triggered)", function(){
  541. let cia = new MOSCIA();
  542. let tick = (cycle) => {
  543. for (let i=0; i < cycle; i++)
  544. cia.phi2 = 1;
  545. };
  546. // Setting up Timer A
  547. cia.RS = 0x04;
  548. cia.DATA = 0x02;
  549. cia.RS = 0x0E;
  550. cia.DATA = 0x11;
  551. // Setting up Timer B
  552. cia.RS = 0x06;
  553. cia.DATA = 0x01;
  554. cia.RS = 0x0F;
  555. cia.DATA = 0x51;
  556. cia.RS = 0x06;
  557. // Verify Timer B Low Byte Value
  558. expect(cia.DATA).to.be.equal(0x01);
  559. tick(1);
  560. // Timer B should not have changed.
  561. expect(cia.DATA).to.be.equal(0x01);
  562. // Timer A should have ticked down by 1.
  563. cia.RS = 0x04;
  564. expect(cia.DATA).to.be.equal(0x01);
  565. tick(1); tick(1);
  566. // Timer A should have underflowed and Timer B ticked down by 1
  567. expect(cia.DATA).to.be.equal(0x02);
  568. cia.RS = 0x06;
  569. expect(cia.DATA).to.be.equal(0x00);
  570. // Check that Timer A triggered interrupt... but Timer B did not!
  571. cia.RS = 0x0D;
  572. let IC = cia.DATA;
  573. expect(IC & 0x01).to.be.equal(0x01);
  574. expect(IC & 0x02).to.be.equal(0x00);
  575. tick(3); // Run through Timer A once more.
  576. // Check that both Timer A & B triggered interrupt!
  577. IC = cia.DATA;
  578. expect(IC & 0x01).to.be.equal(0x01);
  579. expect(IC & 0x02).to.be.equal(0x02);
  580. // Both timers should have latched back to their starting values.
  581. cia.RS = 0x04;
  582. expect(cia.DATA).to.be.equal(0x02);
  583. cia.RS = 0x06;
  584. expect(cia.DATA).to.be.equal(0x01);
  585. });
  586. it("Timer B ticks on Timer A Underflow (CNT Triggered for B only)", function(){
  587. let cia = new MOSCIA();
  588. let tick = (cycle) => {
  589. for (let i=0; i < cycle; i++)
  590. cia.phi2 = 1;
  591. };
  592. // Setup Timer A (trigger on phi2 only)
  593. cia.RS = 0x04;
  594. cia.DATA = 0x02;
  595. cia.RS = 0x0E;
  596. cia.DATA = 0x11;
  597. // Setup Timer B (trigger on A underflow and CNT high)
  598. cia.RS = 0x06;
  599. cia.DATA = 0x01;
  600. cia.RS = 0x0F;
  601. cia.DATA = 0x71;
  602. // Keep CNT low, check that underflowing A *does NOT* tick B.
  603. cia.CNT = 0; // <-- Just to be sure.
  604. tick(2);
  605. // Just make sure we're ticking A
  606. cia.RS = 0x04;
  607. expect(cia.DATA).to.be.equal(0x00);
  608. tick(1);
  609. expect(cia.DATA).to.be.equal(0x02);
  610. // Make sure B did not tick!
  611. cia.RS = 0x06;
  612. expect(cia.DATA).to.be.equal(0x01);
  613. // Clear interrupt flags
  614. cia.RS = 0x0D;
  615. let IC = cia.DATA;
  616. // NOW tick with CNT high!
  617. cia.CNT = 1;
  618. tick(3);
  619. // Checking A rolled over
  620. cia.RS = 0x04;
  621. expect(cia.DATA).to.be.equal(0x02);
  622. // Now checking B ticked...
  623. cia.RS = 0x06;
  624. expect(cia.DATA).to.be.equal(0x00);
  625. // Double check CNT is high
  626. expect(cia.CNT).to.be.equal(1);
  627. // One more A cycle to check B rolls over!
  628. tick(3);
  629. expect(cia.DATA).to.be.equal(0x01);
  630. cia.RS = 0x04;
  631. expect(cia.DATA).to.be.equal(0x02);
  632. });
  633. });