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,150 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module Drive
5
- # A drive bus's eye on what the CPU reaches, for Idle and Orbit. While
6
- # Idle records a pass of the DOS's idle loop, the bus watches it (see
7
- # watch!). While Idle looks for an orbit, the bus guards the drive
8
- # (see guard!). The bus calls watch_read and watch_write with the
9
- # address folded into $0000-$1FFF, RAM and the two VIAs at $1800 and
10
- # $1C00, while @watching.
11
- module Watch
12
- # VIA registers, as bits by offset, whose access makes a watched
13
- # stretch volatile: reads of either VIA's counters and shift register
14
- # and of VIA 1's port B, and writes to VIA 2's timers, shift register
15
- # and ACR. Any write to VIA 1 does too (watch_write).
16
- VOLATILE_VIA1_READS = 0x0731
17
- VOLATILE_VIA2_READS = 0x0730
18
- VOLATILE_VIA2_WRITES = 0x0ff0
19
-
20
- # The timer each VIA register reaches, by offset, as bits: 1 for
21
- # timer 1 and 2 for timer 2.
22
- TIMER_REGISTERS = [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0].freeze
23
-
24
- # Whether a watched stretch did something that makes it unrepeatable.
25
- attr_reader :volatile
26
-
27
- # The RAM a watched stretch read or wrote, as each address's value
28
- # from before the first access.
29
- attr_reader :touched
30
-
31
- # Whether the drive did something since guard! that reached outside
32
- # it, or took something in from outside.
33
- attr_reader :tainted
34
-
35
- # The timers the drive read or wrote since guard!, as bits: VIA 1's
36
- # timer 1 and timer 2 in bits 0 and 1, and VIA 2's in bits 2 and 3.
37
- attr_reader :touched_timers
38
-
39
- # Starts watching: see volatile and touched. The bus stops watching
40
- # once the stretch turns volatile.
41
- def watch!
42
- @recording = true
43
- @volatile = false
44
- @touched = {}
45
- watching!
46
- end
47
-
48
- def unwatch!
49
- @recording = false
50
- watching!
51
- end
52
-
53
- # Starts guarding: see tainted and touched_timers. Reading VIA 1's
54
- # port B, which reads the serial bus, taints the drive, and so do
55
- # any write to VIA 1, whose port B drives the serial bus, a write to
56
- # VIA 2's shift register or ACR, and VIA 2 turning the motor on or
57
- # changing the LED. The bus stops guarding once the drive is tainted.
58
- def guard!
59
- @guarding = true
60
- @tainted = false
61
- @touched_timers = 0
62
- @led = @via2.port_b_output & Drive1541::Mechanism::LED
63
- watching!
64
- end
65
-
66
- private
67
-
68
- def init_watch
69
- @recording = @guarding = @watching = false
70
- @volatile = @tainted = false
71
- @touched = {}
72
- @touched_timers = 0
73
- @led = 0
74
- end
75
-
76
- def watching!
77
- @watching = @recording || @guarding
78
- end
79
-
80
- # An access to a chip beyond the VIAs, as the 1571's CIA and floppy
81
- # controller are: it makes the stretch volatile and taints the
82
- # drive.
83
- def watch_chip
84
- volatile! if @recording
85
- taint! if @guarding
86
- end
87
-
88
- def touch(addr)
89
- @touched[addr] = @ram.peek(addr) unless @touched.key?(addr)
90
- end
91
-
92
- def watch_read(addr)
93
- if addr < 0x0800
94
- touch(addr) if @recording
95
- elsif addr >= 0x1800
96
- via1 = addr < 0x1c00
97
- watch(via1 ? VOLATILE_VIA1_READS : VOLATILE_VIA2_READS, addr) if @recording
98
- guard_read(via1, addr & 0x0f) if @guarding
99
- end
100
- end
101
-
102
- def watch_write(addr)
103
- if addr >= 0x1c00
104
- watch_via2_write(addr) if @recording
105
- guard_via2_write(addr & 0x0f) if @guarding
106
- elsif addr >= 0x1800
107
- volatile! if @recording
108
- taint! if @guarding
109
- end
110
- end
111
-
112
- # Any write to VIA 1 makes the stretch volatile (watch_write), and so
113
- # does a write to VIA 2 that leaves the motor on.
114
- def watch_via2_write(addr)
115
- watch(VOLATILE_VIA2_WRITES, addr)
116
- volatile! if @recording && @via2.port_b_output.anybits?(Drive1541::Mechanism::MOTOR)
117
- end
118
-
119
- def watch(volatile, addr)
120
- volatile! if volatile.anybits?(1 << (addr & 0x0f))
121
- end
122
-
123
- def volatile!
124
- @volatile = true
125
- @recording = false
126
- watching!
127
- end
128
-
129
- def guard_read(via1, offset)
130
- return taint! if via1 && offset.zero?
131
-
132
- @touched_timers |= via1 ? TIMER_REGISTERS[offset] : TIMER_REGISTERS[offset] << 2
133
- end
134
-
135
- def guard_via2_write(offset)
136
- return taint! if offset.between?(0x0a, 0x0b)
137
-
138
- @touched_timers |= TIMER_REGISTERS[offset] << 2
139
- lines = @via2.port_b_output
140
- taint! if lines.anybits?(Drive1541::Mechanism::MOTOR) || (lines & Drive1541::Mechanism::LED) != @led
141
- end
142
-
143
- def taint!
144
- @tainted = true
145
- @guarding = false
146
- watching!
147
- end
148
- end
149
- end
150
- end
data/lib/badline/drive.rb DELETED
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "badline/drive/sleep"
4
- require "badline/drive/idle"
5
- require "badline/drive/orbit"
6
- require "badline/drive/core"
7
- require "badline/drive/vias"
8
- require "badline/drive/fast_serial"
9
- require "badline/drive/idle_cpu"
10
- require "badline/drive/watch"
11
- require "badline/drive/serial_lines"
@@ -1,86 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Drive1541
5
- # The drive CPU's bus. The decoder looks at A15, A12, A11 and A10 only:
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-$7FFF - $0000-$1FFF again, since A13 and A14 aren't decoded
12
- # $8000-$BFFF - the ROM again, since A14 isn't decoded
13
- # $C000-$FFFF - the DOS ROM
14
- #
15
- # Writes to the ROM and to open bus go nowhere. A read from open bus
16
- # finds the last byte on the data bus, which for LDA abs or LDA (zp),Y
17
- # is the address's high byte, and for an indexed read that crosses a
18
- # page is what its dummy read found. VICE-testprogs drive/openbus pins
19
- # both on a real 1541.
20
- #
21
- # While Idle records a pass of the DOS's idle loop, the bus watches it,
22
- # and while Idle looks for an orbit, it guards the drive (see
23
- # Drive::Watch).
24
- class Bus
25
- include Addressable
26
- include Drive::Watch
27
-
28
- attr_reader :ram, :rom, :via1, :via2, :data
29
-
30
- def initialize(rom:, via1:, via2:)
31
- addressable_at(0, length: 2**16)
32
- @ram = Memory.new([], length: 0x0800, start: 0)
33
- @rom = rom
34
- @via1 = via1
35
- @via2 = via2
36
- @data = 0
37
- init_watch
38
- end
39
-
40
- # The last byte on the data bus and the RAM. What a watched stretch
41
- # touched is Idle's, and a restored bus isn't watching.
42
- def save_state(out)
43
- out.int(@data)
44
- @ram.save_state(out)
45
- end
46
-
47
- def load_state(input)
48
- @data = input.int
49
- @ram.load_state(input)
50
- @watching = false
51
- end
52
-
53
- def peek(addr)
54
- return @data = @rom.peek(addr | 0x4000) if addr >= 0x8000
55
-
56
- addr &= 0x1fff
57
- watch_read(addr) if @watching
58
- @data = if addr < 0x0800
59
- @ram.peek(addr)
60
- elsif addr < 0x1800
61
- @data
62
- elsif addr < 0x1c00
63
- @via1.peek(addr)
64
- else
65
- @via2.peek(addr)
66
- end
67
- end
68
-
69
- def poke(addr, value)
70
- @data = value
71
- return if addr >= 0x8000
72
-
73
- addr &= 0x1fff
74
- if addr < 0x0800
75
- touch(addr) if @recording
76
- @ram.poke(addr, value)
77
- elsif addr >= 0x1c00
78
- @via2.poke(addr, value)
79
- elsif addr >= 0x1800
80
- @via1.poke(addr, value)
81
- end
82
- watch_write(addr) if @watching
83
- end
84
- end
85
- end
86
- end
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Drive1541
5
- # The Mechanism's BYTE READY line: to VIA 2's CA1, to the CPU's SO pin
6
- # through SOE, and on the 1571 to a latch VIA 1's PA7 reads.
7
- module ByteReady
8
- # VIA 2, which DiskVIA plugs in.
9
- attr_writer :via
10
-
11
- # Whether BYTE READY reached SO for the CPU to sample on the drive's
12
- # next cycle.
13
- attr_accessor :so_pending
14
-
15
- # Whether SO is pending, which the drive's cycle samples and clears.
16
- def take_so
17
- so = @so_pending
18
- @so_pending = false
19
- so
20
- end
21
-
22
- # The read electronics signal a whole GCR byte. BYTE READY pulls VIA
23
- # 2's CA1 low, a falling edge that sets its flag and, with latching
24
- # on, latches port A. It reaches the CPU's SO pin while VIA 2's CA2
25
- # (SOE) is high, which lets the DOS spin on BVC for each byte. The CPU
26
- # samples SO on the next cycle.
27
- def byte_ready!
28
- @byte_latched = true
29
- @via.ca1 = false
30
- @so_pending = true if @via.ca2_output
31
- end
32
-
33
- # BYTE READY lets go of CA1 with the next bit.
34
- def byte_ready_ended!
35
- @via.ca1 = true
36
- end
37
-
38
- # Whether BYTE READY has come since the CPU last read VIA 2, as the
39
- # 1571 latches it for VIA 1's PA7.
40
- def byte_latched? = @byte_latched
41
-
42
- # A read of VIA 2 clears the 1571's BYTE READY latch.
43
- def release_byte_latch
44
- @byte_latched = false
45
- end
46
- end
47
- end
48
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Drive1541
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,315 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "badline/drive1541/sector_reader"
4
- require "badline/drive1541/disk_state"
5
-
6
- module Badline
7
- class Drive1541
8
- # A disk as the head sees it: a Track for each half track that holds
9
- # data, numbered from 2 (track 1) to MAX_HALF_TRACK (track 42), and
10
- # nothing between them. A .d64 image fills the whole tracks; a .g64
11
- # can fill any of them, with tracks of any length.
12
- #
13
- # The disk has a second side, for the 1571's second head, its half
14
- # tracks numbered from SIDE on. A .d71 fills both sides, its tracks
15
- # 36-70 being tracks 1-35 of the second, and a .g71 holds 84 half
16
- # tracks a side. A 1541 reads the first side only.
17
- #
18
- # The head writes into the tracks' bytes, and a write to a half track
19
- # without data gives it a blank Track first. A disk made from an image
20
- # remembers it: flush reads the sectors back off the tracks written
21
- # since the last flush and stores them in the image, which writes its
22
- # host file. The disk is write-protected when the image won't take
23
- # writes.
24
- class Disk
25
- include State
26
-
27
- MAX_HALF_TRACK = 84
28
-
29
- # Where the second side's half tracks start: its track 1 is SIDE + 2.
30
- SIDE = MAX_HALF_TRACK + 1
31
-
32
- # The tracks a side of a .d71 holds.
33
- D71_SIDE_TRACKS = 35
34
-
35
- # The half track entries a side of a .g71 holds.
36
- G71_SIDE_ENTRIES = 84
37
-
38
- # GCR bytes around a track in each speed zone (Storage::D64Image.zone):
39
- # 200 ms of rotation at 300 rpm, in bytes of 32, 30, 28 and 26 µs.
40
- TRACK_LENGTHS = [6250, 6666, 7142, 7692].freeze
41
-
42
- # How far round the DOS's N: starts each track from the one before,
43
- # in each zone, in 1/10000 of a turn: it steps in and starts writing
44
- # the next track that long after it started the last.
45
- SKEWS = [2916, 897, 8915, 6869].freeze
46
- SKEW_TURN = 10_000
47
-
48
- SYNC_LENGTH = 5
49
- HEADER_GAP = 9
50
- GAP = 0x55
51
- HEADER_ID = 0x08
52
- DATA_ID = 0x07
53
-
54
- # A sector: SYNC, the 10-byte GCR header, the header gap, SYNC and
55
- # the 325-byte GCR data block. The gap after it takes up the rest.
56
- SECTOR_LENGTH = SYNC_LENGTH + 10 + HEADER_GAP + SYNC_LENGTH + 325
57
-
58
- # A disk from the image at +path+: a .g64 or .g71 as its tracks are,
59
- # a .d71 formatted on both sides, and anything else as a .d64,
60
- # formatted. `read_only` opens the image write-protected.
61
- def self.open(path, read_only: false)
62
- image = image_for(path, read_only)
63
- (State.g64?(path) ? from_g64(image) : from_d64(image)).opened(path, read_only)
64
- end
65
-
66
- # The image at +path+, by its name: a .g64 or .g71, a .d71, and
67
- # anything else a .d64.
68
- def self.image_for(path, read_only)
69
- return Storage::G64Image.new(path, read_only:) if State.g64?(path)
70
- return Storage::D71Image.new(path, read_only:) if File.extname(path).casecmp?(".d71")
71
-
72
- Storage::D64Image.new(path, read_only:)
73
- end
74
-
75
- # A disk from a G64 or G71 image, each half track as the image stores
76
- # it, with its speed map. Flushing it writes the tracks back as they
77
- # are.
78
- def self.from_g64(image)
79
- disk = new(image)
80
- image.half_tracks.times do |entry|
81
- track = image.track(entry)
82
- disk.write(half_track_of(entry), Track.new(*track, image.speeds(entry))) if track
83
- end
84
- disk
85
- end
86
-
87
- # The half track a G64 or G71 table entry holds: entry 0 is track 1,
88
- # and a .g71's entries from G71_SIDE_ENTRIES on are the second
89
- # side's.
90
- def self.half_track_of(entry)
91
- side = entry / G71_SIDE_ENTRIES
92
- (side * SIDE) + (entry % G71_SIDE_ENTRIES) + Mechanism::MIN_HALF_TRACK
93
- end
94
-
95
- # The table entry of a half track, or nil for one a G64 or G71 has
96
- # no entry for.
97
- def self.entry_of(half_track)
98
- side = half_track / SIDE
99
- entry = (half_track % SIDE) - Mechanism::MIN_HALF_TRACK
100
- (side * G71_SIDE_ENTRIES) + entry if entry.between?(0, G71_SIDE_ENTRIES - 1)
101
- end
102
-
103
- # The half track an image's track number is on: a .d71's tracks past
104
- # D71_SIDE_TRACKS are on the second side.
105
- def self.d64_half_track(image, track)
106
- return track * 2 unless image.sides == 2 && track > D71_SIDE_TRACKS
107
-
108
- SIDE + ((track - D71_SIDE_TRACKS) * 2)
109
- end
110
-
111
- # The image's track number a half track holds, or nil for a half
112
- # track or one past the image's last.
113
- def self.d64_track(image, half_track)
114
- side = half_track / SIDE
115
- return unless (half_track % SIDE).even?
116
-
117
- track = (half_track % SIDE) / 2
118
- track += D71_SIDE_TRACKS if side == 1
119
- track if track.positive? && track <= image.track_count && side < image.sides
120
- end
121
-
122
- # A disk formatted from a D64 image, each sector laid out as the DOS
123
- # formats it, with the disk ID from the header block. A block the
124
- # image's error table marks 20, 21, 22, 23, 27 or 29 is written the
125
- # way that DOS error would read. The table's other codes, 24, 25, 26
126
- # and 28, describe write or decoding faults the layout can't carry,
127
- # so their blocks are written good and read without an error.
128
- #
129
- # Each track starts sector 0 at the angle the DOS's N: leaves it: track
130
- # 1 at the index angle, and each track after it SKEWS[zone] of a turn
131
- # round from the last. A .d71's second side starts over at the index
132
- # angle.
133
- def self.from_d64(image)
134
- track, sector = image.header_block
135
- header = image.read_block(track, sector)
136
- id = [header[0xa2], header[0xa3]]
137
- disk = new(image)
138
- angle = 0
139
- (1..image.track_count).each do |track|
140
- half_track = d64_half_track(image, track)
141
- zone = Storage::D64Image.zone((half_track % SIDE) / 2)
142
- angle = half_track == SIDE + 2 ? 0 : (angle + SKEWS[zone]) % SKEW_TURN if track > 1
143
- bytes = format_track(image, track, id, zone)
144
- disk.write(half_track, Track.new(bytes.rotate(-(bytes.length * angle / SKEW_TURN)), zone))
145
- end
146
- disk
147
- end
148
-
149
- def self.format_track(image, track, id, zone = Storage::D64Image.zone(track))
150
- sectors = image.sectors_in(track)
151
- length = TRACK_LENGTHS[zone]
152
- gap = (length - (sectors * SECTOR_LENGTH)) / sectors
153
- bytes = []
154
- sectors.times do |sector|
155
- format_sector(bytes, image, track, sector, id)
156
- gap.times { bytes << GAP }
157
- end
158
- bytes << GAP while bytes.length < length
159
- bytes
160
- end
161
-
162
- # Error 21 leaves the block without SYNC marks, and 29 writes its
163
- # header with the wrong first ID byte.
164
- def self.format_sector(bytes, image, track, sector, id)
165
- error = image.block_error(track, sector)
166
- sync = error == 21 ? GAP : 0xff
167
- id = [id[0] ^ 0xff, id[1]] if error == 29
168
- SYNC_LENGTH.times { bytes << sync }
169
- bytes.concat(GCR.encode(header(track, sector, id, error)))
170
- HEADER_GAP.times { bytes << GAP }
171
- SYNC_LENGTH.times { bytes << sync }
172
- bytes.concat(GCR.encode(data_block(image.read_block(track, sector), error)))
173
- end
174
-
175
- # ID, checksum, sector, track, the second ID byte, the first and two
176
- # $0F fillers. Error 20 hides the block's ID and 27 spoils its
177
- # checksum.
178
- def self.header(track, sector, id, error)
179
- checksum = sector ^ track ^ id[1] ^ id[0]
180
- checksum ^= 0xff if error == 27
181
- [error == 20 ? 0x00 : HEADER_ID, checksum, sector, track, id[1], id[0], 0x0f, 0x0f]
182
- end
183
-
184
- # ID, 256 data bytes, their checksum and two $00 fillers. Error 22
185
- # hides the block's ID and 23 spoils its checksum.
186
- def self.data_block(data, error)
187
- checksum = 0
188
- data.each { |byte| checksum ^= byte }
189
- checksum ^= 0xff if error == 23
190
- block = [error == 22 ? 0x00 : DATA_ID]
191
- block.concat(data)
192
- block << checksum << 0x00 << 0x00
193
- end
194
-
195
- attr_reader :image
196
-
197
- def initialize(image = nil)
198
- @image = image
199
- @tracks = Array.new(SIDE * 2)
200
- @written = {}
201
- @path = nil
202
- @read_only = false
203
- end
204
-
205
- # The Track at the half track, or nil where there's no data.
206
- def track(half_track) = @tracks[half_track]
207
-
208
- def write(half_track, track)
209
- @tracks[half_track] = track
210
- end
211
-
212
- # Whether the write-protect notch is covered: the disk's image won't
213
- # take writes, or a disk without an image was opened read-only. A
214
- # disk without an image keeps what it takes only in its tracks.
215
- def write_protected? = @image.nil? ? @read_only : !@image.writable?
216
-
217
- # A half track the head writes to, blank to begin with: no flux, and
218
- # as many bytes as a turn holds at the bit rate of the +zone+ it's
219
- # written in.
220
- def writable_track(half_track, zone)
221
- @tracks[half_track] ||= Track.new(Array.new(TRACK_LENGTHS[zone], 0), zone)
222
- end
223
-
224
- # The head wrote to the half track.
225
- def written(half_track)
226
- @written[half_track] = true
227
- end
228
-
229
- # Whether any track was written since the last flush.
230
- def written? = !@written.empty?
231
-
232
- # Stores each track written since the last flush in the image, all
233
- # in one write to its host file. A G64 image takes the tracks as they
234
- # are. A D64 image takes the sectors read back off them, and keeps
235
- # whole tracks only, so a half track, or a track past its last, stays
236
- # on the disk alone. A sector that no longer reads back keeps its old
237
- # data, and the flush warns once, naming the tracks that lost one.
238
- def flush
239
- return flush_tracks if @image.respond_to?(:store_tracks)
240
-
241
- tracks = @written.keys.filter_map do |half|
242
- track = @image && Disk.d64_track(@image, half)
243
- [half, track] if track
244
- end
245
- @written.clear
246
- return if tracks.empty?
247
-
248
- sectors = tracks.to_h { |half, track| [track, SectorReader.read(@tracks[half].bytes, track)] }
249
- id = disk_id(sectors)
250
- warn_lost(sectors)
251
- @image.store_blocks(sectors.flat_map do |track, found|
252
- Array.new(@image.sectors_in(track)) { |sector| stored_block(track, sector, found[sector], id) }
253
- end)
254
- end
255
-
256
- private
257
-
258
- def flush_tracks
259
- tracks = @written.keys.sort.filter_map do |half|
260
- entry = Disk.entry_of(half)
261
- [entry, [@tracks[half].bytes, @tracks[half].zone]] if entry
262
- end.to_h
263
- @written.clear
264
- @image.store_tracks(tracks) unless tracks.empty?
265
- end
266
-
267
- def warn_lost(sectors)
268
- lost = sectors.keys.select do |track|
269
- Array.new(@image.sectors_in(track)) { |sector| lost?(track, sector, sectors[track][sector]) }.any?
270
- end
271
- return if lost.empty?
272
-
273
- warn "1541: tracks written that no longer read back whole: #{lost.join(', ')}. The .d64 keeps the old " \
274
- "data of the sectors lost, and a .g64 image keeps tracks as the drive writes them."
275
- end
276
-
277
- # A sector the head no longer finds, which the image doesn't already
278
- # hold as unreadable.
279
- def lost?(track, sector, found)
280
- found.nil? && ![20, 21].include?(@image.block_error(track, sector))
281
- end
282
-
283
- # The disk ID the headers must carry, from the header block's $A2 and
284
- # $A3 as Disk.from_d64 takes it: as just read back, or as the image
285
- # holds it.
286
- def disk_id(sectors)
287
- track, sector = @image.header_block
288
- header = sectors.dig(track, sector)&.data
289
- data = header ? header[1, 256] : @image.read_block(track, sector)
290
- [data[0xa2], data[0xa3]]
291
- end
292
-
293
- # [track, sector, data, error] for DiskImage#store_blocks: the data as
294
- # read, nil where it can't be, and the DOS error a read of it would
295
- # raise, the way Disk.from_d64 writes each one. A sector whose header
296
- # isn't found keeps its data, and reads as error 20, or 21 where the
297
- # image already has it so.
298
- def stored_block(track, sector, found, id)
299
- return [track, sector, nil, @image.block_error(track, sector) == 21 ? 21 : 20] unless found
300
-
301
- header = found.header
302
- data = found.data
303
- [track, sector, data && data[1, 256], block_error(header, data, id)]
304
- end
305
-
306
- def block_error(header, data, id)
307
- if header[1] != header[2] ^ header[3] ^ header[4] ^ header[5] then 27
308
- elsif header[5] != id[0] || header[4] != id[1] then 29
309
- elsif data.nil? || data[0] != DATA_ID then 22
310
- elsif data[257] != data[1, 256].reduce(:^) then 23
311
- end
312
- end
313
- end
314
- end
315
- end