badline 0.15.1 → 0.16.1
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 +55 -0
- data/CLAUDE.md +8 -7
- data/README.md +128 -9
- data/doc/media.md +9 -0
- data/doc/pinned-behaviour.md +67 -0
- data/doc/snapshot-format.md +215 -18
- data/doc/snapshots.md +55 -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 +74 -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/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.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 +24 -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 +151 -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 +29 -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/true_drive.rb +19 -6
- data/lib/badline/media/vic20_media.rb +2 -2
- data/lib/badline/media.rb +41 -17
- data/lib/badline/options/family.rb +17 -6
- data/lib/badline/options/help.rb +23 -3
- data/lib/badline/options/table.rb +22 -4
- data/lib/badline/options/validation.rb +84 -5
- data/lib/badline/options.rb +47 -16
- data/lib/badline/pet/bus/expansion.rb +200 -0
- data/lib/badline/pet/bus.rb +222 -0
- data/lib/badline/pet/canvas.rb +97 -0
- data/lib/badline/pet/cassettes.rb +63 -0
- data/lib/badline/pet/characters.rb +32 -0
- data/lib/badline/pet/cpu.rb +10 -0
- data/lib/badline/pet/crtc_video.rb +155 -0
- data/lib/badline/pet/discrete_video.rb +83 -0
- data/lib/badline/pet/ieee_drive.rb +76 -0
- data/lib/badline/pet/ieee_ports.rb +77 -0
- data/lib/badline/pet/ieee_traps.rb +80 -0
- data/lib/badline/pet/keyboard_ports.rb +74 -0
- data/lib/badline/pet/keyed_modules.rb +88 -0
- data/lib/badline/pet/keyed_parts.rb +127 -0
- data/lib/badline/pet/keyed_state.rb +42 -0
- data/lib/badline/pet/model.rb +163 -0
- data/lib/badline/pet/rom_sets.rb +89 -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 +244 -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 +169 -0
- data/lib/badline/roms/dos2031.rom +0 -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/characters-din.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-8296.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 +6 -1
- data/lib/badline/snapshot/field_doc/markdown.rb +1 -1
- data/lib/badline/snapshot/field_doc.rb +17 -3
- data/lib/badline/snapshot/image.rb +28 -10
- data/lib/badline/snapshot/pet_setup.rb +88 -0
- data/lib/badline/snapshot/storage_setup.rb +7 -1
- data/lib/badline/snapshot/vice/pet.rb +117 -0
- data/lib/badline/snapshot/vice/pet_cpu.rb +67 -0
- data/lib/badline/snapshot/vice/pet_crtc.rb +246 -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 +150 -0
- data/lib/badline/snapshot/vice/pet_via.rb +164 -0
- data/lib/badline/snapshot/vice.rb +1 -0
- 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 +70 -1
data/lib/badline/pet.rb
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "badline/pet/rom_sets"
|
|
4
|
+
require "badline/pet/model"
|
|
5
|
+
require "badline/pet/cpu"
|
|
6
|
+
require "badline/pet/via"
|
|
7
|
+
require "badline/pet/via_ports"
|
|
8
|
+
require "badline/pet/keyboard_ports"
|
|
9
|
+
require "badline/pet/ieee_ports"
|
|
10
|
+
require "badline/pet/ieee_traps"
|
|
11
|
+
require "badline/pet/ieee_drive"
|
|
12
|
+
require "badline/pet/cassettes"
|
|
13
|
+
require "badline/pet/characters"
|
|
14
|
+
require "badline/pet/canvas"
|
|
15
|
+
require "badline/pet/discrete_video"
|
|
16
|
+
require "badline/pet/crtc_video"
|
|
17
|
+
require "badline/pet/bus"
|
|
18
|
+
require "badline/pet/sound"
|
|
19
|
+
require "badline/snapshot/pet_setup"
|
|
20
|
+
require "badline/pet/keyed_parts"
|
|
21
|
+
require "badline/pet/keyed_state"
|
|
22
|
+
require "badline/pet/keyed_modules"
|
|
23
|
+
|
|
24
|
+
module Badline
|
|
25
|
+
# The Commodore PET and CBM: a 6502 at 1 MHz, two 6520 PIAs at $E810 and
|
|
26
|
+
# $E820, a 6522 VIA at $E840 and, from the 4032 on, a 6545 CRTC at
|
|
27
|
+
# $E880. Every chip's IRQ is wired to the CPU's, and nothing pulls NMI.
|
|
28
|
+
# Nothing halts the CPU either: the video reads the screen RAM between
|
|
29
|
+
# its accesses.
|
|
30
|
+
#
|
|
31
|
+
# The video's vertical drive line, low in the retrace, reaches PIA 1's
|
|
32
|
+
# CB1, whose falling edge is the editor's 50 or 60 Hz interrupt, and the
|
|
33
|
+
# VIA's PB5. The discrete boards count it out themselves
|
|
34
|
+
# (DiscreteVideo), and the CRTC boards take it from the CRTC's vertical
|
|
35
|
+
# sync, inverted.
|
|
36
|
+
#
|
|
37
|
+
# The key matrix hangs off PIA 1 (KeyboardPorts), the graphics one or
|
|
38
|
+
# the business one as the model has, and type_text types through the
|
|
39
|
+
# editor's keyboard buffer.
|
|
40
|
+
#
|
|
41
|
+
# The discrete boards paint their picture (DiscreteVideo) on a Canvas.
|
|
42
|
+
# The CRTC boards paint theirs from the CRTC's outputs (CRTCVideo).
|
|
43
|
+
# The VIA's CB2 is the sound (Sound).
|
|
44
|
+
#
|
|
45
|
+
# Device 8 answers through traps on the KERNAL's IEEE-488 primitives
|
|
46
|
+
# (IEEETraps), on the IEEE-488 bus (IEEEPorts), or a true 2031 on the
|
|
47
|
+
# bus answers (IEEEDrive), and each cassette port has a datasette
|
|
48
|
+
# (Cassettes). It runs headless.
|
|
49
|
+
class PET
|
|
50
|
+
include Machine::KeyboardBuffer
|
|
51
|
+
include Machine::Clocking
|
|
52
|
+
include Machine::Settling
|
|
53
|
+
include IEEETraps
|
|
54
|
+
include IEEEDrive
|
|
55
|
+
|
|
56
|
+
attr_reader :model, :bus, :cpu, :pia1, :pia2, :via, :crtc, :keyboard, :ieee, :cassettes, :cycles, :init_threshold
|
|
57
|
+
|
|
58
|
+
# The editor's frame rate: 50 or 60 on a CRTC board, 60 on the others.
|
|
59
|
+
attr_reader :refresh_hz
|
|
60
|
+
|
|
61
|
+
# The RAM below $8000, in K.
|
|
62
|
+
attr_reader :ram_kb
|
|
63
|
+
|
|
64
|
+
# The 8296's board jumpers that are fitted, by name.
|
|
65
|
+
attr_reader :jumpers
|
|
66
|
+
|
|
67
|
+
def ram = @bus.ram
|
|
68
|
+
|
|
69
|
+
# Reads and writes memory as the CPU sees it, through the bus.
|
|
70
|
+
def peek(addr) = @bus.peek(addr)
|
|
71
|
+
|
|
72
|
+
def poke(addr, value) = @bus.poke(addr, value)
|
|
73
|
+
|
|
74
|
+
def install_debug_register(&) = @bus.install_debug_register(&)
|
|
75
|
+
|
|
76
|
+
def family = :pet
|
|
77
|
+
|
|
78
|
+
# The datasette on cassette port #1, where a tape goes in (Cassettes).
|
|
79
|
+
def datasette = @cassettes.datasette1
|
|
80
|
+
|
|
81
|
+
# +model+ names one of Model::ALL, with +ram_kb+ of RAM below $8000
|
|
82
|
+
# (Model::RAM_SIZES) in place of the model's own when not nil. A CRTC
|
|
83
|
+
# model runs its 50 Hz editor, or its 60 Hz one for +refresh_hz+ 60.
|
|
84
|
+
# +basic+, +editor+ and +characters+ name ROMs the board takes in place
|
|
85
|
+
# of its own (Model.upgraded, Model.fitted), and +jumpers+ the 8296's
|
|
86
|
+
# board jumpers (ROMSets::JUMPERS).
|
|
87
|
+
def initialize(model: Model::DEFAULT, ram_kb: nil, refresh_hz: 50, debug: false, basic: nil, editor: nil,
|
|
88
|
+
characters: nil, jumpers: [])
|
|
89
|
+
@model = Model.fitted(Model.upgraded(Model.named(model), basic, editor), characters)
|
|
90
|
+
ram_kb ||= @model.ram_kb
|
|
91
|
+
raise ArgumentError, "the #{@model.name} has no #{ram_kb}K RAM board" unless Model.ram_fits?(@model, ram_kb)
|
|
92
|
+
|
|
93
|
+
@ram_kb = ram_kb
|
|
94
|
+
@jumpers = Model.checked_jumpers(@model, jumpers)
|
|
95
|
+
|
|
96
|
+
@refresh_hz = @model.crtc? ? refresh_hz : 60
|
|
97
|
+
@crtc_video = @model.crtc?
|
|
98
|
+
@vertical_drive = true
|
|
99
|
+
matrix = @model.keyboard == :business ? KeyboardPorts::BUSINESS_MATRIX : KeyboardPorts::GRAPHICS_MATRIX
|
|
100
|
+
@keyboard = Input::Keyboard.new(matrix:)
|
|
101
|
+
keyboard_ports = KeyboardPorts.new(@keyboard)
|
|
102
|
+
registers = Array.new(Chips::CRTC::MASKS.length, 0)
|
|
103
|
+
@pia1 = Chips::PIA.new(peripheral: keyboard_ports)
|
|
104
|
+
@ieee = IEEEPorts.new(Drives::IEEEBus.new)
|
|
105
|
+
@pia2 = Chips::PIA.new(peripheral: @ieee)
|
|
106
|
+
@via = VIA.new(start: 0xe800, peripheral: VIAPorts.new(self))
|
|
107
|
+
@sound = Sound.new(@via)
|
|
108
|
+
@cassettes = Cassettes.new(@pia1, @via)
|
|
109
|
+
keyboard_ports.connect(@pia1, @ieee, @cassettes)
|
|
110
|
+
characters = Characters.new(@model.characters)
|
|
111
|
+
@crtc_output = CRTCVideo.new(characters, @via, registers, columns80: @model.video == :crtc80,
|
|
112
|
+
board8296: @model.cbm8296?)
|
|
113
|
+
@crtc = Chips::CRTC.new(@crtc_output, registers:)
|
|
114
|
+
@ieee.connect(@pia1, @pia2, @via)
|
|
115
|
+
@bus = Bus.new(model: @model, ram_kb:, editor: @model.editor(@refresh_hz), pia1: @pia1, pia2: @pia2,
|
|
116
|
+
via: @via, crtc: @crtc, jumpers: @jumpers)
|
|
117
|
+
@crtc_output.cells = @bus.screen.cells
|
|
118
|
+
@discrete = DiscreteVideo.new(@bus.screen.cells, characters, @via)
|
|
119
|
+
@canvas = @crtc_video ? @crtc_output.canvas : @discrete.canvas
|
|
120
|
+
cassettes = @cassettes
|
|
121
|
+
ieee = @ieee
|
|
122
|
+
@bus.on_io_write do
|
|
123
|
+
cassettes.lines_written
|
|
124
|
+
ieee.lines_written
|
|
125
|
+
end
|
|
126
|
+
@cpu = CPU.new(@bus, debug:)
|
|
127
|
+
@cycles = 0
|
|
128
|
+
@init_handlers = []
|
|
129
|
+
@pending_keys = nil
|
|
130
|
+
@dos = nil
|
|
131
|
+
@ieee_trap = nil
|
|
132
|
+
@capture_output = nil
|
|
133
|
+
@drive2031 = nil
|
|
134
|
+
@init_threshold = boot_cycles(ram_kb)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# The vertical drive line, high but in the retrace.
|
|
138
|
+
def vertical_drive? = @vertical_drive
|
|
139
|
+
|
|
140
|
+
# The model, its RAM and its editor's frame rate as the pause menu
|
|
141
|
+
# names them, such as "8032, 32K RAM, 50 HZ", all 128K on an 8296.
|
|
142
|
+
def model_label = "#{@model.name.upcase}, #{@model.cbm8296? ? 128 : @ram_kb}K RAM, #{@refresh_hz} HZ"
|
|
143
|
+
|
|
144
|
+
# The Canvas a front end shows.
|
|
145
|
+
def video = @canvas
|
|
146
|
+
|
|
147
|
+
# The 1 MHz clock and the frame the editor sets up, and all of the
|
|
148
|
+
# Canvas. The CRTC editors' lines and frames are their ROM's
|
|
149
|
+
# (ROMSets.crtc_frame), which a program can change. 80 columns show
|
|
150
|
+
# two dots to a window pixel.
|
|
151
|
+
def timing
|
|
152
|
+
crop = [0, 0, @canvas.width, @canvas.height]
|
|
153
|
+
if @crtc_video
|
|
154
|
+
cycles_per_line, lines_per_frame = ROMSets.crtc_frame(@model.editor(@refresh_hz), @refresh_hz)
|
|
155
|
+
Timing.new(clock_hz: 1_000_000, cycles_per_line:, lines_per_frame:,
|
|
156
|
+
crop:, pixel_width: 1, dots: @model.video == :crtc80 ? 2 : 1)
|
|
157
|
+
else
|
|
158
|
+
Timing.new(clock_hz: 1_000_000, cycles_per_line: DiscreteVideo::CYCLES_PER_LINE,
|
|
159
|
+
lines_per_frame: DiscreteVideo::LINES_PER_FRAME, crop:, pixel_width: 1, dots: 1)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# The video counts and moves the vertical drive line, then the PIAs
|
|
164
|
+
# and the VIA clock, ahead of the CPU, and the drive after it.
|
|
165
|
+
def cycle!
|
|
166
|
+
handle_init if @cycles == @init_threshold
|
|
167
|
+
feed_keyboard if @pending_keys
|
|
168
|
+
|
|
169
|
+
if @crtc_video
|
|
170
|
+
@crtc.cycle!
|
|
171
|
+
drive_retrace(!@crtc.vsync?)
|
|
172
|
+
else
|
|
173
|
+
@discrete.cycle!
|
|
174
|
+
drive_retrace(@discrete.vertical_drive?)
|
|
175
|
+
end
|
|
176
|
+
@pia1.cycle!
|
|
177
|
+
@pia2.cycle!
|
|
178
|
+
@via.cycle!
|
|
179
|
+
@sound.cycle! if @sound.recording?
|
|
180
|
+
@cassettes.cycle!
|
|
181
|
+
@cpu.irq = @pia1.irq? || @pia2.irq? || @via.irq?
|
|
182
|
+
@cpu.cycle!
|
|
183
|
+
@drive2031&.host_cycle!
|
|
184
|
+
|
|
185
|
+
@cycles += 1
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# What a front end plays: the VIA's CB2 (Sound), which answers #record
|
|
189
|
+
# and #drain_samples.
|
|
190
|
+
def sound_source = @sound
|
|
191
|
+
|
|
192
|
+
# The RES line reaches the CPU, the PIAs, the VIA, the CRTC, the
|
|
193
|
+
# 8096's control register and, as IFC, the drive.
|
|
194
|
+
def reset!
|
|
195
|
+
@pia1.reset!
|
|
196
|
+
@pia2.reset!
|
|
197
|
+
@via.reset!
|
|
198
|
+
@crtc.reset!
|
|
199
|
+
@bus.reset!
|
|
200
|
+
@drive2031&.reset!
|
|
201
|
+
@ieee.lines_written
|
|
202
|
+
@cpu.reset!
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Switches the machine off and on: RAM starts cleared, and the RES
|
|
206
|
+
# line resets everything else.
|
|
207
|
+
def power_cycle!
|
|
208
|
+
@bus.power_on!
|
|
209
|
+
reset!
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# Puts a program file's bytes where its first two say, through the bus,
|
|
213
|
+
# and returns that address.
|
|
214
|
+
def load_prg(data)
|
|
215
|
+
load_addr = data[0] | (data[1] << 8)
|
|
216
|
+
bytes = data[2..] || []
|
|
217
|
+
bytes = bytes[0, 0x10000 - load_addr] if load_addr + bytes.length > 0x10000
|
|
218
|
+
bytes.each_with_index { |byte, i| @bus.poke(load_addr + i, byte) }
|
|
219
|
+
load_addr
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Where the editor keeps its keyboard buffer: in page 2 under BASIC 1,
|
|
223
|
+
# in the zero page and page 2 under BASIC 2 and 4.
|
|
224
|
+
def keyboard_buffer
|
|
225
|
+
@model.basic1? ? Machine::KeyboardBuffer::PET_BASIC1_LAYOUT : Machine::KeyboardBuffer::PET_LAYOUT
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
private
|
|
229
|
+
|
|
230
|
+
# The cycle by which the KERNAL has booted and BASIC printed READY,
|
|
231
|
+
# with a margin. The RAM test takes most of it, about 41,000 to
|
|
232
|
+
# 44,000 cycles a K, and the CRTC editors take another 600,000 or so
|
|
233
|
+
# before it: READY is up by about 440,000 on a 2001 with 8K, 1,450,000
|
|
234
|
+
# on a 3032 and 1,980,000 on an 8032.
|
|
235
|
+
def boot_cycles(ram_kb) = (@model.basic == "pet/basic4.rom" ? 700_000 : 150_000) + (46_000 * ram_kb)
|
|
236
|
+
|
|
237
|
+
def drive_retrace(high)
|
|
238
|
+
return if high == @vertical_drive
|
|
239
|
+
|
|
240
|
+
@vertical_drive = high
|
|
241
|
+
@pia1.cb1 = high
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
@@ -4,9 +4,9 @@ module Badline
|
|
|
4
4
|
class Plus4
|
|
5
5
|
# The machine's own fields in a keyed snapshot module (Snapshot::Keyed,
|
|
6
6
|
# BL-MACHINE): the family, its setup by name (Snapshot::Plus4Setup), the
|
|
7
|
-
# cycle count, and the host's typing still to feed
|
|
8
|
-
# still to run
|
|
9
|
-
# written for reports and never read.
|
|
7
|
+
# cycle count, and the host's typing still to feed, on_init handlers
|
|
8
|
+
# still to run and the model plug_true_drive plugs in under host.*. The
|
|
9
|
+
# badline version that wrote it is written for reports and never read.
|
|
10
10
|
module KeyedState
|
|
11
11
|
# How many more on_init handlers the machine a snapshot was taken of had
|
|
12
12
|
# yet to run than this one has. Nil until the machine is restored.
|
|
@@ -29,6 +29,7 @@ module Badline
|
|
|
29
29
|
pending = @pending_keys
|
|
30
30
|
out.ints("host.pending_keys", pending) if pending
|
|
31
31
|
out.int("host.init_pending", booting? ? @init_handlers.length : 0)
|
|
32
|
+
out.text("host.true_drive_model", @true_drive_model)
|
|
32
33
|
end
|
|
33
34
|
|
|
34
35
|
def load_machine_fields(input)
|
|
@@ -36,6 +37,7 @@ module Badline
|
|
|
36
37
|
pending = input.ints("host.pending_keys", [])
|
|
37
38
|
@pending_keys = pending.empty? ? nil : pending.dup
|
|
38
39
|
@init_handlers_lost = [input.int("host.init_pending", 0) - @init_handlers.length, 0].max
|
|
40
|
+
@true_drive_model = input.choice("host.true_drive_model", TCBMDrive::TRUE_DRIVE_MODELS, @true_drive_model)
|
|
39
41
|
end
|
|
40
42
|
end
|
|
41
43
|
|
|
@@ -32,6 +32,7 @@ module Badline
|
|
|
32
32
|
drive.host_clock_hz = timing.clock_hz
|
|
33
33
|
@drive1551 = drive
|
|
34
34
|
@bus.plug_tia(drive.device, drive.host_tia)
|
|
35
|
+
drive.on_renumber { |old| drive1551_renumbered(old) }
|
|
35
36
|
@serial_trap&.device = serial_trap_device
|
|
36
37
|
@init_threshold = [@init_threshold, Badline::Drives::Model1551::BOOT_CYCLES].max if @cycles < @init_threshold
|
|
37
38
|
end
|
|
@@ -43,6 +44,7 @@ module Badline
|
|
|
43
44
|
return unless drive
|
|
44
45
|
|
|
45
46
|
@bus.plug_tia(drive.device, tcbm_tia(drive.device))
|
|
47
|
+
drive.on_renumber
|
|
46
48
|
@drive1551 = nil
|
|
47
49
|
@serial_trap&.device = serial_trap_device
|
|
48
50
|
end
|
|
@@ -93,6 +95,18 @@ module Badline
|
|
|
93
95
|
@drive1551.load_modules(modules, input, "BL-D#{device}")
|
|
94
96
|
end
|
|
95
97
|
|
|
98
|
+
# The 1551's DEV line moved it from device +old+ to the other: its
|
|
99
|
+
# interface's TIA moves with it, and the TCBM interface's own takes
|
|
100
|
+
# its old place.
|
|
101
|
+
def drive1551_renumbered(old)
|
|
102
|
+
drive = @drive1551
|
|
103
|
+
return unless drive
|
|
104
|
+
|
|
105
|
+
@bus.plug_tia(old, tcbm_tia(old))
|
|
106
|
+
@bus.plug_tia(drive.device, drive.host_tia)
|
|
107
|
+
@serial_trap&.device = serial_trap_device
|
|
108
|
+
end
|
|
109
|
+
|
|
96
110
|
# The TCBM interface's own TIA for +device+, or nil without one.
|
|
97
111
|
def tcbm_tia(device)
|
|
98
112
|
tias = @tias
|
data/lib/badline/plus4.rb
CHANGED
|
@@ -89,7 +89,7 @@ module Badline
|
|
|
89
89
|
ntsc = profile == Chips::TED::NTSC
|
|
90
90
|
Timing.new(clock_hz: profile.clock_hz, cycles_per_line: Chips::TED::Beam::CYCLES_PER_LINE,
|
|
91
91
|
lines_per_frame: ntsc ? 262 : 312, crop: ntsc ? [0, 248, 384, 242] : [0, 276, 384, 288],
|
|
92
|
-
pixel_width: 1)
|
|
92
|
+
pixel_width: 1, dots: 1)
|
|
93
93
|
end
|
|
94
94
|
|
|
95
95
|
# Reads and writes memory as the CPU sees it, through the bus.
|
data/lib/badline/roms/README
CHANGED
|
@@ -88,6 +88,18 @@ Downloaded from
|
|
|
88
88
|
https://www.zimmers.net/anonftp/pub/cbm/firmware/drives/new/1551/1551.318008-01.bin
|
|
89
89
|
SHA-1 fae3c788ad9a6cc2dbdfbcf6c0264b2ca921d55e.
|
|
90
90
|
|
|
91
|
+
dos2031.rom
|
|
92
|
+
-----------
|
|
93
|
+
The 2031 disk drive's DOS 2.6, 16 KB for $C000-$FFFF: 901484-03
|
|
94
|
+
($C000-$DFFF, SHA-1 54d608f7f07860f24186749f21c96724dd48bc50)
|
|
95
|
+
followed by 901484-05 ($E000-$FFFF, SHA-1
|
|
96
|
+
ec6b75ecfdd4744e5d57979ef6af990444c11ae1). Drives::Model2031 loads it.
|
|
97
|
+
|
|
98
|
+
Both halves downloaded from
|
|
99
|
+
https://www.zimmers.net/anonftp/pub/cbm/firmware/drives/old/2031/
|
|
100
|
+
and concatenated.
|
|
101
|
+
SHA-1 c53e180a96649ceb3f421739e8dc66faba7cba44.
|
|
102
|
+
|
|
91
103
|
Commodore VIC-20 ROMs
|
|
92
104
|
=====================
|
|
93
105
|
|
|
@@ -179,3 +191,160 @@ plus4/function-high.rom
|
|
|
179
191
|
The Plus/4's 3-plus-1 function ROM, high half, 317054-01
|
|
180
192
|
(3-plus-1.317054-01.bin), for $C000-$FFFF in ROM bank 1.
|
|
181
193
|
SHA-1 0ad7ac2db7da692d972e586ca0dfd747d82c7693.
|
|
194
|
+
|
|
195
|
+
Commodore PET/CBM ROMs
|
|
196
|
+
======================
|
|
197
|
+
|
|
198
|
+
Downloaded from
|
|
199
|
+
https://www.zimmers.net/anonftp/pub/cbm/firmware/computers/pet/
|
|
200
|
+
Each BASIC and KERNAL pair is one ROM set, and the editors and the
|
|
201
|
+
character sets are files of their own, so a model's stock set and the
|
|
202
|
+
upgrade ROMs Commodore sold can be picked apart. PET::ROMSets
|
|
203
|
+
(pet/rom_sets.rb) names them for --basic and --editor and says which
|
|
204
|
+
fit each model, and PET::Bus maps the ones fitted.
|
|
205
|
+
|
|
206
|
+
pet/basic1.rom
|
|
207
|
+
--------------
|
|
208
|
+
BASIC 1 for $C000-$DFFF, four 2K chips concatenated:
|
|
209
|
+
901447-09 (rom-2-c000.901447-09.bin, the revision that replaced
|
|
210
|
+
901447-01), 901447-02, 901447-03 and 901447-04 (rom-1-c800, rom-1-d000,
|
|
211
|
+
rom-1-d800).
|
|
212
|
+
SHA-1 3be9cd41b646fefa00d80f1c3433a06146e97c59.
|
|
213
|
+
|
|
214
|
+
pet/editor1.rom
|
|
215
|
+
---------------
|
|
216
|
+
The BASIC 1 screen editor, 901447-05 (rom-1-e000.901447-05.bin), for
|
|
217
|
+
$E000-$E7FF.
|
|
218
|
+
SHA-1 f02f5fb492ba93dbbd390f24c10f7a832dec432a.
|
|
219
|
+
|
|
220
|
+
pet/kernal1.rom
|
|
221
|
+
---------------
|
|
222
|
+
The BASIC 1 KERNAL for $F000-$FFFF, 901447-06 and 901447-07
|
|
223
|
+
(rom-1-f000.901447-06.bin, rom-1-f800.901447-07.bin) concatenated.
|
|
224
|
+
SHA-1 32dc08828e88c74d6433156e64d402b564556308.
|
|
225
|
+
|
|
226
|
+
pet/characters1.rom
|
|
227
|
+
-------------------
|
|
228
|
+
The 2001's character generator, 901447-08 (characters-1.901447-08.bin),
|
|
229
|
+
with upper and lower case swapped against 901447-10.
|
|
230
|
+
SHA-1 3e067cc621e4beafca2b90cb8f6dba975df2855b.
|
|
231
|
+
|
|
232
|
+
pet/basic2.rom
|
|
233
|
+
--------------
|
|
234
|
+
BASIC 2 for $C000-$DFFF, 901465-01 and 901465-02
|
|
235
|
+
(basic-2-c000.901465-01.bin, basic-2-d000.901465-02.bin) concatenated.
|
|
236
|
+
The 2K chips of the 6540 boards (rom-3-*) hold the same bytes.
|
|
237
|
+
SHA-1 9322a9f0354b9049847d98d3a045fbec860a6264.
|
|
238
|
+
|
|
239
|
+
pet/kernal2.rom
|
|
240
|
+
---------------
|
|
241
|
+
The BASIC 2 KERNAL, 901465-03 (kernal-2.901465-03.bin), for $F000-$FFFF.
|
|
242
|
+
SHA-1 38742bdf449f629bcba6276ef24d3daeb7da6e84.
|
|
243
|
+
|
|
244
|
+
pet/editor2-n.rom
|
|
245
|
+
-----------------
|
|
246
|
+
The BASIC 2 editor for the graphics keyboard, 901447-24
|
|
247
|
+
(edit-2-n.901447-24.bin), for $E000-$E7FF.
|
|
248
|
+
SHA-1 5e5502ce32f5a7e387d65efe058916282041e54b.
|
|
249
|
+
|
|
250
|
+
pet/editor2-b.rom
|
|
251
|
+
-----------------
|
|
252
|
+
The BASIC 2 editor for the business keyboard, 901474-01
|
|
253
|
+
(edit-2-b.901474-01.bin), for $E000-$E7FF.
|
|
254
|
+
SHA-1 174ace3a8c0348cd21d39cc864e2adc58b0101a9.
|
|
255
|
+
|
|
256
|
+
pet/characters2.rom
|
|
257
|
+
-------------------
|
|
258
|
+
The character generator of BASIC 2 and 4 machines, 901447-10
|
|
259
|
+
(characters-2.901447-10.bin).
|
|
260
|
+
SHA-1 0157a2d55b7ac4eaeb38475889ebeea52e2593db.
|
|
261
|
+
|
|
262
|
+
pet/basic4.rom
|
|
263
|
+
--------------
|
|
264
|
+
BASIC 4 for $B000-$DFFF, 901465-23, 901465-20 and 901465-21
|
|
265
|
+
(basic-4-b000.901465-23.bin, basic-4-c000.901465-20.bin,
|
|
266
|
+
basic-4-d000.901465-21.bin) concatenated. 901465-23 is the patched
|
|
267
|
+
$B000 chip that replaced 901465-19. The 8296's 324746-01 holds the same
|
|
268
|
+
four chips (8296/kernal-basic-324746-01.bin, SHA-1
|
|
269
|
+
e3e1431969bf317c885e47f3790e0bcbdf61fe77, $C000, $D000, $B000 and
|
|
270
|
+
$F000 in that order), so the 8296 runs this file and kernal4.rom.
|
|
271
|
+
SHA-1 d70bec479e1e3a0d0908a4897066e9959bbc11c8.
|
|
272
|
+
|
|
273
|
+
pet/kernal4.rom
|
|
274
|
+
---------------
|
|
275
|
+
The BASIC 4 KERNAL, 901465-22 (kernal-4.901465-22.bin), for
|
|
276
|
+
$F000-$FFFF.
|
|
277
|
+
SHA-1 96a0fa56e0c937da92971d9c99d504e44e898806.
|
|
278
|
+
|
|
279
|
+
pet/editor4-n.rom
|
|
280
|
+
-----------------
|
|
281
|
+
The BASIC 4 editor for the graphics keyboard without a CRTC, 901447-29
|
|
282
|
+
(edit-4-n.901447-29.bin), for $E000-$E7FF.
|
|
283
|
+
SHA-1 e88f56e5c54b0e8d8d4e8cb39a4647c803c1f51c.
|
|
284
|
+
|
|
285
|
+
pet/editor4-b.rom
|
|
286
|
+
-----------------
|
|
287
|
+
The BASIC 4 editor for the business keyboard without a CRTC, 901474-02
|
|
288
|
+
(edit-4-b.901474-02.bin), for $E000-$E7FF.
|
|
289
|
+
SHA-1 0ca5c4e8f532f914cb0bf86ea9900f20f0a655ce.
|
|
290
|
+
|
|
291
|
+
pet/editor4-40-n-50hz.rom
|
|
292
|
+
-------------------------
|
|
293
|
+
The 4032's 50 Hz editor, 40 columns on a CRTC, graphics keyboard,
|
|
294
|
+
901498-01 (edit-4-40-n-50Hz.901498-01.bin), for $E000-$E7FF.
|
|
295
|
+
SHA-1 05af284c914d53a52987b5f602466de75765f650.
|
|
296
|
+
|
|
297
|
+
pet/editor4-40-n-60hz.rom
|
|
298
|
+
-------------------------
|
|
299
|
+
The 4032's 60 Hz editor, 901499-01 (edit-4-40-n-60Hz.901499-01.bin),
|
|
300
|
+
for $E000-$E7FF.
|
|
301
|
+
SHA-1 8cbf086c1ce4dfb2a2fe24c47476dfb878493dee.
|
|
302
|
+
|
|
303
|
+
pet/editor4-80-b-50hz.rom
|
|
304
|
+
-------------------------
|
|
305
|
+
The 8032's 50 Hz editor, 80 columns on a CRTC, business keyboard,
|
|
306
|
+
901474-04, the chip dated 3681
|
|
307
|
+
(edit-4-80-b-50Hz.901474-04-3681.bin), for $E000-$E7FF.
|
|
308
|
+
SHA-1 7040b283ba39e9630e3d147f7d076b7abc39bc70.
|
|
309
|
+
|
|
310
|
+
zimmers.net has three dumps of 901474-04 that differ. This one is the
|
|
311
|
+
60 Hz 901474-03 below with the 50 Hz jiffy clock patch at $E431-$E441
|
|
312
|
+
and $E455, the CRTC's vertical registers (R4, R5 and R7) changed in both
|
|
313
|
+
of its register tables at $E72A, and the byte at $E787 changed to keep
|
|
314
|
+
the ROM's byte sum at $8A, the same as 901474-03's. The line length (R0)
|
|
315
|
+
stays the 60 Hz editor's. A second chip, dated 0384, reads the same
|
|
316
|
+
(8296/edit-50hz-324243-02b.txt). The -0283 dump changes R0 and sums to
|
|
317
|
+
$AE, and the _alt dump changes R0 and $E787.
|
|
318
|
+
|
|
319
|
+
pet/editor4-80-b-50hz-0283.rom
|
|
320
|
+
------------------------------
|
|
321
|
+
The 8032's other 50 Hz editor, 901474-04, the chip dated 0283
|
|
322
|
+
(edit-4-80-b-50Hz.901474-04-0283.bin), for $E000-$E7FF, which
|
|
323
|
+
--editor 4-80-b-50hz-0283 fits. It differs from the 3681 dump only in
|
|
324
|
+
the CRTC's register tables at $E72A and $E73C: lines of 64 cycles (R0
|
|
325
|
+
63) and frames of 313 lines, with nine scanlines a character row.
|
|
326
|
+
SHA-1 81975eab31a8f4f51ae2a20d099a567c7b3f2dd1.
|
|
327
|
+
|
|
328
|
+
pet/editor4-80-b-60hz.rom
|
|
329
|
+
-------------------------
|
|
330
|
+
The 8032's 60 Hz editor, 901474-03 (edit-4-80-b-60Hz.901474-03.bin),
|
|
331
|
+
for $E000-$E7FF.
|
|
332
|
+
SHA-1 c605fa343fd77c73cbe1e0e9567e2f014f6e7e30.
|
|
333
|
+
|
|
334
|
+
pet/editor4-80-b-50hz-8296.rom
|
|
335
|
+
------------------------------
|
|
336
|
+
The 8296's 50 Hz editor, 324243-02B, the EPROM marked "8296 UE8" in
|
|
337
|
+
Andre Fachat's working 8296 (8296/edit-50hz-324243-02b.bin), for
|
|
338
|
+
$E000-$E7FF. The 8296 parts list names it the ASCII board's. It is
|
|
339
|
+
901474-04 with the CRTC's register tables at $E72A changed to lines of
|
|
340
|
+
59 cycles and frames of 339 lines (8296/edit-50hz-324243-02b.txt).
|
|
341
|
+
SHA-1 b715db83fd26458dfd254bef5c4aae636753f7f5.
|
|
342
|
+
|
|
343
|
+
pet/characters-din.rom
|
|
344
|
+
----------------------
|
|
345
|
+
The 8296's 4K character generator for the DIN board, 324242-01
|
|
346
|
+
(8296/characters-324242-01.bin), which --characters din fits. Its
|
|
347
|
+
second half is 901447-10 byte for byte, and its first a DIN set, with
|
|
348
|
+
the German letters and the section sign in place of @ [ \ ] and in
|
|
349
|
+
some of the graphics. The CRTC's MA13, bit 5 of R12, picks the half.
|
|
350
|
+
SHA-1 9616f7f18757cccefb702a945f954b644d5b17d1.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -36,6 +36,11 @@ module Badline
|
|
|
36
36
|
C128 = "C128"
|
|
37
37
|
# xplus4 names its machine PLUS4, for the C16 too.
|
|
38
38
|
PLUS4 = "PLUS4"
|
|
39
|
+
# xpet names its machine PET, for every model.
|
|
40
|
+
PET = "PET"
|
|
41
|
+
# The file format version each machine's VICE emulator reads, where
|
|
42
|
+
# it isn't FORMAT_MAJOR.0: xpet refuses any other than 1.0.
|
|
43
|
+
FORMAT_MAJORS = { PET => 1 }.freeze
|
|
39
44
|
GZIP_MAGIC = "\x1f\x8b".b
|
|
40
45
|
|
|
41
46
|
# The VICE version block, when VICE wrote the file: four version
|
|
@@ -65,7 +70,7 @@ module Badline
|
|
|
65
70
|
def [](name) = @sections.find { |section| section.name == name }
|
|
66
71
|
|
|
67
72
|
def to_s
|
|
68
|
-
header = MAGIC + [FORMAT_MAJOR, FORMAT_MINOR].pack("CC") + padded(@machine)
|
|
73
|
+
header = MAGIC + [FORMAT_MAJORS.fetch(@machine, FORMAT_MAJOR), FORMAT_MINOR].pack("CC") + padded(@machine)
|
|
69
74
|
header += VERSION_MAGIC + @vice_version if @vice_version
|
|
70
75
|
header + @sections.map { |section| encode(section) }.join
|
|
71
76
|
end
|
|
@@ -7,7 +7,7 @@ module Badline
|
|
|
7
7
|
# its default, with keys that differ only in a unit's number, such as
|
|
8
8
|
# voice1 to voice3, on one row.
|
|
9
9
|
class Markdown
|
|
10
|
-
NAMES = { "c64" => "C64", "vic20" => "VIC-20", "c128" => "C128", "plus4" => "Plus/4" }.freeze
|
|
10
|
+
NAMES = { "c64" => "C64", "vic20" => "VIC-20", "c128" => "C128", "plus4" => "Plus/4", "pet" => "PET" }.freeze
|
|
11
11
|
TAG_TYPES = { Keyed::INT => "int", Keyed::BOOL => "bool", Keyed::BYTES => "bytes", Keyed::INTS => "ints",
|
|
12
12
|
Keyed::TEXT => "text" }.freeze
|
|
13
13
|
|
|
@@ -36,8 +36,9 @@ module Badline
|
|
|
36
36
|
|
|
37
37
|
# The machines the doc is made from: each family at power-on, the C64
|
|
38
38
|
# with each kind of expansion, cartridge and media, and a second SID,
|
|
39
|
-
#
|
|
40
|
-
# true drives, the 1541 and the 1551
|
|
39
|
+
# the 264 series' models, its TCBM interface, cartridge, tape and
|
|
40
|
+
# true drives, the 1541 and the 1551, and a CRTC PET, a 2001, an 8096,
|
|
41
|
+
# an 8296 with its user port jumpered and a PET with a disk and tapes.
|
|
41
42
|
def self.machines
|
|
42
43
|
{
|
|
43
44
|
"c64" => [C64.new, C64.new(ram_expansion: :plus256k), C64.new(reu: 512),
|
|
@@ -48,10 +49,23 @@ module Badline
|
|
|
48
49
|
"plus4" => [Plus4.new, Plus4.new(model: "c16"), Plus4.new(tcbm: true), Plus4.new(sid_card: :mos6581),
|
|
49
50
|
Plus4.new(sid_card: :mos8580, sid_card_address: 0xfe80),
|
|
50
51
|
Plus4.new(ram_expansion: :csory256),
|
|
51
|
-
plus4_with_cartridge, plus4_with_tape, plus4_with_drive, plus4_with_drive("1551")]
|
|
52
|
+
plus4_with_cartridge, plus4_with_tape, plus4_with_drive, plus4_with_drive("1551")],
|
|
53
|
+
"pet" => [PET.new, PET.new(model: "2001"), PET.new(model: "8096"),
|
|
54
|
+
PET.new(model: "8296", characters: "din", jumpers: %w[userport]), pet_with_media]
|
|
52
55
|
}
|
|
53
56
|
end
|
|
54
57
|
|
|
58
|
+
# A PET with a disk in device 8 through the traps and a tape in each
|
|
59
|
+
# datasette.
|
|
60
|
+
def self.pet_with_media
|
|
61
|
+
bytes = "C64-TAPE-RAW".bytes + [1, 3, 0, 0, 4, 0, 0, 0, 0x30, 0x30, 0x30, 0x30]
|
|
62
|
+
PET.new.tap do |machine|
|
|
63
|
+
machine.mount(Storage::D64Image.new("", read_only: true, bytes: blank(174_848)))
|
|
64
|
+
machine.cassettes.datasette1.insert(Storage::TAP.new("", bytes:))
|
|
65
|
+
machine.cassettes.datasette2.insert(Storage::TAP.new("", bytes:))
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
55
69
|
def self.blank(length) = Array.new(length, 0)
|
|
56
70
|
|
|
57
71
|
def self.with_cartridge(type)
|