tms34010: the null-selector fix unblocks the C tools; document the pipeline
Build / Linux (push) Waiting to run

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.
This commit is contained in:
arti committed 2026-11-01 00:17:01 +02:00
1 parent a4401283cb
commit 3bcdfc3641
1 file changed
+57 -13
+57 -13
View File
@@ -9,14 +9,16 @@ 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)
## Status (verified 2026-11-01)
| 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` |
| `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):
@@ -27,6 +29,21 @@ cd build # lx_loader dlopen()s ./lib<module>.so, so cwd ma
./lx_loader /path/to/gsprom.exe test.out test.hex
```
The C pipeline (front end → optimizer → codegen → assembler → linker):
```sh
./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
@@ -47,10 +64,24 @@ sudo apt install build-essential cmake libncurses-dev libncurses-dev:i386 \
libc6-dev-i386 gcc-multilib
```
Arch names (verified 2026-11-01):
```sh
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. `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.
checked into the repo root. On CMake 4.x, pass the policy floor explicitly:
```sh
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
@@ -76,16 +107,29 @@ and the `lib*.so` modules.
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` (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.
* `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