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,142 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class VICI
|
|
6
|
+
class Sound
|
|
7
|
+
# The sound's fields in a keyed snapshot module, under `prefix`:
|
|
8
|
+
# the voices' shift registers, the noise LFSR, the level, and when
|
|
9
|
+
# each voice next shifts, in cycles from the machine's clock, with
|
|
10
|
+
# how far behind the clock the voices last ran. The volume and the
|
|
11
|
+
# voices' frequencies come from the VIC's registers on load.
|
|
12
|
+
module KeyedState
|
|
13
|
+
def save_fields(out, prefix)
|
|
14
|
+
now = @clock.cycles
|
|
15
|
+
run_to(now)
|
|
16
|
+
out.ints("#{prefix}shift_registers", @shift_registers).int("#{prefix}lfsr", @lfsr)
|
|
17
|
+
out.int("#{prefix}level", @level).int("#{prefix}ran_ago", now - @time)
|
|
18
|
+
out.ints("#{prefix}next_shifts", @next_shifts.map { |due| due - now })
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def load_fields(input, prefix)
|
|
22
|
+
now = @clock.cycles
|
|
23
|
+
input.ints_into("#{prefix}shift_registers", @shift_registers)
|
|
24
|
+
@lfsr = input.masked("#{prefix}lfsr", @lfsr, 0xffff)
|
|
25
|
+
@level = input.int("#{prefix}level", @level)
|
|
26
|
+
@time = now - input.int("#{prefix}ran_ago", now - @time)
|
|
27
|
+
relative = input.ints("#{prefix}next_shifts", @next_shifts.map { |due| due - now })
|
|
28
|
+
VOICES.times { |voice| @next_shifts[voice] = now + relative.fetch(voice, 0) }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# $900A to $900E as written.
|
|
32
|
+
def restore_registers(registers)
|
|
33
|
+
@volume = registers[0x0e] & 0x0f
|
|
34
|
+
VOICES.times do |voice|
|
|
35
|
+
value = registers[0x0a + voice]
|
|
36
|
+
@frequencies[voice] = value & 0x7f
|
|
37
|
+
@enabled[voice] = value >= 0x80
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
include KeyedState
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class Painter
|
|
46
|
+
# The lines' fetches and the line going out, as this painter lays
|
|
47
|
+
# them out (VICI::LINE_LAYOUT), and the picture.
|
|
48
|
+
module KeyedState
|
|
49
|
+
def save_fields(out)
|
|
50
|
+
out.int("line.row", @row).int("line.painted", @painted).bool("line.written", @written)
|
|
51
|
+
out.bytes("line.patterns", @patterns).bytes("line.colors", @colors)
|
|
52
|
+
out.ints("line.counts", @counts).ints("line.starts", @starts).bytes("display", @display)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def load_fields(input, layout)
|
|
56
|
+
input.bytes_into("display", @display)
|
|
57
|
+
return unless layout
|
|
58
|
+
|
|
59
|
+
@row = input.int("line.row", @row)
|
|
60
|
+
@painted = input.int("line.painted", @painted)
|
|
61
|
+
@written = input.bool("line.written", @written)
|
|
62
|
+
input.bytes_into("line.patterns", @patterns)
|
|
63
|
+
input.bytes_into("line.colors", @colors)
|
|
64
|
+
input.ints_into("line.counts", @counts)
|
|
65
|
+
input.ints_into("line.starts", @starts)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# The colours as $900E and $900F hold them, every line to be
|
|
69
|
+
# painted afresh, and the whole display changed.
|
|
70
|
+
def restored!(registers)
|
|
71
|
+
@border = registers[0x0f] & 0x07
|
|
72
|
+
@background = registers[0x0f] >> 4
|
|
73
|
+
@reverse = registers[0x0f].nobits?(0x08)
|
|
74
|
+
@aux = registers[0x0e] >> 4
|
|
75
|
+
@stale.fill(true)
|
|
76
|
+
@memo_keys.fill(-1)
|
|
77
|
+
@dirty_lines.fill(true)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
include KeyedState
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# The shape of the painter's per-line fields. A snapshot whose
|
|
85
|
+
# line.layout differs leaves them at power-on.
|
|
86
|
+
LINE_LAYOUT = 1
|
|
87
|
+
|
|
88
|
+
# The VIC-I's fields in a keyed snapshot module (Snapshot::Keyed): the
|
|
89
|
+
# registers, the beam, the text window's counters and the fetch in
|
|
90
|
+
# flight, the painter's lines under line.*, the picture, and the sound
|
|
91
|
+
# under sound.* What the registers decode to, where the line's fetches
|
|
92
|
+
# end and the next event are worked out on load.
|
|
93
|
+
module KeyedState
|
|
94
|
+
def save_fields(out)
|
|
95
|
+
out.bytes("registers", @registers).int("raster", @rasterline).int("column", @column)
|
|
96
|
+
out.bool("window_open", @window_open).bool("window_done", @window_done).int("row_start", @row_start)
|
|
97
|
+
out.int("matrix", @matrix).int("char_line", @char_line).int("text_rows", @text_rows)
|
|
98
|
+
out.int("fetch_from", @fetch_from).int("fetched", @fetched).int("code", @code)
|
|
99
|
+
out.int("line.layout", LINE_LAYOUT)
|
|
100
|
+
@painter.save_fields(out)
|
|
101
|
+
@sound&.save_fields(out, "sound.")
|
|
102
|
+
out
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def load_fields(input)
|
|
106
|
+
input.bytes_into("registers", @registers)
|
|
107
|
+
@rasterline = input.int("raster", @rasterline)
|
|
108
|
+
@column = input.int("column", @column)
|
|
109
|
+
@window_open = input.bool("window_open", @window_open)
|
|
110
|
+
@window_done = input.bool("window_done", @window_done)
|
|
111
|
+
@row_start = input.int("row_start", @row_start)
|
|
112
|
+
@matrix = input.int("matrix", @matrix)
|
|
113
|
+
@char_line = input.int("char_line", @char_line)
|
|
114
|
+
@text_rows = input.int("text_rows", @text_rows)
|
|
115
|
+
@fetch_from = input.int("fetch_from", @fetch_from)
|
|
116
|
+
@fetched = input.int("fetched", @fetched)
|
|
117
|
+
@code = input.byte("code", @code)
|
|
118
|
+
line = input.int("line.layout", 0) == LINE_LAYOUT
|
|
119
|
+
input.adjust("line in progress from another renderer, restarted") unless line || input.missing?
|
|
120
|
+
@painter.load_fields(input, line)
|
|
121
|
+
@sound&.load_fields(input, "sound.")
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def restored!
|
|
125
|
+
@origin_x = @registers[0] & 0x7f
|
|
126
|
+
@columns = @registers[2] & 0x7f
|
|
127
|
+
@origin_y = @registers[1]
|
|
128
|
+
rows_written(@registers[3])
|
|
129
|
+
bases_written
|
|
130
|
+
@slot = @rasterline * Painter::SLOTS
|
|
131
|
+
@fetch_to = 0
|
|
132
|
+
fetches_end if @window_open
|
|
133
|
+
schedule
|
|
134
|
+
@painter.restored!(@registers)
|
|
135
|
+
@sound&.restore_registers(@registers)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
include KeyedState
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Badline
|
|
4
|
-
|
|
5
|
-
class
|
|
4
|
+
module Chips
|
|
5
|
+
class VICI
|
|
6
6
|
# Paints the VIC-I's display a line at a time from what the VIC
|
|
7
7
|
# fetched for it: each character's pattern byte and colour nibble, the
|
|
8
8
|
# pixel its first character starts at and how many it fetched. Each
|
|
@@ -70,34 +70,6 @@ module Badline
|
|
|
70
70
|
@dirty_lines.fill(false)
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
-
# The colours, the line being painted and how far, what each line
|
|
74
|
-
# fetched, and the display, for a snapshot. Whether it renders is
|
|
75
|
-
# the host's, and a restored display is all changed.
|
|
76
|
-
def save_state(out)
|
|
77
|
-
out.int(@border).int(@background).int(@aux).boolean(@reverse)
|
|
78
|
-
out.int(@row).int(@painted).boolean(@written)
|
|
79
|
-
out.blob(@display).blob(@patterns).blob(@colors)
|
|
80
|
-
out.ints(@counts).ints(@starts).booleans(@stale).ints(@memo_keys)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def load_state(input)
|
|
84
|
-
@border = input.int
|
|
85
|
-
@background = input.int
|
|
86
|
-
@aux = input.int
|
|
87
|
-
@reverse = input.boolean?
|
|
88
|
-
@row = input.int
|
|
89
|
-
@painted = input.int
|
|
90
|
-
@written = input.boolean?
|
|
91
|
-
input.blob_into(@display)
|
|
92
|
-
input.blob_into(@patterns)
|
|
93
|
-
input.blob_into(@colors)
|
|
94
|
-
input.ints_into(@counts)
|
|
95
|
-
input.ints_into(@starts)
|
|
96
|
-
input.booleans_into(@stale)
|
|
97
|
-
input.ints_into(@memo_keys)
|
|
98
|
-
@dirty_lines.fill(true)
|
|
99
|
-
end
|
|
100
|
-
|
|
101
73
|
# Painting can be turned off, and once it's back on every line is
|
|
102
74
|
# painted afresh.
|
|
103
75
|
def render=(value)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class VICI
|
|
6
|
+
class Sound
|
|
7
|
+
# The sound's level averaged over each sample of the audio rate, then
|
|
8
|
+
# through the machine's output stage: a one-pole low-pass at 1,420 Hz
|
|
9
|
+
# and a one-pole high-pass at 158 Hz, both run at the audio rate.
|
|
10
|
+
#
|
|
11
|
+
# The two corners are fitted to xvic's step response: a voice turned
|
|
12
|
+
# on at volume 15 rises and decays back to the line as those two RC
|
|
13
|
+
# stages do, within 6 parts in 11,000.
|
|
14
|
+
class Output
|
|
15
|
+
LOW_PASS_HZ = 1_420
|
|
16
|
+
HIGH_PASS_HZ = 158
|
|
17
|
+
|
|
18
|
+
# Scales the loudest level, four voices high at volume 15, to the
|
|
19
|
+
# top of a signed 16-bit sample.
|
|
20
|
+
SCALE = 32_767.0 / 570
|
|
21
|
+
|
|
22
|
+
attr_reader :samples
|
|
23
|
+
|
|
24
|
+
# `level` is the sound's level as the recording starts, which the
|
|
25
|
+
# stage takes as settled.
|
|
26
|
+
def initialize(clock_hz:, rate:, level:)
|
|
27
|
+
@clock_hz = clock_hz
|
|
28
|
+
@rate = rate
|
|
29
|
+
@remainder = 0
|
|
30
|
+
@window = next_window
|
|
31
|
+
@left = @window
|
|
32
|
+
@sum = 0
|
|
33
|
+
@low = @drift = level.to_f
|
|
34
|
+
@low_pass = 1.0 - Math.exp(-2.0 * Math::PI * LOW_PASS_HZ / rate)
|
|
35
|
+
@high_pass = 1.0 - Math.exp(-2.0 * Math::PI * HIGH_PASS_HZ / rate)
|
|
36
|
+
@samples = []
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Adds `cycles` cycles at `level`, closing every sample they finish.
|
|
40
|
+
def hold(level, cycles)
|
|
41
|
+
left = @left
|
|
42
|
+
while cycles >= left
|
|
43
|
+
@sum += level * left
|
|
44
|
+
cycles -= left
|
|
45
|
+
close
|
|
46
|
+
left = @left
|
|
47
|
+
end
|
|
48
|
+
@sum += level * cycles
|
|
49
|
+
@left = left - cycles
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# The samples closed since the last drain.
|
|
53
|
+
def drain
|
|
54
|
+
samples = @samples
|
|
55
|
+
@samples = []
|
|
56
|
+
samples
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def close
|
|
62
|
+
@low += @low_pass * (@sum.fdiv(@window) - @low)
|
|
63
|
+
@drift += @high_pass * (@low - @drift)
|
|
64
|
+
sample = ((@low - @drift) * SCALE).round
|
|
65
|
+
sample = 32_767 if sample > 32_767
|
|
66
|
+
sample = -32_768 if sample < -32_768
|
|
67
|
+
@samples << sample
|
|
68
|
+
@sum = 0
|
|
69
|
+
@window = next_window
|
|
70
|
+
@left = @window
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Each window is a whole number of cycles, and they add up to the
|
|
74
|
+
# clock's cycles over a second.
|
|
75
|
+
def next_window
|
|
76
|
+
@remainder += @clock_hz
|
|
77
|
+
cycles = @remainder / @rate
|
|
78
|
+
@remainder -= cycles * @rate
|
|
79
|
+
cycles
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "badline/chips/vic_i/sound/output"
|
|
4
|
+
|
|
5
|
+
module Badline
|
|
6
|
+
module Chips
|
|
7
|
+
class VICI
|
|
8
|
+
# The VIC-I's sound: three square-wave voices, bass, alto and soprano at
|
|
9
|
+
# $900A-$900C, a noise voice at $900D, and the volume in $900E bits 0-3.
|
|
10
|
+
#
|
|
11
|
+
# Each voice has a 7-bit counter, ticked every 16, 8, 4 or 2 cycles from
|
|
12
|
+
# bass to noise. It counts up from the low 7 bits of its register, and
|
|
13
|
+
# on the tick it would reach 127 it reloads from the register instead.
|
|
14
|
+
# So a voice's counter comes round every 128 - ((value + 1) & 127)
|
|
15
|
+
# ticks, and the register's new value takes hold at the next reload.
|
|
16
|
+
#
|
|
17
|
+
# A tone voice's counter shifts an 8-bit shift register at each reload,
|
|
18
|
+
# bit 7 out and back into bit 0 inverted while bit 7 of the register
|
|
19
|
+
# enables the voice, and a zero while it doesn't. Bit 0 is the voice's
|
|
20
|
+
# output: a square wave of 16 shifts while the voice is on, which a
|
|
21
|
+
# voice turned off shifts out to silence.
|
|
22
|
+
#
|
|
23
|
+
# The noise voice's counter shifts a 16-bit LFSR instead, bit 0 in from
|
|
24
|
+
# the XOR of bits 3, 12, 14 and 15 while the voice is on and a one
|
|
25
|
+
# while it's off. Each time the LFSR's bit 0 rises, it shifts the noise
|
|
26
|
+
# voice's own 8-bit shift register, bit 7 back into bit 0, inverted
|
|
27
|
+
# while the voice is on. Its bit 0 is the voice's output while the voice
|
|
28
|
+
# is on, and it is silent while it's off.
|
|
29
|
+
#
|
|
30
|
+
# The output is the voices that are high, plus a little more, times the
|
|
31
|
+
# volume, so a volume write steps the output even with every voice off.
|
|
32
|
+
#
|
|
33
|
+
# The voices catch up to the current cycle whenever a write lands, the
|
|
34
|
+
# samples are drained or #catch_up! asks, one shift at a time, whether
|
|
35
|
+
# or not #record collects the output, so their state doesn't depend on
|
|
36
|
+
# whether the host plays it. Unrecorded, while every voice is off and
|
|
37
|
+
# shifted out to silence, they skip to the cycle at once.
|
|
38
|
+
class Sound
|
|
39
|
+
VOICES = 4
|
|
40
|
+
NOISE = 3
|
|
41
|
+
|
|
42
|
+
# The cycles between ticks of each voice's counter.
|
|
43
|
+
DIVIDERS = [16, 8, 4, 2].freeze
|
|
44
|
+
|
|
45
|
+
# What a voice that is high adds to the output's level, and what the
|
|
46
|
+
# output carries with every voice low, before the volume.
|
|
47
|
+
VOICE_LEVEL = 9
|
|
48
|
+
IDLE_LEVEL = 2
|
|
49
|
+
|
|
50
|
+
attr_reader :volume
|
|
51
|
+
|
|
52
|
+
# `clock` answers the machine's cycles, `clock_hz` the rate they run at.
|
|
53
|
+
def initialize(clock, clock_hz)
|
|
54
|
+
@clock = clock
|
|
55
|
+
@clock_hz = clock_hz
|
|
56
|
+
@output = nil
|
|
57
|
+
@time = 0
|
|
58
|
+
@shift_registers = Array.new(VOICES, 0)
|
|
59
|
+
@next_shifts = Array.new(VOICES, 0)
|
|
60
|
+
@frequencies = Array.new(VOICES, 0)
|
|
61
|
+
@enabled = Array.new(VOICES, false)
|
|
62
|
+
power_on!
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def model = :mos6561
|
|
66
|
+
|
|
67
|
+
# The power-on state: every register clear and the tone voices' shift
|
|
68
|
+
# registers empty. The noise voice's LFSR and shift register start full
|
|
69
|
+
# of ones, as a noise voice left off fills them.
|
|
70
|
+
def power_on!
|
|
71
|
+
now = @clock.cycles
|
|
72
|
+
run_to(now)
|
|
73
|
+
@volume = 0
|
|
74
|
+
VOICES.times do |voice|
|
|
75
|
+
@frequencies[voice] = 0
|
|
76
|
+
@enabled[voice] = false
|
|
77
|
+
@shift_registers[voice] = 0
|
|
78
|
+
divider = DIVIDERS[voice]
|
|
79
|
+
@next_shifts[voice] = ((now / divider) + 128) * divider
|
|
80
|
+
end
|
|
81
|
+
@shift_registers[NOISE] = 0xff
|
|
82
|
+
@lfsr = 0xffff
|
|
83
|
+
@level = level_now
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Starts collecting the output, averaged down to `rate` samples a
|
|
87
|
+
# second, for #drain_samples. `clock_hz` is the rate the cycles are
|
|
88
|
+
# taken to run at.
|
|
89
|
+
def record(rate:, clock_hz: @clock_hz)
|
|
90
|
+
run_to(@clock.cycles)
|
|
91
|
+
@output = Output.new(clock_hz:, rate:, level: @level)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def recording? = !@output.nil?
|
|
95
|
+
|
|
96
|
+
# Runs the voices up to the current cycle.
|
|
97
|
+
def catch_up! = run_to(@clock.cycles)
|
|
98
|
+
|
|
99
|
+
# The samples recorded since the last drain.
|
|
100
|
+
def drain_samples
|
|
101
|
+
output = @output
|
|
102
|
+
return [] if output.nil?
|
|
103
|
+
|
|
104
|
+
run_to(@clock.cycles)
|
|
105
|
+
output.drain
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# A write to $900A-$900E, which takes hold from the next cycle.
|
|
109
|
+
def write(register, value)
|
|
110
|
+
run_to(@clock.cycles + 1)
|
|
111
|
+
if register == 0x0e
|
|
112
|
+
@volume = value & 0x0f
|
|
113
|
+
else
|
|
114
|
+
voice = register - 0x0a
|
|
115
|
+
@frequencies[voice] = value & 0x7f
|
|
116
|
+
@enabled[voice] = value >= 0x80
|
|
117
|
+
end
|
|
118
|
+
@level = level_now
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# A voice's shift register as of the current cycle.
|
|
122
|
+
def shift_register(voice)
|
|
123
|
+
run_to(@clock.cycles)
|
|
124
|
+
@shift_registers[voice]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def lfsr
|
|
128
|
+
run_to(@clock.cycles)
|
|
129
|
+
@lfsr
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
private
|
|
133
|
+
|
|
134
|
+
# Runs the voices up to the start of cycle `target`, the output holding
|
|
135
|
+
# each level for the cycles it lasts.
|
|
136
|
+
def run_to(target)
|
|
137
|
+
time = @time
|
|
138
|
+
return if target <= time
|
|
139
|
+
|
|
140
|
+
output = @output
|
|
141
|
+
return skip_to(target) if output.nil? && silent?
|
|
142
|
+
|
|
143
|
+
following = next_shift
|
|
144
|
+
while following < target
|
|
145
|
+
output&.hold(@level, following - time)
|
|
146
|
+
time = following
|
|
147
|
+
shift_due(time)
|
|
148
|
+
@level = level_now
|
|
149
|
+
following = next_shift
|
|
150
|
+
end
|
|
151
|
+
output&.hold(@level, target - time)
|
|
152
|
+
@time = target
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Whether every voice is off and shifted out to where its shifts
|
|
156
|
+
# change nothing: the tone voices' registers empty and the noise
|
|
157
|
+
# voice's LFSR full of ones.
|
|
158
|
+
def silent?
|
|
159
|
+
enabled = @enabled
|
|
160
|
+
registers = @shift_registers
|
|
161
|
+
!(enabled[0] || enabled[1] || enabled[2] || enabled[NOISE]) &&
|
|
162
|
+
registers[0].zero? && registers[1].zero? && registers[2].zero? && @lfsr == 0xffff
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Moves each shift before `target` to its next turn from there,
|
|
166
|
+
# keeping its phase.
|
|
167
|
+
def skip_to(target)
|
|
168
|
+
VOICES.times do |voice|
|
|
169
|
+
due = @next_shifts[voice]
|
|
170
|
+
next if due >= target
|
|
171
|
+
|
|
172
|
+
interval = period(voice) * DIVIDERS[voice]
|
|
173
|
+
@next_shifts[voice] = due + ((target - due + interval - 1) / interval * interval)
|
|
174
|
+
end
|
|
175
|
+
@time = target
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def next_shift
|
|
179
|
+
shifts = @next_shifts
|
|
180
|
+
following = shifts[0]
|
|
181
|
+
following = shifts[1] if shifts[1] < following
|
|
182
|
+
following = shifts[2] if shifts[2] < following
|
|
183
|
+
following = shifts[3] if shifts[3] < following
|
|
184
|
+
following
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def shift_due(time)
|
|
188
|
+
shifts = @next_shifts
|
|
189
|
+
VOICES.times do |voice|
|
|
190
|
+
next unless shifts[voice] == time
|
|
191
|
+
|
|
192
|
+
voice == NOISE ? step_noise : shift_tone(voice)
|
|
193
|
+
shifts[voice] = time + (period(voice) * DIVIDERS[voice])
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def shift_tone(voice)
|
|
198
|
+
bits = @shift_registers[voice]
|
|
199
|
+
fill = @enabled[voice] && bits < 0x80 ? 1 : 0
|
|
200
|
+
@shift_registers[voice] = ((bits << 1) | fill) & 0xff
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def step_noise
|
|
204
|
+
lfsr = @lfsr
|
|
205
|
+
enabled = @enabled[NOISE]
|
|
206
|
+
fill = enabled ? ((lfsr >> 3) ^ (lfsr >> 12) ^ (lfsr >> 14) ^ (lfsr >> 15)) & 1 : 1
|
|
207
|
+
@lfsr = ((lfsr << 1) | fill) & 0xffff
|
|
208
|
+
return unless fill == 1 && lfsr.even?
|
|
209
|
+
|
|
210
|
+
bits = @shift_registers[NOISE]
|
|
211
|
+
fill = (bits >> 7) ^ (enabled ? 1 : 0)
|
|
212
|
+
@shift_registers[NOISE] = ((bits << 1) | fill) & 0xff
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# The ticks between two reloads of a voice's counter.
|
|
216
|
+
def period(voice) = 128 - ((@frequencies[voice] + 1) & 0x7f)
|
|
217
|
+
|
|
218
|
+
def level_now
|
|
219
|
+
registers = @shift_registers
|
|
220
|
+
high = (registers[0] & 1) + (registers[1] & 1) + (registers[2] & 1)
|
|
221
|
+
high += registers[NOISE] & 1 if @enabled[NOISE]
|
|
222
|
+
((high * VOICE_LEVEL) + IDLE_LEVEL) * @volume
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Badline
|
|
4
|
-
|
|
5
|
-
class
|
|
4
|
+
module Chips
|
|
5
|
+
class VICI
|
|
6
6
|
# The text window's rows: where it opens and closes, the video matrix
|
|
7
7
|
# counter and the character line, and the registers that place the
|
|
8
8
|
# window and its memory.
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "badline/
|
|
4
|
-
require "badline/
|
|
5
|
-
require "badline/
|
|
3
|
+
require "badline/chips/vic_i/painter"
|
|
4
|
+
require "badline/chips/vic_i/text_window"
|
|
5
|
+
require "badline/chips/vic_i/sound"
|
|
6
|
+
require "badline/chips/vic_i/keyed_parts"
|
|
6
7
|
|
|
7
8
|
module Badline
|
|
8
|
-
|
|
9
|
+
module Chips
|
|
9
10
|
# The VIC-I, the 6561 on PAL machines: its sixteen registers, the
|
|
10
11
|
# raster, the text window's fetches over the V-bus and the picture. The
|
|
11
12
|
# writes to the sound's registers, $900A-$900E, go on to the Sound
|
|
@@ -39,9 +40,8 @@ module Badline
|
|
|
39
40
|
# display's lines start 6 cycles after the raster count moves, as
|
|
40
41
|
# xvic's view of the frame does, so the character fetched 16 cycles
|
|
41
42
|
# into the line lands 48 pixels in. Lines 0-27 are blanked.
|
|
42
|
-
class
|
|
43
|
+
class VICI
|
|
43
44
|
include TextWindow
|
|
44
|
-
include SavedState
|
|
45
45
|
|
|
46
46
|
# What a VIC-I sets for the machine: the clock, the raster's cycles
|
|
47
47
|
# per line and lines per frame, and how many lines at the top of the
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class Z80
|
|
6
|
+
# The ALU's 8- and 16-bit arithmetic. Bits 5 and 3 of F come from the
|
|
7
|
+
# result, except for CP, which takes them from the operand, and the
|
|
8
|
+
# 16-bit operations, which take them from the high byte.
|
|
9
|
+
module Arithmetic
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
# The eight operations an opcode's bits 5-3 pick: ADD ADC SUB SBC AND
|
|
13
|
+
# XOR OR CP.
|
|
14
|
+
def alu(operation, value)
|
|
15
|
+
case operation
|
|
16
|
+
when 0 then add_a(value, 0)
|
|
17
|
+
when 1 then add_a(value, @f & CF)
|
|
18
|
+
when 2 then @a = subtract(value, 0)
|
|
19
|
+
when 3 then @a = subtract(value, @f & CF)
|
|
20
|
+
when 4 then logic(@a & value, HF)
|
|
21
|
+
when 5 then logic(@a ^ value, 0)
|
|
22
|
+
when 6 then logic(@a | value, 0)
|
|
23
|
+
else compare(value)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def add_a(value, carry)
|
|
28
|
+
result = @a + value + carry
|
|
29
|
+
assign_flags(SZ53[result & 0xff] | (result >> 8) | ((@a ^ value ^ result) & HF) |
|
|
30
|
+
(((@a ^ value ^ 0x80) & (@a ^ result) & 0x80) >> 5))
|
|
31
|
+
@a = result & 0xff
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def subtract(value, carry)
|
|
35
|
+
result = @a - value - carry
|
|
36
|
+
assign_flags(SZ53[result & 0xff] | NF | ((result >> 8) & CF) | ((@a ^ value ^ result) & HF) |
|
|
37
|
+
(((@a ^ value) & (@a ^ result) & 0x80) >> 5))
|
|
38
|
+
result & 0xff
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def compare(value)
|
|
42
|
+
subtract(value, 0)
|
|
43
|
+
assign_flags((@f & ~XYF) | (value & XYF))
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def logic(result, half)
|
|
47
|
+
@a = result
|
|
48
|
+
assign_flags(SZ53P[result] | half)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def increment(value)
|
|
52
|
+
result = (value + 1) & 0xff
|
|
53
|
+
assign_flags((@f & CF) | SZ53[result] | (result == 0x80 ? PF : 0) | (result.nobits?(0x0f) ? HF : 0))
|
|
54
|
+
result
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def decrement(value)
|
|
58
|
+
result = (value - 1) & 0xff
|
|
59
|
+
assign_flags((@f & CF) | NF | SZ53[result] | (result == 0x7f ? PF : 0) | (value.nobits?(0x0f) ? HF : 0))
|
|
60
|
+
result
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def add16(left, right)
|
|
64
|
+
result = left + right
|
|
65
|
+
@wz = (left + 1) & 0xffff
|
|
66
|
+
assign_flags((@f & (SF | ZF | PF)) | ((result >> 8) & XYF) | (((left ^ right ^ result) >> 8) & HF) |
|
|
67
|
+
(result >> 16))
|
|
68
|
+
result & 0xffff
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def adc16(right)
|
|
72
|
+
left = hl
|
|
73
|
+
result = left + right + (@f & CF)
|
|
74
|
+
@wz = (left + 1) & 0xffff
|
|
75
|
+
self.hl = result & 0xffff
|
|
76
|
+
assign_flags(word_flags(result) | (((left ^ right ^ result) >> 8) & HF) |
|
|
77
|
+
(((left ^ right ^ 0x8000) & (left ^ result) & 0x8000) >> 13))
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def sbc16(right)
|
|
81
|
+
left = hl
|
|
82
|
+
result = left - right - (@f & CF)
|
|
83
|
+
@wz = (left + 1) & 0xffff
|
|
84
|
+
self.hl = result & 0xffff
|
|
85
|
+
assign_flags(word_flags(result) | NF | (((left ^ right ^ result) >> 8) & HF) |
|
|
86
|
+
(((left ^ right) & (left ^ result) & 0x8000) >> 13))
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def word_flags(result)
|
|
90
|
+
((result >> 8) & (SF | XYF)) | (result.nobits?(0xffff) ? ZF : 0) | ((result >> 16) & CF)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def daa
|
|
94
|
+
low = @a & 0x0f
|
|
95
|
+
carry = @f.anybits?(CF) || @a > 0x99 ? CF : 0
|
|
96
|
+
correction = (carry.zero? ? 0 : 0x60) | (@f.anybits?(HF) || low > 9 ? 0x06 : 0)
|
|
97
|
+
subtracting = @f.anybits?(NF)
|
|
98
|
+
half = daa_half(low, subtracting)
|
|
99
|
+
@a = (subtracting ? @a - correction : @a + correction) & 0xff
|
|
100
|
+
assign_flags(SZ53P[@a] | (@f & NF) | carry | half)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def daa_half(low, subtracting)
|
|
104
|
+
if subtracting
|
|
105
|
+
@f.anybits?(HF) && low < 6 ? HF : 0
|
|
106
|
+
else
|
|
107
|
+
low > 9 ? HF : 0
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def neg
|
|
112
|
+
value = @a
|
|
113
|
+
@a = 0
|
|
114
|
+
@a = subtract(value, 0)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|