badline 0.15.1 → 0.16.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 +39 -0
- data/CLAUDE.md +8 -7
- data/README.md +102 -6
- data/doc/pinned-behaviour.md +67 -0
- data/doc/snapshot-format.md +213 -18
- data/doc/snapshots.md +14 -0
- data/lib/badline/c64/common.rb +1 -1
- data/lib/badline/chips/crtc/keyed_state.rb +46 -0
- data/lib/badline/chips/crtc.rb +163 -0
- data/lib/badline/chips/pia/control_lines.rb +138 -0
- data/lib/badline/chips/pia/keyed_parts.rb +56 -0
- data/lib/badline/chips/pia.rb +138 -0
- data/lib/badline/chips/vic/register_log.rb +1 -4
- data/lib/badline/core.rb +3 -0
- data/lib/badline/drives/ieee_bus.rb +28 -0
- data/lib/badline/drives/model1551/cable.rb +5 -2
- data/lib/badline/drives/model1551/tia.rb +13 -34
- data/lib/badline/drives/model1551.rb +26 -4
- data/lib/badline/drives.rb +1 -0
- data/lib/badline/frontend/app.rb +1 -1
- data/lib/badline/frontend/controls.rb +23 -3
- data/lib/badline/frontend/gamepads.rb +10 -3
- data/lib/badline/frontend/keys.rb +88 -0
- data/lib/badline/frontend/media_slots.rb +1 -0
- data/lib/badline/frontend/menu/menu_dialogs.rb +2 -1
- data/lib/badline/frontend/menu/menu_media.rb +27 -28
- data/lib/badline/frontend/menu/menu_pages.rb +15 -2
- data/lib/badline/frontend/menu/menu_ports.rb +22 -1
- data/lib/badline/frontend/menu/pause_menu.rb +1 -0
- data/lib/badline/frontend/pet_keyboard.rb +124 -0
- data/lib/badline/frontend/screens.rb +2 -1
- data/lib/badline/frontend/timeline.rb +16 -9
- data/lib/badline/frontend.rb +1 -0
- data/lib/badline/kernal_trap/dos/writes.rb +3 -1
- data/lib/badline/kernal_trap/dos.rb +6 -1
- data/lib/badline/kernal_trap/frames.rb +117 -0
- data/lib/badline/kernal_trap/ieee.rb +148 -0
- data/lib/badline/kernal_trap/ieee_layout.rb +113 -0
- data/lib/badline/kernal_trap/keyed_state.rb +4 -4
- data/lib/badline/kernal_trap/routine.rb +3 -53
- data/lib/badline/kernal_trap/serial.rb +4 -102
- data/lib/badline/kernal_trap/steps.rb +64 -0
- data/lib/badline/kernal_trap.rb +4 -0
- data/lib/badline/machine/keyboard_buffer.rb +8 -0
- data/lib/badline/machine/settling.rb +1 -1
- data/lib/badline/machine.rb +28 -6
- data/lib/badline/media/extensions.rb +5 -2
- data/lib/badline/media/pet_media.rb +40 -0
- data/lib/badline/media/program.rb +14 -2
- data/lib/badline/media/vic20_media.rb +2 -2
- data/lib/badline/media.rb +36 -16
- data/lib/badline/options/family.rb +17 -6
- data/lib/badline/options/help.rb +19 -3
- data/lib/badline/options/table.rb +14 -2
- data/lib/badline/options/validation.rb +68 -5
- data/lib/badline/options.rb +31 -19
- data/lib/badline/pet/bus/expansion.rb +106 -0
- data/lib/badline/pet/bus.rb +204 -0
- data/lib/badline/pet/canvas.rb +97 -0
- data/lib/badline/pet/cassettes.rb +63 -0
- data/lib/badline/pet/characters.rb +26 -0
- data/lib/badline/pet/cpu.rb +10 -0
- data/lib/badline/pet/crtc_video.rb +142 -0
- data/lib/badline/pet/discrete_video.rb +83 -0
- data/lib/badline/pet/ieee_ports.rb +66 -0
- data/lib/badline/pet/ieee_traps.rb +75 -0
- data/lib/badline/pet/keyboard_ports.rb +74 -0
- data/lib/badline/pet/keyed_modules.rb +85 -0
- data/lib/badline/pet/keyed_parts.rb +123 -0
- data/lib/badline/pet/keyed_state.rb +42 -0
- data/lib/badline/pet/model.rb +113 -0
- data/lib/badline/pet/rom_sets.rb +65 -0
- data/lib/badline/pet/sound.rb +128 -0
- data/lib/badline/pet/via.rb +10 -0
- data/lib/badline/pet/via_ports.rb +19 -0
- data/lib/badline/pet.rb +226 -0
- data/lib/badline/plus4/keyed_state.rb +5 -3
- data/lib/badline/plus4/tcbm_drive.rb +14 -0
- data/lib/badline/plus4.rb +1 -1
- data/lib/badline/roms/README +137 -0
- data/lib/badline/roms/pet/basic1.rom +0 -0
- data/lib/badline/roms/pet/basic2.rom +0 -0
- data/lib/badline/roms/pet/basic4.rom +0 -0
- data/lib/badline/roms/pet/characters1.rom +0 -0
- data/lib/badline/roms/pet/characters2.rom +0 -0
- data/lib/badline/roms/pet/editor1.rom +0 -0
- data/lib/badline/roms/pet/editor2-b.rom +0 -0
- data/lib/badline/roms/pet/editor2-n.rom +0 -0
- data/lib/badline/roms/pet/editor4-40-n-50hz.rom +0 -0
- data/lib/badline/roms/pet/editor4-40-n-60hz.rom +0 -0
- data/lib/badline/roms/pet/editor4-80-b-50hz-0283.rom +0 -0
- data/lib/badline/roms/pet/editor4-80-b-50hz.rom +0 -0
- data/lib/badline/roms/pet/editor4-80-b-60hz.rom +0 -0
- data/lib/badline/roms/pet/editor4-b.rom +0 -0
- data/lib/badline/roms/pet/editor4-n.rom +0 -0
- data/lib/badline/roms/pet/kernal1.rom +0 -0
- data/lib/badline/roms/pet/kernal2.rom +0 -0
- data/lib/badline/roms/pet/kernal4.rom +0 -0
- data/lib/badline/snapshot/container.rb +2 -0
- data/lib/badline/snapshot/field_doc/markdown.rb +1 -1
- data/lib/badline/snapshot/field_doc.rb +16 -3
- data/lib/badline/snapshot/image.rb +14 -7
- data/lib/badline/snapshot/pet_setup.rb +71 -0
- data/lib/badline/snapshot/storage_setup.rb +7 -1
- data/lib/badline/snapshot.rb +9 -5
- data/lib/badline/storage/d80_image.rb +48 -0
- data/lib/badline/storage/d82_image.rb +21 -0
- data/lib/badline/storage/tap.rb +16 -3
- data/lib/badline/storage.rb +2 -0
- data/lib/badline/support/pet_checkpoint.rb +38 -0
- data/lib/badline/timing.rb +5 -4
- data/lib/badline/version.rb +1 -1
- data/lib/badline/vic20/attachments.rb +7 -2
- data/lib/badline/vic20/bus/keyed_state.rb +5 -4
- data/lib/badline/vic20/bus.rb +5 -0
- data/lib/badline/vic20.rb +1 -1
- metadata +55 -1
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Snapshot
|
|
5
|
+
# How a PET was built: its model's name, one of PET::Model::ALL, its
|
|
6
|
+
# RAM below $8000 in K and its editor's frame rate, the arguments
|
|
7
|
+
# PET.new takes, and the ROMs it runs by file: BASIC, the editor, the
|
|
8
|
+
# KERNAL and the characters.
|
|
9
|
+
PETSetup = Data.define(:model, :ram_kb, :refresh_hz, :basic, :editor, :kernal, :characters)
|
|
10
|
+
|
|
11
|
+
class PETSetup
|
|
12
|
+
MODELS = PET::Model::ALL.map(&:name).freeze
|
|
13
|
+
|
|
14
|
+
REFRESH_RATES = [50, 60].freeze
|
|
15
|
+
|
|
16
|
+
# The setup of `machine`.
|
|
17
|
+
def self.of(machine)
|
|
18
|
+
model = machine.model
|
|
19
|
+
refresh_hz = machine.refresh_hz
|
|
20
|
+
new(model: model.name, ram_kb: machine.ram.length >> 10, refresh_hz:, basic: model.basic,
|
|
21
|
+
editor: model.editor(refresh_hz), kernal: model.kernal, characters: model.characters)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# The model by name, the RAM, the frame rate and the ROMs, in a keyed
|
|
25
|
+
# snapshot module.
|
|
26
|
+
def write_fields(out)
|
|
27
|
+
out.text("model", model).int("ram_kb", ram_kb).int("refresh_hz", refresh_hz)
|
|
28
|
+
out.text("rom.basic", basic).text("rom.editor", editor).text("rom.kernal", kernal)
|
|
29
|
+
out.text("rom.characters", characters)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# A ROM the snapshot doesn't name is the model's own.
|
|
33
|
+
def self.read_fields(input)
|
|
34
|
+
profile = PET::Model.named(input.choice("model", MODELS, PET::Model::DEFAULT))
|
|
35
|
+
ram_kb = input.int("ram_kb", profile.ram_kb)
|
|
36
|
+
unless PET::Model::RAM_SIZES.include?(ram_kb)
|
|
37
|
+
raise FormatError, "the snapshot is of a PET with #{ram_kb}K of RAM, which badline doesn't build"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
refresh_hz = input.int("refresh_hz", profile.crtc? ? 50 : 60)
|
|
41
|
+
unless REFRESH_RATES.include?(refresh_hz)
|
|
42
|
+
raise FormatError, "the snapshot is of a PET at #{refresh_hz} Hz, which badline doesn't build"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
refresh_hz = 60 unless profile.crtc?
|
|
46
|
+
new(model: profile.name, ram_kb:, refresh_hz:, basic: input.text("rom.basic", profile.basic),
|
|
47
|
+
editor: input.text("rom.editor", profile.editor(refresh_hz)),
|
|
48
|
+
kernal: input.text("rom.kernal", profile.kernal),
|
|
49
|
+
characters: input.text("rom.characters", profile.characters))
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# A machine built this way, at power-on, with the BASIC and editor
|
|
53
|
+
# PET::ROMSets names for its ROMs.
|
|
54
|
+
def build
|
|
55
|
+
version = PET::ROMSets::BASICS.find { |_, roms| roms.first == basic }&.first
|
|
56
|
+
PET.new(model:, ram_kb:, refresh_hz:, basic: version, editor: PET::ROMSets::EDITORS.key(editor))
|
|
57
|
+
rescue ArgumentError => e
|
|
58
|
+
raise FormatError, "the snapshot is of a #{self}, which badline doesn't build: #{e.message}"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# The ROMs are named where they aren't the model's own.
|
|
62
|
+
def to_s
|
|
63
|
+
text = "#{model} with #{ram_kb}K at #{refresh_hz} Hz"
|
|
64
|
+
roms = [basic, editor, kernal, characters]
|
|
65
|
+
profile = PET::Model.named(model)
|
|
66
|
+
stock = [profile.basic, profile.editor(refresh_hz), profile.kernal, profile.characters]
|
|
67
|
+
roms == stock ? text : "#{text} running #{roms.join(', ')}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -11,6 +11,8 @@ module Badline
|
|
|
11
11
|
D71 = 2
|
|
12
12
|
D81 = 3
|
|
13
13
|
T64_ARCHIVE = 4
|
|
14
|
+
D80 = 5
|
|
15
|
+
D82 = 6
|
|
14
16
|
|
|
15
17
|
module_function
|
|
16
18
|
|
|
@@ -18,6 +20,8 @@ module Badline
|
|
|
18
20
|
return D71 if image.is_a?(Storage::D71Image)
|
|
19
21
|
return D64 if image.is_a?(Storage::D64Image)
|
|
20
22
|
return D81 if image.is_a?(Storage::D81Image)
|
|
23
|
+
return D82 if image.is_a?(Storage::D82Image)
|
|
24
|
+
return D80 if image.is_a?(Storage::D80Image)
|
|
21
25
|
|
|
22
26
|
raise ArgumentError, "#{image.class} can't go in a snapshot"
|
|
23
27
|
end
|
|
@@ -37,7 +41,7 @@ module Badline
|
|
|
37
41
|
end
|
|
38
42
|
end
|
|
39
43
|
|
|
40
|
-
KIND_NAMES = %w[directory d64 d71 d81 t64].freeze
|
|
44
|
+
KIND_NAMES = %w[directory d64 d71 d81 t64 d80 d82].freeze
|
|
41
45
|
|
|
42
46
|
# Opens the storage write_fields wrote: the same directory by its
|
|
43
47
|
# path, an archive with the bytes it held, or a disk image with the
|
|
@@ -55,6 +59,8 @@ module Badline
|
|
|
55
59
|
case kind
|
|
56
60
|
when D64 then Storage::D64Image.new(path, read_only:, bytes:)
|
|
57
61
|
when D71 then Storage::D71Image.new(path, read_only:, bytes:)
|
|
62
|
+
when D80 then Storage::D80Image.new(path, read_only:, bytes:)
|
|
63
|
+
when D82 then Storage::D82Image.new(path, read_only:, bytes:)
|
|
58
64
|
else Storage::D81Image.new(path, read_only:, bytes:)
|
|
59
65
|
end
|
|
60
66
|
end
|
data/lib/badline/snapshot.rb
CHANGED
|
@@ -35,9 +35,9 @@ module Badline
|
|
|
35
35
|
# The machine's snapshot file. Saving first runs the machine on to the
|
|
36
36
|
# end of the instruction its CPU is in, and of an REU transfer under
|
|
37
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
|
|
39
|
-
# Plus/4's snapshot is in a container named as xvic, x128
|
|
40
|
-
# names its machine.
|
|
38
|
+
# second save straight after runs none. A VIC-20's, a C128's, a
|
|
39
|
+
# Plus/4's or a PET's snapshot is in a container named as xvic, x128,
|
|
40
|
+
# xplus4 or xpet names its machine.
|
|
41
41
|
def dump(computer) = Image.of(computer).to_s
|
|
42
42
|
|
|
43
43
|
def read(path) = Image.new(Container.parse(File.binread(path)), name: File.basename(path))
|
|
@@ -51,8 +51,8 @@ module Badline
|
|
|
51
51
|
# snapshot that fails leaves the machine as it was.
|
|
52
52
|
def restore(computer, path, &) = read(path).restore(computer, &)
|
|
53
53
|
|
|
54
|
-
# A machine's snapshots, as .vsf files and in memory. C64, Vic20, C128
|
|
55
|
-
# and
|
|
54
|
+
# A machine's snapshots, as .vsf files and in memory. C64, Vic20, C128,
|
|
55
|
+
# Plus4 and PET each include it.
|
|
56
56
|
module Files
|
|
57
57
|
def save_snapshot(path) = Snapshot.save(self, path)
|
|
58
58
|
|
|
@@ -95,4 +95,8 @@ module Badline
|
|
|
95
95
|
class Plus4
|
|
96
96
|
include Snapshot::Files
|
|
97
97
|
end
|
|
98
|
+
|
|
99
|
+
class PET
|
|
100
|
+
include Snapshot::Files
|
|
101
|
+
end
|
|
98
102
|
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Storage
|
|
5
|
+
# An 8050 disk: 77 tracks on one side, in four speed zones.
|
|
6
|
+
class D80Image < DiskImage
|
|
7
|
+
ERROR_TABLES = { 535_331 => 2083 }.freeze
|
|
8
|
+
|
|
9
|
+
# The last track of each zone but the innermost, from the outermost
|
|
10
|
+
# in: tracks 1-39, 40-53 and 54-64, and the last zone from 65 on.
|
|
11
|
+
ZONE_LAST_TRACKS = [39, 53, 64].freeze
|
|
12
|
+
|
|
13
|
+
# The sectors a track holds in each zone, from the outermost in.
|
|
14
|
+
ZONE_SECTORS = [29, 27, 25, 23].freeze
|
|
15
|
+
|
|
16
|
+
# The tracks a side holds.
|
|
17
|
+
SIDE_TRACKS = 77
|
|
18
|
+
|
|
19
|
+
def sectors_in(track)
|
|
20
|
+
zone = ZONE_LAST_TRACKS.count { |last| track > last }
|
|
21
|
+
ZONE_SECTORS[zone]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def error_tables = ERROR_TABLES
|
|
27
|
+
|
|
28
|
+
# The header block holds the disk name at $06 and the ID at $18,
|
|
29
|
+
# after the link to the BAM's first block and the format, "C".
|
|
30
|
+
def header_name = 0x06
|
|
31
|
+
def directory_track = 39
|
|
32
|
+
def directory_sector = 1
|
|
33
|
+
def directory_interleave = 3
|
|
34
|
+
def interleave = 6
|
|
35
|
+
|
|
36
|
+
# Only the directory track is kept from files. The BAM's blocks on
|
|
37
|
+
# track 38 are marked in use, and the rest of that track holds files.
|
|
38
|
+
def reserved_tracks = [39]
|
|
39
|
+
|
|
40
|
+
# The BAM takes blocks 0, 3, 6 and 9 of track 38 as it needs them,
|
|
41
|
+
# each covering 50 tracks with a free count and a four-byte bitmap
|
|
42
|
+
# each from offset 6.
|
|
43
|
+
def bam_tracks = 1..SIDE_TRACKS
|
|
44
|
+
def bam_count(track) = [38, 3 * ((track - 1) / 50), 6 + (5 * ((track - 1) % 50))]
|
|
45
|
+
def bam_bitmap(track) = [38, 3 * ((track - 1) / 50), 7 + (5 * ((track - 1) % 50))]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Storage
|
|
5
|
+
# An 8250 disk: an 8050's 77 tracks on each side, tracks 78-154 on the
|
|
6
|
+
# second, one directory and one BAM for both.
|
|
7
|
+
class D82Image < D80Image
|
|
8
|
+
ERROR_TABLES = { 1_070_662 => 4166 }.freeze
|
|
9
|
+
|
|
10
|
+
def sectors_in(track)
|
|
11
|
+
track > SIDE_TRACKS ? super(track - SIDE_TRACKS) : super
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def error_tables = ERROR_TABLES
|
|
17
|
+
|
|
18
|
+
def bam_tracks = 1..(2 * SIDE_TRACKS)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/badline/storage/tap.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Badline
|
|
4
4
|
module Storage
|
|
5
5
|
# Raw datasette pulse stream. The header holds the signature, the
|
|
6
|
-
# version at $0c, the platform at $0d (0 C64, 1 VIC-20, 2 C16) and the
|
|
6
|
+
# version at $0c, the platform at $0d (0 C64, 1 VIC-20, 2 C16, 3 PET) and the
|
|
7
7
|
# data size at $10; the data runs from $14, every byte the time to the
|
|
8
8
|
# next falling edge on the tape read line, in units of 8 cycles. A
|
|
9
9
|
# version 2 tape, the C16's and the Plus/4's, times half waves instead,
|
|
@@ -16,18 +16,31 @@ module Badline
|
|
|
16
16
|
HEADER_SIZE = 0x14
|
|
17
17
|
OVERFLOW = 0x100 * 8
|
|
18
18
|
|
|
19
|
+
# The platform byte of a PET tape, a version 1 tape timed in PET
|
|
20
|
+
# cycles.
|
|
21
|
+
PET_PLATFORM = 3
|
|
22
|
+
|
|
19
23
|
# The file it was read from, expanded, and the file's bytes.
|
|
20
24
|
attr_reader :version, :platform, :path, :bytes
|
|
21
25
|
|
|
22
26
|
# A blank tape for `platform` at `path`, written to the host file: a
|
|
23
|
-
# version 1 tape for the C64 (0)
|
|
24
|
-
# C16 tape for the 264 series (2).
|
|
27
|
+
# version 1 tape for the C64 (0), the VIC-20 (1) or the PET (3), and
|
|
28
|
+
# a version 2 C16 tape for the 264 series (2).
|
|
25
29
|
def self.create(path, platform:)
|
|
26
30
|
header = platform == 2 ? C16_SIGNATURE + [2] : SIGNATURE + [1]
|
|
27
31
|
File.binwrite(path, (header + [platform, 0, 0, 0, 0, 0, 0]).pack("C*"))
|
|
28
32
|
new(path)
|
|
29
33
|
end
|
|
30
34
|
|
|
35
|
+
# The platform byte of the tape at `path`, or nil when it isn't a
|
|
36
|
+
# TAP file, read from its header alone.
|
|
37
|
+
def self.platform_of(path)
|
|
38
|
+
header = File.binread(path, HEADER_SIZE)&.bytes || []
|
|
39
|
+
return unless [SIGNATURE, C16_SIGNATURE].include?(header[0, SIGNATURE.length]) && header.length > 0x0d
|
|
40
|
+
|
|
41
|
+
header[0x0d]
|
|
42
|
+
end
|
|
43
|
+
|
|
31
44
|
# `bytes` stands in for the host file's contents, as a snapshot
|
|
32
45
|
# restores the tape it holds.
|
|
33
46
|
def initialize(path, bytes: nil)
|
data/lib/badline/storage.rb
CHANGED
|
@@ -7,6 +7,8 @@ require "badline/storage/disk_image"
|
|
|
7
7
|
require "badline/storage/d64_image"
|
|
8
8
|
require "badline/storage/d71_image"
|
|
9
9
|
require "badline/storage/d81_image"
|
|
10
|
+
require "badline/storage/d80_image"
|
|
11
|
+
require "badline/storage/d82_image"
|
|
10
12
|
require "badline/storage/g64_image"
|
|
11
13
|
require "badline/storage/t64"
|
|
12
14
|
require "badline/storage/tap"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Support
|
|
5
|
+
# A Checkpoint of a PET: its CPU, the RAM below $8000, the screen RAM,
|
|
6
|
+
# the picture the video paints, both PIAs, the VIA, the CRTC's
|
|
7
|
+
# registers and counters, and the 8096's control register and 64K
|
|
8
|
+
# board, or nothing on another model.
|
|
9
|
+
module PETCheckpoint
|
|
10
|
+
COMPONENTS = %w[cpu ram screen display pia1 pia2 via crtc expansion].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.bus.screen.cells),
|
|
18
|
+
Checkpoint.fnv1a(machine.video.display),
|
|
19
|
+
Checkpoint.fnv1a(pia_state(machine.pia1)),
|
|
20
|
+
Checkpoint.fnv1a(pia_state(machine.pia2)),
|
|
21
|
+
Checkpoint.fnv1a(Vic20Checkpoint.via_state(machine.via)),
|
|
22
|
+
Checkpoint.fnv1a(crtc_state(machine.crtc)),
|
|
23
|
+
Checkpoint.fnv1a(expansion_state(machine.bus.expansion))
|
|
24
|
+
], COMPONENTS)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.parse(line) = Checkpoint.parse(line, COMPONENTS)
|
|
28
|
+
|
|
29
|
+
def self.pia_state(pia) = [pia.port_a_output, pia.port_b_output, pia.cra, pia.crb]
|
|
30
|
+
|
|
31
|
+
def self.crtc_state(crtc) = crtc.registers + [crtc.column, crtc.line, crtc.row]
|
|
32
|
+
|
|
33
|
+
def self.expansion_state(expansion)
|
|
34
|
+
expansion ? [expansion.control, *expansion.cells] : []
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
data/lib/badline/timing.rb
CHANGED
|
@@ -5,8 +5,9 @@ module Badline
|
|
|
5
5
|
#
|
|
6
6
|
# What a front end needs to run a machine's frames and show them: the CPU
|
|
7
7
|
# clock, the raster's cycles per line and lines per frame, and the
|
|
8
|
-
# [left, top, width, height] of the raster it shows,
|
|
9
|
-
# window's square pixels wide each of its pixels shows
|
|
10
|
-
#
|
|
11
|
-
|
|
8
|
+
# [left, top, width, height] of the raster it shows, how many of the
|
|
9
|
+
# window's square pixels wide each of its pixels shows, and how many of
|
|
10
|
+
# its pixels share one window pixel, as an 80-column screen's dots do.
|
|
11
|
+
# Each machine derives it from its region.
|
|
12
|
+
Timing = Data.define(:clock_hz, :cycles_per_line, :lines_per_frame, :crop, :pixel_width, :dots)
|
|
12
13
|
end
|
data/lib/badline/version.rb
CHANGED
|
@@ -23,12 +23,17 @@ module Badline
|
|
|
23
23
|
# Puts a cartridge's ROM chips, each a CRTFile::Chip with its address
|
|
24
24
|
# and bytes, into their blocks, and switches the machine off and on,
|
|
25
25
|
# as a cartridge goes in with the power off. The KERNAL then starts
|
|
26
|
-
# the cartridge in BLK5 that signs itself with A0CBM.
|
|
27
|
-
|
|
26
|
+
# the cartridge in BLK5 that signs itself with A0CBM. +name+ is the
|
|
27
|
+
# name it goes by (#cartridge_name).
|
|
28
|
+
def attach_cartridge(chips, name = "")
|
|
28
29
|
chips.each { |chip| @bus.map_rom(chip.address, chip.data) }
|
|
30
|
+
@bus.cartridge_name = name
|
|
29
31
|
power_cycle!
|
|
30
32
|
end
|
|
31
33
|
|
|
34
|
+
# The name of the cartridge in the expansion blocks, or an empty one.
|
|
35
|
+
def cartridge_name = @bus.cartridge_name
|
|
36
|
+
|
|
32
37
|
private
|
|
33
38
|
|
|
34
39
|
# The VIC-20's KERNAL, which the traps stand in for.
|
|
@@ -11,9 +11,9 @@ module Badline
|
|
|
11
11
|
end
|
|
12
12
|
|
|
13
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,
|
|
15
|
-
# snapshot module (Snapshot::Keyed). The pages are mapped
|
|
16
|
-
# they are loaded.
|
|
14
|
+
# cartridge's name and its ROM chips as rom<N>.start and rom<N>.bytes,
|
|
15
|
+
# in a keyed snapshot module (Snapshot::Keyed). The pages are mapped
|
|
16
|
+
# again once they are loaded.
|
|
17
17
|
module KeyedState
|
|
18
18
|
def save_fields(out, prefix)
|
|
19
19
|
out.int("#{prefix}data", @data).int("#{prefix}video_data", @video_data)
|
|
@@ -28,7 +28,7 @@ module Badline
|
|
|
28
28
|
def cartridge? = !@roms.empty?
|
|
29
29
|
|
|
30
30
|
def save_rom_fields(out)
|
|
31
|
-
out.int("roms", @roms.length)
|
|
31
|
+
out.text("name", @cartridge_name).int("roms", @roms.length)
|
|
32
32
|
@roms.each_with_index do |rom, number|
|
|
33
33
|
out.int("rom#{number}.start", rom.start)
|
|
34
34
|
rom.save_fields(out, "rom#{number}.bytes")
|
|
@@ -37,6 +37,7 @@ module Badline
|
|
|
37
37
|
|
|
38
38
|
def load_rom_fields(input)
|
|
39
39
|
@roms = []
|
|
40
|
+
@cartridge_name = input.text("name", "")
|
|
40
41
|
input.int("roms", 0).times do |number|
|
|
41
42
|
bytes = input.bytes("rom#{number}.bytes", "".b).bytes
|
|
42
43
|
@roms << ROM.new(bytes, length: bytes.length, start: input.word("rom#{number}.start", 0))
|
data/lib/badline/vic20/bus.rb
CHANGED
|
@@ -160,6 +160,10 @@ module Badline
|
|
|
160
160
|
# The last byte on the V-bus.
|
|
161
161
|
attr_reader :video_data
|
|
162
162
|
|
|
163
|
+
# The name of the cartridge whose ROM chips are in the expansion
|
|
164
|
+
# blocks, or an empty one.
|
|
165
|
+
attr_accessor :cartridge_name
|
|
166
|
+
|
|
163
167
|
# +vic+, +via1+ and +via2+ are the chips in I/O 0, each answering
|
|
164
168
|
# peek and poke with the CPU's address. +blocks+ names the expansion
|
|
165
169
|
# blocks that hold RAM (BLOCKS), and +kernal+ the KERNAL ROM's file.
|
|
@@ -177,6 +181,7 @@ module Badline
|
|
|
177
181
|
@read_pages = Array.new(256, @open_bus)
|
|
178
182
|
@write_pages = Array.new(256, @open_bus)
|
|
179
183
|
@roms = []
|
|
184
|
+
@cartridge_name = ""
|
|
180
185
|
@debug_register = nil
|
|
181
186
|
@via_write_handler = nil
|
|
182
187
|
self.blocks = blocks
|
data/lib/badline/vic20.rb
CHANGED
|
@@ -120,7 +120,7 @@ module Badline
|
|
|
120
120
|
blanked = profile.blanked_lines
|
|
121
121
|
Timing.new(clock_hz: profile.clock_hz, cycles_per_line: profile.cycles_per_line,
|
|
122
122
|
lines_per_frame: profile.lines_per_frame,
|
|
123
|
-
crop: [0, blanked, width, profile.lines_per_frame - blanked], pixel_width: 2)
|
|
123
|
+
crop: [0, blanked, width, profile.lines_per_frame - blanked], pixel_width: 2, dots: 1)
|
|
124
124
|
end
|
|
125
125
|
|
|
126
126
|
# The RESTORE key pulls VIA 1's CA1 low while it is held. The KERNAL
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: badline
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.16.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Inge Jørgensen
|
|
@@ -169,6 +169,11 @@ files:
|
|
|
169
169
|
- lib/badline/chips/cpu/port.rb
|
|
170
170
|
- lib/badline/chips/cpu/stack_operations.rb
|
|
171
171
|
- lib/badline/chips/cpu/traps.rb
|
|
172
|
+
- lib/badline/chips/crtc.rb
|
|
173
|
+
- lib/badline/chips/crtc/keyed_state.rb
|
|
174
|
+
- lib/badline/chips/pia.rb
|
|
175
|
+
- lib/badline/chips/pia/control_lines.rb
|
|
176
|
+
- lib/badline/chips/pia/keyed_parts.rb
|
|
172
177
|
- lib/badline/chips/sid.rb
|
|
173
178
|
- lib/badline/chips/sid/catch_up.rb
|
|
174
179
|
- lib/badline/chips/sid/decimator.rb
|
|
@@ -264,6 +269,7 @@ files:
|
|
|
264
269
|
- lib/badline/drives/engine/sleep.rb
|
|
265
270
|
- lib/badline/drives/engine/vias.rb
|
|
266
271
|
- lib/badline/drives/engine/watch.rb
|
|
272
|
+
- lib/badline/drives/ieee_bus.rb
|
|
267
273
|
- lib/badline/drives/model1541.rb
|
|
268
274
|
- lib/badline/drives/model1541/bus.rb
|
|
269
275
|
- lib/badline/drives/model1541/byte_ready.rb
|
|
@@ -336,6 +342,7 @@ files:
|
|
|
336
342
|
- lib/badline/frontend/pacer.rb
|
|
337
343
|
- lib/badline/frontend/pad_port.rb
|
|
338
344
|
- lib/badline/frontend/painter.rb
|
|
345
|
+
- lib/badline/frontend/pet_keyboard.rb
|
|
339
346
|
- lib/badline/frontend/player/filter_view.rb
|
|
340
347
|
- lib/badline/frontend/player/info_view.rb
|
|
341
348
|
- lib/badline/frontend/player/player_commands.rb
|
|
@@ -375,12 +382,16 @@ files:
|
|
|
375
382
|
- lib/badline/kernal_trap/dos/write_file.rb
|
|
376
383
|
- lib/badline/kernal_trap/dos/writes.rb
|
|
377
384
|
- lib/badline/kernal_trap/file_routine.rb
|
|
385
|
+
- lib/badline/kernal_trap/frames.rb
|
|
386
|
+
- lib/badline/kernal_trap/ieee.rb
|
|
387
|
+
- lib/badline/kernal_trap/ieee_layout.rb
|
|
378
388
|
- lib/badline/kernal_trap/keyed_state.rb
|
|
379
389
|
- lib/badline/kernal_trap/layout.rb
|
|
380
390
|
- lib/badline/kernal_trap/load.rb
|
|
381
391
|
- lib/badline/kernal_trap/routine.rb
|
|
382
392
|
- lib/badline/kernal_trap/save.rb
|
|
383
393
|
- lib/badline/kernal_trap/serial.rb
|
|
394
|
+
- lib/badline/kernal_trap/steps.rb
|
|
384
395
|
- lib/badline/machine.rb
|
|
385
396
|
- lib/badline/machine/clocking.rb
|
|
386
397
|
- lib/badline/machine/keyboard_buffer.rb
|
|
@@ -391,6 +402,7 @@ files:
|
|
|
391
402
|
- lib/badline/media/disk_set.rb
|
|
392
403
|
- lib/badline/media/extensions.rb
|
|
393
404
|
- lib/badline/media/not_disk.rb
|
|
405
|
+
- lib/badline/media/pet_media.rb
|
|
394
406
|
- lib/badline/media/plus4_media.rb
|
|
395
407
|
- lib/badline/media/program.rb
|
|
396
408
|
- lib/badline/media/true_drive.rb
|
|
@@ -407,6 +419,26 @@ files:
|
|
|
407
419
|
- lib/badline/options/option.rb
|
|
408
420
|
- lib/badline/options/table.rb
|
|
409
421
|
- lib/badline/options/validation.rb
|
|
422
|
+
- lib/badline/pet.rb
|
|
423
|
+
- lib/badline/pet/bus.rb
|
|
424
|
+
- lib/badline/pet/bus/expansion.rb
|
|
425
|
+
- lib/badline/pet/canvas.rb
|
|
426
|
+
- lib/badline/pet/cassettes.rb
|
|
427
|
+
- lib/badline/pet/characters.rb
|
|
428
|
+
- lib/badline/pet/cpu.rb
|
|
429
|
+
- lib/badline/pet/crtc_video.rb
|
|
430
|
+
- lib/badline/pet/discrete_video.rb
|
|
431
|
+
- lib/badline/pet/ieee_ports.rb
|
|
432
|
+
- lib/badline/pet/ieee_traps.rb
|
|
433
|
+
- lib/badline/pet/keyboard_ports.rb
|
|
434
|
+
- lib/badline/pet/keyed_modules.rb
|
|
435
|
+
- lib/badline/pet/keyed_parts.rb
|
|
436
|
+
- lib/badline/pet/keyed_state.rb
|
|
437
|
+
- lib/badline/pet/model.rb
|
|
438
|
+
- lib/badline/pet/rom_sets.rb
|
|
439
|
+
- lib/badline/pet/sound.rb
|
|
440
|
+
- lib/badline/pet/via.rb
|
|
441
|
+
- lib/badline/pet/via_ports.rb
|
|
410
442
|
- lib/badline/plus4.rb
|
|
411
443
|
- lib/badline/plus4/acia.rb
|
|
412
444
|
- lib/badline/plus4/acia/frames.rb
|
|
@@ -443,6 +475,24 @@ files:
|
|
|
443
475
|
- lib/badline/roms/kernal-pet64.rom
|
|
444
476
|
- lib/badline/roms/kernal-sx64.rom
|
|
445
477
|
- lib/badline/roms/kernal.rom
|
|
478
|
+
- lib/badline/roms/pet/basic1.rom
|
|
479
|
+
- lib/badline/roms/pet/basic2.rom
|
|
480
|
+
- lib/badline/roms/pet/basic4.rom
|
|
481
|
+
- lib/badline/roms/pet/characters1.rom
|
|
482
|
+
- lib/badline/roms/pet/characters2.rom
|
|
483
|
+
- lib/badline/roms/pet/editor1.rom
|
|
484
|
+
- lib/badline/roms/pet/editor2-b.rom
|
|
485
|
+
- lib/badline/roms/pet/editor2-n.rom
|
|
486
|
+
- lib/badline/roms/pet/editor4-40-n-50hz.rom
|
|
487
|
+
- lib/badline/roms/pet/editor4-40-n-60hz.rom
|
|
488
|
+
- lib/badline/roms/pet/editor4-80-b-50hz-0283.rom
|
|
489
|
+
- lib/badline/roms/pet/editor4-80-b-50hz.rom
|
|
490
|
+
- lib/badline/roms/pet/editor4-80-b-60hz.rom
|
|
491
|
+
- lib/badline/roms/pet/editor4-b.rom
|
|
492
|
+
- lib/badline/roms/pet/editor4-n.rom
|
|
493
|
+
- lib/badline/roms/pet/kernal1.rom
|
|
494
|
+
- lib/badline/roms/pet/kernal2.rom
|
|
495
|
+
- lib/badline/roms/pet/kernal4.rom
|
|
446
496
|
- lib/badline/roms/plus4/basic.rom
|
|
447
497
|
- lib/badline/roms/plus4/function-high.rom
|
|
448
498
|
- lib/badline/roms/plus4/function-low.rom
|
|
@@ -474,6 +524,7 @@ files:
|
|
|
474
524
|
- lib/badline/snapshot/keyed/report.rb
|
|
475
525
|
- lib/badline/snapshot/keyed/writer.rb
|
|
476
526
|
- lib/badline/snapshot/machine_state.rb
|
|
527
|
+
- lib/badline/snapshot/pet_setup.rb
|
|
477
528
|
- lib/badline/snapshot/plus4_setup.rb
|
|
478
529
|
- lib/badline/snapshot/storage_setup.rb
|
|
479
530
|
- lib/badline/snapshot/vic20_setup.rb
|
|
@@ -496,7 +547,9 @@ files:
|
|
|
496
547
|
- lib/badline/storage/crt_file.rb
|
|
497
548
|
- lib/badline/storage/d64_image.rb
|
|
498
549
|
- lib/badline/storage/d71_image.rb
|
|
550
|
+
- lib/badline/storage/d80_image.rb
|
|
499
551
|
- lib/badline/storage/d81_image.rb
|
|
552
|
+
- lib/badline/storage/d82_image.rb
|
|
500
553
|
- lib/badline/storage/disk_image.rb
|
|
501
554
|
- lib/badline/storage/disk_image/bam.rb
|
|
502
555
|
- lib/badline/storage/disk_image/catalog.rb
|
|
@@ -512,6 +565,7 @@ files:
|
|
|
512
565
|
- lib/badline/support.rb
|
|
513
566
|
- lib/badline/support/c128_checkpoint.rb
|
|
514
567
|
- lib/badline/support/checkpoint.rb
|
|
568
|
+
- lib/badline/support/pet_checkpoint.rb
|
|
515
569
|
- lib/badline/support/plus4_checkpoint.rb
|
|
516
570
|
- lib/badline/support/vic20_checkpoint.rb
|
|
517
571
|
- lib/badline/timing.rb
|