#!/usr/bin/env python3
# probeBankOut.py - two facts about a $DF00-strapped cartridge that the rest of the strap testing
# rests on, asked of the emulator directly rather than argued from first principles.
#
#   python3 probeBankOut.py
#
# 1. What VICE maps, and where.  The monitor's "io" command lists the I/O devices and the address
#    range each one claims, which is what says whether a stop on $DF04-$DFFF would be a register
#    access in the emulator or just an address nobody answers.
# 2. Whether an access to $DFxx reaches the cartridge when the I/O area is banked out.  The game's
#    film buffer is the RAM under $D000-$DFFF; copyPageUnderIo $58B2 walks a page pointer up to
#    $DF00 and readFilmByte / writeFilmByte dereference filmPtr anywhere in it, all with $01 = $34.
#    If those reached the 6551 they would consume received characters and clear interrupt flags, so
#    the whole film system would be a hazard on the $DF00 strap.  The test writes through the I/O
#    window, then writes a different value to the same address with the I/O area banked out, then
#    banks I/O back in and reads the register again: if the register still holds the first value, the
#    second write went to RAM and never reached the chip.
import os
import sys

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from viceHarness import ViceSession, aciaArgs, readByte, SCRATCH


def main():
    session = ViceSession("", f"{SCRATCH}/probeBankOut.log", aciaArgs(base="0xDF00"), label="bankout")
    try:
        session.connect()
        session.enterMonitor()
        print("--- what VICE has mapped in the I/O area ---", flush=True)
        print(session.mon("io"), flush=True)
        session.mon("bank cpu")
        session.mon("sidefx on")
        print("--- unmapped $DE00-$DE07 (nothing is strapped there in this run) ---", flush=True)
        print(session.mon("m de00 de07"), flush=True)
        print("--- the page above the four registers, $DF40-$DF47 and $DFFC-$DFFF ---", flush=True)
        print(session.mon("m df40 df47"), flush=True)
        print(session.mon("m dffc dfff"), flush=True)

        session.mon("> df03 1e")
        first = readByte(session, 0xDF03)
        session.mon("> 0001 34")                     # bank the RAM under $D000-$DFFF into view
        session.mon("> df03 55")                     # must land in RAM, not in the ACIA
        underneath = readByte(session, 0xDF03)
        session.mon("> 0001 37")                     # I/O back
        after = readByte(session, 0xDF03)
        print(f"control register written through the I/O window: ${first:02X}", flush=True)
        print(f"same address written again with $01 = $34, read back banked out: "
              f"${underneath:02X}", flush=True)
        print(f"control register with the I/O area banked in again: ${after:02X}", flush=True)
        print("the banked-out write reached the cartridge: "
              f"{'YES - hazard' if after != first else 'no, it went to RAM'}", flush=True)
    finally:
        session.close()


main()
