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,265 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "badline/chips/sid/waveform"
|
|
4
|
+
require "badline/chips/sid/envelope"
|
|
5
|
+
require "badline/chips/sid/voice"
|
|
6
|
+
require "badline/chips/sid/filter"
|
|
7
|
+
require "badline/chips/sid/decimator"
|
|
8
|
+
require "badline/chips/sid/catch_up"
|
|
9
|
+
require "badline/chips/sid/saved_state"
|
|
10
|
+
|
|
11
|
+
module Badline
|
|
12
|
+
module Chips
|
|
13
|
+
# SID (Sound Interface Device) chip, in either the 6581 or the 8580
|
|
14
|
+
# revision.
|
|
15
|
+
#
|
|
16
|
+
# $D400-$D418 - Voices, filter and volume - write only
|
|
17
|
+
# $D419-$D41A - POTX/POTY paddle inputs - read only
|
|
18
|
+
# $D41B-$D41C - Voice 3 oscillator/envelope - read only
|
|
19
|
+
# $D41D-$D41F - Unconnected
|
|
20
|
+
#
|
|
21
|
+
# The register file mirrors every 32 bytes up to $D7FF. A second or
|
|
22
|
+
# third SID, which only the SID player fits, is built `at` another
|
|
23
|
+
# address and decodes just the 32 bytes there.
|
|
24
|
+
#
|
|
25
|
+
# Reading a write-only or unconnected register returns the last byte the
|
|
26
|
+
# SID saw on the data bus. That value fades to $00 as the capacitance
|
|
27
|
+
# holding it drains. Paddles and the 1351 mouse attach as a pots source
|
|
28
|
+
# responding to #pot_x and #pot_y; with none attached the lines read $FF.
|
|
29
|
+
#
|
|
30
|
+
# Three voices feed the filter and the master volume; #output and #sample
|
|
31
|
+
# read out the mixed result, and #record collects it at an audio rate for
|
|
32
|
+
# #drain_samples. The DSP is clocked lazily and catches up when something
|
|
33
|
+
# asks for its state.
|
|
34
|
+
#
|
|
35
|
+
# The 6581 drives its voices well above ground, so the mix carries a large
|
|
36
|
+
# DC offset that the RC network on the C64 board filters out.
|
|
37
|
+
class SID
|
|
38
|
+
include Addressable
|
|
39
|
+
include CatchUp
|
|
40
|
+
include SavedState
|
|
41
|
+
|
|
42
|
+
VOICES = 3
|
|
43
|
+
|
|
44
|
+
# Cycles the data bus holds a value, measured through SID/bitfade.
|
|
45
|
+
BUS_TTL = { mos6581: 0x1d00, mos8580: 0xa2000 }.freeze
|
|
46
|
+
|
|
47
|
+
# Scales the filter's 20-bit mix down to a signed 16-bit sample, as
|
|
48
|
+
# reSID 0.16 does: three voices at full swing and volume 15 span the
|
|
49
|
+
# whole range, on either chip.
|
|
50
|
+
SAMPLE_DIVISOR = ((0xfff * 0xff) >> 7) * 3 * 15 * 2 / (2**16)
|
|
51
|
+
|
|
52
|
+
# Writes the DSP queues between catch-ups. A full queue catches up
|
|
53
|
+
# there and then, so no write loses its timing.
|
|
54
|
+
DEFERRED_WRITES = 0x400
|
|
55
|
+
|
|
56
|
+
# Cycles the filter integrates in one step while synthesizing, after
|
|
57
|
+
# reSID's delta_t_flt. 1 makes the audio exact, at a per-cycle cost.
|
|
58
|
+
FILTER_CHUNK = 4
|
|
59
|
+
|
|
60
|
+
attr_accessor :pots
|
|
61
|
+
attr_reader :model
|
|
62
|
+
|
|
63
|
+
def initialize(model: :mos6581, pots: nil, filter_chunk: FILTER_CHUNK, at: 0xd400)
|
|
64
|
+
addressable_at(at, length: at == 0xd400 ? 2**10 : 2**5)
|
|
65
|
+
@model = model
|
|
66
|
+
@pots = pots
|
|
67
|
+
@bus_ttl_reset = BUS_TTL.fetch(model)
|
|
68
|
+
@filter = Filter.new(model:)
|
|
69
|
+
@synthesizing = false
|
|
70
|
+
@stepped = @synced = false
|
|
71
|
+
@pending_cycles = 0
|
|
72
|
+
@deferred_writes = []
|
|
73
|
+
@decimator = nil
|
|
74
|
+
@samples = []
|
|
75
|
+
@voice_samples = nil
|
|
76
|
+
@filter_chunk = filter_chunk
|
|
77
|
+
@voices = Voice.linked(VOICES, model:)
|
|
78
|
+
@voice1, @voice2, @voice3 = @voices
|
|
79
|
+
@waveform1, @waveform2, @waveform3 = @voices.map(&:waveform)
|
|
80
|
+
reset!
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Switches the chip, its filter and its voices to the other model's
|
|
84
|
+
# values. The cycles already passed run on the old model first, and the
|
|
85
|
+
# running state carries over.
|
|
86
|
+
def model=(model)
|
|
87
|
+
catch_up
|
|
88
|
+
@model = model
|
|
89
|
+
@bus_ttl_reset = BUS_TTL.fetch(model)
|
|
90
|
+
@filter.model = model
|
|
91
|
+
@voices.each { |voice| voice.model = model }
|
|
92
|
+
update_span_rules
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# The RES line clears the registers, the data bus, the filter and the
|
|
96
|
+
# voices, all but their accumulators. Recording carries on across it.
|
|
97
|
+
def reset!
|
|
98
|
+
catch_up
|
|
99
|
+
@registers = Memory.new(length: 2**5)
|
|
100
|
+
@bus_value = 0x00
|
|
101
|
+
@bus_ttl = 0
|
|
102
|
+
@voices.each(&:reset!)
|
|
103
|
+
@filter.reset
|
|
104
|
+
update_span_rules
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# The DSP only counts cycles as they pass. Whatever asks for its state
|
|
108
|
+
# catches it up, a span at a time: each span fast-forwards the voices
|
|
109
|
+
# and ends on one whole cycle, so everything the CPU can read stays
|
|
110
|
+
# exact. The filter only runs once something wants audio.
|
|
111
|
+
def synthesizing? = @synthesizing
|
|
112
|
+
|
|
113
|
+
def synthesize!
|
|
114
|
+
return if @synthesizing
|
|
115
|
+
|
|
116
|
+
@synthesizing = true
|
|
117
|
+
update_span_rules
|
|
118
|
+
catch_up
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Starts collecting the output, averaged down to `rate` samples a
|
|
122
|
+
# second, for #drain_samples. `filter_chunk` overrides the one the SID
|
|
123
|
+
# was built with, for a machine that built its own. `clock_hz` is the
|
|
124
|
+
# rate the SID's cycles are taken to run at.
|
|
125
|
+
def record(rate:, filter_chunk: @filter_chunk, clock_hz: Region::PAL.clock_hz)
|
|
126
|
+
synthesize!
|
|
127
|
+
catch_up
|
|
128
|
+
@filter_chunk = filter_chunk
|
|
129
|
+
@decimator = Decimator.new(clock_hz:, rate:)
|
|
130
|
+
@samples = []
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Also keeps each voice's own output, before the filter and the volume,
|
|
134
|
+
# as each recorded sample closes, for #drain_voice_samples.
|
|
135
|
+
def record_voices!
|
|
136
|
+
@voice_samples = [] if @voice_samples.nil?
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# The voices' outputs since the last drain, three to a sample, in voice
|
|
140
|
+
# order, or nothing unless #record_voices! asked for them.
|
|
141
|
+
def drain_voice_samples
|
|
142
|
+
return [] if @voice_samples.nil?
|
|
143
|
+
|
|
144
|
+
catch_up
|
|
145
|
+
samples = @voice_samples
|
|
146
|
+
@voice_samples = []
|
|
147
|
+
samples
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# The samples recorded since the last drain.
|
|
151
|
+
def drain_samples
|
|
152
|
+
catch_up
|
|
153
|
+
samples = @samples
|
|
154
|
+
@samples = []
|
|
155
|
+
samples
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def voices
|
|
159
|
+
catch_up
|
|
160
|
+
@voices
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Runs the DSP up to the current cycle.
|
|
164
|
+
def catch_up! = catch_up
|
|
165
|
+
|
|
166
|
+
# The byte the data bus holds and the cycles until it fades.
|
|
167
|
+
def bus_state = [@bus_value, @bus_ttl]
|
|
168
|
+
|
|
169
|
+
def restore_bus(value, ttl)
|
|
170
|
+
@bus_value = value
|
|
171
|
+
@bus_ttl = ttl
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def filter
|
|
175
|
+
catch_up
|
|
176
|
+
@filter
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Voice 3's oscillator and envelope, the only synthesis state the CPU
|
|
180
|
+
# can see. Programs poll OSC3 with the noise waveform selected for
|
|
181
|
+
# random numbers, and ENV3 to time hard restarts.
|
|
182
|
+
def osc3
|
|
183
|
+
catch_up
|
|
184
|
+
@waveform3.osc3 >> 4
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def env3
|
|
188
|
+
catch_up
|
|
189
|
+
@voice3.envelope.env3
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def output
|
|
193
|
+
synthesize!
|
|
194
|
+
catch_up
|
|
195
|
+
@filter.output
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def sample
|
|
199
|
+
output
|
|
200
|
+
current_sample
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def cycle!
|
|
204
|
+
age_bus if @bus_ttl != 0
|
|
205
|
+
@pending_cycles += 1
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def peek(addr)
|
|
209
|
+
case offset_of(addr) % (2**5)
|
|
210
|
+
when 0x19 then latch(pots ? pots.pot_x : 0xff)
|
|
211
|
+
when 0x1a then latch(pots ? pots.pot_y : 0xff)
|
|
212
|
+
when 0x1b then latch(osc3)
|
|
213
|
+
when 0x1c then latch(env3)
|
|
214
|
+
else @bus_value
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def poke(addr, value)
|
|
219
|
+
reg = offset_of(addr) % (2**5)
|
|
220
|
+
write_register(reg, value) if reg <= 0x18
|
|
221
|
+
latch(value)
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Register contents as written, for save states and debugging.
|
|
225
|
+
def register(reg) = @registers.peek(reg)
|
|
226
|
+
|
|
227
|
+
private
|
|
228
|
+
|
|
229
|
+
def latch(value)
|
|
230
|
+
@bus_ttl = @bus_ttl_reset
|
|
231
|
+
@bus_value = value
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def age_bus
|
|
235
|
+
@bus_ttl -= 1
|
|
236
|
+
@bus_value = 0x00 if @bus_ttl.zero?
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def write_register(reg, value)
|
|
240
|
+
@registers.poke(reg, value)
|
|
241
|
+
catch_up if @deferred_writes.length == DEFERRED_WRITES * 3
|
|
242
|
+
@deferred_writes.push(@pending_cycles, reg, value)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def apply_write(reg, value)
|
|
246
|
+
reg < 0x15 ? write_voice(reg, value) : @filter.write(reg, value)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def write_voice(reg, value)
|
|
250
|
+
voice = @voices[reg / 7]
|
|
251
|
+
case reg % 7
|
|
252
|
+
when 0 then voice.waveform.frequency_low = value
|
|
253
|
+
when 1 then voice.waveform.frequency_high = value
|
|
254
|
+
when 2 then voice.waveform.pulse_width_low = value
|
|
255
|
+
when 3 then voice.waveform.pulse_width_high = value
|
|
256
|
+
when 4
|
|
257
|
+
voice.control = value
|
|
258
|
+
update_span_rules
|
|
259
|
+
when 5 then voice.envelope.attack_decay = value
|
|
260
|
+
when 6 then voice.envelope.sustain_release = value
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class VDC
|
|
6
|
+
# The VDC's state for a snapshot.
|
|
7
|
+
module SavedState
|
|
8
|
+
# Everything the VDC holds but its display, which it paints again
|
|
9
|
+
# while it renders: the registers, the RAM, the data port and the
|
|
10
|
+
# raster. Whether it renders is the host's.
|
|
11
|
+
def save_state(out)
|
|
12
|
+
out.marker("VDC")
|
|
13
|
+
out.ints(@registers).blob(@memory.ram)
|
|
14
|
+
out.int(@selected).int(@read_latch).int(@write_data).int(@busy_until).int(@phase).int(@line_units)
|
|
15
|
+
@raster.save_state(out)
|
|
16
|
+
@painter.save_state(out)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def load_state(input)
|
|
20
|
+
input.marker("VDC")
|
|
21
|
+
input.ints_into(@registers)
|
|
22
|
+
input.blob_into(@memory.ram)
|
|
23
|
+
@memory.mode64 = @registers[28].anybits?(0x10)
|
|
24
|
+
@selected = input.int
|
|
25
|
+
@read_latch = input.int
|
|
26
|
+
@write_data = input.int
|
|
27
|
+
@busy_until = input.int
|
|
28
|
+
@phase = input.int
|
|
29
|
+
@line_units = input.int
|
|
30
|
+
@raster.load_state(input)
|
|
31
|
+
@painter.load_state(input)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "badline/
|
|
4
|
-
require "badline/
|
|
5
|
-
require "badline/
|
|
6
|
-
require "badline/
|
|
3
|
+
require "badline/chips/vdc/memory"
|
|
4
|
+
require "badline/chips/vdc/window"
|
|
5
|
+
require "badline/chips/vdc/painter"
|
|
6
|
+
require "badline/chips/vdc/raster"
|
|
7
|
+
require "badline/chips/vdc/saved_state"
|
|
7
8
|
|
|
8
9
|
module Badline
|
|
9
|
-
|
|
10
|
+
module Chips
|
|
10
11
|
# The 8563 or 8568 VDC: the address register at $D600 and the data
|
|
11
12
|
# register at $D601, mirrored through $D6FF, in front of 37 internal
|
|
12
13
|
# registers (38 on the 8568), the VDC's own RAM (Memory) and its 80
|
|
@@ -33,6 +34,7 @@ module Badline
|
|
|
33
34
|
# fills or two per byte it copies.
|
|
34
35
|
class VDC
|
|
35
36
|
include Addressable
|
|
37
|
+
include SavedState
|
|
36
38
|
|
|
37
39
|
STATUS_READY = 0x80
|
|
38
40
|
STATUS_VBLANK = 0x20
|
|
@@ -112,32 +114,6 @@ module Badline
|
|
|
112
114
|
@painter.clear!
|
|
113
115
|
end
|
|
114
116
|
|
|
115
|
-
# Everything the VDC holds but its display, which it paints again
|
|
116
|
-
# while it renders: the registers, the RAM, the data port and the
|
|
117
|
-
# raster. Whether it renders is the host's.
|
|
118
|
-
def save_state(out)
|
|
119
|
-
out.marker("VDC")
|
|
120
|
-
out.ints(@registers).blob(@memory.ram)
|
|
121
|
-
out.int(@selected).int(@read_latch).int(@write_data).int(@busy_until).int(@phase).int(@line_units)
|
|
122
|
-
@raster.save_state(out)
|
|
123
|
-
@painter.save_state(out)
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def load_state(input)
|
|
127
|
-
input.marker("VDC")
|
|
128
|
-
input.ints_into(@registers)
|
|
129
|
-
input.blob_into(@memory.ram)
|
|
130
|
-
@memory.mode64 = @registers[28].anybits?(0x10)
|
|
131
|
-
@selected = input.int
|
|
132
|
-
@read_latch = input.int
|
|
133
|
-
@write_data = input.int
|
|
134
|
-
@busy_until = input.int
|
|
135
|
-
@phase = input.int
|
|
136
|
-
@line_units = input.int
|
|
137
|
-
@raster.load_state(input)
|
|
138
|
-
@painter.load_state(input)
|
|
139
|
-
end
|
|
140
|
-
|
|
141
117
|
# The frames the raster has finished, which the blinking counts.
|
|
142
118
|
def frame = @raster.frame
|
|
143
119
|
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class VIA
|
|
6
|
+
# One port's pair of control lines, CA1 and CA2 or CB1 and CB2, set up
|
|
7
|
+
# by a nibble of the peripheral control register, and their two
|
|
8
|
+
# interrupt flags. Bit 0 picks the active edge of C1, rising when set.
|
|
9
|
+
# Bits 3-1 pick the C2 mode:
|
|
10
|
+
#
|
|
11
|
+
# 000 input, falling edge 100 handshake output
|
|
12
|
+
# 001 independent, falling 101 pulse output
|
|
13
|
+
# 010 input, rising edge 110 low output
|
|
14
|
+
# 011 independent, rising 111 high output
|
|
15
|
+
#
|
|
16
|
+
# A port access clears both flags, but an independent input keeps C2's.
|
|
17
|
+
# In handshake mode C2 goes low on a port access and back high on the
|
|
18
|
+
# next active C1 edge. In pulse mode it goes low for the cycle after the
|
|
19
|
+
# access. Port A handshakes on reads and writes, port B on writes only.
|
|
20
|
+
class ControlLines
|
|
21
|
+
attr_reader :control, :c1_high, :c2_high
|
|
22
|
+
|
|
23
|
+
# The level driven on C2, high while it is an input.
|
|
24
|
+
attr_reader :c2_output
|
|
25
|
+
|
|
26
|
+
def initialize(interrupts, c1_flag:, c2_flag:, handshake_on_read:)
|
|
27
|
+
@interrupts = interrupts
|
|
28
|
+
@c1_flag = c1_flag
|
|
29
|
+
@c2_flag = c2_flag
|
|
30
|
+
@handshake_on_read = handshake_on_read
|
|
31
|
+
@c1_high = @c2_high = true
|
|
32
|
+
reset!
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Back to input mode with both handshake outputs released. The input
|
|
36
|
+
# levels carry over.
|
|
37
|
+
def reset!
|
|
38
|
+
@control = 0
|
|
39
|
+
@handshake_low = false
|
|
40
|
+
@pulse = 0
|
|
41
|
+
drive
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def control=(nibble)
|
|
45
|
+
@control = nibble & 0x0f
|
|
46
|
+
drive
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Only the pulse output needs the clock.
|
|
50
|
+
def pulsing? = @pulse.positive?
|
|
51
|
+
|
|
52
|
+
def cycle!
|
|
53
|
+
@pulse -= 1
|
|
54
|
+
drive if @pulse.zero?
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def active_c1_edge?(high) = high == @control.anybits?(0x01)
|
|
58
|
+
|
|
59
|
+
# The lines' levels and mode. Which flags they set, and whether reads
|
|
60
|
+
# handshake, are the port's wiring.
|
|
61
|
+
def save_state(out)
|
|
62
|
+
out.int(@control).boolean(@c1_high).boolean(@c2_high).boolean(@handshake_low).int(@pulse).boolean(@c2_output)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def load_state(input)
|
|
66
|
+
@control = input.int
|
|
67
|
+
@c1_high = input.boolean?
|
|
68
|
+
@c2_high = input.boolean?
|
|
69
|
+
@handshake_low = input.boolean?
|
|
70
|
+
@pulse = input.int
|
|
71
|
+
@c2_output = input.boolean?
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Everything the lines hold, for comparing them at two points.
|
|
75
|
+
def state = [@control, @c1_high, @c2_high, @handshake_low, @pulse, @c2_output]
|
|
76
|
+
|
|
77
|
+
# A new C1 level. An active edge sets the flag and ends a handshake.
|
|
78
|
+
def c1=(high)
|
|
79
|
+
return if high == @c1_high
|
|
80
|
+
|
|
81
|
+
@c1_high = high
|
|
82
|
+
return unless active_c1_edge?(high)
|
|
83
|
+
|
|
84
|
+
@handshake_low = false
|
|
85
|
+
drive
|
|
86
|
+
@interrupts.set(@c1_flag)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# A new C2 level. An active edge sets the flag while C2 is an input.
|
|
90
|
+
def c2=(high)
|
|
91
|
+
return if high == @c2_high
|
|
92
|
+
|
|
93
|
+
@c2_high = high
|
|
94
|
+
@interrupts.set(@c2_flag) if @control.nobits?(0x08) && high == @control.anybits?(0x04)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# A read or write of the handshaking port register.
|
|
98
|
+
def access!(write)
|
|
99
|
+
@interrupts.clear(independent? ? @c1_flag : @c1_flag | @c2_flag)
|
|
100
|
+
return unless write || @handshake_on_read
|
|
101
|
+
|
|
102
|
+
case @control >> 1
|
|
103
|
+
when 4 then @handshake_low = true
|
|
104
|
+
when 5 then @pulse = 2
|
|
105
|
+
end
|
|
106
|
+
drive
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
def independent? = @control & 0x0a == 0x02
|
|
112
|
+
|
|
113
|
+
def drive
|
|
114
|
+
@c2_output = case @control >> 1
|
|
115
|
+
when 4 then !@handshake_low
|
|
116
|
+
when 5 then @pulse.zero?
|
|
117
|
+
when 6 then false
|
|
118
|
+
else true
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class VIA
|
|
6
|
+
# Running a VIA a stretch of cycles at once while nothing but its
|
|
7
|
+
# counters would change, for Drives::Engine::Idle.
|
|
8
|
+
module FastForward
|
|
9
|
+
# quiet_cycles for a VIA that will never set a flag of its own.
|
|
10
|
+
QUIET = 1 << 40
|
|
11
|
+
|
|
12
|
+
# How many cycles the VIA can run with nothing but its counters
|
|
13
|
+
# changing: no flag set, no pulse on a control line and no bit
|
|
14
|
+
# shifted. See Drives::Engine::Idle.
|
|
15
|
+
def quiet_cycles
|
|
16
|
+
return 0 if @sr_uses_t2 || @shift_register.clocking? || @ca.pulsing? || @cb.pulsing?
|
|
17
|
+
|
|
18
|
+
[@t1.quiet_cycles, @t2.quiet_cycles].min
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Runs +cycles+ cycles at once, as many as quiet_cycles allows, which
|
|
22
|
+
# moves only the counters.
|
|
23
|
+
def fast_forward(cycles)
|
|
24
|
+
return if cycles.zero?
|
|
25
|
+
|
|
26
|
+
@t1.fast_forward(cycles)
|
|
27
|
+
@t2.fast_forward(cycles)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# The counters an orbit (see Drives::Engine::Idle) has to bring back: those
|
|
31
|
+
# of the armed timers, and of the timers +touched+ names (bit 0 for
|
|
32
|
+
# timer 1, bit 1 for timer 2). The others only count.
|
|
33
|
+
def counter_state(touched)
|
|
34
|
+
[(@t1.count_state if @t1.armed? || touched.anybits?(1)),
|
|
35
|
+
(@t2.count_state if @t2.armed? || touched.anybits?(2))]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Runs +cycles+ cycles of whole orbits at once: the counters
|
|
39
|
+
# counter_state leaves out move on, and the rest come back round.
|
|
40
|
+
def skip_orbits(cycles, touched)
|
|
41
|
+
@t1.fast_forward(cycles) unless @t1.armed? || touched.anybits?(1)
|
|
42
|
+
@t2.fast_forward(cycles) unless @t2.armed? || touched.anybits?(2)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Everything the VIA holds but its counters, for comparing it at two
|
|
46
|
+
# points. Timer 1's PB7 level counts only while ACR bit 7 puts it on
|
|
47
|
+
# the pin: nothing reads it otherwise.
|
|
48
|
+
def idle_state
|
|
49
|
+
[@ora, @orb, @ddra, @ddrb, @latch_a, @latch_b, @acr, @pcr, @pb6_high, @ifr.flags, @ifr.enable,
|
|
50
|
+
@acr.anybits?(0x80) && @t1.pb7, *@t1.state, *@t2.state, *@ca.state, *@cb.state, *@shift_register.state]
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class VIA
|
|
6
|
+
# The interrupt flag and enable registers. Each source has a flag bit,
|
|
7
|
+
# and IRQ is pulled low while any flag is set with its enable bit.
|
|
8
|
+
class InterruptRegister
|
|
9
|
+
CA2 = 0x01
|
|
10
|
+
CA1 = 0x02
|
|
11
|
+
SR = 0x04
|
|
12
|
+
CB2 = 0x08
|
|
13
|
+
CB1 = 0x10
|
|
14
|
+
TIMER2 = 0x20
|
|
15
|
+
TIMER1 = 0x40
|
|
16
|
+
|
|
17
|
+
attr_reader :flags, :enable
|
|
18
|
+
|
|
19
|
+
def initialize
|
|
20
|
+
reset!
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def reset!
|
|
24
|
+
@flags = 0x00
|
|
25
|
+
@enable = 0x00
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def save_state(out)
|
|
29
|
+
out.int(@flags).int(@enable)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def load_state(input)
|
|
33
|
+
@flags = input.int
|
|
34
|
+
@enable = input.int
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def set(bits)
|
|
38
|
+
@flags |= bits
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def clear(bits)
|
|
42
|
+
@flags &= ~bits
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def irq? = @flags.anybits?(@enable)
|
|
46
|
+
|
|
47
|
+
# Bit 7 reads the IRQ output.
|
|
48
|
+
def read = irq? ? @flags | 0x80 : @flags
|
|
49
|
+
|
|
50
|
+
# Writing 1s clears the flags; bit 7 is ignored.
|
|
51
|
+
def write(value)
|
|
52
|
+
clear(value & 0x7f)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Bit 7 reads as 1.
|
|
56
|
+
def read_enable = @enable | 0x80
|
|
57
|
+
|
|
58
|
+
# Bit 7 picks between setting and clearing the enable bits given.
|
|
59
|
+
def write_enable(value)
|
|
60
|
+
if value.anybits?(0x80)
|
|
61
|
+
@enable |= value & 0x7f
|
|
62
|
+
else
|
|
63
|
+
@enable &= ~value & 0x7f
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class VIA
|
|
6
|
+
# Saving and restoring a VIA for a snapshot.
|
|
7
|
+
module SavedState
|
|
8
|
+
# The registers, the timers, the shift register, the interrupt flags
|
|
9
|
+
# and the control lines. The peripheral is the drive's wiring.
|
|
10
|
+
def save_state(out)
|
|
11
|
+
out.int(@ora).int(@orb).int(@ddra).int(@ddrb).int(@latch_a).int(@latch_b).int(@acr).int(@pcr)
|
|
12
|
+
out.boolean(@pb6_high).boolean(@sr_uses_t2)
|
|
13
|
+
@t1.save_state(out)
|
|
14
|
+
@t2.save_state(out)
|
|
15
|
+
@shift_register.save_state(out)
|
|
16
|
+
@ifr.save_state(out)
|
|
17
|
+
@ca.save_state(out)
|
|
18
|
+
@cb.save_state(out)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Puts the state back without telling the peripheral, which restores
|
|
22
|
+
# its own.
|
|
23
|
+
def load_state(input)
|
|
24
|
+
@ora = input.int
|
|
25
|
+
@orb = input.int
|
|
26
|
+
@ddra = input.int
|
|
27
|
+
@ddrb = input.int
|
|
28
|
+
@latch_a = input.int
|
|
29
|
+
@latch_b = input.int
|
|
30
|
+
@acr = input.int
|
|
31
|
+
@pcr = input.int
|
|
32
|
+
@pb6_high = input.boolean?
|
|
33
|
+
@sr_uses_t2 = input.boolean?
|
|
34
|
+
@t1.load_state(input)
|
|
35
|
+
@t2.load_state(input)
|
|
36
|
+
@shift_register.load_state(input)
|
|
37
|
+
@ifr.load_state(input)
|
|
38
|
+
@ca.load_state(input)
|
|
39
|
+
@cb.load_state(input)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|