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,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1581
6
+ # The drive CPU's bus, as the 74LS139 decodes A13-A15 (1581 Service
7
+ # Manual, memory map and schematic sheet 1):
8
+ #
9
+ # $0000-$1FFF - 8 KB of RAM
10
+ # $2000-$3FFF - nothing: open bus
11
+ # $4000-$5FFF - the 8520, its sixteen registers mirrored
12
+ # $6000-$7FFF - the WD1772, its four registers mirrored
13
+ # $8000-$FFFF - the DOS ROM
14
+ #
15
+ # Writes to the ROM and to open bus go nowhere, and a read from open
16
+ # bus finds the last byte on the data bus, as on the 1541. A write to
17
+ # either of the 8520's ports or their direction registers moves the
18
+ # drive's lines (Drives::Model1581#ports_written).
19
+ #
20
+ # While Idle records a pass of the DOS's idle loop, the bus watches it
21
+ # (watch!): the RAM it reads and writes, and whether it touched the
22
+ # 8520 or the WD1772, either of which makes the pass volatile. While
23
+ # Idle looks for an orbit, the bus guards the drive (guard!), and any
24
+ # access to either chip taints it.
25
+ class Bus
26
+ include Addressable
27
+
28
+ attr_reader :ram, :rom, :cia, :fdc, :data, :volatile, :touched, :tainted, :touched_timers
29
+
30
+ def initialize(rom:, cia:, fdc:, drive:)
31
+ addressable_at(0, length: 2**16)
32
+ @ram = Memory.new([], length: 0x2000, start: 0)
33
+ @rom = rom
34
+ @cia = cia
35
+ @fdc = fdc
36
+ @drive = drive
37
+ @data = 0
38
+ @recording = @guarding = @watching = false
39
+ @volatile = @tainted = false
40
+ @touched = {}
41
+ @touched_timers = 0
42
+ end
43
+
44
+ # The last byte on the data bus and the RAM. What a watched stretch
45
+ # touched is Idle's, and a restored bus isn't watching.
46
+ def save_state(out)
47
+ out.int(@data)
48
+ @ram.save_state(out)
49
+ end
50
+
51
+ def load_state(input)
52
+ @data = input.int
53
+ @ram.load_state(input)
54
+ @watching = false
55
+ end
56
+
57
+ def peek(addr)
58
+ return @data = @rom.peek(addr) if addr >= 0x8000
59
+ return @data = chip_peek(addr) if addr >= 0x2000
60
+
61
+ touch(addr) if @recording
62
+ @data = @ram.peek(addr)
63
+ end
64
+
65
+ def poke(addr, value)
66
+ @data = value
67
+ return if addr >= 0x8000
68
+ return chip_poke(addr, value) if addr >= 0x2000
69
+
70
+ touch(addr) if @recording
71
+ @ram.poke(addr, value)
72
+ end
73
+
74
+ # Starts watching: see volatile and touched.
75
+ def watch!
76
+ @recording = true
77
+ @volatile = false
78
+ @touched = {}
79
+ watching!
80
+ end
81
+
82
+ def unwatch!
83
+ @recording = false
84
+ watching!
85
+ end
86
+
87
+ # Starts guarding: see tainted.
88
+ def guard!
89
+ @guarding = true
90
+ @tainted = false
91
+ watching!
92
+ end
93
+
94
+ private
95
+
96
+ def chip_peek(addr)
97
+ watch_chip if @watching
98
+ if addr >= 0x6000
99
+ @fdc.peek(addr & 0x03)
100
+ elsif addr >= 0x4000
101
+ @cia.peek(0x4000 | (addr & 0x0f))
102
+ else
103
+ @data
104
+ end
105
+ end
106
+
107
+ def chip_poke(addr, value)
108
+ watch_chip if @watching
109
+ if addr >= 0x6000
110
+ @fdc.poke(addr & 0x03, value)
111
+ elsif addr >= 0x4000
112
+ @cia.poke(0x4000 | (addr & 0x0f), value)
113
+ @drive.ports_written if addr.nobits?(0x0c)
114
+ end
115
+ end
116
+
117
+ def touch(addr)
118
+ @touched[addr] = @ram.peek(addr) unless @touched.key?(addr)
119
+ end
120
+
121
+ def watching!
122
+ @watching = @recording || @guarding
123
+ end
124
+
125
+ def watch_chip
126
+ if @recording
127
+ @volatile = true
128
+ @recording = false
129
+ end
130
+ if @guarding
131
+ @tainted = true
132
+ @guarding = false
133
+ end
134
+ watching!
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1581
6
+ # The drive's 6502, on the drive's Bus.
7
+ class CPU
8
+ include Badline::Chips::CPU::Core
9
+ include Engine::IdleCPU
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1581
6
+ class Disk
7
+ # Saving and restoring a Disk for a snapshot: the image by its path,
8
+ # and every track the head wrote since the disk went in, with those
9
+ # written since the last flush. The rest come from the image, read
10
+ # again from its host file where there still is one.
11
+ module SavedState
12
+ # The image's path, expanded, and whether it was opened read-only,
13
+ # for a disk from Disk.open. Nil for a disk made another way.
14
+ attr_reader :path, :read_only
15
+
16
+ # The disk a state from save_state describes: +current+ when it was
17
+ # opened from the same image the same way, and otherwise a disk for
18
+ # the image at the path the state names. Where no file is at that
19
+ # path, the disk has no image and is write-protected, and a
20
+ # detached reader always gets one without an image.
21
+ def self.load(input, current)
22
+ path = input.optional_string
23
+ read_only = input.boolean?
24
+ disk = current if current && !path.nil? && current.path == path && current.read_only == read_only
25
+ disk ||= fresh(path, read_only, input.detached?)
26
+ disk.load_tracks(input)
27
+ disk
28
+ end
29
+
30
+ def self.fresh(path, read_only, detached)
31
+ return Disk.new if path.nil? || detached
32
+ return Disk.new.opened(path, true) unless File.file?(path)
33
+
34
+ Disk.open(path, read_only:)
35
+ end
36
+
37
+ # Notes the image's path and how it was opened.
38
+ def opened(path, read_only)
39
+ @path = File.expand_path(path)
40
+ @read_only = read_only
41
+ self
42
+ end
43
+
44
+ def save_state(out)
45
+ out.optional_string(@path).boolean(@read_only)
46
+ changed = @changed.keys.sort
47
+ out.ints(changed)
48
+ changed.each { |index| save_track(@tracks[index], out) }
49
+ out.ints(@written.keys)
50
+ end
51
+
52
+ def load_tracks(input)
53
+ @changed.clear
54
+ input.ints.each do |index|
55
+ @tracks[index] = load_track(input)
56
+ @changed[index] = true
57
+ end
58
+ @written.clear
59
+ input.ints.each { |index| @written[index] = true }
60
+ end
61
+
62
+ private
63
+
64
+ def save_track(track, out)
65
+ out.int(track.sectors.length)
66
+ track.sectors.each do |sector|
67
+ save_field(sector.id, out)
68
+ out.boolean(!sector.data.nil?)
69
+ save_field(sector.data, out) if sector.data
70
+ end
71
+ end
72
+
73
+ def save_field(field, out)
74
+ out.int(field.mark).ints(field.bytes).boolean(field.good).boolean(field.deleted)
75
+ end
76
+
77
+ def load_track(input)
78
+ Track.new(Array.new(input.int) do
79
+ id = load_field(input)
80
+ Track::Sector.new(id, input.boolean? ? load_field(input) : nil)
81
+ end)
82
+ end
83
+
84
+ def load_field(input) = Track::Field.new(input.int, input.ints, input.boolean?, input.boolean?)
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/drives/model1581/disk/saved_state"
4
+
5
+ module Badline
6
+ module Drives
7
+ class Model1581
8
+ # A 3.5" double-sided disk as the WD1772 sees it: a Track on each side
9
+ # of 80 cylinders, or none where it was never formatted.
10
+ #
11
+ # A .d81 image holds the 1581 DOS's logical blocks in order, 40 of 256
12
+ # bytes on each logical track 1 to 80 (1581 Service Manual, format
13
+ # organization). Logical track t is cylinder t - 1, and the DOS puts
14
+ # its sectors 0 to 19 on side 0 and 20 to 39 on side 1, two to each
15
+ # 512-byte physical sector, numbered from 1. So physical sector s on
16
+ # side h of cylinder c holds logical sectors 20h + 2(s - 1) and the one
17
+ # after it, and every cylinder of the image is a standard Track
18
+ # (Track.standard) on both sides. A block the image's error table
19
+ # marks 20 or 21 loses its sector's ID field, 27 spoils the ID's CRC,
20
+ # 22 loses the data field and 23 spoils its CRC.
21
+ #
22
+ # The WD1772 writes into the tracks, and flush stores the standard
23
+ # sectors of each one written back in the image, which writes its host
24
+ # file. A track formatted another way stays on the disk alone. The disk
25
+ # is write-protected when the image won't take writes.
26
+ class Disk
27
+ include SavedState
28
+
29
+ CYLINDERS = 80
30
+ SIDES = 2
31
+
32
+ # Logical blocks a side of a cylinder holds.
33
+ SIDE_BLOCKS = 20
34
+
35
+ # A logical block's bytes, and how many a physical sector holds.
36
+ BLOCK_SIZE = 256
37
+ BLOCKS = Track::SECTOR_SIZE / BLOCK_SIZE
38
+
39
+ # A disk from the .d81 image at +path+. `read_only` opens the image
40
+ # write-protected.
41
+ def self.open(path, read_only: false)
42
+ new(Storage::D81Image.new(path, read_only:)).opened(path, read_only)
43
+ end
44
+
45
+ attr_reader :image
46
+
47
+ def initialize(image = nil)
48
+ @image = image
49
+ @tracks = Array.new(CYLINDERS * SIDES)
50
+ @written = {}
51
+ @changed = {}
52
+ @path = nil
53
+ @read_only = false
54
+ end
55
+
56
+ # The Track on +side+ of +cylinder+, or nil where there is none: past
57
+ # the image's cylinders, or on a disk without an image that the head
58
+ # never formatted.
59
+ def track(cylinder, side)
60
+ index = (cylinder * SIDES) + side
61
+ return @tracks[index] if @tracks[index] || !@image || cylinder >= CYLINDERS
62
+
63
+ @tracks[index] = image_track(cylinder, side)
64
+ end
65
+
66
+ # A write track laid +track+ down on +side+ of +cylinder+, or a write
67
+ # sector changed it.
68
+ def write(cylinder, side, track)
69
+ return if cylinder >= CYLINDERS
70
+
71
+ index = (cylinder * SIDES) + side
72
+ @tracks[index] = track
73
+ @written[index] = true
74
+ @changed[index] = true
75
+ end
76
+
77
+ # Whether the write-protect hole is open: the disk's image won't take
78
+ # writes, or a disk without an image was opened read-only.
79
+ def write_protected? = @image.nil? ? @read_only : !@image.writable?
80
+
81
+ # Whether any track was written since the last flush.
82
+ def written? = !@written.empty?
83
+
84
+ # Stores the standard sectors of each track written since the last
85
+ # flush in the image, all in one write to its host file.
86
+ def flush
87
+ written = @written.keys.sort
88
+ @written.clear
89
+ return if @image.nil? || written.empty?
90
+
91
+ @image.store_blocks(written.flat_map { |index| track_blocks(index / SIDES, index % SIDES) })
92
+ end
93
+
94
+ private
95
+
96
+ def image_track(cylinder, side)
97
+ track = Track.standard(cylinder, side) { |sector| physical_block(cylinder, side, sector) }
98
+ track.sectors.each { |sector| mark_errors(cylinder, side, sector) }
99
+ track.sectors.reject! { |sector| sector.id.nil? }
100
+ track
101
+ end
102
+
103
+ # The logical track and first sector physical sector +sector+ holds.
104
+ def logical(cylinder, side, sector) = [cylinder + 1, (side * SIDE_BLOCKS) + ((sector - 1) * BLOCKS)]
105
+
106
+ def physical_block(cylinder, side, sector)
107
+ track, first = logical(cylinder, side, sector)
108
+ Array.new(BLOCKS) { |i| @image.read_block(track, first + i) || [] }.flatten
109
+ end
110
+
111
+ def mark_errors(cylinder, side, sector)
112
+ track, first = logical(cylinder, side, sector.id.bytes[2])
113
+ errors = Array.new(BLOCKS) { |i| @image.block_error(track, first + i) }
114
+ sector.id.good = false if errors.include?(27)
115
+ sector.data.good = false if errors.include?(23)
116
+ sector.data = nil if errors.include?(22)
117
+ sector.id = nil if errors.include?(20) || errors.include?(21)
118
+ end
119
+
120
+ # [track, sector, data, nil] for DiskImage#store_blocks, for each
121
+ # logical block a standard sector of the track holds.
122
+ def track_blocks(cylinder, side)
123
+ track = @tracks[(cylinder * SIDES) + side]
124
+ Track::SECTORS.times.flat_map do |index|
125
+ data = track.sector([cylinder, side, index + 1, Track::SIZE_CODE])&.data
126
+ next [] unless data
127
+
128
+ logical_track, first = logical(cylinder, side, index + 1)
129
+ Array.new(BLOCKS) do |i|
130
+ [logical_track, first + i, data.bytes[i * BLOCK_SIZE, BLOCK_SIZE], nil]
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1581
6
+ # The 1581's 3.5" mechanism: the spindle motor, the head on one of
7
+ # its cylinders and sides, the index sensor, and the lines it reports
8
+ # on the drive connector (1581 Service Manual, schematic sheet 2).
9
+ #
10
+ # The motor runs while /MOTOR is low and turns a disk at 300 rpm, a
11
+ # turn every REVOLUTION drive cycles at 2 MHz. The index sensor pulses
12
+ # for INDEX_PULSE cycles at the start of each turn, which is where a
13
+ # Track's bytes start. /RDY is low while the motor turns a disk. The
14
+ # WD1772 steps the head, and /TR00 is low while it sits on cylinder 0.
15
+ # /WPRT is low while the disk's write-protect hole is open, or without
16
+ # a disk.
17
+ #
18
+ # /DISK CHNG goes low as a disk comes out, and at power-on, and goes
19
+ # high again at a step pulse with a disk in, as on any Shugart-style
20
+ # drive with a disk change line. The DOS steps in and out after
21
+ # spinning the motor up to find out whether a disk is in.
22
+ #
23
+ # Times are the WD1772's cycle count (WD1772#now), which the drive
24
+ # passes in: the angle under the head follows from how long the disk
25
+ # has turned.
26
+ class Mechanism
27
+ REVOLUTION = 400_000
28
+ INDEX_PULSE = 4_000
29
+ LAST_CYLINDER = 83
30
+
31
+ attr_reader :disk, :cylinder
32
+ attr_accessor :side
33
+
34
+ def initialize
35
+ @disk = nil
36
+ @cylinder = 0
37
+ @side = 0
38
+ @motor = false
39
+ @changed = true
40
+ @angle = 0
41
+ @since = 0
42
+ end
43
+
44
+ # Puts a Disk in, or with nil takes it out. Whatever was in is
45
+ # flushed first, and the disk change line goes low.
46
+ def insert(disk, now)
47
+ @angle = angle(now)
48
+ @since = now
49
+ flush
50
+ @disk = disk
51
+ @changed = true
52
+ end
53
+
54
+ def flush = @disk&.flush
55
+
56
+ def motor_on? = @motor
57
+
58
+ # Turns the motor on or off at +now+.
59
+ def motor(on, now)
60
+ @angle = angle(now)
61
+ @since = now
62
+ @motor = on
63
+ end
64
+
65
+ # Whether a disk turns.
66
+ def spinning? = @motor && !@disk.nil?
67
+
68
+ # How far into its turn the disk is at +now+, in cycles from the
69
+ # index.
70
+ def angle(now) = spinning? ? (@angle + now - @since) % REVOLUTION : @angle
71
+
72
+ def index?(now) = spinning? && angle(now) < INDEX_PULSE
73
+
74
+ def ready? = spinning?
75
+
76
+ def track0? = @cylinder.zero?
77
+
78
+ def disk_changed? = @changed
79
+
80
+ def write_protected? = @disk.nil? || @disk.write_protected?
81
+
82
+ # A step pulse, towards the hub with +inward+.
83
+ def step(inward)
84
+ @cylinder = (@cylinder + (inward ? 1 : -1)).clamp(0, LAST_CYLINDER)
85
+ @changed = false if @disk
86
+ end
87
+
88
+ # The Track under the head, or nil.
89
+ def track = @disk&.track(@cylinder, @side)
90
+
91
+ # Stores a track the WD1772 laid down under the head.
92
+ def write(track)
93
+ @disk&.write(@cylinder, @side, track)
94
+ end
95
+
96
+ # The disk (Disk#save_state) and the motor, the head and the turn.
97
+ def save_state(out)
98
+ out.boolean(!@disk.nil?)
99
+ @disk&.save_state(out)
100
+ out.int(@cylinder).int(@side).int(@angle).int(@since).boolean(@motor).boolean(@changed)
101
+ end
102
+
103
+ # Puts the state back, reusing the disk in when it's the one the state
104
+ # names (Disk::SavedState.load). A disk taken out is flushed.
105
+ def load_state(input)
106
+ disk = input.boolean? ? Disk::SavedState.load(input, @disk) : nil
107
+ flush unless disk.equal?(@disk)
108
+ @disk = disk
109
+ @cylinder = input.int
110
+ @side = input.int
111
+ @angle = input.int
112
+ @since = input.int
113
+ @motor = input.boolean?
114
+ @changed = input.boolean?
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1581
6
+ # The drive's state for a snapshot.
7
+ module SavedState
8
+ # The drive's whole state, as the 1541's (Drives::Model1541#save_state), with
9
+ # the 8520 and the WD1772 in place of the VIAs.
10
+ def save_state(out)
11
+ settle!
12
+ out.marker("DRIVE1581")
13
+ out.int(@phase).int(@cycles).boolean(@atn)
14
+ @serial_port.save_state(out)
15
+ @cia.save_state(out)
16
+ @fdc.save_state(out)
17
+ @bus.save_state(out)
18
+ @cpu.save_state(out)
19
+ @mechanism.save_state(out)
20
+ end
21
+
22
+ def load_state(input)
23
+ settle!
24
+ input.marker("DRIVE1581")
25
+ @phase = input.int
26
+ @cycles = input.int
27
+ @atn = input.boolean?
28
+ @serial_port.load_state(input)
29
+ @cia.load_state(input)
30
+ @fdc.load_state(input)
31
+ @bus.load_state(input)
32
+ @cpu.load_state(input)
33
+ @mechanism.load_state(input)
34
+ @fast_serial_out = @cia.port_b_lines.anybits?(FAST_SERIAL_OUT)
35
+ ports_written
36
+ push_fast_output(@fast_serial_out ? fast_pins : 0)
37
+ forget_orbits
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1581
6
+ # What the 8520's ports read from outside the chip (1581 Service
7
+ # Manual, schematic sheet 3; the DOS's I/O definitions):
8
+ #
9
+ # PA0 side select (out) PB0 DATA IN (in)
10
+ # PA1 /RDY from the mechanism PB1 DATA OUT (out)
11
+ # PA2 /MOTOR (out) PB2 CLK IN (in)
12
+ # PA3 device number switch 1 PB3 CLK OUT (out)
13
+ # PA4 device number switch 2 PB4 ATN ACK (out)
14
+ # PA5 power LED (out) PB5 fast serial direction (out)
15
+ # PA6 activity LED (out) PB6 /WPRT from the mechanism
16
+ # PA7 /DISK CHNG from the mech. PB7 ATN IN (in)
17
+ #
18
+ # DATA IN, CLK IN and ATN IN come through inverters, so a pulled line
19
+ # reads 1, as on the 1541 (Drives::Engine::SerialLines). A closed switch pulls
20
+ # its line low, and both closed make device 8. The ports' outputs
21
+ # read back as driven: the peripheral pulls only the inputs.
22
+ class SerialPort
23
+ include Engine::SerialLines
24
+
25
+ READY = 0x02
26
+ SWITCHES = 0x18
27
+ DISK_CHANGE = 0x80
28
+ PROTECT = 0x40
29
+
30
+ def initialize(mechanism, device: 8, bus: SerialBus.new)
31
+ @mechanism = mechanism
32
+ @switches = (0xff & ~SWITCHES) | (((device - 8) & 0x03) << 3)
33
+ init_serial_lines(device, bus)
34
+ end
35
+
36
+ def read_a(_port_a, _port_b)
37
+ value = @switches
38
+ value &= ~READY if @mechanism.ready?
39
+ value &= ~DISK_CHANGE if @mechanism.disk_changed?
40
+ value
41
+ end
42
+
43
+ def read_b(_port_a, _port_b)
44
+ low = @bus.low_lines(@host)
45
+ value = 0xff & ~(SERIAL_INPUTS | PROTECT)
46
+ value |= DATA_IN if low.anybits?(SerialBus::DATA)
47
+ value |= CLK_IN if low.anybits?(SerialBus::CLK)
48
+ value |= ATN_IN if low.anybits?(SerialBus::ATN)
49
+ @mechanism.write_protected? ? value : value | PROTECT
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1581
6
+ # A machine's place for a Drives::Model1581 on its serial bus, in a field of
7
+ # its own beside its other true drives, so none of them makes another's
8
+ # per-cycle call a union. The C64, the VIC-20 and the C128 include it,
9
+ # and run the drive from their cycle as they run a 1541.
10
+ #
11
+ # A 1581 reads only .d81 images and the others none, so a .d81 put in
12
+ # device 8 swaps the true drive there for a 1581, and any other disk
13
+ # swaps a 1581 back for the machine's own true drive
14
+ # (Media::TrueDrive).
15
+ module Slot
16
+ attr_reader :drive1581
17
+
18
+ # Plugs in a Drives::Model1581, which then runs alongside the machine on its
19
+ # own clock and talks to it over the serial bus, as a 1541 does.
20
+ def attach_drive1581(drive)
21
+ @iec_bus.detach(@drive1581) if @drive1581
22
+ drive.host_clock_hz = timing.clock_hz
23
+ @drive1581 = drive
24
+ drive.connect(@iec_bus)
25
+ @serial_trap&.device = serial_trap_device
26
+ drive1581_attached
27
+ end
28
+
29
+ # Unplugs the Drives::Model1581.
30
+ def detach_drive1581
31
+ return unless @drive1581
32
+
33
+ @iec_bus.detach(@drive1581)
34
+ @drive1581 = nil
35
+ @serial_trap&.device = serial_trap_device
36
+ end
37
+
38
+ # Plugs in a 1581 as device 8, in place of the true drive there, and
39
+ # returns it.
40
+ def plug_drive1581
41
+ unplug_device8
42
+ Model1581.new.tap { |drive| attach_drive1581(drive) }
43
+ end
44
+
45
+ private
46
+
47
+ # Unplugs the 1541 if it is device 8, for a 1581 to take its place.
48
+ def unplug_device8
49
+ detach_drive1541 if @drive1541&.device == KernalTrap::Routine::DEVICE
50
+ end
51
+
52
+ # What the machine does as a 1581 goes on its bus. The VIC-20 waits
53
+ # for its DOS to boot before typing.
54
+ def drive1581_attached = nil
55
+
56
+ # Whether the 1581 is device 8.
57
+ def drive1581_on_device8? = @drive1581&.device == KernalTrap::Routine::DEVICE
58
+
59
+ # The 1581 on the serial bus, with its device number.
60
+ def save_drive1581(out)
61
+ out.boolean(!@drive1581.nil?)
62
+ return unless @drive1581
63
+
64
+ out.int(@drive1581.device)
65
+ @drive1581.save_state(out)
66
+ end
67
+
68
+ def load_drive1581(input)
69
+ return detach_drive1581 unless input.boolean?
70
+
71
+ device = input.int
72
+ detach_drive1581 if @drive1581 && @drive1581.device != device
73
+ attach_drive1581(Model1581.new(device:)) unless @drive1581
74
+ @drive1581.load_state(input)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end