# 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` (file `0x1BFF80`–`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 ] ``` * `h0` is a **16-bit additive checksum**: the sum of all 16-bit words from the `0xAAAA` magic word to the end of the bank, mod 2^16. Verified for **all 14 banks in both revisions** (`tools/vt1200_map.py`). * `0xAAAA5555` is a fixed format marker. * `h1` is **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 byte `0x40`–`0x100`; hundreds of `@0x1xxxx`… `@0x4xxxx` globals are referenced, so at least the first ~`0x50000` bytes are statically used. * **Board peripherals** appear around byte `0x00B00000`, `0x00C40000`, `0x00C80000` (bit `0x5800000`, `0x6200000`, `0x6400000`). POST writes `@0x62000d0/f0` and `@0x64000d0/e0/f0`; the two identical windows at `0xC40000`/`0xC80000` are 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 ```sh ./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 1. `h1` header field meaning. 2. The 28 non-reset vector entries (`0x000009C0`…): look like low-RAM handlers installed at boot, or unrelocated offsets — unresolved. 3. Exact RAM extent and the peripheral device decoding. 4. **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.py` finds and resolves those constants; the remaining step is a Ghidra script to rewrite them in place.