mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-10-31 12:05:05 +02:00
Andrew Morton's Unix-hosted assembler/linker for the TMS34010, fetched from the gsptools archive and patched to build on x86-64. The K&R sources silently truncate pointers there: implicit int parameter declarations and fixed-argument printf wrappers. The patch fixes those and the flex 2.6 yy_init mismatch. hello.as34.g is harness/hello-world/hello.asm in as34 syntax. as34/ld34 reproduce the GSPA-built payload byte-for-byte (82 bytes, md5 db91788991ebba476b55a11127a36475), and the MAME hello.lua run reports the same markers, the same 1024-word VRAM block and a byte-identical frame. build.sh downloads the upstream tarball at build time (sha256 pinned); the tree is not vendored.
105 lines
4.4 KiB
Markdown
105 lines
4.4 KiB
Markdown
# as34 / ld34 — Morton's Unix-hosted TMS34010 binutils
|
|
|
|
`as34` (assembler) and `ld34` (linker) are Andrew Morton's 1990s TMS34010
|
|
tools, shipped with his GCC 2.5.x port. They are **not TI tools** and not
|
|
related to `GSPA`/`GSPLNK`; they run natively on Linux, with no DOSBox.
|
|
|
|
`build.sh` fetches the original `gsp.tar.gz` from the Wayback Machine,
|
|
applies `as34-port.patch`, and builds three programs:
|
|
|
|
| tool | what it does |
|
|
|---|---|
|
|
| `as34` | assembles `.g` source to a `.go` object (`LINKMAGIC 0x3abf782e`) |
|
|
| `ld34` | links `.go` objects to `g.out` (same linkhdr container), with a map |
|
|
| `dis34` | disassembles `g.out` (kept for inspection; the repo's `tools/smart34010/dis34` is a better independent decoder) |
|
|
|
|
The compiled `.text` is extracted from `g.out` by `extract.py`. `g.out` is
|
|
**not COFF** — `ld34/coff.c` is dead code that is neither compiled nor called.
|
|
The live writer is `ld34/header.c`, which emits the same packed `linkhdr`
|
|
format that `as34` produces.
|
|
|
|
## Build
|
|
|
|
```sh
|
|
tools/as34/build.sh
|
|
```
|
|
|
|
Everything is fetched and built under `tools/as34/build/` (git-ignored;
|
|
override with `AS34_BUILD_DIR`). The tools end up at:
|
|
|
|
```
|
|
tools/as34/build/src/gsp/binutils/as34/as34
|
|
tools/as34/build/src/gsp/binutils/ld34/ld34
|
|
tools/as34/build/src/gsp/binutils/ld34/dis34
|
|
```
|
|
|
|
The tarball is 2.1 MB and is an **uncompressed tar with a `.tar.gz` name** —
|
|
that is how the archive is stored. Its SHA-256 is pinned in `build.sh`.
|
|
|
|
## Test (byte comparison, then MAME)
|
|
|
|
```sh
|
|
tools/as34/test.sh
|
|
REPO=$PWD MAME=/home/arti/code/k-space/mame0289/vt1200 tools/as34/test.sh
|
|
```
|
|
|
|
`hello.as34.g` is `harness/hello-world/hello.asm` ported to `as34` syntax.
|
|
The result is **byte-identical** to the GSPA-built
|
|
`harness/hello-world/payload.bin` (82 bytes, md5
|
|
`db91788991ebba476b55a11127a36475`), and the MAME run reports the same
|
|
markers, the same 1024-word VRAM block and the same frame as the original
|
|
payload.
|
|
|
|
### Syntax differences from GSPA
|
|
|
|
| | GSPA | as34 |
|
|
|---|---|---|
|
|
| hex | `0DEADh` | `>DEAD` (also `0xdead`) |
|
|
| immediate width | `movi x, a0, L` | no `L`/`W` suffix; `movi` is always the 32-bit form |
|
|
| 16-bit immediate add | `addi` | `addiw` — as34's `addi` is the **32-bit** immediate form |
|
|
| immediate order | same (`op src, dst`) | same |
|
|
|
|
Everything else — labels, `@absolute`, `*a2+`, `dsjs`, bit addresses, field
|
|
specifiers — is unchanged. `dsjs` displacement encoding matches GSPA (checked
|
|
against `tools/smart34010/dis34`).
|
|
|
|
## What the port patch changes
|
|
|
|
The code is K&R C written for 32-bit SunOS. On x86-64 the original build
|
|
produces truncated pointers, so the patch is not cosmetic:
|
|
|
|
* **Pointer parameters declared implicitly as `int`** (`Xwrite`, `openfiles`,
|
|
`emitslcode`/`emitnslcode`/`emitswcode`/`emitnswcode`). On a 32-bit host
|
|
the implicit `int` happened to be pointer-sized; on x86-64 it truncates.
|
|
* **K&R printf wrappers** (`amprintf`, `ameprintf`, `amfprintf`, `eprintf`)
|
|
declared `p1…p6` as `int`, truncating `%s` arguments. Rewritten as real
|
|
variadic functions with `va_list`.
|
|
* **`imalloc`** likewise made variadic, and declared in `proto.h` (included
|
|
with `-include` for the assembler's translation units).
|
|
* **flex 2.6**: `yyGetReady()` used to set `yy_init = 1`; with the modern
|
|
skeleton that leaves `yy_c_buf_p` NULL and segfaults. It is now a no-op —
|
|
`YY_INPUT`/`am_input` still supplies the line buffer.
|
|
* `abort(1)` → `abort()`; `hash()` uses unsigned arithmetic; two
|
|
`exit(eprintf(...))` calls split.
|
|
|
|
## Upstream quirks worth knowing
|
|
|
|
* **`-e` takes its argument attached**: `-e_start`. The space form
|
|
(`-e _start`) is broken in the original parser: it sets the entry name to
|
|
the empty string and treats `_start` as an object file.
|
|
* **The container format depends on the host `long` size.** `link.h` stores
|
|
addresses and sizes as `long`; this build writes 8-byte fields, so the
|
|
header is 156 bytes rather than the historical 80. `as34`, `ld34` and
|
|
`extract.py` all agree, but these files are not interchangeable with
|
|
32-bit-host `g.out` files. Making the format stable would mean changing
|
|
`long` to `int32_t` in `link.h`.
|
|
* **`ld34` runs `as34` from `PATH`** when generating C++ ctor/dtor tables.
|
|
`test.sh` passes `-c` to skip that.
|
|
* `as34` is **not** GSPA-compatible at the token level (see the table above).
|
|
|
|
## Licence
|
|
|
|
The upstream tarball contains GPLv2-era GNU binutils code plus Morton's own
|
|
sources. It is downloaded at build time, not vendored here; the patch is the
|
|
only derived file committed.
|