#!/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()
