badline 0.1.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 +185 -0
- data/CLAUDE.md +217 -0
- data/CODE_OF_CONDUCT.md +92 -0
- data/CONTRIBUTING.md +51 -0
- data/README.md +224 -31
- data/doc/pinned-behaviour.md +1117 -0
- data/exe/badline +22 -2
- data/exe/badline-sid +34 -0
- data/lib/badline/address_bus.rb +96 -25
- data/lib/badline/audio/aiff.rb +36 -0
- data/lib/badline/audio/bare_player.rb +129 -0
- data/lib/badline/audio/cli.rb +133 -0
- data/lib/badline/audio/console.rb +75 -0
- data/lib/badline/audio/jukebox.rb +82 -0
- data/lib/badline/audio/machine_player.rb +57 -0
- data/lib/badline/audio/options.rb +137 -0
- data/lib/badline/audio/pcm_writer.rb +57 -0
- data/lib/badline/audio/playback.rb +108 -0
- data/lib/badline/audio/renderer.rb +85 -0
- data/lib/badline/audio/sdl_sink.rb +102 -0
- data/lib/badline/audio/wav.rb +23 -0
- data/lib/badline/audio.rb +14 -0
- data/lib/badline/cartridge/action_replay.rb +111 -0
- data/lib/badline/cartridge/atomic_power.rb +24 -0
- data/lib/badline/cartridge/bank.rb +81 -0
- data/lib/badline/cartridge/comal80.rb +48 -0
- data/lib/badline/cartridge/dinamic.rb +34 -0
- data/lib/badline/cartridge/easy_flash.rb +122 -0
- data/lib/badline/cartridge/epyx_fastload.rb +71 -0
- data/lib/badline/cartridge/final_cartridge3.rb +77 -0
- data/lib/badline/cartridge/flash.rb +265 -0
- data/lib/badline/cartridge/freezer.rb +31 -0
- data/lib/badline/cartridge/fun_play.rb +38 -0
- data/lib/badline/cartridge/g_mod2.rb +62 -0
- data/lib/badline/cartridge/game_system.rb +40 -0
- data/lib/badline/cartridge/kcs_power.rb +72 -0
- data/lib/badline/cartridge/mach5.rb +34 -0
- data/lib/badline/cartridge/magic_desk.rb +6 -3
- data/lib/badline/cartridge/ocean.rb +11 -12
- data/lib/badline/cartridge/pagefox.rb +56 -0
- data/lib/badline/cartridge/retro_replay.rb +276 -0
- data/lib/badline/cartridge/rex_utility.rb +33 -0
- data/lib/badline/cartridge/rgcd.rb +48 -0
- data/lib/badline/cartridge/simons_basic.rb +40 -0
- data/lib/badline/cartridge/standard.rb +3 -19
- data/lib/badline/cartridge/super_games.rb +36 -0
- data/lib/badline/cartridge/westermann.rb +34 -0
- data/lib/badline/cartridge/zaxxon.rb +50 -0
- data/lib/badline/cartridge.rb +132 -16
- data/lib/badline/cia/interrupt_register.rb +102 -0
- data/lib/badline/cia/serial.rb +219 -0
- data/lib/badline/cia/timer.rb +43 -31
- data/lib/badline/cia.rb +138 -88
- data/lib/badline/color_memory.rb +14 -5
- data/lib/badline/computer.rb +97 -12
- data/lib/badline/control_ports.rb +54 -9
- data/lib/badline/cpu/addressing.rb +131 -0
- data/lib/badline/cpu/microcode.rb +169 -0
- data/lib/badline/cpu/operations.rb +88 -0
- data/lib/badline/cpu/stack_operations.rb +82 -0
- data/lib/badline/cpu.rb +109 -168
- data/lib/badline/cycleable.rb +3 -0
- data/lib/badline/datasette.rb +81 -0
- data/lib/badline/debug_register.rb +28 -0
- data/lib/badline/gui/application.rb +79 -18
- data/lib/badline/gui/gamepads.rb +97 -0
- data/lib/badline/gui/joy_map.rb +15 -7
- data/lib/badline/gui.rb +1 -0
- data/lib/badline/input/mouse1351.rb +41 -0
- data/lib/badline/input/paddles.rb +36 -0
- data/lib/badline/input.rb +4 -0
- data/lib/badline/instruction_set/arithmetic.rb +16 -21
- data/lib/badline/instruction_set/bitwise.rb +17 -22
- data/lib/badline/instruction_set/branch.rb +20 -19
- data/lib/badline/instruction_set/flag.rb +7 -7
- data/lib/badline/instruction_set/illegal.rb +14 -22
- data/lib/badline/instruction_set/inc_dec.rb +8 -10
- data/lib/badline/instruction_set/stack.rb +5 -57
- data/lib/badline/instruction_set/transfer.rb +9 -9
- data/lib/badline/instruction_set.rb +9 -31
- data/lib/badline/interrupts.rb +104 -0
- data/lib/badline/joystick.rb +9 -9
- data/lib/badline/kernal_trap/channel.rb +51 -0
- data/lib/badline/kernal_trap/drive/status.rb +49 -0
- data/lib/badline/kernal_trap/drive.rb +277 -0
- data/lib/badline/kernal_trap/file.rb +5 -25
- data/lib/badline/kernal_trap/load.rb +86 -24
- data/lib/badline/kernal_trap/routine.rb +51 -0
- data/lib/badline/kernal_trap/save.rb +46 -14
- data/lib/badline/kernal_trap/serial.rb +171 -0
- data/lib/badline/kernal_trap.rb +4 -0
- data/lib/badline/keyboard.rb +40 -16
- data/lib/badline/media.rb +48 -10
- data/lib/badline/memory.rb +5 -0
- data/lib/badline/roms/eapi/LICENSE.md +15 -0
- data/lib/badline/roms/eapi/README +41 -0
- data/lib/badline/roms/eapi/eapi-am29f040-14 +0 -0
- data/lib/badline/sid/decimator.rb +46 -0
- data/lib/badline/sid/envelope.rb +232 -0
- data/lib/badline/sid/filter.rb +213 -0
- data/lib/badline/sid/voice.rb +61 -0
- data/lib/badline/sid/waveform/combined.rb +126 -0
- data/lib/badline/sid/waveform/fast_forward.rb +105 -0
- data/lib/badline/sid/waveform/noise_writeback.rb +82 -0
- data/lib/badline/sid/waveform.rb +289 -0
- data/lib/badline/sid.rb +274 -7
- data/lib/badline/status.rb +251 -23
- data/lib/badline/storage/crt_file.rb +18 -2
- 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 +99 -13
- data/lib/badline/storage/host_directory.rb +30 -4
- data/lib/badline/storage/sid_file.rb +274 -0
- data/lib/badline/storage/song_lengths.rb +65 -0
- data/lib/badline/storage/t64.rb +67 -0
- data/lib/badline/storage/tap.rb +68 -0
- data/lib/badline/storage.rb +19 -0
- data/lib/badline/time_of_day.rb +105 -52
- data/lib/badline/version.rb +1 -1
- data/lib/badline/vic/bank.rb +14 -6
- data/lib/badline/vic/border_mask.rb +76 -0
- data/lib/badline/vic/collisions.rb +104 -0
- data/lib/badline/vic/color_patches.rb +33 -0
- data/lib/badline/vic/display_state.rb +92 -29
- data/lib/badline/vic/graphics_mode.rb +78 -53
- data/lib/badline/vic/graphics_shifter.rb +140 -0
- data/lib/badline/vic/register_log.rb +63 -0
- data/lib/badline/vic/registers.rb +3 -0
- data/lib/badline/vic/sequencer.rb +163 -137
- data/lib/badline/vic/sequencer_output.rb +116 -0
- data/lib/badline/vic/sprite/internal_bus.rb +49 -0
- data/lib/badline/vic/sprite/shifter.rb +129 -0
- data/lib/badline/vic/sprite.rb +275 -65
- data/lib/badline/vic/sprites.rb +220 -58
- data/lib/badline/vic.rb +389 -55
- data/lib/badline.rb +5 -0
- data/vendor/.gitkeep +0 -0
- metadata +104 -4
data/lib/badline/vic/sprites.rb
CHANGED
|
@@ -1,111 +1,273 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "badline/vic/collisions"
|
|
4
|
+
require "badline/vic/register_log"
|
|
3
5
|
require "badline/vic/sprite"
|
|
4
6
|
|
|
5
7
|
module Badline
|
|
6
8
|
class VIC < Cycleable
|
|
7
9
|
class Sprites
|
|
8
|
-
#
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
# Pixels between the start of the cycle following a write and the
|
|
11
|
+
# point the new value shows. Each signal reaches the output on its own
|
|
12
|
+
# path: the colors feed the final mux, the sequencer inputs — X
|
|
13
|
+
# position, multicolor and expansion — sit furthest upstream, and the
|
|
14
|
+
# priority mux lands one pixel ahead of them.
|
|
15
|
+
COLOR_DELAY = 1
|
|
16
|
+
PRIORITY_DELAY = 6
|
|
17
|
+
SEQUENCER_DELAY = 7
|
|
18
|
+
|
|
19
|
+
# The beam position a CPU write in Bauer cycle 15 sees: the VIC has
|
|
20
|
+
# run column 13 and runs column 14, where MCBASE moves, next.
|
|
21
|
+
CRUNCH_X = 14 * 8
|
|
22
|
+
|
|
23
|
+
WRITE_DELAY = Array.new(2**6).tap do |delays|
|
|
24
|
+
(0x00..0x0e).step(2) { |reg| delays[reg] = SEQUENCER_DELAY }
|
|
25
|
+
[0x10, 0x1c, 0x1d].each { |reg| delays[reg] = SEQUENCER_DELAY }
|
|
26
|
+
delays[0x1b] = PRIORITY_DELAY
|
|
27
|
+
[0x25, 0x26, *0x27..0x2e].each { |reg| delays[reg] = COLOR_DELAY }
|
|
28
|
+
end.freeze
|
|
11
29
|
|
|
12
30
|
def initialize(registers, bank, width)
|
|
13
31
|
@registers = registers
|
|
14
32
|
@bank = bank
|
|
15
33
|
@width = width
|
|
16
|
-
@
|
|
17
|
-
@
|
|
34
|
+
@bus = Sprite::InternalBus.new(bank, width / 8)
|
|
35
|
+
@sprites = Array.new(8) { |i| Sprite.new(i, registers, bank, width, @bus) }
|
|
36
|
+
@collisions = Collisions.new(registers, width)
|
|
37
|
+
@hits = @collisions.hits
|
|
18
38
|
@win_color = Array.new(width, 0)
|
|
19
39
|
@win_priority = Array.new(width, false)
|
|
40
|
+
@palette = Array.new(4, 0)
|
|
41
|
+
@log = RegisterLog.new(registers)
|
|
42
|
+
@any_dma = false
|
|
43
|
+
@stopped_dma = false
|
|
44
|
+
@carry = Array.new(8) { [] }
|
|
45
|
+
@carry_next = Array.new(8) { [] }
|
|
46
|
+
@carried = false
|
|
47
|
+
@lo = width
|
|
48
|
+
@hi = 0
|
|
49
|
+
@sequenced = -1
|
|
20
50
|
end
|
|
21
51
|
|
|
22
52
|
def [](index) = @sprites[index]
|
|
23
53
|
|
|
24
|
-
|
|
25
|
-
|
|
54
|
+
# Pixels a sprite drew past the end of the last line land at the start
|
|
55
|
+
# of this one, which is when the beam reaches them.
|
|
56
|
+
def start_line
|
|
57
|
+
@bus.start_line(@registers[0x15].nonzero?)
|
|
58
|
+
@log.clear
|
|
59
|
+
@sprites.each(&:start_line)
|
|
60
|
+
@collisions.start_line
|
|
61
|
+
@sequenced = -1
|
|
62
|
+
@carry, @carry_next = @carry_next, @carry
|
|
63
|
+
@carry_next.each(&:clear)
|
|
64
|
+
@carried = @carry.any?(&:any?)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Bauer cycle 16, two columns ahead like the compares: MCBASE takes
|
|
68
|
+
# MC for every sprite whose expansion flip-flop is set.
|
|
69
|
+
def advance_mcbase
|
|
70
|
+
@sprites.each(&:advance_mcbase) if @any_dma
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# The end-of-sprite compare, a column after MCBASE moves. It is the
|
|
74
|
+
# only point a sprite's DMA stops, so the cached flag is settled here
|
|
75
|
+
# and set again by the compare that starts one.
|
|
76
|
+
def finish_mcbase
|
|
77
|
+
@stopped_dma = false
|
|
78
|
+
return unless @any_dma
|
|
79
|
+
|
|
80
|
+
running = @sprites.count(&:displaying?)
|
|
81
|
+
@sprites.each(&:finish_mcbase)
|
|
82
|
+
still = @sprites.count(&:displaying?)
|
|
83
|
+
@any_dma = still.positive?
|
|
84
|
+
@stopped_dma = still < running
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# True when the last #finish_mcbase ended a DMA, so the BA columns
|
|
88
|
+
# have to be rebuilt without it.
|
|
89
|
+
def stopped_dma? = @stopped_dma
|
|
90
|
+
|
|
91
|
+
# Bauer cycle 56, after the second Y compare.
|
|
92
|
+
def toggle_expansion
|
|
93
|
+
@sprites.each(&:toggle_expansion) if @any_dma
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Run the Y/enable compare (Bauer cycles 55/56) for every sprite;
|
|
97
|
+
# returns true when any sprite turned its DMA on, so the BA columns
|
|
98
|
+
# can be rebuilt mid-line.
|
|
99
|
+
def check_dma(line, column)
|
|
100
|
+
return false if @registers[0x15].zero?
|
|
101
|
+
|
|
102
|
+
hit = @sprites.map { |sprite| sprite.check_dma(line, column) }.any?
|
|
103
|
+
@any_dma ||= hit
|
|
104
|
+
hit
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Not gated on the DMA flag, since this is where a display outlives its
|
|
108
|
+
# DMA. MC now points at the next row, which a sprite firing after its
|
|
109
|
+
# reload shows, so a line sequenced before this has to be redone.
|
|
110
|
+
def check_display(line)
|
|
111
|
+
@sprites.each { |sprite| sprite.check_display(line) }
|
|
112
|
+
@sequenced = -1
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# A CPU access to a VIC register, in the cycle after the VIC's
|
|
116
|
+
# `column`.
|
|
117
|
+
def bus_data(column, value) = @bus.access(column, value)
|
|
118
|
+
|
|
119
|
+
# Not gated on the DMA flag: a row fetched at the start of the line
|
|
120
|
+
# still renders when cycle 16 ends the sprite.
|
|
121
|
+
def active? = @carried || @sprites.any?(&:rendering?)
|
|
122
|
+
|
|
123
|
+
# Record a mid-line write at the pixel where it becomes visible.
|
|
124
|
+
def log_change(reg, old, value, beam_x)
|
|
125
|
+
clear_y_expansion(old & ~value, beam_x) if reg == 0x17
|
|
126
|
+
delay = WRITE_DELAY[reg]
|
|
127
|
+
return unless delay && active?
|
|
128
|
+
|
|
129
|
+
@log.log(beam_x + delay, reg, old, value)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Latch the collisions for every sprite pixel the beam has passed
|
|
133
|
+
# since the last fold.
|
|
134
|
+
def collide_upto(beam_x, mask)
|
|
135
|
+
upto = [beam_x, @width].min
|
|
136
|
+
return if upto <= @collisions.folded
|
|
137
|
+
|
|
138
|
+
sequence_line if active?
|
|
139
|
+
@collisions.fold(mask, upto, @lo, @hi)
|
|
26
140
|
end
|
|
27
141
|
|
|
28
|
-
def
|
|
142
|
+
def clear_collision(reg, beam_x) = @collisions.clear(reg, beam_x)
|
|
29
143
|
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
@
|
|
36
|
-
|
|
37
|
-
|
|
144
|
+
# End of line: fold in the pixels the beam reached since the last
|
|
145
|
+
# read, then paint the winners over the background. A line with no
|
|
146
|
+
# background to paint over — one in the vertical blank — still
|
|
147
|
+
# collides, so `colors` is nil there rather than absent.
|
|
148
|
+
def finish_line(colors, mask)
|
|
149
|
+
collide_upto(@width, mask)
|
|
150
|
+
colors ? apply(colors, mask) : clear_coverage
|
|
151
|
+
end
|
|
38
152
|
|
|
153
|
+
private
|
|
154
|
+
|
|
155
|
+
# A $d017 write that clears MxYE acts on the flip-flop at once, rather
|
|
156
|
+
# than from a column hook, and crunches in Bauer cycle 15.
|
|
157
|
+
def clear_y_expansion(cleared, beam_x)
|
|
158
|
+
crunch = beam_x == CRUNCH_X
|
|
39
159
|
@sprites.each do |sprite|
|
|
40
|
-
|
|
160
|
+
sprite.clear_y_expansion(crunch) if cleared.anybits?(1 << sprite.index)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Replay the line for every sprite, filling the per-pixel coverage
|
|
165
|
+
# that both the fold and the composite read. A write logged later in
|
|
166
|
+
# the line can only move pixels past it, so re-running after the log
|
|
167
|
+
# grows leaves everything already folded where it was.
|
|
168
|
+
def sequence_line
|
|
169
|
+
return if @sequenced == @log.length
|
|
41
170
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
171
|
+
clear_coverage
|
|
172
|
+
@log.prepare
|
|
173
|
+
@sprites.each do |sprite|
|
|
174
|
+
sprite.sequence(@log)
|
|
175
|
+
merge(sprite)
|
|
45
176
|
end
|
|
177
|
+
@sequenced = @log.length
|
|
178
|
+
end
|
|
46
179
|
|
|
47
|
-
|
|
48
|
-
|
|
180
|
+
# Write one sprite's pixels into the coverage, picking up the color and
|
|
181
|
+
# priority registers as they stood at each pixel. The first sprite to
|
|
182
|
+
# claim a pixel wins (lowest index has priority); later ones only add
|
|
183
|
+
# their bit to it.
|
|
184
|
+
def merge(sprite)
|
|
185
|
+
bit = 1 << sprite.index
|
|
186
|
+
@carry_next[sprite.index].clear
|
|
187
|
+
@carry[sprite.index].each_slice(3) do |x, color, priority|
|
|
188
|
+
track(x, 1)
|
|
189
|
+
merge_pixel(x, color, bit, priority)
|
|
190
|
+
end
|
|
191
|
+
merge_run(sprite, sprite.leftmost, sprite.span, sprite.codes)
|
|
192
|
+
merge_run(sprite, sprite.reload_leftmost, sprite.reload_span, sprite.reload_codes)
|
|
49
193
|
end
|
|
50
194
|
|
|
51
|
-
|
|
195
|
+
def merge_run(sprite, leftmost, span, codes)
|
|
196
|
+
return if span.zero?
|
|
197
|
+
|
|
198
|
+
track(leftmost, span)
|
|
199
|
+
log = @log.empty? ? nil : @log
|
|
200
|
+
log&.rewind
|
|
201
|
+
merge_span(sprite, log, leftmost, span, codes)
|
|
202
|
+
end
|
|
52
203
|
|
|
53
|
-
|
|
54
|
-
# claim a pixel wins (lowest index has priority); later hits only
|
|
55
|
-
# accumulate collision bits.
|
|
56
|
-
def merge(sprite, mask)
|
|
57
|
-
left = sprite.leftmost
|
|
58
|
-
pixels = sprite.line_pixels
|
|
59
|
-
last = sprite.pixel_width
|
|
204
|
+
def merge_span(sprite, log, leftmost, span, codes)
|
|
60
205
|
bit = 1 << sprite.index
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
206
|
+
palette = sprite.palette(log || @registers, @palette)
|
|
207
|
+
priority = (log || @registers)[0x1b].anybits?(bit)
|
|
208
|
+
pos = leftmost
|
|
209
|
+
boundary = log ? 0 : Float::INFINITY
|
|
210
|
+
index = 0
|
|
211
|
+
while index < span
|
|
212
|
+
if pos >= boundary
|
|
213
|
+
log.advance(pos)
|
|
214
|
+
sprite.palette(log, palette)
|
|
215
|
+
priority = log[0x1b].anybits?(bit)
|
|
216
|
+
boundary = log.next_x
|
|
70
217
|
end
|
|
71
|
-
|
|
218
|
+
code = codes[index]
|
|
219
|
+
place(pos, palette[code], bit, priority) unless code.zero?
|
|
220
|
+
index += 1
|
|
221
|
+
pos += 1
|
|
72
222
|
end
|
|
223
|
+
end
|
|
73
224
|
|
|
74
|
-
|
|
75
|
-
|
|
225
|
+
# A pixel past the end of the line belongs to the start of the next.
|
|
226
|
+
def place(pos, color, bit, priority)
|
|
227
|
+
if pos < @width
|
|
228
|
+
merge_pixel(pos, color, bit, priority)
|
|
229
|
+
else
|
|
230
|
+
@carry_next[bit.bit_length - 1].push(pos - @width, color, priority)
|
|
231
|
+
end
|
|
76
232
|
end
|
|
77
233
|
|
|
78
|
-
def
|
|
234
|
+
def track(left, span)
|
|
235
|
+
right = left + span
|
|
236
|
+
if right > @width
|
|
237
|
+
@lo = 0
|
|
238
|
+
@hi = @width
|
|
239
|
+
else
|
|
240
|
+
@lo = left if left < @lo
|
|
241
|
+
@hi = right if right > @hi
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def merge_pixel(pos, color, bit, priority)
|
|
79
246
|
bits = @hits[pos]
|
|
80
247
|
if bits.zero?
|
|
81
248
|
@win_color[pos] = color
|
|
82
249
|
@win_priority[pos] = priority
|
|
83
|
-
else
|
|
84
|
-
@sprite_clash |= bits | bit
|
|
85
250
|
end
|
|
86
251
|
@hits[pos] = bits | bit
|
|
87
|
-
@data_clash |= bit if mask[pos]
|
|
88
252
|
end
|
|
89
253
|
|
|
90
|
-
def apply(colors, mask
|
|
91
|
-
pos =
|
|
92
|
-
while pos <
|
|
93
|
-
|
|
254
|
+
def apply(colors, mask)
|
|
255
|
+
pos = @lo
|
|
256
|
+
while pos < @hi
|
|
257
|
+
unless @hits[pos].zero?
|
|
94
258
|
colors[pos] = @win_color[pos] unless @win_priority[pos] && mask[pos]
|
|
95
259
|
@hits[pos] = 0
|
|
96
260
|
end
|
|
97
261
|
pos += 1
|
|
98
262
|
end
|
|
263
|
+
@lo = @width
|
|
264
|
+
@hi = 0
|
|
99
265
|
end
|
|
100
266
|
|
|
101
|
-
def
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return if @data_clash.zero?
|
|
106
|
-
return unless @registers.collide!(0x1f, @data_clash)
|
|
107
|
-
|
|
108
|
-
@registers.latch_irq!(DATA_COLLISION_IRQ)
|
|
267
|
+
def clear_coverage
|
|
268
|
+
@hits.fill(0, @lo, @hi - @lo) if @hi > @lo
|
|
269
|
+
@lo = @width
|
|
270
|
+
@hi = 0
|
|
109
271
|
end
|
|
110
272
|
end
|
|
111
273
|
end
|