badline 0.17.0 → 0.18.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 (166) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +153 -0
  3. data/CLAUDE.md +11 -7
  4. data/CONTRIBUTING.md +7 -1
  5. data/README.md +169 -20
  6. data/doc/pinned-behaviour.md +128 -0
  7. data/doc/snapshot-format.md +253 -18
  8. data/doc/snapshots.md +57 -23
  9. data/exe/badline-ruby +5 -0
  10. data/lib/badline/audio/terminal.rb +34 -2
  11. data/lib/badline/c128/keyed_state.rb +2 -0
  12. data/lib/badline/c128.rb +1 -0
  13. data/lib/badline/c64/keyed_state.rb +2 -0
  14. data/lib/badline/c64.rb +1 -0
  15. data/lib/badline/cbm2/keyed_state.rb +4 -0
  16. data/lib/badline/cbm2/p500.rb +5 -3
  17. data/lib/badline/cbm2.rb +6 -3
  18. data/lib/badline/chips/cia/timer.rb +2 -2
  19. data/lib/badline/chips/cpu/instruction_set.rb +1 -1
  20. data/lib/badline/chips/m6809/arithmetic.rb +140 -0
  21. data/lib/badline/chips/m6809/bus_steps.rb +223 -0
  22. data/lib/badline/chips/m6809/core.rb +149 -0
  23. data/lib/badline/chips/m6809/indexed.rb +82 -0
  24. data/lib/badline/chips/m6809/interrupts.rb +159 -0
  25. data/lib/badline/chips/m6809/keyed_state.rb +147 -0
  26. data/lib/badline/chips/m6809/opcodes.rb +159 -0
  27. data/lib/badline/chips/m6809/operations.rb +258 -0
  28. data/lib/badline/chips/m6809/plans.rb +143 -0
  29. data/lib/badline/chips/m6809/registers.rb +82 -0
  30. data/lib/badline/chips/m6809/stack.rb +140 -0
  31. data/lib/badline/chips/m6809.rb +13 -0
  32. data/lib/badline/chips/riot/timer.rb +14 -3
  33. data/lib/badline/chips/rriot.rb +4 -2
  34. data/lib/badline/chips/sid/filter.rb +4 -4
  35. data/lib/badline/chips/sid/waveform.rb +6 -6
  36. data/lib/badline/chips/vic_i/keyed_parts.rb +7 -2
  37. data/lib/badline/chips/vic_i.rb +84 -21
  38. data/lib/badline/data_path.rb +3 -3
  39. data/lib/badline/drives/ieee_models.rb +54 -0
  40. data/lib/badline/drives/model1001.rb +37 -0
  41. data/lib/badline/drives/model2031.rb +6 -0
  42. data/lib/badline/drives/model4040/disk.rb +62 -0
  43. data/lib/badline/drives/model4040/ip_bus.rb +46 -0
  44. data/lib/badline/drives/model4040/keyed_state.rb +57 -0
  45. data/lib/badline/drives/model4040/mechanism.rb +192 -0
  46. data/lib/badline/drives/model4040/parts.rb +20 -0
  47. data/lib/badline/drives/model4040.rb +179 -0
  48. data/lib/badline/drives/model8050/board.rb +77 -0
  49. data/lib/badline/drives/model8050/dos_board.rb +91 -0
  50. data/lib/badline/drives/model8050/idle.rb +11 -7
  51. data/lib/badline/drives/model8050/keyed_state.rb +5 -2
  52. data/lib/badline/drives/model8050.rb +18 -130
  53. data/lib/badline/drives/model9060/idle.rb +149 -0
  54. data/lib/badline/drives/model9060/keyed_state.rb +123 -0
  55. data/lib/badline/drives/model9060/parts.rb +98 -0
  56. data/lib/badline/drives/model9060/sasi_bus.rb +88 -0
  57. data/lib/badline/drives/model9060/sasi_commands.rb +168 -0
  58. data/lib/badline/drives/model9060/sasi_target.rb +161 -0
  59. data/lib/badline/drives/model9060.rb +195 -0
  60. data/lib/badline/frontend/app.rb +8 -0
  61. data/lib/badline/frontend/boot.rb +3 -2
  62. data/lib/badline/frontend/controls.rb +62 -6
  63. data/lib/badline/frontend/keys.rb +36 -0
  64. data/lib/badline/frontend/kim1_panel.rb +208 -0
  65. data/lib/badline/frontend/media_slots.rb +8 -1
  66. data/lib/badline/frontend/menu/drive_types.rb +56 -0
  67. data/lib/badline/frontend/menu/menu_dialogs.rb +61 -14
  68. data/lib/badline/frontend/menu/menu_media.rb +42 -12
  69. data/lib/badline/frontend/menu/menu_pages.rb +97 -2
  70. data/lib/badline/frontend/menu/menu_ports.rb +38 -1
  71. data/lib/badline/frontend/menu/pause_menu.rb +5 -1
  72. data/lib/badline/frontend/pet_keyboard.rb +23 -1
  73. data/lib/badline/frontend/screen.rb +1 -1
  74. data/lib/badline/frontend/screens.rb +40 -2
  75. data/lib/badline/frontend/teletype_pane.rb +152 -0
  76. data/lib/badline/frontend/timeline.rb +31 -2
  77. data/lib/badline/frontend.rb +3 -0
  78. data/lib/badline/kim1/bus.rb +117 -0
  79. data/lib/badline/kim1/cpu.rb +25 -0
  80. data/lib/badline/kim1/host_terminal.rb +74 -0
  81. data/lib/badline/kim1/key_entry.rb +74 -0
  82. data/lib/badline/kim1/keyed_modules.rb +53 -0
  83. data/lib/badline/kim1/keyed_state.rb +133 -0
  84. data/lib/badline/kim1/panel.rb +176 -0
  85. data/lib/badline/kim1/rriots.rb +28 -0
  86. data/lib/badline/kim1/sound.rb +29 -0
  87. data/lib/badline/kim1/tape.rb +116 -0
  88. data/lib/badline/kim1/teletype.rb +193 -0
  89. data/lib/badline/kim1.rb +190 -0
  90. data/lib/badline/machine/ieee_drives.rb +94 -117
  91. data/lib/badline/machine/keyboard_buffer.rb +20 -3
  92. data/lib/badline/machine/line_sound.rb +122 -0
  93. data/lib/badline/machine.rb +46 -15
  94. data/lib/badline/media/extensions.rb +8 -4
  95. data/lib/badline/media/kim1_media.rb +150 -0
  96. data/lib/badline/media/pet_media.rb +3 -1
  97. data/lib/badline/media/true_drive.rb +42 -45
  98. data/lib/badline/media.rb +12 -6
  99. data/lib/badline/options/family.rb +98 -8
  100. data/lib/badline/options/help.rb +44 -12
  101. data/lib/badline/options/table.rb +43 -11
  102. data/lib/badline/options/validation.rb +44 -8
  103. data/lib/badline/options.rb +27 -8
  104. data/lib/badline/pet/bus.rb +16 -2
  105. data/lib/badline/pet/keyboard_ports.rb +9 -2
  106. data/lib/badline/pet/keyed_state.rb +4 -0
  107. data/lib/badline/pet/model.rb +11 -2
  108. data/lib/badline/pet/rom_sets.rb +1 -0
  109. data/lib/badline/pet/sound.rb +5 -105
  110. data/lib/badline/pet/superpet/acia.rb +12 -0
  111. data/lib/badline/pet/superpet/board.rb +221 -0
  112. data/lib/badline/pet/superpet/dongle.rb +81 -0
  113. data/lib/badline/pet/superpet/keyed_modules.rb +63 -0
  114. data/lib/badline/pet/superpet/keyed_parts.rb +76 -0
  115. data/lib/badline/pet/superpet/m6809.rb +32 -0
  116. data/lib/badline/pet/superpet/waterloo_traps.rb +199 -0
  117. data/lib/badline/pet/superpet.rb +216 -0
  118. data/lib/badline/pet.rb +19 -3
  119. data/lib/badline/plus4/keyed_state.rb +2 -0
  120. data/lib/badline/plus4.rb +1 -0
  121. data/lib/badline/roms/1001/fdc-251257-02a.rom +0 -0
  122. data/lib/badline/roms/4040/dos-1.2.rom +0 -0
  123. data/lib/badline/roms/4040/dos-2.1-rev.rom +0 -0
  124. data/lib/badline/roms/4040/dos-2.1.rom +0 -0
  125. data/lib/badline/roms/4040/fdc-901466-02.rom +0 -0
  126. data/lib/badline/roms/4040/fdc-901466-04.rom +0 -0
  127. data/lib/badline/roms/9060/dos-3.0.rom +0 -0
  128. data/lib/badline/roms/9060/sasi-300515-revb.rom +0 -0
  129. data/lib/badline/roms/README +166 -0
  130. data/lib/badline/roms/kim1/6530-002.rom +0 -0
  131. data/lib/badline/roms/kim1/6530-003.rom +0 -0
  132. data/lib/badline/roms/pet/characters-superpet.rom +0 -0
  133. data/lib/badline/roms/pet/superpet-a000.rom +0 -0
  134. data/lib/badline/roms/pet/superpet-c000.rom +0 -0
  135. data/lib/badline/roms/pet/superpet-e000-50hz.rom +0 -0
  136. data/lib/badline/roms/pet/superpet-e000.rom +0 -0
  137. data/lib/badline/snapshot/container.rb +2 -0
  138. data/lib/badline/snapshot/field_doc/markdown.rb +1 -1
  139. data/lib/badline/snapshot/field_doc.rb +27 -6
  140. data/lib/badline/snapshot/image.rb +4 -1
  141. data/lib/badline/snapshot/kim1_setup.rb +28 -0
  142. data/lib/badline/snapshot/pet_setup.rb +27 -11
  143. data/lib/badline/snapshot/storage_setup.rb +4 -1
  144. data/lib/badline/snapshot/vic20_setup.rb +11 -7
  145. data/lib/badline/snapshot/vice/pet.rb +13 -7
  146. data/lib/badline/snapshot/vice/pet_cpu.rb +39 -5
  147. data/lib/badline/snapshot/vice/pet_crtc.rb +15 -2
  148. data/lib/badline/snapshot/vice/pet_drive8050.rb +188 -68
  149. data/lib/badline/snapshot/vice/pet_mem.rb +49 -5
  150. data/lib/badline/snapshot/vice/pet_restore.rb +40 -11
  151. data/lib/badline/snapshot.rb +4 -0
  152. data/lib/badline/status.rb +30 -30
  153. data/lib/badline/storage/d67_image.rb +55 -0
  154. data/lib/badline/storage/d90_image.rb +180 -0
  155. data/lib/badline/storage/disk_image/writing.rb +2 -2
  156. data/lib/badline/storage/kim_tape.rb +254 -0
  157. data/lib/badline/storage/papertape.rb +90 -0
  158. data/lib/badline/storage.rb +4 -0
  159. data/lib/badline/support/kim1_checkpoint.rb +41 -0
  160. data/lib/badline/support/superpet_checkpoint.rb +35 -0
  161. data/lib/badline/version.rb +1 -1
  162. data/lib/badline/vic20/keyed_modules.rb +6 -3
  163. data/lib/badline/vic20/keyed_state.rb +6 -4
  164. data/lib/badline/vic20.rb +26 -12
  165. data/lib/badline.rb +1 -0
  166. metadata +77 -1
@@ -0,0 +1,216 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/chips/acia"
4
+ require "badline/chips/m6809"
5
+ require "badline/pet/superpet/dongle"
6
+ require "badline/pet/superpet/acia"
7
+ require "badline/pet/superpet/board"
8
+ require "badline/pet/superpet/m6809"
9
+ require "badline/pet/superpet/waterloo_traps"
10
+ require "badline/pet/superpet/keyed_parts"
11
+ require "badline/pet/superpet/keyed_modules"
12
+
13
+ module Badline
14
+ class PET
15
+ # The SuperPET, the SP9000 or MMF 9000: an 8032 with the University of
16
+ # Waterloo's board in its CPU socket, with 64K of bank RAM, a 6551
17
+ # ACIA, the 6702 and a 6809E (Board). The board's ACIA pulls the PET's
18
+ # IRQ line with the PIAs and the VIA. Its character ROM, 901640-01,
19
+ # holds the 8032's in its first half and an ASCII and an APL set in
20
+ # its second, which the CRTC's MA13 picks.
21
+ #
22
+ # Both CPUs sit on the same bus at the same 1 MHz, and one runs at a
23
+ # time: SW2, the CPU switch, picks it, or with SW2 at PROG bit 0 of the
24
+ # system latch. The one that takes the bus over starts from its RESET
25
+ # (Fachat: "The 6502 does a RESET after being switched on"; on the
26
+ # 324037 schematic one-shots gate the 6809's RES), and the other stops
27
+ # where it is. The PET's IRQ line, the ACIA's with it, reaches both.
28
+ #
29
+ # In 6809 mode device 8 answers through traps on the Waterloo ROM's
30
+ # IEEE-488 routines (WaterlooTraps) as well as the KERNAL's, from the
31
+ # same disk, or a true drive on the bus answers. type_text types
32
+ # through the Waterloo ROM's key buffer, in ASCII, once its menu is up.
33
+ class SuperPET < PET
34
+ # The Waterloo ROM's key buffer: its read and write pointers, and the
35
+ # ring of bytes they run round.
36
+ KEYS_READ = 0x012c
37
+ KEYS_WRITE = 0x012e
38
+ KEYS_FIRST = 0x0130
39
+ KEYS_END = 0x0158
40
+
41
+ # The cycle by which the 6809 has put up the Waterloo menu, with a
42
+ # margin.
43
+ WATERLOO_BOOT = 600_000
44
+
45
+ attr_reader :board, :acia, :dongle, :m6809
46
+
47
+ # The traps on the Waterloo ROM's IEEE-488 routines, while a disk is
48
+ # on device 8 (WaterlooTraps).
49
+ attr_reader :waterloo_traps
50
+
51
+ # +cpu+ is SW2's position and +bank_ram+ SW1's, as Board names them.
52
+ # The other arguments are the PET's for an 8032, its true drive's too.
53
+ def initialize(refresh_hz: 50, debug: false, basic: nil, editor: nil, cpu: "6502", bank_ram: "rw",
54
+ true_drive_model: Drives::IEEEModels::DEFAULT)
55
+ raise ArgumentError, "the CPU switch has no position #{cpu}" unless Board::CPU_SWITCH.include?(cpu)
56
+
57
+ super(model: "superpet", refresh_hz:, debug:, basic:, editor:, true_drive_model:)
58
+ @acia_irq = false
59
+ @acia_due = Chips::ACIA::NEVER
60
+ @acia = ACIA.new(self, 1_000_000)
61
+ @dongle = Dongle.new(self)
62
+ @board = Board.new(@bus, dongle: @dongle, acia: @acia, keyboard_ports: @keyboard_ports, cpu_switch: cpu,
63
+ ram_switch: bank_ram, refresh_hz: @refresh_hz)
64
+ @m6809 = M6809.new(@bus)
65
+ @m6809_running = @board.m6809?
66
+ @waterloo_traps = nil
67
+ @board.on_select { cpu_selected }
68
+ @bus.fit_board(@board)
69
+ @init_threshold = WATERLOO_BOOT if @m6809_running
70
+ end
71
+
72
+ # Whether an autostart finds BASIC: not while the 6809 runs.
73
+ def boots_basic? = !@m6809_running
74
+
75
+ # Device 8 through the traps, for the Waterloo ROM's routines too.
76
+ def mount(storage)
77
+ trap = super
78
+ @waterloo_traps ||= WaterlooTraps.new(cpu: @m6809, bus: @bus, dos: @dos).install
79
+ @waterloo_traps.device = trap_device
80
+ trap
81
+ end
82
+
83
+ def unmount
84
+ super
85
+ @waterloo_traps&.uninstall
86
+ @waterloo_traps = nil
87
+ end
88
+
89
+ def attach_ieee_drive(drive)
90
+ super
91
+ @waterloo_traps&.device = trap_device
92
+ end
93
+
94
+ def detach_ieee_drive
95
+ super
96
+ @waterloo_traps&.device = trap_device
97
+ end
98
+
99
+ # Types into the Waterloo ROM's key buffer, in ASCII, while the 6809
100
+ # runs, and into the editor's otherwise.
101
+ def type_text(text)
102
+ return super unless @m6809_running
103
+
104
+ type_on_init(text.bytes)
105
+ end
106
+
107
+ # Whether the 6809 has the bus, rather than the 6502.
108
+ def m6809_running? = @m6809_running
109
+
110
+ def superpet? = true
111
+
112
+ # Moves the CPU switch to +position+, one of Board::CPU_SWITCH, and
113
+ # resets the machine, so the CPU the switch picks starts from its
114
+ # RESET.
115
+ def switch_cpu(position)
116
+ @board.cpu_switch = position
117
+ reset!
118
+ end
119
+
120
+ # Moves the bank RAM switch to +position+, one of Board::RAM_SWITCH.
121
+ def switch_bank_ram(position)
122
+ @board.ram_switch = position
123
+ end
124
+
125
+ # Whether the picture shows the character ROM's APL set: its second
126
+ # half, which the CRTC's MA13 picks, with VIA CA2 high.
127
+ def apl_characters? = @crtc.registers[12].anybits?(0x20) && @via.ca2_output
128
+
129
+ # Drive 1 while the 6809 runs, where the Waterloo menu's "disk/1."
130
+ # looks, and drive 0 in 6502 mode.
131
+ def disk_drive_number = @m6809_running ? 1 : 0
132
+
133
+ # The 32K below $8000 and the 64K board.
134
+ def model_label = "SUPERPET, 96K RAM, #{@refresh_hz} HZ"
135
+
136
+ # The PET's cycle, with the ACIA run when it falls due and its IRQ
137
+ # on the CPU's.
138
+ def cycle!
139
+ handle_init if @cycles == @init_threshold
140
+ feed_keyboard if @pending_keys
141
+
142
+ @crtc.cycle!
143
+ drive_retrace(!@crtc.vsync?)
144
+ @pia1.cycle!
145
+ @pia2.cycle!
146
+ @via.cycle!
147
+ @sound.cycle! if @sound.recording?
148
+ @cassettes.cycle! if @tapes_running
149
+ @acia.run!(@cycles) if @cycles >= @acia_due
150
+ irq = @pia1.irq? || @pia2.irq? || @via.irq? || @acia_irq
151
+ if @m6809_running
152
+ @m6809.irq = irq
153
+ @m6809.cycle!
154
+ else
155
+ @cpu.irq = irq
156
+ @cpu.cycle!
157
+ end
158
+ clock_ieee_drives
159
+
160
+ @cycles += 1
161
+ end
162
+
163
+ # Whether the ACIA pulls the IRQ line.
164
+ def acia_irq? = @acia_irq
165
+
166
+ # The ACIA's IRQ line, and the cycle it next has something to do at.
167
+ def acia_changed(irq, due)
168
+ @acia_irq = irq
169
+ @acia_due = due
170
+ end
171
+
172
+ # The RES line reaches the board's latches, the 6702, the ACIA and
173
+ # both CPUs too.
174
+ def reset!
175
+ super
176
+ @acia.reset!
177
+ @m6809.reset!
178
+ @board.reset!
179
+ end
180
+
181
+ def power_cycle!
182
+ @board.power_on!
183
+ super
184
+ end
185
+
186
+ private
187
+
188
+ # The Waterloo ROM's ring takes keys until its write pointer would
189
+ # meet its read pointer.
190
+ def feed_keyboard
191
+ return super unless @m6809_running
192
+
193
+ read = word_at(KEYS_READ)
194
+ write = word_at(KEYS_WRITE)
195
+ until @pending_keys.empty?
196
+ following = write + 1 == KEYS_END ? KEYS_FIRST : write + 1
197
+ break if following == read
198
+
199
+ @bus.poke(write, @pending_keys.shift)
200
+ write = following
201
+ end
202
+ @bus.poke(KEYS_WRITE, write >> 8)
203
+ @bus.poke(KEYS_WRITE + 1, write & 0xff)
204
+ @pending_keys = nil if @pending_keys.empty?
205
+ end
206
+
207
+ def word_at(addr) = (@bus.peek(addr) << 8) | @bus.peek(addr + 1)
208
+
209
+ # The CPU the board picks takes the bus over from its RESET.
210
+ def cpu_selected
211
+ @m6809_running = @board.m6809?
212
+ @m6809_running ? @m6809.reset! : @cpu.reset!
213
+ end
214
+ end
215
+ end
216
+ end
data/lib/badline/pet.rb CHANGED
@@ -83,10 +83,13 @@ module Badline
83
83
  # model runs its 50 Hz editor, or its 60 Hz one for +refresh_hz+ 60.
84
84
  # +basic+, +editor+ and +characters+ name ROMs the board takes in place
85
85
  # of its own (Model.upgraded, Model.fitted), and +jumpers+ the 8296's
86
- # board jumpers (ROMSets::JUMPERS).
86
+ # board jumpers (ROMSets::JUMPERS). +true_drive_model+ names the drive
87
+ # plug_true_drive plugs in (Drives::IEEEModels).
87
88
  def initialize(model: Model::DEFAULT, ram_kb: nil, refresh_hz: 50, debug: false, basic: nil, editor: nil,
88
- characters: nil, jumpers: [])
89
+ characters: nil, jumpers: [], true_drive_model: Drives::IEEEModels::DEFAULT)
89
90
  @model = Model.fitted(Model.upgraded(Model.named(model), basic, editor), characters)
91
+ raise ArgumentError, "the SuperPET is built as PET::SuperPET" if @model.superpet? && !superpet?
92
+
90
93
  ram_kb ||= @model.ram_kb
91
94
  raise ArgumentError, "the #{@model.name} has no #{ram_kb}K RAM board" unless Model.ram_fits?(@model, ram_kb)
92
95
 
@@ -99,6 +102,7 @@ module Badline
99
102
  matrix = @model.keyboard == :business ? KeyboardPorts::BUSINESS_MATRIX : KeyboardPorts::GRAPHICS_MATRIX
100
103
  @keyboard = Input::Keyboard.new(matrix:)
101
104
  keyboard_ports = KeyboardPorts.new(@keyboard)
105
+ @keyboard_ports = keyboard_ports
102
106
  registers = Array.new(Chips::CRTC::MASKS.length, 0)
103
107
  @pia1 = Chips::PIA.new(peripheral: keyboard_ports)
104
108
  @ieee = IEEEPorts.new(Drives::IEEEBus.new)
@@ -128,13 +132,23 @@ module Badline
128
132
  @cycles = 0
129
133
  @init_handlers = []
130
134
  @pending_keys = nil
135
+ @init_keys = nil
131
136
  @dos = nil
132
137
  @ieee_trap = nil
133
138
  @capture_output = nil
134
- init_ieee_drives
139
+ init_ieee_drives(true_drive_model)
135
140
  @init_threshold = boot_cycles(ram_kb)
136
141
  end
137
142
 
143
+ # Whether this is the SuperPET's board (SuperPET).
144
+ def superpet? = false
145
+
146
+ # Whether the picture shows the SuperPET's APL characters.
147
+ def apl_characters? = false
148
+
149
+ # Whether an autostart finds BASIC to type into.
150
+ def boots_basic? = true
151
+
138
152
  # The vertical drive line, high but in the retrace.
139
153
  def vertical_drive? = @vertical_drive
140
154
 
@@ -253,3 +267,5 @@ module Badline
253
267
  end
254
268
  end
255
269
  end
270
+
271
+ require "badline/pet/superpet"
@@ -28,6 +28,7 @@ module Badline
28
28
  out.int("cycles", @cycles)
29
29
  pending = @pending_keys
30
30
  out.ints("host.pending_keys", pending) if pending
31
+ save_init_keys(out)
31
32
  out.int("host.init_pending", booting? ? @init_handlers.length : 0)
32
33
  out.text("host.true_drive_model", @true_drive_model)
33
34
  end
@@ -36,6 +37,7 @@ module Badline
36
37
  @cycles = input.int("cycles", @cycles)
37
38
  pending = input.ints("host.pending_keys", [])
38
39
  @pending_keys = pending.empty? ? nil : pending.dup
40
+ load_init_keys(input)
39
41
  @init_handlers_lost = [input.int("host.init_pending", 0) - @init_handlers.length, 0].max
40
42
  @true_drive_model = input.choice("host.true_drive_model", TCBMDrive::TRUE_DRIVE_MODELS, @true_drive_model)
41
43
  end
data/lib/badline/plus4.rb CHANGED
@@ -144,6 +144,7 @@ module Badline
144
144
  @sound_mix = @sid_card ? SoundMix.new(@sound, @sid_card) : nil
145
145
  @init_handlers = []
146
146
  @pending_keys = nil
147
+ @init_keys = nil
147
148
  @dos = nil
148
149
  @serial_trap = nil
149
150
  @save_trap = nil
Binary file
Binary file
Binary file
@@ -128,6 +128,81 @@ https://www.zimmers.net/anonftp/pub/cbm/firmware/drives/old/8050/
128
128
  and named by the 8050's parts list
129
129
  (https://www.zimmers.net/anonftp/pub/cbm/schematics/drives/old/8050/parts.txt).
130
130
 
131
+ 1001/fdc-251257-02a.rom
132
+ -----------------------
133
+ The SFD-1001's floppy controller program, 251257-02A: the first 1 KB
134
+ of the 2716 on its 6530 adaptor (251252-01), whose A10 is grounded, so
135
+ the controller runs it from $FC00-$FFFF in place of the 6530's mask.
136
+ Its interface processor runs 8050/dos-2.7.rom, the same 16 KB as
137
+ 901887-01 and 901888-01. Drives::Model1001 loads it.
138
+ SHA-1 473664d405942865d46a6e723eb7d3f243584f7a (the whole 2 KB EPROM,
139
+ SHA-1 3b954eb34f7ea088eed1d33ebc6d6e83a3e9be15).
140
+
141
+ Downloaded from
142
+ https://www.zimmers.net/anonftp/pub/cbm/firmware/drives/old/1001/251257-02A.bin
143
+
144
+ 4040/dos-1.2.rom
145
+ ----------------
146
+ The 2040's DOS 1.2, the 3040's with DOS 1, 8 KB for the interface
147
+ processor's $E000-$FFFF: 901468-06 ($E000-$EFFF, SHA-1
148
+ 4d9658f2e6ff3276e5c6e224611a66ce44b16fc7) followed by 901468-07
149
+ ($F000-$FFFF, SHA-1 6a51c7954938439ca8342fc295bda050c06e1791). No DOS
150
+ 1.0 image is public, so both DOS 1 units run it, as xpet's 2040 does.
151
+ Drives::Model2040 loads it.
152
+ SHA-1 e37b3bfd801eb19dea50cf8b4a6af8613c3520d3.
153
+
154
+ 4040/fdc-901466-02.rom
155
+ ----------------------
156
+ The 6530 of the DOS 1 floppy controller, 901466-02, the same 1 KB as
157
+ 901466-01, run from $FC00-$FFFF.
158
+ SHA-1 d539858f839f96393f218307df7394362a84a26a.
159
+
160
+ 4040/dos-2.1.rom
161
+ ----------------
162
+ DOS 2.1, 12 KB for the interface processor's $D000-$FFFF: 901468-11
163
+ ($D000, SHA-1 8415f3159dea73161e0cef7960afa6c76953b6f8), 901468-12
164
+ ($E000, SHA-1 e8a94f239082d45f64f01b2d8e488d18fe659cbb) and 901468-13
165
+ ($F000, SHA-1 6ada7904ac9d13c3f1c0a8715f9c4be1aa6eb0bb). xpet's 3040
166
+ runs it, and so does Drives::Model3040.
167
+ SHA-1 02bd4b0c8508b3874b95799a9a63caf369c837de.
168
+
169
+ 4040/dos-2.1-rev.rom
170
+ --------------------
171
+ The revised DOS 2.1, 12 KB for $D000-$FFFF: 901468-14 ($D000, SHA-1
172
+ ffb992b82ec913ddff7be964d7527aca3e21580c), 901468-15 ($E000, SHA-1
173
+ f702d6917fe8a798740ba4d467b500944ae7b70a) and 901468-16 ($F000, SHA-1
174
+ 04b918cf4adeee8015b43383d3cea7288a7d0aa8). xpet's 4040 runs it, and
175
+ so does Drives::Model4040.
176
+ SHA-1 245abbe76581558d270cdbb6fe55f56748403d8e.
177
+
178
+ 4040/fdc-901466-04.rom
179
+ ----------------------
180
+ The 6530 of the DOS 2.1 floppy controller, 901466-04, run from
181
+ $FC00-$FFFF under both DOS 2.1 sets.
182
+ SHA-1 6645fa40b81be1ff7d1384e9b52df06a26ab0bfb.
183
+
184
+ All downloaded from
185
+ https://www.zimmers.net/anonftp/pub/cbm/firmware/drives/old/4040/
186
+ and concatenated in address order.
187
+
188
+ 9060/dos-3.0.rom
189
+ ----------------
190
+ The D9060's and D9090's DOS 3.0, 16 KB for the interface processor's
191
+ $C000-$FFFF: 300516 rev C ($C000-$DFFF, SHA-1
192
+ bb1ddb5da94a86266012eca54818aa21dc4cef6a) followed by 300517 rev C
193
+ ($E000-$FFFF, SHA-1 4c17d014de48c906871b9b6c7d037d8736b1fd52), the set
194
+ xpet's 9000 runs.
195
+ SHA-1 c48df2cbb0eea656c3243df7ea8bfefcd171b8e8.
196
+
197
+ 9060/sasi-300515-revb.rom
198
+ -------------------------
199
+ The program of the D9060's and D9090's SASI host processor, 300515
200
+ rev B, 2 KB for $F800-$FFFF.
201
+ SHA-1 59dafbd4855083074ba8dc96a04d4daa5b76e0d6.
202
+
203
+ Both downloaded from
204
+ https://www.zimmers.net/anonftp/pub/cbm/firmware/drives/old/9090/
205
+
131
206
  Commodore VIC-20 ROMs
132
207
  =====================
133
208
 
@@ -377,6 +452,66 @@ the German letters and the section sign in place of @ [ \ ] and in
377
452
  some of the graphics. The CRTC's MA13, bit 5 of R12, picks the half.
378
453
  SHA-1 9616f7f18757cccefb702a945f954b644d5b17d1.
379
454
 
455
+ Commodore SuperPET ROMs
456
+ =======================
457
+
458
+ Downloaded from
459
+ https://www.zimmers.net/anonftp/pub/cbm/firmware/computers/pet/SuperPET/
460
+ The Waterloo 6809 firmware, as the two-board SuperPET's three 2764s hold
461
+ it. The three-board SuperPET's 2532s and 2516 hold the same bytes, and
462
+ each file below names them. In 6502 mode the SuperPET runs the 8032's
463
+ ROMs above. Nothing maps these yet.
464
+
465
+ pet/superpet-a000.rom
466
+ ---------------------
467
+ The Waterloo ROM for $A000-$BFFF, 970018-12
468
+ (waterloo-a000-bfff.970018-12.bin): 901898-01
469
+ (waterloo-a000.901898-01.bin, SHA-1
470
+ 0414b3ab847c8977eb05c2fcc72efcf2f9d92871) followed by 901898-02
471
+ (waterloo-b000.901898-02.bin, SHA-1
472
+ df154939b934d0aeeb376813ec1ba0d43c2a3378).
473
+ SHA-1 dcd18397dd2a691118aaacf2b087d08e3782f81a.
474
+
475
+ pet/superpet-c000.rom
476
+ ---------------------
477
+ The Waterloo ROM for $C000-$DFFF, 970019-12
478
+ (waterloo-c000-dfff.970019-12.bin): 901898-03
479
+ (waterloo-c000.901898-03.bin, SHA-1
480
+ 6c5b0cce97068f8841112ba6d5cd8e568b562fa3) followed by 901898-04
481
+ (waterloo-d000.901898-04.bin, SHA-1
482
+ b42a2050a319a1ffca7868a8d8d635fadd37ec37).
483
+ SHA-1 3ac4b9ae895c45630d10cfc9079f5dcbce5eb48e.
484
+
485
+ pet/superpet-e000.rom
486
+ ---------------------
487
+ The Waterloo ROM for $E000-$FFFF, 970020-12
488
+ (waterloo-e000-ffff.970020-12.bin), with the 60 Hz CRTC table: 901897-01
489
+ (waterloo-e000.901897-01.bin, SHA-1
490
+ e8ce8347451a001214a5e71a13081b38b4be23bc) for $E000-$E7FF, 2K of $FF
491
+ where the I/O page sits, and 901898-05 (waterloo-f000.901898-05.bin,
492
+ SHA-1 9b4a5134d20345171e7303445f87c4e0b9addc96) for $F000-$FFFF, which
493
+ ends in the 6809's vectors.
494
+ SHA-1 618992fe0046b670695f5b1d1c168ace9e6b8470.
495
+
496
+ pet/superpet-e000-50hz.rom
497
+ --------------------------
498
+ The 50 Hz Waterloo ROM for $E000-$FFFF, 970034-12
499
+ (waterloo-e000-ffff-970034-12.bin, from Christian Forstreuter's MMF
500
+ 9000, U49). Its $E000-$E7FF is the 50 Hz 901897-01
501
+ (waterloo-e000.901897-x.50Hz.bin, SHA-1
502
+ 57f8c3ef305768d9cba9a96d3f7b90d4a3c2daa4), which differs from the 60 Hz
503
+ one in three bytes of the CRTC table, $E0C2, $E0C3 and $E0C5, and the
504
+ rest is superpet-e000.rom's.
505
+ SHA-1 ef6c5e5e9be17b87faed43cf0007f98731d78384.
506
+
507
+ pet/characters-superpet.rom
508
+ ---------------------------
509
+ The SuperPET's 4K character generator, 901640-01
510
+ (characters.901640-01.bin). Its first half is 901447-10 byte for byte,
511
+ and its second holds an ASCII and an APL set. The CRTC's MA13, bit 5 of
512
+ R12, picks the half.
513
+ SHA-1 bf346f11595a3e65e55d6aeeaa2c0cec807b66c7.
514
+
380
515
  Commodore CBM-II ROMs
381
516
  =====================
382
517
 
@@ -459,3 +594,34 @@ p500-basic-hi.901235-02.bin, SHA-1
459
594
  1b9a55f12f8cf025754d8029cc5324b474c35841) concatenated, for
460
595
  $8000-$BFFF in segment 15.
461
596
  SHA-1 e69531d45f5993f8e53c6bd9ab2a7bc10fe2d02f.
597
+
598
+ MOS KIM-1 ROMs
599
+ ==============
600
+
601
+ Downloaded from
602
+ https://www.zimmers.net/anonftp/pub/cbm/firmware/computers/kim1/
603
+ The files there are the monitor listing assembled with $FF in the
604
+ unused bytes. Real 6530-002 and 6530-003 chips have $00 there, as Hans
605
+ Otten found dumping his own
606
+ (http://retro.hansotten.nl/6502-sbc/kim-1-manuals-and-software/kim_1-roms/),
607
+ so badline zeroes those bytes and keeps the code as it is. Only a
608
+ program that reads unused ROM sees the difference.
609
+
610
+ kim1/6530-002.rom
611
+ -----------------
612
+ The mask ROM of the 6530-002, U2: the monitor, for $1C00-$1FFF, its
613
+ keypad and display routines, the teletype's and the 6502's vectors.
614
+ 6530-002.bin from zimmers.net, SHA-1
615
+ 054f7f6989af3a59462ffb0372b6f56f307b5362, with the three bytes at
616
+ $1FF7-$1FF9 zeroed. The result is Otten's dump of a real chip,
617
+ 6530-002 fillerbyte00.bin.
618
+ SHA-1 d0b5ceb279303cad219d6609d7db03a120f59ab8.
619
+
620
+ kim1/6530-003.rom
621
+ -----------------
622
+ The mask ROM of the 6530-003, U3: the cassette routines, for
623
+ $1800-$1BFF. 6530-003.bin from zimmers.net, SHA-1
624
+ 60b6e48f35fe4899e29166641bac3e81e3b9d220, with the 356 bytes at
625
+ $1A96-$1BF9 zeroed. The result is Otten's dump of a real chip,
626
+ 6530-003 fillerbyte00.bin.
627
+ SHA-1 16caaf9d4c8327e0d3198887499fe30056df3084.
Binary file
Binary file
@@ -42,6 +42,8 @@ module Badline
42
42
  CBM2 = "CBM-II"
43
43
  # xcbm5x0 names its machine CBM-II-5x0, the P500.
44
44
  CBM2_5X0 = "CBM-II-5x0"
45
+ # VICE has no KIM-1, so badline names it.
46
+ KIM1 = "KIM1"
45
47
  # The file format version each machine's VICE emulator reads, where
46
48
  # it isn't FORMAT_MAJOR.0: xpet and xcbm2 refuse any other than 1.0, and
47
49
  # xcbm5x0 writes 0.0.
@@ -8,7 +8,7 @@ module Badline
8
8
  # voice1 to voice3, on one row.
9
9
  class Markdown
10
10
  NAMES = { "c64" => "C64", "vic20" => "VIC-20", "c128" => "C128", "plus4" => "Plus/4", "pet" => "PET",
11
- "cbm2" => "CBM-II" }.freeze
11
+ "cbm2" => "CBM-II", "kim1" => "KIM-1" }.freeze
12
12
  TAG_TYPES = { Keyed::INT => "int", Keyed::BOOL => "bool", Keyed::BYTES => "bytes", Keyed::INTS => "ints",
13
13
  Keyed::TEXT => "text" }.freeze
14
14
 
@@ -39,9 +39,11 @@ module Badline
39
39
  # the 264 series' models, its TCBM interface, cartridge, tape and
40
40
  # true drives, the 1541 and the 1551, a CRTC PET, a 2001, an 8096,
41
41
  # an 8296 with its user port jumpered, a PET with a disk and tapes and
42
- # one with a true 2031, one with an 8050 and one with an 8250, and a
43
- # 610, a 720, a 610 with a cartridge and one with a disk, and a PAL
44
- # and an NTSC 510.
42
+ # one with a true 2031, one with an 8050, one with an 8250, one with
43
+ # a 4040 and one with a D9060, a SuperPET in 6809 mode with a disk in
44
+ # device 8, and a 610, a 720, a 610 with a cartridge and one with a
45
+ # disk, a PAL and an NTSC 510, and a KIM-1 on its keypad and one
46
+ # expanded, on a teletype.
45
47
  def self.machines
46
48
  {
47
49
  "c64" => [C64.new, C64.new(ram_expansion: :plus256k), C64.new(reu: 512),
@@ -55,9 +57,11 @@ module Badline
55
57
  plus4_with_cartridge, plus4_with_tape, plus4_with_drive, plus4_with_drive("1551")],
56
58
  "pet" => [PET.new, PET.new(model: "2001"), PET.new(model: "8096"),
57
59
  PET.new(model: "8296", characters: "din", jumpers: %w[userport]), pet_with_media,
58
- pet_with_drive, pet_with_unit("8050"), pet_with_unit("8250")],
60
+ pet_with_drive, pet_with_unit("8050"), pet_with_unit("8250"), pet_with_dos2_unit,
61
+ pet_with_hard_disk, superpet_with_disk],
59
62
  "cbm2" => [CBM2.new, CBM2.new(model: "720", kernal: "03b", mains_hz: 60), cbm2_with_cartridge,
60
- cbm2_with_disk, CBM2::P500.new, CBM2::P500.new(model: "510ntsc")]
63
+ cbm2_with_disk, CBM2::P500.new, CBM2::P500.new(model: "510ntsc")],
64
+ "kim1" => [KIM1.new, KIM1.new(tty: true, ram: :expanded)]
61
65
  }
62
66
  end
63
67
 
@@ -72,6 +76,14 @@ module Badline
72
76
  end
73
77
  end
74
78
 
79
+ # A SuperPET with its CPU switch at 6809 and a disk in device 8
80
+ # through the traps.
81
+ def self.superpet_with_disk
82
+ PET::SuperPET.new(cpu: "6809").tap do |machine|
83
+ machine.mount(Storage::D64Image.new("", read_only: true, bytes: blank(174_848)))
84
+ end
85
+ end
86
+
75
87
  # A PET with a 2031 holding a blank disk.
76
88
  def self.pet_with_drive
77
89
  PET.new.tap do |machine|
@@ -87,9 +99,18 @@ module Badline
87
99
  else
88
100
  Storage::D80Image.new("", bytes: blank(533_248))
89
101
  end
90
- PET.new.tap { |machine| machine.plug_drive8050(model).insert(Drives::Model8050::Disk.new(image)) }
102
+ PET.new.tap { |machine| machine.plug_ieee_drive(model).insert(Drives::Model8050::Disk.new(image)) }
91
103
  end
92
104
 
105
+ # A PET with a 4040 holding a blank disk in drive 0.
106
+ def self.pet_with_dos2_unit
107
+ image = Storage::D64Image.new("", bytes: blank(174_848))
108
+ PET.new.tap { |machine| machine.plug_ieee_drive("4040").insert(Drives::Model4040::Disk.new(image)) }
109
+ end
110
+
111
+ # A PET with a D9060 and no hard disk in it.
112
+ def self.pet_with_hard_disk = PET.new.tap { |machine| machine.plug_ieee_drive("9060") }
113
+
93
114
  def self.blank(length) = Array.new(length, 0)
94
115
 
95
116
  # A 610 with a disk in device 8 through the traps.
@@ -35,7 +35,7 @@ module Badline
35
35
  class Image
36
36
  MACHINE = "BL-MACHINE"
37
37
  FAMILIES = { "c64" => "C64", "vic20" => "VIC-20", "c128" => "C128", "plus4" => "Plus/4", "pet" => "PET",
38
- "cbm2" => "CBM-II" }.freeze
38
+ "cbm2" => "CBM-II", "kim1" => "KIM-1" }.freeze
39
39
 
40
40
  # The snapshots VICE's emulators write that badline doesn't read, by
41
41
  # the machine their container names.
@@ -67,6 +67,7 @@ module Badline
67
67
  # snapshots badline doesn't write for xplus4.
68
68
  def self.exported(computer)
69
69
  raise FormatError, "badline doesn't export a Plus/4's snapshot for VICE" if computer.family == :plus4
70
+ raise FormatError, "VICE has no KIM-1 to open a snapshot of one" if computer.family == :kim1
70
71
 
71
72
  computer.settle_for_vice!
72
73
  sections = computer.save_modules
@@ -101,6 +102,7 @@ module Badline
101
102
  when :plus4 then Container::PLUS4
102
103
  when :pet then Container::PET
103
104
  when :cbm2 then computer.is_a?(CBM2::P500) ? Container::CBM2_5X0 : Container::CBM2
105
+ when :kim1 then Container::KIM1
104
106
  else Container::MACHINE
105
107
  end
106
108
  end
@@ -114,6 +116,7 @@ module Badline
114
116
  when "plus4" then Plus4Setup.read_fields(machine)
115
117
  when "pet" then PETSetup.read_fields(machine)
116
118
  when "cbm2" then CBM2Setup.read_fields(machine)
119
+ when "kim1" then KIM1Setup.read_fields(machine)
117
120
  else C64Setup.read_fields(machine)
118
121
  end
119
122
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Snapshot
5
+ # How a KIM-1 was built: its RAM, one of KIM1::Bus::RAM_CONFIGURATIONS
6
+ # by name, the argument KIM1.new takes. The ROMs are the board's own.
7
+ KIM1Setup = Data.define(:ram)
8
+
9
+ class KIM1Setup
10
+ RAM = KIM1::Bus::RAM_CONFIGURATIONS.map(&:to_s).freeze
11
+
12
+ # The setup of `machine`.
13
+ def self.of(machine) = new(ram: machine.bus.ram_configuration.to_s)
14
+
15
+ # The RAM by name, in a keyed snapshot module.
16
+ def write_fields(out)
17
+ out.text("ram", ram)
18
+ end
19
+
20
+ def self.read_fields(input) = new(ram: input.choice("ram", RAM, "1k"))
21
+
22
+ # A machine built this way, at power-on.
23
+ def build = KIM1.new(ram: ram.to_sym)
24
+
25
+ def to_s = "KIM-1 with #{ram == 'expanded' ? 'expanded' : ram.upcase} RAM"
26
+ end
27
+ end
28
+ end