badline 0.12.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (565) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -1
  3. data/CLAUDE.md +86 -38
  4. data/CONTRIBUTING.md +4 -3
  5. data/README.md +9 -6
  6. data/doc/library.md +9 -9
  7. data/doc/media.md +2 -1
  8. data/doc/pinned-behaviour.md +134 -105
  9. data/doc/snapshot-format.md +1047 -0
  10. data/doc/snapshots.md +73 -43
  11. data/lib/badline/audio/bare_player.rb +53 -20
  12. data/lib/badline/audio/cli.rb +6 -6
  13. data/lib/badline/audio/jukebox.rb +2 -2
  14. data/lib/badline/audio/machine_player.rb +16 -10
  15. data/lib/badline/{media → audio}/queue.rb +1 -1
  16. data/lib/badline/audio/queued_tune.rb +6 -6
  17. data/lib/badline/audio/renderer.rb +33 -22
  18. data/lib/badline/audio/stereo.rb +1 -1
  19. data/lib/badline/c128/banks.rb +6 -3
  20. data/lib/badline/c128/bus/keyed_state.rb +45 -0
  21. data/lib/badline/c128/bus.rb +35 -20
  22. data/lib/badline/c128/color_lines.rb +2 -2
  23. data/lib/badline/c128/cpu.rb +1 -1
  24. data/lib/badline/c128/drives.rb +14 -34
  25. data/lib/badline/c128/fast_serial.rb +5 -5
  26. data/lib/badline/c128/keyed_modules.rb +117 -0
  27. data/lib/badline/c128/keyed_state.rb +91 -0
  28. data/lib/badline/c128/keys.rb +9 -0
  29. data/lib/badline/c128/mmu.rb +9 -8
  30. data/lib/badline/c128/mmu_pages.rb +21 -1
  31. data/lib/badline/c128/modes.rb +21 -11
  32. data/lib/badline/c128/z80.rb +2 -2
  33. data/lib/badline/c128/z80_turns.rb +1 -1
  34. data/lib/badline/c128.rb +21 -16
  35. data/lib/badline/c64/attachments.rb +42 -0
  36. data/lib/badline/c64/banked_ram/banking.rb +32 -0
  37. data/lib/badline/c64/banked_ram/plus256k.rb +64 -0
  38. data/lib/badline/c64/banked_ram/plus60k.rb +47 -0
  39. data/lib/badline/c64/banked_ram/unexpanded.rb +30 -0
  40. data/lib/badline/c64/banked_ram.rb +23 -0
  41. data/lib/badline/c64/bus/debug_register.rb +32 -0
  42. data/lib/badline/c64/bus/extra_sids.rb +32 -0
  43. data/lib/badline/c64/bus/fittings.rb +40 -0
  44. data/lib/badline/c64/bus/keyed_state.rb +41 -0
  45. data/lib/badline/c64/bus/pla.rb +149 -0
  46. data/lib/badline/c64/bus/roms.rb +41 -0
  47. data/lib/badline/c64/bus/sid_slots.rb +44 -0
  48. data/lib/badline/c64/bus.rb +219 -0
  49. data/lib/badline/c64/cartridge/action_replay.rb +115 -0
  50. data/lib/badline/c64/cartridge/atomic_power.rb +26 -0
  51. data/lib/badline/c64/cartridge/bank.rb +83 -0
  52. data/lib/badline/c64/cartridge/comal80.rb +52 -0
  53. data/lib/badline/c64/cartridge/dinamic.rb +36 -0
  54. data/lib/badline/c64/cartridge/easy_flash.rb +132 -0
  55. data/lib/badline/c64/cartridge/epyx_fastload.rb +73 -0
  56. data/lib/badline/c64/cartridge/final_cartridge3.rb +79 -0
  57. data/lib/badline/c64/cartridge/flash.rb +279 -0
  58. data/lib/badline/c64/cartridge/freezer.rb +35 -0
  59. data/lib/badline/c64/cartridge/fun_play.rb +40 -0
  60. data/lib/badline/c64/cartridge/g_mod2.rb +64 -0
  61. data/lib/badline/c64/cartridge/game_system.rb +42 -0
  62. data/lib/badline/c64/cartridge/geo_ram.rb +65 -0
  63. data/lib/badline/c64/cartridge/kcs_power.rb +69 -0
  64. data/lib/badline/c64/cartridge/keyed_state.rb +393 -0
  65. data/lib/badline/c64/cartridge/mach5.rb +34 -0
  66. data/lib/badline/c64/cartridge/magic_desk.rb +32 -0
  67. data/lib/badline/c64/cartridge/ocean.rb +37 -0
  68. data/lib/badline/c64/cartridge/pagefox.rb +60 -0
  69. data/lib/badline/c64/cartridge/retro_replay.rb +278 -0
  70. data/lib/badline/c64/cartridge/rex_utility.rb +31 -0
  71. data/lib/badline/c64/cartridge/rgcd.rb +50 -0
  72. data/lib/badline/c64/cartridge/simons_basic.rb +37 -0
  73. data/lib/badline/c64/cartridge/standard.rb +17 -0
  74. data/lib/badline/c64/cartridge/super_games.rb +40 -0
  75. data/lib/badline/c64/cartridge/westermann.rb +32 -0
  76. data/lib/badline/c64/cartridge/zaxxon.rb +52 -0
  77. data/lib/badline/c64/cartridge.rb +232 -0
  78. data/lib/badline/c64/color_memory.rb +27 -0
  79. data/lib/badline/{computer → c64}/common.rb +2 -2
  80. data/lib/badline/{computer → c64}/kernal_traps.rb +39 -36
  81. data/lib/badline/c64/keyed_modules.rb +111 -0
  82. data/lib/badline/c64/keyed_state.rb +68 -0
  83. data/lib/badline/c64/reu/dma.rb +271 -0
  84. data/lib/badline/c64/reu/keyed_state.rb +140 -0
  85. data/lib/badline/c64/reu/ram.rb +94 -0
  86. data/lib/badline/c64/reu/trigger.rb +34 -0
  87. data/lib/badline/c64/reu.rb +289 -0
  88. data/lib/badline/c64/true_drives.rb +120 -0
  89. data/lib/badline/{computer.rb → c64.rb} +24 -15
  90. data/lib/badline/chips/cia/fast_forward.rb +62 -0
  91. data/lib/badline/chips/cia/interrupt_register.rb +128 -0
  92. data/lib/badline/chips/cia/keyed_parts.rb +213 -0
  93. data/lib/badline/chips/cia/serial.rb +246 -0
  94. data/lib/badline/chips/cia/time_of_day.rb +210 -0
  95. data/lib/badline/chips/cia/timer.rb +188 -0
  96. data/lib/badline/chips/cia.rb +281 -0
  97. data/lib/badline/chips/cpu/addressing.rb +133 -0
  98. data/lib/badline/chips/cpu/boundary.rb +56 -0
  99. data/lib/badline/chips/cpu/core.rb +183 -0
  100. data/lib/badline/chips/cpu/instruction.rb +338 -0
  101. data/lib/badline/chips/cpu/instruction_set/arithmetic.rb +118 -0
  102. data/lib/badline/chips/cpu/instruction_set/bitwise.rb +130 -0
  103. data/lib/badline/chips/cpu/instruction_set/branch.rb +83 -0
  104. data/lib/badline/chips/cpu/instruction_set/flag.rb +67 -0
  105. data/lib/badline/chips/cpu/instruction_set/illegal.rb +274 -0
  106. data/lib/badline/chips/cpu/instruction_set/inc_dec.rb +73 -0
  107. data/lib/badline/chips/cpu/instruction_set/stack.rb +56 -0
  108. data/lib/badline/chips/cpu/instruction_set/transfer.rb +141 -0
  109. data/lib/badline/chips/cpu/instruction_set.rb +59 -0
  110. data/lib/badline/chips/cpu/interrupts.rb +108 -0
  111. data/lib/badline/chips/cpu/keyed_state.rb +177 -0
  112. data/lib/badline/chips/cpu/microcode.rb +195 -0
  113. data/lib/badline/chips/cpu/operations.rb +90 -0
  114. data/lib/badline/chips/cpu/port.rb +133 -0
  115. data/lib/badline/chips/cpu/stack_operations.rb +84 -0
  116. data/lib/badline/chips/cpu/traps.rb +23 -0
  117. data/lib/badline/chips/cpu.rb +17 -0
  118. data/lib/badline/chips/sid/catch_up.rb +122 -0
  119. data/lib/badline/chips/sid/decimator.rb +68 -0
  120. data/lib/badline/chips/sid/envelope.rb +236 -0
  121. data/lib/badline/chips/sid/filter.rb +227 -0
  122. data/lib/badline/chips/sid/keyed_parts.rb +286 -0
  123. data/lib/badline/chips/sid/voice.rb +69 -0
  124. data/lib/badline/chips/sid/waveform/combined.rb +128 -0
  125. data/lib/badline/chips/sid/waveform/fast_forward.rb +107 -0
  126. data/lib/badline/chips/sid/waveform/noise_writeback.rb +124 -0
  127. data/lib/badline/chips/sid/waveform.rb +305 -0
  128. data/lib/badline/chips/sid.rb +264 -0
  129. data/lib/badline/chips/ted/beam.rb +119 -0
  130. data/lib/badline/chips/ted/timers.rb +66 -0
  131. data/lib/badline/chips/ted.rb +143 -0
  132. data/lib/badline/chips/tia.rb +49 -0
  133. data/lib/badline/chips/vdc/keyed_parts.rb +105 -0
  134. data/lib/badline/{c128 → chips}/vdc/memory.rb +1 -1
  135. data/lib/badline/{c128 → chips}/vdc/painter.rb +1 -13
  136. data/lib/badline/{c128 → chips}/vdc/raster.rb +1 -17
  137. data/lib/badline/{c128 → chips}/vdc/window.rb +1 -10
  138. data/lib/badline/{c128 → chips}/vdc.rb +6 -31
  139. data/lib/badline/chips/via/control_lines.rb +109 -0
  140. data/lib/badline/chips/via/fast_forward.rb +55 -0
  141. data/lib/badline/chips/via/interrupt_register.rb +60 -0
  142. data/lib/badline/chips/via/keyed_parts.rb +163 -0
  143. data/lib/badline/chips/via/shift_register.rb +168 -0
  144. data/lib/badline/chips/via/timer1.rb +120 -0
  145. data/lib/badline/chips/via/timer2.rb +117 -0
  146. data/lib/badline/chips/via.rb +267 -0
  147. data/lib/badline/chips/vic/bank.rb +135 -0
  148. data/lib/badline/chips/vic/border_mask.rb +78 -0
  149. data/lib/badline/chips/vic/collisions.rb +106 -0
  150. data/lib/badline/chips/vic/color_patches.rb +38 -0
  151. data/lib/badline/chips/vic/display_state.rb +168 -0
  152. data/lib/badline/chips/vic/graphics_mode.rb +166 -0
  153. data/lib/badline/chips/vic/graphics_shifter.rb +183 -0
  154. data/lib/badline/chips/vic/keyed_parts.rb +228 -0
  155. data/lib/badline/chips/vic/keyed_sprites.rb +225 -0
  156. data/lib/badline/chips/vic/keyed_state.rb +102 -0
  157. data/lib/badline/chips/vic/register_log.rb +65 -0
  158. data/lib/badline/chips/vic/registers.rb +188 -0
  159. data/lib/badline/chips/vic/sequencer.rb +275 -0
  160. data/lib/badline/chips/vic/sequencer_output.rb +118 -0
  161. data/lib/badline/chips/vic/sprite/internal_bus.rb +59 -0
  162. data/lib/badline/chips/vic/sprite/shifter.rb +148 -0
  163. data/lib/badline/chips/vic/sprite/timing.rb +58 -0
  164. data/lib/badline/chips/vic/sprite.rb +337 -0
  165. data/lib/badline/chips/vic/sprites.rb +281 -0
  166. data/lib/badline/chips/vic.rb +787 -0
  167. data/lib/badline/chips/vic_i/keyed_parts.rb +142 -0
  168. data/lib/badline/{vic20/vic → chips/vic_i}/painter.rb +2 -30
  169. data/lib/badline/chips/vic_i/sound/output.rb +85 -0
  170. data/lib/badline/chips/vic_i/sound.rb +227 -0
  171. data/lib/badline/{vic20/vic → chips/vic_i}/text_window.rb +2 -2
  172. data/lib/badline/{vic20/vic.rb → chips/vic_i.rb} +6 -6
  173. data/lib/badline/chips/z80/arithmetic.rb +119 -0
  174. data/lib/badline/chips/z80/bit_page.rb +57 -0
  175. data/lib/badline/chips/z80/block_io.rb +60 -0
  176. data/lib/badline/chips/z80/block_transfers.rb +61 -0
  177. data/lib/badline/chips/z80/bus_cycles.rb +113 -0
  178. data/lib/badline/chips/z80/core.rb +115 -0
  179. data/lib/badline/chips/z80/exchanges.rb +52 -0
  180. data/lib/badline/chips/z80/extended_page.rb +91 -0
  181. data/lib/badline/chips/z80/flags.rb +39 -0
  182. data/lib/badline/chips/z80/interrupt_acceptance.rb +48 -0
  183. data/lib/badline/chips/z80/jumps.rb +84 -0
  184. data/lib/badline/chips/z80/keyed_state.rb +73 -0
  185. data/lib/badline/chips/z80/loads.rb +100 -0
  186. data/lib/badline/chips/z80/main_page.rb +136 -0
  187. data/lib/badline/chips/z80/registers.rb +122 -0
  188. data/lib/badline/chips/z80/shifts.rb +66 -0
  189. data/lib/badline/chips/z80.rb +13 -0
  190. data/lib/badline/chips.rb +10 -0
  191. data/lib/badline/core.rb +13 -32
  192. data/lib/badline/drives/datasette/keyed_state.rb +38 -0
  193. data/lib/badline/drives/datasette.rb +173 -0
  194. data/lib/badline/drives/engine/core.rb +152 -0
  195. data/lib/badline/drives/engine/fast_serial.rb +75 -0
  196. data/lib/badline/drives/engine/idle.rb +127 -0
  197. data/lib/badline/drives/engine/idle_cpu.rb +30 -0
  198. data/lib/badline/drives/engine/orbit.rb +81 -0
  199. data/lib/badline/drives/engine/serial_lines.rb +72 -0
  200. data/lib/badline/drives/engine/sleep.rb +114 -0
  201. data/lib/badline/drives/engine/vias.rb +86 -0
  202. data/lib/badline/drives/engine/watch.rb +152 -0
  203. data/lib/badline/drives/engine.rb +11 -0
  204. data/lib/badline/drives/model1541/bus.rb +75 -0
  205. data/lib/badline/drives/model1541/byte_ready.rb +50 -0
  206. data/lib/badline/drives/model1541/cpu.rb +13 -0
  207. data/lib/badline/drives/model1541/disk.rb +318 -0
  208. data/lib/badline/drives/model1541/disk_via.rb +38 -0
  209. data/lib/badline/drives/model1541/gcr.rb +59 -0
  210. data/lib/badline/drives/model1541/keyed_state.rb +251 -0
  211. data/lib/badline/drives/model1541/mechanism.rb +313 -0
  212. data/lib/badline/drives/model1541/rotation.rb +123 -0
  213. data/lib/badline/drives/model1541/sector_reader.rb +78 -0
  214. data/lib/badline/drives/model1541/serial_port.rb +20 -0
  215. data/lib/badline/drives/model1541/track.rb +100 -0
  216. data/lib/badline/drives/model1541.rb +80 -0
  217. data/lib/badline/drives/model1571/bus.rb +100 -0
  218. data/lib/badline/drives/model1571/cpu.rb +13 -0
  219. data/lib/badline/drives/model1571/keyed_state.rb +108 -0
  220. data/lib/badline/drives/model1571/serial_port.rb +39 -0
  221. data/lib/badline/drives/model1571/serial_via.rb +27 -0
  222. data/lib/badline/drives/model1571/wd1770.rb +108 -0
  223. data/lib/badline/drives/model1571.rb +141 -0
  224. data/lib/badline/drives/model1581/bus.rb +126 -0
  225. data/lib/badline/drives/model1581/cpu.rb +13 -0
  226. data/lib/badline/drives/model1581/disk.rb +133 -0
  227. data/lib/badline/drives/model1581/keyed_state.rb +280 -0
  228. data/lib/badline/drives/model1581/mechanism.rb +98 -0
  229. data/lib/badline/drives/model1581/serial_port.rb +54 -0
  230. data/lib/badline/drives/model1581/slot.rb +61 -0
  231. data/lib/badline/drives/model1581/track.rb +102 -0
  232. data/lib/badline/drives/model1581/track_bytes.rb +77 -0
  233. data/lib/badline/drives/model1581/wd1772/registers.rb +91 -0
  234. data/lib/badline/drives/model1581/wd1772/sector_writes.rb +75 -0
  235. data/lib/badline/drives/model1581/wd1772/sectors.rb +152 -0
  236. data/lib/badline/drives/model1581/wd1772/stepping.rb +111 -0
  237. data/lib/badline/drives/model1581/wd1772/tracks.rb +127 -0
  238. data/lib/badline/drives/model1581/wd1772/turn.rb +75 -0
  239. data/lib/badline/drives/model1581/wd1772.rb +216 -0
  240. data/lib/badline/drives/model1581.rb +206 -0
  241. data/lib/badline/drives/serial_bus.rb +161 -0
  242. data/lib/badline/drives.rb +8 -0
  243. data/lib/badline/frontend/app.rb +3 -3
  244. data/lib/badline/frontend/boot.rb +4 -4
  245. data/lib/badline/frontend/controls.rb +19 -3
  246. data/lib/badline/frontend/drive_led.rb +44 -21
  247. data/lib/badline/frontend/machine_window.rb +3 -1
  248. data/lib/badline/frontend/menu/menu_dialogs.rb +2 -2
  249. data/lib/badline/frontend/player/filter_view.rb +1 -1
  250. data/lib/badline/frontend/player/player_controller.rb +2 -2
  251. data/lib/badline/frontend/player/player_screen.rb +1 -0
  252. data/lib/badline/frontend/player/theme.rb +7 -7
  253. data/lib/badline/frontend/snapshots.rb +12 -1
  254. data/lib/badline/frontend/timeline.rb +30 -12
  255. data/lib/badline/input/control_ports.rb +78 -0
  256. data/lib/badline/input/joystick.rb +27 -0
  257. data/lib/badline/input/keyboard.rb +114 -0
  258. data/lib/badline/input/matrix_typist.rb +98 -0
  259. data/lib/badline/input.rb +4 -0
  260. data/lib/badline/kernal_trap/chrout.rb +45 -0
  261. data/lib/badline/kernal_trap/{drive → dos}/block_commands.rb +1 -1
  262. data/lib/badline/kernal_trap/dos/channel.rb +156 -0
  263. data/lib/badline/kernal_trap/{drive → dos}/channels.rb +1 -26
  264. data/lib/badline/kernal_trap/{drive → dos}/memory.rb +1 -10
  265. data/lib/badline/kernal_trap/{drive → dos}/parameters.rb +1 -1
  266. data/lib/badline/kernal_trap/{drive → dos}/status.rb +1 -9
  267. data/lib/badline/kernal_trap/{drive → dos}/write_file.rb +1 -19
  268. data/lib/badline/kernal_trap/{drive → dos}/writes.rb +1 -1
  269. data/lib/badline/kernal_trap/{drive.rb → dos.rb} +9 -27
  270. data/lib/badline/kernal_trap/file_routine.rb +4 -4
  271. data/lib/badline/kernal_trap/keyed_state.rb +150 -0
  272. data/lib/badline/kernal_trap/layout.rb +75 -11
  273. data/lib/badline/kernal_trap/load.rb +19 -21
  274. data/lib/badline/kernal_trap/routine.rb +12 -0
  275. data/lib/badline/kernal_trap/save.rb +12 -22
  276. data/lib/badline/kernal_trap/serial.rb +8 -24
  277. data/lib/badline/kernal_trap.rb +3 -2
  278. data/lib/badline/machine/clocking.rb +1 -1
  279. data/lib/badline/machine/keyboard_buffer.rb +49 -0
  280. data/lib/badline/machine/settling.rb +29 -0
  281. data/lib/badline/machine.rb +10 -7
  282. data/lib/badline/media/boot_disk.rb +14 -2
  283. data/lib/badline/media/extensions.rb +10 -0
  284. data/lib/badline/media/true_drive.rb +1 -1
  285. data/lib/badline/media/tune.rb +2 -2
  286. data/lib/badline/media.rb +3 -3
  287. data/lib/badline/memory.rb +3 -6
  288. data/lib/badline/model.rb +1 -1
  289. data/lib/badline/options/family.rb +5 -2
  290. data/lib/badline/options/help.rb +42 -16
  291. data/lib/badline/options/table.rb +2 -0
  292. data/lib/badline/options/validation.rb +2 -0
  293. data/lib/badline/options.rb +6 -1
  294. data/lib/badline/plus4/acia.rb +45 -0
  295. data/lib/badline/plus4/bus.rb +312 -0
  296. data/lib/badline/plus4/cpu.rb +10 -0
  297. data/lib/badline/plus4/cpu_port.rb +93 -0
  298. data/lib/badline/plus4/keyboard_port.rb +51 -0
  299. data/lib/badline/plus4/model.rb +38 -0
  300. data/lib/badline/plus4/user_port.rb +31 -0
  301. data/lib/badline/plus4.rb +164 -0
  302. data/lib/badline/roms/README +44 -6
  303. data/lib/badline/roms/plus4/basic.rom +0 -0
  304. data/lib/badline/roms/plus4/function-high.rom +0 -0
  305. data/lib/badline/roms/plus4/function-low.rom +0 -0
  306. data/lib/badline/roms/plus4/kernal-ntsc.rom +0 -0
  307. data/lib/badline/roms/plus4/kernal-pal.rom +0 -0
  308. data/lib/badline/sdl.rb +1 -0
  309. data/lib/badline/{storage/sid_file.rb → sid_tune/file.rb} +3 -3
  310. data/lib/badline/{storage → sid_tune}/hvsc.rb +7 -7
  311. data/lib/badline/{storage → sid_tune}/song_lengths.rb +2 -2
  312. data/lib/badline/{storage → sid_tune}/stil/credit.rb +1 -1
  313. data/lib/badline/{storage → sid_tune}/stil.rb +3 -3
  314. data/lib/badline/sid_tune.rb +6 -0
  315. data/lib/badline/snapshot/c128_setup.rb +32 -0
  316. data/lib/badline/snapshot/c64_setup.rb +83 -0
  317. data/lib/badline/snapshot/container.rb +4 -0
  318. data/lib/badline/snapshot/field_doc/markdown.rb +112 -0
  319. data/lib/badline/snapshot/field_doc.rb +109 -0
  320. data/lib/badline/snapshot/image.rb +132 -46
  321. data/lib/badline/snapshot/keyed/cursor.rb +40 -0
  322. data/lib/badline/snapshot/keyed/modules.rb +66 -0
  323. data/lib/badline/snapshot/keyed/reader.rb +188 -0
  324. data/lib/badline/snapshot/keyed/recorder.rb +88 -0
  325. data/lib/badline/snapshot/keyed/report.rb +26 -0
  326. data/lib/badline/snapshot/keyed/writer.rb +55 -0
  327. data/lib/badline/snapshot/keyed.rb +64 -0
  328. data/lib/badline/snapshot/machine_state.rb +17 -64
  329. data/lib/badline/snapshot/storage_setup.rb +63 -0
  330. data/lib/badline/snapshot/vic20_setup.rb +28 -0
  331. data/lib/badline/snapshot/vice/c64_mem.rb +1 -1
  332. data/lib/badline/snapshot/vice/restore.rb +1 -1
  333. data/lib/badline/snapshot/vice/reu1764.rb +3 -3
  334. data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
  335. data/lib/badline/snapshot/vice.rb +13 -35
  336. data/lib/badline/snapshot.rb +44 -22
  337. data/lib/badline/storage/crt_file.rb +3 -1
  338. data/lib/badline/storage/d64_image.rb +0 -2
  339. data/lib/badline/storage/d71_image.rb +0 -2
  340. data/lib/badline/storage/d81_image.rb +0 -2
  341. data/lib/badline/storage/disk_image.rb +3 -6
  342. data/lib/badline/storage/g64_image.rb +10 -5
  343. data/lib/badline/storage/host_directory.rb +0 -5
  344. data/lib/badline/storage/t64.rb +2 -8
  345. data/lib/badline/storage/tap.rb +43 -15
  346. data/lib/badline/storage/unavailable.rb +1 -1
  347. data/lib/badline/storage.rb +0 -37
  348. data/lib/badline/support/c128_checkpoint.rb +39 -0
  349. data/lib/badline/support/checkpoint.rb +108 -0
  350. data/lib/badline/support/vic20_checkpoint.rb +38 -0
  351. data/lib/badline/support.rb +5 -0
  352. data/lib/badline/version.rb +1 -1
  353. data/lib/badline/vic20/attachments.rb +8 -5
  354. data/lib/badline/vic20/bus/keyed_state.rb +52 -0
  355. data/lib/badline/vic20/bus.rb +2 -25
  356. data/lib/badline/vic20/cpu.rb +1 -1
  357. data/lib/badline/vic20/keyed_modules.rb +73 -0
  358. data/lib/badline/vic20/keyed_state.rb +45 -0
  359. data/lib/badline/vic20/port_wiring.rb +4 -4
  360. data/lib/badline/vic20/user_via_ports.rb +2 -2
  361. data/lib/badline/vic20.rb +22 -17
  362. data/lib/badline.rb +1 -0
  363. metadata +271 -228
  364. data/lib/badline/address_bus/extra_sids.rb +0 -30
  365. data/lib/badline/address_bus/fittings.rb +0 -38
  366. data/lib/badline/address_bus/pla.rb +0 -147
  367. data/lib/badline/address_bus/roms.rb +0 -39
  368. data/lib/badline/address_bus/saved_state.rb +0 -66
  369. data/lib/badline/address_bus/sid_slots.rb +0 -42
  370. data/lib/badline/address_bus.rb +0 -216
  371. data/lib/badline/c128/bus_state.rb +0 -53
  372. data/lib/badline/c128/saved_state.rb +0 -143
  373. data/lib/badline/cartridge/action_replay.rb +0 -126
  374. data/lib/badline/cartridge/atomic_power.rb +0 -24
  375. data/lib/badline/cartridge/bank.rb +0 -81
  376. data/lib/badline/cartridge/comal80.rb +0 -50
  377. data/lib/badline/cartridge/dinamic.rb +0 -34
  378. data/lib/badline/cartridge/easy_flash.rb +0 -145
  379. data/lib/badline/cartridge/epyx_fastload.rb +0 -79
  380. data/lib/badline/cartridge/final_cartridge3.rb +0 -89
  381. data/lib/badline/cartridge/flash.rb +0 -306
  382. data/lib/badline/cartridge/freezer.rb +0 -33
  383. data/lib/badline/cartridge/fun_play.rb +0 -38
  384. data/lib/badline/cartridge/g_mod2.rb +0 -74
  385. data/lib/badline/cartridge/game_system.rb +0 -40
  386. data/lib/badline/cartridge/geo_ram.rb +0 -79
  387. data/lib/badline/cartridge/kcs_power.rb +0 -75
  388. data/lib/badline/cartridge/mach5.rb +0 -32
  389. data/lib/badline/cartridge/magic_desk.rb +0 -30
  390. data/lib/badline/cartridge/ocean.rb +0 -35
  391. data/lib/badline/cartridge/pagefox.rb +0 -68
  392. data/lib/badline/cartridge/retro_replay.rb +0 -320
  393. data/lib/badline/cartridge/rex_utility.rb +0 -29
  394. data/lib/badline/cartridge/rgcd.rb +0 -58
  395. data/lib/badline/cartridge/simons_basic.rb +0 -35
  396. data/lib/badline/cartridge/standard.rb +0 -15
  397. data/lib/badline/cartridge/super_games.rb +0 -48
  398. data/lib/badline/cartridge/westermann.rb +0 -30
  399. data/lib/badline/cartridge/zaxxon.rb +0 -66
  400. data/lib/badline/cartridge.rb +0 -303
  401. data/lib/badline/checkpoint.rb +0 -98
  402. data/lib/badline/chrout_trap.rb +0 -43
  403. data/lib/badline/cia/fast_forward.rb +0 -60
  404. data/lib/badline/cia/interrupt_register.rb +0 -143
  405. data/lib/badline/cia/serial.rb +0 -275
  406. data/lib/badline/cia/state.rb +0 -47
  407. data/lib/badline/cia/timer.rb +0 -206
  408. data/lib/badline/cia.rb +0 -279
  409. data/lib/badline/color_memory.rb +0 -25
  410. data/lib/badline/computer/attachments.rb +0 -88
  411. data/lib/badline/computer/saved_state.rb +0 -117
  412. data/lib/badline/computer/true_drives.rb +0 -69
  413. data/lib/badline/control_ports.rb +0 -76
  414. data/lib/badline/cpu/addressing.rb +0 -131
  415. data/lib/badline/cpu/boundary.rb +0 -54
  416. data/lib/badline/cpu/core.rb +0 -165
  417. data/lib/badline/cpu/microcode.rb +0 -177
  418. data/lib/badline/cpu/operations.rb +0 -88
  419. data/lib/badline/cpu/saved_state.rb +0 -115
  420. data/lib/badline/cpu/stack_operations.rb +0 -82
  421. data/lib/badline/cpu.rb +0 -10
  422. data/lib/badline/cpu_port.rb +0 -112
  423. data/lib/badline/datasette.rb +0 -161
  424. data/lib/badline/debug_register.rb +0 -28
  425. data/lib/badline/drive/core.rb +0 -147
  426. data/lib/badline/drive/fast_serial.rb +0 -73
  427. data/lib/badline/drive/idle.rb +0 -125
  428. data/lib/badline/drive/idle_cpu.rb +0 -28
  429. data/lib/badline/drive/orbit.rb +0 -79
  430. data/lib/badline/drive/serial_lines.rb +0 -73
  431. data/lib/badline/drive/sleep.rb +0 -112
  432. data/lib/badline/drive/vias.rb +0 -84
  433. data/lib/badline/drive/watch.rb +0 -150
  434. data/lib/badline/drive.rb +0 -11
  435. data/lib/badline/drive1541/bus.rb +0 -86
  436. data/lib/badline/drive1541/byte_ready.rb +0 -48
  437. data/lib/badline/drive1541/cpu.rb +0 -11
  438. data/lib/badline/drive1541/disk.rb +0 -315
  439. data/lib/badline/drive1541/disk_state.rb +0 -86
  440. data/lib/badline/drive1541/disk_via.rb +0 -36
  441. data/lib/badline/drive1541/gcr.rb +0 -57
  442. data/lib/badline/drive1541/mechanism.rb +0 -313
  443. data/lib/badline/drive1541/mechanism_state.rb +0 -68
  444. data/lib/badline/drive1541/rotation.rb +0 -121
  445. data/lib/badline/drive1541/sector_reader.rb +0 -76
  446. data/lib/badline/drive1541/serial_port.rb +0 -18
  447. data/lib/badline/drive1541/track.rb +0 -98
  448. data/lib/badline/drive1541.rb +0 -111
  449. data/lib/badline/drive1571/bus.rb +0 -111
  450. data/lib/badline/drive1571/cpu.rb +0 -11
  451. data/lib/badline/drive1571/serial_port.rb +0 -37
  452. data/lib/badline/drive1571/serial_via.rb +0 -25
  453. data/lib/badline/drive1571/wd1770.rb +0 -120
  454. data/lib/badline/drive1571.rb +0 -175
  455. data/lib/badline/drive1581/bus.rb +0 -137
  456. data/lib/badline/drive1581/cpu.rb +0 -11
  457. data/lib/badline/drive1581/disk.rb +0 -135
  458. data/lib/badline/drive1581/disk_state.rb +0 -87
  459. data/lib/badline/drive1581/mechanism.rb +0 -117
  460. data/lib/badline/drive1581/serial_port.rb +0 -52
  461. data/lib/badline/drive1581/slot.rb +0 -78
  462. data/lib/badline/drive1581/track.rb +0 -100
  463. data/lib/badline/drive1581/track_bytes.rb +0 -75
  464. data/lib/badline/drive1581/wd1772/registers.rb +0 -89
  465. data/lib/badline/drive1581/wd1772/sector_writes.rb +0 -73
  466. data/lib/badline/drive1581/wd1772/sectors.rb +0 -150
  467. data/lib/badline/drive1581/wd1772/state.rb +0 -66
  468. data/lib/badline/drive1581/wd1772/stepping.rb +0 -109
  469. data/lib/badline/drive1581/wd1772/tracks.rb +0 -125
  470. data/lib/badline/drive1581/wd1772/turn.rb +0 -73
  471. data/lib/badline/drive1581/wd1772.rb +0 -216
  472. data/lib/badline/drive1581.rb +0 -233
  473. data/lib/badline/iec_bus.rb +0 -159
  474. data/lib/badline/instruction.rb +0 -334
  475. data/lib/badline/instruction_set/arithmetic.rb +0 -114
  476. data/lib/badline/instruction_set/bitwise.rb +0 -126
  477. data/lib/badline/instruction_set/branch.rb +0 -79
  478. data/lib/badline/instruction_set/flag.rb +0 -63
  479. data/lib/badline/instruction_set/illegal.rb +0 -270
  480. data/lib/badline/instruction_set/inc_dec.rb +0 -69
  481. data/lib/badline/instruction_set/stack.rb +0 -52
  482. data/lib/badline/instruction_set/transfer.rb +0 -137
  483. data/lib/badline/instruction_set.rb +0 -55
  484. data/lib/badline/interrupts.rb +0 -104
  485. data/lib/badline/joystick.rb +0 -25
  486. data/lib/badline/kernal_trap/channel.rb +0 -181
  487. data/lib/badline/keyboard.rb +0 -112
  488. data/lib/badline/keyboard_buffer.rb +0 -33
  489. data/lib/badline/ram_expansion/banking.rb +0 -30
  490. data/lib/badline/ram_expansion/plus256k.rb +0 -54
  491. data/lib/badline/ram_expansion/plus60k.rb +0 -43
  492. data/lib/badline/ram_expansion/unexpanded.rb +0 -28
  493. data/lib/badline/ram_expansion.rb +0 -21
  494. data/lib/badline/reu/dma/saved_state.rb +0 -50
  495. data/lib/badline/reu/dma.rb +0 -273
  496. data/lib/badline/reu/ram.rb +0 -107
  497. data/lib/badline/reu/saved_state.rb +0 -80
  498. data/lib/badline/reu/trigger.rb +0 -32
  499. data/lib/badline/reu.rb +0 -289
  500. data/lib/badline/sid/catch_up.rb +0 -120
  501. data/lib/badline/sid/decimator.rb +0 -64
  502. data/lib/badline/sid/envelope/state.rb +0 -68
  503. data/lib/badline/sid/envelope.rb +0 -239
  504. data/lib/badline/sid/filter.rb +0 -263
  505. data/lib/badline/sid/voice.rb +0 -77
  506. data/lib/badline/sid/waveform/combined.rb +0 -126
  507. data/lib/badline/sid/waveform/fast_forward.rb +0 -105
  508. data/lib/badline/sid/waveform/noise_writeback.rb +0 -122
  509. data/lib/badline/sid/waveform/state.rb +0 -66
  510. data/lib/badline/sid/waveform.rb +0 -305
  511. data/lib/badline/sid.rb +0 -303
  512. data/lib/badline/snapshot/setup.rb +0 -75
  513. data/lib/badline/snapshot/state.rb +0 -189
  514. data/lib/badline/time_of_day.rb +0 -228
  515. data/lib/badline/traps.rb +0 -19
  516. data/lib/badline/via/control_lines.rb +0 -122
  517. data/lib/badline/via/fast_forward.rb +0 -53
  518. data/lib/badline/via/interrupt_register.rb +0 -67
  519. data/lib/badline/via/shift_register.rb +0 -180
  520. data/lib/badline/via/state.rb +0 -42
  521. data/lib/badline/via/timer1.rb +0 -131
  522. data/lib/badline/via/timer2.rb +0 -133
  523. data/lib/badline/via.rb +0 -266
  524. data/lib/badline/vic/bank.rb +0 -133
  525. data/lib/badline/vic/border_mask.rb +0 -86
  526. data/lib/badline/vic/collisions.rb +0 -115
  527. data/lib/badline/vic/color_patches.rb +0 -47
  528. data/lib/badline/vic/display_state.rb +0 -185
  529. data/lib/badline/vic/graphics_mode.rb +0 -164
  530. data/lib/badline/vic/graphics_shifter.rb +0 -207
  531. data/lib/badline/vic/register_log.rb +0 -81
  532. data/lib/badline/vic/registers.rb +0 -195
  533. data/lib/badline/vic/sequencer.rb +0 -275
  534. data/lib/badline/vic/sequencer_output.rb +0 -116
  535. data/lib/badline/vic/sequencer_state.rb +0 -89
  536. data/lib/badline/vic/sprite/internal_bus.rb +0 -68
  537. data/lib/badline/vic/sprite/saved_state.rb +0 -64
  538. data/lib/badline/vic/sprite/shifter.rb +0 -146
  539. data/lib/badline/vic/sprite/timing.rb +0 -56
  540. data/lib/badline/vic/sprite.rb +0 -337
  541. data/lib/badline/vic/sprites.rb +0 -282
  542. data/lib/badline/vic/sprites_state.rb +0 -57
  543. data/lib/badline/vic.rb +0 -853
  544. data/lib/badline/vic20/saved_state.rb +0 -124
  545. data/lib/badline/vic20/sound/output.rb +0 -83
  546. data/lib/badline/vic20/sound.rb +0 -233
  547. data/lib/badline/vic20/vic/saved_state.rb +0 -55
  548. data/lib/badline/z80/arithmetic.rb +0 -117
  549. data/lib/badline/z80/bit_page.rb +0 -55
  550. data/lib/badline/z80/block_io.rb +0 -58
  551. data/lib/badline/z80/block_transfers.rb +0 -59
  552. data/lib/badline/z80/bus_cycles.rb +0 -111
  553. data/lib/badline/z80/core.rb +0 -113
  554. data/lib/badline/z80/exchanges.rb +0 -50
  555. data/lib/badline/z80/extended_page.rb +0 -89
  556. data/lib/badline/z80/flags.rb +0 -37
  557. data/lib/badline/z80/interrupt_acceptance.rb +0 -46
  558. data/lib/badline/z80/jumps.rb +0 -82
  559. data/lib/badline/z80/loads.rb +0 -98
  560. data/lib/badline/z80/main_page.rb +0 -134
  561. data/lib/badline/z80/registers.rb +0 -120
  562. data/lib/badline/z80/saved_state.rb +0 -69
  563. data/lib/badline/z80/shifts.rb +0 -64
  564. data/lib/badline/z80.rb +0 -11
  565. /data/lib/badline/snapshot/{fields.rb → vice/fields.rb} +0 -0
@@ -1,131 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class CPU
5
- # Steps that read an instruction's operand bytes and work out the
6
- # address it operates on, which they leave in @address. Also the
7
- # single-step implied, accumulator and immediate instructions, and JMP.
8
- module Addressing
9
- private
10
-
11
- def op_implied_dummy
12
- @memory.peek(@program_counter)
13
- end
14
-
15
- def op_implied_exec
16
- @memory.peek(@program_counter)
17
- send(@operation, nil, nil)
18
- end_instruction
19
- end
20
-
21
- def op_accumulator_exec
22
- @memory.peek(@program_counter)
23
- send(@operation, :accumulator, @a)
24
- end_instruction
25
- end
26
-
27
- def op_immediate_read
28
- value = @memory.peek(@program_counter)
29
- @program_counter = (@program_counter + 1) & 0xffff
30
- send(@operation, nil, value)
31
- end_instruction
32
- end
33
-
34
- def op_zp
35
- @address = @memory.peek(@program_counter)
36
- @program_counter = (@program_counter + 1) & 0xffff
37
- end
38
-
39
- def op_zp_x
40
- @memory.peek(@address)
41
- @address = (@address + @x) & 0xff
42
- end
43
-
44
- def op_zp_y
45
- @memory.peek(@address)
46
- @address = (@address + @y) & 0xff
47
- end
48
-
49
- def op_abs_low
50
- @address = @memory.peek(@program_counter)
51
- @program_counter = (@program_counter + 1) & 0xffff
52
- end
53
-
54
- def op_abs_high
55
- @address |= @memory.peek(@program_counter) << 8
56
- @program_counter = (@program_counter + 1) & 0xffff
57
- end
58
-
59
- def op_abs_high_x
60
- high = @memory.peek(@program_counter)
61
- @program_counter = (@program_counter + 1) & 0xffff
62
- index_address(high, @x)
63
- end
64
-
65
- def op_abs_high_y
66
- high = @memory.peek(@program_counter)
67
- @program_counter = (@program_counter + 1) & 0xffff
68
- index_address(high, @y)
69
- end
70
-
71
- def op_idx_dummy
72
- @memory.peek(@dummy_address)
73
- end
74
-
75
- def op_zp_pointer
76
- @pointer = @memory.peek(@program_counter)
77
- @program_counter = (@program_counter + 1) & 0xffff
78
- end
79
-
80
- def op_pointer_x
81
- @memory.peek(@pointer)
82
- @pointer = (@pointer + @x) & 0xff
83
- end
84
-
85
- def op_pointer_low
86
- @address = @memory.peek(@pointer)
87
- end
88
-
89
- def op_pointer_high
90
- @address |= @memory.peek((@pointer + 1) & 0xff) << 8
91
- end
92
-
93
- def op_pointer_high_y
94
- index_address(@memory.peek((@pointer + 1) & 0xff), @y)
95
- end
96
-
97
- def op_jmp_high
98
- @program_counter = @address | (@memory.peek(@program_counter) << 8)
99
- end_instruction
100
- end
101
-
102
- def op_indirect_low
103
- @pointer = @address
104
- @address = @memory.peek(@pointer)
105
- end
106
-
107
- # The pointer's high byte never increments, so JMP ($30FF) reads its
108
- # target's high byte from $3000, not $3100.
109
- def op_indirect_high
110
- high = @memory.peek((@pointer & 0xff00) | ((@pointer + 1) & 0xff))
111
- @program_counter = @address | (high << 8)
112
- end_instruction
113
- end
114
-
115
- # Adds an index register to a base address. The 6502 adds to the low
116
- # byte first and spends the next cycle reading from that address,
117
- # before the carry reaches the high byte. Read instructions skip that
118
- # cycle when there is no carry.
119
- def index_address(high, index)
120
- low = @address
121
- @address = (((high << 8) | low) + index) & 0xffff
122
- @boundary_crossed = (low + index) > 0xff
123
- if @optional_dummy && !@boundary_crossed
124
- @index += 1
125
- else
126
- @dummy_address = (high << 8) | ((low + index) & 0xff)
127
- end
128
- end
129
- end
130
- end
131
- end
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class CPU
5
- # The steps at an instruction boundary: the opcode fetch that starts
6
- # an instruction, and the ends of one.
7
- module Boundary
8
- private
9
-
10
- # The first cycle of every instruction. Starts an interrupt if one was
11
- # pending when the previous instruction ended. Otherwise reads the
12
- # opcode and switches to its plan.
13
- def op_fetch
14
- return start_interrupt if @boundary_nmi || @boundary_irq
15
-
16
- run_traps
17
- opcode = @memory.peek(@program_counter)
18
- log(opcode) if @debug
19
- micro = MICROCODE[opcode]
20
- @operation = micro.operation
21
- @plan = micro.plan
22
- @writes = micro.writes
23
- @optional_dummy = micro.optional_dummy
24
- @index = 1
25
- @boundary_crossed = false
26
- @program_counter = (@program_counter + 1) & 0xffff
27
- end
28
-
29
- def end_instruction
30
- @instructions += 1
31
- end_sequence
32
- end
33
-
34
- # Makes the next cycle an opcode fetch, and saves the pending interrupt
35
- # flags for op_fetch. The next cycle polls before op_fetch runs, which
36
- # updates the live flags.
37
- def end_sequence
38
- @plan = FETCH_PLAN
39
- @writes = FETCH_WRITES
40
- @index = 0
41
- @boundary_irq = @irq_pending
42
- @boundary_nmi = @nmi_pending
43
- end
44
-
45
- def log(opcode)
46
- instruction = Instruction.find(opcode)
47
- puts(
48
- "#{@cycles}: PC: #{format16(@program_counter)} - " \
49
- "#{instruction.name.upcase} #{instruction.addressing_mode}"
50
- )
51
- end
52
- end
53
- end
54
- end
@@ -1,165 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "badline/cpu/microcode"
4
- require "badline/cpu/addressing"
5
- require "badline/cpu/operations"
6
- require "badline/cpu/stack_operations"
7
- require "badline/cpu/boundary"
8
- require "badline/cpu/saved_state"
9
-
10
- module Badline
11
- class CPU
12
- STATUS_FLAGS = [:carry, :zero, :interrupt, :decimal, :break, 1, :overflow, :negative].freeze
13
-
14
- # The 6502 core, on whatever bus +memory+ is. The C64's 6510 (CPU) and
15
- # the 1541's 6502 (Drive1541::CPU) each include it.
16
- module Core
17
- include IntegerHelper
18
- include InstructionSet
19
- include Interrupts
20
- include Traps
21
- include Addressing
22
- include Operations
23
- include StackOperations
24
- include Boundary
25
- include SavedState
26
-
27
- attr_reader :memory, :instructions, :boundary_crossed, :cycles, :pending_write
28
- attr_accessor :program_counter, :stack_pointer, :status, :a, :x, :y, :nmi, :irq
29
-
30
- alias pending_write? pending_write
31
-
32
- # +ane_constant+ is ANE's magic constant, which varies from chip to
33
- # chip. The default is the C64 6510's.
34
- def initialize(memory, debug: false, ane_constant: 0xef)
35
- @debug = debug
36
- @ane_constant = ane_constant
37
- @memory = memory
38
- @status = CPUStatus.new(STATUS_FLAGS, value: 0b00100000)
39
- reset_registers
40
-
41
- @nmi = @irq = false
42
- @irq_sample = @irq_pending = false
43
- @nmi_sample = @nmi_pending = false
44
- @skip_poll = false
45
- @boundary_crossed = false
46
- @interrupt = nil
47
- @brk = false
48
- @pending_write = false
49
- @stalled_at = nil
50
- @so_high = true
51
-
52
- @cycles = 0
53
- @instructions = 0
54
- @traps = nil
55
- end_sequence
56
- end
57
-
58
- def reset!
59
- status.interrupt = true
60
- reset_registers
61
- @nmi = false
62
- @irq_sample = @irq_pending = false
63
- @nmi_sample = @nmi_pending = false
64
- @skip_poll = false
65
- @pending_write = false
66
- end_sequence
67
- end
68
-
69
- def p
70
- status.value
71
- end
72
-
73
- def p=(new_value)
74
- status.value = new_value
75
- end
76
-
77
- def cycle!
78
- poll # the interrupt lines
79
-
80
- # Run the next step
81
- index = @index
82
- @index = index + 1
83
- send(@plan[index])
84
- @cycles += 1
85
-
86
- # Record if the next step writes to memory
87
- @pending_write = @writes[@index]
88
- nil
89
- end
90
-
91
- # Called instead of #cycle! on a cycle the VIC holds the CPU through
92
- # BA. Records which cycle the CPU was stalled before, and keeps
93
- # sampling the interrupt lines.
94
- def stall!
95
- @stalled_at = @cycles
96
- sample_while_stalled
97
- end
98
-
99
- # The 6502's SO (set overflow) pin, which the 6510 leaves out, so the
100
- # C64 never drives it. A falling edge sets V and a held level does
101
- # nothing more.
102
- def so=(high)
103
- @status.overflow = true if @so_high && !high
104
- @so_high = high
105
- end
106
-
107
- # Pulses SO: pulls it low, which sets V, and releases it.
108
- def so!
109
- @status.overflow = true
110
- @so_high = true
111
- end
112
-
113
- def jammed?
114
- @plan.equal?(JAMMED_PLAN)
115
- end
116
-
117
- # Runs to the end of the instruction, or until the CPU jams.
118
- def step!
119
- cycle!
120
- cycle! until @plan.equal?(FETCH_PLAN) || jammed?
121
- nil
122
- end
123
-
124
- # Whether the next cycle fetches an opcode.
125
- def boundary? = @index.zero? && @plan.equal?(FETCH_PLAN)
126
-
127
- def trapped? = !@traps.nil?
128
-
129
- def inspect
130
- "Cycles: #{@cycles}, PC: #{format16(program_counter)}, " \
131
- "SP: #{format8(stack_pointer)}, A: #{format8(a)}, X: #{format8(x)}, " \
132
- "Y: #{format8(y)}, P: #{format8(p)}"
133
- end
134
-
135
- private
136
-
137
- # True when the CPU was stalled right before this cycle.
138
- def stalled_before_this_cycle?
139
- @stalled_at == @cycles
140
- end
141
-
142
- # True when the CPU was stalled right before the cycle that preceded
143
- # this one.
144
- def stalled_before_previous_cycle?
145
- @stalled_at == @cycles - 1
146
- end
147
-
148
- def write_byte(addr, value)
149
- @memory.poke(addr, value)
150
- end
151
-
152
- def stack_address(offset = 0)
153
- 0x0100 | ((@stack_pointer + offset) & 0xff)
154
- end
155
-
156
- def reset_registers
157
- # The program counter is initialized from the reset vector
158
- @program_counter = @memory.peek16(0xfffc)
159
- # Stack pointer starts at 0x01ff and grows down
160
- @stack_pointer = 0xff
161
- @a = @x = @y = 0x0
162
- end
163
- end
164
- end
165
- end
@@ -1,177 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class CPU
5
- class InvalidOpcodeError < StandardError; end
6
-
7
- # Steps that write to memory. The CPU keeps running through BA on
8
- # cycles that write, so Computer#cycle! asks before each cycle whether
9
- # the next step is one of these.
10
- WRITE_STEPS = %i[
11
- op_mem_write op_rmw_write_original op_rmw_write_result op_push_exec op_jsr_push_high op_jsr_push_low
12
- op_int_push_pch op_int_push_pcl op_int_push_status
13
- ].freeze
14
-
15
- # The steps each addressing mode takes to work out the address an
16
- # instruction operates on. They run after the opcode fetch.
17
- ADDRESSING_STEPS = {
18
- zeropage: %i[op_zp],
19
- zeropage_x: %i[op_zp op_zp_x],
20
- zeropage_y: %i[op_zp op_zp_y],
21
- absolute: %i[op_abs_low op_abs_high],
22
- absolute_x: %i[op_abs_low op_abs_high_x op_idx_dummy],
23
- absolute_y: %i[op_abs_low op_abs_high_y op_idx_dummy],
24
- indirect_x: %i[op_zp_pointer op_pointer_x op_pointer_low op_pointer_high],
25
- indirect_y: %i[op_zp_pointer op_pointer_low op_pointer_high_y op_idx_dummy]
26
- }.freeze
27
-
28
- # The steps that read or write that address, once it is known.
29
- OPERATION_STEPS = {
30
- read: %i[op_mem_read],
31
- write: %i[op_mem_write],
32
- rmw: %i[op_rmw_read op_rmw_write_original op_rmw_write_result]
33
- }.freeze
34
-
35
- STORES = %i[sta stx sty sax sha shx shy tas].freeze
36
- READ_MODIFY_WRITES = %i[asl lsr rol ror inc dec slo sre rla rra isc dcp].freeze
37
- BRANCHES = %i[bcc bcs beq bmi bne bpl bvc bvs].freeze
38
-
39
- # The addresses a 6502 reads after a JAM opcode, before it settles into
40
- # JAMMED_PLAN.
41
- JAM_ADDRESSES = [0xffff, 0xfffe, 0xfffe].freeze
42
-
43
- # The plan between instructions: the next cycle fetches an opcode.
44
- FETCH_PLAN = %i[op_fetch].freeze
45
-
46
- IMPLIED_PLAN = %i[op_fetch op_implied_exec].freeze
47
- ACCUMULATOR_PLAN = %i[op_fetch op_accumulator_exec].freeze
48
- IMMEDIATE_PLAN = %i[op_fetch op_immediate_read].freeze
49
-
50
- # $10, $30, $50, $70, $90, $B0, $D0, $F0 - relative - 2+ cycles.
51
- # A branch that is not taken takes 2 cycles. A taken branch takes 3,
52
- # or 4 when the target is on another page.
53
- BRANCH_PLAN = %i[op_fetch op_relative op_branch op_branch_fixup].freeze
54
-
55
- # $4C - absolute - 3 cycles
56
- JMP_ABSOLUTE_PLAN = %i[op_fetch op_abs_low op_jmp_high].freeze
57
-
58
- # $6C - indirect - 5 cycles
59
- JMP_INDIRECT_PLAN = %i[op_fetch op_abs_low op_abs_high op_indirect_low op_indirect_high].freeze
60
-
61
- # $20 - absolute - 6 cycles
62
- JSR_PLAN = %i[op_fetch op_jsr_low op_jsr_dummy op_jsr_push_high op_jsr_push_low op_jsr_high].freeze
63
-
64
- # $60 - implied - 6 cycles
65
- RTS_PLAN = %i[op_fetch op_implied_dummy op_pull_dummy op_pull_low op_pull_high op_rts_fixup].freeze
66
-
67
- # $40 - implied - 6 cycles
68
- RTI_PLAN = %i[op_fetch op_implied_dummy op_pull_dummy op_rti_pull_status op_pull_low op_rti_pull_high].freeze
69
-
70
- # $08, $48 - implied - 3 cycles
71
- PUSH_PLAN = %i[op_fetch op_implied_dummy op_push_exec].freeze
72
-
73
- # $28, $68 - implied - 4 cycles
74
- PULL_PLAN = %i[op_fetch op_implied_dummy op_pull_dummy op_pull_exec].freeze
75
-
76
- # $02, $12, $22, $32, $42, $52, $62, $72, $92, $B2, $D2, $F2 - illegal
77
- JAM_PLAN = [:op_fetch, :op_implied_dummy, *Array.new(JAM_ADDRESSES.length, :op_jam)].freeze
78
-
79
- # A jammed CPU reads $FFFF on every cycle until reset. It never reaches
80
- # an instruction boundary, so a pending IRQ or NMI never starts.
81
- JAMMED_PLAN = %i[op_jammed].freeze
82
-
83
- # BRK and hardware interrupts push the return address and status, then
84
- # read the new PC from a vector. Only the second step differs: BRK's
85
- # selects the IRQ vector and sets the break flag it pushes.
86
- #
87
- # $00 - implied - 7 cycles (BRK)
88
- INTERRUPT_PLAN = %i[
89
- op_fetch op_implied_dummy op_int_push_pch op_int_push_pcl op_int_push_status
90
- op_int_vector_low op_int_vector_high
91
- ].freeze
92
- BRK_PLAN = %i[
93
- op_fetch op_brk_dummy op_int_push_pch op_int_push_pcl op_int_push_status
94
- op_int_vector_low op_int_vector_high
95
- ].freeze
96
-
97
- SPECIAL_PLANS = {
98
- brk: BRK_PLAN, jam: JAM_PLAN, jsr: JSR_PLAN, rts: RTS_PLAN,
99
- rti: RTI_PLAN, pha: PUSH_PLAN, php: PUSH_PLAN,
100
- pla: PULL_PLAN, plp: PULL_PLAN
101
- }.freeze
102
-
103
- # Everything the CPU needs to run one opcode:
104
- # - +operation+: the instruction method to call, such as :lda
105
- # - +plan+: the step to run on each cycle
106
- # - +writes+: which of those steps write to memory
107
- # - +optional_dummy+: true for indexed reads, which skip the extra
108
- # cycle unless indexing crosses a page
109
- Microcode = Struct.new(:operation, :plan, :writes, :optional_dummy) do
110
- def self.table
111
- Array.new(256) do |opcode|
112
- instruction = Instruction.find(opcode)
113
- raise InvalidOpcodeError, format("$%02x", opcode) unless instruction
114
-
115
- build(instruction)
116
- end.freeze
117
- end
118
-
119
- def self.write_mask(plan)
120
- plan.map { |step| WRITE_STEPS.include?(step) }.freeze
121
- end
122
-
123
- def self.build(instruction)
124
- plan = plan_for(instruction)
125
- new(instruction.name, plan, write_mask(plan),
126
- instruction.boundary_cycle?)
127
- end
128
-
129
- def self.plan_for(instruction)
130
- case instruction.name
131
- when :jmp
132
- if instruction.addressing_mode == :indirect
133
- JMP_INDIRECT_PLAN
134
- else
135
- JMP_ABSOLUTE_PLAN
136
- end
137
- when *BRANCHES then BRANCH_PLAN
138
- else SPECIAL_PLANS[instruction.name] || addressed_plan(instruction)
139
- end
140
- end
141
-
142
- def self.addressed_plan(instruction)
143
- mode = instruction.addressing_mode
144
- case mode
145
- when :implied then IMPLIED_PLAN
146
- when :accumulator then ACCUMULATOR_PLAN
147
- when :immediate then IMMEDIATE_PLAN
148
- else
149
- [:op_fetch, *ADDRESSING_STEPS.fetch(mode),
150
- *OPERATION_STEPS.fetch(operation_kind(instruction.name))].freeze
151
- end
152
- end
153
-
154
- def self.operation_kind(name)
155
- return :write if STORES.include?(name)
156
- return :rmw if READ_MODIFY_WRITES.include?(name)
157
-
158
- :read
159
- end
160
-
161
- private_class_method :build, :plan_for, :addressed_plan, :operation_kind
162
- end
163
-
164
- FETCH_WRITES = Microcode.write_mask(FETCH_PLAN)
165
- INTERRUPT_WRITES = Microcode.write_mask(INTERRUPT_PLAN)
166
- JAMMED_WRITES = Microcode.write_mask(JAMMED_PLAN)
167
- MICROCODE = Microcode.table
168
-
169
- # The instruction methods, in a fixed order a snapshot names them by.
170
- OPERATIONS = MICROCODE.map(&:operation).uniq.freeze
171
-
172
- # The plans a snapshot names that aren't an opcode's.
173
- FETCH = -1
174
- INTERRUPT = -2
175
- JAMMED = -3
176
- end
177
- end
@@ -1,88 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Badline
4
- class CPU
5
- # Steps that read or write an instruction's operand once its address is
6
- # known, plus the branch and JAM steps.
7
- module Operations
8
- private
9
-
10
- def op_mem_read
11
- send(@operation, @address, @memory.peek(@address))
12
- end_instruction
13
- end
14
-
15
- def op_mem_write
16
- send(@operation, @address, nil)
17
- end_instruction
18
- end
19
-
20
- # Read-modify-write instructions (ASL, INC and the like) take three
21
- # cycles here: read the value and compute the result, write the
22
- # original value back, then write the result. The instruction method
23
- # hands the result over through #write_modified.
24
- def op_rmw_read
25
- @value = @memory.peek(@address)
26
- send(@operation, @address, @value)
27
- end
28
-
29
- def op_rmw_write_original
30
- @memory.poke(@address, @value)
31
- end
32
-
33
- def op_rmw_write_result
34
- @memory.poke(@address, @rmw_result)
35
- end_instruction
36
- end
37
-
38
- def op_relative
39
- offset = @memory.peek(@program_counter)
40
- @program_counter = (@program_counter + 1) & 0xffff
41
- @address = (@program_counter + signed_int8(offset)) & 0xffff
42
- @branch_taken = false
43
- send(@operation, @address, nil)
44
- if @branch_taken
45
- # A taken branch within the same page doesn't poll on its last cycle.
46
- @skip_poll = true if same_page?
47
- else
48
- end_instruction
49
- end
50
- end
51
-
52
- def op_branch
53
- @memory.peek(@program_counter)
54
- return unless same_page?
55
-
56
- @program_counter = @address
57
- end_instruction
58
- end
59
-
60
- # A branch to another page spends an extra cycle reading from the target's low byte on the old page.
61
- def op_branch_fixup
62
- @memory.peek((@program_counter & 0xff00) | (@address & 0xff))
63
- @program_counter = @address
64
- end_instruction
65
- end
66
-
67
- def same_page?
68
- @address >> 8 == @program_counter >> 8
69
- end
70
-
71
- # Runs once for each address in JAM_ADDRESSES. By the time a step runs, @index already points at the next one.
72
- def op_jam
73
- position = @index - 2
74
- @memory.peek(JAM_ADDRESSES[position - 1])
75
- return unless position == JAM_ADDRESSES.length
76
-
77
- @plan = JAMMED_PLAN
78
- @writes = JAMMED_WRITES
79
- @index = 0
80
- end
81
-
82
- def op_jammed
83
- @index = 0
84
- @memory.peek(0xffff)
85
- end
86
- end
87
- end
88
- end