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
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "badline/chips/ted"
|
|
4
|
+
require "badline/chips/tia"
|
|
5
|
+
require "badline/plus4/model"
|
|
6
|
+
require "badline/plus4/cpu"
|
|
7
|
+
require "badline/plus4/cpu_port"
|
|
8
|
+
require "badline/plus4/keyboard_port"
|
|
9
|
+
require "badline/plus4/user_port"
|
|
10
|
+
require "badline/plus4/acia"
|
|
11
|
+
require "badline/plus4/bus"
|
|
12
|
+
|
|
13
|
+
module Badline
|
|
14
|
+
# The Commodore 264 series: the Plus/4, the C16 and the C116. A 7501 on
|
|
15
|
+
# the TED's clock, which runs it once or twice a TED cycle (Chips::TED's
|
|
16
|
+
# Beam), the TED and, on the Plus/4, a 6551 ACIA and the user port's
|
|
17
|
+
# 6529. Only the TED pulls IRQ, and nothing pulls NMI, which the 7501
|
|
18
|
+
# doesn't have.
|
|
19
|
+
#
|
|
20
|
+
# It runs headless only: the TED paints no picture yet. Device 8
|
|
21
|
+
# serves disks through the KERNAL traps (C64::KernalTraps), and
|
|
22
|
+
# cartridges go in cartridge 1's slots.
|
|
23
|
+
class Plus4
|
|
24
|
+
include IntegerHelper
|
|
25
|
+
include Machine::KeyboardBuffer
|
|
26
|
+
include Machine::Clocking
|
|
27
|
+
include C64::KernalTraps
|
|
28
|
+
|
|
29
|
+
# The cycle by which the KERNAL has booted and BASIC printed READY,
|
|
30
|
+
# with a margin, in TED cycles. READY is up by about 116,000 on a PAL
|
|
31
|
+
# Plus/4, 126,000 on an NTSC one and sooner on a C16.
|
|
32
|
+
INIT_THRESHOLD = 200_000
|
|
33
|
+
|
|
34
|
+
attr_reader :model, :bus, :cpu, :ted, :port, :keyboard, :keyboard_port, :acia, :user_port, :datasette, :tias,
|
|
35
|
+
:iec_bus, :cycles, :ram_kb
|
|
36
|
+
|
|
37
|
+
def family = :plus4
|
|
38
|
+
|
|
39
|
+
def init_threshold = INIT_THRESHOLD
|
|
40
|
+
|
|
41
|
+
def ram = @bus.ram
|
|
42
|
+
|
|
43
|
+
# Reads and writes memory as the CPU sees it, through the bus.
|
|
44
|
+
def peek(addr) = @bus.peek(addr)
|
|
45
|
+
|
|
46
|
+
def poke(addr, value) = @bus.poke(addr, value)
|
|
47
|
+
|
|
48
|
+
# +model+ names one of Model::ALL, or c116 for the C16, and +ram+ the
|
|
49
|
+
# RAM in K, one of Model::RAM_SIZES, when not the model's own. +tcbm+
|
|
50
|
+
# plugs in a 1551's TCBM interface, the TIAs at $FEC0-$FEFF, with no
|
|
51
|
+
# drive answering on the other side.
|
|
52
|
+
def initialize(model: "plus4", ram: nil, tcbm: false, debug: false)
|
|
53
|
+
@model = Model.named(model)
|
|
54
|
+
@ram_kb = ram || @model.ram_kb
|
|
55
|
+
raise ArgumentError, "no Plus/4 RAM size of #{@ram_kb}K" unless Model::RAM_SIZES.include?(@ram_kb)
|
|
56
|
+
|
|
57
|
+
@ted = Chips::TED.new(@model.ted)
|
|
58
|
+
@keyboard = Input::Keyboard.new(matrix: KeyboardPort::MATRIX)
|
|
59
|
+
@keyboard_port = KeyboardPort.new(@keyboard)
|
|
60
|
+
@ted.keyboard_port = @keyboard_port
|
|
61
|
+
@iec_bus = Drives::SerialBus.new
|
|
62
|
+
@datasette = Drives::Datasette.new(level: true)
|
|
63
|
+
@port = CPUPort.new(serial_bus: @iec_bus, datasette: @datasette)
|
|
64
|
+
plus4_parts = @model.plus4_parts
|
|
65
|
+
@acia = plus4_parts ? ACIA.new : nil
|
|
66
|
+
@user_port = plus4_parts ? UserPort.new(@datasette) : nil
|
|
67
|
+
io = Bus::IOPage.new(keyboard_port: @keyboard_port, acia: @acia, user_port: @user_port)
|
|
68
|
+
@bus = Bus.new(ted: @ted, port: @port, io:, model: @model, ram_kb: @ram_kb)
|
|
69
|
+
@tias = tcbm ? [Chips::TIA.new, Chips::TIA.new] : []
|
|
70
|
+
@bus.plug_tcbm(drive8: @tias[0], drive9: @tias[1]) if tcbm
|
|
71
|
+
@cpu = CPU.new(@bus, debug:)
|
|
72
|
+
@cycles = 0
|
|
73
|
+
@init_handlers = []
|
|
74
|
+
@pending_keys = nil
|
|
75
|
+
@dos = nil
|
|
76
|
+
@serial_trap = nil
|
|
77
|
+
@save_trap = nil
|
|
78
|
+
@capture_output = nil
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# One TED cycle: the TED moves on and decides the CPU's clock, then the
|
|
82
|
+
# CPU runs its cycles in it, none while the TED holds the bus.
|
|
83
|
+
def cycle!
|
|
84
|
+
handle_init if @cycles == INIT_THRESHOLD
|
|
85
|
+
feed_keyboard if @pending_keys
|
|
86
|
+
|
|
87
|
+
ted = @ted
|
|
88
|
+
ted.cycle!
|
|
89
|
+
@datasette.cycle!
|
|
90
|
+
@cpu.irq = ted.irq?
|
|
91
|
+
slots = ted.cpu_slots
|
|
92
|
+
if slots.zero?
|
|
93
|
+
@cpu.stall!
|
|
94
|
+
else
|
|
95
|
+
clock_cpu(ted)
|
|
96
|
+
clock_cpu(ted) if slots == 2
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
@cycles += 1
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# The RESET line: the CPU, the port, the 6529s, the ACIA, the bank
|
|
103
|
+
# latch and ROM selection. The TED has no reset pin.
|
|
104
|
+
def reset!
|
|
105
|
+
@port.reset!
|
|
106
|
+
@keyboard_port.reset!
|
|
107
|
+
@user_port&.reset!
|
|
108
|
+
@dos&.reset!
|
|
109
|
+
@acia&.reset!
|
|
110
|
+
@tias.each(&:reset!)
|
|
111
|
+
@bus.reset!
|
|
112
|
+
@cpu.reset!
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Switches the machine off and on: RAM and the TED start from their
|
|
116
|
+
# power-on state, and the RES line resets everything else.
|
|
117
|
+
def power_cycle!
|
|
118
|
+
@bus.power_on!
|
|
119
|
+
@ted.power_on!
|
|
120
|
+
reset!
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Calls the block with the exit code a VICE testprog writes to $FDCF.
|
|
124
|
+
def install_debug_register(&) = @bus.install_debug_register(&)
|
|
125
|
+
|
|
126
|
+
# Puts a cartridge's ROM chips in cartridge 1's slots (Bus#attach_cartridge)
|
|
127
|
+
# and switches the machine off and on, as a cartridge goes in with the
|
|
128
|
+
# power off. The KERNAL starts it at reset when it signs itself with CBM
|
|
129
|
+
# at $8007.
|
|
130
|
+
def attach_cartridge(chips)
|
|
131
|
+
@bus.attach_cartridge(chips)
|
|
132
|
+
power_cycle!
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Stores a PRG's bytes from its load address on, into RAM, and returns
|
|
136
|
+
# that address.
|
|
137
|
+
def load_prg(data)
|
|
138
|
+
load_addr = uint16(data[0], data[1])
|
|
139
|
+
bytes = data[2..] || []
|
|
140
|
+
bytes = bytes[0, 0x10000 - load_addr] if load_addr + bytes.length > 0x10000
|
|
141
|
+
bytes.each_with_index { |byte, i| @bus.ram_view.poke(load_addr + i, byte) }
|
|
142
|
+
load_addr
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
private
|
|
146
|
+
|
|
147
|
+
# The 264 KERNAL's keyboard buffer.
|
|
148
|
+
def keyboard_buffer = Machine::KeyboardBuffer::PLUS4_LAYOUT
|
|
149
|
+
|
|
150
|
+
# The 264 KERNAL, which the traps stand in for.
|
|
151
|
+
def trap_layout = KernalTrap::PLUS4_LAYOUT
|
|
152
|
+
|
|
153
|
+
def trap_bus = @bus
|
|
154
|
+
|
|
155
|
+
# Device 8, which the serial traps answer for, with no true drive on
|
|
156
|
+
# the bus to take it.
|
|
157
|
+
def serial_trap_device = KernalTrap::Routine::DEVICE
|
|
158
|
+
|
|
159
|
+
# BA stops the CPU at a read, and a write goes ahead.
|
|
160
|
+
def clock_cpu(ted)
|
|
161
|
+
ted.ba_low? && !@cpu.pending_write? ? @cpu.stall! : @cpu.cycle!
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
data/lib/badline/roms/README
CHANGED
|
@@ -132,3 +132,41 @@ c128/character.rom
|
|
|
132
132
|
The character generator ROM, 390059-01 (characters.390059-01.bin),
|
|
133
133
|
8 KB: the C64's set, the same as character.rom, followed by the C128's.
|
|
134
134
|
SHA-1 29ed066d513f2d5c09ff26d9166ba23c2afb2b3f.
|
|
135
|
+
|
|
136
|
+
Commodore 264 series ROMs
|
|
137
|
+
=========================
|
|
138
|
+
|
|
139
|
+
Downloaded from
|
|
140
|
+
https://www.zimmers.net/anonftp/pub/cbm/firmware/computers/plus4/
|
|
141
|
+
for the Plus/4, the C16 and the C116, which share BASIC and the KERNAL.
|
|
142
|
+
Nothing maps them yet.
|
|
143
|
+
|
|
144
|
+
plus4/basic.rom
|
|
145
|
+
---------------
|
|
146
|
+
BASIC 3.5, 318006-01 (basic.318006-01.bin), for $8000-$BFFF in ROM
|
|
147
|
+
bank 0.
|
|
148
|
+
SHA-1 161c96b4ad20f3a4f2321808e37a5ded26a135dd.
|
|
149
|
+
|
|
150
|
+
plus4/kernal-pal.rom
|
|
151
|
+
--------------------
|
|
152
|
+
The PAL KERNAL, 318004-05 (kernal.318004-05.bin), for $C000-$FFFF in
|
|
153
|
+
ROM bank 0, with the character set from $D000.
|
|
154
|
+
SHA-1 7c7e07f016391174a557e790c4ef1cbe33512cdb.
|
|
155
|
+
|
|
156
|
+
plus4/kernal-ntsc.rom
|
|
157
|
+
---------------------
|
|
158
|
+
The NTSC KERNAL, 318005-05 (kernal.318005-05.bin), for $C000-$FFFF in
|
|
159
|
+
ROM bank 0.
|
|
160
|
+
SHA-1 a3d9e5be091b98de39a046ab167fb7632d053682.
|
|
161
|
+
|
|
162
|
+
plus4/function-low.rom
|
|
163
|
+
----------------------
|
|
164
|
+
The Plus/4's 3-plus-1 function ROM, low half, 317053-01
|
|
165
|
+
(3-plus-1.317053-01.bin), for $8000-$BFFF in ROM bank 1.
|
|
166
|
+
SHA-1 3b69f6e7cb4c18bb08e203fb18b7dabfa853390f.
|
|
167
|
+
|
|
168
|
+
plus4/function-high.rom
|
|
169
|
+
-----------------------
|
|
170
|
+
The Plus/4's 3-plus-1 function ROM, high half, 317054-01
|
|
171
|
+
(3-plus-1.317054-01.bin), for $C000-$FFFF in ROM bank 1.
|
|
172
|
+
SHA-1 0ad7ac2db7da692d972e586ca0dfd747d82c7693.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -7,31 +7,20 @@ module Badline
|
|
|
7
7
|
C128Setup = Data.define(:model, :sid_model, :mode)
|
|
8
8
|
|
|
9
9
|
class C128Setup
|
|
10
|
-
MARKER = "C128"
|
|
11
10
|
SID_MODELS = %i[mos6581 mos8580].freeze
|
|
12
11
|
MODES = %i[c64 c128].freeze
|
|
13
12
|
|
|
14
|
-
# The
|
|
15
|
-
def
|
|
16
|
-
|
|
17
|
-
input.marker(MARKER)
|
|
18
|
-
input.check_stamp
|
|
19
|
-
read(input)
|
|
13
|
+
# The model, the SID and the mode by name, in a keyed snapshot module.
|
|
14
|
+
def write_fields(out)
|
|
15
|
+
out.text("model", model).text("sid_model", sid_model.to_s).text("mode", mode.to_s)
|
|
20
16
|
end
|
|
21
17
|
|
|
22
|
-
def self.
|
|
23
|
-
model = input.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
new(model:, sid_model:, mode: MODES.fetch(input.int))
|
|
29
|
-
rescue IndexError
|
|
30
|
-
raise FormatError, "the state names a SID or a mode badline doesn't know"
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def write(out)
|
|
34
|
-
out.string(model).int(SID_MODELS.index(sid_model)).int(MODES.index(mode))
|
|
18
|
+
def self.read_fields(input)
|
|
19
|
+
model = input.choice("model", C128::Model::ALL.map(&:name), "c128")
|
|
20
|
+
sid = input.choice("sid_model", SID_MODELS.map(&:to_s), "mos6581")
|
|
21
|
+
mode = input.choice("mode", MODES.map(&:to_s), "c64")
|
|
22
|
+
new(model:, sid_model: SID_MODELS.find { |name| name.to_s == sid } || :mos6581,
|
|
23
|
+
mode: MODES.find { |name| name.to_s == mode } || :c64)
|
|
35
24
|
end
|
|
36
25
|
|
|
37
26
|
# A machine built this way, at power-on.
|
|
@@ -9,7 +9,6 @@ module Badline
|
|
|
9
9
|
:board)
|
|
10
10
|
|
|
11
11
|
class C64Setup
|
|
12
|
-
MARKER = "COMPUTER"
|
|
13
12
|
SID_MODELS = %i[mos6581 mos8580].freeze
|
|
14
13
|
REGIONS = [Region::PAL, Region::NTSC, Region::NTSC_OLD, Region::DREAN].freeze
|
|
15
14
|
RAM_EXPANSIONS = [:none, *C64::BankedRAM::TYPES.keys].freeze
|
|
@@ -22,23 +21,6 @@ module Badline
|
|
|
22
21
|
kernal: address_bus.kernal, datasette: address_bus.datasette.connected?, board: address_bus.board)
|
|
23
22
|
end
|
|
24
23
|
|
|
25
|
-
# The setup a C64's State starts with.
|
|
26
|
-
def self.from(state)
|
|
27
|
-
input = StateReader.new(state)
|
|
28
|
-
input.marker(MARKER)
|
|
29
|
-
input.check_stamp
|
|
30
|
-
read(input)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def self.read(input)
|
|
34
|
-
new(vic_model: Chips::VIC::MODELS.fetch(input.int), cia_model: Chips::CIA::MODELS.fetch(input.int),
|
|
35
|
-
sid_model: SID_MODELS.fetch(input.int), region: REGIONS.fetch(input.int),
|
|
36
|
-
ram_expansion: ram_expansion(RAM_EXPANSIONS.fetch(input.int)), reu: reu(input.int),
|
|
37
|
-
kernal: KERNALS.fetch(input.int), datasette: input.boolean?, board: BOARDS.fetch(input.int))
|
|
38
|
-
rescue IndexError
|
|
39
|
-
raise FormatError, "the state names a chip model, region, RAM expansion, KERNAL or board badline doesn't know"
|
|
40
|
-
end
|
|
41
|
-
|
|
42
24
|
def self.ram_expansion(name) = name == :none ? nil : name
|
|
43
25
|
|
|
44
26
|
# An REU's size in K, written as 0 for none.
|
|
@@ -46,14 +28,36 @@ module Badline
|
|
|
46
28
|
return nil if size_kb.zero?
|
|
47
29
|
return size_kb if C64::REU::SIZES_KB.include?(size_kb)
|
|
48
30
|
|
|
49
|
-
raise FormatError, "the
|
|
31
|
+
raise FormatError, "the snapshot names a #{size_kb}K REU, which badline doesn't build"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# The setup in a keyed snapshot module (Snapshot::Keyed), with each
|
|
35
|
+
# model, the region, the RAM expansion, the KERNAL and the board by
|
|
36
|
+
# name.
|
|
37
|
+
def write_fields(out)
|
|
38
|
+
out.text("vic_model", vic_model.to_s).text("cia_model", cia_model.to_s).text("sid_model", sid_model.to_s)
|
|
39
|
+
out.text("region", region.name.to_s).text("ram_expansion", (ram_expansion || :none).to_s)
|
|
40
|
+
out.int("reu_kb", reu || 0).text("kernal", kernal.to_s).bool("datasette", datasette)
|
|
41
|
+
out.text("board", board.to_s)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# The setup a keyed snapshot module names, a C64's at power-on for
|
|
45
|
+
# anything it leaves out or names that badline doesn't build.
|
|
46
|
+
def self.read_fields(input)
|
|
47
|
+
region = named(input, "region", REGIONS.map(&:name), :pal)
|
|
48
|
+
new(vic_model: named(input, "vic_model", Chips::VIC::MODELS, :mos6569),
|
|
49
|
+
cia_model: named(input, "cia_model", Chips::CIA::MODELS, :mos6526),
|
|
50
|
+
sid_model: named(input, "sid_model", SID_MODELS, :mos6581),
|
|
51
|
+
region: REGIONS.find { |each| each.name == region } || Region::PAL,
|
|
52
|
+
ram_expansion: ram_expansion(named(input, "ram_expansion", RAM_EXPANSIONS, :none)),
|
|
53
|
+
reu: reu(input.int("reu_kb", 0)), kernal: named(input, "kernal", KERNALS, :c64),
|
|
54
|
+
datasette: input.bool("datasette", true), board: named(input, "board", BOARDS, :c64))
|
|
50
55
|
end
|
|
51
56
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
out.int(KERNALS.index(kernal)).boolean(datasette).int(BOARDS.index(board))
|
|
57
|
+
# The Symbol of `names` the text at `key` names.
|
|
58
|
+
def self.named(input, key, names, default)
|
|
59
|
+
text = input.choice(key, names.map(&:to_s), default.to_s)
|
|
60
|
+
names.find { |name| name.to_s == text } || default
|
|
57
61
|
end
|
|
58
62
|
|
|
59
63
|
# A machine built this way, at power-on.
|
|
@@ -4,6 +4,10 @@ require "zlib"
|
|
|
4
4
|
|
|
5
5
|
module Badline
|
|
6
6
|
module Snapshot
|
|
7
|
+
# A file that isn't a snapshot badline reads, is cut short, or is of a
|
|
8
|
+
# machine built another way.
|
|
9
|
+
class FormatError < StandardError; end
|
|
10
|
+
|
|
7
11
|
# One module of a snapshot: its name, its version and its payload,
|
|
8
12
|
# without the 22-byte module header.
|
|
9
13
|
Section = Data.define(:name, :major, :minor, :data) do
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Snapshot
|
|
5
|
+
module FieldDoc
|
|
6
|
+
# The doc's markdown: one table per module, of each key, its type and
|
|
7
|
+
# its default, with keys that differ only in a unit's number, such as
|
|
8
|
+
# voice1 to voice3, on one row.
|
|
9
|
+
class Markdown
|
|
10
|
+
NAMES = { "c64" => "C64", "vic20" => "VIC-20", "c128" => "C128" }.freeze
|
|
11
|
+
TAG_TYPES = { Keyed::INT => "int", Keyed::BOOL => "bool", Keyed::BYTES => "bytes", Keyed::INTS => "ints",
|
|
12
|
+
Keyed::TEXT => "text" }.freeze
|
|
13
|
+
|
|
14
|
+
# A row: the key, the type, and the defaults each family whose
|
|
15
|
+
# machines read or write it reads it with.
|
|
16
|
+
Row = Struct.new(:key, :type, :defaults)
|
|
17
|
+
|
|
18
|
+
INTRO = <<~MARKDOWN
|
|
19
|
+
# Snapshot format
|
|
20
|
+
|
|
21
|
+
This file is generated by `rake snapshot:fields` from the code that
|
|
22
|
+
loads a snapshot. Don't edit it by hand. doc/snapshots.md covers
|
|
23
|
+
what a snapshot holds and which versions load.
|
|
24
|
+
|
|
25
|
+
A snapshot is a VICE `.vsf` container. The machine is in modules
|
|
26
|
+
named `BL-` plus a unit, each a deflated list of records: a key, a
|
|
27
|
+
type and a value. The types are `int` (a zigzag BER integer), `bool`,
|
|
28
|
+
`bytes`, `ints` (a list of integers) and `text`. A load skips a key
|
|
29
|
+
it doesn't know, and a key that isn't there leaves the value a
|
|
30
|
+
machine built afresh has: the default below. `word`, `byte` and
|
|
31
|
+
`int & 0x..` are ints cut to the latch's width. A text that lists
|
|
32
|
+
its values takes one of them. An optional int is absent when the
|
|
33
|
+
latch holds nothing. A true drive's modules are named from its
|
|
34
|
+
device number, `BL-D8` to `BL-D11`. Keys with `<N>` stand for each
|
|
35
|
+
numbered unit. A default of "written only" is a key the load
|
|
36
|
+
doesn't read, or reads only when the snapshot has it. Where the
|
|
37
|
+
machines differ, the default is given for each, and a key only
|
|
38
|
+
some of them have names them.
|
|
39
|
+
MARKDOWN
|
|
40
|
+
|
|
41
|
+
def initialize(loads)
|
|
42
|
+
@modules = {}
|
|
43
|
+
loads.each { |load| add(load) }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def to_s
|
|
47
|
+
sections = @modules.map do |name, rows|
|
|
48
|
+
families = rows.values.flat_map { |row| row.defaults.keys }.uniq
|
|
49
|
+
["## #{name}", "", "Written by the #{families.map { |family| NAMES.fetch(family) }.join(', ')}.", "",
|
|
50
|
+
"| Key | Type | Default |", "| --- | --- | --- |",
|
|
51
|
+
*rows.values.map { |row| line(row, families) }].join("\n")
|
|
52
|
+
end
|
|
53
|
+
"#{INTRO}\n#{sections.join("\n\n")}\n"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def add(load)
|
|
59
|
+
load.fields.each do |name, fields|
|
|
60
|
+
numbered = numbered_keys(load.written[name].keys + fields.map(&:key))
|
|
61
|
+
fields.each { |field| note(name, numbered.fetch(field.key, field.key), field.type, load.family, field) }
|
|
62
|
+
read = fields.to_set(&:key)
|
|
63
|
+
load.written[name].each do |key, tag|
|
|
64
|
+
next if read.include?(key)
|
|
65
|
+
|
|
66
|
+
note(name, numbered.fetch(key, key), TAG_TYPES.fetch(tag, "?"), load.family, nil)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def note(name, key, type, family, field)
|
|
72
|
+
row = (@modules[name] ||= {})[key] ||= Row.new(key, type, {})
|
|
73
|
+
(row.defaults[family] ||= []) << (field ? brief(field.default, field.type) : "written only")
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Keys that differ only in a number, as the same key with <N>: each
|
|
77
|
+
# key whose number another key in the module shares the rest of.
|
|
78
|
+
def numbered_keys(keys)
|
|
79
|
+
groups = keys.uniq.group_by { |key| key.gsub(/(?<=[a-z])\d+(?=\.|\z)/, "<N>") }
|
|
80
|
+
groups.each_with_object({}) do |(general, members), numbered|
|
|
81
|
+
members.each { |key| numbered[key] = general } if members.length > 1
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def line(row, families)
|
|
86
|
+
each = row.defaults.transform_values { |defaults| summary(defaults.uniq) }
|
|
87
|
+
default = if each.values.uniq.length == 1 && each.length == families.length then each.values.first
|
|
88
|
+
else each.map { |family, value| "#{NAMES.fetch(family)}: #{value}" }.join("; ")
|
|
89
|
+
end
|
|
90
|
+
"| `#{row.key}` | #{row.type} | #{default} |"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def summary(defaults) = defaults.length > 3 ? "varies" : defaults.join(" or ")
|
|
94
|
+
|
|
95
|
+
def brief(value, type)
|
|
96
|
+
case value
|
|
97
|
+
when nil then "absent"
|
|
98
|
+
when Array then list(value)
|
|
99
|
+
when String then type.start_with?("bytes") ? list(value.bytes) : value.inspect
|
|
100
|
+
else value.to_s
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def list(values)
|
|
105
|
+
return values.inspect if values.length <= 8
|
|
106
|
+
|
|
107
|
+
values.uniq.length == 1 ? "#{values.length} × #{values.first}" : "#{values.length} values"
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "badline"
|
|
4
|
+
require "badline/c128"
|
|
5
|
+
|
|
6
|
+
module Badline
|
|
7
|
+
module Snapshot
|
|
8
|
+
# doc/snapshot-format.md, written by running the code: each family's
|
|
9
|
+
# machine is saved with its attachments, and its modules loaded into a
|
|
10
|
+
# machine built the same way at power-on through Keyed::Recorders,
|
|
11
|
+
# which note every key read with its type and the value the new machine
|
|
12
|
+
# had, its default. `rake snapshot:fields` writes it, and a spec checks
|
|
13
|
+
# that the file matches.
|
|
14
|
+
module FieldDoc
|
|
15
|
+
PATH = File.expand_path("../../../doc/snapshot-format.md", __dir__)
|
|
16
|
+
|
|
17
|
+
# Modules read through Recorders.
|
|
18
|
+
class RecordingModules < Keyed::Modules
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def parse(section) = Keyed::Recorder.parse(section)
|
|
22
|
+
|
|
23
|
+
def missing(name) = Keyed::Recorder.missing(name)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# One machine saved and loaded: the family it belongs to, and for
|
|
27
|
+
# each module the keys its records hold, with their tags, and the fields the load read.
|
|
28
|
+
Load = Data.define(:family, :written, :fields)
|
|
29
|
+
|
|
30
|
+
# The machines the doc is made from: each family at power-on, and the
|
|
31
|
+
# C64 with each kind of expansion, cartridge and media.
|
|
32
|
+
def self.machines
|
|
33
|
+
{
|
|
34
|
+
"c64" => [C64.new, C64.new(ram_expansion: :plus256k), C64.new(reu: 512), with_cartridge, with_trap_dos,
|
|
35
|
+
with_tape, with_drive(:d64), with_drive(:d81)],
|
|
36
|
+
"vic20" => [Vic20.new, with_rom],
|
|
37
|
+
"c128" => [C128.new(mode: :c128), with_drive(:d71)]
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.blank(length) = Array.new(length, 0)
|
|
42
|
+
|
|
43
|
+
def self.with_cartridge
|
|
44
|
+
chips = [0x8000, 0xa000].map do |address|
|
|
45
|
+
Storage::CRTFile::Chip.new(chip_type: 2, bank: 0, address:, data: blank(0x2000))
|
|
46
|
+
end
|
|
47
|
+
image = Storage::CRTFile::Image.new(hardware_type: 32, subtype: 0, exrom: 1, game: 0, name: "DOC", chips:)
|
|
48
|
+
C64.new.tap do |machine|
|
|
49
|
+
machine.attach_cartridge(C64::Cartridge.from_crt(Storage::CRTFile.new(bytes: Storage::CRTFile.encode(image))))
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.with_trap_dos
|
|
54
|
+
C64.new.tap { |machine| machine.mount(Storage::D64Image.new("", read_only: true, bytes: blank(174_848))) }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def self.with_tape
|
|
58
|
+
bytes = "C64-TAPE-RAW".bytes + [1, 0, 0, 0, 4, 0, 0, 0, 0x30, 0x30, 0x30, 0x30]
|
|
59
|
+
C64.new.tap { |machine| machine.datasette.insert(Storage::TAP.new("", bytes:)) }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.with_drive(kind)
|
|
63
|
+
case kind
|
|
64
|
+
when :d81
|
|
65
|
+
C64.new.tap do |machine|
|
|
66
|
+
machine.plug_drive1581.insert(Drives::Model1581::Disk.new(Storage::D81Image.new("", bytes: blank(819_200))))
|
|
67
|
+
end
|
|
68
|
+
when :d71
|
|
69
|
+
C128.new(mode: :c128).tap do |machine|
|
|
70
|
+
image = Storage::D71Image.new("", bytes: blank(349_696))
|
|
71
|
+
machine.plug_true_drive.insert(Drives::Model1541::Disk.decode(image))
|
|
72
|
+
end
|
|
73
|
+
else
|
|
74
|
+
C64.new.tap do |machine|
|
|
75
|
+
image = Storage::D64Image.new("", bytes: blank(174_848))
|
|
76
|
+
machine.plug_true_drive.insert(Drives::Model1541::Disk.decode(image))
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def self.with_rom
|
|
82
|
+
Vic20.new.tap { |machine| machine.bus.map_rom(0xa000, blank(0x2000)) }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Saves `machine` and loads it into a new one through Recorders.
|
|
86
|
+
def self.load(family, machine)
|
|
87
|
+
modules = RecordingModules.new(Image.of(machine).sections)
|
|
88
|
+
Image.setup(modules.machine).build.load_modules(modules)
|
|
89
|
+
modules.machine.text("written_by", "")
|
|
90
|
+
written = {}
|
|
91
|
+
fields = {}
|
|
92
|
+
modules.readers.each do |reader|
|
|
93
|
+
written[reader.name] = reader.tags
|
|
94
|
+
fields[reader.name] = reader.fields
|
|
95
|
+
end
|
|
96
|
+
Load.new(family:, written:, fields:)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def self.loads = machines.flat_map { |family, list| list.map { |machine| load(family, machine) } }
|
|
100
|
+
|
|
101
|
+
# The doc, as markdown.
|
|
102
|
+
def self.markdown(loads = self.loads) = Markdown.new(loads).to_s
|
|
103
|
+
|
|
104
|
+
def self.write(path = PATH) = File.write(path, markdown)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
require "badline/snapshot/field_doc/markdown"
|