Files
arti 3bcdfc3641
Build / Linux (push) Waiting to run
tms34010: the null-selector fix unblocks the C tools; document the pipeline
gspac/gspopt/gspcg now run, so the status table and examples cover the
full C path. gspcl itself still stops after gspac because the children
exit 139 at teardown; the manual pipeline is the working route. Note the
relative-path and consumed-intermediate requirements, the b15/sp
round-trip difference, and the non-zero exit statuses.
2026-11-01 00:17:01 +02:00

6.2 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-11-01)

tool result
gspa (TMS340 COFF assembler) works — assembles an 11,852-line disassembly of the VT1200 firmware region, "No Errors, No Warnings", valid COFF
gsplnk (linker) works — links .obj + rts.lib/flib.lib into an absolute image
gsprom (COFF → Tek-hex) works — both -i EPROM pair and plain Tek-hex
gspar (archiver) works — lists rts.lib members
gspac / gspopt / gspcg (C front end, optimizer, codegen) work — the null-selector fix below unblocks the C compiler
gspcl (driver) partial — runs gspac, then stops; gspac/gspcg exit 139 at teardown. Drive the pipeline manually.

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

The C pipeline (front end → optimizer → codegen → assembler → linker):

./lx_loader /path/to/gspac.exe  -k file.c file.if
./lx_loader /path/to/gspopt.exe -k -O2 file.if file.opt
./lx_loader /path/to/gspcg.exe  -m file.opt file.asm file.tmp
./lx_loader /path/to/gspa.exe   file.asm
./lx_loader /path/to/gsplnk.exe file.obj rts.lib flib.lib -o file.out
./lx_loader /path/to/gsprom.exe file.out file.hex

Pass relative filenames and keep the sources, objects and libraries in the loader's cwd: the OS/2 tools cannot open Unix absolute paths, and the tools consume their intermediate .if/.opt files, so regenerate them per run.

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

Arch names (verified 2026-11-01):

sudo pacman -S --needed base-devel cmake lib32-glibc lib32-gcc-libs \
                    lib32-ncurses sdl2-compat

2ine builds 32-bit (-m32) and links the 32-bit libSDL2-2.0.so.0 that is checked into the repo root. On CMake 4.x, pass the policy floor explicitly:

cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug \
      -DCMAKE_POLICY_VERSION_MINIMUM=3.5
cmake --build build -j2

That 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.
  5. lx_loader.c — lxConvert1616to32 treated only 0 as null. The C tools pass 0003:0000 (selector index 0 with RPL 3), which is the OS/2 null far pointer; it hit ldt[0] and aborted. Segment index 0 now returns NULL. This unblocks gspac, gspopt and gspcg.
  6. CMakeLists.txt — HAVE_CURSES_H fallback for CMake 4.x when FindCurses leaves CURSES_HAVE_* unset, and a /usr/lib32 fallback for the ncurses library when the Debian /usr/lib/i386-linux-gnu path is absent.

Known issues / next steps

  • gspcl (the driver) runs gspac, then stops: gspac and gspcg exit 139 at teardown even though they write correct output, and gspcl gives up on the child status. Drive gspac → gspopt → gspcg → gspa manually; that pipeline produces a correct image.
  • gspa 5.01 rejects the B-file name b15 (INVALID REGISTER VALUE). The bare sp encodes the A15 namespace, while the 1987 assembler accepted b15 and encoded the B15 namespace. SP is the same physical register as A15 or B15, so the result is semantically identical but a firmware round-trip differs in one byte. See the VT1200 tools/tms34010-sdk/2INE-501.md.
  • Huge-segment selector arithmetic is stubbed; nothing in the assembler path needs more than 64 KB of data.
  • The tools commonly return a non-zero exit status (segfault or 1) after successful work. Check the output files rather than the exit code.

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.