original-bsd spans 1979..4.4BSD-Lite2 and carries the same if_ether.c string as the ROM. Its pmax (DECstation) if_le.c clears IDON before STRT, Linux does too, but NetBSD's lance.c does not -- and neither does the VT1200 firmware itself (0x3FDDCBE0 writes CSR1/2/3 then 0x7F41 and the live path goes INIT -> poll IDON -> 0x0042 with no IDON clear). Since the firmware works on the real machine, the IDON hypothesis is dead and the descriptor length encoding (section 50) is the remaining explanation.
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):
- Index page: https://9track.net/roms/ (section "DEC VT1200", category Terminal)
- Files: https://9track.net/roms/files/dec/vt1200/
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 sourcetools/ghidra-tms34010-local.patch— all local changes vs. upstreamtools/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:
- Ghidra 12 schema fixes —
<data_space space="ROM">must be lowercaserom(matching the slaspec), and every<memory_block>needsinitialized="false"or a bit/byte-mapped address. - Removes the Midway arcade content — upstream shipped a Midway board map
(
VRAM/RAM/NVRAM/PALETTE/GFX/ROMblocks plusWATCHDOG,DIPSWITCHES,INPUT_n,midtunit_*and arom:0xFFFFCtrap table) that does not describe the VT1200 and whoseGFX/ROMblocks collided with the loaded image. The cleanedpspeckeeps 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