badline 0.12.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (565) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -1
  3. data/CLAUDE.md +86 -38
  4. data/CONTRIBUTING.md +4 -3
  5. data/README.md +9 -6
  6. data/doc/library.md +9 -9
  7. data/doc/media.md +2 -1
  8. data/doc/pinned-behaviour.md +134 -105
  9. data/doc/snapshot-format.md +1047 -0
  10. data/doc/snapshots.md +73 -43
  11. data/lib/badline/audio/bare_player.rb +53 -20
  12. data/lib/badline/audio/cli.rb +6 -6
  13. data/lib/badline/audio/jukebox.rb +2 -2
  14. data/lib/badline/audio/machine_player.rb +16 -10
  15. data/lib/badline/{media → audio}/queue.rb +1 -1
  16. data/lib/badline/audio/queued_tune.rb +6 -6
  17. data/lib/badline/audio/renderer.rb +33 -22
  18. data/lib/badline/audio/stereo.rb +1 -1
  19. data/lib/badline/c128/banks.rb +6 -3
  20. data/lib/badline/c128/bus/keyed_state.rb +45 -0
  21. data/lib/badline/c128/bus.rb +35 -20
  22. data/lib/badline/c128/color_lines.rb +2 -2
  23. data/lib/badline/c128/cpu.rb +1 -1
  24. data/lib/badline/c128/drives.rb +14 -34
  25. data/lib/badline/c128/fast_serial.rb +5 -5
  26. data/lib/badline/c128/keyed_modules.rb +117 -0
  27. data/lib/badline/c128/keyed_state.rb +91 -0
  28. data/lib/badline/c128/keys.rb +9 -0
  29. data/lib/badline/c128/mmu.rb +9 -8
  30. data/lib/badline/c128/mmu_pages.rb +21 -1
  31. data/lib/badline/c128/modes.rb +21 -11
  32. data/lib/badline/c128/z80.rb +2 -2
  33. data/lib/badline/c128/z80_turns.rb +1 -1
  34. data/lib/badline/c128.rb +21 -16
  35. data/lib/badline/c64/attachments.rb +42 -0
  36. data/lib/badline/c64/banked_ram/banking.rb +32 -0
  37. data/lib/badline/c64/banked_ram/plus256k.rb +64 -0
  38. data/lib/badline/c64/banked_ram/plus60k.rb +47 -0
  39. data/lib/badline/c64/banked_ram/unexpanded.rb +30 -0
  40. data/lib/badline/c64/banked_ram.rb +23 -0
  41. data/lib/badline/c64/bus/debug_register.rb +32 -0
  42. data/lib/badline/c64/bus/extra_sids.rb +32 -0
  43. data/lib/badline/c64/bus/fittings.rb +40 -0
  44. data/lib/badline/c64/bus/keyed_state.rb +41 -0
  45. data/lib/badline/c64/bus/pla.rb +149 -0
  46. data/lib/badline/c64/bus/roms.rb +41 -0
  47. data/lib/badline/c64/bus/sid_slots.rb +44 -0
  48. data/lib/badline/c64/bus.rb +219 -0
  49. data/lib/badline/c64/cartridge/action_replay.rb +115 -0
  50. data/lib/badline/c64/cartridge/atomic_power.rb +26 -0
  51. data/lib/badline/c64/cartridge/bank.rb +83 -0
  52. data/lib/badline/c64/cartridge/comal80.rb +52 -0
  53. data/lib/badline/c64/cartridge/dinamic.rb +36 -0
  54. data/lib/badline/c64/cartridge/easy_flash.rb +132 -0
  55. data/lib/badline/c64/cartridge/epyx_fastload.rb +73 -0
  56. data/lib/badline/c64/cartridge/final_cartridge3.rb +79 -0
  57. data/lib/badline/c64/cartridge/flash.rb +279 -0
  58. data/lib/badline/c64/cartridge/freezer.rb +35 -0
  59. data/lib/badline/c64/cartridge/fun_play.rb +40 -0
  60. data/lib/badline/c64/cartridge/g_mod2.rb +64 -0
  61. data/lib/badline/c64/cartridge/game_system.rb +42 -0
  62. data/lib/badline/c64/cartridge/geo_ram.rb +65 -0
  63. data/lib/badline/c64/cartridge/kcs_power.rb +69 -0
  64. data/lib/badline/c64/cartridge/keyed_state.rb +393 -0
  65. data/lib/badline/c64/cartridge/mach5.rb +34 -0
  66. data/lib/badline/c64/cartridge/magic_desk.rb +32 -0
  67. data/lib/badline/c64/cartridge/ocean.rb +37 -0
  68. data/lib/badline/c64/cartridge/pagefox.rb +60 -0
  69. data/lib/badline/c64/cartridge/retro_replay.rb +278 -0
  70. data/lib/badline/c64/cartridge/rex_utility.rb +31 -0
  71. data/lib/badline/c64/cartridge/rgcd.rb +50 -0
  72. data/lib/badline/c64/cartridge/simons_basic.rb +37 -0
  73. data/lib/badline/c64/cartridge/standard.rb +17 -0
  74. data/lib/badline/c64/cartridge/super_games.rb +40 -0
  75. data/lib/badline/c64/cartridge/westermann.rb +32 -0
  76. data/lib/badline/c64/cartridge/zaxxon.rb +52 -0
  77. data/lib/badline/c64/cartridge.rb +232 -0
  78. data/lib/badline/c64/color_memory.rb +27 -0
  79. data/lib/badline/{computer → c64}/common.rb +2 -2
  80. data/lib/badline/{computer → c64}/kernal_traps.rb +39 -36
  81. data/lib/badline/c64/keyed_modules.rb +111 -0
  82. data/lib/badline/c64/keyed_state.rb +68 -0
  83. data/lib/badline/c64/reu/dma.rb +271 -0
  84. data/lib/badline/c64/reu/keyed_state.rb +140 -0
  85. data/lib/badline/c64/reu/ram.rb +94 -0
  86. data/lib/badline/c64/reu/trigger.rb +34 -0
  87. data/lib/badline/c64/reu.rb +289 -0
  88. data/lib/badline/c64/true_drives.rb +120 -0
  89. data/lib/badline/{computer.rb → c64.rb} +24 -15
  90. data/lib/badline/chips/cia/fast_forward.rb +62 -0
  91. data/lib/badline/chips/cia/interrupt_register.rb +128 -0
  92. data/lib/badline/chips/cia/keyed_parts.rb +213 -0
  93. data/lib/badline/chips/cia/serial.rb +246 -0
  94. data/lib/badline/chips/cia/time_of_day.rb +210 -0
  95. data/lib/badline/chips/cia/timer.rb +188 -0
  96. data/lib/badline/chips/cia.rb +281 -0
  97. data/lib/badline/chips/cpu/addressing.rb +133 -0
  98. data/lib/badline/chips/cpu/boundary.rb +56 -0
  99. data/lib/badline/chips/cpu/core.rb +183 -0
  100. data/lib/badline/chips/cpu/instruction.rb +338 -0
  101. data/lib/badline/chips/cpu/instruction_set/arithmetic.rb +118 -0
  102. data/lib/badline/chips/cpu/instruction_set/bitwise.rb +130 -0
  103. data/lib/badline/chips/cpu/instruction_set/branch.rb +83 -0
  104. data/lib/badline/chips/cpu/instruction_set/flag.rb +67 -0
  105. data/lib/badline/chips/cpu/instruction_set/illegal.rb +274 -0
  106. data/lib/badline/chips/cpu/instruction_set/inc_dec.rb +73 -0
  107. data/lib/badline/chips/cpu/instruction_set/stack.rb +56 -0
  108. data/lib/badline/chips/cpu/instruction_set/transfer.rb +141 -0
  109. data/lib/badline/chips/cpu/instruction_set.rb +59 -0
  110. data/lib/badline/chips/cpu/interrupts.rb +108 -0
  111. data/lib/badline/chips/cpu/keyed_state.rb +177 -0
  112. data/lib/badline/chips/cpu/microcode.rb +195 -0
  113. data/lib/badline/chips/cpu/operations.rb +90 -0
  114. data/lib/badline/chips/cpu/port.rb +133 -0
  115. data/lib/badline/chips/cpu/stack_operations.rb +84 -0
  116. data/lib/badline/chips/cpu/traps.rb +23 -0
  117. data/lib/badline/chips/cpu.rb +17 -0
  118. data/lib/badline/chips/sid/catch_up.rb +122 -0
  119. data/lib/badline/chips/sid/decimator.rb +68 -0
  120. data/lib/badline/chips/sid/envelope.rb +236 -0
  121. data/lib/badline/chips/sid/filter.rb +227 -0
  122. data/lib/badline/chips/sid/keyed_parts.rb +286 -0
  123. data/lib/badline/chips/sid/voice.rb +69 -0
  124. data/lib/badline/chips/sid/waveform/combined.rb +128 -0
  125. data/lib/badline/chips/sid/waveform/fast_forward.rb +107 -0
  126. data/lib/badline/chips/sid/waveform/noise_writeback.rb +124 -0
  127. data/lib/badline/chips/sid/waveform.rb +305 -0
  128. data/lib/badline/chips/sid.rb +264 -0
  129. data/lib/badline/chips/ted/beam.rb +119 -0
  130. data/lib/badline/chips/ted/timers.rb +66 -0
  131. data/lib/badline/chips/ted.rb +143 -0
  132. data/lib/badline/chips/tia.rb +49 -0
  133. data/lib/badline/chips/vdc/keyed_parts.rb +105 -0
  134. data/lib/badline/{c128 → chips}/vdc/memory.rb +1 -1
  135. data/lib/badline/{c128 → chips}/vdc/painter.rb +1 -13
  136. data/lib/badline/{c128 → chips}/vdc/raster.rb +1 -17
  137. data/lib/badline/{c128 → chips}/vdc/window.rb +1 -10
  138. data/lib/badline/{c128 → chips}/vdc.rb +6 -31
  139. data/lib/badline/chips/via/control_lines.rb +109 -0
  140. data/lib/badline/chips/via/fast_forward.rb +55 -0
  141. data/lib/badline/chips/via/interrupt_register.rb +60 -0
  142. data/lib/badline/chips/via/keyed_parts.rb +163 -0
  143. data/lib/badline/chips/via/shift_register.rb +168 -0
  144. data/lib/badline/chips/via/timer1.rb +120 -0
  145. data/lib/badline/chips/via/timer2.rb +117 -0
  146. data/lib/badline/chips/via.rb +267 -0
  147. data/lib/badline/chips/vic/bank.rb +135 -0
  148. data/lib/badline/chips/vic/border_mask.rb +78 -0
  149. data/lib/badline/chips/vic/collisions.rb +106 -0
  150. data/lib/badline/chips/vic/color_patches.rb +38 -0
  151. data/lib/badline/chips/vic/display_state.rb +168 -0
  152. data/lib/badline/chips/vic/graphics_mode.rb +166 -0
  153. data/lib/badline/chips/vic/graphics_shifter.rb +183 -0
  154. data/lib/badline/chips/vic/keyed_parts.rb +228 -0
  155. data/lib/badline/chips/vic/keyed_sprites.rb +225 -0
  156. data/lib/badline/chips/vic/keyed_state.rb +102 -0
  157. data/lib/badline/chips/vic/register_log.rb +65 -0
  158. data/lib/badline/chips/vic/registers.rb +188 -0
  159. data/lib/badline/chips/vic/sequencer.rb +275 -0
  160. data/lib/badline/chips/vic/sequencer_output.rb +118 -0
  161. data/lib/badline/chips/vic/sprite/internal_bus.rb +59 -0
  162. data/lib/badline/chips/vic/sprite/shifter.rb +148 -0
  163. data/lib/badline/chips/vic/sprite/timing.rb +58 -0
  164. data/lib/badline/chips/vic/sprite.rb +337 -0
  165. data/lib/badline/chips/vic/sprites.rb +281 -0
  166. data/lib/badline/chips/vic.rb +787 -0
  167. data/lib/badline/chips/vic_i/keyed_parts.rb +142 -0
  168. data/lib/badline/{vic20/vic → chips/vic_i}/painter.rb +2 -30
  169. data/lib/badline/chips/vic_i/sound/output.rb +85 -0
  170. data/lib/badline/chips/vic_i/sound.rb +227 -0
  171. data/lib/badline/{vic20/vic → chips/vic_i}/text_window.rb +2 -2
  172. data/lib/badline/{vic20/vic.rb → chips/vic_i.rb} +6 -6
  173. data/lib/badline/chips/z80/arithmetic.rb +119 -0
  174. data/lib/badline/chips/z80/bit_page.rb +57 -0
  175. data/lib/badline/chips/z80/block_io.rb +60 -0
  176. data/lib/badline/chips/z80/block_transfers.rb +61 -0
  177. data/lib/badline/chips/z80/bus_cycles.rb +113 -0
  178. data/lib/badline/chips/z80/core.rb +115 -0
  179. data/lib/badline/chips/z80/exchanges.rb +52 -0
  180. data/lib/badline/chips/z80/extended_page.rb +91 -0
  181. data/lib/badline/chips/z80/flags.rb +39 -0
  182. data/lib/badline/chips/z80/interrupt_acceptance.rb +48 -0
  183. data/lib/badline/chips/z80/jumps.rb +84 -0
  184. data/lib/badline/chips/z80/keyed_state.rb +73 -0
  185. data/lib/badline/chips/z80/loads.rb +100 -0
  186. data/lib/badline/chips/z80/main_page.rb +136 -0
  187. data/lib/badline/chips/z80/registers.rb +122 -0
  188. data/lib/badline/chips/z80/shifts.rb +66 -0
  189. data/lib/badline/chips/z80.rb +13 -0
  190. data/lib/badline/chips.rb +10 -0
  191. data/lib/badline/core.rb +13 -32
  192. data/lib/badline/drives/datasette/keyed_state.rb +38 -0
  193. data/lib/badline/drives/datasette.rb +173 -0
  194. data/lib/badline/drives/engine/core.rb +152 -0
  195. data/lib/badline/drives/engine/fast_serial.rb +75 -0
  196. data/lib/badline/drives/engine/idle.rb +127 -0
  197. data/lib/badline/drives/engine/idle_cpu.rb +30 -0
  198. data/lib/badline/drives/engine/orbit.rb +81 -0
  199. data/lib/badline/drives/engine/serial_lines.rb +72 -0
  200. data/lib/badline/drives/engine/sleep.rb +114 -0
  201. data/lib/badline/drives/engine/vias.rb +86 -0
  202. data/lib/badline/drives/engine/watch.rb +152 -0
  203. data/lib/badline/drives/engine.rb +11 -0
  204. data/lib/badline/drives/model1541/bus.rb +75 -0
  205. data/lib/badline/drives/model1541/byte_ready.rb +50 -0
  206. data/lib/badline/drives/model1541/cpu.rb +13 -0
  207. data/lib/badline/drives/model1541/disk.rb +318 -0
  208. data/lib/badline/drives/model1541/disk_via.rb +38 -0
  209. data/lib/badline/drives/model1541/gcr.rb +59 -0
  210. data/lib/badline/drives/model1541/keyed_state.rb +251 -0
  211. data/lib/badline/drives/model1541/mechanism.rb +313 -0
  212. data/lib/badline/drives/model1541/rotation.rb +123 -0
  213. data/lib/badline/drives/model1541/sector_reader.rb +78 -0
  214. data/lib/badline/drives/model1541/serial_port.rb +20 -0
  215. data/lib/badline/drives/model1541/track.rb +100 -0
  216. data/lib/badline/drives/model1541.rb +80 -0
  217. data/lib/badline/drives/model1571/bus.rb +100 -0
  218. data/lib/badline/drives/model1571/cpu.rb +13 -0
  219. data/lib/badline/drives/model1571/keyed_state.rb +108 -0
  220. data/lib/badline/drives/model1571/serial_port.rb +39 -0
  221. data/lib/badline/drives/model1571/serial_via.rb +27 -0
  222. data/lib/badline/drives/model1571/wd1770.rb +108 -0
  223. data/lib/badline/drives/model1571.rb +141 -0
  224. data/lib/badline/drives/model1581/bus.rb +126 -0
  225. data/lib/badline/drives/model1581/cpu.rb +13 -0
  226. data/lib/badline/drives/model1581/disk.rb +133 -0
  227. data/lib/badline/drives/model1581/keyed_state.rb +280 -0
  228. data/lib/badline/drives/model1581/mechanism.rb +98 -0
  229. data/lib/badline/drives/model1581/serial_port.rb +54 -0
  230. data/lib/badline/drives/model1581/slot.rb +61 -0
  231. data/lib/badline/drives/model1581/track.rb +102 -0
  232. data/lib/badline/drives/model1581/track_bytes.rb +77 -0
  233. data/lib/badline/drives/model1581/wd1772/registers.rb +91 -0
  234. data/lib/badline/drives/model1581/wd1772/sector_writes.rb +75 -0
  235. data/lib/badline/drives/model1581/wd1772/sectors.rb +152 -0
  236. data/lib/badline/drives/model1581/wd1772/stepping.rb +111 -0
  237. data/lib/badline/drives/model1581/wd1772/tracks.rb +127 -0
  238. data/lib/badline/drives/model1581/wd1772/turn.rb +75 -0
  239. data/lib/badline/drives/model1581/wd1772.rb +216 -0
  240. data/lib/badline/drives/model1581.rb +206 -0
  241. data/lib/badline/drives/serial_bus.rb +161 -0
  242. data/lib/badline/drives.rb +8 -0
  243. data/lib/badline/frontend/app.rb +3 -3
  244. data/lib/badline/frontend/boot.rb +4 -4
  245. data/lib/badline/frontend/controls.rb +19 -3
  246. data/lib/badline/frontend/drive_led.rb +44 -21
  247. data/lib/badline/frontend/machine_window.rb +3 -1
  248. data/lib/badline/frontend/menu/menu_dialogs.rb +2 -2
  249. data/lib/badline/frontend/player/filter_view.rb +1 -1
  250. data/lib/badline/frontend/player/player_controller.rb +2 -2
  251. data/lib/badline/frontend/player/player_screen.rb +1 -0
  252. data/lib/badline/frontend/player/theme.rb +7 -7
  253. data/lib/badline/frontend/snapshots.rb +12 -1
  254. data/lib/badline/frontend/timeline.rb +30 -12
  255. data/lib/badline/input/control_ports.rb +78 -0
  256. data/lib/badline/input/joystick.rb +27 -0
  257. data/lib/badline/input/keyboard.rb +114 -0
  258. data/lib/badline/input/matrix_typist.rb +98 -0
  259. data/lib/badline/input.rb +4 -0
  260. data/lib/badline/kernal_trap/chrout.rb +45 -0
  261. data/lib/badline/kernal_trap/{drive → dos}/block_commands.rb +1 -1
  262. data/lib/badline/kernal_trap/dos/channel.rb +156 -0
  263. data/lib/badline/kernal_trap/{drive → dos}/channels.rb +1 -26
  264. data/lib/badline/kernal_trap/{drive → dos}/memory.rb +1 -10
  265. data/lib/badline/kernal_trap/{drive → dos}/parameters.rb +1 -1
  266. data/lib/badline/kernal_trap/{drive → dos}/status.rb +1 -9
  267. data/lib/badline/kernal_trap/{drive → dos}/write_file.rb +1 -19
  268. data/lib/badline/kernal_trap/{drive → dos}/writes.rb +1 -1
  269. data/lib/badline/kernal_trap/{drive.rb → dos.rb} +9 -27
  270. data/lib/badline/kernal_trap/file_routine.rb +4 -4
  271. data/lib/badline/kernal_trap/keyed_state.rb +150 -0
  272. data/lib/badline/kernal_trap/layout.rb +75 -11
  273. data/lib/badline/kernal_trap/load.rb +19 -21
  274. data/lib/badline/kernal_trap/routine.rb +12 -0
  275. data/lib/badline/kernal_trap/save.rb +12 -22
  276. data/lib/badline/kernal_trap/serial.rb +8 -24
  277. data/lib/badline/kernal_trap.rb +3 -2
  278. data/lib/badline/machine/clocking.rb +1 -1
  279. data/lib/badline/machine/keyboard_buffer.rb +49 -0
  280. data/lib/badline/machine/settling.rb +29 -0
  281. data/lib/badline/machine.rb +10 -7
  282. data/lib/badline/media/boot_disk.rb +14 -2
  283. data/lib/badline/media/extensions.rb +10 -0
  284. data/lib/badline/media/true_drive.rb +1 -1
  285. data/lib/badline/media/tune.rb +2 -2
  286. data/lib/badline/media.rb +3 -3
  287. data/lib/badline/memory.rb +3 -6
  288. data/lib/badline/model.rb +1 -1
  289. data/lib/badline/options/family.rb +5 -2
  290. data/lib/badline/options/help.rb +42 -16
  291. data/lib/badline/options/table.rb +2 -0
  292. data/lib/badline/options/validation.rb +2 -0
  293. data/lib/badline/options.rb +6 -1
  294. data/lib/badline/plus4/acia.rb +45 -0
  295. data/lib/badline/plus4/bus.rb +312 -0
  296. data/lib/badline/plus4/cpu.rb +10 -0
  297. data/lib/badline/plus4/cpu_port.rb +93 -0
  298. data/lib/badline/plus4/keyboard_port.rb +51 -0
  299. data/lib/badline/plus4/model.rb +38 -0
  300. data/lib/badline/plus4/user_port.rb +31 -0
  301. data/lib/badline/plus4.rb +164 -0
  302. data/lib/badline/roms/README +44 -6
  303. data/lib/badline/roms/plus4/basic.rom +0 -0
  304. data/lib/badline/roms/plus4/function-high.rom +0 -0
  305. data/lib/badline/roms/plus4/function-low.rom +0 -0
  306. data/lib/badline/roms/plus4/kernal-ntsc.rom +0 -0
  307. data/lib/badline/roms/plus4/kernal-pal.rom +0 -0
  308. data/lib/badline/sdl.rb +1 -0
  309. data/lib/badline/{storage/sid_file.rb → sid_tune/file.rb} +3 -3
  310. data/lib/badline/{storage → sid_tune}/hvsc.rb +7 -7
  311. data/lib/badline/{storage → sid_tune}/song_lengths.rb +2 -2
  312. data/lib/badline/{storage → sid_tune}/stil/credit.rb +1 -1
  313. data/lib/badline/{storage → sid_tune}/stil.rb +3 -3
  314. data/lib/badline/sid_tune.rb +6 -0
  315. data/lib/badline/snapshot/c128_setup.rb +32 -0
  316. data/lib/badline/snapshot/c64_setup.rb +83 -0
  317. data/lib/badline/snapshot/container.rb +4 -0
  318. data/lib/badline/snapshot/field_doc/markdown.rb +112 -0
  319. data/lib/badline/snapshot/field_doc.rb +109 -0
  320. data/lib/badline/snapshot/image.rb +132 -46
  321. data/lib/badline/snapshot/keyed/cursor.rb +40 -0
  322. data/lib/badline/snapshot/keyed/modules.rb +66 -0
  323. data/lib/badline/snapshot/keyed/reader.rb +188 -0
  324. data/lib/badline/snapshot/keyed/recorder.rb +88 -0
  325. data/lib/badline/snapshot/keyed/report.rb +26 -0
  326. data/lib/badline/snapshot/keyed/writer.rb +55 -0
  327. data/lib/badline/snapshot/keyed.rb +64 -0
  328. data/lib/badline/snapshot/machine_state.rb +17 -64
  329. data/lib/badline/snapshot/storage_setup.rb +63 -0
  330. data/lib/badline/snapshot/vic20_setup.rb +28 -0
  331. data/lib/badline/snapshot/vice/c64_mem.rb +1 -1
  332. data/lib/badline/snapshot/vice/restore.rb +1 -1
  333. data/lib/badline/snapshot/vice/reu1764.rb +3 -3
  334. data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
  335. data/lib/badline/snapshot/vice.rb +13 -35
  336. data/lib/badline/snapshot.rb +44 -22
  337. data/lib/badline/storage/crt_file.rb +3 -1
  338. data/lib/badline/storage/d64_image.rb +0 -2
  339. data/lib/badline/storage/d71_image.rb +0 -2
  340. data/lib/badline/storage/d81_image.rb +0 -2
  341. data/lib/badline/storage/disk_image.rb +3 -6
  342. data/lib/badline/storage/g64_image.rb +10 -5
  343. data/lib/badline/storage/host_directory.rb +0 -5
  344. data/lib/badline/storage/t64.rb +2 -8
  345. data/lib/badline/storage/tap.rb +43 -15
  346. data/lib/badline/storage/unavailable.rb +1 -1
  347. data/lib/badline/storage.rb +0 -37
  348. data/lib/badline/support/c128_checkpoint.rb +39 -0
  349. data/lib/badline/support/checkpoint.rb +108 -0
  350. data/lib/badline/support/vic20_checkpoint.rb +38 -0
  351. data/lib/badline/support.rb +5 -0
  352. data/lib/badline/version.rb +1 -1
  353. data/lib/badline/vic20/attachments.rb +8 -5
  354. data/lib/badline/vic20/bus/keyed_state.rb +52 -0
  355. data/lib/badline/vic20/bus.rb +2 -25
  356. data/lib/badline/vic20/cpu.rb +1 -1
  357. data/lib/badline/vic20/keyed_modules.rb +73 -0
  358. data/lib/badline/vic20/keyed_state.rb +45 -0
  359. data/lib/badline/vic20/port_wiring.rb +4 -4
  360. data/lib/badline/vic20/user_via_ports.rb +2 -2
  361. data/lib/badline/vic20.rb +22 -17
  362. data/lib/badline.rb +1 -0
  363. metadata +271 -228
  364. data/lib/badline/address_bus/extra_sids.rb +0 -30
  365. data/lib/badline/address_bus/fittings.rb +0 -38
  366. data/lib/badline/address_bus/pla.rb +0 -147
  367. data/lib/badline/address_bus/roms.rb +0 -39
  368. data/lib/badline/address_bus/saved_state.rb +0 -66
  369. data/lib/badline/address_bus/sid_slots.rb +0 -42
  370. data/lib/badline/address_bus.rb +0 -216
  371. data/lib/badline/c128/bus_state.rb +0 -53
  372. data/lib/badline/c128/saved_state.rb +0 -143
  373. data/lib/badline/cartridge/action_replay.rb +0 -126
  374. data/lib/badline/cartridge/atomic_power.rb +0 -24
  375. data/lib/badline/cartridge/bank.rb +0 -81
  376. data/lib/badline/cartridge/comal80.rb +0 -50
  377. data/lib/badline/cartridge/dinamic.rb +0 -34
  378. data/lib/badline/cartridge/easy_flash.rb +0 -145
  379. data/lib/badline/cartridge/epyx_fastload.rb +0 -79
  380. data/lib/badline/cartridge/final_cartridge3.rb +0 -89
  381. data/lib/badline/cartridge/flash.rb +0 -306
  382. data/lib/badline/cartridge/freezer.rb +0 -33
  383. data/lib/badline/cartridge/fun_play.rb +0 -38
  384. data/lib/badline/cartridge/g_mod2.rb +0 -74
  385. data/lib/badline/cartridge/game_system.rb +0 -40
  386. data/lib/badline/cartridge/geo_ram.rb +0 -79
  387. data/lib/badline/cartridge/kcs_power.rb +0 -75
  388. data/lib/badline/cartridge/mach5.rb +0 -32
  389. data/lib/badline/cartridge/magic_desk.rb +0 -30
  390. data/lib/badline/cartridge/ocean.rb +0 -35
  391. data/lib/badline/cartridge/pagefox.rb +0 -68
  392. data/lib/badline/cartridge/retro_replay.rb +0 -320
  393. data/lib/badline/cartridge/rex_utility.rb +0 -29
  394. data/lib/badline/cartridge/rgcd.rb +0 -58
  395. data/lib/badline/cartridge/simons_basic.rb +0 -35
  396. data/lib/badline/cartridge/standard.rb +0 -15
  397. data/lib/badline/cartridge/super_games.rb +0 -48
  398. data/lib/badline/cartridge/westermann.rb +0 -30
  399. data/lib/badline/cartridge/zaxxon.rb +0 -66
  400. data/lib/badline/cartridge.rb +0 -303
  401. data/lib/badline/checkpoint.rb +0 -98
  402. data/lib/badline/chrout_trap.rb +0 -43
  403. data/lib/badline/cia/fast_forward.rb +0 -60
  404. data/lib/badline/cia/interrupt_register.rb +0 -143
  405. data/lib/badline/cia/serial.rb +0 -275
  406. data/lib/badline/cia/state.rb +0 -47
  407. data/lib/badline/cia/timer.rb +0 -206
  408. data/lib/badline/cia.rb +0 -279
  409. data/lib/badline/color_memory.rb +0 -25
  410. data/lib/badline/computer/attachments.rb +0 -88
  411. data/lib/badline/computer/saved_state.rb +0 -117
  412. data/lib/badline/computer/true_drives.rb +0 -69
  413. data/lib/badline/control_ports.rb +0 -76
  414. data/lib/badline/cpu/addressing.rb +0 -131
  415. data/lib/badline/cpu/boundary.rb +0 -54
  416. data/lib/badline/cpu/core.rb +0 -165
  417. data/lib/badline/cpu/microcode.rb +0 -177
  418. data/lib/badline/cpu/operations.rb +0 -88
  419. data/lib/badline/cpu/saved_state.rb +0 -115
  420. data/lib/badline/cpu/stack_operations.rb +0 -82
  421. data/lib/badline/cpu.rb +0 -10
  422. data/lib/badline/cpu_port.rb +0 -112
  423. data/lib/badline/datasette.rb +0 -161
  424. data/lib/badline/debug_register.rb +0 -28
  425. data/lib/badline/drive/core.rb +0 -147
  426. data/lib/badline/drive/fast_serial.rb +0 -73
  427. data/lib/badline/drive/idle.rb +0 -125
  428. data/lib/badline/drive/idle_cpu.rb +0 -28
  429. data/lib/badline/drive/orbit.rb +0 -79
  430. data/lib/badline/drive/serial_lines.rb +0 -73
  431. data/lib/badline/drive/sleep.rb +0 -112
  432. data/lib/badline/drive/vias.rb +0 -84
  433. data/lib/badline/drive/watch.rb +0 -150
  434. data/lib/badline/drive.rb +0 -11
  435. data/lib/badline/drive1541/bus.rb +0 -86
  436. data/lib/badline/drive1541/byte_ready.rb +0 -48
  437. data/lib/badline/drive1541/cpu.rb +0 -11
  438. data/lib/badline/drive1541/disk.rb +0 -315
  439. data/lib/badline/drive1541/disk_state.rb +0 -86
  440. data/lib/badline/drive1541/disk_via.rb +0 -36
  441. data/lib/badline/drive1541/gcr.rb +0 -57
  442. data/lib/badline/drive1541/mechanism.rb +0 -313
  443. data/lib/badline/drive1541/mechanism_state.rb +0 -68
  444. data/lib/badline/drive1541/rotation.rb +0 -121
  445. data/lib/badline/drive1541/sector_reader.rb +0 -76
  446. data/lib/badline/drive1541/serial_port.rb +0 -18
  447. data/lib/badline/drive1541/track.rb +0 -98
  448. data/lib/badline/drive1541.rb +0 -111
  449. data/lib/badline/drive1571/bus.rb +0 -111
  450. data/lib/badline/drive1571/cpu.rb +0 -11
  451. data/lib/badline/drive1571/serial_port.rb +0 -37
  452. data/lib/badline/drive1571/serial_via.rb +0 -25
  453. data/lib/badline/drive1571/wd1770.rb +0 -120
  454. data/lib/badline/drive1571.rb +0 -175
  455. data/lib/badline/drive1581/bus.rb +0 -137
  456. data/lib/badline/drive1581/cpu.rb +0 -11
  457. data/lib/badline/drive1581/disk.rb +0 -135
  458. data/lib/badline/drive1581/disk_state.rb +0 -87
  459. data/lib/badline/drive1581/mechanism.rb +0 -117
  460. data/lib/badline/drive1581/serial_port.rb +0 -52
  461. data/lib/badline/drive1581/slot.rb +0 -78
  462. data/lib/badline/drive1581/track.rb +0 -100
  463. data/lib/badline/drive1581/track_bytes.rb +0 -75
  464. data/lib/badline/drive1581/wd1772/registers.rb +0 -89
  465. data/lib/badline/drive1581/wd1772/sector_writes.rb +0 -73
  466. data/lib/badline/drive1581/wd1772/sectors.rb +0 -150
  467. data/lib/badline/drive1581/wd1772/state.rb +0 -66
  468. data/lib/badline/drive1581/wd1772/stepping.rb +0 -109
  469. data/lib/badline/drive1581/wd1772/tracks.rb +0 -125
  470. data/lib/badline/drive1581/wd1772/turn.rb +0 -73
  471. data/lib/badline/drive1581/wd1772.rb +0 -216
  472. data/lib/badline/drive1581.rb +0 -233
  473. data/lib/badline/iec_bus.rb +0 -159
  474. data/lib/badline/instruction.rb +0 -334
  475. data/lib/badline/instruction_set/arithmetic.rb +0 -114
  476. data/lib/badline/instruction_set/bitwise.rb +0 -126
  477. data/lib/badline/instruction_set/branch.rb +0 -79
  478. data/lib/badline/instruction_set/flag.rb +0 -63
  479. data/lib/badline/instruction_set/illegal.rb +0 -270
  480. data/lib/badline/instruction_set/inc_dec.rb +0 -69
  481. data/lib/badline/instruction_set/stack.rb +0 -52
  482. data/lib/badline/instruction_set/transfer.rb +0 -137
  483. data/lib/badline/instruction_set.rb +0 -55
  484. data/lib/badline/interrupts.rb +0 -104
  485. data/lib/badline/joystick.rb +0 -25
  486. data/lib/badline/kernal_trap/channel.rb +0 -181
  487. data/lib/badline/keyboard.rb +0 -112
  488. data/lib/badline/keyboard_buffer.rb +0 -33
  489. data/lib/badline/ram_expansion/banking.rb +0 -30
  490. data/lib/badline/ram_expansion/plus256k.rb +0 -54
  491. data/lib/badline/ram_expansion/plus60k.rb +0 -43
  492. data/lib/badline/ram_expansion/unexpanded.rb +0 -28
  493. data/lib/badline/ram_expansion.rb +0 -21
  494. data/lib/badline/reu/dma/saved_state.rb +0 -50
  495. data/lib/badline/reu/dma.rb +0 -273
  496. data/lib/badline/reu/ram.rb +0 -107
  497. data/lib/badline/reu/saved_state.rb +0 -80
  498. data/lib/badline/reu/trigger.rb +0 -32
  499. data/lib/badline/reu.rb +0 -289
  500. data/lib/badline/sid/catch_up.rb +0 -120
  501. data/lib/badline/sid/decimator.rb +0 -64
  502. data/lib/badline/sid/envelope/state.rb +0 -68
  503. data/lib/badline/sid/envelope.rb +0 -239
  504. data/lib/badline/sid/filter.rb +0 -263
  505. data/lib/badline/sid/voice.rb +0 -77
  506. data/lib/badline/sid/waveform/combined.rb +0 -126
  507. data/lib/badline/sid/waveform/fast_forward.rb +0 -105
  508. data/lib/badline/sid/waveform/noise_writeback.rb +0 -122
  509. data/lib/badline/sid/waveform/state.rb +0 -66
  510. data/lib/badline/sid/waveform.rb +0 -305
  511. data/lib/badline/sid.rb +0 -303
  512. data/lib/badline/snapshot/setup.rb +0 -75
  513. data/lib/badline/snapshot/state.rb +0 -189
  514. data/lib/badline/time_of_day.rb +0 -228
  515. data/lib/badline/traps.rb +0 -19
  516. data/lib/badline/via/control_lines.rb +0 -122
  517. data/lib/badline/via/fast_forward.rb +0 -53
  518. data/lib/badline/via/interrupt_register.rb +0 -67
  519. data/lib/badline/via/shift_register.rb +0 -180
  520. data/lib/badline/via/state.rb +0 -42
  521. data/lib/badline/via/timer1.rb +0 -131
  522. data/lib/badline/via/timer2.rb +0 -133
  523. data/lib/badline/via.rb +0 -266
  524. data/lib/badline/vic/bank.rb +0 -133
  525. data/lib/badline/vic/border_mask.rb +0 -86
  526. data/lib/badline/vic/collisions.rb +0 -115
  527. data/lib/badline/vic/color_patches.rb +0 -47
  528. data/lib/badline/vic/display_state.rb +0 -185
  529. data/lib/badline/vic/graphics_mode.rb +0 -164
  530. data/lib/badline/vic/graphics_shifter.rb +0 -207
  531. data/lib/badline/vic/register_log.rb +0 -81
  532. data/lib/badline/vic/registers.rb +0 -195
  533. data/lib/badline/vic/sequencer.rb +0 -275
  534. data/lib/badline/vic/sequencer_output.rb +0 -116
  535. data/lib/badline/vic/sequencer_state.rb +0 -89
  536. data/lib/badline/vic/sprite/internal_bus.rb +0 -68
  537. data/lib/badline/vic/sprite/saved_state.rb +0 -64
  538. data/lib/badline/vic/sprite/shifter.rb +0 -146
  539. data/lib/badline/vic/sprite/timing.rb +0 -56
  540. data/lib/badline/vic/sprite.rb +0 -337
  541. data/lib/badline/vic/sprites.rb +0 -282
  542. data/lib/badline/vic/sprites_state.rb +0 -57
  543. data/lib/badline/vic.rb +0 -853
  544. data/lib/badline/vic20/saved_state.rb +0 -124
  545. data/lib/badline/vic20/sound/output.rb +0 -83
  546. data/lib/badline/vic20/sound.rb +0 -233
  547. data/lib/badline/vic20/vic/saved_state.rb +0 -55
  548. data/lib/badline/z80/arithmetic.rb +0 -117
  549. data/lib/badline/z80/bit_page.rb +0 -55
  550. data/lib/badline/z80/block_io.rb +0 -58
  551. data/lib/badline/z80/block_transfers.rb +0 -59
  552. data/lib/badline/z80/bus_cycles.rb +0 -111
  553. data/lib/badline/z80/core.rb +0 -113
  554. data/lib/badline/z80/exchanges.rb +0 -50
  555. data/lib/badline/z80/extended_page.rb +0 -89
  556. data/lib/badline/z80/flags.rb +0 -37
  557. data/lib/badline/z80/interrupt_acceptance.rb +0 -46
  558. data/lib/badline/z80/jumps.rb +0 -82
  559. data/lib/badline/z80/loads.rb +0 -98
  560. data/lib/badline/z80/main_page.rb +0 -134
  561. data/lib/badline/z80/registers.rb +0 -120
  562. data/lib/badline/z80/saved_state.rb +0 -69
  563. data/lib/badline/z80/shifts.rb +0 -64
  564. data/lib/badline/z80.rb +0 -11
  565. /data/lib/badline/snapshot/{fields.rb → vice/fields.rb} +0 -0
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIC
6
+ # A mid-line color register write becomes visible one pixel into the
7
+ # column emitted the cycle after the write. That emit paints the whole
8
+ # column with the new color, so the boundary pixel is patched back to
9
+ # the old one before the line is finished. On the 8565 the boundary
10
+ # pixel shows light grey instead, the grey dot, whatever the old and new
11
+ # colors are.
12
+ class ColorPatches
13
+ def initialize(sequencer, grey_dots: false)
14
+ @sequencer = sequencer
15
+ @grey_dots = grey_dots
16
+ @patches = []
17
+ end
18
+
19
+ def clear = @patches.clear
20
+
21
+ def log(reg, old, value, boundary_x)
22
+ @patches << [boundary_x, reg, @grey_dots ? GREY_DOT : old & 0x0f, value & 0x0f]
23
+ end
24
+
25
+ def apply(colors, fg_mask)
26
+ @patches.each do |(x, reg, old, value)|
27
+ border = @sequencer.border_at?(x)
28
+ if reg == 0x20
29
+ colors[x] = old if border
30
+ elsif !border && !fg_mask[x] && colors[x] == value
31
+ colors[x] = old
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,168 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIC
6
+ # = VIC-II display state
7
+ #
8
+ # The bad line condition, the video counters it drives, and the DMA it
9
+ # starts. A condition that arrives mid-line opens the row late, which is
10
+ # what makes the screen scroll sideways or lose a column of cells.
11
+ class DisplayState
12
+ FIRST_LINE = 0x30 # 48: bad lines and the DEN-at-$30 latch begin here
13
+ LAST_LINE = 0xf7 # 247
14
+ COLUMNS_PER_ROW = 40
15
+
16
+ # AEC follows BA three cycles later; the c-accesses before it read
17
+ # the bus the CPU still drives.
18
+ BA_DELAY = 3
19
+
20
+ # Columns run two ahead of Bauer's cycle numbers: column 10 is his
21
+ # cycle 12. BA falls on a match in columns 10-52, the c-accesses run
22
+ # in 13-52 and the g-accesses in 14-53. VC and VMLI reload in column
23
+ # 12 and the row counter steps in column 56.
24
+ DMA_FIRST = 10
25
+ DMA_LAST = 52
26
+ FETCH_FIRST = 13
27
+ GRAPHICS_FIRST = 14
28
+ GRAPHICS_LAST = 53
29
+ LOAD_COLUMN = 12
30
+ RC_COLUMN = 56
31
+
32
+ GRAPHICS_COLUMNS = Array.new(65) { |column| column.between?(GRAPHICS_FIRST, GRAPHICS_LAST) }.freeze
33
+
34
+ attr_reader :vc_base, :vc, :vmli, :rc, :bad_lines_enabled
35
+
36
+ # The wrap column is the last column of a rasterline, 62 on the 6569,
37
+ # which already compares against the line about to start, the same
38
+ # wrap the raster IRQ latch uses.
39
+ def initialize(registers, wrap_column = 62)
40
+ @registers = registers
41
+ @wrap_column = wrap_column
42
+ @vc_base = 0
43
+ @vc = 0
44
+ @vmli = 0
45
+ @rc = 0
46
+ @display = false
47
+ @bad_lines_enabled = false
48
+ @matched = false
49
+ @ba = nil
50
+ new_line(0)
51
+ end
52
+
53
+ def display? = @display
54
+
55
+ # Sets VCBASE, VC, RC and VMLI, in that order, and the display and
56
+ # bad-line flags, as a VICE snapshot gives them.
57
+ def restore_counters(counters, display, bad_lines_enabled)
58
+ @vc_base, @vc, @rc, @vmli = counters
59
+ @display = display
60
+ @bad_lines_enabled = bad_lines_enabled
61
+ end
62
+
63
+ def idle? = !@display
64
+ def bad_line? = !@ba.nil?
65
+
66
+ # The bad line condition as the last column compared it.
67
+ def bad_line_condition? = @matched
68
+
69
+ # True once AEC has followed BA down and the VIC owns the bus.
70
+ def bus_taken?(column) = @ba ? column >= @ba + BA_DELAY : false
71
+
72
+ # The CPU kept the bus through the cycle before +column+, so on a bad
73
+ # line AEC falls BA_DELAY cycles after it at the earliest.
74
+ def keep_bus(column)
75
+ @ba &&= column
76
+ end
77
+
78
+ def fetching?(column)
79
+ @matched && column >= FETCH_FIRST && column <= DMA_LAST
80
+ end
81
+
82
+ def new_frame
83
+ @vc_base = 0
84
+ @bad_lines_enabled = false
85
+ end
86
+
87
+ def new_line(line)
88
+ @ba = nil
89
+ raster_step(line)
90
+ end
91
+
92
+ # The raster counter moved on to +line+, at the line's start or, under
93
+ # the VIC-IIe's TEST bit, within it.
94
+ def raster_step(line)
95
+ @line_bits = line & 0b111
96
+ @den_line = line == FIRST_LINE
97
+ @in_window = line.between?(FIRST_LINE, LAST_LINE)
98
+ end
99
+
100
+ # Returns true when this compare opened display state.
101
+ def cycle(rasterline, column)
102
+ match = column == @wrap_column ? wrap_match(rasterline + 1) : line_match
103
+ @matched = match
104
+ opened = false
105
+ if match
106
+ opened = !@display
107
+ @display = true
108
+ @ba = column if @ba.nil? && column >= DMA_FIRST && column <= DMA_LAST
109
+ end
110
+ load_counters(match) if column == LOAD_COLUMN
111
+ check_row_counter(match) if column == RC_COLUMN
112
+ opened
113
+ end
114
+
115
+ # A g-access in display state consumes one buffer cell and one video
116
+ # matrix address. A row that opens mid-line makes fewer of them, and
117
+ # the shortfall carries into VCBASE.
118
+ def graphics_column?(column) = GRAPHICS_COLUMNS[column]
119
+
120
+ def graphics_access(column)
121
+ return unless graphics_column?(column)
122
+
123
+ @vc = (@vc + 1) & 0x3ff
124
+ @vmli += 1
125
+ end
126
+
127
+ private
128
+
129
+ def line_match
130
+ latch_den if @den_line
131
+ @bad_lines_enabled && @in_window && @line_bits == @registers.yscroll
132
+ end
133
+
134
+ # The wrap column compares against the line about to start. The DEN
135
+ # latch is level-sensitive across the counter's increment, so this one
136
+ # column sees both the line ending and the line starting.
137
+ def wrap_match(line)
138
+ latch_den if @den_line || line == FIRST_LINE
139
+ return false unless line.between?(FIRST_LINE, LAST_LINE)
140
+
141
+ @bad_lines_enabled && (line & 0b111) == @registers.yscroll
142
+ end
143
+
144
+ def latch_den
145
+ @bad_lines_enabled = true if @registers.display_enabled?
146
+ end
147
+
148
+ def load_counters(match)
149
+ @vc = @vc_base
150
+ @vmli = 0
151
+ @rc = 0 if match
152
+ end
153
+
154
+ # A condition still standing when the row counter wraps puts the logic
155
+ # straight back into display state, so a forced row rolls into the
156
+ # next one instead of leaving the line idle (Bauer 3.7.2 step 5).
157
+ def check_row_counter(match)
158
+ if @rc == 7
159
+ @display = false
160
+ @vc_base = @vc
161
+ end
162
+ @display ||= match
163
+ @rc = (@rc + 1) & 0b111 if @display
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIC
6
+ module GraphicsMode
7
+ # Foreground masks depend only on the data byte, so each byte maps to a
8
+ # precomputed frozen pattern shared by reference instead of being
9
+ # written out pixel by pixel.
10
+ HIRES_FG = Array.new(256) do |data|
11
+ Array.new(8) { |i| data.anybits?(1 << (7 - i)) }.freeze
12
+ end.freeze
13
+
14
+ # The high bit of each 2-bit pair (10/11) is foreground.
15
+ PAIR_FG = Array.new(256) do |data|
16
+ Array.new(8) { |i| (data >> (6 - (i & ~1))).allbits?(0b10) }.freeze
17
+ end.freeze
18
+
19
+ # The same patterns as masks, all bits set for a foreground pixel.
20
+ HIRES_MASK = Array.new(256) do |data|
21
+ Array.new(8) { |i| data.anybits?(1 << (7 - i)) ? -1 : 0 }.freeze
22
+ end.freeze
23
+
24
+ NO_FG = HIRES_FG[0]
25
+
26
+ module Hires
27
+ def paint_hires(data, color, background, seq)
28
+ seq.cur_fg = HIRES_FG[data]
29
+ colors = seq.cur_colors
30
+ return colors.fill(background) if data.zero?
31
+
32
+ mask = HIRES_MASK[data]
33
+ flip = color ^ background
34
+ colors[0] = background ^ (flip & mask[0])
35
+ colors[1] = background ^ (flip & mask[1])
36
+ colors[2] = background ^ (flip & mask[2])
37
+ colors[3] = background ^ (flip & mask[3])
38
+ colors[4] = background ^ (flip & mask[4])
39
+ colors[5] = background ^ (flip & mask[5])
40
+ colors[6] = background ^ (flip & mask[6])
41
+ colors[7] = background ^ (flip & mask[7])
42
+ end
43
+ end
44
+
45
+ # Decodes 2-bit pixel pairs into double-wide pixels, each pair indexing
46
+ # the four colours in the mode's palette.
47
+ module Multicolor
48
+ def paint_pairs(data, seq)
49
+ seq.cur_fg = PAIR_FG[data]
50
+ colors = seq.cur_colors
51
+ palette = @palette
52
+ colors[0] = colors[1] = palette[data >> 6]
53
+ colors[2] = colors[3] = palette[(data >> 4) & 0b11]
54
+ colors[4] = colors[5] = palette[(data >> 2) & 0b11]
55
+ colors[6] = colors[7] = palette[data & 0b11]
56
+ end
57
+ end
58
+
59
+ # Each mode paints the byte a g-access read with the screen byte and
60
+ # colour nibble it latched. The VIC reads the byte itself, in the
61
+ # g-access column. #fg gives the foreground mask #paint would leave,
62
+ # without the colours.
63
+ class Text
64
+ include Hires
65
+
66
+ def paint(data, _screencode, color, seq)
67
+ paint_hires(data, color, seq.registers.background, seq)
68
+ end
69
+
70
+ def fg(data, _screencode, _color) = HIRES_FG[data]
71
+ end
72
+
73
+ class MulticolorText
74
+ include Hires
75
+ include Multicolor
76
+
77
+ def initialize
78
+ @palette = Array.new(4, 0)
79
+ end
80
+
81
+ def paint(data, _screencode, color, seq)
82
+ registers = seq.registers
83
+ if color.anybits?(0x08)
84
+ palette = @palette
85
+ palette[0] = registers.background(0)
86
+ palette[1] = registers.background(1)
87
+ palette[2] = registers.background(2)
88
+ palette[3] = color & 0x07
89
+ paint_pairs(data, seq)
90
+ else
91
+ paint_hires(data, color & 0x07, registers.background, seq)
92
+ end
93
+ end
94
+
95
+ def fg(data, _screencode, color) = color.anybits?(0x08) ? PAIR_FG[data] : HIRES_FG[data]
96
+ end
97
+
98
+ class ExtendedBackgroundText
99
+ include Hires
100
+
101
+ def paint(data, screencode, color, seq)
102
+ background = seq.registers.background((screencode >> 6) & 0b11)
103
+ paint_hires(data, color, background, seq)
104
+ end
105
+
106
+ def fg(data, _screencode, _color) = HIRES_FG[data]
107
+ end
108
+
109
+ class Bitmap
110
+ include Hires
111
+
112
+ def paint(data, screencode, _color, seq)
113
+ foreground = (screencode >> 4) & 0x0f
114
+ background = screencode & 0x0f
115
+ paint_hires(data, foreground, background, seq)
116
+ end
117
+
118
+ def fg(data, _screencode, _color) = HIRES_FG[data]
119
+ end
120
+
121
+ class MulticolorBitmap
122
+ include Multicolor
123
+
124
+ def initialize
125
+ @palette = Array.new(4, 0)
126
+ end
127
+
128
+ def paint(data, screencode, color, seq)
129
+ palette = @palette
130
+ palette[0] = seq.registers.background(0)
131
+ palette[1] = (screencode >> 4) & 0x0f
132
+ palette[2] = screencode & 0x0f
133
+ palette[3] = color & 0x0f
134
+ paint_pairs(data, seq)
135
+ end
136
+
137
+ def fg(data, _screencode, _color) = PAIR_FG[data]
138
+ end
139
+
140
+ class Null
141
+ def paint(_data, _screencode, _color, seq)
142
+ seq.cur_fg = NO_FG
143
+ seq.cur_colors.fill(0)
144
+ end
145
+
146
+ def fg(_data, _screencode, _color) = NO_FG
147
+ end
148
+
149
+ NULL_MODE = Null.new
150
+
151
+ # Indexed by ECM/BMM/MCM; the three invalid combinations decode to
152
+ # black.
153
+ MODES = [
154
+ Text.new, # 000 standard text
155
+ MulticolorText.new, # 001 multicolour text
156
+ Bitmap.new, # 010 standard bitmap
157
+ MulticolorBitmap.new, # 011 multicolour bitmap
158
+ ExtendedBackgroundText.new, # 100 ECM text
159
+ NULL_MODE, # 101 invalid
160
+ NULL_MODE, # 110 invalid
161
+ NULL_MODE # 111 invalid
162
+ ].freeze
163
+ end
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,183 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIC
6
+ # The graphics shift register, pixel by pixel, for the groups where a
7
+ # mode or XSCROLL change lands (VICE x64sc `draw_graphics`). The
8
+ # sequencer paints whole bytes everywhere else, which comes to the same
9
+ # thing while nothing changes.
10
+ #
11
+ # The byte a group draws loads at pixel XSCROLL. ECM and BMM take hold at
12
+ # pixel 4 as they rise and at pixel 6 as they fall (the 6569's colour
13
+ # latency), except that BMM falls at pixel 5 out of any mode but hi-res
14
+ # bitmap. MCM takes hold at pixel 4 for the colour lookup but only at
15
+ # pixel 7 for how the register is read, where a rising MCM also resets
16
+ # the multicolour flip-flop. An MCM that falls out of the invalid
17
+ # ECM+MCM mode is a pixel later on both counts: the lookup changes at
18
+ # pixel 5 and the read at the next group's pixel 0. The mode bits are
19
+ # the sequencer's: ECM 4, BMM 2, MCM 1.
20
+ #
21
+ # The 8565 has no colour latency: ECM and BMM take hold, rising or
22
+ # falling, at the next group's pixel 0, and an MCM that falls out of
23
+ # ECM+MCM does so on time. Where that pixel 0 takes the group out of an
24
+ # invalid mode, it is still black into hi-res text, and so is a
25
+ # background pixel into multicolour bitmap.
26
+ class GraphicsShifter
27
+ ECM = 0b100
28
+ ECM_BMM = 0b110
29
+ MULTICOLOR_BITMAP = 0b011
30
+ ECM_MCM = 0b101
31
+ BMM = 0b010
32
+
33
+ # The group #draw painted, and which of its pixels are foreground.
34
+ attr_reader :colors, :fg
35
+
36
+ def initialize(registers, model: :mos6569)
37
+ @registers = registers
38
+ @latency = model != :mos8565
39
+ @next_ecm_bmm = 0
40
+ @black_below = 0
41
+ @colors = Array.new(8, 0)
42
+ @fg = Array.new(8, false)
43
+ @gbuf = 0
44
+ @vbuf = 0
45
+ @cbuf = 0
46
+ @flop = 0
47
+ @pixel = 0
48
+ @mode_lookup = 0
49
+ @mode_read = 0
50
+ @late_mcm = false
51
+ @late_read = false
52
+ end
53
+
54
+ # Rebuilds the state at the end of a group that painted whole bytes:
55
+ # the byte loaded at pixel shift under an unchanging mode.
56
+ def prime(data, screencode, color, shift, mode)
57
+ @mode_lookup = mode
58
+ @next_ecm_bmm = mode & ECM_BMM
59
+ @mode_read = mode & 1
60
+ @late_read = false
61
+ load(data, screencode, color)
62
+ (8 - shift).times { read_pixel }
63
+ end
64
+
65
+ # Draws one group, loading the byte at pixel shift.
66
+ def draw(data, screencode, color, shift, mode)
67
+ i = 0
68
+ while i < 8
69
+ step_mode(i, mode)
70
+ load(data, screencode, color) if i == shift
71
+ pixel = read_pixel
72
+ @colors[i] = pixel < @black_below ? 0 : lookup(pixel)
73
+ @black_below = 0
74
+ @fg[i] = pixel >= 2
75
+ i += 1
76
+ end
77
+ @next_ecm_bmm = mode & ECM_BMM
78
+ end
79
+
80
+ private
81
+
82
+ def step_mode(pixel, mode)
83
+ case pixel
84
+ when 0 then start_group
85
+ when 4 then step_lookup(mode)
86
+ when 5 then step_early_fall(mode)
87
+ when 6 then @mode_lookup &= mode | 1 if @latency
88
+ when 7 then step_read
89
+ end
90
+ end
91
+
92
+ def start_group
93
+ end_late_read
94
+ return if @latency
95
+
96
+ invalid = @mode_lookup > ECM
97
+ @mode_lookup = (@mode_lookup & ~ECM_BMM) | @next_ecm_bmm
98
+ @black_below = black_pixels_out_of_invalid if invalid
99
+ end
100
+
101
+ # The pixel values below which pixel 0 stays black as the group leaves
102
+ # an invalid mode: all four into hi-res text, the background ones into
103
+ # multicolour bitmap.
104
+ def black_pixels_out_of_invalid
105
+ case @mode_lookup
106
+ when 0 then 4
107
+ when MULTICOLOR_BITMAP then 2
108
+ else 0
109
+ end
110
+ end
111
+
112
+ def step_lookup(mode)
113
+ @late_mcm = @latency && @mode_lookup.allbits?(ECM_MCM) && mode.nobits?(1)
114
+ rising = @latency ? mode & ECM_BMM : 0
115
+ @mode_lookup = (@mode_lookup & ~1) | (mode & 1) | (@late_mcm ? 1 : 0) | rising
116
+ end
117
+
118
+ def step_early_fall(mode)
119
+ @mode_lookup &= ~1 if @late_mcm
120
+ @mode_lookup &= mode | ~BMM if @latency && @mode_lookup != BMM
121
+ end
122
+
123
+ def step_read
124
+ return @late_read = true if @late_mcm
125
+
126
+ mcm = @mode_lookup & 1
127
+ @flop = 0 if mcm == 1 && @mode_read.zero?
128
+ @mode_read = mcm
129
+ end
130
+
131
+ def end_late_read
132
+ return unless @late_read
133
+
134
+ @mode_read = 0
135
+ @late_read = false
136
+ end
137
+
138
+ def load(data, screencode, color)
139
+ @gbuf = data
140
+ @vbuf = screencode
141
+ @cbuf = color & 0x0f
142
+ @flop = 1
143
+ end
144
+
145
+ def read_pixel
146
+ multicolor = multicolor?
147
+ if @mode_read == 1 && multicolor
148
+ @pixel = @gbuf >> 6 if @flop == 1
149
+ elsif @gbuf.anybits?(0x80)
150
+ @pixel = multicolor && @mode_read.zero? ? 2 : 3
151
+ else
152
+ @pixel = 0
153
+ end
154
+ @gbuf = (@gbuf << 1) & 0xff
155
+ @flop ^= 1
156
+ @pixel
157
+ end
158
+
159
+ def multicolor? = @mode_lookup.anybits?(BMM) || @cbuf.anybits?(0x08)
160
+
161
+ def lookup(pixel)
162
+ case @mode_lookup
163
+ when 0 then pixel < 2 ? @registers.background : @cbuf
164
+ when 1 then pixel == 3 ? @cbuf & 0x07 : @registers.background(pixel)
165
+ when 2 then pixel < 2 ? @vbuf & 0x0f : @vbuf >> 4
166
+ when 3 then multicolor_bitmap(pixel)
167
+ when 4 then pixel < 2 ? @registers.background(@vbuf >> 6) : @cbuf
168
+ else 0
169
+ end
170
+ end
171
+
172
+ def multicolor_bitmap(pixel)
173
+ case pixel
174
+ when 0 then @registers.background
175
+ when 1 then @vbuf >> 4
176
+ when 2 then @vbuf & 0x0f
177
+ else @cbuf
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end