badline 0.17.0 → 0.19.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 (195) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +193 -0
  3. data/CLAUDE.md +19 -7
  4. data/CONTRIBUTING.md +11 -1
  5. data/README.md +178 -26
  6. data/doc/library.md +5 -1
  7. data/doc/media.md +3 -2
  8. data/doc/pinned-behaviour.md +169 -1
  9. data/doc/snapshot-format.md +302 -35
  10. data/doc/snapshots.md +97 -26
  11. data/doc/vice.md +344 -0
  12. data/exe/badline-ruby +5 -0
  13. data/lib/badline/audio/renderer.rb +4 -8
  14. data/lib/badline/audio/terminal.rb +34 -2
  15. data/lib/badline/c128/keyed_state.rb +2 -0
  16. data/lib/badline/c128.rb +5 -0
  17. data/lib/badline/c64/bus/fittings.rb +6 -0
  18. data/lib/badline/c64/keyed_state.rb +2 -0
  19. data/lib/badline/c64.rb +7 -0
  20. data/lib/badline/cbm2/keyed_state.rb +4 -0
  21. data/lib/badline/cbm2/p500.rb +9 -3
  22. data/lib/badline/cbm2.rb +10 -3
  23. data/lib/badline/chips/cia/timer.rb +2 -2
  24. data/lib/badline/chips/cpu/core.rb +29 -4
  25. data/lib/badline/chips/cpu/instruction_set.rb +1 -1
  26. data/lib/badline/chips/cpu/interrupts.rb +9 -0
  27. data/lib/badline/chips/cpu/keyed_state.rb +15 -9
  28. data/lib/badline/chips/cpu/microcode.rb +10 -0
  29. data/lib/badline/chips/m6809/arithmetic.rb +140 -0
  30. data/lib/badline/chips/m6809/bus_steps.rb +223 -0
  31. data/lib/badline/chips/m6809/core.rb +149 -0
  32. data/lib/badline/chips/m6809/indexed.rb +82 -0
  33. data/lib/badline/chips/m6809/interrupts.rb +159 -0
  34. data/lib/badline/chips/m6809/keyed_state.rb +147 -0
  35. data/lib/badline/chips/m6809/opcodes.rb +159 -0
  36. data/lib/badline/chips/m6809/operations.rb +258 -0
  37. data/lib/badline/chips/m6809/plans.rb +143 -0
  38. data/lib/badline/chips/m6809/registers.rb +82 -0
  39. data/lib/badline/chips/m6809/stack.rb +140 -0
  40. data/lib/badline/chips/m6809.rb +13 -0
  41. data/lib/badline/chips/riot/timer.rb +14 -3
  42. data/lib/badline/chips/rriot.rb +8 -3
  43. data/lib/badline/chips/sid/decimator.rb +1 -1
  44. data/lib/badline/chips/sid/filter.rb +4 -4
  45. data/lib/badline/chips/sid/keyed_parts.rb +51 -18
  46. data/lib/badline/chips/sid/waveform.rb +6 -6
  47. data/lib/badline/chips/sid.rb +6 -2
  48. data/lib/badline/chips/vic_i/keyed_parts.rb +12 -2
  49. data/lib/badline/chips/vic_i/light_pen.rb +89 -0
  50. data/lib/badline/chips/vic_i.rb +91 -23
  51. data/lib/badline/data_path.rb +3 -3
  52. data/lib/badline/drives/ieee_models.rb +54 -0
  53. data/lib/badline/drives/model1001.rb +37 -0
  54. data/lib/badline/drives/model1541/sector_reader.rb +20 -3
  55. data/lib/badline/drives/model1541.rb +1 -0
  56. data/lib/badline/drives/model1551.rb +1 -0
  57. data/lib/badline/drives/model1571.rb +1 -0
  58. data/lib/badline/drives/model1581.rb +1 -0
  59. data/lib/badline/drives/model2031.rb +7 -0
  60. data/lib/badline/drives/model4040/disk.rb +62 -0
  61. data/lib/badline/drives/model4040/ip_bus.rb +46 -0
  62. data/lib/badline/drives/model4040/keyed_state.rb +57 -0
  63. data/lib/badline/drives/model4040/mechanism.rb +195 -0
  64. data/lib/badline/drives/model4040/parts.rb +20 -0
  65. data/lib/badline/drives/model4040.rb +195 -0
  66. data/lib/badline/drives/model8050/board.rb +79 -0
  67. data/lib/badline/drives/model8050/dos_board.rb +134 -0
  68. data/lib/badline/drives/model8050/fdc_bus.rb +7 -0
  69. data/lib/badline/drives/model8050/idle.rb +148 -31
  70. data/lib/badline/drives/model8050/keyed_state.rb +5 -2
  71. data/lib/badline/drives/model8050.rb +32 -130
  72. data/lib/badline/drives/model9060/idle.rb +169 -0
  73. data/lib/badline/drives/model9060/keyed_state.rb +123 -0
  74. data/lib/badline/drives/model9060/parts.rb +98 -0
  75. data/lib/badline/drives/model9060/sasi_bus.rb +88 -0
  76. data/lib/badline/drives/model9060/sasi_commands.rb +168 -0
  77. data/lib/badline/drives/model9060/sasi_target.rb +161 -0
  78. data/lib/badline/drives/model9060.rb +197 -0
  79. data/lib/badline/frontend/app.rb +8 -0
  80. data/lib/badline/frontend/boot.rb +3 -2
  81. data/lib/badline/frontend/controls.rb +62 -6
  82. data/lib/badline/frontend/keys.rb +36 -0
  83. data/lib/badline/frontend/kim1_panel.rb +208 -0
  84. data/lib/badline/frontend/media_slots.rb +8 -1
  85. data/lib/badline/frontend/menu/drive_types.rb +56 -0
  86. data/lib/badline/frontend/menu/menu_dialogs.rb +61 -14
  87. data/lib/badline/frontend/menu/menu_media.rb +42 -12
  88. data/lib/badline/frontend/menu/menu_pages.rb +97 -2
  89. data/lib/badline/frontend/menu/menu_ports.rb +38 -1
  90. data/lib/badline/frontend/menu/pause_menu.rb +5 -1
  91. data/lib/badline/frontend/pet_keyboard.rb +23 -1
  92. data/lib/badline/frontend/screen.rb +1 -1
  93. data/lib/badline/frontend/screens.rb +40 -2
  94. data/lib/badline/frontend/teletype_pane.rb +152 -0
  95. data/lib/badline/frontend/timeline.rb +31 -2
  96. data/lib/badline/frontend.rb +3 -0
  97. data/lib/badline/input/joystick.rb +15 -2
  98. data/lib/badline/kim1/bus.rb +117 -0
  99. data/lib/badline/kim1/cpu.rb +25 -0
  100. data/lib/badline/kim1/host_terminal.rb +74 -0
  101. data/lib/badline/kim1/key_entry.rb +74 -0
  102. data/lib/badline/kim1/keyed_modules.rb +53 -0
  103. data/lib/badline/kim1/keyed_state.rb +133 -0
  104. data/lib/badline/kim1/panel.rb +176 -0
  105. data/lib/badline/kim1/rriots.rb +28 -0
  106. data/lib/badline/kim1/sound.rb +29 -0
  107. data/lib/badline/kim1/tape.rb +118 -0
  108. data/lib/badline/kim1/teletype.rb +193 -0
  109. data/lib/badline/kim1.rb +194 -0
  110. data/lib/badline/machine/ieee_drives.rb +94 -117
  111. data/lib/badline/machine/keyboard_buffer.rb +20 -3
  112. data/lib/badline/machine/line_sound.rb +122 -0
  113. data/lib/badline/machine.rb +49 -15
  114. data/lib/badline/media/extensions.rb +8 -4
  115. data/lib/badline/media/kim1_media.rb +150 -0
  116. data/lib/badline/media/pet_media.rb +3 -1
  117. data/lib/badline/media/true_drive.rb +52 -45
  118. data/lib/badline/media/vic20_media.rb +4 -2
  119. data/lib/badline/media.rb +16 -6
  120. data/lib/badline/memory.rb +2 -4
  121. data/lib/badline/options/family.rb +98 -8
  122. data/lib/badline/options/help.rb +44 -12
  123. data/lib/badline/options/table.rb +44 -12
  124. data/lib/badline/options/validation.rb +44 -8
  125. data/lib/badline/options.rb +27 -8
  126. data/lib/badline/pet/bus.rb +16 -2
  127. data/lib/badline/pet/keyboard_ports.rb +9 -2
  128. data/lib/badline/pet/keyed_state.rb +4 -0
  129. data/lib/badline/pet/model.rb +11 -2
  130. data/lib/badline/pet/rom_sets.rb +1 -0
  131. data/lib/badline/pet/sound.rb +5 -105
  132. data/lib/badline/pet/superpet/acia.rb +12 -0
  133. data/lib/badline/pet/superpet/board.rb +221 -0
  134. data/lib/badline/pet/superpet/dongle.rb +92 -0
  135. data/lib/badline/pet/superpet/keyed_modules.rb +63 -0
  136. data/lib/badline/pet/superpet/keyed_parts.rb +76 -0
  137. data/lib/badline/pet/superpet/m6809.rb +32 -0
  138. data/lib/badline/pet/superpet/waterloo_traps.rb +199 -0
  139. data/lib/badline/pet/superpet.rb +221 -0
  140. data/lib/badline/pet.rb +23 -3
  141. data/lib/badline/plus4/keyed_state.rb +2 -0
  142. data/lib/badline/plus4.rb +5 -0
  143. data/lib/badline/roms/1001/fdc-251257-02a.rom +0 -0
  144. data/lib/badline/roms/4040/dos-1.2.rom +0 -0
  145. data/lib/badline/roms/4040/dos-2.1-rev.rom +0 -0
  146. data/lib/badline/roms/4040/dos-2.1.rom +0 -0
  147. data/lib/badline/roms/4040/fdc-901466-02.rom +0 -0
  148. data/lib/badline/roms/4040/fdc-901466-04.rom +0 -0
  149. data/lib/badline/roms/9060/dos-3.0.rom +0 -0
  150. data/lib/badline/roms/9060/sasi-300515-revb.rom +0 -0
  151. data/lib/badline/roms/README +176 -0
  152. data/lib/badline/roms/kim1/6530-002.rom +0 -0
  153. data/lib/badline/roms/kim1/6530-003.rom +0 -0
  154. data/lib/badline/roms/pet/characters-superpet.rom +0 -0
  155. data/lib/badline/roms/pet/superpet-a000.rom +0 -0
  156. data/lib/badline/roms/pet/superpet-c000.rom +0 -0
  157. data/lib/badline/roms/pet/superpet-e000-50hz.rom +0 -0
  158. data/lib/badline/roms/pet/superpet-e000.rom +0 -0
  159. data/lib/badline/snapshot/container.rb +8 -4
  160. data/lib/badline/snapshot/field_doc/markdown.rb +1 -1
  161. data/lib/badline/snapshot/field_doc.rb +35 -10
  162. data/lib/badline/snapshot/image.rb +19 -7
  163. data/lib/badline/snapshot/kim1_setup.rb +28 -0
  164. data/lib/badline/snapshot/pet_setup.rb +27 -11
  165. data/lib/badline/snapshot/storage_setup.rb +4 -1
  166. data/lib/badline/snapshot/vic20_setup.rb +11 -7
  167. data/lib/badline/snapshot/vice/pet.rb +14 -7
  168. data/lib/badline/snapshot/vice/pet_cpu.rb +39 -5
  169. data/lib/badline/snapshot/vice/pet_crtc.rb +15 -2
  170. data/lib/badline/snapshot/vice/pet_dongle.rb +72 -0
  171. data/lib/badline/snapshot/vice/pet_drive8050.rb +188 -68
  172. data/lib/badline/snapshot/vice/pet_mem.rb +55 -5
  173. data/lib/badline/snapshot/vice/pet_restore.rb +40 -11
  174. data/lib/badline/snapshot/vice/vic20.rb +70 -0
  175. data/lib/badline/snapshot/vice/vic20_cpu.rb +61 -0
  176. data/lib/badline/snapshot/vice/vic20_mem.rb +85 -0
  177. data/lib/badline/snapshot/vice/vic20_restore.rb +124 -0
  178. data/lib/badline/snapshot/vice/vic20_vici.rb +200 -0
  179. data/lib/badline/snapshot/vice.rb +1 -0
  180. data/lib/badline/snapshot.rb +8 -4
  181. data/lib/badline/status.rb +30 -30
  182. data/lib/badline/storage/d67_image.rb +55 -0
  183. data/lib/badline/storage/d90_image.rb +180 -0
  184. data/lib/badline/storage/kim_tape.rb +254 -0
  185. data/lib/badline/storage/papertape.rb +90 -0
  186. data/lib/badline/storage.rb +4 -0
  187. data/lib/badline/support/kim1_checkpoint.rb +41 -0
  188. data/lib/badline/support/superpet_checkpoint.rb +35 -0
  189. data/lib/badline/version.rb +1 -1
  190. data/lib/badline/vic20/keyed_modules.rb +6 -3
  191. data/lib/badline/vic20/keyed_state.rb +6 -4
  192. data/lib/badline/vic20/port_wiring.rb +11 -0
  193. data/lib/badline/vic20.rb +30 -12
  194. data/lib/badline.rb +1 -0
  195. metadata +85 -1
@@ -49,10 +49,11 @@ module Badline
49
49
  # wrapped as the banner is.
50
50
  def media_kinds
51
51
  text = "Media can be #{listed(Media::Extensions::PROGRAMS)} program, #{listed(%i[disk])} disk image, " \
52
- "#{listed(%i[ieee_disk])} disk image for a PET, #{listed(%i[gcr])} disk image for a true drive, " \
53
- "#{listed(%i[disk_list])} list of disk images, " \
52
+ "#{listed(%i[ieee_disk])} disk image or #{listed(%i[hard_disk])} hard disk for a PET, " \
53
+ "#{listed(%i[gcr])} disk image for a true drive, #{listed(%i[disk_list])} list of disk images, " \
54
54
  "#{listed(%i[archive])} tape archive, #{listed(%i[tape])} tape, #{listed(%i[cartridge])} " \
55
- "cartridge, #{listed(%i[tune])} tune, #{listed(%w[.vsf])} snapshot, or a directory to mount as device 8."
55
+ "cartridge, #{listed(%i[tune])} tune, #{listed(%i[papertape])} papertape for a KIM-1, " \
56
+ "#{listed(%w[.vsf])} snapshot, or a directory to mount as device 8."
56
57
  wrap(text)
57
58
  end
58
59
 
@@ -87,17 +88,19 @@ module Badline
87
88
  #{@program} plus4 [options] [media]
88
89
  #{@program} pet [options] [media]
89
90
  #{@program} cbm2 [options] [media]
91
+ #{@program} kim1 [options] [program]
90
92
  #{@program} --headless [options] tune.sid
91
93
  #{@program} [options] tune.sid --audio-out FILE
92
94
  #{@program} sid [options] FILE|DIR...
93
95
 
94
96
  Commands:
95
97
  c64 Run a C64, the one --model names (the default)
96
- vic20 Run a PAL VIC-20, with the RAM --ram names
98
+ vic20 Run a VIC-20, PAL or --ntsc, with the RAM --ram names
97
99
  c128 Run a C128 in C128 mode, the one --model names
98
100
  plus4 Run a Plus/4 or a C16, the one --model names
99
101
  pet Run a PET or a CBM, the one --model names
100
102
  cbm2 Run a CBM-II, a B series or a P500, the one --model names
103
+ kim1 Run a MOS KIM-1, on its keypad and LED display
101
104
  sid Play .sid tunes and directories of them
102
105
 
103
106
  #{media_kinds}
@@ -122,33 +125,60 @@ module Badline
122
125
  ESC, Page Down RUN/STOP and F4 HELP.
123
126
 
124
127
  The PET and the CBM take programs, disks, .d80 and .d82 among them,
125
- and tapes, and a .d80, a .d82 or a PET tape starts one without
126
- `pet`. Their keys type what the host's keys type, Alt with a key
128
+ and tapes, and a .d80, .d82, .d67 or .d90 or a PET tape starts one
129
+ without `pet`. Their keys type what the host's keys type, Alt with a key
127
130
  presses the PET's SHIFT and the key its unshifted character is on,
128
131
  and the pause menu's KEYBOARD page says where the rest are. --basic
129
132
  and --editor fit the upgrades Commodore sold, as in --model 2001
130
133
  --basic 2. BASIC 1 can't LOAD from a disk drive, though a disk still
131
134
  starts its first program, and BASIC 2 can. Their --true-drive makes
132
135
  device 8 an emulated 2031 on the IEEE-488 bus, which reads .d64 and
133
- .g64 images. The 8032 and the 8096 have two 50 Hz editors:
134
- 4-80-b-50hz, the default, and 4-80-b-50hz-0283, another chip's,
136
+ .g64 images, and a .d80 or a .d82 then goes in an emulated 8050 or
137
+ 8250. --drive-type 8050 or 8250 plugs either in instead, and
138
+ --drive-type 1001 an SFD-1001, which takes a .d82 in its one drive.
139
+ --drive-type 4040 or 3040 puts a .d64 in a 4040 or a 3040 instead
140
+ of the 2031, and a .d67, DOS 1's disk, goes in a 2040. A .d90 hard
141
+ disk always goes in a D9060 or a D9090, by its size. The pause
142
+ menu's DRIVE 8 page picks the drive type on the bus.
143
+ The 8032 and the 8096 have two 50 Hz editors: 4-80-b-50hz, the
144
+ default, and 4-80-b-50hz-0283, another chip's,
135
145
  with 64-cycle lines and 313 lines a frame. The 8296 runs its own,
136
146
  4-80-b-50hz-8296, and takes the 8032's too. --characters din fits
137
147
  it with the DIN character ROM, and --jumpers ram9,rama puts RAM at
138
- $9000 and $A000, as xpet's -petram9 and -petramA do.
148
+ $9000 and $A000, as xpet's -petram9 and -petramA do. --model
149
+ superpet runs the SuperPET, and --cpu 6809 its Waterloo 6809 side.
150
+ --bank-ram read write-protects its 64K bank RAM.
139
151
 
140
152
  The CBM-II takes programs, disks, .d80 and .d82 among them, and
141
153
  cartridges, and a cartridge made for it starts one without `cbm2`.
142
154
  --kernal 03b fits the 1983 KERNAL in place of 04a, and --60hz runs
143
155
  it on 60 Hz mains. Its --true-drive makes device 8 an emulated 2031
144
156
  on its IEEE-488 bus, which reads .d64 and .g64 images, and a .d80
145
- or a .d82 then goes in an emulated 8050 or 8250. Its keys type what
157
+ or a .d82 then goes in an emulated 8050 or 8250, and --drive-type
158
+ plugs in either from the start, as on the PET. Its keys type what
146
159
  the host's keys type, F12 is RUN/STOP, Alt with F9 or F10 presses
147
160
  its F9 or F10, and the pause menu's KEYBOARD page says where the
148
161
  rest are. --model 510 or 510ntsc runs the P500, on the VIC-II with
149
162
  KERNAL 02, whose keys are the B series' and whose two joysticks Tab
150
163
  switches to.
151
164
 
165
+ The KIM-1 starts in its monitor, on the keypad and the six LED
166
+ digits, which the window draws with the keys under them. 0-9 and A-F
167
+ are the hex keys, comma AD, period DA, space or + +, G or Return GO,
168
+ P PC, S or Esc ST, R RS and T the SST switch, and a click presses a
169
+ key too. The pause menu's PANEL page sets SST, the TTY/KB jumper and
170
+ what U3's PB7 and PA0 are wired to. --tty puts the monitor on a
171
+ teletype at --baud, shown in the window, or with --headless on the
172
+ terminal, where Ctrl-C quits.
173
+ It loads .ptp and .pap papertapes, which start a KIM-1 without
174
+ `kim1`, and .bin files at --load-address. The program goes into RAM,
175
+ the NMI and IRQ vectors at $17FA and $17FE point at the monitor, and
176
+ the monitor starts it where it loads, or at --start-address.
177
+ --tty-load reads a papertape through the monitor's L command
178
+ instead. --ram 5k fills $0400-$13FF, and --ram expanded $2000-$DFFF
179
+ too. A .wav recording of a KIM tape goes in the cassette deck, which
180
+ the pause menu's DATASETTE page plays for LOADT at $1873.
181
+
152
182
  --headless plays a .sid tune on the host's audio device without the
153
183
  window, and --audio-out renders it to 16-bit PCM instead. The
154
184
  container follows the file's extension, .wav or .aiff. Played on a
@@ -171,10 +201,12 @@ module Badline
171
201
  key=NAME presses a key (space, return, a, f1, run_stop, restore, and
172
202
  on the C128 esc, help, keypad1 and the rest, on the Plus/4
173
203
  esc, help and f1 to f3, on the PET rvs, escape and kp1, and on
174
- the CBM-II escape, norm_graph and kp00) or a joystick's
204
+ the CBM-II escape, norm_graph and kp00, and on the KIM-1 its keys,
205
+ as 0 to f, ad, da, plus, go, pc, st and rs) or a joystick's
175
206
  direction or fire (joy1-up, joy2-fire) for #{Event::HOLD} frames, and
176
207
  pushes the C128's caps_lock or forty_eighty, which lock. type=TEXT
177
- types it, with \\n for RETURN. insert=FILE swaps in a disk, a list's
208
+ types it, with \\n for RETURN, or on the KIM-1 presses the keys it
209
+ names, as in type=AD 0200 DA A9. insert=FILE swaps in a disk, a list's
178
210
  first disk, a tape or a cartridge, and eject=disk, tape or
179
211
  cartridge takes one out. screenshot=FILE saves the frame as a .bmp,
180
212
  with the frame's number in place of %d. menu opens the pause menu,
@@ -7,8 +7,7 @@ module Badline
7
7
  # The names Badline::Model builds, in the order the help lists them.
8
8
  MODELS = %w[c64 c64c ntsc newntsc oldntsc drean sx64 pet64 c64gs ultimax].freeze
9
9
 
10
- # The VIC-20's models, as xvic names its video standards. Only PAL is
11
- # emulated.
10
+ # The VIC-20's models, as xvic names its video standards.
12
11
  VIC20_MODELS = %w[pal ntsc].freeze
13
12
 
14
13
  # The C128's models, as C128::Model names them.
@@ -20,12 +19,22 @@ module Badline
20
19
 
21
20
  # The PETs and CBMs, as PET::Model names them, the 8032 first, the
22
21
  # default.
23
- PET_MODELS = %w[8032 8096 8296 4032 3032 3032b 2001].freeze
22
+ PET_MODELS = %w[8032 8096 8296 4032 3032 3032b 2001 superpet].freeze
24
23
 
25
24
  # The CBM-II's B series, as CBM2::Model names them, the 610 first, the
26
25
  # default, and the P500, as CBM2::P500::Model names them.
27
26
  CBM2_MODELS = %w[610 620 710 720 510 510ntsc].freeze
28
27
 
28
+ # The KIM-1, which has the one model.
29
+ KIM1_MODELS = %w[kim1].freeze
30
+
31
+ # The KIM-1 teletype's rates, as KIM1::Teletype takes them.
32
+ KIM1_BAUDS = %w[110 300 1200 2400 4800 9600].freeze
33
+
34
+ # The KIM-1's RAM as --ram names it, and the names
35
+ # KIM1::Bus::RAM_CONFIGURATIONS gives it.
36
+ KIM1_RAM = { "1k" => :"1k", "5k" => :"5k", "expanded" => :expanded }.freeze
37
+
29
38
  # The B series' KERNALs --kernal names, 901244-04a first, the default.
30
39
  CBM2_KERNALS = %w[04a 03b].freeze
31
40
 
@@ -49,6 +58,22 @@ module Badline
49
58
  Option.new("--disable-jit", "Run without enabling YJIT", section: "Options", build: :ruby),
50
59
  Option.new("-h, --help", "Show this help", section: "Options"),
51
60
  Option.new("--version", "Show the version and what built it", section: "Options", build: :native),
61
+ Option.new("--tty", "Fit the KIM-1's TTY/KB jumper, so its monitor talks to a teletype: a pane in the " \
62
+ "window, or the terminal with --headless",
63
+ section: "Options"),
64
+ Option.new("--baud N", "The KIM-1 teletype's baud: #{KIM1_BAUDS.join(', ')} (default: 9600)",
65
+ section: "Options"),
66
+ Option.new("--tty-load", "Load the KIM-1's .ptp or .pap through its monitor's L command on the teletype, " \
67
+ "in real time, instead of straight into RAM; implies --tty",
68
+ section: "Options"),
69
+ Option.new("--load-address ADDR", "Where the KIM-1 loads a .bin, in hex (default: 0200)",
70
+ section: "Options"),
71
+ Option.new("--start-address ADDR", "Where the KIM-1 starts its program, in hex (default: where it loads)",
72
+ section: "Options"),
73
+ Option.new("--ram SIZE", "VIC-20 RAM expansion: #{RAM_NAMES.join(', ')} (default: unexpanded); " \
74
+ "Plus/4 RAM: 16k, 32k or 64k; PET RAM: 4k, 8k, 16k or 32k (default: the model's own); " \
75
+ "KIM-1 RAM: 1k, 5k or expanded (default: 1k)",
76
+ section: "Options"),
52
77
  Option.new("--no-autostart", "Boot to READY. instead of running the program",
53
78
  section: "Window options", needs: :window),
54
79
  Option.new("--writable", "Let the machine write to disk images, changing their files",
@@ -60,19 +85,20 @@ module Badline
60
85
  "a 1551 on the Plus/4, a 2031 on the PET or the CBM-II, or for a .d80 or .d82 " \
61
86
  "an 8050 or 8250",
62
87
  section: "Window options", needs: :window),
63
- Option.new("--drive-type MODEL", "The Plus/4's true drive: 1541 or 1551 (default: 1551); implies --true-drive",
88
+ Option.new("--drive-type MODEL", "The Plus/4's true drive: 1541 or 1551 (default: 1551); the PET's and the " \
89
+ "CBM-II's: #{Drives::IEEEModels::NAMES.join(', ')} (default: 2031); " \
90
+ "implies --true-drive",
64
91
  section: "Window options", needs: :window),
65
92
  Option.new("--reu SIZE", "Plug in an REU of SIZE K: 128, 256, 512 (a 1750) or up to 16384",
66
93
  section: "Window options", needs: :window),
67
- Option.new("--model NAME", "C64 to run: #{MODELS.join(', ')} (default: #{MODELS.first}); VIC-20: pal; " \
68
- "C128: #{C128_MODELS.join(', ')}; Plus/4: #{PLUS4_MODELS.join(', ')}; " \
94
+ Option.new("--model NAME", "C64 to run: #{MODELS.join(', ')} (default: #{MODELS.first}); " \
95
+ "VIC-20: #{VIC20_MODELS.join(', ')}; C128: #{C128_MODELS.join(', ')}; " \
96
+ "Plus/4: #{PLUS4_MODELS.join(', ')}; " \
69
97
  "PET: #{PET_MODELS.join(', ')}; CBM-II: #{CBM2_MODELS.join(', ')}",
70
98
  section: "Window options", needs: :window),
71
- Option.new("--ntsc", "Run an NTSC C64, as --model ntsc does", section: "Window options", needs: :window),
72
- Option.new("--c64", "Start the C128 in C64 mode, holding C= at power-on",
99
+ Option.new("--ntsc", "Run an NTSC C64 or VIC-20, as --model ntsc does",
73
100
  section: "Window options", needs: :window),
74
- Option.new("--ram SIZE", "VIC-20 RAM expansion: #{RAM_NAMES.join(', ')} (default: unexpanded); " \
75
- "Plus/4 RAM: 16k, 32k or 64k; PET RAM: 4k, 8k, 16k or 32k (default: the model's own)",
101
+ Option.new("--c64", "Start the C128 in C64 mode, holding C= at power-on",
76
102
  section: "Window options", needs: :window),
77
103
  Option.new("--60hz", "Run a CRTC PET's 60 Hz editor instead of its 50 Hz one, or a CBM-II on 60 Hz mains",
78
104
  section: "Window options", needs: :window),
@@ -90,6 +116,12 @@ module Badline
90
116
  "$9000 and $A000, userport for the user port's PA0-PA2 to switch in " \
91
117
  "the RAM under the ROMs",
92
118
  section: "Window options", needs: :window),
119
+ Option.new("--cpu CPU", "Set the SuperPET's CPU switch: 6502, 6809 or prog, for the system latch to pick " \
120
+ "(default: 6502)",
121
+ section: "Window options", needs: :window),
122
+ Option.new("--bank-ram MODE", "Set the SuperPET's bank RAM switch: rw, read for write-protected, or prog, " \
123
+ "for the system latch to pick (default: rw)",
124
+ section: "Window options", needs: :window),
93
125
  Option.new("--c1lo FILE", "Put a .bin ROM image in the Plus/4's cartridge 1, low slot ($8000)",
94
126
  section: "Window options", needs: :window),
95
127
  Option.new("--c1hi FILE", "Put a .bin ROM image in cartridge 1's high slot ($C000)",
@@ -108,7 +140,7 @@ module Badline
108
140
  section: "Window options", needs: :window),
109
141
  Option.new("--verbose", "Print the display, sound and gamepad setup and the frame timing",
110
142
  section: "Window options", needs: :window),
111
- Option.new("--headless", "Play a .sid tune in the terminal instead of the window",
143
+ Option.new("--headless", "Play a .sid tune, or run the KIM-1's teletype, in the terminal instead of the window",
112
144
  section: "Options without the window"),
113
145
  Option.new("--audio-out FILE", "Render a .sid tune to a .wav or .aiff file",
114
146
  section: "Options without the window"),
@@ -132,7 +164,7 @@ module Badline
132
164
  section: "Testing options", needs: :window),
133
165
  Option.new("--save-snapshot FILE", "Save the machine as a .vsf snapshot after the last frame",
134
166
  section: "Testing options", needs: :window),
135
- Option.new("--vice", "Add VICE's modules to --save-snapshot's C64, PET or CBM-II snapshot",
167
+ Option.new("--vice", "Add VICE's modules to --save-snapshot's C64, VIC-20, PET or CBM-II snapshot",
136
168
  section: "Testing options", needs: :window),
137
169
  Option.new("--at FRAME:EVENT", "Run EVENT once FRAME frames have run (see above)",
138
170
  section: "Testing options", needs: :window),
@@ -52,7 +52,9 @@ module Badline
52
52
  end
53
53
 
54
54
  def drive_type_for(value)
55
- raise Error, "invalid argument: --drive-type #{value}" unless PLUS4_DRIVE_TYPES.include?(value)
55
+ unless (PLUS4_DRIVE_TYPES + Drives::IEEEModels::NAMES).include?(value)
56
+ raise Error, "invalid argument: --drive-type #{value}"
57
+ end
56
58
 
57
59
  value
58
60
  end
@@ -63,6 +65,12 @@ module Badline
63
65
  value
64
66
  end
65
67
 
68
+ def baud_for(value)
69
+ raise Error, "invalid argument: --baud #{value}" unless KIM1_BAUDS.include?(value)
70
+
71
+ value.to_i
72
+ end
73
+
66
74
  def reu_size(value)
67
75
  raise Error, "invalid argument: --reu #{value}" unless REU_SIZES.include?(value)
68
76
 
@@ -83,7 +91,7 @@ module Badline
83
91
 
84
92
  def validate
85
93
  validate_family
86
- raise Error, "--drive-type needs plus4" unless @drive_type.nil? || @family == :plus4
94
+ validate_drive_type
87
95
 
88
96
  validate_mode
89
97
  validate_models
@@ -91,10 +99,20 @@ module Badline
91
99
  validate_paths
92
100
  end
93
101
 
102
+ def validate_drive_type
103
+ return if @drive_type.nil?
104
+
105
+ types = @family == :plus4 ? PLUS4_DRIVE_TYPES : Drives::IEEEModels::NAMES
106
+ return if %i[plus4 pet cbm2].include?(@family) && types.include?(@drive_type)
107
+
108
+ raise Error, "--drive-type needs #{PLUS4_DRIVE_TYPES.include?(@drive_type) ? 'plus4' : 'pet or cbm2'}"
109
+ end
110
+
94
111
  def validate_mode
95
112
  if headless?
96
113
  raise Error, "#{@window_only.first} needs the window" unless @window_only.empty?
97
114
  raise Error, "#{@any_window_only.first} needs the window" unless player_window? || @any_window_only.empty?
115
+ return if @family == :kim1
98
116
  raise Error, "no tune given" if tune_paths.empty? && !player_window?
99
117
 
100
118
  tune_paths.each { |path| validate_tune(path) }
@@ -105,6 +123,7 @@ module Badline
105
123
 
106
124
  def validate_family
107
125
  ram_option
126
+ @family == :kim1 ? validate_kim1 : refuse_kim1_options
108
127
  validate_vic20 if @family == :vic20
109
128
  @family == :plus4 ? validate_plus4 : refuse_plus4_options
110
129
  @family == :pet ? validate_pet : refuse_pet_options
@@ -125,7 +144,8 @@ module Badline
125
144
  when :vic20 then @ram = ram_configuration(@ram_name)
126
145
  when :plus4 then @ram_kb = plus4_ram(@ram_name)
127
146
  when :pet then @ram_kb = pet_ram(@ram_name)
128
- else raise Error, "--ram needs vic20, plus4 or pet"
147
+ when :kim1 then @ram = kim1_ram(@ram_name)
148
+ else raise Error, "--ram needs vic20, plus4, pet or kim1"
129
149
  end
130
150
  end
131
151
 
@@ -137,11 +157,8 @@ module Badline
137
157
  raise Error, "the C128 needs the window" if headless?
138
158
  end
139
159
 
140
- # The VIC-20 is a PAL one, in the window, without the C64's SID and
141
- # REU.
160
+ # The VIC-20 runs in the window, without the C64's SID and REU.
142
161
  def validate_vic20
143
- raise Error, "the NTSC VIC-20 isn't emulated yet" if @models.include?("ntsc")
144
-
145
162
  raise Error, "--sid needs the C64" unless @sid_model.nil?
146
163
  raise Error, "--reu needs the C64" unless @reu.nil?
147
164
  raise Error, "the VIC-20 needs the window" if headless?
@@ -185,6 +202,8 @@ module Badline
185
202
  raise Error, "--editor needs pet" unless @editor.nil?
186
203
  raise Error, "--characters needs pet" unless @characters.nil?
187
204
  raise Error, "--jumpers needs pet" unless @jumpers.empty?
205
+ raise Error, "--cpu needs pet --model superpet" unless @cpu.nil?
206
+ raise Error, "--bank-ram needs pet --model superpet" unless @bank_ram.nil?
188
207
  end
189
208
 
190
209
  # The PET runs in the window, without the C64's SID and REU, at the
@@ -202,7 +221,8 @@ module Badline
202
221
  end
203
222
 
204
223
  # --characters names a character ROM the board takes, --jumpers the
205
- # 8296 board's jumpers, and the 8296 has all of its RAM soldered on.
224
+ # 8296 board's jumpers, and the 8296 has all of its RAM soldered on,
225
+ # as the SuperPET has besides its bank RAM.
206
226
  def validate_pet_board
207
227
  unless @characters.nil? || PET::ROMSets.characters(model).include?(@characters)
208
228
  raise Error, "the #{model} takes no character ROM #{@characters}"
@@ -211,6 +231,22 @@ module Badline
211
231
  unknown = @jumpers.find { |jumper| !PET::ROMSets.jumpers(model).include?(jumper) }
212
232
  raise Error, "the #{model} has no jumper #{unknown}" unless unknown.nil?
213
233
  raise Error, "the 8296 has 32k of RAM" if model == "8296" && ![nil, 32].include?(@ram_kb)
234
+ raise Error, "--ram doesn't fit the superpet" if model == "superpet" && !@ram_kb.nil?
235
+
236
+ validate_cpu_switch
237
+ end
238
+
239
+ # --cpu and --bank-ram set the SuperPET's switches, which no other
240
+ # PET has.
241
+ def validate_cpu_switch
242
+ validate_switch("--cpu", @cpu, PET::SuperPET::Board::CPU_SWITCH)
243
+ validate_switch("--bank-ram", @bank_ram, PET::SuperPET::Board::RAM_SWITCH)
244
+ end
245
+
246
+ def validate_switch(flag, value, positions)
247
+ return if value.nil?
248
+ raise Error, "#{flag} needs pet --model superpet" unless model == "superpet"
249
+ raise Error, "invalid argument: #{flag} #{value}" unless positions.include?(value)
214
250
  end
215
251
 
216
252
  # --basic and --editor name ROMs the model's board takes
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "badline/pet/rom_sets"
4
+ require "badline/drives/ieee_models"
4
5
  require "badline/options/option"
5
6
  require "badline/options/event"
6
7
  require "badline/options/table"
@@ -17,7 +18,7 @@ module Badline
17
18
  # the machine family, and without one the family is the C64, the C128
18
19
  # for a program that loads where C128 BASIC starts, the PET for an
19
20
  # 8050's or 8250's disk or a PET tape, or the CBM-II for a cartridge
20
- # signed as its own.
21
+ # signed as its own. `kim1` runs a MOS KIM-1.
21
22
  # The native build adds --no-sound and --version, and badline-ruby adds
22
23
  # --disable-jit.
23
24
  #
@@ -41,7 +42,7 @@ module Badline
41
42
  SID_MODELS = { "6581" => :mos6581, "8580" => :mos8580 }.freeze
42
43
 
43
44
  # What `sid` leaves out besides the window's options.
44
- NOT_FOR_SID = %w[--audio-out].freeze
45
+ NOT_FOR_SID = %w[--audio-out --tty --baud --tty-load --load-address --start-address --ram].freeze
45
46
 
46
47
  REU_SIZES = %w[128 256 512 1024 2048 4096 8192 16384].freeze
47
48
 
@@ -89,8 +90,17 @@ module Badline
89
90
  # The 8296's board jumpers --jumpers names (PET::Bus::Expansion::JUMPERS).
90
91
  attr_reader :jumpers
91
92
 
93
+ # The SuperPET's CPU switch, as --cpu sets it: "6502", "6809" or
94
+ # "prog".
95
+ def cpu = @cpu || "6502"
96
+
97
+ # The SuperPET's bank RAM switch, as --bank-ram sets it: "rw", "read"
98
+ # or "prog".
99
+ def bank_ram = @bank_ram || "rw"
100
+
92
101
  # The VIC-20's RAM expansion --ram names, a key of
93
- # Vic20::Bus::RAM_CONFIGURATIONS, or nil without --ram.
102
+ # Vic20::Bus::RAM_CONFIGURATIONS, or the KIM-1's, one of
103
+ # KIM1::Bus::RAM_CONFIGURATIONS, or nil without --ram.
94
104
  attr_reader :ram
95
105
 
96
106
  # The Plus/4's or the PET's RAM in K --ram names, one of PLUS4_RAM's or
@@ -138,6 +148,7 @@ module Badline
138
148
  @ram_kb = nil
139
149
  @ram_name = nil
140
150
  initialize_pet
151
+ initialize_kim1
141
152
  @kernal = nil
142
153
  @cartridges = {}
143
154
  @autostart = true
@@ -230,8 +241,9 @@ module Badline
230
241
 
231
242
  def true_drive? = @true_drive || !@drive_type.nil?
232
243
 
233
- # The Plus/4's true drive --drive-type names, "1551" without it.
234
- def drive_type = @drive_type || "1551"
244
+ # The true drive --drive-type names: without it, "1551" on the Plus/4
245
+ # and the 2031 on the PET and the CBM-II.
246
+ def drive_type = @drive_type || (@family == :plus4 ? "1551" : Drives::IEEEModels::DEFAULT)
235
247
 
236
248
  # Whether --save-snapshot adds VICE's modules, so x64sc opens it.
237
249
  def vice? = @vice
@@ -277,7 +289,7 @@ module Badline
277
289
  # A .sid on its own plays in the SID player, as `sid` would, unless an
278
290
  # option of the emulator's window asks for the machine.
279
291
  def play_lone_tune
280
- return if @sid_command || %i[vic20 plus4 pet cbm2].include?(@family) || headless? || !@window_only.empty?
292
+ return if @sid_command || %i[vic20 plus4 pet cbm2 kim1].include?(@family) || headless? || !@window_only.empty?
281
293
  return if @media_path.nil?
282
294
 
283
295
  @sid_command = File.extname(@media_path).casecmp?(".sid")
@@ -337,7 +349,7 @@ module Badline
337
349
  when "--model" then @models << value
338
350
  when "--reu" then @reu = reu_size(value)
339
351
  when "--ram" then @ram_name = value
340
- when "--basic", "--editor", "--characters", "--jumpers" then pet_option(name, value)
352
+ when "--basic", "--editor", "--characters", "--jumpers", "--cpu", "--bank-ram" then pet_option(name, value)
341
353
  when "--drive-type" then @drive_type = drive_type_for(value)
342
354
  when "--kernal" then @kernal = kernal_for(value)
343
355
  when "--c1lo", "--c1hi", "--c2lo", "--c2hi" then @cartridges[CARTRIDGE_SLOTS.fetch(name)] = value
@@ -349,12 +361,16 @@ module Badline
349
361
  when "--seconds" then @seconds = decimal(flag, value)
350
362
  when "--songlengths" then @songlengths = value
351
363
  when "--rate" then @rate = number(flag, value)
364
+ when "--baud", "--load-address", "--start-address" then kim1_option(name, flag, value)
352
365
  else @filter_chunk = number(flag, value)
353
366
  end
354
367
  end
355
368
 
356
- # The PET's frame rate, ROMs and board jumpers, its own until named.
369
+ # The PET's frame rate, ROMs, board jumpers and the SuperPET's CPU and
370
+ # bank RAM switches, its own until named.
357
371
  def initialize_pet
372
+ @cpu = nil
373
+ @bank_ram = nil
358
374
  @refresh_hz = nil
359
375
  @basic = nil
360
376
  @editor = nil
@@ -367,6 +383,8 @@ module Badline
367
383
  when "--basic" then @basic = value
368
384
  when "--editor" then @editor = value
369
385
  when "--characters" then @characters = value
386
+ when "--cpu" then @cpu = value
387
+ when "--bank-ram" then @bank_ram = value
370
388
  else @jumpers = value.split(",")
371
389
  end
372
390
  end
@@ -391,6 +409,7 @@ module Badline
391
409
  when "--headless" then @headless = true
392
410
  when "--quiet" then @quiet = true
393
411
  when "--all-subtunes" then @all_subtunes = true
412
+ when "--tty", "--tty-load" then kim1_switch(name)
394
413
  else @tui = false
395
414
  end
396
415
  end
@@ -8,11 +8,12 @@ module Badline
8
8
  #
9
9
  # $0000-$7FFF - RAM, 4K, 8K, 16K or 32K of it from $0000, then nothing
10
10
  # $8000-$8FFF - screen RAM, repeated (Model), then nothing
11
- # $9000-$AFFF - two empty ROM sockets
11
+ # $9000-$AFFF - two empty ROM sockets, or the SuperPET's bank RAM at
12
+ # $9000
12
13
  # $B000-$DFFF - BASIC 4, or BASIC 1 or 2 from $C000
13
14
  # $E000-$E7FF - the screen editor ROM
14
15
  # $E800-$E8FF - I/O (IO)
15
- # $E900-$EFFF - nothing
16
+ # $E900-$EFFF - nothing, but the SuperPET's I/O page at $EF00
16
17
  # $F000-$FFFF - the KERNAL ROM
17
18
  #
18
19
  # The data lines hold the last byte they carried, so a read from an
@@ -136,6 +137,7 @@ module Badline
136
137
  @user_port = !@expansion.nil? && @expansion.user_port?
137
138
  @debug_register = nil
138
139
  @io_write_handler = nil
140
+ @board = nil
139
141
  map_pages
140
142
  end
141
143
 
@@ -174,6 +176,11 @@ module Badline
174
176
  @write_pages[addr >> 8].poke(addr, value)
175
177
  end
176
178
 
179
+ # #peek and #poke as the SuperPET's 6809 calls them.
180
+ def read(addr) = peek(addr)
181
+
182
+ def write(addr, value) = poke(addr, value)
183
+
177
184
  # Whether the CPU reads the KERNAL ROM at $F000-$FFFF, which an 8096's
178
185
  # board covers while its control register turns it on, and an 8296's
179
186
  # RAM too.
@@ -185,6 +192,12 @@ module Badline
185
192
  map_pages
186
193
  end
187
194
 
195
+ # Lays the SuperPET's board (SuperPET::Board) over its pages.
196
+ def fit_board(board)
197
+ @board = board
198
+ map_pages
199
+ end
200
+
188
201
  # Lays the pages out again, for the board's control register.
189
202
  def map_pages
190
203
  map(@open_bus, 0x00, 0x100)
@@ -195,6 +208,7 @@ module Badline
195
208
  map(@io, 0xe8, 0x01)
196
209
  @read_pages.fill(@kernal_rom, 0xf0, 0x10)
197
210
  @expansion&.map(@read_pages, @write_pages)
211
+ @board&.map(@read_pages, @write_pages)
198
212
  map_debug_register if @debug_register
199
213
  end
200
214
 
@@ -42,8 +42,12 @@ module Badline
42
42
 
43
43
  attr_reader :keyboard
44
44
 
45
+ # Whether the SuperPET's board pulls the diagnostic sense low.
46
+ attr_accessor :diagnostic_low
47
+
45
48
  def initialize(keyboard)
46
49
  @keyboard = keyboard
50
+ @diagnostic_low = false
47
51
  @pia = nil
48
52
  @ieee = nil
49
53
  @cassettes = nil
@@ -60,8 +64,11 @@ module Badline
60
64
 
61
65
  # Port A's other lines: PA4 and PA5 read the cassette sense switches,
62
66
  # PA6 the IEEE bus's EOI, and the diagnostic sense on PA7 floats high
63
- # with nothing on it.
64
- def read_a(_lines) = @ieee.eoi_input & @cassettes.sense_input
67
+ # with nothing on it but the SuperPET's board, which can pull it low.
68
+ def read_a(_lines)
69
+ lines = @ieee.eoi_input & @cassettes.sense_input
70
+ @diagnostic_low ? lines & 0x7f : lines
71
+ end
65
72
 
66
73
  def read_b(lines)
67
74
  row = @pia.port_a_output & 0x0f
@@ -25,7 +25,9 @@ module Badline
25
25
  out.int("cycles", @cycles).bool("vertical_drive", @vertical_drive)
26
26
  pending = @pending_keys
27
27
  out.ints("host.pending_keys", pending) if pending
28
+ save_init_keys(out)
28
29
  out.int("host.init_pending", @cycles <= @init_threshold ? @init_handlers.length : 0)
30
+ save_ieee_drive_fields(out)
29
31
  end
30
32
 
31
33
  def load_machine_fields(input)
@@ -33,7 +35,9 @@ module Badline
33
35
  @vertical_drive = input.bool("vertical_drive", @vertical_drive)
34
36
  pending = input.ints("host.pending_keys", [])
35
37
  @pending_keys = pending.empty? ? nil : pending.dup
38
+ load_init_keys(input)
36
39
  @init_handlers_lost = [input.int("host.init_pending", 0) - @init_handlers.length, 0].max
40
+ load_ieee_drive_fields(input)
37
41
  end
38
42
  end
39
43
 
@@ -17,7 +17,8 @@ module Badline
17
17
  # 1K twice over and the 80-column ones with 2K. The 8296 has 128K of
18
18
  # dynamic RAM, the 32K below $8000, the 32K above it, of which the
19
19
  # screen is the start and the rest lies under the ROMs, and the 64K
20
- # board (Bus::Expansion).
20
+ # board (Bus::Expansion). The SuperPET is an 8032 with the 901640-01
21
+ # character ROM, twice the 8032's size, and its own board (SuperPET).
21
22
  module Model
22
23
  Profile = Data.define(:name, :ram_kb, :basic, :editor_50hz, :editor_60hz, :kernal, :characters, :keyboard,
23
24
  :video, :expansion) do
@@ -28,6 +29,9 @@ module Badline
28
29
  # The 8296, whose board decodes its memory in a PLA.
29
30
  def cbm8296? = name == "8296"
30
31
 
32
+ # The SuperPET, an 8032 with the Waterloo board (SuperPET).
33
+ def superpet? = name == "superpet"
34
+
31
35
  # The screen RAM's bytes, and on the 8296 all 32K of RAM from $8000.
32
36
  def screen_bytes
33
37
  return 0x8000 if cbm8296?
@@ -86,7 +90,12 @@ module Badline
86
90
  kernal: "pet/kernal4.rom", characters: "pet/characters2.rom", keyboard: :business,
87
91
  video: :crtc80, expansion: true)
88
92
 
89
- ALL = [PET2001, PET3032, PET3032B, PET4032, CBM8032, CBM8096, CBM8296].freeze
93
+ SUPERPET = Profile.new(name: "superpet", ram_kb: 32, basic: "pet/basic4.rom",
94
+ editor_50hz: "pet/editor4-80-b-50hz.rom", editor_60hz: "pet/editor4-80-b-60hz.rom",
95
+ kernal: "pet/kernal4.rom", characters: "pet/characters-superpet.rom",
96
+ keyboard: :business, video: :crtc80, expansion: false)
97
+
98
+ ALL = [PET2001, PET3032, PET3032B, PET4032, CBM8032, CBM8096, CBM8296, SUPERPET].freeze
90
99
 
91
100
  DEFAULT = "8032"
92
101
 
@@ -39,6 +39,7 @@ module Badline
39
39
  "4032" => { "4" => %w[4-40-n-50hz 4-40-n-60hz] },
40
40
  "8032" => { "4" => %w[4-80-b-50hz 4-80-b-50hz-0283 4-80-b-60hz] },
41
41
  "8096" => { "4" => %w[4-80-b-50hz 4-80-b-50hz-0283 4-80-b-60hz] },
42
+ "superpet" => { "4" => %w[4-80-b-50hz 4-80-b-50hz-0283 4-80-b-60hz] },
42
43
  "8296" => { "4" => %w[4-80-b-50hz-8296 4-80-b-50hz 4-80-b-50hz-0283 4-80-b-60hz] }
43
44
  }.freeze
44
45