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
data/lib/badline/sid.rb DELETED
@@ -1,303 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "badline/sid/waveform"
4
- require "badline/sid/envelope"
5
- require "badline/sid/voice"
6
- require "badline/sid/filter"
7
- require "badline/sid/decimator"
8
- require "badline/sid/catch_up"
9
-
10
- module Badline
11
- # SID (Sound Interface Device) chip, in either the 6581 or the 8580
12
- # revision.
13
- #
14
- # $D400-$D418 - Voices, filter and volume - write only
15
- # $D419-$D41A - POTX/POTY paddle inputs - read only
16
- # $D41B-$D41C - Voice 3 oscillator/envelope - read only
17
- # $D41D-$D41F - Unconnected
18
- #
19
- # The register file mirrors every 32 bytes up to $D7FF. A second or
20
- # third SID, which only the SID player fits, is built `at` another
21
- # address and decodes just the 32 bytes there.
22
- #
23
- # Reading a write-only or unconnected register returns the last byte the
24
- # SID saw on the data bus. That value fades to $00 as the capacitance
25
- # holding it drains. Paddles and the 1351 mouse attach as a pots source
26
- # responding to #pot_x and #pot_y; with none attached the lines read $FF.
27
- #
28
- # Three voices feed the filter and the master volume; #output and #sample
29
- # read out the mixed result, and #record collects it at an audio rate for
30
- # #drain_samples. The DSP is clocked lazily and catches up when something
31
- # asks for its state.
32
- #
33
- # The 6581 drives its voices well above ground, so the mix carries a large
34
- # DC offset that the RC network on the C64 board filters out.
35
- class SID
36
- include Addressable
37
- include CatchUp
38
-
39
- VOICES = 3
40
-
41
- # Cycles the data bus holds a value, measured through SID/bitfade.
42
- BUS_TTL = { mos6581: 0x1d00, mos8580: 0xa2000 }.freeze
43
-
44
- # Scales the filter's 20-bit mix down to a signed 16-bit sample, as
45
- # reSID 0.16 does: three voices at full swing and volume 15 span the
46
- # whole range, on either chip.
47
- SAMPLE_DIVISOR = ((0xfff * 0xff) >> 7) * 3 * 15 * 2 / (2**16)
48
-
49
- # Writes the DSP queues between catch-ups. A full queue catches up
50
- # there and then, so no write loses its timing.
51
- DEFERRED_WRITES = 0x400
52
-
53
- # Cycles the filter integrates in one step while synthesizing, after
54
- # reSID's delta_t_flt. 1 makes the audio exact, at a per-cycle cost.
55
- FILTER_CHUNK = 4
56
-
57
- attr_accessor :pots
58
- attr_reader :model
59
-
60
- def initialize(model: :mos6581, pots: nil, filter_chunk: FILTER_CHUNK, at: 0xd400)
61
- addressable_at(at, length: at == 0xd400 ? 2**10 : 2**5)
62
- @model = model
63
- @pots = pots
64
- @bus_ttl_reset = BUS_TTL.fetch(model)
65
- @filter = Filter.new(model:)
66
- @synthesizing = false
67
- @stepped = @synced = false
68
- @pending_cycles = 0
69
- @deferred_writes = []
70
- @decimator = nil
71
- @samples = []
72
- @voice_samples = nil
73
- @filter_chunk = filter_chunk
74
- @voices = Voice.linked(VOICES, model:)
75
- @voice1, @voice2, @voice3 = @voices
76
- @waveform1, @waveform2, @waveform3 = @voices.map(&:waveform)
77
- reset!
78
- end
79
-
80
- # Switches the chip, its filter and its voices to the other model's
81
- # values. The cycles already passed run on the old model first, and the
82
- # running state carries over.
83
- def model=(model)
84
- catch_up
85
- @model = model
86
- @bus_ttl_reset = BUS_TTL.fetch(model)
87
- @filter.model = model
88
- @voices.each { |voice| voice.model = model }
89
- update_span_rules
90
- end
91
-
92
- # The RES line clears the registers, the data bus, the filter and the
93
- # voices, all but their accumulators. Recording carries on across it.
94
- def reset!
95
- catch_up
96
- @registers = Memory.new(length: 2**5)
97
- @bus_value = 0x00
98
- @bus_ttl = 0
99
- @voices.each(&:reset!)
100
- @filter.reset
101
- update_span_rules
102
- end
103
-
104
- # The DSP only counts cycles as they pass. Whatever asks for its state
105
- # catches it up, a span at a time: each span fast-forwards the voices
106
- # and ends on one whole cycle, so everything the CPU can read stays
107
- # exact. The filter only runs once something wants audio.
108
- def synthesizing? = @synthesizing
109
-
110
- def synthesize!
111
- return if @synthesizing
112
-
113
- @synthesizing = true
114
- update_span_rules
115
- catch_up
116
- end
117
-
118
- # Starts collecting the output, averaged down to `rate` samples a
119
- # second, for #drain_samples. `filter_chunk` overrides the one the SID
120
- # was built with, for a machine that built its own. `clock_hz` is the
121
- # rate the SID's cycles are taken to run at.
122
- def record(rate:, filter_chunk: @filter_chunk, clock_hz: TimeOfDay::CLOCK_HZ)
123
- synthesize!
124
- catch_up
125
- @filter_chunk = filter_chunk
126
- @decimator = Decimator.new(clock_hz:, rate:)
127
- @samples = []
128
- end
129
-
130
- # How far the recording has got into the sample it is averaging, for
131
- # a host that carries on recording from a saved state: it calls
132
- # #record, then #load_recording.
133
- def save_recording(out)
134
- decimator = @decimator
135
- raise ArgumentError, "the SID isn't recording" if decimator.nil?
136
-
137
- out.marker("RECORDING")
138
- decimator.save_state(out)
139
- end
140
-
141
- def load_recording(input)
142
- decimator = @decimator
143
- raise ArgumentError, "the SID isn't recording" if decimator.nil?
144
-
145
- input.marker("RECORDING")
146
- decimator.load_state(input)
147
- end
148
-
149
- # Also keeps each voice's own output, before the filter and the volume,
150
- # as each recorded sample closes, for #drain_voice_samples.
151
- def record_voices!
152
- @voice_samples = [] if @voice_samples.nil?
153
- end
154
-
155
- # The voices' outputs since the last drain, three to a sample, in voice
156
- # order, or nothing unless #record_voices! asked for them.
157
- def drain_voice_samples
158
- return [] if @voice_samples.nil?
159
-
160
- catch_up
161
- samples = @voice_samples
162
- @voice_samples = []
163
- samples
164
- end
165
-
166
- # The samples recorded since the last drain.
167
- def drain_samples
168
- catch_up
169
- samples = @samples
170
- @samples = []
171
- samples
172
- end
173
-
174
- def voices
175
- catch_up
176
- @voices
177
- end
178
-
179
- # Runs the DSP up to the current cycle.
180
- def catch_up! = catch_up
181
-
182
- # The byte the data bus holds and the cycles until it fades.
183
- def bus_state = [@bus_value, @bus_ttl]
184
-
185
- def restore_bus(value, ttl)
186
- @bus_value = value
187
- @bus_ttl = ttl
188
- end
189
-
190
- def filter
191
- catch_up
192
- @filter
193
- end
194
-
195
- # Voice 3's oscillator and envelope, the only synthesis state the CPU
196
- # can see. Programs poll OSC3 with the noise waveform selected for
197
- # random numbers, and ENV3 to time hard restarts.
198
- def osc3
199
- catch_up
200
- @waveform3.osc3 >> 4
201
- end
202
-
203
- def env3
204
- catch_up
205
- @voice3.envelope.env3
206
- end
207
-
208
- def output
209
- synthesize!
210
- catch_up
211
- @filter.output
212
- end
213
-
214
- def sample
215
- output
216
- current_sample
217
- end
218
-
219
- def cycle!
220
- age_bus if @bus_ttl != 0
221
- @pending_cycles += 1
222
- end
223
-
224
- def peek(addr)
225
- case offset_of(addr) % (2**5)
226
- when 0x19 then latch(pots ? pots.pot_x : 0xff)
227
- when 0x1a then latch(pots ? pots.pot_y : 0xff)
228
- when 0x1b then latch(osc3)
229
- when 0x1c then latch(env3)
230
- else @bus_value
231
- end
232
- end
233
-
234
- def poke(addr, value)
235
- reg = offset_of(addr) % (2**5)
236
- write_register(reg, value) if reg <= 0x18
237
- latch(value)
238
- end
239
-
240
- # Register contents as written, for save states and debugging.
241
- def register(reg) = @registers.peek(reg)
242
-
243
- # The registers, the data bus, the voices and the filter, and the span
244
- # the DSP has yet to catch up on, as it stands: saving leaves the SID
245
- # as it was. Whether it synthesizes or records is the host's.
246
- def save_state(out)
247
- out.marker("SID")
248
- @registers.save_state(out)
249
- out.int(@bus_value).int(@bus_ttl).int(@pending_cycles).ints(@deferred_writes)
250
- @voices.each { |voice| voice.save_state(out) }
251
- @filter.save_state(out)
252
- end
253
-
254
- def load_state(input)
255
- input.marker("SID")
256
- @registers.load_state(input)
257
- @bus_value = input.int
258
- @bus_ttl = input.int
259
- @pending_cycles = input.int
260
- input.ints_into(@deferred_writes)
261
- @voices.each { |voice| voice.load_state(input) }
262
- @filter.load_state(input)
263
- update_span_rules
264
- end
265
-
266
- private
267
-
268
- def latch(value)
269
- @bus_ttl = @bus_ttl_reset
270
- @bus_value = value
271
- end
272
-
273
- def age_bus
274
- @bus_ttl -= 1
275
- @bus_value = 0x00 if @bus_ttl.zero?
276
- end
277
-
278
- def write_register(reg, value)
279
- @registers.poke(reg, value)
280
- catch_up if @deferred_writes.length == DEFERRED_WRITES * 3
281
- @deferred_writes.push(@pending_cycles, reg, value)
282
- end
283
-
284
- def apply_write(reg, value)
285
- reg < 0x15 ? write_voice(reg, value) : @filter.write(reg, value)
286
- end
287
-
288
- def write_voice(reg, value)
289
- voice = @voices[reg / 7]
290
- case reg % 7
291
- when 0 then voice.waveform.frequency_low = value
292
- when 1 then voice.waveform.frequency_high = value
293
- when 2 then voice.waveform.pulse_width_low = value
294
- when 3 then voice.waveform.pulse_width_high = value
295
- when 4
296
- voice.control = value
297
- update_span_rules
298
- when 5 then voice.envelope.attack_decay = value
299
- when 6 then voice.envelope.sustain_release = value
300
- end
301
- end
302
- end
303
- end
@@ -1,228 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class TimeOfDay
5
- # The TOD pin is fed from the AC supply. A CIA passes its region's
6
- # clock and mains frequency, and these are PAL's.
7
- CLOCK_HZ = Region::PAL.clock_hz
8
- MAINS_HZ = Region::PAL.mains_hz
9
-
10
- FIELDS = %i[tenths seconds minutes hours].freeze
11
-
12
- def initialize(clock_hz: CLOCK_HZ, mains_hz: MAINS_HZ)
13
- # The accumulator advances mains_hz per cycle, so a TOD pin pulse has
14
- # arrived when it reaches clock_hz. Integer math keeps it exact.
15
- @cycles_per_pulse = clock_hz
16
- @mains_hz = mains_hz
17
- @accumulator = 0
18
- @pulses = 0
19
- @clock = { tenths: 0x00, seconds: 0x00, minutes: 0x00, hours: 0x01 }
20
- @alarm = { tenths: 0x00, seconds: 0x00, minutes: 0x00, hours: 0x00 }
21
- @latch = nil
22
- @stopped = true
23
- @alarm_pending = false
24
- self.fifty_hz = false
25
- end
26
-
27
- # CRA bit 7 divides the TOD pin by 5 instead of 6. The divider has to
28
- # match the pin frequency to keep time, so PAL software selects 50 Hz.
29
- def fifty_hz=(enabled)
30
- @match = enabled ? 4 : 5
31
- end
32
-
33
- # The clock and the alarm, field by field in FIELDS order, the latch,
34
- # and the divider's phase.
35
- def save_state(out)
36
- out.int(@accumulator).int(@pulses).int(@match).boolean(@stopped).boolean(@alarm_pending)
37
- FIELDS.each { |field| out.int(@clock[field]).int(@alarm[field]) }
38
- out.boolean(!@latch.nil?)
39
- FIELDS.each { |field| out.int(@latch[field]) } if @latch
40
- end
41
-
42
- def load_state(input)
43
- @accumulator = input.int
44
- @pulses = input.int
45
- @match = input.int
46
- @stopped = input.boolean?
47
- @alarm_pending = input.boolean?
48
- FIELDS.each do |field|
49
- @clock[field] = input.int
50
- @alarm[field] = input.int
51
- end
52
- @latch = input.boolean? ? FIELDS.to_h { |field| [field, input.int] } : nil
53
- end
54
-
55
- # Whether the clock is stopped, or gets no pulses on its pin, with no
56
- # alarm to raise, so its cycles move only the divider's phase.
57
- def quiet? = (@stopped || @mains_hz.zero?) && !@alarm_pending
58
-
59
- # Runs +cycles+ quiet cycles at once.
60
- def fast_forward(cycles)
61
- @accumulator = (@accumulator + (cycles * @mains_hz)) % @cycles_per_pulse
62
- end
63
-
64
- def cycle!
65
- @accumulator += @mains_hz
66
- pulse! if @accumulator >= @cycles_per_pulse
67
- return unless @alarm_pending
68
-
69
- @alarm_pending = false
70
- yield if block_given?
71
- end
72
-
73
- def tenths
74
- value = (@latch || @clock)[:tenths]
75
- @latch = nil
76
- value
77
- end
78
-
79
- def seconds = (@latch || @clock)[:seconds]
80
- def minutes = (@latch || @clock)[:minutes]
81
-
82
- def hours
83
- @latch ||= @clock.dup
84
- @latch[:hours]
85
- end
86
-
87
- attr_reader :pulses
88
-
89
- # The clock as a read of the tenths would see it: the latch while the
90
- # clock is latched. In FIELDS order.
91
- def latched_fields = FIELDS.map { |field| (@latch || @clock)[field] }
92
-
93
- # The cycles until the clock next steps a tenth, as VICE counts them.
94
- def cycles_to_tenth
95
- to_pulse = (@cycles_per_pulse - @accumulator + @mains_hz - 1) / @mains_hz
96
- to_pulse + ([@match - @pulses, 0].max * @cycles_per_pulse / @mains_hz)
97
- end
98
-
99
- # Sets the clock, the alarm and the latch from VICE's fields, in FIELDS
100
- # order, the latch nil while unlatched.
101
- def restore_fields(clock, alarm, latch)
102
- FIELDS.each_with_index do |field, i|
103
- @clock[field] = clock[i]
104
- @alarm[field] = alarm[i]
105
- end
106
- @latch = latch && FIELDS.each_with_index.to_h { |field, i| [field, latch[i]] }
107
- end
108
-
109
- # Sets whether the clock is stopped, the pulses counted towards the
110
- # next tenth and the cycles until it, placing the divider so the tenth
111
- # lands then.
112
- def restore_divider(stopped, pulses, cycles_to_tenth)
113
- @stopped = stopped
114
- @pulses = pulses
115
- to_pulse = cycles_to_tenth - ([@match - pulses, 0].max * @cycles_per_pulse / @mains_hz)
116
- @accumulator = (@cycles_per_pulse - (to_pulse * @mains_hz)).clamp(0, @cycles_per_pulse - 1)
117
- end
118
-
119
- # The clock and alarm as stored, read without latching the clock.
120
- def registers
121
- [@clock[:tenths], @clock[:seconds], @clock[:minutes], @clock[:hours],
122
- @alarm[:tenths], @alarm[:seconds], @alarm[:minutes], @alarm[:hours],
123
- @stopped ? 1 : 0, @latch ? 1 : 0]
124
- end
125
-
126
- def write(field, value, alarm:)
127
- # The frequency counter is held clear while the clock is stopped, and
128
- # starts counting again from the write to tenths that restarts it.
129
- if field == :tenths && !alarm && @stopped
130
- @pulses = 0
131
- @stopped = false
132
- end
133
- store(field, value & (field == :tenths ? 0x0f : 0x7f), alarm: alarm)
134
- end
135
-
136
- # 12-hour BCD value, bit 7 is the AM/PM flag.
137
- def write_hours(value, alarm:)
138
- value &= 0x9f
139
- # Writing 12 to the hour register flips the AM/PM bit, the same way a
140
- # carry into 12 does. Writing the alarm hours does not.
141
- value ^= 0x80 if !alarm && (value & 0x1f) == 0x12
142
- # Halt the clock when writing hours, so that it doesn't
143
- # advance mid-update.
144
- @stopped = true unless alarm
145
- store(:hours, value, alarm: alarm)
146
- end
147
-
148
- private
149
-
150
- def store(field, value, alarm:)
151
- target = alarm ? @alarm : @clock
152
- return if target[field] == value
153
-
154
- target[field] = value
155
- @alarm_pending = true if alarm?
156
- end
157
-
158
- def pulse!
159
- @accumulator -= @cycles_per_pulse
160
- return if @stopped
161
-
162
- # A three-bit ring counter with six states, compared against the
163
- # divider on each pin pulse rather than on its way past it.
164
- if @pulses == @match
165
- @pulses = 0
166
- advance
167
- else
168
- @pulses += 1
169
- @pulses = 0 if @pulses > 5
170
- end
171
- end
172
-
173
- def advance
174
- tenths = (@clock[:tenths] + 1) & 0x0f
175
- @clock[:tenths] = tenths == 10 ? 0 : tenths
176
- carry_seconds if tenths == 10
177
- @alarm_pending = true if alarm?
178
- end
179
-
180
- def carry_seconds
181
- return unless advance_pair(:seconds)
182
- return unless advance_pair(:minutes)
183
-
184
- advance_hours
185
- end
186
-
187
- # Seconds and minutes hold a four-bit low digit that carries at ten into
188
- # a three-bit high digit that carries out at six. Both are plain binary
189
- # counters, so out-of-range BCD counts up from where it was written.
190
- def advance_pair(field)
191
- low = ((@clock[field] & 0x0f) + 1) & 0x0f
192
- high = (@clock[field] >> 4) & 0x07
193
- carry = false
194
-
195
- if low == 10
196
- low = 0
197
- high = (high + 1) & 0x07
198
- if high == 6
199
- high = 0
200
- carry = true
201
- end
202
- end
203
-
204
- @clock[field] = (high << 4) | low
205
- carry
206
- end
207
-
208
- # The hour runs 9 -> 10 and 12 -> 1 by swapping its two digits, and the
209
- # AM/PM bit flips as it passes through 12.
210
- def advance_hours
211
- pm = @clock[:hours] & 0x80
212
- high = (@clock[:hours] >> 4) & 0x01
213
- low = @clock[:hours] & 0x0f
214
-
215
- if (high == 1 && low == 2) || (high.zero? && low == 9)
216
- low = high
217
- high ^= 1
218
- else
219
- low = (low + 1) & 0x0f
220
- pm ^= 0x80 if high == 1 && low == 2
221
- end
222
-
223
- @clock[:hours] = pm | (high << 4) | low
224
- end
225
-
226
- def alarm? = @clock == @alarm
227
- end
228
- end
data/lib/badline/traps.rb DELETED
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module Traps
5
- def install_trap(addr, &handler)
6
- (@traps ||= {})[addr] = handler
7
- end
8
-
9
- def remove_trap(addr)
10
- @traps&.delete(addr)
11
- end
12
-
13
- private
14
-
15
- def run_traps
16
- @traps[@program_counter]&.call if @traps
17
- end
18
- end
19
- end
@@ -1,122 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class VIA
5
- # One port's pair of control lines, CA1 and CA2 or CB1 and CB2, set up
6
- # by a nibble of the peripheral control register, and their two
7
- # interrupt flags. Bit 0 picks the active edge of C1, rising when set.
8
- # Bits 3-1 pick the C2 mode:
9
- #
10
- # 000 input, falling edge 100 handshake output
11
- # 001 independent, falling 101 pulse output
12
- # 010 input, rising edge 110 low output
13
- # 011 independent, rising 111 high output
14
- #
15
- # A port access clears both flags, but an independent input keeps C2's.
16
- # In handshake mode C2 goes low on a port access and back high on the
17
- # next active C1 edge. In pulse mode it goes low for the cycle after the
18
- # access. Port A handshakes on reads and writes, port B on writes only.
19
- class ControlLines
20
- attr_reader :control, :c1_high, :c2_high
21
-
22
- # The level driven on C2, high while it is an input.
23
- attr_reader :c2_output
24
-
25
- def initialize(interrupts, c1_flag:, c2_flag:, handshake_on_read:)
26
- @interrupts = interrupts
27
- @c1_flag = c1_flag
28
- @c2_flag = c2_flag
29
- @handshake_on_read = handshake_on_read
30
- @c1_high = @c2_high = true
31
- reset!
32
- end
33
-
34
- # Back to input mode with both handshake outputs released. The input
35
- # levels carry over.
36
- def reset!
37
- @control = 0
38
- @handshake_low = false
39
- @pulse = 0
40
- drive
41
- end
42
-
43
- def control=(nibble)
44
- @control = nibble & 0x0f
45
- drive
46
- end
47
-
48
- # Only the pulse output needs the clock.
49
- def pulsing? = @pulse.positive?
50
-
51
- def cycle!
52
- @pulse -= 1
53
- drive if @pulse.zero?
54
- end
55
-
56
- def active_c1_edge?(high) = high == @control.anybits?(0x01)
57
-
58
- # The lines' levels and mode. Which flags they set, and whether reads
59
- # handshake, are the port's wiring.
60
- def save_state(out)
61
- out.int(@control).boolean(@c1_high).boolean(@c2_high).boolean(@handshake_low).int(@pulse).boolean(@c2_output)
62
- end
63
-
64
- def load_state(input)
65
- @control = input.int
66
- @c1_high = input.boolean?
67
- @c2_high = input.boolean?
68
- @handshake_low = input.boolean?
69
- @pulse = input.int
70
- @c2_output = input.boolean?
71
- end
72
-
73
- # Everything the lines hold, for comparing them at two points.
74
- def state = [@control, @c1_high, @c2_high, @handshake_low, @pulse, @c2_output]
75
-
76
- # A new C1 level. An active edge sets the flag and ends a handshake.
77
- def c1=(high)
78
- return if high == @c1_high
79
-
80
- @c1_high = high
81
- return unless active_c1_edge?(high)
82
-
83
- @handshake_low = false
84
- drive
85
- @interrupts.set(@c1_flag)
86
- end
87
-
88
- # A new C2 level. An active edge sets the flag while C2 is an input.
89
- def c2=(high)
90
- return if high == @c2_high
91
-
92
- @c2_high = high
93
- @interrupts.set(@c2_flag) if @control.nobits?(0x08) && high == @control.anybits?(0x04)
94
- end
95
-
96
- # A read or write of the handshaking port register.
97
- def access!(write)
98
- @interrupts.clear(independent? ? @c1_flag : @c1_flag | @c2_flag)
99
- return unless write || @handshake_on_read
100
-
101
- case @control >> 1
102
- when 4 then @handshake_low = true
103
- when 5 then @pulse = 2
104
- end
105
- drive
106
- end
107
-
108
- private
109
-
110
- def independent? = @control & 0x0a == 0x02
111
-
112
- def drive
113
- @c2_output = case @control >> 1
114
- when 4 then !@handshake_low
115
- when 5 then @pulse.zero?
116
- when 6 then false
117
- else true
118
- end
119
- end
120
- end
121
- end
122
- end