SWAPPER-K01 Program Segment (PSEG) - Pseudo-C Analysis¶
Analysis of the ND-500 program segment
SINTRAN/ND500/swapper/SWAPPER-K01.PSEG
and its disassembly
SINTRAN/ND500/swapper/swapper-k01-pseg.asm.
Companion documents: - Data segment:
SINTRAN/ND500/swapper/swapper-k01.dseg.md- Loader/monitor that places this domain:SINTRAN/ND500/nd-500-mon/nd-500-mon-j04.prog.md
All numbers in the disassembly and in this document are OCTAL unless prefixed 0x
(the disassembly was produced with nd500-dis -a -o -noansi -b 0x08000000).
Every claim here was read from the actual bytes or disassembly; anything not provable
from them is labelled inferred or unknown.
1. Summary¶
swapper-k01.pseg is the program (I-space) half of a two-segment ND-500 domain
{ PSEG, DSEG }. It is native ND-500 machine code, 38161 bytes (0x9511), disassembling
to 12046 lines. It is loaded into the ND-500 by the ND-100-side monitor
SINTRAN/ND500/nd-500-mon/nd-500-mon-j04.prog (the "ND-500/5000 MONITOR Version J04"), whose LOAD-SWAPPER /
START-SWAPPER commands place and start this domain.
What the code IS, from the bytes:
- A code segment based at ND-500 logical address
0x08000000(logical segment 1), I/D split: the same numeric address is a code word in I-space (this file) and a data word in D-space (the DSEG file). - 152 routines (152 entry prologues: 119
ents, 32entd, 1init), with 43 skip-return exits (retk). - It reaches SINTRAN / the ND-100 through exactly two kinds of trap:
- one
MON 0B(LEAVE / terminate) at1000000131, and - fifteen
MON 377Bcalls - the ND-500 monitor-call gate (a trap into logical segment 31, address0xF80000FF), each selecting a SINTRAN service by a descriptor operand that lives in the DSEG.
- one
It contains no ND-500 bus-interface register access of its own: it does not touch the 3022/5015 interface. As an ND-500 domain it cannot - the bus registers are ND-100 I/O space. It asks for services by trapping to the ND-100 through segment 31.
Architectural note (verified against
SINTRAN/ND500/old/SWAPPER-MON-DISPATCH.md): this PSEG is a specialised paging/swap worker domain and a client of SINTRAN. It is NOT the trap target for other ND-500 programs' monitor calls and contains no MON-number dispatch table. Do not read it as "the thing that services ND-500 MON calls".
2. Segment layout¶
| Region | I-space address | File offset | Content |
|---|---|---|---|
| Banner / build data | 1000000000..approx 1000000075 |
0x0000.. | ASCII build strings, not code (see 2.1) |
| Entry / startup | approx 1000000076..1000000136 |
first executable code, ends at MON 0B LEAVE |
|
| Routine body | 1000000137..end |
152 routines |
File offset = I-space address - 0x08000000.
2.1 Banner / build data (start of file)¶
The raw file begins with data words, not instructions. Decoded as ASCII they read
(non-printable shown as .):
.......BT....$..D..EJG....(..REV...MGJH....(..-K01..MH.G.H FD....E..../....@....
Legible fragments: REV, MGJH, -K01, MH, FD. These are build/revision tags:
-K01 is the segment version (matches the file name swapper-k01); MGJH / MH
are plausibly author or module initials (inferred); REV labels a revision field.
nd500-dis decodes this region as init/move/comp2 pseudo-ops because it is data,
not code - the first genuine routine begins at the entry/startup block. This is the
standard ND data-before-code pattern.
3. Routine inventory¶
Prologue / epilogue opcodes actually present (counts from the disassembly):
| Opcode | Count | Meaning |
|---|---|---|
ents |
119 | enter, save registers, allocate stack frame (single-word form) |
entd |
32 | enter double / enter with descriptor frame |
init |
1 | (in the banner data region - an artefact of data-as-code, not a real prologue) |
retk |
43 | return with SKIP (skip return = success/answer path) |
ret |
many | plain return (bare 200 byte) |
So the segment holds on the order of 151 real routines (119 + 32), reached by
internal call $0800xxxx / go $... transfers. Frame locals are addressed b.NN
(base-relative); ND-500 registers appear as w1..w4 (32-bit halves), r0..rN
(registers), and tos (top of stack).
A full per-routine map is impractical to hand-verify for all 151 without more time; the load-bearing routines - the entry/startup path and every routine that traps to SINTRAN - are reconstructed below and are the ones that matter for "how it talks to the ND-100".
4. Entry / startup path (verified)¶
Disassembly 1000000076..1000000136:
1000000076 if >< go $24 ; branch on a prior compare
1000000100 w1 := b.24 ; w1 = local(24)
1000000102 call $1000003057, $0 ; call own routine at 0x0800065F (in this PSEG)
1000000110 if -k go $12 ; if that routine took the NON-skip (error) return...
1000000112 r := b.0 ; ...set up result registers
1000000114 r := r.10
1000000116 tos := r.0 ; push result
1000000121 retk ; skip-return to caller (success)
1000000122 call $1000100645, $0 ; else call routine at 0x0800A1A5
1000000130 ifkret ; expect skip return
1000000131 call $0xF8000000, $0 ; MON 0B = LEAVE (terminate this ND-500 program)
Pseudo-C:
/* startup() - I-space 0x08000_003E (=1000000076) */
int startup(void)
{
if (compare_flag_set) /* 1000000076 if >< go $24 */
goto alt;
w1 = local24; /* 1000000100 */
if (routine_0800065F() == OK) { /* 1000000102 call; 1000000110 if -k go */
result.lo = local0; /* 1000000112..1000000116 */
result.hi = reg10;
push(result);
return SKIP; /* 1000000121 retk : success */
}
alt:
routine_0800A1A5(); /* 1000000122 */
/* 1000000130 ifkret : expect skip return */
MON_LEAVE(); /* 1000000131 MON 0B : terminate */
}
MON 0B (LEAVE) is the ND-500 program-termination monitor call: it hands control back
to the ND-500 monitor / SINTRAN. Its call target 0xF8000000 is segment 31 offset 0 -
the trap/escape segment - with MON number 0 in the low byte.
5. The SINTRAN monitor-call gate: MON 377B (verified, central)¶
Fifteen sites issue MON 377B. This is how this ND-500 domain requests ND-100 / SINTRAN
services. The mechanism, read directly from the bytes:
- Trap target
$1777777777777000000377= sign-extended0xF80000FF.0xF8000000is logical segment 31 (the escape/trap segment); the low byte0xFF= octal377is the gate index. Calling into segment 31 traps the ND-500 microcode, which signals the ND-100 (STOP-REASON = monitor call); the ND-100-side ND-500 driver then services it. (Mechanism perSINTRAN/ND500/ND500-MONITOR-CALL-MECHANISM.mdand.../ND500-BUS-INTERFACE-REFERENCE.md; the segment-31 trap is consistent with the0xF80000xxtargets seen here.) - Call shape:
call $0xF80000FF, <argcount>, <descriptor>, <arg2>, <arg3>, ...<argcount>is a literal ($2,$3,$4,$6,$7observed).<descriptor>is always a D-space pointer of the form$1000225xxx(0x080009xxregion of the DSEG) - it selects WHICH SINTRAN service is requested.- remaining operands are the service's parameters: D-space data pointers
(
$1000436xxx/$1000437xxx/$1000440xxx=0x08002xxx) or frame locals (b.NN,@b.NNindirect).
5.1 The local-wrapper-then-trap pattern¶
Every MON 377B is immediately preceded by a call to a local routine with the
same descriptor and argument list. Example at 1000000466:
1000000466 call $1000111601, $2, $1000225064, $1000436574 ; local wrapper 0x0800xxxx
1000000506 ifkret ; expect skip return
1000000507 call $0xF80000FF, $2, $1000225064, $1000436574 ; MON 377B (same args)
1000000527 ifkret
Pseudo-C:
/* request a SINTRAN service (descriptor 0225064B) */
if (local_pre_0800xxxx(2, DESC_0225064, ARG_0436574) == SKIP) {
/* pre-flight/local handling succeeded */
} else {
monitor_call(2, DESC_0225064, ARG_0436574); /* MON 377B : trap to ND-100 */
}
Interpretation (inferred): the local wrapper does an in-domain fast path / validation;
if it cannot complete the request locally it falls through to the real MON 377B trap
that crosses to the ND-100. The ifkret guards mean both the wrapper and the trap use
the ND-500 skip-return convention.
5.2 Descriptor operands observed (service selectors)¶
Count of each $1000225xxx descriptor across all callers (traps and local wrappers):
| Descriptor (octal addr) | D-space file offset | Uses |
|---|---|---|
$1000225014 |
0x0800_09?? region | 8 |
$1000225020 |
7 | |
$1000225044 |
14 | |
$1000225070 |
19 | |
$1000225110 |
49 | |
$1000225120 |
8 | |
| (others: 022,030,034,040,050,054,060,064,074,104,130) | 1-6 each |
The descriptors themselves live in the DSEG; their decoded contents and the exact
service each names are analysed in
SINTRAN/ND500/swapper/swapper-k01.dseg.md
(PSEG->DSEG cross-reference section). What is proven here from the PSEG side is the
mechanism and which descriptors are invoked how often - the heavily-used
$1000225110 (49x) and $1000225070 (19x) are the dominant services this domain asks
the ND-100 for. Mapping each descriptor to a named SINTRAN MON service requires reading
the descriptor bytes (see the DSEG document); it is unknown from the PSEG alone.
6. MON traps - complete list¶
| Site (octal) | Trap | Meaning |
|---|---|---|
1000000131 |
MON 0B |
LEAVE - terminate ND-500 program |
1000000507 |
MON 377B |
monitor-call gate, desc 0225064, 2 args |
1000001131 |
MON 377B |
desc 0225064, 2 args |
1000003167 |
MON 377B |
desc 0225040, 2 args |
1000010131 |
MON 377B |
desc 0225044, 7 args |
1000013600 |
MON 377B |
desc 0225044, 7 args |
1000014466 |
MON 377B |
desc 0225044, 7 args |
1000016502 |
MON 377B |
desc 0225044, 7 args |
1000020237 |
MON 377B |
desc 0225044, 7 args |
1000022231 |
MON 377B |
desc 0225054, 6 args |
1000023534 |
MON 377B |
desc 0225044, 7 args |
1000037154 |
MON 377B |
desc 0225044, 7 args |
1000041466 |
MON 377B |
desc 0225044, (multi-arg) |
1000044151 |
MON 377B |
desc 0225064, 2 args |
1000062726 |
MON 377B |
desc 0225060, 3 args |
1000101077 |
MON 377B |
desc 0225050, 4 args |
All fifteen MON 377B gates use the same trap address 0xF80000FF; they differ only in
descriptor and argument list. This is a single monitor-call convention used uniformly.
7. Control flow¶
7.1 Top-level shape¶
flowchart TD
START["ND-500 monitor: LOAD-SWAPPER / START-SWAPPER<br/>places this domain and starts it"]:::input
ENTRY["startup() I-space 1000000076<br/>check, call own routine 0800065F"]:::start
OK{"skip return<br/>(success)?"}:::special
WORK["151 worker routines<br/>(ents/entd frames, retk exits)"]:::proc
GATE["MON 377B gate<br/>trap to segment 31 = 0xF80000FF"]:::bus
ND100["ND-100 side: nd-500-mon-j04 + SINTRAN<br/>level-12 ND-500 driver services the call"]:::output
LEAVE["MON 0B LEAVE<br/>terminate ND-500 program"]:::special
START --> ENTRY --> OK
OK -- yes --> WORK
OK -- no --> LEAVE
WORK -->|request ND-100 service| GATE --> ND100
ND100 -->|answer via message buffer| WORK
WORK --> LEAVE
classDef input fill:#E3F2FD,stroke:#0D47A1,color:#0D47A1;
classDef start fill:#E3F2FD,stroke:#0D47A1,color:#0D47A1;
classDef proc fill:#E0F7FA,stroke:#00838F,color:#00838F;
classDef output fill:#E8F5E9,stroke:#2E7D32,color:#2E7D32;
classDef special fill:#F3E5F5,stroke:#7B1FA2,color:#7B1FA2;
classDef bus fill:#E0F2F1,stroke:#00695C,color:#00695C;
7.2 The monitor-call gate sequence¶
sequenceDiagram
participant W as Worker routine (PSEG)
participant L as Local wrapper (PSEG)
participant S31 as Segment 31 trap gate
participant D as ND-100 ND-500 driver
Note over W: needs a SINTRAN service
W->>L: call local_wrapper(argc, DESC, args...)
alt handled locally
L-->>W: retk (skip = success)
else must cross to ND-100
L-->>W: non-skip
W->>S31: call 0xF80000FF (MON 377B), argc, DESC, args...
S31->>D: microcode trap, STOP-REASON = monitor call
D-->>W: answer via message buffer, skip return
end
%% WCAG AA palette applied via node styling in flowcharts above
8. Data references¶
The PSEG references DSEG data in two address ranges:
$1000225xxx(=0x080009xx) - the monitor-call descriptors (service selectors), used only as the first argument of the gate calls.$1000436xxx/$1000437xxx/$1000440xxx/$1000246xxx/$1000461xxx/$1000507xxx(=0x08002xxx..0x0800Axxx) - parameter blocks and worker variables loaded, stored, incremented (w incr), tested (w test) and zeroed (w stz) by the routines.
The exhaustive PSEG->DSEG cross-reference (which DSEG address is touched from which PSEG
address, and whether it lands in initialised data or the zero/BSS region) is in
SINTRAN/ND500/swapper/swapper-k01.dseg.md.
It is not duplicated here.
9. Relationship to the residue symbol fragment¶
The ND-100 monitor file SINTRAN/ND500/nd-500-mon/nd-500-mon-j04.prog carries a leaked fragment of the
MON-DEBUG build's symbol table (extracted to
SINTRAN/ND500/nd-500-mon/nd-500-mon-j04-symtab1.sym
and ...-symtab2.sym). Those names (CACHEMODE, BRKDET/BRKFULL, STEPPING/STEPDONE,
DOWNLD, CSTEP, ECHOTEST, EVREP, DTBFUNC) belong to the ND-100 monitor, not to this
ND-500 swapper PSEG. They are listed here only to prevent confusion: do not map this
PSEG's routines to those symbols - there is no evidence they correspond.
10. Open questions / unknowns¶
- Descriptor -> named MON service. Each
$1000225xxxdescriptor selects a SINTRAN service; the mapping requires decoding the descriptor bytes in the DSEG (see the DSEG document). Unknown from the PSEG alone. - Per-routine purpose for the ~151 worker routines. Only the entry path and the
gate-calling routines are reconstructed. Naming all routines needs either the ND-500
symbol list
SINTRAN/ND500/swapper/N500-SYMBOLS.SYMBcross-referenced by address, or more analysis time. MGJH/MHbanner tags. Plausibly author/module initials; not proven.- Local-wrapper semantics. The pattern "local wrapper with same args, then MON 377B" is proven structurally; that the wrapper is a local fast-path/validation is inferred, not proven from the wrapper body (not yet decoded).
To settle (1) and (2): cross-reference
SINTRAN/ND500/swapper/N500-SYMBOLS.SYMB (7157 symbols,
NAME=octal) against these I-space addresses, and decode the descriptor words in the
DSEG. Both are mechanical once usage budget allows.