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
@@ -1,146 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class VIC
5
- class Sprite
6
- # The X comparator and the 24-bit shift register behind it: where a
7
- # line fires the sprite, and the pixels each firing shifts out.
8
- module Shifter
9
- private
10
-
11
- # The first pixel of every comparator match along the line. Writes to
12
- # $d000/$d010 move the compare value mid-line, so a sprite can miss
13
- # its match entirely and pick up a later one, a second one, or none.
14
- def comparator_hits(log)
15
- return compare_x(@registers) unless log
16
-
17
- hits = []
18
- log.rewind
19
- log.advance(0)
20
- from = 0
21
- while from < @width
22
- upto = [log.next_x, @width].min
23
- compare_x(log).each do |start|
24
- match = (start - 1) % @width
25
- hits << start if match >= from && match < upto
26
- end
27
- break if upto >= @width
28
-
29
- from = upto
30
- log.advance(from)
31
- end
32
- hits
33
- end
34
-
35
- # The pixels the sprite starts at, one past each comparator match.
36
- # The 6569's X counter only runs to 503, so the eight coordinates
37
- # above it never match and the sprite stays dark — the gap the
38
- # spritegap tests find at $1f8.
39
- def compare_x(view)
40
- msb = view[0x10].anybits?(@bit) ? 0x100 : 0
41
- @timing.x_pixels[msb | view[index * 2]]
42
- end
43
-
44
- # Pixels from the X match to the next reload.
45
- def reload_cut(start) = (start < @reload_x ? @reload_x : @reload_x + @width) - start
46
-
47
- # A run that reaches the next reload is cut there, holding its last
48
- # pixel through K+6. Returns the span that is left.
49
- def cut_at_reload(cut, span, codes)
50
- return span if cut > span || cut >= MAX_SPAN
51
-
52
- RELOAD_HOLD.times { |i| codes[cut + i] = codes[cut - 1] }
53
- cut + RELOAD_HOLD
54
- end
55
-
56
- # Shift one firing out into `codes`, up to the sprite's end, `cut`
57
- # pixels from the reload.
58
- def run(log, start, codes, bits, cut)
59
- @sr = bits
60
- log&.rewind
61
- pos = start
62
- count = 0
63
- boundary = log ? 0 : Float::INFINITY
64
- mc = multicolor?
65
- expanded = x_expanded?
66
- while count < MAX_SPAN
67
- if pos >= boundary
68
- log.advance(pos)
69
- expanded = log[0x1d].anybits?(@bit)
70
- mc = logged_multicolor(log, mc, expanded, count)
71
- boundary = log.next_x
72
- end
73
- count.zero? ? prime(mc) : step(mc, expanded, count == cut - 1)
74
- break if @latch.zero? && @sr.zero?
75
-
76
- codes[count] = @latch
77
- count += 1
78
- pos += 1
79
- end
80
- count
81
- end
82
-
83
- # The X match loads the shift register and arms both flip-flops, so
84
- # the sprite's first pixel comes straight off the fetched row.
85
- def prime(multicolor)
86
- @mc_flop = @new_chip && !multicolor
87
- @xe_flop = false
88
- @latch = (@sr >> 22) & (multicolor ? 3 : 2)
89
- end
90
-
91
- # The multicolor bit as the log has it at the pixel. A change after
92
- # the first pixel reaches the 8565's flip-flop.
93
- def logged_multicolor(log, was, expanded, count)
94
- multicolor = log[0x1c].anybits?(@bit)
95
- switch_multicolor(multicolor, expanded) if @new_chip && multicolor != was && count.positive?
96
- multicolor
97
- end
98
-
99
- # On the 8565 a multicolor change works on the flip-flop instead of
100
- # the next pixels. It stays as it is unless the change lands between
101
- # the two halves of an expanded pixel, where it flips, or is set by a
102
- # switch to hi-res.
103
- def switch_multicolor(multicolor, expanded)
104
- return unless expanded && !@xe_flop
105
-
106
- @mc_flop = multicolor ? !@mc_flop : true
107
- end
108
-
109
- # One pixel of the sequencer. An unexpanded sprite shifts every pixel;
110
- # an expanded one shifts every other, and the multicolor latch reloads
111
- # every other shift, so its pairs stretch with the expansion. Both
112
- # flip-flops sit idle while their register bit is clear, which is why
113
- # the first pixel after a mid-sprite change repeats the last one.
114
- def step(multicolor, expanded, last)
115
- shift = true
116
- if expanded
117
- shift = @xe_flop
118
- @xe_flop = !@xe_flop
119
- else
120
- @xe_flop = false
121
- end
122
- @mc_flop = false unless multicolor || @new_chip
123
- return unless shift
124
-
125
- @sr = (@sr << 1) & 0xffffff
126
- load_latch(multicolor, last)
127
- end
128
-
129
- # A multicolor pair loaded on the last pixel before the reload keeps
130
- # only its high bit, as a hi-res pixel does (spritefetchbug).
131
- # On the 8565 a hi-res pixel with the multicolor flip-flop clear
132
- # sets it and loads nothing, so the latch repeats its last pixel.
133
- def load_latch(multicolor, last)
134
- if multicolor
135
- @latch = (@sr >> 22) & (last ? 2 : 3) if @mc_flop
136
- @mc_flop = !@mc_flop
137
- elsif @new_chip && !@mc_flop
138
- @mc_flop = true
139
- else
140
- @latch = (@sr >> 22) & 2
141
- end
142
- end
143
- end
144
- end
145
- end
146
- end
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class VIC
5
- class Sprite
6
- # = Timing
7
- #
8
- # Where a region puts the sprites in the line: the cycles of their
9
- # fetches and of the display compare, the pixels those land on, and
10
- # the raster pixels the X counter reads each coordinate at. Where the
11
- # fetches or the compare run a cycle later than on the 6569, what
12
- # hangs off them moves 8 pixels with them.
13
- class Timing
14
- # The X counter's value where it steps back on a raster of more than
15
- # 512 pixels, to run over the eight values below it again.
16
- HOLD_AT = 0x188
17
-
18
- attr_reader :columns, :sprite_cycle, :display_off_x, :x_pixels
19
-
20
- def initialize(region)
21
- @columns = region.cycles_per_line
22
- @sprite_cycle = region.sprite_cycle
23
- @shift = region.sprite_cycle - Region::PAL.sprite_cycle
24
- @display_off_x = DISPLAY_OFF_X + (8 * (region.sprite_display_cycle - Region::PAL.sprite_display_cycle))
25
- @x_pixels = Timing.x_pixels(@columns * 8, region.x_hold)
26
- end
27
-
28
- # The column BA falls in for a sprite's own fetch: 55 for sprite 0 on
29
- # the 6569, and two later for each sprite after it.
30
- def ba_column(index) = 55 + @shift + (2 * index)
31
-
32
- # The raster pixel of a sprite's reload, counted from the start of
33
- # the line it is fetched on, so past the end of it for sprites 3-7
34
- # on the 6569.
35
- def reload_x(index) = RELOAD_X + (8 * @shift) + (RELOAD_STEP * index)
36
-
37
- # The X counter at a raster pixel: X_OFFSET behind it, wrapping at
38
- # the end of the line, less the pixels it held for from HOLD_AT on,
39
- # where it ran over $180-$187 a second time.
40
- def self.xpos(pixel, width, hold)
41
- count = (pixel - X_OFFSET) % width
42
- count < HOLD_AT ? count : count - hold
43
- end
44
-
45
- # The raster pixels at which the X counter reads each coordinate, 512
46
- # lists. A sprite starts at one where its X matches. On the 6569 the
47
- # coordinates past 503 have none.
48
- def self.x_pixels(width, hold)
49
- pixels = Array.new(512) { [] }
50
- width.times { |pixel| pixels[xpos(pixel, width, hold)] << pixel }
51
- pixels.each(&:freeze).freeze
52
- end
53
- end
54
- end
55
- end
56
- end
@@ -1,337 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "badline/vic/sprite/internal_bus"
4
- require "badline/vic/sprite/shifter"
5
- require "badline/vic/sprite/saved_state"
6
- require "badline/vic/sprite/timing"
7
-
8
- module Badline
9
- class VIC
10
- # = Sprite
11
- #
12
- # The DMA/display state machine and the pixel sequencer for one sprite.
13
- # The sequencer is a 24-bit shift register clocked once per pixel: the X
14
- # comparator starts it, the expansion flip-flop gates the shift, and the
15
- # multicolor flip-flop gates a two-bit output latch that feeds the color
16
- # mux. Registers written mid-sprite therefore take hold from the pixel
17
- # they reach, rather than re-decoding the row.
18
- class Sprite
19
- X_OFFSET = 104
20
-
21
- # MCBASE and MC are six-bit byte counters into the sprite's 64-byte
22
- # block. A sprite ends when MCBASE reaches exactly 63, which is why a
23
- # mid-line $d017 write that steps it past 63 keeps it running.
24
- LAST_MCBASE = 63
25
- MC_MASK = 0x3f
26
-
27
- # 24 bits at two pixels each, plus slack for a mid-sprite expansion
28
- # change stretching the tail.
29
- MAX_SPAN = 64
30
-
31
- # Latch codes are the multicolor bit pairs: 0 is transparent, 1 and 3
32
- # are the shared colors, 2 the sprite's own.
33
- SHARED0 = 1
34
- OWN_COLOR = 2
35
- SHARED1 = 3
36
-
37
- # The s-accesses reload the shift register partway through the line,
38
- # at raster pixel 459 for sprite 0 and 16 later for each sprite after
39
- # it. A sprite still shifting there loses the rest of its row, and the
40
- # comparator is ignored for the twelve pixels from it, running on into
41
- # the next line from a reload near the end of this one (the spritescan
42
- # dumps). Its output holds the last pixel for seven, through K+6
43
- # (spritefetchbug).
44
- RELOAD_X = 459
45
- RELOAD_STEP = 16
46
- RELOAD_DEAD = 12
47
- RELOAD_HOLD = 7
48
-
49
- # On the line of its last row, a sprite whose DMA ended at cycle 16
50
- # loses its display at cycle 58, so no hit from this pixel on starts
51
- # it (spritegap3). One already shifting runs on. A region whose
52
- # display compare falls later moves it with the compare.
53
- DISPLAY_OFF_X = 460
54
-
55
- include Shifter
56
- include SavedState
57
-
58
- attr_reader :index, :leftmost, :span, :codes,
59
- :reload_leftmost, :reload_span, :reload_codes
60
-
61
- def initialize(index, registers, bank, bus, model: :mos6569)
62
- @index = index
63
- @new_chip = model == :mos8565
64
- @registers = registers
65
- @bank = bank
66
- @bus = bus
67
- @width = bus.columns * 8
68
- @timing = bus.timing
69
- @bit = 1 << index
70
- @dma = false
71
- @display_on = false
72
- @mcbase = 0
73
- @mc = 0
74
- @exp_ff = true
75
- @crunched_mc = nil
76
- @bits = 0
77
- @row_ready = false
78
- @codes = Array.new(MAX_SPAN + RELOAD_HOLD, 0)
79
- @leftmost = 0
80
- @span = 0
81
- @reload_codes = Array.new(MAX_SPAN + RELOAD_HOLD, 0)
82
- @reload_leftmost = 0
83
- @reload_span = 0
84
- reload = @timing.reload_x(index)
85
- @reload_x = reload % @width
86
- @reload_next_line = reload < @width
87
- @sr = 0
88
- @latch = 0
89
- @mc_flop = false
90
- @xe_flop = false
91
- @first_byte_lost = false
92
- @blind = false
93
- @show_from = 0
94
- end
95
-
96
- def displaying? = @dma
97
-
98
- # True when this line has a row for the sequencer: its own, the next
99
- # one for a sprite that reloads late in the line, or the last one for
100
- # a sprite that reloads at its start.
101
- def rendering?
102
- return true if @row_ready
103
-
104
- @reload_next_line ? @dma && @display_on : !@prev_bits.nil?
105
- end
106
-
107
- def enabled? = @registers[0x15].anybits?(@bit)
108
- def multicolor? = @registers[0x1c].anybits?(@bit)
109
- def x_expanded? = @registers[0x1d].anybits?(@bit)
110
- def y_expanded? = @registers[0x17].anybits?(@bit)
111
- def priority? = @registers[0x1b].anybits?(@bit)
112
-
113
- def x
114
- msb = @registers[0x10].anybits?(@bit) ? 0x100 : 0
115
- msb | @registers[index * 2]
116
- end
117
-
118
- # The Y comparator is eight bits wide, so the PAL lines above 255
119
- # match the coordinates 0-55 a second time (spritey).
120
- def y_match?(line) = (line & 0xff) == @registers[(index * 2) + 1]
121
-
122
- def color = @registers[0x27 + index] & 0x0f
123
-
124
- # Cycle 16: MCBASE takes MC, which the three s-accesses stepped past
125
- # the row, but only while the expansion flip-flop is set.
126
- def advance_mcbase
127
- mc = @crunched_mc || ((@mc + 3) & MC_MASK)
128
- @crunched_mc = nil
129
- @mcbase = mc if @exp_ff && @dma
130
- end
131
-
132
- # The end-of-sprite compare, a column after MCBASE moves. MCBASE has
133
- # to land on 63 exactly, so a crunched sprite steps over it and runs
134
- # on through the rest of its block. Only the DMA stops here; the
135
- # display waits for cycle 58.
136
- def finish_mcbase
137
- @dma = false if @mcbase == LAST_MCBASE
138
- end
139
-
140
- # Clearing MxYE sets the expansion flip-flop at once. Cleared in
141
- # cycle 15, while the flip-flop is still reset, it also crunches MC:
142
- # the bits step to a mix of MC and MCBASE (Bauer §3.8, VICE
143
- # `d017_store`) that cycle 16 then hands to MCBASE.
144
- def clear_y_expansion(crunch)
145
- return if @exp_ff
146
-
147
- @exp_ff = true
148
- return unless crunch && @dma
149
-
150
- mc = (@mc + 3) & MC_MASK
151
- @crunched_mc = (0x2a & @mcbase & mc) | (0x15 & (@mcbase | mc))
152
- end
153
-
154
- # Cycle 56, after the second Y compare: MxYE inverts the expansion
155
- # flip-flop of a sprite with DMA running.
156
- def toggle_expansion
157
- @exp_ff = !@exp_ff if @dma && y_expanded?
158
- end
159
-
160
- # Cycles 55 and 56: a Y/enable match starts the DMA and rewinds
161
- # MCBASE, and returns true. Display is enabled separately in cycle 58,
162
- # so the rows render from the following line on.
163
- #
164
- # On the VIC's side, BA falls at the sprite's own column
165
- # (Timing#ba_column) — 55 for sprite 0 on the 6569, two later for each
166
- # sprite after it, a column behind the window the CPU sees
167
- # (VIC#layout_columns) — or two columns after
168
- # this compare, whichever is later. AEC follows three columns on, and
169
- # the first of the three s-accesses runs in the column it arrives in:
170
- # a DMA starting on the second compare therefore loses that access for
171
- # sprite 0, alone among the eight in following the compares
172
- # immediately (spriteenable2).
173
- def check_dma(line, column)
174
- return false if @dma || !enabled? || !y_match?(line)
175
-
176
- @first_byte_lost = column + 2 > @timing.ba_column(index)
177
- @dma = true
178
- @mcbase = 0
179
- @exp_ff = true
180
- end
181
-
182
- # Cycle 58: MC is reloaded from MCBASE for the coming row, and a
183
- # sprite with DMA running starts displaying only while MxE and Y still
184
- # match — a write to either between the compares and here keeps the
185
- # data fetch running invisibly. The display goes off only here, and
186
- # only once the DMA has, so a DMA restarted on the line of its last
187
- # row keeps a display that was already on (spriterestart).
188
- def check_display(line)
189
- @mc = @mcbase
190
- if @dma
191
- @display_on = true if enabled? && y_match?(line)
192
- else
193
- @display_on = false
194
- end
195
- blind_fetch if @blind && @display_on
196
- end
197
-
198
- # The address of the s-access that falls in phi1, the middle of the
199
- # three, or nil when the sprite's DMA is off and the VIC idles there.
200
- def phi1_address
201
- (pointer * 64) + ((@mc + 1) & MC_MASK) if @dma
202
- end
203
-
204
- # The row fetched at the end of the previous line renders on this one.
205
- # A lost first s-access reads back the $ff the CPU is still driving.
206
- def start_line
207
- @span = 0
208
- @reload_span = 0
209
- @prev_bits = (@bits if @row_ready && @dma)
210
- @row_ready = false
211
- @blind = !@dma && !@reload_next_line
212
- @show_from = 0
213
- lost = @first_byte_lost
214
- @first_byte_lost = false
215
- return unless @dma && @display_on
216
-
217
- @bits = row_bits(@mc)
218
- @bits |= 0xff << 16 if lost
219
- @row_ready = true
220
- end
221
-
222
- # Replay the line through the pixel sequencer, filling the code buffer
223
- # from the X match on. A log of mid-line register writes makes the
224
- # comparator and the shift register see the values each pixel was
225
- # drawn with.
226
- #
227
- # The row can be shown once before the reload and once after it, so a
228
- # sprite moved past the beam can fire a second time on the same line
229
- # (spritex). A match inside the dead pixels shows nothing.
230
- def sequence(log = nil)
231
- @span = 0
232
- @reload_span = 0
233
- reload_bits = reload_row
234
- return unless @row_ready || @prev_bits || reload_bits
235
-
236
- log = nil if log.nil? || log.empty?
237
- @stop_x = @dma ? nil : @timing.display_off_x
238
- comparator_hits(log).each { |start| sequence_hit(log, start, reload_bits) }
239
- end
240
-
241
- # The color at a raster position, for a sprite sequenced with the
242
- # registers as they stand.
243
- def pixel(raster_x)
244
- code = code_at(raster_x, @leftmost, @span, @codes) ||
245
- code_at(raster_x, @reload_leftmost, @reload_span, @reload_codes)
246
- return nil if code.nil? || code.zero?
247
-
248
- palette(@registers, Array.new(4, 0))[code]
249
- end
250
-
251
- # Fill a four-entry lookup from latch code to color, against a view of
252
- # the color registers.
253
- def palette(view, into)
254
- into[SHARED0] = view[0x25] & 0x0f
255
- into[OWN_COLOR] = view[0x27 + index] & 0x0f
256
- into[SHARED1] = view[0x26] & 0x0f
257
- into
258
- end
259
-
260
- private
261
-
262
- # On the line whose compare started the DMA, sprites 3-7 ran their
263
- # s-accesses before it was on, so the shift register holds what the
264
- # VIC saw on its bus instead of a row, and a hit from the display
265
- # turning on shows it (sbsprf24).
266
- def blind_fetch
267
- @bits = @bus.row(index)
268
- @row_ready = true
269
- @show_from = @timing.display_off_x
270
- end
271
-
272
- def code_at(raster_x, leftmost, span, codes)
273
- dist = raster_x - leftmost
274
- dist += @width if dist.negative?
275
- codes[dist] if dist < span
276
- end
277
-
278
- def sequence_hit(log, start, reload_bits)
279
- return if (@stop_x && start >= @stop_x) || start < @show_from || start < @reload_x + RELOAD_DEAD - @width
280
-
281
- if start < @reload_x
282
- sequence_early(log, start)
283
- elsif start >= @reload_x + RELOAD_DEAD
284
- sequence_reloaded(log, start, reload_bits)
285
- end
286
- end
287
-
288
- def sequence_early(log, start)
289
- bits = early_row
290
- return unless bits && @span.zero?
291
-
292
- @leftmost = start
293
- cut = reload_cut(start)
294
- @span = cut_at_reload(cut, run(log, start, @codes, bits, cut), @codes)
295
- end
296
-
297
- def sequence_reloaded(log, start, bits)
298
- return unless bits && @reload_span.zero?
299
-
300
- @reload_leftmost = start
301
- cut = reload_cut(start)
302
- @reload_span = cut_at_reload(cut, run(log, start, @reload_codes, bits, cut), @reload_codes)
303
- end
304
-
305
- # The row in the shift register ahead of the reload: this line's for
306
- # sprites 0-2, and for the others the one their reload at the start of
307
- # the last line brought in.
308
- def early_row = @reload_next_line ? current_row : @prev_bits
309
-
310
- def current_row = (@bits if @row_ready)
311
-
312
- # The row the reload brings in. Sprites 0-2 reload late in the line
313
- # with the next line's row, so one that fires after it shows that row
314
- # a line early (spritegap); the others reload at the start of the line
315
- # with the row it already has.
316
- def reload_row
317
- return current_row unless @reload_next_line
318
- return unless @dma && @display_on
319
-
320
- bits = row_bits(@mc)
321
- bits |= 0xff << 16 if @first_byte_lost
322
- bits
323
- end
324
-
325
- # The three s-accesses step MC through the sprite's block, wrapping
326
- # within it.
327
- def row_bits(counter)
328
- base = pointer * 64
329
- (@bank.peek(base + counter) << 16) |
330
- (@bank.peek(base + ((counter + 1) & MC_MASK)) << 8) |
331
- @bank.peek(base + ((counter + 2) & MC_MASK))
332
- end
333
-
334
- def pointer = @bank.peek(@registers.screen_base + 0x3f8 + index)
335
- end
336
- end
337
- end