badline 0.6.0 → 0.6.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 +40 -0
- data/CLAUDE.md +10 -9
- data/README.md +24 -10
- data/doc/pinned-behaviour.md +131 -30
- data/exe/badline-ruby +20 -24
- data/lib/badline/address_bus.rb +10 -1
- data/lib/badline/audio/cli.rb +18 -5
- data/lib/badline/audio/console.rb +2 -1
- data/lib/badline/audio.rb +0 -3
- data/lib/badline/computer.rb +6 -3
- data/lib/badline/cpu/boundary.rb +54 -0
- data/lib/badline/cpu/core.rb +165 -0
- data/lib/badline/cpu.rb +3 -214
- data/lib/badline/drive1541/cpu.rb +29 -0
- data/lib/badline/drive1541.rb +1 -0
- data/lib/badline/ffi.rb +157 -0
- data/lib/badline/frontend/app.rb +225 -0
- data/lib/badline/frontend/audio_sink.rb +72 -0
- data/lib/badline/frontend/boot.rb +52 -0
- data/lib/badline/frontend/controls.rb +163 -0
- data/lib/badline/frontend/drive_led.rb +51 -0
- data/lib/badline/frontend/frame_rate.rb +83 -0
- data/lib/badline/frontend/gamepads.rb +76 -0
- data/lib/badline/frontend/keys.rb +48 -0
- data/lib/badline/frontend/pacer.rb +100 -0
- data/lib/badline/frontend/pad_port.rb +61 -0
- data/lib/badline/frontend/screen.rb +65 -0
- data/lib/badline/frontend/screenshot.rb +22 -0
- data/lib/badline/frontend/snapshots.rb +60 -0
- data/lib/badline/frontend/sound.rb +153 -0
- data/lib/badline/frontend/timeline.rb +171 -0
- data/lib/badline/frontend.rb +18 -0
- data/lib/badline/options/event.rb +94 -0
- data/lib/badline/options/help.rb +78 -0
- data/lib/badline/options/option.rb +29 -0
- data/lib/badline/options/table.rb +62 -0
- data/lib/badline/options.rb +181 -145
- data/lib/badline/reu/dma/saved_state.rb +50 -0
- data/lib/badline/reu/dma.rb +56 -47
- data/lib/badline/reu/saved_state.rb +2 -1
- data/lib/badline/reu.rb +19 -10
- data/lib/badline/sdl.rb +123 -51
- data/lib/badline/sid/waveform/noise_writeback.rb +33 -11
- data/lib/badline/sid/waveform.rb +2 -3
- data/lib/badline/snapshot/state.rb +1 -1
- data/lib/badline/version.rb +1 -1
- data/lib/badline/vic/bank.rb +21 -0
- data/lib/badline/vic.rb +15 -6
- metadata +26 -19
- data/.claude/hooks/session-start.sh +0 -57
- data/.claude/settings.json +0 -14
- data/lib/badline/audio/sdl_sink.rb +0 -70
- data/lib/badline/audio/stream.rb +0 -123
- data/lib/badline/gui/application.rb +0 -243
- data/lib/badline/gui/drive_led_pane.rb +0 -29
- data/lib/badline/gui/gamepads.rb +0 -104
- data/lib/badline/gui/joy_map.rb +0 -27
- data/lib/badline/gui/key_map.rb +0 -39
- data/lib/badline/gui/palette.rb +0 -35
- data/lib/badline/gui/pane.rb +0 -36
- data/lib/badline/gui/screen_pane.rb +0 -46
- data/lib/badline/gui/snapshots.rb +0 -67
- data/lib/badline/gui/window.rb +0 -61
- data/lib/badline/gui.rb +0 -14
- data/lib/badline/sdl/events.rb +0 -49
- data/lib/badline/sdl/functions.rb +0 -74
- data/vendor/.gitkeep +0 -0
data/lib/badline/reu.rb
CHANGED
|
@@ -106,9 +106,8 @@ module Badline
|
|
|
106
106
|
# From the moment the REC asks for the bus until it hands it back.
|
|
107
107
|
def dma? = @requested || @running
|
|
108
108
|
|
|
109
|
-
# Whether the REC
|
|
110
|
-
#
|
|
111
|
-
# REC lets go.
|
|
109
|
+
# Whether the REC ran a transfer on the last cycle clocked, which it
|
|
110
|
+
# goes on doing until the cycle it lets go of the bus.
|
|
112
111
|
def holds_bus? = @running
|
|
113
112
|
|
|
114
113
|
def reset!
|
|
@@ -120,7 +119,7 @@ module Badline
|
|
|
120
119
|
@length = @length_start = 0xffff
|
|
121
120
|
@interrupt_mask = 0x1f
|
|
122
121
|
@address_control = 0x3f
|
|
123
|
-
@armed = @requested = @running = false
|
|
122
|
+
@armed = @requested = @running = @ba_was_low = false
|
|
124
123
|
interrupt(false)
|
|
125
124
|
end
|
|
126
125
|
|
|
@@ -158,16 +157,20 @@ module Badline
|
|
|
158
157
|
request_bus
|
|
159
158
|
end
|
|
160
159
|
|
|
161
|
-
# Clocks the REC for a cycle, given the VIC's BA line
|
|
162
|
-
#
|
|
163
|
-
# CPU
|
|
164
|
-
|
|
160
|
+
# Clocks the REC for a cycle, given the VIC's BA line. A requested
|
|
161
|
+
# transfer starts on the first cycle with BA high as the REC sees it,
|
|
162
|
+
# even one the CPU writes on. Pinned by REU/rmw-trigger. A fetch
|
|
163
|
+
# requested on the cycle before BA falls writes its first byte on the
|
|
164
|
+
# first BA-low cycle as well, and again when it starts. Pinned by
|
|
165
|
+
# REU/badoublewrite.
|
|
166
|
+
def dma_cycle!(ba_low)
|
|
167
|
+
late = ba_low && @vic.reu_ba_late?
|
|
165
168
|
if @requested
|
|
166
|
-
return if
|
|
169
|
+
return hold_off if ba_low && !late
|
|
167
170
|
|
|
168
171
|
start_transfer
|
|
169
172
|
end
|
|
170
|
-
@dma.cycle!(ba_low)
|
|
173
|
+
@dma.cycle!(ba_low, late, ba_low && @vic.reu_ba_handed_on?)
|
|
171
174
|
end_transfer unless @dma.holds_bus?
|
|
172
175
|
end
|
|
173
176
|
|
|
@@ -239,9 +242,15 @@ module Badline
|
|
|
239
242
|
|
|
240
243
|
def request_bus
|
|
241
244
|
@requested = true
|
|
245
|
+
@ba_was_low = @vic.ba_low?
|
|
242
246
|
@on_dma&.call
|
|
243
247
|
end
|
|
244
248
|
|
|
249
|
+
def hold_off
|
|
250
|
+
@dma.write_ahead(@command & TRANSFER_TYPE, @c64, @expansion | (@bank << 16)) unless @ba_was_low
|
|
251
|
+
@ba_was_low = true
|
|
252
|
+
end
|
|
253
|
+
|
|
245
254
|
def start_transfer
|
|
246
255
|
@requested = false
|
|
247
256
|
@running = true
|
data/lib/badline/sdl.rb
CHANGED
|
@@ -1,67 +1,139 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "fiddle"
|
|
4
|
-
|
|
5
3
|
module Badline
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# SDL::RenderClear.call(renderer) calls SDL_RenderClear. They're built
|
|
12
|
-
# with need_gvl, which skips releasing Ruby's lock around the call: none
|
|
13
|
-
# of these block for long, and releasing it costs more than most of them.
|
|
4
|
+
# libSDL2 through Spinel's FFI DSL, the one binding both builds use. The
|
|
5
|
+
# native build compiles the declarations, and finds the library's
|
|
6
|
+
# directory (see NativeBuild.sdl2_flags). badline-ruby loads badline/ffi
|
|
7
|
+
# first, which implements them over Fiddle, so only the library itself
|
|
8
|
+
# has to be present.
|
|
14
9
|
module SDL
|
|
15
|
-
|
|
10
|
+
ffi_lib "SDL2"
|
|
16
11
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
]
|
|
12
|
+
ffi_func :SDL_Init, [:uint32], :int
|
|
13
|
+
ffi_func :SDL_Quit, [], :void
|
|
14
|
+
ffi_func :SDL_GetError, [], :str
|
|
15
|
+
ffi_func :SDL_SetHint, %i[str str], :int
|
|
16
|
+
ffi_func :SDL_CreateWindow, %i[str int int int int uint32], :ptr
|
|
17
|
+
ffi_func :SDL_SetWindowTitle, %i[ptr str], :void
|
|
18
|
+
ffi_func :SDL_DestroyWindow, [:ptr], :void
|
|
19
|
+
ffi_func :SDL_CreateRenderer, %i[ptr int uint32], :ptr
|
|
20
|
+
ffi_func :SDL_GetWindowDisplayMode, %i[ptr ptr], :int
|
|
21
|
+
ffi_func :SDL_DestroyRenderer, [:ptr], :void
|
|
22
|
+
ffi_func :SDL_RenderSetLogicalSize, %i[ptr int int], :int
|
|
23
|
+
ffi_func :SDL_CreateTexture, %i[ptr uint32 int int int], :ptr
|
|
24
|
+
ffi_func :SDL_DestroyTexture, [:ptr], :void
|
|
25
|
+
ffi_func :SDL_UpdateTexture, %i[ptr ptr int_array int], :int
|
|
26
|
+
ffi_func :SDL_RenderClear, [:ptr], :int
|
|
27
|
+
ffi_func :SDL_SetRenderDrawColor, %i[ptr int int int int], :int
|
|
28
|
+
ffi_func :SDL_RenderFillRect, %i[ptr ptr], :int
|
|
29
|
+
ffi_func :SDL_RenderCopy, %i[ptr ptr ptr ptr], :int
|
|
30
|
+
ffi_func :SDL_RenderPresent, [:ptr], :void
|
|
31
|
+
ffi_func :SDL_PollEvent, [:ptr], :int
|
|
32
|
+
ffi_func :SDL_SetRelativeMouseMode, [:int], :int
|
|
33
|
+
ffi_func :SDL_Delay, [:uint32], :void
|
|
34
|
+
ffi_func :SDL_GetRendererOutputSize, %i[ptr ptr ptr], :int
|
|
35
|
+
ffi_func :SDL_RenderReadPixels, %i[ptr ptr uint32 ptr int], :int
|
|
36
|
+
ffi_func :SDL_CreateRGBSurfaceWithFormatFrom, %i[ptr int int int int uint32], :ptr
|
|
37
|
+
ffi_func :SDL_FreeSurface, [:ptr], :void
|
|
38
|
+
ffi_func :SDL_RWFromFile, %i[str str], :ptr
|
|
39
|
+
ffi_func :SDL_SaveBMP_RW, %i[ptr ptr int], :int
|
|
40
|
+
ffi_func :SDL_InitSubSystem, [:uint32], :int
|
|
41
|
+
ffi_func :SDL_QuitSubSystem, [:uint32], :void
|
|
42
|
+
ffi_func :SDL_OpenAudioDevice, %i[ptr int ptr ptr int], :uint32
|
|
43
|
+
ffi_func :SDL_CloseAudioDevice, [:uint32], :void
|
|
44
|
+
ffi_func :SDL_PauseAudioDevice, %i[uint32 int], :void
|
|
45
|
+
ffi_func :SDL_QueueAudio, %i[uint32 buffer_in uint32], :int
|
|
46
|
+
ffi_func :SDL_GetQueuedAudioSize, [:uint32], :uint32
|
|
47
|
+
ffi_func :SDL_NumJoysticks, [], :int
|
|
48
|
+
ffi_func :SDL_IsGameController, [:int], :int
|
|
49
|
+
ffi_func :SDL_GameControllerOpen, [:int], :ptr
|
|
50
|
+
ffi_func :SDL_GameControllerClose, [:ptr], :void
|
|
51
|
+
ffi_func :SDL_GameControllerName, [:ptr], :str
|
|
52
|
+
ffi_func :SDL_GameControllerGetButton, %i[ptr int], :uint8
|
|
53
|
+
ffi_func :SDL_GameControllerGetAxis, %i[ptr int], :int16
|
|
54
|
+
ffi_func :SDL_ClearQueuedAudio, [:uint32], :void
|
|
55
|
+
ffi_func :SDL_GetCurrentDisplayMode, %i[int ptr], :int
|
|
56
|
+
ffi_func :SDL_CreateRGBSurfaceFrom, %i[ptr int int int int uint32 uint32 uint32 uint32], :ptr
|
|
57
|
+
ffi_func :SDL_CreateTextureFromSurface, %i[ptr ptr], :ptr
|
|
58
|
+
ffi_func :SDL_PushEvent, [:ptr], :int
|
|
59
|
+
ffi_func :SDL_GetKeyName, [:int], :str
|
|
24
60
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
61
|
+
ffi_buffer :event, 56
|
|
62
|
+
ffi_read_u32 :event_type, 0
|
|
63
|
+
ffi_read_u8 :event_repeat, 13
|
|
64
|
+
ffi_read_i32 :event_scancode, 16
|
|
65
|
+
ffi_read_i32 :event_sym, 20
|
|
66
|
+
ffi_read_u16 :event_mod, 24
|
|
67
|
+
# SDL_MouseMotionEvent's xrel and yrel, and SDL_MouseButtonEvent's
|
|
68
|
+
# button.
|
|
69
|
+
ffi_read_i32 :event_xrel, 28
|
|
70
|
+
ffi_read_i32 :event_yrel, 32
|
|
71
|
+
ffi_read_u8 :event_button, 16
|
|
33
72
|
|
|
34
|
-
|
|
73
|
+
ffi_buffer :rect, 16
|
|
74
|
+
ffi_write_i32 :rect_x, 0
|
|
75
|
+
ffi_write_i32 :rect_y, 4
|
|
76
|
+
ffi_write_i32 :rect_w, 8
|
|
77
|
+
ffi_write_i32 :rect_h, 12
|
|
78
|
+
# Where the drive LED goes.
|
|
79
|
+
ffi_buffer :led_rect, 16
|
|
35
80
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
INT16 = Fiddle::TYPE_INT16_T
|
|
40
|
-
UINT32 = Fiddle::TYPE_UINT32_T
|
|
41
|
-
POINTER = Fiddle::TYPE_VOIDP
|
|
42
|
-
STRING = Fiddle::TYPE_CONST_STRING
|
|
81
|
+
# SDL_DisplayMode: Uint32 format; int w, h, refresh_rate; then a pointer.
|
|
82
|
+
ffi_buffer :display_mode, 24
|
|
83
|
+
ffi_read_i32 :mode_refresh, 12
|
|
43
84
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
85
|
+
ffi_buffer :output_w, 4
|
|
86
|
+
ffi_buffer :output_h, 4
|
|
87
|
+
ffi_read_i32 :read_i32, 0
|
|
47
88
|
|
|
48
|
-
|
|
89
|
+
# SDL_AudioSpec: int freq; Uint16 format; Uint8 channels, silence;
|
|
90
|
+
# Uint16 samples, padding; Uint32 size; then two pointers.
|
|
91
|
+
ffi_buffer :wanted, 32
|
|
92
|
+
ffi_buffer :obtained, 32
|
|
93
|
+
ffi_write_i32 :spec_freq, 0
|
|
94
|
+
ffi_write_u16 :spec_format, 4
|
|
95
|
+
ffi_write_u8 :spec_channels, 6
|
|
96
|
+
ffi_write_u16 :spec_samples, 8
|
|
49
97
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
98
|
+
ffi_const :INIT_AUDIO, 0x10
|
|
99
|
+
ffi_const :INIT_VIDEO, 0x20
|
|
100
|
+
ffi_const :INIT_GAMECONTROLLER, 0x2000
|
|
101
|
+
ffi_const :INIT_EVENTS, 0x4000
|
|
102
|
+
ffi_const :WINDOWPOS_CENTERED, 0x2fff0000
|
|
103
|
+
ffi_const :WINDOW_RESIZABLE, 0x20
|
|
104
|
+
ffi_const :RENDERER_ACCELERATED, 0x02
|
|
105
|
+
ffi_const :RENDERER_PRESENTVSYNC, 0x04
|
|
106
|
+
ffi_const :PIXELFORMAT_RGB888, 0x16161804
|
|
107
|
+
ffi_const :TEXTUREACCESS_STREAMING, 1
|
|
108
|
+
ffi_const :QUIT, 0x100
|
|
109
|
+
ffi_const :KEYDOWN, 0x300
|
|
110
|
+
ffi_const :KEYUP, 0x301
|
|
111
|
+
ffi_const :MOUSEMOTION, 0x400
|
|
112
|
+
ffi_const :MOUSEBUTTONDOWN, 0x401
|
|
113
|
+
ffi_const :MOUSEBUTTONUP, 0x402
|
|
114
|
+
ffi_const :KMOD_SHIFT, 0x0003
|
|
115
|
+
ffi_const :CONTROLLERDEVICEADDED, 0x653
|
|
116
|
+
ffi_const :CONTROLLERDEVICEREMOVED, 0x654
|
|
117
|
+
ffi_const :CONTROLLERDEVICEREMAPPED, 0x655
|
|
118
|
+
ffi_const :AUDIO_S16LSB, 0x8010
|
|
119
|
+
ffi_const :ALLOW_FREQUENCY_CHANGE, 0x01
|
|
120
|
+
ffi_const :KEY_TAB, 0x09
|
|
121
|
+
ffi_const :KEY_F10, 0x4000_0043
|
|
122
|
+
ffi_const :KEY_F11, 0x4000_0044
|
|
123
|
+
ffi_const :KEY_F12, 0x4000_0045
|
|
124
|
+
end
|
|
53
125
|
|
|
54
|
-
|
|
55
|
-
|
|
126
|
+
# The few C library calls the native front end makes.
|
|
127
|
+
module LibC
|
|
128
|
+
ffi_func :malloc, [:size_t], :ptr
|
|
129
|
+
ffi_func :free, [:ptr], :void
|
|
130
|
+
ffi_func :poll, %i[ptr size_t int], :int
|
|
56
131
|
|
|
57
|
-
|
|
58
|
-
def self.check_pointer(pointer)
|
|
59
|
-
raise Error, error if pointer.null?
|
|
132
|
+
ffi_const :POLLIN, 0x01
|
|
60
133
|
|
|
61
|
-
|
|
62
|
-
|
|
134
|
+
# struct pollfd: int fd; short events, revents.
|
|
135
|
+
ffi_buffer :pollfd, 8
|
|
136
|
+
ffi_write_i32 :pollfd_fd, 0
|
|
137
|
+
ffi_write_i16 :pollfd_events, 4
|
|
63
138
|
end
|
|
64
139
|
end
|
|
65
|
-
|
|
66
|
-
require "badline/sdl/functions"
|
|
67
|
-
require "badline/sdl/events"
|
|
@@ -20,11 +20,12 @@ module Badline
|
|
|
20
20
|
# so they lose a different number of bits. The 8580's pair is the one
|
|
21
21
|
# that reproduces SID/wf12nsr's pulse+noise row (it reads $f8, and the
|
|
22
22
|
# writeback leaves $fc behind), and SID/wb_testsuite's C->9 and C->E
|
|
23
|
-
# rows need that same $fc written at release.
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
# leave the register alone.
|
|
27
|
-
|
|
23
|
+
# rows need that same $fc written at release. The 6581 reads $00 of a
|
|
24
|
+
# full register (SID/wf12nsr's pulse+noise row) and pulls nothing
|
|
25
|
+
# while the register holds: wb_testsuite's 8->C and C->C rows run
|
|
26
|
+
# pulse+noise and leave the register alone. Its lines only land
|
|
27
|
+
# part way through a shift (#write_back_shift).
|
|
28
|
+
PULSE_NOISE_READ = { mos6581: 0x000, mos8580: 0xf80 }.freeze
|
|
28
29
|
PULSE_NOISE_WRITE = { mos6581: 0xff0, mos8580: 0xfc0 }.freeze
|
|
29
30
|
|
|
30
31
|
# What a 6581 writes back when the test bit falls with only pulse+noise
|
|
@@ -40,24 +41,45 @@ module Badline
|
|
|
40
41
|
# (SID/wf12nsr's noise+triangle and noise+sawtooth rows).
|
|
41
42
|
def write_back(selected, value)
|
|
42
43
|
return value & ((value << 1) | (value >> 1)) unless selected == 0xc
|
|
43
|
-
return
|
|
44
|
+
return 0x000 if @pulse.zero?
|
|
44
45
|
|
|
45
46
|
noise & @pulse_noise_write
|
|
46
47
|
end
|
|
47
48
|
|
|
49
|
+
# What the lines write while the register is part way through a
|
|
50
|
+
# shift, where the 6581's pulse+noise writes its output as read.
|
|
51
|
+
def write_back_mid_shift(selected, value)
|
|
52
|
+
return value if pulse_noise_mid_shift?(selected)
|
|
53
|
+
|
|
54
|
+
write_back(selected, value)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def pulse_noise_mid_shift?(selected) = @topbit_feedback && selected == 0xc
|
|
58
|
+
|
|
48
59
|
def write_shift_register(value)
|
|
49
60
|
NOISE_TAPS.each { |bit, line| @shift_register &= ~bit if value.nobits?(line) }
|
|
50
61
|
end
|
|
51
62
|
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
#
|
|
63
|
+
# The second phase of a shift writes back by the test bit release
|
|
64
|
+
# rule with the waveform left alone. The 6581's pulse+noise, which
|
|
65
|
+
# that rule leaves out, writes its lines too (SID/wf12nsr's
|
|
66
|
+
# pulse+noise row).
|
|
67
|
+
def write_back_shift
|
|
68
|
+
return unless pulse_noise_mid_shift?(@selected) || release_writes_back?(@selected, @selected)
|
|
69
|
+
|
|
70
|
+
write_shift_register(write_back_mid_shift(@selected, @output))
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Setting the test bit starts the bleed, and stalls the register part
|
|
74
|
+
# way through a shift, where a noise combination writes its output
|
|
75
|
+
# back first, from the accumulator it had. SID/noiselfsrinit's
|
|
76
|
+
# $f8/$80 pairs set the bit onto all four from noise alone, and
|
|
77
|
+
# SID/wf12nsr's pulse+noise row sets it onto pulse+noise.
|
|
56
78
|
def raise_test
|
|
57
79
|
@shift_register_reset = @shift_register_reset_delay
|
|
58
80
|
return unless @selected.anybits?(0x8) && combined?(@selected) && @shift_pipeline != 1
|
|
59
81
|
|
|
60
|
-
write_shift_register(
|
|
82
|
+
write_shift_register(write_back_mid_shift(@selected, shape(@selected)))
|
|
61
83
|
end
|
|
62
84
|
|
|
63
85
|
# Releasing the test bit finishes the shift it interrupted: the old
|
data/lib/badline/sid/waveform.rb
CHANGED
|
@@ -256,8 +256,7 @@ module Badline
|
|
|
256
256
|
# A rise of bit 19 starts a shift that takes two more cycles
|
|
257
257
|
# (SID/noisewriteback's noise_writeback_test2, after libresidfp's shift
|
|
258
258
|
# pipeline). The first phase latches the output, and the second writes
|
|
259
|
-
# it over the taps
|
|
260
|
-
# alone, before the register shifts.
|
|
259
|
+
# it over the taps before the register shifts.
|
|
261
260
|
def advance
|
|
262
261
|
previous = @accumulator
|
|
263
262
|
@accumulator = (previous + @frequency) & 0xffffff
|
|
@@ -265,7 +264,7 @@ module Badline
|
|
|
265
264
|
if @accumulator & ~previous & 0x080000 != 0
|
|
266
265
|
@shift_pipeline = 2
|
|
267
266
|
elsif @shift_pipeline != 0 && (@shift_pipeline -= 1).zero?
|
|
268
|
-
|
|
267
|
+
write_back_shift
|
|
269
268
|
shift_noise
|
|
270
269
|
end
|
|
271
270
|
end
|
|
@@ -14,7 +14,7 @@ module Badline
|
|
|
14
14
|
# The layout the chips write their fields in. It goes up whenever a
|
|
15
15
|
# save_state writes something else, so a State in another layout
|
|
16
16
|
# fails before anything is read into a machine.
|
|
17
|
-
SCHEMA =
|
|
17
|
+
SCHEMA = 2
|
|
18
18
|
|
|
19
19
|
attr_reader :values, :strings
|
|
20
20
|
|
data/lib/badline/version.rb
CHANGED
data/lib/badline/vic/bank.rb
CHANGED
|
@@ -13,9 +13,26 @@ module Badline
|
|
|
13
13
|
|
|
14
14
|
attr_reader :address_bus
|
|
15
15
|
|
|
16
|
+
# The bank lines as #sample_lines last saw them.
|
|
17
|
+
attr_accessor :lines
|
|
18
|
+
|
|
16
19
|
def initialize(address_bus = nil)
|
|
17
20
|
addressable_at(0x0000, length: 2**14)
|
|
18
21
|
@address_bus = address_bus || AddressBus.new
|
|
22
|
+
@lines = 0b11
|
|
23
|
+
@swapped = false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# On the 8565, a port A write that swaps the two bank lines, driving
|
|
27
|
+
# one high as the other goes low, shows the VIC both lines low for the
|
|
28
|
+
# cycle after it: every access in that cycle reads bank 3. A swap that
|
|
29
|
+
# the DDR makes, releasing a line to float high, shows nothing.
|
|
30
|
+
# Called once a cycle, ahead of the cycle's accesses.
|
|
31
|
+
def sample_lines
|
|
32
|
+
cia2 = @address_bus.cia2
|
|
33
|
+
lines = cia2.port_a_lines & 0b11
|
|
34
|
+
@swapped = swap?(@lines, lines) && cia2.port_registers[2].allbits?(0b11)
|
|
35
|
+
@lines = lines
|
|
19
36
|
end
|
|
20
37
|
|
|
21
38
|
def peek(offset)
|
|
@@ -66,7 +83,11 @@ module Badline
|
|
|
66
83
|
end
|
|
67
84
|
end
|
|
68
85
|
|
|
86
|
+
def swap?(from, to) = (from ^ to) == 0b11 && from.anybits?(0b11) && to.anybits?(0b11)
|
|
87
|
+
|
|
69
88
|
def bank_switch_register
|
|
89
|
+
return 0 if @swapped
|
|
90
|
+
|
|
70
91
|
@address_bus.cia2.port_a_lines & 0b11
|
|
71
92
|
end
|
|
72
93
|
end
|
data/lib/badline/vic.rb
CHANGED
|
@@ -86,6 +86,7 @@ module Badline
|
|
|
86
86
|
@grey_dots = model == :mos8565
|
|
87
87
|
@delayed_fetch = model == :mos8565
|
|
88
88
|
@dma_delay_idle = model == :mos6569
|
|
89
|
+
@bank_swaps = model == :mos8565
|
|
89
90
|
@address_bus = address_bus || AddressBus.new
|
|
90
91
|
@vic_bank = VIC::Bank.new(@address_bus)
|
|
91
92
|
@debug = debug
|
|
@@ -153,6 +154,7 @@ module Badline
|
|
|
153
154
|
out.int(@column).int(@rasterline).int(@cycles).boolean(@pending_write)
|
|
154
155
|
out.int(@g_tick).ints(@g_kind).int(@g_kept_char).int(@g_kept_color).boolean(@g_display)
|
|
155
156
|
out.int(@fetch_d011).boolean(@lp_triggered).boolean(@lp_low).boolean(@raster_match)
|
|
157
|
+
out.int(@vic_bank.lines)
|
|
156
158
|
out.blob(@character_buffer).blob(@color_buffer).booleans(@sprite_ba)
|
|
157
159
|
@lines.each { |line| out.blob(line) }
|
|
158
160
|
@registers.save_state(out)
|
|
@@ -260,14 +262,19 @@ module Badline
|
|
|
260
262
|
@column > DisplayState::DMA_FIRST && @column <= DisplayState::DMA_LAST + 1
|
|
261
263
|
end
|
|
262
264
|
|
|
263
|
-
#
|
|
264
|
-
#
|
|
265
|
-
#
|
|
265
|
+
# Whether this is the first cycle of sprite 0's BA window on the line
|
|
266
|
+
# whose raster matches its Y, where the sprite's DMA starts. An REU
|
|
267
|
+
# that moved a byte on the cycle before doesn't see BA fall here. Pinned by
|
|
266
268
|
# REU/bonzai/spritetiming.
|
|
267
|
-
def
|
|
268
|
-
|
|
269
|
+
def reu_ba_late?
|
|
270
|
+
@column == SPRITE_BA_FIRST + @sprite_shift && sprite_zero_starting?
|
|
271
|
+
end
|
|
269
272
|
|
|
270
|
-
|
|
273
|
+
# Whether BA passes straight from a bad line's window to sprite 0's on
|
|
274
|
+
# this cycle, the first of sprite 0's. An REU sees the bad line's DMA
|
|
275
|
+
# end here. Pinned by REU/reutiming2/e4-m2 and e6-m2.
|
|
276
|
+
def reu_ba_handed_on?
|
|
277
|
+
@column == DisplayState::DMA_LAST + 2 && @sprite_ba[@column] && @display_state.bad_line_condition?
|
|
271
278
|
end
|
|
272
279
|
|
|
273
280
|
# Light pen input level (CIA1 PB4). A falling edge triggers the latch.
|
|
@@ -372,6 +379,7 @@ module Badline
|
|
|
372
379
|
@lp_triggered = input.boolean?
|
|
373
380
|
@lp_low = input.boolean?
|
|
374
381
|
@raster_match = input.boolean?
|
|
382
|
+
@vic_bank.lines = input.int
|
|
375
383
|
end
|
|
376
384
|
|
|
377
385
|
def load_buffers(input)
|
|
@@ -536,6 +544,7 @@ module Badline
|
|
|
536
544
|
# on zero data with the screen byte and colour the last g-access
|
|
537
545
|
# latched, which an idle g-access clears.
|
|
538
546
|
def draw!
|
|
547
|
+
@vic_bank.sample_lines if @bank_swaps
|
|
539
548
|
slot = @g_tick = (@g_tick + 1) & 3
|
|
540
549
|
display_state = @display_state
|
|
541
550
|
access = display_state.graphics_column?(@column) && !@sequencer.vertical_closed?
|
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.6.
|
|
4
|
+
version: 0.6.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Inge Jørgensen
|
|
@@ -34,8 +34,6 @@ executables:
|
|
|
34
34
|
extensions: []
|
|
35
35
|
extra_rdoc_files: []
|
|
36
36
|
files:
|
|
37
|
-
- ".claude/hooks/session-start.sh"
|
|
38
|
-
- ".claude/settings.json"
|
|
39
37
|
- CHANGELOG.md
|
|
40
38
|
- CLAUDE.md
|
|
41
39
|
- CODE_OF_CONDUCT.md
|
|
@@ -60,8 +58,6 @@ files:
|
|
|
60
58
|
- lib/badline/audio/pcm_writer.rb
|
|
61
59
|
- lib/badline/audio/playback.rb
|
|
62
60
|
- lib/badline/audio/renderer.rb
|
|
63
|
-
- lib/badline/audio/sdl_sink.rb
|
|
64
|
-
- lib/badline/audio/stream.rb
|
|
65
61
|
- lib/badline/audio/terminal.rb
|
|
66
62
|
- lib/badline/audio/wav.rb
|
|
67
63
|
- lib/badline/cartridge.rb
|
|
@@ -106,6 +102,8 @@ files:
|
|
|
106
102
|
- lib/badline/control_ports.rb
|
|
107
103
|
- lib/badline/cpu.rb
|
|
108
104
|
- lib/badline/cpu/addressing.rb
|
|
105
|
+
- lib/badline/cpu/boundary.rb
|
|
106
|
+
- lib/badline/cpu/core.rb
|
|
109
107
|
- lib/badline/cpu/microcode.rb
|
|
110
108
|
- lib/badline/cpu/operations.rb
|
|
111
109
|
- lib/badline/cpu/saved_state.rb
|
|
@@ -115,6 +113,7 @@ files:
|
|
|
115
113
|
- lib/badline/debug_register.rb
|
|
116
114
|
- lib/badline/drive1541.rb
|
|
117
115
|
- lib/badline/drive1541/bus.rb
|
|
116
|
+
- lib/badline/drive1541/cpu.rb
|
|
118
117
|
- lib/badline/drive1541/disk.rb
|
|
119
118
|
- lib/badline/drive1541/disk_state.rb
|
|
120
119
|
- lib/badline/drive1541/disk_via.rb
|
|
@@ -128,17 +127,23 @@ files:
|
|
|
128
127
|
- lib/badline/drive1541/serial_port.rb
|
|
129
128
|
- lib/badline/drive1541/sleep.rb
|
|
130
129
|
- lib/badline/drive1541/track.rb
|
|
131
|
-
- lib/badline/
|
|
132
|
-
- lib/badline/
|
|
133
|
-
- lib/badline/
|
|
134
|
-
- lib/badline/
|
|
135
|
-
- lib/badline/
|
|
136
|
-
- lib/badline/
|
|
137
|
-
- lib/badline/
|
|
138
|
-
- lib/badline/
|
|
139
|
-
- lib/badline/
|
|
140
|
-
- lib/badline/
|
|
141
|
-
- lib/badline/
|
|
130
|
+
- lib/badline/ffi.rb
|
|
131
|
+
- lib/badline/frontend.rb
|
|
132
|
+
- lib/badline/frontend/app.rb
|
|
133
|
+
- lib/badline/frontend/audio_sink.rb
|
|
134
|
+
- lib/badline/frontend/boot.rb
|
|
135
|
+
- lib/badline/frontend/controls.rb
|
|
136
|
+
- lib/badline/frontend/drive_led.rb
|
|
137
|
+
- lib/badline/frontend/frame_rate.rb
|
|
138
|
+
- lib/badline/frontend/gamepads.rb
|
|
139
|
+
- lib/badline/frontend/keys.rb
|
|
140
|
+
- lib/badline/frontend/pacer.rb
|
|
141
|
+
- lib/badline/frontend/pad_port.rb
|
|
142
|
+
- lib/badline/frontend/screen.rb
|
|
143
|
+
- lib/badline/frontend/screenshot.rb
|
|
144
|
+
- lib/badline/frontend/snapshots.rb
|
|
145
|
+
- lib/badline/frontend/sound.rb
|
|
146
|
+
- lib/badline/frontend/timeline.rb
|
|
142
147
|
- lib/badline/iec_bus.rb
|
|
143
148
|
- lib/badline/input.rb
|
|
144
149
|
- lib/badline/input/mouse1351.rb
|
|
@@ -177,6 +182,10 @@ files:
|
|
|
177
182
|
- lib/badline/media/true_drive.rb
|
|
178
183
|
- lib/badline/memory.rb
|
|
179
184
|
- lib/badline/options.rb
|
|
185
|
+
- lib/badline/options/event.rb
|
|
186
|
+
- lib/badline/options/help.rb
|
|
187
|
+
- lib/badline/options/option.rb
|
|
188
|
+
- lib/badline/options/table.rb
|
|
180
189
|
- lib/badline/ram_expansion.rb
|
|
181
190
|
- lib/badline/ram_expansion/banking.rb
|
|
182
191
|
- lib/badline/ram_expansion/plus256k.rb
|
|
@@ -185,6 +194,7 @@ files:
|
|
|
185
194
|
- lib/badline/region.rb
|
|
186
195
|
- lib/badline/reu.rb
|
|
187
196
|
- lib/badline/reu/dma.rb
|
|
197
|
+
- lib/badline/reu/dma/saved_state.rb
|
|
188
198
|
- lib/badline/reu/ram.rb
|
|
189
199
|
- lib/badline/reu/saved_state.rb
|
|
190
200
|
- lib/badline/reu/trigger.rb
|
|
@@ -198,8 +208,6 @@ files:
|
|
|
198
208
|
- lib/badline/roms/eapi/eapi-am29f040-14
|
|
199
209
|
- lib/badline/roms/kernal.rom
|
|
200
210
|
- lib/badline/sdl.rb
|
|
201
|
-
- lib/badline/sdl/events.rb
|
|
202
|
-
- lib/badline/sdl/functions.rb
|
|
203
211
|
- lib/badline/sid.rb
|
|
204
212
|
- lib/badline/sid/catch_up.rb
|
|
205
213
|
- lib/badline/sid/decimator.rb
|
|
@@ -282,7 +290,6 @@ files:
|
|
|
282
290
|
- lib/badline/vic/sprites.rb
|
|
283
291
|
- lib/badline/vic/sprites_state.rb
|
|
284
292
|
- packaging/homebrew/badline.rb
|
|
285
|
-
- vendor/.gitkeep
|
|
286
293
|
homepage: https://github.com/elektronaut/badline
|
|
287
294
|
licenses:
|
|
288
295
|
- MIT
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Prepares a Claude Code on the web container to run `bundle exec rubocop`
|
|
3
|
-
# and `bundle exec rspec`. The regression suites need vendor/ and aren't set
|
|
4
|
-
# up here.
|
|
5
|
-
set -euo pipefail
|
|
6
|
-
|
|
7
|
-
if [ "${CLAUDE_CODE_REMOTE:-}" != "true" ]; then
|
|
8
|
-
exit 0
|
|
9
|
-
fi
|
|
10
|
-
|
|
11
|
-
cd "${CLAUDE_PROJECT_DIR:-$(dirname "$0")/../..}"
|
|
12
|
-
|
|
13
|
-
# The SDL specs open libSDL2 through Fiddle, so only the runtime library is
|
|
14
|
-
# needed, as in CI.
|
|
15
|
-
if ! ldconfig -p | grep 'libSDL2-2\.0\.so\.0' >/dev/null; then
|
|
16
|
-
export DEBIAN_FRONTEND=noninteractive
|
|
17
|
-
apt-get update -qq
|
|
18
|
-
apt-get install -y -qq libsdl2-2.0-0 >/dev/null
|
|
19
|
-
fi
|
|
20
|
-
|
|
21
|
-
# The image ships Ruby 3.3 and an rbenv. Install the newest Ruby 4.0.x, as
|
|
22
|
-
# CI's ruby-version "4.0" picks, from the prebuilt binaries setup-ruby uses,
|
|
23
|
-
# unless a 4.0 is installed already.
|
|
24
|
-
export RBENV_ROOT=/opt/rbenv
|
|
25
|
-
export PATH="$RBENV_ROOT/bin:$RBENV_ROOT/shims:$PATH"
|
|
26
|
-
ruby_version=$(rbenv versions --bare | grep -E '^4\.0\.[0-9]+$' | sort -V | tail -1 || true)
|
|
27
|
-
if [ -z "$ruby_version" ]; then
|
|
28
|
-
ruby_version=$(curl -fsSL https://raw.githubusercontent.com/ruby/setup-ruby/master/ruby-builder-versions.json |
|
|
29
|
-
ruby -rjson -e 'puts JSON.parse($stdin.read)["ruby"].grep(/\A4\.0\.\d+\z/).max_by { Gem::Version.new(_1) }')
|
|
30
|
-
# The binaries only run from the prefix they were built with, so unpack
|
|
31
|
-
# there and link it into rbenv.
|
|
32
|
-
. /etc/os-release
|
|
33
|
-
prefix="/opt/hostedtoolcache/Ruby/$ruby_version/x64"
|
|
34
|
-
mkdir -p "$prefix"
|
|
35
|
-
if curl -fsSL "https://github.com/ruby/ruby-builder/releases/download/ruby-$ruby_version/ruby-$ruby_version-ubuntu-$VERSION_ID-x64.tar.gz" |
|
|
36
|
-
tar -xz -C "$prefix" --strip-components=1; then
|
|
37
|
-
ln -sfn "$prefix" "$RBENV_ROOT/versions/$ruby_version"
|
|
38
|
-
else
|
|
39
|
-
# No binary for this Ubuntu release: build from source, which takes minutes.
|
|
40
|
-
rm -rf "$prefix"
|
|
41
|
-
git -C "$RBENV_ROOT/plugins/ruby-build" pull --ff-only -q || true
|
|
42
|
-
MAKE_OPTS="-j$(nproc)" rbenv install --skip-existing "$ruby_version"
|
|
43
|
-
fi
|
|
44
|
-
fi
|
|
45
|
-
rbenv global "$ruby_version"
|
|
46
|
-
rbenv rehash
|
|
47
|
-
|
|
48
|
-
# Put rbenv's shims ahead of /usr/local/bin/ruby for the session.
|
|
49
|
-
if [ -n "${CLAUDE_ENV_FILE:-}" ]; then
|
|
50
|
-
{
|
|
51
|
-
echo "export RBENV_ROOT=$RBENV_ROOT"
|
|
52
|
-
echo "export PATH=\"$RBENV_ROOT/bin:$RBENV_ROOT/shims:\$PATH\""
|
|
53
|
-
} >> "$CLAUDE_ENV_FILE"
|
|
54
|
-
fi
|
|
55
|
-
|
|
56
|
-
# Bundler switches to the version Gemfile.lock was bundled with.
|
|
57
|
-
bundle install --jobs "$(nproc)"
|