badline 0.12.1 → 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 (505) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -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 +3 -3
  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} +1 -1
  17. data/lib/badline/c128/bus.rb +18 -17
  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 +14 -9
  27. data/lib/badline/{computer → c64}/attachments.rb +4 -6
  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/{computer → c64}/common.rb +2 -2
  73. data/lib/badline/{computer → c64}/kernal_traps.rb +18 -18
  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 +11 -11
  82. data/lib/badline/{computer.rb → c64.rb} +18 -13
  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 +26 -28
  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 +3 -3
  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/load.rb +5 -5
  262. data/lib/badline/kernal_trap/save.rb +4 -4
  263. data/lib/badline/kernal_trap/serial.rb +7 -7
  264. data/lib/badline/kernal_trap.rb +1 -2
  265. data/lib/badline/machine/clocking.rb +1 -1
  266. data/lib/badline/machine.rb +5 -5
  267. data/lib/badline/media/true_drive.rb +1 -1
  268. data/lib/badline/media/tune.rb +2 -2
  269. data/lib/badline/media.rb +3 -3
  270. data/lib/badline/model.rb +1 -1
  271. data/lib/badline/roms/README +6 -6
  272. data/lib/badline/sdl.rb +1 -0
  273. data/lib/badline/{storage/sid_file.rb → sid_tune/file.rb} +3 -3
  274. data/lib/badline/{storage → sid_tune}/hvsc.rb +7 -7
  275. data/lib/badline/{storage → sid_tune}/song_lengths.rb +2 -2
  276. data/lib/badline/{storage → sid_tune}/stil/credit.rb +1 -1
  277. data/lib/badline/{storage → sid_tune}/stil.rb +3 -3
  278. data/lib/badline/sid_tune.rb +6 -0
  279. data/lib/badline/snapshot/c128_setup.rb +43 -0
  280. data/lib/badline/snapshot/c64_setup.rb +79 -0
  281. data/lib/badline/snapshot/image.rb +5 -25
  282. data/lib/badline/snapshot/machine_state.rb +1 -1
  283. data/lib/badline/snapshot/setup.rb +22 -66
  284. data/lib/badline/snapshot/state.rb +8 -18
  285. data/lib/badline/snapshot/storage_setup.rb +68 -0
  286. data/lib/badline/snapshot/vic20_setup.rb +37 -0
  287. data/lib/badline/snapshot/vice/c64_mem.rb +1 -1
  288. data/lib/badline/snapshot/vice/restore.rb +1 -1
  289. data/lib/badline/snapshot/vice/reu1764.rb +1 -1
  290. data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
  291. data/lib/badline/snapshot/vice.rb +7 -5
  292. data/lib/badline/snapshot.rb +3 -4
  293. data/lib/badline/storage/d64_image.rb +0 -2
  294. data/lib/badline/storage/d71_image.rb +0 -2
  295. data/lib/badline/storage/d81_image.rb +0 -2
  296. data/lib/badline/storage/disk_image.rb +3 -6
  297. data/lib/badline/storage/g64_image.rb +2 -2
  298. data/lib/badline/storage/host_directory.rb +0 -5
  299. data/lib/badline/storage/t64.rb +2 -8
  300. data/lib/badline/storage/unavailable.rb +1 -1
  301. data/lib/badline/storage.rb +0 -37
  302. data/lib/badline/support/c128_checkpoint.rb +39 -0
  303. data/lib/badline/support/checkpoint.rb +108 -0
  304. data/lib/badline/support/vic20_checkpoint.rb +38 -0
  305. data/lib/badline/support.rb +5 -0
  306. data/lib/badline/version.rb +1 -1
  307. data/lib/badline/vic20/attachments.rb +5 -5
  308. data/lib/badline/vic20/bus/saved_state.rb +35 -0
  309. data/lib/badline/vic20/bus.rb +3 -25
  310. data/lib/badline/vic20/cpu.rb +1 -1
  311. data/lib/badline/vic20/port_wiring.rb +4 -4
  312. data/lib/badline/vic20/saved_state.rb +16 -30
  313. data/lib/badline/vic20/user_via_ports.rb +2 -2
  314. data/lib/badline/vic20.rb +19 -14
  315. metadata +245 -221
  316. data/lib/badline/address_bus/extra_sids.rb +0 -30
  317. data/lib/badline/address_bus/fittings.rb +0 -38
  318. data/lib/badline/address_bus/pla.rb +0 -147
  319. data/lib/badline/address_bus/roms.rb +0 -39
  320. data/lib/badline/address_bus/saved_state.rb +0 -66
  321. data/lib/badline/address_bus/sid_slots.rb +0 -42
  322. data/lib/badline/address_bus.rb +0 -216
  323. data/lib/badline/cartridge/action_replay.rb +0 -126
  324. data/lib/badline/cartridge/atomic_power.rb +0 -24
  325. data/lib/badline/cartridge/bank.rb +0 -81
  326. data/lib/badline/cartridge/comal80.rb +0 -50
  327. data/lib/badline/cartridge/dinamic.rb +0 -34
  328. data/lib/badline/cartridge/easy_flash.rb +0 -145
  329. data/lib/badline/cartridge/epyx_fastload.rb +0 -79
  330. data/lib/badline/cartridge/final_cartridge3.rb +0 -89
  331. data/lib/badline/cartridge/flash.rb +0 -306
  332. data/lib/badline/cartridge/freezer.rb +0 -33
  333. data/lib/badline/cartridge/fun_play.rb +0 -38
  334. data/lib/badline/cartridge/g_mod2.rb +0 -74
  335. data/lib/badline/cartridge/game_system.rb +0 -40
  336. data/lib/badline/cartridge/geo_ram.rb +0 -79
  337. data/lib/badline/cartridge/kcs_power.rb +0 -75
  338. data/lib/badline/cartridge/mach5.rb +0 -32
  339. data/lib/badline/cartridge/magic_desk.rb +0 -30
  340. data/lib/badline/cartridge/ocean.rb +0 -35
  341. data/lib/badline/cartridge/pagefox.rb +0 -68
  342. data/lib/badline/cartridge/retro_replay.rb +0 -320
  343. data/lib/badline/cartridge/rex_utility.rb +0 -29
  344. data/lib/badline/cartridge/rgcd.rb +0 -58
  345. data/lib/badline/cartridge/simons_basic.rb +0 -35
  346. data/lib/badline/cartridge/standard.rb +0 -15
  347. data/lib/badline/cartridge/super_games.rb +0 -48
  348. data/lib/badline/cartridge/westermann.rb +0 -30
  349. data/lib/badline/cartridge/zaxxon.rb +0 -66
  350. data/lib/badline/cartridge.rb +0 -303
  351. data/lib/badline/checkpoint.rb +0 -98
  352. data/lib/badline/cia/fast_forward.rb +0 -60
  353. data/lib/badline/cia/interrupt_register.rb +0 -143
  354. data/lib/badline/cia/serial.rb +0 -275
  355. data/lib/badline/cia/state.rb +0 -47
  356. data/lib/badline/cia/timer.rb +0 -206
  357. data/lib/badline/cia.rb +0 -279
  358. data/lib/badline/color_memory.rb +0 -25
  359. data/lib/badline/control_ports.rb +0 -76
  360. data/lib/badline/cpu/addressing.rb +0 -131
  361. data/lib/badline/cpu/boundary.rb +0 -54
  362. data/lib/badline/cpu/core.rb +0 -165
  363. data/lib/badline/cpu/microcode.rb +0 -177
  364. data/lib/badline/cpu/operations.rb +0 -88
  365. data/lib/badline/cpu/saved_state.rb +0 -115
  366. data/lib/badline/cpu/stack_operations.rb +0 -82
  367. data/lib/badline/cpu.rb +0 -10
  368. data/lib/badline/cpu_port.rb +0 -112
  369. data/lib/badline/datasette.rb +0 -161
  370. data/lib/badline/drive/core.rb +0 -147
  371. data/lib/badline/drive/fast_serial.rb +0 -73
  372. data/lib/badline/drive/idle.rb +0 -125
  373. data/lib/badline/drive/idle_cpu.rb +0 -28
  374. data/lib/badline/drive/orbit.rb +0 -79
  375. data/lib/badline/drive/serial_lines.rb +0 -73
  376. data/lib/badline/drive/sleep.rb +0 -112
  377. data/lib/badline/drive/vias.rb +0 -84
  378. data/lib/badline/drive/watch.rb +0 -150
  379. data/lib/badline/drive.rb +0 -11
  380. data/lib/badline/drive1541/bus.rb +0 -86
  381. data/lib/badline/drive1541/byte_ready.rb +0 -48
  382. data/lib/badline/drive1541/cpu.rb +0 -11
  383. data/lib/badline/drive1541/disk.rb +0 -315
  384. data/lib/badline/drive1541/disk_state.rb +0 -86
  385. data/lib/badline/drive1541/disk_via.rb +0 -36
  386. data/lib/badline/drive1541/gcr.rb +0 -57
  387. data/lib/badline/drive1541/mechanism.rb +0 -313
  388. data/lib/badline/drive1541/mechanism_state.rb +0 -68
  389. data/lib/badline/drive1541/rotation.rb +0 -121
  390. data/lib/badline/drive1541/sector_reader.rb +0 -76
  391. data/lib/badline/drive1541/serial_port.rb +0 -18
  392. data/lib/badline/drive1541/track.rb +0 -98
  393. data/lib/badline/drive1541.rb +0 -111
  394. data/lib/badline/drive1571/bus.rb +0 -111
  395. data/lib/badline/drive1571/cpu.rb +0 -11
  396. data/lib/badline/drive1571/serial_port.rb +0 -37
  397. data/lib/badline/drive1571/serial_via.rb +0 -25
  398. data/lib/badline/drive1571/wd1770.rb +0 -120
  399. data/lib/badline/drive1571.rb +0 -175
  400. data/lib/badline/drive1581/bus.rb +0 -137
  401. data/lib/badline/drive1581/cpu.rb +0 -11
  402. data/lib/badline/drive1581/disk.rb +0 -135
  403. data/lib/badline/drive1581/disk_state.rb +0 -87
  404. data/lib/badline/drive1581/mechanism.rb +0 -117
  405. data/lib/badline/drive1581/serial_port.rb +0 -52
  406. data/lib/badline/drive1581/slot.rb +0 -78
  407. data/lib/badline/drive1581/track.rb +0 -100
  408. data/lib/badline/drive1581/track_bytes.rb +0 -75
  409. data/lib/badline/drive1581/wd1772/registers.rb +0 -89
  410. data/lib/badline/drive1581/wd1772/sector_writes.rb +0 -73
  411. data/lib/badline/drive1581/wd1772/sectors.rb +0 -150
  412. data/lib/badline/drive1581/wd1772/state.rb +0 -66
  413. data/lib/badline/drive1581/wd1772/stepping.rb +0 -109
  414. data/lib/badline/drive1581/wd1772/tracks.rb +0 -125
  415. data/lib/badline/drive1581/wd1772/turn.rb +0 -73
  416. data/lib/badline/drive1581/wd1772.rb +0 -216
  417. data/lib/badline/drive1581.rb +0 -233
  418. data/lib/badline/iec_bus.rb +0 -159
  419. data/lib/badline/instruction.rb +0 -334
  420. data/lib/badline/instruction_set/arithmetic.rb +0 -114
  421. data/lib/badline/instruction_set/bitwise.rb +0 -126
  422. data/lib/badline/instruction_set/branch.rb +0 -79
  423. data/lib/badline/instruction_set/flag.rb +0 -63
  424. data/lib/badline/instruction_set/illegal.rb +0 -270
  425. data/lib/badline/instruction_set/inc_dec.rb +0 -69
  426. data/lib/badline/instruction_set/stack.rb +0 -52
  427. data/lib/badline/instruction_set/transfer.rb +0 -137
  428. data/lib/badline/instruction_set.rb +0 -55
  429. data/lib/badline/interrupts.rb +0 -104
  430. data/lib/badline/joystick.rb +0 -25
  431. data/lib/badline/kernal_trap/channel.rb +0 -181
  432. data/lib/badline/keyboard.rb +0 -112
  433. data/lib/badline/ram_expansion/banking.rb +0 -30
  434. data/lib/badline/ram_expansion/plus256k.rb +0 -54
  435. data/lib/badline/ram_expansion/plus60k.rb +0 -43
  436. data/lib/badline/ram_expansion/unexpanded.rb +0 -28
  437. data/lib/badline/ram_expansion.rb +0 -21
  438. data/lib/badline/reu/dma/saved_state.rb +0 -50
  439. data/lib/badline/reu/dma.rb +0 -273
  440. data/lib/badline/reu/ram.rb +0 -107
  441. data/lib/badline/reu/saved_state.rb +0 -80
  442. data/lib/badline/reu/trigger.rb +0 -32
  443. data/lib/badline/reu.rb +0 -289
  444. data/lib/badline/sid/catch_up.rb +0 -120
  445. data/lib/badline/sid/decimator.rb +0 -64
  446. data/lib/badline/sid/envelope/state.rb +0 -68
  447. data/lib/badline/sid/envelope.rb +0 -239
  448. data/lib/badline/sid/filter.rb +0 -263
  449. data/lib/badline/sid/voice.rb +0 -77
  450. data/lib/badline/sid/waveform/combined.rb +0 -126
  451. data/lib/badline/sid/waveform/fast_forward.rb +0 -105
  452. data/lib/badline/sid/waveform/noise_writeback.rb +0 -122
  453. data/lib/badline/sid/waveform/state.rb +0 -66
  454. data/lib/badline/sid/waveform.rb +0 -305
  455. data/lib/badline/sid.rb +0 -303
  456. data/lib/badline/time_of_day.rb +0 -228
  457. data/lib/badline/traps.rb +0 -19
  458. data/lib/badline/via/control_lines.rb +0 -122
  459. data/lib/badline/via/fast_forward.rb +0 -53
  460. data/lib/badline/via/interrupt_register.rb +0 -67
  461. data/lib/badline/via/shift_register.rb +0 -180
  462. data/lib/badline/via/state.rb +0 -42
  463. data/lib/badline/via/timer1.rb +0 -131
  464. data/lib/badline/via/timer2.rb +0 -133
  465. data/lib/badline/via.rb +0 -266
  466. data/lib/badline/vic/bank.rb +0 -133
  467. data/lib/badline/vic/border_mask.rb +0 -86
  468. data/lib/badline/vic/collisions.rb +0 -115
  469. data/lib/badline/vic/color_patches.rb +0 -47
  470. data/lib/badline/vic/display_state.rb +0 -185
  471. data/lib/badline/vic/graphics_mode.rb +0 -164
  472. data/lib/badline/vic/graphics_shifter.rb +0 -207
  473. data/lib/badline/vic/register_log.rb +0 -81
  474. data/lib/badline/vic/registers.rb +0 -195
  475. data/lib/badline/vic/sequencer.rb +0 -275
  476. data/lib/badline/vic/sequencer_output.rb +0 -116
  477. data/lib/badline/vic/sequencer_state.rb +0 -89
  478. data/lib/badline/vic/sprite/internal_bus.rb +0 -68
  479. data/lib/badline/vic/sprite/saved_state.rb +0 -64
  480. data/lib/badline/vic/sprite/shifter.rb +0 -146
  481. data/lib/badline/vic/sprite/timing.rb +0 -56
  482. data/lib/badline/vic/sprite.rb +0 -337
  483. data/lib/badline/vic/sprites.rb +0 -282
  484. data/lib/badline/vic/sprites_state.rb +0 -57
  485. data/lib/badline/vic.rb +0 -853
  486. data/lib/badline/vic20/sound/output.rb +0 -83
  487. data/lib/badline/vic20/sound.rb +0 -233
  488. data/lib/badline/z80/arithmetic.rb +0 -117
  489. data/lib/badline/z80/bit_page.rb +0 -55
  490. data/lib/badline/z80/block_io.rb +0 -58
  491. data/lib/badline/z80/block_transfers.rb +0 -59
  492. data/lib/badline/z80/bus_cycles.rb +0 -111
  493. data/lib/badline/z80/core.rb +0 -113
  494. data/lib/badline/z80/exchanges.rb +0 -50
  495. data/lib/badline/z80/extended_page.rb +0 -89
  496. data/lib/badline/z80/flags.rb +0 -37
  497. data/lib/badline/z80/interrupt_acceptance.rb +0 -46
  498. data/lib/badline/z80/jumps.rb +0 -82
  499. data/lib/badline/z80/loads.rb +0 -98
  500. data/lib/badline/z80/main_page.rb +0 -134
  501. data/lib/badline/z80/registers.rb +0 -120
  502. data/lib/badline/z80/saved_state.rb +0 -69
  503. data/lib/badline/z80/shifts.rb +0 -64
  504. data/lib/badline/z80.rb +0 -11
  505. /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