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
data/lib/badline/cia.rb DELETED
@@ -1,279 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "badline/cia/interrupt_register"
4
- require "badline/cia/serial"
5
- require "badline/cia/timer"
6
- require "badline/cia/state"
7
- require "badline/cia/fast_forward"
8
-
9
- module Badline
10
- # CIA (Complex Interface Adapter) chip
11
- class CIA
12
- include Addressable
13
- include State
14
- include FastForward
15
-
16
- # The original NMOS 6526 of the breadbin C64, and the HMOS 6526A of the
17
- # C64C, which differs from it only in its interrupt control register.
18
- MODELS = %i[mos6526 mos6526a].freeze
19
-
20
- attr_reader :start, :control_a, :control_b, :serial, :model
21
-
22
- # What's on the ports outside the chip. It pulls port lines low through
23
- # read_a and read_b, and on CIA 1 drives PB4 through port_b4_high?.
24
- attr_accessor :peripheral
25
-
26
- # Timer A and timer B.
27
- def timers = [@ta, @tb]
28
-
29
- # Port A and B's data and direction registers.
30
- def port_registers = [@data_port_a, @data_port_b, @data_dir_a, @data_dir_b]
31
-
32
- def interrupt_status = @icr.status
33
-
34
- def interrupt_control = @icr.mask
35
-
36
- def interrupt!(delay = 1) = @icr.assert!(delay)
37
-
38
- def time_of_day = @tod
39
-
40
- def timer_a = @ta.counter
41
-
42
- def timer_a=(value)
43
- @ta.counter = value
44
- end
45
-
46
- def timer_a_latch = @ta.latch
47
-
48
- def timer_a_latch=(value)
49
- @ta.latch = value
50
- end
51
-
52
- def timer_b = @tb.counter
53
-
54
- def timer_b=(value)
55
- @tb.counter = value
56
- end
57
-
58
- def timer_b_latch = @tb.latch
59
-
60
- def timer_b_latch=(value)
61
- @tb.latch = value
62
- end
63
-
64
- # +tod_hz+ is the rate of the pulses on the TOD pin, the region's mains
65
- # unless a machine feeds it otherwise, and 0 for a pin held still.
66
- def initialize(start: 0, peripheral: nil, model: :mos6526, region: Region::PAL, tod_hz: nil)
67
- raise ArgumentError, "unknown CIA model #{model}" unless MODELS.include?(model)
68
-
69
- addressable_at(start, length: 2**8)
70
-
71
- @model = model
72
- @clock_hz = region.clock_hz
73
- @mains_hz = tod_hz || region.mains_hz
74
-
75
- @peripheral = peripheral
76
- @port_b4_handler = nil
77
- @port_a_handler = nil
78
- @port_b4_high = true
79
- reset!
80
- end
81
-
82
- # The RES line: ports back to inputs, timers stopped with their latches
83
- # full, interrupts masked and the TOD clock stopped at 1:00:00.0. The
84
- # PB4 level carries over and is resampled on the next cycle.
85
- def reset!
86
- @data_port_a = 0x00
87
- @data_port_b = 0x00
88
- @data_dir_a = 0x00
89
- @data_dir_b = 0x00
90
- @port_b4_driven_high = true
91
- @cnt_high = true
92
- @cnt_rise = false
93
- @tod = TimeOfDay.new(clock_hz: @clock_hz, mains_hz: @mains_hz)
94
- @icr = InterruptRegister.new(@model)
95
- @icr_status = @icr.status
96
- @control_a = ControlRegister.new(%i[start output out_mode run_mode load
97
- in_mode serial_mode clock_frequency])
98
- @control_b = ControlRegister.new(%i[start output out_mode run_mode load
99
- in_cnt in_timer_a alarm])
100
- @ta = Timer.new(@control_a)
101
- @tb = Timer.new(@control_b)
102
- @serial = Serial.new(@control_a)
103
- @port_a_handler&.call
104
- end
105
-
106
- # Register a change handler on the PB4 line. On CIA 1, this feeds the
107
- # light pen input.
108
- def on_port_b4_change(&handler)
109
- @port_b4_handler = handler
110
- end
111
-
112
- # Register a handler for writes that can move port A's lines: to the
113
- # data register or DDR, and the reset. On CIA 2, this tells the drives
114
- # on the serial bus that the C64 may have moved a line.
115
- def on_port_a_write(&handler)
116
- @port_a_handler = handler
117
- end
118
-
119
- # A falling edge on the FLAG pin. On CIA 1 the datasette's tape read
120
- # line drives it, on CIA 2 the serial bus SRQ.
121
- def flag! = raise_interrupt(:flag)
122
-
123
- def interrupted? = @icr_status.value >= 0x80
124
-
125
- def cycle!
126
- @icr.cycle! unless @icr.quiet
127
- refresh_port_b4 if @port_b4_handler
128
- level = @serial.cnt
129
- level == @cnt_high ? @cnt_rise = false : cnt_edge(level)
130
- underflowed = update_timers
131
- @serial.cycle!(underflowed) { trigger_serial } if underflowed || !@serial.idle
132
- @tod.cycle! { trigger_alarm }
133
- end
134
-
135
- def read_port_a
136
- lines = driven_lines(@data_port_a, @data_dir_a)
137
- return lines unless peripheral
138
-
139
- lines & peripheral.read_a(lines, driven_lines(@data_port_b, @data_dir_b))
140
- end
141
-
142
- # Port A as driven by the data/direction registers alone, without
143
- # peripheral pulldown. Cheap path for the VIC bank lookup.
144
- def port_a_lines = driven_lines(@data_port_a, @data_dir_a)
145
-
146
- # Port B as driven by the data/direction registers alone.
147
- def port_b_lines = driven_lines(@data_port_b, @data_dir_b)
148
-
149
- def read_port_b
150
- lines = driven_lines(@data_port_b, @data_dir_b)
151
- lines &= peripheral.read_b(driven_lines(@data_port_a, @data_dir_a), lines) if peripheral
152
- apply_timer_output(lines)
153
- end
154
-
155
- def peek(addr)
156
- case offset_of(addr) & 0x0f
157
- when 0x00 then read_port_a
158
- when 0x01 then read_port_b
159
- when 0x02 then @data_dir_a
160
- when 0x03 then @data_dir_b
161
- when 0x04 then low_byte(@ta.counter)
162
- when 0x05 then high_byte(@ta.counter)
163
- when 0x06 then low_byte(@tb.counter)
164
- when 0x07 then high_byte(@tb.counter)
165
- when 0x08 then @tod.tenths
166
- when 0x09 then @tod.seconds
167
- when 0x0a then @tod.minutes
168
- when 0x0b then @tod.hours
169
- when 0x0c then @serial.data
170
- when 0x0d then @icr.read
171
- when 0x0e then control_a.value
172
- when 0x0f then control_b.value
173
- end
174
- end
175
-
176
- def poke(addr, value)
177
- case offset_of(addr) & 0x0f
178
- when 0x00 then update_port_a { @data_port_a = value }
179
- when 0x01 then update_port_b { @data_port_b = value }
180
- when 0x02 then update_port_a { @data_dir_a = value }
181
- when 0x03 then update_port_b { @data_dir_b = value }
182
- when 0x04 then @ta.write_latch_low(value)
183
- when 0x05 then @ta.write_latch_high(value)
184
- when 0x06 then @tb.write_latch_low(value)
185
- when 0x07 then @tb.write_latch_high(value)
186
- when 0x08 then @tod.write(:tenths, value, alarm: control_b.alarm?)
187
- when 0x09 then @tod.write(:seconds, value, alarm: control_b.alarm?)
188
- when 0x0a then @tod.write(:minutes, value, alarm: control_b.alarm?)
189
- when 0x0b then @tod.write_hours(value, alarm: control_b.alarm?)
190
- when 0x0c then @serial.write(value)
191
- when 0x0d then @icr.write(value)
192
- when 0x0e then write_control_a(value)
193
- when 0x0f then @tb.write_control(value)
194
- end
195
- end
196
-
197
- private
198
-
199
- def update_port_a
200
- yield
201
- @port_a_handler&.call
202
- end
203
-
204
- def update_port_b
205
- yield
206
- @port_b4_driven_high = driven_lines(@data_port_b, @data_dir_b).anybits?(0x10)
207
- refresh_port_b4 if @port_b4_handler
208
- end
209
-
210
- # PB4 is also control port 1's fire line, and a peripheral pulls it low
211
- # without any register write, so the level is resampled every cycle rather
212
- # than only after a poke.
213
- def refresh_port_b4
214
- high = @port_b4_driven_high && (peripheral.nil? || peripheral.port_b4_high?)
215
- return if high == @port_b4_high
216
-
217
- @port_b4_high = high
218
- @port_b4_handler.call(high)
219
- end
220
-
221
- def driven_lines(register, direction)
222
- # Output bits are driven from the data register; input bits float high.
223
- # External peripherals can still pull any line low (wired-AND).
224
- (register & direction) | (~direction & 0xff)
225
- end
226
-
227
- def apply_timer_output(value)
228
- value = with_bit(value, 6, @ta.output?) if control_a.output?
229
- value = with_bit(value, 7, @tb.output?) if control_b.output?
230
- value
231
- end
232
-
233
- def with_bit(value, bit, set)
234
- set ? value | (1 << bit) : value & ~(1 << bit)
235
- end
236
-
237
- def trigger_alarm = raise_interrupt(:alarm)
238
- def trigger_serial = raise_interrupt(:serial)
239
-
240
- def raise_interrupt(source) = @icr.flag(source)
241
-
242
- # CNT is sampled once a cycle. When the serial port drives it from this
243
- # cycle's timer A underflow, the new level is picked up on the next one.
244
- def cnt_edge(level)
245
- @cnt_high = level
246
- @cnt_rise = level
247
- @serial.rising_edge! { trigger_serial } if level
248
- end
249
-
250
- # Returns whether timer A underflowed, which clocks the serial port.
251
- #
252
- # CRB bits 6-5 pick timer B's source: ø2, CNT edges, timer A
253
- # underflows, or timer A underflows gated by the CNT level. Every source
254
- # drives the same count-enable line, so a cascaded underflow goes through
255
- # the input pipeline exactly as a CNT edge does.
256
- def update_timers
257
- @ta.cycle!(@control_a.value & 0x20 == 0x20 ? @cnt_rise : true)
258
- underflowed = @ta.underflowed
259
- @tb.cycle!(
260
- case @control_b.value & 0x60
261
- when 0x00 then true
262
- when 0x20 then @cnt_rise
263
- when 0x40 then underflowed
264
- else underflowed && @cnt_high
265
- end
266
- )
267
- @icr.flag(:timer_a) if underflowed
268
- @icr.timer_b_underflow! if @tb.underflowed
269
- underflowed
270
- end
271
-
272
- def write_control_a(value)
273
- was_output = control_a.serial_mode?
274
- @ta.write_control(value)
275
- @serial.reset! { trigger_serial } if control_a.serial_mode? != was_output
276
- @tod.fifty_hz = control_a.clock_frequency?
277
- end
278
- end
279
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- # Colour RAM is four bits wide. A CPU read takes the upper nibble off the
5
- # open data bus, which still holds the byte the VIC fetched in phi1.
6
- class ColorMemory < Memory
7
- def initialize(vic, start: 0xd800, length: 2**10)
8
- super(start:, length:)
9
- @vic = vic
10
- end
11
-
12
- def peek(addr)
13
- (@vic.phi1_data & 0xf0) | @storage[offset_of(addr)]
14
- end
15
-
16
- def poke(addr, value)
17
- super(addr, value & 0x0f)
18
- end
19
-
20
- # The four bits the cell stores, as the VIC's c-access sees them.
21
- def nibble(addr)
22
- @storage[offset_of(addr)]
23
- end
24
- end
25
- end
@@ -1,88 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Computer
5
- # What plugs into the machine besides its chips, the cartridge, its
6
- # true drives (TrueDrives) and an REU, and their state for a snapshot.
7
- # The disk device 8 serves through the traps is KernalTraps'.
8
- module Attachments
9
- include TrueDrives
10
-
11
- # Puts the cartridge in the expansion port and wires its clock and NMI
12
- # line to the machine, leaving the machine's state as it is. A
13
- # restored snapshot's cartridge comes back through here.
14
- def connect_cartridge(cartridge)
15
- cartridge.clock = -> { @cycles }
16
- cartridge.on_nmi_change { |level| @cartridge_nmi = level }
17
- address_bus.attach_cartridge(cartridge)
18
- end
19
-
20
- # The serial bus, which CIA 2's port A drives through the C64's own
21
- # inverters and reads back on PA6 and PA7, with or without a drive on
22
- # it.
23
- attr_reader :iec_bus
24
-
25
- private
26
-
27
- # CIA 2's port A drives the serial bus, which reads CLK and DATA back
28
- # into it.
29
- def plug_serial_bus
30
- @iec_bus = IECBus.new
31
- @cia2.peripheral = @iec_bus
32
- @cia2.on_port_a_write { push_serial_lines }
33
- push_serial_lines
34
- end
35
-
36
- # Pushes the lines CIA 2's port A pulls into the serial bus.
37
- def push_serial_lines
38
- @iec_bus.host_lines = @cia2.port_a_lines
39
- end
40
-
41
- def save_cartridge(out)
42
- cartridge = address_bus.cartridge
43
- out.boolean(!cartridge.nil?)
44
- cartridge&.save_setup(out)
45
- end
46
-
47
- # A cartridge comes back built afresh from the setup it was built
48
- # with, before the address bus puts its state into it.
49
- def load_cartridge(input)
50
- if input.boolean?
51
- connect_cartridge(Cartridge.from_setup(input))
52
- elsif address_bus.cartridge
53
- address_bus.detach_cartridge
54
- end
55
- end
56
-
57
- # A true 1541 on the serial bus, then a 1581. The leading flag is the
58
- # bus itself, which every machine now has.
59
- def save_serial_bus(out)
60
- out.boolean(true).boolean(!@drive1541.nil?)
61
- if @drive1541
62
- out.int(@drive1541.device)
63
- @drive1541.save_state(out)
64
- end
65
- save_drive1581(out)
66
- end
67
-
68
- def load_serial_bus(input)
69
- input.boolean?
70
- load_drive1541(input)
71
- load_drive1581(input)
72
- end
73
-
74
- # The REU, which the setup says the machine has, and whether it has
75
- # asked for the bus. Its IRQ line reaches the CPU as it was.
76
- def save_reu(out)
77
- @reu&.save_state(out)
78
- out.boolean(@dma)
79
- end
80
-
81
- def load_reu(input)
82
- @reu&.load_state(input)
83
- @reu_irq = @reu ? @reu.irq? : false
84
- @dma = input.boolean?
85
- end
86
- end
87
- end
88
- end
@@ -1,117 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Computer
5
- # The keyword arguments Computer.new takes to build the machine a
6
- # State from #snapshot was taken of.
7
- def self.setup(state)
8
- input = Snapshot::StateReader.new(state)
9
- input.marker("COMPUTER")
10
- input.check_stamp
11
- Snapshot::Setup.read(input)
12
- end
13
-
14
- # A new machine, built as the one a State from #snapshot was taken of,
15
- # at that state. `detached` builds it without the host's files
16
- # (Snapshot::StateReader).
17
- def self.restored(state, detached: false) = setup(state).build.apply_state(state, detached:)
18
-
19
- # The whole machine's state for a snapshot: the machine's own latches,
20
- # the bus and its chips, the CPU, and what is attached to it
21
- # (Attachments).
22
- module SavedState
23
- # How many more on_init handlers the machine a State was taken of had
24
- # yet to run than this one has: they are the host's blocks, which a
25
- # State can't hold. Nil until the machine is restored.
26
- attr_reader :init_handlers_lost
27
-
28
- # The machine's whole state, in memory. #restore takes the machine, or
29
- # another built with the same chip models, region and RAM expansion,
30
- # back to it. The cartridge, the disk in device 8, a true 1541 and its
31
- # disk and the tape go in the state too. What the host holds stays
32
- # out: the keyboard, the joysticks and the pot devices, the traps and
33
- # callbacks, whether the display renders and whether the SID records.
34
- def snapshot
35
- out = Snapshot::StateWriter.new
36
- save_state(out)
37
- out.state
38
- end
39
-
40
- # Takes the machine back to a State from #snapshot. The machine keeps
41
- # its chips, its traps and its callbacks, and puts in the cartridge,
42
- # drives and tape the state has, taking out any it hasn't. Raises
43
- # Snapshot::FormatError for a state of a machine built another way.
44
- # The state goes into a new machine first, so one that fails leaves
45
- # this machine as it was.
46
- def restore(state)
47
- check_setup(Computer.setup(state))
48
- Computer.restored(state)
49
- apply_state(state)
50
- end
51
-
52
- # Puts a State into the machine without trying it on a new one
53
- # first, for a machine built for it (Computer.restored): a state that
54
- # fails leaves the machine part restored. `detached` restores it
55
- # without the host's files (Snapshot::StateReader).
56
- def apply_state(state, detached: false)
57
- input = Snapshot::StateReader.new(state, detached:)
58
- load_state(input)
59
- raise Snapshot::FormatError, "the state goes on past the machine" unless input.finished?
60
-
61
- self
62
- end
63
-
64
- # Sets the machine's cycle count, for a snapshot from VICE, which
65
- # counts from its own clock.
66
- def resume_at(cycles)
67
- @cycles = cycles
68
- end
69
-
70
- def save_state(out)
71
- out.marker("COMPUTER").stamp
72
- Snapshot::Setup.of(address_bus).write(out)
73
- out.int(@cycles).boolean(@nmi_asserted).boolean(@cartridge_nmi).boolean(@restore_pulse).boolean(@freezing)
74
- out.int(@freeze_writes).boolean(!@pending_keys.nil?)
75
- out.ints(@pending_keys) if @pending_keys
76
- out.int(booting? ? @init_handlers.length : 0)
77
- save_cartridge(out)
78
- address_bus.save_state(out)
79
- @cpu.save_state(out)
80
- save_trap_drive(out)
81
- save_serial_bus(out)
82
- save_reu(out)
83
- end
84
-
85
- def load_state(input)
86
- input.marker("COMPUTER")
87
- input.check_stamp
88
- check_setup(Snapshot::Setup.read(input))
89
- @cycles = input.int
90
- @nmi_asserted = input.boolean?
91
- @cartridge_nmi = input.boolean?
92
- @restore_pulse = input.boolean?
93
- @freezing = input.boolean?
94
- @freeze_writes = input.int
95
- @pending_keys = nil
96
- @pending_keys = input.ints if input.boolean?
97
- @init_handlers_lost = [input.int - @init_handlers.length, 0].max
98
- load_cartridge(input)
99
- address_bus.load_state(input)
100
- push_serial_lines
101
- @cpu.load_state(input)
102
- load_trap_drive(input)
103
- load_serial_bus(input)
104
- load_reu(input)
105
- end
106
-
107
- private
108
-
109
- def check_setup(setup)
110
- ours = Snapshot::Setup.of(address_bus)
111
- return if setup == ours
112
-
113
- raise Snapshot::FormatError, "the state is of a machine with #{setup}, not #{ours}"
114
- end
115
- end
116
- end
117
- end
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Computer
5
- # The true drives on the machine's serial bus: a Drive1541, and a
6
- # Drive1581 (Drive1581::Slot), each in a field of its own. Computer,
7
- # Vic20 and C128 each include it.
8
- module TrueDrives
9
- include Drive1581::Slot
10
-
11
- # Plugs in a Drive1541, which then runs alongside the machine on its
12
- # own clock and talks to it over the serial bus. The serial traps stop
13
- # answering the drive's device number, so the KERNAL's TALK, LISTEN and
14
- # byte transfers reach the drive. The LOAD and SAVE traps stay, and
15
- # still serve a mounted image.
16
- def attach_drive1541(drive)
17
- @iec_bus.detach(@drive1541) if @drive1541
18
- drive.host_clock_hz = timing.clock_hz
19
- @drive1541 = drive
20
- drive.connect(@iec_bus)
21
- @serial_trap&.device = serial_trap_device
22
- drive1541_attached
23
- end
24
-
25
- # The true drive on the serial bus: the Drive1581 ahead of the
26
- # Drive1541, or nil.
27
- def true_drive = @drive1581 || @drive1541
28
-
29
- # Plugs a Drive1541 in as device 8, in place of a 1581 there, and
30
- # returns it.
31
- def plug_true_drive
32
- detach_drive1581 if drive1581_on_device8?
33
- Drive1541.new.tap { |drive| attach_drive1541(drive) }
34
- end
35
-
36
- # Unplugs the Drive1541, leaving the serial bus with nothing on it.
37
- def detach_drive1541
38
- return unless @drive1541
39
-
40
- @iec_bus.detach(@drive1541)
41
- @drive1541 = nil
42
- @serial_trap&.device = serial_trap_device
43
- end
44
-
45
- private
46
-
47
- # The device number the serial traps answer: device 8, unless a true
48
- # drive is on the bus as device 8.
49
- def serial_trap_device
50
- device = KernalTrap::Routine::DEVICE
51
- @drive1541&.device == device || drive1581_on_device8? ? nil : device
52
- end
53
-
54
- # What the machine does as a 1541 goes on its bus. The VIC-20 waits
55
- # for its DOS to boot before typing.
56
- def drive1541_attached = nil
57
-
58
- # A true 1541 on the serial bus, with its device number.
59
- def load_drive1541(input)
60
- return detach_drive1541 unless input.boolean?
61
-
62
- device = input.int
63
- detach_drive1541 if @drive1541 && @drive1541.device != device
64
- attach_drive1541(Drive1541.new(device:)) unless @drive1541
65
- @drive1541.load_state(input)
66
- end
67
- end
68
- end
69
- end
@@ -1,76 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- # CIA 1's control ports and the keyboard matrix that spans them.
5
- #
6
- # Port A carries the matrix rows together with joystick 2, port B the matrix
7
- # columns together with joystick 1. Every switch is active low, so the
8
- # joysticks are wired-AND onto the lines *before* the matrix settles: a stick
9
- # held in a direction selects rows and columns of its own, which is where
10
- # hardware's phantom keypresses come from. Paddles and a 1351 mouse have
11
- # buttons on those same lines.
12
- #
13
- # The ports also carry SID's POTX/POTY lines, which reach them through analog
14
- # switches closed by CIA 1 PA6 (port 1) and PA7 (port 2). Close both and the
15
- # pots sit in parallel, so SID charges through the lower of the two
16
- # resistances; close neither and the lines float high. Reading a pot asks the
17
- # CIA for the current select lines, since a program sets them and then goes
18
- # straight to SID without touching the ports again.
19
- #
20
- # A matrix may have rows beyond port A's eight. Their select lines come from
21
- # outside the CIA and are pushed into +extra_rows+, bit 0 for the ninth row
22
- # upwards, active low like port A; idle, every line is high and none of
23
- # those rows is selected. They settle with port A's lines as rows 8 and up,
24
- # so their keys reach port B, but port A reads only its own eight.
25
- class ControlPorts
26
- PORT1_POTS = 0x40
27
- PORT2_POTS = 0x80
28
- FIRE = 0x10
29
-
30
- attr_reader :keyboard, :joystick1, :joystick2
31
- attr_accessor :device1, :device2, :port_a_source, :extra_rows
32
-
33
- def initialize(keyboard:, joystick1:, joystick2:)
34
- @keyboard = keyboard
35
- @joystick1 = joystick1
36
- @joystick2 = joystick2
37
- @device1 = nil
38
- @device2 = nil
39
- @port_a_source = nil
40
- @extra_rows = 0xff
41
- end
42
-
43
- def read_a(port_a, port_b) = scan(port_a, port_b).first & 0xff
44
-
45
- def read_b(port_a, port_b) = scan(port_a, port_b).last
46
-
47
- # Control port 1 pin 6 is both the port B fire line and the VIC's light
48
- # pen input, so joystick 1's button and a 1351's left button latch
49
- # $D013/$D014. The CIA samples this every cycle, so it skips the matrix and
50
- # asks only what the port's own devices drive.
51
- def port_b4_high? = port_bits(@joystick1, @device1).anybits?(FIRE)
52
-
53
- def pot_x = selected_devices.map(&:pot_x).min || 0xff
54
-
55
- def pot_y = selected_devices.map(&:pot_y).min || 0xff
56
-
57
- private
58
-
59
- def selected_devices
60
- lines = @port_a_source&.port_a_lines || 0x00
61
- devices = []
62
- devices << @device1 if @device1 && lines.anybits?(PORT1_POTS)
63
- devices << @device2 if @device2 && lines.anybits?(PORT2_POTS)
64
- devices
65
- end
66
-
67
- def scan(port_a, port_b)
68
- keyboard.scan((port_a & port_bits(@joystick2, @device2)) | (@extra_rows << 8),
69
- port_b & port_bits(@joystick1, @device1))
70
- end
71
-
72
- def port_bits(joystick, device)
73
- device ? joystick.port_bits & device.port_bits : joystick.port_bits
74
- end
75
- end
76
- end