Files
vt1200/harness/udpstream/build-lance.sh
T
arti d99a9cdb6c udpstream: hardware FILL L makes full-screen writes 70x faster (30.6 fps on the unit)
Byte stores to VRAM measure 2284 ms per 1280x1024 frame on the real unit
(0.44 fps) -- about a scanline period per byte, i.e. almost no access through
the arbiter.  vram.asm now drives the GSP's array engine instead: FILL L with
DADDR/DPTCH/DYDX/COLOR1 (B2/B3/B7/B9), PSIZE=1, PMASK=0 and PPOP=0, per the
TMS34010 User's Guide's implied-operand table, with CONTROL read-modify-written
so CD/RM/RR survive.

Measured: 32.7 ms/frame, 30.6 fps on the unit; 27.1 ms in MAME (74x over byte
stores there, 70x on hardware).  2,508,224 destination words/s = 0.40 us/word.

Consequence for video: a full uncompressed frame is wire-limited at 8 fps
(163840 B at 1.27 MB/s); a small source expanded on the device is limited by
the ~33 ms transfer, i.e. ~30 fps full screen if the expansion uses PIXBLT.

build-lance.sh assembles vram.asm and links VRAM.obj; MARK moved to 0x01A00000
because .text had come within 146 bytes of it.
2026-10-30 17:32:59 +02:00

117 lines
4.0 KiB
Bash
Executable File

#!/bin/sh
# Build the raw LANCE receive probe.
#
# harness/udpstream/build.sh
#
# .text at bit 0x018C0000, .bss at 0x01C00000 (both inside the firmware's large
# free block), entry _start, no .cinit (the runtime's autoinit pass does not
# run -- see harness/c-hello/README.md).
set -eu
ROOT=$(cd "$(dirname "$0")/../.." && pwd)
DIR=$(cd "$(dirname "$0")" && pwd)
WORK="$DIR/work"
OUT="$DIR/build"
IMG="$ROOT/tools/tms34010-sdk/1987-05 TMS34010 SDK/1987-11-06 TMS34010 Simulator-C Tools-ASM Tools.img"
DOSBOX_CONF="$ROOT/harness/sdk-scratch/dosbox-bench.conf"
TEXT=018C0000
BSS=01C00000
mkdir -p "$WORK" "$OUT"
if [ ! -x "$WORK/GSPCG.EXE" ]; then
mcopy -s -n -i "$IMG" "::/A2/*" "$WORK/"
mcopy -s -n -i "$IMG" "::/C2/*" "$WORK/"
fi
SRC=${LANCE_SRC:-$DIR/lance.c}
cp "$SRC" "$WORK/LANCE.C"
cp "$DIR/romapi.h" "$WORK/ROMAPI.H"
cp "$DIR/entry.asm" "$WORK/ENTRY.ASM"
cp "$DIR/vram.asm" "$WORK/VRAM.ASM"
{
printf '%s\n' '-a'
printf '%s\n' '-o LANCE.out'
printf '%s\n' '-m LANCE.map'
printf '%s\n' '-e _start'
printf '%s\n' 'LANCE.obj'
printf '%s\n' 'ENTRY.obj'
printf '%s\n' 'VRAM.obj'
printf '%s\n' '-l RTS.LIB'
printf '%s\n' 'MEMORY'
printf '%s\n' '{'
printf '%s\n' " prog: origin = ${TEXT}h, length = 20000h"
printf '%s\n' " ram: origin = ${BSS}h, length = 40000h"
printf '%s\n' '}'
printf '%s\n' 'SECTIONS'
printf '%s\n' '{'
printf '%s\n' ' .text: {} > prog'
printf '%s\n' ' .data: {} > prog'
printf '%s\n' ' .cinit: {} > prog'
printf '%s\n' ' .bss: {} > ram'
printf '%s\n' '}'
} > "$WORK/LANCE.CMD"
sed -i 's/$/\r/' "$WORK/LANCE.CMD"
rm -f "$WORK"/LANCE.OBJ "$WORK"/LANCE.OUT "$WORK"/LANCE.LST \
"$WORK"/LANCE.MAP "$WORK"/LANCE.ASM "$WORK"/LANCE.CPP \
"$WORK"/LANCE.IF "$WORK"/ENTRY.OBJ "$WORK"/ENTRY.LST \
"$WORK"/VRAM.OBJ "$WORK"/VRAM.LST
SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy \
timeout 240 dosbox -conf "$DOSBOX_CONF" -noprimaryconf -nolocalconf \
-c "mount c $WORK" -c "c:" \
-c "gspcpp LANCE" \
-c "gspcc LANCE" \
-c "gspcg LANCE" \
-c "gspa LANCE LANCE.obj LANCE.lst -l" \
-c "gspa ENTRY ENTRY.obj ENTRY.lst -l" \
-c "gspa VRAM VRAM.obj VRAM.lst -l" \
-c "gsplnk LANCE.cmd" \
-c "exit" -exit > "$WORK/dosbox.log" 2>&1
if [ ! -f "$WORK/LANCE.OUT" ]; then
echo "build.sh: GSPLNK produced no LANCE.OUT" >&2
sed 's/\r$//' "$WORK/LANCE.MAP" 2>/dev/null | tail -20 >&2 || true
for f in LANCE.LST ENTRY.LST VRAM.LST; do
sed 's/\r$//' "$WORK/$f" 2>/dev/null | grep -i 'error' | grep -vi 'no errors' >&2 || true
done
exit 1
fi
for f in LANCE.LST ENTRY.LST VRAM.LST; do
if sed 's/\r$//' "$WORK/$f" | grep -i 'error' | grep -qvi 'no errors'; then
echo "build.sh: $f diagnostics:" >&2
sed 's/\r$//' "$WORK/$f" | grep -in 'error' | grep -vi 'no errors' >&2
exit 1
fi
done
OUTNAME=${LANCE_OUT:-lance.coff}
cp "$WORK/LANCE.OUT" "$OUT/$OUTNAME"
sed 's/\r$//' "$WORK/LANCE.MAP" > "$OUT/lance.map"
# Guard: the marker block (MARK in the source) must sit clear of .text, or the
# payload overwrites its own code with cell() writes (an illegal-opcode crash).
python3 - "$SRC" "$OUT/lance.map" <<'PYCHK'
import re, sys
src, mp = sys.argv[1], sys.argv[2]
m = re.search(r'#define\s+MARK\s+(0x[0-9A-Fa-f]+)', open(src).read())
if m:
mark = int(m.group(1), 16)
for ln in open(mp):
f = ln.split()
if len(f) >= 4 and f[0] == '.text':
start, size = int(f[2], 16), int(f[3], 16)
end = start + size
if end > mark:
sys.stderr.write("build: ERROR .text ends at 0x%X, past MARK 0x%X\n" % (end, mark))
sys.exit(1)
print("build: .text ends 0x%X, MARK 0x%X (%d bytes clear)" % (end, mark, (mark - end) // 8))
PYCHK
sed 's/\r$//' "$WORK/LANCE.LST" > "$OUT/lance.lst"
sed 's/\r$//' "$WORK/ENTRY.LST" > "$OUT/entry.lst"
sed 's/\r$//' "$WORK/VRAM.LST" > "$OUT/vram.lst"
echo "build.sh: $OUT/$OUTNAME ($(wc -c < "$OUT/lance.coff") bytes)"
grep -E "ENTRY POINT|^\.(text|cinit|bss)" "$OUT/lance.map" | head -8