badline 0.5.1 → 0.6.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 +12 -0
- data/README.md +58 -0
- data/exe/badline-ruby +2 -1
- data/lib/badline/address_bus/saved_state.rb +72 -0
- data/lib/badline/address_bus.rb +1 -0
- data/lib/badline/audio/stream.rb +6 -0
- data/lib/badline/cartridge/action_replay.rb +15 -0
- data/lib/badline/cartridge/comal80.rb +8 -0
- data/lib/badline/cartridge/dinamic.rb +8 -0
- data/lib/badline/cartridge/easy_flash.rb +20 -1
- data/lib/badline/cartridge/epyx_fastload.rb +8 -0
- data/lib/badline/cartridge/final_cartridge3.rb +12 -0
- data/lib/badline/cartridge/flash.rb +41 -0
- data/lib/badline/cartridge/fun_play.rb +8 -0
- data/lib/badline/cartridge/g_mod2.rb +12 -0
- data/lib/badline/cartridge/game_system.rb +8 -0
- data/lib/badline/cartridge/geo_ram.rb +16 -0
- data/lib/badline/cartridge/magic_desk.rb +8 -0
- data/lib/badline/cartridge/ocean.rb +8 -0
- data/lib/badline/cartridge/pagefox.rb +12 -0
- data/lib/badline/cartridge/retro_replay.rb +44 -1
- data/lib/badline/cartridge/rgcd.rb +10 -0
- data/lib/badline/cartridge/super_games.rb +10 -0
- data/lib/badline/cartridge/zaxxon.rb +16 -0
- data/lib/badline/cartridge.rb +72 -0
- data/lib/badline/cia/interrupt_register.rb +17 -0
- data/lib/badline/cia/serial.rb +44 -0
- data/lib/badline/cia/state.rb +47 -0
- data/lib/badline/cia/timer.rb +33 -0
- data/lib/badline/cia.rb +8 -0
- data/lib/badline/computer/attachments.rb +132 -0
- data/lib/badline/computer/saved_state.rb +116 -0
- data/lib/badline/computer.rb +7 -30
- data/lib/badline/cpu/microcode.rb +8 -0
- data/lib/badline/cpu/saved_state.rb +115 -0
- data/lib/badline/cpu.rb +2 -0
- data/lib/badline/datasette.rb +27 -0
- data/lib/badline/drive1541/bus.rb +13 -0
- data/lib/badline/drive1541/disk.rb +7 -2
- data/lib/badline/drive1541/disk_state.rb +80 -0
- data/lib/badline/drive1541/mechanism.rb +2 -0
- data/lib/badline/drive1541/mechanism_state.rb +67 -0
- data/lib/badline/drive1541/rotation.rb +10 -0
- data/lib/badline/drive1541/serial_port.rb +10 -0
- data/lib/badline/drive1541.rb +34 -0
- data/lib/badline/gui/application.rb +41 -14
- data/lib/badline/gui/gamepads.rb +7 -0
- data/lib/badline/gui/snapshots.rb +67 -0
- data/lib/badline/gui.rb +1 -0
- data/lib/badline/kernal_trap/channel.rb +27 -0
- data/lib/badline/kernal_trap/drive/channels.rb +25 -0
- data/lib/badline/kernal_trap/drive/memory.rb +9 -0
- data/lib/badline/kernal_trap/drive/status.rb +8 -0
- data/lib/badline/kernal_trap/drive/write_file.rb +21 -0
- data/lib/badline/kernal_trap/drive.rb +19 -0
- data/lib/badline/kernal_trap/save.rb +8 -0
- data/lib/badline/kernal_trap/serial.rb +16 -0
- data/lib/badline/memory.rb +8 -0
- data/lib/badline/options.rb +3 -2
- data/lib/badline/ram_expansion/plus256k.rb +16 -0
- data/lib/badline/ram_expansion/plus60k.rb +12 -0
- data/lib/badline/ram_expansion/unexpanded.rb +6 -0
- data/lib/badline/reu/dma.rb +36 -0
- data/lib/badline/reu/ram.rb +15 -0
- data/lib/badline/reu/saved_state.rb +52 -0
- data/lib/badline/reu.rb +4 -0
- data/lib/badline/sdl/events.rb +2 -0
- data/lib/badline/sid/envelope/state.rb +68 -0
- data/lib/badline/sid/envelope.rb +7 -0
- data/lib/badline/sid/filter.rb +38 -0
- data/lib/badline/sid/voice.rb +10 -0
- data/lib/badline/sid/waveform/state.rb +66 -0
- data/lib/badline/sid/waveform.rb +2 -0
- data/lib/badline/sid.rb +34 -0
- data/lib/badline/snapshot/container.rb +117 -0
- data/lib/badline/snapshot/fields.rb +54 -0
- data/lib/badline/snapshot/image.rb +70 -0
- data/lib/badline/snapshot/machine_state.rb +77 -0
- data/lib/badline/snapshot/setup.rb +58 -0
- data/lib/badline/snapshot/state.rb +178 -0
- data/lib/badline/snapshot/vice/c64_mem.rb +53 -0
- data/lib/badline/snapshot/vice/cias.rb +89 -0
- data/lib/badline/snapshot/vice/cias_import.rb +70 -0
- data/lib/badline/snapshot/vice/main_cpu.rb +76 -0
- data/lib/badline/snapshot/vice/peripherals.rb +47 -0
- data/lib/badline/snapshot/vice/restore.rb +125 -0
- data/lib/badline/snapshot/vice/sid_extended.rb +96 -0
- data/lib/badline/snapshot/vice/sid_registers.rb +46 -0
- data/lib/badline/snapshot/vice/vicii.rb +119 -0
- data/lib/badline/snapshot/vice/vicii_import.rb +131 -0
- data/lib/badline/snapshot/vice.rb +74 -0
- data/lib/badline/snapshot.rb +52 -0
- data/lib/badline/storage/crt_file.rb +9 -3
- data/lib/badline/storage/d64_image.rb +2 -0
- data/lib/badline/storage/d71_image.rb +2 -0
- data/lib/badline/storage/d81_image.rb +2 -0
- data/lib/badline/storage/disk_image.rb +11 -2
- data/lib/badline/storage/host_directory.rb +5 -0
- data/lib/badline/storage/t64.rb +6 -0
- data/lib/badline/storage/tap.rb +10 -1
- data/lib/badline/storage/unavailable.rb +20 -0
- data/lib/badline/storage.rb +34 -0
- data/lib/badline/time_of_day.rb +56 -0
- data/lib/badline/version.rb +1 -1
- data/lib/badline/via/control_lines.rb +15 -0
- data/lib/badline/via/interrupt_register.rb +9 -0
- data/lib/badline/via/shift_register.rb +13 -0
- data/lib/badline/via/state.rb +42 -0
- data/lib/badline/via/timer1.rb +13 -0
- data/lib/badline/via/timer2.rb +18 -0
- data/lib/badline/via.rb +2 -0
- data/lib/badline/vic/border_mask.rb +10 -0
- data/lib/badline/vic/collisions.rb +11 -0
- data/lib/badline/vic/color_patches.rb +11 -0
- data/lib/badline/vic/display_state.rb +29 -1
- data/lib/badline/vic/graphics_shifter.rb +26 -0
- data/lib/badline/vic/register_log.rb +18 -0
- data/lib/badline/vic/registers.rb +13 -2
- data/lib/badline/vic/sequencer.rb +12 -0
- data/lib/badline/vic/sequencer_state.rb +89 -0
- data/lib/badline/vic/sprite/internal_bus.rb +11 -0
- data/lib/badline/vic/sprite/saved_state.rb +64 -0
- data/lib/badline/vic/sprite.rb +2 -0
- data/lib/badline/vic/sprites.rb +3 -0
- data/lib/badline/vic/sprites_state.rb +57 -0
- data/lib/badline/vic.rb +94 -10
- data/lib/badline.rb +1 -0
- metadata +35 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b238dd5194dd5fc7783779eced6e4b718b73890e81d78566d12c26c08a379597
|
|
4
|
+
data.tar.gz: 4a47225b0d7e2a055674ce9f4f61cd2bc1064413a2c4c8b6bf228ed99f4dde07
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c636911838f2d65ae88c6b4e940085790c54573c2cc6a9d97450b68f2319eb374f3330e75243487bd7538b56d5cb695f2fe085739ead20db06eb3f24b9169c45
|
|
7
|
+
data.tar.gz: c48b8ecfe80b51a178a757246adba3ea267901db096ccb74c28dbc6482a9ff1f71193c26b4829e98744bcd6847f5fe3f073ff01275604d8383dd36dd91f50f69
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.6.0](https://github.com/elektronaut/badline/compare/v0.5.1...v0.6.0) (2026-09-29)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* save and restore the machine in VICE .vsf snapshots ([07c0a26](https://github.com/elektronaut/badline/commit/07c0a26d7e73595d5cd4a5bfa90b633ee01195be))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* forget the drive's orbits after restoring it ([0238d81](https://github.com/elektronaut/badline/commit/0238d81ab12a0b0ff1e841661e10004ab3683cc1))
|
|
14
|
+
|
|
3
15
|
## [0.5.1](https://github.com/elektronaut/badline/compare/v0.5.0...v0.5.1) (2026-09-29)
|
|
4
16
|
|
|
5
17
|
|
data/README.md
CHANGED
|
@@ -57,6 +57,7 @@ badline game.d64 # Mount a disk image as device 8 and load it
|
|
|
57
57
|
badline game.tap # Insert a tape and load it
|
|
58
58
|
badline game.crt # Attach a cartridge
|
|
59
59
|
badline tune.sid # Play a SID tune
|
|
60
|
+
badline game.vsf # Restore a snapshot, from badline or VICE
|
|
60
61
|
badline ~/c64 # Mount a directory as device 8
|
|
61
62
|
```
|
|
62
63
|
|
|
@@ -107,6 +108,7 @@ slows the emulation down.
|
|
|
107
108
|
| `.tap` | Inserted in the datasette with PLAY pressed, then `LOAD` and `RUN`. It loads at the speed of a real tape |
|
|
108
109
|
| `.crt` | The hardware types listed under [Cartridges](#whats-emulated). Other types are rejected |
|
|
109
110
|
| `.sid` | PSID and RSID tunes, started through a small driver after boot |
|
|
111
|
+
| `.vsf` | A snapshot of a running machine, badline's own or one VICE's x64sc saved. See [Snapshots](#snapshots) |
|
|
110
112
|
| A directory | Mounted read-write as device 8. It serves the `.prg` and `.p00` files in it and the contents of any `.t64`, and `SAVE` writes a new `.prg` |
|
|
111
113
|
|
|
112
114
|
Apart from a `.g64`, which only a true drive can read, there is no 1541
|
|
@@ -139,6 +141,62 @@ and takes out a disk mounted through the traps, so `LOAD` and `SAVE`
|
|
|
139
141
|
reach the 1541 too. With the 1541 in device 8, a `.d64` goes in its
|
|
140
142
|
drive as well.
|
|
141
143
|
|
|
144
|
+
## Snapshots
|
|
145
|
+
|
|
146
|
+
In the window, `F11` saves the whole machine to a new
|
|
147
|
+
`badline-<date>-<time>.vsf` in the working directory, and `F12` goes
|
|
148
|
+
back to the snapshot last saved or opened, in a new machine built as the
|
|
149
|
+
saved one was. Both executables do this, and both open a `.vsf` given as
|
|
150
|
+
the media. A snapshot that fails to open leaves the machine running as
|
|
151
|
+
it was. From Ruby, `computer.save_snapshot(path)` saves,
|
|
152
|
+
`computer.restore_snapshot(path)` takes a machine back to a snapshot,
|
|
153
|
+
and `Badline::Snapshot.load(path)` builds a new machine as the saved one
|
|
154
|
+
was built and restores it. `computer.snapshot` and
|
|
155
|
+
`computer.restore(state)` do the same in memory, without a file. A
|
|
156
|
+
restore that fails leaves the machine as it was.
|
|
157
|
+
|
|
158
|
+
A snapshot holds the machine as it was on the cycle it was saved: the
|
|
159
|
+
chips down to the instruction step and the pixel pipeline, the RAM and
|
|
160
|
+
any +60K or +256K expansion, the cartridge with its RAM and flash, a
|
|
161
|
+
GEO-RAM, a true 1541 with its RAM, its VIAs and the disk under the head,
|
|
162
|
+
a disk or directory mounted through the traps with its open channels,
|
|
163
|
+
and the tape with its place on it. A restored machine runs on exactly
|
|
164
|
+
as the saved one would have. A directory, a tape and a true drive's
|
|
165
|
+
disk image open again from their paths when the snapshot is restored,
|
|
166
|
+
the disk with its tracks as the drive last saw them. A disk image mounted through the traps comes back
|
|
167
|
+
with its contents from the snapshot. What the host holds stays the host's: the keyboard, the
|
|
168
|
+
joysticks, the mouse and paddles, sound, and blocks given to `on_init`
|
|
169
|
+
that hadn't run yet, which a restore reports. A snapshot only restores
|
|
170
|
+
in the badline version that wrote it, into a machine with the same
|
|
171
|
+
chip models, RAM expansion and REU. `computer.snapshot` holds an REU's
|
|
172
|
+
RAM, registers and transfer too, but a machine with an REU doesn't save
|
|
173
|
+
to a file yet, as badline doesn't write VICE's REU module.
|
|
174
|
+
|
|
175
|
+
Snapshots use VICE's `.vsf` format. badline writes VICE's modules for
|
|
176
|
+
the CPU, RAM and CPU port, both CIAs, the SID and the VIC-II, plus the
|
|
177
|
+
ones x64sc needs to open the file, with nothing attached to the
|
|
178
|
+
cartridge, tape or user ports and no true drive. A `BADLINE` module,
|
|
179
|
+
which VICE skips, holds the whole machine, and badline restores its own
|
|
180
|
+
snapshots from it.
|
|
181
|
+
|
|
182
|
+
x64sc 3.10 opens badline's snapshots, taken at the end of the
|
|
183
|
+
instruction the CPU was in, as long as its VIC-II model matches
|
|
184
|
+
(`-model c64` for the default machine). It keeps its own drives and
|
|
185
|
+
leaves out the cartridge, the expansions and the tape. Snapshots x64sc
|
|
186
|
+
saves open in badline through the same modules: the CPU at its
|
|
187
|
+
instruction boundary, RAM, the CPU port, the CIAs' registers, timers and
|
|
188
|
+
clocks, the SID's registers and reSID voice state, and the VIC-II's
|
|
189
|
+
registers, beam position, counters and colour RAM. The VIC-II's pixel
|
|
190
|
+
pipeline starts empty. badline reads the modules x64sc 3.7 to 3.10
|
|
191
|
+
write, and VICE's development versions' `MAINC64CPU` and `VIC-IISC`. A module version
|
|
192
|
+
it doesn't know is left out, or fails the restore for the CPU and RAM.
|
|
193
|
+
It reports the modules it leaves out, such as the 1541 drives, the
|
|
194
|
+
cartridge, the datasette and the keyboard, and carries on without them.
|
|
195
|
+
An NTSC snapshot fails, as badline runs PAL only. Restored into a
|
|
196
|
+
running machine, a VICE snapshot fails for a machine built another way,
|
|
197
|
+
such as a C64C's snapshot in a C64, and otherwise takes the cartridge
|
|
198
|
+
out and switches the machine off and on.
|
|
199
|
+
|
|
142
200
|
## Playing and rendering SID tunes
|
|
143
201
|
|
|
144
202
|
`badline-ruby --headless` plays a `.sid` tune on the host's audio
|
data/exe/badline-ruby
CHANGED
|
@@ -55,7 +55,8 @@ begin
|
|
|
55
55
|
disk: { read_only: options.read_only? })
|
|
56
56
|
rescue Badline::Media::TrueDrive::Error, Badline::Storage::SIDFile::FormatError, Badline::Storage::T64::FormatError,
|
|
57
57
|
Badline::Storage::TAP::FormatError, Badline::Storage::CRTFile::FormatError,
|
|
58
|
-
Badline::Storage::G64Image::FormatError, Badline::Cartridge::UnsupportedTypeError
|
|
58
|
+
Badline::Storage::G64Image::FormatError, Badline::Cartridge::UnsupportedTypeError,
|
|
59
|
+
Badline::Snapshot::FormatError => e
|
|
59
60
|
warn "badline-ruby: #{options.media_path}: #{e.message}"
|
|
60
61
|
exit 1
|
|
61
62
|
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class AddressBus
|
|
5
|
+
# The bus's state for a snapshot: the CPU port, the RAM, colour RAM and
|
|
6
|
+
# a RAM expansion, the cartridge, the datasette and the chips.
|
|
7
|
+
module SavedState
|
|
8
|
+
# The RAM expansion fitted, or an Unexpanded stand-in.
|
|
9
|
+
attr_reader :ram_expansion
|
|
10
|
+
|
|
11
|
+
# Takes the cartridge out of the expansion port, as a restore does for
|
|
12
|
+
# a state without one.
|
|
13
|
+
def detach_cartridge
|
|
14
|
+
@cartridge = nil
|
|
15
|
+
update_overlays!
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# The 6510 port's direction and output registers, and the charge left
|
|
19
|
+
# on its floating bits.
|
|
20
|
+
def port_state = [@port_ddr, @port_out, @port_floating]
|
|
21
|
+
|
|
22
|
+
# Sets the port as port_state reads it, as a snapshot restores it,
|
|
23
|
+
# leaving the RAM under $00 and $01 alone.
|
|
24
|
+
def restore_port(ddr, out, floating)
|
|
25
|
+
@port_ddr = ddr
|
|
26
|
+
@port_out = out
|
|
27
|
+
@port_floating = floating
|
|
28
|
+
update_port!
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# The machine's memory and everything on the bus but the keyboard, the
|
|
32
|
+
# joysticks and the pot devices, which the host holds. A cartridge is
|
|
33
|
+
# already in the port, built from its setup (Computer#load_state).
|
|
34
|
+
def save_state(out)
|
|
35
|
+
out.marker("BUS")
|
|
36
|
+
out.int(@port_ddr).int(@port_out).int(@port_floating)
|
|
37
|
+
@ram.save_state(out)
|
|
38
|
+
@color_ram.save_state(out)
|
|
39
|
+
@ram_expansion.save_state(out)
|
|
40
|
+
@cartridge&.save_state(out)
|
|
41
|
+
@datasette.save_state(out)
|
|
42
|
+
@vic.save_state(out)
|
|
43
|
+
@cia1.save_state(out)
|
|
44
|
+
@cia2.save_state(out)
|
|
45
|
+
@sid.save_state(out)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def load_state(input)
|
|
49
|
+
input.marker("BUS")
|
|
50
|
+
ddr = input.int
|
|
51
|
+
port_out = input.int
|
|
52
|
+
floating = input.int
|
|
53
|
+
@ram.load_state(input)
|
|
54
|
+
@color_ram.load_state(input)
|
|
55
|
+
@ram_expansion.load_state(input)
|
|
56
|
+
@cartridge&.load_state(input)
|
|
57
|
+
@datasette.load_state(input)
|
|
58
|
+
@port_ddr = ddr
|
|
59
|
+
@port_out = port_out
|
|
60
|
+
@port_floating = floating
|
|
61
|
+
@io_port.value = port_value
|
|
62
|
+
update_overlays!
|
|
63
|
+
@vic.load_state(input)
|
|
64
|
+
@cia1.load_state(input)
|
|
65
|
+
@cia2.load_state(input)
|
|
66
|
+
@sid.load_state(input)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
include SavedState
|
|
71
|
+
end
|
|
72
|
+
end
|
data/lib/badline/address_bus.rb
CHANGED
data/lib/badline/audio/stream.rb
CHANGED
|
@@ -64,6 +64,21 @@ module Badline
|
|
|
64
64
|
|
|
65
65
|
private
|
|
66
66
|
|
|
67
|
+
def save_mapper(out)
|
|
68
|
+
save_windows(out, windows)
|
|
69
|
+
out.int(window_index(@rom, windows)).boolean(@active).boolean(@io2_ram).blob(@ram_data)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def load_mapper(input)
|
|
73
|
+
load_windows(input, windows)
|
|
74
|
+
@rom = window_at(input.int, windows)
|
|
75
|
+
@active = input.boolean?
|
|
76
|
+
@io2_ram = input.boolean?
|
|
77
|
+
input.blob_into(@ram_data)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def windows = [@through, @isolated, @contended, *@rom_banks, EMPTY_BANK]
|
|
81
|
+
|
|
67
82
|
def io2_peek(addr)
|
|
68
83
|
@io2_ram ? @ram_data[IO2_PAGE | (addr & 0xff)] : @rom.peek(addr)
|
|
69
84
|
end
|
|
@@ -33,6 +33,14 @@ module Badline
|
|
|
33
33
|
|
|
34
34
|
private
|
|
35
35
|
|
|
36
|
+
def save_mapper(out)
|
|
37
|
+
save_windows(out, [*@roml_banks, *@romh_banks, EMPTY_BANK])
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def load_mapper(input)
|
|
41
|
+
load_windows(input, [*@roml_banks, *@romh_banks, EMPTY_BANK])
|
|
42
|
+
end
|
|
43
|
+
|
|
36
44
|
def select(number, mode)
|
|
37
45
|
@roml = bank(@roml_banks, number)
|
|
38
46
|
@romh = bank(@romh_banks, number)
|
|
@@ -24,6 +24,14 @@ module Badline
|
|
|
24
24
|
|
|
25
25
|
private
|
|
26
26
|
|
|
27
|
+
def save_mapper(out)
|
|
28
|
+
save_windows(out, [*@banks, EMPTY_BANK])
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def load_mapper(input)
|
|
32
|
+
load_windows(input, [*@banks, EMPTY_BANK])
|
|
33
|
+
end
|
|
34
|
+
|
|
27
35
|
def install_chips(chips)
|
|
28
36
|
@banks = banks_from(chips).first
|
|
29
37
|
self.mode = :rom8k
|
|
@@ -78,9 +78,28 @@ module Badline
|
|
|
78
78
|
private
|
|
79
79
|
|
|
80
80
|
def select_bank
|
|
81
|
+
map_bank
|
|
82
|
+
changed!
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def map_bank
|
|
81
86
|
@roml = @low_flash.window(@bank * BANK_SIZE)
|
|
82
87
|
@romh = @high_flash.window(@bank * BANK_SIZE)
|
|
83
|
-
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def save_mapper(out)
|
|
91
|
+
out.int(@bank).int(@control).blob(@io_ram)
|
|
92
|
+
@low_flash.save_state(out)
|
|
93
|
+
@high_flash.save_state(out)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def load_mapper(input)
|
|
97
|
+
@bank = input.int
|
|
98
|
+
@control = input.int
|
|
99
|
+
input.blob_into(@io_ram)
|
|
100
|
+
@low_flash.load_state(input)
|
|
101
|
+
@high_flash.load_state(input)
|
|
102
|
+
map_bank
|
|
84
103
|
end
|
|
85
104
|
|
|
86
105
|
def apply_control
|
|
@@ -62,6 +62,18 @@ module Badline
|
|
|
62
62
|
|
|
63
63
|
private
|
|
64
64
|
|
|
65
|
+
def save_mapper(out)
|
|
66
|
+
save_windows(out, [*@roml_banks, *@romh_banks, EMPTY_BANK])
|
|
67
|
+
out.boolean(@register_visible).boolean(@phi1_ultimax)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def load_mapper(input)
|
|
71
|
+
load_windows(input, [*@roml_banks, *@romh_banks, EMPTY_BANK])
|
|
72
|
+
@io_bank = @roml
|
|
73
|
+
@register_visible = input.boolean?
|
|
74
|
+
@phi1_ultimax = input.boolean?
|
|
75
|
+
end
|
|
76
|
+
|
|
65
77
|
def select(number)
|
|
66
78
|
@io_bank = @roml = bank(@roml_banks, number)
|
|
67
79
|
@romh = bank(@romh_banks, number)
|
|
@@ -2,6 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
module Badline
|
|
4
4
|
class Cartridge
|
|
5
|
+
# A Flash chip's state, for a snapshot.
|
|
6
|
+
module FlashState
|
|
7
|
+
STATES = %i[read program_setup autoselect programming erase_window erasing suspended chip_erase
|
|
8
|
+
program_error].freeze
|
|
9
|
+
|
|
10
|
+
# The array, the command state, a timed operation's end on the
|
|
11
|
+
# machine's clock, and the windows handed out so far, which load_state
|
|
12
|
+
# builds anew.
|
|
13
|
+
def save_state(out)
|
|
14
|
+
out.blob(@data).int(STATES.index(@state)).int(STATES.index(@base_state)).int(@cycle).int(@toggle)
|
|
15
|
+
out.optional_int(@done_at).optional_int(@programmed).optional_int(@remaining)
|
|
16
|
+
out.boolean(!@erasing_sectors.nil?)
|
|
17
|
+
out.ints(@erasing_sectors) if @erasing_sectors
|
|
18
|
+
out.ints(@windows.keys).ints(@status_windows.keys)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def load_state(input)
|
|
22
|
+
input.blob_into(@data)
|
|
23
|
+
@state = STATES.fetch(input.int).to_sym
|
|
24
|
+
@base_state = STATES.fetch(input.int).to_sym
|
|
25
|
+
@cycle = input.int
|
|
26
|
+
@toggle = input.int
|
|
27
|
+
@done_at = input.optional_int
|
|
28
|
+
@programmed = input.optional_int
|
|
29
|
+
@remaining = input.optional_int
|
|
30
|
+
@erasing_sectors = nil
|
|
31
|
+
@erasing_sectors = input.ints if input.boolean?
|
|
32
|
+
rebuild_windows(input.ints, input.ints)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
5
36
|
# An AMD 29F0x0 flash chip, driven through the JEDEC command set in the
|
|
6
37
|
# AMD datasheets. Each command opens with two unlock cycles, $AA to the
|
|
7
38
|
# first unlock address and $55 to the second, and a third write picks
|
|
@@ -66,6 +97,8 @@ module Badline
|
|
|
66
97
|
alias [] peek
|
|
67
98
|
end
|
|
68
99
|
|
|
100
|
+
include FlashState
|
|
101
|
+
|
|
69
102
|
attr_reader :data, :state
|
|
70
103
|
attr_writer :clock
|
|
71
104
|
|
|
@@ -95,6 +128,14 @@ module Badline
|
|
|
95
128
|
end
|
|
96
129
|
end
|
|
97
130
|
|
|
131
|
+
# Hands out new windows at the bases given, as #window would have.
|
|
132
|
+
def rebuild_windows(bases, status_bases)
|
|
133
|
+
@windows = {}
|
|
134
|
+
@status_windows = {}
|
|
135
|
+
bases.each { |base| @windows[base] = Window.new(self, base) }
|
|
136
|
+
status_bases.each { |base| @status_windows[base] = StatusWindow.new(self, base) }
|
|
137
|
+
end
|
|
138
|
+
|
|
98
139
|
def array_mode?
|
|
99
140
|
@state == :read || @state == :program_setup
|
|
100
141
|
end
|
|
@@ -28,6 +28,14 @@ module Badline
|
|
|
28
28
|
|
|
29
29
|
private
|
|
30
30
|
|
|
31
|
+
def save_mapper(out)
|
|
32
|
+
save_windows(out, [*@banks, EMPTY_BANK])
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def load_mapper(input)
|
|
36
|
+
load_windows(input, [*@banks, EMPTY_BANK])
|
|
37
|
+
end
|
|
38
|
+
|
|
31
39
|
def install_chips(chips)
|
|
32
40
|
@banks = []
|
|
33
41
|
chips.each { |chip| @banks[self.class.bank_number(chip.bank)] = rom_bank(chip.data) }
|
|
@@ -47,6 +47,18 @@ module Badline
|
|
|
47
47
|
changed!
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
def save_mapper(out)
|
|
51
|
+
out.int(@bank).boolean(@flash_writes)
|
|
52
|
+
@flash.save_state(out)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def load_mapper(input)
|
|
56
|
+
@bank = input.int
|
|
57
|
+
@flash_writes = input.boolean?
|
|
58
|
+
@flash.load_state(input)
|
|
59
|
+
@roml = @flash.window(@bank * BANK_SIZE)
|
|
60
|
+
end
|
|
61
|
+
|
|
50
62
|
def install_chips(chips)
|
|
51
63
|
data = Array.new(BANKS * BANK_SIZE, 0xff)
|
|
52
64
|
chips.each do |chip|
|
|
@@ -25,6 +25,14 @@ module Badline
|
|
|
25
25
|
|
|
26
26
|
private
|
|
27
27
|
|
|
28
|
+
def save_mapper(out)
|
|
29
|
+
save_windows(out, [*@banks, EMPTY_BANK])
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def load_mapper(input)
|
|
33
|
+
load_windows(input, [*@banks, EMPTY_BANK])
|
|
34
|
+
end
|
|
35
|
+
|
|
28
36
|
def select(addr)
|
|
29
37
|
@roml = bank(@banks, addr & 0x3f)
|
|
30
38
|
changed!
|
|
@@ -52,8 +52,24 @@ module Badline
|
|
|
52
52
|
@block = @page = @window = 0
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
# A GEO-RAM is built from its size alone.
|
|
56
|
+
def save_setup(out)
|
|
57
|
+
out.int(GEO_RAM_SETUP).int(@size)
|
|
58
|
+
end
|
|
59
|
+
|
|
55
60
|
private
|
|
56
61
|
|
|
62
|
+
def save_mapper(out)
|
|
63
|
+
out.blob(@ram_data).int(@block).int(@page).int(@window)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def load_mapper(input)
|
|
67
|
+
input.blob_into(@ram_data)
|
|
68
|
+
@block = input.int
|
|
69
|
+
@page = input.int
|
|
70
|
+
@window = input.int
|
|
71
|
+
end
|
|
72
|
+
|
|
57
73
|
def install_chips(_chips)
|
|
58
74
|
@ram_data = Array.new(@size * 1024, 0)
|
|
59
75
|
reset
|
|
@@ -20,6 +20,14 @@ module Badline
|
|
|
20
20
|
|
|
21
21
|
private
|
|
22
22
|
|
|
23
|
+
def save_mapper(out)
|
|
24
|
+
save_windows(out, [*@banks, EMPTY_BANK])
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def load_mapper(input)
|
|
28
|
+
load_windows(input, [*@banks, EMPTY_BANK])
|
|
29
|
+
end
|
|
30
|
+
|
|
23
31
|
def install_chips(chips)
|
|
24
32
|
@banks = banks_from(chips).first
|
|
25
33
|
@bank_mask = (bank_mask(@banks) | 0x03) & 0x7f
|
|
@@ -19,6 +19,14 @@ module Badline
|
|
|
19
19
|
|
|
20
20
|
private
|
|
21
21
|
|
|
22
|
+
def save_mapper(out)
|
|
23
|
+
save_windows(out, [*@banks, EMPTY_BANK])
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def load_mapper(input)
|
|
27
|
+
load_windows(input, [*@banks, EMPTY_BANK])
|
|
28
|
+
end
|
|
29
|
+
|
|
22
30
|
# In 16K mode the selected bank shows through ROMH as well.
|
|
23
31
|
def select_bank(number)
|
|
24
32
|
@roml = bank(@banks, number)
|
|
@@ -29,6 +29,18 @@ module Badline
|
|
|
29
29
|
|
|
30
30
|
private
|
|
31
31
|
|
|
32
|
+
def save_mapper(out)
|
|
33
|
+
save_windows(out, windows)
|
|
34
|
+
@ram_banks.each { |ram| out.blob(ram.data) }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def load_mapper(input)
|
|
38
|
+
load_windows(input, windows)
|
|
39
|
+
@ram_banks.each { |ram| input.blob_into(ram.data) }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def windows = [*@roml_banks, *@romh_banks, *@ram_banks, @open_bus || EMPTY_BANK, EMPTY_BANK]
|
|
43
|
+
|
|
32
44
|
def select(value)
|
|
33
45
|
half = (value >> 1) & 0x01
|
|
34
46
|
chip = (value >> 2) & 0x03
|
|
@@ -2,6 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
module Badline
|
|
4
4
|
class Cartridge
|
|
5
|
+
# A Retro Replay's registers, RAM and flash, for a snapshot.
|
|
6
|
+
module RetroReplayState
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def save_jumpers(out)
|
|
10
|
+
out.boolean(true).boolean(@flash_jumper).boolean(@bank_jumper)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def save_mapper(out)
|
|
14
|
+
[@active, @frozen, @phi1_ultimax, @ram_enabled, @ram_at_a000, @allow_bank, @no_freeze, @reu_mapping,
|
|
15
|
+
@write_once].each { |flag| out.boolean(flag) }
|
|
16
|
+
out.int(@bank).int(RetroReplay::CONTROL_MODES.index(@config))
|
|
17
|
+
@ram_data.each { |data| out.blob(data) }
|
|
18
|
+
@flash.save_state(out)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def load_mapper(input)
|
|
22
|
+
load_flags(input)
|
|
23
|
+
@bank = input.int
|
|
24
|
+
@config = RetroReplay::CONTROL_MODES.fetch(input.int)
|
|
25
|
+
@ram_data.each { |data| input.blob_into(data) }
|
|
26
|
+
@flash.load_state(input)
|
|
27
|
+
map_windows
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def load_flags(input)
|
|
31
|
+
@active = input.boolean?
|
|
32
|
+
@frozen = input.boolean?
|
|
33
|
+
@phi1_ultimax = input.boolean?
|
|
34
|
+
@ram_enabled = input.boolean?
|
|
35
|
+
@ram_at_a000 = input.boolean?
|
|
36
|
+
@allow_bank = input.boolean?
|
|
37
|
+
@no_freeze = input.boolean?
|
|
38
|
+
@reu_mapping = input.boolean?
|
|
39
|
+
@write_once = input.boolean?
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
5
43
|
# Retro Replay: an Am29F010 flash chip of two 64K halves, each eight 8K
|
|
6
44
|
# ROM banks, and four 8K RAM banks, with the Action Replay's register at
|
|
7
45
|
# $DE00 and an extended one at $DE01. The Nordic Replay (subtype 1) adds
|
|
@@ -44,6 +82,7 @@ module Badline
|
|
|
44
82
|
# the half in bit 5.
|
|
45
83
|
class RetroReplay < Cartridge
|
|
46
84
|
include Freezer
|
|
85
|
+
include RetroReplayState
|
|
47
86
|
|
|
48
87
|
CONTROL_MODES = %i[rom8k rom16k off ultimax].freeze
|
|
49
88
|
IO1_PAGE = 0x1e00
|
|
@@ -212,11 +251,15 @@ module Badline
|
|
|
212
251
|
end
|
|
213
252
|
|
|
214
253
|
def configure
|
|
254
|
+
map_windows
|
|
255
|
+
changed!
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def map_windows
|
|
215
259
|
self.mode = @config
|
|
216
260
|
@rom = flash_window(@bank)
|
|
217
261
|
@roml = roml_window
|
|
218
262
|
@romh = romh_window
|
|
219
|
-
changed!
|
|
220
263
|
end
|
|
221
264
|
|
|
222
265
|
def roml_window
|
|
@@ -28,6 +28,16 @@ module Badline
|
|
|
28
28
|
|
|
29
29
|
private
|
|
30
30
|
|
|
31
|
+
def save_mapper(out)
|
|
32
|
+
save_windows(out, [*@banks, EMPTY_BANK])
|
|
33
|
+
out.boolean(@disabled)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def load_mapper(input)
|
|
37
|
+
load_windows(input, [*@banks, EMPTY_BANK])
|
|
38
|
+
@disabled = input.boolean?
|
|
39
|
+
end
|
|
40
|
+
|
|
31
41
|
def select(value)
|
|
32
42
|
value ^= 0x07 if @hucky
|
|
33
43
|
if value.anybits?(0x08)
|
|
@@ -20,6 +20,16 @@ module Badline
|
|
|
20
20
|
|
|
21
21
|
private
|
|
22
22
|
|
|
23
|
+
def save_mapper(out)
|
|
24
|
+
save_windows(out, [*@roml_banks, *@romh_banks, EMPTY_BANK])
|
|
25
|
+
out.boolean(@locked)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def load_mapper(input)
|
|
29
|
+
load_windows(input, [*@roml_banks, *@romh_banks, EMPTY_BANK])
|
|
30
|
+
@locked = input.boolean?
|
|
31
|
+
end
|
|
32
|
+
|
|
23
33
|
def select(value)
|
|
24
34
|
@roml = bank(@roml_banks, value & 0x03)
|
|
25
35
|
@romh = bank(@romh_banks, value & 0x03)
|
|
@@ -31,6 +31,14 @@ module Badline
|
|
|
31
31
|
def peek(addr)
|
|
32
32
|
@bank.peek(addr)
|
|
33
33
|
end
|
|
34
|
+
|
|
35
|
+
def save_state(out)
|
|
36
|
+
out.int([*@banks, EMPTY_BANK].index { |bank| bank.equal?(@bank) })
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def load_state(input)
|
|
40
|
+
@bank = [*@banks, EMPTY_BANK].fetch(input.int)
|
|
41
|
+
end
|
|
34
42
|
end
|
|
35
43
|
|
|
36
44
|
def reset
|
|
@@ -39,6 +47,14 @@ module Badline
|
|
|
39
47
|
|
|
40
48
|
private
|
|
41
49
|
|
|
50
|
+
def save_mapper(out)
|
|
51
|
+
@romh.save_state(out)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def load_mapper(input)
|
|
55
|
+
@romh.load_state(input)
|
|
56
|
+
end
|
|
57
|
+
|
|
42
58
|
def install_chips(chips)
|
|
43
59
|
roml, romh = banks_from(chips)
|
|
44
60
|
@romh = High.new(romh)
|