badline 0.12.1 → 0.14.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 (565) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -1
  3. data/CLAUDE.md +86 -38
  4. data/CONTRIBUTING.md +4 -3
  5. data/README.md +9 -6
  6. data/doc/library.md +9 -9
  7. data/doc/media.md +2 -1
  8. data/doc/pinned-behaviour.md +134 -105
  9. data/doc/snapshot-format.md +1047 -0
  10. data/doc/snapshots.md +73 -43
  11. data/lib/badline/audio/bare_player.rb +53 -20
  12. data/lib/badline/audio/cli.rb +6 -6
  13. data/lib/badline/audio/jukebox.rb +2 -2
  14. data/lib/badline/audio/machine_player.rb +16 -10
  15. data/lib/badline/{media → audio}/queue.rb +1 -1
  16. data/lib/badline/audio/queued_tune.rb +6 -6
  17. data/lib/badline/audio/renderer.rb +33 -22
  18. data/lib/badline/audio/stereo.rb +1 -1
  19. data/lib/badline/c128/banks.rb +6 -3
  20. data/lib/badline/c128/bus/keyed_state.rb +45 -0
  21. data/lib/badline/c128/bus.rb +35 -20
  22. data/lib/badline/c128/color_lines.rb +2 -2
  23. data/lib/badline/c128/cpu.rb +1 -1
  24. data/lib/badline/c128/drives.rb +14 -34
  25. data/lib/badline/c128/fast_serial.rb +5 -5
  26. data/lib/badline/c128/keyed_modules.rb +117 -0
  27. data/lib/badline/c128/keyed_state.rb +91 -0
  28. data/lib/badline/c128/keys.rb +9 -0
  29. data/lib/badline/c128/mmu.rb +9 -8
  30. data/lib/badline/c128/mmu_pages.rb +21 -1
  31. data/lib/badline/c128/modes.rb +21 -11
  32. data/lib/badline/c128/z80.rb +2 -2
  33. data/lib/badline/c128/z80_turns.rb +1 -1
  34. data/lib/badline/c128.rb +21 -16
  35. data/lib/badline/c64/attachments.rb +42 -0
  36. data/lib/badline/c64/banked_ram/banking.rb +32 -0
  37. data/lib/badline/c64/banked_ram/plus256k.rb +64 -0
  38. data/lib/badline/c64/banked_ram/plus60k.rb +47 -0
  39. data/lib/badline/c64/banked_ram/unexpanded.rb +30 -0
  40. data/lib/badline/c64/banked_ram.rb +23 -0
  41. data/lib/badline/c64/bus/debug_register.rb +32 -0
  42. data/lib/badline/c64/bus/extra_sids.rb +32 -0
  43. data/lib/badline/c64/bus/fittings.rb +40 -0
  44. data/lib/badline/c64/bus/keyed_state.rb +41 -0
  45. data/lib/badline/c64/bus/pla.rb +149 -0
  46. data/lib/badline/c64/bus/roms.rb +41 -0
  47. data/lib/badline/c64/bus/sid_slots.rb +44 -0
  48. data/lib/badline/c64/bus.rb +219 -0
  49. data/lib/badline/c64/cartridge/action_replay.rb +115 -0
  50. data/lib/badline/c64/cartridge/atomic_power.rb +26 -0
  51. data/lib/badline/c64/cartridge/bank.rb +83 -0
  52. data/lib/badline/c64/cartridge/comal80.rb +52 -0
  53. data/lib/badline/c64/cartridge/dinamic.rb +36 -0
  54. data/lib/badline/c64/cartridge/easy_flash.rb +132 -0
  55. data/lib/badline/c64/cartridge/epyx_fastload.rb +73 -0
  56. data/lib/badline/c64/cartridge/final_cartridge3.rb +79 -0
  57. data/lib/badline/c64/cartridge/flash.rb +279 -0
  58. data/lib/badline/c64/cartridge/freezer.rb +35 -0
  59. data/lib/badline/c64/cartridge/fun_play.rb +40 -0
  60. data/lib/badline/c64/cartridge/g_mod2.rb +64 -0
  61. data/lib/badline/c64/cartridge/game_system.rb +42 -0
  62. data/lib/badline/c64/cartridge/geo_ram.rb +65 -0
  63. data/lib/badline/c64/cartridge/kcs_power.rb +69 -0
  64. data/lib/badline/c64/cartridge/keyed_state.rb +393 -0
  65. data/lib/badline/c64/cartridge/mach5.rb +34 -0
  66. data/lib/badline/c64/cartridge/magic_desk.rb +32 -0
  67. data/lib/badline/c64/cartridge/ocean.rb +37 -0
  68. data/lib/badline/c64/cartridge/pagefox.rb +60 -0
  69. data/lib/badline/c64/cartridge/retro_replay.rb +278 -0
  70. data/lib/badline/c64/cartridge/rex_utility.rb +31 -0
  71. data/lib/badline/c64/cartridge/rgcd.rb +50 -0
  72. data/lib/badline/c64/cartridge/simons_basic.rb +37 -0
  73. data/lib/badline/c64/cartridge/standard.rb +17 -0
  74. data/lib/badline/c64/cartridge/super_games.rb +40 -0
  75. data/lib/badline/c64/cartridge/westermann.rb +32 -0
  76. data/lib/badline/c64/cartridge/zaxxon.rb +52 -0
  77. data/lib/badline/c64/cartridge.rb +232 -0
  78. data/lib/badline/c64/color_memory.rb +27 -0
  79. data/lib/badline/{computer → c64}/common.rb +2 -2
  80. data/lib/badline/{computer → c64}/kernal_traps.rb +39 -36
  81. data/lib/badline/c64/keyed_modules.rb +111 -0
  82. data/lib/badline/c64/keyed_state.rb +68 -0
  83. data/lib/badline/c64/reu/dma.rb +271 -0
  84. data/lib/badline/c64/reu/keyed_state.rb +140 -0
  85. data/lib/badline/c64/reu/ram.rb +94 -0
  86. data/lib/badline/c64/reu/trigger.rb +34 -0
  87. data/lib/badline/c64/reu.rb +289 -0
  88. data/lib/badline/c64/true_drives.rb +120 -0
  89. data/lib/badline/{computer.rb → c64.rb} +24 -15
  90. data/lib/badline/chips/cia/fast_forward.rb +62 -0
  91. data/lib/badline/chips/cia/interrupt_register.rb +128 -0
  92. data/lib/badline/chips/cia/keyed_parts.rb +213 -0
  93. data/lib/badline/chips/cia/serial.rb +246 -0
  94. data/lib/badline/chips/cia/time_of_day.rb +210 -0
  95. data/lib/badline/chips/cia/timer.rb +188 -0
  96. data/lib/badline/chips/cia.rb +281 -0
  97. data/lib/badline/chips/cpu/addressing.rb +133 -0
  98. data/lib/badline/chips/cpu/boundary.rb +56 -0
  99. data/lib/badline/chips/cpu/core.rb +183 -0
  100. data/lib/badline/chips/cpu/instruction.rb +338 -0
  101. data/lib/badline/chips/cpu/instruction_set/arithmetic.rb +118 -0
  102. data/lib/badline/chips/cpu/instruction_set/bitwise.rb +130 -0
  103. data/lib/badline/chips/cpu/instruction_set/branch.rb +83 -0
  104. data/lib/badline/chips/cpu/instruction_set/flag.rb +67 -0
  105. data/lib/badline/chips/cpu/instruction_set/illegal.rb +274 -0
  106. data/lib/badline/chips/cpu/instruction_set/inc_dec.rb +73 -0
  107. data/lib/badline/chips/cpu/instruction_set/stack.rb +56 -0
  108. data/lib/badline/chips/cpu/instruction_set/transfer.rb +141 -0
  109. data/lib/badline/chips/cpu/instruction_set.rb +59 -0
  110. data/lib/badline/chips/cpu/interrupts.rb +108 -0
  111. data/lib/badline/chips/cpu/keyed_state.rb +177 -0
  112. data/lib/badline/chips/cpu/microcode.rb +195 -0
  113. data/lib/badline/chips/cpu/operations.rb +90 -0
  114. data/lib/badline/chips/cpu/port.rb +133 -0
  115. data/lib/badline/chips/cpu/stack_operations.rb +84 -0
  116. data/lib/badline/chips/cpu/traps.rb +23 -0
  117. data/lib/badline/chips/cpu.rb +17 -0
  118. data/lib/badline/chips/sid/catch_up.rb +122 -0
  119. data/lib/badline/chips/sid/decimator.rb +68 -0
  120. data/lib/badline/chips/sid/envelope.rb +236 -0
  121. data/lib/badline/chips/sid/filter.rb +227 -0
  122. data/lib/badline/chips/sid/keyed_parts.rb +286 -0
  123. data/lib/badline/chips/sid/voice.rb +69 -0
  124. data/lib/badline/chips/sid/waveform/combined.rb +128 -0
  125. data/lib/badline/chips/sid/waveform/fast_forward.rb +107 -0
  126. data/lib/badline/chips/sid/waveform/noise_writeback.rb +124 -0
  127. data/lib/badline/chips/sid/waveform.rb +305 -0
  128. data/lib/badline/chips/sid.rb +264 -0
  129. data/lib/badline/chips/ted/beam.rb +119 -0
  130. data/lib/badline/chips/ted/timers.rb +66 -0
  131. data/lib/badline/chips/ted.rb +143 -0
  132. data/lib/badline/chips/tia.rb +49 -0
  133. data/lib/badline/chips/vdc/keyed_parts.rb +105 -0
  134. data/lib/badline/{c128 → chips}/vdc/memory.rb +1 -1
  135. data/lib/badline/{c128 → chips}/vdc/painter.rb +1 -13
  136. data/lib/badline/{c128 → chips}/vdc/raster.rb +1 -17
  137. data/lib/badline/{c128 → chips}/vdc/window.rb +1 -10
  138. data/lib/badline/{c128 → chips}/vdc.rb +6 -31
  139. data/lib/badline/chips/via/control_lines.rb +109 -0
  140. data/lib/badline/chips/via/fast_forward.rb +55 -0
  141. data/lib/badline/chips/via/interrupt_register.rb +60 -0
  142. data/lib/badline/chips/via/keyed_parts.rb +163 -0
  143. data/lib/badline/chips/via/shift_register.rb +168 -0
  144. data/lib/badline/chips/via/timer1.rb +120 -0
  145. data/lib/badline/chips/via/timer2.rb +117 -0
  146. data/lib/badline/chips/via.rb +267 -0
  147. data/lib/badline/chips/vic/bank.rb +135 -0
  148. data/lib/badline/chips/vic/border_mask.rb +78 -0
  149. data/lib/badline/chips/vic/collisions.rb +106 -0
  150. data/lib/badline/chips/vic/color_patches.rb +38 -0
  151. data/lib/badline/chips/vic/display_state.rb +168 -0
  152. data/lib/badline/chips/vic/graphics_mode.rb +166 -0
  153. data/lib/badline/chips/vic/graphics_shifter.rb +183 -0
  154. data/lib/badline/chips/vic/keyed_parts.rb +228 -0
  155. data/lib/badline/chips/vic/keyed_sprites.rb +225 -0
  156. data/lib/badline/chips/vic/keyed_state.rb +102 -0
  157. data/lib/badline/chips/vic/register_log.rb +65 -0
  158. data/lib/badline/chips/vic/registers.rb +188 -0
  159. data/lib/badline/chips/vic/sequencer.rb +275 -0
  160. data/lib/badline/chips/vic/sequencer_output.rb +118 -0
  161. data/lib/badline/chips/vic/sprite/internal_bus.rb +59 -0
  162. data/lib/badline/chips/vic/sprite/shifter.rb +148 -0
  163. data/lib/badline/chips/vic/sprite/timing.rb +58 -0
  164. data/lib/badline/chips/vic/sprite.rb +337 -0
  165. data/lib/badline/chips/vic/sprites.rb +281 -0
  166. data/lib/badline/chips/vic.rb +787 -0
  167. data/lib/badline/chips/vic_i/keyed_parts.rb +142 -0
  168. data/lib/badline/{vic20/vic → chips/vic_i}/painter.rb +2 -30
  169. data/lib/badline/chips/vic_i/sound/output.rb +85 -0
  170. data/lib/badline/chips/vic_i/sound.rb +227 -0
  171. data/lib/badline/{vic20/vic → chips/vic_i}/text_window.rb +2 -2
  172. data/lib/badline/{vic20/vic.rb → chips/vic_i.rb} +6 -6
  173. data/lib/badline/chips/z80/arithmetic.rb +119 -0
  174. data/lib/badline/chips/z80/bit_page.rb +57 -0
  175. data/lib/badline/chips/z80/block_io.rb +60 -0
  176. data/lib/badline/chips/z80/block_transfers.rb +61 -0
  177. data/lib/badline/chips/z80/bus_cycles.rb +113 -0
  178. data/lib/badline/chips/z80/core.rb +115 -0
  179. data/lib/badline/chips/z80/exchanges.rb +52 -0
  180. data/lib/badline/chips/z80/extended_page.rb +91 -0
  181. data/lib/badline/chips/z80/flags.rb +39 -0
  182. data/lib/badline/chips/z80/interrupt_acceptance.rb +48 -0
  183. data/lib/badline/chips/z80/jumps.rb +84 -0
  184. data/lib/badline/chips/z80/keyed_state.rb +73 -0
  185. data/lib/badline/chips/z80/loads.rb +100 -0
  186. data/lib/badline/chips/z80/main_page.rb +136 -0
  187. data/lib/badline/chips/z80/registers.rb +122 -0
  188. data/lib/badline/chips/z80/shifts.rb +66 -0
  189. data/lib/badline/chips/z80.rb +13 -0
  190. data/lib/badline/chips.rb +10 -0
  191. data/lib/badline/core.rb +13 -32
  192. data/lib/badline/drives/datasette/keyed_state.rb +38 -0
  193. data/lib/badline/drives/datasette.rb +173 -0
  194. data/lib/badline/drives/engine/core.rb +152 -0
  195. data/lib/badline/drives/engine/fast_serial.rb +75 -0
  196. data/lib/badline/drives/engine/idle.rb +127 -0
  197. data/lib/badline/drives/engine/idle_cpu.rb +30 -0
  198. data/lib/badline/drives/engine/orbit.rb +81 -0
  199. data/lib/badline/drives/engine/serial_lines.rb +72 -0
  200. data/lib/badline/drives/engine/sleep.rb +114 -0
  201. data/lib/badline/drives/engine/vias.rb +86 -0
  202. data/lib/badline/drives/engine/watch.rb +152 -0
  203. data/lib/badline/drives/engine.rb +11 -0
  204. data/lib/badline/drives/model1541/bus.rb +75 -0
  205. data/lib/badline/drives/model1541/byte_ready.rb +50 -0
  206. data/lib/badline/drives/model1541/cpu.rb +13 -0
  207. data/lib/badline/drives/model1541/disk.rb +318 -0
  208. data/lib/badline/drives/model1541/disk_via.rb +38 -0
  209. data/lib/badline/drives/model1541/gcr.rb +59 -0
  210. data/lib/badline/drives/model1541/keyed_state.rb +251 -0
  211. data/lib/badline/drives/model1541/mechanism.rb +313 -0
  212. data/lib/badline/drives/model1541/rotation.rb +123 -0
  213. data/lib/badline/drives/model1541/sector_reader.rb +78 -0
  214. data/lib/badline/drives/model1541/serial_port.rb +20 -0
  215. data/lib/badline/drives/model1541/track.rb +100 -0
  216. data/lib/badline/drives/model1541.rb +80 -0
  217. data/lib/badline/drives/model1571/bus.rb +100 -0
  218. data/lib/badline/drives/model1571/cpu.rb +13 -0
  219. data/lib/badline/drives/model1571/keyed_state.rb +108 -0
  220. data/lib/badline/drives/model1571/serial_port.rb +39 -0
  221. data/lib/badline/drives/model1571/serial_via.rb +27 -0
  222. data/lib/badline/drives/model1571/wd1770.rb +108 -0
  223. data/lib/badline/drives/model1571.rb +141 -0
  224. data/lib/badline/drives/model1581/bus.rb +126 -0
  225. data/lib/badline/drives/model1581/cpu.rb +13 -0
  226. data/lib/badline/drives/model1581/disk.rb +133 -0
  227. data/lib/badline/drives/model1581/keyed_state.rb +280 -0
  228. data/lib/badline/drives/model1581/mechanism.rb +98 -0
  229. data/lib/badline/drives/model1581/serial_port.rb +54 -0
  230. data/lib/badline/drives/model1581/slot.rb +61 -0
  231. data/lib/badline/drives/model1581/track.rb +102 -0
  232. data/lib/badline/drives/model1581/track_bytes.rb +77 -0
  233. data/lib/badline/drives/model1581/wd1772/registers.rb +91 -0
  234. data/lib/badline/drives/model1581/wd1772/sector_writes.rb +75 -0
  235. data/lib/badline/drives/model1581/wd1772/sectors.rb +152 -0
  236. data/lib/badline/drives/model1581/wd1772/stepping.rb +111 -0
  237. data/lib/badline/drives/model1581/wd1772/tracks.rb +127 -0
  238. data/lib/badline/drives/model1581/wd1772/turn.rb +75 -0
  239. data/lib/badline/drives/model1581/wd1772.rb +216 -0
  240. data/lib/badline/drives/model1581.rb +206 -0
  241. data/lib/badline/drives/serial_bus.rb +161 -0
  242. data/lib/badline/drives.rb +8 -0
  243. data/lib/badline/frontend/app.rb +3 -3
  244. data/lib/badline/frontend/boot.rb +4 -4
  245. data/lib/badline/frontend/controls.rb +19 -3
  246. data/lib/badline/frontend/drive_led.rb +44 -21
  247. data/lib/badline/frontend/machine_window.rb +3 -1
  248. data/lib/badline/frontend/menu/menu_dialogs.rb +2 -2
  249. data/lib/badline/frontend/player/filter_view.rb +1 -1
  250. data/lib/badline/frontend/player/player_controller.rb +2 -2
  251. data/lib/badline/frontend/player/player_screen.rb +1 -0
  252. data/lib/badline/frontend/player/theme.rb +7 -7
  253. data/lib/badline/frontend/snapshots.rb +12 -1
  254. data/lib/badline/frontend/timeline.rb +30 -12
  255. data/lib/badline/input/control_ports.rb +78 -0
  256. data/lib/badline/input/joystick.rb +27 -0
  257. data/lib/badline/input/keyboard.rb +114 -0
  258. data/lib/badline/input/matrix_typist.rb +98 -0
  259. data/lib/badline/input.rb +4 -0
  260. data/lib/badline/kernal_trap/chrout.rb +45 -0
  261. data/lib/badline/kernal_trap/{drive → dos}/block_commands.rb +1 -1
  262. data/lib/badline/kernal_trap/dos/channel.rb +156 -0
  263. data/lib/badline/kernal_trap/{drive → dos}/channels.rb +1 -26
  264. data/lib/badline/kernal_trap/{drive → dos}/memory.rb +1 -10
  265. data/lib/badline/kernal_trap/{drive → dos}/parameters.rb +1 -1
  266. data/lib/badline/kernal_trap/{drive → dos}/status.rb +1 -9
  267. data/lib/badline/kernal_trap/{drive → dos}/write_file.rb +1 -19
  268. data/lib/badline/kernal_trap/{drive → dos}/writes.rb +1 -1
  269. data/lib/badline/kernal_trap/{drive.rb → dos.rb} +9 -27
  270. data/lib/badline/kernal_trap/file_routine.rb +4 -4
  271. data/lib/badline/kernal_trap/keyed_state.rb +150 -0
  272. data/lib/badline/kernal_trap/layout.rb +75 -11
  273. data/lib/badline/kernal_trap/load.rb +19 -21
  274. data/lib/badline/kernal_trap/routine.rb +12 -0
  275. data/lib/badline/kernal_trap/save.rb +12 -22
  276. data/lib/badline/kernal_trap/serial.rb +8 -24
  277. data/lib/badline/kernal_trap.rb +3 -2
  278. data/lib/badline/machine/clocking.rb +1 -1
  279. data/lib/badline/machine/keyboard_buffer.rb +49 -0
  280. data/lib/badline/machine/settling.rb +29 -0
  281. data/lib/badline/machine.rb +10 -7
  282. data/lib/badline/media/boot_disk.rb +14 -2
  283. data/lib/badline/media/extensions.rb +10 -0
  284. data/lib/badline/media/true_drive.rb +1 -1
  285. data/lib/badline/media/tune.rb +2 -2
  286. data/lib/badline/media.rb +3 -3
  287. data/lib/badline/memory.rb +3 -6
  288. data/lib/badline/model.rb +1 -1
  289. data/lib/badline/options/family.rb +5 -2
  290. data/lib/badline/options/help.rb +42 -16
  291. data/lib/badline/options/table.rb +2 -0
  292. data/lib/badline/options/validation.rb +2 -0
  293. data/lib/badline/options.rb +6 -1
  294. data/lib/badline/plus4/acia.rb +45 -0
  295. data/lib/badline/plus4/bus.rb +312 -0
  296. data/lib/badline/plus4/cpu.rb +10 -0
  297. data/lib/badline/plus4/cpu_port.rb +93 -0
  298. data/lib/badline/plus4/keyboard_port.rb +51 -0
  299. data/lib/badline/plus4/model.rb +38 -0
  300. data/lib/badline/plus4/user_port.rb +31 -0
  301. data/lib/badline/plus4.rb +164 -0
  302. data/lib/badline/roms/README +44 -6
  303. data/lib/badline/roms/plus4/basic.rom +0 -0
  304. data/lib/badline/roms/plus4/function-high.rom +0 -0
  305. data/lib/badline/roms/plus4/function-low.rom +0 -0
  306. data/lib/badline/roms/plus4/kernal-ntsc.rom +0 -0
  307. data/lib/badline/roms/plus4/kernal-pal.rom +0 -0
  308. data/lib/badline/sdl.rb +1 -0
  309. data/lib/badline/{storage/sid_file.rb → sid_tune/file.rb} +3 -3
  310. data/lib/badline/{storage → sid_tune}/hvsc.rb +7 -7
  311. data/lib/badline/{storage → sid_tune}/song_lengths.rb +2 -2
  312. data/lib/badline/{storage → sid_tune}/stil/credit.rb +1 -1
  313. data/lib/badline/{storage → sid_tune}/stil.rb +3 -3
  314. data/lib/badline/sid_tune.rb +6 -0
  315. data/lib/badline/snapshot/c128_setup.rb +32 -0
  316. data/lib/badline/snapshot/c64_setup.rb +83 -0
  317. data/lib/badline/snapshot/container.rb +4 -0
  318. data/lib/badline/snapshot/field_doc/markdown.rb +112 -0
  319. data/lib/badline/snapshot/field_doc.rb +109 -0
  320. data/lib/badline/snapshot/image.rb +132 -46
  321. data/lib/badline/snapshot/keyed/cursor.rb +40 -0
  322. data/lib/badline/snapshot/keyed/modules.rb +66 -0
  323. data/lib/badline/snapshot/keyed/reader.rb +188 -0
  324. data/lib/badline/snapshot/keyed/recorder.rb +88 -0
  325. data/lib/badline/snapshot/keyed/report.rb +26 -0
  326. data/lib/badline/snapshot/keyed/writer.rb +55 -0
  327. data/lib/badline/snapshot/keyed.rb +64 -0
  328. data/lib/badline/snapshot/machine_state.rb +17 -64
  329. data/lib/badline/snapshot/storage_setup.rb +63 -0
  330. data/lib/badline/snapshot/vic20_setup.rb +28 -0
  331. data/lib/badline/snapshot/vice/c64_mem.rb +1 -1
  332. data/lib/badline/snapshot/vice/restore.rb +1 -1
  333. data/lib/badline/snapshot/vice/reu1764.rb +3 -3
  334. data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
  335. data/lib/badline/snapshot/vice.rb +13 -35
  336. data/lib/badline/snapshot.rb +44 -22
  337. data/lib/badline/storage/crt_file.rb +3 -1
  338. data/lib/badline/storage/d64_image.rb +0 -2
  339. data/lib/badline/storage/d71_image.rb +0 -2
  340. data/lib/badline/storage/d81_image.rb +0 -2
  341. data/lib/badline/storage/disk_image.rb +3 -6
  342. data/lib/badline/storage/g64_image.rb +10 -5
  343. data/lib/badline/storage/host_directory.rb +0 -5
  344. data/lib/badline/storage/t64.rb +2 -8
  345. data/lib/badline/storage/tap.rb +43 -15
  346. data/lib/badline/storage/unavailable.rb +1 -1
  347. data/lib/badline/storage.rb +0 -37
  348. data/lib/badline/support/c128_checkpoint.rb +39 -0
  349. data/lib/badline/support/checkpoint.rb +108 -0
  350. data/lib/badline/support/vic20_checkpoint.rb +38 -0
  351. data/lib/badline/support.rb +5 -0
  352. data/lib/badline/version.rb +1 -1
  353. data/lib/badline/vic20/attachments.rb +8 -5
  354. data/lib/badline/vic20/bus/keyed_state.rb +52 -0
  355. data/lib/badline/vic20/bus.rb +2 -25
  356. data/lib/badline/vic20/cpu.rb +1 -1
  357. data/lib/badline/vic20/keyed_modules.rb +73 -0
  358. data/lib/badline/vic20/keyed_state.rb +45 -0
  359. data/lib/badline/vic20/port_wiring.rb +4 -4
  360. data/lib/badline/vic20/user_via_ports.rb +2 -2
  361. data/lib/badline/vic20.rb +22 -17
  362. data/lib/badline.rb +1 -0
  363. metadata +271 -228
  364. data/lib/badline/address_bus/extra_sids.rb +0 -30
  365. data/lib/badline/address_bus/fittings.rb +0 -38
  366. data/lib/badline/address_bus/pla.rb +0 -147
  367. data/lib/badline/address_bus/roms.rb +0 -39
  368. data/lib/badline/address_bus/saved_state.rb +0 -66
  369. data/lib/badline/address_bus/sid_slots.rb +0 -42
  370. data/lib/badline/address_bus.rb +0 -216
  371. data/lib/badline/c128/bus_state.rb +0 -53
  372. data/lib/badline/c128/saved_state.rb +0 -143
  373. data/lib/badline/cartridge/action_replay.rb +0 -126
  374. data/lib/badline/cartridge/atomic_power.rb +0 -24
  375. data/lib/badline/cartridge/bank.rb +0 -81
  376. data/lib/badline/cartridge/comal80.rb +0 -50
  377. data/lib/badline/cartridge/dinamic.rb +0 -34
  378. data/lib/badline/cartridge/easy_flash.rb +0 -145
  379. data/lib/badline/cartridge/epyx_fastload.rb +0 -79
  380. data/lib/badline/cartridge/final_cartridge3.rb +0 -89
  381. data/lib/badline/cartridge/flash.rb +0 -306
  382. data/lib/badline/cartridge/freezer.rb +0 -33
  383. data/lib/badline/cartridge/fun_play.rb +0 -38
  384. data/lib/badline/cartridge/g_mod2.rb +0 -74
  385. data/lib/badline/cartridge/game_system.rb +0 -40
  386. data/lib/badline/cartridge/geo_ram.rb +0 -79
  387. data/lib/badline/cartridge/kcs_power.rb +0 -75
  388. data/lib/badline/cartridge/mach5.rb +0 -32
  389. data/lib/badline/cartridge/magic_desk.rb +0 -30
  390. data/lib/badline/cartridge/ocean.rb +0 -35
  391. data/lib/badline/cartridge/pagefox.rb +0 -68
  392. data/lib/badline/cartridge/retro_replay.rb +0 -320
  393. data/lib/badline/cartridge/rex_utility.rb +0 -29
  394. data/lib/badline/cartridge/rgcd.rb +0 -58
  395. data/lib/badline/cartridge/simons_basic.rb +0 -35
  396. data/lib/badline/cartridge/standard.rb +0 -15
  397. data/lib/badline/cartridge/super_games.rb +0 -48
  398. data/lib/badline/cartridge/westermann.rb +0 -30
  399. data/lib/badline/cartridge/zaxxon.rb +0 -66
  400. data/lib/badline/cartridge.rb +0 -303
  401. data/lib/badline/checkpoint.rb +0 -98
  402. data/lib/badline/chrout_trap.rb +0 -43
  403. data/lib/badline/cia/fast_forward.rb +0 -60
  404. data/lib/badline/cia/interrupt_register.rb +0 -143
  405. data/lib/badline/cia/serial.rb +0 -275
  406. data/lib/badline/cia/state.rb +0 -47
  407. data/lib/badline/cia/timer.rb +0 -206
  408. data/lib/badline/cia.rb +0 -279
  409. data/lib/badline/color_memory.rb +0 -25
  410. data/lib/badline/computer/attachments.rb +0 -88
  411. data/lib/badline/computer/saved_state.rb +0 -117
  412. data/lib/badline/computer/true_drives.rb +0 -69
  413. data/lib/badline/control_ports.rb +0 -76
  414. data/lib/badline/cpu/addressing.rb +0 -131
  415. data/lib/badline/cpu/boundary.rb +0 -54
  416. data/lib/badline/cpu/core.rb +0 -165
  417. data/lib/badline/cpu/microcode.rb +0 -177
  418. data/lib/badline/cpu/operations.rb +0 -88
  419. data/lib/badline/cpu/saved_state.rb +0 -115
  420. data/lib/badline/cpu/stack_operations.rb +0 -82
  421. data/lib/badline/cpu.rb +0 -10
  422. data/lib/badline/cpu_port.rb +0 -112
  423. data/lib/badline/datasette.rb +0 -161
  424. data/lib/badline/debug_register.rb +0 -28
  425. data/lib/badline/drive/core.rb +0 -147
  426. data/lib/badline/drive/fast_serial.rb +0 -73
  427. data/lib/badline/drive/idle.rb +0 -125
  428. data/lib/badline/drive/idle_cpu.rb +0 -28
  429. data/lib/badline/drive/orbit.rb +0 -79
  430. data/lib/badline/drive/serial_lines.rb +0 -73
  431. data/lib/badline/drive/sleep.rb +0 -112
  432. data/lib/badline/drive/vias.rb +0 -84
  433. data/lib/badline/drive/watch.rb +0 -150
  434. data/lib/badline/drive.rb +0 -11
  435. data/lib/badline/drive1541/bus.rb +0 -86
  436. data/lib/badline/drive1541/byte_ready.rb +0 -48
  437. data/lib/badline/drive1541/cpu.rb +0 -11
  438. data/lib/badline/drive1541/disk.rb +0 -315
  439. data/lib/badline/drive1541/disk_state.rb +0 -86
  440. data/lib/badline/drive1541/disk_via.rb +0 -36
  441. data/lib/badline/drive1541/gcr.rb +0 -57
  442. data/lib/badline/drive1541/mechanism.rb +0 -313
  443. data/lib/badline/drive1541/mechanism_state.rb +0 -68
  444. data/lib/badline/drive1541/rotation.rb +0 -121
  445. data/lib/badline/drive1541/sector_reader.rb +0 -76
  446. data/lib/badline/drive1541/serial_port.rb +0 -18
  447. data/lib/badline/drive1541/track.rb +0 -98
  448. data/lib/badline/drive1541.rb +0 -111
  449. data/lib/badline/drive1571/bus.rb +0 -111
  450. data/lib/badline/drive1571/cpu.rb +0 -11
  451. data/lib/badline/drive1571/serial_port.rb +0 -37
  452. data/lib/badline/drive1571/serial_via.rb +0 -25
  453. data/lib/badline/drive1571/wd1770.rb +0 -120
  454. data/lib/badline/drive1571.rb +0 -175
  455. data/lib/badline/drive1581/bus.rb +0 -137
  456. data/lib/badline/drive1581/cpu.rb +0 -11
  457. data/lib/badline/drive1581/disk.rb +0 -135
  458. data/lib/badline/drive1581/disk_state.rb +0 -87
  459. data/lib/badline/drive1581/mechanism.rb +0 -117
  460. data/lib/badline/drive1581/serial_port.rb +0 -52
  461. data/lib/badline/drive1581/slot.rb +0 -78
  462. data/lib/badline/drive1581/track.rb +0 -100
  463. data/lib/badline/drive1581/track_bytes.rb +0 -75
  464. data/lib/badline/drive1581/wd1772/registers.rb +0 -89
  465. data/lib/badline/drive1581/wd1772/sector_writes.rb +0 -73
  466. data/lib/badline/drive1581/wd1772/sectors.rb +0 -150
  467. data/lib/badline/drive1581/wd1772/state.rb +0 -66
  468. data/lib/badline/drive1581/wd1772/stepping.rb +0 -109
  469. data/lib/badline/drive1581/wd1772/tracks.rb +0 -125
  470. data/lib/badline/drive1581/wd1772/turn.rb +0 -73
  471. data/lib/badline/drive1581/wd1772.rb +0 -216
  472. data/lib/badline/drive1581.rb +0 -233
  473. data/lib/badline/iec_bus.rb +0 -159
  474. data/lib/badline/instruction.rb +0 -334
  475. data/lib/badline/instruction_set/arithmetic.rb +0 -114
  476. data/lib/badline/instruction_set/bitwise.rb +0 -126
  477. data/lib/badline/instruction_set/branch.rb +0 -79
  478. data/lib/badline/instruction_set/flag.rb +0 -63
  479. data/lib/badline/instruction_set/illegal.rb +0 -270
  480. data/lib/badline/instruction_set/inc_dec.rb +0 -69
  481. data/lib/badline/instruction_set/stack.rb +0 -52
  482. data/lib/badline/instruction_set/transfer.rb +0 -137
  483. data/lib/badline/instruction_set.rb +0 -55
  484. data/lib/badline/interrupts.rb +0 -104
  485. data/lib/badline/joystick.rb +0 -25
  486. data/lib/badline/kernal_trap/channel.rb +0 -181
  487. data/lib/badline/keyboard.rb +0 -112
  488. data/lib/badline/keyboard_buffer.rb +0 -33
  489. data/lib/badline/ram_expansion/banking.rb +0 -30
  490. data/lib/badline/ram_expansion/plus256k.rb +0 -54
  491. data/lib/badline/ram_expansion/plus60k.rb +0 -43
  492. data/lib/badline/ram_expansion/unexpanded.rb +0 -28
  493. data/lib/badline/ram_expansion.rb +0 -21
  494. data/lib/badline/reu/dma/saved_state.rb +0 -50
  495. data/lib/badline/reu/dma.rb +0 -273
  496. data/lib/badline/reu/ram.rb +0 -107
  497. data/lib/badline/reu/saved_state.rb +0 -80
  498. data/lib/badline/reu/trigger.rb +0 -32
  499. data/lib/badline/reu.rb +0 -289
  500. data/lib/badline/sid/catch_up.rb +0 -120
  501. data/lib/badline/sid/decimator.rb +0 -64
  502. data/lib/badline/sid/envelope/state.rb +0 -68
  503. data/lib/badline/sid/envelope.rb +0 -239
  504. data/lib/badline/sid/filter.rb +0 -263
  505. data/lib/badline/sid/voice.rb +0 -77
  506. data/lib/badline/sid/waveform/combined.rb +0 -126
  507. data/lib/badline/sid/waveform/fast_forward.rb +0 -105
  508. data/lib/badline/sid/waveform/noise_writeback.rb +0 -122
  509. data/lib/badline/sid/waveform/state.rb +0 -66
  510. data/lib/badline/sid/waveform.rb +0 -305
  511. data/lib/badline/sid.rb +0 -303
  512. data/lib/badline/snapshot/setup.rb +0 -75
  513. data/lib/badline/snapshot/state.rb +0 -189
  514. data/lib/badline/time_of_day.rb +0 -228
  515. data/lib/badline/traps.rb +0 -19
  516. data/lib/badline/via/control_lines.rb +0 -122
  517. data/lib/badline/via/fast_forward.rb +0 -53
  518. data/lib/badline/via/interrupt_register.rb +0 -67
  519. data/lib/badline/via/shift_register.rb +0 -180
  520. data/lib/badline/via/state.rb +0 -42
  521. data/lib/badline/via/timer1.rb +0 -131
  522. data/lib/badline/via/timer2.rb +0 -133
  523. data/lib/badline/via.rb +0 -266
  524. data/lib/badline/vic/bank.rb +0 -133
  525. data/lib/badline/vic/border_mask.rb +0 -86
  526. data/lib/badline/vic/collisions.rb +0 -115
  527. data/lib/badline/vic/color_patches.rb +0 -47
  528. data/lib/badline/vic/display_state.rb +0 -185
  529. data/lib/badline/vic/graphics_mode.rb +0 -164
  530. data/lib/badline/vic/graphics_shifter.rb +0 -207
  531. data/lib/badline/vic/register_log.rb +0 -81
  532. data/lib/badline/vic/registers.rb +0 -195
  533. data/lib/badline/vic/sequencer.rb +0 -275
  534. data/lib/badline/vic/sequencer_output.rb +0 -116
  535. data/lib/badline/vic/sequencer_state.rb +0 -89
  536. data/lib/badline/vic/sprite/internal_bus.rb +0 -68
  537. data/lib/badline/vic/sprite/saved_state.rb +0 -64
  538. data/lib/badline/vic/sprite/shifter.rb +0 -146
  539. data/lib/badline/vic/sprite/timing.rb +0 -56
  540. data/lib/badline/vic/sprite.rb +0 -337
  541. data/lib/badline/vic/sprites.rb +0 -282
  542. data/lib/badline/vic/sprites_state.rb +0 -57
  543. data/lib/badline/vic.rb +0 -853
  544. data/lib/badline/vic20/saved_state.rb +0 -124
  545. data/lib/badline/vic20/sound/output.rb +0 -83
  546. data/lib/badline/vic20/sound.rb +0 -233
  547. data/lib/badline/vic20/vic/saved_state.rb +0 -55
  548. data/lib/badline/z80/arithmetic.rb +0 -117
  549. data/lib/badline/z80/bit_page.rb +0 -55
  550. data/lib/badline/z80/block_io.rb +0 -58
  551. data/lib/badline/z80/block_transfers.rb +0 -59
  552. data/lib/badline/z80/bus_cycles.rb +0 -111
  553. data/lib/badline/z80/core.rb +0 -113
  554. data/lib/badline/z80/exchanges.rb +0 -50
  555. data/lib/badline/z80/extended_page.rb +0 -89
  556. data/lib/badline/z80/flags.rb +0 -37
  557. data/lib/badline/z80/interrupt_acceptance.rb +0 -46
  558. data/lib/badline/z80/jumps.rb +0 -82
  559. data/lib/badline/z80/loads.rb +0 -98
  560. data/lib/badline/z80/main_page.rb +0 -134
  561. data/lib/badline/z80/registers.rb +0 -120
  562. data/lib/badline/z80/saved_state.rb +0 -69
  563. data/lib/badline/z80/shifts.rb +0 -64
  564. data/lib/badline/z80.rb +0 -11
  565. /data/lib/badline/snapshot/{fields.rb → vice/fields.rb} +0 -0
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIA
6
+ # One port's pair of control lines, CA1 and CA2 or CB1 and CB2, set up
7
+ # by a nibble of the peripheral control register, and their two
8
+ # interrupt flags. Bit 0 picks the active edge of C1, rising when set.
9
+ # Bits 3-1 pick the C2 mode:
10
+ #
11
+ # 000 input, falling edge 100 handshake output
12
+ # 001 independent, falling 101 pulse output
13
+ # 010 input, rising edge 110 low output
14
+ # 011 independent, rising 111 high output
15
+ #
16
+ # A port access clears both flags, but an independent input keeps C2's.
17
+ # In handshake mode C2 goes low on a port access and back high on the
18
+ # next active C1 edge. In pulse mode it goes low for the cycle after the
19
+ # access. Port A handshakes on reads and writes, port B on writes only.
20
+ class ControlLines
21
+ attr_reader :control, :c1_high, :c2_high
22
+
23
+ # The level driven on C2, high while it is an input.
24
+ attr_reader :c2_output
25
+
26
+ def initialize(interrupts, c1_flag:, c2_flag:, handshake_on_read:)
27
+ @interrupts = interrupts
28
+ @c1_flag = c1_flag
29
+ @c2_flag = c2_flag
30
+ @handshake_on_read = handshake_on_read
31
+ @c1_high = @c2_high = true
32
+ reset!
33
+ end
34
+
35
+ # Back to input mode with both handshake outputs released. The input
36
+ # levels carry over.
37
+ def reset!
38
+ @control = 0
39
+ @handshake_low = false
40
+ @pulse = 0
41
+ drive
42
+ end
43
+
44
+ def control=(nibble)
45
+ @control = nibble & 0x0f
46
+ drive
47
+ end
48
+
49
+ # Only the pulse output needs the clock.
50
+ def pulsing? = @pulse.positive?
51
+
52
+ def cycle!
53
+ @pulse -= 1
54
+ drive if @pulse.zero?
55
+ end
56
+
57
+ def active_c1_edge?(high) = high == @control.anybits?(0x01)
58
+
59
+ # Everything the lines hold, for comparing them at two points.
60
+ def state = [@control, @c1_high, @c2_high, @handshake_low, @pulse, @c2_output]
61
+
62
+ # A new C1 level. An active edge sets the flag and ends a handshake.
63
+ def c1=(high)
64
+ return if high == @c1_high
65
+
66
+ @c1_high = high
67
+ return unless active_c1_edge?(high)
68
+
69
+ @handshake_low = false
70
+ drive
71
+ @interrupts.set(@c1_flag)
72
+ end
73
+
74
+ # A new C2 level. An active edge sets the flag while C2 is an input.
75
+ def c2=(high)
76
+ return if high == @c2_high
77
+
78
+ @c2_high = high
79
+ @interrupts.set(@c2_flag) if @control.nobits?(0x08) && high == @control.anybits?(0x04)
80
+ end
81
+
82
+ # A read or write of the handshaking port register.
83
+ def access!(write)
84
+ @interrupts.clear(independent? ? @c1_flag : @c1_flag | @c2_flag)
85
+ return unless write || @handshake_on_read
86
+
87
+ case @control >> 1
88
+ when 4 then @handshake_low = true
89
+ when 5 then @pulse = 2
90
+ end
91
+ drive
92
+ end
93
+
94
+ private
95
+
96
+ def independent? = @control & 0x0a == 0x02
97
+
98
+ def drive
99
+ @c2_output = case @control >> 1
100
+ when 4 then !@handshake_low
101
+ when 5 then @pulse.zero?
102
+ when 6 then false
103
+ else true
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIA
6
+ # Running a VIA a stretch of cycles at once while nothing but its
7
+ # counters would change, for Drives::Engine::Idle.
8
+ module FastForward
9
+ # quiet_cycles for a VIA that will never set a flag of its own.
10
+ QUIET = 1 << 40
11
+
12
+ # How many cycles the VIA can run with nothing but its counters
13
+ # changing: no flag set, no pulse on a control line and no bit
14
+ # shifted. See Drives::Engine::Idle.
15
+ def quiet_cycles
16
+ return 0 if @sr_uses_t2 || @shift_register.clocking? || @ca.pulsing? || @cb.pulsing?
17
+
18
+ [@t1.quiet_cycles, @t2.quiet_cycles].min
19
+ end
20
+
21
+ # Runs +cycles+ cycles at once, as many as quiet_cycles allows, which
22
+ # moves only the counters.
23
+ def fast_forward(cycles)
24
+ return if cycles.zero?
25
+
26
+ @t1.fast_forward(cycles)
27
+ @t2.fast_forward(cycles)
28
+ end
29
+
30
+ # The counters an orbit (see Drives::Engine::Idle) has to bring back: those
31
+ # of the armed timers, and of the timers +touched+ names (bit 0 for
32
+ # timer 1, bit 1 for timer 2). The others only count.
33
+ def counter_state(touched)
34
+ [(@t1.count_state if @t1.armed? || touched.anybits?(1)),
35
+ (@t2.count_state if @t2.armed? || touched.anybits?(2))]
36
+ end
37
+
38
+ # Runs +cycles+ cycles of whole orbits at once: the counters
39
+ # counter_state leaves out move on, and the rest come back round.
40
+ def skip_orbits(cycles, touched)
41
+ @t1.fast_forward(cycles) unless @t1.armed? || touched.anybits?(1)
42
+ @t2.fast_forward(cycles) unless @t2.armed? || touched.anybits?(2)
43
+ end
44
+
45
+ # Everything the VIA holds but its counters, for comparing it at two
46
+ # points. Timer 1's PB7 level counts only while ACR bit 7 puts it on
47
+ # the pin: nothing reads it otherwise.
48
+ def idle_state
49
+ [@ora, @orb, @ddra, @ddrb, @latch_a, @latch_b, @acr, @pcr, @pb6_high, @ifr.flags, @ifr.enable,
50
+ @acr.anybits?(0x80) && @t1.pb7, *@t1.state, *@t2.state, *@ca.state, *@cb.state, *@shift_register.state]
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIA
6
+ # The interrupt flag and enable registers. Each source has a flag bit,
7
+ # and IRQ is pulled low while any flag is set with its enable bit.
8
+ class InterruptRegister
9
+ CA2 = 0x01
10
+ CA1 = 0x02
11
+ SR = 0x04
12
+ CB2 = 0x08
13
+ CB1 = 0x10
14
+ TIMER2 = 0x20
15
+ TIMER1 = 0x40
16
+
17
+ attr_reader :flags, :enable
18
+
19
+ def initialize
20
+ reset!
21
+ end
22
+
23
+ def reset!
24
+ @flags = 0x00
25
+ @enable = 0x00
26
+ end
27
+
28
+ def set(bits)
29
+ @flags |= bits
30
+ end
31
+
32
+ def clear(bits)
33
+ @flags &= ~bits
34
+ end
35
+
36
+ def irq? = @flags.anybits?(@enable)
37
+
38
+ # Bit 7 reads the IRQ output.
39
+ def read = irq? ? @flags | 0x80 : @flags
40
+
41
+ # Writing 1s clears the flags; bit 7 is ignored.
42
+ def write(value)
43
+ clear(value & 0x7f)
44
+ end
45
+
46
+ # Bit 7 reads as 1.
47
+ def read_enable = @enable | 0x80
48
+
49
+ # Bit 7 picks between setting and clearing the enable bits given.
50
+ def write_enable(value)
51
+ if value.anybits?(0x80)
52
+ @enable |= value & 0x7f
53
+ else
54
+ @enable &= ~value & 0x7f
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIA
6
+ class Timer1
7
+ # Timer 1's fields in a keyed snapshot module, under `prefix`.
8
+ module KeyedState
9
+ def save_fields(out, prefix)
10
+ out.int("#{prefix}counter", @counter).int("#{prefix}latch", @latch).bool("#{prefix}hold", @hold)
11
+ out.bool("#{prefix}reload", @reload).bool("#{prefix}armed", @armed).bool("#{prefix}pb7", @pb7)
12
+ end
13
+
14
+ def load_fields(input, prefix)
15
+ @counter = input.word("#{prefix}counter", @counter)
16
+ @latch = input.word("#{prefix}latch", @latch)
17
+ @hold = input.bool("#{prefix}hold", @hold)
18
+ @reload = input.bool("#{prefix}reload", @reload)
19
+ @armed = input.bool("#{prefix}armed", @armed)
20
+ @pb7 = input.bool("#{prefix}pb7", @pb7)
21
+ end
22
+ end
23
+
24
+ include KeyedState
25
+ end
26
+
27
+ class Timer2
28
+ # Timer 2's fields in a keyed snapshot module, under `prefix`.
29
+ module KeyedState
30
+ def save_fields(out, prefix)
31
+ out.int("#{prefix}counter", @counter).int("#{prefix}latch_low", @latch_low).bool("#{prefix}hold", @hold)
32
+ out.bool("#{prefix}low_reload", @low_reload).bool("#{prefix}armed", @armed)
33
+ out.bool("#{prefix}low_underflowed", @low_underflowed).bool("#{prefix}count_pulses", @count_pulses)
34
+ out.bool("#{prefix}counting_pulses", @counting_pulses)
35
+ end
36
+
37
+ def load_fields(input, prefix)
38
+ @counter = input.word("#{prefix}counter", @counter)
39
+ @latch_low = input.byte("#{prefix}latch_low", @latch_low)
40
+ @hold = input.bool("#{prefix}hold", @hold)
41
+ @low_reload = input.bool("#{prefix}low_reload", @low_reload)
42
+ @armed = input.bool("#{prefix}armed", @armed)
43
+ @low_underflowed = input.bool("#{prefix}low_underflowed", @low_underflowed)
44
+ @count_pulses = input.bool("#{prefix}count_pulses", @count_pulses)
45
+ @counting_pulses = input.bool("#{prefix}counting_pulses", @counting_pulses)
46
+ end
47
+ end
48
+
49
+ include KeyedState
50
+ end
51
+
52
+ class ShiftRegister
53
+ # The shift register's fields in a keyed snapshot module, under
54
+ # `prefix`.
55
+ module KeyedState
56
+ def save_fields(out, prefix)
57
+ out.int("#{prefix}mode", @mode).int("#{prefix}data", @data).int("#{prefix}bits", @bits)
58
+ out.int("#{prefix}delay", @delay).bool("#{prefix}clock", @clock).bool("#{prefix}cb2", @cb2)
59
+ out.bool("#{prefix}cb2_input", @cb2_input)
60
+ end
61
+
62
+ def load_fields(input, prefix)
63
+ @mode = input.masked("#{prefix}mode", @mode, 0x07)
64
+ @data = input.byte("#{prefix}data", @data)
65
+ @bits = input.int("#{prefix}bits", @bits)
66
+ @delay = input.int("#{prefix}delay", @delay)
67
+ @clock = input.bool("#{prefix}clock", @clock)
68
+ @cb2 = input.bool("#{prefix}cb2", @cb2)
69
+ @cb2_input = input.bool("#{prefix}cb2_input", @cb2_input)
70
+ end
71
+ end
72
+
73
+ include KeyedState
74
+ end
75
+
76
+ class InterruptRegister
77
+ # The flags and the enable mask, under `prefix`.
78
+ module KeyedState
79
+ def save_fields(out, prefix)
80
+ out.int("#{prefix}flags", @flags).int("#{prefix}enable", @enable)
81
+ end
82
+
83
+ def load_fields(input, prefix)
84
+ @flags = input.masked("#{prefix}flags", @flags, 0x7f)
85
+ @enable = input.masked("#{prefix}enable", @enable, 0x7f)
86
+ end
87
+ end
88
+
89
+ include KeyedState
90
+ end
91
+
92
+ class ControlLines
93
+ # A pair of control lines' fields, under `prefix`.
94
+ module KeyedState
95
+ def save_fields(out, prefix)
96
+ out.int("#{prefix}control", @control).bool("#{prefix}c1_high", @c1_high).bool("#{prefix}c2_high", @c2_high)
97
+ out.bool("#{prefix}handshake_low", @handshake_low).int("#{prefix}pulse", @pulse)
98
+ out.bool("#{prefix}c2_output", @c2_output)
99
+ end
100
+
101
+ def load_fields(input, prefix)
102
+ @control = input.masked("#{prefix}control", @control, 0x0f)
103
+ @c1_high = input.bool("#{prefix}c1_high", @c1_high)
104
+ @c2_high = input.bool("#{prefix}c2_high", @c2_high)
105
+ @handshake_low = input.bool("#{prefix}handshake_low", @handshake_low)
106
+ @pulse = input.int("#{prefix}pulse", @pulse)
107
+ @c2_output = input.bool("#{prefix}c2_output", @c2_output)
108
+ end
109
+ end
110
+
111
+ include KeyedState
112
+ end
113
+
114
+ # The VIA's fields in a keyed snapshot module (Snapshot::Keyed): the
115
+ # registers and PB6, and its parts under t1., t2., sr., ifr., ca. and
116
+ # cb. Whether the shift register clocks off timer 2 comes from the
117
+ # ACR on load. The peripheral restores its own state.
118
+ module KeyedState
119
+ def save_fields(out)
120
+ out.int("ora", @ora).int("orb", @orb).int("ddra", @ddra).int("ddrb", @ddrb).int("latch_a", @latch_a)
121
+ out.int("latch_b", @latch_b).int("acr", @acr).int("pcr", @pcr).bool("pb6_high", @pb6_high)
122
+ @t1.save_fields(out, "t1.")
123
+ @t2.save_fields(out, "t2.")
124
+ @shift_register.save_fields(out, "sr.")
125
+ @ifr.save_fields(out, "ifr.")
126
+ @ca.save_fields(out, "ca.")
127
+ @cb.save_fields(out, "cb.")
128
+ out
129
+ end
130
+
131
+ def load_fields(input)
132
+ @ora = input.byte("ora", @ora)
133
+ @orb = input.byte("orb", @orb)
134
+ @ddra = input.byte("ddra", @ddra)
135
+ @ddrb = input.byte("ddrb", @ddrb)
136
+ @latch_a = input.byte("latch_a", @latch_a)
137
+ @latch_b = input.byte("latch_b", @latch_b)
138
+ @acr = input.byte("acr", @acr)
139
+ @pcr = input.byte("pcr", @pcr)
140
+ @pb6_high = input.bool("pb6_high", @pb6_high)
141
+ load_part_fields(input)
142
+ end
143
+
144
+ def restored!
145
+ @sr_uses_t2 = [1, 4, 5].include?((@acr >> 2) & 0x07)
146
+ end
147
+
148
+ private
149
+
150
+ def load_part_fields(input)
151
+ @t1.load_fields(input, "t1.")
152
+ @t2.load_fields(input, "t2.")
153
+ @shift_register.load_fields(input, "sr.")
154
+ @ifr.load_fields(input, "ifr.")
155
+ @ca.load_fields(input, "ca.")
156
+ @cb.load_fields(input, "cb.")
157
+ end
158
+ end
159
+
160
+ include KeyedState
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,168 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIA
6
+ # The 6522's shift register, with the CB1 clock and CB2 data lines it
7
+ # takes over in every mode but the first.
8
+ #
9
+ # ACR bits 4-2 pick the mode. Modes 1 to 3 shift in, left, with the new
10
+ # bit taken from CB2 into bit 0 on each rising CB1 edge. Modes 4 to 7
11
+ # shift out: each falling CB1 edge puts bit 7 on CB2 and rotates it back
12
+ # round into bit 0, so after eight bits the byte is back where it
13
+ # started. Modes 1, 4 and 5 clock off timer 2, modes 2 and 6 off φ2, and
14
+ # modes 3 and 7 off whatever drives CB1 from outside.
15
+ #
16
+ # Under its own clock the register drives CB1, idling high. Reading or
17
+ # writing the data register starts a byte, but only while the register
18
+ # is idle and enabled: an access in mode 0, or one before the eighth bit
19
+ # is in, leaves the count alone. CB1 falls on the first clock tick of
20
+ # the byte and rises on the second, and so on, so a byte is eight pulses
21
+ # over sixteen ticks. The interrupt flag is set on the tick that raises
22
+ # CB1 over the eighth bit, and CB1 then stays high until the next
23
+ # access.
24
+ #
25
+ # In modes 2 and 6 a tick is a φ2 cycle, from the second cycle after
26
+ # the access on, which makes a byte sixteen cycles. In modes 1, 4 and 5
27
+ # it comes two cycles after each timer 2 low byte underflow, on the
28
+ # cycle after the low byte reloads, which makes a byte sixteen
29
+ # underflows. Mode 4 never stops and never interrupts: its counter is
30
+ # disabled, and the byte goes round and round.
31
+ #
32
+ # Under an external clock the register shifts on every CB1 edge, access
33
+ # or not. The access only arms the counter: the flag is set on the eighth
34
+ # rising edge after it, and the counter then waits for the next access.
35
+ class ShiftRegister
36
+ DISABLED = 0
37
+ IN_T2 = 1
38
+ IN_PHI2 = 2
39
+ IN_EXTERNAL = 3
40
+ OUT_FREE_RUNNING = 4
41
+ OUT_T2 = 5
42
+ OUT_PHI2 = 6
43
+ OUT_EXTERNAL = 7
44
+
45
+ attr_reader :mode, :data
46
+ attr_accessor :cb2_input
47
+
48
+ def initialize
49
+ @mode = DISABLED
50
+ @data = 0x00
51
+ # Bits still to count before the flag, zero when the counter is idle.
52
+ @bits = 0
53
+ # The clock's last two cycles, newest in bit 0: timer 2 low byte
54
+ # underflows in modes 1, 4 and 5, and whether the byte has started
55
+ # in modes 2 and 6.
56
+ @delay = 0
57
+ @clock = true
58
+ @cb2 = true
59
+ # Nothing drives CB2 from outside, so it floats high.
60
+ @cb2_input = true
61
+ end
62
+
63
+ def mode=(value)
64
+ @mode = value & 0x07
65
+ end
66
+
67
+ def data=(value)
68
+ @data = value & 0xff
69
+ end
70
+
71
+ # A read or write of the data register, which starts a byte if the
72
+ # register is idle and enabled.
73
+ def access!
74
+ return if @mode == DISABLED || @bits.nonzero?
75
+
76
+ @bits = 8
77
+ @delay = 0 if @mode == IN_PHI2 || @mode == OUT_PHI2
78
+ end
79
+
80
+ # Whether the register is counting bits off its own clock, which
81
+ # changes it from cycle to cycle.
82
+ def clocking? = @bits.nonzero? && internal_clock?
83
+
84
+ # Everything the register holds, for comparing it at two points.
85
+ def state = [@mode, @data, @bits, @delay, @clock, @cb2, @cb2_input]
86
+
87
+ # The CB1 level the register drives, or nil when CB1 is an input.
88
+ def cb1_output
89
+ internal_clock? ? @clock : nil
90
+ end
91
+
92
+ # The CB2 level the register drives, or nil when it doesn't.
93
+ def cb2_output
94
+ @mode >= OUT_FREE_RUNNING ? @cb2 : nil
95
+ end
96
+
97
+ # Clocked once per φ2 cycle, with whether timer 2's low byte underflowed
98
+ # on it. Returns true on the cycle that sets the interrupt flag.
99
+ def cycle!(t2_low_underflow)
100
+ case @mode
101
+ when IN_PHI2, OUT_PHI2 then @bits.nonzero? && phi2_tick
102
+ when IN_T2, OUT_T2, OUT_FREE_RUNNING then t2_tick(t2_low_underflow)
103
+ else false
104
+ end
105
+ end
106
+
107
+ # A level change on CB1 from outside. Only the external clock modes
108
+ # listen: shifting in samples CB2 as CB1 rises, and shifting out puts
109
+ # the next bit on CB2 as it falls. Returns true when the edge sets the
110
+ # interrupt flag.
111
+ def cb1_edge!(rising)
112
+ return false unless @mode == IN_EXTERNAL || @mode == OUT_EXTERNAL
113
+
114
+ shift_in if rising && @mode == IN_EXTERNAL
115
+ shift_out if !rising && @mode == OUT_EXTERNAL
116
+ rising && eighth_bit?
117
+ end
118
+
119
+ private
120
+
121
+ def internal_clock?
122
+ @mode != DISABLED && @mode != IN_EXTERNAL && @mode != OUT_EXTERNAL
123
+ end
124
+
125
+ # A φ2 cycle of a byte: every one but the first ticks.
126
+ def phi2_tick
127
+ started = @delay.nonzero?
128
+ @delay = 1
129
+ started && tick
130
+ end
131
+
132
+ # Ticks on the underflow from two cycles back, while a byte is under
133
+ # way.
134
+ def t2_tick(underflow)
135
+ due = @delay.anybits?(2)
136
+ @delay = ((@delay << 1) & 2) | (underflow ? 1 : 0)
137
+ due && @bits.nonzero? && tick
138
+ end
139
+
140
+ # One half period of the register's own clock: a falling edge puts a
141
+ # bit out, and a rising one takes a bit in and counts it.
142
+ def tick
143
+ @clock = !@clock
144
+ shift_out if !@clock && @mode >= OUT_FREE_RUNNING
145
+ shift_in if @clock && @mode < IN_EXTERNAL
146
+ @clock && @mode != OUT_FREE_RUNNING && eighth_bit?
147
+ end
148
+
149
+ # Counts a bit, and says whether it was the eighth since the access.
150
+ def eighth_bit?
151
+ return false if @bits.zero?
152
+
153
+ @bits -= 1
154
+ @bits.zero?
155
+ end
156
+
157
+ def shift_in
158
+ @data = ((@data << 1) | (@cb2_input ? 1 : 0)) & 0xff
159
+ end
160
+
161
+ def shift_out
162
+ @cb2 = @data.anybits?(0x80)
163
+ @data = ((@data << 1) | (@cb2 ? 1 : 0)) & 0xff
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VIA
6
+ # Timer 1: a 16-bit counter that decrements on every φ2 cycle, with a
7
+ # latch it reloads from on every timeout and the PB7 output.
8
+ #
9
+ # Writing the high counter byte loads the counter on the cycle after,
10
+ # so a timer loaded with N reads N, N-1, ... 0 and then $FFFF, which is
11
+ # the cycle its interrupt flag sets: N + 1.5 cycles after the write in
12
+ # the datasheet's terms. The counter then reloads from the latch on the
13
+ # next cycle, which makes the period N + 2 cycles. It does so in one-shot
14
+ # mode too, unlike timer 2.
15
+ #
16
+ # Only a write of the high counter byte arms the timer. An armed timeout
17
+ # sets the flag and inverts PB7, and in one-shot mode disarms it, so the
18
+ # first timeout after the load alone does. Free-running keeps it armed,
19
+ # but switching to free-running doesn't arm it: an unarmed timer counts
20
+ # and reloads without touching the flag or PB7. The load pulls PB7 low,
21
+ # and ACR bit 7 turning on drives it high, so a timer loaded before its
22
+ # PB7 output is enabled reads high until the timeout pulls it low.
23
+ class Timer1
24
+ attr_accessor :counter, :latch
25
+
26
+ # The level the timer drives on PB7 when ACR bit 7 hands it the pin.
27
+ attr_reader :pb7
28
+
29
+ # ACR bit 7 turning on hands PB7 to the timer high.
30
+ def pb7_enabled!
31
+ @pb7 = true
32
+ end
33
+
34
+ def initialize
35
+ @counter = @latch = 0xffff
36
+ @reload = @hold = false
37
+ @armed = false
38
+ @pb7 = true
39
+ end
40
+
41
+ def write_latch_low(value)
42
+ @latch = (@latch & 0xff00) | value
43
+ end
44
+
45
+ def write_latch_high(value)
46
+ @latch = (value << 8) | (@latch & 0xff)
47
+ end
48
+
49
+ # The high counter byte write: load from the latch, hold the count
50
+ # for a cycle, arm the interrupt and pull PB7 low.
51
+ def start!
52
+ @counter = @latch
53
+ @hold = true
54
+ @reload = false
55
+ @armed = true
56
+ @pb7 = false
57
+ end
58
+
59
+ # One φ2 cycle. Returns true on the cycle that sets the interrupt flag.
60
+ def cycle!(free_run)
61
+ if @hold || @reload
62
+ @counter = @latch if @reload
63
+ @hold = @reload = false
64
+ return false
65
+ end
66
+ @counter = (@counter - 1) & 0xffff
67
+ @counter == 0xffff && timeout(free_run)
68
+ end
69
+
70
+ # How many cycles the timer can run without setting its flag: until
71
+ # an armed timer's timeout, and forever for an unarmed one, whose
72
+ # timeouts only reload the counter. None while an armed timer loads
73
+ # or reloads.
74
+ def quiet_cycles
75
+ return FastForward::QUIET unless @armed
76
+ return 0 if @hold || @reload
77
+
78
+ @counter
79
+ end
80
+
81
+ # Runs +cycles+ cycles at once, as many as quiet_cycles allows. An
82
+ # unarmed timer goes round its period of latch + 2 cycles: the
83
+ # timeout at $FFFF, the reload, and latch down to 0.
84
+ def fast_forward(cycles)
85
+ if @hold || @reload
86
+ cycle!(false)
87
+ cycles -= 1
88
+ end
89
+ return @counter -= cycles if cycles <= @counter
90
+
91
+ phase = (cycles - @counter - 1) % (@latch + 2)
92
+ @reload = phase.zero?
93
+ @counter = @reload ? 0xffff : @latch - phase + 1
94
+ end
95
+
96
+ # What the counter and PB7 don't hold, for comparing the timer at two
97
+ # points.
98
+ def state = [@latch, @armed]
99
+
100
+ # Whether a timeout sets the flag.
101
+ def armed? = @armed
102
+
103
+ # The count, for comparing the timer at two points where it matters.
104
+ def count_state = [@counter, @hold, @reload]
105
+
106
+ private
107
+
108
+ # The counter reloads either way. Armed, PB7 inverts and the flag
109
+ # sets, and one-shot mode disarms. Returns whether the flag sets.
110
+ def timeout(free_run)
111
+ interrupt = @armed
112
+ @reload = true
113
+ @pb7 = !@pb7 if @armed
114
+ @armed &&= free_run
115
+ interrupt
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end