badline 0.16.0 → 0.17.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 +76 -0
- data/CLAUDE.md +1 -1
- data/README.md +130 -17
- data/doc/media.md +14 -2
- data/doc/pinned-behaviour.md +61 -0
- data/doc/snapshot-format.md +379 -70
- data/doc/snapshots.md +185 -10
- data/lib/badline/cbm2/acia.rb +10 -0
- data/lib/badline/cbm2/bus.rb +263 -0
- data/lib/badline/cbm2/cpu.rb +58 -0
- data/lib/badline/cbm2/crtc_video.rb +133 -0
- data/lib/badline/cbm2/ieee_drive.rb +18 -0
- data/lib/badline/cbm2/ieee_layout.rb +69 -0
- data/lib/badline/cbm2/ieee_ports.rb +104 -0
- data/lib/badline/cbm2/ieee_traps.rb +81 -0
- data/lib/badline/cbm2/keyboard_ports.rb +60 -0
- data/lib/badline/cbm2/keyed_modules.rb +67 -0
- data/lib/badline/cbm2/keyed_state.rb +91 -0
- data/lib/badline/cbm2/model.rb +44 -0
- data/lib/badline/cbm2/p500/control_ports.rb +80 -0
- data/lib/badline/cbm2/p500/ieee_layout.rb +41 -0
- data/lib/badline/cbm2/p500/keyed_state.rb +85 -0
- data/lib/badline/cbm2/p500/model.rb +39 -0
- data/lib/badline/cbm2/p500/pages.rb +57 -0
- data/lib/badline/cbm2/p500.rb +262 -0
- data/lib/badline/cbm2/sid_page.rb +19 -0
- data/lib/badline/cbm2.rb +267 -0
- data/lib/badline/{plus4 → chips}/acia/frames.rb +1 -1
- data/lib/badline/chips/acia/keyed_state.rb +47 -0
- data/lib/badline/chips/acia.rb +307 -0
- data/lib/badline/chips/crtc.rb +3 -2
- data/lib/badline/chips/riot/fast_forward.rb +72 -0
- data/lib/badline/chips/riot/keyed_parts.rb +69 -0
- data/lib/badline/chips/riot/timer.rb +80 -0
- data/lib/badline/chips/riot.rb +162 -0
- data/lib/badline/chips/rriot/keyed_state.rb +30 -0
- data/lib/badline/chips/rriot.rb +132 -0
- data/lib/badline/chips/tpi/keyed_state.rb +38 -0
- data/lib/badline/chips/tpi.rb +233 -0
- data/lib/badline/chips/vic/bank.rb +60 -5
- data/lib/badline/chips/vic/sprite.rb +4 -3
- data/lib/badline/drives/datasette/keyed_state.rb +9 -1
- data/lib/badline/drives/datasette.rb +27 -3
- data/lib/badline/drives/ieee_bus.rb +50 -4
- data/lib/badline/drives/model2031/ieee_port.rb +133 -0
- data/lib/badline/drives/model2031/keyed_state.rb +66 -0
- data/lib/badline/drives/model2031/parts.rb +25 -0
- data/lib/badline/drives/model2031.rb +92 -0
- data/lib/badline/drives/model8050/disk.rb +163 -0
- data/lib/badline/drives/model8050/fdc_bus.rb +102 -0
- data/lib/badline/drives/model8050/idle.rb +177 -0
- data/lib/badline/drives/model8050/ieee_port.rb +147 -0
- data/lib/badline/drives/model8050/ip_bus.rb +93 -0
- data/lib/badline/drives/model8050/keyed_state.rb +160 -0
- data/lib/badline/drives/model8050/mechanism.rb +230 -0
- data/lib/badline/drives/model8050/parts.rb +37 -0
- data/lib/badline/drives/model8050.rb +243 -0
- data/lib/badline/frontend/app.rb +10 -3
- data/lib/badline/frontend/boot.rb +1 -1
- data/lib/badline/frontend/controls.rb +51 -15
- data/lib/badline/frontend/gamepads.rb +3 -3
- data/lib/badline/frontend/keys.rb +61 -2
- data/lib/badline/frontend/media_slots.rb +1 -1
- data/lib/badline/frontend/menu/menu_media.rb +14 -11
- data/lib/badline/frontend/menu/menu_pages.rb +29 -6
- data/lib/badline/frontend/menu/menu_ports.rb +40 -4
- data/lib/badline/frontend/menu/pause_menu.rb +1 -1
- data/lib/badline/frontend/pet_keyboard.rb +23 -7
- data/lib/badline/frontend/timeline.rb +19 -10
- data/lib/badline/kernal_trap/dos/disk_commands.rb +80 -0
- data/lib/badline/kernal_trap/dos/status.rb +3 -0
- data/lib/badline/kernal_trap/dos.rb +18 -5
- data/lib/badline/kernal_trap/ieee.rb +7 -2
- data/lib/badline/kernal_trap/ieee_layout.rb +95 -43
- data/lib/badline/machine/ieee_drives.rb +194 -0
- data/lib/badline/machine/settling.rb +4 -0
- data/lib/badline/machine.rb +26 -8
- data/lib/badline/media/cbm2_media.rb +29 -0
- data/lib/badline/media/pet_media.rb +5 -5
- data/lib/badline/media/program.rb +6 -3
- data/lib/badline/media/true_drive.rb +50 -8
- data/lib/badline/media.rb +21 -8
- data/lib/badline/options/family.rb +15 -3
- data/lib/badline/options/help.rb +24 -6
- data/lib/badline/options/table.rb +25 -5
- data/lib/badline/options/validation.rb +47 -7
- data/lib/badline/options.rb +48 -15
- data/lib/badline/pet/bus/expansion.rb +99 -5
- data/lib/badline/pet/bus.rb +30 -12
- data/lib/badline/pet/cassettes.rb +22 -1
- data/lib/badline/pet/characters.rb +8 -2
- data/lib/badline/pet/crtc_video.rb +20 -7
- data/lib/badline/pet/ieee_drive.rb +17 -0
- data/lib/badline/pet/ieee_ports.rb +19 -1
- data/lib/badline/pet/ieee_traps.rb +10 -5
- data/lib/badline/pet/keyed_modules.rb +4 -1
- data/lib/badline/pet/keyed_parts.rb +10 -6
- data/lib/badline/pet/model.rb +56 -6
- data/lib/badline/pet/rom_sets.rb +30 -6
- data/lib/badline/pet.rb +45 -16
- data/lib/badline/plus4/acia.rb +4 -298
- data/lib/badline/plus4/keyed_parts.rb +0 -44
- data/lib/badline/plus4.rb +1 -0
- data/lib/badline/roms/8050/dos-2.7.rom +0 -0
- data/lib/badline/roms/8050/fdc-901869-01.rom +0 -0
- data/lib/badline/roms/8050/fdc-901885-04.rom +0 -0
- data/lib/badline/roms/README +144 -1
- data/lib/badline/roms/cbm2/basic128-02b.rom +0 -0
- data/lib/badline/roms/cbm2/basic128.rom +0 -0
- data/lib/badline/roms/cbm2/basic256.rom +0 -0
- data/lib/badline/roms/cbm2/characters-600.rom +0 -0
- data/lib/badline/roms/cbm2/characters-700.rom +0 -0
- data/lib/badline/roms/cbm2/kernal-03b.rom +0 -0
- data/lib/badline/roms/cbm2/kernal-04a.rom +0 -0
- data/lib/badline/roms/cbm2/p500-basic.rom +0 -0
- data/lib/badline/roms/cbm2/p500-kernal.rom +0 -0
- data/lib/badline/roms/dos2031.rom +0 -0
- data/lib/badline/roms/pet/characters-din.rom +0 -0
- data/lib/badline/roms/pet/editor4-80-b-50hz-8296.rom +0 -0
- data/lib/badline/snapshot/cbm2_setup.rb +53 -0
- data/lib/badline/snapshot/container.rb +9 -1
- data/lib/badline/snapshot/field_doc/markdown.rb +4 -2
- data/lib/badline/snapshot/field_doc.rb +39 -3
- data/lib/badline/snapshot/image.rb +79 -15
- data/lib/badline/snapshot/pet_setup.rb +30 -13
- data/lib/badline/snapshot/vice/cbm2.rb +93 -0
- data/lib/badline/snapshot/vice/cbm2_acia.rb +75 -0
- data/lib/badline/snapshot/vice/cbm2_crtc.rb +127 -0
- data/lib/badline/snapshot/vice/cbm2_mains.rb +49 -0
- data/lib/badline/snapshot/vice/cbm2_mem.rb +75 -0
- data/lib/badline/snapshot/vice/cbm2_restore.rb +204 -0
- data/lib/badline/snapshot/vice/cbm2_tpi.rb +58 -0
- data/lib/badline/snapshot/vice/cias.rb +13 -9
- data/lib/badline/snapshot/vice/p500.rb +96 -0
- data/lib/badline/snapshot/vice/p500_restore.rb +130 -0
- data/lib/badline/snapshot/vice/p500_vicii.rb +166 -0
- data/lib/badline/snapshot/vice/pet.rb +121 -0
- data/lib/badline/snapshot/vice/pet_cpu.rb +70 -0
- data/lib/badline/snapshot/vice/pet_crtc.rb +241 -0
- data/lib/badline/snapshot/vice/pet_drive.rb +180 -0
- data/lib/badline/snapshot/vice/pet_drive8050.rb +216 -0
- data/lib/badline/snapshot/vice/pet_mem.rb +93 -0
- data/lib/badline/snapshot/vice/pet_pias.rb +56 -0
- data/lib/badline/snapshot/vice/pet_restore.rb +214 -0
- data/lib/badline/snapshot/vice/pet_via.rb +165 -0
- data/lib/badline/snapshot/vice/sid_registers.rb +2 -1
- data/lib/badline/snapshot/vice/vicii_import.rb +10 -6
- data/lib/badline/snapshot/vice.rb +4 -0
- data/lib/badline/snapshot.rb +11 -3
- data/lib/badline/storage/crt_file.rb +7 -1
- data/lib/badline/storage/d64_image.rb +7 -0
- data/lib/badline/storage/d80_image.rb +17 -1
- data/lib/badline/storage/d81_image.rb +14 -0
- data/lib/badline/storage/disk_image/bam.rb +18 -3
- data/lib/badline/storage/disk_image/formatting.rb +69 -0
- data/lib/badline/storage/disk_image/writing.rb +35 -0
- data/lib/badline/storage/disk_image.rb +2 -0
- data/lib/badline/storage.rb +1 -0
- data/lib/badline/support/cbm2_checkpoint.rb +48 -0
- data/lib/badline/support/p500_checkpoint.rb +35 -0
- data/lib/badline/version.rb +1 -1
- data/lib/badline.rb +1 -0
- metadata +87 -2
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "badline/drives/model2031"
|
|
4
|
+
require "badline/drives/model8050"
|
|
5
|
+
|
|
6
|
+
module Badline
|
|
7
|
+
module Machine
|
|
8
|
+
# A machine's true drive on its IEEE-488 bus: a Drives::Model2031,
|
|
9
|
+
# Model8050 or Model8250, one at a time, clocked after the CPU each
|
|
10
|
+
# cycle at the machine's clock (ieee_host_clock_hz) and reset with it,
|
|
11
|
+
# as the machine's RES line reaches IFC. The traps on the KERNAL's
|
|
12
|
+
# primitives leave device 8 to the drive while it is device 8
|
|
13
|
+
# (trap_device). The PET (PET::IEEEDrive) and the CBM-II
|
|
14
|
+
# (CBM2::IEEEDrive) include it.
|
|
15
|
+
#
|
|
16
|
+
# The machine's @ieee is its side of the bus: #bus, the
|
|
17
|
+
# Drives::IEEEBus, #push_lines, which shows the drives the lines the
|
|
18
|
+
# machine pulls now, and #cycle_lines, which does so once a cycle if
|
|
19
|
+
# the machine doesn't push them as its chips are written.
|
|
20
|
+
module IEEEDrives
|
|
21
|
+
# The 2031 on the bus, or nil.
|
|
22
|
+
attr_reader :drive2031
|
|
23
|
+
|
|
24
|
+
# The 8050 or 8250 on the bus, or nil.
|
|
25
|
+
attr_reader :drive8050
|
|
26
|
+
|
|
27
|
+
# Plugs in a Drives::Model2031, in place of the drive there.
|
|
28
|
+
def attach_drive2031(drive)
|
|
29
|
+
detach_true_drives
|
|
30
|
+
connect_drive(drive)
|
|
31
|
+
@drive2031 = drive
|
|
32
|
+
@ieee_trap&.device = trap_device
|
|
33
|
+
@init_threshold = [@init_threshold, Badline::Drives::Model2031::BOOT_CYCLES].max if @cycles < @init_threshold
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Unplugs the 2031, leaving it on a bus of its own.
|
|
37
|
+
def detach_drive2031
|
|
38
|
+
drive = @drive2031
|
|
39
|
+
return unless drive
|
|
40
|
+
|
|
41
|
+
drive.connect(Badline::Drives::IEEEBus.new)
|
|
42
|
+
@drive2031 = nil
|
|
43
|
+
@ieee_trap&.device = trap_device
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Plugs in a Drives::Model8050 or Model8250, in place of the drive
|
|
47
|
+
# there.
|
|
48
|
+
def attach_drive8050(drive)
|
|
49
|
+
detach_true_drives
|
|
50
|
+
connect_drive(drive)
|
|
51
|
+
@drive8050 = drive
|
|
52
|
+
@ieee_trap&.device = trap_device
|
|
53
|
+
@init_threshold = [@init_threshold, Badline::Drives::Model8050::BOOT_CYCLES].max if @cycles < @init_threshold
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Unplugs the 8050 or 8250, leaving it on a bus of its own.
|
|
57
|
+
def detach_drive8050
|
|
58
|
+
drive = @drive8050
|
|
59
|
+
return unless drive
|
|
60
|
+
|
|
61
|
+
drive.connect(Badline::Drives::IEEEBus.new)
|
|
62
|
+
@drive8050 = nil
|
|
63
|
+
@ieee_trap&.device = trap_device
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Plugs in an 8050, or an 8250 for +model+ "8250", as device 8, in
|
|
67
|
+
# place of the drive there, and returns it.
|
|
68
|
+
def plug_drive8050(model = "8050")
|
|
69
|
+
drive = model == "8250" ? Badline::Drives::Model8250.new : Badline::Drives::Model8050.new
|
|
70
|
+
drive.tap { |unit| attach_drive8050(unit) }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# The true drive on the bus, or nil.
|
|
74
|
+
def true_drive = @drive8050 || @drive2031
|
|
75
|
+
|
|
76
|
+
# Plugs in a 2031 as device 8, in place of the drive there, and
|
|
77
|
+
# returns it.
|
|
78
|
+
def plug_true_drive
|
|
79
|
+
Badline::Drives::Model2031.new.tap { |drive| attach_drive2031(drive) }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Settles for a snapshot, then runs on until a 2031's CPU, or an
|
|
83
|
+
# 8050's interface processor with its controller at the start of its
|
|
84
|
+
# idle loop, is between instructions with the machine's, as VICE
|
|
85
|
+
# saves them, or for so many cycles, then on to the machine's next
|
|
86
|
+
# instruction. It stands in for Machine::Settling's, which the
|
|
87
|
+
# machines include first.
|
|
88
|
+
def settle_for_vice!
|
|
89
|
+
ran = settle_for_snapshot!
|
|
90
|
+
return ran if @drive2031.nil? && @drive8050.nil?
|
|
91
|
+
|
|
92
|
+
until ran >= Machine::Settling::LIMIT || (drive_settled_for_vice? && settled_for_snapshot?)
|
|
93
|
+
cycle!
|
|
94
|
+
ran += 1
|
|
95
|
+
end
|
|
96
|
+
ran + settle_for_snapshot!
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Whether the true drive is where VICE saves it (#settle_for_vice!).
|
|
100
|
+
def drive_settled_for_vice?
|
|
101
|
+
return @drive2031.cpu.boundary? if @drive2031
|
|
102
|
+
|
|
103
|
+
fdc = @drive8050.fdc_cpu
|
|
104
|
+
@drive8050.ip_cpu.boundary? && fdc.boundary? && fdc.program_counter == Badline::Drives::Model8050::Idle::FDC_LOOP
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
private
|
|
108
|
+
|
|
109
|
+
def init_ieee_drives
|
|
110
|
+
@drive2031 = nil
|
|
111
|
+
@drive8050 = nil
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def detach_true_drives
|
|
115
|
+
detach_drive2031
|
|
116
|
+
detach_drive8050
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def connect_drive(drive)
|
|
120
|
+
drive.host_clock_hz = ieee_host_clock_hz
|
|
121
|
+
drive.connect(@ieee.bus)
|
|
122
|
+
@ieee.push_lines
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# The true drive's cycles for one of the machine's, after the lines
|
|
126
|
+
# it pulls.
|
|
127
|
+
def clock_ieee_drives
|
|
128
|
+
drive2031 = @drive2031
|
|
129
|
+
drive8050 = @drive8050
|
|
130
|
+
return unless drive2031 || drive8050
|
|
131
|
+
|
|
132
|
+
@ieee.cycle_lines
|
|
133
|
+
drive2031&.host_cycle!
|
|
134
|
+
drive8050&.host_cycle!
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# The RES line reaches the true drive as IFC.
|
|
138
|
+
def reset_ieee_drives
|
|
139
|
+
@drive2031&.reset!
|
|
140
|
+
@drive8050&.reset!
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# The true drive as keyed snapshot modules named from its device
|
|
144
|
+
# number: BL-D8, BL-D8-CPU and so on for device 8.
|
|
145
|
+
def save_drive_modules(sections)
|
|
146
|
+
drive2031 = @drive2031
|
|
147
|
+
drive2031&.save_modules(sections, "BL-D#{drive2031.device}")
|
|
148
|
+
drive8050 = @drive8050
|
|
149
|
+
drive8050&.save_modules(sections, "BL-D#{drive8050.device}")
|
|
150
|
+
sections
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# The true drive a snapshot's modules hold, a 2031, an 8050 or an
|
|
154
|
+
# 8250 by its model, built afresh unless the same model is on the bus
|
|
155
|
+
# as the same device, or none when they hold no drive. The bus then
|
|
156
|
+
# carries the machine's lines as its chips left them.
|
|
157
|
+
def load_drive_modules(modules)
|
|
158
|
+
device = 8
|
|
159
|
+
input = modules.optional("BL-D8")
|
|
160
|
+
while input.nil? && device < 15
|
|
161
|
+
device += 1
|
|
162
|
+
input = modules.optional("BL-D#{device}")
|
|
163
|
+
end
|
|
164
|
+
model = input&.text("model", "2031")
|
|
165
|
+
if %w[8050 8250].include?(model)
|
|
166
|
+
load_drive8050_modules(modules, input, model, device)
|
|
167
|
+
elsif input
|
|
168
|
+
load_drive2031_modules(modules, input, device)
|
|
169
|
+
else
|
|
170
|
+
detach_true_drives
|
|
171
|
+
end
|
|
172
|
+
@ieee.push_lines
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def load_drive2031_modules(modules, input, device)
|
|
176
|
+
detach_drive8050
|
|
177
|
+
detach_drive2031 if @drive2031 && @drive2031.device != device
|
|
178
|
+
attach_drive2031(Badline::Drives::Model2031.new(device:)) unless @drive2031
|
|
179
|
+
@drive2031.load_modules(modules, input, "BL-D#{device}")
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def load_drive8050_modules(modules, input, model, device)
|
|
183
|
+
detach_drive2031
|
|
184
|
+
drive = @drive8050
|
|
185
|
+
detach_drive8050 if drive && (drive.device != device || drive.model_name != model)
|
|
186
|
+
unless @drive8050
|
|
187
|
+
unit = model == "8250" ? Badline::Drives::Model8250.new(device:) : Badline::Drives::Model8050.new(device:)
|
|
188
|
+
attach_drive8050(unit)
|
|
189
|
+
end
|
|
190
|
+
@drive8050.load_modules(modules, input, "BL-D#{device}")
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
@@ -24,6 +24,10 @@ module Badline
|
|
|
24
24
|
settle_chips_for_snapshot
|
|
25
25
|
ran
|
|
26
26
|
end
|
|
27
|
+
|
|
28
|
+
# Settles as #settle_for_snapshot! does, for a snapshot VICE opens,
|
|
29
|
+
# which a machine with a drive VICE runs settles further.
|
|
30
|
+
def settle_for_vice! = settle_for_snapshot!
|
|
27
31
|
end
|
|
28
32
|
end
|
|
29
33
|
end
|
data/lib/badline/machine.rb
CHANGED
|
@@ -69,20 +69,24 @@ module Badline
|
|
|
69
69
|
# Media the machine named doesn't take.
|
|
70
70
|
class Unsupported < ArgumentError; end
|
|
71
71
|
|
|
72
|
-
# A new machine of `family`, :c64, :vic20, :c128, :plus4 or :
|
|
73
|
-
# model of it `model` names. A C64's model is one of Model::ALL, with
|
|
74
|
-
# `sid_model` when not nil and an REU of `reu` K when not nil.
|
|
75
|
-
# VIC-20's is "pal", with the RAM expansion `ram` names
|
|
72
|
+
# A new machine of `family`, :c64, :vic20, :c128, :plus4, :pet or :cbm2, the
|
|
73
|
+
# model of it `model` names. A C64's model is one of Model::ALL, with
|
|
74
|
+
# its SID `sid_model` when not nil and an REU of `reu` K when not nil.
|
|
75
|
+
# A VIC-20's is "pal", with the RAM expansion `ram` names
|
|
76
76
|
# (Vic20::Bus::RAM_CONFIGURATIONS), unexpanded when nil. A C128's is
|
|
77
77
|
# one of C128::Model::ALL, with its SID `sid_model` when not nil, built
|
|
78
78
|
# for C64 mode. A Plus/4's is one of Plus4::Model::ALL or c116, with
|
|
79
79
|
# the model's own RAM. A PET's is one of PET::Model::ALL, with its own
|
|
80
|
-
# RAM and ROMs, its CRTC's editor the 50 Hz one.
|
|
80
|
+
# RAM and ROMs, its CRTC's editor the 50 Hz one. A CBM-II's is one of
|
|
81
|
+
# CBM2::Model::ALL, with VICE's KERNAL, 901244-04a, at 50 Hz, or a 510,
|
|
82
|
+
# one of CBM2::P500::Model::ALL, with its region's mains.
|
|
81
83
|
def self.build(family, model:, sid_model: nil, reu: nil, ram: nil)
|
|
82
84
|
return vic20(model, ram) if family == :vic20
|
|
83
85
|
return c128(model, sid_model, :c64) if family == :c128
|
|
84
86
|
return Plus4.new(model:) if family == :plus4
|
|
85
87
|
return PET.new(model:) if family == :pet
|
|
88
|
+
return CBM2::P500.new(model:) if family == :cbm2 && model.start_with?("510")
|
|
89
|
+
return CBM2.new(model:) if family == :cbm2
|
|
86
90
|
raise ArgumentError, "no machine family named #{family}" unless family == :c64
|
|
87
91
|
|
|
88
92
|
profile = Model.named(model)
|
|
@@ -98,12 +102,14 @@ module Badline
|
|
|
98
102
|
# only C64 mode runs: a .sid tune or a program that loads at the C64's
|
|
99
103
|
# BASIC start. A VIC-20 without RAM named gets the expansion the media
|
|
100
104
|
# needs (Media::Vic20Media.ram_for) and yields a line saying so. Raises
|
|
101
|
-
# Unsupported for media a VIC-20, a Plus/4 or a
|
|
105
|
+
# Unsupported for media a VIC-20, a Plus/4, a PET or a CBM-II doesn't
|
|
106
|
+
# take.
|
|
102
107
|
def self.for_options(options, media, &)
|
|
103
108
|
family = options.family
|
|
104
109
|
return vic20_for(media, options.model, options.ram, &) if family == :vic20
|
|
105
110
|
return plus4_for(media, options) if family == :plus4
|
|
106
111
|
return pet_for(media, options) if family == :pet
|
|
112
|
+
return cbm2_for(media, options) if family == :cbm2
|
|
107
113
|
|
|
108
114
|
sid_model = options.sid_model || Media.sid_model(media, otherwise: nil)
|
|
109
115
|
return build(:c64, model: options.model, sid_model:, reu: options.reu) unless family == :c128
|
|
@@ -153,16 +159,28 @@ module Badline
|
|
|
153
159
|
|
|
154
160
|
# A PET with the RAM --ram names (PET::Model::RAM_SIZES), or with the
|
|
155
161
|
# model's own without it, the editor at the frame rate --60hz or
|
|
156
|
-
# --editor asks for,
|
|
162
|
+
# --editor asks for, the ROMs --basic, --editor and --characters fit it
|
|
163
|
+
# with, and the 8296 board's jumpers --jumpers names.
|
|
157
164
|
def self.pet_for(media, options)
|
|
158
165
|
unsupported = !media.nil? && Media::PETMedia::UNSUPPORTED.include?(File.extname(media).downcase)
|
|
159
166
|
raise Unsupported, "doesn't go in a PET" if unsupported
|
|
160
167
|
|
|
161
168
|
PET.new(model: options.model, ram_kb: options.ram_kb, refresh_hz: options.refresh_hz, basic: options.basic,
|
|
162
|
-
editor: options.editor)
|
|
169
|
+
editor: options.editor, characters: options.characters, jumpers: options.jumpers)
|
|
163
170
|
end
|
|
164
171
|
private_class_method :pet_for
|
|
165
172
|
|
|
173
|
+
# A CBM-II with the KERNAL --kernal names, on the mains --60hz asks
|
|
174
|
+
# for: a B series' 50 Hz without it, and a P500's its region's.
|
|
175
|
+
def self.cbm2_for(media, options)
|
|
176
|
+
unsupported = !media.nil? && Media::CBM2Media::UNSUPPORTED.include?(File.extname(media).downcase)
|
|
177
|
+
raise Unsupported, "doesn't go in a CBM-II" if unsupported
|
|
178
|
+
return CBM2::P500.new(model: options.model, mains_hz: options.mains_hz) if options.p500?
|
|
179
|
+
|
|
180
|
+
CBM2.new(model: options.model, kernal: options.kernal, mains_hz: options.mains_hz || 50)
|
|
181
|
+
end
|
|
182
|
+
private_class_method :cbm2_for
|
|
183
|
+
|
|
166
184
|
def self.c64_media?(media)
|
|
167
185
|
return false if media.nil? || !File.file?(media)
|
|
168
186
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Media
|
|
5
|
+
# What a CBM-II does with media of its own (Media.attach). Disks of
|
|
6
|
+
# every kind, .d80 and .d82 among them, directories and .t64 archives
|
|
7
|
+
# mount on device 8 through the traps on the KERNAL's IEEE-488
|
|
8
|
+
# primitives (CBM2::IEEETraps), programs load into BASIC's text segment
|
|
9
|
+
# (Program), and a CBM2 .crt's ROMs go in at their load addresses in
|
|
10
|
+
# segment 15. There is no datasette, the SID plays no .sid tunes, and
|
|
11
|
+
# the true drives are serial ones.
|
|
12
|
+
module CBM2Media
|
|
13
|
+
# What a CBM-II doesn't take.
|
|
14
|
+
UNSUPPORTED = Extensions.of(%i[tune tape gcr])
|
|
15
|
+
|
|
16
|
+
# What loads and runs the first program on the disk in device 8.
|
|
17
|
+
AUTOSTART = %(load"*",8\rrun\r)
|
|
18
|
+
|
|
19
|
+
# Where BASIC's text starts in segment 1, and the pointers to its end
|
|
20
|
+
# and to the KERNAL's end address (EAL) in segment 15.
|
|
21
|
+
BASIC_START = 0x0003
|
|
22
|
+
TEXT_END = 0x2f
|
|
23
|
+
EAL = 0x96
|
|
24
|
+
|
|
25
|
+
# The ROM chips of a CBM2 .crt.
|
|
26
|
+
def self.cartridge_chips(path) = Storage::CRTFile.new(path, machine: :cbm2).chips
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -10,7 +10,7 @@ module Badline
|
|
|
10
10
|
# is no cartridge port and no SID, and the true drives are serial ones.
|
|
11
11
|
module PETMedia
|
|
12
12
|
# What a PET doesn't take.
|
|
13
|
-
UNSUPPORTED = Extensions.of(%i[tune cartridge
|
|
13
|
+
UNSUPPORTED = Extensions.of(%i[tune cartridge])
|
|
14
14
|
|
|
15
15
|
# What loads and runs the first program on the disk in device 8.
|
|
16
16
|
AUTOSTART = %(load"*",8\rrun\r)
|
|
@@ -26,12 +26,12 @@ module Badline
|
|
|
26
26
|
|
|
27
27
|
# BASIC 2 and 4 load the first program off the disk and run it.
|
|
28
28
|
# BASIC 1's LOAD finds no device on the IEEE-488 bus, so the first
|
|
29
|
-
# program goes in as a program file does,
|
|
30
|
-
# booted.
|
|
31
|
-
def disk_autostart(machine
|
|
29
|
+
# program, which the block gives, goes in as a program file does,
|
|
30
|
+
# once the KERNAL has booted.
|
|
31
|
+
def disk_autostart(machine)
|
|
32
32
|
return machine.type_text(AUTOSTART) unless machine.model.basic1?
|
|
33
33
|
|
|
34
|
-
data =
|
|
34
|
+
data = yield
|
|
35
35
|
machine.on_init { Program.load(machine, data, autostart: true) } if data
|
|
36
36
|
end
|
|
37
37
|
end
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
module Badline
|
|
4
4
|
module Media
|
|
5
|
-
# A program loading into a C64, a C128, a 264 series machine
|
|
6
|
-
# once it has booted (Media.attach). The VIC-20 has its own
|
|
5
|
+
# A program loading into a C64, a C128, a 264 series machine, a PET or
|
|
6
|
+
# a CBM-II once it has booted (Media.attach). The VIC-20 has its own
|
|
7
7
|
# (Vic20Basic).
|
|
8
8
|
module Program
|
|
9
9
|
# Where BASIC 3.5 starts on the 264 series.
|
|
@@ -35,10 +35,13 @@ module Badline
|
|
|
35
35
|
# KERNAL's end address (EAL). BASIC 7.0 starts at $1C01 and keeps
|
|
36
36
|
# the end of its text at $1210, and the 264 KERNAL keeps EAL at $9D.
|
|
37
37
|
# PET BASIC 2 and 4 keep the end of their text at $2A and EAL at
|
|
38
|
-
# $C9, and BASIC 1 at $7C and $E5.
|
|
38
|
+
# $C9, and BASIC 1 at $7C and $E5. The CBM-II's BASIC starts at
|
|
39
|
+
# $0003 of segment 1 and keeps the end of its text at $2F, and its
|
|
40
|
+
# KERNAL EAL at $96, in segment 15.
|
|
39
41
|
def basic(computer)
|
|
40
42
|
return [PLUS4_BASIC_START, 0x2d, KernalTrap::PLUS4_ZERO_PAGE.end_address] if computer.family == :plus4
|
|
41
43
|
return pet_basic(computer) if computer.family == :pet
|
|
44
|
+
return [CBM2Media::BASIC_START, CBM2Media::TEXT_END, CBM2Media::EAL] if computer.family == :cbm2
|
|
42
45
|
return [0x1c01, 0x1210, 0xae] if computer.family == :c128 && computer.mode == :c128
|
|
43
46
|
|
|
44
47
|
[BASIC_START, 0x2d, 0xae]
|
|
@@ -4,18 +4,23 @@ module Badline
|
|
|
4
4
|
module Media
|
|
5
5
|
# Device 8 as a true drive instead of the KERNAL traps: a 1541, or on
|
|
6
6
|
# the C128 its 1571, or on the Plus/4 a 1551 if it asks for one, or a
|
|
7
|
-
# 1581
|
|
7
|
+
# 1581, or on the PET or the CBM-II a 2031 on the IEEE-488 bus, or for
|
|
8
|
+
# a .d80 or .d82 an 8050 or 8250. Once a true drive is plugged in as device 8, disk media go into
|
|
8
9
|
# it rather than into the traps, so a LOAD runs the DOS and every byte
|
|
9
10
|
# crosses the serial bus or TCBM. A .g64 holds the
|
|
10
11
|
# disk's raw GCR, which only a true drive reads, so it plugs one in
|
|
11
12
|
# when there's none yet. The 1541 reads only .d64 and .g64 images, the
|
|
12
13
|
# 1571 .d71 and .g71 as well, and the 1581 only .d81, so a .d81 swaps
|
|
13
14
|
# the drive on device 8 for a 1581 (Drives::Model1581::Slot), and another disk
|
|
14
|
-
# image swaps a 1581 back for the machine's own drive. The
|
|
15
|
-
#
|
|
15
|
+
# image swaps a 1581 back for the machine's own drive. The PET and the
|
|
16
|
+
# CBM-II have no 1581, and their 2031 reads .d64 and .g64 images only.
|
|
17
|
+
# The traps' other disk media, a .t64 or a host directory, raise Error.
|
|
16
18
|
module TrueDrive
|
|
17
19
|
class Error < ArgumentError; end
|
|
18
20
|
|
|
21
|
+
# The families whose drives sit on the IEEE-488 bus.
|
|
22
|
+
IEEE_FAMILIES = %i[pet cbm2].freeze
|
|
23
|
+
|
|
19
24
|
class << self
|
|
20
25
|
# Plugs the machine's true drive in as device 8, unless one is there
|
|
21
26
|
# already, and returns it.
|
|
@@ -36,7 +41,7 @@ module Badline
|
|
|
36
41
|
kind = Extensions.kind(path)
|
|
37
42
|
return true if kind == :gcr
|
|
38
43
|
|
|
39
|
-
!drive(computer).nil? && (File.directory?(path) || %i[disk archive].include?(kind))
|
|
44
|
+
!drive(computer).nil? && (File.directory?(path) || %i[disk archive ieee_disk].include?(kind))
|
|
40
45
|
end
|
|
41
46
|
|
|
42
47
|
# Puts the image in the drive on device 8, plugging one in that
|
|
@@ -44,12 +49,16 @@ module Badline
|
|
|
44
49
|
# mounted through the traps, so LOAD and SAVE reach the drive too.
|
|
45
50
|
# `read_only` puts it in write-protected.
|
|
46
51
|
def insert(computer, path, read_only: false)
|
|
47
|
-
|
|
52
|
+
swapped = insert_swapping(computer, path, read_only)
|
|
53
|
+
return swapped if swapped
|
|
48
54
|
|
|
55
|
+
pet = IEEE_FAMILIES.include?(computer.family)
|
|
49
56
|
drive = own_drive(computer)
|
|
50
|
-
name = drive&.model_name || (computer
|
|
57
|
+
name = drive&.model_name || default_model(computer)
|
|
51
58
|
types = name == "1571" ? %w[.d64 .g64 .d71 .g71] : %w[.d64 .g64]
|
|
52
59
|
unless types.include?(File.extname(path).downcase)
|
|
60
|
+
raise Error, "#{path} is not a #{types.join(' or ')} image, which the #{name} reads" if pet
|
|
61
|
+
|
|
53
62
|
raise Error, "#{path} is not a #{types.join(', ')} or .d81 image, which the #{name} and the 1581 read"
|
|
54
63
|
end
|
|
55
64
|
|
|
@@ -61,10 +70,43 @@ module Badline
|
|
|
61
70
|
|
|
62
71
|
private
|
|
63
72
|
|
|
64
|
-
# The
|
|
73
|
+
# The model plug_true_drive plugs in.
|
|
74
|
+
def default_model(computer)
|
|
75
|
+
case computer.family
|
|
76
|
+
when :c128 then "1571"
|
|
77
|
+
when :pet, :cbm2 then "2031"
|
|
78
|
+
else "1541"
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# The drive on device 8 unless it's a 1581, or an 8050 or 8250,
|
|
83
|
+
# which a .d64 swaps back out.
|
|
65
84
|
def own_drive(computer)
|
|
66
85
|
drive = drive(computer)
|
|
67
|
-
drive unless drive&.model_name
|
|
86
|
+
drive unless %w[1581 8050 8250].include?(drive&.model_name)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# A .d81 in a 1581, and on the PET or the CBM-II a .d80 or .d82 in
|
|
90
|
+
# an 8050 or 8250, each swapped in for the drive there, or nil for
|
|
91
|
+
# the rest.
|
|
92
|
+
def insert_swapping(computer, path, read_only)
|
|
93
|
+
extension = File.extname(path).downcase
|
|
94
|
+
if IEEE_FAMILIES.include?(computer.family)
|
|
95
|
+
insert_d80(computer, path, read_only) if %w[.d80 .d82].include?(extension)
|
|
96
|
+
elsif extension == ".d81"
|
|
97
|
+
insert_d81(computer, path, read_only)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# An 8050 for a .d80 and an 8250 for a .d82, swapped in for the
|
|
102
|
+
# drive on device 8 unless it's that model already.
|
|
103
|
+
def insert_d80(computer, path, read_only)
|
|
104
|
+
model = File.extname(path).casecmp?(".d82") ? "8250" : "8050"
|
|
105
|
+
drive = drive(computer)
|
|
106
|
+
drive = computer.plug_drive8050(model) unless drive&.model_name == model
|
|
107
|
+
drive.insert_image(path, read_only:)
|
|
108
|
+
computer.unmount
|
|
109
|
+
"Inserted #{path} in the #{model} as device 8"
|
|
68
110
|
end
|
|
69
111
|
|
|
70
112
|
def insert_d81(computer, path, read_only)
|
data/lib/badline/media.rb
CHANGED
|
@@ -12,6 +12,7 @@ require "badline/media/vic20_cartridge"
|
|
|
12
12
|
require "badline/media/vic20_media"
|
|
13
13
|
require "badline/media/plus4_media"
|
|
14
14
|
require "badline/media/pet_media"
|
|
15
|
+
require "badline/media/cbm2_media"
|
|
15
16
|
require "badline/media/tune"
|
|
16
17
|
require "badline/media/program"
|
|
17
18
|
|
|
@@ -53,8 +54,9 @@ module Badline
|
|
|
53
54
|
# .crt cartridges and raw .bin ROM images in its two cartridges'
|
|
54
55
|
# slots (Plus4Media), and no .sid tunes either. The PET mounts .d80
|
|
55
56
|
# and .d82 disks too, which no other machine takes, and has no
|
|
56
|
-
# cartridges, tunes or true drives (PETMedia)
|
|
57
|
-
# takes
|
|
57
|
+
# cartridges, tunes or true drives (PETMedia), and so does the CBM-II,
|
|
58
|
+
# which takes its own .crt cartridges and no tapes (CBM2Media). The
|
|
59
|
+
# C128 in C64 mode takes a C64's.
|
|
58
60
|
def attach(computer, path, autostart: true, subtune: nil, **)
|
|
59
61
|
path = DiskList.disk(path)
|
|
60
62
|
refuse_unsupported(computer, path)
|
|
@@ -126,17 +128,19 @@ module Badline
|
|
|
126
128
|
private
|
|
127
129
|
|
|
128
130
|
# The VIC-20 and the 264 series have no SID to play a .sid tune on,
|
|
129
|
-
# and only the PET
|
|
131
|
+
# and only the PET and the CBM-II have the IEEE-488 drive a .d80 or
|
|
132
|
+
# .d82 goes in.
|
|
130
133
|
def refuse_unsupported(computer, path)
|
|
131
134
|
family = computer.family
|
|
132
|
-
if Extensions.kind(path) == :ieee_disk && family
|
|
133
|
-
raise ArgumentError, "#{path} needs a PET's IEEE-488 drive"
|
|
135
|
+
if Extensions.kind(path) == :ieee_disk && !%i[pet cbm2].include?(family)
|
|
136
|
+
raise ArgumentError, "#{path} needs a PET's or a CBM-II's IEEE-488 drive"
|
|
134
137
|
end
|
|
135
138
|
|
|
136
139
|
refused, name = case family
|
|
137
140
|
when :vic20 then [Vic20Media::UNSUPPORTED, "a VIC-20"]
|
|
138
141
|
when :plus4 then [Vic20Media::UNSUPPORTED, "a Plus/4"]
|
|
139
142
|
when :pet then [PETMedia::UNSUPPORTED, "a PET"]
|
|
143
|
+
when :cbm2 then [CBM2Media::UNSUPPORTED, "a CBM-II"]
|
|
140
144
|
else [[], ""]
|
|
141
145
|
end
|
|
142
146
|
raise ArgumentError, "#{path} doesn't go in #{name}" if refused.include?(File.extname(path).downcase)
|
|
@@ -159,7 +163,11 @@ module Badline
|
|
|
159
163
|
|
|
160
164
|
def attach_true_drive(computer, path, disk, autostart:)
|
|
161
165
|
message = TrueDrive.insert(computer, path, read_only: disk.fetch(:read_only, false))
|
|
162
|
-
|
|
166
|
+
if autostart && computer.family == :pet
|
|
167
|
+
PETMedia.disk_autostart(computer) { Vic20Media.first_program(path) }
|
|
168
|
+
elsif autostart
|
|
169
|
+
computer.type_text(disk_autostart(computer) { Vic20Media.first_program(path) })
|
|
170
|
+
end
|
|
163
171
|
message
|
|
164
172
|
end
|
|
165
173
|
|
|
@@ -167,7 +175,7 @@ module Badline
|
|
|
167
175
|
storage = open_storage(path, disk)
|
|
168
176
|
computer.mount(storage)
|
|
169
177
|
if autostart && computer.family == :pet
|
|
170
|
-
PETMedia.disk_autostart(computer
|
|
178
|
+
PETMedia.disk_autostart(computer) { storage.read_file("*") }
|
|
171
179
|
elsif autostart
|
|
172
180
|
computer.type_text(disk_autostart(computer) { storage.read_file("*") })
|
|
173
181
|
end
|
|
@@ -178,7 +186,11 @@ module Badline
|
|
|
178
186
|
# VIC-20 goes by that program, which the block gives
|
|
179
187
|
# (Vic20Media.disk_autostart).
|
|
180
188
|
def disk_autostart(computer)
|
|
181
|
-
computer.family
|
|
189
|
+
case computer.family
|
|
190
|
+
when :vic20 then Vic20Media.disk_autostart(yield)
|
|
191
|
+
when :cbm2 then CBM2Media::AUTOSTART
|
|
192
|
+
else AUTOSTART
|
|
193
|
+
end
|
|
182
194
|
end
|
|
183
195
|
|
|
184
196
|
# A VIC-20 or 264 series cartridge is its ROM chips. On the 264, the
|
|
@@ -190,6 +202,7 @@ module Badline
|
|
|
190
202
|
crt = Storage::CRTFile.new(path, machine: :vic20)
|
|
191
203
|
computer.attach_cartridge(crt.chips, crt.name.empty? ? File.basename(path, File.extname(path)) : crt.name)
|
|
192
204
|
when :plus4 then computer.attach_cartridge(Plus4Media.cartridge_chips(path, slot: options.fetch(:slot, nil)))
|
|
205
|
+
when :cbm2 then computer.attach_cartridge(CBM2Media.cartridge_chips(path))
|
|
193
206
|
else
|
|
194
207
|
computer.attach_cartridge(C64::Cartridge.from_file(path, **options))
|
|
195
208
|
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "badline/storage/crt_file"
|
|
3
4
|
require "badline/storage/p00"
|
|
4
5
|
require "badline/storage/tap"
|
|
5
6
|
|
|
@@ -13,7 +14,8 @@ module Badline
|
|
|
13
14
|
|
|
14
15
|
private
|
|
15
16
|
|
|
16
|
-
# Takes `sid`, `c64`, `vic20`, `c128`, `plus4` or `
|
|
17
|
+
# Takes `sid`, `c64`, `vic20`, `c128`, `plus4`, `pet` or `cbm2` when
|
|
18
|
+
# given first.
|
|
17
19
|
def subcommand(args)
|
|
18
20
|
case args.first
|
|
19
21
|
when "sid" then @sid_command = true
|
|
@@ -22,6 +24,7 @@ module Badline
|
|
|
22
24
|
when "c128" then @family = :c128
|
|
23
25
|
when "plus4" then @family = :plus4
|
|
24
26
|
when "pet" then @family = :pet
|
|
27
|
+
when "cbm2" then @family = :cbm2
|
|
25
28
|
else return
|
|
26
29
|
end
|
|
27
30
|
@family_named = !@sid_command
|
|
@@ -34,23 +37,32 @@ module Badline
|
|
|
34
37
|
when :c128 then C128_MODELS
|
|
35
38
|
when :plus4 then PLUS4_MODELS
|
|
36
39
|
when :pet then PET_MODELS
|
|
40
|
+
when :cbm2 then CBM2_MODELS
|
|
37
41
|
else MODELS
|
|
38
42
|
end
|
|
39
43
|
end
|
|
40
44
|
|
|
41
45
|
# Without a family named, a program that loads at C128_BASIC_START is
|
|
42
|
-
# the C128's,
|
|
43
|
-
#
|
|
46
|
+
# the C128's, an 8050's or 8250's disk or a PET tape the PET's, and a
|
|
47
|
+
# cartridge signed as a CBM-II's the CBM-II's. A program that loads
|
|
48
|
+
# where PET BASIC starts could be a VIC-20's too.
|
|
44
49
|
def pick_family
|
|
45
50
|
return if @family_named || @sid_command || @media_path.nil? || !File.file?(@media_path)
|
|
46
51
|
|
|
47
52
|
if pet_media?
|
|
48
53
|
@family = :pet
|
|
54
|
+
elsif cbm2_cartridge?
|
|
55
|
+
@family = :cbm2
|
|
49
56
|
elsif Media::Extensions::PROGRAMS.include?(File.extname(@media_path).downcase)
|
|
50
57
|
@family = :c128 if Storage::P00.load_address(@media_path) == C128_BASIC_START
|
|
51
58
|
end
|
|
52
59
|
end
|
|
53
60
|
|
|
61
|
+
# Whether the media is a cartridge signed as a CBM-II's.
|
|
62
|
+
def cbm2_cartridge?
|
|
63
|
+
Media::Extensions.kind(@media_path) == :cartridge && Storage::CRTFile.cbm2?(@media_path)
|
|
64
|
+
end
|
|
65
|
+
|
|
54
66
|
# Whether the media is an 8050's or 8250's disk or a PET tape.
|
|
55
67
|
def pet_media?
|
|
56
68
|
kind = Media::Extensions.kind(@media_path)
|
data/lib/badline/options/help.rb
CHANGED
|
@@ -86,6 +86,7 @@ module Badline
|
|
|
86
86
|
#{@program} c128 [options] [media]
|
|
87
87
|
#{@program} plus4 [options] [media]
|
|
88
88
|
#{@program} pet [options] [media]
|
|
89
|
+
#{@program} cbm2 [options] [media]
|
|
89
90
|
#{@program} --headless [options] tune.sid
|
|
90
91
|
#{@program} [options] tune.sid --audio-out FILE
|
|
91
92
|
#{@program} sid [options] FILE|DIR...
|
|
@@ -96,6 +97,7 @@ module Badline
|
|
|
96
97
|
c128 Run a C128 in C128 mode, the one --model names
|
|
97
98
|
plus4 Run a Plus/4 or a C16, the one --model names
|
|
98
99
|
pet Run a PET or a CBM, the one --model names
|
|
100
|
+
cbm2 Run a CBM-II, a B series or a P500, the one --model names
|
|
99
101
|
sid Play .sid tunes and directories of them
|
|
100
102
|
|
|
101
103
|
#{media_kinds}
|
|
@@ -126,10 +128,26 @@ module Badline
|
|
|
126
128
|
and the pause menu's KEYBOARD page says where the rest are. --basic
|
|
127
129
|
and --editor fit the upgrades Commodore sold, as in --model 2001
|
|
128
130
|
--basic 2. BASIC 1 can't LOAD from a disk drive, though a disk still
|
|
129
|
-
starts its first program, and BASIC 2 can.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
starts its first program, and BASIC 2 can. Their --true-drive makes
|
|
132
|
+
device 8 an emulated 2031 on the IEEE-488 bus, which reads .d64 and
|
|
133
|
+
.g64 images. The 8032 and the 8096 have two 50 Hz editors:
|
|
134
|
+
4-80-b-50hz, the default, and 4-80-b-50hz-0283, another chip's,
|
|
135
|
+
with 64-cycle lines and 313 lines a frame. The 8296 runs its own,
|
|
136
|
+
4-80-b-50hz-8296, and takes the 8032's too. --characters din fits
|
|
137
|
+
it with the DIN character ROM, and --jumpers ram9,rama puts RAM at
|
|
138
|
+
$9000 and $A000, as xpet's -petram9 and -petramA do.
|
|
139
|
+
|
|
140
|
+
The CBM-II takes programs, disks, .d80 and .d82 among them, and
|
|
141
|
+
cartridges, and a cartridge made for it starts one without `cbm2`.
|
|
142
|
+
--kernal 03b fits the 1983 KERNAL in place of 04a, and --60hz runs
|
|
143
|
+
it on 60 Hz mains. Its --true-drive makes device 8 an emulated 2031
|
|
144
|
+
on its IEEE-488 bus, which reads .d64 and .g64 images, and a .d80
|
|
145
|
+
or a .d82 then goes in an emulated 8050 or 8250. Its keys type what
|
|
146
|
+
the host's keys type, F12 is RUN/STOP, Alt with F9 or F10 presses
|
|
147
|
+
its F9 or F10, and the pause menu's KEYBOARD page says where the
|
|
148
|
+
rest are. --model 510 or 510ntsc runs the P500, on the VIC-II with
|
|
149
|
+
KERNAL 02, whose keys are the B series' and whose two joysticks Tab
|
|
150
|
+
switches to.
|
|
133
151
|
|
|
134
152
|
--headless plays a .sid tune on the host's audio device without the
|
|
135
153
|
window, and --audio-out renders it to 16-bit PCM instead. The
|
|
@@ -152,8 +170,8 @@ module Badline
|
|
|
152
170
|
in --at 3500:key=space or --at 250,500:screenshot=shot%05d.bmp.
|
|
153
171
|
key=NAME presses a key (space, return, a, f1, run_stop, restore, and
|
|
154
172
|
on the C128 esc, help, keypad1 and the rest, on the Plus/4
|
|
155
|
-
esc, help and f1 to f3,
|
|
156
|
-
joystick's
|
|
173
|
+
esc, help and f1 to f3, on the PET rvs, escape and kp1, and on
|
|
174
|
+
the CBM-II escape, norm_graph and kp00) or a joystick's
|
|
157
175
|
direction or fire (joy1-up, joy2-fire) for #{Event::HOLD} frames, and
|
|
158
176
|
pushes the C128's caps_lock or forty_eighty, which lock. type=TEXT
|
|
159
177
|
types it, with \\n for RETURN. insert=FILE swaps in a disk, a list's
|