badline 0.14.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +86 -0
  3. data/CLAUDE.md +22 -5
  4. data/README.md +101 -11
  5. data/doc/media.md +19 -0
  6. data/doc/pinned-behaviour.md +145 -0
  7. data/doc/snapshot-format.md +244 -46
  8. data/doc/snapshots.md +18 -1
  9. data/exe/badline-ruby +1 -1
  10. data/lib/badline/audio/bare_player.rb +4 -8
  11. data/lib/badline/audio/machine_player.rb +4 -26
  12. data/lib/badline/c128/banks.rb +1 -3
  13. data/lib/badline/c128/bus.rb +19 -1
  14. data/lib/badline/c128/mmu_pages.rb +7 -0
  15. data/lib/badline/c64/bus/extra_sids.rb +80 -0
  16. data/lib/badline/c64/bus.rb +1 -0
  17. data/lib/badline/c64/cartridge/action_replay.rb +6 -2
  18. data/lib/badline/c64/cartridge/comal80.rb +1 -0
  19. data/lib/badline/c64/cartridge/dinamic.rb +3 -1
  20. data/lib/badline/c64/cartridge/final_cartridge3.rb +1 -0
  21. data/lib/badline/c64/cartridge/fun_play.rb +2 -1
  22. data/lib/badline/c64/cartridge/game_system.rb +2 -1
  23. data/lib/badline/c64/cartridge/keyed_state.rb +155 -34
  24. data/lib/badline/c64/cartridge/magic_desk.rb +2 -1
  25. data/lib/badline/c64/cartridge/ocean.rb +1 -0
  26. data/lib/badline/c64/cartridge/pagefox.rb +1 -0
  27. data/lib/badline/c64/cartridge/rgcd.rb +2 -1
  28. data/lib/badline/c64/cartridge/super_games.rb +3 -2
  29. data/lib/badline/c64/cartridge/zaxxon.rb +1 -0
  30. data/lib/badline/c64/cartridge.rb +3 -3
  31. data/lib/badline/c64/keyed_modules.rb +6 -2
  32. data/lib/badline/c64/true_drives.rb +13 -1
  33. data/lib/badline/c64.rb +6 -0
  34. data/lib/badline/chips/ted/beam.rb +13 -14
  35. data/lib/badline/chips/ted/fetches.rb +199 -0
  36. data/lib/badline/chips/ted/keyed_state.rb +156 -0
  37. data/lib/badline/chips/ted/modes.rb +134 -0
  38. data/lib/badline/chips/ted/palette.rb +43 -0
  39. data/lib/badline/chips/ted/picture.rb +182 -0
  40. data/lib/badline/chips/ted/sound/output.rb +86 -0
  41. data/lib/badline/chips/ted/sound.rb +284 -0
  42. data/lib/badline/chips/ted.rb +53 -6
  43. data/lib/badline/chips/tia.rb +28 -0
  44. data/lib/badline/chips/vic/register_log.rb +4 -1
  45. data/lib/badline/drives/datasette/keyed_state.rb +14 -4
  46. data/lib/badline/drives/datasette.rb +22 -5
  47. data/lib/badline/drives/engine/core.rb +6 -14
  48. data/lib/badline/drives/engine/idle.rb +42 -4
  49. data/lib/badline/drives/engine/idle_cpu.rb +18 -0
  50. data/lib/badline/drives/engine/serial_connection.rb +25 -0
  51. data/lib/badline/drives/engine/sleep.rb +1 -0
  52. data/lib/badline/drives/engine.rb +1 -0
  53. data/lib/badline/drives/model1541/byte_ready.rb +19 -3
  54. data/lib/badline/drives/model1541/mechanism.rb +10 -1
  55. data/lib/badline/drives/model1541.rb +1 -0
  56. data/lib/badline/drives/model1551/bus.rb +138 -0
  57. data/lib/badline/drives/model1551/cable.rb +104 -0
  58. data/lib/badline/drives/model1551/cpu.rb +14 -0
  59. data/lib/badline/drives/model1551/keyed_state.rb +65 -0
  60. data/lib/badline/drives/model1551/port.rb +74 -0
  61. data/lib/badline/drives/model1551/tia.rb +92 -0
  62. data/lib/badline/drives/model1551.rb +170 -0
  63. data/lib/badline/drives/model1571.rb +1 -0
  64. data/lib/badline/drives/model1581.rb +1 -0
  65. data/lib/badline/frontend/boot.rb +23 -2
  66. data/lib/badline/frontend/controls.rb +7 -3
  67. data/lib/badline/frontend/keys.rb +14 -2
  68. data/lib/badline/frontend/media_slots.rb +11 -1
  69. data/lib/badline/frontend/menu/menu_dialogs.rb +14 -5
  70. data/lib/badline/frontend/menu/menu_media.rb +102 -14
  71. data/lib/badline/frontend/menu/menu_pages.rb +16 -11
  72. data/lib/badline/frontend/menu/menu_ports.rb +13 -1
  73. data/lib/badline/frontend/player/player_controller.rb +11 -4
  74. data/lib/badline/frontend/screen.rb +33 -12
  75. data/lib/badline/frontend/screens.rb +2 -1
  76. data/lib/badline/frontend/sound.rb +4 -4
  77. data/lib/badline/frontend/timeline.rb +19 -6
  78. data/lib/badline/machine/settling.rb +1 -1
  79. data/lib/badline/machine.rb +30 -6
  80. data/lib/badline/media/plus4_media.rb +68 -0
  81. data/lib/badline/media/program.rb +20 -6
  82. data/lib/badline/media/true_drive.rb +7 -5
  83. data/lib/badline/media.rb +33 -12
  84. data/lib/badline/options/family.rb +1 -0
  85. data/lib/badline/options/help.rb +32 -6
  86. data/lib/badline/options/option.rb +2 -1
  87. data/lib/badline/options/table.rb +29 -4
  88. data/lib/badline/options/validation.rb +66 -4
  89. data/lib/badline/options.rb +71 -11
  90. data/lib/badline/plus4/acia/frames.rb +55 -0
  91. data/lib/badline/plus4/acia.rb +276 -16
  92. data/lib/badline/plus4/bus.rb +245 -46
  93. data/lib/badline/plus4/cassette_sense.rb +21 -0
  94. data/lib/badline/plus4/keyboard_port.rb +35 -10
  95. data/lib/badline/plus4/keyed_modules.rb +116 -0
  96. data/lib/badline/plus4/keyed_parts.rb +172 -0
  97. data/lib/badline/plus4/keyed_state.rb +44 -0
  98. data/lib/badline/plus4/ram_expansion.rb +145 -0
  99. data/lib/badline/plus4/sid_card.rb +95 -0
  100. data/lib/badline/plus4/sound_mix.rb +51 -0
  101. data/lib/badline/plus4/tcbm_drive.rb +120 -0
  102. data/lib/badline/plus4/user_port.rb +11 -2
  103. data/lib/badline/plus4.rb +184 -26
  104. data/lib/badline/roms/README +9 -0
  105. data/lib/badline/roms/dos1551.rom +0 -0
  106. data/lib/badline/snapshot/container.rb +2 -0
  107. data/lib/badline/snapshot/field_doc/markdown.rb +7 -6
  108. data/lib/badline/snapshot/field_doc.rb +48 -7
  109. data/lib/badline/snapshot/image.rb +12 -3
  110. data/lib/badline/snapshot/plus4_setup.rb +81 -0
  111. data/lib/badline/snapshot.rb +9 -4
  112. data/lib/badline/storage/tap.rb +21 -12
  113. data/lib/badline/support/checkpoint.rb +3 -2
  114. data/lib/badline/support/plus4_checkpoint.rb +42 -0
  115. data/lib/badline/version.rb +1 -1
  116. metadata +29 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 320b4659e6c9945509741f928989b2378d38ae18a51c1dd5bbca706e3b3ada54
4
- data.tar.gz: 9a6ce80ab26e74e325c8fb660f4ed1fabc64a6e3c1859b723b3816aebe3f4b55
3
+ metadata.gz: 4083bb2ab34b03da1e8139771b512927b0dedf525fa101bc3960641fab81c45e
4
+ data.tar.gz: 8970b724e8e85d62220a8755ed24fb4403a75d2a612c51dd8d580c311fb0738b
5
5
  SHA512:
6
- metadata.gz: 0f4e3b6c6bc7c35eec18ea3a81165050183e92eeebab3c04b12472970b5b0a87d8ad860ceac81e411a39836c601239b3e708bcffbcb7f4eb6561599c1cda1522
7
- data.tar.gz: 61d6698127237a45d99febd816088da06d227519b34455188babc7dafebb977613a61c1472ed348c691433a8c02f4dcbab0346f48083b71fc02035f64f7c8549
6
+ metadata.gz: 0ea5ef78c667d3bc1208d3be9e70ca4b67fc449e840f6875f392eb315de472d2807840cab6a523f34baf18a9568e29b8ef1542de3c7c21fd68b9dd7e0b227331
7
+ data.tar.gz: 392a38d2997cfb3ee1726d7c76bd3fe0d05f073bd77179e588f7d2db0eb016eaee7732ba3340f88f13c3bf740f80764cde001124fee63d416cf07c8cc7febb41
data/CHANGELOG.md CHANGED
@@ -1,5 +1,91 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.15.1](https://github.com/elektronaut/badline/compare/v0.15.0...v0.15.1) (2026-10-12)
4
+
5
+
6
+ ### Features
7
+
8
+ * add the 1551 disk drive, booting its DOS headless ([db03667](https://github.com/elektronaut/badline/commit/db036672799acae2ea13a1b16780875547d74eb6))
9
+ * add the 1551 disk drive, booting its DOS headless ([1f4db55](https://github.com/elektronaut/badline/commit/1f4db555eeb86da755241870a40c75e5441f5894))
10
+ * emulate the Plus/4's 6551 ACIA ([8b1cc23](https://github.com/elektronaut/badline/commit/8b1cc236d7dc5c7e48c772c9256416c1011d2526))
11
+ * emulate the Plus/4's 6551 ACIA ([06bf40f](https://github.com/elektronaut/badline/commit/06bf40f1f618db8decb25fe4d95577a035e9e903))
12
+ * fit a Plus/4 or C16 with a Hannes or Csory RAM expansion ([14bc152](https://github.com/elektronaut/badline/commit/14bc15249914f4ecdb42212ab39d28dc4f2ee557))
13
+ * fit a Plus/4 or C16 with a Hannes or Csory RAM expansion ([85baeba](https://github.com/elektronaut/badline/commit/85baeba267ef6f8e0243444ecd849260a22588de))
14
+ * fit a Plus/4 or C16 with a SID card ([0ed886d](https://github.com/elektronaut/badline/commit/0ed886d5fe10e40223d9de330e38df8501bbbbfc))
15
+ * fit a Plus/4 or C16 with a SID card ([2ae2e19](https://github.com/elektronaut/badline/commit/2ae2e197f783465a8b85c74ca6c78afdc071a66c))
16
+ * machine_diff --family plus4 ([c479566](https://github.com/elektronaut/badline/commit/c479566180254a841d1b6e998089b8ca64ac6a48))
17
+ * machine_diff --family plus4 ([55702f1](https://github.com/elektronaut/badline/commit/55702f10deb8e4f3775d7387a531ef7dbf4a6834))
18
+ * make the 1551 the Plus/4's default true drive ([e3d3120](https://github.com/elektronaut/badline/commit/e3d312099478c71b59088ca4070cd839aabaac46))
19
+ * make the 1551 the Plus/4's default true drive ([e275808](https://github.com/elektronaut/badline/commit/e27580834142351c3bfb4a088b2128bc52885036))
20
+ * name the cartridge on the Expansion port page of every machine ([beab6e5](https://github.com/elektronaut/badline/commit/beab6e58a0aa9a374789645bb18e5c82d50fc0c8))
21
+ * name the cartridge on the Expansion port page of every machine ([6e08889](https://github.com/elektronaut/badline/commit/6e08889edc1de913289ddfd03b75d79b6c42d994))
22
+ * put a true 1551 on the Plus/4's TCBM with --drive-type 1551 ([1d0f9f4](https://github.com/elektronaut/badline/commit/1d0f9f42f622e5e00db1c63dd8413fb7484dd65a))
23
+ * put a true 1551 on the Plus/4's TCBM with --drive-type 1551 ([ba8b9a3](https://github.com/elektronaut/badline/commit/ba8b9a3816300840f6b6fe8138427b81814f3957))
24
+ * put the Plus/4's SID card at $FE80 with --sid-card-address ([da597a2](https://github.com/elektronaut/badline/commit/da597a240f77a870e610f3c186d1afd4f234695a))
25
+ * put the Plus/4's SID card at $FE80 with --sid-card-address ([893c5eb](https://github.com/elektronaut/badline/commit/893c5eb08ca1617c5bced97501e9b8bcae443bb5))
26
+ * save a 1551 in the Plus/4's snapshots ([8c2edad](https://github.com/elektronaut/badline/commit/8c2edadd246985d294b68ae5f46f572691d7045c))
27
+ * save a 1551 in the Plus/4's snapshots ([06313fe](https://github.com/elektronaut/badline/commit/06313fe5de493ff8d92047ea4b2adc815d84d7b7))
28
+
29
+
30
+ ### Bug Fixes
31
+
32
+ * clock the extra SIDs in C64#cycle! ([7fc8b71](https://github.com/elektronaut/badline/commit/7fc8b719702b90b43df822162c7fde48d1205409))
33
+ * clock the extra SIDs in C64#cycle! ([016a9c4](https://github.com/elektronaut/badline/commit/016a9c4517be052db809bfc42345eedf296f3fbc))
34
+ * read the register log's seed by index for Spinel ([d9b3c43](https://github.com/elektronaut/badline/commit/d9b3c43ef51c81faf471018a85721753450949e0))
35
+ * refuse a .crt with a chip in an unmapped bank on the command line ([15b4060](https://github.com/elektronaut/badline/commit/15b4060afe320df465da5f767c21d69ccf93d3bc))
36
+ * refuse a .crt with a chip in an unmapped bank on the command line ([c8c51fc](https://github.com/elektronaut/badline/commit/c8c51fc2f98deae8eaad1c671987c5b726cb4ba5))
37
+ * refuse a cartridge with a chip in a bank the machine doesn't map ([c2bee2a](https://github.com/elektronaut/badline/commit/c2bee2a4ee01b5959a465b7d72034a9be7ec3bf3))
38
+ * refuse a cartridge with a chip in a bank the machine doesn't map ([d08f37e](https://github.com/elektronaut/badline/commit/d08f37e2b2ff0207b1173aee2f467e4f9e71f685))
39
+ * save the datasette's recording state in snapshots ([ba8e5e8](https://github.com/elektronaut/badline/commit/ba8e5e8dbcf088449324d66f30f8bbfe15e80210))
40
+ * save the datasette's recording state in snapshots ([b155546](https://github.com/elektronaut/badline/commit/b1555467f70a1d2db4117ab43e623f8a060a4a3f))
41
+ * take --frames in the SID player ([b9a54f3](https://github.com/elektronaut/badline/commit/b9a54f3c7bb84edd67c69ee38efb4f5f79347760))
42
+ * take --frames in the SID player ([3483684](https://github.com/elektronaut/badline/commit/3483684fe8efdf2b828d85db98c9e4c1667293a4))
43
+ * take a Plus/4 .bin cartridge from Quick open and drag and drop ([214dcd6](https://github.com/elektronaut/badline/commit/214dcd63bc48956d0f2139d89bab63613dde78d7))
44
+ * take a Plus/4 .bin cartridge from Quick open and drag and drop ([32ec8d0](https://github.com/elektronaut/badline/commit/32ec8d0deb54000a1c2b956a02ad26b53ef2cf6d))
45
+ * type ACIA#feed's bytes for Spinel ([32b9f72](https://github.com/elektronaut/badline/commit/32b9f72a7ad24cd862531d19e545e117c7e8e340))
46
+
47
+
48
+ ### Performance Improvements
49
+
50
+ * check the init threshold and the ACIA with one compare ([b0050a7](https://github.com/elektronaut/badline/commit/b0050a7a4716e21551882f10c0811a6f0284686a))
51
+ * count the SID card's cycles when it is touched ([d0cec9c](https://github.com/elektronaut/badline/commit/d0cec9c9d9144bb2303d0cba0b182dcf705d1b32))
52
+ * look in on the ACIA's IRQ only when it is due ([d099091](https://github.com/elektronaut/badline/commit/d09909138087a305ce59384dafbece7ef08f340a))
53
+ * sleep the 1551 through its idle loop ([3fabf2a](https://github.com/elektronaut/badline/commit/3fabf2ab6f866bf088682b14e5f04e4dd9054d29))
54
+ * sleep the 1551 through its idle loop ([8d99fa3](https://github.com/elektronaut/badline/commit/8d99fa3ac22f862a51e967dc5a69471dece782da))
55
+
56
+
57
+ ### Reverts
58
+
59
+ * find the longest G64 track with a splat again ([31a3df2](https://github.com/elektronaut/badline/commit/31a3df2d35ab79a072a46213d5996068eaa2d793))
60
+
61
+
62
+ ### Miscellaneous Chores
63
+
64
+ * release 0.15.1 ([23586fb](https://github.com/elektronaut/badline/commit/23586fbc26b2132c4a8afe04d44cbeaed6b0eb12))
65
+
66
+ ## [0.15.0](https://github.com/elektronaut/badline/compare/v0.14.0...v0.15.0) (2026-10-12)
67
+
68
+
69
+ ### Features
70
+
71
+ * run the Plus/4 and the C16 in the window with badline plus4 ([935bcf1](https://github.com/elektronaut/badline/commit/935bcf11b986c65f01024515d7c98ac1efa46530))
72
+ * paint the TED's picture ([ede7805](https://github.com/elektronaut/badline/commit/ede7805b8113cb6321fbfdffedcb6b7a79e95983))
73
+ * play the TED's sound ([a34efd6](https://github.com/elektronaut/badline/commit/a34efd67dbec995f246781452bce7c9c070ed10b))
74
+ * read the Plus/4's joysticks through the keyboard latch and map its keys ([6a1f7cb](https://github.com/elektronaut/badline/commit/6a1f7cb5a9a9426562fe5b3c9106a245bc23d287))
75
+ * attach programs, disks and cartridges to a Plus/4 ([84a86f4](https://github.com/elektronaut/badline/commit/84a86f43e97e08fdb4ea21ef909adf54bc09540c))
76
+ * put a true 1541 or 1581 on the Plus/4's serial bus ([bd068ff](https://github.com/elektronaut/badline/commit/bd068ffd1b337915ad70ed9e96f10df6ca770c05))
77
+ * put Plus/4 cartridges in both slots, from .crt or raw .bin ([42ae7c0](https://github.com/elektronaut/badline/commit/42ae7c0f66dd200bc1787ad3a9bd62c4f57719eb))
78
+ * play and record Plus/4 and C16 tapes ([cd19fa9](https://github.com/elektronaut/badline/commit/cd19fa920a4e2b8a488011872ca98f6bd95cb43a))
79
+ * show the Plus/4's picture, play its sound and drive its joysticks in the front end ([4213c26](https://github.com/elektronaut/badline/commit/4213c26ffeaafe46bc6ec42433e2dc763b70aa6a))
80
+ * keyed snapshots for the Plus/4 and the C16 ([c7a1ace](https://github.com/elektronaut/badline/commit/c7a1ace2c3c94064bb14841773e109c56e49f1d6))
81
+ * save the Plus/4 from F11 and the Snapshots page ([853085f](https://github.com/elektronaut/badline/commit/853085f0c177fcbf305c1fd60cd1a800dfcbc266))
82
+ * save cartridge mappers' registers in snapshots ([9ea6e0b](https://github.com/elektronaut/badline/commit/9ea6e0b2669c4ae9ed8270cf3de345787c76dcb3))
83
+ * save the extra SIDs in snapshots ([bf7f142](https://github.com/elektronaut/badline/commit/bf7f1426472620b6168352ba3bf74e4780d29e89))
84
+
85
+ ### Bug Fixes
86
+
87
+ * store a C128 bank LOAD into the I/O that bank maps ([58672c2](https://github.com/elektronaut/badline/commit/58672c2bb7b9a5fed8d75d72007d00444eebb696))
88
+
3
89
  ## [0.14.0](https://github.com/elektronaut/badline/compare/v0.13.0...v0.14.0) (2026-10-11)
4
90
 
5
91
 
data/CLAUDE.md CHANGED
@@ -69,10 +69,10 @@ file: `core.rb` requires their members one by one.
69
69
  | rspec (`spec/`) | `bundle exec rspec` | Unit behaviour, all of `lib/` |
70
70
  | SingleStepTests 65x02 | `rake test` (100 sampled cases per opcode) | CPU, per-cycle bus traces |
71
71
  | SingleStepTests z80 | `rake test` (the first 100 cases per opcode, `Z80_SAMPLE=all` for all 1,604,000) | `Z80`: registers, flags, ports and the bus pins on every T-state |
72
- | Wolfgang Lorenz suite | `bin/lorenz` | CPU, CIA, interrupts |
73
- | VICE testbench | `bin/testbench <subtree>` | `VICII/`, `CIA/`, `interrupts/`, `CPU/`, cartridges with `--carts`, the true 1541 drive with `--drive`, the VIC-20 with `--vic20`, the C128 in C64 mode with `--c128c64`, in C128 mode with `--c128`, and its Z80 with `--c128-z80` |
72
+ | Wolfgang Lorenz suite | `bin/lorenz` | CPU, CIA, interrupts; its plus4 build with `--plus4`: the CPU on the 264's bus, the TED's clock, DMA, timers and interrupt |
73
+ | VICE testbench | `bin/testbench <subtree>` | `VICII/`, `CIA/`, `interrupts/`, `CPU/`, cartridges with `--carts`, the true 1541 drive with `--drive`, the VIC-20 with `--vic20`, the C128 in C64 mode with `--c128c64`, in C128 mode with `--c128`, and its Z80 with `--c128-z80`, the Plus/4 with `--plus4` and the C16 with `--c16` |
74
74
  | VICE SID testprogs | `bin/sidtests` | SID |
75
- | Drive scenarios | `bin/drive_scenarios` | The true 1541 running the DOS ROM: save, format, the error channel, idle, write protect and autostart |
75
+ | Drive scenarios | `bin/drive_scenarios` | The true 1541 running the DOS ROM: save, format, the error channel, idle, write protect and autostart; the `plus4-*` rows on the Plus/4 and C16, with the 1541 and 1581 on their serial bus and a tape saved and loaded back on the datasette |
76
76
  | CIA offline grids | `bundle exec rspec --tag slow spec/badline/chips/cia` | CIA timers and shift register, against a bare CIA in about 2 min |
77
77
 
78
78
  The CIA offline grids replay Lorenz's `cia1ta` and `cia1tb` sweeps (about
@@ -190,7 +190,7 @@ overrides that, capped by the core count, but keep the default, because
190
190
  other worktrees share the machine. Whole runs at 4 shards on an M-series
191
191
  laptop take 15 min for `testbench` (`VICII/`), 11 for `testbench-cia`, 1 for
192
192
  `testbench-interrupts`, 37 for `testbench-irqdma`, 11 for
193
- `testbench-cpu`, 2 for `testbench-carts`, about 25 for `testbench-expansions`, under 1 for `testbench-vic20` and about 30 for `testbench-c128c64`. `sid` takes about 12 min. `lorenz` chains itself and takes
193
+ `testbench-cpu`, 2 for `testbench-carts`, about 25 for `testbench-expansions`, under 1 for `testbench-vic20`, `testbench-plus4`, `testbench-c16` and `testbench-plus4-ntsc`, and about 30 for `testbench-c128c64`. `lorenz-plus4` takes about 21 min whole on the Spinel build. `rake regression:lorenz-plus4-1` to `lorenz-plus4-4` run it as four stretches, cut where `lorenz` is, and the last, through the trap tests the chain resumes past, is about half of it. `sid` takes about 12 min. `lorenz` chains itself and takes
194
194
  about 2.5 h on CI whole. `rake regression:lorenz-1` to `lorenz-4` run it as
195
195
  four stretches of about 40 min each, and they can run side by side.
196
196
  `test/baselines/README.md` has the full table. A killed `bin/testbench` run
@@ -239,6 +239,13 @@ the rows your change can't reach tell you nothing about it.
239
239
  - For a change whose reach you can't bound to a set of filters, such as
240
240
  reordering `C64#cycle!` or changing the LOAD trap every suite loads
241
241
  through, push and let CI run the suites
242
+ - Each Spinel harness compiles only the code its own entry point reaches.
243
+ A method nothing in a harness calls, such as a host-side API only the
244
+ window uses, is compiled only by `native/badline.rb`, with untyped
245
+ arguments, and can fail there alone. A change that adds such a method
246
+ builds the native binary locally (`rake native:build`; on macOS with
247
+ `SPINEL_CC="cc -Wno-nullability-completeness"`) before it's pushed, or
248
+ types its arguments in `spinel/sig`
242
249
  - The Regression workflow runs the suites on CRuby, started by hand from
243
250
  the Actions tab, for a person checking that CRuby and Spinel agree.
244
251
  Agents don't start it
@@ -255,7 +262,17 @@ the 6526A) for anything the interrupt register or the CIA model reaches; cartrid
255
262
  `testbench-carts`, plus `testbench-expansions` for banking; GEO-RAM, +60K,
256
263
  +256K, the REU or the VIC's BA line the REU follows → `testbench-expansions`; the 1541 drive, VIA or IEC bus →
257
264
  `testbench-drive` (`bin/testbench --drive`) and `drive-scenarios` (`bin/drive_scenarios <filter>`), plus `testbench-vic20` for the VIA; the VIC-20 (`vic20/`) →
258
- `testbench-vic20` (`bin/testbench --vic20`); the C128 (`c128.rb`, `c128/`), or
265
+ `testbench-vic20` (`bin/testbench --vic20`); the 264 series (`plus4.rb`,
266
+ `plus4/`), the TED (`chips/ted.rb`, `chips/ted/`) or the TIA (`chips/tia.rb`)
267
+ → `testbench-plus4` (`bin/testbench --plus4`) and `testbench-c16`
268
+ (`bin/testbench --c16`), plus `testbench-plus4-ntsc`
269
+ (`bin/testbench --plus4 --ntsc`) for anything NTSC timing or the picture
270
+ reaches, `lorenz-plus4` (`bin/lorenz --plus4`) for
271
+ anything the CPU's clock, the TED's DMA, its timers or its interrupt reach,
272
+ and the `plus4-*` drive scenarios (`bin/drive_scenarios plus4`) for its
273
+ serial bus, its media, the CPU port or the datasette.
274
+ Its tests run one at a time as the C64's do, with
275
+ `ruby --yjit bin/lorenz --plus4 --resume <test> --stop-after <test>`; the C128 (`c128.rb`, `c128/`), or
259
276
  the VIC-IIe, CPU or PLA code it shares with the C64 → `testbench-c128c64`
260
277
  (`bin/testbench --c128c64`); the C128's Z80, MMU or hand-over → `testbench-c128-z80` (`bin/testbench --c128-z80`) and `testbench-c128`; SID → `sid`, plus `sid-8580` for anything the 8580
261
278
  model reaches (`bin/sidtests --sid 8580`). Leave the Lorenz chain to CI,
data/README.md CHANGED
@@ -13,7 +13,7 @@ are modelled at the cycle level.
13
13
  It runs programs, disk and tape images, cartridges and SID tunes, and
14
14
  the SDL2 front end supports the keyboard, joysticks, game controllers,
15
15
  paddles and a 1351 mouse. It also runs a PAL VIC-20, as
16
- `badline vic20`, and the C128, in C128 mode on 40 or 80 columns and in C64 mode, as `badline c128`. See [What's emulated](#whats-emulated) for the details.
16
+ `badline vic20`, the C128, in C128 mode on 40 or 80 columns and in C64 mode, as `badline c128`, and the Plus/4, the C16 and the C116, as `badline plus4`. See [What's emulated](#whats-emulated) for the details.
17
17
 
18
18
  It comes in two builds of the same emulator:
19
19
 
@@ -69,8 +69,8 @@ from it.
69
69
 
70
70
  The first argument can name the machine, as in `badline c64 game.prg`.
71
71
  The C64 is the default, and `--model` picks which C64. See
72
- [The VIC-20](#the-vic-20) for `badline vic20` and [The C128](#the-c128)
73
- for `badline c128`.
72
+ [The VIC-20](#the-vic-20) for `badline vic20`, [The C128](#the-c128)
73
+ for `badline c128` and [The Plus/4](#the-plus4) for `badline plus4`.
74
74
 
75
75
  `badline-ruby` takes the same media and the same options, with the
76
76
  differences noted in the table. `--help` lists the options for either.
@@ -81,12 +81,17 @@ differences noted in the table. `--help` lists the options for either.
81
81
  | --- | --- |
82
82
  | `--no-autostart` | Attach the media and stop at `READY.`, so you can type the `LOAD` yourself |
83
83
  | `--writable` | Let the machine write to disk images. Without it, a disk goes in write-protected: the drive reports `26,WRITE PROTECT ON` for any write and the image file stays as it was |
84
- | `--true-drive` | Put an emulated 1541 on device 8 instead of the KERNAL traps. See [Media](#media) |
84
+ | `--true-drive` | Put an emulated 1541 on device 8 instead of the KERNAL traps, or a 1551 on the Plus/4. See [Media](#media) |
85
+ | `--drive-type 1541` | On the Plus/4, make the true drive on device 8 an emulated 1541 on the serial bus in place of the 1551. It implies `--true-drive`. See [The Plus/4](#the-plus4) |
85
86
  | `-s`, `--subtune N` | Pick a subtune of a `.sid` file, counting from 1 |
86
87
  | `--sid 6581`, `--sid 8580` | Fit the older or newer SID. `--sid auto`, the default, takes a `.sid` tune's own |
87
- | `--ram SIZE` | Give a VIC-20 the RAM expansion `SIZE`: `unexpanded`, `3k`, `8k`, `16k`, `24k`, `32k` or `all`. Without it, the VIC-20 gets the expansion its media needs. See [The VIC-20](#the-vic-20) |
88
+ | `--ram SIZE` | Give a VIC-20 the RAM expansion `SIZE`: `unexpanded`, `3k`, `8k`, `16k`, `24k`, `32k` or `all`. Without it, the VIC-20 gets the expansion its media needs. See [The VIC-20](#the-vic-20). On the Plus/4, `16k`, `32k` or `64k` of RAM in place of the model's own |
89
+ | `--c1lo FILE`, `--c1hi FILE`, `--c2lo FILE`, `--c2hi FILE` | Put a raw `.bin` ROM image in one of the Plus/4's cartridge slots: cartridge 1 or 2, low (`$8000`) or high (`$C000`). See [The Plus/4](#the-plus4) |
90
+ | `--sid-card 6581`, `--sid-card 8580` | Fit a Plus/4 or C16 with a SID card at `$FD40`. See [The Plus/4](#the-plus4) |
91
+ | `--sid-card-address fd40`, `--sid-card-address fe80` | Put the SID card at `$FD40` (the default) or at `$FE80` |
92
+ | `--ram-expansion NAME` | Fit a Plus/4 or C16 with a RAM expansion: `hannes256`, `hannes1m` or `csory256`. See [The Plus/4](#the-plus4) |
88
93
  | `--reu SIZE` | Plug in a RAM Expansion Unit of `SIZE` K: 128, 256, 512 (a 1750) or up to 16384 |
89
- | `--model NAME` | Run another model of the machine, named as in VICE. For the C64: `c64` (the default, a PAL C64 with the 6569 VIC-II, 6526 CIAs and the 6581 SID), `c64c` (the PAL C64C, with the 8565, 6526As and the 8580), `ntsc` (the 6567R8), `newntsc` (the NTSC C64C, with the 8562, 6526As and the 8580), `oldntsc` (the first NTSC C64s' 6567R56A), `drean` (the Drean C64 of Argentina, PAL-N with the 6572), `sx64` (the portable SX-64, with its own KERNAL and no datasette), `pet64` (the PET 64 or Educator 64, a PAL C64 in a PET's case with its own KERNAL and a green monochrome monitor) `c64gs` (the C64GS games console, a PAL C64C with its own BASIC and KERNAL, and no keyboard or datasette) or `ultimax` (the MAX Machine of Japan, NTSC with 2K of RAM, one CIA and no ROMs, which runs only a cartridge). `--sid` or a `.sid` tune's own SID takes the model's place |
94
+ | `--model NAME` | Run another model of the machine, named as in VICE. For the C64: `c64` (the default, a PAL C64 with the 6569 VIC-II, 6526 CIAs and the 6581 SID), `c64c` (the PAL C64C, with the 8565, 6526As and the 8580), `ntsc` (the 6567R8), `newntsc` (the NTSC C64C, with the 8562, 6526As and the 8580), `oldntsc` (the first NTSC C64s' 6567R56A), `drean` (the Drean C64 of Argentina, PAL-N with the 6572), `sx64` (the portable SX-64, with its own KERNAL and no datasette), `pet64` (the PET 64 or Educator 64, a PAL C64 in a PET's case with its own KERNAL and a green monochrome monitor) `c64gs` (the C64GS games console, a PAL C64C with its own BASIC and KERNAL, and no keyboard or datasette) or `ultimax` (the MAX Machine of Japan, NTSC with 2K of RAM, one CIA and no ROMs, which runs only a cartridge). `--sid` or a `.sid` tune's own SID takes the model's place. The VIC-20, the C128 and the Plus/4 have models of their own: see their sections |
90
95
  | `--ntsc` | Run an NTSC C64, as `--model ntsc` does |
91
96
  | `--c64` | Start a C128 in C64 mode, holding `C=` at power-on. See [The C128](#the-c128) |
92
97
  | `--no-sound` | Don't play the SID (`badline` only, where sound is on by default) |
@@ -101,7 +106,7 @@ differences noted in the table. `--help` lists the options for either.
101
106
 
102
107
  | Option | Effect |
103
108
  | --- | --- |
104
- | `--frames N` | Quit after N frames |
109
+ | `--frames N` | Quit after N frames, in the SID player as in the machine's window |
105
110
  | `--unpaced` | Run as fast as it can, without vsync or pacing |
106
111
  | `--at FRAME:EVENT` | Press keys, type, swap media, open the pause menu or take a screenshot once `FRAME` frames have run |
107
112
  | `--script FILE` | Run the events in `FILE`, one `FRAME:EVENT` a line |
@@ -221,6 +226,63 @@ no host key yet: `Tab` and the arrows keep their C64 uses.
221
226
  `F11`, `F12` and the pause menu save and load the C128 in badline's own
222
227
  snapshots, and x128's `.vsf` files don't load.
223
228
 
229
+ ## The Plus/4
230
+
231
+ `badline plus4` runs a PAL Plus/4, with BASIC 3.5 and the 3-plus-1
232
+ function ROMs, and takes the same media as the C64 apart from SID tunes:
233
+
234
+ ```sh
235
+ badline plus4 # READY., in BASIC 3.5
236
+ badline plus4 game.prg # Load and run a program
237
+ badline plus4 game.d64 # Mount a disk image as device 8 and load it
238
+ badline plus4 game.tap # Insert a tape and load it
239
+ badline plus4 game.crt # Attach a cartridge
240
+ badline plus4 --model c16 game.bin # A C16 with a cartridge's ROM image
241
+ ```
242
+
243
+ `--model` picks the machine: `plus4` (the default, PAL with 64K of RAM),
244
+ `c16` (PAL with 16K, without the function ROMs, the ACIA and the user
245
+ port), `c116`, which is the C16 in another case, and `plus4ntsc` and
246
+ `c16ntsc` for their NTSC versions. `--ram 16k`, `32k` or `64k` fits other
247
+ RAM in place of the model's own.
248
+
249
+ A program loads at the start of BASIC 3.5, `$1001`, and runs. A tape's
250
+ `LOAD` reads the datasette, as the 264 KERNAL's does by default. A
251
+ cartridge is a `.crt` or a raw `.bin` ROM image. A `.bin` goes in
252
+ cartridge 1, its low slot for up to 16K and both slots for 32K, and
253
+ `--c1lo`, `--c1hi`, `--c2lo` and `--c2hi` put one in the slot they name,
254
+ as xplus4's options do:
255
+
256
+ ```sh
257
+ badline plus4 --c1lo game-low.bin --c1hi game-high.bin
258
+ ```
259
+
260
+ `--sid-card 6581` or `--sid-card 8580` fits a SID card, as third
261
+ parties built for the 264s, with its SID at `$FD40`-`$FD5F`. The card
262
+ clocks the SID at the TED's single clock, 886,724 Hz on PAL, so a C64
263
+ tune plays about a semitone flat, as it did on those cards. Its sound
264
+ plays with the TED's, and the Sound page swaps its SID's model.
265
+ `--sid-card-address fe80` puts the SID at `$FE80`-`$FE9F` instead, as
266
+ Csory's card does, beside a 1551's TCBM interface at `$FEC0`.
267
+
268
+ `--ram-expansion hannes256` or `hannes1m` fits Hannes's 256K or 1M RAM
269
+ expansion, which banks 64K at a time through its register at `$FD16`,
270
+ above `$1000` or `$4000`, with the TED fetching from the CPU's bank or
271
+ the standard one. `csory256` fits the 256K board with Csory's mapping
272
+ as well, which puts one of 16 blocks of 16K in a window that `$FD15`
273
+ picks. Each needs 64K of the machine's own, and a C16 gets that much.
274
+
275
+ Disks go through the KERNAL traps or, with `--true-drive`, a 1551 on
276
+ device 8, on TCBM, the parallel cable to its interface in the expansion
277
+ port, on the C16 as on the Plus/4. `--drive-type 1541` puts a 1541 on
278
+ the serial bus there instead, and a `.d81` goes in a 1581 on the serial
279
+ bus. The pause menu's Power
280
+ page names the model, its RAM and a RAM expansion, and its Expansion port page names the
281
+ cartridges in, or the slot of one a snapshot put in, and takes them all
282
+ out. `F11` and the
283
+ Snapshots page save it as they do the others, but not for VICE.
284
+ [Input](#input) lists its keys.
285
+
224
286
  ## Snapshots
225
287
 
226
288
  `F11` quicksaves the whole machine to the next of five slots in
@@ -272,6 +334,21 @@ types `"`. These keys have no same-named host key:
272
334
  | `+` / `*` | Keypad `+` / Keypad `*` |
273
335
  | `RESTORE` | `Page Up` |
274
336
 
337
+ The Plus/4 and the C16 keep the C64's host keys for the keys they share,
338
+ and put their own here:
339
+
340
+ | Plus/4 | Host |
341
+ |--------|------|
342
+ | `ESC` | `Escape` |
343
+ | `RUN/STOP` | `Page Down` |
344
+ | `F1` / `F2` / `F3` | `F1` / `F2` / `F3` |
345
+ | `HELP` | `F4`, `Insert` or `Help` |
346
+ | `CRSR ←` / `→` / `↑` / `↓` | `Left` / `Right` / `Up` / `Down` |
347
+ | `SHIFT` | `Left Shift` or `Right Shift` |
348
+
349
+ They have no `RESTORE`, `←` or `↑` key, so `Page Up`, `` ` `` and `]`
350
+ press nothing.
351
+
275
352
  `Tab` switches the keys between the C64 keyboard and the joysticks. The
276
353
  window title shows where they go, and any device plugged into a control
277
354
  port:
@@ -314,10 +391,10 @@ too.
314
391
  | Snapshots | Quicksave, save under a name, load a named save, and the latest quicksaves and autosaves |
315
392
  | Drive 8 | The disk: insert, eject, the previous or next disk of its set, and whether it's writable |
316
393
  | Datasette | The tape: insert, eject, PLAY and REWIND |
317
- | Expansion port | The cartridge: insert, remove, and its freeze button if it has one |
394
+ | Expansion port | The cartridge's name: a `.crt`'s own, or a raw image's file name. Insert, remove, and its freeze button if it has one. On the VIC-20, the cartridge and the RAM expansion |
318
395
  | Ports | The device in each control port, and where the keys go |
319
396
  | Sound | Mute, and the SID's model |
320
- | Power | Reset, power cycle and quit, and on a C128 its model and mode |
397
+ | Power | Reset, power cycle and quit, on a C128 its model and mode, and on a Plus/4 its model and RAM |
321
398
 
322
399
  INSERT opens a file browser. A disk's set is the `.m3u` or `.vfl` list it
323
400
  was opened from, or one in its folder that lists it. Without one, it comes
@@ -330,7 +407,9 @@ inserting or removing a cartridge does, since each power cycles the
330
407
  machine.
331
408
 
332
409
  A disk, list of disks or tape dropped on the window goes into its drive. A cartridge,
333
- program or `.sid` dropped on it opens the menu to ask first.
410
+ program or `.sid` dropped on it opens the menu to ask first. On the Plus/4, a
411
+ `.bin` ROM image dropped or opened with Quick open is a cartridge, and goes
412
+ in cartridge 1 as it does from the command line.
334
413
 
335
414
  ## What's emulated
336
415
 
@@ -357,13 +436,24 @@ program or `.sid` dropped on it opens the menu to ask first.
357
436
  port, FAST mode, the VIC-IIe with its extra keyboard lines, the 8722
358
437
  MMU, the 8563 or 8568 VDC with its 80 column display, and 128K of RAM
359
438
  (`badline c128`), and the Z80, which boots the machine.
439
+ - **Plus/4, C16 and C116**: the 7501, the TED with its picture, sound,
440
+ timers and the CPU's single and double clock, 16K to 64K of RAM, ROM
441
+ banking with the 3-plus-1 function ROMs, the keyboard and both
442
+ joysticks, cartridges in both slots, the datasette and the serial bus
443
+ to device 8, PAL and NTSC (`badline plus4`). The 6551 ACIA sends and
444
+ receives at its baud rates, with nothing on the user port; Ruby code
445
+ driving the machine can plug in a terminal, whose bytes it feeds and
446
+ drains, or a loopback plug (`Plus4::ACIA#plug`).
360
447
  - **1541**: an emulated drive running its own DOS (`--true-drive`).
361
448
  - **1571**: the C128D's drive running DOS 3.0, in 1541 mode and in 1571
362
449
  mode at 2 MHz with both sides of a `.d71` or `.g71`, and fast serial
363
450
  (burst) to a C128 in C128 mode (`badline c128 --true-drive`).
364
451
  - **1581**: the 3.5" drive running its own DOS on its WD1772 and 8520,
365
- reading and writing `.d81` images, on the C64, the VIC-20 and the C128
452
+ reading and writing `.d81` images, on the C64, the VIC-20, the C128 and the Plus/4
366
453
  (`--true-drive` with a `.d81`).
454
+ - **1551**: the 264 series' parallel drive, its 6510T running its own DOS
455
+ at 2 MHz with the 1541's mechanism, on TCBM to a Plus/4 or a C16
456
+ (`badline plus4 --true-drive`).
367
457
  - **Cartridges**: standard 8K, 16K and Ultimax, Simons' BASIC, Ocean,
368
458
  Fun Play / Power Play, Super Games, Epyx FastLoad, Westermann
369
459
  Learning, Rex Utility, C64 Game System / System 3, Dinamic, Zaxxon /
data/doc/media.md CHANGED
@@ -34,6 +34,10 @@ or directories. Loading runs at the speed of a real 1541, and the
34
34
  drive's red activity LED and green power LED light in the bottom right
35
35
  corner of the border. A 1581 flashes its power LED after an error.
36
36
 
37
+ On the Plus/4 and the C16, `--true-drive` puts an emulated 1551 there
38
+ instead, on TCBM, the parallel cable to its interface in the expansion
39
+ port, and `--drive-type 1541` a 1541 on the serial bus.
40
+
37
41
  A `.g64` holds the disk's raw GCR, half tracks and all, so copy
38
42
  protection and fast loaders that read it work.
39
43
 
@@ -99,6 +103,21 @@ the entries after a `UNIT 8` line, or before any `UNIT` line, count.
99
103
  `Media.attach` and the command line take a list as media and attach its
100
104
  first disk.
101
105
 
106
+ ## Recording to tape
107
+
108
+ From Ruby, a blank tape made with
109
+ `Badline::Storage::TAP.create(path, platform:)` (0 for the C64, 1 for
110
+ the VIC-20, 2 for the Plus/4 and the C16) goes in the datasette with
111
+ `computer.datasette.insert`, `record!` presses RECORD and PLAY, and
112
+ `stop!` lets them up and writes the tape to its file. The C64 and the
113
+ VIC-20 record version 1 TAPs, and the Plus/4 and the C16 version 2 TAPs
114
+ of half waves.
115
+
116
+ A program SAVEd that way on the C64 loads and runs in VICE's x64sc, on
117
+ the VIC-20 in xvic, and on the Plus/4 or the C16 in xplus4 as a Plus/4.
118
+ Neither the Plus/4's tape nor the C16's ran on xplus4's C16 model.
119
+ Checked with VICE 3.10.
120
+
102
121
  ## The light pen
103
122
 
104
123
  Control port 1's fire line is also the VIC-II's light pen input, so
@@ -39,6 +39,7 @@ only catches the rows that happen to move.
39
39
  - [VIC-I fetches and the V-bus](#vic-i-fetches-and-the-v-bus)
40
40
  - [VIC-I sound](#vic-i-sound)
41
41
  - [TED beam and the 7501 port](#ted-beam-and-the-7501-port)
42
+ - [TED sound](#ted-sound)
42
43
  - [1541 serial port](#1541-serial-port)
43
44
  - [1541 disk mechanism](#1541-disk-mechanism)
44
45
  - [REU DMA](#reu-dma)
@@ -1519,6 +1520,150 @@ finds one should start here.
1519
1520
  - Pinned by `lorenz-plus4`'s rows for those tests. The xplus4 verdicts
1520
1521
  are its exit codes with `-debugcart`, one program at a time.
1521
1522
 
1523
+ The TED's fetch counters (`Chips::TED::Fetches`) follow xplus4 where the
1524
+ datasheet is silent, and the datasheet where the two disagree. Each was
1525
+ checked with probes that sample `$FF1A`, `$FF1B`, `$FF1D`, `$FF1E` and
1526
+ `$FF1F` through a frame, run on badline and xplus4 r45942 alike.
1527
+
1528
+ - The row's line (`$FF1F` bits 0-2) steps with the line count only on the
1529
+ display window's lines, so it holds 7 from line 204 to the end of the
1530
+ frame, and the character position reload holds 1000 there. The frame's
1531
+ end clears both.
1532
+ - The blink counter (`$FF1F` bits 3-6) counts at horizontal count 336, the
1533
+ datasheet's "Increment Blink", on line 256 of a PAL frame and line 228
1534
+ of an NTSC one, the lines xplus4 counts on. The datasheet gives no line.
1535
+ - A row's last line keeps its own attributes, although the line fetches
1536
+ the next row's, as xplus4 shows it: the attributes take hold as each
1537
+ character's pointer is fetched.
1538
+ - The attribute line reads the row the reload will point to after its own
1539
+ latch: 40 on from it on a row's eighth line, and the reload itself on any
1540
+ other line, as on the first row of a frame or after a scroll change
1541
+ stretched a row past eight lines.
1542
+ - The pointer line is the line after an attribute line, whatever the
1543
+ scroll says by then (the datasheet's DMA timing, step 8). A line whose
1544
+ scroll alone asks for pointers fetches none, so a scroll of 7 starts the
1545
+ first row on line 8, not line 0.
1546
+ - The row's line runs on from the frame's first row, wrapping from 7 to
1547
+ 0, and a pointer line doesn't reset it. After a scroll change moves the
1548
+ DMA lines, a row starts on whatever line the counter has reached.
1549
+ - Both pinned by xplus4 screenshots of scroll changes inside a text row,
1550
+ on lines 20, 100 and 101.
1551
+ - `$FF1A` reads back both bits written to it, the datasheet's two MSBs of
1552
+ the reload. xplus4 reads bit 1 as 0.
1553
+ - xplus4 reads the reload 40 higher for a few cycles around the line step
1554
+ on some lines. badline reads the register as it stands.
1555
+
1556
+ The TED's picture (`Chips::TED::Picture` and `Modes`) matches xplus4's
1557
+ screenshots pixel for pixel, by palette index, on probes for every mode,
1558
+ both column widths, both row counts, each horizontal and vertical scroll,
1559
+ the idle lines before the first row, cursor and flash, and scroll changes
1560
+ mid-frame. Where it follows xplus4 over the datasheet:
1561
+
1562
+ - The 38-column window is pixels 39-342 of the 384, 7 in on the left and
1563
+ 9 on the right. The datasheet's counts (3 and 307 against 451 and 315)
1564
+ would make it 8 and 8.
1565
+ - A multicolour bitmap's 01 takes the luminance of the attribute's bits
1566
+ 0-2, as the hires bitmap's 1 does. The datasheet gives it bits 4-6.
1567
+ - A register write takes hold 19 dots after its cycle starts
1568
+ (`Picture::WRITE_DELAY`), on a character cell's boundary with no scroll.
1569
+ That puts a raster interrupt's colour change within a cycle or two of
1570
+ where xplus4 puts it. Code timed from `$FF1E` or a DMA stall lands 3
1571
+ cycles later than in xplus4, the other side of the line-step difference
1572
+ above. Pinned by probes that change `$FF15` and `$FF19` every 6 cycles,
1573
+ timed both ways, and the spec guard *shows a register written mid-line
1574
+ from the pixel the write lands on* in
1575
+ [`chips/ted_spec.rb`](../spec/badline/chips/ted_spec.rb).
1576
+ - The picture's lines are scanlines as they go out. They follow the line
1577
+ count until a write to `$FF1C`-`$FF1D` moves it, start over where the
1578
+ count wraps to 0 at the end of the frame, and step with each line
1579
+ otherwise. The vertical border is a flip-flop: the window opens when
1580
+ the count reaches line 4 (8 with 24 rows) and shuts when it reaches 204
1581
+ (200), so a count moved past line 4 leaves the frame bordered. Pinned by
1582
+ `TED/write-scanline-coarse.prg`, which matches xplus4's screenshot pixel
1583
+ for pixel, and the spec guards *keeps the window shut through a frame
1584
+ whose line count jumps past line 4* and *paints the scanline after a
1585
+ line count write on the picture's next line*.
1586
+ - A write to `$FF1E` changes nothing: xplus4 reads the same positions
1587
+ after writes of `$00` to `$FF` on line 100, and its screenshots don't
1588
+ move. Härsfalvi says writing back a value read at the right time
1589
+ affects the screen, which no probe here reproduces.
1590
+ - Freezing the TED (`$FF07` bit 5) for about 100 cycles on line 100
1591
+ leaves the picture as xplus4 shows it.
1592
+ - The blink counter's carry turns cursor and flash over together: in one
1593
+ turn flashing characters show the background and the cursor is off, in
1594
+ the other both show, the cursor as reverse.
1595
+
1596
+ ## TED sound
1597
+
1598
+ No testprog checks the TED's sound, so these rules are pinned by xplus4
1599
+ (VICE 3.10) recordings, run as a black box: `-sounddev wav` at 96 kHz of
1600
+ probe programs that set the registers, the same programs run on badline
1601
+ with the sound's level sampled at the same rate, and the two compared by
1602
+ period, level and noise bits. xplus4 records the raw level, with no
1603
+ filter, so its samples read off as levels. xplus4's own source wasn't
1604
+ read.
1605
+
1606
+ - A voice counts once every 4 cycles and toggles its output every
1607
+ 1023 - x counts, so its frequency is the clock over 8 * (1023 - x).
1608
+ `$3FF` counts 1,024. The datasheet's formula has 1024 - x, and its PAL
1609
+ constant, 111,840.45, is 1,000 above the clock over 8.
1610
+ - Pinned by xplus4: voice 1 at `$000`, `$200`, `$300`, `$3F0` and `$3FF`
1611
+ measures 108.344, 216.900, 434.653, 7389.08 and 108.239 Hz. Their
1612
+ ratios are 1023 : 511 : 255 : 15 : 1024 to 5 digits, which 1024 - x
1613
+ can't give, and badline's recordings measure the same within 0.005%.
1614
+ - Spec guard: *a voice's counter* in
1615
+ [`chips/ted/sound_spec.rb`](../spec/badline/chips/ted/sound_spec.rb).
1616
+ - `$3FE` stops a voice after its next toggle, its output high whatever
1617
+ the phase, square wave or noise, and stops the noise's shifts.
1618
+ - Pinned by xplus4: `$3FE` written while voice 1 plays at `$200`, after
1619
+ 21, 22, 23 and 24 frames, holds the level high each time, and noise
1620
+ at `$3FE` holds high too. Noise held at `$3FE` for 20, 21 or 23
1621
+ frames plays on with the same bits once it leaves, one shift on from
1622
+ where it would be if the pending toggle were dropped.
1623
+ - Spec guard: *$3FE* in
1624
+ [`chips/ted/sound_spec.rb`](../spec/badline/chips/ted/sound_spec.rb).
1625
+ - The noise is an 8-bit shift register that shifts at each of voice 2's
1626
+ toggles, taking in the XOR of bits 1, 4, 5 and 7 at bit 0. Bit 1 is the
1627
+ output. Voice 2's counter and the noise run whether voice 2 plays the
1628
+ square wave, the noise or nothing, and the square wins when bits 5 and
1629
+ 6 of `$FF11` are both set.
1630
+ - Pinned by xplus4: 21,306 bits of noise at `$3D7` after a reload,
1631
+ decoded from a recording, satisfy s(n) = s(n-2) ^ s(n-5) ^ s(n-6) ^
1632
+ s(n-8) (Berlekamp-Massey gives linear complexity 8), with period 255,
1633
+ starting 1100110111101110. Run back from there, the register held all
1634
+ ones with the first two output bits already in it, so the output is
1635
+ bit 1. Released from the reload into the square wave, into nothing or
1636
+ into noise, voice 2 plays the same bits once switched to noise.
1637
+ badline's recordings decode to the same first 64 bits in each of
1638
+ these runs and in the `$3FE` ones above.
1639
+ - Spec guard: *the noise* in
1640
+ [`chips/ted/sound_spec.rb`](../spec/badline/chips/ted/sound_spec.rb).
1641
+ - While `$FF11` bit 7 is set, the voices that are on hold high, the noise
1642
+ is silent and its register holds all ones. Written clear, each voice
1643
+ starts on a whole high half-wave. With the voices held high, the volume
1644
+ plays 9-level samples.
1645
+ - Pinned by xplus4: voice 1, voice 2's square wave and both hold the
1646
+ level high under bit 7, noise holds it at 0, and the half-wave after
1647
+ the release is 221 samples at `$200`, a whole one.
1648
+ - Spec guard: *the reload bit* in
1649
+ [`chips/ted/sound_spec.rb`](../spec/badline/chips/ted/sound_spec.rb).
1650
+ - The level comes from the volume and how many voices are on and high.
1651
+ One voice measures 586, 1610, 2634, 3658, 4682, 5706, 6730 and 7754 at
1652
+ volumes 1-8, and both 1172, 3284, 5526, 7984, 10658, 13548, 16654 and
1653
+ 19976. Volumes 9-15 are 8, and volume 0 or no voice on is silent.
1654
+ - Pinned by xplus4: those are its sample values, read off recordings
1655
+ that step the volume with one voice and with both held high.
1656
+ - Not pinned: that the hardware's levels are these. Nothing here says
1657
+ why two voices come out above twice one.
1658
+ - Spec guard: *the levels* in
1659
+ [`chips/ted/sound_spec.rb`](../spec/badline/chips/ted/sound_spec.rb).
1660
+ - The output stage is the level averaged over each sample, then a one-pole
1661
+ high-pass at 2.7 Hz. The Plus/4 schematic (310164, sheet 2) couples SND
1662
+ through R10 (1K) and C18 (10 uF) into R11 (12K) and R12 (10K), with C19
1663
+ (2,700 pF) as a low-pass at about 70 kHz, above any audio rate.
1664
+ - Not pinned: xplus4 records no output stage, and there is no hardware
1665
+ recording.
1666
+
1522
1667
  ## 1541 serial port
1523
1668
 
1524
1669
  - The drive sees the C64's side of the serial bus a host cycle late. The