badline 0.12.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (565) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -1
  3. data/CLAUDE.md +86 -38
  4. data/CONTRIBUTING.md +4 -3
  5. data/README.md +9 -6
  6. data/doc/library.md +9 -9
  7. data/doc/media.md +2 -1
  8. data/doc/pinned-behaviour.md +134 -105
  9. data/doc/snapshot-format.md +1047 -0
  10. data/doc/snapshots.md +73 -43
  11. data/lib/badline/audio/bare_player.rb +53 -20
  12. data/lib/badline/audio/cli.rb +6 -6
  13. data/lib/badline/audio/jukebox.rb +2 -2
  14. data/lib/badline/audio/machine_player.rb +16 -10
  15. data/lib/badline/{media → audio}/queue.rb +1 -1
  16. data/lib/badline/audio/queued_tune.rb +6 -6
  17. data/lib/badline/audio/renderer.rb +33 -22
  18. data/lib/badline/audio/stereo.rb +1 -1
  19. data/lib/badline/c128/banks.rb +6 -3
  20. data/lib/badline/c128/bus/keyed_state.rb +45 -0
  21. data/lib/badline/c128/bus.rb +35 -20
  22. data/lib/badline/c128/color_lines.rb +2 -2
  23. data/lib/badline/c128/cpu.rb +1 -1
  24. data/lib/badline/c128/drives.rb +14 -34
  25. data/lib/badline/c128/fast_serial.rb +5 -5
  26. data/lib/badline/c128/keyed_modules.rb +117 -0
  27. data/lib/badline/c128/keyed_state.rb +91 -0
  28. data/lib/badline/c128/keys.rb +9 -0
  29. data/lib/badline/c128/mmu.rb +9 -8
  30. data/lib/badline/c128/mmu_pages.rb +21 -1
  31. data/lib/badline/c128/modes.rb +21 -11
  32. data/lib/badline/c128/z80.rb +2 -2
  33. data/lib/badline/c128/z80_turns.rb +1 -1
  34. data/lib/badline/c128.rb +21 -16
  35. data/lib/badline/c64/attachments.rb +42 -0
  36. data/lib/badline/c64/banked_ram/banking.rb +32 -0
  37. data/lib/badline/c64/banked_ram/plus256k.rb +64 -0
  38. data/lib/badline/c64/banked_ram/plus60k.rb +47 -0
  39. data/lib/badline/c64/banked_ram/unexpanded.rb +30 -0
  40. data/lib/badline/c64/banked_ram.rb +23 -0
  41. data/lib/badline/c64/bus/debug_register.rb +32 -0
  42. data/lib/badline/c64/bus/extra_sids.rb +32 -0
  43. data/lib/badline/c64/bus/fittings.rb +40 -0
  44. data/lib/badline/c64/bus/keyed_state.rb +41 -0
  45. data/lib/badline/c64/bus/pla.rb +149 -0
  46. data/lib/badline/c64/bus/roms.rb +41 -0
  47. data/lib/badline/c64/bus/sid_slots.rb +44 -0
  48. data/lib/badline/c64/bus.rb +219 -0
  49. data/lib/badline/c64/cartridge/action_replay.rb +115 -0
  50. data/lib/badline/c64/cartridge/atomic_power.rb +26 -0
  51. data/lib/badline/c64/cartridge/bank.rb +83 -0
  52. data/lib/badline/c64/cartridge/comal80.rb +52 -0
  53. data/lib/badline/c64/cartridge/dinamic.rb +36 -0
  54. data/lib/badline/c64/cartridge/easy_flash.rb +132 -0
  55. data/lib/badline/c64/cartridge/epyx_fastload.rb +73 -0
  56. data/lib/badline/c64/cartridge/final_cartridge3.rb +79 -0
  57. data/lib/badline/c64/cartridge/flash.rb +279 -0
  58. data/lib/badline/c64/cartridge/freezer.rb +35 -0
  59. data/lib/badline/c64/cartridge/fun_play.rb +40 -0
  60. data/lib/badline/c64/cartridge/g_mod2.rb +64 -0
  61. data/lib/badline/c64/cartridge/game_system.rb +42 -0
  62. data/lib/badline/c64/cartridge/geo_ram.rb +65 -0
  63. data/lib/badline/c64/cartridge/kcs_power.rb +69 -0
  64. data/lib/badline/c64/cartridge/keyed_state.rb +393 -0
  65. data/lib/badline/c64/cartridge/mach5.rb +34 -0
  66. data/lib/badline/c64/cartridge/magic_desk.rb +32 -0
  67. data/lib/badline/c64/cartridge/ocean.rb +37 -0
  68. data/lib/badline/c64/cartridge/pagefox.rb +60 -0
  69. data/lib/badline/c64/cartridge/retro_replay.rb +278 -0
  70. data/lib/badline/c64/cartridge/rex_utility.rb +31 -0
  71. data/lib/badline/c64/cartridge/rgcd.rb +50 -0
  72. data/lib/badline/c64/cartridge/simons_basic.rb +37 -0
  73. data/lib/badline/c64/cartridge/standard.rb +17 -0
  74. data/lib/badline/c64/cartridge/super_games.rb +40 -0
  75. data/lib/badline/c64/cartridge/westermann.rb +32 -0
  76. data/lib/badline/c64/cartridge/zaxxon.rb +52 -0
  77. data/lib/badline/c64/cartridge.rb +232 -0
  78. data/lib/badline/c64/color_memory.rb +27 -0
  79. data/lib/badline/{computer → c64}/common.rb +2 -2
  80. data/lib/badline/{computer → c64}/kernal_traps.rb +39 -36
  81. data/lib/badline/c64/keyed_modules.rb +111 -0
  82. data/lib/badline/c64/keyed_state.rb +68 -0
  83. data/lib/badline/c64/reu/dma.rb +271 -0
  84. data/lib/badline/c64/reu/keyed_state.rb +140 -0
  85. data/lib/badline/c64/reu/ram.rb +94 -0
  86. data/lib/badline/c64/reu/trigger.rb +34 -0
  87. data/lib/badline/c64/reu.rb +289 -0
  88. data/lib/badline/c64/true_drives.rb +120 -0
  89. data/lib/badline/{computer.rb → c64.rb} +24 -15
  90. data/lib/badline/chips/cia/fast_forward.rb +62 -0
  91. data/lib/badline/chips/cia/interrupt_register.rb +128 -0
  92. data/lib/badline/chips/cia/keyed_parts.rb +213 -0
  93. data/lib/badline/chips/cia/serial.rb +246 -0
  94. data/lib/badline/chips/cia/time_of_day.rb +210 -0
  95. data/lib/badline/chips/cia/timer.rb +188 -0
  96. data/lib/badline/chips/cia.rb +281 -0
  97. data/lib/badline/chips/cpu/addressing.rb +133 -0
  98. data/lib/badline/chips/cpu/boundary.rb +56 -0
  99. data/lib/badline/chips/cpu/core.rb +183 -0
  100. data/lib/badline/chips/cpu/instruction.rb +338 -0
  101. data/lib/badline/chips/cpu/instruction_set/arithmetic.rb +118 -0
  102. data/lib/badline/chips/cpu/instruction_set/bitwise.rb +130 -0
  103. data/lib/badline/chips/cpu/instruction_set/branch.rb +83 -0
  104. data/lib/badline/chips/cpu/instruction_set/flag.rb +67 -0
  105. data/lib/badline/chips/cpu/instruction_set/illegal.rb +274 -0
  106. data/lib/badline/chips/cpu/instruction_set/inc_dec.rb +73 -0
  107. data/lib/badline/chips/cpu/instruction_set/stack.rb +56 -0
  108. data/lib/badline/chips/cpu/instruction_set/transfer.rb +141 -0
  109. data/lib/badline/chips/cpu/instruction_set.rb +59 -0
  110. data/lib/badline/chips/cpu/interrupts.rb +108 -0
  111. data/lib/badline/chips/cpu/keyed_state.rb +177 -0
  112. data/lib/badline/chips/cpu/microcode.rb +195 -0
  113. data/lib/badline/chips/cpu/operations.rb +90 -0
  114. data/lib/badline/chips/cpu/port.rb +133 -0
  115. data/lib/badline/chips/cpu/stack_operations.rb +84 -0
  116. data/lib/badline/chips/cpu/traps.rb +23 -0
  117. data/lib/badline/chips/cpu.rb +17 -0
  118. data/lib/badline/chips/sid/catch_up.rb +122 -0
  119. data/lib/badline/chips/sid/decimator.rb +68 -0
  120. data/lib/badline/chips/sid/envelope.rb +236 -0
  121. data/lib/badline/chips/sid/filter.rb +227 -0
  122. data/lib/badline/chips/sid/keyed_parts.rb +286 -0
  123. data/lib/badline/chips/sid/voice.rb +69 -0
  124. data/lib/badline/chips/sid/waveform/combined.rb +128 -0
  125. data/lib/badline/chips/sid/waveform/fast_forward.rb +107 -0
  126. data/lib/badline/chips/sid/waveform/noise_writeback.rb +124 -0
  127. data/lib/badline/chips/sid/waveform.rb +305 -0
  128. data/lib/badline/chips/sid.rb +264 -0
  129. data/lib/badline/chips/ted/beam.rb +119 -0
  130. data/lib/badline/chips/ted/timers.rb +66 -0
  131. data/lib/badline/chips/ted.rb +143 -0
  132. data/lib/badline/chips/tia.rb +49 -0
  133. data/lib/badline/chips/vdc/keyed_parts.rb +105 -0
  134. data/lib/badline/{c128 → chips}/vdc/memory.rb +1 -1
  135. data/lib/badline/{c128 → chips}/vdc/painter.rb +1 -13
  136. data/lib/badline/{c128 → chips}/vdc/raster.rb +1 -17
  137. data/lib/badline/{c128 → chips}/vdc/window.rb +1 -10
  138. data/lib/badline/{c128 → chips}/vdc.rb +6 -31
  139. data/lib/badline/chips/via/control_lines.rb +109 -0
  140. data/lib/badline/chips/via/fast_forward.rb +55 -0
  141. data/lib/badline/chips/via/interrupt_register.rb +60 -0
  142. data/lib/badline/chips/via/keyed_parts.rb +163 -0
  143. data/lib/badline/chips/via/shift_register.rb +168 -0
  144. data/lib/badline/chips/via/timer1.rb +120 -0
  145. data/lib/badline/chips/via/timer2.rb +117 -0
  146. data/lib/badline/chips/via.rb +267 -0
  147. data/lib/badline/chips/vic/bank.rb +135 -0
  148. data/lib/badline/chips/vic/border_mask.rb +78 -0
  149. data/lib/badline/chips/vic/collisions.rb +106 -0
  150. data/lib/badline/chips/vic/color_patches.rb +38 -0
  151. data/lib/badline/chips/vic/display_state.rb +168 -0
  152. data/lib/badline/chips/vic/graphics_mode.rb +166 -0
  153. data/lib/badline/chips/vic/graphics_shifter.rb +183 -0
  154. data/lib/badline/chips/vic/keyed_parts.rb +228 -0
  155. data/lib/badline/chips/vic/keyed_sprites.rb +225 -0
  156. data/lib/badline/chips/vic/keyed_state.rb +102 -0
  157. data/lib/badline/chips/vic/register_log.rb +65 -0
  158. data/lib/badline/chips/vic/registers.rb +188 -0
  159. data/lib/badline/chips/vic/sequencer.rb +275 -0
  160. data/lib/badline/chips/vic/sequencer_output.rb +118 -0
  161. data/lib/badline/chips/vic/sprite/internal_bus.rb +59 -0
  162. data/lib/badline/chips/vic/sprite/shifter.rb +148 -0
  163. data/lib/badline/chips/vic/sprite/timing.rb +58 -0
  164. data/lib/badline/chips/vic/sprite.rb +337 -0
  165. data/lib/badline/chips/vic/sprites.rb +281 -0
  166. data/lib/badline/chips/vic.rb +787 -0
  167. data/lib/badline/chips/vic_i/keyed_parts.rb +142 -0
  168. data/lib/badline/{vic20/vic → chips/vic_i}/painter.rb +2 -30
  169. data/lib/badline/chips/vic_i/sound/output.rb +85 -0
  170. data/lib/badline/chips/vic_i/sound.rb +227 -0
  171. data/lib/badline/{vic20/vic → chips/vic_i}/text_window.rb +2 -2
  172. data/lib/badline/{vic20/vic.rb → chips/vic_i.rb} +6 -6
  173. data/lib/badline/chips/z80/arithmetic.rb +119 -0
  174. data/lib/badline/chips/z80/bit_page.rb +57 -0
  175. data/lib/badline/chips/z80/block_io.rb +60 -0
  176. data/lib/badline/chips/z80/block_transfers.rb +61 -0
  177. data/lib/badline/chips/z80/bus_cycles.rb +113 -0
  178. data/lib/badline/chips/z80/core.rb +115 -0
  179. data/lib/badline/chips/z80/exchanges.rb +52 -0
  180. data/lib/badline/chips/z80/extended_page.rb +91 -0
  181. data/lib/badline/chips/z80/flags.rb +39 -0
  182. data/lib/badline/chips/z80/interrupt_acceptance.rb +48 -0
  183. data/lib/badline/chips/z80/jumps.rb +84 -0
  184. data/lib/badline/chips/z80/keyed_state.rb +73 -0
  185. data/lib/badline/chips/z80/loads.rb +100 -0
  186. data/lib/badline/chips/z80/main_page.rb +136 -0
  187. data/lib/badline/chips/z80/registers.rb +122 -0
  188. data/lib/badline/chips/z80/shifts.rb +66 -0
  189. data/lib/badline/chips/z80.rb +13 -0
  190. data/lib/badline/chips.rb +10 -0
  191. data/lib/badline/core.rb +13 -32
  192. data/lib/badline/drives/datasette/keyed_state.rb +38 -0
  193. data/lib/badline/drives/datasette.rb +173 -0
  194. data/lib/badline/drives/engine/core.rb +152 -0
  195. data/lib/badline/drives/engine/fast_serial.rb +75 -0
  196. data/lib/badline/drives/engine/idle.rb +127 -0
  197. data/lib/badline/drives/engine/idle_cpu.rb +30 -0
  198. data/lib/badline/drives/engine/orbit.rb +81 -0
  199. data/lib/badline/drives/engine/serial_lines.rb +72 -0
  200. data/lib/badline/drives/engine/sleep.rb +114 -0
  201. data/lib/badline/drives/engine/vias.rb +86 -0
  202. data/lib/badline/drives/engine/watch.rb +152 -0
  203. data/lib/badline/drives/engine.rb +11 -0
  204. data/lib/badline/drives/model1541/bus.rb +75 -0
  205. data/lib/badline/drives/model1541/byte_ready.rb +50 -0
  206. data/lib/badline/drives/model1541/cpu.rb +13 -0
  207. data/lib/badline/drives/model1541/disk.rb +318 -0
  208. data/lib/badline/drives/model1541/disk_via.rb +38 -0
  209. data/lib/badline/drives/model1541/gcr.rb +59 -0
  210. data/lib/badline/drives/model1541/keyed_state.rb +251 -0
  211. data/lib/badline/drives/model1541/mechanism.rb +313 -0
  212. data/lib/badline/drives/model1541/rotation.rb +123 -0
  213. data/lib/badline/drives/model1541/sector_reader.rb +78 -0
  214. data/lib/badline/drives/model1541/serial_port.rb +20 -0
  215. data/lib/badline/drives/model1541/track.rb +100 -0
  216. data/lib/badline/drives/model1541.rb +80 -0
  217. data/lib/badline/drives/model1571/bus.rb +100 -0
  218. data/lib/badline/drives/model1571/cpu.rb +13 -0
  219. data/lib/badline/drives/model1571/keyed_state.rb +108 -0
  220. data/lib/badline/drives/model1571/serial_port.rb +39 -0
  221. data/lib/badline/drives/model1571/serial_via.rb +27 -0
  222. data/lib/badline/drives/model1571/wd1770.rb +108 -0
  223. data/lib/badline/drives/model1571.rb +141 -0
  224. data/lib/badline/drives/model1581/bus.rb +126 -0
  225. data/lib/badline/drives/model1581/cpu.rb +13 -0
  226. data/lib/badline/drives/model1581/disk.rb +133 -0
  227. data/lib/badline/drives/model1581/keyed_state.rb +280 -0
  228. data/lib/badline/drives/model1581/mechanism.rb +98 -0
  229. data/lib/badline/drives/model1581/serial_port.rb +54 -0
  230. data/lib/badline/drives/model1581/slot.rb +61 -0
  231. data/lib/badline/drives/model1581/track.rb +102 -0
  232. data/lib/badline/drives/model1581/track_bytes.rb +77 -0
  233. data/lib/badline/drives/model1581/wd1772/registers.rb +91 -0
  234. data/lib/badline/drives/model1581/wd1772/sector_writes.rb +75 -0
  235. data/lib/badline/drives/model1581/wd1772/sectors.rb +152 -0
  236. data/lib/badline/drives/model1581/wd1772/stepping.rb +111 -0
  237. data/lib/badline/drives/model1581/wd1772/tracks.rb +127 -0
  238. data/lib/badline/drives/model1581/wd1772/turn.rb +75 -0
  239. data/lib/badline/drives/model1581/wd1772.rb +216 -0
  240. data/lib/badline/drives/model1581.rb +206 -0
  241. data/lib/badline/drives/serial_bus.rb +161 -0
  242. data/lib/badline/drives.rb +8 -0
  243. data/lib/badline/frontend/app.rb +3 -3
  244. data/lib/badline/frontend/boot.rb +4 -4
  245. data/lib/badline/frontend/controls.rb +19 -3
  246. data/lib/badline/frontend/drive_led.rb +44 -21
  247. data/lib/badline/frontend/machine_window.rb +3 -1
  248. data/lib/badline/frontend/menu/menu_dialogs.rb +2 -2
  249. data/lib/badline/frontend/player/filter_view.rb +1 -1
  250. data/lib/badline/frontend/player/player_controller.rb +2 -2
  251. data/lib/badline/frontend/player/player_screen.rb +1 -0
  252. data/lib/badline/frontend/player/theme.rb +7 -7
  253. data/lib/badline/frontend/snapshots.rb +12 -1
  254. data/lib/badline/frontend/timeline.rb +30 -12
  255. data/lib/badline/input/control_ports.rb +78 -0
  256. data/lib/badline/input/joystick.rb +27 -0
  257. data/lib/badline/input/keyboard.rb +114 -0
  258. data/lib/badline/input/matrix_typist.rb +98 -0
  259. data/lib/badline/input.rb +4 -0
  260. data/lib/badline/kernal_trap/chrout.rb +45 -0
  261. data/lib/badline/kernal_trap/{drive → dos}/block_commands.rb +1 -1
  262. data/lib/badline/kernal_trap/dos/channel.rb +156 -0
  263. data/lib/badline/kernal_trap/{drive → dos}/channels.rb +1 -26
  264. data/lib/badline/kernal_trap/{drive → dos}/memory.rb +1 -10
  265. data/lib/badline/kernal_trap/{drive → dos}/parameters.rb +1 -1
  266. data/lib/badline/kernal_trap/{drive → dos}/status.rb +1 -9
  267. data/lib/badline/kernal_trap/{drive → dos}/write_file.rb +1 -19
  268. data/lib/badline/kernal_trap/{drive → dos}/writes.rb +1 -1
  269. data/lib/badline/kernal_trap/{drive.rb → dos.rb} +9 -27
  270. data/lib/badline/kernal_trap/file_routine.rb +4 -4
  271. data/lib/badline/kernal_trap/keyed_state.rb +150 -0
  272. data/lib/badline/kernal_trap/layout.rb +75 -11
  273. data/lib/badline/kernal_trap/load.rb +19 -21
  274. data/lib/badline/kernal_trap/routine.rb +12 -0
  275. data/lib/badline/kernal_trap/save.rb +12 -22
  276. data/lib/badline/kernal_trap/serial.rb +8 -24
  277. data/lib/badline/kernal_trap.rb +3 -2
  278. data/lib/badline/machine/clocking.rb +1 -1
  279. data/lib/badline/machine/keyboard_buffer.rb +49 -0
  280. data/lib/badline/machine/settling.rb +29 -0
  281. data/lib/badline/machine.rb +10 -7
  282. data/lib/badline/media/boot_disk.rb +14 -2
  283. data/lib/badline/media/extensions.rb +10 -0
  284. data/lib/badline/media/true_drive.rb +1 -1
  285. data/lib/badline/media/tune.rb +2 -2
  286. data/lib/badline/media.rb +3 -3
  287. data/lib/badline/memory.rb +3 -6
  288. data/lib/badline/model.rb +1 -1
  289. data/lib/badline/options/family.rb +5 -2
  290. data/lib/badline/options/help.rb +42 -16
  291. data/lib/badline/options/table.rb +2 -0
  292. data/lib/badline/options/validation.rb +2 -0
  293. data/lib/badline/options.rb +6 -1
  294. data/lib/badline/plus4/acia.rb +45 -0
  295. data/lib/badline/plus4/bus.rb +312 -0
  296. data/lib/badline/plus4/cpu.rb +10 -0
  297. data/lib/badline/plus4/cpu_port.rb +93 -0
  298. data/lib/badline/plus4/keyboard_port.rb +51 -0
  299. data/lib/badline/plus4/model.rb +38 -0
  300. data/lib/badline/plus4/user_port.rb +31 -0
  301. data/lib/badline/plus4.rb +164 -0
  302. data/lib/badline/roms/README +44 -6
  303. data/lib/badline/roms/plus4/basic.rom +0 -0
  304. data/lib/badline/roms/plus4/function-high.rom +0 -0
  305. data/lib/badline/roms/plus4/function-low.rom +0 -0
  306. data/lib/badline/roms/plus4/kernal-ntsc.rom +0 -0
  307. data/lib/badline/roms/plus4/kernal-pal.rom +0 -0
  308. data/lib/badline/sdl.rb +1 -0
  309. data/lib/badline/{storage/sid_file.rb → sid_tune/file.rb} +3 -3
  310. data/lib/badline/{storage → sid_tune}/hvsc.rb +7 -7
  311. data/lib/badline/{storage → sid_tune}/song_lengths.rb +2 -2
  312. data/lib/badline/{storage → sid_tune}/stil/credit.rb +1 -1
  313. data/lib/badline/{storage → sid_tune}/stil.rb +3 -3
  314. data/lib/badline/sid_tune.rb +6 -0
  315. data/lib/badline/snapshot/c128_setup.rb +32 -0
  316. data/lib/badline/snapshot/c64_setup.rb +83 -0
  317. data/lib/badline/snapshot/container.rb +4 -0
  318. data/lib/badline/snapshot/field_doc/markdown.rb +112 -0
  319. data/lib/badline/snapshot/field_doc.rb +109 -0
  320. data/lib/badline/snapshot/image.rb +132 -46
  321. data/lib/badline/snapshot/keyed/cursor.rb +40 -0
  322. data/lib/badline/snapshot/keyed/modules.rb +66 -0
  323. data/lib/badline/snapshot/keyed/reader.rb +188 -0
  324. data/lib/badline/snapshot/keyed/recorder.rb +88 -0
  325. data/lib/badline/snapshot/keyed/report.rb +26 -0
  326. data/lib/badline/snapshot/keyed/writer.rb +55 -0
  327. data/lib/badline/snapshot/keyed.rb +64 -0
  328. data/lib/badline/snapshot/machine_state.rb +17 -64
  329. data/lib/badline/snapshot/storage_setup.rb +63 -0
  330. data/lib/badline/snapshot/vic20_setup.rb +28 -0
  331. data/lib/badline/snapshot/vice/c64_mem.rb +1 -1
  332. data/lib/badline/snapshot/vice/restore.rb +1 -1
  333. data/lib/badline/snapshot/vice/reu1764.rb +3 -3
  334. data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
  335. data/lib/badline/snapshot/vice.rb +13 -35
  336. data/lib/badline/snapshot.rb +44 -22
  337. data/lib/badline/storage/crt_file.rb +3 -1
  338. data/lib/badline/storage/d64_image.rb +0 -2
  339. data/lib/badline/storage/d71_image.rb +0 -2
  340. data/lib/badline/storage/d81_image.rb +0 -2
  341. data/lib/badline/storage/disk_image.rb +3 -6
  342. data/lib/badline/storage/g64_image.rb +10 -5
  343. data/lib/badline/storage/host_directory.rb +0 -5
  344. data/lib/badline/storage/t64.rb +2 -8
  345. data/lib/badline/storage/tap.rb +43 -15
  346. data/lib/badline/storage/unavailable.rb +1 -1
  347. data/lib/badline/storage.rb +0 -37
  348. data/lib/badline/support/c128_checkpoint.rb +39 -0
  349. data/lib/badline/support/checkpoint.rb +108 -0
  350. data/lib/badline/support/vic20_checkpoint.rb +38 -0
  351. data/lib/badline/support.rb +5 -0
  352. data/lib/badline/version.rb +1 -1
  353. data/lib/badline/vic20/attachments.rb +8 -5
  354. data/lib/badline/vic20/bus/keyed_state.rb +52 -0
  355. data/lib/badline/vic20/bus.rb +2 -25
  356. data/lib/badline/vic20/cpu.rb +1 -1
  357. data/lib/badline/vic20/keyed_modules.rb +73 -0
  358. data/lib/badline/vic20/keyed_state.rb +45 -0
  359. data/lib/badline/vic20/port_wiring.rb +4 -4
  360. data/lib/badline/vic20/user_via_ports.rb +2 -2
  361. data/lib/badline/vic20.rb +22 -17
  362. data/lib/badline.rb +1 -0
  363. metadata +271 -228
  364. data/lib/badline/address_bus/extra_sids.rb +0 -30
  365. data/lib/badline/address_bus/fittings.rb +0 -38
  366. data/lib/badline/address_bus/pla.rb +0 -147
  367. data/lib/badline/address_bus/roms.rb +0 -39
  368. data/lib/badline/address_bus/saved_state.rb +0 -66
  369. data/lib/badline/address_bus/sid_slots.rb +0 -42
  370. data/lib/badline/address_bus.rb +0 -216
  371. data/lib/badline/c128/bus_state.rb +0 -53
  372. data/lib/badline/c128/saved_state.rb +0 -143
  373. data/lib/badline/cartridge/action_replay.rb +0 -126
  374. data/lib/badline/cartridge/atomic_power.rb +0 -24
  375. data/lib/badline/cartridge/bank.rb +0 -81
  376. data/lib/badline/cartridge/comal80.rb +0 -50
  377. data/lib/badline/cartridge/dinamic.rb +0 -34
  378. data/lib/badline/cartridge/easy_flash.rb +0 -145
  379. data/lib/badline/cartridge/epyx_fastload.rb +0 -79
  380. data/lib/badline/cartridge/final_cartridge3.rb +0 -89
  381. data/lib/badline/cartridge/flash.rb +0 -306
  382. data/lib/badline/cartridge/freezer.rb +0 -33
  383. data/lib/badline/cartridge/fun_play.rb +0 -38
  384. data/lib/badline/cartridge/g_mod2.rb +0 -74
  385. data/lib/badline/cartridge/game_system.rb +0 -40
  386. data/lib/badline/cartridge/geo_ram.rb +0 -79
  387. data/lib/badline/cartridge/kcs_power.rb +0 -75
  388. data/lib/badline/cartridge/mach5.rb +0 -32
  389. data/lib/badline/cartridge/magic_desk.rb +0 -30
  390. data/lib/badline/cartridge/ocean.rb +0 -35
  391. data/lib/badline/cartridge/pagefox.rb +0 -68
  392. data/lib/badline/cartridge/retro_replay.rb +0 -320
  393. data/lib/badline/cartridge/rex_utility.rb +0 -29
  394. data/lib/badline/cartridge/rgcd.rb +0 -58
  395. data/lib/badline/cartridge/simons_basic.rb +0 -35
  396. data/lib/badline/cartridge/standard.rb +0 -15
  397. data/lib/badline/cartridge/super_games.rb +0 -48
  398. data/lib/badline/cartridge/westermann.rb +0 -30
  399. data/lib/badline/cartridge/zaxxon.rb +0 -66
  400. data/lib/badline/cartridge.rb +0 -303
  401. data/lib/badline/checkpoint.rb +0 -98
  402. data/lib/badline/chrout_trap.rb +0 -43
  403. data/lib/badline/cia/fast_forward.rb +0 -60
  404. data/lib/badline/cia/interrupt_register.rb +0 -143
  405. data/lib/badline/cia/serial.rb +0 -275
  406. data/lib/badline/cia/state.rb +0 -47
  407. data/lib/badline/cia/timer.rb +0 -206
  408. data/lib/badline/cia.rb +0 -279
  409. data/lib/badline/color_memory.rb +0 -25
  410. data/lib/badline/computer/attachments.rb +0 -88
  411. data/lib/badline/computer/saved_state.rb +0 -117
  412. data/lib/badline/computer/true_drives.rb +0 -69
  413. data/lib/badline/control_ports.rb +0 -76
  414. data/lib/badline/cpu/addressing.rb +0 -131
  415. data/lib/badline/cpu/boundary.rb +0 -54
  416. data/lib/badline/cpu/core.rb +0 -165
  417. data/lib/badline/cpu/microcode.rb +0 -177
  418. data/lib/badline/cpu/operations.rb +0 -88
  419. data/lib/badline/cpu/saved_state.rb +0 -115
  420. data/lib/badline/cpu/stack_operations.rb +0 -82
  421. data/lib/badline/cpu.rb +0 -10
  422. data/lib/badline/cpu_port.rb +0 -112
  423. data/lib/badline/datasette.rb +0 -161
  424. data/lib/badline/debug_register.rb +0 -28
  425. data/lib/badline/drive/core.rb +0 -147
  426. data/lib/badline/drive/fast_serial.rb +0 -73
  427. data/lib/badline/drive/idle.rb +0 -125
  428. data/lib/badline/drive/idle_cpu.rb +0 -28
  429. data/lib/badline/drive/orbit.rb +0 -79
  430. data/lib/badline/drive/serial_lines.rb +0 -73
  431. data/lib/badline/drive/sleep.rb +0 -112
  432. data/lib/badline/drive/vias.rb +0 -84
  433. data/lib/badline/drive/watch.rb +0 -150
  434. data/lib/badline/drive.rb +0 -11
  435. data/lib/badline/drive1541/bus.rb +0 -86
  436. data/lib/badline/drive1541/byte_ready.rb +0 -48
  437. data/lib/badline/drive1541/cpu.rb +0 -11
  438. data/lib/badline/drive1541/disk.rb +0 -315
  439. data/lib/badline/drive1541/disk_state.rb +0 -86
  440. data/lib/badline/drive1541/disk_via.rb +0 -36
  441. data/lib/badline/drive1541/gcr.rb +0 -57
  442. data/lib/badline/drive1541/mechanism.rb +0 -313
  443. data/lib/badline/drive1541/mechanism_state.rb +0 -68
  444. data/lib/badline/drive1541/rotation.rb +0 -121
  445. data/lib/badline/drive1541/sector_reader.rb +0 -76
  446. data/lib/badline/drive1541/serial_port.rb +0 -18
  447. data/lib/badline/drive1541/track.rb +0 -98
  448. data/lib/badline/drive1541.rb +0 -111
  449. data/lib/badline/drive1571/bus.rb +0 -111
  450. data/lib/badline/drive1571/cpu.rb +0 -11
  451. data/lib/badline/drive1571/serial_port.rb +0 -37
  452. data/lib/badline/drive1571/serial_via.rb +0 -25
  453. data/lib/badline/drive1571/wd1770.rb +0 -120
  454. data/lib/badline/drive1571.rb +0 -175
  455. data/lib/badline/drive1581/bus.rb +0 -137
  456. data/lib/badline/drive1581/cpu.rb +0 -11
  457. data/lib/badline/drive1581/disk.rb +0 -135
  458. data/lib/badline/drive1581/disk_state.rb +0 -87
  459. data/lib/badline/drive1581/mechanism.rb +0 -117
  460. data/lib/badline/drive1581/serial_port.rb +0 -52
  461. data/lib/badline/drive1581/slot.rb +0 -78
  462. data/lib/badline/drive1581/track.rb +0 -100
  463. data/lib/badline/drive1581/track_bytes.rb +0 -75
  464. data/lib/badline/drive1581/wd1772/registers.rb +0 -89
  465. data/lib/badline/drive1581/wd1772/sector_writes.rb +0 -73
  466. data/lib/badline/drive1581/wd1772/sectors.rb +0 -150
  467. data/lib/badline/drive1581/wd1772/state.rb +0 -66
  468. data/lib/badline/drive1581/wd1772/stepping.rb +0 -109
  469. data/lib/badline/drive1581/wd1772/tracks.rb +0 -125
  470. data/lib/badline/drive1581/wd1772/turn.rb +0 -73
  471. data/lib/badline/drive1581/wd1772.rb +0 -216
  472. data/lib/badline/drive1581.rb +0 -233
  473. data/lib/badline/iec_bus.rb +0 -159
  474. data/lib/badline/instruction.rb +0 -334
  475. data/lib/badline/instruction_set/arithmetic.rb +0 -114
  476. data/lib/badline/instruction_set/bitwise.rb +0 -126
  477. data/lib/badline/instruction_set/branch.rb +0 -79
  478. data/lib/badline/instruction_set/flag.rb +0 -63
  479. data/lib/badline/instruction_set/illegal.rb +0 -270
  480. data/lib/badline/instruction_set/inc_dec.rb +0 -69
  481. data/lib/badline/instruction_set/stack.rb +0 -52
  482. data/lib/badline/instruction_set/transfer.rb +0 -137
  483. data/lib/badline/instruction_set.rb +0 -55
  484. data/lib/badline/interrupts.rb +0 -104
  485. data/lib/badline/joystick.rb +0 -25
  486. data/lib/badline/kernal_trap/channel.rb +0 -181
  487. data/lib/badline/keyboard.rb +0 -112
  488. data/lib/badline/keyboard_buffer.rb +0 -33
  489. data/lib/badline/ram_expansion/banking.rb +0 -30
  490. data/lib/badline/ram_expansion/plus256k.rb +0 -54
  491. data/lib/badline/ram_expansion/plus60k.rb +0 -43
  492. data/lib/badline/ram_expansion/unexpanded.rb +0 -28
  493. data/lib/badline/ram_expansion.rb +0 -21
  494. data/lib/badline/reu/dma/saved_state.rb +0 -50
  495. data/lib/badline/reu/dma.rb +0 -273
  496. data/lib/badline/reu/ram.rb +0 -107
  497. data/lib/badline/reu/saved_state.rb +0 -80
  498. data/lib/badline/reu/trigger.rb +0 -32
  499. data/lib/badline/reu.rb +0 -289
  500. data/lib/badline/sid/catch_up.rb +0 -120
  501. data/lib/badline/sid/decimator.rb +0 -64
  502. data/lib/badline/sid/envelope/state.rb +0 -68
  503. data/lib/badline/sid/envelope.rb +0 -239
  504. data/lib/badline/sid/filter.rb +0 -263
  505. data/lib/badline/sid/voice.rb +0 -77
  506. data/lib/badline/sid/waveform/combined.rb +0 -126
  507. data/lib/badline/sid/waveform/fast_forward.rb +0 -105
  508. data/lib/badline/sid/waveform/noise_writeback.rb +0 -122
  509. data/lib/badline/sid/waveform/state.rb +0 -66
  510. data/lib/badline/sid/waveform.rb +0 -305
  511. data/lib/badline/sid.rb +0 -303
  512. data/lib/badline/snapshot/setup.rb +0 -75
  513. data/lib/badline/snapshot/state.rb +0 -189
  514. data/lib/badline/time_of_day.rb +0 -228
  515. data/lib/badline/traps.rb +0 -19
  516. data/lib/badline/via/control_lines.rb +0 -122
  517. data/lib/badline/via/fast_forward.rb +0 -53
  518. data/lib/badline/via/interrupt_register.rb +0 -67
  519. data/lib/badline/via/shift_register.rb +0 -180
  520. data/lib/badline/via/state.rb +0 -42
  521. data/lib/badline/via/timer1.rb +0 -131
  522. data/lib/badline/via/timer2.rb +0 -133
  523. data/lib/badline/via.rb +0 -266
  524. data/lib/badline/vic/bank.rb +0 -133
  525. data/lib/badline/vic/border_mask.rb +0 -86
  526. data/lib/badline/vic/collisions.rb +0 -115
  527. data/lib/badline/vic/color_patches.rb +0 -47
  528. data/lib/badline/vic/display_state.rb +0 -185
  529. data/lib/badline/vic/graphics_mode.rb +0 -164
  530. data/lib/badline/vic/graphics_shifter.rb +0 -207
  531. data/lib/badline/vic/register_log.rb +0 -81
  532. data/lib/badline/vic/registers.rb +0 -195
  533. data/lib/badline/vic/sequencer.rb +0 -275
  534. data/lib/badline/vic/sequencer_output.rb +0 -116
  535. data/lib/badline/vic/sequencer_state.rb +0 -89
  536. data/lib/badline/vic/sprite/internal_bus.rb +0 -68
  537. data/lib/badline/vic/sprite/saved_state.rb +0 -64
  538. data/lib/badline/vic/sprite/shifter.rb +0 -146
  539. data/lib/badline/vic/sprite/timing.rb +0 -56
  540. data/lib/badline/vic/sprite.rb +0 -337
  541. data/lib/badline/vic/sprites.rb +0 -282
  542. data/lib/badline/vic/sprites_state.rb +0 -57
  543. data/lib/badline/vic.rb +0 -853
  544. data/lib/badline/vic20/saved_state.rb +0 -124
  545. data/lib/badline/vic20/sound/output.rb +0 -83
  546. data/lib/badline/vic20/sound.rb +0 -233
  547. data/lib/badline/vic20/vic/saved_state.rb +0 -55
  548. data/lib/badline/z80/arithmetic.rb +0 -117
  549. data/lib/badline/z80/bit_page.rb +0 -55
  550. data/lib/badline/z80/block_io.rb +0 -58
  551. data/lib/badline/z80/block_transfers.rb +0 -59
  552. data/lib/badline/z80/bus_cycles.rb +0 -111
  553. data/lib/badline/z80/core.rb +0 -113
  554. data/lib/badline/z80/exchanges.rb +0 -50
  555. data/lib/badline/z80/extended_page.rb +0 -89
  556. data/lib/badline/z80/flags.rb +0 -37
  557. data/lib/badline/z80/interrupt_acceptance.rb +0 -46
  558. data/lib/badline/z80/jumps.rb +0 -82
  559. data/lib/badline/z80/loads.rb +0 -98
  560. data/lib/badline/z80/main_page.rb +0 -134
  561. data/lib/badline/z80/registers.rb +0 -120
  562. data/lib/badline/z80/saved_state.rb +0 -69
  563. data/lib/badline/z80/shifts.rb +0 -64
  564. data/lib/badline/z80.rb +0 -11
  565. /data/lib/badline/snapshot/{fields.rb → vice/fields.rb} +0 -0
@@ -1,104 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module Interrupts
5
- BREAK_MASK = 0x10
6
-
7
- private
8
-
9
- # Samples the IRQ line and the NMI latch once per cycle. An instruction
10
- # boundary commits the sample taken on its second-to-last cycle.
11
- def poll
12
- if @skip_poll
13
- @skip_poll = false
14
- return
15
- end
16
- @irq_pending = @irq_sample
17
- @nmi_pending = @nmi_sample
18
- @irq_sample = @irq && !@status.interrupt?
19
- @nmi_sample = @nmi
20
- end
21
-
22
- # A cycle the VIC stalls through BA keeps sampling the lines, OR-ed with
23
- # the sample it already holds, but the boundary pipeline doesn't advance
24
- # and a skipped poll stays owed to the next real cycle.
25
- def sample_while_stalled
26
- @irq_sample ||= @irq && !interrupt_disabled_after_stall?
27
- @nmi_sample = true if @nmi
28
- end
29
-
30
- # A stalled CLI or SEI execute cycle masks with the I it is about to
31
- # set. Every other step masks with the current I, PLP included: its
32
- # pulled I only arrives with the stalled stack read.
33
- def interrupt_disabled_after_stall?
34
- return @status.interrupt? unless @plan.equal?(CPU::IMPLIED_PLAN)
35
-
36
- case @operation
37
- when :cli then false
38
- when :sei then true
39
- else @status.interrupt?
40
- end
41
- end
42
-
43
- # Runs in the opcode fetch cycle in place of the fetch, with no bus
44
- # access, and switches to the interrupt plan.
45
- def start_interrupt
46
- @interrupt = @boundary_nmi ? 0xfffa : 0xfffe
47
- @brk = false
48
- @plan = CPU::INTERRUPT_PLAN
49
- @writes = CPU::INTERRUPT_WRITES
50
- @index = 1
51
- end
52
-
53
- # BRK reads the byte after its opcode and ignores it, and selects the
54
- # IRQ vector.
55
- def op_brk_dummy
56
- @memory.peek(@program_counter)
57
- @interrupt = 0xfffe
58
- @brk = true
59
- end
60
-
61
- def op_int_push_pch
62
- @address = @brk ? (@program_counter + 1) & 0xffff : @program_counter
63
- @memory.poke(stack_address, high_byte(@address))
64
- @stack_pointer = (@stack_pointer - 1) & 0xff
65
- end
66
-
67
- def op_int_push_pcl
68
- @memory.poke(stack_address, low_byte(@address))
69
- @stack_pointer = (@stack_pointer - 1) & 0xff
70
- end
71
-
72
- def op_int_push_status
73
- value = @brk ? @status.value | BREAK_MASK : @status.value & ~BREAK_MASK
74
- @memory.poke(stack_address, value)
75
- @stack_pointer = (@stack_pointer - 1) & 0xff
76
- @status.interrupt = true
77
- # An NMI that arrives before cycle 4 of a BRK or IRQ takes it over:
78
- # the sequence finishes with the NMI vector.
79
- @interrupt = 0xfffa if @interrupt == 0xfffe && @nmi_pending
80
- @nmi = false if @interrupt == 0xfffa
81
- end
82
-
83
- def op_int_vector_low
84
- @address = @memory.peek(@interrupt)
85
- end
86
-
87
- # Clears any interrupt that is pending, so the handler's first
88
- # instruction always runs before the next interrupt. This applies to
89
- # BRK too.
90
- def op_int_vector_high
91
- high = @memory.peek((@interrupt + 1) & 0xffff)
92
- @program_counter = @address | (high << 8)
93
- @irq_sample = @irq_pending = false
94
- @nmi_sample = @nmi_pending = false
95
- @interrupt = nil
96
- if @brk
97
- @status.break = false
98
- end_instruction
99
- else
100
- end_sequence
101
- end
102
- end
103
- end
104
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class Joystick
5
- DIRECTIONS = { up: 0, down: 1, left: 2, right: 3, fire: 4 }.freeze
6
-
7
- # Kept up to date as switches move, since the CIA samples the fire line
8
- # every cycle to drive the light pen input.
9
- attr_reader :port_bits
10
-
11
- def initialize
12
- @port_bits = 0xff
13
- end
14
-
15
- def press(direction)
16
- bit = DIRECTIONS[direction]
17
- @port_bits &= ~(1 << bit) if bit
18
- end
19
-
20
- def release(direction)
21
- bit = DIRECTIONS[direction]
22
- @port_bits |= 1 << bit if bit
23
- end
24
- end
25
- end
@@ -1,181 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module KernalTrap
5
- # One open channel on the virtual drive, holding a file, a block buffer
6
- # or the command channel's status message. It gives out one byte at a
7
- # time and flags the last one, so the bus can raise EOI with it. A
8
- # channel cut short by a read error never flags one, and holds the
9
- # error for the drive to report once its bytes run out.
10
- class Channel
11
- attr_accessor :buffer
12
- attr_reader :error, :pointer
13
- attr_writer :lead
14
-
15
- def initialize(bytes = [], error: nil, writable: false, base: 0)
16
- @base = base
17
- replace(bytes)
18
- @error = error
19
- @writable = writable
20
- end
21
-
22
- # A block buffer opened with "#", which reads and writes one of the
23
- # drive's buffers in its RAM, so M-R and M-W reach the same bytes. It
24
- # hands out the whole block unless a B-R sets a shorter end, and
25
- # flags that byte as the last. The DOS opens it with the pointer at 1
26
- # and the buffer's number as the byte to send, so the first read
27
- # answers with the number and the next one moves on to the third
28
- # byte.
29
- def self.buffer(memory, number)
30
- new(memory.ram, writable: true, base: Drive::Memory.buffer_address(number)).tap do |channel|
31
- channel.buffer = number
32
- channel.rewind(Drive::BLOCK_SIZE)
33
- channel.pointer = 1
34
- channel.lead = number
35
- end
36
- end
37
-
38
- # A file's bytes, up to the first block its chain can't read. The
39
- # drive reads a block ahead before sending the last byte of the one
40
- # before, so a bad block holds that byte back too, and a bad first
41
- # block or a missing file leaves nothing to send.
42
- def self.for_file(storage, name, type)
43
- data = storage.read_file(name, type:)
44
- return new([], error: [Drive::FILE_NOT_FOUND]) unless data
45
-
46
- failure = storage.respond_to?(:read_error) && storage.read_error(name, type:)
47
- return new(data) unless failure
48
-
49
- new(data[0, failure[:offset] - 1] || [], error: failure.values_at(:error, :track, :sector))
50
- end
51
-
52
- # The file an open names. The drive keeps the first block of the file
53
- # a LOAD (secondary address 0) opens at $7E and $026F of its memory,
54
- # and a LOAD of a name starting with "*" reopens that file rather than
55
- # the first one on the disk. Loaders write the block there with M-W
56
- # to load a file the directory doesn't list. A LOAD of "$" reads the
57
- # directory as a BASIC program, which a pattern after a colon narrows
58
- # to the files it names.
59
- def self.for_name(storage, memory, secondary, name, type)
60
- return new(storage.directory.bytes(name)) if listing?(storage, secondary, name)
61
-
62
- file = Storage.parse_name(name).first
63
- return for_file(storage, file, type) unless secondary.zero? && storage.respond_to?(:first_block)
64
-
65
- last = memory.last_program if name.start_with?("*")
66
- return at_block(storage, *last) if last
67
-
68
- block = storage.first_block(file, type:)
69
- memory.last_program = block if block
70
- for_file(storage, file, type)
71
- end
72
-
73
- def self.listing?(storage, secondary, name)
74
- secondary.zero? && name.start_with?("$") && storage.respond_to?(:directory)
75
- end
76
-
77
- # The file whose chain starts at the block.
78
- def self.at_block(storage, track, sector)
79
- data = storage.read_file_at(track, sector)
80
- data ? new(data) : new([], error: [Drive::ILLEGAL_TRACK_OR_SECTOR, track, sector])
81
- end
82
-
83
- # Reads what save_state wrote after the flag that marks a file open
84
- # for writing (Drive::Channels.channel_from_state). A buffer channel
85
- # takes its block in `ram`, the drive's RAM, again.
86
- def self.from_state(input, ram)
87
- new.tap { |channel| channel.load_state(input, ram) }
88
- end
89
-
90
- # A buffer channel's bytes are the drive's RAM, which the drive
91
- # writes itself.
92
- def save_state(out)
93
- out.boolean(false).boolean(@writable).int(@base).int(@length).int(@pointer)
94
- out.optional_int(@lead).optional_int(@buffer).boolean(!@error.nil?)
95
- out.ints(@error) if @error
96
- out.blob(@bytes) unless @writable
97
- end
98
-
99
- def load_state(input, ram)
100
- @writable = input.boolean?
101
- @base = input.int
102
- @length = input.int
103
- @pointer = input.int
104
- @lead = input.optional_int
105
- @buffer = input.optional_int
106
- @error = input.boolean? ? input.ints : nil
107
- @bytes = @writable ? ram : input.blob
108
- end
109
-
110
- def replace(bytes, length = bytes.length)
111
- @bytes = bytes
112
- rewind(length)
113
- end
114
-
115
- def rewind(length)
116
- @length = length
117
- self.pointer = 0
118
- end
119
-
120
- def pointer=(position)
121
- @pointer = position
122
- @lead = nil
123
- end
124
-
125
- # A block read into the channel. A buffer channel takes it into its
126
- # buffer, a file channel hands it out in place of the file.
127
- def load(block, length)
128
- return replace(block.dup, length) unless @writable
129
-
130
- @bytes[@base, block.length] = block
131
- rewind(length)
132
- end
133
-
134
- def writable? = @writable
135
-
136
- # A buffer channel's block, as a block write puts it on the disk.
137
- def block = @bytes[@base, Drive::BLOCK_SIZE]
138
-
139
- def exhausted?
140
- @pointer >= @length
141
- end
142
-
143
- # A file that holds nothing but its error never opened.
144
- def failed?
145
- exhausted? && !@error.nil?
146
- end
147
-
148
- # Each byte lands at the pointer, which wraps within the block.
149
- def write(bytes)
150
- @lead = nil
151
- bytes.each do |byte|
152
- @bytes[@base + @pointer] = byte
153
- @pointer = (@pointer + 1) & 0xff
154
- end
155
- end
156
-
157
- def read
158
- return read_buffer if @writable
159
- return if exhausted?
160
-
161
- byte = @lead || @bytes[@base + @pointer]
162
- @lead = nil
163
- @pointer += 1
164
- [byte, exhausted? && !@error]
165
- end
166
-
167
- private
168
-
169
- # A buffer never runs out. Past its last byte, which goes out with
170
- # EOI, the pointer wraps back to the second, and a pointer set past
171
- # the end runs on around the block to it.
172
- def read_buffer
173
- byte = @lead || @bytes[@base + @pointer]
174
- @lead = nil
175
- last = @pointer == @length - 1
176
- @pointer = last ? 1 : (@pointer + 1) & 0xff
177
- [byte, last]
178
- end
179
- end
180
- end
181
- end
@@ -1,112 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- # The key matrix spanning CIA 1's two ports: rows on port A, columns on
5
- # port B. Row lines beyond the eighth sit above port A's bits in +rows+.
6
- #
7
- # A pressed key shorts its row line to its column line, so whichever side is
8
- # pulled low drags the other down with it. Scanning works in either
9
- # direction, and chains of keys sharing a line propagate the pulldown -- the
10
- # ghost keys real hardware reports.
11
- class Keyboard
12
- include IntegerHelper
13
-
14
- # Keys the C64 types as a combination: cursor up and cursor left are the
15
- # shifted cursor keys. Pressing one holds both of its matrix keys, while
16
- # a shift key held on its own stays down when it is released.
17
- COMBINATIONS = {
18
- cursor_up: %i[lshift cursor_v],
19
- cursor_left: %i[lshift cursor_h]
20
- }.freeze
21
-
22
- # The C64's wiring: one row of keys per port A line, in port B column
23
- # order.
24
- C64_MATRIX = [
25
- %i[delete return cursor_h f7 f1 f3 f5 cursor_v],
26
- %i[3 w a 4 z s e lshift],
27
- %i[5 r d 6 c f t x],
28
- %i[7 y g 8 b h u v],
29
- %i[9 i j 0 m k o n],
30
- %i[+ p l - . : @ ,],
31
- %i[£ * ; clr_home rshift = up /],
32
- %i[1 left control 2 space cbm q run_stop]
33
- ].freeze
34
-
35
- attr_reader :keys, :matrix
36
-
37
- def initialize(matrix: C64_MATRIX)
38
- @keys = []
39
- @row_masks = nil
40
- @matrix = matrix
41
- @connected = true
42
- end
43
-
44
- # Whether the machine has a keyboard. The C64GS has none: no key goes
45
- # down on it.
46
- def connected? = @connected
47
-
48
- def connected=(connected)
49
- @connected = connected
50
- @keys.clear unless connected
51
- @row_masks = nil
52
- end
53
-
54
- def press(key)
55
- return unless @connected && valid_key?(key)
56
-
57
- @keys << key
58
- @row_masks = nil
59
- end
60
-
61
- def release(key)
62
- @keys.reject! { |k| k == key }
63
- @row_masks = nil
64
- end
65
-
66
- # Settles the row (port A) and column (port B) lines against each other
67
- # until no key contact pulls a line low any more, and returns both.
68
- def scan(rows, cols)
69
- return [rows, cols] if keys.empty?
70
-
71
- loop do
72
- settled_rows = rows
73
- settled_cols = cols
74
-
75
- row_masks.each_with_index do |mask, row|
76
- bit = 1 << row
77
- next if mask.zero? || (rows.allbits?(bit) && cols.allbits?(mask))
78
-
79
- rows &= ~bit
80
- cols &= ~mask
81
- end
82
-
83
- return [rows, cols] if rows == settled_rows && cols == settled_cols
84
- end
85
- end
86
-
87
- def read_a(port_a, port_b) = scan(port_a, port_b).first
88
-
89
- def read_b(port_a, port_b) = scan(port_a, port_b).last
90
-
91
- private
92
-
93
- # Columns held down per row, as a bit mask of port B lines.
94
- def row_masks
95
- @row_masks ||= begin
96
- pressed = held
97
- matrix.map do |row|
98
- row.each_with_index.sum { |key, column| pressed.include?(key) ? 1 << column : 0 }
99
- end
100
- end
101
- end
102
-
103
- # The matrix keys held down, with each combination expanded.
104
- def held
105
- keys.flat_map { |key| COMBINATIONS[key] || [key] }
106
- end
107
-
108
- def valid_key?(key)
109
- COMBINATIONS.key?(key) || matrix.flatten.include?(key)
110
- end
111
- end
112
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module KeyboardBuffer
5
- ADDRESS = 0x0277
6
- COUNT = 0xc6
7
- CAPACITY = 10
8
-
9
- def type_text(text)
10
- codes = text.bytes.map { |b| ascii_to_petscii(b) }
11
- on_init { @pending_keys = codes }
12
- end
13
-
14
- private
15
-
16
- def feed_keyboard
17
- return unless ram.peek(COUNT).zero?
18
-
19
- chunk = @pending_keys.shift(CAPACITY)
20
- ram.write(ADDRESS, chunk)
21
- ram.poke(COUNT, chunk.length)
22
- @pending_keys = nil if @pending_keys.empty?
23
- end
24
-
25
- def ascii_to_petscii(byte)
26
- case byte
27
- when 0x61..0x7a then byte - 0x20
28
- when 0x41..0x5a then byte + 0x80
29
- else byte
30
- end
31
- end
32
- end
33
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module RAMExpansion
5
- # The register and page mapping the expansions share. #map lays the
6
- # selected banks out in the address bus's page tables, and #map_io puts
7
- # the register over the VIC's I/O page at $D100.
8
- module Banking
9
- attr_reader :low_ram, :high_ram, :video_ram
10
-
11
- # The block runs whenever the register moves a bank.
12
- def on_change(&block)
13
- @on_change = block
14
- end
15
-
16
- def peek(_addr) = 0xff
17
-
18
- def map(read_pages, write_pages)
19
- [read_pages, write_pages].each do |pages|
20
- pages.fill(@low_ram, 0x00, 0x10)
21
- pages.fill(@high_ram, 0x10, 0xf0)
22
- end
23
- end
24
-
25
- def map_io(read_pages, write_pages)
26
- read_pages[0xd1] = write_pages[0xd1] = self
27
- end
28
- end
29
- end
30
- end
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module RAMExpansion
5
- # The +256K: four 64K banks, the first of them the machine's own RAM.
6
- # $D100 picks one for $0000-$0FFF (bits 0-1), one for the VIC (bits 2-3)
7
- # and one for $1000-$FFFF (bits 6-7). Setting bit 4 locks the register
8
- # until the next reset.
9
- class Plus256k
10
- include Banking
11
-
12
- def initialize(ram)
13
- @banks = [ram, Memory.new, Memory.new, Memory.new]
14
- @on_change = nil
15
- reset!
16
- end
17
-
18
- def poke(_addr, value)
19
- return if @locked
20
-
21
- @low_ram = @banks[value & 0b11]
22
- @video_ram = @banks[(value >> 2) & 0b11]
23
- @high_ram = @banks[value >> 6]
24
- @locked = value.anybits?(0x10)
25
- @on_change&.call
26
- end
27
-
28
- def reset!
29
- @low_ram = @video_ram = @high_ram = @banks[0]
30
- @locked = false
31
- end
32
-
33
- def type = :plus256k
34
-
35
- def save_state(out)
36
- [@low_ram, @video_ram, @high_ram].each { |bank| out.int(@banks.index(bank)) }
37
- out.boolean(@locked)
38
- @banks.drop(1).each { |bank| bank.save_state(out) }
39
- end
40
-
41
- def load_state(input)
42
- @low_ram = @banks.fetch(input.int)
43
- @video_ram = @banks.fetch(input.int)
44
- @high_ram = @banks.fetch(input.int)
45
- @locked = input.boolean?
46
- @banks.drop(1).each { |bank| bank.load_state(input) }
47
- end
48
-
49
- def power_on!
50
- @banks.drop(1).each(&:clear!)
51
- end
52
- end
53
- end
54
- end
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module RAMExpansion
5
- # The +60K: a second bank of RAM behind $1000-$FFFF, selected by bit 7
6
- # of $D100. $0000-$0FFF stays the machine's own RAM, and so does all of
7
- # what the VIC sees.
8
- class Plus60k
9
- include Banking
10
-
11
- def initialize(ram)
12
- @low_ram = @video_ram = @high_ram = ram
13
- @banks = [ram, Memory.new]
14
- @on_change = nil
15
- end
16
-
17
- def poke(_addr, value)
18
- @high_ram = @banks[value >> 7]
19
- @on_change&.call
20
- end
21
-
22
- def reset!
23
- @high_ram = @banks[0]
24
- end
25
-
26
- def type = :plus60k
27
-
28
- def save_state(out)
29
- out.int(@banks.index(@high_ram))
30
- @banks[1].save_state(out)
31
- end
32
-
33
- def load_state(input)
34
- @high_ram = @banks.fetch(input.int)
35
- @banks[1].load_state(input)
36
- end
37
-
38
- def power_on!
39
- @banks[1].clear!
40
- end
41
- end
42
- end
43
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- module RAMExpansion
5
- # The machine with no expansion fitted: its own RAM everywhere, and
6
- # $D100 left to the VIC.
7
- class Unexpanded
8
- include Banking
9
-
10
- def initialize(ram)
11
- @low_ram = @video_ram = @high_ram = ram
12
- @on_change = nil
13
- end
14
-
15
- def type = nil
16
-
17
- def map_io(_read_pages, _write_pages); end
18
-
19
- def save_state(_out); end
20
-
21
- def load_state(_input); end
22
-
23
- def reset!; end
24
-
25
- def power_on!; end
26
- end
27
- end
28
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "badline/ram_expansion/banking"
4
- require "badline/ram_expansion/unexpanded"
5
- require "badline/ram_expansion/plus60k"
6
- require "badline/ram_expansion/plus256k"
7
-
8
- module Badline
9
- # RAM expansions that bank extra memory in under the CPU through a
10
- # register at $D100, in the VIC's I/O page. Any write to $D100-$D1FF
11
- # sets the register, which reads back as $FF.
12
- module RAMExpansion
13
- TYPES = { plus60k: Plus60k, plus256k: Plus256k }.freeze
14
-
15
- def self.build(type, ram, &)
16
- expansion = type ? TYPES.fetch(type).new(ram) : Unexpanded.new(ram)
17
- expansion.on_change(&)
18
- expansion
19
- end
20
- end
21
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class REU
5
- class DMA
6
- # A transfer's state for a snapshot (REU::SavedState).
7
- module SavedState
8
- # Everything a transfer holds between cycles. Before the first
9
- # transfer, the fields it sets on starting are empty.
10
- def save_state(out)
11
- out.int(@c64).int(@expansion).int(@length).int(@events)
12
- [@type, @c64_step, @expansion_step, @last, @ba_low_after_writes, @swap_byte, @held_read].each do |value|
13
- out.optional_int(value)
14
- end
15
- [@holding, @waiting, @stopped_after_write, @swap_write_due, @swap_read_again, @moved_all,
16
- @extra_cycle].each do |flag|
17
- out.boolean(flag)
18
- end
19
- end
20
-
21
- def load_state(input)
22
- @c64 = input.int
23
- @expansion = input.int
24
- @length = input.int
25
- @events = input.int
26
- load_steps(input)
27
- @holding = input.boolean?
28
- @waiting = input.boolean?
29
- @stopped_after_write = input.boolean?
30
- @swap_write_due = input.boolean?
31
- @swap_read_again = input.boolean?
32
- @moved_all = input.boolean?
33
- @extra_cycle = input.boolean?
34
- end
35
-
36
- private
37
-
38
- def load_steps(input)
39
- @type = input.optional_int
40
- @c64_step = input.optional_int
41
- @expansion_step = input.optional_int
42
- @last = input.optional_int
43
- @ba_low_after_writes = input.optional_int
44
- @swap_byte = input.optional_int
45
- @held_read = input.optional_int
46
- end
47
- end
48
- end
49
- end
50
- end