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
@@ -1,239 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "badline/sid/envelope/state"
4
-
5
- module Badline
6
- class SID
7
- # ADSR envelope generator.
8
- #
9
- # A 15-bit rate counter divides the 1 MHz clock down to one envelope step
10
- # per period. Attack steps linearly; decay and release run through a
11
- # second, level-dependent divider that approximates an exponential
12
- # curve.
13
- #
14
- # Each stage runs a cycle or more behind the one feeding it, after
15
- # reSID 1.0's single-cycle pipeline: the rate counter resets the cycle
16
- # after it matches, the envelope counter steps two cycles after that,
17
- # and a gate edge only switches the rate over on its second cycle.
18
- class Envelope
19
- # Rate counter comparison values for each ADSR nibble. The counter
20
- # takes a cycle to reset, so the period is one cycle longer (2ms to
21
- # 8s over the attack range).
22
- PERIODS = [8, 31, 62, 94, 148, 219, 266, 312,
23
- 391, 976, 1953, 3125, 3906, 11_719, 19_531, 31_250].freeze
24
-
25
- # Envelope levels where the exponential divider changes, and the
26
- # divider it changes to.
27
- EXPONENTIAL_PERIODS = { 0xff => 1, 0x5d => 2, 0x36 => 4, 0x1a => 8,
28
- 0x0e => 16, 0x06 => 30, 0x00 => 1 }.freeze
29
-
30
- # The states a snapshot names by index.
31
- STATES = %i[attack decay_sustain release].freeze
32
-
33
- include State
34
-
35
- attr_reader :state, :counter, :env3
36
-
37
- def initialize
38
- @attack = @decay = @sustain = @release = 0x0
39
- @gate = false
40
- @state = @next_state = :release
41
- @counter = @env3 = 0x00
42
- @rate_counter = 0
43
- @rate_period = PERIODS[0]
44
- @reset_rate_counter = false
45
- @exponential_counter = 0
46
- @exponential_period = 1
47
- @state_pipeline = @envelope_pipeline = @exponential_pipeline = 0
48
- @hold_zero = true
49
- end
50
-
51
- def output = @counter
52
-
53
- # The gate edge switches the state over two cycles. Rising, it runs
54
- # the decay rate for the first of them. The rate counter is left
55
- # running, so the first step lands somewhere inside the current
56
- # period.
57
- def control=(value)
58
- gate = value.anybits?(0x01)
59
- return if gate == @gate
60
-
61
- @gate = gate
62
- gate ? gate_on : gate_off
63
- end
64
-
65
- def attack_decay=(value)
66
- @attack = (value >> 4) & 0x0f
67
- @decay = value & 0x0f
68
- @rate_period = PERIODS[@attack] if @state == :attack
69
- @rate_period = PERIODS[@decay] if @state == :decay_sustain
70
- end
71
-
72
- def sustain_release=(value)
73
- @sustain = (value >> 4) & 0x0f
74
- @release = value & 0x0f
75
- @rate_period = PERIODS[@release] if @state == :release
76
- end
77
-
78
- # ENV3 reads the counter as it stood at the start of the cycle.
79
- #
80
- # Lowering the rate period below the current counter sends it the long
81
- # way round through 2^15 before the envelope can step, the ADSR delay
82
- # bug that hard restarts rely on. Counting from 0x7fff wraps to 1.
83
- def cycle!
84
- @env3 = @counter
85
- run_pipeline if pipelined?
86
- return @reset_rate_counter = true if @rate_counter == @rate_period
87
-
88
- @rate_counter += 1
89
- @rate_counter = 1 if @rate_counter == 0x8000
90
- end
91
-
92
- # Runs `cycles` cycles as #cycle! would. Between steps only the rate
93
- # counter moves, so it jumps from one match to the next and the cycles
94
- # around each step run whole. Frozen at zero, a period changes
95
- # nothing, so whole periods are counted off at once.
96
- def fast_forward(cycles)
97
- while cycles.positive?
98
- if pipelined?
99
- cycle!
100
- cycles -= 1
101
- next
102
- end
103
-
104
- @env3 = @counter
105
- idle = cycles_to_match
106
- return advance_rate_counter(cycles) if cycles < idle
107
-
108
- advance_rate_counter(idle)
109
- cycles = skip_frozen_periods(cycles - idle)
110
- end
111
- end
112
-
113
- private
114
-
115
- def land_step
116
- @envelope_pipeline -= 1
117
- step if @envelope_pipeline.zero? && !@hold_zero
118
- end
119
-
120
- def gate_on
121
- @next_state = :attack
122
- @state = :decay_sustain
123
- @rate_period = PERIODS[@decay]
124
- @state_pipeline = 2
125
- if @reset_rate_counter || @exponential_pipeline == 2
126
- @envelope_pipeline = @exponential_period == 1 || @exponential_pipeline == 2 ? 2 : 4
127
- elsif @exponential_pipeline == 1
128
- @state_pipeline = 3
129
- end
130
- end
131
-
132
- def gate_off
133
- @next_state = :release
134
- @state_pipeline = @envelope_pipeline.positive? ? 3 : 2
135
- end
136
-
137
- def state_change
138
- @state_pipeline -= 1
139
- if @next_state == :attack
140
- enter_attack if @state_pipeline.zero?
141
- elsif (@state == :attack && @state_pipeline.zero?) ||
142
- (@state == :decay_sustain && @state_pipeline == 1)
143
- @state = :release
144
- @rate_period = PERIODS[@release]
145
- end
146
- end
147
-
148
- def enter_attack
149
- @state = :attack
150
- @rate_period = PERIODS[@attack]
151
- @hold_zero = false
152
- end
153
-
154
- # The first attack step also resets the exponential divider.
155
- def reset_rate_counter
156
- @rate_counter = 0
157
- @reset_rate_counter = false
158
- if @state == :attack
159
- @exponential_counter = 0
160
- @envelope_pipeline = 2
161
- elsif !@hold_zero && (@exponential_counter += 1) == @exponential_period
162
- @exponential_pipeline = @exponential_period == 1 ? 1 : 2
163
- end
164
- end
165
-
166
- def exponential_step
167
- @exponential_counter = 0
168
- return unless @state == :release || (@state == :decay_sustain && @counter != sustain_level)
169
-
170
- @envelope_pipeline = 1
171
- end
172
-
173
- def pipelined?
174
- @reset_rate_counter || (@state_pipeline | @envelope_pipeline | @exponential_pipeline) != 0
175
- end
176
-
177
- def run_pipeline
178
- state_change if @state_pipeline.positive?
179
- land_step if @envelope_pipeline.positive?
180
- if @exponential_pipeline.positive? && (@exponential_pipeline -= 1).zero?
181
- exponential_step
182
- elsif @reset_rate_counter
183
- reset_rate_counter
184
- end
185
- end
186
-
187
- # Cycles that only count before the rate counter matches its period.
188
- def cycles_to_match
189
- return @rate_period - @rate_counter if @rate_counter <= @rate_period
190
-
191
- 0x7fff - @rate_counter + @rate_period
192
- end
193
-
194
- def advance_rate_counter(cycles)
195
- @rate_counter += cycles
196
- @rate_counter -= 0x7fff if @rate_counter > 0x7fff
197
- end
198
-
199
- # With the counter on its period, a frozen envelope comes back to the
200
- # same state every period plus one cycles. Otherwise the next cycle
201
- # starts a step.
202
- def skip_frozen_periods(cycles)
203
- cycles %= @rate_period + 1 if @hold_zero && @state != :attack
204
- return cycles unless cycles.positive?
205
-
206
- cycle!
207
- cycles - 1
208
- end
209
-
210
- def step
211
- if @state == :attack
212
- attack_step
213
- else
214
- @counter = (@counter - 1) & 0xff
215
- end
216
- set_exponential_period
217
- end
218
-
219
- def attack_step
220
- @counter = (@counter + 1) & 0xff
221
- return unless @counter == 0xff
222
-
223
- @state = :decay_sustain
224
- @rate_period = PERIODS[@decay]
225
- end
226
-
227
- def sustain_level = (@sustain << 4) | @sustain
228
-
229
- # Reaching zero freezes the envelope until the gate is raised again.
230
- def set_exponential_period
231
- period = EXPONENTIAL_PERIODS[@counter]
232
- return unless period
233
-
234
- @exponential_period = period
235
- @hold_zero = true if @counter.zero?
236
- end
237
- end
238
- end
239
- end
@@ -1,263 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class SID
5
- # The SID's multimode filter: a state-variable design integrating low-,
6
- # band- and high-pass in parallel, with the mixer and master volume on
7
- # its output, and the C64 board's own RC network after that.
8
- #
9
- # Voices are routed through it or around it per the RES/FILT register,
10
- # and the outputs selected by MODE/VOL are summed back together with the
11
- # unfiltered ones.
12
- class Filter
13
- # Cutoff frequency in Hz at each chip's breakpoints. The 6581 curve was
14
- # sampled from a real chip by reSID and bends sharply around $300; the
15
- # 8580's is close to a straight line from 0 to 12.5 kHz. The curve
16
- # between breakpoints is interpolated linearly; reSID fits a spline, so
17
- # the two differ by a few Hz mid-segment.
18
- CUTOFF_POINTS = {
19
- mos6581: [[0, 220], [128, 230], [256, 250], [384, 300],
20
- [512, 420], [640, 780], [768, 1600], [832, 2300],
21
- [896, 3200], [960, 4300], [1024, 5000], [1088, 5400],
22
- [1152, 5800], [1216, 6000], [1280, 6200], [1344, 6400],
23
- [1408, 6600], [1472, 6800], [1536, 7000], [1600, 7200],
24
- [1664, 7400], [1728, 7600], [1792, 7800], [1856, 8000],
25
- [1920, 8200], [1984, 8400], [2047, 8600]].freeze,
26
- mos8580: [[0, 0], [128, 800], [256, 1600], [384, 2500],
27
- [512, 3300], [640, 4100], [768, 4800], [896, 5600],
28
- [1024, 6500], [1152, 7500], [1280, 8400], [1408, 9200],
29
- [1536, 9800], [1664, 10_500], [1792, 11_000],
30
- [1920, 11_700], [2047, 12_500]].freeze
31
- }.freeze
32
-
33
- # 2^20 / 1 MHz, so one cycle of integration is a plain shift.
34
- SCALE = (2**20) / 1_000_000.0
35
-
36
- # The integrator goes unstable above ~16 kHz at a one-cycle step.
37
- W0_MAX = (2 * Math::PI * 16_000 * SCALE).to_i
38
-
39
- # A step of several cycles scales w0 by their count. reSID keeps such
40
- # a step stable by capping the cutoff at 4 kHz over 8 cycles; this is
41
- # the same bound on the product, so a single cycle is never capped.
42
- W0_STEP_MAX = (2 * Math::PI * 4_000 * 8 * SCALE).to_i
43
-
44
- def self.build_w0(points)
45
- table = Array.new(2048)
46
- points.each_cons(2) do |(fc0, hz0), (fc1, hz1)|
47
- (fc0..fc1).each do |register|
48
- hz = hz0 + (((hz1 - hz0) * (register - fc0)).to_f / (fc1 - fc0))
49
- table[register] = [(2 * Math::PI * hz * SCALE).to_i, W0_MAX].min
50
- end
51
- end
52
- table.freeze
53
- end
54
- private_class_method :build_w0
55
-
56
- W0 = CUTOFF_POINTS.transform_values { |points| build_w0(points) }.freeze
57
-
58
- # 1024/Q, with Q sweeping from 0.707 up to 1.707 across the register.
59
- RESONANCE = (0x0..0xf).map { |res| (1024.0 / (0.707 + (res / 15.0))).to_i }.freeze
60
-
61
- # The mixer's own input DC offset, derived by reSID from the 6581's
62
- # zero-volume and full-volume output levels. The 8580 has none.
63
- MIXER_DC = { mos6581: -((0xfff * 0xff) / 18) >> 7, mos8580: 0 }.freeze
64
-
65
- # Fractional bits carried in the integrators. At low cutoffs a cycle's
66
- # step is only a few units, which truncating to whole units would
67
- # swallow, and always toward minus infinity.
68
- FRACTION = 12
69
-
70
- # The RC network between the SID's audio pin and the C64's output jack:
71
- # a 10kΩ/1000pF low-pass at ~16 kHz, then a 1kΩ/10µF high-pass at
72
- # ~16 Hz that strips the 6581's DC offset off the mix.
73
- class External
74
- W0_LOWPASS = (100_000 * SCALE).round
75
- W0_HIGHPASS = (100 * SCALE).round
76
-
77
- # The high-pass step is W0_HIGHPASS/2^20 of the gap, so in whole
78
- # units it stalls on any gap under ~10k, as reSID's does. Sixteen
79
- # fractional bits bring that under one unit.
80
- FRACTION = 16
81
-
82
- # Its input arrives with the filter's fractional bits still on.
83
- INPUT_SHIFT = FRACTION - Filter::FRACTION
84
-
85
- attr_reader :output
86
-
87
- def initialize
88
- @lowpass = 0
89
- @highpass = 0
90
- @output = 0
91
- end
92
-
93
- def save_state(out)
94
- out.int(@lowpass).int(@highpass).int(@output)
95
- end
96
-
97
- def load_state(input)
98
- @lowpass = input.int
99
- @highpass = input.int
100
- @output = input.int
101
- end
102
-
103
- # Takes the input in 1/2^Filter::FRACTION units, and reads the
104
- # output out in whole ones. A step of several cycles moves each pole
105
- # at most onto its input.
106
- def cycle!(input, cycles = 1)
107
- w0_lowpass = [(W0_LOWPASS >> 8) * cycles, 1 << 12].min
108
- w0_highpass = [W0_HIGHPASS * cycles, 1 << 20].min
109
- delta_lowpass = (w0_lowpass * ((input << INPUT_SHIFT) - @lowpass)) >> 12
110
- delta_highpass = (w0_highpass * (@lowpass - @highpass)) >> 20
111
- @output = (@lowpass - @highpass) >> FRACTION
112
- @lowpass += delta_lowpass
113
- @highpass += delta_highpass
114
- @output
115
- end
116
- end
117
-
118
- attr_reader :model, :cutoff, :routing, :mode, :volume
119
-
120
- def initialize(model: :mos6581)
121
- @model = model
122
- @w0_table = W0.fetch(model)
123
- @mixer_dc = MIXER_DC.fetch(model)
124
- @external = External.new
125
- reset
126
- end
127
-
128
- # The integrators and the registers carry over; the cutoff maps
129
- # through the new model's curve.
130
- def model=(model)
131
- @model = model
132
- @w0_table = W0.fetch(model)
133
- @mixer_dc = MIXER_DC.fetch(model)
134
- @w0 = @w0_table[@cutoff]
135
- end
136
-
137
- def reset
138
- @cutoff = 0x000
139
- @routing = 0x0
140
- @mode = 0x0
141
- @volume = 0x0
142
- @voice3_off = false
143
- @w0 = @w0_table[0]
144
- @resonance = RESONANCE[0]
145
- @lowpass = @bandpass = @highpass = 0
146
- @input = @unfiltered = 0
147
- end
148
-
149
- # The registers as the filter decoded them and its integrators. The
150
- # W0 table is the model's.
151
- def save_state(out)
152
- out.int(@cutoff).int(@routing).int(@mode).int(@volume).boolean(@voice3_off).int(@w0).int(@resonance)
153
- [@highpass, @bandpass, @lowpass, @unfiltered, @input].each { |value| out.int(value) }
154
- @external.save_state(out)
155
- end
156
-
157
- def load_state(input)
158
- @cutoff = input.int
159
- @routing = input.int
160
- @mode = input.int
161
- @volume = input.int
162
- @voice3_off = input.boolean?
163
- @w0 = input.int
164
- @resonance = input.int
165
- load_integrators(input)
166
- end
167
-
168
- def write(reg, value)
169
- case reg
170
- when 0x15 then self.cutoff = (@cutoff & 0x7f8) | (value & 0x07)
171
- when 0x16 then self.cutoff = (value << 3) | (@cutoff & 0x007)
172
- when 0x17 then write_resonance(value)
173
- when 0x18 then write_mode_volume(value)
174
- end
175
- end
176
-
177
- def cutoff=(value)
178
- @cutoff = value & 0x7ff
179
- @w0 = @w0_table[@cutoff]
180
- end
181
-
182
- def voice3_off? = @voice3_off
183
-
184
- def lowpass = @lowpass >> FRACTION
185
- def bandpass = @bandpass >> FRACTION
186
- def highpass = @highpass >> FRACTION
187
-
188
- # Integrates `cycles` cycles in one step, from the voices' output at
189
- # the end of them.
190
- def cycle!(voices, cycles = 1)
191
- route(voices)
192
- w0 = @w0 * cycles
193
- w0 = W0_STEP_MAX if w0 > W0_STEP_MAX
194
- @bandpass -= (w0 * @highpass) >> 20
195
- @lowpass -= (w0 * @bandpass) >> 20
196
- @highpass = ((@bandpass * @resonance) >> 10) - @lowpass - (@input << FRACTION)
197
- @external.cycle!(fine_mix, cycles)
198
- end
199
-
200
- # The SID's own audio pin, before the board's RC network.
201
- def mix = fine_mix >> FRACTION
202
-
203
- def output = @external.output
204
-
205
- private
206
-
207
- def load_integrators(input)
208
- @highpass = input.int
209
- @bandpass = input.int
210
- @lowpass = input.int
211
- @unfiltered = input.int
212
- @input = input.int
213
- @external.load_state(input)
214
- end
215
-
216
- def write_resonance(value)
217
- @routing = value & 0x0f
218
- @resonance = RESONANCE[(value >> 4) & 0x0f]
219
- end
220
-
221
- def write_mode_volume(value)
222
- @volume = value & 0x0f
223
- @mode = (value >> 4) & 0x07
224
- @voice3_off = value.anybits?(0x80)
225
- end
226
-
227
- # Unrolled over the three voices, like SID#clock!. Voice 3 is silenced
228
- # by MODE/VOL bit 7 only while it bypasses the filter.
229
- def route(voices)
230
- voice1, voice2, voice3 = voices
231
- @input = 0
232
- @unfiltered = 0
233
- route_voice(voice1.output >> 7, 0x1)
234
- route_voice(voice2.output >> 7, 0x2)
235
- if @routing & 0x4 != 0
236
- @input += voice3.output >> 7
237
- elsif !@voice3_off
238
- @unfiltered += voice3.output >> 7
239
- end
240
- end
241
-
242
- def route_voice(output, bit)
243
- if @routing & bit == bit
244
- @input += output
245
- else
246
- @unfiltered += output
247
- end
248
- end
249
-
250
- # The mix with the integrators' fractional bits kept, so the RC
251
- # network isn't fed the filter's output floored to whole units.
252
- def fine_mix = (((@unfiltered + @mixer_dc) << FRACTION) + filtered) * @volume
253
-
254
- def filtered
255
- value = 0
256
- value += @lowpass if @mode & 0x1 != 0
257
- value += @bandpass if @mode & 0x2 != 0
258
- value += @highpass if @mode & 0x4 != 0
259
- value
260
- end
261
- end
262
- end
263
- end
@@ -1,77 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class SID
5
- # One of the three voices: a waveform generator amplitude-modulated by
6
- # its envelope.
7
- #
8
- # The 6581 waveform DAC swings around a midpoint well above ground, so
9
- # even a silent voice carries a large DC offset into the mixer. The
10
- # 8580's is centred and carries none.
11
- class Voice
12
- WAVE_ZERO = { mos6581: 0x380, mos8580: 0x800 }.freeze
13
- DC_OFFSET = { mos6581: 0x800 * 0xff, mos8580: 0 }.freeze
14
-
15
- attr_reader :waveform, :envelope
16
-
17
- # Each voice hard-syncs and ring-modulates against the previous one,
18
- # wrapping from the first back round to the last.
19
- def self.linked(count, model:)
20
- voices = Array.new(count) { new(model:) }
21
- waveforms = voices.map(&:waveform)
22
- waveforms.each_with_index do |waveform, i|
23
- waveform.sync_source = waveforms[i - 1]
24
- waveform.sync_dest = waveforms[(i + 1) % count]
25
- end
26
- voices
27
- end
28
-
29
- def initialize(model: :mos6581)
30
- @waveform = Waveform.new(model:)
31
- @envelope = Envelope.new
32
- @wave_zero = WAVE_ZERO.fetch(model)
33
- @dc_offset = DC_OFFSET.fetch(model)
34
- end
35
-
36
- def model=(model)
37
- @waveform.model = model
38
- @wave_zero = WAVE_ZERO.fetch(model)
39
- @dc_offset = DC_OFFSET.fetch(model)
40
- end
41
-
42
- def reset!
43
- @waveform.reset!
44
- @envelope = Envelope.new
45
- end
46
-
47
- def save_state(out)
48
- @waveform.save_state(out)
49
- @envelope.save_state(out)
50
- end
51
-
52
- def load_state(input)
53
- @waveform.load_state(input)
54
- @envelope.load_state(input)
55
- end
56
-
57
- def control=(value)
58
- @waveform.control = value
59
- @envelope.control = value
60
- end
61
-
62
- def cycle!
63
- @envelope.cycle!
64
- @waveform.cycle!
65
- end
66
-
67
- def fast_forward(cycles)
68
- @envelope.fast_forward(cycles)
69
- @waveform.fast_forward(cycles)
70
- end
71
-
72
- def output
73
- ((@waveform.output - @wave_zero) * @envelope.output) + @dc_offset
74
- end
75
- end
76
- end
77
- end
@@ -1,126 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class SID
5
- class Waveform
6
- # The shapes the chip puts out when more than one waveform is selected.
7
- #
8
- # Selecting several shapers connects their outputs to the same twelve
9
- # DAC lines. Each line settles somewhere between the levels the
10
- # shapers drive it to, and couples to the lines around it through the
11
- # resistances between them, so a bit reads high only when enough of
12
- # its own drive and its neighbours' is high. Modelled here as a
13
- # threshold on a weighted sum: each selected shaper adds its bit times
14
- # its strength, a high pulse adds its strength to every line, and the
15
- # neighbours contribute with one weight per distance below and one per
16
- # distance above.
17
- #
18
- # A low pulse grounds every line.
19
- #
20
- # The parameters come from bin/sidwavefit, fitted against OSC3 dumps of
21
- # real chips in SID/resid-test (oscsample0/1-6581/8580wf30/50/60/70).
22
- # The tables are built from them once per chip model.
23
- module Combined
24
- BITS = 12
25
-
26
- # Per chip and selection (triangle $1, sawtooth $2, pulse $4): the
27
- # triangle's strength next to a sawtooth (the sawtooth, or a lone
28
- # triangle, has strength 1), the pulse's strength, the threshold as
29
- # a fraction of the full drive, then the weights of the lines one to
30
- # eleven bits below and one to eleven bits above.
31
- PARAMETERS = {
32
- mos6581: {
33
- 0x3 => [0.522, 6.4087, 0.9062,
34
- 0.5304, 0.278, 0.1473, 0.0773, 0.0, 0.0184, 0.0113, 0.0251, 0.0594, 0.2001, 0.2001,
35
- 0.4103, 0.1756, 0.0687, 0.0282, 0.0115, 0.0047, 0.0031, 0.2001, 0.2001, 0.2001, 0.2001],
36
- 0x5 => [5.871, 0.0, 0.7485,
37
- 0.6522, 0.5913, 0.5404, 0.4828, 0.428, 0.361, 0.2955, 0.2453, 0.1558, 0.0501, 0.0016,
38
- 0.7106, 0.6667, 0.6426, 0.6376, 0.5761, 0.6639, 0.7193, 0.4728, 0.4306, 0.392, 0.357],
39
- 0x6 => [3.8329, 4.7751, 0.9565,
40
- 0.815, 0.8302, 0.8204, 0.8107, 0.8511, 0.8416, 0.8322, 0.8728, 0.8636, 0.8545, 0.8954,
41
- 0.8071, 0.7979, 0.7465, 0.7771, 0.7643, 0.7572, 0.7054, 0.4585, 0.4159, 0.3773, 0.3421],
42
- 0x7 => [5.5703, 0.2543, 0.9575,
43
- 0.7177, 0.515, 0.3696, 0.2653, 0.1904, 0.1367, 0.0606, 0.0953, 0.0506, 0.0363, 0.2261,
44
- 0.6347, 0.286, 0.203, 0.0817, 0.0438, 0.1235, 0.2001, 0.2001, 0.2001, 0.2001, 0.2001]
45
- },
46
- mos8580: {
47
- 0x3 => [0.2223, 7.7741, 0.8869,
48
- 0.4626, 0.2025, 0.0911, 0.041, 0.0185, 0.0, 0.0008, 0.0, 0.0, 0.0127, 0.0063,
49
- 0.5633, 0.311, 0.2099, 0.0881, 0.0255, 0.0, 0.0431, 0.2002, 0.2002, 0.2002, 0.2002],
50
- 0x5 => [3.1022, 1.1282, 0.9157,
51
- 0.2731, 0.2748, 0.0031, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
52
- 0.6228, 0.7375, 0.6094, 0.6667, 0.4381, 0.4714, 0.3648, 0.2669, 0.2264, 0.2001, 0.2001],
53
- 0x6 => [0.9477, 0.0012, 0.7837,
54
- 0.2565, 0.2289, 0.1095, 0.0805, 0.0282, 0.0281, 0.0, 0.0, 0.0, 0.0, 0.0063,
55
- 0.3382, 0.3131, 0.3129, 0.2898, 0.233, 0.1762, 0.2135, 0.2002, 0.2002, 0.2002, 0.2002],
56
- 0x7 => [1.219, 1.1111, 0.9473,
57
- 0.3829, 0.1466, 0.0577, 0.0215, 0.0082, 0.0032, 0.0, 0.0, 0.0, 0.0, 0.0,
58
- 0.7273, 0.6845, 0.566, 0.4807, 0.6, 0.1954, 0.4651, 0.2194, 0.2002, 0.2002, 0.2002]
59
- }
60
- }.freeze
61
-
62
- # A compiled parameter set: the weight matrix, and per line the sum
63
- # of its weights and the threshold against the full drive.
64
- class Network
65
- attr_reader :triangle_strength, :pulse_strength
66
-
67
- def initialize(params)
68
- @triangle_strength, @pulse_strength, threshold = params[0, 3]
69
- below = [1.0] + params[3, BITS - 1]
70
- above = [1.0] + params[3 + BITS - 1, BITS - 1]
71
- @weights = Array.new(BITS) do |i|
72
- Array.new(BITS) { |j| j <= i ? below[i - j] : above[j - i] }.freeze
73
- end.freeze
74
- @norms = @weights.map(&:sum).freeze
75
- @threshold = threshold
76
- end
77
-
78
- # `drives` holds [bits, strength] for each selected shaper; a high
79
- # pulse is passed separately, as it drives every line alike.
80
- def shape(drives, pulse)
81
- total = drives.sum { |_, strength| strength }
82
- total += @pulse_strength if pulse
83
- out = 0
84
- BITS.times do |i|
85
- level = pulse ? @pulse_strength * @norms[i] : 0.0
86
- weights = @weights[i]
87
- drives.each do |bits, strength|
88
- BITS.times { |j| level += weights[j] * strength if bits[j] == 1 }
89
- end
90
- out |= 1 << i if level >= @threshold * @norms[i] * total
91
- end
92
- out
93
- end
94
- end
95
-
96
- module_function
97
-
98
- # The pulse-high shapes of the four combinations without noise.
99
- def tables(model)
100
- @tables ||= {}
101
- @tables[model] ||= PARAMETERS.fetch(model).to_h do |selected, params|
102
- [selected, table(selected, params)]
103
- end.freeze
104
- end
105
-
106
- # One combination's shapes, indexed by the phase (the sawtooth), or
107
- # for triangle and pulse by the triangle. A triangle combined with a
108
- # sawtooth is never folded, so it is the phase shifted left one bit.
109
- def table(selected, params)
110
- network = Network.new(params)
111
- Array.new(1 << BITS) do |index|
112
- triangle = selected == 0x5 ? index : (index << 1) & 0xfff
113
- network.shape(drives(selected, network, index, triangle), selected.anybits?(0x4))
114
- end.freeze
115
- end
116
-
117
- def drives(selected, network, saw, triangle)
118
- drives = []
119
- drives << [saw, 1.0] if selected.anybits?(0x2)
120
- drives << [triangle, selected.anybits?(0x2) ? network.triangle_strength : 1.0] if selected.anybits?(0x1)
121
- drives
122
- end
123
- end
124
- end
125
- end
126
- end