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
@@ -0,0 +1,200 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Snapshot
5
+ module Vice
6
+ module Vic20
7
+ # The VIC-I as xvic 3.10 saves it, VIC-I 0.4. The layout was inferred
8
+ # from xvic's snapshots of known states, set from its monitor and
9
+ # stepped an instruction at a time, against what its monitor's io
10
+ # command and its registers showed:
11
+ #
12
+ # - $00 dword: 1 while the frame is interlaced, $04 dword: the field,
13
+ # 0 the long one and 1 the short one; $08 qword: the clock at the
14
+ # frame's first cycle
15
+ # - $10 byte: the cycle in the line; $11 word: the raster line; $13
16
+ # byte: the text window, 0 before it, 1 on its first line until
17
+ # the column in $9000, 2 on its lines after that and 3 after it;
18
+ # $15 byte: the line's fetches, 0 off the window or before the
19
+ # column in $9000, 1 from there, 2 from the cycle before the first
20
+ # fetch, then 3 with a pattern fetch next and 2 with a code fetch
21
+ # next, 4 once done; $17 word: the line again
22
+ # - $1B dword: the columns; $1F dword: the rows; $23 dword: the
23
+ # columns again; $27 dword: 0 on a line after one of the
24
+ # window's, 1 on the others; $2B dword: the video matrix
25
+ # offset the text row starts at; $33 dword: the text rows done;
26
+ # $37 dword: while the fetches wait, the cycles left until the
27
+ # cycle before the first, then the characters fetched, and the
28
+ # columns while $15 is 0
29
+ # - $3D and $41 dwords: the light pen's latch, $9006 and $9007;
30
+ # $45 dword: 1 in every snapshot xvic wrote; $49: 8 bytes of $FF;
31
+ # $51 byte: the last character code fetched
32
+ # - $52: the colour RAM, 1,024 bytes; $452: the registers, 16
33
+ # bytes, with $9003 bit 7 and $9004 as written; $462 dword: the
34
+ # raster line again
35
+ # - $466 dword: the width of xvic's picture, $46A dword: its lines,
36
+ # 312 on the 6561 and 262 on the 6560; $46E dword: its pitch,
37
+ # then the picture itself, twice its lines and 8 more of pitch
38
+ # bytes, and 4 bytes after it, 0 in every snapshot
39
+ #
40
+ # Bytes the layout leaves out, $14, $16, $19-$1A, $2F-$32 and
41
+ # $3B-$3C, were 0 in every snapshot.
42
+ #
43
+ # Written: all of it from badline's VIC, the picture as zeros. The
44
+ # cycle is badline's column, which is where xvic's monitor puts
45
+ # the cycle at an instruction boundary. Read: the registers, the
46
+ # beam, the frame and field, the text window's counters and the
47
+ # line's fetches, the light pen and the colour RAM; the character
48
+ # line is worked out from the line and $9001, as xvic's monitor
49
+ # works it out. The picture is painted afresh.
50
+ module VICI
51
+ NAME = "VIC-I"
52
+ MAJOR = 0
53
+ MINOR = 4
54
+ HEADER = 0x472
55
+ COLOR_RAM = 0x52
56
+ REGISTERS = 0x452
57
+ # xvic's picture: width, lines and pitch, by model.
58
+ PICTURES = { "pal" => [1648, 312, 1648], "ntsc" => [1536, 262, 1536] }.freeze
59
+ AREA_BEFORE = 0
60
+ AREA_FIRST = 1
61
+ AREA_IN = 2
62
+ AREA_AFTER = 3
63
+ FETCH_WAITING = 1
64
+ FETCH_CODE = 2
65
+ FETCH_PATTERN = 3
66
+ FETCH_DONE = 4
67
+ LIGHT_PEN_FLAG = 1
68
+ FILLER = 0xff
69
+
70
+ module_function
71
+
72
+ def reads?(section) = section.major == MAJOR && section.minor == MINOR && section.data.bytesize >= HEADER
73
+
74
+ # The model whose picture the module's size says, or nil.
75
+ def model(section)
76
+ lines = FieldReader.new(section).skip(0x46a).dword
77
+ PICTURES.find { |_, picture| picture[1] == lines }&.first
78
+ end
79
+
80
+ # The module for `machine` from its BL-VICI and BL-COLORRAM fields.
81
+ def export(machine, vic, color_ram)
82
+ profile = machine.vic.profile
83
+ registers = vic.bytes("registers", "\0".b * 16).bytes
84
+ line = vic.int("raster", 0)
85
+ column = vic.int("column", 0)
86
+ frame_lines = vic.int("frame_lines", profile.lines_per_frame)
87
+ fields = FieldWriter.new
88
+ interlaced = frame_lines != profile.lines_per_frame
89
+ fields.dword(interlaced ? 1 : 0).dword(interlaced && frame_lines != profile.interlaced_lines ? 1 : 0)
90
+ fields.qword(machine.cycles - (line * profile.cycles_per_line) - column)
91
+ window(fields, vic, registers, line, column)
92
+ fields.dword(vic.int("pen.x", 0)).dword(vic.int("pen.y", 0)).dword(LIGHT_PEN_FLAG)
93
+ fields.bytes(Array.new(8, FILLER)).byte(vic.int("code", 0))
94
+ colors = color_ram.bytes("ram", "".b).bytes
95
+ fields.bytes(Array.new(0x400) { |cell| colors.fetch(cell, 0) & 0x0f })
96
+ fields.bytes(registers).dword(line)
97
+ picture(fields, PICTURES.fetch(machine.model))
98
+ fields.section(NAME, MAJOR, MINOR)
99
+ end
100
+
101
+ def window(fields, vic, registers, line, column)
102
+ open = vic.bool("window_open", false)
103
+ done = vic.bool("window_done", false)
104
+ columns = registers[2] & 0x7f
105
+ rows = (registers[3] >> 1) & 0x3f
106
+ first = open && vic.int("text_rows", 0).zero? && vic.int("char_line", 0).zero?
107
+ origin = registers[0] & 0x7f
108
+ area = if open then first && column < origin ? AREA_FIRST : AREA_IN
109
+ else done ? AREA_AFTER : AREA_BEFORE
110
+ end
111
+ state, count = fetches(vic, open && column >= origin, columns, column)
112
+ fields.byte(column).word(line).byte(area).byte(0).byte(state).byte(0).word(line).word(0)
113
+ fields.dword(columns).dword(rows).dword(columns)
114
+ fields.dword(border?(open, first, done, registers, line) ? 1 : 0)
115
+ fields.dword(vic.int("row_start", 0)).dword(0).dword(vic.int("text_rows", 0)).dword(count).word(0)
116
+ end
117
+
118
+ # The line's fetches as xvic counts them, from the column in
119
+ # $9000 on: waiting, with the cycles left until the cycle before
120
+ # the first fetch, then fetching, with the characters fetched.
121
+ # Before that column, and off the window's lines, the count is
122
+ # the columns.
123
+ def fetches(vic, started, columns, column)
124
+ return [0, columns] unless started
125
+
126
+ from = vic.int("fetch_from", 0)
127
+ return [FETCH_WAITING, from - 1 - column] if column < from - 1
128
+ return [FETCH_CODE, 0] if column < from
129
+
130
+ fetched = vic.int("fetched", 0)
131
+ return [FETCH_DONE, columns] if fetched >= columns
132
+
133
+ [(column - from).even? ? FETCH_PATTERN : FETCH_CODE, fetched]
134
+ end
135
+
136
+ # Whether xvic's flag at $27 is set: unless the window was open
137
+ # on the line before.
138
+ def border?(open, first, done, registers, line)
139
+ return first if open
140
+ return true unless done
141
+
142
+ height = registers[3].anybits?(0x01) ? 16 : 8
143
+ line != (registers[1] * 2) + (((registers[3] >> 1) & 0x3f) * height)
144
+ end
145
+
146
+ def picture(fields, (width, lines, pitch))
147
+ fields.dword(width).dword(lines).dword(pitch).zeros((((2 * lines) + 8) * pitch) + 4)
148
+ end
149
+
150
+ # The colour RAM's cells, low nibbles.
151
+ def colors(section) = FieldReader.new(section).skip(COLOR_RAM).bytes(0x400).map { |cell| cell & 0x0f }
152
+
153
+ # BL-VICI's fields for `machine`'s profile, in a keyed module's
154
+ # writer.
155
+ def import(section, out, profile)
156
+ fields = FieldReader.new(section)
157
+ interlaced = fields.dword == 1
158
+ short = fields.dword == 1
159
+ fields.skip(8)
160
+ column = fields.byte
161
+ line = fields.word
162
+ area = fields.byte
163
+ fields.skip(1)
164
+ state = fields.byte
165
+ fields.skip(5 + 16)
166
+ row_start = fields.dword
167
+ fields.skip(4)
168
+ text_rows = fields.dword
169
+ count = fields.dword
170
+ fields.skip(2)
171
+ pen_x = fields.dword
172
+ pen_y = fields.dword
173
+ fields.skip(4 + 8)
174
+ code = fields.byte
175
+ registers = FieldReader.new(section).skip(REGISTERS).bytes(16)
176
+ out.bytes("registers", registers).int("raster", line).int("column", column)
177
+ frame_lines = if interlaced then short ? profile.interlaced_lines - 1 : profile.interlaced_lines
178
+ else profile.lines_per_frame
179
+ end
180
+ out.int("frame_lines", frame_lines).bool("long_field", !interlaced || short)
181
+ open = [AREA_FIRST, AREA_IN].include?(area)
182
+ out.bool("window_open", open).bool("window_done", area == AREA_AFTER)
183
+ fetching = open && state != FETCH_WAITING && state != 0
184
+ out.int("row_start", row_start).int("matrix", row_start + (fetching ? count : 0))
185
+ out.int("char_line", open ? char_line(registers, line) : 0).int("text_rows", text_rows)
186
+ out.int("fetch_from", open ? (registers[0] & 0x7f) + Chips::VICI::FETCH_DELAY : 0)
187
+ out.int("fetched", fetching ? count : 0).int("code", code)
188
+ out.int("pen.x", pen_x & 0xff).int("pen.y", pen_y & 0xff)
189
+ end
190
+
191
+ # The line of the character row the window is on.
192
+ def char_line(registers, line)
193
+ height = registers[3].anybits?(0x01) ? 16 : 8
194
+ (line - (registers[1] * 2)) % height
195
+ end
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end
@@ -14,6 +14,7 @@ require "badline/snapshot/vice/vicii"
14
14
  require "badline/snapshot/vice/vicii_import"
15
15
  require "badline/snapshot/vice/restore"
16
16
  require "badline/snapshot/vice/pet"
17
+ require "badline/snapshot/vice/vic20"
17
18
  require "badline/snapshot/vice/cbm2"
18
19
  require "badline/snapshot/vice/p500"
19
20
  require "badline/snapshot/vice/p500_restore"
@@ -25,8 +25,8 @@ module Badline
25
25
  path
26
26
  end
27
27
 
28
- # Saves the machine's snapshot with VICE's modules ahead of its own for
29
- # a C64, so x64sc opens it too.
28
+ # Saves the machine's snapshot with VICE's modules ahead of its own, so
29
+ # x64sc, xvic, xpet, xcbm2 or xcbm5x0 opens it too (Image.exported).
30
30
  def export(computer, path)
31
31
  File.binwrite(path, Image.exported(computer).to_s)
32
32
  path
@@ -56,8 +56,8 @@ module Badline
56
56
  module Files
57
57
  def save_snapshot(path) = Snapshot.save(self, path)
58
58
 
59
- # Saves the snapshot with VICE's modules too, for a C64, so x64sc
60
- # opens it as well as badline.
59
+ # Saves the snapshot with VICE's modules too, so VICE's emulator for
60
+ # the machine opens it as well as badline (Image.exported).
61
61
  def export_snapshot(path) = Snapshot.export(self, path)
62
62
 
63
63
  def restore_snapshot(path, &) = Snapshot.restore(self, path, &)
@@ -100,6 +100,10 @@ module Badline
100
100
  include Snapshot::Files
101
101
  end
102
102
 
103
+ class KIM1
104
+ include Snapshot::Files
105
+ end
106
+
103
107
  class CBM2
104
108
  include Snapshot::Files
105
109
 
@@ -36,7 +36,7 @@ module Badline
36
36
  @value = enabled && enabled != 0 ? @value | 0x01 : @value & ~0x01
37
37
  end
38
38
 
39
- def carry? = @value & 0x01 != 0
39
+ def carry? = @value.anybits?(0x01)
40
40
 
41
41
  def carry = @value.nobits?(0x01) ? 0 : 1
42
42
 
@@ -44,7 +44,7 @@ module Badline
44
44
  @value = enabled && enabled != 0 ? @value | 0x02 : @value & ~0x02
45
45
  end
46
46
 
47
- def zero? = @value & 0x02 != 0
47
+ def zero? = @value.anybits?(0x02)
48
48
 
49
49
  def zero = @value.nobits?(0x02) ? 0 : 1
50
50
 
@@ -52,7 +52,7 @@ module Badline
52
52
  @value = enabled && enabled != 0 ? @value | 0x04 : @value & ~0x04
53
53
  end
54
54
 
55
- def interrupt? = @value & 0x04 != 0
55
+ def interrupt? = @value.anybits?(0x04)
56
56
 
57
57
  def interrupt = @value.nobits?(0x04) ? 0 : 1
58
58
 
@@ -60,7 +60,7 @@ module Badline
60
60
  @value = enabled && enabled != 0 ? @value | 0x08 : @value & ~0x08
61
61
  end
62
62
 
63
- def decimal? = @value & 0x08 != 0
63
+ def decimal? = @value.anybits?(0x08)
64
64
 
65
65
  def decimal = @value.nobits?(0x08) ? 0 : 1
66
66
 
@@ -68,7 +68,7 @@ module Badline
68
68
  @value = enabled && enabled != 0 ? @value | 0x10 : @value & ~0x10
69
69
  end
70
70
 
71
- def break? = @value & 0x10 != 0
71
+ def break? = @value.anybits?(0x10)
72
72
 
73
73
  def break = @value.nobits?(0x10) ? 0 : 1
74
74
 
@@ -76,7 +76,7 @@ module Badline
76
76
  @value = enabled && enabled != 0 ? @value | 0x40 : @value & ~0x40
77
77
  end
78
78
 
79
- def overflow? = @value & 0x40 != 0
79
+ def overflow? = @value.anybits?(0x40)
80
80
 
81
81
  def overflow = @value.nobits?(0x40) ? 0 : 1
82
82
 
@@ -84,7 +84,7 @@ module Badline
84
84
  @value = enabled && enabled != 0 ? @value | 0x80 : @value & ~0x80
85
85
  end
86
86
 
87
- def negative? = @value & 0x80 != 0
87
+ def negative? = @value.anybits?(0x80)
88
88
 
89
89
  def negative = @value.nobits?(0x80) ? 0 : 1
90
90
  end
@@ -95,7 +95,7 @@ module Badline
95
95
  @value = enabled && enabled != 0 ? @value | 0x01 : @value & ~0x01
96
96
  end
97
97
 
98
- def basic? = @value & 0x01 != 0
98
+ def basic? = @value.anybits?(0x01)
99
99
 
100
100
  def basic = @value.nobits?(0x01) ? 0 : 1
101
101
 
@@ -103,7 +103,7 @@ module Badline
103
103
  @value = enabled && enabled != 0 ? @value | 0x02 : @value & ~0x02
104
104
  end
105
105
 
106
- def kernal? = @value & 0x02 != 0
106
+ def kernal? = @value.anybits?(0x02)
107
107
 
108
108
  def kernal = @value.nobits?(0x02) ? 0 : 1
109
109
 
@@ -111,7 +111,7 @@ module Badline
111
111
  @value = enabled && enabled != 0 ? @value | 0x04 : @value & ~0x04
112
112
  end
113
113
 
114
- def io? = @value & 0x04 != 0
114
+ def io? = @value.anybits?(0x04)
115
115
 
116
116
  def io = @value.nobits?(0x04) ? 0 : 1
117
117
 
@@ -119,7 +119,7 @@ module Badline
119
119
  @value = enabled && enabled != 0 ? @value | 0x08 : @value & ~0x08
120
120
  end
121
121
 
122
- def tape_out? = @value & 0x08 != 0
122
+ def tape_out? = @value.anybits?(0x08)
123
123
 
124
124
  def tape_out = @value.nobits?(0x08) ? 0 : 1
125
125
 
@@ -127,7 +127,7 @@ module Badline
127
127
  @value = enabled && enabled != 0 ? @value | 0x10 : @value & ~0x10
128
128
  end
129
129
 
130
- def tape_switch? = @value & 0x10 != 0
130
+ def tape_switch? = @value.anybits?(0x10)
131
131
 
132
132
  def tape_switch = @value.nobits?(0x10) ? 0 : 1
133
133
 
@@ -135,7 +135,7 @@ module Badline
135
135
  @value = enabled && enabled != 0 ? @value | 0x20 : @value & ~0x20
136
136
  end
137
137
 
138
- def tape_motor? = @value & 0x20 != 0
138
+ def tape_motor? = @value.anybits?(0x20)
139
139
 
140
140
  def tape_motor = @value.nobits?(0x20) ? 0 : 1
141
141
  end
@@ -146,7 +146,7 @@ module Badline
146
146
  @value = enabled && enabled != 0 ? @value | 0x01 : @value & ~0x01
147
147
  end
148
148
 
149
- def start? = @value & 0x01 != 0
149
+ def start? = @value.anybits?(0x01)
150
150
 
151
151
  def start = @value.nobits?(0x01) ? 0 : 1
152
152
 
@@ -154,7 +154,7 @@ module Badline
154
154
  @value = enabled && enabled != 0 ? @value | 0x02 : @value & ~0x02
155
155
  end
156
156
 
157
- def output? = @value & 0x02 != 0
157
+ def output? = @value.anybits?(0x02)
158
158
 
159
159
  def output = @value.nobits?(0x02) ? 0 : 1
160
160
 
@@ -162,7 +162,7 @@ module Badline
162
162
  @value = enabled && enabled != 0 ? @value | 0x04 : @value & ~0x04
163
163
  end
164
164
 
165
- def out_mode? = @value & 0x04 != 0
165
+ def out_mode? = @value.anybits?(0x04)
166
166
 
167
167
  def out_mode = @value.nobits?(0x04) ? 0 : 1
168
168
 
@@ -170,7 +170,7 @@ module Badline
170
170
  @value = enabled && enabled != 0 ? @value | 0x08 : @value & ~0x08
171
171
  end
172
172
 
173
- def run_mode? = @value & 0x08 != 0
173
+ def run_mode? = @value.anybits?(0x08)
174
174
 
175
175
  def run_mode = @value.nobits?(0x08) ? 0 : 1
176
176
 
@@ -178,7 +178,7 @@ module Badline
178
178
  @value = enabled && enabled != 0 ? @value | 0x10 : @value & ~0x10
179
179
  end
180
180
 
181
- def load? = @value & 0x10 != 0
181
+ def load? = @value.anybits?(0x10)
182
182
 
183
183
  def load = @value.nobits?(0x10) ? 0 : 1
184
184
 
@@ -186,7 +186,7 @@ module Badline
186
186
  @value = enabled && enabled != 0 ? @value | 0x20 : @value & ~0x20
187
187
  end
188
188
 
189
- def in_mode? = @value & 0x20 != 0
189
+ def in_mode? = @value.anybits?(0x20)
190
190
 
191
191
  def in_mode = @value.nobits?(0x20) ? 0 : 1
192
192
 
@@ -194,7 +194,7 @@ module Badline
194
194
  @value = enabled && enabled != 0 ? @value | 0x40 : @value & ~0x40
195
195
  end
196
196
 
197
- def serial_mode? = @value & 0x40 != 0
197
+ def serial_mode? = @value.anybits?(0x40)
198
198
 
199
199
  def serial_mode = @value.nobits?(0x40) ? 0 : 1
200
200
 
@@ -202,7 +202,7 @@ module Badline
202
202
  @value = enabled && enabled != 0 ? @value | 0x80 : @value & ~0x80
203
203
  end
204
204
 
205
- def clock_frequency? = @value & 0x80 != 0
205
+ def clock_frequency? = @value.anybits?(0x80)
206
206
 
207
207
  def clock_frequency = @value.nobits?(0x80) ? 0 : 1
208
208
 
@@ -210,7 +210,7 @@ module Badline
210
210
  @value = enabled && enabled != 0 ? @value | 0x20 : @value & ~0x20
211
211
  end
212
212
 
213
- def in_cnt? = @value & 0x20 != 0
213
+ def in_cnt? = @value.anybits?(0x20)
214
214
 
215
215
  def in_cnt = @value.nobits?(0x20) ? 0 : 1
216
216
 
@@ -218,7 +218,7 @@ module Badline
218
218
  @value = enabled && enabled != 0 ? @value | 0x40 : @value & ~0x40
219
219
  end
220
220
 
221
- def in_timer_a? = @value & 0x40 != 0
221
+ def in_timer_a? = @value.anybits?(0x40)
222
222
 
223
223
  def in_timer_a = @value.nobits?(0x40) ? 0 : 1
224
224
 
@@ -226,7 +226,7 @@ module Badline
226
226
  @value = enabled && enabled != 0 ? @value | 0x80 : @value & ~0x80
227
227
  end
228
228
 
229
- def alarm? = @value & 0x80 != 0
229
+ def alarm? = @value.anybits?(0x80)
230
230
 
231
231
  def alarm = @value.nobits?(0x80) ? 0 : 1
232
232
  end
@@ -237,7 +237,7 @@ module Badline
237
237
  @value = enabled && enabled != 0 ? @value | 0x01 : @value & ~0x01
238
238
  end
239
239
 
240
- def timer_a? = @value & 0x01 != 0
240
+ def timer_a? = @value.anybits?(0x01)
241
241
 
242
242
  def timer_a = @value.nobits?(0x01) ? 0 : 1
243
243
 
@@ -245,7 +245,7 @@ module Badline
245
245
  @value = enabled && enabled != 0 ? @value | 0x02 : @value & ~0x02
246
246
  end
247
247
 
248
- def timer_b? = @value & 0x02 != 0
248
+ def timer_b? = @value.anybits?(0x02)
249
249
 
250
250
  def timer_b = @value.nobits?(0x02) ? 0 : 1
251
251
 
@@ -253,7 +253,7 @@ module Badline
253
253
  @value = enabled && enabled != 0 ? @value | 0x04 : @value & ~0x04
254
254
  end
255
255
 
256
- def alarm? = @value & 0x04 != 0
256
+ def alarm? = @value.anybits?(0x04)
257
257
 
258
258
  def alarm = @value.nobits?(0x04) ? 0 : 1
259
259
 
@@ -261,7 +261,7 @@ module Badline
261
261
  @value = enabled && enabled != 0 ? @value | 0x08 : @value & ~0x08
262
262
  end
263
263
 
264
- def serial? = @value & 0x08 != 0
264
+ def serial? = @value.anybits?(0x08)
265
265
 
266
266
  def serial = @value.nobits?(0x08) ? 0 : 1
267
267
 
@@ -269,7 +269,7 @@ module Badline
269
269
  @value = enabled && enabled != 0 ? @value | 0x10 : @value & ~0x10
270
270
  end
271
271
 
272
- def flag? = @value & 0x10 != 0
272
+ def flag? = @value.anybits?(0x10)
273
273
 
274
274
  def flag = @value.nobits?(0x10) ? 0 : 1
275
275
 
@@ -277,7 +277,7 @@ module Badline
277
277
  @value = enabled && enabled != 0 ? @value | 0x80 : @value & ~0x80
278
278
  end
279
279
 
280
- def interrupt? = @value & 0x80 != 0
280
+ def interrupt? = @value.anybits?(0x80)
281
281
 
282
282
  def interrupt = @value.nobits?(0x80) ? 0 : 1
283
283
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Storage
5
+ # A 2040's disk, as DOS 1 formats it: the 1541's 35 tracks and speed
6
+ # zones, with 20 sectors on tracks 18 to 24 in place of 19, 690 blocks
7
+ # in all. The BAM and the directory are where a 1541's are, on 18/0
8
+ # and 18/1, but the BAM's format byte is $01 and the header has no DOS
9
+ # type after the ID, as c1541 formats a .d67.
10
+ class D67Image < DiskImage
11
+ ERROR_TABLES = { 177_330 => 690 }.freeze
12
+
13
+ # The sectors a track holds in each of the 1541's speed zones, by its
14
+ # number, from zone 0, the innermost.
15
+ ZONE_SECTORS = [17, 18, 20, 21].freeze
16
+
17
+ # The tracks the image holds.
18
+ def track_count = 35
19
+
20
+ def sides = 1
21
+
22
+ def sectors_in(track) = ZONE_SECTORS[D64Image.zone(track)]
23
+
24
+ private
25
+
26
+ def error_tables = ERROR_TABLES
27
+
28
+ def header_name = 0x90
29
+ def directory_track = 18
30
+ def directory_sector = 1
31
+ def directory_interleave = 3
32
+ def interleave = 10
33
+ def reserved_tracks = [18]
34
+
35
+ def bam_tracks = 1..35
36
+ def bam_count(track) = [18, 0, 4 * track]
37
+ def bam_bitmap(track) = [18, 0, (4 * track) + 1]
38
+ def bitmap_size = 3
39
+
40
+ def header_link = [18, 1]
41
+ def dos_type = " "
42
+ def header_tail = 5
43
+ def bam_headers(_id) = []
44
+
45
+ # The link to the directory, the format byte $01, and after the name
46
+ # the ID and two spaces.
47
+ def write_header(name, id)
48
+ write_at(*header_block, 0, [*header_link, 0x01, 0])
49
+ write_at(*header_block, header_name,
50
+ encode_name(name) + [NAME_PADDING, NAME_PADDING] + id + dos_type.bytes +
51
+ Array.new(header_tail, NAME_PADDING))
52
+ end
53
+ end
54
+ end
55
+ end