badline 0.15.0 → 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.
Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +102 -0
  3. data/CLAUDE.md +15 -7
  4. data/README.md +142 -16
  5. data/doc/media.md +19 -0
  6. data/doc/pinned-behaviour.md +67 -0
  7. data/doc/snapshot-format.md +274 -31
  8. data/doc/snapshots.md +14 -0
  9. data/exe/badline-ruby +1 -1
  10. data/lib/badline/audio/machine_player.rb +2 -14
  11. data/lib/badline/c64/common.rb +1 -1
  12. data/lib/badline/c64/true_drives.rb +13 -1
  13. data/lib/badline/c64.rb +6 -0
  14. data/lib/badline/chips/crtc/keyed_state.rb +46 -0
  15. data/lib/badline/chips/crtc.rb +163 -0
  16. data/lib/badline/chips/pia/control_lines.rb +138 -0
  17. data/lib/badline/chips/pia/keyed_parts.rb +56 -0
  18. data/lib/badline/chips/pia.rb +138 -0
  19. data/lib/badline/chips/tia.rb +16 -0
  20. data/lib/badline/core.rb +3 -0
  21. data/lib/badline/drives/datasette/keyed_state.rb +8 -3
  22. data/lib/badline/drives/engine/core.rb +6 -14
  23. data/lib/badline/drives/engine/idle.rb +42 -4
  24. data/lib/badline/drives/engine/idle_cpu.rb +18 -0
  25. data/lib/badline/drives/engine/serial_connection.rb +25 -0
  26. data/lib/badline/drives/engine/sleep.rb +1 -0
  27. data/lib/badline/drives/engine.rb +1 -0
  28. data/lib/badline/drives/ieee_bus.rb +28 -0
  29. data/lib/badline/drives/model1541/byte_ready.rb +19 -3
  30. data/lib/badline/drives/model1541/mechanism.rb +10 -1
  31. data/lib/badline/drives/model1541.rb +1 -0
  32. data/lib/badline/drives/model1551/bus.rb +138 -0
  33. data/lib/badline/drives/model1551/cable.rb +107 -0
  34. data/lib/badline/drives/model1551/cpu.rb +14 -0
  35. data/lib/badline/drives/model1551/keyed_state.rb +65 -0
  36. data/lib/badline/drives/model1551/port.rb +74 -0
  37. data/lib/badline/drives/model1551/tia.rb +71 -0
  38. data/lib/badline/drives/model1551.rb +192 -0
  39. data/lib/badline/drives/model1571.rb +1 -0
  40. data/lib/badline/drives/model1581.rb +1 -0
  41. data/lib/badline/drives.rb +1 -0
  42. data/lib/badline/frontend/app.rb +1 -1
  43. data/lib/badline/frontend/boot.rb +20 -1
  44. data/lib/badline/frontend/controls.rb +23 -3
  45. data/lib/badline/frontend/gamepads.rb +10 -3
  46. data/lib/badline/frontend/keys.rb +88 -0
  47. data/lib/badline/frontend/media_slots.rb +1 -0
  48. data/lib/badline/frontend/menu/menu_dialogs.rb +15 -6
  49. data/lib/badline/frontend/menu/menu_media.rb +96 -19
  50. data/lib/badline/frontend/menu/menu_pages.rb +25 -7
  51. data/lib/badline/frontend/menu/menu_ports.rb +22 -1
  52. data/lib/badline/frontend/menu/pause_menu.rb +1 -0
  53. data/lib/badline/frontend/pet_keyboard.rb +124 -0
  54. data/lib/badline/frontend/player/player_controller.rb +11 -4
  55. data/lib/badline/frontend/screens.rb +2 -1
  56. data/lib/badline/frontend/timeline.rb +16 -9
  57. data/lib/badline/frontend.rb +1 -0
  58. data/lib/badline/kernal_trap/dos/writes.rb +3 -1
  59. data/lib/badline/kernal_trap/dos.rb +6 -1
  60. data/lib/badline/kernal_trap/frames.rb +117 -0
  61. data/lib/badline/kernal_trap/ieee.rb +148 -0
  62. data/lib/badline/kernal_trap/ieee_layout.rb +113 -0
  63. data/lib/badline/kernal_trap/keyed_state.rb +4 -4
  64. data/lib/badline/kernal_trap/routine.rb +3 -53
  65. data/lib/badline/kernal_trap/serial.rb +4 -102
  66. data/lib/badline/kernal_trap/steps.rb +64 -0
  67. data/lib/badline/kernal_trap.rb +4 -0
  68. data/lib/badline/machine/keyboard_buffer.rb +8 -0
  69. data/lib/badline/machine/settling.rb +1 -1
  70. data/lib/badline/machine.rb +37 -11
  71. data/lib/badline/media/extensions.rb +5 -2
  72. data/lib/badline/media/pet_media.rb +40 -0
  73. data/lib/badline/media/program.rb +14 -2
  74. data/lib/badline/media/true_drive.rb +7 -5
  75. data/lib/badline/media/vic20_media.rb +2 -2
  76. data/lib/badline/media.rb +36 -16
  77. data/lib/badline/options/family.rb +17 -6
  78. data/lib/badline/options/help.rb +23 -5
  79. data/lib/badline/options/option.rb +2 -1
  80. data/lib/badline/options/table.rb +28 -4
  81. data/lib/badline/options/validation.rb +117 -14
  82. data/lib/badline/options.rb +65 -21
  83. data/lib/badline/pet/bus/expansion.rb +106 -0
  84. data/lib/badline/pet/bus.rb +204 -0
  85. data/lib/badline/pet/canvas.rb +97 -0
  86. data/lib/badline/pet/cassettes.rb +63 -0
  87. data/lib/badline/pet/characters.rb +26 -0
  88. data/lib/badline/pet/cpu.rb +10 -0
  89. data/lib/badline/pet/crtc_video.rb +142 -0
  90. data/lib/badline/pet/discrete_video.rb +83 -0
  91. data/lib/badline/pet/ieee_ports.rb +66 -0
  92. data/lib/badline/pet/ieee_traps.rb +75 -0
  93. data/lib/badline/pet/keyboard_ports.rb +74 -0
  94. data/lib/badline/pet/keyed_modules.rb +85 -0
  95. data/lib/badline/pet/keyed_parts.rb +123 -0
  96. data/lib/badline/pet/keyed_state.rb +42 -0
  97. data/lib/badline/pet/model.rb +113 -0
  98. data/lib/badline/pet/rom_sets.rb +65 -0
  99. data/lib/badline/pet/sound.rb +128 -0
  100. data/lib/badline/pet/via.rb +10 -0
  101. data/lib/badline/pet/via_ports.rb +19 -0
  102. data/lib/badline/pet.rb +226 -0
  103. data/lib/badline/plus4/acia/frames.rb +55 -0
  104. data/lib/badline/plus4/acia.rb +276 -16
  105. data/lib/badline/plus4/bus.rb +181 -45
  106. data/lib/badline/plus4/keyed_modules.rb +22 -5
  107. data/lib/badline/plus4/keyed_parts.rb +33 -4
  108. data/lib/badline/plus4/keyed_state.rb +10 -5
  109. data/lib/badline/plus4/ram_expansion.rb +145 -0
  110. data/lib/badline/plus4/sid_card.rb +95 -0
  111. data/lib/badline/plus4/sound_mix.rb +51 -0
  112. data/lib/badline/plus4/tcbm_drive.rb +134 -0
  113. data/lib/badline/plus4/user_port.rb +11 -2
  114. data/lib/badline/plus4.rb +104 -22
  115. data/lib/badline/roms/README +146 -0
  116. data/lib/badline/roms/dos1551.rom +0 -0
  117. data/lib/badline/roms/pet/basic1.rom +0 -0
  118. data/lib/badline/roms/pet/basic2.rom +0 -0
  119. data/lib/badline/roms/pet/basic4.rom +0 -0
  120. data/lib/badline/roms/pet/characters1.rom +0 -0
  121. data/lib/badline/roms/pet/characters2.rom +0 -0
  122. data/lib/badline/roms/pet/editor1.rom +0 -0
  123. data/lib/badline/roms/pet/editor2-b.rom +0 -0
  124. data/lib/badline/roms/pet/editor2-n.rom +0 -0
  125. data/lib/badline/roms/pet/editor4-40-n-50hz.rom +0 -0
  126. data/lib/badline/roms/pet/editor4-40-n-60hz.rom +0 -0
  127. data/lib/badline/roms/pet/editor4-80-b-50hz-0283.rom +0 -0
  128. data/lib/badline/roms/pet/editor4-80-b-50hz.rom +0 -0
  129. data/lib/badline/roms/pet/editor4-80-b-60hz.rom +0 -0
  130. data/lib/badline/roms/pet/editor4-b.rom +0 -0
  131. data/lib/badline/roms/pet/editor4-n.rom +0 -0
  132. data/lib/badline/roms/pet/kernal1.rom +0 -0
  133. data/lib/badline/roms/pet/kernal2.rom +0 -0
  134. data/lib/badline/roms/pet/kernal4.rom +0 -0
  135. data/lib/badline/snapshot/container.rb +2 -0
  136. data/lib/badline/snapshot/field_doc/markdown.rb +1 -1
  137. data/lib/badline/snapshot/field_doc.rb +21 -6
  138. data/lib/badline/snapshot/image.rb +14 -7
  139. data/lib/badline/snapshot/pet_setup.rb +71 -0
  140. data/lib/badline/snapshot/plus4_setup.rb +52 -10
  141. data/lib/badline/snapshot/storage_setup.rb +7 -1
  142. data/lib/badline/snapshot.rb +9 -5
  143. data/lib/badline/storage/d80_image.rb +48 -0
  144. data/lib/badline/storage/d82_image.rb +21 -0
  145. data/lib/badline/storage/g64_image.rb +1 -1
  146. data/lib/badline/storage/tap.rb +16 -3
  147. data/lib/badline/storage.rb +2 -0
  148. data/lib/badline/support/pet_checkpoint.rb +38 -0
  149. data/lib/badline/timing.rb +5 -4
  150. data/lib/badline/version.rb +1 -1
  151. data/lib/badline/vic20/attachments.rb +7 -2
  152. data/lib/badline/vic20/bus/keyed_state.rb +5 -4
  153. data/lib/badline/vic20/bus.rb +5 -0
  154. data/lib/badline/vic20.rb +1 -1
  155. metadata +69 -1
data/lib/badline/plus4.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "badline/chips/ted"
4
4
  require "badline/chips/tia"
5
+ require "badline/drives/model1551"
5
6
  require "badline/plus4/model"
6
7
  require "badline/plus4/cpu"
7
8
  require "badline/plus4/cpu_port"
@@ -9,7 +10,11 @@ require "badline/plus4/keyboard_port"
9
10
  require "badline/plus4/user_port"
10
11
  require "badline/plus4/cassette_sense"
11
12
  require "badline/plus4/acia"
13
+ require "badline/plus4/sid_card"
14
+ require "badline/plus4/sound_mix"
15
+ require "badline/plus4/ram_expansion"
12
16
  require "badline/plus4/bus"
17
+ require "badline/plus4/tcbm_drive"
13
18
  require "badline/snapshot/plus4_setup"
14
19
  require "badline/plus4/keyed_parts"
15
20
  require "badline/plus4/keyed_state"
@@ -19,20 +24,31 @@ module Badline
19
24
  # The Commodore 264 series: the Plus/4, the C16 and the C116. A 7501 on
20
25
  # the TED's clock, which runs it once or twice a TED cycle (Chips::TED's
21
26
  # Beam), the TED and, on the Plus/4, a 6551 ACIA and the user port's
22
- # 6529. Only the TED pulls IRQ, and nothing pulls NMI, which the 7501
23
- # doesn't have.
27
+ # 6529. The TED and the ACIA pull IRQ, and nothing pulls NMI, which the
28
+ # 7501 doesn't have.
24
29
  #
25
30
  # The TED paints the picture a front end shows (#video, #timing). Device 8
26
31
  # serves disks through the KERNAL traps (C64::KernalTraps), or a true
27
- # 1541 or 1581 on the serial bus does (C64::TrueDrives), cartridges go
32
+ # 1541 or 1581 on the serial bus or a 1551 on TCBM does (TCBMDrive),
33
+ # cartridges go
28
34
  # in the two cartridges' slots, and tapes play on the datasette, whose read
29
35
  # line's level the KERNAL times with the TED's timers.
36
+ #
37
+ # A SID card, as third parties built for the 264s, puts a SID at
38
+ # $FD40-$FD5F, or at $FE80-$FE9F as Csory's does. The cards clock it from the TED's single clock, one SID
39
+ # cycle a TED cycle, 886,724 Hz on PAL, below the C64's 985,248 Hz, so a
40
+ # C64 tune plays about a semitone flat (plus4world forum threads 38287
41
+ # and 20130).
42
+ #
43
+ # A RAM expansion, Hannes's 256K or 1M or Csory's 256K, banks more RAM
44
+ # in through a register at $FD16 (RAMExpansion).
30
45
  class Plus4
31
46
  include IntegerHelper
32
47
  include Machine::KeyboardBuffer
33
48
  include Machine::Clocking
34
49
  include Machine::Settling
35
50
  include C64::TrueDrives
51
+ include TCBMDrive
36
52
  include C64::KernalTraps
37
53
 
38
54
  # The cycle by which the KERNAL has booted and BASIC printed READY,
@@ -46,7 +62,7 @@ module Badline
46
62
  DRIVE_BOOT_CYCLES = 1_200_000
47
63
 
48
64
  attr_reader :model, :bus, :cpu, :ted, :sound, :port, :keyboard, :keyboard_port, :joystick1, :joystick2, :acia,
49
- :user_port, :datasette, :tias, :iec_bus, :cycles, :ram_kb, :drive1541, :init_threshold
65
+ :user_port, :datasette, :tias, :iec_bus, :cycles, :ram_kb, :drive1541, :init_threshold, :sid_card
50
66
 
51
67
  def family = :plus4
52
68
 
@@ -57,8 +73,8 @@ module Badline
57
73
  def ram = @bus.ram
58
74
 
59
75
  # What a front end plays: the TED's sound, which answers #record and
60
- # #drain_samples.
61
- def sound_source = @sound
76
+ # #drain_samples, mixed with the SID card's where one is fitted.
77
+ def sound_source = @sound_mix || @sound
62
78
 
63
79
  # The chip whose #display a front end shows.
64
80
  def video = @ted
@@ -73,7 +89,7 @@ module Badline
73
89
  ntsc = profile == Chips::TED::NTSC
74
90
  Timing.new(clock_hz: profile.clock_hz, cycles_per_line: Chips::TED::Beam::CYCLES_PER_LINE,
75
91
  lines_per_frame: ntsc ? 262 : 312, crop: ntsc ? [0, 248, 384, 242] : [0, 276, 384, 288],
76
- pixel_width: 1)
92
+ pixel_width: 1, dots: 1)
77
93
  end
78
94
 
79
95
  # Reads and writes memory as the CPU sees it, through the bus.
@@ -84,11 +100,16 @@ module Badline
84
100
  # +model+ names one of Model::ALL, or c116 for the C16, and +ram+ the
85
101
  # RAM in K, one of Model::RAM_SIZES, when not the model's own. +tcbm+
86
102
  # plugs in a 1551's TCBM interface, the TIAs at $FEC0-$FEFF, with no
87
- # drive answering on the other side.
88
- def initialize(model: "plus4", ram: nil, tcbm: false, debug: false)
103
+ # drive answering on the other side. +true_drive_model+ names the drive
104
+ # plug_true_drive plugs in, "1541" or "1551". +sid_card+ fits a SID
105
+ # card with a SID of that model, :mos6581 or :mos8580, at
106
+ # +sid_card_address+, $FD40 or $FE80. +ram_expansion+
107
+ # fits a RAMExpansion of that kind, :hannes256, :hannes1m or
108
+ # :csory256, over 64K of the machine's own.
109
+ def initialize(model: "plus4", ram: nil, tcbm: false, true_drive_model: "1551", sid_card: nil,
110
+ sid_card_address: SIDCard::ADDRESSES.first, ram_expansion: nil, debug: false)
89
111
  @model = Model.named(model)
90
- @ram_kb = ram || @model.ram_kb
91
- raise ArgumentError, "no Plus/4 RAM size of #{@ram_kb}K" unless Model::RAM_SIZES.include?(@ram_kb)
112
+ @ram_kb = fitted_ram(ram, ram_expansion)
92
113
 
93
114
  @ted = Chips::TED.new(@model.ted)
94
115
  @keyboard = Input::Keyboard.new(matrix: KeyboardPort::MATRIX)
@@ -100,39 +121,45 @@ module Badline
100
121
  @datasette = Drives::Datasette.new(level: true)
101
122
  @port = CPUPort.new(serial_bus: @iec_bus, datasette: @datasette)
102
123
  plus4_parts = @model.plus4_parts
103
- @acia = plus4_parts ? ACIA.new : nil
124
+ @cycles = 0
125
+ @init_threshold = INIT_THRESHOLD
126
+ @acia_irq = false
127
+ @acia_due = ACIA::NEVER
128
+ @due = INIT_THRESHOLD
129
+ @sid_card = sid_card ? SIDCard.new(self, sid_card, sid_card_address) : nil
130
+ @acia = plus4_parts ? ACIA.new(self, @model.ted.clock_hz) : nil
104
131
  @user_port = plus4_parts ? UserPort.new(@datasette) : nil
105
132
  io = Bus::IOPage.new(keyboard_port: @keyboard_port, acia: @acia, user_port: @user_port,
106
- cassette_sense: plus4_parts ? nil : CassetteSense.new(@datasette))
107
- @bus = Bus.new(ted: @ted, port: @port, io:, model: @model, ram_kb: @ram_kb)
133
+ cassette_sense: plus4_parts ? nil : CassetteSense.new(@datasette),
134
+ sid_card: sid_card_at(0xfd40))
135
+ @bus = Bus.new(ted: @ted, port: @port, io:, model: @model, ram_kb: @ram_kb, ram_expansion:)
108
136
  @ted.connect(@bus)
137
+ @bus.plug_sid_card(sid_card_at(0xfe80))
109
138
  @tias = tcbm ? [Chips::TIA.new, Chips::TIA.new] : []
110
139
  @bus.plug_tcbm(drive8: @tias[0], drive9: @tias[1]) if tcbm
111
140
  @cpu = CPU.new(@bus, debug:)
112
- @cycles = 0
113
141
  @sound = Chips::TED::Sound.new(self, @model.ted.clock_hz)
114
142
  @ted.sound = @sound
143
+ @sound_mix = @sid_card ? SoundMix.new(@sound, @sid_card) : nil
115
144
  @init_handlers = []
116
145
  @pending_keys = nil
117
146
  @dos = nil
118
147
  @serial_trap = nil
119
148
  @save_trap = nil
120
149
  @capture_output = nil
121
- @drive1541 = nil
122
- @drive1581 = nil
123
- @init_threshold = INIT_THRESHOLD
150
+ init_drives(true_drive_model)
124
151
  end
125
152
 
126
153
  # One TED cycle: the TED moves on and decides the CPU's clock, then the
127
154
  # CPU runs its cycles in it, none while the TED holds the bus.
128
155
  def cycle!
129
- handle_init if @cycles == @init_threshold
156
+ handle_due if @cycles >= @due
130
157
  feed_keyboard if @pending_keys
131
158
 
132
159
  ted = @ted
133
160
  ted.cycle!
134
161
  @datasette.cycle!
135
- @cpu.irq = ted.irq?
162
+ @cpu.irq = ted.irq? || @acia_irq
136
163
  slots = ted.cpu_slots
137
164
  if slots.zero?
138
165
  @cpu.stall!
@@ -142,13 +169,15 @@ module Badline
142
169
  end
143
170
  @drive1541&.host_cycle!
144
171
  @drive1581&.host_cycle!
172
+ @drive1551&.host_cycle!
145
173
 
146
174
  @cycles += 1
147
175
  end
148
176
 
149
177
  # The RESET line: the CPU, the port, the 6529s, the ACIA, the bank
150
- # latch and ROM selection, and through the serial bus's RESET line, the
151
- # drives. The TED has no reset pin.
178
+ # latch and ROM selection, a RAM expansion's register, the SID card,
179
+ # and through the serial bus's RESET line, the drives. The TED has no
180
+ # reset pin.
152
181
  def reset!
153
182
  @port.reset!
154
183
  @keyboard_port.reset!
@@ -156,7 +185,9 @@ module Badline
156
185
  @dos&.reset!
157
186
  @drive1541&.reset!
158
187
  @drive1581&.reset!
188
+ @drive1551&.reset!
159
189
  @acia&.reset!
190
+ @sid_card&.reset!
160
191
  @tias.each(&:reset!)
161
192
  @bus.reset!
162
193
  @cpu.reset!
@@ -171,6 +202,13 @@ module Badline
171
202
  reset!
172
203
  end
173
204
 
205
+ # The ACIA's IRQ line, and the cycle it next has something to do at.
206
+ def acia_changed(irq, due)
207
+ @acia_irq = irq
208
+ @acia_due = due
209
+ schedule
210
+ end
211
+
174
212
  # Calls the block with the exit code a VICE testprog writes to $FDCF.
175
213
  def install_debug_register(&) = @bus.install_debug_register(&)
176
214
 
@@ -201,6 +239,18 @@ module Badline
201
239
  "#{name} #{standard}, #{@ram_kb}K RAM"
202
240
  end
203
241
 
242
+ # The RAMExpansion fitted, or nil.
243
+ def ram_expansion = @bus.ram_expansion
244
+
245
+ # The RAM expansion as the pause menu names it, such as "HANNES, 256
246
+ # KB", or nil without one.
247
+ def ram_expansion_label
248
+ expansion = @bus.ram_expansion
249
+ return if expansion.nil?
250
+
251
+ "#{RAMExpansion::NAMES.fetch(expansion.kind)}, #{expansion.size_kb} KB"
252
+ end
253
+
204
254
  # Stores a PRG's bytes from its load address on, into RAM, and returns
205
255
  # that address.
206
256
  def load_prg(data)
@@ -213,6 +263,22 @@ module Badline
213
263
 
214
264
  private
215
265
 
266
+ # The SID card if it is at +address+, or nil.
267
+ def sid_card_at(address)
268
+ card = @sid_card
269
+ card if card && card.address == address
270
+ end
271
+
272
+ # The RAM in K: +ram+, or the model's own, or 64K under a RAM
273
+ # expansion, which needs that much.
274
+ def fitted_ram(ram, ram_expansion)
275
+ ram_kb = ram || (ram_expansion ? 64 : @model.ram_kb)
276
+ raise ArgumentError, "no Plus/4 RAM size of #{ram_kb}K" unless Model::RAM_SIZES.include?(ram_kb)
277
+ raise ArgumentError, "a RAM expansion needs 64K, not #{ram_kb}K" if ram_expansion && ram_kb != 64
278
+
279
+ ram_kb
280
+ end
281
+
216
282
  # The 264 KERNAL's keyboard buffer.
217
283
  def keyboard_buffer = Machine::KeyboardBuffer::PLUS4_LAYOUT
218
284
 
@@ -232,6 +298,22 @@ module Badline
232
298
  @init_threshold = [@init_threshold, Drives::Model1581::BOOT_CYCLES].max if @cycles < @init_threshold
233
299
  end
234
300
 
301
+ # What falls due at the start of a cycle: the on_init handlers at the
302
+ # init threshold, and the ACIA's next character.
303
+ def handle_due
304
+ handle_init if @cycles == @init_threshold
305
+ acia = @acia
306
+ acia.run!(@cycles) if acia && @cycles >= @acia_due
307
+ schedule
308
+ end
309
+
310
+ # The next cycle anything falls due at. A drive that raises the init
311
+ # threshold leaves it early, and handle_due looks again then.
312
+ def schedule
313
+ init = @cycles < @init_threshold ? @init_threshold : ACIA::NEVER
314
+ @due = [@acia_due, init].min
315
+ end
316
+
235
317
  # BA stops the CPU at a read, and a write goes ahead.
236
318
  def clock_cpu(ted)
237
319
  ted.ba_low? && !@cpu.pending_write? ? @cpu.stall! : @cpu.cycle!
@@ -79,6 +79,15 @@ Downloaded from
79
79
  https://www.zimmers.net/anonftp/pub/cbm/firmware/drives/new/1581/1581-rom.318045-02.bin
80
80
  SHA-1 01228eae6f066bd9b7b2b6a7fa3f667e41dad393.
81
81
 
82
+ dos1551.rom
83
+ -----------
84
+ The 1551 disk drive's DOS 2.6, 318008-01, 16 KB for $C000-$FFFF.
85
+ Drives::Model1551 loads it.
86
+
87
+ Downloaded from
88
+ https://www.zimmers.net/anonftp/pub/cbm/firmware/drives/new/1551/1551.318008-01.bin
89
+ SHA-1 fae3c788ad9a6cc2dbdfbcf6c0264b2ca921d55e.
90
+
82
91
  Commodore VIC-20 ROMs
83
92
  =====================
84
93
 
@@ -170,3 +179,140 @@ plus4/function-high.rom
170
179
  The Plus/4's 3-plus-1 function ROM, high half, 317054-01
171
180
  (3-plus-1.317054-01.bin), for $C000-$FFFF in ROM bank 1.
172
181
  SHA-1 0ad7ac2db7da692d972e586ca0dfd747d82c7693.
182
+
183
+ Commodore PET/CBM ROMs
184
+ ======================
185
+
186
+ Downloaded from
187
+ https://www.zimmers.net/anonftp/pub/cbm/firmware/computers/pet/
188
+ Each BASIC and KERNAL pair is one ROM set, and the editors and the
189
+ character sets are files of their own, so a model's stock set and the
190
+ upgrade ROMs Commodore sold can be picked apart. PET::ROMSets
191
+ (pet/rom_sets.rb) names them for --basic and --editor and says which
192
+ fit each model, and PET::Bus maps the ones fitted.
193
+
194
+ pet/basic1.rom
195
+ --------------
196
+ BASIC 1 for $C000-$DFFF, four 2K chips concatenated:
197
+ 901447-09 (rom-2-c000.901447-09.bin, the revision that replaced
198
+ 901447-01), 901447-02, 901447-03 and 901447-04 (rom-1-c800, rom-1-d000,
199
+ rom-1-d800).
200
+ SHA-1 3be9cd41b646fefa00d80f1c3433a06146e97c59.
201
+
202
+ pet/editor1.rom
203
+ ---------------
204
+ The BASIC 1 screen editor, 901447-05 (rom-1-e000.901447-05.bin), for
205
+ $E000-$E7FF.
206
+ SHA-1 f02f5fb492ba93dbbd390f24c10f7a832dec432a.
207
+
208
+ pet/kernal1.rom
209
+ ---------------
210
+ The BASIC 1 KERNAL for $F000-$FFFF, 901447-06 and 901447-07
211
+ (rom-1-f000.901447-06.bin, rom-1-f800.901447-07.bin) concatenated.
212
+ SHA-1 32dc08828e88c74d6433156e64d402b564556308.
213
+
214
+ pet/characters1.rom
215
+ -------------------
216
+ The 2001's character generator, 901447-08 (characters-1.901447-08.bin),
217
+ with upper and lower case swapped against 901447-10.
218
+ SHA-1 3e067cc621e4beafca2b90cb8f6dba975df2855b.
219
+
220
+ pet/basic2.rom
221
+ --------------
222
+ BASIC 2 for $C000-$DFFF, 901465-01 and 901465-02
223
+ (basic-2-c000.901465-01.bin, basic-2-d000.901465-02.bin) concatenated.
224
+ The 2K chips of the 6540 boards (rom-3-*) hold the same bytes.
225
+ SHA-1 9322a9f0354b9049847d98d3a045fbec860a6264.
226
+
227
+ pet/kernal2.rom
228
+ ---------------
229
+ The BASIC 2 KERNAL, 901465-03 (kernal-2.901465-03.bin), for $F000-$FFFF.
230
+ SHA-1 38742bdf449f629bcba6276ef24d3daeb7da6e84.
231
+
232
+ pet/editor2-n.rom
233
+ -----------------
234
+ The BASIC 2 editor for the graphics keyboard, 901447-24
235
+ (edit-2-n.901447-24.bin), for $E000-$E7FF.
236
+ SHA-1 5e5502ce32f5a7e387d65efe058916282041e54b.
237
+
238
+ pet/editor2-b.rom
239
+ -----------------
240
+ The BASIC 2 editor for the business keyboard, 901474-01
241
+ (edit-2-b.901474-01.bin), for $E000-$E7FF.
242
+ SHA-1 174ace3a8c0348cd21d39cc864e2adc58b0101a9.
243
+
244
+ pet/characters2.rom
245
+ -------------------
246
+ The character generator of BASIC 2 and 4 machines, 901447-10
247
+ (characters-2.901447-10.bin).
248
+ SHA-1 0157a2d55b7ac4eaeb38475889ebeea52e2593db.
249
+
250
+ pet/basic4.rom
251
+ --------------
252
+ BASIC 4 for $B000-$DFFF, 901465-23, 901465-20 and 901465-21
253
+ (basic-4-b000.901465-23.bin, basic-4-c000.901465-20.bin,
254
+ basic-4-d000.901465-21.bin) concatenated. 901465-23 is the patched
255
+ $B000 chip that replaced 901465-19. The 8296's 324746-01 holds the same
256
+ four chips.
257
+ SHA-1 d70bec479e1e3a0d0908a4897066e9959bbc11c8.
258
+
259
+ pet/kernal4.rom
260
+ ---------------
261
+ The BASIC 4 KERNAL, 901465-22 (kernal-4.901465-22.bin), for
262
+ $F000-$FFFF.
263
+ SHA-1 96a0fa56e0c937da92971d9c99d504e44e898806.
264
+
265
+ pet/editor4-n.rom
266
+ -----------------
267
+ The BASIC 4 editor for the graphics keyboard without a CRTC, 901447-29
268
+ (edit-4-n.901447-29.bin), for $E000-$E7FF.
269
+ SHA-1 e88f56e5c54b0e8d8d4e8cb39a4647c803c1f51c.
270
+
271
+ pet/editor4-b.rom
272
+ -----------------
273
+ The BASIC 4 editor for the business keyboard without a CRTC, 901474-02
274
+ (edit-4-b.901474-02.bin), for $E000-$E7FF.
275
+ SHA-1 0ca5c4e8f532f914cb0bf86ea9900f20f0a655ce.
276
+
277
+ pet/editor4-40-n-50hz.rom
278
+ -------------------------
279
+ The 4032's 50 Hz editor, 40 columns on a CRTC, graphics keyboard,
280
+ 901498-01 (edit-4-40-n-50Hz.901498-01.bin), for $E000-$E7FF.
281
+ SHA-1 05af284c914d53a52987b5f602466de75765f650.
282
+
283
+ pet/editor4-40-n-60hz.rom
284
+ -------------------------
285
+ The 4032's 60 Hz editor, 901499-01 (edit-4-40-n-60Hz.901499-01.bin),
286
+ for $E000-$E7FF.
287
+ SHA-1 8cbf086c1ce4dfb2a2fe24c47476dfb878493dee.
288
+
289
+ pet/editor4-80-b-50hz.rom
290
+ -------------------------
291
+ The 8032's 50 Hz editor, 80 columns on a CRTC, business keyboard,
292
+ 901474-04, the chip dated 3681
293
+ (edit-4-80-b-50Hz.901474-04-3681.bin), for $E000-$E7FF.
294
+ SHA-1 7040b283ba39e9630e3d147f7d076b7abc39bc70.
295
+
296
+ zimmers.net has three dumps of 901474-04 that differ. This one is the
297
+ 60 Hz 901474-03 below with the 50 Hz jiffy clock patch at $E431-$E441
298
+ and $E455, the CRTC's vertical registers (R4, R5 and R7) changed in both
299
+ of its register tables at $E72A, and the byte at $E787 changed to keep
300
+ the ROM's byte sum at $8A, the same as 901474-03's. The line length (R0)
301
+ stays the 60 Hz editor's. A second chip, dated 0384, reads the same
302
+ (8296/edit-50hz-324243-02b.txt). The -0283 dump changes R0 and sums to
303
+ $AE, and the _alt dump changes R0 and $E787.
304
+
305
+ pet/editor4-80-b-50hz-0283.rom
306
+ ------------------------------
307
+ The 8032's other 50 Hz editor, 901474-04, the chip dated 0283
308
+ (edit-4-80-b-50Hz.901474-04-0283.bin), for $E000-$E7FF, which
309
+ --editor 4-80-b-50hz-0283 fits. It differs from the 3681 dump only in
310
+ the CRTC's register tables at $E72A and $E73C: lines of 64 cycles (R0
311
+ 63) and frames of 313 lines, with nine scanlines a character row.
312
+ SHA-1 81975eab31a8f4f51ae2a20d099a567c7b3f2dd1.
313
+
314
+ pet/editor4-80-b-60hz.rom
315
+ -------------------------
316
+ The 8032's 60 Hz editor, 901474-03 (edit-4-80-b-60Hz.901474-03.bin),
317
+ for $E000-$E7FF.
318
+ SHA-1 c605fa343fd77c73cbe1e0e9567e2f014f6e7e30.
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,8 @@ 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"
39
41
  GZIP_MAGIC = "\x1f\x8b".b
40
42
 
41
43
  # The VICE version block, when VICE wrote the file: four version
@@ -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
- # and the 264 series' models, its TCBM interface, cartridge, tape and
40
- # true drive.
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
+ # 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),
@@ -45,11 +46,25 @@ module Badline
45
46
  with_drive(:d81), with_extra_sids],
46
47
  "vic20" => [Vic20.new, with_rom],
47
48
  "c128" => [C128.new(mode: :c128), with_drive(:d71)],
48
- "plus4" => [Plus4.new, Plus4.new(model: "c16"), Plus4.new(tcbm: true), plus4_with_cartridge,
49
- plus4_with_tape, plus4_with_drive]
49
+ "plus4" => [Plus4.new, Plus4.new(model: "c16"), Plus4.new(tcbm: true), Plus4.new(sid_card: :mos6581),
50
+ Plus4.new(sid_card: :mos8580, sid_card_address: 0xfe80),
51
+ Plus4.new(ram_expansion: :csory256),
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"), pet_with_media]
50
54
  }
51
55
  end
52
56
 
57
+ # A PET with a disk in device 8 through the traps and a tape in each
58
+ # datasette.
59
+ def self.pet_with_media
60
+ bytes = "C64-TAPE-RAW".bytes + [1, 3, 0, 0, 4, 0, 0, 0, 0x30, 0x30, 0x30, 0x30]
61
+ PET.new.tap do |machine|
62
+ machine.mount(Storage::D64Image.new("", read_only: true, bytes: blank(174_848)))
63
+ machine.cassettes.datasette1.insert(Storage::TAP.new("", bytes:))
64
+ machine.cassettes.datasette2.insert(Storage::TAP.new("", bytes:))
65
+ end
66
+ end
67
+
53
68
  def self.blank(length) = Array.new(length, 0)
54
69
 
55
70
  def self.with_cartridge(type)
@@ -110,8 +125,8 @@ module Badline
110
125
  Plus4.new(model: "c16").tap { |machine| machine.datasette.insert(Storage::TAP.new("", bytes:)) }
111
126
  end
112
127
 
113
- def self.plus4_with_drive
114
- Plus4.new.tap do |machine|
128
+ def self.plus4_with_drive(model = "1541")
129
+ Plus4.new(true_drive_model: model).tap do |machine|
115
130
  image = Storage::D64Image.new("", bytes: blank(174_848))
116
131
  machine.plug_true_drive.insert(Drives::Model1541::Disk.decode(image))
117
132
  end
@@ -34,7 +34,7 @@ module Badline
34
34
  # of a machine in memory (.of).
35
35
  class Image
36
36
  MACHINE = "BL-MACHINE"
37
- FAMILIES = { "c64" => "C64", "vic20" => "VIC-20", "c128" => "C128", "plus4" => "Plus/4" }.freeze
37
+ FAMILIES = { "c64" => "C64", "vic20" => "VIC-20", "c128" => "C128", "plus4" => "Plus/4", "pet" => "PET" }.freeze
38
38
 
39
39
  attr_reader :container
40
40
 
@@ -54,10 +54,11 @@ module Badline
54
54
  end
55
55
 
56
56
  # The snapshot with VICE's modules ahead of the BL-* ones for a C64,
57
- # so x64sc opens it too. Raises FormatError for a Plus/4, whose
58
- # snapshots badline doesn't write for xplus4.
57
+ # so x64sc opens it too. Raises FormatError for a Plus/4 or a PET,
58
+ # whose snapshots badline doesn't write for xplus4 or xpet.
59
59
  def self.exported(computer)
60
60
  raise FormatError, "badline doesn't export a Plus/4's snapshot for VICE" if computer.family == :plus4
61
+ raise FormatError, "badline doesn't export a PET's snapshot for VICE" if computer.family == :pet
61
62
 
62
63
  computer.settle_for_snapshot!
63
64
  sections = computer.save_modules
@@ -71,6 +72,7 @@ module Badline
71
72
  when :vic20 then Container::VIC20
72
73
  when :c128 then Container::C128
73
74
  when :plus4 then Container::PLUS4
75
+ when :pet then Container::PET
74
76
  else Container::MACHINE
75
77
  end
76
78
  end
@@ -82,6 +84,7 @@ module Badline
82
84
  when "vic20" then Vic20Setup.read_fields(machine)
83
85
  when "c128" then C128Setup.read_fields(machine)
84
86
  when "plus4" then Plus4Setup.read_fields(machine)
87
+ when "pet" then PETSetup.read_fields(machine)
85
88
  else C64Setup.read_fields(machine)
86
89
  end
87
90
  end
@@ -97,15 +100,16 @@ module Badline
97
100
 
98
101
  # A new machine, built as the snapshot's was and restored from it. A
99
102
  # badline snapshot restores from its BL-* modules alone, and a VICE
100
- # one through the modules badline reads. xvic's, x128's and xplus4's own
101
- # modules aren't read. Yields a line for each thing left out, or
102
- # warns it without a block. `detached` restores it without the host's
103
- # files (Keyed::Modules).
103
+ # one through the modules badline reads. xvic's, x128's, xplus4's and
104
+ # xpet's own modules aren't read. Yields a line for each thing left
105
+ # out, or warns it without a block. `detached` restores it without
106
+ # the host's files (Keyed::Modules).
104
107
  def load(detached: false, &)
105
108
  refuse_old_layout
106
109
  raise FormatError, "badline reads only its own VIC-20 snapshots, not xvic's" if vic20? && !badline?
107
110
  raise FormatError, "badline reads only its own C128 snapshots, not x128's" if c128? && !badline?
108
111
  raise FormatError, "badline reads only its own Plus/4 snapshots, not xplus4's" if plus4? && !badline?
112
+ raise FormatError, "badline reads only its own PET snapshots, not xpet's" if pet? && !badline?
109
113
  return load_vice(&) unless badline?
110
114
 
111
115
  modules = Keyed::Modules.new(sections, detached:)
@@ -123,6 +127,9 @@ module Badline
123
127
  # Whether the machine is of the 264 series, as the container names it.
124
128
  def plus4? = @container.machine == Container::PLUS4
125
129
 
130
+ # Whether the machine is a PET, as the container names it.
131
+ def pet? = @container.machine == Container::PET
132
+
126
133
  # Restores `computer` from the snapshot, and returns the Report. The
127
134
  # snapshot goes into a new machine first, so one that fails, or is of
128
135
  # a machine built another way, leaves `computer` as it was.