badline 0.12.1 → 0.14.0

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