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
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "zlib"
|
|
4
|
+
require "badline/snapshot/container"
|
|
5
|
+
|
|
6
|
+
module Badline
|
|
7
|
+
module Snapshot
|
|
8
|
+
# A snapshot module as keyed, typed records, which a later badline
|
|
9
|
+
# reads by name: one it doesn't know is skipped, and one that isn't
|
|
10
|
+
# there leaves the value a freshly built machine has.
|
|
11
|
+
#
|
|
12
|
+
# The payload is deflated. Inside, each record is the key's length and
|
|
13
|
+
# the key (ASCII, lower snake case with dots between sub-units), a
|
|
14
|
+
# one-byte type tag, then the value's length and the value. Lengths are
|
|
15
|
+
# BER-compressed (Ruby's pack "w"), and so are integers, each folded to
|
|
16
|
+
# a natural number (0, -1, 1, -2 ... as 0, 1, 2, 3 ...). The value's
|
|
17
|
+
# length lets a reader skip a tag it doesn't know.
|
|
18
|
+
#
|
|
19
|
+
# A module's header version is MAJOR.MINOR. The major number is this
|
|
20
|
+
# record encoding, and a reader refuses another one. Fields carry no
|
|
21
|
+
# version: a changed meaning gets a new key.
|
|
22
|
+
module Keyed
|
|
23
|
+
MAJOR = 1
|
|
24
|
+
MINOR = 0
|
|
25
|
+
|
|
26
|
+
INT = 0x01
|
|
27
|
+
BOOL = 0x02
|
|
28
|
+
BYTES = 0x03
|
|
29
|
+
INTS = 0x04
|
|
30
|
+
TEXT = 0x05
|
|
31
|
+
|
|
32
|
+
KEY = /\A[a-z0-9_]+(\.[a-z0-9_]+)*\z/
|
|
33
|
+
|
|
34
|
+
# The values an int record holds: what a 64-bit integer holds once
|
|
35
|
+
# zigzag doubles it, which a native build's integers can't exceed.
|
|
36
|
+
VALUES = (-(1 << 62))..((1 << 62) - 1)
|
|
37
|
+
|
|
38
|
+
module_function
|
|
39
|
+
|
|
40
|
+
def ber(number) = [number].pack("w")
|
|
41
|
+
|
|
42
|
+
# Folds an Integer in VALUES to a natural number, as a
|
|
43
|
+
# native build's 64-bit integers hold it.
|
|
44
|
+
def zigzag(value) = value.negative? ? ((-value - 1) << 1) | 1 : value << 1
|
|
45
|
+
|
|
46
|
+
def unzigzag(folded) = folded.odd? ? -(folded >> 1) - 1 : folded >> 1
|
|
47
|
+
|
|
48
|
+
# The module `name`, with the records the block writes to the Writer
|
|
49
|
+
# it yields.
|
|
50
|
+
def section(name)
|
|
51
|
+
out = Writer.new
|
|
52
|
+
yield out
|
|
53
|
+
out.section(name)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
require "badline/snapshot/keyed/cursor"
|
|
60
|
+
require "badline/snapshot/keyed/writer"
|
|
61
|
+
require "badline/snapshot/keyed/report"
|
|
62
|
+
require "badline/snapshot/keyed/reader"
|
|
63
|
+
require "badline/snapshot/keyed/recorder"
|
|
64
|
+
require "badline/snapshot/keyed/modules"
|
|
@@ -2,83 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
module Badline
|
|
4
4
|
module Snapshot
|
|
5
|
-
# The BADLINE module
|
|
6
|
-
#
|
|
7
|
-
#
|
|
5
|
+
# The BADLINE module badline 0.13 and earlier saved the machine in, a
|
|
6
|
+
# positional layout only the version that wrote it reads. All that is
|
|
7
|
+
# left of it is reading which version that was, for the refusal
|
|
8
|
+
# (Image#load).
|
|
8
9
|
#
|
|
9
10
|
# The payload is deflated. Inside, a little-endian 32-bit length leads
|
|
10
11
|
# a run of BER-compressed integers (Ruby's pack "w"): the number of
|
|
11
|
-
# values and of strings, each string's length, then the values
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
# A State only restores in the badline version that wrote it, since
|
|
16
|
-
# each chip writes its fields as it holds them.
|
|
12
|
+
# values and of strings, each string's length, then the values. The
|
|
13
|
+
# strings follow, one after another: the family's marker first, then
|
|
14
|
+
# the badline version.
|
|
17
15
|
module MachineState
|
|
18
16
|
NAME = "BADLINE"
|
|
19
|
-
MAJOR = 2
|
|
20
|
-
MINOR = 0
|
|
21
|
-
|
|
22
|
-
# The values a 64-bit integer holds once encode doubles them, which a
|
|
23
|
-
# native build's integers can't exceed.
|
|
24
|
-
VALUES = (-(1 << 62))..((1 << 62) - 1)
|
|
25
17
|
|
|
26
18
|
module_function
|
|
27
19
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
unless section.major == MAJOR
|
|
34
|
-
raise FormatError, "#{NAME} #{section.version} was written by another badline version, " \
|
|
35
|
-
"and this one reads #{MAJOR}.#{MINOR}"
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
decode(Zlib.inflate(section.data))
|
|
39
|
-
rescue Zlib::Error => e
|
|
40
|
-
raise FormatError, "#{NAME} is damaged: #{e.message}"
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def encode(state)
|
|
44
|
-
values = state.values
|
|
45
|
-
strings = state.strings
|
|
46
|
-
numbers = [values.length, strings.length]
|
|
47
|
-
strings.each { |string| numbers << string.bytesize }
|
|
48
|
-
values.each do |value|
|
|
49
|
-
raise RangeError, "#{value} is too large for a snapshot" unless VALUES.cover?(value)
|
|
50
|
-
|
|
51
|
-
numbers << (value.negative? ? (-2 * value) - 1 : 2 * value)
|
|
52
|
-
end
|
|
53
|
-
index = numbers.pack("w*")
|
|
54
|
-
[index.bytesize].pack("V") + index + strings.join
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def decode(bytes)
|
|
58
|
-
raise FormatError, "#{NAME} ends early" if bytes.bytesize < 4
|
|
20
|
+
# The badline version that saved the module, or an empty string when
|
|
21
|
+
# it is too damaged to say.
|
|
22
|
+
def written_by(section)
|
|
23
|
+
bytes = Zlib.inflate(section.data)
|
|
24
|
+
return "" if bytes.bytesize < 4
|
|
59
25
|
|
|
60
26
|
length = bytes.byteslice(0, 4).unpack1("V").to_i
|
|
61
27
|
numbers = bytes.byteslice(4, length).to_s.unpack("w*").map(&:to_i)
|
|
62
|
-
value_count = numbers.fetch(0, 0)
|
|
63
28
|
string_count = numbers.fetch(1, 0)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
State.new(values(numbers, 2 + string_count), strings(bytes, 4 + length, numbers.slice(2, string_count)))
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def values(numbers, from)
|
|
70
|
-
Array.new(numbers.length - from) do |i|
|
|
71
|
-
folded = numbers[from + i]
|
|
72
|
-
folded.odd? ? -((folded + 1) / 2) : folded / 2
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def strings(bytes, pos, lengths)
|
|
77
|
-
lengths.map do |length|
|
|
78
|
-
raise FormatError, "#{NAME} ends early" if pos + length > bytes.bytesize
|
|
29
|
+
return "" if string_count < 2 || numbers.length < 4
|
|
79
30
|
|
|
80
|
-
|
|
81
|
-
|
|
31
|
+
pos = 4 + length + numbers[2]
|
|
32
|
+
bytes.byteslice(pos, numbers[3]).to_s
|
|
33
|
+
rescue Zlib::Error
|
|
34
|
+
""
|
|
82
35
|
end
|
|
83
36
|
end
|
|
84
37
|
end
|
|
@@ -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,21 @@ 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 or a C128's snapshot
|
|
39
|
+
# is in a container named as xvic or x128 names its machine.
|
|
40
|
+
def dump(computer) = Image.of(computer).to_s
|
|
41
|
+
|
|
42
|
+
def read(path) = Image.new(Container.parse(File.binread(path)), name: File.basename(path))
|
|
40
43
|
|
|
41
44
|
# A new machine, built as the snapshot's was and restored from it.
|
|
42
45
|
# Yields a line for each thing it leaves out.
|
|
@@ -47,12 +50,32 @@ module Badline
|
|
|
47
50
|
# snapshot that fails leaves the machine as it was.
|
|
48
51
|
def restore(computer, path, &) = read(path).restore(computer, &)
|
|
49
52
|
|
|
50
|
-
# A machine's snapshots as .vsf files. C64, Vic20 and
|
|
51
|
-
# include it.
|
|
53
|
+
# A machine's snapshots, as .vsf files and in memory. C64, Vic20 and
|
|
54
|
+
# C128 each include it.
|
|
52
55
|
module Files
|
|
53
56
|
def save_snapshot(path) = Snapshot.save(self, path)
|
|
54
57
|
|
|
58
|
+
# Saves the snapshot with VICE's modules too, for a C64, so x64sc
|
|
59
|
+
# opens it as well as badline.
|
|
60
|
+
def export_snapshot(path) = Snapshot.export(self, path)
|
|
61
|
+
|
|
55
62
|
def restore_snapshot(path, &) = Snapshot.restore(self, path, &)
|
|
63
|
+
|
|
64
|
+
# The machine's snapshot in memory (Image.of), which settles it as a
|
|
65
|
+
# save does.
|
|
66
|
+
def snapshot = Image.of(self)
|
|
67
|
+
|
|
68
|
+
# Takes the machine back to an Image from #snapshot. The machine keeps
|
|
69
|
+
# its chips, its traps and its callbacks, and puts in the cartridge,
|
|
70
|
+
# drives and tape the image has, taking out any it hasn't. Raises
|
|
71
|
+
# Snapshot::FormatError for an image of a machine built another way.
|
|
72
|
+
# The image goes into a new machine first, so one that fails leaves
|
|
73
|
+
# this machine as it was. What it leaves out goes unsaid:
|
|
74
|
+
# Image#restore returns it in a Report.
|
|
75
|
+
def restore(image)
|
|
76
|
+
image.restore(self) { nil }
|
|
77
|
+
self
|
|
78
|
+
end
|
|
56
79
|
end
|
|
57
80
|
end
|
|
58
81
|
|
|
@@ -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
|
|
@@ -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,11 +5,14 @@ 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
|
|
|
@@ -28,10 +31,11 @@ module Badline
|
|
|
28
31
|
def initialize(path, bytes: nil)
|
|
29
32
|
@path = File.expand_path(path)
|
|
30
33
|
@bytes = bytes || File.binread(path).bytes
|
|
31
|
-
|
|
34
|
+
signature = @bytes[0, SIGNATURE.length]
|
|
35
|
+
raise FormatError, "Missing TAP signature" unless [SIGNATURE, C16_SIGNATURE].include?(signature)
|
|
32
36
|
|
|
33
37
|
@version = @bytes[0x0c].to_i
|
|
34
|
-
raise FormatError, "Unsupported TAP version #{@version}" if @version >
|
|
38
|
+
raise FormatError, "Unsupported TAP version #{@version}" if @version > 2
|
|
35
39
|
|
|
36
40
|
@platform = @bytes[0x0d].to_i
|
|
37
41
|
|
|
@@ -55,17 +59,16 @@ module Badline
|
|
|
55
59
|
# Records a pulse `cycles` long at the position, in place of the rest
|
|
56
60
|
# of the tape: a byte of units of 8 cycles, or a zero and the 24-bit
|
|
57
61
|
# cycle count for a long one (a lone zero, an overflow, on a version 0
|
|
58
|
-
# tape).
|
|
62
|
+
# tape). A version 2 tape records it as two equal halves.
|
|
59
63
|
def record_pulse(cycles)
|
|
60
|
-
units = (cycles + 4) / 8
|
|
61
|
-
encoded = if units.between?(1, 0xff) then [units]
|
|
62
|
-
elsif version.zero? then [0]
|
|
63
|
-
else
|
|
64
|
-
count = [cycles, 0xffffff].min
|
|
65
|
-
[0, count & 0xff, (count >> 8) & 0xff, count >> 16]
|
|
66
|
-
end
|
|
67
64
|
@bytes.slice!(@pos..)
|
|
68
|
-
|
|
65
|
+
if version == 2
|
|
66
|
+
half = cycles / 2
|
|
67
|
+
@bytes.concat(encode(cycles - half))
|
|
68
|
+
@bytes.concat(encode(half))
|
|
69
|
+
else
|
|
70
|
+
@bytes.concat(encode(cycles))
|
|
71
|
+
end
|
|
69
72
|
@pos = @end = @bytes.length
|
|
70
73
|
end
|
|
71
74
|
|
|
@@ -77,20 +80,45 @@ module Badline
|
|
|
77
80
|
File.binwrite(@path, @bytes.pack("C*"))
|
|
78
81
|
end
|
|
79
82
|
|
|
83
|
+
# Whether each byte times a half wave, as on a version 2 tape.
|
|
84
|
+
def half_waves? = version == 2
|
|
85
|
+
|
|
80
86
|
# Cycles until the next falling edge, or nil once the tape has run out.
|
|
87
|
+
# On a version 2 tape that is two half waves, or one left at the end.
|
|
81
88
|
def next_pulse
|
|
82
89
|
return if end?
|
|
90
|
+
return next_time unless half_waves?
|
|
91
|
+
|
|
92
|
+
first = next_time
|
|
93
|
+
end? ? first : first + next_time
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Cycles until the read line's next edge on a version 2 tape, or nil
|
|
97
|
+
# once the tape has run out.
|
|
98
|
+
def next_half_wave
|
|
99
|
+
next_time unless end?
|
|
100
|
+
end
|
|
83
101
|
|
|
102
|
+
private
|
|
103
|
+
|
|
104
|
+
def next_time
|
|
84
105
|
byte = @bytes[@pos]
|
|
85
106
|
@pos += 1
|
|
86
107
|
return byte * 8 unless byte.zero?
|
|
87
108
|
|
|
88
|
-
# $00 is an overflow in version 0 and a 24-bit cycle count
|
|
89
|
-
# version 1.
|
|
109
|
+
# $00 is an overflow in version 0 and a 24-bit cycle count from
|
|
110
|
+
# version 1 on.
|
|
90
111
|
version.zero? ? OVERFLOW : long_pulse
|
|
91
112
|
end
|
|
92
113
|
|
|
93
|
-
|
|
114
|
+
def encode(cycles)
|
|
115
|
+
units = (cycles + 4) / 8
|
|
116
|
+
return [units] if units.between?(1, 0xff)
|
|
117
|
+
return [0] if version.zero?
|
|
118
|
+
|
|
119
|
+
count = [cycles, 0xffffff].min
|
|
120
|
+
[0, count & 0xff, (count >> 8) & 0xff, count >> 16]
|
|
121
|
+
end
|
|
94
122
|
|
|
95
123
|
# The stated size disagrees with the file in the wild, and a few dumps
|
|
96
124
|
# leave it zeroed altogether.
|
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
|