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,188 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class CIA
|
|
6
|
+
class Timer
|
|
7
|
+
attr_accessor :counter, :latch
|
|
8
|
+
attr_reader :control, :underflowed
|
|
9
|
+
|
|
10
|
+
def initialize(control)
|
|
11
|
+
@control = control
|
|
12
|
+
@counter = @latch = 0xffff
|
|
13
|
+
@pipe = 0
|
|
14
|
+
@load_delay = 0
|
|
15
|
+
@reload = false
|
|
16
|
+
@underflowed = false
|
|
17
|
+
@oneshot_linger = 0
|
|
18
|
+
@toggle = true
|
|
19
|
+
settle
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# The level this timer drives on its port B pin: a square wave that
|
|
23
|
+
# flips on each underflow, or a single high tick when one happens.
|
|
24
|
+
def output?
|
|
25
|
+
control.out_mode? ? @toggle : @underflowed
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Whether the timer is stopped with nothing in its pipeline, so a
|
|
29
|
+
# cycle changes nothing.
|
|
30
|
+
def idle? = @empty && !started?
|
|
31
|
+
|
|
32
|
+
# Whether the timer counts ø2 in continuous mode with nothing pending
|
|
33
|
+
# but the reload after an underflow, so fast_forward can run it. A
|
|
34
|
+
# latch below 2 is left out.
|
|
35
|
+
def free_running?
|
|
36
|
+
started? && !@control.run_mode? && @control.value.nobits?(0x20) && @latch >= 2 && @pipe == 0b11 &&
|
|
37
|
+
(@load_delay | @oneshot_linger).zero? && (@settled || @reload)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Runs a free-running timer +cycles+ cycles at once, as cycle! would:
|
|
41
|
+
# an underflow every latch + 1 cycles, each one followed by the
|
|
42
|
+
# reload. Returns the underflows.
|
|
43
|
+
def fast_forward(cycles)
|
|
44
|
+
return 0 if cycles.zero?
|
|
45
|
+
return after_underflow(cycles, 0) unless @settled
|
|
46
|
+
|
|
47
|
+
if cycles < @counter
|
|
48
|
+
@counter -= cycles
|
|
49
|
+
return 0
|
|
50
|
+
end
|
|
51
|
+
after_underflow(cycles - @counter, 1)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def cycle!(feed)
|
|
55
|
+
feed &&= @control.value & 0x01 != 0
|
|
56
|
+
if @settled
|
|
57
|
+
return @counter -= 1 if feed && @counter > 1
|
|
58
|
+
elsif @empty
|
|
59
|
+
enter if feed
|
|
60
|
+
return
|
|
61
|
+
end
|
|
62
|
+
run_tick(feed)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def run_tick(feed)
|
|
66
|
+
@underflowed = false
|
|
67
|
+
@oneshot_linger -= 1 if @oneshot_linger.positive?
|
|
68
|
+
tick(feed)
|
|
69
|
+
settle
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def write_control(value)
|
|
73
|
+
@toggle = true if value.anybits?(0x01) && !started?
|
|
74
|
+
@oneshot_linger = 2 if control.run_mode? && value.nobits?(0x08)
|
|
75
|
+
control.value = value & ~0x10
|
|
76
|
+
@load_delay = 3 if value.anybits?(0x10)
|
|
77
|
+
settle
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def write_latch_low(value)
|
|
81
|
+
@latch = (@latch & 0xff00) | value
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def write_latch_high(value)
|
|
85
|
+
@latch = (value << 8) | (@latch & 0xff)
|
|
86
|
+
@counter = @latch unless started?
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Whether the timer's PB output toggle is high, and its count pipeline
|
|
90
|
+
# as two bits, the newer stage high.
|
|
91
|
+
attr_reader :toggle, :pipe
|
|
92
|
+
|
|
93
|
+
# Sets the control register without its load strobe, the toggle and
|
|
94
|
+
# the count pipeline, as a VICE snapshot gives them.
|
|
95
|
+
def restore_pipeline(control, toggle, pipe)
|
|
96
|
+
@control.value = control & ~0x10
|
|
97
|
+
@toggle = toggle
|
|
98
|
+
@pipe = pipe
|
|
99
|
+
settle
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
private
|
|
103
|
+
|
|
104
|
+
def started?
|
|
105
|
+
@control.value & 0x01 != 0
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Where fast_forward lands +cycles+ after an underflow, with
|
|
109
|
+
# +underflows+ underflows counted so far.
|
|
110
|
+
def after_underflow(cycles, underflows)
|
|
111
|
+
periods, rest = cycles.divmod(@latch + 1)
|
|
112
|
+
underflows += periods
|
|
113
|
+
@toggle = !@toggle if underflows.odd?
|
|
114
|
+
@underflowed = rest.zero?
|
|
115
|
+
@reload = rest.zero?
|
|
116
|
+
@counter = @latch - (rest.zero? ? 0 : rest - 1)
|
|
117
|
+
settle
|
|
118
|
+
underflows
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def enter
|
|
122
|
+
@pipe = 0b10
|
|
123
|
+
@empty = false
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# With no load, reload or one-shot linger pending, a full pipe only
|
|
127
|
+
# counts and an empty one only waits to be fed.
|
|
128
|
+
def settle
|
|
129
|
+
quiet = (@load_delay | @oneshot_linger).zero? && !@reload
|
|
130
|
+
@settled = quiet && @pipe == 0b11
|
|
131
|
+
@empty = quiet && @pipe.zero?
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def tick(feed)
|
|
135
|
+
counting = @pipe.anybits?(0b01)
|
|
136
|
+
@pipe = (@pipe >> 1) | (feed ? 0b10 : 0)
|
|
137
|
+
loading = @reload || @load_delay == 1
|
|
138
|
+
@reload = false
|
|
139
|
+
|
|
140
|
+
if loading
|
|
141
|
+
reload
|
|
142
|
+
elsif premature_underflow?
|
|
143
|
+
underflow
|
|
144
|
+
elsif counting
|
|
145
|
+
count
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
forced_load
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def forced_load
|
|
152
|
+
return unless @load_delay.positive?
|
|
153
|
+
|
|
154
|
+
@load_delay -= 1
|
|
155
|
+
@counter = @latch if @load_delay == 1
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# the final pipeline stage, before any pending load lands
|
|
159
|
+
def premature_underflow?
|
|
160
|
+
@counter.zero? && @pipe.anybits?(0b01) && started?
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# A load consumes its tick, so the counter never decrements on it
|
|
164
|
+
def reload
|
|
165
|
+
@counter = @latch
|
|
166
|
+
# A zero latch underflows again on the reload tick while running
|
|
167
|
+
underflow if @counter.zero? && started? && @pipe.anybits?(0b01)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def count
|
|
171
|
+
@counter -= 1 if @counter.positive?
|
|
172
|
+
underflow if @counter.zero? && @pipe.anybits?(0b01)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def underflow
|
|
176
|
+
@underflowed = true
|
|
177
|
+
@reload = true
|
|
178
|
+
@counter = @latch
|
|
179
|
+
@toggle = !@toggle
|
|
180
|
+
return unless control.run_mode? || @oneshot_linger.positive?
|
|
181
|
+
|
|
182
|
+
control.start = false
|
|
183
|
+
@pipe = 0
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "badline/chips/cia/time_of_day"
|
|
4
|
+
require "badline/chips/cia/interrupt_register"
|
|
5
|
+
require "badline/chips/cia/serial"
|
|
6
|
+
require "badline/chips/cia/timer"
|
|
7
|
+
require "badline/chips/cia/fast_forward"
|
|
8
|
+
require "badline/chips/cia/keyed_parts"
|
|
9
|
+
|
|
10
|
+
module Badline
|
|
11
|
+
module Chips
|
|
12
|
+
# CIA (Complex Interface Adapter) chip
|
|
13
|
+
class CIA
|
|
14
|
+
include Addressable
|
|
15
|
+
include FastForward
|
|
16
|
+
|
|
17
|
+
# The original NMOS 6526 of the breadbin C64, and the HMOS 6526A of the
|
|
18
|
+
# C64C, which differs from it only in its interrupt control register.
|
|
19
|
+
MODELS = %i[mos6526 mos6526a].freeze
|
|
20
|
+
|
|
21
|
+
attr_reader :start, :control_a, :control_b, :serial, :model
|
|
22
|
+
|
|
23
|
+
# What's on the ports outside the chip. It pulls port lines low through
|
|
24
|
+
# read_a and read_b, and on CIA 1 drives PB4 through port_b4_high?.
|
|
25
|
+
attr_accessor :peripheral
|
|
26
|
+
|
|
27
|
+
# Timer A and timer B.
|
|
28
|
+
def timers = [@ta, @tb]
|
|
29
|
+
|
|
30
|
+
# Port A and B's data and direction registers.
|
|
31
|
+
def port_registers = [@data_port_a, @data_port_b, @data_dir_a, @data_dir_b]
|
|
32
|
+
|
|
33
|
+
def interrupt_status = @icr.status
|
|
34
|
+
|
|
35
|
+
def interrupt_control = @icr.mask
|
|
36
|
+
|
|
37
|
+
def interrupt!(delay = 1) = @icr.assert!(delay)
|
|
38
|
+
|
|
39
|
+
def time_of_day = @tod
|
|
40
|
+
|
|
41
|
+
def timer_a = @ta.counter
|
|
42
|
+
|
|
43
|
+
def timer_a=(value)
|
|
44
|
+
@ta.counter = value
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def timer_a_latch = @ta.latch
|
|
48
|
+
|
|
49
|
+
def timer_a_latch=(value)
|
|
50
|
+
@ta.latch = value
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def timer_b = @tb.counter
|
|
54
|
+
|
|
55
|
+
def timer_b=(value)
|
|
56
|
+
@tb.counter = value
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def timer_b_latch = @tb.latch
|
|
60
|
+
|
|
61
|
+
def timer_b_latch=(value)
|
|
62
|
+
@tb.latch = value
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# +tod_hz+ is the rate of the pulses on the TOD pin, the region's mains
|
|
66
|
+
# unless a machine feeds it otherwise, and 0 for a pin held still.
|
|
67
|
+
def initialize(start: 0, peripheral: nil, model: :mos6526, region: Region::PAL, tod_hz: nil)
|
|
68
|
+
raise ArgumentError, "unknown CIA model #{model}" unless MODELS.include?(model)
|
|
69
|
+
|
|
70
|
+
addressable_at(start, length: 2**8)
|
|
71
|
+
|
|
72
|
+
@model = model
|
|
73
|
+
@clock_hz = region.clock_hz
|
|
74
|
+
@mains_hz = tod_hz || region.mains_hz
|
|
75
|
+
|
|
76
|
+
@peripheral = peripheral
|
|
77
|
+
@port_b4_handler = nil
|
|
78
|
+
@port_a_handler = nil
|
|
79
|
+
@port_b4_high = true
|
|
80
|
+
reset!
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# The RES line: ports back to inputs, timers stopped with their latches
|
|
84
|
+
# full, interrupts masked and the TOD clock stopped at 1:00:00.0. The
|
|
85
|
+
# PB4 level carries over and is resampled on the next cycle.
|
|
86
|
+
def reset!
|
|
87
|
+
@data_port_a = 0x00
|
|
88
|
+
@data_port_b = 0x00
|
|
89
|
+
@data_dir_a = 0x00
|
|
90
|
+
@data_dir_b = 0x00
|
|
91
|
+
@port_b4_driven_high = true
|
|
92
|
+
@cnt_high = true
|
|
93
|
+
@cnt_rise = false
|
|
94
|
+
@tod = TimeOfDay.new(clock_hz: @clock_hz, mains_hz: @mains_hz)
|
|
95
|
+
@icr = InterruptRegister.new(@model)
|
|
96
|
+
@icr_status = @icr.status
|
|
97
|
+
@control_a = ControlRegister.new(%i[start output out_mode run_mode load
|
|
98
|
+
in_mode serial_mode clock_frequency])
|
|
99
|
+
@control_b = ControlRegister.new(%i[start output out_mode run_mode load
|
|
100
|
+
in_cnt in_timer_a alarm])
|
|
101
|
+
@ta = Timer.new(@control_a)
|
|
102
|
+
@tb = Timer.new(@control_b)
|
|
103
|
+
@serial = Serial.new(@control_a)
|
|
104
|
+
@port_a_handler&.call
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Register a change handler on the PB4 line. On CIA 1, this feeds the
|
|
108
|
+
# light pen input.
|
|
109
|
+
def on_port_b4_change(&handler)
|
|
110
|
+
@port_b4_handler = handler
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Register a handler for writes that can move port A's lines: to the
|
|
114
|
+
# data register or DDR, and the reset. On CIA 2, this tells the drives
|
|
115
|
+
# on the serial bus that the C64 may have moved a line.
|
|
116
|
+
def on_port_a_write(&handler)
|
|
117
|
+
@port_a_handler = handler
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# A falling edge on the FLAG pin. On CIA 1 the datasette's tape read
|
|
121
|
+
# line drives it, on CIA 2 the serial bus SRQ.
|
|
122
|
+
def flag! = raise_interrupt(:flag)
|
|
123
|
+
|
|
124
|
+
def interrupted? = @icr_status.value >= 0x80
|
|
125
|
+
|
|
126
|
+
def cycle!
|
|
127
|
+
@icr.cycle! unless @icr.quiet
|
|
128
|
+
refresh_port_b4 if @port_b4_handler
|
|
129
|
+
level = @serial.cnt
|
|
130
|
+
level == @cnt_high ? @cnt_rise = false : cnt_edge(level)
|
|
131
|
+
underflowed = update_timers
|
|
132
|
+
@serial.cycle!(underflowed) { trigger_serial } if underflowed || !@serial.idle
|
|
133
|
+
@tod.cycle! { trigger_alarm }
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def read_port_a
|
|
137
|
+
lines = driven_lines(@data_port_a, @data_dir_a)
|
|
138
|
+
return lines unless peripheral
|
|
139
|
+
|
|
140
|
+
lines & peripheral.read_a(lines, driven_lines(@data_port_b, @data_dir_b))
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Port A as driven by the data/direction registers alone, without
|
|
144
|
+
# peripheral pulldown. Cheap path for the VIC bank lookup.
|
|
145
|
+
def port_a_lines = driven_lines(@data_port_a, @data_dir_a)
|
|
146
|
+
|
|
147
|
+
# Port B as driven by the data/direction registers alone.
|
|
148
|
+
def port_b_lines = driven_lines(@data_port_b, @data_dir_b)
|
|
149
|
+
|
|
150
|
+
def read_port_b
|
|
151
|
+
lines = driven_lines(@data_port_b, @data_dir_b)
|
|
152
|
+
lines &= peripheral.read_b(driven_lines(@data_port_a, @data_dir_a), lines) if peripheral
|
|
153
|
+
apply_timer_output(lines)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def peek(addr)
|
|
157
|
+
case offset_of(addr) & 0x0f
|
|
158
|
+
when 0x00 then read_port_a
|
|
159
|
+
when 0x01 then read_port_b
|
|
160
|
+
when 0x02 then @data_dir_a
|
|
161
|
+
when 0x03 then @data_dir_b
|
|
162
|
+
when 0x04 then low_byte(@ta.counter)
|
|
163
|
+
when 0x05 then high_byte(@ta.counter)
|
|
164
|
+
when 0x06 then low_byte(@tb.counter)
|
|
165
|
+
when 0x07 then high_byte(@tb.counter)
|
|
166
|
+
when 0x08 then @tod.tenths
|
|
167
|
+
when 0x09 then @tod.seconds
|
|
168
|
+
when 0x0a then @tod.minutes
|
|
169
|
+
when 0x0b then @tod.hours
|
|
170
|
+
when 0x0c then @serial.data
|
|
171
|
+
when 0x0d then @icr.read
|
|
172
|
+
when 0x0e then control_a.value
|
|
173
|
+
when 0x0f then control_b.value
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def poke(addr, value)
|
|
178
|
+
case offset_of(addr) & 0x0f
|
|
179
|
+
when 0x00 then update_port_a { @data_port_a = value }
|
|
180
|
+
when 0x01 then update_port_b { @data_port_b = value }
|
|
181
|
+
when 0x02 then update_port_a { @data_dir_a = value }
|
|
182
|
+
when 0x03 then update_port_b { @data_dir_b = value }
|
|
183
|
+
when 0x04 then @ta.write_latch_low(value)
|
|
184
|
+
when 0x05 then @ta.write_latch_high(value)
|
|
185
|
+
when 0x06 then @tb.write_latch_low(value)
|
|
186
|
+
when 0x07 then @tb.write_latch_high(value)
|
|
187
|
+
when 0x08 then @tod.write(:tenths, value, alarm: control_b.alarm?)
|
|
188
|
+
when 0x09 then @tod.write(:seconds, value, alarm: control_b.alarm?)
|
|
189
|
+
when 0x0a then @tod.write(:minutes, value, alarm: control_b.alarm?)
|
|
190
|
+
when 0x0b then @tod.write_hours(value, alarm: control_b.alarm?)
|
|
191
|
+
when 0x0c then @serial.write(value)
|
|
192
|
+
when 0x0d then @icr.write(value)
|
|
193
|
+
when 0x0e then write_control_a(value)
|
|
194
|
+
when 0x0f then @tb.write_control(value)
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
private
|
|
199
|
+
|
|
200
|
+
def update_port_a
|
|
201
|
+
yield
|
|
202
|
+
@port_a_handler&.call
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def update_port_b
|
|
206
|
+
yield
|
|
207
|
+
@port_b4_driven_high = driven_lines(@data_port_b, @data_dir_b).anybits?(0x10)
|
|
208
|
+
refresh_port_b4 if @port_b4_handler
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# PB4 is also control port 1's fire line, and a peripheral pulls it low
|
|
212
|
+
# without any register write, so the level is resampled every cycle rather
|
|
213
|
+
# than only after a poke.
|
|
214
|
+
def refresh_port_b4
|
|
215
|
+
high = @port_b4_driven_high && (peripheral.nil? || peripheral.port_b4_high?)
|
|
216
|
+
return if high == @port_b4_high
|
|
217
|
+
|
|
218
|
+
@port_b4_high = high
|
|
219
|
+
@port_b4_handler.call(high)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def driven_lines(register, direction)
|
|
223
|
+
# Output bits are driven from the data register; input bits float high.
|
|
224
|
+
# External peripherals can still pull any line low (wired-AND).
|
|
225
|
+
(register & direction) | (~direction & 0xff)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def apply_timer_output(value)
|
|
229
|
+
value = with_bit(value, 6, @ta.output?) if control_a.output?
|
|
230
|
+
value = with_bit(value, 7, @tb.output?) if control_b.output?
|
|
231
|
+
value
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def with_bit(value, bit, set)
|
|
235
|
+
set ? value | (1 << bit) : value & ~(1 << bit)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def trigger_alarm = raise_interrupt(:alarm)
|
|
239
|
+
def trigger_serial = raise_interrupt(:serial)
|
|
240
|
+
|
|
241
|
+
def raise_interrupt(source) = @icr.flag(source)
|
|
242
|
+
|
|
243
|
+
# CNT is sampled once a cycle. When the serial port drives it from this
|
|
244
|
+
# cycle's timer A underflow, the new level is picked up on the next one.
|
|
245
|
+
def cnt_edge(level)
|
|
246
|
+
@cnt_high = level
|
|
247
|
+
@cnt_rise = level
|
|
248
|
+
@serial.rising_edge! { trigger_serial } if level
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# Returns whether timer A underflowed, which clocks the serial port.
|
|
252
|
+
#
|
|
253
|
+
# CRB bits 6-5 pick timer B's source: ø2, CNT edges, timer A
|
|
254
|
+
# underflows, or timer A underflows gated by the CNT level. Every source
|
|
255
|
+
# drives the same count-enable line, so a cascaded underflow goes through
|
|
256
|
+
# the input pipeline exactly as a CNT edge does.
|
|
257
|
+
def update_timers
|
|
258
|
+
@ta.cycle!(@control_a.value & 0x20 == 0x20 ? @cnt_rise : true)
|
|
259
|
+
underflowed = @ta.underflowed
|
|
260
|
+
@tb.cycle!(
|
|
261
|
+
case @control_b.value & 0x60
|
|
262
|
+
when 0x00 then true
|
|
263
|
+
when 0x20 then @cnt_rise
|
|
264
|
+
when 0x40 then underflowed
|
|
265
|
+
else underflowed && @cnt_high
|
|
266
|
+
end
|
|
267
|
+
)
|
|
268
|
+
@icr.flag(:timer_a) if underflowed
|
|
269
|
+
@icr.timer_b_underflow! if @tb.underflowed
|
|
270
|
+
underflowed
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def write_control_a(value)
|
|
274
|
+
was_output = control_a.serial_mode?
|
|
275
|
+
@ta.write_control(value)
|
|
276
|
+
@serial.reset! { trigger_serial } if control_a.serial_mode? != was_output
|
|
277
|
+
@tod.fifty_hz = control_a.clock_frequency?
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class CPU
|
|
6
|
+
# Steps that read an instruction's operand bytes and work out the
|
|
7
|
+
# address it operates on, which they leave in @address. Also the
|
|
8
|
+
# single-step implied, accumulator and immediate instructions, and JMP.
|
|
9
|
+
module Addressing
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def op_implied_dummy
|
|
13
|
+
@memory.peek(@program_counter)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def op_implied_exec
|
|
17
|
+
@memory.peek(@program_counter)
|
|
18
|
+
send(@operation, nil, nil)
|
|
19
|
+
end_instruction
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def op_accumulator_exec
|
|
23
|
+
@memory.peek(@program_counter)
|
|
24
|
+
send(@operation, :accumulator, @a)
|
|
25
|
+
end_instruction
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def op_immediate_read
|
|
29
|
+
value = @memory.peek(@program_counter)
|
|
30
|
+
@program_counter = (@program_counter + 1) & 0xffff
|
|
31
|
+
send(@operation, nil, value)
|
|
32
|
+
end_instruction
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def op_zp
|
|
36
|
+
@address = @memory.peek(@program_counter)
|
|
37
|
+
@program_counter = (@program_counter + 1) & 0xffff
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def op_zp_x
|
|
41
|
+
@memory.peek(@address)
|
|
42
|
+
@address = (@address + @x) & 0xff
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def op_zp_y
|
|
46
|
+
@memory.peek(@address)
|
|
47
|
+
@address = (@address + @y) & 0xff
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def op_abs_low
|
|
51
|
+
@address = @memory.peek(@program_counter)
|
|
52
|
+
@program_counter = (@program_counter + 1) & 0xffff
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def op_abs_high
|
|
56
|
+
@address |= @memory.peek(@program_counter) << 8
|
|
57
|
+
@program_counter = (@program_counter + 1) & 0xffff
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def op_abs_high_x
|
|
61
|
+
high = @memory.peek(@program_counter)
|
|
62
|
+
@program_counter = (@program_counter + 1) & 0xffff
|
|
63
|
+
index_address(high, @x)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def op_abs_high_y
|
|
67
|
+
high = @memory.peek(@program_counter)
|
|
68
|
+
@program_counter = (@program_counter + 1) & 0xffff
|
|
69
|
+
index_address(high, @y)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def op_idx_dummy
|
|
73
|
+
@memory.peek(@dummy_address)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def op_zp_pointer
|
|
77
|
+
@pointer = @memory.peek(@program_counter)
|
|
78
|
+
@program_counter = (@program_counter + 1) & 0xffff
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def op_pointer_x
|
|
82
|
+
@memory.peek(@pointer)
|
|
83
|
+
@pointer = (@pointer + @x) & 0xff
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def op_pointer_low
|
|
87
|
+
@address = @memory.peek(@pointer)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def op_pointer_high
|
|
91
|
+
@address |= @memory.peek((@pointer + 1) & 0xff) << 8
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def op_pointer_high_y
|
|
95
|
+
index_address(@memory.peek((@pointer + 1) & 0xff), @y)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def op_jmp_high
|
|
99
|
+
@program_counter = @address | (@memory.peek(@program_counter) << 8)
|
|
100
|
+
end_instruction
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def op_indirect_low
|
|
104
|
+
@pointer = @address
|
|
105
|
+
@address = @memory.peek(@pointer)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# The pointer's high byte never increments, so JMP ($30FF) reads its
|
|
109
|
+
# target's high byte from $3000, not $3100.
|
|
110
|
+
def op_indirect_high
|
|
111
|
+
high = @memory.peek((@pointer & 0xff00) | ((@pointer + 1) & 0xff))
|
|
112
|
+
@program_counter = @address | (high << 8)
|
|
113
|
+
end_instruction
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Adds an index register to a base address. The 6502 adds to the low
|
|
117
|
+
# byte first and spends the next cycle reading from that address,
|
|
118
|
+
# before the carry reaches the high byte. Read instructions skip that
|
|
119
|
+
# cycle when there is no carry.
|
|
120
|
+
def index_address(high, index)
|
|
121
|
+
low = @address
|
|
122
|
+
@address = (((high << 8) | low) + index) & 0xffff
|
|
123
|
+
@boundary_crossed = (low + index) > 0xff
|
|
124
|
+
if @optional_dummy && !@boundary_crossed
|
|
125
|
+
@index += 1
|
|
126
|
+
else
|
|
127
|
+
@dummy_address = (high << 8) | ((low + index) & 0xff)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class CPU
|
|
6
|
+
# The steps at an instruction boundary: the opcode fetch that starts
|
|
7
|
+
# an instruction, and the ends of one.
|
|
8
|
+
module Boundary
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
# The first cycle of every instruction. Starts an interrupt if one was
|
|
12
|
+
# pending when the previous instruction ended. Otherwise reads the
|
|
13
|
+
# opcode and switches to its plan.
|
|
14
|
+
def op_fetch
|
|
15
|
+
return start_interrupt if @boundary_nmi || @boundary_irq
|
|
16
|
+
|
|
17
|
+
run_traps
|
|
18
|
+
opcode = @memory.peek(@program_counter)
|
|
19
|
+
log(opcode) if @debug
|
|
20
|
+
micro = MICROCODE[opcode]
|
|
21
|
+
@operation = micro.operation
|
|
22
|
+
@plan = micro.plan
|
|
23
|
+
@writes = micro.writes
|
|
24
|
+
@optional_dummy = micro.optional_dummy
|
|
25
|
+
@index = 1
|
|
26
|
+
@boundary_crossed = false
|
|
27
|
+
@program_counter = (@program_counter + 1) & 0xffff
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def end_instruction
|
|
31
|
+
@instructions += 1
|
|
32
|
+
end_sequence
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Makes the next cycle an opcode fetch, and saves the pending interrupt
|
|
36
|
+
# flags for op_fetch. The next cycle polls before op_fetch runs, which
|
|
37
|
+
# updates the live flags.
|
|
38
|
+
def end_sequence
|
|
39
|
+
@plan = FETCH_PLAN
|
|
40
|
+
@writes = FETCH_WRITES
|
|
41
|
+
@index = 0
|
|
42
|
+
@boundary_irq = @irq_pending
|
|
43
|
+
@boundary_nmi = @nmi_pending
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def log(opcode)
|
|
47
|
+
instruction = Instruction.find(opcode)
|
|
48
|
+
puts(
|
|
49
|
+
"#{@cycles}: PC: #{format16(@program_counter)} - " \
|
|
50
|
+
"#{instruction.name.upcase} #{instruction.addressing_mode}"
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|