LDDTX region-address resolution carve (2026-07-19)¶
Full path: E:\Dev\Ronny\NDInsight\SINTRAN\ND500\LDDTX-REGION-RESOLUTION-CARVE-2026-07-19.md
Question: how do ABSWR/ABSST/ABSRE/ABSLD in segment 030-S3SM5 resolve a "region"
address (region-25 observed = MPM word-address 0x0045D800), and can an emulator's ACCP
model compute that address from data it can read out of shared MPM, without guessing?
Grade: [V] = byte-cited in the disassembly / C# source · [I] = inferred from code logic · [UNVERIFIED] = could not confirm from the material in hand.
Primary sources:
- ASM: E:\Dev\Ronny\NDInsight\tools\sintran-segment-carver\versions\L-VSX-500\re\segments-ref\030-S3SM5\030-S3SM5.asm
(ABSWR@044505, ABSST@044551, ABSRE@044613, ABSLD@044656).
- LDDTX/LDATX/STATX implementation (ground truth for the instruction):
E:\Dev\Repos\Ronny\RetroCore\Emulated.HW\ND\CPU\ND100\Instructions.MemoryReference.cs
(calcEL @284, LDATX @317, LDDTX @353, STATX @396).
1. LDDTX — exact semantics (this is NOT a descriptor-table lookup)¶
One line: LDDTX (opcode 143302) is "Load Double word, T/X-indexed" — a privileged
extended-address physical double-word read. It reads two consecutive physical-memory words
at the 24-bit address (T<<16)|(X+disp) into A and D. There is no segment:offset decoding,
no base+bounds, no page/segment descriptor interpretation. The mnemonic in the task
("Load-Descriptor-Table-indexed") is a misnomer. [V]
Cited C# ground truth (Instructions.MemoryReference.cs):
private uint calcEL(sbyte displacement) { // line 284
int EL = (regs.currentRegisters.X + displacement) & 0xFFFF; // low 16 bits: X + 3-bit disp, carry dropped
EL = (regs.currentRegisters.T & 0xFF) << 16 | EL; // high 8 bits: T selects the 64K bank
EL = EL & 0xFF_FFFF; // 24-bit physical address
return (uint)EL;
}
public void LDDTX() { // line 353
uint EL = calcEL(regs.fetched.mriDisplacement);
regs.currentRegisters.A = (ushort)ReadEL(EL); // A := physical[EL]
regs.currentRegisters.D = (ushort)ReadEL(EL + 1); // D := physical[EL+1]
}
private uint ReadEL(uint el) => (uint)cpu.ReadPhysicalMemory(el, true); // PHYSICAL, paging-independent
(X+disp)&0xFFFF | (T&0xFF)<<16;
the carry out of X+disp is dropped and not propagated into T, so T alone picks the
64K bank. For LDDTX (143302) the displacement field n = 0.
Companion ops used by the sibling routines are the same address model, different width:
- LDATX (143300, ABSLD@044701): A := physical[EL] — single-word physical load. [V]
- STATX (143304, ABSST@044575): physical[EL] := A — single-word physical store. [V]
So "resolving region-25" = a plain physical double-word read. The (A,D) it returns IS
region-25's 32-bit physical base address, because that address was previously stored into
the descriptor table as data. The "resolution" is one indirection, not a descriptor decode.
2. The descriptor table and control_block[21]¶
ABSRE (region-25), byte-cited @044625-044632:
044625 LDX ,B -56 ; X := mem[B-56] = pointer to the per-process control block (virtual)
044626 LDD ,X 21 ; A := mem[X+21], D := mem[X+22] -> (A:D) = P, a 32-bit PHYSICAL pointer
044627 LDX 25 ; X := 25 = the region index (word offset into table at P)
044630 RADD SD DX ; X := X + D = 25 + P_low (146017: src=D, dst=X, no clear) [V]
044631 RADD CLD SA DT ; T := A = P_high (146156: src=A, dst=T, CLD=clear) [V]
044632 LDDTX ; A := phys[P+25], D := phys[P+25 +1] -> (A:D) = region-25 base = 0x0045D800
146017 = 0xCC0F: dst=7(X), src=1(D), CLD=0 → X := X + D. [V]
- 146156 = 0xCC6E: dst=6(T), src=5(A), CLD=1 → T := A. [V]
Therefore the effective physical address handed to LDDTX is
EL = (P_high & 0xFF)<<16 | ((P_low + index) & 0xFFFF) = P + index (24-bit), where:
- P = control_block[21] is a 32-bit physical pointer stored as the double word at
virtual control_block[21..22] — the base of a table of region base-addresses. [V]
- index ∈ {23 (ABSLD), 24 (ABSST), 25 (ABSRE), 26 (ABSWR)} is a word offset into that
table, hard-coded per primitive (LDX 26/24/25/23 @044521/044574/044627/044672). [V]
Descriptor format: each table slot at phys[P+index] is a 32-bit (double-word)
physical byte/word address — the runtime base of that region — read big-word-first into
(A,D) (A = high 16, D = low 16). It is not base+bounds and carries no flags in the words
LDDTX consumes; the bound/length comes separately from the loop counter (mem[B+100],
mem[B-100]) that the routine adds after LDDTX. [V for "32-bit address", I for "no flags in
those 2 words"]
All four primitives are identical except (index, direction):
| primitive | entry | index | phys op after LDDTX | direction |
|---|---|---|---|---|
| ABSLD | 044656 | 23 | LDATX @044701 | single-word load ← region-23 |
| ABSST | 044551 | 24 | STATX @044575 | single-word store → region-24 |
| ABSRE | 044613 | 25 | MOVEW @044641 | block move ← region-25 |
| ABSWR | 044505 | 26 | MOVEW @044534 | block write → region-26 |
For ABSRE/ABSWR the (A,D) region base from LDDTX is combined with the running word offset
(mem[B+100]) via the RADD chain @044633-044640 (resp. @044525-044533) to form the T/A/D/L
physical operands of MOVEW (a physical block move). Same region base, per-word cursor. [V]
Note the index values (23-26) are word offsets into the P-table and are a different
numbering from the ACCP command codes (021B/022B/023B…) — see the framing correction in
DUCS-READBACK-REGION-OWNERSHIP-CARVE-2026-07-19.md §0.
3. Can the ACCP compute region-25 = 0x0045D800 from shared-MPM-readable data?¶
No — not from shared MPM alone. The resolution is gated on the ND-100 B register. [V]
The exact chain to reach 0x0045D800 is:
1. X = mem[B-56] — needs the ND-100 B register (the PLANC local-frame pointer). B is
ND-100 CPU state; it is not in shared MPM. [V]
2. P = mem[X+21 .. X+22] — the control block is in ND-100 virtual memory (LDD @044626
is an ordinary paged virtual read, not a physical one). Reaching it needs step 1 plus the
ND-100 page tables. [V]
3. region25 = phys[P+25 .. P+26] — a physical double-word read. Only this last step is a
physical access the ACCP could in principle perform, and only if it already knew P and P
pointed into a window the ACCP can see. [V]
Steps 1-2 are ND-100-private. The ACCP has no handle to the B register, to the control
block's virtual address, or to P, from anything in shared MPM. So the ACCP cannot
replicate LDDTX(control_block[21]+25). [V]
Cross-check against the conveyed data the ACCP does have:
- The LPARP (021B) pointer handed on the wire = 0x00018000 (X5OCT octobus-buffer base).
- The command param block at MPM 0x00420800 = {N, csWord, 0x00400000, 0x00018000,
0x00000000, 0x00800000, 0x00400000, 0x00018000, …}.
- None of these equals 0x0045D800, nor is 0x3D800 (= 0x45D800 − 0x00420000) derivable
from them by any add/shift I can justify. The region base is simply not present in the
shared-MPM data the ACCP receives; it lives only in the ND-100-private descriptor table at
P. [V that the value is absent / [UNVERIFIED] that no encoding exists]
Definitive statement: region-25's (and region-23/24/26's) runtime address is produced by
an ND-100-side physical indirection rooted in the B register and ND-100 virtual memory. It
cannot be computed ACCP-side from shared MPM. The emulator must therefore either
(a) observe the address when the ND-100 actually performs the MOVEW/LDATX/STATX
physical access (i.e. let the guest do the resolution and watch the physical bus), or
(b) sidestep the absolute address entirely — for the DUCS/CMRWC checksum path, compute the
16-bit sum self-consistently over whatever words the ACCP itself deposits, exactly as
recommended in DUCS-READBACK-REGION-OWNERSHIP-CARVE-2026-07-19.md §"Emulator recipe". The
checksum passes regardless of the absolute region address, so (b) needs no knowledge of
0x0045D800 at all. [V for the mechanism; I for "recipe (b) works" — logic-forced]
4. UNVERIFIED / open¶
- [UNVERIFIED] The physical location of the descriptor table
P = control_block[21]: whether it sits in ND-100 local RAM or inside a shared MPM window. If it were provably in a window the ACCP can read AND the ACCP were independently toldP, step-3 alone would let it read0x0045D800; neither precondition is met by any conveyed value observed. Needs a live dump ofcontrol_block[21]and the segment's frame to settle. - [UNVERIFIED] Whether the two words at
phys[P+index]carry any flag/length bits beyond the raw 32-bit address. The routines take length from a separate counter, so the descriptor words LDDTX reads appear to be a bare address, but the full slot layout of the P-table (and why regions are spaced one word apart at 23/24/25/26) was not carved — the table builder (SINTRAN's ND-500 memory allocator) lives elsewhere, not in030-S3SM5. - [V-adjacent]
control_block[21]here is reached only viaLDX ,B -56/LDD ,X 21, a pattern repeated at 043702, 044225, 044266, 044404, 044517, 044563, 045077, 045163, … (all in030-S3SM5.asm) — i.e.[B-56]→control block, [+21]→physical region-table baseis the standard idiom throughout this segment, not a one-off. [V]