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,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1581
6
+ class WD1772
7
+ # The type III commands that take a whole turn, from one index pulse
8
+ # to the next:
9
+ #
10
+ # 11100hE00 read track every byte under the head (Track#raw)
11
+ # 11110hEP0 write track every byte the CPU sends, for a format
12
+ #
13
+ # Write track asks for its first byte at once and starts at the index
14
+ # pulse, giving up with LOST_DATA if the byte hasn't come three bytes
15
+ # later. $F5 writes a sync mark, an $A1, and the first of a run starts
16
+ # the CRC over; $F6 writes $C2; $F7 writes the CRC's two bytes. At
17
+ # the next index pulse the track under the head becomes the fields
18
+ # found in what went down (Track.parse).
19
+ module Tracks
20
+ LATE = 3
21
+
22
+ private
23
+
24
+ def start_type3
25
+ @type1 = false
26
+ @status = 0
27
+ @drq = false
28
+ @mode = @command.anybits?(0x10) ? WRITE : READ
29
+ resume_track unless spinning_up?(TRACK_INDEX)
30
+ end
31
+
32
+ def resume_track
33
+ if @mode == WRITE
34
+ if @mechanism.write_protected?
35
+ @status |= PROTECTED
36
+ return finish
37
+ end
38
+ @drq = true
39
+ end
40
+ @phase = @mode == WRITE ? WRITE_TRACK_START : TRACK_INDEX
41
+ return wait_index(@phase) if @command.nobits?(SETTLE_DELAY)
42
+
43
+ @due = @now + SETTLE
44
+ @settling = true
45
+ end
46
+
47
+ def wait_index(phase)
48
+ @settling = false
49
+ @phase = phase
50
+ @due = next_index
51
+ end
52
+
53
+ def track_index
54
+ return wait_index(TRACK_INDEX) if @settling
55
+
56
+ @bytes = (@mechanism.track || Track.new([])).raw
57
+ @index = 0
58
+ @phase = READ_TRACK
59
+ @due = @now + BYTE
60
+ end
61
+
62
+ def track_byte_read
63
+ @status |= LOST_DATA if @drq
64
+ @data = @bytes[@index]
65
+ @drq = true
66
+ @index += 1
67
+ @index == Track::LENGTH ? finish : @due += BYTE
68
+ end
69
+
70
+ def write_track_start
71
+ return wait_index(WRITE_TRACK_START) if @settling
72
+
73
+ @bytes = []
74
+ @syncs = []
75
+ @crc = 0xffff
76
+ @phase = WRITE_TRACK
77
+ return track_byte_written unless @drq
78
+
79
+ @late = true
80
+ @due = @now + (LATE * BYTE)
81
+ end
82
+
83
+ # The next byte from the data register goes under the head, a 0
84
+ # where DRQ went unanswered.
85
+ def track_byte_written
86
+ return lost if @late && @drq
87
+ return track_written if @bytes.length >= Track::LENGTH
88
+
89
+ @late = false
90
+ value = @drq ? 0 : @data
91
+ @status |= LOST_DATA if @drq
92
+ @drq = true
93
+ before = @bytes.length
94
+ lay_byte(value)
95
+ @due = @now + ((@bytes.length - before) * BYTE)
96
+ end
97
+
98
+ def lay_byte(value)
99
+ case value
100
+ when 0xf5
101
+ @crc = 0xffff unless @syncs.last
102
+ push_byte(Track::SYNC, true)
103
+ when 0xf6 then push_byte(0xc2, false)
104
+ when 0xf7
105
+ crc = @crc
106
+ push_byte(crc >> 8, false)
107
+ push_byte(crc & 0xff, false)
108
+ else push_byte(value, false)
109
+ end
110
+ end
111
+
112
+ def push_byte(value, sync)
113
+ @bytes << value
114
+ @syncs << sync
115
+ @crc = Track.crc([value], @crc)
116
+ end
117
+
118
+ def track_written
119
+ @drq = false
120
+ @mechanism.write(Track.parse(@bytes.first(Track::LENGTH), @syncs))
121
+ finish
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1581
6
+ class WD1772
7
+ # The disk turning under the head: the index pulses a phase waits
8
+ # for or counts, and the cycle the head comes to a place round the
9
+ # track.
10
+ module Turn
11
+ # The disk began or stopped turning: a phase waiting on the turn
12
+ # starts its wait again.
13
+ def spin_changed
14
+ case @phase
15
+ when SPIN_UP, MOTOR_IDLE, INDEX_INTERRUPT then count_index
16
+ when SEARCH then begin_search
17
+ when TRACK_INDEX, WRITE_TRACK_START then wait_index(@phase)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ # The motor starts: with h clear and the motor off, the command waits
24
+ # out six index pulses first, and the phase comes after them.
25
+ def spinning_up?(phase)
26
+ spin_up = !@motor_on && @command.nobits?(NO_SPIN_UP)
27
+ @motor_on = true
28
+ return false unless spin_up
29
+
30
+ @after_spin_up = phase
31
+ @phase = SPIN_UP
32
+ @count = 6
33
+ count_index
34
+ true
35
+ end
36
+
37
+ # Waits for @count index pulses, or for the disk to turn.
38
+ def count_index
39
+ @due = next_index
40
+ end
41
+
42
+ def index_counted
43
+ @count -= 1
44
+ return @due += Mechanism::REVOLUTION if @count.positive?
45
+
46
+ case @phase
47
+ when SPIN_UP then spun_up
48
+ when MOTOR_IDLE
49
+ @motor_on = false
50
+ idle
51
+ else
52
+ @intrq = true
53
+ idle
54
+ end
55
+ end
56
+
57
+ # The cycle the next index pulse starts, or NEVER while no disk turns.
58
+ def next_index = at_angle(0)
59
+
60
+ # The cycle the head next comes to +angle+, from the index.
61
+ def at_angle(angle)
62
+ return NEVER unless @mechanism.spinning?
63
+
64
+ delta = (angle - @mechanism.angle(@now)) % Mechanism::REVOLUTION
65
+ @now + (delta.zero? ? Mechanism::REVOLUTION : delta)
66
+ end
67
+
68
+ # The cycle the byte at +position+ round the track has passed under
69
+ # the head.
70
+ def byte_end(position) = at_angle(((position + 1) % Track::LENGTH) * BYTE)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,218 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/drives/model1581/wd1772/registers"
4
+ require "badline/drives/model1581/wd1772/turn"
5
+ require "badline/drives/model1581/wd1772/stepping"
6
+ require "badline/drives/model1581/wd1772/sectors"
7
+ require "badline/drives/model1581/wd1772/sector_writes"
8
+ require "badline/drives/model1581/wd1772/tracks"
9
+ require "badline/drives/model1581/wd1772/saved_state"
10
+
11
+ module Badline
12
+ module Drives
13
+ class Model1581
14
+ # The WD1772 floppy disk controller at $6000, as the WD177x data sheet
15
+ # describes it, working on the Mechanism's Track at sector level: it
16
+ # finds ID and data fields where they lie round the turn and moves
17
+ # their bytes at the MFM double-density rate, a byte every 32 µs, but
18
+ # keeps no flux or bitstream.
19
+ #
20
+ # $6000 status (read), command (write)
21
+ # $6001 track
22
+ # $6002 sector
23
+ # $6003 data
24
+ #
25
+ # It runs on the drive's clock, 2 MHz here, so the data sheet's times,
26
+ # given for 8 MHz on the chip's clock pin, come out as BYTE cycles a
27
+ # byte, STEP_RATES between steps and SETTLE for the head to settle.
28
+ #
29
+ # A command runs as a chain of phases, each due at a cycle (@due): a
30
+ # step, an index pulse, the end of a byte under the head. Between them
31
+ # nothing happens, so cycle! only counts. BUSY sets as the command is
32
+ # written, and the chip takes it up START cycles later, 16 µs, so a
33
+ # command with nothing to do, such as a seek to the track the head is
34
+ # on, still shows BUSY to the DOS, which polls for it before waiting
35
+ # for it to clear.
36
+ #
37
+ # The 1581 leaves INTRQ and DRQ unconnected and polls the status
38
+ # register instead (schematic sheet 2), but both are here (intrq?,
39
+ # drq?). Its DOS sets h in every command, so the motor spin-up wait
40
+ # never runs; the spindle follows the 8520's /MOTOR line instead.
41
+ class WD1772
42
+ include Registers
43
+ include Turn
44
+ include Stepping
45
+ include Sectors
46
+ include SectorWrites
47
+ include Tracks
48
+ include SavedState
49
+
50
+ BYTE = 64
51
+ START = 32
52
+ STEP_RATES = [12_000, 24_000, 4_000, 6_000].freeze
53
+ SETTLE = 30_000
54
+
55
+ NEVER = 1 << 60
56
+
57
+ # Status bits. Bits 1 and 2 report the index pulse and track 0 after
58
+ # a type I command, and DRQ and lost data after the others; bit 5
59
+ # reports spin-up after a type I command and a deleted data mark
60
+ # after a read.
61
+ BUSY = 0x01
62
+ INDEX = 0x02
63
+ DATA_REQUEST = 0x02
64
+ TRACK0 = 0x04
65
+ LOST_DATA = 0x04
66
+ CRC_ERROR = 0x08
67
+ NOT_FOUND = 0x10
68
+ SPUN_UP = 0x20
69
+ DELETED = 0x20
70
+ PROTECTED = 0x40
71
+ MOTOR_ON = 0x80
72
+
73
+ # Command flags.
74
+ NO_SPIN_UP = 0x08
75
+ VERIFY = 0x04
76
+ SETTLE_DELAY = 0x04
77
+ MULTIPLE = 0x10
78
+ UPDATE = 0x10
79
+ DELETED_MARK = 0x01
80
+
81
+ # Phases.
82
+ IDLE = 0
83
+ SPIN_UP = 1
84
+ STEPPED = 2
85
+ SETTLED = 3
86
+ SEARCH = 4
87
+ READ_DATA = 5
88
+ WRITE_GATE = 6
89
+ WRITE_DATA = 7
90
+ READ_TRACK = 8
91
+ TRACK_INDEX = 9
92
+ WRITE_TRACK = 10
93
+ MOTOR_IDLE = 11
94
+ INDEX_INTERRUPT = 12
95
+ SETTLE_SEARCH = 13
96
+ READ_ADDRESS = 14
97
+ WRITE_TRACK_START = 15
98
+ STARTING = 16
99
+
100
+ # What a search for an ID field is for.
101
+ READ = 0
102
+ WRITE = 1
103
+ ADDRESS = 2
104
+ VERIFY_TRACK = 3
105
+
106
+ attr_reader :now, :track, :sector, :data, :command
107
+
108
+ def initialize(mechanism)
109
+ @mechanism = mechanism
110
+ @now = 0
111
+ @due = NEVER
112
+ @phase = IDLE
113
+ reset!
114
+ end
115
+
116
+ # The MR line: the registers as the data sheet leaves them, $03 in
117
+ # the command register and 1 in the sector register, and no command
118
+ # running.
119
+ def reset!
120
+ @command = 0x03
121
+ @track = 0
122
+ @sector = 1
123
+ @data = 0
124
+ @status = 0
125
+ @type1 = true
126
+ @drq = false
127
+ @intrq = false
128
+ @motor_on = false
129
+ @inward = true
130
+ clear_command
131
+ idle
132
+ end
133
+
134
+ def cycle!
135
+ @now += 1
136
+ advance if @now == @due
137
+ end
138
+
139
+ # How many cycles can go by before the next phase is due.
140
+ def quiet_cycles = @due - @now - 1
141
+
142
+ # Runs +cycles+ cycles at once, as many as quiet_cycles allows.
143
+ def fast_forward(cycles)
144
+ @now += cycles
145
+ end
146
+
147
+ def busy? = @phase != IDLE && @phase != MOTOR_IDLE && @phase != INDEX_INTERRUPT
148
+
149
+ def drq? = @drq
150
+
151
+ def intrq? = @intrq
152
+
153
+ def motor_on? = @motor_on
154
+
155
+ private
156
+
157
+ # A command ends: INTRQ, and the motor turns off after nine more
158
+ # index pulses unless a command comes first.
159
+ def finish
160
+ @intrq = true
161
+ @phase = MOTOR_IDLE
162
+ @count = 9
163
+ count_index
164
+ end
165
+
166
+ # What a command keeps between its phases.
167
+ def clear_command
168
+ @steps = 0
169
+ @count = 0
170
+ @after_spin_up = IDLE
171
+ @mode = 0
172
+ @deadline = NEVER
173
+ @id_at = NEVER
174
+ @found = -1
175
+ @bytes = []
176
+ @syncs = []
177
+ @index = 0
178
+ @crc = 0xffff
179
+ @crc_good = true
180
+ @write_id = 0
181
+ @size = 0
182
+ @gate_open = false
183
+ @late = false
184
+ @settling = false
185
+ end
186
+
187
+ def idle
188
+ @phase = IDLE
189
+ @due = NEVER
190
+ end
191
+
192
+ def advance
193
+ case @phase
194
+ when STARTING then start_command
195
+ when SPIN_UP, MOTOR_IDLE, INDEX_INTERRUPT then index_counted
196
+ when STEPPED then step_done
197
+ when SETTLED then verify_track
198
+ when SETTLE_SEARCH then begin_search
199
+ when SEARCH then id_passed
200
+ when READ_DATA, READ_ADDRESS then byte_read
201
+ else advance_write
202
+ end
203
+ end
204
+
205
+ def advance_write
206
+ case @phase
207
+ when WRITE_GATE then write_gate
208
+ when WRITE_DATA then byte_written
209
+ when READ_TRACK then track_byte_read
210
+ when TRACK_INDEX then track_index
211
+ when WRITE_TRACK_START then write_track_start
212
+ when WRITE_TRACK then track_byte_written
213
+ end
214
+ end
215
+ end
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/drives/engine"
4
+ require "badline/drives/model1581/track"
5
+ require "badline/drives/model1581/track_bytes"
6
+ require "badline/drives/model1581/disk"
7
+ require "badline/drives/model1581/mechanism"
8
+ require "badline/drives/model1581/wd1772"
9
+ require "badline/drives/model1581/cpu"
10
+ require "badline/drives/model1581/serial_port"
11
+ require "badline/drives/model1581/bus"
12
+ require "badline/drives/model1581/saved_state"
13
+
14
+ module Badline
15
+ module Drives
16
+ # The 1581 3.5" disk drive: a 6502 at 2 MHz with 8 KB of RAM, an 8520
17
+ # for the serial bus and the mechanism's lines, a WD1772 for the MFM
18
+ # disk, and the DOS in 32 KB of ROM (1581 Service Manual). Drives::Engine::Core
19
+ # clocks it against the host.
20
+ #
21
+ # The 8520's port B faces the serial bus as VIA 1's does on the 1541,
22
+ # with the same bits, and ATN reaches its FLAG pin, so ATN going low
23
+ # interrupts the DOS. Its SP and CNT carry fast serial on DATA and SRQ,
24
+ # through buffers PB5 turns round (Drives::Engine::FastSerial), as the 1571's
25
+ # 6526 does. The ATN acknowledge differs: a NAND of ATN IN and
26
+ # ATN ACK pulls DATA, so DATA follows ATN only while ATN is asserted
27
+ # and PB4 is high, where the 1541's XOR pulls it whenever the two
28
+ # differ (Drives::SerialBus::DRIVE_ATN_GATED). Port A drives the motor, the side
29
+ # and the two LEDs, and reads the switches and the mechanism's /RDY and
30
+ # /DISK CHNG (SerialPort). Timer B interrupts every 10 ms for the
31
+ # controller code that runs the WD1772.
32
+ #
33
+ # The 8520 differs from the 6526 in its TOD, a 24-bit binary event
34
+ # counter where the 6526 keeps a BCD clock. The 1581 holds the TOD pin
35
+ # high when it carries a WD1772 (jumper J1 out), so the counter never
36
+ # counts, and the DOS's one use of it, writing $00 to the low byte and
37
+ # reading it back 20 µs later to tell a WD1770 from a WD1772, reads $00
38
+ # on either chip: the drive's CIA gets no TOD pulses (CIA's tod_hz).
39
+ class Model1581
40
+ include Engine::Core
41
+ include Engine::FastSerial
42
+ include SavedState
43
+
44
+ CLOCK_HZ = 2_000_000
45
+
46
+ # Where the DOS's idle loop starts over (see Drives::Engine::Idle).
47
+ IDLE_LOOP = 0xb105
48
+
49
+ # The host cycles, at about 1 MHz, by which a 1581 switched on with the
50
+ # machine has run its DOS's reset, the RAM test, the ROM checksum and
51
+ # the controller's half-second wait, and waits on the bus: 2.32 s,
52
+ # with a margin.
53
+ BOOT_CYCLES = 2_700_000
54
+
55
+ # The 8520's port A outputs.
56
+ SIDE = 0x01
57
+ MOTOR = 0x04
58
+ POWER_LED = 0x20
59
+ ACTIVITY_LED = 0x40
60
+
61
+ # Port B's ATN acknowledge, and the fast serial direction.
62
+ ATN_ACK = 0x10
63
+ FAST_SERIAL_OUT = 0x20
64
+
65
+ def cia
66
+ settle!
67
+ @cia
68
+ end
69
+
70
+ def fdc
71
+ settle!
72
+ @fdc
73
+ end
74
+
75
+ def model_name = "1581"
76
+
77
+ # +rom+ covers $8000-$FFFF, and defaults to the DOS image in the ROM
78
+ # path. +device+ is the number the switches on port A's PA3 and PA4
79
+ # set, 8 to 11.
80
+ def initialize(rom: nil, host_clock_hz: Model1541::CLOCK_HZ, device: 8, debug: false)
81
+ @device = device
82
+ @clock_hz = CLOCK_HZ
83
+ @mechanism = Mechanism.new
84
+ @fdc = WD1772.new(@mechanism)
85
+ @serial_port = SerialPort.new(@mechanism, device:)
86
+ @cia = Chips::CIA.new(start: 0x4000, peripheral: @serial_port, tod_hz: 0)
87
+ @bus = Bus.new(rom: rom || ROM.load("dos1581.rom", 0x8000), cia: @cia, fdc: @fdc, drive: self)
88
+ @cpu = CPU.new(@bus, debug:)
89
+ @idle_loop = IDLE_LOOP
90
+ @host_clock_hz = host_clock_hz
91
+ @phase = 0
92
+ @cycles = 0
93
+ @serial_bus = nil
94
+ @atn = false
95
+ @activity = false
96
+ @power = false
97
+ init_fast_serial
98
+ init_idle(debug)
99
+ ports_written
100
+ connect(SerialBus.new)
101
+ end
102
+
103
+ # The serial bus's RESET line reaches the CPU, the 8520 and the
104
+ # WD1772. RAM keeps its contents.
105
+ def reset!
106
+ settle!
107
+ @cia.reset!
108
+ @fdc.reset!
109
+ ports_written
110
+ @cpu.reset!
111
+ end
112
+
113
+ def insert(disk)
114
+ settle!
115
+ @mechanism.insert(disk, @fdc.now)
116
+ @fdc.spin_changed
117
+ end
118
+
119
+ # Puts in a Disk from the .d81 image at +path+, write-protected with
120
+ # `read_only`.
121
+ def insert_image(path, read_only: false)
122
+ insert(Disk.open(path, read_only:))
123
+ end
124
+
125
+ # Whether the activity LED is lit. The power LED stays lit, and
126
+ # flashes on an error.
127
+ def led_on? = @activity
128
+
129
+ def power_led_on? = @power
130
+
131
+ # The 8520's port B as it drives the serial bus, in VIA 1's bits, the
132
+ # ATN acknowledge turned round for the NAND that gates it, with the
133
+ # fast serial pins above it. It holds still while the drive sleeps, so
134
+ # reading it leaves the drive asleep.
135
+ def serial_output
136
+ lines = @cia.port_b_lines
137
+ output = (lines & (SerialBus::DRIVE_DATA_OUT | SerialBus::DRIVE_CLK_OUT)) | SerialBus::DRIVE_ATN_GATED |
138
+ @fast_output
139
+ lines.anybits?(ATN_ACK) ? output : output | SerialBus::DRIVE_ATNA
140
+ end
141
+
142
+ # The 8520's ports drive the motor, the side, the LEDs and the fast
143
+ # serial buffers: the drive follows them after every write to a port
144
+ # or direction register.
145
+ def ports_written
146
+ fast_serial_out = @cia.port_b_lines.anybits?(FAST_SERIAL_OUT)
147
+ turn_fast_serial(fast_serial_out) if fast_serial_out != @fast_serial_out
148
+ lines = @cia.port_a_lines
149
+ @mechanism.side = lines.anybits?(SIDE) ? 1 : 0
150
+ @activity = lines.anybits?(ACTIVITY_LED)
151
+ @power = lines.anybits?(POWER_LED)
152
+ motor = lines.nobits?(MOTOR)
153
+ return if motor == @mechanism.motor_on?
154
+
155
+ @mechanism.motor(motor, @fdc.now)
156
+ @fdc.spin_changed
157
+ end
158
+
159
+ private
160
+
161
+ # One drive cycle: ATN going low pulls FLAG, the WD1772 and the 8520
162
+ # clock ahead of the CPU, and the 8520 alone pulls IRQ.
163
+ def step
164
+ atn = @serial_port.atn_low?
165
+ if atn != @atn
166
+ @atn = atn
167
+ @cia.flag! if atn
168
+ end
169
+ @fdc.cycle!
170
+ @cia.cycle!
171
+ drive_fast_serial if @fast_serial_out
172
+ @cpu.irq = @cia.interrupted?
173
+ @cpu.cycle!
174
+ @cycles += 1
175
+ end
176
+
177
+ def hear_atn
178
+ @atn = @serial_port.atn_low?
179
+ end
180
+
181
+ # A pass of the idle loop reads and writes RAM alone, so it repeats
182
+ # while the 8520 pulls no IRQ, for as long as the 8520's counters and
183
+ # the WD1772's next phase leave room: until timer B's next interrupt
184
+ # for the controller code. Neither chip changes but by the clock, so
185
+ # only the CPU is compared.
186
+ def busy_for_pass? = @cia.interrupted?
187
+
188
+ def quiet_cycles = [@cia.quiet_cycles, @fdc.quiet_cycles].min
189
+
190
+ def idle_state = [*@cpu.idle_state, @bus.data, @atn]
191
+
192
+ def fast_forward_chips(cycles)
193
+ @cia.fast_forward(cycles)
194
+ @fdc.fast_forward(cycles)
195
+ end
196
+
197
+ # Every timer B interrupt reads the 8520, so no orbit (Drives::Engine::Orbit)
198
+ # comes round, and the drive keeps no anchors.
199
+ def anchor = nil
200
+
201
+ def counter_state(_touched) = []
202
+
203
+ def skip_chip_orbits(_cycles, _touched) = nil
204
+ end
205
+ end
206
+ end