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
data/lib/badline/c128.rb CHANGED
@@ -2,23 +2,25 @@
2
2
 
3
3
  require "badline/c128/model"
4
4
  require "badline/c128/mmu"
5
- require "badline/c128/vdc"
5
+ require "badline/chips/vdc"
6
6
  require "badline/c128/mmu_pages"
7
7
  require "badline/c128/io_pages"
8
8
  require "badline/c128/z80_pages"
9
9
  require "badline/c128/color_lines"
10
10
  require "badline/c128/banks"
11
- require "badline/c128/bus_state"
11
+ require "badline/c128/bus/keyed_state"
12
12
  require "badline/c128/bus"
13
13
  require "badline/c128/cpu"
14
14
  require "badline/c128/z80"
15
15
  require "badline/c128/z80_turns"
16
- require "badline/c128/saved_state"
16
+ require "badline/snapshot/c128_setup"
17
+ require "badline/c128/keyed_state"
18
+ require "badline/c128/keyed_modules"
17
19
  require "badline/c128/keys"
18
20
  require "badline/c128/modes"
19
21
  require "badline/c128/drives"
20
22
  require "badline/c128/fast_serial"
21
- require "badline/drive1571"
23
+ require "badline/drives/model1571"
22
24
 
23
25
  module Badline
24
26
  # The Commodore 128: the 8502 on the VIC-IIe's clock, two CIAs, the SID,
@@ -43,11 +45,12 @@ module Badline
43
45
  # mirrors, and $D500-$D7FF holds the hidden MMU, the VDC and open bus.
44
46
  class C128
45
47
  include IntegerHelper
46
- include KeyboardBuffer
48
+ include Machine::KeyboardBuffer
47
49
  include Machine::Clocking
48
- include Computer::Common
49
- include Computer::Attachments
50
- include Computer::KernalTraps
50
+ include Machine::Settling
51
+ include C64::Common
52
+ include C64::Attachments
53
+ include C64::KernalTraps
51
54
  include Keys
52
55
  include Modes
53
56
  include Drives
@@ -56,7 +59,7 @@ module Badline
56
59
 
57
60
  # The C64's 8x8 matrix and the three rows K0-K2 select, in port B
58
61
  # column order.
59
- KEYBOARD_MATRIX = (Keyboard::C64_MATRIX + [
62
+ KEYBOARD_MATRIX = (Input::Keyboard::C64_MATRIX + [
60
63
  %i[help keypad8 keypad5 tab keypad2 keypad4 keypad7 keypad1],
61
64
  %i[esc keypad_plus keypad_minus line_feed keypad_enter keypad6 keypad9 keypad3],
62
65
  %i[alt keypad0 keypad_period crsr_up crsr_down crsr_left crsr_right no_scroll]
@@ -67,10 +70,6 @@ module Badline
67
70
  # BASIC 7.0's, which is READY by then.
68
71
  C128_INIT_THRESHOLD = 2_000_000
69
72
 
70
- # The C128 KERNAL's keyboard buffer and its count.
71
- C128_KEYBOARD_BUFFER = 0x034a
72
- C128_KEYBOARD_COUNT = 0xd0
73
-
74
73
  attr_reader :cpu, :cycles, :drive1541, :model, :init_threshold
75
74
 
76
75
  def family = :c128
@@ -93,6 +92,11 @@ module Badline
93
92
 
94
93
  def ram = @bus.ram
95
94
 
95
+ # Reads and writes memory as the CPU sees it, through the bus.
96
+ def peek(addr) = @bus.peek(addr)
97
+
98
+ def poke(addr, value) = @bus.poke(addr, value)
99
+
96
100
  def keyboard = @bus.keyboard
97
101
 
98
102
  def joystick1 = @bus.joystick1
@@ -116,7 +120,7 @@ module Badline
116
120
 
117
121
  @model = Model.named(model)
118
122
  @c64_built = mode == :c64
119
- @init_threshold = @c64_built ? Computer::INIT_THRESHOLD : C128_INIT_THRESHOLD
123
+ @init_threshold = @c64_built ? C64::INIT_THRESHOLD : C128_INIT_THRESHOLD
120
124
  @holding_commodore = false
121
125
  @bus = Bus.new(@model, sid_model: sid_model || @model.sid_model, mode:)
122
126
  @cpu = CPU.new(@bus, debug:)
@@ -135,6 +139,7 @@ module Badline
135
139
  @restore_pulse = false
136
140
  @init_handlers = []
137
141
  @pending_keys = nil
142
+ @typist = Input::MatrixTypist.new(@bus.keyboard)
138
143
  @capture_output = nil
139
144
  init_drives
140
145
  enter_c64_mode if @c64_built
@@ -149,7 +154,7 @@ module Badline
149
154
  return z80_cycle! if @z80_turn
150
155
 
151
156
  handle_init if @cycles == @init_threshold
152
- feed_keyboard if @pending_keys
157
+ type_pending if @pending_keys
153
158
 
154
159
  clock_bits = @clock_bits
155
160
  @clock_bits = @vic.clock_bits
@@ -209,7 +214,7 @@ module Badline
209
214
  @cia2.reset!
210
215
  @sid.reset!
211
216
  @bus.cartridge&.reset
212
- @drive&.reset!
217
+ @dos&.reset!
213
218
  @drive1541&.reset!
214
219
  @drive1571&.reset!
215
220
  @drive1581&.reset!
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ # What plugs into the machine besides its chips, the cartridge, its
6
+ # true drives (TrueDrives) and an REU, and their state for a snapshot.
7
+ # The disk device 8 serves through the traps is KernalTraps'.
8
+ module Attachments
9
+ include TrueDrives
10
+
11
+ # Puts the cartridge in the expansion port and wires its clock and NMI
12
+ # line to the machine, leaving the machine's state as it is. A
13
+ # restored snapshot's cartridge comes back through here.
14
+ def connect_cartridge(cartridge)
15
+ cartridge.clock = -> { @cycles }
16
+ cartridge.on_nmi_change { |level| @cartridge_nmi = level }
17
+ address_bus.attach_cartridge(cartridge)
18
+ end
19
+
20
+ # The serial bus, which CIA 2's port A drives through the C64's own
21
+ # inverters and reads back on PA6 and PA7, with or without a drive on
22
+ # it.
23
+ attr_reader :iec_bus
24
+
25
+ private
26
+
27
+ # CIA 2's port A drives the serial bus, which reads CLK and DATA back
28
+ # into it.
29
+ def plug_serial_bus
30
+ @iec_bus = Drives::SerialBus.new
31
+ @cia2.peripheral = @iec_bus
32
+ @cia2.on_port_a_write { push_serial_lines }
33
+ push_serial_lines
34
+ end
35
+
36
+ # Pushes the lines CIA 2's port A pulls into the serial bus.
37
+ def push_serial_lines
38
+ @iec_bus.host_lines = @cia2.port_a_lines
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ module BankedRAM
6
+ # The register and page mapping the expansions share. #map lays the
7
+ # selected banks out in the address bus's page tables, and #map_io puts
8
+ # the register over the VIC's I/O page at $D100.
9
+ module Banking
10
+ attr_reader :low_ram, :high_ram, :video_ram
11
+
12
+ # The block runs whenever the register moves a bank.
13
+ def on_change(&block)
14
+ @on_change = block
15
+ end
16
+
17
+ def peek(_addr) = 0xff
18
+
19
+ def map(read_pages, write_pages)
20
+ [read_pages, write_pages].each do |pages|
21
+ pages.fill(@low_ram, 0x00, 0x10)
22
+ pages.fill(@high_ram, 0x10, 0xf0)
23
+ end
24
+ end
25
+
26
+ def map_io(read_pages, write_pages)
27
+ read_pages[0xd1] = write_pages[0xd1] = self
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ module BankedRAM
6
+ # The +256K: four 64K banks, the first of them the machine's own RAM.
7
+ # $D100 picks one for $0000-$0FFF (bits 0-1), one for the VIC (bits 2-3)
8
+ # and one for $1000-$FFFF (bits 6-7). Setting bit 4 locks the register
9
+ # until the next reset.
10
+ class Plus256k
11
+ include Banking
12
+
13
+ def initialize(ram)
14
+ @banks = [ram, Memory.new, Memory.new, Memory.new]
15
+ @on_change = nil
16
+ reset!
17
+ end
18
+
19
+ def poke(_addr, value)
20
+ return if @locked
21
+
22
+ @low_ram = @banks[value & 0b11]
23
+ @video_ram = @banks[(value >> 2) & 0b11]
24
+ @high_ram = @banks[value >> 6]
25
+ @locked = value.anybits?(0x10)
26
+ @on_change&.call
27
+ end
28
+
29
+ def reset!
30
+ @low_ram = @video_ram = @high_ram = @banks[0]
31
+ @locked = false
32
+ end
33
+
34
+ def type = :plus256k
35
+
36
+ # $D100 as the banks it picks give it, whether it is locked, and
37
+ # banks 1 to 3, in a keyed snapshot module.
38
+ def save_fields(out)
39
+ low = @banks.index(@low_ram).to_i
40
+ video = @banks.index(@video_ram).to_i
41
+ out.int("d100", low | (video << 2) | (@banks.index(@high_ram).to_i << 6)).bool("locked", @locked)
42
+ @banks[1].save_fields(out, "bank1")
43
+ @banks[2].save_fields(out, "bank2")
44
+ @banks[3].save_fields(out, "bank3")
45
+ end
46
+
47
+ def load_fields(input)
48
+ value = input.byte("d100", 0)
49
+ @low_ram = @banks[value & 0b11]
50
+ @video_ram = @banks[(value >> 2) & 0b11]
51
+ @high_ram = @banks[value >> 6]
52
+ @locked = input.bool("locked", @locked)
53
+ @banks[1].load_fields(input, "bank1")
54
+ @banks[2].load_fields(input, "bank2")
55
+ @banks[3].load_fields(input, "bank3")
56
+ end
57
+
58
+ def power_on!
59
+ @banks.drop(1).each(&:clear!)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ module BankedRAM
6
+ # The +60K: a second bank of RAM behind $1000-$FFFF, selected by bit 7
7
+ # of $D100. $0000-$0FFF stays the machine's own RAM, and so does all of
8
+ # what the VIC sees.
9
+ class Plus60k
10
+ include Banking
11
+
12
+ def initialize(ram)
13
+ @low_ram = @video_ram = @high_ram = ram
14
+ @banks = [ram, Memory.new]
15
+ @on_change = nil
16
+ end
17
+
18
+ def poke(_addr, value)
19
+ @high_ram = @banks[value >> 7]
20
+ @on_change&.call
21
+ end
22
+
23
+ def reset!
24
+ @high_ram = @banks[0]
25
+ end
26
+
27
+ def type = :plus60k
28
+
29
+ # $D100 as bit 7 picks the bank above $1000, and bank 1, in a
30
+ # keyed snapshot module.
31
+ def save_fields(out)
32
+ out.int("d100", @banks.index(@high_ram).to_i << 7)
33
+ @banks[1].save_fields(out, "bank1")
34
+ end
35
+
36
+ def load_fields(input)
37
+ @high_ram = @banks[(input.byte("d100", @banks.index(@high_ram).to_i << 7) >> 7) & 1]
38
+ @banks[1].load_fields(input, "bank1")
39
+ end
40
+
41
+ def power_on!
42
+ @banks[1].clear!
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ module BankedRAM
6
+ # The machine with no expansion fitted: its own RAM everywhere, and
7
+ # $D100 left to the VIC.
8
+ class Unexpanded
9
+ include Banking
10
+
11
+ def initialize(ram)
12
+ @low_ram = @video_ram = @high_ram = ram
13
+ @on_change = nil
14
+ end
15
+
16
+ def type = nil
17
+
18
+ def map_io(_read_pages, _write_pages); end
19
+
20
+ def save_fields(_out); end
21
+
22
+ def load_fields(_input); end
23
+
24
+ def reset!; end
25
+
26
+ def power_on!; end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/c64/banked_ram/banking"
4
+ require "badline/c64/banked_ram/unexpanded"
5
+ require "badline/c64/banked_ram/plus60k"
6
+ require "badline/c64/banked_ram/plus256k"
7
+
8
+ module Badline
9
+ class C64
10
+ # RAM expansions that bank extra memory in under the CPU through a
11
+ # register at $D100, in the VIC's I/O page. Any write to $D100-$D1FF
12
+ # sets the register, which reads back as $FF.
13
+ module BankedRAM
14
+ TYPES = { plus60k: Plus60k, plus256k: Plus256k }.freeze
15
+
16
+ def self.build(type, ram, &)
17
+ expansion = type ? TYPES.fetch(type).new(ram) : Unexpanded.new(ram)
18
+ expansion.on_change(&)
19
+ expansion
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Bus
6
+ # The VICE debug cartridge register, mapped at $D7FF on the C64. It is a
7
+ # VICE facility rather than real hardware, enabled there with -debugcart:
8
+ # writing a byte ends the run with that value as the exit code. The VICE
9
+ # test suites write $00 for success and $ff for failure.
10
+ #
11
+ # Wraps the SID's top mirror page, so every other access falls through.
12
+ class DebugRegister
13
+ ADDRESS = 0xd7ff
14
+
15
+ def initialize(sid, &handler)
16
+ @sid = sid
17
+ @handler = handler
18
+ end
19
+
20
+ def peek(addr)
21
+ @sid.peek(addr)
22
+ end
23
+
24
+ def poke(addr, value)
25
+ return @handler.call(value) if addr == ADDRESS
26
+
27
+ @sid.poke(addr, value)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Bus
6
+ # The second and third SIDs the SID player fits for a tune written for
7
+ # them, each over its 32 bytes of the I/O area (SIDSlots). The SID
8
+ # player's machine has nothing else in I/O 1 and 2, so the rest of a
9
+ # page there reads the open bus.
10
+ module ExtraSIDs
11
+ # Fits a SID at the address it was built at, where it takes its 32
12
+ # bytes over from whatever maps there.
13
+ def add_sid(sid)
14
+ page = sid.start >> 8
15
+ slots = @sid_slots.find { |candidate| candidate.page == page }
16
+ if slots.nil?
17
+ slots = SIDSlots.new(page, @sid, @open_bus)
18
+ @sid_slots << slots
19
+ end
20
+ slots.place(sid)
21
+ update_overlays!
22
+ end
23
+
24
+ private
25
+
26
+ def map_extra_sids
27
+ @sid_slots.each { |slots| @read_pages[slots.page] = @write_pages[slots.page] = slots }
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Bus
6
+ # What a model fits around the chips: its KERNAL, a datasette or none,
7
+ # and the board and case they sit in.
8
+ module Fittings
9
+ # The keywords #fit takes.
10
+ NAMES = %i[kernal datasette board].freeze
11
+
12
+ # The C64's board and case, the PET 64's, whose built-in monitor
13
+ # shows the VIC's output in shades of green, the C64GS's, which has
14
+ # no keyboard, or the MAX Machine's (:max): 2K of RAM, no ROMs, CIA 1
15
+ # alone at $DC00-$DFFF and the cartridge port in Ultimax mode.
16
+ BOARDS = %i[c64 pet64 gs max].freeze
17
+
18
+ attr_reader :board
19
+
20
+ # Fits the KERNAL ROM ROMs::KERNALS names, leaves the cassette port
21
+ # empty unless `datasette`, and puts the chips in the board BOARDS
22
+ # names.
23
+ def fit(kernal: :c64, datasette: true, board: :c64)
24
+ self.kernal = kernal unless kernal == :c64
25
+ @datasette.disconnect! unless datasette
26
+ self.board = board unless board == :c64
27
+ end
28
+
29
+ def board=(name)
30
+ raise ArgumentError, "no board named #{name}" unless BOARDS.include?(name)
31
+
32
+ @board = name
33
+ vic.palette = name == :pet64 ? Chips::VIC::GREEN_PALETTE : Chips::VIC::PALETTE
34
+ keyboard.connected = name != :gs
35
+ update_overlays!
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Bus
6
+ # The 6510's port under port.* in a keyed snapshot module
7
+ # (Snapshot::Keyed, BL-CPU), and the bus once its memories, the port
8
+ # and the cartridge are loaded: the banks the CPU and the VIC see are
9
+ # worked out again.
10
+ module KeyedState
11
+ # The RAM expansion fitted, or an Unexpanded stand-in.
12
+ attr_reader :ram_expansion
13
+
14
+ # Takes the cartridge out of the expansion port, as a restore does for
15
+ # a snapshot without one.
16
+ def detach_cartridge
17
+ @cartridge = nil
18
+ update_overlays!
19
+ end
20
+
21
+ # The 6510 port's direction and output registers, and the charge left
22
+ # on its floating bits.
23
+ def port_state = [@cpu_port.ddr, @cpu_port.data, @cpu_port.floating]
24
+
25
+ # Sets the port as port_state reads it, as a snapshot restores it,
26
+ # leaving the RAM under $00 and $01 alone.
27
+ def restore_port(ddr, out, floating)
28
+ @cpu_port.restore(ddr, out, floating)
29
+ end
30
+
31
+ def save_port_fields(out) = @cpu_port.save_fields(out, "port.")
32
+
33
+ def load_port_fields(input) = @cpu_port.load_fields(input, "port.")
34
+
35
+ def restored! = update_overlays!
36
+ end
37
+
38
+ include KeyedState
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Bus
6
+ # The C64's PLA: what each page of the CPU's view maps to, from the
7
+ # CPU port's LORAM, HIRAM and CHAREN lines and the cartridge's EXROM
8
+ # and GAME. The bus that includes it supplies the page tables, the
9
+ # ROMs, the chips, #map_ram_pages, which lays out the RAM that the
10
+ # ROMs, the cartridge and I/O map over, and #map_io_pages, which lays
11
+ # out the chips at $D000-$DFFF, with #map_cartridge_io for I/O 1 and 2.
12
+ module PLA
13
+ # A chip's registers seen at another page, which reads and writes
14
+ # them as at the page the chip starts at.
15
+ class Mirror
16
+ def initialize(chip, start)
17
+ @chip = chip
18
+ @start = start
19
+ end
20
+
21
+ def peek(addr) = @chip.peek(@start | (addr & 0xff))
22
+ def poke(addr, value) = @chip.poke(@start | (addr & 0xff), value)
23
+ end
24
+
25
+ private
26
+
27
+ def map_pla_pages
28
+ map_ram_pages
29
+ @ultimax ? map_ultimax_pages : map_banked_pages
30
+ end
31
+
32
+ def map_banked_pages
33
+ map_rom_overlays
34
+ map_cartridge_ram
35
+ @write_pages.fill(@cartridge.romh_writes, 0xe0, 0x20) if @cartridge&.romh_writes
36
+
37
+ if io?
38
+ map_io_pages
39
+ elsif character?
40
+ @read_pages.fill(character_rom, 0xd0, 0x10)
41
+ end
42
+ end
43
+
44
+ # Ultimax mode ignores the $01 lines: 4K of RAM, ROML/ROMH windows,
45
+ # I/O always visible and open address space everywhere else. The ROML
46
+ # and ROMH selects fire on writes as well, so cartridge RAM or flash in
47
+ # either window takes the writes there. The MAX has 2K of RAM, and is
48
+ # in Ultimax mode with no cartridge too.
49
+ def map_ultimax_pages
50
+ first = @board == :max ? 0x08 : 0x10
51
+ @read_pages.fill(@open_bus, first, 0x100 - first)
52
+ @write_pages.fill(@open_bus, first, 0x100 - first)
53
+ map_ultimax_cartridge if @cartridge
54
+ map_io_pages
55
+ map_max_io if @board == :max
56
+ end
57
+
58
+ def map_ultimax_cartridge
59
+ @read_pages.fill(@cartridge.roml, 0x80, 0x20) if @cartridge.roml
60
+ map_ultimax_writes(@cartridge.roml, 0x80)
61
+ @read_pages.fill(@cartridge.romh, 0xe0, 0x20) if @cartridge.romh
62
+ map_ultimax_writes(@cartridge.romh, 0xe0)
63
+ map_ultimax_a000
64
+ end
65
+
66
+ def map_ultimax_writes(bank, first_page)
67
+ @write_pages.fill(bank, first_page, 0x20) if bank.respond_to?(:poke)
68
+ end
69
+
70
+ def map_ultimax_a000
71
+ return unless (window = @cartridge.ultimax_a000)
72
+
73
+ @read_pages.fill(window, 0xa0, 0x20)
74
+ @write_pages.fill(window, 0xa0, 0x20)
75
+ end
76
+
77
+ # The MAX has no CIA 2 and no I/O 2: CIA 1 answers all through
78
+ # $DC00-$DFFF, but for the I/O 1 page a cartridge takes.
79
+ def map_max_io
80
+ @cia1_mirror ||= Mirror.new(cia1, 0xdc00)
81
+ (0xdd..0xdf).each { |page| @read_pages[page] = @write_pages[page] = @cia1_mirror }
82
+ return unless @cartridge
83
+
84
+ @write_pages[0xde] = @cartridge
85
+ @read_pages[0xde] = @cartridge if @cartridge.readable_io_pages.include?(0xde)
86
+ end
87
+
88
+ # EXROM and GAME select the cartridge whether or not it has a chip
89
+ # there, and an empty socket leaves the bus floating.
90
+ def map_rom_overlays
91
+ @read_pages.fill(@cartridge.roml || @open_bus, 0x80, 0x20) if roml?
92
+ if romh?
93
+ @read_pages.fill(@cartridge.romh || @open_bus, 0xa0, 0x20)
94
+ elsif basic?
95
+ @read_pages.fill(basic_rom, 0xa0, 0x20)
96
+ end
97
+ @read_pages.fill(kernal_rom, 0xe0, 0x20) if kernal?
98
+ end
99
+
100
+ # Cartridge RAM in the ROML or ROMH window decodes writes itself,
101
+ # whatever the $01 lines say.
102
+ def map_cartridge_ram
103
+ return unless @cartridge&.exrom&.zero?
104
+
105
+ map_cartridge_ram_bank(@cartridge.roml, 0x80)
106
+ map_cartridge_ram_bank(@cartridge.romh, 0xa0) if @cartridge.game.zero?
107
+ end
108
+
109
+ def map_cartridge_ram_bank(bank, first_page)
110
+ @write_pages.fill(bank, first_page, 0x20) if bank.is_a?(Cartridge::RAMBank)
111
+ end
112
+
113
+ def map_cartridge_io
114
+ @write_pages.fill(@cartridge, 0xde, 2)
115
+ @cartridge.readable_io_pages.each { |p| @read_pages[p] = @cartridge }
116
+ end
117
+
118
+ def basic?
119
+ io_port.kernal? && io_port.basic? && game_high?
120
+ end
121
+
122
+ def game_high?
123
+ @cartridge.nil? || @cartridge.game == 1
124
+ end
125
+
126
+ def roml?
127
+ @cartridge&.exrom&.zero? && io_port.kernal? && io_port.basic?
128
+ end
129
+
130
+ def romh?
131
+ @cartridge&.exrom&.zero? && @cartridge.game.zero? && io_port.kernal?
132
+ end
133
+
134
+ # In 16K mode LORAM alone leaves $d000 as RAM, where it still maps I/O.
135
+ def character?
136
+ (io_port.kernal? || (io_port.basic? && game_high?)) && !io_port.io?
137
+ end
138
+
139
+ def io?
140
+ (io_port.basic? || io_port.kernal?) && io_port.io?
141
+ end
142
+
143
+ def kernal?
144
+ io_port.kernal?
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Bus
6
+ # The BASIC, character and KERNAL ROMs, and which KERNAL is fitted.
7
+ module ROMs
8
+ # The KERNAL ROMs a machine can be fitted with, by name: the C64's,
9
+ # the SX-64's, the PET 64's and the C64GS's. The C64GS's is a 16K
10
+ # image of its BASIC and its KERNAL, and fits both.
11
+ KERNALS = {
12
+ c64: "kernal.rom", sx64: "kernal-sx64.rom", pet64: "kernal-pet64.rom", gs: "c64gs.rom"
13
+ }.freeze
14
+
15
+ attr_reader :basic_rom, :character_rom, :kernal_rom, :kernal
16
+
17
+ # Fits the KERNAL ROM KERNALS names `name`, in place of the one before,
18
+ # with the BASIC of a 16K image or else the C64's.
19
+ def kernal=(name)
20
+ raise ArgumentError, "no KERNAL named #{name}" unless KERNALS.key?(name)
21
+
22
+ @kernal = name
23
+ data = ROM.read(KERNALS[name])
24
+ basic = data.length == 0x4000 ? data[0, 0x2000] : ROM.read("basic.rom")
25
+ @basic_rom = ROM.new(basic, length: 0x2000, start: 0xa000)
26
+ @kernal_rom = ROM.new(data[-0x2000, 0x2000], length: 0x2000, start: 0xe000)
27
+ update_overlays!
28
+ end
29
+
30
+ private
31
+
32
+ def load_roms
33
+ @basic_rom = ROM.load("basic.rom", 0xa000)
34
+ @character_rom = ROM.load("character.rom", 0xd000)
35
+ @kernal = :c64
36
+ @kernal_rom = ROM.load(KERNALS[:c64], 0xe000)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end