badline 0.10.1 → 0.11.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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/CLAUDE.md +5 -3
  4. data/README.md +59 -4
  5. data/doc/pinned-behaviour.md +75 -0
  6. data/doc/snapshots.md +15 -0
  7. data/lib/badline/address_bus/pla.rb +3 -16
  8. data/lib/badline/address_bus.rb +14 -0
  9. data/lib/badline/c128/banks.rb +35 -0
  10. data/lib/badline/c128/bus.rb +347 -0
  11. data/lib/badline/c128/bus_state.rb +53 -0
  12. data/lib/badline/c128/color_lines.rb +39 -0
  13. data/lib/badline/c128/cpu.rb +10 -0
  14. data/lib/badline/c128/keys.rb +35 -0
  15. data/lib/badline/c128/mmu.rb +182 -0
  16. data/lib/badline/c128/mmu_pages.rb +105 -0
  17. data/lib/badline/c128/model.rb +39 -0
  18. data/lib/badline/c128/modes.rb +48 -0
  19. data/lib/badline/c128/saved_state.rb +120 -0
  20. data/lib/badline/c128/vdc/memory.rb +54 -0
  21. data/lib/badline/c128/vdc/painter.rb +143 -0
  22. data/lib/badline/c128/vdc/raster.rb +97 -0
  23. data/lib/badline/c128/vdc/window.rb +215 -0
  24. data/lib/badline/c128/vdc.rb +268 -0
  25. data/lib/badline/c128.rb +320 -0
  26. data/lib/badline/chrout_trap.rb +3 -0
  27. data/lib/badline/computer/attachments.rb +4 -13
  28. data/lib/badline/computer/kernal_traps.rb +29 -0
  29. data/lib/badline/computer.rb +5 -0
  30. data/lib/badline/frontend/app.rb +34 -21
  31. data/lib/badline/frontend/boot.rb +31 -1
  32. data/lib/badline/frontend/controls.rb +11 -0
  33. data/lib/badline/frontend/keys.rb +28 -1
  34. data/lib/badline/frontend/machine_window.rb +16 -13
  35. data/lib/badline/frontend/menu_pages.rb +6 -1
  36. data/lib/badline/frontend/menu_ports.rb +1 -1
  37. data/lib/badline/frontend/pause_menu.rb +1 -0
  38. data/lib/badline/frontend/screen.rb +33 -8
  39. data/lib/badline/frontend/screens.rb +90 -0
  40. data/lib/badline/frontend/timeline.rb +15 -4
  41. data/lib/badline/frontend.rb +1 -0
  42. data/lib/badline/kernal_trap/file.rb +1 -1
  43. data/lib/badline/kernal_trap/layout.rb +58 -8
  44. data/lib/badline/kernal_trap/load.rb +1 -1
  45. data/lib/badline/kernal_trap/save.rb +1 -1
  46. data/lib/badline/kernal_trap/serial.rb +5 -0
  47. data/lib/badline/machine.rb +15 -6
  48. data/lib/badline/media.rb +8 -6
  49. data/lib/badline/options/event.rb +5 -1
  50. data/lib/badline/options/family.rb +52 -0
  51. data/lib/badline/options/help.rb +5 -1
  52. data/lib/badline/options/table.rb +7 -1
  53. data/lib/badline/options/validation.rb +14 -1
  54. data/lib/badline/options.rb +20 -19
  55. data/lib/badline/roms/README +27 -0
  56. data/lib/badline/roms/c128/basic.rom +0 -0
  57. data/lib/badline/roms/c128/character.rom +0 -0
  58. data/lib/badline/roms/c128/kernal.rom +0 -0
  59. data/lib/badline/snapshot/container.rb +2 -0
  60. data/lib/badline/snapshot/image.rb +14 -0
  61. data/lib/badline/snapshot.rb +9 -2
  62. data/lib/badline/version.rb +1 -1
  63. data/lib/badline/vic/display_state.rb +12 -0
  64. data/lib/badline/vic/registers.rb +3 -0
  65. data/lib/badline/vic.rb +108 -7
  66. data/lib/badline.rb +1 -0
  67. metadata +24 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e82b9f5bb012d15fd7744f164b82420c3b71c00b14b43843093e1a2b3722beeb
4
- data.tar.gz: cf94f9a74e8c9d5d6b9d3a94a5404d29376a4c57da7f18b78c9dd87da4a7c880
3
+ metadata.gz: 3f8a451e4b936c57d5cf39cc7253481e5c8deff31898cb015641ed54246a68da
4
+ data.tar.gz: 8d1e5c8aab0d9352e31a5f7b870896aaec254dbcd55c823fe24496d820b2befc
5
5
  SHA512:
6
- metadata.gz: 14986d25fea5add5cecf4c10001b4f9cf9e087023f07bf8a8fc27d950f799ff41ae086518165ca67b840c440e5f56cf661d335ac5d4f5de347260c0bd44864bb
7
- data.tar.gz: 12ba3fa5d2276efb1003edaa884e8f1c58ee7d2e2ac5e05b0f7d927e6d8b5a37869893f012d92560772b3adf18ea2d886c058737bf9e10aac25aec54e36afe6b
6
+ metadata.gz: d97d1b2876eafb8a51cd290c651904c798be975e0f3f7ea9ba4960a3dcaeebb6a76cc9cdad8bb5bf3ac5c732af3ec0eeddb779916b9e793292350d0749ed730f
7
+ data.tar.gz: 2b7f0307a605b0270490ae3155c1671e1197473a0c22edf836bce953c08ff8884d1b09ca92fd7b3bc8c4038de63b66d5b92e3e82297ecfaddd5cde592ef74493
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.11.0](https://github.com/elektronaut/badline/compare/v0.10.1...v0.11.0) (2026-10-09)
4
+
5
+
6
+ ### Features
7
+
8
+ * add the C128 in C64 mode, headless ([17462eb](https://github.com/elektronaut/badline/commit/17462ebb94b27fe59c7cee8c51e82be340158979))
9
+ * boot badline c128 in C128 mode, with --c64 holding C= through the reset ([fbb57e5](https://github.com/elektronaut/badline/commit/fbb57e5e46bd1178bb63b2feedee6776a5e4cc57))
10
+ * boot the C128 in C128 mode through its own MMU and KERNAL ([8bdd810](https://github.com/elektronaut/badline/commit/8bdd810c03cb916b3484fabbf84172098af26835))
11
+ * bundle the C128's BASIC 7.0, KERNAL and character ROMs ([25329f8](https://github.com/elektronaut/badline/commit/25329f83e7a5e07c4df3ea49b85528184fd7f313))
12
+ * follow the C128 between its 40 and 80 column screens, with 40/80 DISPLAY on F6 and ESC on Esc ([4099600](https://github.com/elektronaut/badline/commit/4099600d413fa617dc7cea63ac80302b759c9f08))
13
+ * give the C128's VDC its 80 column display ([80b0831](https://github.com/elektronaut/badline/commit/80b083138629c6410c18a55b48f3e59d22d466f1))
14
+ * run the C128 in the window as badline c128, in both builds, with its VDC, keys and snapshots ([d58eaf6](https://github.com/elektronaut/badline/commit/d58eaf606932527fda9fd5de308c4010bd9fc4cf))
15
+ * run the C128's 2 MHz mode and TEST bit cycle by cycle ([9a0a483](https://github.com/elektronaut/badline/commit/9a0a483f775b2d06fabb32bd99988c1976753fa3))
16
+ * serve device 8 and CHROUT through the C128 KERNAL's traps in C128 mode ([76c1764](https://github.com/elektronaut/badline/commit/76c1764a54d68960194126e50d228a979ace93a2))
17
+
3
18
  ## [0.10.1](https://github.com/elektronaut/badline/compare/v0.10.0...v0.10.1) (2026-10-08)
4
19
 
5
20
 
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`, the true 1541 drive with `--drive`, and the VIC-20 with `--vic20` |
53
+ | VICE testbench | `bin/testbench <subtree>` | `VICII/`, `CIA/`, `interrupts/`, `CPU/`, cartridges with `--carts`, the true 1541 drive with `--drive`, the VIC-20 with `--vic20`, and the C128 in C64 mode with `--c128c64` |
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`, about 25 for `testbench-expansions` and under 1 for `testbench-vic20`. `sid` takes about 12 min. `lorenz` chains itself and takes
147
+ `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
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
@@ -196,7 +196,9 @@ the 6526A) for anything the interrupt register or the CIA model reaches; cartrid
196
196
  `testbench-carts`, plus `testbench-expansions` for banking; GEO-RAM, +60K,
197
197
  +256K, the REU or the VIC's BA line the REU follows → `testbench-expansions`; the 1541 drive, VIA or IEC bus →
198
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
199
+ `testbench-vic20` (`bin/testbench --vic20`); the C128 (`c128.rb`, `c128/`), or
200
+ the VIC-IIe, CPU or PLA code it shares with the C64 → `testbench-c128c64`
201
+ (`bin/testbench --c128c64`); SID → `sid`, plus `sid-8580` for anything the 8580
200
202
  model reaches (`bin/sidtests --sid 8580`). Leave the Lorenz chain to CI,
201
203
  unless your code has a rule in `doc/pinned-behaviour.md` that names Lorenz
202
204
  tests: the interrupt polling, CPU port and CIA timer rules. Run just the
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`. See [What's emulated](#whats-emulated) for the details.
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.
17
17
 
18
18
  It comes in two builds of the same emulator:
19
19
 
@@ -69,7 +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`.
72
+ [The VIC-20](#the-vic-20) for `badline vic20` and [The C128](#the-c128)
73
+ for `badline c128`.
73
74
 
74
75
  `badline-ruby` takes the same media and the same options, with the
75
76
  differences noted in the table. `--help` lists the options for either.
@@ -87,6 +88,7 @@ differences noted in the table. `--help` lists the options for either.
87
88
  | `--reu SIZE` | Plug in a RAM Expansion Unit of `SIZE` K: 128, 256, 512 (a 1750) or up to 16384 |
88
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 |
89
90
  | `--ntsc` | Run an NTSC C64, as `--model ntsc` does |
91
+ | `--c64` | Start a C128 in C64 mode, holding `C=` at power-on. See [The C128](#the-c128) |
90
92
  | `--no-sound` | Don't play the SID (`badline` only, where sound is on by default) |
91
93
  | `--sound` | Play the SID (`badline-ruby`, where sound is off by default) |
92
94
  | `--no-vsync` | Pace the window by a timer, or by the sound while it plays, instead of the display's vsync |
@@ -163,6 +165,55 @@ goes in as a `.crt` does. Disks go through the KERNAL traps or, with
163
165
  save and load the VIC-20 too, in badline's own snapshots: xvic's `.vsf`
164
166
  files don't load.
165
167
 
168
+ ## The C128
169
+
170
+ `badline c128` runs a C128 in C128 mode, with BASIC 7.0, and takes the
171
+ same media as the C64:
172
+
173
+ ```sh
174
+ badline c128 # READY., in BASIC 7.0
175
+ badline c128 game.prg # Load and run a program
176
+ badline c128 game.d64 # Mount a disk image as device 8 and LOAD"*",8,1 it
177
+ badline c128 --c64 # Hold C= at power-on to start in C64 mode
178
+ badline c128 --model c128dcr game.crt
179
+ ```
180
+
181
+ `--c64` holds `C=` down through the reset, so the C128 KERNAL starts C64
182
+ mode, as on a real C128. A program that loads at `$0801`, where C64 BASIC
183
+ starts, and a `.sid` tune start C64 mode the same way, and so does a C64
184
+ cartridge, through the KERNAL. `GO64` gets there from BASIC 7.0. A
185
+ program that loads at `$1C01`, where BASIC 7.0 starts, runs, and other
186
+ programs load at their own address. The disk in device 8 is served
187
+ through the KERNAL traps in either mode. The C128's Z80 isn't emulated:
188
+ the 8502 starts the machine. `--model` picks the board: `c128` (the default, the flat C128
189
+ and the plastic C128D, PAL, with the 6581 SID and a VDC with 16K of
190
+ RAM), `c128dcr` (the metal C128DCR, with the 8580, 6526As and a VDC with
191
+ 64K), and `c128ntsc` and `c128dcrntsc` for their NTSC versions. `--sid`
192
+ takes the model's place. Without `c128`, a program that loads at
193
+ `$1C01`, where C128 BASIC starts, picks the C128 too, and a `.d71`
194
+ stays on the C64.
195
+
196
+ The window shows the screen the C128 prints to, and follows it when
197
+ it moves: to the VDC's 80 columns after `GRAPHIC 5`, `ESC X` or a reset
198
+ with `40/80 DISPLAY` locked down, and back to the VIC-IIe's 40 columns
199
+ after `GRAPHIC 0` or `ESC X` again. In C64 mode it shows the VIC-IIe.
200
+ `F8` switches the window to the other screen, as a monitor's 40/80
201
+ switch does, until the C128 next moves. The window takes the VDC's
202
+ size, which its registers set, a dot to a pixel with its lines doubled.
203
+ Only the chip shown is drawn.
204
+
205
+ Besides the C64's keys, the C128's own keys sit on their host keys: the
206
+ keypad on the keypad, `HELP` on `Insert` (or `Help`), `ALT` on the right
207
+ `Alt`, `NO SCROLL` on `Scroll Lock`, `CAPS LOCK` on `Caps Lock` and
208
+ `40/80 DISPLAY` on `F6` or `Pause`, both of which lock it down and up
209
+ like the real key. In C128 mode `Esc` is `ESC` and `RUN/STOP` is on
210
+ `Page Down` (`Fn`-`Down` on a Mac), and in C64 mode `Esc` stays
211
+ `RUN/STOP`. In C64 mode only a program that scans the C128's keys
212
+ itself sees them. `TAB`, `LINE FEED` and the separate cursor keys have
213
+ no host key yet: `Tab` and the arrows keep their C64 uses.
214
+ `F11`, `F12` and the pause menu save and load the C128 in badline's own
215
+ snapshots, and x128's `.vsf` files don't load.
216
+
166
217
  ## Snapshots
167
218
 
168
219
  `F11` quicksaves the whole machine to the next of five slots in
@@ -200,7 +251,7 @@ types `"`. These keys have no same-named host key:
200
251
 
201
252
  | C64 | Host |
202
253
  |-----|------|
203
- | `RUN/STOP` | `Escape` |
254
+ | `RUN/STOP` | `Escape`, or on the C128 `Page Down` (`Esc` is `ESC` in C128 mode) |
204
255
  | `CLR/HOME` | `Home` |
205
256
  | `INST/DEL` | `Backspace` |
206
257
  | `CRSR ⇔` / `CRSR ⇕` | `Right` / `Down`, and `Left` / `Up` for the shifted directions |
@@ -258,7 +309,7 @@ too.
258
309
  | Expansion port | The cartridge: insert, remove, and its freeze button if it has one |
259
310
  | Ports | The device in each control port, and where the keys go |
260
311
  | Sound | Mute, and the SID's model |
261
- | Power | Reset, power cycle and quit |
312
+ | Power | Reset, power cycle and quit, and on a C128 its model and mode |
262
313
 
263
314
  INSERT opens a file browser. A disk's set is the `.m3u` or `.vfl` list it
264
315
  was opened from, or one in its folder that lists it. Without one, it comes
@@ -294,6 +345,10 @@ program or `.sid` dropped on it opens the menu to ask first.
294
345
  both 6522 VIAs, the keyboard, the joystick and RESTORE, RAM
295
346
  expansions up to 35K (`--ram`), cartridges, the datasette and the
296
347
  serial bus to device 8 (`badline vic20`).
348
+ - **C128**: C128 mode with BASIC 7.0 and C64 mode, on the 8502 with its
349
+ port, FAST mode, the VIC-IIe with its extra keyboard lines, the 8722
350
+ MMU, the 8563 or 8568 VDC with its 80 column display, and 128K of RAM
351
+ (`badline c128`). The Z80 and the 1571 aren't emulated yet.
297
352
  - **1541**: an emulated drive running its own DOS (`--true-drive`).
298
353
  - **Cartridges**: standard 8K, 16K and Ultimax, Simons' BASIC, Ocean,
299
354
  Fun Play / Power Play, Super Games, Epyx FastLoad, Westermann
@@ -25,6 +25,7 @@ only catches the rows that happen to move.
25
25
  - [VIC phi1 bus](#vic-phi1-bus)
26
26
  - [VIC light pen](#vic-light-pen)
27
27
  - [VIC-II 8565](#vic-ii-8565)
28
+ - [VIC-IIe 2 MHz and TEST bit](#vic-iie-2-mhz-and-test-bit)
28
29
  - [VIC-II NTSC](#vic-ii-ntsc)
29
30
  - [VIC-II 6572 (Drean)](#vic-ii-6572-drean)
30
31
  - [CIA 6526 timer pipeline](#cia-6526-timer-pipeline)
@@ -926,6 +927,80 @@ What the 8565 references don't settle, and so what stays as it is:
926
927
  6569's idle access, without the 6569's `$38ff` read where a DMA delay
927
928
  starts.
928
929
 
930
+ ## VIC-IIe 2 MHz and TEST bit
931
+
932
+ The C128's VIC-IIe (`:mos8566`, `:mos8564`) adds $D030: bit 0 (FAST)
933
+ runs the 8502 at 2 MHz, and bit 1 (TEST) clocks the raster counter in
934
+ every cycle. `C128#cycle!` and `#clock_fast` drive both, through
935
+ `VIC#take_cpu_bus`, `#test_step!` and `#refresh_cycle?`. The oracles are
936
+ the testprogs' own references for `c128/2mhzVIC` (3 rows, from the
937
+ author's machine) and `c128/d030tester` (33 rows), and the real-machine
938
+ photos in `c128/2mhztest`. Those are C128-mode programs that switch to C64
939
+ mode as they start, so no testbench list runs them yet: `spec/badline/
940
+ c128_2mhz_spec.rb` runs six d030tester builds from their machine code at
941
+ $1C0E and checks the readings they print.
942
+
943
+ - FAST and TEST take hold in the second cycle after the write that sets
944
+ or clears them. Pinned by d030tester's "Lines cut": STA/STX $D030 keeps
945
+ TEST on for 4 cycles, but for 3 when the STA also sets FAST, because
946
+ the STX then runs its operand fetches at 2 MHz. With the delay at 0
947
+ the FAST builds cut 2 lines, not 3. Spec guard: `c128_spec.rb`.
948
+ - In FAST mode the CPU runs in both halves of every cycle but Bauer's
949
+ refresh cycles 11-15, whose phi1 stays with the VIC: 121 CPU cycles a
950
+ PAL line. BA doesn't halt it. Pinned by `2mhz-vic-hires`,
951
+ `-multicolor` and `-extended`, whose drawing code assumes 121 cycles a
952
+ line.
953
+ - An access to $D000-$DFFF waits for phi2: one in phi1 takes the whole
954
+ cycle. Pinned by `timing-change0`, whose `INC $D020` takes 8 half
955
+ cycles (its comment says "6 cycles + 2"). The machine finds out after
956
+ the CPU's step that it reached I/O, so `CPU::Core` needn't say where
957
+ its next access goes.
958
+ - The VIC's accesses in a FAST cycle latch the CPU's bytes: the g-access,
959
+ or idle access, the byte of phi1, and a c-access the byte of phi2, as
960
+ one made before AEC does on the C64: $FF for the video matrix and the
961
+ byte's low nibble for colour. Pinned by `2mhz-vic-*` (the operands are
962
+ the pixels and the opcodes' low nibbles the colours) and by the "VIC
963
+ internal data" row of d030tester, which shows char $FF's glyph in
964
+ slow-mode lines after a FAST bad line.
965
+ - A c-access in a cycle where the CPU reads or writes a VIC register
966
+ takes that byte for the video matrix as well. Pinned by d030tester:
967
+ `STX $D030` with X=0 leaves an `@` (McCabe's readme: "the `@`
968
+ represents a 0 written to $D030"), and the `DEC $D030` build (2mhzdec)
969
+ leaves char $FD, the byte it reads.
970
+ - In the phi1 an I/O access waits through, the VIC sees the byte the CPU
971
+ writes, or the last byte the bus held for a read. Pinned by d030tester
972
+ and 2mhzdec, whose g-access there shows $00 (X) and $D0 (the operand's
973
+ high byte).
974
+ - AEC can't follow BA down in FAST mode, so on a bad line it falls three
975
+ cycles after the last FAST cycle, and the c-accesses before it read
976
+ $FF and the halted CPU's nibble (`DisplayState#keep_bus`). Pinned by
977
+ d030tester's "VIC internal data" row, where three cells after the FAST
978
+ cycles show colour 0 (the halted read's $D0) and the rest the screen.
979
+ - The TEST bit steps the raster counter ahead of each cycle it is set
980
+ in, except the line's last cycle, which steps it anyway, and the step
981
+ from the frame's last line to line 0 takes two cycles. Pinned by
982
+ d030tester: TEST across the line end (`32c_02_00`, `32c_03_00`) cuts
983
+ one line fewer, and the frame it keeps 312 lines long with two TEST
984
+ windows of a whole frame each reads 19656 cycles ($4CC8) only with the
985
+ two-cycle wrap. A step into a bad line's raster halts the CPU through
986
+ BA for the one cycle the raster matches: `2ae_02_00` and `2ed_02_00`
987
+ cut 5 lines for 4 cycles. Spec guard: `vic_iie_spec.rb`.
988
+ - The beam doesn't follow the raster counter's steps: it draws the next
989
+ display line after the last one (`VIC#output_line`), so the lines TEST
990
+ skips move the picture up, until a line that ends in the vertical sync
991
+ (PAL lines 303-305, three lines from the fourth blanked one) puts the
992
+ beam back on the raster line. A blanked line the beam draws off the
993
+ raster line shows black. Pinned by d030tester's `vadjust` builds, which
994
+ move the picture up a line per cycle of TEST, `vadjust1` included,
995
+ where the first window leaves the raster counter on line 304, and by
996
+ the colour bar that `173_02_00` draws four lines taller.
997
+ - Not matched: the d030tester references come from an emulator that
998
+ models PAL decoding. A line cut an odd number of times flips the colour
999
+ phase, so every row below it shows other hues (all 11 builds whose cut
1000
+ is odd), and lines drawn while TEST runs show alternating hues and
1001
+ per-cycle blanking. Their 8566 shows no grey dots. The 2mhzVIC
1002
+ references have none either.
1003
+
929
1004
  ## VIC-II NTSC
930
1005
 
931
1006
  The 6567R8 (`Region::NTSC`) and the 6567R56A (`Region::NTSC_OLD`) run
data/doc/snapshots.md CHANGED
@@ -80,6 +80,21 @@ it, and badline doesn't open xvic's. Restoring a
80
80
  VIC-20 snapshot while a C64 runs, or a C64 one while a VIC-20 runs,
81
81
  swaps the machine in the window.
82
82
 
83
+ ## The C128
84
+
85
+ `badline c128` saves and restores the same way too. A C128 snapshot
86
+ holds its 128K of RAM, both colour RAM banks, the CPU port, the MMU's
87
+ registers and the page pointer writes it holds, the VIC-IIe, both CIAs,
88
+ the SID, the VDC with its RAM and registers, the CPU, a cartridge, the
89
+ tape, the disk device 8 serves through the traps and a true 1541, and
90
+ restores into a C128 of the same model with the same SID, built for the
91
+ same mode. The VDC's picture is left out and painted again while the
92
+ window shows it, and the window shows the VIC-IIe after a restore. Its
93
+ file names its machine `C128`, as x128's do, and holds only the
94
+ `BADLINE` module, so x128 doesn't open it, and badline doesn't open
95
+ x128's. Restoring a C128 snapshot while another machine runs swaps the
96
+ machine in the window, as for the VIC-20.
97
+
83
98
  ## VICE
84
99
 
85
100
  Snapshots use VICE's `.vsf` format. badline writes VICE's modules for
@@ -5,8 +5,9 @@ module Badline
5
5
  # The C64's PLA: what each page of the CPU's view maps to, from the
6
6
  # CPU port's LORAM, HIRAM and CHAREN lines and the cartridge's EXROM
7
7
  # and GAME. The bus that includes it supplies the page tables, the
8
- # ROMs, the chips, and #map_ram_pages, which lays out the RAM that the
9
- # ROMs, the cartridge and I/O map over.
8
+ # ROMs, the chips, #map_ram_pages, which lays out the RAM that the
9
+ # ROMs, the cartridge and I/O map over, and #map_io_pages, which lays
10
+ # out the chips at $D000-$DFFF, with #map_cartridge_io for I/O 1 and 2.
10
11
  module PLA
11
12
  # A chip's registers seen at another page, which reads and writes
12
13
  # them as at the page the chip starts at.
@@ -108,20 +109,6 @@ module Badline
108
109
  @write_pages.fill(bank, first_page, 0x20) if bank.is_a?(Cartridge::RAMBank)
109
110
  end
110
111
 
111
- def map_io_pages
112
- {
113
- vic => 0xd0..0xd3, sid => 0xd4..0xd7, color_ram => 0xd8..0xdb,
114
- cia1 => 0xdc..0xdc, cia2 => 0xdd..0xdd, @open_bus => 0xde..0xdf
115
- }.each do |chip, pages|
116
- pages.each { |p| @read_pages[p] = @write_pages[p] = chip }
117
- end
118
- @ram_expansion.map_io(@read_pages, @write_pages)
119
- @read_pages[0xd7] = @write_pages[0xd7] = @debug_register if @debug_register
120
- @read_pages[0xdf] = @write_pages[0xdf] = @reu if @reu
121
- map_cartridge_io if @cartridge
122
- map_extra_sids unless @sid_slots.empty?
123
- end
124
-
125
112
  def map_cartridge_io
126
113
  @write_pages.fill(@cartridge, 0xde, 2)
127
114
  @cartridge.readable_io_pages.each { |p| @read_pages[p] = @cartridge }
@@ -217,5 +217,19 @@ module Badline
217
217
  def map_ram_pages
218
218
  @ram_expansion.map(@read_pages, @write_pages)
219
219
  end
220
+
221
+ def map_io_pages
222
+ {
223
+ vic => 0xd0..0xd3, sid => 0xd4..0xd7, color_ram => 0xd8..0xdb,
224
+ cia1 => 0xdc..0xdc, cia2 => 0xdd..0xdd, @open_bus => 0xde..0xdf
225
+ }.each do |chip, pages|
226
+ pages.each { |p| @read_pages[p] = @write_pages[p] = chip }
227
+ end
228
+ @ram_expansion.map_io(@read_pages, @write_pages)
229
+ @read_pages[0xd7] = @write_pages[0xd7] = @debug_register if @debug_register
230
+ @read_pages[0xdf] = @write_pages[0xdf] = @reu if @reu
231
+ map_cartridge_io if @cartridge
232
+ map_extra_sids unless @sid_slots.empty?
233
+ end
220
234
  end
221
235
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C128
5
+ # The RAM the C128 KERNAL's bank numbers 0-15 reach, as its INDFET and
6
+ # INDSTA reach it for LOAD, SAVE and the file name: the RAM bank of the
7
+ # CR value the KERNAL's table at $F7F0 holds for the bank, with common
8
+ # RAM in bank 0. The ROMs and I/O some of those CR values map are left
9
+ # out.
10
+ class Banks
11
+ CONFIGURATIONS = 0xf7f0
12
+
13
+ def initialize(ram, mmu, kernal_rom)
14
+ @ram = ram
15
+ @mmu = mmu
16
+ @kernal_rom = kernal_rom
17
+ end
18
+
19
+ def peek(bank, addr) = @ram.peek(physical(bank, addr))
20
+
21
+ def write(bank, addr, bytes)
22
+ bytes.each_with_index { |byte, i| @ram.poke(physical(bank, (addr + i) & 0xffff), byte) }
23
+ end
24
+
25
+ private
26
+
27
+ def physical(bank, addr)
28
+ page = addr >> 8
29
+ common = page < @mmu.common_low_pages || page >= @mmu.common_high_start
30
+ ram_bank = common ? 0 : (@kernal_rom.peek(CONFIGURATIONS + (bank & 0x0f)) >> 6) & 0x01
31
+ (ram_bank << 16) | addr
32
+ end
33
+ end
34
+ end
35
+ end