badline 0.12.0 → 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 (516) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -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 +4 -4
  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} +6 -6
  17. data/lib/badline/c128/bus.rb +30 -51
  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 +18 -72
  27. data/lib/badline/{computer → c64}/attachments.rb +16 -47
  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/c64/common.rb +34 -0
  73. data/lib/badline/c64/kernal_traps.rb +89 -0
  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 +20 -31
  82. data/lib/badline/{computer.rb → c64.rb} +22 -80
  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 +27 -29
  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 +10 -61
  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/{file.rb → file_routine.rb} +1 -1
  262. data/lib/badline/kernal_trap/load.rb +6 -6
  263. data/lib/badline/kernal_trap/save.rb +5 -5
  264. data/lib/badline/kernal_trap/serial.rb +7 -7
  265. data/lib/badline/kernal_trap.rb +2 -3
  266. data/lib/badline/machine/clocking.rb +50 -0
  267. data/lib/badline/machine.rb +63 -7
  268. data/lib/badline/media/boot_disk.rb +2 -2
  269. data/lib/badline/media/disk_list.rb +3 -3
  270. data/lib/badline/media/disk_set.rb +1 -1
  271. data/lib/badline/media/extensions.rb +33 -0
  272. data/lib/badline/media/program.rb +28 -0
  273. data/lib/badline/media/true_drive.rb +4 -3
  274. data/lib/badline/media/tune.rb +35 -0
  275. data/lib/badline/media/vic20_cartridge.rb +1 -7
  276. data/lib/badline/media/vic20_media.rb +38 -80
  277. data/lib/badline/media.rb +84 -81
  278. data/lib/badline/model.rb +1 -1
  279. data/lib/badline/options/event.rb +3 -1
  280. data/lib/badline/roms/README +6 -6
  281. data/lib/badline/sdl.rb +1 -0
  282. data/lib/badline/{storage/sid_file.rb → sid_tune/file.rb} +3 -3
  283. data/lib/badline/{storage → sid_tune}/hvsc.rb +7 -7
  284. data/lib/badline/{storage → sid_tune}/song_lengths.rb +2 -2
  285. data/lib/badline/{storage → sid_tune}/stil/credit.rb +1 -1
  286. data/lib/badline/{storage → sid_tune}/stil.rb +3 -3
  287. data/lib/badline/sid_tune.rb +6 -0
  288. data/lib/badline/snapshot/c128_setup.rb +43 -0
  289. data/lib/badline/snapshot/c64_setup.rb +79 -0
  290. data/lib/badline/snapshot/image.rb +5 -25
  291. data/lib/badline/snapshot/machine_state.rb +10 -2
  292. data/lib/badline/snapshot/setup.rb +22 -66
  293. data/lib/badline/snapshot/state.rb +8 -17
  294. data/lib/badline/snapshot/storage_setup.rb +68 -0
  295. data/lib/badline/snapshot/vic20_setup.rb +37 -0
  296. data/lib/badline/snapshot/vice/c64_mem.rb +1 -1
  297. data/lib/badline/snapshot/vice/restore.rb +1 -1
  298. data/lib/badline/snapshot/vice/reu1764.rb +1 -1
  299. data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
  300. data/lib/badline/snapshot/vice.rb +7 -5
  301. data/lib/badline/snapshot.rb +13 -12
  302. data/lib/badline/storage/d64_image.rb +15 -9
  303. data/lib/badline/storage/d71_image.rb +0 -2
  304. data/lib/badline/storage/d81_image.rb +0 -2
  305. data/lib/badline/storage/disk_image/writing.rb +2 -2
  306. data/lib/badline/storage/disk_image.rb +3 -6
  307. data/lib/badline/storage/g64_image.rb +2 -2
  308. data/lib/badline/storage/host_directory.rb +0 -5
  309. data/lib/badline/storage/t64.rb +2 -8
  310. data/lib/badline/storage/unavailable.rb +1 -1
  311. data/lib/badline/storage.rb +0 -37
  312. data/lib/badline/support/c128_checkpoint.rb +39 -0
  313. data/lib/badline/support/checkpoint.rb +108 -0
  314. data/lib/badline/support/vic20_checkpoint.rb +38 -0
  315. data/lib/badline/support.rb +5 -0
  316. data/lib/badline/version.rb +1 -1
  317. data/lib/badline/vic20/attachments.rb +11 -81
  318. data/lib/badline/vic20/bus/saved_state.rb +35 -0
  319. data/lib/badline/vic20/bus.rb +3 -25
  320. data/lib/badline/vic20/cpu.rb +1 -1
  321. data/lib/badline/vic20/port_wiring.rb +4 -4
  322. data/lib/badline/vic20/saved_state.rb +16 -60
  323. data/lib/badline/vic20/user_via_ports.rb +2 -2
  324. data/lib/badline/vic20.rb +20 -51
  325. metadata +250 -221
  326. data/lib/badline/address_bus/extra_sids.rb +0 -30
  327. data/lib/badline/address_bus/fittings.rb +0 -38
  328. data/lib/badline/address_bus/pla.rb +0 -147
  329. data/lib/badline/address_bus/roms.rb +0 -39
  330. data/lib/badline/address_bus/saved_state.rb +0 -72
  331. data/lib/badline/address_bus/sid_slots.rb +0 -42
  332. data/lib/badline/address_bus.rb +0 -235
  333. data/lib/badline/cartridge/action_replay.rb +0 -126
  334. data/lib/badline/cartridge/atomic_power.rb +0 -24
  335. data/lib/badline/cartridge/bank.rb +0 -81
  336. data/lib/badline/cartridge/comal80.rb +0 -50
  337. data/lib/badline/cartridge/dinamic.rb +0 -34
  338. data/lib/badline/cartridge/easy_flash.rb +0 -145
  339. data/lib/badline/cartridge/epyx_fastload.rb +0 -79
  340. data/lib/badline/cartridge/final_cartridge3.rb +0 -89
  341. data/lib/badline/cartridge/flash.rb +0 -306
  342. data/lib/badline/cartridge/freezer.rb +0 -33
  343. data/lib/badline/cartridge/fun_play.rb +0 -38
  344. data/lib/badline/cartridge/g_mod2.rb +0 -74
  345. data/lib/badline/cartridge/game_system.rb +0 -40
  346. data/lib/badline/cartridge/geo_ram.rb +0 -79
  347. data/lib/badline/cartridge/kcs_power.rb +0 -75
  348. data/lib/badline/cartridge/mach5.rb +0 -32
  349. data/lib/badline/cartridge/magic_desk.rb +0 -30
  350. data/lib/badline/cartridge/ocean.rb +0 -35
  351. data/lib/badline/cartridge/pagefox.rb +0 -68
  352. data/lib/badline/cartridge/retro_replay.rb +0 -320
  353. data/lib/badline/cartridge/rex_utility.rb +0 -29
  354. data/lib/badline/cartridge/rgcd.rb +0 -58
  355. data/lib/badline/cartridge/simons_basic.rb +0 -35
  356. data/lib/badline/cartridge/standard.rb +0 -15
  357. data/lib/badline/cartridge/super_games.rb +0 -48
  358. data/lib/badline/cartridge/westermann.rb +0 -30
  359. data/lib/badline/cartridge/zaxxon.rb +0 -66
  360. data/lib/badline/cartridge.rb +0 -303
  361. data/lib/badline/checkpoint.rb +0 -98
  362. data/lib/badline/cia/fast_forward.rb +0 -60
  363. data/lib/badline/cia/interrupt_register.rb +0 -143
  364. data/lib/badline/cia/serial.rb +0 -275
  365. data/lib/badline/cia/state.rb +0 -47
  366. data/lib/badline/cia/timer.rb +0 -206
  367. data/lib/badline/cia.rb +0 -279
  368. data/lib/badline/color_memory.rb +0 -25
  369. data/lib/badline/computer/kernal_traps.rb +0 -29
  370. data/lib/badline/control_ports.rb +0 -76
  371. data/lib/badline/cpu/addressing.rb +0 -131
  372. data/lib/badline/cpu/boundary.rb +0 -54
  373. data/lib/badline/cpu/core.rb +0 -165
  374. data/lib/badline/cpu/microcode.rb +0 -177
  375. data/lib/badline/cpu/operations.rb +0 -88
  376. data/lib/badline/cpu/saved_state.rb +0 -115
  377. data/lib/badline/cpu/stack_operations.rb +0 -82
  378. data/lib/badline/cpu.rb +0 -10
  379. data/lib/badline/cycleable.rb +0 -38
  380. data/lib/badline/datasette.rb +0 -161
  381. data/lib/badline/drive/core.rb +0 -147
  382. data/lib/badline/drive/fast_serial.rb +0 -73
  383. data/lib/badline/drive/idle.rb +0 -125
  384. data/lib/badline/drive/idle_cpu.rb +0 -28
  385. data/lib/badline/drive/orbit.rb +0 -79
  386. data/lib/badline/drive/serial_lines.rb +0 -73
  387. data/lib/badline/drive/sleep.rb +0 -112
  388. data/lib/badline/drive/vias.rb +0 -84
  389. data/lib/badline/drive/watch.rb +0 -150
  390. data/lib/badline/drive.rb +0 -11
  391. data/lib/badline/drive1541/bus.rb +0 -86
  392. data/lib/badline/drive1541/byte_ready.rb +0 -48
  393. data/lib/badline/drive1541/cpu.rb +0 -11
  394. data/lib/badline/drive1541/disk.rb +0 -318
  395. data/lib/badline/drive1541/disk_state.rb +0 -94
  396. data/lib/badline/drive1541/disk_via.rb +0 -36
  397. data/lib/badline/drive1541/gcr.rb +0 -57
  398. data/lib/badline/drive1541/mechanism.rb +0 -313
  399. data/lib/badline/drive1541/mechanism_state.rb +0 -68
  400. data/lib/badline/drive1541/rotation.rb +0 -121
  401. data/lib/badline/drive1541/sector_reader.rb +0 -76
  402. data/lib/badline/drive1541/serial_port.rb +0 -18
  403. data/lib/badline/drive1541/track.rb +0 -98
  404. data/lib/badline/drive1541.rb +0 -111
  405. data/lib/badline/drive1571/bus.rb +0 -111
  406. data/lib/badline/drive1571/cpu.rb +0 -11
  407. data/lib/badline/drive1571/serial_port.rb +0 -37
  408. data/lib/badline/drive1571/serial_via.rb +0 -25
  409. data/lib/badline/drive1571/wd1770.rb +0 -120
  410. data/lib/badline/drive1571.rb +0 -175
  411. data/lib/badline/drive1581/bus.rb +0 -137
  412. data/lib/badline/drive1581/cpu.rb +0 -11
  413. data/lib/badline/drive1581/disk.rb +0 -135
  414. data/lib/badline/drive1581/disk_state.rb +0 -87
  415. data/lib/badline/drive1581/mechanism.rb +0 -117
  416. data/lib/badline/drive1581/serial_port.rb +0 -52
  417. data/lib/badline/drive1581/slot.rb +0 -78
  418. data/lib/badline/drive1581/track.rb +0 -100
  419. data/lib/badline/drive1581/track_bytes.rb +0 -75
  420. data/lib/badline/drive1581/wd1772/registers.rb +0 -89
  421. data/lib/badline/drive1581/wd1772/sector_writes.rb +0 -73
  422. data/lib/badline/drive1581/wd1772/sectors.rb +0 -150
  423. data/lib/badline/drive1581/wd1772/state.rb +0 -66
  424. data/lib/badline/drive1581/wd1772/stepping.rb +0 -109
  425. data/lib/badline/drive1581/wd1772/tracks.rb +0 -125
  426. data/lib/badline/drive1581/wd1772/turn.rb +0 -73
  427. data/lib/badline/drive1581/wd1772.rb +0 -216
  428. data/lib/badline/drive1581.rb +0 -233
  429. data/lib/badline/iec_bus.rb +0 -159
  430. data/lib/badline/instruction.rb +0 -334
  431. data/lib/badline/instruction_set/arithmetic.rb +0 -114
  432. data/lib/badline/instruction_set/bitwise.rb +0 -126
  433. data/lib/badline/instruction_set/branch.rb +0 -79
  434. data/lib/badline/instruction_set/flag.rb +0 -63
  435. data/lib/badline/instruction_set/illegal.rb +0 -270
  436. data/lib/badline/instruction_set/inc_dec.rb +0 -69
  437. data/lib/badline/instruction_set/stack.rb +0 -52
  438. data/lib/badline/instruction_set/transfer.rb +0 -137
  439. data/lib/badline/instruction_set.rb +0 -55
  440. data/lib/badline/interrupts.rb +0 -104
  441. data/lib/badline/joystick.rb +0 -25
  442. data/lib/badline/kernal_trap/channel.rb +0 -181
  443. data/lib/badline/keyboard.rb +0 -112
  444. data/lib/badline/ram_expansion/banking.rb +0 -30
  445. data/lib/badline/ram_expansion/plus256k.rb +0 -54
  446. data/lib/badline/ram_expansion/plus60k.rb +0 -43
  447. data/lib/badline/ram_expansion/unexpanded.rb +0 -28
  448. data/lib/badline/ram_expansion.rb +0 -21
  449. data/lib/badline/reu/dma/saved_state.rb +0 -50
  450. data/lib/badline/reu/dma.rb +0 -273
  451. data/lib/badline/reu/ram.rb +0 -107
  452. data/lib/badline/reu/saved_state.rb +0 -80
  453. data/lib/badline/reu/trigger.rb +0 -32
  454. data/lib/badline/reu.rb +0 -289
  455. data/lib/badline/sid/catch_up.rb +0 -120
  456. data/lib/badline/sid/decimator.rb +0 -64
  457. data/lib/badline/sid/envelope/state.rb +0 -68
  458. data/lib/badline/sid/envelope.rb +0 -239
  459. data/lib/badline/sid/filter.rb +0 -263
  460. data/lib/badline/sid/voice.rb +0 -77
  461. data/lib/badline/sid/waveform/combined.rb +0 -126
  462. data/lib/badline/sid/waveform/fast_forward.rb +0 -105
  463. data/lib/badline/sid/waveform/noise_writeback.rb +0 -122
  464. data/lib/badline/sid/waveform/state.rb +0 -66
  465. data/lib/badline/sid/waveform.rb +0 -305
  466. data/lib/badline/sid.rb +0 -303
  467. data/lib/badline/time_of_day.rb +0 -228
  468. data/lib/badline/traps.rb +0 -19
  469. data/lib/badline/via/control_lines.rb +0 -122
  470. data/lib/badline/via/fast_forward.rb +0 -53
  471. data/lib/badline/via/interrupt_register.rb +0 -67
  472. data/lib/badline/via/shift_register.rb +0 -180
  473. data/lib/badline/via/state.rb +0 -42
  474. data/lib/badline/via/timer1.rb +0 -131
  475. data/lib/badline/via/timer2.rb +0 -133
  476. data/lib/badline/via.rb +0 -266
  477. data/lib/badline/vic/bank.rb +0 -133
  478. data/lib/badline/vic/border_mask.rb +0 -86
  479. data/lib/badline/vic/collisions.rb +0 -115
  480. data/lib/badline/vic/color_patches.rb +0 -47
  481. data/lib/badline/vic/display_state.rb +0 -185
  482. data/lib/badline/vic/graphics_mode.rb +0 -164
  483. data/lib/badline/vic/graphics_shifter.rb +0 -207
  484. data/lib/badline/vic/register_log.rb +0 -81
  485. data/lib/badline/vic/registers.rb +0 -195
  486. data/lib/badline/vic/sequencer.rb +0 -275
  487. data/lib/badline/vic/sequencer_output.rb +0 -116
  488. data/lib/badline/vic/sequencer_state.rb +0 -89
  489. data/lib/badline/vic/sprite/internal_bus.rb +0 -68
  490. data/lib/badline/vic/sprite/saved_state.rb +0 -64
  491. data/lib/badline/vic/sprite/shifter.rb +0 -146
  492. data/lib/badline/vic/sprite/timing.rb +0 -56
  493. data/lib/badline/vic/sprite.rb +0 -337
  494. data/lib/badline/vic/sprites.rb +0 -282
  495. data/lib/badline/vic/sprites_state.rb +0 -57
  496. data/lib/badline/vic.rb +0 -852
  497. data/lib/badline/vic20/sound/output.rb +0 -83
  498. data/lib/badline/vic20/sound.rb +0 -233
  499. data/lib/badline/z80/arithmetic.rb +0 -117
  500. data/lib/badline/z80/bit_page.rb +0 -55
  501. data/lib/badline/z80/block_io.rb +0 -58
  502. data/lib/badline/z80/block_transfers.rb +0 -59
  503. data/lib/badline/z80/bus_cycles.rb +0 -111
  504. data/lib/badline/z80/core.rb +0 -113
  505. data/lib/badline/z80/exchanges.rb +0 -50
  506. data/lib/badline/z80/extended_page.rb +0 -89
  507. data/lib/badline/z80/flags.rb +0 -37
  508. data/lib/badline/z80/interrupt_acceptance.rb +0 -46
  509. data/lib/badline/z80/jumps.rb +0 -82
  510. data/lib/badline/z80/loads.rb +0 -98
  511. data/lib/badline/z80/main_page.rb +0 -134
  512. data/lib/badline/z80/registers.rb +0 -120
  513. data/lib/badline/z80/saved_state.rb +0 -69
  514. data/lib/badline/z80/shifts.rb +0 -64
  515. data/lib/badline/z80.rb +0 -11
  516. /data/lib/badline/snapshot/{fields.rb → vice/fields.rb} +0 -0
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class VIC < Cycleable
5
- class Sprite
6
- # = InternalBus
7
- #
8
- # What a sprite's s-accesses read while its DMA is off. The first and
9
- # third fall in phi2, where the VIC's internal bus floats to $ff unless
10
- # the CPU reads or writes a VIC register in that cycle, and the middle
11
- # one is the idle fetch at $3fff (sbsprf24's readme).
12
- class InternalBus
13
- # The columns of a raster line, and where the region puts the
14
- # sprites in it.
15
- attr_reader :columns, :timing
16
-
17
- def initialize(bank, timing)
18
- @bank = bank
19
- @timing = timing
20
- @columns = timing.columns
21
- @sprite_cycle = timing.sprite_cycle
22
- @lines = 0
23
- @ghost = 0xff
24
- @value = Array.new(columns, 0xff)
25
- @line = Array.new(columns, -1)
26
- end
27
-
28
- def save_state(out)
29
- out.int(@lines).int(@ghost).ints(@value).ints(@line)
30
- end
31
-
32
- def load_state(input)
33
- @lines = input.int
34
- @ghost = input.int
35
- input.ints_into(@value)
36
- input.ints_into(@line)
37
- end
38
-
39
- # Sprites 3-7 fetch in Bauer cycles 1-10, so the idle byte is taken
40
- # as the line starts.
41
- def start_line(sprites_enabled)
42
- @lines += 1
43
- @ghost = @bank.peek(0x3fff) if sprites_enabled
44
- end
45
-
46
- # The VIC has advanced to `column`, so the access runs in Bauer cycle
47
- # `column + 1`, and column 0 is the first cycle of the line about to
48
- # start.
49
- def access(column, value)
50
- @value[column] = value
51
- @line[column] = column.zero? ? @lines + 1 : @lines
52
- end
53
-
54
- # The row sprite `index` (3-7) fetched this line, in the phi2 halves
55
- # of the two cycles from its p-access: Bauer cycles 2n-5 and 2n-4 on
56
- # the 6569.
57
- def row(index)
58
- column = (@sprite_cycle + (2 * index) - 1) % @columns
59
- (phi2(column) << 16) | (@ghost << 8) | phi2(column + 1)
60
- end
61
-
62
- private
63
-
64
- def phi2(column) = @line[column] == @lines ? @value[column] : 0xff
65
- end
66
- end
67
- end
68
- end
@@ -1,64 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class VIC < Cycleable
5
- class Sprite
6
- # The sprite's save_state and load_state.
7
- module SavedState
8
- # The shift register, MC, MCBASE, the expansion flip-flop and whether
9
- # the sprite shows, for a VICE snapshot.
10
- attr_reader :sr, :mc, :mcbase, :exp_ff, :display_on
11
-
12
- # Sets MC, MCBASE, the expansion flip-flop, whether the sprite's DMA
13
- # runs and whether it shows, as a VICE snapshot gives them.
14
- def restore_counters(counter, base, expanded, dma, shows)
15
- @mc = counter
16
- @mcbase = base
17
- @exp_ff = expanded
18
- @dma = dma
19
- @display_on = shows
20
- end
21
-
22
- def save_state(out)
23
- out.boolean(@dma).boolean(@display_on).int(@mcbase).int(@mc).boolean(@exp_ff).optional_int(@crunched_mc)
24
- out.int(@bits).boolean(@row_ready).optional_int(@prev_bits).boolean(@first_byte_lost).boolean(@blind)
25
- out.int(@show_from).optional_int(@stop_x)
26
- out.ints(@codes).int(@leftmost).int(@span).ints(@reload_codes).int(@reload_leftmost).int(@reload_span)
27
- out.int(@sr).int(@latch).boolean(@mc_flop).boolean(@xe_flop)
28
- end
29
-
30
- def load_state(input)
31
- load_counters(input)
32
- @show_from = input.int
33
- @stop_x = input.optional_int
34
- input.ints_into(@codes)
35
- @leftmost = input.int
36
- @span = input.int
37
- input.ints_into(@reload_codes)
38
- @reload_leftmost = input.int
39
- @reload_span = input.int
40
- @sr = input.int
41
- @latch = input.int
42
- @mc_flop = input.boolean?
43
- @xe_flop = input.boolean?
44
- end
45
-
46
- private
47
-
48
- def load_counters(input)
49
- @dma = input.boolean?
50
- @display_on = input.boolean?
51
- @mcbase = input.int
52
- @mc = input.int
53
- @exp_ff = input.boolean?
54
- @crunched_mc = input.optional_int
55
- @bits = input.int
56
- @row_ready = input.boolean?
57
- @prev_bits = input.optional_int
58
- @first_byte_lost = input.boolean?
59
- @blind = input.boolean?
60
- end
61
- end
62
- end
63
- end
64
- end
@@ -1,146 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class VIC < Cycleable
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 < Cycleable
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 < Cycleable
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