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
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "badline/media/extensions"
|
|
4
|
+
require "badline/drives/model1541/sector_reader"
|
|
5
|
+
|
|
6
|
+
module Badline
|
|
7
|
+
module Drives
|
|
8
|
+
class Model1541
|
|
9
|
+
# A disk as the head sees it: a Track for each half track that holds
|
|
10
|
+
# data, numbered from 2 (track 1) to MAX_HALF_TRACK (track 42), and
|
|
11
|
+
# nothing between them. A .d64 image fills the whole tracks; a .g64
|
|
12
|
+
# can fill any of them, with tracks of any length.
|
|
13
|
+
#
|
|
14
|
+
# The disk has a second side, for the 1571's second head, its half
|
|
15
|
+
# tracks numbered from SIDE on. A .d71 fills both sides, its tracks
|
|
16
|
+
# 36-70 being tracks 1-35 of the second, and a .g71 holds 84 half
|
|
17
|
+
# tracks a side. A 1541 reads the first side only.
|
|
18
|
+
#
|
|
19
|
+
# The head writes into the tracks' bytes, and a write to a half track
|
|
20
|
+
# without data gives it a blank Track first. A disk made from an image
|
|
21
|
+
# remembers it: flush reads the sectors back off the tracks written
|
|
22
|
+
# since the last flush and stores them in the image, which writes its
|
|
23
|
+
# host file. The disk is write-protected when the image won't take
|
|
24
|
+
# writes.
|
|
25
|
+
class Disk
|
|
26
|
+
# Whether the image is a .g64 or .g71, by its name.
|
|
27
|
+
def self.g64?(path) = Media::Extensions.kind(path) == :gcr
|
|
28
|
+
|
|
29
|
+
MAX_HALF_TRACK = 84
|
|
30
|
+
|
|
31
|
+
# Where the second side's half tracks start: its track 1 is SIDE + 2.
|
|
32
|
+
SIDE = MAX_HALF_TRACK + 1
|
|
33
|
+
|
|
34
|
+
# The tracks a side of a .d71 holds.
|
|
35
|
+
D71_SIDE_TRACKS = 35
|
|
36
|
+
|
|
37
|
+
# The half track entries a side of a .g71 holds.
|
|
38
|
+
G71_SIDE_ENTRIES = 84
|
|
39
|
+
|
|
40
|
+
# GCR bytes around a track in each speed zone (Storage::D64Image.zone):
|
|
41
|
+
# 200 ms of rotation at 300 rpm, in bytes of 32, 30, 28 and 26 µs.
|
|
42
|
+
TRACK_LENGTHS = [6250, 6666, 7142, 7692].freeze
|
|
43
|
+
|
|
44
|
+
# How far round the DOS's N: starts each track from the one before,
|
|
45
|
+
# in each zone, in 1/10000 of a turn: it steps in and starts writing
|
|
46
|
+
# the next track that long after it started the last.
|
|
47
|
+
SKEWS = [2916, 897, 8915, 6869].freeze
|
|
48
|
+
SKEW_TURN = 10_000
|
|
49
|
+
|
|
50
|
+
SYNC_LENGTH = 5
|
|
51
|
+
HEADER_GAP = 9
|
|
52
|
+
GAP = 0x55
|
|
53
|
+
HEADER_ID = 0x08
|
|
54
|
+
DATA_ID = 0x07
|
|
55
|
+
|
|
56
|
+
# A sector: SYNC, the 10-byte GCR header, the header gap, SYNC and
|
|
57
|
+
# the 325-byte GCR data block. The gap after it takes up the rest.
|
|
58
|
+
SECTOR_LENGTH = SYNC_LENGTH + 10 + HEADER_GAP + SYNC_LENGTH + 325
|
|
59
|
+
|
|
60
|
+
# A disk from the image at +path+: a .g64 or .g71 as its tracks are,
|
|
61
|
+
# a .d71 formatted on both sides, and anything else as a .d64,
|
|
62
|
+
# formatted. `read_only` opens the image write-protected.
|
|
63
|
+
def self.open(path, read_only: false)
|
|
64
|
+
image = image_for(path, read_only)
|
|
65
|
+
(Disk.g64?(path) ? from_g64(image) : from_d64(image)).opened(path, read_only)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# The image at +path+, by its name: a .g64 or .g71, a .d71, and
|
|
69
|
+
# anything else a .d64. `bytes` stands in for the file's contents.
|
|
70
|
+
def self.image_for(path, read_only, bytes = nil)
|
|
71
|
+
return Storage::G64Image.new(path, read_only:, bytes:) if Disk.g64?(path)
|
|
72
|
+
return Storage::D71Image.new(path, read_only:, bytes:) if File.extname(path).casecmp?(".d71")
|
|
73
|
+
|
|
74
|
+
Storage::D64Image.new(path, read_only:, bytes:)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# A disk from a G64 or G71 image, each half track as the image stores
|
|
78
|
+
# it, with its speed map. Flushing it writes the tracks back as they
|
|
79
|
+
# are.
|
|
80
|
+
def self.from_g64(image)
|
|
81
|
+
disk = new(image)
|
|
82
|
+
image.half_tracks.times do |entry|
|
|
83
|
+
track = image.track(entry)
|
|
84
|
+
disk.write(half_track_of(entry), Track.new(*track, image.speeds(entry))) if track
|
|
85
|
+
end
|
|
86
|
+
disk
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# The half track a G64 or G71 table entry holds: entry 0 is track 1,
|
|
90
|
+
# and a .g71's entries from G71_SIDE_ENTRIES on are the second
|
|
91
|
+
# side's.
|
|
92
|
+
def self.half_track_of(entry)
|
|
93
|
+
side = entry / G71_SIDE_ENTRIES
|
|
94
|
+
(side * SIDE) + (entry % G71_SIDE_ENTRIES) + Mechanism::MIN_HALF_TRACK
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# The table entry of a half track, or nil for one a G64 or G71 has
|
|
98
|
+
# no entry for.
|
|
99
|
+
def self.entry_of(half_track)
|
|
100
|
+
side = half_track / SIDE
|
|
101
|
+
entry = (half_track % SIDE) - Mechanism::MIN_HALF_TRACK
|
|
102
|
+
(side * G71_SIDE_ENTRIES) + entry if entry.between?(0, G71_SIDE_ENTRIES - 1)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# The half track an image's track number is on: a .d71's tracks past
|
|
106
|
+
# D71_SIDE_TRACKS are on the second side.
|
|
107
|
+
def self.d64_half_track(image, track)
|
|
108
|
+
return track * 2 unless image.sides == 2 && track > D71_SIDE_TRACKS
|
|
109
|
+
|
|
110
|
+
SIDE + ((track - D71_SIDE_TRACKS) * 2)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# The image's track number a half track holds, or nil for a half
|
|
114
|
+
# track or one past the image's last.
|
|
115
|
+
def self.d64_track(image, half_track)
|
|
116
|
+
side = half_track / SIDE
|
|
117
|
+
return unless (half_track % SIDE).even?
|
|
118
|
+
|
|
119
|
+
track = (half_track % SIDE) / 2
|
|
120
|
+
track += D71_SIDE_TRACKS if side == 1
|
|
121
|
+
track if track.positive? && track <= image.track_count && side < image.sides
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# A disk formatted from a D64 image, each sector laid out as the DOS
|
|
125
|
+
# formats it, with the disk ID from the header block. A block the
|
|
126
|
+
# image's error table marks 20, 21, 22, 23, 27 or 29 is written the
|
|
127
|
+
# way that DOS error would read. The table's other codes, 24, 25, 26
|
|
128
|
+
# and 28, describe write or decoding faults the layout can't carry,
|
|
129
|
+
# so their blocks are written good and read without an error.
|
|
130
|
+
#
|
|
131
|
+
# Each track starts sector 0 at the angle the DOS's N: leaves it: track
|
|
132
|
+
# 1 at the index angle, and each track after it SKEWS[zone] of a turn
|
|
133
|
+
# round from the last. A .d71's second side starts over at the index
|
|
134
|
+
# angle.
|
|
135
|
+
def self.from_d64(image)
|
|
136
|
+
track, sector = image.header_block
|
|
137
|
+
header = image.read_block(track, sector)
|
|
138
|
+
id = [header[0xa2], header[0xa3]]
|
|
139
|
+
disk = new(image)
|
|
140
|
+
angle = 0
|
|
141
|
+
(1..image.track_count).each do |track|
|
|
142
|
+
half_track = d64_half_track(image, track)
|
|
143
|
+
zone = Storage::D64Image.zone((half_track % SIDE) / 2)
|
|
144
|
+
angle = half_track == SIDE + 2 ? 0 : (angle + SKEWS[zone]) % SKEW_TURN if track > 1
|
|
145
|
+
bytes = format_track(image, track, id, zone)
|
|
146
|
+
disk.write(half_track, Track.new(bytes.rotate(-(bytes.length * angle / SKEW_TURN)), zone))
|
|
147
|
+
end
|
|
148
|
+
disk
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def self.format_track(image, track, id, zone = Storage::D64Image.zone(track))
|
|
152
|
+
sectors = image.sectors_in(track)
|
|
153
|
+
length = TRACK_LENGTHS[zone]
|
|
154
|
+
gap = (length - (sectors * SECTOR_LENGTH)) / sectors
|
|
155
|
+
bytes = []
|
|
156
|
+
sectors.times do |sector|
|
|
157
|
+
format_sector(bytes, image, track, sector, id)
|
|
158
|
+
gap.times { bytes << GAP }
|
|
159
|
+
end
|
|
160
|
+
bytes << GAP while bytes.length < length
|
|
161
|
+
bytes
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Error 21 leaves the block without SYNC marks, and 29 writes its
|
|
165
|
+
# header with the wrong first ID byte.
|
|
166
|
+
def self.format_sector(bytes, image, track, sector, id)
|
|
167
|
+
error = image.block_error(track, sector)
|
|
168
|
+
sync = error == 21 ? GAP : 0xff
|
|
169
|
+
id = [id[0] ^ 0xff, id[1]] if error == 29
|
|
170
|
+
SYNC_LENGTH.times { bytes << sync }
|
|
171
|
+
bytes.concat(GCR.encode(header(track, sector, id, error)))
|
|
172
|
+
HEADER_GAP.times { bytes << GAP }
|
|
173
|
+
SYNC_LENGTH.times { bytes << sync }
|
|
174
|
+
bytes.concat(GCR.encode(data_block(image.read_block(track, sector), error)))
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# ID, checksum, sector, track, the second ID byte, the first and two
|
|
178
|
+
# $0F fillers. Error 20 hides the block's ID and 27 spoils its
|
|
179
|
+
# checksum.
|
|
180
|
+
def self.header(track, sector, id, error)
|
|
181
|
+
checksum = sector ^ track ^ id[1] ^ id[0]
|
|
182
|
+
checksum ^= 0xff if error == 27
|
|
183
|
+
[error == 20 ? 0x00 : HEADER_ID, checksum, sector, track, id[1], id[0], 0x0f, 0x0f]
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# ID, 256 data bytes, their checksum and two $00 fillers. Error 22
|
|
187
|
+
# hides the block's ID and 23 spoils its checksum.
|
|
188
|
+
def self.data_block(data, error)
|
|
189
|
+
checksum = 0
|
|
190
|
+
data.each { |byte| checksum ^= byte }
|
|
191
|
+
checksum ^= 0xff if error == 23
|
|
192
|
+
block = [error == 22 ? 0x00 : DATA_ID]
|
|
193
|
+
block.concat(data)
|
|
194
|
+
block << checksum << 0x00 << 0x00
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
attr_reader :image
|
|
198
|
+
|
|
199
|
+
def initialize(image = nil)
|
|
200
|
+
@image = image
|
|
201
|
+
@tracks = Array.new(SIDE * 2)
|
|
202
|
+
@written = {}
|
|
203
|
+
@path = nil
|
|
204
|
+
@read_only = false
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# The Track at the half track, or nil where there's no data.
|
|
208
|
+
def track(half_track) = @tracks[half_track]
|
|
209
|
+
|
|
210
|
+
def write(half_track, track)
|
|
211
|
+
@tracks[half_track] = track
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Whether the write-protect notch is covered: the disk's image won't
|
|
215
|
+
# take writes, or a disk without an image was opened read-only. A
|
|
216
|
+
# disk without an image keeps what it takes only in its tracks.
|
|
217
|
+
def write_protected? = @image.nil? ? @read_only : !@image.writable?
|
|
218
|
+
|
|
219
|
+
# A half track the head writes to, blank to begin with: no flux, and
|
|
220
|
+
# as many bytes as a turn holds at the bit rate of the +zone+ it's
|
|
221
|
+
# written in.
|
|
222
|
+
def writable_track(half_track, zone)
|
|
223
|
+
@tracks[half_track] ||= Track.new(Array.new(TRACK_LENGTHS[zone], 0), zone)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# The head wrote to the half track.
|
|
227
|
+
def written(half_track)
|
|
228
|
+
@written[half_track] = true
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Whether any track was written since the last flush.
|
|
232
|
+
def written? = !@written.empty?
|
|
233
|
+
|
|
234
|
+
# Stores each track written since the last flush in the image, all
|
|
235
|
+
# in one write to its host file. A G64 image takes the tracks as they
|
|
236
|
+
# are. A D64 image takes the sectors read back off them, and keeps
|
|
237
|
+
# whole tracks only, so a half track, or a track past its last, stays
|
|
238
|
+
# on the disk alone. A sector that no longer reads back keeps its old
|
|
239
|
+
# data, and the flush warns once, naming the tracks that lost one.
|
|
240
|
+
def flush
|
|
241
|
+
return flush_tracks if @image.respond_to?(:store_tracks)
|
|
242
|
+
|
|
243
|
+
tracks = @written.keys.filter_map do |half|
|
|
244
|
+
track = @image && Disk.d64_track(@image, half)
|
|
245
|
+
[half, track] if track
|
|
246
|
+
end
|
|
247
|
+
@written.clear
|
|
248
|
+
return if tracks.empty?
|
|
249
|
+
|
|
250
|
+
sectors = tracks.to_h { |half, track| [track, SectorReader.read(@tracks[half].bytes, track)] }
|
|
251
|
+
id = disk_id(sectors)
|
|
252
|
+
warn_lost(sectors)
|
|
253
|
+
@image.store_blocks(sectors.flat_map do |track, found|
|
|
254
|
+
Array.new(@image.sectors_in(track)) { |sector| stored_block(track, sector, found[sector], id) }
|
|
255
|
+
end)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
private
|
|
259
|
+
|
|
260
|
+
def flush_tracks
|
|
261
|
+
tracks = @written.keys.sort.filter_map do |half|
|
|
262
|
+
entry = Disk.entry_of(half)
|
|
263
|
+
[entry, [@tracks[half].bytes, @tracks[half].zone]] if entry
|
|
264
|
+
end.to_h
|
|
265
|
+
@written.clear
|
|
266
|
+
@image.store_tracks(tracks) unless tracks.empty?
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def warn_lost(sectors)
|
|
270
|
+
lost = sectors.keys.select do |track|
|
|
271
|
+
Array.new(@image.sectors_in(track)) { |sector| lost?(track, sector, sectors[track][sector]) }.any?
|
|
272
|
+
end
|
|
273
|
+
return if lost.empty?
|
|
274
|
+
|
|
275
|
+
warn "1541: tracks written that no longer read back whole: #{lost.join(', ')}. The .d64 keeps the old " \
|
|
276
|
+
"data of the sectors lost, and a .g64 image keeps tracks as the drive writes them."
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# A sector the head no longer finds, which the image doesn't already
|
|
280
|
+
# hold as unreadable.
|
|
281
|
+
def lost?(track, sector, found)
|
|
282
|
+
found.nil? && ![20, 21].include?(@image.block_error(track, sector))
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# The disk ID the headers must carry, from the header block's $A2 and
|
|
286
|
+
# $A3 as Disk.from_d64 takes it: as just read back, or as the image
|
|
287
|
+
# holds it.
|
|
288
|
+
def disk_id(sectors)
|
|
289
|
+
track, sector = @image.header_block
|
|
290
|
+
header = sectors.dig(track, sector)&.data
|
|
291
|
+
data = header ? header[1, 256] : @image.read_block(track, sector)
|
|
292
|
+
[data[0xa2], data[0xa3]]
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# [track, sector, data, error] for DiskImage#store_blocks: the data as
|
|
296
|
+
# read, nil where it can't be, and the DOS error a read of it would
|
|
297
|
+
# raise, the way Disk.from_d64 writes each one. A sector whose header
|
|
298
|
+
# isn't found keeps its data, and reads as error 20, or 21 where the
|
|
299
|
+
# image already has it so.
|
|
300
|
+
def stored_block(track, sector, found, id)
|
|
301
|
+
return [track, sector, nil, @image.block_error(track, sector) == 21 ? 21 : 20] unless found
|
|
302
|
+
|
|
303
|
+
header = found.header
|
|
304
|
+
data = found.data
|
|
305
|
+
[track, sector, data && data[1, 256], block_error(header, data, id)]
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def block_error(header, data, id)
|
|
309
|
+
if header[1] != header[2] ^ header[3] ^ header[4] ^ header[5] then 27
|
|
310
|
+
elsif header[5] != id[0] || header[4] != id[1] then 29
|
|
311
|
+
elsif data.nil? || data[0] != DATA_ID then 22
|
|
312
|
+
elsif data[257] != data[1, 256].reduce(:^) then 23
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Drives
|
|
5
|
+
class Model1541
|
|
6
|
+
# VIA 2, the one facing the disk mechanism. Its port B drives the
|
|
7
|
+
# Mechanism, and CB2 selects its read or write mode. The mechanism
|
|
8
|
+
# hears both after every write and reset, since ORB, DDRB, the ACR and
|
|
9
|
+
# the PCR can all change them.
|
|
10
|
+
class DiskVIA < Chips::VIA
|
|
11
|
+
attr_reader :mechanism
|
|
12
|
+
|
|
13
|
+
def initialize(start:, mechanism:)
|
|
14
|
+
@mechanism = mechanism
|
|
15
|
+
mechanism.via = self
|
|
16
|
+
super(start:, peripheral: mechanism)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def reset!
|
|
20
|
+
super
|
|
21
|
+
tell_mechanism
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def poke(addr, value)
|
|
25
|
+
super
|
|
26
|
+
tell_mechanism
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def tell_mechanism
|
|
32
|
+
@mechanism.port_b_written(port_b_output)
|
|
33
|
+
@mechanism.cb2_written(cb2_output)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Drives
|
|
5
|
+
class Model1541
|
|
6
|
+
# Group code recording, the 1541's on-disk code. Each nibble becomes
|
|
7
|
+
# five bits, chosen so that no code has more than two 0 bits in a row
|
|
8
|
+
# and no run of codes has ten 1 bits in a row, which only a SYNC mark
|
|
9
|
+
# has. Four bytes become five.
|
|
10
|
+
module GCR
|
|
11
|
+
CODES = [0x0a, 0x0b, 0x12, 0x13, 0x0e, 0x0f, 0x16, 0x17,
|
|
12
|
+
0x09, 0x19, 0x1a, 0x1b, 0x0d, 0x1d, 0x1e, 0x15].freeze
|
|
13
|
+
|
|
14
|
+
# Five-bit code => nibble, nil for the codes that aren't GCR.
|
|
15
|
+
NIBBLES = Array.new(32) { |code| CODES.index(code) }.freeze
|
|
16
|
+
|
|
17
|
+
module_function
|
|
18
|
+
|
|
19
|
+
# Encodes a whole number of four-byte groups.
|
|
20
|
+
def encode(bytes)
|
|
21
|
+
out = []
|
|
22
|
+
i = 0
|
|
23
|
+
while i < bytes.length
|
|
24
|
+
bits = 0
|
|
25
|
+
4.times do |n|
|
|
26
|
+
byte = bytes[i + n]
|
|
27
|
+
bits = (bits << 10) | (CODES[byte >> 4] << 5) | CODES[byte & 0x0f]
|
|
28
|
+
end
|
|
29
|
+
4.downto(0) { |n| out << ((bits >> (n * 8)) & 0xff) }
|
|
30
|
+
i += 4
|
|
31
|
+
end
|
|
32
|
+
out
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Decodes a whole number of five-byte groups, nil when any code
|
|
36
|
+
# isn't GCR.
|
|
37
|
+
def decode(bytes)
|
|
38
|
+
out = []
|
|
39
|
+
i = 0
|
|
40
|
+
while i < bytes.length
|
|
41
|
+
bits = 0
|
|
42
|
+
5.times { |n| bits = (bits << 8) | bytes[i + n] }
|
|
43
|
+
n = 7
|
|
44
|
+
while n.positive?
|
|
45
|
+
high = NIBBLES[(bits >> (n * 5)) & 0x1f]
|
|
46
|
+
low = NIBBLES[(bits >> ((n - 1) * 5)) & 0x1f]
|
|
47
|
+
return nil if high.nil? || low.nil?
|
|
48
|
+
|
|
49
|
+
out << ((high << 4) | low)
|
|
50
|
+
n -= 2
|
|
51
|
+
end
|
|
52
|
+
i += 5
|
|
53
|
+
end
|
|
54
|
+
out
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Drives
|
|
5
|
+
class Model1541
|
|
6
|
+
class Disk
|
|
7
|
+
# The kinds of image a disk embeds, by name.
|
|
8
|
+
IMAGE_KINDS = %w[none d64 d71 g64].freeze
|
|
9
|
+
|
|
10
|
+
# A disk's fields in a keyed snapshot module (BL-D8-DISK): the image
|
|
11
|
+
# file's path and how it was opened, the image as last flushed,
|
|
12
|
+
# embedded under image and image.kind, each half track that differs
|
|
13
|
+
# from what the image decodes to, as track<H>.zone, track<H>.speeds
|
|
14
|
+
# and track<H>.gcr, raw GCR as the head sees it, and the half tracks
|
|
15
|
+
# written since the last flush.
|
|
16
|
+
module KeyedState
|
|
17
|
+
# The image's path, expanded, and whether it was opened read-only,
|
|
18
|
+
# for a disk from Disk.open. Nil for a disk made another way.
|
|
19
|
+
attr_reader :path, :read_only
|
|
20
|
+
|
|
21
|
+
# Notes the image's path and how it was opened.
|
|
22
|
+
def opened(path, read_only)
|
|
23
|
+
@path = File.expand_path(path)
|
|
24
|
+
@read_only = read_only
|
|
25
|
+
self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def save_fields(out)
|
|
29
|
+
path = @path
|
|
30
|
+
out.text("path", path) if path
|
|
31
|
+
out.bool("read_only", @read_only == true)
|
|
32
|
+
image = @image
|
|
33
|
+
decoded = nil
|
|
34
|
+
if image
|
|
35
|
+
out.text("image.kind", Disk.image_kind(image)).text("image.path", image.path.to_s)
|
|
36
|
+
out.bytes("image", image.contents)
|
|
37
|
+
decoded = Disk.decode(image)
|
|
38
|
+
end
|
|
39
|
+
@tracks.each_with_index { |track, half| save_track_fields(out, half, track, decoded) }
|
|
40
|
+
out.ints("written", @written.keys)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def load_track_fields(input)
|
|
44
|
+
@tracks.each_index do |half|
|
|
45
|
+
zone = input.optional_int("track#{half}.zone")
|
|
46
|
+
next if zone.nil?
|
|
47
|
+
|
|
48
|
+
speeds = input.ints("track#{half}.speeds", [])
|
|
49
|
+
gcr = input.bytes("track#{half}.gcr", "".b).bytes
|
|
50
|
+
@tracks[half] = Track.new(gcr, zone, speeds.empty? ? nil : speeds.dup)
|
|
51
|
+
end
|
|
52
|
+
@written.clear
|
|
53
|
+
input.ints("written", []).each { |half| @written[half] = true }
|
|
54
|
+
self
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def save_track_fields(out, half, track, decoded)
|
|
60
|
+
return if track.nil?
|
|
61
|
+
|
|
62
|
+
original = decoded&.track(half)
|
|
63
|
+
return if original && original.zone == track.zone && original.speeds == track.speeds &&
|
|
64
|
+
original.bytes == track.bytes
|
|
65
|
+
|
|
66
|
+
out.int("track#{half}.zone", track.zone)
|
|
67
|
+
speeds = track.speeds
|
|
68
|
+
out.ints("track#{half}.speeds", speeds) if speeds
|
|
69
|
+
out.bytes("track#{half}.gcr", track.bytes)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
include KeyedState
|
|
74
|
+
|
|
75
|
+
# The kind of `image`, by name.
|
|
76
|
+
def self.image_kind(image)
|
|
77
|
+
return "g64" if image.is_a?(Storage::G64Image)
|
|
78
|
+
return "d71" if image.is_a?(Storage::D71Image)
|
|
79
|
+
|
|
80
|
+
"d64"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# The tracks `image` holds, as an insert decodes them.
|
|
84
|
+
def self.decode(image) = image.is_a?(Storage::G64Image) ? from_g64(image) : from_d64(image)
|
|
85
|
+
|
|
86
|
+
# The disk a keyed snapshot module describes: its embedded image
|
|
87
|
+
# decoded, with the tracks the module holds laid over it. The image
|
|
88
|
+
# takes writes back to its file only while that file is there and
|
|
89
|
+
# the reader isn't `detached`. With no image, the disk is the
|
|
90
|
+
# tracks alone, write-protected.
|
|
91
|
+
def self.from_fields(input, detached: false)
|
|
92
|
+
path = input.text("path", "")
|
|
93
|
+
read_only = input.bool("read_only", false)
|
|
94
|
+
kind = input.choice("image.kind", IMAGE_KINDS, "none")
|
|
95
|
+
image_path = input.text("image.path", "")
|
|
96
|
+
disk = kind == "none" ? Disk.new : from_image(input, kind, image_path, read_only || detached)
|
|
97
|
+
disk.opened(path, read_only || kind == "none") unless path.empty?
|
|
98
|
+
disk.load_track_fields(input)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def self.from_image(input, kind, path, read_only)
|
|
102
|
+
bytes = input.bytes("image", "".b).bytes
|
|
103
|
+
writable_path = path.empty? || !File.file?(path) ? "" : path
|
|
104
|
+
image = case kind
|
|
105
|
+
when "g64" then Storage::G64Image.new(writable_path, read_only:, bytes:)
|
|
106
|
+
when "d71" then Storage::D71Image.new(writable_path, read_only:, bytes:)
|
|
107
|
+
else Storage::D64Image.new(writable_path, read_only:, bytes:)
|
|
108
|
+
end
|
|
109
|
+
decode(image)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
class Mechanism
|
|
114
|
+
# The head, the motor, the stepper and the read and write
|
|
115
|
+
# electronics in a keyed snapshot module (BL-D8-MECH): where the
|
|
116
|
+
# head is, the disk's place in its turn, the read clock's next
|
|
117
|
+
# clock in cycles from now, the shift registers and the flags. The
|
|
118
|
+
# cell under the head, its width and the next event come from the
|
|
119
|
+
# track and the time on load, the cell period from the zone, and
|
|
120
|
+
# the write protection from the disk.
|
|
121
|
+
module KeyedState
|
|
122
|
+
def save_fields(out)
|
|
123
|
+
out.int("half_track", @half_track).int("slip", @slip).int("side", @side_base).int("zone", @zone)
|
|
124
|
+
out.int("time", @time).int("read_clock_in", @clock_at - @time).int("clocks", @clocks)
|
|
125
|
+
out.int("shift", @shift).int("ones", @ones).int("bits", @bits).int("write_shift", @write_shift)
|
|
126
|
+
out.bool("motor", @motor).bool("led", @led).bool("sync", @sync).bool("byte_ready", @byte_ready)
|
|
127
|
+
out.bool("byte_latched", @byte_latched).bool("writing", @writing).bool("write_gate", @write_gate)
|
|
128
|
+
out.bool("track_written", @track_written).optional_int("write_index", @write_index)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Puts `disk` under the head without flushing the one there, as a
|
|
132
|
+
# snapshot load replaces it.
|
|
133
|
+
def load_fields(input, disk)
|
|
134
|
+
@disk = disk
|
|
135
|
+
load_head_fields(input)
|
|
136
|
+
load_flag_fields(input)
|
|
137
|
+
@clock = Track.cell(@zone)
|
|
138
|
+
@protected = disk&.write_protected? || false
|
|
139
|
+
track_written = input.bool("track_written", false)
|
|
140
|
+
write_index = input.optional_int("write_index")
|
|
141
|
+
load_track(@time)
|
|
142
|
+
@track_written = track_written
|
|
143
|
+
@write_index = write_index
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
private
|
|
147
|
+
|
|
148
|
+
def load_head_fields(input)
|
|
149
|
+
@half_track = input.int("half_track", @half_track)
|
|
150
|
+
@slip = input.masked("slip", @slip, 0x03)
|
|
151
|
+
@side_base = input.int("side", @side_base)
|
|
152
|
+
@zone = input.masked("zone", @zone, 0x03)
|
|
153
|
+
@time = input.int("time", @time)
|
|
154
|
+
@clock_at = @time + input.int("read_clock_in", @clock_at - @time)
|
|
155
|
+
@clocks = input.int("clocks", @clocks)
|
|
156
|
+
@shift = input.int("shift", @shift)
|
|
157
|
+
@ones = input.int("ones", @ones)
|
|
158
|
+
@bits = input.int("bits", @bits)
|
|
159
|
+
@write_shift = input.int("write_shift", @write_shift)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def load_flag_fields(input)
|
|
163
|
+
@motor = input.bool("motor", @motor)
|
|
164
|
+
@led = input.bool("led", @led)
|
|
165
|
+
@sync = input.bool("sync", @sync)
|
|
166
|
+
@byte_ready = input.bool("byte_ready", @byte_ready)
|
|
167
|
+
@byte_latched = input.bool("byte_latched", @byte_latched)
|
|
168
|
+
@writing = input.bool("writing", @writing)
|
|
169
|
+
@write_gate = input.bool("write_gate", @write_gate)
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
include KeyedState
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
class Bus
|
|
177
|
+
# The drive's RAM and the byte last on its data bus, in a keyed
|
|
178
|
+
# snapshot module (BL-D8-RAM).
|
|
179
|
+
def save_fields(out)
|
|
180
|
+
out.int("data", @data).bytes("ram", @ram.read(0, @ram.length))
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def load_fields(input)
|
|
184
|
+
@data = input.byte("data", @data)
|
|
185
|
+
ram = @ram.read(0, @ram.length)
|
|
186
|
+
@ram.write(0, input.bytes_into("ram", ram))
|
|
187
|
+
@watching = false
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# The drive's own fields in a keyed snapshot module (BL-D8): its model,
|
|
192
|
+
# its clock phase and cycle count, the SO pulse due, and the host's
|
|
193
|
+
# lines as the serial port latched them. A save settles the drive first, so it is awake;
|
|
194
|
+
# a load forgets its orbits.
|
|
195
|
+
module KeyedState
|
|
196
|
+
def save_fields(out)
|
|
197
|
+
settle!
|
|
198
|
+
out.text("model", model_name).int("phase", @phase).int("cycles", @cycles)
|
|
199
|
+
out.bool("so_pending", @mechanism.so_pending)
|
|
200
|
+
@serial_port.save_fields(out, "serial.")
|
|
201
|
+
out
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def load_fields(input)
|
|
205
|
+
settle!
|
|
206
|
+
input.choice("model", [model_name], model_name)
|
|
207
|
+
@phase = input.int("phase", @phase)
|
|
208
|
+
@cycles = input.int("cycles", @cycles)
|
|
209
|
+
@mechanism.so_pending = input.bool("so_pending", @mechanism.so_pending)
|
|
210
|
+
@serial_port.load_fields(input, "serial.")
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def restored! = forget_orbits
|
|
214
|
+
|
|
215
|
+
# The drive as modules of its own, named from `name` (BL-D8 for
|
|
216
|
+
# device 8): its own fields, its RAM, each VIA, the CPU, the
|
|
217
|
+
# mechanism and the disk, when one is in.
|
|
218
|
+
def save_modules(sections, name)
|
|
219
|
+
sections << Snapshot::Keyed.section(name) { |out| save_fields(out) }
|
|
220
|
+
sections << Snapshot::Keyed.section("#{name}-RAM") { |out| @bus.save_fields(out) }
|
|
221
|
+
sections << Snapshot::Keyed.section("#{name}-VIA1") { |out| @via1.save_fields(out) }
|
|
222
|
+
sections << Snapshot::Keyed.section("#{name}-VIA2") { |out| @via2.save_fields(out) }
|
|
223
|
+
sections << Snapshot::Keyed.section("#{name}-CPU") { |out| @cpu.save_fields(out) }
|
|
224
|
+
sections << Snapshot::Keyed.section("#{name}-MECH") { |out| @mechanism.save_fields(out) }
|
|
225
|
+
disk = @mechanism.disk
|
|
226
|
+
sections << Snapshot::Keyed.section("#{name}-DISK") { |out| disk.save_fields(out) } if disk
|
|
227
|
+
sections
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# The drive from its modules, `input` being its own. No disk module
|
|
231
|
+
# means no disk in the drive.
|
|
232
|
+
def load_modules(modules, input, name)
|
|
233
|
+
load_fields(input)
|
|
234
|
+
@bus.load_fields(modules.required("#{name}-RAM"))
|
|
235
|
+
@via1.load_fields(modules.required("#{name}-VIA1"))
|
|
236
|
+
@via2.load_fields(modules.required("#{name}-VIA2"))
|
|
237
|
+
@cpu.load_fields(modules.required("#{name}-CPU"))
|
|
238
|
+
disk = modules.optional("#{name}-DISK")
|
|
239
|
+
mechanism = modules.required("#{name}-MECH")
|
|
240
|
+
@mechanism.load_fields(mechanism, disk.nil? ? nil : Disk.from_fields(disk, detached: modules.detached?))
|
|
241
|
+
@via1.restored!
|
|
242
|
+
@via2.restored!
|
|
243
|
+
@cpu.restored!
|
|
244
|
+
restored!
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
include KeyedState
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end
|