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,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class SID
6
+ class Waveform
7
+ # Noise combined with other waveforms: the output lines write back into
8
+ # the LFSR, and what they write is not always what OSC3 reads.
9
+ module NoiseWriteback
10
+ # The LFSR bits the noise shaper reads, paired with the output bit each
11
+ # one drives (Dag Lem's diagram in SID/noise-reset_new). A combined
12
+ # waveform drives the same lines, so a bit held low there is written
13
+ # back into the register.
14
+ NOISE_TAPS = [[0x100000, 0x800], [0x040000, 0x400], [0x004000, 0x200],
15
+ [0x000800, 0x100], [0x000200, 0x080], [0x000020, 0x040],
16
+ [0x000004, 0x020], [0x000001, 0x010]].freeze
17
+
18
+ # Pulse+noise with the pulse high: the noise lines next to the four
19
+ # below them, which nothing drives, are pulled low. The OSC3 read and
20
+ # the LFSR writeback see the same lines against different thresholds,
21
+ # so they lose a different number of bits. The 8580's pair is the one
22
+ # that reproduces SID/wf12nsr's pulse+noise row (it reads $f8, and the
23
+ # writeback leaves $fc behind), and SID/wb_testsuite's C->9 and C->E
24
+ # rows need that same $fc written at release. The 6581 reads $00 of a
25
+ # full register (SID/wf12nsr's pulse+noise row) and pulls nothing
26
+ # while the register holds: wb_testsuite's 8->C and C->C rows run
27
+ # pulse+noise and leave the register alone. Its lines only land
28
+ # part way through a shift (#write_back_shift).
29
+ PULSE_NOISE_READ = { mos6581: 0x000, mos8580: 0xf80 }.freeze
30
+ PULSE_NOISE_WRITE = { mos6581: 0xff0, mos8580: 0xfc0 }.freeze
31
+
32
+ # What a 6581 writes back when the test bit falls with only pulse+noise
33
+ # common to the old waveform and the new one (SID/wb_testsuite's D->C,
34
+ # E->C, F->C and D->E rows).
35
+ PULSE_NOISE_RELEASE = 0xf80
36
+
37
+ private
38
+
39
+ # What the lines write into the LFSR, against a lower threshold than
40
+ # OSC3 reads them by: a line left high between two low ones reads high
41
+ # (SID/noisewriteback's noise_writeback_test2) but is written low
42
+ # (SID/wf12nsr's noise+triangle and noise+sawtooth rows).
43
+ def write_back(selected, value)
44
+ return value & ((value << 1) | (value >> 1)) unless selected == 0xc
45
+ return 0x000 if @pulse.zero?
46
+
47
+ noise & @pulse_noise_write
48
+ end
49
+
50
+ # What the lines write while the register is part way through a
51
+ # shift, where the 6581's pulse+noise writes its output as read.
52
+ def write_back_mid_shift(selected, value)
53
+ return value if pulse_noise_mid_shift?(selected)
54
+
55
+ write_back(selected, value)
56
+ end
57
+
58
+ def pulse_noise_mid_shift?(selected) = @topbit_feedback && selected == 0xc
59
+
60
+ def write_shift_register(value)
61
+ NOISE_TAPS.each { |bit, line| @shift_register &= ~bit if value.nobits?(line) }
62
+ end
63
+
64
+ # The second phase of a shift writes back by the test bit release
65
+ # rule with the waveform left alone. The 6581's pulse+noise, which
66
+ # that rule leaves out, writes its lines too (SID/wf12nsr's
67
+ # pulse+noise row).
68
+ def write_back_shift
69
+ return unless pulse_noise_mid_shift?(@selected) || release_writes_back?(@selected, @selected)
70
+
71
+ write_shift_register(write_back_mid_shift(@selected, @output))
72
+ end
73
+
74
+ # Setting the test bit starts the bleed, and stalls the register part
75
+ # way through a shift, where a noise combination writes its output
76
+ # back first, from the accumulator it had. SID/noiselfsrinit's
77
+ # $f8/$80 pairs set the bit onto all four from noise alone, and
78
+ # SID/wf12nsr's pulse+noise row sets it onto pulse+noise.
79
+ def raise_test
80
+ @shift_register_reset = @shift_register_reset_delay
81
+ return unless @selected.anybits?(0x8) && combined?(@selected) && @shift_pipeline != 1
82
+
83
+ write_shift_register(write_back_mid_shift(@selected, shape(@selected)))
84
+ end
85
+
86
+ # Releasing the test bit finishes the shift it interrupted: the old
87
+ # waveform's output may be written back first, then a bit clocks in
88
+ # over the forced-high bit 22.
89
+ def release_test(previous)
90
+ value = release_write(previous)
91
+ write_shift_register(value) if value
92
+ shift_noise(1)
93
+ end
94
+
95
+ # What the release writes over the taps, or nil. On the 6581, a change
96
+ # that keeps only pulse+noise of the old waveform writes the lowest
97
+ # noise lines low. On the 8580, a change from pulse+noise to all four
98
+ # writes every line low.
99
+ def release_write(previous)
100
+ if @topbit_feedback
101
+ return noise & PULSE_NOISE_RELEASE if previous != 0xc && (previous & @selected) == 0xc
102
+ elsif previous == 0xc && @selected == 0xf
103
+ return 0x000
104
+ end
105
+ write_back(previous, shape(previous)) if release_writes_back?(previous, @selected)
106
+ end
107
+
108
+ # Which waveform changes write the old output back as the test bit
109
+ # falls (SID/wb_testsuite, after libresidfp's do_writeback). Noise has
110
+ # to have been combined before and still be combined after. Nothing
111
+ # is written back on changing to pulse+noise or from pulse+noise to
112
+ # sawtooth+noise, nor, on the 6581, on trading triangle for sawtooth
113
+ # or back.
114
+ def release_writes_back?(previous, selected)
115
+ return false if previous <= 0x8 || selected <= 0x8
116
+ return false if selected == 0xc || (previous == 0xc && selected == 0xa)
117
+
118
+ !(@topbit_feedback && [previous & 0x3, selected & 0x3].sort == [0x1, 0x2])
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class SID
6
+ class Waveform
7
+ # A snapshot of an oscillator: its phase, the noise register and the
8
+ # output latch, and the same fields as reSID keeps them, for VICE's
9
+ # SIDEXTENDED module. The model's tables and the voices it syncs with
10
+ # are the SID's wiring.
11
+ module SavedState
12
+ # The fields reSID keeps for an oscillator between cycles: the phase,
13
+ # the noise register, its shift pipeline and reset countdown, the
14
+ # floating output's countdown and the pulse level.
15
+ def resid_fields
16
+ [@accumulator, @shift_register, @shift_pipeline, @shift_register_reset, @floating_ttl, @pulse]
17
+ end
18
+
19
+ # Takes the fields resid_fields gives from `fields`, from `at` on.
20
+ def restore_resid_fields(fields, at)
21
+ @accumulator = fields[at]
22
+ @shift_register = fields[at + 1]
23
+ @shift_pipeline = fields[at + 2]
24
+ @shift_register_reset = fields[at + 3]
25
+ @floating_ttl = fields[at + 4]
26
+ @pulse = fields[at + 5]
27
+ @stale = true
28
+ end
29
+
30
+ def save_state(out)
31
+ out.int(@accumulator).int(@delayed_triangle).int(@delayed_sawtooth)
32
+ out.int(@shift_register).int(@shift_register_reset).int(@shift_pipeline)
33
+ out.int(@frequency).int(@pulse_width).int(@selected)
34
+ [@test, @ring, @sync, @msb_rising].each { |flag| out.boolean(flag) }
35
+ out.int(@floating).int(@floating_ttl).int(@pulse).int(@output).boolean(@stale)
36
+ end
37
+
38
+ def load_state(input)
39
+ @accumulator = input.int
40
+ @delayed_triangle = input.int
41
+ @delayed_sawtooth = input.int
42
+ @shift_register = input.int
43
+ @shift_register_reset = input.int
44
+ @shift_pipeline = input.int
45
+ @frequency = input.int
46
+ @pulse_width = input.int
47
+ @selected = input.int
48
+ load_latches(input)
49
+ end
50
+
51
+ private
52
+
53
+ def load_latches(input)
54
+ @test = input.boolean?
55
+ @ring = input.boolean?
56
+ @sync = input.boolean?
57
+ @msb_rising = input.boolean?
58
+ @floating = input.int
59
+ @floating_ttl = input.int
60
+ @pulse = input.int
61
+ @output = input.int
62
+ @stale = input.boolean?
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,307 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/chips/sid/waveform/combined"
4
+ require "badline/chips/sid/waveform/fast_forward"
5
+ require "badline/chips/sid/waveform/noise_writeback"
6
+ require "badline/chips/sid/waveform/saved_state"
7
+
8
+ module Badline
9
+ module Chips
10
+ class SID
11
+ # Waveform generator: a 24-bit phase accumulator and the shapers that
12
+ # read it.
13
+ #
14
+ # The accumulator advances by the 16-bit frequency every cycle, so every
15
+ # waveform is a pure function of the phase. Bit 23 drives hard sync and
16
+ # the triangle fold, bit 19 clocks the noise LFSR.
17
+ #
18
+ # Selecting more than one waveform shorts the shapers onto the lines the
19
+ # oscillator itself reads back, so a combined waveform is not only a
20
+ # shape: a low top bit reaches the accumulator MSB through the sawtooth
21
+ # switch, and noise in the mix is written back into the LFSR. The shape
22
+ # itself comes from Combined's model of the lines pulling on each other.
23
+ #
24
+ # The pulse comparator's output reaches the lines a cycle after the
25
+ # accumulator it compared.
26
+ #
27
+ # With nothing selected the DAC input floats, holding the last value
28
+ # driven onto it until the charge drains away.
29
+ class Waveform
30
+ include FastForward
31
+ include NoiseWriteback
32
+ include SavedState
33
+
34
+ # All bits high at power up, odd ones stored inverted (SID/oscinit).
35
+ POWER_ON_ACCUMULATOR = 0x555555
36
+
37
+ # Holding the test bit bleeds every LFSR bit high; the power-on state is
38
+ # one shift further on, which is what releasing the bit leaves behind.
39
+ SHIFT_REGISTER_RESET = 0x7fffff
40
+ NOISE_SEED = 0x7ffffe
41
+
42
+ # Cycles the test bit needs to bleed the LFSR high. SID/bitfade's
43
+ # delaynoise measures ~$950000 on a real 8580. Nothing measures the
44
+ # 6581: SID/resid-test's oscsample dumps show it holding its bits
45
+ # through the ~$8800 cycles between runs, and the slow reset
46
+ # (SID/noise-reset_old) allows it a second.
47
+ SHIFT_REGISTER_RESET_DELAY = { mos6581: 0x80000, mos8580: 0x950000 }.freeze
48
+
49
+ # Cycles the floating DAC input holds its charge (SID/osc3-wave0).
50
+ FLOATING_OUTPUT_TTL = 0x4000
51
+
52
+ MSB = 0x800000
53
+
54
+ attr_accessor :sync_source, :sync_dest
55
+ attr_reader :accumulator, :shift_register, :frequency, :pulse_width, :pulse
56
+
57
+ def initialize(model: :mos6581)
58
+ use_model(model)
59
+ @tri_saw_delay = model == :mos8580
60
+ @accumulator = POWER_ON_ACCUMULATOR
61
+ @sync_source = @sync_dest = self
62
+ reset!
63
+ end
64
+
65
+ # The running state carries over. A 6581 never delays its shapers, so
66
+ # the 8580's delayed triangle and sawtooth start from the current phase.
67
+ def model=(model)
68
+ use_model(model)
69
+ if model == :mos8580 && !@tri_saw_delay
70
+ @delayed_sawtooth = sawtooth
71
+ @delayed_triangle = triangle
72
+ end
73
+ @tri_saw_delay = model == :mos8580
74
+ end
75
+
76
+ # The RES line clears the registers and reseeds the LFSR, but leaves
77
+ # the accumulator alone (SID/oscinit).
78
+ def reset!
79
+ @delayed_sawtooth = @delayed_triangle = 0x000
80
+ @shift_register = NOISE_SEED
81
+ @shift_register_reset = 0
82
+ @shift_pipeline = 0
83
+ @frequency = 0x0000
84
+ @pulse_width = 0x000
85
+ @selected = 0x0
86
+ @test = false
87
+ @ring = false
88
+ @sync = false
89
+ @msb_rising = false
90
+ @floating = 0x000
91
+ @floating_ttl = 0
92
+ @pulse = 0xfff
93
+ @output = 0x000
94
+ @stale = true
95
+ end
96
+
97
+ def sync? = @sync
98
+ def msb_rising? = @msb_rising
99
+
100
+ def frequency_low=(value)
101
+ @frequency = (@frequency & 0xff00) | value
102
+ end
103
+
104
+ def frequency_high=(value)
105
+ @frequency = (value << 8) | (@frequency & 0x00ff)
106
+ end
107
+
108
+ def pulse_width_low=(value)
109
+ @pulse_width = (@pulse_width & 0xf00) | value
110
+ @stale = true
111
+ end
112
+
113
+ def pulse_width_high=(value)
114
+ @pulse_width = ((value & 0x0f) << 8) | (@pulse_width & 0x0ff)
115
+ @stale = true
116
+ end
117
+
118
+ # The test bit clears the accumulator and stalls the LFSR half way
119
+ # through a shift, holding bit 22 high while its bits bleed up.
120
+ def control=(value)
121
+ previous = @selected
122
+ @selected = (value >> 4) & 0x0f
123
+ @ring = value.anybits?(0x04)
124
+ @sync = value.anybits?(0x02)
125
+ test = value.anybits?(0x08)
126
+ if test
127
+ raise_test unless @test
128
+ @accumulator = 0x000000
129
+ @pulse = 0xfff
130
+ @shift_pipeline = 0
131
+ elsif @test
132
+ release_test(previous)
133
+ end
134
+ @test = test
135
+ @stale = true
136
+ end
137
+
138
+ def cycle!
139
+ latch_output
140
+ compare_pulse
141
+ @test ? bleed_shift_register : advance
142
+ @stale = true
143
+ end
144
+
145
+ # Hard sync resets the next voice's accumulator when ours wraps. A
146
+ # source that is itself synced on the cycle its own MSB rises does not
147
+ # pass the sync on.
148
+ def synchronize!
149
+ return unless @msb_rising && @sync_dest.sync? &&
150
+ !(@sync && @sync_source.msb_rising?)
151
+
152
+ @sync_dest.reset_accumulator
153
+ end
154
+
155
+ def reset_accumulator
156
+ @accumulator = 0x000000
157
+ @stale = true
158
+ end
159
+
160
+ # Held for the rest of the cycle once computed, so the filter, OSC3 and
161
+ # the oscillator's own feedback all see one value per cycle.
162
+ def output
163
+ return @output unless @stale
164
+
165
+ @stale = false
166
+ @output = @selected.zero? ? @floating : shape(@selected)
167
+ end
168
+
169
+ # What OSC3 reads. The 8580 delays the triangle and sawtooth shapers
170
+ # by half a cycle, which OSC3 latches as a whole cycle late; pulse and
171
+ # noise still reach the lines on time.
172
+ def osc3
173
+ return output unless @tri_saw_delay && @selected.anybits?(0x3)
174
+
175
+ shape(@selected, @delayed_sawtooth, @delayed_triangle)
176
+ end
177
+
178
+ def sawtooth = @accumulator >> 12
179
+
180
+ # The upper half of the ramp is folded back down, shifted left one bit
181
+ # to keep the full 12-bit range.
182
+ def triangle(selected = @selected)
183
+ folded = inverted?(selected) ? @accumulator ^ 0xffffff : @accumulator
184
+ (folded >> 11) & 0xfff
185
+ end
186
+
187
+ # Eight taps off the 23-bit LFSR, gathered into a 12-bit sample.
188
+ def noise
189
+ ((@shift_register & 0x100000) >> 9) |
190
+ ((@shift_register & 0x040000) >> 8) |
191
+ ((@shift_register & 0x004000) >> 5) |
192
+ ((@shift_register & 0x000800) >> 3) |
193
+ ((@shift_register & 0x000200) >> 2) |
194
+ ((@shift_register & 0x000020) << 1) |
195
+ ((@shift_register & 0x000004) << 3) |
196
+ ((@shift_register & 0x000001) << 4)
197
+ end
198
+
199
+ private
200
+
201
+ def use_model(model)
202
+ @topbit_feedback = model != :mos8580
203
+ @pulse_noise_read = PULSE_NOISE_READ.fetch(model)
204
+ @pulse_noise_write = PULSE_NOISE_WRITE.fetch(model)
205
+ @combined = Combined.tables(model)
206
+ @shift_register_reset_delay = SHIFT_REGISTER_RESET_DELAY.fetch(model)
207
+ end
208
+
209
+ def shape(selected, saw = sawtooth, tri = triangle(selected))
210
+ case selected
211
+ when 0x1 then tri
212
+ when 0x2 then saw
213
+ when 0x4 then @pulse
214
+ when 0x8 then noise
215
+ else combined(selected, saw, tri)
216
+ end
217
+ end
218
+
219
+ # A low pulse grounds every line. Noise with pulse alone loses its
220
+ # lowest lines; noise with triangle or sawtooth is ANDed over the rest
221
+ # of the mix.
222
+ def combined(selected, saw, tri)
223
+ return 0x000 if selected.anybits?(0x4) && @pulse.zero?
224
+ return noise & @pulse_noise_read if selected == 0xc
225
+
226
+ rest = selected & 0x7
227
+ value = case rest
228
+ when 0x1 then tri
229
+ when 0x2 then saw
230
+ when 0x4 then 0xfff
231
+ else @combined[rest][rest == 0x5 ? tri : saw]
232
+ end
233
+ selected.anybits?(0x8) ? value & noise : value
234
+ end
235
+
236
+ def compare_pulse(phase = @accumulator >> 12) = (@pulse = @test || phase >= @pulse_width ? 0xfff : 0x000)
237
+
238
+ # More than one bit set in the selection.
239
+ def combined?(selected) = selected & (selected - 1) != 0
240
+
241
+ # The one point in the cycle where the waveform selector drives the DAC:
242
+ # either it latches a fresh value, or nothing drives the line and the
243
+ # charge already on it drains a little further.
244
+ def latch_output
245
+ value = output
246
+ if @tri_saw_delay
247
+ @delayed_sawtooth = sawtooth
248
+ @delayed_triangle = triangle
249
+ end
250
+ if @selected.zero?
251
+ drain_floating(1)
252
+ return
253
+ end
254
+
255
+ @floating = value
256
+ @floating_ttl = FLOATING_OUTPUT_TTL
257
+ feed_back(value) if combined?(@selected) && !@test
258
+ end
259
+
260
+ # A zero on the shared output lines travels back into the oscillator:
261
+ # through the sawtooth switch it clears the accumulator MSB on the next
262
+ # cycle, and with noise selected it lands in the LFSR, where a bit
263
+ # pulled low can never come back. The 8580 buffers the top bit behind a
264
+ # flip-flop before the sawtooth switch, so only the LFSR sees it. In the
265
+ # first phase of a shift the register bits float, so nothing is pulled
266
+ # down: the output is latched instead, for the second phase to write.
267
+ def feed_back(value)
268
+ @accumulator &= ~MSB if @topbit_feedback && @selected.anybits?(0x2) && value.nobits?(0x800)
269
+ write_shift_register(write_back(@selected, value)) if @selected.anybits?(0x8) && @shift_pipeline != 1
270
+ end
271
+
272
+ # A rise of bit 19 starts a shift that takes two more cycles
273
+ # (SID/noisewriteback's noise_writeback_test2, after libresidfp's shift
274
+ # pipeline). The first phase latches the output, and the second writes
275
+ # it over the taps before the register shifts.
276
+ def advance
277
+ previous = @accumulator
278
+ @accumulator = (previous + @frequency) & 0xffffff
279
+ @msb_rising = @accumulator & ~previous & MSB != 0
280
+ if @accumulator & ~previous & 0x080000 != 0
281
+ @shift_pipeline = 2
282
+ elsif @shift_pipeline != 0 && (@shift_pipeline -= 1).zero?
283
+ write_back_shift
284
+ shift_noise
285
+ end
286
+ end
287
+
288
+ # Bit 0 feeds back bits 22 and 17, with the test bit forcing bit 22 high.
289
+ def shift_noise(forced = 0)
290
+ bit0 = ((@shift_register >> 22) | forced) ^ (@shift_register >> 17)
291
+ @shift_register = ((@shift_register << 1) & 0x7fffff) | (bit0 & 0x1)
292
+ end
293
+
294
+ # TriXOR = !Saw & ((!V3 & Ring) ^ bit23), where V3 is the modulating
295
+ # voice's MSB (SID/ringmod).
296
+ def inverted?(selected)
297
+ return false if selected & 0x2 != 0
298
+
299
+ msb = @accumulator & MSB != 0
300
+ return msb unless @ring
301
+
302
+ msb == (@sync_source.accumulator & MSB != 0)
303
+ end
304
+ end
305
+ end
306
+ end
307
+ end