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,232 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/c64/cartridge/bank"
4
+ require "badline/c64/cartridge/flash"
5
+ require "badline/c64/cartridge/standard"
6
+ require "badline/c64/cartridge/simons_basic"
7
+ require "badline/c64/cartridge/ocean"
8
+ require "badline/c64/cartridge/fun_play"
9
+ require "badline/c64/cartridge/super_games"
10
+ require "badline/c64/cartridge/epyx_fastload"
11
+ require "badline/c64/cartridge/westermann"
12
+ require "badline/c64/cartridge/rex_utility"
13
+ require "badline/c64/cartridge/game_system"
14
+ require "badline/c64/cartridge/dinamic"
15
+ require "badline/c64/cartridge/zaxxon"
16
+ require "badline/c64/cartridge/magic_desk"
17
+ require "badline/c64/cartridge/comal80"
18
+ require "badline/c64/cartridge/easy_flash"
19
+ require "badline/c64/cartridge/mach5"
20
+ require "badline/c64/cartridge/pagefox"
21
+ require "badline/c64/cartridge/rgcd"
22
+ require "badline/c64/cartridge/g_mod2"
23
+ require "badline/c64/cartridge/freezer"
24
+ require "badline/c64/cartridge/action_replay"
25
+ require "badline/c64/cartridge/atomic_power"
26
+ require "badline/c64/cartridge/final_cartridge3"
27
+ require "badline/c64/cartridge/retro_replay"
28
+ require "badline/c64/cartridge/kcs_power"
29
+ require "badline/c64/cartridge/geo_ram"
30
+
31
+ module Badline
32
+ class C64
33
+ class Cartridge
34
+ class UnsupportedTypeError < StandardError; end
35
+ ROMH_START = 0xa000
36
+ BANK_SIZE = 0x2000
37
+
38
+ HARDWARE_TYPES = {
39
+ 0 => Standard, 1 => ActionReplay, 2 => KCSPower, 3 => FinalCartridge3,
40
+ 4 => SimonsBasic, 5 => Ocean, 7 => FunPlay, 8 => SuperGames,
41
+ 9 => AtomicPower, 10 => EpyxFastload, 11 => Westermann,
42
+ 12 => RexUtility, 15 => GameSystem, 17 => Dinamic, 18 => Zaxxon,
43
+ 19 => MagicDesk, 21 => Comal80, 32 => EasyFlash, 36 => RetroReplay,
44
+ 51 => Mach5, 53 => Pagefox, 57 => RGCD, 60 => GMod2
45
+ }.freeze
46
+
47
+ # The EXROM and GAME line levels of each memory configuration. The lines
48
+ # are active low.
49
+ MODES = {
50
+ rom8k: [0, 1].freeze, rom16k: [0, 0].freeze,
51
+ ultimax: [1, 0].freeze, off: [1, 1].freeze
52
+ }.freeze
53
+
54
+ attr_reader :name, :exrom, :game, :roml, :romh
55
+
56
+ # A callable returning the current cycle, for mappers with timed state.
57
+ attr_writer :clock
58
+
59
+ class << self
60
+ # Options set the cartridge's jumpers, for the mappers that have them.
61
+ def from_file(path, **)
62
+ from_crt(Storage::CRTFile.new(path), **)
63
+ end
64
+
65
+ def from_crt(crt, **)
66
+ mapper_for(crt).new(crt, **)
67
+ end
68
+
69
+ def mapper_for(crt)
70
+ HARDWARE_TYPES.fetch(crt.hardware_type) do
71
+ raise UnsupportedTypeError,
72
+ "Unsupported cartridge hardware type #{crt.hardware_type}"
73
+ end
74
+ end
75
+ end
76
+
77
+ # Keeps the image it was built from, so a snapshot's machine can build
78
+ # the same cartridge before the snapshot's state goes into it.
79
+ def initialize(crt)
80
+ @crt = crt
81
+ @name = crt.name
82
+ @exrom = crt.exrom
83
+ @game = crt.game
84
+ @roml = @romh = nil
85
+ @banks = nil
86
+ @on_change = nil
87
+ @on_nmi_change = nil
88
+ @nmi = false
89
+ @open_bus = nil
90
+ @clock = nil
91
+ install_chips(crt.chips)
92
+ end
93
+
94
+ def on_change(&block)
95
+ @on_change = block
96
+ end
97
+
98
+ # Called with the level of the cartridge's pull on the NMI line when it
99
+ # changes. The line is wired-OR with CIA 2's.
100
+ def on_nmi_change(&block)
101
+ @on_nmi_change = block
102
+ end
103
+
104
+ def nmi?
105
+ @nmi
106
+ end
107
+
108
+ # The address bus hands over the C64's RAM, for mappers that write
109
+ # through to it, and the open bus, for I/O reads the cartridge doesn't
110
+ # drive.
111
+ def connect(ram:, open_bus:)
112
+ @ram = ram
113
+ @open_bus = open_bus
114
+ end
115
+
116
+ def ultimax?
117
+ @game.zero? && @exrom == 1
118
+ end
119
+
120
+ # Whether the first half of the cycle, where the VIC does most of its
121
+ # fetching, sees Ultimax mode. Some cartridges drive GAME and EXROM
122
+ # differently in the two halves; #ultimax? is the second, the CPU's.
123
+ def phi1_ultimax?
124
+ ultimax?
125
+ end
126
+
127
+ # The I/O pages ($de, $df) whose reads the mapper drives. Reads of the
128
+ # others are open bus.
129
+ def readable_io_pages
130
+ []
131
+ end
132
+
133
+ def poke(_addr, _value); end
134
+
135
+ # A window taking writes to $E000-$FFFF while reads there see the C64's
136
+ # memory, for a cartridge that asserts Ultimax on write cycles only.
137
+ def romh_writes; end
138
+
139
+ # A window at $A000-$BFFF in Ultimax mode, where the C64 maps nothing.
140
+ def ultimax_a000; end
141
+
142
+ # The RES line on the expansion port.
143
+ def reset; end
144
+
145
+ # Whether the cartridge has a freeze button.
146
+ def freezer? = false
147
+
148
+ # The freeze button, which cartridges without one ignore.
149
+ def press_button; end
150
+
151
+ def release_button; end
152
+
153
+ private
154
+
155
+ # The banks and views ROML and ROMH can point at, which a snapshot
156
+ # names them by: the mapper's banks, or nothing for a mapper whose
157
+ # windows stay where install_chips put them.
158
+ def windows
159
+ [*@banks, EMPTY_BANK] if @banks
160
+ end
161
+
162
+ def window_index(window, windows)
163
+ return -1 if window.nil?
164
+
165
+ windows.index { |candidate| candidate.equal?(window) } ||
166
+ raise(ArgumentError, "#{self.class.name}: a window that isn't among its banks")
167
+ end
168
+
169
+ def nmi=(level)
170
+ return if @nmi == level
171
+
172
+ @nmi = level
173
+ @on_nmi_change&.call(level)
174
+ end
175
+
176
+ def changed!
177
+ @on_change&.call
178
+ end
179
+
180
+ def mode=(mode)
181
+ @exrom, @game = MODES.fetch(mode)
182
+ end
183
+
184
+ # Sets the lines and tells the machine to map the cartridge again.
185
+ def select_mode(mode)
186
+ self.mode = mode
187
+ changed!
188
+ end
189
+
190
+ def open_bus(addr)
191
+ @open_bus ? @open_bus.peek(addr) : 0xff
192
+ end
193
+
194
+ def install_chips(_chips)
195
+ raise NotImplementedError
196
+ end
197
+
198
+ def rom_bank(data)
199
+ Bank.new(data)
200
+ end
201
+
202
+ # A bank the image leaves out reads as erased ROM.
203
+ def bank(banks, number)
204
+ banks[number] || EMPTY_BANK
205
+ end
206
+
207
+ # The bank register bits a ROM decodes. The ROM holds the highest bank
208
+ # in the image, and has address lines for the power of two that covers
209
+ # it; the register bits above those lines are ignored.
210
+ def bank_mask(banks)
211
+ (1 << (banks.length - 1).bit_length) - 1
212
+ end
213
+
214
+ # Sorts the CHIP packets into ROML and ROMH banks by load address. A 16K
215
+ # chip at $8000 spans both.
216
+ def banks_from(chips)
217
+ roml = []
218
+ romh = []
219
+ chips.each do |chip|
220
+ if chip.address >= ROMH_START
221
+ romh[chip.bank] = rom_bank(chip.data)
222
+ else
223
+ roml[chip.bank] = rom_bank(chip.data[0, BANK_SIZE])
224
+ romh[chip.bank] = rom_bank(chip.data[BANK_SIZE, BANK_SIZE]) if chip.data.length > BANK_SIZE
225
+ end
226
+ end
227
+ [roml, romh]
228
+ end
229
+ end
230
+ end
231
+ end
232
+ require "badline/c64/cartridge/keyed_state"
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ # Colour RAM is four bits wide. A CPU read takes the upper nibble off the
6
+ # open data bus, which still holds the byte the VIC fetched in phi1.
7
+ class ColorMemory < Memory
8
+ def initialize(vic, start: 0xd800, length: 2**10)
9
+ super(start:, length:)
10
+ @vic = vic
11
+ end
12
+
13
+ def peek(addr)
14
+ (@vic.phi1_data & 0xf0) | @storage[offset_of(addr)]
15
+ end
16
+
17
+ def poke(addr, value)
18
+ super(addr, value & 0x0f)
19
+ end
20
+
21
+ # The four bits the cell stores, as the VIC's c-access sees them.
22
+ def nibble(addr)
23
+ @storage[offset_of(addr)]
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class Computer
4
+ class C64
5
5
  # What the C128 does as the C64 does: the NMI line, a PRG put into RAM
6
- # and the region's timing. Computer and C128 each include it.
6
+ # and the region's timing. C64 and C128 each include it.
7
7
  module Common
8
8
  # The clock, the raster and the crop of the machine's region, a pixel
9
9
  # to a window pixel.
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class Computer
4
+ class C64
5
5
  # The disk device 8 serves through the LOAD, SAVE and serial traps, and
6
- # CHROUT capture, on the KERNAL the machine runs. Computer, Vic20 and
6
+ # CHROUT capture, on the KERNAL the machine runs. C64, Vic20 and
7
7
  # C128 each include it and answer two private methods: #trap_layout,
8
8
  # the KernalTrap::Layout of that KERNAL, and #trap_bus, the bus the
9
9
  # traps read and write through.
@@ -13,9 +13,9 @@ module Badline
13
13
  # drive reset clears, and its status. The traps go on the KERNAL the
14
14
  # machine runs (#trap_layout).
15
15
  def mount(storage)
16
- return @drive.insert(storage) if @drive
16
+ return @dos.insert(storage) if @dos
17
17
 
18
- @drive = KernalTrap::Drive.new(storage)
18
+ @dos = KernalTrap::DOS.new(storage)
19
19
  install_kernal_traps(trap_layout)
20
20
  end
21
21
 
@@ -23,35 +23,60 @@ module Badline
23
23
  # serial traps, so the KERNAL's routines go out over the serial bus.
24
24
  # Mounting again starts a new drive, with its RAM cleared.
25
25
  def unmount
26
- return unless @drive
26
+ return unless @dos
27
27
 
28
28
  remove_kernal_traps
29
- @drive = nil
29
+ @dos = nil
30
30
  end
31
31
 
32
32
  # Whether device 8 serves a disk or directory through the traps.
33
- def mounted? = !@drive.nil?
33
+ def mounted? = !@dos.nil?
34
34
 
35
35
  # The path of the disk or directory device 8 serves through the
36
36
  # traps, or an empty one.
37
- def mounted_path = @drive.nil? ? "" : @drive.path
37
+ def mounted_path = @dos.nil? ? "" : @dos.path
38
38
 
39
- # Records what the KERNAL prints through CHROUT (ChroutTrap).
39
+ # Records what the KERNAL prints through CHROUT (KernalTrap::Chrout).
40
40
  def capture_output
41
- @capture_output ||= ChroutTrap.new(cpu:, bus: trap_bus, layout: trap_layout).tap do |trap|
42
- cpu.install_trap(ChroutTrap::ADDRESS) { trap.call }
41
+ @capture_output ||= KernalTrap::Chrout.new(cpu:, bus: trap_bus, layout: trap_layout).tap do |trap|
42
+ cpu.install_trap(KernalTrap::Chrout::ADDRESS) { trap.call }
43
43
  end
44
44
  end
45
45
 
46
+ # Device 8 through the KERNAL traps in a keyed snapshot module
47
+ # (BL-TRAPDOS): the storage under storage.*, the DOS, the serial
48
+ # trap under serial.* and the SAVE trap under save.*. Nothing mounted
49
+ # writes nothing.
50
+ def save_trap_dos_fields(out)
51
+ dos = @dos
52
+ return unless dos
53
+
54
+ Snapshot::StorageSetup.write_fields(dos.storage, out)
55
+ dos.save_fields(out)
56
+ @serial_trap&.save_fields(out, "serial.")
57
+ @save_trap&.save_fields(out, "save.")
58
+ end
59
+
60
+ # `detached` mounts a disk image write-protected and no directory.
61
+ def load_trap_dos_fields(input, detached: false)
62
+ unmount
63
+ return if input.missing?
64
+
65
+ mount(Snapshot::StorageSetup.read_fields(input, detached:))
66
+ @dos&.load_fields(input)
67
+ @serial_trap&.load_fields(input, "serial.")
68
+ @save_trap&.load_fields(input, "save.")
69
+ end
70
+
46
71
  private
47
72
 
48
73
  def install_kernal_traps(layout)
49
74
  @trap_layout = layout
50
- load_trap = KernalTrap::Load.new(cpu:, bus: trap_bus, layout:, drive: @drive)
75
+ load_trap = KernalTrap::Load.new(cpu:, bus: trap_bus, layout:, dos: @dos)
51
76
  cpu.install_trap(layout.load) { load_trap.call }
52
- @serial_trap = KernalTrap::Serial.new(cpu:, bus: trap_bus, layout:, drive: @drive,
77
+ @serial_trap = KernalTrap::Serial.new(cpu:, bus: trap_bus, layout:, dos: @dos,
53
78
  device: serial_trap_device).install
54
- save_trap = @save_trap = KernalTrap::Save.new(cpu:, bus: trap_bus, layout:, drive: @drive)
79
+ save_trap = @save_trap = KernalTrap::Save.new(cpu:, bus: trap_bus, layout:, dos: @dos)
55
80
  cpu.install_trap(layout.save) { save_trap.call }
56
81
  end
57
82
 
@@ -62,28 +87,6 @@ module Badline
62
87
  @serial_trap = nil
63
88
  @save_trap = nil
64
89
  end
65
-
66
- # The disk device 8 serves through the traps, with the traps' own
67
- # state: open channels, the drive's status and RAM, a SAVE under way.
68
- def save_trap_drive(out)
69
- out.boolean(!@drive.nil?)
70
- return unless @drive
71
-
72
- @drive.save_state(out)
73
- @serial_trap.save_state(out)
74
- @save_trap.save_state(out)
75
- end
76
-
77
- def load_trap_drive(input)
78
- return unmount unless input.boolean?
79
-
80
- storage = Storage.reopen(input)
81
- unmount
82
- mount(storage)
83
- @drive.load_state(input)
84
- @serial_trap.load_state(input)
85
- @save_trap.load_state(input)
86
- end
87
90
  end
88
91
  end
89
92
  end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ # The whole machine as keyed snapshot modules (Snapshot::Keyed), in the
6
+ # order a load applies them: BL-MACHINE with the setup, the memories,
7
+ # the cartridge, the CPU with its port, the chips, an REU, the
8
+ # datasette, device 8 through the traps and the true drives. A load
9
+ # reads the CPU's port before the chips, so the banks are mapped as the
10
+ # chips load, and the CPU's own fields after them. What each unit works
11
+ # out again from its fields comes last, once every unit is loaded.
12
+ module KeyedModules
13
+ def save_modules
14
+ bus = address_bus
15
+ sections = [Snapshot::Keyed.section("BL-MACHINE") { |out| save_machine_fields(out) },
16
+ Snapshot::Keyed.section("BL-RAM") { |out| bus.ram.save_fields(out, "ram") }]
17
+ expansion = bus.ram_expansion
18
+ sections << Snapshot::Keyed.section("BL-RAMEXP") { |out| expansion.save_fields(out) } if expansion.type
19
+ sections << Snapshot::Keyed.section("BL-COLORRAM") { |out| bus.color_ram.save_fields(out, "ram") }
20
+ cartridge = bus.cartridge
21
+ sections << Snapshot::Keyed.section("BL-CART") { |out| cartridge.save_fields(out) } if cartridge
22
+ save_chip_modules(sections, bus)
23
+ reu = @reu
24
+ sections << Snapshot::Keyed.section("BL-REU") { |out| reu.save_fields(out) } if reu
25
+ sections << Snapshot::Keyed.section("BL-TAPE") { |out| bus.datasette.save_fields(out) }
26
+ sections << Snapshot::Keyed.section("BL-TRAPDOS") { |out| save_trap_dos_fields(out) } if mounted?
27
+ save_drive_modules(sections)
28
+ end
29
+
30
+ # Raises Snapshot::FormatError for the modules of a machine built
31
+ # another way.
32
+ def load_modules(modules)
33
+ machine = modules.machine
34
+ check_snapshot_setup(Snapshot::C64Setup.read_fields(machine))
35
+ load_machine_fields(machine)
36
+ bus = address_bus
37
+ bus.ram.load_fields(modules.required("BL-RAM"), "ram")
38
+ bus.ram_expansion.load_fields(modules.required("BL-RAMEXP")) if bus.ram_expansion.type
39
+ bus.color_ram.load_fields(modules.required("BL-COLORRAM"), "ram")
40
+ load_cartridge_module(modules.optional("BL-CART"))
41
+ cpu = modules.required("BL-CPU")
42
+ bus.load_port_fields(cpu)
43
+ bus.restored!
44
+ load_chip_modules(modules, cpu)
45
+ bus.datasette.load_fields(modules.required("BL-TAPE"))
46
+ load_trap_dos_module(modules)
47
+ load_drive_modules(modules)
48
+ modules_restored!
49
+ self
50
+ end
51
+
52
+ private
53
+
54
+ def save_chip_modules(sections, bus)
55
+ sections << Snapshot::Keyed.section("BL-CPU") do |out|
56
+ @cpu.save_fields(out)
57
+ bus.save_port_fields(out)
58
+ end
59
+ sections << Snapshot::Keyed.section("BL-VIC") { |out| @vic.save_fields(out) }
60
+ sections << Snapshot::Keyed.section("BL-CIA1") { |out| @cia1.save_fields(out) }
61
+ sections << Snapshot::Keyed.section("BL-CIA2") { |out| @cia2.save_fields(out) }
62
+ sections << Snapshot::Keyed.section("BL-SID") { |out| @sid.save_fields(out) }
63
+ end
64
+
65
+ def load_chip_modules(modules, cpu)
66
+ @vic.load_fields(modules.required("BL-VIC"))
67
+ @cia1.load_fields(modules.required("BL-CIA1"))
68
+ @cia2.load_fields(modules.required("BL-CIA2"))
69
+ @sid.load_fields(modules.required("BL-SID"))
70
+ @reu&.load_fields(modules.required("BL-REU"))
71
+ @cpu.load_fields(cpu)
72
+ end
73
+
74
+ # The cartridge comes back built afresh from the CRT image the module
75
+ # holds, before its state goes in. No module means no cartridge.
76
+ def load_cartridge_module(input)
77
+ if input
78
+ cartridge = Cartridge.from_fields(input)
79
+ connect_cartridge(cartridge)
80
+ cartridge.load_fields(input)
81
+ elsif address_bus.cartridge
82
+ address_bus.detach_cartridge
83
+ end
84
+ end
85
+
86
+ def load_trap_dos_module(modules)
87
+ input = modules.optional("BL-TRAPDOS")
88
+ input ? load_trap_dos_fields(input, detached: modules.detached?) : unmount
89
+ end
90
+
91
+ def modules_restored!
92
+ @cpu.restored!
93
+ @vic.restored!
94
+ @cia1.restored!
95
+ @cia2.restored!
96
+ @sid.restored!
97
+ @reu&.restored!
98
+ machine_restored!
99
+ end
100
+
101
+ def check_snapshot_setup(setup)
102
+ ours = Snapshot::C64Setup.of(address_bus)
103
+ return if setup == ours
104
+
105
+ raise Snapshot::FormatError, "the snapshot is of a machine with #{setup}, not #{ours}"
106
+ end
107
+ end
108
+
109
+ include KeyedModules
110
+ end
111
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ # The machine's own fields in a keyed snapshot module (Snapshot::Keyed,
6
+ # BL-MACHINE): the family, its setup by name, the cycle count, the NMI
7
+ # glue, the freezer's write count and the REU's hold on the bus, and the
8
+ # host's typing still to feed and on_init handlers still to run under
9
+ # host.*. The badline version that wrote it is written for reports and
10
+ # never read.
11
+ module KeyedState
12
+ # How many more on_init handlers the machine a snapshot was taken of had
13
+ # yet to run than this one has: they are the host's blocks, which a
14
+ # snapshot can't hold. Nil until the machine is restored.
15
+ attr_reader :init_handlers_lost
16
+
17
+ # Sets the machine's cycle count, for a snapshot from VICE, which
18
+ # counts from its own clock.
19
+ def resume_at(cycles)
20
+ @cycles = cycles
21
+ end
22
+
23
+ # Whether a snapshot saves now (Machine::Settling): the CPU between
24
+ # instructions or jammed, and no REU transfer under way.
25
+ def settled_for_snapshot? = (@cpu.boundary? || @cpu.jammed?) && !reu&.dma?
26
+
27
+ # The SID's deferred cycles and writes, run up to this cycle, and the
28
+ # VIC's sprite collisions latched up to the beam.
29
+ def settle_chips_for_snapshot
30
+ sid.catch_up!
31
+ @vic.fold_collisions!
32
+ end
33
+
34
+ def save_machine_fields(out)
35
+ out.text("family", "c64").text("written_by", VERSION)
36
+ Snapshot::C64Setup.of(address_bus).write_fields(out)
37
+ out.int("cycles", @cycles).bool("nmi_asserted", @nmi_asserted).bool("cartridge_nmi", @cartridge_nmi)
38
+ out.bool("restore_pulse", @restore_pulse).bool("freezing", @freezing).int("freeze_writes", @freeze_writes)
39
+ out.bool("dma", @dma)
40
+ pending = @pending_keys
41
+ out.ints("host.pending_keys", pending) if pending
42
+ out.int("host.init_pending", booting? ? @init_handlers.length : 0)
43
+ end
44
+
45
+ def load_machine_fields(input)
46
+ @cycles = input.int("cycles", @cycles)
47
+ @nmi_asserted = input.bool("nmi_asserted", @nmi_asserted)
48
+ @cartridge_nmi = input.bool("cartridge_nmi", @cartridge_nmi)
49
+ @restore_pulse = input.bool("restore_pulse", @restore_pulse)
50
+ @freezing = input.bool("freezing", @freezing)
51
+ @freeze_writes = input.int("freeze_writes", @freeze_writes)
52
+ @dma = input.bool("dma", @dma)
53
+ pending = input.ints("host.pending_keys", [])
54
+ @pending_keys = pending.empty? ? nil : pending.dup
55
+ @init_handlers_lost = [input.int("host.init_pending", 0) - @init_handlers.length, 0].max
56
+ end
57
+
58
+ # The REU's IRQ line and the serial bus's lines from CIA 2, once the
59
+ # chips are loaded.
60
+ def machine_restored!
61
+ @reu_irq = @reu.nil? ? false : @reu.irq?
62
+ push_serial_lines
63
+ end
64
+ end
65
+
66
+ include KeyedState
67
+ end
68
+ end