badline 0.16.0 → 0.16.1
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 +16 -0
- data/README.md +32 -9
- data/doc/media.md +9 -0
- data/doc/snapshot-format.md +4 -2
- data/doc/snapshots.md +51 -10
- 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/frontend/menu/menu_pages.rb +11 -2
- data/lib/badline/kernal_trap/ieee.rb +3 -0
- data/lib/badline/machine.rb +3 -2
- data/lib/badline/media/pet_media.rb +5 -5
- data/lib/badline/media/true_drive.rb +19 -6
- data/lib/badline/media.rb +6 -2
- data/lib/badline/options/help.rb +8 -4
- data/lib/badline/options/table.rb +9 -3
- data/lib/badline/options/validation.rb +20 -4
- data/lib/badline/options.rb +27 -8
- data/lib/badline/pet/bus/expansion.rb +99 -5
- data/lib/badline/pet/bus.rb +30 -12
- data/lib/badline/pet/characters.rb +8 -2
- data/lib/badline/pet/crtc_video.rb +20 -7
- data/lib/badline/pet/ieee_drive.rb +76 -0
- data/lib/badline/pet/ieee_ports.rb +12 -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 +33 -15
- data/lib/badline/roms/README +33 -1
- 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/container.rb +4 -1
- data/lib/badline/snapshot/field_doc.rb +4 -3
- data/lib/badline/snapshot/image.rb +22 -11
- data/lib/badline/snapshot/pet_setup.rb +30 -13
- data/lib/badline/snapshot/vice/pet.rb +117 -0
- data/lib/badline/snapshot/vice/pet_cpu.rb +67 -0
- data/lib/badline/snapshot/vice/pet_crtc.rb +246 -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 +150 -0
- data/lib/badline/snapshot/vice/pet_via.rb +164 -0
- data/lib/badline/snapshot/vice.rb +1 -0
- data/lib/badline/version.rb +1 -1
- metadata +16 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Snapshot
|
|
5
|
+
module Vice
|
|
6
|
+
module PET
|
|
7
|
+
# PETMEM 1.3: the board, the RAM below $8000 in K and the 8096's
|
|
8
|
+
# control register at $FFF0, then the RAM, the screen RAM, 1K or 2K
|
|
9
|
+
# as the board has, or on the 8296 its 32K from $8000, an 8096's or
|
|
10
|
+
# 8296's 64K board, and 24 bytes of xpet's own settings, which name
|
|
11
|
+
# the 2001.
|
|
12
|
+
#
|
|
13
|
+
# The board is 0 for the discrete video, 1 for a 40-column CRTC, 2
|
|
14
|
+
# for an 80-column one, 3 for the SuperPET, 4 for the 8096 and 5 for
|
|
15
|
+
# the 8296. xpet's ROMs aren't in the snapshot.
|
|
16
|
+
module PETMem
|
|
17
|
+
NAME = "PETMEM"
|
|
18
|
+
MAJOR = 1
|
|
19
|
+
MINOR = 3
|
|
20
|
+
DISCRETE = 0
|
|
21
|
+
CRTC40 = 1
|
|
22
|
+
CRTC80 = 2
|
|
23
|
+
SUPERPET = 3
|
|
24
|
+
CBM8096 = 4
|
|
25
|
+
CBM8296 = 5
|
|
26
|
+
# The byte after the header's control register, as xpet writes it.
|
|
27
|
+
HEADER_END = 0x05
|
|
28
|
+
# xpet's settings at the end, but for the second byte, which is
|
|
29
|
+
# SETTINGS_2001 on a 2001.
|
|
30
|
+
SETTINGS = [0x00, 0x00, 0x00, 0x00, 0xd6, 0x01, 0x00, 0x20, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00,
|
|
31
|
+
0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00].freeze
|
|
32
|
+
SETTINGS_2001 = 0x03
|
|
33
|
+
EXPANSION = 0x10000
|
|
34
|
+
|
|
35
|
+
module_function
|
|
36
|
+
|
|
37
|
+
def reads?(section) = section.major == MAJOR && section.minor == MINOR
|
|
38
|
+
|
|
39
|
+
def board(model)
|
|
40
|
+
return CBM8296 if model.cbm8296?
|
|
41
|
+
return CBM8096 if model.expansion
|
|
42
|
+
|
|
43
|
+
case model.video
|
|
44
|
+
when :crtc40 then CRTC40
|
|
45
|
+
when :crtc80 then CRTC80
|
|
46
|
+
else DISCRETE
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def export(machine)
|
|
51
|
+
bus = machine.bus
|
|
52
|
+
expansion = bus.expansion
|
|
53
|
+
fields = FieldWriter.new.byte(board(machine.model)).byte(0).byte(machine.ram_kb)
|
|
54
|
+
fields.byte(expansion ? expansion.control : 0).byte(HEADER_END)
|
|
55
|
+
fields.bytes(machine.ram.snapshot).bytes(bus.screen.cells)
|
|
56
|
+
fields.bytes(expansion.cells) if expansion
|
|
57
|
+
settings = SETTINGS.dup
|
|
58
|
+
settings[1] = SETTINGS_2001 if machine.model.basic1?
|
|
59
|
+
fields.bytes(settings).section(NAME, MAJOR, MINOR)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# The board's number in the header.
|
|
63
|
+
def board_of(section) = FieldReader.new(section).byte
|
|
64
|
+
|
|
65
|
+
def ram_kb(section) = FieldReader.new(section).skip(2).byte
|
|
66
|
+
|
|
67
|
+
# Whether xpet's settings at the end name a 2001.
|
|
68
|
+
def pet2001?(section)
|
|
69
|
+
data = section.data
|
|
70
|
+
data.bytesize >= SETTINGS.length && data.getbyte(data.bytesize - SETTINGS.length + 1).to_i.anybits?(0x01)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# The RAM, the screen RAM and an 8096's or 8296's board and control
|
|
74
|
+
# register
|
|
75
|
+
# by their BL-RAM keys, in a keyed module's writer, for a machine
|
|
76
|
+
# with `screen_bytes` of screen RAM.
|
|
77
|
+
def import(section, out, screen_bytes)
|
|
78
|
+
fields = FieldReader.new(section)
|
|
79
|
+
board = fields.byte
|
|
80
|
+
fields.skip(1)
|
|
81
|
+
ram_kb = fields.byte
|
|
82
|
+
control = fields.byte
|
|
83
|
+
fields.skip(1)
|
|
84
|
+
out.bytes("ram", fields.string(ram_kb * 1024)).bytes("screen", fields.string(screen_bytes))
|
|
85
|
+
return unless [CBM8096, CBM8296].include?(board)
|
|
86
|
+
|
|
87
|
+
out.int("expansion.control", control).bytes("expansion.ram", fields.string(EXPANSION))
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Snapshot
|
|
5
|
+
module Vice
|
|
6
|
+
module PET
|
|
7
|
+
# PIA1 and PIA2 1.0: port A's output and direction registers and
|
|
8
|
+
# its control register as read, with the CA1 and CA2 flags in bits 7
|
|
9
|
+
# and 6, the same for port B, and the levels on CA2 and CB2 in bits
|
|
10
|
+
# 7 and 6 of the last byte, high while a line is an input.
|
|
11
|
+
#
|
|
12
|
+
# Read: each side's flags come from its control register, and a
|
|
13
|
+
# handshake under way from the level its C2 output is at. The levels
|
|
14
|
+
# outside on CA1 and CB1 aren't saved: they stay as the machine has
|
|
15
|
+
# them, with PIA 1's CB1 on the vertical drive line.
|
|
16
|
+
module PIAs
|
|
17
|
+
NAMES = %w[PIA1 PIA2].freeze
|
|
18
|
+
MAJOR = 1
|
|
19
|
+
MINOR = 0
|
|
20
|
+
CA2_HIGH = 0x80
|
|
21
|
+
CB2_HIGH = 0x40
|
|
22
|
+
HANDSHAKE = 0x20
|
|
23
|
+
|
|
24
|
+
module_function
|
|
25
|
+
|
|
26
|
+
def reads?(section) = section.major == MAJOR && section.minor == MINOR
|
|
27
|
+
|
|
28
|
+
# The PIA's module, from its BL-PIA1 or BL-PIA2 fields in `input`.
|
|
29
|
+
def export(name, pia, input)
|
|
30
|
+
fields = FieldWriter.new.byte(input.int("ora", 0)).byte(input.int("ddra", 0)).byte(pia.cra)
|
|
31
|
+
fields.byte(input.int("orb", 0)).byte(input.int("ddrb", 0)).byte(pia.crb)
|
|
32
|
+
fields.byte((pia.ca2_output ? CA2_HIGH : 0) | (pia.cb2_output ? CB2_HIGH : 0))
|
|
33
|
+
fields.section(name, MAJOR, MINOR)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# The registers and the control lines by their BL-PIA keys, in a
|
|
37
|
+
# keyed module's writer.
|
|
38
|
+
def import(section, out)
|
|
39
|
+
ora, ddra, cra, orb, ddrb, crb, lines = FieldReader.new(section).bytes(7)
|
|
40
|
+
out.int("ora", ora).int("ddra", ddra).int("orb", orb).int("ddrb", ddrb)
|
|
41
|
+
control_lines(out, "ca.", cra, lines.anybits?(CA2_HIGH))
|
|
42
|
+
control_lines(out, "cb.", crb, lines.anybits?(CB2_HIGH))
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def control_lines(out, prefix, register, c2_high)
|
|
46
|
+
control = register & 0x3f
|
|
47
|
+
out.int("#{prefix}control", control).bool("#{prefix}c1_flag", register.anybits?(0x80))
|
|
48
|
+
out.bool("#{prefix}c2_flag", register.anybits?(0x40)).int("#{prefix}pulse", 0)
|
|
49
|
+
out.bool("#{prefix}handshake_low", control & 0x38 == HANDSHAKE && !c2_high)
|
|
50
|
+
out.bool("#{prefix}c2_high", c2_high) if control.nobits?(0x20)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Snapshot
|
|
5
|
+
module Vice
|
|
6
|
+
module PET
|
|
7
|
+
# Restores a PET from a snapshot xpet wrote. The modules badline
|
|
8
|
+
# reads become the PET's own keyed modules (Keyed), which it loads
|
|
9
|
+
# as it loads its own snapshot. Whatever they don't set stays as the
|
|
10
|
+
# machine has it at power-on, and the datasettes' tapes and the
|
|
11
|
+
# disk device 8 serves stay as they are.
|
|
12
|
+
module Restore
|
|
13
|
+
# MAINCPU and PETMEM hold the machine itself, so a version badline
|
|
14
|
+
# doesn't read fails the restore. The others are left out and
|
|
15
|
+
# reported.
|
|
16
|
+
READ = [MainCPU::NAME, PETMem::NAME, CRTC::NAME, "PIA1", "PIA2", VIA::NAME].freeze
|
|
17
|
+
# The host's media, which a restore keeps.
|
|
18
|
+
KEPT = %w[BL-TAPE1 BL-TAPE2 BL-TRAPDOS].freeze
|
|
19
|
+
|
|
20
|
+
module_function
|
|
21
|
+
|
|
22
|
+
# Applies the modules badline reads to `computer`, and returns a
|
|
23
|
+
# Report. The snapshot goes into a new machine first, so one that
|
|
24
|
+
# fails leaves `computer` as it was, and one of a machine built
|
|
25
|
+
# another way fails too.
|
|
26
|
+
def import(container, computer)
|
|
27
|
+
unless computer.family == :pet
|
|
28
|
+
raise FormatError, "the snapshot is of a PET, not a #{Image::FAMILIES.fetch(computer.family.to_s)}"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
setup = PET.setup(container)
|
|
32
|
+
ours = PETSetup.of(computer)
|
|
33
|
+
raise FormatError, "the snapshot is of a #{setup}, not a #{ours}" unless setup == ours
|
|
34
|
+
|
|
35
|
+
apply(container, setup.build)
|
|
36
|
+
computer.power_cycle!
|
|
37
|
+
report = apply(container, computer)
|
|
38
|
+
kept = computer.mounted? ? ["the disk mounted in device 8 stays mounted"] : []
|
|
39
|
+
Report.new(applied: report.applied, ignored: report.ignored + kept)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Applies the modules badline reads to `computer`, a machine built
|
|
43
|
+
# as the snapshot's was, and returns the Report.
|
|
44
|
+
def apply(container, computer)
|
|
45
|
+
applied = []
|
|
46
|
+
ignored = []
|
|
47
|
+
sections = []
|
|
48
|
+
READ.each do |name|
|
|
49
|
+
section = container[name]
|
|
50
|
+
next if section.nil?
|
|
51
|
+
|
|
52
|
+
if reads?(section)
|
|
53
|
+
applied << name
|
|
54
|
+
else
|
|
55
|
+
raise FormatError, "#{section}: badline doesn't read this version" if required?(name)
|
|
56
|
+
|
|
57
|
+
ignored << "#{section}: badline doesn't read this version, left out"
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
computer.save_modules.each { |section| sections << section if KEPT.include?(section.name) }
|
|
61
|
+
computer.load_modules(Keyed::Modules.new(modules(container, computer, applied) + sections))
|
|
62
|
+
Report.new(applied:, ignored: ignored + left_out(container))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def required?(name) = [MainCPU::NAME, PETMem::NAME].include?(name)
|
|
66
|
+
|
|
67
|
+
def reads?(section)
|
|
68
|
+
case section.name
|
|
69
|
+
when MainCPU::NAME then MainCPU.reads?(section)
|
|
70
|
+
when PETMem::NAME then PETMem.reads?(section)
|
|
71
|
+
when CRTC::NAME then CRTC.reads?(section)
|
|
72
|
+
when VIA::NAME then VIA.reads?(section)
|
|
73
|
+
else PIAs.reads?(section)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# The PET's keyed modules from the ones `applied` names.
|
|
78
|
+
def modules(container, computer, applied)
|
|
79
|
+
model = computer.model
|
|
80
|
+
crtc = applied.include?(CRTC::NAME) ? container[CRTC::NAME] : nil
|
|
81
|
+
video = video(crtc, computer)
|
|
82
|
+
drive = driving?(crtc, video, model)
|
|
83
|
+
sections = [Keyed.section("BL-MACHINE") { |out| machine(out, container, computer, drive) },
|
|
84
|
+
Keyed.section("BL-RAM") do |out|
|
|
85
|
+
PETMem.import(container[PETMem::NAME], out, model.screen_bytes)
|
|
86
|
+
end]
|
|
87
|
+
sections << Keyed.section("BL-CPU") { |out| MainCPU.import(container[MainCPU::NAME], out) }
|
|
88
|
+
%w[PIA1 PIA2].each do |name|
|
|
89
|
+
next unless applied.include?(name)
|
|
90
|
+
|
|
91
|
+
sections << Keyed.section("BL-#{name}") do |out|
|
|
92
|
+
PIAs.import(container[name], out)
|
|
93
|
+
out.bool("cb.c1_high", drive) if name == "PIA1"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
if applied.include?(VIA::NAME)
|
|
97
|
+
sections << Keyed.section("BL-VIA") { |out| VIA.import(container[VIA::NAME], out) }
|
|
98
|
+
end
|
|
99
|
+
sections + video
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def machine(out, container, computer, drive)
|
|
103
|
+
out.text("family", "pet")
|
|
104
|
+
PETSetup.of(computer).write_fields(out)
|
|
105
|
+
out.int("cycles", FieldReader.new(container[MainCPU::NAME]).qword).bool("vertical_drive", drive)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# The vertical drive line, low in the CRTC's vertical sync or past
|
|
109
|
+
# the discrete video's rows, as the video's module, `video`, has it.
|
|
110
|
+
def driving?(crtc, video, model)
|
|
111
|
+
return true if crtc.nil?
|
|
112
|
+
|
|
113
|
+
fields = Keyed::Reader.parse(video.first)
|
|
114
|
+
if model.video == :discrete
|
|
115
|
+
fields.int("line", 0) < Badline::PET::DiscreteVideo::DISPLAYED_LINES
|
|
116
|
+
else
|
|
117
|
+
fields.int("vsync_lines", 0).zero?
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# The discrete video's module, or the CRTC's, run on from xpet's
|
|
122
|
+
# counters to where badline's drops the vertical drive line on the
|
|
123
|
+
# cycle xpet's does (CRTC::CRTC_LEAD). The CRTC runs on from the
|
|
124
|
+
# start of the beam's line, or for a beam in the first cycles of
|
|
125
|
+
# its line, a frame less those cycles on, which lands on the same
|
|
126
|
+
# counters while the registers stood through the frame as they
|
|
127
|
+
# stand.
|
|
128
|
+
def video(crtc, computer)
|
|
129
|
+
return [] if crtc.nil?
|
|
130
|
+
|
|
131
|
+
model = computer.model
|
|
132
|
+
return [Keyed.section("BL-VIDEO") { |out| CRTC.import_discrete(crtc, out) }] if model.video == :discrete
|
|
133
|
+
|
|
134
|
+
counters = Keyed.section("BL-CRTC") do |out|
|
|
135
|
+
CRTC.import(crtc, out, CRTC.columns(model), CRTC.attributes(model))
|
|
136
|
+
end
|
|
137
|
+
cycles = (CRTC::CRTC_LEAD + CRTC.column_of(crtc)) % CRTC.frame_cycles(CRTC.registers(crtc))
|
|
138
|
+
fields = CRTC.run_on(computer, Keyed::Reader.parse(counters), cycles)
|
|
139
|
+
[Keyed.section("BL-CRTC") { |out| CRTC.copy(fields, out) }]
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def left_out(container)
|
|
143
|
+
container.sections.reject { |section| READ.include?(section.name) }
|
|
144
|
+
.map { |section| "#{section}: badline doesn't read this module, left out" }
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Snapshot
|
|
5
|
+
module Vice
|
|
6
|
+
module PET
|
|
7
|
+
# VIA 2.2, the 6522 at $E840: port A's and port B's output and
|
|
8
|
+
# direction registers, timer 1's latch and counter, timer 2's low
|
|
9
|
+
# and high latch, the value it was last loaded with and its counter,
|
|
10
|
+
# which timers will set their interrupt flag (timer 1 in bit 7,
|
|
11
|
+
# timer 2 in bit 6 while it counts cycles), the shift register, the
|
|
12
|
+
# ACR, the PCR, the interrupt flags and enable mask, timer 1's level
|
|
13
|
+
# on PB7 in bit 7, the shift register's clock ticks into its byte,
|
|
14
|
+
# CA2's level in bit 7, and whether timer 2's next underflow sets
|
|
15
|
+
# its flag. xpet saves each counter as a read on the next cycle
|
|
16
|
+
# finds it, where badline's holds it before that cycle counts.
|
|
17
|
+
#
|
|
18
|
+
# Written: timer 2's high latch and the value it was loaded with,
|
|
19
|
+
# which badline doesn't keep, as xpet has them before a program
|
|
20
|
+
# loads it, or while the shift register clocks off it, as its low
|
|
21
|
+
# byte reloads. Free-running, the shift register's ticks are only
|
|
22
|
+
# whether CB1 is low.
|
|
23
|
+
#
|
|
24
|
+
# Read: the registers and both timers with their latches, as they
|
|
25
|
+
# count from the next cycle, and the shift register where its clock
|
|
26
|
+
# ticks are. A load or reload under way, a shift clock tick due off
|
|
27
|
+
# timer 2 and the latched ports start afresh, and CB2's level
|
|
28
|
+
# follows from the PCR.
|
|
29
|
+
module VIA
|
|
30
|
+
NAME = "VIA"
|
|
31
|
+
MAJOR = 2
|
|
32
|
+
MINOR = 2
|
|
33
|
+
T1_ARMED = 0x80
|
|
34
|
+
T2_TIMED = 0x40
|
|
35
|
+
LEVELS = 0x60
|
|
36
|
+
# The shift register's clock ticks a byte takes, which an idle
|
|
37
|
+
# register's count stands at.
|
|
38
|
+
TICKS = 16
|
|
39
|
+
SIZE = 28
|
|
40
|
+
# The shift register's modes that clock off timer 2.
|
|
41
|
+
T2_SHIFTS = [1, 4, 5].freeze
|
|
42
|
+
|
|
43
|
+
module_function
|
|
44
|
+
|
|
45
|
+
def reads?(section) = section.major == MAJOR && section.minor == MINOR
|
|
46
|
+
|
|
47
|
+
# The VIA's module, from its BL-VIA fields in `input`.
|
|
48
|
+
def export(input)
|
|
49
|
+
fields = FieldWriter.new
|
|
50
|
+
%w[ora ddra orb ddrb].each { |key| fields.byte(input.int(key, 0)) }
|
|
51
|
+
fields.word(input.int("t1.latch", 0xffff)).word(timer1(input))
|
|
52
|
+
t2 = timer2(input)
|
|
53
|
+
latch_low = input.int("t2.latch_low", 0xff)
|
|
54
|
+
fields.byte(latch_low).byte(0xff).word(shifting?(input) ? (t2 & 0xff00) | latch_low : 0xffff).word(t2)
|
|
55
|
+
fields.byte(armed(input)).byte(input.int("sr.data", 0))
|
|
56
|
+
fields.byte(input.int("acr", 0)).byte(input.int("pcr", 0))
|
|
57
|
+
fields.byte(input.int("ifr.flags", 0)).byte(input.int("ifr.enable", 0))
|
|
58
|
+
fields.byte(input.bool("t1.pb7", true) ? 0x80 : 0)
|
|
59
|
+
fields.byte(ticks(input))
|
|
60
|
+
fields.byte(LEVELS | (input.bool("ca.c2_output", true) ? 0x80 : 0)).zeros(2)
|
|
61
|
+
fields.byte(input.bool("t2.armed", false) ? 1 : 0).zeros(2).section(NAME, MAJOR, MINOR)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Timer 1's counter as a read on the next cycle finds it: as it
|
|
65
|
+
# stands while a load holds it, the latch while it reloads, and one
|
|
66
|
+
# less otherwise.
|
|
67
|
+
def timer1(input)
|
|
68
|
+
counter = input.int("t1.counter", 0xffff)
|
|
69
|
+
return counter if input.bool("t1.hold", false)
|
|
70
|
+
return input.int("t1.latch", 0xffff) if input.bool("t1.reload", false)
|
|
71
|
+
|
|
72
|
+
(counter - 1) & 0xffff
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Timer 2's counter as a read on the next cycle finds it: as it
|
|
76
|
+
# stands while it counts pulses or a load holds it, and one less
|
|
77
|
+
# otherwise.
|
|
78
|
+
def timer2(input)
|
|
79
|
+
counter = input.int("t2.counter", 0xffff)
|
|
80
|
+
return counter if input.bool("t2.hold", false) || input.bool("t2.counting_pulses", false)
|
|
81
|
+
|
|
82
|
+
(counter - 1) & 0xffff
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# The shift register's clock ticks into its byte: two a bit, the
|
|
86
|
+
# first one dropping CB1, TICKS when idle. Free-running, its bits
|
|
87
|
+
# never run out, and only whether CB1 is low counts.
|
|
88
|
+
def ticks(input)
|
|
89
|
+
bits = input.int("sr.bits", 0)
|
|
90
|
+
return TICKS if bits.zero?
|
|
91
|
+
|
|
92
|
+
low = input.bool("sr.clock", true) ? 0 : 1
|
|
93
|
+
return low if input.int("sr.mode", 0) == 4
|
|
94
|
+
|
|
95
|
+
((8 - bits) * 2) + low
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# The shift register from its mode, data and the ticks into its
|
|
99
|
+
# byte (#ticks), with the last bit put out on CB2.
|
|
100
|
+
def shift_register(out, mode, data, ticks)
|
|
101
|
+
ticks = [ticks, TICKS].min
|
|
102
|
+
bits = ticks == TICKS ? 0 : 8 - (ticks / 2)
|
|
103
|
+
bits = 8 if mode == 4 && ticks < TICKS
|
|
104
|
+
out.int("sr.mode", mode).int("sr.data", data).int("sr.bits", bits).int("sr.delay", 0)
|
|
105
|
+
out.bool("sr.clock", ticks.even?).bool("sr.cb2", ticks.zero? || data.anybits?(0x01))
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Whether the shift register clocks off timer 2.
|
|
109
|
+
def shifting?(input) = T2_SHIFTS.include?((input.int("acr", 0) >> 2) & 0x07)
|
|
110
|
+
|
|
111
|
+
# Timer 2 sets its flag, or clocks the shift register, while it
|
|
112
|
+
# counts cycles.
|
|
113
|
+
def armed(input)
|
|
114
|
+
pulses = input.bool("t2.count_pulses", false)
|
|
115
|
+
timed = !pulses && (input.bool("t2.armed", false) || shifting?(input))
|
|
116
|
+
(input.bool("t1.armed", false) ? T1_ARMED : 0) | (timed ? T2_TIMED : 0)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# The registers, the timers and the control lines by their BL-VIA
|
|
120
|
+
# keys, in a keyed module's writer.
|
|
121
|
+
def import(section, out)
|
|
122
|
+
bytes = FieldReader.new(section).bytes(SIZE)
|
|
123
|
+
acr = bytes[0x10]
|
|
124
|
+
pcr = bytes[0x11]
|
|
125
|
+
out.int("ora", bytes[0]).int("ddra", bytes[1]).int("orb", bytes[2]).int("ddrb", bytes[3])
|
|
126
|
+
out.int("acr", acr).int("pcr", pcr)
|
|
127
|
+
timers(out, bytes, acr)
|
|
128
|
+
shift_register(out, (acr >> 2) & 0x07, bytes[0x0f], bytes[0x15])
|
|
129
|
+
out.int("ifr.flags", bytes[0x12] & 0x7f).int("ifr.enable", bytes[0x13] & 0x7f)
|
|
130
|
+
control_lines(out, "ca.", pcr & 0x0f, bytes[0x16].anybits?(0x80))
|
|
131
|
+
control_lines(out, "cb.", pcr >> 4, true)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def timers(out, bytes, acr)
|
|
135
|
+
out.int("t1.latch", bytes[4] | (bytes[5] << 8)).int("t1.counter",
|
|
136
|
+
((bytes[6] | (bytes[7] << 8)) + 1) & 0xffff)
|
|
137
|
+
out.bool("t1.hold", false)
|
|
138
|
+
out.bool("t1.reload", false).bool("t1.armed", bytes[0x0e].anybits?(T1_ARMED))
|
|
139
|
+
out.bool("t1.pb7", bytes[0x14].anybits?(0x80))
|
|
140
|
+
pulses = acr.anybits?(0x20)
|
|
141
|
+
t2 = bytes[0x0c] | (bytes[0x0d] << 8)
|
|
142
|
+
out.int("t2.latch_low", bytes[8]).int("t2.counter", pulses ? t2 : (t2 + 1) & 0xffff).bool("t2.hold", false)
|
|
143
|
+
out.bool("t2.low_reload", false).bool("t2.low_underflowed", false)
|
|
144
|
+
out.bool("t2.armed", bytes[0x19].anybits?(0x01))
|
|
145
|
+
out.bool("t2.count_pulses", pulses).bool("t2.counting_pulses", pulses)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# A handshake under way holds C2 low.
|
|
149
|
+
def control_lines(out, prefix, control, c2_high)
|
|
150
|
+
mode = control >> 1
|
|
151
|
+
handshake_low = mode == 4 && !c2_high
|
|
152
|
+
output = case mode
|
|
153
|
+
when 4 then !handshake_low
|
|
154
|
+
when 6 then false
|
|
155
|
+
else true
|
|
156
|
+
end
|
|
157
|
+
out.int("#{prefix}control", control).bool("#{prefix}handshake_low", handshake_low)
|
|
158
|
+
out.int("#{prefix}pulse", 0).bool("#{prefix}c2_output", output)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
data/lib/badline/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: badline
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.16.
|
|
4
|
+
version: 0.16.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Inge Jørgensen
|
|
@@ -314,6 +314,10 @@ files:
|
|
|
314
314
|
- lib/badline/drives/model1581/wd1772/stepping.rb
|
|
315
315
|
- lib/badline/drives/model1581/wd1772/tracks.rb
|
|
316
316
|
- lib/badline/drives/model1581/wd1772/turn.rb
|
|
317
|
+
- lib/badline/drives/model2031.rb
|
|
318
|
+
- lib/badline/drives/model2031/ieee_port.rb
|
|
319
|
+
- lib/badline/drives/model2031/keyed_state.rb
|
|
320
|
+
- lib/badline/drives/model2031/parts.rb
|
|
317
321
|
- lib/badline/drives/serial_bus.rb
|
|
318
322
|
- lib/badline/ffi.rb
|
|
319
323
|
- lib/badline/frontend.rb
|
|
@@ -428,6 +432,7 @@ files:
|
|
|
428
432
|
- lib/badline/pet/cpu.rb
|
|
429
433
|
- lib/badline/pet/crtc_video.rb
|
|
430
434
|
- lib/badline/pet/discrete_video.rb
|
|
435
|
+
- lib/badline/pet/ieee_drive.rb
|
|
431
436
|
- lib/badline/pet/ieee_ports.rb
|
|
432
437
|
- lib/badline/pet/ieee_traps.rb
|
|
433
438
|
- lib/badline/pet/keyboard_ports.rb
|
|
@@ -469,6 +474,7 @@ files:
|
|
|
469
474
|
- lib/badline/roms/dos1551.rom
|
|
470
475
|
- lib/badline/roms/dos1571.rom
|
|
471
476
|
- lib/badline/roms/dos1581.rom
|
|
477
|
+
- lib/badline/roms/dos2031.rom
|
|
472
478
|
- lib/badline/roms/eapi/LICENSE.md
|
|
473
479
|
- lib/badline/roms/eapi/README
|
|
474
480
|
- lib/badline/roms/eapi/eapi-am29f040-14
|
|
@@ -478,6 +484,7 @@ files:
|
|
|
478
484
|
- lib/badline/roms/pet/basic1.rom
|
|
479
485
|
- lib/badline/roms/pet/basic2.rom
|
|
480
486
|
- lib/badline/roms/pet/basic4.rom
|
|
487
|
+
- lib/badline/roms/pet/characters-din.rom
|
|
481
488
|
- lib/badline/roms/pet/characters1.rom
|
|
482
489
|
- lib/badline/roms/pet/characters2.rom
|
|
483
490
|
- lib/badline/roms/pet/editor1.rom
|
|
@@ -486,6 +493,7 @@ files:
|
|
|
486
493
|
- lib/badline/roms/pet/editor4-40-n-50hz.rom
|
|
487
494
|
- lib/badline/roms/pet/editor4-40-n-60hz.rom
|
|
488
495
|
- lib/badline/roms/pet/editor4-80-b-50hz-0283.rom
|
|
496
|
+
- lib/badline/roms/pet/editor4-80-b-50hz-8296.rom
|
|
489
497
|
- lib/badline/roms/pet/editor4-80-b-50hz.rom
|
|
490
498
|
- lib/badline/roms/pet/editor4-80-b-60hz.rom
|
|
491
499
|
- lib/badline/roms/pet/editor4-b.rom
|
|
@@ -535,6 +543,13 @@ files:
|
|
|
535
543
|
- lib/badline/snapshot/vice/fields.rb
|
|
536
544
|
- lib/badline/snapshot/vice/main_cpu.rb
|
|
537
545
|
- lib/badline/snapshot/vice/peripherals.rb
|
|
546
|
+
- lib/badline/snapshot/vice/pet.rb
|
|
547
|
+
- lib/badline/snapshot/vice/pet_cpu.rb
|
|
548
|
+
- lib/badline/snapshot/vice/pet_crtc.rb
|
|
549
|
+
- lib/badline/snapshot/vice/pet_mem.rb
|
|
550
|
+
- lib/badline/snapshot/vice/pet_pias.rb
|
|
551
|
+
- lib/badline/snapshot/vice/pet_restore.rb
|
|
552
|
+
- lib/badline/snapshot/vice/pet_via.rb
|
|
538
553
|
- lib/badline/snapshot/vice/restore.rb
|
|
539
554
|
- lib/badline/snapshot/vice/reu1764.rb
|
|
540
555
|
- lib/badline/snapshot/vice/reu_fields.rb
|