badline 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/CLAUDE.md +59 -31
- data/README.md +1 -1
- data/doc/library.md +9 -9
- data/doc/pinned-behaviour.md +105 -105
- data/doc/snapshots.md +1 -4
- data/lib/badline/audio/bare_player.rb +4 -4
- data/lib/badline/audio/cli.rb +6 -6
- data/lib/badline/audio/jukebox.rb +2 -2
- data/lib/badline/audio/machine_player.rb +2 -2
- data/lib/badline/{media → audio}/queue.rb +1 -1
- data/lib/badline/audio/queued_tune.rb +6 -6
- data/lib/badline/audio/renderer.rb +5 -5
- data/lib/badline/audio/stereo.rb +1 -1
- data/lib/badline/c128/{bus_state.rb → bus/saved_state.rb} +6 -6
- data/lib/badline/c128/bus.rb +30 -51
- data/lib/badline/c128/color_lines.rb +2 -2
- data/lib/badline/c128/cpu.rb +1 -1
- data/lib/badline/c128/drives.rb +10 -11
- data/lib/badline/c128/fast_serial.rb +5 -5
- data/lib/badline/c128/mmu_pages.rb +1 -1
- data/lib/badline/c128/modes.rb +2 -2
- data/lib/badline/c128/saved_state.rb +21 -47
- data/lib/badline/c128/z80.rb +2 -2
- data/lib/badline/c128.rb +18 -72
- data/lib/badline/{computer → c64}/attachments.rb +16 -47
- data/lib/badline/c64/banked_ram/banking.rb +32 -0
- data/lib/badline/c64/banked_ram/plus256k.rb +56 -0
- data/lib/badline/c64/banked_ram/plus60k.rb +45 -0
- data/lib/badline/c64/banked_ram/unexpanded.rb +30 -0
- data/lib/badline/c64/banked_ram.rb +23 -0
- data/lib/badline/c64/bus/extra_sids.rb +32 -0
- data/lib/badline/c64/bus/fittings.rb +40 -0
- data/lib/badline/c64/bus/pla.rb +149 -0
- data/lib/badline/c64/bus/roms.rb +41 -0
- data/lib/badline/c64/bus/saved_state.rb +68 -0
- data/lib/badline/c64/bus/sid_slots.rb +44 -0
- data/lib/badline/c64/bus.rb +218 -0
- data/lib/badline/c64/cartridge/action_replay.rb +128 -0
- data/lib/badline/c64/cartridge/atomic_power.rb +26 -0
- data/lib/badline/c64/cartridge/bank.rb +83 -0
- data/lib/badline/c64/cartridge/comal80.rb +52 -0
- data/lib/badline/c64/cartridge/dinamic.rb +36 -0
- data/lib/badline/c64/cartridge/easy_flash.rb +147 -0
- data/lib/badline/c64/cartridge/epyx_fastload.rb +81 -0
- data/lib/badline/c64/cartridge/final_cartridge3.rb +91 -0
- data/lib/badline/c64/cartridge/flash/saved_state.rb +40 -0
- data/lib/badline/c64/cartridge/flash.rb +279 -0
- data/lib/badline/c64/cartridge/freezer.rb +35 -0
- data/lib/badline/c64/cartridge/fun_play.rb +40 -0
- data/lib/badline/c64/cartridge/g_mod2.rb +76 -0
- data/lib/badline/c64/cartridge/game_system.rb +42 -0
- data/lib/badline/c64/cartridge/geo_ram.rb +81 -0
- data/lib/badline/c64/cartridge/kcs_power.rb +77 -0
- data/lib/badline/c64/cartridge/mach5.rb +34 -0
- data/lib/badline/c64/cartridge/magic_desk.rb +32 -0
- data/lib/badline/c64/cartridge/ocean.rb +37 -0
- data/lib/badline/c64/cartridge/pagefox.rb +70 -0
- data/lib/badline/c64/cartridge/retro_replay/saved_state.rb +47 -0
- data/lib/badline/c64/cartridge/retro_replay.rb +286 -0
- data/lib/badline/c64/cartridge/rex_utility.rb +31 -0
- data/lib/badline/c64/cartridge/rgcd.rb +60 -0
- data/lib/badline/c64/cartridge/saved_state.rb +63 -0
- data/lib/badline/c64/cartridge/simons_basic.rb +37 -0
- data/lib/badline/c64/cartridge/standard.rb +17 -0
- data/lib/badline/c64/cartridge/super_games.rb +50 -0
- data/lib/badline/c64/cartridge/westermann.rb +32 -0
- data/lib/badline/c64/cartridge/zaxxon.rb +68 -0
- data/lib/badline/c64/cartridge.rb +258 -0
- data/lib/badline/c64/color_memory.rb +27 -0
- data/lib/badline/c64/common.rb +34 -0
- data/lib/badline/c64/kernal_traps.rb +89 -0
- data/lib/badline/c64/reu/dma/saved_state.rb +52 -0
- data/lib/badline/c64/reu/dma.rb +275 -0
- data/lib/badline/c64/reu/ram.rb +109 -0
- data/lib/badline/c64/reu/saved_state.rb +55 -0
- data/lib/badline/c64/reu/trigger.rb +34 -0
- data/lib/badline/c64/reu.rb +291 -0
- data/lib/badline/{computer → c64}/saved_state.rb +13 -18
- data/lib/badline/{computer → c64}/true_drives.rb +20 -31
- data/lib/badline/{computer.rb → c64.rb} +22 -80
- data/lib/badline/chips/cia/fast_forward.rb +62 -0
- data/lib/badline/chips/cia/interrupt_register.rb +145 -0
- data/lib/badline/chips/cia/saved_state.rb +49 -0
- data/lib/badline/chips/cia/serial/saved_state.rb +45 -0
- data/lib/badline/chips/cia/serial.rb +250 -0
- data/lib/badline/chips/cia/time_of_day.rb +232 -0
- data/lib/badline/chips/cia/timer.rb +208 -0
- data/lib/badline/chips/cia.rb +281 -0
- data/lib/badline/chips/cpu/addressing.rb +133 -0
- data/lib/badline/chips/cpu/boundary.rb +56 -0
- data/lib/badline/chips/cpu/core.rb +167 -0
- data/lib/badline/chips/cpu/instruction.rb +338 -0
- data/lib/badline/chips/cpu/instruction_set/arithmetic.rb +118 -0
- data/lib/badline/chips/cpu/instruction_set/bitwise.rb +130 -0
- data/lib/badline/chips/cpu/instruction_set/branch.rb +83 -0
- data/lib/badline/chips/cpu/instruction_set/flag.rb +67 -0
- data/lib/badline/chips/cpu/instruction_set/illegal.rb +274 -0
- data/lib/badline/chips/cpu/instruction_set/inc_dec.rb +73 -0
- data/lib/badline/chips/cpu/instruction_set/stack.rb +56 -0
- data/lib/badline/chips/cpu/instruction_set/transfer.rb +141 -0
- data/lib/badline/chips/cpu/instruction_set.rb +59 -0
- data/lib/badline/chips/cpu/interrupts.rb +108 -0
- data/lib/badline/chips/cpu/microcode.rb +179 -0
- data/lib/badline/chips/cpu/operations.rb +90 -0
- data/lib/badline/chips/cpu/port.rb +116 -0
- data/lib/badline/chips/cpu/saved_state.rb +117 -0
- data/lib/badline/chips/cpu/stack_operations.rb +84 -0
- data/lib/badline/chips/cpu/traps.rb +23 -0
- data/lib/badline/chips/cpu.rb +12 -0
- data/lib/badline/chips/sid/catch_up.rb +122 -0
- data/lib/badline/chips/sid/decimator.rb +66 -0
- data/lib/badline/chips/sid/envelope/saved_state.rb +70 -0
- data/lib/badline/chips/sid/envelope.rb +241 -0
- data/lib/badline/chips/sid/filter/saved_state.rb +42 -0
- data/lib/badline/chips/sid/filter.rb +241 -0
- data/lib/badline/chips/sid/saved_state.rb +52 -0
- data/lib/badline/chips/sid/voice.rb +79 -0
- data/lib/badline/chips/sid/waveform/combined.rb +128 -0
- data/lib/badline/chips/sid/waveform/fast_forward.rb +107 -0
- data/lib/badline/chips/sid/waveform/noise_writeback.rb +124 -0
- data/lib/badline/chips/sid/waveform/saved_state.rb +68 -0
- data/lib/badline/chips/sid/waveform.rb +307 -0
- data/lib/badline/chips/sid.rb +265 -0
- data/lib/badline/{c128 → chips}/vdc/memory.rb +1 -1
- data/lib/badline/{c128 → chips}/vdc/painter.rb +1 -1
- data/lib/badline/{c128 → chips}/vdc/raster.rb +1 -1
- data/lib/badline/chips/vdc/saved_state.rb +36 -0
- data/lib/badline/{c128 → chips}/vdc/window.rb +1 -1
- data/lib/badline/{c128 → chips}/vdc.rb +7 -31
- data/lib/badline/chips/via/control_lines.rb +124 -0
- data/lib/badline/chips/via/fast_forward.rb +55 -0
- data/lib/badline/chips/via/interrupt_register.rb +69 -0
- data/lib/badline/chips/via/saved_state.rb +44 -0
- data/lib/badline/chips/via/shift_register.rb +182 -0
- data/lib/badline/chips/via/timer1.rb +133 -0
- data/lib/badline/chips/via/timer2.rb +135 -0
- data/lib/badline/chips/via.rb +268 -0
- data/lib/badline/chips/vic/bank.rb +135 -0
- data/lib/badline/chips/vic/border_mask.rb +88 -0
- data/lib/badline/chips/vic/collisions.rb +117 -0
- data/lib/badline/chips/vic/color_patches.rb +49 -0
- data/lib/badline/chips/vic/display_state.rb +187 -0
- data/lib/badline/chips/vic/graphics_mode.rb +166 -0
- data/lib/badline/chips/vic/graphics_shifter/saved_state.rb +40 -0
- data/lib/badline/chips/vic/graphics_shifter.rb +187 -0
- data/lib/badline/chips/vic/register_log.rb +83 -0
- data/lib/badline/chips/vic/registers.rb +197 -0
- data/lib/badline/chips/vic/saved_state.rb +82 -0
- data/lib/badline/chips/vic/sequencer/saved_state.rb +91 -0
- data/lib/badline/chips/vic/sequencer.rb +277 -0
- data/lib/badline/chips/vic/sequencer_output.rb +118 -0
- data/lib/badline/chips/vic/sprite/internal_bus.rb +70 -0
- data/lib/badline/chips/vic/sprite/saved_state.rb +66 -0
- data/lib/badline/chips/vic/sprite/shifter.rb +148 -0
- data/lib/badline/chips/vic/sprite/timing.rb +58 -0
- data/lib/badline/chips/vic/sprite.rb +339 -0
- data/lib/badline/chips/vic/sprites/saved_state.rb +59 -0
- data/lib/badline/chips/vic/sprites.rb +284 -0
- data/lib/badline/chips/vic.rb +783 -0
- data/lib/badline/chips/vic_i/painter/saved_state.rb +40 -0
- data/lib/badline/{vic20/vic → chips/vic_i}/painter.rb +6 -30
- data/lib/badline/{vic20/vic → chips/vic_i}/saved_state.rb +2 -2
- data/lib/badline/chips/vic_i/sound/output.rb +85 -0
- data/lib/badline/chips/vic_i/sound.rb +235 -0
- data/lib/badline/{vic20/vic → chips/vic_i}/text_window.rb +2 -2
- data/lib/badline/{vic20/vic.rb → chips/vic_i.rb} +5 -5
- data/lib/badline/chips/z80/arithmetic.rb +119 -0
- data/lib/badline/chips/z80/bit_page.rb +57 -0
- data/lib/badline/chips/z80/block_io.rb +60 -0
- data/lib/badline/chips/z80/block_transfers.rb +61 -0
- data/lib/badline/chips/z80/bus_cycles.rb +113 -0
- data/lib/badline/chips/z80/core.rb +115 -0
- data/lib/badline/chips/z80/exchanges.rb +52 -0
- data/lib/badline/chips/z80/extended_page.rb +91 -0
- data/lib/badline/chips/z80/flags.rb +39 -0
- data/lib/badline/chips/z80/interrupt_acceptance.rb +48 -0
- data/lib/badline/chips/z80/jumps.rb +84 -0
- data/lib/badline/chips/z80/loads.rb +100 -0
- data/lib/badline/chips/z80/main_page.rb +136 -0
- data/lib/badline/chips/z80/registers.rb +122 -0
- data/lib/badline/chips/z80/saved_state.rb +71 -0
- data/lib/badline/chips/z80/shifts.rb +66 -0
- data/lib/badline/chips/z80.rb +13 -0
- data/lib/badline/core.rb +27 -29
- data/lib/badline/drives/datasette/saved_state.rb +37 -0
- data/lib/badline/drives/datasette.rb +140 -0
- data/lib/badline/drives/engine/core.rb +149 -0
- data/lib/badline/drives/engine/fast_serial.rb +75 -0
- data/lib/badline/drives/engine/idle.rb +127 -0
- data/lib/badline/drives/engine/idle_cpu.rb +30 -0
- data/lib/badline/drives/engine/orbit.rb +81 -0
- data/lib/badline/drives/engine/serial_lines.rb +75 -0
- data/lib/badline/drives/engine/sleep.rb +114 -0
- data/lib/badline/drives/engine/vias.rb +86 -0
- data/lib/badline/drives/engine/watch.rb +152 -0
- data/lib/badline/drives/engine.rb +11 -0
- data/lib/badline/drives/model1541/bus.rb +88 -0
- data/lib/badline/drives/model1541/byte_ready.rb +50 -0
- data/lib/badline/drives/model1541/cpu.rb +13 -0
- data/lib/badline/drives/model1541/disk/saved_state.rb +88 -0
- data/lib/badline/drives/model1541/disk.rb +317 -0
- data/lib/badline/drives/model1541/disk_via.rb +38 -0
- data/lib/badline/drives/model1541/gcr.rb +59 -0
- data/lib/badline/drives/model1541/mechanism/saved_state.rb +72 -0
- data/lib/badline/drives/model1541/mechanism.rb +315 -0
- data/lib/badline/drives/model1541/rotation.rb +123 -0
- data/lib/badline/drives/model1541/saved_state.rb +44 -0
- data/lib/badline/drives/model1541/sector_reader.rb +78 -0
- data/lib/badline/drives/model1541/serial_port.rb +20 -0
- data/lib/badline/drives/model1541/track.rb +100 -0
- data/lib/badline/drives/model1541.rb +81 -0
- data/lib/badline/drives/model1571/bus.rb +113 -0
- data/lib/badline/drives/model1571/cpu.rb +13 -0
- data/lib/badline/drives/model1571/saved_state.rb +47 -0
- data/lib/badline/drives/model1571/serial_port.rb +39 -0
- data/lib/badline/drives/model1571/serial_via.rb +27 -0
- data/lib/badline/drives/model1571/wd1770.rb +122 -0
- data/lib/badline/drives/model1571.rb +142 -0
- data/lib/badline/drives/model1581/bus.rb +139 -0
- data/lib/badline/drives/model1581/cpu.rb +13 -0
- data/lib/badline/drives/model1581/disk/saved_state.rb +89 -0
- data/lib/badline/drives/model1581/disk.rb +137 -0
- data/lib/badline/drives/model1581/mechanism.rb +119 -0
- data/lib/badline/drives/model1581/saved_state.rb +42 -0
- data/lib/badline/drives/model1581/serial_port.rb +54 -0
- data/lib/badline/drives/model1581/slot.rb +79 -0
- data/lib/badline/drives/model1581/track.rb +102 -0
- data/lib/badline/drives/model1581/track_bytes.rb +77 -0
- data/lib/badline/drives/model1581/wd1772/registers.rb +91 -0
- data/lib/badline/drives/model1581/wd1772/saved_state.rb +68 -0
- data/lib/badline/drives/model1581/wd1772/sector_writes.rb +75 -0
- data/lib/badline/drives/model1581/wd1772/sectors.rb +152 -0
- data/lib/badline/drives/model1581/wd1772/stepping.rb +111 -0
- data/lib/badline/drives/model1581/wd1772/tracks.rb +127 -0
- data/lib/badline/drives/model1581/wd1772/turn.rb +75 -0
- data/lib/badline/drives/model1581/wd1772.rb +218 -0
- data/lib/badline/drives/model1581.rb +206 -0
- data/lib/badline/drives/serial_bus.rb +161 -0
- data/lib/badline/frontend/boot.rb +10 -61
- data/lib/badline/frontend/machine_window.rb +3 -1
- data/lib/badline/frontend/player/filter_view.rb +1 -1
- data/lib/badline/frontend/player/player_controller.rb +2 -2
- data/lib/badline/frontend/player/player_screen.rb +1 -0
- data/lib/badline/frontend/player/theme.rb +7 -7
- data/lib/badline/frontend/timeline.rb +3 -3
- data/lib/badline/input/control_ports.rb +78 -0
- data/lib/badline/input/joystick.rb +27 -0
- data/lib/badline/input/keyboard.rb +114 -0
- data/lib/badline/input.rb +3 -0
- data/lib/badline/kernal_trap/{drive → dos}/block_commands.rb +1 -1
- data/lib/badline/kernal_trap/dos/channel.rb +183 -0
- data/lib/badline/kernal_trap/{drive → dos}/channels.rb +1 -1
- data/lib/badline/kernal_trap/{drive → dos}/memory.rb +1 -1
- data/lib/badline/kernal_trap/{drive → dos}/parameters.rb +1 -1
- data/lib/badline/kernal_trap/{drive → dos}/status.rb +1 -1
- data/lib/badline/kernal_trap/{drive → dos}/write_file.rb +1 -1
- data/lib/badline/kernal_trap/{drive → dos}/writes.rb +1 -1
- data/lib/badline/kernal_trap/{drive.rb → dos.rb} +11 -10
- data/lib/badline/kernal_trap/{file.rb → file_routine.rb} +1 -1
- data/lib/badline/kernal_trap/load.rb +6 -6
- data/lib/badline/kernal_trap/save.rb +5 -5
- data/lib/badline/kernal_trap/serial.rb +7 -7
- data/lib/badline/kernal_trap.rb +2 -3
- data/lib/badline/machine/clocking.rb +50 -0
- data/lib/badline/machine.rb +63 -7
- data/lib/badline/media/boot_disk.rb +2 -2
- data/lib/badline/media/disk_list.rb +3 -3
- data/lib/badline/media/disk_set.rb +1 -1
- data/lib/badline/media/extensions.rb +33 -0
- data/lib/badline/media/program.rb +28 -0
- data/lib/badline/media/true_drive.rb +4 -3
- data/lib/badline/media/tune.rb +35 -0
- data/lib/badline/media/vic20_cartridge.rb +1 -7
- data/lib/badline/media/vic20_media.rb +38 -80
- data/lib/badline/media.rb +84 -81
- data/lib/badline/model.rb +1 -1
- data/lib/badline/options/event.rb +3 -1
- data/lib/badline/roms/README +6 -6
- data/lib/badline/sdl.rb +1 -0
- data/lib/badline/{storage/sid_file.rb → sid_tune/file.rb} +3 -3
- data/lib/badline/{storage → sid_tune}/hvsc.rb +7 -7
- data/lib/badline/{storage → sid_tune}/song_lengths.rb +2 -2
- data/lib/badline/{storage → sid_tune}/stil/credit.rb +1 -1
- data/lib/badline/{storage → sid_tune}/stil.rb +3 -3
- data/lib/badline/sid_tune.rb +6 -0
- data/lib/badline/snapshot/c128_setup.rb +43 -0
- data/lib/badline/snapshot/c64_setup.rb +79 -0
- data/lib/badline/snapshot/image.rb +5 -25
- data/lib/badline/snapshot/machine_state.rb +10 -2
- data/lib/badline/snapshot/setup.rb +22 -66
- data/lib/badline/snapshot/state.rb +8 -17
- data/lib/badline/snapshot/storage_setup.rb +68 -0
- data/lib/badline/snapshot/vic20_setup.rb +37 -0
- data/lib/badline/snapshot/vice/c64_mem.rb +1 -1
- data/lib/badline/snapshot/vice/restore.rb +1 -1
- data/lib/badline/snapshot/vice/reu1764.rb +1 -1
- data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
- data/lib/badline/snapshot/vice.rb +7 -5
- data/lib/badline/snapshot.rb +13 -12
- data/lib/badline/storage/d64_image.rb +15 -9
- data/lib/badline/storage/d71_image.rb +0 -2
- data/lib/badline/storage/d81_image.rb +0 -2
- data/lib/badline/storage/disk_image/writing.rb +2 -2
- data/lib/badline/storage/disk_image.rb +3 -6
- data/lib/badline/storage/g64_image.rb +2 -2
- data/lib/badline/storage/host_directory.rb +0 -5
- data/lib/badline/storage/t64.rb +2 -8
- data/lib/badline/storage/unavailable.rb +1 -1
- data/lib/badline/storage.rb +0 -37
- data/lib/badline/support/c128_checkpoint.rb +39 -0
- data/lib/badline/support/checkpoint.rb +108 -0
- data/lib/badline/support/vic20_checkpoint.rb +38 -0
- data/lib/badline/support.rb +5 -0
- data/lib/badline/version.rb +1 -1
- data/lib/badline/vic20/attachments.rb +11 -81
- data/lib/badline/vic20/bus/saved_state.rb +35 -0
- data/lib/badline/vic20/bus.rb +3 -25
- data/lib/badline/vic20/cpu.rb +1 -1
- data/lib/badline/vic20/port_wiring.rb +4 -4
- data/lib/badline/vic20/saved_state.rb +16 -60
- data/lib/badline/vic20/user_via_ports.rb +2 -2
- data/lib/badline/vic20.rb +20 -51
- metadata +250 -221
- data/lib/badline/address_bus/extra_sids.rb +0 -30
- data/lib/badline/address_bus/fittings.rb +0 -38
- data/lib/badline/address_bus/pla.rb +0 -147
- data/lib/badline/address_bus/roms.rb +0 -39
- data/lib/badline/address_bus/saved_state.rb +0 -72
- data/lib/badline/address_bus/sid_slots.rb +0 -42
- data/lib/badline/address_bus.rb +0 -235
- data/lib/badline/cartridge/action_replay.rb +0 -126
- data/lib/badline/cartridge/atomic_power.rb +0 -24
- data/lib/badline/cartridge/bank.rb +0 -81
- data/lib/badline/cartridge/comal80.rb +0 -50
- data/lib/badline/cartridge/dinamic.rb +0 -34
- data/lib/badline/cartridge/easy_flash.rb +0 -145
- data/lib/badline/cartridge/epyx_fastload.rb +0 -79
- data/lib/badline/cartridge/final_cartridge3.rb +0 -89
- data/lib/badline/cartridge/flash.rb +0 -306
- data/lib/badline/cartridge/freezer.rb +0 -33
- data/lib/badline/cartridge/fun_play.rb +0 -38
- data/lib/badline/cartridge/g_mod2.rb +0 -74
- data/lib/badline/cartridge/game_system.rb +0 -40
- data/lib/badline/cartridge/geo_ram.rb +0 -79
- data/lib/badline/cartridge/kcs_power.rb +0 -75
- data/lib/badline/cartridge/mach5.rb +0 -32
- data/lib/badline/cartridge/magic_desk.rb +0 -30
- data/lib/badline/cartridge/ocean.rb +0 -35
- data/lib/badline/cartridge/pagefox.rb +0 -68
- data/lib/badline/cartridge/retro_replay.rb +0 -320
- data/lib/badline/cartridge/rex_utility.rb +0 -29
- data/lib/badline/cartridge/rgcd.rb +0 -58
- data/lib/badline/cartridge/simons_basic.rb +0 -35
- data/lib/badline/cartridge/standard.rb +0 -15
- data/lib/badline/cartridge/super_games.rb +0 -48
- data/lib/badline/cartridge/westermann.rb +0 -30
- data/lib/badline/cartridge/zaxxon.rb +0 -66
- data/lib/badline/cartridge.rb +0 -303
- data/lib/badline/checkpoint.rb +0 -98
- data/lib/badline/cia/fast_forward.rb +0 -60
- data/lib/badline/cia/interrupt_register.rb +0 -143
- data/lib/badline/cia/serial.rb +0 -275
- data/lib/badline/cia/state.rb +0 -47
- data/lib/badline/cia/timer.rb +0 -206
- data/lib/badline/cia.rb +0 -279
- data/lib/badline/color_memory.rb +0 -25
- data/lib/badline/computer/kernal_traps.rb +0 -29
- data/lib/badline/control_ports.rb +0 -76
- data/lib/badline/cpu/addressing.rb +0 -131
- data/lib/badline/cpu/boundary.rb +0 -54
- data/lib/badline/cpu/core.rb +0 -165
- data/lib/badline/cpu/microcode.rb +0 -177
- data/lib/badline/cpu/operations.rb +0 -88
- data/lib/badline/cpu/saved_state.rb +0 -115
- data/lib/badline/cpu/stack_operations.rb +0 -82
- data/lib/badline/cpu.rb +0 -10
- data/lib/badline/cycleable.rb +0 -38
- data/lib/badline/datasette.rb +0 -161
- data/lib/badline/drive/core.rb +0 -147
- data/lib/badline/drive/fast_serial.rb +0 -73
- data/lib/badline/drive/idle.rb +0 -125
- data/lib/badline/drive/idle_cpu.rb +0 -28
- data/lib/badline/drive/orbit.rb +0 -79
- data/lib/badline/drive/serial_lines.rb +0 -73
- data/lib/badline/drive/sleep.rb +0 -112
- data/lib/badline/drive/vias.rb +0 -84
- data/lib/badline/drive/watch.rb +0 -150
- data/lib/badline/drive.rb +0 -11
- data/lib/badline/drive1541/bus.rb +0 -86
- data/lib/badline/drive1541/byte_ready.rb +0 -48
- data/lib/badline/drive1541/cpu.rb +0 -11
- data/lib/badline/drive1541/disk.rb +0 -318
- data/lib/badline/drive1541/disk_state.rb +0 -94
- data/lib/badline/drive1541/disk_via.rb +0 -36
- data/lib/badline/drive1541/gcr.rb +0 -57
- data/lib/badline/drive1541/mechanism.rb +0 -313
- data/lib/badline/drive1541/mechanism_state.rb +0 -68
- data/lib/badline/drive1541/rotation.rb +0 -121
- data/lib/badline/drive1541/sector_reader.rb +0 -76
- data/lib/badline/drive1541/serial_port.rb +0 -18
- data/lib/badline/drive1541/track.rb +0 -98
- data/lib/badline/drive1541.rb +0 -111
- data/lib/badline/drive1571/bus.rb +0 -111
- data/lib/badline/drive1571/cpu.rb +0 -11
- data/lib/badline/drive1571/serial_port.rb +0 -37
- data/lib/badline/drive1571/serial_via.rb +0 -25
- data/lib/badline/drive1571/wd1770.rb +0 -120
- data/lib/badline/drive1571.rb +0 -175
- data/lib/badline/drive1581/bus.rb +0 -137
- data/lib/badline/drive1581/cpu.rb +0 -11
- data/lib/badline/drive1581/disk.rb +0 -135
- data/lib/badline/drive1581/disk_state.rb +0 -87
- data/lib/badline/drive1581/mechanism.rb +0 -117
- data/lib/badline/drive1581/serial_port.rb +0 -52
- data/lib/badline/drive1581/slot.rb +0 -78
- data/lib/badline/drive1581/track.rb +0 -100
- data/lib/badline/drive1581/track_bytes.rb +0 -75
- data/lib/badline/drive1581/wd1772/registers.rb +0 -89
- data/lib/badline/drive1581/wd1772/sector_writes.rb +0 -73
- data/lib/badline/drive1581/wd1772/sectors.rb +0 -150
- data/lib/badline/drive1581/wd1772/state.rb +0 -66
- data/lib/badline/drive1581/wd1772/stepping.rb +0 -109
- data/lib/badline/drive1581/wd1772/tracks.rb +0 -125
- data/lib/badline/drive1581/wd1772/turn.rb +0 -73
- data/lib/badline/drive1581/wd1772.rb +0 -216
- data/lib/badline/drive1581.rb +0 -233
- data/lib/badline/iec_bus.rb +0 -159
- data/lib/badline/instruction.rb +0 -334
- data/lib/badline/instruction_set/arithmetic.rb +0 -114
- data/lib/badline/instruction_set/bitwise.rb +0 -126
- data/lib/badline/instruction_set/branch.rb +0 -79
- data/lib/badline/instruction_set/flag.rb +0 -63
- data/lib/badline/instruction_set/illegal.rb +0 -270
- data/lib/badline/instruction_set/inc_dec.rb +0 -69
- data/lib/badline/instruction_set/stack.rb +0 -52
- data/lib/badline/instruction_set/transfer.rb +0 -137
- data/lib/badline/instruction_set.rb +0 -55
- data/lib/badline/interrupts.rb +0 -104
- data/lib/badline/joystick.rb +0 -25
- data/lib/badline/kernal_trap/channel.rb +0 -181
- data/lib/badline/keyboard.rb +0 -112
- data/lib/badline/ram_expansion/banking.rb +0 -30
- data/lib/badline/ram_expansion/plus256k.rb +0 -54
- data/lib/badline/ram_expansion/plus60k.rb +0 -43
- data/lib/badline/ram_expansion/unexpanded.rb +0 -28
- data/lib/badline/ram_expansion.rb +0 -21
- data/lib/badline/reu/dma/saved_state.rb +0 -50
- data/lib/badline/reu/dma.rb +0 -273
- data/lib/badline/reu/ram.rb +0 -107
- data/lib/badline/reu/saved_state.rb +0 -80
- data/lib/badline/reu/trigger.rb +0 -32
- data/lib/badline/reu.rb +0 -289
- data/lib/badline/sid/catch_up.rb +0 -120
- data/lib/badline/sid/decimator.rb +0 -64
- data/lib/badline/sid/envelope/state.rb +0 -68
- data/lib/badline/sid/envelope.rb +0 -239
- data/lib/badline/sid/filter.rb +0 -263
- data/lib/badline/sid/voice.rb +0 -77
- data/lib/badline/sid/waveform/combined.rb +0 -126
- data/lib/badline/sid/waveform/fast_forward.rb +0 -105
- data/lib/badline/sid/waveform/noise_writeback.rb +0 -122
- data/lib/badline/sid/waveform/state.rb +0 -66
- data/lib/badline/sid/waveform.rb +0 -305
- data/lib/badline/sid.rb +0 -303
- data/lib/badline/time_of_day.rb +0 -228
- data/lib/badline/traps.rb +0 -19
- data/lib/badline/via/control_lines.rb +0 -122
- data/lib/badline/via/fast_forward.rb +0 -53
- data/lib/badline/via/interrupt_register.rb +0 -67
- data/lib/badline/via/shift_register.rb +0 -180
- data/lib/badline/via/state.rb +0 -42
- data/lib/badline/via/timer1.rb +0 -131
- data/lib/badline/via/timer2.rb +0 -133
- data/lib/badline/via.rb +0 -266
- data/lib/badline/vic/bank.rb +0 -133
- data/lib/badline/vic/border_mask.rb +0 -86
- data/lib/badline/vic/collisions.rb +0 -115
- data/lib/badline/vic/color_patches.rb +0 -47
- data/lib/badline/vic/display_state.rb +0 -185
- data/lib/badline/vic/graphics_mode.rb +0 -164
- data/lib/badline/vic/graphics_shifter.rb +0 -207
- data/lib/badline/vic/register_log.rb +0 -81
- data/lib/badline/vic/registers.rb +0 -195
- data/lib/badline/vic/sequencer.rb +0 -275
- data/lib/badline/vic/sequencer_output.rb +0 -116
- data/lib/badline/vic/sequencer_state.rb +0 -89
- data/lib/badline/vic/sprite/internal_bus.rb +0 -68
- data/lib/badline/vic/sprite/saved_state.rb +0 -64
- data/lib/badline/vic/sprite/shifter.rb +0 -146
- data/lib/badline/vic/sprite/timing.rb +0 -56
- data/lib/badline/vic/sprite.rb +0 -337
- data/lib/badline/vic/sprites.rb +0 -282
- data/lib/badline/vic/sprites_state.rb +0 -57
- data/lib/badline/vic.rb +0 -852
- data/lib/badline/vic20/sound/output.rb +0 -83
- data/lib/badline/vic20/sound.rb +0 -233
- data/lib/badline/z80/arithmetic.rb +0 -117
- data/lib/badline/z80/bit_page.rb +0 -55
- data/lib/badline/z80/block_io.rb +0 -58
- data/lib/badline/z80/block_transfers.rb +0 -59
- data/lib/badline/z80/bus_cycles.rb +0 -111
- data/lib/badline/z80/core.rb +0 -113
- data/lib/badline/z80/exchanges.rb +0 -50
- data/lib/badline/z80/extended_page.rb +0 -89
- data/lib/badline/z80/flags.rb +0 -37
- data/lib/badline/z80/interrupt_acceptance.rb +0 -46
- data/lib/badline/z80/jumps.rb +0 -82
- data/lib/badline/z80/loads.rb +0 -98
- data/lib/badline/z80/main_page.rb +0 -134
- data/lib/badline/z80/registers.rb +0 -120
- data/lib/badline/z80/saved_state.rb +0 -69
- data/lib/badline/z80/shifts.rb +0 -64
- data/lib/badline/z80.rb +0 -11
- /data/lib/badline/snapshot/{fields.rb → vice/fields.rb} +0 -0
data/lib/badline/cpu/core.rb
DELETED
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "badline/cpu/microcode"
|
|
4
|
-
require "badline/cpu/addressing"
|
|
5
|
-
require "badline/cpu/operations"
|
|
6
|
-
require "badline/cpu/stack_operations"
|
|
7
|
-
require "badline/cpu/boundary"
|
|
8
|
-
require "badline/cpu/saved_state"
|
|
9
|
-
|
|
10
|
-
module Badline
|
|
11
|
-
class CPU
|
|
12
|
-
STATUS_FLAGS = [:carry, :zero, :interrupt, :decimal, :break, 1, :overflow, :negative].freeze
|
|
13
|
-
|
|
14
|
-
# The 6502 core, on whatever bus +memory+ is. The C64's 6510 (CPU) and
|
|
15
|
-
# the 1541's 6502 (Drive1541::CPU) each include it.
|
|
16
|
-
module Core
|
|
17
|
-
include IntegerHelper
|
|
18
|
-
include InstructionSet
|
|
19
|
-
include Interrupts
|
|
20
|
-
include Traps
|
|
21
|
-
include Addressing
|
|
22
|
-
include Operations
|
|
23
|
-
include StackOperations
|
|
24
|
-
include Boundary
|
|
25
|
-
include SavedState
|
|
26
|
-
|
|
27
|
-
attr_reader :memory, :instructions, :boundary_crossed, :cycles, :pending_write
|
|
28
|
-
attr_accessor :program_counter, :stack_pointer, :status, :a, :x, :y, :nmi, :irq
|
|
29
|
-
|
|
30
|
-
alias pending_write? pending_write
|
|
31
|
-
|
|
32
|
-
# +ane_constant+ is ANE's magic constant, which varies from chip to
|
|
33
|
-
# chip. The default is the C64 6510's.
|
|
34
|
-
def initialize(memory, debug: false, ane_constant: 0xef)
|
|
35
|
-
@debug = debug
|
|
36
|
-
@ane_constant = ane_constant
|
|
37
|
-
@memory = memory
|
|
38
|
-
@status = CPUStatus.new(STATUS_FLAGS, value: 0b00100000)
|
|
39
|
-
reset_registers
|
|
40
|
-
|
|
41
|
-
@nmi = @irq = false
|
|
42
|
-
@irq_sample = @irq_pending = false
|
|
43
|
-
@nmi_sample = @nmi_pending = false
|
|
44
|
-
@skip_poll = false
|
|
45
|
-
@boundary_crossed = false
|
|
46
|
-
@interrupt = nil
|
|
47
|
-
@brk = false
|
|
48
|
-
@pending_write = false
|
|
49
|
-
@stalled_at = nil
|
|
50
|
-
@so_high = true
|
|
51
|
-
|
|
52
|
-
@cycles = 0
|
|
53
|
-
@instructions = 0
|
|
54
|
-
@traps = nil
|
|
55
|
-
end_sequence
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def reset!
|
|
59
|
-
status.interrupt = true
|
|
60
|
-
reset_registers
|
|
61
|
-
@nmi = false
|
|
62
|
-
@irq_sample = @irq_pending = false
|
|
63
|
-
@nmi_sample = @nmi_pending = false
|
|
64
|
-
@skip_poll = false
|
|
65
|
-
@pending_write = false
|
|
66
|
-
end_sequence
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def p
|
|
70
|
-
status.value
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def p=(new_value)
|
|
74
|
-
status.value = new_value
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def cycle!
|
|
78
|
-
poll # the interrupt lines
|
|
79
|
-
|
|
80
|
-
# Run the next step
|
|
81
|
-
index = @index
|
|
82
|
-
@index = index + 1
|
|
83
|
-
send(@plan[index])
|
|
84
|
-
@cycles += 1
|
|
85
|
-
|
|
86
|
-
# Record if the next step writes to memory
|
|
87
|
-
@pending_write = @writes[@index]
|
|
88
|
-
nil
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
# Called instead of #cycle! on a cycle the VIC holds the CPU through
|
|
92
|
-
# BA. Records which cycle the CPU was stalled before, and keeps
|
|
93
|
-
# sampling the interrupt lines.
|
|
94
|
-
def stall!
|
|
95
|
-
@stalled_at = @cycles
|
|
96
|
-
sample_while_stalled
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
# The 6502's SO (set overflow) pin, which the 6510 leaves out, so the
|
|
100
|
-
# C64 never drives it. A falling edge sets V and a held level does
|
|
101
|
-
# nothing more.
|
|
102
|
-
def so=(high)
|
|
103
|
-
@status.overflow = true if @so_high && !high
|
|
104
|
-
@so_high = high
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
# Pulses SO: pulls it low, which sets V, and releases it.
|
|
108
|
-
def so!
|
|
109
|
-
@status.overflow = true
|
|
110
|
-
@so_high = true
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def jammed?
|
|
114
|
-
@plan.equal?(JAMMED_PLAN)
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
# Runs to the end of the instruction, or until the CPU jams.
|
|
118
|
-
def step!
|
|
119
|
-
cycle!
|
|
120
|
-
cycle! until @plan.equal?(FETCH_PLAN) || jammed?
|
|
121
|
-
nil
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
# Whether the next cycle fetches an opcode.
|
|
125
|
-
def boundary? = @index.zero? && @plan.equal?(FETCH_PLAN)
|
|
126
|
-
|
|
127
|
-
def trapped? = !@traps.nil?
|
|
128
|
-
|
|
129
|
-
def inspect
|
|
130
|
-
"Cycles: #{@cycles}, PC: #{format16(program_counter)}, " \
|
|
131
|
-
"SP: #{format8(stack_pointer)}, A: #{format8(a)}, X: #{format8(x)}, " \
|
|
132
|
-
"Y: #{format8(y)}, P: #{format8(p)}"
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
private
|
|
136
|
-
|
|
137
|
-
# True when the CPU was stalled right before this cycle.
|
|
138
|
-
def stalled_before_this_cycle?
|
|
139
|
-
@stalled_at == @cycles
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
# True when the CPU was stalled right before the cycle that preceded
|
|
143
|
-
# this one.
|
|
144
|
-
def stalled_before_previous_cycle?
|
|
145
|
-
@stalled_at == @cycles - 1
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def write_byte(addr, value)
|
|
149
|
-
@memory.poke(addr, value)
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def stack_address(offset = 0)
|
|
153
|
-
0x0100 | ((@stack_pointer + offset) & 0xff)
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
def reset_registers
|
|
157
|
-
# The program counter is initialized from the reset vector
|
|
158
|
-
@program_counter = @memory.peek16(0xfffc)
|
|
159
|
-
# Stack pointer starts at 0x01ff and grows down
|
|
160
|
-
@stack_pointer = 0xff
|
|
161
|
-
@a = @x = @y = 0x0
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
end
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Badline
|
|
4
|
-
class CPU
|
|
5
|
-
class InvalidOpcodeError < StandardError; end
|
|
6
|
-
|
|
7
|
-
# Steps that write to memory. The CPU keeps running through BA on
|
|
8
|
-
# cycles that write, so Computer#cycle! asks before each cycle whether
|
|
9
|
-
# the next step is one of these.
|
|
10
|
-
WRITE_STEPS = %i[
|
|
11
|
-
op_mem_write op_rmw_write_original op_rmw_write_result op_push_exec op_jsr_push_high op_jsr_push_low
|
|
12
|
-
op_int_push_pch op_int_push_pcl op_int_push_status
|
|
13
|
-
].freeze
|
|
14
|
-
|
|
15
|
-
# The steps each addressing mode takes to work out the address an
|
|
16
|
-
# instruction operates on. They run after the opcode fetch.
|
|
17
|
-
ADDRESSING_STEPS = {
|
|
18
|
-
zeropage: %i[op_zp],
|
|
19
|
-
zeropage_x: %i[op_zp op_zp_x],
|
|
20
|
-
zeropage_y: %i[op_zp op_zp_y],
|
|
21
|
-
absolute: %i[op_abs_low op_abs_high],
|
|
22
|
-
absolute_x: %i[op_abs_low op_abs_high_x op_idx_dummy],
|
|
23
|
-
absolute_y: %i[op_abs_low op_abs_high_y op_idx_dummy],
|
|
24
|
-
indirect_x: %i[op_zp_pointer op_pointer_x op_pointer_low op_pointer_high],
|
|
25
|
-
indirect_y: %i[op_zp_pointer op_pointer_low op_pointer_high_y op_idx_dummy]
|
|
26
|
-
}.freeze
|
|
27
|
-
|
|
28
|
-
# The steps that read or write that address, once it is known.
|
|
29
|
-
OPERATION_STEPS = {
|
|
30
|
-
read: %i[op_mem_read],
|
|
31
|
-
write: %i[op_mem_write],
|
|
32
|
-
rmw: %i[op_rmw_read op_rmw_write_original op_rmw_write_result]
|
|
33
|
-
}.freeze
|
|
34
|
-
|
|
35
|
-
STORES = %i[sta stx sty sax sha shx shy tas].freeze
|
|
36
|
-
READ_MODIFY_WRITES = %i[asl lsr rol ror inc dec slo sre rla rra isc dcp].freeze
|
|
37
|
-
BRANCHES = %i[bcc bcs beq bmi bne bpl bvc bvs].freeze
|
|
38
|
-
|
|
39
|
-
# The addresses a 6502 reads after a JAM opcode, before it settles into
|
|
40
|
-
# JAMMED_PLAN.
|
|
41
|
-
JAM_ADDRESSES = [0xffff, 0xfffe, 0xfffe].freeze
|
|
42
|
-
|
|
43
|
-
# The plan between instructions: the next cycle fetches an opcode.
|
|
44
|
-
FETCH_PLAN = %i[op_fetch].freeze
|
|
45
|
-
|
|
46
|
-
IMPLIED_PLAN = %i[op_fetch op_implied_exec].freeze
|
|
47
|
-
ACCUMULATOR_PLAN = %i[op_fetch op_accumulator_exec].freeze
|
|
48
|
-
IMMEDIATE_PLAN = %i[op_fetch op_immediate_read].freeze
|
|
49
|
-
|
|
50
|
-
# $10, $30, $50, $70, $90, $B0, $D0, $F0 - relative - 2+ cycles.
|
|
51
|
-
# A branch that is not taken takes 2 cycles. A taken branch takes 3,
|
|
52
|
-
# or 4 when the target is on another page.
|
|
53
|
-
BRANCH_PLAN = %i[op_fetch op_relative op_branch op_branch_fixup].freeze
|
|
54
|
-
|
|
55
|
-
# $4C - absolute - 3 cycles
|
|
56
|
-
JMP_ABSOLUTE_PLAN = %i[op_fetch op_abs_low op_jmp_high].freeze
|
|
57
|
-
|
|
58
|
-
# $6C - indirect - 5 cycles
|
|
59
|
-
JMP_INDIRECT_PLAN = %i[op_fetch op_abs_low op_abs_high op_indirect_low op_indirect_high].freeze
|
|
60
|
-
|
|
61
|
-
# $20 - absolute - 6 cycles
|
|
62
|
-
JSR_PLAN = %i[op_fetch op_jsr_low op_jsr_dummy op_jsr_push_high op_jsr_push_low op_jsr_high].freeze
|
|
63
|
-
|
|
64
|
-
# $60 - implied - 6 cycles
|
|
65
|
-
RTS_PLAN = %i[op_fetch op_implied_dummy op_pull_dummy op_pull_low op_pull_high op_rts_fixup].freeze
|
|
66
|
-
|
|
67
|
-
# $40 - implied - 6 cycles
|
|
68
|
-
RTI_PLAN = %i[op_fetch op_implied_dummy op_pull_dummy op_rti_pull_status op_pull_low op_rti_pull_high].freeze
|
|
69
|
-
|
|
70
|
-
# $08, $48 - implied - 3 cycles
|
|
71
|
-
PUSH_PLAN = %i[op_fetch op_implied_dummy op_push_exec].freeze
|
|
72
|
-
|
|
73
|
-
# $28, $68 - implied - 4 cycles
|
|
74
|
-
PULL_PLAN = %i[op_fetch op_implied_dummy op_pull_dummy op_pull_exec].freeze
|
|
75
|
-
|
|
76
|
-
# $02, $12, $22, $32, $42, $52, $62, $72, $92, $B2, $D2, $F2 - illegal
|
|
77
|
-
JAM_PLAN = [:op_fetch, :op_implied_dummy, *Array.new(JAM_ADDRESSES.length, :op_jam)].freeze
|
|
78
|
-
|
|
79
|
-
# A jammed CPU reads $FFFF on every cycle until reset. It never reaches
|
|
80
|
-
# an instruction boundary, so a pending IRQ or NMI never starts.
|
|
81
|
-
JAMMED_PLAN = %i[op_jammed].freeze
|
|
82
|
-
|
|
83
|
-
# BRK and hardware interrupts push the return address and status, then
|
|
84
|
-
# read the new PC from a vector. Only the second step differs: BRK's
|
|
85
|
-
# selects the IRQ vector and sets the break flag it pushes.
|
|
86
|
-
#
|
|
87
|
-
# $00 - implied - 7 cycles (BRK)
|
|
88
|
-
INTERRUPT_PLAN = %i[
|
|
89
|
-
op_fetch op_implied_dummy op_int_push_pch op_int_push_pcl op_int_push_status
|
|
90
|
-
op_int_vector_low op_int_vector_high
|
|
91
|
-
].freeze
|
|
92
|
-
BRK_PLAN = %i[
|
|
93
|
-
op_fetch op_brk_dummy op_int_push_pch op_int_push_pcl op_int_push_status
|
|
94
|
-
op_int_vector_low op_int_vector_high
|
|
95
|
-
].freeze
|
|
96
|
-
|
|
97
|
-
SPECIAL_PLANS = {
|
|
98
|
-
brk: BRK_PLAN, jam: JAM_PLAN, jsr: JSR_PLAN, rts: RTS_PLAN,
|
|
99
|
-
rti: RTI_PLAN, pha: PUSH_PLAN, php: PUSH_PLAN,
|
|
100
|
-
pla: PULL_PLAN, plp: PULL_PLAN
|
|
101
|
-
}.freeze
|
|
102
|
-
|
|
103
|
-
# Everything the CPU needs to run one opcode:
|
|
104
|
-
# - +operation+: the instruction method to call, such as :lda
|
|
105
|
-
# - +plan+: the step to run on each cycle
|
|
106
|
-
# - +writes+: which of those steps write to memory
|
|
107
|
-
# - +optional_dummy+: true for indexed reads, which skip the extra
|
|
108
|
-
# cycle unless indexing crosses a page
|
|
109
|
-
Microcode = Struct.new(:operation, :plan, :writes, :optional_dummy) do
|
|
110
|
-
def self.table
|
|
111
|
-
Array.new(256) do |opcode|
|
|
112
|
-
instruction = Instruction.find(opcode)
|
|
113
|
-
raise InvalidOpcodeError, format("$%02x", opcode) unless instruction
|
|
114
|
-
|
|
115
|
-
build(instruction)
|
|
116
|
-
end.freeze
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
def self.write_mask(plan)
|
|
120
|
-
plan.map { |step| WRITE_STEPS.include?(step) }.freeze
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def self.build(instruction)
|
|
124
|
-
plan = plan_for(instruction)
|
|
125
|
-
new(instruction.name, plan, write_mask(plan),
|
|
126
|
-
instruction.boundary_cycle?)
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def self.plan_for(instruction)
|
|
130
|
-
case instruction.name
|
|
131
|
-
when :jmp
|
|
132
|
-
if instruction.addressing_mode == :indirect
|
|
133
|
-
JMP_INDIRECT_PLAN
|
|
134
|
-
else
|
|
135
|
-
JMP_ABSOLUTE_PLAN
|
|
136
|
-
end
|
|
137
|
-
when *BRANCHES then BRANCH_PLAN
|
|
138
|
-
else SPECIAL_PLANS[instruction.name] || addressed_plan(instruction)
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def self.addressed_plan(instruction)
|
|
143
|
-
mode = instruction.addressing_mode
|
|
144
|
-
case mode
|
|
145
|
-
when :implied then IMPLIED_PLAN
|
|
146
|
-
when :accumulator then ACCUMULATOR_PLAN
|
|
147
|
-
when :immediate then IMMEDIATE_PLAN
|
|
148
|
-
else
|
|
149
|
-
[:op_fetch, *ADDRESSING_STEPS.fetch(mode),
|
|
150
|
-
*OPERATION_STEPS.fetch(operation_kind(instruction.name))].freeze
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
def self.operation_kind(name)
|
|
155
|
-
return :write if STORES.include?(name)
|
|
156
|
-
return :rmw if READ_MODIFY_WRITES.include?(name)
|
|
157
|
-
|
|
158
|
-
:read
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
private_class_method :build, :plan_for, :addressed_plan, :operation_kind
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
FETCH_WRITES = Microcode.write_mask(FETCH_PLAN)
|
|
165
|
-
INTERRUPT_WRITES = Microcode.write_mask(INTERRUPT_PLAN)
|
|
166
|
-
JAMMED_WRITES = Microcode.write_mask(JAMMED_PLAN)
|
|
167
|
-
MICROCODE = Microcode.table
|
|
168
|
-
|
|
169
|
-
# The instruction methods, in a fixed order a snapshot names them by.
|
|
170
|
-
OPERATIONS = MICROCODE.map(&:operation).uniq.freeze
|
|
171
|
-
|
|
172
|
-
# The plans a snapshot names that aren't an opcode's.
|
|
173
|
-
FETCH = -1
|
|
174
|
-
INTERRUPT = -2
|
|
175
|
-
JAMMED = -3
|
|
176
|
-
end
|
|
177
|
-
end
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Badline
|
|
4
|
-
class CPU
|
|
5
|
-
# Steps that read or write an instruction's operand once its address is
|
|
6
|
-
# known, plus the branch and JAM steps.
|
|
7
|
-
module Operations
|
|
8
|
-
private
|
|
9
|
-
|
|
10
|
-
def op_mem_read
|
|
11
|
-
send(@operation, @address, @memory.peek(@address))
|
|
12
|
-
end_instruction
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def op_mem_write
|
|
16
|
-
send(@operation, @address, nil)
|
|
17
|
-
end_instruction
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# Read-modify-write instructions (ASL, INC and the like) take three
|
|
21
|
-
# cycles here: read the value and compute the result, write the
|
|
22
|
-
# original value back, then write the result. The instruction method
|
|
23
|
-
# hands the result over through #write_modified.
|
|
24
|
-
def op_rmw_read
|
|
25
|
-
@value = @memory.peek(@address)
|
|
26
|
-
send(@operation, @address, @value)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def op_rmw_write_original
|
|
30
|
-
@memory.poke(@address, @value)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def op_rmw_write_result
|
|
34
|
-
@memory.poke(@address, @rmw_result)
|
|
35
|
-
end_instruction
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def op_relative
|
|
39
|
-
offset = @memory.peek(@program_counter)
|
|
40
|
-
@program_counter = (@program_counter + 1) & 0xffff
|
|
41
|
-
@address = (@program_counter + signed_int8(offset)) & 0xffff
|
|
42
|
-
@branch_taken = false
|
|
43
|
-
send(@operation, @address, nil)
|
|
44
|
-
if @branch_taken
|
|
45
|
-
# A taken branch within the same page doesn't poll on its last cycle.
|
|
46
|
-
@skip_poll = true if same_page?
|
|
47
|
-
else
|
|
48
|
-
end_instruction
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def op_branch
|
|
53
|
-
@memory.peek(@program_counter)
|
|
54
|
-
return unless same_page?
|
|
55
|
-
|
|
56
|
-
@program_counter = @address
|
|
57
|
-
end_instruction
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
# A branch to another page spends an extra cycle reading from the target's low byte on the old page.
|
|
61
|
-
def op_branch_fixup
|
|
62
|
-
@memory.peek((@program_counter & 0xff00) | (@address & 0xff))
|
|
63
|
-
@program_counter = @address
|
|
64
|
-
end_instruction
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def same_page?
|
|
68
|
-
@address >> 8 == @program_counter >> 8
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# Runs once for each address in JAM_ADDRESSES. By the time a step runs, @index already points at the next one.
|
|
72
|
-
def op_jam
|
|
73
|
-
position = @index - 2
|
|
74
|
-
@memory.peek(JAM_ADDRESSES[position - 1])
|
|
75
|
-
return unless position == JAM_ADDRESSES.length
|
|
76
|
-
|
|
77
|
-
@plan = JAMMED_PLAN
|
|
78
|
-
@writes = JAMMED_WRITES
|
|
79
|
-
@index = 0
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def op_jammed
|
|
83
|
-
@index = 0
|
|
84
|
-
@memory.peek(0xffff)
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
end
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Badline
|
|
4
|
-
class CPU
|
|
5
|
-
# The CPU's state for a snapshot: the registers, the interrupt lines and
|
|
6
|
-
# their pipeline, and the step of the instruction in flight, named by
|
|
7
|
-
# where its plan comes from.
|
|
8
|
-
module SavedState
|
|
9
|
-
# Writes everything the CPU holds, down to the step of the instruction
|
|
10
|
-
# it is in, for load_state to put back. The interrupt lines, BA stalls
|
|
11
|
-
# and SO are state too; the traps and the debug flag belong to the host.
|
|
12
|
-
def save_state(out)
|
|
13
|
-
out.marker("CPU")
|
|
14
|
-
out.int(@program_counter).int(@stack_pointer).int(@a).int(@x).int(@y).int(@status.value)
|
|
15
|
-
[@irq, @nmi, @irq_sample, @irq_pending, @nmi_sample, @nmi_pending, @skip_poll, @boundary_irq,
|
|
16
|
-
@boundary_nmi, @boundary_crossed, @brk, @pending_write, @so_high, @optional_dummy,
|
|
17
|
-
@branch_taken].each { |flag| out.boolean(flag) }
|
|
18
|
-
out.optional_int(@interrupt).optional_int(@stalled_at).int(@cycles).int(@instructions)
|
|
19
|
-
out.int(plan_source).int(@index).int(OPERATIONS.index(@operation) || -1)
|
|
20
|
-
[@address, @dummy_address, @value, @rmw_result, @pointer].each { |register| out.optional_int(register) }
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def load_state(input)
|
|
24
|
-
input.marker("CPU")
|
|
25
|
-
@program_counter = input.int
|
|
26
|
-
@stack_pointer = input.int
|
|
27
|
-
@a = input.int
|
|
28
|
-
@x = input.int
|
|
29
|
-
@y = input.int
|
|
30
|
-
@status.value = input.int
|
|
31
|
-
load_flags(input)
|
|
32
|
-
@interrupt = input.optional_int
|
|
33
|
-
@stalled_at = input.optional_int
|
|
34
|
-
@cycles = input.int
|
|
35
|
-
@instructions = input.int
|
|
36
|
-
load_plan(input.int)
|
|
37
|
-
@index = input.int
|
|
38
|
-
operation = input.int
|
|
39
|
-
@operation = operation.negative? ? nil : OPERATIONS.fetch(operation)
|
|
40
|
-
load_working_registers(input)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# Drops the instruction or interrupt sequence in flight and the
|
|
44
|
-
# interrupt lines' pipeline, so the next cycle fetches an opcode at the
|
|
45
|
-
# program counter, and sets the cycle count. A snapshot taken between
|
|
46
|
-
# instructions, as VICE's are, restores through here.
|
|
47
|
-
def resume(cycles)
|
|
48
|
-
@irq_sample = @irq_pending = false
|
|
49
|
-
@nmi_sample = @nmi_pending = false
|
|
50
|
-
@skip_poll = false
|
|
51
|
-
@interrupt = nil
|
|
52
|
-
@brk = false
|
|
53
|
-
@stalled_at = nil
|
|
54
|
-
@cycles = cycles
|
|
55
|
-
end_sequence
|
|
56
|
-
@pending_write = false
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
private
|
|
60
|
-
|
|
61
|
-
# Where the plan running comes from: an opcode's microcode, or FETCH,
|
|
62
|
-
# INTERRUPT or JAMMED below it.
|
|
63
|
-
def plan_source
|
|
64
|
-
return FETCH if @plan.equal?(FETCH_PLAN)
|
|
65
|
-
return INTERRUPT if @plan.equal?(INTERRUPT_PLAN)
|
|
66
|
-
return JAMMED if @plan.equal?(JAMMED_PLAN)
|
|
67
|
-
|
|
68
|
-
MICROCODE.index { |micro| micro.plan.equal?(@plan) && micro.operation == @operation } ||
|
|
69
|
-
MICROCODE.index { |micro| micro.plan.equal?(@plan) }
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def load_plan(source)
|
|
73
|
-
case source
|
|
74
|
-
when FETCH then use_plan(FETCH_PLAN, FETCH_WRITES)
|
|
75
|
-
when INTERRUPT then use_plan(INTERRUPT_PLAN, INTERRUPT_WRITES)
|
|
76
|
-
when JAMMED then use_plan(JAMMED_PLAN, JAMMED_WRITES)
|
|
77
|
-
else
|
|
78
|
-
micro = MICROCODE.fetch(source)
|
|
79
|
-
use_plan(micro.plan, micro.writes)
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def use_plan(plan, writes)
|
|
84
|
-
@plan = plan
|
|
85
|
-
@writes = writes
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def load_flags(input)
|
|
89
|
-
@irq = input.boolean?
|
|
90
|
-
@nmi = input.boolean?
|
|
91
|
-
@irq_sample = input.boolean?
|
|
92
|
-
@irq_pending = input.boolean?
|
|
93
|
-
@nmi_sample = input.boolean?
|
|
94
|
-
@nmi_pending = input.boolean?
|
|
95
|
-
@skip_poll = input.boolean?
|
|
96
|
-
@boundary_irq = input.boolean?
|
|
97
|
-
@boundary_nmi = input.boolean?
|
|
98
|
-
@boundary_crossed = input.boolean?
|
|
99
|
-
@brk = input.boolean?
|
|
100
|
-
@pending_write = input.boolean?
|
|
101
|
-
@so_high = input.boolean?
|
|
102
|
-
@optional_dummy = input.boolean?
|
|
103
|
-
@branch_taken = input.boolean?
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def load_working_registers(input)
|
|
107
|
-
@address = input.optional_int
|
|
108
|
-
@dummy_address = input.optional_int
|
|
109
|
-
@value = input.optional_int
|
|
110
|
-
@rmw_result = input.optional_int
|
|
111
|
-
@pointer = input.optional_int
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
end
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Badline
|
|
4
|
-
class CPU
|
|
5
|
-
# Steps that use the stack: PHA, PHP, PLA, PLP, JSR, RTS and RTI.
|
|
6
|
-
module StackOperations
|
|
7
|
-
private
|
|
8
|
-
|
|
9
|
-
def op_push_exec
|
|
10
|
-
send(@operation, nil, nil)
|
|
11
|
-
end_instruction
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def op_pull_dummy
|
|
15
|
-
@memory.peek(stack_address)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def op_pull_exec
|
|
19
|
-
send(@operation, nil, nil)
|
|
20
|
-
end_instruction
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def op_pull_low
|
|
24
|
-
@stack_pointer = (@stack_pointer + 1) & 0xff
|
|
25
|
-
@address = @memory.peek(stack_address)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def op_pull_high
|
|
29
|
-
@stack_pointer = (@stack_pointer + 1) & 0xff
|
|
30
|
-
@address |= @memory.peek(stack_address) << 8
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def op_rts_fixup
|
|
34
|
-
@memory.peek(@address)
|
|
35
|
-
@program_counter = (@address + 1) & 0xffff
|
|
36
|
-
end_instruction
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def op_rti_pull_status
|
|
40
|
-
@stack_pointer = (@stack_pointer + 1) & 0xff
|
|
41
|
-
@status.value = @memory.peek(stack_address)
|
|
42
|
-
@status.break = false
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def op_rti_pull_high
|
|
46
|
-
@stack_pointer = (@stack_pointer + 1) & 0xff
|
|
47
|
-
@program_counter = @address | (@memory.peek(stack_address) << 8)
|
|
48
|
-
end_instruction
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def op_jsr_low
|
|
52
|
-
@address = @memory.peek(@program_counter)
|
|
53
|
-
@program_counter = (@program_counter + 2) & 0xffff
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def op_jsr_dummy
|
|
57
|
-
@memory.peek(stack_address)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def op_jsr_push_high
|
|
61
|
-
@memory.poke(stack_address, high_byte(return_address))
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def op_jsr_push_low
|
|
65
|
-
@memory.poke(stack_address(-1), low_byte(return_address))
|
|
66
|
-
@stack_pointer = (@stack_pointer - 2) & 0xff
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
# JSR reads its target's high byte after pushing the return address.
|
|
70
|
-
# A JSR running from the stack page can overwrite its own operand
|
|
71
|
-
# with that push, and then jumps to the overwritten address.
|
|
72
|
-
def op_jsr_high
|
|
73
|
-
@program_counter = @address | (@memory.peek(return_address) << 8)
|
|
74
|
-
end_instruction
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def return_address
|
|
78
|
-
(@program_counter - 1) & 0xffff
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
end
|
data/lib/badline/cpu.rb
DELETED
data/lib/badline/cycleable.rb
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Badline
|
|
4
|
-
class Cycleable
|
|
5
|
-
attr_reader :cycles
|
|
6
|
-
|
|
7
|
-
def initialize
|
|
8
|
-
@loop = Fiber.new { loop { main_loop } }
|
|
9
|
-
@cycles = 0
|
|
10
|
-
@pending_write = false
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def cycle!
|
|
14
|
-
@loop.resume
|
|
15
|
-
nil
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def pending_write? = @pending_write
|
|
19
|
-
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
def cycle(write: false)
|
|
23
|
-
@pending_write = write
|
|
24
|
-
Fiber.yield
|
|
25
|
-
poll
|
|
26
|
-
result = yield if block_given?
|
|
27
|
-
@cycles += 1
|
|
28
|
-
@pending_write = false
|
|
29
|
-
result
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def poll; end
|
|
33
|
-
|
|
34
|
-
def main_loop
|
|
35
|
-
Fiber.yield
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|