mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-10-30 12:03:54 +02:00
233 lines
9.7 KiB
Markdown
233 lines
9.7 KiB
Markdown
# 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](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.
|
||
|
||
```sh
|
||
./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:
|
||
|
||
```sh
|
||
unidasm vt1200_v22.bin -arch tms34010 -basepc 0x7E40000 -count 40
|
||
```
|
||
|
||
Or `smart34010`'s `dis34` (note `-b` is a *bit*-address base):
|
||
|
||
```sh
|
||
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:
|
||
|
||
```sh
|
||
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:
|
||
|
||
```sh
|
||
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 |
|
||
|
||
```sh
|
||
/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`](https://github.com/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
|
||
|
||
```sh
|
||
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 `ArrayIndexOutOfBoundsException`s.
|
||
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
|
||
```
|