badline 0.11.0 → 0.12.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/CLAUDE.md +24 -6
- data/CONTRIBUTING.md +15 -9
- data/README.md +16 -5
- data/doc/media.md +28 -1
- data/doc/pinned-behaviour.md +31 -1
- data/exe/badline-ruby +1 -1
- data/lib/badline/c128/bus.rb +4 -17
- data/lib/badline/c128/drives.rb +108 -0
- data/lib/badline/c128/fast_serial.rb +63 -0
- data/lib/badline/c128/io_pages.rb +35 -0
- data/lib/badline/c128/mmu.rb +24 -7
- data/lib/badline/c128/modes.rb +17 -4
- data/lib/badline/c128/saved_state.rb +23 -0
- data/lib/badline/c128/z80.rb +49 -0
- data/lib/badline/c128/z80_pages.rb +118 -0
- data/lib/badline/c128/z80_turns.rb +106 -0
- data/lib/badline/c128.rb +25 -26
- data/lib/badline/cartridge/action_replay.rb +2 -2
- data/lib/badline/cartridge/comal80.rb +1 -7
- data/lib/badline/cartridge/dinamic.rb +0 -8
- data/lib/badline/cartridge/final_cartridge3.rb +6 -6
- data/lib/badline/cartridge/fun_play.rb +0 -8
- data/lib/badline/cartridge/game_system.rb +0 -8
- data/lib/badline/cartridge/kcs_power.rb +10 -7
- data/lib/badline/cartridge/mach5.rb +2 -4
- data/lib/badline/cartridge/magic_desk.rb +0 -8
- data/lib/badline/cartridge/ocean.rb +0 -8
- data/lib/badline/cartridge/pagefox.rb +2 -2
- data/lib/badline/cartridge/retro_replay.rb +7 -6
- data/lib/badline/cartridge/rex_utility.rb +2 -6
- data/lib/badline/cartridge/rgcd.rb +2 -2
- data/lib/badline/cartridge/simons_basic.rb +0 -5
- data/lib/badline/cartridge/super_games.rb +4 -2
- data/lib/badline/cartridge/westermann.rb +2 -6
- data/lib/badline/cartridge.rb +37 -9
- data/lib/badline/cia/fast_forward.rb +60 -0
- data/lib/badline/cia/serial.rb +12 -0
- data/lib/badline/cia/timer.rb +39 -0
- data/lib/badline/cia.rb +10 -5
- data/lib/badline/computer/attachments.rb +4 -50
- data/lib/badline/computer/true_drives.rb +80 -0
- data/lib/badline/computer.rb +4 -0
- data/lib/badline/core.rb +2 -0
- data/lib/badline/drive/core.rb +147 -0
- data/lib/badline/drive/fast_serial.rb +73 -0
- data/lib/badline/{drive1541 → drive}/idle.rb +18 -29
- data/lib/badline/drive/idle_cpu.rb +28 -0
- data/lib/badline/{drive1541 → drive}/orbit.rb +3 -5
- data/lib/badline/drive/serial_lines.rb +73 -0
- data/lib/badline/{drive1541 → drive}/sleep.rb +4 -5
- data/lib/badline/drive/vias.rb +84 -0
- data/lib/badline/drive/watch.rb +150 -0
- data/lib/badline/drive.rb +11 -0
- data/lib/badline/drive1541/bus.rb +5 -129
- data/lib/badline/drive1541/byte_ready.rb +48 -0
- data/lib/badline/drive1541/cpu.rb +1 -19
- data/lib/badline/drive1541/disk.rb +77 -20
- data/lib/badline/drive1541/disk_state.rb +7 -2
- data/lib/badline/drive1541/disk_via.rb +3 -0
- data/lib/badline/drive1541/mechanism.rb +48 -14
- data/lib/badline/drive1541/mechanism_state.rb +5 -4
- data/lib/badline/drive1541/rotation.rb +5 -5
- data/lib/badline/drive1541/serial_port.rb +4 -60
- data/lib/badline/drive1541.rb +14 -172
- data/lib/badline/drive1571/bus.rb +111 -0
- data/lib/badline/drive1571/cpu.rb +11 -0
- data/lib/badline/drive1571/serial_port.rb +37 -0
- data/lib/badline/drive1571/serial_via.rb +25 -0
- data/lib/badline/drive1571/wd1770.rb +120 -0
- data/lib/badline/drive1571.rb +175 -0
- data/lib/badline/drive1581/bus.rb +137 -0
- data/lib/badline/drive1581/cpu.rb +11 -0
- data/lib/badline/drive1581/disk.rb +135 -0
- data/lib/badline/drive1581/disk_state.rb +87 -0
- data/lib/badline/drive1581/mechanism.rb +117 -0
- data/lib/badline/drive1581/serial_port.rb +52 -0
- data/lib/badline/drive1581/slot.rb +78 -0
- data/lib/badline/drive1581/track.rb +100 -0
- data/lib/badline/drive1581/track_bytes.rb +75 -0
- data/lib/badline/drive1581/wd1772/registers.rb +89 -0
- data/lib/badline/drive1581/wd1772/sector_writes.rb +73 -0
- data/lib/badline/drive1581/wd1772/sectors.rb +150 -0
- data/lib/badline/drive1581/wd1772/state.rb +66 -0
- data/lib/badline/drive1581/wd1772/stepping.rb +109 -0
- data/lib/badline/drive1581/wd1772/tracks.rb +125 -0
- data/lib/badline/drive1581/wd1772/turn.rb +73 -0
- data/lib/badline/drive1581/wd1772.rb +216 -0
- data/lib/badline/drive1581.rb +233 -0
- data/lib/badline/frontend/app.rb +2 -4
- data/lib/badline/frontend/audio_device.rb +67 -0
- data/lib/badline/frontend/audio_sink.rb +16 -50
- data/lib/badline/frontend/boot.rb +18 -10
- data/lib/badline/frontend/buttons.rb +7 -7
- data/lib/badline/frontend/drive_led.rb +1 -1
- data/lib/badline/frontend/keys.rb +33 -8
- data/lib/badline/frontend/media_slots.rb +42 -0
- data/lib/badline/frontend/{confirmation.rb → menu/confirmation.rb} +4 -4
- data/lib/badline/frontend/{file_browser.rb → menu/file_browser.rb} +18 -34
- data/lib/badline/frontend/{menu_dialogs.rb → menu/menu_dialogs.rb} +3 -7
- data/lib/badline/frontend/{menu_media.rb → menu/menu_media.rb} +26 -51
- data/lib/badline/frontend/{menu_pages.rb → menu/menu_pages.rb} +7 -9
- data/lib/badline/frontend/{name_field.rb → menu/name_field.rb} +11 -24
- data/lib/badline/frontend/{pause_menu.rb → menu/pause_menu.rb} +13 -28
- data/lib/badline/frontend/menu/theme.rb +18 -0
- data/lib/badline/frontend/{filter_view.rb → player/filter_view.rb} +4 -4
- data/lib/badline/frontend/{info_view.rb → player/info_view.rb} +3 -3
- data/lib/badline/frontend/{player_window.rb → player/player_controller.rb} +17 -25
- data/lib/badline/frontend/{player_footer.rb → player/player_footer.rb} +8 -8
- data/lib/badline/frontend/{player_header.rb → player/player_header.rb} +5 -5
- data/lib/badline/frontend/{player_screen.rb → player/player_screen.rb} +4 -5
- data/lib/badline/frontend/{scope.rb → player/scope.rb} +1 -1
- data/lib/badline/frontend/{sid_view.rb → player/sid_view.rb} +16 -20
- data/lib/badline/frontend/player/theme.rb +18 -0
- data/lib/badline/frontend/{visualizer_view.rb → player/visualizer_view.rb} +8 -8
- data/lib/badline/frontend/sound.rb +19 -38
- data/lib/badline/frontend/timeline.rb +3 -14
- data/lib/badline/frontend.rb +24 -20
- data/lib/badline/iec_bus.rb +68 -6
- data/lib/badline/machine.rb +9 -6
- data/lib/badline/media/boot_disk.rb +50 -0
- data/lib/badline/media/not_disk.rb +8 -0
- data/lib/badline/media/true_drive.rb +48 -25
- data/lib/badline/media.rb +9 -3
- data/lib/badline/options/event.rb +2 -2
- data/lib/badline/options/family.rb +3 -9
- data/lib/badline/options/help.rb +3 -1
- data/lib/badline/options/table.rb +1 -1
- data/lib/badline/roms/README +18 -0
- data/lib/badline/roms/dos1571.rom +0 -0
- data/lib/badline/roms/dos1581.rom +0 -0
- data/lib/badline/sdl.rb +37 -20
- data/lib/badline/snapshot/state.rb +5 -4
- data/lib/badline/storage/d64_image.rb +3 -0
- data/lib/badline/storage/d71_image.rb +9 -4
- data/lib/badline/storage/g64_image.rb +7 -2
- data/lib/badline/storage/p00.rb +8 -0
- data/lib/badline/time_of_day.rb +9 -0
- data/lib/badline/version.rb +1 -1
- data/lib/badline/via/fast_forward.rb +3 -3
- data/lib/badline/vic20/attachments.rb +23 -3
- data/lib/badline/vic20/saved_state.rb +2 -0
- data/lib/badline/vic20.rb +3 -0
- data/lib/badline/z80/arithmetic.rb +117 -0
- data/lib/badline/z80/bit_page.rb +55 -0
- data/lib/badline/z80/block_io.rb +58 -0
- data/lib/badline/z80/block_transfers.rb +59 -0
- data/lib/badline/z80/bus_cycles.rb +111 -0
- data/lib/badline/z80/core.rb +113 -0
- data/lib/badline/z80/exchanges.rb +50 -0
- data/lib/badline/z80/extended_page.rb +89 -0
- data/lib/badline/z80/flags.rb +37 -0
- data/lib/badline/z80/interrupt_acceptance.rb +46 -0
- data/lib/badline/z80/jumps.rb +82 -0
- data/lib/badline/z80/loads.rb +98 -0
- data/lib/badline/z80/main_page.rb +134 -0
- data/lib/badline/z80/registers.rb +120 -0
- data/lib/badline/z80/saved_state.rb +69 -0
- data/lib/badline/z80/shifts.rb +64 -0
- data/lib/badline/z80.rb +11 -0
- metadata +89 -24
- /data/lib/badline/frontend/{menu_ports.rb → menu/menu_ports.rb} +0 -0
- /data/lib/badline/frontend/{player_commands.rb → player/player_commands.rb} +0 -0
- /data/lib/badline/frontend/{player_state.rb → player/player_state.rb} +0 -0
- /data/lib/badline/frontend/{sid_history.rb → player/sid_history.rb} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7e5111f801416999c9748d88475f3bdb54e1a1b4b25b3a4246a64c4b3b59bdd0
|
|
4
|
+
data.tar.gz: c924f57fce55ffd0e9c6134c22618106828e831feed277411e8e6d56bec7c3aa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6a7f251456552573fab6b3041c4cc0c2ce83550c81547953ba9bfb6550e331458bf307f58a3e47ffd2bfaa98cb5c7f8938adc7c68299e1ffd6adb604460f0241
|
|
7
|
+
data.tar.gz: 66632ccc5e1851a028837833e792a4ce2ff71cdd1e66113bed8b652618e73d0c90990359b00812c6368f949db6532b46a43684bf2d9c3334ab9876e7ea6836b6
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.12.0](https://github.com/elektronaut/badline/compare/v0.11.1...v0.12.0) (2026-10-10)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add the 1581's WD1772 and its .d81 disks at sector level ([b834218](https://github.com/elektronaut/badline/commit/b834218bb686ceef295f2aafada86910fe8b61a2))
|
|
9
|
+
* boot C128 boot disks such as CP/M at power-on ([69359b6](https://github.com/elektronaut/badline/commit/69359b60bfe91ec0d9634e3dec4e4039044814e7))
|
|
10
|
+
* emulate the 1581 drive on the C64, the VIC-20 and the C128 ([4696c5b](https://github.com/elektronaut/badline/commit/4696c5b205689b2a86f91503ce153a63ff0f6816))
|
|
11
|
+
* put the C128's Z80 on its bus and boot the C128 through it ([b3d0e60](https://github.com/elektronaut/badline/commit/b3d0e603a8dc606d090917a67a52c4f31854f307))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* let the 1571's WD1770 run its commands, so CP/M's disk BIOS finds no MFM disk ([a380768](https://github.com/elektronaut/badline/commit/a380768ae02ce5da33e73dc23147b4edb72c72ff))
|
|
17
|
+
* parse --at insert of a disk list without the rest of badline ([5d6b93a](https://github.com/elektronaut/badline/commit/5d6b93a86cf4b57be3312bfb7da32980d38f2800))
|
|
18
|
+
* save the KCS Power cartridge's I/O RAM in snapshots ([54fab40](https://github.com/elektronaut/badline/commit/54fab408d0d7447d5b7b977905aa7aaabf8ad92a))
|
|
19
|
+
* uninstall the serial traps when the VIC-20 unmounts ([b2acc3f](https://github.com/elektronaut/badline/commit/b2acc3ff495f10ec5bff3b56aae0e89b2741bd34))
|
|
20
|
+
|
|
21
|
+
## [0.11.1](https://github.com/elektronaut/badline/compare/v0.11.0...v0.11.1) (2026-10-09)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Features
|
|
25
|
+
|
|
26
|
+
* emulate the C128D's 1571 drive in 1541 and 1571 mode ([2c32d99](https://github.com/elektronaut/badline/commit/2c32d993a0449b4b537d5f82e9711b0e14604f95))
|
|
27
|
+
* fast serial between the C128 and its 1571 ([34fe02f](https://github.com/elektronaut/badline/commit/34fe02f2098664c94233da9e40828b40e41b6b1a))
|
|
28
|
+
|
|
3
29
|
## [0.11.0](https://github.com/elektronaut/badline/compare/v0.10.1...v0.11.0) (2026-10-09)
|
|
4
30
|
|
|
5
31
|
|
data/CLAUDE.md
CHANGED
|
@@ -49,8 +49,9 @@ requires only the namespace file.
|
|
|
49
49
|
| --- | --- | --- |
|
|
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
|
+
| 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 |
|
|
52
53
|
| 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`, the VIC-20 with `--vic20`,
|
|
54
|
+
| 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` |
|
|
54
55
|
| VICE SID testprogs | `bin/sidtests` | SID |
|
|
55
56
|
| Drive scenarios | `bin/drive_scenarios` | The true 1541 running the DOS ROM: save, format, the error channel, idle, write protect and autostart |
|
|
56
57
|
| CIA offline grids | `bundle exec rspec --tag slow spec/badline/cia` | CIA timers and shift register, against a bare CIA in about 2 min |
|
|
@@ -103,7 +104,7 @@ worktree and owns a different set of files.
|
|
|
103
104
|
- The external suites under `vendor/` are gitignored, so a new worktree has
|
|
104
105
|
only `vendor/.gitkeep`. From the worktree root, symlink the main
|
|
105
106
|
checkout's suites into it:
|
|
106
|
-
`for d in 65x02 VICE-testprogs; do ln -sfn ../../../../vendor/$d vendor/$d; done`.
|
|
107
|
+
`for d in 65x02 z80-sample VICE-testprogs; do ln -sfn ../../../../vendor/$d vendor/$d; done`.
|
|
107
108
|
The main checkout also has `vendor/OneLoad64-Games-Collection-v5`, which
|
|
108
109
|
`rake vendor:checkout` doesn't fetch. Link it the same way only for
|
|
109
110
|
`.sid` or media work. Don't re-run `rake vendor:checkout` there, and
|
|
@@ -129,12 +130,29 @@ worktree and owns a different set of files.
|
|
|
129
130
|
|
|
130
131
|
## Testing and baselines
|
|
131
132
|
|
|
132
|
-
- `rake vendor:checkout` fetches SingleStepTests
|
|
133
|
-
`vendor/`
|
|
133
|
+
- `rake vendor:checkout` fetches SingleStepTests 65x02, the Z80 sample
|
|
134
|
+
and VICE-testprogs into `vendor/`
|
|
134
135
|
- `bundle exec rspec`: line coverage is about 97%. `spec/spec_helper.rb`
|
|
135
136
|
fails a whole-suite run (every spec file, no filters) below 90%, while
|
|
136
137
|
single-file and filtered runs skip the floor. `:slow` specs are excluded
|
|
137
138
|
by default: run them with `bundle exec rspec --tag slow`
|
|
139
|
+
- `bundle exec parallel_rspec` is the whole run, `:slow` specs included,
|
|
140
|
+
in a process per core, held to the same 90% over the merged coverage.
|
|
141
|
+
CI runs it as two jobs, the plain examples (with the floor) and the
|
|
142
|
+
`:slow` ones. Agents run only the spec files they touch, with
|
|
143
|
+
plain `bundle exec rspec`, and leave whole runs to CI
|
|
144
|
+
- Keep each plain example to a few hundred ms. A million cycles of a C64 or
|
|
145
|
+
a C128 cost 3 to 5 s of CPU, and about three times that under coverage,
|
|
146
|
+
so an example that boots a machine or runs more than about a million
|
|
147
|
+
cycles goes under `:slow`
|
|
148
|
+
- Don't boot per example. Restore a machine from a State taken once
|
|
149
|
+
(`spec/support/taken_once.rb`), and share one machine between examples
|
|
150
|
+
that only read it. Assert on the cheapest oracle that proves the point: a
|
|
151
|
+
register or a RAM byte over a booted screen, a bare chip over a whole
|
|
152
|
+
machine, and the fewest cycles that reach the state
|
|
153
|
+
- Before opening a pull request, run `bundle exec rspec --profile 10` (with
|
|
154
|
+
`--tag slow` for `:slow` ones) on the spec files you added or changed,
|
|
155
|
+
and hold them to that budget
|
|
138
156
|
- `rake test`: SingleStepTests, plus the Minitest tests for the regression
|
|
139
157
|
runners in `test/`. Run it for any CPU change
|
|
140
158
|
|
|
@@ -198,13 +216,13 @@ the 6526A) for anything the interrupt register or the CIA model reaches; cartrid
|
|
|
198
216
|
`testbench-drive` (`bin/testbench --drive`) and `drive-scenarios` (`bin/drive_scenarios <filter>`), plus `testbench-vic20` for the VIA; the VIC-20 (`vic20/`) →
|
|
199
217
|
`testbench-vic20` (`bin/testbench --vic20`); the C128 (`c128.rb`, `c128/`), or
|
|
200
218
|
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
|
|
219
|
+
(`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
|
|
202
220
|
model reaches (`bin/sidtests --sid 8580`). Leave the Lorenz chain to CI,
|
|
203
221
|
unless your code has a rule in `doc/pinned-behaviour.md` that names Lorenz
|
|
204
222
|
tests: the interrupt polling, CPU port and CIA timer rules. Run just the
|
|
205
223
|
tests that rule names, one at a time, with
|
|
206
224
|
`ruby --yjit bin/lorenz --resume <test> --stop-after <test>`. A stretch
|
|
207
|
-
resumes on a fresh machine, so its cuts in
|
|
225
|
+
resumes on a fresh machine, so its cuts in `test/support/suites.rb` have to stay before
|
|
208
226
|
`trap1`, where the tests start carrying state from one to the next. Both Lorenz
|
|
209
227
|
and testbench load through the LOAD trap and type through the keyboard
|
|
210
228
|
buffer, so storage, IEC and keyboard changes can move them too. A broken
|
data/CONTRIBUTING.md
CHANGED
|
@@ -55,25 +55,31 @@ brew install sdl2 # macOS
|
|
|
55
55
|
apt install libsdl2-2.0-0 # Debian/Ubuntu
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
Install the dependencies and run the
|
|
58
|
+
Install the dependencies and run the whole suite, a process per core, as
|
|
59
|
+
CI does:
|
|
59
60
|
|
|
60
61
|
```sh
|
|
61
62
|
bundle install
|
|
62
|
-
bundle exec
|
|
63
|
+
bundle exec parallel_rspec
|
|
63
64
|
```
|
|
64
65
|
|
|
65
|
-
A run of the whole suite fails if line coverage drops below 90%.
|
|
66
|
-
single files or filtered examples
|
|
67
|
-
boot the whole machine and
|
|
68
|
-
`bundle exec rspec --tag slow`.
|
|
66
|
+
A run of the whole suite fails if line coverage drops below 90%. Run
|
|
67
|
+
single files or filtered examples with `bundle exec rspec`, which skips
|
|
68
|
+
that check. Specs tagged `:slow` boot the whole machine, and a plain
|
|
69
|
+
`bundle exec rspec` skips them. Run them with `bundle exec rspec --tag slow`.
|
|
69
70
|
|
|
70
71
|
The CPU is verified separately against the
|
|
71
|
-
[65x02 single step tests](https://github.com/SingleStepTests/65x02)
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
[65x02 single step tests](https://github.com/SingleStepTests/65x02), and
|
|
73
|
+
the Z80 against the [Z80 ones](https://github.com/SingleStepTests/z80).
|
|
74
|
+
`rake test` checks the 65x02 fixtures out into `vendor/65x02` first,
|
|
75
|
+
which takes a moment the first time. For the Z80 it fetches only the
|
|
76
|
+
first 100 cases of each opcode's file into `vendor/z80-sample`.
|
|
77
|
+
`Z80_SAMPLE=all` checks the whole Z80 suite out into `vendor/z80`
|
|
78
|
+
(about 1.5 GB) and runs every case:
|
|
74
79
|
|
|
75
80
|
```sh
|
|
76
81
|
bundle exec rake test
|
|
82
|
+
Z80_SAMPLE=all bundle exec rake test
|
|
77
83
|
```
|
|
78
84
|
|
|
79
85
|
Check style before pushing:
|
data/README.md
CHANGED
|
@@ -125,7 +125,7 @@ library, are covered in [doc/library.md](doc/library.md).
|
|
|
125
125
|
| Format | Handling |
|
|
126
126
|
|--------|----------|
|
|
127
127
|
| `.prg`, `.p00` | Loaded into memory after boot. A program at the BASIC start (`$0801`) is `RUN`, anything else is left for you to `SYS` |
|
|
128
|
-
| `.d64`, `.d71`, `.d81` | Mounted as device 8, then `LOAD"*",8,1` and `RUN`. Write-protected unless `--writable` |
|
|
128
|
+
| `.d64`, `.d71`, `.d81` | Mounted as device 8, then `LOAD"*",8,1` and `RUN`. On a C128 in C128 mode a boot disk goes in a true drive instead and boots at power-on. See [Media](doc/media.md#c128-boot-disks). Write-protected unless `--writable` |
|
|
129
129
|
| `.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` |
|
|
130
130
|
| `.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 |
|
|
131
131
|
| `.t64` | Mounted read-only as device 8 and loaded like a disk image. The files load by name, and no tape is involved |
|
|
@@ -139,7 +139,8 @@ Without `--true-drive`, device 8 is no drive at all but traps on the
|
|
|
139
139
|
KERNAL's disk routines. Loading is instant, but fast loaders and copy
|
|
140
140
|
protection that run code on the drive need `--true-drive`, which puts
|
|
141
141
|
an emulated 1541 there, running its own DOS at a real 1541's speed. Its
|
|
142
|
-
red LED lights in the bottom right corner of the border.
|
|
142
|
+
red LED lights in the bottom right corner of the border. With
|
|
143
|
+
`--true-drive`, a `.d81` goes in an emulated 1581 in place of the 1541.
|
|
143
144
|
[doc/media.md](doc/media.md) has the details, and how to attach media
|
|
144
145
|
from Ruby.
|
|
145
146
|
|
|
@@ -184,8 +185,12 @@ starts, and a `.sid` tune start C64 mode the same way, and so does a C64
|
|
|
184
185
|
cartridge, through the KERNAL. `GO64` gets there from BASIC 7.0. A
|
|
185
186
|
program that loads at `$1C01`, where BASIC 7.0 starts, runs, and other
|
|
186
187
|
programs load at their own address. The disk in device 8 is served
|
|
187
|
-
through the KERNAL traps in either mode
|
|
188
|
-
|
|
188
|
+
through the KERNAL traps in either mode, or with `--true-drive` by the
|
|
189
|
+
C128D's 1571. A boot disk boots in C128 mode, as on a real C128: CP/M's
|
|
190
|
+
system disks, a `.d81` such as VICE-testprogs' `c128-cpm/cpm3.d81` on a
|
|
191
|
+
1581 among them, and boot games. `badline c128 cpm3.d81` comes up at
|
|
192
|
+
CP/M's `A>` prompt. The Z80 starts the machine, as on a real C128, and hands
|
|
193
|
+
it to the 8502. `--model` picks the board: `c128` (the default, the flat C128
|
|
189
194
|
and the plastic C128D, PAL, with the 6581 SID and a VDC with 16K of
|
|
190
195
|
RAM), `c128dcr` (the metal C128DCR, with the 8580, 6526As and a VDC with
|
|
191
196
|
64K), and `c128ntsc` and `c128dcrntsc` for their NTSC versions. `--sid`
|
|
@@ -348,8 +353,14 @@ program or `.sid` dropped on it opens the menu to ask first.
|
|
|
348
353
|
- **C128**: C128 mode with BASIC 7.0 and C64 mode, on the 8502 with its
|
|
349
354
|
port, FAST mode, the VIC-IIe with its extra keyboard lines, the 8722
|
|
350
355
|
MMU, the 8563 or 8568 VDC with its 80 column display, and 128K of RAM
|
|
351
|
-
(`badline c128`)
|
|
356
|
+
(`badline c128`), and the Z80, which boots the machine.
|
|
352
357
|
- **1541**: an emulated drive running its own DOS (`--true-drive`).
|
|
358
|
+
- **1571**: the C128D's drive running DOS 3.0, in 1541 mode and in 1571
|
|
359
|
+
mode at 2 MHz with both sides of a `.d71` or `.g71`, and fast serial
|
|
360
|
+
(burst) to a C128 in C128 mode (`badline c128 --true-drive`).
|
|
361
|
+
- **1581**: the 3.5" drive running its own DOS on its WD1772 and 8520,
|
|
362
|
+
reading and writing `.d81` images, on the C64, the VIC-20 and the C128
|
|
363
|
+
(`--true-drive` with a `.d81`).
|
|
353
364
|
- **Cartridges**: standard 8K, 16K and Ultimax, Simons' BASIC, Ocean,
|
|
354
365
|
Fun Play / Power Play, Super Games, Epyx FastLoad, Westermann
|
|
355
366
|
Learning, Rex Utility, C64 Game System / System 3, Dinamic, Zaxxon /
|
data/doc/media.md
CHANGED
|
@@ -36,6 +36,31 @@ drive's red LED lights in the bottom right corner of the border.
|
|
|
36
36
|
A `.g64` holds the disk's raw GCR, half tracks and all, so copy
|
|
37
37
|
protection and fast loaders that read it work.
|
|
38
38
|
|
|
39
|
+
## The true 1581
|
|
40
|
+
|
|
41
|
+
With a true drive on device 8, a `.d81` goes in an emulated 1581 in
|
|
42
|
+
its place: the 3.5" drive's own DOS on its 6502, with its WD1772 reading
|
|
43
|
+
and writing the image's sectors and its 8520 on the serial bus. Another
|
|
44
|
+
disk image swaps the 1541 (or on the C128 the 1571) back in. On the
|
|
45
|
+
C128 in C128 mode the 1581 talks fast serial (burst), as the 1571 does.
|
|
46
|
+
|
|
47
|
+
## C128 boot disks
|
|
48
|
+
|
|
49
|
+
At power-on the C128 KERNAL reads track 1, sector 0 of the disk in
|
|
50
|
+
device 8, and when the block starts with `CBM` it loads and runs it.
|
|
51
|
+
CP/M's system disks and boot games boot that way. A 1581 first loads and
|
|
52
|
+
runs a `USR` file named `COPYRIGHT CBM 86` when the disk has one, which
|
|
53
|
+
is how CP/M's 1581 disks hand the KERNAL their boot block.
|
|
54
|
+
|
|
55
|
+
On a C128 in C128 mode, a `.d64`, `.d71` or `.d81` that boots, with that
|
|
56
|
+
block or that file, goes in a true drive as device 8, a 1581 for a
|
|
57
|
+
`.d81` and the C128D's 1571 otherwise, and nothing is typed, so the
|
|
58
|
+
KERNAL boots it. `badline c128 cpm3.d81` comes up at CP/M's `A>`
|
|
59
|
+
prompt. Other disks keep the traps and `LOAD"*",8,1`, `--true-drive`
|
|
60
|
+
puts any disk in a true drive, and on the C64, the VIC-20 and a C128 in
|
|
61
|
+
C64 mode nothing changes. A boot disk inserted while the machine runs
|
|
62
|
+
boots at the next reset.
|
|
63
|
+
|
|
39
64
|
## Write protection
|
|
40
65
|
|
|
41
66
|
Disks given on the command line, inserted from the pause menu or by an
|
|
@@ -56,7 +81,9 @@ another disk. Both write to disk images unless told otherwise:
|
|
|
56
81
|
`disk: { read_only: true }`, as the test harnesses under `bin/` do. A
|
|
57
82
|
`.g64` goes in the true 1541, and takes out a disk mounted through the
|
|
58
83
|
traps, so `LOAD` and `SAVE` reach the 1541 too. With the 1541 in device
|
|
59
|
-
8, a `.d64` goes in its drive as well
|
|
84
|
+
8, a `.d64` goes in its drive as well, and a `.d81` in a 1581 that takes
|
|
85
|
+
the 1541's place. On a C128 in C128 mode, `attach` puts a boot disk in a
|
|
86
|
+
true drive and types nothing (`Badline::Media::BootDisk`).
|
|
60
87
|
|
|
61
88
|
`Badline::Media::DiskSet.around(path)` lists the disks of the set a disk
|
|
62
89
|
image belongs to, which the pause menu's PREVIOUS DISK and NEXT DISK step
|
data/doc/pinned-behaviour.md
CHANGED
|
@@ -26,6 +26,7 @@ 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-IIe 2 MHz and TEST bit](#vic-iie-2-mhz-and-test-bit)
|
|
29
|
+
- [C128 Z80 bus](#c128-z80-bus)
|
|
29
30
|
- [VIC-II NTSC](#vic-ii-ntsc)
|
|
30
31
|
- [VIC-II 6572 (Drean)](#vic-ii-6572-drean)
|
|
31
32
|
- [CIA 6526 timer pipeline](#cia-6526-timer-pipeline)
|
|
@@ -1001,6 +1002,35 @@ $1C0E and checks the readings they print.
|
|
|
1001
1002
|
per-cycle blanking. Their 8566 shows no grey dots. The 2mhzVIC
|
|
1002
1003
|
references have none either.
|
|
1003
1004
|
|
|
1005
|
+
## C128 Z80 bus
|
|
1006
|
+
|
|
1007
|
+
- The Z80 gets 2 T-states in every cycle BA leaves it the bus, with no
|
|
1008
|
+
wait states for memory or I/O: each of the 1,868 `c128z80timing`
|
|
1009
|
+
programs measures `T-states / 2` 1 MHz cycles with the screen blanked.
|
|
1010
|
+
Pinned by `c128/z80/c128z80timing`. The timing rows can't pin where in
|
|
1011
|
+
an I/O machine cycle the chips see an IN or OUT, since the timer starts
|
|
1012
|
+
and stops through the same OUT: `Z80Turns::IO_DELAY` is 2 because
|
|
1013
|
+
`c128modez80-23`'s IN at `$D700`, which reads open bus, passes at 1 or 2
|
|
1014
|
+
and fails at 0, 3 and 4.
|
|
1015
|
+
- In C128 mode with CR bits 6-7 both 0, `$0000-$0FFF` reads the BIOS
|
|
1016
|
+
(`$D000-$DFFF` of the KERNAL ROM), and a write, IN or OUT there reaches
|
|
1017
|
+
the RAM at `$Dxxx` of bank 0. CR `$BF` (bank 2, which is bank 0 on a
|
|
1018
|
+
128K machine) leaves the BIOS out, as does bank 1: `$0xxx` is RAM, common
|
|
1019
|
+
RAM's or the bank's. `$D000-$DFFF` is RAM to the Z80's memory accesses.
|
|
1020
|
+
Pinned by `c128modez80-15` to `-22` and `-25`, `outi/tstouti2` and
|
|
1021
|
+
`mmu_zp_sp/tstz80bk` (x128 fails the last).
|
|
1022
|
+
- IN and OUT reach the chips at `$D000-$DFFF` whatever CR's I/O bit says,
|
|
1023
|
+
in both modes. The MMU at `$D500` takes an OUT either way in C128 mode,
|
|
1024
|
+
but answers an IN only with I/O on. Pinned by `c128modez80-10` (the IN)
|
|
1025
|
+
and `tstz80bk`, which programs page relocation through OUT with CR
|
|
1026
|
+
`$BF`.
|
|
1027
|
+
- While I/O is mapped in, the colour RAM the 8502 sees also answers at
|
|
1028
|
+
`$1000-$13FF`, in memory and through IN and OUT. Pinned by
|
|
1029
|
+
`c128modez80-02` to `-09` and `c64modez80-03` and `-05`.
|
|
1030
|
+
- In C64 mode the Z80's memory accesses decode as the 8502's do through
|
|
1031
|
+
the PLA, with no BIOS. Pinned by `c64modez80-00` to `-06`.
|
|
1032
|
+
- Spec guard: [`z80_bus_spec.rb`](../spec/badline/c128/z80_bus_spec.rb).
|
|
1033
|
+
|
|
1004
1034
|
## VIC-II NTSC
|
|
1005
1035
|
|
|
1006
1036
|
The 6567R8 (`Region::NTSC`) and the 6567R56A (`Region::NTSC_OLD`) run
|
|
@@ -1507,7 +1537,7 @@ wasn't read.
|
|
|
1507
1537
|
[`mechanism_spec.rb`](../spec/badline/drive1541/mechanism_spec.rb),
|
|
1508
1538
|
and the `format/name-and-id`, `format/bam-free` and
|
|
1509
1539
|
`format/trap-readable` rows of the `drive-scenarios` suite
|
|
1510
|
-
([`drive_scenarios.rb`](../test/drive_scenarios.rb)), which read the
|
|
1540
|
+
([`drive_scenarios.rb`](../test/support/drive_scenarios.rb)), which read the
|
|
1511
1541
|
formatted disk back from its image.
|
|
1512
1542
|
- The disk turns at 300 rpm whatever bit rate VIA 2's PB5-6 select: a
|
|
1513
1543
|
turn is 200,000 drive cycles over every track and over a half track
|
data/exe/badline-ruby
CHANGED
|
@@ -39,7 +39,7 @@ if options.headless?
|
|
|
39
39
|
console = if options.player_window?
|
|
40
40
|
lambda do |input:, output:|
|
|
41
41
|
load_sdl
|
|
42
|
-
Badline::Frontend::
|
|
42
|
+
Badline::Frontend::PlayerController.new(input:, output:)
|
|
43
43
|
end
|
|
44
44
|
else
|
|
45
45
|
Badline::Audio::Console.method(:new)
|
data/lib/badline/c128/bus.rb
CHANGED
|
@@ -37,6 +37,8 @@ module Badline
|
|
|
37
37
|
include AddressBus::PLA
|
|
38
38
|
include AddressBus::ROMs
|
|
39
39
|
include MMUPages
|
|
40
|
+
include IOPages
|
|
41
|
+
include Z80Pages
|
|
40
42
|
include SavedState
|
|
41
43
|
|
|
42
44
|
# The 8502's port has seven pins. P0-P5 are the 6510's, and P6 senses
|
|
@@ -152,6 +154,7 @@ module Badline
|
|
|
152
154
|
|
|
153
155
|
@color_lines = ColorLines.new(@vic, @cia2, character_rom, @c128_character_rom)
|
|
154
156
|
@color_ram = @color_lines.color_ram(1)
|
|
157
|
+
build_z80_pages
|
|
155
158
|
@vic_writes = VICWrites.new(@vic, @control_ports)
|
|
156
159
|
@open_bus = AddressBus::OpenBus.new(@vic)
|
|
157
160
|
@configuration_reads = ConfigurationPage.new(@mmu, @open_bus)
|
|
@@ -318,6 +321,7 @@ module Badline
|
|
|
318
321
|
romh: @cartridge&.romh)
|
|
319
322
|
@color_ram = @color_lines.cpu_color_ram(c64_mode, port)
|
|
320
323
|
c64_mode ? map_pla_pages : map_c128_pages
|
|
324
|
+
update_z80!
|
|
321
325
|
mode_changed if c64_mode != @c64_mode
|
|
322
326
|
end
|
|
323
327
|
|
|
@@ -325,23 +329,6 @@ module Badline
|
|
|
325
329
|
@c64_mode = !@c64_mode
|
|
326
330
|
@on_mode_change&.call
|
|
327
331
|
end
|
|
328
|
-
|
|
329
|
-
def map_io_pages
|
|
330
|
-
@io_mapped = true
|
|
331
|
-
@read_pages.fill(@vic, 0xd0, 4)
|
|
332
|
-
@write_pages.fill(@vic_writes, 0xd0, 4)
|
|
333
|
-
@read_pages[0xd4] = @write_pages[0xd4] = @sid
|
|
334
|
-
@read_pages[0xd5] = @write_pages[0xd5] = @mmu.c64_mode? ? @open_bus : @mmu
|
|
335
|
-
@read_pages[0xd6] = @write_pages[0xd6] = @vdc
|
|
336
|
-
@read_pages[0xd7] = @write_pages[0xd7] = @debug_page || @open_bus
|
|
337
|
-
@read_pages.fill(@color_ram, 0xd8, 4)
|
|
338
|
-
@write_pages.fill(@color_ram, 0xd8, 4)
|
|
339
|
-
@read_pages[0xdc] = @write_pages[0xdc] = @cia1
|
|
340
|
-
@read_pages[0xdd] = @write_pages[0xdd] = @cia2
|
|
341
|
-
@read_pages.fill(@open_bus, 0xde, 2)
|
|
342
|
-
@write_pages.fill(@open_bus, 0xde, 2)
|
|
343
|
-
map_cartridge_io if @cartridge
|
|
344
|
-
end
|
|
345
332
|
end
|
|
346
333
|
end
|
|
347
334
|
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class C128
|
|
5
|
+
# The true drives on the C128's serial bus: a Drive1541, the C128D's
|
|
6
|
+
# built-in 1571 (Drive1571) or a 1581 (Drive1581::Slot), each in a
|
|
7
|
+
# field of its own, so none makes another's per-cycle call a union.
|
|
8
|
+
module Drives
|
|
9
|
+
attr_reader :drive1571
|
|
10
|
+
|
|
11
|
+
# Plugs in a Drive1571, which then runs alongside the C128 on its own
|
|
12
|
+
# clock and talks to it over the serial bus, as attach_drive1541 does
|
|
13
|
+
# for a 1541.
|
|
14
|
+
def attach_drive1571(drive)
|
|
15
|
+
@iec_bus.detach(@drive1571) if @drive1571
|
|
16
|
+
drive.host_clock_hz = region.clock_hz
|
|
17
|
+
@drive1571 = drive
|
|
18
|
+
drive.connect(iec_bus)
|
|
19
|
+
@serial_trap&.device = serial_trap_device
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Unplugs the Drive1571.
|
|
23
|
+
def detach_drive1571
|
|
24
|
+
return unless @drive1571
|
|
25
|
+
|
|
26
|
+
@iec_bus.detach(@drive1571)
|
|
27
|
+
@drive1571 = nil
|
|
28
|
+
@serial_trap&.device = serial_trap_device
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# The true drive on the bus, a 1581 ahead of the 1571 ahead of a 1541.
|
|
32
|
+
def true_drive = @drive1581 || @drive1571 || @drive1541
|
|
33
|
+
|
|
34
|
+
# Plugs in the C128D's 1571 as device 8, in place of a 1581 there, and
|
|
35
|
+
# returns it.
|
|
36
|
+
def plug_true_drive
|
|
37
|
+
detach_drive1581 if drive1581_on_device8?
|
|
38
|
+
Drive1571.new.tap { |drive| attach_drive1571(drive) }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
# The serial bus, with no disk in device 8's traps and no true drive.
|
|
44
|
+
def init_drives
|
|
45
|
+
@drive = nil
|
|
46
|
+
@serial_trap = nil
|
|
47
|
+
@save_trap = nil
|
|
48
|
+
@drive1541 = nil
|
|
49
|
+
@drive1571 = nil
|
|
50
|
+
@drive1581 = nil
|
|
51
|
+
plug_serial_bus
|
|
52
|
+
plug_fast_serial
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Device 8, unless a true drive is on the bus as device 8.
|
|
56
|
+
def serial_trap_device
|
|
57
|
+
device = KernalTrap::Routine::DEVICE
|
|
58
|
+
@drive1571&.device == device || @drive1541&.device == device || drive1581_on_device8? ? nil : device
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# A 1581 plugged in holds the machine's on_init handlers back until
|
|
62
|
+
# its DOS has booted, which takes longer than the C128 KERNAL's.
|
|
63
|
+
def drive1581_attached
|
|
64
|
+
@init_threshold = [@init_threshold, Drive1581::BOOT_CYCLES].max if @cycles < @init_threshold
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Unplugs the 1541 and the 1571 if either is device 8, for a 1581 to
|
|
68
|
+
# take its place.
|
|
69
|
+
def unplug_device8
|
|
70
|
+
device = KernalTrap::Routine::DEVICE
|
|
71
|
+
detach_drive1541 if @drive1541&.device == device
|
|
72
|
+
detach_drive1571 if @drive1571&.device == device
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# A true 1541 (Computer::Attachments#save_serial_bus), then a 1571 and
|
|
76
|
+
# a 1581.
|
|
77
|
+
def save_serial_bus(out)
|
|
78
|
+
out.boolean(true).boolean(!@drive1541.nil?)
|
|
79
|
+
if @drive1541
|
|
80
|
+
out.int(@drive1541.device)
|
|
81
|
+
@drive1541.save_state(out)
|
|
82
|
+
end
|
|
83
|
+
out.boolean(!@drive1571.nil?)
|
|
84
|
+
if @drive1571
|
|
85
|
+
out.int(@drive1571.device)
|
|
86
|
+
@drive1571.save_state(out)
|
|
87
|
+
end
|
|
88
|
+
save_drive1581(out)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def load_serial_bus(input)
|
|
92
|
+
input.boolean?
|
|
93
|
+
load_drive1541(input)
|
|
94
|
+
load_drive1571(input)
|
|
95
|
+
load_drive1581(input)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def load_drive1571(input)
|
|
99
|
+
return detach_drive1571 unless input.boolean?
|
|
100
|
+
|
|
101
|
+
device = input.int
|
|
102
|
+
detach_drive1571 if @drive1571 && @drive1571.device != device
|
|
103
|
+
attach_drive1571(Drive1571.new(device:)) unless @drive1571
|
|
104
|
+
@drive1571.load_state(input)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class C128
|
|
5
|
+
# Fast serial: CIA 1's CNT and SP on the serial bus's SRQ and DATA,
|
|
6
|
+
# through buffers MCR's FSDIR turns round. Outwards, the machine pushes
|
|
7
|
+
# the lines the pins pull into the bus as they move. Inwards, CIA 1
|
|
8
|
+
# hears the lines whenever a drive moves its own fast serial pins
|
|
9
|
+
# (IECBus#on_fast_change).
|
|
10
|
+
module FastSerial
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
def plug_fast_serial
|
|
14
|
+
@fast_serial_out = false
|
|
15
|
+
@bus.mmu.on_fast_serial_change { turn_fast_serial }
|
|
16
|
+
@iec_bus.on_fast_change { hear_fast_serial unless @fast_serial_out }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# The machine's side of the serial bus each cycle: CIA 1's pins
|
|
20
|
+
# pushed while FSDIR has them out, then the drives.
|
|
21
|
+
def clock_serial_bus
|
|
22
|
+
drive_fast_serial if @fast_serial_out
|
|
23
|
+
@drive1541&.host_cycle!
|
|
24
|
+
@drive1571&.host_cycle!
|
|
25
|
+
@drive1581&.host_cycle!
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def turn_fast_serial
|
|
29
|
+
push_fast_serial
|
|
30
|
+
hear_fast_serial unless @fast_serial_out
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Pushes the lines CIA 1's pins pull while FSDIR has them out. A
|
|
34
|
+
# restored machine pushes them again, its CIA 1 hearing the lines as
|
|
35
|
+
# it last did.
|
|
36
|
+
def push_fast_serial
|
|
37
|
+
@fast_serial_out = @bus.mmu.fast_serial_out?
|
|
38
|
+
@iec_bus.host_fast_lines = @fast_serial_out ? fast_pins : 0
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def drive_fast_serial
|
|
42
|
+
@iec_bus.host_fast_lines = fast_pins
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# The lines CIA 1's CNT and SP pull while its serial port drives
|
|
46
|
+
# them.
|
|
47
|
+
def fast_pins
|
|
48
|
+
serial = @cia1.serial
|
|
49
|
+
return 0 unless serial.output?
|
|
50
|
+
|
|
51
|
+
low = serial.cnt ? 0 : IECBus::SRQ
|
|
52
|
+
serial.sp_out ? low : low | IECBus::DATA
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def hear_fast_serial
|
|
56
|
+
low = @iec_bus.low_lines
|
|
57
|
+
serial = @cia1.serial
|
|
58
|
+
serial.cnt_in = low.nobits?(IECBus::SRQ)
|
|
59
|
+
serial.sp_in = low.nobits?(IECBus::DATA)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class C128
|
|
5
|
+
class Bus
|
|
6
|
+
# The chips at $D000-$DFFF, which the 8502 sees while I/O is mapped
|
|
7
|
+
# in and the Z80 reaches through IN and OUT.
|
|
8
|
+
module IOPages
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def map_io_pages
|
|
12
|
+
@io_mapped = true
|
|
13
|
+
lay_out_io(@read_pages, @write_pages)
|
|
14
|
+
@read_pages[0xd5] = @write_pages[0xd5] = @mmu.c64_mode? ? @open_bus : @mmu
|
|
15
|
+
map_cartridge_io if @cartridge
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# The chips into +reads+ and +writes+, but for the MMU's page.
|
|
19
|
+
def lay_out_io(reads, writes)
|
|
20
|
+
reads.fill(@vic, 0xd0, 4)
|
|
21
|
+
writes.fill(@vic_writes, 0xd0, 4)
|
|
22
|
+
reads[0xd4] = writes[0xd4] = @sid
|
|
23
|
+
reads[0xd6] = writes[0xd6] = @vdc
|
|
24
|
+
reads[0xd7] = writes[0xd7] = @debug_page || @open_bus
|
|
25
|
+
reads.fill(@color_ram, 0xd8, 4)
|
|
26
|
+
writes.fill(@color_ram, 0xd8, 4)
|
|
27
|
+
reads[0xdc] = writes[0xdc] = @cia1
|
|
28
|
+
reads[0xdd] = writes[0xdd] = @cia2
|
|
29
|
+
reads.fill(@open_bus, 0xde, 2)
|
|
30
|
+
writes.fill(@open_bus, 0xde, 2)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
data/lib/badline/c128/mmu.rb
CHANGED
|
@@ -19,12 +19,11 @@ module Badline
|
|
|
19
19
|
# A write to P0H or P1H waits until the matching P0L or P1L write
|
|
20
20
|
# takes it.
|
|
21
21
|
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# force.
|
|
22
|
+
# A reset clears MCR bit 0, so the Z80 runs first, boots and hands the
|
|
23
|
+
# bus to the 8502. A machine built for C64 mode resets into C64 mode
|
|
24
|
+
# instead, with the 8502 running, the state the C128 KERNAL leaves when
|
|
25
|
+
# C= is held at power-on. In C64 mode the MMU answers nowhere, but the
|
|
26
|
+
# CPU's RAM bank, common RAM and the VIC's bank it holds stay in force.
|
|
28
27
|
class MMU
|
|
29
28
|
CR = 0
|
|
30
29
|
MCR = 5
|
|
@@ -36,6 +35,7 @@ module Badline
|
|
|
36
35
|
VR = 11
|
|
37
36
|
|
|
38
37
|
MCR_8502 = 0x01
|
|
38
|
+
MCR_FSDIR = 0x08
|
|
39
39
|
MCR_C64_MODE = 0x40
|
|
40
40
|
VERSION = 0x20
|
|
41
41
|
|
|
@@ -68,6 +68,7 @@ module Badline
|
|
|
68
68
|
@game = 1
|
|
69
69
|
@exrom = 1
|
|
70
70
|
@on_change = nil
|
|
71
|
+
@on_fast_serial_change = nil
|
|
71
72
|
reset!
|
|
72
73
|
end
|
|
73
74
|
|
|
@@ -76,18 +77,32 @@ module Badline
|
|
|
76
77
|
@on_change = block
|
|
77
78
|
end
|
|
78
79
|
|
|
80
|
+
# Calls the block whenever FSDIR turns the fast serial buffers round.
|
|
81
|
+
def on_fast_serial_change(&block)
|
|
82
|
+
@on_fast_serial_change = block
|
|
83
|
+
end
|
|
84
|
+
|
|
79
85
|
def reset!
|
|
86
|
+
fast_serial_out = fast_serial_out?
|
|
80
87
|
@registers.fill(0)
|
|
81
|
-
@registers[MCR] = @reset_mode == :c64 ? MCR_C64_MODE | MCR_8502 :
|
|
88
|
+
@registers[MCR] = @reset_mode == :c64 ? MCR_C64_MODE | MCR_8502 : 0
|
|
82
89
|
@registers[P1L] = 0x01
|
|
83
90
|
@registers[VR] = VERSION
|
|
84
91
|
@p0h_latch = 0
|
|
85
92
|
@p1h_latch = 0
|
|
86
93
|
@on_change&.call
|
|
94
|
+
@on_fast_serial_change&.call if fast_serial_out
|
|
87
95
|
end
|
|
88
96
|
|
|
89
97
|
def c64_mode? = @registers[MCR].anybits?(MCR_C64_MODE)
|
|
90
98
|
|
|
99
|
+
# Whether MCR bit 3, FSDIR, turns the fast serial buffers outwards, so
|
|
100
|
+
# CIA 1's CNT and SP drive SRQ and DATA.
|
|
101
|
+
def fast_serial_out? = @registers[MCR].anybits?(MCR_FSDIR)
|
|
102
|
+
|
|
103
|
+
# Whether MCR bit 0 gives the bus to the Z80.
|
|
104
|
+
def z80? = @registers[MCR].nobits?(MCR_8502)
|
|
105
|
+
|
|
91
106
|
# :c64 or :c128, the mode MCR bit 6 selects.
|
|
92
107
|
def mode = c64_mode? ? :c64 : :c128
|
|
93
108
|
|
|
@@ -174,8 +189,10 @@ module Badline
|
|
|
174
189
|
end
|
|
175
190
|
|
|
176
191
|
def write(offset, value)
|
|
192
|
+
fast_serial_out = fast_serial_out?
|
|
177
193
|
@registers[offset] = value
|
|
178
194
|
@on_change&.call
|
|
195
|
+
@on_fast_serial_change&.call if fast_serial_out? != fast_serial_out
|
|
179
196
|
end
|
|
180
197
|
end
|
|
181
198
|
end
|