badline 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +185 -0
- data/CLAUDE.md +217 -0
- data/CODE_OF_CONDUCT.md +92 -0
- data/CONTRIBUTING.md +51 -0
- data/README.md +224 -31
- data/doc/pinned-behaviour.md +1117 -0
- data/exe/badline +22 -2
- data/exe/badline-sid +34 -0
- data/lib/badline/address_bus.rb +96 -25
- data/lib/badline/audio/aiff.rb +36 -0
- data/lib/badline/audio/bare_player.rb +129 -0
- data/lib/badline/audio/cli.rb +133 -0
- data/lib/badline/audio/console.rb +75 -0
- data/lib/badline/audio/jukebox.rb +82 -0
- data/lib/badline/audio/machine_player.rb +57 -0
- data/lib/badline/audio/options.rb +137 -0
- data/lib/badline/audio/pcm_writer.rb +57 -0
- data/lib/badline/audio/playback.rb +108 -0
- data/lib/badline/audio/renderer.rb +85 -0
- data/lib/badline/audio/sdl_sink.rb +102 -0
- data/lib/badline/audio/wav.rb +23 -0
- data/lib/badline/audio.rb +14 -0
- data/lib/badline/cartridge/action_replay.rb +111 -0
- data/lib/badline/cartridge/atomic_power.rb +24 -0
- data/lib/badline/cartridge/bank.rb +81 -0
- data/lib/badline/cartridge/comal80.rb +48 -0
- data/lib/badline/cartridge/dinamic.rb +34 -0
- data/lib/badline/cartridge/easy_flash.rb +122 -0
- data/lib/badline/cartridge/epyx_fastload.rb +71 -0
- data/lib/badline/cartridge/final_cartridge3.rb +77 -0
- data/lib/badline/cartridge/flash.rb +265 -0
- data/lib/badline/cartridge/freezer.rb +31 -0
- data/lib/badline/cartridge/fun_play.rb +38 -0
- data/lib/badline/cartridge/g_mod2.rb +62 -0
- data/lib/badline/cartridge/game_system.rb +40 -0
- data/lib/badline/cartridge/kcs_power.rb +72 -0
- data/lib/badline/cartridge/mach5.rb +34 -0
- data/lib/badline/cartridge/magic_desk.rb +6 -3
- data/lib/badline/cartridge/ocean.rb +11 -12
- data/lib/badline/cartridge/pagefox.rb +56 -0
- data/lib/badline/cartridge/retro_replay.rb +276 -0
- data/lib/badline/cartridge/rex_utility.rb +33 -0
- data/lib/badline/cartridge/rgcd.rb +48 -0
- data/lib/badline/cartridge/simons_basic.rb +40 -0
- data/lib/badline/cartridge/standard.rb +3 -19
- data/lib/badline/cartridge/super_games.rb +36 -0
- data/lib/badline/cartridge/westermann.rb +34 -0
- data/lib/badline/cartridge/zaxxon.rb +50 -0
- data/lib/badline/cartridge.rb +132 -16
- data/lib/badline/cia/interrupt_register.rb +102 -0
- data/lib/badline/cia/serial.rb +219 -0
- data/lib/badline/cia/timer.rb +43 -31
- data/lib/badline/cia.rb +138 -88
- data/lib/badline/color_memory.rb +14 -5
- data/lib/badline/computer.rb +97 -12
- data/lib/badline/control_ports.rb +54 -9
- data/lib/badline/cpu/addressing.rb +131 -0
- data/lib/badline/cpu/microcode.rb +169 -0
- data/lib/badline/cpu/operations.rb +88 -0
- data/lib/badline/cpu/stack_operations.rb +82 -0
- data/lib/badline/cpu.rb +109 -168
- data/lib/badline/cycleable.rb +3 -0
- data/lib/badline/datasette.rb +81 -0
- data/lib/badline/debug_register.rb +28 -0
- data/lib/badline/gui/application.rb +79 -18
- data/lib/badline/gui/gamepads.rb +97 -0
- data/lib/badline/gui/joy_map.rb +15 -7
- data/lib/badline/gui.rb +1 -0
- data/lib/badline/input/mouse1351.rb +41 -0
- data/lib/badline/input/paddles.rb +36 -0
- data/lib/badline/input.rb +4 -0
- data/lib/badline/instruction_set/arithmetic.rb +16 -21
- data/lib/badline/instruction_set/bitwise.rb +17 -22
- data/lib/badline/instruction_set/branch.rb +20 -19
- data/lib/badline/instruction_set/flag.rb +7 -7
- data/lib/badline/instruction_set/illegal.rb +14 -22
- data/lib/badline/instruction_set/inc_dec.rb +8 -10
- data/lib/badline/instruction_set/stack.rb +5 -57
- data/lib/badline/instruction_set/transfer.rb +9 -9
- data/lib/badline/instruction_set.rb +9 -31
- data/lib/badline/interrupts.rb +104 -0
- data/lib/badline/joystick.rb +9 -9
- data/lib/badline/kernal_trap/channel.rb +51 -0
- data/lib/badline/kernal_trap/drive/status.rb +49 -0
- data/lib/badline/kernal_trap/drive.rb +277 -0
- data/lib/badline/kernal_trap/file.rb +5 -25
- data/lib/badline/kernal_trap/load.rb +86 -24
- data/lib/badline/kernal_trap/routine.rb +51 -0
- data/lib/badline/kernal_trap/save.rb +46 -14
- data/lib/badline/kernal_trap/serial.rb +171 -0
- data/lib/badline/kernal_trap.rb +4 -0
- data/lib/badline/keyboard.rb +40 -16
- data/lib/badline/media.rb +48 -10
- data/lib/badline/memory.rb +5 -0
- data/lib/badline/roms/eapi/LICENSE.md +15 -0
- data/lib/badline/roms/eapi/README +41 -0
- data/lib/badline/roms/eapi/eapi-am29f040-14 +0 -0
- data/lib/badline/sid/decimator.rb +46 -0
- data/lib/badline/sid/envelope.rb +232 -0
- data/lib/badline/sid/filter.rb +213 -0
- data/lib/badline/sid/voice.rb +61 -0
- data/lib/badline/sid/waveform/combined.rb +126 -0
- data/lib/badline/sid/waveform/fast_forward.rb +105 -0
- data/lib/badline/sid/waveform/noise_writeback.rb +82 -0
- data/lib/badline/sid/waveform.rb +289 -0
- data/lib/badline/sid.rb +274 -7
- data/lib/badline/status.rb +251 -23
- data/lib/badline/storage/crt_file.rb +18 -2
- data/lib/badline/storage/d64_image.rb +6 -0
- data/lib/badline/storage/d71_image.rb +4 -0
- data/lib/badline/storage/d81_image.rb +4 -0
- data/lib/badline/storage/disk_image.rb +99 -13
- data/lib/badline/storage/host_directory.rb +30 -4
- data/lib/badline/storage/sid_file.rb +274 -0
- data/lib/badline/storage/song_lengths.rb +65 -0
- data/lib/badline/storage/t64.rb +67 -0
- data/lib/badline/storage/tap.rb +68 -0
- data/lib/badline/storage.rb +19 -0
- data/lib/badline/time_of_day.rb +105 -52
- data/lib/badline/version.rb +1 -1
- data/lib/badline/vic/bank.rb +14 -6
- data/lib/badline/vic/border_mask.rb +76 -0
- data/lib/badline/vic/collisions.rb +104 -0
- data/lib/badline/vic/color_patches.rb +33 -0
- data/lib/badline/vic/display_state.rb +92 -29
- data/lib/badline/vic/graphics_mode.rb +78 -53
- data/lib/badline/vic/graphics_shifter.rb +140 -0
- data/lib/badline/vic/register_log.rb +63 -0
- data/lib/badline/vic/registers.rb +3 -0
- data/lib/badline/vic/sequencer.rb +163 -137
- data/lib/badline/vic/sequencer_output.rb +116 -0
- data/lib/badline/vic/sprite/internal_bus.rb +49 -0
- data/lib/badline/vic/sprite/shifter.rb +129 -0
- data/lib/badline/vic/sprite.rb +275 -65
- data/lib/badline/vic/sprites.rb +220 -58
- data/lib/badline/vic.rb +389 -55
- data/lib/badline.rb +5 -0
- data/vendor/.gitkeep +0 -0
- metadata +104 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7150f883c604da9d4f9bd4712412a020f9352dbbdba08a5051fee95e7f8bce30
|
|
4
|
+
data.tar.gz: cac44823e8c8afcc4637ad40383da5c624f51d29a60a45084b2ba6b81d6ae68e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d09600dbf17cfa3df1d32e6ca5b8b25cd6f3cb012fd54c0cc0f7a4f700d98aaa45e9b0ba6cde95fa6c37e7310368f692e75c0f332f55fad84c5181a07df5da61
|
|
7
|
+
data.tar.gz: e3b2796713ab7701ab0a536276b6e845bb1751586c7706bdbe19a918129bb978927aef395062c98331c493af515a8ef77455446ca21289e434360753bf1aa89a
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.2.1](https://github.com/elektronaut/badline/compare/v0.2.0...v0.2.1) (2026-09-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* decode U commands by the 1541's user table index ([4d37a92](https://github.com/elektronaut/badline/commit/4d37a928f9109d8214294fdac21bce25f201549b))
|
|
9
|
+
* detect disk image error tables by exact image size ([baa2091](https://github.com/elektronaut/badline/commit/baa20918b345723003ff61936c791f476e478fe8))
|
|
10
|
+
* detect the error table on 42-track D64 images ([9d8be41](https://github.com/elektronaut/badline/commit/9d8be41ffd23f0984f26e8e2c3ec0ba692629df9))
|
|
11
|
+
* end a SAVE the host directory can't write like a failed drive write ([4d15efe](https://github.com/elektronaut/badline/commit/4d15efe815d809fb7eba84cc9d59aebb4964f4ad))
|
|
12
|
+
* fail writes to a disk image like a write-protected 1541 ([c4ccb46](https://github.com/elektronaut/badline/commit/c4ccb46382166a896875a4f081c13db7841aaf7d))
|
|
13
|
+
* hand LOADs that reach below $0334 to the ROM's byte loop ([948b816](https://github.com/elektronaut/badline/commit/948b8163d0ba16d4eb4c71ee03ab4fe59297ba56))
|
|
14
|
+
* power-cycle the machine when a cartridge is attached ([2e1d7a4](https://github.com/elektronaut/badline/commit/2e1d7a472f00e0ccbd7a3245db7c685162e40786))
|
|
15
|
+
* print the KERNAL's SAVING message from the SAVE trap ([c912986](https://github.com/elektronaut/badline/commit/c912986e1702ba9907a097aaebd62b36e83b1fe5))
|
|
16
|
+
* print the KERNAL's SEARCHING and LOADING messages from the LOAD trap ([fc7e719](https://github.com/elektronaut/badline/commit/fc7e719e0856b8eddafbb96402893570cf757842))
|
|
17
|
+
* report the DOS version on the command channel at drive power-on ([016ad3f](https://github.com/elektronaut/badline/commit/016ad3f884a2fb1160f30372acd1ae972d0b9702))
|
|
18
|
+
* reset the virtual drive on the U-command reset forms ([a558314](https://github.com/elektronaut/badline/commit/a558314e7f116a28c8341ca82acce65c94469b9d))
|
|
19
|
+
* stop LOADs and file reads at a block the error table marks bad ([457be18](https://github.com/elektronaut/badline/commit/457be18351af7241a26f76631ec9bfad0ce2306e))
|
|
20
|
+
|
|
21
|
+
## [0.2.0](https://github.com/elektronaut/badline/compare/v0.1.0...v0.2.0) (2026-09-23)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Features
|
|
25
|
+
|
|
26
|
+
* add the Action Replay, Retro Replay and Final Cartridge III freezers ([7f4a8ba](https://github.com/elektronaut/badline/commit/7f4a8ba83aee493f22e1bcf8eec03b786ec8b119))
|
|
27
|
+
* add the KCS Power Cartridge (type 2) ([18c3fec](https://github.com/elektronaut/badline/commit/18c3feca3308a8bbe850a3618a7a9fac0eb0df8b))
|
|
28
|
+
* add the Retro Replay's flash mode on the Am29F010 ([4ad4001](https://github.com/elektronaut/badline/commit/4ad40013f5c563a3b94a951881f4b19b70d332e3))
|
|
29
|
+
* **audio:** default the render length from HVSC's song lengths ([5ab7678](https://github.com/elektronaut/badline/commit/5ab76785770bb6386618b531b225b19f477c4cb9))
|
|
30
|
+
* **audio:** render .sid tunes to WAV and AIFF offline ([913c927](https://github.com/elektronaut/badline/commit/913c9274fbf7571d190024a95b9aa0d52ffb5400))
|
|
31
|
+
* bundle EAPI and swap it into EasyFlash cartridges ([421fed1](https://github.com/elektronaut/badline/commit/421fed11d80fcd98a37a69b38a86de56d88c5e2c))
|
|
32
|
+
* carry the Lorenz chain onto Disk4.d64 ([cec8f18](https://github.com/elektronaut/badline/commit/cec8f1867a49d907133f2d9c2b8610aa0ea25a9c))
|
|
33
|
+
* **cartridge:** 15 more CRT hardware types, EasyFlash and Epyx FastLoad included ([8c58b02](https://github.com/elektronaut/badline/commit/8c58b023c2b3b4949a9f401b4c332bed177e78e2))
|
|
34
|
+
* **cartridge:** bank-switching mappers ([4a3c3ee](https://github.com/elektronaut/badline/commit/4a3c3eebc578c03859a86cda39c1f423d6c138f3))
|
|
35
|
+
* **cartridge:** EasyFlash ([d57f5c3](https://github.com/elektronaut/badline/commit/d57f5c3aa117eb8a50f958d8e30b3ccffa962212))
|
|
36
|
+
* **cartridge:** Epyx FastLoad ([6c9a5a4](https://github.com/elektronaut/badline/commit/6c9a5a4a6016335ed2fd4d015a99f02814864eb2))
|
|
37
|
+
* **cartridge:** Pagefox ([6c80f47](https://github.com/elektronaut/badline/commit/6c80f472638cdaed40df0152e0a3b74214c1ed6b))
|
|
38
|
+
* **cartridge:** Simons' BASIC, Westermann, Rex Utility and Mach 5 ([1ece033](https://github.com/elektronaut/badline/commit/1ece0338fb7b2128bca530d9cd92a5da6906f2cd))
|
|
39
|
+
* **cia:** model the CNT pin, serial port and TOD divider ([dd6d17a](https://github.com/elektronaut/badline/commit/dd6d17a02a2421e88de2d642852adf448aa393fd))
|
|
40
|
+
* **cia:** trigger the light pen from control port 1's fire line ([a4059d2](https://github.com/elektronaut/badline/commit/a4059d268a3402d1324f770edb35293aacdfcdb4))
|
|
41
|
+
* **cpu:** let SH* and ANE see VIC stalls ([84bc62b](https://github.com/elektronaut/badline/commit/84bc62b912c07892db2921104b1677e00e0deeeb))
|
|
42
|
+
* **cpu:** model the dummy reads on internal cycles ([a34c37b](https://github.com/elektronaut/badline/commit/a34c37bd79ddb0c749aedafe65e1455cd4df9a38))
|
|
43
|
+
* **cpu:** per-cycle interrupt polling with VIC raster-IRQ recalibration ([056e235](https://github.com/elektronaut/badline/commit/056e23554efb7026f3b58d3a25868fbc20c5c442))
|
|
44
|
+
* fit and score the combined waveform model against real-chip dumps ([232cab2](https://github.com/elektronaut/badline/commit/232cab2a7088204f8eb10c962264cc94ac872786))
|
|
45
|
+
* **gui:** add host gamepads and pointer input modes ([3fc5904](https://github.com/elektronaut/badline/commit/3fc5904d9cdf11b6bdd3461cca7d11f77200184b))
|
|
46
|
+
* **gui:** offer the mouse and paddles on either control port ([4d678e5](https://github.com/elektronaut/badline/commit/4d678e50c51131d0f00b12f1832875b654adcf21))
|
|
47
|
+
* **input:** add joystick 1 on CIA 1 port B ([05465b4](https://github.com/elektronaut/badline/commit/05465b4f5d3e0642dcb1967d1e2419c8c7647c2d))
|
|
48
|
+
* **input:** add paddles, a 1351 mouse and the CIA 1 POT mux ([85e079f](https://github.com/elektronaut/badline/commit/85e079f86a451fefaf11c2aa7cd9127bd538003a))
|
|
49
|
+
* **keyboard:** scan the matrix in both directions ([6a258db](https://github.com/elektronaut/badline/commit/6a258db51b813ddbb9f99f0727d1a9b7c65502b6))
|
|
50
|
+
* play .sid tunes live in badline-sid ([9ad32ed](https://github.com/elektronaut/badline/commit/9ad32edde74a8321f4d0ea81007b4e6b2051e976))
|
|
51
|
+
* **rake:** resume a killed testbench suite run with RESUME=1 ([d907434](https://github.com/elektronaut/badline/commit/d907434763760f62c8295c39e60ec795311528cc))
|
|
52
|
+
* **rake:** run the Lorenz chain as four stretches ([a7be7e1](https://github.com/elektronaut/badline/commit/a7be7e1efe022700190ad88042af781e6038c80e))
|
|
53
|
+
* rename badline-render to badline-sid ([74a832f](https://github.com/elektronaut/badline/commit/74a832fc682e2ae117eec529d35289a59acacbd8))
|
|
54
|
+
* rename badline-render to badline-sid, with -o and -s options ([68ff4c0](https://github.com/elektronaut/badline/commit/68ff4c01bed0571122145b28785b9a70e31698e2))
|
|
55
|
+
* **render:** add --filter-chunk to trade filter exactness for speed ([d5e037c](https://github.com/elektronaut/badline/commit/d5e037cfb0ebdfd8a448b3977e1715573da6cc0e))
|
|
56
|
+
* Retro Replay flash mode ([a4e444f](https://github.com/elektronaut/badline/commit/a4e444f215b0920f24c4d98e06f9b2ea65b6d9ff))
|
|
57
|
+
* run the testbench's cartridge rows as testbench-carts ([2003835](https://github.com/elektronaut/badline/commit/2003835226e4d7e11363356bcd2c978a6d91f986))
|
|
58
|
+
* run the testbench's cartridge rows with --carts ([3f9ec9c](https://github.com/elektronaut/badline/commit/3f9ec9c6cd8bc7ab2b70fd578fde0831ed42a0bc))
|
|
59
|
+
* select the 8580 and connect the paddle fire buttons ([05f8d1c](https://github.com/elektronaut/badline/commit/05f8d1cbd90212f7a30f44df51bee7d05a5e1a4e))
|
|
60
|
+
* **sid:** add the 6581 synthesis core ([3748c99](https://github.com/elektronaut/badline/commit/3748c994cdd708c1937de8757b8e49c23c04f4fe))
|
|
61
|
+
* **sid:** back-fill the idle DSP and add the 8580 chip model ([b0f8fef](https://github.com/elektronaut/badline/commit/b0f8fef6c57578fdced09de7a2853e6d6cf222e9))
|
|
62
|
+
* **sid:** fitted combined waveform shapes and a one-cycle pulse lag ([c9df98a](https://github.com/elektronaut/badline/commit/c9df98ab6e31619c5a3c36f776cf8ed2824be18e))
|
|
63
|
+
* **sid:** model combined waveform feedback and the floating waveform-0 DAC ([a0d4286](https://github.com/elektronaut/badline/commit/a0d4286b237d7919e0009c4d88ea703cc3337345))
|
|
64
|
+
* **sid:** model register read semantics and the paddle inputs ([ef00ef9](https://github.com/elektronaut/badline/commit/ef00ef9a34d5bac696f1b8c47618c403847a1987))
|
|
65
|
+
* **sid:** model the board's RC filter and the 8580 cutoff curve ([f6038ac](https://github.com/elektronaut/badline/commit/f6038ac54188f4a0a9cdf5ff3d97b5ea668682c6))
|
|
66
|
+
* **sid:** pick the subtune to play with --song ([f896627](https://github.com/elektronaut/badline/commit/f896627db8f1f83fe6328d415ef999d2924ff0dd))
|
|
67
|
+
* **sid:** select the 8580 from a tune's header or --sid ([9b1267a](https://github.com/elektronaut/badline/commit/9b1267a0643c062e512eaeef7a3ad356dc7a2827))
|
|
68
|
+
* **sid:** shape combined waveforms from a fitted line-coupling model ([c12f707](https://github.com/elektronaut/badline/commit/c12f7074daba13664066d8e8346dea05bf5f1d5e))
|
|
69
|
+
* step between songs and pause from the terminal in badline-sid ([a1facca](https://github.com/elektronaut/badline/commit/a1facca9d87d7e6be040e2ff3e88f3617ba4b6f8))
|
|
70
|
+
* **storage:** play .sid tunes through a raster-timed player stub ([75ec9fc](https://github.com/elektronaut/badline/commit/75ec9fce5104d95c8bfc39067f62962f9f9eda3f))
|
|
71
|
+
* **storage:** play .tap datasette streams ([d9dc69e](https://github.com/elektronaut/badline/commit/d9dc69eef1ad9c4fbd65290127cee4d210045717))
|
|
72
|
+
* **storage:** serve .t64 archives from mounted directories ([f03a988](https://github.com/elektronaut/badline/commit/f03a988a3482952cad459bf71962c235fec2e728))
|
|
73
|
+
* **storage:** serve .t64 tape archives through the LOAD trap ([7e4faa7](https://github.com/elektronaut/badline/commit/7e4faa7183ae7446caf07f6103e2aced9f39f6c1))
|
|
74
|
+
* **storage:** serve device 8 over trapped serial bus primitives ([4a6ec70](https://github.com/elektronaut/badline/commit/4a6ec7006bdcdc459e3cfc76a379ca2bfc249edc))
|
|
75
|
+
* terminal display for badline-sid playback ([edc37ac](https://github.com/elektronaut/badline/commit/edc37ac758d8e1760475d16b4e89c1e077467870))
|
|
76
|
+
* **testbench:** keep finished rows when a run is killed, and --resume from them ([3155e41](https://github.com/elektronaut/badline/commit/3155e41bf7171c94993f870c60ffb349e6e80a9b))
|
|
77
|
+
* **test:** guard the headless suites with tracked baselines ([7bc4df0](https://github.com/elektronaut/badline/commit/7bc4df05dfaeb89b24d05e2962a85d9a7295df54))
|
|
78
|
+
* **test:** select the SID model in bin/sidtests ([dcc55d0](https://github.com/elektronaut/badline/commit/dcc55d00fce90744c0d21d6797d9d4f5c4a27d0e))
|
|
79
|
+
* **vic:** cycle-accurate border, sprite timing, idle graphics and light pen ([e67ee00](https://github.com/elektronaut/badline/commit/e67ee0082229b292d230d5ea15b4b9a68201a881))
|
|
80
|
+
* **vic:** model bad-line DMA delay and the BA-to-AEC fetch gap ([529b5ca](https://github.com/elektronaut/badline/commit/529b5caad882dc306313e9cd2d6edbf8956a1e75))
|
|
81
|
+
* **vic:** replay sprite registers through a per-pixel sequencer ([91be311](https://github.com/elektronaut/badline/commit/91be3115fc1701b3a3894ab2e2a560fdf3705642))
|
|
82
|
+
* write EasyFlash and GMod2 flash through the Am29F040 command set ([690e6f2](https://github.com/elektronaut/badline/commit/690e6f256071018f4413cacdd126eaee55c7f784))
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
### Bug Fixes
|
|
86
|
+
|
|
87
|
+
* cartridge-visible power-on state and 16K PLA mapping ([d971f72](https://github.com/elektronaut/badline/commit/d971f72105a09f70c10646a1388ac52b3d03d680))
|
|
88
|
+
* **cia:** count the shift register empty at the eighth bit ([a1d2fd1](https://github.com/elektronaut/badline/commit/a1d2fd1fa3a7f72a02adf98f1c8874c64b39cf1f))
|
|
89
|
+
* **cia:** count timer B's cascade input through the enable pipeline ([c7d6439](https://github.com/elektronaut/badline/commit/c7d6439495a5ffb790fe6c79a500a4cec6d996e9))
|
|
90
|
+
* **cia:** load the timer latch on the underflow tick ([2be77c1](https://github.com/elektronaut/badline/commit/2be77c152d1572763dac70a27e62cf6d57d38bba))
|
|
91
|
+
* **cia:** model the 6526 ICR acknowledge timing and timer B bug ([7422b13](https://github.com/elektronaut/badline/commit/7422b1380445625e13a787773ca8b3296f4aa429))
|
|
92
|
+
* **cia:** port the TOD clock's digit counters, alarm compare and divider ([c301ec5](https://github.com/elektronaut/badline/commit/c301ec5140d37a38f559d254bce44d0e264087d9))
|
|
93
|
+
* **cia:** port the TOD digit counters, alarm compare and divider ([5ad8000](https://github.com/elektronaut/badline/commit/5ad8000be779792f6d5b98ff9e6af21f64a95b01))
|
|
94
|
+
* **cia:** power the timer latches and counters on at $ffff ([611fdb6](https://github.com/elektronaut/badline/commit/611fdb61f4c839555549cd44420d8ee06a53636d))
|
|
95
|
+
* **cpu:** halt on JAM until reset ([c262d3e](https://github.com/elektronaut/badline/commit/c262d3eb4c1bdf1325169e8c10d762bc7bcd4326))
|
|
96
|
+
* **cpu:** keep sampling the interrupt lines while the VIC stalls the CPU ([d313090](https://github.com/elektronaut/badline/commit/d313090436c8397a61dd18d86b80d18aaf41507f))
|
|
97
|
+
* **crt:** ignore trailing bytes too short for a CHIP header ([bbb9b09](https://github.com/elektronaut/badline/commit/bbb9b09aa71dea4fa457f3b3cafd33fe93e99e22))
|
|
98
|
+
* give the SID's noise combinations their own writeback shape ([b87da71](https://github.com/elektronaut/badline/commit/b87da7196f7ffe6853fc007c10b2b2f07051071d))
|
|
99
|
+
* **input:** wire the host mouse buttons to the paddle fire lines ([171ae1e](https://github.com/elektronaut/badline/commit/171ae1e3a8db4a5a29eb1ff1621026e056bdebef))
|
|
100
|
+
* keep the SID's accumulators across a reset ([e066262](https://github.com/elektronaut/badline/commit/e06626225374214c5db3f058e78fb3f3571b32b6))
|
|
101
|
+
* **keyboard:** add the missing F5 key to the matrix ([702a0bb](https://github.com/elektronaut/badline/commit/702a0bbd520a47232d1aa677d25aef6108c44426))
|
|
102
|
+
* map RAM at $d000 in 16K mode while only LORAM is set ([01aaff0](https://github.com/elektronaut/badline/commit/01aaff07fb1d61d0f1ed627360f93bbd6b4f98ad))
|
|
103
|
+
* map the Nordic Replay's RAM at $A000 while frozen in Ultimax mode ([3a2215c](https://github.com/elektronaut/badline/commit/3a2215c6e0b69a908f5da2b63ef013dcf27b6a91))
|
|
104
|
+
* open SEQ and USR files on a disk image by their type ([8a0c0b0](https://github.com/elektronaut/badline/commit/8a0c0b055acaeead2ab5eb10ab6992e5a59dbcaa))
|
|
105
|
+
* pace CIA-timed PSID songs off CIA 1 timer A ([a7702fc](https://github.com/elektronaut/badline/commit/a7702fcca61a027a8bfbe6b231f3ddf5267f0f62))
|
|
106
|
+
* pace CIA-timed PSID songs off CIA 1 timer A on the bare rig ([dd8ec20](https://github.com/elektronaut/badline/commit/dd8ec20926c96c0b587aa74fca0a099cbdf4aa0d))
|
|
107
|
+
* pipeline the SID envelope as reSID 1.0 does ([25505ce](https://github.com/elektronaut/badline/commit/25505ced0e202e6b54d9f42d442ce604f541d5b8))
|
|
108
|
+
* power the CIA ports on with every register cleared ([20c12e8](https://github.com/elektronaut/badline/commit/20c12e8a4d85d3c94f630d697f59061c500415eb))
|
|
109
|
+
* power the CPU port on with both registers cleared ([8ba1be9](https://github.com/elektronaut/badline/commit/8ba1be9882cddc69bea9a85b8118a00faa1b3eda))
|
|
110
|
+
* read open bus from the unmapped Ultimax address space ([efcadf6](https://github.com/elektronaut/badline/commit/efcadf6ec742fff40f671e361e3805e8b3c03eb4))
|
|
111
|
+
* read the VIC's phi1 byte from unconnected I/O ([0dda282](https://github.com/elektronaut/badline/commit/0dda2821773b44b63d7181a89c6429087c1b4432))
|
|
112
|
+
* refuse multi-SID and MUS-flag .sid files ([f3c7da6](https://github.com/elektronaut/badline/commit/f3c7da645da714f2409ecbdf50357cb92411d115))
|
|
113
|
+
* report the error table's read errors on block reads ([065f62c](https://github.com/elektronaut/badline/commit/065f62c25811c403f49d094ff1984617e4ffce80))
|
|
114
|
+
* report unreadable media without a backtrace ([9c75c79](https://github.com/elektronaut/badline/commit/9c75c797607d02319ddb77a6a569cc89ea4cf91f))
|
|
115
|
+
* reset the bank-switching mappers' registers on RES ([39c071d](https://github.com/elektronaut/badline/commit/39c071d29bcf9f21e9b8d17e2665f52c86a66811))
|
|
116
|
+
* reset the CIAs, SID and CPU port when a cartridge is attached ([8264966](https://github.com/elektronaut/badline/commit/826496674243ea6d2661d89fc83ee46b3a791ff0))
|
|
117
|
+
* return open bus in colour RAM's upper nibble ([6e8348e](https://github.com/elektronaut/badline/commit/6e8348eae92014c1a48f8ac93ce14c0a88a92eb4))
|
|
118
|
+
* run the chip-agnostic SID testprogs on the 8580 as well ([77918a8](https://github.com/elektronaut/badline/commit/77918a82fc617a65fd6f62adaa82c9d86266e6c9))
|
|
119
|
+
* serve M-W and M-R from drive RAM and run read jobs ([81561dc](https://github.com/elektronaut/badline/commit/81561dc4a3eeda648439bbb65bb6d9dca8995574))
|
|
120
|
+
* serve the DOS B-R block read on the virtual drive ([cdeb085](https://github.com/elektronaut/badline/commit/cdeb08579f0dea239f6fe7aba8ef613e832918a0))
|
|
121
|
+
* **sid:** bank the ROMs out around a tune's init and play ([b664987](https://github.com/elektronaut/badline/commit/b664987a0016a6423365a069703041950007b0a5))
|
|
122
|
+
* **sid:** carry fractional bits through the filter integrators ([73bac1c](https://github.com/elektronaut/badline/commit/73bac1c81ed1d19bcfefe34987d8db2df1386558))
|
|
123
|
+
* **sid:** feed the RC network the filter's fractional mix ([9e670c0](https://github.com/elektronaut/badline/commit/9e670c0bb23373a007049356df5537127a61afa4))
|
|
124
|
+
* **sid:** keep a playing tune from returning to BASIC ([de49325](https://github.com/elektronaut/badline/commit/de49325026588a584fc71a144d1c58338780b56f))
|
|
125
|
+
* **sid:** let the test bit bleed the noise LFSR as slowly as real chips do ([3d95639](https://github.com/elektronaut/badline/commit/3d95639c51b8ec802790d1811a902d95910c44bc))
|
|
126
|
+
* **sid:** reach the output with the pulse a cycle after its compare ([b1bf3eb](https://github.com/elektronaut/badline/commit/b1bf3eb4f8d37dd9182943e2b0388da485aefe67))
|
|
127
|
+
* **sid:** read the 8580's triangle and sawtooth a cycle late on OSC3 ([96ece2b](https://github.com/elektronaut/badline/commit/96ece2bb7489ced2979b785015839c25701e20e5))
|
|
128
|
+
* **sid:** shift the noise LFSR two cycles after bit 19 rises ([b143001](https://github.com/elektronaut/badline/commit/b1430016117333706b3b159e02ce6a0a509c8f9e))
|
|
129
|
+
* **sid:** write the LFSR back on test release only for some waveform changes ([0ca3afb](https://github.com/elektronaut/badline/commit/0ca3afb02ce3873b6a3c6204ee6a044f626bd6da))
|
|
130
|
+
* stop testbench shards when the runner is killed ([0c05c3e](https://github.com/elektronaut/badline/commit/0c05c3e69c115bdb439f70949771876426f9491b))
|
|
131
|
+
* strip the type and mode fields from LOAD and SAVE names ([f09aab3](https://github.com/elektronaut/badline/commit/f09aab3bbf9dbb68267f4ec9d438b98669bbf499))
|
|
132
|
+
* **vic:** 40-column side border compares see CSEL a pixel late ([b9a1904](https://github.com/elektronaut/badline/commit/b9a19043b256cb2990914c7ce09dc1d28f7a9807))
|
|
133
|
+
* **vic:** colour the c-accesses before AEC from the halted CPU's bus ([4661fa3](https://github.com/elektronaut/badline/commit/4661fa34b6663ba7eed7acb6c35e7d7656717d44))
|
|
134
|
+
* **vic:** compare the vertical border in every cycle of its line ([fcde974](https://github.com/elektronaut/badline/commit/fcde974487320ea1ebee69ede2e5104f0775b045))
|
|
135
|
+
* **vic:** crunch sprites on a $d017 clear in cycle 15 ([11d15ef](https://github.com/elektronaut/badline/commit/11d15ef499314b2011ca71cda5746a23c5ea0ec5))
|
|
136
|
+
* **vic:** delay the line 0 raster read by a cycle ([3f4fddc](https://github.com/elektronaut/badline/commit/3f4fddc378b08af2127401497e1a3ee7d07686ae))
|
|
137
|
+
* **vic:** hold a falling ECM for a g-access that leaves the character ROM ([4a4a9b0](https://github.com/elektronaut/badline/commit/4a4a9b0cd1d8b71a2d640cf590bdae71593a3246))
|
|
138
|
+
* **vic:** hold a falling ECM for the g-access that leaves the character ROM ([ffe9a6f](https://github.com/elektronaut/badline/commit/ffe9a6fcf0e44a4457e8bd100009d980bde47439))
|
|
139
|
+
* **vic:** latch sprite collisions per pixel and match Y in eight bits ([8495ed8](https://github.com/elektronaut/badline/commit/8495ed80ddd22555979b5ea310b10416119c1126))
|
|
140
|
+
* **vic:** latch the raster IRQ only as the compare comes to match ([62ccc11](https://github.com/elektronaut/badline/commit/62ccc114420fe8837fbb3794e316bd22a1440bf5))
|
|
141
|
+
* **vic:** let the 40-column side border compares see CSEL a pixel late ([65fe47f](https://github.com/elektronaut/badline/commit/65fe47fda7acbc90304c181e01818147ace711e0))
|
|
142
|
+
* **vic:** model the sprite reload, its dead window and the display end ([e36219e](https://github.com/elektronaut/badline/commit/e36219e8ce7032fd9cd7e387ec6a14e4d1454001))
|
|
143
|
+
* **vic:** move bad-line and sprite BA to the cycles the CPU sees them ([b8c8583](https://github.com/elektronaut/badline/commit/b8c8583343975a2f04224e58a6d5edce488d459a))
|
|
144
|
+
* **vic:** raise the collision IRQ on the cycle that draws the pixel ([e81090b](https://github.com/elektronaut/badline/commit/e81090bf0944ba33074e6c8a7121335cb45f9e0d))
|
|
145
|
+
* **vic:** re-phase the display state to Bauer's cycles in the CPU's frame ([95381ef](https://github.com/elektronaut/badline/commit/95381ef765353bcbbb6b69962e9f7b23fa76018e))
|
|
146
|
+
* **vic:** read g-accesses in their column and shift graphics per pixel ([4cf1841](https://github.com/elektronaut/badline/commit/4cf1841351eee05cbddc979071afdd46460bfe71))
|
|
147
|
+
* **vic:** read line 311 from $d011/$d012 until line 0's compare cycle ([01fb629](https://github.com/elektronaut/badline/commit/01fb6291768c50c3d0fdfa137c9ffb6bfc379802))
|
|
148
|
+
* **vic:** run the vertical border and raster IRQ compares in every cycle ([8149255](https://github.com/elektronaut/badline/commit/8149255559cf406545d4c14bc59d54b21fe6afb2))
|
|
149
|
+
* **vic:** shift out zero data where the sequencer gets no g-access ([f88100f](https://github.com/elektronaut/badline/commit/f88100fdb00101898f4b92a3a52670bf4b2862e5))
|
|
150
|
+
* **vic:** sprite crunch and the expansion flip-flop timing ([171bd30](https://github.com/elektronaut/badline/commit/171bd3005ef836f869f08f47a415f1a0b6f744a3))
|
|
151
|
+
* **vic:** sprite reload hold, K-1 multicolor pair and s-accesses without DMA ([de60342](https://github.com/elektronaut/badline/commit/de60342f8de9515ee9adade4437c39f07afc6252))
|
|
152
|
+
* **vic:** sprite reload hold, K-1 pair and s-accesses without DMA ([30b7ec9](https://github.com/elektronaut/badline/commit/30b7ec99432f21ccdd48d2687896b3ff7995ca05))
|
|
153
|
+
* **vic:** take an MCM falling out of ECM+MCM a pixel late ([f9bfa21](https://github.com/elektronaut/badline/commit/f9bfa217cde58cd7cd98bb66dba6b630662736ee))
|
|
154
|
+
* **vic:** work out the phi1 bus byte per cycle ([cdda146](https://github.com/elektronaut/badline/commit/cdda1465133338141a07240e3e508b82d1ef412e))
|
|
155
|
+
* **vic:** wrap sprite BA past the line end and gate display on MxE ([3d8173c](https://github.com/elektronaut/badline/commit/3d8173c35413bdb07863973dfd464eb741f4d28a))
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
### Performance Improvements
|
|
159
|
+
|
|
160
|
+
* **cia:** cache the timer's settled and empty states ([9deeadd](https://github.com/elektronaut/badline/commit/9deeadd384d25833652c3bcfb7b4d9f1d2344563))
|
|
161
|
+
* **cia:** skip the idle shift register ([a6ba3d4](https://github.com/elektronaut/badline/commit/a6ba3d4f589c12c881d296c4f4298ea580c7f0c2))
|
|
162
|
+
* **cia:** trim the per-cycle CIA work ([5b727c6](https://github.com/elektronaut/badline/commit/5b727c666a66b2d714eb5f4235d639582c76967d))
|
|
163
|
+
* compare finished VIC lines against a per-line copy ([0682d6a](https://github.com/elektronaut/badline/commit/0682d6a77c6ee83026bbf81743b7394c935fbdc3))
|
|
164
|
+
* compile Status flag accessors as plain methods ([8c1bdbe](https://github.com/elektronaut/badline/commit/8c1bdbe9c96e9a9d294685c1d509100414d22306))
|
|
165
|
+
* **cpu:** replace the fiber with a microcode sequencer ([1d6f760](https://github.com/elektronaut/badline/commit/1d6f760ac0bd7c4d5b5ffd1b9257ac2da792ee72))
|
|
166
|
+
* drop per-cycle method calls from the CIA and CPU hot paths ([a8a2843](https://github.com/elektronaut/badline/commit/a8a284324b650e06f12621fa45854bdf8cdbf60b))
|
|
167
|
+
* drop two cfunc calls from the VIC's per-cycle paths ([7fe1f6b](https://github.com/elektronaut/badline/commit/7fe1f6b92eb88d93282204cabe60a51168d5715d))
|
|
168
|
+
* let a headless run leave the VIC's colours unpainted ([34d1c58](https://github.com/elektronaut/badline/commit/34d1c588928ad0196db27755b7c2bdf3c48784c0))
|
|
169
|
+
* let headless runs leave the VIC's colours unpainted ([3154996](https://github.com/elektronaut/badline/commit/3154996b49aac8b2e96ed09132df4824e3d42944))
|
|
170
|
+
* look up graphics columns and test sprite codes with zero? ([6d5fc93](https://github.com/elektronaut/badline/commit/6d5fc9389b20c25bb0f74e7b283f695a54d67ce2))
|
|
171
|
+
* paint hires pixels from a per-byte mask table ([42de4fe](https://github.com/elektronaut/badline/commit/42de4fe1b57bcf955d6332a15272352da87abe4e))
|
|
172
|
+
* paint multicolour pairs from a palette and hires pixels from the fg mask ([d57f709](https://github.com/elektronaut/badline/commit/d57f709e147167140800c3391129e9816cf18665))
|
|
173
|
+
* paint multicolour pairs from a per-group palette ([95f633c](https://github.com/elektronaut/badline/commit/95f633c717710f47a6ade79cecb057db433125c2))
|
|
174
|
+
* run exitcode testbench rows and Lorenz with the VIC unpainted ([6f84e35](https://github.com/elektronaut/badline/commit/6f84e358e9e5c1a3200a40898d22d1485c94f853))
|
|
175
|
+
* run the SID testprogs with the VIC unpainted ([78e8c75](https://github.com/elektronaut/badline/commit/78e8c75a566284ef618aadf4655774079011a680))
|
|
176
|
+
* set Status flags without renormalizing the value ([d2d3033](https://github.com/elektronaut/badline/commit/d2d3033fe137786f03e937a7e2c689c9f58ce677))
|
|
177
|
+
* **sid:** age the bus latch without a method call per cycle ([3ea58b1](https://github.com/elektronaut/badline/commit/3ea58b10ec97985374f5c14fde278688a44949d1))
|
|
178
|
+
* **sid:** batched synthesis with a pull API for audio ([cd2fb42](https://github.com/elektronaut/badline/commit/cd2fb42afcb6ac65e815e98b9981262489ee3674))
|
|
179
|
+
* **sid:** catch the DSP up a span at a time ([4157da0](https://github.com/elektronaut/badline/commit/4157da096d98fe63aaf55c3bbffcf5cf999418ae))
|
|
180
|
+
* **sid:** fast-forward a combined waveform that writes nothing back ([11f9837](https://github.com/elektronaut/badline/commit/11f9837ab74ca979bac882e9443e164eb6098cf6))
|
|
181
|
+
* **sid:** unroll the per-cycle voice loops ([7be0ee9](https://github.com/elektronaut/badline/commit/7be0ee9ab9c7806fcc5b94a59df64099f7d40cda))
|
|
182
|
+
* **test:** boot once and fork a child per test in bin/testbench and bin/sidtests ([7db72e0](https://github.com/elektronaut/badline/commit/7db72e0a6844b30931f7fb73c8196afe86ad5137))
|
|
183
|
+
* unroll the multicolour pair loop ([a0a6f4e](https://github.com/elektronaut/badline/commit/a0a6f4eba30f8caa6f224b3e62b1910329d47839))
|
|
184
|
+
* **vic:** answer the bad-line BA check from the last column's compare ([aa1e983](https://github.com/elektronaut/badline/commit/aa1e983710f000b0c3a544430408ac5c768fba5c))
|
|
185
|
+
* **vic:** stop allocating per column in the sequencer and border restore ([1eeac57](https://github.com/elektronaut/badline/commit/1eeac57f836d791b5c9674bd286716f8284a1afa))
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# Badline
|
|
2
|
+
|
|
3
|
+
A cycle-accurate Commodore 64 emulator in Ruby. `README.md` covers usage,
|
|
4
|
+
supported media and what is emulated, and `CONTRIBUTING.md` covers setup.
|
|
5
|
+
This file covers how to work on the code.
|
|
6
|
+
|
|
7
|
+
## Orientation
|
|
8
|
+
|
|
9
|
+
`lib/badline/` holds one file per chip or subsystem, and namespaced groups
|
|
10
|
+
live in subdirectories:
|
|
11
|
+
|
|
12
|
+
- **Machine**: `computer.rb` clocks everything once per cycle (`cycle!`:
|
|
13
|
+
VIC, both CIAs, SID and the datasette, then the CPU unless the VIC holds
|
|
14
|
+
BA low). `address_bus.rb` handles banking and page-table dispatch
|
|
15
|
+
- **CPU**: `cpu.rb`, `instruction.rb` and `instruction_set/`, plus
|
|
16
|
+
`interrupts.rb`
|
|
17
|
+
- **VIC-II**: `vic.rb` and `vic/`, covering the sequencer, sprites, graphics
|
|
18
|
+
modes, border and register timing
|
|
19
|
+
- **CIA**: `cia.rb` and `cia/` (timers, serial), plus `time_of_day.rb`
|
|
20
|
+
- **SID**: `sid.rb` and `sid/`. `audio/` plays and renders tunes for
|
|
21
|
+
`exe/badline-sid`
|
|
22
|
+
- **Media and host I/O**: `storage/` (disk, tape and cartridge image
|
|
23
|
+
formats), `cartridge/` (mappers), `kernal_trap/` (the LOAD/SAVE and IEC
|
|
24
|
+
traps that stand in for a drive), `media.rb` (attach and autostart),
|
|
25
|
+
`datasette.rb`, and `gui/` and `input/` (SDL front end, controllers)
|
|
26
|
+
|
|
27
|
+
Timing-critical code lives in `cpu`, `interrupts`, `vic`, `cia` and `sid` and
|
|
28
|
+
in the order `Computer#cycle!` clocks them. Changes there move the test
|
|
29
|
+
suites below. `gui/` changes move none of them.
|
|
30
|
+
|
|
31
|
+
Namespaced groups live in `lib/badline/<namespace>/`, with a sibling
|
|
32
|
+
`lib/badline/<namespace>.rb` that requires the members. `lib/badline.rb`
|
|
33
|
+
requires only the namespace file.
|
|
34
|
+
|
|
35
|
+
### Oracles
|
|
36
|
+
|
|
37
|
+
| Oracle | Runner | Covers |
|
|
38
|
+
| --- | --- | --- |
|
|
39
|
+
| rspec (`spec/`) | `bundle exec rspec` | Unit behaviour, all of `lib/` |
|
|
40
|
+
| SingleStepTests 65x02 | `rake test` (100 sampled cases per opcode) | CPU, per-cycle bus traces |
|
|
41
|
+
| Wolfgang Lorenz suite | `bin/lorenz` | CPU, CIA, interrupts |
|
|
42
|
+
| VICE testbench | `bin/testbench <subtree>` | `VICII/`, `CIA/`, `interrupts/`, `CPU/`, and cartridges with `--carts` |
|
|
43
|
+
| VICE SID testprogs | `bin/sidtests` | SID |
|
|
44
|
+
| CIA offline grids | `bundle exec rspec --tag slow spec/badline/cia` | CIA timers and shift register, against a bare CIA in about 2 min |
|
|
45
|
+
|
|
46
|
+
The CIA offline grids replay Lorenz's `cia1ta` and `cia1tb` sweeps (about
|
|
47
|
+
8 s) and the `cia-sdr-icr` loop for every timer A latch (about 2 min),
|
|
48
|
+
checked against each test's own results. On the Lorenz chain, a failing
|
|
49
|
+
timer test takes about 25 minutes.
|
|
50
|
+
|
|
51
|
+
`bin/benchmark` measures emulation speed after boot, and `bin/profile` shows
|
|
52
|
+
where that time goes. `test/baselines/README.md`
|
|
53
|
+
documents the baseline format, the suites and how rows are compared.
|
|
54
|
+
|
|
55
|
+
## Driving the emulator headlessly
|
|
56
|
+
|
|
57
|
+
`exe/badline <media>` opens the SDL window, which is no use for checking
|
|
58
|
+
work. Drive a `Badline::Computer` from Ruby instead, as the `bin/` runners do:
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
computer = Badline::Computer.new
|
|
62
|
+
Badline::Media.attach(computer, path) # PRG, disk, tape, CRT or directory; autostarts
|
|
63
|
+
computer.on_init { computer.type_text("print 6*7\r") } # after boot (~2.5M cycles)
|
|
64
|
+
3_500_000.times { computer.cycle! }
|
|
65
|
+
computer.address_bus.peek(0x0400) # screen RAM starts at $0400
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
- `computer.capture_output` traps CHROUT and records what the machine prints
|
|
69
|
+
- `computer.install_debug_register { |code| ... }` receives the `$D7FF`
|
|
70
|
+
exit code that testprogs report through (`$00` pass, `$ff` fail)
|
|
71
|
+
- To test a BASIC snippet, convert it with `petcat -w2 -o out.prg in.txt`
|
|
72
|
+
|
|
73
|
+
## Working in parallel
|
|
74
|
+
|
|
75
|
+
Several sessions work in this repo at once. Each one has its own git
|
|
76
|
+
worktree and owns a different set of files.
|
|
77
|
+
|
|
78
|
+
- **One branch per unit of work**, cut from a freshly fetched `origin/main`,
|
|
79
|
+
in a worktree under `.claude/worktrees/` (gitignored). A lane can keep
|
|
80
|
+
its worktree between tasks: when `git status --short` is clean, start
|
|
81
|
+
the next unit with `git fetch && git switch -c <branch> origin/main`
|
|
82
|
+
- **Edit only the files your task names.** Other sessions own the rest, and
|
|
83
|
+
edits outside your set collide with theirs. If you need a change
|
|
84
|
+
elsewhere, report it as a follow-up and don't make it
|
|
85
|
+
- The external suites under `vendor/` are gitignored, so a new worktree has
|
|
86
|
+
only `vendor/.gitkeep`. From the worktree root, symlink the main
|
|
87
|
+
checkout's suites into it:
|
|
88
|
+
`for d in 65x02 VICE-testprogs; do ln -sfn ../../../../vendor/$d vendor/$d; done`.
|
|
89
|
+
The main checkout also has `vendor/OneLoad64-Games-Collection-v5`, which
|
|
90
|
+
`rake vendor:checkout` doesn't fetch. Link it the same way only for
|
|
91
|
+
`.sid` or media work. Don't re-run `rake vendor:checkout` there, and
|
|
92
|
+
don't write into `vendor/`
|
|
93
|
+
- The roadmap is `Plan.local.md` in the main checkout. It is untracked and
|
|
94
|
+
not in the public repo. When a planner session assigned your task, the
|
|
95
|
+
planner owns that file: read it and don't edit it. Send the planner your
|
|
96
|
+
results instead: what changed, suite scores before and after, and anything
|
|
97
|
+
worth recording (pinned rules, follow-ups)
|
|
98
|
+
- **Stop only your own processes, by PID.** Never kill by name or
|
|
99
|
+
pattern (`pkill -f`, `killall`, `pgrep … | kill`): other worktrees
|
|
100
|
+
run the same commands, and a pattern stops their runs too. Kill `$!`
|
|
101
|
+
for a job you backgrounded, or a PID you noted when you started it.
|
|
102
|
+
If you have to look one up, match on your worktree's absolute path
|
|
103
|
+
and check the result before you kill anything
|
|
104
|
+
- `bin/testbench` passes TERM and INT on to its shards, and the
|
|
105
|
+
`rake regression:*` tasks pass them on to the runner, so killing the
|
|
106
|
+
PID you started stops the whole run. An interrupted run exits
|
|
107
|
+
non-zero and writes no results or baseline
|
|
108
|
+
- A background task that ends with exit code 144 got SIGTERM, most likely
|
|
109
|
+
from another session's pattern kill, not a timeout. There is no
|
|
110
|
+
run-length limit
|
|
111
|
+
|
|
112
|
+
## Testing and baselines
|
|
113
|
+
|
|
114
|
+
- `rake vendor:checkout` fetches SingleStepTests and VICE-testprogs into
|
|
115
|
+
`vendor/`
|
|
116
|
+
- `bundle exec rspec`: line coverage is about 95%. `spec/spec_helper.rb`
|
|
117
|
+
fails a whole-suite run (every spec file, no filters) below 90%, while
|
|
118
|
+
single-file and filtered runs skip the floor. `:slow` specs are excluded
|
|
119
|
+
by default: run them with `bundle exec rspec --tag slow`
|
|
120
|
+
- `rake test`: SingleStepTests. Run it for any CPU change
|
|
121
|
+
|
|
122
|
+
The headless suites are expensive. `bin/testbench` forks over 4 shards by
|
|
123
|
+
default. `SHARDS=N rake regression:<suite>` or `bin/testbench --shards N`
|
|
124
|
+
overrides that, capped by the core count, but keep the default, because
|
|
125
|
+
other worktrees share the machine. Whole runs at 4 shards on an M-series
|
|
126
|
+
laptop take 15 min for `testbench` (`VICII/`), 11 for `testbench-cia`, 1 for
|
|
127
|
+
`testbench-interrupts`, 37 for `testbench-irqdma`, 11 for
|
|
128
|
+
`testbench-cpu` and 2 for `testbench-carts`. `sid` takes about 12 min. `lorenz` chains itself and takes
|
|
129
|
+
about 2.5 h on CI whole. `rake regression:lorenz-1` to `lorenz-4` run it as
|
|
130
|
+
four stretches of about 40 min each, and they can run side by side.
|
|
131
|
+
`test/baselines/README.md` has the full table. A killed `bin/testbench` run
|
|
132
|
+
leaves its finished rows in `<results>.progress`, and running the same
|
|
133
|
+
command again with `--resume` carries on from them.
|
|
134
|
+
|
|
135
|
+
**Never run a full suite to check your work or to record it.** A full run
|
|
136
|
+
repeats CI on your machine, several times over when worktrees overlap, and
|
|
137
|
+
the rows your change can't reach tell you nothing about it.
|
|
138
|
+
|
|
139
|
+
- Iterate on a subset: `ruby --yjit bin/testbench <filter>` (an id
|
|
140
|
+
substring such as `VICII/spritegap`, and `--list` shows the ids),
|
|
141
|
+
`ruby --yjit bin/sidtests <filter>`, or
|
|
142
|
+
`ruby --yjit bin/lorenz [image] [start_test] [max_cycles]` (resumes the
|
|
143
|
+
chain at a named test, and `--stop-after NAME` ends it once that test is
|
|
144
|
+
done). These take seconds to minutes
|
|
145
|
+
- When your change moves rows, re-record only those rows, in the same
|
|
146
|
+
change: `rake "regression:record:<suite>[filter,...]"` (quote it, because
|
|
147
|
+
zsh globs the brackets). It runs only the matching tests and splices
|
|
148
|
+
their rows into the baseline, and every other row keeps its verdict.
|
|
149
|
+
`lorenz` chains itself, so it takes a stretch of the chain instead:
|
|
150
|
+
`rake "regression:record:lorenz[first,last]"` resumes just ahead of
|
|
151
|
+
`first`, stops after `last` and leaves the `(suite)` row alone.
|
|
152
|
+
`[first,(suite)]` runs on to the end of the chain and records the
|
|
153
|
+
`(suite)` row too. Cover every test your change can reach, and explain
|
|
154
|
+
every moved row. Never re-record just to make a diff go away
|
|
155
|
+
- CI's nightly run owns the whole-suite verdict. The Regression workflow
|
|
156
|
+
runs `testbench`, `lorenz` and `sid` against `main` each night, and skips
|
|
157
|
+
the night when nothing relevant has changed since the last successful
|
|
158
|
+
nightly run. It also runs from the Actions tab on demand. It never runs
|
|
159
|
+
on push or on pull requests, so one verdict can cover a day's merges.
|
|
160
|
+
The `testbench-*` and `sid-8580` suites run from the Actions tab on
|
|
161
|
+
demand
|
|
162
|
+
- The one exception is a change whose reach you can't bound to a set of
|
|
163
|
+
filters, such as reordering `Computer#cycle!` or changing the LOAD trap
|
|
164
|
+
every suite loads through. Ask before running a full suite for it, and
|
|
165
|
+
don't start one on your own judgement
|
|
166
|
+
|
|
167
|
+
Pick the filters from the suites your change can move: VIC → `testbench`;
|
|
168
|
+
CPU, interrupts or timing → the matching `testbench-*` suite, plus
|
|
169
|
+
`rake test` for CPU; CIA → the slow CIA specs first, then the matching
|
|
170
|
+
`testbench-cia` rows; cartridge mappers, banking or power-on state →
|
|
171
|
+
`testbench-carts`; SID → `sid`, plus `sid-8580` for anything the 8580
|
|
172
|
+
model reaches (`bin/sidtests --sid 8580`). Lorenz isn't a per-change check:
|
|
173
|
+
its full chain runs nightly, and the planner assigns any row it moves. The
|
|
174
|
+
exception is code whose rule in `doc/pinned-behaviour.md` names Lorenz
|
|
175
|
+
tests: the interrupt polling, CPU port and CIA timer rules. Run just the
|
|
176
|
+
tests that rule names, one at a time, with
|
|
177
|
+
`ruby --yjit bin/lorenz --resume <test> --stop-after <test>`. A stretch
|
|
178
|
+
resumes on a fresh machine, so its cuts in the Rakefile have to stay before
|
|
179
|
+
`trap1`, where the tests start carrying state from one to the next. Both Lorenz
|
|
180
|
+
and testbench load through the LOAD trap and type through the keyboard
|
|
181
|
+
buffer, so storage, IEC and keyboard changes can move them too. A broken
|
|
182
|
+
trap stalls the Lorenz chain.
|
|
183
|
+
|
|
184
|
+
`ruby --yjit bin/benchmark` measures post-boot speed. Absolute numbers
|
|
185
|
+
depend on the machine and its load: parallel worktrees running suites can
|
|
186
|
+
cost 20% or more, and wall-clock variance is ±15% even when idle. For an
|
|
187
|
+
A/B, run `ruby --yjit bin/profile <idle|text|game|synth> --compare <sha>`.
|
|
188
|
+
It pins the base to a commit, because another worktree's fetch can move
|
|
189
|
+
`origin/main` mid-comparison. It also times in process CPU time, which holds
|
|
190
|
+
about ±3% under load. Without `--compare`, `bin/profile` samples with
|
|
191
|
+
stackprof and splits self time by subsystem. It drops stackprof's GC
|
|
192
|
+
pseudo-frames, which report lazy-sweep samples as GC time. `--ceiling` shows
|
|
193
|
+
how much faster the machine would run if each chip cost nothing.
|
|
194
|
+
|
|
195
|
+
### Pinned behaviour
|
|
196
|
+
|
|
197
|
+
[`doc/pinned-behaviour.md`](doc/pinned-behaviour.md) holds timing rules for
|
|
198
|
+
the CPU, VIC, CIA and SID. Each was derived empirically against a named
|
|
199
|
+
test, and the specs that guard one say `Pinned by <test>` in a comment. When
|
|
200
|
+
you change code a pinned rule governs, re-derive the rule against its test
|
|
201
|
+
and update the doc if the rule moves. A green suite alone isn't enough,
|
|
202
|
+
because the suite can stay green while the rule breaks.
|
|
203
|
+
|
|
204
|
+
## Git
|
|
205
|
+
|
|
206
|
+
- **Don't stage, commit, push or open a PR** unless your task says so in
|
|
207
|
+
those words. Wanting a PR, a finished feature or green CI doesn't count
|
|
208
|
+
as permission. Finish the work, report what changed, and stop. A dirty
|
|
209
|
+
tree is the expected end state
|
|
210
|
+
- Hunks are staged by hand during review, so a partially staged file is
|
|
211
|
+
deliberate. Use `git diff HEAD` to see everything
|
|
212
|
+
- Commit messages use Conventional Commits (`feat:`, `fix:`, `chore:`, …).
|
|
213
|
+
release-please derives version bumps and the changelog from the prefixes
|
|
214
|
+
- No `Co-Authored-By` or `Claude-Session` trailers, even where `git log`
|
|
215
|
+
shows them
|
|
216
|
+
- When a task explicitly asks for a PR, the branch is already from
|
|
217
|
+
`origin/main` (see above). Open it with `gh pr create --base main`
|
data/CODE_OF_CONDUCT.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
|
|
2
|
+
# Contributor Covenant 3.0 Code of Conduct
|
|
3
|
+
|
|
4
|
+
## Our Pledge
|
|
5
|
+
|
|
6
|
+
We pledge to make our community welcoming, safe, and equitable for all.
|
|
7
|
+
|
|
8
|
+
We are committed to fostering an environment that respects and promotes the dignity, rights, and contributions of all individuals, regardless of characteristics including race, ethnicity, caste, color, age, physical characteristics, neurodiversity, disability, sex or gender, gender identity or expression, sexual orientation, language, philosophy or religion, national or social origin, socio-economic position, level of education, or other status. The same privileges of participation are extended to everyone who participates in good faith and in accordance with this Covenant.
|
|
9
|
+
|
|
10
|
+
## Encouraged Behaviors
|
|
11
|
+
|
|
12
|
+
While acknowledging differences in social norms, we all strive to meet our community's expectations for positive behavior. We also understand that our words and actions may be interpreted differently than we intend based on culture, background, or native language.
|
|
13
|
+
|
|
14
|
+
With these considerations in mind, we agree to behave mindfully toward each other and act in ways that center our shared values, including:
|
|
15
|
+
|
|
16
|
+
1. Respecting the **purpose of our community**, our activities, and our ways of gathering.
|
|
17
|
+
2. Engaging **kindly and honestly** with others.
|
|
18
|
+
3. Respecting **different viewpoints** and experiences.
|
|
19
|
+
4. **Taking responsibility** for our actions and contributions.
|
|
20
|
+
5. Gracefully giving and accepting **constructive feedback**.
|
|
21
|
+
6. Committing to **repairing harm** when it occurs.
|
|
22
|
+
7. Behaving in other ways that promote and sustain the **well-being of our community**.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
## Restricted Behaviors
|
|
26
|
+
|
|
27
|
+
We agree to restrict the following behaviors in our community. Instances, threats, and promotion of these behaviors are violations of this Code of Conduct.
|
|
28
|
+
|
|
29
|
+
1. **Harassment.** Violating explicitly expressed boundaries or engaging in unnecessary personal attention after any clear request to stop.
|
|
30
|
+
2. **Character attacks.** Making insulting, demeaning, or pejorative comments directed at a community member or group of people.
|
|
31
|
+
3. **Stereotyping or discrimination.** Characterizing anyone’s personality or behavior on the basis of immutable identities or traits.
|
|
32
|
+
4. **Sexualization.** Behaving in a way that would generally be considered inappropriately intimate in the context or purpose of the community.
|
|
33
|
+
5. **Violating confidentiality**. Sharing or acting on someone's personal or private information without their permission.
|
|
34
|
+
6. **Endangerment.** Causing, encouraging, or threatening violence or other harm toward any person or group.
|
|
35
|
+
7. Behaving in other ways that **threaten the well-being** of our community.
|
|
36
|
+
|
|
37
|
+
### Other Restrictions
|
|
38
|
+
|
|
39
|
+
1. **Misleading identity.** Impersonating someone else for any reason, or pretending to be someone else to evade enforcement actions.
|
|
40
|
+
2. **Failing to credit sources.** Not properly crediting the sources of content you contribute.
|
|
41
|
+
3. **Promotional materials**. Sharing marketing or other commercial content in a way that is outside the norms of the community.
|
|
42
|
+
4. **Irresponsible communication.** Failing to responsibly present content which includes, links or describes any other restricted behaviors.
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
## Reporting an Issue
|
|
46
|
+
|
|
47
|
+
Tensions can occur between community members even when they are trying their best to collaborate. Not every conflict represents a code of conduct violation, and this Code of Conduct reinforces encouraged behaviors and norms that can help avoid conflicts and minimize harm.
|
|
48
|
+
|
|
49
|
+
When an incident does occur, it is important to report it promptly. To report a possible violation, **contact the project maintainer at inge@elektronaut.no.**
|
|
50
|
+
|
|
51
|
+
Community Moderators take reports of violations seriously and will make every effort to respond in a timely manner. They will investigate all reports of code of conduct violations, reviewing messages, logs, and recordings, or interviewing witnesses and other participants. Community Moderators will keep investigation and enforcement actions as transparent as possible while prioritizing safety and confidentiality. In order to honor these values, enforcement actions are carried out in private with the involved parties, but communicating to the whole community may be part of a mutually agreed upon resolution.
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
## Addressing and Repairing Harm
|
|
55
|
+
|
|
56
|
+
****
|
|
57
|
+
|
|
58
|
+
If an investigation by the Community Moderators finds that this Code of Conduct has been violated, the following enforcement ladder may be used to determine how best to repair harm, based on the incident's impact on the individuals involved and the community as a whole. Depending on the severity of a violation, lower rungs on the ladder may be skipped.
|
|
59
|
+
|
|
60
|
+
1) Warning
|
|
61
|
+
1) Event: A violation involving a single incident or series of incidents.
|
|
62
|
+
2) Consequence: A private, written warning from the Community Moderators.
|
|
63
|
+
3) Repair: Examples of repair include a private written apology, acknowledgement of responsibility, and seeking clarification on expectations.
|
|
64
|
+
2) Temporarily Limited Activities
|
|
65
|
+
1) Event: A repeated incidence of a violation that previously resulted in a warning, or the first incidence of a more serious violation.
|
|
66
|
+
2) Consequence: A private, written warning with a time-limited cooldown period designed to underscore the seriousness of the situation and give the community members involved time to process the incident. The cooldown period may be limited to particular communication channels or interactions with particular community members.
|
|
67
|
+
3) Repair: Examples of repair may include making an apology, using the cooldown period to reflect on actions and impact, and being thoughtful about re-entering community spaces after the period is over.
|
|
68
|
+
3) Temporary Suspension
|
|
69
|
+
1) Event: A pattern of repeated violation which the Community Moderators have tried to address with warnings, or a single serious violation.
|
|
70
|
+
2) Consequence: A private written warning with conditions for return from suspension. In general, temporary suspensions give the person being suspended time to reflect upon their behavior and possible corrective actions.
|
|
71
|
+
3) Repair: Examples of repair include respecting the spirit of the suspension, meeting the specified conditions for return, and being thoughtful about how to reintegrate with the community when the suspension is lifted.
|
|
72
|
+
4) Permanent Ban
|
|
73
|
+
1) Event: A pattern of repeated code of conduct violations that other steps on the ladder have failed to resolve, or a violation so serious that the Community Moderators determine there is no way to keep the community safe with this person as a member.
|
|
74
|
+
2) Consequence: Access to all community spaces, tools, and communication channels is removed. In general, permanent bans should be rarely used, should have strong reasoning behind them, and should only be resorted to if working through other remedies has failed to change the behavior.
|
|
75
|
+
3) Repair: There is no possible repair in cases of this severity.
|
|
76
|
+
|
|
77
|
+
This enforcement ladder is intended as a guideline. It does not limit the ability of Community Managers to use their discretion and judgment, in keeping with the best interests of our community.
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
## Scope
|
|
81
|
+
|
|
82
|
+
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public or other spaces. Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
## Attribution
|
|
86
|
+
|
|
87
|
+
This Code of Conduct is adapted from the Contributor Covenant, version 3.0, permanently available at [https://www.contributor-covenant.org/version/3/0/](https://www.contributor-covenant.org/version/3/0/).
|
|
88
|
+
|
|
89
|
+
Contributor Covenant is stewarded by the Organization for Ethical Source and licensed under CC BY-SA 4.0. To view a copy of this license, visit [https://creativecommons.org/licenses/by-sa/4.0/](https://creativecommons.org/licenses/by-sa/4.0/)
|
|
90
|
+
|
|
91
|
+
For answers to common questions about Contributor Covenant, see the FAQ at [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq). Translations are provided at [https://www.contributor-covenant.org/translations](https://www.contributor-covenant.org/translations). Additional enforcement and community guideline resources can be found at [https://www.contributor-covenant.org/resources](https://www.contributor-covenant.org/resources). The enforcement ladder was inspired by the work of [Mozilla’s code of conduct team](https://github.com/mozilla/inclusion).
|
|
92
|
+
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Bug reports and pull requests are welcome on
|
|
4
|
+
[GitHub](https://github.com/elektronaut/badline). Everyone participating
|
|
5
|
+
is expected to follow the [code of conduct](CODE_OF_CONDUCT.md).
|
|
6
|
+
|
|
7
|
+
## Getting started
|
|
8
|
+
|
|
9
|
+
Badline needs SDL2, which is available from most package managers.
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
brew install sdl2 # macOS
|
|
13
|
+
apt install libsdl2-dev # Debian/Ubuntu
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Install the dependencies and run the specs:
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
bundle install
|
|
20
|
+
bundle exec rspec
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
A run of the whole suite fails if line coverage drops below 90%. Runs of
|
|
24
|
+
single files or filtered examples skip that check. Specs tagged `:slow`
|
|
25
|
+
boot the whole machine and are skipped by default. Run them with
|
|
26
|
+
`bundle exec rspec --tag slow`.
|
|
27
|
+
|
|
28
|
+
The CPU is verified separately against the
|
|
29
|
+
[65x02 single step tests](https://github.com/SingleStepTests/65x02).
|
|
30
|
+
`rake test` checks the fixtures out into `vendor/65x02` first, which
|
|
31
|
+
takes a moment the first time:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
bundle exec rake test
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Check style before pushing:
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
bundle exec rubocop
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Pull requests
|
|
44
|
+
|
|
45
|
+
- Add tests for any behavior you change.
|
|
46
|
+
- Write commit messages using
|
|
47
|
+
[Conventional Commits](https://www.conventionalcommits.org). The
|
|
48
|
+
changelog and releases are generated from them, so the `feat:` and
|
|
49
|
+
`fix:` prefixes decide what ends up in the next release.
|
|
50
|
+
- Leave the version and `CHANGELOG.md` alone. Both are updated
|
|
51
|
+
automatically when a release is cut.
|