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
@@ -18,32 +18,24 @@ module Badline
18
18
  class Save < FileRoutine
19
19
  SECONDARY = 0x61
20
20
 
21
- # ST bit at $90
21
+ # ST bit
22
22
  DEVICE_NOT_PRESENT = 0x80
23
23
 
24
- def initialize(cpu:, bus:, layout:, drive:)
24
+ def initialize(cpu:, bus:, layout:, dos:)
25
25
  super(cpu:, bus:, layout:)
26
- @drive = drive
26
+ @dos = dos
27
27
  @saving = false
28
28
  end
29
29
 
30
- def save_state(out)
31
- out.boolean(@saving)
32
- end
33
-
34
- def load_state(input)
35
- @saving = input.boolean?
36
- end
37
-
38
30
  def call
39
31
  return unless active?
40
32
  return finish if @saving
41
- return unless @drive.saves?
33
+ return unless @dos.saves?
42
34
 
43
- @bus.poke(0xb9, SECONDARY)
35
+ @bus.poke(zero_page.secondary_address, SECONDARY)
44
36
  return @cpu.program_counter = @layout.missing_file_name_exit if name.empty?
45
37
 
46
- @bus.poke(0x90, 0x00)
38
+ @bus.poke(zero_page.status, 0x00)
47
39
  @saving = true
48
40
  continue_with(@layout.saving_message, @layout.save)
49
41
  end
@@ -56,20 +48,18 @@ module Badline
56
48
 
57
49
  def finish
58
50
  @saving = false
59
- saved = @drive.save(name, payload, replace: full_filename.start_with?("@"))
60
- @bus.poke(0x90, DEVICE_NOT_PRESENT) unless saved
61
- @bus.poke(0xac, @bus.peek(0xae))
62
- @bus.poke(0xad, @bus.peek(0xaf))
51
+ saved = @dos.save(name, payload, replace: full_filename.start_with?("@"))
52
+ @bus.poke(zero_page.status, DEVICE_NOT_PRESENT) unless saved
53
+ poke_word(zero_page.start_address, peek_word(zero_page.end_address))
63
54
  @cpu.y = 0
64
55
  @cpu.status.overflow = true
65
56
  continue_with(@layout.clock_release, @layout.data_release, @layout.save_done)
66
57
  end
67
58
 
68
- # Start address at $C1/$C2 (STAL), end address (exclusive) at
69
- # $AE/$AF (EAL)
59
+ # Start address at STAL, end address (exclusive) at EAL
70
60
  def payload
71
- start = uint16(@bus.peek(0xc1), @bus.peek(0xc2))
72
- length = (uint16(@bus.peek(0xae), @bus.peek(0xaf)) - start) & 0xffff
61
+ start = peek_word(zero_page.save_start)
62
+ length = (peek_word(zero_page.end_address) - start) & 0xffff
73
63
  [low_byte(start), high_byte(start)] +
74
64
  Array.new(length) { |i| @layout.file_byte(@bus, (start + i) & 0xffff) }
75
65
  end
@@ -23,9 +23,9 @@ module Badline
23
23
 
24
24
  NO_DATA = [0x0d, EOI | READ_TIMEOUT].freeze
25
25
 
26
- def initialize(cpu:, bus:, layout:, drive:, device: DEVICE)
26
+ def initialize(cpu:, bus:, layout:, dos:, device: DEVICE)
27
27
  super(cpu:, bus:, layout:)
28
- @drive = drive
28
+ @dos = dos
29
29
  @device = device
30
30
  @listening = false
31
31
  @talking = false
@@ -35,22 +35,6 @@ module Badline
35
35
  @buffer = []
36
36
  end
37
37
 
38
- # The frame under way, with the channels and the bytes it gathered.
39
- # The device it answers is the machine's to set.
40
- def save_state(out)
41
- out.boolean(@listening).boolean(@talking).optional_int(@listen_channel).optional_int(@talk_channel)
42
- out.int(@frame).blob(@buffer)
43
- end
44
-
45
- def load_state(input)
46
- @listening = input.boolean?
47
- @talking = input.boolean?
48
- @listen_channel = input.optional_int
49
- @talk_channel = input.optional_int
50
- @frame = input.int
51
- @buffer = input.blob
52
- end
53
-
54
38
  def install
55
39
  routines.each do |address, routine|
56
40
  @cpu.install_trap(address) { call_routine(routine) if kernal_mapped? }
@@ -144,7 +128,7 @@ module Badline
144
128
  # takes data only on a channel it has open. Otherwise nothing holds
145
129
  # the data line when a byte starts, so the KERNAL finds no device.
146
130
  def accepted?
147
- [OPEN, CLOSE].include?(@frame) || @drive.listening?(@listen_channel)
131
+ [OPEN, CLOSE].include?(@frame) || @dos.listening?(@listen_channel)
148
132
  end
149
133
 
150
134
  def unlisten
@@ -188,15 +172,15 @@ module Badline
188
172
  return unless @listen_channel
189
173
 
190
174
  case @frame
191
- when OPEN then @drive.open(@listen_channel, @buffer.pack("C*"))
192
- when CLOSE then @drive.close(@listen_channel)
193
- else @drive.write(@listen_channel, @buffer)
175
+ when OPEN then @dos.open(@listen_channel, @buffer.pack("C*"))
176
+ when CLOSE then @dos.close(@listen_channel)
177
+ else @dos.write(@listen_channel, @buffer)
194
178
  end
195
179
  @buffer = []
196
180
  end
197
181
 
198
182
  def received
199
- byte, eoi = @drive.read(@talk_channel)
183
+ byte, eoi = @dos.read(@talk_channel)
200
184
  return NO_DATA unless byte
201
185
 
202
186
  [byte, eoi ? EOI : 0]
@@ -205,7 +189,7 @@ module Badline
205
189
  def update_status(bits)
206
190
  return if bits.zero?
207
191
 
208
- @bus.poke(0x90, @bus.peek(0x90) | bits)
192
+ @bus.poke(zero_page.status, @bus.peek(zero_page.status) | bits)
209
193
  end
210
194
  end
211
195
  end
@@ -2,9 +2,10 @@
2
2
 
3
3
  require "badline/kernal_trap/layout"
4
4
  require "badline/kernal_trap/routine"
5
- require "badline/kernal_trap/channel"
6
- require "badline/kernal_trap/drive"
5
+ require "badline/kernal_trap/dos"
7
6
  require "badline/kernal_trap/file_routine"
8
7
  require "badline/kernal_trap/load"
9
8
  require "badline/kernal_trap/save"
10
9
  require "badline/kernal_trap/serial"
10
+ require "badline/kernal_trap/chrout"
11
+ require "badline/kernal_trap/keyed_state"
@@ -3,7 +3,7 @@
3
3
  module Badline
4
4
  module Machine
5
5
  # Running a machine from outside its own #cycle!, and the handlers that
6
- # wait for its KERNAL to boot. Computer, Vic20 and C128 each include it
6
+ # wait for its KERNAL to boot. C64, Vic20 and C128 each include it
7
7
  # and answer #cycle!, #cycles and #init_threshold, the cycle at which
8
8
  # #on_init's handlers run, and keep the handlers in @init_handlers.
9
9
  module Clocking
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Machine
5
+ # Typing into the KERNAL's keyboard buffer once the machine has booted.
6
+ # The machine that includes it answers #keyboard_buffer, the Layout of
7
+ # the KERNAL it runs, and #ram.
8
+ module KeyboardBuffer
9
+ # Where a KERNAL keeps its keyboard buffer (KEYD), the count of
10
+ # characters in it (NDX), and how many it holds.
11
+ Layout = Data.define(:address, :count, :capacity)
12
+
13
+ # The C64's and the VIC-20's.
14
+ C64_LAYOUT = Layout.new(address: 0x0277, count: 0xc6, capacity: 10)
15
+
16
+ # BASIC 7.0's, in C128 mode.
17
+ C128_LAYOUT = Layout.new(address: 0x034a, count: 0xd0, capacity: 10)
18
+
19
+ # The 264 series KERNAL's, which sets its capacity at $053F to 10
20
+ # ($D86E).
21
+ PLUS4_LAYOUT = Layout.new(address: 0x0527, count: 0xef, capacity: 10)
22
+
23
+ def type_text(text)
24
+ codes = text.bytes.map { |b| ascii_to_petscii(b) }
25
+ on_init { @pending_keys = codes }
26
+ end
27
+
28
+ private
29
+
30
+ def feed_keyboard
31
+ buffer = keyboard_buffer
32
+ return unless ram.peek(buffer.count).zero?
33
+
34
+ chunk = @pending_keys.shift(buffer.capacity)
35
+ ram.write(buffer.address, chunk)
36
+ ram.poke(buffer.count, chunk.length)
37
+ @pending_keys = nil if @pending_keys.empty?
38
+ end
39
+
40
+ def ascii_to_petscii(byte)
41
+ case byte
42
+ when 0x61..0x7a then byte - 0x20
43
+ when 0x41..0x5a then byte + 0x80
44
+ else byte
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Machine
5
+ # Brings the machine to the point a snapshot file is saved at: the main
6
+ # CPU between instructions, or jammed, with no REU transfer holding the
7
+ # bus. C64, Vic20 and C128 each include it, and answer
8
+ # #settled_for_snapshot? and #settle_chips_for_snapshot, which brings
9
+ # what each chip defers up to the cycle without running one.
10
+ module Settling
11
+ # The cycles settling may run: the longest instruction stretched by
12
+ # the VIC's longest hold on the bus, and an REU swap of 64K, two
13
+ # cycles a byte, stretched the same way.
14
+ LIMIT = 100 + 0x40000
15
+
16
+ # Runs the machine on, through its own #cycle!, to the settle point,
17
+ # and returns the cycles that took. A settled machine runs none.
18
+ def settle_for_snapshot!
19
+ ran = 0
20
+ while ran < LIMIT && !settled_for_snapshot?
21
+ cycle!
22
+ ran += 1
23
+ end
24
+ settle_chips_for_snapshot
25
+ ran
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,12 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "badline/machine/clocking"
4
+ require "badline/machine/keyboard_buffer"
5
+ require "badline/machine/settling"
4
6
 
5
7
  module Badline
6
8
  # = Machine
7
9
  #
8
10
  # The machines badline builds by family, as the command line's
9
- # subcommand names them: the C64, Computer, the VIC-20, Vic20, and the
11
+ # subcommand names them: the C64, Badline::C64, the VIC-20, Vic20, and the
10
12
  # C128 in C64 mode, C128.
11
13
  #
12
14
  # A machine answers what the front end, Media, the runners and the
@@ -28,7 +30,7 @@ module Badline
28
30
  # +press_cartridge_button+, +release_cartridge_button+,
29
31
  # +attach_drive1541+, +drive1541+, +true_drive+ and +plug_true_drive+
30
32
  # for the drive Media::TrueDrive plugs in, +attach_drive1581+,
31
- # +drive1581+ and +plug_drive1581+ for a 1581 (Drive1581::Slot), and
33
+ # +drive1581+ and +plug_drive1581+ for a 1581 (Drives::Model1581::Slot), and
32
34
  # +address_bus+ for its +cartridge+ and +detach_cartridge+.
33
35
  # - Snapshots and tests: +snapshot+, +restore+, +save_snapshot+,
34
36
  # +install_debug_register+ and +capture_output+.
@@ -58,16 +60,17 @@ module Badline
58
60
  # VIC-20's is "pal", with the RAM expansion `ram` names
59
61
  # (Vic20::Bus::RAM_CONFIGURATIONS), unexpanded when nil. A C128's is
60
62
  # one of C128::Model::ALL, with its SID `sid_model` when not nil, built
61
- # for C64 mode.
63
+ # for C64 mode. :plus4 is refused until the Plus/4 runs.
62
64
  def self.build(family, model:, sid_model: nil, reu: nil, ram: nil)
63
65
  return vic20(model, ram) if family == :vic20
64
66
  return c128(model, sid_model, :c64) if family == :c128
67
+ raise ArgumentError, "the Plus/4 isn't emulated yet" if family == :plus4
65
68
  raise ArgumentError, "no machine family named #{family}" unless family == :c64
66
69
 
67
70
  profile = Model.named(model)
68
- Computer.new(vic_model: profile.vic_model, cia_model: profile.cia_model,
69
- sid_model: sid_model || profile.sid_model, region: profile.region, reu:,
70
- kernal: profile.kernal, datasette: profile.datasette, board: profile.board)
71
+ C64.new(vic_model: profile.vic_model, cia_model: profile.cia_model,
72
+ sid_model: sid_model || profile.sid_model, region: profile.region, reu:,
73
+ kernal: profile.kernal, datasette: profile.datasette, board: profile.board)
71
74
  end
72
75
 
73
76
  # The machine the command line's `options` name, to start `media`, a
@@ -119,7 +122,7 @@ module Badline
119
122
 
120
123
  extension = File.extname(media).downcase
121
124
  return true if extension == ".sid"
122
- return false unless %w[.prg .p00].include?(extension)
125
+ return false unless Media::Extensions::PROGRAMS.include?(extension)
123
126
 
124
127
  [Media::BASIC_START, Media::BASIC_START - 1].include?(Storage::P00.load_address(media))
125
128
  end
@@ -4,7 +4,8 @@ module Badline
4
4
  module Media
5
5
  # A C128 boot disk. At power-on the C128 KERNAL reads track 1, sector 0
6
6
  # of the disk in device 8 and runs it when it starts with "CBM", as boot
7
- # games have it. The 1581's DOS first loads and runs a USR file named
7
+ # games have it, from a sector image or from the raw GCR of a .g64 or
8
+ # .g71. The 1581's DOS first loads and runs a USR file named
8
9
  # COPYRIGHT CBM 86 when the disk has one, which is how CP/M's 1581 disks
9
10
  # hand the KERNAL their boot sector, so a .d81 with that file boots too.
10
11
  #
@@ -15,7 +16,7 @@ module Badline
15
16
  module BootDisk
16
17
  SIGNATURE = "CBM".bytes.freeze
17
18
  AUTO_BOOT = "copyright cbm 86"
18
- TYPES = Extensions.of(%i[disk])
19
+ TYPES = Extensions.of(%i[disk gcr])
19
20
 
20
21
  class << self
21
22
  def takes?(computer, path)
@@ -37,6 +38,7 @@ module Badline
37
38
  def boot?(path)
38
39
  type = File.extname(path).downcase
39
40
  return false unless TYPES.include?(type) && File.file?(path)
41
+ return gcr_signature(path) == SIGNATURE if Extensions.kind(path) == :gcr
40
42
 
41
43
  image = Media.open_storage(path, { read_only: true })
42
44
  block = image.read_block(1, 0)
@@ -44,6 +46,16 @@ module Badline
44
46
 
45
47
  type == ".d81" && !image.read_file(AUTO_BOOT, type: :usr).nil?
46
48
  end
49
+
50
+ private
51
+
52
+ # The first three bytes of track 1, sector 0 as the drive reads them
53
+ # off the GCR of a .g64 or .g71, or nil when the sector isn't there.
54
+ def gcr_signature(path)
55
+ track = Drives::Model1541::Disk.open(path, read_only: true).track(2)
56
+ data = track && Drives::Model1541::SectorReader.read(track.bytes, 1)[0]&.data
57
+ data && data[1, 3]
58
+ end
47
59
  end
48
60
  end
49
61
  end
@@ -28,6 +28,16 @@ module Badline
28
28
 
29
29
  # What goes in device 8 through the traps.
30
30
  MOUNTABLE = of(%i[disk archive])
31
+
32
+ # What goes in device 8, a true drive's or the traps', and the lists
33
+ # of disks to put there.
34
+ DEVICE8 = of(%i[disk gcr archive disk_list])
35
+
36
+ # Programs, which load on their own.
37
+ PROGRAMS = %w[.prg .p00].freeze
38
+
39
+ # Every medium Media.attach takes by its extension.
40
+ ALL = (KINDS.keys + PROGRAMS).freeze
31
41
  end
32
42
  end
33
43
  end
@@ -9,7 +9,7 @@ module Badline
9
9
  # disk's raw GCR, which only a true drive reads, so it plugs one in
10
10
  # when there's none yet. The 1541 reads only .d64 and .g64 images, the
11
11
  # 1571 .d71 and .g71 as well, and the 1581 only .d81, so a .d81 swaps
12
- # the drive on device 8 for a 1581 (Drive1581::Slot), and another disk
12
+ # the drive on device 8 for a 1581 (Drives::Model1581::Slot), and another disk
13
13
  # image swaps a 1581 back for the machine's own drive. The traps' other
14
14
  # disk media, a .t64 or a host directory, raise Error.
15
15
  module TrueDrive
@@ -10,9 +10,9 @@ module Badline
10
10
  # Plays `subtune`, or the tune's own start subtune, and says what
11
11
  # plays. A tune for more than one SID raises FormatError.
12
12
  def attach(computer, path, autostart:, subtune:)
13
- tune = Storage::SIDFile.new(path)
13
+ tune = SIDTune::File.new(path)
14
14
  if tune.sids > 1
15
- raise Storage::SIDFile::FormatError, "Written for #{tune.sids} SIDs, which only the SID player plays"
15
+ raise SIDTune::File::FormatError, "Written for #{tune.sids} SIDs, which only the SID player plays"
16
16
  end
17
17
 
18
18
  subtune = (subtune || tune.start_subtune).clamp(1, tune.subtunes)
data/lib/badline/media.rb CHANGED
@@ -4,7 +4,7 @@ require "badline/media/extensions"
4
4
  require "badline/media/true_drive"
5
5
  require "badline/media/boot_disk"
6
6
  require "badline/media/not_disk"
7
- require "badline/media/queue"
7
+ require "badline/audio/queue"
8
8
  require "badline/media/disk_set"
9
9
  require "badline/media/disk_list"
10
10
  require "badline/media/vic20_basic"
@@ -83,7 +83,7 @@ module Badline
83
83
  def sid_model(path, otherwise: :mos6581)
84
84
  return otherwise unless path && Extensions.kind(path) == :tune
85
85
 
86
- Storage::SIDFile.new(path).sid_model
86
+ SIDTune::File.new(path).sid_model
87
87
  end
88
88
 
89
89
  # What the medium at `path` is to `computer`, which attach goes by:
@@ -156,7 +156,7 @@ module Badline
156
156
  if computer.family == :vic20
157
157
  computer.attach_cartridge(Storage::CRTFile.new(path, machine: :vic20).chips)
158
158
  else
159
- computer.attach_cartridge(Cartridge.from_file(path, **options))
159
+ computer.attach_cartridge(C64::Cartridge.from_file(path, **options))
160
160
  end
161
161
  "Attached cartridge #{path}"
162
162
  end
@@ -29,13 +29,10 @@ module Badline
29
29
  Array(bytes).each_with_index { |b, i| poke(addr + i, b) }
30
30
  end
31
31
 
32
- def save_state(out)
33
- out.blob(@storage)
34
- end
32
+ # Every byte as one record of a keyed snapshot module, under `key`.
33
+ def save_fields(out, key) = out.bytes(key, @storage)
35
34
 
36
- def load_state(input)
37
- input.blob_into(@storage)
38
- end
35
+ def load_fields(input, key) = input.bytes_into(key, @storage)
39
36
 
40
37
  # Refills the whole memory as if newly built with `initial`
41
38
  def clear!(initial = [])
data/lib/badline/model.rb CHANGED
@@ -7,7 +7,7 @@ module Badline
7
7
  # each was sold with, its video standard, its KERNAL and whether it has
8
8
  # a datasette. The names are x64sc's.
9
9
  module Model
10
- # Each field but the name is a keyword Computer.new takes.
10
+ # Each field but the name is a keyword C64.new takes.
11
11
  Profile = Data.define(:name, :vic_model, :cia_model, :sid_model, :region, :kernal, :datasette, :board)
12
12
 
13
13
  # The breadbin PAL C64: the 6569 VIC-II, 6526 CIAs and the 6581 SID.
@@ -12,13 +12,14 @@ module Badline
12
12
 
13
13
  private
14
14
 
15
- # Takes `sid`, `c64`, `vic20` or `c128` when given first.
15
+ # Takes `sid`, `c64`, `vic20`, `c128` or `plus4` when given first.
16
16
  def subcommand(args)
17
17
  case args.first
18
18
  when "sid" then @sid_command = true
19
19
  when "c64" then @family = :c64
20
20
  when "vic20" then @family = :vic20
21
21
  when "c128" then @family = :c128
22
+ when "plus4" then @family = :plus4
22
23
  else return
23
24
  end
24
25
  @family_named = !@sid_command
@@ -37,7 +38,9 @@ module Badline
37
38
  # the C128's.
38
39
  def pick_family
39
40
  return if @family_named || @sid_command || @media_path.nil?
40
- return unless %w[.prg .p00].include?(File.extname(@media_path).downcase) && File.file?(@media_path)
41
+
42
+ program = Media::Extensions::PROGRAMS.include?(File.extname(@media_path).downcase)
43
+ return unless program && File.file?(@media_path)
41
44
 
42
45
  @family = :c128 if Storage::P00.load_address(@media_path) == C128_BASIC_START
43
46
  end
@@ -35,6 +35,34 @@ module Badline
35
35
 
36
36
  def describe(option) = @native && option.name == "--sound" ? "#{option.text} (default)" : option.text
37
37
 
38
+ # The media the window opens, by their extensions (Media::Extensions),
39
+ # wrapped as the banner is.
40
+ def media_kinds
41
+ text = "Media can be a #{Media::Extensions::PROGRAMS.join('/')} program, a #{listed(%i[disk])} disk image, " \
42
+ "a #{listed(%i[gcr])} disk image for a true drive, an #{listed(%i[disk_list])} list of disk images, " \
43
+ "a #{listed(%i[archive])} tape archive, a #{listed(%i[tape])} tape, a #{listed(%i[cartridge])} " \
44
+ "cartridge, a #{listed(%i[tune])} tune, a .vsf snapshot, or a directory to mount as device 8."
45
+ wrap(text)
46
+ end
47
+
48
+ def listed(kinds) = Media::Extensions.of(kinds).join("/")
49
+
50
+ # The words of `text` in lines of at most 70 characters.
51
+ def wrap(text)
52
+ lines = [""]
53
+ text.split.each do |word|
54
+ line = lines.last
55
+ if line.empty?
56
+ lines[-1] = word
57
+ elsif line.size + word.size < 70
58
+ lines[-1] = "#{line} #{word}"
59
+ else
60
+ lines << word
61
+ end
62
+ end
63
+ lines.join("\n")
64
+ end
65
+
38
66
  def banner
39
67
  <<~BANNER
40
68
  Usage: #{@program} [c64] [options] [media]
@@ -50,11 +78,8 @@ module Badline
50
78
  c128 Run a C128 in C128 mode, the one --model names
51
79
  sid Play .sid tunes and directories of them
52
80
 
53
- Media can be a .prg/.p00 program, a .d64/.d71/.d81 disk image, a
54
- .g64 disk image for the true 1541, an .m3u or .vfl list of disk
55
- images, a .t64 tape archive, a .tap tape, a .crt cartridge, a .sid
56
- tune, a .vsf snapshot, or a directory to mount as device 8. It
57
- opens in the emulator window. There F11 quicksaves the machine to
81
+ #{media_kinds}
82
+ It opens in the emulator window. There F11 quicksaves the machine to
58
83
  the next of five slots in badline's data folder, replacing the
59
84
  oldest, and F12 restores the newest quicksave or named save. The
60
85
  window also autosaves every two minutes of play, which only the
@@ -85,17 +110,18 @@ module Badline
85
110
 
86
111
  --at and --script run events once a number of frames has run, as
87
112
  in --at 3500:key=space or --at 250,500:screenshot=shot%05d.bmp.
88
- key=NAME presses a C64 key (space, return, a, f1, run_stop, restore)
89
- or a joystick's direction or fire (joy1-up, joy2-fire) for #{Event::HOLD}
90
- frames. type=TEXT types it, with \\n for RETURN. insert=FILE swaps
91
- in a disk, a list's first disk, a tape or a cartridge, and
92
- eject=disk, tape or cartridge takes one out. screenshot=FILE saves
93
- the frame as a .bmp, with the frame's number in place of %d. menu
94
- opens the pause menu, and menu=PAGE opens it on snapshots, drive,
95
- datasette, expansion, ports, sound or power. Its frames still count,
96
- and resume closes it. display=vdc or display=vic shows the C128's
97
- 80 or 40 column screen, as F8 switches them. reset, freeze and quit
98
- take no argument.
113
+ key=NAME presses a key (space, return, a, f1, run_stop, restore, and
114
+ on the C128 esc, help, keypad1 and the rest) or a joystick's
115
+ direction or fire (joy1-up, joy2-fire) for #{Event::HOLD} frames, and
116
+ pushes the C128's caps_lock or forty_eighty, which lock. type=TEXT
117
+ types it, with \\n for RETURN. insert=FILE swaps in a disk, a list's
118
+ first disk, a tape or a cartridge, and eject=disk, tape or
119
+ cartridge takes one out. screenshot=FILE saves the frame as a .bmp,
120
+ with the frame's number in place of %d. menu opens the pause menu,
121
+ and menu=PAGE opens it on snapshots, drive, datasette, expansion,
122
+ ports, sound or power. Its frames still count, and resume closes
123
+ it. display=vdc or display=vic shows the C128's 80 or 40 column
124
+ screen, as F8 switches them. reset, freeze and quit take no argument.
99
125
  BANNER
100
126
  end
101
127
 
@@ -75,6 +75,8 @@ module Badline
75
75
  section: "Testing options", needs: :window),
76
76
  Option.new("--save-snapshot FILE", "Save the machine as a .vsf snapshot after the last frame",
77
77
  section: "Testing options", needs: :window),
78
+ Option.new("--vice", "Add VICE's modules to --save-snapshot's C64 snapshot, for x64sc",
79
+ section: "Testing options", needs: :window),
78
80
  Option.new("--at FRAME:EVENT", "Run EVENT once FRAME frames have run (see above)",
79
81
  section: "Testing options", needs: :window),
80
82
  Option.new("--script FILE", "Run the events in FILE, one FRAME:EVENT a line",
@@ -59,6 +59,8 @@ module Badline
59
59
  end
60
60
 
61
61
  def validate_family
62
+ raise Error, "the Plus/4 isn't emulated yet" if @family == :plus4
63
+
62
64
  if @family == :vic20
63
65
  validate_vic20
64
66
  elsif !@ram.nil?
@@ -14,7 +14,7 @@ module Badline
14
14
  # first, plays .sid tunes and directories of them in the terminal.
15
15
  # `c64`, `vic20` or `c128`, given first, names the machine family, and
16
16
  # without one the family is the C64, or the C128 for a program that loads
17
- # where C128 BASIC starts. The native build adds --no-sound and
17
+ # where C128 BASIC starts. `plus4` is refused until the Plus/4 runs. The native build adds --no-sound and
18
18
  # --version, and badline-ruby adds --disable-jit.
19
19
  #
20
20
  # TABLE lists the options, and both the parser and the help read it. It
@@ -94,6 +94,7 @@ module Badline
94
94
  @true_drive = false
95
95
  @screenshot = ""
96
96
  @save_snapshot = ""
97
+ @vice = false
97
98
  @timeline = []
98
99
  @jit = true
99
100
  @help = false
@@ -171,6 +172,9 @@ module Badline
171
172
 
172
173
  def true_drive? = @true_drive
173
174
 
175
+ # Whether --save-snapshot adds VICE's modules, so x64sc opens it.
176
+ def vice? = @vice
177
+
174
178
  def jit? = @jit
175
179
 
176
180
  # The name of the model to build: a C64 Badline::Model names, a VIC-20
@@ -272,6 +276,7 @@ module Badline
272
276
  when "--no-vsync" then @vsync = false
273
277
  when "--verbose" then @verbose = true
274
278
  when "--true-drive" then @true_drive = true
279
+ when "--vice" then @vice = true
275
280
  when "--ntsc" then @models << "ntsc"
276
281
  when "--c64" then @c64_mode = true
277
282
  when "--unpaced" then @paced = false
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class Plus4
5
+ # The Plus/4's 6551 ACIA at $FD00-$FD0F, its four registers repeated,
6
+ # as a stub with nothing on the line: it never receives, its
7
+ # transmitter is always empty, and it never interrupts. The command and
8
+ # control registers keep what is written to them, and a write to the
9
+ # status register, a programmed reset, clears the command register's
10
+ # low five bits.
11
+ class ACIA
12
+ STATUS = 0x10
13
+
14
+ attr_reader :command, :control
15
+
16
+ def initialize
17
+ reset!
18
+ end
19
+
20
+ def reset!
21
+ @command = 0
22
+ @control = 0
23
+ end
24
+
25
+ def irq? = false
26
+
27
+ def peek(addr)
28
+ case addr & 0x03
29
+ when 1 then STATUS
30
+ when 2 then @command
31
+ when 3 then @control
32
+ else 0
33
+ end
34
+ end
35
+
36
+ def poke(addr, value)
37
+ case addr & 0x03
38
+ when 1 then @command &= 0xe0
39
+ when 2 then @command = value
40
+ when 3 then @control = value
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end