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,279 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/c64/cartridge/flash/saved_state"
4
+
5
+ module Badline
6
+ class C64
7
+ class Cartridge
8
+ # An AMD 29F0x0 flash chip, driven through the JEDEC command set in the
9
+ # AMD datasheets. Each command opens with two unlock cycles, $AA to the
10
+ # first unlock address and $55 to the second, and a third write picks
11
+ # the command:
12
+ #
13
+ # $90 autoselect: offset 0 reads the manufacturer, 1 the device and 2
14
+ # the sector protection, until a reset
15
+ # $F0 reset to reading the array, which a lone $F0 also does
16
+ # $A0 byte program: the next write clears bits of the array, which
17
+ # only an erase sets again
18
+ # $80 erase, after two more unlock cycles: $10 to the first unlock
19
+ # address erases the chip, and $30 to a sector erases the sector.
20
+ # Further sectors can follow within the 50 us window.
21
+ #
22
+ # While a program or erase runs, a read returns status: DQ7 the
23
+ # complement of the programmed bit (0 while erasing), DQ6 toggling on
24
+ # every read, DQ5 set when a program failed and DQ3 set once an erase
25
+ # has left its window. $B0 suspends a sector erase and $30 resumes it.
26
+ #
27
+ # The cartridge reads the array through windows, and the chip swaps
28
+ # them for status windows while it is busy or in autoselect.
29
+ class Flash
30
+ Model = Data.define(:size, :sector_size, :unlock1, :unlock2, :unlock_mask, :manufacturer, :device)
31
+
32
+ AM29F040 = Model.new(size: 0x80000, sector_size: 0x10000, unlock1: 0x5555, unlock2: 0x2aaa,
33
+ unlock_mask: 0x7fff, manufacturer: 0x01, device: 0xa4)
34
+ AM29F040B = Model.new(size: 0x80000, sector_size: 0x10000, unlock1: 0x555, unlock2: 0x2aa,
35
+ unlock_mask: 0x7ff, manufacturer: 0x01, device: 0xa4)
36
+ AM29F010 = Model.new(size: 0x20000, sector_size: 0x4000, unlock1: 0x5555, unlock2: 0x2aaa,
37
+ unlock_mask: 0x7fff, manufacturer: 0x01, device: 0x20)
38
+
39
+ # The datasheet's typical times, in cycles at 1 MHz.
40
+ PROGRAM_CYCLES = 7
41
+ ERASE_WINDOW_CYCLES = 50
42
+ SECTOR_ERASE_CYCLES = 1_000_000
43
+ CHIP_ERASE_CYCLES = 8_000_000
44
+
45
+ # The array, read directly while the chip reads it.
46
+ class Window
47
+ def initialize(flash, base)
48
+ @flash = flash
49
+ @data = flash.data
50
+ @base = base
51
+ end
52
+
53
+ def peek(addr)
54
+ @data[@base | (addr & 0x1fff)]
55
+ end
56
+ alias [] peek
57
+
58
+ def poke(addr, value)
59
+ @flash.write(@base | (addr & 0x1fff), value)
60
+ end
61
+ alias []= poke
62
+ end
63
+
64
+ # Reads through the chip, for its status and autoselect codes.
65
+ class StatusWindow < Window
66
+ def peek(addr)
67
+ @flash.read(@base | (addr & 0x1fff))
68
+ end
69
+ alias [] peek
70
+ end
71
+
72
+ include SavedState
73
+
74
+ attr_reader :data, :state
75
+ attr_writer :clock
76
+
77
+ def initialize(data, model: AM29F040B, clock: -> { 0 })
78
+ @model = model
79
+ @data = data + ([0xff] * (model.size - data.length))
80
+ @clock = clock
81
+ @windows = {}
82
+ @status_windows = {}
83
+ @on_change = nil
84
+ @state = :read
85
+ @base_state = :read
86
+ @cycle = 0
87
+ @toggle = 0
88
+ end
89
+
90
+ # Called when the chip starts or stops answering reads from the array.
91
+ def on_change(&block)
92
+ @on_change = block
93
+ end
94
+
95
+ def window(base)
96
+ if array_mode?
97
+ @windows[base] ||= Window.new(self, base)
98
+ else
99
+ @status_windows[base] ||= StatusWindow.new(self, base)
100
+ end
101
+ end
102
+
103
+ # Hands out new windows at the bases given, as #window would have.
104
+ def rebuild_windows(bases, status_bases)
105
+ @windows = {}
106
+ @status_windows = {}
107
+ bases.each { |base| @windows[base] = Window.new(self, base) }
108
+ status_bases.each { |base| @status_windows[base] = StatusWindow.new(self, base) }
109
+ end
110
+
111
+ def array_mode?
112
+ @state == :read || @state == :program_setup
113
+ end
114
+
115
+ def read(offset)
116
+ settle
117
+ case @state
118
+ when :read then @data[offset]
119
+ when :autoselect then autoselect_code(offset)
120
+ when :suspended then suspended_read(offset)
121
+ else status
122
+ end
123
+ end
124
+
125
+ def write(offset, value)
126
+ settle
127
+ case @state
128
+ when :program_setup then program(offset, value)
129
+ when :erase_window then extend_erase(offset, value)
130
+ when :erasing then suspend if value == 0xb0
131
+ when :suspended then resume if value == 0x30
132
+ when :program_error then enter(:read, base: :read) if value == 0xf0
133
+ when :programming, :chip_erase then nil
134
+ else command(offset, value)
135
+ end
136
+ end
137
+
138
+ private
139
+
140
+ def command(offset, value)
141
+ if value == 0xf0
142
+ @cycle = 0
143
+ return enter(:read, base: :read)
144
+ end
145
+
146
+ address = offset & @model.unlock_mask
147
+ @cycle = case @cycle
148
+ when 0, 3 then address == @model.unlock1 && value == 0xaa ? @cycle + 1 : 0
149
+ when 1, 4 then address == @model.unlock2 && value == 0x55 ? @cycle + 1 : 0
150
+ when 2 then command_cycle(address, value)
151
+ when 5 then erase_command(offset, address, value)
152
+ end
153
+ end
154
+
155
+ def command_cycle(address, value)
156
+ return 0 unless address == @model.unlock1
157
+
158
+ case value
159
+ when 0x90 then enter(:autoselect, base: :autoselect)
160
+ when 0xa0 then @state = :program_setup
161
+ when 0x80 then return 3
162
+ end
163
+ 0
164
+ end
165
+
166
+ def erase_command(offset, address, value)
167
+ if value == 0x10 && address == @model.unlock1
168
+ start_busy(:chip_erase, CHIP_ERASE_CYCLES)
169
+ elsif value == 0x30
170
+ @erasing_sectors = [sector(offset)]
171
+ start_busy(:erase_window, ERASE_WINDOW_CYCLES)
172
+ end
173
+ 0
174
+ end
175
+
176
+ def program(offset, value)
177
+ @programmed = value
178
+ @data[offset] &= value
179
+ if @data[offset] == value
180
+ start_busy(:programming, PROGRAM_CYCLES)
181
+ else
182
+ enter(:program_error)
183
+ end
184
+ end
185
+
186
+ def extend_erase(offset, value)
187
+ case value
188
+ when 0x30
189
+ @erasing_sectors |= [sector(offset)]
190
+ @done_at = now + ERASE_WINDOW_CYCLES
191
+ when 0xb0
192
+ @remaining = @erasing_sectors.length * SECTOR_ERASE_CYCLES
193
+ enter(:suspended)
194
+ else
195
+ @erasing_sectors = nil
196
+ enter(@base_state)
197
+ end
198
+ end
199
+
200
+ def suspend
201
+ @remaining = @done_at - now
202
+ enter(:suspended)
203
+ end
204
+
205
+ def resume
206
+ start_busy(:erasing, @remaining)
207
+ end
208
+
209
+ # Moves a timed operation on once the clock has passed its end.
210
+ def settle
211
+ return unless @done_at && now >= @done_at
212
+
213
+ case @state
214
+ when :erase_window
215
+ start_busy(:erasing, @done_at - now + (@erasing_sectors.length * SECTOR_ERASE_CYCLES))
216
+ settle
217
+ when :erasing
218
+ @erasing_sectors.each { |s| @data.fill(0xff, s * @model.sector_size, @model.sector_size) }
219
+ @erasing_sectors = nil
220
+ finish
221
+ when :chip_erase
222
+ @data.fill(0xff)
223
+ finish
224
+ else
225
+ finish
226
+ end
227
+ end
228
+
229
+ def finish
230
+ @done_at = nil
231
+ enter(@base_state)
232
+ end
233
+
234
+ def start_busy(state, cycles)
235
+ @done_at = now + cycles
236
+ @programmed = 0xff unless state == :programming
237
+ enter(state)
238
+ end
239
+
240
+ def enter(state, base: @base_state)
241
+ was_array = array_mode?
242
+ @state = state
243
+ @base_state = base
244
+ @done_at = nil unless %i[programming erase_window erasing chip_erase].include?(state)
245
+ @on_change&.call if was_array != array_mode?
246
+ end
247
+
248
+ def status
249
+ @toggle ^= 0x40
250
+ value = (~@programmed & 0x80) | @toggle
251
+ value |= 0x20 if @state == :program_error
252
+ value |= 0x08 if @state == :erasing || @state == :chip_erase
253
+ value
254
+ end
255
+
256
+ def suspended_read(offset)
257
+ @erasing_sectors.include?(sector(offset)) ? 0x80 : @data[offset]
258
+ end
259
+
260
+ def autoselect_code(offset)
261
+ case offset & 0x43
262
+ when 0 then @model.manufacturer
263
+ when 1 then @model.device
264
+ when 2 then 0x00
265
+ else @data[offset]
266
+ end
267
+ end
268
+
269
+ def sector(offset)
270
+ offset / @model.sector_size
271
+ end
272
+
273
+ def now
274
+ @clock.call
275
+ end
276
+ end
277
+ end
278
+ end
279
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Cartridge
6
+ # The freeze button of a freezer cartridge. A press pulls NMI, and the
7
+ # computer calls #freeze! once the CPU has pushed the return address and
8
+ # status of the interrupt, so the vector fetch that follows reads the
9
+ # cartridge ROM in Ultimax mode. The cartridge lets go of NMI when its
10
+ # software acknowledges the freeze.
11
+ module Freezer
12
+ def freezer? = true
13
+
14
+ def press_button
15
+ @button = true
16
+ self.nmi = true if freeze_allowed?
17
+ end
18
+
19
+ def release_button
20
+ @button = false
21
+ end
22
+
23
+ private
24
+
25
+ def freeze_allowed?
26
+ true
27
+ end
28
+
29
+ def button_pressed?
30
+ @button == true
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Cartridge
6
+ # Fun Play / Power Play: up to 16 8K banks. A write to I/O 1 selects the
7
+ # bank from bits 3-5 and 0, and either 8K mode ($00 in bits 7, 6, 2 and 1)
8
+ # or no ROM ($86 in those bits).
9
+ class FunPlay < Cartridge
10
+ def poke(addr, value)
11
+ return if addr > 0xdeff
12
+
13
+ @roml = bank(@banks, self.class.bank_number(value))
14
+ case value & 0xc6
15
+ when 0x00 then self.mode = :rom8k
16
+ when 0x86 then self.mode = :off
17
+ end
18
+ changed!
19
+ end
20
+
21
+ # The CRT file numbers each bank by the register value that selects it.
22
+ def reset
23
+ poke(0xde00, 0)
24
+ end
25
+
26
+ def self.bank_number(value)
27
+ ((value >> 3) & 0x07) | ((value & 0x01) << 3)
28
+ end
29
+
30
+ private
31
+
32
+ def install_chips(chips)
33
+ @banks = []
34
+ chips.each { |chip| @banks[self.class.bank_number(chip.bank)] = rom_bank(chip.data) }
35
+ reset
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Cartridge
6
+ # GMod2: an Am29F040 flash chip of 64 8K banks at ROML. A write to I/O 1
7
+ # selects the bank from bits 0-5. Bit 6 selects the EEPROM, which
8
+ # switches the ROM out, and bits 6 and 7 together enable flash writes:
9
+ # the cartridge then asserts Ultimax on write cycles only, so reads see
10
+ # the C64's memory and writes to $E000-$FFFF reach the flash. The EEPROM
11
+ # isn't emulated.
12
+ class GMod2 < Cartridge
13
+ BANKS = 64
14
+
15
+ attr_reader :flash
16
+
17
+ def clock=(clock)
18
+ super
19
+ @flash.clock = clock
20
+ end
21
+
22
+ def poke(addr, value)
23
+ return if addr > 0xdeff
24
+
25
+ @bank = value & 0x3f
26
+ @flash_writes = value.allbits?(0xc0)
27
+ self.mode = value.anybits?(0x40) ? :off : :rom8k
28
+ select_bank
29
+ end
30
+
31
+ def romh_writes
32
+ @roml if @flash_writes
33
+ end
34
+
35
+ # Reset selects the first bank in 8K mode, and leaves the flash as it
36
+ # is.
37
+ def reset
38
+ @bank = 0
39
+ @flash_writes = false
40
+ self.mode = :rom8k
41
+ select_bank
42
+ end
43
+
44
+ private
45
+
46
+ def select_bank
47
+ @roml = @flash.window(@bank * BANK_SIZE)
48
+ changed!
49
+ end
50
+
51
+ def save_mapper(out)
52
+ out.int(@bank).boolean(@flash_writes)
53
+ @flash.save_state(out)
54
+ end
55
+
56
+ def load_mapper(input)
57
+ @bank = input.int
58
+ @flash_writes = input.boolean?
59
+ @flash.load_state(input)
60
+ @roml = @flash.window(@bank * BANK_SIZE)
61
+ end
62
+
63
+ def install_chips(chips)
64
+ data = Array.new(BANKS * BANK_SIZE, 0xff)
65
+ chips.each do |chip|
66
+ bytes = chip.data.first(BANK_SIZE)
67
+ data[(chip.bank & 0x3f) * BANK_SIZE, bytes.length] = bytes
68
+ end
69
+ @flash = Flash.new(data, model: Flash::AM29F040)
70
+ @flash.on_change { select_bank }
71
+ reset
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Cartridge
6
+ # C64 Game System / System 3: up to 64 8K banks. Any access to
7
+ # $DE00-$DEFF selects the bank from the low six address bits; the data
8
+ # is ignored.
9
+ class GameSystem < Cartridge
10
+ def readable_io_pages
11
+ [0xde]
12
+ end
13
+
14
+ def peek(addr)
15
+ select(addr) if addr < 0xdf00
16
+ open_bus(addr)
17
+ end
18
+
19
+ def poke(addr, _value)
20
+ select(addr) if addr < 0xdf00
21
+ end
22
+
23
+ def reset
24
+ select(0)
25
+ end
26
+
27
+ private
28
+
29
+ def select(addr)
30
+ @roml = bank(@banks, addr & 0x3f)
31
+ changed!
32
+ end
33
+
34
+ def install_chips(chips)
35
+ @banks = banks_from(chips).first
36
+ self.mode = :rom8k
37
+ reset
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Cartridge
6
+ # GEO-RAM: a RAM expansion on the expansion port, seen through a 256-byte
7
+ # window at $DE00-$DEFF. Two write-only registers pick the page the
8
+ # window shows: $DFFE selects one of the 64 pages of a 16K block, and
9
+ # $DFFF selects the block. As in VICE, the registers answer at every
10
+ # address from $DF80 up, even for $DFFE and odd for $DFFF, and the block
11
+ # number wraps at the number of blocks the RAM holds. Reads of I/O 2 are
12
+ # open bus. It leaves EXROM and GAME high, and RES clears both
13
+ # registers.
14
+ class GeoRAM < Cartridge
15
+ SIZES = [64, 128, 256, 512, 1024, 2048, 4096].freeze
16
+ BLOCK_SIZE = 0x4000
17
+ PAGE_MASK = 0x3f
18
+
19
+ attr_reader :size
20
+
21
+ # size is the RAM in kilobytes.
22
+ def initialize(size: 512)
23
+ raise ArgumentError, "Unsupported GEO-RAM size #{size}K" unless SIZES.include?(size)
24
+
25
+ @size = size
26
+ @block_mask = ((size * 1024) / BLOCK_SIZE) - 1
27
+ super(Storage::CRTFile::Image.new(hardware_type: nil, subtype: 0, exrom: 1, game: 1,
28
+ name: "GEO-RAM", chips: []))
29
+ end
30
+
31
+ def readable_io_pages
32
+ [0xde]
33
+ end
34
+
35
+ def peek(addr)
36
+ @ram_data[@window + (addr & 0xff)]
37
+ end
38
+
39
+ def poke(addr, value)
40
+ if addr <= 0xdeff
41
+ @ram_data[@window + (addr & 0xff)] = value
42
+ elsif addr >= 0xdf80
43
+ if addr.odd?
44
+ @block = value & @block_mask
45
+ else
46
+ @page = value & PAGE_MASK
47
+ end
48
+ @window = (@block * BLOCK_SIZE) + (@page * 0x100)
49
+ end
50
+ end
51
+
52
+ def reset
53
+ @block = @page = @window = 0
54
+ end
55
+
56
+ # A GEO-RAM is built from its size alone.
57
+ def save_setup(out)
58
+ out.int(GEO_RAM_SETUP).int(@size)
59
+ end
60
+
61
+ private
62
+
63
+ def save_mapper(out)
64
+ out.blob(@ram_data).int(@block).int(@page).int(@window)
65
+ end
66
+
67
+ def load_mapper(input)
68
+ input.blob_into(@ram_data)
69
+ @block = input.int
70
+ @page = input.int
71
+ @window = input.int
72
+ end
73
+
74
+ def install_chips(_chips)
75
+ @ram_data = Array.new(@size * 1024, 0)
76
+ reset
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Cartridge
6
+ # The KCS Power Cartridge: 16K of ROM, 128 bytes of RAM and a freeze
7
+ # button. It boots in 16K mode, and any access to I/O 1 sets the lines
8
+ # from address bit 1 and the direction:
9
+ #
10
+ # read, bit 1 clear 8K
11
+ # read, bit 1 set off
12
+ # write, bit 1 clear 16K
13
+ # write, bit 1 set Ultimax
14
+ #
15
+ # A read of I/O 1 returns the second last page of ROML. I/O 2 holds the
16
+ # RAM in its lower half, and the upper half reads the EXROM line in bit 7
17
+ # and GAME in bit 6, which the freezer checks to find the mode it
18
+ # interrupted. A freeze switches to Ultimax and lets go of NMI.
19
+ class KCSPower < Cartridge
20
+ include Freezer
21
+
22
+ IO1_ROM_PAGE = 0x1e00
23
+
24
+ def readable_io_pages
25
+ [0xde, 0xdf]
26
+ end
27
+
28
+ def peek(addr)
29
+ if addr < 0xdf00
30
+ select_mode(addr.anybits?(0x02) ? :off : :rom8k)
31
+ @roml.peek(IO1_ROM_PAGE | (addr & 0xff))
32
+ elsif addr.anybits?(0x80)
33
+ (@exrom << 7) | (@game << 6) | (open_bus(addr) & 0x3f)
34
+ else
35
+ @io_ram[addr & 0x7f]
36
+ end
37
+ end
38
+
39
+ def poke(addr, value)
40
+ if addr < 0xdf00
41
+ select_mode(addr.anybits?(0x02) ? :ultimax : :rom16k)
42
+ elsif addr.nobits?(0x80)
43
+ @io_ram[addr & 0x7f] = value
44
+ end
45
+ end
46
+
47
+ def reset
48
+ self.nmi = false
49
+ select_mode(:rom16k)
50
+ end
51
+
52
+ def freeze!
53
+ self.nmi = false
54
+ select_mode(:ultimax)
55
+ end
56
+
57
+ private
58
+
59
+ def save_mapper(out)
60
+ out.blob(@io_ram)
61
+ end
62
+
63
+ def load_mapper(input)
64
+ input.blob_into(@io_ram)
65
+ end
66
+
67
+ def install_chips(chips)
68
+ roml, romh = banks_from(chips)
69
+ @roml = roml.first || EMPTY_BANK
70
+ @romh = romh.first || EMPTY_BANK
71
+ @io_ram = Array.new(0x80, 0xff)
72
+ reset
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Cartridge
6
+ # 8K. Writing I/O 1 switches the ROM in, writing I/O 2 switches it out.
7
+ # Both I/O pages read the last 512 bytes of the ROM.
8
+ class Mach5 < Cartridge
9
+ def readable_io_pages
10
+ [0xde, 0xdf]
11
+ end
12
+
13
+ def peek(addr)
14
+ @roml.peek(addr)
15
+ end
16
+
17
+ def poke(addr, _value)
18
+ select_mode(addr < 0xdf00 ? :rom8k : :off)
19
+ end
20
+
21
+ def reset
22
+ select_mode(:rom8k)
23
+ end
24
+
25
+ private
26
+
27
+ def install_chips(chips)
28
+ @roml = banks_from(chips).first.compact.first || EMPTY_BANK
29
+ reset
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Cartridge
6
+ # Magic Desk: up to 128 8K banks. A write to I/O 1 selects the bank from
7
+ # bits 0-6, masked to the size of the ROM and at least four banks, and
8
+ # switches the ROM out with bit 7.
9
+ class MagicDesk < Cartridge
10
+ def poke(addr, value)
11
+ return if addr > 0xdeff
12
+
13
+ @exrom = value.anybits?(0x80) ? 1 : 0
14
+ @roml = bank(@banks, value & @bank_mask)
15
+ changed!
16
+ end
17
+
18
+ def reset
19
+ poke(0xde00, 0)
20
+ end
21
+
22
+ private
23
+
24
+ def install_chips(chips)
25
+ @banks = banks_from(chips).first
26
+ @bank_mask = (bank_mask(@banks) | 0x03) & 0x7f
27
+ reset
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end