jsbeeb 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (498) hide show
  1. package/.editorconfig +15 -0
  2. package/.git-blame-ignore-revs +3 -0
  3. package/.github/copilot-instructions.md +94 -0
  4. package/.github/workflows/claude-issue-triage.yml +105 -0
  5. package/.github/workflows/claude.yml +63 -0
  6. package/.github/workflows/release-please.yml +75 -0
  7. package/.github/workflows/test-and-deploy.yml +86 -0
  8. package/.gitmodules +6 -0
  9. package/.husky/pre-commit +1 -0
  10. package/.idea/codeStyleSettings.xml +9 -0
  11. package/.idea/codeStyles/Project.xml +62 -0
  12. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  13. package/.idea/compiler.xml +22 -0
  14. package/.idea/copyright/profiles_settings.xml +3 -0
  15. package/.idea/encodings.xml +6 -0
  16. package/.idea/inspectionProfiles/Project_Default.xml +7 -0
  17. package/.idea/jsLibraryMappings.xml +6 -0
  18. package/.idea/jsLinters/jshint.xml +85 -0
  19. package/.idea/jsLinters/jslint.xml +15 -0
  20. package/.idea/jsbeeb.iml +11 -0
  21. package/.idea/misc.xml +6 -0
  22. package/.idea/modules.xml +8 -0
  23. package/.idea/prettier.xml +7 -0
  24. package/.idea/runConfigurations/Debug.xml +5 -0
  25. package/.idea/scopes/scope_settings.xml +5 -0
  26. package/.idea/vcs.xml +8 -0
  27. package/.prettierignore +4 -0
  28. package/.prettierrc.json +1 -0
  29. package/.release-please-manifest.json +3 -0
  30. package/.vscode/launch.json +14 -0
  31. package/.vscode/settings.json +6 -0
  32. package/CHANGELOG.md +32 -0
  33. package/CLAUDE.md +136 -0
  34. package/COPYING +674 -0
  35. package/Dockerfile +22 -0
  36. package/Makefile +30 -0
  37. package/README.md +259 -0
  38. package/docker/nginx-default.conf +10 -0
  39. package/docs/pal-comb-filter-research.md +129 -0
  40. package/docs/pal-simulation-design.md +368 -0
  41. package/eslint.config.js +35 -0
  42. package/index.html +954 -0
  43. package/jsconfig.json +10 -0
  44. package/package.json +102 -0
  45. package/public/discs/README.Irq-Timing +3 -0
  46. package/public/discs/README.bcdtest +5 -0
  47. package/public/discs/README.elite +6 -0
  48. package/public/discs/README.eng_test +3 -0
  49. package/public/discs/README.protection +7 -0
  50. package/public/favicon.ico +0 -0
  51. package/public/images/botbar.png +0 -0
  52. package/public/images/cub-monitor.png +0 -0
  53. package/public/images/jsbeeb-example.png +0 -0
  54. package/public/images/placeholder.png +0 -0
  55. package/public/images/red-off-16.png +0 -0
  56. package/public/images/red-on-16.png +0 -0
  57. package/public/images/sb/CD-left.jpg +0 -0
  58. package/public/images/sb/CD-right.jpg +0 -0
  59. package/public/images/sidebar.png +0 -0
  60. package/public/images/tv.png +0 -0
  61. package/public/images/yellow-off-16.png +0 -0
  62. package/public/images/yellow-on-16.png +0 -0
  63. package/public/jsbeeb-icon.png +0 -0
  64. package/public/robots.txt +3 -0
  65. package/public/roms/ADFS1-53.rom +0 -0
  66. package/public/roms/BASIC.ROM +0 -0
  67. package/public/roms/README +4 -0
  68. package/public/roms/a01/BASIC1.rom +0 -0
  69. package/public/roms/ample.rom +0 -0
  70. package/public/roms/ats-3.0.rom +0 -0
  71. package/public/roms/b/DFS-0.9.rom +0 -0
  72. package/public/roms/b/DFS-1.2.rom +0 -0
  73. package/public/roms/b1770/dfs1770.rom +0 -0
  74. package/public/roms/b1770/zADFS.ROM +0 -0
  75. package/public/roms/bp/dfs.rom +0 -0
  76. package/public/roms/bp/zADFS.ROM +0 -0
  77. package/public/roms/bpos.rom +0 -0
  78. package/public/roms/compact/adfs210.rom +0 -0
  79. package/public/roms/compact/basic48.rom +0 -0
  80. package/public/roms/compact/basic486.rom +0 -0
  81. package/public/roms/compact/os51.rom +0 -0
  82. package/public/roms/compact/utils.rom +0 -0
  83. package/public/roms/deos.rom +0 -0
  84. package/public/roms/master/anfs-4.25.rom +0 -0
  85. package/public/roms/master/mos.txt +68819 -0
  86. package/public/roms/master/mos3.20 +0 -0
  87. package/public/roms/os.rom +0 -0
  88. package/public/roms/os01.rom +0 -0
  89. package/public/roms/tube/6502Tube.rom +0 -0
  90. package/public/roms/tube/ARMeval_100.rom +0 -0
  91. package/public/roms/tube/BIOS.ROM +0 -0
  92. package/public/roms/tube/ReCo6502ROM_816 +0 -0
  93. package/public/roms/tube/Z80_120.rom +0 -0
  94. package/public/roms/us/USBASIC.rom +0 -0
  95. package/public/roms/us/USDNFS.rom +0 -0
  96. package/public/roms/usmos.rom +0 -0
  97. package/public/sounds/disc525/motor.wav +0 -0
  98. package/public/sounds/disc525/motoroff.wav +0 -0
  99. package/public/sounds/disc525/motoron.wav +0 -0
  100. package/public/sounds/disc525/seek.wav +0 -0
  101. package/public/sounds/disc525/seek2.wav +0 -0
  102. package/public/sounds/disc525/seek3.wav +0 -0
  103. package/public/sounds/disc525/step.wav +0 -0
  104. package/public/teletext/txt0.dat +0 -0
  105. package/public/teletext/txt1.dat +0 -0
  106. package/public/teletext/txt2.dat +0 -0
  107. package/public/teletext/txt3.dat +0 -0
  108. package/release-please-config.json +13 -0
  109. package/run-container.sh +92 -0
  110. package/src/6502.js +1347 -0
  111. package/src/6502.opcodes.js +1411 -0
  112. package/src/acia.js +261 -0
  113. package/src/adc.js +149 -0
  114. package/src/analogue-source.js +21 -0
  115. package/src/app/app.js +175 -0
  116. package/src/app/electron.js +20 -0
  117. package/src/app/preload.js +8 -0
  118. package/src/app-bench.js +33 -0
  119. package/src/basic/multiline-tetris +9 -0
  120. package/src/basic-tokenise.js +104 -0
  121. package/src/canvas.js +177 -0
  122. package/src/cmos.js +141 -0
  123. package/src/config.js +165 -0
  124. package/src/ddnoise.js +138 -0
  125. package/src/disc-drive.js +371 -0
  126. package/src/disc-hfe.js +396 -0
  127. package/src/disc.js +997 -0
  128. package/src/econet/L3FS.dat +0 -0
  129. package/src/econet/scsi.dat +0 -0
  130. package/src/econet.js +714 -0
  131. package/src/fake6502.js +32 -0
  132. package/src/fdc.js +248 -0
  133. package/src/filestore.js +666 -0
  134. package/src/gamepad-source.js +59 -0
  135. package/src/gamepads.js +268 -0
  136. package/src/google-drive.js +160 -0
  137. package/src/intel-fdc.js +1717 -0
  138. package/src/jsbeeb.css +363 -0
  139. package/src/keyboard.js +411 -0
  140. package/src/lib/README +1 -0
  141. package/src/lib/webgl-debug.js +911 -0
  142. package/src/main.js +1759 -0
  143. package/src/microphone-input.js +149 -0
  144. package/src/models.js +200 -0
  145. package/src/mouse-joystick-source.js +107 -0
  146. package/src/music5000-worklet.js +43 -0
  147. package/src/music5000.js +207 -0
  148. package/src/scheduler.js +148 -0
  149. package/src/serial.js +31 -0
  150. package/src/soundchip.js +314 -0
  151. package/src/sth.js +59 -0
  152. package/src/tapes.js +265 -0
  153. package/src/teletext.js +348 -0
  154. package/src/teletext_adaptor.js +172 -0
  155. package/src/teletext_data.js +1064 -0
  156. package/src/touchscreen.js +86 -0
  157. package/src/tube.js +349 -0
  158. package/src/url-params.js +256 -0
  159. package/src/utils.js +1090 -0
  160. package/src/via.js +702 -0
  161. package/src/video-filters/pal-composite.js +94 -0
  162. package/src/video-filters/passthrough-filter.js +70 -0
  163. package/src/video-filters/shaders/pal-composite.frag.glsl +147 -0
  164. package/src/video-filters/shaders/pal-composite.vert.glsl +8 -0
  165. package/src/video-filters/shaders/passthrough.frag.glsl +6 -0
  166. package/src/video-filters/shaders/passthrough.vert.glsl +7 -0
  167. package/src/video.js +794 -0
  168. package/src/wd-fdc.js +1344 -0
  169. package/src/web/audio-handler.js +146 -0
  170. package/src/web/audio-renderer.js +115 -0
  171. package/src/web/debug.js +529 -0
  172. package/tests/integration/RmwX.asm +47 -0
  173. package/tests/integration/TestInstructionsSource +27 -0
  174. package/tests/integration/TestTimingsResults +27 -0
  175. package/tests/integration/TestTimingsSource +61 -0
  176. package/tests/integration/bcd.js +23 -0
  177. package/tests/integration/dormann.js +101 -0
  178. package/tests/integration/dp111timing.js +42 -0
  179. package/tests/integration/ensure-submodules.js +25 -0
  180. package/tests/integration/nops.bas +119 -0
  181. package/tests/integration/nops.js +24 -0
  182. package/tests/integration/protection.js +26 -0
  183. package/tests/integration/rmw.js +69 -0
  184. package/tests/integration/teletext/expected_bug_469.png +0 -0
  185. package/tests/integration/teletext/expected_flash_0.png +0 -0
  186. package/tests/integration/teletext/expected_flash_1.png +0 -0
  187. package/tests/integration/teletext/expected_hoglet_held_char.png +0 -0
  188. package/tests/integration/teletext/expected_reveal_flash_0.png +0 -0
  189. package/tests/integration/teletext/expected_reveal_flash_1.png +0 -0
  190. package/tests/integration/teletext.js +126 -0
  191. package/tests/integration/timings.js +56 -0
  192. package/tests/integration/via.js +1125 -0
  193. package/tests/suite/README.md +7 -0
  194. package/tests/suite/Test Suite 2.15.txt +373 -0
  195. package/tests/suite/bin/ start +0 -0
  196. package/tests/suite/bin/adca +0 -0
  197. package/tests/suite/bin/adcax +0 -0
  198. package/tests/suite/bin/adcay +0 -0
  199. package/tests/suite/bin/adcb +0 -0
  200. package/tests/suite/bin/adcix +0 -0
  201. package/tests/suite/bin/adciy +0 -0
  202. package/tests/suite/bin/adcz +0 -0
  203. package/tests/suite/bin/adczx +0 -0
  204. package/tests/suite/bin/alrb +0 -0
  205. package/tests/suite/bin/ancb +0 -0
  206. package/tests/suite/bin/anda +0 -0
  207. package/tests/suite/bin/andax +0 -0
  208. package/tests/suite/bin/anday +0 -0
  209. package/tests/suite/bin/andb +0 -0
  210. package/tests/suite/bin/andix +0 -0
  211. package/tests/suite/bin/andiy +0 -0
  212. package/tests/suite/bin/andz +0 -0
  213. package/tests/suite/bin/andzx +0 -0
  214. package/tests/suite/bin/aneb +0 -0
  215. package/tests/suite/bin/arrb +0 -0
  216. package/tests/suite/bin/asla +0 -0
  217. package/tests/suite/bin/aslax +0 -0
  218. package/tests/suite/bin/asln +0 -0
  219. package/tests/suite/bin/aslz +0 -0
  220. package/tests/suite/bin/aslzx +0 -0
  221. package/tests/suite/bin/asoa +0 -0
  222. package/tests/suite/bin/asoax +0 -0
  223. package/tests/suite/bin/asoay +0 -0
  224. package/tests/suite/bin/asoix +0 -0
  225. package/tests/suite/bin/asoiy +0 -0
  226. package/tests/suite/bin/asoz +0 -0
  227. package/tests/suite/bin/asozx +0 -0
  228. package/tests/suite/bin/axsa +0 -0
  229. package/tests/suite/bin/axsix +0 -0
  230. package/tests/suite/bin/axsz +0 -0
  231. package/tests/suite/bin/axszy +0 -0
  232. package/tests/suite/bin/bccr +0 -0
  233. package/tests/suite/bin/bcsr +0 -0
  234. package/tests/suite/bin/beqr +0 -0
  235. package/tests/suite/bin/bita +0 -0
  236. package/tests/suite/bin/bitz +0 -0
  237. package/tests/suite/bin/bmir +0 -0
  238. package/tests/suite/bin/bner +0 -0
  239. package/tests/suite/bin/bplr +0 -0
  240. package/tests/suite/bin/branchwrap +0 -0
  241. package/tests/suite/bin/brkn +0 -0
  242. package/tests/suite/bin/bvcr +0 -0
  243. package/tests/suite/bin/bvsr +0 -0
  244. package/tests/suite/bin/cia1pb6 +0 -0
  245. package/tests/suite/bin/cia1pb7 +0 -0
  246. package/tests/suite/bin/cia1ta +0 -0
  247. package/tests/suite/bin/cia1tab +0 -0
  248. package/tests/suite/bin/cia1tb +0 -0
  249. package/tests/suite/bin/cia1tb123 +0 -0
  250. package/tests/suite/bin/cia2pb6 +0 -0
  251. package/tests/suite/bin/cia2pb7 +0 -0
  252. package/tests/suite/bin/cia2ta +0 -0
  253. package/tests/suite/bin/cia2tb +0 -0
  254. package/tests/suite/bin/cia2tb123 +0 -0
  255. package/tests/suite/bin/clcn +0 -0
  256. package/tests/suite/bin/cldn +0 -0
  257. package/tests/suite/bin/clin +0 -0
  258. package/tests/suite/bin/clvn +0 -0
  259. package/tests/suite/bin/cmpa +0 -0
  260. package/tests/suite/bin/cmpax +0 -0
  261. package/tests/suite/bin/cmpay +0 -0
  262. package/tests/suite/bin/cmpb +0 -0
  263. package/tests/suite/bin/cmpix +0 -0
  264. package/tests/suite/bin/cmpiy +0 -0
  265. package/tests/suite/bin/cmpz +0 -0
  266. package/tests/suite/bin/cmpzx +0 -0
  267. package/tests/suite/bin/cntdef +0 -0
  268. package/tests/suite/bin/cnto2 +0 -0
  269. package/tests/suite/bin/cpuport +0 -0
  270. package/tests/suite/bin/cputiming +0 -0
  271. package/tests/suite/bin/cpxa +0 -0
  272. package/tests/suite/bin/cpxb +0 -0
  273. package/tests/suite/bin/cpxz +0 -0
  274. package/tests/suite/bin/cpya +0 -0
  275. package/tests/suite/bin/cpyb +0 -0
  276. package/tests/suite/bin/cpyz +0 -0
  277. package/tests/suite/bin/dcma +0 -0
  278. package/tests/suite/bin/dcmax +0 -0
  279. package/tests/suite/bin/dcmay +0 -0
  280. package/tests/suite/bin/dcmix +0 -0
  281. package/tests/suite/bin/dcmiy +0 -0
  282. package/tests/suite/bin/dcmz +0 -0
  283. package/tests/suite/bin/dcmzx +0 -0
  284. package/tests/suite/bin/deca +0 -0
  285. package/tests/suite/bin/decax +0 -0
  286. package/tests/suite/bin/decz +0 -0
  287. package/tests/suite/bin/deczx +0 -0
  288. package/tests/suite/bin/dexn +0 -0
  289. package/tests/suite/bin/deyn +0 -0
  290. package/tests/suite/bin/eora +0 -0
  291. package/tests/suite/bin/eorax +0 -0
  292. package/tests/suite/bin/eoray +0 -0
  293. package/tests/suite/bin/eorb +0 -0
  294. package/tests/suite/bin/eorix +0 -0
  295. package/tests/suite/bin/eoriy +0 -0
  296. package/tests/suite/bin/eorz +0 -0
  297. package/tests/suite/bin/eorzx +0 -0
  298. package/tests/suite/bin/finish +0 -0
  299. package/tests/suite/bin/flipos +0 -0
  300. package/tests/suite/bin/icr01 +0 -0
  301. package/tests/suite/bin/imr +0 -0
  302. package/tests/suite/bin/inca +0 -0
  303. package/tests/suite/bin/incax +0 -0
  304. package/tests/suite/bin/incz +0 -0
  305. package/tests/suite/bin/inczx +0 -0
  306. package/tests/suite/bin/insa +0 -0
  307. package/tests/suite/bin/insax +0 -0
  308. package/tests/suite/bin/insay +0 -0
  309. package/tests/suite/bin/insix +0 -0
  310. package/tests/suite/bin/insiy +0 -0
  311. package/tests/suite/bin/insz +0 -0
  312. package/tests/suite/bin/inszx +0 -0
  313. package/tests/suite/bin/inxn +0 -0
  314. package/tests/suite/bin/inyn +0 -0
  315. package/tests/suite/bin/irq +0 -0
  316. package/tests/suite/bin/jmpi +0 -0
  317. package/tests/suite/bin/jmpw +0 -0
  318. package/tests/suite/bin/jsrw +0 -0
  319. package/tests/suite/bin/lasay +0 -0
  320. package/tests/suite/bin/laxa +0 -0
  321. package/tests/suite/bin/laxay +0 -0
  322. package/tests/suite/bin/laxix +0 -0
  323. package/tests/suite/bin/laxiy +0 -0
  324. package/tests/suite/bin/laxz +0 -0
  325. package/tests/suite/bin/laxzy +0 -0
  326. package/tests/suite/bin/ldaa +0 -0
  327. package/tests/suite/bin/ldaax +0 -0
  328. package/tests/suite/bin/ldaay +0 -0
  329. package/tests/suite/bin/ldab +0 -0
  330. package/tests/suite/bin/ldaix +0 -0
  331. package/tests/suite/bin/ldaiy +0 -0
  332. package/tests/suite/bin/ldaz +0 -0
  333. package/tests/suite/bin/ldazx +0 -0
  334. package/tests/suite/bin/ldxa +0 -0
  335. package/tests/suite/bin/ldxay +0 -0
  336. package/tests/suite/bin/ldxb +0 -0
  337. package/tests/suite/bin/ldxz +0 -0
  338. package/tests/suite/bin/ldxzy +0 -0
  339. package/tests/suite/bin/ldya +0 -0
  340. package/tests/suite/bin/ldyax +0 -0
  341. package/tests/suite/bin/ldyb +0 -0
  342. package/tests/suite/bin/ldyz +0 -0
  343. package/tests/suite/bin/ldyzx +0 -0
  344. package/tests/suite/bin/loadth +0 -0
  345. package/tests/suite/bin/lsea +0 -0
  346. package/tests/suite/bin/lseax +0 -0
  347. package/tests/suite/bin/lseay +0 -0
  348. package/tests/suite/bin/lseix +0 -0
  349. package/tests/suite/bin/lseiy +0 -0
  350. package/tests/suite/bin/lsez +0 -0
  351. package/tests/suite/bin/lsezx +0 -0
  352. package/tests/suite/bin/lsra +0 -0
  353. package/tests/suite/bin/lsrax +0 -0
  354. package/tests/suite/bin/lsrn +0 -0
  355. package/tests/suite/bin/lsrz +0 -0
  356. package/tests/suite/bin/lsrzx +0 -0
  357. package/tests/suite/bin/lxab +0 -0
  358. package/tests/suite/bin/mmu +0 -0
  359. package/tests/suite/bin/mmufetch +0 -0
  360. package/tests/suite/bin/nmi +0 -0
  361. package/tests/suite/bin/nopa +0 -0
  362. package/tests/suite/bin/nopax +0 -0
  363. package/tests/suite/bin/nopb +0 -0
  364. package/tests/suite/bin/nopn +0 -0
  365. package/tests/suite/bin/nopz +0 -0
  366. package/tests/suite/bin/nopzx +0 -0
  367. package/tests/suite/bin/oneshot +0 -0
  368. package/tests/suite/bin/oraa +0 -0
  369. package/tests/suite/bin/oraax +0 -0
  370. package/tests/suite/bin/oraay +0 -0
  371. package/tests/suite/bin/orab +0 -0
  372. package/tests/suite/bin/oraix +0 -0
  373. package/tests/suite/bin/oraiy +0 -0
  374. package/tests/suite/bin/oraz +0 -0
  375. package/tests/suite/bin/orazx +0 -0
  376. package/tests/suite/bin/phan +0 -0
  377. package/tests/suite/bin/phpn +0 -0
  378. package/tests/suite/bin/plan +0 -0
  379. package/tests/suite/bin/plpn +0 -0
  380. package/tests/suite/bin/rlaa +0 -0
  381. package/tests/suite/bin/rlaax +0 -0
  382. package/tests/suite/bin/rlaay +0 -0
  383. package/tests/suite/bin/rlaix +0 -0
  384. package/tests/suite/bin/rlaiy +0 -0
  385. package/tests/suite/bin/rlaz +0 -0
  386. package/tests/suite/bin/rlazx +0 -0
  387. package/tests/suite/bin/rola +0 -0
  388. package/tests/suite/bin/rolax +0 -0
  389. package/tests/suite/bin/roln +0 -0
  390. package/tests/suite/bin/rolz +0 -0
  391. package/tests/suite/bin/rolzx +0 -0
  392. package/tests/suite/bin/rora +0 -0
  393. package/tests/suite/bin/rorax +0 -0
  394. package/tests/suite/bin/rorn +0 -0
  395. package/tests/suite/bin/rorz +0 -0
  396. package/tests/suite/bin/rorzx +0 -0
  397. package/tests/suite/bin/rraa +0 -0
  398. package/tests/suite/bin/rraax +0 -0
  399. package/tests/suite/bin/rraay +0 -0
  400. package/tests/suite/bin/rraix +0 -0
  401. package/tests/suite/bin/rraiy +0 -0
  402. package/tests/suite/bin/rraz +0 -0
  403. package/tests/suite/bin/rrazx +0 -0
  404. package/tests/suite/bin/rtin +0 -0
  405. package/tests/suite/bin/rtsn +0 -0
  406. package/tests/suite/bin/sbca +0 -0
  407. package/tests/suite/bin/sbcax +0 -0
  408. package/tests/suite/bin/sbcay +0 -0
  409. package/tests/suite/bin/sbcb +0 -0
  410. package/tests/suite/bin/sbcb(eb) +0 -0
  411. package/tests/suite/bin/sbcix +0 -0
  412. package/tests/suite/bin/sbciy +0 -0
  413. package/tests/suite/bin/sbcz +0 -0
  414. package/tests/suite/bin/sbczx +0 -0
  415. package/tests/suite/bin/sbxb +0 -0
  416. package/tests/suite/bin/secn +0 -0
  417. package/tests/suite/bin/sedn +0 -0
  418. package/tests/suite/bin/sein +0 -0
  419. package/tests/suite/bin/shaay +0 -0
  420. package/tests/suite/bin/shaiy +0 -0
  421. package/tests/suite/bin/shsay +0 -0
  422. package/tests/suite/bin/shxay +0 -0
  423. package/tests/suite/bin/shyax +0 -0
  424. package/tests/suite/bin/staa +0 -0
  425. package/tests/suite/bin/staax +0 -0
  426. package/tests/suite/bin/staay +0 -0
  427. package/tests/suite/bin/staix +0 -0
  428. package/tests/suite/bin/staiy +0 -0
  429. package/tests/suite/bin/staz +0 -0
  430. package/tests/suite/bin/stazx +0 -0
  431. package/tests/suite/bin/stxa +0 -0
  432. package/tests/suite/bin/stxz +0 -0
  433. package/tests/suite/bin/stxzy +0 -0
  434. package/tests/suite/bin/stya +0 -0
  435. package/tests/suite/bin/styz +0 -0
  436. package/tests/suite/bin/styzx +0 -0
  437. package/tests/suite/bin/taxn +0 -0
  438. package/tests/suite/bin/tayn +0 -0
  439. package/tests/suite/bin/trap1 +0 -0
  440. package/tests/suite/bin/trap10 +0 -0
  441. package/tests/suite/bin/trap11 +0 -0
  442. package/tests/suite/bin/trap12 +0 -0
  443. package/tests/suite/bin/trap13 +0 -0
  444. package/tests/suite/bin/trap14 +0 -0
  445. package/tests/suite/bin/trap15 +0 -0
  446. package/tests/suite/bin/trap16 +0 -0
  447. package/tests/suite/bin/trap17 +0 -0
  448. package/tests/suite/bin/trap2 +0 -0
  449. package/tests/suite/bin/trap3 +0 -0
  450. package/tests/suite/bin/trap4 +0 -0
  451. package/tests/suite/bin/trap5 +0 -0
  452. package/tests/suite/bin/trap6 +0 -0
  453. package/tests/suite/bin/trap7 +0 -0
  454. package/tests/suite/bin/trap8 +0 -0
  455. package/tests/suite/bin/trap9 +0 -0
  456. package/tests/suite/bin/tsxn +0 -0
  457. package/tests/suite/bin/txan +0 -0
  458. package/tests/suite/bin/txsn +0 -0
  459. package/tests/suite/bin/tyan +0 -0
  460. package/tests/suite/cbm-hackers-post.html +178 -0
  461. package/tests/suite/cbm-hackers-post.md +78 -0
  462. package/tests/test-machine.js +288 -0
  463. package/tests/test-suite.js +147 -0
  464. package/tests/test.css +7 -0
  465. package/tests/unit/gzip/test-1 +0 -0
  466. package/tests/unit/gzip/test-1.gz +0 -0
  467. package/tests/unit/gzip/test-2 +0 -0
  468. package/tests/unit/gzip/test-2.gz +0 -0
  469. package/tests/unit/gzip/test-3 +0 -0
  470. package/tests/unit/gzip/test-3.gz +0 -0
  471. package/tests/unit/gzip/test-4 +0 -0
  472. package/tests/unit/gzip/test-4.gz +0 -0
  473. package/tests/unit/test-adc.js +307 -0
  474. package/tests/unit/test-bcd.js +30 -0
  475. package/tests/unit/test-cmos.js +266 -0
  476. package/tests/unit/test-disc-drive.js +85 -0
  477. package/tests/unit/test-disc-hfe.js +347 -0
  478. package/tests/unit/test-disc.js +232 -0
  479. package/tests/unit/test-fifo.js +35 -0
  480. package/tests/unit/test-gamepad-source.js +67 -0
  481. package/tests/unit/test-gzip.js +22 -0
  482. package/tests/unit/test-intel-fdc.js +93 -0
  483. package/tests/unit/test-keyboard.js +410 -0
  484. package/tests/unit/test-mouse-joystick-source.js +128 -0
  485. package/tests/unit/test-scheduler.js +190 -0
  486. package/tests/unit/test-serial.js +154 -0
  487. package/tests/unit/test-teletext-adaptor.js +359 -0
  488. package/tests/unit/test-tokenise.js +65 -0
  489. package/tests/unit/test-url-params.js +398 -0
  490. package/tests/unit/test-utils.js +276 -0
  491. package/tests/unit/test-video.js +498 -0
  492. package/tests/unit/test-zip.js +56 -0
  493. package/tests/unit/zip/test-mixed.zip +0 -0
  494. package/tests/unit/zip/test-rom.zip +0 -0
  495. package/tests/unit/zip/test-ssd.zip +0 -0
  496. package/tools/fir-generator.js +80 -0
  497. package/tools/vite-plugin-fir-shader.js +131 -0
  498. package/vite.config.js +34 -0
@@ -0,0 +1,23 @@
1
+ import { describe, it } from "vitest";
2
+ import { TestMachine } from "../test-machine.js";
3
+ import assert from "assert";
4
+
5
+ describe("test binary coded decimal behaviour", { timeout: 30000 }, function () {
6
+ const doTest = async (model) => {
7
+ const testMachine = new TestMachine(model);
8
+ await testMachine.initialise();
9
+ await testMachine.loadDisc("discs/bcdtest.ssd");
10
+ await testMachine.runUntilInput();
11
+ await testMachine.type("*BCDTEST");
12
+ let output = "";
13
+ testMachine.captureText((elem) => (output += elem.text));
14
+ await testMachine.runUntilInput();
15
+ assert(output.indexOf("PASSED") >= 0, `Failed with ${output}`);
16
+ };
17
+ it("should match on 65C12", async () => {
18
+ await doTest("Master");
19
+ });
20
+ it("should match on 6502", async () => {
21
+ await doTest();
22
+ });
23
+ });
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+
3
+ import _ from "underscore";
4
+ import { describe, it } from "vitest";
5
+ import * as utils from "../../src/utils.js";
6
+ import { fake6502, fake65C02, fake65C12 } from "../../src/fake6502.js";
7
+
8
+ import assert from "assert";
9
+
10
+ const log = false;
11
+
12
+ async function runTest(processor, test, name) {
13
+ const base = "tests/6502_65C02_functional_tests/bin_files/" + test;
14
+
15
+ function parseSuccess(listing) {
16
+ let expectedPc = null;
17
+ let next = false;
18
+ let successRe = /^\s*success\b\s*(;.*)?$/;
19
+ _.each(listing.split("\n"), function (line) {
20
+ if (next) {
21
+ next = false;
22
+ expectedPc = parseInt(line.match(/^([0-9a-fA-F]+)/)[1], 16);
23
+ console.log("Found success address $" + utils.hexword(expectedPc));
24
+ } else {
25
+ next = !!line.match(successRe);
26
+ }
27
+ });
28
+ if (expectedPc === null) throw "Unable to parse";
29
+ return expectedPc;
30
+ }
31
+
32
+ const expectedPc = parseSuccess((await utils.loadData(base + ".lst")).toString());
33
+ const data = await utils.loadData(base + ".bin");
34
+ for (let i = 0; i < data.length; ++i) processor.writemem(i, data[i]);
35
+
36
+ processor.pc = 0x400;
37
+ processor.debugInstruction.add(function (addr) {
38
+ if (log) {
39
+ console.log(
40
+ utils.hexword(addr) +
41
+ " : A=" +
42
+ utils.hexbyte(processor.a) +
43
+ " : X=" +
44
+ utils.hexbyte(processor.x) +
45
+ " : Y=" +
46
+ utils.hexbyte(processor.y) +
47
+ " : " +
48
+ processor.disassembler.disassemble(processor.pc)[0],
49
+ );
50
+ }
51
+
52
+ // Stop once we get stuck at the same address.
53
+ return addr === processor.getPrevPc(1);
54
+ });
55
+ console.log("Running Dormann " + name + " tests...");
56
+ processor.execute(2000000 * 60);
57
+ console.log(`Run complete at $${utils.hexword(processor.pc)}`);
58
+ const result = processor.pc === expectedPc;
59
+ if (!result) logFailure(processor);
60
+ return result;
61
+ }
62
+
63
+ function logFailure(processor) {
64
+ console.log("Failed at " + utils.hexword(processor.pc));
65
+ console.log("Previous PCs:");
66
+ for (let i = 1; i < 16; ++i) {
67
+ console.log(" " + utils.hexword(processor.getPrevPc(i)));
68
+ }
69
+ console.log("A: " + utils.hexbyte(processor.a));
70
+ console.log("X: " + utils.hexbyte(processor.x));
71
+ console.log("Y: " + utils.hexbyte(processor.y));
72
+ console.log("S: " + utils.hexbyte(processor.s));
73
+ console.log("P: " + utils.hexbyte(processor.p.asByte()) + " " + processor.p.debugString());
74
+ console.log(
75
+ utils.hd(
76
+ function (i) {
77
+ return processor.readmem(i);
78
+ },
79
+ 0x00,
80
+ 0x40,
81
+ ),
82
+ );
83
+ }
84
+
85
+ describe("dormann tests", { timeout: 30000 }, function () {
86
+ it("should pass 6502 functional tests", async () => {
87
+ const cpu = fake6502();
88
+ await cpu.initialise();
89
+ assert(await runTest(cpu, "6502_functional_test", "6502"));
90
+ });
91
+ it("should pass 65c02 extended opcode tests", async () => {
92
+ const cpu = fake65C02();
93
+ await cpu.initialise();
94
+ assert(await runTest(cpu, "65C02_extended_opcodes_test", "65C02"));
95
+ });
96
+ it("should pass 65c12 extended opcode tests", async () => {
97
+ const cpu = fake65C12();
98
+ await cpu.initialise();
99
+ assert(await runTest(cpu, "65C12_extended_opcodes_test", "65C12"));
100
+ });
101
+ });
@@ -0,0 +1,42 @@
1
+ import { describe, it } from "vitest";
2
+ import { TestMachine } from "../test-machine.js";
3
+ import assert from "assert";
4
+
5
+ describe("test dp111's timing tests", { timeout: 30000 }, function () {
6
+ const doTest = async (disc, machine) => {
7
+ const testMachine = new TestMachine(machine);
8
+ await testMachine.initialise();
9
+ await testMachine.loadDisc(`tests/integration/dp111_6502Timing/${disc}.ssd`);
10
+ await testMachine.runUntilInput();
11
+ let output = "";
12
+ testMachine.captureText((elem) => {
13
+ output += `${elem.text}\n`;
14
+ });
15
+ await testMachine.type("*RUN 6502TIM");
16
+ let numFailedTests = null;
17
+ const hook = testMachine.processor.debugWrite.add((addr, value) => {
18
+ if (addr === 0xfcd0) {
19
+ numFailedTests = value;
20
+ }
21
+ });
22
+ await testMachine.runUntilInput();
23
+ hook.remove();
24
+ if (numFailedTests) {
25
+ console.log(`Test failed, output:\n${output}`);
26
+ }
27
+ assert.equal(numFailedTests, 0);
28
+ };
29
+ it("should handle 6502timing", async () => {
30
+ await doTest("6502timing");
31
+ });
32
+ it("should handle 6502timing with 1MHz bus", async () => {
33
+ await doTest("6502timing1M");
34
+ });
35
+
36
+ it("should handle 65C12timing", async () => {
37
+ await doTest("65C12timing", "Master");
38
+ });
39
+ it("should handle 65C12timing with 1MHz bus", async () => {
40
+ await doTest("65C12timing1M", "Master");
41
+ });
42
+ });
@@ -0,0 +1,25 @@
1
+ import { describe, it } from "vitest";
2
+ import assert from "assert";
3
+ import * as fs from "fs";
4
+
5
+ describe("ensure git submodules are present", function () {
6
+ it("should have functional tests", function () {
7
+ try {
8
+ fs.accessSync("tests/6502_65C02_functional_tests/README.md");
9
+ } catch {
10
+ assert.fail(
11
+ "Functional tests submodule missing. Ensure git submodules are fetched (git submodule update --init).",
12
+ );
13
+ }
14
+ });
15
+
16
+ it("should have timing tests", function () {
17
+ try {
18
+ fs.accessSync("tests/integration/dp111_6502Timing/README.md");
19
+ } catch {
20
+ assert.fail(
21
+ "Timing tests submodule missing. Ensure git submodules are fetched (git submodule update --init).",
22
+ );
23
+ }
24
+ });
25
+ });
@@ -0,0 +1,119 @@
1
+ 1REM Thanks to Tom Seddon!
2
+ 10REM>NOPS
3
+ 20MODE1
4
+ 30PRINX%=0:PRINY%=0:COLWIDTH%=0
5
+ 40CODESIZE%=1000:DIMCODE%CODESIZE%
6
+ 50:
7
+ 60FORPASS%=0TO2STEP2:P%=CODE%:[OPTPASS%
8
+ 70LDA&60:PHA
9
+ 80LDA#0:STA&60
10
+ 90JSRSMBTEST
11
+ 100LDA&60:STA&70
12
+ 110PLA:STA&60
13
+ 120RTS
14
+ 130:
15
+ 140.SMBTEST
16
+ 150EQUB&87:EQUB&60:\SMB0 &60
17
+ 160RTS
18
+ 170]
19
+ 180NEXT
20
+ 190CALLCODE%
21
+ 200ROCKWELL%=?&70<>0
22
+ 210IFROCKWELL%:PROCPRINT(3,0,"ROCKWELL/WDC CPU"):ELSE:PROCPRINT(3,0,"CMOS CPU")
23
+ 220PROCPRINT(0,1,"2 CYCLES")
24
+ 230T2C%=FNTIME(1,&EA,1,-1)
25
+ 240PROCPRINT(0,1,"3 CYCLES")
26
+ 250T3C%=FNTIME(1,&A5,2,-1)
27
+ 260PROCPRINT(0,1,"4 CYCLES")
28
+ 270T4C%=FNTIME(1,&AD,3,-1)
29
+ 271PROCPRINT(0,1,"8 CYCLES")
30
+ 272T8C%=FNTIME(2,&AD,3,-1)
31
+ 273PROCPRINT(0,1,"1 CYCLES")
32
+ 274T1C%=T2C%-INT(((T3C%-T2C%)+(T4C%-T2C%)/2+(T8C%-T2C%)/6)/3)
33
+ 275PROCPRINT(0,3,"GUESS: "+STR$T1C%)
34
+ 280RESTORE560:PROCMULTI(T2C%,2,2)
35
+ 290RESTORE580:PROCMULTI(T3C%,3,2)
36
+ 300RESTORE620:PROCMULTI(T4C%,4,2)
37
+ 310RESTORE680:PROCMULTI(T8C%,8,3)
38
+ 320RESTORE410:PROCMULTI(-1,1,1)
39
+ 330IFNOTROCKWELL%:RESTORE440:PROCMULTI(-1,1,1)
40
+ 340RESTORE470:PROCMULTI(-1,1,1)
41
+ 350IFNOTROCKWELL%:RESTORE500:PROCMULTI(-1,1,1)
42
+ 360IFNOTROCKWELL%:RESTORE530:PROCMULTI(-1,1,1)
43
+ 370END
44
+ 380:
45
+ 390:
46
+ 400REM 1 CYCLES, 1 BYTES
47
+ 410DATA &03,&13,&23,&33,&43,&53,&63,&73,&83,&93,&A3,&B3,&C3,&D3,&E3,&F3,-1
48
+ 420:
49
+ 430REM 1 CYCLES, 1 BYTES (NOT ROCKWELL)
50
+ 440DATA &07,&17,&27,&37,&47,&57,&67,&77,&87,&97,&A7,&B7,&C7,&D7,&E7,&F7,-1
51
+ 450:
52
+ 460REM 1 CYCLES, 1 BYTES
53
+ 470DATA &0B,&1B,&2B,&3B,&4B,&5B,&6B,&7B,&8B,&9B,&AB,&BB,&EB,&FB,-1
54
+ 480:
55
+ 490REM 1 CYCLES, 1 BYTES (NOT WDC)
56
+ 500DATA &CB,&DB,-1
57
+ 510:
58
+ 520REM 1 CYCLES, 1 BYTES (NOT ROCKWELL)
59
+ 530DATA &0F,&1F,&2F,&3F,&4F,&5F,&6F,&7F,&8F,&9F,&AF,&BF,&CF,&DF,&EF,&FF,-1
60
+ 540:
61
+ 550REM 2 CYCLES, 2 BYTES
62
+ 560DATA &02,&22,&42,&62,&82,&C2,&E2,-1
63
+ 570:
64
+ 580REM 3 CYCLES, 2 BYTES
65
+ 590DATA &44,-1
66
+ 600:
67
+ 610REM 4 CYCLES, 2 BYTES
68
+ 620DATA &54,&D4,&F4,-1
69
+ 630:
70
+ 640REM 4 CYCLES, 3 BYTES
71
+ 650DATA &DC,&FC,-1
72
+ 660:
73
+ 670REM 8 CYCLES, 3 BYTES
74
+ 680DATA &5C,-1
75
+ 690:
76
+ 700DEFPROCMULTI(TEXPECTED%,NC%,NB%)
77
+ 710PROCPRINT(0,2,STR$NC%+" CYCLES")
78
+ 720REPEAT
79
+ 730READNOP%:IFNOP%=-1:GOTO750
80
+ 740T%=FNTIME(1,NOP%,NB%,TEXPECTED%)
81
+ 750UNTILNOP%=-1
82
+ 760ENDPROC
83
+ 770:
84
+ 780DEFFNTIME(NCOPIES%,NOP%,N%,TEXPECTED%)
85
+ 790IFN%<1ORN%>3:STOP
86
+ 800FORPASS%=0TO2STEP2:P%=CODE%:[OPTPASS%
87
+ 810.START
88
+ 820LDX#0
89
+ 830.XLOOP
90
+ 840LDY#0
91
+ 850.YLOOP
92
+ 860]
93
+ 870FORI%=1TONCOPIES%*10
94
+ 880[OPTPASS%:EQUBNOP%:]
95
+ 890IFN%>=2:[OPTPASS%:EQUB0:]
96
+ 900IFN%>=3:[OPTPASS%:EQUB0:]
97
+ 910NEXT
98
+ 920[OPTPASS%
99
+ 930DEY:BNEYLOOP
100
+ 940DEX:BNEXLOOP
101
+ 950RTS
102
+ 960]IFP%>CODE%+CODESIZE%:STOP
103
+ 970NEXT
104
+ 980TIME=0
105
+ 990REMPRINTFNHEX2(NOP%)" (";N%"): ";
106
+ 1000CALLSTART
107
+ 1010T%=TIME
108
+ 1020IFTEXPECTED%>=0ANDABS(TIME-TEXPECTED%)>2:B%=1:ELSE:B%=0
109
+ 1030PROCPRINT(B%,3,FNHEX2(NOP%)+" ("+STR$N%+"): "+STR$T%)
110
+ 1040=T%
111
+ 1050DEFFNHEX2(X%)=RIGHT$("0"+STR$~X%,2)
112
+ 1060DEFPROCPRINT(B%,F%,MSG$)
113
+ 1070COLOUR128+B%:COLOURF%
114
+ 1080PRINTTAB(PRINX%,PRINY%);MSG$;
115
+ 1090COLOUR128:COLOUR7
116
+ 1100IFLENMSG$>COLWIDTH%:COLWIDTH%=LENMSG$
117
+ 1110PRINY%=PRINY%+1
118
+ 1120IFPRINY%=32:PRINY%=0:PRINX%=PRINX%+COLWIDTH%+1:COLWIDTH%=0
119
+ 1130ENDPROC
@@ -0,0 +1,24 @@
1
+ import { describe, it } from "vitest";
2
+ import assert from "assert";
3
+ import * as utils from "../../src/utils.js";
4
+ import { TestMachine } from "../test-machine.js";
5
+
6
+ describe("test various NOP timings", { timeout: 30000 }, function () {
7
+ it("should match the nops.bas code", async () => {
8
+ const testMachine = new TestMachine("Master");
9
+ await testMachine.initialise();
10
+ await testMachine.runUntilInput();
11
+ const data = await utils.loadData("tests/integration/nops.bas");
12
+ await testMachine.loadBasic(utils.uint8ArrayToString(data));
13
+
14
+ let numCaptures = 0;
15
+ testMachine.captureText((elem) => {
16
+ assert(elem.background !== 1, `Failure from test - ${JSON.stringify(elem)}`);
17
+ console.log(`emulator output: ${elem.text}`);
18
+ numCaptures++;
19
+ });
20
+ await testMachine.type("RUN");
21
+ await testMachine.runUntilInput(2 * 60);
22
+ assert(numCaptures === 97, "Missing output");
23
+ });
24
+ });
@@ -0,0 +1,26 @@
1
+ import { describe, it } from "vitest";
2
+ import { TestMachine } from "../test-machine.js";
3
+
4
+ describe("test Kevin Edwards' gnarly protection system", { timeout: 10000 }, function () {
5
+ const doTest = async (name) => {
6
+ const testMachine = new TestMachine();
7
+ await testMachine.initialise();
8
+ await testMachine.loadDisc("discs/Protection.ssd");
9
+ await testMachine.runUntilInput();
10
+ await testMachine.type(`CHAIN "B.${name}"`);
11
+ const hook = testMachine.processor.debugInstruction.add((addr) => {
12
+ return addr === 0xfff4 && testMachine.processor.a === 200 && testMachine.processor.x === 3;
13
+ });
14
+ await testMachine.runUntilAddress(0xe00, 20);
15
+ hook.remove();
16
+ };
17
+ it("should decode Alien8", async () => {
18
+ await doTest("ALIEN8");
19
+ });
20
+ it("should decode Nightshade", async () => {
21
+ await doTest("NIGHTSH");
22
+ });
23
+ it("should decode Lunar Jetman", async () => {
24
+ await doTest("JETMAN");
25
+ });
26
+ });
@@ -0,0 +1,69 @@
1
+ import * as utils from "../../src/utils.js";
2
+ import { describe, it } from "vitest";
3
+ import { TestMachine } from "../test-machine.js";
4
+ import assert from "assert";
5
+
6
+ describe("test read-modify-write behaviour", function () {
7
+ const doTest = async (model) => {
8
+ const testMachine = new TestMachine(model);
9
+ await testMachine.initialise();
10
+ await testMachine.loadDisc("discs/RmwX.ssd");
11
+ await testMachine.runUntilInput();
12
+ await testMachine.type("*TIMINGS");
13
+ await testMachine.runUntilInput();
14
+ let result = "";
15
+ for (let i = 0x100; i < 0x110; i += 4) {
16
+ if (i !== 0x100) result += " ";
17
+ for (let j = 3; j >= 0; --j) {
18
+ result += utils.hexbyte(testMachine.readbyte(i + j));
19
+ }
20
+ }
21
+ return result;
22
+ };
23
+ it("should match on 65C12", async () => {
24
+ const result = await doTest("Master");
25
+ assert.strictEqual(result, "f4ff0a16 eaeadee9 f2fe0a16 c3ced9e5");
26
+ });
27
+ it("should match on 6502", async () => {
28
+ const result = await doTest();
29
+ assert.strictEqual(result, "f2fe0a16 eaeadae6 f2fe0a16 c1cdd9e5");
30
+ });
31
+ });
32
+
33
+ describe("should pass scarybeasts' RMW test on master", function () {
34
+ it("should match", async function () {
35
+ // https://stardot.org.uk/forums/viewtopic.php?f=4&t=23131
36
+ const source = `
37
+ P%=&2000
38
+ [OPT0
39
+ SEI
40
+ LDA #0:STA &FE68
41
+ LDA #1:STA &FE69
42
+ LDA #&7F:STA &FE6D
43
+ LDA #1:STA &FE68
44
+ LDA #0:STA &FE69
45
+ DEC &FE68
46
+ LDA &FE6D
47
+ AND #&20
48
+ STA &71
49
+ LDA #0:STA &FE69
50
+ LDA &FE68
51
+ STA &70
52
+ CLI
53
+ RTS
54
+ ]
55
+ ?&70=0
56
+ ?&71=0
57
+ CALL &2000`;
58
+ const testMachine = new TestMachine("Master");
59
+ await testMachine.initialise();
60
+ await testMachine.runUntilInput();
61
+ await testMachine.loadBasic(source);
62
+
63
+ testMachine.captureText((elem) => console.log(`emulator output: ${elem.text}`));
64
+ await testMachine.type("RUN");
65
+ await testMachine.runUntilInput();
66
+ assert.equal(testMachine.readbyte(0x70), 252);
67
+ assert.equal(testMachine.readbyte(0x71), 0);
68
+ });
69
+ });
@@ -0,0 +1,126 @@
1
+ import { describe, it } from "vitest";
2
+ import { TestMachine } from "../test-machine.js";
3
+ import assert from "assert";
4
+ import { Video } from "../../src/video.js";
5
+ import sharp from "sharp";
6
+ import pixelmatch from "pixelmatch";
7
+
8
+ class CapturingVideo extends Video {
9
+ constructor() {
10
+ super(false, new Uint32Array(1024 * 1024), () => {});
11
+ this.paint_ext = (left, top, right, bottom) => this._onPaint(left, top, right, bottom);
12
+ this._capturing = false;
13
+ this._captureSharp = null;
14
+ }
15
+
16
+ _onPaint(left, top, right, bottom) {
17
+ if (this._capturing) {
18
+ const width = right - left;
19
+ const height = bottom - top;
20
+ const bufferCopy = new Uint8Array(this.fb32.buffer.slice(0));
21
+ this._captureSharp = sharp(bufferCopy, {
22
+ raw: { width: 1024, height: 1024, channels: 4 },
23
+ }).extract({ left: left, top: top, width, height });
24
+ this._capturing = false;
25
+ }
26
+ }
27
+
28
+ async capture(testMachine) {
29
+ this._capturing = true;
30
+ await testMachine.runUntilVblank();
31
+ if (this._capturing) throw new Error("Should have captured by now");
32
+ return this._captureSharp;
33
+ }
34
+ }
35
+
36
+ async function setupCeefaxTestMachine(video) {
37
+ const testMachine = new TestMachine(null, { video: video });
38
+ await testMachine.initialise();
39
+ await testMachine.runUntilInput();
40
+ await testMachine.loadDisc("discs/eng_test.ssd");
41
+ await testMachine.type("*EXEC !BOOT");
42
+ await testMachine.runFor(3 * 1000 * 1000);
43
+ return testMachine;
44
+ }
45
+
46
+ const rootDir = "tests/integration/teletext";
47
+ const outputDir = `tests/integration/output`;
48
+
49
+ async function compare(video, testMachine, expectedName) {
50
+ const outputName = `${expectedName.replace("expected", "actual")}`;
51
+ const captureSharp = await video.capture(testMachine);
52
+ const outputFile = `${outputDir}/${outputName}`;
53
+ await captureSharp.removeAlpha().toFile(outputFile);
54
+ const expectedFile = `${rootDir}/${expectedName}`;
55
+ const diffFile = `${outputDir}/${outputName.replace(".png", ".diff.png")}`;
56
+
57
+ const { data: expectedData, info } = await sharp(expectedFile)
58
+ .ensureAlpha()
59
+ .raw()
60
+ .toBuffer({ resolveWithObject: true });
61
+ const actualData = await sharp(outputFile).ensureAlpha().raw().toBuffer();
62
+ const diffData = new Uint8Array(info.width * info.height * info.channels);
63
+
64
+ const numDiffPixels = pixelmatch(expectedData, actualData, diffData, info.width, info.height, {
65
+ threshold: 0.1,
66
+ });
67
+ await sharp(diffData, { raw: info }).removeAlpha().toFile(diffFile);
68
+ assert.equal(
69
+ numDiffPixels,
70
+ 0,
71
+ `Images do not match - expected ${expectedFile}, got ${outputFile}, diffs: ${diffFile}}`,
72
+ );
73
+ }
74
+
75
+ describe("Test Ceefax test page", { timeout: 30000 }, () => {
76
+ it("should match the Ceefax test page (no flash)", async () => {
77
+ const video = new CapturingVideo();
78
+ const testMachine = await setupCeefaxTestMachine(video);
79
+ await compare(video, testMachine, `expected_flash_0.png`);
80
+ });
81
+ it("should match the Ceefax test page (flash)", async () => {
82
+ const video = new CapturingVideo();
83
+ const testMachine = await setupCeefaxTestMachine(video);
84
+ await testMachine.runFor(1500000);
85
+ await compare(video, testMachine, `expected_flash_1.png`);
86
+ });
87
+ it("should match the Ceefax test page after reveal (no flash)", async () => {
88
+ const video = new CapturingVideo();
89
+ const testMachine = await setupCeefaxTestMachine(video);
90
+ await testMachine.type(" ");
91
+ await compare(video, testMachine, `expected_reveal_flash_0.png`);
92
+ });
93
+ it("should match the Ceefax test page after reveal (flash)", async () => {
94
+ const video = new CapturingVideo();
95
+ const testMachine = await setupCeefaxTestMachine(video);
96
+ await testMachine.type(" ");
97
+ await testMachine.runFor(1500000);
98
+ await compare(video, testMachine, `expected_reveal_flash_1.png`);
99
+ });
100
+ });
101
+
102
+ describe("Test other teletext test pages", { timeout: 30000 }, () => {
103
+ it("should work with hoglet's test case", async () => {
104
+ const video = new CapturingVideo();
105
+ const testMachine = new TestMachine(null, { video: video });
106
+ await testMachine.initialise();
107
+ await testMachine.runUntilInput();
108
+ // https://github.com/mattgodbolt/jsbeeb/issues/316
109
+ await testMachine.type("VDU &91,&61,&9E,&92,&93,&94,&81,&91,&91,10,13");
110
+ await testMachine.runUntilInput();
111
+ await compare(video, testMachine, `expected_hoglet_held_char.png`);
112
+ });
113
+ it("should work with the alternative engineer test page bug 469", async () => {
114
+ const video = new CapturingVideo();
115
+ const testMachine = new TestMachine(null, { video: video });
116
+ await testMachine.initialise();
117
+ await testMachine.runUntilInput();
118
+ // https://github.com/mattgodbolt/jsbeeb/issues/469
119
+ // Taken from the 7th line of the engineer test page from b2.
120
+ await testMachine.type(
121
+ "CLS:VDU &81,&80,&81,&A0,&80,&A0,&81,&9E,&A0,&9E,&A0,&97,&AC,&93,&93,&96,&96,&92,&92,&92,&95,&95,&91,&91,&94,&94,&94,&A0,&A0,&94,&80,&81,&80,&81,&80,&81,&80,&81,&B0,&B7",
122
+ );
123
+ await testMachine.runUntilInput();
124
+ await compare(video, testMachine, `expected_bug_469.png`);
125
+ });
126
+ });
@@ -0,0 +1,56 @@
1
+ import { describe, it } from "vitest";
2
+ import { TestMachine } from "../test-machine.js";
3
+ import assert from "assert";
4
+
5
+ describe("test timings", function () {
6
+ const doTest = async (model) => {
7
+ const testMachine = new TestMachine(model);
8
+ await testMachine.initialise();
9
+ await testMachine.loadDisc("discs/TestTimings.ssd");
10
+ await testMachine.runUntilInput();
11
+ await testMachine.type('CHAIN "TEST"');
12
+ await testMachine.runUntilInput();
13
+ const result = [];
14
+ const num = testMachine.readbyte(0x71) + 1;
15
+ for (let i = 0; i < num; ++i) {
16
+ const irqAddr = (testMachine.readbyte(0x4300 + i) << 8) | testMachine.readbyte(0x4000 + i);
17
+ const a = testMachine.readbyte(0x4100 + i);
18
+ const b = testMachine.readbyte(0x4200 + i);
19
+ result.push([irqAddr, a, b]);
20
+ }
21
+ return result;
22
+ };
23
+ it("should match expected values", async () => {
24
+ const result = await doTest();
25
+ // prettier-ignore
26
+ assert.deepStrictEqual(result,
27
+ [
28
+ [0x4436, 0x00, 0xDD],
29
+ [0x4443, 0x00, 0xDD],
30
+ [0x4450, 0x00, 0xDD],
31
+ [0x445E, 0x00, 0xDD],
32
+ [0x0000, 0x00, 0x00],
33
+ [0x0000, 0x00, 0x00],
34
+ [0x4488, 0x00, 0xFF],
35
+ [0x4497, 0x00, 0x00],
36
+ [0x0000, 0x00, 0x00],
37
+ [0x44B8, 0xC0, 0xFF],
38
+ [0x44C5, 0xC0, 0xFF],
39
+ [0x0000, 0x00, 0x00],
40
+ [0x0000, 0x00, 0x00],
41
+ [0x44F6, 0xC0, 0xDB],
42
+ [0x4506, 0xC0, 0xDC],
43
+ [0x4516, 0xC0, 0xFF],
44
+ [0x4527, 0xC0, 0x00],
45
+ [0x453A, 0xC0, 0x01],
46
+ [0x454A, 0xC0, 0x01],
47
+ [0x4559, 0xC0, 0x00],
48
+ [0x4569, 0xC0, 0x00],
49
+ [0x4578, 0xC0, 0x01],
50
+ [0x458A, 0xC0, 0xFF],
51
+ [0x4599, 0xC0, 0x00],
52
+ [0x45A6, 0xC0, 0x00],
53
+ [0x0000, 0x00, 0x00]
54
+ ]);
55
+ });
56
+ });