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
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "badline/chips/via/control_lines"
|
|
4
|
+
require "badline/chips/via/fast_forward"
|
|
5
|
+
require "badline/chips/via/interrupt_register"
|
|
6
|
+
require "badline/chips/via/shift_register"
|
|
7
|
+
require "badline/chips/via/saved_state"
|
|
8
|
+
require "badline/chips/via/timer1"
|
|
9
|
+
require "badline/chips/via/timer2"
|
|
10
|
+
|
|
11
|
+
module Badline
|
|
12
|
+
module Chips
|
|
13
|
+
# VIA (Versatile Interface Adapter): the MOS 6522, two ports with
|
|
14
|
+
# handshake lines, two timers and a shift register. The 1541 has two.
|
|
15
|
+
#
|
|
16
|
+
# Sixteen registers repeat across a 1 KB window. The control pins take
|
|
17
|
+
# levels from outside through ca1= and friends, and PB6 takes its pulses
|
|
18
|
+
# for timer 2 through pb6= alone: the peripheral's port B input doesn't
|
|
19
|
+
# feed the counter.
|
|
20
|
+
class VIA
|
|
21
|
+
include Addressable
|
|
22
|
+
include FastForward
|
|
23
|
+
include SavedState
|
|
24
|
+
|
|
25
|
+
attr_reader :start, :peripheral, :shift_register, :acr, :pcr
|
|
26
|
+
|
|
27
|
+
def timer1 = @t1.counter
|
|
28
|
+
|
|
29
|
+
def timer1_latch = @t1.latch
|
|
30
|
+
|
|
31
|
+
def timer2 = @t2.counter
|
|
32
|
+
|
|
33
|
+
def interrupt_flags = @ifr.read
|
|
34
|
+
|
|
35
|
+
def interrupt_enable = @ifr.read_enable
|
|
36
|
+
|
|
37
|
+
def initialize(start: 0, peripheral: nil)
|
|
38
|
+
addressable_at(start, length: 2**10)
|
|
39
|
+
|
|
40
|
+
@peripheral = peripheral
|
|
41
|
+
@t1 = Timer1.new
|
|
42
|
+
@t2 = Timer2.new
|
|
43
|
+
@shift_register = ShiftRegister.new
|
|
44
|
+
@ifr = InterruptRegister.new
|
|
45
|
+
@ca = ControlLines.new(@ifr, c1_flag: InterruptRegister::CA1, c2_flag: InterruptRegister::CA2,
|
|
46
|
+
handshake_on_read: true)
|
|
47
|
+
@cb = ControlLines.new(@ifr, c1_flag: InterruptRegister::CB1, c2_flag: InterruptRegister::CB2,
|
|
48
|
+
handshake_on_read: false)
|
|
49
|
+
@pb6_high = true
|
|
50
|
+
@acr = 0x00
|
|
51
|
+
reset!
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# The RES line clears every register but the timers and the shift
|
|
55
|
+
# register, which carry on counting, and so releases IRQ.
|
|
56
|
+
def reset!
|
|
57
|
+
@ora = @orb = @ddra = @ddrb = 0x00
|
|
58
|
+
@latch_a = @latch_b = 0xff
|
|
59
|
+
@ifr.reset!
|
|
60
|
+
@ca.reset!
|
|
61
|
+
@cb.reset!
|
|
62
|
+
write_acr(0x00)
|
|
63
|
+
@pcr = 0x00
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def irq? = @ifr.irq?
|
|
67
|
+
|
|
68
|
+
def cycle!
|
|
69
|
+
@ca.cycle! if @ca.pulsing?
|
|
70
|
+
@cb.cycle! if @cb.pulsing?
|
|
71
|
+
@ifr.set(InterruptRegister::TIMER1) if @t1.cycle!(@acr.anybits?(0x40))
|
|
72
|
+
@ifr.set(InterruptRegister::TIMER2) if @t2.cycle!(@sr_uses_t2)
|
|
73
|
+
@ifr.set(InterruptRegister::SR) if @shift_register.cycle!(@t2.low_underflowed)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Port A as driven by ORA and DDRA, input lines floating high.
|
|
77
|
+
def port_a_output = driven_lines(@ora, @ddra)
|
|
78
|
+
|
|
79
|
+
# Port B as driven by ORB and DDRB, with PB7 handed to timer 1 by ACR
|
|
80
|
+
# bit 7.
|
|
81
|
+
def port_b_output
|
|
82
|
+
lines = driven_lines(@orb, @ddrb)
|
|
83
|
+
return lines unless @acr.anybits?(0x80)
|
|
84
|
+
|
|
85
|
+
@t1.pb7 ? lines | 0x80 : lines & 0x7f
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# An active CA1 edge latches port A while ACR bit 0 is set.
|
|
89
|
+
def ca1=(high)
|
|
90
|
+
return if high == @ca.c1_high
|
|
91
|
+
|
|
92
|
+
@latch_a = pins_a if @acr.anybits?(0x01) && @ca.active_c1_edge?(high)
|
|
93
|
+
@ca.c1 = high
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def ca2=(high)
|
|
97
|
+
@ca.c2 = high
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# An active CB1 edge latches port B while ACR bit 1 is set. CB1 also
|
|
101
|
+
# clocks the shift register in its external clock modes.
|
|
102
|
+
def cb1=(high)
|
|
103
|
+
return if high == @cb.c1_high
|
|
104
|
+
|
|
105
|
+
@ifr.set(InterruptRegister::SR) if @shift_register.cb1_edge!(high)
|
|
106
|
+
@latch_b = pins_b if @acr.anybits?(0x02) && @cb.active_c1_edge?(high)
|
|
107
|
+
@cb.c1 = high
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def cb2=(high)
|
|
111
|
+
@shift_register.cb2_input = high
|
|
112
|
+
@cb.c2 = high
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# A falling edge counts a pulse while timer 2 counts them.
|
|
116
|
+
def pb6=(high)
|
|
117
|
+
fell = @pb6_high && !high
|
|
118
|
+
@pb6_high = high
|
|
119
|
+
@ifr.set(InterruptRegister::TIMER2) if fell && @t2.pulse!
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def ca2_output = @ca.c2_output
|
|
123
|
+
|
|
124
|
+
# The shift register's clock on CB1, or nil when CB1 is an input.
|
|
125
|
+
def cb1_output = @shift_register.cb1_output
|
|
126
|
+
|
|
127
|
+
# The shift register takes CB2 over in its shift-out modes.
|
|
128
|
+
def cb2_output
|
|
129
|
+
level = @shift_register.cb2_output
|
|
130
|
+
level.nil? ? @cb.c2_output : level
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def peek(addr)
|
|
134
|
+
case offset_of(addr) & 0x0f
|
|
135
|
+
when 0x00 then read_port_b
|
|
136
|
+
when 0x01 then read_port_a(handshake: true)
|
|
137
|
+
when 0x02 then @ddrb
|
|
138
|
+
when 0x03 then @ddra
|
|
139
|
+
when 0x04 then read_timer_low(@t1.counter, InterruptRegister::TIMER1)
|
|
140
|
+
when 0x05 then high_byte(@t1.counter)
|
|
141
|
+
when 0x06 then low_byte(@t1.latch)
|
|
142
|
+
when 0x07 then high_byte(@t1.latch)
|
|
143
|
+
when 0x08 then read_timer_low(@t2.counter, InterruptRegister::TIMER2)
|
|
144
|
+
when 0x09 then high_byte(@t2.counter)
|
|
145
|
+
when 0x0a then read_shift_register
|
|
146
|
+
when 0x0b then @acr
|
|
147
|
+
when 0x0c then @pcr
|
|
148
|
+
when 0x0d then @ifr.read
|
|
149
|
+
when 0x0e then @ifr.read_enable
|
|
150
|
+
else read_port_a(handshake: false)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def poke(addr, value)
|
|
155
|
+
case offset_of(addr) & 0x0f
|
|
156
|
+
when 0x00 then write_port_b(value)
|
|
157
|
+
when 0x01 then write_port_a(value, handshake: true)
|
|
158
|
+
when 0x02 then @ddrb = value
|
|
159
|
+
when 0x03 then @ddra = value
|
|
160
|
+
when 0x04, 0x06 then @t1.write_latch_low(value)
|
|
161
|
+
when 0x05 then write_timer1_high(value, start: true)
|
|
162
|
+
when 0x07 then write_timer1_high(value, start: false)
|
|
163
|
+
when 0x08 then @t2.latch_low = value
|
|
164
|
+
when 0x09 then write_timer2_high(value)
|
|
165
|
+
when 0x0a then write_shift_register(value)
|
|
166
|
+
when 0x0b then write_acr(value)
|
|
167
|
+
when 0x0c then write_pcr(value)
|
|
168
|
+
when 0x0d then @ifr.write(value)
|
|
169
|
+
when 0x0e then @ifr.write_enable(value)
|
|
170
|
+
else write_port_a(value, handshake: false)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
private
|
|
175
|
+
|
|
176
|
+
# Output bits are driven from the data register; input bits float high.
|
|
177
|
+
# External peripherals can still pull any line low (wired-AND).
|
|
178
|
+
def driven_lines(register, direction)
|
|
179
|
+
(register & direction) | (~direction & 0xff)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def pins_a
|
|
183
|
+
lines = port_a_output
|
|
184
|
+
peripheral ? lines & peripheral.read_a(lines) : lines
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def pins_b
|
|
188
|
+
lines = port_b_output
|
|
189
|
+
peripheral ? lines & peripheral.read_b(lines) : lines
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Port A reads the pins, or what CA1 latched off them.
|
|
193
|
+
def read_port_a(handshake:)
|
|
194
|
+
value = @acr.anybits?(0x01) ? @latch_a : pins_a
|
|
195
|
+
@ca.access!(false) if handshake
|
|
196
|
+
value
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def write_port_a(value, handshake:)
|
|
200
|
+
@ora = value
|
|
201
|
+
@ca.access!(true) if handshake
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Port B reads its output bits from ORB, or from timer 1 for PB7, and
|
|
205
|
+
# its input bits from the pins, or from what CB1 latched off them.
|
|
206
|
+
def read_port_b
|
|
207
|
+
outputs = @acr.anybits?(0x80) ? @ddrb | 0x80 : @ddrb
|
|
208
|
+
inputs = @acr.anybits?(0x02) ? @latch_b : pins_b
|
|
209
|
+
@cb.access!(false)
|
|
210
|
+
(port_b_output & outputs) | (inputs & ~outputs & 0xff)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def write_port_b(value)
|
|
214
|
+
@orb = value
|
|
215
|
+
@cb.access!(true)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# A read of either timer's low counter byte acknowledges its interrupt.
|
|
219
|
+
def read_timer_low(counter, flag)
|
|
220
|
+
@ifr.clear(flag)
|
|
221
|
+
low_byte(counter)
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# $5 loads and starts the counter; $7 only writes the latch. Both
|
|
225
|
+
# acknowledge the interrupt.
|
|
226
|
+
def write_timer1_high(value, start:)
|
|
227
|
+
@t1.write_latch_high(value)
|
|
228
|
+
@t1.start! if start
|
|
229
|
+
@ifr.clear(InterruptRegister::TIMER1)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def write_timer2_high(value)
|
|
233
|
+
@t2.load(value)
|
|
234
|
+
@ifr.clear(InterruptRegister::TIMER2)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def read_shift_register
|
|
238
|
+
value = @shift_register.data
|
|
239
|
+
@shift_register.access!
|
|
240
|
+
@ifr.clear(InterruptRegister::SR)
|
|
241
|
+
value
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def write_shift_register(value)
|
|
245
|
+
@shift_register.data = value
|
|
246
|
+
@shift_register.access!
|
|
247
|
+
@ifr.clear(InterruptRegister::SR)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Bits 4-2 pick the shift register's mode. Modes 1, 4 and 5 clock off
|
|
251
|
+
# timer 2's low byte. Bit 7 turning on hands PB7 to timer 1 high.
|
|
252
|
+
def write_acr(value)
|
|
253
|
+
@t1.pb7_enabled! if value.anybits?(0x80) && @acr.nobits?(0x80)
|
|
254
|
+
@acr = value
|
|
255
|
+
@t2.count_pulses = value.anybits?(0x20)
|
|
256
|
+
mode = (value >> 2) & 0x07
|
|
257
|
+
@shift_register.mode = mode
|
|
258
|
+
@sr_uses_t2 = [1, 4, 5].include?(mode)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def write_pcr(value)
|
|
262
|
+
@pcr = value
|
|
263
|
+
@ca.control = value & 0x0f
|
|
264
|
+
@cb.control = value >> 4
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class VIC
|
|
6
|
+
# The 16K window the VIC sees into RAM, selected by CIA2 $DD00, in the
|
|
7
|
+
# bank a +256K picks for it. Character
|
|
8
|
+
# ROM shadows $1000-$1FFF in banks 0 and 2.
|
|
9
|
+
#
|
|
10
|
+
# The machine's bus pushes in what the VIC sees through #connect,
|
|
11
|
+
# #map_character_rom and #map whenever it changes. Until then the bank
|
|
12
|
+
# has a CIA 2, RAM, colour RAM and character ROM of its own.
|
|
13
|
+
class Bank
|
|
14
|
+
include Addressable
|
|
15
|
+
|
|
16
|
+
# The CIA2 port A bank bits are inverted: %11 selects bank 0.
|
|
17
|
+
BANK_STARTS = [0xc000, 0x8000, 0x4000, 0x0000].freeze
|
|
18
|
+
|
|
19
|
+
attr_reader :ram, :color_ram
|
|
20
|
+
|
|
21
|
+
# The bank lines as #sample_lines last saw them.
|
|
22
|
+
attr_accessor :lines
|
|
23
|
+
|
|
24
|
+
def initialize(vic)
|
|
25
|
+
addressable_at(0x0000, length: 2**14)
|
|
26
|
+
connect(cia2: CIA.new(start: 0xdd00), color_ram: C64::ColorMemory.new(vic))
|
|
27
|
+
map_character_rom(ROM.load("character.rom", 0xd000))
|
|
28
|
+
@base = 0
|
|
29
|
+
@starts = BANK_STARTS
|
|
30
|
+
map(Memory.new([], length: 2**16, start: 0))
|
|
31
|
+
@lines = 0b11
|
|
32
|
+
@swapped = false
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# CIA 2, whose port A picks the bank, and the colour RAM, read from
|
|
36
|
+
# the address +color_base+ gives offset 0.
|
|
37
|
+
def connect(cia2:, color_ram:, color_base: 0xd800)
|
|
38
|
+
@cia2 = cia2
|
|
39
|
+
@color_ram = color_ram
|
|
40
|
+
@color_base = color_base
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# The character ROM, read from the address +base+ gives offset 0. It
|
|
44
|
+
# shows in the banks whose low line is high, unless +shadow+ is false.
|
|
45
|
+
def map_character_rom(rom, base: 0xc000, shadow: true)
|
|
46
|
+
@character_rom = rom
|
|
47
|
+
@character_base = base
|
|
48
|
+
@shadow_mask = shadow ? 0b01 : 0b00
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# The RAM the VIC's 64K starts at +base+ in, and the cartridge's
|
|
52
|
+
# Ultimax lines in each half of the cycle with the ROMH bank they
|
|
53
|
+
# show.
|
|
54
|
+
def map(ram, base: 0, phi1_ultimax: false, ultimax: false, romh: nil)
|
|
55
|
+
@ram = ram
|
|
56
|
+
unless base == @base
|
|
57
|
+
@base = base
|
|
58
|
+
@starts = BANK_STARTS.map { |start| base + start }.freeze
|
|
59
|
+
end
|
|
60
|
+
@phi1_ultimax = phi1_ultimax
|
|
61
|
+
@ultimax = ultimax
|
|
62
|
+
@romh = romh
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# On the 8565, a port A write that swaps the two bank lines, driving
|
|
66
|
+
# one high as the other goes low, shows the VIC both lines low for the
|
|
67
|
+
# cycle after it: every access in that cycle reads bank 3. A swap that
|
|
68
|
+
# the DDR makes, releasing a line to float high, shows nothing.
|
|
69
|
+
# Called once a cycle, ahead of the cycle's accesses.
|
|
70
|
+
def sample_lines
|
|
71
|
+
lines = @cia2.port_a_lines & 0b11
|
|
72
|
+
@swapped = swap?(@lines, lines) && @cia2.port_registers[2].allbits?(0b11)
|
|
73
|
+
@lines = lines
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def peek(offset)
|
|
77
|
+
return ultimax_peek(offset) if @phi1_ultimax
|
|
78
|
+
|
|
79
|
+
bits = bank_switch_register
|
|
80
|
+
if (bits & @shadow_mask) == 0b01 && (offset & 0xf000) == 0x1000
|
|
81
|
+
@character_rom.peek(@character_base + offset)
|
|
82
|
+
else
|
|
83
|
+
@ram.peek(@starts[bits] + offset)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# A fetch in the second half of the cycle, the c-access, sees the
|
|
88
|
+
# memory configuration the CPU does in that half. No cartridge drives
|
|
89
|
+
# Ultimax mode in the first half alone, so otherwise it reads as #peek.
|
|
90
|
+
def peek_phi2(offset)
|
|
91
|
+
@ultimax ? ultimax_peek(offset) : peek(offset)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def peek_color(offset)
|
|
95
|
+
@color_ram.nibble(@color_base + offset)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def poke(_addr, _value)
|
|
99
|
+
raise ReadOnlyMemoryError
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# True if the VIC reads the character ROM at this offset.
|
|
103
|
+
def character_rom?(offset)
|
|
104
|
+
!@phi1_ultimax && (bank_switch_register & @shadow_mask) == 0b01 && (offset & 0xf000) == 0x1000
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def start
|
|
108
|
+
BANK_STARTS[bank_switch_register]
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
|
|
113
|
+
# In Ultimax mode the cartridge ROMH replaces the character ROM
|
|
114
|
+
# shadow, visible at $3000-$3FFF of the window. The MAX is in
|
|
115
|
+
# Ultimax mode with no cartridge too.
|
|
116
|
+
def ultimax_peek(offset)
|
|
117
|
+
romh = @romh
|
|
118
|
+
if romh && offset.allbits?(0x3000)
|
|
119
|
+
romh.peek(0xe000 + (offset & 0x1fff))
|
|
120
|
+
else
|
|
121
|
+
@ram.peek(@starts[bank_switch_register] + offset)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def swap?(from, to) = (from ^ to) == 0b11 && from.anybits?(0b11) && to.anybits?(0b11)
|
|
126
|
+
|
|
127
|
+
def bank_switch_register
|
|
128
|
+
return 0 if @swapped
|
|
129
|
+
|
|
130
|
+
@cia2.port_a_lines & 0b11
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class VIC
|
|
6
|
+
# Border coverage per 8-pixel group, tracked as the sequencer outputs
|
|
7
|
+
# a line.
|
|
8
|
+
#
|
|
9
|
+
# The border is repainted over composited sprites from a snapshot of
|
|
10
|
+
# the finished line, which keeps mid-line border color splits intact.
|
|
11
|
+
class BorderMask
|
|
12
|
+
FULL = 0
|
|
13
|
+
NONE = 1
|
|
14
|
+
MIXED = 2
|
|
15
|
+
|
|
16
|
+
# The group table and per-pixel mask are exposed so the sequencer's
|
|
17
|
+
# pixel loops can write them without a method call per column.
|
|
18
|
+
attr_reader :groups, :mask
|
|
19
|
+
|
|
20
|
+
def initialize(width)
|
|
21
|
+
@width = width
|
|
22
|
+
@groups = Array.new(width / 8, FULL)
|
|
23
|
+
@mask = Array.new(width, true)
|
|
24
|
+
@snapshot = Array.new(width, 0)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def reset
|
|
28
|
+
@groups.fill(FULL)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def save_state(out)
|
|
32
|
+
out.ints(@groups).booleans(@mask).blob(@snapshot)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def load_state(input)
|
|
36
|
+
input.ints_into(@groups)
|
|
37
|
+
input.booleans_into(@mask)
|
|
38
|
+
input.blob_into(@snapshot)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def at?(pixel_x)
|
|
42
|
+
case @groups[pixel_x >> 3]
|
|
43
|
+
when FULL then true
|
|
44
|
+
when MIXED then @mask[pixel_x]
|
|
45
|
+
else false
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def snapshot(colors)
|
|
50
|
+
@snapshot[0, @width] = colors
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def restore(colors)
|
|
54
|
+
group = 0
|
|
55
|
+
while group < @groups.length
|
|
56
|
+
case @groups[group]
|
|
57
|
+
when FULL then group = restore_full(colors, group)
|
|
58
|
+
when MIXED then restore_mixed(colors, group * 8)
|
|
59
|
+
end
|
|
60
|
+
group += 1
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
# Copies a run of full-border groups in one splice and returns its
|
|
67
|
+
# last group.
|
|
68
|
+
def restore_full(colors, first)
|
|
69
|
+
last = first
|
|
70
|
+
last += 1 while @groups[last + 1] == FULL
|
|
71
|
+
x_pos = first * 8
|
|
72
|
+
length = (last - first + 1) * 8
|
|
73
|
+
colors[x_pos, length] = @snapshot[x_pos, length]
|
|
74
|
+
last
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def restore_mixed(colors, x_pos)
|
|
78
|
+
i = 0
|
|
79
|
+
while i < 8
|
|
80
|
+
x = x_pos + i
|
|
81
|
+
colors[x] = @snapshot[x] if @mask[x]
|
|
82
|
+
i += 1
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class VIC
|
|
6
|
+
# = Sprite collisions
|
|
7
|
+
#
|
|
8
|
+
# The $D01E/$D01F latches and the per-pixel sprite coverage that feeds
|
|
9
|
+
# them. Collisions latch as the beam passes each covered pixel, so a
|
|
10
|
+
# read mid-line sees the pixels drawn before the reading cycle and none
|
|
11
|
+
# of the ones after it.
|
|
12
|
+
class Collisions
|
|
13
|
+
# $D019 latch bits raised by the collision registers.
|
|
14
|
+
SPRITE_COLLISION_IRQ = 0x04 # IMMC, mirrors $D01E
|
|
15
|
+
DATA_COLLISION_IRQ = 0x02 # IMBC, mirrors $D01F
|
|
16
|
+
|
|
17
|
+
# A read holds the register's reset asserted past the cycle that
|
|
18
|
+
# issued it, so the pixels drawn under it never reach the register.
|
|
19
|
+
# The read still reports only the pixels drawn before its own cycle,
|
|
20
|
+
# which is why the two numbers do not cancel out.
|
|
21
|
+
CLEAR_OVERRUN = 12
|
|
22
|
+
|
|
23
|
+
# The pixel the last fold reached, so the sprites know whether a read
|
|
24
|
+
# has anything left to latch.
|
|
25
|
+
attr_reader :folded
|
|
26
|
+
|
|
27
|
+
# One bitmask per pixel of the line, written straight by the sprite
|
|
28
|
+
# merge and read back here and by the composite.
|
|
29
|
+
attr_reader :hits
|
|
30
|
+
|
|
31
|
+
def initialize(registers, width)
|
|
32
|
+
@registers = registers
|
|
33
|
+
@width = width
|
|
34
|
+
@hits = Array.new(width, 0)
|
|
35
|
+
@folded = 0
|
|
36
|
+
@cleared_sprite = 0
|
|
37
|
+
@cleared_data = 0
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def save_state(out)
|
|
41
|
+
out.blob(@hits).int(@folded).int(@cleared_sprite).int(@cleared_data)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def load_state(input)
|
|
45
|
+
input.blob_into(@hits)
|
|
46
|
+
@folded = input.int
|
|
47
|
+
@cleared_sprite = input.int
|
|
48
|
+
@cleared_data = input.int
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def start_line
|
|
52
|
+
@folded = 0
|
|
53
|
+
@cleared_sprite = carry(@cleared_sprite)
|
|
54
|
+
@cleared_data = carry(@cleared_data)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Latch every covered pixel between the last fold and the beam. The
|
|
58
|
+
# sprites' touched span bounds the scan; the coverage is zero outside
|
|
59
|
+
# it either way.
|
|
60
|
+
def fold(mask, upto, low, high)
|
|
61
|
+
from = [@folded, low].max
|
|
62
|
+
@folded = upto
|
|
63
|
+
scan(mask, from, [upto, high].min)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# A read resets its register for the pixels that follow the reading
|
|
67
|
+
# cycle as well as for everything before it.
|
|
68
|
+
def clear(reg, beam_x)
|
|
69
|
+
if reg == 0x1e
|
|
70
|
+
@cleared_sprite = beam_x + CLEAR_OVERRUN
|
|
71
|
+
else
|
|
72
|
+
@cleared_data = beam_x + CLEAR_OVERRUN
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
# Two or more sprites on a pixel collide with each other; any sprite
|
|
79
|
+
# over a foreground pixel collides with the graphics. Pixels still
|
|
80
|
+
# under a read's reset are dropped rather than latched.
|
|
81
|
+
def scan(mask, from, upto)
|
|
82
|
+
sprite_clash = 0
|
|
83
|
+
data_clash = 0
|
|
84
|
+
pos = from
|
|
85
|
+
while pos < upto
|
|
86
|
+
bits = @hits[pos]
|
|
87
|
+
unless bits.zero?
|
|
88
|
+
sprite_clash |= bits if pos >= @cleared_sprite && bits.anybits?(bits - 1)
|
|
89
|
+
data_clash |= bits if pos >= @cleared_data && mask[pos]
|
|
90
|
+
end
|
|
91
|
+
pos += 1
|
|
92
|
+
end
|
|
93
|
+
latch(sprite_clash, data_clash)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def latch(sprite_clash, data_clash)
|
|
97
|
+
latch_one(0x1e, sprite_clash, SPRITE_COLLISION_IRQ)
|
|
98
|
+
latch_one(0x1f, data_clash, DATA_COLLISION_IRQ)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# The IRQ is raised on the edge out of an empty register, so a
|
|
102
|
+
# collision folded on top of an unread one raises nothing.
|
|
103
|
+
def latch_one(reg, clash, irq)
|
|
104
|
+
return if clash.zero?
|
|
105
|
+
return unless @registers.collide!(reg, clash)
|
|
106
|
+
|
|
107
|
+
@registers.latch_irq!(irq)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# A reset still asserted at the line wrap carries into the new line.
|
|
111
|
+
def carry(cleared)
|
|
112
|
+
cleared > @width ? cleared - @width : 0
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class VIC
|
|
6
|
+
# A mid-line color register write becomes visible one pixel into the
|
|
7
|
+
# column emitted the cycle after the write. That emit paints the whole
|
|
8
|
+
# column with the new color, so the boundary pixel is patched back to
|
|
9
|
+
# the old one before the line is finished. On the 8565 the boundary
|
|
10
|
+
# pixel shows light grey instead, the grey dot, whatever the old and new
|
|
11
|
+
# colors are.
|
|
12
|
+
class ColorPatches
|
|
13
|
+
def initialize(sequencer, grey_dots: false)
|
|
14
|
+
@sequencer = sequencer
|
|
15
|
+
@grey_dots = grey_dots
|
|
16
|
+
@patches = []
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def clear = @patches.clear
|
|
20
|
+
|
|
21
|
+
# Each patch as its four numbers: the boundary pixel, the register,
|
|
22
|
+
# the old colour and the new.
|
|
23
|
+
def save_state(out)
|
|
24
|
+
out.int(@patches.length)
|
|
25
|
+
@patches.each { |patch| out.ints(patch) }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def load_state(input)
|
|
29
|
+
@patches.replace(Array.new(input.int) { input.ints })
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def log(reg, old, value, boundary_x)
|
|
33
|
+
@patches << [boundary_x, reg, @grey_dots ? GREY_DOT : old & 0x0f, value & 0x0f]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def apply(colors, fg_mask)
|
|
37
|
+
@patches.each do |(x, reg, old, value)|
|
|
38
|
+
border = @sequencer.border_at?(x)
|
|
39
|
+
if reg == 0x20
|
|
40
|
+
colors[x] = old if border
|
|
41
|
+
elsif !border && !fg_mask[x] && colors[x] == value
|
|
42
|
+
colors[x] = old
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|