Skip to content

144B DeviceFunction

In progress   MON 144B (100 decimal) · Mnemonic MAGTP · Group: Device Handling (manual section 2.11)

Available from: All programs (manual compatibility box)

Emulation source: src/handlers/mon_144B_DeviceFunction.c

Description

Performs various operations on floppy disks, magnetic tapes, Versatec plotters, and SCSI streamers.

  • The parameter values depend on the device.
  • If the function code is in the range 5B to 24B, except 23B, the parameter buffer and the two device dependent parameters are dummies.
  • If the function code is in the range 20B to 24B, except 23B, the hardware status is returned.

Parameters

Name Type Direction Description
FunctionCode INTEGER2 In Function code. See the following pages.
Buffer INTEGER2[1024] In/Out Buffer used for data transfer to and from the device.
DeviceNo INTEGER2 In Logical device number (or open-file number). See appendix B.
DeviceParam1 INTEGER2 In First device dependent parameter. See the following pages.
DeviceParam2 INTEGER2 In Second device dependent parameter. See the following pages.

Direction: In = the program supplies the value, Out = the call returns it, In/Out = both.

See also

DeviceControl, @DEVICE-FUNCTION

Compatibility

Machines Users Programs
ND-100 and ND-500 All users All programs

The manual's compatibility box for this call, word for word.

Yes/no fields from the YAML extraction (not in the manual's words):

ND-100 ND-500 User programs RT programs System programs
Yes Yes Yes Yes No

Examples

From the manual (OCR text, not corrected).

INTEGER : DevNo, Func, Param1, Param2
BYTES : Buff(0:2047)
...
ON ROUTINEERROR DO
   IF ErrCode >‹ 0 THEN ...
ENDON
Monitor_Call(‘DeviceFunction‘, Func, Buff(0), DevNo, Param1, Param2)
INTEGER DevNo, Func, Param1, Param2
INTEGER Buff(1024)
...
Monitor Call('DeviceFunction', Func, Buff(1), DevNo, Param1, Param2)
IF (ErrCode .NE. 0) THEN ...
DevNo, Func, Param1, Param2 : INTEGER2;
Buff : ARRAY [0..63] OF RECORD...END;
...
DeviceFunction(Func, Buff, DevNo, Param1, Param2);
IF ErrCode <> 0 THEN ...
01 DevNo COMP.
01 Func COMP.
01 Param1 COMP.
01 Param2 COMP.
01 Buff.
   02 array COMP OCCURS 1024 TIMES.
01 ErrCode COMP.
...
MONITOR-CALL "DeviceFunction" USING Func, Buff, DevNo, Param1, Param2.
CALL "CbError" USING ErrCode.
IF ErrCode NOT = 0 GO ...
DevNo : W BLOCK 1
Func : W BLOCK 1
Param1 : W BLOCK 1
Param2 : W BLOCK 1
Buff : W BLOCK 1024
ErrCode : W BLOCK 1
DeviceFunction : EQU 3789 + 144B
...
CALLG DeviceFunction, 5, Func, Buff, DevNo, Param1, Param2
IF K GO ERROR
...
ERROR : W1 =: ErrCode                      %ErrorCode in W1 register.
LDA (PAR                             %Load register A with address of parameter list.
MON 144                              %Monitor call DeviceFunction.
STA STAT                             %Store status returned.
...
STAT, 0
PAR, FUNC                            %Function to be performed.
BUFF                                 %Address of buffer used for data transfer.
DEVNO                                %Logical device number.
PARA1                                %Device dependent parameter.
PARA2                                %Device dependent parameter.
...

FUNC, ...
BUFF, 0
**+120/                              %Make a buffer of 80 words.
DEVNO, ...
PARA1, ...
PARA2, ...

ndmonlib implementation

In progress Registered MON_STATUS_IN_PROGRESS: partly implemented. The dispatcher calls the handler.

Handler mon_144B_DeviceFunction
Code lines 79 (non-blank, non-comment lines in the file)

Notes from the handler source

src/handlers/mon_144B_DeviceFunction.c line 49

Function 0B - Read-Record.

The ND linker uses this to load its DDB tables: it OPENs 'DDBTABLES-G':VTM,
SETBTs the byte pointer to 0, then issues MAGTP(0, buffer, <that file>, ...)
and immediately requires the first word of the buffer to be 1
(0xB004AFB8: "w comp2 r.0x0,$0x1", else error 0x106A). The real
DDBTABLES-G06:VTM begins with 0x00000001 and carries 0x40-byte records at
+0x78, which is exactly where the linker indexes - so the file image maps
directly onto the buffer.

src/handlers/mon_144B_DeviceFunction.c line 75

Resume at the position the caller established (the linker sets it with
74B SETBT before calling), matching how 117B RFILE streams.

src/handlers/mon_144B_DeviceFunction.c line 137

UNVERIFIED: which parameter carries the transfer size. Table 9.1 lists
param2 as "octal no. of words", but the linker passes param1=4096 and
param2=3, and 4096 is the only value that can span the table it then
indexes (count at +0x0, 0x40-byte records from +0x78). The manual's
"following pages" that would settle the ND-500 parameter convention
are not in the scanned set. Treating param1 as a BYTE count is
therefore INFERRED - it is what the linker's own usage demands, not
something read from a manual. Revisit if another caller disagrees.

src/handlers/mon_144B_DeviceFunction.c line 148

Every other function code is a real device operation (tape motion,
formatting, hardware status) against hardware we do not emulate.
Returning benign SUCCESS keeps callers moving; it is NOT correct, and
the true return convention (status word / IO buffer format) is
UNVERIFIED. Do not port as final.

Emulation research

Source

This section comes from the emulation: block of the call's YAML file in the NDInsight repo. It records what was learned while implementing the call in nd500x; its status is nd500x's, not ndmonlib's.

Status (nd500x) partial
nd500x handler nd500x/src/libmon/handlers/mon_144B_DeviceFunction.c
Last updated 2026-07-17

Function codes

  • Radix: octal
  • Note: The manual body says only "Function code. See the following pages." THIS is that table. It is OCTAL - it skips 8 and 9, which is the giveaway.
  • Source

    • Doc: ND-60.050.06 SINTRAN III Users Guide
    • Page: 232
    • Table: 9.1
    • Codes

    1. 0

    Field Value
    Name Read-Record
    Description Reads a record from the device, or from the open file given by DeviceNo, into Buffer.
    Param1 Octal addr. of data buf. for area users to read (manual)
    Param2 Octal no. of words (manual)
    Status implemented

    2. 1

    Field Value
    Name Write-Record
    Param2 Octal no. of words
    Status not_implemented

    3. 5

    Field Value
    Name Unlock-and-Stop
    Status not_implemented

    4. 6

    Field Value
    Name Lock-Cassette
    Status not_implemented

    5. 7

    Field Value
    Name Erase-EOF
    Status not_implemented

    6. 10

    Field Value
    Name Advance-to-EOF
    Status not_implemented

    7. 11

    Field Value
    Name Reverse-to-EOF
    Status not_implemented

    8. 12

    Field Value
    Name Write-EOF
    Status not_implemented

    9. 13

    Field Value
    Name Rewind
    Status not_implemented

    10. 14

    Field Value
    Name Write-Erase-Gap
    Status not_implemented

    11. 15

    Field Value
    Name Back-Space-Records
    Status not_implemented

    12. 16

    Field Value
    Name Advance-Records
    Status not_implemented

    13. 17

    Field Value
    Name Unload
    Status not_implemented

    14. 20

    Field Value
    Name Read Status
    Description Reads the device status register via an IOX instruction.
    Status not_implemented

    15. 21

    Field Value
    Name Clear Device
    Status not_implemented

    16. 23

    Field Value
    Name Select Density-and-Parity
    Param2 Density/parity value (Users Guide section 9.2.2.1)
    Status not_implemented

    17. 24

    Field Value
    Name Read Last Status
    Description Returns the status of the last operation, saved by the driver, without executing an IOX instruction.
    Status not_implemented

Observed calls

1. ND linker (linker-b01.dom) @0xB004E9BC, via wrapper @0xB004E98A

Field Value
Params Functioncode: 0
Buffer: 0xB00530BC
Deviceno: 65
Deviceparam1: 4096
Deviceparam2: 3
Expectation The linker OPENs 'DDBTABLES-G':VTM (abbreviation-resolves to DDBTABLES-G06:VTM), 74B SETBTs the byte pointer to 0, then issues this call, and IMMEDIATELY requires the first word of Buffer to be 1 (0xB004AFB8 "w comp2 r.0x0,$0x1"), else it raises error 0x106A. The real DDBTABLES-G06:VTM begins 00 00 00 01 and carries 0x40-byte records at +0x78 - exactly where the linker then indexes. The file image maps directly onto the buffer.
Note If this call returns success WITHOUT filling Buffer, the linker's tables stay blank and it later walks blank memory as records, computes a bogus pointer 0x40404040 (0x20202020+0x20202020 - spaces read as a record), takes a protect violation, and aborts via its own trap handler. The failure surfaces ~83000 instructions later as a stack overflow, which is a symptom, NOT the bug.

Return contract

  • Success: K flag cleared; Buffer filled for transfer functions.
  • Errors

    Code Octal Meaning
    90 132B No file opened with this number (Read-Record on a non-open device)
    3 003B End of file / seek failed
    97 141B Transfer error

Verified

1. Function codes are octal, and this is the right table.

Field Value
Evidence The table skips 8 and 9. Independently, the ND linker's own MAGTP wrapper at 0xB004E98A special-cases function codes 0x10 and 0x14 (16 and 20 decimal = 20B and 24B octal) = exactly Read Status / Read Last Status - the codes the manual says take dummy parameters ("in the range 5B to 24B, except 23B, the parameter buffer and the two device dependent parameters are dummies").

2. Function 0 reads the open file named by DeviceNo into Buffer.

Field Value
Evidence Implemented and run: error 0x106A drops from 1 occurrence to 0, and the downstream protect violation and stack overflow disappear entirely. Log: "Read-Record 4096 bytes from device 101 into 0xB00530BC, pos=10000".

3. DeviceNo may be an open-file number, not only a logical device.

Field Value
Evidence Manual parameter text says "Logical device number (or open-file number)". Observed: DeviceNo=65, the file number returned by the preceding 50B OPEN. Corroborated by the access-code table entry for code 8: "Direct transfer for ReadFromFile, WriteToFile and DeviceFunction".

Unverified

  • WHICH parameter carries the transfer size. Table 9.1 lists param2 as "octal no. of words", but the linker passes param1=4096 and param2=3, and 4096 is the only value that can span the table it then indexes. nd500x treats param1 as a BYTE count. This is INFERRED from the caller's usage, not read from a manual - the pages that would settle the ND-500 parameter convention are not in the scanned set.
  • The return convention for the status-reporting functions (20B-24B): the manual says "the hardware status is returned" but the format is not in the scanned pages.
  • All function codes other than 0 are unimplemented in nd500x and currently return benign SUCCESS. That is NOT correct behaviour - they are real device operations against hardware not emulated.

Discrepancies

1. The carve of the ND-100 worker (L-VSX-500 segment 006-S3FS, MAGTP @026354B) validates the function code to the range 100B..177B, which would make function 0 out of range.

Field Value
Is The ND linker passes function 0 and expects it to work. The carve itself notes GOTAB[144B] = 000000 is a fall-through and the real dispatch lives in an UNCARVED overlay, so that range check is not authoritative for the ND-500 path.
Evidence NDInsight/tools/sintran-segment-carver/versions/L-VSX-500/re/mon-analysis/144B-DeviceFunction/144B-DeviceFunction.pseudo.c

Sources

Doc Page Table Note
ND-60.050.06 SINTRAN III Users Guide 232 9.1 The function-code table. Concluded on page 233 (codes 20-24).
nd500x/docs/HANDOFF_CSHARP_STRING_WRITE_MMU.md Section 7 item 3 - full port notes for the C# side.

Source

SINTRAN III Monitor Calls (ND-860228.2 EN), page 143.