badline 0.12.1 → 0.13.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 (505) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -0
  3. data/CLAUDE.md +59 -31
  4. data/README.md +1 -1
  5. data/doc/library.md +9 -9
  6. data/doc/pinned-behaviour.md +105 -105
  7. data/doc/snapshots.md +1 -4
  8. data/lib/badline/audio/bare_player.rb +3 -3
  9. data/lib/badline/audio/cli.rb +6 -6
  10. data/lib/badline/audio/jukebox.rb +2 -2
  11. data/lib/badline/audio/machine_player.rb +2 -2
  12. data/lib/badline/{media → audio}/queue.rb +1 -1
  13. data/lib/badline/audio/queued_tune.rb +6 -6
  14. data/lib/badline/audio/renderer.rb +5 -5
  15. data/lib/badline/audio/stereo.rb +1 -1
  16. data/lib/badline/c128/{bus_state.rb → bus/saved_state.rb} +1 -1
  17. data/lib/badline/c128/bus.rb +18 -17
  18. data/lib/badline/c128/color_lines.rb +2 -2
  19. data/lib/badline/c128/cpu.rb +1 -1
  20. data/lib/badline/c128/drives.rb +10 -11
  21. data/lib/badline/c128/fast_serial.rb +5 -5
  22. data/lib/badline/c128/mmu_pages.rb +1 -1
  23. data/lib/badline/c128/modes.rb +2 -2
  24. data/lib/badline/c128/saved_state.rb +21 -47
  25. data/lib/badline/c128/z80.rb +2 -2
  26. data/lib/badline/c128.rb +14 -9
  27. data/lib/badline/{computer → c64}/attachments.rb +4 -6
  28. data/lib/badline/c64/banked_ram/banking.rb +32 -0
  29. data/lib/badline/c64/banked_ram/plus256k.rb +56 -0
  30. data/lib/badline/c64/banked_ram/plus60k.rb +45 -0
  31. data/lib/badline/c64/banked_ram/unexpanded.rb +30 -0
  32. data/lib/badline/c64/banked_ram.rb +23 -0
  33. data/lib/badline/c64/bus/extra_sids.rb +32 -0
  34. data/lib/badline/c64/bus/fittings.rb +40 -0
  35. data/lib/badline/c64/bus/pla.rb +149 -0
  36. data/lib/badline/c64/bus/roms.rb +41 -0
  37. data/lib/badline/c64/bus/saved_state.rb +68 -0
  38. data/lib/badline/c64/bus/sid_slots.rb +44 -0
  39. data/lib/badline/c64/bus.rb +218 -0
  40. data/lib/badline/c64/cartridge/action_replay.rb +128 -0
  41. data/lib/badline/c64/cartridge/atomic_power.rb +26 -0
  42. data/lib/badline/c64/cartridge/bank.rb +83 -0
  43. data/lib/badline/c64/cartridge/comal80.rb +52 -0
  44. data/lib/badline/c64/cartridge/dinamic.rb +36 -0
  45. data/lib/badline/c64/cartridge/easy_flash.rb +147 -0
  46. data/lib/badline/c64/cartridge/epyx_fastload.rb +81 -0
  47. data/lib/badline/c64/cartridge/final_cartridge3.rb +91 -0
  48. data/lib/badline/c64/cartridge/flash/saved_state.rb +40 -0
  49. data/lib/badline/c64/cartridge/flash.rb +279 -0
  50. data/lib/badline/c64/cartridge/freezer.rb +35 -0
  51. data/lib/badline/c64/cartridge/fun_play.rb +40 -0
  52. data/lib/badline/c64/cartridge/g_mod2.rb +76 -0
  53. data/lib/badline/c64/cartridge/game_system.rb +42 -0
  54. data/lib/badline/c64/cartridge/geo_ram.rb +81 -0
  55. data/lib/badline/c64/cartridge/kcs_power.rb +77 -0
  56. data/lib/badline/c64/cartridge/mach5.rb +34 -0
  57. data/lib/badline/c64/cartridge/magic_desk.rb +32 -0
  58. data/lib/badline/c64/cartridge/ocean.rb +37 -0
  59. data/lib/badline/c64/cartridge/pagefox.rb +70 -0
  60. data/lib/badline/c64/cartridge/retro_replay/saved_state.rb +47 -0
  61. data/lib/badline/c64/cartridge/retro_replay.rb +286 -0
  62. data/lib/badline/c64/cartridge/rex_utility.rb +31 -0
  63. data/lib/badline/c64/cartridge/rgcd.rb +60 -0
  64. data/lib/badline/c64/cartridge/saved_state.rb +63 -0
  65. data/lib/badline/c64/cartridge/simons_basic.rb +37 -0
  66. data/lib/badline/c64/cartridge/standard.rb +17 -0
  67. data/lib/badline/c64/cartridge/super_games.rb +50 -0
  68. data/lib/badline/c64/cartridge/westermann.rb +32 -0
  69. data/lib/badline/c64/cartridge/zaxxon.rb +68 -0
  70. data/lib/badline/c64/cartridge.rb +258 -0
  71. data/lib/badline/c64/color_memory.rb +27 -0
  72. data/lib/badline/{computer → c64}/common.rb +2 -2
  73. data/lib/badline/{computer → c64}/kernal_traps.rb +18 -18
  74. data/lib/badline/c64/reu/dma/saved_state.rb +52 -0
  75. data/lib/badline/c64/reu/dma.rb +275 -0
  76. data/lib/badline/c64/reu/ram.rb +109 -0
  77. data/lib/badline/c64/reu/saved_state.rb +55 -0
  78. data/lib/badline/c64/reu/trigger.rb +34 -0
  79. data/lib/badline/c64/reu.rb +291 -0
  80. data/lib/badline/{computer → c64}/saved_state.rb +13 -18
  81. data/lib/badline/{computer → c64}/true_drives.rb +11 -11
  82. data/lib/badline/{computer.rb → c64.rb} +18 -13
  83. data/lib/badline/chips/cia/fast_forward.rb +62 -0
  84. data/lib/badline/chips/cia/interrupt_register.rb +145 -0
  85. data/lib/badline/chips/cia/saved_state.rb +49 -0
  86. data/lib/badline/chips/cia/serial/saved_state.rb +45 -0
  87. data/lib/badline/chips/cia/serial.rb +250 -0
  88. data/lib/badline/chips/cia/time_of_day.rb +232 -0
  89. data/lib/badline/chips/cia/timer.rb +208 -0
  90. data/lib/badline/chips/cia.rb +281 -0
  91. data/lib/badline/chips/cpu/addressing.rb +133 -0
  92. data/lib/badline/chips/cpu/boundary.rb +56 -0
  93. data/lib/badline/chips/cpu/core.rb +167 -0
  94. data/lib/badline/chips/cpu/instruction.rb +338 -0
  95. data/lib/badline/chips/cpu/instruction_set/arithmetic.rb +118 -0
  96. data/lib/badline/chips/cpu/instruction_set/bitwise.rb +130 -0
  97. data/lib/badline/chips/cpu/instruction_set/branch.rb +83 -0
  98. data/lib/badline/chips/cpu/instruction_set/flag.rb +67 -0
  99. data/lib/badline/chips/cpu/instruction_set/illegal.rb +274 -0
  100. data/lib/badline/chips/cpu/instruction_set/inc_dec.rb +73 -0
  101. data/lib/badline/chips/cpu/instruction_set/stack.rb +56 -0
  102. data/lib/badline/chips/cpu/instruction_set/transfer.rb +141 -0
  103. data/lib/badline/chips/cpu/instruction_set.rb +59 -0
  104. data/lib/badline/chips/cpu/interrupts.rb +108 -0
  105. data/lib/badline/chips/cpu/microcode.rb +179 -0
  106. data/lib/badline/chips/cpu/operations.rb +90 -0
  107. data/lib/badline/chips/cpu/port.rb +116 -0
  108. data/lib/badline/chips/cpu/saved_state.rb +117 -0
  109. data/lib/badline/chips/cpu/stack_operations.rb +84 -0
  110. data/lib/badline/chips/cpu/traps.rb +23 -0
  111. data/lib/badline/chips/cpu.rb +12 -0
  112. data/lib/badline/chips/sid/catch_up.rb +122 -0
  113. data/lib/badline/chips/sid/decimator.rb +66 -0
  114. data/lib/badline/chips/sid/envelope/saved_state.rb +70 -0
  115. data/lib/badline/chips/sid/envelope.rb +241 -0
  116. data/lib/badline/chips/sid/filter/saved_state.rb +42 -0
  117. data/lib/badline/chips/sid/filter.rb +241 -0
  118. data/lib/badline/chips/sid/saved_state.rb +52 -0
  119. data/lib/badline/chips/sid/voice.rb +79 -0
  120. data/lib/badline/chips/sid/waveform/combined.rb +128 -0
  121. data/lib/badline/chips/sid/waveform/fast_forward.rb +107 -0
  122. data/lib/badline/chips/sid/waveform/noise_writeback.rb +124 -0
  123. data/lib/badline/chips/sid/waveform/saved_state.rb +68 -0
  124. data/lib/badline/chips/sid/waveform.rb +307 -0
  125. data/lib/badline/chips/sid.rb +265 -0
  126. data/lib/badline/{c128 → chips}/vdc/memory.rb +1 -1
  127. data/lib/badline/{c128 → chips}/vdc/painter.rb +1 -1
  128. data/lib/badline/{c128 → chips}/vdc/raster.rb +1 -1
  129. data/lib/badline/chips/vdc/saved_state.rb +36 -0
  130. data/lib/badline/{c128 → chips}/vdc/window.rb +1 -1
  131. data/lib/badline/{c128 → chips}/vdc.rb +7 -31
  132. data/lib/badline/chips/via/control_lines.rb +124 -0
  133. data/lib/badline/chips/via/fast_forward.rb +55 -0
  134. data/lib/badline/chips/via/interrupt_register.rb +69 -0
  135. data/lib/badline/chips/via/saved_state.rb +44 -0
  136. data/lib/badline/chips/via/shift_register.rb +182 -0
  137. data/lib/badline/chips/via/timer1.rb +133 -0
  138. data/lib/badline/chips/via/timer2.rb +135 -0
  139. data/lib/badline/chips/via.rb +268 -0
  140. data/lib/badline/chips/vic/bank.rb +135 -0
  141. data/lib/badline/chips/vic/border_mask.rb +88 -0
  142. data/lib/badline/chips/vic/collisions.rb +117 -0
  143. data/lib/badline/chips/vic/color_patches.rb +49 -0
  144. data/lib/badline/chips/vic/display_state.rb +187 -0
  145. data/lib/badline/chips/vic/graphics_mode.rb +166 -0
  146. data/lib/badline/chips/vic/graphics_shifter/saved_state.rb +40 -0
  147. data/lib/badline/chips/vic/graphics_shifter.rb +187 -0
  148. data/lib/badline/chips/vic/register_log.rb +83 -0
  149. data/lib/badline/chips/vic/registers.rb +197 -0
  150. data/lib/badline/chips/vic/saved_state.rb +82 -0
  151. data/lib/badline/chips/vic/sequencer/saved_state.rb +91 -0
  152. data/lib/badline/chips/vic/sequencer.rb +277 -0
  153. data/lib/badline/chips/vic/sequencer_output.rb +118 -0
  154. data/lib/badline/chips/vic/sprite/internal_bus.rb +70 -0
  155. data/lib/badline/chips/vic/sprite/saved_state.rb +66 -0
  156. data/lib/badline/chips/vic/sprite/shifter.rb +148 -0
  157. data/lib/badline/chips/vic/sprite/timing.rb +58 -0
  158. data/lib/badline/chips/vic/sprite.rb +339 -0
  159. data/lib/badline/chips/vic/sprites/saved_state.rb +59 -0
  160. data/lib/badline/chips/vic/sprites.rb +284 -0
  161. data/lib/badline/chips/vic.rb +783 -0
  162. data/lib/badline/chips/vic_i/painter/saved_state.rb +40 -0
  163. data/lib/badline/{vic20/vic → chips/vic_i}/painter.rb +6 -30
  164. data/lib/badline/{vic20/vic → chips/vic_i}/saved_state.rb +2 -2
  165. data/lib/badline/chips/vic_i/sound/output.rb +85 -0
  166. data/lib/badline/chips/vic_i/sound.rb +235 -0
  167. data/lib/badline/{vic20/vic → chips/vic_i}/text_window.rb +2 -2
  168. data/lib/badline/{vic20/vic.rb → chips/vic_i.rb} +5 -5
  169. data/lib/badline/chips/z80/arithmetic.rb +119 -0
  170. data/lib/badline/chips/z80/bit_page.rb +57 -0
  171. data/lib/badline/chips/z80/block_io.rb +60 -0
  172. data/lib/badline/chips/z80/block_transfers.rb +61 -0
  173. data/lib/badline/chips/z80/bus_cycles.rb +113 -0
  174. data/lib/badline/chips/z80/core.rb +115 -0
  175. data/lib/badline/chips/z80/exchanges.rb +52 -0
  176. data/lib/badline/chips/z80/extended_page.rb +91 -0
  177. data/lib/badline/chips/z80/flags.rb +39 -0
  178. data/lib/badline/chips/z80/interrupt_acceptance.rb +48 -0
  179. data/lib/badline/chips/z80/jumps.rb +84 -0
  180. data/lib/badline/chips/z80/loads.rb +100 -0
  181. data/lib/badline/chips/z80/main_page.rb +136 -0
  182. data/lib/badline/chips/z80/registers.rb +122 -0
  183. data/lib/badline/chips/z80/saved_state.rb +71 -0
  184. data/lib/badline/chips/z80/shifts.rb +66 -0
  185. data/lib/badline/chips/z80.rb +13 -0
  186. data/lib/badline/core.rb +26 -28
  187. data/lib/badline/drives/datasette/saved_state.rb +37 -0
  188. data/lib/badline/drives/datasette.rb +140 -0
  189. data/lib/badline/drives/engine/core.rb +149 -0
  190. data/lib/badline/drives/engine/fast_serial.rb +75 -0
  191. data/lib/badline/drives/engine/idle.rb +127 -0
  192. data/lib/badline/drives/engine/idle_cpu.rb +30 -0
  193. data/lib/badline/drives/engine/orbit.rb +81 -0
  194. data/lib/badline/drives/engine/serial_lines.rb +75 -0
  195. data/lib/badline/drives/engine/sleep.rb +114 -0
  196. data/lib/badline/drives/engine/vias.rb +86 -0
  197. data/lib/badline/drives/engine/watch.rb +152 -0
  198. data/lib/badline/drives/engine.rb +11 -0
  199. data/lib/badline/drives/model1541/bus.rb +88 -0
  200. data/lib/badline/drives/model1541/byte_ready.rb +50 -0
  201. data/lib/badline/drives/model1541/cpu.rb +13 -0
  202. data/lib/badline/drives/model1541/disk/saved_state.rb +88 -0
  203. data/lib/badline/drives/model1541/disk.rb +317 -0
  204. data/lib/badline/drives/model1541/disk_via.rb +38 -0
  205. data/lib/badline/drives/model1541/gcr.rb +59 -0
  206. data/lib/badline/drives/model1541/mechanism/saved_state.rb +72 -0
  207. data/lib/badline/drives/model1541/mechanism.rb +315 -0
  208. data/lib/badline/drives/model1541/rotation.rb +123 -0
  209. data/lib/badline/drives/model1541/saved_state.rb +44 -0
  210. data/lib/badline/drives/model1541/sector_reader.rb +78 -0
  211. data/lib/badline/drives/model1541/serial_port.rb +20 -0
  212. data/lib/badline/drives/model1541/track.rb +100 -0
  213. data/lib/badline/drives/model1541.rb +81 -0
  214. data/lib/badline/drives/model1571/bus.rb +113 -0
  215. data/lib/badline/drives/model1571/cpu.rb +13 -0
  216. data/lib/badline/drives/model1571/saved_state.rb +47 -0
  217. data/lib/badline/drives/model1571/serial_port.rb +39 -0
  218. data/lib/badline/drives/model1571/serial_via.rb +27 -0
  219. data/lib/badline/drives/model1571/wd1770.rb +122 -0
  220. data/lib/badline/drives/model1571.rb +142 -0
  221. data/lib/badline/drives/model1581/bus.rb +139 -0
  222. data/lib/badline/drives/model1581/cpu.rb +13 -0
  223. data/lib/badline/drives/model1581/disk/saved_state.rb +89 -0
  224. data/lib/badline/drives/model1581/disk.rb +137 -0
  225. data/lib/badline/drives/model1581/mechanism.rb +119 -0
  226. data/lib/badline/drives/model1581/saved_state.rb +42 -0
  227. data/lib/badline/drives/model1581/serial_port.rb +54 -0
  228. data/lib/badline/drives/model1581/slot.rb +79 -0
  229. data/lib/badline/drives/model1581/track.rb +102 -0
  230. data/lib/badline/drives/model1581/track_bytes.rb +77 -0
  231. data/lib/badline/drives/model1581/wd1772/registers.rb +91 -0
  232. data/lib/badline/drives/model1581/wd1772/saved_state.rb +68 -0
  233. data/lib/badline/drives/model1581/wd1772/sector_writes.rb +75 -0
  234. data/lib/badline/drives/model1581/wd1772/sectors.rb +152 -0
  235. data/lib/badline/drives/model1581/wd1772/stepping.rb +111 -0
  236. data/lib/badline/drives/model1581/wd1772/tracks.rb +127 -0
  237. data/lib/badline/drives/model1581/wd1772/turn.rb +75 -0
  238. data/lib/badline/drives/model1581/wd1772.rb +218 -0
  239. data/lib/badline/drives/model1581.rb +206 -0
  240. data/lib/badline/drives/serial_bus.rb +161 -0
  241. data/lib/badline/frontend/boot.rb +3 -3
  242. data/lib/badline/frontend/machine_window.rb +3 -1
  243. data/lib/badline/frontend/player/filter_view.rb +1 -1
  244. data/lib/badline/frontend/player/player_controller.rb +2 -2
  245. data/lib/badline/frontend/player/player_screen.rb +1 -0
  246. data/lib/badline/frontend/player/theme.rb +7 -7
  247. data/lib/badline/frontend/timeline.rb +3 -3
  248. data/lib/badline/input/control_ports.rb +78 -0
  249. data/lib/badline/input/joystick.rb +27 -0
  250. data/lib/badline/input/keyboard.rb +114 -0
  251. data/lib/badline/input.rb +3 -0
  252. data/lib/badline/kernal_trap/{drive → dos}/block_commands.rb +1 -1
  253. data/lib/badline/kernal_trap/dos/channel.rb +183 -0
  254. data/lib/badline/kernal_trap/{drive → dos}/channels.rb +1 -1
  255. data/lib/badline/kernal_trap/{drive → dos}/memory.rb +1 -1
  256. data/lib/badline/kernal_trap/{drive → dos}/parameters.rb +1 -1
  257. data/lib/badline/kernal_trap/{drive → dos}/status.rb +1 -1
  258. data/lib/badline/kernal_trap/{drive → dos}/write_file.rb +1 -1
  259. data/lib/badline/kernal_trap/{drive → dos}/writes.rb +1 -1
  260. data/lib/badline/kernal_trap/{drive.rb → dos.rb} +11 -10
  261. data/lib/badline/kernal_trap/load.rb +5 -5
  262. data/lib/badline/kernal_trap/save.rb +4 -4
  263. data/lib/badline/kernal_trap/serial.rb +7 -7
  264. data/lib/badline/kernal_trap.rb +1 -2
  265. data/lib/badline/machine/clocking.rb +1 -1
  266. data/lib/badline/machine.rb +5 -5
  267. data/lib/badline/media/true_drive.rb +1 -1
  268. data/lib/badline/media/tune.rb +2 -2
  269. data/lib/badline/media.rb +3 -3
  270. data/lib/badline/model.rb +1 -1
  271. data/lib/badline/roms/README +6 -6
  272. data/lib/badline/sdl.rb +1 -0
  273. data/lib/badline/{storage/sid_file.rb → sid_tune/file.rb} +3 -3
  274. data/lib/badline/{storage → sid_tune}/hvsc.rb +7 -7
  275. data/lib/badline/{storage → sid_tune}/song_lengths.rb +2 -2
  276. data/lib/badline/{storage → sid_tune}/stil/credit.rb +1 -1
  277. data/lib/badline/{storage → sid_tune}/stil.rb +3 -3
  278. data/lib/badline/sid_tune.rb +6 -0
  279. data/lib/badline/snapshot/c128_setup.rb +43 -0
  280. data/lib/badline/snapshot/c64_setup.rb +79 -0
  281. data/lib/badline/snapshot/image.rb +5 -25
  282. data/lib/badline/snapshot/machine_state.rb +1 -1
  283. data/lib/badline/snapshot/setup.rb +22 -66
  284. data/lib/badline/snapshot/state.rb +8 -18
  285. data/lib/badline/snapshot/storage_setup.rb +68 -0
  286. data/lib/badline/snapshot/vic20_setup.rb +37 -0
  287. data/lib/badline/snapshot/vice/c64_mem.rb +1 -1
  288. data/lib/badline/snapshot/vice/restore.rb +1 -1
  289. data/lib/badline/snapshot/vice/reu1764.rb +1 -1
  290. data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
  291. data/lib/badline/snapshot/vice.rb +7 -5
  292. data/lib/badline/snapshot.rb +3 -4
  293. data/lib/badline/storage/d64_image.rb +0 -2
  294. data/lib/badline/storage/d71_image.rb +0 -2
  295. data/lib/badline/storage/d81_image.rb +0 -2
  296. data/lib/badline/storage/disk_image.rb +3 -6
  297. data/lib/badline/storage/g64_image.rb +2 -2
  298. data/lib/badline/storage/host_directory.rb +0 -5
  299. data/lib/badline/storage/t64.rb +2 -8
  300. data/lib/badline/storage/unavailable.rb +1 -1
  301. data/lib/badline/storage.rb +0 -37
  302. data/lib/badline/support/c128_checkpoint.rb +39 -0
  303. data/lib/badline/support/checkpoint.rb +108 -0
  304. data/lib/badline/support/vic20_checkpoint.rb +38 -0
  305. data/lib/badline/support.rb +5 -0
  306. data/lib/badline/version.rb +1 -1
  307. data/lib/badline/vic20/attachments.rb +5 -5
  308. data/lib/badline/vic20/bus/saved_state.rb +35 -0
  309. data/lib/badline/vic20/bus.rb +3 -25
  310. data/lib/badline/vic20/cpu.rb +1 -1
  311. data/lib/badline/vic20/port_wiring.rb +4 -4
  312. data/lib/badline/vic20/saved_state.rb +16 -30
  313. data/lib/badline/vic20/user_via_ports.rb +2 -2
  314. data/lib/badline/vic20.rb +19 -14
  315. metadata +245 -221
  316. data/lib/badline/address_bus/extra_sids.rb +0 -30
  317. data/lib/badline/address_bus/fittings.rb +0 -38
  318. data/lib/badline/address_bus/pla.rb +0 -147
  319. data/lib/badline/address_bus/roms.rb +0 -39
  320. data/lib/badline/address_bus/saved_state.rb +0 -66
  321. data/lib/badline/address_bus/sid_slots.rb +0 -42
  322. data/lib/badline/address_bus.rb +0 -216
  323. data/lib/badline/cartridge/action_replay.rb +0 -126
  324. data/lib/badline/cartridge/atomic_power.rb +0 -24
  325. data/lib/badline/cartridge/bank.rb +0 -81
  326. data/lib/badline/cartridge/comal80.rb +0 -50
  327. data/lib/badline/cartridge/dinamic.rb +0 -34
  328. data/lib/badline/cartridge/easy_flash.rb +0 -145
  329. data/lib/badline/cartridge/epyx_fastload.rb +0 -79
  330. data/lib/badline/cartridge/final_cartridge3.rb +0 -89
  331. data/lib/badline/cartridge/flash.rb +0 -306
  332. data/lib/badline/cartridge/freezer.rb +0 -33
  333. data/lib/badline/cartridge/fun_play.rb +0 -38
  334. data/lib/badline/cartridge/g_mod2.rb +0 -74
  335. data/lib/badline/cartridge/game_system.rb +0 -40
  336. data/lib/badline/cartridge/geo_ram.rb +0 -79
  337. data/lib/badline/cartridge/kcs_power.rb +0 -75
  338. data/lib/badline/cartridge/mach5.rb +0 -32
  339. data/lib/badline/cartridge/magic_desk.rb +0 -30
  340. data/lib/badline/cartridge/ocean.rb +0 -35
  341. data/lib/badline/cartridge/pagefox.rb +0 -68
  342. data/lib/badline/cartridge/retro_replay.rb +0 -320
  343. data/lib/badline/cartridge/rex_utility.rb +0 -29
  344. data/lib/badline/cartridge/rgcd.rb +0 -58
  345. data/lib/badline/cartridge/simons_basic.rb +0 -35
  346. data/lib/badline/cartridge/standard.rb +0 -15
  347. data/lib/badline/cartridge/super_games.rb +0 -48
  348. data/lib/badline/cartridge/westermann.rb +0 -30
  349. data/lib/badline/cartridge/zaxxon.rb +0 -66
  350. data/lib/badline/cartridge.rb +0 -303
  351. data/lib/badline/checkpoint.rb +0 -98
  352. data/lib/badline/cia/fast_forward.rb +0 -60
  353. data/lib/badline/cia/interrupt_register.rb +0 -143
  354. data/lib/badline/cia/serial.rb +0 -275
  355. data/lib/badline/cia/state.rb +0 -47
  356. data/lib/badline/cia/timer.rb +0 -206
  357. data/lib/badline/cia.rb +0 -279
  358. data/lib/badline/color_memory.rb +0 -25
  359. data/lib/badline/control_ports.rb +0 -76
  360. data/lib/badline/cpu/addressing.rb +0 -131
  361. data/lib/badline/cpu/boundary.rb +0 -54
  362. data/lib/badline/cpu/core.rb +0 -165
  363. data/lib/badline/cpu/microcode.rb +0 -177
  364. data/lib/badline/cpu/operations.rb +0 -88
  365. data/lib/badline/cpu/saved_state.rb +0 -115
  366. data/lib/badline/cpu/stack_operations.rb +0 -82
  367. data/lib/badline/cpu.rb +0 -10
  368. data/lib/badline/cpu_port.rb +0 -112
  369. data/lib/badline/datasette.rb +0 -161
  370. data/lib/badline/drive/core.rb +0 -147
  371. data/lib/badline/drive/fast_serial.rb +0 -73
  372. data/lib/badline/drive/idle.rb +0 -125
  373. data/lib/badline/drive/idle_cpu.rb +0 -28
  374. data/lib/badline/drive/orbit.rb +0 -79
  375. data/lib/badline/drive/serial_lines.rb +0 -73
  376. data/lib/badline/drive/sleep.rb +0 -112
  377. data/lib/badline/drive/vias.rb +0 -84
  378. data/lib/badline/drive/watch.rb +0 -150
  379. data/lib/badline/drive.rb +0 -11
  380. data/lib/badline/drive1541/bus.rb +0 -86
  381. data/lib/badline/drive1541/byte_ready.rb +0 -48
  382. data/lib/badline/drive1541/cpu.rb +0 -11
  383. data/lib/badline/drive1541/disk.rb +0 -315
  384. data/lib/badline/drive1541/disk_state.rb +0 -86
  385. data/lib/badline/drive1541/disk_via.rb +0 -36
  386. data/lib/badline/drive1541/gcr.rb +0 -57
  387. data/lib/badline/drive1541/mechanism.rb +0 -313
  388. data/lib/badline/drive1541/mechanism_state.rb +0 -68
  389. data/lib/badline/drive1541/rotation.rb +0 -121
  390. data/lib/badline/drive1541/sector_reader.rb +0 -76
  391. data/lib/badline/drive1541/serial_port.rb +0 -18
  392. data/lib/badline/drive1541/track.rb +0 -98
  393. data/lib/badline/drive1541.rb +0 -111
  394. data/lib/badline/drive1571/bus.rb +0 -111
  395. data/lib/badline/drive1571/cpu.rb +0 -11
  396. data/lib/badline/drive1571/serial_port.rb +0 -37
  397. data/lib/badline/drive1571/serial_via.rb +0 -25
  398. data/lib/badline/drive1571/wd1770.rb +0 -120
  399. data/lib/badline/drive1571.rb +0 -175
  400. data/lib/badline/drive1581/bus.rb +0 -137
  401. data/lib/badline/drive1581/cpu.rb +0 -11
  402. data/lib/badline/drive1581/disk.rb +0 -135
  403. data/lib/badline/drive1581/disk_state.rb +0 -87
  404. data/lib/badline/drive1581/mechanism.rb +0 -117
  405. data/lib/badline/drive1581/serial_port.rb +0 -52
  406. data/lib/badline/drive1581/slot.rb +0 -78
  407. data/lib/badline/drive1581/track.rb +0 -100
  408. data/lib/badline/drive1581/track_bytes.rb +0 -75
  409. data/lib/badline/drive1581/wd1772/registers.rb +0 -89
  410. data/lib/badline/drive1581/wd1772/sector_writes.rb +0 -73
  411. data/lib/badline/drive1581/wd1772/sectors.rb +0 -150
  412. data/lib/badline/drive1581/wd1772/state.rb +0 -66
  413. data/lib/badline/drive1581/wd1772/stepping.rb +0 -109
  414. data/lib/badline/drive1581/wd1772/tracks.rb +0 -125
  415. data/lib/badline/drive1581/wd1772/turn.rb +0 -73
  416. data/lib/badline/drive1581/wd1772.rb +0 -216
  417. data/lib/badline/drive1581.rb +0 -233
  418. data/lib/badline/iec_bus.rb +0 -159
  419. data/lib/badline/instruction.rb +0 -334
  420. data/lib/badline/instruction_set/arithmetic.rb +0 -114
  421. data/lib/badline/instruction_set/bitwise.rb +0 -126
  422. data/lib/badline/instruction_set/branch.rb +0 -79
  423. data/lib/badline/instruction_set/flag.rb +0 -63
  424. data/lib/badline/instruction_set/illegal.rb +0 -270
  425. data/lib/badline/instruction_set/inc_dec.rb +0 -69
  426. data/lib/badline/instruction_set/stack.rb +0 -52
  427. data/lib/badline/instruction_set/transfer.rb +0 -137
  428. data/lib/badline/instruction_set.rb +0 -55
  429. data/lib/badline/interrupts.rb +0 -104
  430. data/lib/badline/joystick.rb +0 -25
  431. data/lib/badline/kernal_trap/channel.rb +0 -181
  432. data/lib/badline/keyboard.rb +0 -112
  433. data/lib/badline/ram_expansion/banking.rb +0 -30
  434. data/lib/badline/ram_expansion/plus256k.rb +0 -54
  435. data/lib/badline/ram_expansion/plus60k.rb +0 -43
  436. data/lib/badline/ram_expansion/unexpanded.rb +0 -28
  437. data/lib/badline/ram_expansion.rb +0 -21
  438. data/lib/badline/reu/dma/saved_state.rb +0 -50
  439. data/lib/badline/reu/dma.rb +0 -273
  440. data/lib/badline/reu/ram.rb +0 -107
  441. data/lib/badline/reu/saved_state.rb +0 -80
  442. data/lib/badline/reu/trigger.rb +0 -32
  443. data/lib/badline/reu.rb +0 -289
  444. data/lib/badline/sid/catch_up.rb +0 -120
  445. data/lib/badline/sid/decimator.rb +0 -64
  446. data/lib/badline/sid/envelope/state.rb +0 -68
  447. data/lib/badline/sid/envelope.rb +0 -239
  448. data/lib/badline/sid/filter.rb +0 -263
  449. data/lib/badline/sid/voice.rb +0 -77
  450. data/lib/badline/sid/waveform/combined.rb +0 -126
  451. data/lib/badline/sid/waveform/fast_forward.rb +0 -105
  452. data/lib/badline/sid/waveform/noise_writeback.rb +0 -122
  453. data/lib/badline/sid/waveform/state.rb +0 -66
  454. data/lib/badline/sid/waveform.rb +0 -305
  455. data/lib/badline/sid.rb +0 -303
  456. data/lib/badline/time_of_day.rb +0 -228
  457. data/lib/badline/traps.rb +0 -19
  458. data/lib/badline/via/control_lines.rb +0 -122
  459. data/lib/badline/via/fast_forward.rb +0 -53
  460. data/lib/badline/via/interrupt_register.rb +0 -67
  461. data/lib/badline/via/shift_register.rb +0 -180
  462. data/lib/badline/via/state.rb +0 -42
  463. data/lib/badline/via/timer1.rb +0 -131
  464. data/lib/badline/via/timer2.rb +0 -133
  465. data/lib/badline/via.rb +0 -266
  466. data/lib/badline/vic/bank.rb +0 -133
  467. data/lib/badline/vic/border_mask.rb +0 -86
  468. data/lib/badline/vic/collisions.rb +0 -115
  469. data/lib/badline/vic/color_patches.rb +0 -47
  470. data/lib/badline/vic/display_state.rb +0 -185
  471. data/lib/badline/vic/graphics_mode.rb +0 -164
  472. data/lib/badline/vic/graphics_shifter.rb +0 -207
  473. data/lib/badline/vic/register_log.rb +0 -81
  474. data/lib/badline/vic/registers.rb +0 -195
  475. data/lib/badline/vic/sequencer.rb +0 -275
  476. data/lib/badline/vic/sequencer_output.rb +0 -116
  477. data/lib/badline/vic/sequencer_state.rb +0 -89
  478. data/lib/badline/vic/sprite/internal_bus.rb +0 -68
  479. data/lib/badline/vic/sprite/saved_state.rb +0 -64
  480. data/lib/badline/vic/sprite/shifter.rb +0 -146
  481. data/lib/badline/vic/sprite/timing.rb +0 -56
  482. data/lib/badline/vic/sprite.rb +0 -337
  483. data/lib/badline/vic/sprites.rb +0 -282
  484. data/lib/badline/vic/sprites_state.rb +0 -57
  485. data/lib/badline/vic.rb +0 -853
  486. data/lib/badline/vic20/sound/output.rb +0 -83
  487. data/lib/badline/vic20/sound.rb +0 -233
  488. data/lib/badline/z80/arithmetic.rb +0 -117
  489. data/lib/badline/z80/bit_page.rb +0 -55
  490. data/lib/badline/z80/block_io.rb +0 -58
  491. data/lib/badline/z80/block_transfers.rb +0 -59
  492. data/lib/badline/z80/bus_cycles.rb +0 -111
  493. data/lib/badline/z80/core.rb +0 -113
  494. data/lib/badline/z80/exchanges.rb +0 -50
  495. data/lib/badline/z80/extended_page.rb +0 -89
  496. data/lib/badline/z80/flags.rb +0 -37
  497. data/lib/badline/z80/interrupt_acceptance.rb +0 -46
  498. data/lib/badline/z80/jumps.rb +0 -82
  499. data/lib/badline/z80/loads.rb +0 -98
  500. data/lib/badline/z80/main_page.rb +0 -134
  501. data/lib/badline/z80/registers.rb +0 -120
  502. data/lib/badline/z80/saved_state.rb +0 -69
  503. data/lib/badline/z80/shifts.rb +0 -64
  504. data/lib/badline/z80.rb +0 -11
  505. /data/lib/badline/snapshot/{fields.rb → vice/fields.rb} +0 -0
@@ -0,0 +1,197 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIC
6
+ # = VIC-II Registers
7
+ #
8
+ # == Sprite positions
9
+ #
10
+ # $D000: Sprite 0 X
11
+ # $D001: Sprite 0 Y
12
+ # $D002: Sprite 1 X
13
+ # $D003: Sprite 1 Y
14
+ # $D004: Sprite 2 X
15
+ # $D005: Sprite 2 Y
16
+ # $D006: Sprite 3 X
17
+ # $D007: Sprite 3 Y
18
+ # $D008: Sprite 4 X
19
+ # $D009: Sprite 4 Y
20
+ # $D00A: Sprite 5 X
21
+ # $D00B: Sprite 5 Y
22
+ # $D00C: Sprite 6 X
23
+ # $D00D: Sprite 6 Y
24
+ # $D00E: Sprite 7 X
25
+ # $D00F: Sprite 7 Y
26
+ #
27
+ # $D010: Most Significant Bits of Sprites 0-7 Horizontal Position
28
+ # $D011: Vertical Fine Scrolling and Control Register
29
+ # $D012: Rasterline
30
+ # - Read: Current rasterline
31
+ # - Write: Set rasterline interrupt
32
+ #
33
+ # == Light pen
34
+ #
35
+ # $D013: Light Pen Horizontal Position
36
+ # $D014: Light Pen Vertical Position
37
+ #
38
+ # $D015: Sprite Enable Register
39
+ # $D016: Horizontal Fine Scrolling and Control Register
40
+ # $D017: Sprite Vertical Expansion Register
41
+ # $D018: VIC-II Chip Memory Control Register
42
+ # $D019: VIC Interrupt Flag Register
43
+ # $D01A: IRQ Mask Register
44
+ # $D01B: Sprite to Foreground Display Priority Register
45
+ # $D01C: Sprite Multicolor Registers
46
+ # $D01D: Sprite Horizontal Expansion Register
47
+ #
48
+ # == Sprite collision detection
49
+ #
50
+ # $D01E: Sprite to Sprite Collision Register
51
+ # $D01F: Sprite to Foreground Collision Register
52
+ #
53
+ # == Color registers
54
+ #
55
+ # All color registers are 4bit, bits 4-7 always read 1.
56
+ #
57
+ # $D020: Border color
58
+ # $D021: Background color 0
59
+ # $D022: Background color 1
60
+ # $D023: Background color 2
61
+ # $D024: Background color 3
62
+ # $D025: Sprite multicolor 0
63
+ # $D026: Sprite multicolor 1
64
+ # $D027: Sprite 0 color
65
+ # $D028: Sprite 1 color
66
+ # $D029: Sprite 2 color
67
+ # $D02A: Sprite 3 color
68
+ # $D02B: Sprite 4 color
69
+ # $D02C: Sprite 5 color
70
+ # $D02D: Sprite 6 color
71
+ # $D02E: Sprite 7 color
72
+ #
73
+ # == VIC-IIe (8566 and 8564)
74
+ #
75
+ # $D02F: Extra keyboard lines K0-K2 in bits 0-2, bits 3-7 read 1
76
+ # $D030: FAST (2 MHz) in bit 0 and TEST in bit 1, bits 2-7 read 1
77
+ #
78
+ # $D02F-$D03F: Not in use on the 6569 and 8565, always reads 0xff,
79
+ # and $D031-$D03F on the VIC-IIe
80
+ # $D040-$D3FF: Repeat $D0000 to $D03F every 64 bytes
81
+ class Registers
82
+ include IntegerHelper
83
+
84
+ # The raw register bytes, for the per-column reads on the hot path.
85
+ attr_reader :bytes
86
+
87
+ # Every register powers on as zero, as in VICE. A VIC-IIe reads
88
+ # $D02F and $D030 back as registers.
89
+ def initialize(iie: false)
90
+ @bytes = Array.new(2**6, 0)
91
+ @irq_line = false
92
+ @iie = iie
93
+ end
94
+
95
+ # True while any enabled latch bit is set in $D019/$D01A. Cached and
96
+ # re-evaluated on writes, since it's checked every cycle.
97
+ def irq_line? = @irq_line
98
+
99
+ def [](reg) = @bytes[reg]
100
+
101
+ def read(reg)
102
+ case reg
103
+ when 0x16 then @bytes[reg] | 0xc0 # bits 7-6 unused, read 1
104
+ when 0x18 then @bytes[reg] | 0x01 # bit 0 unused, reads 1
105
+ when 0x1a, 0x20..0x2e then @bytes[reg] | 0xf0
106
+ when 0x1e, 0x1f then read_clear(reg) # collision registers clear on read
107
+ when 0x2f then @iie ? @bytes[reg] | 0xf8 : 0xff
108
+ when 0x30 then @iie ? @bytes[reg] | 0xfc : 0xff
109
+ when 0x31..0x3f then 0xff
110
+ else @bytes[reg]
111
+ end
112
+ end
113
+
114
+ def write(reg, value)
115
+ case reg
116
+ when 0x19 # write 1 to clear
117
+ @bytes[reg] &= ~value
118
+ update_irq_line
119
+ when 0x1a # only the four latch bits
120
+ @bytes[reg] = value & 0x0f
121
+ update_irq_line
122
+ when 0x1e, 0x1f then nil # the collision registers are read-only
123
+ else @bytes[reg] = value
124
+ end
125
+ end
126
+
127
+ # Graphics modes
128
+ def ecm = @bytes[0x11][6]
129
+ def bmm = @bytes[0x11][5]
130
+ def mcm = @bytes[0x16][4]
131
+ # ECM/BMM from $D011 bits 6-5, MCM from $D016 bit 4.
132
+ def mode = ((@bytes[0x11] >> 4) & 0b110) | ((@bytes[0x16] >> 4) & 0b001)
133
+
134
+ def xscroll = @bytes[0x16] & 0b0111
135
+ def yscroll = @bytes[0x11] & 0b0111
136
+
137
+ def rsel? = @bytes[0x11].anybits?(0x08)
138
+ def csel? = @bytes[0x16].anybits?(0x08)
139
+ def display_enabled? = @bytes[0x11].anybits?(0x10)
140
+
141
+ def char_base = (@bytes[0x18] & 0b1110) * 0x400
142
+ def bitmap_base = (@bytes[0x18] & 0b1000) * 0x400
143
+ def screen_base = (@bytes[0x18] >> 4) * 0x400
144
+
145
+ def border = @bytes[0x20] & 0x0f
146
+ def background(index = 0) = @bytes[0x21 + index] & 0x0f
147
+
148
+ # The VIC-IIe's $D02F and $D030 bits. The 6569 and 8565 drive no
149
+ # extra keyboard lines and run at 1 MHz.
150
+ def extra_keyboard_lines = @iie ? @bytes[0x2f] & 0x07 : 0x07
151
+ def fast? = @iie && @bytes[0x30].anybits?(0x01)
152
+ def test? = @iie && @bytes[0x30].anybits?(0x02)
153
+
154
+ # FAST and TEST as bits 0 and 1.
155
+ def clock_bits = @iie ? @bytes[0x30] & 0x03 : 0
156
+
157
+ def raster_target = uint16(@bytes[0x12], (@bytes[0x11] & 0x80) >> 7)
158
+
159
+ def latch_irq!(bit)
160
+ @bytes[0x19] |= bit
161
+ update_irq_line
162
+ end
163
+
164
+ def latch_raster_irq! = latch_irq!(0x01)
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
+ def collide!(reg, bits)
176
+ return false if bits.zero?
177
+
178
+ was_zero = @bytes[reg].zero?
179
+ @bytes[reg] |= bits
180
+ was_zero
181
+ end
182
+
183
+ # Works the IRQ line out from $D019 and $D01A again, after the bytes
184
+ # were set directly.
185
+ def update_irq_line
186
+ @irq_line = (@bytes[0x19] & @bytes[0x1a]).anybits?(0x0f)
187
+ end
188
+
189
+ private
190
+
191
+ def read_clear(reg)
192
+ @bytes[reg].tap { @bytes[reg] = 0 }
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIC
6
+ # The VIC's state for a snapshot.
7
+ module SavedState
8
+ # Everything the VIC holds between cycles: the beam, the fetch and
9
+ # g-access pipeline, the light pen and raster latches, the finished
10
+ # lines, on the VIC-IIe the display line and the TEST bit's wrap, the
11
+ # registers and the display, sequencer and sprite logic.
12
+ # Whether it renders is the host's, and every line comes back dirty so
13
+ # a front end repaints.
14
+ def save_state(out)
15
+ out.marker("VIC")
16
+ out.int(@column).int(@rasterline)
17
+ out.int(@g_tick).ints(@g_kind).int(@g_kept_char).int(@g_kept_color).boolean(@g_display)
18
+ out.int(@fetch_d011).boolean(@lp_triggered).boolean(@lp_low).boolean(@raster_match)
19
+ out.int(@vic_bank.lines)
20
+ out.blob(@character_buffer).blob(@color_buffer).booleans(@sprite_ba)
21
+ @lines.each { |line| out.blob(line) }
22
+ out.int(@output_line).boolean(@test_wrap) if @iie
23
+ @registers.save_state(out)
24
+ @display_state.save_state(out)
25
+ @sequencer.save_state(out)
26
+ @sprites.save_state(out)
27
+ end
28
+
29
+ def load_state(input)
30
+ input.marker("VIC")
31
+ load_beam(input)
32
+ load_buffers(input)
33
+ load_lines(input)
34
+ load_test_state(input) if @iie
35
+ @registers.load_state(input)
36
+ @display_state.load_state(input)
37
+ @sequencer.load_state(input)
38
+ @sprites.load_state(input)
39
+ end
40
+
41
+ private
42
+
43
+ def load_beam(input)
44
+ @column = input.int
45
+ @rasterline = @output_line = input.int
46
+ @g_tick = input.int
47
+ input.ints_into(@g_kind)
48
+ @g_kept_char = input.int
49
+ @g_kept_color = input.int
50
+ @g_display = input.boolean?
51
+ @fetch_d011 = input.int
52
+ @lp_triggered = input.boolean?
53
+ @lp_low = input.boolean?
54
+ @raster_match = input.boolean?
55
+ @vic_bank.lines = input.int
56
+ end
57
+
58
+ def load_buffers(input)
59
+ input.blob_into(@character_buffer)
60
+ input.blob_into(@color_buffer)
61
+ input.booleans_into(@sprite_ba)
62
+ end
63
+
64
+ # The VIC-IIe's display line and TEST wrap, which only its TEST bit
65
+ # moves off the raster line.
66
+ def load_test_state(input)
67
+ @output_line = input.int
68
+ @test_wrap = input.boolean?
69
+ end
70
+
71
+ # The display is the finished lines one after another.
72
+ def load_lines(input)
73
+ @lines.each_with_index do |line, number|
74
+ input.blob_into(line)
75
+ @display[number * @width, @width] = line
76
+ end
77
+ @dirty_lines.fill(true)
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIC
6
+ class Sequencer
7
+ # The sequencer's save_state and load_state.
8
+ module SavedState
9
+ FG_SHIFTER = -1
10
+ PAIR_CODES = 256
11
+
12
+ # The line buffers, the border flip-flops, the g-access ring and the
13
+ # pixel pipeline. The foreground masks the groups point at go as
14
+ # FG_SHIFTER for the shift register's, or their data byte in
15
+ # GraphicsMode's HIRES_FG, or that plus 256 in its PAIR_FG. The left
16
+ # vertical border compare goes as -1 before it has run.
17
+ def save_state(out)
18
+ out.int(@line).boolean(@first_csel).int(@left_vertical_border.nil? ? -1 : bit(@left_vertical_border))
19
+ out.blob(@colors).booleans(@fg)
20
+ @border_mask.save_state(out)
21
+ out.ints(@cur_colors).int(fg_code(@cur_fg)).ints(@prev_colors).int(fg_code(@prev_fg))
22
+ out.boolean(@vertical_border).boolean(@vertical_armed).boolean(@main_border)
23
+ @color_patches.save_state(out)
24
+ @shifter.save_state(out)
25
+ out.int(@xscroll).int(@last_shift).int(@last_mode).boolean(@settling).boolean(@prev_fresh).boolean(@check)
26
+ out.ints(@ring_data).ints(@ring_char).ints(@ring_color)
27
+ end
28
+
29
+ def load_state(input)
30
+ load_line(input)
31
+ @border_mask.load_state(input)
32
+ input.ints_into(@cur_colors)
33
+ @cur_fg = fg_pattern(input.int)
34
+ input.ints_into(@prev_colors)
35
+ @prev_fg = fg_pattern(input.int)
36
+ @vertical_border = input.boolean?
37
+ @vertical_armed = input.boolean?
38
+ @main_border = input.boolean?
39
+ @color_patches.load_state(input)
40
+ @shifter.load_state(input)
41
+ load_pipeline(input)
42
+ end
43
+
44
+ private
45
+
46
+ def bit(flag) = flag ? 1 : 0
47
+
48
+ def load_line(input)
49
+ @line = input.int
50
+ @first_csel = input.boolean?
51
+ left = input.int
52
+ @left_vertical_border = left.negative? ? nil : left == 1
53
+ input.blob_into(@colors)
54
+ input.booleans_into(@fg)
55
+ end
56
+
57
+ def load_pipeline(input)
58
+ @xscroll = input.int
59
+ @last_shift = input.int
60
+ @last_mode = input.int
61
+ @settling = input.boolean?
62
+ @prev_fresh = input.boolean?
63
+ @check = input.boolean?
64
+ input.ints_into(@ring_data)
65
+ input.ints_into(@ring_char)
66
+ input.ints_into(@ring_color)
67
+ end
68
+
69
+ def fg_code(pattern)
70
+ return FG_SHIFTER if pattern.equal?(@shifter.fg)
71
+
72
+ hires = GraphicsMode::HIRES_FG.index { |fg| fg.equal?(pattern) }
73
+ return hires if hires
74
+
75
+ pair = GraphicsMode::PAIR_FG.index { |fg| fg.equal?(pattern) }
76
+ raise ArgumentError, "a foreground mask the sequencer doesn't know" unless pair
77
+
78
+ PAIR_CODES + pair
79
+ end
80
+
81
+ def fg_pattern(code)
82
+ return @shifter.fg if code == FG_SHIFTER
83
+ return GraphicsMode::HIRES_FG.fetch(code) if code < PAIR_CODES
84
+
85
+ GraphicsMode::PAIR_FG.fetch(code - PAIR_CODES)
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,277 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/chips/vic/border_mask"
4
+ require "badline/chips/vic/color_patches"
5
+ require "badline/chips/vic/graphics_mode"
6
+ require "badline/chips/vic/graphics_shifter"
7
+ require "badline/chips/vic/sequencer_output"
8
+ require "badline/chips/vic/sequencer/saved_state"
9
+
10
+ module Badline
11
+ module Chips
12
+ class VIC
13
+ # = VIC-II Sequencer
14
+ #
15
+ # Turns fetched graphics data into output pixels.
16
+ class Sequencer
17
+ include Output
18
+ include SavedState
19
+
20
+ BORDER_Y_BOUNDS = [
21
+ [55, 247].freeze,
22
+ [51, 251].freeze
23
+ ].freeze
24
+
25
+ MODES = GraphicsMode::MODES
26
+
27
+ attr_reader :colors, :fg, :registers, :bank, :cur_colors,
28
+ :color_patches
29
+ # The fg masks are shared frozen patterns assigned by reference, never
30
+ # mutated in place.
31
+ attr_accessor :cur_fg
32
+ # False leaves the line's colours unpainted and keeps only the
33
+ # foreground mask the sprite collisions read.
34
+ attr_writer :render
35
+
36
+ def initialize(width, registers, bank, model: :mos6569, region: Region::PAL)
37
+ @width = width
38
+ window_bounds(region.display_x_bounds)
39
+ @registers = registers
40
+ @bank = bank
41
+ @colors = Array.new(width, 0)
42
+ @fg = Array.new(width, false)
43
+ @border_mask = BorderMask.new(width)
44
+ # Hot-path aliases: the pixel loops write coverage straight into the
45
+ # mask's arrays.
46
+ @border = @border_mask.mask
47
+ @border_groups = @border_mask.groups
48
+ @cur_colors = Array.new(8, 0)
49
+ @cur_fg = GraphicsMode::NO_FG
50
+ @prev_colors = Array.new(8, 0)
51
+ @prev_fg = GraphicsMode::NO_FG
52
+ @vertical_border = true
53
+ @vertical_armed = true
54
+ @main_border = true
55
+ @color_patches = ColorPatches.new(self, grey_dots: model == :mos8565)
56
+ @shifter = GraphicsShifter.new(registers, model:)
57
+ @xscroll = 0
58
+ @last_shift = 0
59
+ @last_mode = 0
60
+ @settling = false
61
+ @ring_data = Array.new(4, 0)
62
+ @ring_char = Array.new(4, 0)
63
+ @ring_color = Array.new(4, 1)
64
+ @prev_fresh = false
65
+ @check = true
66
+ @render = true
67
+ new_line(0)
68
+ end
69
+
70
+ # Reset the line buffers at the start of a rasterline.
71
+ def new_line(line)
72
+ @line = line
73
+ @left_vertical_border = nil
74
+ @first_csel = @registers.csel?
75
+ @colors.fill(@registers.border)
76
+ @fg.fill(false)
77
+ @border_mask.reset
78
+ @prev_colors.fill(@registers.background)
79
+ @prev_fg = GraphicsMode::NO_FG
80
+ @prev_fresh = false
81
+ @check = true
82
+ @color_patches.clear
83
+ end
84
+
85
+ # The load point for the next group's byte: XSCROLL as a g-access
86
+ # column with the border open sees it, a column before the group that
87
+ # uses it (VICE x64sc `xscroll_pipe`).
88
+ def latch_xscroll(xscroll = @registers.xscroll)
89
+ return if xscroll == @xscroll
90
+
91
+ @xscroll = xscroll
92
+ @check = true
93
+ end
94
+
95
+ # A write to a register the painted colours depend on: the byte kept
96
+ # from the previous group is painted again before its pixels are shown.
97
+ def colors_changed!
98
+ @prev_fresh = false
99
+ @check = true
100
+ end
101
+
102
+ def apply_color_patches
103
+ @color_patches.apply(@colors, @fg)
104
+ end
105
+
106
+ # The vertical border compares run in every cycle of their line (VICE
107
+ # x64sc). The top one resets the flip-flop at once when DEN is set. The
108
+ # bottom one only arms it, and the armed state takes hold at the line's
109
+ # first cycle and at the left window edge (Bauer §3.9 rules 2-5). The
110
+ # VIC calls this after each $d011 write.
111
+ def compare_vertical_border(line)
112
+ top, bottom = BORDER_Y_BOUNDS[@registers.rsel? ? 1 : 0]
113
+ @vertical_armed = true if line == bottom
114
+ @vertical_armed = @vertical_border = false if line == top && @registers.display_enabled?
115
+ end
116
+
117
+ # The line's first cycle, Bauer's cycle 1, which is the last column of
118
+ # the line before it.
119
+ def start_vertical_border(line)
120
+ compare_vertical_border(line)
121
+ @vertical_border = @vertical_armed
122
+ end
123
+
124
+ # The 40-column left compare, a column before the column that draws its
125
+ # pixel. The 38-column one runs in the drawing column.
126
+ def left_compare_vertical_border
127
+ @left_vertical_border = start_vertical_border(@line) if @registers.csel?
128
+ end
129
+
130
+ def border_at?(pixel_x) = @border_mask.at?(pixel_x)
131
+
132
+ # True while the vertical border flip-flop is set and stays set for the
133
+ # rest of the line: it can only clear mid-line on a top compare line
134
+ # with DEN set.
135
+ def vertical_closed?
136
+ return false unless @vertical_border
137
+ return true unless @line == 51 || @line == 55
138
+
139
+ top, = BORDER_Y_BOUNDS[@registers.rsel? ? 1 : 0]
140
+ !(@line == top && @registers.display_enabled?)
141
+ end
142
+
143
+ # Snapshot the finished line so apply_border can restore the border
144
+ # pixels sprites were composited over, keeping mid-line border splits.
145
+ def snapshot_line = @border_mask.snapshot(@colors)
146
+
147
+ # Repaint the border over the composited line, hiding the sprites.
148
+ def apply_border = @border_mask.restore(@colors)
149
+
150
+ # The g-accesses the VIC hands over, as a ring the column's slot
151
+ # indexes: the byte read, the screen byte and the colour nibble. The
152
+ # slot before is the byte the previous group loaded.
153
+ attr_reader :ring_data, :ring_char, :ring_color
154
+
155
+ # The border flip-flops: vertical, the vertical one armed to set, and
156
+ # the main one.
157
+ def borders = [@vertical_border, @vertical_armed, @main_border]
158
+
159
+ def restore_borders(vertical, armed, main)
160
+ @vertical_border = vertical
161
+ @vertical_armed = armed
162
+ @main_border = main
163
+ end
164
+
165
+ # Paints the byte in the slot through the current mode. An idle access
166
+ # latches 0/0 and one that made no access passes on zero data with the
167
+ # kept values; under a closed border neither has foreground. A group
168
+ # where the mode or the load point changes, and the one after it, run
169
+ # the shift register pixel by pixel.
170
+ def emit(slot, col, display)
171
+ mode = @registers.mode
172
+ return emit_checked(slot, col, display, mode) if @check || mode != @last_mode
173
+
174
+ paint_slot(slot, mode, display)
175
+ output(col, @last_shift)
176
+ roll
177
+ end
178
+
179
+ private
180
+
181
+ # The display window's edges per CSEL state, as the region gives them.
182
+ # The graphics window always spans the full 40 columns, ignoring CSEL,
183
+ # and the border flip-flop takes [left compare, right compare] per
184
+ # CSEL state.
185
+ def window_bounds(bounds)
186
+ narrow, wide = bounds
187
+ @gfx_x_start = wide[0]
188
+ @gfx_x_end = wide[1] + 1
189
+ @window_compares = [
190
+ [narrow[0], narrow[1] + 1].freeze,
191
+ [@gfx_x_start, @gfx_x_end].freeze
192
+ ].freeze
193
+ end
194
+
195
+ # After a mode, XSCROLL or colour change: groups paint whole bytes
196
+ # again once the change has settled, and run pixel by pixel until then.
197
+ def emit_checked(slot, col, display, mode)
198
+ shift = @xscroll
199
+ if mode == @last_mode && shift == @last_shift && !@settling
200
+ emit_settled(slot, col, display, mode, shift)
201
+ else
202
+ emit_pixels(slot, col, mode, shift, !display && border_hidden?)
203
+ @settling = mode != @last_mode || shift != @last_shift
204
+ @last_mode = mode
205
+ @last_shift = shift
206
+ end
207
+ end
208
+
209
+ def emit_settled(slot, col, display, mode, shift)
210
+ repaint_previous(mode, (slot - 1) & 3) unless @prev_fresh || shift.zero?
211
+ paint_slot(slot, mode, display)
212
+ output(col, shift)
213
+ roll
214
+ @prev_fresh = true
215
+ @check = false
216
+ end
217
+
218
+ def paint_slot(slot, mode, display)
219
+ if !display && border_hidden?
220
+ @cur_fg = GraphicsMode::NO_FG
221
+ else
222
+ paint(slot, mode)
223
+ end
224
+ end
225
+
226
+ def repaint_previous(mode, slot)
227
+ roll
228
+ paint(slot, mode)
229
+ roll
230
+ end
231
+
232
+ def paint(slot, mode)
233
+ if @render
234
+ MODES[mode].paint(@ring_data[slot], @ring_char[slot], @ring_color[slot], self)
235
+ else
236
+ @cur_fg = MODES[mode].fg(@ring_data[slot], @ring_char[slot], @ring_color[slot])
237
+ end
238
+ end
239
+
240
+ def emit_pixels(slot, col, mode, shift, hidden)
241
+ prime_shifter((slot - 1) & 3) unless @settling
242
+ @shifter.draw(hidden ? 0 : @ring_data[slot], @ring_char[slot], @ring_color[slot], shift, mode)
243
+ @cur_colors[0, 8] = @shifter.colors
244
+ @cur_fg = @shifter.fg
245
+ output(col, 0)
246
+ @prev_fresh = false
247
+ @check = true
248
+ end
249
+
250
+ # Picks up from a group that painted whole bytes.
251
+ def prime_shifter(slot)
252
+ @shifter.prime(@ring_data[slot], @ring_char[slot], @ring_color[slot], @last_shift, @last_mode)
253
+ end
254
+
255
+ # The group is border throughout when the main flip-flop is set and the
256
+ # vertical one keeps it from clearing.
257
+ def border_hidden? = @main_border && vertical_closed?
258
+
259
+ def pixel_shown?(pixel_x, left_compare, right_compare)
260
+ @main_border = true if pixel_x == right_compare
261
+ @main_border = false if pixel_x == left_compare && !left_vertical_border
262
+ !@main_border
263
+ end
264
+
265
+ def left_vertical_border
266
+ @left_vertical_border.nil? ? start_vertical_border(@line) : @left_vertical_border
267
+ end
268
+
269
+ def roll
270
+ @prev_colors, @cur_colors = @cur_colors, @prev_colors
271
+ @prev_fg, @cur_fg = @cur_fg, @prev_fg
272
+ nil
273
+ end
274
+ end
275
+ end
276
+ end
277
+ end