Fixes needed to run the 1990 TI 'TMS340 Family Code Generation Tools r5.01'
(16-bit OS/2 1.x NE, DOSCALLS-only) on 2ine:
* CMake: fall back to the system SDL2 headers when /usr/local/include/SDL2
is absent; the hard-coded path broke the build on stock distros.
* doscalls16: implement the entry points these tools import
- Dos16GetDateTime (33) with the OS/2 1.x *hours-first* 10-byte layout
(the year-first 8-byte layout crashes gspa in asctime/localtime)
- Dos16NewSize (68)
- Dos16GetHugeShift (135) / Dos16HugeIncr (136)
- Dos16CreateCSAlias (43), Dos16DevConfig (52), Dos16Move (67)
* lx_loader: walk NE fixup chains to the segment's 64K virtual size instead
of its file size, so fixups pointing into the BSS tail are applied. gspa
segfaulted in a lcall to its CRT exit handler because of this.
* doscalls: do not assert that the host PID fits in 16 bits (pid_max is
4194304 on current kernels); the 16-bit API truncates anyway.
Verified: gspa assembles a 2,412-line TMS34010 source with 'No Errors,
No Warnings', gsplnk links it with rts.lib, gsprom converts to Tek-hex.
The C compiler child (gspac via gspcl) still hits the lxConvert1616to32
selector assertion; see TMS34010.md.
4.1 KiB
2ine fork: TI TMS34010 OS/2 toolchain support
This is a fork of icculus/2ine at commit
1ca194f ("viocalls: Actually, VioGetMode() needs to initialize ncurses",
2022-01-31) plus a small patch series that makes TI's 1990 "TMS340 Family
Code Generation Tools r5.01" usable on Linux.
Those tools (gspa, gsplnk, gsprom, gspcg, gspopt, gspcl, …) are
16-bit OS/2 1.x NE executables that import only DOSCALLS — exactly the
shape 2ine's 16-bit bridge targets.
Status (verified 2026-10-31)
| tool | result |
|---|---|
gspa (TMS340 COFF assembler) |
works — assembles a 2,400-line source, "No Errors, No Warnings", valid COFF |
gsplnk (linker) |
works — links .obj + rts.lib into an absolute image |
gsprom (COFF → Tek-hex) |
works — "Translation complete" |
gspcl → gspac (C compiler) |
blocked — the compiler child starts, then 2ine asserts in lxConvert1616to32 |
Example session (from the repo root):
cd build # lx_loader dlopen()s ./lib<module>.so, so cwd matters
./lx_loader /path/to/gspa.exe test.asm
./lx_loader /path/to/gsplnk.exe test.obj rts.lib -o test.out
./lx_loader /path/to/gsprom.exe test.out test.hex
TMS340 COFF Assembler Version 5.01
(c) Copyright 1985, 1990 Texas Instruments Incorporated
PASS 1
PASS 2
No Errors, No Warnings
lx_dump also parses the NE headers (segments, fixups, DOSCALLS imports).
Build
Dependencies (Debian/Ubuntu names):
sudo apt install build-essential cmake libncurses-dev libncurses-dev:i386 \
libc6-dev-i386 gcc-multilib
2ine builds 32-bit (-m32) and links the 32-bit libSDL2-2.0.so.0 that is
checked into the repo root. cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug && cmake --build build -j2 produces build/lx_loader (32-bit), build/lx_dump
and the lib*.so modules.
Patches
CMakeLists.txt— the hard-codedinclude_directories("/usr/local/include/SDL2")is used only if it exists; otherwise fall back to/usr/include/SDL2. Without this,lib2ine.ccannot findSDL.hon a stock distro.native/doscalls*.c/.h— 16-bit entry points these tools import:Dos16GetDateTime(ordinal 33). The OS/2 1.x 16-bitDATETIMEis the hours-first 10-byte layout (same shape as the 32-bit struct), not the year-first 8-byte one. Proven against the tool's ownasctime/localtimewrapper; getting this wrong crashesgspaat startup.Dos16NewSize(68) — validate selector, no-op (2ine maps full 64 KB).Dos16GetHugeShift(135) → 3,Dos16HugeIncr(136) — huge-segment selector arithmetic.Dos16CreateCSAlias(43),Dos16DevConfig(52),Dos16Move(67) — for the C compiler child.
lx_loader.c— NE fixup chains were walked only up to the segment's file size, so fixups whose target lies in the BSS tail were skipped, leaving the0xFFFF:0000placeholder in memory (gspathen segfaulted in alcallto its CRT exit handler). Chains now run to the 64 KB virtual size or the end-of-chain marker.native/doscalls.c—Dos16GetPIDasserted that the host PID fits in 16 bits. On modern kernels (pid_max= 4194304) it does not, so the process aborted before the tool ran. The 16-bit API already truncates; the asserts are disabled.
Known issues / next steps
gspcl(C compiler driver) spawnsgspacsuccessfully, but the child dies onlx_loader.c:546: lxConvert1616to32: Assertion 'GLoaderState.ldt[selector] != 0'— a 16:16 far pointer whose selector is not one of 2ine's mapped segments (likely selector arithmetic aroundDos16CreateCSAlias/Dos16AllocSeg). The assembler/linker/converter path is unaffected.- Huge-segment selector arithmetic is stubbed; nothing in the assembler path needs more than 64 KB of data.
Provenance
Upstream: https://github.com/icculus/2ine. The patch series was written while bringing up the TI toolchain for the VT1200 project and is published here so the fixes are not lost; it has not been sent upstream.