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,213 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class CIA
|
|
6
|
+
class Timer
|
|
7
|
+
# A timer's fields in a keyed snapshot module (Snapshot::Keyed),
|
|
8
|
+
# under `prefix`: the counter, the latch and the pipeline between
|
|
9
|
+
# them. The fast-path flags are worked out again on load.
|
|
10
|
+
module KeyedState
|
|
11
|
+
def save_fields(out, prefix)
|
|
12
|
+
out.int("#{prefix}counter", @counter).int("#{prefix}latch", @latch).int("#{prefix}pipe", @pipe)
|
|
13
|
+
out.int("#{prefix}load_delay", @load_delay).bool("#{prefix}reload", @reload)
|
|
14
|
+
out.bool("#{prefix}underflowed", @underflowed).int("#{prefix}oneshot_linger", @oneshot_linger)
|
|
15
|
+
out.bool("#{prefix}toggle", @toggle)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def load_fields(input, prefix)
|
|
19
|
+
@counter = input.word("#{prefix}counter", @counter)
|
|
20
|
+
@latch = input.word("#{prefix}latch", @latch)
|
|
21
|
+
@pipe = input.masked("#{prefix}pipe", @pipe, 0b11)
|
|
22
|
+
@load_delay = input.int("#{prefix}load_delay", @load_delay)
|
|
23
|
+
@reload = input.bool("#{prefix}reload", @reload)
|
|
24
|
+
@underflowed = input.bool("#{prefix}underflowed", @underflowed)
|
|
25
|
+
@oneshot_linger = input.int("#{prefix}oneshot_linger", @oneshot_linger)
|
|
26
|
+
@toggle = input.bool("#{prefix}toggle", @toggle)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def restored! = settle
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
include KeyedState
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class InterruptRegister
|
|
36
|
+
# The interrupt register's fields in a keyed snapshot module, under
|
|
37
|
+
# `prefix`: the mask, the flags, an assert on its way and the reads
|
|
38
|
+
# whose acknowledge is still landing.
|
|
39
|
+
module KeyedState
|
|
40
|
+
def save_fields(out, prefix)
|
|
41
|
+
out.int("#{prefix}mask", @mask.value).int("#{prefix}status", @status.value)
|
|
42
|
+
out.int("#{prefix}pending", @pending)
|
|
43
|
+
out.optional_int("#{prefix}read", @read).optional_int("#{prefix}read_last_cycle", @read_last_cycle)
|
|
44
|
+
out.optional_int("#{prefix}read_two_cycles_ago", @read_two_cycles_ago)
|
|
45
|
+
out.bool("#{prefix}timer_b_bug", @timer_b_bug)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def load_fields(input, prefix)
|
|
49
|
+
@mask.value = input.byte("#{prefix}mask", @mask.value)
|
|
50
|
+
@status.value = input.byte("#{prefix}status", @status.value)
|
|
51
|
+
@pending = input.int("#{prefix}pending", @pending)
|
|
52
|
+
@read = input.optional_int("#{prefix}read")
|
|
53
|
+
@read_last_cycle = input.optional_int("#{prefix}read_last_cycle")
|
|
54
|
+
@read_two_cycles_ago = input.optional_int("#{prefix}read_two_cycles_ago")
|
|
55
|
+
@timer_b_bug = input.bool("#{prefix}timer_b_bug", @timer_b_bug)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Quiet when nothing is due and no read is recent enough to matter.
|
|
59
|
+
def restored!
|
|
60
|
+
@quiet = @pending.zero? && @read.nil? && @read_last_cycle.nil? && @read_two_cycles_ago.nil?
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
include KeyedState
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
class Serial
|
|
68
|
+
# The serial port's fields in a keyed snapshot module, under
|
|
69
|
+
# `prefix`: the registers, the bit count, the delay lines, the CNT
|
|
70
|
+
# and SP levels, and whether the next cycle can be skipped, which
|
|
71
|
+
# can lag what the delay lines show by a cycle.
|
|
72
|
+
module KeyedState
|
|
73
|
+
def save_fields(out, prefix)
|
|
74
|
+
out.int("#{prefix}data", @data).int("#{prefix}shift", @shift).int("#{prefix}steps", @steps)
|
|
75
|
+
out.optional_int("#{prefix}empty_in", @empty_in).optional_int("#{prefix}busy_in", @busy_in)
|
|
76
|
+
out.bool("#{prefix}busy", @busy).bool("#{prefix}abandoned", @abandoned)
|
|
77
|
+
out.optional_int("#{prefix}pending", @pending).bool("#{prefix}underflow_high", @underflow_high)
|
|
78
|
+
out.bool("#{prefix}in_flight", @in_flight).int("#{prefix}flight_up", @flight_up)
|
|
79
|
+
out.int("#{prefix}flight_down", @flight_down).bool("#{prefix}cnt", @cnt).bool("#{prefix}cnt_in", @cnt_in)
|
|
80
|
+
out.bool("#{prefix}sp_in", @sp_in).bool("#{prefix}sp_out", @sp_out).bool("#{prefix}idle", @idle)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def load_fields(input, prefix)
|
|
84
|
+
@data = input.byte("#{prefix}data", @data)
|
|
85
|
+
@shift = input.byte("#{prefix}shift", @shift)
|
|
86
|
+
@steps = input.int("#{prefix}steps", @steps)
|
|
87
|
+
@empty_in = input.optional_int("#{prefix}empty_in")
|
|
88
|
+
@busy_in = input.optional_int("#{prefix}busy_in")
|
|
89
|
+
@busy = input.bool("#{prefix}busy", @busy)
|
|
90
|
+
@abandoned = input.bool("#{prefix}abandoned", @abandoned)
|
|
91
|
+
@pending = input.optional_int("#{prefix}pending")
|
|
92
|
+
load_line_fields(input, prefix)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def restored! = nil
|
|
96
|
+
|
|
97
|
+
private
|
|
98
|
+
|
|
99
|
+
def load_line_fields(input, prefix)
|
|
100
|
+
@underflow_high = input.bool("#{prefix}underflow_high", @underflow_high)
|
|
101
|
+
@in_flight = input.bool("#{prefix}in_flight", @in_flight)
|
|
102
|
+
@flight_up = input.int("#{prefix}flight_up", @flight_up)
|
|
103
|
+
@flight_down = input.int("#{prefix}flight_down", @flight_down)
|
|
104
|
+
@cnt = input.bool("#{prefix}cnt", @cnt)
|
|
105
|
+
@cnt_in = input.bool("#{prefix}cnt_in", @cnt_in)
|
|
106
|
+
@sp_in = input.bool("#{prefix}sp_in", @sp_in)
|
|
107
|
+
@sp_out = input.bool("#{prefix}sp_out", @sp_out)
|
|
108
|
+
@idle = input.bool("#{prefix}idle", @idle)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
include KeyedState
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
class TimeOfDay
|
|
116
|
+
# The TOD clock's fields in a keyed snapshot module, under `prefix`:
|
|
117
|
+
# the clock, the alarm and a latched read field by field, the
|
|
118
|
+
# pulses towards the next tenth, and the mains divider's phase in
|
|
119
|
+
# cycle·Hz (it reaches the clock rate when a pulse arrives). The
|
|
120
|
+
# 50/60 Hz divider comes from CRA bit 7 on load.
|
|
121
|
+
module KeyedState
|
|
122
|
+
def save_fields(out, prefix)
|
|
123
|
+
out.int("#{prefix}mains_phase", @accumulator).int("#{prefix}pulses", @pulses)
|
|
124
|
+
out.bool("#{prefix}stopped", @stopped).bool("#{prefix}alarm_pending", @alarm_pending)
|
|
125
|
+
FIELDS.each do |field|
|
|
126
|
+
out.int("#{prefix}clock.#{field}", @clock[field]).int("#{prefix}alarm.#{field}", @alarm[field])
|
|
127
|
+
end
|
|
128
|
+
latch = @latch
|
|
129
|
+
FIELDS.each { |field| out.int("#{prefix}latch.#{field}", latch[field]) } if latch
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def load_fields(input, prefix)
|
|
133
|
+
@accumulator = input.int("#{prefix}mains_phase", @accumulator)
|
|
134
|
+
@pulses = input.int("#{prefix}pulses", @pulses)
|
|
135
|
+
@stopped = input.bool("#{prefix}stopped", @stopped)
|
|
136
|
+
@alarm_pending = input.bool("#{prefix}alarm_pending", @alarm_pending)
|
|
137
|
+
FIELDS.each do |field|
|
|
138
|
+
@clock[field] = input.byte("#{prefix}clock.#{field}", @clock[field])
|
|
139
|
+
@alarm[field] = input.byte("#{prefix}alarm.#{field}", @alarm[field])
|
|
140
|
+
end
|
|
141
|
+
load_latch_fields(input, prefix)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def restored!(fifty_hz)
|
|
145
|
+
self.fifty_hz = fifty_hz
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
private
|
|
149
|
+
|
|
150
|
+
def load_latch_fields(input, prefix)
|
|
151
|
+
return @latch = nil if input.optional_int("#{prefix}latch.hours").nil?
|
|
152
|
+
|
|
153
|
+
@latch = FIELDS.to_h { |field| [field, input.byte("#{prefix}latch.#{field}", 0)] }
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
include KeyedState
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# The CIA's fields in a keyed snapshot module (Snapshot::Keyed): the
|
|
161
|
+
# ports, the control registers, the PB4 and CNT levels, and its parts
|
|
162
|
+
# under ta., tb., icr., sdr. and tod.
|
|
163
|
+
module KeyedState
|
|
164
|
+
def save_fields(out)
|
|
165
|
+
out.int("pra", @data_port_a).int("prb", @data_port_b).int("ddra", @data_dir_a).int("ddrb", @data_dir_b)
|
|
166
|
+
out.int("cra", @control_a.value).int("crb", @control_b.value)
|
|
167
|
+
out.bool("pb4_high", @port_b4_high).bool("pb4_driven_high", @port_b4_driven_high)
|
|
168
|
+
out.bool("cnt_high", @cnt_high).bool("cnt_rise", @cnt_rise)
|
|
169
|
+
@ta.save_fields(out, "ta.")
|
|
170
|
+
@tb.save_fields(out, "tb.")
|
|
171
|
+
@icr.save_fields(out, "icr.")
|
|
172
|
+
@serial.save_fields(out, "sdr.")
|
|
173
|
+
@tod.save_fields(out, "tod.")
|
|
174
|
+
out
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def load_fields(input)
|
|
178
|
+
@data_port_a = input.byte("pra", @data_port_a)
|
|
179
|
+
@data_port_b = input.byte("prb", @data_port_b)
|
|
180
|
+
@data_dir_a = input.byte("ddra", @data_dir_a)
|
|
181
|
+
@data_dir_b = input.byte("ddrb", @data_dir_b)
|
|
182
|
+
@control_a.value = input.byte("cra", @control_a.value)
|
|
183
|
+
@control_b.value = input.byte("crb", @control_b.value)
|
|
184
|
+
@port_b4_high = input.bool("pb4_high", @port_b4_high)
|
|
185
|
+
@port_b4_driven_high = input.bool("pb4_driven_high", @port_b4_driven_high)
|
|
186
|
+
@cnt_high = input.bool("cnt_high", @cnt_high)
|
|
187
|
+
@cnt_rise = input.bool("cnt_rise", @cnt_rise)
|
|
188
|
+
load_part_fields(input)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def restored!
|
|
192
|
+
@ta.restored!
|
|
193
|
+
@tb.restored!
|
|
194
|
+
@icr.restored!
|
|
195
|
+
@serial.restored!
|
|
196
|
+
@tod.restored!(@control_a.clock_frequency?)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
private
|
|
200
|
+
|
|
201
|
+
def load_part_fields(input)
|
|
202
|
+
@ta.load_fields(input, "ta.")
|
|
203
|
+
@tb.load_fields(input, "tb.")
|
|
204
|
+
@icr.load_fields(input, "icr.")
|
|
205
|
+
@serial.load_fields(input, "sdr.")
|
|
206
|
+
@tod.load_fields(input, "tod.")
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
include KeyedState
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class CIA
|
|
6
|
+
# The serial shift register and the CNT line that clocks it.
|
|
7
|
+
#
|
|
8
|
+
# With CRA bit 6 clear the port is an input: SP is sampled on every
|
|
9
|
+
# rising CNT edge, and the byte reaches the data register after eight of
|
|
10
|
+
# them. With the bit set the CIA drives CNT itself, toggling it on every
|
|
11
|
+
# timer A underflow, so a byte takes sixteen underflows to go out. CNT falls
|
|
12
|
+
# as each bit is put on SP, and rises again to clock it in.
|
|
13
|
+
#
|
|
14
|
+
# The register counts itself empty as soon as the eighth bit is on SP,
|
|
15
|
+
# fifteen underflows in: the serial flag follows a few cycles later
|
|
16
|
+
# rather than waiting for the sixteenth underflow, and a byte written
|
|
17
|
+
# from that point on goes out on the next one.
|
|
18
|
+
class Serial
|
|
19
|
+
BITS = 8
|
|
20
|
+
|
|
21
|
+
# A byte written to the data register reaches the shift register one
|
|
22
|
+
# cycle later. The empty countdown starts on the underflow that puts
|
|
23
|
+
# the eighth bit on SP and is decremented on that same cycle, so the
|
|
24
|
+
# flag lands four cycles after it.
|
|
25
|
+
LOAD_DELAY = 1
|
|
26
|
+
EMPTY_DELAY = 5
|
|
27
|
+
BUSY_DELAY = 5
|
|
28
|
+
|
|
29
|
+
# The logic watching the shift register runs a few cycles behind it,
|
|
30
|
+
# so the level saying a bit is still on its way out is scheduled
|
|
31
|
+
# through a delay line: a bit set at position 7 - n takes effect n
|
|
32
|
+
# cycles later. Putting a bit on SP raises the level after one cycle
|
|
33
|
+
# and drops it again after two before raising it for good after
|
|
34
|
+
# three; the eighth bit skips straight to the last of those. CNT
|
|
35
|
+
# rising over a bit lowers the level four cycles later.
|
|
36
|
+
IN_FLIGHT = 0x50
|
|
37
|
+
LAST_IN_FLIGHT = 0x10
|
|
38
|
+
BOUNCE = 0x20
|
|
39
|
+
SETTLED = 0x08
|
|
40
|
+
|
|
41
|
+
attr_reader :data, :sp_out, :cnt, :cnt_in, :idle
|
|
42
|
+
attr_accessor :sp_in
|
|
43
|
+
|
|
44
|
+
def initialize(control)
|
|
45
|
+
@control = control
|
|
46
|
+
@data = 0x0
|
|
47
|
+
@shift = 0x0
|
|
48
|
+
@steps = 0
|
|
49
|
+
@empty_in = nil
|
|
50
|
+
@busy_in = nil
|
|
51
|
+
@busy = false
|
|
52
|
+
@abandoned = false
|
|
53
|
+
@pending = nil
|
|
54
|
+
@underflow_high = false
|
|
55
|
+
@in_flight = false
|
|
56
|
+
@flight_up = 0x0
|
|
57
|
+
@flight_down = 0x0
|
|
58
|
+
@idle = true
|
|
59
|
+
# Nothing drives the user port, so both lines float high.
|
|
60
|
+
@cnt = true
|
|
61
|
+
@cnt_in = true
|
|
62
|
+
@sp_in = true
|
|
63
|
+
@sp_out = true
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# The bits shifted so far, and the byte waiting to go out after the
|
|
67
|
+
# one shifting.
|
|
68
|
+
attr_reader :steps, :pending
|
|
69
|
+
|
|
70
|
+
def shift_register = @shift
|
|
71
|
+
|
|
72
|
+
# Sets the data register and the shift register, as a VICE snapshot
|
|
73
|
+
# gives them.
|
|
74
|
+
def restore_shift(data, shift)
|
|
75
|
+
@data = data
|
|
76
|
+
@shift = shift
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def output?
|
|
80
|
+
@control.serial_mode?
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Whether nothing is counting down or in the delay lines, so only
|
|
84
|
+
# timer A's underflows reach the register.
|
|
85
|
+
def drained? = idle?
|
|
86
|
+
|
|
87
|
+
# Takes timer A's underflow line as cycle! would have left it, with
|
|
88
|
+
# +underflowed+ its level on the last cycle, for a CIA run without
|
|
89
|
+
# the register in use (CIA#fast_forward).
|
|
90
|
+
def follow_underflow(underflowed)
|
|
91
|
+
@underflow_high = underflowed
|
|
92
|
+
@idle = !underflowed
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def cnt_in=(level)
|
|
96
|
+
@cnt_in = level
|
|
97
|
+
@cnt = level unless output?
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def write(value)
|
|
101
|
+
@data = value
|
|
102
|
+
@pending = LOAD_DELAY
|
|
103
|
+
@idle = false
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Clocked every cycle with timer A's underflow line. Yields once the
|
|
107
|
+
# shift register reports itself empty, which it does without waiting
|
|
108
|
+
# for the underflow that raises CNT over the eighth bit.
|
|
109
|
+
def cycle!(underflowed)
|
|
110
|
+
return if @idle && !underflowed
|
|
111
|
+
|
|
112
|
+
shift(underflowed)
|
|
113
|
+
@pending -= 1 if @pending&.positive?
|
|
114
|
+
drain_flight
|
|
115
|
+
count_busy
|
|
116
|
+
@idle = !underflowed && idle?
|
|
117
|
+
return if @empty_in.nil?
|
|
118
|
+
|
|
119
|
+
@empty_in -= 1
|
|
120
|
+
return unless @empty_in.zero?
|
|
121
|
+
|
|
122
|
+
@empty_in = nil
|
|
123
|
+
@busy = false
|
|
124
|
+
yield
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Clocked by rising CNT edges while receiving. Yields once a whole
|
|
128
|
+
# byte has arrived.
|
|
129
|
+
def rising_edge!
|
|
130
|
+
return if output?
|
|
131
|
+
|
|
132
|
+
@shift = ((@shift << 1) | (@sp_in ? 1 : 0)) & 0xff
|
|
133
|
+
@steps += 1
|
|
134
|
+
return unless @steps == BITS
|
|
135
|
+
|
|
136
|
+
@steps = 0
|
|
137
|
+
@data = @shift
|
|
138
|
+
yield if block_given?
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# A mode change drops the byte in flight and hands CNT back to
|
|
142
|
+
# whichever side drives it now, and yields: that byte counts as gone.
|
|
143
|
+
# Handing the port over as an input tears a transmission down, so a
|
|
144
|
+
# busy register reports it; the same change latches how far the bit
|
|
145
|
+
# in flight had got, and taking the port back reports that.
|
|
146
|
+
def reset!
|
|
147
|
+
abandoned = output? ? @abandoned : @busy
|
|
148
|
+
@abandoned = output? ? false : @in_flight
|
|
149
|
+
@in_flight = false
|
|
150
|
+
@steps = 0
|
|
151
|
+
@empty_in = nil
|
|
152
|
+
@busy_in = nil
|
|
153
|
+
@busy = false
|
|
154
|
+
@pending = nil
|
|
155
|
+
@cnt = output? || @cnt_in
|
|
156
|
+
yield if abandoned
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
private
|
|
160
|
+
|
|
161
|
+
# Without an underflow, a register with nothing counting down and
|
|
162
|
+
# nothing in the delay lines has nothing to do on a cycle.
|
|
163
|
+
def idle?
|
|
164
|
+
!@pending&.positive? && (@flight_up | @flight_down).zero? &&
|
|
165
|
+
@busy_in.nil? && @empty_in.nil?
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# The shift register picks up a waiting byte whenever the underflow
|
|
169
|
+
# line is asserted, but every half-step after that needs a fresh edge
|
|
170
|
+
# on it. A zero latch holds the line down for good rather than
|
|
171
|
+
# pulsing it, so such a byte stops after its first bit and never
|
|
172
|
+
# reaches the data register.
|
|
173
|
+
def shift(underflowed)
|
|
174
|
+
edge = underflowed && !@underflow_high
|
|
175
|
+
@underflow_high = underflowed
|
|
176
|
+
clock(edge) if underflowed && output?
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def clock(edge)
|
|
180
|
+
start if @steps <= 1
|
|
181
|
+
if @steps.zero?
|
|
182
|
+
@flight_down |= SETTLED
|
|
183
|
+
elsif edge || @steps == BITS * 2
|
|
184
|
+
half_step
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def half_step
|
|
189
|
+
@steps -= 1
|
|
190
|
+
@cnt = @steps.even?
|
|
191
|
+
if @cnt
|
|
192
|
+
@flight_down |= SETTLED
|
|
193
|
+
else
|
|
194
|
+
shift_out
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# The register reads as busy from a few cycles after the first bit
|
|
199
|
+
# reaches SP until it reports itself empty over the eighth.
|
|
200
|
+
def mark_busy
|
|
201
|
+
case @steps
|
|
202
|
+
when (BITS * 2) - 1 then @busy_in = BUSY_DELAY
|
|
203
|
+
when 1
|
|
204
|
+
@empty_in = EMPTY_DELAY
|
|
205
|
+
@busy_in = nil
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def count_busy
|
|
210
|
+
return if @busy_in.nil?
|
|
211
|
+
|
|
212
|
+
@busy_in -= 1
|
|
213
|
+
return unless @busy_in.zero?
|
|
214
|
+
|
|
215
|
+
@busy_in = nil
|
|
216
|
+
@busy = true
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def drain_flight
|
|
220
|
+
@in_flight = false if @flight_down.anybits?(0x80)
|
|
221
|
+
@flight_down = (@flight_down << 1) & 0xff
|
|
222
|
+
@in_flight = true if @flight_up.anybits?(0x80)
|
|
223
|
+
@flight_up = (@flight_up << 1) & 0xff
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# A byte only moves out of the data register once the one before it
|
|
227
|
+
# has put its last bit on SP.
|
|
228
|
+
def start
|
|
229
|
+
return unless @pending&.zero?
|
|
230
|
+
|
|
231
|
+
@pending = nil
|
|
232
|
+
@shift = @data
|
|
233
|
+
@steps = BITS * 2
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def shift_out
|
|
237
|
+
@sp_out = @shift.anybits?(0x80)
|
|
238
|
+
@shift = (@shift << 1) & 0xff
|
|
239
|
+
mark_busy
|
|
240
|
+
@flight_up |= @steps == 1 ? LAST_IN_FLIGHT : IN_FLIGHT
|
|
241
|
+
@flight_down |= BOUNCE
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
end
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class CIA
|
|
6
|
+
class TimeOfDay
|
|
7
|
+
# The TOD pin is fed from the AC supply. A CIA passes its region's
|
|
8
|
+
# clock and mains frequency, and these are PAL's.
|
|
9
|
+
CLOCK_HZ = Region::PAL.clock_hz
|
|
10
|
+
MAINS_HZ = Region::PAL.mains_hz
|
|
11
|
+
|
|
12
|
+
FIELDS = %i[tenths seconds minutes hours].freeze
|
|
13
|
+
|
|
14
|
+
def initialize(clock_hz: CLOCK_HZ, mains_hz: MAINS_HZ)
|
|
15
|
+
# The accumulator advances mains_hz per cycle, so a TOD pin pulse has
|
|
16
|
+
# arrived when it reaches clock_hz. Integer math keeps it exact.
|
|
17
|
+
@cycles_per_pulse = clock_hz
|
|
18
|
+
@mains_hz = mains_hz
|
|
19
|
+
@accumulator = 0
|
|
20
|
+
@pulses = 0
|
|
21
|
+
@clock = { tenths: 0x00, seconds: 0x00, minutes: 0x00, hours: 0x01 }
|
|
22
|
+
@alarm = { tenths: 0x00, seconds: 0x00, minutes: 0x00, hours: 0x00 }
|
|
23
|
+
@latch = nil
|
|
24
|
+
@stopped = true
|
|
25
|
+
@alarm_pending = false
|
|
26
|
+
self.fifty_hz = false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# CRA bit 7 divides the TOD pin by 5 instead of 6. The divider has to
|
|
30
|
+
# match the pin frequency to keep time, so PAL software selects 50 Hz.
|
|
31
|
+
def fifty_hz=(enabled)
|
|
32
|
+
@match = enabled ? 4 : 5
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Whether the clock is stopped, or gets no pulses on its pin, with no
|
|
36
|
+
# alarm to raise, so its cycles move only the divider's phase.
|
|
37
|
+
def quiet? = (@stopped || @mains_hz.zero?) && !@alarm_pending
|
|
38
|
+
|
|
39
|
+
# Runs +cycles+ quiet cycles at once.
|
|
40
|
+
def fast_forward(cycles)
|
|
41
|
+
@accumulator = (@accumulator + (cycles * @mains_hz)) % @cycles_per_pulse
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def cycle!
|
|
45
|
+
@accumulator += @mains_hz
|
|
46
|
+
pulse! if @accumulator >= @cycles_per_pulse
|
|
47
|
+
return unless @alarm_pending
|
|
48
|
+
|
|
49
|
+
@alarm_pending = false
|
|
50
|
+
yield if block_given?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def tenths
|
|
54
|
+
value = (@latch || @clock)[:tenths]
|
|
55
|
+
@latch = nil
|
|
56
|
+
value
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def seconds = (@latch || @clock)[:seconds]
|
|
60
|
+
def minutes = (@latch || @clock)[:minutes]
|
|
61
|
+
|
|
62
|
+
def hours
|
|
63
|
+
@latch ||= @clock.dup
|
|
64
|
+
@latch[:hours]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
attr_reader :pulses
|
|
68
|
+
|
|
69
|
+
# The clock as a read of the tenths would see it: the latch while the
|
|
70
|
+
# clock is latched. In FIELDS order.
|
|
71
|
+
def latched_fields = FIELDS.map { |field| (@latch || @clock)[field] }
|
|
72
|
+
|
|
73
|
+
# The cycles until the clock next steps a tenth, as VICE counts them.
|
|
74
|
+
def cycles_to_tenth
|
|
75
|
+
to_pulse = (@cycles_per_pulse - @accumulator + @mains_hz - 1) / @mains_hz
|
|
76
|
+
to_pulse + ([@match - @pulses, 0].max * @cycles_per_pulse / @mains_hz)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Sets the clock, the alarm and the latch from VICE's fields, in FIELDS
|
|
80
|
+
# order, the latch nil while unlatched.
|
|
81
|
+
def restore_fields(clock, alarm, latch)
|
|
82
|
+
FIELDS.each_with_index do |field, i|
|
|
83
|
+
@clock[field] = clock[i]
|
|
84
|
+
@alarm[field] = alarm[i]
|
|
85
|
+
end
|
|
86
|
+
@latch = latch && FIELDS.each_with_index.to_h { |field, i| [field, latch[i]] }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Sets whether the clock is stopped, the pulses counted towards the
|
|
90
|
+
# next tenth and the cycles until it, placing the divider so the tenth
|
|
91
|
+
# lands then.
|
|
92
|
+
def restore_divider(stopped, pulses, cycles_to_tenth)
|
|
93
|
+
@stopped = stopped
|
|
94
|
+
@pulses = pulses
|
|
95
|
+
to_pulse = cycles_to_tenth - ([@match - pulses, 0].max * @cycles_per_pulse / @mains_hz)
|
|
96
|
+
@accumulator = (@cycles_per_pulse - (to_pulse * @mains_hz)).clamp(0, @cycles_per_pulse - 1)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# The clock and alarm as stored, read without latching the clock.
|
|
100
|
+
def registers
|
|
101
|
+
[@clock[:tenths], @clock[:seconds], @clock[:minutes], @clock[:hours],
|
|
102
|
+
@alarm[:tenths], @alarm[:seconds], @alarm[:minutes], @alarm[:hours],
|
|
103
|
+
@stopped ? 1 : 0, @latch ? 1 : 0]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def write(field, value, alarm:)
|
|
107
|
+
# The frequency counter is held clear while the clock is stopped, and
|
|
108
|
+
# starts counting again from the write to tenths that restarts it.
|
|
109
|
+
if field == :tenths && !alarm && @stopped
|
|
110
|
+
@pulses = 0
|
|
111
|
+
@stopped = false
|
|
112
|
+
end
|
|
113
|
+
store(field, value & (field == :tenths ? 0x0f : 0x7f), alarm: alarm)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# 12-hour BCD value, bit 7 is the AM/PM flag.
|
|
117
|
+
def write_hours(value, alarm:)
|
|
118
|
+
value &= 0x9f
|
|
119
|
+
# Writing 12 to the hour register flips the AM/PM bit, the same way a
|
|
120
|
+
# carry into 12 does. Writing the alarm hours does not.
|
|
121
|
+
value ^= 0x80 if !alarm && (value & 0x1f) == 0x12
|
|
122
|
+
# Halt the clock when writing hours, so that it doesn't
|
|
123
|
+
# advance mid-update.
|
|
124
|
+
@stopped = true unless alarm
|
|
125
|
+
store(:hours, value, alarm: alarm)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
private
|
|
129
|
+
|
|
130
|
+
def store(field, value, alarm:)
|
|
131
|
+
target = alarm ? @alarm : @clock
|
|
132
|
+
return if target[field] == value
|
|
133
|
+
|
|
134
|
+
target[field] = value
|
|
135
|
+
@alarm_pending = true if alarm?
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def pulse!
|
|
139
|
+
@accumulator -= @cycles_per_pulse
|
|
140
|
+
return if @stopped
|
|
141
|
+
|
|
142
|
+
# A three-bit ring counter with six states, compared against the
|
|
143
|
+
# divider on each pin pulse rather than on its way past it.
|
|
144
|
+
if @pulses == @match
|
|
145
|
+
@pulses = 0
|
|
146
|
+
advance
|
|
147
|
+
else
|
|
148
|
+
@pulses += 1
|
|
149
|
+
@pulses = 0 if @pulses > 5
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def advance
|
|
154
|
+
tenths = (@clock[:tenths] + 1) & 0x0f
|
|
155
|
+
@clock[:tenths] = tenths == 10 ? 0 : tenths
|
|
156
|
+
carry_seconds if tenths == 10
|
|
157
|
+
@alarm_pending = true if alarm?
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def carry_seconds
|
|
161
|
+
return unless advance_pair(:seconds)
|
|
162
|
+
return unless advance_pair(:minutes)
|
|
163
|
+
|
|
164
|
+
advance_hours
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Seconds and minutes hold a four-bit low digit that carries at ten into
|
|
168
|
+
# a three-bit high digit that carries out at six. Both are plain binary
|
|
169
|
+
# counters, so out-of-range BCD counts up from where it was written.
|
|
170
|
+
def advance_pair(field)
|
|
171
|
+
low = ((@clock[field] & 0x0f) + 1) & 0x0f
|
|
172
|
+
high = (@clock[field] >> 4) & 0x07
|
|
173
|
+
carry = false
|
|
174
|
+
|
|
175
|
+
if low == 10
|
|
176
|
+
low = 0
|
|
177
|
+
high = (high + 1) & 0x07
|
|
178
|
+
if high == 6
|
|
179
|
+
high = 0
|
|
180
|
+
carry = true
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
@clock[field] = (high << 4) | low
|
|
185
|
+
carry
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# The hour runs 9 -> 10 and 12 -> 1 by swapping its two digits, and the
|
|
189
|
+
# AM/PM bit flips as it passes through 12.
|
|
190
|
+
def advance_hours
|
|
191
|
+
pm = @clock[:hours] & 0x80
|
|
192
|
+
high = (@clock[:hours] >> 4) & 0x01
|
|
193
|
+
low = @clock[:hours] & 0x0f
|
|
194
|
+
|
|
195
|
+
if (high == 1 && low == 2) || (high.zero? && low == 9)
|
|
196
|
+
low = high
|
|
197
|
+
high ^= 1
|
|
198
|
+
else
|
|
199
|
+
low = (low + 1) & 0x0f
|
|
200
|
+
pm ^= 0x80 if high == 1 && low == 2
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
@clock[:hours] = pm | (high << 4) | low
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def alarm? = @clock == @alarm
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|