badline 0.11.1 → 0.12.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 +26 -0
- data/CLAUDE.md +8 -7
- data/CONTRIBUTING.md +7 -6
- data/README.md +12 -5
- data/doc/media.md +28 -1
- data/doc/pinned-behaviour.md +31 -1
- data/exe/badline-ruby +1 -1
- data/lib/badline/address_bus/saved_state.rb +4 -10
- data/lib/badline/address_bus.rb +8 -27
- data/lib/badline/audio/bare_player.rb +1 -1
- data/lib/badline/c128/bus.rb +17 -52
- data/lib/badline/c128/bus_state.rb +5 -5
- data/lib/badline/c128/drives.rb +35 -22
- data/lib/badline/c128/fast_serial.rb +1 -0
- data/lib/badline/c128/io_pages.rb +35 -0
- data/lib/badline/c128/mmu.rb +9 -7
- data/lib/badline/c128/modes.rb +17 -4
- data/lib/badline/c128/saved_state.rb +22 -0
- data/lib/badline/c128/z80.rb +49 -0
- data/lib/badline/c128/z80_pages.rb +118 -0
- data/lib/badline/c128/z80_turns.rb +106 -0
- data/lib/badline/c128.rb +21 -83
- data/lib/badline/cartridge/action_replay.rb +2 -2
- data/lib/badline/cartridge/comal80.rb +1 -7
- data/lib/badline/cartridge/dinamic.rb +0 -8
- data/lib/badline/cartridge/final_cartridge3.rb +6 -6
- data/lib/badline/cartridge/fun_play.rb +0 -8
- data/lib/badline/cartridge/game_system.rb +0 -8
- data/lib/badline/cartridge/kcs_power.rb +10 -7
- data/lib/badline/cartridge/mach5.rb +2 -4
- data/lib/badline/cartridge/magic_desk.rb +0 -8
- data/lib/badline/cartridge/ocean.rb +0 -8
- data/lib/badline/cartridge/pagefox.rb +2 -2
- data/lib/badline/cartridge/retro_replay.rb +7 -6
- data/lib/badline/cartridge/rex_utility.rb +2 -6
- data/lib/badline/cartridge/rgcd.rb +2 -2
- data/lib/badline/cartridge/simons_basic.rb +0 -5
- data/lib/badline/cartridge/super_games.rb +4 -2
- data/lib/badline/cartridge/westermann.rb +2 -6
- data/lib/badline/cartridge.rb +37 -9
- data/lib/badline/cia/fast_forward.rb +21 -3
- data/lib/badline/cia.rb +8 -5
- data/lib/badline/computer/attachments.rb +14 -95
- data/lib/badline/computer/common.rb +34 -0
- data/lib/badline/computer/kernal_traps.rb +65 -5
- data/lib/badline/computer/true_drives.rb +69 -0
- data/lib/badline/computer.rb +9 -68
- data/lib/badline/core.rb +4 -2
- data/lib/badline/cpu_port.rb +112 -0
- data/lib/badline/drive/core.rb +8 -33
- data/lib/badline/drive/fast_serial.rb +73 -0
- data/lib/badline/drive/idle.rb +1 -11
- data/lib/badline/drive/orbit.rb +2 -5
- data/lib/badline/drive/sleep.rb +0 -2
- data/lib/badline/drive/vias.rb +84 -0
- data/lib/badline/drive.rb +2 -0
- data/lib/badline/drive1541/disk.rb +14 -17
- data/lib/badline/drive1541/disk_state.rb +7 -15
- data/lib/badline/drive1541.rb +1 -0
- data/lib/badline/drive1571/wd1770.rb +94 -8
- data/lib/badline/drive1571.rb +8 -58
- data/lib/badline/drive1581/bus.rb +137 -0
- data/lib/badline/drive1581/cpu.rb +11 -0
- data/lib/badline/drive1581/disk.rb +135 -0
- data/lib/badline/drive1581/disk_state.rb +87 -0
- data/lib/badline/drive1581/mechanism.rb +117 -0
- data/lib/badline/drive1581/serial_port.rb +52 -0
- data/lib/badline/drive1581/slot.rb +78 -0
- data/lib/badline/drive1581/track.rb +100 -0
- data/lib/badline/drive1581/track_bytes.rb +75 -0
- data/lib/badline/drive1581/wd1772/registers.rb +89 -0
- data/lib/badline/drive1581/wd1772/sector_writes.rb +73 -0
- data/lib/badline/drive1581/wd1772/sectors.rb +150 -0
- data/lib/badline/drive1581/wd1772/state.rb +66 -0
- data/lib/badline/drive1581/wd1772/stepping.rb +109 -0
- data/lib/badline/drive1581/wd1772/tracks.rb +125 -0
- data/lib/badline/drive1581/wd1772/turn.rb +73 -0
- data/lib/badline/drive1581/wd1772.rb +216 -0
- data/lib/badline/drive1581.rb +233 -0
- data/lib/badline/frontend/app.rb +1 -3
- data/lib/badline/frontend/audio_device.rb +67 -0
- data/lib/badline/frontend/audio_sink.rb +16 -50
- data/lib/badline/frontend/boot.rb +24 -67
- data/lib/badline/frontend/buttons.rb +7 -7
- data/lib/badline/frontend/keys.rb +33 -8
- data/lib/badline/frontend/media_slots.rb +42 -0
- data/lib/badline/frontend/{confirmation.rb → menu/confirmation.rb} +4 -4
- data/lib/badline/frontend/{file_browser.rb → menu/file_browser.rb} +18 -34
- data/lib/badline/frontend/{menu_dialogs.rb → menu/menu_dialogs.rb} +3 -7
- data/lib/badline/frontend/{menu_media.rb → menu/menu_media.rb} +26 -51
- data/lib/badline/frontend/{menu_pages.rb → menu/menu_pages.rb} +5 -8
- data/lib/badline/frontend/{name_field.rb → menu/name_field.rb} +11 -24
- data/lib/badline/frontend/{pause_menu.rb → menu/pause_menu.rb} +13 -28
- data/lib/badline/frontend/menu/theme.rb +18 -0
- data/lib/badline/frontend/{filter_view.rb → player/filter_view.rb} +4 -4
- data/lib/badline/frontend/{info_view.rb → player/info_view.rb} +3 -3
- data/lib/badline/frontend/{player_window.rb → player/player_controller.rb} +17 -25
- data/lib/badline/frontend/{player_footer.rb → player/player_footer.rb} +8 -8
- data/lib/badline/frontend/{player_header.rb → player/player_header.rb} +5 -5
- data/lib/badline/frontend/{player_screen.rb → player/player_screen.rb} +4 -5
- data/lib/badline/frontend/{scope.rb → player/scope.rb} +1 -1
- data/lib/badline/frontend/{sid_view.rb → player/sid_view.rb} +16 -20
- data/lib/badline/frontend/player/theme.rb +18 -0
- data/lib/badline/frontend/{visualizer_view.rb → player/visualizer_view.rb} +8 -8
- data/lib/badline/frontend/sound.rb +19 -38
- data/lib/badline/frontend/timeline.rb +3 -14
- data/lib/badline/frontend.rb +24 -20
- data/lib/badline/iec_bus.rb +14 -2
- data/lib/badline/kernal_trap/{file.rb → file_routine.rb} +1 -1
- data/lib/badline/kernal_trap/load.rb +1 -1
- data/lib/badline/kernal_trap/save.rb +1 -1
- data/lib/badline/kernal_trap.rb +1 -1
- data/lib/badline/machine/clocking.rb +50 -0
- data/lib/badline/machine.rb +63 -6
- data/lib/badline/media/boot_disk.rb +50 -0
- data/lib/badline/media/disk_list.rb +3 -3
- data/lib/badline/media/disk_set.rb +1 -1
- data/lib/badline/media/extensions.rb +33 -0
- data/lib/badline/media/not_disk.rb +8 -0
- data/lib/badline/media/program.rb +28 -0
- data/lib/badline/media/true_drive.rb +38 -17
- data/lib/badline/media/tune.rb +35 -0
- data/lib/badline/media/vic20_cartridge.rb +1 -7
- data/lib/badline/media/vic20_media.rb +38 -80
- data/lib/badline/media.rb +90 -81
- data/lib/badline/options/event.rb +4 -2
- data/lib/badline/options/family.rb +3 -9
- data/lib/badline/options/help.rb +2 -1
- data/lib/badline/roms/README +9 -0
- data/lib/badline/roms/dos1581.rom +0 -0
- data/lib/badline/sdl.rb +37 -20
- data/lib/badline/sid.rb +1 -1
- data/lib/badline/snapshot/machine_state.rb +9 -1
- data/lib/badline/snapshot/state.rb +6 -4
- data/lib/badline/snapshot.rb +11 -9
- data/lib/badline/storage/d64_image.rb +15 -7
- data/lib/badline/storage/disk_image/writing.rb +2 -2
- data/lib/badline/storage/disk_image.rb +1 -1
- data/lib/badline/storage/host_directory.rb +1 -1
- data/lib/badline/storage/p00.rb +8 -0
- data/lib/badline/storage/t64.rb +1 -1
- data/lib/badline/time_of_day.rb +3 -3
- data/lib/badline/version.rb +1 -1
- data/lib/badline/vic/bank.rb +1 -1
- data/lib/badline/vic/border_mask.rb +1 -1
- data/lib/badline/vic/collisions.rb +1 -1
- data/lib/badline/vic/color_patches.rb +1 -1
- data/lib/badline/vic/display_state.rb +1 -1
- data/lib/badline/vic/graphics_mode.rb +1 -1
- data/lib/badline/vic/graphics_shifter.rb +1 -1
- data/lib/badline/vic/register_log.rb +1 -1
- data/lib/badline/vic/registers.rb +1 -1
- data/lib/badline/vic/sequencer.rb +1 -1
- data/lib/badline/vic/sequencer_output.rb +1 -1
- data/lib/badline/vic/sequencer_state.rb +1 -1
- data/lib/badline/vic/sprite/internal_bus.rb +1 -1
- data/lib/badline/vic/sprite/saved_state.rb +1 -1
- data/lib/badline/vic/sprite/shifter.rb +1 -1
- data/lib/badline/vic/sprite/timing.rb +1 -1
- data/lib/badline/vic/sprite.rb +1 -1
- data/lib/badline/vic/sprites.rb +1 -1
- data/lib/badline/vic/sprites_state.rb +1 -1
- data/lib/badline/vic.rb +6 -5
- data/lib/badline/vic20/attachments.rb +15 -71
- data/lib/badline/vic20/saved_state.rb +2 -30
- data/lib/badline/vic20.rb +4 -37
- data/lib/badline/z80/core.rb +2 -0
- data/lib/badline/z80/saved_state.rb +69 -0
- metadata +61 -23
- data/lib/badline/cycleable.rb +0 -38
- /data/lib/badline/frontend/{menu_ports.rb → menu/menu_ports.rb} +0 -0
- /data/lib/badline/frontend/{player_commands.rb → player/player_commands.rb} +0 -0
- /data/lib/badline/frontend/{player_state.rb → player/player_state.rb} +0 -0
- /data/lib/badline/frontend/{sid_history.rb → player/sid_history.rb} +0 -0
data/lib/badline/sdl.rb
CHANGED
|
@@ -59,23 +59,6 @@ module Badline
|
|
|
59
59
|
ffi_func :SDL_PushEvent, [:ptr], :int
|
|
60
60
|
ffi_func :SDL_GetKeyName, [:int], :str
|
|
61
61
|
|
|
62
|
-
ffi_buffer :event, 56
|
|
63
|
-
ffi_read_u32 :event_type, 0
|
|
64
|
-
ffi_read_u8 :event_repeat, 13
|
|
65
|
-
ffi_read_i32 :event_scancode, 16
|
|
66
|
-
ffi_read_i32 :event_sym, 20
|
|
67
|
-
ffi_read_u16 :event_mod, 24
|
|
68
|
-
# SDL_MouseMotionEvent's xrel and yrel, and SDL_MouseButtonEvent's
|
|
69
|
-
# button.
|
|
70
|
-
ffi_read_i32 :event_xrel, 28
|
|
71
|
-
ffi_read_i32 :event_yrel, 32
|
|
72
|
-
ffi_read_u8 :event_button, 16
|
|
73
|
-
# Where the pointer is, in a motion or button event.
|
|
74
|
-
ffi_read_i32 :event_x, 20
|
|
75
|
-
ffi_read_i32 :event_y, 24
|
|
76
|
-
# SDL_DropEvent's file, which the receiver frees.
|
|
77
|
-
ffi_read_ptr :event_file, 8
|
|
78
|
-
|
|
79
62
|
ffi_buffer :rect, 16
|
|
80
63
|
ffi_write_i32 :rect_x, 0
|
|
81
64
|
ffi_write_i32 :rect_y, 4
|
|
@@ -115,19 +98,53 @@ module Badline
|
|
|
115
98
|
ffi_const :PIXELFORMAT_ARGB8888, 0x16362004
|
|
116
99
|
ffi_const :BLENDMODE_BLEND, 0x01
|
|
117
100
|
ffi_const :TEXTUREACCESS_STREAMING, 1
|
|
101
|
+
ffi_const :AUDIO_S16LSB, 0x8010
|
|
102
|
+
ffi_const :ALLOW_FREQUENCY_CHANGE, 0x01
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# The events: the SDL_Event that SDL_PollEvent fills, the fields the
|
|
106
|
+
# front end reads from it, the event types, the key modifier and
|
|
107
|
+
# keycodes, and the dropped file's path.
|
|
108
|
+
module SDL
|
|
109
|
+
ffi_buffer :event, 56
|
|
110
|
+
ffi_read_u32 :event_type, 0
|
|
111
|
+
ffi_read_u8 :event_repeat, 13
|
|
112
|
+
ffi_read_i32 :event_scancode, 16
|
|
113
|
+
ffi_read_i32 :event_sym, 20
|
|
114
|
+
ffi_read_u16 :event_mod, 24
|
|
115
|
+
# SDL_MouseMotionEvent's xrel and yrel, and SDL_MouseButtonEvent's
|
|
116
|
+
# button.
|
|
117
|
+
ffi_read_i32 :event_xrel, 28
|
|
118
|
+
ffi_read_i32 :event_yrel, 32
|
|
119
|
+
ffi_read_u8 :event_button, 16
|
|
120
|
+
# Where the pointer is, in a motion or button event.
|
|
121
|
+
ffi_read_i32 :event_x, 20
|
|
122
|
+
ffi_read_i32 :event_y, 24
|
|
123
|
+
# SDL_DropEvent's file, which the receiver frees.
|
|
124
|
+
ffi_read_ptr :event_file, 8
|
|
125
|
+
|
|
118
126
|
ffi_const :QUIT, 0x100
|
|
119
127
|
ffi_const :KEYDOWN, 0x300
|
|
120
128
|
ffi_const :KEYUP, 0x301
|
|
121
129
|
ffi_const :MOUSEMOTION, 0x400
|
|
122
130
|
ffi_const :MOUSEBUTTONDOWN, 0x401
|
|
123
131
|
ffi_const :MOUSEBUTTONUP, 0x402
|
|
124
|
-
ffi_const :
|
|
132
|
+
ffi_const :MOUSEWHEEL, 0x403
|
|
125
133
|
ffi_const :CONTROLLERDEVICEADDED, 0x653
|
|
126
134
|
ffi_const :CONTROLLERDEVICEREMOVED, 0x654
|
|
127
|
-
ffi_const :
|
|
128
|
-
ffi_const :
|
|
135
|
+
ffi_const :DROPFILE, 0x1000
|
|
136
|
+
ffi_const :KMOD_SHIFT, 0x0003
|
|
129
137
|
ffi_const :KEY_TAB, 0x09
|
|
130
138
|
ffi_const :KEY_F10, 0x4000_0043
|
|
139
|
+
|
|
140
|
+
# The path of the file the DROPFILE event in SDL.event carries, as a
|
|
141
|
+
# String, freeing SDL's copy.
|
|
142
|
+
def self.dropped_file
|
|
143
|
+
file = SDL.event_file(SDL.event)
|
|
144
|
+
path = LibC.strstr(file, "")
|
|
145
|
+
LibC.free(file)
|
|
146
|
+
path
|
|
147
|
+
end
|
|
131
148
|
end
|
|
132
149
|
|
|
133
150
|
# The few C library calls the native front end makes.
|
data/lib/badline/sid.rb
CHANGED
|
@@ -119,7 +119,7 @@ module Badline
|
|
|
119
119
|
# second, for #drain_samples. `filter_chunk` overrides the one the SID
|
|
120
120
|
# was built with, for a machine that built its own. `clock_hz` is the
|
|
121
121
|
# rate the SID's cycles are taken to run at.
|
|
122
|
-
def record(rate:, filter_chunk: @filter_chunk, clock_hz:
|
|
122
|
+
def record(rate:, filter_chunk: @filter_chunk, clock_hz: Region::PAL.clock_hz)
|
|
123
123
|
synthesize!
|
|
124
124
|
catch_up
|
|
125
125
|
@filter_chunk = filter_chunk
|
|
@@ -19,6 +19,10 @@ module Badline
|
|
|
19
19
|
MAJOR = 2
|
|
20
20
|
MINOR = 0
|
|
21
21
|
|
|
22
|
+
# The values a 64-bit integer holds once encode doubles them, which a
|
|
23
|
+
# native build's integers can't exceed.
|
|
24
|
+
VALUES = (-(1 << 62))..((1 << 62) - 1)
|
|
25
|
+
|
|
22
26
|
module_function
|
|
23
27
|
|
|
24
28
|
def section(state)
|
|
@@ -41,7 +45,11 @@ module Badline
|
|
|
41
45
|
strings = state.strings
|
|
42
46
|
numbers = [values.length, strings.length]
|
|
43
47
|
strings.each { |string| numbers << string.bytesize }
|
|
44
|
-
values.each
|
|
48
|
+
values.each do |value|
|
|
49
|
+
raise RangeError, "#{value} is too large for a snapshot" unless VALUES.cover?(value)
|
|
50
|
+
|
|
51
|
+
numbers << (value.negative? ? (-2 * value) - 1 : 2 * value)
|
|
52
|
+
end
|
|
45
53
|
index = numbers.pack("w*")
|
|
46
54
|
[index.bytesize].pack("V") + index + strings.join
|
|
47
55
|
end
|
|
@@ -15,10 +15,12 @@ module Badline
|
|
|
15
15
|
# save_state writes something else, so a State in another layout
|
|
16
16
|
# fails before anything is read into a machine. Layout 3, without the
|
|
17
17
|
# KERNAL and datasette in the setup, layout 4, without the VIA shift
|
|
18
|
-
# register's clock delay,
|
|
19
|
-
#
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
# register's clock delay, layout 5, without the board in the setup,
|
|
19
|
+
# layout 6, without the C128's Z80, layout 7, without a 1581 on the
|
|
20
|
+
# serial bus, and layout 8, with the VIC's unused cycle count and
|
|
21
|
+
# pending-write flag, still read.
|
|
22
|
+
SCHEMA = 9
|
|
23
|
+
READABLE = [3, 4, 5, 6, 7, 8, SCHEMA].freeze
|
|
22
24
|
|
|
23
25
|
attr_reader :values, :strings
|
|
24
26
|
|
data/lib/badline/snapshot.rb
CHANGED
|
@@ -47,23 +47,25 @@ module Badline
|
|
|
47
47
|
# applied and left out, yielding a line for each thing left out. A
|
|
48
48
|
# snapshot that fails leaves the machine as it was.
|
|
49
49
|
def restore(computer, path, &) = read(path).restore(computer, &)
|
|
50
|
+
|
|
51
|
+
# A machine's snapshots as .vsf files. Computer, Vic20 and C128 each
|
|
52
|
+
# include it.
|
|
53
|
+
module Files
|
|
54
|
+
def save_snapshot(path) = Snapshot.save(self, path)
|
|
55
|
+
|
|
56
|
+
def restore_snapshot(path, &) = Snapshot.restore(self, path, &)
|
|
57
|
+
end
|
|
50
58
|
end
|
|
51
59
|
|
|
52
60
|
class Computer
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def restore_snapshot(path, &) = Snapshot.restore(self, path, &)
|
|
61
|
+
include Snapshot::Files
|
|
56
62
|
end
|
|
57
63
|
|
|
58
64
|
class Vic20
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def restore_snapshot(path, &) = Snapshot.restore(self, path, &)
|
|
65
|
+
include Snapshot::Files
|
|
62
66
|
end
|
|
63
67
|
|
|
64
68
|
class C128
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def restore_snapshot(path, &) = Snapshot.restore(self, path, &)
|
|
69
|
+
include Snapshot::Files
|
|
68
70
|
end
|
|
69
71
|
end
|
|
@@ -20,15 +20,23 @@ module Badline
|
|
|
20
20
|
# The sides of a disk the image's tracks fill.
|
|
21
21
|
def sides = 1
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
# The last track of each of the 1541's speed zones but the innermost,
|
|
24
|
+
# from the outermost, zone 3, in: tracks 1-17, 18-24 and 25-30, and
|
|
25
|
+
# zone 0 from 31 on.
|
|
26
|
+
ZONE_LAST_TRACKS = [17, 24, 30].freeze
|
|
27
|
+
|
|
28
|
+
# The sectors a track holds in each zone, by its number.
|
|
29
|
+
ZONE_SECTORS = [17, 18, 19, 21].freeze
|
|
30
|
+
|
|
31
|
+
# The speed zone a track is written in, 3 for the outermost.
|
|
32
|
+
def self.zone(track)
|
|
33
|
+
zone = 3
|
|
34
|
+
zone -= 1 while zone.positive? && track > ZONE_LAST_TRACKS[3 - zone]
|
|
35
|
+
zone
|
|
30
36
|
end
|
|
31
37
|
|
|
38
|
+
def sectors_in(track) = ZONE_SECTORS[D64Image.zone(track)]
|
|
39
|
+
|
|
32
40
|
private
|
|
33
41
|
|
|
34
42
|
def error_tables = ERROR_TABLES
|
|
@@ -11,7 +11,7 @@ module Badline
|
|
|
11
11
|
module Writing
|
|
12
12
|
# Whether the disk takes writes: the image wasn't opened read-only
|
|
13
13
|
# and the host file takes them.
|
|
14
|
-
def writable? = !read_only? &&
|
|
14
|
+
def writable? = !read_only? && File.writable?(@path)
|
|
15
15
|
|
|
16
16
|
# Writes a new file, or with `replace` writes over the one of the
|
|
17
17
|
# same name in its directory entry. A name already on the disk
|
|
@@ -87,7 +87,7 @@ module Badline
|
|
|
87
87
|
saved = [@bytes.dup, @errors&.dup]
|
|
88
88
|
begin
|
|
89
89
|
yield
|
|
90
|
-
|
|
90
|
+
File.binwrite(@path, (@bytes + @errors.to_a).pack("C*"))
|
|
91
91
|
rescue WriteError, SystemCallError => e
|
|
92
92
|
@bytes, @errors = saved
|
|
93
93
|
raise e.is_a?(WriteError) ? e : WriteError.new(WriteError::WRITE_PROTECT_ON)
|
|
@@ -46,7 +46,7 @@ module Badline
|
|
|
46
46
|
# path, whether it is write-protected, and its bytes with the error
|
|
47
47
|
# table after them.
|
|
48
48
|
def save_setup(out)
|
|
49
|
-
out.int(storage_kind).string(
|
|
49
|
+
out.int(storage_kind).string(File.expand_path(@path)).boolean(@read_only).blob(@bytes + @errors.to_a)
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
# A LOAD reads only PRG files. An OPEN names the type it wants, or
|
data/lib/badline/storage/p00.rb
CHANGED
|
@@ -18,6 +18,14 @@ module Badline
|
|
|
18
18
|
def data(bytes)
|
|
19
19
|
bytes[HEADER_SIZE..]
|
|
20
20
|
end
|
|
21
|
+
|
|
22
|
+
# The load address of the program in a .prg file, or wrapped in a
|
|
23
|
+
# .p00 one, or -1 when the file is too short to have one.
|
|
24
|
+
def load_address(path)
|
|
25
|
+
bytes = File.binread(path).bytes
|
|
26
|
+
offset = wraps?(bytes) ? HEADER_SIZE : 0
|
|
27
|
+
bytes.size >= offset + 2 ? bytes[offset] | (bytes[offset + 1] << 8) : -1
|
|
28
|
+
end
|
|
21
29
|
end
|
|
22
30
|
end
|
|
23
31
|
end
|
data/lib/badline/storage/t64.rb
CHANGED
|
@@ -26,7 +26,7 @@ module Badline
|
|
|
26
26
|
# What Storage.reopen needs to open the archive again: its path and
|
|
27
27
|
# its bytes.
|
|
28
28
|
def save_setup(out)
|
|
29
|
-
out.int(T64_ARCHIVE).string(
|
|
29
|
+
out.int(T64_ARCHIVE).string(File.expand_path(@path)).blob(@bytes)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def read_file(name, **)
|
data/lib/badline/time_of_day.rb
CHANGED
|
@@ -52,9 +52,9 @@ module Badline
|
|
|
52
52
|
@latch = input.boolean? ? FIELDS.to_h { |field| [field, input.int] } : nil
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
# Whether the clock is stopped
|
|
56
|
-
# move only the divider's phase.
|
|
57
|
-
def quiet? = @stopped && !@alarm_pending
|
|
55
|
+
# Whether the clock is stopped, or gets no pulses on its pin, with no
|
|
56
|
+
# alarm to raise, so its cycles move only the divider's phase.
|
|
57
|
+
def quiet? = (@stopped || @mains_hz.zero?) && !@alarm_pending
|
|
58
58
|
|
|
59
59
|
# Runs +cycles+ quiet cycles at once.
|
|
60
60
|
def fast_forward(cycles)
|
data/lib/badline/version.rb
CHANGED
data/lib/badline/vic/bank.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Badline
|
|
4
|
-
class VIC
|
|
4
|
+
class VIC
|
|
5
5
|
# A mid-line color register write becomes visible one pixel into the
|
|
6
6
|
# column emitted the cycle after the write. That emit paints the whole
|
|
7
7
|
# column with the new color, so the boundary pixel is patched back to
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Badline
|
|
4
|
-
class VIC
|
|
4
|
+
class VIC
|
|
5
5
|
# The graphics shift register, pixel by pixel, for the groups where a
|
|
6
6
|
# mode or XSCROLL change lands (VICE x64sc `draw_graphics`). The
|
|
7
7
|
# sequencer paints whole bytes everywhere else, which comes to the same
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Badline
|
|
4
|
-
class VIC
|
|
4
|
+
class VIC
|
|
5
5
|
# Mid-line writes to the sprite registers, keyed by the pixel at which
|
|
6
6
|
# they become visible. Compositing replays the line through the log, so
|
|
7
7
|
# each pixel is drawn with the register values that were in effect when
|
data/lib/badline/vic/sprite.rb
CHANGED
data/lib/badline/vic/sprites.rb
CHANGED
data/lib/badline/vic.rb
CHANGED
|
@@ -7,7 +7,7 @@ require "badline/vic/sequencer"
|
|
|
7
7
|
require "badline/vic/sprites"
|
|
8
8
|
|
|
9
9
|
module Badline
|
|
10
|
-
class VIC
|
|
10
|
+
class VIC
|
|
11
11
|
include Addressable
|
|
12
12
|
include IntegerHelper
|
|
13
13
|
|
|
@@ -145,7 +145,6 @@ module Badline
|
|
|
145
145
|
@render = true
|
|
146
146
|
|
|
147
147
|
power_on!
|
|
148
|
-
super()
|
|
149
148
|
end
|
|
150
149
|
|
|
151
150
|
# The VIC has no reset pin, so only a power cycle brings back the
|
|
@@ -192,7 +191,7 @@ module Badline
|
|
|
192
191
|
# a front end repaints.
|
|
193
192
|
def save_state(out)
|
|
194
193
|
out.marker("VIC")
|
|
195
|
-
out.int(@column).int(@rasterline)
|
|
194
|
+
out.int(@column).int(@rasterline)
|
|
196
195
|
out.int(@g_tick).ints(@g_kind).int(@g_kept_char).int(@g_kept_color).boolean(@g_display)
|
|
197
196
|
out.int(@fetch_d011).boolean(@lp_triggered).boolean(@lp_low).boolean(@raster_match)
|
|
198
197
|
out.int(@vic_bank.lines)
|
|
@@ -469,8 +468,10 @@ module Badline
|
|
|
469
468
|
def load_beam(input)
|
|
470
469
|
@column = input.int
|
|
471
470
|
@rasterline = @output_line = input.int
|
|
472
|
-
|
|
473
|
-
|
|
471
|
+
if input.schema < 9
|
|
472
|
+
input.int
|
|
473
|
+
input.boolean?
|
|
474
|
+
end
|
|
474
475
|
@g_tick = input.int
|
|
475
476
|
input.ints_into(@g_kind)
|
|
476
477
|
@g_kept_char = input.int
|
|
@@ -3,9 +3,13 @@
|
|
|
3
3
|
module Badline
|
|
4
4
|
class Vic20
|
|
5
5
|
# What plugs into the VIC-20 besides its chips: cartridge ROM in the
|
|
6
|
-
# expansion blocks, the disk device 8 serves through the KERNAL traps
|
|
7
|
-
# and a true 1541 on the serial bus
|
|
6
|
+
# expansion blocks, the disk device 8 serves through the KERNAL traps
|
|
7
|
+
# (Computer::KernalTraps), and a true 1541 or 1581 on the serial bus
|
|
8
|
+
# (Computer::TrueDrives).
|
|
8
9
|
module Attachments
|
|
10
|
+
include Computer::TrueDrives
|
|
11
|
+
include Computer::KernalTraps
|
|
12
|
+
|
|
9
13
|
# The cycle by which a 1541 switched on with the machine has run its
|
|
10
14
|
# DOS's reset, the RAM test and the ROM checksum, and waits on the
|
|
11
15
|
# bus, with a margin: about 1.1 million of the VIC-20's cycles.
|
|
@@ -25,84 +29,24 @@ module Badline
|
|
|
25
29
|
power_cycle!
|
|
26
30
|
end
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
# point while the machine runs: the drive keeps its RAM and its
|
|
30
|
-
# status.
|
|
31
|
-
def mount(storage)
|
|
32
|
-
return @drive.insert(storage) if @drive
|
|
33
|
-
|
|
34
|
-
@drive = KernalTrap::Drive.new(storage)
|
|
35
|
-
layout = KernalTrap::VIC20_LAYOUT
|
|
36
|
-
load_trap = KernalTrap::Load.new(cpu:, bus:, layout:, drive: @drive)
|
|
37
|
-
cpu.install_trap(layout.load) { load_trap.call }
|
|
38
|
-
@serial_trap = KernalTrap::Serial.new(cpu:, bus:, layout:, drive: @drive, device: serial_trap_device).install
|
|
39
|
-
save_trap = @save_trap = KernalTrap::Save.new(cpu:, bus:, layout:, drive: @drive)
|
|
40
|
-
cpu.install_trap(layout.save) { save_trap.call }
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# Takes device 8's mounted storage out, and with it the LOAD, SAVE and
|
|
44
|
-
# serial traps, so the KERNAL's routines go out over the serial bus.
|
|
45
|
-
# Mounting again starts a new drive, with its RAM cleared.
|
|
46
|
-
def unmount
|
|
47
|
-
return unless @drive
|
|
32
|
+
private
|
|
48
33
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
@serial_trap.device = nil
|
|
52
|
-
@serial_trap = nil
|
|
53
|
-
@save_trap = nil
|
|
54
|
-
@drive = nil
|
|
55
|
-
end
|
|
34
|
+
# The VIC-20's KERNAL, which the traps stand in for.
|
|
35
|
+
def trap_layout = KernalTrap::VIC20_LAYOUT
|
|
56
36
|
|
|
57
|
-
|
|
58
|
-
def mounted? = !@drive.nil?
|
|
37
|
+
def trap_bus = @bus
|
|
59
38
|
|
|
60
|
-
# Plugs in a Drive1541, which then runs alongside the VIC-20 on its own
|
|
61
|
-
# clock and talks to it over the serial bus. The serial traps stop
|
|
62
|
-
# answering the drive's device number, so the KERNAL's TALK, LISTEN
|
|
63
|
-
# and byte transfers reach the drive. The LOAD and SAVE traps stay,
|
|
64
|
-
# and still serve a mounted image.
|
|
65
|
-
#
|
|
66
39
|
# A drive that powers on with the machine takes longer to boot than
|
|
67
40
|
# the KERNAL, and doesn't answer the bus until it has, so the
|
|
68
41
|
# machine's on_init handlers wait for it too.
|
|
69
|
-
def
|
|
42
|
+
def drive1541_attached
|
|
70
43
|
@init_threshold = [@init_threshold, DRIVE_BOOT_CYCLES].max if @cycles < @init_threshold
|
|
71
|
-
@iec_bus.detach(@drive1541) if @drive1541
|
|
72
|
-
drive.host_clock_hz = timing.clock_hz
|
|
73
|
-
@drive1541 = drive
|
|
74
|
-
drive.connect(@iec_bus)
|
|
75
|
-
@serial_trap&.device = serial_trap_device
|
|
76
44
|
end
|
|
77
45
|
|
|
78
|
-
#
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def plug_true_drive = Drive1541.new.tap { |drive| attach_drive1541(drive) }
|
|
83
|
-
|
|
84
|
-
# Unplugs the Drive1541, leaving the serial bus with nothing on it.
|
|
85
|
-
def detach_drive1541
|
|
86
|
-
return unless @drive1541
|
|
87
|
-
|
|
88
|
-
@iec_bus.detach(@drive1541)
|
|
89
|
-
@drive1541 = nil
|
|
90
|
-
@serial_trap&.device = serial_trap_device
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
# Records what the KERNAL prints through CHROUT (ChroutTrap).
|
|
94
|
-
def capture_output
|
|
95
|
-
@capture_output ||= ChroutTrap.new(cpu:, bus:, layout: KernalTrap::VIC20_LAYOUT).tap do |trap|
|
|
96
|
-
cpu.install_trap(ChroutTrap::ADDRESS) { trap.call }
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
private
|
|
101
|
-
|
|
102
|
-
# The device number the serial traps answer: device 8, unless a true
|
|
103
|
-
# drive is on the bus as device 8.
|
|
104
|
-
def serial_trap_device
|
|
105
|
-
@drive1541&.device == KernalTrap::Routine::DEVICE ? nil : KernalTrap::Routine::DEVICE
|
|
46
|
+
# A 1581 plugged in, as a 1541 does, holds the machine's on_init
|
|
47
|
+
# handlers back until its DOS has booted.
|
|
48
|
+
def drive1581_attached
|
|
49
|
+
@init_threshold = [@init_threshold, Drive1581::BOOT_CYCLES].max if @cycles < @init_threshold
|
|
106
50
|
end
|
|
107
51
|
end
|
|
108
52
|
end
|