Files
vt1200/dwt/loader
arti 41b0979aef c-hello: first C program on the VT1200, running on real hardware
The 1987 TI K&R toolchain already compiled and linked a fib test, but nothing
had ever been executed on a VT1200. This is that program: hello.c draws HELLO
into video RAM (1 bpp, bit 0x04000000, no X11) and is loaded through the COFF
loader with hostload.py, on the real unit and in MAME.

Two runtime traps shaped the design, both recorded in the README:

  * boot.obj's exit() is `for(;;)` and _c_int00 ends in `reti`.  That is a
    standalone-ROM runtime, not a process: the child spun forever, and because
    the VT1200 OS is cooperative it took the whole terminal down (illegal
    opcode on hardware).  entry.asm replaces boot.obj -- set STK/FP, call
    _main, `rets` back to the create_process trampoline, the same return
    xhello uses -- and the image carries no .cinit (tables are built in code).
  * Pointers are bit addresses and pointer arithmetic scales by object size,
    so p + n on a char * is n bytes.  The pre-fix frame in evidence/ is that
    bug: 32 one-byte bars spread across a row.

Framebuffer geometry is not portable: the real unit is 1280 px wide at a
256-byte row pitch, MAME's canvas is 1024 px at 128.  build.sh builds both
(ROW_BYTES), and the README records how the real pitch was measured from a
real-unit frame rather than taken from MAME.

Evidence: real-unit frames in harness/c-hello/evidence/ (the pre-fix stripes
and the working HELLO), and dwt/loader/evidence/real-unit-xhello/ for the X
window that ran on the unit earlier.
2026-10-29 18:25:38 +02:00
..

dwt/loader — the COFF loader half of the app loader

Loads a GSPLNK-linked COFF image that is already in RAM into a first-class process on the VT1200 OS. The transport (TFTP) is separate; this half takes a buffer and length, picks the addresses from the COFF, and calls create_process.

Read dwt/notes/LOADER.md for the full report and dwt/notes/LOADER_CROSS.md for the transport interface.

Files

file purpose
loader.asm the loader; linked at bit 0x01880000, raw .bin 1220 B
marker.asm acceptance app with .text/.data/.bss at three addresses
coff.py TI COFF reader/dumper (summary, raw, manifest)
build.sh GSPA/GSPLNK wrapper; keeps the linked COFF
reldemo.sh, rel_a.asm, rel_b.asm relocation and position-dependence demo
loader.lua debugger-assisted harness (no network, no rdebug)
probe_os.lua heap-list and register-write probe used to design the harness
build/ linked loader/app COFFs, raw .bins, maps, listings
evidence/ run logs, COFF dumps, the xhello window frame

work/ (the DOS tools extracted from the SDK floppy) and run/ (private NVRAM/cfg) are local scratch and ignored.

Build

./dwt/loader/build.sh dwt/loader/loader.asm 01880000
./dwt/loader/build.sh dwt/loader/marker.asm 018C0000 018D0000 018D8000
./dwt/loader/build.sh dwt/gui/xhello.asm    01840000
./dwt/loader/reldemo.sh

build.sh takes SOURCE.asm [TEXT_ORIGIN [DATA_ORIGIN [BSS_ORIGIN]]] (origins are bit addresses) and writes build/<name>.coff, .bin, .map, .lst, .obj.

Run (debugger-assisted, no network)

VT1200_SKIP_LEVEL1=1 LOADER_AT=2500 LOADER_END=2620 \
LOADER_COFF=dwt/loader/build/marker.coff LOADER_OUT=$PWD/dwt/loader/evidence \
/home/arti/code/k-space/mame0289/vt1200 vt1200 \
  -rompath harness/mame/roms -video none -sound none -nothrottle -skip_gameinfo \
  -nvram_directory $PWD/dwt/loader/run/nvram \
  -cfg_directory $PWD/dwt/loader/run/cfg \
  -debug -debugger none \
  -autoboot_script dwt/loader/loader.lua -autoboot_delay 0

The script pokes the loader at 0x01880000 and the COFF at LOADER_BUF (default 0x01900000), writes the descriptor, and sets PC. It never uses the network, the rdebug service or a firmware transport.

Knobs: LOADER_MODE=1 (callable/return instead of debug-resume), LOADER_A8_DESC=1 (descriptor in A8), LOADER_SNAP=1 (PNG at LOADER_END), LOADER_VERBOSE=1, LOADER_TRACE=1.