badline 0.16.1 → 0.18.0
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 +213 -0
- data/CLAUDE.md +11 -7
- data/CONTRIBUTING.md +7 -1
- data/README.md +265 -26
- data/doc/media.md +5 -2
- data/doc/pinned-behaviour.md +189 -0
- data/doc/snapshot-format.md +616 -74
- data/doc/snapshots.md +192 -24
- data/exe/badline-ruby +5 -0
- data/lib/badline/audio/terminal.rb +34 -2
- data/lib/badline/c128/keyed_state.rb +2 -0
- data/lib/badline/c128.rb +1 -0
- data/lib/badline/c64/keyed_state.rb +2 -0
- data/lib/badline/c64.rb +1 -0
- data/lib/badline/cbm2/acia.rb +10 -0
- data/lib/badline/cbm2/bus.rb +263 -0
- data/lib/badline/cbm2/cpu.rb +58 -0
- data/lib/badline/cbm2/crtc_video.rb +133 -0
- data/lib/badline/cbm2/ieee_drive.rb +18 -0
- data/lib/badline/cbm2/ieee_layout.rb +69 -0
- data/lib/badline/cbm2/ieee_ports.rb +104 -0
- data/lib/badline/cbm2/ieee_traps.rb +81 -0
- data/lib/badline/cbm2/keyboard_ports.rb +60 -0
- data/lib/badline/cbm2/keyed_modules.rb +67 -0
- data/lib/badline/cbm2/keyed_state.rb +95 -0
- data/lib/badline/cbm2/model.rb +44 -0
- data/lib/badline/cbm2/p500/control_ports.rb +80 -0
- data/lib/badline/cbm2/p500/ieee_layout.rb +41 -0
- data/lib/badline/cbm2/p500/keyed_state.rb +85 -0
- data/lib/badline/cbm2/p500/model.rb +39 -0
- data/lib/badline/cbm2/p500/pages.rb +57 -0
- data/lib/badline/cbm2/p500.rb +264 -0
- data/lib/badline/cbm2/sid_page.rb +19 -0
- data/lib/badline/cbm2.rb +270 -0
- data/lib/badline/{plus4 → chips}/acia/frames.rb +1 -1
- data/lib/badline/chips/acia/keyed_state.rb +47 -0
- data/lib/badline/chips/acia.rb +307 -0
- data/lib/badline/chips/cia/timer.rb +2 -2
- data/lib/badline/chips/cpu/instruction_set.rb +1 -1
- data/lib/badline/chips/crtc.rb +3 -2
- data/lib/badline/chips/m6809/arithmetic.rb +140 -0
- data/lib/badline/chips/m6809/bus_steps.rb +223 -0
- data/lib/badline/chips/m6809/core.rb +149 -0
- data/lib/badline/chips/m6809/indexed.rb +82 -0
- data/lib/badline/chips/m6809/interrupts.rb +159 -0
- data/lib/badline/chips/m6809/keyed_state.rb +147 -0
- data/lib/badline/chips/m6809/opcodes.rb +159 -0
- data/lib/badline/chips/m6809/operations.rb +258 -0
- data/lib/badline/chips/m6809/plans.rb +143 -0
- data/lib/badline/chips/m6809/registers.rb +82 -0
- data/lib/badline/chips/m6809/stack.rb +140 -0
- data/lib/badline/chips/m6809.rb +13 -0
- data/lib/badline/chips/riot/fast_forward.rb +72 -0
- data/lib/badline/chips/riot/keyed_parts.rb +69 -0
- data/lib/badline/chips/riot/timer.rb +91 -0
- data/lib/badline/chips/riot.rb +162 -0
- data/lib/badline/chips/rriot/keyed_state.rb +30 -0
- data/lib/badline/chips/rriot.rb +134 -0
- data/lib/badline/chips/sid/filter.rb +4 -4
- data/lib/badline/chips/sid/waveform.rb +6 -6
- data/lib/badline/chips/tpi/keyed_state.rb +38 -0
- data/lib/badline/chips/tpi.rb +233 -0
- data/lib/badline/chips/vic/bank.rb +60 -5
- data/lib/badline/chips/vic/sprite.rb +4 -3
- data/lib/badline/chips/vic_i/keyed_parts.rb +7 -2
- data/lib/badline/chips/vic_i.rb +84 -21
- data/lib/badline/data_path.rb +3 -3
- data/lib/badline/drives/datasette/keyed_state.rb +9 -1
- data/lib/badline/drives/datasette.rb +27 -3
- data/lib/badline/drives/ieee_models.rb +54 -0
- data/lib/badline/drives/model1001.rb +37 -0
- data/lib/badline/drives/model2031.rb +6 -0
- data/lib/badline/drives/model4040/disk.rb +62 -0
- data/lib/badline/drives/model4040/ip_bus.rb +46 -0
- data/lib/badline/drives/model4040/keyed_state.rb +57 -0
- data/lib/badline/drives/model4040/mechanism.rb +192 -0
- data/lib/badline/drives/model4040/parts.rb +20 -0
- data/lib/badline/drives/model4040.rb +179 -0
- data/lib/badline/drives/model8050/board.rb +77 -0
- data/lib/badline/drives/model8050/disk.rb +163 -0
- data/lib/badline/drives/model8050/dos_board.rb +91 -0
- data/lib/badline/drives/model8050/fdc_bus.rb +102 -0
- data/lib/badline/drives/model8050/idle.rb +181 -0
- data/lib/badline/drives/model8050/ieee_port.rb +147 -0
- data/lib/badline/drives/model8050/ip_bus.rb +93 -0
- data/lib/badline/drives/model8050/keyed_state.rb +163 -0
- data/lib/badline/drives/model8050/mechanism.rb +230 -0
- data/lib/badline/drives/model8050/parts.rb +37 -0
- data/lib/badline/drives/model8050.rb +131 -0
- data/lib/badline/drives/model9060/idle.rb +149 -0
- data/lib/badline/drives/model9060/keyed_state.rb +123 -0
- data/lib/badline/drives/model9060/parts.rb +98 -0
- data/lib/badline/drives/model9060/sasi_bus.rb +88 -0
- data/lib/badline/drives/model9060/sasi_commands.rb +168 -0
- data/lib/badline/drives/model9060/sasi_target.rb +161 -0
- data/lib/badline/drives/model9060.rb +195 -0
- data/lib/badline/frontend/app.rb +18 -3
- data/lib/badline/frontend/boot.rb +4 -3
- data/lib/badline/frontend/controls.rb +107 -15
- data/lib/badline/frontend/gamepads.rb +3 -3
- data/lib/badline/frontend/keys.rb +97 -2
- data/lib/badline/frontend/kim1_panel.rb +208 -0
- data/lib/badline/frontend/media_slots.rb +8 -1
- data/lib/badline/frontend/menu/drive_types.rb +56 -0
- data/lib/badline/frontend/menu/menu_dialogs.rb +61 -14
- data/lib/badline/frontend/menu/menu_media.rb +47 -14
- data/lib/badline/frontend/menu/menu_pages.rb +113 -4
- data/lib/badline/frontend/menu/menu_ports.rb +77 -4
- data/lib/badline/frontend/menu/pause_menu.rb +6 -2
- data/lib/badline/frontend/pet_keyboard.rb +45 -7
- data/lib/badline/frontend/screen.rb +1 -1
- data/lib/badline/frontend/screens.rb +40 -2
- data/lib/badline/frontend/teletype_pane.rb +152 -0
- data/lib/badline/frontend/timeline.rb +49 -11
- data/lib/badline/frontend.rb +3 -0
- data/lib/badline/kernal_trap/dos/disk_commands.rb +80 -0
- data/lib/badline/kernal_trap/dos/status.rb +3 -0
- data/lib/badline/kernal_trap/dos.rb +18 -5
- data/lib/badline/kernal_trap/ieee.rb +4 -2
- data/lib/badline/kernal_trap/ieee_layout.rb +95 -43
- data/lib/badline/kim1/bus.rb +117 -0
- data/lib/badline/kim1/cpu.rb +25 -0
- data/lib/badline/kim1/host_terminal.rb +74 -0
- data/lib/badline/kim1/key_entry.rb +74 -0
- data/lib/badline/kim1/keyed_modules.rb +53 -0
- data/lib/badline/kim1/keyed_state.rb +133 -0
- data/lib/badline/kim1/panel.rb +176 -0
- data/lib/badline/kim1/rriots.rb +28 -0
- data/lib/badline/kim1/sound.rb +29 -0
- data/lib/badline/kim1/tape.rb +116 -0
- data/lib/badline/kim1/teletype.rb +193 -0
- data/lib/badline/kim1.rb +190 -0
- data/lib/badline/machine/ieee_drives.rb +171 -0
- data/lib/badline/machine/keyboard_buffer.rb +20 -3
- data/lib/badline/machine/line_sound.rb +122 -0
- data/lib/badline/machine/settling.rb +4 -0
- data/lib/badline/machine.rb +62 -14
- data/lib/badline/media/cbm2_media.rb +29 -0
- data/lib/badline/media/extensions.rb +8 -4
- data/lib/badline/media/kim1_media.rb +150 -0
- data/lib/badline/media/pet_media.rb +3 -1
- data/lib/badline/media/program.rb +6 -3
- data/lib/badline/media/true_drive.rb +51 -25
- data/lib/badline/media.rb +23 -8
- data/lib/badline/options/family.rb +108 -6
- data/lib/badline/options/help.rb +58 -12
- data/lib/badline/options/table.rb +60 -14
- data/lib/badline/options/validation.rb +71 -11
- data/lib/badline/options.rb +46 -13
- data/lib/badline/pet/bus.rb +16 -2
- data/lib/badline/pet/cassettes.rb +22 -1
- data/lib/badline/pet/ieee_drive.rb +5 -64
- data/lib/badline/pet/ieee_ports.rb +7 -0
- data/lib/badline/pet/keyboard_ports.rb +9 -2
- data/lib/badline/pet/keyed_state.rb +4 -0
- data/lib/badline/pet/model.rb +11 -2
- data/lib/badline/pet/rom_sets.rb +1 -0
- data/lib/badline/pet/sound.rb +5 -105
- data/lib/badline/pet/superpet/acia.rb +12 -0
- data/lib/badline/pet/superpet/board.rb +221 -0
- data/lib/badline/pet/superpet/dongle.rb +81 -0
- data/lib/badline/pet/superpet/keyed_modules.rb +63 -0
- data/lib/badline/pet/superpet/keyed_parts.rb +76 -0
- data/lib/badline/pet/superpet/m6809.rb +32 -0
- data/lib/badline/pet/superpet/waterloo_traps.rb +199 -0
- data/lib/badline/pet/superpet.rb +216 -0
- data/lib/badline/pet.rb +33 -6
- data/lib/badline/plus4/acia.rb +4 -298
- data/lib/badline/plus4/keyed_parts.rb +0 -44
- data/lib/badline/plus4/keyed_state.rb +2 -0
- data/lib/badline/plus4.rb +2 -0
- data/lib/badline/roms/1001/fdc-251257-02a.rom +0 -0
- data/lib/badline/roms/4040/dos-1.2.rom +0 -0
- data/lib/badline/roms/4040/dos-2.1-rev.rom +0 -0
- data/lib/badline/roms/4040/dos-2.1.rom +0 -0
- data/lib/badline/roms/4040/fdc-901466-02.rom +0 -0
- data/lib/badline/roms/4040/fdc-901466-04.rom +0 -0
- data/lib/badline/roms/8050/dos-2.7.rom +0 -0
- data/lib/badline/roms/8050/fdc-901869-01.rom +0 -0
- data/lib/badline/roms/8050/fdc-901885-04.rom +0 -0
- data/lib/badline/roms/9060/dos-3.0.rom +0 -0
- data/lib/badline/roms/9060/sasi-300515-revb.rom +0 -0
- data/lib/badline/roms/README +277 -0
- data/lib/badline/roms/cbm2/basic128-02b.rom +0 -0
- data/lib/badline/roms/cbm2/basic128.rom +0 -0
- data/lib/badline/roms/cbm2/basic256.rom +0 -0
- data/lib/badline/roms/cbm2/characters-600.rom +0 -0
- data/lib/badline/roms/cbm2/characters-700.rom +0 -0
- data/lib/badline/roms/cbm2/kernal-03b.rom +0 -0
- data/lib/badline/roms/cbm2/kernal-04a.rom +0 -0
- data/lib/badline/roms/cbm2/p500-basic.rom +0 -0
- data/lib/badline/roms/cbm2/p500-kernal.rom +0 -0
- data/lib/badline/roms/kim1/6530-002.rom +0 -0
- data/lib/badline/roms/kim1/6530-003.rom +0 -0
- data/lib/badline/roms/pet/characters-superpet.rom +0 -0
- data/lib/badline/roms/pet/superpet-a000.rom +0 -0
- data/lib/badline/roms/pet/superpet-c000.rom +0 -0
- data/lib/badline/roms/pet/superpet-e000-50hz.rom +0 -0
- data/lib/badline/roms/pet/superpet-e000.rom +0 -0
- data/lib/badline/snapshot/cbm2_setup.rb +53 -0
- data/lib/badline/snapshot/container.rb +9 -2
- data/lib/badline/snapshot/field_doc/markdown.rb +4 -2
- data/lib/badline/snapshot/field_doc.rb +59 -3
- data/lib/badline/snapshot/image.rb +65 -9
- data/lib/badline/snapshot/kim1_setup.rb +28 -0
- data/lib/badline/snapshot/pet_setup.rb +27 -11
- data/lib/badline/snapshot/storage_setup.rb +4 -1
- data/lib/badline/snapshot/vic20_setup.rb +11 -7
- data/lib/badline/snapshot/vice/cbm2.rb +93 -0
- data/lib/badline/snapshot/vice/cbm2_acia.rb +75 -0
- data/lib/badline/snapshot/vice/cbm2_crtc.rb +127 -0
- data/lib/badline/snapshot/vice/cbm2_mains.rb +49 -0
- data/lib/badline/snapshot/vice/cbm2_mem.rb +75 -0
- data/lib/badline/snapshot/vice/cbm2_restore.rb +204 -0
- data/lib/badline/snapshot/vice/cbm2_tpi.rb +58 -0
- data/lib/badline/snapshot/vice/cias.rb +13 -9
- data/lib/badline/snapshot/vice/p500.rb +96 -0
- data/lib/badline/snapshot/vice/p500_restore.rb +130 -0
- data/lib/badline/snapshot/vice/p500_vicii.rb +166 -0
- data/lib/badline/snapshot/vice/pet.rb +20 -10
- data/lib/badline/snapshot/vice/pet_cpu.rb +42 -5
- data/lib/badline/snapshot/vice/pet_crtc.rb +25 -17
- data/lib/badline/snapshot/vice/pet_drive.rb +180 -0
- data/lib/badline/snapshot/vice/pet_drive8050.rb +336 -0
- data/lib/badline/snapshot/vice/pet_mem.rb +49 -5
- data/lib/badline/snapshot/vice/pet_restore.rb +100 -7
- data/lib/badline/snapshot/vice/pet_via.rb +6 -5
- data/lib/badline/snapshot/vice/sid_registers.rb +2 -1
- data/lib/badline/snapshot/vice/vicii_import.rb +10 -6
- data/lib/badline/snapshot/vice.rb +3 -0
- data/lib/badline/snapshot.rb +15 -3
- data/lib/badline/status.rb +30 -30
- data/lib/badline/storage/crt_file.rb +7 -1
- data/lib/badline/storage/d64_image.rb +7 -0
- data/lib/badline/storage/d67_image.rb +55 -0
- data/lib/badline/storage/d80_image.rb +17 -1
- data/lib/badline/storage/d81_image.rb +14 -0
- data/lib/badline/storage/d90_image.rb +180 -0
- data/lib/badline/storage/disk_image/bam.rb +18 -3
- data/lib/badline/storage/disk_image/formatting.rb +69 -0
- data/lib/badline/storage/disk_image/writing.rb +37 -2
- data/lib/badline/storage/disk_image.rb +2 -0
- data/lib/badline/storage/kim_tape.rb +254 -0
- data/lib/badline/storage/papertape.rb +90 -0
- data/lib/badline/storage.rb +5 -0
- data/lib/badline/support/cbm2_checkpoint.rb +48 -0
- data/lib/badline/support/kim1_checkpoint.rb +41 -0
- data/lib/badline/support/p500_checkpoint.rb +35 -0
- data/lib/badline/support/superpet_checkpoint.rb +35 -0
- data/lib/badline/version.rb +1 -1
- data/lib/badline/vic20/keyed_modules.rb +6 -3
- data/lib/badline/vic20/keyed_state.rb +6 -4
- data/lib/badline/vic20.rb +26 -12
- data/lib/badline.rb +2 -0
- metadata +148 -2
|
@@ -4,20 +4,24 @@ module Badline
|
|
|
4
4
|
module Snapshot
|
|
5
5
|
module Vice
|
|
6
6
|
module VICII
|
|
7
|
-
# Reads a VIC-II module and puts it into badline's VIC.
|
|
7
|
+
# Reads a VIC-II module and puts it into badline's VIC. A reader of
|
|
8
|
+
# another layout passes no fields and sets the same state itself.
|
|
8
9
|
class Import
|
|
9
10
|
def initialize(fields)
|
|
10
11
|
@fields = fields
|
|
12
|
+
return if fields.nil?
|
|
13
|
+
|
|
11
14
|
read_beam
|
|
12
15
|
read_counters
|
|
13
16
|
read_sprites
|
|
14
17
|
end
|
|
15
18
|
|
|
16
|
-
def apply(computer)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
def apply(computer) = apply_to(computer.vic, computer.address_bus.color_ram, 0xd800)
|
|
20
|
+
|
|
21
|
+
# Puts it into `vic`, with its colour RAM into `color_ram` from
|
|
22
|
+
# `base`.
|
|
23
|
+
def apply_to(vic, color_ram, base)
|
|
24
|
+
@color_ram.each_with_index { |value, offset| color_ram.poke(base + offset, value) }
|
|
21
25
|
load_registers(vic)
|
|
22
26
|
position(vic)
|
|
23
27
|
load_counters(vic)
|
|
@@ -14,6 +14,9 @@ require "badline/snapshot/vice/vicii"
|
|
|
14
14
|
require "badline/snapshot/vice/vicii_import"
|
|
15
15
|
require "badline/snapshot/vice/restore"
|
|
16
16
|
require "badline/snapshot/vice/pet"
|
|
17
|
+
require "badline/snapshot/vice/cbm2"
|
|
18
|
+
require "badline/snapshot/vice/p500"
|
|
19
|
+
require "badline/snapshot/vice/p500_restore"
|
|
17
20
|
|
|
18
21
|
module Badline
|
|
19
22
|
module Snapshot
|
data/lib/badline/snapshot.rb
CHANGED
|
@@ -36,8 +36,8 @@ module Badline
|
|
|
36
36
|
# end of the instruction its CPU is in, and of an REU transfer under
|
|
37
37
|
# way (Machine::Settling), so a save advances it by a few cycles, and a
|
|
38
38
|
# second save straight after runs none. A VIC-20's, a C128's, a
|
|
39
|
-
# Plus/4's or a
|
|
40
|
-
# xplus4 or
|
|
39
|
+
# Plus/4's, a PET's or a CBM-II's snapshot is in a container named as
|
|
40
|
+
# xvic, x128, xplus4, xpet or xcbm2 names its machine.
|
|
41
41
|
def dump(computer) = Image.of(computer).to_s
|
|
42
42
|
|
|
43
43
|
def read(path) = Image.new(Container.parse(File.binread(path)), name: File.basename(path))
|
|
@@ -52,7 +52,7 @@ module Badline
|
|
|
52
52
|
def restore(computer, path, &) = read(path).restore(computer, &)
|
|
53
53
|
|
|
54
54
|
# A machine's snapshots, as .vsf files and in memory. C64, Vic20, C128,
|
|
55
|
-
# Plus4 and
|
|
55
|
+
# Plus4, PET, CBM2 and CBM2::P500 each include it.
|
|
56
56
|
module Files
|
|
57
57
|
def save_snapshot(path) = Snapshot.save(self, path)
|
|
58
58
|
|
|
@@ -99,4 +99,16 @@ module Badline
|
|
|
99
99
|
class PET
|
|
100
100
|
include Snapshot::Files
|
|
101
101
|
end
|
|
102
|
+
|
|
103
|
+
class KIM1
|
|
104
|
+
include Snapshot::Files
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
class CBM2
|
|
108
|
+
include Snapshot::Files
|
|
109
|
+
|
|
110
|
+
class P500
|
|
111
|
+
include Snapshot::Files
|
|
112
|
+
end
|
|
113
|
+
end
|
|
102
114
|
end
|
data/lib/badline/status.rb
CHANGED
|
@@ -36,7 +36,7 @@ module Badline
|
|
|
36
36
|
@value = enabled && enabled != 0 ? @value | 0x01 : @value & ~0x01
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
def carry? = @value
|
|
39
|
+
def carry? = @value.anybits?(0x01)
|
|
40
40
|
|
|
41
41
|
def carry = @value.nobits?(0x01) ? 0 : 1
|
|
42
42
|
|
|
@@ -44,7 +44,7 @@ module Badline
|
|
|
44
44
|
@value = enabled && enabled != 0 ? @value | 0x02 : @value & ~0x02
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
def zero? = @value
|
|
47
|
+
def zero? = @value.anybits?(0x02)
|
|
48
48
|
|
|
49
49
|
def zero = @value.nobits?(0x02) ? 0 : 1
|
|
50
50
|
|
|
@@ -52,7 +52,7 @@ module Badline
|
|
|
52
52
|
@value = enabled && enabled != 0 ? @value | 0x04 : @value & ~0x04
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
def interrupt? = @value
|
|
55
|
+
def interrupt? = @value.anybits?(0x04)
|
|
56
56
|
|
|
57
57
|
def interrupt = @value.nobits?(0x04) ? 0 : 1
|
|
58
58
|
|
|
@@ -60,7 +60,7 @@ module Badline
|
|
|
60
60
|
@value = enabled && enabled != 0 ? @value | 0x08 : @value & ~0x08
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
-
def decimal? = @value
|
|
63
|
+
def decimal? = @value.anybits?(0x08)
|
|
64
64
|
|
|
65
65
|
def decimal = @value.nobits?(0x08) ? 0 : 1
|
|
66
66
|
|
|
@@ -68,7 +68,7 @@ module Badline
|
|
|
68
68
|
@value = enabled && enabled != 0 ? @value | 0x10 : @value & ~0x10
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
-
def break? = @value
|
|
71
|
+
def break? = @value.anybits?(0x10)
|
|
72
72
|
|
|
73
73
|
def break = @value.nobits?(0x10) ? 0 : 1
|
|
74
74
|
|
|
@@ -76,7 +76,7 @@ module Badline
|
|
|
76
76
|
@value = enabled && enabled != 0 ? @value | 0x40 : @value & ~0x40
|
|
77
77
|
end
|
|
78
78
|
|
|
79
|
-
def overflow? = @value
|
|
79
|
+
def overflow? = @value.anybits?(0x40)
|
|
80
80
|
|
|
81
81
|
def overflow = @value.nobits?(0x40) ? 0 : 1
|
|
82
82
|
|
|
@@ -84,7 +84,7 @@ module Badline
|
|
|
84
84
|
@value = enabled && enabled != 0 ? @value | 0x80 : @value & ~0x80
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
-
def negative? = @value
|
|
87
|
+
def negative? = @value.anybits?(0x80)
|
|
88
88
|
|
|
89
89
|
def negative = @value.nobits?(0x80) ? 0 : 1
|
|
90
90
|
end
|
|
@@ -95,7 +95,7 @@ module Badline
|
|
|
95
95
|
@value = enabled && enabled != 0 ? @value | 0x01 : @value & ~0x01
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
-
def basic? = @value
|
|
98
|
+
def basic? = @value.anybits?(0x01)
|
|
99
99
|
|
|
100
100
|
def basic = @value.nobits?(0x01) ? 0 : 1
|
|
101
101
|
|
|
@@ -103,7 +103,7 @@ module Badline
|
|
|
103
103
|
@value = enabled && enabled != 0 ? @value | 0x02 : @value & ~0x02
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
-
def kernal? = @value
|
|
106
|
+
def kernal? = @value.anybits?(0x02)
|
|
107
107
|
|
|
108
108
|
def kernal = @value.nobits?(0x02) ? 0 : 1
|
|
109
109
|
|
|
@@ -111,7 +111,7 @@ module Badline
|
|
|
111
111
|
@value = enabled && enabled != 0 ? @value | 0x04 : @value & ~0x04
|
|
112
112
|
end
|
|
113
113
|
|
|
114
|
-
def io? = @value
|
|
114
|
+
def io? = @value.anybits?(0x04)
|
|
115
115
|
|
|
116
116
|
def io = @value.nobits?(0x04) ? 0 : 1
|
|
117
117
|
|
|
@@ -119,7 +119,7 @@ module Badline
|
|
|
119
119
|
@value = enabled && enabled != 0 ? @value | 0x08 : @value & ~0x08
|
|
120
120
|
end
|
|
121
121
|
|
|
122
|
-
def tape_out? = @value
|
|
122
|
+
def tape_out? = @value.anybits?(0x08)
|
|
123
123
|
|
|
124
124
|
def tape_out = @value.nobits?(0x08) ? 0 : 1
|
|
125
125
|
|
|
@@ -127,7 +127,7 @@ module Badline
|
|
|
127
127
|
@value = enabled && enabled != 0 ? @value | 0x10 : @value & ~0x10
|
|
128
128
|
end
|
|
129
129
|
|
|
130
|
-
def tape_switch? = @value
|
|
130
|
+
def tape_switch? = @value.anybits?(0x10)
|
|
131
131
|
|
|
132
132
|
def tape_switch = @value.nobits?(0x10) ? 0 : 1
|
|
133
133
|
|
|
@@ -135,7 +135,7 @@ module Badline
|
|
|
135
135
|
@value = enabled && enabled != 0 ? @value | 0x20 : @value & ~0x20
|
|
136
136
|
end
|
|
137
137
|
|
|
138
|
-
def tape_motor? = @value
|
|
138
|
+
def tape_motor? = @value.anybits?(0x20)
|
|
139
139
|
|
|
140
140
|
def tape_motor = @value.nobits?(0x20) ? 0 : 1
|
|
141
141
|
end
|
|
@@ -146,7 +146,7 @@ module Badline
|
|
|
146
146
|
@value = enabled && enabled != 0 ? @value | 0x01 : @value & ~0x01
|
|
147
147
|
end
|
|
148
148
|
|
|
149
|
-
def start? = @value
|
|
149
|
+
def start? = @value.anybits?(0x01)
|
|
150
150
|
|
|
151
151
|
def start = @value.nobits?(0x01) ? 0 : 1
|
|
152
152
|
|
|
@@ -154,7 +154,7 @@ module Badline
|
|
|
154
154
|
@value = enabled && enabled != 0 ? @value | 0x02 : @value & ~0x02
|
|
155
155
|
end
|
|
156
156
|
|
|
157
|
-
def output? = @value
|
|
157
|
+
def output? = @value.anybits?(0x02)
|
|
158
158
|
|
|
159
159
|
def output = @value.nobits?(0x02) ? 0 : 1
|
|
160
160
|
|
|
@@ -162,7 +162,7 @@ module Badline
|
|
|
162
162
|
@value = enabled && enabled != 0 ? @value | 0x04 : @value & ~0x04
|
|
163
163
|
end
|
|
164
164
|
|
|
165
|
-
def out_mode? = @value
|
|
165
|
+
def out_mode? = @value.anybits?(0x04)
|
|
166
166
|
|
|
167
167
|
def out_mode = @value.nobits?(0x04) ? 0 : 1
|
|
168
168
|
|
|
@@ -170,7 +170,7 @@ module Badline
|
|
|
170
170
|
@value = enabled && enabled != 0 ? @value | 0x08 : @value & ~0x08
|
|
171
171
|
end
|
|
172
172
|
|
|
173
|
-
def run_mode? = @value
|
|
173
|
+
def run_mode? = @value.anybits?(0x08)
|
|
174
174
|
|
|
175
175
|
def run_mode = @value.nobits?(0x08) ? 0 : 1
|
|
176
176
|
|
|
@@ -178,7 +178,7 @@ module Badline
|
|
|
178
178
|
@value = enabled && enabled != 0 ? @value | 0x10 : @value & ~0x10
|
|
179
179
|
end
|
|
180
180
|
|
|
181
|
-
def load? = @value
|
|
181
|
+
def load? = @value.anybits?(0x10)
|
|
182
182
|
|
|
183
183
|
def load = @value.nobits?(0x10) ? 0 : 1
|
|
184
184
|
|
|
@@ -186,7 +186,7 @@ module Badline
|
|
|
186
186
|
@value = enabled && enabled != 0 ? @value | 0x20 : @value & ~0x20
|
|
187
187
|
end
|
|
188
188
|
|
|
189
|
-
def in_mode? = @value
|
|
189
|
+
def in_mode? = @value.anybits?(0x20)
|
|
190
190
|
|
|
191
191
|
def in_mode = @value.nobits?(0x20) ? 0 : 1
|
|
192
192
|
|
|
@@ -194,7 +194,7 @@ module Badline
|
|
|
194
194
|
@value = enabled && enabled != 0 ? @value | 0x40 : @value & ~0x40
|
|
195
195
|
end
|
|
196
196
|
|
|
197
|
-
def serial_mode? = @value
|
|
197
|
+
def serial_mode? = @value.anybits?(0x40)
|
|
198
198
|
|
|
199
199
|
def serial_mode = @value.nobits?(0x40) ? 0 : 1
|
|
200
200
|
|
|
@@ -202,7 +202,7 @@ module Badline
|
|
|
202
202
|
@value = enabled && enabled != 0 ? @value | 0x80 : @value & ~0x80
|
|
203
203
|
end
|
|
204
204
|
|
|
205
|
-
def clock_frequency? = @value
|
|
205
|
+
def clock_frequency? = @value.anybits?(0x80)
|
|
206
206
|
|
|
207
207
|
def clock_frequency = @value.nobits?(0x80) ? 0 : 1
|
|
208
208
|
|
|
@@ -210,7 +210,7 @@ module Badline
|
|
|
210
210
|
@value = enabled && enabled != 0 ? @value | 0x20 : @value & ~0x20
|
|
211
211
|
end
|
|
212
212
|
|
|
213
|
-
def in_cnt? = @value
|
|
213
|
+
def in_cnt? = @value.anybits?(0x20)
|
|
214
214
|
|
|
215
215
|
def in_cnt = @value.nobits?(0x20) ? 0 : 1
|
|
216
216
|
|
|
@@ -218,7 +218,7 @@ module Badline
|
|
|
218
218
|
@value = enabled && enabled != 0 ? @value | 0x40 : @value & ~0x40
|
|
219
219
|
end
|
|
220
220
|
|
|
221
|
-
def in_timer_a? = @value
|
|
221
|
+
def in_timer_a? = @value.anybits?(0x40)
|
|
222
222
|
|
|
223
223
|
def in_timer_a = @value.nobits?(0x40) ? 0 : 1
|
|
224
224
|
|
|
@@ -226,7 +226,7 @@ module Badline
|
|
|
226
226
|
@value = enabled && enabled != 0 ? @value | 0x80 : @value & ~0x80
|
|
227
227
|
end
|
|
228
228
|
|
|
229
|
-
def alarm? = @value
|
|
229
|
+
def alarm? = @value.anybits?(0x80)
|
|
230
230
|
|
|
231
231
|
def alarm = @value.nobits?(0x80) ? 0 : 1
|
|
232
232
|
end
|
|
@@ -237,7 +237,7 @@ module Badline
|
|
|
237
237
|
@value = enabled && enabled != 0 ? @value | 0x01 : @value & ~0x01
|
|
238
238
|
end
|
|
239
239
|
|
|
240
|
-
def timer_a? = @value
|
|
240
|
+
def timer_a? = @value.anybits?(0x01)
|
|
241
241
|
|
|
242
242
|
def timer_a = @value.nobits?(0x01) ? 0 : 1
|
|
243
243
|
|
|
@@ -245,7 +245,7 @@ module Badline
|
|
|
245
245
|
@value = enabled && enabled != 0 ? @value | 0x02 : @value & ~0x02
|
|
246
246
|
end
|
|
247
247
|
|
|
248
|
-
def timer_b? = @value
|
|
248
|
+
def timer_b? = @value.anybits?(0x02)
|
|
249
249
|
|
|
250
250
|
def timer_b = @value.nobits?(0x02) ? 0 : 1
|
|
251
251
|
|
|
@@ -253,7 +253,7 @@ module Badline
|
|
|
253
253
|
@value = enabled && enabled != 0 ? @value | 0x04 : @value & ~0x04
|
|
254
254
|
end
|
|
255
255
|
|
|
256
|
-
def alarm? = @value
|
|
256
|
+
def alarm? = @value.anybits?(0x04)
|
|
257
257
|
|
|
258
258
|
def alarm = @value.nobits?(0x04) ? 0 : 1
|
|
259
259
|
|
|
@@ -261,7 +261,7 @@ module Badline
|
|
|
261
261
|
@value = enabled && enabled != 0 ? @value | 0x08 : @value & ~0x08
|
|
262
262
|
end
|
|
263
263
|
|
|
264
|
-
def serial? = @value
|
|
264
|
+
def serial? = @value.anybits?(0x08)
|
|
265
265
|
|
|
266
266
|
def serial = @value.nobits?(0x08) ? 0 : 1
|
|
267
267
|
|
|
@@ -269,7 +269,7 @@ module Badline
|
|
|
269
269
|
@value = enabled && enabled != 0 ? @value | 0x10 : @value & ~0x10
|
|
270
270
|
end
|
|
271
271
|
|
|
272
|
-
def flag? = @value
|
|
272
|
+
def flag? = @value.anybits?(0x10)
|
|
273
273
|
|
|
274
274
|
def flag = @value.nobits?(0x10) ? 0 : 1
|
|
275
275
|
|
|
@@ -277,7 +277,7 @@ module Badline
|
|
|
277
277
|
@value = enabled && enabled != 0 ? @value | 0x80 : @value & ~0x80
|
|
278
278
|
end
|
|
279
279
|
|
|
280
|
-
def interrupt? = @value
|
|
280
|
+
def interrupt? = @value.anybits?(0x80)
|
|
281
281
|
|
|
282
282
|
def interrupt = @value.nobits?(0x80) ? 0 : 1
|
|
283
283
|
end
|
|
@@ -8,6 +8,7 @@ module Badline
|
|
|
8
8
|
SIGNATURE = "C64 CARTRIDGE ".b
|
|
9
9
|
VIC20_SIGNATURE = "VIC20 CARTRIDGE ".b
|
|
10
10
|
PLUS4_SIGNATURE = "PLUS4 CARTRIDGE ".b
|
|
11
|
+
CBM2_SIGNATURE = "CBM2 CARTRIDGE ".b
|
|
11
12
|
CHIP_SIGNATURE = "CHIP".b
|
|
12
13
|
CHIP_HEADER_SIZE = 0x10
|
|
13
14
|
RAM_CHIP = 1
|
|
@@ -19,6 +20,9 @@ module Badline
|
|
|
19
20
|
# What .write needs of an image: the fields a parsed CRTFile reads.
|
|
20
21
|
Image = Data.define(:hardware_type, :subtype, :exrom, :game, :name, :chips)
|
|
21
22
|
|
|
23
|
+
# Whether the file at +path+ is signed as a CBM-II's cartridge.
|
|
24
|
+
def self.cbm2?(path) = File.binread(path, CBM2_SIGNATURE.length) == CBM2_SIGNATURE
|
|
25
|
+
|
|
22
26
|
def self.write(path, image)
|
|
23
27
|
File.binwrite(path, encode(image))
|
|
24
28
|
end
|
|
@@ -36,7 +40,8 @@ module Badline
|
|
|
36
40
|
end
|
|
37
41
|
|
|
38
42
|
# `bytes` stands in for the file's contents. `machine` is the one the
|
|
39
|
-
# image has to be for, :c64, :vic20 or :
|
|
43
|
+
# image has to be for, :c64, :vic20, :plus4 or :cbm2, or nil for
|
|
44
|
+
# any.
|
|
40
45
|
def initialize(path = nil, bytes: nil, machine: :c64)
|
|
41
46
|
parse(bytes || File.binread(path))
|
|
42
47
|
return if machine.nil? || @machine == machine
|
|
@@ -60,6 +65,7 @@ module Badline
|
|
|
60
65
|
return :c64 if bytes.start_with?(SIGNATURE)
|
|
61
66
|
return :vic20 if bytes.start_with?(VIC20_SIGNATURE)
|
|
62
67
|
return :plus4 if bytes.start_with?(PLUS4_SIGNATURE)
|
|
68
|
+
return :cbm2 if bytes.start_with?(CBM2_SIGNATURE)
|
|
63
69
|
|
|
64
70
|
raise FormatError, "Missing CRT signature"
|
|
65
71
|
end
|
|
@@ -52,6 +52,13 @@ module Badline
|
|
|
52
52
|
def bam_tracks = 1..35
|
|
53
53
|
def bam_count(track) = [18, 0, 4 * track]
|
|
54
54
|
def bam_bitmap(track) = [18, 0, (4 * track) + 1]
|
|
55
|
+
def bitmap_size = 3
|
|
56
|
+
|
|
57
|
+
# The header links the directory and holds the BAM itself.
|
|
58
|
+
def header_link = [18, 1]
|
|
59
|
+
def dos_type = "2A"
|
|
60
|
+
def header_tail = 4
|
|
61
|
+
def bam_headers(_id) = []
|
|
55
62
|
end
|
|
56
63
|
end
|
|
57
64
|
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Storage
|
|
5
|
+
# A 2040's disk, as DOS 1 formats it: the 1541's 35 tracks and speed
|
|
6
|
+
# zones, with 20 sectors on tracks 18 to 24 in place of 19, 690 blocks
|
|
7
|
+
# in all. The BAM and the directory are where a 1541's are, on 18/0
|
|
8
|
+
# and 18/1, but the BAM's format byte is $01 and the header has no DOS
|
|
9
|
+
# type after the ID, as c1541 formats a .d67.
|
|
10
|
+
class D67Image < DiskImage
|
|
11
|
+
ERROR_TABLES = { 177_330 => 690 }.freeze
|
|
12
|
+
|
|
13
|
+
# The sectors a track holds in each of the 1541's speed zones, by its
|
|
14
|
+
# number, from zone 0, the innermost.
|
|
15
|
+
ZONE_SECTORS = [17, 18, 20, 21].freeze
|
|
16
|
+
|
|
17
|
+
# The tracks the image holds.
|
|
18
|
+
def track_count = 35
|
|
19
|
+
|
|
20
|
+
def sides = 1
|
|
21
|
+
|
|
22
|
+
def sectors_in(track) = ZONE_SECTORS[D64Image.zone(track)]
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def error_tables = ERROR_TABLES
|
|
27
|
+
|
|
28
|
+
def header_name = 0x90
|
|
29
|
+
def directory_track = 18
|
|
30
|
+
def directory_sector = 1
|
|
31
|
+
def directory_interleave = 3
|
|
32
|
+
def interleave = 10
|
|
33
|
+
def reserved_tracks = [18]
|
|
34
|
+
|
|
35
|
+
def bam_tracks = 1..35
|
|
36
|
+
def bam_count(track) = [18, 0, 4 * track]
|
|
37
|
+
def bam_bitmap(track) = [18, 0, (4 * track) + 1]
|
|
38
|
+
def bitmap_size = 3
|
|
39
|
+
|
|
40
|
+
def header_link = [18, 1]
|
|
41
|
+
def dos_type = " "
|
|
42
|
+
def header_tail = 5
|
|
43
|
+
def bam_headers(_id) = []
|
|
44
|
+
|
|
45
|
+
# The link to the directory, the format byte $01, and after the name
|
|
46
|
+
# the ID and two spaces.
|
|
47
|
+
def write_header(name, id)
|
|
48
|
+
write_at(*header_block, 0, [*header_link, 0x01, 0])
|
|
49
|
+
write_at(*header_block, header_name,
|
|
50
|
+
encode_name(name) + [NAME_PADDING, NAME_PADDING] + id + dos_type.bytes +
|
|
51
|
+
Array.new(header_tail, NAME_PADDING))
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -31,7 +31,7 @@ module Badline
|
|
|
31
31
|
def directory_track = 39
|
|
32
32
|
def directory_sector = 1
|
|
33
33
|
def directory_interleave = 3
|
|
34
|
-
def interleave =
|
|
34
|
+
def interleave = 5
|
|
35
35
|
|
|
36
36
|
# Only the directory track is kept from files. The BAM's blocks on
|
|
37
37
|
# track 38 are marked in use, and the rest of that track holds files.
|
|
@@ -43,6 +43,22 @@ module Badline
|
|
|
43
43
|
def bam_tracks = 1..SIDE_TRACKS
|
|
44
44
|
def bam_count(track) = [38, 3 * ((track - 1) / 50), 6 + (5 * ((track - 1) % 50))]
|
|
45
45
|
def bam_bitmap(track) = [38, 3 * ((track - 1) / 50), 7 + (5 * ((track - 1) % 50))]
|
|
46
|
+
def bitmap_size = 4
|
|
47
|
+
|
|
48
|
+
# The header links the BAM's first block, and each BAM block the next,
|
|
49
|
+
# the last one the directory. A BAM block names the format and the
|
|
50
|
+
# first track it covers and the one past its last.
|
|
51
|
+
def header_link = [38, 0]
|
|
52
|
+
def dos_type = "2C"
|
|
53
|
+
def header_tail = 4
|
|
54
|
+
|
|
55
|
+
def bam_headers(_id)
|
|
56
|
+
groups = bam_tracks.each_slice(50).to_a
|
|
57
|
+
groups.each_with_index.map do |tracks, block|
|
|
58
|
+
link = block == groups.length - 1 ? [directory_track, directory_sector] : [38, 3 * (block + 1)]
|
|
59
|
+
[38, 3 * block, [*link, dos_type.getbyte(1), 0, tracks.first, tracks.last + 1]]
|
|
60
|
+
end
|
|
61
|
+
end
|
|
46
62
|
end
|
|
47
63
|
end
|
|
48
64
|
end
|
|
@@ -21,6 +21,20 @@ module Badline
|
|
|
21
21
|
def bam_tracks = 1..80
|
|
22
22
|
def bam_count(track) = [40, track > 40 ? 2 : 1, 0x10 + (((track - 1) % 40) * 6)]
|
|
23
23
|
def bam_bitmap(track) = [40, track > 40 ? 2 : 1, 0x11 + (((track - 1) % 40) * 6)]
|
|
24
|
+
def bitmap_size = 5
|
|
25
|
+
|
|
26
|
+
# The header links the directory's first block, at 40/3. Each BAM
|
|
27
|
+
# block links the next, names the format and its complement, and
|
|
28
|
+
# holds the ID and the I/O byte.
|
|
29
|
+
def header_link = [40, 3]
|
|
30
|
+
def dos_type = "3D"
|
|
31
|
+
def header_tail = 2
|
|
32
|
+
|
|
33
|
+
def bam_headers(id)
|
|
34
|
+
[[40, 1, [40, 2]], [40, 2, [0, 0xff]]].map do |track, sector, link|
|
|
35
|
+
[track, sector, [*link, 0x44, 0xbb, *id, 0xc0, 0]]
|
|
36
|
+
end
|
|
37
|
+
end
|
|
24
38
|
|
|
25
39
|
def sectors_in(_track) = 40
|
|
26
40
|
end
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module Storage
|
|
5
|
+
# A D9060 or D9090 hard disk: 153 cylinders of 32 blocks a head, four
|
|
6
|
+
# heads on the D9060 and six on the D9090. DOS 3.0 numbers a block by
|
|
7
|
+
# its cylinder as the track, from 0, and by head × 32 + sector as the
|
|
8
|
+
# sector. The controller numbers the same block by its place in the
|
|
9
|
+
# image (LBA), and reads and writes it there.
|
|
10
|
+
#
|
|
11
|
+
# The image's size tells the two apart. One of another size, such as an
|
|
12
|
+
# empty file to format, takes the heads it's given, or four, and reads as
|
|
13
|
+
# zeros past its end.
|
|
14
|
+
class D90Image < DiskImage
|
|
15
|
+
CYLINDERS = 153
|
|
16
|
+
SECTORS_PER_HEAD = 32
|
|
17
|
+
|
|
18
|
+
# The heads of each drive, by the size of its image.
|
|
19
|
+
HEADS = { 5_013_504 => 4, 7_520_256 => 6 }.freeze
|
|
20
|
+
|
|
21
|
+
# The BAM entry of a head: a free count and a four-byte bitmap.
|
|
22
|
+
ENTRY = 5
|
|
23
|
+
|
|
24
|
+
# The heads of the drive an image of the size belongs to, or nil for
|
|
25
|
+
# a size neither has.
|
|
26
|
+
def self.heads_for(size) = HEADS[size]
|
|
27
|
+
|
|
28
|
+
attr_reader :heads
|
|
29
|
+
|
|
30
|
+
def initialize(path, read_only: false, bytes: nil, heads: nil)
|
|
31
|
+
super(path, read_only:, bytes:)
|
|
32
|
+
@heads = heads || HEADS.fetch(@bytes.length, 4)
|
|
33
|
+
size = block_count * SECTOR_SIZE
|
|
34
|
+
@bytes.concat(Array.new(size - @bytes.length, 0)) if @bytes.length < size
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def sectors_in(_track) = @heads * SECTORS_PER_HEAD
|
|
38
|
+
|
|
39
|
+
# The blocks the disk holds.
|
|
40
|
+
def block_count = CYLINDERS * sectors_in(0)
|
|
41
|
+
|
|
42
|
+
# The controller's number for the block.
|
|
43
|
+
def lba(track, sector) = (track * sectors_in(track)) + sector
|
|
44
|
+
|
|
45
|
+
def header_block = [76, 20]
|
|
46
|
+
|
|
47
|
+
# Whether the disk holds the blocks from the LBA on.
|
|
48
|
+
def blocks?(lba, count) = lba >= 0 && lba + count <= block_count
|
|
49
|
+
|
|
50
|
+
# The bytes of the blocks from the LBA on, or nil when the disk
|
|
51
|
+
# doesn't hold them all.
|
|
52
|
+
def read_blocks(lba, count)
|
|
53
|
+
@bytes[lba * SECTOR_SIZE, count * SECTOR_SIZE] if blocks?(lba, count)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Writes whole blocks from the LBA on, straight to the host file. It
|
|
57
|
+
# writes nothing when the disk doesn't hold them all. A disk that
|
|
58
|
+
# takes no writes raises WRITE PROTECT ON and keeps its blocks.
|
|
59
|
+
def write_blocks(lba, bytes)
|
|
60
|
+
return unless (bytes.length % SECTOR_SIZE).zero? && blocks?(lba, bytes.length / SECTOR_SIZE)
|
|
61
|
+
raise WriteError, WriteError::WRITE_PROTECT_ON unless writable?
|
|
62
|
+
|
|
63
|
+
store(lba * SECTOR_SIZE, bytes)
|
|
64
|
+
@bytes[lba * SECTOR_SIZE, bytes.length] = bytes
|
|
65
|
+
@entries = nil
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def bam_block?(track, sector) = block?(track, sector)
|
|
69
|
+
|
|
70
|
+
def block_free?(track, sector)
|
|
71
|
+
block?(track, sector) && @bytes[bitmap_byte(track, sector)][sector % 8] == 1
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def error_tables = {}
|
|
77
|
+
|
|
78
|
+
def store(offset, bytes)
|
|
79
|
+
File.open(@path, "r+b") do |file|
|
|
80
|
+
file.seek(offset)
|
|
81
|
+
file.write(bytes.pack("C*"))
|
|
82
|
+
end
|
|
83
|
+
rescue SystemCallError
|
|
84
|
+
raise WriteError, WriteError::WRITE_PROTECT_ON
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def block?(track, sector)
|
|
88
|
+
track.between?(0, CYLINDERS - 1) && sector.between?(0, sectors_in(track) - 1)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def track_offset(track) = track * sectors_in(track)
|
|
92
|
+
|
|
93
|
+
def clear_blocks
|
|
94
|
+
header = sector_offset(*header_block)
|
|
95
|
+
@bytes.fill(0, 0, header)
|
|
96
|
+
@bytes.fill(0, header + SECTOR_SIZE, (block_count * SECTOR_SIZE) - header - SECTOR_SIZE)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# The header at 76/20 holds the disk name at $06 and the ID at $18,
|
|
100
|
+
# after the link to the directory's first block, 76/10.
|
|
101
|
+
def header_name = 0x06
|
|
102
|
+
def directory_track = 76
|
|
103
|
+
def directory_sector = 10
|
|
104
|
+
def directory_interleave = 3
|
|
105
|
+
def interleave = 10
|
|
106
|
+
def reserved_tracks = [76]
|
|
107
|
+
|
|
108
|
+
# A link to track 0 ends a chain, so files never go there.
|
|
109
|
+
def allocation_order = super - [0]
|
|
110
|
+
|
|
111
|
+
def bam_tracks = 0..(CYLINDERS - 1)
|
|
112
|
+
def header_link = [76, 10]
|
|
113
|
+
def dos_type = "3A"
|
|
114
|
+
def header_tail = 4
|
|
115
|
+
|
|
116
|
+
# The header holds no format letter after its link.
|
|
117
|
+
def write_header(name, id)
|
|
118
|
+
super
|
|
119
|
+
write_at(*header_block, 2, [0])
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# The BAM takes sector 0 of a cylinder for each group of cylinders
|
|
123
|
+
# its entries fit in, twelve on a D9060 and eight on a D9090: the
|
|
124
|
+
# cylinder after the group's first, or the last one for a group of
|
|
125
|
+
# one at the end.
|
|
126
|
+
def tracks_per_bam_block = (SECTOR_SIZE - 16) / (@heads * ENTRY)
|
|
127
|
+
|
|
128
|
+
def bam_block_track(track)
|
|
129
|
+
first = track - (track % tracks_per_bam_block)
|
|
130
|
+
[first + 1, CYLINDERS - 1].min
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def entry_offset(track, sector)
|
|
134
|
+
group = track % tracks_per_bam_block
|
|
135
|
+
sector_offset(bam_block_track(track), 0) + 16 +
|
|
136
|
+
(((group * @heads) + (sector / SECTORS_PER_HEAD)) * ENTRY)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def bitmap_byte(track, sector) = entry_offset(track, sector) + 1 + ((sector % SECTORS_PER_HEAD) / 8)
|
|
140
|
+
|
|
141
|
+
def mark(track, sector, free)
|
|
142
|
+
return if !block?(track, sector) || block_free?(track, sector) == free
|
|
143
|
+
|
|
144
|
+
entry = entry_offset(track, sector)
|
|
145
|
+
byte = bitmap_byte(track, sector)
|
|
146
|
+
bit = 1 << (sector % 8)
|
|
147
|
+
@bytes[byte] = free ? @bytes[byte] | bit : @bytes[byte] & ~bit
|
|
148
|
+
@bytes[entry] = (@bytes[entry] + (free ? 1 : -1)) & 0xff
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def free_track(track)
|
|
152
|
+
@heads.times do |head|
|
|
153
|
+
@bytes[entry_offset(track, head * SECTORS_PER_HEAD), ENTRY] = [SECTORS_PER_HEAD, 0xff, 0xff, 0xff, 0xff]
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def blocks_free
|
|
158
|
+
(bam_tracks.to_a - reserved_tracks).sum do |track|
|
|
159
|
+
(0...@heads).sum { |head| @bytes[entry_offset(track, head * SECTORS_PER_HEAD)] }
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Block 0/0 points at the bad-block list in 0/1, the directory, the
|
|
164
|
+
# header and the BAM's first block, and holds the ID. Each BAM block
|
|
165
|
+
# links the next and the one before it, $FF $FF at either end, and
|
|
166
|
+
# names the first cylinder it covers and the one past its last.
|
|
167
|
+
def bam_headers(id)
|
|
168
|
+
groups = bam_tracks.each_slice(tracks_per_bam_block).to_a
|
|
169
|
+
blocks = groups.map { |tracks| bam_block_track(tracks.first) }
|
|
170
|
+
bam = groups.each_with_index.map do |tracks, i|
|
|
171
|
+
following = i == groups.length - 1 ? [0xff, 0xff] : [blocks[i + 1], 0]
|
|
172
|
+
previous = i.zero? ? [0xff, 0xff] : [blocks[i - 1], 0]
|
|
173
|
+
[blocks[i], 0, [*following, *previous, tracks.first, tracks.last + 1]]
|
|
174
|
+
end
|
|
175
|
+
[[0, 0, [0, 1, 0, 0xff, *header_link, *header_block, blocks.first, 0, *id]],
|
|
176
|
+
[0, 1, Array.new(SECTOR_SIZE, 0xff)], *bam]
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|