badline 0.13.0 → 0.15.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 (286) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +72 -1
  3. data/CLAUDE.md +42 -12
  4. data/CONTRIBUTING.md +4 -3
  5. data/README.md +76 -13
  6. data/doc/media.md +2 -1
  7. data/doc/pinned-behaviour.md +174 -0
  8. data/doc/snapshot-format.md +1197 -0
  9. data/doc/snapshots.md +90 -40
  10. data/lib/badline/audio/bare_player.rb +46 -17
  11. data/lib/badline/audio/machine_player.rb +6 -10
  12. data/lib/badline/audio/renderer.rb +32 -21
  13. data/lib/badline/c128/banks.rb +7 -6
  14. data/lib/badline/c128/bus/keyed_state.rb +45 -0
  15. data/lib/badline/c128/bus.rb +36 -4
  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 +27 -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/extra_sids.rb +80 -0
  31. data/lib/badline/c64/bus/keyed_state.rb +41 -0
  32. data/lib/badline/c64/bus.rb +3 -1
  33. data/lib/badline/c64/cartridge/action_replay.rb +6 -15
  34. data/lib/badline/c64/cartridge/comal80.rb +1 -0
  35. data/lib/badline/c64/cartridge/dinamic.rb +3 -1
  36. data/lib/badline/c64/cartridge/easy_flash.rb +0 -15
  37. data/lib/badline/c64/cartridge/epyx_fastload.rb +0 -8
  38. data/lib/badline/c64/cartridge/final_cartridge3.rb +1 -12
  39. data/lib/badline/c64/cartridge/flash.rb +3 -3
  40. data/lib/badline/c64/cartridge/fun_play.rb +2 -1
  41. data/lib/badline/c64/cartridge/g_mod2.rb +0 -12
  42. data/lib/badline/c64/cartridge/game_system.rb +2 -1
  43. data/lib/badline/c64/cartridge/geo_ram.rb +0 -16
  44. data/lib/badline/c64/cartridge/kcs_power.rb +0 -8
  45. data/lib/badline/c64/cartridge/keyed_state.rb +514 -0
  46. data/lib/badline/c64/cartridge/magic_desk.rb +2 -1
  47. data/lib/badline/c64/cartridge/ocean.rb +1 -0
  48. data/lib/badline/c64/cartridge/pagefox.rb +1 -10
  49. data/lib/badline/c64/cartridge/retro_replay.rb +0 -8
  50. data/lib/badline/c64/cartridge/rgcd.rb +2 -11
  51. data/lib/badline/c64/cartridge/super_games.rb +3 -12
  52. data/lib/badline/c64/cartridge/zaxxon.rb +1 -16
  53. data/lib/badline/c64/cartridge.rb +4 -30
  54. data/lib/badline/c64/kernal_traps.rb +28 -25
  55. data/lib/badline/c64/keyed_modules.rb +115 -0
  56. data/lib/badline/c64/keyed_state.rb +68 -0
  57. data/lib/badline/c64/reu/dma.rb +0 -4
  58. data/lib/badline/c64/reu/keyed_state.rb +140 -0
  59. data/lib/badline/c64/reu/ram.rb +0 -15
  60. data/lib/badline/c64/reu.rb +1 -3
  61. data/lib/badline/c64/true_drives.rb +56 -5
  62. data/lib/badline/c64.rb +7 -3
  63. data/lib/badline/chips/cia/interrupt_register.rb +0 -17
  64. data/lib/badline/chips/cia/keyed_parts.rb +213 -0
  65. data/lib/badline/chips/cia/serial.rb +0 -4
  66. data/lib/badline/chips/cia/time_of_day.rb +0 -22
  67. data/lib/badline/chips/cia/timer.rb +0 -20
  68. data/lib/badline/chips/cia.rb +2 -2
  69. data/lib/badline/chips/cpu/core.rb +18 -2
  70. data/lib/badline/chips/cpu/keyed_state.rb +177 -0
  71. data/lib/badline/chips/cpu/microcode.rb +16 -0
  72. data/lib/badline/chips/cpu/port.rb +20 -3
  73. data/lib/badline/chips/cpu.rb +5 -0
  74. data/lib/badline/chips/sid/decimator.rb +10 -8
  75. data/lib/badline/chips/sid/envelope.rb +1 -6
  76. data/lib/badline/chips/sid/filter.rb +0 -14
  77. data/lib/badline/chips/sid/keyed_parts.rb +286 -0
  78. data/lib/badline/chips/sid/voice.rb +0 -10
  79. data/lib/badline/chips/sid/waveform.rb +0 -2
  80. data/lib/badline/chips/sid.rb +1 -2
  81. data/lib/badline/chips/ted/beam.rb +118 -0
  82. data/lib/badline/chips/ted/fetches.rb +199 -0
  83. data/lib/badline/chips/ted/keyed_state.rb +156 -0
  84. data/lib/badline/chips/ted/modes.rb +134 -0
  85. data/lib/badline/chips/ted/palette.rb +43 -0
  86. data/lib/badline/chips/ted/picture.rb +182 -0
  87. data/lib/badline/chips/ted/sound/output.rb +86 -0
  88. data/lib/badline/chips/ted/sound.rb +284 -0
  89. data/lib/badline/chips/ted/timers.rb +66 -0
  90. data/lib/badline/chips/ted.rb +190 -0
  91. data/lib/badline/chips/tia.rb +61 -0
  92. data/lib/badline/chips/vdc/keyed_parts.rb +105 -0
  93. data/lib/badline/chips/vdc/painter.rb +0 -12
  94. data/lib/badline/chips/vdc/raster.rb +0 -16
  95. data/lib/badline/chips/vdc/window.rb +0 -9
  96. data/lib/badline/chips/vdc.rb +1 -2
  97. data/lib/badline/chips/via/control_lines.rb +0 -15
  98. data/lib/badline/chips/via/interrupt_register.rb +0 -9
  99. data/lib/badline/chips/via/keyed_parts.rb +163 -0
  100. data/lib/badline/chips/via/shift_register.rb +0 -14
  101. data/lib/badline/chips/via/timer1.rb +0 -13
  102. data/lib/badline/chips/via/timer2.rb +0 -18
  103. data/lib/badline/chips/via.rb +1 -2
  104. data/lib/badline/chips/vic/border_mask.rb +0 -10
  105. data/lib/badline/chips/vic/collisions.rb +0 -11
  106. data/lib/badline/chips/vic/color_patches.rb +0 -11
  107. data/lib/badline/chips/vic/display_state.rb +0 -19
  108. data/lib/badline/chips/vic/graphics_shifter.rb +0 -4
  109. data/lib/badline/chips/vic/keyed_parts.rb +228 -0
  110. data/lib/badline/chips/vic/keyed_sprites.rb +225 -0
  111. data/lib/badline/chips/vic/keyed_state.rb +102 -0
  112. data/lib/badline/chips/vic/register_log.rb +0 -18
  113. data/lib/badline/chips/vic/registers.rb +0 -9
  114. data/lib/badline/chips/vic/sequencer.rb +0 -2
  115. data/lib/badline/chips/vic/sprite/internal_bus.rb +0 -11
  116. data/lib/badline/chips/vic/sprite.rb +0 -2
  117. data/lib/badline/chips/vic/sprites.rb +0 -3
  118. data/lib/badline/chips/vic.rb +6 -2
  119. data/lib/badline/chips/vic_i/keyed_parts.rb +142 -0
  120. data/lib/badline/chips/vic_i/painter.rb +0 -4
  121. data/lib/badline/chips/vic_i/sound.rb +38 -46
  122. data/lib/badline/chips/vic_i.rb +2 -2
  123. data/lib/badline/chips/z80/core.rb +2 -2
  124. data/lib/badline/chips/z80/keyed_state.rb +73 -0
  125. data/lib/badline/chips.rb +10 -0
  126. data/lib/badline/core.rb +4 -21
  127. data/lib/badline/drives/datasette/keyed_state.rb +43 -0
  128. data/lib/badline/drives/datasette.rb +62 -12
  129. data/lib/badline/drives/engine/core.rb +3 -0
  130. data/lib/badline/drives/engine/serial_lines.rb +4 -7
  131. data/lib/badline/drives/model1541/bus.rb +0 -13
  132. data/lib/badline/drives/model1541/disk.rb +9 -8
  133. data/lib/badline/drives/model1541/keyed_state.rb +251 -0
  134. data/lib/badline/drives/model1541/mechanism.rb +0 -2
  135. data/lib/badline/drives/model1541.rb +1 -2
  136. data/lib/badline/drives/model1571/bus.rb +0 -13
  137. data/lib/badline/drives/model1571/keyed_state.rb +108 -0
  138. data/lib/badline/drives/model1571/wd1770.rb +0 -14
  139. data/lib/badline/drives/model1571.rb +1 -2
  140. data/lib/badline/drives/model1581/bus.rb +0 -13
  141. data/lib/badline/drives/model1581/disk.rb +0 -4
  142. data/lib/badline/drives/model1581/keyed_state.rb +280 -0
  143. data/lib/badline/drives/model1581/mechanism.rb +0 -21
  144. data/lib/badline/drives/model1581/slot.rb +0 -18
  145. data/lib/badline/drives/model1581/wd1772.rb +0 -2
  146. data/lib/badline/drives/model1581.rb +2 -2
  147. data/lib/badline/drives.rb +8 -0
  148. data/lib/badline/frontend/app.rb +3 -3
  149. data/lib/badline/frontend/boot.rb +4 -2
  150. data/lib/badline/frontend/controls.rb +25 -5
  151. data/lib/badline/frontend/drive_led.rb +44 -21
  152. data/lib/badline/frontend/keys.rb +14 -2
  153. data/lib/badline/frontend/media_slots.rb +11 -1
  154. data/lib/badline/frontend/menu/menu_dialogs.rb +4 -3
  155. data/lib/badline/frontend/menu/menu_media.rb +13 -3
  156. data/lib/badline/frontend/menu/menu_pages.rb +8 -8
  157. data/lib/badline/frontend/menu/menu_ports.rb +13 -1
  158. data/lib/badline/frontend/screen.rb +33 -12
  159. data/lib/badline/frontend/screens.rb +2 -1
  160. data/lib/badline/frontend/snapshots.rb +12 -1
  161. data/lib/badline/frontend/sound.rb +4 -4
  162. data/lib/badline/frontend/timeline.rb +43 -12
  163. data/lib/badline/input/matrix_typist.rb +98 -0
  164. data/lib/badline/input.rb +1 -0
  165. data/lib/badline/kernal_trap/chrout.rb +45 -0
  166. data/lib/badline/kernal_trap/dos/channel.rb +0 -27
  167. data/lib/badline/kernal_trap/dos/channels.rb +0 -25
  168. data/lib/badline/kernal_trap/dos/memory.rb +0 -9
  169. data/lib/badline/kernal_trap/dos/status.rb +0 -8
  170. data/lib/badline/kernal_trap/dos/write_file.rb +0 -18
  171. data/lib/badline/kernal_trap/dos.rb +0 -19
  172. data/lib/badline/kernal_trap/file_routine.rb +4 -4
  173. data/lib/badline/kernal_trap/keyed_state.rb +150 -0
  174. data/lib/badline/kernal_trap/layout.rb +75 -11
  175. data/lib/badline/kernal_trap/load.rb +14 -16
  176. data/lib/badline/kernal_trap/routine.rb +12 -0
  177. data/lib/badline/kernal_trap/save.rb +8 -18
  178. data/lib/badline/kernal_trap/serial.rb +1 -17
  179. data/lib/badline/kernal_trap.rb +2 -0
  180. data/lib/badline/machine/keyboard_buffer.rb +49 -0
  181. data/lib/badline/machine/settling.rb +29 -0
  182. data/lib/badline/machine.rb +29 -6
  183. data/lib/badline/media/boot_disk.rb +14 -2
  184. data/lib/badline/media/extensions.rb +10 -0
  185. data/lib/badline/media/plus4_media.rb +68 -0
  186. data/lib/badline/media/program.rb +20 -6
  187. data/lib/badline/media.rb +33 -12
  188. data/lib/badline/memory.rb +3 -6
  189. data/lib/badline/options/family.rb +6 -2
  190. data/lib/badline/options/help.rb +66 -16
  191. data/lib/badline/options/table.rb +17 -2
  192. data/lib/badline/options/validation.rb +26 -2
  193. data/lib/badline/options.rb +42 -9
  194. data/lib/badline/plus4/acia.rb +45 -0
  195. data/lib/badline/plus4/bus.rb +375 -0
  196. data/lib/badline/plus4/cassette_sense.rb +21 -0
  197. data/lib/badline/plus4/cpu.rb +10 -0
  198. data/lib/badline/plus4/cpu_port.rb +93 -0
  199. data/lib/badline/plus4/keyboard_port.rb +76 -0
  200. data/lib/badline/plus4/keyed_modules.rb +99 -0
  201. data/lib/badline/plus4/keyed_parts.rb +143 -0
  202. data/lib/badline/plus4/keyed_state.rb +41 -0
  203. data/lib/badline/plus4/model.rb +38 -0
  204. data/lib/badline/plus4/user_port.rb +31 -0
  205. data/lib/badline/plus4.rb +240 -0
  206. data/lib/badline/roms/README +38 -0
  207. data/lib/badline/roms/plus4/basic.rom +0 -0
  208. data/lib/badline/roms/plus4/function-high.rom +0 -0
  209. data/lib/badline/roms/plus4/function-low.rom +0 -0
  210. data/lib/badline/roms/plus4/kernal-ntsc.rom +0 -0
  211. data/lib/badline/roms/plus4/kernal-pal.rom +0 -0
  212. data/lib/badline/snapshot/c128_setup.rb +9 -20
  213. data/lib/badline/snapshot/c64_setup.rb +28 -24
  214. data/lib/badline/snapshot/container.rb +6 -0
  215. data/lib/badline/snapshot/field_doc/markdown.rb +113 -0
  216. data/lib/badline/snapshot/field_doc.rb +148 -0
  217. data/lib/badline/snapshot/image.rb +143 -28
  218. data/lib/badline/snapshot/keyed/cursor.rb +40 -0
  219. data/lib/badline/snapshot/keyed/modules.rb +66 -0
  220. data/lib/badline/snapshot/keyed/reader.rb +188 -0
  221. data/lib/badline/snapshot/keyed/recorder.rb +88 -0
  222. data/lib/badline/snapshot/keyed/report.rb +26 -0
  223. data/lib/badline/snapshot/keyed/writer.rb +55 -0
  224. data/lib/badline/snapshot/keyed.rb +64 -0
  225. data/lib/badline/snapshot/machine_state.rb +17 -64
  226. data/lib/badline/snapshot/plus4_setup.rb +39 -0
  227. data/lib/badline/snapshot/storage_setup.rb +29 -34
  228. data/lib/badline/snapshot/vic20_setup.rb +6 -15
  229. data/lib/badline/snapshot/vice/reu1764.rb +2 -2
  230. data/lib/badline/snapshot/vice.rb +7 -31
  231. data/lib/badline/snapshot.rb +48 -20
  232. data/lib/badline/storage/crt_file.rb +3 -1
  233. data/lib/badline/storage/g64_image.rb +9 -4
  234. data/lib/badline/storage/tap.rb +57 -20
  235. data/lib/badline/support/checkpoint.rb +3 -2
  236. data/lib/badline/support/plus4_checkpoint.rb +42 -0
  237. data/lib/badline/version.rb +1 -1
  238. data/lib/badline/vic20/attachments.rb +3 -0
  239. data/lib/badline/vic20/bus/keyed_state.rb +52 -0
  240. data/lib/badline/vic20/bus.rb +1 -2
  241. data/lib/badline/vic20/keyed_modules.rb +73 -0
  242. data/lib/badline/vic20/keyed_state.rb +45 -0
  243. data/lib/badline/vic20.rb +5 -5
  244. data/lib/badline.rb +1 -0
  245. metadata +75 -42
  246. data/lib/badline/c128/bus/saved_state.rb +0 -53
  247. data/lib/badline/c128/saved_state.rb +0 -117
  248. data/lib/badline/c64/bus/saved_state.rb +0 -68
  249. data/lib/badline/c64/cartridge/flash/saved_state.rb +0 -40
  250. data/lib/badline/c64/cartridge/retro_replay/saved_state.rb +0 -47
  251. data/lib/badline/c64/cartridge/saved_state.rb +0 -63
  252. data/lib/badline/c64/reu/dma/saved_state.rb +0 -52
  253. data/lib/badline/c64/reu/saved_state.rb +0 -55
  254. data/lib/badline/c64/saved_state.rb +0 -112
  255. data/lib/badline/chips/cia/saved_state.rb +0 -49
  256. data/lib/badline/chips/cia/serial/saved_state.rb +0 -45
  257. data/lib/badline/chips/cpu/saved_state.rb +0 -117
  258. data/lib/badline/chips/sid/envelope/saved_state.rb +0 -70
  259. data/lib/badline/chips/sid/filter/saved_state.rb +0 -42
  260. data/lib/badline/chips/sid/saved_state.rb +0 -52
  261. data/lib/badline/chips/sid/waveform/saved_state.rb +0 -68
  262. data/lib/badline/chips/vdc/saved_state.rb +0 -36
  263. data/lib/badline/chips/via/saved_state.rb +0 -44
  264. data/lib/badline/chips/vic/graphics_shifter/saved_state.rb +0 -40
  265. data/lib/badline/chips/vic/saved_state.rb +0 -82
  266. data/lib/badline/chips/vic/sequencer/saved_state.rb +0 -91
  267. data/lib/badline/chips/vic/sprite/saved_state.rb +0 -66
  268. data/lib/badline/chips/vic/sprites/saved_state.rb +0 -59
  269. data/lib/badline/chips/vic_i/painter/saved_state.rb +0 -40
  270. data/lib/badline/chips/vic_i/saved_state.rb +0 -55
  271. data/lib/badline/chips/z80/saved_state.rb +0 -71
  272. data/lib/badline/chrout_trap.rb +0 -43
  273. data/lib/badline/debug_register.rb +0 -28
  274. data/lib/badline/drives/datasette/saved_state.rb +0 -37
  275. data/lib/badline/drives/model1541/disk/saved_state.rb +0 -88
  276. data/lib/badline/drives/model1541/mechanism/saved_state.rb +0 -72
  277. data/lib/badline/drives/model1541/saved_state.rb +0 -44
  278. data/lib/badline/drives/model1571/saved_state.rb +0 -47
  279. data/lib/badline/drives/model1581/disk/saved_state.rb +0 -89
  280. data/lib/badline/drives/model1581/saved_state.rb +0 -42
  281. data/lib/badline/drives/model1581/wd1772/saved_state.rb +0 -68
  282. data/lib/badline/keyboard_buffer.rb +0 -33
  283. data/lib/badline/snapshot/setup.rb +0 -31
  284. data/lib/badline/snapshot/state.rb +0 -179
  285. data/lib/badline/vic20/bus/saved_state.rb +0 -35
  286. data/lib/badline/vic20/saved_state.rb +0 -110
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class C64
5
- class Bus
6
- # The bus's state for a snapshot: the CPU port, the RAM, colour RAM and
7
- # a RAM expansion, the cartridge, the datasette and the chips.
8
- module SavedState
9
- # The RAM expansion fitted, or an Unexpanded stand-in.
10
- attr_reader :ram_expansion
11
-
12
- # Takes the cartridge out of the expansion port, as a restore does for
13
- # a state without one.
14
- def detach_cartridge
15
- @cartridge = nil
16
- update_overlays!
17
- end
18
-
19
- # The 6510 port's direction and output registers, and the charge left
20
- # on its floating bits.
21
- def port_state = [@cpu_port.ddr, @cpu_port.data, @cpu_port.floating]
22
-
23
- # Sets the port as port_state reads it, as a snapshot restores it,
24
- # leaving the RAM under $00 and $01 alone.
25
- def restore_port(ddr, out, floating)
26
- @cpu_port.restore(ddr, out, floating)
27
- end
28
-
29
- # The machine's memory and everything on the bus but the keyboard, the
30
- # joysticks and the pot devices, which the host holds. A cartridge is
31
- # already in the port, built from its setup (C64#load_state).
32
- def save_state(out)
33
- out.marker("BUS")
34
- out.int(@cpu_port.ddr).int(@cpu_port.data).int(@cpu_port.floating)
35
- @ram.save_state(out)
36
- @color_ram.save_state(out)
37
- @ram_expansion.save_state(out)
38
- @cartridge&.save_state(out)
39
- @datasette.save_state(out)
40
- @vic.save_state(out)
41
- @cia1.save_state(out)
42
- @cia2.save_state(out)
43
- @sid.save_state(out)
44
- end
45
-
46
- def load_state(input)
47
- input.marker("BUS")
48
- ddr = input.int
49
- port_out = input.int
50
- floating = input.int
51
- @ram.load_state(input)
52
- @color_ram.load_state(input)
53
- @ram_expansion.load_state(input)
54
- @cartridge&.load_state(input)
55
- @datasette.load_state(input)
56
- @cpu_port.load(ddr, port_out, floating)
57
- update_overlays!
58
- @vic.load_state(input)
59
- @cia1.load_state(input)
60
- @cia2.load_state(input)
61
- @sid.load_state(input)
62
- end
63
- end
64
-
65
- include SavedState
66
- end
67
- end
68
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class C64
5
- class Cartridge
6
- class Flash
7
- # A Flash chip's state, for a snapshot.
8
- module SavedState
9
- STATES = %i[read program_setup autoselect programming erase_window erasing suspended chip_erase
10
- program_error].freeze
11
-
12
- # The array, the command state, a timed operation's end on the
13
- # machine's clock, and the windows handed out so far, which load_state
14
- # builds anew.
15
- def save_state(out)
16
- out.blob(@data).int(STATES.index(@state)).int(STATES.index(@base_state)).int(@cycle).int(@toggle)
17
- out.optional_int(@done_at).optional_int(@programmed).optional_int(@remaining)
18
- out.boolean(!@erasing_sectors.nil?)
19
- out.ints(@erasing_sectors) if @erasing_sectors
20
- out.ints(@windows.keys).ints(@status_windows.keys)
21
- end
22
-
23
- def load_state(input)
24
- input.blob_into(@data)
25
- @state = STATES.fetch(input.int).to_sym
26
- @base_state = STATES.fetch(input.int).to_sym
27
- @cycle = input.int
28
- @toggle = input.int
29
- @done_at = input.optional_int
30
- @programmed = input.optional_int
31
- @remaining = input.optional_int
32
- @erasing_sectors = nil
33
- @erasing_sectors = input.ints if input.boolean?
34
- rebuild_windows(input.ints, input.ints)
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class C64
5
- class Cartridge
6
- class RetroReplay < Cartridge
7
- # A Retro Replay's registers, RAM and flash, for a snapshot.
8
- module SavedState
9
- private
10
-
11
- def save_jumpers(out)
12
- out.boolean(true).boolean(@flash_jumper).boolean(@bank_jumper)
13
- end
14
-
15
- def save_mapper(out)
16
- [@active, @frozen, @phi1_ultimax, @ram_enabled, @ram_at_a000, @allow_bank, @no_freeze, @reu_mapping,
17
- @write_once].each { |flag| out.boolean(flag) }
18
- out.int(@bank).int(RetroReplay::CONTROL_MODES.index(@config))
19
- @ram_data.each { |data| out.blob(data) }
20
- @flash.save_state(out)
21
- end
22
-
23
- def load_mapper(input)
24
- load_flags(input)
25
- @bank = input.int
26
- @config = RetroReplay::CONTROL_MODES.fetch(input.int)
27
- @ram_data.each { |data| input.blob_into(data) }
28
- @flash.load_state(input)
29
- map_windows
30
- end
31
-
32
- def load_flags(input)
33
- @active = input.boolean?
34
- @frozen = input.boolean?
35
- @phi1_ultimax = input.boolean?
36
- @ram_enabled = input.boolean?
37
- @ram_at_a000 = input.boolean?
38
- @allow_bank = input.boolean?
39
- @no_freeze = input.boolean?
40
- @reu_mapping = input.boolean?
41
- @write_once = input.boolean?
42
- end
43
- end
44
- end
45
- end
46
- end
47
- end
@@ -1,63 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class C64
5
- class Cartridge
6
- # A cartridge's state for a snapshot: the setup that builds it again and
7
- # the state that goes into it.
8
- module SavedState
9
- # What builds the same cartridge afresh (Cartridge.from_setup): the CRT
10
- # image it was built from, and the jumpers of a mapper that has them.
11
- def save_setup(out)
12
- out.int(CRT_SETUP).string(Storage::CRTFile.encode(@crt))
13
- save_jumpers(out)
14
- end
15
-
16
- # The lines, the pull on NMI, the button and the mapper's own state.
17
- # Loading sets them without calling back into the machine, which maps
18
- # the cartridge again afterwards.
19
- def save_state(out)
20
- out.marker("CARTRIDGE")
21
- out.int(@exrom).int(@game).boolean(@nmi).boolean(@button == true)
22
- save_mapper(out)
23
- end
24
-
25
- def load_state(input)
26
- input.marker("CARTRIDGE")
27
- @exrom = input.int
28
- @game = input.int
29
- @nmi = input.boolean?
30
- @button = input.boolean?
31
- load_mapper(input)
32
- end
33
-
34
- private
35
-
36
- def save_jumpers(out)
37
- out.boolean(false)
38
- end
39
-
40
- # The mapper's own state: where its windows point, for a mapper that
41
- # moves them, and whatever a mapper adds after calling super.
42
- def save_mapper(out)
43
- save_windows(out, windows) if windows
44
- end
45
-
46
- def load_mapper(input)
47
- load_windows(input, windows) if windows
48
- end
49
-
50
- # Where the ROML and ROMH windows point, as their places in `windows`,
51
- # the banks and views the mapper picks them from, or -1 for none.
52
- def save_windows(out, windows)
53
- out.int(window_index(@roml, windows)).int(window_index(@romh, windows))
54
- end
55
-
56
- def load_windows(input, windows)
57
- @roml = window_at(input.int, windows)
58
- @romh = window_at(input.int, windows)
59
- end
60
- end
61
- end
62
- end
63
- end
@@ -1,52 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class C64
5
- class REU
6
- class DMA
7
- # A transfer's state for a snapshot (REU::SavedState).
8
- module SavedState
9
- # Everything a transfer holds between cycles. Before the first
10
- # transfer, the fields it sets on starting are empty.
11
- def save_state(out)
12
- out.int(@c64).int(@expansion).int(@length).int(@events)
13
- [@type, @c64_step, @expansion_step, @last, @ba_low_after_writes, @swap_byte, @held_read].each do |value|
14
- out.optional_int(value)
15
- end
16
- [@holding, @waiting, @stopped_after_write, @swap_write_due, @swap_read_again, @moved_all,
17
- @extra_cycle].each do |flag|
18
- out.boolean(flag)
19
- end
20
- end
21
-
22
- def load_state(input)
23
- @c64 = input.int
24
- @expansion = input.int
25
- @length = input.int
26
- @events = input.int
27
- load_steps(input)
28
- @holding = input.boolean?
29
- @waiting = input.boolean?
30
- @stopped_after_write = input.boolean?
31
- @swap_write_due = input.boolean?
32
- @swap_read_again = input.boolean?
33
- @moved_all = input.boolean?
34
- @extra_cycle = input.boolean?
35
- end
36
-
37
- private
38
-
39
- def load_steps(input)
40
- @type = input.optional_int
41
- @c64_step = input.optional_int
42
- @expansion_step = input.optional_int
43
- @last = input.optional_int
44
- @ba_low_after_writes = input.optional_int
45
- @swap_byte = input.optional_int
46
- @held_read = input.optional_int
47
- end
48
- end
49
- end
50
- end
51
- end
52
- end
@@ -1,55 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class C64
5
- class REU
6
- # The REU's state for a snapshot: the REC's registers and the values
7
- # its counters start from, an armed or running transfer, the IRQ line,
8
- # the transfer's own state and the RAM. The size is the machine's
9
- # setup (Snapshot::C64Setup), so a restore finds an REU of the same size.
10
- module SavedState
11
- def size_kb = @size_kb
12
-
13
- def save_state(out)
14
- out.marker("REU")
15
- [@status, @command, @c64, @c64_start, @expansion, @expansion_start, @bank, @bank_start, @length,
16
- @length_start, @interrupt_mask, @address_control].each { |value| out.int(value) }
17
- out.boolean(@armed).boolean(@requested).boolean(@running).boolean(@irq).boolean(@ba_was_low)
18
- @dma.save_state(out)
19
- @ram.save_state(out)
20
- end
21
-
22
- # The IRQ line comes back as it was without calling back into the
23
- # machine, which reads it again afterwards.
24
- def load_state(input)
25
- input.marker("REU")
26
- load_registers(input)
27
- @armed = input.boolean?
28
- @requested = input.boolean?
29
- @running = input.boolean?
30
- @irq = input.boolean?
31
- @ba_was_low = input.boolean?
32
- @dma.load_state(input)
33
- @ram.load_state(input)
34
- end
35
-
36
- private
37
-
38
- def load_registers(input)
39
- @status = input.int
40
- @command = input.int
41
- @c64 = input.int
42
- @c64_start = input.int
43
- @expansion = input.int
44
- @expansion_start = input.int
45
- @bank = input.int
46
- @bank_start = input.int
47
- @length = input.int
48
- @length_start = input.int
49
- @interrupt_mask = input.int
50
- @address_control = input.int
51
- end
52
- end
53
- end
54
- end
55
- end
@@ -1,112 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class C64
5
- # The keyword arguments C64.new takes to build the machine a
6
- # State from #snapshot was taken of.
7
- def self.setup(state) = Snapshot::C64Setup.from(state)
8
-
9
- # A new machine, built as the one a State from #snapshot was taken of,
10
- # at that state. `detached` builds it without the host's files
11
- # (Snapshot::StateReader).
12
- def self.restored(state, detached: false) = setup(state).build.apply_state(state, detached:)
13
-
14
- # The whole machine's state for a snapshot: the machine's own latches,
15
- # the bus and its chips, the CPU, and what is attached to it
16
- # (Attachments).
17
- module SavedState
18
- # How many more on_init handlers the machine a State was taken of had
19
- # yet to run than this one has: they are the host's blocks, which a
20
- # State can't hold. Nil until the machine is restored.
21
- attr_reader :init_handlers_lost
22
-
23
- # The machine's whole state, in memory. #restore takes the machine, or
24
- # another built with the same chip models, region and RAM expansion,
25
- # back to it. The cartridge, the disk in device 8, a true 1541 and its
26
- # disk and the tape go in the state too. What the host holds stays
27
- # out: the keyboard, the joysticks and the pot devices, the traps and
28
- # callbacks, whether the display renders and whether the SID records.
29
- def snapshot
30
- out = Snapshot::StateWriter.new
31
- save_state(out)
32
- out.state
33
- end
34
-
35
- # Takes the machine back to a State from #snapshot. The machine keeps
36
- # its chips, its traps and its callbacks, and puts in the cartridge,
37
- # drives and tape the state has, taking out any it hasn't. Raises
38
- # Snapshot::FormatError for a state of a machine built another way.
39
- # The state goes into a new machine first, so one that fails leaves
40
- # this machine as it was.
41
- def restore(state)
42
- check_setup(C64.setup(state))
43
- C64.restored(state)
44
- apply_state(state)
45
- end
46
-
47
- # Puts a State into the machine without trying it on a new one
48
- # first, for a machine built for it (C64.restored): a state that
49
- # fails leaves the machine part restored. `detached` restores it
50
- # without the host's files (Snapshot::StateReader).
51
- def apply_state(state, detached: false)
52
- input = Snapshot::StateReader.new(state, detached:)
53
- load_state(input)
54
- raise Snapshot::FormatError, "the state goes on past the machine" unless input.finished?
55
-
56
- self
57
- end
58
-
59
- # Sets the machine's cycle count, for a snapshot from VICE, which
60
- # counts from its own clock.
61
- def resume_at(cycles)
62
- @cycles = cycles
63
- end
64
-
65
- def save_state(out)
66
- out.marker(Snapshot::C64Setup::MARKER).stamp
67
- Snapshot::C64Setup.of(address_bus).write(out)
68
- out.int(@cycles).boolean(@nmi_asserted).boolean(@cartridge_nmi).boolean(@restore_pulse).boolean(@freezing)
69
- out.int(@freeze_writes).boolean(!@pending_keys.nil?)
70
- out.ints(@pending_keys) if @pending_keys
71
- out.int(booting? ? @init_handlers.length : 0)
72
- save_cartridge(out)
73
- address_bus.save_state(out)
74
- @cpu.save_state(out)
75
- save_trap_dos(out)
76
- save_serial_bus(out)
77
- save_reu(out)
78
- end
79
-
80
- def load_state(input)
81
- input.marker(Snapshot::C64Setup::MARKER)
82
- input.check_stamp
83
- check_setup(Snapshot::C64Setup.read(input))
84
- @cycles = input.int
85
- @nmi_asserted = input.boolean?
86
- @cartridge_nmi = input.boolean?
87
- @restore_pulse = input.boolean?
88
- @freezing = input.boolean?
89
- @freeze_writes = input.int
90
- @pending_keys = nil
91
- @pending_keys = input.ints if input.boolean?
92
- @init_handlers_lost = [input.int - @init_handlers.length, 0].max
93
- load_cartridge(input)
94
- address_bus.load_state(input)
95
- push_serial_lines
96
- @cpu.load_state(input)
97
- load_trap_dos(input)
98
- load_serial_bus(input)
99
- load_reu(input)
100
- end
101
-
102
- private
103
-
104
- def check_setup(setup)
105
- ours = Snapshot::C64Setup.of(address_bus)
106
- return if setup == ours
107
-
108
- raise Snapshot::FormatError, "the state is of a machine with #{setup}, not #{ours}"
109
- end
110
- end
111
- end
112
- end
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module Chips
5
- class CIA
6
- # A snapshot of the chip: everything it holds but its wiring, the ports,
7
- # the PB4 and CNT levels, the timers, the interrupt register, the serial
8
- # port and the TOD clock.
9
- module SavedState
10
- def save_state(out)
11
- out.marker("CIA")
12
- out.int(@data_port_a).int(@data_port_b).int(@data_dir_a).int(@data_dir_b)
13
- out.boolean(@port_b4_high).boolean(@port_b4_driven_high).boolean(@cnt_high).boolean(@cnt_rise)
14
- out.int(@control_a.value).int(@control_b.value)
15
- @ta.save_state(out)
16
- @tb.save_state(out)
17
- @icr.save_state(out)
18
- @serial.save_state(out)
19
- @tod.save_state(out)
20
- end
21
-
22
- def load_state(input)
23
- input.marker("CIA")
24
- @data_port_a = input.int
25
- @data_port_b = input.int
26
- @data_dir_a = input.int
27
- @data_dir_b = input.int
28
- @port_b4_high = input.boolean?
29
- @port_b4_driven_high = input.boolean?
30
- @cnt_high = input.boolean?
31
- @cnt_rise = input.boolean?
32
- @control_a.value = input.int
33
- @control_b.value = input.int
34
- load_parts(input)
35
- end
36
-
37
- private
38
-
39
- def load_parts(input)
40
- @ta.load_state(input)
41
- @tb.load_state(input)
42
- @icr.load_state(input)
43
- @serial.load_state(input)
44
- @tod.load_state(input)
45
- end
46
- end
47
- end
48
- end
49
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module Chips
5
- class CIA
6
- class Serial
7
- # The shift register's state for a snapshot.
8
- module SavedState
9
- def save_state(out)
10
- out.int(@data).int(@shift).int(@steps).optional_int(@empty_in).optional_int(@busy_in)
11
- out.boolean(@busy).boolean(@abandoned).optional_int(@pending).boolean(@underflow_high).boolean(@in_flight)
12
- out.int(@flight_up).int(@flight_down).boolean(@idle)
13
- [@cnt, @cnt_in, @sp_in, @sp_out].each { |level| out.boolean(level) }
14
- end
15
-
16
- def load_state(input)
17
- @data = input.int
18
- @shift = input.int
19
- @steps = input.int
20
- @empty_in = input.optional_int
21
- @busy_in = input.optional_int
22
- @busy = input.boolean?
23
- @abandoned = input.boolean?
24
- @pending = input.optional_int
25
- load_lines(input)
26
- end
27
-
28
- private
29
-
30
- def load_lines(input)
31
- @underflow_high = input.boolean?
32
- @in_flight = input.boolean?
33
- @flight_up = input.int
34
- @flight_down = input.int
35
- @idle = input.boolean?
36
- @cnt = input.boolean?
37
- @cnt_in = input.boolean?
38
- @sp_in = input.boolean?
39
- @sp_out = input.boolean?
40
- end
41
- end
42
- end
43
- end
44
- end
45
- end
@@ -1,117 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module Chips
5
- class CPU
6
- # The CPU's state for a snapshot: the registers, the interrupt lines and
7
- # their pipeline, and the step of the instruction in flight, named by
8
- # where its plan comes from.
9
- module SavedState
10
- # Writes everything the CPU holds, down to the step of the instruction
11
- # it is in, for load_state to put back. The interrupt lines, BA stalls
12
- # and SO are state too; the traps and the debug flag belong to the host.
13
- def save_state(out)
14
- out.marker("CPU")
15
- out.int(@program_counter).int(@stack_pointer).int(@a).int(@x).int(@y).int(@status.value)
16
- [@irq, @nmi, @irq_sample, @irq_pending, @nmi_sample, @nmi_pending, @skip_poll, @boundary_irq,
17
- @boundary_nmi, @boundary_crossed, @brk, @pending_write, @so_high, @optional_dummy,
18
- @branch_taken].each { |flag| out.boolean(flag) }
19
- out.optional_int(@interrupt).optional_int(@stalled_at).int(@cycles).int(@instructions)
20
- out.int(plan_source).int(@index).int(OPERATIONS.index(@operation) || -1)
21
- [@address, @dummy_address, @value, @rmw_result, @pointer].each { |register| out.optional_int(register) }
22
- end
23
-
24
- def load_state(input)
25
- input.marker("CPU")
26
- @program_counter = input.int
27
- @stack_pointer = input.int
28
- @a = input.int
29
- @x = input.int
30
- @y = input.int
31
- @status.value = input.int
32
- load_flags(input)
33
- @interrupt = input.optional_int
34
- @stalled_at = input.optional_int
35
- @cycles = input.int
36
- @instructions = input.int
37
- load_plan(input.int)
38
- @index = input.int
39
- operation = input.int
40
- @operation = operation.negative? ? nil : OPERATIONS.fetch(operation)
41
- load_working_registers(input)
42
- end
43
-
44
- # Drops the instruction or interrupt sequence in flight and the
45
- # interrupt lines' pipeline, so the next cycle fetches an opcode at the
46
- # program counter, and sets the cycle count. A snapshot taken between
47
- # instructions, as VICE's are, restores through here.
48
- def resume(cycles)
49
- @irq_sample = @irq_pending = false
50
- @nmi_sample = @nmi_pending = false
51
- @skip_poll = false
52
- @interrupt = nil
53
- @brk = false
54
- @stalled_at = nil
55
- @cycles = cycles
56
- end_sequence
57
- @pending_write = false
58
- end
59
-
60
- private
61
-
62
- # Where the plan running comes from: an opcode's microcode, or FETCH,
63
- # INTERRUPT or JAMMED below it.
64
- def plan_source
65
- return FETCH if @plan.equal?(FETCH_PLAN)
66
- return INTERRUPT if @plan.equal?(INTERRUPT_PLAN)
67
- return JAMMED if @plan.equal?(JAMMED_PLAN)
68
-
69
- MICROCODE.index { |micro| micro.plan.equal?(@plan) && micro.operation == @operation } ||
70
- MICROCODE.index { |micro| micro.plan.equal?(@plan) }
71
- end
72
-
73
- def load_plan(source)
74
- case source
75
- when FETCH then use_plan(FETCH_PLAN, FETCH_WRITES)
76
- when INTERRUPT then use_plan(INTERRUPT_PLAN, INTERRUPT_WRITES)
77
- when JAMMED then use_plan(JAMMED_PLAN, JAMMED_WRITES)
78
- else
79
- micro = MICROCODE.fetch(source)
80
- use_plan(micro.plan, micro.writes)
81
- end
82
- end
83
-
84
- def use_plan(plan, writes)
85
- @plan = plan
86
- @writes = writes
87
- end
88
-
89
- def load_flags(input)
90
- @irq = input.boolean?
91
- @nmi = input.boolean?
92
- @irq_sample = input.boolean?
93
- @irq_pending = input.boolean?
94
- @nmi_sample = input.boolean?
95
- @nmi_pending = input.boolean?
96
- @skip_poll = input.boolean?
97
- @boundary_irq = input.boolean?
98
- @boundary_nmi = input.boolean?
99
- @boundary_crossed = input.boolean?
100
- @brk = input.boolean?
101
- @pending_write = input.boolean?
102
- @so_high = input.boolean?
103
- @optional_dummy = input.boolean?
104
- @branch_taken = input.boolean?
105
- end
106
-
107
- def load_working_registers(input)
108
- @address = input.optional_int
109
- @dummy_address = input.optional_int
110
- @value = input.optional_int
111
- @rmw_result = input.optional_int
112
- @pointer = input.optional_int
113
- end
114
- end
115
- end
116
- end
117
- end