arti 8ff16b5b73 NETWORK_REPORT: machine-generated coverage -- 26 unmapped entries found and mapped
Replaces the 30-address spot check with a mechanical pass: every report address
is classified against the MMTM prologue table, so interior labels are shown to
be interior rather than asserted. 225 addresses, 82 mapped, 143 unmapped, of
which 102 fall inside a mapped function and 41 sit in 26 unmapped entries.

Maps those 26: arpresolve (if_ether.c:261) for 0x3F60FB60, ifa_ifwithnet
(if.c:189) for 0x3F623180, tcp_respond (tcp_subr.c:112) for 0x3F6BD9F0,
leerror (if_le.c:972) for 0x3F9DAFF0, the leintr TINT half for 0x3F9D8A50,
leinit/lereset for 0x3F9D27D0, the tcp timer pair for 0x3F604C30, and marks the
rest firmware-specific with the reason.

Also corrects the RX entry: the function starts at 0x3F602DB0, not 0x3F602E00.
2026-10-30 11:25:54 +02: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%