badline 0.12.0 → 0.13.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 +25 -0
- data/CLAUDE.md +59 -31
- data/README.md +1 -1
- data/doc/library.md +9 -9
- data/doc/pinned-behaviour.md +105 -105
- data/doc/snapshots.md +1 -4
- data/lib/badline/audio/bare_player.rb +4 -4
- data/lib/badline/audio/cli.rb +6 -6
- data/lib/badline/audio/jukebox.rb +2 -2
- data/lib/badline/audio/machine_player.rb +2 -2
- data/lib/badline/{media → audio}/queue.rb +1 -1
- data/lib/badline/audio/queued_tune.rb +6 -6
- data/lib/badline/audio/renderer.rb +5 -5
- data/lib/badline/audio/stereo.rb +1 -1
- data/lib/badline/c128/{bus_state.rb → bus/saved_state.rb} +6 -6
- data/lib/badline/c128/bus.rb +30 -51
- data/lib/badline/c128/color_lines.rb +2 -2
- data/lib/badline/c128/cpu.rb +1 -1
- data/lib/badline/c128/drives.rb +10 -11
- data/lib/badline/c128/fast_serial.rb +5 -5
- data/lib/badline/c128/mmu_pages.rb +1 -1
- data/lib/badline/c128/modes.rb +2 -2
- data/lib/badline/c128/saved_state.rb +21 -47
- data/lib/badline/c128/z80.rb +2 -2
- data/lib/badline/c128.rb +18 -72
- data/lib/badline/{computer → c64}/attachments.rb +16 -47
- data/lib/badline/c64/banked_ram/banking.rb +32 -0
- data/lib/badline/c64/banked_ram/plus256k.rb +56 -0
- data/lib/badline/c64/banked_ram/plus60k.rb +45 -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/extra_sids.rb +32 -0
- data/lib/badline/c64/bus/fittings.rb +40 -0
- data/lib/badline/c64/bus/pla.rb +149 -0
- data/lib/badline/c64/bus/roms.rb +41 -0
- data/lib/badline/c64/bus/saved_state.rb +68 -0
- data/lib/badline/c64/bus/sid_slots.rb +44 -0
- data/lib/badline/c64/bus.rb +218 -0
- data/lib/badline/c64/cartridge/action_replay.rb +128 -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 +147 -0
- data/lib/badline/c64/cartridge/epyx_fastload.rb +81 -0
- data/lib/badline/c64/cartridge/final_cartridge3.rb +91 -0
- data/lib/badline/c64/cartridge/flash/saved_state.rb +40 -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 +76 -0
- data/lib/badline/c64/cartridge/game_system.rb +42 -0
- data/lib/badline/c64/cartridge/geo_ram.rb +81 -0
- data/lib/badline/c64/cartridge/kcs_power.rb +77 -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 +70 -0
- data/lib/badline/c64/cartridge/retro_replay/saved_state.rb +47 -0
- data/lib/badline/c64/cartridge/retro_replay.rb +286 -0
- data/lib/badline/c64/cartridge/rex_utility.rb +31 -0
- data/lib/badline/c64/cartridge/rgcd.rb +60 -0
- data/lib/badline/c64/cartridge/saved_state.rb +63 -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 +50 -0
- data/lib/badline/c64/cartridge/westermann.rb +32 -0
- data/lib/badline/c64/cartridge/zaxxon.rb +68 -0
- data/lib/badline/c64/cartridge.rb +258 -0
- data/lib/badline/c64/color_memory.rb +27 -0
- data/lib/badline/c64/common.rb +34 -0
- data/lib/badline/c64/kernal_traps.rb +89 -0
- data/lib/badline/c64/reu/dma/saved_state.rb +52 -0
- data/lib/badline/c64/reu/dma.rb +275 -0
- data/lib/badline/c64/reu/ram.rb +109 -0
- data/lib/badline/c64/reu/saved_state.rb +55 -0
- data/lib/badline/c64/reu/trigger.rb +34 -0
- data/lib/badline/c64/reu.rb +291 -0
- data/lib/badline/{computer → c64}/saved_state.rb +13 -18
- data/lib/badline/{computer → c64}/true_drives.rb +20 -31
- data/lib/badline/{computer.rb → c64.rb} +22 -80
- data/lib/badline/chips/cia/fast_forward.rb +62 -0
- data/lib/badline/chips/cia/interrupt_register.rb +145 -0
- data/lib/badline/chips/cia/saved_state.rb +49 -0
- data/lib/badline/chips/cia/serial/saved_state.rb +45 -0
- data/lib/badline/chips/cia/serial.rb +250 -0
- data/lib/badline/chips/cia/time_of_day.rb +232 -0
- data/lib/badline/chips/cia/timer.rb +208 -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 +167 -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/microcode.rb +179 -0
- data/lib/badline/chips/cpu/operations.rb +90 -0
- data/lib/badline/chips/cpu/port.rb +116 -0
- data/lib/badline/chips/cpu/saved_state.rb +117 -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 +12 -0
- data/lib/badline/chips/sid/catch_up.rb +122 -0
- data/lib/badline/chips/sid/decimator.rb +66 -0
- data/lib/badline/chips/sid/envelope/saved_state.rb +70 -0
- data/lib/badline/chips/sid/envelope.rb +241 -0
- data/lib/badline/chips/sid/filter/saved_state.rb +42 -0
- data/lib/badline/chips/sid/filter.rb +241 -0
- data/lib/badline/chips/sid/saved_state.rb +52 -0
- data/lib/badline/chips/sid/voice.rb +79 -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/saved_state.rb +68 -0
- data/lib/badline/chips/sid/waveform.rb +307 -0
- data/lib/badline/chips/sid.rb +265 -0
- data/lib/badline/{c128 → chips}/vdc/memory.rb +1 -1
- data/lib/badline/{c128 → chips}/vdc/painter.rb +1 -1
- data/lib/badline/{c128 → chips}/vdc/raster.rb +1 -1
- data/lib/badline/chips/vdc/saved_state.rb +36 -0
- data/lib/badline/{c128 → chips}/vdc/window.rb +1 -1
- data/lib/badline/{c128 → chips}/vdc.rb +7 -31
- data/lib/badline/chips/via/control_lines.rb +124 -0
- data/lib/badline/chips/via/fast_forward.rb +55 -0
- data/lib/badline/chips/via/interrupt_register.rb +69 -0
- data/lib/badline/chips/via/saved_state.rb +44 -0
- data/lib/badline/chips/via/shift_register.rb +182 -0
- data/lib/badline/chips/via/timer1.rb +133 -0
- data/lib/badline/chips/via/timer2.rb +135 -0
- data/lib/badline/chips/via.rb +268 -0
- data/lib/badline/chips/vic/bank.rb +135 -0
- data/lib/badline/chips/vic/border_mask.rb +88 -0
- data/lib/badline/chips/vic/collisions.rb +117 -0
- data/lib/badline/chips/vic/color_patches.rb +49 -0
- data/lib/badline/chips/vic/display_state.rb +187 -0
- data/lib/badline/chips/vic/graphics_mode.rb +166 -0
- data/lib/badline/chips/vic/graphics_shifter/saved_state.rb +40 -0
- data/lib/badline/chips/vic/graphics_shifter.rb +187 -0
- data/lib/badline/chips/vic/register_log.rb +83 -0
- data/lib/badline/chips/vic/registers.rb +197 -0
- data/lib/badline/chips/vic/saved_state.rb +82 -0
- data/lib/badline/chips/vic/sequencer/saved_state.rb +91 -0
- data/lib/badline/chips/vic/sequencer.rb +277 -0
- data/lib/badline/chips/vic/sequencer_output.rb +118 -0
- data/lib/badline/chips/vic/sprite/internal_bus.rb +70 -0
- data/lib/badline/chips/vic/sprite/saved_state.rb +66 -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 +339 -0
- data/lib/badline/chips/vic/sprites/saved_state.rb +59 -0
- data/lib/badline/chips/vic/sprites.rb +284 -0
- data/lib/badline/chips/vic.rb +783 -0
- data/lib/badline/chips/vic_i/painter/saved_state.rb +40 -0
- data/lib/badline/{vic20/vic → chips/vic_i}/painter.rb +6 -30
- data/lib/badline/{vic20/vic → chips/vic_i}/saved_state.rb +2 -2
- data/lib/badline/chips/vic_i/sound/output.rb +85 -0
- data/lib/badline/chips/vic_i/sound.rb +235 -0
- data/lib/badline/{vic20/vic → chips/vic_i}/text_window.rb +2 -2
- data/lib/badline/{vic20/vic.rb → chips/vic_i.rb} +5 -5
- 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/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/saved_state.rb +71 -0
- data/lib/badline/chips/z80/shifts.rb +66 -0
- data/lib/badline/chips/z80.rb +13 -0
- data/lib/badline/core.rb +27 -29
- data/lib/badline/drives/datasette/saved_state.rb +37 -0
- data/lib/badline/drives/datasette.rb +140 -0
- data/lib/badline/drives/engine/core.rb +149 -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 +75 -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 +88 -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/saved_state.rb +88 -0
- data/lib/badline/drives/model1541/disk.rb +317 -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/mechanism/saved_state.rb +72 -0
- data/lib/badline/drives/model1541/mechanism.rb +315 -0
- data/lib/badline/drives/model1541/rotation.rb +123 -0
- data/lib/badline/drives/model1541/saved_state.rb +44 -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 +81 -0
- data/lib/badline/drives/model1571/bus.rb +113 -0
- data/lib/badline/drives/model1571/cpu.rb +13 -0
- data/lib/badline/drives/model1571/saved_state.rb +47 -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 +122 -0
- data/lib/badline/drives/model1571.rb +142 -0
- data/lib/badline/drives/model1581/bus.rb +139 -0
- data/lib/badline/drives/model1581/cpu.rb +13 -0
- data/lib/badline/drives/model1581/disk/saved_state.rb +89 -0
- data/lib/badline/drives/model1581/disk.rb +137 -0
- data/lib/badline/drives/model1581/mechanism.rb +119 -0
- data/lib/badline/drives/model1581/saved_state.rb +42 -0
- data/lib/badline/drives/model1581/serial_port.rb +54 -0
- data/lib/badline/drives/model1581/slot.rb +79 -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/saved_state.rb +68 -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 +218 -0
- data/lib/badline/drives/model1581.rb +206 -0
- data/lib/badline/drives/serial_bus.rb +161 -0
- data/lib/badline/frontend/boot.rb +10 -61
- data/lib/badline/frontend/machine_window.rb +3 -1
- 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/timeline.rb +3 -3
- 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.rb +3 -0
- data/lib/badline/kernal_trap/{drive → dos}/block_commands.rb +1 -1
- data/lib/badline/kernal_trap/dos/channel.rb +183 -0
- data/lib/badline/kernal_trap/{drive → dos}/channels.rb +1 -1
- data/lib/badline/kernal_trap/{drive → dos}/memory.rb +1 -1
- data/lib/badline/kernal_trap/{drive → dos}/parameters.rb +1 -1
- data/lib/badline/kernal_trap/{drive → dos}/status.rb +1 -1
- data/lib/badline/kernal_trap/{drive → dos}/write_file.rb +1 -1
- data/lib/badline/kernal_trap/{drive → dos}/writes.rb +1 -1
- data/lib/badline/kernal_trap/{drive.rb → dos.rb} +11 -10
- data/lib/badline/kernal_trap/{file.rb → file_routine.rb} +1 -1
- data/lib/badline/kernal_trap/load.rb +6 -6
- data/lib/badline/kernal_trap/save.rb +5 -5
- data/lib/badline/kernal_trap/serial.rb +7 -7
- data/lib/badline/kernal_trap.rb +2 -3
- data/lib/badline/machine/clocking.rb +50 -0
- data/lib/badline/machine.rb +63 -7
- data/lib/badline/media/boot_disk.rb +2 -2
- data/lib/badline/media/disk_list.rb +3 -3
- data/lib/badline/media/disk_set.rb +1 -1
- data/lib/badline/media/extensions.rb +33 -0
- data/lib/badline/media/program.rb +28 -0
- data/lib/badline/media/true_drive.rb +4 -3
- data/lib/badline/media/tune.rb +35 -0
- data/lib/badline/media/vic20_cartridge.rb +1 -7
- data/lib/badline/media/vic20_media.rb +38 -80
- data/lib/badline/media.rb +84 -81
- data/lib/badline/model.rb +1 -1
- data/lib/badline/options/event.rb +3 -1
- data/lib/badline/roms/README +6 -6
- 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 +43 -0
- data/lib/badline/snapshot/c64_setup.rb +79 -0
- data/lib/badline/snapshot/image.rb +5 -25
- data/lib/badline/snapshot/machine_state.rb +10 -2
- data/lib/badline/snapshot/setup.rb +22 -66
- data/lib/badline/snapshot/state.rb +8 -17
- data/lib/badline/snapshot/storage_setup.rb +68 -0
- data/lib/badline/snapshot/vic20_setup.rb +37 -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 +1 -1
- data/lib/badline/snapshot/vice/reu_fields.rb +40 -0
- data/lib/badline/snapshot/vice.rb +7 -5
- data/lib/badline/snapshot.rb +13 -12
- data/lib/badline/storage/d64_image.rb +15 -9
- data/lib/badline/storage/d71_image.rb +0 -2
- data/lib/badline/storage/d81_image.rb +0 -2
- data/lib/badline/storage/disk_image/writing.rb +2 -2
- data/lib/badline/storage/disk_image.rb +3 -6
- data/lib/badline/storage/g64_image.rb +2 -2
- data/lib/badline/storage/host_directory.rb +0 -5
- data/lib/badline/storage/t64.rb +2 -8
- 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 +11 -81
- data/lib/badline/vic20/bus/saved_state.rb +35 -0
- data/lib/badline/vic20/bus.rb +3 -25
- data/lib/badline/vic20/cpu.rb +1 -1
- data/lib/badline/vic20/port_wiring.rb +4 -4
- data/lib/badline/vic20/saved_state.rb +16 -60
- data/lib/badline/vic20/user_via_ports.rb +2 -2
- data/lib/badline/vic20.rb +20 -51
- metadata +250 -221
- 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 -72
- data/lib/badline/address_bus/sid_slots.rb +0 -42
- data/lib/badline/address_bus.rb +0 -235
- 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/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/kernal_traps.rb +0 -29
- 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/cycleable.rb +0 -38
- data/lib/badline/datasette.rb +0 -161
- 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 -318
- data/lib/badline/drive1541/disk_state.rb +0 -94
- 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/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/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 -852
- data/lib/badline/vic20/sound/output.rb +0 -83
- data/lib/badline/vic20/sound.rb +0 -233
- 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
data/lib/badline/sid.rb
DELETED
|
@@ -1,303 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "badline/sid/waveform"
|
|
4
|
-
require "badline/sid/envelope"
|
|
5
|
-
require "badline/sid/voice"
|
|
6
|
-
require "badline/sid/filter"
|
|
7
|
-
require "badline/sid/decimator"
|
|
8
|
-
require "badline/sid/catch_up"
|
|
9
|
-
|
|
10
|
-
module Badline
|
|
11
|
-
# SID (Sound Interface Device) chip, in either the 6581 or the 8580
|
|
12
|
-
# revision.
|
|
13
|
-
#
|
|
14
|
-
# $D400-$D418 - Voices, filter and volume - write only
|
|
15
|
-
# $D419-$D41A - POTX/POTY paddle inputs - read only
|
|
16
|
-
# $D41B-$D41C - Voice 3 oscillator/envelope - read only
|
|
17
|
-
# $D41D-$D41F - Unconnected
|
|
18
|
-
#
|
|
19
|
-
# The register file mirrors every 32 bytes up to $D7FF. A second or
|
|
20
|
-
# third SID, which only the SID player fits, is built `at` another
|
|
21
|
-
# address and decodes just the 32 bytes there.
|
|
22
|
-
#
|
|
23
|
-
# Reading a write-only or unconnected register returns the last byte the
|
|
24
|
-
# SID saw on the data bus. That value fades to $00 as the capacitance
|
|
25
|
-
# holding it drains. Paddles and the 1351 mouse attach as a pots source
|
|
26
|
-
# responding to #pot_x and #pot_y; with none attached the lines read $FF.
|
|
27
|
-
#
|
|
28
|
-
# Three voices feed the filter and the master volume; #output and #sample
|
|
29
|
-
# read out the mixed result, and #record collects it at an audio rate for
|
|
30
|
-
# #drain_samples. The DSP is clocked lazily and catches up when something
|
|
31
|
-
# asks for its state.
|
|
32
|
-
#
|
|
33
|
-
# The 6581 drives its voices well above ground, so the mix carries a large
|
|
34
|
-
# DC offset that the RC network on the C64 board filters out.
|
|
35
|
-
class SID
|
|
36
|
-
include Addressable
|
|
37
|
-
include CatchUp
|
|
38
|
-
|
|
39
|
-
VOICES = 3
|
|
40
|
-
|
|
41
|
-
# Cycles the data bus holds a value, measured through SID/bitfade.
|
|
42
|
-
BUS_TTL = { mos6581: 0x1d00, mos8580: 0xa2000 }.freeze
|
|
43
|
-
|
|
44
|
-
# Scales the filter's 20-bit mix down to a signed 16-bit sample, as
|
|
45
|
-
# reSID 0.16 does: three voices at full swing and volume 15 span the
|
|
46
|
-
# whole range, on either chip.
|
|
47
|
-
SAMPLE_DIVISOR = ((0xfff * 0xff) >> 7) * 3 * 15 * 2 / (2**16)
|
|
48
|
-
|
|
49
|
-
# Writes the DSP queues between catch-ups. A full queue catches up
|
|
50
|
-
# there and then, so no write loses its timing.
|
|
51
|
-
DEFERRED_WRITES = 0x400
|
|
52
|
-
|
|
53
|
-
# Cycles the filter integrates in one step while synthesizing, after
|
|
54
|
-
# reSID's delta_t_flt. 1 makes the audio exact, at a per-cycle cost.
|
|
55
|
-
FILTER_CHUNK = 4
|
|
56
|
-
|
|
57
|
-
attr_accessor :pots
|
|
58
|
-
attr_reader :model
|
|
59
|
-
|
|
60
|
-
def initialize(model: :mos6581, pots: nil, filter_chunk: FILTER_CHUNK, at: 0xd400)
|
|
61
|
-
addressable_at(at, length: at == 0xd400 ? 2**10 : 2**5)
|
|
62
|
-
@model = model
|
|
63
|
-
@pots = pots
|
|
64
|
-
@bus_ttl_reset = BUS_TTL.fetch(model)
|
|
65
|
-
@filter = Filter.new(model:)
|
|
66
|
-
@synthesizing = false
|
|
67
|
-
@stepped = @synced = false
|
|
68
|
-
@pending_cycles = 0
|
|
69
|
-
@deferred_writes = []
|
|
70
|
-
@decimator = nil
|
|
71
|
-
@samples = []
|
|
72
|
-
@voice_samples = nil
|
|
73
|
-
@filter_chunk = filter_chunk
|
|
74
|
-
@voices = Voice.linked(VOICES, model:)
|
|
75
|
-
@voice1, @voice2, @voice3 = @voices
|
|
76
|
-
@waveform1, @waveform2, @waveform3 = @voices.map(&:waveform)
|
|
77
|
-
reset!
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
# Switches the chip, its filter and its voices to the other model's
|
|
81
|
-
# values. The cycles already passed run on the old model first, and the
|
|
82
|
-
# running state carries over.
|
|
83
|
-
def model=(model)
|
|
84
|
-
catch_up
|
|
85
|
-
@model = model
|
|
86
|
-
@bus_ttl_reset = BUS_TTL.fetch(model)
|
|
87
|
-
@filter.model = model
|
|
88
|
-
@voices.each { |voice| voice.model = model }
|
|
89
|
-
update_span_rules
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# The RES line clears the registers, the data bus, the filter and the
|
|
93
|
-
# voices, all but their accumulators. Recording carries on across it.
|
|
94
|
-
def reset!
|
|
95
|
-
catch_up
|
|
96
|
-
@registers = Memory.new(length: 2**5)
|
|
97
|
-
@bus_value = 0x00
|
|
98
|
-
@bus_ttl = 0
|
|
99
|
-
@voices.each(&:reset!)
|
|
100
|
-
@filter.reset
|
|
101
|
-
update_span_rules
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
# The DSP only counts cycles as they pass. Whatever asks for its state
|
|
105
|
-
# catches it up, a span at a time: each span fast-forwards the voices
|
|
106
|
-
# and ends on one whole cycle, so everything the CPU can read stays
|
|
107
|
-
# exact. The filter only runs once something wants audio.
|
|
108
|
-
def synthesizing? = @synthesizing
|
|
109
|
-
|
|
110
|
-
def synthesize!
|
|
111
|
-
return if @synthesizing
|
|
112
|
-
|
|
113
|
-
@synthesizing = true
|
|
114
|
-
update_span_rules
|
|
115
|
-
catch_up
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
# Starts collecting the output, averaged down to `rate` samples a
|
|
119
|
-
# second, for #drain_samples. `filter_chunk` overrides the one the SID
|
|
120
|
-
# was built with, for a machine that built its own. `clock_hz` is the
|
|
121
|
-
# rate the SID's cycles are taken to run at.
|
|
122
|
-
def record(rate:, filter_chunk: @filter_chunk, clock_hz: TimeOfDay::CLOCK_HZ)
|
|
123
|
-
synthesize!
|
|
124
|
-
catch_up
|
|
125
|
-
@filter_chunk = filter_chunk
|
|
126
|
-
@decimator = Decimator.new(clock_hz:, rate:)
|
|
127
|
-
@samples = []
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
# How far the recording has got into the sample it is averaging, for
|
|
131
|
-
# a host that carries on recording from a saved state: it calls
|
|
132
|
-
# #record, then #load_recording.
|
|
133
|
-
def save_recording(out)
|
|
134
|
-
decimator = @decimator
|
|
135
|
-
raise ArgumentError, "the SID isn't recording" if decimator.nil?
|
|
136
|
-
|
|
137
|
-
out.marker("RECORDING")
|
|
138
|
-
decimator.save_state(out)
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def load_recording(input)
|
|
142
|
-
decimator = @decimator
|
|
143
|
-
raise ArgumentError, "the SID isn't recording" if decimator.nil?
|
|
144
|
-
|
|
145
|
-
input.marker("RECORDING")
|
|
146
|
-
decimator.load_state(input)
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# Also keeps each voice's own output, before the filter and the volume,
|
|
150
|
-
# as each recorded sample closes, for #drain_voice_samples.
|
|
151
|
-
def record_voices!
|
|
152
|
-
@voice_samples = [] if @voice_samples.nil?
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
# The voices' outputs since the last drain, three to a sample, in voice
|
|
156
|
-
# order, or nothing unless #record_voices! asked for them.
|
|
157
|
-
def drain_voice_samples
|
|
158
|
-
return [] if @voice_samples.nil?
|
|
159
|
-
|
|
160
|
-
catch_up
|
|
161
|
-
samples = @voice_samples
|
|
162
|
-
@voice_samples = []
|
|
163
|
-
samples
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
# The samples recorded since the last drain.
|
|
167
|
-
def drain_samples
|
|
168
|
-
catch_up
|
|
169
|
-
samples = @samples
|
|
170
|
-
@samples = []
|
|
171
|
-
samples
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
def voices
|
|
175
|
-
catch_up
|
|
176
|
-
@voices
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
# Runs the DSP up to the current cycle.
|
|
180
|
-
def catch_up! = catch_up
|
|
181
|
-
|
|
182
|
-
# The byte the data bus holds and the cycles until it fades.
|
|
183
|
-
def bus_state = [@bus_value, @bus_ttl]
|
|
184
|
-
|
|
185
|
-
def restore_bus(value, ttl)
|
|
186
|
-
@bus_value = value
|
|
187
|
-
@bus_ttl = ttl
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
def filter
|
|
191
|
-
catch_up
|
|
192
|
-
@filter
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
# Voice 3's oscillator and envelope, the only synthesis state the CPU
|
|
196
|
-
# can see. Programs poll OSC3 with the noise waveform selected for
|
|
197
|
-
# random numbers, and ENV3 to time hard restarts.
|
|
198
|
-
def osc3
|
|
199
|
-
catch_up
|
|
200
|
-
@waveform3.osc3 >> 4
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
def env3
|
|
204
|
-
catch_up
|
|
205
|
-
@voice3.envelope.env3
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
def output
|
|
209
|
-
synthesize!
|
|
210
|
-
catch_up
|
|
211
|
-
@filter.output
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
def sample
|
|
215
|
-
output
|
|
216
|
-
current_sample
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
def cycle!
|
|
220
|
-
age_bus if @bus_ttl != 0
|
|
221
|
-
@pending_cycles += 1
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
def peek(addr)
|
|
225
|
-
case offset_of(addr) % (2**5)
|
|
226
|
-
when 0x19 then latch(pots ? pots.pot_x : 0xff)
|
|
227
|
-
when 0x1a then latch(pots ? pots.pot_y : 0xff)
|
|
228
|
-
when 0x1b then latch(osc3)
|
|
229
|
-
when 0x1c then latch(env3)
|
|
230
|
-
else @bus_value
|
|
231
|
-
end
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
def poke(addr, value)
|
|
235
|
-
reg = offset_of(addr) % (2**5)
|
|
236
|
-
write_register(reg, value) if reg <= 0x18
|
|
237
|
-
latch(value)
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
# Register contents as written, for save states and debugging.
|
|
241
|
-
def register(reg) = @registers.peek(reg)
|
|
242
|
-
|
|
243
|
-
# The registers, the data bus, the voices and the filter, and the span
|
|
244
|
-
# the DSP has yet to catch up on, as it stands: saving leaves the SID
|
|
245
|
-
# as it was. Whether it synthesizes or records is the host's.
|
|
246
|
-
def save_state(out)
|
|
247
|
-
out.marker("SID")
|
|
248
|
-
@registers.save_state(out)
|
|
249
|
-
out.int(@bus_value).int(@bus_ttl).int(@pending_cycles).ints(@deferred_writes)
|
|
250
|
-
@voices.each { |voice| voice.save_state(out) }
|
|
251
|
-
@filter.save_state(out)
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
def load_state(input)
|
|
255
|
-
input.marker("SID")
|
|
256
|
-
@registers.load_state(input)
|
|
257
|
-
@bus_value = input.int
|
|
258
|
-
@bus_ttl = input.int
|
|
259
|
-
@pending_cycles = input.int
|
|
260
|
-
input.ints_into(@deferred_writes)
|
|
261
|
-
@voices.each { |voice| voice.load_state(input) }
|
|
262
|
-
@filter.load_state(input)
|
|
263
|
-
update_span_rules
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
private
|
|
267
|
-
|
|
268
|
-
def latch(value)
|
|
269
|
-
@bus_ttl = @bus_ttl_reset
|
|
270
|
-
@bus_value = value
|
|
271
|
-
end
|
|
272
|
-
|
|
273
|
-
def age_bus
|
|
274
|
-
@bus_ttl -= 1
|
|
275
|
-
@bus_value = 0x00 if @bus_ttl.zero?
|
|
276
|
-
end
|
|
277
|
-
|
|
278
|
-
def write_register(reg, value)
|
|
279
|
-
@registers.poke(reg, value)
|
|
280
|
-
catch_up if @deferred_writes.length == DEFERRED_WRITES * 3
|
|
281
|
-
@deferred_writes.push(@pending_cycles, reg, value)
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
def apply_write(reg, value)
|
|
285
|
-
reg < 0x15 ? write_voice(reg, value) : @filter.write(reg, value)
|
|
286
|
-
end
|
|
287
|
-
|
|
288
|
-
def write_voice(reg, value)
|
|
289
|
-
voice = @voices[reg / 7]
|
|
290
|
-
case reg % 7
|
|
291
|
-
when 0 then voice.waveform.frequency_low = value
|
|
292
|
-
when 1 then voice.waveform.frequency_high = value
|
|
293
|
-
when 2 then voice.waveform.pulse_width_low = value
|
|
294
|
-
when 3 then voice.waveform.pulse_width_high = value
|
|
295
|
-
when 4
|
|
296
|
-
voice.control = value
|
|
297
|
-
update_span_rules
|
|
298
|
-
when 5 then voice.envelope.attack_decay = value
|
|
299
|
-
when 6 then voice.envelope.sustain_release = value
|
|
300
|
-
end
|
|
301
|
-
end
|
|
302
|
-
end
|
|
303
|
-
end
|
data/lib/badline/time_of_day.rb
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Badline
|
|
4
|
-
class TimeOfDay
|
|
5
|
-
# The TOD pin is fed from the AC supply. A CIA passes its region's
|
|
6
|
-
# clock and mains frequency, and these are PAL's.
|
|
7
|
-
CLOCK_HZ = Region::PAL.clock_hz
|
|
8
|
-
MAINS_HZ = Region::PAL.mains_hz
|
|
9
|
-
|
|
10
|
-
FIELDS = %i[tenths seconds minutes hours].freeze
|
|
11
|
-
|
|
12
|
-
def initialize(clock_hz: CLOCK_HZ, mains_hz: MAINS_HZ)
|
|
13
|
-
# The accumulator advances mains_hz per cycle, so a TOD pin pulse has
|
|
14
|
-
# arrived when it reaches clock_hz. Integer math keeps it exact.
|
|
15
|
-
@cycles_per_pulse = clock_hz
|
|
16
|
-
@mains_hz = mains_hz
|
|
17
|
-
@accumulator = 0
|
|
18
|
-
@pulses = 0
|
|
19
|
-
@clock = { tenths: 0x00, seconds: 0x00, minutes: 0x00, hours: 0x01 }
|
|
20
|
-
@alarm = { tenths: 0x00, seconds: 0x00, minutes: 0x00, hours: 0x00 }
|
|
21
|
-
@latch = nil
|
|
22
|
-
@stopped = true
|
|
23
|
-
@alarm_pending = false
|
|
24
|
-
self.fifty_hz = false
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# CRA bit 7 divides the TOD pin by 5 instead of 6. The divider has to
|
|
28
|
-
# match the pin frequency to keep time, so PAL software selects 50 Hz.
|
|
29
|
-
def fifty_hz=(enabled)
|
|
30
|
-
@match = enabled ? 4 : 5
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# The clock and the alarm, field by field in FIELDS order, the latch,
|
|
34
|
-
# and the divider's phase.
|
|
35
|
-
def save_state(out)
|
|
36
|
-
out.int(@accumulator).int(@pulses).int(@match).boolean(@stopped).boolean(@alarm_pending)
|
|
37
|
-
FIELDS.each { |field| out.int(@clock[field]).int(@alarm[field]) }
|
|
38
|
-
out.boolean(!@latch.nil?)
|
|
39
|
-
FIELDS.each { |field| out.int(@latch[field]) } if @latch
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def load_state(input)
|
|
43
|
-
@accumulator = input.int
|
|
44
|
-
@pulses = input.int
|
|
45
|
-
@match = input.int
|
|
46
|
-
@stopped = input.boolean?
|
|
47
|
-
@alarm_pending = input.boolean?
|
|
48
|
-
FIELDS.each do |field|
|
|
49
|
-
@clock[field] = input.int
|
|
50
|
-
@alarm[field] = input.int
|
|
51
|
-
end
|
|
52
|
-
@latch = input.boolean? ? FIELDS.to_h { |field| [field, input.int] } : nil
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Whether the clock is stopped, or gets no pulses on its pin, with no
|
|
56
|
-
# alarm to raise, so its cycles move only the divider's phase.
|
|
57
|
-
def quiet? = (@stopped || @mains_hz.zero?) && !@alarm_pending
|
|
58
|
-
|
|
59
|
-
# Runs +cycles+ quiet cycles at once.
|
|
60
|
-
def fast_forward(cycles)
|
|
61
|
-
@accumulator = (@accumulator + (cycles * @mains_hz)) % @cycles_per_pulse
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def cycle!
|
|
65
|
-
@accumulator += @mains_hz
|
|
66
|
-
pulse! if @accumulator >= @cycles_per_pulse
|
|
67
|
-
return unless @alarm_pending
|
|
68
|
-
|
|
69
|
-
@alarm_pending = false
|
|
70
|
-
yield if block_given?
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def tenths
|
|
74
|
-
value = (@latch || @clock)[:tenths]
|
|
75
|
-
@latch = nil
|
|
76
|
-
value
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def seconds = (@latch || @clock)[:seconds]
|
|
80
|
-
def minutes = (@latch || @clock)[:minutes]
|
|
81
|
-
|
|
82
|
-
def hours
|
|
83
|
-
@latch ||= @clock.dup
|
|
84
|
-
@latch[:hours]
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
attr_reader :pulses
|
|
88
|
-
|
|
89
|
-
# The clock as a read of the tenths would see it: the latch while the
|
|
90
|
-
# clock is latched. In FIELDS order.
|
|
91
|
-
def latched_fields = FIELDS.map { |field| (@latch || @clock)[field] }
|
|
92
|
-
|
|
93
|
-
# The cycles until the clock next steps a tenth, as VICE counts them.
|
|
94
|
-
def cycles_to_tenth
|
|
95
|
-
to_pulse = (@cycles_per_pulse - @accumulator + @mains_hz - 1) / @mains_hz
|
|
96
|
-
to_pulse + ([@match - @pulses, 0].max * @cycles_per_pulse / @mains_hz)
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
# Sets the clock, the alarm and the latch from VICE's fields, in FIELDS
|
|
100
|
-
# order, the latch nil while unlatched.
|
|
101
|
-
def restore_fields(clock, alarm, latch)
|
|
102
|
-
FIELDS.each_with_index do |field, i|
|
|
103
|
-
@clock[field] = clock[i]
|
|
104
|
-
@alarm[field] = alarm[i]
|
|
105
|
-
end
|
|
106
|
-
@latch = latch && FIELDS.each_with_index.to_h { |field, i| [field, latch[i]] }
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
# Sets whether the clock is stopped, the pulses counted towards the
|
|
110
|
-
# next tenth and the cycles until it, placing the divider so the tenth
|
|
111
|
-
# lands then.
|
|
112
|
-
def restore_divider(stopped, pulses, cycles_to_tenth)
|
|
113
|
-
@stopped = stopped
|
|
114
|
-
@pulses = pulses
|
|
115
|
-
to_pulse = cycles_to_tenth - ([@match - pulses, 0].max * @cycles_per_pulse / @mains_hz)
|
|
116
|
-
@accumulator = (@cycles_per_pulse - (to_pulse * @mains_hz)).clamp(0, @cycles_per_pulse - 1)
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
# The clock and alarm as stored, read without latching the clock.
|
|
120
|
-
def registers
|
|
121
|
-
[@clock[:tenths], @clock[:seconds], @clock[:minutes], @clock[:hours],
|
|
122
|
-
@alarm[:tenths], @alarm[:seconds], @alarm[:minutes], @alarm[:hours],
|
|
123
|
-
@stopped ? 1 : 0, @latch ? 1 : 0]
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def write(field, value, alarm:)
|
|
127
|
-
# The frequency counter is held clear while the clock is stopped, and
|
|
128
|
-
# starts counting again from the write to tenths that restarts it.
|
|
129
|
-
if field == :tenths && !alarm && @stopped
|
|
130
|
-
@pulses = 0
|
|
131
|
-
@stopped = false
|
|
132
|
-
end
|
|
133
|
-
store(field, value & (field == :tenths ? 0x0f : 0x7f), alarm: alarm)
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# 12-hour BCD value, bit 7 is the AM/PM flag.
|
|
137
|
-
def write_hours(value, alarm:)
|
|
138
|
-
value &= 0x9f
|
|
139
|
-
# Writing 12 to the hour register flips the AM/PM bit, the same way a
|
|
140
|
-
# carry into 12 does. Writing the alarm hours does not.
|
|
141
|
-
value ^= 0x80 if !alarm && (value & 0x1f) == 0x12
|
|
142
|
-
# Halt the clock when writing hours, so that it doesn't
|
|
143
|
-
# advance mid-update.
|
|
144
|
-
@stopped = true unless alarm
|
|
145
|
-
store(:hours, value, alarm: alarm)
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
private
|
|
149
|
-
|
|
150
|
-
def store(field, value, alarm:)
|
|
151
|
-
target = alarm ? @alarm : @clock
|
|
152
|
-
return if target[field] == value
|
|
153
|
-
|
|
154
|
-
target[field] = value
|
|
155
|
-
@alarm_pending = true if alarm?
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def pulse!
|
|
159
|
-
@accumulator -= @cycles_per_pulse
|
|
160
|
-
return if @stopped
|
|
161
|
-
|
|
162
|
-
# A three-bit ring counter with six states, compared against the
|
|
163
|
-
# divider on each pin pulse rather than on its way past it.
|
|
164
|
-
if @pulses == @match
|
|
165
|
-
@pulses = 0
|
|
166
|
-
advance
|
|
167
|
-
else
|
|
168
|
-
@pulses += 1
|
|
169
|
-
@pulses = 0 if @pulses > 5
|
|
170
|
-
end
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
def advance
|
|
174
|
-
tenths = (@clock[:tenths] + 1) & 0x0f
|
|
175
|
-
@clock[:tenths] = tenths == 10 ? 0 : tenths
|
|
176
|
-
carry_seconds if tenths == 10
|
|
177
|
-
@alarm_pending = true if alarm?
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
def carry_seconds
|
|
181
|
-
return unless advance_pair(:seconds)
|
|
182
|
-
return unless advance_pair(:minutes)
|
|
183
|
-
|
|
184
|
-
advance_hours
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
# Seconds and minutes hold a four-bit low digit that carries at ten into
|
|
188
|
-
# a three-bit high digit that carries out at six. Both are plain binary
|
|
189
|
-
# counters, so out-of-range BCD counts up from where it was written.
|
|
190
|
-
def advance_pair(field)
|
|
191
|
-
low = ((@clock[field] & 0x0f) + 1) & 0x0f
|
|
192
|
-
high = (@clock[field] >> 4) & 0x07
|
|
193
|
-
carry = false
|
|
194
|
-
|
|
195
|
-
if low == 10
|
|
196
|
-
low = 0
|
|
197
|
-
high = (high + 1) & 0x07
|
|
198
|
-
if high == 6
|
|
199
|
-
high = 0
|
|
200
|
-
carry = true
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
@clock[field] = (high << 4) | low
|
|
205
|
-
carry
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
# The hour runs 9 -> 10 and 12 -> 1 by swapping its two digits, and the
|
|
209
|
-
# AM/PM bit flips as it passes through 12.
|
|
210
|
-
def advance_hours
|
|
211
|
-
pm = @clock[:hours] & 0x80
|
|
212
|
-
high = (@clock[:hours] >> 4) & 0x01
|
|
213
|
-
low = @clock[:hours] & 0x0f
|
|
214
|
-
|
|
215
|
-
if (high == 1 && low == 2) || (high.zero? && low == 9)
|
|
216
|
-
low = high
|
|
217
|
-
high ^= 1
|
|
218
|
-
else
|
|
219
|
-
low = (low + 1) & 0x0f
|
|
220
|
-
pm ^= 0x80 if high == 1 && low == 2
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
@clock[:hours] = pm | (high << 4) | low
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
def alarm? = @clock == @alarm
|
|
227
|
-
end
|
|
228
|
-
end
|
data/lib/badline/traps.rb
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Badline
|
|
4
|
-
module Traps
|
|
5
|
-
def install_trap(addr, &handler)
|
|
6
|
-
(@traps ||= {})[addr] = handler
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def remove_trap(addr)
|
|
10
|
-
@traps&.delete(addr)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
private
|
|
14
|
-
|
|
15
|
-
def run_traps
|
|
16
|
-
@traps[@program_counter]&.call if @traps
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Badline
|
|
4
|
-
class VIA
|
|
5
|
-
# One port's pair of control lines, CA1 and CA2 or CB1 and CB2, set up
|
|
6
|
-
# by a nibble of the peripheral control register, and their two
|
|
7
|
-
# interrupt flags. Bit 0 picks the active edge of C1, rising when set.
|
|
8
|
-
# Bits 3-1 pick the C2 mode:
|
|
9
|
-
#
|
|
10
|
-
# 000 input, falling edge 100 handshake output
|
|
11
|
-
# 001 independent, falling 101 pulse output
|
|
12
|
-
# 010 input, rising edge 110 low output
|
|
13
|
-
# 011 independent, rising 111 high output
|
|
14
|
-
#
|
|
15
|
-
# A port access clears both flags, but an independent input keeps C2's.
|
|
16
|
-
# In handshake mode C2 goes low on a port access and back high on the
|
|
17
|
-
# next active C1 edge. In pulse mode it goes low for the cycle after the
|
|
18
|
-
# access. Port A handshakes on reads and writes, port B on writes only.
|
|
19
|
-
class ControlLines
|
|
20
|
-
attr_reader :control, :c1_high, :c2_high
|
|
21
|
-
|
|
22
|
-
# The level driven on C2, high while it is an input.
|
|
23
|
-
attr_reader :c2_output
|
|
24
|
-
|
|
25
|
-
def initialize(interrupts, c1_flag:, c2_flag:, handshake_on_read:)
|
|
26
|
-
@interrupts = interrupts
|
|
27
|
-
@c1_flag = c1_flag
|
|
28
|
-
@c2_flag = c2_flag
|
|
29
|
-
@handshake_on_read = handshake_on_read
|
|
30
|
-
@c1_high = @c2_high = true
|
|
31
|
-
reset!
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
# Back to input mode with both handshake outputs released. The input
|
|
35
|
-
# levels carry over.
|
|
36
|
-
def reset!
|
|
37
|
-
@control = 0
|
|
38
|
-
@handshake_low = false
|
|
39
|
-
@pulse = 0
|
|
40
|
-
drive
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def control=(nibble)
|
|
44
|
-
@control = nibble & 0x0f
|
|
45
|
-
drive
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# Only the pulse output needs the clock.
|
|
49
|
-
def pulsing? = @pulse.positive?
|
|
50
|
-
|
|
51
|
-
def cycle!
|
|
52
|
-
@pulse -= 1
|
|
53
|
-
drive if @pulse.zero?
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def active_c1_edge?(high) = high == @control.anybits?(0x01)
|
|
57
|
-
|
|
58
|
-
# The lines' levels and mode. Which flags they set, and whether reads
|
|
59
|
-
# handshake, are the port's wiring.
|
|
60
|
-
def save_state(out)
|
|
61
|
-
out.int(@control).boolean(@c1_high).boolean(@c2_high).boolean(@handshake_low).int(@pulse).boolean(@c2_output)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def load_state(input)
|
|
65
|
-
@control = input.int
|
|
66
|
-
@c1_high = input.boolean?
|
|
67
|
-
@c2_high = input.boolean?
|
|
68
|
-
@handshake_low = input.boolean?
|
|
69
|
-
@pulse = input.int
|
|
70
|
-
@c2_output = input.boolean?
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# Everything the lines hold, for comparing them at two points.
|
|
74
|
-
def state = [@control, @c1_high, @c2_high, @handshake_low, @pulse, @c2_output]
|
|
75
|
-
|
|
76
|
-
# A new C1 level. An active edge sets the flag and ends a handshake.
|
|
77
|
-
def c1=(high)
|
|
78
|
-
return if high == @c1_high
|
|
79
|
-
|
|
80
|
-
@c1_high = high
|
|
81
|
-
return unless active_c1_edge?(high)
|
|
82
|
-
|
|
83
|
-
@handshake_low = false
|
|
84
|
-
drive
|
|
85
|
-
@interrupts.set(@c1_flag)
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
# A new C2 level. An active edge sets the flag while C2 is an input.
|
|
89
|
-
def c2=(high)
|
|
90
|
-
return if high == @c2_high
|
|
91
|
-
|
|
92
|
-
@c2_high = high
|
|
93
|
-
@interrupts.set(@c2_flag) if @control.nobits?(0x08) && high == @control.anybits?(0x04)
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
# A read or write of the handshaking port register.
|
|
97
|
-
def access!(write)
|
|
98
|
-
@interrupts.clear(independent? ? @c1_flag : @c1_flag | @c2_flag)
|
|
99
|
-
return unless write || @handshake_on_read
|
|
100
|
-
|
|
101
|
-
case @control >> 1
|
|
102
|
-
when 4 then @handshake_low = true
|
|
103
|
-
when 5 then @pulse = 2
|
|
104
|
-
end
|
|
105
|
-
drive
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
private
|
|
109
|
-
|
|
110
|
-
def independent? = @control & 0x0a == 0x02
|
|
111
|
-
|
|
112
|
-
def drive
|
|
113
|
-
@c2_output = case @control >> 1
|
|
114
|
-
when 4 then !@handshake_low
|
|
115
|
-
when 5 then @pulse.zero?
|
|
116
|
-
when 6 then false
|
|
117
|
-
else true
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
end
|