badline 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (516) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/CLAUDE.md +59 -31
  4. data/README.md +1 -1
  5. data/doc/library.md +9 -9
  6. data/doc/pinned-behaviour.md +105 -105
  7. data/doc/snapshots.md +1 -4
  8. data/lib/badline/audio/bare_player.rb +4 -4
  9. data/lib/badline/audio/cli.rb +6 -6
  10. data/lib/badline/audio/jukebox.rb +2 -2
  11. data/lib/badline/audio/machine_player.rb +2 -2
  12. data/lib/badline/{media → audio}/queue.rb +1 -1
  13. data/lib/badline/audio/queued_tune.rb +6 -6
  14. data/lib/badline/audio/renderer.rb +5 -5
  15. data/lib/badline/audio/stereo.rb +1 -1
  16. data/lib/badline/c128/{bus_state.rb → bus/saved_state.rb} +6 -6
  17. data/lib/badline/c128/bus.rb +30 -51
  18. data/lib/badline/c128/color_lines.rb +2 -2
  19. data/lib/badline/c128/cpu.rb +1 -1
  20. data/lib/badline/c128/drives.rb +10 -11
  21. data/lib/badline/c128/fast_serial.rb +5 -5
  22. data/lib/badline/c128/mmu_pages.rb +1 -1
  23. data/lib/badline/c128/modes.rb +2 -2
  24. data/lib/badline/c128/saved_state.rb +21 -47
  25. data/lib/badline/c128/z80.rb +2 -2
  26. data/lib/badline/c128.rb +18 -72
  27. data/lib/badline/{computer → c64}/attachments.rb +16 -47
  28. data/lib/badline/c64/banked_ram/banking.rb +32 -0
  29. data/lib/badline/c64/banked_ram/plus256k.rb +56 -0
  30. data/lib/badline/c64/banked_ram/plus60k.rb +45 -0
  31. data/lib/badline/c64/banked_ram/unexpanded.rb +30 -0
  32. data/lib/badline/c64/banked_ram.rb +23 -0
  33. data/lib/badline/c64/bus/extra_sids.rb +32 -0
  34. data/lib/badline/c64/bus/fittings.rb +40 -0
  35. data/lib/badline/c64/bus/pla.rb +149 -0
  36. data/lib/badline/c64/bus/roms.rb +41 -0
  37. data/lib/badline/c64/bus/saved_state.rb +68 -0
  38. data/lib/badline/c64/bus/sid_slots.rb +44 -0
  39. data/lib/badline/c64/bus.rb +218 -0
  40. data/lib/badline/c64/cartridge/action_replay.rb +128 -0
  41. data/lib/badline/c64/cartridge/atomic_power.rb +26 -0
  42. data/lib/badline/c64/cartridge/bank.rb +83 -0
  43. data/lib/badline/c64/cartridge/comal80.rb +52 -0
  44. data/lib/badline/c64/cartridge/dinamic.rb +36 -0
  45. data/lib/badline/c64/cartridge/easy_flash.rb +147 -0
  46. data/lib/badline/c64/cartridge/epyx_fastload.rb +81 -0
  47. data/lib/badline/c64/cartridge/final_cartridge3.rb +91 -0
  48. data/lib/badline/c64/cartridge/flash/saved_state.rb +40 -0
  49. data/lib/badline/c64/cartridge/flash.rb +279 -0
  50. data/lib/badline/c64/cartridge/freezer.rb +35 -0
  51. data/lib/badline/c64/cartridge/fun_play.rb +40 -0
  52. data/lib/badline/c64/cartridge/g_mod2.rb +76 -0
  53. data/lib/badline/c64/cartridge/game_system.rb +42 -0
  54. data/lib/badline/c64/cartridge/geo_ram.rb +81 -0
  55. data/lib/badline/c64/cartridge/kcs_power.rb +77 -0
  56. data/lib/badline/c64/cartridge/mach5.rb +34 -0
  57. data/lib/badline/c64/cartridge/magic_desk.rb +32 -0
  58. data/lib/badline/c64/cartridge/ocean.rb +37 -0
  59. data/lib/badline/c64/cartridge/pagefox.rb +70 -0
  60. data/lib/badline/c64/cartridge/retro_replay/saved_state.rb +47 -0
  61. data/lib/badline/c64/cartridge/retro_replay.rb +286 -0
  62. data/lib/badline/c64/cartridge/rex_utility.rb +31 -0
  63. data/lib/badline/c64/cartridge/rgcd.rb +60 -0
  64. data/lib/badline/c64/cartridge/saved_state.rb +63 -0
  65. data/lib/badline/c64/cartridge/simons_basic.rb +37 -0
  66. data/lib/badline/c64/cartridge/standard.rb +17 -0
  67. data/lib/badline/c64/cartridge/super_games.rb +50 -0
  68. data/lib/badline/c64/cartridge/westermann.rb +32 -0
  69. data/lib/badline/c64/cartridge/zaxxon.rb +68 -0
  70. data/lib/badline/c64/cartridge.rb +258 -0
  71. data/lib/badline/c64/color_memory.rb +27 -0
  72. data/lib/badline/c64/common.rb +34 -0
  73. data/lib/badline/c64/kernal_traps.rb +89 -0
  74. data/lib/badline/c64/reu/dma/saved_state.rb +52 -0
  75. data/lib/badline/c64/reu/dma.rb +275 -0
  76. data/lib/badline/c64/reu/ram.rb +109 -0
  77. data/lib/badline/c64/reu/saved_state.rb +55 -0
  78. data/lib/badline/c64/reu/trigger.rb +34 -0
  79. data/lib/badline/c64/reu.rb +291 -0
  80. data/lib/badline/{computer → c64}/saved_state.rb +13 -18
  81. data/lib/badline/{computer → c64}/true_drives.rb +20 -31
  82. data/lib/badline/{computer.rb → c64.rb} +22 -80
  83. data/lib/badline/chips/cia/fast_forward.rb +62 -0
  84. data/lib/badline/chips/cia/interrupt_register.rb +145 -0
  85. data/lib/badline/chips/cia/saved_state.rb +49 -0
  86. data/lib/badline/chips/cia/serial/saved_state.rb +45 -0
  87. data/lib/badline/chips/cia/serial.rb +250 -0
  88. data/lib/badline/chips/cia/time_of_day.rb +232 -0
  89. data/lib/badline/chips/cia/timer.rb +208 -0
  90. data/lib/badline/chips/cia.rb +281 -0
  91. data/lib/badline/chips/cpu/addressing.rb +133 -0
  92. data/lib/badline/chips/cpu/boundary.rb +56 -0
  93. data/lib/badline/chips/cpu/core.rb +167 -0
  94. data/lib/badline/chips/cpu/instruction.rb +338 -0
  95. data/lib/badline/chips/cpu/instruction_set/arithmetic.rb +118 -0
  96. data/lib/badline/chips/cpu/instruction_set/bitwise.rb +130 -0
  97. data/lib/badline/chips/cpu/instruction_set/branch.rb +83 -0
  98. data/lib/badline/chips/cpu/instruction_set/flag.rb +67 -0
  99. data/lib/badline/chips/cpu/instruction_set/illegal.rb +274 -0
  100. data/lib/badline/chips/cpu/instruction_set/inc_dec.rb +73 -0
  101. data/lib/badline/chips/cpu/instruction_set/stack.rb +56 -0
  102. data/lib/badline/chips/cpu/instruction_set/transfer.rb +141 -0
  103. data/lib/badline/chips/cpu/instruction_set.rb +59 -0
  104. data/lib/badline/chips/cpu/interrupts.rb +108 -0
  105. data/lib/badline/chips/cpu/microcode.rb +179 -0
  106. data/lib/badline/chips/cpu/operations.rb +90 -0
  107. data/lib/badline/chips/cpu/port.rb +116 -0
  108. data/lib/badline/chips/cpu/saved_state.rb +117 -0
  109. data/lib/badline/chips/cpu/stack_operations.rb +84 -0
  110. data/lib/badline/chips/cpu/traps.rb +23 -0
  111. data/lib/badline/chips/cpu.rb +12 -0
  112. data/lib/badline/chips/sid/catch_up.rb +122 -0
  113. data/lib/badline/chips/sid/decimator.rb +66 -0
  114. data/lib/badline/chips/sid/envelope/saved_state.rb +70 -0
  115. data/lib/badline/chips/sid/envelope.rb +241 -0
  116. data/lib/badline/chips/sid/filter/saved_state.rb +42 -0
  117. data/lib/badline/chips/sid/filter.rb +241 -0
  118. data/lib/badline/chips/sid/saved_state.rb +52 -0
  119. data/lib/badline/chips/sid/voice.rb +79 -0
  120. data/lib/badline/chips/sid/waveform/combined.rb +128 -0
  121. data/lib/badline/chips/sid/waveform/fast_forward.rb +107 -0
  122. data/lib/badline/chips/sid/waveform/noise_writeback.rb +124 -0
  123. data/lib/badline/chips/sid/waveform/saved_state.rb +68 -0
  124. data/lib/badline/chips/sid/waveform.rb +307 -0
  125. data/lib/badline/chips/sid.rb +265 -0
  126. data/lib/badline/{c128 → chips}/vdc/memory.rb +1 -1
  127. data/lib/badline/{c128 → chips}/vdc/painter.rb +1 -1
  128. data/lib/badline/{c128 → chips}/vdc/raster.rb +1 -1
  129. data/lib/badline/chips/vdc/saved_state.rb +36 -0
  130. data/lib/badline/{c128 → chips}/vdc/window.rb +1 -1
  131. data/lib/badline/{c128 → chips}/vdc.rb +7 -31
  132. data/lib/badline/chips/via/control_lines.rb +124 -0
  133. data/lib/badline/chips/via/fast_forward.rb +55 -0
  134. data/lib/badline/chips/via/interrupt_register.rb +69 -0
  135. data/lib/badline/chips/via/saved_state.rb +44 -0
  136. data/lib/badline/chips/via/shift_register.rb +182 -0
  137. data/lib/badline/chips/via/timer1.rb +133 -0
  138. data/lib/badline/chips/via/timer2.rb +135 -0
  139. data/lib/badline/chips/via.rb +268 -0
  140. data/lib/badline/chips/vic/bank.rb +135 -0
  141. data/lib/badline/chips/vic/border_mask.rb +88 -0
  142. data/lib/badline/chips/vic/collisions.rb +117 -0
  143. data/lib/badline/chips/vic/color_patches.rb +49 -0
  144. data/lib/badline/chips/vic/display_state.rb +187 -0
  145. data/lib/badline/chips/vic/graphics_mode.rb +166 -0
  146. data/lib/badline/chips/vic/graphics_shifter/saved_state.rb +40 -0
  147. data/lib/badline/chips/vic/graphics_shifter.rb +187 -0
  148. data/lib/badline/chips/vic/register_log.rb +83 -0
  149. data/lib/badline/chips/vic/registers.rb +197 -0
  150. data/lib/badline/chips/vic/saved_state.rb +82 -0
  151. data/lib/badline/chips/vic/sequencer/saved_state.rb +91 -0
  152. data/lib/badline/chips/vic/sequencer.rb +277 -0
  153. data/lib/badline/chips/vic/sequencer_output.rb +118 -0
  154. data/lib/badline/chips/vic/sprite/internal_bus.rb +70 -0
  155. data/lib/badline/chips/vic/sprite/saved_state.rb +66 -0
  156. data/lib/badline/chips/vic/sprite/shifter.rb +148 -0
  157. data/lib/badline/chips/vic/sprite/timing.rb +58 -0
  158. data/lib/badline/chips/vic/sprite.rb +339 -0
  159. data/lib/badline/chips/vic/sprites/saved_state.rb +59 -0
  160. data/lib/badline/chips/vic/sprites.rb +284 -0
  161. data/lib/badline/chips/vic.rb +783 -0
  162. data/lib/badline/chips/vic_i/painter/saved_state.rb +40 -0
  163. data/lib/badline/{vic20/vic → chips/vic_i}/painter.rb +6 -30
  164. data/lib/badline/{vic20/vic → chips/vic_i}/saved_state.rb +2 -2
  165. data/lib/badline/chips/vic_i/sound/output.rb +85 -0
  166. data/lib/badline/chips/vic_i/sound.rb +235 -0
  167. data/lib/badline/{vic20/vic → chips/vic_i}/text_window.rb +2 -2
  168. data/lib/badline/{vic20/vic.rb → chips/vic_i.rb} +5 -5
  169. data/lib/badline/chips/z80/arithmetic.rb +119 -0
  170. data/lib/badline/chips/z80/bit_page.rb +57 -0
  171. data/lib/badline/chips/z80/block_io.rb +60 -0
  172. data/lib/badline/chips/z80/block_transfers.rb +61 -0
  173. data/lib/badline/chips/z80/bus_cycles.rb +113 -0
  174. data/lib/badline/chips/z80/core.rb +115 -0
  175. data/lib/badline/chips/z80/exchanges.rb +52 -0
  176. data/lib/badline/chips/z80/extended_page.rb +91 -0
  177. data/lib/badline/chips/z80/flags.rb +39 -0
  178. data/lib/badline/chips/z80/interrupt_acceptance.rb +48 -0
  179. data/lib/badline/chips/z80/jumps.rb +84 -0
  180. data/lib/badline/chips/z80/loads.rb +100 -0
  181. data/lib/badline/chips/z80/main_page.rb +136 -0
  182. data/lib/badline/chips/z80/registers.rb +122 -0
  183. data/lib/badline/chips/z80/saved_state.rb +71 -0
  184. data/lib/badline/chips/z80/shifts.rb +66 -0
  185. data/lib/badline/chips/z80.rb +13 -0
  186. data/lib/badline/core.rb +27 -29
  187. data/lib/badline/drives/datasette/saved_state.rb +37 -0
  188. data/lib/badline/drives/datasette.rb +140 -0
  189. data/lib/badline/drives/engine/core.rb +149 -0
  190. data/lib/badline/drives/engine/fast_serial.rb +75 -0
  191. data/lib/badline/drives/engine/idle.rb +127 -0
  192. data/lib/badline/drives/engine/idle_cpu.rb +30 -0
  193. data/lib/badline/drives/engine/orbit.rb +81 -0
  194. data/lib/badline/drives/engine/serial_lines.rb +75 -0
  195. data/lib/badline/drives/engine/sleep.rb +114 -0
  196. data/lib/badline/drives/engine/vias.rb +86 -0
  197. data/lib/badline/drives/engine/watch.rb +152 -0
  198. data/lib/badline/drives/engine.rb +11 -0
  199. data/lib/badline/drives/model1541/bus.rb +88 -0
  200. data/lib/badline/drives/model1541/byte_ready.rb +50 -0
  201. data/lib/badline/drives/model1541/cpu.rb +13 -0
  202. data/lib/badline/drives/model1541/disk/saved_state.rb +88 -0
  203. data/lib/badline/drives/model1541/disk.rb +317 -0
  204. data/lib/badline/drives/model1541/disk_via.rb +38 -0
  205. data/lib/badline/drives/model1541/gcr.rb +59 -0
  206. data/lib/badline/drives/model1541/mechanism/saved_state.rb +72 -0
  207. data/lib/badline/drives/model1541/mechanism.rb +315 -0
  208. data/lib/badline/drives/model1541/rotation.rb +123 -0
  209. data/lib/badline/drives/model1541/saved_state.rb +44 -0
  210. data/lib/badline/drives/model1541/sector_reader.rb +78 -0
  211. data/lib/badline/drives/model1541/serial_port.rb +20 -0
  212. data/lib/badline/drives/model1541/track.rb +100 -0
  213. data/lib/badline/drives/model1541.rb +81 -0
  214. data/lib/badline/drives/model1571/bus.rb +113 -0
  215. data/lib/badline/drives/model1571/cpu.rb +13 -0
  216. data/lib/badline/drives/model1571/saved_state.rb +47 -0
  217. data/lib/badline/drives/model1571/serial_port.rb +39 -0
  218. data/lib/badline/drives/model1571/serial_via.rb +27 -0
  219. data/lib/badline/drives/model1571/wd1770.rb +122 -0
  220. data/lib/badline/drives/model1571.rb +142 -0
  221. data/lib/badline/drives/model1581/bus.rb +139 -0
  222. data/lib/badline/drives/model1581/cpu.rb +13 -0
  223. data/lib/badline/drives/model1581/disk/saved_state.rb +89 -0
  224. data/lib/badline/drives/model1581/disk.rb +137 -0
  225. data/lib/badline/drives/model1581/mechanism.rb +119 -0
  226. data/lib/badline/drives/model1581/saved_state.rb +42 -0
  227. data/lib/badline/drives/model1581/serial_port.rb +54 -0
  228. data/lib/badline/drives/model1581/slot.rb +79 -0
  229. data/lib/badline/drives/model1581/track.rb +102 -0
  230. data/lib/badline/drives/model1581/track_bytes.rb +77 -0
  231. data/lib/badline/drives/model1581/wd1772/registers.rb +91 -0
  232. data/lib/badline/drives/model1581/wd1772/saved_state.rb +68 -0
  233. data/lib/badline/drives/model1581/wd1772/sector_writes.rb +75 -0
  234. data/lib/badline/drives/model1581/wd1772/sectors.rb +152 -0
  235. data/lib/badline/drives/model1581/wd1772/stepping.rb +111 -0
  236. data/lib/badline/drives/model1581/wd1772/tracks.rb +127 -0
  237. data/lib/badline/drives/model1581/wd1772/turn.rb +75 -0
  238. data/lib/badline/drives/model1581/wd1772.rb +218 -0
  239. data/lib/badline/drives/model1581.rb +206 -0
  240. data/lib/badline/drives/serial_bus.rb +161 -0
  241. data/lib/badline/frontend/boot.rb +10 -61
  242. data/lib/badline/frontend/machine_window.rb +3 -1
  243. data/lib/badline/frontend/player/filter_view.rb +1 -1
  244. data/lib/badline/frontend/player/player_controller.rb +2 -2
  245. data/lib/badline/frontend/player/player_screen.rb +1 -0
  246. data/lib/badline/frontend/player/theme.rb +7 -7
  247. data/lib/badline/frontend/timeline.rb +3 -3
  248. data/lib/badline/input/control_ports.rb +78 -0
  249. data/lib/badline/input/joystick.rb +27 -0
  250. data/lib/badline/input/keyboard.rb +114 -0
  251. data/lib/badline/input.rb +3 -0
  252. data/lib/badline/kernal_trap/{drive → dos}/block_commands.rb +1 -1
  253. data/lib/badline/kernal_trap/dos/channel.rb +183 -0
  254. data/lib/badline/kernal_trap/{drive → dos}/channels.rb +1 -1
  255. data/lib/badline/kernal_trap/{drive → dos}/memory.rb +1 -1
  256. data/lib/badline/kernal_trap/{drive → dos}/parameters.rb +1 -1
  257. data/lib/badline/kernal_trap/{drive → dos}/status.rb +1 -1
  258. data/lib/badline/kernal_trap/{drive → dos}/write_file.rb +1 -1
  259. data/lib/badline/kernal_trap/{drive → dos}/writes.rb +1 -1
  260. data/lib/badline/kernal_trap/{drive.rb → dos.rb} +11 -10
  261. data/lib/badline/kernal_trap/{file.rb → file_routine.rb} +1 -1
  262. data/lib/badline/kernal_trap/load.rb +6 -6
  263. data/lib/badline/kernal_trap/save.rb +5 -5
  264. data/lib/badline/kernal_trap/serial.rb +7 -7
  265. data/lib/badline/kernal_trap.rb +2 -3
  266. data/lib/badline/machine/clocking.rb +50 -0
  267. data/lib/badline/machine.rb +63 -7
  268. data/lib/badline/media/boot_disk.rb +2 -2
  269. data/lib/badline/media/disk_list.rb +3 -3
  270. data/lib/badline/media/disk_set.rb +1 -1
  271. data/lib/badline/media/extensions.rb +33 -0
  272. data/lib/badline/media/program.rb +28 -0
  273. data/lib/badline/media/true_drive.rb +4 -3
  274. data/lib/badline/media/tune.rb +35 -0
  275. data/lib/badline/media/vic20_cartridge.rb +1 -7
  276. data/lib/badline/media/vic20_media.rb +38 -80
  277. data/lib/badline/media.rb +84 -81
  278. data/lib/badline/model.rb +1 -1
  279. data/lib/badline/options/event.rb +3 -1
  280. data/lib/badline/roms/README +6 -6
  281. data/lib/badline/sdl.rb +1 -0
  282. data/lib/badline/{storage/sid_file.rb → sid_tune/file.rb} +3 -3
  283. data/lib/badline/{storage → sid_tune}/hvsc.rb +7 -7
  284. data/lib/badline/{storage → sid_tune}/song_lengths.rb +2 -2
  285. data/lib/badline/{storage → sid_tune}/stil/credit.rb +1 -1
  286. data/lib/badline/{storage → sid_tune}/stil.rb +3 -3
  287. data/lib/badline/sid_tune.rb +6 -0
  288. data/lib/badline/snapshot/c128_setup.rb +43 -0
  289. data/lib/badline/snapshot/c64_setup.rb +79 -0
  290. data/lib/badline/snapshot/image.rb +5 -25
  291. data/lib/badline/snapshot/machine_state.rb +10 -2
  292. data/lib/badline/snapshot/setup.rb +22 -66
  293. data/lib/badline/snapshot/state.rb +8 -17
  294. data/lib/badline/snapshot/storage_setup.rb +68 -0
  295. data/lib/badline/snapshot/vic20_setup.rb +37 -0
  296. data/lib/badline/snapshot/vice/c64_mem.rb +1 -1
  297. data/lib/badline/snapshot/vice/restore.rb +1 -1
  298. data/lib/badline/snapshot/vice/reu1764.rb +1 -1
  299. data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
  300. data/lib/badline/snapshot/vice.rb +7 -5
  301. data/lib/badline/snapshot.rb +13 -12
  302. data/lib/badline/storage/d64_image.rb +15 -9
  303. data/lib/badline/storage/d71_image.rb +0 -2
  304. data/lib/badline/storage/d81_image.rb +0 -2
  305. data/lib/badline/storage/disk_image/writing.rb +2 -2
  306. data/lib/badline/storage/disk_image.rb +3 -6
  307. data/lib/badline/storage/g64_image.rb +2 -2
  308. data/lib/badline/storage/host_directory.rb +0 -5
  309. data/lib/badline/storage/t64.rb +2 -8
  310. data/lib/badline/storage/unavailable.rb +1 -1
  311. data/lib/badline/storage.rb +0 -37
  312. data/lib/badline/support/c128_checkpoint.rb +39 -0
  313. data/lib/badline/support/checkpoint.rb +108 -0
  314. data/lib/badline/support/vic20_checkpoint.rb +38 -0
  315. data/lib/badline/support.rb +5 -0
  316. data/lib/badline/version.rb +1 -1
  317. data/lib/badline/vic20/attachments.rb +11 -81
  318. data/lib/badline/vic20/bus/saved_state.rb +35 -0
  319. data/lib/badline/vic20/bus.rb +3 -25
  320. data/lib/badline/vic20/cpu.rb +1 -1
  321. data/lib/badline/vic20/port_wiring.rb +4 -4
  322. data/lib/badline/vic20/saved_state.rb +16 -60
  323. data/lib/badline/vic20/user_via_ports.rb +2 -2
  324. data/lib/badline/vic20.rb +20 -51
  325. metadata +250 -221
  326. data/lib/badline/address_bus/extra_sids.rb +0 -30
  327. data/lib/badline/address_bus/fittings.rb +0 -38
  328. data/lib/badline/address_bus/pla.rb +0 -147
  329. data/lib/badline/address_bus/roms.rb +0 -39
  330. data/lib/badline/address_bus/saved_state.rb +0 -72
  331. data/lib/badline/address_bus/sid_slots.rb +0 -42
  332. data/lib/badline/address_bus.rb +0 -235
  333. data/lib/badline/cartridge/action_replay.rb +0 -126
  334. data/lib/badline/cartridge/atomic_power.rb +0 -24
  335. data/lib/badline/cartridge/bank.rb +0 -81
  336. data/lib/badline/cartridge/comal80.rb +0 -50
  337. data/lib/badline/cartridge/dinamic.rb +0 -34
  338. data/lib/badline/cartridge/easy_flash.rb +0 -145
  339. data/lib/badline/cartridge/epyx_fastload.rb +0 -79
  340. data/lib/badline/cartridge/final_cartridge3.rb +0 -89
  341. data/lib/badline/cartridge/flash.rb +0 -306
  342. data/lib/badline/cartridge/freezer.rb +0 -33
  343. data/lib/badline/cartridge/fun_play.rb +0 -38
  344. data/lib/badline/cartridge/g_mod2.rb +0 -74
  345. data/lib/badline/cartridge/game_system.rb +0 -40
  346. data/lib/badline/cartridge/geo_ram.rb +0 -79
  347. data/lib/badline/cartridge/kcs_power.rb +0 -75
  348. data/lib/badline/cartridge/mach5.rb +0 -32
  349. data/lib/badline/cartridge/magic_desk.rb +0 -30
  350. data/lib/badline/cartridge/ocean.rb +0 -35
  351. data/lib/badline/cartridge/pagefox.rb +0 -68
  352. data/lib/badline/cartridge/retro_replay.rb +0 -320
  353. data/lib/badline/cartridge/rex_utility.rb +0 -29
  354. data/lib/badline/cartridge/rgcd.rb +0 -58
  355. data/lib/badline/cartridge/simons_basic.rb +0 -35
  356. data/lib/badline/cartridge/standard.rb +0 -15
  357. data/lib/badline/cartridge/super_games.rb +0 -48
  358. data/lib/badline/cartridge/westermann.rb +0 -30
  359. data/lib/badline/cartridge/zaxxon.rb +0 -66
  360. data/lib/badline/cartridge.rb +0 -303
  361. data/lib/badline/checkpoint.rb +0 -98
  362. data/lib/badline/cia/fast_forward.rb +0 -60
  363. data/lib/badline/cia/interrupt_register.rb +0 -143
  364. data/lib/badline/cia/serial.rb +0 -275
  365. data/lib/badline/cia/state.rb +0 -47
  366. data/lib/badline/cia/timer.rb +0 -206
  367. data/lib/badline/cia.rb +0 -279
  368. data/lib/badline/color_memory.rb +0 -25
  369. data/lib/badline/computer/kernal_traps.rb +0 -29
  370. data/lib/badline/control_ports.rb +0 -76
  371. data/lib/badline/cpu/addressing.rb +0 -131
  372. data/lib/badline/cpu/boundary.rb +0 -54
  373. data/lib/badline/cpu/core.rb +0 -165
  374. data/lib/badline/cpu/microcode.rb +0 -177
  375. data/lib/badline/cpu/operations.rb +0 -88
  376. data/lib/badline/cpu/saved_state.rb +0 -115
  377. data/lib/badline/cpu/stack_operations.rb +0 -82
  378. data/lib/badline/cpu.rb +0 -10
  379. data/lib/badline/cycleable.rb +0 -38
  380. data/lib/badline/datasette.rb +0 -161
  381. data/lib/badline/drive/core.rb +0 -147
  382. data/lib/badline/drive/fast_serial.rb +0 -73
  383. data/lib/badline/drive/idle.rb +0 -125
  384. data/lib/badline/drive/idle_cpu.rb +0 -28
  385. data/lib/badline/drive/orbit.rb +0 -79
  386. data/lib/badline/drive/serial_lines.rb +0 -73
  387. data/lib/badline/drive/sleep.rb +0 -112
  388. data/lib/badline/drive/vias.rb +0 -84
  389. data/lib/badline/drive/watch.rb +0 -150
  390. data/lib/badline/drive.rb +0 -11
  391. data/lib/badline/drive1541/bus.rb +0 -86
  392. data/lib/badline/drive1541/byte_ready.rb +0 -48
  393. data/lib/badline/drive1541/cpu.rb +0 -11
  394. data/lib/badline/drive1541/disk.rb +0 -318
  395. data/lib/badline/drive1541/disk_state.rb +0 -94
  396. data/lib/badline/drive1541/disk_via.rb +0 -36
  397. data/lib/badline/drive1541/gcr.rb +0 -57
  398. data/lib/badline/drive1541/mechanism.rb +0 -313
  399. data/lib/badline/drive1541/mechanism_state.rb +0 -68
  400. data/lib/badline/drive1541/rotation.rb +0 -121
  401. data/lib/badline/drive1541/sector_reader.rb +0 -76
  402. data/lib/badline/drive1541/serial_port.rb +0 -18
  403. data/lib/badline/drive1541/track.rb +0 -98
  404. data/lib/badline/drive1541.rb +0 -111
  405. data/lib/badline/drive1571/bus.rb +0 -111
  406. data/lib/badline/drive1571/cpu.rb +0 -11
  407. data/lib/badline/drive1571/serial_port.rb +0 -37
  408. data/lib/badline/drive1571/serial_via.rb +0 -25
  409. data/lib/badline/drive1571/wd1770.rb +0 -120
  410. data/lib/badline/drive1571.rb +0 -175
  411. data/lib/badline/drive1581/bus.rb +0 -137
  412. data/lib/badline/drive1581/cpu.rb +0 -11
  413. data/lib/badline/drive1581/disk.rb +0 -135
  414. data/lib/badline/drive1581/disk_state.rb +0 -87
  415. data/lib/badline/drive1581/mechanism.rb +0 -117
  416. data/lib/badline/drive1581/serial_port.rb +0 -52
  417. data/lib/badline/drive1581/slot.rb +0 -78
  418. data/lib/badline/drive1581/track.rb +0 -100
  419. data/lib/badline/drive1581/track_bytes.rb +0 -75
  420. data/lib/badline/drive1581/wd1772/registers.rb +0 -89
  421. data/lib/badline/drive1581/wd1772/sector_writes.rb +0 -73
  422. data/lib/badline/drive1581/wd1772/sectors.rb +0 -150
  423. data/lib/badline/drive1581/wd1772/state.rb +0 -66
  424. data/lib/badline/drive1581/wd1772/stepping.rb +0 -109
  425. data/lib/badline/drive1581/wd1772/tracks.rb +0 -125
  426. data/lib/badline/drive1581/wd1772/turn.rb +0 -73
  427. data/lib/badline/drive1581/wd1772.rb +0 -216
  428. data/lib/badline/drive1581.rb +0 -233
  429. data/lib/badline/iec_bus.rb +0 -159
  430. data/lib/badline/instruction.rb +0 -334
  431. data/lib/badline/instruction_set/arithmetic.rb +0 -114
  432. data/lib/badline/instruction_set/bitwise.rb +0 -126
  433. data/lib/badline/instruction_set/branch.rb +0 -79
  434. data/lib/badline/instruction_set/flag.rb +0 -63
  435. data/lib/badline/instruction_set/illegal.rb +0 -270
  436. data/lib/badline/instruction_set/inc_dec.rb +0 -69
  437. data/lib/badline/instruction_set/stack.rb +0 -52
  438. data/lib/badline/instruction_set/transfer.rb +0 -137
  439. data/lib/badline/instruction_set.rb +0 -55
  440. data/lib/badline/interrupts.rb +0 -104
  441. data/lib/badline/joystick.rb +0 -25
  442. data/lib/badline/kernal_trap/channel.rb +0 -181
  443. data/lib/badline/keyboard.rb +0 -112
  444. data/lib/badline/ram_expansion/banking.rb +0 -30
  445. data/lib/badline/ram_expansion/plus256k.rb +0 -54
  446. data/lib/badline/ram_expansion/plus60k.rb +0 -43
  447. data/lib/badline/ram_expansion/unexpanded.rb +0 -28
  448. data/lib/badline/ram_expansion.rb +0 -21
  449. data/lib/badline/reu/dma/saved_state.rb +0 -50
  450. data/lib/badline/reu/dma.rb +0 -273
  451. data/lib/badline/reu/ram.rb +0 -107
  452. data/lib/badline/reu/saved_state.rb +0 -80
  453. data/lib/badline/reu/trigger.rb +0 -32
  454. data/lib/badline/reu.rb +0 -289
  455. data/lib/badline/sid/catch_up.rb +0 -120
  456. data/lib/badline/sid/decimator.rb +0 -64
  457. data/lib/badline/sid/envelope/state.rb +0 -68
  458. data/lib/badline/sid/envelope.rb +0 -239
  459. data/lib/badline/sid/filter.rb +0 -263
  460. data/lib/badline/sid/voice.rb +0 -77
  461. data/lib/badline/sid/waveform/combined.rb +0 -126
  462. data/lib/badline/sid/waveform/fast_forward.rb +0 -105
  463. data/lib/badline/sid/waveform/noise_writeback.rb +0 -122
  464. data/lib/badline/sid/waveform/state.rb +0 -66
  465. data/lib/badline/sid/waveform.rb +0 -305
  466. data/lib/badline/sid.rb +0 -303
  467. data/lib/badline/time_of_day.rb +0 -228
  468. data/lib/badline/traps.rb +0 -19
  469. data/lib/badline/via/control_lines.rb +0 -122
  470. data/lib/badline/via/fast_forward.rb +0 -53
  471. data/lib/badline/via/interrupt_register.rb +0 -67
  472. data/lib/badline/via/shift_register.rb +0 -180
  473. data/lib/badline/via/state.rb +0 -42
  474. data/lib/badline/via/timer1.rb +0 -131
  475. data/lib/badline/via/timer2.rb +0 -133
  476. data/lib/badline/via.rb +0 -266
  477. data/lib/badline/vic/bank.rb +0 -133
  478. data/lib/badline/vic/border_mask.rb +0 -86
  479. data/lib/badline/vic/collisions.rb +0 -115
  480. data/lib/badline/vic/color_patches.rb +0 -47
  481. data/lib/badline/vic/display_state.rb +0 -185
  482. data/lib/badline/vic/graphics_mode.rb +0 -164
  483. data/lib/badline/vic/graphics_shifter.rb +0 -207
  484. data/lib/badline/vic/register_log.rb +0 -81
  485. data/lib/badline/vic/registers.rb +0 -195
  486. data/lib/badline/vic/sequencer.rb +0 -275
  487. data/lib/badline/vic/sequencer_output.rb +0 -116
  488. data/lib/badline/vic/sequencer_state.rb +0 -89
  489. data/lib/badline/vic/sprite/internal_bus.rb +0 -68
  490. data/lib/badline/vic/sprite/saved_state.rb +0 -64
  491. data/lib/badline/vic/sprite/shifter.rb +0 -146
  492. data/lib/badline/vic/sprite/timing.rb +0 -56
  493. data/lib/badline/vic/sprite.rb +0 -337
  494. data/lib/badline/vic/sprites.rb +0 -282
  495. data/lib/badline/vic/sprites_state.rb +0 -57
  496. data/lib/badline/vic.rb +0 -852
  497. data/lib/badline/vic20/sound/output.rb +0 -83
  498. data/lib/badline/vic20/sound.rb +0 -233
  499. data/lib/badline/z80/arithmetic.rb +0 -117
  500. data/lib/badline/z80/bit_page.rb +0 -55
  501. data/lib/badline/z80/block_io.rb +0 -58
  502. data/lib/badline/z80/block_transfers.rb +0 -59
  503. data/lib/badline/z80/bus_cycles.rb +0 -111
  504. data/lib/badline/z80/core.rb +0 -113
  505. data/lib/badline/z80/exchanges.rb +0 -50
  506. data/lib/badline/z80/extended_page.rb +0 -89
  507. data/lib/badline/z80/flags.rb +0 -37
  508. data/lib/badline/z80/interrupt_acceptance.rb +0 -46
  509. data/lib/badline/z80/jumps.rb +0 -82
  510. data/lib/badline/z80/loads.rb +0 -98
  511. data/lib/badline/z80/main_page.rb +0 -134
  512. data/lib/badline/z80/registers.rb +0 -120
  513. data/lib/badline/z80/saved_state.rb +0 -69
  514. data/lib/badline/z80/shifts.rb +0 -64
  515. data/lib/badline/z80.rb +0 -11
  516. /data/lib/badline/snapshot/{fields.rb → vice/fields.rb} +0 -0
@@ -4,7 +4,6 @@ require "zlib"
4
4
  require "badline/snapshot/state"
5
5
  require "badline/snapshot/setup"
6
6
  require "badline/snapshot/container"
7
- require "badline/snapshot/fields"
8
7
  require "badline/snapshot/machine_state"
9
8
  require "badline/snapshot/vice"
10
9
  require "badline/snapshot/image"
@@ -14,7 +13,7 @@ module Badline
14
13
  #
15
14
  # A snapshot badline writes carries VICE's modules for what both
16
15
  # emulators model, and a BADLINE module holding the State
17
- # Computer#snapshot takes, with everything badline needs to carry on
16
+ # C64#snapshot takes, with everything badline needs to carry on
18
17
  # exactly where it stopped. VICE skips modules it doesn't know. Restoring
19
18
  # a badline snapshot uses the BADLINE module alone; a snapshot from VICE
20
19
  # restores through its modules, as far as they map, and reports the
@@ -47,23 +46,25 @@ module Badline
47
46
  # applied and left out, yielding a line for each thing left out. A
48
47
  # snapshot that fails leaves the machine as it was.
49
48
  def restore(computer, path, &) = read(path).restore(computer, &)
50
- end
51
49
 
52
- class Computer
53
- def save_snapshot(path) = Snapshot.save(self, path)
50
+ # A machine's snapshots as .vsf files. C64, Vic20 and C128 each
51
+ # include it.
52
+ module Files
53
+ def save_snapshot(path) = Snapshot.save(self, path)
54
54
 
55
- def restore_snapshot(path, &) = Snapshot.restore(self, path, &)
55
+ def restore_snapshot(path, &) = Snapshot.restore(self, path, &)
56
+ end
56
57
  end
57
58
 
58
- class Vic20
59
- def save_snapshot(path) = Snapshot.save(self, path)
59
+ class C64
60
+ include Snapshot::Files
61
+ end
60
62
 
61
- def restore_snapshot(path, &) = Snapshot.restore(self, path, &)
63
+ class Vic20
64
+ include Snapshot::Files
62
65
  end
63
66
 
64
67
  class C128
65
- def save_snapshot(path) = Snapshot.save(self, path)
66
-
67
- def restore_snapshot(path, &) = Snapshot.restore(self, path, &)
68
+ include Snapshot::Files
68
69
  end
69
70
  end
@@ -15,20 +15,26 @@ module Badline
15
15
  count
16
16
  end
17
17
 
18
- def storage_kind = D64
19
-
20
18
  # The sides of a disk the image's tracks fill.
21
19
  def sides = 1
22
20
 
23
- def sectors_in(track)
24
- case track
25
- when 1..17 then 21
26
- when 18..24 then 19
27
- when 25..30 then 18
28
- else 17
29
- end
21
+ # The last track of each of the 1541's speed zones but the innermost,
22
+ # from the outermost, zone 3, in: tracks 1-17, 18-24 and 25-30, and
23
+ # zone 0 from 31 on.
24
+ ZONE_LAST_TRACKS = [17, 24, 30].freeze
25
+
26
+ # The sectors a track holds in each zone, by its number.
27
+ ZONE_SECTORS = [17, 18, 19, 21].freeze
28
+
29
+ # The speed zone a track is written in, 3 for the outermost.
30
+ def self.zone(track)
31
+ zone = 3
32
+ zone -= 1 while zone.positive? && track > ZONE_LAST_TRACKS[3 - zone]
33
+ zone
30
34
  end
31
35
 
36
+ def sectors_in(track) = ZONE_SECTORS[D64Image.zone(track)]
37
+
32
38
  private
33
39
 
34
40
  def error_tables = ERROR_TABLES
@@ -5,8 +5,6 @@ module Badline
5
5
  class D71Image < D64Image
6
6
  ERROR_TABLES = { 351_062 => 1366 }.freeze
7
7
 
8
- def storage_kind = D71
9
-
10
8
  # Tracks 1-35 on the first side and 36-70 on the second.
11
9
  def track_count = 70
12
10
 
@@ -5,8 +5,6 @@ module Badline
5
5
  class D81Image < DiskImage
6
6
  ERROR_TABLES = { 822_400 => 3200 }.freeze
7
7
 
8
- def storage_kind = D81
9
-
10
8
  private
11
9
 
12
10
  def error_tables = ERROR_TABLES
@@ -11,7 +11,7 @@ module Badline
11
11
  module Writing
12
12
  # Whether the disk takes writes: the image wasn't opened read-only
13
13
  # and the host file takes them.
14
- def writable? = !read_only? && ::File.writable?(@path)
14
+ def writable? = !read_only? && File.writable?(@path)
15
15
 
16
16
  # Writes a new file, or with `replace` writes over the one of the
17
17
  # same name in its directory entry. A name already on the disk
@@ -87,7 +87,7 @@ module Badline
87
87
  saved = [@bytes.dup, @errors&.dup]
88
88
  begin
89
89
  yield
90
- ::File.binwrite(@path, (@bytes + @errors.to_a).pack("C*"))
90
+ File.binwrite(@path, (@bytes + @errors.to_a).pack("C*"))
91
91
  rescue WriteError, SystemCallError => e
92
92
  @bytes, @errors = saved
93
93
  raise e.is_a?(WriteError) ? e : WriteError.new(WriteError::WRITE_PROTECT_ON)
@@ -42,12 +42,9 @@ module Badline
42
42
  # Whether the image was opened write-protected.
43
43
  def read_only? = @read_only
44
44
 
45
- # What Storage.reopen needs to open the image again as it stands: its
46
- # path, whether it is write-protected, and its bytes with the error
47
- # table after them.
48
- def save_setup(out)
49
- out.int(storage_kind).string(::File.expand_path(@path)).boolean(@read_only).blob(@bytes + @errors.to_a)
50
- end
45
+ # The image as its file holds it, with its error table after the
46
+ # blocks.
47
+ def contents = @bytes + @errors.to_a
51
48
 
52
49
  # A LOAD reads only PRG files. An OPEN names the type it wants, or
53
50
  # takes the first file of any type with a nil `type`.
@@ -5,7 +5,7 @@ module Badline
5
5
  # A .g64 image: a 1541 disk's flux as raw GCR, track by track, for the
6
6
  # true drive to read the way it reads a real disk, copy protection and
7
7
  # all. It has no file system of its own, so only the true drive
8
- # (Drive1541::Disk.from_g64) can use it. A .g71 holds a 1571 disk the
8
+ # (Drives::Model1541::Disk.from_g64) can use it. A .g71 holds a 1571 disk the
9
9
  # same way, with "GCR-1571" for its signature and 168 half tracks,
10
10
  # the first side's 84 and then the second's.
11
11
  #
@@ -21,7 +21,7 @@ module Badline
21
21
  # A larger one is the offset of a speed map, two bits a byte, four
22
22
  # track bytes to a map byte, the first byte's in the top two bits, for
23
23
  # a track whose zone changes along it. The drive passes each byte
24
- # under the head at its own zone's rate (Drive1541::Track).
24
+ # under the head at its own zone's rate (Drives::Model1541::Track).
25
25
  #
26
26
  # The drive writes a track at one zone, so a track written back takes
27
27
  # that zone as its speed entry. Writing it puts it in its own block,
@@ -17,11 +17,6 @@ module Badline
17
17
  @path = path
18
18
  end
19
19
 
20
- # What Storage.reopen needs to open the directory again.
21
- def save_setup(out)
22
- out.int(HOST_DIRECTORY).string(::File.expand_path(@path))
23
- end
24
-
25
20
  def read_file(name, **)
26
21
  entry = find(name)
27
22
  return unless entry
@@ -20,14 +20,8 @@ module Badline
20
20
  raise FormatError, "Missing T64 signature" unless @bytes[0, 3] == SIGNATURE
21
21
  end
22
22
 
23
- # The host file's path, as it was opened.
24
- attr_reader :path
25
-
26
- # What Storage.reopen needs to open the archive again: its path and
27
- # its bytes.
28
- def save_setup(out)
29
- out.int(T64_ARCHIVE).string(::File.expand_path(@path)).blob(@bytes)
30
- end
23
+ # The host file's path, as it was opened, and its bytes.
24
+ attr_reader :path, :bytes
31
25
 
32
26
  def read_file(name, **)
33
27
  pattern = Storage.matcher(name)
@@ -3,7 +3,7 @@
3
3
  module Badline
4
4
  module Storage
5
5
  # Stands in for a directory a detached restore leaves out
6
- # (Snapshot::StateReader): it finds no files and refuses every write
6
+ # (Snapshot::StorageSetup): it finds no files and refuses every write
7
7
  # as a write-protected disk does.
8
8
  class Unavailable
9
9
  def path = ""
@@ -11,10 +11,6 @@ require "badline/storage/g64_image"
11
11
  require "badline/storage/t64"
12
12
  require "badline/storage/tap"
13
13
  require "badline/storage/crt_file"
14
- require "badline/storage/sid_file"
15
- require "badline/storage/hvsc"
16
- require "badline/storage/song_lengths"
17
- require "badline/storage/stil"
18
14
  require "badline/storage/unavailable"
19
15
 
20
16
  module Badline
@@ -36,29 +32,7 @@ module Badline
36
32
  end
37
33
  end
38
34
 
39
- # The storage a snapshot's device 8 serves, by the number save_setup
40
- # writes first.
41
- HOST_DIRECTORY = 0
42
- D64 = 1
43
- D71 = 2
44
- D81 = 3
45
- T64_ARCHIVE = 4
46
-
47
35
  class << self
48
- # Opens the storage a save_setup wrote: the same directory by its
49
- # path, an archive with the bytes it held, or a disk image with the
50
- # bytes it held, writes and all. A detached reader gets the image
51
- # write-protected, and Unavailable for a directory.
52
- def reopen(input)
53
- kind = input.int
54
- path = input.string
55
- case kind
56
- when HOST_DIRECTORY then input.detached? ? Unavailable.new : HostDirectory.new(path)
57
- when T64_ARCHIVE then T64.new(path, bytes: input.blob)
58
- else reopen_image(kind, path, input)
59
- end
60
- end
61
-
62
36
  # Folds shifted PETSCII letters to their ASCII equivalents.
63
37
  def ascii(bytes)
64
38
  bytes.map { |b| b.between?(0xc1, 0xda) ? b - 0x80 : b }.pack("C*")
@@ -83,17 +57,6 @@ module Badline
83
57
  [base.to_s, FILE_TYPES[type.to_s.strip[0]&.upcase]]
84
58
  end
85
59
 
86
- def reopen_image(kind, path, input)
87
- read_only = input.boolean? || input.detached?
88
- bytes = input.blob
89
- case kind
90
- when D64 then D64Image.new(path, read_only:, bytes:)
91
- when D71 then D71Image.new(path, read_only:, bytes:)
92
- when D81 then D81Image.new(path, read_only:, bytes:)
93
- else raise Snapshot::FormatError, "unknown storage #{kind} in the state"
94
- end
95
- end
96
-
97
60
  # CBM-style filename pattern: "*" and "?" wildcards, case-insensitive.
98
61
  # The DOS stops comparing at the first "*", so whatever follows it
99
62
  # is ignored.
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Support
5
+ # A Checkpoint of a C128, in either mode: a C64's components, with the
6
+ # whole 128K of RAM in place of bank 0 and the colour RAM bank the 8502
7
+ # sees, and besides them the VDC's registers and beam, the VDC's RAM, the
8
+ # MMU's registers and the Z80.
9
+ module C128Checkpoint
10
+ COMPONENTS = %w[cpu ram color_ram display vic cia1 cia2 sid vdc vdc_ram mmu z80].freeze
11
+
12
+ def self.take(machine)
13
+ Checkpoint.new(machine.cycles, [
14
+ Checkpoint.fnv1a(Checkpoint.cpu_state(machine.cpu)),
15
+ Checkpoint.fnv1a(Checkpoint.ram(machine.ram, 0x20000)),
16
+ Checkpoint.fnv1a(Checkpoint.color_ram(machine.address_bus.color_ram, 0xd800)),
17
+ Checkpoint.fnv1a(machine.vic.display),
18
+ Checkpoint.fnv1a(Checkpoint.vic_state(machine.vic)),
19
+ Checkpoint.fnv1a(Checkpoint.cia_state(machine.cia1)),
20
+ Checkpoint.fnv1a(Checkpoint.cia_state(machine.cia2)),
21
+ Checkpoint.fnv1a(Array.new(0x20) { |reg| machine.sid.register(reg) }),
22
+ Checkpoint.fnv1a(machine.vdc.registers + [machine.vdc.frame]),
23
+ Checkpoint.fnv1a(machine.vdc.ram),
24
+ Checkpoint.fnv1a(machine.mmu.registers),
25
+ Checkpoint.fnv1a(z80_state(machine.z80))
26
+ ], COMPONENTS)
27
+ end
28
+
29
+ def self.parse(line) = Checkpoint.parse(line, COMPONENTS)
30
+
31
+ def self.z80_state(z80)
32
+ [z80.pc, z80.sp, z80.af, z80.bc, z80.de, z80.hl, z80.ix, z80.iy, z80.af_alt, z80.bc_alt, z80.de_alt,
33
+ z80.hl_alt, z80.i, z80.r, z80.im, flag(z80.iff1), flag(z80.iff2), flag(z80.halted), z80.cycles]
34
+ end
35
+
36
+ def self.flag(value) = value == true ? 1 : 0
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Support
5
+ # A digest of the machine's state at one cycle, for comparing two runs of
6
+ # the same scenario, on two builds or two revisions. Each component is
7
+ # hashed on its own with 32-bit FNV-1a, so a mismatch names the part of the
8
+ # machine that went its own way. Nothing is read through a chip's bus
9
+ # interface, so taking a checkpoint leaves the machine as it was.
10
+ #
11
+ # Checkpoint.take digests a C64's components, COMPONENTS.
12
+ # Vic20Checkpoint and C128Checkpoint digest the other families', each
13
+ # with a list of its own, which a checkpoint carries as +components+.
14
+ #
15
+ # Colour RAM is digested as the four bits each cell stores: the upper
16
+ # nibble a CPU read sees comes off the open bus.
17
+ class Checkpoint
18
+ COMPONENTS = %w[cpu ram color_ram display vic cia1 cia2 sid].freeze
19
+
20
+ FNV_OFFSET = 0x811c9dc5
21
+ FNV_PRIME = 0x01000193
22
+
23
+ attr_reader :cycle, :digests, :components
24
+
25
+ class << self
26
+ def take(computer)
27
+ new(computer.cycles, [
28
+ fnv1a(cpu_state(computer.cpu)),
29
+ fnv1a(ram(computer.ram, 0x10000)),
30
+ fnv1a(color_ram(computer.address_bus.color_ram, 0xd800)),
31
+ fnv1a(computer.vic.display),
32
+ fnv1a(vic_state(computer.vic)),
33
+ fnv1a(cia_state(computer.cia1)),
34
+ fnv1a(cia_state(computer.cia2)),
35
+ fnv1a(Array.new(0x20) { |reg| computer.sid.register(reg) })
36
+ ])
37
+ end
38
+
39
+ # Reads a line written by #to_s, with a digest for each of
40
+ # `components`.
41
+ def parse(line, components = COMPONENTS)
42
+ fields = line.split
43
+ digests = components.map do |name|
44
+ field = fields.find { |f| f.start_with?("#{name}=") }
45
+ raise ArgumentError, "no #{name} digest in #{line.inspect}" unless field
46
+
47
+ field.split("=").last.to_i(16)
48
+ end
49
+ new(fields.first.to_i, digests, components)
50
+ end
51
+
52
+ def fnv1a(values)
53
+ hash = FNV_OFFSET
54
+ values.each { |value| hash = ((hash ^ (value & 0xffffffff)) * FNV_PRIME) & 0xffffffff }
55
+ hash
56
+ end
57
+
58
+ # The registers and cycle count of a 6502 or an 8502.
59
+ def cpu_state(cpu)
60
+ [cpu.program_counter, cpu.a, cpu.x, cpu.y, cpu.stack_pointer, cpu.p, cpu.cycles]
61
+ end
62
+
63
+ # The first `length` bytes of `memory`.
64
+ def ram(memory, length)
65
+ Array.new(length) { |addr| memory.peek(addr) }
66
+ end
67
+
68
+ # The 1K of colour RAM at `start`.
69
+ def color_ram(memory, start)
70
+ Array.new(0x400) { |offset| memory.nibble(start + offset) }
71
+ end
72
+
73
+ # A VIC-II's or a VIC-I's registers and beam position.
74
+ def vic_state(vic)
75
+ vic.register_file + [vic.rasterline, vic.column]
76
+ end
77
+
78
+ def cia_state(cia)
79
+ start = cia.start
80
+ [cia.peek(start), cia.peek(start + 1), cia.peek(start + 2), cia.peek(start + 3),
81
+ cia.timer_a, cia.timer_a_latch, cia.timer_b, cia.timer_b_latch, cia.serial.data,
82
+ cia.control_a.value, cia.control_b.value, cia.interrupt_status.value,
83
+ cia.interrupt_control.value] + cia.time_of_day.registers
84
+ end
85
+ end
86
+
87
+ def initialize(cycle, digests, components = COMPONENTS)
88
+ @cycle = cycle
89
+ @digests = digests
90
+ @components = components
91
+ end
92
+
93
+ # The components whose digests differ from `other`'s.
94
+ def differences(other)
95
+ components.each_index.reject { |i| digests[i] == other.digests[i] }.map { |i| components[i] }
96
+ end
97
+
98
+ def ==(other)
99
+ other.is_a?(Checkpoint) && cycle == other.cycle && components == other.components && digests == other.digests
100
+ end
101
+
102
+ def to_s
103
+ fields = components.each_index.map { |i| "#{components[i]}=#{digests[i].to_s(16).rjust(8, '0')}" }
104
+ "#{cycle} #{fields.join(' ')}"
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Support
5
+ # A Checkpoint of a VIC-20: its CPU, the 48K of RAM the bus decodes, the
6
+ # colour RAM, the VIC-I's display and registers, both VIAs and the
7
+ # sound. The sound's shift registers and noise LFSR move only while it
8
+ # records, so a run that wants them digested records it.
9
+ module Vic20Checkpoint
10
+ COMPONENTS = %w[cpu ram color_ram display vic via1 via2 sound].freeze
11
+
12
+ def self.take(machine)
13
+ Checkpoint.new(machine.cycles, [
14
+ Checkpoint.fnv1a(Checkpoint.cpu_state(machine.cpu)),
15
+ Checkpoint.fnv1a(Checkpoint.ram(machine.ram, 0xc000)),
16
+ Checkpoint.fnv1a(Checkpoint.color_ram(machine.bus.color_ram, 0)),
17
+ Checkpoint.fnv1a(machine.vic.display),
18
+ Checkpoint.fnv1a(Checkpoint.vic_state(machine.vic)),
19
+ Checkpoint.fnv1a(via_state(machine.via1)),
20
+ Checkpoint.fnv1a(via_state(machine.via2)),
21
+ Checkpoint.fnv1a(sound_state(machine.sound))
22
+ ], COMPONENTS)
23
+ end
24
+
25
+ def self.parse(line) = Checkpoint.parse(line, COMPONENTS)
26
+
27
+ def self.via_state(via)
28
+ [via.port_a_output, via.port_b_output, via.timer1, via.timer1_latch, via.timer2,
29
+ via.shift_register.data, via.acr, via.pcr, via.interrupt_flags, via.interrupt_enable]
30
+ end
31
+
32
+ def self.sound_state(sound)
33
+ [sound.volume, sound.shift_register(0), sound.shift_register(1), sound.shift_register(2),
34
+ sound.shift_register(3), sound.lfsr]
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/support/checkpoint"
4
+ require "badline/support/vic20_checkpoint"
5
+ require "badline/support/c128_checkpoint"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- VERSION = "0.12.0"
4
+ VERSION = "0.13.0"
5
5
  end
@@ -3,10 +3,12 @@
3
3
  module Badline
4
4
  class Vic20
5
5
  # What plugs into the VIC-20 besides its chips: cartridge ROM in the
6
- # expansion blocks, the disk device 8 serves through the KERNAL traps,
7
- # and a true 1541 or 1581 on the serial bus.
6
+ # expansion blocks, the disk device 8 serves through the KERNAL traps
7
+ # (C64::KernalTraps), and a true 1541 or 1581 on the serial bus
8
+ # (C64::TrueDrives).
8
9
  module Attachments
9
- include Drive1581::Slot
10
+ include C64::TrueDrives
11
+ include C64::KernalTraps
10
12
 
11
13
  # The cycle by which a 1541 switched on with the machine has run its
12
14
  # DOS's reset, the RAM test and the ROM checksum, and waits on the
@@ -27,96 +29,24 @@ module Badline
27
29
  power_cycle!
28
30
  end
29
31
 
30
- # Puts the storage in device 8. Mounting again swaps the disk at any
31
- # point while the machine runs: the drive keeps its RAM and its
32
- # status.
33
- def mount(storage)
34
- return @drive.insert(storage) if @drive
35
-
36
- @drive = KernalTrap::Drive.new(storage)
37
- layout = KernalTrap::VIC20_LAYOUT
38
- load_trap = KernalTrap::Load.new(cpu:, bus:, layout:, drive: @drive)
39
- cpu.install_trap(layout.load) { load_trap.call }
40
- @serial_trap = KernalTrap::Serial.new(cpu:, bus:, layout:, drive: @drive, device: serial_trap_device).install
41
- save_trap = @save_trap = KernalTrap::Save.new(cpu:, bus:, layout:, drive: @drive)
42
- cpu.install_trap(layout.save) { save_trap.call }
43
- end
44
-
45
- # Takes device 8's mounted storage out, and with it the LOAD, SAVE and
46
- # serial traps, so the KERNAL's routines go out over the serial bus.
47
- # Mounting again starts a new drive, with its RAM cleared.
48
- def unmount
49
- return unless @drive
32
+ private
50
33
 
51
- cpu.remove_trap(KernalTrap::VIC20_LAYOUT.load)
52
- cpu.remove_trap(KernalTrap::VIC20_LAYOUT.save)
53
- @serial_trap.uninstall
54
- @serial_trap = nil
55
- @save_trap = nil
56
- @drive = nil
57
- end
34
+ # The VIC-20's KERNAL, which the traps stand in for.
35
+ def trap_layout = KernalTrap::VIC20_LAYOUT
58
36
 
59
- # Whether device 8 serves a disk or directory through the traps.
60
- def mounted? = !@drive.nil?
37
+ def trap_bus = @bus
61
38
 
62
- # Plugs in a Drive1541, which then runs alongside the VIC-20 on its own
63
- # clock and talks to it over the serial bus. The serial traps stop
64
- # answering the drive's device number, so the KERNAL's TALK, LISTEN
65
- # and byte transfers reach the drive. The LOAD and SAVE traps stay,
66
- # and still serve a mounted image.
67
- #
68
39
  # A drive that powers on with the machine takes longer to boot than
69
40
  # the KERNAL, and doesn't answer the bus until it has, so the
70
41
  # machine's on_init handlers wait for it too.
71
- def attach_drive1541(drive)
42
+ def drive1541_attached
72
43
  @init_threshold = [@init_threshold, DRIVE_BOOT_CYCLES].max if @cycles < @init_threshold
73
- @iec_bus.detach(@drive1541) if @drive1541
74
- drive.host_clock_hz = timing.clock_hz
75
- @drive1541 = drive
76
- drive.connect(@iec_bus)
77
- @serial_trap&.device = serial_trap_device
78
- end
79
-
80
- # The true drive on the serial bus: the Drive1581 ahead of the
81
- # Drive1541, or nil.
82
- def true_drive = @drive1581 || @drive1541
83
-
84
- # Plugs a Drive1541 in as device 8, in place of a 1581 there, and
85
- # returns it.
86
- def plug_true_drive
87
- detach_drive1581 if drive1581_on_device8?
88
- Drive1541.new.tap { |drive| attach_drive1541(drive) }
89
- end
90
-
91
- # Unplugs the Drive1541, leaving the serial bus with nothing on it.
92
- def detach_drive1541
93
- return unless @drive1541
94
-
95
- @iec_bus.detach(@drive1541)
96
- @drive1541 = nil
97
- @serial_trap&.device = serial_trap_device
98
- end
99
-
100
- # Records what the KERNAL prints through CHROUT (ChroutTrap).
101
- def capture_output
102
- @capture_output ||= ChroutTrap.new(cpu:, bus:, layout: KernalTrap::VIC20_LAYOUT).tap do |trap|
103
- cpu.install_trap(ChroutTrap::ADDRESS) { trap.call }
104
- end
105
- end
106
-
107
- private
108
-
109
- # The device number the serial traps answer: device 8, unless a true
110
- # drive is on the bus as device 8.
111
- def serial_trap_device
112
- device = KernalTrap::Routine::DEVICE
113
- @drive1541&.device == device || drive1581_on_device8? ? nil : device
114
44
  end
115
45
 
116
46
  # A 1581 plugged in, as a 1541 does, holds the machine's on_init
117
47
  # handlers back until its DOS has booted.
118
48
  def drive1581_attached
119
- @init_threshold = [@init_threshold, Drive1581::BOOT_CYCLES].max if @cycles < @init_threshold
49
+ @init_threshold = [@init_threshold, Drives::Model1581::BOOT_CYCLES].max if @cycles < @init_threshold
120
50
  end
121
51
  end
122
52
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class Vic20
5
+ class Bus
6
+ # The bus's state for a snapshot.
7
+ module SavedState
8
+ # The RAM, the colour RAM, the byte each side's data lines hold and the
9
+ # cartridge's ROM chips, for a snapshot. The expansion blocks are how
10
+ # the machine was built.
11
+ def save_state(out)
12
+ out.marker("VIC20 BUS")
13
+ @ram.save_state(out)
14
+ out.blob(@color_ram.cells).int(@data).int(@video_data).int(@roms.length)
15
+ @roms.each do |rom|
16
+ out.int(rom.start)
17
+ rom.save_state(out)
18
+ end
19
+ end
20
+
21
+ def load_state(input)
22
+ input.marker("VIC20 BUS")
23
+ @ram.load_state(input)
24
+ input.blob_into(@color_ram.cells)
25
+ @data = input.int
26
+ @video_data = input.int
27
+ chips = Array.new(input.int) { [input.int, input.blob] }
28
+ @roms = []
29
+ chips.each { |chip| @roms << ROM.new(chip[1], length: chip[1].length, start: chip[0]) }
30
+ map_pages
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "badline/vic20/bus/saved_state"
4
+
3
5
  module Badline
4
6
  class Vic20
5
7
  # The CPU's bus:
@@ -27,6 +29,7 @@ module Badline
27
29
  # Writes to ROM and to empty spots go nowhere.
28
30
  class Bus
29
31
  include Addressable
32
+ include SavedState
30
33
 
31
34
  # The pages each expansion block covers, as [first page, count].
32
35
  BLOCKS = {
@@ -215,31 +218,6 @@ module Badline
215
218
  @ram.clear!(RAM_POWER_ON)
216
219
  end
217
220
 
218
- # The RAM, the colour RAM, the byte each side's data lines hold and the
219
- # cartridge's ROM chips, for a snapshot. The expansion blocks are how
220
- # the machine was built.
221
- def save_state(out)
222
- out.marker("VIC20 BUS")
223
- @ram.save_state(out)
224
- out.blob(@color_ram.cells).int(@data).int(@video_data).int(@roms.length)
225
- @roms.each do |rom|
226
- out.int(rom.start)
227
- rom.save_state(out)
228
- end
229
- end
230
-
231
- def load_state(input)
232
- input.marker("VIC20 BUS")
233
- @ram.load_state(input)
234
- input.blob_into(@color_ram.cells)
235
- @data = input.int
236
- @video_data = input.int
237
- chips = Array.new(input.int) { [input.int, input.blob] }
238
- @roms = []
239
- chips.each { |chip| @roms << ROM.new(chip[1], length: chip[1].length, start: chip[0]) }
240
- map_pages
241
- end
242
-
243
221
  # Whether +block+ (BLOCKS) holds RAM.
244
222
  def ram?(block) = @blocks.include?(block)
245
223