diff --git a/README.md b/README.md index f96e80a..54aa22e 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/tools/tms34010-sdk/OS2-501.md b/tools/tms34010-sdk/OS2-501.md new file mode 100644 index 0000000..1f2b326 --- /dev/null +++ b/tools/tms34010-sdk/OS2-501.md @@ -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 **** +(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.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 #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; extensions: -ea<.ext> -eo<.ext> +Linker (-z): -a (absolute) -ar (relocatable) -c (ROM init) -cr (RAM init) + -e -f -h -i -l -m -o -r -s -u +``` + +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).