badline 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (505) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -0
  3. data/CLAUDE.md +59 -31
  4. data/README.md +1 -1
  5. data/doc/library.md +9 -9
  6. data/doc/pinned-behaviour.md +105 -105
  7. data/doc/snapshots.md +1 -4
  8. data/lib/badline/audio/bare_player.rb +3 -3
  9. data/lib/badline/audio/cli.rb +6 -6
  10. data/lib/badline/audio/jukebox.rb +2 -2
  11. data/lib/badline/audio/machine_player.rb +2 -2
  12. data/lib/badline/{media → audio}/queue.rb +1 -1
  13. data/lib/badline/audio/queued_tune.rb +6 -6
  14. data/lib/badline/audio/renderer.rb +5 -5
  15. data/lib/badline/audio/stereo.rb +1 -1
  16. data/lib/badline/c128/{bus_state.rb → bus/saved_state.rb} +1 -1
  17. data/lib/badline/c128/bus.rb +18 -17
  18. data/lib/badline/c128/color_lines.rb +2 -2
  19. data/lib/badline/c128/cpu.rb +1 -1
  20. data/lib/badline/c128/drives.rb +10 -11
  21. data/lib/badline/c128/fast_serial.rb +5 -5
  22. data/lib/badline/c128/mmu_pages.rb +1 -1
  23. data/lib/badline/c128/modes.rb +2 -2
  24. data/lib/badline/c128/saved_state.rb +21 -47
  25. data/lib/badline/c128/z80.rb +2 -2
  26. data/lib/badline/c128.rb +14 -9
  27. data/lib/badline/{computer → c64}/attachments.rb +4 -6
  28. data/lib/badline/c64/banked_ram/banking.rb +32 -0
  29. data/lib/badline/c64/banked_ram/plus256k.rb +56 -0
  30. data/lib/badline/c64/banked_ram/plus60k.rb +45 -0
  31. data/lib/badline/c64/banked_ram/unexpanded.rb +30 -0
  32. data/lib/badline/c64/banked_ram.rb +23 -0
  33. data/lib/badline/c64/bus/extra_sids.rb +32 -0
  34. data/lib/badline/c64/bus/fittings.rb +40 -0
  35. data/lib/badline/c64/bus/pla.rb +149 -0
  36. data/lib/badline/c64/bus/roms.rb +41 -0
  37. data/lib/badline/c64/bus/saved_state.rb +68 -0
  38. data/lib/badline/c64/bus/sid_slots.rb +44 -0
  39. data/lib/badline/c64/bus.rb +218 -0
  40. data/lib/badline/c64/cartridge/action_replay.rb +128 -0
  41. data/lib/badline/c64/cartridge/atomic_power.rb +26 -0
  42. data/lib/badline/c64/cartridge/bank.rb +83 -0
  43. data/lib/badline/c64/cartridge/comal80.rb +52 -0
  44. data/lib/badline/c64/cartridge/dinamic.rb +36 -0
  45. data/lib/badline/c64/cartridge/easy_flash.rb +147 -0
  46. data/lib/badline/c64/cartridge/epyx_fastload.rb +81 -0
  47. data/lib/badline/c64/cartridge/final_cartridge3.rb +91 -0
  48. data/lib/badline/c64/cartridge/flash/saved_state.rb +40 -0
  49. data/lib/badline/c64/cartridge/flash.rb +279 -0
  50. data/lib/badline/c64/cartridge/freezer.rb +35 -0
  51. data/lib/badline/c64/cartridge/fun_play.rb +40 -0
  52. data/lib/badline/c64/cartridge/g_mod2.rb +76 -0
  53. data/lib/badline/c64/cartridge/game_system.rb +42 -0
  54. data/lib/badline/c64/cartridge/geo_ram.rb +81 -0
  55. data/lib/badline/c64/cartridge/kcs_power.rb +77 -0
  56. data/lib/badline/c64/cartridge/mach5.rb +34 -0
  57. data/lib/badline/c64/cartridge/magic_desk.rb +32 -0
  58. data/lib/badline/c64/cartridge/ocean.rb +37 -0
  59. data/lib/badline/c64/cartridge/pagefox.rb +70 -0
  60. data/lib/badline/c64/cartridge/retro_replay/saved_state.rb +47 -0
  61. data/lib/badline/c64/cartridge/retro_replay.rb +286 -0
  62. data/lib/badline/c64/cartridge/rex_utility.rb +31 -0
  63. data/lib/badline/c64/cartridge/rgcd.rb +60 -0
  64. data/lib/badline/c64/cartridge/saved_state.rb +63 -0
  65. data/lib/badline/c64/cartridge/simons_basic.rb +37 -0
  66. data/lib/badline/c64/cartridge/standard.rb +17 -0
  67. data/lib/badline/c64/cartridge/super_games.rb +50 -0
  68. data/lib/badline/c64/cartridge/westermann.rb +32 -0
  69. data/lib/badline/c64/cartridge/zaxxon.rb +68 -0
  70. data/lib/badline/c64/cartridge.rb +258 -0
  71. data/lib/badline/c64/color_memory.rb +27 -0
  72. data/lib/badline/{computer → c64}/common.rb +2 -2
  73. data/lib/badline/{computer → c64}/kernal_traps.rb +18 -18
  74. data/lib/badline/c64/reu/dma/saved_state.rb +52 -0
  75. data/lib/badline/c64/reu/dma.rb +275 -0
  76. data/lib/badline/c64/reu/ram.rb +109 -0
  77. data/lib/badline/c64/reu/saved_state.rb +55 -0
  78. data/lib/badline/c64/reu/trigger.rb +34 -0
  79. data/lib/badline/c64/reu.rb +291 -0
  80. data/lib/badline/{computer → c64}/saved_state.rb +13 -18
  81. data/lib/badline/{computer → c64}/true_drives.rb +11 -11
  82. data/lib/badline/{computer.rb → c64.rb} +18 -13
  83. data/lib/badline/chips/cia/fast_forward.rb +62 -0
  84. data/lib/badline/chips/cia/interrupt_register.rb +145 -0
  85. data/lib/badline/chips/cia/saved_state.rb +49 -0
  86. data/lib/badline/chips/cia/serial/saved_state.rb +45 -0
  87. data/lib/badline/chips/cia/serial.rb +250 -0
  88. data/lib/badline/chips/cia/time_of_day.rb +232 -0
  89. data/lib/badline/chips/cia/timer.rb +208 -0
  90. data/lib/badline/chips/cia.rb +281 -0
  91. data/lib/badline/chips/cpu/addressing.rb +133 -0
  92. data/lib/badline/chips/cpu/boundary.rb +56 -0
  93. data/lib/badline/chips/cpu/core.rb +167 -0
  94. data/lib/badline/chips/cpu/instruction.rb +338 -0
  95. data/lib/badline/chips/cpu/instruction_set/arithmetic.rb +118 -0
  96. data/lib/badline/chips/cpu/instruction_set/bitwise.rb +130 -0
  97. data/lib/badline/chips/cpu/instruction_set/branch.rb +83 -0
  98. data/lib/badline/chips/cpu/instruction_set/flag.rb +67 -0
  99. data/lib/badline/chips/cpu/instruction_set/illegal.rb +274 -0
  100. data/lib/badline/chips/cpu/instruction_set/inc_dec.rb +73 -0
  101. data/lib/badline/chips/cpu/instruction_set/stack.rb +56 -0
  102. data/lib/badline/chips/cpu/instruction_set/transfer.rb +141 -0
  103. data/lib/badline/chips/cpu/instruction_set.rb +59 -0
  104. data/lib/badline/chips/cpu/interrupts.rb +108 -0
  105. data/lib/badline/chips/cpu/microcode.rb +179 -0
  106. data/lib/badline/chips/cpu/operations.rb +90 -0
  107. data/lib/badline/chips/cpu/port.rb +116 -0
  108. data/lib/badline/chips/cpu/saved_state.rb +117 -0
  109. data/lib/badline/chips/cpu/stack_operations.rb +84 -0
  110. data/lib/badline/chips/cpu/traps.rb +23 -0
  111. data/lib/badline/chips/cpu.rb +12 -0
  112. data/lib/badline/chips/sid/catch_up.rb +122 -0
  113. data/lib/badline/chips/sid/decimator.rb +66 -0
  114. data/lib/badline/chips/sid/envelope/saved_state.rb +70 -0
  115. data/lib/badline/chips/sid/envelope.rb +241 -0
  116. data/lib/badline/chips/sid/filter/saved_state.rb +42 -0
  117. data/lib/badline/chips/sid/filter.rb +241 -0
  118. data/lib/badline/chips/sid/saved_state.rb +52 -0
  119. data/lib/badline/chips/sid/voice.rb +79 -0
  120. data/lib/badline/chips/sid/waveform/combined.rb +128 -0
  121. data/lib/badline/chips/sid/waveform/fast_forward.rb +107 -0
  122. data/lib/badline/chips/sid/waveform/noise_writeback.rb +124 -0
  123. data/lib/badline/chips/sid/waveform/saved_state.rb +68 -0
  124. data/lib/badline/chips/sid/waveform.rb +307 -0
  125. data/lib/badline/chips/sid.rb +265 -0
  126. data/lib/badline/{c128 → chips}/vdc/memory.rb +1 -1
  127. data/lib/badline/{c128 → chips}/vdc/painter.rb +1 -1
  128. data/lib/badline/{c128 → chips}/vdc/raster.rb +1 -1
  129. data/lib/badline/chips/vdc/saved_state.rb +36 -0
  130. data/lib/badline/{c128 → chips}/vdc/window.rb +1 -1
  131. data/lib/badline/{c128 → chips}/vdc.rb +7 -31
  132. data/lib/badline/chips/via/control_lines.rb +124 -0
  133. data/lib/badline/chips/via/fast_forward.rb +55 -0
  134. data/lib/badline/chips/via/interrupt_register.rb +69 -0
  135. data/lib/badline/chips/via/saved_state.rb +44 -0
  136. data/lib/badline/chips/via/shift_register.rb +182 -0
  137. data/lib/badline/chips/via/timer1.rb +133 -0
  138. data/lib/badline/chips/via/timer2.rb +135 -0
  139. data/lib/badline/chips/via.rb +268 -0
  140. data/lib/badline/chips/vic/bank.rb +135 -0
  141. data/lib/badline/chips/vic/border_mask.rb +88 -0
  142. data/lib/badline/chips/vic/collisions.rb +117 -0
  143. data/lib/badline/chips/vic/color_patches.rb +49 -0
  144. data/lib/badline/chips/vic/display_state.rb +187 -0
  145. data/lib/badline/chips/vic/graphics_mode.rb +166 -0
  146. data/lib/badline/chips/vic/graphics_shifter/saved_state.rb +40 -0
  147. data/lib/badline/chips/vic/graphics_shifter.rb +187 -0
  148. data/lib/badline/chips/vic/register_log.rb +83 -0
  149. data/lib/badline/chips/vic/registers.rb +197 -0
  150. data/lib/badline/chips/vic/saved_state.rb +82 -0
  151. data/lib/badline/chips/vic/sequencer/saved_state.rb +91 -0
  152. data/lib/badline/chips/vic/sequencer.rb +277 -0
  153. data/lib/badline/chips/vic/sequencer_output.rb +118 -0
  154. data/lib/badline/chips/vic/sprite/internal_bus.rb +70 -0
  155. data/lib/badline/chips/vic/sprite/saved_state.rb +66 -0
  156. data/lib/badline/chips/vic/sprite/shifter.rb +148 -0
  157. data/lib/badline/chips/vic/sprite/timing.rb +58 -0
  158. data/lib/badline/chips/vic/sprite.rb +339 -0
  159. data/lib/badline/chips/vic/sprites/saved_state.rb +59 -0
  160. data/lib/badline/chips/vic/sprites.rb +284 -0
  161. data/lib/badline/chips/vic.rb +783 -0
  162. data/lib/badline/chips/vic_i/painter/saved_state.rb +40 -0
  163. data/lib/badline/{vic20/vic → chips/vic_i}/painter.rb +6 -30
  164. data/lib/badline/{vic20/vic → chips/vic_i}/saved_state.rb +2 -2
  165. data/lib/badline/chips/vic_i/sound/output.rb +85 -0
  166. data/lib/badline/chips/vic_i/sound.rb +235 -0
  167. data/lib/badline/{vic20/vic → chips/vic_i}/text_window.rb +2 -2
  168. data/lib/badline/{vic20/vic.rb → chips/vic_i.rb} +5 -5
  169. data/lib/badline/chips/z80/arithmetic.rb +119 -0
  170. data/lib/badline/chips/z80/bit_page.rb +57 -0
  171. data/lib/badline/chips/z80/block_io.rb +60 -0
  172. data/lib/badline/chips/z80/block_transfers.rb +61 -0
  173. data/lib/badline/chips/z80/bus_cycles.rb +113 -0
  174. data/lib/badline/chips/z80/core.rb +115 -0
  175. data/lib/badline/chips/z80/exchanges.rb +52 -0
  176. data/lib/badline/chips/z80/extended_page.rb +91 -0
  177. data/lib/badline/chips/z80/flags.rb +39 -0
  178. data/lib/badline/chips/z80/interrupt_acceptance.rb +48 -0
  179. data/lib/badline/chips/z80/jumps.rb +84 -0
  180. data/lib/badline/chips/z80/loads.rb +100 -0
  181. data/lib/badline/chips/z80/main_page.rb +136 -0
  182. data/lib/badline/chips/z80/registers.rb +122 -0
  183. data/lib/badline/chips/z80/saved_state.rb +71 -0
  184. data/lib/badline/chips/z80/shifts.rb +66 -0
  185. data/lib/badline/chips/z80.rb +13 -0
  186. data/lib/badline/core.rb +26 -28
  187. data/lib/badline/drives/datasette/saved_state.rb +37 -0
  188. data/lib/badline/drives/datasette.rb +140 -0
  189. data/lib/badline/drives/engine/core.rb +149 -0
  190. data/lib/badline/drives/engine/fast_serial.rb +75 -0
  191. data/lib/badline/drives/engine/idle.rb +127 -0
  192. data/lib/badline/drives/engine/idle_cpu.rb +30 -0
  193. data/lib/badline/drives/engine/orbit.rb +81 -0
  194. data/lib/badline/drives/engine/serial_lines.rb +75 -0
  195. data/lib/badline/drives/engine/sleep.rb +114 -0
  196. data/lib/badline/drives/engine/vias.rb +86 -0
  197. data/lib/badline/drives/engine/watch.rb +152 -0
  198. data/lib/badline/drives/engine.rb +11 -0
  199. data/lib/badline/drives/model1541/bus.rb +88 -0
  200. data/lib/badline/drives/model1541/byte_ready.rb +50 -0
  201. data/lib/badline/drives/model1541/cpu.rb +13 -0
  202. data/lib/badline/drives/model1541/disk/saved_state.rb +88 -0
  203. data/lib/badline/drives/model1541/disk.rb +317 -0
  204. data/lib/badline/drives/model1541/disk_via.rb +38 -0
  205. data/lib/badline/drives/model1541/gcr.rb +59 -0
  206. data/lib/badline/drives/model1541/mechanism/saved_state.rb +72 -0
  207. data/lib/badline/drives/model1541/mechanism.rb +315 -0
  208. data/lib/badline/drives/model1541/rotation.rb +123 -0
  209. data/lib/badline/drives/model1541/saved_state.rb +44 -0
  210. data/lib/badline/drives/model1541/sector_reader.rb +78 -0
  211. data/lib/badline/drives/model1541/serial_port.rb +20 -0
  212. data/lib/badline/drives/model1541/track.rb +100 -0
  213. data/lib/badline/drives/model1541.rb +81 -0
  214. data/lib/badline/drives/model1571/bus.rb +113 -0
  215. data/lib/badline/drives/model1571/cpu.rb +13 -0
  216. data/lib/badline/drives/model1571/saved_state.rb +47 -0
  217. data/lib/badline/drives/model1571/serial_port.rb +39 -0
  218. data/lib/badline/drives/model1571/serial_via.rb +27 -0
  219. data/lib/badline/drives/model1571/wd1770.rb +122 -0
  220. data/lib/badline/drives/model1571.rb +142 -0
  221. data/lib/badline/drives/model1581/bus.rb +139 -0
  222. data/lib/badline/drives/model1581/cpu.rb +13 -0
  223. data/lib/badline/drives/model1581/disk/saved_state.rb +89 -0
  224. data/lib/badline/drives/model1581/disk.rb +137 -0
  225. data/lib/badline/drives/model1581/mechanism.rb +119 -0
  226. data/lib/badline/drives/model1581/saved_state.rb +42 -0
  227. data/lib/badline/drives/model1581/serial_port.rb +54 -0
  228. data/lib/badline/drives/model1581/slot.rb +79 -0
  229. data/lib/badline/drives/model1581/track.rb +102 -0
  230. data/lib/badline/drives/model1581/track_bytes.rb +77 -0
  231. data/lib/badline/drives/model1581/wd1772/registers.rb +91 -0
  232. data/lib/badline/drives/model1581/wd1772/saved_state.rb +68 -0
  233. data/lib/badline/drives/model1581/wd1772/sector_writes.rb +75 -0
  234. data/lib/badline/drives/model1581/wd1772/sectors.rb +152 -0
  235. data/lib/badline/drives/model1581/wd1772/stepping.rb +111 -0
  236. data/lib/badline/drives/model1581/wd1772/tracks.rb +127 -0
  237. data/lib/badline/drives/model1581/wd1772/turn.rb +75 -0
  238. data/lib/badline/drives/model1581/wd1772.rb +218 -0
  239. data/lib/badline/drives/model1581.rb +206 -0
  240. data/lib/badline/drives/serial_bus.rb +161 -0
  241. data/lib/badline/frontend/boot.rb +3 -3
  242. data/lib/badline/frontend/machine_window.rb +3 -1
  243. data/lib/badline/frontend/player/filter_view.rb +1 -1
  244. data/lib/badline/frontend/player/player_controller.rb +2 -2
  245. data/lib/badline/frontend/player/player_screen.rb +1 -0
  246. data/lib/badline/frontend/player/theme.rb +7 -7
  247. data/lib/badline/frontend/timeline.rb +3 -3
  248. data/lib/badline/input/control_ports.rb +78 -0
  249. data/lib/badline/input/joystick.rb +27 -0
  250. data/lib/badline/input/keyboard.rb +114 -0
  251. data/lib/badline/input.rb +3 -0
  252. data/lib/badline/kernal_trap/{drive → dos}/block_commands.rb +1 -1
  253. data/lib/badline/kernal_trap/dos/channel.rb +183 -0
  254. data/lib/badline/kernal_trap/{drive → dos}/channels.rb +1 -1
  255. data/lib/badline/kernal_trap/{drive → dos}/memory.rb +1 -1
  256. data/lib/badline/kernal_trap/{drive → dos}/parameters.rb +1 -1
  257. data/lib/badline/kernal_trap/{drive → dos}/status.rb +1 -1
  258. data/lib/badline/kernal_trap/{drive → dos}/write_file.rb +1 -1
  259. data/lib/badline/kernal_trap/{drive → dos}/writes.rb +1 -1
  260. data/lib/badline/kernal_trap/{drive.rb → dos.rb} +11 -10
  261. data/lib/badline/kernal_trap/load.rb +5 -5
  262. data/lib/badline/kernal_trap/save.rb +4 -4
  263. data/lib/badline/kernal_trap/serial.rb +7 -7
  264. data/lib/badline/kernal_trap.rb +1 -2
  265. data/lib/badline/machine/clocking.rb +1 -1
  266. data/lib/badline/machine.rb +5 -5
  267. data/lib/badline/media/true_drive.rb +1 -1
  268. data/lib/badline/media/tune.rb +2 -2
  269. data/lib/badline/media.rb +3 -3
  270. data/lib/badline/model.rb +1 -1
  271. data/lib/badline/roms/README +6 -6
  272. data/lib/badline/sdl.rb +1 -0
  273. data/lib/badline/{storage/sid_file.rb → sid_tune/file.rb} +3 -3
  274. data/lib/badline/{storage → sid_tune}/hvsc.rb +7 -7
  275. data/lib/badline/{storage → sid_tune}/song_lengths.rb +2 -2
  276. data/lib/badline/{storage → sid_tune}/stil/credit.rb +1 -1
  277. data/lib/badline/{storage → sid_tune}/stil.rb +3 -3
  278. data/lib/badline/sid_tune.rb +6 -0
  279. data/lib/badline/snapshot/c128_setup.rb +43 -0
  280. data/lib/badline/snapshot/c64_setup.rb +79 -0
  281. data/lib/badline/snapshot/image.rb +5 -25
  282. data/lib/badline/snapshot/machine_state.rb +1 -1
  283. data/lib/badline/snapshot/setup.rb +22 -66
  284. data/lib/badline/snapshot/state.rb +8 -18
  285. data/lib/badline/snapshot/storage_setup.rb +68 -0
  286. data/lib/badline/snapshot/vic20_setup.rb +37 -0
  287. data/lib/badline/snapshot/vice/c64_mem.rb +1 -1
  288. data/lib/badline/snapshot/vice/restore.rb +1 -1
  289. data/lib/badline/snapshot/vice/reu1764.rb +1 -1
  290. data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
  291. data/lib/badline/snapshot/vice.rb +7 -5
  292. data/lib/badline/snapshot.rb +3 -4
  293. data/lib/badline/storage/d64_image.rb +0 -2
  294. data/lib/badline/storage/d71_image.rb +0 -2
  295. data/lib/badline/storage/d81_image.rb +0 -2
  296. data/lib/badline/storage/disk_image.rb +3 -6
  297. data/lib/badline/storage/g64_image.rb +2 -2
  298. data/lib/badline/storage/host_directory.rb +0 -5
  299. data/lib/badline/storage/t64.rb +2 -8
  300. data/lib/badline/storage/unavailable.rb +1 -1
  301. data/lib/badline/storage.rb +0 -37
  302. data/lib/badline/support/c128_checkpoint.rb +39 -0
  303. data/lib/badline/support/checkpoint.rb +108 -0
  304. data/lib/badline/support/vic20_checkpoint.rb +38 -0
  305. data/lib/badline/support.rb +5 -0
  306. data/lib/badline/version.rb +1 -1
  307. data/lib/badline/vic20/attachments.rb +5 -5
  308. data/lib/badline/vic20/bus/saved_state.rb +35 -0
  309. data/lib/badline/vic20/bus.rb +3 -25
  310. data/lib/badline/vic20/cpu.rb +1 -1
  311. data/lib/badline/vic20/port_wiring.rb +4 -4
  312. data/lib/badline/vic20/saved_state.rb +16 -30
  313. data/lib/badline/vic20/user_via_ports.rb +2 -2
  314. data/lib/badline/vic20.rb +19 -14
  315. metadata +245 -221
  316. data/lib/badline/address_bus/extra_sids.rb +0 -30
  317. data/lib/badline/address_bus/fittings.rb +0 -38
  318. data/lib/badline/address_bus/pla.rb +0 -147
  319. data/lib/badline/address_bus/roms.rb +0 -39
  320. data/lib/badline/address_bus/saved_state.rb +0 -66
  321. data/lib/badline/address_bus/sid_slots.rb +0 -42
  322. data/lib/badline/address_bus.rb +0 -216
  323. data/lib/badline/cartridge/action_replay.rb +0 -126
  324. data/lib/badline/cartridge/atomic_power.rb +0 -24
  325. data/lib/badline/cartridge/bank.rb +0 -81
  326. data/lib/badline/cartridge/comal80.rb +0 -50
  327. data/lib/badline/cartridge/dinamic.rb +0 -34
  328. data/lib/badline/cartridge/easy_flash.rb +0 -145
  329. data/lib/badline/cartridge/epyx_fastload.rb +0 -79
  330. data/lib/badline/cartridge/final_cartridge3.rb +0 -89
  331. data/lib/badline/cartridge/flash.rb +0 -306
  332. data/lib/badline/cartridge/freezer.rb +0 -33
  333. data/lib/badline/cartridge/fun_play.rb +0 -38
  334. data/lib/badline/cartridge/g_mod2.rb +0 -74
  335. data/lib/badline/cartridge/game_system.rb +0 -40
  336. data/lib/badline/cartridge/geo_ram.rb +0 -79
  337. data/lib/badline/cartridge/kcs_power.rb +0 -75
  338. data/lib/badline/cartridge/mach5.rb +0 -32
  339. data/lib/badline/cartridge/magic_desk.rb +0 -30
  340. data/lib/badline/cartridge/ocean.rb +0 -35
  341. data/lib/badline/cartridge/pagefox.rb +0 -68
  342. data/lib/badline/cartridge/retro_replay.rb +0 -320
  343. data/lib/badline/cartridge/rex_utility.rb +0 -29
  344. data/lib/badline/cartridge/rgcd.rb +0 -58
  345. data/lib/badline/cartridge/simons_basic.rb +0 -35
  346. data/lib/badline/cartridge/standard.rb +0 -15
  347. data/lib/badline/cartridge/super_games.rb +0 -48
  348. data/lib/badline/cartridge/westermann.rb +0 -30
  349. data/lib/badline/cartridge/zaxxon.rb +0 -66
  350. data/lib/badline/cartridge.rb +0 -303
  351. data/lib/badline/checkpoint.rb +0 -98
  352. data/lib/badline/cia/fast_forward.rb +0 -60
  353. data/lib/badline/cia/interrupt_register.rb +0 -143
  354. data/lib/badline/cia/serial.rb +0 -275
  355. data/lib/badline/cia/state.rb +0 -47
  356. data/lib/badline/cia/timer.rb +0 -206
  357. data/lib/badline/cia.rb +0 -279
  358. data/lib/badline/color_memory.rb +0 -25
  359. data/lib/badline/control_ports.rb +0 -76
  360. data/lib/badline/cpu/addressing.rb +0 -131
  361. data/lib/badline/cpu/boundary.rb +0 -54
  362. data/lib/badline/cpu/core.rb +0 -165
  363. data/lib/badline/cpu/microcode.rb +0 -177
  364. data/lib/badline/cpu/operations.rb +0 -88
  365. data/lib/badline/cpu/saved_state.rb +0 -115
  366. data/lib/badline/cpu/stack_operations.rb +0 -82
  367. data/lib/badline/cpu.rb +0 -10
  368. data/lib/badline/cpu_port.rb +0 -112
  369. data/lib/badline/datasette.rb +0 -161
  370. data/lib/badline/drive/core.rb +0 -147
  371. data/lib/badline/drive/fast_serial.rb +0 -73
  372. data/lib/badline/drive/idle.rb +0 -125
  373. data/lib/badline/drive/idle_cpu.rb +0 -28
  374. data/lib/badline/drive/orbit.rb +0 -79
  375. data/lib/badline/drive/serial_lines.rb +0 -73
  376. data/lib/badline/drive/sleep.rb +0 -112
  377. data/lib/badline/drive/vias.rb +0 -84
  378. data/lib/badline/drive/watch.rb +0 -150
  379. data/lib/badline/drive.rb +0 -11
  380. data/lib/badline/drive1541/bus.rb +0 -86
  381. data/lib/badline/drive1541/byte_ready.rb +0 -48
  382. data/lib/badline/drive1541/cpu.rb +0 -11
  383. data/lib/badline/drive1541/disk.rb +0 -315
  384. data/lib/badline/drive1541/disk_state.rb +0 -86
  385. data/lib/badline/drive1541/disk_via.rb +0 -36
  386. data/lib/badline/drive1541/gcr.rb +0 -57
  387. data/lib/badline/drive1541/mechanism.rb +0 -313
  388. data/lib/badline/drive1541/mechanism_state.rb +0 -68
  389. data/lib/badline/drive1541/rotation.rb +0 -121
  390. data/lib/badline/drive1541/sector_reader.rb +0 -76
  391. data/lib/badline/drive1541/serial_port.rb +0 -18
  392. data/lib/badline/drive1541/track.rb +0 -98
  393. data/lib/badline/drive1541.rb +0 -111
  394. data/lib/badline/drive1571/bus.rb +0 -111
  395. data/lib/badline/drive1571/cpu.rb +0 -11
  396. data/lib/badline/drive1571/serial_port.rb +0 -37
  397. data/lib/badline/drive1571/serial_via.rb +0 -25
  398. data/lib/badline/drive1571/wd1770.rb +0 -120
  399. data/lib/badline/drive1571.rb +0 -175
  400. data/lib/badline/drive1581/bus.rb +0 -137
  401. data/lib/badline/drive1581/cpu.rb +0 -11
  402. data/lib/badline/drive1581/disk.rb +0 -135
  403. data/lib/badline/drive1581/disk_state.rb +0 -87
  404. data/lib/badline/drive1581/mechanism.rb +0 -117
  405. data/lib/badline/drive1581/serial_port.rb +0 -52
  406. data/lib/badline/drive1581/slot.rb +0 -78
  407. data/lib/badline/drive1581/track.rb +0 -100
  408. data/lib/badline/drive1581/track_bytes.rb +0 -75
  409. data/lib/badline/drive1581/wd1772/registers.rb +0 -89
  410. data/lib/badline/drive1581/wd1772/sector_writes.rb +0 -73
  411. data/lib/badline/drive1581/wd1772/sectors.rb +0 -150
  412. data/lib/badline/drive1581/wd1772/state.rb +0 -66
  413. data/lib/badline/drive1581/wd1772/stepping.rb +0 -109
  414. data/lib/badline/drive1581/wd1772/tracks.rb +0 -125
  415. data/lib/badline/drive1581/wd1772/turn.rb +0 -73
  416. data/lib/badline/drive1581/wd1772.rb +0 -216
  417. data/lib/badline/drive1581.rb +0 -233
  418. data/lib/badline/iec_bus.rb +0 -159
  419. data/lib/badline/instruction.rb +0 -334
  420. data/lib/badline/instruction_set/arithmetic.rb +0 -114
  421. data/lib/badline/instruction_set/bitwise.rb +0 -126
  422. data/lib/badline/instruction_set/branch.rb +0 -79
  423. data/lib/badline/instruction_set/flag.rb +0 -63
  424. data/lib/badline/instruction_set/illegal.rb +0 -270
  425. data/lib/badline/instruction_set/inc_dec.rb +0 -69
  426. data/lib/badline/instruction_set/stack.rb +0 -52
  427. data/lib/badline/instruction_set/transfer.rb +0 -137
  428. data/lib/badline/instruction_set.rb +0 -55
  429. data/lib/badline/interrupts.rb +0 -104
  430. data/lib/badline/joystick.rb +0 -25
  431. data/lib/badline/kernal_trap/channel.rb +0 -181
  432. data/lib/badline/keyboard.rb +0 -112
  433. data/lib/badline/ram_expansion/banking.rb +0 -30
  434. data/lib/badline/ram_expansion/plus256k.rb +0 -54
  435. data/lib/badline/ram_expansion/plus60k.rb +0 -43
  436. data/lib/badline/ram_expansion/unexpanded.rb +0 -28
  437. data/lib/badline/ram_expansion.rb +0 -21
  438. data/lib/badline/reu/dma/saved_state.rb +0 -50
  439. data/lib/badline/reu/dma.rb +0 -273
  440. data/lib/badline/reu/ram.rb +0 -107
  441. data/lib/badline/reu/saved_state.rb +0 -80
  442. data/lib/badline/reu/trigger.rb +0 -32
  443. data/lib/badline/reu.rb +0 -289
  444. data/lib/badline/sid/catch_up.rb +0 -120
  445. data/lib/badline/sid/decimator.rb +0 -64
  446. data/lib/badline/sid/envelope/state.rb +0 -68
  447. data/lib/badline/sid/envelope.rb +0 -239
  448. data/lib/badline/sid/filter.rb +0 -263
  449. data/lib/badline/sid/voice.rb +0 -77
  450. data/lib/badline/sid/waveform/combined.rb +0 -126
  451. data/lib/badline/sid/waveform/fast_forward.rb +0 -105
  452. data/lib/badline/sid/waveform/noise_writeback.rb +0 -122
  453. data/lib/badline/sid/waveform/state.rb +0 -66
  454. data/lib/badline/sid/waveform.rb +0 -305
  455. data/lib/badline/sid.rb +0 -303
  456. data/lib/badline/time_of_day.rb +0 -228
  457. data/lib/badline/traps.rb +0 -19
  458. data/lib/badline/via/control_lines.rb +0 -122
  459. data/lib/badline/via/fast_forward.rb +0 -53
  460. data/lib/badline/via/interrupt_register.rb +0 -67
  461. data/lib/badline/via/shift_register.rb +0 -180
  462. data/lib/badline/via/state.rb +0 -42
  463. data/lib/badline/via/timer1.rb +0 -131
  464. data/lib/badline/via/timer2.rb +0 -133
  465. data/lib/badline/via.rb +0 -266
  466. data/lib/badline/vic/bank.rb +0 -133
  467. data/lib/badline/vic/border_mask.rb +0 -86
  468. data/lib/badline/vic/collisions.rb +0 -115
  469. data/lib/badline/vic/color_patches.rb +0 -47
  470. data/lib/badline/vic/display_state.rb +0 -185
  471. data/lib/badline/vic/graphics_mode.rb +0 -164
  472. data/lib/badline/vic/graphics_shifter.rb +0 -207
  473. data/lib/badline/vic/register_log.rb +0 -81
  474. data/lib/badline/vic/registers.rb +0 -195
  475. data/lib/badline/vic/sequencer.rb +0 -275
  476. data/lib/badline/vic/sequencer_output.rb +0 -116
  477. data/lib/badline/vic/sequencer_state.rb +0 -89
  478. data/lib/badline/vic/sprite/internal_bus.rb +0 -68
  479. data/lib/badline/vic/sprite/saved_state.rb +0 -64
  480. data/lib/badline/vic/sprite/shifter.rb +0 -146
  481. data/lib/badline/vic/sprite/timing.rb +0 -56
  482. data/lib/badline/vic/sprite.rb +0 -337
  483. data/lib/badline/vic/sprites.rb +0 -282
  484. data/lib/badline/vic/sprites_state.rb +0 -57
  485. data/lib/badline/vic.rb +0 -853
  486. data/lib/badline/vic20/sound/output.rb +0 -83
  487. data/lib/badline/vic20/sound.rb +0 -233
  488. data/lib/badline/z80/arithmetic.rb +0 -117
  489. data/lib/badline/z80/bit_page.rb +0 -55
  490. data/lib/badline/z80/block_io.rb +0 -58
  491. data/lib/badline/z80/block_transfers.rb +0 -59
  492. data/lib/badline/z80/bus_cycles.rb +0 -111
  493. data/lib/badline/z80/core.rb +0 -113
  494. data/lib/badline/z80/exchanges.rb +0 -50
  495. data/lib/badline/z80/extended_page.rb +0 -89
  496. data/lib/badline/z80/flags.rb +0 -37
  497. data/lib/badline/z80/interrupt_acceptance.rb +0 -46
  498. data/lib/badline/z80/jumps.rb +0 -82
  499. data/lib/badline/z80/loads.rb +0 -98
  500. data/lib/badline/z80/main_page.rb +0 -134
  501. data/lib/badline/z80/registers.rb +0 -120
  502. data/lib/badline/z80/saved_state.rb +0 -69
  503. data/lib/badline/z80/shifts.rb +0 -64
  504. data/lib/badline/z80.rb +0 -11
  505. /data/lib/badline/snapshot/{fields.rb → vice/fields.rb} +0 -0
@@ -0,0 +1,265 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/chips/sid/waveform"
4
+ require "badline/chips/sid/envelope"
5
+ require "badline/chips/sid/voice"
6
+ require "badline/chips/sid/filter"
7
+ require "badline/chips/sid/decimator"
8
+ require "badline/chips/sid/catch_up"
9
+ require "badline/chips/sid/saved_state"
10
+
11
+ module Badline
12
+ module Chips
13
+ # SID (Sound Interface Device) chip, in either the 6581 or the 8580
14
+ # revision.
15
+ #
16
+ # $D400-$D418 - Voices, filter and volume - write only
17
+ # $D419-$D41A - POTX/POTY paddle inputs - read only
18
+ # $D41B-$D41C - Voice 3 oscillator/envelope - read only
19
+ # $D41D-$D41F - Unconnected
20
+ #
21
+ # The register file mirrors every 32 bytes up to $D7FF. A second or
22
+ # third SID, which only the SID player fits, is built `at` another
23
+ # address and decodes just the 32 bytes there.
24
+ #
25
+ # Reading a write-only or unconnected register returns the last byte the
26
+ # SID saw on the data bus. That value fades to $00 as the capacitance
27
+ # holding it drains. Paddles and the 1351 mouse attach as a pots source
28
+ # responding to #pot_x and #pot_y; with none attached the lines read $FF.
29
+ #
30
+ # Three voices feed the filter and the master volume; #output and #sample
31
+ # read out the mixed result, and #record collects it at an audio rate for
32
+ # #drain_samples. The DSP is clocked lazily and catches up when something
33
+ # asks for its state.
34
+ #
35
+ # The 6581 drives its voices well above ground, so the mix carries a large
36
+ # DC offset that the RC network on the C64 board filters out.
37
+ class SID
38
+ include Addressable
39
+ include CatchUp
40
+ include SavedState
41
+
42
+ VOICES = 3
43
+
44
+ # Cycles the data bus holds a value, measured through SID/bitfade.
45
+ BUS_TTL = { mos6581: 0x1d00, mos8580: 0xa2000 }.freeze
46
+
47
+ # Scales the filter's 20-bit mix down to a signed 16-bit sample, as
48
+ # reSID 0.16 does: three voices at full swing and volume 15 span the
49
+ # whole range, on either chip.
50
+ SAMPLE_DIVISOR = ((0xfff * 0xff) >> 7) * 3 * 15 * 2 / (2**16)
51
+
52
+ # Writes the DSP queues between catch-ups. A full queue catches up
53
+ # there and then, so no write loses its timing.
54
+ DEFERRED_WRITES = 0x400
55
+
56
+ # Cycles the filter integrates in one step while synthesizing, after
57
+ # reSID's delta_t_flt. 1 makes the audio exact, at a per-cycle cost.
58
+ FILTER_CHUNK = 4
59
+
60
+ attr_accessor :pots
61
+ attr_reader :model
62
+
63
+ def initialize(model: :mos6581, pots: nil, filter_chunk: FILTER_CHUNK, at: 0xd400)
64
+ addressable_at(at, length: at == 0xd400 ? 2**10 : 2**5)
65
+ @model = model
66
+ @pots = pots
67
+ @bus_ttl_reset = BUS_TTL.fetch(model)
68
+ @filter = Filter.new(model:)
69
+ @synthesizing = false
70
+ @stepped = @synced = false
71
+ @pending_cycles = 0
72
+ @deferred_writes = []
73
+ @decimator = nil
74
+ @samples = []
75
+ @voice_samples = nil
76
+ @filter_chunk = filter_chunk
77
+ @voices = Voice.linked(VOICES, model:)
78
+ @voice1, @voice2, @voice3 = @voices
79
+ @waveform1, @waveform2, @waveform3 = @voices.map(&:waveform)
80
+ reset!
81
+ end
82
+
83
+ # Switches the chip, its filter and its voices to the other model's
84
+ # values. The cycles already passed run on the old model first, and the
85
+ # running state carries over.
86
+ def model=(model)
87
+ catch_up
88
+ @model = model
89
+ @bus_ttl_reset = BUS_TTL.fetch(model)
90
+ @filter.model = model
91
+ @voices.each { |voice| voice.model = model }
92
+ update_span_rules
93
+ end
94
+
95
+ # The RES line clears the registers, the data bus, the filter and the
96
+ # voices, all but their accumulators. Recording carries on across it.
97
+ def reset!
98
+ catch_up
99
+ @registers = Memory.new(length: 2**5)
100
+ @bus_value = 0x00
101
+ @bus_ttl = 0
102
+ @voices.each(&:reset!)
103
+ @filter.reset
104
+ update_span_rules
105
+ end
106
+
107
+ # The DSP only counts cycles as they pass. Whatever asks for its state
108
+ # catches it up, a span at a time: each span fast-forwards the voices
109
+ # and ends on one whole cycle, so everything the CPU can read stays
110
+ # exact. The filter only runs once something wants audio.
111
+ def synthesizing? = @synthesizing
112
+
113
+ def synthesize!
114
+ return if @synthesizing
115
+
116
+ @synthesizing = true
117
+ update_span_rules
118
+ catch_up
119
+ end
120
+
121
+ # Starts collecting the output, averaged down to `rate` samples a
122
+ # second, for #drain_samples. `filter_chunk` overrides the one the SID
123
+ # was built with, for a machine that built its own. `clock_hz` is the
124
+ # rate the SID's cycles are taken to run at.
125
+ def record(rate:, filter_chunk: @filter_chunk, clock_hz: Region::PAL.clock_hz)
126
+ synthesize!
127
+ catch_up
128
+ @filter_chunk = filter_chunk
129
+ @decimator = Decimator.new(clock_hz:, rate:)
130
+ @samples = []
131
+ end
132
+
133
+ # Also keeps each voice's own output, before the filter and the volume,
134
+ # as each recorded sample closes, for #drain_voice_samples.
135
+ def record_voices!
136
+ @voice_samples = [] if @voice_samples.nil?
137
+ end
138
+
139
+ # The voices' outputs since the last drain, three to a sample, in voice
140
+ # order, or nothing unless #record_voices! asked for them.
141
+ def drain_voice_samples
142
+ return [] if @voice_samples.nil?
143
+
144
+ catch_up
145
+ samples = @voice_samples
146
+ @voice_samples = []
147
+ samples
148
+ end
149
+
150
+ # The samples recorded since the last drain.
151
+ def drain_samples
152
+ catch_up
153
+ samples = @samples
154
+ @samples = []
155
+ samples
156
+ end
157
+
158
+ def voices
159
+ catch_up
160
+ @voices
161
+ end
162
+
163
+ # Runs the DSP up to the current cycle.
164
+ def catch_up! = catch_up
165
+
166
+ # The byte the data bus holds and the cycles until it fades.
167
+ def bus_state = [@bus_value, @bus_ttl]
168
+
169
+ def restore_bus(value, ttl)
170
+ @bus_value = value
171
+ @bus_ttl = ttl
172
+ end
173
+
174
+ def filter
175
+ catch_up
176
+ @filter
177
+ end
178
+
179
+ # Voice 3's oscillator and envelope, the only synthesis state the CPU
180
+ # can see. Programs poll OSC3 with the noise waveform selected for
181
+ # random numbers, and ENV3 to time hard restarts.
182
+ def osc3
183
+ catch_up
184
+ @waveform3.osc3 >> 4
185
+ end
186
+
187
+ def env3
188
+ catch_up
189
+ @voice3.envelope.env3
190
+ end
191
+
192
+ def output
193
+ synthesize!
194
+ catch_up
195
+ @filter.output
196
+ end
197
+
198
+ def sample
199
+ output
200
+ current_sample
201
+ end
202
+
203
+ def cycle!
204
+ age_bus if @bus_ttl != 0
205
+ @pending_cycles += 1
206
+ end
207
+
208
+ def peek(addr)
209
+ case offset_of(addr) % (2**5)
210
+ when 0x19 then latch(pots ? pots.pot_x : 0xff)
211
+ when 0x1a then latch(pots ? pots.pot_y : 0xff)
212
+ when 0x1b then latch(osc3)
213
+ when 0x1c then latch(env3)
214
+ else @bus_value
215
+ end
216
+ end
217
+
218
+ def poke(addr, value)
219
+ reg = offset_of(addr) % (2**5)
220
+ write_register(reg, value) if reg <= 0x18
221
+ latch(value)
222
+ end
223
+
224
+ # Register contents as written, for save states and debugging.
225
+ def register(reg) = @registers.peek(reg)
226
+
227
+ private
228
+
229
+ def latch(value)
230
+ @bus_ttl = @bus_ttl_reset
231
+ @bus_value = value
232
+ end
233
+
234
+ def age_bus
235
+ @bus_ttl -= 1
236
+ @bus_value = 0x00 if @bus_ttl.zero?
237
+ end
238
+
239
+ def write_register(reg, value)
240
+ @registers.poke(reg, value)
241
+ catch_up if @deferred_writes.length == DEFERRED_WRITES * 3
242
+ @deferred_writes.push(@pending_cycles, reg, value)
243
+ end
244
+
245
+ def apply_write(reg, value)
246
+ reg < 0x15 ? write_voice(reg, value) : @filter.write(reg, value)
247
+ end
248
+
249
+ def write_voice(reg, value)
250
+ voice = @voices[reg / 7]
251
+ case reg % 7
252
+ when 0 then voice.waveform.frequency_low = value
253
+ when 1 then voice.waveform.frequency_high = value
254
+ when 2 then voice.waveform.pulse_width_low = value
255
+ when 3 then voice.waveform.pulse_width_high = value
256
+ when 4
257
+ voice.control = value
258
+ update_span_rules
259
+ when 5 then voice.envelope.attack_decay = value
260
+ when 6 then voice.envelope.sustain_release = value
261
+ end
262
+ end
263
+ end
264
+ end
265
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class C128
4
+ module Chips
5
5
  class VDC
6
6
  # The VDC's own DRAM: 16K of two 4416s (16K by 4) or 64K of 4164s or
7
7
  # 4464s, behind the 16-bit addresses the VDC computes.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class C128
4
+ module Chips
5
5
  class VDC
6
6
  # Paints the VDC's scan lines into its display, one line at a time,
7
7
  # from the registers as they stand when the line ends. Each pixel of
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class C128
4
+ module Chips
5
5
  class VDC
6
6
  # The VDC's raster: R0 + 1 characters a line, R9 + 1 lines a row,
7
7
  # R4 + 1 rows a frame and then R5 more lines, with the frame's size
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VDC
6
+ # The VDC's state for a snapshot.
7
+ module SavedState
8
+ # Everything the VDC holds but its display, which it paints again
9
+ # while it renders: the registers, the RAM, the data port and the
10
+ # raster. Whether it renders is the host's.
11
+ def save_state(out)
12
+ out.marker("VDC")
13
+ out.ints(@registers).blob(@memory.ram)
14
+ out.int(@selected).int(@read_latch).int(@write_data).int(@busy_until).int(@phase).int(@line_units)
15
+ @raster.save_state(out)
16
+ @painter.save_state(out)
17
+ end
18
+
19
+ def load_state(input)
20
+ input.marker("VDC")
21
+ input.ints_into(@registers)
22
+ input.blob_into(@memory.ram)
23
+ @memory.mode64 = @registers[28].anybits?(0x10)
24
+ @selected = input.int
25
+ @read_latch = input.int
26
+ @write_data = input.int
27
+ @busy_until = input.int
28
+ @phase = input.int
29
+ @line_units = input.int
30
+ @raster.load_state(input)
31
+ @painter.load_state(input)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class C128
4
+ module Chips
5
5
  class VDC
6
6
  # Paints the characters of a displayed line, R1 of them from the
7
7
  # line's first dot, in text mode or, with R25 bit 7, bitmap mode.
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "badline/c128/vdc/memory"
4
- require "badline/c128/vdc/window"
5
- require "badline/c128/vdc/painter"
6
- require "badline/c128/vdc/raster"
3
+ require "badline/chips/vdc/memory"
4
+ require "badline/chips/vdc/window"
5
+ require "badline/chips/vdc/painter"
6
+ require "badline/chips/vdc/raster"
7
+ require "badline/chips/vdc/saved_state"
7
8
 
8
9
  module Badline
9
- class C128
10
+ module Chips
10
11
  # The 8563 or 8568 VDC: the address register at $D600 and the data
11
12
  # register at $D601, mirrored through $D6FF, in front of 37 internal
12
13
  # registers (38 on the 8568), the VDC's own RAM (Memory) and its 80
@@ -33,6 +34,7 @@ module Badline
33
34
  # fills or two per byte it copies.
34
35
  class VDC
35
36
  include Addressable
37
+ include SavedState
36
38
 
37
39
  STATUS_READY = 0x80
38
40
  STATUS_VBLANK = 0x20
@@ -112,32 +114,6 @@ module Badline
112
114
  @painter.clear!
113
115
  end
114
116
 
115
- # Everything the VDC holds but its display, which it paints again
116
- # while it renders: the registers, the RAM, the data port and the
117
- # raster. Whether it renders is the host's.
118
- def save_state(out)
119
- out.marker("VDC")
120
- out.ints(@registers).blob(@memory.ram)
121
- out.int(@selected).int(@read_latch).int(@write_data).int(@busy_until).int(@phase).int(@line_units)
122
- @raster.save_state(out)
123
- @painter.save_state(out)
124
- end
125
-
126
- def load_state(input)
127
- input.marker("VDC")
128
- input.ints_into(@registers)
129
- input.blob_into(@memory.ram)
130
- @memory.mode64 = @registers[28].anybits?(0x10)
131
- @selected = input.int
132
- @read_latch = input.int
133
- @write_data = input.int
134
- @busy_until = input.int
135
- @phase = input.int
136
- @line_units = input.int
137
- @raster.load_state(input)
138
- @painter.load_state(input)
139
- end
140
-
141
117
  # The frames the raster has finished, which the blinking counts.
142
118
  def frame = @raster.frame
143
119
 
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIA
6
+ # One port's pair of control lines, CA1 and CA2 or CB1 and CB2, set up
7
+ # by a nibble of the peripheral control register, and their two
8
+ # interrupt flags. Bit 0 picks the active edge of C1, rising when set.
9
+ # Bits 3-1 pick the C2 mode:
10
+ #
11
+ # 000 input, falling edge 100 handshake output
12
+ # 001 independent, falling 101 pulse output
13
+ # 010 input, rising edge 110 low output
14
+ # 011 independent, rising 111 high output
15
+ #
16
+ # A port access clears both flags, but an independent input keeps C2's.
17
+ # In handshake mode C2 goes low on a port access and back high on the
18
+ # next active C1 edge. In pulse mode it goes low for the cycle after the
19
+ # access. Port A handshakes on reads and writes, port B on writes only.
20
+ class ControlLines
21
+ attr_reader :control, :c1_high, :c2_high
22
+
23
+ # The level driven on C2, high while it is an input.
24
+ attr_reader :c2_output
25
+
26
+ def initialize(interrupts, c1_flag:, c2_flag:, handshake_on_read:)
27
+ @interrupts = interrupts
28
+ @c1_flag = c1_flag
29
+ @c2_flag = c2_flag
30
+ @handshake_on_read = handshake_on_read
31
+ @c1_high = @c2_high = true
32
+ reset!
33
+ end
34
+
35
+ # Back to input mode with both handshake outputs released. The input
36
+ # levels carry over.
37
+ def reset!
38
+ @control = 0
39
+ @handshake_low = false
40
+ @pulse = 0
41
+ drive
42
+ end
43
+
44
+ def control=(nibble)
45
+ @control = nibble & 0x0f
46
+ drive
47
+ end
48
+
49
+ # Only the pulse output needs the clock.
50
+ def pulsing? = @pulse.positive?
51
+
52
+ def cycle!
53
+ @pulse -= 1
54
+ drive if @pulse.zero?
55
+ end
56
+
57
+ def active_c1_edge?(high) = high == @control.anybits?(0x01)
58
+
59
+ # The lines' levels and mode. Which flags they set, and whether reads
60
+ # handshake, are the port's wiring.
61
+ def save_state(out)
62
+ out.int(@control).boolean(@c1_high).boolean(@c2_high).boolean(@handshake_low).int(@pulse).boolean(@c2_output)
63
+ end
64
+
65
+ def load_state(input)
66
+ @control = input.int
67
+ @c1_high = input.boolean?
68
+ @c2_high = input.boolean?
69
+ @handshake_low = input.boolean?
70
+ @pulse = input.int
71
+ @c2_output = input.boolean?
72
+ end
73
+
74
+ # Everything the lines hold, for comparing them at two points.
75
+ def state = [@control, @c1_high, @c2_high, @handshake_low, @pulse, @c2_output]
76
+
77
+ # A new C1 level. An active edge sets the flag and ends a handshake.
78
+ def c1=(high)
79
+ return if high == @c1_high
80
+
81
+ @c1_high = high
82
+ return unless active_c1_edge?(high)
83
+
84
+ @handshake_low = false
85
+ drive
86
+ @interrupts.set(@c1_flag)
87
+ end
88
+
89
+ # A new C2 level. An active edge sets the flag while C2 is an input.
90
+ def c2=(high)
91
+ return if high == @c2_high
92
+
93
+ @c2_high = high
94
+ @interrupts.set(@c2_flag) if @control.nobits?(0x08) && high == @control.anybits?(0x04)
95
+ end
96
+
97
+ # A read or write of the handshaking port register.
98
+ def access!(write)
99
+ @interrupts.clear(independent? ? @c1_flag : @c1_flag | @c2_flag)
100
+ return unless write || @handshake_on_read
101
+
102
+ case @control >> 1
103
+ when 4 then @handshake_low = true
104
+ when 5 then @pulse = 2
105
+ end
106
+ drive
107
+ end
108
+
109
+ private
110
+
111
+ def independent? = @control & 0x0a == 0x02
112
+
113
+ def drive
114
+ @c2_output = case @control >> 1
115
+ when 4 then !@handshake_low
116
+ when 5 then @pulse.zero?
117
+ when 6 then false
118
+ else true
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIA
6
+ # Running a VIA a stretch of cycles at once while nothing but its
7
+ # counters would change, for Drives::Engine::Idle.
8
+ module FastForward
9
+ # quiet_cycles for a VIA that will never set a flag of its own.
10
+ QUIET = 1 << 40
11
+
12
+ # How many cycles the VIA can run with nothing but its counters
13
+ # changing: no flag set, no pulse on a control line and no bit
14
+ # shifted. See Drives::Engine::Idle.
15
+ def quiet_cycles
16
+ return 0 if @sr_uses_t2 || @shift_register.clocking? || @ca.pulsing? || @cb.pulsing?
17
+
18
+ [@t1.quiet_cycles, @t2.quiet_cycles].min
19
+ end
20
+
21
+ # Runs +cycles+ cycles at once, as many as quiet_cycles allows, which
22
+ # moves only the counters.
23
+ def fast_forward(cycles)
24
+ return if cycles.zero?
25
+
26
+ @t1.fast_forward(cycles)
27
+ @t2.fast_forward(cycles)
28
+ end
29
+
30
+ # The counters an orbit (see Drives::Engine::Idle) has to bring back: those
31
+ # of the armed timers, and of the timers +touched+ names (bit 0 for
32
+ # timer 1, bit 1 for timer 2). The others only count.
33
+ def counter_state(touched)
34
+ [(@t1.count_state if @t1.armed? || touched.anybits?(1)),
35
+ (@t2.count_state if @t2.armed? || touched.anybits?(2))]
36
+ end
37
+
38
+ # Runs +cycles+ cycles of whole orbits at once: the counters
39
+ # counter_state leaves out move on, and the rest come back round.
40
+ def skip_orbits(cycles, touched)
41
+ @t1.fast_forward(cycles) unless @t1.armed? || touched.anybits?(1)
42
+ @t2.fast_forward(cycles) unless @t2.armed? || touched.anybits?(2)
43
+ end
44
+
45
+ # Everything the VIA holds but its counters, for comparing it at two
46
+ # points. Timer 1's PB7 level counts only while ACR bit 7 puts it on
47
+ # the pin: nothing reads it otherwise.
48
+ def idle_state
49
+ [@ora, @orb, @ddra, @ddrb, @latch_a, @latch_b, @acr, @pcr, @pb6_high, @ifr.flags, @ifr.enable,
50
+ @acr.anybits?(0x80) && @t1.pb7, *@t1.state, *@t2.state, *@ca.state, *@cb.state, *@shift_register.state]
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIA
6
+ # The interrupt flag and enable registers. Each source has a flag bit,
7
+ # and IRQ is pulled low while any flag is set with its enable bit.
8
+ class InterruptRegister
9
+ CA2 = 0x01
10
+ CA1 = 0x02
11
+ SR = 0x04
12
+ CB2 = 0x08
13
+ CB1 = 0x10
14
+ TIMER2 = 0x20
15
+ TIMER1 = 0x40
16
+
17
+ attr_reader :flags, :enable
18
+
19
+ def initialize
20
+ reset!
21
+ end
22
+
23
+ def reset!
24
+ @flags = 0x00
25
+ @enable = 0x00
26
+ end
27
+
28
+ def save_state(out)
29
+ out.int(@flags).int(@enable)
30
+ end
31
+
32
+ def load_state(input)
33
+ @flags = input.int
34
+ @enable = input.int
35
+ end
36
+
37
+ def set(bits)
38
+ @flags |= bits
39
+ end
40
+
41
+ def clear(bits)
42
+ @flags &= ~bits
43
+ end
44
+
45
+ def irq? = @flags.anybits?(@enable)
46
+
47
+ # Bit 7 reads the IRQ output.
48
+ def read = irq? ? @flags | 0x80 : @flags
49
+
50
+ # Writing 1s clears the flags; bit 7 is ignored.
51
+ def write(value)
52
+ clear(value & 0x7f)
53
+ end
54
+
55
+ # Bit 7 reads as 1.
56
+ def read_enable = @enable | 0x80
57
+
58
+ # Bit 7 picks between setting and clearing the enable bits given.
59
+ def write_enable(value)
60
+ if value.anybits?(0x80)
61
+ @enable |= value & 0x7f
62
+ else
63
+ @enable &= ~value & 0x7f
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIA
6
+ # Saving and restoring a VIA for a snapshot.
7
+ module SavedState
8
+ # The registers, the timers, the shift register, the interrupt flags
9
+ # and the control lines. The peripheral is the drive's wiring.
10
+ def save_state(out)
11
+ out.int(@ora).int(@orb).int(@ddra).int(@ddrb).int(@latch_a).int(@latch_b).int(@acr).int(@pcr)
12
+ out.boolean(@pb6_high).boolean(@sr_uses_t2)
13
+ @t1.save_state(out)
14
+ @t2.save_state(out)
15
+ @shift_register.save_state(out)
16
+ @ifr.save_state(out)
17
+ @ca.save_state(out)
18
+ @cb.save_state(out)
19
+ end
20
+
21
+ # Puts the state back without telling the peripheral, which restores
22
+ # its own.
23
+ def load_state(input)
24
+ @ora = input.int
25
+ @orb = input.int
26
+ @ddra = input.int
27
+ @ddrb = input.int
28
+ @latch_a = input.int
29
+ @latch_b = input.int
30
+ @acr = input.int
31
+ @pcr = input.int
32
+ @pb6_high = input.boolean?
33
+ @sr_uses_t2 = input.boolean?
34
+ @t1.load_state(input)
35
+ @t2.load_state(input)
36
+ @shift_register.load_state(input)
37
+ @ifr.load_state(input)
38
+ @ca.load_state(input)
39
+ @cb.load_state(input)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end