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,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/drives/engine"
4
+ require "badline/drives/model1541/bus"
5
+ require "badline/drives/model1541/cpu"
6
+ require "badline/drives/model1541/serial_port"
7
+ require "badline/drives/model1541/gcr"
8
+ require "badline/drives/model1541/track"
9
+ require "badline/drives/model1541/disk"
10
+ require "badline/drives/model1541/mechanism"
11
+ require "badline/drives/model1541/disk_via"
12
+ require "badline/drives/model1541/saved_state"
13
+
14
+ module Badline
15
+ module Drives
16
+ # The 1541 disk drive as a machine of its own: a 6502 running the DOS
17
+ # ROM at 1 MHz, with 2 KB of RAM and two VIAs on its bus. Drives::Engine::Core
18
+ # clocks it against the host and sleeps through the DOS's idle loop.
19
+ class Model1541
20
+ include Engine::Core
21
+ include Engine::VIAs
22
+ include SavedState
23
+
24
+ CLOCK_HZ = 1_000_000
25
+
26
+ # Where the DOS 2.6 idle loop starts over (see Drives::Engine::Idle).
27
+ IDLE_LOOP = 0xebff
28
+
29
+ def model_name = "1541"
30
+
31
+ # +rom+ covers $C000-$FFFF, and defaults to the DOS image in the ROM
32
+ # path. +device+ is the number the jumpers on VIA 1's PB5 and PB6 set,
33
+ # 8 to 11.
34
+ def initialize(rom: nil, host_clock_hz: CLOCK_HZ, device: 8, debug: false)
35
+ @device = device
36
+ @serial_port = SerialPort.new(device:)
37
+ @via1 = Chips::VIA.new(start: 0x1800, peripheral: @serial_port)
38
+ @mechanism = Mechanism.new
39
+ @via2 = DiskVIA.new(start: 0x1c00, mechanism: @mechanism)
40
+ @bus = Bus.new(rom: rom || ROM.load("dos1541.rom", 0xc000), via1: @via1, via2: @via2)
41
+ @cpu = CPU.new(@bus, debug:)
42
+ @clock_hz = CLOCK_HZ
43
+ @idle_loop = IDLE_LOOP
44
+ @host_clock_hz = host_clock_hz
45
+ @phase = 0
46
+ @cycles = 0
47
+ @serial_bus = nil
48
+ init_idle(debug)
49
+ # CA1 powers up at the level of a released ATN, without an edge.
50
+ @via1.ca1 = false
51
+ @via1.reset!
52
+ connect(SerialBus.new)
53
+ end
54
+
55
+ private
56
+
57
+ # One drive cycle. The VIAs clock ahead of the CPU, as the C64's chips
58
+ # do, and either one pulls IRQ. Nothing drives NMI on the 1541. The CPU
59
+ # runs whether or not the motor turns, since it answers ATN.
60
+ #
61
+ # The disk mechanism runs first, so BYTE READY lands on the VIA ahead
62
+ # of the CPU's cycle. The CPU samples SO a cycle late: BYTE READY sets
63
+ # V for the next cycle's instruction step.
64
+ #
65
+ # ATN reaches VIA 1's CA1 through the same inverter as PB7, so CA1 goes
66
+ # high as the C64 asserts ATN, as the serial port sees it: from the
67
+ # host cycle after the one that asserts it.
68
+ def step
69
+ so = @mechanism.take_so
70
+ @mechanism.cycle!
71
+ @via1.ca1 = @serial_port.atn_low?
72
+ @via1.cycle!
73
+ @via2.cycle!
74
+ @cpu.irq = @via1.irq? || @via2.irq?
75
+ @cpu.so! if so
76
+ @cpu.cycle!
77
+ @cycles += 1
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1571
6
+ # The drive CPU's bus:
7
+ #
8
+ # $0000-$07FF - 2 KB of RAM
9
+ # $0800-$17FF - nothing: open bus
10
+ # $1800-$1BFF - VIA 1, its sixteen registers mirrored
11
+ # $1C00-$1FFF - VIA 2, its sixteen registers mirrored
12
+ # $2000-$3FFF - the WD1770, its four registers mirrored
13
+ # $4000-$7FFF - the CIA, its sixteen registers mirrored
14
+ # $8000-$FFFF - the DOS ROM
15
+ #
16
+ # Writes to the ROM and to open bus go nowhere, and a read from open
17
+ # bus finds the last byte on the data bus, as on the 1541. Any access
18
+ # to VIA 2 clears the BYTE READY latch VIA 1's PA7 reads (SerialPort).
19
+ #
20
+ # While Idle records a pass of the DOS's idle loop, the bus watches it,
21
+ # and while Idle looks for an orbit, it guards the drive (see
22
+ # Drives::Engine::Watch). Any access to the CIA or the WD1770 makes the pass
23
+ # volatile and taints the drive.
24
+ class Bus
25
+ include Addressable
26
+ include Engine::Watch
27
+
28
+ attr_reader :ram, :rom, :via1, :via2, :cia, :fdc, :data
29
+
30
+ def initialize(rom:, via1:, via2:, cia:, fdc:)
31
+ addressable_at(0, length: 2**16)
32
+ @ram = Memory.new([], length: 0x0800, start: 0)
33
+ @rom = rom
34
+ @via1 = via1
35
+ @via2 = via2
36
+ @cia = cia
37
+ @fdc = fdc
38
+ @mechanism = via2.mechanism
39
+ @data = 0
40
+ init_watch
41
+ end
42
+
43
+ # The last byte on the data bus and the RAM. What a watched stretch
44
+ # touched is Idle's, and a restored bus isn't watching.
45
+ def save_state(out)
46
+ out.int(@data)
47
+ @ram.save_state(out)
48
+ end
49
+
50
+ def load_state(input)
51
+ @data = input.int
52
+ @ram.load_state(input)
53
+ @watching = false
54
+ end
55
+
56
+ def peek(addr)
57
+ return @data = @rom.peek(addr) if addr >= 0x8000
58
+ return @data = chip_peek(addr) if addr >= 0x2000
59
+
60
+ watch_read(addr) if @watching
61
+ @data = if addr < 0x0800
62
+ @ram.peek(addr)
63
+ elsif addr < 0x1800
64
+ @data
65
+ elsif addr < 0x1c00
66
+ @via1.peek(addr)
67
+ else
68
+ @mechanism.release_byte_latch
69
+ @via2.peek(addr)
70
+ end
71
+ end
72
+
73
+ def poke(addr, value)
74
+ @data = value
75
+ return if addr >= 0x8000
76
+ return chip_poke(addr, value) if addr >= 0x2000
77
+
78
+ low_poke(addr, value)
79
+ end
80
+
81
+ private
82
+
83
+ # A write below $2000: RAM or a VIA.
84
+ def low_poke(addr, value)
85
+ if addr < 0x0800
86
+ touch(addr) if @recording
87
+ @ram.poke(addr, value)
88
+ elsif addr >= 0x1c00
89
+ @mechanism.release_byte_latch
90
+ @via2.poke(addr, value)
91
+ elsif addr >= 0x1800
92
+ @via1.poke(addr, value)
93
+ end
94
+ watch_write(addr) if @watching
95
+ end
96
+
97
+ def chip_peek(addr)
98
+ watch_chip if @watching
99
+ addr >= 0x4000 ? @cia.peek(0x4000 | (addr & 0x0f)) : @fdc.peek(addr & 0x03)
100
+ end
101
+
102
+ def chip_poke(addr, value)
103
+ if addr >= 0x4000
104
+ @cia.poke(0x4000 | (addr & 0x0f), value)
105
+ else
106
+ @fdc.poke(addr & 0x03, value)
107
+ end
108
+ watch_chip if @watching
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1571
6
+ # The drive's 6502, on the drive's Bus.
7
+ class CPU
8
+ include Badline::Chips::CPU::Core
9
+ include Engine::IdleCPU
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1571
6
+ # The drive's state for a snapshot.
7
+ module SavedState
8
+ # The drive's whole state, as the 1541's (Drives::Model1541#save_state), with
9
+ # the CIA and the WD1770's registers. The clock rate, the side and the
10
+ # fast serial direction follow from VIA 1's port A.
11
+ def save_state(out)
12
+ settle!
13
+ out.marker("DRIVE1571")
14
+ out.int(@phase).int(@cycles).boolean(@mechanism.so_pending)
15
+ @serial_port.save_state(out)
16
+ @via1.save_state(out)
17
+ @via2.save_state(out)
18
+ @cia.save_state(out)
19
+ @fdc.save_state(out)
20
+ @bus.save_state(out)
21
+ @cpu.save_state(out)
22
+ @mechanism.save_state(out)
23
+ end
24
+
25
+ def load_state(input)
26
+ settle!
27
+ input.marker("DRIVE1571")
28
+ @phase = input.int
29
+ @cycles = input.int
30
+ @mechanism.so_pending = input.boolean?
31
+ @serial_port.load_state(input)
32
+ @via1.load_state(input)
33
+ @via2.load_state(input)
34
+ @cia.load_state(input)
35
+ @fdc.load_state(input)
36
+ @bus.load_state(input)
37
+ @cpu.load_state(input)
38
+ @mechanism.load_state(input)
39
+ @fast_serial_out = @via1.port_a_output.anybits?(FAST_SERIAL_OUT)
40
+ port_a_written(@via1.port_a_output)
41
+ push_fast_output(@fast_serial_out ? fast_pins : 0)
42
+ forget_orbits
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1571
6
+ # What VIA 1's ports read from outside the chip. Port B carries the
7
+ # serial bus inputs and the device number jumpers, as on the 1541
8
+ # (Drives::Engine::SerialLines). Port A reads the mechanism on two inputs:
9
+ #
10
+ # PA0 track 0 sensor, low while the head sits on track 1
11
+ # PA7 BYTE READY, latched low from a whole byte until the CPU next
12
+ # reads or writes VIA 2
13
+ #
14
+ # The DOS steps the head out until PA0 reads low with the stepper on
15
+ # phase 0, and polls PA7 for each byte at 2 MHz, taking the byte from
16
+ # VIA 2's port A or putting the next one there after each. PA1 (fast serial
17
+ # direction), PA2 (side) and PA5 (1 or 2 MHz) are outputs, which
18
+ # Drives::Model1571 follows (SerialVIA).
19
+ class SerialPort
20
+ include Engine::SerialLines
21
+
22
+ TRACK0 = 0x01
23
+ BYTE_READY = 0x80
24
+
25
+ def initialize(mechanism, device: 8, bus: SerialBus.new)
26
+ @mechanism = mechanism
27
+ init_serial_lines(device, bus)
28
+ end
29
+
30
+ def read_a(_lines)
31
+ value = 0xff
32
+ value &= ~TRACK0 if @mechanism.half_track == Model1541::Mechanism::MIN_HALF_TRACK
33
+ value &= ~BYTE_READY if @mechanism.byte_latched?
34
+ value
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1571
6
+ # VIA 1, the one facing the serial bus. Its port A also selects the
7
+ # side, the clock rate and the fast serial direction, so the drive
8
+ # hears port A after every write and reset (Drives::Model1571#port_a_written).
9
+ class SerialVIA < Chips::VIA
10
+ def initialize(start:, peripheral:, drive:)
11
+ @drive = drive
12
+ super(start:, peripheral:)
13
+ end
14
+
15
+ def reset!
16
+ super
17
+ @drive.port_a_written(port_a_output)
18
+ end
19
+
20
+ def poke(addr, value)
21
+ super
22
+ @drive.port_a_written(port_a_output)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1571
6
+ # The WD1770 floppy controller at $2000, which DOS 3.0 drives for MFM
7
+ # disks. The 1571 here only ever holds GCR disks, so the controller
8
+ # never finds an MFM sector: it runs each command for its time and ends
9
+ # it as the WD177x data sheet does on a disk without one.
10
+ #
11
+ # $2000 status (read), command (write)
12
+ # $2001 track
13
+ # $2002 sector
14
+ # $2003 data
15
+ #
16
+ # BUSY sets as a command is written. A restore, seek or step (type I)
17
+ # moves the track register and ends a few milliseconds later, with
18
+ # TRACK 0 reported at track 0. A sector read or write, a read address
19
+ # or a read track ends with RECORD NOT FOUND after five turns of the
20
+ # disk, and a write track after one, with nothing written. A force
21
+ # interrupt ends the command at once. Time is the drive CPU's cycles.
22
+ class WD1770
23
+ BUSY = 0x01
24
+ TRACK0 = 0x04
25
+ NOT_FOUND = 0x10
26
+ MOTOR_ON = 0x80
27
+
28
+ # Cycles at 2 MHz, the 1571's clock in 1571 mode: a turn of the disk
29
+ # at 300 rpm, and a step with the head settling.
30
+ TURN = 400_000
31
+ STEP = 12_000
32
+
33
+ # The CPU whose cycles time the commands.
34
+ attr_writer :cpu
35
+
36
+ def initialize
37
+ @registers = [0, 0, 0, 0]
38
+ @status = 0
39
+ @due = 0
40
+ @result = 0
41
+ @cpu = nil
42
+ end
43
+
44
+ # Register +offset+, 0 to 3: the status, settled to the command's end
45
+ # once its time has run out.
46
+ def peek(offset)
47
+ return @registers[offset] unless offset.zero?
48
+
49
+ finish if @status.anybits?(BUSY) && @cpu.cycles >= @due
50
+ @status
51
+ end
52
+
53
+ def poke(offset, value)
54
+ offset.zero? ? command(value) : @registers[offset] = value
55
+ end
56
+
57
+ def save_state(out)
58
+ out.ints([*@registers, @status, @due, @result])
59
+ end
60
+
61
+ # A state from before the controller ran commands holds the four
62
+ # registers alone.
63
+ def load_state(input)
64
+ values = input.ints
65
+ @registers = values[0, 4]
66
+ @status = values[4] || 0
67
+ @due = values[5] || 0
68
+ @result = values[6] || 0
69
+ end
70
+
71
+ private
72
+
73
+ def command(value)
74
+ return interrupt if (value & 0xf0) == 0xd0
75
+
76
+ @registers[0] = value
77
+ value < 0x80 ? step(value) : search(value)
78
+ end
79
+
80
+ # A restore ($0x), seek ($1x) or step ($2x to $7x), its track register
81
+ # moved at once.
82
+ def step(value)
83
+ track = @registers[1]
84
+ target = case value >> 4
85
+ when 0 then 0
86
+ when 1 then @registers[3]
87
+ else track + step_direction(value)
88
+ end
89
+ @registers[1] = target.clamp(0, 255) if value < 0x20 || value.anybits?(0x10)
90
+ start(STEP * [(target - track).abs, 1].max, @registers[1].zero? ? TRACK0 : 0)
91
+ end
92
+
93
+ # Step in ($4x) moves toward higher tracks, step out ($6x) toward
94
+ # track 0, and step ($2x) the way the last one went.
95
+ def step_direction(value)
96
+ @direction = 1 if (value >> 5) == 2
97
+ @direction = -1 if (value >> 5) == 3
98
+ @direction || 1
99
+ end
100
+
101
+ # A sector or track command that finds no MFM sector.
102
+ def search(value)
103
+ value >= 0xf0 ? start(TURN, 0) : start(TURN * 5, NOT_FOUND)
104
+ end
105
+
106
+ def start(cycles, result)
107
+ @status = BUSY | MOTOR_ON
108
+ @due = @cpu.cycles + cycles
109
+ @result = result
110
+ end
111
+
112
+ def finish
113
+ @status = @result
114
+ end
115
+
116
+ def interrupt
117
+ @status &= ~BUSY & 0xff
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/drives/model1571/cpu"
4
+ require "badline/drives/model1571/wd1770"
5
+ require "badline/drives/model1571/serial_port"
6
+ require "badline/drives/model1571/serial_via"
7
+ require "badline/drives/model1571/bus"
8
+ require "badline/drives/model1571/saved_state"
9
+
10
+ module Badline
11
+ module Drives
12
+ # The 1571 disk drive, the C128D's built-in one: the 1541's 6502, two
13
+ # VIAs and GCR mechanism, with a second head, a 6526 CIA for fast
14
+ # serial, a WD1770 for MFM disks and DOS 3.0 in 32 KB of ROM. Drives::Engine::Core
15
+ # clocks it against the host and sleeps through the DOS's idle loop.
16
+ #
17
+ # VIA 1's port A picks the clock, 1 or 2 MHz on PA5, and the head on
18
+ # PA2, and reads the track 0 sensor and BYTE READY (SerialPort). The
19
+ # DOS resets at 2 MHz and drops to 1 MHz as a 1541 would run, which is
20
+ # how it stays until a C128 asks for fast serial. The disk turns at the
21
+ # same speed either way (Drives::Model1541::Mechanism#clock_hz=).
22
+ #
23
+ # The CIA sits at $4000, on the IRQ line with both VIAs. Only its serial
24
+ # port is wired, for fast serial through buffers PA1 turns round
25
+ # (Drives::Engine::FastSerial). The drive sleeps only while the CIA is quiet
26
+ # (CIA#quiet?).
27
+ class Model1571
28
+ include Engine::Core
29
+ include Engine::VIAs
30
+ include Engine::FastSerial
31
+ include SavedState
32
+
33
+ CLOCK_HZ = 1_000_000
34
+ FAST_CLOCK_HZ = 2_000_000
35
+
36
+ # Where the DOS 3.0 idle loop starts over, as DOS 2.6's does.
37
+ IDLE_LOOP = 0xebff
38
+
39
+ # VIA 1's port A outputs.
40
+ FAST_SERIAL_OUT = 0x02
41
+ SIDE = 0x04
42
+ FAST = 0x20
43
+
44
+ def cia
45
+ settle!
46
+ @cia
47
+ end
48
+
49
+ def fdc
50
+ settle!
51
+ @fdc
52
+ end
53
+
54
+ def model_name = "1571"
55
+
56
+ # +rom+ covers $8000-$FFFF, and defaults to the DOS image in the ROM
57
+ # path. +device+ is the number the jumpers on VIA 1's PB5 and PB6 set,
58
+ # 8 to 11.
59
+ def initialize(rom: nil, host_clock_hz: CLOCK_HZ, device: 8, debug: false)
60
+ @device = device
61
+ @clock_hz = CLOCK_HZ
62
+ init_fast_serial
63
+ @mechanism = Model1541::Mechanism.new(slip: 2)
64
+ @serial_port = SerialPort.new(@mechanism, device:)
65
+ @via1 = SerialVIA.new(start: 0x1800, peripheral: @serial_port, drive: self)
66
+ @via2 = Model1541::DiskVIA.new(start: 0x1c00, mechanism: @mechanism)
67
+ @cia = Chips::CIA.new(start: 0x4000)
68
+ @fdc = WD1770.new
69
+ @bus = Bus.new(rom: rom || ROM.load("dos1571.rom", 0x8000), via1: @via1, via2: @via2, cia: @cia, fdc: @fdc)
70
+ @cpu = CPU.new(@bus, debug:)
71
+ @fdc.cpu = @cpu
72
+ @idle_loop = IDLE_LOOP
73
+ @host_clock_hz = host_clock_hz
74
+ @phase = 0
75
+ @cycles = 0
76
+ @serial_bus = nil
77
+ init_idle(debug)
78
+ # CA1 powers up at the level of a released ATN, without an edge.
79
+ @via1.ca1 = false
80
+ @via1.reset!
81
+ connect(SerialBus.new)
82
+ end
83
+
84
+ # The serial bus's RESET line reaches the CPU, both VIAs and the CIA.
85
+ # RAM keeps its contents.
86
+ def reset!
87
+ settle!
88
+ @via1.reset!
89
+ @via2.reset!
90
+ @cia.reset!
91
+ @cpu.reset!
92
+ end
93
+
94
+ # VIA 1 drives port A to +lines+: the side, the clock rate and the fast
95
+ # serial direction follow it.
96
+ def port_a_written(lines)
97
+ @mechanism.side = lines.anybits?(SIDE) ? 1 : 0
98
+ fast_serial_out = lines.anybits?(FAST_SERIAL_OUT)
99
+ turn_fast_serial(fast_serial_out) if fast_serial_out != @fast_serial_out
100
+ clock_hz = lines.anybits?(FAST) ? FAST_CLOCK_HZ : CLOCK_HZ
101
+ return if clock_hz == @clock_hz
102
+
103
+ @clock_hz = clock_hz
104
+ @mechanism.clock_hz = clock_hz
105
+ end
106
+
107
+ # Whether the drive runs at 2 MHz.
108
+ def fast? = @clock_hz == FAST_CLOCK_HZ
109
+
110
+ # VIA 1's port B, with the fast serial pins pulling DATA and SRQ
111
+ # (Drives::SerialBus::DRIVE_FAST_DATA and DRIVE_FAST_SRQ) above it.
112
+ def serial_output = @via1.port_b_output | @fast_output
113
+
114
+ private
115
+
116
+ # One drive cycle, as the 1541's (Drives::Model1541#step), with the CIA
117
+ # clocked beside the VIAs and pulling IRQ with them.
118
+ def step
119
+ so = @mechanism.take_so
120
+ @mechanism.cycle!
121
+ @via1.ca1 = @serial_port.atn_low?
122
+ @via1.cycle!
123
+ @via2.cycle!
124
+ @cia.cycle!
125
+ drive_fast_serial if @fast_serial_out
126
+ @cpu.irq = @via1.irq? || @via2.irq? || @cia.interrupted?
127
+ @cpu.so! if so
128
+ @cpu.cycle!
129
+ @cycles += 1
130
+ end
131
+
132
+ # The VIAs' quiet cycles while the CIA is quiet, and none otherwise.
133
+ def quiet_cycles
134
+ @cia.quiet? ? [@via1.quiet_cycles, @via2.quiet_cycles].min : 0
135
+ end
136
+
137
+ def fast_forward_more(cycles)
138
+ @cia.fast_forward(cycles)
139
+ end
140
+ end
141
+ end
142
+ end