badline 0.12.1 → 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 (565) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -1
  3. data/CLAUDE.md +86 -38
  4. data/CONTRIBUTING.md +4 -3
  5. data/README.md +9 -6
  6. data/doc/library.md +9 -9
  7. data/doc/media.md +2 -1
  8. data/doc/pinned-behaviour.md +134 -105
  9. data/doc/snapshot-format.md +1047 -0
  10. data/doc/snapshots.md +73 -43
  11. data/lib/badline/audio/bare_player.rb +53 -20
  12. data/lib/badline/audio/cli.rb +6 -6
  13. data/lib/badline/audio/jukebox.rb +2 -2
  14. data/lib/badline/audio/machine_player.rb +16 -10
  15. data/lib/badline/{media → audio}/queue.rb +1 -1
  16. data/lib/badline/audio/queued_tune.rb +6 -6
  17. data/lib/badline/audio/renderer.rb +33 -22
  18. data/lib/badline/audio/stereo.rb +1 -1
  19. data/lib/badline/c128/banks.rb +6 -3
  20. data/lib/badline/c128/bus/keyed_state.rb +45 -0
  21. data/lib/badline/c128/bus.rb +35 -20
  22. data/lib/badline/c128/color_lines.rb +2 -2
  23. data/lib/badline/c128/cpu.rb +1 -1
  24. data/lib/badline/c128/drives.rb +14 -34
  25. data/lib/badline/c128/fast_serial.rb +5 -5
  26. data/lib/badline/c128/keyed_modules.rb +117 -0
  27. data/lib/badline/c128/keyed_state.rb +91 -0
  28. data/lib/badline/c128/keys.rb +9 -0
  29. data/lib/badline/c128/mmu.rb +9 -8
  30. data/lib/badline/c128/mmu_pages.rb +21 -1
  31. data/lib/badline/c128/modes.rb +21 -11
  32. data/lib/badline/c128/z80.rb +2 -2
  33. data/lib/badline/c128/z80_turns.rb +1 -1
  34. data/lib/badline/c128.rb +21 -16
  35. data/lib/badline/c64/attachments.rb +42 -0
  36. data/lib/badline/c64/banked_ram/banking.rb +32 -0
  37. data/lib/badline/c64/banked_ram/plus256k.rb +64 -0
  38. data/lib/badline/c64/banked_ram/plus60k.rb +47 -0
  39. data/lib/badline/c64/banked_ram/unexpanded.rb +30 -0
  40. data/lib/badline/c64/banked_ram.rb +23 -0
  41. data/lib/badline/c64/bus/debug_register.rb +32 -0
  42. data/lib/badline/c64/bus/extra_sids.rb +32 -0
  43. data/lib/badline/c64/bus/fittings.rb +40 -0
  44. data/lib/badline/c64/bus/keyed_state.rb +41 -0
  45. data/lib/badline/c64/bus/pla.rb +149 -0
  46. data/lib/badline/c64/bus/roms.rb +41 -0
  47. data/lib/badline/c64/bus/sid_slots.rb +44 -0
  48. data/lib/badline/c64/bus.rb +219 -0
  49. data/lib/badline/c64/cartridge/action_replay.rb +115 -0
  50. data/lib/badline/c64/cartridge/atomic_power.rb +26 -0
  51. data/lib/badline/c64/cartridge/bank.rb +83 -0
  52. data/lib/badline/c64/cartridge/comal80.rb +52 -0
  53. data/lib/badline/c64/cartridge/dinamic.rb +36 -0
  54. data/lib/badline/c64/cartridge/easy_flash.rb +132 -0
  55. data/lib/badline/c64/cartridge/epyx_fastload.rb +73 -0
  56. data/lib/badline/c64/cartridge/final_cartridge3.rb +79 -0
  57. data/lib/badline/c64/cartridge/flash.rb +279 -0
  58. data/lib/badline/c64/cartridge/freezer.rb +35 -0
  59. data/lib/badline/c64/cartridge/fun_play.rb +40 -0
  60. data/lib/badline/c64/cartridge/g_mod2.rb +64 -0
  61. data/lib/badline/c64/cartridge/game_system.rb +42 -0
  62. data/lib/badline/c64/cartridge/geo_ram.rb +65 -0
  63. data/lib/badline/c64/cartridge/kcs_power.rb +69 -0
  64. data/lib/badline/c64/cartridge/keyed_state.rb +393 -0
  65. data/lib/badline/c64/cartridge/mach5.rb +34 -0
  66. data/lib/badline/c64/cartridge/magic_desk.rb +32 -0
  67. data/lib/badline/c64/cartridge/ocean.rb +37 -0
  68. data/lib/badline/c64/cartridge/pagefox.rb +60 -0
  69. data/lib/badline/c64/cartridge/retro_replay.rb +278 -0
  70. data/lib/badline/c64/cartridge/rex_utility.rb +31 -0
  71. data/lib/badline/c64/cartridge/rgcd.rb +50 -0
  72. data/lib/badline/c64/cartridge/simons_basic.rb +37 -0
  73. data/lib/badline/c64/cartridge/standard.rb +17 -0
  74. data/lib/badline/c64/cartridge/super_games.rb +40 -0
  75. data/lib/badline/c64/cartridge/westermann.rb +32 -0
  76. data/lib/badline/c64/cartridge/zaxxon.rb +52 -0
  77. data/lib/badline/c64/cartridge.rb +232 -0
  78. data/lib/badline/c64/color_memory.rb +27 -0
  79. data/lib/badline/{computer → c64}/common.rb +2 -2
  80. data/lib/badline/{computer → c64}/kernal_traps.rb +39 -36
  81. data/lib/badline/c64/keyed_modules.rb +111 -0
  82. data/lib/badline/c64/keyed_state.rb +68 -0
  83. data/lib/badline/c64/reu/dma.rb +271 -0
  84. data/lib/badline/c64/reu/keyed_state.rb +140 -0
  85. data/lib/badline/c64/reu/ram.rb +94 -0
  86. data/lib/badline/c64/reu/trigger.rb +34 -0
  87. data/lib/badline/c64/reu.rb +289 -0
  88. data/lib/badline/c64/true_drives.rb +120 -0
  89. data/lib/badline/{computer.rb → c64.rb} +24 -15
  90. data/lib/badline/chips/cia/fast_forward.rb +62 -0
  91. data/lib/badline/chips/cia/interrupt_register.rb +128 -0
  92. data/lib/badline/chips/cia/keyed_parts.rb +213 -0
  93. data/lib/badline/chips/cia/serial.rb +246 -0
  94. data/lib/badline/chips/cia/time_of_day.rb +210 -0
  95. data/lib/badline/chips/cia/timer.rb +188 -0
  96. data/lib/badline/chips/cia.rb +281 -0
  97. data/lib/badline/chips/cpu/addressing.rb +133 -0
  98. data/lib/badline/chips/cpu/boundary.rb +56 -0
  99. data/lib/badline/chips/cpu/core.rb +183 -0
  100. data/lib/badline/chips/cpu/instruction.rb +338 -0
  101. data/lib/badline/chips/cpu/instruction_set/arithmetic.rb +118 -0
  102. data/lib/badline/chips/cpu/instruction_set/bitwise.rb +130 -0
  103. data/lib/badline/chips/cpu/instruction_set/branch.rb +83 -0
  104. data/lib/badline/chips/cpu/instruction_set/flag.rb +67 -0
  105. data/lib/badline/chips/cpu/instruction_set/illegal.rb +274 -0
  106. data/lib/badline/chips/cpu/instruction_set/inc_dec.rb +73 -0
  107. data/lib/badline/chips/cpu/instruction_set/stack.rb +56 -0
  108. data/lib/badline/chips/cpu/instruction_set/transfer.rb +141 -0
  109. data/lib/badline/chips/cpu/instruction_set.rb +59 -0
  110. data/lib/badline/chips/cpu/interrupts.rb +108 -0
  111. data/lib/badline/chips/cpu/keyed_state.rb +177 -0
  112. data/lib/badline/chips/cpu/microcode.rb +195 -0
  113. data/lib/badline/chips/cpu/operations.rb +90 -0
  114. data/lib/badline/chips/cpu/port.rb +133 -0
  115. data/lib/badline/chips/cpu/stack_operations.rb +84 -0
  116. data/lib/badline/chips/cpu/traps.rb +23 -0
  117. data/lib/badline/chips/cpu.rb +17 -0
  118. data/lib/badline/chips/sid/catch_up.rb +122 -0
  119. data/lib/badline/chips/sid/decimator.rb +68 -0
  120. data/lib/badline/chips/sid/envelope.rb +236 -0
  121. data/lib/badline/chips/sid/filter.rb +227 -0
  122. data/lib/badline/chips/sid/keyed_parts.rb +286 -0
  123. data/lib/badline/chips/sid/voice.rb +69 -0
  124. data/lib/badline/chips/sid/waveform/combined.rb +128 -0
  125. data/lib/badline/chips/sid/waveform/fast_forward.rb +107 -0
  126. data/lib/badline/chips/sid/waveform/noise_writeback.rb +124 -0
  127. data/lib/badline/chips/sid/waveform.rb +305 -0
  128. data/lib/badline/chips/sid.rb +264 -0
  129. data/lib/badline/chips/ted/beam.rb +119 -0
  130. data/lib/badline/chips/ted/timers.rb +66 -0
  131. data/lib/badline/chips/ted.rb +143 -0
  132. data/lib/badline/chips/tia.rb +49 -0
  133. data/lib/badline/chips/vdc/keyed_parts.rb +105 -0
  134. data/lib/badline/{c128 → chips}/vdc/memory.rb +1 -1
  135. data/lib/badline/{c128 → chips}/vdc/painter.rb +1 -13
  136. data/lib/badline/{c128 → chips}/vdc/raster.rb +1 -17
  137. data/lib/badline/{c128 → chips}/vdc/window.rb +1 -10
  138. data/lib/badline/{c128 → chips}/vdc.rb +6 -31
  139. data/lib/badline/chips/via/control_lines.rb +109 -0
  140. data/lib/badline/chips/via/fast_forward.rb +55 -0
  141. data/lib/badline/chips/via/interrupt_register.rb +60 -0
  142. data/lib/badline/chips/via/keyed_parts.rb +163 -0
  143. data/lib/badline/chips/via/shift_register.rb +168 -0
  144. data/lib/badline/chips/via/timer1.rb +120 -0
  145. data/lib/badline/chips/via/timer2.rb +117 -0
  146. data/lib/badline/chips/via.rb +267 -0
  147. data/lib/badline/chips/vic/bank.rb +135 -0
  148. data/lib/badline/chips/vic/border_mask.rb +78 -0
  149. data/lib/badline/chips/vic/collisions.rb +106 -0
  150. data/lib/badline/chips/vic/color_patches.rb +38 -0
  151. data/lib/badline/chips/vic/display_state.rb +168 -0
  152. data/lib/badline/chips/vic/graphics_mode.rb +166 -0
  153. data/lib/badline/chips/vic/graphics_shifter.rb +183 -0
  154. data/lib/badline/chips/vic/keyed_parts.rb +228 -0
  155. data/lib/badline/chips/vic/keyed_sprites.rb +225 -0
  156. data/lib/badline/chips/vic/keyed_state.rb +102 -0
  157. data/lib/badline/chips/vic/register_log.rb +65 -0
  158. data/lib/badline/chips/vic/registers.rb +188 -0
  159. data/lib/badline/chips/vic/sequencer.rb +275 -0
  160. data/lib/badline/chips/vic/sequencer_output.rb +118 -0
  161. data/lib/badline/chips/vic/sprite/internal_bus.rb +59 -0
  162. data/lib/badline/chips/vic/sprite/shifter.rb +148 -0
  163. data/lib/badline/chips/vic/sprite/timing.rb +58 -0
  164. data/lib/badline/chips/vic/sprite.rb +337 -0
  165. data/lib/badline/chips/vic/sprites.rb +281 -0
  166. data/lib/badline/chips/vic.rb +787 -0
  167. data/lib/badline/chips/vic_i/keyed_parts.rb +142 -0
  168. data/lib/badline/{vic20/vic → chips/vic_i}/painter.rb +2 -30
  169. data/lib/badline/chips/vic_i/sound/output.rb +85 -0
  170. data/lib/badline/chips/vic_i/sound.rb +227 -0
  171. data/lib/badline/{vic20/vic → chips/vic_i}/text_window.rb +2 -2
  172. data/lib/badline/{vic20/vic.rb → chips/vic_i.rb} +6 -6
  173. data/lib/badline/chips/z80/arithmetic.rb +119 -0
  174. data/lib/badline/chips/z80/bit_page.rb +57 -0
  175. data/lib/badline/chips/z80/block_io.rb +60 -0
  176. data/lib/badline/chips/z80/block_transfers.rb +61 -0
  177. data/lib/badline/chips/z80/bus_cycles.rb +113 -0
  178. data/lib/badline/chips/z80/core.rb +115 -0
  179. data/lib/badline/chips/z80/exchanges.rb +52 -0
  180. data/lib/badline/chips/z80/extended_page.rb +91 -0
  181. data/lib/badline/chips/z80/flags.rb +39 -0
  182. data/lib/badline/chips/z80/interrupt_acceptance.rb +48 -0
  183. data/lib/badline/chips/z80/jumps.rb +84 -0
  184. data/lib/badline/chips/z80/keyed_state.rb +73 -0
  185. data/lib/badline/chips/z80/loads.rb +100 -0
  186. data/lib/badline/chips/z80/main_page.rb +136 -0
  187. data/lib/badline/chips/z80/registers.rb +122 -0
  188. data/lib/badline/chips/z80/shifts.rb +66 -0
  189. data/lib/badline/chips/z80.rb +13 -0
  190. data/lib/badline/chips.rb +10 -0
  191. data/lib/badline/core.rb +13 -32
  192. data/lib/badline/drives/datasette/keyed_state.rb +38 -0
  193. data/lib/badline/drives/datasette.rb +173 -0
  194. data/lib/badline/drives/engine/core.rb +152 -0
  195. data/lib/badline/drives/engine/fast_serial.rb +75 -0
  196. data/lib/badline/drives/engine/idle.rb +127 -0
  197. data/lib/badline/drives/engine/idle_cpu.rb +30 -0
  198. data/lib/badline/drives/engine/orbit.rb +81 -0
  199. data/lib/badline/drives/engine/serial_lines.rb +72 -0
  200. data/lib/badline/drives/engine/sleep.rb +114 -0
  201. data/lib/badline/drives/engine/vias.rb +86 -0
  202. data/lib/badline/drives/engine/watch.rb +152 -0
  203. data/lib/badline/drives/engine.rb +11 -0
  204. data/lib/badline/drives/model1541/bus.rb +75 -0
  205. data/lib/badline/drives/model1541/byte_ready.rb +50 -0
  206. data/lib/badline/drives/model1541/cpu.rb +13 -0
  207. data/lib/badline/drives/model1541/disk.rb +318 -0
  208. data/lib/badline/drives/model1541/disk_via.rb +38 -0
  209. data/lib/badline/drives/model1541/gcr.rb +59 -0
  210. data/lib/badline/drives/model1541/keyed_state.rb +251 -0
  211. data/lib/badline/drives/model1541/mechanism.rb +313 -0
  212. data/lib/badline/drives/model1541/rotation.rb +123 -0
  213. data/lib/badline/drives/model1541/sector_reader.rb +78 -0
  214. data/lib/badline/drives/model1541/serial_port.rb +20 -0
  215. data/lib/badline/drives/model1541/track.rb +100 -0
  216. data/lib/badline/drives/model1541.rb +80 -0
  217. data/lib/badline/drives/model1571/bus.rb +100 -0
  218. data/lib/badline/drives/model1571/cpu.rb +13 -0
  219. data/lib/badline/drives/model1571/keyed_state.rb +108 -0
  220. data/lib/badline/drives/model1571/serial_port.rb +39 -0
  221. data/lib/badline/drives/model1571/serial_via.rb +27 -0
  222. data/lib/badline/drives/model1571/wd1770.rb +108 -0
  223. data/lib/badline/drives/model1571.rb +141 -0
  224. data/lib/badline/drives/model1581/bus.rb +126 -0
  225. data/lib/badline/drives/model1581/cpu.rb +13 -0
  226. data/lib/badline/drives/model1581/disk.rb +133 -0
  227. data/lib/badline/drives/model1581/keyed_state.rb +280 -0
  228. data/lib/badline/drives/model1581/mechanism.rb +98 -0
  229. data/lib/badline/drives/model1581/serial_port.rb +54 -0
  230. data/lib/badline/drives/model1581/slot.rb +61 -0
  231. data/lib/badline/drives/model1581/track.rb +102 -0
  232. data/lib/badline/drives/model1581/track_bytes.rb +77 -0
  233. data/lib/badline/drives/model1581/wd1772/registers.rb +91 -0
  234. data/lib/badline/drives/model1581/wd1772/sector_writes.rb +75 -0
  235. data/lib/badline/drives/model1581/wd1772/sectors.rb +152 -0
  236. data/lib/badline/drives/model1581/wd1772/stepping.rb +111 -0
  237. data/lib/badline/drives/model1581/wd1772/tracks.rb +127 -0
  238. data/lib/badline/drives/model1581/wd1772/turn.rb +75 -0
  239. data/lib/badline/drives/model1581/wd1772.rb +216 -0
  240. data/lib/badline/drives/model1581.rb +206 -0
  241. data/lib/badline/drives/serial_bus.rb +161 -0
  242. data/lib/badline/drives.rb +8 -0
  243. data/lib/badline/frontend/app.rb +3 -3
  244. data/lib/badline/frontend/boot.rb +4 -4
  245. data/lib/badline/frontend/controls.rb +19 -3
  246. data/lib/badline/frontend/drive_led.rb +44 -21
  247. data/lib/badline/frontend/machine_window.rb +3 -1
  248. data/lib/badline/frontend/menu/menu_dialogs.rb +2 -2
  249. data/lib/badline/frontend/player/filter_view.rb +1 -1
  250. data/lib/badline/frontend/player/player_controller.rb +2 -2
  251. data/lib/badline/frontend/player/player_screen.rb +1 -0
  252. data/lib/badline/frontend/player/theme.rb +7 -7
  253. data/lib/badline/frontend/snapshots.rb +12 -1
  254. data/lib/badline/frontend/timeline.rb +30 -12
  255. data/lib/badline/input/control_ports.rb +78 -0
  256. data/lib/badline/input/joystick.rb +27 -0
  257. data/lib/badline/input/keyboard.rb +114 -0
  258. data/lib/badline/input/matrix_typist.rb +98 -0
  259. data/lib/badline/input.rb +4 -0
  260. data/lib/badline/kernal_trap/chrout.rb +45 -0
  261. data/lib/badline/kernal_trap/{drive → dos}/block_commands.rb +1 -1
  262. data/lib/badline/kernal_trap/dos/channel.rb +156 -0
  263. data/lib/badline/kernal_trap/{drive → dos}/channels.rb +1 -26
  264. data/lib/badline/kernal_trap/{drive → dos}/memory.rb +1 -10
  265. data/lib/badline/kernal_trap/{drive → dos}/parameters.rb +1 -1
  266. data/lib/badline/kernal_trap/{drive → dos}/status.rb +1 -9
  267. data/lib/badline/kernal_trap/{drive → dos}/write_file.rb +1 -19
  268. data/lib/badline/kernal_trap/{drive → dos}/writes.rb +1 -1
  269. data/lib/badline/kernal_trap/{drive.rb → dos.rb} +9 -27
  270. data/lib/badline/kernal_trap/file_routine.rb +4 -4
  271. data/lib/badline/kernal_trap/keyed_state.rb +150 -0
  272. data/lib/badline/kernal_trap/layout.rb +75 -11
  273. data/lib/badline/kernal_trap/load.rb +19 -21
  274. data/lib/badline/kernal_trap/routine.rb +12 -0
  275. data/lib/badline/kernal_trap/save.rb +12 -22
  276. data/lib/badline/kernal_trap/serial.rb +8 -24
  277. data/lib/badline/kernal_trap.rb +3 -2
  278. data/lib/badline/machine/clocking.rb +1 -1
  279. data/lib/badline/machine/keyboard_buffer.rb +49 -0
  280. data/lib/badline/machine/settling.rb +29 -0
  281. data/lib/badline/machine.rb +10 -7
  282. data/lib/badline/media/boot_disk.rb +14 -2
  283. data/lib/badline/media/extensions.rb +10 -0
  284. data/lib/badline/media/true_drive.rb +1 -1
  285. data/lib/badline/media/tune.rb +2 -2
  286. data/lib/badline/media.rb +3 -3
  287. data/lib/badline/memory.rb +3 -6
  288. data/lib/badline/model.rb +1 -1
  289. data/lib/badline/options/family.rb +5 -2
  290. data/lib/badline/options/help.rb +42 -16
  291. data/lib/badline/options/table.rb +2 -0
  292. data/lib/badline/options/validation.rb +2 -0
  293. data/lib/badline/options.rb +6 -1
  294. data/lib/badline/plus4/acia.rb +45 -0
  295. data/lib/badline/plus4/bus.rb +312 -0
  296. data/lib/badline/plus4/cpu.rb +10 -0
  297. data/lib/badline/plus4/cpu_port.rb +93 -0
  298. data/lib/badline/plus4/keyboard_port.rb +51 -0
  299. data/lib/badline/plus4/model.rb +38 -0
  300. data/lib/badline/plus4/user_port.rb +31 -0
  301. data/lib/badline/plus4.rb +164 -0
  302. data/lib/badline/roms/README +44 -6
  303. data/lib/badline/roms/plus4/basic.rom +0 -0
  304. data/lib/badline/roms/plus4/function-high.rom +0 -0
  305. data/lib/badline/roms/plus4/function-low.rom +0 -0
  306. data/lib/badline/roms/plus4/kernal-ntsc.rom +0 -0
  307. data/lib/badline/roms/plus4/kernal-pal.rom +0 -0
  308. data/lib/badline/sdl.rb +1 -0
  309. data/lib/badline/{storage/sid_file.rb → sid_tune/file.rb} +3 -3
  310. data/lib/badline/{storage → sid_tune}/hvsc.rb +7 -7
  311. data/lib/badline/{storage → sid_tune}/song_lengths.rb +2 -2
  312. data/lib/badline/{storage → sid_tune}/stil/credit.rb +1 -1
  313. data/lib/badline/{storage → sid_tune}/stil.rb +3 -3
  314. data/lib/badline/sid_tune.rb +6 -0
  315. data/lib/badline/snapshot/c128_setup.rb +32 -0
  316. data/lib/badline/snapshot/c64_setup.rb +83 -0
  317. data/lib/badline/snapshot/container.rb +4 -0
  318. data/lib/badline/snapshot/field_doc/markdown.rb +112 -0
  319. data/lib/badline/snapshot/field_doc.rb +109 -0
  320. data/lib/badline/snapshot/image.rb +132 -46
  321. data/lib/badline/snapshot/keyed/cursor.rb +40 -0
  322. data/lib/badline/snapshot/keyed/modules.rb +66 -0
  323. data/lib/badline/snapshot/keyed/reader.rb +188 -0
  324. data/lib/badline/snapshot/keyed/recorder.rb +88 -0
  325. data/lib/badline/snapshot/keyed/report.rb +26 -0
  326. data/lib/badline/snapshot/keyed/writer.rb +55 -0
  327. data/lib/badline/snapshot/keyed.rb +64 -0
  328. data/lib/badline/snapshot/machine_state.rb +17 -64
  329. data/lib/badline/snapshot/storage_setup.rb +63 -0
  330. data/lib/badline/snapshot/vic20_setup.rb +28 -0
  331. data/lib/badline/snapshot/vice/c64_mem.rb +1 -1
  332. data/lib/badline/snapshot/vice/restore.rb +1 -1
  333. data/lib/badline/snapshot/vice/reu1764.rb +3 -3
  334. data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
  335. data/lib/badline/snapshot/vice.rb +13 -35
  336. data/lib/badline/snapshot.rb +44 -22
  337. data/lib/badline/storage/crt_file.rb +3 -1
  338. data/lib/badline/storage/d64_image.rb +0 -2
  339. data/lib/badline/storage/d71_image.rb +0 -2
  340. data/lib/badline/storage/d81_image.rb +0 -2
  341. data/lib/badline/storage/disk_image.rb +3 -6
  342. data/lib/badline/storage/g64_image.rb +10 -5
  343. data/lib/badline/storage/host_directory.rb +0 -5
  344. data/lib/badline/storage/t64.rb +2 -8
  345. data/lib/badline/storage/tap.rb +43 -15
  346. data/lib/badline/storage/unavailable.rb +1 -1
  347. data/lib/badline/storage.rb +0 -37
  348. data/lib/badline/support/c128_checkpoint.rb +39 -0
  349. data/lib/badline/support/checkpoint.rb +108 -0
  350. data/lib/badline/support/vic20_checkpoint.rb +38 -0
  351. data/lib/badline/support.rb +5 -0
  352. data/lib/badline/version.rb +1 -1
  353. data/lib/badline/vic20/attachments.rb +8 -5
  354. data/lib/badline/vic20/bus/keyed_state.rb +52 -0
  355. data/lib/badline/vic20/bus.rb +2 -25
  356. data/lib/badline/vic20/cpu.rb +1 -1
  357. data/lib/badline/vic20/keyed_modules.rb +73 -0
  358. data/lib/badline/vic20/keyed_state.rb +45 -0
  359. data/lib/badline/vic20/port_wiring.rb +4 -4
  360. data/lib/badline/vic20/user_via_ports.rb +2 -2
  361. data/lib/badline/vic20.rb +22 -17
  362. data/lib/badline.rb +1 -0
  363. metadata +271 -228
  364. data/lib/badline/address_bus/extra_sids.rb +0 -30
  365. data/lib/badline/address_bus/fittings.rb +0 -38
  366. data/lib/badline/address_bus/pla.rb +0 -147
  367. data/lib/badline/address_bus/roms.rb +0 -39
  368. data/lib/badline/address_bus/saved_state.rb +0 -66
  369. data/lib/badline/address_bus/sid_slots.rb +0 -42
  370. data/lib/badline/address_bus.rb +0 -216
  371. data/lib/badline/c128/bus_state.rb +0 -53
  372. data/lib/badline/c128/saved_state.rb +0 -143
  373. data/lib/badline/cartridge/action_replay.rb +0 -126
  374. data/lib/badline/cartridge/atomic_power.rb +0 -24
  375. data/lib/badline/cartridge/bank.rb +0 -81
  376. data/lib/badline/cartridge/comal80.rb +0 -50
  377. data/lib/badline/cartridge/dinamic.rb +0 -34
  378. data/lib/badline/cartridge/easy_flash.rb +0 -145
  379. data/lib/badline/cartridge/epyx_fastload.rb +0 -79
  380. data/lib/badline/cartridge/final_cartridge3.rb +0 -89
  381. data/lib/badline/cartridge/flash.rb +0 -306
  382. data/lib/badline/cartridge/freezer.rb +0 -33
  383. data/lib/badline/cartridge/fun_play.rb +0 -38
  384. data/lib/badline/cartridge/g_mod2.rb +0 -74
  385. data/lib/badline/cartridge/game_system.rb +0 -40
  386. data/lib/badline/cartridge/geo_ram.rb +0 -79
  387. data/lib/badline/cartridge/kcs_power.rb +0 -75
  388. data/lib/badline/cartridge/mach5.rb +0 -32
  389. data/lib/badline/cartridge/magic_desk.rb +0 -30
  390. data/lib/badline/cartridge/ocean.rb +0 -35
  391. data/lib/badline/cartridge/pagefox.rb +0 -68
  392. data/lib/badline/cartridge/retro_replay.rb +0 -320
  393. data/lib/badline/cartridge/rex_utility.rb +0 -29
  394. data/lib/badline/cartridge/rgcd.rb +0 -58
  395. data/lib/badline/cartridge/simons_basic.rb +0 -35
  396. data/lib/badline/cartridge/standard.rb +0 -15
  397. data/lib/badline/cartridge/super_games.rb +0 -48
  398. data/lib/badline/cartridge/westermann.rb +0 -30
  399. data/lib/badline/cartridge/zaxxon.rb +0 -66
  400. data/lib/badline/cartridge.rb +0 -303
  401. data/lib/badline/checkpoint.rb +0 -98
  402. data/lib/badline/chrout_trap.rb +0 -43
  403. data/lib/badline/cia/fast_forward.rb +0 -60
  404. data/lib/badline/cia/interrupt_register.rb +0 -143
  405. data/lib/badline/cia/serial.rb +0 -275
  406. data/lib/badline/cia/state.rb +0 -47
  407. data/lib/badline/cia/timer.rb +0 -206
  408. data/lib/badline/cia.rb +0 -279
  409. data/lib/badline/color_memory.rb +0 -25
  410. data/lib/badline/computer/attachments.rb +0 -88
  411. data/lib/badline/computer/saved_state.rb +0 -117
  412. data/lib/badline/computer/true_drives.rb +0 -69
  413. data/lib/badline/control_ports.rb +0 -76
  414. data/lib/badline/cpu/addressing.rb +0 -131
  415. data/lib/badline/cpu/boundary.rb +0 -54
  416. data/lib/badline/cpu/core.rb +0 -165
  417. data/lib/badline/cpu/microcode.rb +0 -177
  418. data/lib/badline/cpu/operations.rb +0 -88
  419. data/lib/badline/cpu/saved_state.rb +0 -115
  420. data/lib/badline/cpu/stack_operations.rb +0 -82
  421. data/lib/badline/cpu.rb +0 -10
  422. data/lib/badline/cpu_port.rb +0 -112
  423. data/lib/badline/datasette.rb +0 -161
  424. data/lib/badline/debug_register.rb +0 -28
  425. data/lib/badline/drive/core.rb +0 -147
  426. data/lib/badline/drive/fast_serial.rb +0 -73
  427. data/lib/badline/drive/idle.rb +0 -125
  428. data/lib/badline/drive/idle_cpu.rb +0 -28
  429. data/lib/badline/drive/orbit.rb +0 -79
  430. data/lib/badline/drive/serial_lines.rb +0 -73
  431. data/lib/badline/drive/sleep.rb +0 -112
  432. data/lib/badline/drive/vias.rb +0 -84
  433. data/lib/badline/drive/watch.rb +0 -150
  434. data/lib/badline/drive.rb +0 -11
  435. data/lib/badline/drive1541/bus.rb +0 -86
  436. data/lib/badline/drive1541/byte_ready.rb +0 -48
  437. data/lib/badline/drive1541/cpu.rb +0 -11
  438. data/lib/badline/drive1541/disk.rb +0 -315
  439. data/lib/badline/drive1541/disk_state.rb +0 -86
  440. data/lib/badline/drive1541/disk_via.rb +0 -36
  441. data/lib/badline/drive1541/gcr.rb +0 -57
  442. data/lib/badline/drive1541/mechanism.rb +0 -313
  443. data/lib/badline/drive1541/mechanism_state.rb +0 -68
  444. data/lib/badline/drive1541/rotation.rb +0 -121
  445. data/lib/badline/drive1541/sector_reader.rb +0 -76
  446. data/lib/badline/drive1541/serial_port.rb +0 -18
  447. data/lib/badline/drive1541/track.rb +0 -98
  448. data/lib/badline/drive1541.rb +0 -111
  449. data/lib/badline/drive1571/bus.rb +0 -111
  450. data/lib/badline/drive1571/cpu.rb +0 -11
  451. data/lib/badline/drive1571/serial_port.rb +0 -37
  452. data/lib/badline/drive1571/serial_via.rb +0 -25
  453. data/lib/badline/drive1571/wd1770.rb +0 -120
  454. data/lib/badline/drive1571.rb +0 -175
  455. data/lib/badline/drive1581/bus.rb +0 -137
  456. data/lib/badline/drive1581/cpu.rb +0 -11
  457. data/lib/badline/drive1581/disk.rb +0 -135
  458. data/lib/badline/drive1581/disk_state.rb +0 -87
  459. data/lib/badline/drive1581/mechanism.rb +0 -117
  460. data/lib/badline/drive1581/serial_port.rb +0 -52
  461. data/lib/badline/drive1581/slot.rb +0 -78
  462. data/lib/badline/drive1581/track.rb +0 -100
  463. data/lib/badline/drive1581/track_bytes.rb +0 -75
  464. data/lib/badline/drive1581/wd1772/registers.rb +0 -89
  465. data/lib/badline/drive1581/wd1772/sector_writes.rb +0 -73
  466. data/lib/badline/drive1581/wd1772/sectors.rb +0 -150
  467. data/lib/badline/drive1581/wd1772/state.rb +0 -66
  468. data/lib/badline/drive1581/wd1772/stepping.rb +0 -109
  469. data/lib/badline/drive1581/wd1772/tracks.rb +0 -125
  470. data/lib/badline/drive1581/wd1772/turn.rb +0 -73
  471. data/lib/badline/drive1581/wd1772.rb +0 -216
  472. data/lib/badline/drive1581.rb +0 -233
  473. data/lib/badline/iec_bus.rb +0 -159
  474. data/lib/badline/instruction.rb +0 -334
  475. data/lib/badline/instruction_set/arithmetic.rb +0 -114
  476. data/lib/badline/instruction_set/bitwise.rb +0 -126
  477. data/lib/badline/instruction_set/branch.rb +0 -79
  478. data/lib/badline/instruction_set/flag.rb +0 -63
  479. data/lib/badline/instruction_set/illegal.rb +0 -270
  480. data/lib/badline/instruction_set/inc_dec.rb +0 -69
  481. data/lib/badline/instruction_set/stack.rb +0 -52
  482. data/lib/badline/instruction_set/transfer.rb +0 -137
  483. data/lib/badline/instruction_set.rb +0 -55
  484. data/lib/badline/interrupts.rb +0 -104
  485. data/lib/badline/joystick.rb +0 -25
  486. data/lib/badline/kernal_trap/channel.rb +0 -181
  487. data/lib/badline/keyboard.rb +0 -112
  488. data/lib/badline/keyboard_buffer.rb +0 -33
  489. data/lib/badline/ram_expansion/banking.rb +0 -30
  490. data/lib/badline/ram_expansion/plus256k.rb +0 -54
  491. data/lib/badline/ram_expansion/plus60k.rb +0 -43
  492. data/lib/badline/ram_expansion/unexpanded.rb +0 -28
  493. data/lib/badline/ram_expansion.rb +0 -21
  494. data/lib/badline/reu/dma/saved_state.rb +0 -50
  495. data/lib/badline/reu/dma.rb +0 -273
  496. data/lib/badline/reu/ram.rb +0 -107
  497. data/lib/badline/reu/saved_state.rb +0 -80
  498. data/lib/badline/reu/trigger.rb +0 -32
  499. data/lib/badline/reu.rb +0 -289
  500. data/lib/badline/sid/catch_up.rb +0 -120
  501. data/lib/badline/sid/decimator.rb +0 -64
  502. data/lib/badline/sid/envelope/state.rb +0 -68
  503. data/lib/badline/sid/envelope.rb +0 -239
  504. data/lib/badline/sid/filter.rb +0 -263
  505. data/lib/badline/sid/voice.rb +0 -77
  506. data/lib/badline/sid/waveform/combined.rb +0 -126
  507. data/lib/badline/sid/waveform/fast_forward.rb +0 -105
  508. data/lib/badline/sid/waveform/noise_writeback.rb +0 -122
  509. data/lib/badline/sid/waveform/state.rb +0 -66
  510. data/lib/badline/sid/waveform.rb +0 -305
  511. data/lib/badline/sid.rb +0 -303
  512. data/lib/badline/snapshot/setup.rb +0 -75
  513. data/lib/badline/snapshot/state.rb +0 -189
  514. data/lib/badline/time_of_day.rb +0 -228
  515. data/lib/badline/traps.rb +0 -19
  516. data/lib/badline/via/control_lines.rb +0 -122
  517. data/lib/badline/via/fast_forward.rb +0 -53
  518. data/lib/badline/via/interrupt_register.rb +0 -67
  519. data/lib/badline/via/shift_register.rb +0 -180
  520. data/lib/badline/via/state.rb +0 -42
  521. data/lib/badline/via/timer1.rb +0 -131
  522. data/lib/badline/via/timer2.rb +0 -133
  523. data/lib/badline/via.rb +0 -266
  524. data/lib/badline/vic/bank.rb +0 -133
  525. data/lib/badline/vic/border_mask.rb +0 -86
  526. data/lib/badline/vic/collisions.rb +0 -115
  527. data/lib/badline/vic/color_patches.rb +0 -47
  528. data/lib/badline/vic/display_state.rb +0 -185
  529. data/lib/badline/vic/graphics_mode.rb +0 -164
  530. data/lib/badline/vic/graphics_shifter.rb +0 -207
  531. data/lib/badline/vic/register_log.rb +0 -81
  532. data/lib/badline/vic/registers.rb +0 -195
  533. data/lib/badline/vic/sequencer.rb +0 -275
  534. data/lib/badline/vic/sequencer_output.rb +0 -116
  535. data/lib/badline/vic/sequencer_state.rb +0 -89
  536. data/lib/badline/vic/sprite/internal_bus.rb +0 -68
  537. data/lib/badline/vic/sprite/saved_state.rb +0 -64
  538. data/lib/badline/vic/sprite/shifter.rb +0 -146
  539. data/lib/badline/vic/sprite/timing.rb +0 -56
  540. data/lib/badline/vic/sprite.rb +0 -337
  541. data/lib/badline/vic/sprites.rb +0 -282
  542. data/lib/badline/vic/sprites_state.rb +0 -57
  543. data/lib/badline/vic.rb +0 -853
  544. data/lib/badline/vic20/saved_state.rb +0 -124
  545. data/lib/badline/vic20/sound/output.rb +0 -83
  546. data/lib/badline/vic20/sound.rb +0 -233
  547. data/lib/badline/vic20/vic/saved_state.rb +0 -55
  548. data/lib/badline/z80/arithmetic.rb +0 -117
  549. data/lib/badline/z80/bit_page.rb +0 -55
  550. data/lib/badline/z80/block_io.rb +0 -58
  551. data/lib/badline/z80/block_transfers.rb +0 -59
  552. data/lib/badline/z80/bus_cycles.rb +0 -111
  553. data/lib/badline/z80/core.rb +0 -113
  554. data/lib/badline/z80/exchanges.rb +0 -50
  555. data/lib/badline/z80/extended_page.rb +0 -89
  556. data/lib/badline/z80/flags.rb +0 -37
  557. data/lib/badline/z80/interrupt_acceptance.rb +0 -46
  558. data/lib/badline/z80/jumps.rb +0 -82
  559. data/lib/badline/z80/loads.rb +0 -98
  560. data/lib/badline/z80/main_page.rb +0 -134
  561. data/lib/badline/z80/registers.rb +0 -120
  562. data/lib/badline/z80/saved_state.rb +0 -69
  563. data/lib/badline/z80/shifts.rb +0 -64
  564. data/lib/badline/z80.rb +0 -11
  565. /data/lib/badline/snapshot/{fields.rb → vice/fields.rb} +0 -0
@@ -0,0 +1,228 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIC
6
+ class Registers
7
+ # The registers as the VIC holds them. The IRQ line comes from
8
+ # $D019 and $D01A on load.
9
+ module KeyedState
10
+ def save_fields(out)
11
+ out.bytes("registers", @bytes)
12
+ end
13
+
14
+ def load_fields(input)
15
+ input.bytes_into("registers", @bytes)
16
+ end
17
+
18
+ def restored! = update_irq_line
19
+ end
20
+
21
+ include KeyedState
22
+ end
23
+
24
+ class DisplayState
25
+ # The video counters, the row counter, display or idle state, the
26
+ # bad line conditions and BA.
27
+ module KeyedState
28
+ def save_fields(out)
29
+ out.int("vc_base", @vc_base).int("vc", @vc).int("vmli", @vmli).int("rc", @rc)
30
+ out.bool("display_state", @display).bool("bad_lines_enabled", @bad_lines_enabled).bool("matched", @matched)
31
+ out.optional_int("ba", @ba)
32
+ out.int("line_bits", @line_bits).bool("den_line", @den_line).bool("in_window", @in_window)
33
+ end
34
+
35
+ def load_fields(input)
36
+ @vc_base = input.masked("vc_base", @vc_base, 0x3ff)
37
+ @vc = input.masked("vc", @vc, 0x3ff)
38
+ @vmli = input.int("vmli", @vmli)
39
+ @rc = input.masked("rc", @rc, 0x07)
40
+ @display = input.bool("display_state", @display)
41
+ @bad_lines_enabled = input.bool("bad_lines_enabled", @bad_lines_enabled)
42
+ @matched = input.bool("matched", @matched)
43
+ @ba = input.optional_int("ba")
44
+ @line_bits = input.int("line_bits", @line_bits)
45
+ @den_line = input.bool("den_line", @den_line)
46
+ @in_window = input.bool("in_window", @in_window)
47
+ end
48
+ end
49
+
50
+ include KeyedState
51
+ end
52
+
53
+ class GraphicsShifter
54
+ # The pipeline between the g-access and the pixels, under `prefix`.
55
+ module KeyedState
56
+ def save_fields(out, prefix)
57
+ out.int("#{prefix}next_ecm_bmm", @next_ecm_bmm).int("#{prefix}black_below", @black_below)
58
+ out.ints("#{prefix}colors", @colors).ints("#{prefix}fg", @fg.map { |set| set ? 1 : 0 })
59
+ out.int("#{prefix}gbuf", @gbuf).int("#{prefix}vbuf", @vbuf).int("#{prefix}cbuf", @cbuf)
60
+ out.int("#{prefix}flop", @flop).int("#{prefix}pixel", @pixel).int("#{prefix}mode_lookup", @mode_lookup)
61
+ out.int("#{prefix}mode_read", @mode_read).bool("#{prefix}late_mcm", @late_mcm)
62
+ out.bool("#{prefix}late_read", @late_read)
63
+ end
64
+
65
+ def load_fields(input, prefix)
66
+ @next_ecm_bmm = input.int("#{prefix}next_ecm_bmm", @next_ecm_bmm)
67
+ @black_below = input.int("#{prefix}black_below", @black_below)
68
+ input.ints_into("#{prefix}colors", @colors)
69
+ fg = input.ints("#{prefix}fg", @fg.map { |set| set ? 1 : 0 })
70
+ @fg.each_index { |index| @fg[index] = fg.fetch(index, 0) == 1 }
71
+ @gbuf = input.int("#{prefix}gbuf", @gbuf)
72
+ @vbuf = input.int("#{prefix}vbuf", @vbuf)
73
+ @cbuf = input.int("#{prefix}cbuf", @cbuf)
74
+ @flop = input.int("#{prefix}flop", @flop)
75
+ @pixel = input.int("#{prefix}pixel", @pixel)
76
+ @mode_lookup = input.int("#{prefix}mode_lookup", @mode_lookup)
77
+ @mode_read = input.int("#{prefix}mode_read", @mode_read)
78
+ @late_mcm = input.bool("#{prefix}late_mcm", @late_mcm)
79
+ @late_read = input.bool("#{prefix}late_read", @late_read)
80
+ end
81
+ end
82
+
83
+ include KeyedState
84
+ end
85
+
86
+ class BorderMask
87
+ # The line's border coverage, under `prefix`.
88
+ module KeyedState
89
+ def save_fields(out, prefix)
90
+ out.ints("#{prefix}groups", @groups).ints("#{prefix}mask", @mask.map { |set| set ? 1 : 0 })
91
+ out.bytes("#{prefix}snapshot", @snapshot)
92
+ end
93
+
94
+ def load_fields(input, prefix)
95
+ input.ints_into("#{prefix}groups", @groups)
96
+ mask = input.ints("#{prefix}mask", @mask.map { |set| set ? 1 : 0 })
97
+ @mask.each_index { |index| @mask[index] = mask.fetch(index, 0) == 1 }
98
+ input.bytes_into("#{prefix}snapshot", @snapshot)
99
+ end
100
+ end
101
+
102
+ include KeyedState
103
+ end
104
+
105
+ class ColorPatches
106
+ # The line's colour writes, four values to a patch, under `prefix`.
107
+ module KeyedState
108
+ def save_fields(out, prefix)
109
+ out.ints("#{prefix}patches", @patches.flatten)
110
+ end
111
+
112
+ def load_fields(input, prefix)
113
+ values = input.ints("#{prefix}patches", [])
114
+ @patches.replace(values.each_slice(4).to_a)
115
+ end
116
+ end
117
+
118
+ include KeyedState
119
+ end
120
+
121
+ class Sequencer
122
+ # The sequencer's fields: the border flip-flops and compares, the
123
+ # pixel pipeline and the shifter, with the line batch under
124
+ # `line_prefix` when `line` is true. Foreground masks go as text:
125
+ # "shifter", or the mode table and the data byte.
126
+ module KeyedState
127
+ # The foreground patterns' codes: the shifter's own, HIRES_FG's by
128
+ # index, and PAIR_FG's after them.
129
+ FG_SHIFTER = -1
130
+ PAIR_CODES = 256
131
+
132
+ def save_fields(out, line_prefix)
133
+ out.bool("first_csel", @first_csel).optional_int("left_vertical_border", left_vertical_code)
134
+ out.ints("cur_colors", @cur_colors).text("cur_fg", fg_name(@cur_fg))
135
+ out.ints("prev_colors", @prev_colors).text("prev_fg", fg_name(@prev_fg))
136
+ out.bool("vertical_border", @vertical_border).bool("vertical_armed", @vertical_armed)
137
+ out.bool("main_border", @main_border).int("xscroll", @xscroll).int("last_shift", @last_shift)
138
+ out.int("last_mode", @last_mode).bool("settling", @settling).bool("prev_fresh", @prev_fresh)
139
+ out.bool("check", @check)
140
+ @shifter.save_fields(out, "shifter.")
141
+ out.int("#{line_prefix}number", @line).bytes("#{line_prefix}colors", @colors)
142
+ out.ints("#{line_prefix}fg", @fg.map { |set| set ? 1 : 0 })
143
+ @border_mask.save_fields(out, "#{line_prefix}border.")
144
+ @color_patches.save_fields(out, line_prefix)
145
+ end
146
+
147
+ def load_fields(input, line_prefix, line)
148
+ @first_csel = input.bool("first_csel", @first_csel)
149
+ left = input.optional_int("left_vertical_border")
150
+ @left_vertical_border = left.nil? ? nil : left == 1
151
+ input.ints_into("cur_colors", @cur_colors)
152
+ @cur_fg = fg_named(input.text("cur_fg", fg_name(@cur_fg)))
153
+ input.ints_into("prev_colors", @prev_colors)
154
+ @prev_fg = fg_named(input.text("prev_fg", fg_name(@prev_fg)))
155
+ load_pipeline_fields(input)
156
+ @shifter.load_fields(input, "shifter.")
157
+ load_line_fields(input, line_prefix) if line
158
+ end
159
+
160
+ private
161
+
162
+ def left_vertical_code
163
+ left = @left_vertical_border
164
+ return nil if left.nil?
165
+
166
+ left ? 1 : 0
167
+ end
168
+
169
+ def load_pipeline_fields(input)
170
+ @vertical_border = input.bool("vertical_border", @vertical_border)
171
+ @vertical_armed = input.bool("vertical_armed", @vertical_armed)
172
+ @main_border = input.bool("main_border", @main_border)
173
+ @xscroll = input.masked("xscroll", @xscroll, 0x07)
174
+ @last_shift = input.int("last_shift", @last_shift)
175
+ @last_mode = input.int("last_mode", @last_mode)
176
+ @settling = input.bool("settling", @settling)
177
+ @prev_fresh = input.bool("prev_fresh", @prev_fresh)
178
+ @check = input.bool("check", @check)
179
+ end
180
+
181
+ def load_line_fields(input, line_prefix)
182
+ @line = input.int("#{line_prefix}number", @line)
183
+ input.bytes_into("#{line_prefix}colors", @colors)
184
+ fg = input.ints("#{line_prefix}fg", @fg.map { |set| set ? 1 : 0 })
185
+ @fg.each_index { |index| @fg[index] = fg.fetch(index, 0) == 1 }
186
+ @border_mask.load_fields(input, "#{line_prefix}border.")
187
+ @color_patches.load_fields(input, line_prefix)
188
+ end
189
+
190
+ def fg_name(pattern)
191
+ code = fg_code(pattern)
192
+ return "shifter" if code == FG_SHIFTER
193
+ return "hires:#{code}" if code < PAIR_CODES
194
+
195
+ "pair:#{code - PAIR_CODES}"
196
+ end
197
+
198
+ def fg_named(name)
199
+ return @shifter.fg if name == "shifter"
200
+
201
+ table, number = name.split(":")
202
+ index = number.to_i
203
+ return GraphicsMode::PAIR_FG.fetch(index.clamp(0, GraphicsMode::PAIR_FG.length - 1)) if table == "pair"
204
+
205
+ GraphicsMode::HIRES_FG.fetch(index.clamp(0, GraphicsMode::HIRES_FG.length - 1))
206
+ end
207
+
208
+ def fg_code(pattern)
209
+ return FG_SHIFTER if pattern.equal?(@shifter.fg)
210
+
211
+ hires = GraphicsMode::HIRES_FG.index { |fg| fg.equal?(pattern) }
212
+ return hires if hires
213
+
214
+ pair = GraphicsMode::PAIR_FG.index { |fg| fg.equal?(pattern) }
215
+ raise ArgumentError, "a foreground mask the sequencer doesn't know" unless pair
216
+
217
+ PAIR_CODES + pair
218
+ end
219
+ end
220
+
221
+ include KeyedState
222
+ end
223
+ end
224
+ end
225
+ end
226
+
227
+ require "badline/chips/vic/keyed_sprites"
228
+ require "badline/chips/vic/keyed_state"
@@ -0,0 +1,225 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIC
6
+ class Sprite
7
+ # A sprite's fields under `prefix`: its DMA and display, MC, MCBASE
8
+ # and the expansion flip-flop, the fetch in progress and the shift
9
+ # register, and the line batch under `line_prefix` when `line` is
10
+ # true.
11
+ module KeyedState
12
+ # The shift register, MC, MCBASE, the expansion flip-flop and whether
13
+ # the sprite shows, for a VICE snapshot.
14
+ attr_reader :sr, :mc, :mcbase, :exp_ff, :display_on
15
+
16
+ # Sets MC, MCBASE, the expansion flip-flop, whether the sprite's DMA
17
+ # runs and whether it shows, as a VICE snapshot gives them.
18
+ def restore_counters(counter, base, expanded, dma, shows)
19
+ @mc = counter
20
+ @mcbase = base
21
+ @exp_ff = expanded
22
+ @dma = dma
23
+ @display_on = shows
24
+ end
25
+
26
+ def save_fields(out, prefix, line_prefix)
27
+ out.bool("#{prefix}dma", @dma).bool("#{prefix}display_on", @display_on).int("#{prefix}mcbase", @mcbase)
28
+ out.int("#{prefix}mc", @mc).bool("#{prefix}exp_ff", @exp_ff).optional_int("#{prefix}crunched_mc",
29
+ @crunched_mc)
30
+ out.int("#{prefix}bits", @bits).bool("#{prefix}row_ready", @row_ready)
31
+ out.optional_int("#{prefix}prev_bits", @prev_bits).bool("#{prefix}first_byte_lost", @first_byte_lost)
32
+ out.bool("#{prefix}blind", @blind).int("#{prefix}sr", @sr).int("#{prefix}latch", @latch)
33
+ out.bool("#{prefix}mc_flop", @mc_flop).bool("#{prefix}xe_flop", @xe_flop)
34
+ save_line_fields(out, line_prefix)
35
+ end
36
+
37
+ def load_fields(input, prefix, line_prefix, line)
38
+ @dma = input.bool("#{prefix}dma", @dma)
39
+ @display_on = input.bool("#{prefix}display_on", @display_on)
40
+ @mcbase = input.masked("#{prefix}mcbase", @mcbase, 0x3f)
41
+ @mc = input.masked("#{prefix}mc", @mc, 0x3f)
42
+ @exp_ff = input.bool("#{prefix}exp_ff", @exp_ff)
43
+ @crunched_mc = input.optional_int("#{prefix}crunched_mc")
44
+ @bits = input.int("#{prefix}bits", @bits)
45
+ @row_ready = input.bool("#{prefix}row_ready", @row_ready)
46
+ @prev_bits = input.optional_int("#{prefix}prev_bits")
47
+ @first_byte_lost = input.bool("#{prefix}first_byte_lost", @first_byte_lost)
48
+ @blind = input.bool("#{prefix}blind", @blind)
49
+ @sr = input.int("#{prefix}sr", @sr)
50
+ @latch = input.int("#{prefix}latch", @latch)
51
+ @mc_flop = input.bool("#{prefix}mc_flop", @mc_flop)
52
+ @xe_flop = input.bool("#{prefix}xe_flop", @xe_flop)
53
+ load_line_fields(input, line_prefix) if line
54
+ end
55
+
56
+ private
57
+
58
+ def save_line_fields(out, prefix)
59
+ out.int("#{prefix}show_from", @show_from).optional_int("#{prefix}stop_x", @stop_x)
60
+ out.ints("#{prefix}codes", @codes).int("#{prefix}leftmost", @leftmost).int("#{prefix}span", @span)
61
+ out.ints("#{prefix}reload_codes", @reload_codes).int("#{prefix}reload_leftmost", @reload_leftmost)
62
+ out.int("#{prefix}reload_span", @reload_span)
63
+ end
64
+
65
+ def load_line_fields(input, prefix)
66
+ @show_from = input.int("#{prefix}show_from", @show_from)
67
+ @stop_x = input.optional_int("#{prefix}stop_x")
68
+ input.ints_into("#{prefix}codes", @codes)
69
+ @leftmost = input.int("#{prefix}leftmost", @leftmost)
70
+ @span = input.int("#{prefix}span", @span)
71
+ input.ints_into("#{prefix}reload_codes", @reload_codes)
72
+ @reload_leftmost = input.int("#{prefix}reload_leftmost", @reload_leftmost)
73
+ @reload_span = input.int("#{prefix}reload_span", @reload_span)
74
+ end
75
+ end
76
+
77
+ include KeyedState
78
+
79
+ class InternalBus
80
+ # The sprites' internal bus, under `prefix`.
81
+ module KeyedState
82
+ def save_fields(out, prefix)
83
+ out.int("#{prefix}lines", @lines).int("#{prefix}ghost", @ghost).ints("#{prefix}value", @value)
84
+ out.ints("#{prefix}line", @line)
85
+ end
86
+
87
+ def load_fields(input, prefix)
88
+ @lines = input.int("#{prefix}lines", @lines)
89
+ @ghost = input.byte("#{prefix}ghost", @ghost)
90
+ input.ints_into("#{prefix}value", @value)
91
+ input.ints_into("#{prefix}line", @line)
92
+ end
93
+ end
94
+
95
+ include KeyedState
96
+ end
97
+ end
98
+
99
+ class Collisions
100
+ # The read-clear timing at the beam, and the line's coverage under
101
+ # `line_prefix` when `line` is true.
102
+ module KeyedState
103
+ def save_fields(out, line_prefix)
104
+ out.int("collisions.cleared_sprite", @cleared_sprite).int("collisions.cleared_data", @cleared_data)
105
+ out.bytes("#{line_prefix}hits", @hits).int("#{line_prefix}folded", @folded)
106
+ end
107
+
108
+ def load_fields(input, line_prefix, line)
109
+ @cleared_sprite = input.int("collisions.cleared_sprite", @cleared_sprite)
110
+ @cleared_data = input.int("collisions.cleared_data", @cleared_data)
111
+ return unless line
112
+
113
+ input.bytes_into("#{line_prefix}hits", @hits)
114
+ @folded = input.int("#{line_prefix}folded", @folded)
115
+ end
116
+ end
117
+
118
+ include KeyedState
119
+ end
120
+
121
+ class RegisterLog
122
+ # The line's sprite register writes, under `prefix`: the entries as
123
+ # pixel, register and value in turn, the seed with -1 for a register
124
+ # not logged, and the next pixel as -1 past the last entry.
125
+ module KeyedState
126
+ def save_fields(out, prefix)
127
+ out.ints("#{prefix}entries", @entries.flatten)
128
+ out.ints("#{prefix}seed", @seed.map { |value| value.nil? ? -1 : value })
129
+ out.ints("#{prefix}values", @values).int("#{prefix}cursor", @cursor)
130
+ out.int("#{prefix}next_x", @next_x.infinite? ? -1 : @next_x)
131
+ end
132
+
133
+ def load_fields(input, prefix)
134
+ @entries.replace(input.ints("#{prefix}entries", []).each_slice(3).to_a)
135
+ @seed.replace(input.ints("#{prefix}seed", []).map { |value| value.negative? ? nil : value })
136
+ input.ints_into("#{prefix}values", @values)
137
+ @cursor = input.int("#{prefix}cursor", @cursor)
138
+ next_x = input.int("#{prefix}next_x", 0)
139
+ @next_x = next_x.negative? ? Float::INFINITY : next_x
140
+ end
141
+ end
142
+
143
+ include KeyedState
144
+ end
145
+
146
+ class Sprites
147
+ # The sprites under sprite0. to sprite7., their bus under sbus.,
148
+ # the collisions, and the line batch under `line_prefix`: the
149
+ # window's colours and priorities, the span touched, the pixels
150
+ # carried into the next line, the register log. Whether any DMA
151
+ # runs comes from the sprites on load.
152
+ module KeyedState
153
+ # Whether any sprite's DMA runs, set after Sprite#restore_counters.
154
+ def update_any_dma
155
+ @any_dma = @sprites.any?(&:displaying?)
156
+ end
157
+
158
+ def save_fields(out, line_prefix)
159
+ @sprites.each do |sprite|
160
+ sprite.save_fields(out, "sprite#{sprite.index}.", "#{line_prefix}sprite#{sprite.index}.")
161
+ end
162
+ @bus.save_fields(out, "sbus.")
163
+ @collisions.save_fields(out, "#{line_prefix}collisions.")
164
+ out.bool("#{line_prefix}carried", @carried).int("#{line_prefix}lo", @lo).int("#{line_prefix}hi", @hi)
165
+ out.int("#{line_prefix}sequenced", @sequenced).bytes("#{line_prefix}win_color", @win_color)
166
+ out.ints("#{line_prefix}win_priority", @win_priority.map { |set| set ? 1 : 0 })
167
+ out.ints("#{line_prefix}palette", @palette).bool("#{line_prefix}stopped_dma", @stopped_dma)
168
+ save_carry_fields(out, "#{line_prefix}carry", @carry)
169
+ save_carry_fields(out, "#{line_prefix}carry_next", @carry_next)
170
+ @log.save_fields(out, "#{line_prefix}log.")
171
+ end
172
+
173
+ def load_fields(input, line_prefix, line)
174
+ @sprites.each do |sprite|
175
+ sprite.load_fields(input, "sprite#{sprite.index}.", "#{line_prefix}sprite#{sprite.index}.", line)
176
+ end
177
+ @bus.load_fields(input, "sbus.")
178
+ @collisions.load_fields(input, "#{line_prefix}collisions.", line)
179
+ load_line_fields(input, line_prefix) if line
180
+ end
181
+
182
+ def restored! = update_any_dma
183
+
184
+ private
185
+
186
+ def load_line_fields(input, prefix)
187
+ @carried = input.bool("#{prefix}carried", @carried)
188
+ @lo = input.int("#{prefix}lo", @lo)
189
+ @hi = input.int("#{prefix}hi", @hi)
190
+ @sequenced = input.int("#{prefix}sequenced", @sequenced)
191
+ input.bytes_into("#{prefix}win_color", @win_color)
192
+ priority = input.ints("#{prefix}win_priority", @win_priority.map { |set| set ? 1 : 0 })
193
+ @win_priority.each_index { |index| @win_priority[index] = priority.fetch(index, 0) == 1 }
194
+ input.ints_into("#{prefix}palette", @palette)
195
+ @stopped_dma = input.bool("#{prefix}stopped_dma", @stopped_dma)
196
+ load_carry_fields(input, "#{prefix}carry", @carry)
197
+ load_carry_fields(input, "#{prefix}carry_next", @carry_next)
198
+ @log.load_fields(input, "#{prefix}log.")
199
+ end
200
+
201
+ # Each sprite's carried pixels as x, colour and priority (0 or 1)
202
+ # in turn.
203
+ def save_carry_fields(out, prefix, carry)
204
+ carry.each_with_index do |pixels, index|
205
+ values = []
206
+ pixels.each_slice(3) { |x, color, priority| values.push(x, color, priority ? 1 : 0) }
207
+ out.ints("#{prefix}#{index}", values)
208
+ end
209
+ end
210
+
211
+ def load_carry_fields(input, prefix, carry)
212
+ carry.each_with_index do |pixels, index|
213
+ pixels.clear
214
+ input.ints("#{prefix}#{index}", []).each_slice(3) do |x, color, priority|
215
+ pixels.push(x, color, priority == 1)
216
+ end
217
+ end
218
+ end
219
+ end
220
+
221
+ include KeyedState
222
+ end
223
+ end
224
+ end
225
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIC
6
+ # The shape of the line batch the renderer keeps (design note §9.2).
7
+ # A snapshot whose line.layout differs restarts the rest of its line
8
+ # with an empty pipeline.
9
+ LINE_LAYOUT = 1
10
+
11
+ # The VIC-II's fields in a keyed snapshot module (Snapshot::Keyed):
12
+ # the beam, the g-access ring oldest first under g.*, the light pen
13
+ # and raster latches, the video matrix line, the registers, the
14
+ # display state, the sequencer and the sprites, the line batch under
15
+ # line.* with line.layout, and the picture as display. The IRQ line,
16
+ # the sprites' BA columns, whether any sprite DMA runs and the
17
+ # display's copy of the lines are worked out on load.
18
+ module KeyedState
19
+ def save_fields(out)
20
+ out.int("column", @column).int("raster", @rasterline).int("fetch_d011", @fetch_d011)
21
+ save_ring_fields(out)
22
+ out.bool("lp_triggered", @lp_triggered).bool("lp_low", @lp_low).bool("raster_match", @raster_match)
23
+ out.int("bank_lines", @vic_bank.lines).bytes("character_buffer", @character_buffer)
24
+ out.bytes("color_buffer", @color_buffer)
25
+ out.int("output_line", @output_line).bool("test_wrap", @test_wrap) if @iie
26
+ @registers.save_fields(out)
27
+ @display_state.save_fields(out)
28
+ out.int("line.layout", LINE_LAYOUT)
29
+ @sequencer.save_fields(out, "line.")
30
+ @sprites.save_fields(out, "line.")
31
+ out.bytes("display", @lines.flatten)
32
+ out
33
+ end
34
+
35
+ def load_fields(input)
36
+ @column = input.int("column", @column)
37
+ @rasterline = @output_line = input.int("raster", @rasterline)
38
+ @fetch_d011 = input.byte("fetch_d011", @fetch_d011)
39
+ load_ring_fields(input)
40
+ @lp_triggered = input.bool("lp_triggered", @lp_triggered)
41
+ @lp_low = input.bool("lp_low", @lp_low)
42
+ @raster_match = input.bool("raster_match", @raster_match)
43
+ @vic_bank.lines = input.int("bank_lines", @vic_bank.lines)
44
+ input.bytes_into("character_buffer", @character_buffer)
45
+ input.bytes_into("color_buffer", @color_buffer)
46
+ load_test_fields(input) if @iie
47
+ @registers.load_fields(input)
48
+ @display_state.load_fields(input)
49
+ line = input.int("line.layout", 0) == LINE_LAYOUT
50
+ input.adjust("line in progress from another renderer, restarted") unless line || input.missing?
51
+ @sequencer.load_fields(input, "line.", line)
52
+ @sprites.load_fields(input, "line.", line)
53
+ load_display_fields(input)
54
+ end
55
+
56
+ def restored!
57
+ @registers.restored!
58
+ @sprites.restored!
59
+ rebuild_sprite_ba
60
+ @dirty_lines.fill(true)
61
+ end
62
+
63
+ private
64
+
65
+ # Oldest first, so the ring's base is the reader's own.
66
+ def save_ring_fields(out)
67
+ order = Array.new(4) { |age| (@g_tick + 1 + age) & 3 }
68
+ out.ints("g.kind", order.map { |slot| @g_kind[slot] }).ints("g.data", order.map { |slot| @g_data[slot] })
69
+ out.ints("g.char", order.map { |slot| @g_char[slot] }).ints("g.color", order.map { |slot| @g_color[slot] })
70
+ out.int("g.kept_char", @g_kept_char).int("g.kept_color", @g_kept_color).bool("g.display", @g_display)
71
+ end
72
+
73
+ def load_ring_fields(input)
74
+ @g_tick = 3
75
+ input.ints_into("g.kind", @g_kind)
76
+ input.ints_into("g.data", @g_data)
77
+ input.ints_into("g.char", @g_char)
78
+ input.ints_into("g.color", @g_color)
79
+ @g_kept_char = input.byte("g.kept_char", @g_kept_char)
80
+ @g_kept_color = input.masked("g.kept_color", @g_kept_color, 0x0f)
81
+ @g_display = input.bool("g.display", @g_display)
82
+ end
83
+
84
+ def load_test_fields(input)
85
+ @output_line = input.int("output_line", @output_line)
86
+ @test_wrap = input.bool("test_wrap", @test_wrap)
87
+ end
88
+
89
+ def load_display_fields(input)
90
+ display = @lines.flatten
91
+ input.bytes_into("display", display)
92
+ @lines.each_with_index do |line, number|
93
+ line.replace(display[number * @width, @width])
94
+ @display[number * @width, @width] = line
95
+ end
96
+ end
97
+ end
98
+
99
+ include KeyedState
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIC
6
+ # Mid-line writes to the sprite registers, keyed by the pixel at which
7
+ # they become visible. Compositing replays the line through the log, so
8
+ # each pixel is drawn with the register values that were in effect when
9
+ # the VIC reached it.
10
+ class RegisterLog
11
+ def initialize(registers)
12
+ @registers = registers
13
+ @entries = []
14
+ @seed = []
15
+ @values = Array.new(2**6, 0)
16
+ @cursor = 0
17
+ @next_x = 0
18
+ end
19
+
20
+ # The pixel at which the next logged write takes effect.
21
+ attr_reader :next_x
22
+
23
+ def empty? = @entries.empty?
24
+ def length = @entries.length
25
+
26
+ def clear
27
+ return if @entries.empty?
28
+
29
+ @entries.clear
30
+ @seed.clear
31
+ end
32
+
33
+ def log(pixel_x, reg, old, value)
34
+ @seed[reg] = old if @seed[reg].nil?
35
+ @entries << [pixel_x, reg, value]
36
+ end
37
+
38
+ def prepare
39
+ @entries.sort_by! { |entry| entry[0] }
40
+ end
41
+
42
+ # Restart the cursor before the line's first pixel, with every logged
43
+ # register back at the value it held when the line started.
44
+ def rewind
45
+ @values.length.times { |reg| @values[reg] = @registers[reg] }
46
+ @seed.each_with_index { |value, reg| @values[reg] = value unless value.nil? }
47
+ @cursor = 0
48
+ @next_x = @entries.empty? ? Float::INFINITY : @entries[0][0]
49
+ end
50
+
51
+ def [](reg) = @values[reg]
52
+
53
+ # Apply every write visible at or before pixel_x.
54
+ def advance(pixel_x)
55
+ while @cursor < @entries.length && @entries[@cursor][0] <= pixel_x
56
+ entry = @entries[@cursor]
57
+ @values[entry[1]] = entry[2]
58
+ @cursor += 1
59
+ end
60
+ @next_x = @cursor < @entries.length ? @entries[@cursor][0] : Float::INFINITY
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end