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,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Cartridge
6
+ # Epyx FastLoad: 8K. A capacitor holds the ROM in for 512 cycles after
7
+ # it was last discharged, by reset, a read through ROML or a read of
8
+ # I/O 1; once it charges, $8000-$9FFF reads RAM. I/O 2 reads the last
9
+ # 256 bytes of the ROM.
10
+ class EpyxFastload < Cartridge
11
+ DISCHARGED_CYCLES = 512
12
+
13
+ class Window
14
+ def initialize(cartridge, rom)
15
+ @cartridge = cartridge
16
+ @rom = rom
17
+ end
18
+
19
+ def peek(addr)
20
+ @cartridge.rom_visible? ? @rom.peek(addr) : @cartridge.ram_peek(addr)
21
+ end
22
+ end
23
+
24
+ def clock=(clock)
25
+ super
26
+ discharge!
27
+ end
28
+
29
+ def readable_io_pages
30
+ [0xde, 0xdf]
31
+ end
32
+
33
+ def peek(addr)
34
+ return @rom.peek(addr) if addr >= 0xdf00
35
+
36
+ discharge!
37
+ open_bus(addr)
38
+ end
39
+
40
+ # True while the capacitor holds the ROM in, discharging it again.
41
+ def rom_visible?
42
+ return true unless @clock
43
+ return false if @clock.call - @discharged_at >= DISCHARGED_CYCLES
44
+
45
+ discharge!
46
+ true
47
+ end
48
+
49
+ def ram_peek(addr)
50
+ @ram.peek(addr)
51
+ end
52
+
53
+ # Reset discharges the capacitor, so the ROM shows.
54
+ def reset
55
+ discharge!
56
+ end
57
+
58
+ private
59
+
60
+ def save_mapper(out)
61
+ out.int(@discharged_at)
62
+ end
63
+
64
+ def load_mapper(input)
65
+ @discharged_at = input.int
66
+ end
67
+
68
+ def discharge!
69
+ @discharged_at = @clock ? @clock.call : 0
70
+ end
71
+
72
+ def install_chips(chips)
73
+ @rom = banks_from(chips).first.compact.first || EMPTY_BANK
74
+ @roml = Window.new(self, @rom)
75
+ @discharged_at = 0
76
+ self.mode = :rom8k
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Cartridge
6
+ # The Final Cartridge III: four 16K banks, or sixteen on the III+. I/O 1
7
+ # and I/O 2 show the last two pages of the selected ROML bank. A write
8
+ # to $DFFF sets the register:
9
+ #
10
+ # bits 0-1 bank (0-3 on the III+)
11
+ # bit 4 EXROM level
12
+ # bit 5 GAME level
13
+ # bit 6 NMI line, active low
14
+ # bit 7 hides the register until the next freeze
15
+ #
16
+ # Clearing bit 6 pulls NMI without freezing, and setting it lets go of
17
+ # NMI after a freeze. A freeze keeps the bank and switches to Ultimax,
18
+ # which the VIC doesn't see until the register sets it again.
19
+ class FinalCartridge3 < Cartridge
20
+ include Freezer
21
+
22
+ REGISTER = 0xdfff
23
+
24
+ def readable_io_pages
25
+ [0xde, 0xdf]
26
+ end
27
+
28
+ def peek(addr)
29
+ @io_bank.peek(addr)
30
+ end
31
+
32
+ def poke(addr, value)
33
+ return unless addr == REGISTER && @register_visible
34
+
35
+ @register_visible = value.nobits?(0x80)
36
+ self.nmi = value.nobits?(0x40)
37
+ select(value & @bank_mask)
38
+ @exrom = (value >> 4) & 0x01
39
+ @game = (value >> 5) & 0x01
40
+ @phi1_ultimax = ultimax?
41
+ changed!
42
+ end
43
+
44
+ def phi1_ultimax?
45
+ @phi1_ultimax
46
+ end
47
+
48
+ def reset
49
+ @register_visible = true
50
+ @phi1_ultimax = false
51
+ self.nmi = false
52
+ select(0)
53
+ select_mode(:rom16k)
54
+ end
55
+
56
+ def freeze!
57
+ @register_visible = true
58
+ @phi1_ultimax = false
59
+ select_mode(:ultimax)
60
+ end
61
+
62
+ private
63
+
64
+ def save_mapper(out)
65
+ super
66
+ out.boolean(@register_visible).boolean(@phi1_ultimax)
67
+ end
68
+
69
+ def load_mapper(input)
70
+ super
71
+ @io_bank = @roml
72
+ @register_visible = input.boolean?
73
+ @phi1_ultimax = input.boolean?
74
+ end
75
+
76
+ def windows = [*@roml_banks, *@romh_banks, EMPTY_BANK]
77
+
78
+ def select(number)
79
+ @io_bank = @roml = bank(@roml_banks, number)
80
+ @romh = bank(@romh_banks, number)
81
+ end
82
+
83
+ def install_chips(chips)
84
+ @roml_banks, @romh_banks = banks_from(chips)
85
+ @bank_mask = @roml_banks.length > 4 ? 0x0f : 0x03
86
+ reset
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ class C64
5
+ class Cartridge
6
+ class Flash
7
+ # A Flash chip's state, for a snapshot.
8
+ module SavedState
9
+ STATES = %i[read program_setup autoselect programming erase_window erasing suspended chip_erase
10
+ program_error].freeze
11
+
12
+ # The array, the command state, a timed operation's end on the
13
+ # machine's clock, and the windows handed out so far, which load_state
14
+ # builds anew.
15
+ def save_state(out)
16
+ out.blob(@data).int(STATES.index(@state)).int(STATES.index(@base_state)).int(@cycle).int(@toggle)
17
+ out.optional_int(@done_at).optional_int(@programmed).optional_int(@remaining)
18
+ out.boolean(!@erasing_sectors.nil?)
19
+ out.ints(@erasing_sectors) if @erasing_sectors
20
+ out.ints(@windows.keys).ints(@status_windows.keys)
21
+ end
22
+
23
+ def load_state(input)
24
+ input.blob_into(@data)
25
+ @state = STATES.fetch(input.int).to_sym
26
+ @base_state = STATES.fetch(input.int).to_sym
27
+ @cycle = input.int
28
+ @toggle = input.int
29
+ @done_at = input.optional_int
30
+ @programmed = input.optional_int
31
+ @remaining = input.optional_int
32
+ @erasing_sectors = nil
33
+ @erasing_sectors = input.ints if input.boolean?
34
+ rebuild_windows(input.ints, input.ints)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -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