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
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "badline/chips/tpi/keyed_state"
|
|
4
|
+
|
|
5
|
+
module Badline
|
|
6
|
+
module Chips
|
|
7
|
+
# The MOS 6525 TPI (tri-port interface): three 8-bit ports, A, B and C,
|
|
8
|
+
# each with a direction register, a 1 making the pin an output. Its
|
|
9
|
+
# three address lines repeat the eight registers every 8 bytes:
|
|
10
|
+
#
|
|
11
|
+
# 0 - PRA
|
|
12
|
+
# 1 - PRB
|
|
13
|
+
# 2 - PRC, or in mode 1 the interrupt latches (bits 0-4) and the levels
|
|
14
|
+
# of IRQ, CA and CB (bits 5-7)
|
|
15
|
+
# 3 - DDRA
|
|
16
|
+
# 4 - DDRB
|
|
17
|
+
# 5 - DDRC, which in mode 1 is the interrupt mask, its bits 0-4 enabling
|
|
18
|
+
# I0-I4 with a 1, and reads back all eight bits written
|
|
19
|
+
# 6 - CR: bit 0 MC, the mode, bit 1 IP, the priority, bits 2-3 IE3 and
|
|
20
|
+
# IE4, the active edges of I3 and I4 (1 rising), bits 4-5 CA's mode
|
|
21
|
+
# and bits 6-7 CB's
|
|
22
|
+
# 7 - AIR, the active interrupt register, in mode 1
|
|
23
|
+
#
|
|
24
|
+
# A port reads its pins: an output's level, and what the peripheral
|
|
25
|
+
# lets through of an input, which floats high (read_a, read_b and
|
|
26
|
+
# read_c pull lines low, as a VIA's peripheral does).
|
|
27
|
+
#
|
|
28
|
+
# In mode 1 PC0-PC4 are the interrupt inputs I0-I4 (#interrupt_line).
|
|
29
|
+
# A falling edge on I0-I2, or the edge IE3 and IE4 pick on I3 and I4,
|
|
30
|
+
# sets the input's latch whether or not its mask bit is set. A write of
|
|
31
|
+
# 0 to a latch's bit of PRC clears it, and a 1 does nothing. PC5 is
|
|
32
|
+
# the IRQ output, open drain, low (#irq?) while the AIR holds a bit;
|
|
33
|
+
# PC6 is CA and PC7 CB (#ca?, #cb?).
|
|
34
|
+
#
|
|
35
|
+
# Without priority (IP 0), the AIR holds every unmasked latch that is
|
|
36
|
+
# set, and a read of it clears them and it. With priority (IP 1) the
|
|
37
|
+
# inputs rank I4 > I3 > I2 > I1 > I0, and the AIR holds the one highest
|
|
38
|
+
# unmasked latch that outranks the interrupt in service, the top of a
|
|
39
|
+
# five-level stack. A read of the AIR pushes it on the stack, clears it
|
|
40
|
+
# and its latch, and lets IRQ go; a write pops the stack, letting lower
|
|
41
|
+
# interrupts through again.
|
|
42
|
+
#
|
|
43
|
+
# CA: 00 set high by I3's active edge and low by a read of PRA, 01
|
|
44
|
+
# pulsed low by a read of PRA, 10 low, 11 high. CB: 00 set low by a
|
|
45
|
+
# write of PRB and high by I4's active edge, 01 pulsed low by a write of
|
|
46
|
+
# PRB, 10 low, 11 high. A pulse is shorter than a cycle, so CA and CB
|
|
47
|
+
# read high in mode 01.
|
|
48
|
+
#
|
|
49
|
+
# The rules are the MPS 6525 datasheet's (Commodore Semiconductor
|
|
50
|
+
# Group), pages 2-81 to 2-83.
|
|
51
|
+
class TPI
|
|
52
|
+
STACK_DEPTH = 5
|
|
53
|
+
|
|
54
|
+
attr_reader :peripheral, :latches, :control, :stack
|
|
55
|
+
|
|
56
|
+
def initialize(peripheral: nil)
|
|
57
|
+
@peripheral = peripheral
|
|
58
|
+
@lines = 0x1f
|
|
59
|
+
@stack = []
|
|
60
|
+
reset!
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# The RES pin clears every register: mode 0, and every pin an input.
|
|
64
|
+
def reset!
|
|
65
|
+
@pra = @prb = @prc = 0
|
|
66
|
+
@ddra = @ddrb = @ddrc = 0
|
|
67
|
+
@control = 0
|
|
68
|
+
@latches = 0
|
|
69
|
+
@air = 0
|
|
70
|
+
@stack.clear
|
|
71
|
+
@ca = @cb = false
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# The interrupt mask in mode 1: DDRC's bits 0-4.
|
|
75
|
+
def mask = @ddrc & 0x1f
|
|
76
|
+
|
|
77
|
+
# Whether IRQ is pulled low.
|
|
78
|
+
def irq? = @air != 0
|
|
79
|
+
|
|
80
|
+
# The levels of CA and CB in mode 1.
|
|
81
|
+
def ca? = @ca
|
|
82
|
+
|
|
83
|
+
def cb? = @cb
|
|
84
|
+
|
|
85
|
+
# The port lines as the chip drives them, inputs floating high.
|
|
86
|
+
def port_a_output = driven(@pra, @ddra)
|
|
87
|
+
|
|
88
|
+
def port_b_output = driven(@prb, @ddrb)
|
|
89
|
+
|
|
90
|
+
def port_c_output = mode1? ? pins_c_mode1 : driven(@prc, @ddrc)
|
|
91
|
+
|
|
92
|
+
# Something outside drives interrupt input +index+, I0 to I4, +high+
|
|
93
|
+
# or low. Its active edge sets its latch in mode 1.
|
|
94
|
+
def interrupt_line(index, high)
|
|
95
|
+
bit = 1 << index
|
|
96
|
+
was_high = @lines.anybits?(bit)
|
|
97
|
+
return if was_high == high
|
|
98
|
+
|
|
99
|
+
@lines = high ? @lines | bit : @lines & ~bit
|
|
100
|
+
return unless mode1? && high == rising_active?(index)
|
|
101
|
+
|
|
102
|
+
@latches |= bit
|
|
103
|
+
@ca = true if index == 3 && ca_mode.zero?
|
|
104
|
+
@cb = true if index == 4 && cb_mode.zero?
|
|
105
|
+
update_air
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def peek(addr)
|
|
109
|
+
case addr & 0x07
|
|
110
|
+
when 0 then read_pra
|
|
111
|
+
when 1 then pins(@prb, @ddrb, @peripheral ? @peripheral.read_b(port_b_output) : 0xff)
|
|
112
|
+
when 2 then mode1? ? pins_c_mode1 : read_pins_c
|
|
113
|
+
when 3 then @ddra
|
|
114
|
+
when 4 then @ddrb
|
|
115
|
+
when 5 then @ddrc
|
|
116
|
+
when 6 then @control
|
|
117
|
+
else read_air
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def poke(addr, value)
|
|
122
|
+
case addr & 0x07
|
|
123
|
+
when 0 then @pra = value
|
|
124
|
+
when 1 then write_prb(value)
|
|
125
|
+
when 2 then write_prc(value)
|
|
126
|
+
when 3 then @ddra = value
|
|
127
|
+
when 4 then @ddrb = value
|
|
128
|
+
when 5 then write_ddrc(value)
|
|
129
|
+
when 6 then write_control(value)
|
|
130
|
+
else pop_air
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
private
|
|
135
|
+
|
|
136
|
+
def mode1? = @control.anybits?(0x01)
|
|
137
|
+
|
|
138
|
+
def priority? = @control.anybits?(0x02)
|
|
139
|
+
|
|
140
|
+
def ca_mode = (@control >> 4) & 0x03
|
|
141
|
+
|
|
142
|
+
def cb_mode = (@control >> 6) & 0x03
|
|
143
|
+
|
|
144
|
+
# I3 and I4 latch on the edge IE3 and IE4 pick, the others falling.
|
|
145
|
+
def rising_active?(index)
|
|
146
|
+
case index
|
|
147
|
+
when 3 then @control.anybits?(0x04)
|
|
148
|
+
when 4 then @control.anybits?(0x08)
|
|
149
|
+
else false
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def driven(register, direction) = (register & direction) | (~direction & 0xff)
|
|
154
|
+
|
|
155
|
+
def pins(register, direction, inputs) = (register & direction) | (inputs & ~direction & 0xff)
|
|
156
|
+
|
|
157
|
+
def read_pra
|
|
158
|
+
@ca = false if mode1? && ca_mode.zero?
|
|
159
|
+
pins(@pra, @ddra, @peripheral ? @peripheral.read_a(port_a_output) : 0xff)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def read_pins_c
|
|
163
|
+
pins(@prc, @ddrc, @peripheral ? @peripheral.read_c(port_c_output) : 0xff)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# The latches, IRQ's level, CA's and CB's.
|
|
167
|
+
def pins_c_mode1
|
|
168
|
+
@latches | (irq? ? 0 : 0x20) | (@ca ? 0x40 : 0) | (@cb ? 0x80 : 0)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def write_prb(value)
|
|
172
|
+
@prb = value
|
|
173
|
+
@cb = false if mode1? && cb_mode.zero?
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def write_prc(value)
|
|
177
|
+
return @prc = value unless mode1?
|
|
178
|
+
|
|
179
|
+
@latches &= value | 0xe0
|
|
180
|
+
update_air
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def write_ddrc(value)
|
|
184
|
+
@ddrc = value
|
|
185
|
+
update_air
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def write_control(value)
|
|
189
|
+
@control = value
|
|
190
|
+
@ca = ca_mode.anybits?(0x01) unless ca_mode.zero?
|
|
191
|
+
@cb = cb_mode.anybits?(0x01) unless cb_mode.zero?
|
|
192
|
+
update_air
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def read_air
|
|
196
|
+
value = @air
|
|
197
|
+
return value unless mode1?
|
|
198
|
+
|
|
199
|
+
@latches &= ~value
|
|
200
|
+
@air = 0
|
|
201
|
+
if priority?
|
|
202
|
+
@stack.shift if @stack.length == STACK_DEPTH
|
|
203
|
+
@stack << value
|
|
204
|
+
end
|
|
205
|
+
update_air
|
|
206
|
+
value
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def pop_air
|
|
210
|
+
return unless mode1?
|
|
211
|
+
|
|
212
|
+
@stack.pop
|
|
213
|
+
update_air
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# The AIR's bits from the latches, the mask and, with priority, the
|
|
217
|
+
# interrupt in service.
|
|
218
|
+
def update_air
|
|
219
|
+
pending = mode1? ? @latches & mask : 0
|
|
220
|
+
return @air = pending unless priority?
|
|
221
|
+
|
|
222
|
+
highest = highest_bit(pending)
|
|
223
|
+
@air = highest > (@stack.last || 0) ? highest : 0
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def highest_bit(bits)
|
|
227
|
+
bit = 0x10
|
|
228
|
+
bit >>= 1 while bit.positive? && bits.nobits?(bit)
|
|
229
|
+
bit
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
@@ -10,6 +10,13 @@ module Badline
|
|
|
10
10
|
# The machine's bus pushes in what the VIC sees through #connect,
|
|
11
11
|
# #map_character_rom and #map whenever it changes. Until then the bank
|
|
12
12
|
# has a CIA 2, RAM, colour RAM and character ROM of its own.
|
|
13
|
+
#
|
|
14
|
+
# The P500 wires the VIC another way (#map_video_bus): its phi1
|
|
15
|
+
# reads go to the character ROM while VICDOTSEL is high, and its phi2
|
|
16
|
+
# reads to the 1K static video matrix while STATVID is high, VA12
|
|
17
|
+
# high picking the matrix and VA12 low reading 0. Otherwise both go to
|
|
18
|
+
# the DRAM's 16K bank that VA14 and VA15 pick (#video_bus_lines). The
|
|
19
|
+
# colour nibbles come from the colour RAM in every phi2 read.
|
|
13
20
|
class Bank
|
|
14
21
|
include Addressable
|
|
15
22
|
|
|
@@ -30,6 +37,11 @@ module Badline
|
|
|
30
37
|
map(Memory.new([], length: 2**16, start: 0))
|
|
31
38
|
@lines = 0b11
|
|
32
39
|
@swapped = false
|
|
40
|
+
@video_bus = false
|
|
41
|
+
@matrix = @ram
|
|
42
|
+
@statvid = false
|
|
43
|
+
@dotsel = false
|
|
44
|
+
@video_base = 0
|
|
33
45
|
end
|
|
34
46
|
|
|
35
47
|
# CIA 2, whose port A picks the bank, and the colour RAM, read from
|
|
@@ -57,9 +69,31 @@ module Badline
|
|
|
57
69
|
@base = base
|
|
58
70
|
@starts = BANK_STARTS.map { |start| base + start }.freeze
|
|
59
71
|
end
|
|
60
|
-
@phi1_ultimax = phi1_ultimax
|
|
61
|
-
@ultimax = ultimax
|
|
62
72
|
@romh = romh
|
|
73
|
+
@phi1_other = phi1_ultimax
|
|
74
|
+
@phi2_other = ultimax
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# The P500's video bus: +dram+ is segment 0's 64K, +matrix+ the
|
|
78
|
+
# static video matrix, read from its start address on, and
|
|
79
|
+
# +color_ram+ the colour RAM, read from +color_base+ on. The
|
|
80
|
+
# character ROM is the one #map_character_rom gives, read from
|
|
81
|
+
# +base+ on.
|
|
82
|
+
def map_video_bus(dram, matrix, color_ram, color_base)
|
|
83
|
+
@ram = dram
|
|
84
|
+
@matrix = matrix
|
|
85
|
+
@color_ram = color_ram
|
|
86
|
+
@color_base = color_base
|
|
87
|
+
@video_bus = true
|
|
88
|
+
@phi1_other = true
|
|
89
|
+
@phi2_other = true
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# STATVID, VICDOTSEL and VA14-VA15, as the P500's TPIs drive them.
|
|
93
|
+
def video_bus_lines(statvid, dotsel, bank)
|
|
94
|
+
@statvid = statvid
|
|
95
|
+
@dotsel = dotsel
|
|
96
|
+
@video_base = bank << 14
|
|
63
97
|
end
|
|
64
98
|
|
|
65
99
|
# On the 8565, a port A write that swaps the two bank lines, driving
|
|
@@ -74,7 +108,7 @@ module Badline
|
|
|
74
108
|
end
|
|
75
109
|
|
|
76
110
|
def peek(offset)
|
|
77
|
-
return
|
|
111
|
+
return phi1_other(offset) if @phi1_other
|
|
78
112
|
|
|
79
113
|
bits = bank_switch_register
|
|
80
114
|
if (bits & @shadow_mask) == 0b01 && (offset & 0xf000) == 0x1000
|
|
@@ -88,7 +122,13 @@ module Badline
|
|
|
88
122
|
# memory configuration the CPU does in that half. No cartridge drives
|
|
89
123
|
# Ultimax mode in the first half alone, so otherwise it reads as #peek.
|
|
90
124
|
def peek_phi2(offset)
|
|
91
|
-
@
|
|
125
|
+
@phi2_other ? phi2_other(offset) : peek(offset)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# A sprite's s-access in phi2: on the P500's video bus as the other
|
|
129
|
+
# phi2 reads, and otherwise as #peek.
|
|
130
|
+
def peek_sprite(offset)
|
|
131
|
+
@video_bus ? phi2_other(offset) : peek(offset)
|
|
92
132
|
end
|
|
93
133
|
|
|
94
134
|
def peek_color(offset)
|
|
@@ -101,7 +141,7 @@ module Badline
|
|
|
101
141
|
|
|
102
142
|
# True if the VIC reads the character ROM at this offset.
|
|
103
143
|
def character_rom?(offset)
|
|
104
|
-
!@
|
|
144
|
+
!@phi1_other && (bank_switch_register & @shadow_mask) == 0b01 && (offset & 0xf000) == 0x1000
|
|
105
145
|
end
|
|
106
146
|
|
|
107
147
|
def start
|
|
@@ -110,6 +150,21 @@ module Badline
|
|
|
110
150
|
|
|
111
151
|
private
|
|
112
152
|
|
|
153
|
+
def phi1_other(offset)
|
|
154
|
+
return ultimax_peek(offset) unless @video_bus
|
|
155
|
+
return @character_rom.peek(@character_base + (offset & 0x0fff)) if @dotsel
|
|
156
|
+
|
|
157
|
+
@ram.peek(@video_base + offset)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def phi2_other(offset)
|
|
161
|
+
return ultimax_peek(offset) unless @video_bus
|
|
162
|
+
return @ram.peek(@video_base + offset) unless @statvid
|
|
163
|
+
return 0 if offset.nobits?(0x1000)
|
|
164
|
+
|
|
165
|
+
@matrix.peek(@matrix.start + (offset & 0x03ff))
|
|
166
|
+
end
|
|
167
|
+
|
|
113
168
|
# In Ultimax mode the cartridge ROMH replaces the character ROM
|
|
114
169
|
# shadow, visible at $3000-$3FFF of the window. The MAX is in
|
|
115
170
|
# Ultimax mode with no cartridge too.
|
|
@@ -322,12 +322,13 @@ module Badline
|
|
|
322
322
|
end
|
|
323
323
|
|
|
324
324
|
# The three s-accesses step MC through the sprite's block, wrapping
|
|
325
|
-
# within it.
|
|
325
|
+
# within it. The first and third fall in phi2 and the second in
|
|
326
|
+
# phi1 (Bank#peek_sprite).
|
|
326
327
|
def row_bits(counter)
|
|
327
328
|
base = pointer * 64
|
|
328
|
-
(@bank.
|
|
329
|
+
(@bank.peek_sprite(base + counter) << 16) |
|
|
329
330
|
(@bank.peek(base + ((counter + 1) & MC_MASK)) << 8) |
|
|
330
|
-
@bank.
|
|
331
|
+
@bank.peek_sprite(base + ((counter + 2) & MC_MASK))
|
|
331
332
|
end
|
|
332
333
|
|
|
333
334
|
def pointer = @bank.peek(@registers.screen_base + 0x3f8 + index)
|
|
@@ -86,13 +86,15 @@ module Badline
|
|
|
86
86
|
LINE_LAYOUT = 1
|
|
87
87
|
|
|
88
88
|
# The VIC-I's fields in a keyed snapshot module (Snapshot::Keyed): the
|
|
89
|
-
# registers, the beam, the
|
|
90
|
-
#
|
|
89
|
+
# registers, the beam, the frame's length in lines and whether the
|
|
90
|
+
# next interlaced field is the long one, the text window's counters
|
|
91
|
+
# and the fetch in flight, the painter's lines under line.*, the picture, and the sound
|
|
91
92
|
# under sound.* What the registers decode to, where the line's fetches
|
|
92
93
|
# end and the next event are worked out on load.
|
|
93
94
|
module KeyedState
|
|
94
95
|
def save_fields(out)
|
|
95
96
|
out.bytes("registers", @registers).int("raster", @rasterline).int("column", @column)
|
|
97
|
+
out.int("frame_lines", @frame_lines).bool("long_field", @long_field)
|
|
96
98
|
out.bool("window_open", @window_open).bool("window_done", @window_done).int("row_start", @row_start)
|
|
97
99
|
out.int("matrix", @matrix).int("char_line", @char_line).int("text_rows", @text_rows)
|
|
98
100
|
out.int("fetch_from", @fetch_from).int("fetched", @fetched).int("code", @code)
|
|
@@ -106,6 +108,8 @@ module Badline
|
|
|
106
108
|
input.bytes_into("registers", @registers)
|
|
107
109
|
@rasterline = input.int("raster", @rasterline)
|
|
108
110
|
@column = input.int("column", @column)
|
|
111
|
+
@frame_lines = input.int("frame_lines", @lines_per_frame)
|
|
112
|
+
@long_field = input.bool("long_field", true)
|
|
109
113
|
@window_open = input.bool("window_open", @window_open)
|
|
110
114
|
@window_done = input.bool("window_done", @window_done)
|
|
111
115
|
@row_start = input.int("row_start", @row_start)
|
|
@@ -122,6 +126,7 @@ module Badline
|
|
|
122
126
|
end
|
|
123
127
|
|
|
124
128
|
def restored!
|
|
129
|
+
@frame_wrap = @frame_lines == @interlaced_lines ? @count_column : @wrap_column
|
|
125
130
|
@origin_x = @registers[0] & 0x7f
|
|
126
131
|
@columns = @registers[2] & 0x7f
|
|
127
132
|
@origin_y = @registers[1]
|
data/lib/badline/chips/vic_i.rb
CHANGED
|
@@ -7,13 +7,15 @@ require "badline/chips/vic_i/keyed_parts"
|
|
|
7
7
|
|
|
8
8
|
module Badline
|
|
9
9
|
module Chips
|
|
10
|
-
# The VIC-I, the 6561 on PAL machines
|
|
10
|
+
# The VIC-I, the 6561 on PAL machines or the 6560 on NTSC ones: its
|
|
11
|
+
# sixteen registers, the
|
|
11
12
|
# raster, the text window's fetches over the V-bus and the picture. The
|
|
12
13
|
# writes to the sound's registers, $900A-$900E, go on to the Sound
|
|
13
14
|
# attached as #sound.
|
|
14
15
|
#
|
|
15
16
|
# The registers repeat through $9000-$90FF. $9003 bit 7 and $9004 read
|
|
16
|
-
# the raster
|
|
17
|
+
# the raster count, its bit 0 and bits 8-1, which on the 6561 is the
|
|
18
|
+
# raster line (see Profile for the 6560's). $9006 and $9007 read the
|
|
17
19
|
# light pen, which nothing triggers yet, and $9008 and $9009 the two
|
|
18
20
|
# pots, which read $FF with nothing plugged in. The other registers
|
|
19
21
|
# read back what was written to them.
|
|
@@ -35,23 +37,48 @@ module Badline
|
|
|
35
37
|
# of a text row where the row started, and the next row starts where
|
|
36
38
|
# the last line of the row left it. It starts the frame at zero.
|
|
37
39
|
#
|
|
38
|
-
# The picture is 4 pixels a cycle, so 284 a line
|
|
39
|
-
# pixels come out in the two cycles after its
|
|
40
|
-
# display's lines start 6 cycles after the raster
|
|
41
|
-
# xvic's view of the frame does, so the character
|
|
42
|
-
# into the line lands 48 pixels in. Lines 0-27 are
|
|
40
|
+
# The picture is 4 pixels a cycle, so 284 a line on the 6561 and 260 on
|
|
41
|
+
# the 6560. A character's 8 pixels come out in the two cycles after its
|
|
42
|
+
# pattern fetch. The display's lines start 6 cycles after the raster
|
|
43
|
+
# line moves, as xvic's view of the frame does, so the character
|
|
44
|
+
# fetched 16 cycles into the line lands 48 pixels in. Lines 0-27 are
|
|
45
|
+
# blanked.
|
|
43
46
|
class VICI
|
|
44
47
|
include TextWindow
|
|
45
48
|
|
|
46
49
|
# What a VIC-I sets for the machine: the clock, the raster's cycles
|
|
47
|
-
# per line and lines per frame,
|
|
48
|
-
#
|
|
49
|
-
# the
|
|
50
|
-
|
|
50
|
+
# per line and lines per frame, how many lines at the top of the frame
|
|
51
|
+
# it blanks and how many it shows from there, and where in the line
|
|
52
|
+
# the raster count $9003 and $9004 read moves on, and how many lines
|
|
53
|
+
# the long field of an interlaced frame has, or 0 without interlace.
|
|
54
|
+
#
|
|
55
|
+
# The 6561's count is the raster line. The 6560's runs ahead of it: it
|
|
56
|
+
# reads the next line from +count_column+ on, and on the last line it
|
|
57
|
+
# reads one past the last line from there, then 0 from
|
|
58
|
+
# +wrap_column+ on, so the count's first and last values each last
|
|
59
|
+
# about half a line. The 6561's +count_column+ is past the end of the
|
|
60
|
+
# line, so it never moves early.
|
|
61
|
+
#
|
|
62
|
+
# With $9000 bit 7 set at the start of a frame, the 6560 interlaces:
|
|
63
|
+
# its frames alternate between the long field, +interlaced_lines+
|
|
64
|
+
# long, and the short one, a line shorter, the long one first. On the
|
|
65
|
+
# long field's last line the count wraps to 0 where it would move on,
|
|
66
|
+
# so its first and last values each last a whole line.
|
|
67
|
+
Profile = Data.define(:clock_hz, :cycles_per_line, :lines_per_frame, :blanked_lines, :shown_lines,
|
|
68
|
+
:count_column, :wrap_column, :interlaced_lines)
|
|
51
69
|
|
|
52
70
|
# The 6561: 71 cycles by 312 lines, lines 0-27 blanked (Marko
|
|
53
71
|
# Mäkelä's VIC-I.txt).
|
|
54
|
-
PAL = Profile.new(clock_hz: 1_108_405, cycles_per_line: 71, lines_per_frame: 312, blanked_lines: 28
|
|
72
|
+
PAL = Profile.new(clock_hz: 1_108_405, cycles_per_line: 71, lines_per_frame: 312, blanked_lines: 28,
|
|
73
|
+
shown_lines: 284, count_column: 71, wrap_column: 71, interlaced_lines: 0)
|
|
74
|
+
|
|
75
|
+
# The 6560: 65 cycles by 261 lines on a 14.31818 MHz crystal divided
|
|
76
|
+
# by 14. The count's columns and the lines shown are xvic's, measured
|
|
77
|
+
# as a black box: the count moves on 28 cycles into the line, and
|
|
78
|
+
# wraps to 0 on the last line 61 cycles in. Interlaced, its fields are
|
|
79
|
+
# 263 and 262 lines.
|
|
80
|
+
NTSC = Profile.new(clock_hz: 1_022_727, cycles_per_line: 65, lines_per_frame: 261, blanked_lines: 28,
|
|
81
|
+
shown_lines: 233, count_column: 28, wrap_column: 61, interlaced_lines: 263)
|
|
55
82
|
|
|
56
83
|
PIXELS_PER_CYCLE = 4
|
|
57
84
|
|
|
@@ -71,6 +98,10 @@ module Badline
|
|
|
71
98
|
0xb27240, 0xf2b27f, 0xc2655d, 0xbdffff, 0xf299ff, 0x8de57f, 0x806eda, 0xffffa5
|
|
72
99
|
].freeze
|
|
73
100
|
|
|
101
|
+
# The display's lines: the frame's, or the long interlaced field's
|
|
102
|
+
# where that is longer.
|
|
103
|
+
attr_reader :height
|
|
104
|
+
|
|
74
105
|
attr_reader :rasterline, :column, :profile
|
|
75
106
|
attr_accessor :sound
|
|
76
107
|
|
|
@@ -78,7 +109,11 @@ module Badline
|
|
|
78
109
|
@profile = profile
|
|
79
110
|
@cycles_per_line = profile.cycles_per_line
|
|
80
111
|
@lines_per_frame = profile.lines_per_frame
|
|
81
|
-
@
|
|
112
|
+
@count_column = profile.count_column
|
|
113
|
+
@wrap_column = profile.wrap_column
|
|
114
|
+
@interlaced_lines = profile.interlaced_lines
|
|
115
|
+
@height = [@lines_per_frame, @interlaced_lines].max
|
|
116
|
+
@painter = Painter.new(@height, @cycles_per_line * PIXELS_PER_CYCLE, profile.blanked_lines)
|
|
82
117
|
@patterns = @painter.patterns
|
|
83
118
|
@colors = @painter.colors
|
|
84
119
|
@counts = @painter.counts
|
|
@@ -106,11 +141,14 @@ module Badline
|
|
|
106
141
|
@origin_x = @origin_y = @columns = @rows = 0
|
|
107
142
|
@char_shift = 3
|
|
108
143
|
@screen_base = @char_base = 0
|
|
144
|
+
@long_field = true
|
|
145
|
+
@frame_lines = @lines_per_frame
|
|
146
|
+
@frame_wrap = @wrap_column
|
|
109
147
|
new_frame
|
|
110
148
|
@fetch_from = @fetch_to = 0
|
|
111
149
|
@fetched = @slot = 0
|
|
112
150
|
@code = 0
|
|
113
|
-
@painter.power_on!(@
|
|
151
|
+
@painter.power_on!(@frame_lines - 1)
|
|
114
152
|
schedule
|
|
115
153
|
end
|
|
116
154
|
|
|
@@ -131,14 +169,12 @@ module Badline
|
|
|
131
169
|
# The sixteen registers as written.
|
|
132
170
|
def register_file = @registers.dup
|
|
133
171
|
|
|
134
|
-
# The display, a palette index a pixel,
|
|
135
|
-
# of the frame.
|
|
172
|
+
# The display, a palette index a pixel, 4 to a cycle of the line, and
|
|
173
|
+
# every line of the frame.
|
|
136
174
|
def display = @painter.display
|
|
137
175
|
|
|
138
176
|
def width = @painter.width
|
|
139
177
|
|
|
140
|
-
def height = @lines_per_frame
|
|
141
|
-
|
|
142
178
|
# Whether each line of the display has changed since the front end
|
|
143
179
|
# last cleared them.
|
|
144
180
|
def dirty_lines = @painter.dirty_lines
|
|
@@ -157,8 +193,8 @@ module Badline
|
|
|
157
193
|
def peek(addr)
|
|
158
194
|
register = addr & 0x0f
|
|
159
195
|
case register
|
|
160
|
-
when 0x03 then ((
|
|
161
|
-
when 0x04 then
|
|
196
|
+
when 0x03 then ((raster_count & 0x01) << 7) | (@registers[3] & 0x7f)
|
|
197
|
+
when 0x04 then raster_count >> 1
|
|
162
198
|
when 0x06, 0x07 then 0
|
|
163
199
|
when 0x08, 0x09 then 0xff
|
|
164
200
|
else @registers[register]
|
|
@@ -181,6 +217,16 @@ module Badline
|
|
|
181
217
|
end
|
|
182
218
|
end
|
|
183
219
|
|
|
220
|
+
# The raster count $9003 and $9004 read (see Profile).
|
|
221
|
+
def raster_count
|
|
222
|
+
line = @rasterline
|
|
223
|
+
column = @column
|
|
224
|
+
return line if column < @count_column
|
|
225
|
+
return 0 if line == @frame_lines - 1 && column >= @frame_wrap
|
|
226
|
+
|
|
227
|
+
line + 1
|
|
228
|
+
end
|
|
229
|
+
|
|
184
230
|
private
|
|
185
231
|
|
|
186
232
|
def event(column)
|
|
@@ -205,9 +251,10 @@ module Badline
|
|
|
205
251
|
|
|
206
252
|
def start_line
|
|
207
253
|
line = @rasterline + 1
|
|
208
|
-
if line == @
|
|
254
|
+
if line == @frame_lines
|
|
209
255
|
line = 0
|
|
210
256
|
new_frame
|
|
257
|
+
next_field
|
|
211
258
|
end
|
|
212
259
|
@rasterline = line
|
|
213
260
|
next_text_line if @window_open
|
|
@@ -215,6 +262,22 @@ module Badline
|
|
|
215
262
|
place_fetches
|
|
216
263
|
end
|
|
217
264
|
|
|
265
|
+
# How many lines the frame starting has, and where on its last line
|
|
266
|
+
# the count wraps: the field's, if $9000 bit 7 asks the 6560 to
|
|
267
|
+
# interlace, else the profile's.
|
|
268
|
+
def next_field
|
|
269
|
+
if @interlaced_lines.positive? && @registers[0] >= 0x80
|
|
270
|
+
long = @long_field
|
|
271
|
+
@frame_lines = long ? @interlaced_lines : @interlaced_lines - 1
|
|
272
|
+
@frame_wrap = long ? @count_column : @wrap_column
|
|
273
|
+
@long_field = !long
|
|
274
|
+
else
|
|
275
|
+
@frame_lines = @lines_per_frame
|
|
276
|
+
@frame_wrap = @wrap_column
|
|
277
|
+
@long_field = true
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
218
281
|
def place_fetches
|
|
219
282
|
line = @rasterline
|
|
220
283
|
@slot = line * Painter::SLOTS
|
data/lib/badline/data_path.rb
CHANGED
|
@@ -24,10 +24,10 @@ module Badline
|
|
|
24
24
|
File.join(xdg, "badline")
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
# The quicksaves, autosaves or
|
|
28
|
-
# along with data_path if it doesn't exist yet.
|
|
27
|
+
# The quicksaves, autosaves, saves or tapes subfolder of data_path,
|
|
28
|
+
# created along with data_path if it doesn't exist yet.
|
|
29
29
|
def data_folder(name)
|
|
30
|
-
raise ArgumentError, "unknown data folder: #{name}" unless %w[quicksaves autosaves saves].include?(name)
|
|
30
|
+
raise ArgumentError, "unknown data folder: #{name}" unless %w[quicksaves autosaves saves tapes].include?(name)
|
|
31
31
|
|
|
32
32
|
path = File.join(data_path, name)
|
|
33
33
|
FileUtils.mkdir_p(path)
|
|
@@ -10,7 +10,8 @@ module Badline
|
|
|
10
10
|
# bytes and how far it has played. A tape that isn't in leaves tape.* out. A datasette that
|
|
11
11
|
# times the read line's level adds when in the countdown the line
|
|
12
12
|
# rises, and whether a recording's low half wave is on the tape. The
|
|
13
|
-
# sense and flag handlers don't fire on load
|
|
13
|
+
# sense and flag handlers don't fire on load, and the running handler
|
|
14
|
+
# does when the load starts or stops the tape.
|
|
14
15
|
module KeyedState
|
|
15
16
|
def save_fields(out)
|
|
16
17
|
out.bool("playing", @playing).bool("motor", @motor).int("countdown", @countdown)
|
|
@@ -33,6 +34,13 @@ module Badline
|
|
|
33
34
|
@write_high = input.bool("write_high", @write_high)
|
|
34
35
|
@rise_at = input.int("rise_at", @rise_at)
|
|
35
36
|
@low_recorded = input.bool("low_recorded", @low_recorded)
|
|
37
|
+
load_tape(input)
|
|
38
|
+
update_running
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def load_tape(input)
|
|
36
44
|
bytes = input.bytes("tape.bytes", "".b).bytes
|
|
37
45
|
return @tape = nil if bytes.empty?
|
|
38
46
|
|