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
@@ -0,0 +1,183 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module KernalTrap
5
+ class DOS
6
+ # One open channel on the virtual drive, holding a file, a block buffer
7
+ # or the command channel's status message. It gives out one byte at a
8
+ # time and flags the last one, so the bus can raise EOI with it. A
9
+ # channel cut short by a read error never flags one, and holds the
10
+ # error for the drive to report once its bytes run out.
11
+ class Channel
12
+ attr_accessor :buffer
13
+ attr_reader :error, :pointer
14
+ attr_writer :lead
15
+
16
+ def initialize(bytes = [], error: nil, writable: false, base: 0)
17
+ @base = base
18
+ replace(bytes)
19
+ @error = error
20
+ @writable = writable
21
+ end
22
+
23
+ # A block buffer opened with "#", which reads and writes one of the
24
+ # drive's buffers in its RAM, so M-R and M-W reach the same bytes. It
25
+ # hands out the whole block unless a B-R sets a shorter end, and
26
+ # flags that byte as the last. The DOS opens it with the pointer at 1
27
+ # and the buffer's number as the byte to send, so the first read
28
+ # answers with the number and the next one moves on to the third
29
+ # byte.
30
+ def self.buffer(memory, number)
31
+ new(memory.ram, writable: true, base: Memory.buffer_address(number)).tap do |channel|
32
+ channel.buffer = number
33
+ channel.rewind(BLOCK_SIZE)
34
+ channel.pointer = 1
35
+ channel.lead = number
36
+ end
37
+ end
38
+
39
+ # A file's bytes, up to the first block its chain can't read. The
40
+ # drive reads a block ahead before sending the last byte of the one
41
+ # before, so a bad block holds that byte back too, and a bad first
42
+ # block or a missing file leaves nothing to send.
43
+ def self.for_file(storage, name, type)
44
+ data = storage.read_file(name, type:)
45
+ return new([], error: [FILE_NOT_FOUND]) unless data
46
+
47
+ failure = storage.respond_to?(:read_error) && storage.read_error(name, type:)
48
+ return new(data) unless failure
49
+
50
+ new(data[0, failure[:offset] - 1] || [], error: failure.values_at(:error, :track, :sector))
51
+ end
52
+
53
+ # The file an open names. The drive keeps the first block of the file
54
+ # a LOAD (secondary address 0) opens at $7E and $026F of its memory,
55
+ # and a LOAD of a name starting with "*" reopens that file rather than
56
+ # the first one on the disk. Loaders write the block there with M-W
57
+ # to load a file the directory doesn't list. A LOAD of "$" reads the
58
+ # directory as a BASIC program, which a pattern after a colon narrows
59
+ # to the files it names.
60
+ def self.for_name(storage, memory, secondary, name, type)
61
+ return new(storage.directory.bytes(name)) if listing?(storage, secondary, name)
62
+
63
+ file = Storage.parse_name(name).first
64
+ return for_file(storage, file, type) unless secondary.zero? && storage.respond_to?(:first_block)
65
+
66
+ last = memory.last_program if name.start_with?("*")
67
+ return at_block(storage, *last) if last
68
+
69
+ block = storage.first_block(file, type:)
70
+ memory.last_program = block if block
71
+ for_file(storage, file, type)
72
+ end
73
+
74
+ def self.listing?(storage, secondary, name)
75
+ secondary.zero? && name.start_with?("$") && storage.respond_to?(:directory)
76
+ end
77
+
78
+ # The file whose chain starts at the block.
79
+ def self.at_block(storage, track, sector)
80
+ data = storage.read_file_at(track, sector)
81
+ data ? new(data) : new([], error: [ILLEGAL_TRACK_OR_SECTOR, track, sector])
82
+ end
83
+
84
+ # Reads what save_state wrote after the flag that marks a file open
85
+ # for writing (Channels.channel_from_state). A buffer channel
86
+ # takes its block in `ram`, the drive's RAM, again.
87
+ def self.from_state(input, ram)
88
+ new.tap { |channel| channel.load_state(input, ram) }
89
+ end
90
+
91
+ # A buffer channel's bytes are the drive's RAM, which the drive
92
+ # writes itself.
93
+ def save_state(out)
94
+ out.boolean(false).boolean(@writable).int(@base).int(@length).int(@pointer)
95
+ out.optional_int(@lead).optional_int(@buffer).boolean(!@error.nil?)
96
+ out.ints(@error) if @error
97
+ out.blob(@bytes) unless @writable
98
+ end
99
+
100
+ def load_state(input, ram)
101
+ @writable = input.boolean?
102
+ @base = input.int
103
+ @length = input.int
104
+ @pointer = input.int
105
+ @lead = input.optional_int
106
+ @buffer = input.optional_int
107
+ @error = input.boolean? ? input.ints : nil
108
+ @bytes = @writable ? ram : input.blob
109
+ end
110
+
111
+ def replace(bytes, length = bytes.length)
112
+ @bytes = bytes
113
+ rewind(length)
114
+ end
115
+
116
+ def rewind(length)
117
+ @length = length
118
+ self.pointer = 0
119
+ end
120
+
121
+ def pointer=(position)
122
+ @pointer = position
123
+ @lead = nil
124
+ end
125
+
126
+ # A block read into the channel. A buffer channel takes it into its
127
+ # buffer, a file channel hands it out in place of the file.
128
+ def load(block, length)
129
+ return replace(block.dup, length) unless @writable
130
+
131
+ @bytes[@base, block.length] = block
132
+ rewind(length)
133
+ end
134
+
135
+ def writable? = @writable
136
+
137
+ # A buffer channel's block, as a block write puts it on the disk.
138
+ def block = @bytes[@base, BLOCK_SIZE]
139
+
140
+ def exhausted?
141
+ @pointer >= @length
142
+ end
143
+
144
+ # A file that holds nothing but its error never opened.
145
+ def failed?
146
+ exhausted? && !@error.nil?
147
+ end
148
+
149
+ # Each byte lands at the pointer, which wraps within the block.
150
+ def write(bytes)
151
+ @lead = nil
152
+ bytes.each do |byte|
153
+ @bytes[@base + @pointer] = byte
154
+ @pointer = (@pointer + 1) & 0xff
155
+ end
156
+ end
157
+
158
+ def read
159
+ return read_buffer if @writable
160
+ return if exhausted?
161
+
162
+ byte = @lead || @bytes[@base + @pointer]
163
+ @lead = nil
164
+ @pointer += 1
165
+ [byte, exhausted? && !@error]
166
+ end
167
+
168
+ private
169
+
170
+ # A buffer never runs out. Past its last byte, which goes out with
171
+ # EOI, the pointer wraps back to the second, and a pointer set past
172
+ # the end runs on around the block to it.
173
+ def read_buffer
174
+ byte = @lead || @bytes[@base + @pointer]
175
+ @lead = nil
176
+ last = @pointer == @length - 1
177
+ @pointer = last ? 1 : (@pointer + 1) & 0xff
178
+ [byte, last]
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Badline
4
4
  module KernalTrap
5
- class Drive
5
+ class DOS
6
6
  # The drive's open data channels by secondary address, and the five
7
7
  # buffers they hold. The DOS hands out the highest free buffer.
8
8
  # Reading the BAM when it initializes the disk takes buffer 4, so
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Badline
4
4
  module KernalTrap
5
- class Drive
5
+ class DOS
6
6
  # The drive's 2K of RAM, as M-W and M-R reach it, with the job queue
7
7
  # that runs a read job written into it: a job code for each of five
8
8
  # buffers at $00, their track and sector pairs from $06, and the
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Badline
4
4
  module KernalTrap
5
- class Drive
5
+ class DOS
6
6
  # The numbers a DOS command takes. The DOS skips spaces, commas and
7
7
  # cursor-rights before a parameter, reads it from the characters $30
8
8
  # to $3F that follow, the low nibble of each, and skips whatever
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Badline
4
4
  module KernalTrap
5
- class Drive
5
+ class DOS
6
6
  # The command channel's side of the drive: the last DOS error with the
7
7
  # track and sector it happened at, or the bytes an M-R read. Once its
8
8
  # last byte has been read, it holds OK again.
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Badline
4
4
  module KernalTrap
5
- class Drive
5
+ class DOS
6
6
  # A channel open for writing a file. It gathers the bytes sent to it,
7
7
  # and the drive writes the file to the disk when the channel closes.
8
8
  # An append starts from the file's end, a replace writes over the
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Badline
4
4
  module KernalTrap
5
- class Drive
5
+ class DOS
6
6
  # Opens for writing, the S command and the reports a write makes. A
7
7
  # file open for writing takes the type its name asks for, or SEQ on a
8
8
  # data channel. On a write-protected disk, or storage that doesn't
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "badline/kernal_trap/drive/block_commands"
4
- require "badline/kernal_trap/drive/channels"
5
- require "badline/kernal_trap/drive/memory"
6
- require "badline/kernal_trap/drive/parameters"
7
- require "badline/kernal_trap/drive/status"
8
- require "badline/kernal_trap/drive/writes"
9
- require "badline/kernal_trap/drive/write_file"
3
+ require "badline/kernal_trap/dos/block_commands"
4
+ require "badline/kernal_trap/dos/channel"
5
+ require "badline/kernal_trap/dos/channels"
6
+ require "badline/kernal_trap/dos/memory"
7
+ require "badline/kernal_trap/dos/parameters"
8
+ require "badline/kernal_trap/dos/status"
9
+ require "badline/kernal_trap/dos/writes"
10
+ require "badline/kernal_trap/dos/write_file"
10
11
 
11
12
  module Badline
12
13
  module KernalTrap
@@ -16,7 +17,7 @@ module Badline
16
17
  # LOAD. A disk image whose host file takes writes takes files, blocks
17
18
  # and BAM changes too. Other disks are write-protected, though storage
18
19
  # that can write files still takes a SAVE handed over whole.
19
- class Drive
20
+ class DOS
20
21
  include BlockCommands
21
22
  include Writes
22
23
 
@@ -146,10 +147,10 @@ module Badline
146
147
  # vector, as U: does.
147
148
  def reset! = reset(cold: true)
148
149
 
149
- # The mounted storage's setup, for Storage.reopen, then the drive's
150
+ # The mounted storage's setup (Snapshot::StorageSetup), then the drive's
150
151
  # RAM, its status and its open channels.
151
152
  def save_state(out)
152
- @storage.save_setup(out)
153
+ Snapshot::StorageSetup.write(@storage, out)
153
154
  out.marker("TRAP DRIVE")
154
155
  @memory.save_state(out)
155
156
  @status.save_state(out)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Badline
4
4
  module KernalTrap
5
- class File < Routine
5
+ class FileRoutine < Routine
6
6
  private
7
7
 
8
8
  def active?
@@ -12,7 +12,7 @@ module Badline
12
12
  # below $0334, into the zero page, the stack or the KERNAL vectors: the
13
13
  # ROM's byte loop then loads it through the serial traps, and a loader
14
14
  # that overwrites ISTOP takes over mid-load as it does on a real drive.
15
- class Load < File
15
+ class Load < FileRoutine
16
16
  # ST bits at $90
17
17
  EOI = 0x40
18
18
  VERIFY_MISMATCH = 0x10
@@ -23,9 +23,9 @@ module Badline
23
23
  # address even when the first one relocated.
24
24
  LOAD_SECONDARY = 0x60
25
25
 
26
- def initialize(cpu:, bus:, layout:, drive:)
26
+ def initialize(cpu:, bus:, layout:, dos:)
27
27
  super(cpu:, bus:, layout:)
28
- @drive = drive
28
+ @dos = dos
29
29
  end
30
30
 
31
31
  def call
@@ -38,7 +38,7 @@ module Badline
38
38
 
39
39
  data, complete = receive(name)
40
40
  if low_memory?(data)
41
- @drive.close(0)
41
+ @dos.close(0)
42
42
  else
43
43
  finish(data, complete)
44
44
  end
@@ -50,10 +50,10 @@ module Badline
50
50
  # flagged EOI. A read error in the file's chain stops the bytes early,
51
51
  # with no EOI.
52
52
  def receive(name)
53
- @drive.open(0, name)
53
+ @dos.open(0, name)
54
54
  data = []
55
55
  loop do
56
- byte, eoi = @drive.read(0)
56
+ byte, eoi = @dos.read(0)
57
57
  return [data, false] unless byte
58
58
 
59
59
  data << byte
@@ -15,15 +15,15 @@ module Badline
15
15
  # write: the drive stops listening, so ST reads DEVICE NOT PRESENT,
16
16
  # and the ROM returns without an error. A "@" before the drive prefix
17
17
  # writes over a file of the same name.
18
- class Save < File
18
+ class Save < FileRoutine
19
19
  SECONDARY = 0x61
20
20
 
21
21
  # ST bit at $90
22
22
  DEVICE_NOT_PRESENT = 0x80
23
23
 
24
- def initialize(cpu:, bus:, layout:, drive:)
24
+ def initialize(cpu:, bus:, layout:, dos:)
25
25
  super(cpu:, bus:, layout:)
26
- @drive = drive
26
+ @dos = dos
27
27
  @saving = false
28
28
  end
29
29
 
@@ -38,7 +38,7 @@ module Badline
38
38
  def call
39
39
  return unless active?
40
40
  return finish if @saving
41
- return unless @drive.saves?
41
+ return unless @dos.saves?
42
42
 
43
43
  @bus.poke(0xb9, SECONDARY)
44
44
  return @cpu.program_counter = @layout.missing_file_name_exit if name.empty?
@@ -56,7 +56,7 @@ module Badline
56
56
 
57
57
  def finish
58
58
  @saving = false
59
- saved = @drive.save(name, payload, replace: full_filename.start_with?("@"))
59
+ saved = @dos.save(name, payload, replace: full_filename.start_with?("@"))
60
60
  @bus.poke(0x90, DEVICE_NOT_PRESENT) unless saved
61
61
  @bus.poke(0xac, @bus.peek(0xae))
62
62
  @bus.poke(0xad, @bus.peek(0xaf))
@@ -23,9 +23,9 @@ module Badline
23
23
 
24
24
  NO_DATA = [0x0d, EOI | READ_TIMEOUT].freeze
25
25
 
26
- def initialize(cpu:, bus:, layout:, drive:, device: DEVICE)
26
+ def initialize(cpu:, bus:, layout:, dos:, device: DEVICE)
27
27
  super(cpu:, bus:, layout:)
28
- @drive = drive
28
+ @dos = dos
29
29
  @device = device
30
30
  @listening = false
31
31
  @talking = false
@@ -144,7 +144,7 @@ module Badline
144
144
  # takes data only on a channel it has open. Otherwise nothing holds
145
145
  # the data line when a byte starts, so the KERNAL finds no device.
146
146
  def accepted?
147
- [OPEN, CLOSE].include?(@frame) || @drive.listening?(@listen_channel)
147
+ [OPEN, CLOSE].include?(@frame) || @dos.listening?(@listen_channel)
148
148
  end
149
149
 
150
150
  def unlisten
@@ -188,15 +188,15 @@ module Badline
188
188
  return unless @listen_channel
189
189
 
190
190
  case @frame
191
- when OPEN then @drive.open(@listen_channel, @buffer.pack("C*"))
192
- when CLOSE then @drive.close(@listen_channel)
193
- else @drive.write(@listen_channel, @buffer)
191
+ when OPEN then @dos.open(@listen_channel, @buffer.pack("C*"))
192
+ when CLOSE then @dos.close(@listen_channel)
193
+ else @dos.write(@listen_channel, @buffer)
194
194
  end
195
195
  @buffer = []
196
196
  end
197
197
 
198
198
  def received
199
- byte, eoi = @drive.read(@talk_channel)
199
+ byte, eoi = @dos.read(@talk_channel)
200
200
  return NO_DATA unless byte
201
201
 
202
202
  [byte, eoi ? EOI : 0]
@@ -2,9 +2,8 @@
2
2
 
3
3
  require "badline/kernal_trap/layout"
4
4
  require "badline/kernal_trap/routine"
5
- require "badline/kernal_trap/channel"
6
- require "badline/kernal_trap/drive"
7
- require "badline/kernal_trap/file"
5
+ require "badline/kernal_trap/dos"
6
+ require "badline/kernal_trap/file_routine"
8
7
  require "badline/kernal_trap/load"
9
8
  require "badline/kernal_trap/save"
10
9
  require "badline/kernal_trap/serial"
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Machine
5
+ # Running a machine from outside its own #cycle!, and the handlers that
6
+ # wait for its KERNAL to boot. C64, Vic20 and C128 each include it
7
+ # and answer #cycle!, #cycles and #init_threshold, the cycle at which
8
+ # #on_init's handlers run, and keep the handlers in @init_handlers.
9
+ module Clocking
10
+ # Runs `count` cycles, one #cycle! after another.
11
+ def run_cycles(count)
12
+ i = 0
13
+ while i < count
14
+ cycle!
15
+ i += 1
16
+ end
17
+ end
18
+
19
+ # Runs cycles until the block returns true or the cycle count passes
20
+ # `limit`, checking before each cycle.
21
+ def run_until(limit)
22
+ cycle! until yield || @cycles > limit
23
+ end
24
+
25
+ # Runs the block once the KERNAL has booted (see init_threshold), or
26
+ # now if it has.
27
+ def on_init(&block)
28
+ if booting?
29
+ @init_handlers << block
30
+ else
31
+ block.call
32
+ end
33
+ end
34
+
35
+ def inspect
36
+ "#<#{self.class.name} cycles=#{@cycles} cpu=(#{@cpu.inspect})>"
37
+ end
38
+
39
+ private
40
+
41
+ def booting?
42
+ @cycles < init_threshold
43
+ end
44
+
45
+ def handle_init
46
+ @init_handlers.each(&:call)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "badline/machine/clocking"
4
+
3
5
  module Badline
4
6
  # = Machine
5
7
  #
6
8
  # The machines badline builds by family, as the command line's
7
- # subcommand names them: the C64, Computer, the VIC-20, Vic20, and the
9
+ # subcommand names them: the C64, Badline::C64, the VIC-20, Vic20, and the
8
10
  # C128 in C64 mode, C128.
9
11
  #
10
12
  # A machine answers what the front end, Media, the runners and the
@@ -26,7 +28,7 @@ module Badline
26
28
  # +press_cartridge_button+, +release_cartridge_button+,
27
29
  # +attach_drive1541+, +drive1541+, +true_drive+ and +plug_true_drive+
28
30
  # for the drive Media::TrueDrive plugs in, +attach_drive1581+,
29
- # +drive1581+ and +plug_drive1581+ for a 1581 (Drive1581::Slot), and
31
+ # +drive1581+ and +plug_drive1581+ for a 1581 (Drives::Model1581::Slot), and
30
32
  # +address_bus+ for its +cartridge+ and +detach_cartridge+.
31
33
  # - Snapshots and tests: +snapshot+, +restore+, +save_snapshot+,
32
34
  # +install_debug_register+ and +capture_output+.
@@ -44,22 +46,48 @@ module Badline
44
46
  # +press_caps_lock+, +release_caps_lock+, +press_display_key+,
45
47
  # +release_display_key+, and +attach_drive1571+ and +drive1571+ for the
46
48
  # C128D's 1571, its true drive.
49
+ #
50
+ # Each machine includes Machine::Clocking for the clocking part.
47
51
  module Machine
52
+ # Media the machine named doesn't take.
53
+ class Unsupported < ArgumentError; end
54
+
48
55
  # A new machine of `family`, :c64, :vic20 or :c128, the model of it
49
56
  # `model` names. A C64's model is one of Model::ALL, with its SID
50
57
  # `sid_model` when not nil and an REU of `reu` K when not nil. A
51
58
  # VIC-20's is "pal", with the RAM expansion `ram` names
52
59
  # (Vic20::Bus::RAM_CONFIGURATIONS), unexpanded when nil. A C128's is
53
- # one of C128::Model::ALL, with its SID `sid_model` when not nil.
60
+ # one of C128::Model::ALL, with its SID `sid_model` when not nil, built
61
+ # for C64 mode.
54
62
  def self.build(family, model:, sid_model: nil, reu: nil, ram: nil)
55
63
  return vic20(model, ram) if family == :vic20
56
- return C128.new(model:, sid_model:) if family == :c128
64
+ return c128(model, sid_model, :c64) if family == :c128
57
65
  raise ArgumentError, "no machine family named #{family}" unless family == :c64
58
66
 
59
67
  profile = Model.named(model)
60
- Computer.new(vic_model: profile.vic_model, cia_model: profile.cia_model,
61
- sid_model: sid_model || profile.sid_model, region: profile.region, reu:,
62
- kernal: profile.kernal, datasette: profile.datasette, board: profile.board)
68
+ C64.new(vic_model: profile.vic_model, cia_model: profile.cia_model,
69
+ sid_model: sid_model || profile.sid_model, region: profile.region, reu:,
70
+ kernal: profile.kernal, datasette: profile.datasette, board: profile.board)
71
+ end
72
+
73
+ # The machine the command line's `options` name, to start `media`, a
74
+ # path or nil. A C64 or a C128 without a SID named takes the one a .sid
75
+ # tune names. The C128 is built for C128 mode, with C= held through the
76
+ # reset, so its KERNAL starts C64 mode, for --c64 (+c64_mode?+) or media
77
+ # only C64 mode runs: a .sid tune or a program that loads at the C64's
78
+ # BASIC start. A VIC-20 without RAM named gets the expansion the media
79
+ # needs (Media::Vic20Media.ram_for) and yields a line saying so. Raises
80
+ # Unsupported for media a VIC-20 doesn't take.
81
+ def self.for_options(options, media, &)
82
+ family = options.family
83
+ return vic20_for(media, options.model, options.ram, &) if family == :vic20
84
+
85
+ sid_model = options.sid_model || Media.sid_model(media, otherwise: nil)
86
+ return build(:c64, model: options.model, sid_model:, reu: options.reu) unless family == :c128
87
+
88
+ machine = c128(options.model, sid_model, :c128)
89
+ machine.hold_commodore_key if options.c64_mode? || c64_media?(media)
90
+ machine
63
91
  end
64
92
 
65
93
  def self.vic20(model, ram)
@@ -68,5 +96,33 @@ module Badline
68
96
  Vic20.new(ram: ram || :unexpanded)
69
97
  end
70
98
  private_class_method :vic20
99
+
100
+ def self.c128(model, sid_model, mode) = C128.new(model:, sid_model:, mode:)
101
+ private_class_method :c128
102
+
103
+ def self.vic20_for(media, model, ram)
104
+ unless media.nil?
105
+ unsupported = Media::Vic20Media::UNSUPPORTED.include?(File.extname(media).downcase)
106
+ raise Unsupported, "doesn't go in a VIC-20" if unsupported
107
+
108
+ unless ram
109
+ ram = Media::Vic20Media.ram_for(media)
110
+ yield "RAM expansion: #{ram}"
111
+ end
112
+ end
113
+ build(:vic20, model:, ram:)
114
+ end
115
+ private_class_method :vic20_for
116
+
117
+ def self.c64_media?(media)
118
+ return false if media.nil? || !File.file?(media)
119
+
120
+ extension = File.extname(media).downcase
121
+ return true if extension == ".sid"
122
+ return false unless %w[.prg .p00].include?(extension)
123
+
124
+ [Media::BASIC_START, Media::BASIC_START - 1].include?(Storage::P00.load_address(media))
125
+ end
126
+ private_class_method :c64_media?
71
127
  end
72
128
  end
@@ -15,7 +15,7 @@ module Badline
15
15
  module BootDisk
16
16
  SIGNATURE = "CBM".bytes.freeze
17
17
  AUTO_BOOT = "copyright cbm 86"
18
- TYPES = %w[.d64 .d71 .d81].freeze
18
+ TYPES = Extensions.of(%i[disk])
19
19
 
20
20
  class << self
21
21
  def takes?(computer, path)
@@ -38,7 +38,7 @@ module Badline
38
38
  type = File.extname(path).downcase
39
39
  return false unless TYPES.include?(type) && File.file?(path)
40
40
 
41
- image = MOUNT_TYPES.fetch(type).new(path, read_only: true)
41
+ image = Media.open_storage(path, { read_only: true })
42
42
  block = image.read_block(1, 0)
43
43
  return true if block && block[0, 3] == SIGNATURE
44
44
 
@@ -11,9 +11,9 @@ module Badline
11
11
  # A list naming no disk image that's there.
12
12
  class Error < ArgumentError; end
13
13
 
14
- EXTENSIONS = %w[.m3u .vfl].freeze
14
+ EXTENSIONS = Extensions.of(%i[disk_list])
15
15
 
16
- def self.list?(path) = EXTENSIONS.include?(File.extname(path).downcase)
16
+ def self.list?(path) = Extensions.kind(path) == :disk_list
17
17
 
18
18
  # The disk `path` puts in the drive: a list's first disk, or the
19
19
  # path itself.
@@ -32,7 +32,7 @@ module Badline
32
32
  found = []
33
33
  entries(list).each do |entry|
34
34
  disk = entry.start_with?("/") ? entry : File.join(directory, entry)
35
- found << disk if DiskSet::EXTENSIONS.include?(File.extname(disk).downcase) && File.file?(disk)
35
+ found << disk if Extensions::DISKS.include?(File.extname(disk).downcase) && File.file?(disk)
36
36
  end
37
37
  found
38
38
  end
@@ -13,7 +13,7 @@ module Badline
13
13
  # ahead of the names.
14
14
  module DiskSet
15
15
  KINDS = %w[disk disc side part].freeze
16
- EXTENSIONS = %w[.d64 .d71 .d81 .g64].freeze
16
+ EXTENSIONS = Extensions::DISKS
17
17
 
18
18
  # The paths of the set's disks in order, or just `path` when it
19
19
  # belongs to none. A list's set is the disks it lists.
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Media
5
+ # The kind of medium each file extension names, which every check of a
6
+ # path's extension reads. A file with any other extension is a program.
7
+ # It loads on its own, for Options.
8
+ #
9
+ # - :disk, a disk image that the traps mount and a true drive reads
10
+ # - :gcr, a disk's raw GCR, which only a true drive reads
11
+ # - :archive, a .t64, which the traps mount read-only
12
+ # - :tape, :cartridge and :tune
13
+ # - :disk_list, a list of the disks of a set (DiskList)
14
+ module Extensions
15
+ KINDS = {
16
+ ".d64" => :disk, ".d71" => :disk, ".d81" => :disk, ".g64" => :gcr, ".g71" => :gcr, ".t64" => :archive,
17
+ ".tap" => :tape, ".crt" => :cartridge, ".sid" => :tune, ".m3u" => :disk_list, ".vfl" => :disk_list
18
+ }.freeze
19
+
20
+ # The kind of the medium at `path`, by its extension.
21
+ def self.kind(path) = KINDS.fetch(File.extname(path).downcase, :program)
22
+
23
+ # The extensions of the kinds given.
24
+ def self.of(kinds) = KINDS.keys.select { |extension| kinds.include?(KINDS[extension]) }.freeze
25
+
26
+ # Disk images, which a drive reads.
27
+ DISKS = of(%i[disk gcr])
28
+
29
+ # What goes in device 8 through the traps.
30
+ MOUNTABLE = of(%i[disk archive])
31
+ end
32
+ end
33
+ end