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
@@ -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
@@ -20,24 +20,6 @@ module Badline
20
20
  # The pixel at which the next logged write takes effect.
21
21
  attr_reader :next_x
22
22
 
23
- # The entries as pixel, register and value in turn, the seed with -1
24
- # for a register the line hasn't logged, and a next pixel past the
25
- # last entry as -1.
26
- def save_state(out)
27
- out.ints(@entries.flatten)
28
- out.ints(@seed.map { |value| value.nil? ? -1 : value })
29
- out.ints(@values).int(@cursor).int(@next_x.infinite? ? -1 : @next_x)
30
- end
31
-
32
- def load_state(input)
33
- @entries.replace(input.ints.each_slice(3).to_a)
34
- @seed.replace(input.ints.map { |value| value.negative? ? nil : value })
35
- input.ints_into(@values)
36
- @cursor = input.int
37
- next_x = input.int
38
- @next_x = next_x.negative? ? Float::INFINITY : next_x
39
- end
40
-
41
23
  def empty? = @entries.empty?
42
24
  def length = @entries.length
43
25
 
@@ -163,15 +163,6 @@ module Badline
163
163
 
164
164
  def latch_raster_irq! = latch_irq!(0x01)
165
165
 
166
- def save_state(out)
167
- out.blob(@bytes).boolean(@irq_line)
168
- end
169
-
170
- def load_state(input)
171
- input.blob_into(@bytes)
172
- @irq_line = input.boolean?
173
- end
174
-
175
166
  def collide!(reg, bits)
176
167
  return false if bits.zero?
177
168
 
@@ -5,7 +5,6 @@ require "badline/chips/vic/color_patches"
5
5
  require "badline/chips/vic/graphics_mode"
6
6
  require "badline/chips/vic/graphics_shifter"
7
7
  require "badline/chips/vic/sequencer_output"
8
- require "badline/chips/vic/sequencer/saved_state"
9
8
 
10
9
  module Badline
11
10
  module Chips
@@ -15,7 +14,6 @@ module Badline
15
14
  # Turns fetched graphics data into output pixels.
16
15
  class Sequencer
17
16
  include Output
18
- include SavedState
19
17
 
20
18
  BORDER_Y_BOUNDS = [
21
19
  [55, 247].freeze,
@@ -26,17 +26,6 @@ module Badline
26
26
  @line = Array.new(columns, -1)
27
27
  end
28
28
 
29
- def save_state(out)
30
- out.int(@lines).int(@ghost).ints(@value).ints(@line)
31
- end
32
-
33
- def load_state(input)
34
- @lines = input.int
35
- @ghost = input.int
36
- input.ints_into(@value)
37
- input.ints_into(@line)
38
- end
39
-
40
29
  # Sprites 3-7 fetch in Bauer cycles 1-10, so the idle byte is taken
41
30
  # as the line starts.
42
31
  def start_line(sprites_enabled)
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "badline/chips/vic/sprite/internal_bus"
4
4
  require "badline/chips/vic/sprite/shifter"
5
- require "badline/chips/vic/sprite/saved_state"
6
5
  require "badline/chips/vic/sprite/timing"
7
6
 
8
7
  module Badline
@@ -54,7 +53,6 @@ module Badline
54
53
  DISPLAY_OFF_X = 460
55
54
 
56
55
  include Shifter
57
- include SavedState
58
56
 
59
57
  attr_reader :index, :leftmost, :span, :codes,
60
58
  :reload_leftmost, :reload_span, :reload_codes
@@ -3,14 +3,11 @@
3
3
  require "badline/chips/vic/collisions"
4
4
  require "badline/chips/vic/register_log"
5
5
  require "badline/chips/vic/sprite"
6
- require "badline/chips/vic/sprites/saved_state"
7
6
 
8
7
  module Badline
9
8
  module Chips
10
9
  class VIC
11
10
  class Sprites
12
- include SavedState
13
-
14
11
  # Pixels between the start of the cycle following a write and the
15
12
  # point the new value shows. Each signal reaches the output on its own
16
13
  # path: the colors feed the final mux, the sequencer inputs — X