badline 0.2.0 → 0.2.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 +18 -0
- data/lib/badline/address_bus.rb +8 -2
- data/lib/badline/cartridge.rb +8 -8
- data/lib/badline/cia/interrupt_register.rb +20 -6
- data/lib/badline/cia.rb +32 -17
- data/lib/badline/computer.rb +32 -7
- data/lib/badline/cpu/microcode.rb +41 -43
- data/lib/badline/cpu.rb +1 -1
- data/lib/badline/kernal_trap/channel.rb +21 -3
- data/lib/badline/kernal_trap/drive/status.rb +49 -0
- data/lib/badline/kernal_trap/drive.rb +86 -48
- data/lib/badline/kernal_trap/file.rb +1 -1
- data/lib/badline/kernal_trap/load.rb +87 -25
- data/lib/badline/kernal_trap/routine.rb +17 -0
- data/lib/badline/kernal_trap/save.rb +46 -14
- data/lib/badline/kernal_trap/serial.rb +34 -2
- data/lib/badline/memory.rb +5 -0
- data/lib/badline/status.rb +255 -32
- data/lib/badline/storage/d64_image.rb +6 -0
- data/lib/badline/storage/d71_image.rb +4 -0
- data/lib/badline/storage/d81_image.rb +4 -0
- data/lib/badline/storage/disk_image.rb +56 -17
- data/lib/badline/storage/host_directory.rb +13 -1
- data/lib/badline/storage/sid_file.rb +1 -1
- data/lib/badline/version.rb +1 -1
- data/lib/badline/vic.rb +18 -8
- metadata +2 -1
data/lib/badline/status.rb
CHANGED
|
@@ -1,41 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Badline
|
|
4
|
+
# A register of flag bits. +flags+ names each bit from bit 0 up: a
|
|
5
|
+
# symbol for a flag, or 0 or 1 for a bit that always reads as that. The
|
|
6
|
+
# subclasses below carry the accessors for each register layout.
|
|
4
7
|
class Status
|
|
5
8
|
attr_reader :value, :flags, :bitmask, :low_mask, :high_mask
|
|
6
9
|
|
|
7
|
-
class << self
|
|
8
|
-
# Each flag layout gets a subclass of its own, with the flag accessors
|
|
9
|
-
# compiled as ordinary methods rather than closures.
|
|
10
|
-
def new(flags = [], value: 0x0)
|
|
11
|
-
return super unless equal?(Status)
|
|
12
|
-
|
|
13
|
-
layout(flags).new(flags, value:)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
private
|
|
17
|
-
|
|
18
|
-
def layout(flags)
|
|
19
|
-
@layouts ||= {}
|
|
20
|
-
@layouts[flags] ||= Class.new(Status) { define_accessors(flags) }
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def define_accessors(flags)
|
|
24
|
-
flags.each_with_index do |name, i|
|
|
25
|
-
next unless name.is_a?(Symbol)
|
|
26
|
-
|
|
27
|
-
mask = 1 << i
|
|
28
|
-
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
|
29
|
-
def #{name}=(enabled) # def carry=(enabled)
|
|
30
|
-
@value = enabled && enabled != 0 ? @value | #{mask} : @value & #{~mask} # @value = ... | 0x01 : ... & ~0x01
|
|
31
|
-
end # end
|
|
32
|
-
def #{name}? = @value & #{mask} != 0 # def carry? = @value & 0x01 != 0
|
|
33
|
-
def #{name} = @value & #{mask} == 0 ? 0 : 1 # def carry = ... ? 0 : 1
|
|
34
|
-
RUBY
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
10
|
def initialize(flags = [], value: 0x0)
|
|
40
11
|
@flags = flags
|
|
41
12
|
|
|
@@ -58,4 +29,256 @@ module Badline
|
|
|
58
29
|
end
|
|
59
30
|
end
|
|
60
31
|
end
|
|
32
|
+
|
|
33
|
+
# The 6510 processor status register.
|
|
34
|
+
class CPUStatus < Status
|
|
35
|
+
def carry=(enabled)
|
|
36
|
+
@value = enabled && enabled != 0 ? @value | 0x01 : @value & ~0x01
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def carry? = @value & 0x01 != 0
|
|
40
|
+
|
|
41
|
+
def carry = @value.nobits?(0x01) ? 0 : 1
|
|
42
|
+
|
|
43
|
+
def zero=(enabled)
|
|
44
|
+
@value = enabled && enabled != 0 ? @value | 0x02 : @value & ~0x02
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def zero? = @value & 0x02 != 0
|
|
48
|
+
|
|
49
|
+
def zero = @value.nobits?(0x02) ? 0 : 1
|
|
50
|
+
|
|
51
|
+
def interrupt=(enabled)
|
|
52
|
+
@value = enabled && enabled != 0 ? @value | 0x04 : @value & ~0x04
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def interrupt? = @value & 0x04 != 0
|
|
56
|
+
|
|
57
|
+
def interrupt = @value.nobits?(0x04) ? 0 : 1
|
|
58
|
+
|
|
59
|
+
def decimal=(enabled)
|
|
60
|
+
@value = enabled && enabled != 0 ? @value | 0x08 : @value & ~0x08
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def decimal? = @value & 0x08 != 0
|
|
64
|
+
|
|
65
|
+
def decimal = @value.nobits?(0x08) ? 0 : 1
|
|
66
|
+
|
|
67
|
+
def break=(enabled)
|
|
68
|
+
@value = enabled && enabled != 0 ? @value | 0x10 : @value & ~0x10
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def break? = @value & 0x10 != 0
|
|
72
|
+
|
|
73
|
+
def break = @value.nobits?(0x10) ? 0 : 1
|
|
74
|
+
|
|
75
|
+
def overflow=(enabled)
|
|
76
|
+
@value = enabled && enabled != 0 ? @value | 0x40 : @value & ~0x40
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def overflow? = @value & 0x40 != 0
|
|
80
|
+
|
|
81
|
+
def overflow = @value.nobits?(0x40) ? 0 : 1
|
|
82
|
+
|
|
83
|
+
def negative=(enabled)
|
|
84
|
+
@value = enabled && enabled != 0 ? @value | 0x80 : @value & ~0x80
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def negative? = @value & 0x80 != 0
|
|
88
|
+
|
|
89
|
+
def negative = @value.nobits?(0x80) ? 0 : 1
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# The 6510 I/O port at $01.
|
|
93
|
+
class PortStatus < Status
|
|
94
|
+
def basic=(enabled)
|
|
95
|
+
@value = enabled && enabled != 0 ? @value | 0x01 : @value & ~0x01
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def basic? = @value & 0x01 != 0
|
|
99
|
+
|
|
100
|
+
def basic = @value.nobits?(0x01) ? 0 : 1
|
|
101
|
+
|
|
102
|
+
def kernal=(enabled)
|
|
103
|
+
@value = enabled && enabled != 0 ? @value | 0x02 : @value & ~0x02
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def kernal? = @value & 0x02 != 0
|
|
107
|
+
|
|
108
|
+
def kernal = @value.nobits?(0x02) ? 0 : 1
|
|
109
|
+
|
|
110
|
+
def io=(enabled)
|
|
111
|
+
@value = enabled && enabled != 0 ? @value | 0x04 : @value & ~0x04
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def io? = @value & 0x04 != 0
|
|
115
|
+
|
|
116
|
+
def io = @value.nobits?(0x04) ? 0 : 1
|
|
117
|
+
|
|
118
|
+
def tape_out=(enabled)
|
|
119
|
+
@value = enabled && enabled != 0 ? @value | 0x08 : @value & ~0x08
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def tape_out? = @value & 0x08 != 0
|
|
123
|
+
|
|
124
|
+
def tape_out = @value.nobits?(0x08) ? 0 : 1
|
|
125
|
+
|
|
126
|
+
def tape_switch=(enabled)
|
|
127
|
+
@value = enabled && enabled != 0 ? @value | 0x10 : @value & ~0x10
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def tape_switch? = @value & 0x10 != 0
|
|
131
|
+
|
|
132
|
+
def tape_switch = @value.nobits?(0x10) ? 0 : 1
|
|
133
|
+
|
|
134
|
+
def tape_motor=(enabled)
|
|
135
|
+
@value = enabled && enabled != 0 ? @value | 0x20 : @value & ~0x20
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def tape_motor? = @value & 0x20 != 0
|
|
139
|
+
|
|
140
|
+
def tape_motor = @value.nobits?(0x20) ? 0 : 1
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# A CIA timer control register, CRA or CRB. Bits 5-7 differ between the two.
|
|
144
|
+
class ControlRegister < Status
|
|
145
|
+
def start=(enabled)
|
|
146
|
+
@value = enabled && enabled != 0 ? @value | 0x01 : @value & ~0x01
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def start? = @value & 0x01 != 0
|
|
150
|
+
|
|
151
|
+
def start = @value.nobits?(0x01) ? 0 : 1
|
|
152
|
+
|
|
153
|
+
def output=(enabled)
|
|
154
|
+
@value = enabled && enabled != 0 ? @value | 0x02 : @value & ~0x02
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def output? = @value & 0x02 != 0
|
|
158
|
+
|
|
159
|
+
def output = @value.nobits?(0x02) ? 0 : 1
|
|
160
|
+
|
|
161
|
+
def out_mode=(enabled)
|
|
162
|
+
@value = enabled && enabled != 0 ? @value | 0x04 : @value & ~0x04
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def out_mode? = @value & 0x04 != 0
|
|
166
|
+
|
|
167
|
+
def out_mode = @value.nobits?(0x04) ? 0 : 1
|
|
168
|
+
|
|
169
|
+
def run_mode=(enabled)
|
|
170
|
+
@value = enabled && enabled != 0 ? @value | 0x08 : @value & ~0x08
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def run_mode? = @value & 0x08 != 0
|
|
174
|
+
|
|
175
|
+
def run_mode = @value.nobits?(0x08) ? 0 : 1
|
|
176
|
+
|
|
177
|
+
def load=(enabled)
|
|
178
|
+
@value = enabled && enabled != 0 ? @value | 0x10 : @value & ~0x10
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def load? = @value & 0x10 != 0
|
|
182
|
+
|
|
183
|
+
def load = @value.nobits?(0x10) ? 0 : 1
|
|
184
|
+
|
|
185
|
+
def in_mode=(enabled)
|
|
186
|
+
@value = enabled && enabled != 0 ? @value | 0x20 : @value & ~0x20
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def in_mode? = @value & 0x20 != 0
|
|
190
|
+
|
|
191
|
+
def in_mode = @value.nobits?(0x20) ? 0 : 1
|
|
192
|
+
|
|
193
|
+
def serial_mode=(enabled)
|
|
194
|
+
@value = enabled && enabled != 0 ? @value | 0x40 : @value & ~0x40
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def serial_mode? = @value & 0x40 != 0
|
|
198
|
+
|
|
199
|
+
def serial_mode = @value.nobits?(0x40) ? 0 : 1
|
|
200
|
+
|
|
201
|
+
def clock_frequency=(enabled)
|
|
202
|
+
@value = enabled && enabled != 0 ? @value | 0x80 : @value & ~0x80
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def clock_frequency? = @value & 0x80 != 0
|
|
206
|
+
|
|
207
|
+
def clock_frequency = @value.nobits?(0x80) ? 0 : 1
|
|
208
|
+
|
|
209
|
+
def in_cnt=(enabled)
|
|
210
|
+
@value = enabled && enabled != 0 ? @value | 0x20 : @value & ~0x20
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def in_cnt? = @value & 0x20 != 0
|
|
214
|
+
|
|
215
|
+
def in_cnt = @value.nobits?(0x20) ? 0 : 1
|
|
216
|
+
|
|
217
|
+
def in_timer_a=(enabled)
|
|
218
|
+
@value = enabled && enabled != 0 ? @value | 0x40 : @value & ~0x40
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def in_timer_a? = @value & 0x40 != 0
|
|
222
|
+
|
|
223
|
+
def in_timer_a = @value.nobits?(0x40) ? 0 : 1
|
|
224
|
+
|
|
225
|
+
def alarm=(enabled)
|
|
226
|
+
@value = enabled && enabled != 0 ? @value | 0x80 : @value & ~0x80
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def alarm? = @value & 0x80 != 0
|
|
230
|
+
|
|
231
|
+
def alarm = @value.nobits?(0x80) ? 0 : 1
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# The CIA interrupt sources, as flags or as their mask.
|
|
235
|
+
class InterruptFlags < Status
|
|
236
|
+
def timer_a=(enabled)
|
|
237
|
+
@value = enabled && enabled != 0 ? @value | 0x01 : @value & ~0x01
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def timer_a? = @value & 0x01 != 0
|
|
241
|
+
|
|
242
|
+
def timer_a = @value.nobits?(0x01) ? 0 : 1
|
|
243
|
+
|
|
244
|
+
def timer_b=(enabled)
|
|
245
|
+
@value = enabled && enabled != 0 ? @value | 0x02 : @value & ~0x02
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def timer_b? = @value & 0x02 != 0
|
|
249
|
+
|
|
250
|
+
def timer_b = @value.nobits?(0x02) ? 0 : 1
|
|
251
|
+
|
|
252
|
+
def alarm=(enabled)
|
|
253
|
+
@value = enabled && enabled != 0 ? @value | 0x04 : @value & ~0x04
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def alarm? = @value & 0x04 != 0
|
|
257
|
+
|
|
258
|
+
def alarm = @value.nobits?(0x04) ? 0 : 1
|
|
259
|
+
|
|
260
|
+
def serial=(enabled)
|
|
261
|
+
@value = enabled && enabled != 0 ? @value | 0x08 : @value & ~0x08
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def serial? = @value & 0x08 != 0
|
|
265
|
+
|
|
266
|
+
def serial = @value.nobits?(0x08) ? 0 : 1
|
|
267
|
+
|
|
268
|
+
def flag=(enabled)
|
|
269
|
+
@value = enabled && enabled != 0 ? @value | 0x10 : @value & ~0x10
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def flag? = @value & 0x10 != 0
|
|
273
|
+
|
|
274
|
+
def flag = @value.nobits?(0x10) ? 0 : 1
|
|
275
|
+
|
|
276
|
+
def interrupt=(enabled)
|
|
277
|
+
@value = enabled && enabled != 0 ? @value | 0x80 : @value & ~0x80
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def interrupt? = @value & 0x80 != 0
|
|
281
|
+
|
|
282
|
+
def interrupt = @value.nobits?(0x80) ? 0 : 1
|
|
283
|
+
end
|
|
61
284
|
end
|
|
@@ -3,8 +3,14 @@
|
|
|
3
3
|
module Badline
|
|
4
4
|
module Storage
|
|
5
5
|
class D64Image < DiskImage
|
|
6
|
+
# Image sizes with an error table, mapped to its length: 35 tracks
|
|
7
|
+
# (174848 bytes without one), 40 tracks (196608) and 42 tracks (205312)
|
|
8
|
+
ERROR_TABLES = { 175_531 => 683, 197_376 => 768, 206_114 => 802 }.freeze
|
|
9
|
+
|
|
6
10
|
private
|
|
7
11
|
|
|
12
|
+
def error_tables = ERROR_TABLES
|
|
13
|
+
|
|
8
14
|
def directory_track = 18
|
|
9
15
|
def directory_sector = 1
|
|
10
16
|
|
|
@@ -21,13 +21,27 @@ module Badline
|
|
|
21
21
|
# A LOAD reads only PRG files. An OPEN names the type it wants, or
|
|
22
22
|
# takes the first file of any type with a nil `type`.
|
|
23
23
|
def read_file(name, type: :prg)
|
|
24
|
-
|
|
25
|
-
entry = entries.find do |e|
|
|
26
|
-
(type.nil? || e[:type] == type) && pattern.match?(e[:name])
|
|
27
|
-
end
|
|
24
|
+
entry = find_entry(name, type)
|
|
28
25
|
read_chain(entry[:track], entry[:sector]) if entry
|
|
29
26
|
end
|
|
30
27
|
|
|
28
|
+
# The first block in a file's chain that the error table marks bad:
|
|
29
|
+
# its DOS error, its track and sector, and how many of the file's
|
|
30
|
+
# bytes come before it. Nil when the whole chain reads cleanly.
|
|
31
|
+
def read_error(name, type: :prg)
|
|
32
|
+
entry = find_entry(name, type)
|
|
33
|
+
return unless @errors && entry
|
|
34
|
+
|
|
35
|
+
offset = 0
|
|
36
|
+
each_sector(entry[:track], entry[:sector]) do |data, track, sector|
|
|
37
|
+
error = block_error(track, sector)
|
|
38
|
+
return { error:, track:, sector:, offset: } if error
|
|
39
|
+
|
|
40
|
+
offset += data[0].zero? ? data[1] - 1 : SECTOR_SIZE - 2
|
|
41
|
+
end
|
|
42
|
+
nil
|
|
43
|
+
end
|
|
44
|
+
|
|
31
45
|
# Raw block access for the DOS `U1` command. Returns nil for blocks
|
|
32
46
|
# outside the image's geometry.
|
|
33
47
|
def read_block(track, sector)
|
|
@@ -44,15 +58,30 @@ module Badline
|
|
|
44
58
|
DOS_ERRORS[@errors[track_offset(track) + sector]]
|
|
45
59
|
end
|
|
46
60
|
|
|
61
|
+
# The block holding the disk name and ID, at the start of the
|
|
62
|
+
# directory track.
|
|
63
|
+
def header_block = [directory_track, 0]
|
|
64
|
+
|
|
65
|
+
# The directory block a new file's entry goes into: the first with a
|
|
66
|
+
# free slot, or the last one when every slot is taken.
|
|
67
|
+
def new_entry_block
|
|
68
|
+
last = nil
|
|
69
|
+
each_sector(directory_track, directory_sector) do |data, track, sector|
|
|
70
|
+
return [track, sector] if (0...ENTRIES_PER_SECTOR).any? { |i| data[(i * ENTRY_SIZE) + 2].zero? }
|
|
71
|
+
|
|
72
|
+
last = [track, sector]
|
|
73
|
+
end
|
|
74
|
+
last
|
|
75
|
+
end
|
|
76
|
+
|
|
47
77
|
private
|
|
48
78
|
|
|
49
|
-
# An error table holds one byte per block
|
|
50
|
-
#
|
|
79
|
+
# An error table holds one byte per block after the last one. The image
|
|
80
|
+
# sizes that carry one are listed exactly, since a 40-track D64 with a
|
|
81
|
+
# table is also a whole number of 256-byte blocks.
|
|
51
82
|
def split_error_table
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
@bytes.pop(@bytes.length / (SECTOR_SIZE + 1))
|
|
83
|
+
blocks = error_tables[@bytes.length]
|
|
84
|
+
@bytes.pop(blocks) if blocks
|
|
56
85
|
end
|
|
57
86
|
|
|
58
87
|
def block?(track, sector)
|
|
@@ -62,9 +91,19 @@ module Badline
|
|
|
62
91
|
sector_offset(track, sector) + SECTOR_SIZE <= @bytes.length
|
|
63
92
|
end
|
|
64
93
|
|
|
94
|
+
def find_entry(name, type)
|
|
95
|
+
pattern = Storage.matcher(name)
|
|
96
|
+
entries.find do |e|
|
|
97
|
+
(type.nil? || e[:type] == type) && pattern.match?(e[:name])
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
65
101
|
def entries
|
|
66
|
-
@entries ||=
|
|
67
|
-
|
|
102
|
+
@entries ||= begin
|
|
103
|
+
list = []
|
|
104
|
+
each_sector(directory_track, directory_sector) { |data| list.concat(parse_entries(data)) }
|
|
105
|
+
list
|
|
106
|
+
end
|
|
68
107
|
end
|
|
69
108
|
|
|
70
109
|
def parse_entries(data)
|
|
@@ -85,19 +124,19 @@ module Badline
|
|
|
85
124
|
end
|
|
86
125
|
|
|
87
126
|
def read_chain(track, sector)
|
|
88
|
-
|
|
89
|
-
|
|
127
|
+
bytes = []
|
|
128
|
+
each_sector(track, sector) do |data|
|
|
129
|
+
bytes.concat(data[0].zero? ? data[2..data[1]] : data[2..])
|
|
90
130
|
end
|
|
131
|
+
bytes
|
|
91
132
|
end
|
|
92
133
|
|
|
93
134
|
def each_sector(track, sector)
|
|
94
|
-
return to_enum(:each_sector, track, sector) unless block_given?
|
|
95
|
-
|
|
96
135
|
visited = {}
|
|
97
136
|
while track != 0 && !visited[[track, sector]]
|
|
98
137
|
visited[[track, sector]] = true
|
|
99
138
|
data = sector_at(track, sector)
|
|
100
|
-
yield data
|
|
139
|
+
yield data, track, sector
|
|
101
140
|
track, sector = data[0, 2]
|
|
102
141
|
end
|
|
103
142
|
end
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module Badline
|
|
4
4
|
module Storage
|
|
5
|
+
# A host directory served as a drive: .prg files by their host name,
|
|
6
|
+
# .p00 and .t64 entries by their embedded names. A host file that can't
|
|
7
|
+
# be read is left out, and a failed write reports false.
|
|
5
8
|
class HostDirectory
|
|
6
9
|
def initialize(path)
|
|
7
10
|
@path = path
|
|
@@ -18,6 +21,9 @@ module Badline
|
|
|
18
21
|
def write_file(name, bytes)
|
|
19
22
|
host_name = "#{name.downcase.tr('/', '_')}.prg"
|
|
20
23
|
File.binwrite(File.join(@path, host_name), bytes.pack("C*"))
|
|
24
|
+
true
|
|
25
|
+
rescue SystemCallError
|
|
26
|
+
false
|
|
21
27
|
end
|
|
22
28
|
|
|
23
29
|
private
|
|
@@ -29,6 +35,8 @@ module Badline
|
|
|
29
35
|
|
|
30
36
|
def entries
|
|
31
37
|
Dir.children(@path).sort.flat_map { |f| entry_for(f) }.compact
|
|
38
|
+
rescue SystemCallError
|
|
39
|
+
[]
|
|
32
40
|
end
|
|
33
41
|
|
|
34
42
|
def entry_for(file)
|
|
@@ -45,18 +53,22 @@ module Badline
|
|
|
45
53
|
def p00_entry(file)
|
|
46
54
|
header = File.binread(File.join(@path, file), P00::HEADER_SIZE).bytes
|
|
47
55
|
{ name: P00.name(header), file: } if P00.wraps?(header)
|
|
56
|
+
rescue SystemCallError
|
|
57
|
+
nil
|
|
48
58
|
end
|
|
49
59
|
|
|
50
60
|
def t64_entries(file)
|
|
51
61
|
archive = T64.new(File.join(@path, file))
|
|
52
62
|
archive.names.map { |name| { name:, archive: } }
|
|
53
|
-
rescue T64::FormatError
|
|
63
|
+
rescue T64::FormatError, SystemCallError
|
|
54
64
|
nil
|
|
55
65
|
end
|
|
56
66
|
|
|
57
67
|
def file_bytes(file)
|
|
58
68
|
bytes = File.binread(File.join(@path, file)).bytes
|
|
59
69
|
P00.wraps?(bytes) ? P00.data(bytes) : bytes
|
|
70
|
+
rescue SystemCallError
|
|
71
|
+
nil
|
|
60
72
|
end
|
|
61
73
|
end
|
|
62
74
|
end
|
data/lib/badline/version.rb
CHANGED
data/lib/badline/vic.rb
CHANGED
|
@@ -57,20 +57,33 @@ module Badline
|
|
|
57
57
|
|
|
58
58
|
@width = 504
|
|
59
59
|
@height = 312
|
|
60
|
+
@columns_per_line = @width / 8
|
|
61
|
+
@last_line = @height - 1
|
|
62
|
+
@display = Array.new(@width * @height, 0)
|
|
63
|
+
@lines = Array.new(@height) { Array.new(@width, 0) }
|
|
64
|
+
@dirty_lines = Array.new(@height, true)
|
|
65
|
+
@render = true
|
|
66
|
+
|
|
67
|
+
power_on!
|
|
68
|
+
super()
|
|
69
|
+
end
|
|
60
70
|
|
|
71
|
+
# The VIC has no reset pin, so only a power cycle brings back the
|
|
72
|
+
# registers, the raster position and the fetch and sprite state it
|
|
73
|
+
# starts with. The display keeps its buffers, cleared to black.
|
|
74
|
+
def power_on!
|
|
61
75
|
@registers = VIC::Registers.new
|
|
62
76
|
@register_bytes = @registers.bytes
|
|
63
77
|
@display_state = VIC::DisplayState.new(@registers)
|
|
64
78
|
@sequencer = VIC::Sequencer.new(@width, @registers, @vic_bank)
|
|
79
|
+
@sequencer.render = @render
|
|
65
80
|
@sprites = VIC::Sprites.new(@registers, @vic_bank, @width)
|
|
66
|
-
@display
|
|
67
|
-
@lines
|
|
68
|
-
@dirty_lines
|
|
81
|
+
@display.fill(0)
|
|
82
|
+
@lines.each { |line| line.fill(0) }
|
|
83
|
+
@dirty_lines.fill(true)
|
|
69
84
|
|
|
70
85
|
@column = 0
|
|
71
86
|
@rasterline = 0
|
|
72
|
-
@columns_per_line = @width / 8
|
|
73
|
-
@last_line = @height - 1
|
|
74
87
|
|
|
75
88
|
@character_buffer = Array.new(40, 0)
|
|
76
89
|
@color_buffer = Array.new(40, 0)
|
|
@@ -87,9 +100,6 @@ module Badline
|
|
|
87
100
|
@lp_triggered = false
|
|
88
101
|
@lp_low = false
|
|
89
102
|
@raster_match = false
|
|
90
|
-
@render = true
|
|
91
|
-
|
|
92
|
-
super()
|
|
93
103
|
end
|
|
94
104
|
|
|
95
105
|
def cycle!
|
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.2.
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Inge Jørgensen
|
|
@@ -145,6 +145,7 @@ files:
|
|
|
145
145
|
- lib/badline/kernal_trap.rb
|
|
146
146
|
- lib/badline/kernal_trap/channel.rb
|
|
147
147
|
- lib/badline/kernal_trap/drive.rb
|
|
148
|
+
- lib/badline/kernal_trap/drive/status.rb
|
|
148
149
|
- lib/badline/kernal_trap/file.rb
|
|
149
150
|
- lib/badline/kernal_trap/load.rb
|
|
150
151
|
- lib/badline/kernal_trap/routine.rb
|