badline 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +49 -1
- data/CLAUDE.md +27 -7
- data/CONTRIBUTING.md +4 -3
- data/README.md +8 -5
- data/doc/media.md +2 -1
- data/doc/pinned-behaviour.md +29 -0
- data/doc/snapshot-format.md +1047 -0
- data/doc/snapshots.md +72 -39
- data/lib/badline/audio/bare_player.rb +50 -17
- data/lib/badline/audio/machine_player.rb +15 -9
- data/lib/badline/audio/renderer.rb +32 -21
- data/lib/badline/c128/banks.rb +6 -3
- data/lib/badline/c128/bus/keyed_state.rb +45 -0
- data/lib/badline/c128/bus.rb +17 -3
- 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 +20 -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/keyed_state.rb +41 -0
- data/lib/badline/c64/bus.rb +2 -1
- data/lib/badline/c64/cartridge/action_replay.rb +0 -13
- 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 +0 -12
- data/lib/badline/c64/cartridge/flash.rb +3 -3
- data/lib/badline/c64/cartridge/g_mod2.rb +0 -12
- 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 +393 -0
- data/lib/badline/c64/cartridge/pagefox.rb +0 -10
- data/lib/badline/c64/cartridge/retro_replay.rb +0 -8
- data/lib/badline/c64/cartridge/rgcd.rb +0 -10
- data/lib/badline/c64/cartridge/super_games.rb +0 -10
- data/lib/badline/c64/cartridge/zaxxon.rb +0 -16
- data/lib/badline/c64/cartridge.rb +1 -27
- data/lib/badline/c64/kernal_traps.rb +28 -25
- data/lib/badline/c64/keyed_modules.rb +111 -0
- data/lib/badline/c64/keyed_state.rb +68 -0
- data/lib/badline/c64/reu/dma.rb +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 +119 -0
- data/lib/badline/chips/ted/timers.rb +66 -0
- data/lib/badline/chips/ted.rb +143 -0
- data/lib/badline/chips/tia.rb +49 -0
- data/lib/badline/chips/vdc/keyed_parts.rb +105 -0
- data/lib/badline/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 +38 -0
- data/lib/badline/drives/datasette.rb +40 -7
- 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 +1 -1
- data/lib/badline/frontend/controls.rb +19 -3
- data/lib/badline/frontend/drive_led.rb +44 -21
- data/lib/badline/frontend/menu/menu_dialogs.rb +2 -2
- data/lib/badline/frontend/snapshots.rb +12 -1
- data/lib/badline/frontend/timeline.rb +28 -10
- 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 +5 -2
- data/lib/badline/media/boot_disk.rb +14 -2
- data/lib/badline/media/extensions.rb +10 -0
- data/lib/badline/memory.rb +3 -6
- data/lib/badline/options/family.rb +5 -2
- data/lib/badline/options/help.rb +42 -16
- data/lib/badline/options/table.rb +2 -0
- data/lib/badline/options/validation.rb +2 -0
- data/lib/badline/options.rb +6 -1
- data/lib/badline/plus4/acia.rb +45 -0
- data/lib/badline/plus4/bus.rb +312 -0
- data/lib/badline/plus4/cpu.rb +10 -0
- data/lib/badline/plus4/cpu_port.rb +93 -0
- data/lib/badline/plus4/keyboard_port.rb +51 -0
- data/lib/badline/plus4/model.rb +38 -0
- data/lib/badline/plus4/user_port.rb +31 -0
- data/lib/badline/plus4.rb +164 -0
- data/lib/badline/roms/README +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 +4 -0
- data/lib/badline/snapshot/field_doc/markdown.rb +112 -0
- data/lib/badline/snapshot/field_doc.rb +109 -0
- data/lib/badline/snapshot/image.rb +134 -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/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 +43 -20
- data/lib/badline/storage/crt_file.rb +3 -1
- data/lib/badline/storage/g64_image.rb +8 -3
- data/lib/badline/storage/tap.rb +43 -15
- 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 +61 -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
|
@@ -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
|
data/lib/badline/chips/vic.rb
CHANGED
|
@@ -5,14 +5,13 @@ require "badline/chips/vic/registers"
|
|
|
5
5
|
require "badline/chips/vic/display_state"
|
|
6
6
|
require "badline/chips/vic/sequencer"
|
|
7
7
|
require "badline/chips/vic/sprites"
|
|
8
|
-
require "badline/chips/vic/
|
|
8
|
+
require "badline/chips/vic/keyed_parts"
|
|
9
9
|
|
|
10
10
|
module Badline
|
|
11
11
|
module Chips
|
|
12
12
|
class VIC
|
|
13
13
|
include Addressable
|
|
14
14
|
include IntegerHelper
|
|
15
|
-
include SavedState
|
|
16
15
|
|
|
17
16
|
# The 6569 of the breadbin C64, the HMOS 8565 of the C64C, and the
|
|
18
17
|
# C128's VIC-IIe, the 8566 (PAL) and 8564 (NTSC). The VIC-IIe draws as
|
|
@@ -229,6 +228,11 @@ module Badline
|
|
|
229
228
|
@sequencer.start_vertical_border(@rasterline == @last_line ? 0 : @rasterline + 1) if hooks.anybits?(HOOK_LAST)
|
|
230
229
|
end
|
|
231
230
|
|
|
231
|
+
# Latches the sprite collisions up to the beam, as a read of $D01E or
|
|
232
|
+
# $D01F would, so the registers stand as the hardware has them when a
|
|
233
|
+
# snapshot is saved.
|
|
234
|
+
def fold_collisions! = @sprites.collide_upto(@column * 8, @sequencer.fg)
|
|
235
|
+
|
|
232
236
|
# The IRQ line is held asserted while any enabled latch bit is set in
|
|
233
237
|
# $D019/$D01A, until the program acknowledges it by writing to $D019.
|
|
234
238
|
def interrupted?
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class VICI
|
|
6
|
+
class Sound
|
|
7
|
+
# The sound's fields in a keyed snapshot module, under `prefix`:
|
|
8
|
+
# the voices' shift registers, the noise LFSR, the level, and when
|
|
9
|
+
# each voice next shifts, in cycles from the machine's clock, with
|
|
10
|
+
# how far behind the clock the voices last ran. The volume and the
|
|
11
|
+
# voices' frequencies come from the VIC's registers on load.
|
|
12
|
+
module KeyedState
|
|
13
|
+
def save_fields(out, prefix)
|
|
14
|
+
now = @clock.cycles
|
|
15
|
+
run_to(now)
|
|
16
|
+
out.ints("#{prefix}shift_registers", @shift_registers).int("#{prefix}lfsr", @lfsr)
|
|
17
|
+
out.int("#{prefix}level", @level).int("#{prefix}ran_ago", now - @time)
|
|
18
|
+
out.ints("#{prefix}next_shifts", @next_shifts.map { |due| due - now })
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def load_fields(input, prefix)
|
|
22
|
+
now = @clock.cycles
|
|
23
|
+
input.ints_into("#{prefix}shift_registers", @shift_registers)
|
|
24
|
+
@lfsr = input.masked("#{prefix}lfsr", @lfsr, 0xffff)
|
|
25
|
+
@level = input.int("#{prefix}level", @level)
|
|
26
|
+
@time = now - input.int("#{prefix}ran_ago", now - @time)
|
|
27
|
+
relative = input.ints("#{prefix}next_shifts", @next_shifts.map { |due| due - now })
|
|
28
|
+
VOICES.times { |voice| @next_shifts[voice] = now + relative.fetch(voice, 0) }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# $900A to $900E as written.
|
|
32
|
+
def restore_registers(registers)
|
|
33
|
+
@volume = registers[0x0e] & 0x0f
|
|
34
|
+
VOICES.times do |voice|
|
|
35
|
+
value = registers[0x0a + voice]
|
|
36
|
+
@frequencies[voice] = value & 0x7f
|
|
37
|
+
@enabled[voice] = value >= 0x80
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
include KeyedState
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class Painter
|
|
46
|
+
# The lines' fetches and the line going out, as this painter lays
|
|
47
|
+
# them out (VICI::LINE_LAYOUT), and the picture.
|
|
48
|
+
module KeyedState
|
|
49
|
+
def save_fields(out)
|
|
50
|
+
out.int("line.row", @row).int("line.painted", @painted).bool("line.written", @written)
|
|
51
|
+
out.bytes("line.patterns", @patterns).bytes("line.colors", @colors)
|
|
52
|
+
out.ints("line.counts", @counts).ints("line.starts", @starts).bytes("display", @display)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def load_fields(input, layout)
|
|
56
|
+
input.bytes_into("display", @display)
|
|
57
|
+
return unless layout
|
|
58
|
+
|
|
59
|
+
@row = input.int("line.row", @row)
|
|
60
|
+
@painted = input.int("line.painted", @painted)
|
|
61
|
+
@written = input.bool("line.written", @written)
|
|
62
|
+
input.bytes_into("line.patterns", @patterns)
|
|
63
|
+
input.bytes_into("line.colors", @colors)
|
|
64
|
+
input.ints_into("line.counts", @counts)
|
|
65
|
+
input.ints_into("line.starts", @starts)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# The colours as $900E and $900F hold them, every line to be
|
|
69
|
+
# painted afresh, and the whole display changed.
|
|
70
|
+
def restored!(registers)
|
|
71
|
+
@border = registers[0x0f] & 0x07
|
|
72
|
+
@background = registers[0x0f] >> 4
|
|
73
|
+
@reverse = registers[0x0f].nobits?(0x08)
|
|
74
|
+
@aux = registers[0x0e] >> 4
|
|
75
|
+
@stale.fill(true)
|
|
76
|
+
@memo_keys.fill(-1)
|
|
77
|
+
@dirty_lines.fill(true)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
include KeyedState
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# The shape of the painter's per-line fields. A snapshot whose
|
|
85
|
+
# line.layout differs leaves them at power-on.
|
|
86
|
+
LINE_LAYOUT = 1
|
|
87
|
+
|
|
88
|
+
# The VIC-I's fields in a keyed snapshot module (Snapshot::Keyed): the
|
|
89
|
+
# registers, the beam, the text window's counters and the fetch in
|
|
90
|
+
# flight, the painter's lines under line.*, the picture, and the sound
|
|
91
|
+
# under sound.* What the registers decode to, where the line's fetches
|
|
92
|
+
# end and the next event are worked out on load.
|
|
93
|
+
module KeyedState
|
|
94
|
+
def save_fields(out)
|
|
95
|
+
out.bytes("registers", @registers).int("raster", @rasterline).int("column", @column)
|
|
96
|
+
out.bool("window_open", @window_open).bool("window_done", @window_done).int("row_start", @row_start)
|
|
97
|
+
out.int("matrix", @matrix).int("char_line", @char_line).int("text_rows", @text_rows)
|
|
98
|
+
out.int("fetch_from", @fetch_from).int("fetched", @fetched).int("code", @code)
|
|
99
|
+
out.int("line.layout", LINE_LAYOUT)
|
|
100
|
+
@painter.save_fields(out)
|
|
101
|
+
@sound&.save_fields(out, "sound.")
|
|
102
|
+
out
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def load_fields(input)
|
|
106
|
+
input.bytes_into("registers", @registers)
|
|
107
|
+
@rasterline = input.int("raster", @rasterline)
|
|
108
|
+
@column = input.int("column", @column)
|
|
109
|
+
@window_open = input.bool("window_open", @window_open)
|
|
110
|
+
@window_done = input.bool("window_done", @window_done)
|
|
111
|
+
@row_start = input.int("row_start", @row_start)
|
|
112
|
+
@matrix = input.int("matrix", @matrix)
|
|
113
|
+
@char_line = input.int("char_line", @char_line)
|
|
114
|
+
@text_rows = input.int("text_rows", @text_rows)
|
|
115
|
+
@fetch_from = input.int("fetch_from", @fetch_from)
|
|
116
|
+
@fetched = input.int("fetched", @fetched)
|
|
117
|
+
@code = input.byte("code", @code)
|
|
118
|
+
line = input.int("line.layout", 0) == LINE_LAYOUT
|
|
119
|
+
input.adjust("line in progress from another renderer, restarted") unless line || input.missing?
|
|
120
|
+
@painter.load_fields(input, line)
|
|
121
|
+
@sound&.load_fields(input, "sound.")
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def restored!
|
|
125
|
+
@origin_x = @registers[0] & 0x7f
|
|
126
|
+
@columns = @registers[2] & 0x7f
|
|
127
|
+
@origin_y = @registers[1]
|
|
128
|
+
rows_written(@registers[3])
|
|
129
|
+
bases_written
|
|
130
|
+
@slot = @rasterline * Painter::SLOTS
|
|
131
|
+
@fetch_to = 0
|
|
132
|
+
fetches_end if @window_open
|
|
133
|
+
schedule
|
|
134
|
+
@painter.restored!(@registers)
|
|
135
|
+
@sound&.restore_registers(@registers)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
include KeyedState
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "badline/chips/vic_i/painter/saved_state"
|
|
4
|
-
|
|
5
3
|
module Badline
|
|
6
4
|
module Chips
|
|
7
5
|
class VICI
|
|
@@ -28,8 +26,6 @@ module Badline
|
|
|
28
26
|
# nibble's low three bits) and 11 the auxiliary colour, whatever
|
|
29
27
|
# $900F bit 3 says (MOS 6560/6561 datasheet, "Color operating modes").
|
|
30
28
|
class Painter
|
|
31
|
-
include SavedState
|
|
32
|
-
|
|
33
29
|
# The characters a line holds room for. A line fetches at most 34.
|
|
34
30
|
SLOTS = 40
|
|
35
31
|
|
|
@@ -30,10 +30,11 @@ module Badline
|
|
|
30
30
|
# The output is the voices that are high, plus a little more, times the
|
|
31
31
|
# volume, so a volume write steps the output even with every voice off.
|
|
32
32
|
#
|
|
33
|
-
# The voices
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
33
|
+
# The voices catch up to the current cycle whenever a write lands, the
|
|
34
|
+
# samples are drained or #catch_up! asks, one shift at a time, whether
|
|
35
|
+
# or not #record collects the output, so their state doesn't depend on
|
|
36
|
+
# whether the host plays it. Unrecorded, while every voice is off and
|
|
37
|
+
# shifted out to silence, they skip to the cycle at once.
|
|
37
38
|
class Sound
|
|
38
39
|
VOICES = 4
|
|
39
40
|
NOISE = 3
|
|
@@ -86,14 +87,15 @@ module Badline
|
|
|
86
87
|
# second, for #drain_samples. `clock_hz` is the rate the cycles are
|
|
87
88
|
# taken to run at.
|
|
88
89
|
def record(rate:, clock_hz: @clock_hz)
|
|
89
|
-
|
|
90
|
-
run_to(now)
|
|
91
|
-
resume(now)
|
|
90
|
+
run_to(@clock.cycles)
|
|
92
91
|
@output = Output.new(clock_hz:, rate:, level: @level)
|
|
93
92
|
end
|
|
94
93
|
|
|
95
94
|
def recording? = !@output.nil?
|
|
96
95
|
|
|
96
|
+
# Runs the voices up to the current cycle.
|
|
97
|
+
def catch_up! = run_to(@clock.cycles)
|
|
98
|
+
|
|
97
99
|
# The samples recorded since the last drain.
|
|
98
100
|
def drain_samples
|
|
99
101
|
output = @output
|
|
@@ -116,29 +118,7 @@ module Badline
|
|
|
116
118
|
@level = level_now
|
|
117
119
|
end
|
|
118
120
|
|
|
119
|
-
#
|
|
120
|
-
# Recording is the host's, and starts the voices again from the
|
|
121
|
-
# cycle it starts at.
|
|
122
|
-
def save_state(out)
|
|
123
|
-
run_to(@clock.cycles)
|
|
124
|
-
out.marker("VIC20 SOUND").int(@volume).ints(@frequencies).booleans(@enabled)
|
|
125
|
-
out.ints(@shift_registers).ints(@next_shifts).int(@lfsr).int(@level).int(@time)
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
def load_state(input)
|
|
129
|
-
input.marker("VIC20 SOUND")
|
|
130
|
-
@volume = input.int
|
|
131
|
-
input.ints_into(@frequencies)
|
|
132
|
-
input.booleans_into(@enabled)
|
|
133
|
-
input.ints_into(@shift_registers)
|
|
134
|
-
input.ints_into(@next_shifts)
|
|
135
|
-
@lfsr = input.int
|
|
136
|
-
@level = input.int
|
|
137
|
-
@time = input.int
|
|
138
|
-
resume(@clock.cycles) if recording?
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
# A voice's shift register as of the current cycle, while recording.
|
|
121
|
+
# A voice's shift register as of the current cycle.
|
|
142
122
|
def shift_register(voice)
|
|
143
123
|
run_to(@clock.cycles)
|
|
144
124
|
@shift_registers[voice]
|
|
@@ -151,35 +131,47 @@ module Badline
|
|
|
151
131
|
|
|
152
132
|
private
|
|
153
133
|
|
|
154
|
-
# Moves each shift that the cycles since the voices last ran have
|
|
155
|
-
# passed to its next turn from `now`, keeping its phase.
|
|
156
|
-
def resume(now)
|
|
157
|
-
@time = now
|
|
158
|
-
VOICES.times do |voice|
|
|
159
|
-
due = @next_shifts[voice]
|
|
160
|
-
next if due >= now
|
|
161
|
-
|
|
162
|
-
interval = period(voice) * DIVIDERS[voice]
|
|
163
|
-
@next_shifts[voice] = due + ((now - due + interval - 1) / interval * interval)
|
|
164
|
-
end
|
|
165
|
-
end
|
|
166
|
-
|
|
167
134
|
# Runs the voices up to the start of cycle `target`, the output holding
|
|
168
135
|
# each level for the cycles it lasts.
|
|
169
136
|
def run_to(target)
|
|
170
137
|
time = @time
|
|
138
|
+
return if target <= time
|
|
139
|
+
|
|
171
140
|
output = @output
|
|
172
|
-
return if output.nil?
|
|
141
|
+
return skip_to(target) if output.nil? && silent?
|
|
173
142
|
|
|
174
143
|
following = next_shift
|
|
175
144
|
while following < target
|
|
176
|
-
output
|
|
145
|
+
output&.hold(@level, following - time)
|
|
177
146
|
time = following
|
|
178
147
|
shift_due(time)
|
|
179
148
|
@level = level_now
|
|
180
149
|
following = next_shift
|
|
181
150
|
end
|
|
182
|
-
output
|
|
151
|
+
output&.hold(@level, target - time)
|
|
152
|
+
@time = target
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Whether every voice is off and shifted out to where its shifts
|
|
156
|
+
# change nothing: the tone voices' registers empty and the noise
|
|
157
|
+
# voice's LFSR full of ones.
|
|
158
|
+
def silent?
|
|
159
|
+
enabled = @enabled
|
|
160
|
+
registers = @shift_registers
|
|
161
|
+
!(enabled[0] || enabled[1] || enabled[2] || enabled[NOISE]) &&
|
|
162
|
+
registers[0].zero? && registers[1].zero? && registers[2].zero? && @lfsr == 0xffff
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Moves each shift before `target` to its next turn from there,
|
|
166
|
+
# keeping its phase.
|
|
167
|
+
def skip_to(target)
|
|
168
|
+
VOICES.times do |voice|
|
|
169
|
+
due = @next_shifts[voice]
|
|
170
|
+
next if due >= target
|
|
171
|
+
|
|
172
|
+
interval = period(voice) * DIVIDERS[voice]
|
|
173
|
+
@next_shifts[voice] = due + ((target - due + interval - 1) / interval * interval)
|
|
174
|
+
end
|
|
183
175
|
@time = target
|
|
184
176
|
end
|
|
185
177
|
|
data/lib/badline/chips/vic_i.rb
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require "badline/chips/vic_i/painter"
|
|
4
4
|
require "badline/chips/vic_i/text_window"
|
|
5
|
-
require "badline/chips/vic_i/
|
|
5
|
+
require "badline/chips/vic_i/sound"
|
|
6
|
+
require "badline/chips/vic_i/keyed_parts"
|
|
6
7
|
|
|
7
8
|
module Badline
|
|
8
9
|
module Chips
|
|
@@ -41,7 +42,6 @@ module Badline
|
|
|
41
42
|
# into the line lands 48 pixels in. Lines 0-27 are blanked.
|
|
42
43
|
class VICI
|
|
43
44
|
include TextWindow
|
|
44
|
-
include SavedState
|
|
45
45
|
|
|
46
46
|
# What a VIC-I sets for the machine: the clock, the raster's cycles
|
|
47
47
|
# per line and lines per frame, and how many lines at the top of the
|
|
@@ -14,7 +14,7 @@ require "badline/chips/z80/extended_page"
|
|
|
14
14
|
require "badline/chips/z80/block_transfers"
|
|
15
15
|
require "badline/chips/z80/block_io"
|
|
16
16
|
require "badline/chips/z80/interrupt_acceptance"
|
|
17
|
-
require "badline/chips/z80/
|
|
17
|
+
require "badline/chips/z80/keyed_state"
|
|
18
18
|
|
|
19
19
|
module Badline
|
|
20
20
|
module Chips
|
|
@@ -44,7 +44,7 @@ module Badline
|
|
|
44
44
|
include BlockTransfers
|
|
45
45
|
include BlockIO
|
|
46
46
|
include InterruptAcceptance
|
|
47
|
-
include
|
|
47
|
+
include KeyedState
|
|
48
48
|
|
|
49
49
|
attr_reader :bus, :cycles, :nmi
|
|
50
50
|
attr_accessor :int
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Chips
|
|
5
|
+
class Z80
|
|
6
|
+
# The Z80's fields in a keyed snapshot module (Snapshot::Keyed),
|
|
7
|
+
# between instructions, where it always is after the C128's cycle:
|
|
8
|
+
# the registers, the T-state count and the interrupt latches.
|
|
9
|
+
module KeyedState
|
|
10
|
+
def save_fields(out)
|
|
11
|
+
out.int("a", @a).int("f", @f).int("b", @b).int("c", @c).int("d", @d).int("e", @e).int("h", @h).int("l", @l)
|
|
12
|
+
out.int("af_alt", @af_alt).int("bc_alt", @bc_alt).int("de_alt", @de_alt).int("hl_alt", @hl_alt)
|
|
13
|
+
out.int("i", @i).int("r", @r).int("pc", @pc).int("sp", @sp).int("ix", @ix).int("iy", @iy).int("wz", @wz)
|
|
14
|
+
out.int("q", @q).int("last_q", @last_q).int("im", @im).int("cycles", @cycles)
|
|
15
|
+
out.bool("iff1", @iff1).bool("iff2", @iff2).bool("halted", @halted).bool("after_ei", @after_ei)
|
|
16
|
+
out.bool("after_ld_a_ir", @after_ld_a_ir).bool("int", @int).bool("nmi", @nmi)
|
|
17
|
+
out.bool("nmi_pending", @nmi_pending)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def load_fields(input)
|
|
21
|
+
load_main_fields(input)
|
|
22
|
+
load_special_fields(input)
|
|
23
|
+
@cycles = input.int("cycles", @cycles)
|
|
24
|
+
load_latch_fields(input)
|
|
25
|
+
@prefix = 0
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def restored! = nil
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def load_main_fields(input)
|
|
33
|
+
@a = input.byte("a", @a)
|
|
34
|
+
@f = input.byte("f", @f)
|
|
35
|
+
@b = input.byte("b", @b)
|
|
36
|
+
@c = input.byte("c", @c)
|
|
37
|
+
@d = input.byte("d", @d)
|
|
38
|
+
@e = input.byte("e", @e)
|
|
39
|
+
@h = input.byte("h", @h)
|
|
40
|
+
@l = input.byte("l", @l)
|
|
41
|
+
@af_alt = input.word("af_alt", @af_alt)
|
|
42
|
+
@bc_alt = input.word("bc_alt", @bc_alt)
|
|
43
|
+
@de_alt = input.word("de_alt", @de_alt)
|
|
44
|
+
@hl_alt = input.word("hl_alt", @hl_alt)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def load_special_fields(input)
|
|
48
|
+
@i = input.byte("i", @i)
|
|
49
|
+
@r = input.byte("r", @r)
|
|
50
|
+
@pc = input.word("pc", @pc)
|
|
51
|
+
@sp = input.word("sp", @sp)
|
|
52
|
+
@ix = input.word("ix", @ix)
|
|
53
|
+
@iy = input.word("iy", @iy)
|
|
54
|
+
@wz = input.word("wz", @wz)
|
|
55
|
+
@q = input.byte("q", @q)
|
|
56
|
+
@last_q = input.byte("last_q", @last_q)
|
|
57
|
+
@im = input.int("im", @im)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def load_latch_fields(input)
|
|
61
|
+
@iff1 = input.bool("iff1", @iff1)
|
|
62
|
+
@iff2 = input.bool("iff2", @iff2)
|
|
63
|
+
@halted = input.bool("halted", @halted)
|
|
64
|
+
@after_ei = input.bool("after_ei", @after_ei)
|
|
65
|
+
@after_ld_a_ir = input.bool("after_ld_a_ir", @after_ld_a_ir)
|
|
66
|
+
@int = input.bool("int", @int)
|
|
67
|
+
@nmi = input.bool("nmi", @nmi)
|
|
68
|
+
@nmi_pending = input.bool("nmi_pending", @nmi_pending)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# The chips badline/core's machines share. The C128's own, the Z80 and the
|
|
4
|
+
# VDC, stay out of the core: badline/c128 requires them.
|
|
5
|
+
require "badline/chips/cpu"
|
|
6
|
+
require "badline/chips/cia"
|
|
7
|
+
require "badline/chips/via"
|
|
8
|
+
require "badline/chips/sid"
|
|
9
|
+
require "badline/chips/vic"
|
|
10
|
+
require "badline/chips/vic_i"
|
data/lib/badline/core.rb
CHANGED
|
@@ -15,29 +15,13 @@ require "badline/memory"
|
|
|
15
15
|
require "badline/c64/color_memory"
|
|
16
16
|
require "badline/rom"
|
|
17
17
|
require "badline/c64/banked_ram"
|
|
18
|
-
require "badline/chips/cpu/port"
|
|
19
|
-
require "badline/c64/bus"
|
|
20
|
-
require "badline/chips/cpu/instruction"
|
|
21
|
-
require "badline/chips/cpu/instruction_set"
|
|
22
18
|
require "badline/status"
|
|
23
19
|
require "badline/input"
|
|
24
|
-
require "badline/
|
|
25
|
-
require "badline/
|
|
26
|
-
require "badline/
|
|
27
|
-
require "badline/chips/via"
|
|
28
|
-
require "badline/chips/sid"
|
|
29
|
-
require "badline/debug_register"
|
|
20
|
+
require "badline/chips"
|
|
21
|
+
require "badline/drives"
|
|
22
|
+
require "badline/c64/bus"
|
|
30
23
|
require "badline/c64/reu"
|
|
31
|
-
require "badline/
|
|
32
|
-
require "badline/chips/cpu/traps"
|
|
33
|
-
require "badline/chips/cpu"
|
|
34
|
-
require "badline/chips/vic"
|
|
35
|
-
require "badline/keyboard_buffer"
|
|
36
|
-
require "badline/drives/serial_bus"
|
|
37
|
-
require "badline/drives/model1541"
|
|
38
|
-
require "badline/drives/model1581"
|
|
39
|
-
require "badline/drives/model1581/slot"
|
|
40
|
-
require "badline/snapshot/state"
|
|
24
|
+
require "badline/snapshot/keyed"
|
|
41
25
|
require "badline/snapshot/c64_setup"
|
|
42
26
|
require "badline/snapshot/storage_setup"
|
|
43
27
|
require "badline/machine"
|
|
@@ -47,5 +31,4 @@ require "badline/storage"
|
|
|
47
31
|
require "badline/sid_tune"
|
|
48
32
|
require "badline/c64/cartridge"
|
|
49
33
|
require "badline/kernal_trap"
|
|
50
|
-
require "badline/chrout_trap"
|
|
51
34
|
require "badline/media"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Drives
|
|
5
|
+
class Datasette
|
|
6
|
+
# The datasette's fields in a keyed snapshot module (Snapshot::Keyed,
|
|
7
|
+
# BL-TAPE): the keys, the motor, the countdown to the next pulse, and
|
|
8
|
+
# a tape in it under tape.*: its path, its bytes and how far it has
|
|
9
|
+
# played. A tape that isn't in leaves tape.* out. The sense and flag
|
|
10
|
+
# handlers don't fire on load.
|
|
11
|
+
module KeyedState
|
|
12
|
+
def save_fields(out)
|
|
13
|
+
out.bool("playing", @playing).bool("motor", @motor).int("countdown", @countdown)
|
|
14
|
+
tape = @tape
|
|
15
|
+
return out unless tape
|
|
16
|
+
|
|
17
|
+
out.text("tape.path", tape.path.to_s).bytes("tape.bytes", tape.bytes).int("tape.position", tape.position)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# The tape goes back in from the bytes the module holds, without its
|
|
21
|
+
# host file, unless the tape in is the same one.
|
|
22
|
+
def load_fields(input)
|
|
23
|
+
@playing = input.bool("playing", @playing)
|
|
24
|
+
@motor = input.bool("motor", @motor)
|
|
25
|
+
@countdown = input.int("countdown", @countdown)
|
|
26
|
+
bytes = input.bytes("tape.bytes", "".b).bytes
|
|
27
|
+
return @tape = nil if bytes.empty?
|
|
28
|
+
|
|
29
|
+
path = input.text("tape.path", "")
|
|
30
|
+
@tape = Storage::TAP.new(path, bytes:) unless @tape&.path.to_s == path && @tape&.bytes == bytes
|
|
31
|
+
@tape&.position = input.int("tape.position", 0)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
include KeyedState
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|