badline 0.12.0 → 0.13.0

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