badline 0.13.0 → 0.15.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 +72 -1
- data/CLAUDE.md +42 -12
- data/CONTRIBUTING.md +4 -3
- data/README.md +76 -13
- data/doc/media.md +2 -1
- data/doc/pinned-behaviour.md +174 -0
- data/doc/snapshot-format.md +1197 -0
- data/doc/snapshots.md +90 -40
- data/lib/badline/audio/bare_player.rb +46 -17
- data/lib/badline/audio/machine_player.rb +6 -10
- data/lib/badline/audio/renderer.rb +32 -21
- data/lib/badline/c128/banks.rb +7 -6
- data/lib/badline/c128/bus/keyed_state.rb +45 -0
- data/lib/badline/c128/bus.rb +36 -4
- data/lib/badline/c128/drives.rb +6 -25
- data/lib/badline/c128/keyed_modules.rb +117 -0
- data/lib/badline/c128/keyed_state.rb +91 -0
- data/lib/badline/c128/keys.rb +9 -0
- data/lib/badline/c128/mmu.rb +9 -8
- data/lib/badline/c128/mmu_pages.rb +27 -0
- data/lib/badline/c128/modes.rb +19 -9
- data/lib/badline/c128/z80_turns.rb +1 -1
- data/lib/badline/c128.rb +8 -8
- data/lib/badline/c64/attachments.rb +0 -44
- data/lib/badline/c64/banked_ram/plus256k.rb +18 -10
- data/lib/badline/c64/banked_ram/plus60k.rb +8 -6
- data/lib/badline/c64/banked_ram/unexpanded.rb +2 -2
- data/lib/badline/c64/bus/debug_register.rb +32 -0
- data/lib/badline/c64/bus/extra_sids.rb +80 -0
- data/lib/badline/c64/bus/keyed_state.rb +41 -0
- data/lib/badline/c64/bus.rb +3 -1
- data/lib/badline/c64/cartridge/action_replay.rb +6 -15
- data/lib/badline/c64/cartridge/comal80.rb +1 -0
- data/lib/badline/c64/cartridge/dinamic.rb +3 -1
- data/lib/badline/c64/cartridge/easy_flash.rb +0 -15
- data/lib/badline/c64/cartridge/epyx_fastload.rb +0 -8
- data/lib/badline/c64/cartridge/final_cartridge3.rb +1 -12
- data/lib/badline/c64/cartridge/flash.rb +3 -3
- data/lib/badline/c64/cartridge/fun_play.rb +2 -1
- data/lib/badline/c64/cartridge/g_mod2.rb +0 -12
- data/lib/badline/c64/cartridge/game_system.rb +2 -1
- data/lib/badline/c64/cartridge/geo_ram.rb +0 -16
- data/lib/badline/c64/cartridge/kcs_power.rb +0 -8
- data/lib/badline/c64/cartridge/keyed_state.rb +514 -0
- data/lib/badline/c64/cartridge/magic_desk.rb +2 -1
- data/lib/badline/c64/cartridge/ocean.rb +1 -0
- data/lib/badline/c64/cartridge/pagefox.rb +1 -10
- data/lib/badline/c64/cartridge/retro_replay.rb +0 -8
- data/lib/badline/c64/cartridge/rgcd.rb +2 -11
- data/lib/badline/c64/cartridge/super_games.rb +3 -12
- data/lib/badline/c64/cartridge/zaxxon.rb +1 -16
- data/lib/badline/c64/cartridge.rb +4 -30
- data/lib/badline/c64/kernal_traps.rb +28 -25
- data/lib/badline/c64/keyed_modules.rb +115 -0
- data/lib/badline/c64/keyed_state.rb +68 -0
- data/lib/badline/c64/reu/dma.rb +0 -4
- data/lib/badline/c64/reu/keyed_state.rb +140 -0
- data/lib/badline/c64/reu/ram.rb +0 -15
- data/lib/badline/c64/reu.rb +1 -3
- data/lib/badline/c64/true_drives.rb +56 -5
- data/lib/badline/c64.rb +7 -3
- data/lib/badline/chips/cia/interrupt_register.rb +0 -17
- data/lib/badline/chips/cia/keyed_parts.rb +213 -0
- data/lib/badline/chips/cia/serial.rb +0 -4
- data/lib/badline/chips/cia/time_of_day.rb +0 -22
- data/lib/badline/chips/cia/timer.rb +0 -20
- data/lib/badline/chips/cia.rb +2 -2
- data/lib/badline/chips/cpu/core.rb +18 -2
- data/lib/badline/chips/cpu/keyed_state.rb +177 -0
- data/lib/badline/chips/cpu/microcode.rb +16 -0
- data/lib/badline/chips/cpu/port.rb +20 -3
- data/lib/badline/chips/cpu.rb +5 -0
- data/lib/badline/chips/sid/decimator.rb +10 -8
- data/lib/badline/chips/sid/envelope.rb +1 -6
- data/lib/badline/chips/sid/filter.rb +0 -14
- data/lib/badline/chips/sid/keyed_parts.rb +286 -0
- data/lib/badline/chips/sid/voice.rb +0 -10
- data/lib/badline/chips/sid/waveform.rb +0 -2
- data/lib/badline/chips/sid.rb +1 -2
- data/lib/badline/chips/ted/beam.rb +118 -0
- data/lib/badline/chips/ted/fetches.rb +199 -0
- data/lib/badline/chips/ted/keyed_state.rb +156 -0
- data/lib/badline/chips/ted/modes.rb +134 -0
- data/lib/badline/chips/ted/palette.rb +43 -0
- data/lib/badline/chips/ted/picture.rb +182 -0
- data/lib/badline/chips/ted/sound/output.rb +86 -0
- data/lib/badline/chips/ted/sound.rb +284 -0
- data/lib/badline/chips/ted/timers.rb +66 -0
- data/lib/badline/chips/ted.rb +190 -0
- data/lib/badline/chips/tia.rb +61 -0
- data/lib/badline/chips/vdc/keyed_parts.rb +105 -0
- data/lib/badline/chips/vdc/painter.rb +0 -12
- data/lib/badline/chips/vdc/raster.rb +0 -16
- data/lib/badline/chips/vdc/window.rb +0 -9
- data/lib/badline/chips/vdc.rb +1 -2
- data/lib/badline/chips/via/control_lines.rb +0 -15
- data/lib/badline/chips/via/interrupt_register.rb +0 -9
- data/lib/badline/chips/via/keyed_parts.rb +163 -0
- data/lib/badline/chips/via/shift_register.rb +0 -14
- data/lib/badline/chips/via/timer1.rb +0 -13
- data/lib/badline/chips/via/timer2.rb +0 -18
- data/lib/badline/chips/via.rb +1 -2
- data/lib/badline/chips/vic/border_mask.rb +0 -10
- data/lib/badline/chips/vic/collisions.rb +0 -11
- data/lib/badline/chips/vic/color_patches.rb +0 -11
- data/lib/badline/chips/vic/display_state.rb +0 -19
- data/lib/badline/chips/vic/graphics_shifter.rb +0 -4
- data/lib/badline/chips/vic/keyed_parts.rb +228 -0
- data/lib/badline/chips/vic/keyed_sprites.rb +225 -0
- data/lib/badline/chips/vic/keyed_state.rb +102 -0
- data/lib/badline/chips/vic/register_log.rb +0 -18
- data/lib/badline/chips/vic/registers.rb +0 -9
- data/lib/badline/chips/vic/sequencer.rb +0 -2
- data/lib/badline/chips/vic/sprite/internal_bus.rb +0 -11
- data/lib/badline/chips/vic/sprite.rb +0 -2
- data/lib/badline/chips/vic/sprites.rb +0 -3
- data/lib/badline/chips/vic.rb +6 -2
- data/lib/badline/chips/vic_i/keyed_parts.rb +142 -0
- data/lib/badline/chips/vic_i/painter.rb +0 -4
- data/lib/badline/chips/vic_i/sound.rb +38 -46
- data/lib/badline/chips/vic_i.rb +2 -2
- data/lib/badline/chips/z80/core.rb +2 -2
- data/lib/badline/chips/z80/keyed_state.rb +73 -0
- data/lib/badline/chips.rb +10 -0
- data/lib/badline/core.rb +4 -21
- data/lib/badline/drives/datasette/keyed_state.rb +43 -0
- data/lib/badline/drives/datasette.rb +62 -12
- data/lib/badline/drives/engine/core.rb +3 -0
- data/lib/badline/drives/engine/serial_lines.rb +4 -7
- data/lib/badline/drives/model1541/bus.rb +0 -13
- data/lib/badline/drives/model1541/disk.rb +9 -8
- data/lib/badline/drives/model1541/keyed_state.rb +251 -0
- data/lib/badline/drives/model1541/mechanism.rb +0 -2
- data/lib/badline/drives/model1541.rb +1 -2
- data/lib/badline/drives/model1571/bus.rb +0 -13
- data/lib/badline/drives/model1571/keyed_state.rb +108 -0
- data/lib/badline/drives/model1571/wd1770.rb +0 -14
- data/lib/badline/drives/model1571.rb +1 -2
- data/lib/badline/drives/model1581/bus.rb +0 -13
- data/lib/badline/drives/model1581/disk.rb +0 -4
- data/lib/badline/drives/model1581/keyed_state.rb +280 -0
- data/lib/badline/drives/model1581/mechanism.rb +0 -21
- data/lib/badline/drives/model1581/slot.rb +0 -18
- data/lib/badline/drives/model1581/wd1772.rb +0 -2
- data/lib/badline/drives/model1581.rb +2 -2
- data/lib/badline/drives.rb +8 -0
- data/lib/badline/frontend/app.rb +3 -3
- data/lib/badline/frontend/boot.rb +4 -2
- data/lib/badline/frontend/controls.rb +25 -5
- data/lib/badline/frontend/drive_led.rb +44 -21
- data/lib/badline/frontend/keys.rb +14 -2
- data/lib/badline/frontend/media_slots.rb +11 -1
- data/lib/badline/frontend/menu/menu_dialogs.rb +4 -3
- data/lib/badline/frontend/menu/menu_media.rb +13 -3
- data/lib/badline/frontend/menu/menu_pages.rb +8 -8
- data/lib/badline/frontend/menu/menu_ports.rb +13 -1
- data/lib/badline/frontend/screen.rb +33 -12
- data/lib/badline/frontend/screens.rb +2 -1
- data/lib/badline/frontend/snapshots.rb +12 -1
- data/lib/badline/frontend/sound.rb +4 -4
- data/lib/badline/frontend/timeline.rb +43 -12
- data/lib/badline/input/matrix_typist.rb +98 -0
- data/lib/badline/input.rb +1 -0
- data/lib/badline/kernal_trap/chrout.rb +45 -0
- data/lib/badline/kernal_trap/dos/channel.rb +0 -27
- data/lib/badline/kernal_trap/dos/channels.rb +0 -25
- data/lib/badline/kernal_trap/dos/memory.rb +0 -9
- data/lib/badline/kernal_trap/dos/status.rb +0 -8
- data/lib/badline/kernal_trap/dos/write_file.rb +0 -18
- data/lib/badline/kernal_trap/dos.rb +0 -19
- data/lib/badline/kernal_trap/file_routine.rb +4 -4
- data/lib/badline/kernal_trap/keyed_state.rb +150 -0
- data/lib/badline/kernal_trap/layout.rb +75 -11
- data/lib/badline/kernal_trap/load.rb +14 -16
- data/lib/badline/kernal_trap/routine.rb +12 -0
- data/lib/badline/kernal_trap/save.rb +8 -18
- data/lib/badline/kernal_trap/serial.rb +1 -17
- data/lib/badline/kernal_trap.rb +2 -0
- data/lib/badline/machine/keyboard_buffer.rb +49 -0
- data/lib/badline/machine/settling.rb +29 -0
- data/lib/badline/machine.rb +29 -6
- data/lib/badline/media/boot_disk.rb +14 -2
- data/lib/badline/media/extensions.rb +10 -0
- data/lib/badline/media/plus4_media.rb +68 -0
- data/lib/badline/media/program.rb +20 -6
- data/lib/badline/media.rb +33 -12
- data/lib/badline/memory.rb +3 -6
- data/lib/badline/options/family.rb +6 -2
- data/lib/badline/options/help.rb +66 -16
- data/lib/badline/options/table.rb +17 -2
- data/lib/badline/options/validation.rb +26 -2
- data/lib/badline/options.rb +42 -9
- data/lib/badline/plus4/acia.rb +45 -0
- data/lib/badline/plus4/bus.rb +375 -0
- data/lib/badline/plus4/cassette_sense.rb +21 -0
- data/lib/badline/plus4/cpu.rb +10 -0
- data/lib/badline/plus4/cpu_port.rb +93 -0
- data/lib/badline/plus4/keyboard_port.rb +76 -0
- data/lib/badline/plus4/keyed_modules.rb +99 -0
- data/lib/badline/plus4/keyed_parts.rb +143 -0
- data/lib/badline/plus4/keyed_state.rb +41 -0
- data/lib/badline/plus4/model.rb +38 -0
- data/lib/badline/plus4/user_port.rb +31 -0
- data/lib/badline/plus4.rb +240 -0
- data/lib/badline/roms/README +38 -0
- data/lib/badline/roms/plus4/basic.rom +0 -0
- data/lib/badline/roms/plus4/function-high.rom +0 -0
- data/lib/badline/roms/plus4/function-low.rom +0 -0
- data/lib/badline/roms/plus4/kernal-ntsc.rom +0 -0
- data/lib/badline/roms/plus4/kernal-pal.rom +0 -0
- data/lib/badline/snapshot/c128_setup.rb +9 -20
- data/lib/badline/snapshot/c64_setup.rb +28 -24
- data/lib/badline/snapshot/container.rb +6 -0
- data/lib/badline/snapshot/field_doc/markdown.rb +113 -0
- data/lib/badline/snapshot/field_doc.rb +148 -0
- data/lib/badline/snapshot/image.rb +143 -28
- data/lib/badline/snapshot/keyed/cursor.rb +40 -0
- data/lib/badline/snapshot/keyed/modules.rb +66 -0
- data/lib/badline/snapshot/keyed/reader.rb +188 -0
- data/lib/badline/snapshot/keyed/recorder.rb +88 -0
- data/lib/badline/snapshot/keyed/report.rb +26 -0
- data/lib/badline/snapshot/keyed/writer.rb +55 -0
- data/lib/badline/snapshot/keyed.rb +64 -0
- data/lib/badline/snapshot/machine_state.rb +17 -64
- data/lib/badline/snapshot/plus4_setup.rb +39 -0
- data/lib/badline/snapshot/storage_setup.rb +29 -34
- data/lib/badline/snapshot/vic20_setup.rb +6 -15
- data/lib/badline/snapshot/vice/reu1764.rb +2 -2
- data/lib/badline/snapshot/vice.rb +7 -31
- data/lib/badline/snapshot.rb +48 -20
- data/lib/badline/storage/crt_file.rb +3 -1
- data/lib/badline/storage/g64_image.rb +9 -4
- data/lib/badline/storage/tap.rb +57 -20
- data/lib/badline/support/checkpoint.rb +3 -2
- data/lib/badline/support/plus4_checkpoint.rb +42 -0
- data/lib/badline/version.rb +1 -1
- data/lib/badline/vic20/attachments.rb +3 -0
- data/lib/badline/vic20/bus/keyed_state.rb +52 -0
- data/lib/badline/vic20/bus.rb +1 -2
- data/lib/badline/vic20/keyed_modules.rb +73 -0
- data/lib/badline/vic20/keyed_state.rb +45 -0
- data/lib/badline/vic20.rb +5 -5
- data/lib/badline.rb +1 -0
- metadata +75 -42
- data/lib/badline/c128/bus/saved_state.rb +0 -53
- data/lib/badline/c128/saved_state.rb +0 -117
- data/lib/badline/c64/bus/saved_state.rb +0 -68
- data/lib/badline/c64/cartridge/flash/saved_state.rb +0 -40
- data/lib/badline/c64/cartridge/retro_replay/saved_state.rb +0 -47
- data/lib/badline/c64/cartridge/saved_state.rb +0 -63
- data/lib/badline/c64/reu/dma/saved_state.rb +0 -52
- data/lib/badline/c64/reu/saved_state.rb +0 -55
- data/lib/badline/c64/saved_state.rb +0 -112
- data/lib/badline/chips/cia/saved_state.rb +0 -49
- data/lib/badline/chips/cia/serial/saved_state.rb +0 -45
- data/lib/badline/chips/cpu/saved_state.rb +0 -117
- data/lib/badline/chips/sid/envelope/saved_state.rb +0 -70
- data/lib/badline/chips/sid/filter/saved_state.rb +0 -42
- data/lib/badline/chips/sid/saved_state.rb +0 -52
- data/lib/badline/chips/sid/waveform/saved_state.rb +0 -68
- data/lib/badline/chips/vdc/saved_state.rb +0 -36
- data/lib/badline/chips/via/saved_state.rb +0 -44
- data/lib/badline/chips/vic/graphics_shifter/saved_state.rb +0 -40
- data/lib/badline/chips/vic/saved_state.rb +0 -82
- data/lib/badline/chips/vic/sequencer/saved_state.rb +0 -91
- data/lib/badline/chips/vic/sprite/saved_state.rb +0 -66
- data/lib/badline/chips/vic/sprites/saved_state.rb +0 -59
- data/lib/badline/chips/vic_i/painter/saved_state.rb +0 -40
- data/lib/badline/chips/vic_i/saved_state.rb +0 -55
- data/lib/badline/chips/z80/saved_state.rb +0 -71
- data/lib/badline/chrout_trap.rb +0 -43
- data/lib/badline/debug_register.rb +0 -28
- data/lib/badline/drives/datasette/saved_state.rb +0 -37
- data/lib/badline/drives/model1541/disk/saved_state.rb +0 -88
- data/lib/badline/drives/model1541/mechanism/saved_state.rb +0 -72
- data/lib/badline/drives/model1541/saved_state.rb +0 -44
- data/lib/badline/drives/model1571/saved_state.rb +0 -47
- data/lib/badline/drives/model1581/disk/saved_state.rb +0 -89
- data/lib/badline/drives/model1581/saved_state.rb +0 -42
- data/lib/badline/drives/model1581/wd1772/saved_state.rb +0 -68
- data/lib/badline/keyboard_buffer.rb +0 -33
- data/lib/badline/snapshot/setup.rb +0 -31
- data/lib/badline/snapshot/state.rb +0 -179
- data/lib/badline/vic20/bus/saved_state.rb +0 -35
- data/lib/badline/vic20/saved_state.rb +0 -110
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Badline
|
|
4
4
|
module Snapshot
|
|
5
|
-
# The storage device 8 serves through the traps, as a
|
|
5
|
+
# The storage device 8 serves through the traps, as a snapshot holds it:
|
|
6
6
|
# its kind, its path and, for an archive or a disk image, its bytes, so
|
|
7
7
|
# it opens again without the host file.
|
|
8
8
|
module StorageSetup
|
|
@@ -14,23 +14,6 @@ module Badline
|
|
|
14
14
|
|
|
15
15
|
module_function
|
|
16
16
|
|
|
17
|
-
# The same directory by its path, an archive with the bytes it held,
|
|
18
|
-
# or a disk image with its path, whether it is write-protected, and
|
|
19
|
-
# its bytes with the error table after them.
|
|
20
|
-
def write(storage, out)
|
|
21
|
-
if storage.is_a?(Storage::HostDirectory)
|
|
22
|
-
out.int(HOST_DIRECTORY).string(File.expand_path(storage.path))
|
|
23
|
-
elsif storage.is_a?(Storage::T64)
|
|
24
|
-
out.int(T64_ARCHIVE).string(File.expand_path(storage.path)).blob(storage.bytes)
|
|
25
|
-
else
|
|
26
|
-
write_image(storage, out)
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def write_image(image, out)
|
|
31
|
-
out.int(image_kind(image)).string(File.expand_path(image.path)).boolean(image.read_only?).blob(image.contents)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
17
|
def image_kind(image)
|
|
35
18
|
return D71 if image.is_a?(Storage::D71Image)
|
|
36
19
|
return D64 if image.is_a?(Storage::D64Image)
|
|
@@ -39,28 +22,40 @@ module Badline
|
|
|
39
22
|
raise ArgumentError, "#{image.class} can't go in a snapshot"
|
|
40
23
|
end
|
|
41
24
|
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
25
|
+
# The storage's kind by name, in a keyed snapshot module, under
|
|
26
|
+
# storage.*: its path, and for an archive or a disk image whether it
|
|
27
|
+
# is write-protected and its bytes.
|
|
28
|
+
def write_fields(storage, out)
|
|
29
|
+
out.text("storage.path", File.expand_path(storage.path))
|
|
30
|
+
if storage.is_a?(Storage::HostDirectory)
|
|
31
|
+
out.text("storage.kind", "directory")
|
|
32
|
+
elsif storage.is_a?(Storage::T64)
|
|
33
|
+
out.text("storage.kind", "t64").bytes("storage.bytes", storage.bytes)
|
|
34
|
+
else
|
|
35
|
+
out.text("storage.kind", KIND_NAMES.fetch(image_kind(storage))).bool("storage.read_only", storage.read_only?)
|
|
36
|
+
out.bytes("storage.bytes", storage.contents)
|
|
53
37
|
end
|
|
54
38
|
end
|
|
55
39
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
40
|
+
KIND_NAMES = %w[directory d64 d71 d81 t64].freeze
|
|
41
|
+
|
|
42
|
+
# Opens the storage write_fields wrote: the same directory by its
|
|
43
|
+
# path, an archive with the bytes it held, or a disk image with the
|
|
44
|
+
# bytes it held, writes and all. A detached reader gets the image
|
|
45
|
+
# write-protected, and Storage::Unavailable for a directory.
|
|
46
|
+
def read_fields(input, detached: false)
|
|
47
|
+
kind = KIND_NAMES.index(input.choice("storage.kind", KIND_NAMES, "directory")).to_i
|
|
48
|
+
path = input.text("storage.path", "")
|
|
49
|
+
return (detached ? Storage::Unavailable.new : Storage::HostDirectory.new(path)) if kind == HOST_DIRECTORY
|
|
50
|
+
|
|
51
|
+
bytes = input.bytes("storage.bytes", "".b).bytes
|
|
52
|
+
return Storage::T64.new(path, bytes:) if kind == T64_ARCHIVE
|
|
53
|
+
|
|
54
|
+
read_only = input.bool("storage.read_only", false) || detached
|
|
59
55
|
case kind
|
|
60
56
|
when D64 then Storage::D64Image.new(path, read_only:, bytes:)
|
|
61
57
|
when D71 then Storage::D71Image.new(path, read_only:, bytes:)
|
|
62
|
-
|
|
63
|
-
else raise FormatError, "unknown storage #{kind} in the state"
|
|
58
|
+
else Storage::D81Image.new(path, read_only:, bytes:)
|
|
64
59
|
end
|
|
65
60
|
end
|
|
66
61
|
end
|
|
@@ -7,25 +7,16 @@ module Badline
|
|
|
7
7
|
Vic20Setup = Data.define(:ram)
|
|
8
8
|
|
|
9
9
|
class Vic20Setup
|
|
10
|
-
MARKER = "VIC20"
|
|
11
10
|
RAM_CONFIGURATIONS = Vic20::Bus::RAM_CONFIGURATIONS.keys.freeze
|
|
12
11
|
|
|
13
|
-
# The
|
|
14
|
-
def
|
|
15
|
-
|
|
16
|
-
input.marker(MARKER)
|
|
17
|
-
input.check_stamp
|
|
18
|
-
read(input)
|
|
12
|
+
# The RAM expansion by name, in a keyed snapshot module.
|
|
13
|
+
def write_fields(out)
|
|
14
|
+
out.text("ram", ram.to_s)
|
|
19
15
|
end
|
|
20
16
|
|
|
21
|
-
def self.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
raise FormatError, "the state names a VIC-20 RAM expansion badline doesn't know"
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def write(out)
|
|
28
|
-
out.int(RAM_CONFIGURATIONS.index(ram))
|
|
17
|
+
def self.read_fields(input)
|
|
18
|
+
text = input.choice("ram", RAM_CONFIGURATIONS.map(&:to_s), "unexpanded")
|
|
19
|
+
new(ram: RAM_CONFIGURATIONS.find { |name| name.to_s == text } || :unexpanded)
|
|
29
20
|
end
|
|
30
21
|
|
|
31
22
|
# A machine built this way, at power-on.
|
|
@@ -9,8 +9,8 @@ module Badline
|
|
|
9
9
|
# from $DF00, and the RAM.
|
|
10
10
|
#
|
|
11
11
|
# Written: the registers and the RAM. VICE saves between transfers,
|
|
12
|
-
# so
|
|
13
|
-
#
|
|
12
|
+
# so a save runs a transfer in flight to its end first
|
|
13
|
+
# (Machine::Settling).
|
|
14
14
|
#
|
|
15
15
|
# Read: the registers, as the values the counters run from and
|
|
16
16
|
# start from, and the RAM. The status register's interrupt, end of
|
|
@@ -22,43 +22,19 @@ module Badline
|
|
|
22
22
|
# machine at power-on with nothing attached, and applies the modules it
|
|
23
23
|
# has, in the order x64sc writes them.
|
|
24
24
|
module Vice
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
|
|
32
|
-
TRANSFER_CYCLES = 0x40000
|
|
33
|
-
|
|
34
|
-
# The modules a badline snapshot carries for VICE, in x64sc's order.
|
|
35
|
-
# They describe a copy of the machine restored from `state`, so saving
|
|
36
|
-
# leaves the machine itself alone. VICE saves between instructions,
|
|
37
|
-
# and resumes by fetching an opcode at the program counter, so when
|
|
38
|
-
# badline's CPU is inside an instruction, or an REU transfer holds
|
|
39
|
-
# the bus, the copy runs on to the end of both. The copy's SID
|
|
40
|
-
# catches up, so its registers and voices stand as of that cycle.
|
|
41
|
-
def self.export(state)
|
|
42
|
-
machine = settled(state)
|
|
25
|
+
# The modules a badline snapshot carries for VICE, in x64sc's order,
|
|
26
|
+
# describing `machine`, which Machine::Settling has brought between
|
|
27
|
+
# instructions with no REU transfer under way: VICE saves between
|
|
28
|
+
# instructions, and resumes by fetching an opcode at the program
|
|
29
|
+
# counter. Its SID has caught up, so the registers and voices stand
|
|
30
|
+
# as of that cycle.
|
|
31
|
+
def self.export(machine)
|
|
43
32
|
sections = [MainCPU.export(machine), C64Mem.export(machine), Peripherals.cartridge_port(machine)]
|
|
44
33
|
sections << REU1764.export(machine) if machine.reu
|
|
45
34
|
sections + [*CIAs.export(machine), SIDRegisters.export(machine), SIDExtended.export(machine),
|
|
46
35
|
Peripherals.drives, VICII.export(machine), Peripherals.glue(machine), *Peripherals.rest]
|
|
47
36
|
end
|
|
48
37
|
|
|
49
|
-
# The copy is detached from the host's files (Snapshot::StateReader),
|
|
50
|
-
# so it reads none and its traps write none.
|
|
51
|
-
def self.settled(state)
|
|
52
|
-
copy = C64.restored(state, detached: true)
|
|
53
|
-
(BOUNDARY_CYCLES + TRANSFER_CYCLES).times do
|
|
54
|
-
break if copy.cpu.boundary? && !copy.reu&.dma?
|
|
55
|
-
|
|
56
|
-
copy.cycle!
|
|
57
|
-
end
|
|
58
|
-
copy.sid.catch_up!
|
|
59
|
-
copy
|
|
60
|
-
end
|
|
61
|
-
|
|
62
38
|
# How the machine the snapshot was saved from was built: the VIC
|
|
63
39
|
# model and the region from the VIC-II's model, and an REU from
|
|
64
40
|
# REU1764. VICE doesn't save the CIA model; the 8565 and 8562 go
|
data/lib/badline/snapshot.rb
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "zlib"
|
|
4
|
-
require "badline/snapshot/state"
|
|
5
|
-
require "badline/snapshot/setup"
|
|
6
4
|
require "badline/snapshot/container"
|
|
5
|
+
require "badline/snapshot/c64_setup"
|
|
7
6
|
require "badline/snapshot/machine_state"
|
|
7
|
+
require "badline/snapshot/keyed"
|
|
8
8
|
require "badline/snapshot/vice"
|
|
9
9
|
require "badline/snapshot/image"
|
|
10
10
|
|
|
11
11
|
module Badline
|
|
12
12
|
# Saves and restores the whole machine in VICE's .vsf snapshot format.
|
|
13
13
|
#
|
|
14
|
-
# A snapshot badline writes
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
# modules badline doesn't take.
|
|
14
|
+
# A snapshot badline writes holds the machine as BL-* modules, one per
|
|
15
|
+
# unit, each a list of keyed records (Snapshot::Keyed), which later
|
|
16
|
+
# badlines read: doc/snapshot-format.md lists them. VICE skips modules it
|
|
17
|
+
# doesn't know. An export for VICE puts VICE's own modules for the C64
|
|
18
|
+
# ahead of them. A snapshot from VICE restores through its modules, as
|
|
19
|
+
# far as they map, and reports the modules badline doesn't take.
|
|
21
20
|
module Snapshot
|
|
22
21
|
module_function
|
|
23
22
|
|
|
@@ -26,17 +25,22 @@ module Badline
|
|
|
26
25
|
path
|
|
27
26
|
end
|
|
28
27
|
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
def
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return Container.new([MachineState.section(state)], machine: Container::C128).to_s if computer.family == :c128
|
|
35
|
-
|
|
36
|
-
Container.new(Vice.export(state) + [MachineState.section(state)]).to_s
|
|
28
|
+
# Saves the machine's snapshot with VICE's modules ahead of its own for
|
|
29
|
+
# a C64, so x64sc opens it too.
|
|
30
|
+
def export(computer, path)
|
|
31
|
+
File.binwrite(path, Image.exported(computer).to_s)
|
|
32
|
+
path
|
|
37
33
|
end
|
|
38
34
|
|
|
39
|
-
|
|
35
|
+
# The machine's snapshot file. Saving first runs the machine on to the
|
|
36
|
+
# end of the instruction its CPU is in, and of an REU transfer under
|
|
37
|
+
# way (Machine::Settling), so a save advances it by a few cycles, and a
|
|
38
|
+
# second save straight after runs none. A VIC-20's, a C128's or a
|
|
39
|
+
# Plus/4's snapshot is in a container named as xvic, x128 or xplus4
|
|
40
|
+
# names its machine.
|
|
41
|
+
def dump(computer) = Image.of(computer).to_s
|
|
42
|
+
|
|
43
|
+
def read(path) = Image.new(Container.parse(File.binread(path)), name: File.basename(path))
|
|
40
44
|
|
|
41
45
|
# A new machine, built as the snapshot's was and restored from it.
|
|
42
46
|
# Yields a line for each thing it leaves out.
|
|
@@ -47,12 +51,32 @@ module Badline
|
|
|
47
51
|
# snapshot that fails leaves the machine as it was.
|
|
48
52
|
def restore(computer, path, &) = read(path).restore(computer, &)
|
|
49
53
|
|
|
50
|
-
# A machine's snapshots as .vsf files. C64, Vic20
|
|
51
|
-
# include it.
|
|
54
|
+
# A machine's snapshots, as .vsf files and in memory. C64, Vic20, C128
|
|
55
|
+
# and Plus4 each include it.
|
|
52
56
|
module Files
|
|
53
57
|
def save_snapshot(path) = Snapshot.save(self, path)
|
|
54
58
|
|
|
59
|
+
# Saves the snapshot with VICE's modules too, for a C64, so x64sc
|
|
60
|
+
# opens it as well as badline.
|
|
61
|
+
def export_snapshot(path) = Snapshot.export(self, path)
|
|
62
|
+
|
|
55
63
|
def restore_snapshot(path, &) = Snapshot.restore(self, path, &)
|
|
64
|
+
|
|
65
|
+
# The machine's snapshot in memory (Image.of), which settles it as a
|
|
66
|
+
# save does.
|
|
67
|
+
def snapshot = Image.of(self)
|
|
68
|
+
|
|
69
|
+
# Takes the machine back to an Image from #snapshot. The machine keeps
|
|
70
|
+
# its chips, its traps and its callbacks, and puts in the cartridge,
|
|
71
|
+
# drives and tape the image has, taking out any it hasn't. Raises
|
|
72
|
+
# Snapshot::FormatError for an image of a machine built another way.
|
|
73
|
+
# The image goes into a new machine first, so one that fails leaves
|
|
74
|
+
# this machine as it was. What it leaves out goes unsaid:
|
|
75
|
+
# Image#restore returns it in a Report.
|
|
76
|
+
def restore(image)
|
|
77
|
+
image.restore(self) { nil }
|
|
78
|
+
self
|
|
79
|
+
end
|
|
56
80
|
end
|
|
57
81
|
end
|
|
58
82
|
|
|
@@ -67,4 +91,8 @@ module Badline
|
|
|
67
91
|
class C128
|
|
68
92
|
include Snapshot::Files
|
|
69
93
|
end
|
|
94
|
+
|
|
95
|
+
class Plus4
|
|
96
|
+
include Snapshot::Files
|
|
97
|
+
end
|
|
70
98
|
end
|
|
@@ -7,6 +7,7 @@ module Badline
|
|
|
7
7
|
|
|
8
8
|
SIGNATURE = "C64 CARTRIDGE ".b
|
|
9
9
|
VIC20_SIGNATURE = "VIC20 CARTRIDGE ".b
|
|
10
|
+
PLUS4_SIGNATURE = "PLUS4 CARTRIDGE ".b
|
|
10
11
|
CHIP_SIGNATURE = "CHIP".b
|
|
11
12
|
CHIP_HEADER_SIZE = 0x10
|
|
12
13
|
RAM_CHIP = 1
|
|
@@ -35,7 +36,7 @@ module Badline
|
|
|
35
36
|
end
|
|
36
37
|
|
|
37
38
|
# `bytes` stands in for the file's contents. `machine` is the one the
|
|
38
|
-
# image has to be for, :c64 or :
|
|
39
|
+
# image has to be for, :c64, :vic20 or :plus4, or nil for any.
|
|
39
40
|
def initialize(path = nil, bytes: nil, machine: :c64)
|
|
40
41
|
parse(bytes || File.binread(path))
|
|
41
42
|
return if machine.nil? || @machine == machine
|
|
@@ -58,6 +59,7 @@ module Badline
|
|
|
58
59
|
def signed_machine(bytes)
|
|
59
60
|
return :c64 if bytes.start_with?(SIGNATURE)
|
|
60
61
|
return :vic20 if bytes.start_with?(VIC20_SIGNATURE)
|
|
62
|
+
return :plus4 if bytes.start_with?(PLUS4_SIGNATURE)
|
|
61
63
|
|
|
62
64
|
raise FormatError, "Missing CRT signature"
|
|
63
65
|
end
|
|
@@ -47,7 +47,7 @@ module Badline
|
|
|
47
47
|
# track 1 and 1 for track 1.5, laid out as VICE lays one out: every
|
|
48
48
|
# block as long as the longest track.
|
|
49
49
|
def self.create(path, tracks, half_tracks: HALF_TRACKS)
|
|
50
|
-
max =
|
|
50
|
+
max = tracks.values.map { |bytes, _| bytes.length }.push(MAX_TRACK_SIZE).max
|
|
51
51
|
offsets = Array.new(half_tracks, 0)
|
|
52
52
|
zones = Array.new(half_tracks, 0)
|
|
53
53
|
blocks = +"".b
|
|
@@ -66,15 +66,20 @@ module Badline
|
|
|
66
66
|
[bytes.length].pack("v") + bytes.pack("C*").ljust(size, "\x00".b)
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
-
attr_reader :half_tracks, :max_track_size
|
|
69
|
+
attr_reader :half_tracks, :max_track_size, :path
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
# `bytes` stands in for the host file's contents, as a snapshot
|
|
72
|
+
# restores the image as it was.
|
|
73
|
+
def initialize(path, read_only: false, bytes: nil)
|
|
72
74
|
@path = path
|
|
73
75
|
@read_only = read_only
|
|
74
|
-
@data = File.binread(path)
|
|
76
|
+
@data = bytes ? bytes.pack("C*") : File.binread(path)
|
|
75
77
|
parse
|
|
76
78
|
end
|
|
77
79
|
|
|
80
|
+
# The image as its file holds it.
|
|
81
|
+
def contents = @data.bytes
|
|
82
|
+
|
|
78
83
|
# Whether the image was opened write-protected.
|
|
79
84
|
def read_only? = @read_only
|
|
80
85
|
|
data/lib/badline/storage/tap.rb
CHANGED
|
@@ -5,21 +5,26 @@ module Badline
|
|
|
5
5
|
# Raw datasette pulse stream. The header holds the signature, the
|
|
6
6
|
# version at $0c, the platform at $0d (0 C64, 1 VIC-20, 2 C16) and the
|
|
7
7
|
# data size at $10; the data runs from $14, every byte the time to the
|
|
8
|
-
# next falling edge on the tape read line, in units of 8 cycles.
|
|
8
|
+
# next falling edge on the tape read line, in units of 8 cycles. A
|
|
9
|
+
# version 2 tape, the C16's and the Plus/4's, times half waves instead,
|
|
10
|
+
# so it takes two bytes to the next falling edge.
|
|
9
11
|
class TAP
|
|
10
12
|
class FormatError < StandardError; end
|
|
11
13
|
|
|
12
14
|
SIGNATURE = "C64-TAPE-RAW".bytes.freeze
|
|
15
|
+
C16_SIGNATURE = "C16-TAPE-RAW".bytes.freeze
|
|
13
16
|
HEADER_SIZE = 0x14
|
|
14
17
|
OVERFLOW = 0x100 * 8
|
|
15
18
|
|
|
16
19
|
# The file it was read from, expanded, and the file's bytes.
|
|
17
20
|
attr_reader :version, :platform, :path, :bytes
|
|
18
21
|
|
|
19
|
-
# A blank
|
|
20
|
-
#
|
|
22
|
+
# A blank tape for `platform` at `path`, written to the host file: a
|
|
23
|
+
# version 1 tape for the C64 (0) or the VIC-20 (1), and a version 2
|
|
24
|
+
# C16 tape for the 264 series (2).
|
|
21
25
|
def self.create(path, platform:)
|
|
22
|
-
|
|
26
|
+
header = platform == 2 ? C16_SIGNATURE + [2] : SIGNATURE + [1]
|
|
27
|
+
File.binwrite(path, (header + [platform, 0, 0, 0, 0, 0, 0]).pack("C*"))
|
|
23
28
|
new(path)
|
|
24
29
|
end
|
|
25
30
|
|
|
@@ -28,10 +33,11 @@ module Badline
|
|
|
28
33
|
def initialize(path, bytes: nil)
|
|
29
34
|
@path = File.expand_path(path)
|
|
30
35
|
@bytes = bytes || File.binread(path).bytes
|
|
31
|
-
|
|
36
|
+
signature = @bytes[0, SIGNATURE.length]
|
|
37
|
+
raise FormatError, "Missing TAP signature" unless [SIGNATURE, C16_SIGNATURE].include?(signature)
|
|
32
38
|
|
|
33
39
|
@version = @bytes[0x0c].to_i
|
|
34
|
-
raise FormatError, "Unsupported TAP version #{@version}" if @version >
|
|
40
|
+
raise FormatError, "Unsupported TAP version #{@version}" if @version > 2
|
|
35
41
|
|
|
36
42
|
@platform = @bytes[0x0d].to_i
|
|
37
43
|
|
|
@@ -55,18 +61,18 @@ module Badline
|
|
|
55
61
|
# Records a pulse `cycles` long at the position, in place of the rest
|
|
56
62
|
# of the tape: a byte of units of 8 cycles, or a zero and the 24-bit
|
|
57
63
|
# cycle count for a long one (a lone zero, an overflow, on a version 0
|
|
58
|
-
# tape).
|
|
64
|
+
# tape). A version 2 tape records it as two equal halves.
|
|
59
65
|
def record_pulse(cycles)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
return record(encode(cycles)) unless version == 2
|
|
67
|
+
|
|
68
|
+
half = cycles / 2
|
|
69
|
+
record(encode(cycles - half) + encode(half))
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Records a half wave `cycles` long at the position, in place of the
|
|
73
|
+
# rest of the tape, as a version 2 tape times them.
|
|
74
|
+
def record_half_wave(cycles)
|
|
75
|
+
record(encode(cycles))
|
|
70
76
|
end
|
|
71
77
|
|
|
72
78
|
# Writes the tape back to its host file, with the data size the
|
|
@@ -77,20 +83,51 @@ module Badline
|
|
|
77
83
|
File.binwrite(@path, @bytes.pack("C*"))
|
|
78
84
|
end
|
|
79
85
|
|
|
86
|
+
# Whether each byte times a half wave, as on a version 2 tape.
|
|
87
|
+
def half_waves? = version == 2
|
|
88
|
+
|
|
80
89
|
# Cycles until the next falling edge, or nil once the tape has run out.
|
|
90
|
+
# On a version 2 tape that is two half waves, or one left at the end.
|
|
81
91
|
def next_pulse
|
|
82
92
|
return if end?
|
|
93
|
+
return next_time unless half_waves?
|
|
94
|
+
|
|
95
|
+
first = next_time
|
|
96
|
+
end? ? first : first + next_time
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Cycles until the read line's next edge on a version 2 tape, or nil
|
|
100
|
+
# once the tape has run out.
|
|
101
|
+
def next_half_wave
|
|
102
|
+
next_time unless end?
|
|
103
|
+
end
|
|
83
104
|
|
|
105
|
+
private
|
|
106
|
+
|
|
107
|
+
def next_time
|
|
84
108
|
byte = @bytes[@pos]
|
|
85
109
|
@pos += 1
|
|
86
110
|
return byte * 8 unless byte.zero?
|
|
87
111
|
|
|
88
|
-
# $00 is an overflow in version 0 and a 24-bit cycle count
|
|
89
|
-
# version 1.
|
|
112
|
+
# $00 is an overflow in version 0 and a 24-bit cycle count from
|
|
113
|
+
# version 1 on.
|
|
90
114
|
version.zero? ? OVERFLOW : long_pulse
|
|
91
115
|
end
|
|
92
116
|
|
|
93
|
-
|
|
117
|
+
def record(times)
|
|
118
|
+
@bytes.slice!(@pos..)
|
|
119
|
+
@bytes.concat(times)
|
|
120
|
+
@pos = @end = @bytes.length
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def encode(cycles)
|
|
124
|
+
units = (cycles + 4) / 8
|
|
125
|
+
return [units] if units.between?(1, 0xff)
|
|
126
|
+
return [0] if version.zero?
|
|
127
|
+
|
|
128
|
+
count = [cycles, 0xffffff].min
|
|
129
|
+
[0, count & 0xff, (count >> 8) & 0xff, count >> 16]
|
|
130
|
+
end
|
|
94
131
|
|
|
95
132
|
# The stated size disagrees with the file in the wild, and a few dumps
|
|
96
133
|
# leave it zeroed altogether.
|
|
@@ -9,8 +9,9 @@ module Badline
|
|
|
9
9
|
# interface, so taking a checkpoint leaves the machine as it was.
|
|
10
10
|
#
|
|
11
11
|
# Checkpoint.take digests a C64's components, COMPONENTS.
|
|
12
|
-
# Vic20Checkpoint and
|
|
13
|
-
# with a list of its own, which a checkpoint carries as
|
|
12
|
+
# Vic20Checkpoint, C128Checkpoint and Plus4Checkpoint digest the other
|
|
13
|
+
# families', each with a list of its own, which a checkpoint carries as
|
|
14
|
+
# +components+.
|
|
14
15
|
#
|
|
15
16
|
# Colour RAM is digested as the four bits each cell stores: the upper
|
|
16
17
|
# nibble a CPU read sees comes off the open bus.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Support
|
|
5
|
+
# A Checkpoint of a 264 series machine: its CPU, its RAM, the TED's
|
|
6
|
+
# picture, the TED's registers, timers and beam, its sound, and the
|
|
7
|
+
# CPU's port with the ROM banks. The sound's voices are run up to the
|
|
8
|
+
# cycle to read them, which changes nothing they do.
|
|
9
|
+
module Plus4Checkpoint
|
|
10
|
+
COMPONENTS = %w[cpu ram display ted sound port].freeze
|
|
11
|
+
|
|
12
|
+
def self.take(machine)
|
|
13
|
+
ram = machine.ram
|
|
14
|
+
Checkpoint.new(machine.cycles, [
|
|
15
|
+
Checkpoint.fnv1a(Checkpoint.cpu_state(machine.cpu)),
|
|
16
|
+
Checkpoint.fnv1a(Checkpoint.ram(ram, ram.length)),
|
|
17
|
+
Checkpoint.fnv1a(machine.ted.display),
|
|
18
|
+
Checkpoint.fnv1a(ted_state(machine.ted)),
|
|
19
|
+
Checkpoint.fnv1a(sound_state(machine.sound)),
|
|
20
|
+
Checkpoint.fnv1a(port_state(machine))
|
|
21
|
+
], COMPONENTS)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.parse(line) = Checkpoint.parse(line, COMPONENTS)
|
|
25
|
+
|
|
26
|
+
def self.ted_state(ted)
|
|
27
|
+
Array.new(0x20) { |register| ted.peek(0xff00 + register) } +
|
|
28
|
+
ted.timer_counts + [ted.line, ted.column, ted.interrupt_flags, ted.cpu_slots]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.sound_state(sound)
|
|
32
|
+
[sound.noise, sound.phase(0), sound.phase(1), sound.level, sound.volume, sound.control]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.port_state(machine)
|
|
36
|
+
port = machine.port
|
|
37
|
+
bus = machine.bus
|
|
38
|
+
[port.ddr, port.data, bus.low_bank, bus.high_bank, bus.rom_selected ? 1 : 0]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
data/lib/badline/version.rb
CHANGED
|
@@ -34,6 +34,9 @@ module Badline
|
|
|
34
34
|
# The VIC-20's KERNAL, which the traps stand in for.
|
|
35
35
|
def trap_layout = KernalTrap::VIC20_LAYOUT
|
|
36
36
|
|
|
37
|
+
# The VIC-20's KERNAL keeps its keyboard buffer where the C64's does.
|
|
38
|
+
def keyboard_buffer = Machine::KeyboardBuffer::C64_LAYOUT
|
|
39
|
+
|
|
37
40
|
def trap_bus = @bus
|
|
38
41
|
|
|
39
42
|
# A drive that powers on with the machine takes longer to boot than
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class Vic20
|
|
5
|
+
class Bus
|
|
6
|
+
class ColorRAM
|
|
7
|
+
# The cells in a keyed snapshot module, under `key`.
|
|
8
|
+
def save_fields(out, key) = out.bytes(key, @cells)
|
|
9
|
+
|
|
10
|
+
def load_fields(input, key) = input.bytes_into(key, @cells)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# The bytes each side's data lines hold, under `prefix`, and a
|
|
14
|
+
# cartridge's ROM chips as rom<N>.start and rom<N>.bytes, in a keyed
|
|
15
|
+
# snapshot module (Snapshot::Keyed). The pages are mapped again once
|
|
16
|
+
# they are loaded.
|
|
17
|
+
module KeyedState
|
|
18
|
+
def save_fields(out, prefix)
|
|
19
|
+
out.int("#{prefix}data", @data).int("#{prefix}video_data", @video_data)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def load_fields(input, prefix)
|
|
23
|
+
@data = input.byte("#{prefix}data", @data)
|
|
24
|
+
@video_data = input.byte("#{prefix}video_data", @video_data)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Whether a cartridge's ROM chips are in the expansion blocks.
|
|
28
|
+
def cartridge? = !@roms.empty?
|
|
29
|
+
|
|
30
|
+
def save_rom_fields(out)
|
|
31
|
+
out.int("roms", @roms.length)
|
|
32
|
+
@roms.each_with_index do |rom, number|
|
|
33
|
+
out.int("rom#{number}.start", rom.start)
|
|
34
|
+
rom.save_fields(out, "rom#{number}.bytes")
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def load_rom_fields(input)
|
|
39
|
+
@roms = []
|
|
40
|
+
input.int("roms", 0).times do |number|
|
|
41
|
+
bytes = input.bytes("rom#{number}.bytes", "".b).bytes
|
|
42
|
+
@roms << ROM.new(bytes, length: bytes.length, start: input.word("rom#{number}.start", 0))
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def restored! = map_pages
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
include KeyedState
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
data/lib/badline/vic20/bus.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "badline/vic20/bus/
|
|
3
|
+
require "badline/vic20/bus/keyed_state"
|
|
4
4
|
|
|
5
5
|
module Badline
|
|
6
6
|
class Vic20
|
|
@@ -29,7 +29,6 @@ module Badline
|
|
|
29
29
|
# Writes to ROM and to empty spots go nowhere.
|
|
30
30
|
class Bus
|
|
31
31
|
include Addressable
|
|
32
|
-
include SavedState
|
|
33
32
|
|
|
34
33
|
# The pages each expansion block covers, as [first page, count].
|
|
35
34
|
BLOCKS = {
|