badline 0.8.0 → 0.10.0

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 (134) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +58 -0
  3. data/CLAUDE.md +6 -4
  4. data/README.md +60 -19
  5. data/doc/library.md +10 -3
  6. data/doc/media.md +11 -2
  7. data/doc/pinned-behaviour.md +199 -9
  8. data/doc/sid-player.md +8 -4
  9. data/doc/snapshots.md +79 -33
  10. data/lib/badline/address_bus/pla.rb +130 -0
  11. data/lib/badline/address_bus/roms.rb +32 -0
  12. data/lib/badline/address_bus.rb +13 -92
  13. data/lib/badline/audio/bare_player.rb +24 -0
  14. data/lib/badline/audio/checkpoints.rb +42 -0
  15. data/lib/badline/audio/jukebox.rb +11 -4
  16. data/lib/badline/audio/machine_player.rb +16 -0
  17. data/lib/badline/audio/renderer.rb +80 -9
  18. data/lib/badline/audio/stereo.rb +3 -5
  19. data/lib/badline/audio.rb +1 -0
  20. data/lib/badline/chrout_trap.rb +4 -3
  21. data/lib/badline/computer/attachments.rb +52 -12
  22. data/lib/badline/computer/saved_state.rb +1 -0
  23. data/lib/badline/computer.rb +50 -33
  24. data/lib/badline/control_ports.rb +10 -3
  25. data/lib/badline/core.rb +51 -0
  26. data/lib/badline/data_path.rb +37 -0
  27. data/lib/badline/datasette.rb +63 -10
  28. data/lib/badline/drive1541/disk.rb +3 -3
  29. data/lib/badline/drive1541/disk_state.rb +14 -5
  30. data/lib/badline/drive1541/serial_port.rb +5 -8
  31. data/lib/badline/drive1541/sleep.rb +5 -6
  32. data/lib/badline/drive1541.rb +3 -3
  33. data/lib/badline/frontend/app.rb +63 -64
  34. data/lib/badline/frontend/boot.rb +34 -4
  35. data/lib/badline/frontend/confirmation.rb +17 -11
  36. data/lib/badline/frontend/controls.rb +12 -6
  37. data/lib/badline/frontend/drive_led.rb +9 -10
  38. data/lib/badline/frontend/frame_rate.rb +4 -4
  39. data/lib/badline/frontend/machine_window.rb +87 -0
  40. data/lib/badline/frontend/menu_dialogs.rb +52 -14
  41. data/lib/badline/frontend/menu_media.rb +70 -16
  42. data/lib/badline/frontend/menu_pages.rb +47 -42
  43. data/lib/badline/frontend/menu_ports.rb +69 -0
  44. data/lib/badline/frontend/name_field.rb +88 -0
  45. data/lib/badline/frontend/pacer.rb +6 -5
  46. data/lib/badline/frontend/pause_menu.rb +52 -37
  47. data/lib/badline/frontend/player_screen.rb +1 -1
  48. data/lib/badline/frontend/player_window.rb +4 -4
  49. data/lib/badline/frontend/screen.rb +39 -37
  50. data/lib/badline/frontend/sid_view.rb +1 -1
  51. data/lib/badline/frontend/snapshots.rb +145 -17
  52. data/lib/badline/frontend/sound.rb +17 -9
  53. data/lib/badline/frontend/timeline.rb +36 -5
  54. data/lib/badline/frontend.rb +3 -0
  55. data/lib/badline/iec_bus.rb +16 -28
  56. data/lib/badline/kernal_trap/drive.rb +3 -0
  57. data/lib/badline/kernal_trap/file.rb +1 -1
  58. data/lib/badline/kernal_trap/layout.rb +112 -0
  59. data/lib/badline/kernal_trap/load.rb +24 -25
  60. data/lib/badline/kernal_trap/routine.rb +17 -5
  61. data/lib/badline/kernal_trap/save.rb +13 -23
  62. data/lib/badline/kernal_trap/serial.rb +38 -24
  63. data/lib/badline/kernal_trap.rb +1 -0
  64. data/lib/badline/keyboard.rb +17 -14
  65. data/lib/badline/machine.rb +60 -0
  66. data/lib/badline/media/disk_list.rb +75 -0
  67. data/lib/badline/media/disk_set.rb +13 -3
  68. data/lib/badline/media/vic20_basic.rb +54 -0
  69. data/lib/badline/media/vic20_cartridge.rb +74 -0
  70. data/lib/badline/media/vic20_media.rb +132 -0
  71. data/lib/badline/media.rb +39 -20
  72. data/lib/badline/model.rb +62 -0
  73. data/lib/badline/options/event.rb +10 -6
  74. data/lib/badline/options/help.rb +25 -13
  75. data/lib/badline/options/table.rb +15 -1
  76. data/lib/badline/options/validation.rb +63 -3
  77. data/lib/badline/options.rb +37 -34
  78. data/lib/badline/region.rb +16 -4
  79. data/lib/badline/reu/ram.rb +27 -0
  80. data/lib/badline/reu/saved_state.rb +27 -0
  81. data/lib/badline/roms/README +37 -0
  82. data/lib/badline/roms/kernal-sx64.rom +0 -0
  83. data/lib/badline/roms/vic20/basic.rom +0 -0
  84. data/lib/badline/roms/vic20/character.rom +0 -0
  85. data/lib/badline/roms/vic20/kernal-ntsc.rom +0 -0
  86. data/lib/badline/roms/vic20/kernal-pal.rom +0 -0
  87. data/lib/badline/sid/decimator.rb +13 -0
  88. data/lib/badline/sid/filter.rb +6 -3
  89. data/lib/badline/sid.rb +19 -0
  90. data/lib/badline/snapshot/container.rb +2 -0
  91. data/lib/badline/snapshot/fields.rb +1 -0
  92. data/lib/badline/snapshot/image.rb +15 -0
  93. data/lib/badline/snapshot/setup.rb +20 -8
  94. data/lib/badline/snapshot/state.rb +15 -7
  95. data/lib/badline/snapshot/vice/main_cpu.rb +1 -1
  96. data/lib/badline/snapshot/vice/peripherals.rb +12 -2
  97. data/lib/badline/snapshot/vice/restore.rb +3 -1
  98. data/lib/badline/snapshot/vice/reu1764.rb +55 -0
  99. data/lib/badline/snapshot/vice/vicii.rb +59 -13
  100. data/lib/badline/snapshot/vice/vicii_import.rb +14 -3
  101. data/lib/badline/snapshot/vice.rb +25 -23
  102. data/lib/badline/snapshot.rb +10 -0
  103. data/lib/badline/storage/crt_file.rb +16 -5
  104. data/lib/badline/storage/disk_image.rb +3 -0
  105. data/lib/badline/storage/host_directory.rb +3 -0
  106. data/lib/badline/storage/t64.rb +10 -4
  107. data/lib/badline/storage/tap.rb +44 -8
  108. data/lib/badline/storage/unavailable.rb +3 -1
  109. data/lib/badline/storage.rb +5 -5
  110. data/lib/badline/timing.rb +12 -0
  111. data/lib/badline/version.rb +1 -1
  112. data/lib/badline/via/shift_register.rb +43 -16
  113. data/lib/badline/vic/bank.rb +53 -16
  114. data/lib/badline/vic/registers.rb +20 -4
  115. data/lib/badline/vic/sprite/timing.rb +5 -9
  116. data/lib/badline/vic/sprite.rb +4 -3
  117. data/lib/badline/vic.rb +34 -15
  118. data/lib/badline/vic20/attachments.rb +103 -0
  119. data/lib/badline/vic20/bus.rb +308 -0
  120. data/lib/badline/vic20/cpu.rb +10 -0
  121. data/lib/badline/vic20/keyboard_via_ports.rb +53 -0
  122. data/lib/badline/vic20/port_wiring.rb +50 -0
  123. data/lib/badline/vic20/saved_state.rb +152 -0
  124. data/lib/badline/vic20/sound/output.rb +83 -0
  125. data/lib/badline/vic20/sound.rb +233 -0
  126. data/lib/badline/vic20/user_via_ports.rb +47 -0
  127. data/lib/badline/vic20/vic/painter.rb +239 -0
  128. data/lib/badline/vic20/vic/saved_state.rb +55 -0
  129. data/lib/badline/vic20/vic/text_window.rb +71 -0
  130. data/lib/badline/vic20/vic.rb +267 -0
  131. data/lib/badline/vic20.rb +220 -0
  132. data/lib/badline.rb +2 -38
  133. metadata +37 -2
  134. data/lib/badline/address_bus/ultimax_pages.rb +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: feaedb95b99aa7efed205645c112426a2649ad7a08c975708d085bf69a7e9555
4
- data.tar.gz: b284281a2e1256f0fe94abf5174990ac8dc8a98cd7035f1cd53aebd3ccbefbd6
3
+ metadata.gz: bd764dccd3b8af3f8e0dcbb7d17debc3fceb24a9899f80871ebbf184ffefd65b
4
+ data.tar.gz: 46a62d801813476242a407c09ab3ff4fec1126d10bfee134047f18e90fd86955
5
5
  SHA512:
6
- metadata.gz: 870ff9cb5c9a9d65c8e9dd8dee6cc87a45871c1a07c79c4b9dc69a692600c3167f92b1debca0f860ab96b783a81bb608276542322b17e305acb82e95c9fc560b
7
- data.tar.gz: 7c12bf1fd073b2b0e58e41195d67316f0c518a0f5b8c013ded19f025b48456fea738e5ad3df26a796c84151638e8c0449b5bf14b7d013fcb876c61db5d2d9469
6
+ metadata.gz: 82a62fb4a3de3ef65e123bacf22ba300efe628f1bde38815dc950a39034d8c2b9423de79b3805fce84e19bcbaa8100a3e67488d5ef0a3ecb2de6434689886883
7
+ data.tar.gz: 595b19f034d708db60089e707507e74281059d271527fe61e0a205d9e8e0853a4f6b4d077aeed648f59a86d06bf31d3ee6e5902345fdb52d5fb36ded8de94da3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,63 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.10.0](https://github.com/elektronaut/badline/compare/v0.9.0...v0.10.0) (2026-10-08)
4
+
5
+
6
+ ### Features
7
+
8
+ * add the VIC-20's bus and CPU ([184f4c2](https://github.com/elektronaut/badline/commit/184f4c28c609fe0d46358c0143fabe2beba2fa70))
9
+ * name the machine family with a c64 or vic20 subcommand ([586a02f](https://github.com/elektronaut/badline/commit/586a02fbd80c6e6351d85c91263b5a39438ba13e))
10
+ * open the pause menu from the timeline and screenshot it ([63dc744](https://github.com/elektronaut/badline/commit/63dc74468432397c1ec0273a64fcd28ff46008d2))
11
+ * paint the VIC-20's display from the VIC-I's fetches ([76f67c3](https://github.com/elektronaut/badline/commit/76f67c3709363f682715681d17ea799441412f12))
12
+ * play the VIC-20's sound from the VIC-I's voices ([c490a86](https://github.com/elektronaut/badline/commit/c490a86959e18e0fecdcf21bf0139b63be25d9a9))
13
+ * read the VIC-20 .crt signature and the .tap platform byte ([fc0b130](https://github.com/elektronaut/badline/commit/fc0b130ad3a9481e7a9e61d909286281026797b1))
14
+ * run the VIC-20 in the window, in both builds ([24c056c](https://github.com/elektronaut/badline/commit/24c056c531fb356d3d47a9aad94c50ba0a0b0031))
15
+ * run the VIC-20 with its VIC-I registers and VIAs ([6089cee](https://github.com/elektronaut/badline/commit/6089ceee361e65d59c33a1eaeb3395f315eeed2d))
16
+ * save and restore the VIC-20 in badline's own snapshots ([8620849](https://github.com/elektronaut/badline/commit/8620849be5177069e16a559a35b239d75d7cc82a))
17
+ * serve the VIC-20's device 8 through the KERNAL traps and autostart its media ([356695e](https://github.com/elektronaut/badline/commit/356695e7529f999acf4bdc82951b107460ecdf39))
18
+ * wire the VIC-20's datasette and serial bus to its VIAs, with a true 1541 ([2f06e88](https://github.com/elektronaut/badline/commit/2f06e88cf5276780cc03f7d8121480e95b05480f))
19
+ * wire the VIC-20's keyboard, joystick and RESTORE to its VIAs ([32139f6](https://github.com/elektronaut/badline/commit/32139f647aeb3f5e7601928150b85973db6b9b5e))
20
+
21
+
22
+ ### Bug Fixes
23
+
24
+ * show the disk device 8 holds on the menu's Drive page ([c8b0eaf](https://github.com/elektronaut/badline/commit/c8b0eaf05573246114af6b6f8404095424a1981c))
25
+ * start the VIA shift register only when idle, on the 6522's clock ([bdcb1c8](https://github.com/elektronaut/badline/commit/bdcb1c88bb729e48ffdaaffd91e1274778c4ee29))
26
+
27
+
28
+ ### Performance Improvements
29
+
30
+ * type Memory's storage as Array[Integer] for Spinel ([797c9b1](https://github.com/elektronaut/badline/commit/797c9b1cab26e6ace4f0d0a20011a3a084e73bc9))
31
+
32
+ ## [0.9.0](https://github.com/elektronaut/badline/compare/v0.8.0...v0.9.0) (2026-10-05)
33
+
34
+
35
+ ### Features
36
+
37
+ * add a per-user data folder for badline's own files ([27bdf0e](https://github.com/elektronaut/badline/commit/27bdf0edc16d95fc57dea940741cc0b7de74bbb1))
38
+ * add the Drean C64, PAL-N with the 6572, as --model drean ([0562d8e](https://github.com/elektronaut/badline/commit/0562d8eb5b11239039eac934fd21eb7824868f98))
39
+ * add the SX-64 as --model sx64 ([e947cba](https://github.com/elektronaut/badline/commit/e947cba8ff46f0f01eeb6e1a49c0bd4bf91324ea))
40
+ * autosave, and a Snapshots page in the pause menu ([78aede9](https://github.com/elektronaut/badline/commit/78aede9a6052ce6c32184952a7b1d380e7c129e2))
41
+ * keep five quicksave slots in the data folder ([6043543](https://github.com/elektronaut/badline/commit/6043543632aa61a42ff69bdff8ea15ae354ce810))
42
+ * pick the C64 to run with --model ([d5539c8](https://github.com/elektronaut/badline/commit/d5539c8ade245b1e96e78765f15906ce4a80da5b))
43
+ * restore snapshots without their tape, .t64 or true drive disk files ([0c0733a](https://github.com/elektronaut/badline/commit/0c0733a5c7eaf9c217466f7569769eb005c5248f))
44
+ * run the testlist's Drean rows as testbench-drean ([dc8a075](https://github.com/elektronaut/badline/commit/dc8a07524168d399fb7c0305c661ab694c53bc2c))
45
+ * save NTSC, Drean and REU machines as .vsf snapshots ([c4126cf](https://github.com/elektronaut/badline/commit/c4126cfa878d8efe7aaaa9e5113c4ee2a4886e6b))
46
+ * seek within a subtune from checkpoints kept as it plays ([3ac57be](https://github.com/elektronaut/badline/commit/3ac57beac448a43a76387a0ff1f370cd07d06d81))
47
+ * take disk sets from .m3u and .vfl lists ([b4e6845](https://github.com/elektronaut/badline/commit/b4e6845eb04cde80f87c1fcb372987311bf1dd97))
48
+
49
+
50
+ ### Bug Fixes
51
+
52
+ * describe F11's quicksave slots, F12 and the autosave in --help ([6cbf148](https://github.com/elektronaut/badline/commit/6cbf148d327699070ef4fba4f2b3e3dd39d41348))
53
+ * keep the board's low-pass stable for long filter steps ([c5af022](https://github.com/elektronaut/badline/commit/c5af0224aad60dbb665e6804bb536746e354da96))
54
+ * leave CIA 1's timer B and the serial lines as the KERNAL's LOAD does ([b4f1a41](https://github.com/elektronaut/badline/commit/b4f1a4173b9413fd59b05bab12d173e0679c4c17))
55
+ * play an NTSC machine's sound at its own clock ([510aab1](https://github.com/elektronaut/badline/commit/510aab1052a58a54b1790802e2a5705fcb208c5c))
56
+ * put CIA 2's port A on the serial bus without a drive ([31f8a4f](https://github.com/elektronaut/badline/commit/31f8a4fad0ea210d4272b4672a84414527b68e31))
57
+ * run the 6567R8 and 6572 X counter over $180-$187 twice ([08a4da3](https://github.com/elektronaut/badline/commit/08a4da33d4bd68a85d61895dcf8c1ea5fa5b539c))
58
+ * set CIA 1's timer B for each byte the serial traps stand in for ([f98e6d7](https://github.com/elektronaut/badline/commit/f98e6d7666d2326ce4d8d3ab7f938dc4fd60cbd1))
59
+ * take .m3u and .vfl lists of disks in --at's insert ([d1e771e](https://github.com/elektronaut/badline/commit/d1e771e6781fc5560dda2e10e6d76abb53be0807))
60
+
3
61
  ## [0.8.0](https://github.com/elektronaut/badline/compare/v0.7.0...v0.8.0) (2026-10-03)
4
62
 
5
63
 
data/CLAUDE.md CHANGED
@@ -50,7 +50,7 @@ requires only the namespace file.
50
50
  | rspec (`spec/`) | `bundle exec rspec` | Unit behaviour, all of `lib/` |
51
51
  | SingleStepTests 65x02 | `rake test` (100 sampled cases per opcode) | CPU, per-cycle bus traces |
52
52
  | Wolfgang Lorenz suite | `bin/lorenz` | CPU, CIA, interrupts |
53
- | VICE testbench | `bin/testbench <subtree>` | `VICII/`, `CIA/`, `interrupts/`, `CPU/`, cartridges with `--carts`, and the true 1541 drive with `--drive` |
53
+ | VICE testbench | `bin/testbench <subtree>` | `VICII/`, `CIA/`, `interrupts/`, `CPU/`, cartridges with `--carts`, the true 1541 drive with `--drive`, and the VIC-20 with `--vic20` |
54
54
  | VICE SID testprogs | `bin/sidtests` | SID |
55
55
  | Drive scenarios | `bin/drive_scenarios` | The true 1541 running the DOS ROM: save, format, the error channel, idle, write protect and autostart |
56
56
  | CIA offline grids | `bundle exec rspec --tag slow spec/badline/cia` | CIA timers and shift register, against a bare CIA in about 2 min |
@@ -144,7 +144,7 @@ overrides that, capped by the core count, but keep the default, because
144
144
  other worktrees share the machine. Whole runs at 4 shards on an M-series
145
145
  laptop take 15 min for `testbench` (`VICII/`), 11 for `testbench-cia`, 1 for
146
146
  `testbench-interrupts`, 37 for `testbench-irqdma`, 11 for
147
- `testbench-cpu`, 2 for `testbench-carts` and about 25 for `testbench-expansions`. `sid` takes about 12 min. `lorenz` chains itself and takes
147
+ `testbench-cpu`, 2 for `testbench-carts`, about 25 for `testbench-expansions` and under 1 for `testbench-vic20`. `sid` takes about 12 min. `lorenz` chains itself and takes
148
148
  about 2.5 h on CI whole. `rake regression:lorenz-1` to `lorenz-4` run it as
149
149
  four stretches of about 40 min each, and they can run side by side.
150
150
  `test/baselines/README.md` has the full table. A killed `bin/testbench` run
@@ -187,14 +187,16 @@ the rows your change can't reach tell you nothing about it.
187
187
  Pick the filters from the suites your change can move: VIC → `testbench`,
188
188
  plus `testbench-vicii-new` (`bin/testbench --vicii-new`, the 8565) for
189
189
  anything the VIC model reaches, and `testbench-ntsc` (`bin/testbench --ntsc`,
190
- the 6567R8 and 6567R56A) for anything a region's timing reaches;
190
+ the 6567R8 and 6567R56A) and `testbench-drean` (`bin/testbench --drean`,
191
+ the 6572) for anything a region's timing reaches;
191
192
  CPU, interrupts or timing → the matching `testbench-*` suite, plus
192
193
  `rake test` for CPU; CIA → the slow CIA specs first, then the matching
193
194
  `testbench-cia` rows, plus `testbench-cia-new` (`bin/testbench --cia-new`,
194
195
  the 6526A) for anything the interrupt register or the CIA model reaches; cartridge mappers, banking or power-on state →
195
196
  `testbench-carts`, plus `testbench-expansions` for banking; GEO-RAM, +60K,
196
197
  +256K, the REU or the VIC's BA line the REU follows → `testbench-expansions`; the 1541 drive, VIA or IEC bus →
197
- `testbench-drive` (`bin/testbench --drive`) and `drive-scenarios` (`bin/drive_scenarios <filter>`); SID → `sid`, plus `sid-8580` for anything the 8580
198
+ `testbench-drive` (`bin/testbench --drive`) and `drive-scenarios` (`bin/drive_scenarios <filter>`), plus `testbench-vic20` for the VIA; the VIC-20 (`vic20/`) →
199
+ `testbench-vic20` (`bin/testbench --vic20`); SID → `sid`, plus `sid-8580` for anything the 8580
198
200
  model reaches (`bin/sidtests --sid 8580`). Leave the Lorenz chain to CI,
199
201
  unless your code has a rule in `doc/pinned-behaviour.md` that names Lorenz
200
202
  tests: the interrupt polling, CPU port and CIA timer rules. Run just the
data/README.md CHANGED
@@ -3,6 +3,8 @@
3
3
 
4
4
  # Badline
5
5
 
6
+ ![A C64 booted to BASIC in badline, its cursor blinking](doc/images/boot.gif)
7
+
6
8
  Badline is a Commodore 64 emulator written in Ruby. It emulates a PAL
7
9
  or NTSC machine one clock cycle at a time, stepping the 6510, the VIC-II, both
8
10
  CIAs and the SID together, so raster timing, bad lines and sprite DMA
@@ -10,8 +12,8 @@ are modelled at the cycle level.
10
12
 
11
13
  It runs programs, disk and tape images, cartridges and SID tunes, and
12
14
  the SDL2 front end supports the keyboard, joysticks, game controllers,
13
- paddles and a 1351 mouse. See [What's emulated](#whats-emulated) for the
14
- details.
15
+ paddles and a 1351 mouse. It also runs a PAL VIC-20, as
16
+ `badline vic20`. See [What's emulated](#whats-emulated) for the details.
15
17
 
16
18
  It comes in two builds of the same emulator:
17
19
 
@@ -65,6 +67,10 @@ Programs, disk and tape images and SID tunes start automatically, and
65
67
  a cartridge starts itself. A mounted directory waits for you to `LOAD`
66
68
  from it.
67
69
 
70
+ The first argument can name the machine, as in `badline c64 game.prg`.
71
+ The C64 is the default, and `--model` picks which C64. See
72
+ [The VIC-20](#the-vic-20) for `badline vic20`.
73
+
68
74
  `badline-ruby` takes the same media and the same options, with the
69
75
  differences noted in the table. `--help` lists the options for either.
70
76
 
@@ -77,8 +83,10 @@ differences noted in the table. `--help` lists the options for either.
77
83
  | `--true-drive` | Put an emulated 1541 on device 8 instead of the KERNAL traps. See [Media](#media) |
78
84
  | `-s`, `--subtune N` | Pick a subtune of a `.sid` file, counting from 1 |
79
85
  | `--sid 6581`, `--sid 8580` | Fit the older or newer SID. `--sid auto`, the default, takes a `.sid` tune's own |
86
+ | `--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) |
80
87
  | `--reu SIZE` | Plug in a RAM Expansion Unit of `SIZE` K: 128, 256, 512 (a 1750) or up to 16384 |
81
- | `--ntsc` | Run an NTSC C64, with the 6567R8 VIC-II, instead of a PAL one |
88
+ | `--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) or `sx64` (the portable SX-64, with its own KERNAL and no datasette). `--sid` or a `.sid` tune's own SID takes the model's place |
89
+ | `--ntsc` | Run an NTSC C64, as `--model ntsc` does |
82
90
  | `--no-sound` | Don't play the SID (`badline` only, where sound is on by default) |
83
91
  | `--sound` | Play the SID (`badline-ruby`, where sound is off by default) |
84
92
  | `--no-vsync` | Pace the window by a timer, or by the sound while it plays, instead of the display's vsync |
@@ -93,7 +101,7 @@ differences noted in the table. `--help` lists the options for either.
93
101
  | --- | --- |
94
102
  | `--frames N` | Quit after N frames |
95
103
  | `--unpaced` | Run as fast as it can, without vsync or pacing |
96
- | `--at FRAME:EVENT` | Press keys, type, swap media or take a screenshot once `FRAME` frames have run |
104
+ | `--at FRAME:EVENT` | Press keys, type, swap media, open the pause menu or take a screenshot once `FRAME` frames have run |
97
105
  | `--script FILE` | Run the events in `FILE`, one `FRAME:EVENT` a line |
98
106
  | `--screenshot FILE` | Save the last frame as a `.bmp` |
99
107
  | `--save-snapshot FILE` | Save the machine as a `.vsf` snapshot after the last frame |
@@ -117,6 +125,7 @@ library, are covered in [doc/library.md](doc/library.md).
117
125
  | `.prg`, `.p00` | Loaded into memory after boot. A program at the BASIC start (`$0801`) is `RUN`, anything else is left for you to `SYS` |
118
126
  | `.d64`, `.d71`, `.d81` | Mounted as device 8, then `LOAD"*",8,1` and `RUN`. Write-protected unless `--writable` |
119
127
  | `.g64` | Put in a true 1541, then `LOAD"*",8,1` and `RUN`. It holds the disk's raw GCR, so copy protection that reads it works. Write-protected unless `--writable` |
128
+ | `.m3u`, `.vfl` | A list of disk images, one path a line, relative to the list: an `.m3u` playlist, or a VICE flip list, which only unit 8's entries are taken from. Its first disk goes in as above, and the list is its set for the pause menu |
120
129
  | `.t64` | Mounted read-only as device 8 and loaded like a disk image. The files load by name, and no tape is involved |
121
130
  | `.tap` | Inserted in the datasette with PLAY pressed, then `LOAD` and `RUN`. It loads at the speed of a real tape |
122
131
  | `.crt` | The hardware types listed under [Cartridges](#whats-emulated). Other types are rejected |
@@ -132,14 +141,38 @@ red LED lights in the bottom right corner of the border.
132
141
  [doc/media.md](doc/media.md) has the details, and how to attach media
133
142
  from Ruby.
134
143
 
144
+ ## The VIC-20
145
+
146
+ `badline vic20` runs a PAL VIC-20, and takes the same media as the C64
147
+ apart from SID tunes:
148
+
149
+ ```sh
150
+ badline vic20 # READY.
151
+ badline vic20 game.prg # Load and run a program
152
+ badline vic20 game.d64 # Mount a disk image as device 8 and load it
153
+ badline vic20 game.tap # Insert a tape and load it
154
+ badline vic20 game.crt # Attach a cartridge
155
+ ```
156
+
157
+ Without `--ram`, it picks the RAM expansion from where the program, or
158
+ the first program on a disk, loads: a BASIC program gets the expansion
159
+ its start of BASIC comes with, and more of BLK1 to BLK3 when it runs
160
+ past `$3FFF`. A program that loads at `$A000` is a cartridge's ROM, and
161
+ goes in as a `.crt` does. Disks go through the KERNAL traps or, with
162
+ `--true-drive`, a 1541, as on the C64. `F11`, `F12` and the pause menu
163
+ save and load the VIC-20 too, in badline's own snapshots: xvic's `.vsf`
164
+ files don't load.
165
+
135
166
  ## Snapshots
136
167
 
137
- `F11` saves the whole machine to a new `badline-<date>-<time>.vsf` in
138
- the working directory, and `F12` goes back to the snapshot last saved
139
- or opened. Snapshots use VICE's `.vsf` format: badline opens those
140
- x64sc saves, and x64sc opens badline's. See
141
- [doc/snapshots.md](doc/snapshots.md) for what they hold and how far the
142
- two agree.
168
+ `F11` quicksaves the whole machine to the next of five slots in
169
+ badline's data folder, replacing the oldest, and `F12` restores the
170
+ newest, even after badline has quit and started again. badline also
171
+ autosaves every two minutes of play, and the pause menu's Snapshots page
172
+ saves under a name and loads any of them. Snapshots use
173
+ VICE's `.vsf` format: badline opens those x64sc saves, and x64sc opens
174
+ badline's. See [doc/snapshots.md](doc/snapshots.md) for where they're
175
+ kept, what they hold and how far the two agree.
143
176
 
144
177
  ## Playing and rendering SID tunes
145
178
 
@@ -215,8 +248,11 @@ through the rows, Right goes into a page and Left back out, and Return or
215
248
  Space presses a row. A row with choices steps to the next. The mouse works
216
249
  too.
217
250
 
251
+ ![The pause menu's Drive 8 page, with a disk in](doc/images/pause-menu.png)
252
+
218
253
  | Page | What it holds |
219
254
  |------|---------------|
255
+ | Snapshots | Quicksave, save under a name, load a named save, and the latest quicksaves and autosaves |
220
256
  | Drive 8 | The disk: insert, eject, the previous or next disk of its set, and whether it's writable |
221
257
  | Datasette | The tape: insert, eject, PLAY and REWIND |
222
258
  | Expansion port | The cartridge: insert, remove, and its freeze button if it has one |
@@ -224,15 +260,17 @@ too.
224
260
  | Sound | Mute, and the SID's model |
225
261
  | Power | Reset, power cycle and quit |
226
262
 
227
- INSERT opens a file browser. A disk's set comes from the names in its
228
- folder: `Disk 1`, `Side B`, `d2`, TOSEC's `(Disk 1 of 2)`, or a trailing
229
- `_1`, `_2` when the first of the set is there. WRITABLE starts as
263
+ INSERT opens a file browser. A disk's set is the `.m3u` or `.vfl` list it
264
+ was opened from, or one in its folder that lists it. Without one, it comes
265
+ from the names in its folder: `Disk 1`, `Side B`, `d2`, TOSEC's
266
+ `(Disk 1 of 2)`, or a trailing `_1`, `_2` when the first of the set is
267
+ there. WRITABLE starts as
230
268
  `--writable` sets it and stays as set for the next disk. Quick open starts
231
269
  a file in a new machine, as the command line does. It asks first, as
232
270
  inserting or removing a cartridge does, since each power cycles the
233
271
  machine.
234
272
 
235
- A disk or tape dropped on the window goes into its drive. A cartridge,
273
+ A disk, list of disks or tape dropped on the window goes into its drive. A cartridge,
236
274
  program or `.sid` dropped on it opens the menu to ask first.
237
275
 
238
276
  ## What's emulated
@@ -242,8 +280,8 @@ program or `.sid` dropped on it opens the menu to ask first.
242
280
  [65x02 single step tests](https://github.com/SingleStepTests/65x02).
243
281
  - **Memory**: banking through the 6510 port, the cartridge lines and
244
282
  Ultimax mode, and the +60K and +256K RAM expansions.
245
- - **VIC-II**: the PAL 6569, the C64C's 8565, and NTSC's 6567R8 (`--ntsc`)
246
- and 6567R56A: every graphics mode, sprites, collisions, bad lines,
283
+ - **VIC-II**: the PAL 6569, the C64C's 8565, NTSC's 6567R8, 8562 and
284
+ 6567R56A, and the Drean's PAL-N 6572 (`--model`): every graphics mode, sprites, collisions, bad lines,
247
285
  sprite DMA, the border and the light pen.
248
286
  - **CIA 1 and 2**: the 6526 and the C64C's 6526A, with timers,
249
287
  time-of-day clocks, the serial shift register, the keyboard matrix
@@ -252,6 +290,10 @@ program or `.sid` dropped on it opens the menu to ask first.
252
290
  - **REU**: the 1700, 1764 and 1750 and bigger units up to 16M
253
291
  (`--reu`), with DMA timed against the VIC's bad lines and sprites.
254
292
  - **Datasette**: `.tap` playback.
293
+ - **VIC-20**: the 6502, the PAL 6561 VIC-I with its picture and sound,
294
+ both 6522 VIAs, the keyboard, the joystick and RESTORE, RAM
295
+ expansions up to 35K (`--ram`), cartridges, the datasette and the
296
+ serial bus to device 8 (`badline vic20`).
255
297
  - **1541**: an emulated drive running its own DOS (`--true-drive`).
256
298
  - **Cartridges**: standard 8K, 16K and Ultimax, Simons' BASIC, Ocean,
257
299
  Fun Play / Power Play, Super Games, Epyx FastLoad, Westermann
@@ -261,8 +303,8 @@ program or `.sid` dropped on it opens the menu to ask first.
261
303
  Power / Nordic Power, Retro Replay / Nordic Replay, Final Cartridge III
262
304
  / III+ and the KCS Power Cartridge. Flash writes stay in memory.
263
305
 
264
- Machines other than the default, and the cartridges' jumpers, are
265
- built from Ruby: see [doc/library.md](doc/library.md).
306
+ Chip combinations `--model` doesn't name, and the cartridges' jumpers,
307
+ are built from Ruby: see [doc/library.md](doc/library.md).
266
308
 
267
309
  Known gaps:
268
310
 
@@ -270,7 +312,6 @@ Known gaps:
270
312
  turns on, stutters: it plays in bursts with silent gaps between them.
271
313
  - Without `--true-drive`, fast loaders and anything else that runs code
272
314
  on the drive won't work.
273
- - No PAL-N (Drean) machine.
274
315
 
275
316
  ## Contributing
276
317
 
data/doc/library.md CHANGED
@@ -19,7 +19,9 @@ computer.address_bus.peek(0x0400) # screen RAM starts at $0400
19
19
  ## Building a machine
20
20
 
21
21
  `Badline::Computer.new` builds the default machine: a PAL C64 with the
22
- 6569 VIC-II, 6526 CIAs and a 6581 SID. Its keywords build others:
22
+ 6569 VIC-II, 6526 CIAs and a 6581 SID. Its keywords build others, and
23
+ `Badline::Model.named("c64c")` gives the ones `--model` names for each
24
+ model (`Badline::Model::ALL`):
23
25
 
24
26
  - `vic_model: :mos8565` fits the C64C's 8565, with its grey dots on
25
27
  colour register writes and its own timing for mode splits, sprite
@@ -28,7 +30,8 @@ computer.address_bus.peek(0x0400) # screen RAM starts at $0400
28
30
  65 cycles by 263 lines at 1,022,727 Hz, with its later sprite fetches
29
31
  and its X counter, and TOD clocks on 60 Hz mains.
30
32
  `Badline::Region::NTSC_OLD` is the first NTSC C64s' 6567R56A, 64 cycles
31
- by 262 lines. The stock KERNAL tells them from PAL by the raster, so
33
+ by 262 lines, and `Badline::Region::DREAN` the Drean C64's PAL-N
34
+ 6572, 65 cycles by 312 lines at 1,023,440 Hz. The stock KERNAL tells them from PAL by the raster, so
32
35
  every region boots the same ROMs.
33
36
  - `cia_model: :mos6526a` fits the C64C's 6526As, whose interrupt
34
37
  register timing differs.
@@ -36,6 +39,9 @@ computer.address_bus.peek(0x0400) # screen RAM starts at $0400
36
39
  - `ram_expansion: :plus60k` or `:plus256k` fits the +60K or +256K RAM
37
40
  expansion, banked through its register at `$D100`.
38
41
  - `reu: 512` plugs in a RAM Expansion Unit of that many K.
42
+ - `kernal: :sx64` fits the SX-64's KERNAL, and `datasette: false`
43
+ leaves the cassette port empty, so inserting a tape raises
44
+ `Badline::Datasette::Missing`. The SX-64 has both.
39
45
 
40
46
  ## Cartridges
41
47
 
@@ -57,6 +63,7 @@ Its contents are lost when the emulator quits.
57
63
  The KERNAL, BASIC and character ROMs come with the gem. To run other
58
64
  images, such as a patched KERNAL, point `BADLINE_ROM_PATH` at a
59
65
  directory that holds `kernal.rom`, `basic.rom` and `character.rom`, plus
60
- `eapi/eapi-am29f040-14` if you attach EasyFlash cartridges.
66
+ `kernal-sx64.rom` for the SX-64 and `eapi/eapi-am29f040-14` if you
67
+ attach EasyFlash cartridges.
61
68
  `Badline.rom_path = dir` does the same before a `Badline::Computer` is
62
69
  built, and `nil` restores the bundled set.
data/doc/media.md CHANGED
@@ -59,8 +59,17 @@ traps, so `LOAD` and `SAVE` reach the 1541 too. With the 1541 in device
59
59
  8, a `.d64` goes in its drive as well.
60
60
 
61
61
  `Badline::Media::DiskSet.around(path)` lists the disks of the set a disk
62
- image belongs to, found by name in its folder, which the pause menu's
63
- PREVIOUS DISK and NEXT DISK step through.
62
+ image belongs to, which the pause menu's PREVIOUS DISK and NEXT DISK step
63
+ through. An `.m3u` or `.vfl` list in the disk's folder that names it
64
+ gives the set. Without one, the set is found by name in the folder.
65
+ Given a list, it returns the disks the list names.
66
+
67
+ A list names one disk image a line, as a path relative to the list or an
68
+ absolute one. Blank lines and lines starting with `#` are skipped, and
69
+ entries that aren't there are left out. In a VICE `.vfl` flip list, only
70
+ the entries after a `UNIT 8` line, or before any `UNIT` line, count.
71
+ `Media.attach` and the command line take a list as media and attach its
72
+ first disk.
64
73
 
65
74
  ## The light pen
66
75
 
@@ -26,11 +26,16 @@ only catches the rows that happen to move.
26
26
  - [VIC light pen](#vic-light-pen)
27
27
  - [VIC-II 8565](#vic-ii-8565)
28
28
  - [VIC-II NTSC](#vic-ii-ntsc)
29
+ - [VIC-II 6572 (Drean)](#vic-ii-6572-drean)
29
30
  - [CIA 6526 timer pipeline](#cia-6526-timer-pipeline)
30
31
  - [CIA 6526A interrupt register](#cia-6526a-interrupt-register)
31
32
  - [CIA serial shift register](#cia-serial-shift-register)
33
+ - [VIA shift register](#via-shift-register)
32
34
  - [6510 I/O port](#6510-io-port)
33
35
  - [RAM power-on pattern](#ram-power-on-pattern)
36
+ - [VIC-20 RAM power-on pattern](#vic-20-ram-power-on-pattern)
37
+ - [VIC-I fetches and the V-bus](#vic-i-fetches-and-the-v-bus)
38
+ - [VIC-I sound](#vic-i-sound)
34
39
  - [1541 serial port](#1541-serial-port)
35
40
  - [1541 disk mechanism](#1541-disk-mechanism)
36
41
  - [REU DMA](#reu-dma)
@@ -293,7 +298,9 @@ only catches the rows that happen to move.
293
298
  early in the next one for 3–7.
294
299
  - A sprite still shifting at K loses the rest of its row. Its output
295
300
  holds its last pixel from K through **K+6**, then goes dark.
296
- - A comparator hit in K..K+11 shows nothing.
301
+ - A comparator hit in K..K+11 shows nothing. Where K falls in the
302
+ last 11 pixels of the line, as sprite 3's does on a 65-cycle line,
303
+ the twelve run on into the next line's first pixels.
297
304
  - A hit from K+12 on shows the row the reload brought. For sprites 0–2
298
305
  that is the *next* line's row, a line early. For sprites 3–7 it is the
299
306
  current row, and a hit ahead of their K shows the previous line's row.
@@ -307,6 +314,11 @@ only catches the rows that happen to move.
307
314
  `spritex/demusinterruptus` and `spritegap2` pass on it too.
308
315
  - Spec guard: *the reload* in
309
316
  [`vic/sprite_spec.rb`](../spec/badline/vic/sprite_spec.rb).
317
+ - The run into the next line is pinned by `spritescan_drean`'s 6572
318
+ dump, where sprite 3 shows nothing for X = $193 to $19e, the twelve
319
+ pixels from K = 515 on a 520-pixel line. Without it a hit at $198 to
320
+ $19e collides. Spec guard: *the reload near the end of a 65-cycle
321
+ line*. The `testbench-ntsc` sprite rows pass either way.
310
322
  - The hold's length is pinned by `spritefetchbug/test-136-2a`, whose
311
323
  X-expanded sprite 0 sits at X = $136 and is still shifting at 459. Its
312
324
  reference holds the last pixel through 465. Holding it for one pixel
@@ -941,14 +953,22 @@ region moves the sprites. The positions live in `Region::Profile` and
941
953
  - Spec guard: *sprite DMA cycle stealing on NTSC* and *#phi1_data on
942
954
  NTSC* in [`vic_spec.rb`](../spec/badline/vic_spec.rb), and
943
955
  [`timing_spec.rb`](../spec/badline/vic/sprite/timing_spec.rb).
944
- - **Display compare and X counter.** The 6567R8 turns a sprite's display
945
- on and off in cycle 59 (`sprite_display_cycle`), where the 6567R56A
946
- keeps the 6569's cycle 58. Its X counter holds for 8 pixels
947
- (`x_hold`), reading $184-$187 three times, so it reaches $1ff on a
948
- 520-pixel line. The 6567R56A's runs straight through 512 pixels.
949
- Neither is pinned yet: moving the 6567R8's display compare to 58, the
950
- 6567R56A's to 59, or running the 6567R8's counter straight through and
951
- wrapping it at 512 fails no row of those subsets.
956
+ - **Display compare.** The 6567R8 turns a sprite's display on and off in
957
+ cycle 59 (`sprite_display_cycle`), where the 6567R56A keeps the 6569's
958
+ cycle 58. This isn't pinned yet: moving the 6567R8's to 58 or the
959
+ 6567R56A's to 59 fails no row of those subsets.
960
+ - **X counter.** The 6567R8's X counter spends 8 pixels more on a line
961
+ (`x_hold`): after $187 it runs over $180-$187 a second time, then on
962
+ from $188, so it reaches $1ff on a 520-pixel line. The 6567R56A's runs
963
+ straight through 512 pixels.
964
+ - Pinned for the 6572, which shares the line, by `spritescan_drean`'s
965
+ dump (see [VIC-II 6572 (Drean)](#vic-ii-6572-drean)).
966
+ - The 6567R8's own lightpen dump (`split-tests/lightpen`'s
967
+ `dump6567.prg`, run by hand on `--model ntsc`) agrees: the sample the
968
+ test takes 8 pixels into the hold reads $c2 ($180-$181). Reading
969
+ $184-$187 there instead, as badline did before, gives $c4. The 6572's
970
+ `dump6572.prg` has the same values. The `testbench-ntsc` rows pass
971
+ either way.
952
972
  - **Blanking and crop.** The blanked lines are the ones VICE's NTSC view
953
973
  leaves out, 12-27 on the 6567R8 and 13-27 on the 6567R56A, so the
954
974
  `testbench-ntsc` screenshots, VICE's 247 lines from line 28 running on
@@ -970,6 +990,34 @@ What the NTSC references don't settle, and so what stays as it is:
970
990
  readme says it was matched against screenshots, and the one 6567R8
971
991
  photograph in the testprogs is of revision R01.
972
992
 
993
+ ## VIC-II 6572 (Drean)
994
+
995
+ The 6572 of the Drean C64 (`Region::DREAN`) runs the 6567R8's line, 65
996
+ cycles with its sprite fetches in cycle 59, its display compare in cycle
997
+ 59 and its X counter running over $180-$187 twice, on PAL-N's 312 lines at
998
+ 1,023,440 Hz. The oracle is `split-tests/spritescan/spritescan_drean.prg`,
999
+ which checks itself against its `dump6572.bin`, from a real 6572R1. The
1000
+ testlist comments that row out, and `testbench-drean`
1001
+ (`bin/testbench --drean`) runs it.
1002
+
1003
+ - Pinned by that dump: every byte the test compares matches, and the
1004
+ test passes.
1005
+ - The X counter's second run over $180-$187 is pinned by sprite 1,
1006
+ pattern C (a one-pixel sprite against one shifted a pixel left), which
1007
+ collides for X = $180 to $186 on the 6572. Those are inside sprite 1's
1008
+ twelve dead pixels (K = 483), so the sprite only shows from the second
1009
+ time the counter reads its X. Repeating $184-$187 in the hold instead
1010
+ misses $180-$183 (4 bytes), repeating $180-$183 misses $184-$186 (3),
1011
+ and repeating $17c-$183 or $184-$18b moves 18 bytes. Spec guard: the
1012
+ 6567R8 and 6572 examples in
1013
+ [`timing_spec.rb`](../spec/badline/vic/sprite/timing_spec.rb).
1014
+ - The display compare isn't pinned: the dump matches with it in cycle
1015
+ 58 as well as 59.
1016
+ - Not matched: `spritegap3`'s 6572 dump has sprite 0 at X = 0 miss the
1017
+ sprite at X = 1 for every pair it is in, where badline, like the
1018
+ 6567R8 dump, has them collide. The test still passes, because it
1019
+ accepts the 6567R8's dump too.
1020
+
973
1021
  ## CIA 6526 timer pipeline
974
1022
 
975
1023
  - Start and stop go through two stages. A force load lands one tick after
@@ -1152,6 +1200,43 @@ and each was knocked out: removing it fails the rows named.
1152
1200
  [`cia_spec.rb`](../spec/badline/cia_spec.rb) covers the flag timing, the
1153
1201
  waiting byte, both mode-change reports and the zero-latch stall.
1154
1202
 
1203
+ ## VIA shift register
1204
+
1205
+ - A read or write of SR starts a byte only while the register is idle
1206
+ and enabled. An access in mode 0 starts nothing, even once the mode
1207
+ changes, and an access before the eighth bit is in leaves the count
1208
+ alone. The byte in progress runs on, and the first access after it
1209
+ ends starts the next.
1210
+ - In the φ2 modes (2 and 6) CB1 falls on the second cycle after the
1211
+ access, rises on the third, and so on. Mode 6 puts a bit out on cycles
1212
+ +2, +4 … +16, mode 2 takes one in on cycles +3, +5 … +17, and the flag
1213
+ rises with the eighth rising edge, on cycle +17.
1214
+ - In the timer 2 modes (1, 4 and 5) each clock edge comes two cycles
1215
+ after the timer 2 low byte underflows, on the cycle after the low byte
1216
+ reloads from its latch. The half period stays N + 2 cycles.
1217
+ - Pinned by the `VIC20/via_sr` rows, each checked by breaking the rule and
1218
+ rerunning all 32. The plain and `exp` rows dump SR every 7 cycles, the
1219
+ `ifr` and `iex` rows dump IFR, and the SR write comes before the ACR
1220
+ write that sets the mode:
1221
+ - Mode 0 starts nothing: `viasr08` and `viasr18`, and the `ifr`/`iex`
1222
+ rows of modes 04, 08, 14 and 18, which would see the SR flag.
1223
+ - No restart before the eighth bit: `viasr14` and `viasr18`. Their
1224
+ reads come every 7 cycles, faster than a byte.
1225
+ - The φ2 start a cycle late: `viasr08` and `viasr18`. Ticking from the
1226
+ first cycle, or from the third, fails both.
1227
+ - The timer 2 edge two cycles late: `viasr04`, `viasr10` and `viasr14`.
1228
+ A delay of 0, 1 or 3 cycles fails all three.
1229
+ - Every rule also fails the row's `exp` twin, the same test on an
1230
+ expanded VIC-20.
1231
+ - Nothing pins whether the timer 2 delay keeps running while the register
1232
+ is idle. It does, and freezing it passes every row too. Nothing pins
1233
+ the flag's cycle in the φ2 modes either: no row starts a byte and then
1234
+ reads IFR.
1235
+ - Spec guard: the mode blocks in
1236
+ [`shift_register_spec.rb`](../spec/badline/via/shift_register_spec.rb)
1237
+ and *the shift register* in
1238
+ [`via_spec.rb`](../spec/badline/via_spec.rb).
1239
+
1155
1240
  ## 6510 I/O port
1156
1241
 
1157
1242
  - DDR at `$00`/`$01`: inputs are pulled up, bit 5 reads low, and bits 3, 6
@@ -1195,6 +1280,111 @@ and each was knocked out: removing it fails the rows named.
1195
1280
  [`address_bus_spec.rb`](../spec/badline/address_bus_spec.rb).
1196
1281
  - The RAM expansions' extra banks still power on at `$00`.
1197
1282
 
1283
+ ## VIC-20 RAM power-on pattern
1284
+
1285
+ - The VIC-20's RAM powers on in alternating bytes, `$ff` at the even
1286
+ addresses and `$00` at the odd ones, on every power cycle. The internal
1287
+ RAM and the expansion blocks (RAM1-3, BLK1-3, BLK5) all follow it.
1288
+ Colour RAM powers on at zero. `Vic20::Bus::RAM_POWER_ON` holds it.
1289
+ - Pinned by `VIC20/raminitpattern`: `ae.crt` fails unless `$0288` reads
1290
+ `$ff` and `jellymonsters.crt` unless `$1046` does, read from a
1291
+ cartridge before the KERNAL clears RAM. The readme says AE and Jelly
1292
+ Monsters need `$ff` there. Its dumps of real machines' `$1000-$1fff`
1293
+ show bytes alternating `$00` and `$ff` on most machines, with either
1294
+ phase, and noise or other patterns on the rest. They show nothing
1295
+ for colour RAM or expansion RAM that a pattern could be read from.
1296
+ - Spec guard: *RAM at power-on* in
1297
+ [`vic20/bus_spec.rb`](../spec/badline/vic20/bus_spec.rb).
1298
+
1299
+ ## VIC-I fetches and the V-bus
1300
+
1301
+ - On a line of the text window the 6561 fetches the first character code
1302
+ 4 cycles after the column in `$9000`, 16 cycles after the raster count
1303
+ moves with the KERNAL's origin of 12, then the code's pattern byte in
1304
+ the next cycle, two cycles a character. Outside the window it fetches
1305
+ nothing.
1306
+ - A read where no chip answers in I/O 0 (`$9100`, `$9200`) returns the
1307
+ V-bus's last byte: the VIC's fetch in a cycle it fetches in, and the
1308
+ CPU's own last byte on the V-bus in the other cycles.
1309
+ - Pinned by `VIC20/split-tests/timing`: all 1,024 bytes of its readings
1310
+ of `$9003`, `$9004`, `$9100` and `$9200` over 256 cycles match
1311
+ `dumps/dump6561e.prg`, a real 6561E. The later 6561-101's dump reads
1312
+ `$20` in the idle cycles instead; badline follows the 6561E.
1313
+ - Spec guard:
1314
+ [`vic20/vic_split_tests_timing_spec.rb`](../spec/badline/vic20/vic_split_tests_timing_spec.rb)
1315
+ (`:slow`), and *the fetches* in
1316
+ [`vic20/vic_video_spec.rb`](../spec/badline/vic20/vic_video_spec.rb).
1317
+ - A write to `$900F` or `$900E` takes hold from the second of the four
1318
+ pixels of the cycle it lands in, the reverse bit two pixels later, and
1319
+ a character's pixels come out in the two cycles after its pattern
1320
+ fetch. These match xvic's screenshots of a test of cycle-timed writes
1321
+ pixel for pixel; no testprog or hardware capture checks them.
1322
+ - Spec guard: *a colour write* in
1323
+ [`vic20/vic_video_spec.rb`](../spec/badline/vic20/vic_video_spec.rb).
1324
+
1325
+ ## VIC-I sound
1326
+
1327
+ No testprog checks the VIC-I's sound, so these rules are pinned by xvic
1328
+ (VICE 3.10) recordings, run as a black box: `-sounddev wav` at 44.1 kHz of
1329
+ programs that set the registers, the same programs run on badline, and
1330
+ the two compared by period, harmonics and spectrum. xvic's own source
1331
+ wasn't read.
1332
+
1333
+ - A voice's counter comes round every 128 - ((value + 1) & 127) ticks of
1334
+ 16, 8, 4 and 2 cycles from bass to noise, and a tone voice's shift
1335
+ register plays 16 shifts a period, as Marko Mäkelä's `VIC-I.txt`
1336
+ (revision 1.2, Levente Hársfalvi's measurements) gives the frequencies.
1337
+ - Pinned by xvic: `$900A` = `$FE`, `$80` and `$FF` measure 4329.70,
1338
+ 34.0922 and 33.8256 Hz, `$900B` = `$F0` 577.29 Hz, and `$900C` = `$F0`
1339
+ and `$A0` 1154.59 and 182.30 Hz, each within 0.001 Hz of the formula
1340
+ on the PAL clock.
1341
+ - Spec guard: *a tone voice's counter* in
1342
+ [`vic20/sound_spec.rb`](../spec/badline/vic20/sound_spec.rb).
1343
+ - A tone voice's shift register takes bit 7 back into bit 0 inverted while
1344
+ the voice is on and a zero while it's off, and keeps shifting either way.
1345
+ Bit 0 is the output, not gated by the enable bit. This is the die-shot
1346
+ reading of the 6561 on the Denial forum (Lance Ewing: the feedback is a
1347
+ NOR of bit 7 and the inverted enable bit, and the counter keeps shifting
1348
+ a voice that's off).
1349
+ - Pinned by xvic: a bass voice loaded with 10101010, 11000000, 10000000
1350
+ and 11101000 by turning it on and off a shift at a time, then left
1351
+ on, has the same harmonics in xvic's recording and badline's to
1352
+ 0.1 dB through the 12th. 10101010 puts the 7th and 9th harmonics
1353
+ above the fundamental, which a register cleared while off couldn't.
1354
+ - Spec guard: *a tone voice* in
1355
+ [`vic20/sound_spec.rb`](../spec/badline/vic20/sound_spec.rb).
1356
+ - The noise voice's counter steps a 16-bit LFSR: bit 0 takes the XOR of
1357
+ bits 3, 12, 14 and 15 while the voice is on and a one while it's off.
1358
+ Each rise of the LFSR's bit 0 shifts the noise voice's own shift
1359
+ register, bit 7 back into bit 0, inverted while the voice is on, and
1360
+ its bit 0 is the output while the voice is on. These are the die-shot
1361
+ readings on the Denial forum (Lance Ewing and nippur72), which also
1362
+ say the voice is silent while off.
1363
+ - Pinned by xvic: noise at `$FE` and `$FD` repeats every 0.11825 s and
1364
+ 0.2365 s (autocorrelation 0.98 at those lags, in both xvic's
1365
+ recording and badline's), 65535 steps of 2 and 4 cycles. The octave
1366
+ band levels of noise at `$FE`, `$FD`, `$F0`, `$C0` and `$80` match
1367
+ xvic's within 0.5 dB up to 8 kHz.
1368
+ - Spec guard: *the noise voice* in
1369
+ [`vic20/sound_spec.rb`](../spec/badline/vic20/sound_spec.rb).
1370
+ - The output is the voices that are high plus 2/9 of a voice, times the
1371
+ volume, so a volume write steps the output with every voice off, as
1372
+ 4-bit samples played through `$900E` need.
1373
+ - Pinned by xvic: a volume step from 0 to 15 with every voice off peaks
1374
+ at 0.218 of a voice turned on at volume 15.
1375
+ - Spec guard: *the volume* in
1376
+ [`vic20/sound_spec.rb`](../spec/badline/vic20/sound_spec.rb).
1377
+ - Not pinned: the volume scales the output linearly. xvic's tone level
1378
+ per volume step isn't linear (volume 1 is 0.099 of volume 15 and 14
1379
+ is 1.015), and nothing here says whether the hardware is.
1380
+ - The output stage is a one-pole low-pass at 1,420 Hz and a one-pole
1381
+ high-pass at 158 Hz.
1382
+ - Pinned by xvic: a bass voice turned on at volume 15 fits those two RC
1383
+ stages at 1,417 and 158.0 Hz, with an RMS error of 6 against a peak of
1384
+ 11,280. badline's own recording fits 1,420 and 157.6 Hz.
1385
+ - Spec guard: *a step* in
1386
+ [`vic20/sound/output_spec.rb`](../spec/badline/vic20/sound/output_spec.rb).
1387
+
1198
1388
  ## 1541 serial port
1199
1389
 
1200
1390
  - The drive sees the C64's side of the serial bus a host cycle late. The