Files
2ine-tms34010/TMS34010.md
T
opencode.energia.arti.ee 68f873784b
Build / Linux (push) Waiting to run
tms34010: run TI TMS34010 OS/2 tools (gspa/gsplnk/gsprom) under 2ine
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.
2026-10-31 20:50:11 +00:00

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

  1. CMakeLists.txt — the hard-coded include_directories("/usr/local/include/SDL2") is used only if it exists; otherwise fall back to /usr/include/SDL2. Without this, lib2ine.c cannot find SDL.h on a stock distro.
  2. native/doscalls*.c/.h — 16-bit entry points these tools import:
    • Dos16GetDateTime (ordinal 33). The OS/2 1.x 16-bit DATETIME is 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 own asctime/localtime wrapper; getting this wrong crashes gspa at 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.
  3. 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 the 0xFFFF:0000 placeholder in memory (gspa then segfaulted in a lcall to its CRT exit handler). Chains now run to the 64 KB virtual size or the end-of-chain marker.
  4. native/doscalls.c — Dos16GetPID asserted 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) spawns gspac successfully, but the child dies on lx_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 around Dos16CreateCSAlias/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.