badline 0.16.1 → 0.18.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 +213 -0
- data/CLAUDE.md +11 -7
- data/CONTRIBUTING.md +7 -1
- data/README.md +265 -26
- data/doc/media.md +5 -2
- data/doc/pinned-behaviour.md +189 -0
- data/doc/snapshot-format.md +616 -74
- data/doc/snapshots.md +192 -24
- data/exe/badline-ruby +5 -0
- data/lib/badline/audio/terminal.rb +34 -2
- data/lib/badline/c128/keyed_state.rb +2 -0
- data/lib/badline/c128.rb +1 -0
- data/lib/badline/c64/keyed_state.rb +2 -0
- data/lib/badline/c64.rb +1 -0
- data/lib/badline/cbm2/acia.rb +10 -0
- data/lib/badline/cbm2/bus.rb +263 -0
- data/lib/badline/cbm2/cpu.rb +58 -0
- data/lib/badline/cbm2/crtc_video.rb +133 -0
- data/lib/badline/cbm2/ieee_drive.rb +18 -0
- data/lib/badline/cbm2/ieee_layout.rb +69 -0
- data/lib/badline/cbm2/ieee_ports.rb +104 -0
- data/lib/badline/cbm2/ieee_traps.rb +81 -0
- data/lib/badline/cbm2/keyboard_ports.rb +60 -0
- data/lib/badline/cbm2/keyed_modules.rb +67 -0
- data/lib/badline/cbm2/keyed_state.rb +95 -0
- data/lib/badline/cbm2/model.rb +44 -0
- data/lib/badline/cbm2/p500/control_ports.rb +80 -0
- data/lib/badline/cbm2/p500/ieee_layout.rb +41 -0
- data/lib/badline/cbm2/p500/keyed_state.rb +85 -0
- data/lib/badline/cbm2/p500/model.rb +39 -0
- data/lib/badline/cbm2/p500/pages.rb +57 -0
- data/lib/badline/cbm2/p500.rb +264 -0
- data/lib/badline/cbm2/sid_page.rb +19 -0
- data/lib/badline/cbm2.rb +270 -0
- data/lib/badline/{plus4 → chips}/acia/frames.rb +1 -1
- data/lib/badline/chips/acia/keyed_state.rb +47 -0
- data/lib/badline/chips/acia.rb +307 -0
- data/lib/badline/chips/cia/timer.rb +2 -2
- data/lib/badline/chips/cpu/instruction_set.rb +1 -1
- data/lib/badline/chips/crtc.rb +3 -2
- 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/fast_forward.rb +72 -0
- data/lib/badline/chips/riot/keyed_parts.rb +69 -0
- data/lib/badline/chips/riot/timer.rb +91 -0
- data/lib/badline/chips/riot.rb +162 -0
- data/lib/badline/chips/rriot/keyed_state.rb +30 -0
- data/lib/badline/chips/rriot.rb +134 -0
- data/lib/badline/chips/sid/filter.rb +4 -4
- data/lib/badline/chips/sid/waveform.rb +6 -6
- data/lib/badline/chips/tpi/keyed_state.rb +38 -0
- data/lib/badline/chips/tpi.rb +233 -0
- data/lib/badline/chips/vic/bank.rb +60 -5
- data/lib/badline/chips/vic/sprite.rb +4 -3
- data/lib/badline/chips/vic_i/keyed_parts.rb +7 -2
- data/lib/badline/chips/vic_i.rb +84 -21
- data/lib/badline/data_path.rb +3 -3
- data/lib/badline/drives/datasette/keyed_state.rb +9 -1
- data/lib/badline/drives/datasette.rb +27 -3
- data/lib/badline/drives/ieee_models.rb +54 -0
- data/lib/badline/drives/model1001.rb +37 -0
- data/lib/badline/drives/model2031.rb +6 -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 +192 -0
- data/lib/badline/drives/model4040/parts.rb +20 -0
- data/lib/badline/drives/model4040.rb +179 -0
- data/lib/badline/drives/model8050/board.rb +77 -0
- data/lib/badline/drives/model8050/disk.rb +163 -0
- data/lib/badline/drives/model8050/dos_board.rb +91 -0
- data/lib/badline/drives/model8050/fdc_bus.rb +102 -0
- data/lib/badline/drives/model8050/idle.rb +181 -0
- data/lib/badline/drives/model8050/ieee_port.rb +147 -0
- data/lib/badline/drives/model8050/ip_bus.rb +93 -0
- data/lib/badline/drives/model8050/keyed_state.rb +163 -0
- data/lib/badline/drives/model8050/mechanism.rb +230 -0
- data/lib/badline/drives/model8050/parts.rb +37 -0
- data/lib/badline/drives/model8050.rb +131 -0
- data/lib/badline/drives/model9060/idle.rb +149 -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 +195 -0
- data/lib/badline/frontend/app.rb +18 -3
- data/lib/badline/frontend/boot.rb +4 -3
- data/lib/badline/frontend/controls.rb +107 -15
- data/lib/badline/frontend/gamepads.rb +3 -3
- data/lib/badline/frontend/keys.rb +97 -2
- 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 +47 -14
- data/lib/badline/frontend/menu/menu_pages.rb +113 -4
- data/lib/badline/frontend/menu/menu_ports.rb +77 -4
- data/lib/badline/frontend/menu/pause_menu.rb +6 -2
- data/lib/badline/frontend/pet_keyboard.rb +45 -7
- 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 +49 -11
- data/lib/badline/frontend.rb +3 -0
- data/lib/badline/kernal_trap/dos/disk_commands.rb +80 -0
- data/lib/badline/kernal_trap/dos/status.rb +3 -0
- data/lib/badline/kernal_trap/dos.rb +18 -5
- data/lib/badline/kernal_trap/ieee.rb +4 -2
- data/lib/badline/kernal_trap/ieee_layout.rb +95 -43
- 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 +116 -0
- data/lib/badline/kim1/teletype.rb +193 -0
- data/lib/badline/kim1.rb +190 -0
- data/lib/badline/machine/ieee_drives.rb +171 -0
- data/lib/badline/machine/keyboard_buffer.rb +20 -3
- data/lib/badline/machine/line_sound.rb +122 -0
- data/lib/badline/machine/settling.rb +4 -0
- data/lib/badline/machine.rb +62 -14
- data/lib/badline/media/cbm2_media.rb +29 -0
- 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/program.rb +6 -3
- data/lib/badline/media/true_drive.rb +51 -25
- data/lib/badline/media.rb +23 -8
- data/lib/badline/options/family.rb +108 -6
- data/lib/badline/options/help.rb +58 -12
- data/lib/badline/options/table.rb +60 -14
- data/lib/badline/options/validation.rb +71 -11
- data/lib/badline/options.rb +46 -13
- data/lib/badline/pet/bus.rb +16 -2
- data/lib/badline/pet/cassettes.rb +22 -1
- data/lib/badline/pet/ieee_drive.rb +5 -64
- data/lib/badline/pet/ieee_ports.rb +7 -0
- 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 +81 -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 +216 -0
- data/lib/badline/pet.rb +33 -6
- data/lib/badline/plus4/acia.rb +4 -298
- data/lib/badline/plus4/keyed_parts.rb +0 -44
- data/lib/badline/plus4/keyed_state.rb +2 -0
- data/lib/badline/plus4.rb +2 -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/8050/dos-2.7.rom +0 -0
- data/lib/badline/roms/8050/fdc-901869-01.rom +0 -0
- data/lib/badline/roms/8050/fdc-901885-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 +277 -0
- data/lib/badline/roms/cbm2/basic128-02b.rom +0 -0
- data/lib/badline/roms/cbm2/basic128.rom +0 -0
- data/lib/badline/roms/cbm2/basic256.rom +0 -0
- data/lib/badline/roms/cbm2/characters-600.rom +0 -0
- data/lib/badline/roms/cbm2/characters-700.rom +0 -0
- data/lib/badline/roms/cbm2/kernal-03b.rom +0 -0
- data/lib/badline/roms/cbm2/kernal-04a.rom +0 -0
- data/lib/badline/roms/cbm2/p500-basic.rom +0 -0
- data/lib/badline/roms/cbm2/p500-kernal.rom +0 -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/cbm2_setup.rb +53 -0
- data/lib/badline/snapshot/container.rb +9 -2
- data/lib/badline/snapshot/field_doc/markdown.rb +4 -2
- data/lib/badline/snapshot/field_doc.rb +59 -3
- data/lib/badline/snapshot/image.rb +65 -9
- 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/cbm2.rb +93 -0
- data/lib/badline/snapshot/vice/cbm2_acia.rb +75 -0
- data/lib/badline/snapshot/vice/cbm2_crtc.rb +127 -0
- data/lib/badline/snapshot/vice/cbm2_mains.rb +49 -0
- data/lib/badline/snapshot/vice/cbm2_mem.rb +75 -0
- data/lib/badline/snapshot/vice/cbm2_restore.rb +204 -0
- data/lib/badline/snapshot/vice/cbm2_tpi.rb +58 -0
- data/lib/badline/snapshot/vice/cias.rb +13 -9
- data/lib/badline/snapshot/vice/p500.rb +96 -0
- data/lib/badline/snapshot/vice/p500_restore.rb +130 -0
- data/lib/badline/snapshot/vice/p500_vicii.rb +166 -0
- data/lib/badline/snapshot/vice/pet.rb +20 -10
- data/lib/badline/snapshot/vice/pet_cpu.rb +42 -5
- data/lib/badline/snapshot/vice/pet_crtc.rb +25 -17
- data/lib/badline/snapshot/vice/pet_drive.rb +180 -0
- data/lib/badline/snapshot/vice/pet_drive8050.rb +336 -0
- data/lib/badline/snapshot/vice/pet_mem.rb +49 -5
- data/lib/badline/snapshot/vice/pet_restore.rb +100 -7
- data/lib/badline/snapshot/vice/pet_via.rb +6 -5
- data/lib/badline/snapshot/vice/sid_registers.rb +2 -1
- data/lib/badline/snapshot/vice/vicii_import.rb +10 -6
- data/lib/badline/snapshot/vice.rb +3 -0
- data/lib/badline/snapshot.rb +15 -3
- data/lib/badline/status.rb +30 -30
- data/lib/badline/storage/crt_file.rb +7 -1
- data/lib/badline/storage/d64_image.rb +7 -0
- data/lib/badline/storage/d67_image.rb +55 -0
- data/lib/badline/storage/d80_image.rb +17 -1
- data/lib/badline/storage/d81_image.rb +14 -0
- data/lib/badline/storage/d90_image.rb +180 -0
- data/lib/badline/storage/disk_image/bam.rb +18 -3
- data/lib/badline/storage/disk_image/formatting.rb +69 -0
- data/lib/badline/storage/disk_image/writing.rb +37 -2
- data/lib/badline/storage/disk_image.rb +2 -0
- data/lib/badline/storage/kim_tape.rb +254 -0
- data/lib/badline/storage/papertape.rb +90 -0
- data/lib/badline/storage.rb +5 -0
- data/lib/badline/support/cbm2_checkpoint.rb +48 -0
- data/lib/badline/support/kim1_checkpoint.rb +41 -0
- data/lib/badline/support/p500_checkpoint.rb +35 -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.rb +26 -12
- data/lib/badline.rb +2 -0
- metadata +148 -2
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Drives
|
|
5
|
+
class Model8050
|
|
6
|
+
# Sleeping through the two processors' idle loops, exactly.
|
|
7
|
+
#
|
|
8
|
+
# With nothing to do, the IP goes round its DOS's idle loop from
|
|
9
|
+
# @ip_loop, and the FDC round its job loop from @fdc_loop (IP_LOOP and
|
|
10
|
+
# FDC_LOOP on the 8050), each pass finding the job queue empty, until
|
|
11
|
+
# ATN interrupts the IP or the 6530's timer the FDC, every 5 ms on the
|
|
12
|
+
# 8050. A pass puts back what it found,
|
|
13
|
+
# so each processor comes back to its loop's start as it left it, and
|
|
14
|
+
# only the chips' counters and the cycle counts move.
|
|
15
|
+
#
|
|
16
|
+
# Each time a processor comes to its loop's start, the unit compares
|
|
17
|
+
# what that processor sees with what it saw last time round: the CPU
|
|
18
|
+
# (Engine::IdleCPU#idle_state), its chips but for their counters, its
|
|
19
|
+
# RAM and the common RAM, and on the FDC's side the drives. The same,
|
|
20
|
+
# with no read of a counter or an interrupt flag between (the buses'
|
|
21
|
+
# volatile), makes the pass repeatable. Once both processors have a
|
|
22
|
+
# repeatable pass, with the motors off, no head stepping, no disk
|
|
23
|
+
# going in or out and no interrupt pulled, the unit sleeps:
|
|
24
|
+
# host_cycle! only counts the cycles it owes, until one of the chips'
|
|
25
|
+
# counters is due to pull IRQ (quiet_cycles), the controller moves a
|
|
26
|
+
# line of the bus, or something outside reads or changes the unit
|
|
27
|
+
# (settle!).
|
|
28
|
+
#
|
|
29
|
+
# Waking runs the counters on in bulk, counts off each processor's
|
|
30
|
+
# whole passes, and runs the rest of a pass on that processor alone.
|
|
31
|
+
# Its passes touch nothing the other one or the counters move, so the
|
|
32
|
+
# order the two run in doesn't matter. Then the unit runs cycle by
|
|
33
|
+
# cycle again. Woken by a counter, it keeps the passes it found, and
|
|
34
|
+
# sleeps again as soon as both repeat: the IP's, which the timer's
|
|
35
|
+
# interrupt doesn't reach, at once, and the FDC's a pass after its
|
|
36
|
+
# interrupt. Woken from outside, it finds both afresh.
|
|
37
|
+
module Idle
|
|
38
|
+
IP_LOOP = 0xc5a1
|
|
39
|
+
FDC_LOOP = 0xfc17
|
|
40
|
+
|
|
41
|
+
# Whether the unit may sleep through its idle loops.
|
|
42
|
+
attr_reader :idle_skip
|
|
43
|
+
|
|
44
|
+
def idle_skip=(on)
|
|
45
|
+
settle!
|
|
46
|
+
@idle_skip = on
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def asleep? = @asleep
|
|
50
|
+
|
|
51
|
+
# Brings the unit up to the present, cycle for cycle, and drops the
|
|
52
|
+
# passes it found, since whoever called may change it.
|
|
53
|
+
def settle!
|
|
54
|
+
wake! if @asleep
|
|
55
|
+
forget_passes
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
# The unit's loops start at +ip_loop+ and +fdc_loop+.
|
|
61
|
+
def init_idle(ip_loop, fdc_loop)
|
|
62
|
+
@ip_loop = ip_loop
|
|
63
|
+
@fdc_loop = fdc_loop
|
|
64
|
+
@idle_skip = true
|
|
65
|
+
@asleep = false
|
|
66
|
+
@owed = 0
|
|
67
|
+
@budget = 0
|
|
68
|
+
forget_passes
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def forget_passes
|
|
72
|
+
@ip_mark = nil
|
|
73
|
+
@fdc_mark = nil
|
|
74
|
+
@ip_pass = nil
|
|
75
|
+
@fdc_pass = nil
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# A cycle owed while asleep, which wakes the unit once the budget
|
|
79
|
+
# is spent.
|
|
80
|
+
def owe_cycle
|
|
81
|
+
@owed += 1
|
|
82
|
+
wake! if @owed >= @budget
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Looks for the loops' starts after a cycle run awake. An interrupt
|
|
86
|
+
# pulled breaks the processor's pass.
|
|
87
|
+
def watch_loops
|
|
88
|
+
ip = @ip_cpu
|
|
89
|
+
@ip_pass = nil if ip.irq
|
|
90
|
+
@fdc_pass = nil if @fdc_cpu.irq
|
|
91
|
+
ip_pass_found if ip.program_counter == @ip_loop && ip.boundary?
|
|
92
|
+
fdc = @fdc_cpu
|
|
93
|
+
fdc_pass_found if fdc.program_counter == @fdc_loop && fdc.boundary?
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def ip_pass_found
|
|
97
|
+
state = ip_state
|
|
98
|
+
@ip_pass = repeated(@ip_mark, state, @ip_cpu, @ip_bus.volatile)
|
|
99
|
+
@ip_mark = [state, @ip_cpu.cycles, @ip_cpu.instructions]
|
|
100
|
+
@ip_bus.volatile = false
|
|
101
|
+
fall_asleep if @ip_pass && @fdc_pass
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def fdc_pass_found
|
|
105
|
+
state = fdc_state
|
|
106
|
+
@fdc_pass = repeated(@fdc_mark, state, @fdc_cpu, @fdc_bus.volatile)
|
|
107
|
+
@fdc_mark = [state, @fdc_cpu.cycles, @fdc_cpu.instructions]
|
|
108
|
+
@fdc_bus.volatile = false
|
|
109
|
+
fall_asleep if @ip_pass && @fdc_pass
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# The pass since +mark+ as [cycles, instructions] if it left the
|
|
113
|
+
# processor as it found it, or nil.
|
|
114
|
+
def repeated(mark, state, cpu, volatile)
|
|
115
|
+
return nil if mark.nil? || volatile || mark[0] != state
|
|
116
|
+
|
|
117
|
+
[cpu.cycles - mark[1], cpu.instructions - mark[2]]
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def fall_asleep
|
|
121
|
+
return unless @mechanism.quiet? && !@ip_cpu.irq && !@fdc_cpu.irq
|
|
122
|
+
|
|
123
|
+
budget = quiet_cycles
|
|
124
|
+
return if budget < 2
|
|
125
|
+
|
|
126
|
+
@asleep = true
|
|
127
|
+
@owed = 0
|
|
128
|
+
@budget = budget
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# How many cycles the chips can run with no counter pulling IRQ.
|
|
132
|
+
def quiet_cycles
|
|
133
|
+
[@data_riot.quiet_cycles, @control_riot.quiet_cycles, @rriot.quiet_cycles, @via.quiet_cycles].min
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Runs the cycles owed: the counters in bulk, then each processor's
|
|
137
|
+
# whole passes and the rest of a pass.
|
|
138
|
+
def wake!
|
|
139
|
+
owed = @owed
|
|
140
|
+
@asleep = false
|
|
141
|
+
@owed = 0
|
|
142
|
+
return if owed.zero?
|
|
143
|
+
|
|
144
|
+
@data_riot.fast_forward(owed)
|
|
145
|
+
@control_riot.fast_forward(owed)
|
|
146
|
+
@rriot.fast_forward(owed)
|
|
147
|
+
@via.fast_forward(owed)
|
|
148
|
+
skip(@ip_cpu, @ip_pass, @ip_mark, owed)
|
|
149
|
+
skip(@fdc_cpu, @fdc_pass, @fdc_mark, owed)
|
|
150
|
+
@cycles += owed
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Counts off the processor's whole passes, moving its mark on with
|
|
154
|
+
# them, and runs the rest on the processor alone.
|
|
155
|
+
def skip(cpu, pass, mark, owed)
|
|
156
|
+
passes = owed / pass[0]
|
|
157
|
+
cpu.fast_forward(passes * pass[0], passes * pass[1])
|
|
158
|
+
mark[1] += passes * pass[0]
|
|
159
|
+
mark[2] += passes * pass[1]
|
|
160
|
+
(owed - (passes * pass[0])).times { cpu.cycle! }
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# What the IP sees: its CPU, its RIOTs but for their counters, its
|
|
164
|
+
# bus's last byte and the common RAM, as the count of the writes
|
|
165
|
+
# that changed it.
|
|
166
|
+
def ip_state
|
|
167
|
+
[*@ip_cpu.idle_state, *@data_riot.idle_state, *@control_riot.idle_state, @ip_bus.data, common_changes]
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# What the FDC sees: its CPU, the VIA and the 6530 but for their
|
|
171
|
+
# counters, its bus's last byte, the drives and the common RAM.
|
|
172
|
+
def fdc_state
|
|
173
|
+
[*@fdc_cpu.idle_state, *@via.idle_state, *@rriot.idle_state, @fdc_bus.data, *@mechanism.idle_state,
|
|
174
|
+
common_changes]
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def common_changes = @ip_bus.common_changes + @fdc_bus.common_changes
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Drives
|
|
5
|
+
class Model8050
|
|
6
|
+
# The interface processor's two 6532s on the IEEE-488 bus
|
|
7
|
+
# (Drives::IEEEBus), through MC3446 transceivers (schematic 8050001,
|
|
8
|
+
# sheet 1). UC1 carries the data lines, its port A reading them and
|
|
9
|
+
# its port B driving them. UE1 carries the rest:
|
|
10
|
+
#
|
|
11
|
+
# PA0 ATN acknowledge (ATNA) PB0-2 the device number jumpers
|
|
12
|
+
# PA1 NDAC out, low while set PB3 drive 1's LED
|
|
13
|
+
# PA2 NRFD out PB4 drive 0's LED
|
|
14
|
+
# PA3 EOI out PB5 the error LED
|
|
15
|
+
# PA4 DAV out PB6 NDAC in
|
|
16
|
+
# PA5 EOI in PB7 NRFD in
|
|
17
|
+
# PA6 DAV in
|
|
18
|
+
# PA7 ATN in, high while ATN is low
|
|
19
|
+
#
|
|
20
|
+
# The ports read and drive the lines' levels, 0 for a low line, but
|
|
21
|
+
# for NDAC out, which pulls NDAC low while set. The DOS sets it as it
|
|
22
|
+
# waits for a byte and clears it once it has taken one ($C627-$C650).
|
|
23
|
+
# Every input reads the bus, the drive's own lines included.
|
|
24
|
+
#
|
|
25
|
+
# ATN in also reaches UE1's PA7 edge detector, which the DOS arms for
|
|
26
|
+
# the rising edge ($C58A), so ATN interrupts the interface processor.
|
|
27
|
+
# While ATN in and ATNA differ, the board pulls NRFD and NDAC low, so
|
|
28
|
+
# the drive answers ATN before the DOS gets to it, as the 2031 does.
|
|
29
|
+
#
|
|
30
|
+
# The device number jumpers ground PB0-2: cutting one adds its weight
|
|
31
|
+
# to 8.
|
|
32
|
+
#
|
|
33
|
+
# The drive takes the controller's lines a host cycle late, as the
|
|
34
|
+
# 2031 does: latch_host takes them at the end of each host cycle.
|
|
35
|
+
class IEEEPort
|
|
36
|
+
ATNA = 0x01
|
|
37
|
+
NDAC_OUT = 0x02
|
|
38
|
+
NRFD_OUT = 0x04
|
|
39
|
+
EOI_OUT = 0x08
|
|
40
|
+
DAV_OUT = 0x10
|
|
41
|
+
EOI_IN = 0x20
|
|
42
|
+
DAV_IN = 0x40
|
|
43
|
+
ATN_IN = 0x80
|
|
44
|
+
NDAC_IN = 0x40
|
|
45
|
+
NRFD_IN = 0x80
|
|
46
|
+
|
|
47
|
+
attr_reader :bus
|
|
48
|
+
|
|
49
|
+
# The lines the controller pulled, as latch_host took them.
|
|
50
|
+
attr_accessor :host
|
|
51
|
+
|
|
52
|
+
# The RIOTs on the data lines and on the control lines.
|
|
53
|
+
attr_accessor :data_riot, :control_riot
|
|
54
|
+
|
|
55
|
+
def initialize(device:, bus:)
|
|
56
|
+
raise ArgumentError, "an 8050 is device 8 to 15, not #{device}" unless device.between?(8, 15)
|
|
57
|
+
|
|
58
|
+
@jumpers = (device - 8) | 0xf8
|
|
59
|
+
@host = 0
|
|
60
|
+
@data_riot = nil
|
|
61
|
+
@control_riot = nil
|
|
62
|
+
self.bus = bus
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def bus=(bus)
|
|
66
|
+
@bus = bus
|
|
67
|
+
latch_host
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Takes the controller's lines for the drive cycles of the next host
|
|
71
|
+
# cycle.
|
|
72
|
+
def latch_host
|
|
73
|
+
@host = @bus.host_lines
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Whether the controller has moved ATN since the last latch_host.
|
|
77
|
+
def atn_moved? = (@bus.host_lines ^ @host).anybits?(IEEEBus::ATN)
|
|
78
|
+
|
|
79
|
+
# Whether the controller has moved any line since the last
|
|
80
|
+
# latch_host.
|
|
81
|
+
def lines_moved? = @bus.host_lines != @host
|
|
82
|
+
|
|
83
|
+
def atn_low? = @host.anybits?(IEEEBus::ATN)
|
|
84
|
+
|
|
85
|
+
# UC1's port A: the data lines.
|
|
86
|
+
def data_lines = ~@bus.low_lines(@host) & 0xff
|
|
87
|
+
|
|
88
|
+
# UE1's port A inputs. ATN in comes through the edge detector's own
|
|
89
|
+
# pin (RIOT#pa7=), so bit 7 is left high here.
|
|
90
|
+
def control_a
|
|
91
|
+
low = @bus.low_lines(@host)
|
|
92
|
+
value = 0xff
|
|
93
|
+
value &= ~EOI_IN if low.anybits?(IEEEBus::EOI)
|
|
94
|
+
value &= ~DAV_IN if low.anybits?(IEEEBus::DAV)
|
|
95
|
+
value
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# UE1's port B inputs: the jumpers, NDAC and NRFD.
|
|
99
|
+
def control_b
|
|
100
|
+
low = @bus.low_lines(@host)
|
|
101
|
+
value = @jumpers
|
|
102
|
+
value &= ~NDAC_IN if low.anybits?(IEEEBus::NDAC)
|
|
103
|
+
value &= ~NRFD_IN if low.anybits?(IEEEBus::NRFD)
|
|
104
|
+
value
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# The lines the drive pulls low while ATN is low or not, as bus bits.
|
|
108
|
+
def ieee_low_lines(atn)
|
|
109
|
+
control = @control_riot.port_a_output
|
|
110
|
+
low = ~@data_riot.port_b_output & IEEEBus::DIO
|
|
111
|
+
low |= IEEEBus::EOI if control.nobits?(EOI_OUT)
|
|
112
|
+
low |= IEEEBus::DAV if control.nobits?(DAV_OUT)
|
|
113
|
+
low |= IEEEBus::NRFD if control.nobits?(NRFD_OUT)
|
|
114
|
+
low |= IEEEBus::NDAC if control.anybits?(NDAC_OUT)
|
|
115
|
+
low |= IEEEBus::NRFD | IEEEBus::NDAC if atn != control.anybits?(ATNA)
|
|
116
|
+
low
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Which LEDs UE1 lights: bit 0 drive 1's, bit 1 drive 0's, bit 2 the
|
|
120
|
+
# error LED.
|
|
121
|
+
def leds = (@control_riot.port_b_output >> 3) & 0x07
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# UC1's peripheral: the data lines on port A, port B only driving.
|
|
125
|
+
class DataLines
|
|
126
|
+
def initialize(port)
|
|
127
|
+
@port = port
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def read_a(_lines) = @port.data_lines
|
|
131
|
+
|
|
132
|
+
def read_b(_lines) = 0xff
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# UE1's peripheral: the control lines and the jumpers.
|
|
136
|
+
class ControlLines
|
|
137
|
+
def initialize(port)
|
|
138
|
+
@port = port
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def read_a(_lines) = @port.control_a
|
|
142
|
+
|
|
143
|
+
def read_b(_lines) = @port.control_b
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Drives
|
|
5
|
+
class Model8050
|
|
6
|
+
# The interface processor's bus (schematic 8050001, sheet 1). A
|
|
7
|
+
# 74LS42 on A12-A15 picks a 4 KB block:
|
|
8
|
+
#
|
|
9
|
+
# $0000-$0FFF - the two 6532s. A9 is their RS pin and A7 picks one:
|
|
10
|
+
# UC1's RAM at $00-$7F and UE1's at $80-$FF, mirrored at
|
|
11
|
+
# $0100 for the stack since A8 isn't decoded, and their
|
|
12
|
+
# registers at $0200 (UC1) and $0280 (UE1)
|
|
13
|
+
# $1000-$4FFF - the common RAM, 1 KB in each block, mirrored through it
|
|
14
|
+
# $5000-$BFFF - nothing: open bus
|
|
15
|
+
# $C000-$FFFF - DOS 2.7, 901887-01 and 901888-01
|
|
16
|
+
#
|
|
17
|
+
# Writes to the ROM and to open bus go nowhere, and a read from open
|
|
18
|
+
# bus finds the last byte on the data bus.
|
|
19
|
+
class IPBus
|
|
20
|
+
include Addressable
|
|
21
|
+
|
|
22
|
+
attr_reader :common, :rom, :data_riot, :control_riot
|
|
23
|
+
attr_accessor :data
|
|
24
|
+
|
|
25
|
+
# How many writes have changed a byte of the common RAM
|
|
26
|
+
# (Model8050::Idle).
|
|
27
|
+
attr_reader :common_changes
|
|
28
|
+
|
|
29
|
+
# Whether a timer or the interrupt flags have been read since it was
|
|
30
|
+
# last cleared (Model8050::Idle).
|
|
31
|
+
attr_accessor :volatile
|
|
32
|
+
|
|
33
|
+
def initialize(rom:, common:, data_riot:, control_riot:)
|
|
34
|
+
addressable_at(0, length: 2**16)
|
|
35
|
+
@rom = rom
|
|
36
|
+
@common = common
|
|
37
|
+
@data_riot = data_riot
|
|
38
|
+
@control_riot = control_riot
|
|
39
|
+
@data = 0
|
|
40
|
+
@volatile = false
|
|
41
|
+
@common_changes = 0
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def peek(addr)
|
|
45
|
+
return @data = @rom.peek(addr) if addr >= 0xc000
|
|
46
|
+
|
|
47
|
+
@data = if addr < 0x1000
|
|
48
|
+
peek_riots(addr)
|
|
49
|
+
elsif addr < 0x5000
|
|
50
|
+
@common.peek((((addr >> 12) - 1) << 10) | (addr & 0x03ff))
|
|
51
|
+
else
|
|
52
|
+
@data
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def poke(addr, value)
|
|
57
|
+
@data = value
|
|
58
|
+
return if addr >= 0x5000
|
|
59
|
+
|
|
60
|
+
if addr < 0x1000
|
|
61
|
+
poke_riots(addr, value)
|
|
62
|
+
else
|
|
63
|
+
poke_common((((addr >> 12) - 1) << 10) | (addr & 0x03ff), value)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def poke_common(index, value)
|
|
70
|
+
@common_changes += 1 if @common.peek(index) != value
|
|
71
|
+
@common.poke(index, value)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def peek_riots(addr)
|
|
75
|
+
@volatile = true if addr & 0x204 == 0x204
|
|
76
|
+
if addr.anybits?(0x80)
|
|
77
|
+
addr.anybits?(0x200) ? @control_riot.peek(addr & 0x1f) : @control_riot.read_ram(addr)
|
|
78
|
+
else
|
|
79
|
+
addr.anybits?(0x200) ? @data_riot.peek(addr & 0x1f) : @data_riot.read_ram(addr)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def poke_riots(addr, value)
|
|
84
|
+
if addr.anybits?(0x80)
|
|
85
|
+
addr.anybits?(0x200) ? @control_riot.poke(addr & 0x1f, value) : @control_riot.write_ram(addr, value)
|
|
86
|
+
else
|
|
87
|
+
addr.anybits?(0x200) ? @data_riot.poke(addr & 0x1f, value) : @data_riot.write_ram(addr, value)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Drives
|
|
5
|
+
class Model8050
|
|
6
|
+
class Disk
|
|
7
|
+
# A disk's fields in a keyed snapshot module (BL-D8-DISK, BL-D8-DISK1
|
|
8
|
+
# for drive 1): the image file's path and how it was opened, the
|
|
9
|
+
# image as last flushed, embedded under image and image.format, each
|
|
10
|
+
# track whose cells differ from what the image lays out, as
|
|
11
|
+
# track<N>, a cell per byte or 256 for a sync, and the tracks
|
|
12
|
+
# written since the last flush.
|
|
13
|
+
module KeyedState
|
|
14
|
+
IMAGE_FORMATS = %w[d80 d82].freeze
|
|
15
|
+
|
|
16
|
+
def save_fields(out)
|
|
17
|
+
image = @image
|
|
18
|
+
out.text("path", image.path.to_s).bool("read_only", image.read_only?)
|
|
19
|
+
out.text("image.format", image_format)
|
|
20
|
+
out.bytes("image", image.contents)
|
|
21
|
+
@tracks.each do |number, cells|
|
|
22
|
+
out.ints("track#{number}", cells) unless cells == build(number)
|
|
23
|
+
end
|
|
24
|
+
out.ints("written", @written.keys)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Puts back the tracks and the writes not yet flushed.
|
|
28
|
+
def load_track_fields(input)
|
|
29
|
+
(1..(side_tracks * sides)).each do |number|
|
|
30
|
+
cells = input.ints("track#{number}", [])
|
|
31
|
+
@tracks[number] = cells.dup unless cells.empty?
|
|
32
|
+
end
|
|
33
|
+
input.ints("written", []).each { |number| @written[number] = true }
|
|
34
|
+
self
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
include KeyedState
|
|
39
|
+
|
|
40
|
+
# The kind of image the disk lays out, as image.format names it.
|
|
41
|
+
def image_format = @image.is_a?(Storage::D82Image) ? "d82" : "d80"
|
|
42
|
+
|
|
43
|
+
# The disk a BL-D8-DISK module holds. A detached reader gets the
|
|
44
|
+
# image write-protected, and it and a host file that is gone leave
|
|
45
|
+
# it no path to write back to.
|
|
46
|
+
def self.from_fields(input, detached: false)
|
|
47
|
+
path = input.text("path", "")
|
|
48
|
+
read_only = input.bool("read_only", false) || detached
|
|
49
|
+
kind = input.choice("image.format", KeyedState::IMAGE_FORMATS, "d80")
|
|
50
|
+
bytes = input.bytes("image", "".b).bytes
|
|
51
|
+
path = "" if detached || !File.file?(path)
|
|
52
|
+
image_class = kind == "d82" ? Storage::D82Image : Storage::D80Image
|
|
53
|
+
new(image_class.new(path, read_only:, bytes:)).load_track_fields(input)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
class Mechanism
|
|
58
|
+
# The drives' fields in a keyed snapshot module (BL-D8-MECH), a value
|
|
59
|
+
# a drive in each list: the heads' cylinders, the stepper phases,
|
|
60
|
+
# each disk's place in its turn and its bit clock, the disk change
|
|
61
|
+
# under way and the motors, then the byte ready pulse, the byte on
|
|
62
|
+
# VIA port A and SYNC. The disks load from their own modules.
|
|
63
|
+
module KeyedState
|
|
64
|
+
def save_fields(out)
|
|
65
|
+
out.ints("cylinders", @cylinders).ints("phases", @phases).ints("positions", @positions)
|
|
66
|
+
out.ints("bit_clocks", @clocks).ints("changing", @changing)
|
|
67
|
+
out.ints("motors", @motors.map { |on| on ? 1 : 0 }).ints("syncs", @syncs.map { |low| low ? 1 : 0 })
|
|
68
|
+
out.bool("so_pending", @so_pending).bool("ca1_low", @ca1_low).int("data_in", @data_in)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def load_fields(input, disks)
|
|
72
|
+
@disks = disks
|
|
73
|
+
input.ints_into("cylinders", @cylinders)
|
|
74
|
+
input.ints_into("phases", @phases)
|
|
75
|
+
input.ints_into("positions", @positions)
|
|
76
|
+
input.ints_into("bit_clocks", @clocks)
|
|
77
|
+
input.ints_into("changing", @changing)
|
|
78
|
+
@motors = input.ints("motors", [0, 0]).map { |on| on == 1 }
|
|
79
|
+
@syncs = input.ints("syncs", [0, 0]).map { |low| low == 1 }
|
|
80
|
+
@so_pending = input.bool("so_pending", @so_pending)
|
|
81
|
+
@ca1_low = input.bool("ca1_low", @ca1_low)
|
|
82
|
+
@data_in = input.byte("data_in", @data_in)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
include KeyedState
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# The unit's own fields in a keyed snapshot module (BL-D8): its model,
|
|
90
|
+
# its clock phase and cycle count, each bus's last byte, and the
|
|
91
|
+
# controller's lines as the port latched them, under ieee.*. A save
|
|
92
|
+
# settles the unit first, so it is awake; a load finds its passes
|
|
93
|
+
# afresh.
|
|
94
|
+
module KeyedState
|
|
95
|
+
def save_fields(out)
|
|
96
|
+
settle!
|
|
97
|
+
out.text("model", model_name).int("phase", @phase).int("cycles", @cycles)
|
|
98
|
+
out.int("ip_data", @ip_bus.data).int("fdc_data", @fdc_bus.data)
|
|
99
|
+
out.int("ieee.host", @ieee_port.host)
|
|
100
|
+
out
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def load_fields(input)
|
|
104
|
+
settle!
|
|
105
|
+
input.choice("model", [model_name], model_name)
|
|
106
|
+
@phase = input.int("phase", @phase)
|
|
107
|
+
@cycles = input.int("cycles", @cycles)
|
|
108
|
+
@ip_bus.data = input.byte("ip_data", @ip_bus.data)
|
|
109
|
+
@fdc_bus.data = input.byte("fdc_data", @fdc_bus.data)
|
|
110
|
+
@ieee_port.host = input.int("ieee.host", @ieee_port.host)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# The unit as modules of its own, named from `name` (BL-D8 for
|
|
114
|
+
# device 8): its own fields, the common RAM, UC1 and UE1 with their
|
|
115
|
+
# RAM, each processor, the VIA, the 6530, the drives and each disk
|
|
116
|
+
# in, drive 1's as -DISK1.
|
|
117
|
+
def save_modules(sections, name)
|
|
118
|
+
sections << Snapshot::Keyed.section(name) { |out| save_fields(out) }
|
|
119
|
+
sections << Snapshot::Keyed.section("#{name}-COMMON") { |out| @common.save_fields(out, "ram") }
|
|
120
|
+
sections << Snapshot::Keyed.section("#{name}-RIOT1") { |out| @data_riot.save_fields(out) }
|
|
121
|
+
sections << Snapshot::Keyed.section("#{name}-RIOT2") { |out| @control_riot.save_fields(out) }
|
|
122
|
+
sections << Snapshot::Keyed.section("#{name}-IPCPU") { |out| @ip_cpu.save_fields(out) }
|
|
123
|
+
sections << Snapshot::Keyed.section("#{name}-FDCCPU") { |out| @fdc_cpu.save_fields(out) }
|
|
124
|
+
sections << Snapshot::Keyed.section("#{name}-VIA") { |out| @via.save_fields(out) }
|
|
125
|
+
sections << Snapshot::Keyed.section("#{name}-RRIOT") { |out| @rriot.save_fields(out) }
|
|
126
|
+
sections << Snapshot::Keyed.section("#{name}-MECH") { |out| @mechanism.save_fields(out) }
|
|
127
|
+
[0, 1].each do |drive|
|
|
128
|
+
disk = @mechanism.disk(drive)
|
|
129
|
+
sections << Snapshot::Keyed.section(disk_module(name, drive)) { |out| disk.save_fields(out) } if disk
|
|
130
|
+
end
|
|
131
|
+
sections
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# The unit from its modules, `input` being its own. No disk module
|
|
135
|
+
# means no disk in that drive.
|
|
136
|
+
def load_modules(modules, input, name)
|
|
137
|
+
load_fields(input)
|
|
138
|
+
@common.load_fields(modules.required("#{name}-COMMON"), "ram")
|
|
139
|
+
@data_riot.load_fields(modules.required("#{name}-RIOT1"))
|
|
140
|
+
@control_riot.load_fields(modules.required("#{name}-RIOT2"))
|
|
141
|
+
@ip_cpu.load_fields(modules.required("#{name}-IPCPU"))
|
|
142
|
+
@fdc_cpu.load_fields(modules.required("#{name}-FDCCPU"))
|
|
143
|
+
@via.load_fields(modules.required("#{name}-VIA"))
|
|
144
|
+
@rriot.load_fields(modules.required("#{name}-RRIOT"))
|
|
145
|
+
disks = [0, 1].map do |drive|
|
|
146
|
+
disk = modules.optional(disk_module(name, drive))
|
|
147
|
+
disk.nil? ? nil : disk_from_fields(disk, modules.detached?)
|
|
148
|
+
end
|
|
149
|
+
@mechanism.load_fields(modules.required("#{name}-MECH"), disks)
|
|
150
|
+
@via.restored!
|
|
151
|
+
@ip_cpu.restored!
|
|
152
|
+
@fdc_cpu.restored!
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
private
|
|
156
|
+
|
|
157
|
+
def disk_module(name, drive) = drive.zero? ? "#{name}-DISK" : "#{name}-DISK1"
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
include KeyedState
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|