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,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class CPU
6
+ module Traps
7
+ def install_trap(addr, &handler)
8
+ (@traps ||= {})[addr] = handler
9
+ end
10
+
11
+ def remove_trap(addr)
12
+ @traps&.delete(addr)
13
+ end
14
+
15
+ private
16
+
17
+ def run_traps
18
+ @traps[@program_counter]&.call if @traps
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/chips/cpu/core"
4
+
5
+ module Badline
6
+ module Chips
7
+ # The C64's 6510, on the C64::Bus.
8
+ class CPU
9
+ include Core
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class SID
6
+ # Running the DSP over the cycles that have passed since it last caught
7
+ # up, in spans that fast-forward the voices and end on a whole cycle.
8
+ module CatchUp
9
+ private
10
+
11
+ # Runs the cycles that have passed, landing each queued write on the
12
+ # cycle the CPU wrote it on.
13
+ def catch_up
14
+ replayed = 0
15
+ i = 0
16
+ while i < @deferred_writes.length
17
+ cycle = @deferred_writes[i]
18
+ run(cycle - replayed)
19
+ replayed = cycle
20
+ apply_write(@deferred_writes[i + 1], @deferred_writes[i + 2])
21
+ i += 3
22
+ end
23
+ run(@pending_cycles - replayed)
24
+ @deferred_writes.clear
25
+ @pending_cycles = 0
26
+ end
27
+
28
+ def run(cycles)
29
+ while cycles != 0
30
+ span = span(cycles)
31
+ fast_forward(span - 1) if span > 1
32
+ clock!(span)
33
+ cycles -= span
34
+ end
35
+ end
36
+
37
+ # The longest stretch that can be fast-forwarded. A combined waveform
38
+ # feeding back into its own oscillator steps cycle by cycle, and a span
39
+ # never runs past an MSB rise that hard-syncs the next voice, so both
40
+ # land on a whole cycle.
41
+ def span(cycles)
42
+ return 1 if @stepped
43
+
44
+ span = @synthesizing ? synthesis_span(cycles) : cycles
45
+ return span unless @synced
46
+
47
+ span = sync_span(@waveform1, span)
48
+ span = sync_span(@waveform2, span)
49
+ sync_span(@waveform3, span)
50
+ end
51
+
52
+ # The filter steps at most @filter_chunk cycles at a time, and never
53
+ # across the end of a recorded sample.
54
+ def synthesis_span(cycles)
55
+ span = [cycles, @filter_chunk].min
56
+ return span unless @decimator
57
+
58
+ [@decimator.cycles_to_close, span].min
59
+ end
60
+
61
+ # Whether a span has to step, or watch for hard sync, only changes with
62
+ # a voice's control register.
63
+ def update_span_rules
64
+ @stepped = @voices.any? { |voice| voice.waveform.stepped?(@synthesizing) }
65
+ @synced = @voices.any? { |voice| voice.waveform.sync? }
66
+ end
67
+
68
+ def sync_span(waveform, span)
69
+ return span unless waveform.sync_dest.sync?
70
+
71
+ rise = waveform.cycles_to_msb_rise
72
+ rise && rise < span ? rise : span
73
+ end
74
+
75
+ # Unrolled over the three voices: the per-cycle block calls cost
76
+ # measurably on the synthesis path.
77
+ def fast_forward(cycles)
78
+ @voice1.fast_forward(cycles)
79
+ @voice2.fast_forward(cycles)
80
+ @voice3.fast_forward(cycles)
81
+ end
82
+
83
+ # The last cycle of a span, run whole. The filter integrates the span
84
+ # from the voices' output at its end.
85
+ def clock!(span)
86
+ @voice1.cycle!
87
+ @voice2.cycle!
88
+ @voice3.cycle!
89
+ @waveform1.synchronize!
90
+ @waveform2.synchronize!
91
+ @waveform3.synchronize!
92
+ return unless @synthesizing
93
+
94
+ @filter.cycle!(@voices, span)
95
+ record_sample(span) if @decimator
96
+ end
97
+
98
+ def record_sample(span)
99
+ sample = @decimator.push(current_sample, span)
100
+ return unless sample
101
+
102
+ @samples << sample
103
+ record_voices if @voice_samples
104
+ end
105
+
106
+ def record_voices
107
+ voice_samples = @voice_samples
108
+ voice_samples << (@voice1.output >> 7)
109
+ voice_samples << (@voice2.output >> 7)
110
+ voice_samples << (@voice3.output >> 7)
111
+ end
112
+
113
+ def current_sample
114
+ sample = @filter.output / SAMPLE_DIVISOR
115
+ return sample unless sample < -0x8000 || sample > 0x7fff
116
+
117
+ sample.clamp(-0x8000, 0x7fff)
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class SID
6
+ # Reduces the SID's one-sample-per-cycle stream to an audio rate by
7
+ # averaging each window. Point sampling would be cheaper, but the pulse
8
+ # and noise waveforms carry enough energy above the output Nyquist to
9
+ # alias audibly.
10
+ #
11
+ # A sample can stand for several cycles at once, when the DSP has run
12
+ # them as one step.
13
+ class Decimator
14
+ def initialize(clock_hz:, rate:)
15
+ @clock_hz = clock_hz
16
+ @rate = rate
17
+ @phase = 0
18
+ @sum = 0
19
+ @count = 0
20
+ @cycles_to_close = window_cycles
21
+ end
22
+
23
+ # Cycles until the current window closes, counting the next one as 1.
24
+ attr_reader :cycles_to_close
25
+
26
+ # How far the current window has got. The clock and the rate are the
27
+ # host's.
28
+ def save_state(out)
29
+ out.int(@phase).int(@sum).int(@count).int(@cycles_to_close)
30
+ end
31
+
32
+ def load_state(input)
33
+ @phase = input.int
34
+ @sum = input.int
35
+ @count = input.int
36
+ @cycles_to_close = input.int
37
+ end
38
+
39
+ # Returns the averaged sample when these cycles close a window, and
40
+ # nil otherwise. They must not run past the window's end.
41
+ def push(sample, cycles = 1)
42
+ @sum += sample * cycles
43
+ @count += cycles
44
+ @phase += @rate * cycles
45
+ @cycles_to_close -= cycles
46
+ return unless @phase >= @clock_hz
47
+
48
+ @phase -= @clock_hz
49
+ @cycles_to_close = window_cycles
50
+ average
51
+ end
52
+
53
+ private
54
+
55
+ def window_cycles = (@clock_hz - @phase + @rate - 1) / @rate
56
+
57
+ def average
58
+ value = @sum.fdiv(@count).round
59
+ @sum = 0
60
+ @count = 0
61
+ value
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class SID
6
+ class Envelope
7
+ # A snapshot of an envelope: its rates, the gate, the state and the
8
+ # counters and pipelines between them, and the same fields as reSID
9
+ # keeps them, for VICE's SIDEXTENDED module.
10
+ module SavedState
11
+ # The fields reSID keeps for an envelope between cycles: the rate and
12
+ # exponential counters, the level, the state as an index into STATES,
13
+ # whether it holds at zero, the two periods and the pipeline.
14
+ def resid_fields
15
+ [@rate_counter, @exponential_counter, @counter, STATES.index(@state).to_i, @hold_zero ? 1 : 0,
16
+ @rate_period, @exponential_period, @envelope_pipeline]
17
+ end
18
+
19
+ # Takes the fields resid_fields gives from `fields`, from `at` on.
20
+ def restore_resid_fields(fields, at)
21
+ @rate_counter = fields[at]
22
+ @exponential_counter = fields[at + 1]
23
+ @counter = @env3 = fields[at + 2]
24
+ state = fields[at + 3]
25
+ @state = @next_state = STATES.fetch(state.clamp(0, STATES.length - 1)).to_sym
26
+ @hold_zero = fields[at + 4] != 0
27
+ @rate_period = fields[at + 5]
28
+ @exponential_period = fields[at + 6]
29
+ @envelope_pipeline = fields[at + 7]
30
+ end
31
+
32
+ def save_state(out)
33
+ [@attack, @decay, @sustain, @release].each { |rate| out.int(rate) }
34
+ out.boolean(@gate).int(STATES.index(@state)).int(STATES.index(@next_state))
35
+ out.int(@counter).int(@env3).int(@rate_counter).int(@rate_period).boolean(@reset_rate_counter)
36
+ out.int(@exponential_counter).int(@exponential_period)
37
+ out.int(@state_pipeline).int(@envelope_pipeline).int(@exponential_pipeline).boolean(@hold_zero)
38
+ end
39
+
40
+ def load_state(input)
41
+ @attack = input.int
42
+ @decay = input.int
43
+ @sustain = input.int
44
+ @release = input.int
45
+ @gate = input.boolean?
46
+ @state = STATES.fetch(input.int).to_sym
47
+ @next_state = STATES.fetch(input.int).to_sym
48
+ load_counters(input)
49
+ end
50
+
51
+ private
52
+
53
+ def load_counters(input)
54
+ @counter = input.int
55
+ @env3 = input.int
56
+ @rate_counter = input.int
57
+ @rate_period = input.int
58
+ @reset_rate_counter = input.boolean?
59
+ @exponential_counter = input.int
60
+ @exponential_period = input.int
61
+ @state_pipeline = input.int
62
+ @envelope_pipeline = input.int
63
+ @exponential_pipeline = input.int
64
+ @hold_zero = input.boolean?
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,241 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/chips/sid/envelope/saved_state"
4
+
5
+ module Badline
6
+ module Chips
7
+ class SID
8
+ # ADSR envelope generator.
9
+ #
10
+ # A 15-bit rate counter divides the 1 MHz clock down to one envelope step
11
+ # per period. Attack steps linearly; decay and release run through a
12
+ # second, level-dependent divider that approximates an exponential
13
+ # curve.
14
+ #
15
+ # Each stage runs a cycle or more behind the one feeding it, after
16
+ # reSID 1.0's single-cycle pipeline: the rate counter resets the cycle
17
+ # after it matches, the envelope counter steps two cycles after that,
18
+ # and a gate edge only switches the rate over on its second cycle.
19
+ class Envelope
20
+ # Rate counter comparison values for each ADSR nibble. The counter
21
+ # takes a cycle to reset, so the period is one cycle longer (2ms to
22
+ # 8s over the attack range).
23
+ PERIODS = [8, 31, 62, 94, 148, 219, 266, 312,
24
+ 391, 976, 1953, 3125, 3906, 11_719, 19_531, 31_250].freeze
25
+
26
+ # Envelope levels where the exponential divider changes, and the
27
+ # divider it changes to.
28
+ EXPONENTIAL_PERIODS = { 0xff => 1, 0x5d => 2, 0x36 => 4, 0x1a => 8,
29
+ 0x0e => 16, 0x06 => 30, 0x00 => 1 }.freeze
30
+
31
+ # The states a snapshot names by index.
32
+ STATES = %i[attack decay_sustain release].freeze
33
+
34
+ include SavedState
35
+
36
+ attr_reader :state, :counter, :env3
37
+
38
+ def initialize
39
+ @attack = @decay = @sustain = @release = 0x0
40
+ @gate = false
41
+ @state = @next_state = :release
42
+ @counter = @env3 = 0x00
43
+ @rate_counter = 0
44
+ @rate_period = PERIODS[0]
45
+ @reset_rate_counter = false
46
+ @exponential_counter = 0
47
+ @exponential_period = 1
48
+ @state_pipeline = @envelope_pipeline = @exponential_pipeline = 0
49
+ @hold_zero = true
50
+ end
51
+
52
+ def output = @counter
53
+
54
+ # The gate edge switches the state over two cycles. Rising, it runs
55
+ # the decay rate for the first of them. The rate counter is left
56
+ # running, so the first step lands somewhere inside the current
57
+ # period.
58
+ def control=(value)
59
+ gate = value.anybits?(0x01)
60
+ return if gate == @gate
61
+
62
+ @gate = gate
63
+ gate ? gate_on : gate_off
64
+ end
65
+
66
+ def attack_decay=(value)
67
+ @attack = (value >> 4) & 0x0f
68
+ @decay = value & 0x0f
69
+ @rate_period = PERIODS[@attack] if @state == :attack
70
+ @rate_period = PERIODS[@decay] if @state == :decay_sustain
71
+ end
72
+
73
+ def sustain_release=(value)
74
+ @sustain = (value >> 4) & 0x0f
75
+ @release = value & 0x0f
76
+ @rate_period = PERIODS[@release] if @state == :release
77
+ end
78
+
79
+ # ENV3 reads the counter as it stood at the start of the cycle.
80
+ #
81
+ # Lowering the rate period below the current counter sends it the long
82
+ # way round through 2^15 before the envelope can step, the ADSR delay
83
+ # bug that hard restarts rely on. Counting from 0x7fff wraps to 1.
84
+ def cycle!
85
+ @env3 = @counter
86
+ run_pipeline if pipelined?
87
+ return @reset_rate_counter = true if @rate_counter == @rate_period
88
+
89
+ @rate_counter += 1
90
+ @rate_counter = 1 if @rate_counter == 0x8000
91
+ end
92
+
93
+ # Runs `cycles` cycles as #cycle! would. Between steps only the rate
94
+ # counter moves, so it jumps from one match to the next and the cycles
95
+ # around each step run whole. Frozen at zero, a period changes
96
+ # nothing, so whole periods are counted off at once.
97
+ def fast_forward(cycles)
98
+ while cycles.positive?
99
+ if pipelined?
100
+ cycle!
101
+ cycles -= 1
102
+ next
103
+ end
104
+
105
+ @env3 = @counter
106
+ idle = cycles_to_match
107
+ return advance_rate_counter(cycles) if cycles < idle
108
+
109
+ advance_rate_counter(idle)
110
+ cycles = skip_frozen_periods(cycles - idle)
111
+ end
112
+ end
113
+
114
+ private
115
+
116
+ def land_step
117
+ @envelope_pipeline -= 1
118
+ step if @envelope_pipeline.zero? && !@hold_zero
119
+ end
120
+
121
+ def gate_on
122
+ @next_state = :attack
123
+ @state = :decay_sustain
124
+ @rate_period = PERIODS[@decay]
125
+ @state_pipeline = 2
126
+ if @reset_rate_counter || @exponential_pipeline == 2
127
+ @envelope_pipeline = @exponential_period == 1 || @exponential_pipeline == 2 ? 2 : 4
128
+ elsif @exponential_pipeline == 1
129
+ @state_pipeline = 3
130
+ end
131
+ end
132
+
133
+ def gate_off
134
+ @next_state = :release
135
+ @state_pipeline = @envelope_pipeline.positive? ? 3 : 2
136
+ end
137
+
138
+ def state_change
139
+ @state_pipeline -= 1
140
+ if @next_state == :attack
141
+ enter_attack if @state_pipeline.zero?
142
+ elsif (@state == :attack && @state_pipeline.zero?) ||
143
+ (@state == :decay_sustain && @state_pipeline == 1)
144
+ @state = :release
145
+ @rate_period = PERIODS[@release]
146
+ end
147
+ end
148
+
149
+ def enter_attack
150
+ @state = :attack
151
+ @rate_period = PERIODS[@attack]
152
+ @hold_zero = false
153
+ end
154
+
155
+ # The first attack step also resets the exponential divider.
156
+ def reset_rate_counter
157
+ @rate_counter = 0
158
+ @reset_rate_counter = false
159
+ if @state == :attack
160
+ @exponential_counter = 0
161
+ @envelope_pipeline = 2
162
+ elsif !@hold_zero && (@exponential_counter += 1) == @exponential_period
163
+ @exponential_pipeline = @exponential_period == 1 ? 1 : 2
164
+ end
165
+ end
166
+
167
+ def exponential_step
168
+ @exponential_counter = 0
169
+ return unless @state == :release || (@state == :decay_sustain && @counter != sustain_level)
170
+
171
+ @envelope_pipeline = 1
172
+ end
173
+
174
+ def pipelined?
175
+ @reset_rate_counter || (@state_pipeline | @envelope_pipeline | @exponential_pipeline) != 0
176
+ end
177
+
178
+ def run_pipeline
179
+ state_change if @state_pipeline.positive?
180
+ land_step if @envelope_pipeline.positive?
181
+ if @exponential_pipeline.positive? && (@exponential_pipeline -= 1).zero?
182
+ exponential_step
183
+ elsif @reset_rate_counter
184
+ reset_rate_counter
185
+ end
186
+ end
187
+
188
+ # Cycles that only count before the rate counter matches its period.
189
+ def cycles_to_match
190
+ return @rate_period - @rate_counter if @rate_counter <= @rate_period
191
+
192
+ 0x7fff - @rate_counter + @rate_period
193
+ end
194
+
195
+ def advance_rate_counter(cycles)
196
+ @rate_counter += cycles
197
+ @rate_counter -= 0x7fff if @rate_counter > 0x7fff
198
+ end
199
+
200
+ # With the counter on its period, a frozen envelope comes back to the
201
+ # same state every period plus one cycles. Otherwise the next cycle
202
+ # starts a step.
203
+ def skip_frozen_periods(cycles)
204
+ cycles %= @rate_period + 1 if @hold_zero && @state != :attack
205
+ return cycles unless cycles.positive?
206
+
207
+ cycle!
208
+ cycles - 1
209
+ end
210
+
211
+ def step
212
+ if @state == :attack
213
+ attack_step
214
+ else
215
+ @counter = (@counter - 1) & 0xff
216
+ end
217
+ set_exponential_period
218
+ end
219
+
220
+ def attack_step
221
+ @counter = (@counter + 1) & 0xff
222
+ return unless @counter == 0xff
223
+
224
+ @state = :decay_sustain
225
+ @rate_period = PERIODS[@decay]
226
+ end
227
+
228
+ def sustain_level = (@sustain << 4) | @sustain
229
+
230
+ # Reaching zero freezes the envelope until the gate is raised again.
231
+ def set_exponential_period
232
+ period = EXPONENTIAL_PERIODS[@counter]
233
+ return unless period
234
+
235
+ @exponential_period = period
236
+ @hold_zero = true if @counter.zero?
237
+ end
238
+ end
239
+ end
240
+ end
241
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class SID
6
+ class Filter
7
+ # The filter's state for a snapshot.
8
+ module SavedState
9
+ # The registers as the filter decoded them and its integrators. The
10
+ # W0 table is the model's.
11
+ def save_state(out)
12
+ out.int(@cutoff).int(@routing).int(@mode).int(@volume).boolean(@voice3_off).int(@w0).int(@resonance)
13
+ [@highpass, @bandpass, @lowpass, @unfiltered, @input].each { |value| out.int(value) }
14
+ @external.save_state(out)
15
+ end
16
+
17
+ def load_state(input)
18
+ @cutoff = input.int
19
+ @routing = input.int
20
+ @mode = input.int
21
+ @volume = input.int
22
+ @voice3_off = input.boolean?
23
+ @w0 = input.int
24
+ @resonance = input.int
25
+ load_integrators(input)
26
+ end
27
+
28
+ private
29
+
30
+ def load_integrators(input)
31
+ @highpass = input.int
32
+ @bandpass = input.int
33
+ @lowpass = input.int
34
+ @unfiltered = input.int
35
+ @input = input.int
36
+ @external.load_state(input)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end