modemwars/swiftlink/probeOpenBus.py
2026-08-23 02:09:40 -05:00

52 lines
2.2 KiB
Python

#!/usr/bin/env python3
# probeOpenBus.py - what does a read of $DE03 return when there is no cartridge at $DE00?
#
# python3 probeOpenBus.py <disk.d64> [samples]
#
# aciaDetect writes $1E to the control register of whatever is at $DE00 and reads it back; a match
# means "the cartridge is here" and a mismatch takes the $DF00 fallback. With nothing mapped at
# $DE00 the read is open bus - on a C64 the last byte the VIC put on the data bus, and in VICE the
# same thing - so the fallback is only taken because that floating byte happens not to be $1E. This
# samples it at many different raster positions to see how close to $1E it ever gets.
#
# The emulator is stopped and restarted between samples so each read lands at a different point in
# the frame. Reads are taken with sidefx off, which is how the harness reads memory everywhere else.
import os
import re
import sys
import time
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from viceHarness import ViceSession, aciaArgs, readByte, ACIA_BASE, SCRATCH
def main():
disk = os.path.abspath(sys.argv[1])
samples = int(sys.argv[2]) if len(sys.argv) > 2 else 120
session = ViceSession(disk, f"{SCRATCH}/openbus.vice.log", aciaArgs(base="0xDF00"),
label="openbus")
seen = {}
try:
session.connect()
session.bootPastLoader()
time.sleep(5)
for index in range(samples):
session.enterMonitor()
value = readByte(session, 0xDE03)
session.sock.sendall(b"x\n")
session.recv(1)
if value is not None:
seen[value] = seen.get(value, 0) + 1
time.sleep(0.12)
total = sum(seen.values())
print(f"=== {total} reads of $DE03 with no cartridge mapped there ===", flush=True)
for value, count in sorted(seen.items(), key=lambda kv: -kv[1]):
print(f" ${value:02X} {count} times ({100.0 * count / total:.1f}%)", flush=True)
hit = seen.get(0x1E, 0)
print(f"reads that would have made the probe believe an ACIA is at $DE00 (${0x1E:02X}): "
f"{hit} of {total}", flush=True)
finally:
session.close()
main()