#!/bin/sh # Build the C hello world with the 1987 TI TMS34010 SDK (K&R C compiler). # # harness/c-hello/build.sh # # Pipeline: gspcpp -> gspcc -> gspcg -> gspa -> gsplnk, all under DOSBox. # entry.asm is assembled separately: it is the process entry (sets STK/FP, # calls _main, `rets`) and replaces boot.obj, whose exit path is a `for(;;)` # spin followed by an `reti` -- both wrong for a create_process child. # # .text/.data are linked at bit 0x018A0000, .bss at 0x01A00000 (both inside the # firmware's large free block). # # Outputs: build/hello.coff (the linker output the COFF loader eats), # hello.map, hello.lst, entry.lst, hello.obj 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=018A0000 BSS=01A00000 # `build.sh emu` builds a 128-byte-stride variant for MAME's 1024x1024 canvas. MODE=${1:-real} NAME=hello if [ "$MODE" = "emu" ]; then NAME=hello-emu; fi 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 if [ "$MODE" = "emu" ]; then sed 's/#define ROW_BYTES 256/#define ROW_BYTES 128/' "$DIR/hello.c" > "$WORK/HELLO.C" else cp "$DIR/hello.c" "$WORK/HELLO.C" fi cp "$DIR/entry.asm" "$WORK/ENTRY.ASM" { printf '%s\n' '-a' printf '%s\n' '-o HELLO.out' printf '%s\n' '-m HELLO.map' printf '%s\n' '-e _start' printf '%s\n' 'HELLO.obj' printf '%s\n' 'ENTRY.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/HELLO.CMD" sed -i 's/$/\r/' "$WORK/HELLO.CMD" rm -f "$WORK"/HELLO.OBJ "$WORK"/HELLO.OUT "$WORK"/HELLO.LST \ "$WORK"/HELLO.MAP "$WORK"/HELLO.HI "$WORK"/HELLO.LO \ "$WORK"/HELLO.ASM "$WORK"/HELLO.CPP "$WORK"/HELLO.IF \ "$WORK"/ENTRY.OBJ "$WORK"/ENTRY.LST SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy \ timeout 240 dosbox -conf "$DOSBOX_CONF" -noprimaryconf -nolocalconf \ -c "mount c $WORK" -c "c:" \ -c "gspcpp HELLO" \ -c "gspcc HELLO" \ -c "gspcg HELLO" \ -c "gspa HELLO HELLO.obj HELLO.lst -l" \ -c "gspa ENTRY ENTRY.obj ENTRY.lst -l" \ -c "gsplnk HELLO.cmd" \ -c "exit" -exit > "$WORK/dosbox.log" 2>&1 if [ ! -f "$WORK/HELLO.OUT" ]; then echo "build.sh: GSPLNK produced no HELLO.OUT" >&2 sed 's/\r$//' "$WORK/HELLO.MAP" 2>/dev/null | tail -20 >&2 || true exit 1 fi if [ ! -f "$WORK/HELLO.OBJ" ] || [ ! -f "$WORK/ENTRY.OBJ" ]; then echo "build.sh: missing object file (compile/assemble failed)" >&2 for f in HELLO.LST ENTRY.LST; do sed 's/\r$//' "$WORK/$f" 2>/dev/null | grep -i 'error' | grep -vi 'no errors' >&2 || true done exit 1 fi # NB: the C code generator writes "***" banner comments into the .s file, so the # assembly listing is full of asterisks; only real error lines are matched here. for f in HELLO.LST ENTRY.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 cp "$WORK/HELLO.OUT" "$OUT/$NAME.coff" cp "$WORK/HELLO.OBJ" "$OUT/hello.obj" cp "$WORK/ENTRY.OBJ" "$OUT/entry.obj" sed 's/\r$//' "$WORK/HELLO.MAP" > "$OUT/hello.map" sed 's/\r$//' "$WORK/HELLO.LST" > "$OUT/hello.lst" sed 's/\r$//' "$WORK/ENTRY.LST" > "$OUT/entry.lst" [ -f "$WORK/HELLO.ASM" ] && sed 's/\r$//' "$WORK/HELLO.ASM" > "$OUT/hello.s" echo "build.sh: $OUT/$NAME.coff ($(wc -c < "$OUT/hello.coff") bytes)" sed -n '1,40p' "$OUT/hello.map"