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
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class TED
6
+ # The raster and the clock the TED gives the CPU, a single clock
7
+ # cycle at a time.
8
+ #
9
+ # A line is 456 dots, horizontal counts 0-455, and a single clock
10
+ # cycle 8 of them, so a line is 57 cycles; #column counts them, the
11
+ # cycle at count 8 * column. The line count steps at count 376, in
12
+ # column 47, and runs 0-311 on PAL and 0-261 with $FF07 bit 6 set
13
+ # (NTSC). The datasheet's horizontal and vertical decode tables give
14
+ # those counts.
15
+ #
16
+ # The CPU runs once in a single clock cycle and twice in a double
17
+ # clock one. The datasheet's "System Clock Doubling": in the display
18
+ # window's lines the clock is single from count 400 round to 344,
19
+ # columns 50-56 and 0-42, and double in columns 43-49. The window is
20
+ # lines 0-203: the datasheet says 0-204, but xplus4 runs line 204 at
21
+ # double clock, as the lines below it. In the other lines it is double
22
+ # but for the five refresh cycles at counts 304-344, columns 38-42,
23
+ # which are single everywhere. With $FF06 bit 4 clear (blank) every
24
+ # line is double but for refresh, and $FF13 bit 1 or $FF07 bit 5
25
+ # (freeze) makes every cycle single.
26
+ #
27
+ # So a display line gives the CPU 64 cycles and a border line 109,
28
+ # the counts measured on real machines.
29
+ #
30
+ # DMA: each character row takes the bus for 40 cycles on two lines,
31
+ # the line before the row for the attributes and the row's first
32
+ # line for the character pointers (the datasheet's register 20). A
33
+ # row starts on the line after one whose low three bits match $FF06
34
+ # bits 0-2, as the KERNAL's scroll of 3 puts the first row on line 4,
35
+ # where the datasheet's 25-row window starts, and a row starts only
36
+ # in lines 0-203. xplus4 takes the bus on the same lines. The fetches run in columns 54-56 and 0-36, and BA
37
+ # goes low 3 cycles before the first, in column 51, so the CPU stops
38
+ # at its next read. A DMA line leaves the CPU 24 cycles.
39
+ module Beam
40
+ CYCLES_PER_LINE = 57
41
+ LINE_STEP_COLUMN = 47
42
+ BA_COLUMN = 51
43
+ DMA_COLUMN = 54
44
+ DMA_END_COLUMN = 36
45
+ REFRESH_COLUMNS = (38..42)
46
+ DOUBLE_COLUMNS = (43..49)
47
+ LAST_DISPLAY_LINE = 203
48
+
49
+ # The single clock cycle in the line, 0-56.
50
+ attr_reader :column
51
+
52
+ # The raster line.
53
+ attr_reader :line
54
+
55
+ # How many cycles the CPU runs in this cycle: 0 while the TED holds
56
+ # the bus for DMA, 1 at single clock and 2 at double clock.
57
+ attr_reader :cpu_slots
58
+
59
+ # Whether BA is low, from 3 cycles before DMA to its end.
60
+ def ba_low? = @ba_low
61
+
62
+ # Lines a frame, by $FF07 bit 6.
63
+ def lines_per_frame = @registers[0x07].anybits?(0x40) ? 262 : 312
64
+
65
+ private
66
+
67
+ def reset_beam
68
+ @column = 0
69
+ @line = 0
70
+ @dma_line = false
71
+ @ba_low = false
72
+ @cpu_slots = 1
73
+ end
74
+
75
+ def move_beam
76
+ column = @column + 1
77
+ column = 0 if column == CYCLES_PER_LINE
78
+ @column = column
79
+ return unless column == LINE_STEP_COLUMN
80
+
81
+ line = @line + 1
82
+ line = 0 if line >= lines_per_frame
83
+ self.line = line
84
+ end
85
+
86
+ def decide_clock
87
+ column = @column
88
+ @dma_line = dma_line? if column == BA_COLUMN
89
+ if @dma_line && (column >= BA_COLUMN || column <= DMA_END_COLUMN)
90
+ @ba_low = true
91
+ @cpu_slots = column >= DMA_COLUMN || column <= DMA_END_COLUMN ? 0 : 1
92
+ return
93
+ end
94
+
95
+ @ba_low = false
96
+ @cpu_slots = single_clock?(column) ? 1 : 2
97
+ end
98
+
99
+ def single_clock?(column)
100
+ return true if REFRESH_COLUMNS.include?(column) || @registers[0x13].anybits?(0x02) || frozen?
101
+
102
+ display_window? && !DOUBLE_COLUMNS.include?(column)
103
+ end
104
+
105
+ def display_window? = @registers[0x06].anybits?(0x10) && @line <= LAST_DISPLAY_LINE
106
+
107
+ def dma_line?
108
+ return false unless @registers[0x06].anybits?(0x10)
109
+
110
+ phase = (@line - (@registers[0x06] & 0x07)) & 0x07
111
+ return false if phase > 1
112
+
113
+ row = phase.zero? ? @line + 1 : @line
114
+ row <= LAST_DISPLAY_LINE
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class TED
6
+ # The three 16-bit timers at $FF00-$FF05, which count down once a
7
+ # single clock cycle whatever clock the CPU runs at. Each raises its
8
+ # interrupt flag as it counts down to zero. Timer 1's next count then
9
+ # loads the value last written to it, and timers 2 and 3 roll over to
10
+ # $FFFF.
11
+ #
12
+ # A write to a timer's low byte stops it until its high byte is
13
+ # written. Timer 1's writes set its reload value and its count
14
+ # together, and timers 2 and 3's set the count.
15
+ module Timers
16
+ # The interrupt flag each timer raises in $FF09.
17
+ TIMER_FLAGS = [0x08, 0x10, 0x40].freeze
18
+
19
+ # The counts, the reload value of timer 1, and which timers run.
20
+ attr_reader :timer_counts, :timer_running
21
+
22
+ private
23
+
24
+ def reset_timers
25
+ @timer_counts = [0, 0, 0]
26
+ @timer_running = [false, false, false]
27
+ @timer1_reload = 0
28
+ end
29
+
30
+ def count_timers
31
+ i = 0
32
+ while i < 3
33
+ count_timer(i) if @timer_running[i]
34
+ i += 1
35
+ end
36
+ end
37
+
38
+ def count_timer(index)
39
+ count = @timer_counts[index]
40
+ if count.zero? && index.zero?
41
+ @timer_counts[0] = @timer1_reload
42
+ return
43
+ end
44
+
45
+ count = (count - 1) & 0xffff
46
+ @timer_counts[index] = count
47
+ @interrupt_flags |= TIMER_FLAGS[index] if count.zero?
48
+ end
49
+
50
+ def read_timer(register)
51
+ count = @timer_counts[register >> 1]
52
+ register.even? ? count & 0xff : count >> 8
53
+ end
54
+
55
+ def write_timer(register, value)
56
+ index = register >> 1
57
+ count = @timer_counts[index]
58
+ count = register.even? ? (count & 0xff00) | value : (count & 0x00ff) | (value << 8)
59
+ @timer_counts[index] = count
60
+ @timer1_reload = count if index.zero?
61
+ @timer_running[index] = register.odd?
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/chips/ted/timers"
4
+ require "badline/chips/ted/beam"
5
+
6
+ module Badline
7
+ module Chips
8
+ # The TED of the Commodore 264 series, the 7360 and 8360: its registers
9
+ # at $FF00-$FF1F, the raster, the three timers, the interrupt, the
10
+ # keyboard latch and the clock it gives the CPU (Beam). It paints no
11
+ # picture and plays no sound yet: those registers keep what is written
12
+ # to them.
13
+ #
14
+ # The machine clocks it once a single clock cycle, 57 to a line, and
15
+ # asks it then how many cycles the CPU runs in that one (#cpu_slots)
16
+ # and whether BA is low (#ba_low?).
17
+ #
18
+ # $FF08 is the keyboard latch: a write latches the K0-K7 inputs, which
19
+ # the keyboard port answers for the byte written (KeyboardPort#latch),
20
+ # and a read returns them. $FF09 holds the interrupt flags, each
21
+ # cleared by writing a 1 to it, with bit 7 set while the interrupt
22
+ # line is pulled. $FF0A holds the mask and bit 8 of the raster compare,
23
+ # and $FF0B the compare's low byte. $FF13 bit 0 reads whether the CPU
24
+ # sees ROM at $8000-$FFFF (#rom_selected=). $FF1C and $FF1D read and
25
+ # set the raster line, and $FF1E reads the horizontal position's top 8
26
+ # bits.
27
+ class TED
28
+ include Timers
29
+ include Beam
30
+
31
+ # The clock a TED is fed, its single clock: the crystal divided by 20
32
+ # on PAL machines and by 16 on NTSC ones (the Plus/4 hardware manual's
33
+ # TED datasheet).
34
+ Profile = Data.define(:name, :clock_hz)
35
+
36
+ PAL = Profile.new(name: :pal, clock_hz: 886_724)
37
+ NTSC = Profile.new(name: :ntsc, clock_hz: 894_886)
38
+
39
+ RASTER_FLAG = 0x02
40
+
41
+ # The interrupt sources a mask bit can enable: the raster, the light
42
+ # pen and the three timers.
43
+ SOURCES = 0x5e
44
+
45
+ attr_reader :profile, :interrupt_flags, :interrupt_mask
46
+
47
+ # What answers the keyboard latch: an object with #latch(value).
48
+ attr_writer :keyboard_port
49
+
50
+ # Whether the CPU sees ROM at $8000-$FFFF, which $FF13 bit 0 reads.
51
+ attr_writer :rom_selected
52
+
53
+ def initialize(profile = PAL)
54
+ @profile = profile
55
+ @keyboard_port = nil
56
+ @rom_selected = true
57
+ power_on!
58
+ end
59
+
60
+ def power_on!
61
+ @registers = Array.new(0x20, 0)
62
+ @interrupt_flags = 0
63
+ @interrupt_mask = 0
64
+ @raster_compare = 0
65
+ @key_latch = 0xff
66
+ reset_timers
67
+ reset_beam
68
+ end
69
+
70
+ # Counts the timers and moves the beam on a cycle, unless $FF07's
71
+ # freeze bit holds them, then decides the CPU's clock for the cycle.
72
+ def cycle!
73
+ unless frozen?
74
+ count_timers
75
+ move_beam
76
+ end
77
+ decide_clock
78
+ end
79
+
80
+ # Whether the interrupt line is pulled: a flag raised whose mask bit
81
+ # is set.
82
+ def irq? = @interrupt_flags.anybits?(@interrupt_mask & SOURCES)
83
+
84
+ def peek(addr)
85
+ register = addr & 0x3f
86
+ return 0xff if register >= 0x20
87
+
88
+ case register
89
+ when 0x00..0x05 then read_timer(register)
90
+ when 0x08 then @key_latch
91
+ when 0x09 then read_interrupt_flags
92
+ when 0x0a then @interrupt_mask | 0xa0
93
+ when 0x0b then @raster_compare & 0xff
94
+ when 0x13 then (@registers[0x13] & 0xfe) | (@rom_selected ? 1 : 0)
95
+ when 0x1c then 0xfe | (@line >> 8)
96
+ when 0x1d then @line & 0xff
97
+ when 0x1e then @column << 2
98
+ else @registers[register]
99
+ end
100
+ end
101
+
102
+ def poke(addr, value)
103
+ register = addr & 0x3f
104
+ return if register >= 0x20
105
+
106
+ @registers[register] = value
107
+ case register
108
+ when 0x00..0x05 then write_timer(register, value)
109
+ when 0x08 then @key_latch = @keyboard_port ? @keyboard_port.latch(value) : 0xff
110
+ when 0x09 then @interrupt_flags &= ~value
111
+ when 0x0a then write_interrupt_mask(value)
112
+ when 0x0b then @raster_compare = (@raster_compare & 0x100) | value
113
+ when 0x1c then self.line = (@line & 0xff) | ((value & 0x01) << 8)
114
+ when 0x1d then self.line = (@line & 0x100) | value
115
+ end
116
+ end
117
+
118
+ private
119
+
120
+ # $FF07 bit 5 stops the beam and the timers.
121
+ def frozen? = @registers[0x07].anybits?(0x20)
122
+
123
+ def read_interrupt_flags
124
+ value = @interrupt_flags | 0x21
125
+ irq? ? value | 0x80 : value
126
+ end
127
+
128
+ def write_interrupt_mask(value)
129
+ @interrupt_mask = value & 0x5f
130
+ @raster_compare = (@raster_compare & 0xff) | ((value & 0x01) << 8)
131
+ end
132
+
133
+ def line=(value)
134
+ @line = value
135
+ raster_reached
136
+ end
137
+
138
+ def raster_reached
139
+ @interrupt_flags |= RASTER_FLAG if @line == @raster_compare
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ # The 6523 TIA, a tri-port interface adapter: three 8-bit ports, A, B
6
+ # and C at registers 0-2, each with its direction register at 3-5, a 1
7
+ # making the pin an output. Its three address lines repeat the
8
+ # registers every 8 bytes, and registers 6 and 7 read $FF.
9
+ #
10
+ # A pin read as an output returns what the port drives, and one read as
11
+ # an input returns what the other side drives, #inputs, per port.
12
+ class TIA
13
+ attr_reader :ports, :directions
14
+
15
+ # What the other side drives onto each port's pins.
16
+ attr_reader :inputs
17
+
18
+ def initialize
19
+ @inputs = [0, 0, 0]
20
+ reset!
21
+ end
22
+
23
+ def reset!
24
+ @ports = [0, 0, 0]
25
+ @directions = [0, 0, 0]
26
+ end
27
+
28
+ def peek(addr)
29
+ register = addr & 0x07
30
+ return 0xff if register > 5
31
+ return @directions[register - 3] if register >= 3
32
+
33
+ direction = @directions[register]
34
+ (@ports[register] & direction) | (@inputs[register] & ~direction & 0xff)
35
+ end
36
+
37
+ def poke(addr, value)
38
+ register = addr & 0x07
39
+ return if register > 5
40
+
41
+ if register >= 3
42
+ @directions[register - 3] = value
43
+ else
44
+ @ports[register] = value
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class VDC
6
+ class Raster
7
+ # The raster's fields in a keyed snapshot module, under `prefix`:
8
+ # the frame count, where the beam is in the character rows and the
9
+ # frame, and the frame's size and sync as it latched them.
10
+ module KeyedState
11
+ def save_fields(out, prefix)
12
+ out.int("#{prefix}frame", @frame).int("#{prefix}row", @row).int("#{prefix}row_line", @row_line)
13
+ out.bool("#{prefix}adjusting", @adjusting).int("#{prefix}frame_line", @frame_line)
14
+ out.int("#{prefix}frame_lines", @frame_lines).int("#{prefix}sync_start", @sync_start)
15
+ out.int("#{prefix}sync_lines", @sync_lines)
16
+ end
17
+
18
+ def load_fields(input, prefix)
19
+ @frame = input.int("#{prefix}frame", @frame)
20
+ @row = input.int("#{prefix}row", @row)
21
+ @row_line = input.int("#{prefix}row_line", @row_line)
22
+ @adjusting = input.bool("#{prefix}adjusting", @adjusting)
23
+ @frame_line = input.int("#{prefix}frame_line", @frame_line)
24
+ @frame_lines = input.int("#{prefix}frame_lines", @frame_lines)
25
+ @sync_start = input.int("#{prefix}sync_start", @sync_start)
26
+ @sync_lines = input.int("#{prefix}sync_lines", @sync_lines)
27
+ end
28
+ end
29
+
30
+ include KeyedState
31
+ end
32
+
33
+ class Window
34
+ # The start addresses the frame latched, under `prefix`.
35
+ module KeyedState
36
+ def save_fields(out, prefix)
37
+ out.int("#{prefix}display_start", @display_start).int("#{prefix}attribute_start", @attribute_start)
38
+ end
39
+
40
+ def load_fields(input, prefix)
41
+ @display_start = input.word("#{prefix}display_start", @display_start)
42
+ @attribute_start = input.word("#{prefix}attribute_start", @attribute_start)
43
+ end
44
+ end
45
+
46
+ include KeyedState
47
+ end
48
+
49
+ class Painter
50
+ # The display's size, as the frame latched it, and the window's
51
+ # start addresses. The picture is painted again.
52
+ module KeyedState
53
+ def save_fields(out)
54
+ out.int("display.width", @width).int("display.height", @height)
55
+ @window.save_fields(out, "window.")
56
+ end
57
+
58
+ def load_fields(input)
59
+ resize(input.int("display.width", @width), input.int("display.height", @height))
60
+ @window.load_fields(input, "window.")
61
+ end
62
+ end
63
+
64
+ include KeyedState
65
+ end
66
+
67
+ # The VDC's fields in a keyed snapshot module (Snapshot::Keyed): the
68
+ # registers, the RAM, the register selected, the data latches, the
69
+ # dot clock's phase and the line's length in the same units
70
+ # (dots·Hz, the line latched at its start), how long an access or
71
+ # block operation stays busy from now, the raster under raster.* and
72
+ # the display's size and window under display.* and window.*. The
73
+ # RAM's layout comes from R28 on load.
74
+ module KeyedState
75
+ def save_fields(out)
76
+ out.bytes("registers", @registers).bytes("ram", @memory.ram).int("selected", @selected)
77
+ out.int("read_latch", @read_latch).int("write_data", @write_data).int("phase", @phase)
78
+ out.int("line_units", @line_units).int("busy_for", @busy_until - @phase)
79
+ @raster.save_fields(out, "raster.")
80
+ @painter.save_fields(out)
81
+ out
82
+ end
83
+
84
+ def load_fields(input)
85
+ input.bytes_into("registers", @registers)
86
+ input.bytes_into("ram", @memory.ram)
87
+ @selected = input.masked("selected", @selected, 0x3f)
88
+ @read_latch = input.byte("read_latch", @read_latch)
89
+ @write_data = input.byte("write_data", @write_data)
90
+ @phase = input.int("phase", @phase)
91
+ @line_units = input.int("line_units", @line_units)
92
+ @busy_until = @phase + input.int("busy_for", @busy_until - @phase)
93
+ @raster.load_fields(input, "raster.")
94
+ @painter.load_fields(input)
95
+ end
96
+
97
+ def restored!
98
+ @memory.mode64 = @registers[28].anybits?(0x10)
99
+ end
100
+ end
101
+
102
+ include KeyedState
103
+ end
104
+ end
105
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class C128
4
+ module Chips
5
5
  class VDC
6
6
  # The VDC's own DRAM: 16K of two 4416s (16K by 4) or 64K of 4164s or
7
7
  # 4464s, behind the 16-bit addresses the VDC computes.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class C128
4
+ module Chips
5
5
  class VDC
6
6
  # Paints the VDC's scan lines into its display, one line at a time,
7
7
  # from the registers as they stand when the line ends. Each pixel of
@@ -56,18 +56,6 @@ module Badline
56
56
  [0, 0, shown.clamp(1, @width), (frame_lines - sync_lines).clamp(1, @height)]
57
57
  end
58
58
 
59
- # The display's size and the window's start addresses. The display
60
- # starts again cleared, to be painted while the VDC renders.
61
- def save_state(out)
62
- out.int(@width).int(@height)
63
- @window.save_state(out)
64
- end
65
-
66
- def load_state(input)
67
- resize(input.int, input.int)
68
- @window.load_state(input)
69
- end
70
-
71
59
  def clear_dirty_lines!
72
60
  @dirty_lines.fill(false)
73
61
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class C128
4
+ module Chips
5
5
  class VDC
6
6
  # The VDC's raster: R0 + 1 characters a line, R9 + 1 lines a row,
7
7
  # R4 + 1 rows a frame and then R5 more lines, with the frame's size
@@ -30,22 +30,6 @@ module Badline
30
30
  # Outside the displayed rows, as status bit 5 reads.
31
31
  def vertical_blank? = @adjusting || @row >= @registers[6]
32
32
 
33
- def save_state(out)
34
- out.int(@frame).int(@row).int(@row_line).boolean(@adjusting).int(@frame_line).int(@frame_lines)
35
- out.int(@sync_start).int(@sync_lines)
36
- end
37
-
38
- def load_state(input)
39
- @frame = input.int
40
- @row = input.int
41
- @row_line = input.int
42
- @adjusting = input.boolean?
43
- @frame_line = input.int
44
- @frame_lines = input.int
45
- @sync_start = input.int
46
- @sync_lines = input.int
47
- end
48
-
49
33
  def end_line(render)
50
34
  paint_line if render
51
35
  @frame_line += 1
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class C128
4
+ module Chips
5
5
  class VDC
6
6
  # Paints the characters of a displayed line, R1 of them from the
7
7
  # line's first dot, in text mode or, with R25 bit 7, bitmap mode.
@@ -57,15 +57,6 @@ module Badline
57
57
  @attribute_start = (regs[20] << 8) | regs[21]
58
58
  end
59
59
 
60
- def save_state(out)
61
- out.int(@display_start).int(@attribute_start)
62
- end
63
-
64
- def load_state(input)
65
- @display_start = input.int
66
- @attribute_start = input.int
67
- end
68
-
69
60
  def paint(line, row, row_line, frame)
70
61
  regs = @registers
71
62
  lay_out_cell
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "badline/c128/vdc/memory"
4
- require "badline/c128/vdc/window"
5
- require "badline/c128/vdc/painter"
6
- require "badline/c128/vdc/raster"
3
+ require "badline/chips/vdc/memory"
4
+ require "badline/chips/vdc/window"
5
+ require "badline/chips/vdc/painter"
6
+ require "badline/chips/vdc/raster"
7
+ require "badline/chips/vdc/keyed_parts"
7
8
 
8
9
  module Badline
9
- class C128
10
+ module Chips
10
11
  # The 8563 or 8568 VDC: the address register at $D600 and the data
11
12
  # register at $D601, mirrored through $D6FF, in front of 37 internal
12
13
  # registers (38 on the 8568), the VDC's own RAM (Memory) and its 80
@@ -112,32 +113,6 @@ module Badline
112
113
  @painter.clear!
113
114
  end
114
115
 
115
- # Everything the VDC holds but its display, which it paints again
116
- # while it renders: the registers, the RAM, the data port and the
117
- # raster. Whether it renders is the host's.
118
- def save_state(out)
119
- out.marker("VDC")
120
- out.ints(@registers).blob(@memory.ram)
121
- out.int(@selected).int(@read_latch).int(@write_data).int(@busy_until).int(@phase).int(@line_units)
122
- @raster.save_state(out)
123
- @painter.save_state(out)
124
- end
125
-
126
- def load_state(input)
127
- input.marker("VDC")
128
- input.ints_into(@registers)
129
- input.blob_into(@memory.ram)
130
- @memory.mode64 = @registers[28].anybits?(0x10)
131
- @selected = input.int
132
- @read_latch = input.int
133
- @write_data = input.int
134
- @busy_until = input.int
135
- @phase = input.int
136
- @line_units = input.int
137
- @raster.load_state(input)
138
- @painter.load_state(input)
139
- end
140
-
141
116
  # The frames the raster has finished, which the blinking counts.
142
117
  def frame = @raster.frame
143
118