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,368 @@
1
+ # PAL Television Simulation for jsbeeb
2
+
3
+ **Status:** ✅ Implemented
4
+ **Author:** Claude Code
5
+ **Date:** October 2025
6
+ **Branch:** claude/pal
7
+ **PR:** #525 (DRAFT)
8
+
9
+ ## Executive Summary
10
+
11
+ This document describes the PAL composite video simulation in jsbeeb, which adds authentic analog TV artifacts (dot crawl, color bleeding) that were part of the original BBC Micro viewing experience.
12
+
13
+ The implementation uses WebGL fragment shaders to simulate the complete PAL signal path: RGB → YUV encoding → composite signal → PAL decoding → RGB display. The approach uses **baseband chroma blending** with **complementary luma extraction**, achieving sharp luminance with smooth chrominance and no checkerboard artifacts.
14
+
15
+ **Performance:** Real-time 60fps on modern GPUs, ~1-2ms per frame.
16
+
17
+ ## How It Works
18
+
19
+ ### Signal Processing Pipeline
20
+
21
+ The shader implements these steps for each pixel:
22
+
23
+ 1. **Encode to composite** (per horizontal tap)
24
+ - Convert RGB → YUV using scaled matrix
25
+ - Generate composite: `C(t) = Y + U·sin(ωt) + V·cos(ωt)·v_switch`
26
+ - Where v_switch alternates ±1 each scanline (PAL phase)
27
+
28
+ 2. **Demodulate with FIR filter**
29
+ - Multiply composite by sin(ωt) and cos(ωt) to shift chroma to baseband
30
+ - Apply 21-tap FIR low-pass filter (~2.2 MHz cutoff) horizontally
31
+ - FIR_GAIN = 2.0 compensates for demodulation amplitude loss (sin²(x) = 0.5)
32
+ - Process current line AND previous line (2H delay) separately
33
+
34
+ 3. **Blend chroma at baseband**
35
+ - Mix current and previous line's U/V values: 50/50 weighted average
36
+ - **Critical:** Blend AFTER demodulation to avoid phase mixing
37
+ - Exploits slow vertical chroma changes for noise reduction
38
+
39
+ 4. **Extract luma via complementary subtraction**
40
+ - Remodulate blended chroma back to composite frequency
41
+ - Subtract from current line's composite: `Y_out = composite - chroma_remod`
42
+ - Gives sharp luma without vertical averaging
43
+
44
+ 5. **Convert back to RGB** for display
45
+
46
+ ### Why This Approach Works
47
+
48
+ **Baseband blending avoids U/V corruption:**
49
+
50
+ - Each line demodulated with its correct PAL phase FIRST
51
+ - Then clean U and V components blended (no phase mixing)
52
+ - Contrast with failed approaches that blended at composite level
53
+
54
+ **Complementary decoder preserves luma sharpness:**
55
+
56
+ - Luma extracted by subtraction, not averaging
57
+ - Avoids vertical blur from comb filters
58
+ - Slightly less sharp than notch filter, but more authentic
59
+
60
+ **2H delay for interlaced rendering:**
61
+
62
+ - jsbeeb renders only odd OR even lines per frame
63
+ - Using line-2 samples from same field (both fresh data)
64
+ - Represents TV's 1H delay within a single field
65
+
66
+ ## Evolution: What Was Tried and Why
67
+
68
+ ### The Investigation Journey
69
+
70
+ Initial implementation suffered from excessive vertical blur and/or checkerboard artifacts. The investigation tested multiple approaches to Y/C separation and chroma filtering:
71
+
72
+ ### Failed Approaches
73
+
74
+ #### 1. 1H Comb Bandpass at Composite Level (Approach C)
75
+
76
+ Inspired by BBC decoder schematic from Jim Easterbrook's PAL decoder page.
77
+
78
+ **Approach:**
79
+
80
+ ```glsl
81
+ chroma_band = (composite_curr + composite_prev_1H) / 2.0;
82
+ // Demodulate chroma_band with FIR → U, V
83
+ Y = composite_curr - remodulated_chroma;
84
+ ```
85
+
86
+ **Why it failed:**
87
+
88
+ - 1H spacing = 0.75 cycles = 270° phase shift
89
+ - Mathematical analysis showed U/V mixing:
90
+ ```
91
+ chroma_band = (U_N + V_{N-1})·sin(ωt) + (V_N + U_{N-1})·cos(ωt)
92
+ ```
93
+ - When demodulated, extracted corrupted U/V values (phase mixing)
94
+ - Tried compensating with FIR_GAIN = 4.0 (double amplitude loss) - made it worse
95
+ - Result: Severe checkerboard artifacts, washed out colors
96
+
97
+ **Lesson:** 1H comb at composite level doesn't work for PAL due to phase relationships. Must demodulate FIRST with correct phase, THEN blend.
98
+
99
+ #### 2. 3-Tap Bandpass Comb with Complementary Subtraction
100
+
101
+ **Approach:**
102
+
103
+ ```glsl
104
+ chroma = -0.25*prev + 0.5*curr - 0.25*next; // "Bandpass"
105
+ y_out = composite_curr - chroma; // Complementary
106
+ ```
107
+
108
+ **Why it failed:**
109
+ Mathematical reduction negates the negative coefficients:
110
+
111
+ ```
112
+ y_out = composite_curr - (-0.25*prev + 0.5*curr - 0.25*next)
113
+ = 0.25*prev + 0.5*curr + 0.25*next // Standard lowpass!
114
+ ```
115
+
116
+ Result: Luma averaged across 4 scanlines (N-2 to N+2 span), excessive blur.
117
+
118
+ **Validation:** Explicit lowpass produced IDENTICAL blur (toggled multiple times to confirm).
119
+
120
+ **Lesson:** Complementary subtraction with this 3-tap design mathematically collapses to simple averaging.
121
+
122
+ #### 3. Various 2-Tap Comb Filters Without Proper Gain
123
+
124
+ **Approach:**
125
+
126
+ ```glsl
127
+ // Tried various weightings
128
+ y = 0.5*prev + 0.5*curr; // 50/50
129
+ y = 0.25*prev + 0.75*curr; // 25/75
130
+ y = 0.33*prev + 0.67*curr; // 33/67
131
+ ```
132
+
133
+ **Why they failed:**
134
+ All showed checkerboard artifacts with FIR_GAIN = 1.0.
135
+
136
+ **Root cause identified:** The issue wasn't the comb filter design - it was insufficient gain compensation!
137
+
138
+ - Demodulation: `composite * sin(ωt)` produces baseband at 0.5× amplitude (sin²(x) identity)
139
+ - With FIR_GAIN = 1.0: Only removed HALF the chroma from luma
140
+ - Result: Residual chroma in luma channel → checkerboard
141
+
142
+ **Fix:** FIR_GAIN = 2.0 properly compensates for demodulation amplitude loss.
143
+
144
+ **Lesson:** This was THE fundamental bug causing most artifacts. Weight tuning was papering over a deeper mathematical issue.
145
+
146
+ #### 4. Active Video Only Phase Calculation
147
+
148
+ **Approach:**
149
+
150
+ ```glsl
151
+ cycles_per_pixel = 230.0 / 896.0; // Subcarrier over visible pixels only
152
+ ```
153
+
154
+ **Why it failed:**
155
+
156
+ - Ignored blanking periods (horizontal retrace)
157
+ - Subcarrier runs continuously through blanking
158
+ - Wrong phase relationships between lines
159
+
160
+ **Fix:** Use full scanline: 283.75 cycles / 1024 pixels (includes blanking).
161
+
162
+ #### 5. Comb Filter Without Temporal Phase
163
+
164
+ **Approach:**
165
+
166
+ ```glsl
167
+ y = (composite_curr + composite_prev) / 2.0; // Simple average
168
+ ```
169
+
170
+ **Why it failed:**
171
+
172
+ - Didn't account for 0.75 cycle phase offset between lines
173
+ - Result: Heavy vertical striping (chroma not canceling properly)
174
+
175
+ **Fix:** Added `line_phase_offset = line * 0.7516` for proper phase relationships.
176
+
177
+ #### 6. Horizontal Bandwidth Limiting of Composite Signal
178
+
179
+ **Approach:**
180
+ Apply horizontal low-pass filter to composite signal before Y/C separation.
181
+
182
+ **Why it failed:**
183
+
184
+ - Didn't address root cause of artifacts
185
+ - Just added blur without fixing underlying issues
186
+ - Abandoned as unnecessary once phase and gain issues were fixed
187
+
188
+ ### Working Approaches (Evolution)
189
+
190
+ #### Early Success: 2H Comb Filter with Weighted Coefficients
191
+
192
+ **Approach:**
193
+
194
+ ```glsl
195
+ luma = COMB_PREV_WEIGHT * prev_2H + (1-COMB_PREV_WEIGHT) * current;
196
+ ```
197
+
198
+ - Uses 2H (2-line) spacing for proper PAL phase (180° inversion)
199
+ - Tunable weighting via COMB_PREV_WEIGHT (0.33 was final setting)
200
+ - FIR_GAIN = 2.0 for proper demodulation compensation
201
+
202
+ **Status:** Working and producing good results, but superseded by sharper Approach D.
203
+
204
+ **Result:** Good Y/C separation, authentic dot crawl, but more vertical blur than final approach.
205
+
206
+ #### Final Success: Baseband Chroma Blending (Current Implementation)
207
+
208
+ **Key insight from PAL decoder expert:** "Improve the decoded chroma" - blend AFTER demodulation, not before.
209
+
210
+ **Approach:**
211
+
212
+ 1. Demodulate current and previous (2H for interlaced) lines separately
213
+ 2. Each demodulation uses correct phase for that line (avoids U/V mixing)
214
+ 3. Blend clean U/V at baseband: `mix(uv_curr, uv_prev, 0.5)`
215
+ 4. Extract luma via complementary subtraction from composite
216
+ 5. FIR_GAIN = 2.0 for proper amplitude compensation
217
+
218
+ **Why this works:**
219
+
220
+ - **Phase-correct demodulation first:** Each line processed with its own PAL phase
221
+ - **Baseband blending:** No U/V mixing (pure U with U, pure V with V)
222
+ - **Complementary decoder:** Luma from composite minus remodulated chroma (sharp)
223
+ - **Proper gain compensation:** FIR_GAIN = 2.0 handles demodulation loss only
224
+
225
+ **Result:**
226
+
227
+ - Sharp luma with slight authentic blur (no vertical averaging of composite)
228
+ - Smooth chroma (vertical blending exploits slow chroma changes)
229
+ - Good color saturation (no phase corruption)
230
+ - No checkerboard artifacts (clean Y/C separation)
231
+
232
+ **Comparison with notch filter approach:**
233
+
234
+ - Pure notch filter (luma = composite - FIR_filtered_chroma) was tested
235
+ - With FIR_GAIN = 2.0, it's super sharp with no checkerboard
236
+ - BUT: Too sharp - sharper than authentic PAL TVs
237
+ - Current approach has more authentic slight blur
238
+
239
+ ### Critical Technical Discoveries
240
+
241
+ 1. **Demodulation amplitude loss MUST be compensated**
242
+ - sin²(x) = 0.5 - 0.5·cos(2x) → baseband has 0.5× amplitude
243
+ - FIR_GAIN = 2.0 compensates for this loss
244
+ - This was the root cause of most checkerboard artifacts
245
+
246
+ 2. **"Blend chroma" means at baseband, not composite**
247
+ - Composite-level blending causes phase mixing
248
+ - Baseband-level blending preserves clean U/V separation
249
+
250
+ 3. **Texture coordinates represent full scanline**
251
+ - 1024px = 64μs complete scanline (visible + blanking)
252
+ - Phase must map across full width, not just visible pixels
253
+
254
+ 4. **The "0.75 cycle offset" is essential**
255
+ - 1H spacing = 270° phase shift
256
+ - 2H spacing = 180° phase shift (used for PAL cancellation)
257
+ - This fractional offset creates the 8-field dot crawl pattern
258
+
259
+ 5. **Properly scaled YUV matrix eliminates separate gain constant**
260
+ - ITU-R BT.470-6 defines white at 0.7V, peak at 0.931V
261
+ - Baking this into the RGB→YUV matrix removes need for CHROMA_GAIN
262
+ - Cleaner implementation, one less magic number
263
+
264
+ ## Technical Reference
265
+
266
+ ### PAL Parameters
267
+
268
+ - **Subcarrier frequency:** 283.75 cycles per scanline (4.43 MHz over 64μs)
269
+ - **Line phase offset:** 0.7516 fractional cycles per line
270
+ - **Field phase offset:** 234.875 cycles per field (= 0.7516 × 312.5 lines)
271
+ - **V phase alternation:** ±1 per scanline (PAL's defining characteristic)
272
+ - **8-field sequence:** Phase repeats every 8 fields, creating animated dot crawl
273
+
274
+ ### Color Space Conversion
275
+
276
+ Uses ITU-R BT.470-6 YUV matrix scaled for PAL signal levels:
277
+
278
+ - RGB(1,1,1) → YUV(0.7, 0, 0) — white at 0.7V
279
+ - Worst case (yellow) peaks at 0.931V — prevents overmodulation
280
+ - No separate CHROMA_GAIN needed (baked into matrix coefficients)
281
+
282
+ See shader source for actual matrix values.
283
+
284
+ ### FIR Filter
285
+
286
+ - **Taps:** 21 (symmetric)
287
+ - **Cutoff frequency:** 2.217 MHz (half subcarrier)
288
+ - **Sample rate:** 16 MHz
289
+ - **Gain compensation:** FIR_GAIN = 2.0 to compensate for demodulation amplitude loss
290
+ - **Source:** Derived from svofski/CRT project
291
+
292
+ ### Chroma Blending
293
+
294
+ 50/50 weighted average of current and previous line's U/V components (at baseband, after demodulation).
295
+
296
+ ## Known Limitations
297
+
298
+ ### Not Yet Implemented
299
+
300
+ - User-adjustable parameters (artifact intensity, etc.)
301
+ - Quality presets (composite/s-video/rgb simulation modes)
302
+ - Toggle to switch between PAL and clean RGB
303
+ - Performance monitoring
304
+
305
+ ### Outstanding Issues
306
+
307
+ 1. **Non-interlaced mode sub-optimal**
308
+ - Current: Uses same 2H delay as interlaced (blends same-phase lines)
309
+ - Better: Should use 1H delay (blend opposite-phase lines N and N-1)
310
+ - Impact: Less accurate chroma in non-interlaced modes
311
+ - Fix: Add `uInterlaced` uniform, use `line_offset = interlaced ? 2.0 : 1.0`
312
+
313
+ 2. **Fixed field line count**
314
+ - Assumes 312.5 lines/field for phase calculation
315
+ - CRTC can configure variable line counts
316
+ - May affect dot crawl accuracy in unusual configurations
317
+
318
+ 3. **Edge artifacts at borders**
319
+ - Visible color fringe where content meets black border
320
+ - Caused by chroma blending with black (correct behavior)
321
+ - May need comparison with real hardware to validate
322
+
323
+ 4. **No gamma correction**
324
+ - Should ideally use sRGB framebuffer (GL_FRAMEBUFFER_SRGB)
325
+ - Deferred for future implementation
326
+
327
+ ## Integration with jsbeeb
328
+
329
+ ### Frame Counter Propagation
330
+
331
+ The 8-field PAL sequence requires frame-accurate phase:
332
+
333
+ ```javascript
334
+ // video.js → main.js → canvas.js → shader
335
+ video.frameCount → gl.uniform1f(frameCountLocation, frameCount)
336
+ ```
337
+
338
+ ### Interlaced Rendering Interaction
339
+
340
+ jsbeeb simulates interlacing by clearing alternate lines each frame:
341
+
342
+ - Even frames: render lines 1,3,5... (clear 0,2,4...)
343
+ - Odd frames: render lines 0,2,4... (clear 1,3,5...)
344
+
345
+ The shader's 2H delay (line-2) ensures we sample from the same field, avoiding stale/black data.
346
+
347
+ ## References
348
+
349
+ ### PAL Standards
350
+
351
+ - ITU-R BT.470-6 (1998): PAL signal levels and YUV coefficients
352
+ - ITU-R BT.601: Digital video encoding
353
+
354
+ ### BBC Micro Hardware
355
+
356
+ - BBC Hardware Guide: PAL encoder circuit, subcarrier generation
357
+ - BeebWiki Video ULA: RGB output and palette
358
+
359
+ ### Decoding Theory
360
+
361
+ - Watkinson "Engineer's Guide to Encoding & Decoding": Comb filter principles
362
+ - Jim Easterbrook PAL decoder page: Complementary decoder approach
363
+ - svofski/CRT project: FIR filter coefficients source
364
+
365
+ ### WebGL Implementation
366
+
367
+ - WebGL Fundamentals: Shader optimization techniques
368
+ - MDN WebGL Best Practices: Performance guidelines
@@ -0,0 +1,35 @@
1
+ import prettier from "eslint-plugin-prettier";
2
+ import eslintConfigPrettier from "eslint-config-prettier";
3
+ import js from "@eslint/js";
4
+ import globals from "globals";
5
+
6
+ export default [
7
+ {
8
+ ignores: ["lib/", "out/", "dist/", "coverage/"],
9
+ },
10
+ js.configs.recommended,
11
+ eslintConfigPrettier,
12
+ {
13
+ plugins: { prettier },
14
+ languageOptions: {
15
+ parserOptions: {
16
+ ecmaVersion: 2020,
17
+ sourceType: "module",
18
+ },
19
+ globals: {
20
+ ...globals.browser,
21
+ ...globals.node,
22
+ },
23
+ },
24
+ rules: {
25
+ "no-unused-vars": [
26
+ "error",
27
+ {
28
+ varsIgnorePattern: "^_",
29
+ argsIgnorePattern: "^_",
30
+ caughtErrorsIgnorePattern: "^_",
31
+ },
32
+ ],
33
+ },
34
+ },
35
+ ];