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,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1581
6
+ # One side of a cylinder as the WD1772 finds it: its sectors, each an
7
+ # ID field and a data field at a place round the turn, counted in
8
+ # bytes from the index pulse. The disk turns at 300 rpm and the bits
9
+ # pass at 250 kbit/s, so a turn is LENGTH bytes of 32 µs. The bytes
10
+ # between the fields, the gaps and the sync marks, are not kept: a
11
+ # read track lays them out again (raw).
12
+ #
13
+ # A standard track is the one the 1581 DOS formats (its format routine,
14
+ # and the 1581 Service Manual's per-sector organization): 32 bytes of
15
+ # $4E after the index, then ten 512-byte sectors numbered from 1, each
16
+ #
17
+ # 12 x $00, 3 x $A1, $FE, track, side, sector, size code, CRC,
18
+ # 22 x $4E, 12 x $00, 3 x $A1, $FB, 512 data bytes, CRC,
19
+ # 35 x $4E
20
+ #
21
+ # and $4E to the index. A write track lays down whatever the CPU sends,
22
+ # and parse finds its fields again.
23
+ class Track
24
+ LENGTH = 6250
25
+ GAP = 0x4e
26
+ SYNC = 0xa1
27
+ ID_MARK = 0xfe
28
+ DATA_MARK = 0xfb
29
+ DELETED_MARK = 0xf8
30
+
31
+ SECTORS = 10
32
+ SECTOR_SIZE = 512
33
+ SIZE_CODE = 2
34
+
35
+ # Where the first sector's ID mark lies, and how far apart the
36
+ # sectors are.
37
+ FIRST_ID = 32 + 15
38
+ SECTOR_SPACING = 574 + 35
39
+
40
+ # From an ID mark to its data mark.
41
+ DATA_OFFSET = 44
42
+
43
+ # How far after an ID field's CRC a data mark still belongs to it
44
+ # (WD177x data sheet).
45
+ DATA_MARK_WINDOW = 43
46
+
47
+ # An ID or data field: its mark's place, its bytes, whether its CRC
48
+ # reads back, and for a data field whether its mark is the deleted
49
+ # one.
50
+ Field = Struct.new(:mark, :bytes, :good, :deleted)
51
+
52
+ # A sector: its ID field and its data field, or nil where none
53
+ # follows the ID.
54
+ Sector = Struct.new(:id, :data)
55
+
56
+ # The CRC-CCITT the WD1772 writes after each field, over the field
57
+ # from its first $A1: x^16 + x^12 + x^5 + 1 from $FFFF.
58
+ def self.crc(bytes, crc = 0xffff)
59
+ bytes.each do |byte|
60
+ crc ^= byte << 8
61
+ 8.times { crc = crc.anybits?(0x8000) ? ((crc << 1) ^ 0x1021) & 0xffff : (crc << 1) & 0xffff }
62
+ end
63
+ crc
64
+ end
65
+
66
+ # A field's CRC as the two bytes written after it: the mark and
67
+ # +bytes+, behind three $A1s.
68
+ def self.field_crc(mark, bytes)
69
+ crc = crc([SYNC, SYNC, SYNC, mark] + bytes)
70
+ [crc >> 8, crc & 0xff]
71
+ end
72
+
73
+ # A standard track for +cylinder+ and +side+, each sector's data the
74
+ # block yields for its number, 1 to 10.
75
+ def self.standard(cylinder, side)
76
+ sectors = Array.new(SECTORS) do |index|
77
+ mark = FIRST_ID + (index * SECTOR_SPACING)
78
+ id = Field.new(mark, [cylinder, side, index + 1, SIZE_CODE], true, false)
79
+ Sector.new(id, Field.new(mark + DATA_OFFSET, yield(index + 1), true, false))
80
+ end
81
+ new(sectors)
82
+ end
83
+
84
+ attr_reader :sectors
85
+
86
+ def initialize(sectors)
87
+ @sectors = sectors
88
+ end
89
+
90
+ # The first sector whose ID mark lies at or after +position+, round
91
+ # from the index if none does, or nil on a track without IDs.
92
+ def next_id(position)
93
+ @sectors.find { |sector| sector.id.mark >= position } || @sectors.first
94
+ end
95
+
96
+ # The sector with the ID field +id+, track, side, sector and size
97
+ # code, or nil.
98
+ def sector(id) = @sectors.find { |sector| sector.id.bytes == id }
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1581
6
+ class Track
7
+ # A Track as the bytes going round under the head, for the WD1772's
8
+ # read track: its fields with their gaps and sync marks.
9
+ module Bytes
10
+ # The track's LENGTH bytes from the index: $4E gaps, and before each
11
+ # field 12 x $00 and three $A1 sync marks, its mark, its bytes and
12
+ # its CRC, spoiled where the field's CRC doesn't read back.
13
+ def raw
14
+ bytes = Array.new(LENGTH, GAP)
15
+ @sectors.each do |sector|
16
+ lay(bytes, sector.id, ID_MARK)
17
+ data = sector.data
18
+ lay(bytes, data, data.deleted ? DELETED_MARK : DATA_MARK) if data
19
+ end
20
+ bytes
21
+ end
22
+
23
+ private
24
+
25
+ def lay(bytes, field, mark)
26
+ start = field.mark - 15
27
+ crc = Track.field_crc(mark, field.bytes)
28
+ crc[1] ^= 0xff unless field.good
29
+ [*Array.new(12, 0), SYNC, SYNC, SYNC, mark, *field.bytes, *crc].each_with_index do |byte, i|
30
+ bytes[start + i] = byte if start + i < LENGTH
31
+ end
32
+ end
33
+ end
34
+
35
+ # Finding the fields in the bytes a write track laid down.
36
+ module Parse
37
+ # Every sector in +bytes+, a turn as a write track laid it down,
38
+ # where +syncs+ marks the $A1s written as sync marks: an ID mark
39
+ # behind three of them, its four bytes and CRC, and the data field
40
+ # that follows it within DATA_MARK_WINDOW bytes, its length from
41
+ # the ID's size code.
42
+ def parse(bytes, syncs)
43
+ sectors = []
44
+ position = 0
45
+ while (mark = find_mark(bytes, syncs, position...bytes.length, ID_MARK..ID_MARK))
46
+ id = read_field(bytes, mark, 4)
47
+ position = mark + 7
48
+ data_mark = find_mark(bytes, syncs, position...(position + DATA_MARK_WINDOW), DELETED_MARK..DATA_MARK)
49
+ sectors << Sector.new(id, data_mark && read_field(bytes, data_mark, 128 << (id.bytes[3] & 3)))
50
+ end
51
+ new(sectors)
52
+ end
53
+
54
+ private
55
+
56
+ # The first place in +range+ that holds one of +marks+ behind three
57
+ # sync marks.
58
+ def find_mark(bytes, syncs, range, marks)
59
+ ([range.first, 3].max...[range.end, bytes.length].min).find do |at|
60
+ marks.cover?(bytes[at]) && syncs[at - 1] && syncs[at - 2] && syncs[at - 3]
61
+ end
62
+ end
63
+
64
+ def read_field(bytes, mark, length)
65
+ field = bytes[mark + 1, length] || []
66
+ field += Array.new(length - field.length, 0)
67
+ crc = bytes[mark + 1 + length, 2] || []
68
+ Field.new(mark, field, crc == Track.field_crc(bytes[mark], field), bytes[mark] < 0xfa)
69
+ end
70
+ end
71
+
72
+ include Bytes
73
+ extend Parse
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1581
6
+ class WD1772
7
+ # The four registers as the CPU reaches them, and a command written
8
+ # to the command register.
9
+ module Registers
10
+ # Register +offset+, 0 to 3.
11
+ def peek(offset)
12
+ case offset
13
+ when 0 then status
14
+ when 1 then @track
15
+ when 2 then @sector
16
+ else read_data
17
+ end
18
+ end
19
+
20
+ def poke(offset, value)
21
+ case offset
22
+ when 0 then write_command(value)
23
+ when 1 then @track = value unless busy?
24
+ when 2 then @sector = value unless busy?
25
+ else write_data(value)
26
+ end
27
+ end
28
+
29
+ # The status register, which clears INTRQ: after a type I command
30
+ # bits 1, 2, 5 and 6 follow the index sensor, the track 0 sensor, the
31
+ # spin-up and the write-protect line as they are now.
32
+ def status
33
+ @intrq = false
34
+ value = @status | (@motor_on ? MOTOR_ON : 0) | (busy? ? BUSY : 0)
35
+ return value | (@drq ? DATA_REQUEST : 0) unless @type1
36
+
37
+ value |= PROTECTED if @mechanism.write_protected?
38
+ value |= TRACK0 if @mechanism.track0?
39
+ value | (@mechanism.index?(@now) ? INDEX : 0)
40
+ end
41
+
42
+ private
43
+
44
+ def read_data
45
+ @drq = false
46
+ @data
47
+ end
48
+
49
+ def write_data(value)
50
+ @drq = false
51
+ @data = value
52
+ end
53
+
54
+ # A command while busy goes nowhere, but for a force interrupt.
55
+ def write_command(value)
56
+ @intrq = false
57
+ return force_interrupt(value) if value & 0xf0 == 0xd0
58
+ return if busy?
59
+
60
+ @command = value
61
+ @phase = STARTING
62
+ @due = @now + START
63
+ end
64
+
65
+ def start_command
66
+ if @command < 0x80 then start_type1
67
+ elsif @command < 0xc0 then start_type2
68
+ elsif @command & 0xf0 == 0xc0 then start_read_address
69
+ else start_type3
70
+ end
71
+ end
72
+
73
+ # Stops a command where it is, leaving its status but for BUSY, or
74
+ # with none running switches the status to type I. I3 interrupts at
75
+ # once and I2 at the next index pulse.
76
+ def force_interrupt(value)
77
+ @type1 = true unless busy?
78
+ @drq = false
79
+ idle
80
+ @intrq = true if value.anybits?(0x08)
81
+ return unless value.anybits?(0x04)
82
+
83
+ @phase = INDEX_INTERRUPT
84
+ @count = 1
85
+ count_index
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1581
6
+ class WD1772
7
+ # Saving and restoring the WD1772 for a snapshot: its registers and
8
+ # lines, and the command running, down to the byte it is at.
9
+ module SavedState
10
+ def save_state(out)
11
+ [@now, @due, @phase, @command, @track, @sector, @data, @status, @steps, @count, @after_spin_up, @mode,
12
+ @deadline, @id_at, @found, @index, @crc, @write_id, @size].each { |value| out.int(value) }
13
+ [@type1, @drq, @intrq, @motor_on, @inward, @crc_good, @gate_open, @late,
14
+ @settling].each { |flag| out.boolean(flag) }
15
+ out.ints(@bytes).ints(@syncs.map { |sync| sync ? 1 : 0 })
16
+ end
17
+
18
+ def load_state(input)
19
+ load_registers(input)
20
+ load_command(input)
21
+ load_flags(input)
22
+ @bytes = input.ints
23
+ @syncs = input.ints.map { |sync| sync == 1 }
24
+ end
25
+
26
+ private
27
+
28
+ def load_registers(input)
29
+ @now = input.int
30
+ @due = input.int
31
+ @phase = input.int
32
+ @command = input.int
33
+ @track = input.int
34
+ @sector = input.int
35
+ @data = input.int
36
+ @status = input.int
37
+ end
38
+
39
+ def load_command(input)
40
+ @steps = input.int
41
+ @count = input.int
42
+ @after_spin_up = input.int
43
+ @mode = input.int
44
+ @deadline = input.int
45
+ @id_at = input.int
46
+ @found = input.int
47
+ @index = input.int
48
+ @crc = input.int
49
+ @write_id = input.int
50
+ @size = input.int
51
+ end
52
+
53
+ def load_flags(input)
54
+ @type1 = input.boolean?
55
+ @drq = input.boolean?
56
+ @intrq = input.boolean?
57
+ @motor_on = input.boolean?
58
+ @inward = input.boolean?
59
+ @crc_good = input.boolean?
60
+ @gate_open = input.boolean?
61
+ @late = input.boolean?
62
+ @settling = input.boolean?
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1581
6
+ class WD1772
7
+ # Write sector, once Sectors has found the ID: it asks for the first
8
+ # byte 2 bytes after the ID's CRC and gives up at 22 with LOST_DATA,
9
+ # then writes the data field where a format puts it, behind 12 x $00
10
+ # and three $A1s, its mark deleted with a, a byte of 0 for each one
11
+ # the CPU missed, and the CRC and a $FF after the last.
12
+ module SectorWrites
13
+ WRITE_REQUEST = 2
14
+ WRITE_DEADLINE = 22
15
+
16
+ private
17
+
18
+ def write_sector(sector)
19
+ @write_id = sector.id.mark
20
+ @size = 128 << (sector.id.bytes[3] & 0x03)
21
+ @gate_open = false
22
+ @phase = WRITE_GATE
23
+ @due = byte_end(@write_id + 6 + WRITE_REQUEST)
24
+ end
25
+
26
+ # Two bytes after the ID's CRC, DRQ asks for the first byte, and
27
+ # twenty bytes on it has to be there.
28
+ def write_gate
29
+ unless @gate_open
30
+ @gate_open = true
31
+ @drq = true
32
+ return @due += (WRITE_DEADLINE - WRITE_REQUEST) * BYTE
33
+ end
34
+ return lost if @drq
35
+
36
+ @bytes = []
37
+ @phase = WRITE_DATA
38
+ @due = byte_end(@write_id + Track::DATA_OFFSET)
39
+ end
40
+
41
+ # The next byte goes under the head from the data register, a 0
42
+ # where DRQ went unanswered, and DRQ asks for the one after it.
43
+ # After the last come the CRC and a $FF.
44
+ def byte_written
45
+ return sector_written if @bytes.length == @size
46
+
47
+ @status |= LOST_DATA if @drq && !@bytes.empty?
48
+ @bytes << (@drq && !@bytes.empty? ? 0 : @data)
49
+ @drq = @bytes.length < @size
50
+ @due += @bytes.length == @size ? 3 * BYTE : BYTE
51
+ end
52
+
53
+ def sector_written
54
+ sector = found
55
+ if sector
56
+ sector.data = Track::Field.new(@write_id + Track::DATA_OFFSET, @bytes, true,
57
+ @command.anybits?(DELETED_MARK))
58
+ @mechanism.write(@mechanism.track)
59
+ end
60
+ return finish if @command.nobits?(MULTIPLE)
61
+
62
+ @sector = (@sector + 1) & 0xff
63
+ begin_search
64
+ end
65
+
66
+ def lost
67
+ @status |= LOST_DATA
68
+ @drq = false
69
+ finish
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1581
6
+ class WD1772
7
+ # The type II commands and read address, which find an ID field on
8
+ # the track under the head:
9
+ #
10
+ # 100mhE00 read sector the data field after the ID that carries
11
+ # the track and sector registers
12
+ # 101mhEPa write sector a data field after that ID, deleted with a
13
+ # 11000hE00 read address the next ID field's six bytes, the track
14
+ # going into the sector register
15
+ #
16
+ # The search reads each ID field as it passes. One that matches but
17
+ # whose CRC doesn't read back sets CRC_ERROR and the search goes on;
18
+ # after five index pulses it gives up with NOT_FOUND. Each byte of a
19
+ # field passes in BYTE cycles and sets DRQ as it lands in the data
20
+ # register, and LOST_DATA where the last one was still unread. With m
21
+ # the command goes on to the next sector until one isn't found. E
22
+ # lets the head settle first. SectorWrites writes the data field.
23
+ module Sectors
24
+ private
25
+
26
+ def start_type2
27
+ start_search(@command < 0xa0 ? READ : WRITE)
28
+ end
29
+
30
+ def start_read_address
31
+ start_search(ADDRESS)
32
+ end
33
+
34
+ def start_search(mode)
35
+ @type1 = false
36
+ @status = 0
37
+ @drq = false
38
+ @mode = mode
39
+ resume_type2 unless spinning_up?(SEARCH)
40
+ end
41
+
42
+ def resume_type2
43
+ if @mode == WRITE && @mechanism.write_protected?
44
+ @status |= PROTECTED
45
+ return finish
46
+ end
47
+ return begin_search if @command.nobits?(SETTLE_DELAY)
48
+
49
+ @phase = SETTLE_SEARCH
50
+ @due = @now + SETTLE
51
+ end
52
+
53
+ # Searches for five index pulses from now.
54
+ def begin_search
55
+ index = next_index
56
+ @deadline = index == NEVER ? NEVER : index + (4 * Mechanism::REVOLUTION)
57
+ search
58
+ end
59
+
60
+ # Waits for the next ID field to pass under the head.
61
+ def search
62
+ @phase = SEARCH
63
+ track = @mechanism.track
64
+ sector = track&.next_id((@mechanism.angle(@now) / BYTE) + 1)
65
+ @found = sector ? track.sectors.index(sector) : -1
66
+ @id_at = sector ? byte_end(sector.id.mark) : NEVER
67
+ @due = [@id_at, @deadline].min
68
+ end
69
+
70
+ def found = @mechanism.track&.sectors&.[](@found)
71
+
72
+ def id_passed
73
+ return not_found unless @now == @id_at
74
+
75
+ sector = found
76
+ return search if sector.nil?
77
+
78
+ id = sector.id
79
+ return id_read(id) if @mode == ADDRESS
80
+ return search unless matches?(id.bytes)
81
+ return crc_mismatch unless id.good
82
+
83
+ @status &= ~CRC_ERROR
84
+ @mode == VERIFY_TRACK ? finish : sector_found(sector)
85
+ end
86
+
87
+ def matches?(id)
88
+ id[0] == @track && (@mode == VERIFY_TRACK || id[2] == @sector)
89
+ end
90
+
91
+ def crc_mismatch
92
+ @status |= CRC_ERROR
93
+ search
94
+ end
95
+
96
+ def not_found
97
+ @status |= NOT_FOUND
98
+ finish
99
+ end
100
+
101
+ def sector_found(sector)
102
+ return write_sector(sector) if @mode == WRITE
103
+
104
+ data = sector.data
105
+ return search if data.nil? || data.mark > sector.id.mark + 7 + Track::DATA_MARK_WINDOW
106
+
107
+ @status |= DELETED if data.deleted
108
+ transfer(data.bytes, data.mark, READ_DATA)
109
+ @crc_good = data.good
110
+ end
111
+
112
+ # Read address: the ID's bytes and its CRC.
113
+ def id_read(id)
114
+ @status |= CRC_ERROR unless id.good
115
+ transfer(id.bytes + Track.field_crc(Track::ID_MARK, id.bytes), id.mark, READ_ADDRESS)
116
+ end
117
+
118
+ def transfer(bytes, mark, phase)
119
+ @bytes = bytes
120
+ @index = 0
121
+ @phase = phase
122
+ @due = byte_end(mark + 1)
123
+ end
124
+
125
+ # A byte of the field lands in the data register. After the last,
126
+ # the CRC passes.
127
+ def byte_read
128
+ return field_read if @index == @bytes.length
129
+
130
+ @status |= LOST_DATA if @drq
131
+ @data = @bytes[@index]
132
+ @drq = true
133
+ @index += 1
134
+ @due += @index == @bytes.length && @phase == READ_DATA ? 2 * BYTE : BYTE
135
+ end
136
+
137
+ def field_read
138
+ if @phase == READ_ADDRESS
139
+ @sector = @bytes[0]
140
+ elsif !@crc_good
141
+ @status |= CRC_ERROR
142
+ elsif @command.anybits?(MULTIPLE)
143
+ @sector = (@sector + 1) & 0xff
144
+ return begin_search
145
+ end
146
+ finish
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1581
6
+ class WD1772
7
+ # The type I commands, which move the head:
8
+ #
9
+ # 0000hVrr restore step out to track 0, the track register to 0
10
+ # 0001hVrr seek step until the track register holds the data
11
+ # register's track
12
+ # 001uhVrr step one step the way the last one went
13
+ # 010uhVrr step in one step towards the hub
14
+ # 011uhVrr step out one step towards the rim
15
+ #
16
+ # Each step waits out the step rate rr picks (STEP_RATES), and u has
17
+ # a step update the track register, as restore and seek always do.
18
+ # With V the head settles and the command reads IDs until one carries
19
+ # the track register's track, or sets NOT_FOUND after five turns.
20
+ module Stepping
21
+ private
22
+
23
+ def start_type1
24
+ @type1 = true
25
+ @status = 0
26
+ @drq = false
27
+ @phase = STEPPED
28
+ @steps = 0
29
+ if @command < 0x10
30
+ @track = 0xff
31
+ @data = 0
32
+ elsif @command >= 0x40
33
+ @inward = @command < 0x60
34
+ end
35
+ step_done unless spinning_up?(STEPPED)
36
+ end
37
+
38
+ def spun_up
39
+ @status |= SPUN_UP
40
+ @phase = @after_spin_up
41
+ case @after_spin_up
42
+ when STEPPED then step_done
43
+ when SEARCH then resume_type2
44
+ else resume_track
45
+ end
46
+ end
47
+
48
+ # The step rate has passed: the next step, or the end of the moves.
49
+ def step_done
50
+ return next_step if @steps.zero? || @command < 0x20
51
+
52
+ moved
53
+ end
54
+
55
+ # Restore and seek step until the track register matches, restore
56
+ # also stopping at track 0. The others step once.
57
+ def next_step
58
+ return single_step if @command >= 0x20
59
+ return seek_restore if @command < 0x10 && restored?
60
+
61
+ if @track == @data
62
+ moved
63
+ else
64
+ @inward = @data > @track
65
+ @track = (@track + (@inward ? 1 : -1)) & 0xff
66
+ pulse
67
+ end
68
+ end
69
+
70
+ def restored?
71
+ return false unless @mechanism.track0? || @steps >= 255
72
+
73
+ @status |= NOT_FOUND if !@mechanism.track0? && @command.anybits?(VERIFY)
74
+ true
75
+ end
76
+
77
+ def seek_restore
78
+ @track = 0 if @mechanism.track0?
79
+ moved
80
+ end
81
+
82
+ def single_step
83
+ @track = (@track + (@inward ? 1 : -1)) & 0xff if @command.anybits?(UPDATE)
84
+ pulse
85
+ end
86
+
87
+ def pulse
88
+ @steps += 1
89
+ @mechanism.step(@inward)
90
+ @phase = STEPPED
91
+ @due = @now + STEP_RATES[@command & 0x03]
92
+ end
93
+
94
+ # The head is there: with V it settles, and the command ends
95
+ # otherwise.
96
+ def moved
97
+ return finish unless @command.anybits?(VERIFY) && @status.nobits?(NOT_FOUND)
98
+
99
+ @phase = SETTLED
100
+ @due = @now + SETTLE
101
+ end
102
+
103
+ def verify_track
104
+ @mode = VERIFY_TRACK
105
+ begin_search
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end