Files
vt1200/harness/udpstream/test-bcast.sh
T
arti f251672d5d udpstream: payload sends and receives raw Ethernet with its own LANCE driver
lance_bcast.c drives the chip entirely on its own -- init block, PADR/LADRF,
eight TX and eight RX descriptors, INIT/IDON/STRT, TDMD, completion polling --
and test-bcast.sh runs it in MAME and reports:

  TXD=6  RXF=5  ET=0x88B5  source MAC 0xC6FC  ok=1  PASS

The tap capture separates the directions: six 60-byte 0x88b5 broadcasts from
08:00:2b:16:4b:5a (our payload) and 49 from the host. RXF counts host frames
(early stop at five) and the recorded source MAC is the host's.

Fixes behind it: per-frame TX descriptor (the chip advances its own ring
position), cfg-net needed for a tap to exist at all, pkill -x instead of -f,
and two bit-vs-byte addressing bugs.
2026-10-30 16:21:02 +02:00

122 lines
4.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# test-bcast.sh -- run the raw-Ethernet broadcast payload in MAME and report
# what it sent and received.
#
# harness/udpstream/test-bcast.sh [payload.coff]
#
# Everything the earlier manual runs got wrong is handled here:
# * stale MAME is killed with `pkill -x` (a `pkill -f` pattern also matches
# this script's own command line and kills the test itself)
# * the network interface choice lives in harness/mame/cfg-net -- an empty
# cfg dir means MAME never opens a tap, so the LANCE sees no carrier and
# reports TMD3_LCAR
# * the host's tap only has carrier once MAME has attached it, so the script
# waits for LOWER_UP before sending anything
# * host frames are sent while the payload is inside its listen window
#
# Exit status 0 only if the payload reported transmitting and receiving.
set -uo pipefail
ROOT=$(cd "$(dirname "$0")/../.." && pwd)
M=${MAME:-/home/arti/code/k-space/mame0289/vt1200}
COFF=${1:-$ROOT/harness/udpstream/build/lance_bcast.coff}
RUN=${RUN:-/tmp/vt1200-bcast}
MARK=0x018D0000 # must match #define MARK in the payload
LOADER_AT=${LOADER_AT:-400}
LOADER_END=${LOADER_END:-2500}
DUMP_AT=${DUMP_AT:-1200} # payload now holds after its panel, so any later frame works
HOST_FRAMES=${HOST_FRAMES:-60}
[ -x "$M" ] || { echo "no MAME binary at $M (set MAME=...)" >&2; exit 1; }
[ -f "$COFF" ] || { echo "no payload at $COFF" >&2; exit 1; }
echo "== setting up =="
pkill -9 -x vt1200 2>/dev/null
sleep 2
sudo -n ip link set vt1200 up 2>/dev/null
rm -rf "$RUN"
mkdir -p "$RUN/cfg" "$RUN/nvram"
cp "$ROOT/harness/mame/cfg-net/vt1200.cfg" "$RUN/cfg/" 2>/dev/null \
|| { echo "missing harness/mame/cfg-net/vt1200.cfg (the taptun selection)" >&2; exit 1; }
TAP=$(ip -o link show 2>/dev/null | sed -n 's/^[0-9]*: \(tap-mess-[^:]*\):.*/\1/p' | head -1)
[ -n "$TAP" ] || { echo "no tap-mess-* interface -- start MAME once so it exists" >&2; exit 1; }
echo " tap: $TAP"
CAP="$RUN/frames.cap"
sudo -n timeout 70 tcpdump -i "$TAP" -e -n ether proto 0x88b5 > "$CAP" 2>&1 &
VT1200_SKIP_LEVEL1=1 \
LOADER_AT=$LOADER_AT LOADER_END=$LOADER_END \
LOADER_BIN="$ROOT/dwt/loader/build/loader.bin" \
LOADER_COFF="$COFF" LOADER_OUT="$RUN" \
VT1200_DUMP_RAM=$DUMP_AT VT1200_DUMP_DIR="$RUN" \
timeout 110 "$M" vt1200 \
-rompath "$ROOT/harness/mame/roms" -video none -sound none -skip_gameinfo \
-networkprovider taptun -nvram_directory "$RUN/nvram" -cfg_directory "$RUN/cfg" \
-debug -debugger none -autoboot_script /tmp/opencode/loader_probe_l3.lua \
-autoboot_delay 0 > "$RUN/mame.log" 2>&1 &
echo "== waiting for link =="
for i in $(seq 1 60); do
if ip -o link show "$TAP" 2>/dev/null | grep -q LOWER_UP; then
echo " carrier up after ${i}s"
break
fi
sleep 1
done
ip -o link show "$TAP" 2>/dev/null | grep -q LOWER_UP \
|| echo " WARNING: no carrier on $TAP -- the chip will report LCAR"
echo "== waiting for the payload to start (frame $LOADER_AT ~ $((LOADER_AT / 60))s) =="
sleep $((LOADER_AT / 60 + 2))
echo "== sending $HOST_FRAMES host broadcast frames =="
for i in $(seq 1 "$HOST_FRAMES"); do
sudo -n python3 "$ROOT/harness/udpstream/sendraw.py" --iface vt1200 --count 1 --gap 0 >/dev/null 2>&1
sleep 0.25
done
echo "== waiting for the payload to finish =="
sleep 8
pkill -9 -x vt1200 2>/dev/null
echo "== results =="
DUMP=$(ls -1 "$RUN"/vt1200-ram-*.bin 2>/dev/null | head -1)
if [ -n "$DUMP" ]; then
python3 - "$DUMP" "$MARK" <<'PY'
import struct, sys
d = open(sys.argv[1], 'rb').read()
base = int(sys.argv[2], 16) >> 3
def cell(bitoff): # cell() offsets are BIT offsets in the payload
o = base + (bitoff >> 3)
return struct.unpack("<I", d[o: o + 4])[0]
txd, rxf, ok, et, m0 = cell(0x160), cell(0x180), cell(0x1A0), cell(0x200), cell(0x220)
print(" TXD (frames transmitted) = %d" % txd)
print(" RXF (frames received) = %d" % rxf)
print(" last ethertype = 0x%04X" % et)
print(" last source MAC hi word = 0x%04X" % m0)
print(" ok = %d" % ok)
unwritten = (txd == 0x55555555 or rxf == 0x55555555)
if unwritten:
print(" markers not written (dump landed outside the run)")
sys.exit(0 if (not unwritten and txd > 0 and rxf > 0) else 1)
PY
RC=$?
else
echo " no RAM dump in $RUN"
RC=1
fi
CAPN=$(grep -c 88b5 "$CAP" 2>/dev/null)
[ -n "$CAPN" ] || CAPN=0
echo " payload broadcasts seen on $TAP: $CAPN"
[ "$CAPN" -gt 0 ] || RC=1
echo
if [ "$RC" = 0 ]; then echo "== PASS =="; else echo "== FAIL =="; fi
echo " log: $RUN/mame.log"
echo " pcap: $CAP"
exit $RC