6.2 KiB
VT1200 memory map
Derived statically from the firmware ROM images (v2.1 and v2.2) and independently re-verified. Confidence is called out per section.
The CPU is a Texas Instruments TMS34010. It is a bit-addressed machine:
a 32-bit logical address selects a bit; the top two logical address bits are
not emitted, so the external physical space is 128 MiB and
physical_bit == logical_bit & 0x3FFFFFFF. The firmware stores absolute
bit addresses, so a stored pointer P refers to physical byte P >> 3.
ROM — confidence: HIGH
| Property | Value |
|---|---|
| Size | 1,835,008 bytes (0x1C0000, 1.75 MiB) |
| Physical byte range | 0x07E40000 – 0x07FFFFFF |
| Bit range | 0x3F200000 – 0x3FFFFFFF |
| Placement | top-aligned in the 128 MiB space |
Evidence: 1000+ absolute string pointers in the image satisfy
(P >> 3) - string_offset == 0x07E40000; e.g. "Messages re-xmt'ed" at
offset 0xC2DDB is referenced by the 32-bit value 0x3F816ED8
(0x3F816ED8 >> 3 == 0x07F02DDB == 0x07E40000 + 0xC2DDB).
Bank order — confidence: HIGH
The seven 256 KiB banks are laid out in reverse part-number order: the
highest-numbered EPROM pair sits at the lowest address. In the address-ordered
image (reconstruct.py, default) file offset == physical byte - 0x07E40000.
k |
v2.1 pair | v2.2 pair | file offset | physical byte | bit base |
|---|---|---|---|---|---|
| 0 | 23-222E9 / 223E9 | 23-286E9 / 287E9 | 0x000000 |
0x07E40000 |
0x3F200000 |
| 1 | 23-220E9 / 221E9 | 23-284E9 / 285E9 | 0x040000 |
0x07E80000 |
0x3F400000 |
| 2 | 23-218E9 / 219E9 | 23-282E9 / 283E9 | 0x080000 |
0x07EC0000 |
0x3F600000 |
| 3 | 23-216E9 / 217E9 | 23-280E9 / 281E9 | 0x0C0000 |
0x07F00000 |
0x3F800000 |
| 4 | 23-214E9 / 215E9 | 23-278E9 / 279E9 | 0x100000 |
0x07F40000 |
0x3FA00000 |
| 5 | 23-212E9 / 213E9 | 23-276E9 / 277E9 | 0x140000 |
0x07F80000 |
0x3FC00000 |
| 6 | 23-210E9 / 211E9 | 23-274E9 / 275E9 | 0x180000 |
0x07FC0000 |
0x3FE00000 |
Conversion, for a part-number-ordered image (e.g. a raw reconstruct.py --part-order file):
physical_byte(F) = 0x07E40000 + (6 - (F >> 18)) * 0x40000 + (F & 0x3FFFF)
Reset / interrupt vector page — confidence: HIGH
The vector page occupies the last 128 bytes of the ROM.
- Physical byte
0x07FFFF80–0x07FFFFFF(file0x1BFF80–0x1C0000) - Logical bit
0xFFFFFC00–0xFFFFFFFF - 32 entries, one 32-bit bit-address each; entry 31 (
0xFFFFFFE0) is reset
| entry | value | target |
|---|---|---|
| 31 (RESET) | 0x3F200040 |
0x07E40008 — power-on code (60 03 50 05 40 07 00 56 …) |
| 1 | 0x3F207C40 |
0x07E40F88 |
| 22, 23 | 0x3F207CC0, 0x3F207D00 |
0x07E40F98, 0x07E40FA0 |
| 0, 2–21, 24–30 | 0x000009C0 … 0x00000F60 |
unresolved (see Open items) |
The reset vector is identical in v2.1 and v2.2, and points at byte-identical POST code.
Bank header — confidence: HIGH (checksum), LOW (h1)
Every 256 KiB bank begins with an 8-byte header of four big-endian-friendly 16-bit little-endian words:
[ h0 ][ h1 ][ 0xAAAA ][ 0x5555 ]
h0is a 16-bit additive checksum: the sum of all 16-bit words from the0xAAAAmagic word to the end of the bank, mod 2^16. Verified for all 14 banks in both revisions (tools/vt1200_map.py).0xAAAA5555is a fixed format marker.h1is unidentified (not CRC32-low16, CRC-16/CCITT, XOR or byte sum). It is per-bank and differs between revisions — possibly a build/part id.
The header is not a load address or length field.
CPU on-chip registers — confidence: HIGH (datasheet)
The TMS34010's own I/O registers live in logical bit space
0xC0000000–0xC00001FF, register n at 0xC0000000 + 0x10*n. Observed in
the firmware:
CONTROL 0xC00000B0 DPYCTL 0xC0000080
HSTCTLH 0xC0000100 INTENB 0xC0000110
INTPEND 0xC0000120 CONVSP 0xC0000130
CONVDP 0xC0000140 HSBLNK 0xC0000150
RAM and board peripherals — confidence: MEDIUM (RAM) / LOW (peripherals)
- RAM begins at
0x0000000. 1 MB on the system-logic board plus up to 3× 1 MB SIMMs (service guide). POST clears words from address 0; interrupt handlers save registers at byte0x40–0x100; hundreds of@0x1xxxx…@0x4xxxxglobals are referenced, so at least the first ~0x50000bytes are statically used. - Board peripherals appear around byte
0x00B00000,0x00C40000,0x00C80000(bit0x5800000,0x6200000,0x6400000). POST writes@0x62000d0/f0and@0x64000d0/e0/f0; the two identical windows at0xC40000/0xC80000are presumed to be the two DUARTs. Device decoding not confirmed.
Interrupt sources (service guide): Display, Host Interface, Interrupt 1, Interrupt 2, NMI, Trap, Window Violation; plus LANCE Ethernet, DUART (2 ch + 2 timers), video clock.
v2.1 vs v2.2 — confidence: HIGH
Same load base, same bank order, same vector page, same header format, and the
boot bank (286/287) is byte-identical (reset target 0x07E40008). The
main X-server banks were relinked: ~90 % of bytes differ overall (bank 0 ≈50 %,
banks 1–6 ≈93–97 %). So v2.2 is not a small patch to v2.1.
Reproduce
./reconstruct.py v2.2 # address-ordered image (default)
python3 tools/vt1200_map.py vt1200_v22.bin # vectors + header checksums
# disassemble the power-on / exception bank (address 0, bit base 0x3F200000):
unidasm vt1200_v22.bin -arch tms34010 -basepc 0 -count 40
python3 -m unittest test_reconstruct -v # layout regression tests
Load the image in an emulator/disassembler at byte base 0x07E40000.
Open items
h1header field meaning.- The 28 non-reset vector entries (
0x000009C0…): look like low-RAM handlers installed at boot, or unrelocated offsets — unresolved. - Exact RAM extent and the peripheral device decoding.
- Address model mismatch: the firmware stores bit addresses, but the
Ghidra TMS34010 module models byte addresses (instructions step by 2). A
pointer constant must be divided by 8 to resolve in Ghidra.
tools/ptr_constants.pyfinds and resolves those constants; the remaining step is a Ghidra script to rewrite them in place.