mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-11-01 12:14:56 +02:00
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:
1 parent
173f3bebda
commit
005dfb02d5
2 files changed
+343
-1
No files matched your search
@@ -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
|
||||
|
||||
@@ -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).
|
||||
Reference in new issue
Block a user