badline 0.12.1 → 0.14.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 (565) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -1
  3. data/CLAUDE.md +86 -38
  4. data/CONTRIBUTING.md +4 -3
  5. data/README.md +9 -6
  6. data/doc/library.md +9 -9
  7. data/doc/media.md +2 -1
  8. data/doc/pinned-behaviour.md +134 -105
  9. data/doc/snapshot-format.md +1047 -0
  10. data/doc/snapshots.md +73 -43
  11. data/lib/badline/audio/bare_player.rb +53 -20
  12. data/lib/badline/audio/cli.rb +6 -6
  13. data/lib/badline/audio/jukebox.rb +2 -2
  14. data/lib/badline/audio/machine_player.rb +16 -10
  15. data/lib/badline/{media → audio}/queue.rb +1 -1
  16. data/lib/badline/audio/queued_tune.rb +6 -6
  17. data/lib/badline/audio/renderer.rb +33 -22
  18. data/lib/badline/audio/stereo.rb +1 -1
  19. data/lib/badline/c128/banks.rb +6 -3
  20. data/lib/badline/c128/bus/keyed_state.rb +45 -0
  21. data/lib/badline/c128/bus.rb +35 -20
  22. data/lib/badline/c128/color_lines.rb +2 -2
  23. data/lib/badline/c128/cpu.rb +1 -1
  24. data/lib/badline/c128/drives.rb +14 -34
  25. data/lib/badline/c128/fast_serial.rb +5 -5
  26. data/lib/badline/c128/keyed_modules.rb +117 -0
  27. data/lib/badline/c128/keyed_state.rb +91 -0
  28. data/lib/badline/c128/keys.rb +9 -0
  29. data/lib/badline/c128/mmu.rb +9 -8
  30. data/lib/badline/c128/mmu_pages.rb +21 -1
  31. data/lib/badline/c128/modes.rb +21 -11
  32. data/lib/badline/c128/z80.rb +2 -2
  33. data/lib/badline/c128/z80_turns.rb +1 -1
  34. data/lib/badline/c128.rb +21 -16
  35. data/lib/badline/c64/attachments.rb +42 -0
  36. data/lib/badline/c64/banked_ram/banking.rb +32 -0
  37. data/lib/badline/c64/banked_ram/plus256k.rb +64 -0
  38. data/lib/badline/c64/banked_ram/plus60k.rb +47 -0
  39. data/lib/badline/c64/banked_ram/unexpanded.rb +30 -0
  40. data/lib/badline/c64/banked_ram.rb +23 -0
  41. data/lib/badline/c64/bus/debug_register.rb +32 -0
  42. data/lib/badline/c64/bus/extra_sids.rb +32 -0
  43. data/lib/badline/c64/bus/fittings.rb +40 -0
  44. data/lib/badline/c64/bus/keyed_state.rb +41 -0
  45. data/lib/badline/c64/bus/pla.rb +149 -0
  46. data/lib/badline/c64/bus/roms.rb +41 -0
  47. data/lib/badline/c64/bus/sid_slots.rb +44 -0
  48. data/lib/badline/c64/bus.rb +219 -0
  49. data/lib/badline/c64/cartridge/action_replay.rb +115 -0
  50. data/lib/badline/c64/cartridge/atomic_power.rb +26 -0
  51. data/lib/badline/c64/cartridge/bank.rb +83 -0
  52. data/lib/badline/c64/cartridge/comal80.rb +52 -0
  53. data/lib/badline/c64/cartridge/dinamic.rb +36 -0
  54. data/lib/badline/c64/cartridge/easy_flash.rb +132 -0
  55. data/lib/badline/c64/cartridge/epyx_fastload.rb +73 -0
  56. data/lib/badline/c64/cartridge/final_cartridge3.rb +79 -0
  57. data/lib/badline/c64/cartridge/flash.rb +279 -0
  58. data/lib/badline/c64/cartridge/freezer.rb +35 -0
  59. data/lib/badline/c64/cartridge/fun_play.rb +40 -0
  60. data/lib/badline/c64/cartridge/g_mod2.rb +64 -0
  61. data/lib/badline/c64/cartridge/game_system.rb +42 -0
  62. data/lib/badline/c64/cartridge/geo_ram.rb +65 -0
  63. data/lib/badline/c64/cartridge/kcs_power.rb +69 -0
  64. data/lib/badline/c64/cartridge/keyed_state.rb +393 -0
  65. data/lib/badline/c64/cartridge/mach5.rb +34 -0
  66. data/lib/badline/c64/cartridge/magic_desk.rb +32 -0
  67. data/lib/badline/c64/cartridge/ocean.rb +37 -0
  68. data/lib/badline/c64/cartridge/pagefox.rb +60 -0
  69. data/lib/badline/c64/cartridge/retro_replay.rb +278 -0
  70. data/lib/badline/c64/cartridge/rex_utility.rb +31 -0
  71. data/lib/badline/c64/cartridge/rgcd.rb +50 -0
  72. data/lib/badline/c64/cartridge/simons_basic.rb +37 -0
  73. data/lib/badline/c64/cartridge/standard.rb +17 -0
  74. data/lib/badline/c64/cartridge/super_games.rb +40 -0
  75. data/lib/badline/c64/cartridge/westermann.rb +32 -0
  76. data/lib/badline/c64/cartridge/zaxxon.rb +52 -0
  77. data/lib/badline/c64/cartridge.rb +232 -0
  78. data/lib/badline/c64/color_memory.rb +27 -0
  79. data/lib/badline/{computer → c64}/common.rb +2 -2
  80. data/lib/badline/{computer → c64}/kernal_traps.rb +39 -36
  81. data/lib/badline/c64/keyed_modules.rb +111 -0
  82. data/lib/badline/c64/keyed_state.rb +68 -0
  83. data/lib/badline/c64/reu/dma.rb +271 -0
  84. data/lib/badline/c64/reu/keyed_state.rb +140 -0
  85. data/lib/badline/c64/reu/ram.rb +94 -0
  86. data/lib/badline/c64/reu/trigger.rb +34 -0
  87. data/lib/badline/c64/reu.rb +289 -0
  88. data/lib/badline/c64/true_drives.rb +120 -0
  89. data/lib/badline/{computer.rb → c64.rb} +24 -15
  90. data/lib/badline/chips/cia/fast_forward.rb +62 -0
  91. data/lib/badline/chips/cia/interrupt_register.rb +128 -0
  92. data/lib/badline/chips/cia/keyed_parts.rb +213 -0
  93. data/lib/badline/chips/cia/serial.rb +246 -0
  94. data/lib/badline/chips/cia/time_of_day.rb +210 -0
  95. data/lib/badline/chips/cia/timer.rb +188 -0
  96. data/lib/badline/chips/cia.rb +281 -0
  97. data/lib/badline/chips/cpu/addressing.rb +133 -0
  98. data/lib/badline/chips/cpu/boundary.rb +56 -0
  99. data/lib/badline/chips/cpu/core.rb +183 -0
  100. data/lib/badline/chips/cpu/instruction.rb +338 -0
  101. data/lib/badline/chips/cpu/instruction_set/arithmetic.rb +118 -0
  102. data/lib/badline/chips/cpu/instruction_set/bitwise.rb +130 -0
  103. data/lib/badline/chips/cpu/instruction_set/branch.rb +83 -0
  104. data/lib/badline/chips/cpu/instruction_set/flag.rb +67 -0
  105. data/lib/badline/chips/cpu/instruction_set/illegal.rb +274 -0
  106. data/lib/badline/chips/cpu/instruction_set/inc_dec.rb +73 -0
  107. data/lib/badline/chips/cpu/instruction_set/stack.rb +56 -0
  108. data/lib/badline/chips/cpu/instruction_set/transfer.rb +141 -0
  109. data/lib/badline/chips/cpu/instruction_set.rb +59 -0
  110. data/lib/badline/chips/cpu/interrupts.rb +108 -0
  111. data/lib/badline/chips/cpu/keyed_state.rb +177 -0
  112. data/lib/badline/chips/cpu/microcode.rb +195 -0
  113. data/lib/badline/chips/cpu/operations.rb +90 -0
  114. data/lib/badline/chips/cpu/port.rb +133 -0
  115. data/lib/badline/chips/cpu/stack_operations.rb +84 -0
  116. data/lib/badline/chips/cpu/traps.rb +23 -0
  117. data/lib/badline/chips/cpu.rb +17 -0
  118. data/lib/badline/chips/sid/catch_up.rb +122 -0
  119. data/lib/badline/chips/sid/decimator.rb +68 -0
  120. data/lib/badline/chips/sid/envelope.rb +236 -0
  121. data/lib/badline/chips/sid/filter.rb +227 -0
  122. data/lib/badline/chips/sid/keyed_parts.rb +286 -0
  123. data/lib/badline/chips/sid/voice.rb +69 -0
  124. data/lib/badline/chips/sid/waveform/combined.rb +128 -0
  125. data/lib/badline/chips/sid/waveform/fast_forward.rb +107 -0
  126. data/lib/badline/chips/sid/waveform/noise_writeback.rb +124 -0
  127. data/lib/badline/chips/sid/waveform.rb +305 -0
  128. data/lib/badline/chips/sid.rb +264 -0
  129. data/lib/badline/chips/ted/beam.rb +119 -0
  130. data/lib/badline/chips/ted/timers.rb +66 -0
  131. data/lib/badline/chips/ted.rb +143 -0
  132. data/lib/badline/chips/tia.rb +49 -0
  133. data/lib/badline/chips/vdc/keyed_parts.rb +105 -0
  134. data/lib/badline/{c128 → chips}/vdc/memory.rb +1 -1
  135. data/lib/badline/{c128 → chips}/vdc/painter.rb +1 -13
  136. data/lib/badline/{c128 → chips}/vdc/raster.rb +1 -17
  137. data/lib/badline/{c128 → chips}/vdc/window.rb +1 -10
  138. data/lib/badline/{c128 → chips}/vdc.rb +6 -31
  139. data/lib/badline/chips/via/control_lines.rb +109 -0
  140. data/lib/badline/chips/via/fast_forward.rb +55 -0
  141. data/lib/badline/chips/via/interrupt_register.rb +60 -0
  142. data/lib/badline/chips/via/keyed_parts.rb +163 -0
  143. data/lib/badline/chips/via/shift_register.rb +168 -0
  144. data/lib/badline/chips/via/timer1.rb +120 -0
  145. data/lib/badline/chips/via/timer2.rb +117 -0
  146. data/lib/badline/chips/via.rb +267 -0
  147. data/lib/badline/chips/vic/bank.rb +135 -0
  148. data/lib/badline/chips/vic/border_mask.rb +78 -0
  149. data/lib/badline/chips/vic/collisions.rb +106 -0
  150. data/lib/badline/chips/vic/color_patches.rb +38 -0
  151. data/lib/badline/chips/vic/display_state.rb +168 -0
  152. data/lib/badline/chips/vic/graphics_mode.rb +166 -0
  153. data/lib/badline/chips/vic/graphics_shifter.rb +183 -0
  154. data/lib/badline/chips/vic/keyed_parts.rb +228 -0
  155. data/lib/badline/chips/vic/keyed_sprites.rb +225 -0
  156. data/lib/badline/chips/vic/keyed_state.rb +102 -0
  157. data/lib/badline/chips/vic/register_log.rb +65 -0
  158. data/lib/badline/chips/vic/registers.rb +188 -0
  159. data/lib/badline/chips/vic/sequencer.rb +275 -0
  160. data/lib/badline/chips/vic/sequencer_output.rb +118 -0
  161. data/lib/badline/chips/vic/sprite/internal_bus.rb +59 -0
  162. data/lib/badline/chips/vic/sprite/shifter.rb +148 -0
  163. data/lib/badline/chips/vic/sprite/timing.rb +58 -0
  164. data/lib/badline/chips/vic/sprite.rb +337 -0
  165. data/lib/badline/chips/vic/sprites.rb +281 -0
  166. data/lib/badline/chips/vic.rb +787 -0
  167. data/lib/badline/chips/vic_i/keyed_parts.rb +142 -0
  168. data/lib/badline/{vic20/vic → chips/vic_i}/painter.rb +2 -30
  169. data/lib/badline/chips/vic_i/sound/output.rb +85 -0
  170. data/lib/badline/chips/vic_i/sound.rb +227 -0
  171. data/lib/badline/{vic20/vic → chips/vic_i}/text_window.rb +2 -2
  172. data/lib/badline/{vic20/vic.rb → chips/vic_i.rb} +6 -6
  173. data/lib/badline/chips/z80/arithmetic.rb +119 -0
  174. data/lib/badline/chips/z80/bit_page.rb +57 -0
  175. data/lib/badline/chips/z80/block_io.rb +60 -0
  176. data/lib/badline/chips/z80/block_transfers.rb +61 -0
  177. data/lib/badline/chips/z80/bus_cycles.rb +113 -0
  178. data/lib/badline/chips/z80/core.rb +115 -0
  179. data/lib/badline/chips/z80/exchanges.rb +52 -0
  180. data/lib/badline/chips/z80/extended_page.rb +91 -0
  181. data/lib/badline/chips/z80/flags.rb +39 -0
  182. data/lib/badline/chips/z80/interrupt_acceptance.rb +48 -0
  183. data/lib/badline/chips/z80/jumps.rb +84 -0
  184. data/lib/badline/chips/z80/keyed_state.rb +73 -0
  185. data/lib/badline/chips/z80/loads.rb +100 -0
  186. data/lib/badline/chips/z80/main_page.rb +136 -0
  187. data/lib/badline/chips/z80/registers.rb +122 -0
  188. data/lib/badline/chips/z80/shifts.rb +66 -0
  189. data/lib/badline/chips/z80.rb +13 -0
  190. data/lib/badline/chips.rb +10 -0
  191. data/lib/badline/core.rb +13 -32
  192. data/lib/badline/drives/datasette/keyed_state.rb +38 -0
  193. data/lib/badline/drives/datasette.rb +173 -0
  194. data/lib/badline/drives/engine/core.rb +152 -0
  195. data/lib/badline/drives/engine/fast_serial.rb +75 -0
  196. data/lib/badline/drives/engine/idle.rb +127 -0
  197. data/lib/badline/drives/engine/idle_cpu.rb +30 -0
  198. data/lib/badline/drives/engine/orbit.rb +81 -0
  199. data/lib/badline/drives/engine/serial_lines.rb +72 -0
  200. data/lib/badline/drives/engine/sleep.rb +114 -0
  201. data/lib/badline/drives/engine/vias.rb +86 -0
  202. data/lib/badline/drives/engine/watch.rb +152 -0
  203. data/lib/badline/drives/engine.rb +11 -0
  204. data/lib/badline/drives/model1541/bus.rb +75 -0
  205. data/lib/badline/drives/model1541/byte_ready.rb +50 -0
  206. data/lib/badline/drives/model1541/cpu.rb +13 -0
  207. data/lib/badline/drives/model1541/disk.rb +318 -0
  208. data/lib/badline/drives/model1541/disk_via.rb +38 -0
  209. data/lib/badline/drives/model1541/gcr.rb +59 -0
  210. data/lib/badline/drives/model1541/keyed_state.rb +251 -0
  211. data/lib/badline/drives/model1541/mechanism.rb +313 -0
  212. data/lib/badline/drives/model1541/rotation.rb +123 -0
  213. data/lib/badline/drives/model1541/sector_reader.rb +78 -0
  214. data/lib/badline/drives/model1541/serial_port.rb +20 -0
  215. data/lib/badline/drives/model1541/track.rb +100 -0
  216. data/lib/badline/drives/model1541.rb +80 -0
  217. data/lib/badline/drives/model1571/bus.rb +100 -0
  218. data/lib/badline/drives/model1571/cpu.rb +13 -0
  219. data/lib/badline/drives/model1571/keyed_state.rb +108 -0
  220. data/lib/badline/drives/model1571/serial_port.rb +39 -0
  221. data/lib/badline/drives/model1571/serial_via.rb +27 -0
  222. data/lib/badline/drives/model1571/wd1770.rb +108 -0
  223. data/lib/badline/drives/model1571.rb +141 -0
  224. data/lib/badline/drives/model1581/bus.rb +126 -0
  225. data/lib/badline/drives/model1581/cpu.rb +13 -0
  226. data/lib/badline/drives/model1581/disk.rb +133 -0
  227. data/lib/badline/drives/model1581/keyed_state.rb +280 -0
  228. data/lib/badline/drives/model1581/mechanism.rb +98 -0
  229. data/lib/badline/drives/model1581/serial_port.rb +54 -0
  230. data/lib/badline/drives/model1581/slot.rb +61 -0
  231. data/lib/badline/drives/model1581/track.rb +102 -0
  232. data/lib/badline/drives/model1581/track_bytes.rb +77 -0
  233. data/lib/badline/drives/model1581/wd1772/registers.rb +91 -0
  234. data/lib/badline/drives/model1581/wd1772/sector_writes.rb +75 -0
  235. data/lib/badline/drives/model1581/wd1772/sectors.rb +152 -0
  236. data/lib/badline/drives/model1581/wd1772/stepping.rb +111 -0
  237. data/lib/badline/drives/model1581/wd1772/tracks.rb +127 -0
  238. data/lib/badline/drives/model1581/wd1772/turn.rb +75 -0
  239. data/lib/badline/drives/model1581/wd1772.rb +216 -0
  240. data/lib/badline/drives/model1581.rb +206 -0
  241. data/lib/badline/drives/serial_bus.rb +161 -0
  242. data/lib/badline/drives.rb +8 -0
  243. data/lib/badline/frontend/app.rb +3 -3
  244. data/lib/badline/frontend/boot.rb +4 -4
  245. data/lib/badline/frontend/controls.rb +19 -3
  246. data/lib/badline/frontend/drive_led.rb +44 -21
  247. data/lib/badline/frontend/machine_window.rb +3 -1
  248. data/lib/badline/frontend/menu/menu_dialogs.rb +2 -2
  249. data/lib/badline/frontend/player/filter_view.rb +1 -1
  250. data/lib/badline/frontend/player/player_controller.rb +2 -2
  251. data/lib/badline/frontend/player/player_screen.rb +1 -0
  252. data/lib/badline/frontend/player/theme.rb +7 -7
  253. data/lib/badline/frontend/snapshots.rb +12 -1
  254. data/lib/badline/frontend/timeline.rb +30 -12
  255. data/lib/badline/input/control_ports.rb +78 -0
  256. data/lib/badline/input/joystick.rb +27 -0
  257. data/lib/badline/input/keyboard.rb +114 -0
  258. data/lib/badline/input/matrix_typist.rb +98 -0
  259. data/lib/badline/input.rb +4 -0
  260. data/lib/badline/kernal_trap/chrout.rb +45 -0
  261. data/lib/badline/kernal_trap/{drive → dos}/block_commands.rb +1 -1
  262. data/lib/badline/kernal_trap/dos/channel.rb +156 -0
  263. data/lib/badline/kernal_trap/{drive → dos}/channels.rb +1 -26
  264. data/lib/badline/kernal_trap/{drive → dos}/memory.rb +1 -10
  265. data/lib/badline/kernal_trap/{drive → dos}/parameters.rb +1 -1
  266. data/lib/badline/kernal_trap/{drive → dos}/status.rb +1 -9
  267. data/lib/badline/kernal_trap/{drive → dos}/write_file.rb +1 -19
  268. data/lib/badline/kernal_trap/{drive → dos}/writes.rb +1 -1
  269. data/lib/badline/kernal_trap/{drive.rb → dos.rb} +9 -27
  270. data/lib/badline/kernal_trap/file_routine.rb +4 -4
  271. data/lib/badline/kernal_trap/keyed_state.rb +150 -0
  272. data/lib/badline/kernal_trap/layout.rb +75 -11
  273. data/lib/badline/kernal_trap/load.rb +19 -21
  274. data/lib/badline/kernal_trap/routine.rb +12 -0
  275. data/lib/badline/kernal_trap/save.rb +12 -22
  276. data/lib/badline/kernal_trap/serial.rb +8 -24
  277. data/lib/badline/kernal_trap.rb +3 -2
  278. data/lib/badline/machine/clocking.rb +1 -1
  279. data/lib/badline/machine/keyboard_buffer.rb +49 -0
  280. data/lib/badline/machine/settling.rb +29 -0
  281. data/lib/badline/machine.rb +10 -7
  282. data/lib/badline/media/boot_disk.rb +14 -2
  283. data/lib/badline/media/extensions.rb +10 -0
  284. data/lib/badline/media/true_drive.rb +1 -1
  285. data/lib/badline/media/tune.rb +2 -2
  286. data/lib/badline/media.rb +3 -3
  287. data/lib/badline/memory.rb +3 -6
  288. data/lib/badline/model.rb +1 -1
  289. data/lib/badline/options/family.rb +5 -2
  290. data/lib/badline/options/help.rb +42 -16
  291. data/lib/badline/options/table.rb +2 -0
  292. data/lib/badline/options/validation.rb +2 -0
  293. data/lib/badline/options.rb +6 -1
  294. data/lib/badline/plus4/acia.rb +45 -0
  295. data/lib/badline/plus4/bus.rb +312 -0
  296. data/lib/badline/plus4/cpu.rb +10 -0
  297. data/lib/badline/plus4/cpu_port.rb +93 -0
  298. data/lib/badline/plus4/keyboard_port.rb +51 -0
  299. data/lib/badline/plus4/model.rb +38 -0
  300. data/lib/badline/plus4/user_port.rb +31 -0
  301. data/lib/badline/plus4.rb +164 -0
  302. data/lib/badline/roms/README +44 -6
  303. data/lib/badline/roms/plus4/basic.rom +0 -0
  304. data/lib/badline/roms/plus4/function-high.rom +0 -0
  305. data/lib/badline/roms/plus4/function-low.rom +0 -0
  306. data/lib/badline/roms/plus4/kernal-ntsc.rom +0 -0
  307. data/lib/badline/roms/plus4/kernal-pal.rom +0 -0
  308. data/lib/badline/sdl.rb +1 -0
  309. data/lib/badline/{storage/sid_file.rb → sid_tune/file.rb} +3 -3
  310. data/lib/badline/{storage → sid_tune}/hvsc.rb +7 -7
  311. data/lib/badline/{storage → sid_tune}/song_lengths.rb +2 -2
  312. data/lib/badline/{storage → sid_tune}/stil/credit.rb +1 -1
  313. data/lib/badline/{storage → sid_tune}/stil.rb +3 -3
  314. data/lib/badline/sid_tune.rb +6 -0
  315. data/lib/badline/snapshot/c128_setup.rb +32 -0
  316. data/lib/badline/snapshot/c64_setup.rb +83 -0
  317. data/lib/badline/snapshot/container.rb +4 -0
  318. data/lib/badline/snapshot/field_doc/markdown.rb +112 -0
  319. data/lib/badline/snapshot/field_doc.rb +109 -0
  320. data/lib/badline/snapshot/image.rb +132 -46
  321. data/lib/badline/snapshot/keyed/cursor.rb +40 -0
  322. data/lib/badline/snapshot/keyed/modules.rb +66 -0
  323. data/lib/badline/snapshot/keyed/reader.rb +188 -0
  324. data/lib/badline/snapshot/keyed/recorder.rb +88 -0
  325. data/lib/badline/snapshot/keyed/report.rb +26 -0
  326. data/lib/badline/snapshot/keyed/writer.rb +55 -0
  327. data/lib/badline/snapshot/keyed.rb +64 -0
  328. data/lib/badline/snapshot/machine_state.rb +17 -64
  329. data/lib/badline/snapshot/storage_setup.rb +63 -0
  330. data/lib/badline/snapshot/vic20_setup.rb +28 -0
  331. data/lib/badline/snapshot/vice/c64_mem.rb +1 -1
  332. data/lib/badline/snapshot/vice/restore.rb +1 -1
  333. data/lib/badline/snapshot/vice/reu1764.rb +3 -3
  334. data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
  335. data/lib/badline/snapshot/vice.rb +13 -35
  336. data/lib/badline/snapshot.rb +44 -22
  337. data/lib/badline/storage/crt_file.rb +3 -1
  338. data/lib/badline/storage/d64_image.rb +0 -2
  339. data/lib/badline/storage/d71_image.rb +0 -2
  340. data/lib/badline/storage/d81_image.rb +0 -2
  341. data/lib/badline/storage/disk_image.rb +3 -6
  342. data/lib/badline/storage/g64_image.rb +10 -5
  343. data/lib/badline/storage/host_directory.rb +0 -5
  344. data/lib/badline/storage/t64.rb +2 -8
  345. data/lib/badline/storage/tap.rb +43 -15
  346. data/lib/badline/storage/unavailable.rb +1 -1
  347. data/lib/badline/storage.rb +0 -37
  348. data/lib/badline/support/c128_checkpoint.rb +39 -0
  349. data/lib/badline/support/checkpoint.rb +108 -0
  350. data/lib/badline/support/vic20_checkpoint.rb +38 -0
  351. data/lib/badline/support.rb +5 -0
  352. data/lib/badline/version.rb +1 -1
  353. data/lib/badline/vic20/attachments.rb +8 -5
  354. data/lib/badline/vic20/bus/keyed_state.rb +52 -0
  355. data/lib/badline/vic20/bus.rb +2 -25
  356. data/lib/badline/vic20/cpu.rb +1 -1
  357. data/lib/badline/vic20/keyed_modules.rb +73 -0
  358. data/lib/badline/vic20/keyed_state.rb +45 -0
  359. data/lib/badline/vic20/port_wiring.rb +4 -4
  360. data/lib/badline/vic20/user_via_ports.rb +2 -2
  361. data/lib/badline/vic20.rb +22 -17
  362. data/lib/badline.rb +1 -0
  363. metadata +271 -228
  364. data/lib/badline/address_bus/extra_sids.rb +0 -30
  365. data/lib/badline/address_bus/fittings.rb +0 -38
  366. data/lib/badline/address_bus/pla.rb +0 -147
  367. data/lib/badline/address_bus/roms.rb +0 -39
  368. data/lib/badline/address_bus/saved_state.rb +0 -66
  369. data/lib/badline/address_bus/sid_slots.rb +0 -42
  370. data/lib/badline/address_bus.rb +0 -216
  371. data/lib/badline/c128/bus_state.rb +0 -53
  372. data/lib/badline/c128/saved_state.rb +0 -143
  373. data/lib/badline/cartridge/action_replay.rb +0 -126
  374. data/lib/badline/cartridge/atomic_power.rb +0 -24
  375. data/lib/badline/cartridge/bank.rb +0 -81
  376. data/lib/badline/cartridge/comal80.rb +0 -50
  377. data/lib/badline/cartridge/dinamic.rb +0 -34
  378. data/lib/badline/cartridge/easy_flash.rb +0 -145
  379. data/lib/badline/cartridge/epyx_fastload.rb +0 -79
  380. data/lib/badline/cartridge/final_cartridge3.rb +0 -89
  381. data/lib/badline/cartridge/flash.rb +0 -306
  382. data/lib/badline/cartridge/freezer.rb +0 -33
  383. data/lib/badline/cartridge/fun_play.rb +0 -38
  384. data/lib/badline/cartridge/g_mod2.rb +0 -74
  385. data/lib/badline/cartridge/game_system.rb +0 -40
  386. data/lib/badline/cartridge/geo_ram.rb +0 -79
  387. data/lib/badline/cartridge/kcs_power.rb +0 -75
  388. data/lib/badline/cartridge/mach5.rb +0 -32
  389. data/lib/badline/cartridge/magic_desk.rb +0 -30
  390. data/lib/badline/cartridge/ocean.rb +0 -35
  391. data/lib/badline/cartridge/pagefox.rb +0 -68
  392. data/lib/badline/cartridge/retro_replay.rb +0 -320
  393. data/lib/badline/cartridge/rex_utility.rb +0 -29
  394. data/lib/badline/cartridge/rgcd.rb +0 -58
  395. data/lib/badline/cartridge/simons_basic.rb +0 -35
  396. data/lib/badline/cartridge/standard.rb +0 -15
  397. data/lib/badline/cartridge/super_games.rb +0 -48
  398. data/lib/badline/cartridge/westermann.rb +0 -30
  399. data/lib/badline/cartridge/zaxxon.rb +0 -66
  400. data/lib/badline/cartridge.rb +0 -303
  401. data/lib/badline/checkpoint.rb +0 -98
  402. data/lib/badline/chrout_trap.rb +0 -43
  403. data/lib/badline/cia/fast_forward.rb +0 -60
  404. data/lib/badline/cia/interrupt_register.rb +0 -143
  405. data/lib/badline/cia/serial.rb +0 -275
  406. data/lib/badline/cia/state.rb +0 -47
  407. data/lib/badline/cia/timer.rb +0 -206
  408. data/lib/badline/cia.rb +0 -279
  409. data/lib/badline/color_memory.rb +0 -25
  410. data/lib/badline/computer/attachments.rb +0 -88
  411. data/lib/badline/computer/saved_state.rb +0 -117
  412. data/lib/badline/computer/true_drives.rb +0 -69
  413. data/lib/badline/control_ports.rb +0 -76
  414. data/lib/badline/cpu/addressing.rb +0 -131
  415. data/lib/badline/cpu/boundary.rb +0 -54
  416. data/lib/badline/cpu/core.rb +0 -165
  417. data/lib/badline/cpu/microcode.rb +0 -177
  418. data/lib/badline/cpu/operations.rb +0 -88
  419. data/lib/badline/cpu/saved_state.rb +0 -115
  420. data/lib/badline/cpu/stack_operations.rb +0 -82
  421. data/lib/badline/cpu.rb +0 -10
  422. data/lib/badline/cpu_port.rb +0 -112
  423. data/lib/badline/datasette.rb +0 -161
  424. data/lib/badline/debug_register.rb +0 -28
  425. data/lib/badline/drive/core.rb +0 -147
  426. data/lib/badline/drive/fast_serial.rb +0 -73
  427. data/lib/badline/drive/idle.rb +0 -125
  428. data/lib/badline/drive/idle_cpu.rb +0 -28
  429. data/lib/badline/drive/orbit.rb +0 -79
  430. data/lib/badline/drive/serial_lines.rb +0 -73
  431. data/lib/badline/drive/sleep.rb +0 -112
  432. data/lib/badline/drive/vias.rb +0 -84
  433. data/lib/badline/drive/watch.rb +0 -150
  434. data/lib/badline/drive.rb +0 -11
  435. data/lib/badline/drive1541/bus.rb +0 -86
  436. data/lib/badline/drive1541/byte_ready.rb +0 -48
  437. data/lib/badline/drive1541/cpu.rb +0 -11
  438. data/lib/badline/drive1541/disk.rb +0 -315
  439. data/lib/badline/drive1541/disk_state.rb +0 -86
  440. data/lib/badline/drive1541/disk_via.rb +0 -36
  441. data/lib/badline/drive1541/gcr.rb +0 -57
  442. data/lib/badline/drive1541/mechanism.rb +0 -313
  443. data/lib/badline/drive1541/mechanism_state.rb +0 -68
  444. data/lib/badline/drive1541/rotation.rb +0 -121
  445. data/lib/badline/drive1541/sector_reader.rb +0 -76
  446. data/lib/badline/drive1541/serial_port.rb +0 -18
  447. data/lib/badline/drive1541/track.rb +0 -98
  448. data/lib/badline/drive1541.rb +0 -111
  449. data/lib/badline/drive1571/bus.rb +0 -111
  450. data/lib/badline/drive1571/cpu.rb +0 -11
  451. data/lib/badline/drive1571/serial_port.rb +0 -37
  452. data/lib/badline/drive1571/serial_via.rb +0 -25
  453. data/lib/badline/drive1571/wd1770.rb +0 -120
  454. data/lib/badline/drive1571.rb +0 -175
  455. data/lib/badline/drive1581/bus.rb +0 -137
  456. data/lib/badline/drive1581/cpu.rb +0 -11
  457. data/lib/badline/drive1581/disk.rb +0 -135
  458. data/lib/badline/drive1581/disk_state.rb +0 -87
  459. data/lib/badline/drive1581/mechanism.rb +0 -117
  460. data/lib/badline/drive1581/serial_port.rb +0 -52
  461. data/lib/badline/drive1581/slot.rb +0 -78
  462. data/lib/badline/drive1581/track.rb +0 -100
  463. data/lib/badline/drive1581/track_bytes.rb +0 -75
  464. data/lib/badline/drive1581/wd1772/registers.rb +0 -89
  465. data/lib/badline/drive1581/wd1772/sector_writes.rb +0 -73
  466. data/lib/badline/drive1581/wd1772/sectors.rb +0 -150
  467. data/lib/badline/drive1581/wd1772/state.rb +0 -66
  468. data/lib/badline/drive1581/wd1772/stepping.rb +0 -109
  469. data/lib/badline/drive1581/wd1772/tracks.rb +0 -125
  470. data/lib/badline/drive1581/wd1772/turn.rb +0 -73
  471. data/lib/badline/drive1581/wd1772.rb +0 -216
  472. data/lib/badline/drive1581.rb +0 -233
  473. data/lib/badline/iec_bus.rb +0 -159
  474. data/lib/badline/instruction.rb +0 -334
  475. data/lib/badline/instruction_set/arithmetic.rb +0 -114
  476. data/lib/badline/instruction_set/bitwise.rb +0 -126
  477. data/lib/badline/instruction_set/branch.rb +0 -79
  478. data/lib/badline/instruction_set/flag.rb +0 -63
  479. data/lib/badline/instruction_set/illegal.rb +0 -270
  480. data/lib/badline/instruction_set/inc_dec.rb +0 -69
  481. data/lib/badline/instruction_set/stack.rb +0 -52
  482. data/lib/badline/instruction_set/transfer.rb +0 -137
  483. data/lib/badline/instruction_set.rb +0 -55
  484. data/lib/badline/interrupts.rb +0 -104
  485. data/lib/badline/joystick.rb +0 -25
  486. data/lib/badline/kernal_trap/channel.rb +0 -181
  487. data/lib/badline/keyboard.rb +0 -112
  488. data/lib/badline/keyboard_buffer.rb +0 -33
  489. data/lib/badline/ram_expansion/banking.rb +0 -30
  490. data/lib/badline/ram_expansion/plus256k.rb +0 -54
  491. data/lib/badline/ram_expansion/plus60k.rb +0 -43
  492. data/lib/badline/ram_expansion/unexpanded.rb +0 -28
  493. data/lib/badline/ram_expansion.rb +0 -21
  494. data/lib/badline/reu/dma/saved_state.rb +0 -50
  495. data/lib/badline/reu/dma.rb +0 -273
  496. data/lib/badline/reu/ram.rb +0 -107
  497. data/lib/badline/reu/saved_state.rb +0 -80
  498. data/lib/badline/reu/trigger.rb +0 -32
  499. data/lib/badline/reu.rb +0 -289
  500. data/lib/badline/sid/catch_up.rb +0 -120
  501. data/lib/badline/sid/decimator.rb +0 -64
  502. data/lib/badline/sid/envelope/state.rb +0 -68
  503. data/lib/badline/sid/envelope.rb +0 -239
  504. data/lib/badline/sid/filter.rb +0 -263
  505. data/lib/badline/sid/voice.rb +0 -77
  506. data/lib/badline/sid/waveform/combined.rb +0 -126
  507. data/lib/badline/sid/waveform/fast_forward.rb +0 -105
  508. data/lib/badline/sid/waveform/noise_writeback.rb +0 -122
  509. data/lib/badline/sid/waveform/state.rb +0 -66
  510. data/lib/badline/sid/waveform.rb +0 -305
  511. data/lib/badline/sid.rb +0 -303
  512. data/lib/badline/snapshot/setup.rb +0 -75
  513. data/lib/badline/snapshot/state.rb +0 -189
  514. data/lib/badline/time_of_day.rb +0 -228
  515. data/lib/badline/traps.rb +0 -19
  516. data/lib/badline/via/control_lines.rb +0 -122
  517. data/lib/badline/via/fast_forward.rb +0 -53
  518. data/lib/badline/via/interrupt_register.rb +0 -67
  519. data/lib/badline/via/shift_register.rb +0 -180
  520. data/lib/badline/via/state.rb +0 -42
  521. data/lib/badline/via/timer1.rb +0 -131
  522. data/lib/badline/via/timer2.rb +0 -133
  523. data/lib/badline/via.rb +0 -266
  524. data/lib/badline/vic/bank.rb +0 -133
  525. data/lib/badline/vic/border_mask.rb +0 -86
  526. data/lib/badline/vic/collisions.rb +0 -115
  527. data/lib/badline/vic/color_patches.rb +0 -47
  528. data/lib/badline/vic/display_state.rb +0 -185
  529. data/lib/badline/vic/graphics_mode.rb +0 -164
  530. data/lib/badline/vic/graphics_shifter.rb +0 -207
  531. data/lib/badline/vic/register_log.rb +0 -81
  532. data/lib/badline/vic/registers.rb +0 -195
  533. data/lib/badline/vic/sequencer.rb +0 -275
  534. data/lib/badline/vic/sequencer_output.rb +0 -116
  535. data/lib/badline/vic/sequencer_state.rb +0 -89
  536. data/lib/badline/vic/sprite/internal_bus.rb +0 -68
  537. data/lib/badline/vic/sprite/saved_state.rb +0 -64
  538. data/lib/badline/vic/sprite/shifter.rb +0 -146
  539. data/lib/badline/vic/sprite/timing.rb +0 -56
  540. data/lib/badline/vic/sprite.rb +0 -337
  541. data/lib/badline/vic/sprites.rb +0 -282
  542. data/lib/badline/vic/sprites_state.rb +0 -57
  543. data/lib/badline/vic.rb +0 -853
  544. data/lib/badline/vic20/saved_state.rb +0 -124
  545. data/lib/badline/vic20/sound/output.rb +0 -83
  546. data/lib/badline/vic20/sound.rb +0 -233
  547. data/lib/badline/vic20/vic/saved_state.rb +0 -55
  548. data/lib/badline/z80/arithmetic.rb +0 -117
  549. data/lib/badline/z80/bit_page.rb +0 -55
  550. data/lib/badline/z80/block_io.rb +0 -58
  551. data/lib/badline/z80/block_transfers.rb +0 -59
  552. data/lib/badline/z80/bus_cycles.rb +0 -111
  553. data/lib/badline/z80/core.rb +0 -113
  554. data/lib/badline/z80/exchanges.rb +0 -50
  555. data/lib/badline/z80/extended_page.rb +0 -89
  556. data/lib/badline/z80/flags.rb +0 -37
  557. data/lib/badline/z80/interrupt_acceptance.rb +0 -46
  558. data/lib/badline/z80/jumps.rb +0 -82
  559. data/lib/badline/z80/loads.rb +0 -98
  560. data/lib/badline/z80/main_page.rb +0 -134
  561. data/lib/badline/z80/registers.rb +0 -120
  562. data/lib/badline/z80/saved_state.rb +0 -69
  563. data/lib/badline/z80/shifts.rb +0 -64
  564. data/lib/badline/z80.rb +0 -11
  565. /data/lib/badline/snapshot/{fields.rb → vice/fields.rb} +0 -0
@@ -0,0 +1,80 @@
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/keyed_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
+
23
+ CLOCK_HZ = 1_000_000
24
+
25
+ # Where the DOS 2.6 idle loop starts over (see Drives::Engine::Idle).
26
+ IDLE_LOOP = 0xebff
27
+
28
+ def model_name = "1541"
29
+
30
+ # +rom+ covers $C000-$FFFF, and defaults to the DOS image in the ROM
31
+ # path. +device+ is the number the jumpers on VIA 1's PB5 and PB6 set,
32
+ # 8 to 11.
33
+ def initialize(rom: nil, host_clock_hz: CLOCK_HZ, device: 8, debug: false)
34
+ @device = device
35
+ @serial_port = SerialPort.new(device:)
36
+ @via1 = Chips::VIA.new(start: 0x1800, peripheral: @serial_port)
37
+ @mechanism = Mechanism.new
38
+ @via2 = DiskVIA.new(start: 0x1c00, mechanism: @mechanism)
39
+ @bus = Bus.new(rom: rom || ROM.load("dos1541.rom", 0xc000), via1: @via1, via2: @via2)
40
+ @cpu = CPU.new(@bus, debug:)
41
+ @clock_hz = CLOCK_HZ
42
+ @idle_loop = IDLE_LOOP
43
+ @host_clock_hz = host_clock_hz
44
+ @phase = 0
45
+ @cycles = 0
46
+ @serial_bus = nil
47
+ init_idle(debug)
48
+ # CA1 powers up at the level of a released ATN, without an edge.
49
+ @via1.ca1 = false
50
+ @via1.reset!
51
+ connect(SerialBus.new)
52
+ end
53
+
54
+ private
55
+
56
+ # One drive cycle. The VIAs clock ahead of the CPU, as the C64's chips
57
+ # do, and either one pulls IRQ. Nothing drives NMI on the 1541. The CPU
58
+ # runs whether or not the motor turns, since it answers ATN.
59
+ #
60
+ # The disk mechanism runs first, so BYTE READY lands on the VIA ahead
61
+ # of the CPU's cycle. The CPU samples SO a cycle late: BYTE READY sets
62
+ # V for the next cycle's instruction step.
63
+ #
64
+ # ATN reaches VIA 1's CA1 through the same inverter as PB7, so CA1 goes
65
+ # high as the C64 asserts ATN, as the serial port sees it: from the
66
+ # host cycle after the one that asserts it.
67
+ def step
68
+ so = @mechanism.take_so
69
+ @mechanism.cycle!
70
+ @via1.ca1 = @serial_port.atn_low?
71
+ @via1.cycle!
72
+ @via2.cycle!
73
+ @cpu.irq = @via1.irq? || @via2.irq?
74
+ @cpu.so! if so
75
+ @cpu.cycle!
76
+ @cycles += 1
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,100 @@
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
+ def peek(addr)
44
+ return @data = @rom.peek(addr) if addr >= 0x8000
45
+ return @data = chip_peek(addr) if addr >= 0x2000
46
+
47
+ watch_read(addr) if @watching
48
+ @data = if addr < 0x0800
49
+ @ram.peek(addr)
50
+ elsif addr < 0x1800
51
+ @data
52
+ elsif addr < 0x1c00
53
+ @via1.peek(addr)
54
+ else
55
+ @mechanism.release_byte_latch
56
+ @via2.peek(addr)
57
+ end
58
+ end
59
+
60
+ def poke(addr, value)
61
+ @data = value
62
+ return if addr >= 0x8000
63
+ return chip_poke(addr, value) if addr >= 0x2000
64
+
65
+ low_poke(addr, value)
66
+ end
67
+
68
+ private
69
+
70
+ # A write below $2000: RAM or a VIA.
71
+ def low_poke(addr, value)
72
+ if addr < 0x0800
73
+ touch(addr) if @recording
74
+ @ram.poke(addr, value)
75
+ elsif addr >= 0x1c00
76
+ @mechanism.release_byte_latch
77
+ @via2.poke(addr, value)
78
+ elsif addr >= 0x1800
79
+ @via1.poke(addr, value)
80
+ end
81
+ watch_write(addr) if @watching
82
+ end
83
+
84
+ def chip_peek(addr)
85
+ watch_chip if @watching
86
+ addr >= 0x4000 ? @cia.peek(0x4000 | (addr & 0x0f)) : @fdc.peek(addr & 0x03)
87
+ end
88
+
89
+ def chip_poke(addr, value)
90
+ if addr >= 0x4000
91
+ @cia.poke(0x4000 | (addr & 0x0f), value)
92
+ else
93
+ @fdc.poke(addr & 0x03, value)
94
+ end
95
+ watch_chip if @watching
96
+ end
97
+ end
98
+ end
99
+ end
100
+ 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,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ class Model1571
6
+ class WD1770
7
+ # The controller's registers, status and result in a keyed snapshot
8
+ # module (BL-D8-FDC), and how many of the drive CPU's cycles until a
9
+ # command under way finishes. It loads after the CPU, which that
10
+ # counts from.
11
+ def save_fields(out)
12
+ out.ints("registers", @registers).int("status", @status).int("result", @result)
13
+ out.int("due_in", @due - @cpu.cycles)
14
+ end
15
+
16
+ def load_fields(input)
17
+ input.ints_into("registers", @registers)
18
+ @status = input.byte("status", @status)
19
+ @result = input.int("result", @result)
20
+ @due = @cpu.cycles + input.int("due_in", @due - @cpu.cycles)
21
+ end
22
+ end
23
+
24
+ class Bus
25
+ # The drive's RAM and the byte last on its data bus, in a keyed
26
+ # snapshot module (BL-D8-RAM).
27
+ def save_fields(out)
28
+ out.int("data", @data).bytes("ram", @ram.read(0, @ram.length))
29
+ end
30
+
31
+ def load_fields(input)
32
+ @data = input.byte("data", @data)
33
+ ram = @ram.read(0, @ram.length)
34
+ @ram.write(0, input.bytes_into("ram", ram))
35
+ @watching = false
36
+ end
37
+ end
38
+
39
+ # The drive's own fields in a keyed snapshot module (BL-D8), as the
40
+ # 1541's. The clock rate, the side and the fast serial direction come
41
+ # from VIA 1's port A once the VIAs are loaded.
42
+ module KeyedState
43
+ def save_fields(out)
44
+ settle!
45
+ out.text("model", model_name).int("phase", @phase).int("cycles", @cycles)
46
+ out.bool("so_pending", @mechanism.so_pending)
47
+ @serial_port.save_fields(out, "serial.")
48
+ out
49
+ end
50
+
51
+ def load_fields(input)
52
+ settle!
53
+ input.choice("model", [model_name], model_name)
54
+ @phase = input.int("phase", @phase)
55
+ @cycles = input.int("cycles", @cycles)
56
+ @mechanism.so_pending = input.bool("so_pending", @mechanism.so_pending)
57
+ @serial_port.load_fields(input, "serial.")
58
+ end
59
+
60
+ def restored!
61
+ @fast_serial_out = @via1.port_a_output.anybits?(FAST_SERIAL_OUT)
62
+ port_a_written(@via1.port_a_output)
63
+ push_fast_output(@fast_serial_out ? fast_pins : 0)
64
+ forget_orbits
65
+ end
66
+
67
+ # The drive as modules of its own, as the 1541's, with the CIA and
68
+ # the WD1770.
69
+ def save_modules(sections, name)
70
+ sections << Snapshot::Keyed.section(name) { |out| save_fields(out) }
71
+ sections << Snapshot::Keyed.section("#{name}-RAM") { |out| @bus.save_fields(out) }
72
+ sections << Snapshot::Keyed.section("#{name}-VIA1") { |out| @via1.save_fields(out) }
73
+ sections << Snapshot::Keyed.section("#{name}-VIA2") { |out| @via2.save_fields(out) }
74
+ sections << Snapshot::Keyed.section("#{name}-CIA") { |out| @cia.save_fields(out) }
75
+ sections << Snapshot::Keyed.section("#{name}-CPU") { |out| @cpu.save_fields(out) }
76
+ sections << Snapshot::Keyed.section("#{name}-FDC") { |out| @fdc.save_fields(out) }
77
+ sections << Snapshot::Keyed.section("#{name}-MECH") { |out| @mechanism.save_fields(out) }
78
+ disk = @mechanism.disk
79
+ sections << Snapshot::Keyed.section("#{name}-DISK") { |out| disk.save_fields(out) } if disk
80
+ sections
81
+ end
82
+
83
+ # The drive from its modules, `input` being its own. The WD1770
84
+ # counts from the CPU's cycles, so it loads after the CPU.
85
+ def load_modules(modules, input, name)
86
+ load_fields(input)
87
+ @bus.load_fields(modules.required("#{name}-RAM"))
88
+ @via1.load_fields(modules.required("#{name}-VIA1"))
89
+ @via2.load_fields(modules.required("#{name}-VIA2"))
90
+ @cia.load_fields(modules.required("#{name}-CIA"))
91
+ @cpu.load_fields(modules.required("#{name}-CPU"))
92
+ @fdc.load_fields(modules.required("#{name}-FDC"))
93
+ disk = modules.optional("#{name}-DISK")
94
+ mechanism = modules.required("#{name}-MECH")
95
+ @mechanism.load_fields(mechanism,
96
+ disk.nil? ? nil : Model1541::Disk.from_fields(disk, detached: modules.detached?))
97
+ @via1.restored!
98
+ @via2.restored!
99
+ @cia.restored!
100
+ @cpu.restored!
101
+ restored!
102
+ end
103
+ end
104
+
105
+ include KeyedState
106
+ end
107
+ end
108
+ 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,108 @@
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
+ private
58
+
59
+ def command(value)
60
+ return interrupt if (value & 0xf0) == 0xd0
61
+
62
+ @registers[0] = value
63
+ value < 0x80 ? step(value) : search(value)
64
+ end
65
+
66
+ # A restore ($0x), seek ($1x) or step ($2x to $7x), its track register
67
+ # moved at once.
68
+ def step(value)
69
+ track = @registers[1]
70
+ target = case value >> 4
71
+ when 0 then 0
72
+ when 1 then @registers[3]
73
+ else track + step_direction(value)
74
+ end
75
+ @registers[1] = target.clamp(0, 255) if value < 0x20 || value.anybits?(0x10)
76
+ start(STEP * [(target - track).abs, 1].max, @registers[1].zero? ? TRACK0 : 0)
77
+ end
78
+
79
+ # Step in ($4x) moves toward higher tracks, step out ($6x) toward
80
+ # track 0, and step ($2x) the way the last one went.
81
+ def step_direction(value)
82
+ @direction = 1 if (value >> 5) == 2
83
+ @direction = -1 if (value >> 5) == 3
84
+ @direction || 1
85
+ end
86
+
87
+ # A sector or track command that finds no MFM sector.
88
+ def search(value)
89
+ value >= 0xf0 ? start(TURN, 0) : start(TURN * 5, NOT_FOUND)
90
+ end
91
+
92
+ def start(cycles, result)
93
+ @status = BUSY | MOTOR_ON
94
+ @due = @cpu.cycles + cycles
95
+ @result = result
96
+ end
97
+
98
+ def finish
99
+ @status = @result
100
+ end
101
+
102
+ def interrupt
103
+ @status &= ~BUSY & 0xff
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,141 @@
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/keyed_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
+
32
+ CLOCK_HZ = 1_000_000
33
+ FAST_CLOCK_HZ = 2_000_000
34
+
35
+ # Where the DOS 3.0 idle loop starts over, as DOS 2.6's does.
36
+ IDLE_LOOP = 0xebff
37
+
38
+ # VIA 1's port A outputs.
39
+ FAST_SERIAL_OUT = 0x02
40
+ SIDE = 0x04
41
+ FAST = 0x20
42
+
43
+ def cia
44
+ settle!
45
+ @cia
46
+ end
47
+
48
+ def fdc
49
+ settle!
50
+ @fdc
51
+ end
52
+
53
+ def model_name = "1571"
54
+
55
+ # +rom+ covers $8000-$FFFF, and defaults to the DOS image in the ROM
56
+ # path. +device+ is the number the jumpers on VIA 1's PB5 and PB6 set,
57
+ # 8 to 11.
58
+ def initialize(rom: nil, host_clock_hz: CLOCK_HZ, device: 8, debug: false)
59
+ @device = device
60
+ @clock_hz = CLOCK_HZ
61
+ init_fast_serial
62
+ @mechanism = Model1541::Mechanism.new(slip: 2)
63
+ @serial_port = SerialPort.new(@mechanism, device:)
64
+ @via1 = SerialVIA.new(start: 0x1800, peripheral: @serial_port, drive: self)
65
+ @via2 = Model1541::DiskVIA.new(start: 0x1c00, mechanism: @mechanism)
66
+ @cia = Chips::CIA.new(start: 0x4000)
67
+ @fdc = WD1770.new
68
+ @bus = Bus.new(rom: rom || ROM.load("dos1571.rom", 0x8000), via1: @via1, via2: @via2, cia: @cia, fdc: @fdc)
69
+ @cpu = CPU.new(@bus, debug:)
70
+ @fdc.cpu = @cpu
71
+ @idle_loop = IDLE_LOOP
72
+ @host_clock_hz = host_clock_hz
73
+ @phase = 0
74
+ @cycles = 0
75
+ @serial_bus = nil
76
+ init_idle(debug)
77
+ # CA1 powers up at the level of a released ATN, without an edge.
78
+ @via1.ca1 = false
79
+ @via1.reset!
80
+ connect(SerialBus.new)
81
+ end
82
+
83
+ # The serial bus's RESET line reaches the CPU, both VIAs and the CIA.
84
+ # RAM keeps its contents.
85
+ def reset!
86
+ settle!
87
+ @via1.reset!
88
+ @via2.reset!
89
+ @cia.reset!
90
+ @cpu.reset!
91
+ end
92
+
93
+ # VIA 1 drives port A to +lines+: the side, the clock rate and the fast
94
+ # serial direction follow it.
95
+ def port_a_written(lines)
96
+ @mechanism.side = lines.anybits?(SIDE) ? 1 : 0
97
+ fast_serial_out = lines.anybits?(FAST_SERIAL_OUT)
98
+ turn_fast_serial(fast_serial_out) if fast_serial_out != @fast_serial_out
99
+ clock_hz = lines.anybits?(FAST) ? FAST_CLOCK_HZ : CLOCK_HZ
100
+ return if clock_hz == @clock_hz
101
+
102
+ @clock_hz = clock_hz
103
+ @mechanism.clock_hz = clock_hz
104
+ end
105
+
106
+ # Whether the drive runs at 2 MHz.
107
+ def fast? = @clock_hz == FAST_CLOCK_HZ
108
+
109
+ # VIA 1's port B, with the fast serial pins pulling DATA and SRQ
110
+ # (Drives::SerialBus::DRIVE_FAST_DATA and DRIVE_FAST_SRQ) above it.
111
+ def serial_output = @via1.port_b_output | @fast_output
112
+
113
+ private
114
+
115
+ # One drive cycle, as the 1541's (Drives::Model1541#step), with the CIA
116
+ # clocked beside the VIAs and pulling IRQ with them.
117
+ def step
118
+ so = @mechanism.take_so
119
+ @mechanism.cycle!
120
+ @via1.ca1 = @serial_port.atn_low?
121
+ @via1.cycle!
122
+ @via2.cycle!
123
+ @cia.cycle!
124
+ drive_fast_serial if @fast_serial_out
125
+ @cpu.irq = @via1.irq? || @via2.irq? || @cia.interrupted?
126
+ @cpu.so! if so
127
+ @cpu.cycle!
128
+ @cycles += 1
129
+ end
130
+
131
+ # The VIAs' quiet cycles while the CIA is quiet, and none otherwise.
132
+ def quiet_cycles
133
+ @cia.quiet? ? [@via1.quiet_cycles, @via2.quiet_cycles].min : 0
134
+ end
135
+
136
+ def fast_forward_more(cycles)
137
+ @cia.fast_forward(cycles)
138
+ end
139
+ end
140
+ end
141
+ end