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
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class CIA
6
+ # Running a CIA a stretch of cycles at once, for Drives::Engine::Idle.
7
+ module FastForward
8
+ # quiet_cycles for a CIA whose counters will never set a flag.
9
+ QUIET = 1 << 40
10
+
11
+ # Whether fast_forward can run the CIA: timer B stopped with nothing
12
+ # in its pipeline, no interrupt or acknowledge on its way, CNT where it
13
+ # was, the TOD clock stopped, and timer A either stopped, or free
14
+ # running (Timer#free_running?) with its interrupt masked and the
15
+ # serial port an idle input. Drives::Engine::Idle sleeps the 1571's CIA through
16
+ # such cycles, which its DOS leaves timer A running in.
17
+ def quiet?
18
+ return false unless @tb.idle? && @icr.quiet && @tod.quiet? && cnt_steady?
19
+
20
+ @ta.idle? ? @serial.idle : timer_a_free_running?
21
+ end
22
+
23
+ # How many cycles the CIA can run with nothing but its counters
24
+ # moving: as quiet? allows, but with timer B free running too, up to
25
+ # the cycle before it underflows. The 1581's DOS leaves timer B
26
+ # interrupting every 10 ms.
27
+ def quiet_cycles
28
+ return 0 unless @icr.quiet && @tod.quiet? && cnt_steady? && timer_a_quiet?
29
+ return QUIET if @tb.idle?
30
+ return 0 unless @tb.free_running? && @control_b.value.nobits?(0x60)
31
+
32
+ @tb.counter - 1
33
+ end
34
+
35
+ # Runs +cycles+ cycles at once while quiet? or for quiet_cycles, as
36
+ # cycle! would: timer A's underflows flag in the ICR, and reach the
37
+ # serial port's underflow line.
38
+ def fast_forward(cycles)
39
+ @tod.fast_forward(cycles)
40
+ @tb.fast_forward(cycles) unless @tb.idle?
41
+ return if @ta.idle?
42
+
43
+ @icr.flag(:timer_a) if @ta.fast_forward(cycles).positive?
44
+ @serial.follow_underflow(@ta.underflowed)
45
+ end
46
+
47
+ private
48
+
49
+ def timer_a_quiet? = @ta.idle? ? @serial.idle : timer_a_free_running?
50
+
51
+ # Timer A free running with its interrupt masked, and the serial port
52
+ # an idle input it only clocks.
53
+ def timer_a_free_running?
54
+ @ta.free_running? && !@control_a.serial_mode? && @icr.mask.value.nobits?(0x01) && @serial.drained?
55
+ end
56
+
57
+ # Whether CNT holds the level the last cycle sampled.
58
+ def cnt_steady? = @serial.cnt == @cnt_high && !@cnt_rise
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class CIA
6
+ # The interrupt control register: the source flags, their mask and the
7
+ # IR bit that drives the interrupt line, with the 6526's acknowledge
8
+ # timing.
9
+ class InterruptRegister
10
+ attr_reader :status, :mask, :quiet
11
+
12
+ # The 6526A is the faster of the two: see the rules below.
13
+ def initialize(model = :mos6526)
14
+ @fast = model == :mos6526a
15
+ @mask = InterruptFlags.new([:timer_a, :timer_b, :alarm, :serial, :flag, 0, 0, 0])
16
+ @status = InterruptFlags.new([:timer_a, :timer_b, :alarm, :serial, :flag, 0, 0, :interrupt])
17
+ @pending = 0
18
+ @read = @read_last_cycle = @read_two_cycles_ago = nil
19
+ @timer_b_bug = false
20
+ @quiet = true
21
+ end
22
+
23
+ # The CIA skips this while quiet: no read is recent enough to matter
24
+ # and no assert is due.
25
+ def cycle!
26
+ @read_two_cycles_ago = @read_last_cycle
27
+ @read_last_cycle = @read
28
+ @read = nil
29
+ if @pending.positive?
30
+ @pending -= 1
31
+ status.interrupt = true if @pending.zero?
32
+ end
33
+ @quiet = @pending.zero? && @read_last_cycle.nil? && @read_two_cycles_ago.nil?
34
+ end
35
+
36
+ def interrupted? = status.value >= 0x80
37
+
38
+ def save_state(out)
39
+ out.int(@mask.value).int(@status.value).int(@pending)
40
+ [@read, @read_last_cycle, @read_two_cycles_ago].each { |read| out.optional_int(read) }
41
+ out.boolean(@timer_b_bug).boolean(@quiet)
42
+ end
43
+
44
+ def load_state(input)
45
+ @mask.value = input.int
46
+ @status.value = input.int
47
+ @pending = input.int
48
+ @read = input.optional_int
49
+ @read_last_cycle = input.optional_int
50
+ @read_two_cycles_ago = input.optional_int
51
+ @timer_b_bug = input.boolean?
52
+ @quiet = input.boolean?
53
+ end
54
+
55
+ # Raises IR on this cycle.
56
+ def assert_now
57
+ status.interrupt = true
58
+ @pending = 0
59
+ end
60
+
61
+ # Schedules IR to rise after delay cycles, keeping an earlier one.
62
+ def assert!(delay = 1)
63
+ @pending = @pending.positive? ? [@pending, delay].min : delay
64
+ @quiet = false
65
+ end
66
+
67
+ # Latch a source, pulling the interrupt line if it is armed. The 6526
68
+ # raises IR a cycle after the flag. The 6526A raises it on the flag's
69
+ # own cycle, unless the ICR was read on the cycle before.
70
+ def flag(source)
71
+ bit = source_bit(source)
72
+ @status.value |= bit
73
+ return unless mask.value.anybits?(bit)
74
+
75
+ @fast && @read_last_cycle.nil? ? assert_now : assert!
76
+ end
77
+
78
+ # The 6526 timer B bug: an underflow on the cycle after a read still
79
+ # raises the flag, but the next read drops it unseen. The 6526A has
80
+ # no such bug.
81
+ def timer_b_underflow!
82
+ @timer_b_bug = !@fast && !@read_last_cycle.nil?
83
+ flag(:timer_b)
84
+ end
85
+
86
+ # A read releases the interrupt line at once, and cancels an assert
87
+ # due on the next cycle, but its acknowledge lands a cycle late. On
88
+ # the 6526 that holds only IR: the next cycle still reads IR set if it
89
+ # was set, or about to be. The 6526A reads an IR about to rise as set
90
+ # at once, and holds every bit it read: the next cycle reads them all
91
+ # again, along with anything flagged since.
92
+ def read
93
+ status.timer_b = false if @timer_b_bug
94
+ @timer_b_bug = false
95
+ value = status.value
96
+ value |= 0x80 if @fast && @pending == 1
97
+ @read = @pending == 1 ? value | 0x80 : value
98
+ @quiet = false
99
+ value |= held(@read_last_cycle) if @read_last_cycle
100
+ status.value = 0x0
101
+ @pending = 0
102
+ value
103
+ end
104
+
105
+ # Bit 7 picks between setting and clearing the mask bits given.
106
+ def write(value)
107
+ if value.nobits?(0x80)
108
+ @mask.value &= ~(value & 0x1f)
109
+ else
110
+ @mask.value |= (value & 0x1f)
111
+ end
112
+ if mask.value.anybits?(status.value & 0x1f)
113
+ assert!(arm_delay) unless interrupted?
114
+ elsif @pending == 1 && @read_two_cycles_ago
115
+ # On the 6526, masking the pending source cancels the assert due
116
+ # on the next cycle only while a read two cycles back is
117
+ # acknowledging.
118
+ @pending = 0
119
+ end
120
+ end
121
+
122
+ private
123
+
124
+ # Arming a pending source raises IR two cycles later on the 6526,
125
+ # and one cycle later on the 6526A.
126
+ def arm_delay = @fast ? 1 : 2
127
+
128
+ # What a read on the cycle before still holds: IR on the 6526, and
129
+ # every bit it read on the 6526A.
130
+ def held(last) = @fast ? last : last & 0x80
131
+
132
+ def source_bit(source)
133
+ case source
134
+ when :timer_a then 0x01
135
+ when :timer_b then 0x02
136
+ when :alarm then 0x04
137
+ when :serial then 0x08
138
+ when :flag then 0x10
139
+ else raise ArgumentError, "unknown interrupt source #{source}"
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class CIA
6
+ # A snapshot of the chip: everything it holds but its wiring, the ports,
7
+ # the PB4 and CNT levels, the timers, the interrupt register, the serial
8
+ # port and the TOD clock.
9
+ module SavedState
10
+ def save_state(out)
11
+ out.marker("CIA")
12
+ out.int(@data_port_a).int(@data_port_b).int(@data_dir_a).int(@data_dir_b)
13
+ out.boolean(@port_b4_high).boolean(@port_b4_driven_high).boolean(@cnt_high).boolean(@cnt_rise)
14
+ out.int(@control_a.value).int(@control_b.value)
15
+ @ta.save_state(out)
16
+ @tb.save_state(out)
17
+ @icr.save_state(out)
18
+ @serial.save_state(out)
19
+ @tod.save_state(out)
20
+ end
21
+
22
+ def load_state(input)
23
+ input.marker("CIA")
24
+ @data_port_a = input.int
25
+ @data_port_b = input.int
26
+ @data_dir_a = input.int
27
+ @data_dir_b = input.int
28
+ @port_b4_high = input.boolean?
29
+ @port_b4_driven_high = input.boolean?
30
+ @cnt_high = input.boolean?
31
+ @cnt_rise = input.boolean?
32
+ @control_a.value = input.int
33
+ @control_b.value = input.int
34
+ load_parts(input)
35
+ end
36
+
37
+ private
38
+
39
+ def load_parts(input)
40
+ @ta.load_state(input)
41
+ @tb.load_state(input)
42
+ @icr.load_state(input)
43
+ @serial.load_state(input)
44
+ @tod.load_state(input)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class CIA
6
+ class Serial
7
+ # The shift register's state for a snapshot.
8
+ module SavedState
9
+ def save_state(out)
10
+ out.int(@data).int(@shift).int(@steps).optional_int(@empty_in).optional_int(@busy_in)
11
+ out.boolean(@busy).boolean(@abandoned).optional_int(@pending).boolean(@underflow_high).boolean(@in_flight)
12
+ out.int(@flight_up).int(@flight_down).boolean(@idle)
13
+ [@cnt, @cnt_in, @sp_in, @sp_out].each { |level| out.boolean(level) }
14
+ end
15
+
16
+ def load_state(input)
17
+ @data = input.int
18
+ @shift = input.int
19
+ @steps = input.int
20
+ @empty_in = input.optional_int
21
+ @busy_in = input.optional_int
22
+ @busy = input.boolean?
23
+ @abandoned = input.boolean?
24
+ @pending = input.optional_int
25
+ load_lines(input)
26
+ end
27
+
28
+ private
29
+
30
+ def load_lines(input)
31
+ @underflow_high = input.boolean?
32
+ @in_flight = input.boolean?
33
+ @flight_up = input.int
34
+ @flight_down = input.int
35
+ @idle = input.boolean?
36
+ @cnt = input.boolean?
37
+ @cnt_in = input.boolean?
38
+ @sp_in = input.boolean?
39
+ @sp_out = input.boolean?
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,250 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/chips/cia/serial/saved_state"
4
+
5
+ module Badline
6
+ module Chips
7
+ class CIA
8
+ # The serial shift register and the CNT line that clocks it.
9
+ #
10
+ # With CRA bit 6 clear the port is an input: SP is sampled on every
11
+ # rising CNT edge, and the byte reaches the data register after eight of
12
+ # them. With the bit set the CIA drives CNT itself, toggling it on every
13
+ # timer A underflow, so a byte takes sixteen underflows to go out. CNT falls
14
+ # as each bit is put on SP, and rises again to clock it in.
15
+ #
16
+ # The register counts itself empty as soon as the eighth bit is on SP,
17
+ # fifteen underflows in: the serial flag follows a few cycles later
18
+ # rather than waiting for the sixteenth underflow, and a byte written
19
+ # from that point on goes out on the next one.
20
+ class Serial
21
+ include SavedState
22
+
23
+ BITS = 8
24
+
25
+ # A byte written to the data register reaches the shift register one
26
+ # cycle later. The empty countdown starts on the underflow that puts
27
+ # the eighth bit on SP and is decremented on that same cycle, so the
28
+ # flag lands four cycles after it.
29
+ LOAD_DELAY = 1
30
+ EMPTY_DELAY = 5
31
+ BUSY_DELAY = 5
32
+
33
+ # The logic watching the shift register runs a few cycles behind it,
34
+ # so the level saying a bit is still on its way out is scheduled
35
+ # through a delay line: a bit set at position 7 - n takes effect n
36
+ # cycles later. Putting a bit on SP raises the level after one cycle
37
+ # and drops it again after two before raising it for good after
38
+ # three; the eighth bit skips straight to the last of those. CNT
39
+ # rising over a bit lowers the level four cycles later.
40
+ IN_FLIGHT = 0x50
41
+ LAST_IN_FLIGHT = 0x10
42
+ BOUNCE = 0x20
43
+ SETTLED = 0x08
44
+
45
+ attr_reader :data, :sp_out, :cnt, :cnt_in, :idle
46
+ attr_accessor :sp_in
47
+
48
+ def initialize(control)
49
+ @control = control
50
+ @data = 0x0
51
+ @shift = 0x0
52
+ @steps = 0
53
+ @empty_in = nil
54
+ @busy_in = nil
55
+ @busy = false
56
+ @abandoned = false
57
+ @pending = nil
58
+ @underflow_high = false
59
+ @in_flight = false
60
+ @flight_up = 0x0
61
+ @flight_down = 0x0
62
+ @idle = true
63
+ # Nothing drives the user port, so both lines float high.
64
+ @cnt = true
65
+ @cnt_in = true
66
+ @sp_in = true
67
+ @sp_out = true
68
+ end
69
+
70
+ # The bits shifted so far, and the byte waiting to go out after the
71
+ # one shifting.
72
+ attr_reader :steps, :pending
73
+
74
+ def shift_register = @shift
75
+
76
+ # Sets the data register and the shift register, as a VICE snapshot
77
+ # gives them.
78
+ def restore_shift(data, shift)
79
+ @data = data
80
+ @shift = shift
81
+ end
82
+
83
+ def output?
84
+ @control.serial_mode?
85
+ end
86
+
87
+ # Whether nothing is counting down or in the delay lines, so only
88
+ # timer A's underflows reach the register.
89
+ def drained? = idle?
90
+
91
+ # Takes timer A's underflow line as cycle! would have left it, with
92
+ # +underflowed+ its level on the last cycle, for a CIA run without
93
+ # the register in use (CIA#fast_forward).
94
+ def follow_underflow(underflowed)
95
+ @underflow_high = underflowed
96
+ @idle = !underflowed
97
+ end
98
+
99
+ def cnt_in=(level)
100
+ @cnt_in = level
101
+ @cnt = level unless output?
102
+ end
103
+
104
+ def write(value)
105
+ @data = value
106
+ @pending = LOAD_DELAY
107
+ @idle = false
108
+ end
109
+
110
+ # Clocked every cycle with timer A's underflow line. Yields once the
111
+ # shift register reports itself empty, which it does without waiting
112
+ # for the underflow that raises CNT over the eighth bit.
113
+ def cycle!(underflowed)
114
+ return if @idle && !underflowed
115
+
116
+ shift(underflowed)
117
+ @pending -= 1 if @pending&.positive?
118
+ drain_flight
119
+ count_busy
120
+ @idle = !underflowed && idle?
121
+ return if @empty_in.nil?
122
+
123
+ @empty_in -= 1
124
+ return unless @empty_in.zero?
125
+
126
+ @empty_in = nil
127
+ @busy = false
128
+ yield
129
+ end
130
+
131
+ # Clocked by rising CNT edges while receiving. Yields once a whole
132
+ # byte has arrived.
133
+ def rising_edge!
134
+ return if output?
135
+
136
+ @shift = ((@shift << 1) | (@sp_in ? 1 : 0)) & 0xff
137
+ @steps += 1
138
+ return unless @steps == BITS
139
+
140
+ @steps = 0
141
+ @data = @shift
142
+ yield if block_given?
143
+ end
144
+
145
+ # A mode change drops the byte in flight and hands CNT back to
146
+ # whichever side drives it now, and yields: that byte counts as gone.
147
+ # Handing the port over as an input tears a transmission down, so a
148
+ # busy register reports it; the same change latches how far the bit
149
+ # in flight had got, and taking the port back reports that.
150
+ def reset!
151
+ abandoned = output? ? @abandoned : @busy
152
+ @abandoned = output? ? false : @in_flight
153
+ @in_flight = false
154
+ @steps = 0
155
+ @empty_in = nil
156
+ @busy_in = nil
157
+ @busy = false
158
+ @pending = nil
159
+ @cnt = output? || @cnt_in
160
+ yield if abandoned
161
+ end
162
+
163
+ private
164
+
165
+ # Without an underflow, a register with nothing counting down and
166
+ # nothing in the delay lines has nothing to do on a cycle.
167
+ def idle?
168
+ !@pending&.positive? && (@flight_up | @flight_down).zero? &&
169
+ @busy_in.nil? && @empty_in.nil?
170
+ end
171
+
172
+ # The shift register picks up a waiting byte whenever the underflow
173
+ # line is asserted, but every half-step after that needs a fresh edge
174
+ # on it. A zero latch holds the line down for good rather than
175
+ # pulsing it, so such a byte stops after its first bit and never
176
+ # reaches the data register.
177
+ def shift(underflowed)
178
+ edge = underflowed && !@underflow_high
179
+ @underflow_high = underflowed
180
+ clock(edge) if underflowed && output?
181
+ end
182
+
183
+ def clock(edge)
184
+ start if @steps <= 1
185
+ if @steps.zero?
186
+ @flight_down |= SETTLED
187
+ elsif edge || @steps == BITS * 2
188
+ half_step
189
+ end
190
+ end
191
+
192
+ def half_step
193
+ @steps -= 1
194
+ @cnt = @steps.even?
195
+ if @cnt
196
+ @flight_down |= SETTLED
197
+ else
198
+ shift_out
199
+ end
200
+ end
201
+
202
+ # The register reads as busy from a few cycles after the first bit
203
+ # reaches SP until it reports itself empty over the eighth.
204
+ def mark_busy
205
+ case @steps
206
+ when (BITS * 2) - 1 then @busy_in = BUSY_DELAY
207
+ when 1
208
+ @empty_in = EMPTY_DELAY
209
+ @busy_in = nil
210
+ end
211
+ end
212
+
213
+ def count_busy
214
+ return if @busy_in.nil?
215
+
216
+ @busy_in -= 1
217
+ return unless @busy_in.zero?
218
+
219
+ @busy_in = nil
220
+ @busy = true
221
+ end
222
+
223
+ def drain_flight
224
+ @in_flight = false if @flight_down.anybits?(0x80)
225
+ @flight_down = (@flight_down << 1) & 0xff
226
+ @in_flight = true if @flight_up.anybits?(0x80)
227
+ @flight_up = (@flight_up << 1) & 0xff
228
+ end
229
+
230
+ # A byte only moves out of the data register once the one before it
231
+ # has put its last bit on SP.
232
+ def start
233
+ return unless @pending&.zero?
234
+
235
+ @pending = nil
236
+ @shift = @data
237
+ @steps = BITS * 2
238
+ end
239
+
240
+ def shift_out
241
+ @sp_out = @shift.anybits?(0x80)
242
+ @shift = (@shift << 1) & 0xff
243
+ mark_busy
244
+ @flight_up |= @steps == 1 ? LAST_IN_FLIGHT : IN_FLIGHT
245
+ @flight_down |= BOUNCE
246
+ end
247
+ end
248
+ end
249
+ end
250
+ end