badline 0.17.0 → 0.19.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 +193 -0
- data/CLAUDE.md +19 -7
- data/CONTRIBUTING.md +11 -1
- data/README.md +178 -26
- data/doc/library.md +5 -1
- data/doc/media.md +3 -2
- data/doc/pinned-behaviour.md +169 -1
- data/doc/snapshot-format.md +302 -35
- data/doc/snapshots.md +97 -26
- data/doc/vice.md +344 -0
- data/exe/badline-ruby +5 -0
- data/lib/badline/audio/renderer.rb +4 -8
- data/lib/badline/audio/terminal.rb +34 -2
- data/lib/badline/c128/keyed_state.rb +2 -0
- data/lib/badline/c128.rb +5 -0
- data/lib/badline/c64/bus/fittings.rb +6 -0
- data/lib/badline/c64/keyed_state.rb +2 -0
- data/lib/badline/c64.rb +7 -0
- data/lib/badline/cbm2/keyed_state.rb +4 -0
- data/lib/badline/cbm2/p500.rb +9 -3
- data/lib/badline/cbm2.rb +10 -3
- data/lib/badline/chips/cia/timer.rb +2 -2
- data/lib/badline/chips/cpu/core.rb +29 -4
- data/lib/badline/chips/cpu/instruction_set.rb +1 -1
- data/lib/badline/chips/cpu/interrupts.rb +9 -0
- data/lib/badline/chips/cpu/keyed_state.rb +15 -9
- data/lib/badline/chips/cpu/microcode.rb +10 -0
- data/lib/badline/chips/m6809/arithmetic.rb +140 -0
- data/lib/badline/chips/m6809/bus_steps.rb +223 -0
- data/lib/badline/chips/m6809/core.rb +149 -0
- data/lib/badline/chips/m6809/indexed.rb +82 -0
- data/lib/badline/chips/m6809/interrupts.rb +159 -0
- data/lib/badline/chips/m6809/keyed_state.rb +147 -0
- data/lib/badline/chips/m6809/opcodes.rb +159 -0
- data/lib/badline/chips/m6809/operations.rb +258 -0
- data/lib/badline/chips/m6809/plans.rb +143 -0
- data/lib/badline/chips/m6809/registers.rb +82 -0
- data/lib/badline/chips/m6809/stack.rb +140 -0
- data/lib/badline/chips/m6809.rb +13 -0
- data/lib/badline/chips/riot/timer.rb +14 -3
- data/lib/badline/chips/rriot.rb +8 -3
- data/lib/badline/chips/sid/decimator.rb +1 -1
- data/lib/badline/chips/sid/filter.rb +4 -4
- data/lib/badline/chips/sid/keyed_parts.rb +51 -18
- data/lib/badline/chips/sid/waveform.rb +6 -6
- data/lib/badline/chips/sid.rb +6 -2
- data/lib/badline/chips/vic_i/keyed_parts.rb +12 -2
- data/lib/badline/chips/vic_i/light_pen.rb +89 -0
- data/lib/badline/chips/vic_i.rb +91 -23
- data/lib/badline/data_path.rb +3 -3
- data/lib/badline/drives/ieee_models.rb +54 -0
- data/lib/badline/drives/model1001.rb +37 -0
- data/lib/badline/drives/model1541/sector_reader.rb +20 -3
- data/lib/badline/drives/model1541.rb +1 -0
- data/lib/badline/drives/model1551.rb +1 -0
- data/lib/badline/drives/model1571.rb +1 -0
- data/lib/badline/drives/model1581.rb +1 -0
- data/lib/badline/drives/model2031.rb +7 -0
- data/lib/badline/drives/model4040/disk.rb +62 -0
- data/lib/badline/drives/model4040/ip_bus.rb +46 -0
- data/lib/badline/drives/model4040/keyed_state.rb +57 -0
- data/lib/badline/drives/model4040/mechanism.rb +195 -0
- data/lib/badline/drives/model4040/parts.rb +20 -0
- data/lib/badline/drives/model4040.rb +195 -0
- data/lib/badline/drives/model8050/board.rb +79 -0
- data/lib/badline/drives/model8050/dos_board.rb +134 -0
- data/lib/badline/drives/model8050/fdc_bus.rb +7 -0
- data/lib/badline/drives/model8050/idle.rb +148 -31
- data/lib/badline/drives/model8050/keyed_state.rb +5 -2
- data/lib/badline/drives/model8050.rb +32 -130
- data/lib/badline/drives/model9060/idle.rb +169 -0
- data/lib/badline/drives/model9060/keyed_state.rb +123 -0
- data/lib/badline/drives/model9060/parts.rb +98 -0
- data/lib/badline/drives/model9060/sasi_bus.rb +88 -0
- data/lib/badline/drives/model9060/sasi_commands.rb +168 -0
- data/lib/badline/drives/model9060/sasi_target.rb +161 -0
- data/lib/badline/drives/model9060.rb +197 -0
- data/lib/badline/frontend/app.rb +8 -0
- data/lib/badline/frontend/boot.rb +3 -2
- data/lib/badline/frontend/controls.rb +62 -6
- data/lib/badline/frontend/keys.rb +36 -0
- data/lib/badline/frontend/kim1_panel.rb +208 -0
- data/lib/badline/frontend/media_slots.rb +8 -1
- data/lib/badline/frontend/menu/drive_types.rb +56 -0
- data/lib/badline/frontend/menu/menu_dialogs.rb +61 -14
- data/lib/badline/frontend/menu/menu_media.rb +42 -12
- data/lib/badline/frontend/menu/menu_pages.rb +97 -2
- data/lib/badline/frontend/menu/menu_ports.rb +38 -1
- data/lib/badline/frontend/menu/pause_menu.rb +5 -1
- data/lib/badline/frontend/pet_keyboard.rb +23 -1
- data/lib/badline/frontend/screen.rb +1 -1
- data/lib/badline/frontend/screens.rb +40 -2
- data/lib/badline/frontend/teletype_pane.rb +152 -0
- data/lib/badline/frontend/timeline.rb +31 -2
- data/lib/badline/frontend.rb +3 -0
- data/lib/badline/input/joystick.rb +15 -2
- data/lib/badline/kim1/bus.rb +117 -0
- data/lib/badline/kim1/cpu.rb +25 -0
- data/lib/badline/kim1/host_terminal.rb +74 -0
- data/lib/badline/kim1/key_entry.rb +74 -0
- data/lib/badline/kim1/keyed_modules.rb +53 -0
- data/lib/badline/kim1/keyed_state.rb +133 -0
- data/lib/badline/kim1/panel.rb +176 -0
- data/lib/badline/kim1/rriots.rb +28 -0
- data/lib/badline/kim1/sound.rb +29 -0
- data/lib/badline/kim1/tape.rb +118 -0
- data/lib/badline/kim1/teletype.rb +193 -0
- data/lib/badline/kim1.rb +194 -0
- data/lib/badline/machine/ieee_drives.rb +94 -117
- data/lib/badline/machine/keyboard_buffer.rb +20 -3
- data/lib/badline/machine/line_sound.rb +122 -0
- data/lib/badline/machine.rb +49 -15
- data/lib/badline/media/extensions.rb +8 -4
- data/lib/badline/media/kim1_media.rb +150 -0
- data/lib/badline/media/pet_media.rb +3 -1
- data/lib/badline/media/true_drive.rb +52 -45
- data/lib/badline/media/vic20_media.rb +4 -2
- data/lib/badline/media.rb +16 -6
- data/lib/badline/memory.rb +2 -4
- data/lib/badline/options/family.rb +98 -8
- data/lib/badline/options/help.rb +44 -12
- data/lib/badline/options/table.rb +44 -12
- data/lib/badline/options/validation.rb +44 -8
- data/lib/badline/options.rb +27 -8
- data/lib/badline/pet/bus.rb +16 -2
- data/lib/badline/pet/keyboard_ports.rb +9 -2
- data/lib/badline/pet/keyed_state.rb +4 -0
- data/lib/badline/pet/model.rb +11 -2
- data/lib/badline/pet/rom_sets.rb +1 -0
- data/lib/badline/pet/sound.rb +5 -105
- data/lib/badline/pet/superpet/acia.rb +12 -0
- data/lib/badline/pet/superpet/board.rb +221 -0
- data/lib/badline/pet/superpet/dongle.rb +92 -0
- data/lib/badline/pet/superpet/keyed_modules.rb +63 -0
- data/lib/badline/pet/superpet/keyed_parts.rb +76 -0
- data/lib/badline/pet/superpet/m6809.rb +32 -0
- data/lib/badline/pet/superpet/waterloo_traps.rb +199 -0
- data/lib/badline/pet/superpet.rb +221 -0
- data/lib/badline/pet.rb +23 -3
- data/lib/badline/plus4/keyed_state.rb +2 -0
- data/lib/badline/plus4.rb +5 -0
- data/lib/badline/roms/1001/fdc-251257-02a.rom +0 -0
- data/lib/badline/roms/4040/dos-1.2.rom +0 -0
- data/lib/badline/roms/4040/dos-2.1-rev.rom +0 -0
- data/lib/badline/roms/4040/dos-2.1.rom +0 -0
- data/lib/badline/roms/4040/fdc-901466-02.rom +0 -0
- data/lib/badline/roms/4040/fdc-901466-04.rom +0 -0
- data/lib/badline/roms/9060/dos-3.0.rom +0 -0
- data/lib/badline/roms/9060/sasi-300515-revb.rom +0 -0
- data/lib/badline/roms/README +176 -0
- data/lib/badline/roms/kim1/6530-002.rom +0 -0
- data/lib/badline/roms/kim1/6530-003.rom +0 -0
- data/lib/badline/roms/pet/characters-superpet.rom +0 -0
- data/lib/badline/roms/pet/superpet-a000.rom +0 -0
- data/lib/badline/roms/pet/superpet-c000.rom +0 -0
- data/lib/badline/roms/pet/superpet-e000-50hz.rom +0 -0
- data/lib/badline/roms/pet/superpet-e000.rom +0 -0
- data/lib/badline/snapshot/container.rb +8 -4
- data/lib/badline/snapshot/field_doc/markdown.rb +1 -1
- data/lib/badline/snapshot/field_doc.rb +35 -10
- data/lib/badline/snapshot/image.rb +19 -7
- data/lib/badline/snapshot/kim1_setup.rb +28 -0
- data/lib/badline/snapshot/pet_setup.rb +27 -11
- data/lib/badline/snapshot/storage_setup.rb +4 -1
- data/lib/badline/snapshot/vic20_setup.rb +11 -7
- data/lib/badline/snapshot/vice/pet.rb +14 -7
- data/lib/badline/snapshot/vice/pet_cpu.rb +39 -5
- data/lib/badline/snapshot/vice/pet_crtc.rb +15 -2
- data/lib/badline/snapshot/vice/pet_dongle.rb +72 -0
- data/lib/badline/snapshot/vice/pet_drive8050.rb +188 -68
- data/lib/badline/snapshot/vice/pet_mem.rb +55 -5
- data/lib/badline/snapshot/vice/pet_restore.rb +40 -11
- data/lib/badline/snapshot/vice/vic20.rb +70 -0
- data/lib/badline/snapshot/vice/vic20_cpu.rb +61 -0
- data/lib/badline/snapshot/vice/vic20_mem.rb +85 -0
- data/lib/badline/snapshot/vice/vic20_restore.rb +124 -0
- data/lib/badline/snapshot/vice/vic20_vici.rb +200 -0
- data/lib/badline/snapshot/vice.rb +1 -0
- data/lib/badline/snapshot.rb +8 -4
- data/lib/badline/status.rb +30 -30
- data/lib/badline/storage/d67_image.rb +55 -0
- data/lib/badline/storage/d90_image.rb +180 -0
- data/lib/badline/storage/kim_tape.rb +254 -0
- data/lib/badline/storage/papertape.rb +90 -0
- data/lib/badline/storage.rb +4 -0
- data/lib/badline/support/kim1_checkpoint.rb +41 -0
- data/lib/badline/support/superpet_checkpoint.rb +35 -0
- data/lib/badline/version.rb +1 -1
- data/lib/badline/vic20/keyed_modules.rb +6 -3
- data/lib/badline/vic20/keyed_state.rb +6 -4
- data/lib/badline/vic20/port_wiring.rb +11 -0
- data/lib/badline/vic20.rb +30 -12
- data/lib/badline.rb +1 -0
- metadata +85 -1
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "badline/snapshot/vice/cbm2_acia"
|
|
3
4
|
require "badline/snapshot/vice/pet_cpu"
|
|
5
|
+
require "badline/snapshot/vice/pet_dongle"
|
|
4
6
|
require "badline/snapshot/vice/pet_mem"
|
|
5
7
|
require "badline/snapshot/vice/pet_pias"
|
|
6
8
|
require "badline/snapshot/vice/pet_via"
|
|
@@ -22,8 +24,8 @@ module Badline
|
|
|
22
24
|
# The models badline builds by the board PETMEM names (PETMem): the
|
|
23
25
|
# discrete board is a 2001's where xpet's settings say so, and a
|
|
24
26
|
# 3032 otherwise.
|
|
25
|
-
MODELS = { PETMem::CRTC40 => "4032", PETMem::CRTC80 => "8032", PETMem::
|
|
26
|
-
PETMem::CBM8296 => "8296" }.freeze
|
|
27
|
+
MODELS = { PETMem::CRTC40 => "4032", PETMem::CRTC80 => "8032", PETMem::SUPERPET => "superpet",
|
|
28
|
+
PETMem::CBM8096 => "8096", PETMem::CBM8296 => "8296" }.freeze
|
|
27
29
|
# The modules xpet resets the machine without, for the parts badline
|
|
28
30
|
# doesn't model in VICE's terms, each as xpet leaves them with
|
|
29
31
|
# nothing attached: no file system drive open, both cassette ports
|
|
@@ -50,7 +52,8 @@ module Badline
|
|
|
50
52
|
PIAs.export("PIA1", machine.pia1, reader(readers, "BL-PIA1")),
|
|
51
53
|
PIAs.export("PIA2", machine.pia2, reader(readers, "BL-PIA2")), VIA.export(reader(readers, "BL-VIA")),
|
|
52
54
|
*Drive2031.export(machine, readers), *Drive8050.export(machine, readers)] +
|
|
53
|
-
PERIPHERALS.map { |name, major, minor, bytes| FieldWriter.new.bytes(bytes).section(name, major, minor) }
|
|
55
|
+
PERIPHERALS.map { |name, major, minor, bytes| FieldWriter.new.bytes(bytes).section(name, major, minor) } +
|
|
56
|
+
(machine.superpet? ? [CBM2::ACIA.export(reader(readers, "BL-ACIA"), machine.cycles)] : [])
|
|
54
57
|
end
|
|
55
58
|
|
|
56
59
|
def reader(readers, name) = readers[name] || Keyed::Reader.missing(name)
|
|
@@ -61,7 +64,9 @@ module Badline
|
|
|
61
64
|
# xpet doesn't save the keyboard, the ROMs or an 8296's jumpers, so
|
|
62
65
|
# a discrete board is a 3032 with the graphics keyboard unless it is
|
|
63
66
|
# a 2001, each model has its own ROMs, and an 8296 none of its
|
|
64
|
-
# jumpers, as xpet's own has.
|
|
67
|
+
# jumpers, as xpet's own has. Nor does it save the SuperPET's
|
|
68
|
+
# switches: its CPU switch is at the CPU that has the bus, and its
|
|
69
|
+
# RAM switch at R/W, which is the only position xpet has.
|
|
65
70
|
def setup(container)
|
|
66
71
|
memory = memory(container)
|
|
67
72
|
ram_kb = PETMem.ram_kb(memory)
|
|
@@ -75,8 +80,11 @@ module Badline
|
|
|
75
80
|
crtc = nil unless crtc.nil? || CRTC.reads?(crtc)
|
|
76
81
|
refresh_hz = refresh_hz(crtc, profile)
|
|
77
82
|
profile = Badline::PET::Model.upgraded(profile, nil, editor(crtc, profile, refresh_hz))
|
|
83
|
+
superpet = profile.superpet?
|
|
84
|
+
cpu_switch = PETMem.m6809?(memory) ? "6809" : "6502"
|
|
78
85
|
PETSetup.new(model: name, ram_kb:, refresh_hz:, basic: profile.basic, editor: profile.editor(refresh_hz),
|
|
79
|
-
kernal: profile.kernal, characters: profile.characters, jumpers: ""
|
|
86
|
+
kernal: profile.kernal, characters: profile.characters, jumpers: "",
|
|
87
|
+
cpu_switch: superpet ? cpu_switch : "", ram_switch: superpet ? "rw" : "")
|
|
80
88
|
end
|
|
81
89
|
|
|
82
90
|
def memory(container)
|
|
@@ -94,8 +102,7 @@ module Badline
|
|
|
94
102
|
name = MODELS[board]
|
|
95
103
|
return name unless name.nil?
|
|
96
104
|
|
|
97
|
-
|
|
98
|
-
raise FormatError, "#{memory}: #{what}, which badline doesn't build"
|
|
105
|
+
raise FormatError, "#{memory}: board #{board}, which badline doesn't build"
|
|
99
106
|
end
|
|
100
107
|
|
|
101
108
|
# The editor's frame rate, from the cycles the CRTC's registers set
|
|
@@ -25,7 +25,11 @@ module Badline
|
|
|
25
25
|
|
|
26
26
|
def reads?(section) = section.major == MAJOR && section.minor == MINOR
|
|
27
27
|
|
|
28
|
-
def export(machine)
|
|
28
|
+
def export(machine)
|
|
29
|
+
sources = [machine.pia1.irq?, machine.pia2.irq?, machine.via.irq?]
|
|
30
|
+
sources << machine.acia_irq? if machine.superpet?
|
|
31
|
+
write(machine, sources.count(true))
|
|
32
|
+
end
|
|
29
33
|
|
|
30
34
|
# The module for `machine`, whose CPU's IRQ line `irqs` sources
|
|
31
35
|
# pull.
|
|
@@ -52,16 +56,46 @@ module Badline
|
|
|
52
56
|
end
|
|
53
57
|
|
|
54
58
|
# The SuperPET's 6809, CPU6809 1.1, which xpet saves on every model
|
|
55
|
-
# and won't load a snapshot without: the clock
|
|
56
|
-
#
|
|
57
|
-
#
|
|
59
|
+
# and won't load a snapshot without: the clock, X, Y, U, S and PC,
|
|
60
|
+
# DP, CC, A and B, then five bytes. xpet 3.10's layout was inferred
|
|
61
|
+
# from its snapshots of a 6809 running a loop that loads each
|
|
62
|
+
# register with a value of its own; the five bytes are 0 in every
|
|
63
|
+
# snapshot xpet wrote.
|
|
64
|
+
#
|
|
65
|
+
# Written: the clock and the registers, the SuperPET's 6809's
|
|
66
|
+
# between instructions while it has the bus, and otherwise the
|
|
67
|
+
# registers of a 6809 that hasn't run, as xpet leaves them. Read:
|
|
68
|
+
# the registers, with the 6809 on an instruction boundary, as
|
|
69
|
+
# xpet's snapshot is taken on one.
|
|
58
70
|
module CPU6809
|
|
59
71
|
NAME = "CPU6809"
|
|
72
|
+
MAJOR = 1
|
|
73
|
+
MINOR = 1
|
|
74
|
+
# The CC an xpet without a SuperPET board saves.
|
|
75
|
+
IDLE_CC = 0x04
|
|
60
76
|
|
|
61
77
|
module_function
|
|
62
78
|
|
|
79
|
+
def reads?(section) = section.major == MAJOR && section.minor == MINOR
|
|
80
|
+
|
|
63
81
|
def export(machine)
|
|
64
|
-
FieldWriter.new.qword(machine.cycles)
|
|
82
|
+
fields = FieldWriter.new.qword(machine.cycles)
|
|
83
|
+
unless machine.superpet? && machine.m6809_running?
|
|
84
|
+
return fields.zeros(11).byte(IDLE_CC).zeros(7).section(NAME, MAJOR, MINOR)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
cpu = machine.m6809
|
|
88
|
+
[cpu.x, cpu.y, cpu.u, cpu.s, cpu.pc].each { |register| fields.word(register) }
|
|
89
|
+
fields.byte(cpu.dp).byte(cpu.cc).byte(cpu.a).byte(cpu.b).zeros(5).section(NAME, MAJOR, MINOR)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# The registers by their BL-M6809 keys, in a keyed module's writer,
|
|
93
|
+
# with the 6809's cycle count the machine's `cycles`.
|
|
94
|
+
def import(section, out, cycles)
|
|
95
|
+
fields = FieldReader.new(section).skip(8)
|
|
96
|
+
%w[x y u s pc].each { |name| out.int(name, fields.word) }
|
|
97
|
+
%w[dp cc a b].each { |name| out.int(name, fields.byte) }
|
|
98
|
+
out.int("cycles", cycles).bool("nmi.armed", true)
|
|
65
99
|
end
|
|
66
100
|
end
|
|
67
101
|
end
|
|
@@ -6,7 +6,7 @@ module Badline
|
|
|
6
6
|
module PET
|
|
7
7
|
# CRTC 1.2, which xpet saves on every model, the discrete boards'
|
|
8
8
|
# video too, as a 6545 with the registers fixed: the board's screen
|
|
9
|
-
# settings, the registers, the one selected, the beam's character,
|
|
9
|
+
# settings, the character set VIA CA2 picks, the registers, the one selected, the beam's character,
|
|
10
10
|
# row and line in the row, whether the frame is in its vertical
|
|
11
11
|
# adjust, the row's start in screen RAM, the lines of vertical sync
|
|
12
12
|
# left, whether the rows show, the picture's size, the lines in the
|
|
@@ -36,6 +36,13 @@ module Badline
|
|
|
36
36
|
SETTINGS = [0xff, 0x03, 0x00, 0x20, 0x00, 0x20, 0x00, 0x10, 0xff, 0x1f].freeze
|
|
37
37
|
# The 8296's, whose screen RAM spans 4K.
|
|
38
38
|
SETTINGS_8296 = [0xff, 0x0f, 0x00, 0x20, 0x00, 0x20, 0xff, 0x0f, 0xff, 0x1f].freeze
|
|
39
|
+
# The SuperPET's, whose character ROM spans 4K, inferred from
|
|
40
|
+
# xpet 3.10's SuperPET snapshots.
|
|
41
|
+
SETTINGS_SUPERPET = [0xff, 0x03, 0x00, 0x20, 0x00, 0x20, 0x00, 0x10, 0xff, 0x3f].freeze
|
|
42
|
+
# The word after the settings while VIA CA2 is high, picking the
|
|
43
|
+
# character ROM's second set, as xpet 3.10 writes it and paints
|
|
44
|
+
# the picture from on every PET board.
|
|
45
|
+
SECOND_SET = 0x1000
|
|
39
46
|
# The 2001's and 3000 series' video as xpet's CRTC runs it: 64
|
|
40
47
|
# cycles a line, 32 rows of 8 lines and 4 more, the first 25 rows
|
|
41
48
|
# shown.
|
|
@@ -85,7 +92,7 @@ module Badline
|
|
|
85
92
|
crtc_beam(run_on(fresh_crtc(machine), crtc_input, -CRTC_LEAD % frame_cycles(registers)),
|
|
86
93
|
registers)
|
|
87
94
|
end
|
|
88
|
-
fields = FieldWriter.new.bytes(model.
|
|
95
|
+
fields = FieldWriter.new.bytes(settings(model)).word(machine.via.ca2_output ? SECOND_SET : 0)
|
|
89
96
|
fields.byte(0).byte(columns(model))
|
|
90
97
|
fields.byte(model.basic1? ? 1 : 0).bytes(registers).byte(discrete ? 0 : crtc_input.int("selected", 0))
|
|
91
98
|
beam_fields(fields, beam, registers, model)
|
|
@@ -93,6 +100,12 @@ module Badline
|
|
|
93
100
|
fields.section(NAME, MAJOR, MINOR)
|
|
94
101
|
end
|
|
95
102
|
|
|
103
|
+
def settings(model)
|
|
104
|
+
return SETTINGS_8296 if model.cbm8296?
|
|
105
|
+
|
|
106
|
+
model.superpet? ? SETTINGS_SUPERPET : SETTINGS
|
|
107
|
+
end
|
|
108
|
+
|
|
96
109
|
def crtc_registers(input)
|
|
97
110
|
registers = input.bytes("registers", "".b).bytes
|
|
98
111
|
Array.new(REGISTERS) { |index| registers[index] || 0 }
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Snapshot
|
|
5
|
+
module Vice
|
|
6
|
+
module PET
|
|
7
|
+
# The SuperPET's 6702 in PETMEM's settings at the end, from their
|
|
8
|
+
# fifth byte: the byte the 6702 reads, the last write that shifted
|
|
9
|
+
# it, 1 while the last write left D0 clear, then a little-endian word
|
|
10
|
+
# for each data line's shift register. Bit k of a word, below the
|
|
11
|
+
# register's last stage, is stage k XORed with stage k + 1, and its
|
|
12
|
+
# last stage's bit is that stage XORed with the stage the next shift
|
|
13
|
+
# brings in if the latch then holds the last write that shifted.
|
|
14
|
+
# Every PET's settings hold a 6702 as the RES line leaves it.
|
|
15
|
+
#
|
|
16
|
+
# Mapped from xpet 3.10's snapshots after each of 56 writes to $EFE0
|
|
17
|
+
# from its monitor, against PET::SuperPET::Dongle after the same
|
|
18
|
+
# writes.
|
|
19
|
+
#
|
|
20
|
+
# Written and read: the registers, and whether D0 was clear in the
|
|
21
|
+
# last write. A write the 6702 hasn't shifted on yet is written as
|
|
22
|
+
# shifted. Read, the latch is $00 or $FF by D0, and no shift waits.
|
|
23
|
+
module Dongle
|
|
24
|
+
# Offsets in PETMEM's settings.
|
|
25
|
+
AT = 4
|
|
26
|
+
LENGTH = 19
|
|
27
|
+
OUTPUT = 0
|
|
28
|
+
ARMED = 2
|
|
29
|
+
WORDS = 3
|
|
30
|
+
# The last write that shifted, as xpet has it after RES.
|
|
31
|
+
RESET_LAST = 0x01
|
|
32
|
+
|
|
33
|
+
module_function
|
|
34
|
+
|
|
35
|
+
# The settings' bytes for a 6702 with `registers`, after a write
|
|
36
|
+
# of `latch`.
|
|
37
|
+
def export(registers, latch)
|
|
38
|
+
incoming = RESET_LAST ^ Badline::PET::SuperPET::Dongle::FEEDBACK ^ 0xff
|
|
39
|
+
output = 0
|
|
40
|
+
words = []
|
|
41
|
+
8.times do |bit|
|
|
42
|
+
register = registers[bit]
|
|
43
|
+
output |= (register & 1) << bit
|
|
44
|
+
top = Badline::PET::SuperPET::Dongle::LENGTHS[bit] - 1
|
|
45
|
+
last = ((register >> top) ^ register ^ (incoming >> bit)) & 1
|
|
46
|
+
word = ((register ^ (register >> 1)) & ((1 << top) - 1)) | (last << top)
|
|
47
|
+
words << (word & 0xff) << (word >> 8)
|
|
48
|
+
end
|
|
49
|
+
[output ^ Badline::PET::SuperPET::Dongle::INVERTED, RESET_LAST, latch.nobits?(0x01) ? 1 : 0, *words]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# The 6702's BL-SUPERPET keys from the settings' `bytes`, in a keyed
|
|
53
|
+
# module's writer.
|
|
54
|
+
def import(bytes, out)
|
|
55
|
+
stages = bytes[OUTPUT] ^ Badline::PET::SuperPET::Dongle::INVERTED
|
|
56
|
+
registers = Array.new(8) do |bit|
|
|
57
|
+
word = bytes[WORDS + (bit * 2)] | (bytes[WORDS + (bit * 2) + 1] << 8)
|
|
58
|
+
stage = (stages >> bit) & 1
|
|
59
|
+
register = stage
|
|
60
|
+
(Badline::PET::SuperPET::Dongle::LENGTHS[bit] - 1).times do |index|
|
|
61
|
+
stage ^= (word >> index) & 1
|
|
62
|
+
register |= stage << (index + 1)
|
|
63
|
+
end
|
|
64
|
+
register
|
|
65
|
+
end
|
|
66
|
+
out.ints("dongle.registers", registers).int("dongle.latch", bytes[ARMED].zero? ? 0xff : 0x00)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -4,70 +4,96 @@ module Badline
|
|
|
4
4
|
module Snapshot
|
|
5
5
|
module Vice
|
|
6
6
|
module PET
|
|
7
|
-
# A true
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
7
|
+
# A true unit with an interface processor on device 8, as xpet 3.10,
|
|
8
|
+
# xcbm2 and xcbm5x0 save it with true drive emulation: an 8050, an
|
|
9
|
+
# 8250, an SFD-1001, a 4040, a 3040, a 2040, or a D9060 or D9090,
|
|
10
|
+
# which xpet's type 9000 stands for. Each is DRIVE8 2.0 with the
|
|
11
|
+
# unit's drives, DRIVE9 to DRIVE11 with none, DRIVECPU0 1.3, the
|
|
12
|
+
# interface processor and its RAM, RIOT1D0 and RIOT2D0 0.0, its two
|
|
13
|
+
# 6532s, and FDC0 0.0. xpet runs the floppy controller and the hard
|
|
14
|
+
# disk's SASI host at a high level, so their processors, VIAs and
|
|
15
|
+
# 6530s aren't in the snapshot: FDC0 holds the controller's state,
|
|
16
|
+
# its last track in byte 6.
|
|
14
17
|
#
|
|
15
|
-
# DRIVE8 holds a block of 139 bytes for each
|
|
16
|
-
# unit: each block has its head's half track, twice
|
|
17
|
-
# $10 and the
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
18
|
+
# DRIVE8 holds a block of 139 bytes for each of the unit's drives,
|
|
19
|
+
# then 6 for the unit: each block has its head's half track, twice
|
|
20
|
+
# the track, at $10 and the unit's type as a word at $28 (TYPES).
|
|
21
|
+
# The 1001 and the hard disks have one block, and a hard disk's head
|
|
22
|
+
# rests at HARD_DISK_TRACK. DRIVECPU0 is laid out as the 2031's
|
|
23
|
+
# (Drive2031), its RAM the IP's page 0, the 6532s' 128 bytes each,
|
|
24
|
+
# then the 4K of common RAM. A RIOT module holds port A's output and
|
|
25
|
+
# direction registers, port B's, the edge control (bit 0 the PA7
|
|
26
|
+
# interrupt, bit 1 a rising edge), the flags (bit 7 the timer's
|
|
27
|
+
# interrupt, which xpet raises IRQ for, bit 6 PA7's), the timer's
|
|
24
28
|
# counter, its divider as a word, two bytes xpet leaves 0, and
|
|
25
29
|
# whether the timer interrupts.
|
|
26
30
|
#
|
|
27
|
-
# Written, once the controller is in its idle
|
|
28
|
-
# instructions (PET#settle_for_vice!): the IP's
|
|
29
|
-
# the 6532s, the heads' tracks, and FDC0 as xpet
|
|
30
|
-
# controller with the track badline's controller last
|
|
31
|
-
# A unit whose controller is still busy is left out of
|
|
32
|
-
# modules. Read: the IP's registers and RAM and the 6532s,
|
|
33
|
-
# controller as a unit switched on has it in its idle loop,
|
|
34
|
-
# heads on track 1, from where its next job steps them. A job
|
|
35
|
-
# way in xpet's controller starts again from there. The disks
|
|
36
|
-
# the drives stay
|
|
31
|
+
# Written, once the controller, or the SASI host, is in its idle
|
|
32
|
+
# loop between instructions (PET#settle_for_vice!): the IP's
|
|
33
|
+
# registers and RAM, the 6532s, the heads' tracks, and FDC0 as xpet
|
|
34
|
+
# leaves an idle controller with the track badline's controller last
|
|
35
|
+
# stepped to. A unit whose controller is still busy is left out of
|
|
36
|
+
# xpet's modules. Read: the IP's registers and RAM and the 6532s,
|
|
37
|
+
# with the controller as a unit switched on has it in its idle loop,
|
|
38
|
+
# its heads on track 1, from where its next job steps them. A job
|
|
39
|
+
# under way in xpet's controller starts again from there. The disks
|
|
40
|
+
# in the drives stay, and a hard disk's image with them, which also
|
|
41
|
+
# says whether the unit is a D9060 or a D9090.
|
|
37
42
|
module Drive8050
|
|
38
43
|
UNIT = "DRIVE8"
|
|
39
44
|
CPU = Drive2031::CPU
|
|
40
45
|
RIOTS = %w[RIOT1D0 RIOT2D0].freeze
|
|
41
46
|
FDC = "FDC0"
|
|
42
47
|
NAMES = [UNIT, CPU, *RIOTS, FDC].freeze
|
|
43
|
-
|
|
44
|
-
#
|
|
45
|
-
|
|
48
|
+
# xpet's drive types by DRIVE8's type word, for the units written
|
|
49
|
+
# and read here.
|
|
50
|
+
TYPES = { 0x1f72 => "8050", 0x203a => "8250", 0x03e9 => "1001", 0x0fc8 => "4040", 0x0be0 => "3040",
|
|
51
|
+
0x07f8 => "2040", 0x2328 => "9060" }.freeze
|
|
52
|
+
# The type word each model is written with.
|
|
53
|
+
WORDS = TYPES.invert.merge("9090" => 0x2328).freeze
|
|
54
|
+
# The units that are hard disks, and the DOS 2.1 and DOS 1 units
|
|
55
|
+
# on the 4040's board.
|
|
56
|
+
HARD_DISKS = %w[9060 9090].freeze
|
|
57
|
+
DOS2_BOARD = %w[4040 3040 2040].freeze
|
|
58
|
+
# The drives each unit has, a block of DRIVE8 each.
|
|
59
|
+
DRIVE_COUNTS = { "8050" => 2, "8250" => 2, "1001" => 1, "4040" => 2, "3040" => 2, "2040" => 2, "9060" => 1,
|
|
60
|
+
"9090" => 1 }.freeze
|
|
61
|
+
# A drive's block in DRIVE8, and its fields.
|
|
62
|
+
BLOCK = 0x8b
|
|
46
63
|
HALF_TRACK = 0x10
|
|
47
64
|
TYPE = 0x28
|
|
48
|
-
|
|
65
|
+
# The half track xpet keeps a hard disk's head on.
|
|
66
|
+
HARD_DISK_TRACK = 0x98
|
|
67
|
+
# The unit's bytes after the drives' blocks.
|
|
68
|
+
TAIL = 6
|
|
49
69
|
# DRIVE8 as xpet saves an idle 8050, by the bytes that aren't 0,
|
|
50
|
-
# but for the type
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
70
|
+
# but for the type and the drive count at COUNT: the first drive's
|
|
71
|
+
# block, and from BLOCK on the second's with a byte past it.
|
|
72
|
+
IDLE = { 0x00 => 0x01, 0x02 => 0x01, 0x0e => 0x01, 0x0f => 0x01, 0x10 => 0x4c, 0x1a => 0x01, 0x20 => 0x55,
|
|
73
|
+
0x30 => 0x06, 0x6f => 0xcd, 0x70 => 0xab, 0x71 => 0x34, 0x72 => 0x12 }.freeze
|
|
74
|
+
IDLE_SECOND = { 0x0e => 0x01, 0x0f => 0x01, 0x10 => 0x24, 0x1a => 0x01, 0x20 => 0x55, 0x8f => 0x01 }.freeze
|
|
75
|
+
COUNT = 0x01
|
|
54
76
|
ZERO_PAGE = 0x80
|
|
55
77
|
COMMON = 0x1000
|
|
56
78
|
# FDC0 as xpet leaves an idle controller, and where the track goes.
|
|
57
79
|
FDC_IDLE = [0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00].freeze
|
|
58
80
|
FDC_TRACK = 6
|
|
59
81
|
# Where badline's controller keeps drive 0's track, in the 6530's
|
|
60
|
-
# RAM.
|
|
82
|
+
# RAM: the 8050's, and the 4040's in the low six bits.
|
|
61
83
|
TRACK_AT = 0x21
|
|
84
|
+
DOS2_TRACK_AT = 0x03
|
|
85
|
+
DOS2_TRACK = 0x3f
|
|
62
86
|
DIVIDERS = [1, 8, 64, 1024].freeze
|
|
63
87
|
IRQ_EDGE = 0x01
|
|
64
88
|
RISING = 0x02
|
|
65
89
|
TIMER_FLAG = 0x80
|
|
66
90
|
PA7_FLAG = 0x40
|
|
91
|
+
# The hard disk's controller, which holds the image's path.
|
|
92
|
+
SASI = "BL-D8-SASI"
|
|
67
93
|
|
|
68
94
|
module_function
|
|
69
95
|
|
|
70
|
-
# Whether the snapshot has a true
|
|
96
|
+
# Whether the snapshot has a true unit of these.
|
|
71
97
|
def present?(container) = !container[FDC].nil? && !container[CPU].nil?
|
|
72
98
|
|
|
73
99
|
def reads?(section)
|
|
@@ -78,48 +104,93 @@ module Badline
|
|
|
78
104
|
end
|
|
79
105
|
end
|
|
80
106
|
|
|
81
|
-
# The model DRIVE8 names, or nil.
|
|
107
|
+
# The model DRIVE8 names, or nil. Type 9000 reads as the D9060.
|
|
82
108
|
def model(container)
|
|
83
109
|
unit = container[UNIT]
|
|
84
|
-
return nil if unit.nil? || unit.data.bytesize <
|
|
110
|
+
return nil if unit.nil? || unit.data.bytesize < BLOCK
|
|
85
111
|
|
|
86
|
-
TYPES[FieldReader.new(unit).skip(TYPE).word]
|
|
112
|
+
model = TYPES[FieldReader.new(unit).skip(TYPE).word]
|
|
113
|
+
model if model && unit.data.bytesize >= size(model)
|
|
87
114
|
end
|
|
88
115
|
|
|
89
|
-
# xpet
|
|
90
|
-
|
|
91
|
-
|
|
116
|
+
# Whether xpet saves the two models as one type.
|
|
117
|
+
def same_type?(model, other) = WORDS.key?(model) && WORDS[model] == WORDS[other]
|
|
118
|
+
|
|
119
|
+
def hard_disk?(model) = HARD_DISKS.include?(model)
|
|
120
|
+
|
|
121
|
+
# The hard disk whose image the kept modules `disks` hold: a
|
|
122
|
+
# D9090 for one with six heads, and otherwise a D9060.
|
|
123
|
+
def hard_disk_model(disks)
|
|
124
|
+
own = disks.find { |section| section.name == SASI }
|
|
125
|
+
own && Keyed::Reader.parse(own).int("disk_heads", 4) == 6 ? "9090" : "9060"
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# DRIVE8's size for the model.
|
|
129
|
+
def size(model) = (BLOCK * DRIVE_COUNTS.fetch(model)) + TAIL
|
|
130
|
+
|
|
131
|
+
# xpet's modules for the unit whose BL-D8 modules `readers` holds,
|
|
132
|
+
# and none without one, or with its controller away from its idle
|
|
133
|
+
# loop.
|
|
92
134
|
def export(machine, readers)
|
|
93
135
|
drive = readers["BL-D8"]
|
|
94
136
|
model = drive&.text("model", "")
|
|
95
|
-
return [] unless
|
|
137
|
+
return [] unless WORDS.key?(model) && idle?(model, readers)
|
|
96
138
|
|
|
97
|
-
[unit(model, readers
|
|
139
|
+
[unit(model, readers), *Drive2031::UNITS.drop(1).map { |name| none(name) },
|
|
98
140
|
Drive2031.cpu_section(machine, readers.fetch("BL-D8-IPCPU"), ram(readers)),
|
|
99
141
|
riot(RIOTS[0], readers.fetch("BL-D8-RIOT1")), riot(RIOTS[1], readers.fetch("BL-D8-RIOT2")),
|
|
100
|
-
fdc(readers
|
|
142
|
+
fdc(model, readers)]
|
|
101
143
|
end
|
|
102
144
|
|
|
103
145
|
# Whether both processors are between instructions, the
|
|
104
146
|
# controller at the start of its idle loop.
|
|
105
|
-
def idle?(readers)
|
|
106
|
-
|
|
107
|
-
!position?(
|
|
108
|
-
|
|
147
|
+
def idle?(model, readers)
|
|
148
|
+
controller = readers.fetch(hard_disk?(model) ? "BL-D8-SASICPU" : "BL-D8-FDCCPU")
|
|
149
|
+
!position?(controller) && !position?(readers.fetch("BL-D8-IPCPU")) &&
|
|
150
|
+
controller.int("pc", 0) == controller_loop(model)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Where the model's controller, or its SASI host, waits for jobs.
|
|
154
|
+
def controller_loop(model)
|
|
155
|
+
case model
|
|
156
|
+
when "9060", "9090" then Drives::Model9060::Idle::SASI_LOOP
|
|
157
|
+
when "2040" then Drives::Model2040::FDC_LOOP
|
|
158
|
+
when "4040", "3040" then Drives::Model4040::FDC_LOOP
|
|
159
|
+
else Drives::Model8050::Idle::FDC_LOOP
|
|
160
|
+
end
|
|
109
161
|
end
|
|
110
162
|
|
|
111
163
|
def position?(cpu) = !cpu.text("pos.seq", "").empty?
|
|
112
164
|
|
|
113
|
-
def unit(model,
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
165
|
+
def unit(model, readers)
|
|
166
|
+
count = DRIVE_COUNTS.fetch(model)
|
|
167
|
+
bytes = Array.new(size(model), 0)
|
|
168
|
+
IDLE.each { |offset, value| bytes[offset] = value }
|
|
169
|
+
IDLE_SECOND.each { |offset, value| bytes[BLOCK + offset] = value } if count > 1
|
|
170
|
+
bytes[COUNT] = count
|
|
171
|
+
tracks = half_tracks(model, readers)
|
|
172
|
+
count.times do |drive|
|
|
173
|
+
at = BLOCK * drive
|
|
174
|
+
bytes[at + HALF_TRACK] = tracks[drive]
|
|
175
|
+
bytes[at + TYPE, 2] = [WORDS.fetch(model)].pack("v").bytes
|
|
119
176
|
end
|
|
120
177
|
FieldWriter.new.bytes(bytes).section(UNIT, Drive2031::DRIVE_MAJOR, Drive2031::DRIVE_MINOR)
|
|
121
178
|
end
|
|
122
179
|
|
|
180
|
+
# Each drive's head as xpet's half track: the 8050's cylinder on
|
|
181
|
+
# from 1, the 4040's half track on from track 1, and a hard
|
|
182
|
+
# disk's where xpet keeps it.
|
|
183
|
+
def half_tracks(model, readers)
|
|
184
|
+
return [HARD_DISK_TRACK] if hard_disk?(model)
|
|
185
|
+
|
|
186
|
+
mechanism = readers.fetch("BL-D8-MECH")
|
|
187
|
+
if DOS2_BOARD.include?(model)
|
|
188
|
+
mechanism.ints("half_tracks", [0, 0]).map { |half_track| half_track + 2 }
|
|
189
|
+
else
|
|
190
|
+
mechanism.ints("cylinders", [0, 0]).map { |cylinder| (cylinder + 1) * 2 }
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
123
194
|
def none(name) = Drive2031.unit(Drive2031::NONE, name)
|
|
124
195
|
|
|
125
196
|
# The IP's RAM as xpet lays it out: page 0 from both 6532s, then
|
|
@@ -143,16 +214,25 @@ module Badline
|
|
|
143
214
|
fields.zeros(2).flag(input.bool("timer.irq_enabled", false)).section(name, 0, 0)
|
|
144
215
|
end
|
|
145
216
|
|
|
146
|
-
|
|
217
|
+
# FDC0 with the controller's track, and a hard disk's with none.
|
|
218
|
+
def fdc(model, readers)
|
|
147
219
|
bytes = FDC_IDLE.dup
|
|
148
|
-
|
|
220
|
+
unless hard_disk?(model)
|
|
221
|
+
ram = readers.fetch("BL-D8-RRIOT").bytes("ram", "".b)
|
|
222
|
+
bytes[FDC_TRACK] = if DOS2_BOARD.include?(model)
|
|
223
|
+
ram.getbyte(DOS2_TRACK_AT).to_i & DOS2_TRACK
|
|
224
|
+
else
|
|
225
|
+
ram.getbyte(TRACK_AT).to_i
|
|
226
|
+
end
|
|
227
|
+
end
|
|
149
228
|
FieldWriter.new.bytes(bytes).section(FDC, 0, 0)
|
|
150
229
|
end
|
|
151
230
|
|
|
152
231
|
# The unit's keyed modules, named for device 8, from the
|
|
153
232
|
# snapshot's: the IP's side from xpet's, the controller's side
|
|
154
233
|
# from `reference`, a unit's in its idle loop, and `disks`, the
|
|
155
|
-
# drives' disk modules badline keeps
|
|
234
|
+
# drives' disk modules badline keeps, or a hard disk's controller
|
|
235
|
+
# with its image.
|
|
156
236
|
def import(container, reference, disks)
|
|
157
237
|
cpu = container[CPU]
|
|
158
238
|
page = FieldReader.new(cpu).skip(Drive2031::RAM_AT).string(ZERO_PAGE * 2)
|
|
@@ -162,16 +242,48 @@ module Badline
|
|
|
162
242
|
riot_section("BL-D8-RIOT1", container[RIOTS[0]], page.byteslice(0, ZERO_PAGE)),
|
|
163
243
|
riot_section("BL-D8-RIOT2", container[RIOTS[1]], page.byteslice(ZERO_PAGE, ZERO_PAGE)),
|
|
164
244
|
Keyed.section("BL-D8-IPCPU") { |out| Drive2031.registers(cpu, out) }]
|
|
165
|
-
sections + reference
|
|
245
|
+
sections + controller_side(reference, disks)
|
|
166
246
|
end
|
|
167
247
|
|
|
168
|
-
# The controller's side, which comes from a unit in its idle loop
|
|
248
|
+
# The controller's side, which comes from a unit in its idle loop:
|
|
249
|
+
# a floppy unit's, and a hard disk's SASI host.
|
|
169
250
|
CONTROLLER = %w[BL-D8-FDCCPU BL-D8-VIA BL-D8-RRIOT BL-D8-MECH].freeze
|
|
251
|
+
HOST = %w[BL-D8-SASICPU BL-D8-SASIRAM BL-D8-VIA].freeze
|
|
252
|
+
|
|
253
|
+
def controller_side(reference, disks)
|
|
254
|
+
base = reference.find { |section| section.name == SASI }
|
|
255
|
+
return reference.select { |section| CONTROLLER.include?(section.name) } + disks if base.nil?
|
|
256
|
+
|
|
257
|
+
reference.select { |section| HOST.include?(section.name) } + [controller(base, disks)]
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# The hard disk's controller as `base` has it, with the image
|
|
261
|
+
# badline's kept in `disks`.
|
|
262
|
+
def controller(base, disks)
|
|
263
|
+
kept = disks.find { |section| section.name == SASI }
|
|
264
|
+
return base if kept.nil?
|
|
170
265
|
|
|
266
|
+
target = Drives::Model9060::SASITarget.new
|
|
267
|
+
target.load_fields(Keyed::Reader.parse(base))
|
|
268
|
+
own = Keyed::Reader.parse(kept)
|
|
269
|
+
path = own.text("path", "")
|
|
270
|
+
if File.file?(path)
|
|
271
|
+
target.disk = Storage::D90Image.new(path, read_only: own.bool("read_only", false),
|
|
272
|
+
heads: own.int("disk_heads", 4))
|
|
273
|
+
end
|
|
274
|
+
Keyed.section(SASI) { |out| target.save_fields(out) }
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# The unit's own fields: its model and clock, with the controller's
|
|
278
|
+
# last byte from `reference`, or a hard disk's SASI lines.
|
|
171
279
|
def unit_fields(container, reference, out)
|
|
172
280
|
own = Keyed::Reader.parse(reference.find { |section| section.name == "BL-D8" })
|
|
173
|
-
|
|
174
|
-
out.
|
|
281
|
+
model = own.text("model", "8050")
|
|
282
|
+
out.text("model", model).int("phase", 0).int("cycles", FieldReader.new(container[CPU]).qword)
|
|
283
|
+
return out.int("fdc_data", own.int("fdc_data", 0)) unless hard_disk?(model)
|
|
284
|
+
|
|
285
|
+
out.int("sasi_data", own.int("sasi_data", 0)).bool("sasi.ack_high", own.bool("sasi.ack_high", true))
|
|
286
|
+
out.bool("sasi.reset_high", own.bool("sasi.reset_high", false))
|
|
175
287
|
end
|
|
176
288
|
|
|
177
289
|
def riot_section(name, section, ram)
|
|
@@ -199,15 +311,23 @@ module Badline
|
|
|
199
311
|
end
|
|
200
312
|
|
|
201
313
|
def booted(model)
|
|
202
|
-
unit = model
|
|
203
|
-
|
|
204
|
-
unit.cycle! until
|
|
314
|
+
unit = new_unit(model)
|
|
315
|
+
unit.boot_cycles.times { unit.host_cycle! }
|
|
316
|
+
unit.cycle! until unit.settled_for_vice?
|
|
205
317
|
unit.save_modules([], "BL-D8")
|
|
206
318
|
end
|
|
207
319
|
|
|
208
|
-
def
|
|
209
|
-
|
|
210
|
-
|
|
320
|
+
def new_unit(model)
|
|
321
|
+
case model
|
|
322
|
+
when "8250" then Drives::Model8250.new
|
|
323
|
+
when "1001" then Drives::Model1001.new
|
|
324
|
+
when "4040" then Drives::Model4040.new
|
|
325
|
+
when "3040" then Drives::Model3040.new
|
|
326
|
+
when "2040" then Drives::Model2040.new
|
|
327
|
+
when "9060" then Drives::Model9060.new
|
|
328
|
+
when "9090" then Drives::Model9090.new
|
|
329
|
+
else Drives::Model8050.new
|
|
330
|
+
end
|
|
211
331
|
end
|
|
212
332
|
end
|
|
213
333
|
end
|