Skip to content

MON 67B (octal) - OutBufferSpace (OSIZE)

Returns the number of bytes that can still be written to a device's output buffer before the calling program must wait - i.e. bytes FREE, not bytes used. Not available for internal devices. This is an ND-100 monitor call.

Status: dispatch head byte-proven (GOTAB[67B] = 121372B = F1642); the candidate worker body (OSIZE = 044231B) is real SINTRAN L bytes but is not statically reachable from the F1642 stub - the MON 67 -> OSIZE link crosses an uncarved kernel bridge (see Honest caveats). All addresses/values are octal.


Dispatch path

flowchart LR
    A["User program<br/>MON 67B"] --> B["ENT14 level-14<br/>T = MON number"]
    B --> C["GOTAB[67B] = 121372B<br/>(byte-proven)"]
    C --> D["F1642 entry stub<br/>025-S3IRPIT :121372B"]
    D -.uncarved CALLPROC.-> E["OSIZE buffer-scan worker<br/>commoncode :044231B"]
    E --> F["per-device free-space<br/>via IOXT + POF/PON reads"]
    class A blue
    class B,C,D teal
    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 dashed hop (D ⇢ E) is the resident CALLPROC/segment-switch - it is not present in any carved segment, so it is the one link that cannot be followed statically. F1642 sets up registers, MST PIE / EXIT, and re-enters via a runtime-populated pointer; its three direct jumps all stay inside overlay 025 and its one readable indirect pointer (116036B) is not 044231.


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[67] dispatch word commoncode.asm · .hex 071322B (1 word) 58788 GOTAB+67 = 121372B VERIFIED
F1642 entry stub 025-S3IRPIT.asm · .hex 121372B-121417B (21 words) 56820 F1642 VERIFIED
resident CALLPROC bridge - (uncarved) - - CALLPROC UNVERIFIED
OSIZE worker body (candidate) commoncode.asm · .hex 044231B-044427B (127 words) 37170 OSIZE real bytes; link MISATTRIBUTED

There is no MFELL -> CALLPROC fall-through row: GOTAB[67] is non-zero (121372B), so the level-14 handler is the F1642 stub, not a resident fall-through path.

Verify by hand: grep '071322' ../../segments-ref/SINTRAN-DATA_commoncode/SINTRAN-DATA_commoncode.hex -> 71322 121372 242 372 58788 (the GOTAB word = 121372B); then dd if=../../../resident/SINTRAN-DATA_commoncode.bin bs=1 skip=58788 count=2 2>/dev/null | od -An -tx1 -> a2 fa (= octal 121372). For the stub first word: dd if=../../../segments/025-S3IRPIT.bin bs=1 skip=56820 count=2 2>/dev/null | od -An -tx1 -> cc 6f (= octal 146157, F1642's first word).


Instruction walkthrough

Full listing: 067B-OutBufferSpace.ASM. The functional body is the OSIZE worker (region B); the F1642 stub (region A) is the level-14 entry.

F1642 entry stub (121372-121417) - a 21-word compiler wrapper (label F1642, next symbol F1643=121417B). It stages saved registers (RADD CLD SA DX/DB/DL), enables interrupts (121400 MST PIE) and returns (121401 EXIT). Three direct jumps (JMP 4 -> 121410, JMP -44 -> 121343, JMP -17 -> 121371) all land inside overlay 025; the one indirect call (121405 JPL I 10) dereferences pointer word @121415 = 116036B, a runtime-populated value that does not resolve to the OSIZE body. Words 121411-121416 decode as instructions but are constant/pointer data, and 121417.. is 000000 padding. So beyond those resolved hops the stub's control flow is not byte-closable from a static decode.

OSIZE worker prologue (044231-044240) - frame/pointer setup relative to B, clears working locals (STZ), moves the I/O interrupt-enable words into CPU regs (LDA 107 / TRR IIE / TRA IIC), and sets X as the loop index at the loop head 044240.

Per-device scan loop (044240-044342) - loads a double-word device-table entry (044241 LDD I ,X 104, stride 2 words), tests an end-of-table sentinel (044243 SKP IF DA UEQ ST -> JMP 77 -> 044343), and skips empty slots (044245 JAZ -> 044337). For a live device it does a device I/O status read (044250-044252 LDT / AAT 2 / IOXT) and branches on device class (044255 JAZ -> 044304).

Buffer-pointer arithmetic, two class paths - 044256-044303: masks fields (AND 67, SHA ZIN SHR 6), reads the buffer descriptor with interrupts off (044267 POF ... 044270 LDD ,X 0 ... 044271 PON), compares head vs tail, and conditionally zeroes the pair (buffer empty) before 044303 JMP 34 -> 044337. - 044304-044330: alternate path selected by BSKP ONE 60/100 DD bit tests; at 044320 JPL I 27 -> 044347 is an indirect call through the pointer word at 044347. Computes a masked/shifted value and stores it via STA ,X 27.

Result store (044331-044336) - RADD SD DA / SWAP SD DA assemble the free-byte count into A, then STD I ,X 15 stores the result (paging-mode bit SSPTM toggled around the store).

Loop advance (044337-044342) - index += 2 (AAA 2), JMP -102 -> 044240 back to the loop head.

Data / tail (044343-044427) - 044343 JMP 10 -> 044353 jumps over a data/pointer block (044344-044352, e.g. pointer word 000215B at 044347). The tail 044353-044427 is a second scan with more indirect worker calls and IOT-style transfers; its exact role (a sibling buffer routine sharing the segment) is UNVERIFIED. There is no explicit EXIT/skip-return inside 044231-044336, consistent with a called worker rather than a top-level MON entry.


Parameter / register contract

Reg / field Dir Meaning Verdict
A in logical device number (1 = own terminal) inferred (manual behaviour; not isolable from this carve)
A out number of bytes free in the output buffer inferred; the count is assembled by RADD SD DA / SWAP SD DA and stored via STD I ,X 15 (the compute is VERIFIED from bytes)
device table in scanned via LDD I ,X 104, stride 2 words VERIFIED (bytes)
IOXT - per-device status read inside the loop VERIFIED (bytes)
skip return / error out no in-body skip-return; internal-device / illegal-LDN errors would be raised by the F1642 entry wrapper inferred

The exact ZAREG/ZXREG/ZTREG save-area mapping and the user-visible A/X/T convention live in the caller-side MON 67 wrapper and the uncarved CALLPROC frame, so the precise register contract is inferred, not byte-proven here.


Pseudo-code (for an emulator)

See 067B-OutBufferSpace.pseudo.c - a pseudo-C model of the handler for emulator authors. The control flow of both regions is byte-verified; the semantic labels (which field is head/tail, the A-in/A-out register roles) are inferred from the call structure and the manual, and the F1642 -> OSIZE bridge is modelled but not proven. Every instruction is translated per the canonical ND-100 Instruction Semantics reference.


Honest caveats

What is byte-proven: GOTAB[67B] = 121372B (level-14 dispatch; prove-mon.py 067 reads commoncode file byte 0xe5a4 = a2 fa = 121372). The F1642 stub at 121372B is real code (its first word 146157B matches the disassembly, and F1643=121417B bounds it at 21 words). The OSIZE worker entry bytes at 044231B (060730B ...) match the disassembly and describe a per-device buffer scan using IOXT, interrupt-guarded (POF/PON) double-word reads, and pointer arithmetic that assembles a count - consistent with computing output-buffer free space.

What is NOT proven: the link from the F1642 stub (in 025-S3IRPIT) to the OSIZE worker (in resident commoncode). F1642's three direct jumps stay inside overlay 025 (121410/121343/121371), and its one readable indirect pointer is 116036B - not 044231. F1642 returns via MST PIE / EXIT; the transfer to the resident worker goes through the resident CALLPROC/second-level dispatch, which lives in an uncarved overlay. So the MON 67 -> OSIZE attribution rests on the symbol name + the matching "free output-buffer space" behaviour, not a followed pointer - hence MISATTRIBUTED in the strict sense.

This reconciles the two earlier notes into one story: the dispatch head (GOTAB -> F1642) is solid; the OSIZE body is real bytes and a plausible worker; only the middle hop is open. Note also a numeric coincidence - 044231 falls inside overlay 025's word span, but OSIZE=044231 is defined in the resident image (base 0), a different physical location; do not conflate them. A second OSIZE=111254 exists in N500-SYMBOLS (ND-500 side); this folder documents the ND-100 resident 044231 body only. Confirming the bridge needs a live trace (break at 121372B on a real MON 67, single-step the segment switch, confirm P lands on OSIZE=044231).

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