#!/usr/bin/env python3 """Boot the compiled CALC.COM and quit it through its own command menu. The compile ladder proves the front-end reaches the final '.'. This proves the linked image is a runnable program: it is loaded above the boot sector, prints the MicroCalc welcome/grid, accepts a numeric formula in cell A1, reaches the command menu, accepts `/Q' and exits 0. The first cell-entry path used to restart CALC (a nested procedure fell through into its enclosing body); feeding one formula here keeps that regression visible. The loader is the high-image variant of bootcom.s (LOAD_SEG=0x1000, input at 0x9800); the ordinary fixture harness uses the same default now, while rt_exec.py keeps the original low loader for its own driver image. """ import os import shutil import subprocess import sys import tempfile HERE = os.path.dirname(os.path.abspath(__file__)) SHELL = os.path.dirname(HERE) RES = os.path.join(os.path.dirname(SHELL), "Resources", "TP3") sys.path.insert(0, HERE) import run_com_exec as r # noqa: E402 def main(): td = tempfile.mkdtemp(prefix="tpcalc-") try: for name in ("CALC.PAS", "CALC.INC"): shutil.copy(os.path.join(RES, name), os.path.join(td, name)) exe = r.ensure_comtest() src = os.path.join(td, "CALC.PAS") p = subprocess.run([exe], cwd=td, input=(src + "\n").encode(), capture_output=True) coms = [os.path.join(td, n) for n in os.listdir(td) if n.upper().endswith(".COM")] if p.returncode != 0 or not coms: sys.exit("comtest did not produce CALC.COM:\n%s" % p.stdout.decode(errors="replace")) com = open(coms[0], "rb").read() if len(com) > r.COM_MAX: sys.exit("CALC.COM is %d bytes, past the loader's %d" % (len(com), r.COM_MAX)) boot = r.build_boot_sector(no_keypress=True) img = os.path.join(td, "calc.img") open(img, "wb").write(r.build_floppy(boot, com, b"\r1+2\r/Q")) out, rc, note = r.run_qemu(img) code = r.exit_code_of(rc) text = out.decode("latin-1") missing = [s for s in ("Welcome to MicroCalc", "AutoCalc: ON", "3.00", "Update, Quit") if s not in text] if code != 0 or missing: sys.exit("CALC did not start/quit cleanly: exit=%r note=%s missing=%r\n%s" % (code, note, missing, r.visible_output(out[:2000]))) print(" CALC.COM PASS com=%d bytes, exit=0, cell-entry/formula/menu" % len(com)) return 0 finally: shutil.rmtree(td, ignore_errors=True) if __name__ == "__main__": sys.exit(main())