ND-5000 B30 Microcode: Process-Start CPU / MMU / Address Setup Carve¶
Full path: E:\Dev\Ronny\NDInsight\SINTRAN\ND500\SWAPPER-START-CPU-MMU-SETUP-CARVE-2026-07-21.md
Question answered: when a process (the swapper = process 0, or any process) is started via the octobus mailbox (MICFU 23B/25B 3START, or 22B start-process-0), how does the microcode set up the CPU registers, the MMU, and the code/data addresses?
Ground truth: E:\Dev\Ronny\ND5000UC\microcode\MICRO-5800-B30.md (lossless disassembly,
one 128-bit microword per row, B-series ND-5800/SAMSON image). Companion carve:
E:\Dev\Ronny\ND5000UC\microcode\MAILBOX-MICROCODE-PSEUDOCODE.md. Where the two disagree, the
microword listing wins.
Evidence tags (strict)¶
| Tag | Meaning |
|---|---|
| [V] | VERIFIED directly in the microword listing (operand / destination / jump target explicit). |
| [INFERRED] | Reasoned from verified data flow plus a documented rule; NOT proven by the bytes alone. |
| UNVERIFIED | Could not establish from this listing. Do not build on it. |
Address-arithmetic decode rules used (from PSEUDOCODE.md section 3.10, calibrated on known
offsets): a memory op (RD,POF/WR,POF) on microword N uses the address computed by the
ADACT on microword N-1; AA=2=DISP(=DPA), AA=7=EA3 running pointer; ORCON=byte
displacement; units are BYTES (halfword offset = byte/2); EA3SAVE latches EA3 := the address.
SUMMARY: the start -> context -> MMU -> execute flow¶
MSG_START (015671, MICFU 23B/25B)
-> CPU_AVAIL? gate (015671-673) [V]
-> MSG_START1 (015674): call NEWCNTXT [V]
NEWCNTXT (014660): SC12 := SRF11 (process #) [V]
if switching process -> CNTXTSAVE old, then CNTXTLOAD new
CNTXTLOAD (014742): ctx = 0o4000 + 0o400*proc BYTES [V]
restore P, L, descriptor regs, X1-X4, A1-A4, E1-E4, status, MOD
load per-process MMU: MM,PS / MM,PHS (segment),
MM,DOM / MM,ADOM (domain) [V]
-> EXECUTE (014636): arm traps, SET_RUNNING, enable I-cache,
resume MACRO execution at the restored P [V]
One-line answer to the core MMU question: the page/segment-table pointers MM,PSTP /
MM,PUWP are written ONLY with small CONSTANTS at CPU cold init (INIT_SAM and the macro-start
init), never per-process and never derived from the DMA'd image address. Per-process address
translation is switched entirely by loading the DOMAIN registers (MM,DOM / MM,ADOM) and
SEGMENT registers (MM,PS / MM,PHS) from the context block. [V]
Deliverable 1: Context-block layout¶
1.1 Base-address formula [V]¶
The prompt hypothesis ctx = 0o4000 + 0o400*idx BYTES is CONFIRMED, with idx = SRF11
(the current-process number), NOT X5CPU+1:
| uWord | Field decode | Meaning |
|---|---|---|
014660 NEWCNTXT |
ALU,A A,SRF11 D,SC12 |
SC12 := SRF11 (process number) [V] |
014742-014745 CNTXTLOAD |
4x ALU,A+B,*2 A,SC12 B,SC12 D,SC12 |
SC12 := ((((p2)2)2)2)... each A+B,*2=(SC12+SC12)2=4SC12; 4 words = 4^4 = 256 -> SC12 := 256*proc [V] |
000020 OFFSET |
ALU,A A,LARG LARG=00000004000 D,SC13 T,RETURN |
SC13 := 0o4000 constant [V] |
014747 |
ALU,A+B A,SC12 B,SC13 D,DAC,DPA |
DPA := SC12 + SC13 = 0o4000 + 256*proc BYTES [V] |
CNTXTSAVE uses the identical computation (014666-014671 4x A+B,*2; 014672 calls OFFSET;
014673 DPA := SC12+SC13) [V]. So the block base is symmetric for save and load.
Note 0o400 octal = 256 decimal; the block stride is 256 BYTES = 128 halfwords = 64 words per
process. [V]
Correction to the mailbox-track prior: the mailbox idx = X5CPU+1 formula is for the per-CPU
MAILINK extension block in shared memory (poll/#CPUDF), a DIFFERENT structure. The per-process
CONTEXT block is indexed by SRF11 (process number) and lives at 0o4000 + 0o400*proc in
ND-500-local memory reached via D,DAC,DPA. [V distinction]
GET_CNTXT is a different structure [V]: GET_CNTXT (013370-013372) does only TWO
A+B,*2 doublings (=*16) then T,RETURN via OFFSET. Stride 16 bytes, used by the TRAP path
(TRAP_FIND 013152), NOT by process start. Do not confuse it with the 256-byte register
context block. [V]
1.2 Context-block offset -> CPU state (BYTE offsets from block base)¶
Verified from CNTXTLOAD reads (014750-015000) and CNTXTSAVE writes (014701-014721);
both agree on every slot.
| Byte off | Halfword off | CPU state | SAVE uWord | LOAD uWord |
|---|---|---|---|---|
| 0x00 | 0 | P (program counter = code entry) | 014702 WR SC3 (SC3:=IAC,P @014677) |
014751 RD->SC3; 014757 IAC,P := SC3 [V] |
| 0x04 | 2 | L (link/return register) | 014703 WR SC4 (SC4:=IAC,L @014700) |
014752 RD->SC4; 014760 IAC,L := SC4 [V] |
| 0x08 | 4 | descriptor B (DAC,B) |
014704 WR SC5 (SC5:=DAC,B @014674) |
014753 RD->SC5; 014755 SC5->DAC,REG04 [V dest; name INFERRED] |
| 0x0C | 6 | restart/transfer descriptor (DAC,XFER/LDRES) |
014705 WR SC6 (SC6:=DAC,XFER @014675) |
014754 RD->SC6; 014756 SC6->DAC,LDRES [V dest; name INFERRED] |
| 0x10 | 010 | X1 | 014706 WR X1 |
014762 RD->X1 [V] |
| 0x14 | 012 | X2 | 014707 WR X2 |
014763 RD->X2 [V] |
| 0x18 | 014 | X3 | 014710 WR X3 |
014764 RD->X3 [V] |
| 0x1C | 016 | X4 | 014711 WR X4 |
014765 RD->X4 [V] |
| 0x20 | 020 | A1 (address/base reg) | 014712 WR A1 |
014766 RD->A1 [V] |
| 0x24 | 022 | A2 | 014713 WR A2 |
014767 RD->A2 [V] |
| 0x28 | 024 | A3 | 014714 WR A3 |
014770 RD->A3 [V] |
| 0x2C | 026 | A4 | 014715 WR A4 |
014771 RD->A4 [V] |
| 0x30 | 030 | E1 | 014716 WR E1 |
014772 RD->E1 [V] |
| 0x34 | 032 | E2 | 014717 WR E2 |
014773 RD->E2 [V] |
| 0x38 | 034 | E3 | 014720 WR E3 |
014774 RD->E3 [V] |
| 0x3C | 036 | E4 | 014721 WR E4 (IX*2) |
014775 RD->E4 [V] |
| 0x40 region | 040+ | status word(s) + domain bytes + MOD (second 32-word IX*2 block) | 014722+ (READST/status) |
014776-015000 RD->SC3/SC4/SC5 [V regs; exact offsets INFERRED due to IX*2 scaling] |
The registers are the ND-500 macro register file: X1-X4 (index registers), A1-A4 (address / base registers), E1-E4 (extended registers). "General registers R1..Rn" in the prompt = these X/A/E banks. [V that these 12 registers + P + L + 2 descriptor cells are saved/restored]
1.3 The second (status/domain/MOD) sub-block [V regs, INFERRED offsets]¶
After E4, CNTXTLOAD reads three more words (IX*2 scaled) and dispatches them:
| uWord | Action |
|---|---|
014776 RD -> SC3 |
first status/domain word from ctx [V read] |
014777 RD -> SC4 |
second [V] |
015000 RD -> SC5 |
third [V] |
015001 SC3 -> WRITEST1 |
reconstruct ALU/MIC/IDU status registers from SC3 (015030-015035) [V] |
015004 SC13 := SC3; call NEW_PS_1 |
load program segment (see Deliverable 3) [V] |
015005 SPEC,MOD := SC12 |
restore the MODUS register [V] |
015011 SC13 := SC3 (byte); call NEW_CED |
current domain (see Deliverable 3) [V] |
015012 SC13 := SC4 (byte); call NEW_CAD |
alternative domain [V] |
The exact byte offset that supplies the domain vs the status bits is IX*2-scaled and not cleanly readable per word; the register DESTINATIONS are [V], the ctx byte offsets in this sub-block are [INFERRED].
Deliverable 2: CPU register setup at start (EXECUTE and the load path)¶
The load itself is done by CNTXTLOAD (Deliverable 1). EXECUTE (014636) then begins running:
| uWord | Field decode | Effect |
|---|---|---|
014636 EXECUTE |
ALU,FZRO AAP1,CLEAR D,IXC; call TRAP_ARM1 |
clear index-cache pointer, arm traps [V] |
014637 |
AAP2,CLEAR; call SET_RUNNING |
mark CPU running (srf run-state flag) [V] |
014640-014642 |
build IDU status mask from SRF10 | pending-trap merge [V] |
014645 EXECUTE_1 |
ISAMP; ... ADR_MOD |
sample / MOD address setup [V] |
014646-014647 |
SC5 := RF2; SC4 := SPEC,MOD |
stage MOD [V] |
014650 |
ALU,A SLOW2 A,IAC,P ... LOADLA |
load look-ahead from P = begin instruction fetch at the restored P [V] |
014651 / 014656 |
call ENA_IC (014656 ENA_IC: MOD |= BM26) |
enable instruction cache and resume MACRO execution [V] |
Program counter (P = code entry): comes from context-block offset 0x00
(014757 IAC,P := SC3, SC3 = mem[ctx+0]). EXECUTE resumes fetch at that P
(014650/014654 A,IAC,P ... LOADLA). [V]
Link register L: context-block offset 0x04 (014760 IAC,L := SC4). [V]
Data base: the ND-500 has no single "data base" register; data addressing uses the
A1-A4 address registers, restored from context-block offsets 0x20-0x2C
(014766-014771). Which segment/domain those logical addresses map through is set by the
MMU domain/segment registers (Deliverable 3). [V registers; "A-registers are the data base"
is standard ND-500 architecture, INFERRED from register naming]
Not from an SRF cell, not computed: every architectural register at start comes from the per-process CONTEXT BLOCK in ND-500-local memory, read word-by-word by CNTXTLOAD. The only SRF involvement is SRF11 (process number, selects the block) and SRF13/14/15/17 (scratch and saved domain shadow). [V]
Deliverable 3: MMU setup (THE core question)¶
3.1 Every WRITE to a page/segment-table pointer in the whole image [V, exhaustive grep]¶
D,MM,PSTP, D,MM,PUWP, D,DMM,PSTP, D,DMM,PUWP, D,IMM,PSTP, D,IMM,PUWP:
| uWord | Write | Source | Context |
|---|---|---|---|
014572 INIT_SAM_3 |
D,MM,PUWP |
A,SC3 |
CPU cold init (INIT_SAM chain) [V] |
014573 |
D,MM,PSTP |
A,SC13 |
CPU cold init [V] |
017731 |
D,MM,PSTP |
A,BM00 via ALU,FZRO = 0 |
macro-start / SIM_EXEC init [V] |
017732 |
D,MM,PUWP |
A,BM02 = 4 |
macro-start / SIM_EXEC init [V] |
There are NO writes anywhere to DMM,PSTP, DMM,PUWP, IMM,PSTP, or IMM,PUWP by those
names. [V - exhaustive]
The 017534-017557 block that mentions A,DMM,PSTP / A,IMM,PSTP etc. is the LOOK_SRF
debug-read path (... D,SC1 -> LOOK_HW_WRITE): those registers are READ (as ALU A source)
to display them, never written there. [V]
3.2 What PSTP/PUWP actually receive [V writes; values partly traced]¶
- INIT_SAM_3:
MM,PUWP := SC3,MM,PSTP := SC13. Just upstream,PSTBASE(000021) loadsSC13 := 2constant (LARG=00000000002), andSC3 := SC13at014564. The exact SC3/SC13 values at014572depend on the conditional path through014564-014571; both derive from small constants (PSTBASE=2, OFFSET=0o4000), NOT from any image address. [V that the sources are constant-fed; exact final value INFERRED / path-dependent] - Macro-start init:
MM,PSTP := 0,MM,PUWP := 4(BM02). Small constants. [V]
Decisive fact: PSTP/PUWP are loaded with SMALL CONSTANTS (0, 2, 4, 0o4000-class), so they are configuration/base values into a FIXED system table region, not physical byte addresses computed from where the swapper image was DMA'd. [V]
3.3 What DOES change per process: the DOMAIN and SEGMENT registers [V]¶
CNTXTLOAD loads these from the context block via three helper routines:
| Helper | uWord | Write | Meaning |
|---|---|---|---|
| NEW_PS_1 | 015043 |
MM,PS := SC13 (halfword) |
program segment [V] |
| NEW_PS_1 | 015044 |
MM,PHS := SC13 (halfword) |
physical segment [V] |
| NEW_CED | 015053-015054 |
SRF14 := SC13; MM,DOM := SC13 (byte) |
current execution domain [V] |
| NEW_CAD | 015055-015056 |
SRF15 := SC13; MM,ADOM := SC13 (byte) |
alternative domain [V] |
The caller sequence inside CNTXTLOAD: 015004 SC13:=SC3; call NEW_PS_1 (segment),
015011 SC13:=SC3(byte); call NEW_CED (current domain), 015012 SC13:=SC4(byte); call NEW_CAD
(alt domain). SRF14/SRF15 keep a software shadow of the two domain bytes. [V]
3.4 The MMU model this proves¶
- The ND-5000 MMU is domain + segment organized.
PSTP(page/segment table pointer) andPUWPpoint at a FIXED table structure in ND-500-local memory. [V that PSTP is set once from a constant] - Per-process, the microcode does NOT re-point PSTP/PUWP; it switches the DOMAIN
(
MM,DOM/MM,ADOM) and SEGMENT (MM,PS/MM,PHS) registers, which index into the PSTP-rooted table to select this process's page mappings. [V that only domain/segment change; the "index into a domain-keyed table" mechanism is INFERRED from the register roles and the fact PSTP stays constant] - Instruction space (I-space, IMM) and data space (D-space, DMM) are two VIEWS through the same
written
MM,*registers. Because there is no separate write toIMM,PSTP/DMM,PSTP, the hardware evidently fans the singleMM,PSTP/MM,PUWP/MM,PS/MM,DOMwrite out to both the I-side and D-side units, orMM,*is the write alias andIMM,*/DMM,*are the read-back views. [INFERRED - the listing shows onlyMM,*writes andIMM,*/DMM,*reads]
Deliverable 4: Code vs data address origin¶
Where the code (PSEG) address comes from: the process's P register = mem[ctx+0]
(014757). This is a LOGICAL ND-500 address. It is translated by the I-space MMU using the
loaded MM,PS (program segment) and MM,DOM (domain), which index the PSTP-rooted tables. [V
for P source and for MM,PS/MM,DOM load; translation mechanism INFERRED]
Where the data (DSEG) address comes from: data references go through the A1-A4 address
registers (mem[ctx+0x20..0x2C]) and are translated by the D-space MMU using MM,DOM/MM,ADOM
(current + alternative domain). [V for A-register source and domain load]
Does the microcode tie PSTP/PUWP to the image load address? NO. [V] PSTP/PUWP are set from constants at init only (Deliverable 3.2) and are never recomputed from where the 14B/RESIWR copy family placed the image. Therefore:
After the swapper image is DMA'd into ND-500 memory, the microcode does NOT itself learn where PSEG/DSEG physically live. It assumes the page/segment tables (rooted at the constant PSTP) and the per-domain/per-segment descriptors ALREADY EXIST in ND-500-local memory, built by SINTRAN/ACCP. The microcode's whole job at start is to select the right domain+segment for the process (MM,DOM/MM,ADOM/MM,PS from the context block) and resume at P. [V for "microcode does not derive it"; "SINTRAN/ACCP build the tables" is INFERRED - not provable from this listing, but it is the only remaining producer]
This matches the D4 RUN-blocker finding: real placement (page/segment tables) must be built by SINTRAN's genuine swapper/placement path; a faked swapper leaves the tables unbuilt, so a started domain has no valid PSTP-rooted mapping.
Deliverable 5: INIT_SAM chain (full trace)¶
Entry: INIT_SAMSON (014517), reached from the reset vector SAMSON (000000,
COND,MSEXO ... INIT_SAMSON) and from 014516 (G,OOPS -> INIT_SAMSON). This is CPU COLD
INIT, run at control-store start / micro-start, BEFORE any process executes. NOT per-process. [V]
Sequence (all [V] destinations):
| uWord | Action |
|---|---|
014517 |
LC := BM14-1 (loop count) |
014520 |
MIC,CNT32 := 0 |
014521-014522 INIT_SRF |
zero the SRF register file (RF2D loop, LCDECR / LCZ) |
014524-014525 |
SPEC,MOD := BM21; RF2 := BM21 |
014527 INIT_FROM17 |
SRF11 := 0; call SET_IDLE |
014530-014531 |
clear CPU-available cell (ADR_CPUAVA) |
014532 |
call INIT_CLRSTS (014606: clears MIC,TE / IDU,TE / MIC,STS / IDU,STS / MIC,MISTS / MM,CTRP / SPEC,TRPCLR) |
014533 |
call INIT_REG (014621: seeds SRF0..SRF7 with math constants; register file base) |
014534 |
call INIT_ADRP (025646: computes #CPUDF = START_MESS + SAMSON_CPU<<8, writes srf[2017]) |
014535-014541 |
clear caches: CLR_DC, CLR_IC, CLR_DTSB, CLR_ITSB; TRAP_ARM |
014542-014546 FILL_CC |
fill the cache-control array (SPEC,MIB, SPEC,CC), zero-instruction fill |
014552-014561 |
set up SYSPAR SRF cells; call SYS_READ (017111: 3 system-param words), SYS_DATAF (025630: X5MXF/X5FIF ring header) |
014564 |
SC3 := SC13 (conditional, INVSEQ COND,MZRO -> INIT_SAM_1) |
014567 INIT_SAM_1 |
SC4 := SC13; call PSTBASE (PSTBASE 000021: SC13 := 2 const) |
014570 |
SC5 := SC13 |
014572 INIT_SAM_3 |
MM,PUWP := SC3 [V] |
014573 |
MM,PSTP := SC13 [V] |
014574-014575 |
call CPU_READ; SRF11 := SC14-1 (=-1, no runnable process) |
014602 INIT_SAM_4 |
SC12 := SC14; call PRNOWR; call UNLOCK_QUE; -> IDLE (014605) |
So INIT_SAM: (1) zeroes SRF and status/trap state, (2) clears all four caches, (3) establishes
the shared-memory comm block pointer #CPUDF, (4) reads system parameters and the notification
ring header, (5) sets the MMU page/segment table pointers MM,PSTP/MM,PUWP from constants
(PSTBASE=2 class), (6) marks "no process running" (SRF11 := -1) and drops into the IDLE mailbox
loop. It runs ONCE at micro-start; process starts thereafter go through
MSG_START -> NEWCNTXT -> CNTXTLOAD -> EXECUTE and never revisit PSTP/PUWP. [V]
Second MMU-init site (017725-017737, MACRO_ST1 / SIM_EXEC path): a "bare macro state"
reset that zeroes MM,CTSB, sets MM,PSTP := 0, MM,PUWP := 4, MM,PS := 0, MM,DOM := 0,
MM,ADOM := 0, MM,PHS := 0, then SPEC,MOD := SC2 and jumps to MACRO_SETP / SIM_EXEC_1
(017771, which SET_RUNNINGs). This is the alternate cold macro-entry (e.g. first-ever start /
CS-load hand-off), also constant-fed. [V]
POISONED PRIORS / OPEN QUESTIONS¶
-
X5CPU+1context-base prior is WRONG for the register context block. The per-process register CONTEXT block is0o4000 + 0o400*SRF11(process number), verified.X5CPU+1is the per-CPU MAILINK extension block (mailbox poll), a different structure. [V correction] -
Exact PSTP/PUWP numeric values at INIT_SAM_3 are path-dependent. SC3/SC13 flow through conditional words
014564-014571; both derive from constants (PSTBASE=2, OFFSET=0o4000), but the final value on any given cold start is INFERRED, not byte-pinned. The point (small constant, not image address) is [V]. -
The domain-keyed page-table walk is INFERRED. The listing proves PSTP stays constant and only MM,DOM/MM,ADOM/MM,PS/MM,PHS change per process. The claim that PSTP roots a table indexed by domain+segment is the natural reading of the register roles but is not shown as an explicit memory walk in the start path (the walk is in hardware/the fault path, not the context load).
-
"SINTRAN/ACCP build the page/segment tables" is INFERRED. The microcode never builds them during process start; it assumes they exist. The producer is not in this listing. This is the microcode-side confirmation of the D4 RUN blocker (tables must come from SINTRAN's real placement, not the faked swapper).
-
IMM vs DMM PSTP/PUWP fan-out is UNVERIFIED at the RTL level. Only
MM,*is written;IMM,*/DMM,*appear only as read sources (LOOK_SRF). WhetherMM,PSTPphysically fans to both units orIMM,*/DMM,*are read-back aliases of the same register is not decidable from the microword listing alone. The C# model (MmsUnit.cs) should treat aMM,PSTPwrite as updating BOTH the I-space and D-space table pointer until proven otherwise. -
Context second-block byte offsets (0x40+) are INFERRED. The IX*2 scaling on
014776-015000prevents clean per-word offset reading; the register destinations (status/domain/MOD) are [V], the exact ctx byte positions are not. -
Descriptor cells at ctx+0x08 / ctx+0x0C (
DAC,B/DAC,XFER/LDRES) are saved/restored [V] but their architectural meaning (segment descriptor B / transfer-restart descriptor) is INFERRED from the DAC mnemonic.