The r5.01 tools are a superset of the 1987 DOS set: ANSI C, one driver, gspopt, a bigger runtime, and 35.8% smaller .text at -o2 on the same source. Add a practical guide: * what the package contains and how to extract it * running it: OS/2 1.3 under 86Box (full toolchain) and 2ine (assembler/ linker/converter, with the patched fork linked) * the gspcl option table and verified command lines (-o0/-o1/-o2, -pk, -al, -z/-lrts.lib), plus the manual gspac -> gspopt -> gspcg -> gspa pipeline and the linker command file * gotchas: -o semantics, bit-addressed section sizes, CRLF, AUTOEXEC not running in the guest, emulated-keyboard limits, one-way assembler compatibility * measured code-size and throughput numbers for both toolchains Link it from the docs index and the repository layout.
13 KiB
Using the 1990 r5.01 (OS/2) TMS34010 toolchain
The 1990 TMS340 Family Code Generation Tools r5.01 are a strict superset of
the 1987 DOS tools in 1987-05 TMS34010 SDK/, with one practical catch: they
are 16-bit OS/2 1.x NE programs, not DOS. This file is the how-to: what
they buy you, how to get them running today, and every command line that was
verified on 2026-10-31.
Measured on one 110-line K&R C source (loops, array indexing, switch, struct,
helper call, bit ops) compiled by both toolchains:
| build | .text |
instrs | .obj |
|---|---|---|---|
| 1987 GSPCG 2.01, no optimizer | 704 B | 243 | 1364 B |
5.01, no -o |
684 B (−2.8 %) | 237 | 1298 B |
5.01 -o0 |
550 B (−21.9 %) | 202 | 1164 B |
5.01 -o1 |
474 B (−32.7 %) | 173 | 1038 B |
5.01 -o2 |
452 B (−35.8 %) | 161 | 1016 B |
So: use -o2. Without an -o flag the newer compiler is only ~3 % better
than the 1987 one — all the win is the optimizer (gspopt, an
intermediate-code optimizer, not an assembly peephole). But 5.01 is also a
language upgrade (ANSI C by default, -pk for K&R) and a tooling upgrade
(single driver, ANSI headers, 104 vs 80 runtime symbols, 6 runtime variants).
1. What is in the package
1990-11 TMS340 Family SDK/
1990-11-19 TMS340 Family Code Generation Tools (1 of 2) ...zip # executables
1990-11-19 TMS340 Family Code Generation Tools (2 of 2) ...zip # headers + libs
1990-11-19 TMS340 Family C Source Debugger r5.00 ...zip
1990-11-19 TMS340 Family Graphics Library (1..3 of 3) r2.01 ...zip
1990-11-19 TIGA SDK r2.01 ...zip
Disk 1 (the tools you need):
| file | role | version banner |
|---|---|---|
gspcl.exe |
C compiler driver (preprocess → compile → optimize → assemble → link) | TMS340 C Compiler Shell 5.01 |
gspac.exe |
C parser / front end | — |
gspcg.exe |
code generator | TMS340 C Codegen 5.01 |
gspopt.exe |
intermediate-code optimizer | TMS340 ANSI C Optimizer 5.01 |
gspa.exe |
COFF assembler | TMS340 COFF Assembler 5.01 |
gsplnk.exe |
linker | TMS340 COFF Linker 5.01 |
gsprom.exe |
COFF → Tek-hex converter | COFF Object Converter 5.01 |
gspar.exe, clist.exe |
archiver, listing utility |
Disk 2: assert.h ctype.h errno.h float.h limits.h math.h setjmp.h stdarg.h stddef.h stdlib.h string.h time.h sysint.if, and the runtimes
rts.lib rtsb.lib rtsc.lib rtscb.lib rtsi.lib rtsib.lib (integer/float
variants) plus flib.lib flibc.lib flibi.lib, rts.src and flib.src.
Extract to a working directory:
cd "tools/tms34010-sdk/1990-11 TMS340 Family SDK"
unzip -o "1990-11-19 TMS340 Family Code Generation Tools (1 of 2) r5.01 rev2564062-1641.zip" -d ../../os2-501/bin
unzip -o "1990-11-19 TMS340 Family Code Generation Tools (2 of 2) r5.01 rev2564062-1641.zip" -d ../../os2-501/lib
They are MZ+NE, NE 5.1, target OS byte 0x01 (OS/2 1.x), and every tool
imports only DOSCALLS — no Presentation Manager, no VIO/KBD, i.e. plain
console programs. That is why they can work under an emulation layer as well as
under real OS/2.
2. Getting a runtime
2.1 OS/2 1.3 under 86Box — the full toolchain (compile, link, convert)
This is the only route that runs gspcl today.
Media: the preinstalled image on archive.org, item Os21.3VirtualHardDisk,
file MicrosoftOs-21.30HardDisk.vhd (a Virtual-PC dynamic VHD, 500 MiB
virtual). Convert it to raw:
qemu-img convert -O raw MicrosoftOs-21.30HardDisk.vhd os2-13.img
The image is one bootable FAT16 partition, CHS 1015/16/63, partition start LBA 63 — so the filesystem is editable from the host while the VM is stopped:
mcopy -i os2-13.img@@32256 myfile.c ::/TI/
86Box settings that work (86Box 6.0):
[Machine]
machine = asus386 ; AMI BIOS: accepts a user-defined (type 47) disk
cpu_family = i386dx
cpu_speed = 20000000
mem_size = 6144
[Video]
gfxcard = cl_gd5422_migrated_isa
[Storage controllers]
hdc_1 = ide_isa_2ch
[Hard disks]
hdd_01_fn = os2-13.img
hdd_01_ide_channel = 0:0
hdd_01_parameters = 63, 16, 1015, 0, ide
hdd_01_speed = ramdisk
Boot to [C:\] (~10 s). Two traps:
CONFIG.SYSand batch files must be CRLF. LF-only merges lines and the kernel dies withSYS1919/ an internal processing error.- This image does not run
AUTOEXEC.BATorSTARTUP.CMD. Verified with a file-marker test. Put everything you need on the disk first, then start the work with one typed command.
If you drive 86Box over Xvfb with xdotool, note that the emulated keyboard
drops keys typed faster than ~0.9 s apart, and punctuation/shift are
unreliable. Type only letters (name your batch CG.CMD, BK.CMD, …) one
character at a time, and have the batch print a unique end token so the host
can detect completion by OCR (or just wait and take a screenshot).
2.2 2ine — assembler/linker/converter natively, no VM
gspa, gsplnk and gsprom run under
2ine with a small patch series; the patched
fork lives at https://git.wut.ee/opencode.energia.arti.ee/2ine-tms34010
(see its TMS34010.md). Build it 32-bit (cmake -S . -B build && cmake --build build -j2, needs gcc-multilib, libc6-dev-i386, libncurses-dev:i386).
cd 2ine/build # lx_loader dlopen()s ./lib<module>.so, so cwd matters
./lx_loader gspa.exe test.asm # assemble
./lx_loader gsplnk.exe test.obj rts.lib -o test.out
./lx_loader gsprom.exe test.out test.hex # COFF -> Tek-hex
./lx_dump gspa.exe # NE header/segments/imports
gspcl (the C compiler) does not work yet there: the gspac child hits
lxConvert1616to32 with a selector 2ine has not mapped. Use 86Box when you need
to compile C.
3. The compiler driver: gspcl
gspcl [-options] filenames... [-z link_options...]
Verbatim option summary (from the tool's own usage output, VCL.TXT):
-c no linking (negates -z) -q quiet
-dNAME pre-define NAME -qq super quiet
-g symbolic debugging -s C source interlist
-i<dir> #include search path -uNAME undefine NAME
-k keep .asm file -vXX target processor 340XX
-n compile only (no asm) -z... link, options follow
Parser: -pe -po -pk (K&R) -pw -pl -p? -pn
Typing: -tf -tp
Runtime: -ma -ms (small model) -mf (IEEE) -mn -mc (TMS34082) -me -mr -mx -mm
Optimizer: -o (level 2) -o0 (register) -o1 (+local) -o2 (+global) -om (inline)
Assembler: -al (listing) -ax (xref) -ah (old hex) -as (local symbols)
Files: -fa -fc -fo -ft<dir>; extensions: -ea<.ext> -eo<.ext>
Linker (-z): -a (absolute) -ar (relocatable) -c (ROM init) -cr (RAM init)
-e<sym> -f<val> -h -i<dir> -l<lib> -m<map> -o<file> -r -s -u<sym>
Two things to internalise:
-oalone means level 2.-o0is the lowest optimization level, not "off". With no-o*at all the optimizer is not run.- ANSI C is the default.
int f(int a)compiles.-pkselects K&R compatibility for 1987-era sources.
Examples
Compile and link an absolute image in one step:
gspcl -k -o2 file.c -z -a -c -o file.out -m file.map -lrts.lib
Compile only, keep the generated assembly (this is what you want while debugging codegen):
gspcl -k -o2 -c file.c -> file.obj, file.asm
gspcl -k -o2 -al -c file.c -> ... plus file.lst (assembly listing)
K&R source from the 1987 era:
gspcl -pk -o2 -k -c file.c
Several C files plus a library:
gspcl -k -o2 -c a.c b.c
gspcl -o2 -z -a -o prog.out -m prog.map a.obj b.obj -lrts.lib
Environment variables: C_OPTION (default options), C_DIR (include/library
paths), TMP (temp directory).
Manual pipeline (what the driver does internally)
gspac -k file.c file.if # parse -> intermediate
gspopt -k -O2 file.if file.opt # optimize intermediate (optional)
gspcg -m file.opt file.asm file.tmp
gspa file.asm # -> file.obj
gsplnk ... # or let gspcl -z do it
On the benchmark source the .if is 3263 B, the .opt 4032 B (the annotated
intermediate grows), and the object shrinks 1298 → 1016 B. Use the manual form
only when you want to inspect or hand-tune the intermediate; the driver is
otherwise equivalent (same 1016-byte object, same .asm except a header
comment).
4. Assembler, linker, converter
GSPA file.asm # -> file.obj
GSPLNK file.obj rts.lib -o file.out # simple form; or a command file (see below)
GSPROM file.out file.hex # COFF -> Tek-hex
An assembly listing is produced by the driver's -al option (gspcl -al -c file.c); via the standalone assembler the same listing switch is passed as
-l to GSPA.
Linker command file (rt.cmd), as used for the VT1200 ROM round-trip:
-a
-o file.out
-m file.map
file.obj
SECTIONS
{
.text 3F208000h: {}
}
The SECTIONS origin is a bit address (TMS34010 is bit-addressed), and
gsprom -i writes the high/low EPROM pair (same interface as the 2.01
converter used in the ROM round-trip). As with the 1987 converter, the hex
file's own addresses wrap at 64 KB, so take placement from the COFF file or the
map, never from the hex.
Assembler differences vs 2.00: 65 directives vs 51; new .ASECT .COPROC .ENDSTRUCT .EXE .HWORD .IEEEFL .LABEL .STRUCT .TAG .TMS340 .TMS34010 .TMS34020 .TMS34082 .VERSION. .usect and .if already existed in 2.00.
Compatibility is one-way. GSPA 5.01 assembles 2.00 output unchanged; GSPA
2.00 rejects 5.01 output (11 errors: .version, CLRS, bare JR). Upgrade
the assembler together with the compiler.
5. Libraries and headers
| library | 1987 | 1990 |
|---|---|---|
rts.lib |
41,922 B, 66 members, 80 symbols | 67,784 B, 85 members, 104 symbols |
flib.lib |
12,686 B, 28 members, 40 symbols | 15,512 B, 35 members, 47 symbols |
1990 ships six integer runtime variants (rts, rtsb, rtsc, rtscb, rtsi,
rtsib — byte/large-model variants) and three float variants (flib, flibc,
flibi). Math moved into rts.lib (_sin, _sqrt, _pow, …), errno and
strxfrm were added, and _printf was removed (only sprintf remains in
rts.lib) — if you need formatted output, use sprintf.
Headers are ANSI-ised with prototypes and include guards (stdarg.h v5.01,
stdlib.h, errno.h, math.h). Point -i at the disk-2 directory (and
-i/-z -i at the library directory) if you keep headers/libs elsewhere.
6. Gotchas
-ois not optional if you want the win. No-o→ no optimizer → only ~3 % smaller than 1987.-o2→ 36 % smaller.- Bit-addressed sizes. COFF section sizes are in bits (16 bits per
instruction word); a
.textof0x0e20is 452 bytes, not 3.6 KB. - ANSI by default. K&R code needs
-pk; mixing old headers with the new compiler may need-tf/-tp(relaxed prototype/pointer checks). - CRLF for
CONFIG.SYSand.CMD/.BATinside the OS/2 guest. AUTOEXEC.BAT/STARTUP.CMDare not executed by this OS/2 1.3 image — stage files offline through the disk image (mtools, offset 32256).- Typing into 86Box: ≥0.9 s per key, letters only; punctuation and shifted
characters are unreliable. Name batches with letters (
CG.CMD) and invoke them by bare name. - Don't put the 5.01
.asmthrough GSPA 2.00 — it will not assemble. - No
/dev/kvmneeded for 86Box; it is a pure software emulator.
7. Throughput (why this matters for the edit/compile loop)
One 2,412-line / ~2,000-instruction assembly, same file everywhere, measured 2026-10-31 on this host:
| environment | assembler | s / run |
|---|---|---|
| 2ine (native, 32-bit loader) | 5.01 gspa |
0.054 |
DOSBox-X 2025.02, cycles=max |
2.00 GSPA |
0.070 |
DOSBox 0.74, cycles=max |
2.00 GSPA |
0.104 |
| 86Box, 386DX @ 20 MHz, OS/2 1.3 | 5.01 gspa |
4.50 |
DOSBox 0.74, cycles=3000 |
2.00 GSPA |
5.06 |
So the full 5.01 toolchain is ~80× slower than 2ine's native assembler: use 86Box for compiling (where the 36 % code-size win is), and 2ine for iterating on assembly. Booting the OS/2 guest costs ~10 s, so keep it running while you work.
8. Reproducing the numbers
The comparison above comes from a K&R-compatible bench.c (sum loop, indexed
loop, switch, struct update, helper call, bit loop) compiled five ways
(2.01; 5.01 with no -o, -o0, -o1, -o2), with sizes read from the COFF
section headers and instruction counts from the assembler listings. The exact
commands are the ones in §3; the per-function table and the gspopt
before/after are in /home/arti/os2-work/codegen/REPORT.md on the build
machine (scratch, not part of this repo).