badline 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (505) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -0
  3. data/CLAUDE.md +59 -31
  4. data/README.md +1 -1
  5. data/doc/library.md +9 -9
  6. data/doc/pinned-behaviour.md +105 -105
  7. data/doc/snapshots.md +1 -4
  8. data/lib/badline/audio/bare_player.rb +3 -3
  9. data/lib/badline/audio/cli.rb +6 -6
  10. data/lib/badline/audio/jukebox.rb +2 -2
  11. data/lib/badline/audio/machine_player.rb +2 -2
  12. data/lib/badline/{media → audio}/queue.rb +1 -1
  13. data/lib/badline/audio/queued_tune.rb +6 -6
  14. data/lib/badline/audio/renderer.rb +5 -5
  15. data/lib/badline/audio/stereo.rb +1 -1
  16. data/lib/badline/c128/{bus_state.rb → bus/saved_state.rb} +1 -1
  17. data/lib/badline/c128/bus.rb +18 -17
  18. data/lib/badline/c128/color_lines.rb +2 -2
  19. data/lib/badline/c128/cpu.rb +1 -1
  20. data/lib/badline/c128/drives.rb +10 -11
  21. data/lib/badline/c128/fast_serial.rb +5 -5
  22. data/lib/badline/c128/mmu_pages.rb +1 -1
  23. data/lib/badline/c128/modes.rb +2 -2
  24. data/lib/badline/c128/saved_state.rb +21 -47
  25. data/lib/badline/c128/z80.rb +2 -2
  26. data/lib/badline/c128.rb +14 -9
  27. data/lib/badline/{computer → c64}/attachments.rb +4 -6
  28. data/lib/badline/c64/banked_ram/banking.rb +32 -0
  29. data/lib/badline/c64/banked_ram/plus256k.rb +56 -0
  30. data/lib/badline/c64/banked_ram/plus60k.rb +45 -0
  31. data/lib/badline/c64/banked_ram/unexpanded.rb +30 -0
  32. data/lib/badline/c64/banked_ram.rb +23 -0
  33. data/lib/badline/c64/bus/extra_sids.rb +32 -0
  34. data/lib/badline/c64/bus/fittings.rb +40 -0
  35. data/lib/badline/c64/bus/pla.rb +149 -0
  36. data/lib/badline/c64/bus/roms.rb +41 -0
  37. data/lib/badline/c64/bus/saved_state.rb +68 -0
  38. data/lib/badline/c64/bus/sid_slots.rb +44 -0
  39. data/lib/badline/c64/bus.rb +218 -0
  40. data/lib/badline/c64/cartridge/action_replay.rb +128 -0
  41. data/lib/badline/c64/cartridge/atomic_power.rb +26 -0
  42. data/lib/badline/c64/cartridge/bank.rb +83 -0
  43. data/lib/badline/c64/cartridge/comal80.rb +52 -0
  44. data/lib/badline/c64/cartridge/dinamic.rb +36 -0
  45. data/lib/badline/c64/cartridge/easy_flash.rb +147 -0
  46. data/lib/badline/c64/cartridge/epyx_fastload.rb +81 -0
  47. data/lib/badline/c64/cartridge/final_cartridge3.rb +91 -0
  48. data/lib/badline/c64/cartridge/flash/saved_state.rb +40 -0
  49. data/lib/badline/c64/cartridge/flash.rb +279 -0
  50. data/lib/badline/c64/cartridge/freezer.rb +35 -0
  51. data/lib/badline/c64/cartridge/fun_play.rb +40 -0
  52. data/lib/badline/c64/cartridge/g_mod2.rb +76 -0
  53. data/lib/badline/c64/cartridge/game_system.rb +42 -0
  54. data/lib/badline/c64/cartridge/geo_ram.rb +81 -0
  55. data/lib/badline/c64/cartridge/kcs_power.rb +77 -0
  56. data/lib/badline/c64/cartridge/mach5.rb +34 -0
  57. data/lib/badline/c64/cartridge/magic_desk.rb +32 -0
  58. data/lib/badline/c64/cartridge/ocean.rb +37 -0
  59. data/lib/badline/c64/cartridge/pagefox.rb +70 -0
  60. data/lib/badline/c64/cartridge/retro_replay/saved_state.rb +47 -0
  61. data/lib/badline/c64/cartridge/retro_replay.rb +286 -0
  62. data/lib/badline/c64/cartridge/rex_utility.rb +31 -0
  63. data/lib/badline/c64/cartridge/rgcd.rb +60 -0
  64. data/lib/badline/c64/cartridge/saved_state.rb +63 -0
  65. data/lib/badline/c64/cartridge/simons_basic.rb +37 -0
  66. data/lib/badline/c64/cartridge/standard.rb +17 -0
  67. data/lib/badline/c64/cartridge/super_games.rb +50 -0
  68. data/lib/badline/c64/cartridge/westermann.rb +32 -0
  69. data/lib/badline/c64/cartridge/zaxxon.rb +68 -0
  70. data/lib/badline/c64/cartridge.rb +258 -0
  71. data/lib/badline/c64/color_memory.rb +27 -0
  72. data/lib/badline/{computer → c64}/common.rb +2 -2
  73. data/lib/badline/{computer → c64}/kernal_traps.rb +18 -18
  74. data/lib/badline/c64/reu/dma/saved_state.rb +52 -0
  75. data/lib/badline/c64/reu/dma.rb +275 -0
  76. data/lib/badline/c64/reu/ram.rb +109 -0
  77. data/lib/badline/c64/reu/saved_state.rb +55 -0
  78. data/lib/badline/c64/reu/trigger.rb +34 -0
  79. data/lib/badline/c64/reu.rb +291 -0
  80. data/lib/badline/{computer → c64}/saved_state.rb +13 -18
  81. data/lib/badline/{computer → c64}/true_drives.rb +11 -11
  82. data/lib/badline/{computer.rb → c64.rb} +18 -13
  83. data/lib/badline/chips/cia/fast_forward.rb +62 -0
  84. data/lib/badline/chips/cia/interrupt_register.rb +145 -0
  85. data/lib/badline/chips/cia/saved_state.rb +49 -0
  86. data/lib/badline/chips/cia/serial/saved_state.rb +45 -0
  87. data/lib/badline/chips/cia/serial.rb +250 -0
  88. data/lib/badline/chips/cia/time_of_day.rb +232 -0
  89. data/lib/badline/chips/cia/timer.rb +208 -0
  90. data/lib/badline/chips/cia.rb +281 -0
  91. data/lib/badline/chips/cpu/addressing.rb +133 -0
  92. data/lib/badline/chips/cpu/boundary.rb +56 -0
  93. data/lib/badline/chips/cpu/core.rb +167 -0
  94. data/lib/badline/chips/cpu/instruction.rb +338 -0
  95. data/lib/badline/chips/cpu/instruction_set/arithmetic.rb +118 -0
  96. data/lib/badline/chips/cpu/instruction_set/bitwise.rb +130 -0
  97. data/lib/badline/chips/cpu/instruction_set/branch.rb +83 -0
  98. data/lib/badline/chips/cpu/instruction_set/flag.rb +67 -0
  99. data/lib/badline/chips/cpu/instruction_set/illegal.rb +274 -0
  100. data/lib/badline/chips/cpu/instruction_set/inc_dec.rb +73 -0
  101. data/lib/badline/chips/cpu/instruction_set/stack.rb +56 -0
  102. data/lib/badline/chips/cpu/instruction_set/transfer.rb +141 -0
  103. data/lib/badline/chips/cpu/instruction_set.rb +59 -0
  104. data/lib/badline/chips/cpu/interrupts.rb +108 -0
  105. data/lib/badline/chips/cpu/microcode.rb +179 -0
  106. data/lib/badline/chips/cpu/operations.rb +90 -0
  107. data/lib/badline/chips/cpu/port.rb +116 -0
  108. data/lib/badline/chips/cpu/saved_state.rb +117 -0
  109. data/lib/badline/chips/cpu/stack_operations.rb +84 -0
  110. data/lib/badline/chips/cpu/traps.rb +23 -0
  111. data/lib/badline/chips/cpu.rb +12 -0
  112. data/lib/badline/chips/sid/catch_up.rb +122 -0
  113. data/lib/badline/chips/sid/decimator.rb +66 -0
  114. data/lib/badline/chips/sid/envelope/saved_state.rb +70 -0
  115. data/lib/badline/chips/sid/envelope.rb +241 -0
  116. data/lib/badline/chips/sid/filter/saved_state.rb +42 -0
  117. data/lib/badline/chips/sid/filter.rb +241 -0
  118. data/lib/badline/chips/sid/saved_state.rb +52 -0
  119. data/lib/badline/chips/sid/voice.rb +79 -0
  120. data/lib/badline/chips/sid/waveform/combined.rb +128 -0
  121. data/lib/badline/chips/sid/waveform/fast_forward.rb +107 -0
  122. data/lib/badline/chips/sid/waveform/noise_writeback.rb +124 -0
  123. data/lib/badline/chips/sid/waveform/saved_state.rb +68 -0
  124. data/lib/badline/chips/sid/waveform.rb +307 -0
  125. data/lib/badline/chips/sid.rb +265 -0
  126. data/lib/badline/{c128 → chips}/vdc/memory.rb +1 -1
  127. data/lib/badline/{c128 → chips}/vdc/painter.rb +1 -1
  128. data/lib/badline/{c128 → chips}/vdc/raster.rb +1 -1
  129. data/lib/badline/chips/vdc/saved_state.rb +36 -0
  130. data/lib/badline/{c128 → chips}/vdc/window.rb +1 -1
  131. data/lib/badline/{c128 → chips}/vdc.rb +7 -31
  132. data/lib/badline/chips/via/control_lines.rb +124 -0
  133. data/lib/badline/chips/via/fast_forward.rb +55 -0
  134. data/lib/badline/chips/via/interrupt_register.rb +69 -0
  135. data/lib/badline/chips/via/saved_state.rb +44 -0
  136. data/lib/badline/chips/via/shift_register.rb +182 -0
  137. data/lib/badline/chips/via/timer1.rb +133 -0
  138. data/lib/badline/chips/via/timer2.rb +135 -0
  139. data/lib/badline/chips/via.rb +268 -0
  140. data/lib/badline/chips/vic/bank.rb +135 -0
  141. data/lib/badline/chips/vic/border_mask.rb +88 -0
  142. data/lib/badline/chips/vic/collisions.rb +117 -0
  143. data/lib/badline/chips/vic/color_patches.rb +49 -0
  144. data/lib/badline/chips/vic/display_state.rb +187 -0
  145. data/lib/badline/chips/vic/graphics_mode.rb +166 -0
  146. data/lib/badline/chips/vic/graphics_shifter/saved_state.rb +40 -0
  147. data/lib/badline/chips/vic/graphics_shifter.rb +187 -0
  148. data/lib/badline/chips/vic/register_log.rb +83 -0
  149. data/lib/badline/chips/vic/registers.rb +197 -0
  150. data/lib/badline/chips/vic/saved_state.rb +82 -0
  151. data/lib/badline/chips/vic/sequencer/saved_state.rb +91 -0
  152. data/lib/badline/chips/vic/sequencer.rb +277 -0
  153. data/lib/badline/chips/vic/sequencer_output.rb +118 -0
  154. data/lib/badline/chips/vic/sprite/internal_bus.rb +70 -0
  155. data/lib/badline/chips/vic/sprite/saved_state.rb +66 -0
  156. data/lib/badline/chips/vic/sprite/shifter.rb +148 -0
  157. data/lib/badline/chips/vic/sprite/timing.rb +58 -0
  158. data/lib/badline/chips/vic/sprite.rb +339 -0
  159. data/lib/badline/chips/vic/sprites/saved_state.rb +59 -0
  160. data/lib/badline/chips/vic/sprites.rb +284 -0
  161. data/lib/badline/chips/vic.rb +783 -0
  162. data/lib/badline/chips/vic_i/painter/saved_state.rb +40 -0
  163. data/lib/badline/{vic20/vic → chips/vic_i}/painter.rb +6 -30
  164. data/lib/badline/{vic20/vic → chips/vic_i}/saved_state.rb +2 -2
  165. data/lib/badline/chips/vic_i/sound/output.rb +85 -0
  166. data/lib/badline/chips/vic_i/sound.rb +235 -0
  167. data/lib/badline/{vic20/vic → chips/vic_i}/text_window.rb +2 -2
  168. data/lib/badline/{vic20/vic.rb → chips/vic_i.rb} +5 -5
  169. data/lib/badline/chips/z80/arithmetic.rb +119 -0
  170. data/lib/badline/chips/z80/bit_page.rb +57 -0
  171. data/lib/badline/chips/z80/block_io.rb +60 -0
  172. data/lib/badline/chips/z80/block_transfers.rb +61 -0
  173. data/lib/badline/chips/z80/bus_cycles.rb +113 -0
  174. data/lib/badline/chips/z80/core.rb +115 -0
  175. data/lib/badline/chips/z80/exchanges.rb +52 -0
  176. data/lib/badline/chips/z80/extended_page.rb +91 -0
  177. data/lib/badline/chips/z80/flags.rb +39 -0
  178. data/lib/badline/chips/z80/interrupt_acceptance.rb +48 -0
  179. data/lib/badline/chips/z80/jumps.rb +84 -0
  180. data/lib/badline/chips/z80/loads.rb +100 -0
  181. data/lib/badline/chips/z80/main_page.rb +136 -0
  182. data/lib/badline/chips/z80/registers.rb +122 -0
  183. data/lib/badline/chips/z80/saved_state.rb +71 -0
  184. data/lib/badline/chips/z80/shifts.rb +66 -0
  185. data/lib/badline/chips/z80.rb +13 -0
  186. data/lib/badline/core.rb +26 -28
  187. data/lib/badline/drives/datasette/saved_state.rb +37 -0
  188. data/lib/badline/drives/datasette.rb +140 -0
  189. data/lib/badline/drives/engine/core.rb +149 -0
  190. data/lib/badline/drives/engine/fast_serial.rb +75 -0
  191. data/lib/badline/drives/engine/idle.rb +127 -0
  192. data/lib/badline/drives/engine/idle_cpu.rb +30 -0
  193. data/lib/badline/drives/engine/orbit.rb +81 -0
  194. data/lib/badline/drives/engine/serial_lines.rb +75 -0
  195. data/lib/badline/drives/engine/sleep.rb +114 -0
  196. data/lib/badline/drives/engine/vias.rb +86 -0
  197. data/lib/badline/drives/engine/watch.rb +152 -0
  198. data/lib/badline/drives/engine.rb +11 -0
  199. data/lib/badline/drives/model1541/bus.rb +88 -0
  200. data/lib/badline/drives/model1541/byte_ready.rb +50 -0
  201. data/lib/badline/drives/model1541/cpu.rb +13 -0
  202. data/lib/badline/drives/model1541/disk/saved_state.rb +88 -0
  203. data/lib/badline/drives/model1541/disk.rb +317 -0
  204. data/lib/badline/drives/model1541/disk_via.rb +38 -0
  205. data/lib/badline/drives/model1541/gcr.rb +59 -0
  206. data/lib/badline/drives/model1541/mechanism/saved_state.rb +72 -0
  207. data/lib/badline/drives/model1541/mechanism.rb +315 -0
  208. data/lib/badline/drives/model1541/rotation.rb +123 -0
  209. data/lib/badline/drives/model1541/saved_state.rb +44 -0
  210. data/lib/badline/drives/model1541/sector_reader.rb +78 -0
  211. data/lib/badline/drives/model1541/serial_port.rb +20 -0
  212. data/lib/badline/drives/model1541/track.rb +100 -0
  213. data/lib/badline/drives/model1541.rb +81 -0
  214. data/lib/badline/drives/model1571/bus.rb +113 -0
  215. data/lib/badline/drives/model1571/cpu.rb +13 -0
  216. data/lib/badline/drives/model1571/saved_state.rb +47 -0
  217. data/lib/badline/drives/model1571/serial_port.rb +39 -0
  218. data/lib/badline/drives/model1571/serial_via.rb +27 -0
  219. data/lib/badline/drives/model1571/wd1770.rb +122 -0
  220. data/lib/badline/drives/model1571.rb +142 -0
  221. data/lib/badline/drives/model1581/bus.rb +139 -0
  222. data/lib/badline/drives/model1581/cpu.rb +13 -0
  223. data/lib/badline/drives/model1581/disk/saved_state.rb +89 -0
  224. data/lib/badline/drives/model1581/disk.rb +137 -0
  225. data/lib/badline/drives/model1581/mechanism.rb +119 -0
  226. data/lib/badline/drives/model1581/saved_state.rb +42 -0
  227. data/lib/badline/drives/model1581/serial_port.rb +54 -0
  228. data/lib/badline/drives/model1581/slot.rb +79 -0
  229. data/lib/badline/drives/model1581/track.rb +102 -0
  230. data/lib/badline/drives/model1581/track_bytes.rb +77 -0
  231. data/lib/badline/drives/model1581/wd1772/registers.rb +91 -0
  232. data/lib/badline/drives/model1581/wd1772/saved_state.rb +68 -0
  233. data/lib/badline/drives/model1581/wd1772/sector_writes.rb +75 -0
  234. data/lib/badline/drives/model1581/wd1772/sectors.rb +152 -0
  235. data/lib/badline/drives/model1581/wd1772/stepping.rb +111 -0
  236. data/lib/badline/drives/model1581/wd1772/tracks.rb +127 -0
  237. data/lib/badline/drives/model1581/wd1772/turn.rb +75 -0
  238. data/lib/badline/drives/model1581/wd1772.rb +218 -0
  239. data/lib/badline/drives/model1581.rb +206 -0
  240. data/lib/badline/drives/serial_bus.rb +161 -0
  241. data/lib/badline/frontend/boot.rb +3 -3
  242. data/lib/badline/frontend/machine_window.rb +3 -1
  243. data/lib/badline/frontend/player/filter_view.rb +1 -1
  244. data/lib/badline/frontend/player/player_controller.rb +2 -2
  245. data/lib/badline/frontend/player/player_screen.rb +1 -0
  246. data/lib/badline/frontend/player/theme.rb +7 -7
  247. data/lib/badline/frontend/timeline.rb +3 -3
  248. data/lib/badline/input/control_ports.rb +78 -0
  249. data/lib/badline/input/joystick.rb +27 -0
  250. data/lib/badline/input/keyboard.rb +114 -0
  251. data/lib/badline/input.rb +3 -0
  252. data/lib/badline/kernal_trap/{drive → dos}/block_commands.rb +1 -1
  253. data/lib/badline/kernal_trap/dos/channel.rb +183 -0
  254. data/lib/badline/kernal_trap/{drive → dos}/channels.rb +1 -1
  255. data/lib/badline/kernal_trap/{drive → dos}/memory.rb +1 -1
  256. data/lib/badline/kernal_trap/{drive → dos}/parameters.rb +1 -1
  257. data/lib/badline/kernal_trap/{drive → dos}/status.rb +1 -1
  258. data/lib/badline/kernal_trap/{drive → dos}/write_file.rb +1 -1
  259. data/lib/badline/kernal_trap/{drive → dos}/writes.rb +1 -1
  260. data/lib/badline/kernal_trap/{drive.rb → dos.rb} +11 -10
  261. data/lib/badline/kernal_trap/load.rb +5 -5
  262. data/lib/badline/kernal_trap/save.rb +4 -4
  263. data/lib/badline/kernal_trap/serial.rb +7 -7
  264. data/lib/badline/kernal_trap.rb +1 -2
  265. data/lib/badline/machine/clocking.rb +1 -1
  266. data/lib/badline/machine.rb +5 -5
  267. data/lib/badline/media/true_drive.rb +1 -1
  268. data/lib/badline/media/tune.rb +2 -2
  269. data/lib/badline/media.rb +3 -3
  270. data/lib/badline/model.rb +1 -1
  271. data/lib/badline/roms/README +6 -6
  272. data/lib/badline/sdl.rb +1 -0
  273. data/lib/badline/{storage/sid_file.rb → sid_tune/file.rb} +3 -3
  274. data/lib/badline/{storage → sid_tune}/hvsc.rb +7 -7
  275. data/lib/badline/{storage → sid_tune}/song_lengths.rb +2 -2
  276. data/lib/badline/{storage → sid_tune}/stil/credit.rb +1 -1
  277. data/lib/badline/{storage → sid_tune}/stil.rb +3 -3
  278. data/lib/badline/sid_tune.rb +6 -0
  279. data/lib/badline/snapshot/c128_setup.rb +43 -0
  280. data/lib/badline/snapshot/c64_setup.rb +79 -0
  281. data/lib/badline/snapshot/image.rb +5 -25
  282. data/lib/badline/snapshot/machine_state.rb +1 -1
  283. data/lib/badline/snapshot/setup.rb +22 -66
  284. data/lib/badline/snapshot/state.rb +8 -18
  285. data/lib/badline/snapshot/storage_setup.rb +68 -0
  286. data/lib/badline/snapshot/vic20_setup.rb +37 -0
  287. data/lib/badline/snapshot/vice/c64_mem.rb +1 -1
  288. data/lib/badline/snapshot/vice/restore.rb +1 -1
  289. data/lib/badline/snapshot/vice/reu1764.rb +1 -1
  290. data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
  291. data/lib/badline/snapshot/vice.rb +7 -5
  292. data/lib/badline/snapshot.rb +3 -4
  293. data/lib/badline/storage/d64_image.rb +0 -2
  294. data/lib/badline/storage/d71_image.rb +0 -2
  295. data/lib/badline/storage/d81_image.rb +0 -2
  296. data/lib/badline/storage/disk_image.rb +3 -6
  297. data/lib/badline/storage/g64_image.rb +2 -2
  298. data/lib/badline/storage/host_directory.rb +0 -5
  299. data/lib/badline/storage/t64.rb +2 -8
  300. data/lib/badline/storage/unavailable.rb +1 -1
  301. data/lib/badline/storage.rb +0 -37
  302. data/lib/badline/support/c128_checkpoint.rb +39 -0
  303. data/lib/badline/support/checkpoint.rb +108 -0
  304. data/lib/badline/support/vic20_checkpoint.rb +38 -0
  305. data/lib/badline/support.rb +5 -0
  306. data/lib/badline/version.rb +1 -1
  307. data/lib/badline/vic20/attachments.rb +5 -5
  308. data/lib/badline/vic20/bus/saved_state.rb +35 -0
  309. data/lib/badline/vic20/bus.rb +3 -25
  310. data/lib/badline/vic20/cpu.rb +1 -1
  311. data/lib/badline/vic20/port_wiring.rb +4 -4
  312. data/lib/badline/vic20/saved_state.rb +16 -30
  313. data/lib/badline/vic20/user_via_ports.rb +2 -2
  314. data/lib/badline/vic20.rb +19 -14
  315. metadata +245 -221
  316. data/lib/badline/address_bus/extra_sids.rb +0 -30
  317. data/lib/badline/address_bus/fittings.rb +0 -38
  318. data/lib/badline/address_bus/pla.rb +0 -147
  319. data/lib/badline/address_bus/roms.rb +0 -39
  320. data/lib/badline/address_bus/saved_state.rb +0 -66
  321. data/lib/badline/address_bus/sid_slots.rb +0 -42
  322. data/lib/badline/address_bus.rb +0 -216
  323. data/lib/badline/cartridge/action_replay.rb +0 -126
  324. data/lib/badline/cartridge/atomic_power.rb +0 -24
  325. data/lib/badline/cartridge/bank.rb +0 -81
  326. data/lib/badline/cartridge/comal80.rb +0 -50
  327. data/lib/badline/cartridge/dinamic.rb +0 -34
  328. data/lib/badline/cartridge/easy_flash.rb +0 -145
  329. data/lib/badline/cartridge/epyx_fastload.rb +0 -79
  330. data/lib/badline/cartridge/final_cartridge3.rb +0 -89
  331. data/lib/badline/cartridge/flash.rb +0 -306
  332. data/lib/badline/cartridge/freezer.rb +0 -33
  333. data/lib/badline/cartridge/fun_play.rb +0 -38
  334. data/lib/badline/cartridge/g_mod2.rb +0 -74
  335. data/lib/badline/cartridge/game_system.rb +0 -40
  336. data/lib/badline/cartridge/geo_ram.rb +0 -79
  337. data/lib/badline/cartridge/kcs_power.rb +0 -75
  338. data/lib/badline/cartridge/mach5.rb +0 -32
  339. data/lib/badline/cartridge/magic_desk.rb +0 -30
  340. data/lib/badline/cartridge/ocean.rb +0 -35
  341. data/lib/badline/cartridge/pagefox.rb +0 -68
  342. data/lib/badline/cartridge/retro_replay.rb +0 -320
  343. data/lib/badline/cartridge/rex_utility.rb +0 -29
  344. data/lib/badline/cartridge/rgcd.rb +0 -58
  345. data/lib/badline/cartridge/simons_basic.rb +0 -35
  346. data/lib/badline/cartridge/standard.rb +0 -15
  347. data/lib/badline/cartridge/super_games.rb +0 -48
  348. data/lib/badline/cartridge/westermann.rb +0 -30
  349. data/lib/badline/cartridge/zaxxon.rb +0 -66
  350. data/lib/badline/cartridge.rb +0 -303
  351. data/lib/badline/checkpoint.rb +0 -98
  352. data/lib/badline/cia/fast_forward.rb +0 -60
  353. data/lib/badline/cia/interrupt_register.rb +0 -143
  354. data/lib/badline/cia/serial.rb +0 -275
  355. data/lib/badline/cia/state.rb +0 -47
  356. data/lib/badline/cia/timer.rb +0 -206
  357. data/lib/badline/cia.rb +0 -279
  358. data/lib/badline/color_memory.rb +0 -25
  359. data/lib/badline/control_ports.rb +0 -76
  360. data/lib/badline/cpu/addressing.rb +0 -131
  361. data/lib/badline/cpu/boundary.rb +0 -54
  362. data/lib/badline/cpu/core.rb +0 -165
  363. data/lib/badline/cpu/microcode.rb +0 -177
  364. data/lib/badline/cpu/operations.rb +0 -88
  365. data/lib/badline/cpu/saved_state.rb +0 -115
  366. data/lib/badline/cpu/stack_operations.rb +0 -82
  367. data/lib/badline/cpu.rb +0 -10
  368. data/lib/badline/cpu_port.rb +0 -112
  369. data/lib/badline/datasette.rb +0 -161
  370. data/lib/badline/drive/core.rb +0 -147
  371. data/lib/badline/drive/fast_serial.rb +0 -73
  372. data/lib/badline/drive/idle.rb +0 -125
  373. data/lib/badline/drive/idle_cpu.rb +0 -28
  374. data/lib/badline/drive/orbit.rb +0 -79
  375. data/lib/badline/drive/serial_lines.rb +0 -73
  376. data/lib/badline/drive/sleep.rb +0 -112
  377. data/lib/badline/drive/vias.rb +0 -84
  378. data/lib/badline/drive/watch.rb +0 -150
  379. data/lib/badline/drive.rb +0 -11
  380. data/lib/badline/drive1541/bus.rb +0 -86
  381. data/lib/badline/drive1541/byte_ready.rb +0 -48
  382. data/lib/badline/drive1541/cpu.rb +0 -11
  383. data/lib/badline/drive1541/disk.rb +0 -315
  384. data/lib/badline/drive1541/disk_state.rb +0 -86
  385. data/lib/badline/drive1541/disk_via.rb +0 -36
  386. data/lib/badline/drive1541/gcr.rb +0 -57
  387. data/lib/badline/drive1541/mechanism.rb +0 -313
  388. data/lib/badline/drive1541/mechanism_state.rb +0 -68
  389. data/lib/badline/drive1541/rotation.rb +0 -121
  390. data/lib/badline/drive1541/sector_reader.rb +0 -76
  391. data/lib/badline/drive1541/serial_port.rb +0 -18
  392. data/lib/badline/drive1541/track.rb +0 -98
  393. data/lib/badline/drive1541.rb +0 -111
  394. data/lib/badline/drive1571/bus.rb +0 -111
  395. data/lib/badline/drive1571/cpu.rb +0 -11
  396. data/lib/badline/drive1571/serial_port.rb +0 -37
  397. data/lib/badline/drive1571/serial_via.rb +0 -25
  398. data/lib/badline/drive1571/wd1770.rb +0 -120
  399. data/lib/badline/drive1571.rb +0 -175
  400. data/lib/badline/drive1581/bus.rb +0 -137
  401. data/lib/badline/drive1581/cpu.rb +0 -11
  402. data/lib/badline/drive1581/disk.rb +0 -135
  403. data/lib/badline/drive1581/disk_state.rb +0 -87
  404. data/lib/badline/drive1581/mechanism.rb +0 -117
  405. data/lib/badline/drive1581/serial_port.rb +0 -52
  406. data/lib/badline/drive1581/slot.rb +0 -78
  407. data/lib/badline/drive1581/track.rb +0 -100
  408. data/lib/badline/drive1581/track_bytes.rb +0 -75
  409. data/lib/badline/drive1581/wd1772/registers.rb +0 -89
  410. data/lib/badline/drive1581/wd1772/sector_writes.rb +0 -73
  411. data/lib/badline/drive1581/wd1772/sectors.rb +0 -150
  412. data/lib/badline/drive1581/wd1772/state.rb +0 -66
  413. data/lib/badline/drive1581/wd1772/stepping.rb +0 -109
  414. data/lib/badline/drive1581/wd1772/tracks.rb +0 -125
  415. data/lib/badline/drive1581/wd1772/turn.rb +0 -73
  416. data/lib/badline/drive1581/wd1772.rb +0 -216
  417. data/lib/badline/drive1581.rb +0 -233
  418. data/lib/badline/iec_bus.rb +0 -159
  419. data/lib/badline/instruction.rb +0 -334
  420. data/lib/badline/instruction_set/arithmetic.rb +0 -114
  421. data/lib/badline/instruction_set/bitwise.rb +0 -126
  422. data/lib/badline/instruction_set/branch.rb +0 -79
  423. data/lib/badline/instruction_set/flag.rb +0 -63
  424. data/lib/badline/instruction_set/illegal.rb +0 -270
  425. data/lib/badline/instruction_set/inc_dec.rb +0 -69
  426. data/lib/badline/instruction_set/stack.rb +0 -52
  427. data/lib/badline/instruction_set/transfer.rb +0 -137
  428. data/lib/badline/instruction_set.rb +0 -55
  429. data/lib/badline/interrupts.rb +0 -104
  430. data/lib/badline/joystick.rb +0 -25
  431. data/lib/badline/kernal_trap/channel.rb +0 -181
  432. data/lib/badline/keyboard.rb +0 -112
  433. data/lib/badline/ram_expansion/banking.rb +0 -30
  434. data/lib/badline/ram_expansion/plus256k.rb +0 -54
  435. data/lib/badline/ram_expansion/plus60k.rb +0 -43
  436. data/lib/badline/ram_expansion/unexpanded.rb +0 -28
  437. data/lib/badline/ram_expansion.rb +0 -21
  438. data/lib/badline/reu/dma/saved_state.rb +0 -50
  439. data/lib/badline/reu/dma.rb +0 -273
  440. data/lib/badline/reu/ram.rb +0 -107
  441. data/lib/badline/reu/saved_state.rb +0 -80
  442. data/lib/badline/reu/trigger.rb +0 -32
  443. data/lib/badline/reu.rb +0 -289
  444. data/lib/badline/sid/catch_up.rb +0 -120
  445. data/lib/badline/sid/decimator.rb +0 -64
  446. data/lib/badline/sid/envelope/state.rb +0 -68
  447. data/lib/badline/sid/envelope.rb +0 -239
  448. data/lib/badline/sid/filter.rb +0 -263
  449. data/lib/badline/sid/voice.rb +0 -77
  450. data/lib/badline/sid/waveform/combined.rb +0 -126
  451. data/lib/badline/sid/waveform/fast_forward.rb +0 -105
  452. data/lib/badline/sid/waveform/noise_writeback.rb +0 -122
  453. data/lib/badline/sid/waveform/state.rb +0 -66
  454. data/lib/badline/sid/waveform.rb +0 -305
  455. data/lib/badline/sid.rb +0 -303
  456. data/lib/badline/time_of_day.rb +0 -228
  457. data/lib/badline/traps.rb +0 -19
  458. data/lib/badline/via/control_lines.rb +0 -122
  459. data/lib/badline/via/fast_forward.rb +0 -53
  460. data/lib/badline/via/interrupt_register.rb +0 -67
  461. data/lib/badline/via/shift_register.rb +0 -180
  462. data/lib/badline/via/state.rb +0 -42
  463. data/lib/badline/via/timer1.rb +0 -131
  464. data/lib/badline/via/timer2.rb +0 -133
  465. data/lib/badline/via.rb +0 -266
  466. data/lib/badline/vic/bank.rb +0 -133
  467. data/lib/badline/vic/border_mask.rb +0 -86
  468. data/lib/badline/vic/collisions.rb +0 -115
  469. data/lib/badline/vic/color_patches.rb +0 -47
  470. data/lib/badline/vic/display_state.rb +0 -185
  471. data/lib/badline/vic/graphics_mode.rb +0 -164
  472. data/lib/badline/vic/graphics_shifter.rb +0 -207
  473. data/lib/badline/vic/register_log.rb +0 -81
  474. data/lib/badline/vic/registers.rb +0 -195
  475. data/lib/badline/vic/sequencer.rb +0 -275
  476. data/lib/badline/vic/sequencer_output.rb +0 -116
  477. data/lib/badline/vic/sequencer_state.rb +0 -89
  478. data/lib/badline/vic/sprite/internal_bus.rb +0 -68
  479. data/lib/badline/vic/sprite/saved_state.rb +0 -64
  480. data/lib/badline/vic/sprite/shifter.rb +0 -146
  481. data/lib/badline/vic/sprite/timing.rb +0 -56
  482. data/lib/badline/vic/sprite.rb +0 -337
  483. data/lib/badline/vic/sprites.rb +0 -282
  484. data/lib/badline/vic/sprites_state.rb +0 -57
  485. data/lib/badline/vic.rb +0 -853
  486. data/lib/badline/vic20/sound/output.rb +0 -83
  487. data/lib/badline/vic20/sound.rb +0 -233
  488. data/lib/badline/z80/arithmetic.rb +0 -117
  489. data/lib/badline/z80/bit_page.rb +0 -55
  490. data/lib/badline/z80/block_io.rb +0 -58
  491. data/lib/badline/z80/block_transfers.rb +0 -59
  492. data/lib/badline/z80/bus_cycles.rb +0 -111
  493. data/lib/badline/z80/core.rb +0 -113
  494. data/lib/badline/z80/exchanges.rb +0 -50
  495. data/lib/badline/z80/extended_page.rb +0 -89
  496. data/lib/badline/z80/flags.rb +0 -37
  497. data/lib/badline/z80/interrupt_acceptance.rb +0 -46
  498. data/lib/badline/z80/jumps.rb +0 -82
  499. data/lib/badline/z80/loads.rb +0 -98
  500. data/lib/badline/z80/main_page.rb +0 -134
  501. data/lib/badline/z80/registers.rb +0 -120
  502. data/lib/badline/z80/saved_state.rb +0 -69
  503. data/lib/badline/z80/shifts.rb +0 -64
  504. data/lib/badline/z80.rb +0 -11
  505. /data/lib/badline/snapshot/{fields.rb → vice/fields.rb} +0 -0
@@ -0,0 +1,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
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Cartridge
6
+ # One 8K bank of cartridge ROM. The chip decodes only the low address
7
+ # lines, so the same bank answers at $8000, $A000 or $E000, and a smaller
8
+ # chip mirrors across the window.
9
+ class Bank
10
+ def initialize(data)
11
+ size = [1 << (data.length - 1).bit_length, 1].max
12
+ @mask = size - 1
13
+ @data = (data + ([0xff] * (size - data.length))).freeze
14
+ end
15
+
16
+ def peek(addr)
17
+ @data[addr & @mask]
18
+ end
19
+ alias [] peek
20
+ end
21
+
22
+ # Cartridge RAM mapped into the ROML or ROMH window. Writes land in the
23
+ # C64's RAM underneath as well, when there is a backing. Banks built on
24
+ # the same data are views of the same RAM.
25
+ class RAMBank
26
+ attr_reader :data
27
+ attr_writer :backing
28
+
29
+ def initialize(data = Array.new(BANK_SIZE, 0))
30
+ @data = data
31
+ @backing = nil
32
+ end
33
+
34
+ def peek(addr)
35
+ @data[addr & 0x1fff]
36
+ end
37
+ alias [] peek
38
+
39
+ def poke(addr, value)
40
+ @data[addr & 0x1fff] = value
41
+ @backing&.poke(addr, value)
42
+ end
43
+ alias []= poke
44
+ end
45
+
46
+ # Cartridge RAM the window reads, where the cartridge ignores writes.
47
+ class RAMReader
48
+ def initialize(data)
49
+ @data = data
50
+ end
51
+
52
+ def peek(addr)
53
+ @data[addr & 0x1fff]
54
+ end
55
+ alias [] peek
56
+ end
57
+
58
+ # Cartridge RAM that takes writes while the window reads something else.
59
+ class WriteOnlyRAM < RAMBank
60
+ def initialize(data, reader)
61
+ super(data)
62
+ @reader = reader
63
+ end
64
+
65
+ def peek(addr)
66
+ @reader.peek(addr)
67
+ end
68
+ alias [] peek
69
+ end
70
+
71
+ # Cartridge RAM selected together with the C64's RAM, both driving the
72
+ # bus on a read. The result is ORed, as VICE has it.
73
+ class ContendedRAM < RAMBank
74
+ def peek(addr)
75
+ @data[addr & 0x1fff] | @backing.peek(addr)
76
+ end
77
+ alias [] peek
78
+ end
79
+
80
+ EMPTY_BANK = Bank.new([0xff])
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Cartridge
6
+ # Comal-80: four 16K banks, or eight with the extra ROMs. A write to
7
+ # I/O 1 selects the bank and the memory configuration. The black board
8
+ # (subtype 0) takes the bank from bits 0-2 and switches the ROM out with
9
+ # bit 6; the grey one (subtype 1) takes the bank from bits 0-1 and the
10
+ # configuration from bits 5-6.
11
+ class Comal80 < Cartridge
12
+ GREY_MODES = %i[rom16k ultimax rom8k off].freeze
13
+
14
+ def initialize(crt)
15
+ @grey = crt.subtype == 1
16
+ super
17
+ end
18
+
19
+ def poke(addr, value)
20
+ return if addr > 0xdeff
21
+
22
+ if @grey
23
+ select(value & 0x03, GREY_MODES[(value >> 5) & 0x03])
24
+ else
25
+ select(value & 0x07, value.anybits?(0x40) ? :off : :rom16k)
26
+ end
27
+ changed!
28
+ end
29
+
30
+ def reset
31
+ select(0, :rom16k)
32
+ changed!
33
+ end
34
+
35
+ private
36
+
37
+ def windows = [*@roml_banks, *@romh_banks, EMPTY_BANK]
38
+
39
+ def select(number, mode)
40
+ @roml = bank(@roml_banks, number)
41
+ @romh = bank(@romh_banks, number)
42
+ self.mode = mode
43
+ end
44
+
45
+ def install_chips(chips)
46
+ @roml_banks, @romh_banks = banks_from(chips)
47
+ reset
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Cartridge
6
+ # Dinamic: up to 16 8K banks. Reading $DE00-$DE0F selects the bank from
7
+ # the low address bits.
8
+ class Dinamic < Cartridge
9
+ def readable_io_pages
10
+ [0xde]
11
+ end
12
+
13
+ def peek(addr)
14
+ if addr < 0xde10
15
+ @roml = bank(@banks, addr & 0x0f)
16
+ changed!
17
+ end
18
+ open_bus(addr)
19
+ end
20
+
21
+ def reset
22
+ @roml = bank(@banks, 0)
23
+ changed!
24
+ end
25
+
26
+ private
27
+
28
+ def install_chips(chips)
29
+ @banks = banks_from(chips).first
30
+ self.mode = :rom8k
31
+ reset
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Cartridge
6
+ # EasyFlash: two Am29F040B flash chips, one for ROML and one for ROMH,
7
+ # each 64 banks of 8K, and 256 bytes of RAM at $DF00. $DE00 selects the
8
+ # bank. $DE02 sets the memory configuration: bit 2 hands the GAME line
9
+ # to bit 0 (otherwise the boot jumper holds it low), bit 1 pulls EXROM
10
+ # low and bit 7 drives the LED.
11
+ #
12
+ # The flash takes writes in Ultimax mode, at $8000 for ROML and $E000
13
+ # for ROMH, which is how EAPI programs and erases it. The writes stay in
14
+ # memory; #save_crt writes the flash out as a new image.
15
+ #
16
+ # An image built for EasyFlash carries an EAPI, the flash driver, at $B800
17
+ # in bank 0 of ROMH. On attach, as in VICE, the bundled Am29F040 EAPI
18
+ # (roms/eapi) takes its place, so the image drives the flash emulated here.
19
+ class EasyFlash < Cartridge
20
+ BANKS = 64
21
+ EAPI_OFFSET = 0x1800
22
+
23
+ def self.eapi
24
+ @eapi ||= ROM.read("eapi/eapi-am29f040-14").drop(2).freeze
25
+ end
26
+
27
+ attr_reader :low_flash, :high_flash
28
+
29
+ def clock=(clock)
30
+ super
31
+ [@low_flash, @high_flash].each { |flash| flash.clock = clock }
32
+ end
33
+
34
+ def readable_io_pages
35
+ [0xdf]
36
+ end
37
+
38
+ def peek(addr)
39
+ @io_ram[addr & 0xff]
40
+ end
41
+
42
+ def poke(addr, value)
43
+ if addr >= 0xdf00
44
+ @io_ram[addr & 0xff] = value
45
+ elsif addr.nobits?(0x02)
46
+ @bank = value & 0x3f
47
+ select_bank
48
+ else
49
+ @control = value & 0x87
50
+ apply_control
51
+ changed!
52
+ end
53
+ end
54
+
55
+ def led?
56
+ @control.anybits?(0x80)
57
+ end
58
+
59
+ # Reset clears both registers, and leaves the flash and the RAM.
60
+ def reset
61
+ @bank = 0
62
+ @control = 0
63
+ apply_control
64
+ select_bank
65
+ end
66
+
67
+ # Writes every bank that isn't blank to a CRT image at path.
68
+ def save_crt(path)
69
+ chips = (0...BANKS).flat_map do |number|
70
+ [[@low_flash, 0x8000], [@high_flash, 0xa000]].filter_map do |flash, address|
71
+ data = flash.data[number * BANK_SIZE, BANK_SIZE]
72
+ Storage::CRTFile::Chip.new(chip_type: 2, bank: number, address:, data:) if data.any?(0..0xfe)
73
+ end
74
+ end
75
+ image = Storage::CRTFile::Image.new(hardware_type: 32, subtype: 0, exrom: 1, game: 0, name:, chips:)
76
+ Storage::CRTFile.write(path, image)
77
+ end
78
+
79
+ private
80
+
81
+ def select_bank
82
+ map_bank
83
+ changed!
84
+ end
85
+
86
+ def map_bank
87
+ @roml = @low_flash.window(@bank * BANK_SIZE)
88
+ @romh = @high_flash.window(@bank * BANK_SIZE)
89
+ end
90
+
91
+ def save_mapper(out)
92
+ out.int(@bank).int(@control).blob(@io_ram)
93
+ @low_flash.save_state(out)
94
+ @high_flash.save_state(out)
95
+ end
96
+
97
+ def load_mapper(input)
98
+ @bank = input.int
99
+ @control = input.int
100
+ input.blob_into(@io_ram)
101
+ @low_flash.load_state(input)
102
+ @high_flash.load_state(input)
103
+ map_bank
104
+ end
105
+
106
+ def apply_control
107
+ game = @control.nobits?(0x04) || @control.anybits?(0x01)
108
+ exrom = @control.anybits?(0x02)
109
+ @game = game ? 0 : 1
110
+ @exrom = exrom ? 0 : 1
111
+ end
112
+
113
+ def install_chips(chips)
114
+ low = Array.new(BANKS * BANK_SIZE, 0xff)
115
+ high = Array.new(BANKS * BANK_SIZE, 0xff)
116
+ chips.each do |chip|
117
+ offset = (chip.bank & 0x3f) * BANK_SIZE
118
+ if chip.address >= ROMH_START
119
+ place(high, offset, chip.data)
120
+ else
121
+ place(low, offset, chip.data)
122
+ place(high, offset, chip.data[BANK_SIZE..]) if chip.data.length > BANK_SIZE
123
+ end
124
+ end
125
+ install_eapi(high)
126
+ @low_flash = Flash.new(low)
127
+ @high_flash = Flash.new(high)
128
+ [@low_flash, @high_flash].each { |flash| flash.on_change { select_bank } }
129
+ @io_ram = Array.new(0x100, 0xff)
130
+ reset
131
+ end
132
+
133
+ def install_eapi(high)
134
+ return unless high[EAPI_OFFSET, 4] == "eapi".bytes
135
+
136
+ eapi = EasyFlash.eapi
137
+ high[EAPI_OFFSET, eapi.length] = eapi
138
+ end
139
+
140
+ def place(flash_data, offset, bytes)
141
+ bytes = bytes.first(BANK_SIZE)
142
+ flash_data[offset, bytes.length] = bytes
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end