badline 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (505) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -0
  3. data/CLAUDE.md +59 -31
  4. data/README.md +1 -1
  5. data/doc/library.md +9 -9
  6. data/doc/pinned-behaviour.md +105 -105
  7. data/doc/snapshots.md +1 -4
  8. data/lib/badline/audio/bare_player.rb +3 -3
  9. data/lib/badline/audio/cli.rb +6 -6
  10. data/lib/badline/audio/jukebox.rb +2 -2
  11. data/lib/badline/audio/machine_player.rb +2 -2
  12. data/lib/badline/{media → audio}/queue.rb +1 -1
  13. data/lib/badline/audio/queued_tune.rb +6 -6
  14. data/lib/badline/audio/renderer.rb +5 -5
  15. data/lib/badline/audio/stereo.rb +1 -1
  16. data/lib/badline/c128/{bus_state.rb → bus/saved_state.rb} +1 -1
  17. data/lib/badline/c128/bus.rb +18 -17
  18. data/lib/badline/c128/color_lines.rb +2 -2
  19. data/lib/badline/c128/cpu.rb +1 -1
  20. data/lib/badline/c128/drives.rb +10 -11
  21. data/lib/badline/c128/fast_serial.rb +5 -5
  22. data/lib/badline/c128/mmu_pages.rb +1 -1
  23. data/lib/badline/c128/modes.rb +2 -2
  24. data/lib/badline/c128/saved_state.rb +21 -47
  25. data/lib/badline/c128/z80.rb +2 -2
  26. data/lib/badline/c128.rb +14 -9
  27. data/lib/badline/{computer → c64}/attachments.rb +4 -6
  28. data/lib/badline/c64/banked_ram/banking.rb +32 -0
  29. data/lib/badline/c64/banked_ram/plus256k.rb +56 -0
  30. data/lib/badline/c64/banked_ram/plus60k.rb +45 -0
  31. data/lib/badline/c64/banked_ram/unexpanded.rb +30 -0
  32. data/lib/badline/c64/banked_ram.rb +23 -0
  33. data/lib/badline/c64/bus/extra_sids.rb +32 -0
  34. data/lib/badline/c64/bus/fittings.rb +40 -0
  35. data/lib/badline/c64/bus/pla.rb +149 -0
  36. data/lib/badline/c64/bus/roms.rb +41 -0
  37. data/lib/badline/c64/bus/saved_state.rb +68 -0
  38. data/lib/badline/c64/bus/sid_slots.rb +44 -0
  39. data/lib/badline/c64/bus.rb +218 -0
  40. data/lib/badline/c64/cartridge/action_replay.rb +128 -0
  41. data/lib/badline/c64/cartridge/atomic_power.rb +26 -0
  42. data/lib/badline/c64/cartridge/bank.rb +83 -0
  43. data/lib/badline/c64/cartridge/comal80.rb +52 -0
  44. data/lib/badline/c64/cartridge/dinamic.rb +36 -0
  45. data/lib/badline/c64/cartridge/easy_flash.rb +147 -0
  46. data/lib/badline/c64/cartridge/epyx_fastload.rb +81 -0
  47. data/lib/badline/c64/cartridge/final_cartridge3.rb +91 -0
  48. data/lib/badline/c64/cartridge/flash/saved_state.rb +40 -0
  49. data/lib/badline/c64/cartridge/flash.rb +279 -0
  50. data/lib/badline/c64/cartridge/freezer.rb +35 -0
  51. data/lib/badline/c64/cartridge/fun_play.rb +40 -0
  52. data/lib/badline/c64/cartridge/g_mod2.rb +76 -0
  53. data/lib/badline/c64/cartridge/game_system.rb +42 -0
  54. data/lib/badline/c64/cartridge/geo_ram.rb +81 -0
  55. data/lib/badline/c64/cartridge/kcs_power.rb +77 -0
  56. data/lib/badline/c64/cartridge/mach5.rb +34 -0
  57. data/lib/badline/c64/cartridge/magic_desk.rb +32 -0
  58. data/lib/badline/c64/cartridge/ocean.rb +37 -0
  59. data/lib/badline/c64/cartridge/pagefox.rb +70 -0
  60. data/lib/badline/c64/cartridge/retro_replay/saved_state.rb +47 -0
  61. data/lib/badline/c64/cartridge/retro_replay.rb +286 -0
  62. data/lib/badline/c64/cartridge/rex_utility.rb +31 -0
  63. data/lib/badline/c64/cartridge/rgcd.rb +60 -0
  64. data/lib/badline/c64/cartridge/saved_state.rb +63 -0
  65. data/lib/badline/c64/cartridge/simons_basic.rb +37 -0
  66. data/lib/badline/c64/cartridge/standard.rb +17 -0
  67. data/lib/badline/c64/cartridge/super_games.rb +50 -0
  68. data/lib/badline/c64/cartridge/westermann.rb +32 -0
  69. data/lib/badline/c64/cartridge/zaxxon.rb +68 -0
  70. data/lib/badline/c64/cartridge.rb +258 -0
  71. data/lib/badline/c64/color_memory.rb +27 -0
  72. data/lib/badline/{computer → c64}/common.rb +2 -2
  73. data/lib/badline/{computer → c64}/kernal_traps.rb +18 -18
  74. data/lib/badline/c64/reu/dma/saved_state.rb +52 -0
  75. data/lib/badline/c64/reu/dma.rb +275 -0
  76. data/lib/badline/c64/reu/ram.rb +109 -0
  77. data/lib/badline/c64/reu/saved_state.rb +55 -0
  78. data/lib/badline/c64/reu/trigger.rb +34 -0
  79. data/lib/badline/c64/reu.rb +291 -0
  80. data/lib/badline/{computer → c64}/saved_state.rb +13 -18
  81. data/lib/badline/{computer → c64}/true_drives.rb +11 -11
  82. data/lib/badline/{computer.rb → c64.rb} +18 -13
  83. data/lib/badline/chips/cia/fast_forward.rb +62 -0
  84. data/lib/badline/chips/cia/interrupt_register.rb +145 -0
  85. data/lib/badline/chips/cia/saved_state.rb +49 -0
  86. data/lib/badline/chips/cia/serial/saved_state.rb +45 -0
  87. data/lib/badline/chips/cia/serial.rb +250 -0
  88. data/lib/badline/chips/cia/time_of_day.rb +232 -0
  89. data/lib/badline/chips/cia/timer.rb +208 -0
  90. data/lib/badline/chips/cia.rb +281 -0
  91. data/lib/badline/chips/cpu/addressing.rb +133 -0
  92. data/lib/badline/chips/cpu/boundary.rb +56 -0
  93. data/lib/badline/chips/cpu/core.rb +167 -0
  94. data/lib/badline/chips/cpu/instruction.rb +338 -0
  95. data/lib/badline/chips/cpu/instruction_set/arithmetic.rb +118 -0
  96. data/lib/badline/chips/cpu/instruction_set/bitwise.rb +130 -0
  97. data/lib/badline/chips/cpu/instruction_set/branch.rb +83 -0
  98. data/lib/badline/chips/cpu/instruction_set/flag.rb +67 -0
  99. data/lib/badline/chips/cpu/instruction_set/illegal.rb +274 -0
  100. data/lib/badline/chips/cpu/instruction_set/inc_dec.rb +73 -0
  101. data/lib/badline/chips/cpu/instruction_set/stack.rb +56 -0
  102. data/lib/badline/chips/cpu/instruction_set/transfer.rb +141 -0
  103. data/lib/badline/chips/cpu/instruction_set.rb +59 -0
  104. data/lib/badline/chips/cpu/interrupts.rb +108 -0
  105. data/lib/badline/chips/cpu/microcode.rb +179 -0
  106. data/lib/badline/chips/cpu/operations.rb +90 -0
  107. data/lib/badline/chips/cpu/port.rb +116 -0
  108. data/lib/badline/chips/cpu/saved_state.rb +117 -0
  109. data/lib/badline/chips/cpu/stack_operations.rb +84 -0
  110. data/lib/badline/chips/cpu/traps.rb +23 -0
  111. data/lib/badline/chips/cpu.rb +12 -0
  112. data/lib/badline/chips/sid/catch_up.rb +122 -0
  113. data/lib/badline/chips/sid/decimator.rb +66 -0
  114. data/lib/badline/chips/sid/envelope/saved_state.rb +70 -0
  115. data/lib/badline/chips/sid/envelope.rb +241 -0
  116. data/lib/badline/chips/sid/filter/saved_state.rb +42 -0
  117. data/lib/badline/chips/sid/filter.rb +241 -0
  118. data/lib/badline/chips/sid/saved_state.rb +52 -0
  119. data/lib/badline/chips/sid/voice.rb +79 -0
  120. data/lib/badline/chips/sid/waveform/combined.rb +128 -0
  121. data/lib/badline/chips/sid/waveform/fast_forward.rb +107 -0
  122. data/lib/badline/chips/sid/waveform/noise_writeback.rb +124 -0
  123. data/lib/badline/chips/sid/waveform/saved_state.rb +68 -0
  124. data/lib/badline/chips/sid/waveform.rb +307 -0
  125. data/lib/badline/chips/sid.rb +265 -0
  126. data/lib/badline/{c128 → chips}/vdc/memory.rb +1 -1
  127. data/lib/badline/{c128 → chips}/vdc/painter.rb +1 -1
  128. data/lib/badline/{c128 → chips}/vdc/raster.rb +1 -1
  129. data/lib/badline/chips/vdc/saved_state.rb +36 -0
  130. data/lib/badline/{c128 → chips}/vdc/window.rb +1 -1
  131. data/lib/badline/{c128 → chips}/vdc.rb +7 -31
  132. data/lib/badline/chips/via/control_lines.rb +124 -0
  133. data/lib/badline/chips/via/fast_forward.rb +55 -0
  134. data/lib/badline/chips/via/interrupt_register.rb +69 -0
  135. data/lib/badline/chips/via/saved_state.rb +44 -0
  136. data/lib/badline/chips/via/shift_register.rb +182 -0
  137. data/lib/badline/chips/via/timer1.rb +133 -0
  138. data/lib/badline/chips/via/timer2.rb +135 -0
  139. data/lib/badline/chips/via.rb +268 -0
  140. data/lib/badline/chips/vic/bank.rb +135 -0
  141. data/lib/badline/chips/vic/border_mask.rb +88 -0
  142. data/lib/badline/chips/vic/collisions.rb +117 -0
  143. data/lib/badline/chips/vic/color_patches.rb +49 -0
  144. data/lib/badline/chips/vic/display_state.rb +187 -0
  145. data/lib/badline/chips/vic/graphics_mode.rb +166 -0
  146. data/lib/badline/chips/vic/graphics_shifter/saved_state.rb +40 -0
  147. data/lib/badline/chips/vic/graphics_shifter.rb +187 -0
  148. data/lib/badline/chips/vic/register_log.rb +83 -0
  149. data/lib/badline/chips/vic/registers.rb +197 -0
  150. data/lib/badline/chips/vic/saved_state.rb +82 -0
  151. data/lib/badline/chips/vic/sequencer/saved_state.rb +91 -0
  152. data/lib/badline/chips/vic/sequencer.rb +277 -0
  153. data/lib/badline/chips/vic/sequencer_output.rb +118 -0
  154. data/lib/badline/chips/vic/sprite/internal_bus.rb +70 -0
  155. data/lib/badline/chips/vic/sprite/saved_state.rb +66 -0
  156. data/lib/badline/chips/vic/sprite/shifter.rb +148 -0
  157. data/lib/badline/chips/vic/sprite/timing.rb +58 -0
  158. data/lib/badline/chips/vic/sprite.rb +339 -0
  159. data/lib/badline/chips/vic/sprites/saved_state.rb +59 -0
  160. data/lib/badline/chips/vic/sprites.rb +284 -0
  161. data/lib/badline/chips/vic.rb +783 -0
  162. data/lib/badline/chips/vic_i/painter/saved_state.rb +40 -0
  163. data/lib/badline/{vic20/vic → chips/vic_i}/painter.rb +6 -30
  164. data/lib/badline/{vic20/vic → chips/vic_i}/saved_state.rb +2 -2
  165. data/lib/badline/chips/vic_i/sound/output.rb +85 -0
  166. data/lib/badline/chips/vic_i/sound.rb +235 -0
  167. data/lib/badline/{vic20/vic → chips/vic_i}/text_window.rb +2 -2
  168. data/lib/badline/{vic20/vic.rb → chips/vic_i.rb} +5 -5
  169. data/lib/badline/chips/z80/arithmetic.rb +119 -0
  170. data/lib/badline/chips/z80/bit_page.rb +57 -0
  171. data/lib/badline/chips/z80/block_io.rb +60 -0
  172. data/lib/badline/chips/z80/block_transfers.rb +61 -0
  173. data/lib/badline/chips/z80/bus_cycles.rb +113 -0
  174. data/lib/badline/chips/z80/core.rb +115 -0
  175. data/lib/badline/chips/z80/exchanges.rb +52 -0
  176. data/lib/badline/chips/z80/extended_page.rb +91 -0
  177. data/lib/badline/chips/z80/flags.rb +39 -0
  178. data/lib/badline/chips/z80/interrupt_acceptance.rb +48 -0
  179. data/lib/badline/chips/z80/jumps.rb +84 -0
  180. data/lib/badline/chips/z80/loads.rb +100 -0
  181. data/lib/badline/chips/z80/main_page.rb +136 -0
  182. data/lib/badline/chips/z80/registers.rb +122 -0
  183. data/lib/badline/chips/z80/saved_state.rb +71 -0
  184. data/lib/badline/chips/z80/shifts.rb +66 -0
  185. data/lib/badline/chips/z80.rb +13 -0
  186. data/lib/badline/core.rb +26 -28
  187. data/lib/badline/drives/datasette/saved_state.rb +37 -0
  188. data/lib/badline/drives/datasette.rb +140 -0
  189. data/lib/badline/drives/engine/core.rb +149 -0
  190. data/lib/badline/drives/engine/fast_serial.rb +75 -0
  191. data/lib/badline/drives/engine/idle.rb +127 -0
  192. data/lib/badline/drives/engine/idle_cpu.rb +30 -0
  193. data/lib/badline/drives/engine/orbit.rb +81 -0
  194. data/lib/badline/drives/engine/serial_lines.rb +75 -0
  195. data/lib/badline/drives/engine/sleep.rb +114 -0
  196. data/lib/badline/drives/engine/vias.rb +86 -0
  197. data/lib/badline/drives/engine/watch.rb +152 -0
  198. data/lib/badline/drives/engine.rb +11 -0
  199. data/lib/badline/drives/model1541/bus.rb +88 -0
  200. data/lib/badline/drives/model1541/byte_ready.rb +50 -0
  201. data/lib/badline/drives/model1541/cpu.rb +13 -0
  202. data/lib/badline/drives/model1541/disk/saved_state.rb +88 -0
  203. data/lib/badline/drives/model1541/disk.rb +317 -0
  204. data/lib/badline/drives/model1541/disk_via.rb +38 -0
  205. data/lib/badline/drives/model1541/gcr.rb +59 -0
  206. data/lib/badline/drives/model1541/mechanism/saved_state.rb +72 -0
  207. data/lib/badline/drives/model1541/mechanism.rb +315 -0
  208. data/lib/badline/drives/model1541/rotation.rb +123 -0
  209. data/lib/badline/drives/model1541/saved_state.rb +44 -0
  210. data/lib/badline/drives/model1541/sector_reader.rb +78 -0
  211. data/lib/badline/drives/model1541/serial_port.rb +20 -0
  212. data/lib/badline/drives/model1541/track.rb +100 -0
  213. data/lib/badline/drives/model1541.rb +81 -0
  214. data/lib/badline/drives/model1571/bus.rb +113 -0
  215. data/lib/badline/drives/model1571/cpu.rb +13 -0
  216. data/lib/badline/drives/model1571/saved_state.rb +47 -0
  217. data/lib/badline/drives/model1571/serial_port.rb +39 -0
  218. data/lib/badline/drives/model1571/serial_via.rb +27 -0
  219. data/lib/badline/drives/model1571/wd1770.rb +122 -0
  220. data/lib/badline/drives/model1571.rb +142 -0
  221. data/lib/badline/drives/model1581/bus.rb +139 -0
  222. data/lib/badline/drives/model1581/cpu.rb +13 -0
  223. data/lib/badline/drives/model1581/disk/saved_state.rb +89 -0
  224. data/lib/badline/drives/model1581/disk.rb +137 -0
  225. data/lib/badline/drives/model1581/mechanism.rb +119 -0
  226. data/lib/badline/drives/model1581/saved_state.rb +42 -0
  227. data/lib/badline/drives/model1581/serial_port.rb +54 -0
  228. data/lib/badline/drives/model1581/slot.rb +79 -0
  229. data/lib/badline/drives/model1581/track.rb +102 -0
  230. data/lib/badline/drives/model1581/track_bytes.rb +77 -0
  231. data/lib/badline/drives/model1581/wd1772/registers.rb +91 -0
  232. data/lib/badline/drives/model1581/wd1772/saved_state.rb +68 -0
  233. data/lib/badline/drives/model1581/wd1772/sector_writes.rb +75 -0
  234. data/lib/badline/drives/model1581/wd1772/sectors.rb +152 -0
  235. data/lib/badline/drives/model1581/wd1772/stepping.rb +111 -0
  236. data/lib/badline/drives/model1581/wd1772/tracks.rb +127 -0
  237. data/lib/badline/drives/model1581/wd1772/turn.rb +75 -0
  238. data/lib/badline/drives/model1581/wd1772.rb +218 -0
  239. data/lib/badline/drives/model1581.rb +206 -0
  240. data/lib/badline/drives/serial_bus.rb +161 -0
  241. data/lib/badline/frontend/boot.rb +3 -3
  242. data/lib/badline/frontend/machine_window.rb +3 -1
  243. data/lib/badline/frontend/player/filter_view.rb +1 -1
  244. data/lib/badline/frontend/player/player_controller.rb +2 -2
  245. data/lib/badline/frontend/player/player_screen.rb +1 -0
  246. data/lib/badline/frontend/player/theme.rb +7 -7
  247. data/lib/badline/frontend/timeline.rb +3 -3
  248. data/lib/badline/input/control_ports.rb +78 -0
  249. data/lib/badline/input/joystick.rb +27 -0
  250. data/lib/badline/input/keyboard.rb +114 -0
  251. data/lib/badline/input.rb +3 -0
  252. data/lib/badline/kernal_trap/{drive → dos}/block_commands.rb +1 -1
  253. data/lib/badline/kernal_trap/dos/channel.rb +183 -0
  254. data/lib/badline/kernal_trap/{drive → dos}/channels.rb +1 -1
  255. data/lib/badline/kernal_trap/{drive → dos}/memory.rb +1 -1
  256. data/lib/badline/kernal_trap/{drive → dos}/parameters.rb +1 -1
  257. data/lib/badline/kernal_trap/{drive → dos}/status.rb +1 -1
  258. data/lib/badline/kernal_trap/{drive → dos}/write_file.rb +1 -1
  259. data/lib/badline/kernal_trap/{drive → dos}/writes.rb +1 -1
  260. data/lib/badline/kernal_trap/{drive.rb → dos.rb} +11 -10
  261. data/lib/badline/kernal_trap/load.rb +5 -5
  262. data/lib/badline/kernal_trap/save.rb +4 -4
  263. data/lib/badline/kernal_trap/serial.rb +7 -7
  264. data/lib/badline/kernal_trap.rb +1 -2
  265. data/lib/badline/machine/clocking.rb +1 -1
  266. data/lib/badline/machine.rb +5 -5
  267. data/lib/badline/media/true_drive.rb +1 -1
  268. data/lib/badline/media/tune.rb +2 -2
  269. data/lib/badline/media.rb +3 -3
  270. data/lib/badline/model.rb +1 -1
  271. data/lib/badline/roms/README +6 -6
  272. data/lib/badline/sdl.rb +1 -0
  273. data/lib/badline/{storage/sid_file.rb → sid_tune/file.rb} +3 -3
  274. data/lib/badline/{storage → sid_tune}/hvsc.rb +7 -7
  275. data/lib/badline/{storage → sid_tune}/song_lengths.rb +2 -2
  276. data/lib/badline/{storage → sid_tune}/stil/credit.rb +1 -1
  277. data/lib/badline/{storage → sid_tune}/stil.rb +3 -3
  278. data/lib/badline/sid_tune.rb +6 -0
  279. data/lib/badline/snapshot/c128_setup.rb +43 -0
  280. data/lib/badline/snapshot/c64_setup.rb +79 -0
  281. data/lib/badline/snapshot/image.rb +5 -25
  282. data/lib/badline/snapshot/machine_state.rb +1 -1
  283. data/lib/badline/snapshot/setup.rb +22 -66
  284. data/lib/badline/snapshot/state.rb +8 -18
  285. data/lib/badline/snapshot/storage_setup.rb +68 -0
  286. data/lib/badline/snapshot/vic20_setup.rb +37 -0
  287. data/lib/badline/snapshot/vice/c64_mem.rb +1 -1
  288. data/lib/badline/snapshot/vice/restore.rb +1 -1
  289. data/lib/badline/snapshot/vice/reu1764.rb +1 -1
  290. data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
  291. data/lib/badline/snapshot/vice.rb +7 -5
  292. data/lib/badline/snapshot.rb +3 -4
  293. data/lib/badline/storage/d64_image.rb +0 -2
  294. data/lib/badline/storage/d71_image.rb +0 -2
  295. data/lib/badline/storage/d81_image.rb +0 -2
  296. data/lib/badline/storage/disk_image.rb +3 -6
  297. data/lib/badline/storage/g64_image.rb +2 -2
  298. data/lib/badline/storage/host_directory.rb +0 -5
  299. data/lib/badline/storage/t64.rb +2 -8
  300. data/lib/badline/storage/unavailable.rb +1 -1
  301. data/lib/badline/storage.rb +0 -37
  302. data/lib/badline/support/c128_checkpoint.rb +39 -0
  303. data/lib/badline/support/checkpoint.rb +108 -0
  304. data/lib/badline/support/vic20_checkpoint.rb +38 -0
  305. data/lib/badline/support.rb +5 -0
  306. data/lib/badline/version.rb +1 -1
  307. data/lib/badline/vic20/attachments.rb +5 -5
  308. data/lib/badline/vic20/bus/saved_state.rb +35 -0
  309. data/lib/badline/vic20/bus.rb +3 -25
  310. data/lib/badline/vic20/cpu.rb +1 -1
  311. data/lib/badline/vic20/port_wiring.rb +4 -4
  312. data/lib/badline/vic20/saved_state.rb +16 -30
  313. data/lib/badline/vic20/user_via_ports.rb +2 -2
  314. data/lib/badline/vic20.rb +19 -14
  315. metadata +245 -221
  316. data/lib/badline/address_bus/extra_sids.rb +0 -30
  317. data/lib/badline/address_bus/fittings.rb +0 -38
  318. data/lib/badline/address_bus/pla.rb +0 -147
  319. data/lib/badline/address_bus/roms.rb +0 -39
  320. data/lib/badline/address_bus/saved_state.rb +0 -66
  321. data/lib/badline/address_bus/sid_slots.rb +0 -42
  322. data/lib/badline/address_bus.rb +0 -216
  323. data/lib/badline/cartridge/action_replay.rb +0 -126
  324. data/lib/badline/cartridge/atomic_power.rb +0 -24
  325. data/lib/badline/cartridge/bank.rb +0 -81
  326. data/lib/badline/cartridge/comal80.rb +0 -50
  327. data/lib/badline/cartridge/dinamic.rb +0 -34
  328. data/lib/badline/cartridge/easy_flash.rb +0 -145
  329. data/lib/badline/cartridge/epyx_fastload.rb +0 -79
  330. data/lib/badline/cartridge/final_cartridge3.rb +0 -89
  331. data/lib/badline/cartridge/flash.rb +0 -306
  332. data/lib/badline/cartridge/freezer.rb +0 -33
  333. data/lib/badline/cartridge/fun_play.rb +0 -38
  334. data/lib/badline/cartridge/g_mod2.rb +0 -74
  335. data/lib/badline/cartridge/game_system.rb +0 -40
  336. data/lib/badline/cartridge/geo_ram.rb +0 -79
  337. data/lib/badline/cartridge/kcs_power.rb +0 -75
  338. data/lib/badline/cartridge/mach5.rb +0 -32
  339. data/lib/badline/cartridge/magic_desk.rb +0 -30
  340. data/lib/badline/cartridge/ocean.rb +0 -35
  341. data/lib/badline/cartridge/pagefox.rb +0 -68
  342. data/lib/badline/cartridge/retro_replay.rb +0 -320
  343. data/lib/badline/cartridge/rex_utility.rb +0 -29
  344. data/lib/badline/cartridge/rgcd.rb +0 -58
  345. data/lib/badline/cartridge/simons_basic.rb +0 -35
  346. data/lib/badline/cartridge/standard.rb +0 -15
  347. data/lib/badline/cartridge/super_games.rb +0 -48
  348. data/lib/badline/cartridge/westermann.rb +0 -30
  349. data/lib/badline/cartridge/zaxxon.rb +0 -66
  350. data/lib/badline/cartridge.rb +0 -303
  351. data/lib/badline/checkpoint.rb +0 -98
  352. data/lib/badline/cia/fast_forward.rb +0 -60
  353. data/lib/badline/cia/interrupt_register.rb +0 -143
  354. data/lib/badline/cia/serial.rb +0 -275
  355. data/lib/badline/cia/state.rb +0 -47
  356. data/lib/badline/cia/timer.rb +0 -206
  357. data/lib/badline/cia.rb +0 -279
  358. data/lib/badline/color_memory.rb +0 -25
  359. data/lib/badline/control_ports.rb +0 -76
  360. data/lib/badline/cpu/addressing.rb +0 -131
  361. data/lib/badline/cpu/boundary.rb +0 -54
  362. data/lib/badline/cpu/core.rb +0 -165
  363. data/lib/badline/cpu/microcode.rb +0 -177
  364. data/lib/badline/cpu/operations.rb +0 -88
  365. data/lib/badline/cpu/saved_state.rb +0 -115
  366. data/lib/badline/cpu/stack_operations.rb +0 -82
  367. data/lib/badline/cpu.rb +0 -10
  368. data/lib/badline/cpu_port.rb +0 -112
  369. data/lib/badline/datasette.rb +0 -161
  370. data/lib/badline/drive/core.rb +0 -147
  371. data/lib/badline/drive/fast_serial.rb +0 -73
  372. data/lib/badline/drive/idle.rb +0 -125
  373. data/lib/badline/drive/idle_cpu.rb +0 -28
  374. data/lib/badline/drive/orbit.rb +0 -79
  375. data/lib/badline/drive/serial_lines.rb +0 -73
  376. data/lib/badline/drive/sleep.rb +0 -112
  377. data/lib/badline/drive/vias.rb +0 -84
  378. data/lib/badline/drive/watch.rb +0 -150
  379. data/lib/badline/drive.rb +0 -11
  380. data/lib/badline/drive1541/bus.rb +0 -86
  381. data/lib/badline/drive1541/byte_ready.rb +0 -48
  382. data/lib/badline/drive1541/cpu.rb +0 -11
  383. data/lib/badline/drive1541/disk.rb +0 -315
  384. data/lib/badline/drive1541/disk_state.rb +0 -86
  385. data/lib/badline/drive1541/disk_via.rb +0 -36
  386. data/lib/badline/drive1541/gcr.rb +0 -57
  387. data/lib/badline/drive1541/mechanism.rb +0 -313
  388. data/lib/badline/drive1541/mechanism_state.rb +0 -68
  389. data/lib/badline/drive1541/rotation.rb +0 -121
  390. data/lib/badline/drive1541/sector_reader.rb +0 -76
  391. data/lib/badline/drive1541/serial_port.rb +0 -18
  392. data/lib/badline/drive1541/track.rb +0 -98
  393. data/lib/badline/drive1541.rb +0 -111
  394. data/lib/badline/drive1571/bus.rb +0 -111
  395. data/lib/badline/drive1571/cpu.rb +0 -11
  396. data/lib/badline/drive1571/serial_port.rb +0 -37
  397. data/lib/badline/drive1571/serial_via.rb +0 -25
  398. data/lib/badline/drive1571/wd1770.rb +0 -120
  399. data/lib/badline/drive1571.rb +0 -175
  400. data/lib/badline/drive1581/bus.rb +0 -137
  401. data/lib/badline/drive1581/cpu.rb +0 -11
  402. data/lib/badline/drive1581/disk.rb +0 -135
  403. data/lib/badline/drive1581/disk_state.rb +0 -87
  404. data/lib/badline/drive1581/mechanism.rb +0 -117
  405. data/lib/badline/drive1581/serial_port.rb +0 -52
  406. data/lib/badline/drive1581/slot.rb +0 -78
  407. data/lib/badline/drive1581/track.rb +0 -100
  408. data/lib/badline/drive1581/track_bytes.rb +0 -75
  409. data/lib/badline/drive1581/wd1772/registers.rb +0 -89
  410. data/lib/badline/drive1581/wd1772/sector_writes.rb +0 -73
  411. data/lib/badline/drive1581/wd1772/sectors.rb +0 -150
  412. data/lib/badline/drive1581/wd1772/state.rb +0 -66
  413. data/lib/badline/drive1581/wd1772/stepping.rb +0 -109
  414. data/lib/badline/drive1581/wd1772/tracks.rb +0 -125
  415. data/lib/badline/drive1581/wd1772/turn.rb +0 -73
  416. data/lib/badline/drive1581/wd1772.rb +0 -216
  417. data/lib/badline/drive1581.rb +0 -233
  418. data/lib/badline/iec_bus.rb +0 -159
  419. data/lib/badline/instruction.rb +0 -334
  420. data/lib/badline/instruction_set/arithmetic.rb +0 -114
  421. data/lib/badline/instruction_set/bitwise.rb +0 -126
  422. data/lib/badline/instruction_set/branch.rb +0 -79
  423. data/lib/badline/instruction_set/flag.rb +0 -63
  424. data/lib/badline/instruction_set/illegal.rb +0 -270
  425. data/lib/badline/instruction_set/inc_dec.rb +0 -69
  426. data/lib/badline/instruction_set/stack.rb +0 -52
  427. data/lib/badline/instruction_set/transfer.rb +0 -137
  428. data/lib/badline/instruction_set.rb +0 -55
  429. data/lib/badline/interrupts.rb +0 -104
  430. data/lib/badline/joystick.rb +0 -25
  431. data/lib/badline/kernal_trap/channel.rb +0 -181
  432. data/lib/badline/keyboard.rb +0 -112
  433. data/lib/badline/ram_expansion/banking.rb +0 -30
  434. data/lib/badline/ram_expansion/plus256k.rb +0 -54
  435. data/lib/badline/ram_expansion/plus60k.rb +0 -43
  436. data/lib/badline/ram_expansion/unexpanded.rb +0 -28
  437. data/lib/badline/ram_expansion.rb +0 -21
  438. data/lib/badline/reu/dma/saved_state.rb +0 -50
  439. data/lib/badline/reu/dma.rb +0 -273
  440. data/lib/badline/reu/ram.rb +0 -107
  441. data/lib/badline/reu/saved_state.rb +0 -80
  442. data/lib/badline/reu/trigger.rb +0 -32
  443. data/lib/badline/reu.rb +0 -289
  444. data/lib/badline/sid/catch_up.rb +0 -120
  445. data/lib/badline/sid/decimator.rb +0 -64
  446. data/lib/badline/sid/envelope/state.rb +0 -68
  447. data/lib/badline/sid/envelope.rb +0 -239
  448. data/lib/badline/sid/filter.rb +0 -263
  449. data/lib/badline/sid/voice.rb +0 -77
  450. data/lib/badline/sid/waveform/combined.rb +0 -126
  451. data/lib/badline/sid/waveform/fast_forward.rb +0 -105
  452. data/lib/badline/sid/waveform/noise_writeback.rb +0 -122
  453. data/lib/badline/sid/waveform/state.rb +0 -66
  454. data/lib/badline/sid/waveform.rb +0 -305
  455. data/lib/badline/sid.rb +0 -303
  456. data/lib/badline/time_of_day.rb +0 -228
  457. data/lib/badline/traps.rb +0 -19
  458. data/lib/badline/via/control_lines.rb +0 -122
  459. data/lib/badline/via/fast_forward.rb +0 -53
  460. data/lib/badline/via/interrupt_register.rb +0 -67
  461. data/lib/badline/via/shift_register.rb +0 -180
  462. data/lib/badline/via/state.rb +0 -42
  463. data/lib/badline/via/timer1.rb +0 -131
  464. data/lib/badline/via/timer2.rb +0 -133
  465. data/lib/badline/via.rb +0 -266
  466. data/lib/badline/vic/bank.rb +0 -133
  467. data/lib/badline/vic/border_mask.rb +0 -86
  468. data/lib/badline/vic/collisions.rb +0 -115
  469. data/lib/badline/vic/color_patches.rb +0 -47
  470. data/lib/badline/vic/display_state.rb +0 -185
  471. data/lib/badline/vic/graphics_mode.rb +0 -164
  472. data/lib/badline/vic/graphics_shifter.rb +0 -207
  473. data/lib/badline/vic/register_log.rb +0 -81
  474. data/lib/badline/vic/registers.rb +0 -195
  475. data/lib/badline/vic/sequencer.rb +0 -275
  476. data/lib/badline/vic/sequencer_output.rb +0 -116
  477. data/lib/badline/vic/sequencer_state.rb +0 -89
  478. data/lib/badline/vic/sprite/internal_bus.rb +0 -68
  479. data/lib/badline/vic/sprite/saved_state.rb +0 -64
  480. data/lib/badline/vic/sprite/shifter.rb +0 -146
  481. data/lib/badline/vic/sprite/timing.rb +0 -56
  482. data/lib/badline/vic/sprite.rb +0 -337
  483. data/lib/badline/vic/sprites.rb +0 -282
  484. data/lib/badline/vic/sprites_state.rb +0 -57
  485. data/lib/badline/vic.rb +0 -853
  486. data/lib/badline/vic20/sound/output.rb +0 -83
  487. data/lib/badline/vic20/sound.rb +0 -233
  488. data/lib/badline/z80/arithmetic.rb +0 -117
  489. data/lib/badline/z80/bit_page.rb +0 -55
  490. data/lib/badline/z80/block_io.rb +0 -58
  491. data/lib/badline/z80/block_transfers.rb +0 -59
  492. data/lib/badline/z80/bus_cycles.rb +0 -111
  493. data/lib/badline/z80/core.rb +0 -113
  494. data/lib/badline/z80/exchanges.rb +0 -50
  495. data/lib/badline/z80/extended_page.rb +0 -89
  496. data/lib/badline/z80/flags.rb +0 -37
  497. data/lib/badline/z80/interrupt_acceptance.rb +0 -46
  498. data/lib/badline/z80/jumps.rb +0 -82
  499. data/lib/badline/z80/loads.rb +0 -98
  500. data/lib/badline/z80/main_page.rb +0 -134
  501. data/lib/badline/z80/registers.rb +0 -120
  502. data/lib/badline/z80/saved_state.rb +0 -69
  503. data/lib/badline/z80/shifts.rb +0 -64
  504. data/lib/badline/z80.rb +0 -11
  505. /data/lib/badline/snapshot/{fields.rb → vice/fields.rb} +0 -0
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/drives/datasette/saved_state"
4
+
5
+ module Badline
6
+ module Drives
7
+ # The 1530 datasette. Plays a pulse stream into CIA 1's FLAG pin while the
8
+ # motor runs with a key pressed, and reports the keys through the cassette
9
+ # sense line on the $01 port. With RECORD down too, it records the
10
+ # machine's write line onto the tape instead.
11
+ class Datasette
12
+ include SavedState
13
+
14
+ # What inserting a tape raises on a machine without a cassette port.
15
+ class Missing < ArgumentError; end
16
+
17
+ attr_reader :tape
18
+ attr_writer :motor
19
+
20
+ def initialize(tape = nil)
21
+ @tape = tape
22
+ @connected = true
23
+ @playing = false
24
+ @recording = false
25
+ @write_high = true
26
+ @since = 0
27
+ @motor = false
28
+ @countdown = 0
29
+ @flag_handler = nil
30
+ @sense_handler = nil
31
+ end
32
+
33
+ # Falling edges on the tape read line.
34
+ def on_flag(&handler)
35
+ @flag_handler = handler
36
+ end
37
+
38
+ # The cassette sense line, which the $01 port reads back.
39
+ def on_sense_change(&handler)
40
+ @sense_handler = handler
41
+ end
42
+
43
+ # Whether the machine has a datasette at its cassette port. The SX-64
44
+ # has none: its keys stay up and it takes no tape.
45
+ def connected? = @connected
46
+
47
+ def disconnect!
48
+ eject
49
+ @connected = false
50
+ end
51
+
52
+ def insert(tape)
53
+ raise Missing, "this machine has no datasette" unless @connected
54
+
55
+ @tape = tape
56
+ rewind
57
+ end
58
+
59
+ def eject
60
+ stop!
61
+ @tape = nil
62
+ end
63
+
64
+ def rewind
65
+ @tape&.rewind
66
+ @countdown = 0
67
+ end
68
+
69
+ def play! = press(true)
70
+ def stop! = press(false)
71
+
72
+ # Presses RECORD and PLAY together.
73
+ def record!
74
+ return if !@connected || @tape.nil?
75
+
76
+ press(true)
77
+ @recording = true
78
+ @since = 0
79
+ end
80
+
81
+ def recording? = @recording
82
+
83
+ # The machine's tape write line. While the deck records with its motor
84
+ # running, each rising edge ends a pulse on the tape, as long as the
85
+ # time since the edge before, and plays back as a falling edge on the
86
+ # read line.
87
+ def write_line=(high)
88
+ rose = high && !@write_high
89
+ @write_high = high
90
+ return unless rose && @recording && running?
91
+
92
+ @tape.record_pulse(@since)
93
+ @since = 0
94
+ end
95
+
96
+ def playing? = @playing
97
+
98
+ # Sense reads low while a key is down on the deck.
99
+ def sense_low? = @playing
100
+
101
+ def motor? = @motor
102
+
103
+ def running? = @playing && @motor && !@tape.nil?
104
+
105
+ def cycle!
106
+ return unless running?
107
+ return @since += 1 if @recording
108
+
109
+ @countdown = @tape.next_pulse.to_i if @countdown.zero?
110
+ return if @countdown.zero?
111
+
112
+ @countdown -= 1
113
+ @flag_handler&.call if @countdown.zero?
114
+ end
115
+
116
+ def inspect
117
+ "#<#{self.class.name} tape=#{@tape ? @tape.class.name : 'none'} " \
118
+ "playing=#{@playing} motor=#{@motor}>"
119
+ end
120
+
121
+ private
122
+
123
+ def press(down)
124
+ return if down == @playing || !@connected
125
+
126
+ finish_recording unless down
127
+ @playing = down
128
+ @sense_handler&.call
129
+ end
130
+
131
+ # Releasing the keys ends a recording, and writes the tape out.
132
+ def finish_recording
133
+ return unless @recording
134
+
135
+ @recording = false
136
+ @tape.save
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ module Engine
6
+ # What every Commodore disk drive here shares: a 6502 running the DOS
7
+ # ROM, with chips on its bus facing the serial bus and the disk
8
+ # mechanism, on a clock of its own.
9
+ #
10
+ # The drive runs on its own crystal, so it clocks against the host's
11
+ # clock through a fractional accumulator: each host cycle adds the
12
+ # drive's clock rate worth of phase, and every whole host period in it
13
+ # runs a drive cycle. Against the PAL C64's 985,248 Hz a drive at
14
+ # 1 MHz runs one drive cycle per host cycle and a second one about
15
+ # every 67. The host sets its clock on attaching the drive, and until
16
+ # then a 1 MHz drive runs one cycle per host cycle.
17
+ #
18
+ # The Mechanism reads a Disk put in with insert.
19
+ #
20
+ # While the DOS idles, host_cycle! skips the drive's cycles and catches
21
+ # up on them later, exactly (see Idle). The readers of the drive's parts
22
+ # catch up first, so they find the drive as running every cycle would
23
+ # have left it. Once the DOS's timer interrupts come round, the drive
24
+ # sleeps through them too (see Orbit).
25
+ #
26
+ # A model includes Core and builds its parts, sets @clock_hz and
27
+ # @idle_loop, and runs one drive cycle in step. It hears ATN on
28
+ # connecting (hear_atn), drives the serial bus (serial_output), and
29
+ # answers Idle's and Orbit's questions about its chips, as VIAs does
30
+ # for the 1541 and the 1571.
31
+ module Core
32
+ include Sleep
33
+ include Idle
34
+ include Orbit
35
+
36
+ attr_reader :device, :serial_bus
37
+
38
+ def cpu
39
+ settle!
40
+ @cpu
41
+ end
42
+
43
+ def bus
44
+ settle!
45
+ @bus
46
+ end
47
+
48
+ def mechanism
49
+ settle!
50
+ @mechanism
51
+ end
52
+
53
+ def cycles
54
+ settle!
55
+ @cycles
56
+ end
57
+
58
+ def ram = bus.ram
59
+
60
+ def host_clock_hz=(clock_hz)
61
+ settle!
62
+ @host_clock_hz = clock_hz
63
+ end
64
+
65
+ # Plugs the drive into a serial bus, leaving the one it was on. A drive
66
+ # starts out on a bus of its own, with nothing else on it.
67
+ def connect(serial_bus)
68
+ settle!
69
+ @serial_bus&.detach(self)
70
+ @serial_bus = serial_bus
71
+ @serial_port.bus = serial_bus
72
+ serial_bus.attach(self)
73
+ hear_atn
74
+ end
75
+
76
+ # Puts a Disk in the drive (Disk.from_d64 makes one from an image).
77
+ # Nil takes the disk out.
78
+ def insert(disk)
79
+ settle!
80
+ @mechanism.insert(disk)
81
+ end
82
+
83
+ def disk = mechanism.disk
84
+
85
+ # Whether the LED is lit. Reading it leaves the drive asleep: the LED
86
+ # is the same at the end of every pass the drive sleeps through.
87
+ def led_on? = @mechanism.led_on?
88
+
89
+ # Stores what the head wrote since the motor last stopped in the
90
+ # disk's image, as the motor stopping does.
91
+ def flush
92
+ settle!
93
+ @mechanism.flush
94
+ end
95
+
96
+ # Runs the drive cycles that fall in one host cycle: none, one or two.
97
+ # The host has run this cycle already, and the drive sees what it did
98
+ # from the next one on (see SerialPort). Asleep, the drive owes the
99
+ # cycles instead, until ATN moves or its counters are due (see Idle).
100
+ # It looks at ATN only after the machine pushed its lines into the bus
101
+ # (see host_written!).
102
+ def host_cycle!
103
+ if @asleep
104
+ return if (@slept += 1) != @wake_at && @host_still
105
+
106
+ return doze
107
+ end
108
+
109
+ phase = @phase + @clock_hz
110
+ while phase >= @host_clock_hz
111
+ @asleep ? @owed += 1 : run_cycle
112
+ phase -= @host_clock_hz
113
+ end
114
+ @phase = phase
115
+ settle! if @serial_port.atn_moved?
116
+ @serial_port.latch_host
117
+ plan_wake if @asleep
118
+ end
119
+
120
+ # The machine pushed its lines into the bus, so ATN may have moved.
121
+ def host_written!
122
+ @host_still = false
123
+ end
124
+
125
+ # The host moved its fast serial pins, which a 1541 has none to hear.
126
+ def fast_lines_moved = nil
127
+
128
+ # Runs one drive cycle, catching up first on any the drive owes (see
129
+ # step).
130
+ def cycle!
131
+ settle!
132
+ step
133
+ end
134
+
135
+ def inspect
136
+ "#<#{self.class.name} cycles=#{cycles} cpu=(#{cpu.inspect})>"
137
+ end
138
+
139
+ private
140
+
141
+ # A drive cycle from host_cycle!, which may find the idle loop.
142
+ def run_cycle
143
+ step
144
+ idle_loop_reached if @cpu.program_counter == @idle_loop && @idle_skip
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ module Engine
6
+ # Fast serial on a drive with a CIA, the 1571's 6526 or the 1581's
7
+ # 8520: through buffers a port line turns round, the CIA's CNT drives
8
+ # SRQ and its SP drives DATA, or it hears them. The drive pushes its
9
+ # pins into the bus as they move, and hears the host's as the host
10
+ # pushes them, pin by pin, so each byte goes through both shift
11
+ # registers bit by bit. The CIA takes no part in a pass of the idle
12
+ # loop, and any access to it, or the host moving its fast serial pins,
13
+ # wakes the drive.
14
+ #
15
+ # A model includes it beside Core, and calls turn_fast_serial when its
16
+ # direction line moves and drive_fast_serial each cycle the buffers
17
+ # face out. Its serial_output carries @fast_output above its port.
18
+ module FastSerial
19
+ # Whether the buffers face out, the drive's CIA driving DATA and SRQ.
20
+ attr_reader :fast_serial_out
21
+
22
+ # The host moved its fast serial pins: the CIA hears SRQ on CNT and
23
+ # DATA on SP while the buffers face in.
24
+ def fast_lines_moved
25
+ settle!
26
+ hear_fast_serial unless @fast_serial_out
27
+ end
28
+
29
+ private
30
+
31
+ def init_fast_serial
32
+ @fast_serial_out = false
33
+ @fast_output = 0
34
+ end
35
+
36
+ # The buffers turned round: outwards the CIA's pins drive the lines,
37
+ # and inwards they let go and hear them.
38
+ def turn_fast_serial(out)
39
+ @fast_serial_out = out
40
+ return unless @serial_bus
41
+
42
+ push_fast_output(out ? fast_pins : 0)
43
+ hear_fast_serial unless out
44
+ end
45
+
46
+ def drive_fast_serial
47
+ low = fast_pins
48
+ push_fast_output(low) if low != @fast_output
49
+ end
50
+
51
+ # The lines the CIA's CNT and SP pull while its serial port drives
52
+ # them.
53
+ def fast_pins
54
+ serial = @cia.serial
55
+ return 0 unless serial.output?
56
+
57
+ low = serial.cnt ? 0 : SerialBus::DRIVE_FAST_SRQ
58
+ serial.sp_out ? low : low | SerialBus::DRIVE_FAST_DATA
59
+ end
60
+
61
+ def push_fast_output(low)
62
+ @fast_output = low
63
+ @serial_bus&.drives_fast_moved!
64
+ end
65
+
66
+ def hear_fast_serial
67
+ low = @serial_bus.low_lines
68
+ serial = @cia.serial
69
+ serial.cnt_in = low.nobits?(SerialBus::SRQ)
70
+ serial.sp_in = low.nobits?(SerialBus::DATA)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ module Engine
6
+ # Skipping the drive's cycles while the DOS idles, exactly.
7
+ #
8
+ # With nothing to do, the DOS goes round its idle loop from the
9
+ # model's @idle_loop ($EBFF in the 1541, 446 cycles a pass), until VIA
10
+ # 2's timer 1 interrupts it every 14,850 cycles for the job loop, or
11
+ # ATN interrupts it through VIA 1's CA1. A pass writes RAM and VIA 2's
12
+ # port B, but puts back what it found, so the drive comes round to the
13
+ # loop's start as it left it. Only the timers' counters and the cycle
14
+ # counts move.
15
+ #
16
+ # Each time the CPU comes to the loop's start, the drive records the
17
+ # pass that follows. At the next it checks that the pass
18
+ #
19
+ # - left the CPU, both VIAs but for their counters, the bus's last
20
+ # byte, the SO pin, the mechanism (Mechanism#idle_state) and what
21
+ # the ports read from it, and every byte of RAM it read or wrote as
22
+ # it found them (Bus#watch!)
23
+ # - read nothing that changes from pass to pass: no counter, no shift
24
+ # register, and not VIA 1's port B, which reads the serial bus
25
+ # - wrote nothing that reaches outside the drive: not VIA 1, whose port
26
+ # B drives the serial bus, and not the motor on
27
+ # - ran while no counter could set a flag (VIA#quiet_cycles), with the
28
+ # motor off, no interrupt pulled and no trap on the CPU.
29
+ #
30
+ # Such a pass runs the same way again from where it ended, for as
31
+ # long as ATN holds still and no counter sets a flag, so the drive
32
+ # sleeps: host_cycle! only counts the host cycles that go by (see
33
+ # Sleep). It wakes
34
+ # when ATN moves, when a counter is due to set a flag, or when something
35
+ # outside reads or changes the drive (the readers in Core call
36
+ # settle!). Waking counts off the whole passes it owes in bulk,
37
+ # moving the counters on, and runs the rest cycle by cycle.
38
+ #
39
+ # The loop reads neither CLK nor DATA, so the drive sleeps through them
40
+ # moving and takes the C64's lines as they stand once it wakes. Its
41
+ # own lines hold still while it sleeps, so the C64 reads them without
42
+ # waking it (serial_output).
43
+ #
44
+ # A pass starts at the loop's start, where the CPU always comes from
45
+ # the loop's last instruction, a JMP, so what that leaves in the CPU's
46
+ # working registers is the same each time round.
47
+ #
48
+ # The timer's interrupts come round too, and once they do, the drive
49
+ # sleeps on through them (see Orbit).
50
+ module Idle
51
+ # Whether the drive may sleep through its idle loop. On by default,
52
+ # but for a drive whose CPU logs each instruction.
53
+ attr_reader :idle_skip
54
+
55
+ def idle_skip=(on)
56
+ settle!
57
+ @idle_skip = on
58
+ end
59
+
60
+ private
61
+
62
+ def init_idle(debug)
63
+ @idle_skip = !debug
64
+ @recording = false
65
+ @pass_cycles = 0
66
+ @pass_instructions = 0
67
+ init_sleep
68
+ init_orbits
69
+ end
70
+
71
+ # The CPU is at the loop's start. At an instruction boundary, the
72
+ # drive sleeps if the pass it recorded can repeat, and otherwise
73
+ # records the next.
74
+ def idle_loop_reached
75
+ return unless @cpu.boundary?
76
+
77
+ if @recording
78
+ stop_recording
79
+ return fall_asleep if repeatable_pass? && room_for_pass?
80
+ end
81
+ start_recording
82
+ end
83
+
84
+ def start_recording
85
+ return if busy_for_pass? || @cpu.trapped?
86
+
87
+ @recording = true
88
+ @record_state = idle_state
89
+ @record_cycles = @cycles
90
+ @record_instructions = @cpu.instructions
91
+ @record_quiet = quiet_cycles
92
+ @bus.watch!
93
+ end
94
+
95
+ def stop_recording
96
+ @recording = false
97
+ @bus.unwatch!
98
+ end
99
+
100
+ # Whether the pass just recorded can repeat.
101
+ def repeatable_pass?
102
+ !@bus.volatile && @cycles - @record_cycles <= @record_quiet && idle_state == @record_state &&
103
+ ram_as_found?
104
+ end
105
+
106
+ # Whether the counters leave room for a whole pass.
107
+ def room_for_pass? = quiet_cycles >= @cycles - @record_cycles
108
+
109
+ # Sleeps through the pass just recorded, over and over.
110
+ def fall_asleep
111
+ @pass_cycles = @cycles - @record_cycles
112
+ @pass_instructions = @cpu.instructions - @record_instructions
113
+ @asleep = true
114
+ @host_still = false
115
+ @owed = 0
116
+ @budget = quiet_cycles
117
+ anchor
118
+ end
119
+
120
+ def ram_as_found?
121
+ ram = @bus.ram
122
+ @bus.touched.all? { |addr, value| ram.peek(addr) == value }
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ module Engine
6
+ # What Idle needs of a drive's 6502, which includes it beside
7
+ # CPU::Core.
8
+ module IdleCPU
9
+ # Everything the CPU holds but its cycle and instruction counts: the
10
+ # registers, the interrupt lines and pipeline, and what the last
11
+ # instruction left in its working registers. Drives::Engine::Idle compares
12
+ # it at two instruction boundaries.
13
+ def idle_state
14
+ [@program_counter, @stack_pointer, @a, @x, @y, @status.value,
15
+ @irq, @nmi, @irq_sample, @irq_pending, @nmi_sample, @nmi_pending, @skip_poll,
16
+ @boundary_irq, @boundary_nmi, @so_high, @interrupt, @brk, @pending_write, @stalled_at, @traps,
17
+ @operation, @optional_dummy, @boundary_crossed, @branch_taken,
18
+ @address, @pointer, @dummy_address, @value, @rmw_result]
19
+ end
20
+
21
+ # Counts +cycles+ cycles and +instructions+ instructions that ran
22
+ # without changing anything idle_state holds.
23
+ def fast_forward(cycles, instructions)
24
+ @cycles += cycles
25
+ @instructions += instructions
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ module Engine
6
+ # Sleeping through the DOS's timer interrupts, exactly, once they come
7
+ # round.
8
+ #
9
+ # VIA 2's timer 1 interrupts the idle loop for the job loop, which
10
+ # finds no job, restarts the timer and returns into the pass it cut
11
+ # into, 14,998 cycles and more apart. The interrupts land at a
12
+ # different point in the pass each time, until, six of them on, the
13
+ # whole drive is back where it was: an orbit of 90,044 cycles.
14
+ #
15
+ # Each place the drive falls asleep (see Idle) is an anchor, and the
16
+ # drive keeps everything it holds at each one: RAM, the counters of
17
+ # the timers that are armed or that it read or wrote since, and the
18
+ # rest as Idle compares a pass. It keeps them only while it keeps to
19
+ # itself, with Bus#guard! checking that it doesn't read the serial
20
+ # bus, write VIA 1, turn the motor on or change the LED. ATN moving,
21
+ # or a reader settling the drive, forgets them.
22
+ #
23
+ # Coming to an anchor it kept before closes an orbit, which runs the
24
+ # same way again from here for as long as ATN holds still, so the
25
+ # drive sleeps on without waking for its counters. Waking counts off
26
+ # the whole orbits it owes in bulk, moving on only the counters it
27
+ # never touched, and runs the rest as Idle does.
28
+ module Orbit
29
+ # How many anchors the drive keeps while it looks for an orbit.
30
+ ANCHORS = 32
31
+
32
+ private
33
+
34
+ def init_orbits
35
+ @anchors = {}
36
+ @orbit_cycles = nil
37
+ @orbit_instructions = 0
38
+ @bus.guard!
39
+ end
40
+
41
+ # The drive falls asleep at an anchor. One it came to before closes
42
+ # an orbit: everything from there to here runs the same way again.
43
+ def anchor
44
+ forget_orbits if @bus.tainted || @anchors.size >= ANCHORS
45
+ key = anchor_state
46
+ if (seen = @anchors[key])
47
+ @orbit_cycles = @cycles - seen[0]
48
+ @orbit_instructions = @cpu.instructions - seen[1]
49
+ else
50
+ @anchors[key] = [@cycles, @cpu.instructions]
51
+ end
52
+ end
53
+
54
+ def forget_orbits
55
+ @anchors.clear
56
+ @orbit_cycles = nil
57
+ @bus.guard!
58
+ end
59
+
60
+ # Runs whole orbits, which bring the drive back to the anchor it
61
+ # sleeps at but for the counters it never touched. Returns the
62
+ # cycles.
63
+ def skip_orbits(orbits)
64
+ cycles = orbits * @orbit_cycles
65
+ touched = @bus.touched_timers
66
+ @cpu.fast_forward(cycles, orbits * @orbit_instructions)
67
+ skip_chip_orbits(cycles, touched)
68
+ @cycles += cycles
69
+ cycles
70
+ end
71
+
72
+ # Everything the drive holds at an anchor, but for the counters of
73
+ # the unarmed timers it hasn't touched since it was last tainted.
74
+ def anchor_state
75
+ touched = @bus.touched_timers
76
+ [*idle_state, *counter_state(touched), @bus.ram.snapshot]
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Drives
5
+ module Engine
6
+ # What VIA 1's port B reads from the serial bus. DATA IN (PB0), CLK IN
7
+ # (PB2) and ATN IN (PB7) come through inverters, so a released line
8
+ # reads 0 and a pulled one 1. The jumpers on PB5 and PB6 pull a line
9
+ # low when closed, and both closed make device 8.
10
+ #
11
+ # The drive sees the host's side of the bus a host cycle late. The
12
+ # host's CIA changes its pins at the end of the cycle that writes them,
13
+ # and the drive's VIA samples its own late in each of its cycles, so a
14
+ # drive cycle that runs alongside the write reads the lines from
15
+ # before it. The drive runs after the host in each host cycle (see
16
+ # C64#cycle!), so the port reads the host's lines as latch_host
17
+ # took them at the end of the last one. Fast loaders that time their
18
+ # transfer from an ATN edge, as VICE's drive tests do, depend on it.
19
+ #
20
+ # A model's serial port includes it, with its own port A.
21
+ module SerialLines
22
+ DATA_IN = 0x01
23
+ CLK_IN = 0x04
24
+ ATN_IN = 0x80
25
+ SERIAL_INPUTS = DATA_IN | CLK_IN | ATN_IN
26
+ JUMPERS = 0b0110_0000
27
+
28
+ attr_reader :bus
29
+
30
+ def bus=(bus)
31
+ @bus = bus
32
+ latch_host
33
+ end
34
+
35
+ # Takes the host's lines as the machine last pushed them into the bus,
36
+ # for the drive cycles of the next host cycle.
37
+ def latch_host
38
+ @host = @bus.host_lines
39
+ end
40
+
41
+ # The host's lines as last latched. The jumpers and the bus are the
42
+ # drive's wiring.
43
+ def save_state(out)
44
+ out.int(@host)
45
+ end
46
+
47
+ def load_state(input)
48
+ @host = input.int
49
+ end
50
+
51
+ # Whether the host has moved ATN since the last latch_host.
52
+ def atn_moved? = (@bus.host_lines ^ @host).anybits?(SerialBus::HOST_ATN_OUT)
53
+
54
+ def atn_low? = @bus.atn_low?(@host)
55
+
56
+ def read_b(_lines)
57
+ low = @bus.low_lines(@host)
58
+ value = @port_b
59
+ value |= DATA_IN if low.anybits?(SerialBus::DATA)
60
+ value |= CLK_IN if low.anybits?(SerialBus::CLK)
61
+ value |= ATN_IN if low.anybits?(SerialBus::ATN)
62
+ value
63
+ end
64
+
65
+ private
66
+
67
+ def init_serial_lines(device, bus)
68
+ @port_b = (0xff & ~(SERIAL_INPUTS | JUMPERS)) | (((device - 8) & 0x03) << 5)
69
+ @host = 0
70
+ self.bus = bus
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end