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.
- package/.editorconfig +15 -0
- package/.git-blame-ignore-revs +3 -0
- package/.github/copilot-instructions.md +94 -0
- package/.github/workflows/claude-issue-triage.yml +105 -0
- package/.github/workflows/claude.yml +63 -0
- package/.github/workflows/release-please.yml +75 -0
- package/.github/workflows/test-and-deploy.yml +86 -0
- package/.gitmodules +6 -0
- package/.husky/pre-commit +1 -0
- package/.idea/codeStyleSettings.xml +9 -0
- package/.idea/codeStyles/Project.xml +62 -0
- package/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/compiler.xml +22 -0
- package/.idea/copyright/profiles_settings.xml +3 -0
- package/.idea/encodings.xml +6 -0
- package/.idea/inspectionProfiles/Project_Default.xml +7 -0
- package/.idea/jsLibraryMappings.xml +6 -0
- package/.idea/jsLinters/jshint.xml +85 -0
- package/.idea/jsLinters/jslint.xml +15 -0
- package/.idea/jsbeeb.iml +11 -0
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/prettier.xml +7 -0
- package/.idea/runConfigurations/Debug.xml +5 -0
- package/.idea/scopes/scope_settings.xml +5 -0
- package/.idea/vcs.xml +8 -0
- package/.prettierignore +4 -0
- package/.prettierrc.json +1 -0
- package/.release-please-manifest.json +3 -0
- package/.vscode/launch.json +14 -0
- package/.vscode/settings.json +6 -0
- package/CHANGELOG.md +32 -0
- package/CLAUDE.md +136 -0
- package/COPYING +674 -0
- package/Dockerfile +22 -0
- package/Makefile +30 -0
- package/README.md +259 -0
- package/docker/nginx-default.conf +10 -0
- package/docs/pal-comb-filter-research.md +129 -0
- package/docs/pal-simulation-design.md +368 -0
- package/eslint.config.js +35 -0
- package/index.html +954 -0
- package/jsconfig.json +10 -0
- package/package.json +102 -0
- package/public/discs/README.Irq-Timing +3 -0
- package/public/discs/README.bcdtest +5 -0
- package/public/discs/README.elite +6 -0
- package/public/discs/README.eng_test +3 -0
- package/public/discs/README.protection +7 -0
- package/public/favicon.ico +0 -0
- package/public/images/botbar.png +0 -0
- package/public/images/cub-monitor.png +0 -0
- package/public/images/jsbeeb-example.png +0 -0
- package/public/images/placeholder.png +0 -0
- package/public/images/red-off-16.png +0 -0
- package/public/images/red-on-16.png +0 -0
- package/public/images/sb/CD-left.jpg +0 -0
- package/public/images/sb/CD-right.jpg +0 -0
- package/public/images/sidebar.png +0 -0
- package/public/images/tv.png +0 -0
- package/public/images/yellow-off-16.png +0 -0
- package/public/images/yellow-on-16.png +0 -0
- package/public/jsbeeb-icon.png +0 -0
- package/public/robots.txt +3 -0
- package/public/roms/ADFS1-53.rom +0 -0
- package/public/roms/BASIC.ROM +0 -0
- package/public/roms/README +4 -0
- package/public/roms/a01/BASIC1.rom +0 -0
- package/public/roms/ample.rom +0 -0
- package/public/roms/ats-3.0.rom +0 -0
- package/public/roms/b/DFS-0.9.rom +0 -0
- package/public/roms/b/DFS-1.2.rom +0 -0
- package/public/roms/b1770/dfs1770.rom +0 -0
- package/public/roms/b1770/zADFS.ROM +0 -0
- package/public/roms/bp/dfs.rom +0 -0
- package/public/roms/bp/zADFS.ROM +0 -0
- package/public/roms/bpos.rom +0 -0
- package/public/roms/compact/adfs210.rom +0 -0
- package/public/roms/compact/basic48.rom +0 -0
- package/public/roms/compact/basic486.rom +0 -0
- package/public/roms/compact/os51.rom +0 -0
- package/public/roms/compact/utils.rom +0 -0
- package/public/roms/deos.rom +0 -0
- package/public/roms/master/anfs-4.25.rom +0 -0
- package/public/roms/master/mos.txt +68819 -0
- package/public/roms/master/mos3.20 +0 -0
- package/public/roms/os.rom +0 -0
- package/public/roms/os01.rom +0 -0
- package/public/roms/tube/6502Tube.rom +0 -0
- package/public/roms/tube/ARMeval_100.rom +0 -0
- package/public/roms/tube/BIOS.ROM +0 -0
- package/public/roms/tube/ReCo6502ROM_816 +0 -0
- package/public/roms/tube/Z80_120.rom +0 -0
- package/public/roms/us/USBASIC.rom +0 -0
- package/public/roms/us/USDNFS.rom +0 -0
- package/public/roms/usmos.rom +0 -0
- package/public/sounds/disc525/motor.wav +0 -0
- package/public/sounds/disc525/motoroff.wav +0 -0
- package/public/sounds/disc525/motoron.wav +0 -0
- package/public/sounds/disc525/seek.wav +0 -0
- package/public/sounds/disc525/seek2.wav +0 -0
- package/public/sounds/disc525/seek3.wav +0 -0
- package/public/sounds/disc525/step.wav +0 -0
- package/public/teletext/txt0.dat +0 -0
- package/public/teletext/txt1.dat +0 -0
- package/public/teletext/txt2.dat +0 -0
- package/public/teletext/txt3.dat +0 -0
- package/release-please-config.json +13 -0
- package/run-container.sh +92 -0
- package/src/6502.js +1347 -0
- package/src/6502.opcodes.js +1411 -0
- package/src/acia.js +261 -0
- package/src/adc.js +149 -0
- package/src/analogue-source.js +21 -0
- package/src/app/app.js +175 -0
- package/src/app/electron.js +20 -0
- package/src/app/preload.js +8 -0
- package/src/app-bench.js +33 -0
- package/src/basic/multiline-tetris +9 -0
- package/src/basic-tokenise.js +104 -0
- package/src/canvas.js +177 -0
- package/src/cmos.js +141 -0
- package/src/config.js +165 -0
- package/src/ddnoise.js +138 -0
- package/src/disc-drive.js +371 -0
- package/src/disc-hfe.js +396 -0
- package/src/disc.js +997 -0
- package/src/econet/L3FS.dat +0 -0
- package/src/econet/scsi.dat +0 -0
- package/src/econet.js +714 -0
- package/src/fake6502.js +32 -0
- package/src/fdc.js +248 -0
- package/src/filestore.js +666 -0
- package/src/gamepad-source.js +59 -0
- package/src/gamepads.js +268 -0
- package/src/google-drive.js +160 -0
- package/src/intel-fdc.js +1717 -0
- package/src/jsbeeb.css +363 -0
- package/src/keyboard.js +411 -0
- package/src/lib/README +1 -0
- package/src/lib/webgl-debug.js +911 -0
- package/src/main.js +1759 -0
- package/src/microphone-input.js +149 -0
- package/src/models.js +200 -0
- package/src/mouse-joystick-source.js +107 -0
- package/src/music5000-worklet.js +43 -0
- package/src/music5000.js +207 -0
- package/src/scheduler.js +148 -0
- package/src/serial.js +31 -0
- package/src/soundchip.js +314 -0
- package/src/sth.js +59 -0
- package/src/tapes.js +265 -0
- package/src/teletext.js +348 -0
- package/src/teletext_adaptor.js +172 -0
- package/src/teletext_data.js +1064 -0
- package/src/touchscreen.js +86 -0
- package/src/tube.js +349 -0
- package/src/url-params.js +256 -0
- package/src/utils.js +1090 -0
- package/src/via.js +702 -0
- package/src/video-filters/pal-composite.js +94 -0
- package/src/video-filters/passthrough-filter.js +70 -0
- package/src/video-filters/shaders/pal-composite.frag.glsl +147 -0
- package/src/video-filters/shaders/pal-composite.vert.glsl +8 -0
- package/src/video-filters/shaders/passthrough.frag.glsl +6 -0
- package/src/video-filters/shaders/passthrough.vert.glsl +7 -0
- package/src/video.js +794 -0
- package/src/wd-fdc.js +1344 -0
- package/src/web/audio-handler.js +146 -0
- package/src/web/audio-renderer.js +115 -0
- package/src/web/debug.js +529 -0
- package/tests/integration/RmwX.asm +47 -0
- package/tests/integration/TestInstructionsSource +27 -0
- package/tests/integration/TestTimingsResults +27 -0
- package/tests/integration/TestTimingsSource +61 -0
- package/tests/integration/bcd.js +23 -0
- package/tests/integration/dormann.js +101 -0
- package/tests/integration/dp111timing.js +42 -0
- package/tests/integration/ensure-submodules.js +25 -0
- package/tests/integration/nops.bas +119 -0
- package/tests/integration/nops.js +24 -0
- package/tests/integration/protection.js +26 -0
- package/tests/integration/rmw.js +69 -0
- package/tests/integration/teletext/expected_bug_469.png +0 -0
- package/tests/integration/teletext/expected_flash_0.png +0 -0
- package/tests/integration/teletext/expected_flash_1.png +0 -0
- package/tests/integration/teletext/expected_hoglet_held_char.png +0 -0
- package/tests/integration/teletext/expected_reveal_flash_0.png +0 -0
- package/tests/integration/teletext/expected_reveal_flash_1.png +0 -0
- package/tests/integration/teletext.js +126 -0
- package/tests/integration/timings.js +56 -0
- package/tests/integration/via.js +1125 -0
- package/tests/suite/README.md +7 -0
- package/tests/suite/Test Suite 2.15.txt +373 -0
- package/tests/suite/bin/ start +0 -0
- package/tests/suite/bin/adca +0 -0
- package/tests/suite/bin/adcax +0 -0
- package/tests/suite/bin/adcay +0 -0
- package/tests/suite/bin/adcb +0 -0
- package/tests/suite/bin/adcix +0 -0
- package/tests/suite/bin/adciy +0 -0
- package/tests/suite/bin/adcz +0 -0
- package/tests/suite/bin/adczx +0 -0
- package/tests/suite/bin/alrb +0 -0
- package/tests/suite/bin/ancb +0 -0
- package/tests/suite/bin/anda +0 -0
- package/tests/suite/bin/andax +0 -0
- package/tests/suite/bin/anday +0 -0
- package/tests/suite/bin/andb +0 -0
- package/tests/suite/bin/andix +0 -0
- package/tests/suite/bin/andiy +0 -0
- package/tests/suite/bin/andz +0 -0
- package/tests/suite/bin/andzx +0 -0
- package/tests/suite/bin/aneb +0 -0
- package/tests/suite/bin/arrb +0 -0
- package/tests/suite/bin/asla +0 -0
- package/tests/suite/bin/aslax +0 -0
- package/tests/suite/bin/asln +0 -0
- package/tests/suite/bin/aslz +0 -0
- package/tests/suite/bin/aslzx +0 -0
- package/tests/suite/bin/asoa +0 -0
- package/tests/suite/bin/asoax +0 -0
- package/tests/suite/bin/asoay +0 -0
- package/tests/suite/bin/asoix +0 -0
- package/tests/suite/bin/asoiy +0 -0
- package/tests/suite/bin/asoz +0 -0
- package/tests/suite/bin/asozx +0 -0
- package/tests/suite/bin/axsa +0 -0
- package/tests/suite/bin/axsix +0 -0
- package/tests/suite/bin/axsz +0 -0
- package/tests/suite/bin/axszy +0 -0
- package/tests/suite/bin/bccr +0 -0
- package/tests/suite/bin/bcsr +0 -0
- package/tests/suite/bin/beqr +0 -0
- package/tests/suite/bin/bita +0 -0
- package/tests/suite/bin/bitz +0 -0
- package/tests/suite/bin/bmir +0 -0
- package/tests/suite/bin/bner +0 -0
- package/tests/suite/bin/bplr +0 -0
- package/tests/suite/bin/branchwrap +0 -0
- package/tests/suite/bin/brkn +0 -0
- package/tests/suite/bin/bvcr +0 -0
- package/tests/suite/bin/bvsr +0 -0
- package/tests/suite/bin/cia1pb6 +0 -0
- package/tests/suite/bin/cia1pb7 +0 -0
- package/tests/suite/bin/cia1ta +0 -0
- package/tests/suite/bin/cia1tab +0 -0
- package/tests/suite/bin/cia1tb +0 -0
- package/tests/suite/bin/cia1tb123 +0 -0
- package/tests/suite/bin/cia2pb6 +0 -0
- package/tests/suite/bin/cia2pb7 +0 -0
- package/tests/suite/bin/cia2ta +0 -0
- package/tests/suite/bin/cia2tb +0 -0
- package/tests/suite/bin/cia2tb123 +0 -0
- package/tests/suite/bin/clcn +0 -0
- package/tests/suite/bin/cldn +0 -0
- package/tests/suite/bin/clin +0 -0
- package/tests/suite/bin/clvn +0 -0
- package/tests/suite/bin/cmpa +0 -0
- package/tests/suite/bin/cmpax +0 -0
- package/tests/suite/bin/cmpay +0 -0
- package/tests/suite/bin/cmpb +0 -0
- package/tests/suite/bin/cmpix +0 -0
- package/tests/suite/bin/cmpiy +0 -0
- package/tests/suite/bin/cmpz +0 -0
- package/tests/suite/bin/cmpzx +0 -0
- package/tests/suite/bin/cntdef +0 -0
- package/tests/suite/bin/cnto2 +0 -0
- package/tests/suite/bin/cpuport +0 -0
- package/tests/suite/bin/cputiming +0 -0
- package/tests/suite/bin/cpxa +0 -0
- package/tests/suite/bin/cpxb +0 -0
- package/tests/suite/bin/cpxz +0 -0
- package/tests/suite/bin/cpya +0 -0
- package/tests/suite/bin/cpyb +0 -0
- package/tests/suite/bin/cpyz +0 -0
- package/tests/suite/bin/dcma +0 -0
- package/tests/suite/bin/dcmax +0 -0
- package/tests/suite/bin/dcmay +0 -0
- package/tests/suite/bin/dcmix +0 -0
- package/tests/suite/bin/dcmiy +0 -0
- package/tests/suite/bin/dcmz +0 -0
- package/tests/suite/bin/dcmzx +0 -0
- package/tests/suite/bin/deca +0 -0
- package/tests/suite/bin/decax +0 -0
- package/tests/suite/bin/decz +0 -0
- package/tests/suite/bin/deczx +0 -0
- package/tests/suite/bin/dexn +0 -0
- package/tests/suite/bin/deyn +0 -0
- package/tests/suite/bin/eora +0 -0
- package/tests/suite/bin/eorax +0 -0
- package/tests/suite/bin/eoray +0 -0
- package/tests/suite/bin/eorb +0 -0
- package/tests/suite/bin/eorix +0 -0
- package/tests/suite/bin/eoriy +0 -0
- package/tests/suite/bin/eorz +0 -0
- package/tests/suite/bin/eorzx +0 -0
- package/tests/suite/bin/finish +0 -0
- package/tests/suite/bin/flipos +0 -0
- package/tests/suite/bin/icr01 +0 -0
- package/tests/suite/bin/imr +0 -0
- package/tests/suite/bin/inca +0 -0
- package/tests/suite/bin/incax +0 -0
- package/tests/suite/bin/incz +0 -0
- package/tests/suite/bin/inczx +0 -0
- package/tests/suite/bin/insa +0 -0
- package/tests/suite/bin/insax +0 -0
- package/tests/suite/bin/insay +0 -0
- package/tests/suite/bin/insix +0 -0
- package/tests/suite/bin/insiy +0 -0
- package/tests/suite/bin/insz +0 -0
- package/tests/suite/bin/inszx +0 -0
- package/tests/suite/bin/inxn +0 -0
- package/tests/suite/bin/inyn +0 -0
- package/tests/suite/bin/irq +0 -0
- package/tests/suite/bin/jmpi +0 -0
- package/tests/suite/bin/jmpw +0 -0
- package/tests/suite/bin/jsrw +0 -0
- package/tests/suite/bin/lasay +0 -0
- package/tests/suite/bin/laxa +0 -0
- package/tests/suite/bin/laxay +0 -0
- package/tests/suite/bin/laxix +0 -0
- package/tests/suite/bin/laxiy +0 -0
- package/tests/suite/bin/laxz +0 -0
- package/tests/suite/bin/laxzy +0 -0
- package/tests/suite/bin/ldaa +0 -0
- package/tests/suite/bin/ldaax +0 -0
- package/tests/suite/bin/ldaay +0 -0
- package/tests/suite/bin/ldab +0 -0
- package/tests/suite/bin/ldaix +0 -0
- package/tests/suite/bin/ldaiy +0 -0
- package/tests/suite/bin/ldaz +0 -0
- package/tests/suite/bin/ldazx +0 -0
- package/tests/suite/bin/ldxa +0 -0
- package/tests/suite/bin/ldxay +0 -0
- package/tests/suite/bin/ldxb +0 -0
- package/tests/suite/bin/ldxz +0 -0
- package/tests/suite/bin/ldxzy +0 -0
- package/tests/suite/bin/ldya +0 -0
- package/tests/suite/bin/ldyax +0 -0
- package/tests/suite/bin/ldyb +0 -0
- package/tests/suite/bin/ldyz +0 -0
- package/tests/suite/bin/ldyzx +0 -0
- package/tests/suite/bin/loadth +0 -0
- package/tests/suite/bin/lsea +0 -0
- package/tests/suite/bin/lseax +0 -0
- package/tests/suite/bin/lseay +0 -0
- package/tests/suite/bin/lseix +0 -0
- package/tests/suite/bin/lseiy +0 -0
- package/tests/suite/bin/lsez +0 -0
- package/tests/suite/bin/lsezx +0 -0
- package/tests/suite/bin/lsra +0 -0
- package/tests/suite/bin/lsrax +0 -0
- package/tests/suite/bin/lsrn +0 -0
- package/tests/suite/bin/lsrz +0 -0
- package/tests/suite/bin/lsrzx +0 -0
- package/tests/suite/bin/lxab +0 -0
- package/tests/suite/bin/mmu +0 -0
- package/tests/suite/bin/mmufetch +0 -0
- package/tests/suite/bin/nmi +0 -0
- package/tests/suite/bin/nopa +0 -0
- package/tests/suite/bin/nopax +0 -0
- package/tests/suite/bin/nopb +0 -0
- package/tests/suite/bin/nopn +0 -0
- package/tests/suite/bin/nopz +0 -0
- package/tests/suite/bin/nopzx +0 -0
- package/tests/suite/bin/oneshot +0 -0
- package/tests/suite/bin/oraa +0 -0
- package/tests/suite/bin/oraax +0 -0
- package/tests/suite/bin/oraay +0 -0
- package/tests/suite/bin/orab +0 -0
- package/tests/suite/bin/oraix +0 -0
- package/tests/suite/bin/oraiy +0 -0
- package/tests/suite/bin/oraz +0 -0
- package/tests/suite/bin/orazx +0 -0
- package/tests/suite/bin/phan +0 -0
- package/tests/suite/bin/phpn +0 -0
- package/tests/suite/bin/plan +0 -0
- package/tests/suite/bin/plpn +0 -0
- package/tests/suite/bin/rlaa +0 -0
- package/tests/suite/bin/rlaax +0 -0
- package/tests/suite/bin/rlaay +0 -0
- package/tests/suite/bin/rlaix +0 -0
- package/tests/suite/bin/rlaiy +0 -0
- package/tests/suite/bin/rlaz +0 -0
- package/tests/suite/bin/rlazx +0 -0
- package/tests/suite/bin/rola +0 -0
- package/tests/suite/bin/rolax +0 -0
- package/tests/suite/bin/roln +0 -0
- package/tests/suite/bin/rolz +0 -0
- package/tests/suite/bin/rolzx +0 -0
- package/tests/suite/bin/rora +0 -0
- package/tests/suite/bin/rorax +0 -0
- package/tests/suite/bin/rorn +0 -0
- package/tests/suite/bin/rorz +0 -0
- package/tests/suite/bin/rorzx +0 -0
- package/tests/suite/bin/rraa +0 -0
- package/tests/suite/bin/rraax +0 -0
- package/tests/suite/bin/rraay +0 -0
- package/tests/suite/bin/rraix +0 -0
- package/tests/suite/bin/rraiy +0 -0
- package/tests/suite/bin/rraz +0 -0
- package/tests/suite/bin/rrazx +0 -0
- package/tests/suite/bin/rtin +0 -0
- package/tests/suite/bin/rtsn +0 -0
- package/tests/suite/bin/sbca +0 -0
- package/tests/suite/bin/sbcax +0 -0
- package/tests/suite/bin/sbcay +0 -0
- package/tests/suite/bin/sbcb +0 -0
- package/tests/suite/bin/sbcb(eb) +0 -0
- package/tests/suite/bin/sbcix +0 -0
- package/tests/suite/bin/sbciy +0 -0
- package/tests/suite/bin/sbcz +0 -0
- package/tests/suite/bin/sbczx +0 -0
- package/tests/suite/bin/sbxb +0 -0
- package/tests/suite/bin/secn +0 -0
- package/tests/suite/bin/sedn +0 -0
- package/tests/suite/bin/sein +0 -0
- package/tests/suite/bin/shaay +0 -0
- package/tests/suite/bin/shaiy +0 -0
- package/tests/suite/bin/shsay +0 -0
- package/tests/suite/bin/shxay +0 -0
- package/tests/suite/bin/shyax +0 -0
- package/tests/suite/bin/staa +0 -0
- package/tests/suite/bin/staax +0 -0
- package/tests/suite/bin/staay +0 -0
- package/tests/suite/bin/staix +0 -0
- package/tests/suite/bin/staiy +0 -0
- package/tests/suite/bin/staz +0 -0
- package/tests/suite/bin/stazx +0 -0
- package/tests/suite/bin/stxa +0 -0
- package/tests/suite/bin/stxz +0 -0
- package/tests/suite/bin/stxzy +0 -0
- package/tests/suite/bin/stya +0 -0
- package/tests/suite/bin/styz +0 -0
- package/tests/suite/bin/styzx +0 -0
- package/tests/suite/bin/taxn +0 -0
- package/tests/suite/bin/tayn +0 -0
- package/tests/suite/bin/trap1 +0 -0
- package/tests/suite/bin/trap10 +0 -0
- package/tests/suite/bin/trap11 +0 -0
- package/tests/suite/bin/trap12 +0 -0
- package/tests/suite/bin/trap13 +0 -0
- package/tests/suite/bin/trap14 +0 -0
- package/tests/suite/bin/trap15 +0 -0
- package/tests/suite/bin/trap16 +0 -0
- package/tests/suite/bin/trap17 +0 -0
- package/tests/suite/bin/trap2 +0 -0
- package/tests/suite/bin/trap3 +0 -0
- package/tests/suite/bin/trap4 +0 -0
- package/tests/suite/bin/trap5 +0 -0
- package/tests/suite/bin/trap6 +0 -0
- package/tests/suite/bin/trap7 +0 -0
- package/tests/suite/bin/trap8 +0 -0
- package/tests/suite/bin/trap9 +0 -0
- package/tests/suite/bin/tsxn +0 -0
- package/tests/suite/bin/txan +0 -0
- package/tests/suite/bin/txsn +0 -0
- package/tests/suite/bin/tyan +0 -0
- package/tests/suite/cbm-hackers-post.html +178 -0
- package/tests/suite/cbm-hackers-post.md +78 -0
- package/tests/test-machine.js +288 -0
- package/tests/test-suite.js +147 -0
- package/tests/test.css +7 -0
- package/tests/unit/gzip/test-1 +0 -0
- package/tests/unit/gzip/test-1.gz +0 -0
- package/tests/unit/gzip/test-2 +0 -0
- package/tests/unit/gzip/test-2.gz +0 -0
- package/tests/unit/gzip/test-3 +0 -0
- package/tests/unit/gzip/test-3.gz +0 -0
- package/tests/unit/gzip/test-4 +0 -0
- package/tests/unit/gzip/test-4.gz +0 -0
- package/tests/unit/test-adc.js +307 -0
- package/tests/unit/test-bcd.js +30 -0
- package/tests/unit/test-cmos.js +266 -0
- package/tests/unit/test-disc-drive.js +85 -0
- package/tests/unit/test-disc-hfe.js +347 -0
- package/tests/unit/test-disc.js +232 -0
- package/tests/unit/test-fifo.js +35 -0
- package/tests/unit/test-gamepad-source.js +67 -0
- package/tests/unit/test-gzip.js +22 -0
- package/tests/unit/test-intel-fdc.js +93 -0
- package/tests/unit/test-keyboard.js +410 -0
- package/tests/unit/test-mouse-joystick-source.js +128 -0
- package/tests/unit/test-scheduler.js +190 -0
- package/tests/unit/test-serial.js +154 -0
- package/tests/unit/test-teletext-adaptor.js +359 -0
- package/tests/unit/test-tokenise.js +65 -0
- package/tests/unit/test-url-params.js +398 -0
- package/tests/unit/test-utils.js +276 -0
- package/tests/unit/test-video.js +498 -0
- package/tests/unit/test-zip.js +56 -0
- package/tests/unit/zip/test-mixed.zip +0 -0
- package/tests/unit/zip/test-rom.zip +0 -0
- package/tests/unit/zip/test-ssd.zip +0 -0
- package/tools/fir-generator.js +80 -0
- package/tools/vite-plugin-fir-shader.js +131 -0
- 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
|
package/eslint.config.js
ADDED
|
@@ -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
|
+
];
|