badline 0.9.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -0
- data/CLAUDE.md +6 -4
- data/README.md +39 -4
- data/doc/pinned-behaviour.md +146 -0
- data/doc/snapshots.md +13 -0
- data/lib/badline/address_bus/pla.rb +130 -0
- data/lib/badline/address_bus.rb +9 -88
- data/lib/badline/chrout_trap.rb +4 -3
- data/lib/badline/computer/attachments.rb +47 -7
- data/lib/badline/computer/saved_state.rb +1 -0
- data/lib/badline/computer.rb +44 -29
- data/lib/badline/control_ports.rb +10 -3
- data/lib/badline/core.rb +3 -0
- data/lib/badline/datasette.rb +39 -1
- data/lib/badline/drive1541/serial_port.rb +5 -8
- data/lib/badline/drive1541/sleep.rb +5 -6
- data/lib/badline/drive1541.rb +3 -3
- data/lib/badline/frontend/app.rb +62 -64
- data/lib/badline/frontend/boot.rb +33 -8
- data/lib/badline/frontend/controls.rb +12 -6
- data/lib/badline/frontend/drive_led.rb +9 -10
- data/lib/badline/frontend/frame_rate.rb +4 -4
- data/lib/badline/frontend/machine_window.rb +87 -0
- data/lib/badline/frontend/menu_media.rb +49 -24
- data/lib/badline/frontend/menu_pages.rb +23 -40
- data/lib/badline/frontend/menu_ports.rb +69 -0
- data/lib/badline/frontend/pacer.rb +6 -5
- data/lib/badline/frontend/pause_menu.rb +30 -33
- data/lib/badline/frontend/player_screen.rb +1 -1
- data/lib/badline/frontend/player_window.rb +1 -1
- data/lib/badline/frontend/screen.rb +39 -37
- data/lib/badline/frontend/sid_view.rb +1 -1
- data/lib/badline/frontend/sound.rb +11 -9
- data/lib/badline/frontend/timeline.rb +36 -5
- data/lib/badline/frontend.rb +2 -0
- data/lib/badline/iec_bus.rb +16 -28
- data/lib/badline/kernal_trap/drive.rb +3 -0
- data/lib/badline/kernal_trap/file.rb +1 -1
- data/lib/badline/kernal_trap/layout.rb +112 -0
- data/lib/badline/kernal_trap/load.rb +16 -27
- data/lib/badline/kernal_trap/routine.rb +11 -27
- data/lib/badline/kernal_trap/save.rb +13 -23
- data/lib/badline/kernal_trap/serial.rb +21 -19
- data/lib/badline/kernal_trap.rb +1 -0
- data/lib/badline/keyboard.rb +17 -14
- data/lib/badline/machine.rb +60 -0
- data/lib/badline/media/vic20_basic.rb +54 -0
- data/lib/badline/media/vic20_cartridge.rb +74 -0
- data/lib/badline/media/vic20_media.rb +132 -0
- data/lib/badline/media.rb +32 -18
- data/lib/badline/options/event.rb +5 -3
- data/lib/badline/options/help.rb +11 -3
- data/lib/badline/options/table.rb +11 -1
- data/lib/badline/options/validation.rb +55 -4
- data/lib/badline/options.rb +33 -33
- data/lib/badline/roms/README +27 -0
- data/lib/badline/roms/vic20/basic.rom +0 -0
- data/lib/badline/roms/vic20/character.rom +0 -0
- data/lib/badline/roms/vic20/kernal-ntsc.rom +0 -0
- data/lib/badline/roms/vic20/kernal-pal.rom +0 -0
- data/lib/badline/snapshot/container.rb +2 -0
- data/lib/badline/snapshot/image.rb +15 -0
- data/lib/badline/snapshot/state.rb +4 -3
- data/lib/badline/snapshot.rb +10 -0
- data/lib/badline/storage/crt_file.rb +16 -5
- data/lib/badline/storage/disk_image.rb +3 -0
- data/lib/badline/storage/host_directory.rb +3 -0
- data/lib/badline/storage/t64.rb +3 -0
- data/lib/badline/storage/tap.rb +38 -4
- data/lib/badline/storage/unavailable.rb +2 -0
- data/lib/badline/timing.rb +12 -0
- data/lib/badline/version.rb +1 -1
- data/lib/badline/via/shift_register.rb +43 -16
- data/lib/badline/vic/bank.rb +53 -16
- data/lib/badline/vic/registers.rb +20 -4
- data/lib/badline/vic.rb +34 -15
- data/lib/badline/vic20/attachments.rb +103 -0
- data/lib/badline/vic20/bus.rb +308 -0
- data/lib/badline/vic20/cpu.rb +10 -0
- data/lib/badline/vic20/keyboard_via_ports.rb +53 -0
- data/lib/badline/vic20/port_wiring.rb +50 -0
- data/lib/badline/vic20/saved_state.rb +152 -0
- data/lib/badline/vic20/sound/output.rb +83 -0
- data/lib/badline/vic20/sound.rb +233 -0
- data/lib/badline/vic20/user_via_ports.rb +47 -0
- data/lib/badline/vic20/vic/painter.rb +239 -0
- data/lib/badline/vic20/vic/saved_state.rb +55 -0
- data/lib/badline/vic20/vic/text_window.rb +71 -0
- data/lib/badline/vic20/vic.rb +267 -0
- data/lib/badline/vic20.rb +220 -0
- metadata +28 -2
- 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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bd764dccd3b8af3f8e0dcbb7d17debc3fceb24a9899f80871ebbf184ffefd65b
|
|
4
|
+
data.tar.gz: 46a62d801813476242a407c09ab3ff4fec1126d10bfee134047f18e90fd86955
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 82a62fb4a3de3ef65e123bacf22ba300efe628f1bde38815dc950a39034d8c2b9423de79b3805fce84e19bcbaa8100a3e67488d5ef0a3ecb2de6434689886883
|
|
7
|
+
data.tar.gz: 595b19f034d708db60089e707507e74281059d271527fe61e0a205d9e8e0853a4f6b4d077aeed648f59a86d06bf31d3ee6e5902345fdb52d5fb36ded8de94da3
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
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
|
+
|
|
3
32
|
## [0.9.0](https://github.com/elektronaut/badline/compare/v0.8.0...v0.9.0) (2026-10-05)
|
|
4
33
|
|
|
5
34
|
|
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`,
|
|
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
|
|
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)
|
|
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>`)
|
|
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
|
+

|
|
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.
|
|
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,9 @@ 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
|
-
| `--model NAME` | Run another
|
|
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 |
|
|
82
89
|
| `--ntsc` | Run an NTSC C64, as `--model ntsc` does |
|
|
83
90
|
| `--no-sound` | Don't play the SID (`badline` only, where sound is on by default) |
|
|
84
91
|
| `--sound` | Play the SID (`badline-ruby`, where sound is off by default) |
|
|
@@ -94,7 +101,7 @@ differences noted in the table. `--help` lists the options for either.
|
|
|
94
101
|
| --- | --- |
|
|
95
102
|
| `--frames N` | Quit after N frames |
|
|
96
103
|
| `--unpaced` | Run as fast as it can, without vsync or pacing |
|
|
97
|
-
| `--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 |
|
|
98
105
|
| `--script FILE` | Run the events in `FILE`, one `FRAME:EVENT` a line |
|
|
99
106
|
| `--screenshot FILE` | Save the last frame as a `.bmp` |
|
|
100
107
|
| `--save-snapshot FILE` | Save the machine as a `.vsf` snapshot after the last frame |
|
|
@@ -134,6 +141,28 @@ red LED lights in the bottom right corner of the border.
|
|
|
134
141
|
[doc/media.md](doc/media.md) has the details, and how to attach media
|
|
135
142
|
from Ruby.
|
|
136
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
|
+
|
|
137
166
|
## Snapshots
|
|
138
167
|
|
|
139
168
|
`F11` quicksaves the whole machine to the next of five slots in
|
|
@@ -219,6 +248,8 @@ through the rows, Right goes into a page and Left back out, and Return or
|
|
|
219
248
|
Space presses a row. A row with choices steps to the next. The mouse works
|
|
220
249
|
too.
|
|
221
250
|
|
|
251
|
+

|
|
252
|
+
|
|
222
253
|
| Page | What it holds |
|
|
223
254
|
|------|---------------|
|
|
224
255
|
| Snapshots | Quicksave, save under a name, load a named save, and the latest quicksaves and autosaves |
|
|
@@ -259,6 +290,10 @@ program or `.sid` dropped on it opens the menu to ask first.
|
|
|
259
290
|
- **REU**: the 1700, 1764 and 1750 and bigger units up to 16M
|
|
260
291
|
(`--reu`), with DMA timed against the VIC's bad lines and sprites.
|
|
261
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`).
|
|
262
297
|
- **1541**: an emulated drive running its own DOS (`--true-drive`).
|
|
263
298
|
- **Cartridges**: standard 8K, 16K and Ultimax, Simons' BASIC, Ocean,
|
|
264
299
|
Fun Play / Power Play, Super Games, Epyx FastLoad, Westermann
|
data/doc/pinned-behaviour.md
CHANGED
|
@@ -30,8 +30,12 @@ only catches the rows that happen to move.
|
|
|
30
30
|
- [CIA 6526 timer pipeline](#cia-6526-timer-pipeline)
|
|
31
31
|
- [CIA 6526A interrupt register](#cia-6526a-interrupt-register)
|
|
32
32
|
- [CIA serial shift register](#cia-serial-shift-register)
|
|
33
|
+
- [VIA shift register](#via-shift-register)
|
|
33
34
|
- [6510 I/O port](#6510-io-port)
|
|
34
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)
|
|
35
39
|
- [1541 serial port](#1541-serial-port)
|
|
36
40
|
- [1541 disk mechanism](#1541-disk-mechanism)
|
|
37
41
|
- [REU DMA](#reu-dma)
|
|
@@ -1196,6 +1200,43 @@ and each was knocked out: removing it fails the rows named.
|
|
|
1196
1200
|
[`cia_spec.rb`](../spec/badline/cia_spec.rb) covers the flag timing, the
|
|
1197
1201
|
waiting byte, both mode-change reports and the zero-latch stall.
|
|
1198
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
|
+
|
|
1199
1240
|
## 6510 I/O port
|
|
1200
1241
|
|
|
1201
1242
|
- DDR at `$00`/`$01`: inputs are pulled up, bit 5 reads low, and bits 3, 6
|
|
@@ -1239,6 +1280,111 @@ and each was knocked out: removing it fails the rows named.
|
|
|
1239
1280
|
[`address_bus_spec.rb`](../spec/badline/address_bus_spec.rb).
|
|
1240
1281
|
- The RAM expansions' extra banks still power on at `$00`.
|
|
1241
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
|
+
|
|
1242
1388
|
## 1541 serial port
|
|
1243
1389
|
|
|
1244
1390
|
- The drive sees the C64's side of the serial bus a host cycle late. The
|
data/doc/snapshots.md
CHANGED
|
@@ -66,6 +66,19 @@ expansion, REU, KERNAL and datasette. One saved before badline recorded
|
|
|
66
66
|
the KERNAL and the datasette restores as a machine with the C64's KERNAL
|
|
67
67
|
and a datasette.
|
|
68
68
|
|
|
69
|
+
## The VIC-20
|
|
70
|
+
|
|
71
|
+
`badline vic20` saves and restores the same way, with the same keys,
|
|
72
|
+
slots and pause menu page. A VIC-20 snapshot holds its RAM and colour
|
|
73
|
+
RAM, a cartridge's ROM, the VIC with its picture and sound, both VIAs,
|
|
74
|
+
the CPU, the tape with its place on it, the disk or directory device 8
|
|
75
|
+
serves through the traps and a true 1541, and restores into a VIC-20
|
|
76
|
+
with the same RAM expansion. Its file names its machine `VIC20`, as
|
|
77
|
+
xvic's do, and holds only the `BADLINE` module, so xvic doesn't open
|
|
78
|
+
it, and badline doesn't open xvic's. Restoring a
|
|
79
|
+
VIC-20 snapshot while a C64 runs, or a C64 one while a VIC-20 runs,
|
|
80
|
+
swaps the machine in the window.
|
|
81
|
+
|
|
69
82
|
## VICE
|
|
70
83
|
|
|
71
84
|
Snapshots use VICE's `.vsf` format. badline writes VICE's modules for
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class AddressBus
|
|
5
|
+
# The C64's PLA: what each page of the CPU's view maps to, from the
|
|
6
|
+
# CPU port's LORAM, HIRAM and CHAREN lines and the cartridge's EXROM
|
|
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.
|
|
10
|
+
module PLA
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
def map_pla_pages
|
|
14
|
+
map_ram_pages
|
|
15
|
+
@ultimax ? map_ultimax_pages : map_banked_pages
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def map_banked_pages
|
|
19
|
+
map_rom_overlays
|
|
20
|
+
map_cartridge_ram
|
|
21
|
+
@write_pages.fill(@cartridge.romh_writes, 0xe0, 0x20) if @cartridge&.romh_writes
|
|
22
|
+
|
|
23
|
+
if io?
|
|
24
|
+
map_io_pages
|
|
25
|
+
elsif character?
|
|
26
|
+
@read_pages.fill(character_rom, 0xd0, 0x10)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Ultimax cartridges ignore the $01 lines: 4K of RAM, ROML/ROMH windows,
|
|
31
|
+
# I/O always visible and open address space everywhere else. The ROML
|
|
32
|
+
# and ROMH selects fire on writes as well, so cartridge RAM or flash in
|
|
33
|
+
# either window takes the writes there.
|
|
34
|
+
def map_ultimax_pages
|
|
35
|
+
@read_pages.fill(@open_bus, 0x10, 0xf0)
|
|
36
|
+
@write_pages.fill(@open_bus, 0x10, 0xf0)
|
|
37
|
+
@read_pages.fill(@cartridge.roml, 0x80, 0x20) if @cartridge.roml
|
|
38
|
+
map_ultimax_writes(@cartridge.roml, 0x80)
|
|
39
|
+
@read_pages.fill(@cartridge.romh, 0xe0, 0x20) if @cartridge.romh
|
|
40
|
+
map_ultimax_writes(@cartridge.romh, 0xe0)
|
|
41
|
+
map_ultimax_a000
|
|
42
|
+
map_io_pages
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def map_ultimax_writes(bank, first_page)
|
|
46
|
+
@write_pages.fill(bank, first_page, 0x20) if bank.respond_to?(:poke)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def map_ultimax_a000
|
|
50
|
+
return unless (window = @cartridge.ultimax_a000)
|
|
51
|
+
|
|
52
|
+
@read_pages.fill(window, 0xa0, 0x20)
|
|
53
|
+
@write_pages.fill(window, 0xa0, 0x20)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# EXROM and GAME select the cartridge whether or not it has a chip
|
|
57
|
+
# there, and an empty socket leaves the bus floating.
|
|
58
|
+
def map_rom_overlays
|
|
59
|
+
@read_pages.fill(@cartridge.roml || @open_bus, 0x80, 0x20) if roml?
|
|
60
|
+
if romh?
|
|
61
|
+
@read_pages.fill(@cartridge.romh || @open_bus, 0xa0, 0x20)
|
|
62
|
+
elsif basic?
|
|
63
|
+
@read_pages.fill(basic_rom, 0xa0, 0x20)
|
|
64
|
+
end
|
|
65
|
+
@read_pages.fill(kernal_rom, 0xe0, 0x20) if kernal?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Cartridge RAM in the ROML or ROMH window decodes writes itself,
|
|
69
|
+
# whatever the $01 lines say.
|
|
70
|
+
def map_cartridge_ram
|
|
71
|
+
return unless @cartridge&.exrom&.zero?
|
|
72
|
+
|
|
73
|
+
map_cartridge_ram_bank(@cartridge.roml, 0x80)
|
|
74
|
+
map_cartridge_ram_bank(@cartridge.romh, 0xa0) if @cartridge.game.zero?
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def map_cartridge_ram_bank(bank, first_page)
|
|
78
|
+
@write_pages.fill(bank, first_page, 0x20) if bank.is_a?(Cartridge::RAMBank)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def map_io_pages
|
|
82
|
+
{
|
|
83
|
+
vic => 0xd0..0xd3, sid => 0xd4..0xd7, color_ram => 0xd8..0xdb,
|
|
84
|
+
cia1 => 0xdc..0xdc, cia2 => 0xdd..0xdd, @open_bus => 0xde..0xdf
|
|
85
|
+
}.each do |chip, pages|
|
|
86
|
+
pages.each { |p| @read_pages[p] = @write_pages[p] = chip }
|
|
87
|
+
end
|
|
88
|
+
@ram_expansion.map_io(@read_pages, @write_pages)
|
|
89
|
+
@read_pages[0xd7] = @write_pages[0xd7] = @debug_register if @debug_register
|
|
90
|
+
@read_pages[0xdf] = @write_pages[0xdf] = @reu if @reu
|
|
91
|
+
map_cartridge_io if @cartridge
|
|
92
|
+
map_extra_sids unless @sid_slots.empty?
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def map_cartridge_io
|
|
96
|
+
@write_pages.fill(@cartridge, 0xde, 2)
|
|
97
|
+
@cartridge.readable_io_pages.each { |p| @read_pages[p] = @cartridge }
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def basic?
|
|
101
|
+
io_port.kernal? && io_port.basic? && game_high?
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def game_high?
|
|
105
|
+
@cartridge.nil? || @cartridge.game == 1
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def roml?
|
|
109
|
+
@cartridge&.exrom&.zero? && io_port.kernal? && io_port.basic?
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def romh?
|
|
113
|
+
@cartridge&.exrom&.zero? && @cartridge.game.zero? && io_port.kernal?
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# In 16K mode LORAM alone leaves $d000 as RAM, where it still maps I/O.
|
|
117
|
+
def character?
|
|
118
|
+
(io_port.kernal? || (io_port.basic? && game_high?)) && !io_port.io?
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def io?
|
|
122
|
+
(io_port.basic? || io_port.kernal?) && io_port.io?
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def kernal?
|
|
126
|
+
io_port.kernal?
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
data/lib/badline/address_bus.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require "badline/address_bus/saved_state"
|
|
4
4
|
require "badline/address_bus/sid_slots"
|
|
5
5
|
require "badline/address_bus/extra_sids"
|
|
6
|
-
require "badline/address_bus/
|
|
6
|
+
require "badline/address_bus/pla"
|
|
7
7
|
require "badline/address_bus/roms"
|
|
8
8
|
|
|
9
9
|
module Badline
|
|
@@ -34,7 +34,7 @@ module Badline
|
|
|
34
34
|
# 0xE000-0xFFFF - KERNAL ROM / Cartridge ROM (high) - 8kb
|
|
35
35
|
class AddressBus
|
|
36
36
|
include Addressable
|
|
37
|
-
include
|
|
37
|
+
include PLA
|
|
38
38
|
include ExtraSIDs
|
|
39
39
|
include ROMs
|
|
40
40
|
|
|
@@ -79,7 +79,7 @@ module Badline
|
|
|
79
79
|
@joystick1 = Joystick.new
|
|
80
80
|
@joystick2 = Joystick.new
|
|
81
81
|
@control_ports = ControlPorts.new(keyboard: @keyboard, joystick1: @joystick1, joystick2: @joystick2)
|
|
82
|
-
@vic = VIC.new(
|
|
82
|
+
@vic = VIC.new(model: vic_model, region:)
|
|
83
83
|
@cia1 = CIA.new(start: 0xdc00, peripheral: @control_ports, model: cia_model, region:)
|
|
84
84
|
@cia2 = CIA.new(start: 0xdd00, model: cia_model, region:)
|
|
85
85
|
@control_ports.port_a_source = @cia1
|
|
@@ -92,6 +92,8 @@ module Badline
|
|
|
92
92
|
@datasette.on_sense_change { @io_port.value = port_value }
|
|
93
93
|
|
|
94
94
|
@color_ram = ColorMemory.new(@vic)
|
|
95
|
+
@vic.vic_bank.connect(cia2: @cia2, color_ram: @color_ram)
|
|
96
|
+
@vic.vic_bank.map_character_rom(character_rom)
|
|
95
97
|
@open_bus = OpenBus.new(@vic)
|
|
96
98
|
@cpu_off_bus = false
|
|
97
99
|
|
|
@@ -201,96 +203,15 @@ module Badline
|
|
|
201
203
|
def update_overlays!
|
|
202
204
|
@ultimax = @cartridge ? @cartridge.ultimax? : false
|
|
203
205
|
@phi1_ultimax = @cartridge ? @cartridge.phi1_ultimax? : false
|
|
204
|
-
@ram_expansion.map(@read_pages, @write_pages)
|
|
205
206
|
@video_ram = @ram_expansion.video_ram
|
|
207
|
+
@vic.vic_bank.map(@video_ram, phi1_ultimax: @phi1_ultimax, ultimax: @ultimax, romh: @cartridge&.romh)
|
|
206
208
|
|
|
207
|
-
|
|
209
|
+
map_pla_pages
|
|
208
210
|
@write_pages[0xff] = @reu.trigger.wrap(@write_pages[0xff]) if @reu
|
|
209
211
|
end
|
|
210
212
|
|
|
211
|
-
def
|
|
212
|
-
|
|
213
|
-
map_cartridge_ram
|
|
214
|
-
@write_pages.fill(@cartridge.romh_writes, 0xe0, 0x20) if @cartridge&.romh_writes
|
|
215
|
-
|
|
216
|
-
if io?
|
|
217
|
-
map_io_pages
|
|
218
|
-
elsif character?
|
|
219
|
-
@read_pages.fill(character_rom, 0xd0, 0x10)
|
|
220
|
-
end
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
# EXROM and GAME select the cartridge whether or not it has a chip
|
|
224
|
-
# there, and an empty socket leaves the bus floating.
|
|
225
|
-
def map_rom_overlays
|
|
226
|
-
@read_pages.fill(@cartridge.roml || @open_bus, 0x80, 0x20) if roml?
|
|
227
|
-
if romh?
|
|
228
|
-
@read_pages.fill(@cartridge.romh || @open_bus, 0xa0, 0x20)
|
|
229
|
-
elsif basic?
|
|
230
|
-
@read_pages.fill(basic_rom, 0xa0, 0x20)
|
|
231
|
-
end
|
|
232
|
-
@read_pages.fill(kernal_rom, 0xe0, 0x20) if kernal?
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
# Cartridge RAM in the ROML or ROMH window decodes writes itself,
|
|
236
|
-
# whatever the $01 lines say.
|
|
237
|
-
def map_cartridge_ram
|
|
238
|
-
return unless @cartridge&.exrom&.zero?
|
|
239
|
-
|
|
240
|
-
map_cartridge_ram_bank(@cartridge.roml, 0x80)
|
|
241
|
-
map_cartridge_ram_bank(@cartridge.romh, 0xa0) if @cartridge.game.zero?
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
def map_cartridge_ram_bank(bank, first_page)
|
|
245
|
-
@write_pages.fill(bank, first_page, 0x20) if bank.is_a?(Cartridge::RAMBank)
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
def map_io_pages
|
|
249
|
-
{
|
|
250
|
-
vic => 0xd0..0xd3, sid => 0xd4..0xd7, color_ram => 0xd8..0xdb,
|
|
251
|
-
cia1 => 0xdc..0xdc, cia2 => 0xdd..0xdd, @open_bus => 0xde..0xdf
|
|
252
|
-
}.each do |chip, pages|
|
|
253
|
-
pages.each { |p| @read_pages[p] = @write_pages[p] = chip }
|
|
254
|
-
end
|
|
255
|
-
@ram_expansion.map_io(@read_pages, @write_pages)
|
|
256
|
-
@read_pages[0xd7] = @write_pages[0xd7] = @debug_register if @debug_register
|
|
257
|
-
@read_pages[0xdf] = @write_pages[0xdf] = @reu if @reu
|
|
258
|
-
map_cartridge_io if @cartridge
|
|
259
|
-
map_extra_sids unless @sid_slots.empty?
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
def map_cartridge_io
|
|
263
|
-
@write_pages.fill(@cartridge, 0xde, 2)
|
|
264
|
-
@cartridge.readable_io_pages.each { |p| @read_pages[p] = @cartridge }
|
|
265
|
-
end
|
|
266
|
-
|
|
267
|
-
def basic?
|
|
268
|
-
io_port.kernal? && io_port.basic? && game_high?
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
def game_high?
|
|
272
|
-
@cartridge.nil? || @cartridge.game == 1
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
def roml?
|
|
276
|
-
@cartridge&.exrom&.zero? && io_port.kernal? && io_port.basic?
|
|
277
|
-
end
|
|
278
|
-
|
|
279
|
-
def romh?
|
|
280
|
-
@cartridge&.exrom&.zero? && @cartridge.game.zero? && io_port.kernal?
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
# In 16K mode LORAM alone leaves $d000 as RAM, where it still maps I/O.
|
|
284
|
-
def character?
|
|
285
|
-
(io_port.kernal? || (io_port.basic? && game_high?)) && !io_port.io?
|
|
286
|
-
end
|
|
287
|
-
|
|
288
|
-
def io?
|
|
289
|
-
(io_port.basic? || io_port.kernal?) && io_port.io?
|
|
290
|
-
end
|
|
291
|
-
|
|
292
|
-
def kernal?
|
|
293
|
-
io_port.kernal?
|
|
213
|
+
def map_ram_pages
|
|
214
|
+
@ram_expansion.map(@read_pages, @write_pages)
|
|
294
215
|
end
|
|
295
216
|
end
|
|
296
217
|
end
|
data/lib/badline/chrout_trap.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Badline
|
|
4
4
|
# Observe-only PC trap on the KERNAL CHROUT routine ($FFD2). Records each
|
|
5
|
-
# character written while the KERNAL
|
|
5
|
+
# character written while the layout finds the KERNAL mapped in, then lets execution fall
|
|
6
6
|
# through to the ROM, so the screen output is unaffected. Used for headless
|
|
7
7
|
# capture of program output.
|
|
8
8
|
class ChroutTrap
|
|
@@ -10,14 +10,15 @@ module Badline
|
|
|
10
10
|
|
|
11
11
|
attr_reader :output
|
|
12
12
|
|
|
13
|
-
def initialize(cpu:, bus:)
|
|
13
|
+
def initialize(cpu:, bus:, layout:)
|
|
14
14
|
@cpu = cpu
|
|
15
15
|
@bus = bus
|
|
16
|
+
@layout = layout
|
|
16
17
|
@output = +""
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
def call
|
|
20
|
-
@output << ascii(@cpu.a) if @
|
|
21
|
+
@output << ascii(@cpu.a) if @layout.kernal_mapped?(@bus)
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
def inspect
|