#!/usr/bin/env bash # verify-iigs-serial.sh - Cross-channel SCC gate for the Apple IIgs port. # # The 8530 carries both built-in ports on one chip: channel A is the printer # port (AppleTalk's), channel B is the modem port. WR9's reset command is # chip-wide, so an open that issues the force-hardware-reset (0xC0) wipes the # other channel too. This gate proves it does not. # # SCCPROBE (examples/sccprobe/sccprobe.c) brings channel A up through the real # HAL and sends "A1", hands it back, opens channel B -- the operation under # test -- and then pokes "A2" straight into channel A's data register. Both # strings reach the host only if channel A's transmitter is still enabled after # the modem-port open, so: # # A1 present, A2 present -> PASS (channel A survived) # A1 present, A2 missing -> FAIL (the open wiped the other channel) # A1 missing -> the probe never ran / printer path is broken # # MAME CONNECTS OUT to the bitbanger socket, so the peer here listens first. # Needs the PATCHED apple2gs (patches/mame-0.264-apple2gs-scc-clock.patch): # stock 0.264 feeds the SCC BRG the wrong clock and pins RX at 230400, so no # baud ever matches the null_modem. # # scripts/verify-iigs-serial.sh set -uo pipefail repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) MAME="$repo/toolchains/cache/mame-mame0264/apple2gs" sys_disk=$repo/toolchains/emulators/support/gsos-system.po rompath="${MAME_ROMPATH:-$HOME/.mame/roms}" PORT="${IIGS_SCC_PORT:-45231}" readFrame="${MAME_READ_FRAME:-9000}" WALL="${IIGS_SCC_WALL:-420}" [ -x "$MAME" ] || { echo "verify-iigs-serial: missing patched MAME at $MAME" >&2; exit 2; } [ -f "$sys_disk" ] || { echo "verify-iigs-serial: missing $sys_disk" >&2; exit 2; } [ -f "$repo/build/iigs/bin/SCCPROBE" ] || { echo "verify-iigs-serial: build SCCPROBE first" >&2; exit 2; } work=$(mktemp -d -t joeylib-iigs-scc.XXXXXX) peer_pid="" cleanup() { [ -n "$peer_pid" ] && kill -9 "$peer_pid" 2>/dev/null rm -rf "$work" } trap cleanup EXIT # A disk holding just the probe, so this never disturbs the normal joey.2mg. JOEY_DISK_EXAMPLES="SCCPROBE" bash "$repo/scripts/make-iigs-disk.sh" "$work/scc.2mg" >/dev/null 2>&1 || { echo "verify-iigs-serial: FAIL - could not build the probe disk" >&2 exit 1 } cp "$sys_disk" "$work/boot.po" # Serial peer: listen, then log every byte the IIgs sends. cat > "$work/peer.py" <<'PY' import socket, sys, time port = int(sys.argv[1]) out = sys.argv[2] srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) srv.bind(("127.0.0.1", port)) srv.listen(1) srv.settimeout(300) try: conn, _ = srv.accept() except socket.timeout: open(out, "wb").write(b"") sys.exit(0) conn.settimeout(1.0) buf = b"" deadline = time.time() + 280 while time.time() < deadline: try: chunk = conn.recv(256) except socket.timeout: continue except OSError: break if not chunk: break buf += chunk with open(out, "wb") as f: f.write(buf) with open(out, "wb") as f: f.write(buf) PY python3 "$work/peer.py" "$PORT" "$work/rx.bin" & peer_pid=$! sleep 1 # Finder keystroke timeline, same calibration as verify-iigs.sh: select the # JOEYLIB volume, Cmd-O to open it, type the program name, Cmd-O to launch. cat > "$work/scc.lua" <= steps[idx][1] do steps[idx][2]() idx = idx + 1 end end) LUA cd "$work" out=$(QT_QPA_PLATFORM=offscreen SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy \ timeout -s KILL "$WALL" "$MAME" apple2gs \ -rompath "$rompath" \ -flop3 "$work/boot.po" -flop4 "$work/scc.2mg" \ -printer null_modem -bitb "socket.127.0.0.1:$PORT" \ -video none -sound none -nothrottle \ -autoboot_script "$work/scc.lua" &1) || true kill -9 "$peer_pid" 2>/dev/null peer_pid="" sleep 1 line=$(echo "$out" | grep -E '^VERIFY-IIGS-SCC ' | tail -1) rx=$(od -A n -c "$work/rx.bin" 2>/dev/null | tr -s ' ' | tr -d '\n') echo "$line" echo " printer-port bytes:$rx" if [ -z "$line" ]; then echo "verify-iigs-serial: FAIL - MAME produced no report" >&2 echo "$out" | tail -10 >&2 exit 1 fi if ! grep -q "A1" "$work/rx.bin" 2>/dev/null; then echo "verify-iigs-serial: FAIL - the printer port never sent 'A1'." >&2 echo " Either SCCPROBE did not run (check the flags above) or the" >&2 echo " channel A transmit path is broken." >&2 exit 1 fi if ! grep -q "A2" "$work/rx.bin" 2>/dev/null; then echo "verify-iigs-serial: FAIL - 'A1' arrived but 'A2' did not." >&2 echo " Opening the MODEM port killed the PRINTER channel: that is the" >&2 echo " chip-wide WR9 0xC0 force-hardware-reset. Use the per-channel" >&2 echo " reset (0x80 channel A / 0x40 channel B) in serialInitScc." >&2 exit 1 fi echo "verify-iigs-serial: PASS (printer channel still transmits after the modem port was opened)"