badline 0.16.0 → 0.17.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 +76 -0
- data/CLAUDE.md +1 -1
- data/README.md +130 -17
- data/doc/media.md +14 -2
- data/doc/pinned-behaviour.md +61 -0
- data/doc/snapshot-format.md +379 -70
- data/doc/snapshots.md +185 -10
- 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 +91 -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 +262 -0
- data/lib/badline/cbm2/sid_page.rb +19 -0
- data/lib/badline/cbm2.rb +267 -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/crtc.rb +3 -2
- 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 +80 -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 +132 -0
- 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/drives/datasette/keyed_state.rb +9 -1
- data/lib/badline/drives/datasette.rb +27 -3
- data/lib/badline/drives/ieee_bus.rb +50 -4
- data/lib/badline/drives/model2031/ieee_port.rb +133 -0
- data/lib/badline/drives/model2031/keyed_state.rb +66 -0
- data/lib/badline/drives/model2031/parts.rb +25 -0
- data/lib/badline/drives/model2031.rb +92 -0
- data/lib/badline/drives/model8050/disk.rb +163 -0
- data/lib/badline/drives/model8050/fdc_bus.rb +102 -0
- data/lib/badline/drives/model8050/idle.rb +177 -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 +160 -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 +243 -0
- data/lib/badline/frontend/app.rb +10 -3
- data/lib/badline/frontend/boot.rb +1 -1
- data/lib/badline/frontend/controls.rb +51 -15
- data/lib/badline/frontend/gamepads.rb +3 -3
- data/lib/badline/frontend/keys.rb +61 -2
- data/lib/badline/frontend/media_slots.rb +1 -1
- data/lib/badline/frontend/menu/menu_media.rb +14 -11
- data/lib/badline/frontend/menu/menu_pages.rb +29 -6
- data/lib/badline/frontend/menu/menu_ports.rb +40 -4
- data/lib/badline/frontend/menu/pause_menu.rb +1 -1
- data/lib/badline/frontend/pet_keyboard.rb +23 -7
- data/lib/badline/frontend/timeline.rb +19 -10
- 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 +7 -2
- data/lib/badline/kernal_trap/ieee_layout.rb +95 -43
- data/lib/badline/machine/ieee_drives.rb +194 -0
- data/lib/badline/machine/settling.rb +4 -0
- data/lib/badline/machine.rb +26 -8
- data/lib/badline/media/cbm2_media.rb +29 -0
- data/lib/badline/media/pet_media.rb +5 -5
- data/lib/badline/media/program.rb +6 -3
- data/lib/badline/media/true_drive.rb +50 -8
- data/lib/badline/media.rb +21 -8
- data/lib/badline/options/family.rb +15 -3
- data/lib/badline/options/help.rb +24 -6
- data/lib/badline/options/table.rb +25 -5
- data/lib/badline/options/validation.rb +47 -7
- data/lib/badline/options.rb +48 -15
- data/lib/badline/pet/bus/expansion.rb +99 -5
- data/lib/badline/pet/bus.rb +30 -12
- data/lib/badline/pet/cassettes.rb +22 -1
- data/lib/badline/pet/characters.rb +8 -2
- data/lib/badline/pet/crtc_video.rb +20 -7
- data/lib/badline/pet/ieee_drive.rb +17 -0
- data/lib/badline/pet/ieee_ports.rb +19 -1
- data/lib/badline/pet/ieee_traps.rb +10 -5
- data/lib/badline/pet/keyed_modules.rb +4 -1
- data/lib/badline/pet/keyed_parts.rb +10 -6
- data/lib/badline/pet/model.rb +56 -6
- data/lib/badline/pet/rom_sets.rb +30 -6
- data/lib/badline/pet.rb +45 -16
- data/lib/badline/plus4/acia.rb +4 -298
- data/lib/badline/plus4/keyed_parts.rb +0 -44
- data/lib/badline/plus4.rb +1 -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/README +144 -1
- 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/dos2031.rom +0 -0
- data/lib/badline/roms/pet/characters-din.rom +0 -0
- data/lib/badline/roms/pet/editor4-80-b-50hz-8296.rom +0 -0
- data/lib/badline/snapshot/cbm2_setup.rb +53 -0
- data/lib/badline/snapshot/container.rb +9 -1
- data/lib/badline/snapshot/field_doc/markdown.rb +4 -2
- data/lib/badline/snapshot/field_doc.rb +39 -3
- data/lib/badline/snapshot/image.rb +79 -15
- data/lib/badline/snapshot/pet_setup.rb +30 -13
- 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 +121 -0
- data/lib/badline/snapshot/vice/pet_cpu.rb +70 -0
- data/lib/badline/snapshot/vice/pet_crtc.rb +241 -0
- data/lib/badline/snapshot/vice/pet_drive.rb +180 -0
- data/lib/badline/snapshot/vice/pet_drive8050.rb +216 -0
- data/lib/badline/snapshot/vice/pet_mem.rb +93 -0
- data/lib/badline/snapshot/vice/pet_pias.rb +56 -0
- data/lib/badline/snapshot/vice/pet_restore.rb +214 -0
- data/lib/badline/snapshot/vice/pet_via.rb +165 -0
- 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 +4 -0
- data/lib/badline/snapshot.rb +11 -3
- data/lib/badline/storage/crt_file.rb +7 -1
- data/lib/badline/storage/d64_image.rb +7 -0
- data/lib/badline/storage/d80_image.rb +17 -1
- data/lib/badline/storage/d81_image.rb +14 -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 +35 -0
- data/lib/badline/storage/disk_image.rb +2 -0
- data/lib/badline/storage.rb +1 -0
- data/lib/badline/support/cbm2_checkpoint.rb +48 -0
- data/lib/badline/support/p500_checkpoint.rb +35 -0
- data/lib/badline/version.rb +1 -1
- data/lib/badline.rb +1 -0
- metadata +87 -2
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Snapshot
|
|
5
|
+
module Vice
|
|
6
|
+
module P500
|
|
7
|
+
# VIC-II 1.3 as xcbm5x0 writes it, which runs VICE's line-based
|
|
8
|
+
# VIC-II rather than x64sc's, so the module is laid out otherwise
|
|
9
|
+
# than x64sc's under the same name: whether bad lines may happen,
|
|
10
|
+
# whether this line is one, the vertical border, the colour
|
|
11
|
+
# buffer, colour RAM, whether the sequencer is idle, the light
|
|
12
|
+
# pen's trigger and position, the video matrix buffer, the sprites
|
|
13
|
+
# whose DMA starts next line, a word xcbm5x0 keeps at $00100000,
|
|
14
|
+
# the beam's cycle and line, the registers, the sprite collisions
|
|
15
|
+
# pending, the sprites' DMA, the VIC's bank, VC, the matrix's
|
|
16
|
+
# width, VCBASE, then sprite and drawing fields with the bank
|
|
17
|
+
# again, the line its picture draws next and its size, and the
|
|
18
|
+
# picture. xcbm5x0's cycle in the line is badline's column.
|
|
19
|
+
#
|
|
20
|
+
# Written: the registers, colour RAM, the buffers, the beam with
|
|
21
|
+
# its counters and the sprites' DMA as badline's VIC has them, the
|
|
22
|
+
# bank as TPI2's PC6 and PC7 pick it, and the rest as xcbm5x0
|
|
23
|
+
# leaves it. The picture is left blank, as xcbm5x0 paints it again.
|
|
24
|
+
#
|
|
25
|
+
# Read: the registers, colour RAM, the buffers, the beam with VC,
|
|
26
|
+
# VCBASE and whether the sequencer is idle, the light pen and the
|
|
27
|
+
# sprites' DMA, through the x64sc module's reader (VICII::Import).
|
|
28
|
+
# The row counter follows from the line and YSCROLL, and the
|
|
29
|
+
# sprites' counters and the borders' flip-flops start afresh.
|
|
30
|
+
# xcbm5x0's VIC isn't x64sc's, so a program badline runs on from its
|
|
31
|
+
# snapshot reads the raster a cycle or so off now and then.
|
|
32
|
+
module VICII
|
|
33
|
+
NAME = Vice::VICII::NAME
|
|
34
|
+
MAJOR = 1
|
|
35
|
+
MINOR = 3
|
|
36
|
+
ALLOW_BAD_LINES = 0x000
|
|
37
|
+
BAD_LINE = 0x001
|
|
38
|
+
BLANK = 0x002
|
|
39
|
+
COLOR_BUFFER = 0x003
|
|
40
|
+
COLOR_RAM = 0x02b
|
|
41
|
+
IDLE = 0x42b
|
|
42
|
+
LIGHT_PEN = 0x42c
|
|
43
|
+
MATRIX_BUFFER = 0x42f
|
|
44
|
+
RAM_BASE = 0x458
|
|
45
|
+
CYCLE = 0x45c
|
|
46
|
+
LINE = 0x45d
|
|
47
|
+
REGISTERS = 0x45f
|
|
48
|
+
SPRITE_DMA = 0x4a0
|
|
49
|
+
BANK = 0x4a2
|
|
50
|
+
VC = 0x4a4
|
|
51
|
+
VC_ADD = 0x4a6
|
|
52
|
+
VC_BASE = 0x4a7
|
|
53
|
+
VIDEO_INT = 0x4a9
|
|
54
|
+
DRAW_FLAGS = 0x4cd
|
|
55
|
+
FETCH_BANK = 0x4cf
|
|
56
|
+
DRAWN_LINE = 0x4d1
|
|
57
|
+
PICTURE = 0x4d5
|
|
58
|
+
HEADER = 0x4e1
|
|
59
|
+
# The picture's size: PAL's and NTSC's.
|
|
60
|
+
SIZES = { 312 => [504, 312], 263 => [520, 275] }.freeze
|
|
61
|
+
|
|
62
|
+
module_function
|
|
63
|
+
|
|
64
|
+
def reads?(section) = section.major == MAJOR && section.minor == MINOR
|
|
65
|
+
|
|
66
|
+
# The lines xcbm5x0's picture has, which name its region.
|
|
67
|
+
def picture_lines(section) = FieldReader.new(section).skip(PICTURE + 4).dword
|
|
68
|
+
|
|
69
|
+
def export(machine)
|
|
70
|
+
vic = machine.vic
|
|
71
|
+
width, height = SIZES.fetch(vic.region.lines_per_frame)
|
|
72
|
+
bytes = Array.new(HEADER + (width * (height + 4)), 0)
|
|
73
|
+
sequencer(vic, bytes)
|
|
74
|
+
bytes[COLOR_RAM, 0x400] = Array.new(0x400) { |offset| machine.color_ram.nibble(0xd400 + offset) }
|
|
75
|
+
beam(vic, bytes)
|
|
76
|
+
bank = ((machine.tpi2.port_c_output >> 6) & 0x03) << 14
|
|
77
|
+
[BANK, FETCH_BANK].each { |at| word(bytes, at, bank) }
|
|
78
|
+
[RAM_BASE + 2, DRAW_FLAGS].each { |at| bytes[at] = 0x10 }
|
|
79
|
+
bytes[VIDEO_INT] = 1
|
|
80
|
+
[vic.rasterline, width, height, width].each_with_index do |value, n|
|
|
81
|
+
dword(bytes, DRAWN_LINE + (4 * n), value)
|
|
82
|
+
end
|
|
83
|
+
FieldWriter.new.bytes(bytes).section(NAME, MAJOR, MINOR)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# The sequencer's state and the buffers it reads.
|
|
87
|
+
def sequencer(vic, bytes)
|
|
88
|
+
state = vic.display_state
|
|
89
|
+
bytes[ALLOW_BAD_LINES] = state.bad_lines_enabled ? 1 : 0
|
|
90
|
+
bytes[BAD_LINE] = state.bad_line_condition? ? 1 : 0
|
|
91
|
+
bytes[BLANK] = vic.sequencer.borders.first ? 1 : 0
|
|
92
|
+
bytes[COLOR_BUFFER, 40] = vic.color_buffer.map { |value| value || 0 }
|
|
93
|
+
bytes[IDLE] = state.display? ? 0 : 1
|
|
94
|
+
bytes[MATRIX_BUFFER, 40] = vic.character_buffer.map { |value| value || 0 }
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# The beam, the registers and the counters.
|
|
98
|
+
def beam(vic, bytes)
|
|
99
|
+
state = vic.display_state
|
|
100
|
+
bytes[CYCLE] = vic.column
|
|
101
|
+
word(bytes, LINE, vic.rasterline)
|
|
102
|
+
bytes[REGISTERS, 0x40] = vic.register_file
|
|
103
|
+
bytes[SPRITE_DMA] = 8.times.sum { |n| vic.sprites[n].displaying? ? 1 << n : 0 }
|
|
104
|
+
word(bytes, VC, state.vc)
|
|
105
|
+
bytes[VC_ADD] = 40
|
|
106
|
+
word(bytes, VC_BASE, state.vc_base)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def word(bytes, at, value) = bytes[at, 2] = [value & 0xffff].pack("v").bytes
|
|
110
|
+
|
|
111
|
+
def dword(bytes, at, value) = bytes[at, 4] = [value].pack("V").bytes
|
|
112
|
+
|
|
113
|
+
def import(section, vic, color_ram)
|
|
114
|
+
Import.new(section, vic.region).apply_to(vic, color_ram, 0xd400)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Reads xcbm5x0's module into the fields x64sc's reader puts into
|
|
118
|
+
# badline's VIC.
|
|
119
|
+
class Import < Vice::VICII::Import
|
|
120
|
+
# x64sc's cycle is badline's column plus one, its cycle 0 the
|
|
121
|
+
# last column of the line before (VICII.vice_cycle).
|
|
122
|
+
def initialize(section, region)
|
|
123
|
+
super(nil)
|
|
124
|
+
bytes = section.data.bytes
|
|
125
|
+
@registers = bytes[REGISTERS, 0x40]
|
|
126
|
+
line = bytes[LINE] | (bytes[LINE + 1] << 8)
|
|
127
|
+
@cycle = (bytes[CYCLE] + 1) % region.cycles_per_line
|
|
128
|
+
@line = @cycle.zero? ? (line + 1) % region.lines_per_frame : line
|
|
129
|
+
@frame_start = false
|
|
130
|
+
@irq_status = @registers[0x19]
|
|
131
|
+
@raster_match = false
|
|
132
|
+
@character_buffer = bytes[MATRIX_BUFFER, 40]
|
|
133
|
+
@color_buffer = bytes[COLOR_BUFFER, 40]
|
|
134
|
+
read_old_counters(bytes)
|
|
135
|
+
@color_ram = bytes[COLOR_RAM, 0x400]
|
|
136
|
+
@sprite_mc = Array.new(8, 0)
|
|
137
|
+
@sprite_mcbase = Array.new(8, 0)
|
|
138
|
+
@sprite_exp_ff = 0
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
private
|
|
142
|
+
|
|
143
|
+
def read_old_counters(bytes)
|
|
144
|
+
@bad_lines_enabled = !bytes[ALLOW_BAD_LINES].zero?
|
|
145
|
+
@collisions = [@registers[0x1e], @registers[0x1f]]
|
|
146
|
+
@display = bytes[IDLE].zero?
|
|
147
|
+
@vc_base = bytes[VC_BASE] | (bytes[VC_BASE + 1] << 8)
|
|
148
|
+
@vc = bytes[VC] | (bytes[VC + 1] << 8)
|
|
149
|
+
@rc = @display ? (@line - @registers[0x11]) & 0x07 : 7
|
|
150
|
+
@vmli = 0
|
|
151
|
+
@lp_low = false
|
|
152
|
+
@lp_triggered = !bytes[LIGHT_PEN].zero?
|
|
153
|
+
@fetch_d011 = @registers[0x11]
|
|
154
|
+
@dma_bits = bytes[SPRITE_DMA]
|
|
155
|
+
@display_bits = @dma_bits
|
|
156
|
+
blank = !bytes[BLANK].zero?
|
|
157
|
+
@vertical_border = blank
|
|
158
|
+
@vertical_armed = false
|
|
159
|
+
@main_border = blank
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "badline/snapshot/vice/pet_cpu"
|
|
4
|
+
require "badline/snapshot/vice/pet_mem"
|
|
5
|
+
require "badline/snapshot/vice/pet_pias"
|
|
6
|
+
require "badline/snapshot/vice/pet_via"
|
|
7
|
+
require "badline/snapshot/vice/pet_crtc"
|
|
8
|
+
require "badline/snapshot/vice/pet_drive"
|
|
9
|
+
require "badline/snapshot/vice/pet_drive8050"
|
|
10
|
+
require "badline/snapshot/vice/pet_restore"
|
|
11
|
+
|
|
12
|
+
module Badline
|
|
13
|
+
module Snapshot
|
|
14
|
+
module Vice
|
|
15
|
+
# xpet's modules for the PET: the CPU, the RAM, the CRTC, both PIAs,
|
|
16
|
+
# the VIA and a true 2031, written from badline's machine and read
|
|
17
|
+
# into it. Each
|
|
18
|
+
# module's file says what maps and what is approximated. They go
|
|
19
|
+
# through the PET's own keyed fields (Keyed), which a save writes and a
|
|
20
|
+
# load reads, so they read no chip's insides.
|
|
21
|
+
module PET
|
|
22
|
+
# The models badline builds by the board PETMEM names (PETMem): the
|
|
23
|
+
# discrete board is a 2001's where xpet's settings say so, and a
|
|
24
|
+
# 3032 otherwise.
|
|
25
|
+
MODELS = { PETMem::CRTC40 => "4032", PETMem::CRTC80 => "8032", PETMem::CBM8096 => "8096",
|
|
26
|
+
PETMem::CBM8296 => "8296" }.freeze
|
|
27
|
+
# The modules xpet resets the machine without, for the parts badline
|
|
28
|
+
# doesn't model in VICE's terms, each as xpet leaves them with
|
|
29
|
+
# nothing attached: no file system drive open, both cassette ports
|
|
30
|
+
# on with a datasette in #1, and nothing in the user port.
|
|
31
|
+
PERIPHERALS = [
|
|
32
|
+
["FSDRIVE", 0, 0, Array.new(258, 0)], ["TAPEPORT", 1, 0, [0x01, 0x01, 0x01]], ["USERPORT", 1, 0, [0x01, 0x00]]
|
|
33
|
+
].freeze
|
|
34
|
+
# The cycles a frame below which a CRTC editor runs at 60 Hz.
|
|
35
|
+
SIXTY_HZ_FRAME = 18_333
|
|
36
|
+
# The 8032's 50 Hz editors by the cycles a line they set up: xpet's
|
|
37
|
+
# own, 901474-04 dated 0283, sets 64.
|
|
38
|
+
EDITOR_0283_LINE = 64
|
|
39
|
+
|
|
40
|
+
module_function
|
|
41
|
+
|
|
42
|
+
# The modules xpet 3.10 needs, in its order, describing `machine`,
|
|
43
|
+
# which Machine::Settling has brought between instructions, from
|
|
44
|
+
# its keyed modules, `sections`.
|
|
45
|
+
def export(machine, sections)
|
|
46
|
+
readers = {}
|
|
47
|
+
sections.each { |section| readers[section.name] = Keyed::Reader.parse(section) }
|
|
48
|
+
[MainCPU.export(machine), CPU6809.export(machine), PETMem.export(machine),
|
|
49
|
+
CRTC.export(machine, reader(readers, "BL-CRTC"), reader(readers, "BL-VIDEO")),
|
|
50
|
+
PIAs.export("PIA1", machine.pia1, reader(readers, "BL-PIA1")),
|
|
51
|
+
PIAs.export("PIA2", machine.pia2, reader(readers, "BL-PIA2")), VIA.export(reader(readers, "BL-VIA")),
|
|
52
|
+
*Drive2031.export(machine, readers), *Drive8050.export(machine, readers)] +
|
|
53
|
+
PERIPHERALS.map { |name, major, minor, bytes| FieldWriter.new.bytes(bytes).section(name, major, minor) }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def reader(readers, name) = readers[name] || Keyed::Reader.missing(name)
|
|
57
|
+
|
|
58
|
+
# How the machine xpet saved was built: the model from PETMEM's
|
|
59
|
+
# board, the RAM, and on a CRTC board the editor's frame rate, and
|
|
60
|
+
# for an 8032's 50 Hz editor which one, from the CRTC's registers.
|
|
61
|
+
# xpet doesn't save the keyboard, the ROMs or an 8296's jumpers, so
|
|
62
|
+
# a discrete board is a 3032 with the graphics keyboard unless it is
|
|
63
|
+
# a 2001, each model has its own ROMs, and an 8296 none of its
|
|
64
|
+
# jumpers, as xpet's own has.
|
|
65
|
+
def setup(container)
|
|
66
|
+
memory = memory(container)
|
|
67
|
+
ram_kb = PETMem.ram_kb(memory)
|
|
68
|
+
name = model_name(memory)
|
|
69
|
+
profile = Badline::PET::Model.named(name)
|
|
70
|
+
unless Badline::PET::Model.ram_fits?(profile, ram_kb)
|
|
71
|
+
raise FormatError, "#{memory}: a #{name} with #{ram_kb}K of RAM, which badline doesn't build"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
crtc = container[CRTC::NAME]
|
|
75
|
+
crtc = nil unless crtc.nil? || CRTC.reads?(crtc)
|
|
76
|
+
refresh_hz = refresh_hz(crtc, profile)
|
|
77
|
+
profile = Badline::PET::Model.upgraded(profile, nil, editor(crtc, profile, refresh_hz))
|
|
78
|
+
PETSetup.new(model: name, ram_kb:, refresh_hz:, basic: profile.basic, editor: profile.editor(refresh_hz),
|
|
79
|
+
kernal: profile.kernal, characters: profile.characters, jumpers: "")
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def memory(container)
|
|
83
|
+
section = container[PETMem::NAME]
|
|
84
|
+
raise FormatError, "the snapshot has no #{PETMem::NAME} module" if section.nil?
|
|
85
|
+
raise FormatError, "#{section}: badline doesn't read this version" unless PETMem.reads?(section)
|
|
86
|
+
|
|
87
|
+
section
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def model_name(memory)
|
|
91
|
+
board = PETMem.board_of(memory)
|
|
92
|
+
return PETMem.pet2001?(memory) ? "2001" : "3032" if board == PETMem::DISCRETE
|
|
93
|
+
|
|
94
|
+
name = MODELS[board]
|
|
95
|
+
return name unless name.nil?
|
|
96
|
+
|
|
97
|
+
what = board == PETMem::SUPERPET ? "a SuperPET" : "board #{board}"
|
|
98
|
+
raise FormatError, "#{memory}: #{what}, which badline doesn't build"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# The editor's frame rate, from the cycles the CRTC's registers set
|
|
102
|
+
# up a frame.
|
|
103
|
+
def refresh_hz(crtc, profile)
|
|
104
|
+
return 60 unless profile.crtc?
|
|
105
|
+
return 50 if crtc.nil?
|
|
106
|
+
|
|
107
|
+
registers = CRTC.registers(crtc)
|
|
108
|
+
(registers[0] + 1) * CRTC.frame_lines(registers) > SIXTY_HZ_FRAME ? 50 : 60
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# The editor by ROMSets' name where the model's own doesn't set up
|
|
112
|
+
# the CRTC's frame, or nil.
|
|
113
|
+
def editor(crtc, profile, refresh_hz)
|
|
114
|
+
return nil if crtc.nil? || refresh_hz != 50 || profile.video != :crtc80
|
|
115
|
+
|
|
116
|
+
CRTC.registers(crtc)[0] + 1 == EDITOR_0283_LINE ? "4-80-b-50hz-0283" : nil
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Snapshot
|
|
5
|
+
module Vice
|
|
6
|
+
module PET
|
|
7
|
+
# The 6502 as xpet 3.10 saves it, MAINCPU 1.3: the clock, the
|
|
8
|
+
# registers, the last opcode and two words after it, then the IRQ
|
|
9
|
+
# and NMI bookkeeping: five clocks, the IRQ and NMI source counts and
|
|
10
|
+
# the pending interrupts. xpet's MAINCPU has no BA line to save.
|
|
11
|
+
#
|
|
12
|
+
# Written: the clock and the registers, which between instructions
|
|
13
|
+
# are the whole CPU, with the IRQ sources that pull the line and a
|
|
14
|
+
# pending IRQ. VICE's interrupt clocks are written as long past.
|
|
15
|
+
#
|
|
16
|
+
# Read: the clock and the registers. The CPU starts on an
|
|
17
|
+
# instruction boundary, as xpet's snapshot is taken on one.
|
|
18
|
+
module MainCPU
|
|
19
|
+
NAME = "MAINCPU"
|
|
20
|
+
MAJOR = 1
|
|
21
|
+
MINOR = 3
|
|
22
|
+
IK_IRQ = 0x02
|
|
23
|
+
|
|
24
|
+
module_function
|
|
25
|
+
|
|
26
|
+
def reads?(section) = section.major == MAJOR && section.minor == MINOR
|
|
27
|
+
|
|
28
|
+
def export(machine) = write(machine, [machine.pia1.irq?, machine.pia2.irq?, machine.via.irq?].count(true))
|
|
29
|
+
|
|
30
|
+
# The module for `machine`, whose CPU's IRQ line `irqs` sources
|
|
31
|
+
# pull.
|
|
32
|
+
def write(machine, irqs)
|
|
33
|
+
cpu = machine.cpu
|
|
34
|
+
fields = FieldWriter.new.qword(machine.cycles)
|
|
35
|
+
[cpu.a, cpu.x, cpu.y, cpu.stack_pointer].each { |register| fields.byte(register) }
|
|
36
|
+
fields.word(cpu.program_counter).byte(cpu.p)
|
|
37
|
+
fields.dword(0).dword(0).dword(0)
|
|
38
|
+
5.times { fields.qword(0) }
|
|
39
|
+
fields.dword(irqs).dword(0).dword(irqs.positive? ? IK_IRQ : 0)
|
|
40
|
+
fields.section(NAME, MAJOR, MINOR)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# The clock, the registers by their BL-CPU keys, in a keyed
|
|
44
|
+
# module's writer.
|
|
45
|
+
def import(section, out)
|
|
46
|
+
fields = FieldReader.new(section)
|
|
47
|
+
clock = fields.qword
|
|
48
|
+
out.int("a", fields.byte).int("x", fields.byte).int("y", fields.byte).int("sp", fields.byte)
|
|
49
|
+
out.int("pc", fields.word).int("p", fields.byte).int("cycles", clock)
|
|
50
|
+
clock
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# The SuperPET's 6809, CPU6809 1.1, which xpet saves on every model
|
|
55
|
+
# and won't load a snapshot without: the clock and the registers as
|
|
56
|
+
# an xpet with no SuperPET board leaves them. badline doesn't read
|
|
57
|
+
# it.
|
|
58
|
+
module CPU6809
|
|
59
|
+
NAME = "CPU6809"
|
|
60
|
+
|
|
61
|
+
module_function
|
|
62
|
+
|
|
63
|
+
def export(machine)
|
|
64
|
+
FieldWriter.new.qword(machine.cycles).zeros(11).byte(0x04).zeros(7).section(NAME, 1, 1)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Snapshot
|
|
5
|
+
module Vice
|
|
6
|
+
module PET
|
|
7
|
+
# CRTC 1.2, which xpet saves on every model, the discrete boards'
|
|
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,
|
|
10
|
+
# row and line in the row, whether the frame is in its vertical
|
|
11
|
+
# adjust, the row's start in screen RAM, the lines of vertical sync
|
|
12
|
+
# left, whether the rows show, the picture's size, the lines in the
|
|
13
|
+
# frame and the line in it, then xpet's picture.
|
|
14
|
+
#
|
|
15
|
+
# Written: the registers and the beam as badline's CRTC, or its
|
|
16
|
+
# discrete video, has them. The picture is left blank, as xpet
|
|
17
|
+
# paints it again.
|
|
18
|
+
#
|
|
19
|
+
# Read: the registers and the beam, with what follows from them: the
|
|
20
|
+
# memory address, the characters since horizontal sync and whether
|
|
21
|
+
# the character shows. The picture starts again with the next
|
|
22
|
+
# frame.
|
|
23
|
+
module CRTC
|
|
24
|
+
NAME = "CRTC"
|
|
25
|
+
MAJOR = 1
|
|
26
|
+
MINOR = 2
|
|
27
|
+
# The registers xpet saves, two more than badline's CRTC has.
|
|
28
|
+
REGISTERS = 20
|
|
29
|
+
# Where the selected register is in the module, and the beam after
|
|
30
|
+
# it.
|
|
31
|
+
SELECTED = 0x23
|
|
32
|
+
# The board's screen settings xpet saves ahead of the registers:
|
|
33
|
+
# the screen RAM's masks and the bits of the frame's start address
|
|
34
|
+
# it latches (BOARD_ATTRIBUTES), then the bytes a character reads
|
|
35
|
+
# and whether the board is a 2001's.
|
|
36
|
+
SETTINGS = [0xff, 0x03, 0x00, 0x20, 0x00, 0x20, 0x00, 0x10, 0xff, 0x1f].freeze
|
|
37
|
+
# The 8296's, whose screen RAM spans 4K.
|
|
38
|
+
SETTINGS_8296 = [0xff, 0x0f, 0x00, 0x20, 0x00, 0x20, 0xff, 0x0f, 0xff, 0x1f].freeze
|
|
39
|
+
# The 2001's and 3000 series' video as xpet's CRTC runs it: 64
|
|
40
|
+
# cycles a line, 32 rows of 8 lines and 4 more, the first 25 rows
|
|
41
|
+
# shown.
|
|
42
|
+
DISCRETE_REGISTERS = [0x3f, 0x28, 0x32, 0x08, 0x1f, 0x04, 0x19, 0x1d, 0x00, 0x07, 0x00, 0x00, 0x10, 0x00,
|
|
43
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00].freeze
|
|
44
|
+
DISCRETE_HEIGHT = 216
|
|
45
|
+
DISCRETE_LINE = 64
|
|
46
|
+
DISCRETE_FRAME = DISCRETE_LINE * 260
|
|
47
|
+
# How many cycles badline's beam runs ahead of xpet's, where both
|
|
48
|
+
# drop the vertical drive line on the same cycle.
|
|
49
|
+
DISCRETE_LEAD = 20
|
|
50
|
+
CRTC_LEAD = -3
|
|
51
|
+
HEIGHT = 272
|
|
52
|
+
# A byte xpet writes after the picture's size.
|
|
53
|
+
AFTER_SIZE = 0x20
|
|
54
|
+
# The memory address's bits that pick a byte of screen RAM.
|
|
55
|
+
SCREEN_BITS = 0x0fff
|
|
56
|
+
# The bits above them, which the boards decode as attributes.
|
|
57
|
+
HIGH_BITS = 0x3000
|
|
58
|
+
|
|
59
|
+
# Where the beam is, in xpet's terms: the character, the row and
|
|
60
|
+
# its line, the lines of vertical sync left, whether the rows show,
|
|
61
|
+
# the row's start address and the line in the frame.
|
|
62
|
+
Beam = Data.define(:column, :row, :raster, :vsync, :shown, :start, :frame_line)
|
|
63
|
+
|
|
64
|
+
module_function
|
|
65
|
+
|
|
66
|
+
def reads?(section) = section.major == MAJOR && section.minor == MINOR
|
|
67
|
+
|
|
68
|
+
def width(model) = model.video == :crtc80 ? 704 : 384
|
|
69
|
+
|
|
70
|
+
def height(model) = model.video == :discrete ? DISCRETE_HEIGHT : HEIGHT
|
|
71
|
+
|
|
72
|
+
def columns(model) = model.video == :crtc80 ? 2 : 1
|
|
73
|
+
|
|
74
|
+
# The frame's start address bits xpet latches on the board: MA12,
|
|
75
|
+
# which inverts the 80-column boards' picture.
|
|
76
|
+
def attributes(model) = model.video == :crtc80 ? 0x1000 : 0
|
|
77
|
+
|
|
78
|
+
def export(machine, crtc_input, video_input)
|
|
79
|
+
model = machine.model
|
|
80
|
+
discrete = model.video == :discrete
|
|
81
|
+
registers = discrete ? DISCRETE_REGISTERS : crtc_registers(crtc_input)
|
|
82
|
+
beam = if discrete
|
|
83
|
+
discrete_beam(video_input)
|
|
84
|
+
else
|
|
85
|
+
crtc_beam(run_on(fresh_crtc(machine), crtc_input, -CRTC_LEAD % frame_cycles(registers)),
|
|
86
|
+
registers)
|
|
87
|
+
end
|
|
88
|
+
fields = FieldWriter.new.bytes(model.cbm8296? ? SETTINGS_8296 : SETTINGS).word(attributes(model))
|
|
89
|
+
fields.byte(0).byte(columns(model))
|
|
90
|
+
fields.byte(model.basic1? ? 1 : 0).bytes(registers).byte(discrete ? 0 : crtc_input.int("selected", 0))
|
|
91
|
+
beam_fields(fields, beam, registers, model)
|
|
92
|
+
picture(fields, model)
|
|
93
|
+
fields.section(NAME, MAJOR, MINOR)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def crtc_registers(input)
|
|
97
|
+
registers = input.bytes("registers", "".b).bytes
|
|
98
|
+
Array.new(REGISTERS) { |index| registers[index] || 0 }
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def beam_fields(fields, beam, registers, model)
|
|
102
|
+
fields.byte(beam.column).byte(beam.row).byte(beam.raster).zeros(2).flag(beam.raster.zero?)
|
|
103
|
+
fields.word(beam.start & attributes(model)).word((beam.start & SCREEN_BITS) * columns(model))
|
|
104
|
+
fields.byte(beam.vsync).byte(0).flag(beam.shown)
|
|
105
|
+
fields.word(width(model)).word(height(model)).byte(AFTER_SIZE).zeros(3)
|
|
106
|
+
shown = registers[6] * (registers[9] + 1)
|
|
107
|
+
fields.byte([(height(model) - shown) / 2, 0].max).byte(0)
|
|
108
|
+
fields.word(frame_lines(registers)).word(beam.frame_line).byte(0)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Blank, as xpet paints it again: the line it draws, its size twice
|
|
112
|
+
# over, and four lines more than it shows.
|
|
113
|
+
def picture(fields, model)
|
|
114
|
+
width = width(model)
|
|
115
|
+
height = height(model)
|
|
116
|
+
fields.dword(0).dword(width).dword(height).dword(width).zeros(width * (height + 4))
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def frame_lines(registers) = ((registers[4] + 1) * (registers[9] + 1)) + registers[5]
|
|
120
|
+
|
|
121
|
+
def frame_cycles(registers) = (registers[0] + 1) * frame_lines(registers)
|
|
122
|
+
|
|
123
|
+
# The CRTC of a machine built as `machine` was, at power-on.
|
|
124
|
+
def fresh_crtc(machine) = PETSetup.of(machine).build.crtc
|
|
125
|
+
|
|
126
|
+
# The BL-CRTC fields of `crtc`, a CRTC of its own, loaded with those
|
|
127
|
+
# in `input` and run `cycles` cycles.
|
|
128
|
+
def run_on(crtc, input, cycles)
|
|
129
|
+
crtc.load_fields(input)
|
|
130
|
+
cycles.times { crtc.cycle! }
|
|
131
|
+
Keyed::Reader.parse(Keyed.section("BL-CRTC") { |out| crtc.save_fields(out) })
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Writes the BL-CRTC fields `input` holds to `out`.
|
|
135
|
+
def copy(input, out)
|
|
136
|
+
out.bytes("registers", input.bytes("registers", "".b)).int("selected", input.int("selected", 0))
|
|
137
|
+
%w[column since_hsync line row vsync_lines row_start address].each { |key| out.int(key, input.int(key, 0)) }
|
|
138
|
+
%w[adjusting row_display column_display].each { |key| out.bool(key, input.bool(key, false)) }
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Both move a row's start on at R1 of its last line.
|
|
142
|
+
def crtc_beam(input, registers)
|
|
143
|
+
column = input.int("column", 0)
|
|
144
|
+
row = input.int("row", 0)
|
|
145
|
+
line = input.int("line", 0)
|
|
146
|
+
adjusting = input.bool("adjusting", false)
|
|
147
|
+
start = input.int("row_start", 0)
|
|
148
|
+
rows = registers[4] + 1
|
|
149
|
+
lines = registers[9] + 1
|
|
150
|
+
Beam.new(column:, row: adjusting ? rows : row, raster: adjusting ? 0 : line,
|
|
151
|
+
vsync: input.int("vsync_lines", 0), shown: input.bool("row_display", true), start:,
|
|
152
|
+
frame_line: adjusting ? (rows * lines) + line : (row * lines) + line)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Whether the row's start has moved on by `column` of `line`.
|
|
156
|
+
def moved?(line, column, registers)
|
|
157
|
+
line > registers[9] || (line == registers[9] && column > registers[1])
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# The discrete video's line in the frame, in xpet's fixed rows: the
|
|
161
|
+
# rows show until line 200, vertical sync runs from row 29 for 16
|
|
162
|
+
# lines, and the 4 lines past row 31 are the vertical adjust.
|
|
163
|
+
def discrete_beam(input)
|
|
164
|
+
cycle = ((input.int("line", 0) * DISCRETE_LINE) + input.int("column", 0) - DISCRETE_LEAD) % DISCRETE_FRAME
|
|
165
|
+
line = cycle / DISCRETE_LINE
|
|
166
|
+
row = [line >> 3, 32].min
|
|
167
|
+
adjusting = row == 32
|
|
168
|
+
raster = adjusting ? 0 : line & 0x07
|
|
169
|
+
column = cycle % DISCRETE_LINE
|
|
170
|
+
sync = line - (DISCRETE_REGISTERS[7] * 8)
|
|
171
|
+
moved = !adjusting && moved?(raster, column, DISCRETE_REGISTERS)
|
|
172
|
+
Beam.new(column:, row:, raster:, vsync: sync.between?(0, 15) ? 16 - sync : 0, shown: line < 200,
|
|
173
|
+
start: 0x1000 + ((moved ? row + 1 : row) * 40), frame_line: line)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# The beam the module holds, with the row's start as the module
|
|
177
|
+
# has it: the attribute bits latched in the high word and the
|
|
178
|
+
# offset into screen RAM, in bytes, in the low.
|
|
179
|
+
def beam(section)
|
|
180
|
+
fields = FieldReader.new(section).skip(SELECTED + 1)
|
|
181
|
+
column, row, raster = fields.bytes(3)
|
|
182
|
+
fields.skip(3)
|
|
183
|
+
latched = fields.word
|
|
184
|
+
offset = fields.word
|
|
185
|
+
vsync = fields.byte
|
|
186
|
+
fields.skip(1)
|
|
187
|
+
shown = fields.flag?
|
|
188
|
+
fields.skip(12)
|
|
189
|
+
Beam.new(column:, row:, raster:, vsync:, shown:, start: (latched << 16) | offset,
|
|
190
|
+
frame_line: fields.word)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def registers(section) = FieldReader.new(section).skip(SETTINGS.length + 5).bytes(REGISTERS)
|
|
194
|
+
|
|
195
|
+
def selected(section) = FieldReader.new(section).skip(SELECTED).byte
|
|
196
|
+
|
|
197
|
+
# How many cycles into its line xpet's beam is. A beam whose line
|
|
198
|
+
# has moved on a cycle before it starts holds -1.
|
|
199
|
+
def column_of(section)
|
|
200
|
+
column = beam(section).column
|
|
201
|
+
column < 0x80 ? column : column - 0x100
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# The CRTC's fields by their BL-CRTC keys at the start of the line
|
|
205
|
+
# the module's beam is in (#column_of), in a keyed module's writer,
|
|
206
|
+
# for a board that reads `columns` bytes a character with
|
|
207
|
+
# `attributes` latched from the frame's start.
|
|
208
|
+
def import(section, out, columns, attributes)
|
|
209
|
+
registers = registers(section)
|
|
210
|
+
beam = beam(section)
|
|
211
|
+
rows = registers[4] + 1
|
|
212
|
+
adjusting = beam.row >= rows
|
|
213
|
+
line = adjusting ? beam.frame_line - (rows * (registers[9] + 1)) : beam.raster
|
|
214
|
+
start = start_address(beam.start, registers, columns, attributes)
|
|
215
|
+
start = (start - registers[1]) & 0x3fff if !adjusting && moved?(line, column_of(section), registers)
|
|
216
|
+
out.bytes("registers", registers.first(Chips::CRTC::MASKS.length)).int("selected", selected(section) & 0x1f)
|
|
217
|
+
out.int("column", 0).int("line", [line, 0].max).int("row", adjusting ? rows - 1 : beam.row)
|
|
218
|
+
out.int("since_hsync", registers[0] + 1 - registers[2]).int("vsync_lines", beam.vsync)
|
|
219
|
+
out.bool("adjusting", adjusting).bool("row_display", beam.shown).bool("column_display", true)
|
|
220
|
+
out.int("row_start", start).int("address", start)
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# The row's start address from the module's (#beam): the bits
|
|
224
|
+
# that pick screen RAM from its offset, the attribute bits the
|
|
225
|
+
# board latches from its high word, and those above from R12.
|
|
226
|
+
def start_address(start, registers, columns, attributes)
|
|
227
|
+
high = (registers[12] << 8) & HIGH_BITS & ~attributes
|
|
228
|
+
high | ((start >> 16) & attributes) | (((start & 0xffff) / columns) & SCREEN_BITS)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# The discrete video's fields by their BL-VIDEO keys, in a keyed
|
|
232
|
+
# module's writer.
|
|
233
|
+
def import_discrete(section, out)
|
|
234
|
+
cycle = ((beam(section).frame_line * DISCRETE_LINE) + column_of(section) + DISCRETE_LEAD) % DISCRETE_FRAME
|
|
235
|
+
out.int("column", cycle % DISCRETE_LINE).int("line", cycle / DISCRETE_LINE)
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|