DOM / SEG File Format (New ND-500(0) Domain Format)¶
:DOM (domain) and :SEG (free segment) are the file types produced by the
newer ND Linker (ND-211224) and consumed directly by the ND-500(0) Monitor to run a
program. They replace the old :PSEG/:DSEG/:LINK + DESCRIPTION-FILE:DESC scheme -
see DESCRIPTION-FILE-FORMAT.md for that older format and
why it needed a separate index file. CONVERT-DOMAIN (ND-500 vendor program,
CONVERT-DOM-A03.DOM) migrates old-format domains into :DOM/:SEG.
Primary source - VERIFIED, code-level ground truth, stronger than the manual alone:
src/include/nd500/dom.h in the pcc-nd500 repository - the exact #pragma pack(1)
struct layout used by dom_utils.c (libdom.a), consumed by both nd500-dis and
nd500-dump in the pcc-nd500 toolchain to load and run real .DOM files (this is the
code path behind the working HELLO.DOM compile/link/run chain documented in the
nd500-apps skill) - not just a transcription of the manual's prose.
Secondary source: ND-860289-2-EN ND Linker User Guide and Reference Manual.md
(NDInsight Reference-Manuals/), Appendix E "The New Domain Format" - the narrative
description; the header field list there is qualitative only (no byte offsets), which is
why dom.h's concrete offsets are the primary source here.
All multi-byte fields are big-endian (ND-500 native byte order).
1. Overall file layout¶
0x0000 Domain/Segment Header (4096 bytes = 2 pages of 2048; page 2 is reserved)
0x1000 Debug info
Link info
Program/Data segments (slave segments, DOM only)
Only pages actually used are allocated on disk. A :DOM file with no external links can
be copied with a plain @COPY-FILE (everything needed is inside it); a :SEG file holds
exactly one program+data segment pair, referenced by one or more :DOM files via a
link key match (see section 5).
2. File Header (16 bytes, offset 0x00 - shared by DOM and SEG)¶
| Offset | Field | Size | Meaning |
|---|---|---|---|
| 0x00 | LINKLOCK | 4 | Random lock value. A domain linked to a :SEG file records this value as its LINKKEY; they must match at load time or the segment is considered a different version. |
| 0x04 | VERSION | 1 | ND Linker version that produced this file. |
| 0x05 | REVISION | 1 | ND Linker revision. |
| 0x06 | FLAGS | 1 | Bit 3: trap block valid. Bit 4: is a :DOM file (vs :SEG). Bit 5: root/multidomain. Bit 6: SINTRAN-III domain. Bit 7: is ND-500/5000. |
| 0x07 | MACHINE | 1 | Target machine type. |
| 0x08 | OS_ID | 1 | Operating system ID. |
| 0x09 | reserved | 1 | |
| 0x0A | SUBSYSTEM_KEY | 6 |
dom_is_dom_file()/dom_is_nd500_file()/dom_is_sintran_iii() test bits 4/7/6 of the
FLAGS byte directly.
3. DOM-specific part (offset 0x10 - 0xC6)¶
| Offset | Field | Size | Meaning |
|---|---|---|---|
| 0x10 | PRIVILEGES | 8 (4x16-bit) | Domain privileges. |
| 0x18-0x25 | (padding) | 14 | |
| 0x26 | MOTHER | 8 | Domain Reference (below) to the mother domain. |
| 0x2E | CHILDREN[16] | 128 (16x8) | Domain References to up to 16 child domains. |
| 0x2E+128=0xAE .. 0xC5 | (padding) | to 0xC6 |
Domain Reference (8 bytes): MIN_INDEX(u16) + MAX_INDEX(u16) = byte range into the
name pool for this domain's name, + LINK_KEY(u32) which should match the referenced
domain's LINKLOCK.
4. Common part (offset 0xC6 - 0x108, both DOM and SEG)¶
| Offset | Field | Size | Meaning |
|---|---|---|---|
| 0xC6 | FREIND | 2 | Free byte pointer into the name pool. |
| 0xC8 | DEB_LB | 4 | Debug info lower bound (file offset). |
| 0xCC | DEB_SZ | 4 | Debug info size. |
| 0xD0 | LINK_LB | 4 | Link info lower bound. |
| 0xD4 | LINK_SZ | 4 | Link info size. |
| 0xD8 | STADDR | 4 | Start address. |
| 0xDC | RESTADDR | 4 | Restart address. |
| 0xE0 | THA | 4 | Trap Handler Address. |
| 0xE4 | MTE2 / 0xE8 MTE1 | 4+4 | Memory Trap Enable (64-bit mask, high then low word). |
| 0xEC | OTE2 / 0xF0 OTE1 | 4+4 | Own Trap Enable (64-bit mask). |
| 0xF4 | CTE2 / 0xF8 CTE1 | 4+4 | Child Trap Enable (64-bit mask). |
| 0xFC | TEMM2 / 0x100 TEMM1 | 4+4 | Trap Enable Mod Mask (64-bit mask). |
| 0x104 | PRIORITY | 4 | Process priority. |
(Common part ends at 0x108.)
5. Segment part (28 bytes) - the building block for one program OR one data segment¶
| Field | Size | Meaning when NOT linked | Meaning when ATT.LINKED_SEGMENT bit set |
|---|---|---|---|
| LB | 4 | Lower bound = file offset of segment content | Name-pool index of the linked-to segment's name |
| SZ | 4 | Size in bytes | LINKKEY to match against the target :SEG file's LINKLOCK |
| ATT | 4 | Attribute bitmask (section 6) | (same) |
| FLA | 4 | Fixed Lower Address = virtual load address | |
| FUA | 4 | Fixed Upper Address | |
| AFA | 4 | Absolute Fix Address | |
| MINP | 2 | Min pages | MIN name-pool index (if linked) |
| MAXP | 2 | Max pages | MAX name-pool index (if linked) |
A Segment Descriptor (56 bytes) = one Program Segment Part + one Data Segment Part, back to back.
6. Segment ATT (attribute) bits¶
| Bit | Name | Meaning |
|---|---|---|
| 10 | FIXED_ABSOLUTE | |
| 11 | FIXED_CONTIGUOUS | |
| 12 | FIXED_SCATTERED | |
| 13 | SEGMENT_USED | Slot contains valid data - test this before reading a slot. |
| 14 | LINKED_SEGMENT | LB/SZ (and MINP/MAXP) hold name-pool index / link key, not offset/size - see section 5. |
| 15 | ROUTINE_VECTOR | |
| 16 | INSUFF_LOADED | |
| 17 | FORTRAN_COMMON | |
| 18 | OTHER_MACHINE | |
| 19 | START_VECTOR | Start vector on this segment. |
| 20 | INDIRECT | |
| 21 | SHARED_ND100 | |
| 22 | COPY_CAPABILITY | |
| 23 | CLEAR_CAPABILITY | |
| 24 | CACHE | |
| 25 | FILE_AS_SEGMENT | |
| 26 | EMPTY_DATA | |
| 27 | SHARED_DATA | |
| 28 | PROGRAM_SEGMENT | |
| 29 | SWAP_ON_SWAPFILE | |
| 30 | PARAMETER_ACCESS | |
| 31 | WRITE_PERMIT |
7. DOM header - full layout (4096 bytes)¶
| Offset | Field | Size |
|---|---|---|
| 0x000 | File Header | 16 |
| 0x010 | DOM-specific part | to 0xC6 |
| 0x0C6 | Common part | to 0x108 |
| 0x108 | Indirect segments[32] | 32 x 10 = 320, to 0x248 |
| 0x248 | LANGUAGE_MSAL | 4 |
| 0x24C | IDX_FREE_MIN/MAX | 2+2 |
| 0x250-0x253 | (padding) | 4 |
| 0x254 | Segment table: 32 x Segment Descriptor (56 bytes each) | 1792, to 0x954 |
| 0x954 | Name pool | to 0x1000 |
Indirect Segment (10 bytes): MIN_INDEX(u16) + MAX_INDEX(u16) + LINK_KEY(u32) + SLOG(u8, logical segment number) + reserved(u8).
To read segment N's descriptor: header + 0x254 + N*56 (N = 0..31). Program part first
(28 bytes), then data part (28 bytes). Check ATT.SEGMENT_USED before trusting the slot.
8. SEG header - full layout (4096 bytes)¶
A :SEG file holds exactly one segment pair (no domain-level bookkeeping - mother/child,
segment table, language mask):
| Offset | Field | Size |
|---|---|---|
| 0x000 | File Header | 16 |
| 0x010-0x013 | (padding) | 4 |
| 0x014 | Program Segment Part | 28, to 0x030 |
| 0x030 | Data Segment Part | 28, to 0x04C |
| 0x04C-0x06F | (padding) | to 0x070 |
| 0x070 | PROG_LOGSEG | 1 |
| 0x071 | DATA_LOGSEG | 1 |
| 0x072 | N100_COUNT | 2 |
| 0x074 | N100 RT segments[10] | 10 x 12 = 120, to 0xEC |
| 0xEC-0xC5 | (pad to Common part) | |
| 0x0C6 | Common part | to 0x108 |
| 0x108 | Indirect segments[32] | 320, to 0x1C8 |
| 0x1C8 | LANGUAGE_MSAL | 4 |
| 0x1CC | IDX_MIN/MAX (ID message) | 2+2 |
| 0x1D0-0x1D3 | reserved | 4 |
| 0x1D4 | Linked segments[32] | 32 x 16 = 512, to 0x3D4 |
| ... | Name pool | to 0x1000 |
ND-100 RT Segment (12 bytes): N100SW[6] (name) + N100SNO(u16) + N500LOGPA(u16, map address in ND-500 logical memory, pages) + N100SIZE(u16, pages).
Linked Segment (16 bytes, SEG files only): PROG_MIN/MAX(u16 each) + PROG_KEY(u32) + DATA_MIN/MAX(u16 each) + DATA_KEY(u32).
9. Name pool¶
A byte pool at the end of the header (0x954..0x1000 for DOM, 0x454..0x1000 for SEG).
A name is pool[min_index .. max_index). min_index==0 || max_index==0 || min_index>=max_index
means "no name."
10. Open items¶
- FLAGS byte (offset 0x06) is now confirmed against a real, freshly-produced
.DOM:CONVERT-DOM-A03convertingLINKAGE-LOAD-H02(2026-08-10, see../ND500-APPS/CONVERT-DOM-A03/userguide.md) wrote0xF8= bits 3/4/5/6/7 set = TRAPBLOCK_VALID + IS_DOMAIN_FILE + IS_ROOT_DOMAIN + IS_SINTRAN_III + IS_ND500, exactly matching this doc's bit table. - The rest of the segment table, name pool, and common part have no field-by-field
validation report against a real
.DOMbeyond what the workingnd500-dis/nd500-dump/nd500x runtime already exercises implicitly (they run real DOMs successfully, which is strong indirect validation, but no dedicated byte-level walkthrough doc exists yet). DOM_COMMON_OFFSET/DOM_STADDR_OFFSETmacro names indom.h(0xC6, 0xD8) match this doc's Common Part table exactly - kept in sync intentionally; ifdom.hchanges, update this doc too.