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
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: Region::PAL.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