SDD 1608a68cdb hello-world: the TMS34010 SDK assembles code that runs on the emulated VT1200
An 82-byte payload written in GSPA assembly, linked at bit 01800000h and
loaded into main RAM by harness/mame/hello.lua, executes on the CPU: it
writes DEAD/BEEF and a 1024-iteration counter into RAM and fills a 256x64
block in video RAM, which appears in the frame dump at x 256..511,
y 136..199.  Entry is a debugger breakpoint on the level-0 menu idle loop,
not a delivery mechanism.  Includes the build script, a COFF .text
extractor (gsprom's hex addresses wrap at 64 KB), the run log, RAM excerpt,
frame crops including a no-load control, and HELLO_WORLD_REPORT.md.
2026-10-18 01:20:38 +03:00

DEC VT1200 X Terminal — ROM images

The DEC VT1200 is a monochrome X Window System (X11) terminal (circa 1990). It runs the X server, terminal manager, window manager, and VT emulator entirely from ROM on a Texas Instruments TMS34010 CPU, with 2–4 MB of RAM and no virtual memory.

These are the firmware ROM dumps, split by firmware revision. The confirmed memory map is in MEMORY_MAP.md.

Contents

Folder Firmware ROMs Part numbers
v2.1/ V2.1 14 x 128 KiB 23-210E9 .. 23-223E9
v2.2/ V2.2 14 x 128 KiB 23-274E9 .. 23-287E9

Each file is 131072 bytes (128 KiB) and is named by its DEC part number.

Source

Dumped and published by 9track.net (Dave/9track collection):

Fetched: 2026-10-15.

Notes

  • The bitsavers terminal document archive does not currently host VT1200 ROM images (checked /bits/ and /pdf/dec/terminal/), so 9track.net is the canonical source for these dumps.
  • The 9track table does not list the component/location for each ROM; only the part-number-labeled filenames are given.
  • Verify integrity with sha256sum v2.1/* v2.2/*.

Firmware layout (reverse-engineered)

The 14 EPROMs are byte-interleaved 16-bit words, not a flat byte stream. Within each consecutive pair of part numbers, the odd part number holds the low byte and the even part number holds the high byte:

v2.1 pairs: (210,211) (212,213) (214,215) (216,217) (218,219) (220,221) (222,223)
v2.2 pairs: (274,275) (276,277) (278,279) (280,281) (282,283) (284,285) (286,287)

The seven 256 KiB banks are laid out so that file offset == physical byte - 0x07E40000: the highest part-number pair sits at the lowest address. reconstruct.py writes that 1.75 MiB (0x1C0000) image by default; pass --part-order for the legacy ascending-part-number ordering.

./reconstruct.py v2.1        # -> vt1200_v21.bin  (address order)
./reconstruct.py v2.2        # -> vt1200_v22.bin
python3 -m unittest test_reconstruct -v      # layout regression tests

Evidence this interleave is correct: only it produces readable text, e.g. -DEC-Terminal-Medium-R-Normal--14-100-100-100-C-80-ISO8859-1, WM XIO Error, packet_size = %d exceeds MAXSIZE_RCVPKT, and SCCS headers such as $Header: ctype.c,v 1.1 89/10/05 19:40:49 craig Exp $. Getting the interleave wrong shifts every string by one byte (e.g. DEC becomes EDC).

Disassembly

The CPU is a TI TMS34010. The ROM is loaded at physical byte base 0x07E40000 (bit 0x3F200000); the reset vector (0x3F200040) points at the power-on code at ROM+8 (DINT; SETF 16,0,0; SETF 0,0,1; CLR A0; …). Each 256 KiB bank begins with an 8-byte header [checksum16][?][AAAA][5555].

MAME's bundled disassembler, which ships a tms34010 backend:

unidasm vt1200_v22.bin -arch tms34010 -basepc 0x7E40000 -count 40

Or smart34010's dis34 (note -b is a bit-address base):

dis34 -a -l -b 3F200000 vt1200_v21.bin

unidasm/dis34 print bit addresses (0x10 per 16-bit instruction), whereas Ghidra uses byte addresses. tools/vt1200_map.py prints the vectors and verifies the per-bank header checksums:

python3 tools/vt1200_map.py vt1200_v22.bin

Pointer constants (bit-address → byte-address)

The firmware stores bit addresses; a 32-bit value P refers to physical byte P >> 3. A byte-addressed tool such as Ghidra cannot resolve those constants directly. tools/ptr_constants.py scans an address-ordered image for such constants and resolves their targets:

python3 tools/ptr_constants.py vt1200_v22.bin
python3 tools/ptr_constants.py vt1200_v22.bin --strings
python3 tools/ptr_constants.py vt1200_v22.bin --tsv pointers.tsv
python3 -m unittest test_ptr_constants -v

On v2.2 it finds ~44,700 constants, of which ~3,680 distinct targets are strings (e.g. 0x004B08 <- 0x3F225840 'LAT: could not allocate XCB for …').

The Ghidra side is implemented in ghidra_scripts/FixPtrConstants.java: it scans the loaded ROM and adds a DATA reference from each constant to the byte it points at (P >> 3), leaving the bytes untouched. AssertPtrFix.java is a headless regression check for it. Already applied to the project:

Program references created
vt1200_v21.bin 37,187
vt1200_v22.bin 40,290
/opt/ghidra/support/analyzeHeadless ghidra vt1200 \
    -process -noanalysis \
    -scriptPath ghidra_scripts \
    -postScript FixPtrConstants.java

Ghidra

Ghidra has no built-in TMS34010 language, so we install the community module ZPaul2Fresh8/Ghidra_TMS34010:

  • tools/ghidra-tms34010/ — vendored, patched module source
  • tools/ghidra-tms34010-local.patch — all local changes vs. upstream
  • tools/install-ghidra-plugin.sh — installs + compiles it into Ghidra
tools/install-ghidra-plugin.sh          # needs sudo; installs into /opt/ghidra

The patch does two things:

  1. Ghidra 12 schema fixes — <data_space space="ROM"> must be lowercase rom (matching the slaspec), and every <memory_block> needs initialized="false" or a bit/byte-mapped address.
  2. Removes the Midway arcade content — upstream shipped a Midway board map (VRAM/RAM/NVRAM/PALETTE/GFX/ROM blocks plus WATCHDOG, DIPSWITCHES, INPUT_n, midtunit_* and a rom:0xFFFFC trap table) that does not describe the VT1200 and whose GFX/ROM blocks collided with the loaded image. The cleaned pspec keeps only the CPU definition.

Project

ghidra/ is a ready-to-open Ghidra project (ghidra/vt1200.gpr) containing the reconstructed v2.1 and v2.2 images, imported with tms34010:LE:32:default at byte base 0x07E40000 and disassembled from the reset vector plus a linear pass over the boot bank.

Program Functions Instructions
vt1200_v21.bin 8 61,401
vt1200_v22.bin 6 62,444

Helper scripts live in ghidra_scripts/:

  • VerifyTMS34010.java — locates the loaded block, follows flow from the reset vector, then linearly disassembles the boot bank, and prints regions.
  • StatsTMS34010.java — function/instruction counts.
  • FixPtrConstants.java — converts bit-address pointer constants to references.
  • AssertPtrFix.java — headless regression check for the above.

Caveats:

  • currentProgram.getImageBase() is not the ROM base. Use the loaded block (rom:07e40000–rom:07ffffff); the helper script does this.
  • The module's pcode semantics are incomplete, so flow-following cannot expand far and the analyzers emit non-fatal ArrayIndexOutOfBoundsExceptions. That is why the boot bank is also disassembled linearly.
  • Ghidra 12 dropped Jython; its bundled Python scripts need PyGhidra, so the helpers here are Java.
  • Data cross-references are materialised by FixPtrConstants.java (the bit vs byte address issue) — see the pointer-constants section above.

Documentation

docs/ holds the free DEC/TI documents gathered during this work. Each PDF has a .txt sidecar with the extracted text (handy for grep).

File Source
EK-V1000-SV-002_service-guide.pdf filibeto.org/dec/hardware/EK-V1000-SV-002.pdf
EK-V1000-UG-002_installing-VT1000.pdf filibeto.org/dec/hardware/EK-V1000-UG-002.pdf
EK-V1200-UG-001_installing-VT1200.pdf filibeto.org/dec/hardware/EK-V1200-UG-001.pdf
EK-V1000-RN-005_VT1000-v2.0-release-notes.pdf filibeto.org/dec/hardware/EK-V1000-RN-005.pdf
EK-V1200-RN-001_VT1200-release-notes.pdf filibeto.org/dec/hardware/EK-V1200-RN-001.pdf
EK-V1000-RC-003_installing-optional-memory.pdf filibeto.org/dec/hardware/EK-V1000-RC-003.pdf
EK-V120I-IN-001_installing-DECimage-1200.pdf filibeto.org/dec/hardware/EK-V120I-IN-001.pdf
EK-V1000-IP-001_illustrated-parts-breakdown.pdf filibeto.org/dec/hardware/EK-V1000-IP-001.pdf
DTJ-1991-vol3num4_X-Window-Terminals.pdf Digital Technical Journal 3(4), Fall 1991, pp. 26–35
TMS34010-users-guide.pdf TI TMS34010 User's Guide
ipb_pages/*.png page renders of the IPB (that scan has no text layer)

reference/ holds the VT1000 v1.2 ROM dump (12 × 27C010) published by bitsavers (bitsavers.org/pdf/dec/terminal/vt1000/VT1000-v1.2.zip) plus an earlier linear dis34 disassembly of v2.1 (gzipped).

Notably no online document contains the memory map — the missing artifact is the MP-02989-01 VT1000/VT1200 System Box Maintenance Print Set (fold-out schematics). See MEMORY_MAP.md.

Repository layout

vt1200/
├── v2.1/  v2.2/                 # original 28 EPROM dumps
├── reconstruct.py               # de-interleave a revision -> address-ordered image
├── test_reconstruct.py
├── MEMORY_MAP.md                # the confirmed memory map
├── README.md
├── vt1200_v21.bin  vt1200_v22.bin
├── docs/                        # DEC/TI manuals (PDF + extracted .txt) + ipb_pages/
├── reference/                   # VT1000 v1.2 ROM dump, earlier dis34 output
├── ghidra/                      # Ghidra project (vt1200.gpr + .rep)
├── ghidra_scripts/              # Verify/Stats/FixPtrConstants/AssertPtrFix .java
├── tools/
│   ├── vt1200_map.py            # vectors + bank-header checksums
│   ├── ptr_constants.py         # find/resolve bit-address constants
│   ├── smart34010/              # dis34 disassembler source
│   ├── ghidra-tms34010/         # patched processor module source
│   ├── ghidra-tms34010-local.patch
│   └── install-ghidra-plugin.sh
└── test_ptr_constants.py
Languages
C 23.7%
Python 19.7%
Lua 12.2%
C++ 11.9%
Shell 9.8%
Other 22.6%