# Testing the SwiftLink opponent module in VICE > **Note on addresses.** Sections 0 to 9 record runs made before the probe-hardening pass, which > relocated six internal helpers, and before the adopt-mode and re-entrancy-guard pass, which moved > five more. Addresses quoted in those sections are the ones those routines had at the time of the > run. Sections 10 and 11 quote the addresses of the builds they were run against - the pre-guard > build in section 10, the current one in section 11. See `ADDRESS_CHANGES.md` for both mappings. What was tested: `../Modem_Wars_SwiftLink.d64`, the stock game disk with the $E000 opponent module replaced by the 6551/SwiftLink build (`swiftlink/build/swiftlinkDriverE000.bin`). Everything below was observed in VICE 3.7.1 (`x64sc`) - sections 0 to 6 on 2026-08-21, the fix in section 5 and sections 7 to 9 on 2026-08-22, against a disk rebuilt with `./build.sh` (`checkAbi.py`: 452 of 4096 bytes changed in 24 regions, `ABI CHECK PASSED`). Nothing is inferred from the source alone unless it says so. Scripts used, all in `swiftlink/`: | script | what it does | |---|---| | `viceHarness.py` | launches `x64sc` on a private Xvfb display with a private config file, drives the remote monitor, sends real key events | | `testBoot.py` | boots a disk, photographs the options menu, dumps $E000 | | `testModemSelect.py` | boots, picks COMPETE WITH MODEM OPPONENT, answers the modem prompts, records every access to $DE00-$DE03 | | `testTwoMachines.py` | two instances with their serial lines cross-connected through a TCP relay | | `testRealtime.py` | two instances at **true C64 speed**, windowed byte counting, cycle-counter check, error tracepoint, hot-key rate selection | | `testHotkeys.py` | one instance at true C64 speed: which host key is the Commodore key, C= + C, the border paint, forced-DCD traces, baud hot keys | | `testStrap.py`, `testStrapPair.py` | the `$DF00` strap: one machine with watchpoints on both cartridge pages and both mirror ranges, then two machines with the mirror tripwire armed | | `test1200AutoBaud.py` | one machine against a fake Hayes modem that answers `CONNECT 1200`, then `$E7B2` driven directly | | `testHighRates.py` | 4800 to 38400 and a deliberate rate mismatch: per-machine rate selection, clean and instrumented windows, `uartRxCount` sampling, a wedge dump and a `uartPendingCount` repair probe | | `testCost.py` | prices and classifies every pass of the NMI handler by pairing its entry with its exits, and prints the per-character-time budget | | `testWedge.py` | pairs handler entries with exits, counts re-entries, measures the duty cycle, counts the `$E00C` frame service, and profiles PC/SP | | `testStack.py` | the deep-nesting tracepoint `trace exec e685 if sp < $b4` and the stack-page tripwires; `traceonly` mode records the staircase without ever stopping the machine | | `testGuard.py` | counts entries to `commNmiHandler` against the ones the re-entrancy guard turned away | | `testAdopt.py` | one machine: control-register presets written from the monitor and read back out of the driver's choices, plus the 38400 hot key and C= + U | | `testAdoptPair.py` | the same with two machines: control (and command) register pre-set on both, before/after dumps and a measured window | | `scanIoAccess.py`, `probeBankOut.py`, `probeOpenBus.py` | static scan of every instruction in the game that can reach `$DE00-$DFFF`, VICE's I/O map, and what an empty `$DE00` reads back | | `probeInput.py`, `probeFire.py`, `probeModemPrompt.py` | small experiments used to work out how to drive the game headlessly | Logs kept: `testLogs/aciaAccessLog.txt` (800 monitor stops on $DE00-$DE03), `testLogs/twoMachineRun.txt` (the whole two-machine session), `testLogs/realtimeRun300first.txt` and `testLogs/realtimeRun2400first.txt` with their per-second `testLogs/realtime.*.samples.txt`, `testLogs/hotkeyRun.txt` and `testLogs/hotkeyKeymapSweep.txt`, `testLogs/fixRun1..3*.txt`, `testLogs/strapDf00*.txt` and `strapSelectDf00*.txt`, `testLogs/rate1200Run1..3.txt` and `autoBaud1200Run1..4.txt`, `testLogs/highRate*.txt`, the wedge-diagnosis logs `testLogs/stack.st384*.txt`, `stack.st192a.txt`, `wedge.wg384a*.txt` and `cost.c192a*.txt`, and the current build's `testLogs/portCompat*.txt` with their `stack.pc*.deep.txt` traces. Sections 1-4 all ran in warp. Sections 5 to 11 ran at true C64 speed, with the qualifications each section states; how that was finally managed is the first entry under "Problems and loose ends". Seven companion reports hold the full detail: `realtimeReport.md`, `hotkeyReport.md`, `strapReport.md`, `rate1200Report.md`, `highRateReport.md`, `wedgeDiagnosis.md` (section 10) and `portCompatReport.md` (section 11). `hardenReport.md` covers the probe-hardening pass between them. **Sections 10 and 11 supersede parts of section 9, and of `highRateReport.md` and `hardenReport.md`.** Section 9's "38400 wedges, four boots out of four" was a measurement of a build whose NMI handler could be re-entered without bound; section 10 establishes that mechanism and section 11 measures the build that fixes it, in which 38400 is selectable and did not wedge in seven boots. The older sections and reports are left exactly as they were taken - they are records of runs made against the build of the day - and carry pointer notes instead. Because the machine is shared, every run picks its own X display number, its own TCP ports and its own VICE config file (`-config /vicerc.