badline 0.13.0 → 0.14.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 (254) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +49 -1
  3. data/CLAUDE.md +27 -7
  4. data/CONTRIBUTING.md +4 -3
  5. data/README.md +8 -5
  6. data/doc/media.md +2 -1
  7. data/doc/pinned-behaviour.md +29 -0
  8. data/doc/snapshot-format.md +1047 -0
  9. data/doc/snapshots.md +72 -39
  10. data/lib/badline/audio/bare_player.rb +50 -17
  11. data/lib/badline/audio/machine_player.rb +15 -9
  12. data/lib/badline/audio/renderer.rb +32 -21
  13. data/lib/badline/c128/banks.rb +6 -3
  14. data/lib/badline/c128/bus/keyed_state.rb +45 -0
  15. data/lib/badline/c128/bus.rb +17 -3
  16. data/lib/badline/c128/drives.rb +6 -25
  17. data/lib/badline/c128/keyed_modules.rb +117 -0
  18. data/lib/badline/c128/keyed_state.rb +91 -0
  19. data/lib/badline/c128/keys.rb +9 -0
  20. data/lib/badline/c128/mmu.rb +9 -8
  21. data/lib/badline/c128/mmu_pages.rb +20 -0
  22. data/lib/badline/c128/modes.rb +19 -9
  23. data/lib/badline/c128/z80_turns.rb +1 -1
  24. data/lib/badline/c128.rb +8 -8
  25. data/lib/badline/c64/attachments.rb +0 -44
  26. data/lib/badline/c64/banked_ram/plus256k.rb +18 -10
  27. data/lib/badline/c64/banked_ram/plus60k.rb +8 -6
  28. data/lib/badline/c64/banked_ram/unexpanded.rb +2 -2
  29. data/lib/badline/c64/bus/debug_register.rb +32 -0
  30. data/lib/badline/c64/bus/keyed_state.rb +41 -0
  31. data/lib/badline/c64/bus.rb +2 -1
  32. data/lib/badline/c64/cartridge/action_replay.rb +0 -13
  33. data/lib/badline/c64/cartridge/easy_flash.rb +0 -15
  34. data/lib/badline/c64/cartridge/epyx_fastload.rb +0 -8
  35. data/lib/badline/c64/cartridge/final_cartridge3.rb +0 -12
  36. data/lib/badline/c64/cartridge/flash.rb +3 -3
  37. data/lib/badline/c64/cartridge/g_mod2.rb +0 -12
  38. data/lib/badline/c64/cartridge/geo_ram.rb +0 -16
  39. data/lib/badline/c64/cartridge/kcs_power.rb +0 -8
  40. data/lib/badline/c64/cartridge/keyed_state.rb +393 -0
  41. data/lib/badline/c64/cartridge/pagefox.rb +0 -10
  42. data/lib/badline/c64/cartridge/retro_replay.rb +0 -8
  43. data/lib/badline/c64/cartridge/rgcd.rb +0 -10
  44. data/lib/badline/c64/cartridge/super_games.rb +0 -10
  45. data/lib/badline/c64/cartridge/zaxxon.rb +0 -16
  46. data/lib/badline/c64/cartridge.rb +1 -27
  47. data/lib/badline/c64/kernal_traps.rb +28 -25
  48. data/lib/badline/c64/keyed_modules.rb +111 -0
  49. data/lib/badline/c64/keyed_state.rb +68 -0
  50. data/lib/badline/c64/reu/dma.rb +0 -4
  51. data/lib/badline/c64/reu/keyed_state.rb +140 -0
  52. data/lib/badline/c64/reu/ram.rb +0 -15
  53. data/lib/badline/c64/reu.rb +1 -3
  54. data/lib/badline/c64/true_drives.rb +56 -5
  55. data/lib/badline/c64.rb +7 -3
  56. data/lib/badline/chips/cia/interrupt_register.rb +0 -17
  57. data/lib/badline/chips/cia/keyed_parts.rb +213 -0
  58. data/lib/badline/chips/cia/serial.rb +0 -4
  59. data/lib/badline/chips/cia/time_of_day.rb +0 -22
  60. data/lib/badline/chips/cia/timer.rb +0 -20
  61. data/lib/badline/chips/cia.rb +2 -2
  62. data/lib/badline/chips/cpu/core.rb +18 -2
  63. data/lib/badline/chips/cpu/keyed_state.rb +177 -0
  64. data/lib/badline/chips/cpu/microcode.rb +16 -0
  65. data/lib/badline/chips/cpu/port.rb +20 -3
  66. data/lib/badline/chips/cpu.rb +5 -0
  67. data/lib/badline/chips/sid/decimator.rb +10 -8
  68. data/lib/badline/chips/sid/envelope.rb +1 -6
  69. data/lib/badline/chips/sid/filter.rb +0 -14
  70. data/lib/badline/chips/sid/keyed_parts.rb +286 -0
  71. data/lib/badline/chips/sid/voice.rb +0 -10
  72. data/lib/badline/chips/sid/waveform.rb +0 -2
  73. data/lib/badline/chips/sid.rb +1 -2
  74. data/lib/badline/chips/ted/beam.rb +119 -0
  75. data/lib/badline/chips/ted/timers.rb +66 -0
  76. data/lib/badline/chips/ted.rb +143 -0
  77. data/lib/badline/chips/tia.rb +49 -0
  78. data/lib/badline/chips/vdc/keyed_parts.rb +105 -0
  79. data/lib/badline/chips/vdc/painter.rb +0 -12
  80. data/lib/badline/chips/vdc/raster.rb +0 -16
  81. data/lib/badline/chips/vdc/window.rb +0 -9
  82. data/lib/badline/chips/vdc.rb +1 -2
  83. data/lib/badline/chips/via/control_lines.rb +0 -15
  84. data/lib/badline/chips/via/interrupt_register.rb +0 -9
  85. data/lib/badline/chips/via/keyed_parts.rb +163 -0
  86. data/lib/badline/chips/via/shift_register.rb +0 -14
  87. data/lib/badline/chips/via/timer1.rb +0 -13
  88. data/lib/badline/chips/via/timer2.rb +0 -18
  89. data/lib/badline/chips/via.rb +1 -2
  90. data/lib/badline/chips/vic/border_mask.rb +0 -10
  91. data/lib/badline/chips/vic/collisions.rb +0 -11
  92. data/lib/badline/chips/vic/color_patches.rb +0 -11
  93. data/lib/badline/chips/vic/display_state.rb +0 -19
  94. data/lib/badline/chips/vic/graphics_shifter.rb +0 -4
  95. data/lib/badline/chips/vic/keyed_parts.rb +228 -0
  96. data/lib/badline/chips/vic/keyed_sprites.rb +225 -0
  97. data/lib/badline/chips/vic/keyed_state.rb +102 -0
  98. data/lib/badline/chips/vic/register_log.rb +0 -18
  99. data/lib/badline/chips/vic/registers.rb +0 -9
  100. data/lib/badline/chips/vic/sequencer.rb +0 -2
  101. data/lib/badline/chips/vic/sprite/internal_bus.rb +0 -11
  102. data/lib/badline/chips/vic/sprite.rb +0 -2
  103. data/lib/badline/chips/vic/sprites.rb +0 -3
  104. data/lib/badline/chips/vic.rb +6 -2
  105. data/lib/badline/chips/vic_i/keyed_parts.rb +142 -0
  106. data/lib/badline/chips/vic_i/painter.rb +0 -4
  107. data/lib/badline/chips/vic_i/sound.rb +38 -46
  108. data/lib/badline/chips/vic_i.rb +2 -2
  109. data/lib/badline/chips/z80/core.rb +2 -2
  110. data/lib/badline/chips/z80/keyed_state.rb +73 -0
  111. data/lib/badline/chips.rb +10 -0
  112. data/lib/badline/core.rb +4 -21
  113. data/lib/badline/drives/datasette/keyed_state.rb +38 -0
  114. data/lib/badline/drives/datasette.rb +40 -7
  115. data/lib/badline/drives/engine/core.rb +3 -0
  116. data/lib/badline/drives/engine/serial_lines.rb +4 -7
  117. data/lib/badline/drives/model1541/bus.rb +0 -13
  118. data/lib/badline/drives/model1541/disk.rb +9 -8
  119. data/lib/badline/drives/model1541/keyed_state.rb +251 -0
  120. data/lib/badline/drives/model1541/mechanism.rb +0 -2
  121. data/lib/badline/drives/model1541.rb +1 -2
  122. data/lib/badline/drives/model1571/bus.rb +0 -13
  123. data/lib/badline/drives/model1571/keyed_state.rb +108 -0
  124. data/lib/badline/drives/model1571/wd1770.rb +0 -14
  125. data/lib/badline/drives/model1571.rb +1 -2
  126. data/lib/badline/drives/model1581/bus.rb +0 -13
  127. data/lib/badline/drives/model1581/disk.rb +0 -4
  128. data/lib/badline/drives/model1581/keyed_state.rb +280 -0
  129. data/lib/badline/drives/model1581/mechanism.rb +0 -21
  130. data/lib/badline/drives/model1581/slot.rb +0 -18
  131. data/lib/badline/drives/model1581/wd1772.rb +0 -2
  132. data/lib/badline/drives/model1581.rb +2 -2
  133. data/lib/badline/drives.rb +8 -0
  134. data/lib/badline/frontend/app.rb +3 -3
  135. data/lib/badline/frontend/boot.rb +1 -1
  136. data/lib/badline/frontend/controls.rb +19 -3
  137. data/lib/badline/frontend/drive_led.rb +44 -21
  138. data/lib/badline/frontend/menu/menu_dialogs.rb +2 -2
  139. data/lib/badline/frontend/snapshots.rb +12 -1
  140. data/lib/badline/frontend/timeline.rb +28 -10
  141. data/lib/badline/input/matrix_typist.rb +98 -0
  142. data/lib/badline/input.rb +1 -0
  143. data/lib/badline/kernal_trap/chrout.rb +45 -0
  144. data/lib/badline/kernal_trap/dos/channel.rb +0 -27
  145. data/lib/badline/kernal_trap/dos/channels.rb +0 -25
  146. data/lib/badline/kernal_trap/dos/memory.rb +0 -9
  147. data/lib/badline/kernal_trap/dos/status.rb +0 -8
  148. data/lib/badline/kernal_trap/dos/write_file.rb +0 -18
  149. data/lib/badline/kernal_trap/dos.rb +0 -19
  150. data/lib/badline/kernal_trap/file_routine.rb +4 -4
  151. data/lib/badline/kernal_trap/keyed_state.rb +150 -0
  152. data/lib/badline/kernal_trap/layout.rb +75 -11
  153. data/lib/badline/kernal_trap/load.rb +14 -16
  154. data/lib/badline/kernal_trap/routine.rb +12 -0
  155. data/lib/badline/kernal_trap/save.rb +8 -18
  156. data/lib/badline/kernal_trap/serial.rb +1 -17
  157. data/lib/badline/kernal_trap.rb +2 -0
  158. data/lib/badline/machine/keyboard_buffer.rb +49 -0
  159. data/lib/badline/machine/settling.rb +29 -0
  160. data/lib/badline/machine.rb +5 -2
  161. data/lib/badline/media/boot_disk.rb +14 -2
  162. data/lib/badline/media/extensions.rb +10 -0
  163. data/lib/badline/memory.rb +3 -6
  164. data/lib/badline/options/family.rb +5 -2
  165. data/lib/badline/options/help.rb +42 -16
  166. data/lib/badline/options/table.rb +2 -0
  167. data/lib/badline/options/validation.rb +2 -0
  168. data/lib/badline/options.rb +6 -1
  169. data/lib/badline/plus4/acia.rb +45 -0
  170. data/lib/badline/plus4/bus.rb +312 -0
  171. data/lib/badline/plus4/cpu.rb +10 -0
  172. data/lib/badline/plus4/cpu_port.rb +93 -0
  173. data/lib/badline/plus4/keyboard_port.rb +51 -0
  174. data/lib/badline/plus4/model.rb +38 -0
  175. data/lib/badline/plus4/user_port.rb +31 -0
  176. data/lib/badline/plus4.rb +164 -0
  177. data/lib/badline/roms/README +38 -0
  178. data/lib/badline/roms/plus4/basic.rom +0 -0
  179. data/lib/badline/roms/plus4/function-high.rom +0 -0
  180. data/lib/badline/roms/plus4/function-low.rom +0 -0
  181. data/lib/badline/roms/plus4/kernal-ntsc.rom +0 -0
  182. data/lib/badline/roms/plus4/kernal-pal.rom +0 -0
  183. data/lib/badline/snapshot/c128_setup.rb +9 -20
  184. data/lib/badline/snapshot/c64_setup.rb +28 -24
  185. data/lib/badline/snapshot/container.rb +4 -0
  186. data/lib/badline/snapshot/field_doc/markdown.rb +112 -0
  187. data/lib/badline/snapshot/field_doc.rb +109 -0
  188. data/lib/badline/snapshot/image.rb +134 -28
  189. data/lib/badline/snapshot/keyed/cursor.rb +40 -0
  190. data/lib/badline/snapshot/keyed/modules.rb +66 -0
  191. data/lib/badline/snapshot/keyed/reader.rb +188 -0
  192. data/lib/badline/snapshot/keyed/recorder.rb +88 -0
  193. data/lib/badline/snapshot/keyed/report.rb +26 -0
  194. data/lib/badline/snapshot/keyed/writer.rb +55 -0
  195. data/lib/badline/snapshot/keyed.rb +64 -0
  196. data/lib/badline/snapshot/machine_state.rb +17 -64
  197. data/lib/badline/snapshot/storage_setup.rb +29 -34
  198. data/lib/badline/snapshot/vic20_setup.rb +6 -15
  199. data/lib/badline/snapshot/vice/reu1764.rb +2 -2
  200. data/lib/badline/snapshot/vice.rb +7 -31
  201. data/lib/badline/snapshot.rb +43 -20
  202. data/lib/badline/storage/crt_file.rb +3 -1
  203. data/lib/badline/storage/g64_image.rb +8 -3
  204. data/lib/badline/storage/tap.rb +43 -15
  205. data/lib/badline/version.rb +1 -1
  206. data/lib/badline/vic20/attachments.rb +3 -0
  207. data/lib/badline/vic20/bus/keyed_state.rb +52 -0
  208. data/lib/badline/vic20/bus.rb +1 -2
  209. data/lib/badline/vic20/keyed_modules.rb +73 -0
  210. data/lib/badline/vic20/keyed_state.rb +45 -0
  211. data/lib/badline/vic20.rb +5 -5
  212. data/lib/badline.rb +1 -0
  213. metadata +61 -42
  214. data/lib/badline/c128/bus/saved_state.rb +0 -53
  215. data/lib/badline/c128/saved_state.rb +0 -117
  216. data/lib/badline/c64/bus/saved_state.rb +0 -68
  217. data/lib/badline/c64/cartridge/flash/saved_state.rb +0 -40
  218. data/lib/badline/c64/cartridge/retro_replay/saved_state.rb +0 -47
  219. data/lib/badline/c64/cartridge/saved_state.rb +0 -63
  220. data/lib/badline/c64/reu/dma/saved_state.rb +0 -52
  221. data/lib/badline/c64/reu/saved_state.rb +0 -55
  222. data/lib/badline/c64/saved_state.rb +0 -112
  223. data/lib/badline/chips/cia/saved_state.rb +0 -49
  224. data/lib/badline/chips/cia/serial/saved_state.rb +0 -45
  225. data/lib/badline/chips/cpu/saved_state.rb +0 -117
  226. data/lib/badline/chips/sid/envelope/saved_state.rb +0 -70
  227. data/lib/badline/chips/sid/filter/saved_state.rb +0 -42
  228. data/lib/badline/chips/sid/saved_state.rb +0 -52
  229. data/lib/badline/chips/sid/waveform/saved_state.rb +0 -68
  230. data/lib/badline/chips/vdc/saved_state.rb +0 -36
  231. data/lib/badline/chips/via/saved_state.rb +0 -44
  232. data/lib/badline/chips/vic/graphics_shifter/saved_state.rb +0 -40
  233. data/lib/badline/chips/vic/saved_state.rb +0 -82
  234. data/lib/badline/chips/vic/sequencer/saved_state.rb +0 -91
  235. data/lib/badline/chips/vic/sprite/saved_state.rb +0 -66
  236. data/lib/badline/chips/vic/sprites/saved_state.rb +0 -59
  237. data/lib/badline/chips/vic_i/painter/saved_state.rb +0 -40
  238. data/lib/badline/chips/vic_i/saved_state.rb +0 -55
  239. data/lib/badline/chips/z80/saved_state.rb +0 -71
  240. data/lib/badline/chrout_trap.rb +0 -43
  241. data/lib/badline/debug_register.rb +0 -28
  242. data/lib/badline/drives/datasette/saved_state.rb +0 -37
  243. data/lib/badline/drives/model1541/disk/saved_state.rb +0 -88
  244. data/lib/badline/drives/model1541/mechanism/saved_state.rb +0 -72
  245. data/lib/badline/drives/model1541/saved_state.rb +0 -44
  246. data/lib/badline/drives/model1571/saved_state.rb +0 -47
  247. data/lib/badline/drives/model1581/disk/saved_state.rb +0 -89
  248. data/lib/badline/drives/model1581/saved_state.rb +0 -42
  249. data/lib/badline/drives/model1581/wd1772/saved_state.rb +0 -68
  250. data/lib/badline/keyboard_buffer.rb +0 -33
  251. data/lib/badline/snapshot/setup.rb +0 -31
  252. data/lib/badline/snapshot/state.rb +0 -179
  253. data/lib/badline/vic20/bus/saved_state.rb +0 -35
  254. data/lib/badline/vic20/saved_state.rb +0 -110
@@ -1,66 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module Chips
5
- class VIC
6
- class Sprite
7
- # The sprite's save_state and load_state.
8
- module SavedState
9
- # The shift register, MC, MCBASE, the expansion flip-flop and whether
10
- # the sprite shows, for a VICE snapshot.
11
- attr_reader :sr, :mc, :mcbase, :exp_ff, :display_on
12
-
13
- # Sets MC, MCBASE, the expansion flip-flop, whether the sprite's DMA
14
- # runs and whether it shows, as a VICE snapshot gives them.
15
- def restore_counters(counter, base, expanded, dma, shows)
16
- @mc = counter
17
- @mcbase = base
18
- @exp_ff = expanded
19
- @dma = dma
20
- @display_on = shows
21
- end
22
-
23
- def save_state(out)
24
- out.boolean(@dma).boolean(@display_on).int(@mcbase).int(@mc).boolean(@exp_ff).optional_int(@crunched_mc)
25
- out.int(@bits).boolean(@row_ready).optional_int(@prev_bits).boolean(@first_byte_lost).boolean(@blind)
26
- out.int(@show_from).optional_int(@stop_x)
27
- out.ints(@codes).int(@leftmost).int(@span).ints(@reload_codes).int(@reload_leftmost).int(@reload_span)
28
- out.int(@sr).int(@latch).boolean(@mc_flop).boolean(@xe_flop)
29
- end
30
-
31
- def load_state(input)
32
- load_counters(input)
33
- @show_from = input.int
34
- @stop_x = input.optional_int
35
- input.ints_into(@codes)
36
- @leftmost = input.int
37
- @span = input.int
38
- input.ints_into(@reload_codes)
39
- @reload_leftmost = input.int
40
- @reload_span = input.int
41
- @sr = input.int
42
- @latch = input.int
43
- @mc_flop = input.boolean?
44
- @xe_flop = input.boolean?
45
- end
46
-
47
- private
48
-
49
- def load_counters(input)
50
- @dma = input.boolean?
51
- @display_on = input.boolean?
52
- @mcbase = input.int
53
- @mc = input.int
54
- @exp_ff = input.boolean?
55
- @crunched_mc = input.optional_int
56
- @bits = input.int
57
- @row_ready = input.boolean?
58
- @prev_bits = input.optional_int
59
- @first_byte_lost = input.boolean?
60
- @blind = input.boolean?
61
- end
62
- end
63
- end
64
- end
65
- end
66
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module Chips
5
- class VIC
6
- class Sprites
7
- # The sprites' save_state and load_state.
8
- module SavedState
9
- # Whether any sprite's DMA runs, set after Sprite#restore_counters.
10
- def update_any_dma
11
- @any_dma = @sprites.any?(&:displaying?)
12
- end
13
-
14
- # The sprites, their shared bus, the collisions and the register log,
15
- # then the line's coverage and the pixels carried into the next line,
16
- # each as x, colour and priority.
17
- def save_state(out)
18
- out.boolean(@any_dma).boolean(@stopped_dma).boolean(@carried).int(@lo).int(@hi).int(@sequenced)
19
- out.blob(@win_color).booleans(@win_priority).ints(@palette)
20
- [@carry, @carry_next].each { |carry| carry.each { |pixels| save_carry(pixels, out) } }
21
- @sprites.each { |sprite| sprite.save_state(out) }
22
- @bus.save_state(out)
23
- @collisions.save_state(out)
24
- @log.save_state(out)
25
- end
26
-
27
- def load_state(input)
28
- @any_dma = input.boolean?
29
- @stopped_dma = input.boolean?
30
- @carried = input.boolean?
31
- @lo = input.int
32
- @hi = input.int
33
- @sequenced = input.int
34
- input.blob_into(@win_color)
35
- input.booleans_into(@win_priority)
36
- input.ints_into(@palette)
37
- [@carry, @carry_next].each { |carry| carry.each { |pixels| load_carry(pixels, input) } }
38
- @sprites.each { |sprite| sprite.load_state(input) }
39
- @bus.load_state(input)
40
- @collisions.load_state(input)
41
- @log.load_state(input)
42
- end
43
-
44
- private
45
-
46
- def save_carry(pixels, out)
47
- out.int(pixels.length / 3)
48
- pixels.each_slice(3) { |x, color, priority| out.int(x).int(color).boolean(priority) }
49
- end
50
-
51
- def load_carry(pixels, input)
52
- pixels.clear
53
- input.int.times { pixels.push(input.int, input.int, input.boolean?) }
54
- end
55
- end
56
- end
57
- end
58
- end
59
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module Chips
5
- class VICI
6
- class Painter
7
- # The painter's state for a snapshot.
8
- module SavedState
9
- # The colours, the line being painted and how far, what each line
10
- # fetched, and the display, for a snapshot. Whether it renders is
11
- # the host's, and a restored display is all changed.
12
- def save_state(out)
13
- out.int(@border).int(@background).int(@aux).boolean(@reverse)
14
- out.int(@row).int(@painted).boolean(@written)
15
- out.blob(@display).blob(@patterns).blob(@colors)
16
- out.ints(@counts).ints(@starts).booleans(@stale).ints(@memo_keys)
17
- end
18
-
19
- def load_state(input)
20
- @border = input.int
21
- @background = input.int
22
- @aux = input.int
23
- @reverse = input.boolean?
24
- @row = input.int
25
- @painted = input.int
26
- @written = input.boolean?
27
- input.blob_into(@display)
28
- input.blob_into(@patterns)
29
- input.blob_into(@colors)
30
- input.ints_into(@counts)
31
- input.ints_into(@starts)
32
- input.booleans_into(@stale)
33
- input.ints_into(@memo_keys)
34
- @dirty_lines.fill(true)
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,55 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module Chips
5
- class VICI
6
- # The VIC's state for a snapshot: the registers and what they set, the
7
- # raster, the text window and its fetches, and the picture with what
8
- # each line fetched. The sound saves its own.
9
- module SavedState
10
- def save_state(out)
11
- out.marker("VIC20 VIC")
12
- out.ints(@registers).int(@rasterline).int(@column).int(@next_event)
13
- [@origin_x, @origin_y, @columns, @rows, @char_shift, @screen_base, @char_base].each { |value| out.int(value) }
14
- out.boolean(@window_open).boolean(@window_done)
15
- [@row_start, @matrix, @char_line, @text_rows].each { |value| out.int(value) }
16
- [@fetch_from, @fetch_to, @fetched, @slot, @code].each { |value| out.int(value) }
17
- @painter.save_state(out)
18
- end
19
-
20
- def load_state(input)
21
- input.marker("VIC20 VIC")
22
- input.ints_into(@registers)
23
- @rasterline = input.int
24
- @column = input.int
25
- @next_event = input.int
26
- load_window(input)
27
- @fetch_from = input.int
28
- @fetch_to = input.int
29
- @fetched = input.int
30
- @slot = input.int
31
- @code = input.int
32
- @painter.load_state(input)
33
- end
34
-
35
- private
36
-
37
- def load_window(input)
38
- @origin_x = input.int
39
- @origin_y = input.int
40
- @columns = input.int
41
- @rows = input.int
42
- @char_shift = input.int
43
- @screen_base = input.int
44
- @char_base = input.int
45
- @window_open = input.boolean?
46
- @window_done = input.boolean?
47
- @row_start = input.int
48
- @matrix = input.int
49
- @char_line = input.int
50
- @text_rows = input.int
51
- end
52
- end
53
- end
54
- end
55
- end
@@ -1,71 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module Chips
5
- class Z80
6
- # The registers, the T-state count and the interrupt latches for a
7
- # snapshot, taken between instructions.
8
- module SavedState
9
- def save_state(out)
10
- out.marker("Z80")
11
- out.int(@a).int(@f).int(@b).int(@c).int(@d).int(@e).int(@h).int(@l)
12
- out.int(@af_alt).int(@bc_alt).int(@de_alt).int(@hl_alt)
13
- out.int(@i).int(@r).int(@pc).int(@sp).int(@ix).int(@iy).int(@wz).int(@q).int(@last_q).int(@im)
14
- out.int(@cycles)
15
- out.boolean(@iff1).boolean(@iff2).boolean(@halted).boolean(@after_ei).boolean(@after_ld_a_ir)
16
- out.boolean(@int).boolean(@nmi).boolean(@nmi_pending)
17
- end
18
-
19
- def load_state(input)
20
- input.marker("Z80")
21
- load_main_registers(input)
22
- @af_alt = input.int
23
- @bc_alt = input.int
24
- @de_alt = input.int
25
- @hl_alt = input.int
26
- load_special_registers(input)
27
- @cycles = input.int
28
- load_latches(input)
29
- @prefix = 0
30
- end
31
-
32
- private
33
-
34
- def load_main_registers(input)
35
- @a = input.int
36
- @f = input.int
37
- @b = input.int
38
- @c = input.int
39
- @d = input.int
40
- @e = input.int
41
- @h = input.int
42
- @l = input.int
43
- end
44
-
45
- def load_special_registers(input)
46
- @i = input.int
47
- @r = input.int
48
- @pc = input.int
49
- @sp = input.int
50
- @ix = input.int
51
- @iy = input.int
52
- @wz = input.int
53
- @q = input.int
54
- @last_q = input.int
55
- @im = input.int
56
- end
57
-
58
- def load_latches(input)
59
- @iff1 = input.boolean?
60
- @iff2 = input.boolean?
61
- @halted = input.boolean?
62
- @after_ei = input.boolean?
63
- @after_ld_a_ir = input.boolean?
64
- @int = input.boolean?
65
- @nmi = input.boolean?
66
- @nmi_pending = input.boolean?
67
- end
68
- end
69
- end
70
- end
71
- end
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- # Observe-only PC trap on the KERNAL CHROUT routine ($FFD2). Records each
5
- # character written while the layout finds the KERNAL mapped in, then lets execution fall
6
- # through to the ROM, so the screen output is unaffected. Used for headless
7
- # capture of program output.
8
- class ChroutTrap
9
- ADDRESS = 0xffd2
10
-
11
- attr_reader :output
12
-
13
- # The KERNAL layout whose mapping the trap checks.
14
- attr_writer :layout
15
-
16
- def initialize(cpu:, bus:, layout:)
17
- @cpu = cpu
18
- @bus = bus
19
- @layout = layout
20
- @output = +""
21
- end
22
-
23
- def call
24
- @output << ascii(@cpu.a) if @layout.kernal_mapped?(@bus)
25
- end
26
-
27
- def inspect
28
- "#<#{self.class.name} output=#{@output.inspect}>"
29
- end
30
-
31
- private
32
-
33
- def ascii(byte)
34
- case byte
35
- when 0x0d then "\n"
36
- when 0x41..0x5a then (byte + 0x20).chr
37
- when 0xc1..0xda then (byte - 0x80).chr
38
- when 0x20..0x7e then byte.chr
39
- else ""
40
- end
41
- end
42
- end
43
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- # The VICE debug cartridge register, mapped at $D7FF on the C64. It is a
5
- # VICE facility rather than real hardware, enabled there with -debugcart:
6
- # writing a byte ends the run with that value as the exit code. The VICE
7
- # test suites write $00 for success and $ff for failure.
8
- #
9
- # Wraps the SID's top mirror page, so every other access falls through.
10
- class DebugRegister
11
- ADDRESS = 0xd7ff
12
-
13
- def initialize(sid, &handler)
14
- @sid = sid
15
- @handler = handler
16
- end
17
-
18
- def peek(addr)
19
- @sid.peek(addr)
20
- end
21
-
22
- def poke(addr, value)
23
- return @handler.call(value) if addr == ADDRESS
24
-
25
- @sid.poke(addr, value)
26
- end
27
- end
28
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module Drives
5
- class Datasette
6
- # The datasette's state for a snapshot.
7
- module SavedState
8
- # The keys, the motor, the countdown to the next pulse and the tape:
9
- # its path, its bytes and how far it has played.
10
- def save_state(out)
11
- out.marker("DATASETTE")
12
- out.boolean(@playing).boolean(@motor).int(@countdown).boolean(!@tape.nil?)
13
- return unless @tape
14
-
15
- out.string(@tape.path).blob(@tape.bytes).int(@tape.position)
16
- end
17
-
18
- # The tape goes back in from the bytes the state holds, without its
19
- # host file, unless the tape in is the same one. The sense and flag
20
- # handlers don't fire.
21
- def load_state(input)
22
- input.marker("DATASETTE")
23
- @playing = input.boolean?
24
- @motor = input.boolean?
25
- @countdown = input.int
26
- return @tape = nil unless input.boolean?
27
-
28
- path = input.string
29
- bytes = input.blob
30
- position = input.int
31
- @tape = Storage::TAP.new(path, bytes:) unless @tape&.path&.b == path && @tape.bytes == bytes
32
- @tape.position = position
33
- end
34
- end
35
- end
36
- end
37
- end
@@ -1,88 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "badline/media/extensions"
4
-
5
- module Badline
6
- module Drives
7
- class Model1541
8
- class Disk
9
- # Saving and restoring a Disk for a snapshot: the image by its path,
10
- # and every half track as the head sees it, with those written since
11
- # the last flush. The image itself is read again from its host file,
12
- # where there still is one.
13
- module SavedState
14
- # The image's path, expanded, and whether it was opened read-only,
15
- # for a disk from Disk.open. Nil for a disk made another way.
16
- attr_reader :path, :read_only
17
-
18
- # Whether the image is a .g64 or .g71, by its name.
19
- def self.g64?(path) = Media::Extensions.kind(path) == :gcr
20
-
21
- # A disk for the image at the path (Disk.image_for), its tracks left
22
- # for the state.
23
- def self.reopen(path, read_only) = Disk.new(Disk.image_for(path, read_only)).opened(path, read_only)
24
-
25
- # The disk a state from save_state describes: +current+ when it was
26
- # opened from the same image the same way, and otherwise a disk for
27
- # the image at the path the state names. Where no file is at that
28
- # path, the disk has no image and is write-protected, and a
29
- # detached reader always gets one without an image. Either way its
30
- # tracks come from the state.
31
- def self.load(input, current)
32
- path = input.optional_string
33
- read_only = input.boolean?
34
- disk = current if current && !path.nil? && current.path == path && current.read_only == read_only
35
- disk ||= fresh(path, read_only, input.detached?)
36
- disk.load_tracks(input)
37
- disk
38
- end
39
-
40
- def self.fresh(path, read_only, detached)
41
- return Disk.new if path.nil? || detached
42
- return Disk.new.opened(path, true) unless File.file?(path)
43
-
44
- reopen(path, read_only)
45
- end
46
-
47
- # Notes the image's path and how it was opened.
48
- def opened(path, read_only)
49
- @path = File.expand_path(path)
50
- @read_only = read_only
51
- self
52
- end
53
-
54
- def save_state(out)
55
- out.optional_string(@path).boolean(@read_only)
56
- @tracks.each do |track|
57
- out.boolean(!track.nil?)
58
- save_track(track, out) if track
59
- end
60
- out.ints(@written.keys)
61
- end
62
-
63
- def load_tracks(input)
64
- @tracks.each_index do |half_track|
65
- @tracks[half_track] = input.boolean? ? load_track(input) : nil
66
- end
67
- @written.clear
68
- input.ints.each { |half_track| @written[half_track] = true }
69
- end
70
-
71
- private
72
-
73
- def save_track(track, out)
74
- out.int(track.zone).boolean(!track.speeds.nil?)
75
- out.ints(track.speeds) if track.speeds
76
- out.blob(track.bytes)
77
- end
78
-
79
- def load_track(input)
80
- zone = input.int
81
- speeds = input.boolean? ? input.ints : nil
82
- Track.new(input.blob, zone, speeds)
83
- end
84
- end
85
- end
86
- end
87
- end
88
- end
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module Drives
5
- class Model1541
6
- class Mechanism
7
- # Saving and restoring the Mechanism for a snapshot.
8
- module SavedState
9
- # The disk (Disk#save_state) and everything the head, the motor, the
10
- # stepper and the read and write electronics hold, down to the cell
11
- # under the head and the read clock's phase.
12
- def save_state(out)
13
- out.boolean(!@disk.nil?)
14
- @disk&.save_state(out)
15
- [@half_track, @slip, @side_base, @zone, @clock, @time, @clock_at, @clocks, @shift, @ones, @bits,
16
- @write_shift, @index, @mask, @cell_end, @width, @next].each { |value| out.int(value) }
17
- [@motor, @led, @sync, @byte_ready, @byte_latched, @writing, @write_gate, @protected,
18
- @track_written].each { |flag| out.boolean(flag) }
19
- out.optional_int(@write_index)
20
- end
21
-
22
- # Puts the state back, reusing the disk in when it's the one the state
23
- # names (Disk::SavedState.load). A disk taken out is flushed, as insert
24
- # does.
25
- def load_state(input)
26
- disk = input.boolean? ? Disk::SavedState.load(input, @disk) : nil
27
- flush unless disk.equal?(@disk)
28
- @disk = disk
29
- load_head(input)
30
- load_flags(input)
31
- @write_index = input.optional_int
32
- head_on_track
33
- end
34
-
35
- private
36
-
37
- def load_head(input)
38
- @half_track = input.int
39
- @slip = input.int
40
- @side_base = input.int
41
- @zone = input.int
42
- @clock = input.int
43
- @time = input.int
44
- @clock_at = input.int
45
- @clocks = input.int
46
- @shift = input.int
47
- @ones = input.int
48
- @bits = input.int
49
- @write_shift = input.int
50
- @index = input.int
51
- @mask = input.int
52
- @cell_end = input.int
53
- @width = input.int
54
- @next = input.int
55
- end
56
-
57
- def load_flags(input)
58
- @motor = input.boolean?
59
- @led = input.boolean?
60
- @sync = input.boolean?
61
- @byte_ready = input.boolean?
62
- @byte_latched = input.boolean?
63
- @writing = input.boolean?
64
- @write_gate = input.boolean?
65
- @protected = input.boolean?
66
- @track_written = input.boolean?
67
- end
68
- end
69
- end
70
- end
71
- end
72
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module Drives
5
- class Model1541
6
- # The drive's state for a snapshot.
7
- module SavedState
8
- # The drive's whole state: its clock phase, the CPU, RAM, both VIAs,
9
- # the serial port's latch of the C64's lines and the mechanism with its
10
- # disk. The drive settles first, so it is awake and not recording a
11
- # pass, and a restored drive starts the same way, its orbits forgotten
12
- # from the state it takes: Idle's and Orbit's bookkeeping
13
- # isn't stored. The device number, the host's clock rate and whether
14
- # the drive may sleep are the machine's wiring.
15
- def save_state(out)
16
- settle!
17
- out.marker("DRIVE1541")
18
- out.int(@phase).int(@cycles).boolean(@mechanism.so_pending)
19
- @serial_port.save_state(out)
20
- @via1.save_state(out)
21
- @via2.save_state(out)
22
- @bus.save_state(out)
23
- @cpu.save_state(out)
24
- @mechanism.save_state(out)
25
- end
26
-
27
- def load_state(input)
28
- settle!
29
- input.marker("DRIVE1541")
30
- @phase = input.int
31
- @cycles = input.int
32
- @mechanism.so_pending = input.boolean?
33
- @serial_port.load_state(input)
34
- @via1.load_state(input)
35
- @via2.load_state(input)
36
- @bus.load_state(input)
37
- @cpu.load_state(input)
38
- @mechanism.load_state(input)
39
- forget_orbits
40
- end
41
- end
42
- end
43
- end
44
- end
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module Drives
5
- class Model1571
6
- # The drive's state for a snapshot.
7
- module SavedState
8
- # The drive's whole state, as the 1541's (Drives::Model1541#save_state), with
9
- # the CIA and the WD1770's registers. The clock rate, the side and the
10
- # fast serial direction follow from VIA 1's port A.
11
- def save_state(out)
12
- settle!
13
- out.marker("DRIVE1571")
14
- out.int(@phase).int(@cycles).boolean(@mechanism.so_pending)
15
- @serial_port.save_state(out)
16
- @via1.save_state(out)
17
- @via2.save_state(out)
18
- @cia.save_state(out)
19
- @fdc.save_state(out)
20
- @bus.save_state(out)
21
- @cpu.save_state(out)
22
- @mechanism.save_state(out)
23
- end
24
-
25
- def load_state(input)
26
- settle!
27
- input.marker("DRIVE1571")
28
- @phase = input.int
29
- @cycles = input.int
30
- @mechanism.so_pending = input.boolean?
31
- @serial_port.load_state(input)
32
- @via1.load_state(input)
33
- @via2.load_state(input)
34
- @cia.load_state(input)
35
- @fdc.load_state(input)
36
- @bus.load_state(input)
37
- @cpu.load_state(input)
38
- @mechanism.load_state(input)
39
- @fast_serial_out = @via1.port_a_output.anybits?(FAST_SERIAL_OUT)
40
- port_a_written(@via1.port_a_output)
41
- push_fast_output(@fast_serial_out ? fast_pins : 0)
42
- forget_orbits
43
- end
44
- end
45
- end
46
- end
47
- end