badline 0.18.0 → 0.19.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 +40 -0
- data/CLAUDE.md +8 -0
- data/CONTRIBUTING.md +4 -0
- data/README.md +10 -7
- data/doc/library.md +5 -1
- data/doc/media.md +3 -2
- data/doc/pinned-behaviour.md +41 -1
- data/doc/snapshot-format.md +56 -24
- data/doc/snapshots.md +45 -8
- data/doc/vice.md +344 -0
- data/lib/badline/audio/renderer.rb +4 -8
- data/lib/badline/c128.rb +4 -0
- data/lib/badline/c64/bus/fittings.rb +6 -0
- data/lib/badline/c64.rb +6 -0
- data/lib/badline/cbm2/p500.rb +4 -0
- data/lib/badline/cbm2.rb +4 -0
- data/lib/badline/chips/cpu/core.rb +29 -4
- data/lib/badline/chips/cpu/interrupts.rb +9 -0
- data/lib/badline/chips/cpu/keyed_state.rb +15 -9
- data/lib/badline/chips/cpu/microcode.rb +10 -0
- data/lib/badline/chips/rriot.rb +4 -1
- data/lib/badline/chips/sid/decimator.rb +1 -1
- data/lib/badline/chips/sid/keyed_parts.rb +51 -18
- data/lib/badline/chips/sid.rb +6 -2
- data/lib/badline/chips/vic_i/keyed_parts.rb +6 -1
- data/lib/badline/chips/vic_i/light_pen.rb +89 -0
- data/lib/badline/chips/vic_i.rb +12 -7
- data/lib/badline/drives/model1541/sector_reader.rb +20 -3
- data/lib/badline/drives/model1541.rb +1 -0
- data/lib/badline/drives/model1551.rb +1 -0
- data/lib/badline/drives/model1571.rb +1 -0
- data/lib/badline/drives/model1581.rb +1 -0
- data/lib/badline/drives/model2031.rb +1 -0
- data/lib/badline/drives/model4040/mechanism.rb +6 -3
- data/lib/badline/drives/model4040.rb +17 -1
- data/lib/badline/drives/model8050/board.rb +2 -0
- data/lib/badline/drives/model8050/dos_board.rb +49 -6
- data/lib/badline/drives/model8050/fdc_bus.rb +7 -0
- data/lib/badline/drives/model8050/idle.rb +137 -24
- data/lib/badline/drives/model8050.rb +14 -0
- data/lib/badline/drives/model9060/idle.rb +30 -10
- data/lib/badline/drives/model9060.rb +2 -0
- data/lib/badline/input/joystick.rb +15 -2
- data/lib/badline/kim1/tape.rb +3 -1
- data/lib/badline/kim1.rb +4 -0
- data/lib/badline/machine.rb +3 -0
- data/lib/badline/media/true_drive.rb +10 -0
- data/lib/badline/media/vic20_media.rb +4 -2
- data/lib/badline/media.rb +5 -1
- data/lib/badline/memory.rb +2 -4
- data/lib/badline/options/table.rb +1 -1
- data/lib/badline/pet/superpet/dongle.rb +13 -2
- data/lib/badline/pet/superpet.rb +5 -0
- data/lib/badline/pet.rb +4 -0
- data/lib/badline/plus4.rb +4 -0
- data/lib/badline/roms/README +11 -1
- data/lib/badline/snapshot/container.rb +6 -4
- data/lib/badline/snapshot/field_doc.rb +8 -4
- data/lib/badline/snapshot/image.rb +15 -6
- data/lib/badline/snapshot/vice/pet.rb +1 -0
- data/lib/badline/snapshot/vice/pet_dongle.rb +72 -0
- data/lib/badline/snapshot/vice/pet_mem.rb +11 -5
- data/lib/badline/snapshot/vice/vic20.rb +70 -0
- data/lib/badline/snapshot/vice/vic20_cpu.rb +61 -0
- data/lib/badline/snapshot/vice/vic20_mem.rb +85 -0
- data/lib/badline/snapshot/vice/vic20_restore.rb +124 -0
- data/lib/badline/snapshot/vice/vic20_vici.rb +200 -0
- data/lib/badline/snapshot/vice.rb +1 -0
- data/lib/badline/snapshot.rb +4 -4
- data/lib/badline/storage/disk_image/writing.rb +2 -2
- data/lib/badline/version.rb +1 -1
- data/lib/badline/vic20/port_wiring.rb +11 -0
- data/lib/badline/vic20.rb +4 -0
- metadata +9 -1
data/doc/vice.md
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
# VICE
|
|
2
|
+
|
|
3
|
+
badline checks itself against VICE 3.10's emulators, run as black boxes:
|
|
4
|
+
their command lines, their remote monitor, their screenshots, sound
|
|
5
|
+
recordings and snapshots. VICE's source isn't read for this, and badline
|
|
6
|
+
holds none of its code, ROMs or data. The VICE-testprogs repository is a
|
|
7
|
+
separate project: its testlists, hooks and reference screenshots are what
|
|
8
|
+
`bin/testbench` runs (see [CLAUDE.md](../CLAUDE.md#oracles)). This page
|
|
9
|
+
covers what each emulator checks, how they're driven, what they get
|
|
10
|
+
wrong or leave out, the `.vsf` modules badline reads and writes, and
|
|
11
|
+
where badline knowingly does otherwise.
|
|
12
|
+
|
|
13
|
+
- [Which emulator checks what](#which-emulator-checks-what)
|
|
14
|
+
- [Driving them](#driving-them)
|
|
15
|
+
- [Quirks and bugs](#quirks-and-bugs)
|
|
16
|
+
- [Snapshot modules](#snapshot-modules)
|
|
17
|
+
- [Where badline differs](#where-badline-differs)
|
|
18
|
+
|
|
19
|
+
## Which emulator checks what
|
|
20
|
+
|
|
21
|
+
| Emulator | Machines | What it checks |
|
|
22
|
+
| --- | --- | --- |
|
|
23
|
+
| `x64sc` | C64, every `--model` | The testbench's published results, runs from an exact start, and `.vsf` both ways |
|
|
24
|
+
| `x128` | C128 | The VDC (`-exitscreenshot`), the MMU and both modes' boot screens. Not the C64-mode VIC-II or 2 MHz (below) |
|
|
25
|
+
| `xvic` | VIC-20, PAL and NTSC | The 6560's raster count and interlace, the VIC-I's sound by recording, the power-on RAM, cycle-timed writes by screenshot, `.vsf` both ways |
|
|
26
|
+
| `xplus4` | Plus/4, C16, C116 | The TED's fetches and picture by screenshot and trace probe, its sound by recording, the 1551's load time, the ACIA's registers and timing |
|
|
27
|
+
| `xpet` | Every PET and CBM model, the SuperPET | Boot banners and BYTES FREE, frame lengths, the CRTC's frame, the IEEE-488 drives' listings and error channels, `.vsf` both ways |
|
|
28
|
+
| `xcbm2` | The B series | Boot, the CRTC's frame, the burn-in disk on a true 8050, `.vsf` both ways |
|
|
29
|
+
| `xcbm5x0` | The P500 | Boot, the VIC-II's cycle stealing, `.vsf` both ways |
|
|
30
|
+
| `c1541` | Disk images | Blank `.d67` and `.d90` images, which `D67Image` and `D90Image` format alike byte for byte (their specs' fixtures), and listing and validating the images badline's true drives write |
|
|
31
|
+
| `petcat` | BASIC text | `petcat -w2 -o out.prg in.txt` turns a BASIC listing into a `.prg` |
|
|
32
|
+
|
|
33
|
+
VICE has no KIM-1. No row of VICE's testlists runs the PET's IEEE-488
|
|
34
|
+
floppies and hard disks, the SuperPET's 6809 or a 1581, so those rest
|
|
35
|
+
on badline's own drive scenarios and specs, the schematics and the ROMs.
|
|
36
|
+
|
|
37
|
+
`x128` runs older VIC-II emulation than `x64sc`: in its results for the
|
|
38
|
+
C64-mode testlist (r45942) about 180 rows that `x64sc` passes fail, among
|
|
39
|
+
them 52 `spritesplit`, 25 `irqdma` and 18 `reutiming2` rows, and it fails
|
|
40
|
+
all 33 `d030tester` and all 4 `2mhzVIC` screenshot rows in C128 mode. So
|
|
41
|
+
`testbench-c128c64` is held to badline's own C64C verdicts, and the 2 MHz
|
|
42
|
+
rows to the testprogs' references, which come from real machines.
|
|
43
|
+
|
|
44
|
+
## Driving them
|
|
45
|
+
|
|
46
|
+
- Run each by its full path, such as `/opt/homebrew/bin/x64sc`. A bare
|
|
47
|
+
`x64sc` failed with "argv[0] is NULL". Headless, `x64sc` needs
|
|
48
|
+
`-console`, or it aborts for want of GSettings schemas.
|
|
49
|
+
- **Exit codes.** `-debugcart` gives the program a debug register, and a
|
|
50
|
+
write to it ends the run with that exit code, `$00` for a pass and
|
|
51
|
+
`$FF` for a fail. It is `$D7FF` on the C64 and the C128, `$910F` on
|
|
52
|
+
the VIC-20, `$FDCF` on the 264 series, `$8BFF` on the PET and `$DAFF`
|
|
53
|
+
in segment 15 on the CBM-II. `-limitcycles N` ends a run that hasn't
|
|
54
|
+
written it, as a timeout. `bin/testbench` installs the same register
|
|
55
|
+
(`install_debug_register`) and the same cycle budgets.
|
|
56
|
+
- **Screenshots.** `-exitscreenshot` writes a PNG as the run ends
|
|
57
|
+
(`-exitscreenshotvicii` for the C128's 40 columns, with
|
|
58
|
+
`-exitscreenshot` its VDC). Sizes: 384x288 PAL and 384x242 NTSC on
|
|
59
|
+
`xplus4`; 384x217 for the PET's discrete board, 384x273 for 40 CRTC
|
|
60
|
+
columns and 704x273 for 80 on `xpet`; 704x267 for a 600 and 704x367 for
|
|
61
|
+
a 700 on `xcbm2`; 384x272 PAL and 384x247 NTSC on `xcbm5x0`. The
|
|
62
|
+
testbench hooks compare from (32,35) on the C64, the 264 and the
|
|
63
|
+
CBM-II ((32,23) on an NTSC `xcbm2`), (32,33) on the PET, and (96,48)
|
|
64
|
+
PAL and (40,22) NTSC on the VIC-20.
|
|
65
|
+
- **Typing.** `-keybuf` types into the keyboard buffer once the machine
|
|
66
|
+
is up. On `xpet` keep each line under 80 characters. The monitor's
|
|
67
|
+
`keybuf` with `\"` escapes typed nothing there.
|
|
68
|
+
- **The remote monitor.** `-remotemonitor -remotemonitoraddress
|
|
69
|
+
ip4://127.0.0.1:PORT` takes monitor commands over a socket: registers
|
|
70
|
+
(`r`, and `r PC = $xxxx` to set one), memory (`m`, `bsave`), `io`,
|
|
71
|
+
breakpoints, the stopwatch, `dump` and `undump` for snapshots, and
|
|
72
|
+
`resourceget "Name"`, with the name quoted. A breakpoint hit is
|
|
73
|
+
reported only after the next command, so poll with `r`, then `x`.
|
|
74
|
+
Numbers are hex unless marked, counts too (`ignore 1 36` skips 54
|
|
75
|
+
hits). Its `CYC` is badline's column at the instruction boundary plus
|
|
76
|
+
one. `-moncommands` with the GTK monitor waits for input at reset and
|
|
77
|
+
hangs; `-nativemonitor` with the commands on stdin runs them.
|
|
78
|
+
- **An exact start.** `x64sc`'s autostart adds a random delay, so one run
|
|
79
|
+
of a test that depends on where it starts is no reference: the
|
|
80
|
+
published results show `irq-ack-vicii` passing 15 runs in 16 for that
|
|
81
|
+
reason. To compare from the same place, park the CPU in a loop at
|
|
82
|
+
`$C000` in both emulators, break on its first fetch on a chosen raster
|
|
83
|
+
line, and resume at the program's entry through a stub of N cycles.
|
|
84
|
+
badline and `x64sc` started this way agreed cycle for cycle over 91
|
|
85
|
+
start positions.
|
|
86
|
+
- **Power-on RAM.** `xvic -default -memory all -initbreak reset
|
|
87
|
+
-moncommands cmds.txt`, with `bsave "path" 0 0000 1fff` and `quit` in
|
|
88
|
+
the file, dumps RAM before the KERNAL touches it.
|
|
89
|
+
- **Sound.** `-sounddev wav -soundarg f.wav +autostart-warp` records
|
|
90
|
+
from power-on in real time. `-sounddev dummy -soundrecdev wav` writes
|
|
91
|
+
an empty file, because autostart turns warp on. The Homebrew `xpet`
|
|
92
|
+
has no WAV driver.
|
|
93
|
+
- **Models.** Use `-model vic20ntsc` for an NTSC VIC-20: `xvic -ntsc`
|
|
94
|
+
keeps the PAL KERNAL. `x64sc` 3.10's default VIC-II is the 8565, so a
|
|
95
|
+
6569 snapshot needs `-model c64`. The 264's RAM expansions are
|
|
96
|
+
`-memoryexphack 1|2|3` (Csory 256K, Hannes 256K, Hannes 1M);
|
|
97
|
+
`-ramsize` takes only 16, 32 and 64. The B series' autostart needs a
|
|
98
|
+
device on 8 (`-busdevice8 +drive8truedrive`).
|
|
99
|
+
- **Paths.** `xpet`'s `-editor` and `-autostart` need absolute paths. A
|
|
100
|
+
relative one gives a blank or stuck screen.
|
|
101
|
+
- **True drives.** `-drive8type T -drive8truedrive` with the disk as `-8`.
|
|
102
|
+
`-attach8ro` is a flag of its own: `-attach8ro -8 <img>` mounts an
|
|
103
|
+
image write-protected.
|
|
104
|
+
|
|
105
|
+
## Quirks and bugs
|
|
106
|
+
|
|
107
|
+
What follows was observed from outside. Each is a reason a row, a
|
|
108
|
+
recording or a snapshot from that emulator isn't a reference for the
|
|
109
|
+
part named.
|
|
110
|
+
|
|
111
|
+
### x64sc
|
|
112
|
+
|
|
113
|
+
- `undump` of a snapshot with any module short of what it expects resets
|
|
114
|
+
the machine without saying so, beyond "pre 2.4.30 snapshot" in the log.
|
|
115
|
+
MAINCPU 1.4 is 103 bytes, and 3.10 reads that layout whatever the minor
|
|
116
|
+
version.
|
|
117
|
+
- `-limitcycles` below a snapshot's own clock exits before a frame.
|
|
118
|
+
- Its true 1581 caches a track and writes it back later, so a run that
|
|
119
|
+
formats and exits through the debug register leaves the `.d81`
|
|
120
|
+
unwritten. Send `I0` and wait before the exit.
|
|
121
|
+
- In the remote monitor, a condition on `RL` works, but `RL == … && CY
|
|
122
|
+
>= …` never fired.
|
|
123
|
+
|
|
124
|
+
### xvic
|
|
125
|
+
|
|
126
|
+
- Its remote monitor stopped answering a new connection after an earlier
|
|
127
|
+
client disconnected. Drive a session over one socket, from one script
|
|
128
|
+
that starts `xvic` and stops it by its PID.
|
|
129
|
+
- `xvic -ntsc` keeps the PAL KERNAL (above).
|
|
130
|
+
- Its monitor's `LIN`, and so a breakpoint's `RL`, stays modulo 261
|
|
131
|
+
under interlace, while `$9003`/`$9004` and its own snapshots follow
|
|
132
|
+
the 263- and 262-line fields: a frame after a long field shows `LIN`
|
|
133
|
+
2 more than the line, and so on.
|
|
134
|
+
- `undump` of a snapshot taken in an interlaced frame ends that frame
|
|
135
|
+
after 261 lines, its own snapshots too: the field after it starts 2
|
|
136
|
+
lines early after a long field and 1 after a short one. The fields
|
|
137
|
+
alternate as before from there.
|
|
138
|
+
- It refuses a snapshot whose file isn't in format 3.1, and resets on the
|
|
139
|
+
first instruction without `FSDRIVE`, `TAPEPORT`, `JOYPORT0`,
|
|
140
|
+
`JOYSTICK0` and `USERPORT`. Without any drive module it keeps its own
|
|
141
|
+
drives, but with `DRIVE8` and no `DRIVECPU0` and the 1541's VIAs it
|
|
142
|
+
resets too.
|
|
143
|
+
|
|
144
|
+
### xplus4
|
|
145
|
+
|
|
146
|
+
- Its default drive 8 is a 1551, on the `plus4`, `c16` and `c16ntsc`
|
|
147
|
+
models. `Plus4/tcbm/test.prg` passes only with it.
|
|
148
|
+
- It clocks a SID card only with a real sound device: with `-sounddev
|
|
149
|
+
dummy`, OSC3 reads 0.
|
|
150
|
+
- r45284 shows a bitmap fetched from empty ROM space wrongly against the
|
|
151
|
+
photo of a real machine in `Plus4/openmem`.
|
|
152
|
+
- It steps the TED's line about 3 single clock cycles after the
|
|
153
|
+
datasheet's decode, and fails `trap10`, `trap12` and `trap14` of the
|
|
154
|
+
Lorenz suite's plus4 build (below).
|
|
155
|
+
- Its C16 model loads no tape, not even one it saved itself, and never
|
|
156
|
+
asks for PLAY: LOAD goes straight to SEARCHING. Its Plus/4 model loads
|
|
157
|
+
the tapes badline saves for the 264 (#704).
|
|
158
|
+
- It writes a version 2 `.tap` with one byte per whole wave (`$36`, `$6B`,
|
|
159
|
+
`$D5`, version 1's values), where the format and badline give one per
|
|
160
|
+
half wave (`$1A`, `$35`, `$6A`). Both time the same signal.
|
|
161
|
+
|
|
162
|
+
### xpet
|
|
163
|
+
|
|
164
|
+
- **Its 6809 runs with the wrong instruction timing.** Single-stepped
|
|
165
|
+
stopwatch deltas: BSR 5, PULS D 5, SUBD # 1, LDX # 0, ABX 2, JSR [,X]
|
|
166
|
+
8, LEAS 3, CLRA 1, 25 cycles for a sequence the datasheet times at
|
|
167
|
+
about 41. `-limitcycles` never fires under `-cpu6809`, so take 6809
|
|
168
|
+
screenshots through the monitor. Its 6809 runs one cycle per PET cycle,
|
|
169
|
+
16,650 cycles between the Waterloo ROM's frame interrupts.
|
|
170
|
+
- **The SuperPET has no software CPU select and no write protect.** With
|
|
171
|
+
`-cpuprog` it boots the 6502, and no write to `$EFF4`-`$EFFF` starts
|
|
172
|
+
the 6809. Writes to the bank RAM stick after any one bit written to
|
|
173
|
+
`$EFF4`-`$EFFB`, with the switch at 6502 or at PROG. The
|
|
174
|
+
CPU switch (`CPUswitch`) is read only at reset. `$EFFD` acts as
|
|
175
|
+
`$EFFC`. Its 6702 at `$EFE0` answers 16 reads with no write with `$D6`,
|
|
176
|
+
and writes and reads in turn of 0 to 15 with `d6 c6 c6 56 56 44 44 d6
|
|
177
|
+
d6 84 84 15 15 01 01 91`, as badline's does. It saves the 6702 in
|
|
178
|
+
PETMEM's settings (below), and every other PET's settings hold one as
|
|
179
|
+
RES leaves it.
|
|
180
|
+
- **Its 2040 isn't usable.** On a 4032 or a 3032 `OPEN15,8,15` hangs and
|
|
181
|
+
`LOAD"$0",8` never finishes; on a 2001 the directory comes back empty.
|
|
182
|
+
- **It runs only the interface processor of an IEEE-488 drive** with two
|
|
183
|
+
processors: the 8050, 8250, SFD-1001, 4040, 3040, 2040 and its type
|
|
184
|
+
9000. The floppy controller and the hard disk's SASI side run at a high
|
|
185
|
+
level, in a module `FDC0`, and the 9000 loads no SASI ROM. Nothing in
|
|
186
|
+
`xpet` times the second processor, the mechanism or SASI. The monitor
|
|
187
|
+
reaches no device for the controller.
|
|
188
|
+
- On `-model 2001` its screen mirror takes the `$8BFF` write before the
|
|
189
|
+
debug cartridge sees it, so `pet-pass.prg` times out with PET-PASS on
|
|
190
|
+
the screen; `+screen2001` gives exit 0. On `-model 8296` the same row
|
|
191
|
+
times out.
|
|
192
|
+
- It patches the 2001's BASIC 1 ROM at start ("patching 2001 ROM to make
|
|
193
|
+
IEEE488 work!"), so a 2001's LOAD from a drive in `xpet` is no
|
|
194
|
+
reference for the stock ROM.
|
|
195
|
+
- It repeats a CRTC row's character lines past the eighth, where the
|
|
196
|
+
8032029 and 8032087 schematics blank them. Its results mark `crtc3`,
|
|
197
|
+
`crtc10` and `crtc13` as errors, and `crtc13`'s reference shows `xpet`'s
|
|
198
|
+
own power-on RAM. Its 8296 runs the 8032's editor, 901474-04 dated
|
|
199
|
+
0283.
|
|
200
|
+
- Its discrete board's monitor `LIN` and `CYC` run on a 20,032-cycle
|
|
201
|
+
raster, out of step with its 16,640-cycle retrace. `-pal` and `-ntsc`
|
|
202
|
+
change nothing measurable on a PET.
|
|
203
|
+
- `-autostart` refuses ("Autostart is not available on this setup") once
|
|
204
|
+
`-editor` names a ROM it doesn't know by checksum, and `-initbreak
|
|
205
|
+
ready` never breaks then. Load through the monitor instead
|
|
206
|
+
(`l "path.prg" 0`, `g 0410`), or break on a store.
|
|
207
|
+
- `undump` wants snapshot format 1.0, and with `FSDRIVE`, `TAPEPORT` or
|
|
208
|
+
`USERPORT` missing it loads, then resets on the first instruction
|
|
209
|
+
stepped. A snapshot it saved while its true 2031 searched for a file
|
|
210
|
+
never finishes the LOAD, its own included; mid-transfer ones resume.
|
|
211
|
+
Its CRTC loses a few lines on opening any snapshot.
|
|
212
|
+
- `-autostart` with `-limitcycles` sometimes times out on a 3032; a rerun
|
|
213
|
+
passes.
|
|
214
|
+
|
|
215
|
+
### xcbm2
|
|
216
|
+
|
|
217
|
+
- **It ticks the mains once a frame of its CRTC**, as vertical sync
|
|
218
|
+
ends, whatever its mains is set to: 40,064 cycles apart on a 600 at
|
|
219
|
+
50 Hz, where 50 Hz is 40,000, and its 700 has no 60 Hz. Every 610 run,
|
|
220
|
+
`-ntsc` and `-power60` included, used the 50 Hz CRTC table. Its 710
|
|
221
|
+
defaults to `-ntsc -power60`.
|
|
222
|
+
- **It has no DRAM refresh**, so the burn-in disk's 6526 timer cell
|
|
223
|
+
reads BAD on its 610, after one cycle of the test and after three.
|
|
224
|
+
- **The 610 + 2031 TALK race reproduces in it.** With a true 2031,
|
|
225
|
+
`LOAD"$",8` typed at some phases after power-on gives `?FILE NOT
|
|
226
|
+
FOUND`: the KERNAL's TALK puts DAV about 44 cycles after ATN, and the
|
|
227
|
+
2031's DOS raises NRFD while ATNA is still set. `xcbm2` fails at
|
|
228
|
+
`-keybuf-delay` 0 and 10 to 50 and lists at 5 and 100, as badline fails
|
|
229
|
+
at some phases and not others. The first `LOAD"$"` after power-on gives
|
|
230
|
+
FILE NOT FOUND in it too.
|
|
231
|
+
- **It reads the wrong top bits of TPI1's port C in mode 1.** At READY
|
|
232
|
+
on a 610, with CR `$E3` (CA low, CB high) and no interrupt, its monitor
|
|
233
|
+
reads `$C0` at `$DE02`, though its own `io de00` says CA is low and no
|
|
234
|
+
interrupt is active. The 6525 datasheet reads the pins there, CB, CA
|
|
235
|
+
and IRQ, so badline reads `$A0`: CB high, CA low and IRQ released.
|
|
236
|
+
- It saves no mains and no TPI priority stack. Its cursor blinks 32
|
|
237
|
+
fields on and 32 off, where the 6845 blinks 16 and 16. Opening any
|
|
238
|
+
snapshot costs it a couple of hundred cycles of its CRTC.
|
|
239
|
+
|
|
240
|
+
### xcbm5x0
|
|
241
|
+
|
|
242
|
+
- It runs VICE's line-based VIC-II, not `x64sc`'s, so it reads the
|
|
243
|
+
raster a cycle off now and then.
|
|
244
|
+
- It ticks the mains every 19,656 cycles, a PAL frame, on NTSC too:
|
|
245
|
+
about 52 Hz, where the NTSC 510's mains is 60.
|
|
246
|
+
- A sprite's phi2 bytes in text mode read the KERNAL from `$E040` on,
|
|
247
|
+
where the FPLA puts the video bus.
|
|
248
|
+
|
|
249
|
+
### c1541
|
|
250
|
+
|
|
251
|
+
- It refuses `d60` as an image type, but formats a zero-filled `.d90` of
|
|
252
|
+
a D9060's size.
|
|
253
|
+
|
|
254
|
+
## Snapshot modules
|
|
255
|
+
|
|
256
|
+
No VICE document lays out the `.vsf` modules, so badline's readers and
|
|
257
|
+
writers in `lib/badline/snapshot/vice/` were mapped from dumps: known
|
|
258
|
+
pokes into memory, register writes and breakpoints at known delays,
|
|
259
|
+
compared with the monitor at the same moment. Each file's doc comment
|
|
260
|
+
gives its module's layout and what maps across.
|
|
261
|
+
[snapshots.md](snapshots.md#vice) covers what each emulator opens and
|
|
262
|
+
what it leaves out.
|
|
263
|
+
|
|
264
|
+
| Emulator | Machine name, format | Modules (files) |
|
|
265
|
+
| --- | --- | --- |
|
|
266
|
+
| `x64sc` | `C64SC`, 2.0 | MAINCPU 1.4 (`main_cpu.rb`), C64MEM (`c64_mem.rb`), CIA1 and CIA2 (`cias.rb`, `cias_import.rb`), SID and SIDEXTENDED (`sid_registers.rb`, `sid_extended.rb`), VIC-II (`vicii.rb`, `vicii_import.rb`), REU1764 (`reu1764.rb`), and the empty ports it refuses a file without (`peripherals.rb`) |
|
|
267
|
+
| `xpet` | `PET`, 1.0 | MAINCPU 1.3 (`pet_cpu.rb`), PETMEM 1.3 (`pet_mem.rb`), CRTC 1.2 (`pet_crtc.rb`), PIA1 and PIA2 (`pet_pias.rb`), VIA 2.2 (`pet_via.rb`), CPU6809 1.1 (`pet_cpu.rb`) and Acia1 (`cbm2_acia.rb`) for the SuperPET, a 2031 (`pet_drive.rb`) and the two-processor drives (`pet_drive8050.rb`) |
|
|
268
|
+
| `xcbm2` | `CBM-II`, 1.0 | The PET's CPU, CBM2MEM 1.0 (`cbm2_mem.rb`), CRTC 1.2 (`cbm2_crtc.rb`), TPI1 and TPI2 (`cbm2_tpi.rb`), Acia1 1.1 (`cbm2_acia.rb`), the C64's CIA and SID, the mains (`cbm2_mains.rb`) |
|
|
269
|
+
| `xcbm5x0` | `CBM-II-5x0`, 0.0 | As `xcbm2`, with its own VIC-II 1.3 (`p500_vicii.rb`) and C500DATA, the cycles to the mains' next tick (`p500.rb`) |
|
|
270
|
+
| `xvic` | `VIC20`, 3.1 | MAINCPU 1.4 (`vic20_cpu.rb`), VIC20MEM 1.1 (`vic20_mem.rb`), VIC-I 0.4 with the colour RAM (`vic20_vici.rb`), VIA1 and VIA2 (`pet_via.rb`), and the empty ports it resets without (`vic20.rb`) |
|
|
271
|
+
| `x128`, `xplus4` | `C128` 1.0, `PLUS4` | None read or written |
|
|
272
|
+
|
|
273
|
+
Facts the layouts rest on that the files' comments state in full:
|
|
274
|
+
|
|
275
|
+
- CBM2MEM's header is the RAM board's size in 128K units, the RAM mapped
|
|
276
|
+
into segment 15 beyond the B series' own (`$40` on a P500), the model
|
|
277
|
+
line (0 a 700, 1 a 600 at 60 Hz, 2 a 600 at 50 Hz) and both segment
|
|
278
|
+
registers.
|
|
279
|
+
- A TPI module is the eight registers, then the latched interrupts and CA
|
|
280
|
+
and CB. In mode 1 `xcbm2` keeps the latches in PRC's low five bits and
|
|
281
|
+
the mask in DDRC's.
|
|
282
|
+
- PETMEM's 24 bytes of settings at the end hold the SuperPET's 6702 from
|
|
283
|
+
the fifth byte: the byte it reads, the last write that shifted it, 1
|
|
284
|
+
while the last write left D0 clear, then a little-endian word per data
|
|
285
|
+
line, bit k the XOR of stages k and k + 1 of its shift register. Mapped
|
|
286
|
+
from dumps after 56 writes to `$EFE0`, which all decode to the
|
|
287
|
+
registers badline's 6702 has after the same writes.
|
|
288
|
+
- CPU6809 1.1 is an 8-byte clock, X, Y, U, S and PC, DP, CC, A and B,
|
|
289
|
+
then 5 zero bytes.
|
|
290
|
+
- xvic's MAINCPU 1.4 is 83 bytes, x64sc's without the BA flags and the
|
|
291
|
+
two clocks after the interrupt counts. VIC20MEM 1.1 is a byte of the
|
|
292
|
+
blocks that hold RAM (bit 0 the 3K, bits 1-3 BLK1-BLK3, bit 5 BLK5),
|
|
293
|
+
both data lines' last bytes, a byte badline leaves at 0, then
|
|
294
|
+
`$0000`-`$03FF`, `$1000`-`$1FFF`, the 3K and the blocks in turn.
|
|
295
|
+
- VIC-I 0.4 holds the interlace flag and field, the frame's first clock,
|
|
296
|
+
the beam, the text window's state, its counters and the line's fetch
|
|
297
|
+
state, the light pen, the colour RAM, the registers and xvic's picture
|
|
298
|
+
(1,648 by 632 bytes on PAL, 1,536 by 532 on NTSC). xvic's monitor's
|
|
299
|
+
cycle at an instruction boundary is badline's column.
|
|
300
|
+
- The two-processor drives all save the 8050's set: DRIVE8 2.0,
|
|
301
|
+
DRIVECPU0 1.3 for the interface processor, RIOT1D0 and RIOT2D0, FDC0
|
|
302
|
+
(8 bytes) and FSDRIVE. DRIVE8's type word tells the models apart, and
|
|
303
|
+
the SFD-1001's and the 9000's DRIVE8 holds one drive. A RIOT module's
|
|
304
|
+
timer flag, bit 7, is set only while the timer's interrupt is enabled.
|
|
305
|
+
|
|
306
|
+
## Where badline differs
|
|
307
|
+
|
|
308
|
+
Where VICE and a schematic, a datasheet or a test from real hardware
|
|
309
|
+
disagree, badline follows the hardware source. These are the places a
|
|
310
|
+
program can tell:
|
|
311
|
+
|
|
312
|
+
- **The CBM-II's DRAM refresh**, a cycle in about 21, which `xcbm2`
|
|
313
|
+
lacks. It passes the burn-in's timer cell, and a program badline runs
|
|
314
|
+
on from an `xcbm2` snapshot runs about 5% slower than in `xcbm2`.
|
|
315
|
+
`refresh: false` builds a B series without it, for comparing with
|
|
316
|
+
`xcbm2`. [CBM-II DRAM refresh](pinned-behaviour.md#cbm-ii-dram-refresh).
|
|
317
|
+
- **The TED's line step and the 7501's port**: the datasheet's decode,
|
|
318
|
+
about 3 cycles ahead of `xplus4`, and the trap tests `xplus4` fails.
|
|
319
|
+
[TED beam and the 7501 port](pinned-behaviour.md#ted-beam-and-the-7501-port).
|
|
320
|
+
Where the TED's fetches, picture and sound follow `xplus4` over the
|
|
321
|
+
datasheet, such as a voice's 1023 - x period, the same doc says so
|
|
322
|
+
under the TED's entries.
|
|
323
|
+
- **The 6809's timing** follows the MC6809E datasheet and the neetandev
|
|
324
|
+
vectors, never `xpet`.
|
|
325
|
+
[6809 dead cycles](pinned-behaviour.md#6809-dead-cycles).
|
|
326
|
+
- **The SuperPET's CPU select and write protect** through the system
|
|
327
|
+
latch at `$EFF8`, after the 324037 schematic, Levak and Fachat
|
|
328
|
+
(`PET::SuperPET::Board`). A program that uses them runs otherwise on
|
|
329
|
+
`xpet`. With SW2 at PROG, badline starts the 6809 at power-on, as the
|
|
330
|
+
latch's clear bit 0 picks it; `xpet` boots the 6502.
|
|
331
|
+
- **A CRTC PET's rows taller than eight lines** blank the lines past the
|
|
332
|
+
eighth, after the schematics, where `xpet` repeats them
|
|
333
|
+
(`PET::CRTCVideo`). Don't take `xpet` as a reference for tall rows.
|
|
334
|
+
- **A 6525's port C in mode 1** reads the CB, CA and IRQ pins in its top
|
|
335
|
+
three bits, after the datasheet (`Chips::TPI`): `$A0` at a B series'
|
|
336
|
+
READY, where `xcbm2` reads `$C0`.
|
|
337
|
+
- **The P500's sprite bytes in phi2** come from the video bus the FPLA
|
|
338
|
+
describes (`Chips::VIC::Bank#peek_sprite`), not the KERNAL bytes
|
|
339
|
+
`xcbm5x0` returns.
|
|
340
|
+
- **The PET's power-on RAM** is zeros. `crtc13`'s reference shows
|
|
341
|
+
`xpet`'s own pattern, and no dump of a real PET's is known.
|
|
342
|
+
- **The VIC-I's sound**: its volume scales the output linearly, where
|
|
343
|
+
`xvic`'s doesn't, and its loudness and output stage are fitted, not
|
|
344
|
+
pinned. [VIC-I sound](pinned-behaviour.md#vic-i-sound).
|
|
@@ -143,7 +143,6 @@ module Badline
|
|
|
143
143
|
audio = modules.required("BL-AUDIO")
|
|
144
144
|
restore_player(modules, audio)
|
|
145
145
|
record
|
|
146
|
-
player.stereo.sids.each_with_index { |sid, index| sid.load_recording_fields(audio, "sid#{index + 1}.rec.") }
|
|
147
146
|
@level = audio.int("level", 0)
|
|
148
147
|
@still = audio.int("still", 0)
|
|
149
148
|
audio.int("played", 0)
|
|
@@ -176,9 +175,9 @@ module Badline
|
|
|
176
175
|
end
|
|
177
176
|
|
|
178
177
|
# The player's modules, after a BL-AUDIO module with the cycles into
|
|
179
|
-
# the subtune, each SID's model and
|
|
180
|
-
#
|
|
181
|
-
# them, so they leave no samples behind.
|
|
178
|
+
# the subtune, each SID's model and the silence count. Each SID's own
|
|
179
|
+
# module holds how far its recording has got. The SIDs have caught up
|
|
180
|
+
# as the frame drained them, so they leave no samples behind.
|
|
182
181
|
def save_checkpoint(played, clock_hz)
|
|
183
182
|
checkpoints = @checkpoints
|
|
184
183
|
return if checkpoints.nil? || !checkpoints.due?(played, clock_hz)
|
|
@@ -187,10 +186,7 @@ module Badline
|
|
|
187
186
|
sections = player.save_modules
|
|
188
187
|
audio = Snapshot::Keyed.section("BL-AUDIO") do |out|
|
|
189
188
|
out.int("played", played)
|
|
190
|
-
sids.each_with_index
|
|
191
|
-
out.text("sid#{index + 1}.model", sid.model.to_s)
|
|
192
|
-
sid.save_recording_fields(out, "sid#{index + 1}.rec.")
|
|
193
|
-
end
|
|
189
|
+
sids.each_with_index { |sid, index| out.text("sid#{index + 1}.model", sid.model.to_s) }
|
|
194
190
|
out.int("level", @level).int("still", @still)
|
|
195
191
|
end
|
|
196
192
|
checkpoints.keep(played, [audio, *sections])
|
data/lib/badline/c128.rb
CHANGED
|
@@ -74,6 +74,8 @@ module Badline
|
|
|
74
74
|
|
|
75
75
|
def family = :c128
|
|
76
76
|
|
|
77
|
+
def portless_board = nil
|
|
78
|
+
|
|
77
79
|
def address_bus = @bus
|
|
78
80
|
|
|
79
81
|
def region = @bus.region
|
|
@@ -124,6 +126,7 @@ module Badline
|
|
|
124
126
|
@holding_commodore = false
|
|
125
127
|
@bus = Bus.new(@model, sid_model: sid_model || @model.sid_model, mode:)
|
|
126
128
|
@cpu = CPU.new(@bus, debug:)
|
|
129
|
+
@cpu.power_on! if @c64_built
|
|
127
130
|
build_z80
|
|
128
131
|
@vic = @bus.vic
|
|
129
132
|
@vic.open_bus = -> { @bus.ram.peek(@cpu.program_counter) }
|
|
@@ -204,6 +207,7 @@ module Badline
|
|
|
204
207
|
@vdc.power_on!
|
|
205
208
|
@bus.power_on!
|
|
206
209
|
reset!
|
|
210
|
+
@cpu.power_on! if @c64_built
|
|
207
211
|
enter_c64_mode if @c64_built
|
|
208
212
|
end
|
|
209
213
|
|
|
@@ -15,8 +15,14 @@ module Badline
|
|
|
15
15
|
# alone at $DC00-$DFFF and the cartridge port in Ultimax mode.
|
|
16
16
|
BOARDS = %i[c64 pet64 gs max].freeze
|
|
17
17
|
|
|
18
|
+
# The boards with no serial port for a disk drive: the C64GS's case
|
|
19
|
+
# covers its board's, and the MAX Machine has none.
|
|
20
|
+
NO_SERIAL_PORT = { gs: "the C64GS", max: "the MAX Machine" }.freeze
|
|
21
|
+
|
|
18
22
|
attr_reader :board
|
|
19
23
|
|
|
24
|
+
def portless_board = NO_SERIAL_PORT[@board]
|
|
25
|
+
|
|
20
26
|
# Fits the KERNAL ROM ROMs::KERNALS names, leaves the cassette port
|
|
21
27
|
# empty unless `datasette`, and puts the chips in the board BOARDS
|
|
22
28
|
# names.
|
data/lib/badline/c64.rb
CHANGED
|
@@ -48,6 +48,10 @@ module Badline
|
|
|
48
48
|
|
|
49
49
|
def datasette = address_bus.datasette
|
|
50
50
|
|
|
51
|
+
# The board's name when it has no serial port for a disk drive, or nil.
|
|
52
|
+
# Every family answers it, nil on all but these C64 boards.
|
|
53
|
+
def portless_board = address_bus.portless_board
|
|
54
|
+
|
|
51
55
|
def install_debug_register(&) = address_bus.install_debug_register(&)
|
|
52
56
|
|
|
53
57
|
# The machine options (sid_model:, cia_model:, vic_model:, region: and
|
|
@@ -63,6 +67,7 @@ module Badline
|
|
|
63
67
|
@address_bus = Bus.new(**machine.except(*Bus::Fittings::NAMES))
|
|
64
68
|
@address_bus.fit(**machine.slice(*Bus::Fittings::NAMES))
|
|
65
69
|
@cpu = Chips::CPU.new(@address_bus, debug:)
|
|
70
|
+
@cpu.power_on!
|
|
66
71
|
@vic = @address_bus.vic
|
|
67
72
|
@vic.open_bus = -> { @address_bus.ram.peek(@cpu.program_counter) }
|
|
68
73
|
@cia1 = @address_bus.cia1
|
|
@@ -141,6 +146,7 @@ module Badline
|
|
|
141
146
|
vic.power_on!
|
|
142
147
|
address_bus.power_on!
|
|
143
148
|
reset!
|
|
149
|
+
cpu.power_on!
|
|
144
150
|
end
|
|
145
151
|
|
|
146
152
|
# The RES line reaches the CPU and its port, both CIAs, the SID, the
|
data/lib/badline/cbm2/p500.rb
CHANGED
|
@@ -55,6 +55,8 @@ module Badline
|
|
|
55
55
|
|
|
56
56
|
def family = :cbm2
|
|
57
57
|
|
|
58
|
+
def portless_board = nil
|
|
59
|
+
|
|
58
60
|
def peek(addr) = @bus.peek(addr)
|
|
59
61
|
|
|
60
62
|
def poke(addr, value) = @bus.poke(addr, value)
|
|
@@ -102,6 +104,7 @@ module Badline
|
|
|
102
104
|
keyboard_ports.connect(@tpi2)
|
|
103
105
|
map_io
|
|
104
106
|
@cpu = CPU.new(@bus, debug:)
|
|
107
|
+
@cpu.power_on!
|
|
105
108
|
@cycles = 0
|
|
106
109
|
@mains_half_period = clock_hz / (2 * @mains_hz)
|
|
107
110
|
@mains_countdown = @mains_half_period
|
|
@@ -211,6 +214,7 @@ module Badline
|
|
|
211
214
|
@color_ram.clear!
|
|
212
215
|
@vic.power_on!
|
|
213
216
|
reset!
|
|
217
|
+
@cpu.power_on!
|
|
214
218
|
end
|
|
215
219
|
|
|
216
220
|
# The cycle by which the KERNAL has tested segments 0 and 1 and BASIC
|
data/lib/badline/cbm2.rb
CHANGED
|
@@ -74,6 +74,8 @@ module Badline
|
|
|
74
74
|
|
|
75
75
|
def family = :cbm2
|
|
76
76
|
|
|
77
|
+
def portless_board = nil
|
|
78
|
+
|
|
77
79
|
# Reads and writes memory as the CPU sees it, in its execution segment.
|
|
78
80
|
def peek(addr) = @bus.peek(addr)
|
|
79
81
|
|
|
@@ -123,6 +125,7 @@ module Badline
|
|
|
123
125
|
keyboard_ports.connect(@tpi2)
|
|
124
126
|
map_io
|
|
125
127
|
@cpu = CPU.new(@bus, debug:)
|
|
128
|
+
@cpu.power_on!
|
|
126
129
|
@cycles = 0
|
|
127
130
|
@mains_half_period = CLOCK_HZ / (2 * mains_hz)
|
|
128
131
|
@mains_countdown = @mains_half_period
|
|
@@ -224,6 +227,7 @@ module Badline
|
|
|
224
227
|
def power_cycle!
|
|
225
228
|
@bus.power_on!
|
|
226
229
|
reset!
|
|
230
|
+
@cpu.power_on!
|
|
227
231
|
end
|
|
228
232
|
|
|
229
233
|
private
|
|
@@ -25,8 +25,8 @@ module Badline
|
|
|
25
25
|
include Boundary
|
|
26
26
|
include KeyedState
|
|
27
27
|
|
|
28
|
-
attr_reader :memory, :instructions, :boundary_crossed, :cycles, :pending_write
|
|
29
|
-
attr_accessor :
|
|
28
|
+
attr_reader :memory, :instructions, :boundary_crossed, :cycles, :pending_write, :program_counter
|
|
29
|
+
attr_accessor :stack_pointer, :status, :a, :x, :y, :nmi, :irq
|
|
30
30
|
|
|
31
31
|
alias pending_write? pending_write
|
|
32
32
|
|
|
@@ -56,15 +56,32 @@ module Badline
|
|
|
56
56
|
end_sequence
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
+
# Clears the registers and runs the reset sequence from its first
|
|
60
|
+
# stack read, the two reads at the program counter having run while
|
|
61
|
+
# the reset circuit held RES. The first opcode fetch comes 5 cycles
|
|
62
|
+
# after power-on, where x64sc's does.
|
|
63
|
+
def power_on!
|
|
64
|
+
@program_counter = @stack_pointer = 0
|
|
65
|
+
@a = @x = @y = 0
|
|
66
|
+
reset!
|
|
67
|
+
@index = 2
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Starts the reset sequence, RESET_PLAN, which reads the program
|
|
71
|
+
# counter from $FFFC and fetches the first opcode 7 cycles later. A,
|
|
72
|
+
# X and Y keep their values, and S ends 3 lower.
|
|
59
73
|
def reset!
|
|
60
74
|
status.interrupt = true
|
|
61
|
-
reset_registers
|
|
62
75
|
@nmi = false
|
|
63
76
|
@irq_sample = @irq_pending = false
|
|
64
77
|
@nmi_sample = @nmi_pending = false
|
|
65
78
|
@skip_poll = false
|
|
66
79
|
@pending_write = false
|
|
67
|
-
|
|
80
|
+
@interrupt = 0xfffc
|
|
81
|
+
@brk = false
|
|
82
|
+
@plan = RESET_PLAN
|
|
83
|
+
@writes = RESET_WRITES
|
|
84
|
+
@index = 0
|
|
68
85
|
end
|
|
69
86
|
|
|
70
87
|
# Drops the instruction or interrupt sequence in flight and the
|
|
@@ -83,6 +100,14 @@ module Badline
|
|
|
83
100
|
@pending_write = false
|
|
84
101
|
end
|
|
85
102
|
|
|
103
|
+
# Sets the program counter. A CPU in its reset sequence leaves it,
|
|
104
|
+
# so the next cycle fetches an opcode at +address+ and not at the
|
|
105
|
+
# reset vector's.
|
|
106
|
+
def program_counter=(address)
|
|
107
|
+
@program_counter = address
|
|
108
|
+
end_sequence if @plan.equal?(RESET_PLAN)
|
|
109
|
+
end
|
|
110
|
+
|
|
86
111
|
def p
|
|
87
112
|
status.value
|
|
88
113
|
end
|
|
@@ -82,6 +82,15 @@ module Badline
|
|
|
82
82
|
@nmi = false if @interrupt == 0xfffa
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
+
def op_reset_dummy
|
|
86
|
+
@memory.peek(@program_counter)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def op_reset_stack
|
|
90
|
+
@memory.peek(stack_address)
|
|
91
|
+
@stack_pointer = (@stack_pointer - 1) & 0xff
|
|
92
|
+
end
|
|
93
|
+
|
|
85
94
|
def op_int_vector_low
|
|
86
95
|
@address = @memory.peek(@interrupt)
|
|
87
96
|
end
|
|
@@ -4,14 +4,17 @@ module Badline
|
|
|
4
4
|
module Chips
|
|
5
5
|
class CPU
|
|
6
6
|
# Where a CPU caught inside an instruction is, as a snapshot names it:
|
|
7
|
-
# an opcode's instruction, an IRQ or NMI sequence, or
|
|
8
|
-
|
|
7
|
+
# an opcode's instruction, an IRQ or NMI sequence, jammed, or the
|
|
8
|
+
# reset sequence.
|
|
9
|
+
POSITIONS = %w[boundary op interrupt jam reset].freeze
|
|
9
10
|
|
|
10
11
|
# The CPU's fields in a keyed snapshot module (Snapshot::Keyed): the
|
|
11
12
|
# registers, the interrupt lines' pipeline, the counts and, inside an
|
|
12
13
|
# instruction, where it is in hardware terms (pos.*), rather than as
|
|
13
14
|
# the microcode lays it out.
|
|
14
15
|
module KeyedState
|
|
16
|
+
SEQUENCE_NAMES = { INTERRUPT => "interrupt", RESET => "reset" }.freeze
|
|
17
|
+
|
|
15
18
|
def save_fields(out)
|
|
16
19
|
out.int("pc", @program_counter).int("sp", @stack_pointer).int("a", @a).int("x", @x).int("y", @y)
|
|
17
20
|
out.int("p", @status.value).bool("nmi", @nmi).bool("so_high", @so_high)
|
|
@@ -75,8 +78,8 @@ module Badline
|
|
|
75
78
|
return
|
|
76
79
|
end
|
|
77
80
|
|
|
78
|
-
out.text("pos.seq", source
|
|
79
|
-
out.int("pos.op", source) unless source
|
|
81
|
+
out.text("pos.seq", SEQUENCE_NAMES.fetch(source, "op"))
|
|
82
|
+
out.int("pos.op", source) unless SEQUENCE_NAMES.key?(source)
|
|
80
83
|
out.int("pos.t", position_t(source)).bool("pos.crossed", @boundary_crossed)
|
|
81
84
|
out.bool("pos.branch_taken", @branch_taken == true).bool("pos.brk", @brk)
|
|
82
85
|
out.optional_int("pos.vector", @interrupt)
|
|
@@ -88,7 +91,7 @@ module Badline
|
|
|
88
91
|
# The cycles of the instruction or sequence run so far, counting the
|
|
89
92
|
# opcode fetch as 1 and leaving out stalled cycles.
|
|
90
93
|
def position_t(source)
|
|
91
|
-
return @index if source
|
|
94
|
+
return @index if SEQUENCE_NAMES.key?(source)
|
|
92
95
|
|
|
93
96
|
MICROCODE.fetch(source).t_at(@index, @boundary_crossed)
|
|
94
97
|
end
|
|
@@ -96,7 +99,8 @@ module Badline
|
|
|
96
99
|
def load_position(input)
|
|
97
100
|
case input.choice("pos.seq", POSITIONS, "boundary")
|
|
98
101
|
when "op" then load_instruction(input)
|
|
99
|
-
when "interrupt" then
|
|
102
|
+
when "interrupt" then load_sequence(input, INTERRUPT_PLAN, INTERRUPT_WRITES, 1)
|
|
103
|
+
when "reset" then load_sequence(input, RESET_PLAN, RESET_WRITES, 0)
|
|
100
104
|
when "jam" then load_jam
|
|
101
105
|
else load_boundary
|
|
102
106
|
end
|
|
@@ -112,10 +116,11 @@ module Badline
|
|
|
112
116
|
load_latches(input)
|
|
113
117
|
end
|
|
114
118
|
|
|
115
|
-
|
|
116
|
-
|
|
119
|
+
# An interrupt or reset sequence, whose plan starts at step +first+.
|
|
120
|
+
def load_sequence(input, plan, writes, first)
|
|
121
|
+
use_plan(plan, writes)
|
|
117
122
|
@boundary_crossed = input.bool("pos.crossed", false)
|
|
118
|
-
@index = input.int("pos.t",
|
|
123
|
+
@index = input.int("pos.t", first).clamp(first, plan.length - 1)
|
|
119
124
|
load_latches(input)
|
|
120
125
|
end
|
|
121
126
|
|
|
@@ -162,6 +167,7 @@ module Badline
|
|
|
162
167
|
return FETCH if @plan.equal?(FETCH_PLAN)
|
|
163
168
|
return INTERRUPT if @plan.equal?(INTERRUPT_PLAN)
|
|
164
169
|
return JAMMED if @plan.equal?(JAMMED_PLAN)
|
|
170
|
+
return RESET if @plan.equal?(RESET_PLAN)
|
|
165
171
|
|
|
166
172
|
MICROCODE.index { |micro| micro.plan.equal?(@plan) && micro.operation == @operation } ||
|
|
167
173
|
MICROCODE.index { |micro| micro.plan.equal?(@plan) }
|