badline 0.12.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +66 -1
- data/CLAUDE.md +86 -38
- data/CONTRIBUTING.md +4 -3
- data/README.md +9 -6
- data/doc/library.md +9 -9
- data/doc/media.md +2 -1
- data/doc/pinned-behaviour.md +134 -105
- data/doc/snapshot-format.md +1047 -0
- data/doc/snapshots.md +73 -43
- data/lib/badline/audio/bare_player.rb +53 -20
- data/lib/badline/audio/cli.rb +6 -6
- data/lib/badline/audio/jukebox.rb +2 -2
- data/lib/badline/audio/machine_player.rb +16 -10
- data/lib/badline/{media → audio}/queue.rb +1 -1
- data/lib/badline/audio/queued_tune.rb +6 -6
- data/lib/badline/audio/renderer.rb +33 -22
- data/lib/badline/audio/stereo.rb +1 -1
- data/lib/badline/c128/banks.rb +6 -3
- data/lib/badline/c128/bus/keyed_state.rb +45 -0
- data/lib/badline/c128/bus.rb +35 -20
- data/lib/badline/c128/color_lines.rb +2 -2
- data/lib/badline/c128/cpu.rb +1 -1
- data/lib/badline/c128/drives.rb +14 -34
- data/lib/badline/c128/fast_serial.rb +5 -5
- data/lib/badline/c128/keyed_modules.rb +117 -0
- data/lib/badline/c128/keyed_state.rb +91 -0
- data/lib/badline/c128/keys.rb +9 -0
- data/lib/badline/c128/mmu.rb +9 -8
- data/lib/badline/c128/mmu_pages.rb +21 -1
- data/lib/badline/c128/modes.rb +21 -11
- data/lib/badline/c128/z80.rb +2 -2
- data/lib/badline/c128/z80_turns.rb +1 -1
- data/lib/badline/c128.rb +21 -16
- data/lib/badline/c64/attachments.rb +42 -0
- data/lib/badline/c64/banked_ram/banking.rb +32 -0
- data/lib/badline/c64/banked_ram/plus256k.rb +64 -0
- data/lib/badline/c64/banked_ram/plus60k.rb +47 -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/debug_register.rb +32 -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/keyed_state.rb +41 -0
- data/lib/badline/c64/bus/pla.rb +149 -0
- data/lib/badline/c64/bus/roms.rb +41 -0
- data/lib/badline/c64/bus/sid_slots.rb +44 -0
- data/lib/badline/c64/bus.rb +219 -0
- data/lib/badline/c64/cartridge/action_replay.rb +115 -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 +132 -0
- data/lib/badline/c64/cartridge/epyx_fastload.rb +73 -0
- data/lib/badline/c64/cartridge/final_cartridge3.rb +79 -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 +64 -0
- data/lib/badline/c64/cartridge/game_system.rb +42 -0
- data/lib/badline/c64/cartridge/geo_ram.rb +65 -0
- data/lib/badline/c64/cartridge/kcs_power.rb +69 -0
- data/lib/badline/c64/cartridge/keyed_state.rb +393 -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 +60 -0
- data/lib/badline/c64/cartridge/retro_replay.rb +278 -0
- data/lib/badline/c64/cartridge/rex_utility.rb +31 -0
- data/lib/badline/c64/cartridge/rgcd.rb +50 -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 +40 -0
- data/lib/badline/c64/cartridge/westermann.rb +32 -0
- data/lib/badline/c64/cartridge/zaxxon.rb +52 -0
- data/lib/badline/c64/cartridge.rb +232 -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 +39 -36
- data/lib/badline/c64/keyed_modules.rb +111 -0
- data/lib/badline/c64/keyed_state.rb +68 -0
- data/lib/badline/c64/reu/dma.rb +271 -0
- data/lib/badline/c64/reu/keyed_state.rb +140 -0
- data/lib/badline/c64/reu/ram.rb +94 -0
- data/lib/badline/c64/reu/trigger.rb +34 -0
- data/lib/badline/c64/reu.rb +289 -0
- data/lib/badline/c64/true_drives.rb +120 -0
- data/lib/badline/{computer.rb → c64.rb} +24 -15
- data/lib/badline/chips/cia/fast_forward.rb +62 -0
- data/lib/badline/chips/cia/interrupt_register.rb +128 -0
- data/lib/badline/chips/cia/keyed_parts.rb +213 -0
- data/lib/badline/chips/cia/serial.rb +246 -0
- data/lib/badline/chips/cia/time_of_day.rb +210 -0
- data/lib/badline/chips/cia/timer.rb +188 -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 +183 -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/keyed_state.rb +177 -0
- data/lib/badline/chips/cpu/microcode.rb +195 -0
- data/lib/badline/chips/cpu/operations.rb +90 -0
- data/lib/badline/chips/cpu/port.rb +133 -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 +17 -0
- data/lib/badline/chips/sid/catch_up.rb +122 -0
- data/lib/badline/chips/sid/decimator.rb +68 -0
- data/lib/badline/chips/sid/envelope.rb +236 -0
- data/lib/badline/chips/sid/filter.rb +227 -0
- data/lib/badline/chips/sid/keyed_parts.rb +286 -0
- data/lib/badline/chips/sid/voice.rb +69 -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.rb +305 -0
- data/lib/badline/chips/sid.rb +264 -0
- data/lib/badline/chips/ted/beam.rb +119 -0
- data/lib/badline/chips/ted/timers.rb +66 -0
- data/lib/badline/chips/ted.rb +143 -0
- data/lib/badline/chips/tia.rb +49 -0
- data/lib/badline/chips/vdc/keyed_parts.rb +105 -0
- data/lib/badline/{c128 → chips}/vdc/memory.rb +1 -1
- data/lib/badline/{c128 → chips}/vdc/painter.rb +1 -13
- data/lib/badline/{c128 → chips}/vdc/raster.rb +1 -17
- data/lib/badline/{c128 → chips}/vdc/window.rb +1 -10
- data/lib/badline/{c128 → chips}/vdc.rb +6 -31
- data/lib/badline/chips/via/control_lines.rb +109 -0
- data/lib/badline/chips/via/fast_forward.rb +55 -0
- data/lib/badline/chips/via/interrupt_register.rb +60 -0
- data/lib/badline/chips/via/keyed_parts.rb +163 -0
- data/lib/badline/chips/via/shift_register.rb +168 -0
- data/lib/badline/chips/via/timer1.rb +120 -0
- data/lib/badline/chips/via/timer2.rb +117 -0
- data/lib/badline/chips/via.rb +267 -0
- data/lib/badline/chips/vic/bank.rb +135 -0
- data/lib/badline/chips/vic/border_mask.rb +78 -0
- data/lib/badline/chips/vic/collisions.rb +106 -0
- data/lib/badline/chips/vic/color_patches.rb +38 -0
- data/lib/badline/chips/vic/display_state.rb +168 -0
- data/lib/badline/chips/vic/graphics_mode.rb +166 -0
- data/lib/badline/chips/vic/graphics_shifter.rb +183 -0
- data/lib/badline/chips/vic/keyed_parts.rb +228 -0
- data/lib/badline/chips/vic/keyed_sprites.rb +225 -0
- data/lib/badline/chips/vic/keyed_state.rb +102 -0
- data/lib/badline/chips/vic/register_log.rb +65 -0
- data/lib/badline/chips/vic/registers.rb +188 -0
- data/lib/badline/chips/vic/sequencer.rb +275 -0
- data/lib/badline/chips/vic/sequencer_output.rb +118 -0
- data/lib/badline/chips/vic/sprite/internal_bus.rb +59 -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 +337 -0
- data/lib/badline/chips/vic/sprites.rb +281 -0
- data/lib/badline/chips/vic.rb +787 -0
- data/lib/badline/chips/vic_i/keyed_parts.rb +142 -0
- data/lib/badline/{vic20/vic → chips/vic_i}/painter.rb +2 -30
- data/lib/badline/chips/vic_i/sound/output.rb +85 -0
- data/lib/badline/chips/vic_i/sound.rb +227 -0
- data/lib/badline/{vic20/vic → chips/vic_i}/text_window.rb +2 -2
- data/lib/badline/{vic20/vic.rb → chips/vic_i.rb} +6 -6
- 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/keyed_state.rb +73 -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/shifts.rb +66 -0
- data/lib/badline/chips/z80.rb +13 -0
- data/lib/badline/chips.rb +10 -0
- data/lib/badline/core.rb +13 -32
- data/lib/badline/drives/datasette/keyed_state.rb +38 -0
- data/lib/badline/drives/datasette.rb +173 -0
- data/lib/badline/drives/engine/core.rb +152 -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 +72 -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 +75 -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.rb +318 -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/keyed_state.rb +251 -0
- data/lib/badline/drives/model1541/mechanism.rb +313 -0
- data/lib/badline/drives/model1541/rotation.rb +123 -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 +80 -0
- data/lib/badline/drives/model1571/bus.rb +100 -0
- data/lib/badline/drives/model1571/cpu.rb +13 -0
- data/lib/badline/drives/model1571/keyed_state.rb +108 -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 +108 -0
- data/lib/badline/drives/model1571.rb +141 -0
- data/lib/badline/drives/model1581/bus.rb +126 -0
- data/lib/badline/drives/model1581/cpu.rb +13 -0
- data/lib/badline/drives/model1581/disk.rb +133 -0
- data/lib/badline/drives/model1581/keyed_state.rb +280 -0
- data/lib/badline/drives/model1581/mechanism.rb +98 -0
- data/lib/badline/drives/model1581/serial_port.rb +54 -0
- data/lib/badline/drives/model1581/slot.rb +61 -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/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 +216 -0
- data/lib/badline/drives/model1581.rb +206 -0
- data/lib/badline/drives/serial_bus.rb +161 -0
- data/lib/badline/drives.rb +8 -0
- data/lib/badline/frontend/app.rb +3 -3
- data/lib/badline/frontend/boot.rb +4 -4
- data/lib/badline/frontend/controls.rb +19 -3
- data/lib/badline/frontend/drive_led.rb +44 -21
- data/lib/badline/frontend/machine_window.rb +3 -1
- data/lib/badline/frontend/menu/menu_dialogs.rb +2 -2
- 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/snapshots.rb +12 -1
- data/lib/badline/frontend/timeline.rb +30 -12
- 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/matrix_typist.rb +98 -0
- data/lib/badline/input.rb +4 -0
- data/lib/badline/kernal_trap/chrout.rb +45 -0
- data/lib/badline/kernal_trap/{drive → dos}/block_commands.rb +1 -1
- data/lib/badline/kernal_trap/dos/channel.rb +156 -0
- data/lib/badline/kernal_trap/{drive → dos}/channels.rb +1 -26
- data/lib/badline/kernal_trap/{drive → dos}/memory.rb +1 -10
- data/lib/badline/kernal_trap/{drive → dos}/parameters.rb +1 -1
- data/lib/badline/kernal_trap/{drive → dos}/status.rb +1 -9
- data/lib/badline/kernal_trap/{drive → dos}/write_file.rb +1 -19
- data/lib/badline/kernal_trap/{drive → dos}/writes.rb +1 -1
- data/lib/badline/kernal_trap/{drive.rb → dos.rb} +9 -27
- data/lib/badline/kernal_trap/file_routine.rb +4 -4
- data/lib/badline/kernal_trap/keyed_state.rb +150 -0
- data/lib/badline/kernal_trap/layout.rb +75 -11
- data/lib/badline/kernal_trap/load.rb +19 -21
- data/lib/badline/kernal_trap/routine.rb +12 -0
- data/lib/badline/kernal_trap/save.rb +12 -22
- data/lib/badline/kernal_trap/serial.rb +8 -24
- data/lib/badline/kernal_trap.rb +3 -2
- data/lib/badline/machine/clocking.rb +1 -1
- data/lib/badline/machine/keyboard_buffer.rb +49 -0
- data/lib/badline/machine/settling.rb +29 -0
- data/lib/badline/machine.rb +10 -7
- data/lib/badline/media/boot_disk.rb +14 -2
- data/lib/badline/media/extensions.rb +10 -0
- 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/memory.rb +3 -6
- data/lib/badline/model.rb +1 -1
- data/lib/badline/options/family.rb +5 -2
- data/lib/badline/options/help.rb +42 -16
- data/lib/badline/options/table.rb +2 -0
- data/lib/badline/options/validation.rb +2 -0
- data/lib/badline/options.rb +6 -1
- data/lib/badline/plus4/acia.rb +45 -0
- data/lib/badline/plus4/bus.rb +312 -0
- data/lib/badline/plus4/cpu.rb +10 -0
- data/lib/badline/plus4/cpu_port.rb +93 -0
- data/lib/badline/plus4/keyboard_port.rb +51 -0
- data/lib/badline/plus4/model.rb +38 -0
- data/lib/badline/plus4/user_port.rb +31 -0
- data/lib/badline/plus4.rb +164 -0
- data/lib/badline/roms/README +44 -6
- data/lib/badline/roms/plus4/basic.rom +0 -0
- data/lib/badline/roms/plus4/function-high.rom +0 -0
- data/lib/badline/roms/plus4/function-low.rom +0 -0
- data/lib/badline/roms/plus4/kernal-ntsc.rom +0 -0
- data/lib/badline/roms/plus4/kernal-pal.rom +0 -0
- 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 +32 -0
- data/lib/badline/snapshot/c64_setup.rb +83 -0
- data/lib/badline/snapshot/container.rb +4 -0
- data/lib/badline/snapshot/field_doc/markdown.rb +112 -0
- data/lib/badline/snapshot/field_doc.rb +109 -0
- data/lib/badline/snapshot/image.rb +132 -46
- data/lib/badline/snapshot/keyed/cursor.rb +40 -0
- data/lib/badline/snapshot/keyed/modules.rb +66 -0
- data/lib/badline/snapshot/keyed/reader.rb +188 -0
- data/lib/badline/snapshot/keyed/recorder.rb +88 -0
- data/lib/badline/snapshot/keyed/report.rb +26 -0
- data/lib/badline/snapshot/keyed/writer.rb +55 -0
- data/lib/badline/snapshot/keyed.rb +64 -0
- data/lib/badline/snapshot/machine_state.rb +17 -64
- data/lib/badline/snapshot/storage_setup.rb +63 -0
- data/lib/badline/snapshot/vic20_setup.rb +28 -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 +3 -3
- data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
- data/lib/badline/snapshot/vice.rb +13 -35
- data/lib/badline/snapshot.rb +44 -22
- data/lib/badline/storage/crt_file.rb +3 -1
- 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 +10 -5
- data/lib/badline/storage/host_directory.rb +0 -5
- data/lib/badline/storage/t64.rb +2 -8
- data/lib/badline/storage/tap.rb +43 -15
- 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 +8 -5
- data/lib/badline/vic20/bus/keyed_state.rb +52 -0
- data/lib/badline/vic20/bus.rb +2 -25
- data/lib/badline/vic20/cpu.rb +1 -1
- data/lib/badline/vic20/keyed_modules.rb +73 -0
- data/lib/badline/vic20/keyed_state.rb +45 -0
- data/lib/badline/vic20/port_wiring.rb +4 -4
- data/lib/badline/vic20/user_via_ports.rb +2 -2
- data/lib/badline/vic20.rb +22 -17
- data/lib/badline.rb +1 -0
- metadata +271 -228
- 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/c128/bus_state.rb +0 -53
- data/lib/badline/c128/saved_state.rb +0 -143
- 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/chrout_trap.rb +0 -43
- 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/attachments.rb +0 -88
- data/lib/badline/computer/saved_state.rb +0 -117
- data/lib/badline/computer/true_drives.rb +0 -69
- 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/debug_register.rb +0 -28
- 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/keyboard_buffer.rb +0 -33
- 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/snapshot/setup.rb +0 -75
- data/lib/badline/snapshot/state.rb +0 -189
- 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/saved_state.rb +0 -124
- data/lib/badline/vic20/sound/output.rb +0 -83
- data/lib/badline/vic20/sound.rb +0 -233
- data/lib/badline/vic20/vic/saved_state.rb +0 -55
- 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
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "badline/media/extensions"
|
|
4
|
-
|
|
5
|
-
module Badline
|
|
6
|
-
class Drive1541
|
|
7
|
-
class Disk
|
|
8
|
-
# Saving and restoring a Disk for a snapshot: the image by its path,
|
|
9
|
-
# and every half track as the head sees it, with those written since
|
|
10
|
-
# the last flush. The image itself is read again from its host file,
|
|
11
|
-
# where there still is one.
|
|
12
|
-
module State
|
|
13
|
-
# The image's path, expanded, and whether it was opened read-only,
|
|
14
|
-
# for a disk from Disk.open. Nil for a disk made another way.
|
|
15
|
-
attr_reader :path, :read_only
|
|
16
|
-
|
|
17
|
-
# Whether the image is a .g64 or .g71, by its name.
|
|
18
|
-
def self.g64?(path) = Media::Extensions.kind(path) == :gcr
|
|
19
|
-
|
|
20
|
-
# A disk for the image at the path (Disk.image_for), its tracks left
|
|
21
|
-
# for the state.
|
|
22
|
-
def self.reopen(path, read_only) = Disk.new(Disk.image_for(path, read_only)).opened(path, read_only)
|
|
23
|
-
|
|
24
|
-
# The disk a state from save_state describes: +current+ when it was
|
|
25
|
-
# opened from the same image the same way, and otherwise a disk for
|
|
26
|
-
# the image at the path the state names. Where no file is at that
|
|
27
|
-
# path, the disk has no image and is write-protected, and a
|
|
28
|
-
# detached reader always gets one without an image. Either way its
|
|
29
|
-
# tracks come from the state.
|
|
30
|
-
def self.load(input, current)
|
|
31
|
-
path = input.optional_string
|
|
32
|
-
read_only = input.boolean?
|
|
33
|
-
disk = current if current && !path.nil? && current.path == path && current.read_only == read_only
|
|
34
|
-
disk ||= fresh(path, read_only, input.detached?)
|
|
35
|
-
disk.load_tracks(input)
|
|
36
|
-
disk
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def self.fresh(path, read_only, detached)
|
|
40
|
-
return Disk.new if path.nil? || detached
|
|
41
|
-
return Disk.new.opened(path, true) unless File.file?(path)
|
|
42
|
-
|
|
43
|
-
reopen(path, read_only)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# Notes the image's path and how it was opened.
|
|
47
|
-
def opened(path, read_only)
|
|
48
|
-
@path = File.expand_path(path)
|
|
49
|
-
@read_only = read_only
|
|
50
|
-
self
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def save_state(out)
|
|
54
|
-
out.optional_string(@path).boolean(@read_only)
|
|
55
|
-
@tracks.each do |track|
|
|
56
|
-
out.boolean(!track.nil?)
|
|
57
|
-
save_track(track, out) if track
|
|
58
|
-
end
|
|
59
|
-
out.ints(@written.keys)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def load_tracks(input)
|
|
63
|
-
@tracks.each_index do |half_track|
|
|
64
|
-
@tracks[half_track] = input.boolean? ? load_track(input) : nil
|
|
65
|
-
end
|
|
66
|
-
@written.clear
|
|
67
|
-
input.ints.each { |half_track| @written[half_track] = true }
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
private
|
|
71
|
-
|
|
72
|
-
def save_track(track, out)
|
|
73
|
-
out.int(track.zone).boolean(!track.speeds.nil?)
|
|
74
|
-
out.ints(track.speeds) if track.speeds
|
|
75
|
-
out.blob(track.bytes)
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def load_track(input)
|
|
79
|
-
zone = input.int
|
|
80
|
-
speeds = input.boolean? ? input.ints : nil
|
|
81
|
-
Track.new(input.blob, zone, speeds)
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Badline
|
|
4
|
-
class Drive1541
|
|
5
|
-
# VIA 2, the one facing the disk mechanism. Its port B drives the
|
|
6
|
-
# Mechanism, and CB2 selects its read or write mode. The mechanism
|
|
7
|
-
# hears both after every write and reset, since ORB, DDRB, the ACR and
|
|
8
|
-
# the PCR can all change them.
|
|
9
|
-
class DiskVIA < VIA
|
|
10
|
-
attr_reader :mechanism
|
|
11
|
-
|
|
12
|
-
def initialize(start:, mechanism:)
|
|
13
|
-
@mechanism = mechanism
|
|
14
|
-
mechanism.via = self
|
|
15
|
-
super(start:, peripheral: mechanism)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def reset!
|
|
19
|
-
super
|
|
20
|
-
tell_mechanism
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def poke(addr, value)
|
|
24
|
-
super
|
|
25
|
-
tell_mechanism
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
private
|
|
29
|
-
|
|
30
|
-
def tell_mechanism
|
|
31
|
-
@mechanism.port_b_written(port_b_output)
|
|
32
|
-
@mechanism.cb2_written(cb2_output)
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Badline
|
|
4
|
-
class Drive1541
|
|
5
|
-
# Group code recording, the 1541's on-disk code. Each nibble becomes
|
|
6
|
-
# five bits, chosen so that no code has more than two 0 bits in a row
|
|
7
|
-
# and no run of codes has ten 1 bits in a row, which only a SYNC mark
|
|
8
|
-
# has. Four bytes become five.
|
|
9
|
-
module GCR
|
|
10
|
-
CODES = [0x0a, 0x0b, 0x12, 0x13, 0x0e, 0x0f, 0x16, 0x17,
|
|
11
|
-
0x09, 0x19, 0x1a, 0x1b, 0x0d, 0x1d, 0x1e, 0x15].freeze
|
|
12
|
-
|
|
13
|
-
# Five-bit code => nibble, nil for the codes that aren't GCR.
|
|
14
|
-
NIBBLES = Array.new(32) { |code| CODES.index(code) }.freeze
|
|
15
|
-
|
|
16
|
-
module_function
|
|
17
|
-
|
|
18
|
-
# Encodes a whole number of four-byte groups.
|
|
19
|
-
def encode(bytes)
|
|
20
|
-
out = []
|
|
21
|
-
i = 0
|
|
22
|
-
while i < bytes.length
|
|
23
|
-
bits = 0
|
|
24
|
-
4.times do |n|
|
|
25
|
-
byte = bytes[i + n]
|
|
26
|
-
bits = (bits << 10) | (CODES[byte >> 4] << 5) | CODES[byte & 0x0f]
|
|
27
|
-
end
|
|
28
|
-
4.downto(0) { |n| out << ((bits >> (n * 8)) & 0xff) }
|
|
29
|
-
i += 4
|
|
30
|
-
end
|
|
31
|
-
out
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
# Decodes a whole number of five-byte groups, nil when any code
|
|
35
|
-
# isn't GCR.
|
|
36
|
-
def decode(bytes)
|
|
37
|
-
out = []
|
|
38
|
-
i = 0
|
|
39
|
-
while i < bytes.length
|
|
40
|
-
bits = 0
|
|
41
|
-
5.times { |n| bits = (bits << 8) | bytes[i + n] }
|
|
42
|
-
n = 7
|
|
43
|
-
while n.positive?
|
|
44
|
-
high = NIBBLES[(bits >> (n * 5)) & 0x1f]
|
|
45
|
-
low = NIBBLES[(bits >> ((n - 1) * 5)) & 0x1f]
|
|
46
|
-
return nil if high.nil? || low.nil?
|
|
47
|
-
|
|
48
|
-
out << ((high << 4) | low)
|
|
49
|
-
n -= 2
|
|
50
|
-
end
|
|
51
|
-
i += 5
|
|
52
|
-
end
|
|
53
|
-
out
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
@@ -1,313 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "badline/drive1541/rotation"
|
|
4
|
-
require "badline/drive1541/mechanism_state"
|
|
5
|
-
require "badline/drive1541/byte_ready"
|
|
6
|
-
|
|
7
|
-
module Badline
|
|
8
|
-
class Drive1541
|
|
9
|
-
# The disk mechanism behind VIA 2: the spindle motor, the head on its
|
|
10
|
-
# stepper, the LED, the read and write electronics and the
|
|
11
|
-
# write-protect sensor.
|
|
12
|
-
#
|
|
13
|
-
# Port B drives it and reads it back:
|
|
14
|
-
#
|
|
15
|
-
# PB0-1 stepper phase (out) PB4 write protect (in, 1 = writable)
|
|
16
|
-
# PB2 motor on (out) PB5-6 bit rate, speed zone 0-3 (out)
|
|
17
|
-
# PB3 LED on (out) PB7 SYNC (in, 0 while in a SYNC mark)
|
|
18
|
-
#
|
|
19
|
-
# Port A reads the read shift register's low eight bits, which CA1
|
|
20
|
-
# latches on BYTE READY. In write mode it drives the write shift
|
|
21
|
-
# register, and the read shift register takes the bits written.
|
|
22
|
-
#
|
|
23
|
-
# The disk turns at 300 rpm under the head, and a read clock at the
|
|
24
|
-
# bit rate PB5-6 select clocks the bits off it (see Rotation).
|
|
25
|
-
#
|
|
26
|
-
# Ten 1 bits in a row are a SYNC mark while CB2 selects reading: PB7
|
|
27
|
-
# reads it, and it holds the bit counter at zero, so the first 0 bit
|
|
28
|
-
# after it starts a byte. Every eighth bit after that is BYTE READY,
|
|
29
|
-
# which pulls VIA 2's CA1 low until the next bit and reaches the CPU's
|
|
30
|
-
# SO pin (see byte_ready!).
|
|
31
|
-
#
|
|
32
|
-
# CB2 low selects write mode, where SYNC detection and the flux are
|
|
33
|
-
# off and the clock runs on at the selected rate. At each BYTE READY
|
|
34
|
-
# the write shift register loads what the VIA drives on port A, and
|
|
35
|
-
# the next eight clocks put that byte's bits on the track, most
|
|
36
|
-
# significant first, in place of what it held. While reading, the load
|
|
37
|
-
# takes the byte just read, so a switch to writing mid-byte writes the
|
|
38
|
-
# rest of it. A write lays its bits one to a cell from the cell under
|
|
39
|
-
# the head, so on a track written at the selected rate each bit fills
|
|
40
|
-
# the cell it passes over. A write to a half track without data gives
|
|
41
|
-
# it a blank track first, a turn long at the selected rate, and a
|
|
42
|
-
# write to a track written at another rate lays the whole track out
|
|
43
|
-
# again as a turn at the selected rate first (Track#relaid).
|
|
44
|
-
#
|
|
45
|
-
# PB4 reads the write-protect sensor: high with no disk in, or with
|
|
46
|
-
# the notch of a writable one open. With the disk write-protected the
|
|
47
|
-
# write gate stays shut: the bits and BYTE READY go on, and nothing
|
|
48
|
-
# reaches the disk. The DOS reads PB4 first and refuses to write, so
|
|
49
|
-
# only a program that writes without asking finds that out.
|
|
50
|
-
#
|
|
51
|
-
# The motor stopping flushes what was written to the disk's image
|
|
52
|
-
# (see Disk#flush), which is when the DOS is done with a job, and so
|
|
53
|
-
# does taking the disk out.
|
|
54
|
-
#
|
|
55
|
-
# The stepper moves the head a half track each time the phase steps
|
|
56
|
-
# by one, inwards for +1 and outwards for -1. Each half track has a
|
|
57
|
-
# phase of its own, from power-on the low two bits of its number, so
|
|
58
|
-
# the head sits on a whole track when phase 0 or 2 holds it. The
|
|
59
|
-
# stepper's coils are powered only while PB2 runs the motor, as VICE
|
|
60
|
-
# reads the 1541's schematic, so a phase set with the motor off moves
|
|
61
|
-
# nothing until the motor comes on and it pulls the head. Tracks run
|
|
62
|
-
# from half track 2 (track 1), where the head stops against the end of
|
|
63
|
-
# its rail, to Disk::MAX_HALF_TRACK. A step out against the stop slips:
|
|
64
|
-
# the head stays on track 1 and the phase that tried to pull it out
|
|
65
|
-
# becomes track 1's, so the DOS's bump leaves the head on track 1 in
|
|
66
|
-
# line with the phase it ends on, and its first step in reaches the
|
|
67
|
-
# half track after it.
|
|
68
|
-
#
|
|
69
|
-
# The 1571's stepper is lined up so that phase 0 holds track 1, where
|
|
70
|
-
# its track 0 sensor looks for the head (Mechanism.new's +slip+).
|
|
71
|
-
class Mechanism
|
|
72
|
-
include Rotation
|
|
73
|
-
include MechanismState
|
|
74
|
-
include ByteReady
|
|
75
|
-
|
|
76
|
-
MOTOR = 0x04
|
|
77
|
-
LED = 0x08
|
|
78
|
-
WRITE_PROTECT = 0x10
|
|
79
|
-
SYNC = 0x80
|
|
80
|
-
|
|
81
|
-
MIN_HALF_TRACK = 2
|
|
82
|
-
# Where the head sits at power-on: track 18, the directory.
|
|
83
|
-
START_HALF_TRACK = 36
|
|
84
|
-
|
|
85
|
-
SYNC_BITS = 10
|
|
86
|
-
|
|
87
|
-
attr_reader :disk, :half_track, :zone
|
|
88
|
-
|
|
89
|
-
# +slip+ is the stepper's phase offset at power-on: 0, where each half
|
|
90
|
-
# track's phase is the low two bits of its number, or 2 for track 1
|
|
91
|
-
# on phase 0.
|
|
92
|
-
def initialize(slip: 0)
|
|
93
|
-
@via = nil
|
|
94
|
-
@so_pending = false
|
|
95
|
-
@disk = nil
|
|
96
|
-
@half_track = START_HALF_TRACK
|
|
97
|
-
@slip = slip
|
|
98
|
-
@motor = false
|
|
99
|
-
@led = false
|
|
100
|
-
@zone = 0
|
|
101
|
-
@clock = Track.cell(0)
|
|
102
|
-
@time = 0
|
|
103
|
-
@clock_at = @clock / 2
|
|
104
|
-
@clocks = 0
|
|
105
|
-
@shift = 0
|
|
106
|
-
@ones = 0
|
|
107
|
-
@bits = 0
|
|
108
|
-
@sync = false
|
|
109
|
-
@byte_ready = false
|
|
110
|
-
@byte_latched = false
|
|
111
|
-
@writing = false
|
|
112
|
-
@write_shift = 0
|
|
113
|
-
@write_gate = false
|
|
114
|
-
@protected = false
|
|
115
|
-
@side_base = 0
|
|
116
|
-
@cycle_ticks = CYCLE
|
|
117
|
-
load_track
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
# The drive's clock rate: the disk turns on by fewer ticks each
|
|
121
|
-
# cycle at 2 MHz.
|
|
122
|
-
def clock_hz=(clock_hz)
|
|
123
|
-
@cycle_ticks = CYCLE * Drive1541::CLOCK_HZ / clock_hz
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
# The head that reads, 0 or 1, on a drive with two (Disk::SIDE).
|
|
127
|
-
def side = @side_base.zero? ? 0 : 1
|
|
128
|
-
|
|
129
|
-
def side=(side)
|
|
130
|
-
side_base = side * Disk::SIDE
|
|
131
|
-
return if side_base == @side_base
|
|
132
|
-
|
|
133
|
-
@side_base = side_base
|
|
134
|
-
load_track
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def motor_on? = @motor
|
|
138
|
-
|
|
139
|
-
def led_on? = @led
|
|
140
|
-
|
|
141
|
-
def sync? = @sync
|
|
142
|
-
|
|
143
|
-
def writing? = @writing
|
|
144
|
-
|
|
145
|
-
# What port B and CB2 can change with the motor off: the motor, the
|
|
146
|
-
# LED, the zone and the clock's rate, the stepper, write mode and
|
|
147
|
-
# where a write starts, and the track and cell under the head. The
|
|
148
|
-
# rest moves only while the motor turns, or as a disk goes in (see
|
|
149
|
-
# Drive::Idle).
|
|
150
|
-
def idle_state
|
|
151
|
-
[@motor, @led, @zone, @clock, @half_track, @slip, @side_base, @disk, @track, @index, @mask, @cell_end,
|
|
152
|
-
@time, @writing, @write_index, @sync, @byte_latched]
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
# Puts a Disk in, or takes it out with nil, flushing the disk that
|
|
156
|
-
# was in. The head goes on from the same point in the turn.
|
|
157
|
-
def insert(disk)
|
|
158
|
-
flush
|
|
159
|
-
@disk = disk
|
|
160
|
-
@protected = disk&.write_protected? || false
|
|
161
|
-
@write_gate = !disk.nil? && !@protected
|
|
162
|
-
load_track
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
# Stores what the head wrote in the disk's image.
|
|
166
|
-
def flush
|
|
167
|
-
@disk.flush if @disk&.written?
|
|
168
|
-
rescue Storage::WriteError => e
|
|
169
|
-
warn "1541: couldn't write the disk back: #{e.message}"
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
# VIA 2 drives CB2 to +high+: low selects write mode, which stops
|
|
173
|
-
# SYNC detection at once.
|
|
174
|
-
def cb2_written(high)
|
|
175
|
-
@write_index = nil if high || !@writing
|
|
176
|
-
@writing = !high
|
|
177
|
-
@sync = !@writing && @ones >= SYNC_BITS
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
# VIA 2 drives port B's lines to +lines+.
|
|
181
|
-
def port_b_written(lines)
|
|
182
|
-
motor = @motor
|
|
183
|
-
@motor = lines.anybits?(MOTOR)
|
|
184
|
-
flush if motor && !@motor
|
|
185
|
-
@led = lines.anybits?(LED)
|
|
186
|
-
zone = (lines >> 5) & 0x03
|
|
187
|
-
if zone != @zone
|
|
188
|
-
@zone = zone
|
|
189
|
-
@clock = Track.cell(zone)
|
|
190
|
-
@track_written = false
|
|
191
|
-
end
|
|
192
|
-
step(lines & 0x03) if @motor
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
# Port A is the read shift register.
|
|
196
|
-
def read_a(_lines) = @shift & 0xff
|
|
197
|
-
|
|
198
|
-
# SYNC low in a SYNC mark, and write protect low for a protected
|
|
199
|
-
# disk.
|
|
200
|
-
def read_b(_lines)
|
|
201
|
-
lines = @sync ? 0xff & ~SYNC : 0xff
|
|
202
|
-
@protected ? lines & ~WRITE_PROTECT : lines
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
private
|
|
206
|
-
|
|
207
|
-
def read_bit(one)
|
|
208
|
-
if @byte_ready
|
|
209
|
-
@byte_ready = false
|
|
210
|
-
byte_ready_ended!
|
|
211
|
-
end
|
|
212
|
-
@shift = ((@shift << 1) & 0x3fe) | (one ? 1 : 0)
|
|
213
|
-
if one
|
|
214
|
-
@ones += 1
|
|
215
|
-
@sync = true if @ones >= SYNC_BITS
|
|
216
|
-
else
|
|
217
|
-
@ones = 0
|
|
218
|
-
@sync = false
|
|
219
|
-
end
|
|
220
|
-
count_bit
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
# The write shift register's top bit goes onto the track through the
|
|
224
|
-
# write gate, and into the read shift register, as the head's own
|
|
225
|
-
# signal.
|
|
226
|
-
def write_bit(at)
|
|
227
|
-
if @byte_ready
|
|
228
|
-
@byte_ready = false
|
|
229
|
-
byte_ready_ended!
|
|
230
|
-
end
|
|
231
|
-
one = @write_shift.anybits?(0x80)
|
|
232
|
-
@write_shift = (@write_shift << 1) & 0xff
|
|
233
|
-
store_bit(one, at) if @write_gate
|
|
234
|
-
@shift = ((@shift << 1) & 0x3fe) | (one ? 1 : 0)
|
|
235
|
-
@ones = one ? @ones + 1 : 0
|
|
236
|
-
count_bit
|
|
237
|
-
end
|
|
238
|
-
|
|
239
|
-
# Each bit written goes in the cell after the last one's, from the
|
|
240
|
-
# cell under the head when the write started.
|
|
241
|
-
def store_bit(one, at)
|
|
242
|
-
track_written(at) unless @track_written
|
|
243
|
-
@write_index ||= (@index * 8) + 8 - @mask.bit_length
|
|
244
|
-
index = @write_index >> 3
|
|
245
|
-
mask = 0x80 >> (@write_index & 7)
|
|
246
|
-
if one
|
|
247
|
-
@bytes[index] |= mask
|
|
248
|
-
else
|
|
249
|
-
@bytes[index] &= ~mask
|
|
250
|
-
end
|
|
251
|
-
@write_index += 1
|
|
252
|
-
@write_index = 0 if @write_index == @length * 8
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
# The first write to the track since the head came to it or the rate
|
|
256
|
-
# changed: a half track without data gets a blank track, and a track
|
|
257
|
-
# written at another rate is laid out again at this one.
|
|
258
|
-
def track_written(at)
|
|
259
|
-
surface = self.surface
|
|
260
|
-
track = @disk.writable_track(surface, @zone)
|
|
261
|
-
@disk.write(surface, track.relaid(@zone)) unless track.written_at?(@zone)
|
|
262
|
-
load_track(at)
|
|
263
|
-
@disk.written(surface)
|
|
264
|
-
@track_written = true
|
|
265
|
-
end
|
|
266
|
-
|
|
267
|
-
# Every eighth bit outside a SYNC mark is BYTE READY, which loads the
|
|
268
|
-
# write shift register: from what the VIA drives on port A in write
|
|
269
|
-
# mode, and with the byte just read otherwise.
|
|
270
|
-
def count_bit
|
|
271
|
-
if @sync
|
|
272
|
-
@bits = 0
|
|
273
|
-
return
|
|
274
|
-
end
|
|
275
|
-
@bits += 1
|
|
276
|
-
return unless @bits == 8
|
|
277
|
-
|
|
278
|
-
@bits = 0
|
|
279
|
-
@write_shift = @writing ? @via.port_a_output : @shift & 0xff
|
|
280
|
-
@byte_ready = true
|
|
281
|
-
byte_ready!
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
# The stepper's rotor turns with the head, a phase to each half
|
|
285
|
-
# track, so the energized phase pulls the head to the neighbouring
|
|
286
|
-
# half track it belongs to. A phase two away pulls both ways, and the
|
|
287
|
-
# head stays. Against the stop at track 1 the head can't follow, and
|
|
288
|
-
# the phases slip round to where the head is.
|
|
289
|
-
def step(phase)
|
|
290
|
-
move = (phase - @half_track - @slip) & 0x03
|
|
291
|
-
if move == 1
|
|
292
|
-
seek(@half_track + 1)
|
|
293
|
-
elsif move == 3 && @half_track == MIN_HALF_TRACK
|
|
294
|
-
@slip = (phase - MIN_HALF_TRACK) & 0x03
|
|
295
|
-
elsif move == 3
|
|
296
|
-
seek(@half_track - 1)
|
|
297
|
-
end
|
|
298
|
-
end
|
|
299
|
-
|
|
300
|
-
# The half track under the head that reads, numbered on the disk
|
|
301
|
-
# (see Disk::SIDE).
|
|
302
|
-
def surface = @half_track + @side_base
|
|
303
|
-
|
|
304
|
-
def seek(half_track)
|
|
305
|
-
half_track = half_track.clamp(MIN_HALF_TRACK, Disk::MAX_HALF_TRACK)
|
|
306
|
-
return if half_track == @half_track
|
|
307
|
-
|
|
308
|
-
@half_track = half_track
|
|
309
|
-
load_track
|
|
310
|
-
end
|
|
311
|
-
end
|
|
312
|
-
end
|
|
313
|
-
end
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Badline
|
|
4
|
-
class Drive1541
|
|
5
|
-
# Saving and restoring the Mechanism for a snapshot.
|
|
6
|
-
module MechanismState
|
|
7
|
-
# The disk (Disk#save_state) and everything the head, the motor, the
|
|
8
|
-
# stepper and the read and write electronics hold, down to the cell
|
|
9
|
-
# under the head and the read clock's phase.
|
|
10
|
-
def save_state(out)
|
|
11
|
-
out.boolean(!@disk.nil?)
|
|
12
|
-
@disk&.save_state(out)
|
|
13
|
-
[@half_track, @slip, @side_base, @zone, @clock, @time, @clock_at, @clocks, @shift, @ones, @bits, @write_shift,
|
|
14
|
-
@index, @mask, @cell_end, @width, @next].each { |value| out.int(value) }
|
|
15
|
-
[@motor, @led, @sync, @byte_ready, @byte_latched, @writing, @write_gate, @protected,
|
|
16
|
-
@track_written].each { |flag| out.boolean(flag) }
|
|
17
|
-
out.optional_int(@write_index)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# Puts the state back, reusing the disk in when it's the one the state
|
|
21
|
-
# names (Disk::State.load). A disk taken out is flushed, as insert
|
|
22
|
-
# does.
|
|
23
|
-
def load_state(input)
|
|
24
|
-
disk = input.boolean? ? Disk::State.load(input, @disk) : nil
|
|
25
|
-
flush unless disk.equal?(@disk)
|
|
26
|
-
@disk = disk
|
|
27
|
-
load_head(input)
|
|
28
|
-
load_flags(input)
|
|
29
|
-
@write_index = input.optional_int
|
|
30
|
-
head_on_track
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
private
|
|
34
|
-
|
|
35
|
-
def load_head(input)
|
|
36
|
-
@half_track = input.int
|
|
37
|
-
@slip = input.int
|
|
38
|
-
@side_base = input.int
|
|
39
|
-
@zone = input.int
|
|
40
|
-
@clock = input.int
|
|
41
|
-
@time = input.int
|
|
42
|
-
@clock_at = input.int
|
|
43
|
-
@clocks = input.int
|
|
44
|
-
@shift = input.int
|
|
45
|
-
@ones = input.int
|
|
46
|
-
@bits = input.int
|
|
47
|
-
@write_shift = input.int
|
|
48
|
-
@index = input.int
|
|
49
|
-
@mask = input.int
|
|
50
|
-
@cell_end = input.int
|
|
51
|
-
@width = input.int
|
|
52
|
-
@next = input.int
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def load_flags(input)
|
|
56
|
-
@motor = input.boolean?
|
|
57
|
-
@led = input.boolean?
|
|
58
|
-
@sync = input.boolean?
|
|
59
|
-
@byte_ready = input.boolean?
|
|
60
|
-
@byte_latched = input.boolean?
|
|
61
|
-
@writing = input.boolean?
|
|
62
|
-
@write_gate = input.boolean?
|
|
63
|
-
@protected = input.boolean?
|
|
64
|
-
@track_written = input.boolean?
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Badline
|
|
4
|
-
class Drive1541
|
|
5
|
-
# The disk turning under the Mechanism's head, and its read clock.
|
|
6
|
-
#
|
|
7
|
-
# The disk turns at 300 rpm, whatever the bit rate: once in 200 ms, or
|
|
8
|
-
# 200,000 drive cycles. Each track's bits pass under the head at the
|
|
9
|
-
# rate they were written at (see Track), and a 1 bit is a flux
|
|
10
|
-
# transition at the start of its cell.
|
|
11
|
-
#
|
|
12
|
-
# The read circuit clocks bits out at the rate PB5-6 select, from a
|
|
13
|
-
# counter the 16 MHz crystal steps every 16 - zone ticks. A flux
|
|
14
|
-
# transition clears the counter. The counter clocks a bit into the
|
|
15
|
-
# read shift register as it reaches 2 and every four steps after
|
|
16
|
-
# that, and the bit is a 1 only for the first clock after the counter
|
|
17
|
-
# passed 0. A bit is 4 * (16 - zone) ticks, so a byte takes 32, 30, 28
|
|
18
|
-
# or 26 drive cycles in zones 0 to 3, and each transition brings the
|
|
19
|
-
# clock back into step with the flux. A track read at the rate it was
|
|
20
|
-
# written reads its bits. At another rate the clock and the cells
|
|
21
|
-
# drift apart between transitions: a faster clock slips an extra 0
|
|
22
|
-
# bit into some runs of 0 bits, a slower one drops one from some, and
|
|
23
|
-
# the bytes come out garbled. Without flux the counter runs round on
|
|
24
|
-
# its own and reads a 1 bit in every four.
|
|
25
|
-
module Rotation
|
|
26
|
-
CYCLE = 16 * Track::TICK
|
|
27
|
-
|
|
28
|
-
# What the head reads with no disk in, or off the tracks a disk has:
|
|
29
|
-
# no flux.
|
|
30
|
-
BLANK = Track.new(Array.new(Disk::TRACK_LENGTHS[0], 0).freeze, 0)
|
|
31
|
-
|
|
32
|
-
# One drive cycle: nothing with the motor off, and otherwise the
|
|
33
|
-
# disk turns on by a cycle's ticks, 16 at 1 MHz and 8 at 2 MHz,
|
|
34
|
-
# through whatever cells and clocks fall in them.
|
|
35
|
-
def cycle!
|
|
36
|
-
return unless @motor
|
|
37
|
-
|
|
38
|
-
@time += @cycle_ticks
|
|
39
|
-
pass_time if @time >= @next
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
private
|
|
43
|
-
|
|
44
|
-
# The cell edges and clocks up to now, in the order they come. A
|
|
45
|
-
# clock that falls on a cell edge comes after it.
|
|
46
|
-
def pass_time
|
|
47
|
-
while @cell_end <= @time || @clock_at <= @time
|
|
48
|
-
if @cell_end <= @clock_at
|
|
49
|
-
next_cell
|
|
50
|
-
else
|
|
51
|
-
clock
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
@next = [@cell_end, @clock_at].min
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# The head comes to the next cell, and a 1 bit's flux clears the
|
|
58
|
-
# read clock while reading.
|
|
59
|
-
def next_cell
|
|
60
|
-
start = @cell_end
|
|
61
|
-
@mask >>= 1
|
|
62
|
-
start = next_byte(start) if @mask.zero?
|
|
63
|
-
@cell_end = @index == @last && @mask == 1 ? Track::TURN : start + @width
|
|
64
|
-
return if @writing || @bytes[@index].nobits?(@mask)
|
|
65
|
-
|
|
66
|
-
@clock_at = start + (@clock / 2)
|
|
67
|
-
@clocks = 0
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
# The head comes to the next byte, and at the end of the track back
|
|
71
|
-
# round to the first, where the turn starts over.
|
|
72
|
-
def next_byte(start)
|
|
73
|
-
@mask = 0x80
|
|
74
|
-
@index += 1
|
|
75
|
-
if @index == @length
|
|
76
|
-
@index = 0
|
|
77
|
-
@time -= Track::TURN
|
|
78
|
-
@clock_at -= Track::TURN
|
|
79
|
-
start = 0
|
|
80
|
-
end
|
|
81
|
-
@width = @widths[@index] if @widths
|
|
82
|
-
start
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# The read clock ticks a bit into the shift register: a 1 the first
|
|
86
|
-
# time after a flux transition or the counter's wrap.
|
|
87
|
-
def clock
|
|
88
|
-
at = @clock_at
|
|
89
|
-
one = @clocks.zero?
|
|
90
|
-
@clocks = (@clocks + 1) & 3
|
|
91
|
-
@clock_at = at + @clock
|
|
92
|
-
@writing ? write_bit(at) : read_bit(one)
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
# The track under the head and its layout, leaving the head's place
|
|
96
|
-
# on it as it stands.
|
|
97
|
-
def head_on_track
|
|
98
|
-
@track = @disk&.track(surface) || BLANK
|
|
99
|
-
@bytes = @track.bytes
|
|
100
|
-
@widths = @track.widths
|
|
101
|
-
@length = @track.length
|
|
102
|
-
@last = @length - 1
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
# The track under the head, from the cell that's under it +time+
|
|
106
|
-
# into the turn.
|
|
107
|
-
def load_track(time = @time)
|
|
108
|
-
@track = @disk&.track(surface) || BLANK
|
|
109
|
-
@bytes = @track.bytes
|
|
110
|
-
@widths = @track.widths
|
|
111
|
-
@length = @track.length
|
|
112
|
-
@last = @length - 1
|
|
113
|
-
@index, @mask, @cell_end = @track.cell_at(time)
|
|
114
|
-
@width = @widths ? @widths[@index] : @track.width
|
|
115
|
-
@write_index = nil
|
|
116
|
-
@track_written = false
|
|
117
|
-
@next = [@cell_end, @clock_at].min
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
end
|