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,94 @@
1
+ "use strict";
2
+
3
+ // PAL Composite Video Filter - Approach D: Baseband Chroma Blending
4
+ //
5
+ // Simulates PAL composite video artifacts by encoding the framebuffer to a
6
+ // composite signal and decoding it back to RGB, mimicking the behavior of
7
+ // connecting a BBC Micro to a PAL television via composite cable.
8
+ //
9
+ // REFERENCES:
10
+ // - John Watkinson's "Engineer's Guide to Decoding & Encoding" (Section 3.4)
11
+ // - https://www.jim-easterbrook.me.uk/pal/ - Jim Easterbrook's PAL decoder research
12
+ // - docs/pal-simulation-design.md - Full implementation details and alternatives tried
13
+ // - docs/pal-comb-filter-research.md - Research on authentic PAL TV implementations
14
+
15
+ import VERT_SHADER from "./shaders/pal-composite.vert.glsl?raw";
16
+ import FRAG_SHADER from "./shaders/pal-composite.frag.glsl?raw";
17
+
18
+ export class PALCompositeFilter {
19
+ static requiresGl() {
20
+ return true;
21
+ }
22
+
23
+ static getDisplayConfig() {
24
+ return {
25
+ name: "PAL TV",
26
+ image: "images/tv.png",
27
+ imageAlt: "A SolaVox television",
28
+ imageWidth: 1000,
29
+ imageHeight: 719,
30
+ canvasLeft: 50,
31
+ canvasTop: 70,
32
+ visibleWidth: 800,
33
+ visibleHeight: 600,
34
+ };
35
+ }
36
+
37
+ constructor(gl) {
38
+ this.gl = gl;
39
+ this.program = null;
40
+ this.locations = {};
41
+
42
+ this._init();
43
+ }
44
+
45
+ _init() {
46
+ const gl = this.gl;
47
+
48
+ // Compile shaders
49
+ const vertShader = this._compileShader(gl.VERTEX_SHADER, VERT_SHADER);
50
+ const fragShader = this._compileShader(gl.FRAGMENT_SHADER, FRAG_SHADER);
51
+
52
+ // Link program
53
+ this.program = gl.createProgram();
54
+ gl.attachShader(this.program, vertShader);
55
+ gl.attachShader(this.program, fragShader);
56
+ gl.linkProgram(this.program);
57
+
58
+ if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) {
59
+ const info = gl.getProgramInfoLog(this.program);
60
+ throw new Error("Failed to link PAL shader program: " + info);
61
+ }
62
+
63
+ // Get uniform locations
64
+ this.locations.uFramebuffer = gl.getUniformLocation(this.program, "uFramebuffer");
65
+ this.locations.uResolution = gl.getUniformLocation(this.program, "uResolution");
66
+ this.locations.uTexelSize = gl.getUniformLocation(this.program, "uTexelSize");
67
+ this.locations.uFrameCount = gl.getUniformLocation(this.program, "uFrameCount");
68
+
69
+ console.log("PAL composite filter initialized");
70
+ }
71
+
72
+ _compileShader(type, source) {
73
+ const gl = this.gl;
74
+ const shader = gl.createShader(type);
75
+ gl.shaderSource(shader, source);
76
+ gl.compileShader(shader);
77
+
78
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
79
+ const info = gl.getShaderInfoLog(shader);
80
+ const typeName = type === gl.VERTEX_SHADER ? "vertex" : "fragment";
81
+ throw new Error(`Failed to compile ${typeName} shader: ${info}`);
82
+ }
83
+
84
+ return shader;
85
+ }
86
+
87
+ setUniforms(params) {
88
+ const gl = this.gl;
89
+ gl.uniform1i(this.locations.uFramebuffer, 0); // Texture unit 0
90
+ gl.uniform2f(this.locations.uResolution, params.width, params.height);
91
+ gl.uniform2f(this.locations.uTexelSize, 1.0 / params.width, 1.0 / params.height);
92
+ gl.uniform1f(this.locations.uFrameCount, params.frameCount % 8); // 8-field temporal phase sequence
93
+ }
94
+ }
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+
3
+ import VERT_SHADER from "./shaders/passthrough.vert.glsl?raw";
4
+ import FRAG_SHADER from "./shaders/passthrough.frag.glsl?raw";
5
+
6
+ export class PassthroughFilter {
7
+ static requiresGl() {
8
+ return false;
9
+ }
10
+
11
+ static getDisplayConfig() {
12
+ return {
13
+ name: "RGB Monitor",
14
+ image: "images/cub-monitor.png",
15
+ imageAlt: "A fake CUB computer monitor",
16
+ imageWidth: 896,
17
+ imageHeight: 648,
18
+ canvasLeft: 0,
19
+ canvasTop: 8,
20
+ visibleWidth: 896,
21
+ visibleHeight: 600,
22
+ };
23
+ }
24
+
25
+ constructor(gl) {
26
+ this.gl = gl;
27
+ this.program = null;
28
+ this.locations = {};
29
+
30
+ this._init();
31
+ }
32
+
33
+ _init() {
34
+ const gl = this.gl;
35
+
36
+ const vertexShader = this._compileShader(gl.VERTEX_SHADER, VERT_SHADER);
37
+ const fragmentShader = this._compileShader(gl.FRAGMENT_SHADER, FRAG_SHADER);
38
+
39
+ this.program = gl.createProgram();
40
+ gl.attachShader(this.program, vertexShader);
41
+ gl.attachShader(this.program, fragmentShader);
42
+ gl.linkProgram(this.program);
43
+
44
+ if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) {
45
+ throw new Error("Failed to link passthrough shader program: " + gl.getProgramInfoLog(this.program));
46
+ }
47
+
48
+ this.locations.tex = gl.getUniformLocation(this.program, "tex");
49
+ }
50
+
51
+ _compileShader(type, source) {
52
+ const gl = this.gl;
53
+ const shader = gl.createShader(type);
54
+ gl.shaderSource(shader, source);
55
+ gl.compileShader(shader);
56
+
57
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
58
+ const error = gl.getShaderInfoLog(shader);
59
+ gl.deleteShader(shader);
60
+ throw new Error("Shader compilation failed: " + error);
61
+ }
62
+
63
+ return shader;
64
+ }
65
+
66
+ setUniforms(_params) {
67
+ const gl = this.gl;
68
+ gl.uniform1i(this.locations.tex, 0);
69
+ }
70
+ }
@@ -0,0 +1,147 @@
1
+ precision highp float;
2
+
3
+ varying vec2 vTexCoord;
4
+
5
+ uniform sampler2D uFramebuffer;
6
+ uniform vec2 uResolution;
7
+ uniform vec2 uTexelSize;
8
+ uniform float uFrameCount;
9
+
10
+ const float PI = 3.14159265359;
11
+
12
+ // IMPLEMENTATION (Baseband Blending Method):
13
+ // 1. Encode RGB to PAL composite: Y + U*sin(ωt) + V*cos(ωt)*v_switch
14
+ // 2. Demodulate current line (with correct phase) → U_curr, V_curr
15
+ // 3. Demodulate previous line (2H for interlaced, same field) → U_prev, V_prev
16
+ // 4. Blend at baseband: U_final = mix(U_curr, U_prev), V_final = mix(V_curr, V_prev)
17
+ // 5. Remodulate blended chroma back to composite frequency
18
+ // 6. Extract luma via complementary subtraction: Y = composite - remodulated_chroma
19
+ // 7. Combine luma and chroma, convert back to RGB
20
+ //
21
+ // NOTE: Uses 2H delay (line-2) not 1H (line-1) because jsbeeb simulates interlacing by
22
+ // rendering only odd or even lines per frame. A real PAL TV's 1H delay line would contain
23
+ // the previous scanline from the SAME field, which is 2 texture lines apart. Proper
24
+ // support for non-interlaced modes needs to be added.
25
+
26
+ // Chroma demodulation gain: compensates for sin²(x) = 0.5 - 0.5·cos(2x) amplitude loss
27
+ const float FIR_GAIN = 2.0;
28
+
29
+ // Chroma vertical blending weight (0.0 = no blend, 0.5 = equal blend)
30
+ const float CHROMA_BLEND_WEIGHT = 0.5;
31
+
32
+ // PAL standard base parameters
33
+ const float PAL_TOTAL_LINES = 625.0; // Total scanlines per frame
34
+ const float PAL_FRAME_RATE = 25.0; // Frames per second
35
+ const float PAL_SUBCARRIER_MHZ = 4.43361875; // PAL color subcarrier frequency (exact)
36
+
37
+ // Derived PAL parameters
38
+ const float PAL_LINES_PER_FIELD = PAL_TOTAL_LINES / 2.0;
39
+ const float PAL_CYCLES_PER_LINE = PAL_SUBCARRIER_MHZ * 1e6 / (PAL_TOTAL_LINES * PAL_FRAME_RATE);
40
+ const float PAL_LINE_PHASE_OFFSET = fract(PAL_CYCLES_PER_LINE);
41
+ const float PAL_FIELD_PHASE_OFFSET = PAL_LINE_PHASE_OFFSET * PAL_LINES_PER_FIELD;
42
+
43
+ // jsbeeb texture parameters
44
+ const float TEXTURE_WIDTH = 1024.0; // Framebuffer width (896 visible + 128 blanking)
45
+
46
+ // RGB → YUV conversion with proper PAL signal levels baked in
47
+ // Derived from ITU-R BT.470-6: white at 0.7V, peak at 0.931V
48
+ // Matrix ensures RGB(1,1,1) → YUV(0.7,0,0) and worst case (yellow) peaks at 0.931V
49
+ vec3 rgb_to_yuv(vec3 rgb) {
50
+ return vec3(
51
+ 0.2093 * rgb.r + 0.4109 * rgb.g + 0.0798 * rgb.b,
52
+ -0.102228 * rgb.r - 0.200704 * rgb.g + 0.302939 * rgb.b,
53
+ 0.427311 * rgb.r - 0.357823 * rgb.g - 0.069488 * rgb.b
54
+ );
55
+ }
56
+
57
+ // YUV → RGB inverse matrix
58
+ vec3 yuv_to_rgb(vec3 yuv) {
59
+ return vec3(
60
+ 1.42857143 * yuv.x - 0.0000193387 * yuv.y + 1.64048673 * yuv.z,
61
+ 1.42857711 * yuv.x - 0.567986687 * yuv.y - 0.83560997 * yuv.z,
62
+ 1.42854218 * yuv.x + 2.92468392 * yuv.y - 0.0000217418 * yuv.z
63
+ );
64
+ }
65
+
66
+ // Demodulate composite signal at given position
67
+ vec2 demodulate_uv(vec2 xy, float pixel_x, float offset_pixels, float v_switch, float cycles_per_pixel, float phase_offset) {
68
+ float t = ((pixel_x + offset_pixels) * cycles_per_pixel + phase_offset) * 2.0 * PI;
69
+
70
+ vec2 sample_uv = xy + vec2(offset_pixels * uTexelSize.x, 0.0);
71
+ vec3 rgb = texture2D(uFramebuffer, sample_uv).rgb;
72
+ vec3 yuv = rgb_to_yuv(rgb);
73
+
74
+ // Encode to composite: Y + U*sin(ωt) + V*cos(ωt)*v_switch
75
+ float composite = yuv.x + yuv.y * sin(t) + yuv.z * cos(t) * v_switch;
76
+
77
+ // Demodulate: multiply by carrier to shift chroma to baseband
78
+ return vec2(composite * sin(t), composite * cos(t) * v_switch);
79
+ }
80
+
81
+ void main() {
82
+ // Use gl_FragCoord for pixel coordinates - it's hardware-provided and avoids interpolation artifacts
83
+ vec2 pixelCoord = vec2(gl_FragCoord.x, uResolution.y - gl_FragCoord.y);
84
+
85
+ // BEGIN_FIR_COEFFICIENTS
86
+ // This section is replaced by the Vite build to include FIR filter coefficients.
87
+ // Change Cutoff (in comment below) or FIRTAPS value to configure.
88
+ // Cutoff: 1.108 MHz (quarter subcarrier)
89
+ const int FIRTAPS = 21;
90
+ float FIR[FIRTAPS];
91
+ // END_FIR_COEFFICIENTS
92
+
93
+ float line = floor(pixelCoord.y);
94
+
95
+ // PAL phase alternates each scanline (V component inverts)
96
+ float v_switch = mod(line, 2.0) < 1.0 ? 1.0 : -1.0;
97
+
98
+ // Map PAL subcarrier across texture width
99
+ float cycles_per_pixel = PAL_CYCLES_PER_LINE / TEXTURE_WIDTH;
100
+
101
+ // PAL temporal phase (8-field sequence creates animated dot crawl)
102
+ float line_phase_offset = line * PAL_LINE_PHASE_OFFSET;
103
+ float frame_phase_offset = uFrameCount * PAL_FIELD_PHASE_OFFSET;
104
+ float phase_offset = line_phase_offset + frame_phase_offset;
105
+
106
+ // Step 1: Demodulate current line with FIR filter
107
+ vec2 filtered_uv_curr = vec2(0.0);
108
+ for (int i = 0; i < FIRTAPS; i++) {
109
+ float offset = float(i - (FIRTAPS - 1) / 2);
110
+ vec2 uv = demodulate_uv(vTexCoord, pixelCoord.x, offset, v_switch, cycles_per_pixel, phase_offset);
111
+ filtered_uv_curr += FIR_GAIN * uv * FIR[i];
112
+ }
113
+
114
+ // Step 2: Demodulate previous line (2H for interlaced, same field) with FIR filter
115
+ // In interlaced mode, only odd OR even lines are rendered per frame.
116
+ // Using 2H (line-2) ensures we sample from the same field (both fresh data).
117
+ // This represents the TV's 1H delay within a single field.
118
+ vec2 prev_uv = vTexCoord - vec2(0.0, 2.0 * uTexelSize.y);
119
+ float prev_line = line - 2.0;
120
+ float prev_v_switch = v_switch * -1.0;
121
+ float prev_phase_offset = prev_line * PAL_LINE_PHASE_OFFSET + frame_phase_offset;
122
+
123
+ vec2 filtered_uv_prev = vec2(0.0);
124
+ for (int i = 0; i < FIRTAPS; i++) {
125
+ float offset = float(i - (FIRTAPS - 1) / 2);
126
+ vec2 uv = demodulate_uv(prev_uv, pixelCoord.x, offset, prev_v_switch, cycles_per_pixel, prev_phase_offset);
127
+ filtered_uv_prev += FIR_GAIN * uv * FIR[i];
128
+ }
129
+
130
+ // Step 3: Blend chroma at baseband
131
+ vec2 filtered_uv = mix(filtered_uv_curr, filtered_uv_prev, CHROMA_BLEND_WEIGHT);
132
+
133
+ // Step 4: Get luma via complementary subtraction
134
+ float t_curr = (pixelCoord.x * cycles_per_pixel + phase_offset) * 2.0 * PI;
135
+ vec3 rgb_curr = texture2D(uFramebuffer, vTexCoord).rgb;
136
+ vec3 yuv_curr = rgb_to_yuv(rgb_curr);
137
+ float composite_curr = yuv_curr.x + yuv_curr.y * sin(t_curr) + yuv_curr.z * cos(t_curr) * v_switch;
138
+
139
+ // Remodulate blended chroma back to composite frequency
140
+ float remodulated_chroma = filtered_uv.x * sin(t_curr) + filtered_uv.y * cos(t_curr) * v_switch;
141
+
142
+ // Complementary subtraction: luma = composite - chroma
143
+ float y_out = composite_curr - remodulated_chroma;
144
+
145
+ vec3 rgb_out = yuv_to_rgb(vec3(y_out, filtered_uv.x, filtered_uv.y));
146
+ gl_FragColor = vec4(clamp(rgb_out, 0.0, 1.0), 1.0);
147
+ }
@@ -0,0 +1,8 @@
1
+ attribute vec2 pos;
2
+ attribute vec2 uvIn;
3
+ varying vec2 vTexCoord;
4
+
5
+ void main() {
6
+ vTexCoord = uvIn;
7
+ gl_Position = vec4(pos * 2.0 - 1.0, 0.0, 1.0);
8
+ }
@@ -0,0 +1,6 @@
1
+ precision mediump float;
2
+ uniform sampler2D tex;
3
+ varying vec2 uv;
4
+ void main() {
5
+ gl_FragColor = texture2D(tex, uv).rgba;
6
+ }
@@ -0,0 +1,7 @@
1
+ attribute vec2 pos;
2
+ attribute vec2 uvIn;
3
+ varying vec2 uv;
4
+ void main() {
5
+ uv = uvIn;
6
+ gl_Position = vec4(2.0 * pos - 1.0, 0.0, 1.0);
7
+ }