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
|
@@ -2,37 +2,109 @@
|
|
|
2
2
|
|
|
3
3
|
module Badline
|
|
4
4
|
module Snapshot
|
|
5
|
-
# What a restore applied and what it left out: module names
|
|
6
|
-
# for each thing left out, saying why.
|
|
7
|
-
|
|
5
|
+
# What a restore applied and what it left out: module names and a line
|
|
6
|
+
# for each thing left out or changed, saying why. For a badline
|
|
7
|
+
# snapshot, `modules` holds each BL-* module's Keyed::Report, which
|
|
8
|
+
# give the fields per module this badline doesn't know, the modules it
|
|
9
|
+
# expected and didn't find, and the values it read other than as
|
|
10
|
+
# written, and `written_by` the badline version that saved it.
|
|
11
|
+
class Report
|
|
12
|
+
attr_reader :applied, :ignored, :written_by
|
|
13
|
+
|
|
14
|
+
def initialize(applied:, ignored:, modules: [], written_by: "")
|
|
15
|
+
@applied = applied
|
|
16
|
+
@ignored = ignored
|
|
17
|
+
@modules = modules
|
|
18
|
+
@written_by = written_by
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# The keys nothing read, by module, for the modules that had any.
|
|
22
|
+
def unknown
|
|
23
|
+
@modules.reject { |report| report.unknown.empty? }.to_h { |report| [report.name, report.unknown] }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# The modules the snapshot didn't have.
|
|
27
|
+
def missing = @modules.select(&:missing).map(&:name)
|
|
28
|
+
|
|
29
|
+
# A line for each value read other than as written.
|
|
30
|
+
def adjusted = @modules.flat_map { |report| report.adjusted.map { |line| "#{report.name}: #{line}" } }
|
|
31
|
+
end
|
|
8
32
|
|
|
9
|
-
# A snapshot read from a file
|
|
33
|
+
# A snapshot: the container and its modules, read from a file or taken
|
|
34
|
+
# of a machine in memory (.of).
|
|
10
35
|
class Image
|
|
36
|
+
MACHINE = "BL-MACHINE"
|
|
37
|
+
FAMILIES = { "c64" => "C64", "vic20" => "VIC-20", "c128" => "C128" }.freeze
|
|
38
|
+
|
|
11
39
|
attr_reader :container
|
|
12
40
|
|
|
13
|
-
|
|
41
|
+
# `name` is what a refusal calls the snapshot, such as its file's name.
|
|
42
|
+
def initialize(container, name: "the snapshot")
|
|
14
43
|
@container = container
|
|
44
|
+
@name = name
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# The machine's snapshot, saved as a file saves it: the machine runs
|
|
48
|
+
# on to the end of the instruction its CPU is in, and of an REU
|
|
49
|
+
# transfer under way (Machine::Settling), then writes its BL-*
|
|
50
|
+
# modules.
|
|
51
|
+
def self.of(computer)
|
|
52
|
+
computer.settle_for_snapshot!
|
|
53
|
+
new(Container.new(computer.save_modules, machine: machine_name(computer)))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# The snapshot with VICE's modules ahead of the BL-* ones for a C64,
|
|
57
|
+
# so x64sc opens it too.
|
|
58
|
+
def self.exported(computer)
|
|
59
|
+
computer.settle_for_snapshot!
|
|
60
|
+
sections = computer.save_modules
|
|
61
|
+
sections = Vice.export(computer) + sections if computer.family == :c64
|
|
62
|
+
new(Container.new(sections, machine: machine_name(computer)))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# The machine as VICE's emulators name it.
|
|
66
|
+
def self.machine_name(computer)
|
|
67
|
+
case computer.family
|
|
68
|
+
when :vic20 then Container::VIC20
|
|
69
|
+
when :c128 then Container::C128
|
|
70
|
+
else Container::MACHINE
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# How the machine was built, from the family BL-MACHINE, read by
|
|
75
|
+
# `machine`, names.
|
|
76
|
+
def self.setup(machine)
|
|
77
|
+
case machine.choice("family", FAMILIES.keys, "c64")
|
|
78
|
+
when "vic20" then Vic20Setup.read_fields(machine)
|
|
79
|
+
when "c128" then C128Setup.read_fields(machine)
|
|
80
|
+
else C64Setup.read_fields(machine)
|
|
81
|
+
end
|
|
15
82
|
end
|
|
16
83
|
|
|
17
84
|
def sections = @container.sections
|
|
18
85
|
|
|
19
|
-
|
|
20
|
-
|
|
86
|
+
def to_s = @container.to_s
|
|
87
|
+
|
|
88
|
+
def ==(other) = other.is_a?(Image) && to_s == other.to_s
|
|
21
89
|
|
|
22
|
-
#
|
|
23
|
-
def
|
|
90
|
+
# Whether badline wrote it, with the whole machine in BL-* modules.
|
|
91
|
+
def badline? = !@container[MACHINE].nil?
|
|
24
92
|
|
|
25
93
|
# A new machine, built as the snapshot's was and restored from it. A
|
|
26
|
-
# badline snapshot restores from its
|
|
27
|
-
#
|
|
28
|
-
# modules
|
|
29
|
-
# warns it without a block.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
94
|
+
# badline snapshot restores from its BL-* modules alone, and a VICE
|
|
95
|
+
# one through the modules badline reads. xvic's and x128's own
|
|
96
|
+
# modules aren't read. Yields a line for each thing left out, or
|
|
97
|
+
# warns it without a block. `detached` restores it without the host's
|
|
98
|
+
# files (Keyed::Modules).
|
|
99
|
+
def load(detached: false, &)
|
|
100
|
+
refuse_old_layout
|
|
101
|
+
raise FormatError, "badline reads only its own VIC-20 snapshots, not xvic's" if vic20? && !badline?
|
|
102
|
+
raise FormatError, "badline reads only its own C128 snapshots, not x128's" if c128? && !badline?
|
|
103
|
+
return load_vice(&) unless badline?
|
|
104
|
+
|
|
105
|
+
modules = Keyed::Modules.new(sections, detached:)
|
|
106
|
+
computer = opening { Image.setup(modules.machine).build.load_modules(modules) }
|
|
107
|
+
tell(report(modules, computer), &)
|
|
36
108
|
computer
|
|
37
109
|
end
|
|
38
110
|
|
|
@@ -42,57 +114,71 @@ module Badline
|
|
|
42
114
|
# Whether the machine is a C128, as the container names it.
|
|
43
115
|
def c128? = @container.machine == Container::C128
|
|
44
116
|
|
|
45
|
-
# Restores `computer` from the snapshot, and returns the Report.
|
|
46
|
-
# snapshot
|
|
117
|
+
# Restores `computer` from the snapshot, and returns the Report. The
|
|
118
|
+
# snapshot goes into a new machine first, so one that fails, or is of
|
|
119
|
+
# a machine built another way, leaves `computer` as it was.
|
|
47
120
|
def restore(computer, &)
|
|
48
|
-
|
|
121
|
+
refuse_old_layout
|
|
122
|
+
report = badline? ? restore_modules(computer) : Vice::Restore.import(@container, computer)
|
|
49
123
|
tell(report, &)
|
|
50
124
|
report
|
|
51
125
|
end
|
|
52
126
|
|
|
53
127
|
private
|
|
54
128
|
|
|
55
|
-
def
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
raise FormatError, "badline reads only its own VIC-20 snapshots, not xvic's" unless badline?
|
|
129
|
+
def load_vice(&)
|
|
130
|
+
computer = Vice.setup(@container).build
|
|
131
|
+
tell(Vice::Restore.apply(@container, computer), &)
|
|
132
|
+
computer
|
|
133
|
+
end
|
|
61
134
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
135
|
+
# The snapshot goes into a new machine first, so one that fails
|
|
136
|
+
# leaves `computer` as it was.
|
|
137
|
+
def restore_modules(computer)
|
|
138
|
+
modules = Keyed::Modules.new(sections)
|
|
139
|
+
family = modules.machine.choice("family", FAMILIES.keys, "c64")
|
|
140
|
+
unless family == computer.family.to_s
|
|
141
|
+
raise FormatError, "the snapshot is of a #{FAMILIES.fetch(family, family)}, " \
|
|
142
|
+
"not a #{FAMILIES.fetch(computer.family.to_s)}"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
trial = Keyed::Modules.new(sections)
|
|
146
|
+
opening { Image.setup(trial.machine).build.load_modules(trial) }
|
|
147
|
+
opening { computer.load_modules(modules) }
|
|
148
|
+
report(modules, computer)
|
|
65
149
|
end
|
|
66
150
|
|
|
67
|
-
# A
|
|
68
|
-
#
|
|
69
|
-
def
|
|
70
|
-
|
|
151
|
+
# A snapshot from a badline before the keyed modules, which only the
|
|
152
|
+
# version that saved it reads.
|
|
153
|
+
def refuse_old_layout
|
|
154
|
+
old = @container[MachineState::NAME]
|
|
155
|
+
return if old.nil? || badline?
|
|
156
|
+
|
|
157
|
+
version = MachineState.written_by(old)
|
|
158
|
+
layout = "in the old snapshot layout, which this badline can't read."
|
|
159
|
+
raise FormatError, "#{@name} was saved by an earlier badline #{layout}" if version.empty?
|
|
71
160
|
|
|
72
|
-
|
|
73
|
-
tell(state_report(machine), &)
|
|
74
|
-
machine
|
|
161
|
+
raise FormatError, "#{@name} was saved by badline #{version} #{layout} It still opens in badline #{version}."
|
|
75
162
|
end
|
|
76
163
|
|
|
77
164
|
def tell(report)
|
|
78
165
|
report.ignored.each { |line| block_given? ? yield(line) : warn("badline: #{line}") }
|
|
79
166
|
end
|
|
80
167
|
|
|
81
|
-
def restore_state(computer)
|
|
82
|
-
opening { computer.restore(state) }
|
|
83
|
-
state_report(computer)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
168
|
def opening
|
|
87
169
|
yield
|
|
88
170
|
rescue SystemCallError => e
|
|
89
171
|
raise FormatError, "a file the snapshot names won't open: #{e.message}"
|
|
90
172
|
end
|
|
91
173
|
|
|
92
|
-
def
|
|
174
|
+
def report(modules, computer)
|
|
175
|
+
written_by = modules.machine.text("written_by", "")
|
|
176
|
+
reports = modules.readers.map(&:report)
|
|
177
|
+
ignored = reports.flat_map(&:lines)
|
|
178
|
+
ignored.concat(modules.unread.map { |name| "#{name}: badline doesn't read this module, left out" })
|
|
93
179
|
lost = computer.init_handlers_lost
|
|
94
|
-
ignored
|
|
95
|
-
Report.new(applied:
|
|
180
|
+
ignored << "#{lost} on_init handler(s) the saved machine had yet to run, left out" if lost.positive?
|
|
181
|
+
Report.new(applied: reports.reject(&:missing).map(&:name), ignored:, modules: reports, written_by:)
|
|
96
182
|
end
|
|
97
183
|
end
|
|
98
184
|
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Snapshot
|
|
5
|
+
module Keyed
|
|
6
|
+
# Reads BER numbers and byte runs from a module's payload, or from one
|
|
7
|
+
# record's value, failing on anything cut short.
|
|
8
|
+
class Cursor
|
|
9
|
+
def initialize(bytes, name)
|
|
10
|
+
@bytes = bytes
|
|
11
|
+
@name = name
|
|
12
|
+
@pos = 0
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def done? = @pos >= @bytes.bytesize
|
|
16
|
+
|
|
17
|
+
def remaining = @bytes.bytesize - @pos
|
|
18
|
+
|
|
19
|
+
def ber
|
|
20
|
+
value = 0
|
|
21
|
+
loop do
|
|
22
|
+
raise FormatError, "#{@name} holds a number too large for a snapshot" if value >= (1 << 56)
|
|
23
|
+
|
|
24
|
+
byte = take(1).getbyte(0).to_i
|
|
25
|
+
value = (value << 7) | (byte & 0x7f)
|
|
26
|
+
return value if byte < 0x80
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def int = Keyed.unzigzag(ber)
|
|
31
|
+
|
|
32
|
+
def take(count)
|
|
33
|
+
raise FormatError, "#{@name} ends early, at byte #{@bytes.bytesize}" if count > remaining
|
|
34
|
+
|
|
35
|
+
@bytes.byteslice(@pos, count).to_s.tap { @pos += count }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Snapshot
|
|
5
|
+
module Keyed
|
|
6
|
+
# A snapshot's BL-* modules by name, which a family reads in its own
|
|
7
|
+
# fixed order, whatever order the file has them in. Each module is
|
|
8
|
+
# parsed once, and its Reader kept for the Report.
|
|
9
|
+
#
|
|
10
|
+
# A `detached` load restores a machine that opens no host file and
|
|
11
|
+
# writes none: a disk image comes from the bytes the snapshot holds,
|
|
12
|
+
# write-protected, and a directory device 8 serves is left out.
|
|
13
|
+
class Modules
|
|
14
|
+
attr_reader :readers
|
|
15
|
+
|
|
16
|
+
def initialize(sections, detached: false)
|
|
17
|
+
@sections = {}
|
|
18
|
+
sections.each { |section| @sections[section.name] = section }
|
|
19
|
+
@parsed = {}
|
|
20
|
+
@readers = []
|
|
21
|
+
@detached = detached
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def detached? = @detached
|
|
25
|
+
|
|
26
|
+
# BL-MACHINE, which every family writes first.
|
|
27
|
+
def machine = required("BL-MACHINE")
|
|
28
|
+
|
|
29
|
+
# The module a family always writes, or a Reader standing in for it,
|
|
30
|
+
# reported missing.
|
|
31
|
+
def required(name)
|
|
32
|
+
reader = @parsed[name]
|
|
33
|
+
return reader if reader
|
|
34
|
+
|
|
35
|
+
section = @sections[name]
|
|
36
|
+
keep(name, section.nil? ? missing(name) : parse(section))
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# The module, or nil when the snapshot has none, as it has none for a
|
|
40
|
+
# cartridge or a drive that isn't there.
|
|
41
|
+
def optional(name)
|
|
42
|
+
reader = @parsed[name]
|
|
43
|
+
return reader if reader
|
|
44
|
+
|
|
45
|
+
section = @sections[name]
|
|
46
|
+
section.nil? ? nil : keep(name, parse(section))
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# The BL-* modules no family read, from a later badline.
|
|
50
|
+
def unread = @sections.keys.select { |name| name.start_with?("BL-") && !@parsed.key?(name) }
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def parse(section) = Reader.parse(section)
|
|
55
|
+
|
|
56
|
+
def missing(name) = Reader.missing(name)
|
|
57
|
+
|
|
58
|
+
def keep(name, reader)
|
|
59
|
+
@parsed[name] = reader
|
|
60
|
+
@readers << reader
|
|
61
|
+
reader
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Snapshot
|
|
5
|
+
module Keyed
|
|
6
|
+
# Parses a module's records into one Hash per type, so every value
|
|
7
|
+
# read has a single type in Spinel. Each read takes the current value
|
|
8
|
+
# as its default, which in a machine built for the load is power-on,
|
|
9
|
+
# and returns it when the record is missing or of another type.
|
|
10
|
+
#
|
|
11
|
+
# A Reader with no records stands in for a module the snapshot
|
|
12
|
+
# doesn't have, so every load takes the same path.
|
|
13
|
+
class Reader
|
|
14
|
+
# The tag of each key the module's records hold.
|
|
15
|
+
attr_reader :name, :tags
|
|
16
|
+
|
|
17
|
+
# Whether it stands in for a module the snapshot doesn't have.
|
|
18
|
+
def missing? = @missing
|
|
19
|
+
|
|
20
|
+
# The records in `section`, which must be in this encoding.
|
|
21
|
+
def self.parse(section)
|
|
22
|
+
unless section.major == MAJOR
|
|
23
|
+
raise FormatError, "#{section.name} #{section.version} was written by a newer badline's encoding, " \
|
|
24
|
+
"and this one reads #{MAJOR}.#{MINOR}"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
new(section.name, Zlib.inflate(section.data))
|
|
28
|
+
rescue Zlib::Error => e
|
|
29
|
+
raise FormatError, "#{section.name} is damaged: #{e.message}"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Stands in for a module the snapshot doesn't have.
|
|
33
|
+
def self.missing(name) = new(name, "".b, missing: true)
|
|
34
|
+
|
|
35
|
+
def initialize(name, payload = "".b, missing: false)
|
|
36
|
+
@name = name
|
|
37
|
+
@missing = missing
|
|
38
|
+
@ints = {}
|
|
39
|
+
@bools = {}
|
|
40
|
+
@bytes = {}
|
|
41
|
+
@lists = {}
|
|
42
|
+
@texts = {}
|
|
43
|
+
@tags = {}
|
|
44
|
+
@read = {}
|
|
45
|
+
@adjusted = []
|
|
46
|
+
@unknown_tags = 0
|
|
47
|
+
parse(Cursor.new(payload, name))
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def int(key, default) = fetch_int(key, default)
|
|
51
|
+
|
|
52
|
+
def word(key, default) = fetch_masked(key, default, 0xffff)
|
|
53
|
+
|
|
54
|
+
def byte(key, default) = fetch_masked(key, default, 0xff)
|
|
55
|
+
|
|
56
|
+
# An int cut to the bits a latch holds, reported if it was wider.
|
|
57
|
+
def masked(key, default, mask) = fetch_masked(key, default, mask)
|
|
58
|
+
|
|
59
|
+
def bool(key, default) = present?(key, "a bool", @bools.key?(key)) ? @bools.fetch(key) : default
|
|
60
|
+
|
|
61
|
+
# Nil when the record is missing.
|
|
62
|
+
def optional_int(key) = present?(key, "an int", @ints.key?(key)) ? @ints.fetch(key) : nil
|
|
63
|
+
|
|
64
|
+
def ints(key, default) = present?(key, "a list of ints", @lists.key?(key)) ? @lists.fetch(key) : default
|
|
65
|
+
|
|
66
|
+
# A binary String.
|
|
67
|
+
def bytes(key, default) = fetch_bytes(key, default)
|
|
68
|
+
|
|
69
|
+
# Reads a hardware array into `array` in place. A shorter list
|
|
70
|
+
# leaves the rest as it was and a longer one is cut, and both are
|
|
71
|
+
# reported.
|
|
72
|
+
def ints_into(key, array)
|
|
73
|
+
return array unless present?(key, "a list of ints", @lists.key?(key))
|
|
74
|
+
|
|
75
|
+
fill(key, array, @lists.fetch(key))
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def bytes_into(key, array)
|
|
79
|
+
return array unless present?(key, "bytes", @bytes.key?(key))
|
|
80
|
+
|
|
81
|
+
fill(key, array, @bytes.fetch(key).bytes)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def text(key, default) = fetch_text(key, default)
|
|
85
|
+
|
|
86
|
+
# The text, if it is one of `names`, and otherwise `default`,
|
|
87
|
+
# reported.
|
|
88
|
+
def choice(key, names, default)
|
|
89
|
+
value = fetch_text(key, default)
|
|
90
|
+
return value if names.include?(value)
|
|
91
|
+
|
|
92
|
+
@adjusted << "#{key} #{value.inspect} is not one of #{names.join(', ')}, left at #{default}"
|
|
93
|
+
default
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Reports something a unit's load left out or changed beyond one
|
|
97
|
+
# field, such as a line batch from another renderer.
|
|
98
|
+
def adjust(line)
|
|
99
|
+
@adjusted << line
|
|
100
|
+
self
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# The keys of records nothing read.
|
|
104
|
+
def unknown = @tags.keys.reject { |key| @read.key?(key) }
|
|
105
|
+
|
|
106
|
+
def report
|
|
107
|
+
Report.new(name:, missing: @missing, unknown:, adjusted: @adjusted.dup, unknown_tags: @unknown_tags)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
private
|
|
111
|
+
|
|
112
|
+
def fetch_int(key, default) = present?(key, "an int", @ints.key?(key)) ? @ints.fetch(key) : default
|
|
113
|
+
|
|
114
|
+
def fetch_masked(key, default, mask)
|
|
115
|
+
value = fetch_int(key, default)
|
|
116
|
+
return value if value & mask == value
|
|
117
|
+
|
|
118
|
+
@adjusted << "#{key} #{value} is wider than its latch, masked to #{value & mask}"
|
|
119
|
+
value & mask
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def fetch_bytes(key, default) = present?(key, "bytes", @bytes.key?(key)) ? @bytes.fetch(key) : default
|
|
123
|
+
|
|
124
|
+
def fetch_text(key, default) = present?(key, "text", @texts.key?(key)) ? @texts.fetch(key) : default
|
|
125
|
+
|
|
126
|
+
# Whether the key has a record of the type read, `there`. A record
|
|
127
|
+
# of another type counts as missing, and is reported.
|
|
128
|
+
def present?(key, type, there)
|
|
129
|
+
@read[key] = true if there || @tags.key?(key)
|
|
130
|
+
@adjusted << "#{key} is not #{type}, left at its default" if !there && @tags.key?(key)
|
|
131
|
+
there
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def fill(key, array, values)
|
|
135
|
+
unless values.length == array.length
|
|
136
|
+
what = values.length < array.length ? "the rest left as they were" : "the rest cut"
|
|
137
|
+
@adjusted << "#{key} holds #{values.length} values where #{array.length} fit, #{what}"
|
|
138
|
+
end
|
|
139
|
+
[values.length, array.length].min.times { |index| array[index] = values[index] }
|
|
140
|
+
array
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def parse(cursor)
|
|
144
|
+
until cursor.done?
|
|
145
|
+
key = cursor.take(cursor.ber)
|
|
146
|
+
tag = cursor.take(1).getbyte(0).to_i
|
|
147
|
+
store(key, tag, cursor.take(cursor.ber))
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def store(key, tag, value)
|
|
152
|
+
unless tag.between?(INT, TEXT)
|
|
153
|
+
@unknown_tags += 1
|
|
154
|
+
return
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
forget(key)
|
|
158
|
+
@tags[key] = tag
|
|
159
|
+
case tag
|
|
160
|
+
when INT then @ints[key] = Cursor.new(value, "#{@name} #{key}").int
|
|
161
|
+
when BOOL then @bools[key] = value.getbyte(0).to_i != 0
|
|
162
|
+
when BYTES then @bytes[key] = value
|
|
163
|
+
when INTS then @lists[key] = list(Cursor.new(value, "#{@name} #{key}"))
|
|
164
|
+
else @texts[key] = value.force_encoding(Encoding::UTF_8)
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def forget(key)
|
|
169
|
+
return unless @tags.key?(key)
|
|
170
|
+
|
|
171
|
+
@adjusted << "#{key} appears more than once, the last one counts"
|
|
172
|
+
@ints.delete(key)
|
|
173
|
+
@bools.delete(key)
|
|
174
|
+
@bytes.delete(key)
|
|
175
|
+
@lists.delete(key)
|
|
176
|
+
@texts.delete(key)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def list(cursor)
|
|
180
|
+
count = cursor.ber
|
|
181
|
+
raise FormatError, "#{@name} ends early, in a list of #{count}" if count > cursor.remaining
|
|
182
|
+
|
|
183
|
+
Array.new(count) { cursor.int }
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Snapshot
|
|
5
|
+
module Keyed
|
|
6
|
+
# A Reader that notes every read: the module, the key, the type read
|
|
7
|
+
# and the default passed. Loading a machine at power-on through
|
|
8
|
+
# Recorders lists each module's fields with their power-on values
|
|
9
|
+
# (FieldDoc).
|
|
10
|
+
class Recorder < Reader
|
|
11
|
+
Field = Data.define(:module_name, :key, :type, :default)
|
|
12
|
+
|
|
13
|
+
attr_reader :fields
|
|
14
|
+
|
|
15
|
+
def initialize(name, payload = "".b, missing: false)
|
|
16
|
+
super
|
|
17
|
+
@fields = []
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def int(key, default)
|
|
21
|
+
note(key, "int", default)
|
|
22
|
+
super
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def word(key, default)
|
|
26
|
+
note(key, "word", default)
|
|
27
|
+
super
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def byte(key, default)
|
|
31
|
+
note(key, "byte", default)
|
|
32
|
+
super
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def masked(key, default, mask)
|
|
36
|
+
note(key, "int & 0x#{mask.to_s(16)}", default)
|
|
37
|
+
super
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def bool(key, default)
|
|
41
|
+
note(key, "bool", default)
|
|
42
|
+
super
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def optional_int(key)
|
|
46
|
+
note(key, "int, optional", nil)
|
|
47
|
+
super
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def ints(key, default)
|
|
51
|
+
note(key, "ints", default.dup)
|
|
52
|
+
super
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def bytes(key, default)
|
|
56
|
+
note(key, "bytes", default.dup)
|
|
57
|
+
super
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def ints_into(key, array)
|
|
61
|
+
note(key, "ints", array.dup)
|
|
62
|
+
super
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def bytes_into(key, array)
|
|
66
|
+
note(key, "bytes", array.dup)
|
|
67
|
+
super
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def text(key, default)
|
|
71
|
+
note(key, "text", default)
|
|
72
|
+
super
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def choice(key, names, default)
|
|
76
|
+
note(key, "text: #{names.join(' ')}", default)
|
|
77
|
+
super
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
def note(key, type, default)
|
|
83
|
+
@fields << Field.new(module_name: name, key:, type:, default:)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Snapshot
|
|
5
|
+
module Keyed
|
|
6
|
+
# What reading a module left out or changed: whether the snapshot
|
|
7
|
+
# had the module at all, the keys nothing read, a line for each value
|
|
8
|
+
# read other than as written, and how many records had a tag this
|
|
9
|
+
# badline doesn't know.
|
|
10
|
+
Report = Data.define(:name, :missing, :unknown, :adjusted, :unknown_tags) do
|
|
11
|
+
# Lines for the user. A missing module and adjusted values always
|
|
12
|
+
# get one, and unknown keys and tags only when `verbose`, since a
|
|
13
|
+
# snapshot from a later badline has them on every load.
|
|
14
|
+
def lines(verbose: false)
|
|
15
|
+
lines = missing ? ["#{name} is missing, left at power-on"] : []
|
|
16
|
+
lines.concat(adjusted.map { |line| "#{name}: #{line}" })
|
|
17
|
+
return lines unless verbose
|
|
18
|
+
|
|
19
|
+
lines << "#{name}: #{unknown.length} unknown field(s): #{unknown.join(', ')}" unless unknown.empty?
|
|
20
|
+
lines << "#{name}: #{unknown_tags} field(s) of an unknown type, skipped" if unknown_tags.positive?
|
|
21
|
+
lines
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|