badline 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (516) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/CLAUDE.md +59 -31
  4. data/README.md +1 -1
  5. data/doc/library.md +9 -9
  6. data/doc/pinned-behaviour.md +105 -105
  7. data/doc/snapshots.md +1 -4
  8. data/lib/badline/audio/bare_player.rb +4 -4
  9. data/lib/badline/audio/cli.rb +6 -6
  10. data/lib/badline/audio/jukebox.rb +2 -2
  11. data/lib/badline/audio/machine_player.rb +2 -2
  12. data/lib/badline/{media → audio}/queue.rb +1 -1
  13. data/lib/badline/audio/queued_tune.rb +6 -6
  14. data/lib/badline/audio/renderer.rb +5 -5
  15. data/lib/badline/audio/stereo.rb +1 -1
  16. data/lib/badline/c128/{bus_state.rb → bus/saved_state.rb} +6 -6
  17. data/lib/badline/c128/bus.rb +30 -51
  18. data/lib/badline/c128/color_lines.rb +2 -2
  19. data/lib/badline/c128/cpu.rb +1 -1
  20. data/lib/badline/c128/drives.rb +10 -11
  21. data/lib/badline/c128/fast_serial.rb +5 -5
  22. data/lib/badline/c128/mmu_pages.rb +1 -1
  23. data/lib/badline/c128/modes.rb +2 -2
  24. data/lib/badline/c128/saved_state.rb +21 -47
  25. data/lib/badline/c128/z80.rb +2 -2
  26. data/lib/badline/c128.rb +18 -72
  27. data/lib/badline/{computer → c64}/attachments.rb +16 -47
  28. data/lib/badline/c64/banked_ram/banking.rb +32 -0
  29. data/lib/badline/c64/banked_ram/plus256k.rb +56 -0
  30. data/lib/badline/c64/banked_ram/plus60k.rb +45 -0
  31. data/lib/badline/c64/banked_ram/unexpanded.rb +30 -0
  32. data/lib/badline/c64/banked_ram.rb +23 -0
  33. data/lib/badline/c64/bus/extra_sids.rb +32 -0
  34. data/lib/badline/c64/bus/fittings.rb +40 -0
  35. data/lib/badline/c64/bus/pla.rb +149 -0
  36. data/lib/badline/c64/bus/roms.rb +41 -0
  37. data/lib/badline/c64/bus/saved_state.rb +68 -0
  38. data/lib/badline/c64/bus/sid_slots.rb +44 -0
  39. data/lib/badline/c64/bus.rb +218 -0
  40. data/lib/badline/c64/cartridge/action_replay.rb +128 -0
  41. data/lib/badline/c64/cartridge/atomic_power.rb +26 -0
  42. data/lib/badline/c64/cartridge/bank.rb +83 -0
  43. data/lib/badline/c64/cartridge/comal80.rb +52 -0
  44. data/lib/badline/c64/cartridge/dinamic.rb +36 -0
  45. data/lib/badline/c64/cartridge/easy_flash.rb +147 -0
  46. data/lib/badline/c64/cartridge/epyx_fastload.rb +81 -0
  47. data/lib/badline/c64/cartridge/final_cartridge3.rb +91 -0
  48. data/lib/badline/c64/cartridge/flash/saved_state.rb +40 -0
  49. data/lib/badline/c64/cartridge/flash.rb +279 -0
  50. data/lib/badline/c64/cartridge/freezer.rb +35 -0
  51. data/lib/badline/c64/cartridge/fun_play.rb +40 -0
  52. data/lib/badline/c64/cartridge/g_mod2.rb +76 -0
  53. data/lib/badline/c64/cartridge/game_system.rb +42 -0
  54. data/lib/badline/c64/cartridge/geo_ram.rb +81 -0
  55. data/lib/badline/c64/cartridge/kcs_power.rb +77 -0
  56. data/lib/badline/c64/cartridge/mach5.rb +34 -0
  57. data/lib/badline/c64/cartridge/magic_desk.rb +32 -0
  58. data/lib/badline/c64/cartridge/ocean.rb +37 -0
  59. data/lib/badline/c64/cartridge/pagefox.rb +70 -0
  60. data/lib/badline/c64/cartridge/retro_replay/saved_state.rb +47 -0
  61. data/lib/badline/c64/cartridge/retro_replay.rb +286 -0
  62. data/lib/badline/c64/cartridge/rex_utility.rb +31 -0
  63. data/lib/badline/c64/cartridge/rgcd.rb +60 -0
  64. data/lib/badline/c64/cartridge/saved_state.rb +63 -0
  65. data/lib/badline/c64/cartridge/simons_basic.rb +37 -0
  66. data/lib/badline/c64/cartridge/standard.rb +17 -0
  67. data/lib/badline/c64/cartridge/super_games.rb +50 -0
  68. data/lib/badline/c64/cartridge/westermann.rb +32 -0
  69. data/lib/badline/c64/cartridge/zaxxon.rb +68 -0
  70. data/lib/badline/c64/cartridge.rb +258 -0
  71. data/lib/badline/c64/color_memory.rb +27 -0
  72. data/lib/badline/c64/common.rb +34 -0
  73. data/lib/badline/c64/kernal_traps.rb +89 -0
  74. data/lib/badline/c64/reu/dma/saved_state.rb +52 -0
  75. data/lib/badline/c64/reu/dma.rb +275 -0
  76. data/lib/badline/c64/reu/ram.rb +109 -0
  77. data/lib/badline/c64/reu/saved_state.rb +55 -0
  78. data/lib/badline/c64/reu/trigger.rb +34 -0
  79. data/lib/badline/c64/reu.rb +291 -0
  80. data/lib/badline/{computer → c64}/saved_state.rb +13 -18
  81. data/lib/badline/{computer → c64}/true_drives.rb +20 -31
  82. data/lib/badline/{computer.rb → c64.rb} +22 -80
  83. data/lib/badline/chips/cia/fast_forward.rb +62 -0
  84. data/lib/badline/chips/cia/interrupt_register.rb +145 -0
  85. data/lib/badline/chips/cia/saved_state.rb +49 -0
  86. data/lib/badline/chips/cia/serial/saved_state.rb +45 -0
  87. data/lib/badline/chips/cia/serial.rb +250 -0
  88. data/lib/badline/chips/cia/time_of_day.rb +232 -0
  89. data/lib/badline/chips/cia/timer.rb +208 -0
  90. data/lib/badline/chips/cia.rb +281 -0
  91. data/lib/badline/chips/cpu/addressing.rb +133 -0
  92. data/lib/badline/chips/cpu/boundary.rb +56 -0
  93. data/lib/badline/chips/cpu/core.rb +167 -0
  94. data/lib/badline/chips/cpu/instruction.rb +338 -0
  95. data/lib/badline/chips/cpu/instruction_set/arithmetic.rb +118 -0
  96. data/lib/badline/chips/cpu/instruction_set/bitwise.rb +130 -0
  97. data/lib/badline/chips/cpu/instruction_set/branch.rb +83 -0
  98. data/lib/badline/chips/cpu/instruction_set/flag.rb +67 -0
  99. data/lib/badline/chips/cpu/instruction_set/illegal.rb +274 -0
  100. data/lib/badline/chips/cpu/instruction_set/inc_dec.rb +73 -0
  101. data/lib/badline/chips/cpu/instruction_set/stack.rb +56 -0
  102. data/lib/badline/chips/cpu/instruction_set/transfer.rb +141 -0
  103. data/lib/badline/chips/cpu/instruction_set.rb +59 -0
  104. data/lib/badline/chips/cpu/interrupts.rb +108 -0
  105. data/lib/badline/chips/cpu/microcode.rb +179 -0
  106. data/lib/badline/chips/cpu/operations.rb +90 -0
  107. data/lib/badline/chips/cpu/port.rb +116 -0
  108. data/lib/badline/chips/cpu/saved_state.rb +117 -0
  109. data/lib/badline/chips/cpu/stack_operations.rb +84 -0
  110. data/lib/badline/chips/cpu/traps.rb +23 -0
  111. data/lib/badline/chips/cpu.rb +12 -0
  112. data/lib/badline/chips/sid/catch_up.rb +122 -0
  113. data/lib/badline/chips/sid/decimator.rb +66 -0
  114. data/lib/badline/chips/sid/envelope/saved_state.rb +70 -0
  115. data/lib/badline/chips/sid/envelope.rb +241 -0
  116. data/lib/badline/chips/sid/filter/saved_state.rb +42 -0
  117. data/lib/badline/chips/sid/filter.rb +241 -0
  118. data/lib/badline/chips/sid/saved_state.rb +52 -0
  119. data/lib/badline/chips/sid/voice.rb +79 -0
  120. data/lib/badline/chips/sid/waveform/combined.rb +128 -0
  121. data/lib/badline/chips/sid/waveform/fast_forward.rb +107 -0
  122. data/lib/badline/chips/sid/waveform/noise_writeback.rb +124 -0
  123. data/lib/badline/chips/sid/waveform/saved_state.rb +68 -0
  124. data/lib/badline/chips/sid/waveform.rb +307 -0
  125. data/lib/badline/chips/sid.rb +265 -0
  126. data/lib/badline/{c128 → chips}/vdc/memory.rb +1 -1
  127. data/lib/badline/{c128 → chips}/vdc/painter.rb +1 -1
  128. data/lib/badline/{c128 → chips}/vdc/raster.rb +1 -1
  129. data/lib/badline/chips/vdc/saved_state.rb +36 -0
  130. data/lib/badline/{c128 → chips}/vdc/window.rb +1 -1
  131. data/lib/badline/{c128 → chips}/vdc.rb +7 -31
  132. data/lib/badline/chips/via/control_lines.rb +124 -0
  133. data/lib/badline/chips/via/fast_forward.rb +55 -0
  134. data/lib/badline/chips/via/interrupt_register.rb +69 -0
  135. data/lib/badline/chips/via/saved_state.rb +44 -0
  136. data/lib/badline/chips/via/shift_register.rb +182 -0
  137. data/lib/badline/chips/via/timer1.rb +133 -0
  138. data/lib/badline/chips/via/timer2.rb +135 -0
  139. data/lib/badline/chips/via.rb +268 -0
  140. data/lib/badline/chips/vic/bank.rb +135 -0
  141. data/lib/badline/chips/vic/border_mask.rb +88 -0
  142. data/lib/badline/chips/vic/collisions.rb +117 -0
  143. data/lib/badline/chips/vic/color_patches.rb +49 -0
  144. data/lib/badline/chips/vic/display_state.rb +187 -0
  145. data/lib/badline/chips/vic/graphics_mode.rb +166 -0
  146. data/lib/badline/chips/vic/graphics_shifter/saved_state.rb +40 -0
  147. data/lib/badline/chips/vic/graphics_shifter.rb +187 -0
  148. data/lib/badline/chips/vic/register_log.rb +83 -0
  149. data/lib/badline/chips/vic/registers.rb +197 -0
  150. data/lib/badline/chips/vic/saved_state.rb +82 -0
  151. data/lib/badline/chips/vic/sequencer/saved_state.rb +91 -0
  152. data/lib/badline/chips/vic/sequencer.rb +277 -0
  153. data/lib/badline/chips/vic/sequencer_output.rb +118 -0
  154. data/lib/badline/chips/vic/sprite/internal_bus.rb +70 -0
  155. data/lib/badline/chips/vic/sprite/saved_state.rb +66 -0
  156. data/lib/badline/chips/vic/sprite/shifter.rb +148 -0
  157. data/lib/badline/chips/vic/sprite/timing.rb +58 -0
  158. data/lib/badline/chips/vic/sprite.rb +339 -0
  159. data/lib/badline/chips/vic/sprites/saved_state.rb +59 -0
  160. data/lib/badline/chips/vic/sprites.rb +284 -0
  161. data/lib/badline/chips/vic.rb +783 -0
  162. data/lib/badline/chips/vic_i/painter/saved_state.rb +40 -0
  163. data/lib/badline/{vic20/vic → chips/vic_i}/painter.rb +6 -30
  164. data/lib/badline/{vic20/vic → chips/vic_i}/saved_state.rb +2 -2
  165. data/lib/badline/chips/vic_i/sound/output.rb +85 -0
  166. data/lib/badline/chips/vic_i/sound.rb +235 -0
  167. data/lib/badline/{vic20/vic → chips/vic_i}/text_window.rb +2 -2
  168. data/lib/badline/{vic20/vic.rb → chips/vic_i.rb} +5 -5
  169. data/lib/badline/chips/z80/arithmetic.rb +119 -0
  170. data/lib/badline/chips/z80/bit_page.rb +57 -0
  171. data/lib/badline/chips/z80/block_io.rb +60 -0
  172. data/lib/badline/chips/z80/block_transfers.rb +61 -0
  173. data/lib/badline/chips/z80/bus_cycles.rb +113 -0
  174. data/lib/badline/chips/z80/core.rb +115 -0
  175. data/lib/badline/chips/z80/exchanges.rb +52 -0
  176. data/lib/badline/chips/z80/extended_page.rb +91 -0
  177. data/lib/badline/chips/z80/flags.rb +39 -0
  178. data/lib/badline/chips/z80/interrupt_acceptance.rb +48 -0
  179. data/lib/badline/chips/z80/jumps.rb +84 -0
  180. data/lib/badline/chips/z80/loads.rb +100 -0
  181. data/lib/badline/chips/z80/main_page.rb +136 -0
  182. data/lib/badline/chips/z80/registers.rb +122 -0
  183. data/lib/badline/chips/z80/saved_state.rb +71 -0
  184. data/lib/badline/chips/z80/shifts.rb +66 -0
  185. data/lib/badline/chips/z80.rb +13 -0
  186. data/lib/badline/core.rb +27 -29
  187. data/lib/badline/drives/datasette/saved_state.rb +37 -0
  188. data/lib/badline/drives/datasette.rb +140 -0
  189. data/lib/badline/drives/engine/core.rb +149 -0
  190. data/lib/badline/drives/engine/fast_serial.rb +75 -0
  191. data/lib/badline/drives/engine/idle.rb +127 -0
  192. data/lib/badline/drives/engine/idle_cpu.rb +30 -0
  193. data/lib/badline/drives/engine/orbit.rb +81 -0
  194. data/lib/badline/drives/engine/serial_lines.rb +75 -0
  195. data/lib/badline/drives/engine/sleep.rb +114 -0
  196. data/lib/badline/drives/engine/vias.rb +86 -0
  197. data/lib/badline/drives/engine/watch.rb +152 -0
  198. data/lib/badline/drives/engine.rb +11 -0
  199. data/lib/badline/drives/model1541/bus.rb +88 -0
  200. data/lib/badline/drives/model1541/byte_ready.rb +50 -0
  201. data/lib/badline/drives/model1541/cpu.rb +13 -0
  202. data/lib/badline/drives/model1541/disk/saved_state.rb +88 -0
  203. data/lib/badline/drives/model1541/disk.rb +317 -0
  204. data/lib/badline/drives/model1541/disk_via.rb +38 -0
  205. data/lib/badline/drives/model1541/gcr.rb +59 -0
  206. data/lib/badline/drives/model1541/mechanism/saved_state.rb +72 -0
  207. data/lib/badline/drives/model1541/mechanism.rb +315 -0
  208. data/lib/badline/drives/model1541/rotation.rb +123 -0
  209. data/lib/badline/drives/model1541/saved_state.rb +44 -0
  210. data/lib/badline/drives/model1541/sector_reader.rb +78 -0
  211. data/lib/badline/drives/model1541/serial_port.rb +20 -0
  212. data/lib/badline/drives/model1541/track.rb +100 -0
  213. data/lib/badline/drives/model1541.rb +81 -0
  214. data/lib/badline/drives/model1571/bus.rb +113 -0
  215. data/lib/badline/drives/model1571/cpu.rb +13 -0
  216. data/lib/badline/drives/model1571/saved_state.rb +47 -0
  217. data/lib/badline/drives/model1571/serial_port.rb +39 -0
  218. data/lib/badline/drives/model1571/serial_via.rb +27 -0
  219. data/lib/badline/drives/model1571/wd1770.rb +122 -0
  220. data/lib/badline/drives/model1571.rb +142 -0
  221. data/lib/badline/drives/model1581/bus.rb +139 -0
  222. data/lib/badline/drives/model1581/cpu.rb +13 -0
  223. data/lib/badline/drives/model1581/disk/saved_state.rb +89 -0
  224. data/lib/badline/drives/model1581/disk.rb +137 -0
  225. data/lib/badline/drives/model1581/mechanism.rb +119 -0
  226. data/lib/badline/drives/model1581/saved_state.rb +42 -0
  227. data/lib/badline/drives/model1581/serial_port.rb +54 -0
  228. data/lib/badline/drives/model1581/slot.rb +79 -0
  229. data/lib/badline/drives/model1581/track.rb +102 -0
  230. data/lib/badline/drives/model1581/track_bytes.rb +77 -0
  231. data/lib/badline/drives/model1581/wd1772/registers.rb +91 -0
  232. data/lib/badline/drives/model1581/wd1772/saved_state.rb +68 -0
  233. data/lib/badline/drives/model1581/wd1772/sector_writes.rb +75 -0
  234. data/lib/badline/drives/model1581/wd1772/sectors.rb +152 -0
  235. data/lib/badline/drives/model1581/wd1772/stepping.rb +111 -0
  236. data/lib/badline/drives/model1581/wd1772/tracks.rb +127 -0
  237. data/lib/badline/drives/model1581/wd1772/turn.rb +75 -0
  238. data/lib/badline/drives/model1581/wd1772.rb +218 -0
  239. data/lib/badline/drives/model1581.rb +206 -0
  240. data/lib/badline/drives/serial_bus.rb +161 -0
  241. data/lib/badline/frontend/boot.rb +10 -61
  242. data/lib/badline/frontend/machine_window.rb +3 -1
  243. data/lib/badline/frontend/player/filter_view.rb +1 -1
  244. data/lib/badline/frontend/player/player_controller.rb +2 -2
  245. data/lib/badline/frontend/player/player_screen.rb +1 -0
  246. data/lib/badline/frontend/player/theme.rb +7 -7
  247. data/lib/badline/frontend/timeline.rb +3 -3
  248. data/lib/badline/input/control_ports.rb +78 -0
  249. data/lib/badline/input/joystick.rb +27 -0
  250. data/lib/badline/input/keyboard.rb +114 -0
  251. data/lib/badline/input.rb +3 -0
  252. data/lib/badline/kernal_trap/{drive → dos}/block_commands.rb +1 -1
  253. data/lib/badline/kernal_trap/dos/channel.rb +183 -0
  254. data/lib/badline/kernal_trap/{drive → dos}/channels.rb +1 -1
  255. data/lib/badline/kernal_trap/{drive → dos}/memory.rb +1 -1
  256. data/lib/badline/kernal_trap/{drive → dos}/parameters.rb +1 -1
  257. data/lib/badline/kernal_trap/{drive → dos}/status.rb +1 -1
  258. data/lib/badline/kernal_trap/{drive → dos}/write_file.rb +1 -1
  259. data/lib/badline/kernal_trap/{drive → dos}/writes.rb +1 -1
  260. data/lib/badline/kernal_trap/{drive.rb → dos.rb} +11 -10
  261. data/lib/badline/kernal_trap/{file.rb → file_routine.rb} +1 -1
  262. data/lib/badline/kernal_trap/load.rb +6 -6
  263. data/lib/badline/kernal_trap/save.rb +5 -5
  264. data/lib/badline/kernal_trap/serial.rb +7 -7
  265. data/lib/badline/kernal_trap.rb +2 -3
  266. data/lib/badline/machine/clocking.rb +50 -0
  267. data/lib/badline/machine.rb +63 -7
  268. data/lib/badline/media/boot_disk.rb +2 -2
  269. data/lib/badline/media/disk_list.rb +3 -3
  270. data/lib/badline/media/disk_set.rb +1 -1
  271. data/lib/badline/media/extensions.rb +33 -0
  272. data/lib/badline/media/program.rb +28 -0
  273. data/lib/badline/media/true_drive.rb +4 -3
  274. data/lib/badline/media/tune.rb +35 -0
  275. data/lib/badline/media/vic20_cartridge.rb +1 -7
  276. data/lib/badline/media/vic20_media.rb +38 -80
  277. data/lib/badline/media.rb +84 -81
  278. data/lib/badline/model.rb +1 -1
  279. data/lib/badline/options/event.rb +3 -1
  280. data/lib/badline/roms/README +6 -6
  281. data/lib/badline/sdl.rb +1 -0
  282. data/lib/badline/{storage/sid_file.rb → sid_tune/file.rb} +3 -3
  283. data/lib/badline/{storage → sid_tune}/hvsc.rb +7 -7
  284. data/lib/badline/{storage → sid_tune}/song_lengths.rb +2 -2
  285. data/lib/badline/{storage → sid_tune}/stil/credit.rb +1 -1
  286. data/lib/badline/{storage → sid_tune}/stil.rb +3 -3
  287. data/lib/badline/sid_tune.rb +6 -0
  288. data/lib/badline/snapshot/c128_setup.rb +43 -0
  289. data/lib/badline/snapshot/c64_setup.rb +79 -0
  290. data/lib/badline/snapshot/image.rb +5 -25
  291. data/lib/badline/snapshot/machine_state.rb +10 -2
  292. data/lib/badline/snapshot/setup.rb +22 -66
  293. data/lib/badline/snapshot/state.rb +8 -17
  294. data/lib/badline/snapshot/storage_setup.rb +68 -0
  295. data/lib/badline/snapshot/vic20_setup.rb +37 -0
  296. data/lib/badline/snapshot/vice/c64_mem.rb +1 -1
  297. data/lib/badline/snapshot/vice/restore.rb +1 -1
  298. data/lib/badline/snapshot/vice/reu1764.rb +1 -1
  299. data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
  300. data/lib/badline/snapshot/vice.rb +7 -5
  301. data/lib/badline/snapshot.rb +13 -12
  302. data/lib/badline/storage/d64_image.rb +15 -9
  303. data/lib/badline/storage/d71_image.rb +0 -2
  304. data/lib/badline/storage/d81_image.rb +0 -2
  305. data/lib/badline/storage/disk_image/writing.rb +2 -2
  306. data/lib/badline/storage/disk_image.rb +3 -6
  307. data/lib/badline/storage/g64_image.rb +2 -2
  308. data/lib/badline/storage/host_directory.rb +0 -5
  309. data/lib/badline/storage/t64.rb +2 -8
  310. data/lib/badline/storage/unavailable.rb +1 -1
  311. data/lib/badline/storage.rb +0 -37
  312. data/lib/badline/support/c128_checkpoint.rb +39 -0
  313. data/lib/badline/support/checkpoint.rb +108 -0
  314. data/lib/badline/support/vic20_checkpoint.rb +38 -0
  315. data/lib/badline/support.rb +5 -0
  316. data/lib/badline/version.rb +1 -1
  317. data/lib/badline/vic20/attachments.rb +11 -81
  318. data/lib/badline/vic20/bus/saved_state.rb +35 -0
  319. data/lib/badline/vic20/bus.rb +3 -25
  320. data/lib/badline/vic20/cpu.rb +1 -1
  321. data/lib/badline/vic20/port_wiring.rb +4 -4
  322. data/lib/badline/vic20/saved_state.rb +16 -60
  323. data/lib/badline/vic20/user_via_ports.rb +2 -2
  324. data/lib/badline/vic20.rb +20 -51
  325. metadata +250 -221
  326. data/lib/badline/address_bus/extra_sids.rb +0 -30
  327. data/lib/badline/address_bus/fittings.rb +0 -38
  328. data/lib/badline/address_bus/pla.rb +0 -147
  329. data/lib/badline/address_bus/roms.rb +0 -39
  330. data/lib/badline/address_bus/saved_state.rb +0 -72
  331. data/lib/badline/address_bus/sid_slots.rb +0 -42
  332. data/lib/badline/address_bus.rb +0 -235
  333. data/lib/badline/cartridge/action_replay.rb +0 -126
  334. data/lib/badline/cartridge/atomic_power.rb +0 -24
  335. data/lib/badline/cartridge/bank.rb +0 -81
  336. data/lib/badline/cartridge/comal80.rb +0 -50
  337. data/lib/badline/cartridge/dinamic.rb +0 -34
  338. data/lib/badline/cartridge/easy_flash.rb +0 -145
  339. data/lib/badline/cartridge/epyx_fastload.rb +0 -79
  340. data/lib/badline/cartridge/final_cartridge3.rb +0 -89
  341. data/lib/badline/cartridge/flash.rb +0 -306
  342. data/lib/badline/cartridge/freezer.rb +0 -33
  343. data/lib/badline/cartridge/fun_play.rb +0 -38
  344. data/lib/badline/cartridge/g_mod2.rb +0 -74
  345. data/lib/badline/cartridge/game_system.rb +0 -40
  346. data/lib/badline/cartridge/geo_ram.rb +0 -79
  347. data/lib/badline/cartridge/kcs_power.rb +0 -75
  348. data/lib/badline/cartridge/mach5.rb +0 -32
  349. data/lib/badline/cartridge/magic_desk.rb +0 -30
  350. data/lib/badline/cartridge/ocean.rb +0 -35
  351. data/lib/badline/cartridge/pagefox.rb +0 -68
  352. data/lib/badline/cartridge/retro_replay.rb +0 -320
  353. data/lib/badline/cartridge/rex_utility.rb +0 -29
  354. data/lib/badline/cartridge/rgcd.rb +0 -58
  355. data/lib/badline/cartridge/simons_basic.rb +0 -35
  356. data/lib/badline/cartridge/standard.rb +0 -15
  357. data/lib/badline/cartridge/super_games.rb +0 -48
  358. data/lib/badline/cartridge/westermann.rb +0 -30
  359. data/lib/badline/cartridge/zaxxon.rb +0 -66
  360. data/lib/badline/cartridge.rb +0 -303
  361. data/lib/badline/checkpoint.rb +0 -98
  362. data/lib/badline/cia/fast_forward.rb +0 -60
  363. data/lib/badline/cia/interrupt_register.rb +0 -143
  364. data/lib/badline/cia/serial.rb +0 -275
  365. data/lib/badline/cia/state.rb +0 -47
  366. data/lib/badline/cia/timer.rb +0 -206
  367. data/lib/badline/cia.rb +0 -279
  368. data/lib/badline/color_memory.rb +0 -25
  369. data/lib/badline/computer/kernal_traps.rb +0 -29
  370. data/lib/badline/control_ports.rb +0 -76
  371. data/lib/badline/cpu/addressing.rb +0 -131
  372. data/lib/badline/cpu/boundary.rb +0 -54
  373. data/lib/badline/cpu/core.rb +0 -165
  374. data/lib/badline/cpu/microcode.rb +0 -177
  375. data/lib/badline/cpu/operations.rb +0 -88
  376. data/lib/badline/cpu/saved_state.rb +0 -115
  377. data/lib/badline/cpu/stack_operations.rb +0 -82
  378. data/lib/badline/cpu.rb +0 -10
  379. data/lib/badline/cycleable.rb +0 -38
  380. data/lib/badline/datasette.rb +0 -161
  381. data/lib/badline/drive/core.rb +0 -147
  382. data/lib/badline/drive/fast_serial.rb +0 -73
  383. data/lib/badline/drive/idle.rb +0 -125
  384. data/lib/badline/drive/idle_cpu.rb +0 -28
  385. data/lib/badline/drive/orbit.rb +0 -79
  386. data/lib/badline/drive/serial_lines.rb +0 -73
  387. data/lib/badline/drive/sleep.rb +0 -112
  388. data/lib/badline/drive/vias.rb +0 -84
  389. data/lib/badline/drive/watch.rb +0 -150
  390. data/lib/badline/drive.rb +0 -11
  391. data/lib/badline/drive1541/bus.rb +0 -86
  392. data/lib/badline/drive1541/byte_ready.rb +0 -48
  393. data/lib/badline/drive1541/cpu.rb +0 -11
  394. data/lib/badline/drive1541/disk.rb +0 -318
  395. data/lib/badline/drive1541/disk_state.rb +0 -94
  396. data/lib/badline/drive1541/disk_via.rb +0 -36
  397. data/lib/badline/drive1541/gcr.rb +0 -57
  398. data/lib/badline/drive1541/mechanism.rb +0 -313
  399. data/lib/badline/drive1541/mechanism_state.rb +0 -68
  400. data/lib/badline/drive1541/rotation.rb +0 -121
  401. data/lib/badline/drive1541/sector_reader.rb +0 -76
  402. data/lib/badline/drive1541/serial_port.rb +0 -18
  403. data/lib/badline/drive1541/track.rb +0 -98
  404. data/lib/badline/drive1541.rb +0 -111
  405. data/lib/badline/drive1571/bus.rb +0 -111
  406. data/lib/badline/drive1571/cpu.rb +0 -11
  407. data/lib/badline/drive1571/serial_port.rb +0 -37
  408. data/lib/badline/drive1571/serial_via.rb +0 -25
  409. data/lib/badline/drive1571/wd1770.rb +0 -120
  410. data/lib/badline/drive1571.rb +0 -175
  411. data/lib/badline/drive1581/bus.rb +0 -137
  412. data/lib/badline/drive1581/cpu.rb +0 -11
  413. data/lib/badline/drive1581/disk.rb +0 -135
  414. data/lib/badline/drive1581/disk_state.rb +0 -87
  415. data/lib/badline/drive1581/mechanism.rb +0 -117
  416. data/lib/badline/drive1581/serial_port.rb +0 -52
  417. data/lib/badline/drive1581/slot.rb +0 -78
  418. data/lib/badline/drive1581/track.rb +0 -100
  419. data/lib/badline/drive1581/track_bytes.rb +0 -75
  420. data/lib/badline/drive1581/wd1772/registers.rb +0 -89
  421. data/lib/badline/drive1581/wd1772/sector_writes.rb +0 -73
  422. data/lib/badline/drive1581/wd1772/sectors.rb +0 -150
  423. data/lib/badline/drive1581/wd1772/state.rb +0 -66
  424. data/lib/badline/drive1581/wd1772/stepping.rb +0 -109
  425. data/lib/badline/drive1581/wd1772/tracks.rb +0 -125
  426. data/lib/badline/drive1581/wd1772/turn.rb +0 -73
  427. data/lib/badline/drive1581/wd1772.rb +0 -216
  428. data/lib/badline/drive1581.rb +0 -233
  429. data/lib/badline/iec_bus.rb +0 -159
  430. data/lib/badline/instruction.rb +0 -334
  431. data/lib/badline/instruction_set/arithmetic.rb +0 -114
  432. data/lib/badline/instruction_set/bitwise.rb +0 -126
  433. data/lib/badline/instruction_set/branch.rb +0 -79
  434. data/lib/badline/instruction_set/flag.rb +0 -63
  435. data/lib/badline/instruction_set/illegal.rb +0 -270
  436. data/lib/badline/instruction_set/inc_dec.rb +0 -69
  437. data/lib/badline/instruction_set/stack.rb +0 -52
  438. data/lib/badline/instruction_set/transfer.rb +0 -137
  439. data/lib/badline/instruction_set.rb +0 -55
  440. data/lib/badline/interrupts.rb +0 -104
  441. data/lib/badline/joystick.rb +0 -25
  442. data/lib/badline/kernal_trap/channel.rb +0 -181
  443. data/lib/badline/keyboard.rb +0 -112
  444. data/lib/badline/ram_expansion/banking.rb +0 -30
  445. data/lib/badline/ram_expansion/plus256k.rb +0 -54
  446. data/lib/badline/ram_expansion/plus60k.rb +0 -43
  447. data/lib/badline/ram_expansion/unexpanded.rb +0 -28
  448. data/lib/badline/ram_expansion.rb +0 -21
  449. data/lib/badline/reu/dma/saved_state.rb +0 -50
  450. data/lib/badline/reu/dma.rb +0 -273
  451. data/lib/badline/reu/ram.rb +0 -107
  452. data/lib/badline/reu/saved_state.rb +0 -80
  453. data/lib/badline/reu/trigger.rb +0 -32
  454. data/lib/badline/reu.rb +0 -289
  455. data/lib/badline/sid/catch_up.rb +0 -120
  456. data/lib/badline/sid/decimator.rb +0 -64
  457. data/lib/badline/sid/envelope/state.rb +0 -68
  458. data/lib/badline/sid/envelope.rb +0 -239
  459. data/lib/badline/sid/filter.rb +0 -263
  460. data/lib/badline/sid/voice.rb +0 -77
  461. data/lib/badline/sid/waveform/combined.rb +0 -126
  462. data/lib/badline/sid/waveform/fast_forward.rb +0 -105
  463. data/lib/badline/sid/waveform/noise_writeback.rb +0 -122
  464. data/lib/badline/sid/waveform/state.rb +0 -66
  465. data/lib/badline/sid/waveform.rb +0 -305
  466. data/lib/badline/sid.rb +0 -303
  467. data/lib/badline/time_of_day.rb +0 -228
  468. data/lib/badline/traps.rb +0 -19
  469. data/lib/badline/via/control_lines.rb +0 -122
  470. data/lib/badline/via/fast_forward.rb +0 -53
  471. data/lib/badline/via/interrupt_register.rb +0 -67
  472. data/lib/badline/via/shift_register.rb +0 -180
  473. data/lib/badline/via/state.rb +0 -42
  474. data/lib/badline/via/timer1.rb +0 -131
  475. data/lib/badline/via/timer2.rb +0 -133
  476. data/lib/badline/via.rb +0 -266
  477. data/lib/badline/vic/bank.rb +0 -133
  478. data/lib/badline/vic/border_mask.rb +0 -86
  479. data/lib/badline/vic/collisions.rb +0 -115
  480. data/lib/badline/vic/color_patches.rb +0 -47
  481. data/lib/badline/vic/display_state.rb +0 -185
  482. data/lib/badline/vic/graphics_mode.rb +0 -164
  483. data/lib/badline/vic/graphics_shifter.rb +0 -207
  484. data/lib/badline/vic/register_log.rb +0 -81
  485. data/lib/badline/vic/registers.rb +0 -195
  486. data/lib/badline/vic/sequencer.rb +0 -275
  487. data/lib/badline/vic/sequencer_output.rb +0 -116
  488. data/lib/badline/vic/sequencer_state.rb +0 -89
  489. data/lib/badline/vic/sprite/internal_bus.rb +0 -68
  490. data/lib/badline/vic/sprite/saved_state.rb +0 -64
  491. data/lib/badline/vic/sprite/shifter.rb +0 -146
  492. data/lib/badline/vic/sprite/timing.rb +0 -56
  493. data/lib/badline/vic/sprite.rb +0 -337
  494. data/lib/badline/vic/sprites.rb +0 -282
  495. data/lib/badline/vic/sprites_state.rb +0 -57
  496. data/lib/badline/vic.rb +0 -852
  497. data/lib/badline/vic20/sound/output.rb +0 -83
  498. data/lib/badline/vic20/sound.rb +0 -233
  499. data/lib/badline/z80/arithmetic.rb +0 -117
  500. data/lib/badline/z80/bit_page.rb +0 -55
  501. data/lib/badline/z80/block_io.rb +0 -58
  502. data/lib/badline/z80/block_transfers.rb +0 -59
  503. data/lib/badline/z80/bus_cycles.rb +0 -111
  504. data/lib/badline/z80/core.rb +0 -113
  505. data/lib/badline/z80/exchanges.rb +0 -50
  506. data/lib/badline/z80/extended_page.rb +0 -89
  507. data/lib/badline/z80/flags.rb +0 -37
  508. data/lib/badline/z80/interrupt_acceptance.rb +0 -46
  509. data/lib/badline/z80/jumps.rb +0 -82
  510. data/lib/badline/z80/loads.rb +0 -98
  511. data/lib/badline/z80/main_page.rb +0 -134
  512. data/lib/badline/z80/registers.rb +0 -120
  513. data/lib/badline/z80/saved_state.rb +0 -69
  514. data/lib/badline/z80/shifts.rb +0 -64
  515. data/lib/badline/z80.rb +0 -11
  516. /data/lib/badline/snapshot/{fields.rb → vice/fields.rb} +0 -0
@@ -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
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Bus
6
+ # The bus's state for a snapshot: the CPU port, the RAM, colour RAM and
7
+ # a RAM expansion, the cartridge, the datasette and the chips.
8
+ module SavedState
9
+ # The RAM expansion fitted, or an Unexpanded stand-in.
10
+ attr_reader :ram_expansion
11
+
12
+ # Takes the cartridge out of the expansion port, as a restore does for
13
+ # a state without one.
14
+ def detach_cartridge
15
+ @cartridge = nil
16
+ update_overlays!
17
+ end
18
+
19
+ # The 6510 port's direction and output registers, and the charge left
20
+ # on its floating bits.
21
+ def port_state = [@cpu_port.ddr, @cpu_port.data, @cpu_port.floating]
22
+
23
+ # Sets the port as port_state reads it, as a snapshot restores it,
24
+ # leaving the RAM under $00 and $01 alone.
25
+ def restore_port(ddr, out, floating)
26
+ @cpu_port.restore(ddr, out, floating)
27
+ end
28
+
29
+ # The machine's memory and everything on the bus but the keyboard, the
30
+ # joysticks and the pot devices, which the host holds. A cartridge is
31
+ # already in the port, built from its setup (C64#load_state).
32
+ def save_state(out)
33
+ out.marker("BUS")
34
+ out.int(@cpu_port.ddr).int(@cpu_port.data).int(@cpu_port.floating)
35
+ @ram.save_state(out)
36
+ @color_ram.save_state(out)
37
+ @ram_expansion.save_state(out)
38
+ @cartridge&.save_state(out)
39
+ @datasette.save_state(out)
40
+ @vic.save_state(out)
41
+ @cia1.save_state(out)
42
+ @cia2.save_state(out)
43
+ @sid.save_state(out)
44
+ end
45
+
46
+ def load_state(input)
47
+ input.marker("BUS")
48
+ ddr = input.int
49
+ port_out = input.int
50
+ floating = input.int
51
+ @ram.load_state(input)
52
+ @color_ram.load_state(input)
53
+ @ram_expansion.load_state(input)
54
+ @cartridge&.load_state(input)
55
+ @datasette.load_state(input)
56
+ @cpu_port.load(ddr, port_out, floating)
57
+ update_overlays!
58
+ @vic.load_state(input)
59
+ @cia1.load_state(input)
60
+ @cia2.load_state(input)
61
+ @sid.load_state(input)
62
+ end
63
+ end
64
+
65
+ include SavedState
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Bus
6
+ # Stands in for a page of I/O that a second or third SID shares: each 32
7
+ # bytes of it go to the SID placed there, or else to the first SID's
8
+ # mirrors in `$d400-$d7ff`, and to the open bus in I/O 1 and 2.
9
+ class SIDSlots
10
+ attr_reader :page
11
+
12
+ def initialize(page, first, open_bus)
13
+ @page = page
14
+ @io = page >= 0xde
15
+ @first = first
16
+ @open_bus = open_bus
17
+ @sids = []
18
+ @slots = Array.new(8, -1)
19
+ end
20
+
21
+ def place(sid)
22
+ @slots[(sid.start >> 5) & 7] = @sids.size
23
+ @sids << sid
24
+ end
25
+
26
+ def peek(addr)
27
+ index = @slots[(addr >> 5) & 7]
28
+ return @sids[index].peek(addr) unless index.negative?
29
+
30
+ @io ? @open_bus.peek(addr) : @first.peek(addr)
31
+ end
32
+
33
+ def poke(addr, value)
34
+ index = @slots[(addr >> 5) & 7]
35
+ if !index.negative?
36
+ @sids[index].poke(addr, value)
37
+ elsif !@io
38
+ @first.poke(addr, value)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,218 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/c64/bus/saved_state"
4
+ require "badline/c64/bus/sid_slots"
5
+ require "badline/c64/bus/extra_sids"
6
+ require "badline/c64/bus/pla"
7
+ require "badline/c64/bus/roms"
8
+ require "badline/c64/bus/fittings"
9
+
10
+ module Badline
11
+ # Memory layout:
12
+ #
13
+ # 0x0000-0x00FF - Page 0 - Zeropage
14
+ # 0x0100-0x01FF - Page 1 - Stack
15
+ # 0x0200-0x02FF - Page 2 - OS/BASIC pointers
16
+ # 0x0300-0x03FF - Page 3 - OS/BASIC pointers
17
+ # 0x0400-0x07FF - Page 4-7 - Screen memory
18
+ # 0x0800-0x9FFF - Page 8-159 - BASIC program storage area
19
+ # 0xA000-0xBFFF - Page 160-191 - Machine code program storage (ROM overlay)
20
+ # 0xC000-0xCFFF - Page 192-207 - Machine code program storage
21
+ # 0xD000-0xD3FF - Page 208-211 - VIC II registers
22
+ # 0xD400-0xD7FF - Page 212-215 - SID registers
23
+ # 0xD800-0xDBFF - Page 216-219 - Color memory
24
+ # 0xDC00-0xDCFF - Page 220 - CIA 1
25
+ # 0xDD00-0xDDFF - Page 221 - CIA 2
26
+ # 0xDE00-0xDEFF - Page 222 - I/O 1
27
+ # 0xDF00-0xDFFF - Page 223 - I/O 2
28
+ # 0xE000-0xFFFF - Page 224-255 - Machine code program storage (ROM overlay)
29
+
30
+ class C64
31
+ # Overlays:
32
+ #
33
+ # 0x8000-0x9FFF - Cartridge ROM (low) - 8kb
34
+ # 0xA000-0xBFFF - BASIC ROM / Cartridge ROM (high) - 8kb
35
+ # 0xD000-0xDFFF - Character ROM / I/O - 4kb
36
+ # 0xE000-0xFFFF - KERNAL ROM / Cartridge ROM (high) - 8kb
37
+ class Bus
38
+ include Addressable
39
+ include PLA
40
+ include ExtraSIDs
41
+ include ROMs
42
+ include Fittings
43
+
44
+ # I/O 1 and 2, and the Ultimax holes, with nothing on the bus. A read
45
+ # picks up the byte the VIC fetched in the preceding phi1 half-cycle,
46
+ # and a write goes nowhere.
47
+ class OpenBus
48
+ def initialize(vic)
49
+ @vic = vic
50
+ end
51
+
52
+ def peek(_addr) = @vic.phi1_data
53
+ def poke(_addr, _value); end
54
+ end
55
+
56
+ # The 6510's port pins with pull-ups, and the floating ones (CPU::Port).
57
+ PORT_PULLUPS = 0b0001_0111
58
+ PORT_FLOATING = 0b1100_1000
59
+
60
+ # RAM powers on in runs of $00 $00 $FF $FF $FF $FF $00 $00, inverted in
61
+ # the second and fourth 16K: a C64C (ASSY 250469 R4) from
62
+ # C64/raminitpattern/readme.txt, without its occasional random bytes.
63
+ # See doc/pinned-behaviour.md.
64
+ RAM_POWER_ON = Array.new(2**16) { |addr| (((addr + 2) / 4) ^ (addr / 0x4000)).odd? ? 0xff : 0x00 }.freeze
65
+
66
+ attr_reader :io_port, :ram,
67
+ :vic, :sid, :color_ram, :cia1, :cia2, :keyboard, :joystick1, :joystick2,
68
+ :control_ports, :cartridge, :ultimax, :phi1_ultimax, :datasette, :region, :video_ram, :reu
69
+
70
+ # ram_expansion fits a +60K (:plus60k) or +256K (:plus256k).
71
+ def initialize(sid_model: :mos6581, cia_model: :mos6526, vic_model: :mos6569, region: Region::PAL,
72
+ ram_expansion: nil)
73
+ @region = region
74
+ @board = :c64
75
+ @ram = Memory.new(RAM_POWER_ON, length: 2**16, start: 0)
76
+ @ram_expansion = BankedRAM.build(ram_expansion, @ram) { update_overlays! }
77
+ @cartridge = @reu = nil
78
+ @debug_register = nil
79
+
80
+ load_roms
81
+
82
+ @keyboard = Input::Keyboard.new
83
+ @joystick1 = Input::Joystick.new
84
+ @joystick2 = Input::Joystick.new
85
+ @control_ports = Input::ControlPorts.new(keyboard: @keyboard, joystick1: @joystick1, joystick2: @joystick2)
86
+ @vic = Chips::VIC.new(model: vic_model, region:)
87
+ @cia1 = Chips::CIA.new(start: 0xdc00, peripheral: @control_ports, model: cia_model, region:)
88
+ @cia2 = Chips::CIA.new(start: 0xdd00, model: cia_model, region:)
89
+ @control_ports.port_a_source = @cia1
90
+ @cia1.on_port_b4_change { |high| @vic.lightpen_level(high) }
91
+ @sid = Chips::SID.new(model: sid_model, pots: @control_ports)
92
+ @sid_slots = []
93
+
94
+ @datasette = Drives::Datasette.new
95
+ @datasette.on_flag { @cia1.flag! }
96
+ @datasette.on_sense_change { @cpu_port.refresh }
97
+
98
+ @color_ram = ColorMemory.new(@vic)
99
+ @vic.vic_bank.connect(cia2: @cia2, color_ram: @color_ram)
100
+ @vic.vic_bank.map_character_rom(character_rom)
101
+ @open_bus = OpenBus.new(@vic)
102
+ @cpu_off_bus = false
103
+
104
+ @cpu_port = Chips::CPU::Port.new(@datasette, pullups: PORT_PULLUPS, floating: PORT_FLOATING)
105
+ @cpu_port.on_change { update_overlays! }
106
+ @io_port = @cpu_port.status
107
+
108
+ @read_pages = Array.new(256)
109
+ @write_pages = Array.new(256)
110
+ update_overlays!
111
+ end
112
+
113
+ def attach_cartridge(cartridge)
114
+ @cartridge = cartridge
115
+ cartridge.connect(ram: @ram, open_bus: @open_bus)
116
+ cartridge.on_change { update_overlays! }
117
+ update_overlays!
118
+ end
119
+
120
+ # An REU takes I/O 2 unless a cartridge claims it, and watches writes
121
+ # to $FF00 for the one that starts an armed transfer.
122
+ def attach_reu(reu)
123
+ @reu = reu
124
+ update_overlays!
125
+ end
126
+
127
+ def power_on!
128
+ @ram.clear!(RAM_POWER_ON)
129
+ @ram_expansion.power_on!
130
+ end
131
+
132
+ # The RES line clears the 6510 port's direction and output registers,
133
+ # and a RAM expansion's bank register. The port's floating bits keep
134
+ # their charge.
135
+ def reset!
136
+ @ram_expansion.reset!
137
+ @cpu_port.reset!
138
+ end
139
+
140
+ def disable_overlays!
141
+ poke(0, 0x2f)
142
+ poke(1, 0)
143
+ end
144
+
145
+ def install_debug_register(&)
146
+ @debug_register = DebugRegister.new(@sid, &)
147
+ update_overlays!
148
+ end
149
+
150
+ def peek(addr)
151
+ return @cpu_port.ddr if addr.zero?
152
+ return @io_port.value if addr == 0x01
153
+
154
+ @read_pages[addr >> 8].peek(addr)
155
+ end
156
+
157
+ # A write to $00 or $01 goes to the port, but the RAM below is still
158
+ # write-enabled, and takes whatever is left on the bus: the byte the VIC
159
+ # fetched in the phi1 half of the cycle.
160
+ def poke(addr, value)
161
+ if addr < 0x02
162
+ @ram.poke(addr, @vic.phi1_data)
163
+ addr.zero? ? @cpu_port.write_ddr(value) : @cpu_port.write_data(value)
164
+ elsif !@cpu_off_bus
165
+ @write_pages[addr >> 8].poke(addr, value)
166
+ end
167
+ end
168
+
169
+ # Runs a CPU cycle with the CPU off the bus, as an REU's /DMA line
170
+ # holds it: a write it makes reaches nothing but its own port.
171
+ def cycle_cpu_off_bus(cpu)
172
+ @cpu_off_bus = true
173
+ cpu.cycle!
174
+ @cpu_off_bus = false
175
+ end
176
+
177
+ def inspect
178
+ "#<#{self.class.name} port=#{format('0x%02x', @io_port.value)} " \
179
+ "cartridge=#{@cartridge ? @cartridge.class.name : 'none'} " \
180
+ "ultimax=#{@ultimax}>"
181
+ end
182
+
183
+ private
184
+
185
+ # Banking changes only on $01 writes and cartridge line/bank changes,
186
+ # so reads and writes dispatch through per-page handler tables instead
187
+ # of range checks.
188
+ def update_overlays!
189
+ max = @board == :max
190
+ @ultimax = max || (@cartridge ? @cartridge.ultimax? : false)
191
+ @phi1_ultimax = max || (@cartridge ? @cartridge.phi1_ultimax? : false)
192
+ @video_ram = @ram_expansion.video_ram
193
+ @vic.vic_bank.map(@video_ram, phi1_ultimax: @phi1_ultimax, ultimax: @ultimax, romh: @cartridge&.romh)
194
+
195
+ map_pla_pages
196
+ @write_pages[0xff] = @reu.trigger.wrap(@write_pages[0xff]) if @reu
197
+ end
198
+
199
+ def map_ram_pages
200
+ @ram_expansion.map(@read_pages, @write_pages)
201
+ end
202
+
203
+ def map_io_pages
204
+ {
205
+ vic => 0xd0..0xd3, sid => 0xd4..0xd7, color_ram => 0xd8..0xdb,
206
+ cia1 => 0xdc..0xdc, cia2 => 0xdd..0xdd, @open_bus => 0xde..0xdf
207
+ }.each do |chip, pages|
208
+ pages.each { |p| @read_pages[p] = @write_pages[p] = chip }
209
+ end
210
+ @ram_expansion.map_io(@read_pages, @write_pages)
211
+ @read_pages[0xd7] = @write_pages[0xd7] = @debug_register if @debug_register
212
+ @read_pages[0xdf] = @write_pages[0xdf] = @reu if @reu
213
+ map_cartridge_io if @cartridge
214
+ map_extra_sids unless @sid_slots.empty?
215
+ end
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Cartridge
6
+ # Action Replay v4.2 to v6: four 8K ROM banks and 8K of RAM. A write to
7
+ # I/O 1 sets the control register:
8
+ #
9
+ # bit 0 pulls GAME low
10
+ # bit 1 releases EXROM
11
+ # bit 2 switches the register off until the next freeze or reset
12
+ # bits 3-4 ROM bank
13
+ # bit 5 RAM instead of ROM at ROML and I/O 2
14
+ # bit 6 acknowledges a freeze and lets go of NMI
15
+ #
16
+ # I/O 2 shows the last page of the RAM or of the ROM bank. The register
17
+ # doesn't decode R/W, so a read of I/O 1 writes whatever is on the bus
18
+ # into it. RAM with only EXROM released ($22) selects the cartridge RAM
19
+ # and the C64's together at ROML. A freeze switches the cartridge back
20
+ # on, in Ultimax mode with the RAM at ROML and the first bank at ROMH.
21
+ class ActionReplay < Cartridge
22
+ include Freezer
23
+
24
+ CONTROL_MODES = %i[rom8k rom16k off ultimax].freeze
25
+ IO2_PAGE = 0x1f00
26
+
27
+ def connect(ram:, open_bus:)
28
+ super
29
+ @through.backing = ram
30
+ @contended.backing = ram
31
+ end
32
+
33
+ def readable_io_pages
34
+ [0xde, 0xdf]
35
+ end
36
+
37
+ def peek(addr)
38
+ return open_bus(addr) unless @active
39
+ return io2_peek(addr) if addr >= 0xdf00
40
+
41
+ open_bus(addr).tap { |value| control(value) }
42
+ end
43
+
44
+ def poke(addr, value)
45
+ return unless @active
46
+
47
+ if addr < 0xdf00
48
+ control(value)
49
+ elsif @io2_ram
50
+ @ram_data[IO2_PAGE | (addr & 0xff)] = value
51
+ end
52
+ end
53
+
54
+ def reset
55
+ @active = true
56
+ self.nmi = false
57
+ control(0)
58
+ end
59
+
60
+ def freeze!
61
+ @active = true
62
+ @rom = bank(@rom_banks, 0)
63
+ select(:ultimax, @isolated, io2_ram: true)
64
+ end
65
+
66
+ private
67
+
68
+ def save_mapper(out)
69
+ super
70
+ out.int(window_index(@rom, windows)).boolean(@active).boolean(@io2_ram).blob(@ram_data)
71
+ end
72
+
73
+ def load_mapper(input)
74
+ super
75
+ @rom = window_at(input.int, windows)
76
+ @active = input.boolean?
77
+ @io2_ram = input.boolean?
78
+ input.blob_into(@ram_data)
79
+ end
80
+
81
+ def windows = [@through, @isolated, @contended, *@rom_banks, EMPTY_BANK]
82
+
83
+ def io2_peek(addr)
84
+ @io2_ram ? @ram_data[IO2_PAGE | (addr & 0xff)] : @rom.peek(addr)
85
+ end
86
+
87
+ def control(value)
88
+ self.nmi = false if value.anybits?(0x40)
89
+ @rom = bank(@rom_banks, (value >> 3) & 0x03)
90
+ configure(value)
91
+ @active = false if value.anybits?(0x04)
92
+ end
93
+
94
+ def configure(value)
95
+ return select(:rom8k, @contended, io2_ram: true) if (value & 0x23) == 0x22
96
+
97
+ configure_standard(value)
98
+ end
99
+
100
+ def configure_standard(value)
101
+ mode = CONTROL_MODES[value & 0x03]
102
+ if value.anybits?(0x20)
103
+ select(mode, mode == :ultimax ? @isolated : @through, io2_ram: true)
104
+ else
105
+ select(mode, @rom, io2_ram: false)
106
+ end
107
+ end
108
+
109
+ def select(mode, roml, io2_ram:, romh: @rom)
110
+ self.mode = mode
111
+ @roml = roml
112
+ @romh = romh
113
+ @io2_ram = io2_ram
114
+ changed!
115
+ end
116
+
117
+ def install_chips(chips)
118
+ @rom_banks = banks_from(chips).first
119
+ @ram_data = Array.new(BANK_SIZE, 0)
120
+ @through = RAMBank.new(@ram_data)
121
+ @isolated = RAMBank.new(@ram_data)
122
+ @contended = ContendedRAM.new(@ram_data)
123
+ reset
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Cartridge
6
+ # Atomic Power, sold as Nordic Power: an Action Replay 5 with one more
7
+ # configuration. RAM with only EXROM released and bits 2, 6 and 7 clear
8
+ # ($22) selects 16K mode with the ROM bank at ROML and the RAM at ROMH
9
+ # and I/O 2. Writes to that RAM don't reach the C64's. The VIC never
10
+ # sees Ultimax mode.
11
+ class AtomicPower < ActionReplay
12
+ def phi1_ultimax?
13
+ false
14
+ end
15
+
16
+ private
17
+
18
+ def configure(value)
19
+ return select(:rom16k, @rom, romh: @isolated, io2_ram: true) if (value & 0xe7) == 0x22
20
+
21
+ configure_standard(value)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end