badline 0.12.1 → 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 +17 -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 +3 -3
- 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} +1 -1
- data/lib/badline/c128/bus.rb +18 -17
- 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 +14 -9
- data/lib/badline/{computer → c64}/attachments.rb +4 -6
- 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/{computer → c64}/common.rb +2 -2
- data/lib/badline/{computer → c64}/kernal_traps.rb +18 -18
- 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 +11 -11
- data/lib/badline/{computer.rb → c64.rb} +18 -13
- 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 +26 -28
- 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 +3 -3
- 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/load.rb +5 -5
- data/lib/badline/kernal_trap/save.rb +4 -4
- data/lib/badline/kernal_trap/serial.rb +7 -7
- data/lib/badline/kernal_trap.rb +1 -2
- data/lib/badline/machine/clocking.rb +1 -1
- data/lib/badline/machine.rb +5 -5
- data/lib/badline/media/true_drive.rb +1 -1
- data/lib/badline/media/tune.rb +2 -2
- data/lib/badline/media.rb +3 -3
- data/lib/badline/model.rb +1 -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 +1 -1
- data/lib/badline/snapshot/setup.rb +22 -66
- data/lib/badline/snapshot/state.rb +8 -18
- 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 +3 -4
- data/lib/badline/storage/d64_image.rb +0 -2
- data/lib/badline/storage/d71_image.rb +0 -2
- data/lib/badline/storage/d81_image.rb +0 -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 +5 -5
- 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 -30
- data/lib/badline/vic20/user_via_ports.rb +2 -2
- data/lib/badline/vic20.rb +19 -14
- metadata +245 -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 -66
- data/lib/badline/address_bus/sid_slots.rb +0 -42
- data/lib/badline/address_bus.rb +0 -216
- 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/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/cpu_port.rb +0 -112
- 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 -315
- data/lib/badline/drive1541/disk_state.rb +0 -86
- 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 -853
- 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,140 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "badline/drives/datasette/saved_state"
|
|
4
|
+
|
|
5
|
+
module Badline
|
|
6
|
+
module Drives
|
|
7
|
+
# The 1530 datasette. Plays a pulse stream into CIA 1's FLAG pin while the
|
|
8
|
+
# motor runs with a key pressed, and reports the keys through the cassette
|
|
9
|
+
# sense line on the $01 port. With RECORD down too, it records the
|
|
10
|
+
# machine's write line onto the tape instead.
|
|
11
|
+
class Datasette
|
|
12
|
+
include SavedState
|
|
13
|
+
|
|
14
|
+
# What inserting a tape raises on a machine without a cassette port.
|
|
15
|
+
class Missing < ArgumentError; end
|
|
16
|
+
|
|
17
|
+
attr_reader :tape
|
|
18
|
+
attr_writer :motor
|
|
19
|
+
|
|
20
|
+
def initialize(tape = nil)
|
|
21
|
+
@tape = tape
|
|
22
|
+
@connected = true
|
|
23
|
+
@playing = false
|
|
24
|
+
@recording = false
|
|
25
|
+
@write_high = true
|
|
26
|
+
@since = 0
|
|
27
|
+
@motor = false
|
|
28
|
+
@countdown = 0
|
|
29
|
+
@flag_handler = nil
|
|
30
|
+
@sense_handler = nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Falling edges on the tape read line.
|
|
34
|
+
def on_flag(&handler)
|
|
35
|
+
@flag_handler = handler
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# The cassette sense line, which the $01 port reads back.
|
|
39
|
+
def on_sense_change(&handler)
|
|
40
|
+
@sense_handler = handler
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Whether the machine has a datasette at its cassette port. The SX-64
|
|
44
|
+
# has none: its keys stay up and it takes no tape.
|
|
45
|
+
def connected? = @connected
|
|
46
|
+
|
|
47
|
+
def disconnect!
|
|
48
|
+
eject
|
|
49
|
+
@connected = false
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def insert(tape)
|
|
53
|
+
raise Missing, "this machine has no datasette" unless @connected
|
|
54
|
+
|
|
55
|
+
@tape = tape
|
|
56
|
+
rewind
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def eject
|
|
60
|
+
stop!
|
|
61
|
+
@tape = nil
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def rewind
|
|
65
|
+
@tape&.rewind
|
|
66
|
+
@countdown = 0
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def play! = press(true)
|
|
70
|
+
def stop! = press(false)
|
|
71
|
+
|
|
72
|
+
# Presses RECORD and PLAY together.
|
|
73
|
+
def record!
|
|
74
|
+
return if !@connected || @tape.nil?
|
|
75
|
+
|
|
76
|
+
press(true)
|
|
77
|
+
@recording = true
|
|
78
|
+
@since = 0
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def recording? = @recording
|
|
82
|
+
|
|
83
|
+
# The machine's tape write line. While the deck records with its motor
|
|
84
|
+
# running, each rising edge ends a pulse on the tape, as long as the
|
|
85
|
+
# time since the edge before, and plays back as a falling edge on the
|
|
86
|
+
# read line.
|
|
87
|
+
def write_line=(high)
|
|
88
|
+
rose = high && !@write_high
|
|
89
|
+
@write_high = high
|
|
90
|
+
return unless rose && @recording && running?
|
|
91
|
+
|
|
92
|
+
@tape.record_pulse(@since)
|
|
93
|
+
@since = 0
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def playing? = @playing
|
|
97
|
+
|
|
98
|
+
# Sense reads low while a key is down on the deck.
|
|
99
|
+
def sense_low? = @playing
|
|
100
|
+
|
|
101
|
+
def motor? = @motor
|
|
102
|
+
|
|
103
|
+
def running? = @playing && @motor && !@tape.nil?
|
|
104
|
+
|
|
105
|
+
def cycle!
|
|
106
|
+
return unless running?
|
|
107
|
+
return @since += 1 if @recording
|
|
108
|
+
|
|
109
|
+
@countdown = @tape.next_pulse.to_i if @countdown.zero?
|
|
110
|
+
return if @countdown.zero?
|
|
111
|
+
|
|
112
|
+
@countdown -= 1
|
|
113
|
+
@flag_handler&.call if @countdown.zero?
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def inspect
|
|
117
|
+
"#<#{self.class.name} tape=#{@tape ? @tape.class.name : 'none'} " \
|
|
118
|
+
"playing=#{@playing} motor=#{@motor}>"
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
private
|
|
122
|
+
|
|
123
|
+
def press(down)
|
|
124
|
+
return if down == @playing || !@connected
|
|
125
|
+
|
|
126
|
+
finish_recording unless down
|
|
127
|
+
@playing = down
|
|
128
|
+
@sense_handler&.call
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Releasing the keys ends a recording, and writes the tape out.
|
|
132
|
+
def finish_recording
|
|
133
|
+
return unless @recording
|
|
134
|
+
|
|
135
|
+
@recording = false
|
|
136
|
+
@tape.save
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Drives
|
|
5
|
+
module Engine
|
|
6
|
+
# What every Commodore disk drive here shares: a 6502 running the DOS
|
|
7
|
+
# ROM, with chips on its bus facing the serial bus and the disk
|
|
8
|
+
# mechanism, on a clock of its own.
|
|
9
|
+
#
|
|
10
|
+
# The drive runs on its own crystal, so it clocks against the host's
|
|
11
|
+
# clock through a fractional accumulator: each host cycle adds the
|
|
12
|
+
# drive's clock rate worth of phase, and every whole host period in it
|
|
13
|
+
# runs a drive cycle. Against the PAL C64's 985,248 Hz a drive at
|
|
14
|
+
# 1 MHz runs one drive cycle per host cycle and a second one about
|
|
15
|
+
# every 67. The host sets its clock on attaching the drive, and until
|
|
16
|
+
# then a 1 MHz drive runs one cycle per host cycle.
|
|
17
|
+
#
|
|
18
|
+
# The Mechanism reads a Disk put in with insert.
|
|
19
|
+
#
|
|
20
|
+
# While the DOS idles, host_cycle! skips the drive's cycles and catches
|
|
21
|
+
# up on them later, exactly (see Idle). The readers of the drive's parts
|
|
22
|
+
# catch up first, so they find the drive as running every cycle would
|
|
23
|
+
# have left it. Once the DOS's timer interrupts come round, the drive
|
|
24
|
+
# sleeps through them too (see Orbit).
|
|
25
|
+
#
|
|
26
|
+
# A model includes Core and builds its parts, sets @clock_hz and
|
|
27
|
+
# @idle_loop, and runs one drive cycle in step. It hears ATN on
|
|
28
|
+
# connecting (hear_atn), drives the serial bus (serial_output), and
|
|
29
|
+
# answers Idle's and Orbit's questions about its chips, as VIAs does
|
|
30
|
+
# for the 1541 and the 1571.
|
|
31
|
+
module Core
|
|
32
|
+
include Sleep
|
|
33
|
+
include Idle
|
|
34
|
+
include Orbit
|
|
35
|
+
|
|
36
|
+
attr_reader :device, :serial_bus
|
|
37
|
+
|
|
38
|
+
def cpu
|
|
39
|
+
settle!
|
|
40
|
+
@cpu
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def bus
|
|
44
|
+
settle!
|
|
45
|
+
@bus
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def mechanism
|
|
49
|
+
settle!
|
|
50
|
+
@mechanism
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def cycles
|
|
54
|
+
settle!
|
|
55
|
+
@cycles
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def ram = bus.ram
|
|
59
|
+
|
|
60
|
+
def host_clock_hz=(clock_hz)
|
|
61
|
+
settle!
|
|
62
|
+
@host_clock_hz = clock_hz
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Plugs the drive into a serial bus, leaving the one it was on. A drive
|
|
66
|
+
# starts out on a bus of its own, with nothing else on it.
|
|
67
|
+
def connect(serial_bus)
|
|
68
|
+
settle!
|
|
69
|
+
@serial_bus&.detach(self)
|
|
70
|
+
@serial_bus = serial_bus
|
|
71
|
+
@serial_port.bus = serial_bus
|
|
72
|
+
serial_bus.attach(self)
|
|
73
|
+
hear_atn
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Puts a Disk in the drive (Disk.from_d64 makes one from an image).
|
|
77
|
+
# Nil takes the disk out.
|
|
78
|
+
def insert(disk)
|
|
79
|
+
settle!
|
|
80
|
+
@mechanism.insert(disk)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def disk = mechanism.disk
|
|
84
|
+
|
|
85
|
+
# Whether the LED is lit. Reading it leaves the drive asleep: the LED
|
|
86
|
+
# is the same at the end of every pass the drive sleeps through.
|
|
87
|
+
def led_on? = @mechanism.led_on?
|
|
88
|
+
|
|
89
|
+
# Stores what the head wrote since the motor last stopped in the
|
|
90
|
+
# disk's image, as the motor stopping does.
|
|
91
|
+
def flush
|
|
92
|
+
settle!
|
|
93
|
+
@mechanism.flush
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Runs the drive cycles that fall in one host cycle: none, one or two.
|
|
97
|
+
# The host has run this cycle already, and the drive sees what it did
|
|
98
|
+
# from the next one on (see SerialPort). Asleep, the drive owes the
|
|
99
|
+
# cycles instead, until ATN moves or its counters are due (see Idle).
|
|
100
|
+
# It looks at ATN only after the machine pushed its lines into the bus
|
|
101
|
+
# (see host_written!).
|
|
102
|
+
def host_cycle!
|
|
103
|
+
if @asleep
|
|
104
|
+
return if (@slept += 1) != @wake_at && @host_still
|
|
105
|
+
|
|
106
|
+
return doze
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
phase = @phase + @clock_hz
|
|
110
|
+
while phase >= @host_clock_hz
|
|
111
|
+
@asleep ? @owed += 1 : run_cycle
|
|
112
|
+
phase -= @host_clock_hz
|
|
113
|
+
end
|
|
114
|
+
@phase = phase
|
|
115
|
+
settle! if @serial_port.atn_moved?
|
|
116
|
+
@serial_port.latch_host
|
|
117
|
+
plan_wake if @asleep
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# The machine pushed its lines into the bus, so ATN may have moved.
|
|
121
|
+
def host_written!
|
|
122
|
+
@host_still = false
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# The host moved its fast serial pins, which a 1541 has none to hear.
|
|
126
|
+
def fast_lines_moved = nil
|
|
127
|
+
|
|
128
|
+
# Runs one drive cycle, catching up first on any the drive owes (see
|
|
129
|
+
# step).
|
|
130
|
+
def cycle!
|
|
131
|
+
settle!
|
|
132
|
+
step
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def inspect
|
|
136
|
+
"#<#{self.class.name} cycles=#{cycles} cpu=(#{cpu.inspect})>"
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
private
|
|
140
|
+
|
|
141
|
+
# A drive cycle from host_cycle!, which may find the idle loop.
|
|
142
|
+
def run_cycle
|
|
143
|
+
step
|
|
144
|
+
idle_loop_reached if @cpu.program_counter == @idle_loop && @idle_skip
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Drives
|
|
5
|
+
module Engine
|
|
6
|
+
# Fast serial on a drive with a CIA, the 1571's 6526 or the 1581's
|
|
7
|
+
# 8520: through buffers a port line turns round, the CIA's CNT drives
|
|
8
|
+
# SRQ and its SP drives DATA, or it hears them. The drive pushes its
|
|
9
|
+
# pins into the bus as they move, and hears the host's as the host
|
|
10
|
+
# pushes them, pin by pin, so each byte goes through both shift
|
|
11
|
+
# registers bit by bit. The CIA takes no part in a pass of the idle
|
|
12
|
+
# loop, and any access to it, or the host moving its fast serial pins,
|
|
13
|
+
# wakes the drive.
|
|
14
|
+
#
|
|
15
|
+
# A model includes it beside Core, and calls turn_fast_serial when its
|
|
16
|
+
# direction line moves and drive_fast_serial each cycle the buffers
|
|
17
|
+
# face out. Its serial_output carries @fast_output above its port.
|
|
18
|
+
module FastSerial
|
|
19
|
+
# Whether the buffers face out, the drive's CIA driving DATA and SRQ.
|
|
20
|
+
attr_reader :fast_serial_out
|
|
21
|
+
|
|
22
|
+
# The host moved its fast serial pins: the CIA hears SRQ on CNT and
|
|
23
|
+
# DATA on SP while the buffers face in.
|
|
24
|
+
def fast_lines_moved
|
|
25
|
+
settle!
|
|
26
|
+
hear_fast_serial unless @fast_serial_out
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def init_fast_serial
|
|
32
|
+
@fast_serial_out = false
|
|
33
|
+
@fast_output = 0
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# The buffers turned round: outwards the CIA's pins drive the lines,
|
|
37
|
+
# and inwards they let go and hear them.
|
|
38
|
+
def turn_fast_serial(out)
|
|
39
|
+
@fast_serial_out = out
|
|
40
|
+
return unless @serial_bus
|
|
41
|
+
|
|
42
|
+
push_fast_output(out ? fast_pins : 0)
|
|
43
|
+
hear_fast_serial unless out
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def drive_fast_serial
|
|
47
|
+
low = fast_pins
|
|
48
|
+
push_fast_output(low) if low != @fast_output
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# The lines the CIA's CNT and SP pull while its serial port drives
|
|
52
|
+
# them.
|
|
53
|
+
def fast_pins
|
|
54
|
+
serial = @cia.serial
|
|
55
|
+
return 0 unless serial.output?
|
|
56
|
+
|
|
57
|
+
low = serial.cnt ? 0 : SerialBus::DRIVE_FAST_SRQ
|
|
58
|
+
serial.sp_out ? low : low | SerialBus::DRIVE_FAST_DATA
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def push_fast_output(low)
|
|
62
|
+
@fast_output = low
|
|
63
|
+
@serial_bus&.drives_fast_moved!
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def hear_fast_serial
|
|
67
|
+
low = @serial_bus.low_lines
|
|
68
|
+
serial = @cia.serial
|
|
69
|
+
serial.cnt_in = low.nobits?(SerialBus::SRQ)
|
|
70
|
+
serial.sp_in = low.nobits?(SerialBus::DATA)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Drives
|
|
5
|
+
module Engine
|
|
6
|
+
# Skipping the drive's cycles while the DOS idles, exactly.
|
|
7
|
+
#
|
|
8
|
+
# With nothing to do, the DOS goes round its idle loop from the
|
|
9
|
+
# model's @idle_loop ($EBFF in the 1541, 446 cycles a pass), until VIA
|
|
10
|
+
# 2's timer 1 interrupts it every 14,850 cycles for the job loop, or
|
|
11
|
+
# ATN interrupts it through VIA 1's CA1. A pass writes RAM and VIA 2's
|
|
12
|
+
# port B, but puts back what it found, so the drive comes round to the
|
|
13
|
+
# loop's start as it left it. Only the timers' counters and the cycle
|
|
14
|
+
# counts move.
|
|
15
|
+
#
|
|
16
|
+
# Each time the CPU comes to the loop's start, the drive records the
|
|
17
|
+
# pass that follows. At the next it checks that the pass
|
|
18
|
+
#
|
|
19
|
+
# - left the CPU, both VIAs but for their counters, the bus's last
|
|
20
|
+
# byte, the SO pin, the mechanism (Mechanism#idle_state) and what
|
|
21
|
+
# the ports read from it, and every byte of RAM it read or wrote as
|
|
22
|
+
# it found them (Bus#watch!)
|
|
23
|
+
# - read nothing that changes from pass to pass: no counter, no shift
|
|
24
|
+
# register, and not VIA 1's port B, which reads the serial bus
|
|
25
|
+
# - wrote nothing that reaches outside the drive: not VIA 1, whose port
|
|
26
|
+
# B drives the serial bus, and not the motor on
|
|
27
|
+
# - ran while no counter could set a flag (VIA#quiet_cycles), with the
|
|
28
|
+
# motor off, no interrupt pulled and no trap on the CPU.
|
|
29
|
+
#
|
|
30
|
+
# Such a pass runs the same way again from where it ended, for as
|
|
31
|
+
# long as ATN holds still and no counter sets a flag, so the drive
|
|
32
|
+
# sleeps: host_cycle! only counts the host cycles that go by (see
|
|
33
|
+
# Sleep). It wakes
|
|
34
|
+
# when ATN moves, when a counter is due to set a flag, or when something
|
|
35
|
+
# outside reads or changes the drive (the readers in Core call
|
|
36
|
+
# settle!). Waking counts off the whole passes it owes in bulk,
|
|
37
|
+
# moving the counters on, and runs the rest cycle by cycle.
|
|
38
|
+
#
|
|
39
|
+
# The loop reads neither CLK nor DATA, so the drive sleeps through them
|
|
40
|
+
# moving and takes the C64's lines as they stand once it wakes. Its
|
|
41
|
+
# own lines hold still while it sleeps, so the C64 reads them without
|
|
42
|
+
# waking it (serial_output).
|
|
43
|
+
#
|
|
44
|
+
# A pass starts at the loop's start, where the CPU always comes from
|
|
45
|
+
# the loop's last instruction, a JMP, so what that leaves in the CPU's
|
|
46
|
+
# working registers is the same each time round.
|
|
47
|
+
#
|
|
48
|
+
# The timer's interrupts come round too, and once they do, the drive
|
|
49
|
+
# sleeps on through them (see Orbit).
|
|
50
|
+
module Idle
|
|
51
|
+
# Whether the drive may sleep through its idle loop. On by default,
|
|
52
|
+
# but for a drive whose CPU logs each instruction.
|
|
53
|
+
attr_reader :idle_skip
|
|
54
|
+
|
|
55
|
+
def idle_skip=(on)
|
|
56
|
+
settle!
|
|
57
|
+
@idle_skip = on
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def init_idle(debug)
|
|
63
|
+
@idle_skip = !debug
|
|
64
|
+
@recording = false
|
|
65
|
+
@pass_cycles = 0
|
|
66
|
+
@pass_instructions = 0
|
|
67
|
+
init_sleep
|
|
68
|
+
init_orbits
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# The CPU is at the loop's start. At an instruction boundary, the
|
|
72
|
+
# drive sleeps if the pass it recorded can repeat, and otherwise
|
|
73
|
+
# records the next.
|
|
74
|
+
def idle_loop_reached
|
|
75
|
+
return unless @cpu.boundary?
|
|
76
|
+
|
|
77
|
+
if @recording
|
|
78
|
+
stop_recording
|
|
79
|
+
return fall_asleep if repeatable_pass? && room_for_pass?
|
|
80
|
+
end
|
|
81
|
+
start_recording
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def start_recording
|
|
85
|
+
return if busy_for_pass? || @cpu.trapped?
|
|
86
|
+
|
|
87
|
+
@recording = true
|
|
88
|
+
@record_state = idle_state
|
|
89
|
+
@record_cycles = @cycles
|
|
90
|
+
@record_instructions = @cpu.instructions
|
|
91
|
+
@record_quiet = quiet_cycles
|
|
92
|
+
@bus.watch!
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def stop_recording
|
|
96
|
+
@recording = false
|
|
97
|
+
@bus.unwatch!
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Whether the pass just recorded can repeat.
|
|
101
|
+
def repeatable_pass?
|
|
102
|
+
!@bus.volatile && @cycles - @record_cycles <= @record_quiet && idle_state == @record_state &&
|
|
103
|
+
ram_as_found?
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Whether the counters leave room for a whole pass.
|
|
107
|
+
def room_for_pass? = quiet_cycles >= @cycles - @record_cycles
|
|
108
|
+
|
|
109
|
+
# Sleeps through the pass just recorded, over and over.
|
|
110
|
+
def fall_asleep
|
|
111
|
+
@pass_cycles = @cycles - @record_cycles
|
|
112
|
+
@pass_instructions = @cpu.instructions - @record_instructions
|
|
113
|
+
@asleep = true
|
|
114
|
+
@host_still = false
|
|
115
|
+
@owed = 0
|
|
116
|
+
@budget = quiet_cycles
|
|
117
|
+
anchor
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def ram_as_found?
|
|
121
|
+
ram = @bus.ram
|
|
122
|
+
@bus.touched.all? { |addr, value| ram.peek(addr) == value }
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Drives
|
|
5
|
+
module Engine
|
|
6
|
+
# What Idle needs of a drive's 6502, which includes it beside
|
|
7
|
+
# CPU::Core.
|
|
8
|
+
module IdleCPU
|
|
9
|
+
# Everything the CPU holds but its cycle and instruction counts: the
|
|
10
|
+
# registers, the interrupt lines and pipeline, and what the last
|
|
11
|
+
# instruction left in its working registers. Drives::Engine::Idle compares
|
|
12
|
+
# it at two instruction boundaries.
|
|
13
|
+
def idle_state
|
|
14
|
+
[@program_counter, @stack_pointer, @a, @x, @y, @status.value,
|
|
15
|
+
@irq, @nmi, @irq_sample, @irq_pending, @nmi_sample, @nmi_pending, @skip_poll,
|
|
16
|
+
@boundary_irq, @boundary_nmi, @so_high, @interrupt, @brk, @pending_write, @stalled_at, @traps,
|
|
17
|
+
@operation, @optional_dummy, @boundary_crossed, @branch_taken,
|
|
18
|
+
@address, @pointer, @dummy_address, @value, @rmw_result]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Counts +cycles+ cycles and +instructions+ instructions that ran
|
|
22
|
+
# without changing anything idle_state holds.
|
|
23
|
+
def fast_forward(cycles, instructions)
|
|
24
|
+
@cycles += cycles
|
|
25
|
+
@instructions += instructions
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Drives
|
|
5
|
+
module Engine
|
|
6
|
+
# Sleeping through the DOS's timer interrupts, exactly, once they come
|
|
7
|
+
# round.
|
|
8
|
+
#
|
|
9
|
+
# VIA 2's timer 1 interrupts the idle loop for the job loop, which
|
|
10
|
+
# finds no job, restarts the timer and returns into the pass it cut
|
|
11
|
+
# into, 14,998 cycles and more apart. The interrupts land at a
|
|
12
|
+
# different point in the pass each time, until, six of them on, the
|
|
13
|
+
# whole drive is back where it was: an orbit of 90,044 cycles.
|
|
14
|
+
#
|
|
15
|
+
# Each place the drive falls asleep (see Idle) is an anchor, and the
|
|
16
|
+
# drive keeps everything it holds at each one: RAM, the counters of
|
|
17
|
+
# the timers that are armed or that it read or wrote since, and the
|
|
18
|
+
# rest as Idle compares a pass. It keeps them only while it keeps to
|
|
19
|
+
# itself, with Bus#guard! checking that it doesn't read the serial
|
|
20
|
+
# bus, write VIA 1, turn the motor on or change the LED. ATN moving,
|
|
21
|
+
# or a reader settling the drive, forgets them.
|
|
22
|
+
#
|
|
23
|
+
# Coming to an anchor it kept before closes an orbit, which runs the
|
|
24
|
+
# same way again from here for as long as ATN holds still, so the
|
|
25
|
+
# drive sleeps on without waking for its counters. Waking counts off
|
|
26
|
+
# the whole orbits it owes in bulk, moving on only the counters it
|
|
27
|
+
# never touched, and runs the rest as Idle does.
|
|
28
|
+
module Orbit
|
|
29
|
+
# How many anchors the drive keeps while it looks for an orbit.
|
|
30
|
+
ANCHORS = 32
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def init_orbits
|
|
35
|
+
@anchors = {}
|
|
36
|
+
@orbit_cycles = nil
|
|
37
|
+
@orbit_instructions = 0
|
|
38
|
+
@bus.guard!
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# The drive falls asleep at an anchor. One it came to before closes
|
|
42
|
+
# an orbit: everything from there to here runs the same way again.
|
|
43
|
+
def anchor
|
|
44
|
+
forget_orbits if @bus.tainted || @anchors.size >= ANCHORS
|
|
45
|
+
key = anchor_state
|
|
46
|
+
if (seen = @anchors[key])
|
|
47
|
+
@orbit_cycles = @cycles - seen[0]
|
|
48
|
+
@orbit_instructions = @cpu.instructions - seen[1]
|
|
49
|
+
else
|
|
50
|
+
@anchors[key] = [@cycles, @cpu.instructions]
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def forget_orbits
|
|
55
|
+
@anchors.clear
|
|
56
|
+
@orbit_cycles = nil
|
|
57
|
+
@bus.guard!
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Runs whole orbits, which bring the drive back to the anchor it
|
|
61
|
+
# sleeps at but for the counters it never touched. Returns the
|
|
62
|
+
# cycles.
|
|
63
|
+
def skip_orbits(orbits)
|
|
64
|
+
cycles = orbits * @orbit_cycles
|
|
65
|
+
touched = @bus.touched_timers
|
|
66
|
+
@cpu.fast_forward(cycles, orbits * @orbit_instructions)
|
|
67
|
+
skip_chip_orbits(cycles, touched)
|
|
68
|
+
@cycles += cycles
|
|
69
|
+
cycles
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Everything the drive holds at an anchor, but for the counters of
|
|
73
|
+
# the unarmed timers it hasn't touched since it was last tainted.
|
|
74
|
+
def anchor_state
|
|
75
|
+
touched = @bus.touched_timers
|
|
76
|
+
[*idle_state, *counter_state(touched), @bus.ram.snapshot]
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Drives
|
|
5
|
+
module Engine
|
|
6
|
+
# What VIA 1's port B reads from the serial bus. DATA IN (PB0), CLK IN
|
|
7
|
+
# (PB2) and ATN IN (PB7) come through inverters, so a released line
|
|
8
|
+
# reads 0 and a pulled one 1. The jumpers on PB5 and PB6 pull a line
|
|
9
|
+
# low when closed, and both closed make device 8.
|
|
10
|
+
#
|
|
11
|
+
# The drive sees the host's side of the bus a host cycle late. The
|
|
12
|
+
# host's CIA changes its pins at the end of the cycle that writes them,
|
|
13
|
+
# and the drive's VIA samples its own late in each of its cycles, so a
|
|
14
|
+
# drive cycle that runs alongside the write reads the lines from
|
|
15
|
+
# before it. The drive runs after the host in each host cycle (see
|
|
16
|
+
# C64#cycle!), so the port reads the host's lines as latch_host
|
|
17
|
+
# took them at the end of the last one. Fast loaders that time their
|
|
18
|
+
# transfer from an ATN edge, as VICE's drive tests do, depend on it.
|
|
19
|
+
#
|
|
20
|
+
# A model's serial port includes it, with its own port A.
|
|
21
|
+
module SerialLines
|
|
22
|
+
DATA_IN = 0x01
|
|
23
|
+
CLK_IN = 0x04
|
|
24
|
+
ATN_IN = 0x80
|
|
25
|
+
SERIAL_INPUTS = DATA_IN | CLK_IN | ATN_IN
|
|
26
|
+
JUMPERS = 0b0110_0000
|
|
27
|
+
|
|
28
|
+
attr_reader :bus
|
|
29
|
+
|
|
30
|
+
def bus=(bus)
|
|
31
|
+
@bus = bus
|
|
32
|
+
latch_host
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Takes the host's lines as the machine last pushed them into the bus,
|
|
36
|
+
# for the drive cycles of the next host cycle.
|
|
37
|
+
def latch_host
|
|
38
|
+
@host = @bus.host_lines
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# The host's lines as last latched. The jumpers and the bus are the
|
|
42
|
+
# drive's wiring.
|
|
43
|
+
def save_state(out)
|
|
44
|
+
out.int(@host)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def load_state(input)
|
|
48
|
+
@host = input.int
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Whether the host has moved ATN since the last latch_host.
|
|
52
|
+
def atn_moved? = (@bus.host_lines ^ @host).anybits?(SerialBus::HOST_ATN_OUT)
|
|
53
|
+
|
|
54
|
+
def atn_low? = @bus.atn_low?(@host)
|
|
55
|
+
|
|
56
|
+
def read_b(_lines)
|
|
57
|
+
low = @bus.low_lines(@host)
|
|
58
|
+
value = @port_b
|
|
59
|
+
value |= DATA_IN if low.anybits?(SerialBus::DATA)
|
|
60
|
+
value |= CLK_IN if low.anybits?(SerialBus::CLK)
|
|
61
|
+
value |= ATN_IN if low.anybits?(SerialBus::ATN)
|
|
62
|
+
value
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def init_serial_lines(device, bus)
|
|
68
|
+
@port_b = (0xff & ~(SERIAL_INPUTS | JUMPERS)) | (((device - 8) & 0x03) << 5)
|
|
69
|
+
@host = 0
|
|
70
|
+
self.bus = bus
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|