What Makes ND-500 Programs Special¶
Complete Guide to ND-500 Program Characteristics and Differences from RT Programs
Version: 1.0
Last Updated: October 16, 2025
Purpose: Explain the unique characteristics of ND-500 programs compared to regular SINTRAN RT programs
Table of Contents¶
- Overview
- Fundamental Differences
- ND-500 Program Structure
- Lifecycle and Management
- Communication Mechanisms
- Special Monitor Calls
- Memory Management
- Process States
- C# Implementation
1. Overview¶
1.1 What are ND-500 Programs?¶
ND-500 programs are NOT standard SINTRAN RT programs. They are shadow processes that run on the ND-500 CPU(s), controlled and coordinated by the ND-100 SINTRAN kernel.
flowchart TB
subgraph ND100 [ND100 SINTRAN Kernel]
RT[RT Programs RealTime Run on ND100 CPU]
BG[Background Programs TimeSharing Run on ND100 CPU]
KERNEL[SINTRAN Kernel Manages All Programs]
end
subgraph ND500 [ND500 CPUs]
P1[ND500 Process 1 Graphics DB etc]
P2[ND500 Process 2 Application Logic]
P3[ND500 Process N Computation]
end
subgraph MPM [Multiport Memory 5MPM]
MSG[Message Buffers]
DESC[Process Descriptors]
end
KERNEL -->|Manages| RT
KERNEL -->|Manages| BG
KERNEL -->|Controls via Messages| P1
KERNEL -->|Controls via Messages| P2
KERNEL -->|Controls via Messages| P3
RT -->|"Send Receive"| MSG
P1 -->|"Read Write"| MSG
P2 -->|"Read Write"| MSG
P3 -->|"Read Write"| MSG
KERNEL -->|Updates| DESC
style P1 fill:#009688,stroke:#00695C,stroke-width:2px,color:#fff
style P2 fill:#009688,stroke:#00695C,stroke-width:2px,color:#fff
style P3 fill:#009688,stroke:#00695C,stroke-width:2px,color:#fff
style MSG fill:#009688,stroke:#00695C,stroke-width:2px,color:#fff
1.2 Key Concept: Shadow Processes¶
ND-500 programs are "shadow processes" because: - The process logic runs on ND-500 CPU - The control structures live on ND-100 (SINTRAN kernel) - Communication is asynchronous via message buffers in multiport memory (5MPM) - ND-100 coordinates process lifecycle, I/O, and resource allocation
2. Fundamental Differences¶
2.1 Comparison Table¶
| Aspect | RT Programs (ND-100) | ND-500 Programs |
|---|---|---|
| Execution | On ND-100 CPU | On ND-500 CPU(s) |
| Control Structure | RT-Description (26 words) | Process Descriptor (5PRDSIZE words) |
| Location | RT-Description table at 026000₈ |
Process table at S500S to S500E |
| Scheduling | SINTRAN scheduler (levels, priority) | ND-500 internal + SINTRAN coordination |
| Memory | ND-100 virtual memory (PITs) | ND-500 memory + 5MPM shared memory |
| MMU/PIT | Uses RPIT (PIT 1) or MPIT (PIT 2) | Uses special 5PIT for 5MPM access |
| Communication | Direct MON calls | Message-based via 5MPM buffers |
| Context Switch | Load ACTPRI → TRR PCR | Send activation message to ND-500 |
| I/O Access | Direct through SINTRAN drivers | Via ND-100 proxy (DVIO/DVINST) |
| Segments | SINTRAN segments | ND-500 data segments (F5DSG-L5DSG) |
| Max Count | ~32-64 RT programs | MX5PROCS (calculated at boot) |
| Creation | @START-RT-PROGRAM command | ND-500 program load + activation |
| Termination | RTOFF/KILL-RT | Terminate message (TERM5) |
2.2 Not in RT-Description Table!¶
CRITICAL: ND-500 programs do NOT have entries in the standard RT-Description table at 026000₈. They have their own process descriptor table located at symbols S500S (start) to S500E (end) in multiport memory.
From PH-P2-OPPSTART.NPL lines 1417-1419:
CALL CH5CPUPRESENT; 0=:MX5PROCS % Check if ND-500 CPU is present
A:="S500E"-"S500S"=:D:=0; T:=5PRDSIZE; *RDIV ST
IF A-1<<MX5PROCS THEN A=:MX5PROCS FI % Calculate max ND-500 processes
Formula:
MX5PROCS = ("S500E" - "S500S") / 5PRDSIZE
Where:
S500S = Start address of ND-500 process table (in 5MPM)
S500E = End address of ND-500 process table
5PRDSIZE = Size of each process descriptor (words)
MX5PROCS = Maximum number of ND-500 processes
3. ND-500 Program Structure¶
3.1 Process Descriptor (Complete)¶
/// <summary>
/// ND-500 Process Descriptor (in 5MPM).
/// Location: S500S + (process_num * 5PRDSIZE)
/// Size: 5PRDSIZE words (from symbols, typically 6-10 words)
/// All fields are 16-bit words.
/// </summary>
public struct ND500ProcessDescriptor
{
// ===== Process Identity =====
/// <summary>Offset 0: XADPROC - Process descriptor address (16 bits)
/// Points back to this structure (for validation)
/// </summary>
public ushort ProcessDescriptorAddr;
/// <summary>Offset 1: MESSBUFF - Message buffer address in 5MPM (16 bits)
/// Each process has dedicated message buffer for communication
/// Buffer size: 55MESSIZE words (from symbols)
/// </summary>
public ushort MessageBufferAddr;
/// <summary>Offset 2: Process status flags (16 bits)
/// Bits (specific positions TBD from analysis):
/// - Active/Inactive
/// - Waiting for message
/// - Error condition
/// </summary>
public ushort Status;
/// <summary>Offset 3: SENDE - Send enabled flag (16 bits)
/// 0 = Cannot send messages
/// >0 = Can send, value is process ID or state
/// Written by: *SENDE@3 STATX
/// </summary>
public ushort SendEnabled;
/// <summary>Offset 4: RECE - Receive state (16 bits)
/// Indicates if process can receive messages
/// Written by: *RECE@3 STATX
/// </summary>
public ushort ReceiveState;
/// <summary>Offset 5+: Extended fields (varies by system)
/// May include:
/// - Error codes
/// - Timing information
/// - Resource links
/// - ND-500 specific state
/// </summary>
public ushort[] Extended;
}
3.2 Process Descriptor Initialization¶
From RP-P2-N500.NPL lines 775-788:
% Initialize ND-500 process descriptors
A:=55MSNEGSIZE+D=:SWMSG
T:=5MBBANK; A=:X:=0 BONE 5SYSRES
*AAX 5MSFL; STATX; AAX -5MSFL
5SWPROC=:MSINPROCNO; X:="S500S" % Start at first process descriptor
FOR MSINPROCNO DO WHILE MSINPROCNO<<=MX5PROCS
X=:MSPRDESCR % Save descriptor address
A:=D/\1777+55MESSIZE % Calculate message buffer size
IF A>>2000 THEN D SHZ -12 +1 SH 12 FI % Bank align if needed
A:=D+55MESNEGSIZE=:X.MESSBUFF % Store message buffer address
T:=5MBBANK; X:=:A; *AAX XADPR; STATX; AAX -XADPR
MSINPROCNO; *SENDE@3 STATX % Initialize SENDE field
X:=MSPRDESCR+5PRDSIZE; 55MESSIZE; D+A % Next descriptor
OD
Key operations:
1. Allocate message buffer in 5MPM (size 55MESSIZE)
2. Bank-align buffers (cross-bank messages not supported)
3. Store buffer address in MESSBUFF field
4. Initialize SENDE field with process number
5. Advance to next descriptor (5PRDSIZE words)
3.3 Message Buffer Structure¶
/// <summary>
/// ND-500 Message Buffer (in 5MPM).
/// Size: 55MESSIZE words (from symbols, ~100 words typical).
/// Located at: ProcessDescriptor.MessageBufferAddr
/// All fields are 16-bit words.
/// </summary>
public struct ND500MessageBuffer
{
// ===== Message Header (common to all messages) =====
/// <summary>Offset 0: PLINK - Process link (16 bits)
/// Links back to process descriptor or next message
/// </summary>
public ushort ProcessLink;
/// <summary>Offset 1: 5MSFL - Message flags (16 bits)
/// Bit flags:
/// 5ITMQUEUE (bit ?): In monitor queue, ready for processing
/// 5SYSRES (bit ?): System reserved message
/// </summary>
public ushort MessageFlags;
/// <summary>Offset 2: Function code (16 bits)
/// Specifies what operation to perform:
/// 1 = DVIO output
/// 2 = DVINST input
/// 3 = File operation
/// etc.
/// </summary>
public ushort FunctionCode;
/// <summary>Offset 3: Error code (16 bits)
/// 0 = Success
/// >0 = Error code (EC174, EC175, etc.)
/// </summary>
public ushort ErrorCode;
// ===== I/O Operation Fields =====
/// <summary>Offset 4-5: TODF - To Datafield (32 bits)
/// Address of target datafield (device) on ND-100
/// </summary>
public uint ToDatafield;
/// <summary>Offset 6-7: DNOBY/NRBYT - Number of bytes (32 bits)
/// Byte count for DMA transfers
/// </summary>
public uint ByteCount;
/// <summary>Offset 8-9: N500A - ND-500 logical address (32 bits)
/// Byte address in ND-500 memory space
/// </summary>
public uint ND500LogicalAddr;
/// <summary>Offset 10-11: N100A - ND-100 physical address (32 bits)
/// Physical byte address in ND-100 multiport memory
/// Result of CNVWADR translation
/// Bit 31 set = multiport memory
/// </summary>
public uint ND100PhysicalAddr;
// ===== Additional Fields (varies by function) =====
/// <summary>Offset 12: XMICF - Microcode function (16 bits)
/// Specifies microcode operation:
/// 3RMED = Read data memory
/// 3WMED = Write data memory
/// 3START = Start process
/// 3WMONCO = Write after monitor call
/// </summary>
public ushort MicrocodeFunction;
/// <summary>Offset 13: 5DITN - DIT number (16 bits)
/// Data Interface Table number (usually 0)
/// </summary>
public ushort DITNumber;
/// <summary>Offset 14+: Variable data area</summary>
public ushort[] Data;
}
4. Lifecycle and Management¶
4.1 ND-500 Program Lifecycle¶
stateDiagram-v2
[*] --> Created: Load ND-500 Code
Created --> Initialized: Initialize Process Descriptor
Initialized --> Inactive: SENDE=0, RECE setup
Inactive --> Active: XACT500 / Activation Message
Active --> Running: ND-500 executes code
Running --> Waiting: Waiting for ND-100 I/O
Waiting --> Active: I/O Complete
Running --> Active: Yield/Message wait
Active --> Inactive: 5RTOFF / Inhibit
Inactive --> Active: 5RTON / Enable
Active --> Terminated: TERM5 / Terminate
Terminated --> [*]
note right of Created
Process descriptor allocated
Message buffer created in 5MPM
end note
note right of Active
SENDE>0
Can send messages
Scheduled by ND-500
end note
note right of Waiting
Blocked on ND-100 I/O
DVIO/DVINST in progress
Message in monitor queue
end note
4.2 Activation: XACT500¶
From MP-P2-N500.NPL line 692:
CC5CPU=:B; CALL XACT500
XACT500 routine (simplified):
SUBR XACT500
XACT500:
% B = ND-500 CPU datafield
T:=B.HDEV+LCON5; A:=...; *IOXT % Load control register
T:=B.HDEV+LTAG5; A:=3START; *IOXT % TAG-OUT: Start operation
% ND-500 now activates the process
EXIT
What happens: 1. ND-100 sends activation message to ND-500 2. ND-500 microcode reads message buffer 3. ND-500 loads process context 4. ND-500 starts executing process code 5. Process runs until: - I/O request (sends message back to ND-100) - Completion (sends termination message) - Error (sends error message)
4.3 Deactivation and Termination¶
SUBR TER500
TER500:
% B = ND-500 CPU datafield
T:=B.HDEV+TERM5; *IOXT % Hardware terminate
% Or send termination message
EXIT
Termination process:
1. ND-100 sends TERM5 to ND-500 hardware
2. ND-500 stops process execution
3. Process descriptor marked inactive (SENDE=0)
4. Message buffers cleared
5. Resources released
5. Communication Mechanisms¶
5.1 Message Passing Flow¶
sequenceDiagram
participant RT as RT Program(ND-100)
participant Kernel as SINTRAN Kernel
participant MPM as 5MPM(Message Buffer)
participant Proc as ND-500 Process
RT->>Kernel: MON call (DVIO)
Note over Kernel: Find ND-500 datafield
Kernel->>Kernel: Allocate/Get message buffer
Kernel->>MPM: Write message(Function, addresses, data)
Kernel->>Kernel: CNVWADR (address translation)
Kernel->>MPM: Set 5ITMQUEUE flag
Kernel->>Proc: Interrupt ND-500(via LTAG5)
Proc->>MPM: Read message
Note over Proc: Process request(Graphics, DB, etc.)
Proc->>MPM: Write response(Status, data)
Proc->>Kernel: Interrupt ND-100(Level 12)
Kernel->>MPM: Read response
Kernel->>Kernel: Process result
Kernel->>RT: Return to RT program
5.2 Special: No Direct Scheduling¶
CRITICAL DIFFERENCE:
RT Programs:
SINTRAN Scheduler → Pick from EXEC Queue → Load ACTPRI → TRR PCR → Execute
ND-500 Programs:
SINTRAN sends message → ND-500 internal scheduler → ND-500 executes → Send message back
ND-100 does NOT directly schedule ND-500 processes! It only: 1. Sends activation/deactivation messages 2. Handles I/O requests from ND-500 3. Manages resources on behalf of ND-500 processes 4. Coordinates between RT programs and ND-500 processes
6. Special Monitor Calls¶
6.1 ND-500 Specific MON Calls¶
| MON Call | Purpose | Difference from RT |
|---|---|---|
| DVIO | Data I/O | Proxied through ND-100 to actual device |
| DVINST | Direct input/output | Same as DVIO but direct |
| 5MONICO | Restart ND-500 process after MON call | Special: Updates message buffer, sends to ND-500 |
| EMONICO | Restart with error code | Returns error to ND-500 process |
| XACTRDY | Mark process ready | Updates ND-500 descriptor |
6.2 5MONICO - The Key Restart Routine¶
From RP-P2-MONCALLS.NPL line 3226:
T:=CLM; CALL 5MONICO % Return status to ND-500 proc.
CALL ACTRDY % Restart process
CALL LOWACT500; SVB=:B % Start ND-500
What 5MONICO does: 1. Updates message buffer with results 2. Clears error flags 3. Sets completion status 4. Does NOT load into execution queue (like regular RT) 5. Instead: Sends message to ND-500 to continue execution
6.3 EMONICO - Error Restart¶
From MP-P2-N500.NPL line 962:
X:=CSWPM; CALL EMONICO % Restart proc. with error code
CALL XACTRDY
EMONICO operation:
1. Writes error code to message buffer ErrorCode field
2. Sets error flags in message
3. Sends notification to ND-500
4. ND-500 process receives error and handles it
7. Memory Management¶
7.1 Memory Regions¶
ND-100 Memory Spaces:
┌─────────────────────────────────────────────────────────────┐
│ ND-100 Physical Memory │
│ - RT Program Code/Data (via PITs) │
│ - SINTRAN Kernel │
│ - Device Datafields │
│ - RT-Descriptions │
└─────────────────────────────────────────────────────────────┘
Multiport Memory (5MPM):
┌─────────────────────────────────────────────────────────────┐
│ Accessible by BOTH ND-100 and ND-500 │
│ - ND-500 Process Descriptors (S500S - S500E) │
│ - Message Buffers (one per ND-500 process) │
│ - DMA Transfer Buffers │
│ - ACCP Buffers (communication protocol) │
│ - OCTOBUS Buffers (network) │
│ - HW Buffers (hardware interface) │
└─────────────────────────────────────────────────────────────┘
ND-500 Memory:
┌─────────────────────────────────────────────────────────────┐
│ ND-500 Private Memory │
│ - Process Code │
│ - Process Data │
│ - Stack │
│ - ND-500 Data Segments (F5DSG - L5DSG on ND-100 disk) │
└─────────────────────────────────────────────────────────────┘
7.2 ND-500 Data Segments¶
From PH-P2-OPPSTART.NPL lines 1420-1434:
"F5DSG"=:CSGNO*5SEGSIZE+SEGSTART=:X
T:=SEGTBANK; *SEGLE@3 LDATX
A=:CSGSIZE % ND-500 data segment size
...
DO WHILE CSGNO><"L5DSG" % For each ND-500 segment
...
NXMADR; T:=SEGTBANK; *MADR@3 STATX % Mass storage of ND-500 data segm
...
OD
ND-500 Data Segments:
- Stored on ND-100 disk (symbols F5DSG to L5DSG)
- Loaded into ND-500 memory when process starts
- Each process can have multiple segments
- Managed by SINTRAN segment system
- Can be marked 5INHB (inhibited) if not used
8. Process States¶
8.1 State Flags¶
/// <summary>
/// ND-500 Process state flags (in descriptor Status field).
/// </summary>
[Flags]
public enum ND500ProcessState : ushort
{
Inactive = 0,
/// <summary>Process can send messages (SENDE > 0)</summary>
SendEnabled = 1 << 0,
/// <summary>Process can receive messages</summary>
ReceiveEnabled = 1 << 1,
/// <summary>Process is currently running on ND-500 CPU</summary>
Running = 1 << 2,
/// <summary>Process is waiting for ND-100 I/O</summary>
WaitingForIO = 1 << 3,
/// <summary>Process has error condition</summary>
Error = 1 << 4,
/// <summary>Process is inhibited (5RTOFF equivalent)</summary>
Inhibited = 1 << 5,
/// <summary>Process is in ND-500 internal wait state</summary>
InternalWait = 1 << 6,
/// <summary>Message pending in buffer</summary>
MessagePending = 1 << 7
}
8.2 State Transitions¶
Unlike RT programs which have well-defined states in the STATE/PRIORITY word, ND-500 processes have distributed state:
- ND-100 side: Process descriptor status, message flags
- ND-500 side: ND-500 internal process state
- Coordination: Via message passing
Example state check:
T:=5MBBANK; X:=PROC_DESC; *AAX SENDE@3; LDATX
IF A=0 THEN
% Process is inactive, cannot send
ELSE
% Process is active, can send messages
FI
9. C# Implementation¶
9.1 Complete ND-500 Process Reader¶
/// <summary>
/// Reads ND-500 process information from multiport memory.
/// </summary>
public class ND500ProcessReader
{
private readonly IMemoryAccess _memory;
// Symbol addresses (read from symbol files or configuration)
private ushort _s500sAddr; // Start of process table
private ushort _s500eAddr; // End of process table
private ushort _5prdSize; // Size of each descriptor
private ushort _5mbBank; // 5MPM bank number
public ND500ProcessReader(IMemoryAccess memory,
ushort s500s, ushort s500e,
ushort prdSize, ushort mbBank)
{
_memory = memory;
_s500sAddr = s500s;
_s500eAddr = s500e;
_5prdSize = prdSize;
_5mbBank = mbBank;
}
/// <summary>
/// Get all ND-500 processes.
/// </summary>
public List<ND500ProcessInfo> GetAllND500Processes()
{
var processes = new List<ND500ProcessInfo>();
// Calculate max processes
int maxProcs = (_s500eAddr - _s500sAddr) / _5prdSize;
ushort addr = _s500sAddr;
for (int i = 0; i < maxProcs; i++)
{
var proc = ReadProcessDescriptor(addr, i);
if (proc != null && proc.IsValid)
{
processes.Add(proc);
}
addr += _5prdSize;
}
return processes;
}
/// <summary>
/// Read ND-500 process descriptor.
/// </summary>
private ND500ProcessInfo ReadProcessDescriptor(ushort addr, int processNum)
{
// Read from 5MPM using bank addressing
var desc = new ND500ProcessInfo
{
ProcessNumber = processNum,
DescriptorAddress = addr,
ProcessDescriptorAddr = _memory.ReadWord(addr + 0),
MessageBufferAddr = _memory.ReadWord(addr + 1),
Status = _memory.ReadWord(addr + 2),
SendEnabled = _memory.ReadWord(addr + 3),
ReceiveState = _memory.ReadWord(addr + 4)
};
// Read message buffer if valid
if (desc.MessageBufferAddr != 0)
{
desc.MessageBuffer = ReadMessageBuffer(desc.MessageBufferAddr);
}
return desc;
}
/// <summary>
/// Read message buffer.
/// </summary>
private ND500MessageInfo ReadMessageBuffer(ushort addr)
{
return new ND500MessageInfo
{
ProcessLink = _memory.ReadWord(addr + 0),
MessageFlags = _memory.ReadWord(addr + 1),
FunctionCode = _memory.ReadWord(addr + 2),
ErrorCode = _memory.ReadWord(addr + 3),
ToDatafield = _memory.ReadDoubleWord(addr + 4),
ByteCount = _memory.ReadDoubleWord(addr + 6),
ND500LogicalAddr = _memory.ReadDoubleWord(addr + 8),
ND100PhysicalAddr = _memory.ReadDoubleWord(addr + 10),
MicrocodeFunction = _memory.ReadWord(addr + 12),
DITNumber = _memory.ReadWord(addr + 13)
};
}
}
/// <summary>
/// ND-500 Process information for display.
/// </summary>
public class ND500ProcessInfo
{
public int ProcessNumber { get; set; }
public ushort DescriptorAddress { get; set; }
public ushort ProcessDescriptorAddr { get; set; }
public ushort MessageBufferAddr { get; set; }
public ushort Status { get; set; }
public ushort SendEnabled { get; set; }
public ushort ReceiveState { get; set; }
public ND500MessageInfo MessageBuffer { get; set; }
/// <summary>Is descriptor valid?</summary>
public bool IsValid => ProcessDescriptorAddr == DescriptorAddress;
/// <summary>Can process send messages?</summary>
public bool CanSend => SendEnabled != 0;
/// <summary>Is process active?</summary>
public bool IsActive => CanSend && (Status & 0x80) == 0; // No error bit
/// <summary>Get state description.</summary>
public string StateDescription
{
get
{
if (!CanSend) return "INACTIVE";
if ((Status & 0x80) != 0) return "ERROR";
if ((MessageBuffer?.MessageFlags & 0x01) != 0) return "MSG_PENDING";
return "ACTIVE";
}
}
}
/// <summary>
/// Message buffer information.
/// </summary>
public class ND500MessageInfo
{
public ushort ProcessLink { get; set; }
public ushort MessageFlags { get; set; }
public ushort FunctionCode { get; set; }
public ushort ErrorCode { get; set; }
public uint ToDatafield { get; set; }
public uint ByteCount { get; set; }
public uint ND500LogicalAddr { get; set; }
public uint ND100PhysicalAddr { get; set; }
public ushort MicrocodeFunction { get; set; }
public ushort DITNumber { get; set; }
/// <summary>Is message in monitor queue (ready to process)?</summary>
public bool InMonitorQueue => (MessageFlags & 0x01) != 0; // 5ITMQUEUE
/// <summary>Get function name.</summary>
public string FunctionName => FunctionCode switch
{
1 => "DVIO (Output)",
2 => "DVINST (Input)",
3 => "File Operation",
_ => $"Function {FunctionCode}"
};
}
9.2 Display ND-500 Processes¶
/// <summary>
/// Display ND-500 processes in debug window.
/// </summary>
public string RenderND500Processes()
{
var reader = new ND500ProcessReader(_memory, S500S, S500E, PRDSIZE, MBBANK);
var processes = reader.GetAllND500Processes();
var sb = new StringBuilder();
sb.AppendLine("╔══════════════════════════════════════════════════════════════════════════════╗");
sb.AppendLine("║ ND-500 Processes ║");
sb.AppendLine("╚══════════════════════════════════════════════════════════════════════════════╝");
sb.AppendLine();
sb.AppendLine($"Total ND-500 Processes: {processes.Count}");
sb.AppendLine($"Active: {processes.Count(p => p.IsActive)}");
sb.AppendLine();
sb.AppendLine("┌──────┬────────────┬────────────────┬──────────────┬────────────────────────┐");
sb.AppendLine("│ Proc │ Descriptor │ Message Buffer │ State │ Current Operation │");
sb.AppendLine("├──────┼────────────┼────────────────┼──────────────┼────────────────────────┤");
foreach (var proc in processes)
{
var desc = OctalHelpers.ToOctal(proc.DescriptorAddress, 6);
var msgBuf = OctalHelpers.ToOctal(proc.MessageBufferAddr, 6);
var state = proc.StateDescription.PadRight(12);
var func = proc.MessageBuffer?.FunctionName ?? "Idle";
sb.AppendLine($"│ {proc.ProcessNumber,2} │ {desc} │ {msgBuf} │ {state} │ {func,-22} │");
}
sb.AppendLine("└──────┴────────────┴────────────────┴──────────────┴────────────────────────┘");
return sb.ToString();
}
Summary¶
Key Takeaways¶
-
ND-500 programs are NOT RT programs - They are shadow processes on a separate CPU
-
Different control structures:
- RT programs: RT-Description (26 words) at
026000₈ - ND-500 programs: Process Descriptor (5PRDSIZE words) at
S500S-S500Ein 5MPM
- RT programs: RT-Description (26 words) at
-
Message-based communication - Not direct MON calls
-
No direct scheduling - SINTRAN sends messages, ND-500 schedules internally
-
Shared memory is key - 5MPM contains all coordination structures
-
Special monitor calls - 5MONICO, EMONICO instead of regular restart
-
Address translation critical - CNVWADR converts for DMA access
-
Distributed state - State exists on both ND-100 and ND-500 sides
ND-500 programs enable offloading compute-intensive tasks (graphics, database, protocols) while SINTRAN maintains overall system control!
For more details: - 05-ND500-DMA-KERNEL.md - DMA and address translation - 04-MMU-CONTEXT-SWITCHING.md - MMU and PIT usage - Analysis\ND500\MP-P2-N500.md - Complete API reference