badline 0.13.0 → 0.15.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 +72 -1
- data/CLAUDE.md +42 -12
- data/CONTRIBUTING.md +4 -3
- data/README.md +76 -13
- data/doc/media.md +2 -1
- data/doc/pinned-behaviour.md +174 -0
- data/doc/snapshot-format.md +1197 -0
- data/doc/snapshots.md +90 -40
- data/lib/badline/audio/bare_player.rb +46 -17
- data/lib/badline/audio/machine_player.rb +6 -10
- data/lib/badline/audio/renderer.rb +32 -21
- data/lib/badline/c128/banks.rb +7 -6
- data/lib/badline/c128/bus/keyed_state.rb +45 -0
- data/lib/badline/c128/bus.rb +36 -4
- data/lib/badline/c128/drives.rb +6 -25
- 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 +27 -0
- data/lib/badline/c128/modes.rb +19 -9
- data/lib/badline/c128/z80_turns.rb +1 -1
- data/lib/badline/c128.rb +8 -8
- data/lib/badline/c64/attachments.rb +0 -44
- data/lib/badline/c64/banked_ram/plus256k.rb +18 -10
- data/lib/badline/c64/banked_ram/plus60k.rb +8 -6
- data/lib/badline/c64/banked_ram/unexpanded.rb +2 -2
- data/lib/badline/c64/bus/debug_register.rb +32 -0
- data/lib/badline/c64/bus/extra_sids.rb +80 -0
- data/lib/badline/c64/bus/keyed_state.rb +41 -0
- data/lib/badline/c64/bus.rb +3 -1
- data/lib/badline/c64/cartridge/action_replay.rb +6 -15
- data/lib/badline/c64/cartridge/comal80.rb +1 -0
- data/lib/badline/c64/cartridge/dinamic.rb +3 -1
- data/lib/badline/c64/cartridge/easy_flash.rb +0 -15
- data/lib/badline/c64/cartridge/epyx_fastload.rb +0 -8
- data/lib/badline/c64/cartridge/final_cartridge3.rb +1 -12
- data/lib/badline/c64/cartridge/flash.rb +3 -3
- data/lib/badline/c64/cartridge/fun_play.rb +2 -1
- data/lib/badline/c64/cartridge/g_mod2.rb +0 -12
- data/lib/badline/c64/cartridge/game_system.rb +2 -1
- data/lib/badline/c64/cartridge/geo_ram.rb +0 -16
- data/lib/badline/c64/cartridge/kcs_power.rb +0 -8
- data/lib/badline/c64/cartridge/keyed_state.rb +514 -0
- data/lib/badline/c64/cartridge/magic_desk.rb +2 -1
- data/lib/badline/c64/cartridge/ocean.rb +1 -0
- data/lib/badline/c64/cartridge/pagefox.rb +1 -10
- data/lib/badline/c64/cartridge/retro_replay.rb +0 -8
- data/lib/badline/c64/cartridge/rgcd.rb +2 -11
- data/lib/badline/c64/cartridge/super_games.rb +3 -12
- data/lib/badline/c64/cartridge/zaxxon.rb +1 -16
- data/lib/badline/c64/cartridge.rb +4 -30
- data/lib/badline/c64/kernal_traps.rb +28 -25
- data/lib/badline/c64/keyed_modules.rb +115 -0
- data/lib/badline/c64/keyed_state.rb +68 -0
- data/lib/badline/c64/reu/dma.rb +0 -4
- data/lib/badline/c64/reu/keyed_state.rb +140 -0
- data/lib/badline/c64/reu/ram.rb +0 -15
- data/lib/badline/c64/reu.rb +1 -3
- data/lib/badline/c64/true_drives.rb +56 -5
- data/lib/badline/c64.rb +7 -3
- data/lib/badline/chips/cia/interrupt_register.rb +0 -17
- data/lib/badline/chips/cia/keyed_parts.rb +213 -0
- data/lib/badline/chips/cia/serial.rb +0 -4
- data/lib/badline/chips/cia/time_of_day.rb +0 -22
- data/lib/badline/chips/cia/timer.rb +0 -20
- data/lib/badline/chips/cia.rb +2 -2
- data/lib/badline/chips/cpu/core.rb +18 -2
- data/lib/badline/chips/cpu/keyed_state.rb +177 -0
- data/lib/badline/chips/cpu/microcode.rb +16 -0
- data/lib/badline/chips/cpu/port.rb +20 -3
- data/lib/badline/chips/cpu.rb +5 -0
- data/lib/badline/chips/sid/decimator.rb +10 -8
- data/lib/badline/chips/sid/envelope.rb +1 -6
- data/lib/badline/chips/sid/filter.rb +0 -14
- data/lib/badline/chips/sid/keyed_parts.rb +286 -0
- data/lib/badline/chips/sid/voice.rb +0 -10
- data/lib/badline/chips/sid/waveform.rb +0 -2
- data/lib/badline/chips/sid.rb +1 -2
- data/lib/badline/chips/ted/beam.rb +118 -0
- data/lib/badline/chips/ted/fetches.rb +199 -0
- data/lib/badline/chips/ted/keyed_state.rb +156 -0
- data/lib/badline/chips/ted/modes.rb +134 -0
- data/lib/badline/chips/ted/palette.rb +43 -0
- data/lib/badline/chips/ted/picture.rb +182 -0
- data/lib/badline/chips/ted/sound/output.rb +86 -0
- data/lib/badline/chips/ted/sound.rb +284 -0
- data/lib/badline/chips/ted/timers.rb +66 -0
- data/lib/badline/chips/ted.rb +190 -0
- data/lib/badline/chips/tia.rb +61 -0
- data/lib/badline/chips/vdc/keyed_parts.rb +105 -0
- data/lib/badline/chips/vdc/painter.rb +0 -12
- data/lib/badline/chips/vdc/raster.rb +0 -16
- data/lib/badline/chips/vdc/window.rb +0 -9
- data/lib/badline/chips/vdc.rb +1 -2
- data/lib/badline/chips/via/control_lines.rb +0 -15
- data/lib/badline/chips/via/interrupt_register.rb +0 -9
- data/lib/badline/chips/via/keyed_parts.rb +163 -0
- data/lib/badline/chips/via/shift_register.rb +0 -14
- data/lib/badline/chips/via/timer1.rb +0 -13
- data/lib/badline/chips/via/timer2.rb +0 -18
- data/lib/badline/chips/via.rb +1 -2
- data/lib/badline/chips/vic/border_mask.rb +0 -10
- data/lib/badline/chips/vic/collisions.rb +0 -11
- data/lib/badline/chips/vic/color_patches.rb +0 -11
- data/lib/badline/chips/vic/display_state.rb +0 -19
- data/lib/badline/chips/vic/graphics_shifter.rb +0 -4
- 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 +0 -18
- data/lib/badline/chips/vic/registers.rb +0 -9
- data/lib/badline/chips/vic/sequencer.rb +0 -2
- data/lib/badline/chips/vic/sprite/internal_bus.rb +0 -11
- data/lib/badline/chips/vic/sprite.rb +0 -2
- data/lib/badline/chips/vic/sprites.rb +0 -3
- data/lib/badline/chips/vic.rb +6 -2
- data/lib/badline/chips/vic_i/keyed_parts.rb +142 -0
- data/lib/badline/chips/vic_i/painter.rb +0 -4
- data/lib/badline/chips/vic_i/sound.rb +38 -46
- data/lib/badline/chips/vic_i.rb +2 -2
- data/lib/badline/chips/z80/core.rb +2 -2
- data/lib/badline/chips/z80/keyed_state.rb +73 -0
- data/lib/badline/chips.rb +10 -0
- data/lib/badline/core.rb +4 -21
- data/lib/badline/drives/datasette/keyed_state.rb +43 -0
- data/lib/badline/drives/datasette.rb +62 -12
- data/lib/badline/drives/engine/core.rb +3 -0
- data/lib/badline/drives/engine/serial_lines.rb +4 -7
- data/lib/badline/drives/model1541/bus.rb +0 -13
- data/lib/badline/drives/model1541/disk.rb +9 -8
- data/lib/badline/drives/model1541/keyed_state.rb +251 -0
- data/lib/badline/drives/model1541/mechanism.rb +0 -2
- data/lib/badline/drives/model1541.rb +1 -2
- data/lib/badline/drives/model1571/bus.rb +0 -13
- data/lib/badline/drives/model1571/keyed_state.rb +108 -0
- data/lib/badline/drives/model1571/wd1770.rb +0 -14
- data/lib/badline/drives/model1571.rb +1 -2
- data/lib/badline/drives/model1581/bus.rb +0 -13
- data/lib/badline/drives/model1581/disk.rb +0 -4
- data/lib/badline/drives/model1581/keyed_state.rb +280 -0
- data/lib/badline/drives/model1581/mechanism.rb +0 -21
- data/lib/badline/drives/model1581/slot.rb +0 -18
- data/lib/badline/drives/model1581/wd1772.rb +0 -2
- data/lib/badline/drives/model1581.rb +2 -2
- data/lib/badline/drives.rb +8 -0
- data/lib/badline/frontend/app.rb +3 -3
- data/lib/badline/frontend/boot.rb +4 -2
- data/lib/badline/frontend/controls.rb +25 -5
- data/lib/badline/frontend/drive_led.rb +44 -21
- data/lib/badline/frontend/keys.rb +14 -2
- data/lib/badline/frontend/media_slots.rb +11 -1
- data/lib/badline/frontend/menu/menu_dialogs.rb +4 -3
- data/lib/badline/frontend/menu/menu_media.rb +13 -3
- data/lib/badline/frontend/menu/menu_pages.rb +8 -8
- data/lib/badline/frontend/menu/menu_ports.rb +13 -1
- data/lib/badline/frontend/screen.rb +33 -12
- data/lib/badline/frontend/screens.rb +2 -1
- data/lib/badline/frontend/snapshots.rb +12 -1
- data/lib/badline/frontend/sound.rb +4 -4
- data/lib/badline/frontend/timeline.rb +43 -12
- data/lib/badline/input/matrix_typist.rb +98 -0
- data/lib/badline/input.rb +1 -0
- data/lib/badline/kernal_trap/chrout.rb +45 -0
- data/lib/badline/kernal_trap/dos/channel.rb +0 -27
- data/lib/badline/kernal_trap/dos/channels.rb +0 -25
- data/lib/badline/kernal_trap/dos/memory.rb +0 -9
- data/lib/badline/kernal_trap/dos/status.rb +0 -8
- data/lib/badline/kernal_trap/dos/write_file.rb +0 -18
- data/lib/badline/kernal_trap/dos.rb +0 -19
- 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 +14 -16
- data/lib/badline/kernal_trap/routine.rb +12 -0
- data/lib/badline/kernal_trap/save.rb +8 -18
- data/lib/badline/kernal_trap/serial.rb +1 -17
- data/lib/badline/kernal_trap.rb +2 -0
- data/lib/badline/machine/keyboard_buffer.rb +49 -0
- data/lib/badline/machine/settling.rb +29 -0
- data/lib/badline/machine.rb +29 -6
- data/lib/badline/media/boot_disk.rb +14 -2
- data/lib/badline/media/extensions.rb +10 -0
- data/lib/badline/media/plus4_media.rb +68 -0
- data/lib/badline/media/program.rb +20 -6
- data/lib/badline/media.rb +33 -12
- data/lib/badline/memory.rb +3 -6
- data/lib/badline/options/family.rb +6 -2
- data/lib/badline/options/help.rb +66 -16
- data/lib/badline/options/table.rb +17 -2
- data/lib/badline/options/validation.rb +26 -2
- data/lib/badline/options.rb +42 -9
- data/lib/badline/plus4/acia.rb +45 -0
- data/lib/badline/plus4/bus.rb +375 -0
- data/lib/badline/plus4/cassette_sense.rb +21 -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 +76 -0
- data/lib/badline/plus4/keyed_modules.rb +99 -0
- data/lib/badline/plus4/keyed_parts.rb +143 -0
- data/lib/badline/plus4/keyed_state.rb +41 -0
- data/lib/badline/plus4/model.rb +38 -0
- data/lib/badline/plus4/user_port.rb +31 -0
- data/lib/badline/plus4.rb +240 -0
- data/lib/badline/roms/README +38 -0
- 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/snapshot/c128_setup.rb +9 -20
- data/lib/badline/snapshot/c64_setup.rb +28 -24
- data/lib/badline/snapshot/container.rb +6 -0
- data/lib/badline/snapshot/field_doc/markdown.rb +113 -0
- data/lib/badline/snapshot/field_doc.rb +148 -0
- data/lib/badline/snapshot/image.rb +143 -28
- 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/plus4_setup.rb +39 -0
- data/lib/badline/snapshot/storage_setup.rb +29 -34
- data/lib/badline/snapshot/vic20_setup.rb +6 -15
- data/lib/badline/snapshot/vice/reu1764.rb +2 -2
- data/lib/badline/snapshot/vice.rb +7 -31
- data/lib/badline/snapshot.rb +48 -20
- data/lib/badline/storage/crt_file.rb +3 -1
- data/lib/badline/storage/g64_image.rb +9 -4
- data/lib/badline/storage/tap.rb +57 -20
- data/lib/badline/support/checkpoint.rb +3 -2
- data/lib/badline/support/plus4_checkpoint.rb +42 -0
- data/lib/badline/version.rb +1 -1
- data/lib/badline/vic20/attachments.rb +3 -0
- data/lib/badline/vic20/bus/keyed_state.rb +52 -0
- data/lib/badline/vic20/bus.rb +1 -2
- data/lib/badline/vic20/keyed_modules.rb +73 -0
- data/lib/badline/vic20/keyed_state.rb +45 -0
- data/lib/badline/vic20.rb +5 -5
- data/lib/badline.rb +1 -0
- metadata +75 -42
- data/lib/badline/c128/bus/saved_state.rb +0 -53
- data/lib/badline/c128/saved_state.rb +0 -117
- data/lib/badline/c64/bus/saved_state.rb +0 -68
- data/lib/badline/c64/cartridge/flash/saved_state.rb +0 -40
- data/lib/badline/c64/cartridge/retro_replay/saved_state.rb +0 -47
- data/lib/badline/c64/cartridge/saved_state.rb +0 -63
- data/lib/badline/c64/reu/dma/saved_state.rb +0 -52
- data/lib/badline/c64/reu/saved_state.rb +0 -55
- data/lib/badline/c64/saved_state.rb +0 -112
- data/lib/badline/chips/cia/saved_state.rb +0 -49
- data/lib/badline/chips/cia/serial/saved_state.rb +0 -45
- data/lib/badline/chips/cpu/saved_state.rb +0 -117
- data/lib/badline/chips/sid/envelope/saved_state.rb +0 -70
- data/lib/badline/chips/sid/filter/saved_state.rb +0 -42
- data/lib/badline/chips/sid/saved_state.rb +0 -52
- data/lib/badline/chips/sid/waveform/saved_state.rb +0 -68
- data/lib/badline/chips/vdc/saved_state.rb +0 -36
- data/lib/badline/chips/via/saved_state.rb +0 -44
- data/lib/badline/chips/vic/graphics_shifter/saved_state.rb +0 -40
- data/lib/badline/chips/vic/saved_state.rb +0 -82
- data/lib/badline/chips/vic/sequencer/saved_state.rb +0 -91
- data/lib/badline/chips/vic/sprite/saved_state.rb +0 -66
- data/lib/badline/chips/vic/sprites/saved_state.rb +0 -59
- data/lib/badline/chips/vic_i/painter/saved_state.rb +0 -40
- data/lib/badline/chips/vic_i/saved_state.rb +0 -55
- data/lib/badline/chips/z80/saved_state.rb +0 -71
- data/lib/badline/chrout_trap.rb +0 -43
- data/lib/badline/debug_register.rb +0 -28
- data/lib/badline/drives/datasette/saved_state.rb +0 -37
- data/lib/badline/drives/model1541/disk/saved_state.rb +0 -88
- data/lib/badline/drives/model1541/mechanism/saved_state.rb +0 -72
- data/lib/badline/drives/model1541/saved_state.rb +0 -44
- data/lib/badline/drives/model1571/saved_state.rb +0 -47
- data/lib/badline/drives/model1581/disk/saved_state.rb +0 -89
- data/lib/badline/drives/model1581/saved_state.rb +0 -42
- data/lib/badline/drives/model1581/wd1772/saved_state.rb +0 -68
- data/lib/badline/keyboard_buffer.rb +0 -33
- data/lib/badline/snapshot/setup.rb +0 -31
- data/lib/badline/snapshot/state.rb +0 -179
- data/lib/badline/vic20/bus/saved_state.rb +0 -35
- data/lib/badline/vic20/saved_state.rb +0 -110
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class VIC
|
|
6
|
+
class Registers
|
|
7
|
+
# The registers as the VIC holds them. The IRQ line comes from
|
|
8
|
+
# $D019 and $D01A on load.
|
|
9
|
+
module KeyedState
|
|
10
|
+
def save_fields(out)
|
|
11
|
+
out.bytes("registers", @bytes)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def load_fields(input)
|
|
15
|
+
input.bytes_into("registers", @bytes)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def restored! = update_irq_line
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
include KeyedState
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class DisplayState
|
|
25
|
+
# The video counters, the row counter, display or idle state, the
|
|
26
|
+
# bad line conditions and BA.
|
|
27
|
+
module KeyedState
|
|
28
|
+
def save_fields(out)
|
|
29
|
+
out.int("vc_base", @vc_base).int("vc", @vc).int("vmli", @vmli).int("rc", @rc)
|
|
30
|
+
out.bool("display_state", @display).bool("bad_lines_enabled", @bad_lines_enabled).bool("matched", @matched)
|
|
31
|
+
out.optional_int("ba", @ba)
|
|
32
|
+
out.int("line_bits", @line_bits).bool("den_line", @den_line).bool("in_window", @in_window)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def load_fields(input)
|
|
36
|
+
@vc_base = input.masked("vc_base", @vc_base, 0x3ff)
|
|
37
|
+
@vc = input.masked("vc", @vc, 0x3ff)
|
|
38
|
+
@vmli = input.int("vmli", @vmli)
|
|
39
|
+
@rc = input.masked("rc", @rc, 0x07)
|
|
40
|
+
@display = input.bool("display_state", @display)
|
|
41
|
+
@bad_lines_enabled = input.bool("bad_lines_enabled", @bad_lines_enabled)
|
|
42
|
+
@matched = input.bool("matched", @matched)
|
|
43
|
+
@ba = input.optional_int("ba")
|
|
44
|
+
@line_bits = input.int("line_bits", @line_bits)
|
|
45
|
+
@den_line = input.bool("den_line", @den_line)
|
|
46
|
+
@in_window = input.bool("in_window", @in_window)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
include KeyedState
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class GraphicsShifter
|
|
54
|
+
# The pipeline between the g-access and the pixels, under `prefix`.
|
|
55
|
+
module KeyedState
|
|
56
|
+
def save_fields(out, prefix)
|
|
57
|
+
out.int("#{prefix}next_ecm_bmm", @next_ecm_bmm).int("#{prefix}black_below", @black_below)
|
|
58
|
+
out.ints("#{prefix}colors", @colors).ints("#{prefix}fg", @fg.map { |set| set ? 1 : 0 })
|
|
59
|
+
out.int("#{prefix}gbuf", @gbuf).int("#{prefix}vbuf", @vbuf).int("#{prefix}cbuf", @cbuf)
|
|
60
|
+
out.int("#{prefix}flop", @flop).int("#{prefix}pixel", @pixel).int("#{prefix}mode_lookup", @mode_lookup)
|
|
61
|
+
out.int("#{prefix}mode_read", @mode_read).bool("#{prefix}late_mcm", @late_mcm)
|
|
62
|
+
out.bool("#{prefix}late_read", @late_read)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def load_fields(input, prefix)
|
|
66
|
+
@next_ecm_bmm = input.int("#{prefix}next_ecm_bmm", @next_ecm_bmm)
|
|
67
|
+
@black_below = input.int("#{prefix}black_below", @black_below)
|
|
68
|
+
input.ints_into("#{prefix}colors", @colors)
|
|
69
|
+
fg = input.ints("#{prefix}fg", @fg.map { |set| set ? 1 : 0 })
|
|
70
|
+
@fg.each_index { |index| @fg[index] = fg.fetch(index, 0) == 1 }
|
|
71
|
+
@gbuf = input.int("#{prefix}gbuf", @gbuf)
|
|
72
|
+
@vbuf = input.int("#{prefix}vbuf", @vbuf)
|
|
73
|
+
@cbuf = input.int("#{prefix}cbuf", @cbuf)
|
|
74
|
+
@flop = input.int("#{prefix}flop", @flop)
|
|
75
|
+
@pixel = input.int("#{prefix}pixel", @pixel)
|
|
76
|
+
@mode_lookup = input.int("#{prefix}mode_lookup", @mode_lookup)
|
|
77
|
+
@mode_read = input.int("#{prefix}mode_read", @mode_read)
|
|
78
|
+
@late_mcm = input.bool("#{prefix}late_mcm", @late_mcm)
|
|
79
|
+
@late_read = input.bool("#{prefix}late_read", @late_read)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
include KeyedState
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
class BorderMask
|
|
87
|
+
# The line's border coverage, under `prefix`.
|
|
88
|
+
module KeyedState
|
|
89
|
+
def save_fields(out, prefix)
|
|
90
|
+
out.ints("#{prefix}groups", @groups).ints("#{prefix}mask", @mask.map { |set| set ? 1 : 0 })
|
|
91
|
+
out.bytes("#{prefix}snapshot", @snapshot)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def load_fields(input, prefix)
|
|
95
|
+
input.ints_into("#{prefix}groups", @groups)
|
|
96
|
+
mask = input.ints("#{prefix}mask", @mask.map { |set| set ? 1 : 0 })
|
|
97
|
+
@mask.each_index { |index| @mask[index] = mask.fetch(index, 0) == 1 }
|
|
98
|
+
input.bytes_into("#{prefix}snapshot", @snapshot)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
include KeyedState
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
class ColorPatches
|
|
106
|
+
# The line's colour writes, four values to a patch, under `prefix`.
|
|
107
|
+
module KeyedState
|
|
108
|
+
def save_fields(out, prefix)
|
|
109
|
+
out.ints("#{prefix}patches", @patches.flatten)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def load_fields(input, prefix)
|
|
113
|
+
values = input.ints("#{prefix}patches", [])
|
|
114
|
+
@patches.replace(values.each_slice(4).to_a)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
include KeyedState
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
class Sequencer
|
|
122
|
+
# The sequencer's fields: the border flip-flops and compares, the
|
|
123
|
+
# pixel pipeline and the shifter, with the line batch under
|
|
124
|
+
# `line_prefix` when `line` is true. Foreground masks go as text:
|
|
125
|
+
# "shifter", or the mode table and the data byte.
|
|
126
|
+
module KeyedState
|
|
127
|
+
# The foreground patterns' codes: the shifter's own, HIRES_FG's by
|
|
128
|
+
# index, and PAIR_FG's after them.
|
|
129
|
+
FG_SHIFTER = -1
|
|
130
|
+
PAIR_CODES = 256
|
|
131
|
+
|
|
132
|
+
def save_fields(out, line_prefix)
|
|
133
|
+
out.bool("first_csel", @first_csel).optional_int("left_vertical_border", left_vertical_code)
|
|
134
|
+
out.ints("cur_colors", @cur_colors).text("cur_fg", fg_name(@cur_fg))
|
|
135
|
+
out.ints("prev_colors", @prev_colors).text("prev_fg", fg_name(@prev_fg))
|
|
136
|
+
out.bool("vertical_border", @vertical_border).bool("vertical_armed", @vertical_armed)
|
|
137
|
+
out.bool("main_border", @main_border).int("xscroll", @xscroll).int("last_shift", @last_shift)
|
|
138
|
+
out.int("last_mode", @last_mode).bool("settling", @settling).bool("prev_fresh", @prev_fresh)
|
|
139
|
+
out.bool("check", @check)
|
|
140
|
+
@shifter.save_fields(out, "shifter.")
|
|
141
|
+
out.int("#{line_prefix}number", @line).bytes("#{line_prefix}colors", @colors)
|
|
142
|
+
out.ints("#{line_prefix}fg", @fg.map { |set| set ? 1 : 0 })
|
|
143
|
+
@border_mask.save_fields(out, "#{line_prefix}border.")
|
|
144
|
+
@color_patches.save_fields(out, line_prefix)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def load_fields(input, line_prefix, line)
|
|
148
|
+
@first_csel = input.bool("first_csel", @first_csel)
|
|
149
|
+
left = input.optional_int("left_vertical_border")
|
|
150
|
+
@left_vertical_border = left.nil? ? nil : left == 1
|
|
151
|
+
input.ints_into("cur_colors", @cur_colors)
|
|
152
|
+
@cur_fg = fg_named(input.text("cur_fg", fg_name(@cur_fg)))
|
|
153
|
+
input.ints_into("prev_colors", @prev_colors)
|
|
154
|
+
@prev_fg = fg_named(input.text("prev_fg", fg_name(@prev_fg)))
|
|
155
|
+
load_pipeline_fields(input)
|
|
156
|
+
@shifter.load_fields(input, "shifter.")
|
|
157
|
+
load_line_fields(input, line_prefix) if line
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
private
|
|
161
|
+
|
|
162
|
+
def left_vertical_code
|
|
163
|
+
left = @left_vertical_border
|
|
164
|
+
return nil if left.nil?
|
|
165
|
+
|
|
166
|
+
left ? 1 : 0
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def load_pipeline_fields(input)
|
|
170
|
+
@vertical_border = input.bool("vertical_border", @vertical_border)
|
|
171
|
+
@vertical_armed = input.bool("vertical_armed", @vertical_armed)
|
|
172
|
+
@main_border = input.bool("main_border", @main_border)
|
|
173
|
+
@xscroll = input.masked("xscroll", @xscroll, 0x07)
|
|
174
|
+
@last_shift = input.int("last_shift", @last_shift)
|
|
175
|
+
@last_mode = input.int("last_mode", @last_mode)
|
|
176
|
+
@settling = input.bool("settling", @settling)
|
|
177
|
+
@prev_fresh = input.bool("prev_fresh", @prev_fresh)
|
|
178
|
+
@check = input.bool("check", @check)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def load_line_fields(input, line_prefix)
|
|
182
|
+
@line = input.int("#{line_prefix}number", @line)
|
|
183
|
+
input.bytes_into("#{line_prefix}colors", @colors)
|
|
184
|
+
fg = input.ints("#{line_prefix}fg", @fg.map { |set| set ? 1 : 0 })
|
|
185
|
+
@fg.each_index { |index| @fg[index] = fg.fetch(index, 0) == 1 }
|
|
186
|
+
@border_mask.load_fields(input, "#{line_prefix}border.")
|
|
187
|
+
@color_patches.load_fields(input, line_prefix)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def fg_name(pattern)
|
|
191
|
+
code = fg_code(pattern)
|
|
192
|
+
return "shifter" if code == FG_SHIFTER
|
|
193
|
+
return "hires:#{code}" if code < PAIR_CODES
|
|
194
|
+
|
|
195
|
+
"pair:#{code - PAIR_CODES}"
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def fg_named(name)
|
|
199
|
+
return @shifter.fg if name == "shifter"
|
|
200
|
+
|
|
201
|
+
table, number = name.split(":")
|
|
202
|
+
index = number.to_i
|
|
203
|
+
return GraphicsMode::PAIR_FG.fetch(index.clamp(0, GraphicsMode::PAIR_FG.length - 1)) if table == "pair"
|
|
204
|
+
|
|
205
|
+
GraphicsMode::HIRES_FG.fetch(index.clamp(0, GraphicsMode::HIRES_FG.length - 1))
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def fg_code(pattern)
|
|
209
|
+
return FG_SHIFTER if pattern.equal?(@shifter.fg)
|
|
210
|
+
|
|
211
|
+
hires = GraphicsMode::HIRES_FG.index { |fg| fg.equal?(pattern) }
|
|
212
|
+
return hires if hires
|
|
213
|
+
|
|
214
|
+
pair = GraphicsMode::PAIR_FG.index { |fg| fg.equal?(pattern) }
|
|
215
|
+
raise ArgumentError, "a foreground mask the sequencer doesn't know" unless pair
|
|
216
|
+
|
|
217
|
+
PAIR_CODES + pair
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
include KeyedState
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
require "badline/chips/vic/keyed_sprites"
|
|
228
|
+
require "badline/chips/vic/keyed_state"
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class VIC
|
|
6
|
+
class Sprite
|
|
7
|
+
# A sprite's fields under `prefix`: its DMA and display, MC, MCBASE
|
|
8
|
+
# and the expansion flip-flop, the fetch in progress and the shift
|
|
9
|
+
# register, and the line batch under `line_prefix` when `line` is
|
|
10
|
+
# true.
|
|
11
|
+
module KeyedState
|
|
12
|
+
# The shift register, MC, MCBASE, the expansion flip-flop and whether
|
|
13
|
+
# the sprite shows, for a VICE snapshot.
|
|
14
|
+
attr_reader :sr, :mc, :mcbase, :exp_ff, :display_on
|
|
15
|
+
|
|
16
|
+
# Sets MC, MCBASE, the expansion flip-flop, whether the sprite's DMA
|
|
17
|
+
# runs and whether it shows, as a VICE snapshot gives them.
|
|
18
|
+
def restore_counters(counter, base, expanded, dma, shows)
|
|
19
|
+
@mc = counter
|
|
20
|
+
@mcbase = base
|
|
21
|
+
@exp_ff = expanded
|
|
22
|
+
@dma = dma
|
|
23
|
+
@display_on = shows
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def save_fields(out, prefix, line_prefix)
|
|
27
|
+
out.bool("#{prefix}dma", @dma).bool("#{prefix}display_on", @display_on).int("#{prefix}mcbase", @mcbase)
|
|
28
|
+
out.int("#{prefix}mc", @mc).bool("#{prefix}exp_ff", @exp_ff).optional_int("#{prefix}crunched_mc",
|
|
29
|
+
@crunched_mc)
|
|
30
|
+
out.int("#{prefix}bits", @bits).bool("#{prefix}row_ready", @row_ready)
|
|
31
|
+
out.optional_int("#{prefix}prev_bits", @prev_bits).bool("#{prefix}first_byte_lost", @first_byte_lost)
|
|
32
|
+
out.bool("#{prefix}blind", @blind).int("#{prefix}sr", @sr).int("#{prefix}latch", @latch)
|
|
33
|
+
out.bool("#{prefix}mc_flop", @mc_flop).bool("#{prefix}xe_flop", @xe_flop)
|
|
34
|
+
save_line_fields(out, line_prefix)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def load_fields(input, prefix, line_prefix, line)
|
|
38
|
+
@dma = input.bool("#{prefix}dma", @dma)
|
|
39
|
+
@display_on = input.bool("#{prefix}display_on", @display_on)
|
|
40
|
+
@mcbase = input.masked("#{prefix}mcbase", @mcbase, 0x3f)
|
|
41
|
+
@mc = input.masked("#{prefix}mc", @mc, 0x3f)
|
|
42
|
+
@exp_ff = input.bool("#{prefix}exp_ff", @exp_ff)
|
|
43
|
+
@crunched_mc = input.optional_int("#{prefix}crunched_mc")
|
|
44
|
+
@bits = input.int("#{prefix}bits", @bits)
|
|
45
|
+
@row_ready = input.bool("#{prefix}row_ready", @row_ready)
|
|
46
|
+
@prev_bits = input.optional_int("#{prefix}prev_bits")
|
|
47
|
+
@first_byte_lost = input.bool("#{prefix}first_byte_lost", @first_byte_lost)
|
|
48
|
+
@blind = input.bool("#{prefix}blind", @blind)
|
|
49
|
+
@sr = input.int("#{prefix}sr", @sr)
|
|
50
|
+
@latch = input.int("#{prefix}latch", @latch)
|
|
51
|
+
@mc_flop = input.bool("#{prefix}mc_flop", @mc_flop)
|
|
52
|
+
@xe_flop = input.bool("#{prefix}xe_flop", @xe_flop)
|
|
53
|
+
load_line_fields(input, line_prefix) if line
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def save_line_fields(out, prefix)
|
|
59
|
+
out.int("#{prefix}show_from", @show_from).optional_int("#{prefix}stop_x", @stop_x)
|
|
60
|
+
out.ints("#{prefix}codes", @codes).int("#{prefix}leftmost", @leftmost).int("#{prefix}span", @span)
|
|
61
|
+
out.ints("#{prefix}reload_codes", @reload_codes).int("#{prefix}reload_leftmost", @reload_leftmost)
|
|
62
|
+
out.int("#{prefix}reload_span", @reload_span)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def load_line_fields(input, prefix)
|
|
66
|
+
@show_from = input.int("#{prefix}show_from", @show_from)
|
|
67
|
+
@stop_x = input.optional_int("#{prefix}stop_x")
|
|
68
|
+
input.ints_into("#{prefix}codes", @codes)
|
|
69
|
+
@leftmost = input.int("#{prefix}leftmost", @leftmost)
|
|
70
|
+
@span = input.int("#{prefix}span", @span)
|
|
71
|
+
input.ints_into("#{prefix}reload_codes", @reload_codes)
|
|
72
|
+
@reload_leftmost = input.int("#{prefix}reload_leftmost", @reload_leftmost)
|
|
73
|
+
@reload_span = input.int("#{prefix}reload_span", @reload_span)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
include KeyedState
|
|
78
|
+
|
|
79
|
+
class InternalBus
|
|
80
|
+
# The sprites' internal bus, under `prefix`.
|
|
81
|
+
module KeyedState
|
|
82
|
+
def save_fields(out, prefix)
|
|
83
|
+
out.int("#{prefix}lines", @lines).int("#{prefix}ghost", @ghost).ints("#{prefix}value", @value)
|
|
84
|
+
out.ints("#{prefix}line", @line)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def load_fields(input, prefix)
|
|
88
|
+
@lines = input.int("#{prefix}lines", @lines)
|
|
89
|
+
@ghost = input.byte("#{prefix}ghost", @ghost)
|
|
90
|
+
input.ints_into("#{prefix}value", @value)
|
|
91
|
+
input.ints_into("#{prefix}line", @line)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
include KeyedState
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
class Collisions
|
|
100
|
+
# The read-clear timing at the beam, and the line's coverage under
|
|
101
|
+
# `line_prefix` when `line` is true.
|
|
102
|
+
module KeyedState
|
|
103
|
+
def save_fields(out, line_prefix)
|
|
104
|
+
out.int("collisions.cleared_sprite", @cleared_sprite).int("collisions.cleared_data", @cleared_data)
|
|
105
|
+
out.bytes("#{line_prefix}hits", @hits).int("#{line_prefix}folded", @folded)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def load_fields(input, line_prefix, line)
|
|
109
|
+
@cleared_sprite = input.int("collisions.cleared_sprite", @cleared_sprite)
|
|
110
|
+
@cleared_data = input.int("collisions.cleared_data", @cleared_data)
|
|
111
|
+
return unless line
|
|
112
|
+
|
|
113
|
+
input.bytes_into("#{line_prefix}hits", @hits)
|
|
114
|
+
@folded = input.int("#{line_prefix}folded", @folded)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
include KeyedState
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
class RegisterLog
|
|
122
|
+
# The line's sprite register writes, under `prefix`: the entries as
|
|
123
|
+
# pixel, register and value in turn, the seed with -1 for a register
|
|
124
|
+
# not logged, and the next pixel as -1 past the last entry.
|
|
125
|
+
module KeyedState
|
|
126
|
+
def save_fields(out, prefix)
|
|
127
|
+
out.ints("#{prefix}entries", @entries.flatten)
|
|
128
|
+
out.ints("#{prefix}seed", @seed.map { |value| value.nil? ? -1 : value })
|
|
129
|
+
out.ints("#{prefix}values", @values).int("#{prefix}cursor", @cursor)
|
|
130
|
+
out.int("#{prefix}next_x", @next_x.infinite? ? -1 : @next_x)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def load_fields(input, prefix)
|
|
134
|
+
@entries.replace(input.ints("#{prefix}entries", []).each_slice(3).to_a)
|
|
135
|
+
@seed.replace(input.ints("#{prefix}seed", []).map { |value| value.negative? ? nil : value })
|
|
136
|
+
input.ints_into("#{prefix}values", @values)
|
|
137
|
+
@cursor = input.int("#{prefix}cursor", @cursor)
|
|
138
|
+
next_x = input.int("#{prefix}next_x", 0)
|
|
139
|
+
@next_x = next_x.negative? ? Float::INFINITY : next_x
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
include KeyedState
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
class Sprites
|
|
147
|
+
# The sprites under sprite0. to sprite7., their bus under sbus.,
|
|
148
|
+
# the collisions, and the line batch under `line_prefix`: the
|
|
149
|
+
# window's colours and priorities, the span touched, the pixels
|
|
150
|
+
# carried into the next line, the register log. Whether any DMA
|
|
151
|
+
# runs comes from the sprites on load.
|
|
152
|
+
module KeyedState
|
|
153
|
+
# Whether any sprite's DMA runs, set after Sprite#restore_counters.
|
|
154
|
+
def update_any_dma
|
|
155
|
+
@any_dma = @sprites.any?(&:displaying?)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def save_fields(out, line_prefix)
|
|
159
|
+
@sprites.each do |sprite|
|
|
160
|
+
sprite.save_fields(out, "sprite#{sprite.index}.", "#{line_prefix}sprite#{sprite.index}.")
|
|
161
|
+
end
|
|
162
|
+
@bus.save_fields(out, "sbus.")
|
|
163
|
+
@collisions.save_fields(out, "#{line_prefix}collisions.")
|
|
164
|
+
out.bool("#{line_prefix}carried", @carried).int("#{line_prefix}lo", @lo).int("#{line_prefix}hi", @hi)
|
|
165
|
+
out.int("#{line_prefix}sequenced", @sequenced).bytes("#{line_prefix}win_color", @win_color)
|
|
166
|
+
out.ints("#{line_prefix}win_priority", @win_priority.map { |set| set ? 1 : 0 })
|
|
167
|
+
out.ints("#{line_prefix}palette", @palette).bool("#{line_prefix}stopped_dma", @stopped_dma)
|
|
168
|
+
save_carry_fields(out, "#{line_prefix}carry", @carry)
|
|
169
|
+
save_carry_fields(out, "#{line_prefix}carry_next", @carry_next)
|
|
170
|
+
@log.save_fields(out, "#{line_prefix}log.")
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def load_fields(input, line_prefix, line)
|
|
174
|
+
@sprites.each do |sprite|
|
|
175
|
+
sprite.load_fields(input, "sprite#{sprite.index}.", "#{line_prefix}sprite#{sprite.index}.", line)
|
|
176
|
+
end
|
|
177
|
+
@bus.load_fields(input, "sbus.")
|
|
178
|
+
@collisions.load_fields(input, "#{line_prefix}collisions.", line)
|
|
179
|
+
load_line_fields(input, line_prefix) if line
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def restored! = update_any_dma
|
|
183
|
+
|
|
184
|
+
private
|
|
185
|
+
|
|
186
|
+
def load_line_fields(input, prefix)
|
|
187
|
+
@carried = input.bool("#{prefix}carried", @carried)
|
|
188
|
+
@lo = input.int("#{prefix}lo", @lo)
|
|
189
|
+
@hi = input.int("#{prefix}hi", @hi)
|
|
190
|
+
@sequenced = input.int("#{prefix}sequenced", @sequenced)
|
|
191
|
+
input.bytes_into("#{prefix}win_color", @win_color)
|
|
192
|
+
priority = input.ints("#{prefix}win_priority", @win_priority.map { |set| set ? 1 : 0 })
|
|
193
|
+
@win_priority.each_index { |index| @win_priority[index] = priority.fetch(index, 0) == 1 }
|
|
194
|
+
input.ints_into("#{prefix}palette", @palette)
|
|
195
|
+
@stopped_dma = input.bool("#{prefix}stopped_dma", @stopped_dma)
|
|
196
|
+
load_carry_fields(input, "#{prefix}carry", @carry)
|
|
197
|
+
load_carry_fields(input, "#{prefix}carry_next", @carry_next)
|
|
198
|
+
@log.load_fields(input, "#{prefix}log.")
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Each sprite's carried pixels as x, colour and priority (0 or 1)
|
|
202
|
+
# in turn.
|
|
203
|
+
def save_carry_fields(out, prefix, carry)
|
|
204
|
+
carry.each_with_index do |pixels, index|
|
|
205
|
+
values = []
|
|
206
|
+
pixels.each_slice(3) { |x, color, priority| values.push(x, color, priority ? 1 : 0) }
|
|
207
|
+
out.ints("#{prefix}#{index}", values)
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def load_carry_fields(input, prefix, carry)
|
|
212
|
+
carry.each_with_index do |pixels, index|
|
|
213
|
+
pixels.clear
|
|
214
|
+
input.ints("#{prefix}#{index}", []).each_slice(3) do |x, color, priority|
|
|
215
|
+
pixels.push(x, color, priority == 1)
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
include KeyedState
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class VIC
|
|
6
|
+
# The shape of the line batch the renderer keeps (design note §9.2).
|
|
7
|
+
# A snapshot whose line.layout differs restarts the rest of its line
|
|
8
|
+
# with an empty pipeline.
|
|
9
|
+
LINE_LAYOUT = 1
|
|
10
|
+
|
|
11
|
+
# The VIC-II's fields in a keyed snapshot module (Snapshot::Keyed):
|
|
12
|
+
# the beam, the g-access ring oldest first under g.*, the light pen
|
|
13
|
+
# and raster latches, the video matrix line, the registers, the
|
|
14
|
+
# display state, the sequencer and the sprites, the line batch under
|
|
15
|
+
# line.* with line.layout, and the picture as display. The IRQ line,
|
|
16
|
+
# the sprites' BA columns, whether any sprite DMA runs and the
|
|
17
|
+
# display's copy of the lines are worked out on load.
|
|
18
|
+
module KeyedState
|
|
19
|
+
def save_fields(out)
|
|
20
|
+
out.int("column", @column).int("raster", @rasterline).int("fetch_d011", @fetch_d011)
|
|
21
|
+
save_ring_fields(out)
|
|
22
|
+
out.bool("lp_triggered", @lp_triggered).bool("lp_low", @lp_low).bool("raster_match", @raster_match)
|
|
23
|
+
out.int("bank_lines", @vic_bank.lines).bytes("character_buffer", @character_buffer)
|
|
24
|
+
out.bytes("color_buffer", @color_buffer)
|
|
25
|
+
out.int("output_line", @output_line).bool("test_wrap", @test_wrap) if @iie
|
|
26
|
+
@registers.save_fields(out)
|
|
27
|
+
@display_state.save_fields(out)
|
|
28
|
+
out.int("line.layout", LINE_LAYOUT)
|
|
29
|
+
@sequencer.save_fields(out, "line.")
|
|
30
|
+
@sprites.save_fields(out, "line.")
|
|
31
|
+
out.bytes("display", @lines.flatten)
|
|
32
|
+
out
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def load_fields(input)
|
|
36
|
+
@column = input.int("column", @column)
|
|
37
|
+
@rasterline = @output_line = input.int("raster", @rasterline)
|
|
38
|
+
@fetch_d011 = input.byte("fetch_d011", @fetch_d011)
|
|
39
|
+
load_ring_fields(input)
|
|
40
|
+
@lp_triggered = input.bool("lp_triggered", @lp_triggered)
|
|
41
|
+
@lp_low = input.bool("lp_low", @lp_low)
|
|
42
|
+
@raster_match = input.bool("raster_match", @raster_match)
|
|
43
|
+
@vic_bank.lines = input.int("bank_lines", @vic_bank.lines)
|
|
44
|
+
input.bytes_into("character_buffer", @character_buffer)
|
|
45
|
+
input.bytes_into("color_buffer", @color_buffer)
|
|
46
|
+
load_test_fields(input) if @iie
|
|
47
|
+
@registers.load_fields(input)
|
|
48
|
+
@display_state.load_fields(input)
|
|
49
|
+
line = input.int("line.layout", 0) == LINE_LAYOUT
|
|
50
|
+
input.adjust("line in progress from another renderer, restarted") unless line || input.missing?
|
|
51
|
+
@sequencer.load_fields(input, "line.", line)
|
|
52
|
+
@sprites.load_fields(input, "line.", line)
|
|
53
|
+
load_display_fields(input)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def restored!
|
|
57
|
+
@registers.restored!
|
|
58
|
+
@sprites.restored!
|
|
59
|
+
rebuild_sprite_ba
|
|
60
|
+
@dirty_lines.fill(true)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
# Oldest first, so the ring's base is the reader's own.
|
|
66
|
+
def save_ring_fields(out)
|
|
67
|
+
order = Array.new(4) { |age| (@g_tick + 1 + age) & 3 }
|
|
68
|
+
out.ints("g.kind", order.map { |slot| @g_kind[slot] }).ints("g.data", order.map { |slot| @g_data[slot] })
|
|
69
|
+
out.ints("g.char", order.map { |slot| @g_char[slot] }).ints("g.color", order.map { |slot| @g_color[slot] })
|
|
70
|
+
out.int("g.kept_char", @g_kept_char).int("g.kept_color", @g_kept_color).bool("g.display", @g_display)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def load_ring_fields(input)
|
|
74
|
+
@g_tick = 3
|
|
75
|
+
input.ints_into("g.kind", @g_kind)
|
|
76
|
+
input.ints_into("g.data", @g_data)
|
|
77
|
+
input.ints_into("g.char", @g_char)
|
|
78
|
+
input.ints_into("g.color", @g_color)
|
|
79
|
+
@g_kept_char = input.byte("g.kept_char", @g_kept_char)
|
|
80
|
+
@g_kept_color = input.masked("g.kept_color", @g_kept_color, 0x0f)
|
|
81
|
+
@g_display = input.bool("g.display", @g_display)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def load_test_fields(input)
|
|
85
|
+
@output_line = input.int("output_line", @output_line)
|
|
86
|
+
@test_wrap = input.bool("test_wrap", @test_wrap)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def load_display_fields(input)
|
|
90
|
+
display = @lines.flatten
|
|
91
|
+
input.bytes_into("display", display)
|
|
92
|
+
@lines.each_with_index do |line, number|
|
|
93
|
+
line.replace(display[number * @width, @width])
|
|
94
|
+
@display[number * @width, @width] = line
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
include KeyedState
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -20,24 +20,6 @@ module Badline
|
|
|
20
20
|
# The pixel at which the next logged write takes effect.
|
|
21
21
|
attr_reader :next_x
|
|
22
22
|
|
|
23
|
-
# The entries as pixel, register and value in turn, the seed with -1
|
|
24
|
-
# for a register the line hasn't logged, and a next pixel past the
|
|
25
|
-
# last entry as -1.
|
|
26
|
-
def save_state(out)
|
|
27
|
-
out.ints(@entries.flatten)
|
|
28
|
-
out.ints(@seed.map { |value| value.nil? ? -1 : value })
|
|
29
|
-
out.ints(@values).int(@cursor).int(@next_x.infinite? ? -1 : @next_x)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def load_state(input)
|
|
33
|
-
@entries.replace(input.ints.each_slice(3).to_a)
|
|
34
|
-
@seed.replace(input.ints.map { |value| value.negative? ? nil : value })
|
|
35
|
-
input.ints_into(@values)
|
|
36
|
-
@cursor = input.int
|
|
37
|
-
next_x = input.int
|
|
38
|
-
@next_x = next_x.negative? ? Float::INFINITY : next_x
|
|
39
|
-
end
|
|
40
|
-
|
|
41
23
|
def empty? = @entries.empty?
|
|
42
24
|
def length = @entries.length
|
|
43
25
|
|
|
@@ -163,15 +163,6 @@ module Badline
|
|
|
163
163
|
|
|
164
164
|
def latch_raster_irq! = latch_irq!(0x01)
|
|
165
165
|
|
|
166
|
-
def save_state(out)
|
|
167
|
-
out.blob(@bytes).boolean(@irq_line)
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
def load_state(input)
|
|
171
|
-
input.blob_into(@bytes)
|
|
172
|
-
@irq_line = input.boolean?
|
|
173
|
-
end
|
|
174
|
-
|
|
175
166
|
def collide!(reg, bits)
|
|
176
167
|
return false if bits.zero?
|
|
177
168
|
|
|
@@ -5,7 +5,6 @@ require "badline/chips/vic/color_patches"
|
|
|
5
5
|
require "badline/chips/vic/graphics_mode"
|
|
6
6
|
require "badline/chips/vic/graphics_shifter"
|
|
7
7
|
require "badline/chips/vic/sequencer_output"
|
|
8
|
-
require "badline/chips/vic/sequencer/saved_state"
|
|
9
8
|
|
|
10
9
|
module Badline
|
|
11
10
|
module Chips
|
|
@@ -15,7 +14,6 @@ module Badline
|
|
|
15
14
|
# Turns fetched graphics data into output pixels.
|
|
16
15
|
class Sequencer
|
|
17
16
|
include Output
|
|
18
|
-
include SavedState
|
|
19
17
|
|
|
20
18
|
BORDER_Y_BOUNDS = [
|
|
21
19
|
[55, 247].freeze,
|
|
@@ -26,17 +26,6 @@ module Badline
|
|
|
26
26
|
@line = Array.new(columns, -1)
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
def save_state(out)
|
|
30
|
-
out.int(@lines).int(@ghost).ints(@value).ints(@line)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def load_state(input)
|
|
34
|
-
@lines = input.int
|
|
35
|
-
@ghost = input.int
|
|
36
|
-
input.ints_into(@value)
|
|
37
|
-
input.ints_into(@line)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
29
|
# Sprites 3-7 fetch in Bauer cycles 1-10, so the idle byte is taken
|
|
41
30
|
# as the line starts.
|
|
42
31
|
def start_line(sprites_enabled)
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require "badline/chips/vic/sprite/internal_bus"
|
|
4
4
|
require "badline/chips/vic/sprite/shifter"
|
|
5
|
-
require "badline/chips/vic/sprite/saved_state"
|
|
6
5
|
require "badline/chips/vic/sprite/timing"
|
|
7
6
|
|
|
8
7
|
module Badline
|
|
@@ -54,7 +53,6 @@ module Badline
|
|
|
54
53
|
DISPLAY_OFF_X = 460
|
|
55
54
|
|
|
56
55
|
include Shifter
|
|
57
|
-
include SavedState
|
|
58
56
|
|
|
59
57
|
attr_reader :index, :leftmost, :span, :codes,
|
|
60
58
|
:reload_leftmost, :reload_span, :reload_codes
|
|
@@ -3,14 +3,11 @@
|
|
|
3
3
|
require "badline/chips/vic/collisions"
|
|
4
4
|
require "badline/chips/vic/register_log"
|
|
5
5
|
require "badline/chips/vic/sprite"
|
|
6
|
-
require "badline/chips/vic/sprites/saved_state"
|
|
7
6
|
|
|
8
7
|
module Badline
|
|
9
8
|
module Chips
|
|
10
9
|
class VIC
|
|
11
10
|
class Sprites
|
|
12
|
-
include SavedState
|
|
13
|
-
|
|
14
11
|
# Pixels between the start of the cycle following a write and the
|
|
15
12
|
# point the new value shows. Each signal reaches the output on its own
|
|
16
13
|
# path: the colors feed the final mux, the sequencer inputs — X
|