badline 0.13.0 → 0.14.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 +49 -1
- data/CLAUDE.md +27 -7
- data/CONTRIBUTING.md +4 -3
- data/README.md +8 -5
- data/doc/media.md +2 -1
- data/doc/pinned-behaviour.md +29 -0
- data/doc/snapshot-format.md +1047 -0
- data/doc/snapshots.md +72 -39
- data/lib/badline/audio/bare_player.rb +50 -17
- data/lib/badline/audio/machine_player.rb +15 -9
- data/lib/badline/audio/renderer.rb +32 -21
- data/lib/badline/c128/banks.rb +6 -3
- data/lib/badline/c128/bus/keyed_state.rb +45 -0
- data/lib/badline/c128/bus.rb +17 -3
- 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 +20 -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/keyed_state.rb +41 -0
- data/lib/badline/c64/bus.rb +2 -1
- data/lib/badline/c64/cartridge/action_replay.rb +0 -13
- 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 +0 -12
- data/lib/badline/c64/cartridge/flash.rb +3 -3
- data/lib/badline/c64/cartridge/g_mod2.rb +0 -12
- 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 +393 -0
- data/lib/badline/c64/cartridge/pagefox.rb +0 -10
- data/lib/badline/c64/cartridge/retro_replay.rb +0 -8
- data/lib/badline/c64/cartridge/rgcd.rb +0 -10
- data/lib/badline/c64/cartridge/super_games.rb +0 -10
- data/lib/badline/c64/cartridge/zaxxon.rb +0 -16
- data/lib/badline/c64/cartridge.rb +1 -27
- data/lib/badline/c64/kernal_traps.rb +28 -25
- data/lib/badline/c64/keyed_modules.rb +111 -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 +119 -0
- data/lib/badline/chips/ted/timers.rb +66 -0
- data/lib/badline/chips/ted.rb +143 -0
- data/lib/badline/chips/tia.rb +49 -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 +38 -0
- data/lib/badline/drives/datasette.rb +40 -7
- 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 +1 -1
- data/lib/badline/frontend/controls.rb +19 -3
- data/lib/badline/frontend/drive_led.rb +44 -21
- data/lib/badline/frontend/menu/menu_dialogs.rb +2 -2
- data/lib/badline/frontend/snapshots.rb +12 -1
- data/lib/badline/frontend/timeline.rb +28 -10
- 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 +5 -2
- data/lib/badline/media/boot_disk.rb +14 -2
- data/lib/badline/media/extensions.rb +10 -0
- data/lib/badline/memory.rb +3 -6
- data/lib/badline/options/family.rb +5 -2
- data/lib/badline/options/help.rb +42 -16
- data/lib/badline/options/table.rb +2 -0
- data/lib/badline/options/validation.rb +2 -0
- data/lib/badline/options.rb +6 -1
- data/lib/badline/plus4/acia.rb +45 -0
- data/lib/badline/plus4/bus.rb +312 -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 +51 -0
- data/lib/badline/plus4/model.rb +38 -0
- data/lib/badline/plus4/user_port.rb +31 -0
- data/lib/badline/plus4.rb +164 -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 +4 -0
- data/lib/badline/snapshot/field_doc/markdown.rb +112 -0
- data/lib/badline/snapshot/field_doc.rb +109 -0
- data/lib/badline/snapshot/image.rb +134 -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/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 +43 -20
- data/lib/badline/storage/crt_file.rb +3 -1
- data/lib/badline/storage/g64_image.rb +8 -3
- data/lib/badline/storage/tap.rb +43 -15
- 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 +61 -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
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "badline/drives/model1581/disk/saved_state"
|
|
4
|
-
|
|
5
3
|
module Badline
|
|
6
4
|
module Drives
|
|
7
5
|
class Model1581
|
|
@@ -24,8 +22,6 @@ module Badline
|
|
|
24
22
|
# file. A track formatted another way stays on the disk alone. The disk
|
|
25
23
|
# is write-protected when the image won't take writes.
|
|
26
24
|
class Disk
|
|
27
|
-
include SavedState
|
|
28
|
-
|
|
29
25
|
CYLINDERS = 80
|
|
30
26
|
SIDES = 2
|
|
31
27
|
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Drives
|
|
5
|
+
class Model1581
|
|
6
|
+
class WD1772
|
|
7
|
+
PHASE_NAMES = %w[idle spin_up stepped settled search read_data write_gate write_data read_track track_index
|
|
8
|
+
write_track motor_idle index_interrupt settle_search read_address write_track_start
|
|
9
|
+
starting].freeze
|
|
10
|
+
MODE_NAMES = %w[read write address verify_track].freeze
|
|
11
|
+
|
|
12
|
+
# The controller in a keyed snapshot module (BL-D8-FDC): its own
|
|
13
|
+
# cycle count, the step of the command running and what the search
|
|
14
|
+
# is for by name, the registers and lines, the command's counters,
|
|
15
|
+
# and when its next step, its deadline and the next ID field fall,
|
|
16
|
+
# in its cycles from now, each absent when it never does.
|
|
17
|
+
def save_fields(out)
|
|
18
|
+
out.int("now", @now).text("phase", PHASE_NAMES.fetch(@phase)).text("mode", MODE_NAMES.fetch(@mode))
|
|
19
|
+
[["due_in", @due], ["deadline_in", @deadline], ["id_in", @id_at]].each do |key, at|
|
|
20
|
+
out.int(key, at - @now) unless at == NEVER
|
|
21
|
+
end
|
|
22
|
+
out.int("command", @command).int("track", @track).int("sector", @sector).int("data", @data)
|
|
23
|
+
out.int("status", @status).int("steps", @steps).int("count", @count).int("after_spin_up", @after_spin_up)
|
|
24
|
+
out.int("found", @found).int("index", @index).int("crc", @crc).int("write_id", @write_id).int("size", @size)
|
|
25
|
+
save_flag_fields(out)
|
|
26
|
+
out.bytes("bytes", @bytes).ints("syncs", @syncs.map { |sync| sync ? 1 : 0 })
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def load_fields(input)
|
|
30
|
+
@now = input.int("now", @now)
|
|
31
|
+
@phase = PHASE_NAMES.index(input.choice("phase", PHASE_NAMES, "idle")).to_i
|
|
32
|
+
@mode = MODE_NAMES.index(input.choice("mode", MODE_NAMES, "read")).to_i
|
|
33
|
+
@due = at_fields(input, "due_in")
|
|
34
|
+
@deadline = at_fields(input, "deadline_in")
|
|
35
|
+
@id_at = at_fields(input, "id_in")
|
|
36
|
+
load_register_fields(input)
|
|
37
|
+
load_flag_fields(input)
|
|
38
|
+
@bytes = input.bytes("bytes", "".b).bytes
|
|
39
|
+
@syncs = input.ints("syncs", []).map { |sync| sync == 1 }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def at_fields(input, key)
|
|
45
|
+
cycles = input.optional_int(key)
|
|
46
|
+
cycles.nil? ? NEVER : @now + cycles
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def load_register_fields(input)
|
|
50
|
+
@command = input.byte("command", @command)
|
|
51
|
+
@track = input.byte("track", @track)
|
|
52
|
+
@sector = input.byte("sector", @sector)
|
|
53
|
+
@data = input.byte("data", @data)
|
|
54
|
+
@status = input.byte("status", @status)
|
|
55
|
+
@steps = input.int("steps", @steps)
|
|
56
|
+
@count = input.int("count", @count)
|
|
57
|
+
@after_spin_up = input.int("after_spin_up", @after_spin_up)
|
|
58
|
+
@found = input.int("found", @found)
|
|
59
|
+
@index = input.int("index", @index)
|
|
60
|
+
@crc = input.int("crc", @crc)
|
|
61
|
+
@write_id = input.int("write_id", @write_id)
|
|
62
|
+
@size = input.int("size", @size)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def save_flag_fields(out)
|
|
66
|
+
out.bool("type1", @type1).bool("drq", @drq).bool("intrq", @intrq).bool("motor_on", @motor_on)
|
|
67
|
+
out.bool("inward", @inward).bool("crc_good", @crc_good).bool("gate_open", @gate_open).bool("late", @late)
|
|
68
|
+
out.bool("settling", @settling)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def load_flag_fields(input)
|
|
72
|
+
@type1 = input.bool("type1", @type1)
|
|
73
|
+
@drq = input.bool("drq", @drq)
|
|
74
|
+
@intrq = input.bool("intrq", @intrq)
|
|
75
|
+
@motor_on = input.bool("motor_on", @motor_on)
|
|
76
|
+
@inward = input.bool("inward", @inward)
|
|
77
|
+
@crc_good = input.bool("crc_good", @crc_good)
|
|
78
|
+
@gate_open = input.bool("gate_open", @gate_open)
|
|
79
|
+
@late = input.bool("late", @late)
|
|
80
|
+
@settling = input.bool("settling", @settling)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
class Mechanism
|
|
85
|
+
# The head, the motor and the disk-change switch in a keyed snapshot
|
|
86
|
+
# module (BL-D8-MECH), with the disk's angle as it stands `now`, on
|
|
87
|
+
# the controller's clock.
|
|
88
|
+
def save_fields(out, now)
|
|
89
|
+
out.int("cylinder", @cylinder).int("side", @side).int("angle", angle(now)).bool("motor", @motor)
|
|
90
|
+
out.bool("changed", @changed)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Puts `disk` under the head without flushing the one there, as a
|
|
94
|
+
# snapshot load replaces it.
|
|
95
|
+
def load_fields(input, disk, now)
|
|
96
|
+
@disk = disk
|
|
97
|
+
@cylinder = input.int("cylinder", @cylinder)
|
|
98
|
+
@side = input.masked("side", @side, 1)
|
|
99
|
+
@angle = input.int("angle", @angle)
|
|
100
|
+
@since = now
|
|
101
|
+
@motor = input.bool("motor", @motor)
|
|
102
|
+
@changed = input.bool("changed", @changed)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
class Disk
|
|
107
|
+
# A disk's fields in a keyed snapshot module (BL-D8-DISK): the image
|
|
108
|
+
# file's path and how it was opened, the image as last flushed,
|
|
109
|
+
# embedded, each track the head wrote since the disk went in, sector
|
|
110
|
+
# by sector as the WD1772 sees them, and the tracks written since the
|
|
111
|
+
# last flush.
|
|
112
|
+
module KeyedState
|
|
113
|
+
# The image's path, expanded, and whether it was opened read-only,
|
|
114
|
+
# for a disk from Disk.open. Nil for a disk made another way.
|
|
115
|
+
attr_reader :path, :read_only
|
|
116
|
+
|
|
117
|
+
# Notes the image's path and how it was opened.
|
|
118
|
+
def opened(path, read_only)
|
|
119
|
+
@path = File.expand_path(path)
|
|
120
|
+
@read_only = read_only
|
|
121
|
+
self
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def save_fields(out)
|
|
125
|
+
path = @path
|
|
126
|
+
out.text("path", path) if path
|
|
127
|
+
out.bool("read_only", @read_only == true)
|
|
128
|
+
image = @image
|
|
129
|
+
out.text("image.path", image.path.to_s).bytes("image", image.contents) if image
|
|
130
|
+
changed = @changed.keys.sort
|
|
131
|
+
out.ints("changed", changed)
|
|
132
|
+
changed.each { |index| save_track_fields(out, "track#{index}.", @tracks[index]) }
|
|
133
|
+
out.ints("written", @written.keys)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def load_track_fields(input)
|
|
137
|
+
@changed.clear
|
|
138
|
+
input.ints("changed", []).each do |index|
|
|
139
|
+
@tracks[index] = load_track_sectors(input, "track#{index}.")
|
|
140
|
+
@changed[index] = true
|
|
141
|
+
end
|
|
142
|
+
@written.clear
|
|
143
|
+
input.ints("written", []).each { |index| @written[index] = true }
|
|
144
|
+
self
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
private
|
|
148
|
+
|
|
149
|
+
def save_track_fields(out, prefix, track)
|
|
150
|
+
out.int("#{prefix}sectors", track.sectors.length)
|
|
151
|
+
track.sectors.each_with_index do |sector, number|
|
|
152
|
+
save_field_fields(out, "#{prefix}sector#{number}.id.", sector.id)
|
|
153
|
+
data = sector.data
|
|
154
|
+
save_field_fields(out, "#{prefix}sector#{number}.data.", data) if data
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def save_field_fields(out, prefix, field)
|
|
159
|
+
out.int("#{prefix}mark", field.mark).bytes("#{prefix}bytes", field.bytes)
|
|
160
|
+
out.bool("#{prefix}good", field.good).bool("#{prefix}deleted", field.deleted)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def load_track_sectors(input, prefix)
|
|
164
|
+
Track.new(Array.new(input.int("#{prefix}sectors", 0)) do |number|
|
|
165
|
+
id = load_field_fields(input, "#{prefix}sector#{number}.id.")
|
|
166
|
+
data = input.optional_int("#{prefix}sector#{number}.data.mark")
|
|
167
|
+
Track::Sector.new(id, data.nil? ? nil : load_field_fields(input, "#{prefix}sector#{number}.data."))
|
|
168
|
+
end)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def load_field_fields(input, prefix)
|
|
172
|
+
Track::Field.new(input.int("#{prefix}mark", 0), input.bytes("#{prefix}bytes", "".b).bytes,
|
|
173
|
+
input.bool("#{prefix}good", true), input.bool("#{prefix}deleted", false))
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
include KeyedState
|
|
178
|
+
|
|
179
|
+
# The disk a keyed snapshot module describes: its embedded image,
|
|
180
|
+
# with the tracks the module holds laid over it. The image takes
|
|
181
|
+
# writes back to its file only while that file is there and the
|
|
182
|
+
# reader isn't `detached`. With no image, the disk is the tracks
|
|
183
|
+
# alone.
|
|
184
|
+
def self.from_fields(input, detached: false)
|
|
185
|
+
path = input.text("path", "")
|
|
186
|
+
read_only = input.bool("read_only", false)
|
|
187
|
+
bytes = input.bytes("image", "".b).bytes
|
|
188
|
+
image_path = input.text("image.path", "")
|
|
189
|
+
disk = bytes.empty? ? Disk.new : Disk.new(image_from(image_path, bytes, read_only || detached))
|
|
190
|
+
disk.opened(path, read_only || bytes.empty?) unless path.empty?
|
|
191
|
+
disk.load_track_fields(input)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def self.image_from(path, bytes, read_only)
|
|
195
|
+
Storage::D81Image.new(File.file?(path) ? path : "", read_only:, bytes:)
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
class Bus
|
|
200
|
+
# The drive's RAM and the byte last on its data bus, in a keyed
|
|
201
|
+
# snapshot module (BL-D8-RAM).
|
|
202
|
+
def save_fields(out)
|
|
203
|
+
out.int("data", @data).bytes("ram", @ram.read(0, @ram.length))
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def load_fields(input)
|
|
207
|
+
@data = input.byte("data", @data)
|
|
208
|
+
ram = @ram.read(0, @ram.length)
|
|
209
|
+
@ram.write(0, input.bytes_into("ram", ram))
|
|
210
|
+
@watching = false
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# The drive's own fields in a keyed snapshot module (BL-D8): its
|
|
215
|
+
# model, its clock phase and cycle count, the ATN level it last saw
|
|
216
|
+
# and the host's lines as the serial port latched them. The fast
|
|
217
|
+
# serial direction and the ports' lines come from the 8520 once it
|
|
218
|
+
# is loaded.
|
|
219
|
+
module KeyedState
|
|
220
|
+
def save_fields(out)
|
|
221
|
+
settle!
|
|
222
|
+
out.text("model", model_name).int("phase", @phase).int("cycles", @cycles).bool("atn", @atn)
|
|
223
|
+
@serial_port.save_fields(out, "serial.")
|
|
224
|
+
out
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def load_fields(input)
|
|
228
|
+
settle!
|
|
229
|
+
input.choice("model", [model_name], model_name)
|
|
230
|
+
@phase = input.int("phase", @phase)
|
|
231
|
+
@cycles = input.int("cycles", @cycles)
|
|
232
|
+
@atn = input.bool("atn", @atn)
|
|
233
|
+
@serial_port.load_fields(input, "serial.")
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def restored!
|
|
237
|
+
@fast_serial_out = @cia.port_b_lines.anybits?(FAST_SERIAL_OUT)
|
|
238
|
+
ports_written
|
|
239
|
+
push_fast_output(@fast_serial_out ? fast_pins : 0)
|
|
240
|
+
forget_orbits
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# The drive as modules of its own, as the 1541's, with the 8520 and
|
|
244
|
+
# the WD1772 in place of the VIAs.
|
|
245
|
+
def save_modules(sections, name)
|
|
246
|
+
sections << Snapshot::Keyed.section(name) { |out| save_fields(out) }
|
|
247
|
+
sections << Snapshot::Keyed.section("#{name}-RAM") { |out| @bus.save_fields(out) }
|
|
248
|
+
sections << Snapshot::Keyed.section("#{name}-CIA") { |out| @cia.save_fields(out) }
|
|
249
|
+
sections << Snapshot::Keyed.section("#{name}-CPU") { |out| @cpu.save_fields(out) }
|
|
250
|
+
sections << Snapshot::Keyed.section("#{name}-FDC") { |out| @fdc.save_fields(out) }
|
|
251
|
+
now = @fdc.now
|
|
252
|
+
sections << Snapshot::Keyed.section("#{name}-MECH") { |out| @mechanism.save_fields(out, now) }
|
|
253
|
+
disk = @mechanism.disk
|
|
254
|
+
sections << Snapshot::Keyed.section("#{name}-DISK") { |out| disk.save_fields(out) } if disk
|
|
255
|
+
sections
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# The drive from its modules, `input` being its own. The mechanism
|
|
259
|
+
# takes the disk's angle on the WD1772's clock, so it loads after
|
|
260
|
+
# the controller.
|
|
261
|
+
def load_modules(modules, input, name)
|
|
262
|
+
load_fields(input)
|
|
263
|
+
@bus.load_fields(modules.required("#{name}-RAM"))
|
|
264
|
+
@cia.load_fields(modules.required("#{name}-CIA"))
|
|
265
|
+
@cpu.load_fields(modules.required("#{name}-CPU"))
|
|
266
|
+
@fdc.load_fields(modules.required("#{name}-FDC"))
|
|
267
|
+
disk = modules.optional("#{name}-DISK")
|
|
268
|
+
mechanism = modules.required("#{name}-MECH")
|
|
269
|
+
@mechanism.load_fields(mechanism, disk.nil? ? nil : Disk.from_fields(disk, detached: modules.detached?),
|
|
270
|
+
@fdc.now)
|
|
271
|
+
@cia.restored!
|
|
272
|
+
@cpu.restored!
|
|
273
|
+
restored!
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
include KeyedState
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
@@ -92,27 +92,6 @@ module Badline
|
|
|
92
92
|
def write(track)
|
|
93
93
|
@disk&.write(@cylinder, @side, track)
|
|
94
94
|
end
|
|
95
|
-
|
|
96
|
-
# The disk (Disk#save_state) and the motor, the head and the turn.
|
|
97
|
-
def save_state(out)
|
|
98
|
-
out.boolean(!@disk.nil?)
|
|
99
|
-
@disk&.save_state(out)
|
|
100
|
-
out.int(@cylinder).int(@side).int(@angle).int(@since).boolean(@motor).boolean(@changed)
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# Puts the state back, reusing the disk in when it's the one the state
|
|
104
|
-
# names (Disk::SavedState.load). A disk taken out is flushed.
|
|
105
|
-
def load_state(input)
|
|
106
|
-
disk = input.boolean? ? Disk::SavedState.load(input, @disk) : nil
|
|
107
|
-
flush unless disk.equal?(@disk)
|
|
108
|
-
@disk = disk
|
|
109
|
-
@cylinder = input.int
|
|
110
|
-
@side = input.int
|
|
111
|
-
@angle = input.int
|
|
112
|
-
@since = input.int
|
|
113
|
-
@motor = input.boolean?
|
|
114
|
-
@changed = input.boolean?
|
|
115
|
-
end
|
|
116
95
|
end
|
|
117
96
|
end
|
|
118
97
|
end
|
|
@@ -55,24 +55,6 @@ module Badline
|
|
|
55
55
|
|
|
56
56
|
# Whether the 1581 is device 8.
|
|
57
57
|
def drive1581_on_device8? = @drive1581&.device == KernalTrap::Routine::DEVICE
|
|
58
|
-
|
|
59
|
-
# The 1581 on the serial bus, with its device number.
|
|
60
|
-
def save_drive1581(out)
|
|
61
|
-
out.boolean(!@drive1581.nil?)
|
|
62
|
-
return unless @drive1581
|
|
63
|
-
|
|
64
|
-
out.int(@drive1581.device)
|
|
65
|
-
@drive1581.save_state(out)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def load_drive1581(input)
|
|
69
|
-
return detach_drive1581 unless input.boolean?
|
|
70
|
-
|
|
71
|
-
device = input.int
|
|
72
|
-
detach_drive1581 if @drive1581 && @drive1581.device != device
|
|
73
|
-
attach_drive1581(Model1581.new(device:)) unless @drive1581
|
|
74
|
-
@drive1581.load_state(input)
|
|
75
|
-
end
|
|
76
58
|
end
|
|
77
59
|
end
|
|
78
60
|
end
|
|
@@ -6,7 +6,6 @@ require "badline/drives/model1581/wd1772/stepping"
|
|
|
6
6
|
require "badline/drives/model1581/wd1772/sectors"
|
|
7
7
|
require "badline/drives/model1581/wd1772/sector_writes"
|
|
8
8
|
require "badline/drives/model1581/wd1772/tracks"
|
|
9
|
-
require "badline/drives/model1581/wd1772/saved_state"
|
|
10
9
|
|
|
11
10
|
module Badline
|
|
12
11
|
module Drives
|
|
@@ -45,7 +44,6 @@ module Badline
|
|
|
45
44
|
include Sectors
|
|
46
45
|
include SectorWrites
|
|
47
46
|
include Tracks
|
|
48
|
-
include SavedState
|
|
49
47
|
|
|
50
48
|
BYTE = 64
|
|
51
49
|
START = 32
|
|
@@ -9,7 +9,8 @@ require "badline/drives/model1581/wd1772"
|
|
|
9
9
|
require "badline/drives/model1581/cpu"
|
|
10
10
|
require "badline/drives/model1581/serial_port"
|
|
11
11
|
require "badline/drives/model1581/bus"
|
|
12
|
-
require "badline/drives/model1581/
|
|
12
|
+
require "badline/drives/model1581/keyed_state"
|
|
13
|
+
require "badline/drives/model1581/slot"
|
|
13
14
|
|
|
14
15
|
module Badline
|
|
15
16
|
module Drives
|
|
@@ -39,7 +40,6 @@ module Badline
|
|
|
39
40
|
class Model1581
|
|
40
41
|
include Engine::Core
|
|
41
42
|
include Engine::FastSerial
|
|
42
|
-
include SavedState
|
|
43
43
|
|
|
44
44
|
CLOCK_HZ = 2_000_000
|
|
45
45
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# The drives and the serial bus badline/core's machines share. The C128's
|
|
4
|
+
# 1571 stays out of the core: badline/c128 requires it.
|
|
5
|
+
require "badline/drives/datasette"
|
|
6
|
+
require "badline/drives/serial_bus"
|
|
7
|
+
require "badline/drives/model1541"
|
|
8
|
+
require "badline/drives/model1581"
|
data/lib/badline/frontend/app.rb
CHANGED
|
@@ -21,7 +21,7 @@ module Badline
|
|
|
21
21
|
@timeline = timeline
|
|
22
22
|
@snapshots = Snapshots.new(computer, options)
|
|
23
23
|
@screens = Screens.new(computer)
|
|
24
|
-
@led = DriveLed.
|
|
24
|
+
@led = DriveLed.new(computer)
|
|
25
25
|
@controls = Controls.new(computer)
|
|
26
26
|
@window = MachineWindow.new(@screens.screen, vsync: @pacer.vsync?)
|
|
27
27
|
@pacer.fit(@window.refresh_rate) if @pacer.vsync?
|
|
@@ -128,7 +128,7 @@ module Badline
|
|
|
128
128
|
@computer = computer
|
|
129
129
|
@screens.computer = computer
|
|
130
130
|
fit_window
|
|
131
|
-
@led = DriveLed.
|
|
131
|
+
@led = DriveLed.new(computer)
|
|
132
132
|
@controls.computer = computer
|
|
133
133
|
@gamepads.computer = computer
|
|
134
134
|
@sound.switch(computer.sound_source, computer.timing.clock_hz)
|
|
@@ -220,7 +220,7 @@ module Badline
|
|
|
220
220
|
renderer = @window.renderer
|
|
221
221
|
SDL.SDL_RenderClear(renderer)
|
|
222
222
|
SDL.SDL_RenderCopy(renderer, @window.texture, nil, nil)
|
|
223
|
-
@led
|
|
223
|
+
@led.draw(renderer, @window.width, @window.height)
|
|
224
224
|
@timeline.screenshots(@frames + 1).each { |path| Screenshot.write(renderer, path) }
|
|
225
225
|
SDL.SDL_RenderPresent(renderer)
|
|
226
226
|
end
|
|
@@ -10,7 +10,7 @@ module Badline
|
|
|
10
10
|
# attach, an --at key names nothing or an event fails, which it warns
|
|
11
11
|
# about.
|
|
12
12
|
def self.run(options)
|
|
13
|
-
error = Timeline.error(options.timeline)
|
|
13
|
+
error = Timeline.error(options.timeline, options.family)
|
|
14
14
|
unless error.empty?
|
|
15
15
|
warn "#{options.program}: #{error}"
|
|
16
16
|
return 1
|
|
@@ -29,6 +29,7 @@ module Badline
|
|
|
29
29
|
@arrows_port = 2
|
|
30
30
|
@mouse = Input::Mouse1351.new
|
|
31
31
|
@paddles = Input::Paddles.new
|
|
32
|
+
@held = {}
|
|
32
33
|
end
|
|
33
34
|
|
|
34
35
|
# Routes the input to another machine, the pot device going into its
|
|
@@ -73,10 +74,8 @@ module Badline
|
|
|
73
74
|
def key(scancode, down)
|
|
74
75
|
if joystick_mode? && Keys.joystick?(scancode)
|
|
75
76
|
joystick_key(scancode, down)
|
|
76
|
-
elsif @computer.family == :c128
|
|
77
|
-
c128_key(Keys.c128_key(scancode, @computer.mode), down)
|
|
78
77
|
else
|
|
79
|
-
|
|
78
|
+
machine_key(scancode, down)
|
|
80
79
|
end
|
|
81
80
|
end
|
|
82
81
|
|
|
@@ -104,6 +103,23 @@ module Badline
|
|
|
104
103
|
|
|
105
104
|
private
|
|
106
105
|
|
|
106
|
+
# A host key lets go of the key it pressed, though the C128 has
|
|
107
|
+
# switched between C64 and C128 mode since and maps it elsewhere.
|
|
108
|
+
def machine_key(scancode, down)
|
|
109
|
+
@held[scancode] = host_key(scancode) if down || !@held.key?(scancode)
|
|
110
|
+
key = @held[scancode]
|
|
111
|
+
@held.delete(scancode) unless down
|
|
112
|
+
if @computer.family == :c128
|
|
113
|
+
c128_key(key, down)
|
|
114
|
+
else
|
|
115
|
+
c64_key(key, down)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def host_key(scancode)
|
|
120
|
+
@computer.family == :c128 ? Keys.c128_key(scancode, @computer.mode) : Keys.c64_key(scancode)
|
|
121
|
+
end
|
|
122
|
+
|
|
107
123
|
# RESTORE isn't in the key matrix, so it goes to the machine instead.
|
|
108
124
|
def c64_key(key, down)
|
|
109
125
|
if key == :restore
|
|
@@ -2,48 +2,71 @@
|
|
|
2
2
|
|
|
3
3
|
module Badline
|
|
4
4
|
module Frontend
|
|
5
|
-
# The true drive's
|
|
6
|
-
# border: bright while the DOS lights it, as it
|
|
7
|
-
# open or after an error, and dim otherwise
|
|
5
|
+
# The true drive's LEDs, drawn over the bottom right corner of the
|
|
6
|
+
# border: the red activity LED, bright while the DOS lights it, as it
|
|
7
|
+
# does while a file is open or after an error, and dim otherwise, and
|
|
8
|
+
# left of it the green power LED, which a 1581 flashes after an error.
|
|
9
|
+
# They follow whichever true drive the machine has, one plugged in
|
|
10
|
+
# after start among them, and are drawn only while it has one.
|
|
8
11
|
class DriveLed
|
|
9
12
|
WIDTH = 12
|
|
10
13
|
HEIGHT = 4
|
|
11
14
|
|
|
15
|
+
# The power LED's distance left of the activity LED.
|
|
16
|
+
POWER_OFFSET = WIDTH + 4
|
|
17
|
+
|
|
12
18
|
LIT = [0xff, 0x20, 0x20].freeze
|
|
13
19
|
DARK = [0x40, 0x00, 0x00].freeze
|
|
20
|
+
POWER_LIT = [0x20, 0xff, 0x20].freeze
|
|
21
|
+
POWER_DARK = [0x00, 0x40, 0x00].freeze
|
|
14
22
|
|
|
15
|
-
#
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
drive ? new(drive) : nil
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# Sets SDL.led_rect to where the LED goes on a screen `width` by
|
|
22
|
-
# `height`.
|
|
23
|
-
def self.place(width, height)
|
|
23
|
+
# Sets SDL.led_rect to where the activity LED goes on a screen `width`
|
|
24
|
+
# by `height`, or with `offset` that many pixels left of it.
|
|
25
|
+
def self.place(width, height, offset = 0)
|
|
24
26
|
rect = SDL.led_rect
|
|
25
|
-
SDL.rect_x(rect, width - WIDTH - 8)
|
|
27
|
+
SDL.rect_x(rect, width - WIDTH - 8 - offset)
|
|
26
28
|
SDL.rect_y(rect, height - HEIGHT - 6)
|
|
27
29
|
SDL.rect_w(rect, WIDTH)
|
|
28
30
|
SDL.rect_h(rect, HEIGHT)
|
|
29
31
|
end
|
|
30
32
|
|
|
31
|
-
def initialize(
|
|
32
|
-
@
|
|
33
|
+
def initialize(computer)
|
|
34
|
+
@computer = computer
|
|
33
35
|
end
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
# Whether the machine has a true drive, and so LEDs to draw.
|
|
38
|
+
def shown? = !@computer.true_drive.nil?
|
|
39
|
+
|
|
40
|
+
def lit?
|
|
41
|
+
drive = @computer.true_drive
|
|
42
|
+
drive.nil? ? false : drive.led_on?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def power_lit?
|
|
46
|
+
drive = @computer.true_drive
|
|
47
|
+
drive.nil? ? false : drive.power_led_on?
|
|
48
|
+
end
|
|
36
49
|
|
|
37
50
|
def color = lit? ? LIT : DARK
|
|
38
51
|
|
|
39
|
-
|
|
40
|
-
|
|
52
|
+
def power_color = power_lit? ? POWER_LIT : POWER_DARK
|
|
53
|
+
|
|
54
|
+
# Fills the LEDs' rectangles on a screen `width` by `height` in their
|
|
55
|
+
# colours, then puts back the black that RenderClear clears with.
|
|
41
56
|
def draw(renderer, width, height)
|
|
42
|
-
|
|
43
|
-
|
|
57
|
+
return unless shown?
|
|
58
|
+
|
|
59
|
+
fill(renderer, width, height, 0, color)
|
|
60
|
+
fill(renderer, width, height, POWER_OFFSET, power_color)
|
|
61
|
+
SDL.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def fill(renderer, width, height, offset, rgb)
|
|
67
|
+
DriveLed.place(width, height, offset)
|
|
44
68
|
SDL.SDL_SetRenderDrawColor(renderer, rgb[0], rgb[1], rgb[2], 255)
|
|
45
69
|
SDL.SDL_RenderFillRect(renderer, SDL.led_rect)
|
|
46
|
-
SDL.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255)
|
|
47
70
|
end
|
|
48
71
|
end
|
|
49
72
|
end
|
|
@@ -8,8 +8,8 @@ module Badline
|
|
|
8
8
|
# name. A disk or tape picked goes straight in, and a save loads.
|
|
9
9
|
class MenuDialogs
|
|
10
10
|
EXTENSIONS = {
|
|
11
|
-
disk:
|
|
12
|
-
|
|
11
|
+
disk: Media::Extensions::DEVICE8, tape: Media::Extensions.of(%i[tape]),
|
|
12
|
+
cartridge: Media::Extensions.of(%i[cartridge]), program: Media::Extensions::ALL, snapshot: %w[.vsf]
|
|
13
13
|
}.freeze
|
|
14
14
|
TITLES = { disk: "INSERT A DISK", tape: "INSERT A TAPE", cartridge: "INSERT A CARTRIDGE",
|
|
15
15
|
program: "QUICK OPEN", snapshot: "LOAD A SAVE" }.freeze
|
|
@@ -20,6 +20,7 @@ module Badline
|
|
|
20
20
|
def initialize(computer, options)
|
|
21
21
|
@computer = computer
|
|
22
22
|
@at_finish = options.save_snapshot
|
|
23
|
+
@vice = options.vice?
|
|
23
24
|
@autosave = options.frames.zero?
|
|
24
25
|
@autosave_at = AUTOSAVE_FRAMES
|
|
25
26
|
end
|
|
@@ -128,11 +129,21 @@ module Badline
|
|
|
128
129
|
end
|
|
129
130
|
|
|
130
131
|
def finish
|
|
131
|
-
|
|
132
|
+
return if @at_finish.empty?
|
|
133
|
+
|
|
134
|
+
@vice ? export(@at_finish) : save(@at_finish)
|
|
132
135
|
end
|
|
133
136
|
|
|
134
137
|
private
|
|
135
138
|
|
|
139
|
+
# Saves the machine with VICE's modules too, and warns when it can't.
|
|
140
|
+
def export(path)
|
|
141
|
+
@computer.export_snapshot(path)
|
|
142
|
+
puts "Saved #{path} for badline and VICE"
|
|
143
|
+
rescue Snapshot::FormatError, SystemCallError => e
|
|
144
|
+
warn "badline: #{path}: #{e.message}"
|
|
145
|
+
end
|
|
146
|
+
|
|
136
147
|
def restore_from(path)
|
|
137
148
|
@computer = Snapshot.load(path) { |line| puts line }
|
|
138
149
|
puts "Restored #{name_of(path)} from #{path}"
|