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
@@ -1,76 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Drive1541
5
- # Reads a track's blocks back out of its GCR, as the DOS finds them:
6
- # each SYNC mark is ten or more 1 bits, and the block after it starts
7
- # at the first 0 bit. Writes land wherever the head was, so a block
8
- # can start at any bit of the stored bytes, and the reader works on
9
- # the bits.
10
- #
11
- # A header block starts with $08, and the next block after a header is
12
- # that sector's data block, whatever it holds.
13
- module SectorReader
14
- HEADER_BITS = 10 * 8
15
- DATA_BITS = 325 * 8
16
- SYNC = /1{10,}/
17
-
18
- # A sector as read: its decoded header, [ID, checksum, sector, track,
19
- # the second ID byte, the first, ...], and its decoded data block,
20
- # [ID, 256 data bytes, checksum, ...], nil when there isn't one that
21
- # decodes.
22
- Sector = Struct.new(:header, :data)
23
-
24
- module_function
25
-
26
- # The sectors found on the track's bytes, by sector number. Headers
27
- # for another track are left out.
28
- def read(bytes, track)
29
- ring = ring(bytes)
30
- return {} unless ring
31
-
32
- sectors = {}
33
- each_block(ring) do |header, data|
34
- next unless header[3] == track
35
-
36
- sectors[header[2]] ||= Sector.new(header, data)
37
- end
38
- sectors
39
- end
40
-
41
- # The track's bits, starting at a 0 bit so no SYNC mark straddles the
42
- # start, twice over so a block can run on past the end. Nil for a
43
- # track without a 0 bit.
44
- def ring(bytes)
45
- bits = bytes.pack("C*").unpack1("B*")
46
- zero = bits.index("0")
47
- return unless zero
48
-
49
- bits = bits[zero..] + bits[0, zero]
50
- [bits * 2, bits.length]
51
- end
52
-
53
- # Yields each header whose SYNC mark starts in the first turn, with
54
- # the data block after it.
55
- def each_block(ring)
56
- bits, length = ring
57
- pos = 0
58
- while (sync = SYNC.match(bits, pos)) && sync.begin(0) < length
59
- pos = sync.end(0)
60
- header = decode(bits, pos, HEADER_BITS)
61
- next unless header && header[0] == Disk::HEADER_ID
62
-
63
- data_sync = SYNC.match(bits, pos + HEADER_BITS)
64
- yield header, data_sync && decode(bits, data_sync.end(0), DATA_BITS)
65
- end
66
- end
67
-
68
- def decode(bits, pos, count)
69
- slice = bits[pos, count]
70
- return unless slice.length == count
71
-
72
- GCR.decode([slice].pack("B*").bytes)
73
- end
74
- end
75
- end
76
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Drive1541
5
- # What VIA 1's ports read from outside the chip. Port B carries the
6
- # serial bus inputs and the device number jumpers (Drive::SerialLines);
7
- # port A goes to the unused parallel header and floats high.
8
- class SerialPort
9
- include Drive::SerialLines
10
-
11
- def initialize(device: 8, bus: IECBus.new)
12
- init_serial_lines(device, bus)
13
- end
14
-
15
- def read_a(_lines) = 0xff
16
- end
17
- end
18
- end
@@ -1,98 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Drive1541
5
- # One ring of flux on the disk, as the GCR bytes the head reads from it,
6
- # most significant bit first, and the speed zone it was written in
7
- # (0-3). The bytes wrap around: the last one's bits run into the
8
- # first's. A track is as long as its bytes, which is what a .g64 image
9
- # stores for each half track.
10
- #
11
- # The disk turns at 300 rpm, so every track passes under the head in
12
- # the same 200 ms, and its bits pass at the rate they were written at.
13
- # Each bit is a cell of time, starting at the track's index angle with
14
- # the first byte's top bit, and a 1 bit is a flux transition at the
15
- # start of its cell. The cells are spread evenly over the turn, so a
16
- # track as long as a turn holds at its zone's rate
17
- # (Disk::TRACK_LENGTHS) passes at that rate, within the part of a byte
18
- # the length rounds off, and a longer or shorter one faster or slower.
19
- # A .g64 speed map gives each byte the zone it was written in, and the
20
- # cells of each byte are as wide as their zone's, scaled together to
21
- # fill the turn.
22
- #
23
- # Times are in TICKs, 1/65536 of a tick of the drive's 16 MHz crystal,
24
- # so the cells add up to a turn within a tick.
25
- class Track
26
- TICK = 1 << 16
27
- TURN = 200_000 * 16 * TICK
28
-
29
- # A bit cell at the zone's rate, in TICKs.
30
- def self.cell(zone) = 4 * (16 - zone) * TICK
31
-
32
- attr_reader :bytes, :zone, :speeds, :width, :widths
33
-
34
- # +speeds+ holds each byte's zone, where the track's rate changes
35
- # along it.
36
- def initialize(bytes, zone, speeds = nil)
37
- @bytes = bytes
38
- @zone = zone
39
- @speeds = speeds
40
- @widths = speeds && scaled_widths(speeds)
41
- @width = speeds ? @widths[0] : TURN / (bytes.length * 8)
42
- end
43
-
44
- def length = @bytes.length
45
-
46
- # Whether the whole track was written at the +zone+'s rate.
47
- def written_at?(zone) = @widths.nil? && @zone == zone
48
-
49
- # The bit cell under the head +time+ TICKs into the turn, as
50
- # [byte, mask, the time the cell ends].
51
- def cell_at(time)
52
- start = 0
53
- index = 0
54
- if @widths
55
- while index < length - 1 && time >= start + (@widths[index] * 8)
56
- start += @widths[index] * 8
57
- index += 1
58
- end
59
- else
60
- index = [time / (@width * 8), length - 1].min
61
- start = index * @width * 8
62
- end
63
- width = @widths ? @widths[index] : @width
64
- bit = [(time - start) / width, 7].min
65
- cell_end = index == length - 1 && bit == 7 ? TURN : start + ((bit + 1) * width)
66
- [index, 0x80 >> bit, cell_end]
67
- end
68
-
69
- # The track laid out again as one turn at the +zone+'s rate, each
70
- # flux transition in the cell under it.
71
- def relaid(zone)
72
- bits = Disk::TRACK_LENGTHS[zone] * 8
73
- cell = TURN / bits
74
- relaid = Array.new(bits / 8, 0)
75
- time = 0
76
- @bytes.each_with_index do |byte, index|
77
- width = @widths ? @widths[index] : @width
78
- 8.times do |bit|
79
- if byte.anybits?(0x80 >> bit)
80
- cell_index = [time / cell, bits - 1].min
81
- relaid[cell_index >> 3] |= 0x80 >> (cell_index & 7)
82
- end
83
- time += width
84
- end
85
- end
86
- Track.new(relaid, zone)
87
- end
88
-
89
- private
90
-
91
- def scaled_widths(speeds)
92
- units = 0
93
- speeds.each { |zone| units += 16 - zone }
94
- speeds.map { |zone| TURN * (16 - zone) / (units * 8) }
95
- end
96
- end
97
- end
98
- end
@@ -1,111 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "badline/drive"
4
- require "badline/drive1541/bus"
5
- require "badline/drive1541/cpu"
6
- require "badline/drive1541/serial_port"
7
- require "badline/drive1541/gcr"
8
- require "badline/drive1541/track"
9
- require "badline/drive1541/disk"
10
- require "badline/drive1541/mechanism"
11
- require "badline/drive1541/disk_via"
12
-
13
- module Badline
14
- # The 1541 disk drive as a machine of its own: a 6502 running the DOS
15
- # ROM at 1 MHz, with 2 KB of RAM and two VIAs on its bus. Drive::Core
16
- # clocks it against the host and sleeps through the DOS's idle loop.
17
- class Drive1541
18
- include Drive::Core
19
- include Drive::VIAs
20
-
21
- CLOCK_HZ = 1_000_000
22
-
23
- # Where the DOS 2.6 idle loop starts over (see Drive::Idle).
24
- IDLE_LOOP = 0xebff
25
-
26
- def model_name = "1541"
27
-
28
- # +rom+ covers $C000-$FFFF, and defaults to the DOS image in the ROM
29
- # path. +device+ is the number the jumpers on VIA 1's PB5 and PB6 set,
30
- # 8 to 11.
31
- def initialize(rom: nil, host_clock_hz: CLOCK_HZ, device: 8, debug: false)
32
- @device = device
33
- @serial_port = SerialPort.new(device:)
34
- @via1 = VIA.new(start: 0x1800, peripheral: @serial_port)
35
- @mechanism = Mechanism.new
36
- @via2 = DiskVIA.new(start: 0x1c00, mechanism: @mechanism)
37
- @bus = Bus.new(rom: rom || ROM.load("dos1541.rom", 0xc000), via1: @via1, via2: @via2)
38
- @cpu = CPU.new(@bus, debug:)
39
- @clock_hz = CLOCK_HZ
40
- @idle_loop = IDLE_LOOP
41
- @host_clock_hz = host_clock_hz
42
- @phase = 0
43
- @cycles = 0
44
- @serial_bus = nil
45
- init_idle(debug)
46
- # CA1 powers up at the level of a released ATN, without an edge.
47
- @via1.ca1 = false
48
- @via1.reset!
49
- connect(IECBus.new)
50
- end
51
-
52
- # The drive's whole state: its clock phase, the CPU, RAM, both VIAs,
53
- # the serial port's latch of the C64's lines and the mechanism with its
54
- # disk. The drive settles first, so it is awake and not recording a
55
- # pass, and a restored drive starts the same way, its orbits forgotten
56
- # from the state it takes: Idle's and Orbit's bookkeeping
57
- # isn't stored. The device number, the host's clock rate and whether
58
- # the drive may sleep are the machine's wiring.
59
- def save_state(out)
60
- settle!
61
- out.marker("DRIVE1541")
62
- out.int(@phase).int(@cycles).boolean(@mechanism.so_pending)
63
- @serial_port.save_state(out)
64
- @via1.save_state(out)
65
- @via2.save_state(out)
66
- @bus.save_state(out)
67
- @cpu.save_state(out)
68
- @mechanism.save_state(out)
69
- end
70
-
71
- def load_state(input)
72
- settle!
73
- input.marker("DRIVE1541")
74
- @phase = input.int
75
- @cycles = input.int
76
- @mechanism.so_pending = input.boolean?
77
- @serial_port.load_state(input)
78
- @via1.load_state(input)
79
- @via2.load_state(input)
80
- @bus.load_state(input)
81
- @cpu.load_state(input)
82
- @mechanism.load_state(input)
83
- forget_orbits
84
- end
85
-
86
- private
87
-
88
- # One drive cycle. The VIAs clock ahead of the CPU, as the C64's chips
89
- # do, and either one pulls IRQ. Nothing drives NMI on the 1541. The CPU
90
- # runs whether or not the motor turns, since it answers ATN.
91
- #
92
- # The disk mechanism runs first, so BYTE READY lands on the VIA ahead
93
- # of the CPU's cycle. The CPU samples SO a cycle late: BYTE READY sets
94
- # V for the next cycle's instruction step.
95
- #
96
- # ATN reaches VIA 1's CA1 through the same inverter as PB7, so CA1 goes
97
- # high as the C64 asserts ATN, as the serial port sees it: from the
98
- # host cycle after the one that asserts it.
99
- def step
100
- so = @mechanism.take_so
101
- @mechanism.cycle!
102
- @via1.ca1 = @serial_port.atn_low?
103
- @via1.cycle!
104
- @via2.cycle!
105
- @cpu.irq = @via1.irq? || @via2.irq?
106
- @cpu.so! if so
107
- @cpu.cycle!
108
- @cycles += 1
109
- end
110
- end
111
- end
@@ -1,111 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Drive1571
5
- # The drive CPU's bus:
6
- #
7
- # $0000-$07FF - 2 KB of RAM
8
- # $0800-$17FF - nothing: open bus
9
- # $1800-$1BFF - VIA 1, its sixteen registers mirrored
10
- # $1C00-$1FFF - VIA 2, its sixteen registers mirrored
11
- # $2000-$3FFF - the WD1770, its four registers mirrored
12
- # $4000-$7FFF - the CIA, its sixteen registers mirrored
13
- # $8000-$FFFF - the DOS ROM
14
- #
15
- # Writes to the ROM and to open bus go nowhere, and a read from open
16
- # bus finds the last byte on the data bus, as on the 1541. Any access
17
- # to VIA 2 clears the BYTE READY latch VIA 1's PA7 reads (SerialPort).
18
- #
19
- # While Idle records a pass of the DOS's idle loop, the bus watches it,
20
- # and while Idle looks for an orbit, it guards the drive (see
21
- # Drive::Watch). Any access to the CIA or the WD1770 makes the pass
22
- # volatile and taints the drive.
23
- class Bus
24
- include Addressable
25
- include Drive::Watch
26
-
27
- attr_reader :ram, :rom, :via1, :via2, :cia, :fdc, :data
28
-
29
- def initialize(rom:, via1:, via2:, cia:, fdc:)
30
- addressable_at(0, length: 2**16)
31
- @ram = Memory.new([], length: 0x0800, start: 0)
32
- @rom = rom
33
- @via1 = via1
34
- @via2 = via2
35
- @cia = cia
36
- @fdc = fdc
37
- @mechanism = via2.mechanism
38
- @data = 0
39
- init_watch
40
- end
41
-
42
- # The last byte on the data bus and the RAM. What a watched stretch
43
- # touched is Idle's, and a restored bus isn't watching.
44
- def save_state(out)
45
- out.int(@data)
46
- @ram.save_state(out)
47
- end
48
-
49
- def load_state(input)
50
- @data = input.int
51
- @ram.load_state(input)
52
- @watching = false
53
- end
54
-
55
- def peek(addr)
56
- return @data = @rom.peek(addr) if addr >= 0x8000
57
- return @data = chip_peek(addr) if addr >= 0x2000
58
-
59
- watch_read(addr) if @watching
60
- @data = if addr < 0x0800
61
- @ram.peek(addr)
62
- elsif addr < 0x1800
63
- @data
64
- elsif addr < 0x1c00
65
- @via1.peek(addr)
66
- else
67
- @mechanism.release_byte_latch
68
- @via2.peek(addr)
69
- end
70
- end
71
-
72
- def poke(addr, value)
73
- @data = value
74
- return if addr >= 0x8000
75
- return chip_poke(addr, value) if addr >= 0x2000
76
-
77
- low_poke(addr, value)
78
- end
79
-
80
- private
81
-
82
- # A write below $2000: RAM or a VIA.
83
- def low_poke(addr, value)
84
- if addr < 0x0800
85
- touch(addr) if @recording
86
- @ram.poke(addr, value)
87
- elsif addr >= 0x1c00
88
- @mechanism.release_byte_latch
89
- @via2.poke(addr, value)
90
- elsif addr >= 0x1800
91
- @via1.poke(addr, value)
92
- end
93
- watch_write(addr) if @watching
94
- end
95
-
96
- def chip_peek(addr)
97
- watch_chip if @watching
98
- addr >= 0x4000 ? @cia.peek(0x4000 | (addr & 0x0f)) : @fdc.peek(addr & 0x03)
99
- end
100
-
101
- def chip_poke(addr, value)
102
- if addr >= 0x4000
103
- @cia.poke(0x4000 | (addr & 0x0f), value)
104
- else
105
- @fdc.poke(addr & 0x03, value)
106
- end
107
- watch_chip if @watching
108
- end
109
- end
110
- end
111
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Drive1571
5
- # The drive's 6502, on the drive's Bus.
6
- class CPU
7
- include Badline::CPU::Core
8
- include Drive::IdleCPU
9
- end
10
- end
11
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Drive1571
5
- # What VIA 1's ports read from outside the chip. Port B carries the
6
- # serial bus inputs and the device number jumpers, as on the 1541
7
- # (Drive::SerialLines). Port A reads the mechanism on two inputs:
8
- #
9
- # PA0 track 0 sensor, low while the head sits on track 1
10
- # PA7 BYTE READY, latched low from a whole byte until the CPU next
11
- # reads or writes VIA 2
12
- #
13
- # The DOS steps the head out until PA0 reads low with the stepper on
14
- # phase 0, and polls PA7 for each byte at 2 MHz, taking the byte from
15
- # VIA 2's port A or putting the next one there after each. PA1 (fast serial
16
- # direction), PA2 (side) and PA5 (1 or 2 MHz) are outputs, which
17
- # Drive1571 follows (SerialVIA).
18
- class SerialPort
19
- include Drive::SerialLines
20
-
21
- TRACK0 = 0x01
22
- BYTE_READY = 0x80
23
-
24
- def initialize(mechanism, device: 8, bus: IECBus.new)
25
- @mechanism = mechanism
26
- init_serial_lines(device, bus)
27
- end
28
-
29
- def read_a(_lines)
30
- value = 0xff
31
- value &= ~TRACK0 if @mechanism.half_track == Drive1541::Mechanism::MIN_HALF_TRACK
32
- value &= ~BYTE_READY if @mechanism.byte_latched?
33
- value
34
- end
35
- end
36
- end
37
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Drive1571
5
- # VIA 1, the one facing the serial bus. Its port A also selects the
6
- # side, the clock rate and the fast serial direction, so the drive
7
- # hears port A after every write and reset (Drive1571#port_a_written).
8
- class SerialVIA < VIA
9
- def initialize(start:, peripheral:, drive:)
10
- @drive = drive
11
- super(start:, peripheral:)
12
- end
13
-
14
- def reset!
15
- super
16
- @drive.port_a_written(port_a_output)
17
- end
18
-
19
- def poke(addr, value)
20
- super
21
- @drive.port_a_written(port_a_output)
22
- end
23
- end
24
- end
25
- end
@@ -1,120 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Drive1571
5
- # The WD1770 floppy controller at $2000, which DOS 3.0 drives for MFM
6
- # disks. The 1571 here only ever holds GCR disks, so the controller
7
- # never finds an MFM sector: it runs each command for its time and ends
8
- # it as the WD177x data sheet does on a disk without one.
9
- #
10
- # $2000 status (read), command (write)
11
- # $2001 track
12
- # $2002 sector
13
- # $2003 data
14
- #
15
- # BUSY sets as a command is written. A restore, seek or step (type I)
16
- # moves the track register and ends a few milliseconds later, with
17
- # TRACK 0 reported at track 0. A sector read or write, a read address
18
- # or a read track ends with RECORD NOT FOUND after five turns of the
19
- # disk, and a write track after one, with nothing written. A force
20
- # interrupt ends the command at once. Time is the drive CPU's cycles.
21
- class WD1770
22
- BUSY = 0x01
23
- TRACK0 = 0x04
24
- NOT_FOUND = 0x10
25
- MOTOR_ON = 0x80
26
-
27
- # Cycles at 2 MHz, the 1571's clock in 1571 mode: a turn of the disk
28
- # at 300 rpm, and a step with the head settling.
29
- TURN = 400_000
30
- STEP = 12_000
31
-
32
- # The CPU whose cycles time the commands.
33
- attr_writer :cpu
34
-
35
- def initialize
36
- @registers = [0, 0, 0, 0]
37
- @status = 0
38
- @due = 0
39
- @result = 0
40
- @cpu = nil
41
- end
42
-
43
- # Register +offset+, 0 to 3: the status, settled to the command's end
44
- # once its time has run out.
45
- def peek(offset)
46
- return @registers[offset] unless offset.zero?
47
-
48
- finish if @status.anybits?(BUSY) && @cpu.cycles >= @due
49
- @status
50
- end
51
-
52
- def poke(offset, value)
53
- offset.zero? ? command(value) : @registers[offset] = value
54
- end
55
-
56
- def save_state(out)
57
- out.ints([*@registers, @status, @due, @result])
58
- end
59
-
60
- # A state from before the controller ran commands holds the four
61
- # registers alone.
62
- def load_state(input)
63
- values = input.ints
64
- @registers = values[0, 4]
65
- @status = values[4] || 0
66
- @due = values[5] || 0
67
- @result = values[6] || 0
68
- end
69
-
70
- private
71
-
72
- def command(value)
73
- return interrupt if (value & 0xf0) == 0xd0
74
-
75
- @registers[0] = value
76
- value < 0x80 ? step(value) : search(value)
77
- end
78
-
79
- # A restore ($0x), seek ($1x) or step ($2x to $7x), its track register
80
- # moved at once.
81
- def step(value)
82
- track = @registers[1]
83
- target = case value >> 4
84
- when 0 then 0
85
- when 1 then @registers[3]
86
- else track + step_direction(value)
87
- end
88
- @registers[1] = target.clamp(0, 255) if value < 0x20 || value.anybits?(0x10)
89
- start(STEP * [(target - track).abs, 1].max, @registers[1].zero? ? TRACK0 : 0)
90
- end
91
-
92
- # Step in ($4x) moves toward higher tracks, step out ($6x) toward
93
- # track 0, and step ($2x) the way the last one went.
94
- def step_direction(value)
95
- @direction = 1 if (value >> 5) == 2
96
- @direction = -1 if (value >> 5) == 3
97
- @direction || 1
98
- end
99
-
100
- # A sector or track command that finds no MFM sector.
101
- def search(value)
102
- value >= 0xf0 ? start(TURN, 0) : start(TURN * 5, NOT_FOUND)
103
- end
104
-
105
- def start(cycles, result)
106
- @status = BUSY | MOTOR_ON
107
- @due = @cpu.cycles + cycles
108
- @result = result
109
- end
110
-
111
- def finish
112
- @status = @result
113
- end
114
-
115
- def interrupt
116
- @status &= ~BUSY & 0xff
117
- end
118
- end
119
- end
120
- end