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,86 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "badline/media/extensions"
4
-
5
- module Badline
6
- class Drive1541
7
- class Disk
8
- # Saving and restoring a Disk for a snapshot: the image by its path,
9
- # and every half track as the head sees it, with those written since
10
- # the last flush. The image itself is read again from its host file,
11
- # where there still is one.
12
- module State
13
- # The image's path, expanded, and whether it was opened read-only,
14
- # for a disk from Disk.open. Nil for a disk made another way.
15
- attr_reader :path, :read_only
16
-
17
- # Whether the image is a .g64 or .g71, by its name.
18
- def self.g64?(path) = Media::Extensions.kind(path) == :gcr
19
-
20
- # A disk for the image at the path (Disk.image_for), its tracks left
21
- # for the state.
22
- def self.reopen(path, read_only) = Disk.new(Disk.image_for(path, read_only)).opened(path, read_only)
23
-
24
- # The disk a state from save_state describes: +current+ when it was
25
- # opened from the same image the same way, and otherwise a disk for
26
- # the image at the path the state names. Where no file is at that
27
- # path, the disk has no image and is write-protected, and a
28
- # detached reader always gets one without an image. Either way its
29
- # tracks come from the state.
30
- def self.load(input, current)
31
- path = input.optional_string
32
- read_only = input.boolean?
33
- disk = current if current && !path.nil? && current.path == path && current.read_only == read_only
34
- disk ||= fresh(path, read_only, input.detached?)
35
- disk.load_tracks(input)
36
- disk
37
- end
38
-
39
- def self.fresh(path, read_only, detached)
40
- return Disk.new if path.nil? || detached
41
- return Disk.new.opened(path, true) unless File.file?(path)
42
-
43
- reopen(path, read_only)
44
- end
45
-
46
- # Notes the image's path and how it was opened.
47
- def opened(path, read_only)
48
- @path = File.expand_path(path)
49
- @read_only = read_only
50
- self
51
- end
52
-
53
- def save_state(out)
54
- out.optional_string(@path).boolean(@read_only)
55
- @tracks.each do |track|
56
- out.boolean(!track.nil?)
57
- save_track(track, out) if track
58
- end
59
- out.ints(@written.keys)
60
- end
61
-
62
- def load_tracks(input)
63
- @tracks.each_index do |half_track|
64
- @tracks[half_track] = input.boolean? ? load_track(input) : nil
65
- end
66
- @written.clear
67
- input.ints.each { |half_track| @written[half_track] = true }
68
- end
69
-
70
- private
71
-
72
- def save_track(track, out)
73
- out.int(track.zone).boolean(!track.speeds.nil?)
74
- out.ints(track.speeds) if track.speeds
75
- out.blob(track.bytes)
76
- end
77
-
78
- def load_track(input)
79
- zone = input.int
80
- speeds = input.boolean? ? input.ints : nil
81
- Track.new(input.blob, zone, speeds)
82
- end
83
- end
84
- end
85
- end
86
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Drive1541
5
- # VIA 2, the one facing the disk mechanism. Its port B drives the
6
- # Mechanism, and CB2 selects its read or write mode. The mechanism
7
- # hears both after every write and reset, since ORB, DDRB, the ACR and
8
- # the PCR can all change them.
9
- class DiskVIA < VIA
10
- attr_reader :mechanism
11
-
12
- def initialize(start:, mechanism:)
13
- @mechanism = mechanism
14
- mechanism.via = self
15
- super(start:, peripheral: mechanism)
16
- end
17
-
18
- def reset!
19
- super
20
- tell_mechanism
21
- end
22
-
23
- def poke(addr, value)
24
- super
25
- tell_mechanism
26
- end
27
-
28
- private
29
-
30
- def tell_mechanism
31
- @mechanism.port_b_written(port_b_output)
32
- @mechanism.cb2_written(cb2_output)
33
- end
34
- end
35
- end
36
- end
@@ -1,57 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Drive1541
5
- # Group code recording, the 1541's on-disk code. Each nibble becomes
6
- # five bits, chosen so that no code has more than two 0 bits in a row
7
- # and no run of codes has ten 1 bits in a row, which only a SYNC mark
8
- # has. Four bytes become five.
9
- module GCR
10
- CODES = [0x0a, 0x0b, 0x12, 0x13, 0x0e, 0x0f, 0x16, 0x17,
11
- 0x09, 0x19, 0x1a, 0x1b, 0x0d, 0x1d, 0x1e, 0x15].freeze
12
-
13
- # Five-bit code => nibble, nil for the codes that aren't GCR.
14
- NIBBLES = Array.new(32) { |code| CODES.index(code) }.freeze
15
-
16
- module_function
17
-
18
- # Encodes a whole number of four-byte groups.
19
- def encode(bytes)
20
- out = []
21
- i = 0
22
- while i < bytes.length
23
- bits = 0
24
- 4.times do |n|
25
- byte = bytes[i + n]
26
- bits = (bits << 10) | (CODES[byte >> 4] << 5) | CODES[byte & 0x0f]
27
- end
28
- 4.downto(0) { |n| out << ((bits >> (n * 8)) & 0xff) }
29
- i += 4
30
- end
31
- out
32
- end
33
-
34
- # Decodes a whole number of five-byte groups, nil when any code
35
- # isn't GCR.
36
- def decode(bytes)
37
- out = []
38
- i = 0
39
- while i < bytes.length
40
- bits = 0
41
- 5.times { |n| bits = (bits << 8) | bytes[i + n] }
42
- n = 7
43
- while n.positive?
44
- high = NIBBLES[(bits >> (n * 5)) & 0x1f]
45
- low = NIBBLES[(bits >> ((n - 1) * 5)) & 0x1f]
46
- return nil if high.nil? || low.nil?
47
-
48
- out << ((high << 4) | low)
49
- n -= 2
50
- end
51
- i += 5
52
- end
53
- out
54
- end
55
- end
56
- end
57
- end
@@ -1,313 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "badline/drive1541/rotation"
4
- require "badline/drive1541/mechanism_state"
5
- require "badline/drive1541/byte_ready"
6
-
7
- module Badline
8
- class Drive1541
9
- # The disk mechanism behind VIA 2: the spindle motor, the head on its
10
- # stepper, the LED, the read and write electronics and the
11
- # write-protect sensor.
12
- #
13
- # Port B drives it and reads it back:
14
- #
15
- # PB0-1 stepper phase (out) PB4 write protect (in, 1 = writable)
16
- # PB2 motor on (out) PB5-6 bit rate, speed zone 0-3 (out)
17
- # PB3 LED on (out) PB7 SYNC (in, 0 while in a SYNC mark)
18
- #
19
- # Port A reads the read shift register's low eight bits, which CA1
20
- # latches on BYTE READY. In write mode it drives the write shift
21
- # register, and the read shift register takes the bits written.
22
- #
23
- # The disk turns at 300 rpm under the head, and a read clock at the
24
- # bit rate PB5-6 select clocks the bits off it (see Rotation).
25
- #
26
- # Ten 1 bits in a row are a SYNC mark while CB2 selects reading: PB7
27
- # reads it, and it holds the bit counter at zero, so the first 0 bit
28
- # after it starts a byte. Every eighth bit after that is BYTE READY,
29
- # which pulls VIA 2's CA1 low until the next bit and reaches the CPU's
30
- # SO pin (see byte_ready!).
31
- #
32
- # CB2 low selects write mode, where SYNC detection and the flux are
33
- # off and the clock runs on at the selected rate. At each BYTE READY
34
- # the write shift register loads what the VIA drives on port A, and
35
- # the next eight clocks put that byte's bits on the track, most
36
- # significant first, in place of what it held. While reading, the load
37
- # takes the byte just read, so a switch to writing mid-byte writes the
38
- # rest of it. A write lays its bits one to a cell from the cell under
39
- # the head, so on a track written at the selected rate each bit fills
40
- # the cell it passes over. A write to a half track without data gives
41
- # it a blank track first, a turn long at the selected rate, and a
42
- # write to a track written at another rate lays the whole track out
43
- # again as a turn at the selected rate first (Track#relaid).
44
- #
45
- # PB4 reads the write-protect sensor: high with no disk in, or with
46
- # the notch of a writable one open. With the disk write-protected the
47
- # write gate stays shut: the bits and BYTE READY go on, and nothing
48
- # reaches the disk. The DOS reads PB4 first and refuses to write, so
49
- # only a program that writes without asking finds that out.
50
- #
51
- # The motor stopping flushes what was written to the disk's image
52
- # (see Disk#flush), which is when the DOS is done with a job, and so
53
- # does taking the disk out.
54
- #
55
- # The stepper moves the head a half track each time the phase steps
56
- # by one, inwards for +1 and outwards for -1. Each half track has a
57
- # phase of its own, from power-on the low two bits of its number, so
58
- # the head sits on a whole track when phase 0 or 2 holds it. The
59
- # stepper's coils are powered only while PB2 runs the motor, as VICE
60
- # reads the 1541's schematic, so a phase set with the motor off moves
61
- # nothing until the motor comes on and it pulls the head. Tracks run
62
- # from half track 2 (track 1), where the head stops against the end of
63
- # its rail, to Disk::MAX_HALF_TRACK. A step out against the stop slips:
64
- # the head stays on track 1 and the phase that tried to pull it out
65
- # becomes track 1's, so the DOS's bump leaves the head on track 1 in
66
- # line with the phase it ends on, and its first step in reaches the
67
- # half track after it.
68
- #
69
- # The 1571's stepper is lined up so that phase 0 holds track 1, where
70
- # its track 0 sensor looks for the head (Mechanism.new's +slip+).
71
- class Mechanism
72
- include Rotation
73
- include MechanismState
74
- include ByteReady
75
-
76
- MOTOR = 0x04
77
- LED = 0x08
78
- WRITE_PROTECT = 0x10
79
- SYNC = 0x80
80
-
81
- MIN_HALF_TRACK = 2
82
- # Where the head sits at power-on: track 18, the directory.
83
- START_HALF_TRACK = 36
84
-
85
- SYNC_BITS = 10
86
-
87
- attr_reader :disk, :half_track, :zone
88
-
89
- # +slip+ is the stepper's phase offset at power-on: 0, where each half
90
- # track's phase is the low two bits of its number, or 2 for track 1
91
- # on phase 0.
92
- def initialize(slip: 0)
93
- @via = nil
94
- @so_pending = false
95
- @disk = nil
96
- @half_track = START_HALF_TRACK
97
- @slip = slip
98
- @motor = false
99
- @led = false
100
- @zone = 0
101
- @clock = Track.cell(0)
102
- @time = 0
103
- @clock_at = @clock / 2
104
- @clocks = 0
105
- @shift = 0
106
- @ones = 0
107
- @bits = 0
108
- @sync = false
109
- @byte_ready = false
110
- @byte_latched = false
111
- @writing = false
112
- @write_shift = 0
113
- @write_gate = false
114
- @protected = false
115
- @side_base = 0
116
- @cycle_ticks = CYCLE
117
- load_track
118
- end
119
-
120
- # The drive's clock rate: the disk turns on by fewer ticks each
121
- # cycle at 2 MHz.
122
- def clock_hz=(clock_hz)
123
- @cycle_ticks = CYCLE * Drive1541::CLOCK_HZ / clock_hz
124
- end
125
-
126
- # The head that reads, 0 or 1, on a drive with two (Disk::SIDE).
127
- def side = @side_base.zero? ? 0 : 1
128
-
129
- def side=(side)
130
- side_base = side * Disk::SIDE
131
- return if side_base == @side_base
132
-
133
- @side_base = side_base
134
- load_track
135
- end
136
-
137
- def motor_on? = @motor
138
-
139
- def led_on? = @led
140
-
141
- def sync? = @sync
142
-
143
- def writing? = @writing
144
-
145
- # What port B and CB2 can change with the motor off: the motor, the
146
- # LED, the zone and the clock's rate, the stepper, write mode and
147
- # where a write starts, and the track and cell under the head. The
148
- # rest moves only while the motor turns, or as a disk goes in (see
149
- # Drive::Idle).
150
- def idle_state
151
- [@motor, @led, @zone, @clock, @half_track, @slip, @side_base, @disk, @track, @index, @mask, @cell_end,
152
- @time, @writing, @write_index, @sync, @byte_latched]
153
- end
154
-
155
- # Puts a Disk in, or takes it out with nil, flushing the disk that
156
- # was in. The head goes on from the same point in the turn.
157
- def insert(disk)
158
- flush
159
- @disk = disk
160
- @protected = disk&.write_protected? || false
161
- @write_gate = !disk.nil? && !@protected
162
- load_track
163
- end
164
-
165
- # Stores what the head wrote in the disk's image.
166
- def flush
167
- @disk.flush if @disk&.written?
168
- rescue Storage::WriteError => e
169
- warn "1541: couldn't write the disk back: #{e.message}"
170
- end
171
-
172
- # VIA 2 drives CB2 to +high+: low selects write mode, which stops
173
- # SYNC detection at once.
174
- def cb2_written(high)
175
- @write_index = nil if high || !@writing
176
- @writing = !high
177
- @sync = !@writing && @ones >= SYNC_BITS
178
- end
179
-
180
- # VIA 2 drives port B's lines to +lines+.
181
- def port_b_written(lines)
182
- motor = @motor
183
- @motor = lines.anybits?(MOTOR)
184
- flush if motor && !@motor
185
- @led = lines.anybits?(LED)
186
- zone = (lines >> 5) & 0x03
187
- if zone != @zone
188
- @zone = zone
189
- @clock = Track.cell(zone)
190
- @track_written = false
191
- end
192
- step(lines & 0x03) if @motor
193
- end
194
-
195
- # Port A is the read shift register.
196
- def read_a(_lines) = @shift & 0xff
197
-
198
- # SYNC low in a SYNC mark, and write protect low for a protected
199
- # disk.
200
- def read_b(_lines)
201
- lines = @sync ? 0xff & ~SYNC : 0xff
202
- @protected ? lines & ~WRITE_PROTECT : lines
203
- end
204
-
205
- private
206
-
207
- def read_bit(one)
208
- if @byte_ready
209
- @byte_ready = false
210
- byte_ready_ended!
211
- end
212
- @shift = ((@shift << 1) & 0x3fe) | (one ? 1 : 0)
213
- if one
214
- @ones += 1
215
- @sync = true if @ones >= SYNC_BITS
216
- else
217
- @ones = 0
218
- @sync = false
219
- end
220
- count_bit
221
- end
222
-
223
- # The write shift register's top bit goes onto the track through the
224
- # write gate, and into the read shift register, as the head's own
225
- # signal.
226
- def write_bit(at)
227
- if @byte_ready
228
- @byte_ready = false
229
- byte_ready_ended!
230
- end
231
- one = @write_shift.anybits?(0x80)
232
- @write_shift = (@write_shift << 1) & 0xff
233
- store_bit(one, at) if @write_gate
234
- @shift = ((@shift << 1) & 0x3fe) | (one ? 1 : 0)
235
- @ones = one ? @ones + 1 : 0
236
- count_bit
237
- end
238
-
239
- # Each bit written goes in the cell after the last one's, from the
240
- # cell under the head when the write started.
241
- def store_bit(one, at)
242
- track_written(at) unless @track_written
243
- @write_index ||= (@index * 8) + 8 - @mask.bit_length
244
- index = @write_index >> 3
245
- mask = 0x80 >> (@write_index & 7)
246
- if one
247
- @bytes[index] |= mask
248
- else
249
- @bytes[index] &= ~mask
250
- end
251
- @write_index += 1
252
- @write_index = 0 if @write_index == @length * 8
253
- end
254
-
255
- # The first write to the track since the head came to it or the rate
256
- # changed: a half track without data gets a blank track, and a track
257
- # written at another rate is laid out again at this one.
258
- def track_written(at)
259
- surface = self.surface
260
- track = @disk.writable_track(surface, @zone)
261
- @disk.write(surface, track.relaid(@zone)) unless track.written_at?(@zone)
262
- load_track(at)
263
- @disk.written(surface)
264
- @track_written = true
265
- end
266
-
267
- # Every eighth bit outside a SYNC mark is BYTE READY, which loads the
268
- # write shift register: from what the VIA drives on port A in write
269
- # mode, and with the byte just read otherwise.
270
- def count_bit
271
- if @sync
272
- @bits = 0
273
- return
274
- end
275
- @bits += 1
276
- return unless @bits == 8
277
-
278
- @bits = 0
279
- @write_shift = @writing ? @via.port_a_output : @shift & 0xff
280
- @byte_ready = true
281
- byte_ready!
282
- end
283
-
284
- # The stepper's rotor turns with the head, a phase to each half
285
- # track, so the energized phase pulls the head to the neighbouring
286
- # half track it belongs to. A phase two away pulls both ways, and the
287
- # head stays. Against the stop at track 1 the head can't follow, and
288
- # the phases slip round to where the head is.
289
- def step(phase)
290
- move = (phase - @half_track - @slip) & 0x03
291
- if move == 1
292
- seek(@half_track + 1)
293
- elsif move == 3 && @half_track == MIN_HALF_TRACK
294
- @slip = (phase - MIN_HALF_TRACK) & 0x03
295
- elsif move == 3
296
- seek(@half_track - 1)
297
- end
298
- end
299
-
300
- # The half track under the head that reads, numbered on the disk
301
- # (see Disk::SIDE).
302
- def surface = @half_track + @side_base
303
-
304
- def seek(half_track)
305
- half_track = half_track.clamp(MIN_HALF_TRACK, Disk::MAX_HALF_TRACK)
306
- return if half_track == @half_track
307
-
308
- @half_track = half_track
309
- load_track
310
- end
311
- end
312
- end
313
- end
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Drive1541
5
- # Saving and restoring the Mechanism for a snapshot.
6
- module MechanismState
7
- # The disk (Disk#save_state) and everything the head, the motor, the
8
- # stepper and the read and write electronics hold, down to the cell
9
- # under the head and the read clock's phase.
10
- def save_state(out)
11
- out.boolean(!@disk.nil?)
12
- @disk&.save_state(out)
13
- [@half_track, @slip, @side_base, @zone, @clock, @time, @clock_at, @clocks, @shift, @ones, @bits, @write_shift,
14
- @index, @mask, @cell_end, @width, @next].each { |value| out.int(value) }
15
- [@motor, @led, @sync, @byte_ready, @byte_latched, @writing, @write_gate, @protected,
16
- @track_written].each { |flag| out.boolean(flag) }
17
- out.optional_int(@write_index)
18
- end
19
-
20
- # Puts the state back, reusing the disk in when it's the one the state
21
- # names (Disk::State.load). A disk taken out is flushed, as insert
22
- # does.
23
- def load_state(input)
24
- disk = input.boolean? ? Disk::State.load(input, @disk) : nil
25
- flush unless disk.equal?(@disk)
26
- @disk = disk
27
- load_head(input)
28
- load_flags(input)
29
- @write_index = input.optional_int
30
- head_on_track
31
- end
32
-
33
- private
34
-
35
- def load_head(input)
36
- @half_track = input.int
37
- @slip = input.int
38
- @side_base = input.int
39
- @zone = input.int
40
- @clock = input.int
41
- @time = input.int
42
- @clock_at = input.int
43
- @clocks = input.int
44
- @shift = input.int
45
- @ones = input.int
46
- @bits = input.int
47
- @write_shift = input.int
48
- @index = input.int
49
- @mask = input.int
50
- @cell_end = input.int
51
- @width = input.int
52
- @next = input.int
53
- end
54
-
55
- def load_flags(input)
56
- @motor = input.boolean?
57
- @led = input.boolean?
58
- @sync = input.boolean?
59
- @byte_ready = input.boolean?
60
- @byte_latched = input.boolean?
61
- @writing = input.boolean?
62
- @write_gate = input.boolean?
63
- @protected = input.boolean?
64
- @track_written = input.boolean?
65
- end
66
- end
67
- end
68
- end
@@ -1,121 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Drive1541
5
- # The disk turning under the Mechanism's head, and its read clock.
6
- #
7
- # The disk turns at 300 rpm, whatever the bit rate: once in 200 ms, or
8
- # 200,000 drive cycles. Each track's bits pass under the head at the
9
- # rate they were written at (see Track), and a 1 bit is a flux
10
- # transition at the start of its cell.
11
- #
12
- # The read circuit clocks bits out at the rate PB5-6 select, from a
13
- # counter the 16 MHz crystal steps every 16 - zone ticks. A flux
14
- # transition clears the counter. The counter clocks a bit into the
15
- # read shift register as it reaches 2 and every four steps after
16
- # that, and the bit is a 1 only for the first clock after the counter
17
- # passed 0. A bit is 4 * (16 - zone) ticks, so a byte takes 32, 30, 28
18
- # or 26 drive cycles in zones 0 to 3, and each transition brings the
19
- # clock back into step with the flux. A track read at the rate it was
20
- # written reads its bits. At another rate the clock and the cells
21
- # drift apart between transitions: a faster clock slips an extra 0
22
- # bit into some runs of 0 bits, a slower one drops one from some, and
23
- # the bytes come out garbled. Without flux the counter runs round on
24
- # its own and reads a 1 bit in every four.
25
- module Rotation
26
- CYCLE = 16 * Track::TICK
27
-
28
- # What the head reads with no disk in, or off the tracks a disk has:
29
- # no flux.
30
- BLANK = Track.new(Array.new(Disk::TRACK_LENGTHS[0], 0).freeze, 0)
31
-
32
- # One drive cycle: nothing with the motor off, and otherwise the
33
- # disk turns on by a cycle's ticks, 16 at 1 MHz and 8 at 2 MHz,
34
- # through whatever cells and clocks fall in them.
35
- def cycle!
36
- return unless @motor
37
-
38
- @time += @cycle_ticks
39
- pass_time if @time >= @next
40
- end
41
-
42
- private
43
-
44
- # The cell edges and clocks up to now, in the order they come. A
45
- # clock that falls on a cell edge comes after it.
46
- def pass_time
47
- while @cell_end <= @time || @clock_at <= @time
48
- if @cell_end <= @clock_at
49
- next_cell
50
- else
51
- clock
52
- end
53
- end
54
- @next = [@cell_end, @clock_at].min
55
- end
56
-
57
- # The head comes to the next cell, and a 1 bit's flux clears the
58
- # read clock while reading.
59
- def next_cell
60
- start = @cell_end
61
- @mask >>= 1
62
- start = next_byte(start) if @mask.zero?
63
- @cell_end = @index == @last && @mask == 1 ? Track::TURN : start + @width
64
- return if @writing || @bytes[@index].nobits?(@mask)
65
-
66
- @clock_at = start + (@clock / 2)
67
- @clocks = 0
68
- end
69
-
70
- # The head comes to the next byte, and at the end of the track back
71
- # round to the first, where the turn starts over.
72
- def next_byte(start)
73
- @mask = 0x80
74
- @index += 1
75
- if @index == @length
76
- @index = 0
77
- @time -= Track::TURN
78
- @clock_at -= Track::TURN
79
- start = 0
80
- end
81
- @width = @widths[@index] if @widths
82
- start
83
- end
84
-
85
- # The read clock ticks a bit into the shift register: a 1 the first
86
- # time after a flux transition or the counter's wrap.
87
- def clock
88
- at = @clock_at
89
- one = @clocks.zero?
90
- @clocks = (@clocks + 1) & 3
91
- @clock_at = at + @clock
92
- @writing ? write_bit(at) : read_bit(one)
93
- end
94
-
95
- # The track under the head and its layout, leaving the head's place
96
- # on it as it stands.
97
- def head_on_track
98
- @track = @disk&.track(surface) || BLANK
99
- @bytes = @track.bytes
100
- @widths = @track.widths
101
- @length = @track.length
102
- @last = @length - 1
103
- end
104
-
105
- # The track under the head, from the cell that's under it +time+
106
- # into the turn.
107
- def load_track(time = @time)
108
- @track = @disk&.track(surface) || BLANK
109
- @bytes = @track.bytes
110
- @widths = @track.widths
111
- @length = @track.length
112
- @last = @length - 1
113
- @index, @mask, @cell_end = @track.cell_at(time)
114
- @width = @widths ? @widths[@index] : @track.width
115
- @write_index = nil
116
- @track_written = false
117
- @next = [@cell_end, @clock_at].min
118
- end
119
- end
120
- end
121
- end