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
data/lib/badline/vic.rb DELETED
@@ -1,853 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "badline/vic/bank"
4
- require "badline/vic/registers"
5
- require "badline/vic/display_state"
6
- require "badline/vic/sequencer"
7
- require "badline/vic/sprites"
8
-
9
- module Badline
10
- class VIC
11
- include Addressable
12
- include IntegerHelper
13
-
14
- # The 6569 of the breadbin C64, the HMOS 8565 of the C64C, and the
15
- # C128's VIC-IIe, the 8566 (PAL) and 8564 (NTSC). The VIC-IIe draws as
16
- # the 8565 and adds the $D02F and $D030 registers.
17
- MODELS = %i[mos6569 mos8565 mos8566 mos8564].freeze
18
-
19
- # The sixteen colours #display's palette indices stand for, as RGB.
20
- PALETTE = [
21
- 0x000000, 0xffffff, 0x924a40, 0x84c5cc,
22
- 0x9351b6, 0x72b14b, 0x483aaa, 0xd5df7c,
23
- 0x675200, 0xc33d00, 0xc18178, 0x606060,
24
- 0x8a8a8a, 0xb3ec91, 0x867ade, 0xb3b3b3
25
- ].freeze
26
-
27
- # The sixteen colours' luminances, out of 32, as Philip Timmermann
28
- # (Pepto) measured them on the 6569.
29
- LUMINANCES = [0, 32, 10, 20, 12, 16, 8, 24, 12, 8, 16, 10, 15, 24, 15, 20].freeze
30
-
31
- # The sixteen colours on a green monochrome monitor, which shows only
32
- # their luminance, as the PET 64's does.
33
- GREEN_PALETTE = LUMINANCES.map do |luminance|
34
- green = luminance * 255 / 32
35
- ((green / 4) << 16) | (green << 8) | (green / 4)
36
- end.freeze
37
-
38
- attr_reader :display, :width, :height, :vic_bank, :column,
39
- :rasterline, :dirty_lines, :model, :region
40
-
41
- # The RGB colours #display's palette indices stand for: PALETTE, or
42
- # GREEN_PALETTE on a monochrome monitor.
43
- attr_accessor :palette
44
-
45
- # The line of #display the beam draws, which is the raster line unless
46
- # the VIC-IIe's TEST bit has moved the raster counter on since the
47
- # last vertical sync (#test_step!).
48
- attr_reader :output_line
49
-
50
- # The parts a VICE snapshot reads and sets.
51
- attr_reader :registers, :display_state, :sequencer, :sprites, :character_buffer, :color_buffer,
52
- :fetch_d011
53
-
54
- # Returns the byte the CPU's halted read would see, for the c-accesses
55
- # that run before AEC. Without it they read colour RAM.
56
- attr_writer :open_bus
57
-
58
- LIGHTPEN_IRQ = 0x08 # $D019 latch bit
59
- COLOR_REGISTERS = 0x20..0x2e
60
-
61
- # What the 8565 shows on the pixel before a color register write takes
62
- # hold, where the 6569 shows the old color: the grey dot.
63
- GREY_DOT = 0x0f
64
-
65
- # A g-access reaches the pixel output this many columns after it runs.
66
- GRAPHICS_DELAY = 2
67
-
68
- # What a column's g-access passed to the sequencer.
69
- G_BLANK = 0
70
- G_IDLE = 1
71
- G_DISPLAY = 2
72
-
73
- # The idle g-access in the column a mid-row bad line opens display
74
- # state reads here on a 6569.
75
- DMA_DELAY_IDLE_ADDRESS = 0x38ff
76
-
77
- # The $d011 mode bits a g-access still sees for a cycle after they fall:
78
- # BMM always, and ECM too when the access it leaves read the character
79
- # ROM.
80
- FETCH_HOLD = 0x20
81
- FETCH_HOLD_ROM = 0x60
82
-
83
- # The hooks a column can carry, as bits: MCBASE, the left border
84
- # compare with the end of the sprite, the sprite DMA compare, the
85
- # expansion flip-flop, the sprite display compare, and the start of the
86
- # vertical border for the line after the last column.
87
- HOOK_MCBASE = 1
88
- HOOK_LEFT = 2
89
- HOOK_DMA = 4
90
- HOOK_EXPANSION = 8
91
- HOOK_DISPLAY = 16
92
- HOOK_LAST = 32
93
-
94
- # The vertical sync starts this many lines into the vertical blank,
95
- # and lasts VSYNC_LINES.
96
- VSYNC_DELAY = 3
97
- VSYNC_LINES = 3
98
-
99
- # On the 6569 the DMA compares fall in columns 53 and 54 and the
100
- # display compare in column 57. A region whose sprite fetches run later
101
- # moves them with the fetches (Region::Profile#sprite_cycle).
102
- DMA_COLUMN = 53
103
- EXPANSION_COLUMN = 54
104
-
105
- # BA falls three columns ahead of each sprite's pair of s-accesses, and
106
- # the five-column windows step two columns apart from sprite 0 at column
107
- # 54 on the 6569, a column later where the fetches are. From sprite 3 on
108
- # they reach past the end of the line, so each is split: the tail
109
- # columns fall on the line whose DMA compare started the fetch, the head
110
- # columns on the line after it.
111
- SPRITE_BA_FIRST = 54
112
- SPRITE_BA_LENGTH = 5
113
-
114
- def initialize(debug: false, model: :mos6569, region: Region::PAL)
115
- raise ArgumentError, "unknown VIC-II model #{model}" unless MODELS.include?(model)
116
-
117
- addressable_at(0xd000, length: 2**10)
118
- @model = model
119
- @iie = %i[mos8566 mos8564].include?(model)
120
- @core = model == :mos6569 ? :mos6569 : :mos8565
121
- @region = region
122
- @palette = PALETTE
123
- @lightpen_extra = @core == :mos8565 ? 1 : 2
124
- @grey_dots = @core == :mos8565
125
- @delayed_fetch = @core == :mos8565
126
- @dma_delay_idle = @core == :mos6569
127
- @bank_swaps = @core == :mos8565
128
- @vic_bank = VIC::Bank.new(self)
129
- @debug = debug
130
-
131
- @columns_per_line = region.cycles_per_line
132
- @sprite_cycle = region.sprite_cycle
133
- @sprite_shift = region.sprite_cycle - Region::PAL.sprite_cycle
134
- @width = @columns_per_line * 8
135
- @height = region.lines_per_frame
136
- @last_column = @columns_per_line - 1
137
- @last_line = @height - 1
138
- @vsync_line = region.vblank[0] + VSYNC_DELAY
139
- layout_columns
140
- @blank_columns = Array.new(@columns_per_line) { |column| Region.blanked?(column, region.hblank) }.freeze
141
- @blank_lines = Array.new(@height) { |line| Region.blanked?(line, region.vblank) }.freeze
142
- @display = Array.new(@width * @height, 0)
143
- @lines = Array.new(@height) { Array.new(@width, 0) }
144
- @dirty_lines = Array.new(@height, true)
145
- @render = true
146
-
147
- power_on!
148
- end
149
-
150
- # The VIC has no reset pin, so only a power cycle brings back the
151
- # registers, the raster position and the fetch and sprite state it
152
- # starts with. The display keeps its buffers, cleared to black.
153
- def power_on!
154
- @registers = VIC::Registers.new(iie: @iie)
155
- @register_bytes = @registers.bytes
156
- @display_state = VIC::DisplayState.new(@registers, @last_column)
157
- @sequencer = VIC::Sequencer.new(@width, @registers, @vic_bank, model: @core, region: @region)
158
- @sequencer.render = @render
159
- @sprites = VIC::Sprites.new(@registers, @vic_bank, @width, model: @core, region: @region)
160
- @display.fill(0)
161
- @lines.each { |line| line.fill(0) }
162
- @dirty_lines.fill(true)
163
-
164
- @column = 0
165
- @rasterline = 0
166
- @output_line = 0
167
-
168
- @character_buffer = Array.new(40, 0)
169
- @color_buffer = Array.new(40, 0)
170
- @sprite_ba = Array.new(@width / 8, false)
171
- @g_tick = 0
172
- @g_kind = Array.new(4, G_BLANK)
173
- @g_kept_char = 0
174
- @g_kept_color = 0
175
- @g_data = @sequencer.ring_data
176
- @g_char = @sequencer.ring_char
177
- @g_color = @sequencer.ring_color
178
- @g_display = false
179
- @fetch_d011 = @register_bytes[0x11]
180
- @lp_triggered = false
181
- @lp_low = false
182
- @raster_match = false
183
- @test_wrap = false
184
- end
185
-
186
- # Everything the VIC holds between cycles: the beam, the fetch and
187
- # g-access pipeline, the light pen and raster latches, the finished
188
- # lines, on the VIC-IIe the display line and the TEST bit's wrap, the
189
- # registers and the display, sequencer and sprite logic.
190
- # Whether it renders is the host's, and every line comes back dirty so
191
- # a front end repaints.
192
- def save_state(out)
193
- out.marker("VIC")
194
- out.int(@column).int(@rasterline)
195
- out.int(@g_tick).ints(@g_kind).int(@g_kept_char).int(@g_kept_color).boolean(@g_display)
196
- out.int(@fetch_d011).boolean(@lp_triggered).boolean(@lp_low).boolean(@raster_match)
197
- out.int(@vic_bank.lines)
198
- out.blob(@character_buffer).blob(@color_buffer).booleans(@sprite_ba)
199
- @lines.each { |line| out.blob(line) }
200
- out.int(@output_line).boolean(@test_wrap) if @iie
201
- @registers.save_state(out)
202
- @display_state.save_state(out)
203
- @sequencer.save_state(out)
204
- @sprites.save_state(out)
205
- end
206
-
207
- def load_state(input)
208
- input.marker("VIC")
209
- load_beam(input)
210
- load_buffers(input)
211
- load_lines(input)
212
- load_test_state(input) if @iie
213
- @registers.load_state(input)
214
- @display_state.load_state(input)
215
- @sequencer.load_state(input)
216
- @sprites.load_state(input)
217
- end
218
-
219
- def cycle!
220
- start_line! if @column.zero?
221
-
222
- # The g-access runs in the first half of the cycle, ahead of the bad
223
- # line compare, and the c-access in the second half, after it.
224
- draw!
225
- dma_delay_idle_access if @display_state.cycle(@rasterline, @column)
226
-
227
- fetch_character_data! if dma_active?
228
-
229
- hooks = @hook_columns[@column]
230
- column_hooks(hooks) if hooks
231
-
232
- @column += 1
233
- if @column == @columns_per_line
234
- finish_line!
235
- @column = 0
236
- step_output_line
237
- @rasterline = @rasterline == @last_line ? 0 : @rasterline + 1
238
- check_raster_irq!(@rasterline.zero? ? @last_line : @rasterline)
239
- end
240
- watch_collisions
241
- nil
242
- end
243
-
244
- # The sprite and border hooks that fall on named cycles, one column
245
- # ahead of Bauer's numbering — two for MCBASE, the DMA compares and the
246
- # expansion flip-flop, which the `spriteenable` and `spritecrunch`
247
- # references place a column earlier still. Guarded in
248
- # #cycle! so an ordinary column pays an array read rather than the
249
- # dispatch.
250
- def column_hooks(hooks)
251
- @sprites.advance_mcbase if hooks.anybits?(HOOK_MCBASE)
252
- if hooks.anybits?(HOOK_LEFT)
253
- @sequencer.left_compare_vertical_border
254
- finish_sprite_mcbase
255
- end
256
- check_sprite_dma if hooks.anybits?(HOOK_DMA)
257
- @sprites.toggle_expansion if hooks.anybits?(HOOK_EXPANSION)
258
- @sprites.check_display(@rasterline) if hooks.anybits?(HOOK_DISPLAY)
259
- @sequencer.start_vertical_border(@rasterline == @last_line ? 0 : @rasterline + 1) if hooks.anybits?(HOOK_LAST)
260
- end
261
-
262
- # The IRQ line is held asserted while any enabled latch bit is set in
263
- # $D019/$D01A, until the program acknowledges it by writing to $D019.
264
- def interrupted?
265
- @registers.irq_line?
266
- end
267
-
268
- # The VIC-IIe's $D02F lines K0-K2 and $D030 bits, for the machine to
269
- # read. The 6569 and 8565 give 7, false and false.
270
- def extra_keyboard_lines = @registers.extra_keyboard_lines
271
- def fast? = @registers.fast?
272
- def test? = @registers.test?
273
-
274
- # $D030's FAST and TEST bits as bits 0 and 1, which the C128 reads once
275
- # a cycle.
276
- def clock_bits = @registers.clock_bits
277
-
278
- # Whether the cycle just run was one of the five refresh cycles, Bauer's
279
- # 11-15, whose phi1 half the VIC keeps in the VIC-IIe's FAST mode.
280
- # @column has already advanced, so it is the Bauer cycle less one.
281
- def refresh_cycle? = @column.between?(10, 14)
282
-
283
- # In the VIC-IIe's FAST mode the 8502 drives the bus in both halves of
284
- # the cycle, and the VIC's accesses in the cycle just run latched what
285
- # it put there. The g-access, or the idle access, took the byte of
286
- # phi1. A c-access took the byte of phi2 as one made before AEC does
287
- # (#fetch_character_data!): $ff for the video matrix, unless the CPU
288
- # was reading or writing the VIC's own registers, and the byte's low
289
- # nibble for colour. AEC can't follow BA down while the CPU runs at
290
- # 2 MHz, so on a bad line it falls three cycles after FAST mode ends.
291
- def take_cpu_bus(phi1, phi2, register_access)
292
- slot = @g_tick
293
- @g_data[slot] = phi1 unless @g_kind[slot] == G_BLANK
294
- display_state = @display_state
295
- display_state.keep_bus(@column)
296
- return unless display_state.fetching?(@column.zero? ? @last_column : @column - 1)
297
-
298
- vmli = display_state.vmli
299
- @character_buffer[vmli] = register_access ? phi2 : 0xff
300
- @color_buffer[vmli] = phi2 & 0x0f
301
- end
302
-
303
- # The VIC-IIe's TEST bit clocks the raster counter in every cycle, and
304
- # the C128 calls this ahead of each cycle the bit is set in. The line's
305
- # last cycle, whose own step it falls in with, adds nothing more. The
306
- # counter takes two steps from the frame's last line to line 0, as line
307
- # 0 reads the last line for its first cycle.
308
- def test_step!
309
- return if @column == @last_column
310
-
311
- if @rasterline == @last_line
312
- @test_wrap = !@test_wrap
313
- return if @test_wrap
314
-
315
- @rasterline = 0
316
- @display_state.new_frame
317
- else
318
- @test_wrap = false
319
- @rasterline += 1
320
- end
321
- @display_state.raster_step(@rasterline)
322
- check_raster_irq!
323
- end
324
-
325
- def peek(addr)
326
- i = offset_of(addr) % (2**6)
327
- case i
328
- when 0x11 then (@registers[0x11] & 0x7f) | ((raster_counter & 0x100) >> 1)
329
- when 0x12 then raster_counter & 0xff
330
- when 0x19 then irq_status # Latch + master IRQ bit, unused bits read 1
331
- when 0x1e, 0x1f then read_collision(i)
332
- else @registers.read(i)
333
- end.tap { |value| @sprites.bus_data(@column, value) }
334
- end
335
-
336
- # The register file as stored, read without a bus access's side effects.
337
- def register_file = Array.new(0x40) { |reg| @registers[reg] }
338
-
339
- def poke(addr, value)
340
- reg = offset_of(addr) % (2**6)
341
- @sprites.bus_data(@column, value)
342
- log_register_change(reg, value)
343
- @registers.write(reg, value)
344
- compare_raster_writes(reg)
345
- end
346
-
347
- def position
348
- (@rasterline * @width) + (@column * 8)
349
- end
350
-
351
- def dma_active?
352
- @display_state.fetching?(@column)
353
- end
354
-
355
- # Asked once the VIC has advanced, so @column is one ahead of the cycle
356
- # the CPU is about to run. A bad line holds BA on the condition as it
357
- # stands rather than the latched match.
358
- def ba_low?
359
- return true if @sprite_ba[@column]
360
-
361
- @display_state.bad_line_condition? &&
362
- @column > DisplayState::DMA_FIRST && @column <= DisplayState::DMA_LAST + 1
363
- end
364
-
365
- # Whether this is the first cycle of sprite 0's BA window on the line
366
- # whose raster matches its Y, where the sprite's DMA starts. An REU
367
- # that moved a byte on the cycle before doesn't see BA fall here. Pinned by
368
- # REU/bonzai/spritetiming.
369
- def reu_ba_late?
370
- @column == SPRITE_BA_FIRST + @sprite_shift && sprite_zero_starting?
371
- end
372
-
373
- # Whether BA passes straight from a bad line's window to sprite 0's on
374
- # this cycle, the first of sprite 0's. An REU sees the bad line's DMA
375
- # end here. Pinned by REU/reutiming2/e4-m2 and e6-m2.
376
- def reu_ba_handed_on?
377
- @column == DisplayState::DMA_LAST + 2 && @sprite_ba[@column] && @display_state.bad_line_condition?
378
- end
379
-
380
- # Light pen input level (CIA1 PB4). A falling edge triggers the latch.
381
- def lightpen_level(high)
382
- @lp_low = !high
383
- trigger_lightpen if @lp_low
384
- end
385
-
386
- # The first trigger per frame latches the beam position into LPX/LPY and
387
- # raises the LP IRQ. The latch happens one cycle after the edge, with
388
- # the model's extra half-pixels, two on the 6569 and one on the 8565; a
389
- # trigger on the last line is consumed without latching unless it lands
390
- # on the line's first cycle.
391
- def trigger_lightpen
392
- return if @lp_triggered
393
-
394
- @lp_triggered = true
395
- column = @column + 1
396
- line = @rasterline
397
- if column == @columns_per_line
398
- column = 0
399
- line = line == @last_line ? 0 : line + 1
400
- end
401
- return if line == @last_line && column.positive?
402
-
403
- vic_x = Sprite::Timing.xpos(column * 8, @width, @region.x_hold)
404
- latch_lightpen((vic_x >> 1) + @lightpen_extra, line)
405
- end
406
-
407
- # The byte the VIC fetched in the phi1 half of the cycle the CPU is
408
- # running, worked out from the VIC's state. The CPU cycle after column
409
- # c is Bauer cycle c + 2, and each Bauer cycle has a fixed access (VICE
410
- # `cycle_phi1_fetch`).
411
- def phi1_data
412
- vic_bank.peek(phi1_address)
413
- end
414
-
415
- def hblank? = @blank_columns[@column]
416
- def vblank? = @blank_lines[@rasterline]
417
- def blanking? = @blank_lines[@rasterline] || @blank_columns[@column]
418
-
419
- def render? = @render
420
-
421
- # Whether finished lines are painted into #display. A headless run that
422
- # only reads the machine's state can turn it off: the sprite
423
- # collisions, lightpen and every register still behave the same, but
424
- # #display keeps the last lines painted. Turned back on, it is whole
425
- # again from the start of the next frame.
426
- def render=(on)
427
- @render = on
428
- @sequencer.render = on
429
- end
430
-
431
- # Puts the beam at the start of `line`.
432
- def restore_line(line)
433
- @rasterline = @output_line = line
434
- @column = 0
435
- end
436
-
437
- # The latches a VICE snapshot holds: the raster match, the light pen's
438
- # line held low and its trigger, as bits 0, 1 and 2.
439
- def latch_bits = (@raster_match ? 1 : 0) | (@lp_low ? 2 : 0) | (@lp_triggered ? 4 : 0)
440
-
441
- # Sets the latches from latch_bits, and the $D011 the next g-access
442
- # holds.
443
- def restore_latches(bits, fetch_d011)
444
- @raster_match = bits.anybits?(1)
445
- @lp_low = bits.anybits?(2)
446
- @lp_triggered = bits.anybits?(4)
447
- @fetch_d011 = fetch_d011
448
- end
449
-
450
- # Marks the columns BA is low for the sprites whose DMA runs.
451
- def rebuild_sprite_ba
452
- @sprite_ba.fill(false)
453
- 8.times do |n|
454
- next unless @sprites[n].displaying?
455
-
456
- @sprite_ba_tail[n].each { |c| @sprite_ba[c] = true }
457
- @sprite_ba_head[n].each { |c| @sprite_ba[c] = true }
458
- end
459
- end
460
-
461
- # Reset the dirty flags once the frontend has consumed them.
462
- def clear_dirty_lines!
463
- @dirty_lines.fill(false)
464
- end
465
-
466
- private
467
-
468
- def load_beam(input)
469
- @column = input.int
470
- @rasterline = @output_line = input.int
471
- if input.schema < 9
472
- input.int
473
- input.boolean?
474
- end
475
- @g_tick = input.int
476
- input.ints_into(@g_kind)
477
- @g_kept_char = input.int
478
- @g_kept_color = input.int
479
- @g_display = input.boolean?
480
- @fetch_d011 = input.int
481
- @lp_triggered = input.boolean?
482
- @lp_low = input.boolean?
483
- @raster_match = input.boolean?
484
- @vic_bank.lines = input.int
485
- end
486
-
487
- def load_buffers(input)
488
- input.blob_into(@character_buffer)
489
- input.blob_into(@color_buffer)
490
- input.booleans_into(@sprite_ba)
491
- end
492
-
493
- # The VIC-IIe's display line and TEST wrap, which only its TEST bit
494
- # moves off the raster line.
495
- def load_test_state(input)
496
- @output_line = input.int
497
- @test_wrap = input.boolean?
498
- end
499
-
500
- # The display is the finished lines one after another.
501
- def load_lines(input)
502
- @lines.each_with_index do |line, number|
503
- input.blob_into(line)
504
- @display[number * @width, @width] = line
505
- end
506
- @dirty_lines.fill(true)
507
- end
508
-
509
- # The raster counter as $D011/$D012 read it. Every line advances on the
510
- # CPU cycle paired with column 62 except line 0, which the counter
511
- # reaches a cycle later, together with the line 0 raster compare.
512
- def raster_counter
513
- @column.zero? && @rasterline.zero? ? @last_line : @rasterline
514
- end
515
-
516
- # Mid-line writes to the color and sprite registers are logged against
517
- # the cycle after the write (the CPU runs after the VIC within a machine
518
- # cycle, so @column already points there); each register adds its own
519
- # pixel delay on top. On the 8565 a color register write that leaves
520
- # the value as it was still shows its grey dot.
521
- def log_register_change(reg, value)
522
- old = @registers[reg]
523
- return if old == value && !grey_dot?(reg)
524
-
525
- if (0x20..0x24).cover?(reg)
526
- @sequencer.colors_changed! unless reg == 0x20
527
- @sequencer.color_patches.log(reg, old, value, @column * 8) if @render && !blanking?
528
- else
529
- log_sprite_change(reg, old, value)
530
- end
531
- end
532
-
533
- def grey_dot?(reg) = @grey_dots && COLOR_REGISTERS.cover?(reg)
534
-
535
- # A sprite color shows its grey dot as a write of light grey on the
536
- # pixel before the new color.
537
- def log_sprite_change(reg, old, value)
538
- beam_x = @column * 8
539
- @sprites.log_change(reg, old, GREY_DOT, beam_x - 1) if grey_dot?(reg)
540
- @sprites.log_change(reg, old, value, beam_x)
541
- end
542
-
543
- # On the 6569 Bauer cycles 1-10 and 58-63 are sprite p- and s-accesses,
544
- # 11-15 refresh, 16-55 g-accesses and 56-57 idle. Where the sprite
545
- # fetches start later, the idle cycles before them grow, and on the
546
- # 6567R8 cycle 10 idles too. @column has already advanced, so it is the
547
- # Bauer cycle less one.
548
- def phi1_address
549
- cycle = @column + 1
550
- slot = (cycle - @sprite_cycle) % @columns_per_line
551
- if slot < 16
552
- sprite_phi1_address(slot)
553
- elsif cycle.between?(11, 15)
554
- 0x3f00 | ((0xff - (5 * @rasterline) - (cycle - 11)) & 0xff)
555
- elsif cycle.between?(16, 55)
556
- graphics_phi1_address
557
- else
558
- 0x3fff
559
- end
560
- end
561
-
562
- # Each sprite takes two cycles from sprite 0's, the p-access and then
563
- # the middle s-access.
564
- def sprite_phi1_address(slot)
565
- n = slot >> 1
566
- return @registers.screen_base + 0x3f8 + n if slot.even?
567
-
568
- @sprites[n].phi1_address || 0x3fff
569
- end
570
-
571
- # The g-access of the column just run. In display state it used the
572
- # VC and VMLI it then stepped past.
573
- def graphics_phi1_address
574
- return @registers.ecm.nonzero? ? 0x39ff : 0x3fff unless @g_display
575
-
576
- graphics_address(@registers[0x11], @display_state.vmli - 1, (@display_state.vc - 1) & 0x3ff)
577
- end
578
-
579
- # A $d011/$d012 write is compared in the next column. A write in the
580
- # line's second last column is left to its last, which compares the
581
- # next line.
582
- def compare_raster_writes(reg)
583
- return unless (0x11..0x12).cover?(reg)
584
- return if @column == @last_column
585
-
586
- check_raster_irq!
587
- @sequencer.compare_vertical_border(@rasterline) if reg == 0x11
588
- end
589
-
590
- def check_sprite_dma
591
- rebuild_sprite_ba if @sprites.check_dma(@rasterline, @column)
592
- end
593
-
594
- # A sprite whose DMA ends here fetches nothing at the end of this line,
595
- # so its BA tail goes too.
596
- def finish_sprite_mcbase
597
- @sprites.finish_mcbase
598
- rebuild_sprite_ba if @sprites.stopped_dma?
599
- end
600
-
601
- # The trigger re-arms at the start of each frame; if the pen line is
602
- # still low, the latch retriggers immediately with a fixed LPX of $d1.
603
- def start_lightpen_frame
604
- @lp_triggered = false
605
- return unless @lp_low
606
-
607
- @lp_triggered = true
608
- latch_lightpen(0xd1, 0)
609
- end
610
-
611
- def latch_lightpen(lpx, line)
612
- @registers.write(0x13, lpx & 0xff)
613
- @registers.write(0x14, line & 0xff)
614
- @registers.latch_irq!(LIGHTPEN_IRQ)
615
- end
616
-
617
- def sprite_zero_starting?
618
- @registers[0x15].anybits?(0x01) && @registers[0x01] == (@rasterline & 0xff)
619
- end
620
-
621
- # Splits the sprite BA windows at the end of the line and marks the hook
622
- # columns, for a line of the region's length: 14, 15, 53, 54 and 57, and
623
- # the line's last column, which starts the vertical border for the line
624
- # after it. The marks let an ordinary column cost one array read instead
625
- # of the dispatch.
626
- def layout_columns
627
- last = @last_column
628
- windows = Array.new(8) do |n|
629
- first = SPRITE_BA_FIRST + @sprite_shift + (2 * n)
630
- first...(first + SPRITE_BA_LENGTH)
631
- end
632
- @sprite_ba_tail = windows.map { |w| w.select { |c| c <= last } }.freeze
633
- @sprite_ba_head = windows.map { |w| w.filter_map { |c| c - last - 1 if c > last } }.freeze
634
- @hook_columns = layout_hooks.map { |hooks| hooks unless hooks.zero? }.freeze
635
- end
636
-
637
- def layout_hooks
638
- hooks = Array.new(@columns_per_line, 0)
639
- hooks[14] |= HOOK_MCBASE
640
- hooks[15] |= HOOK_LEFT
641
- hooks[DMA_COLUMN + @sprite_shift] |= HOOK_DMA
642
- hooks[DMA_COLUMN + @sprite_shift + 1] |= HOOK_DMA
643
- hooks[EXPANSION_COLUMN] |= HOOK_EXPANSION
644
- hooks[@region.sprite_display_cycle - 1] |= HOOK_DISPLAY
645
- hooks[@last_column] |= HOOK_LAST
646
- hooks
647
- end
648
-
649
- # Runs this column's g-access and draws the one from GRAPHICS_DELAY
650
- # columns earlier. The access reads its byte now, through the mode,
651
- # $d018 and bank of this cycle. A column with no g-access, or one made
652
- # while the vertical border flip-flop is set, latches nothing: it passes
653
- # on zero data with the screen byte and colour the last g-access
654
- # latched, which an idle g-access clears.
655
- def draw!
656
- @vic_bank.sample_lines if @bank_swaps
657
- slot = @g_tick = (@g_tick + 1) & 3
658
- display_state = @display_state
659
- access = display_state.graphics_column?(@column) && !@sequencer.vertical_closed?
660
- if access
661
- latch_graphics(slot, display_state)
662
- else
663
- @g_kind[slot] = G_BLANK
664
- @g_data[slot] = 0
665
- @g_char[slot] = @g_kept_char
666
- @g_color[slot] = @g_kept_color
667
- end
668
- @g_display = display_state.display?
669
- display_state.graphics_access(@column) if @g_display
670
- emit_graphics((slot - GRAPHICS_DELAY) & 3, @column - 16) unless blanking?
671
- @sequencer.latch_xscroll(@register_bytes[0x16] & 0b111) if access
672
- @fetch_d011 = @register_bytes[0x11]
673
- end
674
-
675
- def latch_graphics(slot, display_state)
676
- unless display_state.display?
677
- @g_kind[slot] = G_IDLE
678
- @g_data[slot] = vic_bank.peek(@registers.ecm.zero? ? 0x3fff : 0x39ff)
679
- @g_char[slot] = @g_color[slot] = @g_kept_char = @g_kept_color = 0
680
- return
681
- end
682
-
683
- vmli = display_state.vmli
684
- @g_kind[slot] = G_DISPLAY
685
- @g_data[slot] = fetch_graphics(vmli, display_state.vc)
686
- @g_char[slot] = @g_kept_char = @character_buffer[vmli] || 0
687
- @g_color[slot] = @g_kept_color = @color_buffer[vmli] || 1
688
- end
689
-
690
- # On the 6569 a bad line that opens display state mid-row (DMA delay)
691
- # moves the idle g-access of the column that triggers it from $3fff (or
692
- # $39ff) to DMA_DELAY_IDLE_ADDRESS, unless YSCROLL is 0 (vsp-tester,
693
- # colorfetchbug/main).
694
- def dma_delay_idle_access
695
- slot = @g_tick
696
- return unless @dma_delay_idle && @g_kind[slot] == G_IDLE
697
- return if @registers.yscroll.zero?
698
-
699
- @g_data[slot] = vic_bank.peek(DMA_DELAY_IDLE_ADDRESS)
700
- end
701
-
702
- # The 6569's g-access sees a mode bit that falls a cycle late: it
703
- # addresses with $d011 as this column has it, OR-ed with the held bits
704
- # the column before had. When BMM changes and the access moves from RAM
705
- # onto the character ROM, the low address byte still comes from the old
706
- # mode. The 8565's addresses with $d011 as the column before had it
707
- # (VICE x64sc `vicii_fetch_graphics`).
708
- def fetch_graphics(vmli, counter)
709
- d011 = @register_bytes[0x11]
710
- last = @fetch_d011
711
- return vic_bank.peek(graphics_address(d011, vmli, counter)) if d011 == last
712
- return vic_bank.peek(graphics_address(last, vmli, counter)) if @delayed_fetch
713
-
714
- from = graphics_address(last, vmli, counter)
715
- from_rom = vic_bank.character_rom?(from)
716
- address = graphics_address(d011 | (last & (from_rom ? FETCH_HOLD_ROM : FETCH_HOLD)), vmli, counter)
717
- if (d011 ^ last).anybits?(0x20) && !from_rom
718
- to = graphics_address(d011, vmli, counter)
719
- address = (from & 0xff) | (to & 0x3f00) if vic_bank.character_rom?(to)
720
- end
721
- vic_bank.peek(address)
722
- end
723
-
724
- def graphics_address(d011, vmli, counter)
725
- rc = @display_state.rc
726
- case d011 & 0x60
727
- when 0x00 then @registers.char_base | ((@character_buffer[vmli] || 0) << 3) | rc
728
- when 0x20 then @registers.bitmap_base | (counter << 3) | rc
729
- when 0x40 then (@registers.char_base | ((@character_buffer[vmli] || 0) << 3) | rc) & 0x39ff
730
- else (@registers.bitmap_base | (counter << 3) | rc) & 0x39ff
731
- end
732
- end
733
-
734
- def emit_graphics(slot, col)
735
- @sequencer.emit(slot, col, @g_kind[slot] == G_DISPLAY)
736
- end
737
-
738
- # Fold the rest of the line's sprite collisions in — they latch whether
739
- # or not there is a line to draw — then composite the active sprites
740
- # over the finished background and copy the line into the frame display.
741
- def finish_line!
742
- return finish_blank_line if vblank? || !@render
743
-
744
- composite = @sprites.active?
745
- @sequencer.apply_color_patches
746
- @sequencer.snapshot_line if composite
747
- @sprites.finish_line(composite ? @sequencer.colors : nil, @sequencer.fg)
748
- @sequencer.apply_border if composite
749
-
750
- colors = @sequencer.colors
751
- output_line = @output_line
752
- line = @lines[output_line]
753
- return if line == colors
754
-
755
- line[0, @width] = colors
756
- @display[output_line * @width, @width] = colors
757
- @dirty_lines[output_line] = true
758
- end
759
-
760
- # A blanked line paints nothing, and is never shown unless the TEST
761
- # bit has moved the beam off the raster line, where it shows black.
762
- def finish_blank_line
763
- @sprites.finish_line(nil, @sequencer.fg)
764
- return if @output_line == @rasterline || !@render
765
-
766
- line = @output_line
767
- @lines[line].fill(0)
768
- @display.fill(0, line * @width, @width)
769
- @dirty_lines[line] = true
770
- end
771
-
772
- # The display line the beam draws next follows the one before it, and
773
- # a line that ends in the vertical sync puts it back on the raster
774
- # line. Only the VIC-IIe's TEST bit moves the raster counter on between
775
- # the two, so the lines it skips shift the picture up until the next
776
- # sync.
777
- def step_output_line
778
- @output_line = if @rasterline.between?(@vsync_line, @vsync_line + VSYNC_LINES - 1)
779
- @rasterline + 1
780
- else
781
- @output_line == @last_line ? 0 : @output_line + 1
782
- end
783
- end
784
-
785
- def video_matrix(index)
786
- vic_bank.peek_phi2(@registers.screen_base + index)
787
- end
788
-
789
- def start_line!
790
- if @rasterline.zero?
791
- @display_state.new_frame
792
- start_lightpen_frame
793
- # The line 0 raster compare happens one cycle later than on all
794
- # other lines (Bauer 3.12).
795
- check_raster_irq!
796
- end
797
- @sequencer.new_line(@rasterline)
798
- @sprites.start_line
799
- rebuild_sprite_ba
800
- @display_state.new_line(@rasterline)
801
- end
802
-
803
- # The raster compare latches the flag only as the line and the target
804
- # come to match, so a target moved along with the raster line holds the
805
- # match without latching again (VICE x64sc). It runs at each line step
806
- # and after each $d011/$d012 write. The line asserts via #interrupted?
807
- # when the mask bit in $D01A is set.
808
- def check_raster_irq!(line = @rasterline)
809
- match = line == @registers.raster_target
810
- @registers.latch_raster_irq! if match && !@raster_match
811
- @raster_match = match
812
- end
813
-
814
- # A collision register carries the pixels drawn up to the cycle before
815
- # the read — the VIC runs ahead of the CPU within a machine cycle, so
816
- # the column the read lands on has not latched yet — and the reset the
817
- # read asserts outlives it, swallowing the pixels drawn under it.
818
- def read_collision(reg)
819
- beam_x = @column * 8
820
- @sprites.collide_upto(beam_x, @sequencer.fg)
821
- @registers.read(reg).tap { @sprites.clear_collision(reg, beam_x) }
822
- end
823
-
824
- # A collision raises its $D019 bit as the beam crosses the pixel rather
825
- # than when the line is folded at its end, so while an enabled
826
- # collision IRQ is still unlatched the fold keeps up with the beam.
827
- def watch_collisions
828
- return if (@registers[0x1a] & ~@registers[0x19]).nobits?(0x06)
829
-
830
- @sprites.collide_upto(@column * 8, @sequencer.fg)
831
- end
832
-
833
- def irq_status
834
- @sprites.collide_upto(@column * 8, @sequencer.fg)
835
- (@registers[0x19] & 0x0f) | 0x70 | (interrupted? ? 0x80 : 0)
836
- end
837
-
838
- # A c-access that falls between BA and AEC reads a bus the CPU still
839
- # drives: the video matrix byte comes back as $ff, and the colour
840
- # nibble is the low nibble of the byte at the halted CPU's PC.
841
- def fetch_character_data!
842
- vmli = @display_state.vmli
843
- vc = @display_state.vc
844
- if @display_state.bus_taken?(@column)
845
- @character_buffer[vmli] = video_matrix(vc)
846
- @color_buffer[vmli] = vic_bank.peek_color(vc)
847
- else
848
- @character_buffer[vmli] = 0xff
849
- @color_buffer[vmli] = @open_bus ? @open_bus.call & 0x0f : vic_bank.peek_color(vc)
850
- end
851
- end
852
- end
853
- end