Skip to content

MON 504B (octal) - OutputString (DVOUTS / NPL NOUTSTR)

Writes a string of bytes to a device or open file from an ND-500 process - the pure output half of the DVIO output+input pair. All addresses/values are octal.

Status: handler body byte-proven (real SINTRAN L bytes at OSTRS=141205B, the level-12 output-string restart worker; shared entry NOUTS=141027B = DVIO). The MON 504B -> NOUTSTR GOSW-slot mapping is VERIFIED-from-NPL; the runtime level-12 GOSW dispatch that reaches it is an uncarved kernel path, so the MON 504 -> OSTRS link stays UNVERIFIED (see Honest caveats).


Dispatch path

MON 504B is an ND-500 level-12 monitor call (NPL name DVOUTS, System-Monitor GOSW handler NOUTSTR). It is not dispatched through the ND-100 monitor GOTAB - a GOTAB[504] probe lands on an unrelated datafield-pointer word (spurious). It arrives at the worker via the resident level-12 GOSW 5CMNO-L12MIN, slot 4 (base STAPROC=500B), VERIFIED from SINTRAN/NPL-SOURCE/NPL/MP-P2-N500.NPL (NOUTSTR is the 5th name in the GOSW).

flowchart LR
    A["ND-500 process<br/>MON 504B"] --> B["stop MOCALL<br/>level-12 driver"]
    B --> C["MCHANDEL reads<br/>MCNO = 504B"]
    C -.uncarved 5CMNO GOSW slot 4.-> D["NOUTSTR / OSTRS worker<br/>026-S3IMPIT :141205B"]
    D --> E["shared entry NOUTS=141027B<br/>(= DVIO output setup)"]
    class A blue
    class B,C teal
    class D,E green
    classDef blue fill:#E3F2FD,stroke:#0D47A1,color:#0D47A1
    classDef teal fill:#E0F7FA,stroke:#00838F,color:#00838F
    classDef green fill:#E8F5E9,stroke:#2E7D32,color:#2E7D32

The dashed hop (C -> D) is the resident level-12 GOSW (5CMNO-L12MIN, slot 4) - it is not present in any carved segment, so it is the one link that cannot be followed statically. The GOSW-slot-4 -> NOUTSTR mapping IS proven from the NPL source; only the runtime pointer-follow is unproven.


Code location (dispatch path)

Every row is a real region you can open. Byte offset = (addr - loadbase) in octal words x 2 (decimal). Handler load base = 32000B.

Role Segment (full disasm) Addr range (octal) Byte offset Symbol Verdict
GOTAB[504] probe (spurious) commoncode.asm · .hex 071735B reads 057414B 59322 (datafield-pointer word, not code) MISATTRIBUTED - ND-500 call is not in GOTAB
Level-12 GOSW dispatch — (uncarved resident level-12) MCHANDEL reads MCNO=504B; 5CMNO-L12MIN slot 4 — 5CMNO / L12MIN / NOUTSTR UNVERIFIED (runtime) / GOSW slot VERIFIED-from-NPL
Shared output entry 026-S3IMPIT.asm · .hex 141027B (= DVIO) 72750 NOUTS=141027B (shared with DVIO) VERIFIED (symbol)
OSTRS worker body 026-S3IMPIT.asm · .hex 141205B–141266B (EXIT) 72970 OSTRS=141205B; internal PT5RS=141256B VERIFIED
Trailing slice words 026-S3IMPIT.asm · .hex 141267B–141270B 73074 next-region entry; @141270B=141205B (-> OSTRS) VERIFIED (data; targets exact)

Verify by hand: grep '^141205 ' ../../segments-ref/026-S3IMPIT/026-S3IMPIT.hex → byte offset 72970; then dd if=../../../segments/026-S3IMPIT.bin bs=1 skip=72970 count=8 | od -An -tx1 → cc 65 08 fe ba 13 ba 13 (= octal 146145 004376 135023 135023 …, the OSTRS entry RADD CLD SL DA / STA -2 / JPL I 23 / JPL I 23).


Instruction walkthrough

Full listing: 504B-OutputString.ASM. The 52-word slice is the OSTRS worker (141205B..141266B, closing at EXIT) plus two trailing words carved in only to make one contiguous block.

Entry / dispatch setup (141205..141231) - 141205 RADD CLD SL DA / 141206 STA -2 compose a value in A, then 141207 / 141210 JPL I 23 dispatch indirectly through the pool at 141232..141233. 141211..141225 index a datafield (LDT I 22, AAX 37, LDATX, then AAX 134, LDDTX, STX I 11) and 141217 SKP IF DA EQL ST compares a loaded word - the equal case takes 141220 JMP 7 -> 141227 (the only in-window direct branch). 141226..141230 JPL I 11 dispatch again indirectly; 141231 JMP I -25 is the indirect exit of the not-selected path.

Pointer / literal pool (141232..141236) - data. nd100-dis renders these as instructions (STD I,B,X, STZ, STA,B, STT I), but they are the indirect-jump targets/literals the body reaches via JPL I 23 / JPL I 11 / STX I 11. Their exact worker addresses are not resolved from this segment's symbol table (UNVERIFIED - see caveats).

Device-output sequence (141237..141255) - a critical section: 141242 IOF disables interrupts, IRW 120 DB / IRW 120 DP write device control/data registers (LDA 6 / LDA 5 supply the values), 141250 MST PID sets status, 141251 ION re-enables interrupts, 141252 JMP I 3 -> 141255 continues indirectly. This is the byte-level "push the string out to the device" step (the exact device is INFERRED).

PT5RS continuation (141256..141265) - labelled PT5RS in the L07 SYMBOL-2-LIST; a second register block (IRW 140 DX/DL/DP, LDA 7/6/5, MST PID) - INFERRED to program the return-status / second channel path.

Exit (141266) - EXIT. The worker returns here into the level-12 message loop (reached indirectly, outside this slice). 141267 JPL I 75 -> 141364 and 141270 (data word = 141205B, a pointer back to OSTRS) are not part of the worker - they are the trailing words that round the slice to 52 contiguous words.


Parameter / register contract

ND-500 monitor calls pass parameters in the ND-500 message buffer (indexed by 5MBBANK + field displacement), not in ND-100 A/T/X user registers. The register use below is level-12 driver-internal.

Item Dir Meaning Verdict
arg 1: LDN / open file number in device or open-file selector manual (DVOUTS spec); not observed in these bytes
arg 2: number of bytes to write in output byte count manual (DVOUTS spec); range check is in the shared DVIO entry, not here
arg 3: string / array to write in the bytes to output manual (DVOUTS spec)
X / T (entry) in index the output datafield (LDT I 22, AAX 37, LDATX) VERIFIED (bytes)
141217 SKP IF DA EQL ST in select branch on a datafield compare VERIFIED (byte); meaning inferred
IRW 120 / IRW 140 writes out device control/data register writes under IOF..ION VERIFIED (bytes); target device inferred
Error EC174 (count > 4000B) out illegal output byte count inferred / shared with DVIO entry (SAA 174 lives at the 141041B DVIO region, not in this OSTRS slice)
Exit out EXIT at 141266B, then indirect return to the level-12 loop VERIFIED (byte)

Skip-return: none in the ND-100 sense; control leaves via the indirect jumps back into the level-12 dispatch loop.


Pseudo-code (for an emulator)

See 504B-OutputString.pseudo.c - a pseudo-C model of the OSTRS worker for emulator authors. Control flow (datafield indexing, the IOF..ION device-register writes, the PT5RS continuation, EXIT) is byte-verified; the semantic labels (which field, which device, the message-buffer layout) are inferred from the code and the manual's DVOUTS argument list, not independently proven from these bytes.

Every instruction is translated per ../../instruction-semantics/ND100-INSTRUCTION-SEMANTICS.md (the authoritative ND-100 semantics reference). The datafield indexing uses the T/X physical transfers LDATX / LDDTX: these form a 24-bit PHYSICAL address EL = ((T & 0377) << 16) | ((X + disp3) & 0177777) where T is the memory bank (the ND-500 message-buffer bank 5MBBANK) and X the word offset - the access bypasses the MMU / page tables (reference section 5). disp3 = 0 here because the code pre-adjusts X with AAX.


Honest caveats

What is byte-proven: the worker at OSTRS=141205B is real SINTRAN L code carved from 026-S3IMPIT (load 32000B). OSTRS=141205B and the shared entry NOUTS=141027B (= DVIO) both match the L07 SYMBOL-2-LIST; the internal continuation label PT5RS=141256B also matches. The entry bytes (146145 004376 135023 135023 …) reproduce from the canonical segment (dd above), and the IOF..ION device-output critical section is present in the bytes. The MON 504 -> NOUTSTR GOSW-slot-4 mapping is proven from the NPL 5CMNO-L12MIN GOSW (NOUTSTR is the 5th name, base STAPROC=500).

What is NOT proven: - The runtime dispatch. MON 504 is an ND-500 level-12 call; it is not in GOTAB. GOTAB[504]=071735B reads 057414B, an unrelated datafield-pointer word, not a handler - a false lead reported only for honesty. The real path is the resident level-12 GOSW (MCHANDEL reads MCNO, 5CMNO-L12MIN slot 4), which lives in an uncarved overlay and cannot be followed statically. The NPL proves the slot; the pointer-follow does not. - The pool. Words 141232..141236 are data (indirect-jump targets/literals), not the instructions the disassembler prints, and their exact worker addresses are not resolved from this segment's symbol table. - The output-count range check. DVOUTS' > 4000B -> EC174 guard is in the shared DVIO entry region (~141041B, SAA 174), not in this OSTRS slice - hence marked inferred here. - NPL is a different revision than L. NPL carries the names (DVOUTS, NOUTSTR); the L bytes place the worker at OSTRS=141205B. Only behaviour and names carry over; the names were re-verified against the L07 symbol table above.

Confirming the full chain needs a live trace (break at the level-12 GOSW on a real ND-500 MON 504, single-step, confirm P lands on OSTRS=141205B).


Method: ../../../../../EXTRACTING-RESIDENT-CODE.md §7.6/7.7 · dispatch reality: ../../TASK-05-mismatches.md · master map: ../../MON-CALL-INDEX.md.