ND-500 Monitor Call Architecture: Complete Technical Guide¶
⚠ CORRECTION 2026-07-20 — the TAG-value table in this file is FABRICATED¶
The table around lines 580-610 (
0x01 MON_CALL_REQUEST, …) is not real, and the IOX offset table beside it contradicts the verified codes. Debunked inSINTRAN\ND500\ND500-BUS-INTERFACE-REFERENCE.md§10.3: the TAG field is 4 bits, and the value cited as a message type is the DIEN strobe. There is no high-level TAG protocol — monitor calls do not travel as TAG codes.What actually happens (vendor:
ND500UC\manuals\ND-05.012.01 ND-500 Micro Program Guide.md§13, lines 1090-1400;ND-30.013.02 Test Micro Program Descriptions§3.12-3.14):
- A monitor call is a
callgthrough a segment-31 capability carryingPC_IND|PC_OMC. The microcode's trap decoder routes it (trap code 6 →CALL_MON), builds the stop record in the process's own message in shared memory, and answers it. Cross-confirmed from the NDIX kernel side:callg $0xf8000180,$4,…— segment 31, offset0x180= 600 octal.- The wire-level TAG lines are register strobes only. TAG-OUT:
0/1MAR,2/3STATUS,4read CONTROL,5reset activate,6/7DATA register (the RIOM DMA into ND-100 memory). TAG-IN: clock/enable strobes for the control-store-load and debug path.- Verified ND-100-side IOX octal codes: RMAR
060, LMAR061, RSTA062, LCON065, MCLR066, TERM067, RTAG070, WTAG071, WDAT073, SLOC074, CLKD075, UNLC076, RETG077.- Message-status lifecycle (vendor-anchored, matches the byte-verified model):
0free,1message-to-ND-500,2in-process,3answer,4error.Authoritative replacements:
SINTRAN\ND500\ND500-BUS-INTERFACE-REFERENCE.md,SINTRAN\ND500\ND500-MONITOR-CALL-MECHANISM.md, andE:\Dev\Ronny\ND5000UC\microcode\MAILBOX-MICROCODE-PSEUDOCODE.md§3.8 for the decodedCALL_MONpath.
How ND-500 Programs Invoke ND-100 Monitor Calls via Segment 31
Scope: classic ND-500 only. Everything below describes the classic ND-500 generation — an ND-500 CPU with a 5015 interface card, talking to an ND-100 through a 3022 card and 5MPM shared memory. The ND-5000 (SAMSON) uses an entirely different transport (octobus / ACCP, no 3022, no 5015). The message layout and the monitor call concept carry over; the signalling, the register set and the IOX codes in this document do not. Do not read this file as ND-5000 documentation.
Table of Contents¶
- Overview: The "Other CPU" Mechanism
- Segment 31 and the "Other Machine" Bit
- Complete Monitor Call Flow
- MICFU and MCNO: Who Says What, and In Which Direction
- Memory Locations and Disassembly Guide
- Message Buffer Structure
- Hardware: 3022/5015 Interface
- Detailed Examples
Overview: The "Other CPU" Mechanism¶
The Problem¶
The ND-500 is a powerful 32-bit processor designed for computation, but it has no I/O system and no interrupts. Meanwhile, the ND-100 has a sophisticated I/O system and handles all peripherals (disks, terminals, network, etc.).
Question: How does an ND-500 program request I/O operations from the ND-100?
Answer: The Segment 31 "Other CPU" trap mechanism.
The Solution Architecture¶
graph TB
subgraph "ND-500 User Program"
USER[User Code<br/>FORTRAN, Pascal, etc.]
end
subgraph "ND-500 System Libraries"
DVIO[DVIO Library<br/>Device I/O Wrapper]
RFILE[RFILE Library<br/>File Read Wrapper]
WFILE[WFILE Library<br/>File Write Wrapper]
end
subgraph "ND-500 Trap Mechanism"
SEG31[Segment 31 Trap<br/>"Other CPU" bit=1]
TRAP[Trap Handler<br/>Saves CPU State]
end
subgraph "5MPM (Shared Memory)"
BUFFER[Message Buffer<br/>Process Communication<br/>Parameters & Results]
end
subgraph "3022/5015 Interface"
INTERFACE[Hardware Interface<br/>STATUS / CONTROL / MAR / DATA<br/>activate + level-12 interrupt]
end
subgraph "ND-100 Interrupt System"
INT12[Interrupt Level 12<br/>Monitor Call Handler]
end
subgraph "ND-100 Operating System"
SINTRAN[SINTRAN III<br/>File System, Devices]
DRIVERS[I/O Drivers<br/>Disk, Terminal, Network]
end
USER --> DVIO
USER --> RFILE
DVIO --> SEG31
RFILE --> SEG31
SEG31 --> TRAP
TRAP --> BUFFER
BUFFER --> INTERFACE
INTERFACE --> INT12
INT12 --> SINTRAN
SINTRAN --> DRIVERS
DRIVERS --> DEVICES[Physical Devices]
DRIVERS -.Result.-> BUFFER
BUFFER -.Resume.-> TRAP
TRAP -.Continue.-> USER
Segment 31 and the "Other Machine" Bit¶
Segment Descriptor Format¶
In the ND-500, each of the 32 segments (0-31) has capabilities defined in a 16-bit descriptor:
Bit 15: I (Indirect bit)
Bit 14: O (Other CPU bit) ← THIS IS THE KEY!
Bit 13-0: Other protection/addressing bits
What Makes Segment 31 Special¶
Segment 31 is reserved for monitor calls to the ND-100.
When SINTRAN III's ND-500 monitor initializes a process (during PLACE-DOMAIN), it sets:
ProgramCapabilities[31] = 0xC000 (binary: 1100 0000 0000 0000)
DataCapabilities[31] = 0xC000
This means: - Bit 15 (I) = 1: Indirect (addresses go through segment table) - Bit 14 (O) = 1: Other CPU - TRAP instead of normal execution
How the Trap is Triggered¶
sequenceDiagram
participant CPU as ND-500 CPU
participant SEG as Segment Check Logic
participant TRAP as Trap Handler
CPU->>CPU: Fetch CALLG instruction
Note over CPU: callg $0xf8000180<br/>(segment 31, offset 0x180 = 600 oct)
CPU->>SEG: Check segment 31 capabilities
SEG->>SEG: Read ProgramCapabilities[31]<br/>Value = 0xC000
SEG->>SEG: Check bit 14 (O bit)
Note over SEG: Bit 14 = 1<br/>"Other CPU" flag SET
SEG->>TRAP: Trigger "Other CPU" trap!
Note over TRAP: CPU does NOT execute CALLG<br/>Trap handler takes over instead
TRAP->>TRAP: Save CPU state (PC, registers)
TRAP->>TRAP: Fill message buffer (N5STA, STOPR=MOCALL)
TRAP->>TRAP: Set STATUS "finished" + stop reason -> level-12 IRQ
TRAP->>CPU: Set IsWaiting flag
Note over CPU: CPU suspends execution<br/>Waits for ND-100 response
Code Detection Example¶
// In ND-500 CPU execution loop
if (instruction.IsCALLG())
{
uint targetAddress = instruction.GetTarget();
// Segment number is the top 5 bits of the 32-bit address: 0xf8000180 -> 31.
byte segment = (byte)((targetAddress >> 27) & 0x1F);
if (segment == 0x1F) // Segment 31?
{
ushort progCap = _cpu.ProgramCapabilities[31];
// Check for the "other machine" capability (PC_OMC)
if ((progCap & 0x4000) != 0)
{
// Raise the instruction-fetch/protect trap. The trap decoder then routes
// trap code 6 to CALL_MON - the CALLG itself is never performed.
_trapHandler.RaiseInstructionFetchTrap(_cpu, targetAddress);
return;
}
}
}
// Execute CALLG normally for other segments...
Note on the address encoding (corrected 2026-07-20). The shift used to be
>> 24, which pairs with the literal#0x1F000000that this document used elsewhere. That encoding does not match the only cross-confirmed real call we have — the NDIX kernel'scallg $0xf8000180,$4,…, where segment 31 sits in bits 31-27. The shift has been corrected to>> 27and the0x1F000000literals replaced accordingly.
Key Point: The CPU detects the capability before attempting to execute the CALLG. It doesn't try to fetch code from segment 31 - instead, it immediately traps.
Complete Monitor Call Flow¶
Full Sequence Diagram¶
sequenceDiagram
participant USER as ND-500 User Program
participant LIB as System Library<br/>(DVIO, RFILE, etc.)
participant CPU500 as ND-500 CPU
participant TRAP as ND-500 Trap Handler
participant MPM as 5MPM<br/>(Shared Memory)
participant IF as 3022/5015<br/>Interface
participant INT as ND-100<br/>Interrupt Level 12
participant SINT as SINTRAN III<br/>(ND-100 OS)
participant DEV as I/O Device
Note over USER: Need to write to terminal
USER->>LIB: Call DVIO(device=1, buffer, len)
activate LIB
LIB->>LIB: Marshal parameters into the<br/>CALLG argument list
LIB->>CPU500: callg $0xf8000180, $4, args...
Note over CPU500: Segment 31, offset 0x180<br/>= 600 octal
CPU500->>CPU500: Check seg 31 capabilities
CPU500->>CPU500: PC_IND|PC_OMC set -> trap!
CPU500->>TRAP: Trap decoder: code 6 -> CALL_MON
activate TRAP
TRAP->>MPM: N500A (+7) := saved P
TRAP->>MPM: STOPR (+11) := MOCALL<br/>MCNO (+13) := low halfword of<br/>the CALLG target (600 oct)
TRAP->>MPM: NUMPA (+12) := argc;<br/>copy args into ADDRESS slots (+40+2k)<br/>and VALUE slots (+100+2k)
TRAP->>MPM: N5STA (+2) := 3 (ANSWER)
TRAP->>CPU500: Microcode enters IDLE loop
deactivate TRAP
Note over CPU500: ND-500 in IDLE loop<br/>Only an activate or a terminate<br/>can bring it out
IF->>IF: STATUS "finished" (bit 3)<br/>+ stop reason (bits 10-14)
IF->>INT: Trigger interrupt level 12<br/>(ident 16 oct, gated by CONTROL bit 0)
activate INT
INT->>IF: Read STATUS via IOX (RSTA5)
INT->>MPM: Walk message queue from MAILINK,<br/>check N5STA=3 / STOPR=MOCALL
INT->>MPM: Read message buffer
MPM-->>INT: MCNO, NUMPA, parameter slots
INT->>INT: MCHANDLE: dispatch on MCNO<br/>(e.g. 600 oct)
INT->>MPM: Read the caller's data<br/>via the parameter addresses
MPM-->>INT: User data bytes
INT->>SINT: Call SINT routine for DVIO
activate SINT
SINT->>DEV: Write to device 1 (terminal)
activate DEV
DEV-->>SINT: Success
deactivate DEV
SINT-->>INT: Error code = 0 (success)
deactivate SINT
INT->>MPM: Write FUNCV (function value / result)
INT->>MPM: N5STA := 1 (MSGN500),<br/>MICFU := 24 oct (3MONCO)
INT->>IF: XACT500: activate via LCON5<br/>(CONTROL bit 2)
deactivate INT
IF->>TRAP: Activate wakes the microcode<br/>out of the IDLE loop
activate TRAP
TRAP->>MPM: Read MICFU = 3MONCO<br/>-> "restart after monitor call"
MPM-->>TRAP: FUNCV = 0
TRAP->>CPU500: Resume the process at the<br/>instruction after the CALLG,<br/>FUNCV delivered as the result
deactivate TRAP
Note over CPU500: ND-500 RESUMES
CPU500->>LIB: Return from CALLG
deactivate LIB
LIB->>USER: Return error = 0
Note over USER: Terminal write succeeded!
MICFU and MCNO: Who Says What, and In Which Direction¶
CORRECTION 2026-07-20. This section used to claim that MICFU was a 16-bit "monitor call function" written by the ND-500 library before the trap, and it listed a table of values (
0x00 DVIO_IN,0x01 DVIO_OUT,0x10 RFILE,0x30 PAGE-FAULT, …) together with a category tree and two code samples built on it. All of that was invented. MICFU is an ND-100 → ND-500 command code with a small set of verified octal values, and it is never what carries a monitor call. The monitor call number lives in MCNO, written by the microcode. Authoritative table:SINTRAN\ND500\ND500-BUS-INTERFACE-REFERENCE.md§6.4 (and §6.2 for the message layout).
The two fields, and their directions¶
Both live in the same message in 5MPM, but they travel opposite ways:
| Field | Offset (oct) | Written by | Meaning |
|---|---|---|---|
| MICFU | 6 | ND-100 | Command to the ND-500: "start this process", "restart after monitor call", "read your microprogram version", … |
| MCNO | 13 | ND-500 microcode | The monitor call number the macro-program asked for |
| FUNCV | 13 | ND-100 | The function value handed back when the call is answered |
So a monitor call is not expressed as a MICFU. It is expressed as a callg into
segment 31, and the microcode's trap decoder (trap code 6 → CALL_MON) records the
low halfword of the CALLG target as MCNO. MICFU only appears afterwards, when the
ND-100 has finished the work and commands the ND-500 to carry on.
Verified MICFU command codes¶
Values verified in the SINTRAN L07 + M06 symbol tables (reference §6.4). Octal:
| Value (oct) | Symbol | Meaning |
|---|---|---|
| 1 | 3RMICV | Read microprogram version (the watchdog message) |
| 5 | 3SWMESS | Message to the swapper (carries its own SWFUN field) |
| 23 | 3START | Start process |
| 24 | 3MONCO | Restart after monitor call — the one that ends the flow above |
| 25 | 3TRACO | Trap continue |
| 26 | 3WMONCO | Wait monitor call |
| 27 | 3FITRNSF | File transfer |
| 44 | 3RPREG | Read P register (histogram message) |
There is no "0x00-0x0F device I/O / 0x10-0x2F file operations" range. Anything you may have read elsewhere in that shape came from the fabricated model.
Where the monitor call number actually comes from¶
The number is part of the call target, not of any pre-loaded message field. From the NDIX kernel side a monitor call looks like:
callg $0xf8000180, $4, ... ; segment 31, offset 0x180 = 600 octal
0xf8…… selects segment 31; the offset 0x180 is the monitor call number, and the
microcode copies it into MCNO. The $4 is the argument count, which the microcode
records in NUMPA before copying the arguments into the message's parameter slots.
Key Insight: the ND-500 program does not hand-build a message before trapping.
It just makes a normal callg; the microcode builds the whole stop record for it.
On 8-bit MON numbers¶
The old text framed MICFU as a workaround for the ND-100's 8-bit MON operand. That
framing does not survive: the ND-500's monitor call number is a segment-31 offset, so
it is naturally wider than 8 bits without needing any separate function-code scheme.
Memory Locations and Disassembly Guide¶
Where to Find Monitor Call Code¶
On the ND-500 Side¶
System Libraries in ND-500 Memory:
The monitor call library routines are part of the ND-500 XMSG or MONITOR domain. Typical locations:
Segment: Varies (loaded by PLACE-DOMAIN)
Offset: Typically 0x00001000 - 0x00005000
Example DVIO location:
Segment 5, Offset 0x1200
Full address: 0x05001200
How to find them:
-
Check XMSG/MONITOR domain file:
(DOMAINS)XMSG:DOMAIN (DOMAINS)MONITOR:DOMAIN -
Use ND-500 Monitor commands:
N500: LIST-DOMAINS DOMAIN SEGMENT SIZE LOADED XMSG 5 1234 YES MONITOR 6 567 YES -
Look for CALLG instructions targeting segment 31.
(The worked disassembly that used to sit here — a library routine loading a 5MPM message address and storing a MICFU before the call — was invented, and has been removed. No such code exists: the library does not touch the message.)
What you are actually looking for is a
callgwhose target has the top five address bits equal to 31, with the monitor call number in the low halfword, e.g.callg $0xf8000180, $4, …(segment 31, offset0x180= 600 octal). Everything after that instruction happens in microcode, not in visible ND-500 code.
On the ND-100 Side¶
Interrupt Handler Location:
The ND-100 interrupt level 12 handler is part of SINTRAN III kernel:
The handler reached from the level-12 ident is 5STDRIV, in the SINTRAN source
MP-P2-N500.NPL (lines 656-694). The addresses that used to be printed here
(INT12-HANDLER 0x0512, ND500-TRAP, MICFU-DISPATCH) were invented and have been
removed — those symbols do not exist in the SINTRAN symbol table.
How to find it:
-
Look up the real symbols. The names that do exist are
5STDRIV(the level-12 driver),CLE5STATUS(read + clear STATUS),CHN5STATUS(dispatch on N5STA),DECOMESS(dispatch on MICFU/STOPR),MCHANDLE(monitor call handler) andXACT500(hand the ND-500 its next work and activate it). Their addresses depend on the SINTRAN version you carved; resolve them from that image's symbol table rather than from any number quoted in a document. -
Follow the ident, not a vector table. The ND-100 has no level-12 vector slot in low memory (the
Address 0x000Centry printed here before was invented). On an interrupt the level-12 code executesIDENT PL12; the 3022 answers with its ident code — 16 octal for thumbwheel setting 0 — and SINTRAN's ident dispatch table routes that code to5STDRIV. -
Real handler flow (the former invented disassembly checking a "TAG value" has been removed — the driver never reads TAG registers):
5STDRIV (NPL:MP-P2-N500.NPL:656-694), entered from the level-12 ident: 1. CALL CLE5STATUS % read RSTA5 (STATUS), clear latched power bits 2. status /\ 720 >< 0 ? % 5PAGF/5DMAER/5PFAIL/5POWOF error paths 3. Scan execution queue from MAILINK, following LINK fields (via 5MBBANK) 4. CHN5STATUS per message % dispatch on N5STA 5. DECOMESS on answers % dispatch on STOPR (MOCALL -> MCHANDLE) 6. CALL XACT500; WT12 % give ND-500 next work, wait for next IRQ
Message Buffer Structure in 5MPM¶
Each ND-500 process has a message in shared memory. (The former layout here — "base 0x400 + N*0x100", PC_SAVED/ITMQUEUE fields — was invented and has been replaced by the verified layout.)
Verified message layout (ND-100 halfword offsets, octal; symbol-table +
carve-verified — see SINTRAN\ND500\ND500-BUS-INTERFACE-REFERENCE.md §6.2, and
vendor ND-05.012.01 §13.1 for the 6-word header):
Offset | Field | Description
-------|--------|-------------------------------------------------
0 | LINK | word: next message in chain (-1 = end)
2 | N5STA | status: 0 free, 1 MSGN500, 2 WAITING, 3 ANSWER, 4 5ERANSWER
4 | X5CPU | CPU number
6 | MICFU | micro function code (see reference 6.4)
7 | N500A | saved P register
11 | STOPR | stop reason (MOCALL/5FMOCALL/TRAPCODE/...)
12 | NUMPA | number of parameters
13 | MCNO / FUNCV | monitor call number / function value
16 | TRAPN | trap number
17-30 | trap record
40+2k | parameter ADDRESSES (16 slots)
100+2k | parameter VALUES, 32-bit (16 slots)
140 | ABUFA | buffer pointer
Status lifecycle: 1 MSGN500 -> 2 WAITING (set by microcode at start of handling) -> 3 ANSWER or 4 5ERANSWER (set by microcode when finished). Vendor statement: ND-05.012.01 §13.1 ("Status of the block").
Hardware: 3022/5015 Interface¶
Physical Components¶
graph LR
subgraph "ND-100 Side"
ND100[ND-100 CPU]
CARD3022[3022 Interface Card]
IOX[IOX Bus<br/>Device 100₈]
end
subgraph "ND-500 Side"
CARD5015[5015 Interface Card]
ND500[ND-500 CPU]
end
subgraph "Shared Resources"
MPM[5MPM<br/>Multiport Memory<br/>128KB-2MB]
end
ND100 <-->|IOX commands| CARD3022
CARD3022 <-->|TAG registers<br/>Interrupts| CARD5015
CARD5015 <-->|Memory access| MPM
ND500 <-->|Memory access| MPM
CARD3022 <-->|DMA| MPM
TAG Registers (CORRECTED — register strobes, not inter-CPU messaging)¶
The former "TAG Values" table (0x01 MON_CALL_REQUEST etc.) was fabricated and has been removed. Both TAG registers are on the 5015 (ND-30.013.02 §3.12/3.13):
- TAG-IN (ND-100 → 5015): 4-bit strobe codes that clock/enable individual 5015 registers (DICLK1/2, DUCLK, WACLK, BRKCLK, TGCLK, CNTCLK, DIEN, DUEN, WAR, BRKR, CNTR, RESBRK, DUNL, EOUTEN). Used by the control-store loader and test programs; never by the runtime driver.
- TAG-OUT (5015 → 3022, driven by ND-500 microcode): 3-bit codes commanding the 3022 — read/write MAR, read/write STATUS, read CONTROL, reset activate, and read/write DATA and ND-100 memory (the microcode's message-fetch/answer DMA path, also underlying the RIOM instruction; there is no WIOM - manual ND-05.009.4 section 16.23 defines RIOM only, with no write companion).
Real inter-CPU signaling: ND-100 → ND-500 = activate (CONTROL bit 2, LCON5); ND-500 → ND-100 = STATUS "finished" (bit 3) + stop reason (bits 10-14) raising the level-12 interrupt when CONTROL bit 0 is set.
IOX Offsets for 3022 Interface (verified, OCTAL — see reference §3.2 for the¶
four-mode decode; the former table here was wrong)
| Offset (oct) | Mnemonic | Purpose (unlocked, not test mode) |
|---|---|---|
| 0 | RMAR5 | Read memory address register |
| 1 | LMAR5 | Load memory address register |
| 2 | RSTA5 | Read STATUS register |
| 5 | LCON5 | Load CONTROL register (bit 2 = activate) |
| 6 | MCLR5 | ND-500 master clear |
| 7 | TERM5 | Terminate |
| 10 | RTAG5 | Read TAG (readback) |
| 11 | LTAG5/WTAG | Write 5015 TAG-IN strobe |
| 13 | WDAT | Write DATAX |
| 14 | SLOC5 | Set locked |
| 15 | CLKD5 | Clock DATA (locked mode) |
| 16 | UNLC5 | Release locked |
| 17 | RETG5 | Return tag (bit 1 = stop bit) |
Detailed Examples¶
Example 1: DVIO Output (Write to Terminal)¶
ND-500 User Program (FORTRAN):
PROGRAM HELLO
CHARACTER*13 MSG
INTEGER DEVICE, IERR
MSG = 'HELLO, WORLD!'
DEVICE = 1
CALL DVIO(DEVICE, MSG, 13, IERR)
IF (IERR .NE. 0) THEN
WRITE(*,*) 'ERROR:', IERR
END IF
END
Compiled to ND-500 Assembly:
; Allocate stack space
ENTB 4 ; Allocate 16-word block
; Store message
LDWC [B+3], 'HE' ; 'H', 'E'
LDWC [B+4], 'LL' ; 'L', 'L'
LDWC [B+5], 'O,' ; 'O', ','
; ... etc ...
; Prepare parameters
LDWS R0, #1 ; Device = 1 (terminal)
LDAA [B+3] ; Address of MSG
LDWS R2, #13 ; Length = 13
; Call DVIO library
CALLG DVIO ; Call DVIO routine (ordinary intra-domain call)
; DVIO library code
DVIO:
; Nothing to marshal into shared memory. The library simply re-issues the
; request as a monitor call: a CALLG whose target is in segment 31, with the
; monitor call number as the offset and the arguments as the CALLG arg list.
CALLG $0xf8000180, $4, dev, buf, len, err ; <- traps to CALL_MON
; On resume, the function value written by the ND-100 (FUNCV) is the result.
RET ; Return to user program
CORRECTION 2026-07-20. The body of
DVIOabove used to contain a dozen lines that computed a message-buffer address as5MPM base + 0x400 + process*0x100, stored a "MICFU = DVIO_OUT" and set an "ITMQUEUE" flag. None of that exists. There is no such base-plus-index formula (a process's message is found by walking the LINK chain from MAILINK), there is no ITMQUEUE field, and the library never writes the message at all.
What Happens:
- CPU fetches a CALLG whose target is in segment 31
- The segment-31 capability carries
PC_IND|PC_OMC - That raises an instruction-fetch/protect trap instead of performing the call
- The trap decoder routes trap code 6 to
CALL_MON, which builds the stop record
Corrected emulator pseudo-code (the former version implemented the fabricated
TAG protocol with invented message offsets — replaced 2026-07-20; the per-gap list
against the real C# code is SINTRAN\ND500\ND500-EMULATOR-DISCREPANCY-AUDIT.md):
// ND-500 microcode side: monitor-call stop
public void HandleOtherMachineCall(ND500CPU cpu, uint targetAddress)
{
// Message address comes from the process's own message (queue LINK chain),
// NOT from a computed "base + N*0x100" formula.
var msg = CurrentProcessMessage();
msg.N500A = cpu.P; // saved P (halfword offset 7)
msg.STOPR = STOPR_MOCALL; // stop reason (offset 0o11)
msg.MCNO = targetAddress & 0x07FFFFFF; // e.g. 0x180 = 600 octal
// parameters into ADDRESS slots (0o40+2k) / VALUE slots (0o100+2k)
msg.N5STA = N5STA_ANSWER; // 3 = answer to ND-100
Status |= STATUS_FINISHED; // bit 3, plus stop reason in bits 10-14
if ((Control & CONTROL_INTENABLE) != 0)
_nd100.RaiseInterrupt(level: 12, ident: ThumbwheelIdent); // 16 octal
EnterIdleLoop(); // wait for activate/terminate
}
// ND-100 side: level-12 driver (5STDRIV shape)
public void HandleLevel12()
{
var status = ReadIOX(RSTA5); // the real "what happened" channel
if ((status & (PAGF|DMAER|PFAIL|POWOF)) != 0) { HandleErrors(status); return; }
for (var m = Mailink; m != -1; m = m.LINK) // walk the message queue
if (m.N5STA == N5STA_ANSWER && m.STOPR == STOPR_MOCALL)
MCHandle(m); // dispatch on m.MCNO
Xact500(); // give ND-500 next work: set message
// N5STA := MSGN500, MICFU := 3MONCO (24B),
// then activate via LCON5 (CONTROL bit 2)
}
ND-500 Resumes:
CALLG $0xf8000180, $4, ... ; <- resumes after this, result = FUNCV
RET ; Return to user program
User Program Gets Result:
CALL DVIO(DEVICE, MSG, 13, IERR)
! IERR = 0 (success)
Output on terminal:
HELLO, WORLD!
Summary¶
Key Takeaways¶
- Segment 31 is NOT executed - the capability carries
PC_IND|PC_OMC, so a CALLG into it traps - The trap decoder routes trap code 6 to
CALL_MON; everything from there on is microcode - MCNO carries the monitor call number (the segment-31 offset). MICFU is the opposite direction — an ND-100 command to the ND-500, e.g.
3MONCO= 24 octal, "restart after monitor call" - The message in 5MPM holds the stop record, the parameters and the result (FUNCV)
- STATUS "finished" + level-12 interrupt (500→100) and activate via CONTROL bit 2 (100→500) coordinate the CPUs — TAG registers are register strobes only
- The ND-500 sits in its IDLE loop during the call: "nothing but an activate or a terminate from the ND-100 can cause the micro program to leave the IDLE loop"
To Find MON Call Implementations¶
On ND-500:
- Check XMSG/MONITOR domain files
- Disassemble from domain load address
- Look for callg instructions whose target is in segment 31 (0xf8……)
On ND-100:
- Resolve 5STDRIV / DECOMESS / MCHANDLE in the symbol table of the image you carved
- Follow the level-12 ident (16 octal at thumbwheel 0), not a low-memory vector
- Disassemble from 5STDRIV
In 5MPM: - Find a process's message by walking the LINK chain from MAILINK — there is no "base + process*0x100" formula - Use the verified halfword offsets above: N5STA +2, MICFU +6, N500A +7, STOPR +11, NUMPA +12, MCNO/FUNCV +13, parameter addresses +40+2k, parameter values +100+2k (octal)
Document Version: 2.0 (body de-fabricated 2026-07-20 — TAG protocol, MICFU code table, message-buffer address formula and the code samples built on them replaced with the verified model; see the correction header at the top of this file) Date: 2025-11-18, revised 2026-07-20 Purpose: Technical documentation of ND-500 to ND-100 monitor call architecture
Related Documents: - INTEGRATION-GUIDE-SEGMENT31.md (Implementation guide) - ND500-ENTB-IMPLEMENTATION-GUIDE.md (ENTB instruction) - SINTRAN-Deep-Dive-Guide.md (System architecture)