badline 0.12.1 → 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 (505) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -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 +3 -3
  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} +1 -1
  17. data/lib/badline/c128/bus.rb +18 -17
  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 +14 -9
  27. data/lib/badline/{computer → c64}/attachments.rb +4 -6
  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/{computer → c64}/common.rb +2 -2
  73. data/lib/badline/{computer → c64}/kernal_traps.rb +18 -18
  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 +11 -11
  82. data/lib/badline/{computer.rb → c64.rb} +18 -13
  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 +26 -28
  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 +3 -3
  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/load.rb +5 -5
  262. data/lib/badline/kernal_trap/save.rb +4 -4
  263. data/lib/badline/kernal_trap/serial.rb +7 -7
  264. data/lib/badline/kernal_trap.rb +1 -2
  265. data/lib/badline/machine/clocking.rb +1 -1
  266. data/lib/badline/machine.rb +5 -5
  267. data/lib/badline/media/true_drive.rb +1 -1
  268. data/lib/badline/media/tune.rb +2 -2
  269. data/lib/badline/media.rb +3 -3
  270. data/lib/badline/model.rb +1 -1
  271. data/lib/badline/roms/README +6 -6
  272. data/lib/badline/sdl.rb +1 -0
  273. data/lib/badline/{storage/sid_file.rb → sid_tune/file.rb} +3 -3
  274. data/lib/badline/{storage → sid_tune}/hvsc.rb +7 -7
  275. data/lib/badline/{storage → sid_tune}/song_lengths.rb +2 -2
  276. data/lib/badline/{storage → sid_tune}/stil/credit.rb +1 -1
  277. data/lib/badline/{storage → sid_tune}/stil.rb +3 -3
  278. data/lib/badline/sid_tune.rb +6 -0
  279. data/lib/badline/snapshot/c128_setup.rb +43 -0
  280. data/lib/badline/snapshot/c64_setup.rb +79 -0
  281. data/lib/badline/snapshot/image.rb +5 -25
  282. data/lib/badline/snapshot/machine_state.rb +1 -1
  283. data/lib/badline/snapshot/setup.rb +22 -66
  284. data/lib/badline/snapshot/state.rb +8 -18
  285. data/lib/badline/snapshot/storage_setup.rb +68 -0
  286. data/lib/badline/snapshot/vic20_setup.rb +37 -0
  287. data/lib/badline/snapshot/vice/c64_mem.rb +1 -1
  288. data/lib/badline/snapshot/vice/restore.rb +1 -1
  289. data/lib/badline/snapshot/vice/reu1764.rb +1 -1
  290. data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
  291. data/lib/badline/snapshot/vice.rb +7 -5
  292. data/lib/badline/snapshot.rb +3 -4
  293. data/lib/badline/storage/d64_image.rb +0 -2
  294. data/lib/badline/storage/d71_image.rb +0 -2
  295. data/lib/badline/storage/d81_image.rb +0 -2
  296. data/lib/badline/storage/disk_image.rb +3 -6
  297. data/lib/badline/storage/g64_image.rb +2 -2
  298. data/lib/badline/storage/host_directory.rb +0 -5
  299. data/lib/badline/storage/t64.rb +2 -8
  300. data/lib/badline/storage/unavailable.rb +1 -1
  301. data/lib/badline/storage.rb +0 -37
  302. data/lib/badline/support/c128_checkpoint.rb +39 -0
  303. data/lib/badline/support/checkpoint.rb +108 -0
  304. data/lib/badline/support/vic20_checkpoint.rb +38 -0
  305. data/lib/badline/support.rb +5 -0
  306. data/lib/badline/version.rb +1 -1
  307. data/lib/badline/vic20/attachments.rb +5 -5
  308. data/lib/badline/vic20/bus/saved_state.rb +35 -0
  309. data/lib/badline/vic20/bus.rb +3 -25
  310. data/lib/badline/vic20/cpu.rb +1 -1
  311. data/lib/badline/vic20/port_wiring.rb +4 -4
  312. data/lib/badline/vic20/saved_state.rb +16 -30
  313. data/lib/badline/vic20/user_via_ports.rb +2 -2
  314. data/lib/badline/vic20.rb +19 -14
  315. metadata +245 -221
  316. data/lib/badline/address_bus/extra_sids.rb +0 -30
  317. data/lib/badline/address_bus/fittings.rb +0 -38
  318. data/lib/badline/address_bus/pla.rb +0 -147
  319. data/lib/badline/address_bus/roms.rb +0 -39
  320. data/lib/badline/address_bus/saved_state.rb +0 -66
  321. data/lib/badline/address_bus/sid_slots.rb +0 -42
  322. data/lib/badline/address_bus.rb +0 -216
  323. data/lib/badline/cartridge/action_replay.rb +0 -126
  324. data/lib/badline/cartridge/atomic_power.rb +0 -24
  325. data/lib/badline/cartridge/bank.rb +0 -81
  326. data/lib/badline/cartridge/comal80.rb +0 -50
  327. data/lib/badline/cartridge/dinamic.rb +0 -34
  328. data/lib/badline/cartridge/easy_flash.rb +0 -145
  329. data/lib/badline/cartridge/epyx_fastload.rb +0 -79
  330. data/lib/badline/cartridge/final_cartridge3.rb +0 -89
  331. data/lib/badline/cartridge/flash.rb +0 -306
  332. data/lib/badline/cartridge/freezer.rb +0 -33
  333. data/lib/badline/cartridge/fun_play.rb +0 -38
  334. data/lib/badline/cartridge/g_mod2.rb +0 -74
  335. data/lib/badline/cartridge/game_system.rb +0 -40
  336. data/lib/badline/cartridge/geo_ram.rb +0 -79
  337. data/lib/badline/cartridge/kcs_power.rb +0 -75
  338. data/lib/badline/cartridge/mach5.rb +0 -32
  339. data/lib/badline/cartridge/magic_desk.rb +0 -30
  340. data/lib/badline/cartridge/ocean.rb +0 -35
  341. data/lib/badline/cartridge/pagefox.rb +0 -68
  342. data/lib/badline/cartridge/retro_replay.rb +0 -320
  343. data/lib/badline/cartridge/rex_utility.rb +0 -29
  344. data/lib/badline/cartridge/rgcd.rb +0 -58
  345. data/lib/badline/cartridge/simons_basic.rb +0 -35
  346. data/lib/badline/cartridge/standard.rb +0 -15
  347. data/lib/badline/cartridge/super_games.rb +0 -48
  348. data/lib/badline/cartridge/westermann.rb +0 -30
  349. data/lib/badline/cartridge/zaxxon.rb +0 -66
  350. data/lib/badline/cartridge.rb +0 -303
  351. data/lib/badline/checkpoint.rb +0 -98
  352. data/lib/badline/cia/fast_forward.rb +0 -60
  353. data/lib/badline/cia/interrupt_register.rb +0 -143
  354. data/lib/badline/cia/serial.rb +0 -275
  355. data/lib/badline/cia/state.rb +0 -47
  356. data/lib/badline/cia/timer.rb +0 -206
  357. data/lib/badline/cia.rb +0 -279
  358. data/lib/badline/color_memory.rb +0 -25
  359. data/lib/badline/control_ports.rb +0 -76
  360. data/lib/badline/cpu/addressing.rb +0 -131
  361. data/lib/badline/cpu/boundary.rb +0 -54
  362. data/lib/badline/cpu/core.rb +0 -165
  363. data/lib/badline/cpu/microcode.rb +0 -177
  364. data/lib/badline/cpu/operations.rb +0 -88
  365. data/lib/badline/cpu/saved_state.rb +0 -115
  366. data/lib/badline/cpu/stack_operations.rb +0 -82
  367. data/lib/badline/cpu.rb +0 -10
  368. data/lib/badline/cpu_port.rb +0 -112
  369. data/lib/badline/datasette.rb +0 -161
  370. data/lib/badline/drive/core.rb +0 -147
  371. data/lib/badline/drive/fast_serial.rb +0 -73
  372. data/lib/badline/drive/idle.rb +0 -125
  373. data/lib/badline/drive/idle_cpu.rb +0 -28
  374. data/lib/badline/drive/orbit.rb +0 -79
  375. data/lib/badline/drive/serial_lines.rb +0 -73
  376. data/lib/badline/drive/sleep.rb +0 -112
  377. data/lib/badline/drive/vias.rb +0 -84
  378. data/lib/badline/drive/watch.rb +0 -150
  379. data/lib/badline/drive.rb +0 -11
  380. data/lib/badline/drive1541/bus.rb +0 -86
  381. data/lib/badline/drive1541/byte_ready.rb +0 -48
  382. data/lib/badline/drive1541/cpu.rb +0 -11
  383. data/lib/badline/drive1541/disk.rb +0 -315
  384. data/lib/badline/drive1541/disk_state.rb +0 -86
  385. data/lib/badline/drive1541/disk_via.rb +0 -36
  386. data/lib/badline/drive1541/gcr.rb +0 -57
  387. data/lib/badline/drive1541/mechanism.rb +0 -313
  388. data/lib/badline/drive1541/mechanism_state.rb +0 -68
  389. data/lib/badline/drive1541/rotation.rb +0 -121
  390. data/lib/badline/drive1541/sector_reader.rb +0 -76
  391. data/lib/badline/drive1541/serial_port.rb +0 -18
  392. data/lib/badline/drive1541/track.rb +0 -98
  393. data/lib/badline/drive1541.rb +0 -111
  394. data/lib/badline/drive1571/bus.rb +0 -111
  395. data/lib/badline/drive1571/cpu.rb +0 -11
  396. data/lib/badline/drive1571/serial_port.rb +0 -37
  397. data/lib/badline/drive1571/serial_via.rb +0 -25
  398. data/lib/badline/drive1571/wd1770.rb +0 -120
  399. data/lib/badline/drive1571.rb +0 -175
  400. data/lib/badline/drive1581/bus.rb +0 -137
  401. data/lib/badline/drive1581/cpu.rb +0 -11
  402. data/lib/badline/drive1581/disk.rb +0 -135
  403. data/lib/badline/drive1581/disk_state.rb +0 -87
  404. data/lib/badline/drive1581/mechanism.rb +0 -117
  405. data/lib/badline/drive1581/serial_port.rb +0 -52
  406. data/lib/badline/drive1581/slot.rb +0 -78
  407. data/lib/badline/drive1581/track.rb +0 -100
  408. data/lib/badline/drive1581/track_bytes.rb +0 -75
  409. data/lib/badline/drive1581/wd1772/registers.rb +0 -89
  410. data/lib/badline/drive1581/wd1772/sector_writes.rb +0 -73
  411. data/lib/badline/drive1581/wd1772/sectors.rb +0 -150
  412. data/lib/badline/drive1581/wd1772/state.rb +0 -66
  413. data/lib/badline/drive1581/wd1772/stepping.rb +0 -109
  414. data/lib/badline/drive1581/wd1772/tracks.rb +0 -125
  415. data/lib/badline/drive1581/wd1772/turn.rb +0 -73
  416. data/lib/badline/drive1581/wd1772.rb +0 -216
  417. data/lib/badline/drive1581.rb +0 -233
  418. data/lib/badline/iec_bus.rb +0 -159
  419. data/lib/badline/instruction.rb +0 -334
  420. data/lib/badline/instruction_set/arithmetic.rb +0 -114
  421. data/lib/badline/instruction_set/bitwise.rb +0 -126
  422. data/lib/badline/instruction_set/branch.rb +0 -79
  423. data/lib/badline/instruction_set/flag.rb +0 -63
  424. data/lib/badline/instruction_set/illegal.rb +0 -270
  425. data/lib/badline/instruction_set/inc_dec.rb +0 -69
  426. data/lib/badline/instruction_set/stack.rb +0 -52
  427. data/lib/badline/instruction_set/transfer.rb +0 -137
  428. data/lib/badline/instruction_set.rb +0 -55
  429. data/lib/badline/interrupts.rb +0 -104
  430. data/lib/badline/joystick.rb +0 -25
  431. data/lib/badline/kernal_trap/channel.rb +0 -181
  432. data/lib/badline/keyboard.rb +0 -112
  433. data/lib/badline/ram_expansion/banking.rb +0 -30
  434. data/lib/badline/ram_expansion/plus256k.rb +0 -54
  435. data/lib/badline/ram_expansion/plus60k.rb +0 -43
  436. data/lib/badline/ram_expansion/unexpanded.rb +0 -28
  437. data/lib/badline/ram_expansion.rb +0 -21
  438. data/lib/badline/reu/dma/saved_state.rb +0 -50
  439. data/lib/badline/reu/dma.rb +0 -273
  440. data/lib/badline/reu/ram.rb +0 -107
  441. data/lib/badline/reu/saved_state.rb +0 -80
  442. data/lib/badline/reu/trigger.rb +0 -32
  443. data/lib/badline/reu.rb +0 -289
  444. data/lib/badline/sid/catch_up.rb +0 -120
  445. data/lib/badline/sid/decimator.rb +0 -64
  446. data/lib/badline/sid/envelope/state.rb +0 -68
  447. data/lib/badline/sid/envelope.rb +0 -239
  448. data/lib/badline/sid/filter.rb +0 -263
  449. data/lib/badline/sid/voice.rb +0 -77
  450. data/lib/badline/sid/waveform/combined.rb +0 -126
  451. data/lib/badline/sid/waveform/fast_forward.rb +0 -105
  452. data/lib/badline/sid/waveform/noise_writeback.rb +0 -122
  453. data/lib/badline/sid/waveform/state.rb +0 -66
  454. data/lib/badline/sid/waveform.rb +0 -305
  455. data/lib/badline/sid.rb +0 -303
  456. data/lib/badline/time_of_day.rb +0 -228
  457. data/lib/badline/traps.rb +0 -19
  458. data/lib/badline/via/control_lines.rb +0 -122
  459. data/lib/badline/via/fast_forward.rb +0 -53
  460. data/lib/badline/via/interrupt_register.rb +0 -67
  461. data/lib/badline/via/shift_register.rb +0 -180
  462. data/lib/badline/via/state.rb +0 -42
  463. data/lib/badline/via/timer1.rb +0 -131
  464. data/lib/badline/via/timer2.rb +0 -133
  465. data/lib/badline/via.rb +0 -266
  466. data/lib/badline/vic/bank.rb +0 -133
  467. data/lib/badline/vic/border_mask.rb +0 -86
  468. data/lib/badline/vic/collisions.rb +0 -115
  469. data/lib/badline/vic/color_patches.rb +0 -47
  470. data/lib/badline/vic/display_state.rb +0 -185
  471. data/lib/badline/vic/graphics_mode.rb +0 -164
  472. data/lib/badline/vic/graphics_shifter.rb +0 -207
  473. data/lib/badline/vic/register_log.rb +0 -81
  474. data/lib/badline/vic/registers.rb +0 -195
  475. data/lib/badline/vic/sequencer.rb +0 -275
  476. data/lib/badline/vic/sequencer_output.rb +0 -116
  477. data/lib/badline/vic/sequencer_state.rb +0 -89
  478. data/lib/badline/vic/sprite/internal_bus.rb +0 -68
  479. data/lib/badline/vic/sprite/saved_state.rb +0 -64
  480. data/lib/badline/vic/sprite/shifter.rb +0 -146
  481. data/lib/badline/vic/sprite/timing.rb +0 -56
  482. data/lib/badline/vic/sprite.rb +0 -337
  483. data/lib/badline/vic/sprites.rb +0 -282
  484. data/lib/badline/vic/sprites_state.rb +0 -57
  485. data/lib/badline/vic.rb +0 -853
  486. data/lib/badline/vic20/sound/output.rb +0 -83
  487. data/lib/badline/vic20/sound.rb +0 -233
  488. data/lib/badline/z80/arithmetic.rb +0 -117
  489. data/lib/badline/z80/bit_page.rb +0 -55
  490. data/lib/badline/z80/block_io.rb +0 -58
  491. data/lib/badline/z80/block_transfers.rb +0 -59
  492. data/lib/badline/z80/bus_cycles.rb +0 -111
  493. data/lib/badline/z80/core.rb +0 -113
  494. data/lib/badline/z80/exchanges.rb +0 -50
  495. data/lib/badline/z80/extended_page.rb +0 -89
  496. data/lib/badline/z80/flags.rb +0 -37
  497. data/lib/badline/z80/interrupt_acceptance.rb +0 -46
  498. data/lib/badline/z80/jumps.rb +0 -82
  499. data/lib/badline/z80/loads.rb +0 -98
  500. data/lib/badline/z80/main_page.rb +0 -134
  501. data/lib/badline/z80/registers.rb +0 -120
  502. data/lib/badline/z80/saved_state.rb +0 -69
  503. data/lib/badline/z80/shifts.rb +0 -64
  504. data/lib/badline/z80.rb +0 -11
  505. /data/lib/badline/snapshot/{fields.rb → vice/fields.rb} +0 -0
@@ -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