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,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class Z80
6
+ # The CB page: rotates and shifts (quarter 0), BIT (1), RES (2) and SET
7
+ # (3) of the bit the row names, on the column's register or (HL). After
8
+ # DD or FD the operand is always (IX+d): the displacement comes before
9
+ # the opcode, and an opcode that names a register other than (HL) also
10
+ # copies the result into it.
11
+ module BitPage
12
+ private
13
+
14
+ def execute_bits(opcode)
15
+ operation = opcode >> 6
16
+ number = (opcode >> 3) & 7
17
+ index = opcode & 7
18
+ return bits_in_memory(operation, number, hl) if index == 6
19
+
20
+ value = register(index)
21
+ if operation == 1
22
+ bit(number, value, value)
23
+ else
24
+ set_register(index, bit_result(operation, number, value))
25
+ end
26
+ end
27
+
28
+ def execute_index_bits
29
+ displaced
30
+ opcode = fetch_byte
31
+ @cycles += 2
32
+ result = bits_in_memory(opcode >> 6, (opcode >> 3) & 7, @wz)
33
+ index = opcode & 7
34
+ set_plain_register(index, result) unless index == 6 || (opcode >> 6) == 1
35
+ end
36
+
37
+ def bits_in_memory(operation, number, address)
38
+ value = read_byte(address)
39
+ @cycles += 1
40
+ return bit(number, value, @wz >> 8) if operation == 1
41
+
42
+ result = bit_result(operation, number, value)
43
+ write_byte(address, result)
44
+ result
45
+ end
46
+
47
+ def bit_result(operation, number, value)
48
+ case operation
49
+ when 0 then shift(number, value)
50
+ when 2 then value & ~(1 << number) & 0xff
51
+ else value | (1 << number)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class Z80
6
+ # INI, IND, OUTI, OUTD and their repeating forms. B counts the bytes
7
+ # and sets S, Z, 5 and 3. The byte's bit 7 sets N, and adding it to C
8
+ # plus or minus one for INI and IND, or to L for OUTI and OUTD, sets H
9
+ # and C on a carry out and P/V from the parity of its low 3 bits
10
+ # exclusive-ored with B.
11
+ module BlockIO
12
+ private
13
+
14
+ def block_input(step, repeat)
15
+ @cycles += 1
16
+ port = bc
17
+ value = input(port)
18
+ @wz = (port + step) & 0xffff
19
+ @b = (@b - 1) & 0xff
20
+ write_byte(hl, value)
21
+ self.hl = (hl + step) & 0xffff
22
+ block_io_flags(value, value + ((@c + step) & 0xff), repeat)
23
+ end
24
+
25
+ def block_output(step, repeat)
26
+ @cycles += 1
27
+ value = read_byte(hl)
28
+ @b = (@b - 1) & 0xff
29
+ output(bc, value)
30
+ self.hl = (hl + step) & 0xffff
31
+ @wz = (bc + step) & 0xffff
32
+ block_io_flags(value, value + @l, repeat)
33
+ end
34
+
35
+ def block_io_flags(value, sum, repeat)
36
+ carry = sum > 0xff ? HF | CF : 0
37
+ assign_flags(SZ53[@b] | ((value >> 6) & NF) | carry | PARITY[(sum & 7) ^ @b])
38
+ return unless repeat && !@b.zero?
39
+
40
+ repeat_block
41
+ repeat_io_flags(value, carry)
42
+ end
43
+
44
+ def repeat_io_flags(value, carry)
45
+ flags = @f & ~HF
46
+ if carry.zero?
47
+ flags ^= PARITY[@b & 7] ^ PF
48
+ elsif value.anybits?(0x80)
49
+ flags ^= PARITY[(@b - 1) & 7] ^ PF
50
+ flags |= HF if @b.nobits?(0x0f)
51
+ else
52
+ flags ^= PARITY[(@b + 1) & 7] ^ PF
53
+ flags |= HF if @b.allbits?(0x0f)
54
+ end
55
+ assign_flags(flags)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class Z80
6
+ # LDI, LDD, CPI, CPD and their repeating forms. A repeating form that
7
+ # goes round again winds the program counter back to its ED and spends
8
+ # 5 T-states more, and bits 5 and 3 then come from the program
9
+ # counter's high byte.
10
+ module BlockTransfers
11
+ private
12
+
13
+ # ED A0-BB: the column picks LD, CP, IN or OUT, bit 3 counts down, and
14
+ # bit 4 repeats.
15
+ def block_operation(opcode)
16
+ step = opcode.nobits?(0x08) ? 1 : -1
17
+ repeat = opcode.anybits?(0x10)
18
+ case opcode & 3
19
+ when 0 then block_load(step, repeat)
20
+ when 1 then block_compare(step, repeat)
21
+ when 2 then block_input(step, repeat)
22
+ else block_output(step, repeat)
23
+ end
24
+ end
25
+
26
+ def block_load(step, repeat)
27
+ value = read_byte(hl)
28
+ write_byte(de, value)
29
+ @cycles += 2
30
+ self.hl = (hl + step) & 0xffff
31
+ self.de = (de + step) & 0xffff
32
+ self.bc = (bc - 1) & 0xffff
33
+ sum = value + @a
34
+ assign_flags((@f & (SF | ZF | CF)) | (sum & XF) | ((sum & 0x02) << 4) | (bc.zero? ? 0 : PF))
35
+ repeat_block if repeat && !bc.zero?
36
+ end
37
+
38
+ def block_compare(step, repeat)
39
+ value = read_byte(hl)
40
+ @cycles += 5
41
+ result = (@a - value) & 0xff
42
+ half = (@a ^ value ^ result) & HF
43
+ adjusted = result - (half >> 4)
44
+ self.hl = (hl + step) & 0xffff
45
+ self.bc = (bc - 1) & 0xffff
46
+ @wz = (@wz + step) & 0xffff
47
+ assign_flags((@f & CF) | NF | half | (SZ53[result] & (SF | ZF)) | (adjusted & XF) | ((adjusted & 0x02) << 4) |
48
+ (bc.zero? ? 0 : PF))
49
+ repeat_block if repeat && !bc.zero? && !result.zero?
50
+ end
51
+
52
+ def repeat_block
53
+ @cycles += 5
54
+ @pc = (@pc - 2) & 0xffff
55
+ @wz = (@pc + 1) & 0xffff
56
+ assign_flags((@f & ~XYF) | ((@pc >> 8) & XYF))
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class Z80
6
+ # The machine cycles that reach the bus. An opcode fetch (M1) takes 4
7
+ # T-states and refreshes a row of DRAM, which counts up the low 7 bits
8
+ # of R. A memory read or write takes 3, and an I/O read or write 4,
9
+ # one of them the wait state the Z80 inserts itself. Each calls the bus
10
+ # on its first T-state, and T-states the CPU spends inside lengthen
11
+ # the machine cycle before them.
12
+ module BusCycles
13
+ private
14
+
15
+ def fetch_opcode
16
+ opcode = @bus.fetch(@pc)
17
+ @pc = (@pc + 1) & 0xffff
18
+ refresh
19
+ @cycles += 4
20
+ opcode
21
+ end
22
+
23
+ # A halted CPU fetches from the address after HALT, again and again,
24
+ # and leaves the program counter there.
25
+ def idle_fetch
26
+ @bus.fetch(@pc)
27
+ refresh
28
+ @cycles += 4
29
+ end
30
+
31
+ def refresh
32
+ @r = (@r & 0x80) | ((@r + 1) & 0x7f)
33
+ end
34
+
35
+ def read_byte(address)
36
+ value = @bus.read(address)
37
+ @cycles += 3
38
+ value
39
+ end
40
+
41
+ def write_byte(address, value)
42
+ @bus.write(address, value)
43
+ @cycles += 3
44
+ end
45
+
46
+ def read_word(address)
47
+ low = read_byte(address)
48
+ low | (read_byte((address + 1) & 0xffff) << 8)
49
+ end
50
+
51
+ def write_word(address, value)
52
+ write_byte(address, value & 0xff)
53
+ write_byte((address + 1) & 0xffff, value >> 8)
54
+ end
55
+
56
+ def input(port)
57
+ value = @bus.input(port)
58
+ @cycles += 4
59
+ value
60
+ end
61
+
62
+ def output(port, value)
63
+ @bus.output(port, value)
64
+ @cycles += 4
65
+ end
66
+
67
+ # The byte after the opcode.
68
+ def fetch_byte
69
+ value = read_byte(@pc)
70
+ @pc = (@pc + 1) & 0xffff
71
+ value
72
+ end
73
+
74
+ def fetch_word
75
+ low = fetch_byte
76
+ low | (fetch_byte << 8)
77
+ end
78
+
79
+ def push(value)
80
+ @sp = (@sp - 1) & 0xffff
81
+ write_byte(@sp, value >> 8)
82
+ @sp = (@sp - 1) & 0xffff
83
+ write_byte(@sp, value & 0xff)
84
+ end
85
+
86
+ def pop
87
+ low = read_byte(@sp)
88
+ high = read_byte((@sp + 1) & 0xffff)
89
+ @sp = (@sp + 2) & 0xffff
90
+ low | (high << 8)
91
+ end
92
+
93
+ # The address of an (HL) operand, or of (IX+d), whose displacement is
94
+ # read from after the opcode and added in 5 T-states inside.
95
+ def operand_address
96
+ return hl if @prefix.zero?
97
+
98
+ displaced
99
+ @cycles += 5
100
+ @wz
101
+ end
102
+
103
+ # Reads the displacement of an (IX+d) or (IY+d) operand and leaves
104
+ # the address in WZ.
105
+ def displaced
106
+ offset = fetch_byte
107
+ offset -= 256 if offset > 127
108
+ @wz = (index_register + offset) & 0xffff
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/chips/z80/flags"
4
+ require "badline/chips/z80/registers"
5
+ require "badline/chips/z80/bus_cycles"
6
+ require "badline/chips/z80/arithmetic"
7
+ require "badline/chips/z80/shifts"
8
+ require "badline/chips/z80/loads"
9
+ require "badline/chips/z80/exchanges"
10
+ require "badline/chips/z80/jumps"
11
+ require "badline/chips/z80/main_page"
12
+ require "badline/chips/z80/bit_page"
13
+ require "badline/chips/z80/extended_page"
14
+ require "badline/chips/z80/block_transfers"
15
+ require "badline/chips/z80/block_io"
16
+ require "badline/chips/z80/interrupt_acceptance"
17
+ require "badline/chips/z80/keyed_state"
18
+
19
+ module Badline
20
+ module Chips
21
+ class Z80
22
+ # The Z80 core, on whatever bus +bus+ is. The bus answers
23
+ # fetch(address) for an opcode fetch (M1), read(address) and
24
+ # write(address, value) for memory, input(port) and output(port, value)
25
+ # for I/O, and acknowledge for the byte a device puts on the data bus
26
+ # when the CPU takes a maskable interrupt.
27
+ #
28
+ # #step! runs one instruction, prefixes and all, or takes an interrupt,
29
+ # or idles one opcode fetch while halted. #cycles counts T-states, and
30
+ # each bus call happens while it holds the T-state its machine cycle
31
+ # starts on.
32
+ module Core
33
+ include Flags
34
+ include Registers
35
+ include BusCycles
36
+ include Arithmetic
37
+ include Shifts
38
+ include Loads
39
+ include Exchanges
40
+ include Jumps
41
+ include MainPage
42
+ include BitPage
43
+ include ExtendedPage
44
+ include BlockTransfers
45
+ include BlockIO
46
+ include InterruptAcceptance
47
+ include KeyedState
48
+
49
+ attr_reader :bus, :cycles, :nmi
50
+ attr_accessor :int
51
+
52
+ def initialize(bus)
53
+ @bus = bus
54
+ @cycles = 0
55
+ @a = @f = 0xff
56
+ @b = @c = @d = @e = @h = @l = 0xff
57
+ @af_alt = @bc_alt = @de_alt = @hl_alt = 0xffff
58
+ @ix = @iy = @sp = 0xffff
59
+ @wz = @q = @last_q = 0
60
+ @prefix = 0
61
+ @int = @nmi = @nmi_pending = false
62
+ reset!
63
+ end
64
+
65
+ # The RESET line: the program counter, I, R and the interrupt mode go
66
+ # to 0, and interrupts are disabled.
67
+ def reset!
68
+ @pc = @i = @r = @im = 0
69
+ @iff1 = @iff2 = false
70
+ @halted = @after_ei = @after_ld_a_ir = false
71
+ @nmi_pending = false
72
+ end
73
+
74
+ # The NMI line. Asserting it latches an interrupt, taken after the
75
+ # current instruction, and holding it does nothing more.
76
+ def nmi=(asserted)
77
+ @nmi_pending = true if asserted && !@nmi
78
+ @nmi = asserted
79
+ end
80
+
81
+ # The WAIT line: a bus that holds it during an access lengthens that
82
+ # machine cycle by +states+ T-states.
83
+ def wait(states)
84
+ @cycles += states
85
+ end
86
+
87
+ def step!
88
+ if @nmi_pending
89
+ take_nmi
90
+ elsif @int && @iff1 && !@after_ei
91
+ take_int
92
+ else
93
+ @after_ei = @after_ld_a_ir = false
94
+ @last_q = @q
95
+ @q = 0
96
+ @prefix = 0
97
+ @halted ? idle_fetch : execute(fetch_opcode)
98
+ end
99
+ nil
100
+ end
101
+
102
+ def inspect
103
+ "Cycles: #{@cycles}, PC: #{hex(@pc)}, SP: #{hex(@sp)}, AF: #{hex(af)}, BC: #{hex(bc)}, " \
104
+ "DE: #{hex(de)}, HL: #{hex(hl)}, IX: #{hex(@ix)}, IY: #{hex(@iy)}"
105
+ end
106
+
107
+ private
108
+
109
+ def hex(value)
110
+ value.to_s(16).rjust(4, "0")
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class Z80
6
+ # EX AF,AF', EXX, EX DE,HL and EX (SP),HL. Only the last swaps IX or IY
7
+ # after a prefix.
8
+ module Exchanges
9
+ private
10
+
11
+ def exchange_alternates
12
+ bc_alt = @bc_alt
13
+ de_alt = @de_alt
14
+ hl_alt = @hl_alt
15
+ @bc_alt = bc
16
+ @de_alt = de
17
+ @hl_alt = hl
18
+ self.bc = bc_alt
19
+ self.de = de_alt
20
+ self.hl = hl_alt
21
+ end
22
+
23
+ def exchange_af
24
+ af_alt = @af_alt
25
+ @af_alt = af
26
+ self.af = af_alt
27
+ end
28
+
29
+ def exchange_de_hl
30
+ d = @d
31
+ e = @e
32
+ @d = @h
33
+ @e = @l
34
+ @h = d
35
+ @l = e
36
+ end
37
+
38
+ def exchange_stack_top
39
+ low = read_byte(@sp)
40
+ high = read_byte((@sp + 1) & 0xffff)
41
+ @cycles += 1
42
+ value = hl_or_index
43
+ write_byte((@sp + 1) & 0xffff, value >> 8)
44
+ write_byte(@sp, value & 0xff)
45
+ @cycles += 2
46
+ @wz = low | (high << 8)
47
+ self.hl_or_index = @wz
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class Z80
6
+ # The interrupt mode each of ED 46, 4E, 56, 5E, 66, 6E, 76 and 7E sets.
7
+ # 4E and 6E set mode 0 on the NMOS Z80.
8
+ INTERRUPT_MODES = [0, 0, 1, 2, 0, 0, 1, 2].freeze
9
+
10
+ # The ED page: its second quarter, the block instructions, and 8
11
+ # T-states of nothing for the rest.
12
+ module ExtendedPage
13
+ private
14
+
15
+ def execute_extended(opcode)
16
+ case opcode >> 6
17
+ when 1 then extended_operation(opcode)
18
+ when 2 then block_operation(opcode) if (opcode & 0x24) == 0x20
19
+ end
20
+ end
21
+
22
+ def extended_operation(opcode)
23
+ row = (opcode >> 3) & 7
24
+ case opcode & 7
25
+ when 0 then input_register(row)
26
+ when 1 then output_register(row)
27
+ when 2 then add_pair_with_carry(row)
28
+ when 3 then row.nobits?(1) ? store_word(pair(row >> 1)) : set_pair(row >> 1, load_word)
29
+ when 4 then neg
30
+ when 5 then return_from_interrupt
31
+ when 6 then @im = INTERRUPT_MODES[row]
32
+ else special_register(row)
33
+ end
34
+ end
35
+
36
+ # IN r,(C), and IN F,(C) at index 6, which sets the flags alone.
37
+ def input_register(index)
38
+ port = bc
39
+ value = input(port)
40
+ @wz = (port + 1) & 0xffff
41
+ assign_flags((@f & CF) | SZ53P[value])
42
+ set_register(index, value) unless index == 6
43
+ end
44
+
45
+ # OUT (C),r, and at index 6 OUT (C),0.
46
+ def output_register(index)
47
+ port = bc
48
+ output(port, index == 6 ? 0 : register(index))
49
+ @wz = (port + 1) & 0xffff
50
+ end
51
+
52
+ def add_pair_with_carry(row)
53
+ row.nobits?(1) ? sbc16(pair(row >> 1)) : adc16(pair(row >> 1))
54
+ @cycles += 7
55
+ end
56
+
57
+ # RETN and RETI both restore IFF1 from IFF2.
58
+ def return_from_interrupt
59
+ @iff1 = @iff2
60
+ return_from_call
61
+ end
62
+
63
+ # LD I,A, LD R,A, LD A,I, LD A,R, RRD and RLD, and two that do
64
+ # nothing.
65
+ def special_register(row)
66
+ case row
67
+ when 0 then @i = load_ir(@a)
68
+ when 1 then @r = load_ir(@a)
69
+ when 2 then @a = load_a_from_ir(@i)
70
+ when 3 then @a = load_a_from_ir(@r)
71
+ when 4 then rotate_digits(false)
72
+ when 5 then rotate_digits(true)
73
+ end
74
+ end
75
+
76
+ def load_ir(value)
77
+ @cycles += 1
78
+ value
79
+ end
80
+
81
+ # P/V copies IFF2, and an interrupt taken next clears it again.
82
+ def load_a_from_ir(value)
83
+ @cycles += 1
84
+ assign_flags((@f & CF) | SZ53[value] | (@iff2 ? PF : 0))
85
+ @after_ld_a_ir = true
86
+ value
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class Z80
6
+ CF = 0x01
7
+ NF = 0x02
8
+ PF = 0x04
9
+ XF = 0x08
10
+ HF = 0x10
11
+ YF = 0x20
12
+ ZF = 0x40
13
+ SF = 0x80
14
+
15
+ # Bits 5 and 3, which most instructions copy from a result.
16
+ XYF = YF | XF
17
+
18
+ # S, Z, Y and X as a result byte sets them.
19
+ SZ53 = Array.new(256) { |v| (v & (SF | XYF)) | (v.zero? ? ZF : 0) }.freeze
20
+
21
+ # P/V as parity: set when a byte has an even number of bits set.
22
+ PARITY = Array.new(256) { |v| (0x6996 >> ((v ^ (v >> 4)) & 0x0f)).nobits?(1) ? PF : 0 }.freeze
23
+
24
+ SZ53P = Array.new(256) { |v| SZ53[v] | PARITY[v] }.freeze
25
+
26
+ # The flags, which the core keeps in F as the chip does. Every
27
+ # instruction that sets them through the ALU also latches them in Q,
28
+ # which SCF and CCF read on the next instruction.
29
+ module Flags
30
+ private
31
+
32
+ def assign_flags(value)
33
+ @f = value
34
+ @q = value
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class Z80
6
+ # Taking NMI and INT between instructions. Either wakes a halted CPU,
7
+ # whose program counter already points past the HALT.
8
+ module InterruptAcceptance
9
+ private
10
+
11
+ # An opcode fetch whose byte is ignored, a T-state more, and a call
12
+ # to $0066. IFF2 keeps what IFF1 held, for RETN to restore.
13
+ def take_nmi
14
+ @nmi_pending = false
15
+ @halted = false
16
+ @iff1 = false
17
+ @bus.fetch(@pc)
18
+ refresh
19
+ @cycles += 5
20
+ push(@pc)
21
+ @pc = 0x66
22
+ @wz = 0x66
23
+ end
24
+
25
+ # The acknowledge cycle, an M1 with two wait states, reads a byte
26
+ # from the device. Mode 0 runs it as an opcode, which is a RST in
27
+ # practice, mode 1 calls $0038, and mode 2 calls through the vector
28
+ # at I and that byte.
29
+ def take_int
30
+ @halted = false
31
+ @f &= ~PF if @after_ld_a_ir
32
+ @iff1 = @iff2 = false
33
+ @after_ld_a_ir = false
34
+ @prefix = 0
35
+ data = @bus.acknowledge
36
+ refresh
37
+ @cycles += 6
38
+ return execute(data) if @im.zero?
39
+
40
+ @cycles += 1
41
+ push(@pc)
42
+ @pc = @im == 1 ? 0x38 : read_word((@i << 8) | data)
43
+ @wz = @pc
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end