Skip to content

MON 32B (octal) - OutMessage (MSG)

Writes a message string to the calling program's terminal (maximum 512 characters). This is convenient for error messages from background programs. On the ND-100 and ND-500 it is available to all users; the message text is passed by address and written character-by-character to the user's terminal.

Status: GOTAB dispatch head byte-proven as fall-through (GOTAB[32B] = 000000, no per-call stub); the MSG worker body is real SINTRAN L bytes in segment 025-S3IRPIT (the SYMBOL-2-LIST code overlay - the parallel 026-S3IMPIT overlay holds unrelated float/data at the same address). The exact MON 32 -> worker link crosses an uncarved kernel bridge (see Honest caveats). All addresses/values are octal.

  • Full disassembly: 32B-OutMessage.ASM - the actual code (the MSG worker body; there is no entry stub because the GOTAB slot is zero).
  • Bytes live once in the canonical segment layer: ../../segments-ref/.

Dispatch path

flowchart LR
    A["User program<br/>MON 32B"] --> B["ENT14 level-14<br/>T = MON number"]
    B --> C["GOTAB[32B] = 000000<br/>(byte-proven: fall-through)"]
    C -.uncarved MFELL / CALLPROC.-> E["MSG out-message worker<br/>025-S3IRPIT :102453B"]
    E --> F["character loop:<br/>LBYT fetch + emit"]
    class A blue
    class B,C blue
    class E,F 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 GOTAB slot is zero, so there is no per-call entry stub. The dashed hop (C -> E) is the resident MFELL/CALLPROC fall-through second-level dispatch - it is not present in any carved segment, so it is the one link that cannot be followed statically.


Code location (dispatch path)

Every row is a real region you can open. Byte offset = (addr - loadbase) in octal words x 2.

Role Segment (full disasm) Addr range (octal) Byte offset Symbol Verdict
GOTAB[32] dispatch word commoncode.asm - .hex 071265B (1 word) 58730 GOTAB+32 = 000000 VERIFIED (fall-through)
resident MFELL/CALLPROC bridge - (uncarved) - - MFELL/CALLPROC UNVERIFIED
MSG out-message worker body 025-S3IRPIT.asm - .hex 102453B-102514B (code) + 102515B-102524B (link cells) 41558 MSG real bytes; link MISATTRIBUTED

The window is bounded strictly to the next symbol GERDV=102525B (42 words). Words 102453B-102514B are code; 102515B-102524B are a pointer table (link cells) the JPL I / JMP I indirections dereference - nd100-dis renders them as bogus instructions but they are data.

Verify by hand: grep '^102453 ' ../../segments-ref/025-S3IRPIT/025-S3IRPIT.hex -> byte offset 41558; then dd if=../../../segments/025-S3IRPIT.bin bs=1 skip=41558 count=8 | od -An -tx1 -> ba 23 51 08 49 0f cc 69 (= octal 135043 050410 044417 146151 = JPL I 43 / LDT ,B 10 / LDA ,B 17 / RADD CLD SA DD, the MSG entry).

The GOTAB slot itself: dd if=../../../resident/SINTRAN-DATA_commoncode.bin bs=1 skip=58730 count=2 | od -An -tx1 -> 00 00 (= 000000, fall-through). prove-mon.py 32 reads the same GOTAB zero.


Instruction walkthrough

Full listing: 32B-OutMessage.ASM. The body is the MSG worker (there is no F16xx stub because GOTAB[32] = 0).

Entry + setup (102453-102462) - 102453 JPL I 43 (link cell 102516) calls the shared resident prologue worker; 102454-102461 build the terminal output descriptor from the local B-frame; 102462 MST PIE masked-sets the interrupt-enable register from A.

Character loop (102463-102504) - 102463 clears X (the index); 102464 LDT 34 loads the remaining character count; 102465 SKP IF DT GRE SX continues while T > X. Each iteration 102470 LBYT fetches one character; 102471 SAT 47 / 102474 SAT 44 compare it against the control bytes 47B/44B and 102500/102502 JPL -31/-33 -> 102447 call the preceding in-segment emit routine; 102503 AAX 1 advances and 102504 JMP -20 -> 102464 loops.

Finish (102505-102514) - 102505 JPL I 14 (link 102521) is a resident worker; 102506 RADD CLD SX DA / 102507 SHA ZIN SHR 1 halves the emitted count (bytes -> words); 102511 ADD ,B 10 / 102512 STA ,B 10 fold it back into the frame; 102513 JPL I 7 (link 102522) and the tail 102514 JMP I 7 (link 102523) return through the resident exit.


Parameter / register contract

Manual-side names/types are from 32B_OutMessage.yaml.

Reg / field Dir Meaning Verdict
entry point in 102453B = MSG worker entry (fall-through, no stub) VERIFIED (bytes)
X (manual) in address of the string to write to the terminal (LDX (TEXT) inferred (manual MAC example)
Message in STRING, max 512 characters inferred (manual)
T internal character count driving the scan loop (LDT 34, SKP IF DT GRE SX) VERIFIED (bytes); count source inferred
control bytes 47B/44B internal per-character class test (SAT 47/SAT 44) VERIFIED (bytes); meaning inferred
B+10 internal/out running emitted-word count (ADD ,B 10 / STA ,B 10) VERIFIED (bytes)

The user-visible X = string-address convention lives in the caller-side MON 32 wrapper and the uncarved MFELL/CALLPROC frame, so the precise register-to-field assignment is inferred from the manual, not byte-proven here.


Pseudo-code (for an emulator)

See 32B-OutMessage.pseudo.c - a pseudo-C model of the handler for emulator authors. The control flow (character loop, LBYT fetch, the two byte comparisons, the emit calls, the halving shift, and the indirect resident tail) is byte-verified; the register/field semantics and the exact 47B/44B character-class meaning are inferred from the manual and the code shape.

Every instruction in the pseudo-code is translated against the canonical ND-100 instruction semantics reference (RADD CLD copy idiom, MST PIE masked-set, LBYT byte load, SKP compare senses, SHA ZIN SHR logical shift, addressing-mode effective addresses).


Honest caveats

What is byte-proven: GOTAB[32B] = 000000 (level-14 dispatch, a fall-through with no per-call vector); the MSG worker body at 102453B in 025-S3IRPIT is real code (entry bytes 135043 050410 044417 146151 match the disassembly); and it is a terminal output loop (LBYT fetch + per-character emit + word-count fold-back), consistent with OutMessage.

Which overlay and why: MSG=102453B is a SYMBOL-2-LIST symbol. 025-S3IRPIT is the SYMBOL-2-LIST code overlay - its companion MON-32-family code is real here, whereas the parallel 026-S3IMPIT overlay holds unrelated float/data words at 102453B (FAD ,X ,B ...). So 025-S3IRPIT is the segment that carries the real MSG worker; 026-S3IMPIT is a different overlay image at the same load base.

What is NOT proven: the link from the zero GOTAB slot to the MSG worker. Because the vector is zero there is no stub to disassemble and no pointer to dereference; dispatch drops into the resident MFELL/CALLPROC second-level path, which lives in an uncarved overlay. So the MON 32 -> MSG attribution rests on the MSG symbol name + the matching output behaviour, not a followed pointer - hence MISATTRIBUTED in the strict sense. The JPL -31/-33 -> 102447 calls target the preceding in-segment routine (a shared emit worker); the link cells 102516/102517/102521/102522/102523 resolve to low resident addresses (000374, 004177, 004116, 001135, 010341) that are outside 025-S3IRPIT and are not resolved here. Confirming the dispatch link needs a live trace: issue a real MON 32, single-step the level-14 fall-through into the resident CALLPROC, and confirm P lands on MSG = 102453.

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