docs: how to use the 1990 r5.01 (OS/2) TMS34010 toolchain

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.
This commit is contained in:
opencode.energia.arti.ee committed 2026-10-31 20:51:06 +00:00
1 parent 173f3bebda
commit 005dfb02d5
2 files changed
+343 -1

No files matched your search

+2 -1
View File
@@ -568,6 +568,7 @@ also why a server-side change cannot cause or cure it.
| `reference/level1-test-sequence.md` | the 15 level-1 tests and their codes |
| `reference/third-party-code.md` | what open-source code is in the ROM |
| `reference/tms34010-sdk.md` | the 1987 toolchain, buildable today |
| `tools/tms34010-sdk/OS2-501.md` | using the 1990 r5.01 toolchain (ANSI C + optimizer) |
| `EXPLOIT_NOTES.md` | the original code-execution audit and the crash decode |
| `NEXT_SESSION.md` | the LAT soak handoff (older; see the reports for later work) |
@@ -587,7 +588,7 @@ vt1200/
│ ├── ptr_constants.py # find/resolve bit-address constants
│ ├── smart34010/ # dis34 (two encoding fixes)
│ ├── as34/ # TMS34010 binutils, ported to 64-bit Linux
│ ├── tms34010-sdk/ # the 1987 TI SDK (under DOSBox)
│ ├── tms34010-sdk/ # TI SDKs: 1987 DOS + 1990 OS/2 (see OS2-501.md)
│ └── ghidra-tms34010/ # patched processor module + install script
├── harness/
│ ├── mame/ # the MAME driver, Lua probes, reports
+341
View File
@@ -0,0 +1,341 @@
# 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:
```sh
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:
```sh
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:
```sh
mcopy -i os2-13.img@@32256 myfile.c ::/TI/
```
86Box settings that work (86Box 6.0):
```ini
[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.SYS` and batch files must be CRLF.** LF-only merges lines and the
kernel dies with `SYS1919` / an internal processing error.
* **This image does not run `AUTOEXEC.BAT` or `STARTUP.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](https://github.com/icculus/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`).
```sh
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:
* **`-o` alone means level 2.** `-o0` is 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. `-pk` selects 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
* **`-o` is 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 `.text` of `0x0e20` is 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.SYS` and `.CMD`/`.BAT` inside the OS/2 guest.
* **`AUTOEXEC.BAT`/`STARTUP.CMD` are 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 `.asm` through GSPA 2.00** — it will not assemble.
* **No `/dev/kvm` needed** 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).