Google
 

Trailing-Edge - PDP-10 Archives - BB-X116A-BB_1984 - ntman.mac
There are 26 other files named ntman.mac in the archive. Click here to see a list.
;DNET:NTMAN.MAC[10,36,MON,NEW], 05-Oct-1983 03:21:15, Edit by TARL
;MCO 10994 - Fixes to MCO 10988
;DNET:NTMAN.MAC[10,36,MON,NEW], 29-Sep-1983 20:54:32, Edit by TARL
;MCO 10988 - Add interface to DLL via KONDSP functions KF.xxx
;DNET:NTMAN.MAC[10,36,MON,NEW], 22-Sep-1983 23:20:34, Edit by TARL
;MCO 10971 - Grand Re-merge of the -10/-20 sources
;TITLE NTMAN - Network Management Interface for DECnet-36
  	SUBTTL	Tarl Neustaedter

	SEARCH D36PAR,MACSYM
	SALL

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.

IFN FTOPS20,<
	SEARCH PROLOG
	TTITLE NTMAN,,< - Network Management interface for DECnet-36>
	>

IFN FTOPS10,<
	SEARCH F,S
	TITLE NTMAN - Network Management interface for DECnet-36
.CPYRT<
COPYRIGHT (C) 1984 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
>
>;END IFN FTOPS10

	D36SYM			;SET UP D36 SPECIFIC PARAMETERS
	$RELOC
	ENTRY NTMAN		;TO FORCE LINK TO LOAD WITH REST OF DECNET


	SUBTTL	Table of Contents

	SUBTTL	Table of Contents


;		Table of Contents for NTMAN
;
;
;			   Section			      Page
;   1. Table of Contents. . . . . . . . . . . . . . . . . . .    3
;   2. Data structures
;        2.1.   Value definitions . . . . . . . . . . . . . .    4
;        2.2.   BEGSTR NT . . . . . . . . . . . . . . . . . .    5
;        2.3.   BEGSTRs NQ,EL . . . . . . . . . . . . . . . .    6
;        2.4.   Byte pointers into NSP node block . . . . . .    7
;        2.5.   Parameter and counter definitions . . . . . .    8
;   3. NTMAN
;        3.1.   Entry . . . . . . . . . . . . . . . . . . . .   14
;        3.2.   Get pertinent data from user's data block . .   15
;        3.3.   Dispatch to functions . . . . . . . . . . . .   16
;   4. Functions
;        4.1.   .NTPSI - Set event PSI. . . . . . . . . . . .   17
;        4.2.   .NTMAP - Map node name/number . . . . . . . .   18
;        4.3.   .NTREX - Return local node number . . . . . .   19
;        4.4.   .NTSET,.NTCLR - Parse and process a parameter   20
;        4.5.   .NTZRO,.NTSZC - Zero counters . . . . . . . .   21
;        4.6.   .NTSHO
;             4.6.1.     Select parameters to return. . . . .   22
;             4.6.2.     Return parameters to user. . . . . .   23
;        4.7.   .NTRET
;             4.7.1.     List node names. . . . . . . . . . .   24
;             4.7.2.     List circuit and line names. . . . .   25
;        4.8.   .NTEVQ - Pass queued event to user. . . . . .   26
;   5. Entities
;        5.1.   Convert entity names to entity ids. . . . . .   27
;        5.2.   Circuit ID to name conversion . . . . . . . .   28
;        5.3.   Convert name to Circuit-ID. . . . . . . . . .   29
;   6. Layers
;        6.1.   Main interface to layer levels. . . . . . . .   30
;        6.2.   Read/set NSP node blocks. . . . . . . . . . .   31
;        6.3.   Read/set RTR circuit blocks . . . . . . . . .   32
;        6.4.   Read/set node state . . . . . . . . . . . . .   33
;        6.5.   Read/set logging masks. . . . . . . . . . . .   34
;        6.6.   Read/set for executor node. . . . . . . . . .   35
;        6.7.   Read/set RTR node information . . . . . . . .   36
;        6.8.   Find circuit which points to a node . . . . .   37
;        6.9.   Set/clear node names. . . . . . . . . . . . .   38
;        6.10.  Create/Destroy loopback nodes . . . . . . . .   39
;   7. Events
;        7.1.   Event receiver. . . . . . . . . . . . . . . .   40
;        7.2.   Mask out unwanted events. . . . . . . . . . .   41
;   8. User strings
;        8.1.   Write parameter with nice . . . . . . . . . .   42
;        8.2.   Write coded data. . . . . . . . . . . . . . .   43
;        8.3.   Write ascii image data. . . . . . . . . . . .   44
;        8.4.   Write numeric data. . . . . . . . . . . . . .   45
;        8.5.   Read a number from user . . . . . . . . . . .   46
;        8.6.   Read and write milliseconds . . . . . . . . .   47
;        8.7.   Copy STRINGID from user to exec . . . . . . .   48
;        8.8.   Copy STRINGID from exec to user . . . . . . .   49
;        8.9.   Get and put user byte routines. . . . . . . .   50
;        8.10.  Get and put single bytes into data strings. .   51
;   9. Miscellaneous
;        9.1.   String compare which handles upper/lower case   52
;        9.2.   Error returns . . . . . . . . . . . . . . . .   53
;        9.3.   Name/number conversion. . . . . . . . . . . .   54
;  10. Data base
;       10.1.   Find NMX per-entity data base . . . . . . . .   55
;       10.2.   Find an NSP node block. . . . . . . . . . . .   56
;       10.3.   Find an existing NSP node block . . . . . . .   57
;  11. Data Base
;       11.1.   NMXNMI - Get node software ID.. . . . . . . .   58
	SUBTTL Data structures -- Value definitions

;AC definitions
	TM=FREE0		;A WORK AC. PRESERVED
	NT=FREE2		;POINTS TO THE TABLE FORMAT BLOCK


;Network managment circuit states
	XP NCK.ON,0		;CIRCUIT/LINE STATE ON
	XP NCK.OF,1		;STATE OFF
	XP NCK.SR,2		;SERVICE
	XP NCK.CL,3		;CLEARED

;Network management non-error code
	XP NESUC%,1

;Entity types
	.NTNOD==0		;NODE ENTITY
	.NTLIN==1		;LINE
	.NTCKT==3		;CIRCUIT
;Function codes
	.NTPSI==-3		;SET PSI MASK (TOPS20 ONLY)
	.NTSET==0		;FOR SPECIAL CASE CHECK
 	.NTEVQ==6		;REMOVE AN ITEM FROM THE EVENT QUEUE
;Qualifiers for functions
 	.NTLOP==-3		;LOOP
 	.NTACT==-2		;ACTIVE ITEMS
 	.NTKNO==-1		;KNOWN ITEMS		;(FOR .NTRET)
 	.NTSUM==0		;SUMMARY		;(FOR .NTSHO)
 	.NTCOU==3		;COUNTERS
;Offsets to important locations in block
	.NTBPT==6		;BYTE POINTER TO DATA STRING
	.NTBYT==7		;BYTE COUNT FOR DATA STRING
	.NTERR==10		;RETURN CODE, OR ERROR CODE

	XP .NQMXS,44		;MAXIMUM EVENT STRING LENGTH IN BYTES.

;MACRO TO CALL A ROUTINE, KNOWING THAT THE ROUTINE CAN RETURN NON-SKIP
;MEANING AN ERROR. THIS ERROR WOULD SIMPLY POPJ ALL THE WAY BACK TO THE
;TOP. NOTE THAT THE BOTTOM LEVEL MUST HAVE SET AN ERROR CODE IN NXERR.
DEFINE ECALL(ROUTINE),<
	CALL ROUTINE
	 RET
>

;MACRO TO GIVE AN ERROR RETURN. THIS IS USED SIMPLY TO HIGHLIGHT THE FACT
;OF AN ERROR RETURN, AND DOES NOT PRECLUDE OTHER WAYS OF REACHING THE ROUTINES
;WHICH SET AN ERROR CODE. A JSP IS USED TO FACILITATE DEBUGGING.
DEFINE ERRRET(ROUTINE),<JSP CX,ROUTINE>

	$LOW

NMXLST:	BLOCK 1			;LOST EVENT FLAG
NMXIDN:	BLOCK 1			;POINTER TO EXECUTOR IDENTIFICATION IF SET
NMXNDQ::BLOCK QH.LEN		;QUEUE HEADER FOR NMX NODE BLOCKS
NMXEVQ::BLOCK QH.LEN		;QUEUE HEADER FOR EVENT BLOCKS
	$HIGH			;RELOC TO HIGHSEG (RSCOD PSECT ON TOPS-20)

EXTERN DNGWDZ,DNGWDS,DNGEBL,DNFEBL,DNFWDS,NMXTIM,NMXPRV		;D36COM
EXTERN TIMBAS,DNGTIM						;D36COM
EXTERN RTRMXN,RTRNRV,RTRADR,RTNLID,RTNGLS,RTRNMX,RTNSLS,RTRCBQ	;RTR
EXTERN RTNGLB,RTRKBA						;RTR
EXTERN RTN,RSKP,CHKBPT,KONNAM
EXTERN SCTN2A,SCTA2N,SCTAND			     		;SCT
IFN FTOPS10,<EXTERN GETWRD,GETWR1,PSIDVT>

	SUBTTL Data structures -- BEGSTR NT

;Table to find and validate a call parameter or counter.
BEGSTR NT
	FIELD TYP,4		;DATA TYPE (ASCII, HEX,...)
	 XP NT.FC,1		;CODED FORMAT
	 XP NT.FCM,2		;CODED MULTIPLE (THIS MEANS SPECIAL CASING)
	 XP NT.FAI,3		;ASCII IMAGE (8-BIT)
	 XP NT.FDU,4		;DECIMAL, UNSIGNED. CANNOT BE ZERO.
	 XP NT.FDS,5		;DECIMAL, SIGNED
	 XP NT.FH,6		;HEX INTEGER.
	 XP NT.FHI,7		;HEX, IMAGE.
	 XP NT.FOC,^D8		;OCTAL.
				;ABOVE ARE DATA TYPES AS DESCRIBED IN NM SPEC
				; V3.0 PAGE 162.
				;BELOW ARE DATA TYPES USED INTERNALLY ONLY TO
				; THIS MODULE TO INCLUDE COUNTERS AS DATA TYPES
				; THESE SHOULD BE SHIFTED DOWN IF NM SPECIFIES
				; MORE DATA TYPES
	 XP NT.FDM,^D9		;INTERNAL DATA TYPE ONLY. DECIMAL,MILLISECONDS.
				; THIS GETS OUTPUT AS NT.FDU (SEE NMXWNM)
	 XP NT.FCO,^D10		;COUNTER (NOT REAL DATA TYPE, SPECIAL CASED)
	 XP NT.FCB,^D11		;BIT MAPPED COUNTER (DITTO ABOVE, POWER OF 2)
	FIELD LEN,5		;LENGTH
	FIELD ROU,6		;INDEX TO ROUTINE TO CALL
	FIELD APL,3		;APPLICABILITY RESTRICTIONS (NOTE - THIS REALLY)
	 BIT A.E		;EXECUTOR		    (BELONGS IN NEXT  )
	 BIT A.L		;LOOP NODES		    (WORD, BUT WE RAN )
	 BIT A.R		;REMOTE NODES. 		    (OUT OF SPACE.    )
	FIELD IDX,18		;VALUE TO PASS TO DATA ROUTINE
;NOTE THAT THE FOLLOWING ENTRIES ARE ONLY IN THE PRIMARY TABLE,
; THEY ARE NOT INCLUDED IN CODED MULTIPLE SUB-ENTRIES
NXTWRD				;FORCE NEXT WORD ALIGNMENT.
	FIELD SEQ,12		;SEQUENCE OR TYPE OF FIELD
	FIELD INF,4		;INFORMATION TYPE
	 BIT I.C		;CHARACTERISTICS (LISTED IN SPEC AS 'C')
	 BIT I.S		;STATUS (LISTED IN SPEC AS 'S')
	 BIT I.%		;SUMMARY (LISTED IN SPEC AS '*')
	 BIT I.N		;NONE. NOOP BIT, NOT NECESSARY
	FIELD SET,2		;SETTABILITY RESTRICTIONS
	 XP NTS.,0		;0 MEANS READ AND WRITE
	 XP NTS.R,1		;READ ONLY PARAMETER.
	 XP NTS.W,2		;WRITE ONLY PARAMETER.
	FIELD DFL,18		;DEFAULT VALUE. USUALLY ZERO
ENDSTR
IFN <NT.LST-2>,<PRINTX ?LENGTH OF BEGSTR NT IS WRONG> ;TABLE LOGIC KNOWS LENGTH

;Bit positions for fields - will need for building tables.
TYP$==POS(NTTYP)
SEQ$==POS(NTSEQ)
SET$==POS(NTSET)
LEN$==POS(NTLEN)
ROU$==POS(NTROU)
	SUBTTL Data structures -- BEGSTRs NQ,EL
BEGSTR NQ
	WORD NXT		;POINTER TO NEXT EVENT IN QUEUE
	FIELD CCL,13		;EVENT CLASS
	FIELD CTY,5		;EVENT TYPE
	WORD TIM		;TIME STAMP
	HWORD ETP		;ENTITY TYPE
	WORD EID		;ENTITY ID
	WORD STR,<.NQMXS/4>	;PLACE TO SAVE STRING PASSED TO US.
ENDSTR



	SUBTTL Data structures -- Byte pointers into NSP node block
;Define byte pointers for parameters in the node block.

NSPLKM:	POINTR(NN.LKM(T1),NNLKM) ;BYTE POINTER.  POINT T1 TO NODE BLOCK.
NSPDLX:	POINTR(NN.DLY(T1),NNDLY) ;DITTO.
;Counters
NSPTMC: POINTR(NN.TMC(T1),NNTMC)
NSPRBC: POINTR(NN.RBC(T1),NNRBC)
NSPXBC: POINTR(NN.XBC(T1),NNXBC)
NSPRMC: POINTR(NN.RMC(T1),NNRMC)
NSPXMC: POINTR(NN.XMC(T1),NNXMC)
NSPRCC: POINTR(NN.RCC(T1),NNRCC)
NSPXCC: POINTR(NN.XCC(T1),NNXCC)
NSPLKC:	POINTR(NN.LKC(T1),NNLKC)
NSPCRC:	POINTR(NN.CRC(T1),NNCRC)

;NMX dispatch table. Routines are indexes into this table.

NMXDSP:

PHASE	0			;Make labels be relative offsets.
NMXMIN:!			;Lowest offset for NMXDSP
NSP:!	IFIW NMXNSP		;Call NMX's NSP NMX server
EXE:!	IFIW NMXEXE		;Call for EXECUTOR node
XND:!	IFIW NMXXND		;Call for RTR node stuff
CIR:!	IFIW NMXCIR		;Single entry for Circuit of a node
RTL:!	IFIW NMXRTL		;Line block entries.
RTD:!	IFIW NMXRTD		;Special case of rtl. Return node name.
NMC:!	IFIW NMXNMC		;Call SCTAND
RTS:!	IFIW NMXRTS		;Router state setting/reading.
RTB:!	IFIW NMXRTB		;Router substate reading
NMS:!	IFIW NMXNMS		;Network management state setting/reading
NMI:!	IFIW NMXNMI		;Get Identification string
LLP:!	IFIW NMXLLP		;Loopback type
DLL:!	IFIW NMXDLL		;Data link layer
NMXMAX:!			;Maximum value plus one
IFGE <NMXMAX-<1_WID(NTROU)>>,<PRINTX ?Too many Layer servers for width of NTROU>
DEPHASE
	SUBTTL Data structures -- Parameter and counter definitions
DEFINE	NODE$P,<

N(0	,C,1	,S%,ER	,R,NMS,0)	                ;State.
N(100	,AI,31	,C%,E	,,NMI,0)	                ;Identification
N(500	,AI,6	,N,R	,W,NMC,0)	                ;Name of node (set only)
N(501	,AI,16	,C%,L	,,LLP,0)       	                ;Circuit
N(510	,DM,2	,C,E	,,EXE,SCTINT##,	%SCINT##)       ;Incoming timer
N(511	,DM,2	,C,E	,,EXE,SCTOTT##,	%SCOTT##)       ;Outgoing timer
N(600	,DU,2	,S%,ER	,R,NSP,NSPLKC)	                ;Active links.
N(601	,DM,2	,S%,R	,R,NSP,NSPDLX)	                ;Delay
N(700	,CM,3	,C,E	,R)		                ;NSP version
  CMENT(DU,1	,EXE,NSPVER##)		                ;  Version number
  CMENT(DU,1	,EXE,NSPECO##)		                ;  ECO number
  CMENT(DU,1	,EXE,NSPUEC##)		                ;  User ECO number
N(720	,DU,1	,C,E	,,EXE,NSPDLY##,	%NSDLY##)       ;Delay factor.
N(721	,DU,1	,C,E	,,EXE,NSPWGT##,	%NSWGT##)       ;Delay weight.
N(722	,DU,2	,C,E	,,EXE,NSPINA##,	%NSINA##)       ;Inactivity timer.
N(723	,DU,2	,C,E	,,EXE,NSPRTH##,	%NSRTH##)       ;Retransmit factor.
N(820	,DU,2	,S,R	,R,XND,RTNCST##)                ;Cost
N(821	,DU,1	,S,R	,R,XND,RTNHOP##)                ;Hops
N(822	,AI,16	,S%,R	,R,CIR,0)	                ;circuit
N(900	,CM,3	,C,E	,R)		                ;Routing version
  CMENT(DU,1	,EXE,RTRVER##)		                ;  Version number
  CMENT(DU,1	,EXE,RTRECO##)		                ;  ECO number
  CMENT(DU,1	,EXE,RTRCUS##)		                ;  User ECO number
N(901	,C,1	,C,E	,R,EXE,RTRTYP##)                ;Type
N(910	,DM,2	,C,E	,,EXE,RTRTM1##,	%RTTM1##)       ;Routing timer.
N(920	,DU,2	,C,E	,R,EXE,RTRMXN##)                ;Maximum address.
N(922	,DU,2	,C,E	,,EXE,RTRMXC##,	%RTMXC##)       ;Maximum cost.
N(923	,DU,1	,C,E	,,EXE,RTRMXH##,	%RTMXH##)       ;Maximum hops.
N(924	,DU,1	,C,E	,,EXE,RTRMXV##,	%RTMXV##)       ;Maximum visits.
N(931	,DU,2	,C,E	,R,EXE,RTRBSZ##)                ;Buffer size.
>

DEFINE	LINE$P,<

N(0	,C,1	,S%,	,,DLL,0,	NCK.OF)		;State
N(1	,C,1	,S%,	,R,DLL,0)	                ;Substate
N(1110	,C,1	,C,	,,DLL,0)	                ;Controller
N(1112	,C,1	,C,	,,DLL,0)	                ;Protocol
>

DEFINE	CIRC$P,<

N(0	,C,1	,S%,	,,RTS,,		NCK.OF)         ;State.
N(1	,C,1	,S%,	,R,RTB,)	                ;Substate
N(800	,CM,2	,S%,	,R)		                ;Adjacent node
  CMENT(DU,2	,RTL,RTLNAD##)		                ;  Node address
  CMENT(AI,6	,RTD,RTLNAD##)		                ;  Node Name.
N(810	,DU,2	,S,	,R,RTL,RTLBSZ##)                ;Block size
N(900	,DU,1	,C,	,,RTL,RTLCST##,	1)              ;Cost.
N(906	,DM,2	,C,	,,RTL,RTLTM3##,	%RTTM3##)       ;Hello timer
N(907	,DM,2	,C,	,,RTL,RTLTM4##,	%RTTM4##)	;Listen timer
>


DEFINE	NODE$C,<

N(0	,CO,2	,,	,,NSP,0)       	;seconds since last zeroed
N(600	,CO,4	,,	,,NSP,NSPRBC)	;Bytes received
N(601	,CO,4	,,	,,NSP,NSPXBC)	;Bytes sent
N(610	,CO,4	,,	,,NSP,NSPRMC)	;Messages received.
N(611	,CO,4	,,	,,NSP,NSPXMC)	;Messages sent
N(620	,CO,2	,,	,,NSP,NSPRCC)	;Connects received.
N(621	,CO,2	,,	,,NSP,NSPXCC)	;Connects sent
N(630	,CO,2	,,	,,NSP,NSPTMC)	;Response timeouts
N(640	,CO,2	,,	,,NSP,NSPCRC)	;Recv connect resource errors
N(900	,CO,1	,,E	,,EXE,RTRCAP##)	;Aged packet loss
N(901	,CO,2	,,E	,,EXE,RTRCNU##)	;Node unreachable packet loss
N(902	,CO,1	,,E	,,EXE,RTRCNO##)	;Node out-of-range packet loss
N(903	,CO,1	,,E	,,EXE,RTRCOP##)	;Oversised packet loss
N(910	,CO,1	,,E	,,EXE,RTRCPF##)	;Packet format error
N(920	,CO,1	,,E	,,EXE,RTRCPR##)	;Partial routing update loss
N(930	,CO,1	,,E	,,EXE,RTRCVR##)	;Verification reject
>

DEFINE	LINE$C,<				;Line counters

N(1100	,CO,1	,,	,,DLL,0)	;Remote process errors
N(1101	,CO,1	,,	,,DLL,0)	;Local process errors
>

DEFINE	CIRC$C,<				;Circuit counters

N(0	,CO,2	,,	,,RTL,0)	;Seconds since last zeroed.
N(800	,CO,4	,,	,,RTL,RTLCAP##)	;Arriving packets received
N(801	,CO,4	,,	,,RTL,RTLCDP##)	;Departing packets sent
N(802	,CO,2	,,	,,RTL,RTLCAL##)	;Arriving congestion loss
N(810	,CO,4	,,	,,RTL,RTLCTR##)	;Transit packets received
N(811	,CO,4	,,	,,RTL,RTLCTS##)	;Transit packest sent
N(812	,CO,2	,,	,,RTL,RTLCTL##)	;Transit congestion loss
N(820	,CO,1	,,	,,RTL,RTLCCD##)	;Line down
N(821	,CO,1	,,	,,RTL,RTLCIF##)	;Initialization failure
N(1000	,CO,4	,,	,,RTL,RTLBYR##)	;Bytes received
N(1001	,CO,4	,,	,,RTL,RTLBYS##)	;Bytes sent
N(1010	,CO,4	,,	,,RTL,RTLDBR##)	;Data blocks received
N(1011	,CO,4	,,	,,RTL,RTLDBS##)	;Data blocks sent

>

DEFINE DEFLAB(LABEL),<CM.'LABEL>

..LBL==0				;Start off at CM.1

DEFINE NLABEL,<..LBL=..LBL+1
DEFLAB(\..LBL)>

DEFINE XPAND(.RES,.PFX,.CHA),<
.RES=0
IFB <.CHA>,<.RES=-1>
IRPC .CHA,<IFNB <.CHA>,<.RES=.RES!.PFX'.CHA>>
>

DEFINE .M(MASK),<1_WID(MASK)>

;Macro to create primary table entry
DEFINE NTENT(.SEQ,.INF,.SET,.DFL),<
IFGE <^D'.SEQ-.M(NTSEQ)>,<PRINTX ?Parameter .SEQ will not fit in NTSEQ>
XPAND(INF,NTI.,.INF)
DFL==.DFL
<<^D'.SEQ>B<SEQ$>&NTSEQ>!
<INF&NTINF>!
<<NTS.'.SET>B<SET$>&NTSET>!
<DFL&NTDFL>
>

;Define rightmost positions of fields, for ddt
NTN==:<1B<POS(NTSEQ)>!1B<POS(NTINF)>!1B<POS(NTSET)>!1B<POS(NTDFL)>>
NSS==:<1B<POS(NTTYP)>!1B<POS(NTLEN)>!1B<POS(NTROU)>!1B<POS(NTAPL)>!1B<POS(NTIDX)>>
;Example - NTN$3M NODEP+3$10r$o/   100.,10.,4.,0.,0.
;displays fields NTSEQ, NTINF, NTSET, NTDFL .

;Macro to define secondary entry (Format)
DEFINE STENT(.TYP,.LEN,.ROU,.IDX,.APL),<
IFGE <.ROU-NMXMAX>,<PRINTX ?Routine .ROU out of range [.IDX]>
IFGE <^D'.LEN-.M(NTLEN)>,<PRINTX ?Parameter .LEN will not fit in NTLEN>
XPAND(APL,NTA.,.APL)
<APL&NTAPL>!
<<NT.F'.TYP>B<TYP$>&NTTYP>!
<<^D'.LEN>B<LEN$>&NTLEN>!
<<.ROU>B<ROU$>&NTROU>!
.IDX
>

DEFINE N(.SEQ,.TYP,.LEN,.INF,.APP,.SET,.ROU,.IDX,.DFL),<
IFN LASTLN,<PRINTX ?NMXPHE Phase error in previous CM (This .SEQ, .TYP, .LEN).
	PRINTX [SEQ=.SEQ, TYP=.TYP, LEN=.LEN, INF=.INF, APP=.APP, SET=.SET]
	LASTLN=0>
IFN <NT.F'.TYP-NT.FCM>,<IFB <.ROU>,<
	  PRINTX ?NMXILD Illegal to default unless multiple (.SEQ,.TYP,.LEN)
	  PRINTX [SEQ=.SEQ, TYP=.TYP, LEN=.LEN, INF=.INF, APP=.APP, SET=.SET]
	  >
	>
IFE <NT.F'.TYP-NT.FCM>,<IFNB <.ROU>,<
	  PRINTX ?NMXMDM Must default in multiple (.SEQ,.TYP,.LEN)
	  PRINTX [SEQ=.SEQ, TYP=.TYP, LEN=.LEN, INF=.INF, APP=.APP, SET=.SET]
	  >
	LASTLN==.LEN		;;NUMBER OF FIELDS TO FOLLOW.
NLABEL :			;;DEFINE LABEL FOR THESE CM ENTRIES
	>
>

DEFINE CMENT(.TYP,.LEN,.ROU,.IDX),<
	LASTLN=LASTLN-1		;DECREMENT NUMBER YET TO GO.
	STENT(.TYP,.LEN,.ROU,.IDX,)
>

LASTLN=0
;Define all the coded multiple subentries - Should all go in a
; contiguous block, with labels pointing at each sub-group

CMBLK:
	NODE$P
	LINE$P
	CIRC$P
..LBL=0				;RE-SET LABEL NAMES, SO WE GET THE SAME
				; LABELS THE SECOND TIME THROUGH.
;Define all the REAL stuff now.

DEFINE N(.SEQ,.TYP,.LEN,.INF,.APP,.SET,.ROU,.IDX,.DFL),<
IDX=.IDX
IFE <NT.F'.TYP-NT.FCM>,<IDX=DEFLAB(\<..LBL+1>)
	..LBL=..LBL+1
	>
	STENT(.TYP,.LEN,.ROU,IDX,.APP)
	NTENT(.SEQ,.INF,.SET,.DFL)
>

DEFINE CMENT(.TYP,.LEN,.ROU,.IDX),<>	;ALREADY DEFINED ALL THESE.

DEFINE MAKTAB(.LAB,.STF),<
XLIST
.LAB::.STF
.LAB'L==:.-.LAB
LIST
>

MAKTAB(NODEP,NODE$P)
MAKTAB(NODEC,NODE$C)
MAKTAB(LINEP,LINE$P)
MAKTAB(LINEC,LINE$C)
MAKTAB(CIRCP,CIRC$P)
MAKTAB(CIRCC,CIRC$C)

;Pointers to parameter data base.
PRMP::	XWD <-NODEPL/NT.LST>,NODEP	;NODE PARAMETERS
	XWD <-LINEPL/NT.LST>,LINEP	;LINE PARAMETERS
	Z				;LOGGING PARAMETERS
	XWD <-CIRCPL/NT.LST>,CIRCP	;CIRCUIT PARAMETERS
	Z				;MODULE - WE DON'T HAVE ANY
	Z				;EVENTS - CAN'T SET ANYTHING.

CNTP::	XWD <-NODECL/NT.LST>,NODEC	;NODE PARAMETERS
	XWD <-LINECL/NT.LST>,LINEC	;LINE PARAMETERS
	Z				;LOGGING PARAMETERS
	XWD <-CIRCCL/NT.LST>,CIRCC	;CIRCUIT PARAMETERS
	Z				;MODULE - WE DON'T HAVE ANY
	Z				;EVENTS - CAN'T SET ANYTHING.
	SUBTTL NTMAN -- Entry

;Called from DISP2A in UUOCON
;Call
;	M[T6]/ UUO itself (Used for storing values in the AC later)
;	T1/ Contents of the AC at UUO time
;	P/ Pointer to a stack in the current section
;Return
;	RET	error, .NTERR and AC contain error code
;	SKPRET	success. AC unchanged


.NTMAN::
NTMAN::
IFN FTOPS20,<
	MCENT			;ENTER MONITOR CONTEXT
	UMOVE T1,1		;GET ADDRESS OF BLOCK
>
	SEC1			;DO THE UUO IN SECTION 1
	TRVAR <<NMXVAR,NX.LST>>	;SET UP TRVAR
	SETZM NMXVAR		;CLEAN FIRST WORD OF BLOCK
	HRRI T2,1+NMXVAR	;GET POINTER TO SECOND WORD IN BLOCK
	HRLI T2,NMXVAR		;POINT AT START OF BLOCK
	BLT T2,NX.LST-1+NMXVAR	;CLEAN UNTIL END OF BLOCK
	STOR T1,NXADR,+NMXVAR	;SAVE ADDRESS OF ARGUMENT BLOCK
IFN FTOPS10,STOR T6,NXUUO,+NMXVAR ;** TOPS10 CALLS US WITH M/ UUO EXECUTED
	CALL GETBLK		;GET STUFF FROM USER PARAMETER BLOCK
	 ERRRET NTERXI		;DIDN'T MAKE IT. SOMETHING WRONG.
	CALL NMXDIS		;DISPATCH TO ROUTINES (IN NTMAN)
	 ERRRET NTERXI		;ERROR EXIT OF SOME KIND. CHECK.
	TMNE NXERR,+NMXVAR	;MAKE SURE NO ERROR CODE HAS MADE IT'S WAY HERE
	 BUG.(CHK,NTMSRF,NTMAN,SOFT,<Skipness of return fouled up>,,<

Cause:	We have come back from NTMAN with aa skip return, but there
	is an error code stored in field NXERR.

Cure:	Find out who is giving the error code (or trashing NXERR) and
	make him give a non-skip return.
>,RTN)
	LOAD T2,NXADR,+NMXVAR	;GET ADDRESS OF USER'S ARGUMENT BLOCK
	MOVX T1,NESUC%		;ERROR CODE INDICATING SUCCESS.
	UMOVEM T1,.NTERR(T2)	;PUT IN ERROR CODE SPOT OF ARGUMENT BLOCK
	UMOVE T3,.NTBYT(T2)	;GET ORIGINAL NUMBER OF BYTES HE ALLOWED US
	LOAD T1,NXDAT,+BP.BYT+NMXVAR ;GET NUMBER OF BYTES LEFT IN STRING
	SUB T3,T1		;GET NUMBER OF BYTES WE ACTUALLY DEPOSITED
	TMNE NXWUS,+NMXVAR	;DID WE WRITE TO THE USER'S STRING?
	 UMOVEM T3,.NTBYT(T2)	;TELL USER HOW MANY BYTES WE GAVE HIM
IFN FTOPS20,MRETNG		;MAKE THE UUO DO A GOOD RETURN
IFN FTOPS10,RETSKP

NTERXI:
	OPSTR <SKIPL T1,>,NXERR,+NMXVAR
	BUG.(CHK,NTMNEC,NTMAN,SOFT,<No error code, with error return>,,<

Cause:	Some routine has returned non-skip, but has not given
	an error code by calling NTExxx. This means that we returned
	to top level, and field NXERR was zero.

Cure:	Determine which routine is failing, and make the error return
	give an error code.
>)
IFN FTOPS10,<
	LOAD T6,NXUUO,+NMXVAR	;GET UUO BACK - NEED FOR STOTAC
	CALL STOTAC##		;PUT ERROR CODE IN AC
	LOAD T1,NXERR,+NMXVAR	;GET ERROR CODE
	CAXN T1,NEADC%		;WAS THIS AN ADDRESS CHECK?
	RET			;YES, DON'T DO FURTHER DAMAGE.
> ;END IFN FTOPS10
	LOAD T2,NXADR,+NMXVAR	;GET ADDRESS OF USER BLOCK
	UMOVEM T1,.NTERR(T2)	;NOPE, SAFE TO GIVE HIM ERROR CODE
	SETZ T1,		;0 BYTES
	UMOVEM T1,.NTBYT(T2)	;TELL NML THAT WE DIDN'T GIVE HIM ANYTHING.
IFN FTOPS20,ITERR (NTMX1)	;GENERIC NETWORK MANAGEMENT ERROR
IFN FTOPS10,RET			;RETURN NON-SKIP, INDICATING UUO FAILED
	SUBTTL NTMAN -- Get pertinent data from user's data block

;Called from NMXDIS

;GETBLK - Copy pertinent fields from user's argument block to NX block
;;Call
;	NX/ Pointer to NX block
;Returns
;	Non skip on failure - Address check
;	Skip return on success
GETBLK:
	CALL NMXPRV		;MAKE SURE WE ARE PRIVED.
	 ERRRET NTEPRV		;NOPE, GIVE THE NO PRIVS RETURN
	SAVEAC P1		;SO WE CAN HOLD SOME STUFF
	LOAD T6,NXADR,+NMXVAR	;GETWRD UNDERSTANDS T6 AS ADDRESS.
	CALL GETWRD		;GET FIRST WORD OF BLOCK
	 ERRRET NTEADC		;NO GO. CAN'T HAPPEN
	CAIGE T1,.NTERR		;MAKE SURE BLOCK INCLUDES .NTERR
	 ERRRET NTEADC		;NOPE, ADDRESS CHECK.
	CALL GETWR1		;GET NEXT WORD IN BLOCK
	 ERRRET NTEADC		;ADDRESS CHECK
	CAXL T1,.NTNOD		;RANGE CHECK THE ENTITY TYPE
	CAXLE T1,.NTCOU
	 ERRRET NTEINI		;BAD ENTITY TYPE
	STOR T1,NXENT,+NMXVAR	;SAVE AS ENTITY TYPE
	CALL GETWR1		;GET BYTE POINTER TO ENTITY ID
	 ERRRET NTEADC
	MOVE P1,T6		;SAVE POINTER TO ARG BLOCK FOR A WHILE
	MOVX T2,^D16		;THIS COULD BE AS MUCH AS 16 BYTES
	CALL CHKBPT		;ASK IF THIS IS A GOOD BYTE POINTER
	 ERRRET NTEADC		;NOPE - BAD BYTE POINTER
	MOVE T6,P1		;GET BACK POINTER TO OUR ARGUMENT LIST
	STOR T1,NXEID,+BP.BPT+NMXVAR ;SAVE RESOLVED BYTE POINTER
	MOVX T1,^D16		;MAXIMUM LENGTH FOR AN ENTITY ID
	STOR T1,NXEID,+BP.BYT+NMXVAR ;SAVE
	CALL GETWR1		;GET FUNCTION TO BE PERFORMED
	 ERRRET NTEADC		;SIGH.
	CAXL T1,.NTPSI		;RANGE CHECK FUNCTION
	CAXLE T1,.NTEVQ
	 ERRRET NTEUFO		;BAD FUNCTION
	STOR T1,NXFNC,+NMXVAR	;SAVE AWAY.
	CALL GETWR1		;GET SELECTION CRITERIA
	 ERRRET NTEADC
	STOR T1,NXSEL,+NMXVAR	;STASH AWAY
	CALL GETWR1		;GET FUNCTION QUALIFIER
	 ERRRET NTEADC
				;I DON'T KNOW WHAT TO DO WITH THIS. TOSS.
	CALL GETWR1		;GET BYTE POINTER TO FUNCTION QUALIFIER
	 ERRRET NTEADC
	MOVE P1,T1		;HANG ON TO BYTE POINTER FOR A WHILE
	CALL GETWR1		;GET BYTE COUNT OF STRING
	 ERRRET NTEADC
	STOR T1,NXDAT,+BP.BYT+NMXVAR ;SAVE BYTE COUNT
	UMOVEM T1,(T6)		;TRY TO MOVE IT BACK. (MAKE SURE WRITABLE)
IFN FTOPS10,ERJMP NTEADC 	;DIDN'T WORK, MUST BE A HIGH SEGMENT.
	MOVE T2,T1		;NUMBER OF BYTES WE WANT TO CHECK
	MOVE T1,P1		;BYTE POINTER WE ARE GOING TO ASK ABOUT
	MOVE P1,T6		;SAVE OUR ARGUMENT LIST POINTER
	CALL CHKBPT		;ASK IF THIS BYTE POINTER IS ANY GOOD
	 ERRRET NTEADC		;NOPE.
	STOR T1,NXDAT,+BP.BPT+NMXVAR ;SAVE FOR GETBYT
	MOVE T6,P1		;GET BACK POINTER TO THE USER ARG BLOCK
	CALL GETWR1		;MAKE SURE .NTERR IS IN CORE
	 ERRRET NTEADC		;I'LL BE DAMMNED. IT WASN'T.
	UMOVEM T1,(T6)		;TRY TO PUT IT BACK.
IFN FTOPS10,ERJMP NTEADC	;DIDN'T WORK, MUST BE FIRST WORD IN HISEG
	RETSKP			;RETURN SUCCESS TO CALLER
	SUBTTL NTMAN -- Dispatch to functions

NMXDIS:
	LOAD P1,NXENT,+NMXVAR	;GET ENTITY TYPE
	LOAD T1,NXFNC,+NMXVAR	;GET FUNCTION CODE
	MOVE T2,<-.NTPSI>+[	;GET FLAG BITS FOR THIS FUNCTION
		NX%WRM			;.NTPSI (TOPS-20 ONLY)
		NX%WUS			;.NTMAP
		NX%WUS			;.NTREX
		NX%WRM!NX%ECV		;.NTSET
		NX%WRM!NX%ZMC!NX%ECV	;.NTCLR
		NX%WRM!NX%ZMC!NX%ECV	;.NTZRO
		NX%WUS!NX%ECV		;.NTSHO
		NX%WUS!NX%ZMC!NX%WRM!NX%ECV;.NTSZC
		NX%WUS			;.NTRET
		NX%WUS](T1)		;.NTDQE
	STOR T2,NXFLG,+NMXVAR	;SAVE FLAGS WE JUST GOT
	TXNN T2,NX%ECV		;SHOULD WE PARSE THE ENTITY?
	JRST NMXDI2		;NO, SKIP OVER
	ECALL ENTCVT		;CONVERT THE ENTITY TO AN ID
	LOAD T1,NXFNC,+NMXVAR	;GET FUNCTION CODE BACK AGAIN.
NMXDI2:
	CAXL T1,.NTPSI		;RANGE CHECK FUNCTION
	CAXLE T1,.NTEVQ		; CODE.
	BUG.(CHK,NTMFUR,NTMAN,SOFT,<Function code out of range>,,<

Cause:	We are going to dispatch by function code, and we have
	found that the function code is out of range. Since the function
	code the user supplies is checked in GETBLK, this means that
	field NXFNC has been trashed in the meantime.
>,NTEMPE)
	CAXL P1,.NTNOD		;RANGE CHECK ENTITY
	CAXLE P1,.NTCKT		;  TYPE.
	BUG.(CHK,NTMEOR,NTMAN,SOFT,<Entity type out of range>,,<

Cause:	We are double checking the entity ID, before dispatching
	on it, and we have found the value to be illegal. Since the
	value the user supplies is checked at GETBLK, this means that
	field NXENT has been trashed.
>,NTEMPE)
	CALLRET @.+1-.NTPSI(T1)	;DISPATCH TO APPROPRIATE ROUTINE.
	  IFIW NTLPSI		;.NTPSI - SET EVENT INTERRUPT (TOPS-20 ONLY)
	  IFIW NODMAP		;.NTMAP - MAP NODE NUMBERS AND NAMES
	  IFIW NODLOC		;.NTREX - RETURN ENTITY ID FOR EXECUTOR
	  IFIW PRSPRM		;.NTSET - SET A PARAMETER
	  IFIW PRSPRM		;.NTCLR - CLEAR A PARAMETER
	  IFIW PRSCOU		;.NTZRO - ZERO COUNTERS
	  IFIW SELITM		;.NTSHO - SHOW PARAMETERS/COUNTERS
	  IFIW PRSCOU		;.NTSZC - SHOW AND ZERO COUNTERS
	  IFIW @<-.NTNOD>+[	;.NTRET - LIST ENTITIES
		IFIW NMXLND	;  .NTNOD - NODE
		IFIW NMXLCK	;  .NTLIN - LINE
		IFIW NTEURC	;  .NTLOG - DOESN'T EXIST
		IFIW NMXLCK](P1);  .NTCKT - CIRCUIT
	  IFIW GETEVT		;.NTEVQ - PASS A QUEUED EVENT TO USER
	SUBTTL Functions -- .NTPSI - Set event PSI
NTLPSI:
IFN FTOPS10,<ERRRET NTEUFO>	;NOT IN TOPS10
IFN FTOPS20,<
       	SKIPN T1,EVRFRK		;SOMEONE ALREADY DOING THIS?
	IFSKP.
	   HRRZS T1		;YES, GET HIS ID
	   CAME T1,FORKX	;IS HE RESETTING?
 	   JRST NTEMPE		;NO, ONLY ONE EVENT READER IS ALLOWED
	ENDIF.
	MOVE T1,.NTSEL(Q1)	;GET USER'S PSI CHANNEL
	CAME T1,[-1]		;DOES HE STILL WANT TO BE NOTIFIED?
	IFSKP.
	   SETZM EVRFRK		;NO, NO MORE EVENT READER
	ELSE.
	   CAIL T1,0		;YES, CHECK FOR
	   CAILE T1,^D36	; LEGAL PSI CHANNEL
 	   JRST NTEMPE		;ILLEGAL
	   AOS T1		;FIX IT FOR INTERNAL USE
	   HRLM T1,EVRFRK	;SET IT UP
	   MOVE T1,FORKX	;GET USER
	   HRRM T1,EVRFRK	;SET IT UP
	   SKIPE NMXEVQ		;IS THERE ANYTHING IN THE QUEUE ?
	   CALL NMLEVT		;YES. GIVE INTERRUPT.
	ENDIF.
	RETSKP


;KILL THE EVENT READER (CALLED FROM .RESET AND KSELF)
;RETURNS:	+1

EVRKIL::HRRZ T1,EVRFRK		;GET THE EVENT LOGGER
	CAMN T1,FORKX		;IS IT US?
	SETZM EVRFRK		;YES, NO MORE EVENT READER
	RET			;NO, NOTHING TO DO

;GIVE THE EVENT READER A PSI
;CALLED FROM LV8CHK
NMLEVT::SETZM NMLPSI		;CLEAR THE FLAG
	HLRZ T1,EVRFRK		;GET PSI CHANNEL
	JUMPE T1,RTN		;IF THERE IS ONE.
	SOS T1			;THERE IS. MAKE IT REAL.
	HRRZ T2,EVRFRK		;GET EVENT READER FORK
	CALL PSIRQ		;LET HIM KNOW
	RET			;DONE.

;ASSERT EVENT PSI FOR SCHEDULER TO CATCH
;MAY BE CALLED AT ANY LEVEL.
;CALL PSIDVT
;RETURNS +1 ALWAYS
;	RESCD			;MUST BE RESIDENT

PSIDVT::SETOM NMLPSI  		;SET FLAG FOR SCHEDULER.
	RET

>;END IFN FTOPS20
	SUBTTL Functions -- .NTMAP - Map node name/number

;Called from NMXDIS

;Extract parameter from input string, if a number return node name,
;	if a name, return node number (Address, or ID).
;Call
;	NC/ Pointer to block of data copied from user.

NODMAP:
	SAVEAC P1		;NEED ACS FOR BYTE ROUTINES
	ECALL GET2BT		;GET NODE NUMBER
	STOR T1,NXNUM,+NMXVAR	;STORE ENTITY ID (MAYBE)
	ECALL GETSTR		;COPY SOME BYTES
	JE NXVAL,+NMXVAR,NODMA2	;IF NO NAME, HE GAVE US AN ADDR
	CALL NMXN2A		;CONVERT NAME IN NXVAL TO NUMBER
	 ERRRET NTEURC		;SAY THAT IT FOULED UP.
	STOR T1,NXNUM,+NMXVAR	;STORE THE NODE ADDRESS AWAY.
NODMA2:
	JE NXNUM,+NMXVAR,NTEPAM	;IF NO NODE ADDRESS YET, ILLEGAL.
	LOAD T1,NXADR,+NMXVAR	;GET USER'S ARG BLOCK ADDRESS
	UMOVE T1,.NTBPT(T1)	;GET BYTE POINTER AGAIN
	STOR T1,NXDAT,+BP.BPT+NMXVAR ;RESET EVERYTHING AGAIN
	LOAD T1,NXADR,+NMXVAR	;ARG BLOCK ADDRESS AGAIN
	ADDI T1,.NTBYT		;POINT TO BYTE COUNT
	UMOVE T1,(T1)		;GET BYTE COUNT FOR DATA STRING
	STOR T1,NXDAT,+BP.BYT+NMXVAR ;STASH AWAY FOR PUTBYT
	LOAD T1,NXNUM,+NMXVAR	;GET NODE ADDRESS
	CAMLE T1,RTRMXN		;MAKE SURE IN RANGE.
	 ERRRET NTEURC		;HE GAVE US A BAD NODE NUMBER
	CALL NMXA2N		;CONVERT NODE ADDRESS TO NODE NAME
	 TRN
NODMA3:	LOAD T1,NXNUM,+NMXVAR	;GET NODE NUMBER
	ECALL PUT2BT		;PUT INTO DATA STRING
	XMOVEI P1,NX.VAL+NMXVAR	;POINTER TO STRINGID CONTAINING NODE NAME
	CALLRET PUTSTR		;COPY STRING FROM NXVAL TO USER DATA STRING
	SUBTTL Functions -- .NTREX - Return local node number

;Called from NMXDIS

NODLOC:
	CAXE P1,.NTNOD		;THIS FUNCTION ONLY VALID FOR NODE ENTITY
	ERRRET NTEUFO		;ERROR "FUNCTION ILLEGAL FOR THIS ENTITY"
	MOVE T1,RTRADR		;GET OUR NODE ADDRESS
	ECALL PUT2BT		;SEND TWO BYTES INTO THE OUTPUT STRING.
	SETZ T1,		;NO NODE NAME (DON'T BOTHER)
	CALLRET PUTBYT		;STORE AWAY IN USER STRING
	SUBTTL Functions -- .NTSET,.NTCLR - Parse and process a parameter

;Called from NMXDIS

;PRSPRM - Parse a parameter from the data string, and process
;CALL
;	T1/ Function (From NXFNC)
;RETURN
;	Non skip, on error, with code stored in NXERR
;	Skip, no error, parameter has been processed
PRSPRM:
	SAVEAC NT
	MOVE NT,PRMP(P1)	;GET AOBJN POINTER TO NMXTAB
	JE NXDAT,+BP.BYT+NMXVAR,TABCLR ;IF NO PARAMETER, TRY CLEAR ALL
	ECALL GET2BT		;GET DATA-ID FIELD.
	STOR T1,NXPRM,+NMXVAR	;STORE SEQUENCE NUMBER (THIS WILL BE CHANGED
				;  LATER, WHEN WE FIND THE ENTRY IN NMXTAB)
	ASH T1,-^D15		;SHIFT SO 11-ISH BIT 15 IS IN BOTTOM
	LOAD T2,NXCXP,+NMXVAR	;DOES BLOCK SAY PARAMETER OR COUNTER
	CAME T2,T1		;DO WE MATCH FUNCTION WITH DATA STREAM?
	ERRRET NTEPNA		;NOPE - ILLEGAL DATA STREAM.
	LOAD T1,NXPRM,+NMXVAR	;GET SEQUENCE NUMBER IN SCRATCH AC.
;Now search for sequence number in NMXTAB table.
TABSRC:	JUMPGE NT,NTEUPT	;IF END OF TABLE, NO SUCH PARAMETER
	LOAD T2,NTSEQ,(NT)	;GET AN ENTRY OUT OF THE TABLE.
	CAME T1,T2		;IS THIS THE ENTRY WE ARE LOOKING FOR ?
	JRST [ADD NT,[1,,NT.LST] ;INCREMENT POINTER, DECREMENT COUNT
		JRST TABSRC]	;AND TRY AGAIN
;NT now points to table entry describing this parameter or counter.
	STOR T2,NXPRM,+NMXVAR	;SAVE VALUE TO PASS TO CALLED ROUTINE.
	LOAD T1,NTSET,(NT)	;GET SETTABILITY RESTRICTIONS
	CAXN T1,NTS.R		;IS IT READ ONLY?
	ERRRET NTEOPF		;YEP - HE CAN'T BE WRITING THIS ONE
	LOAD T1,NXENT,+NMXVAR	;GET TYPE OF ENTITY
	CAXE T1,.NTNOD		;IS IT A NODE?
	JRST TABSR1		;NO, APPLICABILITY DOESN'T APPLY
	LOAD T1,NXNTY,+NMXVAR	;GET TYPE OF NODE
	MOVE T1,[NTA.E		;BIT INIDICATING EXECUTOR
		 NTA.R		;    REMOTE
		 NTA.L]-1(T1)	;    LOOPBACK
	TDNN T1,NT.APL(NT)	;DOES THIS PARAMETER APPLY TO THIS NODE TYPE?
	ERRRET NTEPNA		;NO, PARAMETER NOT APPLICABLE
TABSR1:	JN NXZMC,+NMXVAR,TABSR2	;IF ZEROING MONITOR CORE, DON'T GET VALUES
	LOAD T1,NTTYP,(NT)	;FIND OUT WHAT KIND OF DATA WE ARE READING
	CAXL T1,NT.FC		;IS IT LESSER THAN SIMPLE CODED?
	CAXLE T1,NT.FDM		;OR GREATER THAN DECIMAL MILLISECONDS
TABSRE:	BUG.(CHK,NTMBFP,NTMAN,SOFT,<Bad format type encountered>,,<

Cause:	We are in the process of reading a value from the user string,
	descriptor tables have returned an invalid format for this
	item. The AC "NT" points to the descriptor for this item, and
	field NTSEQ should tell you which item is being referred to.

Cure:	Fix the entry for this item to contain a valid format type.
>,NTEMPE)
	CALL <-NT.FC>+@[	;DISPATCH ACCORDING TO FORMAT TYPE
		IFIW NMXRNC	;ORDINARY CODED.
		IFIW TABSRE	;CODED MULTIPLE. ILLEGAL
		IFIW GETSTR	;ASCII IMAGE. WILL ALSO BE STRINGID
		IFIW NMXRNU	;DECIMAL UNSIGNED.
		IFIW NMXRNS	;DECIMAL SIGNED.
		IFIW NMXRNU	;HEX INTEGER.
		IFIW GETSTR	;HEX IMAGE. STRING ID.
		IFIW NMXRNU	;OCTAL - READ AS DECIMAL UNSIGNED
		IFIW NMXRNM](T1);MILLISECONDS (REALLY DECIMAL UNSIGNED)
	 RET			;PROPAGATE ERROR
TABSR2:	CALLRET NMXLAY		;HAVE THE LAYER DO THE REST.

;Logic for CLEAR ALL command

TABCLR: TMNN NXZMC,+NMXVAR	;ARE WE DOING A CLEAR?
	ERRRET NTEPAM		;NOPE, PARAMETER MISSING
TABCL1:	JUMPGE NT,RSKP		;DONE WHEN POSITIVE
	LOAD T1,NTSET,(NT)	;GET SETTABILITY RESTRICTIONS
	CAXE T1,NTS.		;ARE THERE ARE RESTRICTIONS?
	JRST TABCL5		;YES, IGNORE THIS PARAMETER
	LOAD T1,NXENT,+NMXVAR	;GET ENTITY TYPE
	CAXE T1,.NTNOD		;IS IT NODE?
	JRST TABCL2		;NOPE, APPLICABILITY DOESN'T APPLY
	LOAD T1,NXNTY,+NMXVAR	;GET TYPE OF NODE
	MOVE T1,[NTA.E
		NTA.R
		NTA.L]-1(T1)	;GET BITS REPRESENTING APPLICABILITY
	TDNN T1,NT.APL(NT)	;DOES THIS APPLY TO THIS NODE?
	JRST TABCL5		;NOPE, BYPASS IT
TABCL2:	ECALL NMXLAY		;CALL THE LAYER TO CLEAR THIS PARAMETER
TABCL5:	ADD NT,[1,,NT.LST]	;INCREMENT POINTER, DECREMENT COUNT
	JRST TABCL1		;AND DO THE NEXT PARAMETER

	SUBTTL Functions -- .NTZRO,.NTSZC - Zero counters

;Called from NMXDIS

;Call
;	T1/ Functions (from NXFNC)
;Return
;	RET	Error, code stored in NXERR
;	RETSKP	Counters have been processed
PRSCOU:
	SAVEAC NT
	MOVE NT,CNTP(P1)	;GET FORMAT POINTER FOR COUNTERS FOR ENTITY
	SETONE NXCXP,+NMXVAR	;INDICATE COUNTERS ARE BEING DONE
PRSCO1:	JUMPGE NT,RSKP		;WHEN DONE, RETURN SUCCESS
	ECALL PUTPRM		;DO THIS PARAMETER
	ADD NT,[1,,NT.LST]	;INCREMENT BOTH SIDES
	JRST PRSCO1		;TRY FOR SOME MORE.
	SUBTTL Functions -- .NTSHO -- Select parameters to return
;SELITM - Select items from list of parameters for an entity, and
;	write their values to the user string
;Call
;	P1/ Type of entity
;Return
;	RET			;on error, NXERR contains code
;	RETSKP			;success, all info for this entity in string
;

SELITM:
	SAVEAC <P1,P2,NT>	;GET SOME WORK REGISTERS
	LOAD T1,NXSEL,+NMXVAR	;GET SELECTION CRITERIA
	SKIPL T1		;IF NEGATIVE
	CAXLE T1,.NTCOU		;OR GREATER THAN HIGHEST VALUE
	ERRRET NTEUFO		;GIVE AN ERROR
	CAXE T1,.NTCOU		;IS THIS SHOW COUNTERS?
	JRST [MOVE NT,PRMP(P1)	;NOPE, GET POINTER TO PARAMETERS
		JRST SELIT2]	;AND JOIN COMMON CODE
	SETONE NXCXP,+NMXVAR	;NOTE THAT WE ARE DOING COUNTERS
	MOVE NT,CNTP(P1)	;GET POINTER TO COUNTER LIST
SELIT2:
	CAXL T1,.NTSUM		;RANGE CHECK SELECTION CRITERIA
	CAXLE T1,.NTCOU		;COUNTERS IS HIGHEST.
	BUG.(CHK,NTMSOR,NTMAN,SOFT,<Selection criteria is out of range>,,<

Cause:	We are going to select items to return (for .NTSHO) depending
	on the selection criteria, and we have found the criteria to
	be out of range.

Cure:	Fix the check in GETBLK or find out who is trashing field NXSEL
>,NTEMPE)
	MOVE P1,<-.NTSUM>+[NTI.% ;SUMMARY BIT
		NTI.S		;STATUS BIT
		NTI.C		;CHARACTERISTICS BIT
		NTINF](T1)	;COUNTERS (DO ALL OF THEM)
	LOAD T1,NXNTY,+NMXVAR	;GET NODE TYPE (REMOTE, EXECUTOR...)
	CAXL T1,0		;RANGE CHECK NODE TYPE (LOWEST IS NONE)
	CAXLE T1,NX.LPN		;LOOPBACK IS HIGHEST YET.
	BUG.(CHK,NTMNTR,NTMAN,SOFT,<Node type is out of range>,,<

Cause:	We are going to select entries to return (for function .NTSHO)
	and we need to know the node type (executor,remote, or loop) to
	decide. Other entities (circuit, lines) should have this field
	zero. This field is set by ENTCVT.
>,NTEMPE)
	MOVE P2,[NTAPL		;NO NODE TYPE, DO THEM ALL
		NTA.E		;BIT INDICATING APPLIES TO EXECUTOR NODE
		NTA.R		;APPLIES TO REMOTE NODES
		NTA.L](T1)	;APPLIES TO LOOPBACK NODES

SELIT4:	JUMPGE NT,RSKP		;WHEN DONE, RETURN SUCCESS
	TDNE P1,NT.INF(NT)	;DOES THIS MATCH OUR SELECTION CRITERIA?
	TDNN P2,NT.APL(NT)	;AND DOES THIS APPLY TO US?
	JRST SELIT6		;NOPE. SKIP OVER IT
	ECALL PUTPRM		;YEP. DO THIS PARAMETER
SELIT6:	ADD NT,[1,,NT.LST]	;POINT TO NEXT ITEM ON LIST
	JRST SELIT4		;GO TRY FOR THIS NEW ITEM
	SUBTTL Functions -- .NTSHO -- Return parameters to user
;PUTPRM - Process a parameter/counter, and put into user data string
;Also called by PRSCOU, for function .NTSZC and .NTZRO

PUTPRM:	SAVEAC <P1,P2,NT,TM>	;SAVE A BUNCH OF ACS (TRASHED IN CM HANDLING)
	LOAD T1,NTIDX,(NT)	;GET INDEX TO PASS TO LOWER LEVEL
	STOR T1,NXPRM,+NMXVAR	;SAVE IN NX BLOCK
	LOAD T1,NTTYP,(NT)	;GET TYPE OF PARAMETER
	CAXN T1,NT.FCM		;IS THIS PARAMETER TYPE 'CODED MULTIPLE'?
	JRST PUTPR1		;YES, SPECIAL CASE IT.
	ECALL NMXLAY		;CALL LAYER-LEVEL ROUTINE TO DO PARAMETER
	ECALL NMXWTY		;WRITE STRING OUT TO USER IN APPROPRIATE FORMAT
	RETSKP			;FINISHED

;HANDLE CODED MULTIPLES HERE.
PUTPR1:
	MOVE P2,NT		;SAVE NT FOR A WHILE
	LOAD T1,NTLEN,(P2)	;GET NUMBER OF POSSIBLE CM ENTRIES
	MOVN T1,T1		;MAKE IT A NEGATIVE NUMBER (FOR JUMPGE)
	LOAD NT,NTIDX,(P2)	;GET POINTER TO CM STENT TABLE
	HRL NT,T1		;NOW WE HAVE A NT TYPE POINTER IN NT
	SETZ P1,		;NO ENTRIES HAVE BEEN FOUND YET.
PUTPR2:	ECALL NMXLAY		;CALL THE LAYER, FIND OUT ABOUT PARAMETER
	JN NXNIL,+NMXVAR,PUTPR4	;IF THE LAYER DIDN'T KNOW ABOUT IT, TRY NEXT
	JE NXWUS,+NMXVAR,PUTPR4	;IF NOT WRITING, SKIP OVER WRITE CODE
	JUMPN P1,PUTPR3		;IF FIRST THING FOUND, OUTPUT CM HEADER
	EXCH P2,NT		;TEMPORARILY GET BACK REAL NT POINTER
	ECALL NMXWTY		;WRITE OUT CM HEADER TO USER STRING
	EXCH P2,NT		;GET BACK NT POINTER TO CM TABLE
	SETZ T1,		;ZILP, WILL HAVE REAL VALUE AT PUTPR5
	ECALL PUTBYT		;RESERVE A BYTE. (DATA TYPE OF CM+NUMBER)
	LOAD TM,NXDAT,+BP.BPT+NMXVAR ;GET POINTER TO DATA TYPE - CHANGED LATER
PUTPR3:	AOJ P1,			;INCREMENT NUMBER OF FIELD WE HAVE PROCESSED
	ECALL NMXWT3		;OUTPUT DATA TYPE BYTE, AND DATA
PUTPR4:	AOBJN NT,PUTPR2		;TRY ANOTHER CM ENTRY.
PUTPR5:	SKIPN T1,P1		;GET NUMBER OF FIELDS WE SENT
	RETSKP			;NONE OF THEM WERE AVAILABLE (NXNIL IS SET)
	TXO T1,<1_7>!<1_6>	;DATA TYPE IS CODED, AND IT IS MULTIPLE
	XCTBU [DPB T1,TM]	;REPLACE BYTE WE SENT EARLIER.
	SETZRO NXNIL,+NMXVAR	;CLEAR THE "NOTHING DONE" BIT.
	RETSKP			;FINISHED, GOOD RETURN
	SUBTTL Functions -- .NTRET -- List node names
;NMXLND - List a series of node names. Function .NTRET
;Call
;	NMXVAR/ NX block
;Return
;	RET		;On error, error code loaded into NXERR,+NMXVAR
;	RETSKP		;Success, with user's data string containing list

NMXLND:
	SAVEAC <P1,P2,NT>	;I NEED A LOT OF ACS
	SETZ NT,		;FLAG NOTHING SPECIAL YET
	LOAD P1,NXSEL,+NMXVAR	;FIND OUT WHAT KIND OF LIST HE WANTS
	CAXN P1,.NTLOP		;DID HE WANT LOOP NODES?
	JRST NMXLLN		;YEP, GIVE HIM THOSE
	CAXN P1,.NTACT		;DOES HE WANT ACTIVE NODES?
	JRST NMXLNA		;YEP, GIVE HIM ALL REACHABLE NODES
	CAXE P1,.NTKNO		;DOES HE WANT ALL KNOWN NODES?
	ERRRET NTEUFO		;NOPE - WHAT DOES HE WANT???
	SETO NT,		;FLAG SOMETHING SPECIAL - DO ALL NODES

NMXLNA:	MOVX P2,1		;START AT NODE NUMBER 1
NMXLN2:	CAMLE P2,RTRMXN		;HAVE WE PASSED THE MAXIMUM NODE NUMBER?
	JRST NMXLLN		;YES, DO LOOPBACK NODES NOW.
	JUMPE NT,NMXLN3		;IF ONLY ACTIVE NODES, SKIP OVER SOME CODE
	MOVE T1,P2		;COPY NODE ADDRESS WE WANT TO KNOW ABOUT
	CALL SCTA2N		;ASK SCLINK IF HE EVER HEARD OF THIS NODE
	 JRST NMXLN3		;NOPE, ENQUIRE FURTHER
	JRST NMXLN4		;SCT KNOWS ABOUT IT, GO PUT IT INTO LIST
NMXLN3:	MOVE T1,P2		;COPY NODE NUMBER
	CALL RTNLID		;ASK RTR IF NODE IS REACHABLE
	 AOJA P2,NMXLN2		;NOPE. TRY FOR NEXT NODE
NMXLN4:	MOVE T1,P2		;COPY NODE NUMBER
	ECALL PUT2BT		;PUT NODE NUMBER IN DATA STRING
	SETZ T1,		;NO NAME FOLLOWING, SO A ZERO STRINGID HEAD
	ECALL PUTBYT		;PUT BYTE IN DATA STRING
	AOJA P2,NMXLN2		;GO DO ANOTHER NODE
NMXLLN:	MOVE P2,SCTLNL##	;GET POINTER TO LOOPBACK NODE NAME LIST
NMXLN5:	JUMPE P2,RSKP		;WHEN DONE, RETURN SUCCESS
	LOAD T1,LNNAM,(P2)	;GET THE NAME
	ECALL NMXA21		;CONVERT FROM SIXBIT TO 8BIT STRINGID
	SETZ T1,		;NO NUMBER
	ECALL PUT2BT		;PUT TWO BYTES IN STREAM INDICATING NO NUMBER
	XMOVEI P1,NX.VAL+NMXVAR	;POINT TO THE WHERE THE NODE STRING IS
	ECALL PUTSTR		;COPY THE STRING TO THE USER
	LOAD P2,LNNXT,(P2)	;GET NEXT LOOPBACK NODE BLOCK POINTER
	JRST NMXLN5		;AND LOOP
	SUBTTL Functions -- .NTRET -- List circuit and line names
;NMXLCK - Return a list of line/circuit names
;Call
;	NMXVAR/ NX block
;Return
;	RET			;ON ERROR, NXERR,+NMXVAR CONTAINING ERROR CODE
;	RETSKP			;WITH LIST OF NAMES IN USER DATA STRING

NMXLCK:
	SAVEAC P2		;GET A SCRATCH REGISTER
	MOVE P2,RTRCBQ		;GET POINTER TO CIRCUIT BLOCKS (SINCE WE ARE
				; ONLY LOOKING AT THE BLOCKS, WE CAN DO THIS
				; WITHOUT ANY INTERLOCK. THE CIRCUIT BLOCKS
				; NEVER GET REMOVED, SO A ONCE-VALID POINTER
				; IS ALWAYS VALID).
NMXLC1:	JUMPE P2,RSKP		;IF END OF LIST, WE HAVE FINISHED
	LOAD P1,NXSEL,+NMXVAR	;GET SELECTOR
	CAXN P1,.NTKNO		;TELL ABOUT ALL KNOWN ITEMS?
	 JRST NMXLC4		;YES, JUST LIST IT
	LOAD T1,RCLID,(P2)	;GET THE LINE ID FOR THIS CIRCUIT
	CALL RTNGLS		;ASK RTR FOR THE LINE STATE
	 BUG.(CHK,NTMBLI,NTMAN,SOFT,<Bad Line id>,,<

Cause:	Router has given us an error return when we asked for the state
	of a circuit. The only valid error return from this routine is
	due to the circuit not existing.

Cure:	None known.
>,NTEMPE)
	CAXN P1,.NTLOP		;IS HE ASKING FOR SERVICE STATE?
	 CAXE T1,NCK.SR		;YES, IS THIS IN SERVICE STATE?
	  TRNA			;NO.
	 JRST NMXLC4		;IT'S THE RIGHT FLAVOR. GO LIST IT.
	CAXN P1,.NTACT		;IS HE ASKING FOR ACTIVE STATE?
	 CAXE T1,NCK.ON		;IS THIS LINE ACTIVE?
	  JRST NMXLC7		;NO, ABANDON ALL HOPE FOR THIS LINE
NMXLC4:	LOAD T1,RCLID,(P2)	;GET THE LINE ID AGAIN.
	MOVE T2,[POINT 8,NX.VAL+NMXVAR] ;DATA STORAGE AREA
	ECALL NMXC2N		;CONVERT CIRCUIT-ID TO NAME
	XMOVEI P1,NX.VAL+NMXVAR	;POINT TO THE CIRCUIT NAME STRINGID
	ECALL PUTSTR		;PUT THIS STRING IN THE USER'S BUFFER
NMXLC7:	LOAD P2,RCNXT,(P2)	;GET POINTER TO NEXT CIRCUIT
	JRST NMXLC1		;GO TRY FOR NEXT LINE


	SUBTTL Functions -- .NTEVQ - Pass queued event to user
;Called from NMXDIS

GETEVT::
	SAVEAC <P1,P2,NT>	;NEED FOR POINTER TO NMX BLOCK
	D36OFF			;#AVOID RACES
	DEQUE P2,NMXEVQ,NQ.NXT,GETEVX ;#PULL AN EVENT BLOCK OFF THE QUEUE
	D36ON			;#ALLOW THE REST OF THE WORLD TO RUN AGAIN
	CALL GETEV1		;CALL REST OF CODE AS SUBROUTINE TO TRAP RETURN
	 JRST NMXEP2		;SOMETHING FAILED, RETURN THE BLOCK
	RETSKP			;SUCCESS RETURN

GETEV1:	LOAD T1,NQCCL,(P2)	;GET EVENT CLASS
	ASH T1,6		;SHIFT IT OVER TO MAKE ROOM FOR TYPE
	OPSTR <ADD T1,>,NQCTY,(P2) ;ADD IN EVENT TYPE
	ECALL PUT2BT
	LOAD T1,NQTIM,(P2)	;GET TIME EVENT OCCURRED
	CALL NMXTIM		;GET THE TIMESTAMP
	STKVAR <SEC,MSC>	;SET UP A STKVAR TO HOLD TWO WORDS
	MOVEM T2,SEC		;SAVE SECONDS
	MOVEM T3,MSC		;SAVE MILLISECONDS
	ECALL PUT2BT		;GIVE THE USER THE JULIAN-HALF-DAY
	MOVE T1,SEC		;GET BACK SECONDS
	ECALL PUT2BT
	MOVE T1,MSC		;GET BACK MILLISECONDS
	ECALL PUT2BT
	LOAD T1,NQETP,(P2)	;ENTITY TYPE (NODE, LINE, CIRCUIT)
	ECALL PUT2BT		;SPEC SAYS THIS IS A 2-BYTE FIELD.
	LOAD T1,NQETP,(P2)	;GET ENTITY TYPE AGAIN
	CAXN T1,.NTNOD		;IS IT A NODE?
	 JRST NMXPNO		;YES, PUT NODE ID INTO STRING
	CAXE T1,.NTCKT		;IS IT A CIRCUIT?
	 CAXN T1,.NTLIN		;OR A LINE?
	  JRST NMXPCK		;PUT A CIRCUIT/LINE ID
	AOJ T1,			;BUMP IT UP BY ONE
	TRNE T1,<<377_8>+377>	;DO WE NOW HAVE ELEVENISH 0?
	 BUG.(CHK,NTMURE,NTMAN,SOFT,<Unrecognized entity type>,,<

Cause:	We have received an event from a DECnet layer, and the entity
	type is not legal.

Cure:	Find the routine which generated the event, and cause it to
	supply a legal entity type.
>,NTEMPE)
;NO ENTITY TYPE. FALL THROUGH TO DATA STRING
NMXEPP:	MOVE P1,[POINT 8,NQ.STR(P2)] ;BYTE POINTER TO DATA STRING
	ILDB NT,P1		;GET NUMBER OF BYTES TO COPY
	JUMPE NT,NMXEP2		;IF NOTHING TO COPY, FALL THROUGH.
NMXEP1:	ILDB T1,P1		;GET NEXT DATA BYTE
	ECALL PUTBYT		;STORE BYTE IN USER DATA STREAM
	SOJG NT,NMXEP1		;AND COPY MORE BYTES UNTIL DONE
NMXEP2:	SKIPE T1,NMXLST		;WAS THERE A LOST EVENT?
	JRST NMXEP3		;YES, QUEUE A LOST EVENT.
	MOVE T1,P2		;POINTER TO THE NQ BLOCK
	CALL DNFEBL		;FREE THE QUEUED EVENT BLOCK
	RETSKP			;AND RETURN SUCCESS.

NMXEP3:	SETZM NMXLST		;ZERO FLAG OF LOST EVENTS
	STOR T1,NQTIM,(P2)	;STORE THE ORIGINAL TIMESTAMP IN LOST BLOCK
	SETZRO <NQCTY,NQCCL,NQETP,NQEID,NQSTR>,(P2) ;ZERO FOR LOST EVENT
	D36OFF			;AVOID ANYONE TOUCHING THE QUEUE
	ENDQUE P2,NMXEVQ,NQ.NXT,T1 ;QUEUE THE LOST BLOCK UP
	D36ON			;AND LET THE WORLD BACK IN.
	RETSKP			;AND RETURN

NMXPNO:
	LOAD T1,NQEID,(P2)	;GET ENTITY ID (NODE NUMBER)
	ECALL PUT2BT		;PUT IT IN USER STRING AS TWO BYTES
	SETZ T1,		;BYTE INDICATING HOW MANY BYTES FOR NAME
	ECALL PUTBYT		;SINGLE BYTE INDICATING NO NAME
	JRST NMXEPP		;AND FINISH OFF THE EVENT RETURNING

NMXPCK:
	LOAD T1,NQEID,(P2)	;GET ENTITY ID (LINE/CIRCUIT ID)
	MOVE T2,[POINT 8,NX.VAL+NMXVAR] ;WHERE TO STORE CIRCUIT NAME STRING
	ECALL NMXC2N		;CONVERT THE ID TO A NAME
	XMOVEI P1,NX.VAL+NMXVAR	;POINTER TO STRING CONTAINING THE NAME
	ECALL PUTSTR		;COPY THE ENTITY NAME TO USER BLOCK
	JRST NMXEPP		;FINISH OFF COPYING THE EVENT BLOCK

GETEVX:	D36ON			;#ALLOW INTERRUPTS
	JRST NTEOPF		;OPERATION FAILURE (NO EVENTS TO RETURN)
	SUBTTL Entities -- Convert entity names to entity ids

;Called from NMXDIS

ENTCVT:	SETZRO NXNTY,+NMXVAR	;NO NODE AS OF YET
	CALLRET @.+1-.NTNOD(P1)
	  IFIW NODCVT		;CONVERT NODE TYPE
	  IFIW LINCVT		;LINE TYPE
	  IFIW NTEURC		;LOGGING. PUNT, WE DON'T DO THESE
	  IFIW LINCVT		;SAME AS LINE
	  IFIW NTEURC		;MODULE - ILLEGAL
	  IFIW NTEURC		;ILLEGAL.


;Called from ENTCVT

NODCVT:
	SAVEAC <P1>		;NEED FOR TEMP BYTE STORAGE
	ECALL GETEBY		;GET ENTITY STRING BYTE
	MOVE P1,T1		;SAVE THE BYTE FOR A WHILE
	ECALL GETEBY		;GET ANOTHER BYTE
	ASH T1,^D8		;SHIFT HIGH-ORDER BYTE OVER
	IOR T1,P1		;INCLUDE LOW ORDER BYTE
	JUMPN T1,NODCV0		;IF WE HAVE AN ADDRESS, WE ARE OK
	ECALL GETSTI		;NO ADDRESS, I MUST HAVE A NAME
	CALL NMXN2A		;CONVERT THE NAME TO AN ADDRESS.
	 JRST NODCV2		;NO SUCH NAME, MUST BE LOOPBACK
NODCV0:	STOR T1,NXNUM,+NMXVAR	;SAVE IN ARGUMENT BLOCK
	CAME T1,RTRADR		;IS THIS US?
	 JRST NODCV1		;NOPE
	MOVX T1,NX.EXN		;THIS IS THE EXECUTOR NODE
	STOR T1,NXNTY,+NMXVAR	;DECLARE TYPE OF NODE
	RETSKP			;WE'RE DONE, RETURN
NODCV1:	MOVX T1,NX.REN		;THIS IS A REMOTE NODE
	STOR T1,NXNTY,+NMXVAR	;DECLARE THAT THIS IS A NODE, AND WHAT TYPE
	RETSKP
NODCV2:	LOAD T2,NXFNC,+NMXVAR	;GET THE FUNCTION CODE WE ARE TO DO
	CAXE T2,.NTSET		;IS THIS A SET?
	CALL SCTCKL##		;NO, MAKE SURE THE LOOPBACK NODE EXISTS
	  TRNA			;ACCEPTABLE
	ERRRET NTEURC		;UNRECOGNIZED COMPONENT
	STOR T1,NXNUM,+NMXVAR	;SAVE THE NODNAME IN NXNUM
	MOVX T1,NX.LPN		;THIS IS A LOOPBACK NODE
	STOR T1,NXNTY,+NMXVAR	;SAVE THE NODE TYPE
	RETSKP

;Called from ENTCVT

LINCVT:
	ECALL GETSTI		;COPY MULTIPLE BYTES (INTERNAL LIMIT 16)
	MOVE T1,[POINT 8,NX.VAL+NMXVAR] ;BYTE POINTER TO LINE NAME WE COPIED
	ECALL NMXN2C		;CONVERT NAME TO LINE-ID
	STOR T1,NXNUM,+NMXVAR	;SAVE AWAY LINE ID
	RETSKP
	SUBTTL Entities -- Circuit ID to name conversion
;NMXC2N - Convert circuit ID to name
;Call
;	T1/ Circuit ID
;	T2/ Local byte pointer to use in returning bytes
;	Area must be large enough to receive 16 bytes.
;Return
;	+1/ No such circuit ID
;	+2/ Data area has stringid for circuit name
;

NMXC2N::
	SAVEAC <P1,P2>		;SOME SCRATCH ACS
	DMOVE P1,T1		;SAVE BOTH ARGUMENTS FOR THIS CALL
	SETZ T6,		;NUMBER OF BYTES DEPOSITED
	IDPB T6,P2		;FIRST BYTE IS COUNT OF BYTES FOLLOWING
	MOVE T5,P2		;SAVE BYTE POINTER TO COUNT BYTE
	LOAD T1,LIDEV,+P1	;GET THE TYPE OF DEVICE
	CAXLE T1,LD.MAX		;IN RANGE OF DEVICES WE KNOW?
	 BUG.(CHK,NTMKOR,NTMAN,SOFT,<Kontroller out of range in Circuit-id>,,<

Cause:	The Kontroller field in a line-id is out of range. The value
	LD.MAX defines the number of Kontrollers known by D36PAR, and
	thus by NTMAN. The most likely cause of this bug is a trashed
	AC.

Note:	A Kontroller is any device driver to which router will interface.
	It is currently used to define the name of a Circuit/Line,
	under the assumption that each Kontroller will control only
	a single line type.
>,RTN)
;WE KNOW THAT ALL DEVICE NAMES ARE AT MOST 4 BYTES LONG, AND THUS FIT IN A WORD
	HRLI T2,(POINT 7,)	;WE STORE THE DATA IN 7 BIT BYTES INTERNALLY
	HRRI T2,KONNAM(T1)	;GET POINTER TO DEVICE NAME
NMXC20:	ILDB T1,T2		;GET A BYTE FROM THE DEVICE NAME
	JUMPE T1,NMXC21		;END OF STRING, FALL THROUGH
	IDPB T1,P2		;SAVE IT IN OUR DESTINATION DATA STRING
	AOJA T6,NMXC20		;INCREMENT NUMBER OF BYTES DEPOSITED
NMXC21:	MOVEI T1,"-"		;SEPERATOR
	IDPB T1,P2		;STORE IT
	AOJ T6,			;COUNT UP CHARACTER
	LOAD T1,LIKON,+P1	;GET THE KONTROLLER NUMBER
	PUSHJ P,NMXC28		;OUTPUT NUMBER IN DECIMAL
	MOVEI T1,"-"
	IDPB T1,P2		;STORE THE SEPARATOR
	AOJ T6,			;INCREMENT NUMBER OF BYTES
	LOAD T1,LIUNI,+P1	;GET THE UNIT NUMBER
	PUSHJ P,NMXC28		;OUTPUT THE NUMBER IN DECIMAL
	LOAD T1,LIDEV,+P1	;GET THE DEVICE TYPE
	CAXE T1,LD.CIP		;IS IT A CI?
	JRST NMXC22		;NO, WE ARE DONE
	MOVEI T1,"."		;OUTPUT SEPERATOR
	IDPB T1,P2		;STORE IT
	AOJ T6,			;AND INCREMENT COUNT
	LOAD T1,LIDRP,+P1	;GET THE DROP NUMBER (PORT ON THE CI)
	PUSHJ P,NMXC28		;AND OUTPUT IT IN DECIMAL
NMXC22:	CAIL T6,^D16		;DID WE DO THIS IN 16 BYTES?
	BUG.(HLT,NTMCNO,NTMAN,SOFT,<Circuit name overrun>,,<

Cause:	We have returned more than 16 bytes of data into a 16 byte field.
	The data beyond the buffer has been trashed.

Cure:	Examine the algorithm above to determine why we returned more
	bytes than we expected. While you are at it, fix the above
	code to check for overrun while it is producing the bytes, so
	that we don't have this embarrasing halt.
>)
	DPB T6,T5		;STORE NUMBER OF BYTES WE GAVE
	RETSKP

NMXC28:	IDIVI T1,^D10		;SEPERATE INTO DIGITS
	JUMPE T1,NMXC29		;COMPLETED THE SEPARATION, START OUTPUTTING.
	PUSH P,T2		;SAVE DIGIT ON STACK
	PUSHJ P,NMXC28		;RECURSE
	POP P,T2		;GET BACK DIGIT
NMXC29:	ADDI T2,"0"		;MAKE IT INTO AN ASCII DIGIT
	IDPB T2,P2		;DEPOSIT INTO STRING
	AOJ T6,			;INCREMENT NUMBER OF BYTES GIVEN
	RET			;RETURN
	SUBTTL Entities -- Convert name to Circuit-ID.
;NMXN2C - Convert a string to line id
;Call
;	T1/ Byte pointer to name
;Return
;	+1, No such circuit
;	+2, t1/ Circuit ID

NMXN2C:
	SAVEAC <P1,P2>		;WORK REGISTERS
	MOVE P1,T1		;SAVE BYTE POINTER TO NAME
	MOVE T6,[POINT 7,T2]	;BYTE POINTER TO COPY NAME
	MOVEI T5,5		;MAX OF 5 BYTES (ONE WORD)
	ILDB T4,P1		;GET NUMBER OF BYTES IN THIS STRINGID
	SETZB T2,P2		;CLEAR OUT DESTINATION, AND CIRCUIT ID
NMXN20:	SOJL T4,NTEINI		;TERMINATED TOO SOON. INVALID
	ILDB T1,P1		;GET A BYTE
	CAIL T1,140		;IS IT LOWER CASE?
	SUBI T1,40		;YES, MAKE IT UPPER CASE
	CAIN T1,"-"		;DID IT INCLUDE THE DASH?
	 JRST NMXN21		;YES, STOP HERE.
	IDPB T1,T6		;SAVE IN COPYING STRING
	SOJG T5,NMXN20		;GET ANOTHER BYTE
	ERRRET NTEINI		;ILLEGAL NAME, GIVE UNRECOGNIZED COMPONENT
NMXN21:	MOVEI T1,LD.MAX		;MAXIMUM KONTROLLER DEVICE NUMBER
NMXN22:	CAMN T2,KONNAM(T1)	;IS THIS THE CONTROLLER WE CARE ABOUT?
	 JRST NMXN23		;YES, EXIT
	SOJGE T1,NMXN22		;TRY FOR NEXT KONTROLLER DEVICE NUMBER
	ERRRET NTEINI		;ILLEGAL NAME
NMXN23:	STOR T1,LIDEV,+P2	;STORE IN CIRCUIT ID WE ARE BUILDING
	CALL NMXN28		;GET A NUMBER FROM THE STRING
	STOR T1,LIKON,+P2	;STORE AS KONTROLLER NUMBER IN CIRCUIT ID
	CALL NMXN28		;GET THE NEXT NUMBER FROM THE STRING
	STOR T1,LIUNI,+P2	;SAVE UNIT NUMBER
	CALL NMXN28		;GET NEXT NUMBER (IF ANY)
	STOR T1,LIDRP,+P2	;SAVE AS DROP NUMBER (PORT ON CI)
	MOVE T1,P2		;GET THE CIRCUIT ID WE JUST BUILT
	CALL RTNGLS		;GET THE LINE STATE (JUST TO VERIFY CIRCUIT)
	 ERRRET NTEURC		;NO SUCH CIRCUIT
	MOVE T1,P2		;GET THE CIRCUIT AGAIN.
	RETSKP			;RETURN SUCCESS.

NMXN28:	SETZ T1,		;CLEAR DESTINATION NUMBER
NMXN29:	SOJL T4,RTN		;NO MORE BYTES, RETURN
	ILDB T2,P1		;GET NEXT DIGIT
	CAIL T2,"0"		;RANGE
	CAILE T2,"9"		; CHECK
	RET			;NOT A DIGIT
	SUBI T2,"0"		;CONVERT TO NUMBER
	IMULI T1,^D10		;SHIFT ORIGINAL NUMBER
	ADD T1,T2		;ADD IN CURRENT DIGIT
	JRST NMXN29		;AND GET ANOTHER DIGIT

	SUBTTL Layers -- Main interface to layer levels
;NMXLAY - Call layer-level routine, to get/set value.
;CALL
;	NMXVAR/ NX block
;	NT/ Pointer to STENT part of NT block
;Return
;	RET			;on error, NXERR has code
;	RETSKP			;NXNIL will be set if this layer does not
;				; know about this entity.
NMXLAY:
	SETZRO NXNIL,+NMXVAR	;CLEAR THE "I DIDN'T DO ANYTHING" FLAG
	LOAD T1,NTDFL,(NT)	;GET DEFAULT VALUE, IF ANY
	TMNE NXZMC,+NMXVAR	;ARE WE CLEARING/ZEROING?
	STOR T1,NXVAL,+NMXVAR	;YES, SET DEFAULT AS VALUE TO SET
	LOAD T1,NTROU,(NT)	;GET ROUTINE FOR THIS PARAMETER
	CAXGE T1,NMXMAX		;RANGE CHECK
	CAXGE T1,NMXMIN
	BUG.(CHK,NTMDVI,NTMAN,SOFT,<NMXDSP value illegal>,,<

Cause:	We are going to call a "layer" to obtain or set a value for
	an item. The routine value in the descriptor block pointed
	to by NT is illegal.

Cure:	Examine the data structure pointed to by NT. In all probability
	this is caused by a trashed NT, since the descriptor block
	generation macros are supposed to range check this value.

Note:	A "layer" is any routine described at NMXDSP.
>,NTEMPE)
	CALLRET @NMXDSP(T1)	;CALL LAYER-LEVEL ROUTINE

	SUBTTL Layers -- Read/set NSP node blocks

;Called from NMXLAY through NMXDSP+NSP

;NMXNSP - NMX's handler of some NSP parameters. Will extract anything
;	NSP keeps in it's node block

NMXNSP::
	LOAD T1,NXNUM,+NMXVAR	;GET NUMBER OF ENTITY (NODE ADDRESS)
	CALL SRHNOD		;SEARCH FOR THE NODE
	 JRST NMXNIL		;NOT KNOWN HERE, BUT DO REST OF THE STUFF
	LOAD T2,NXPRM,+NMXVAR	;GET PARAMETER PASSED TO US (POINTER TO BPT)
	JUMPE T2,NSPNM2		;IS IT SECONDS SINCE LAST ZEROED?
	TMNN NXWRM,+NMXVAR	;AM I WRITING THE MONITOR'S DATA?
	 JRST [LDB T3,(T2)	;GET VALUE FROM ENTITY
		JRST NSPNM1]	;AND JOIN COMMON CODE BELOW
	LOAD T4,NXVAL,+NMXVAR	;GET VALUE SENT BY PROGRAM
	D36OFF			;#DON'T ALLOW RACES
	LDB T3,(T2)		;#GET ORIGINAL VALUE
	DPB T4,(T2)		;#STORE NEW VALUE (PROBABLY ZERO)
	D36ON			;#ALLOW RACES AGAIN.
NSPNM1:	STOR T3,NXVAL,+NMXVAR	;SAVE OLD VALUE IN ARG BLOCK
	RETSKP

NSPNM2:	SAVEAC P1		;POINTER TO NN BLOCK
	MOVE P1,T1		;SAVE FOR LATER USE
	CALL DNGTIM		;GET CURRENT TIME STAMP
	JN NXZMC,+NMXVAR,NSPNM3	;IF ZEROING, SPECIAL CODE
	OPSTR <SUB T1,>,NNSLZ,(P1) ;GET OFFSET IN MILLISECONDS
	IDIVI T1,TIMBAS		;AND CONVERT TO SECONDS
	STOR T1,NXVAL,+NMXVAR	;SAVE FOR NMXLAY
	RETSKP

NSPNM3:	LOAD T2,NNSLZ,(P1)	;GET OLD TIME STAMP
	STOR T1,NNSLZ,(P1)	;STORE CURRENT TIME STAMP
	SUB T1,T2		;GET OFFSET
	IDIVI T1,TIMBAS		;CONVERT TO SECONDS
	STOR T1,NXVAL,+NMXVAR	;SAVE FOR NMXLAY
	RETSKP


	SUBTTL Layers -- Read/set RTR circuit blocks
;NMXRTL - call RTR to do line stuff
;Call
;	NT/ Pointer to format block
;	NMXVAR/ NX Block
;Return
;	RET			;if invalid line id in NXNUM
;	RETSKP			;With value set or loaded into NXVAL

NMXRTL::
	LOAD T1,NXNUM,+NMXVAR	;GET LINE ID
	LOAD T2,NTIDX,(NT)	;GET POINTER TO BYTE POINTER IN RTR
	XMOVEI T3,+NMXVAR	;COPY OF NX FOR RTR
	CALL RTRNMX		;ASK RTR DO DO SOME NMX STUFF
	 ERRRET NTEURC		;BAD LINE ID
	STOR T1,NXVAL,+NMXVAR	;SAVE FOR CALLER TO PICK UP
	RETSKP			;RETURN SUCCESS

;NMXRTD - Special case of NMXRTL, re-formatting the output to look nice
;	to NML.

NMXRTD:	ECALL NMXRTL		;DO THE ACTUAL WORK.
	LOAD T1,NXVAL,+NMXVAR	;GET NODE ADDRESS
	CALL NMXA2N		;CONVERT ADDRESS TO NAME
	CALLRET NMXNIL		;FLAG WE DIDN'T DO ANYTHING
	RETSKP			;AND RETURN "SUCCESS" (WE DIDN'T FAIL)


;NMXRTS - Call router to do stuff with circuit state
;Call
;Return
;	Ret			;If state cannot be set or other error
;	RETSKP			;Success.

NMXRTS:	LOAD T1,NXNUM,+NMXVAR	;GET LINE ID TO SET STATE OF
	JN NXWRM,+NMXVAR,NMXRT2	;IF SETTING LINE STATE, OTHER CODE
	CALL RTNGLS		;ASK WHAT THE LINE STATE IS
	 BUG.(CHK,NTMXNL,NTMAN,SOFT,<ROUTER doesn't know about a line>,,<

Cause:	We have asked router for the state of a circuit, and router has
	given us a failure return. The only valid failure is for a non-existant
	circuit, and we are supposed to check the circuit ID for existance
	at ENTCVT before getting here.
>,NTEMPE)
	STOR T1,NXVAL,+NMXVAR	;SAVE STATE FOR USER
	RETSKP			;RETURN SUCCESS

NMXRT2:	LOAD T2,NXVAL,+NMXVAR	;GET LINE STATE TO SET TO
	CAXL T2,NCK.ON		;RANGE CHECK THE REQUESTED
	CAXLE T2,NCK.SR		;STATE (OR ELSE ROUTER BUGCHKS)
	ERRRET NTEIPV		;INVALID PARAMETER VALUE
	CALL RTNSLS		;ASK ROUTER TO SET THE CIRCUIT STATE
	 ERRRET NTEOPF		;SAY THAT THE OPERATION FAILED.
	RETSKP			;SUCCESS, RETURN

NMXRTB:	LOAD T1,NXNUM,+NMXVAR	;GET LINE ID OF CIRCUIT WE ARE GOING TO READ
	TMNE NXWRM,+NMXVAR	;MAKE SURE WE ARE READING
	BUG.(CHK,NTMSSB,NTMAN,SOFT,<Setting a circuit substate>,,<

Cause:	Setting a substate is illegal - This entry should be READ-ONLY
	in the descriptor block, and we should have caught this before.

Action:	Make the entry in the descriptor block be READ ONLY.
>,NTEMPE)
	CALL RTNGLB		;ASK ROUTER FOR SUBSTATE (IF APPLICABLE)
	 CALLRET NMXNIL		;FLAG WE DIDN'T DO ANYTHING
	STOR T1,NXVAL,+NMXVAR	;SAVE SUBSTATE FOR USER
	RETSKP			;AND SAY WE DIDN'T FAIL.
	SUBTTL Layers -- Read/set node state
;Read a state for any node, and set node on for executor
;Call
;	NXNUM,+NMXVAR/ node number
;	NXNTY,+NMXVAR/ node type
;	NXVAL,+NMXVAR/ state to be set to, or place to return value
;Return
;	RET			;on error, with error code in NXERR
;	RETSKP			;Success, with state in NXVAL if read.

NMXNMS:
;	JN NXWRM,+NMXVAR,NTEFNS	;WE DON'T SUPPORT SETTING NODE STATE
	LOAD T1,NXNTY,+NMXVAR	;WHAT KIND OF NODE IS THIS?
	CAXN T1,NX.EXN		;IS IT THE EXECUTOR NODE?
	 JRST NMXNS2		;YES, DO SPECIAL STUFF
	LOAD T1,NXNUM,+NMXVAR	;NODE WHICH WE ARE ASKING ABOUT
	CALL RTNLID		;ASK ROUTER WHAT HE THINKS ABOUT THIS NODE
	 SKIPA T1,[5]		;UNREACHABLE. RETURN CODE
	MOVX T1,4		;REACHABLE.
	STOR T1,NXVAL,+NMXVAR	;SAVE FOR NICE TO PRINT OUT
	RETSKP			;VOILA!

NMXNS2:
	SETZRO NXVAL,+NMXVAR	;STATE IS ON, WHICH IS THE ONLY SUPPORTED STATE
				;FOR THE EXECUTOR NODE.
	RETSKP
	SUBTTL Layers -- Read/set executor node information
;Called through NMXDSP+EXE

NMXEXE::LOAD T2,NTIDX,(NT)	;GET INDEX, IN THIS CASE, POINTER TO WORD
;	CALLRET NMXVAL		;HAVE POINTER, JUST DO THE FUNCTION

NMXVAL:
;All is OK, do the requested function
	LOAD T1,NXVAL,+NMXVAR	;STORE NEW VALUE WITH EXCHANGE
	TMNN NXWRM,+NMXVAR	;WRITE VALUE?
	SKIPA T1,(T2)		;NO, READ, RETURN WITH OLD VALUE
	EXCH T1,(T2)		;RETURN OLD VALUE IN T1
	STOR T1,NXVAL,+NMXVAR	;SAVE VALUE FOR POSTERITY
	RETSKP			;SUCCESS RETURN


	SUBTTL Layers -- Read/set RTR node information


;NMXXND - Do NMX functions for all RTR nodes. This information is entirely
;	in RTR, so we extract information from the routing vector.

NMXXND::
	LOAD T1,NXNUM,+NMXVAR	;GET NODE NUMBER
	CALL RTNLID		;FIND OUT IF IT IS REACHABLE
	 JRST NMXNIL		;FLAG WE DIDN'T DO ANTYING
	LOAD T2,NXNUM,+NMXVAR	;GET NODE NUMBER AGAIN.
	TMNN NXWUS,+NMXVAR		;MAKE SURE WE ARE WRITING USER'S STRING
	 BUG.(CHK,NTMBCX,NTMAN,SOFT,<Bad call to NMXXND>,,<

Cause:	We have called a "layer" which handles information in Router's
	routing vector. All the information in this vector is supposed
	to be read only, but we have been called for a set or clear.

Cure:	Look at the descriptor block pointed to by NT, and determine
	which item caused this layer to be called. Then fix the item's
	entry to indicate that this is a read-only parameter.
>,NTEMPE)
	ADD T2,RTRNRV		;ADD IN ADDRESS OF VECTOR, GETTING REAL ADDRESS
	LOAD T3,NXPRM,+NMXVAR	;GET ADDRESS OF BYTE POINTER TO FIELD
	LDB T1,(T3)		;GET VALUE ITSELF
	STOR T1,NXVAL,+NMXVAR	;SAVE FOR CALLER.
	RETSKP			;HAVE THE VALUE, RETURN

	SUBTTL Layers -- Find circuit which points to a node

;Called from NMXLAY through NMXDSP+CIR

;NMXCIR - Get Circuit pointing to this node

NMXCIR::
	LOAD T1,NXNUM,+NMXVAR	;GET NODE NUMBER
	CAMN T1,RTRADR		;EXECUTOR NODE?
	JRST NMXNIL		;YUP, DON'T LET HIM TRY FOR THIS.
	CALL RTNLID		;GET LINE POINTING TO THIS NODE
	 JRST NMXNIL		;SORRY, NO PATH TO NODE.
	MOVE T2,[POINT 8,NX.VAL+NMXVAR] ;POINTER TO VALUE AREA
	CALLRET NMXC2N		;CONVERT CIRCUIT ID TO NAME
				;VALUE IS NOW IN NXVAL, RETURN
	SUBTTL Layers -- Set/clear node names

;Called from NMXLAY through NMXDSP+NMC
NMXNMC::SETZ T1,		;START OFF WITH A CLEAR NODE NAME
	JN NXZMC,+NMXVAR,NMXNM2	;IF WE ARE CLEARING, THIS IS GOOD ENOUGH.
	MOVE T4,[POINT 6,T1]	;DESTINATION BYTE POINTER FOR SIXBIT NAME
	MOVE T3,[POINT 8,NX.VAL+NMXVAR] ;POINTER TO STRINGID CONTAINING NAME
	ILDB T2,T3		;GET NUMBER OF BYTES IN NODE NAME
	JUMPE T2,NMXNM2		;IF NO BYTES, FALL INTO CLEAR CODE
NMXNM0:	ILDB T5,T3		;GET A BYTE FROM THE NODE NAME STRINGID
	CAIL T5,^O140		;IS IT LOWER CASE
	SUBI T5,^O40		;MAKE IT UPPER CASE
	SUBI T5,^O40		;MAKE IT SIXBIT
	IDPB T5,T4		;STORE IT IN THE SIXBIT NODE NAME
	SOJG T2,NMXNM0		;LOOP UNTIL ENTIRE NAME COPIED.
NMXNM2:	LOAD T2,NXNUM,+NMXVAR	;GET NODE ADDRESS
	CALL SCTAND		;SET THE NODE NAME FOR THIS NODE
	 ERRRET	NTENRM		;NAME ALREADY TAKEN.
	RETSKP			;SUCCESS
	SUBTTL Layers -- Create/Destroy loopback nodes

;Called from NMXLAY through NMXDSP+LLP
;Loopback nodes
NMXLLP:	JN NXZMC,+NMXVAR,NMXLL1	;IF WE ARE CLEARING, DON'T LOOK FOR CIRCUIT
	JE NXWRM,+NMXVAR,NMXLL2	;IF WE ARE READING, DON'T TRY TO SET STUFF
	MOVE T1,[POINT 8,NX.VAL+NMXVAR] ;BYTE POINTER TO CIRCUIT NAME
	ECALL NMXN2C		;CONVERT IT TO LINE ID
	SKIPA T2,T1		;COPY TO WHERE SCTANL EXPECTS IT
NMXLL1:	SETZ T2,		;CLEAR THE CIRCUIT
	LOAD T1,NXNUM,+NMXVAR	;GET NODE NAME
	CALL SCTANL##		;ADD LOOPBACK NODE NAME
	 ERRRET NTENRM		;NAME ALREADY TAKEN, OR NO ROOM
	RETSKP			;DONE.

NMXLL2:	LOAD T1,NXNUM,+NMXVAR	;GET THE NODE NAME
	CALL SCTN2L##		;CONVERT THE NAME TO CIRCUIT BLOCK POINTER
	 ERRRET NTEURC		;UNRECOGNIZED COMPONENT
	MOVE T2,[POINT 8,NX.VAL+NMXVAR] ;VALUE AREA TO USE
	CALLRET NMXC2N		;CONVERT CIRCUIT ID TO NAME
	SUBTTL Layers -- Call the data link layer
;Called from NMXLAY through NMXDSP+DLL

NMXDLL:
	LOAD T1,NXNUM,+NMXVAR	;GET ENTITY ID (LINE ID)
	LOAD T5,LIDEV,+T1	;STORE KONTROLLER FOR LATER
	CALL RTRKBA		;CONVERT TO POINTER TO CIRCUIT BLOCK
	 BUG.(CHK,NTMILI,NTMAN,SOFT,<Invalid Line ID>,,<

Cause:	We have called NMXDLL to perform a function for a line, and the
	previously validated line id is bad. The probable cause is
	something trashing NMXVAR+NXNUM
>,NTEMPE)
	LOAD T4,NXFLG,+NMXVAR	;GET FLAGS FOR FUNCTION
	MOVX T1,KF.RED		;ASSUME READ
	TXNE T4,NX%WRM		;ARE WE WRITING TO THE MONITOR?
	MOVX T1,KF.SET		;YES, ASSUME SET
	TXNE T4,NX%ZMC		;ARE WE DOING A CLEAR?
	MOVX T1,KF.CLR		;YES, CLEAR FUNCTION
	LOAD T3,NTSEQ,(NT)	;GET PARAMETER NUMBER
	TXNE T4,NX%CXP		;IS THIS A COUNTER?
	IOR T3,1_^D15		;YES, MARK IT AS SUCH FOR DLL
	LOAD T4,NXVAL,+NMXVAR	;GET VALUE FOR SET (IF ANY)
	CALL @KONDSP##(T5)	;CALL THE KONTROLLER
	 JRST NMXDL1		;HANDLE ERROR RETURN
	STOR T1,NXVAL,+NMXVAR	;STORE IN CASE IT WAS A READ
	RETSKP			;RETURN SUCCESS

NMXDL1:	JUMPN T1,NTEOPF		;IF ANY KIND OF ERROR CODE, FLAG THE ERROR
NMXNIL:	SETONE NXNIL,+NMXVAR	;SET FLAG SAYING "I DIDN'T DO ANYTHING"
	RETSKP			;AND RETURN SUCCESS


	SUBTTL Events -- Event receiver
;Receive an event, from some module.
;Call
;	T1/ Pointer to NE begstr to put on queue
;	This should be obtained with a CALL DNGEBL
;Return
;	RET	always.
NMXEVT::
	SAVEAC <P1,P2>		;SAVE AN AC TO BLOCK
	MOVE P2,T1		;SAVE POINTER TO EVENT BLOCK
	CALL DNGEBL		;GET A BLOCK FOR THIS EVENT
	 JRST NMXEQF		;EVENT BLOCKS USED UP - QUEUE MUST BE FULL
	MOVE P1,T1		;SAVE POINTER TO OUR EVENT BLOCK
	CALL DNGTIM		;GET CURRENT TIME OF DAY
	STOR T1,NQTIM,(P1)	;STASH AWAY FOR LATER USERS
	LOAD T1,NECCL,(P2)	;GET EVENT CLASS
	LOAD T2,NECTY,(P2)	;GET EVENT TYPE
	LOAD T3,NEETP,(P2)	;GET ENTITY TYPE
	LOAD T4,NEEID,(P2)	;GET ENTITY ID
	STOR T1,NQCCL,(P1)	;STORE AWAY IN OUR BLOCK
	STOR T2,NQCTY,(P1)	;STORE IN OUR BLOCK
	STOR T3,NQETP,(P1)	;STORE ENTITY TYPE
	STOR T4,NQEID,(P1)	;STORE ENTITY ID
	LOAD T5,NEDAT,(P2)	;GET FULLWORD POINTER TO DATA STRING
	LOAD T4,NEDLN,(P2)	;LENGTH OF DATA STRING
	CAXL T4,.NQMXS		;MAKE SURE IT WILL FIT
	 BUG.(CHK,NTMESL,NTMAN,SOFT,<Event string too long>,,<

Cause:	We have received an event from a DECnet layer, and the
	length of the data string is too long to fit in our storage
	block.

Cure:	Either increase the size of .NQMXS or persuade the DECnet layer
	to return a smaller string.
>,NMXEVE)
	MOVE T3,[POINT 8,(T5)]	;MAKE A BYTE POINTER TO HIS STRING
	MOVE T2,[POINT 8,NQ.STR(P1)] ;MAKE A BYTE POINTER TO OUR STRING
	IDPB T4,T2		;FIRST BYTE OF STRING IS DATA LENGTH
NMXEV1:	JUMPE T4,NMXEV2		;IF NO BYTES LEFT, STOP COPYING
	ILDB T1,T3		;GET A BYTE FROM HIS STRING
	IDPB T1,T2		;STORE IT INTO OUR STRING
	SOJG T4,NMXEV1		;GO DO MORE BYTES
NMXEV2:	D36OFF			;TURN OFF INTERRUPTS.
	ENDQUE P1,NMXEVQ,NQ.NXT,T1 ;QUEUE THIS BLOCK UP
	D36ON			;LET THEM COME BACK IN
	CALL PSIDVT		;NOTIFY THE WORLD ABOUT AN EVENT
	RETSKP			;RETURN.

NMXEQF:
	CALL DNGTIM		;GET CURRENT TIME OF DAY
	D36OFF			;TURN OFF DECNET
	SKIPN NMXLST		;HAVE WE ALREADY LOST AN EVENT?
	MOVEM T1,NMXLST		;NOPE, FLAG WHEN WE LOST THIS ONE
NMXEVF:	D36ON			;TURN DECNET BACK ON.
NMXEVE:	MOVE T1,P2		;RETURN BLOCK OF CORE TO FREE POOL
	RET			;RETURN ERROR

	SUBTTL User strings -- Write parameter with nice
;NMXWTY - Write a parameter to the user data string, including NICE
;	headers such as DATA ID and DATA TYPE
;Call
;	NT/ Pointer to STENT part of NT block
;	NXVAL,+NMXVAR/ Value obtained from NMXLAY
;	NXNIL,+NMXVAR/ if on, return immediatley, don't do anything.
;Return
;	RET			;On error, NXERR has error code
;	RETSKP			;when done, maybe with stuff in user string
;

NMXWTY:
	JN NXNIL,+NMXVAR,RSKP	;IF LAYER DIDN'T KNOW ABOUT HIM, IGNORE IT.
	JE NXWUS,+NMXVAR,RSKP	;IF NOT WRITING TO THE USER, RETURN
	SETZ T1,		;START OFF WITH A CLEAN HEADER DUO-BYTE
	JE NXCXP,+NMXVAR,NMXWT2	;SKIP OVER COUNTER ONLY CODE IF PARAMETER
	LOAD T1,NTLEN,(NT)	;GET COUNTER SIZE
	CAXN T1,4		;IS IT SIZE 4?
	 MOVX T1,3		;NICE WANTS IT TO GET A 3
	ASH T1,^D13		;SHIFT IT INTO WIDTH FIELD OF HEADER FIELD
	TXO T1,1_^D15		;TURN ON BIT INDICATING A COUNTER HEADER
NMXWT2:	LOAD T2,NTSEQ,(NT)	;GET SEQUENCE NUMBER OF PARAMETER OR COUNTER
	IOR T1,T2		;OR INTO HEADER DUO-BYTE
	ECALL PUT2BT		;PUT 2 BYTES OF HEADER INTO USER DATA STRING
NMXWT3:	LOAD T1,NTTYP,(NT)	;GET DATA TYPE OF THIS PARAMETER
	CAXL T1,NT.FC		;IS IT LESSER THAN SIMPLE CODED?
	CAXLE T1,NT.FCB		;OR GREATER THAN BIT MAPPED COUNTER?
	BUG.(CHK,NTMFOR,NTMAN,SOFT,<Format out of range>,,<

Cause:	We are formatting output for a show, and the format block for
	this item has an illegal format type.
>,NTEMPE)
	CALLRET @.+1-NT.FC(T1)
	  IFIW NMXWCD		;ORDINARY CODED. HANDLE AS INTEGER
	  IFIW RSKP		;CODED MULTIPLE IS HANDLED AT ANOTHER LEVEL
	  IFIW NMXWAI		;ASCII IMAGE. STRINGID
	  IFIW NMXWNU		;DECIMAL UNSIGNED
	  IFIW NMXWNU		;DECIMAL SIGNED.
	  IFIW NMXWNU		;HEXADECIMAL INTEGER.
	  IFIW NMXWAI		;HEX IMAGE. BYTE STRING
	  IFIW NMXWNU		;OCTAL
	  IFIW NMXWNM		;MILLISECONDS
	  IFIW NMXWCN		;COUNTER
	  IFIW NMXWCN		;BIT MAPPED COUNTERS
	SUBTTL User strings -- Write coded data
;NMXWCD - Write coded info to user data string
;Call
;	NT/ Pointer to format block
;Return
;	RET			;Error, code is in NXERR
;	RETSKP			;data type byte and data are in user string
;

NMXWCD:
	SAVEAC <P1,P2>		;GET SOME WORK AREA
	LOAD T1,NTLEN,(NT)	;GET SIZE OF FIELD
	CAIE T1,1		;WE ONLY HAVE SINGLE BYTE CODEDS. (**HACK**)
	 BUG.(CHK,NTMBCF,NTMAN,SOFT,<Bad coded field on output>,,<

Cause:	We are formatting output for a SHOW, and we have been requested
	to generate a CODED field of more than one byte. We currently
	don't know how to do this.

Action:	Look at the descriptor block pointed to by NT. Check to see if
	this item is supposed to be a multiple byte coded. If not, fix
	the item's entry. If it is correct, you are going to have to write
	the code to handle multiple byte codeds.
>,NTEMPE)
	TXO T1,1_7		;INDICATE CODED NON MULTIPLE (PP 148 OF NM)
	ECALL PUTBYT		;DEPOSIT DATA TYPE BYTE IN USER STRING
	LOAD T1,NXVAL,+NMXVAR	;GET THE CODED VALUE TO OUTPUT
	CALLRET PUTBYT		;PUT THE BYTE IN THE OUTPUT STRING, AND RETURN
	SUBTTL User strings -- Write ascii image data
;NMXWAI - Write ASCII image data to user data string
;Call
;	NT/ Pointer to format block
;Return
;	RET			;Error, code is in NXERR
;	RETSKP			;data type byte and data are in user string

NMXWAI:
	SAVEAC <P1,P2>		;GET SOME WORK AREA
	MOVX T1,<1_6>		;NON-CODED, ASCII IMAGE DATA
	ECALL PUTBYT		;STORE DATA TYPE BYTE
	MOVE P1,[POINT 8,NX.VAL+NMXVAR] ;BYTE POINTER TO STRINGID WITH VALUE
	ILDB T1,P1		;GET FIRST BYTE, WHICH IS SIZE
	MOVE P2,T1		;COPY SIZE, TO COUNT DOWN BYTES
NMXWA2:	ECALL PUTBYT		;PUT IT IN USER DATA STRING
	ILDB T1,P1		;GET NEXT BYTE
	SOJGE P2,NMXWA2		;DECREMENT COUNT, IF ANY BYTES LEFT, DO THEM
	RETSKP			;DO A GOOD RETURN
	SUBTTL User strings -- Write numeric data
;NMXWNU - Write a numeric value to the user data string
;CALL
;	NMXVAR/ NX block
;	NT/ Pointer to STENT part of NT block
;	NXVAL,+NMXVAR/ Integer to deposit
;RETURN
;	RET			;On error, NXERR contains code
;	RETSKP			;Integer has been placed in data string
;

NMXWNU:	LOAD T2,NTLEN,(NT)	;GET LENGTH IN BYTES OF THIS NUMBER
	LOAD T1,NTTYP,(NT)	;GET FORMAT OF THIS NUMBER
	CAXL T1,NT.FDU		;MAKE SURE THIS IS IN NUMERIC RANGE
	CAXLE T1,NT.FOC		;BETWEEN DECIMAL UNSIGNED AND OCTAL.
	BUG.(CHK,NTMINT,NTMAN,SOFT,<Invalid numeric type>,,<

Cause:	We are generating output for a numeric field, and we have been
	asked to generate something other than Decimal, Hexadecimal or Octal.
>,NTEMPE)
	MOVE T1,<-NT.FDU>+[	;GET NICE TYPE.
		0_3		;DECIMAL UNSIGNED IS FORMAT 0
		1_3		;DECIMAL SIGNED IS FORMAT 1
		2_3		;HEXADECIMAL NUMBER IS FORMAT 2
		-1		;HEX IMAGE DOESN'T COME HERE.
		3_3](T1)	;OCTAL NUMBER IS FORMAT 3
	IOR T1,T2		;OR IN SIZE OF FIELD
	ECALL PUTBYT		;PUT THIS BYTE IN USER DATA AS DATA TYPE
NMXWCN:	LOAD T2,NTLEN,(NT)	;GET NUMBER OF BYTES FOR COUNTER AGAIN
	LOAD T1,NXVAL,+NMXVAR	;GET VALUE TO RETURN
	CAXL T2,1		;MUST BE AT LEAST ONE BYTE
	CAXLE T2,4		;MAY BE AT MOST 4 BYTES
NMXWCE:	BUG.(CHK,NTMBDL,NTMAN,SOFT,<Bad multiple byte length>,,<

Cause:	We are generating output for a numeric field, and we have been
	asked to generate an illegal number of bytes.
>,NTEMPE)
	CALLRET @.(T2)
	  IFIW PUTBYT		;PUT A SINGLE BYTE
	  IFIW PUT2BT		;PUT A DUO BYTE
	  IFIW NMXWCE		;DO THREE BYTES. ILLEGAL
	  IFIW PUT4BT		;4 BYTES.

	SUBTTL User strings -- Read a number from user
;NMXRNU - Read an integer from data string, and put into NXVAL
;

NMXRNU:
	LOAD T1,NTLEN,(NT)	;GET SIZE OF FIELD
	ECALL NMXRBY		;READ BYTES
	JUMPE T1,NTEIPV		;ILLEGAL TO SET QUANTITY TO ZERO
	STOR T1,NXVAL,+NMXVAR	;SAVE VALUE IN NX BLOCK
	RETSKP			;RETURN SUCCESS

NMXRNC:	LOAD T1,NTLEN,(NT)	;GET SIZE OF CODED FIELD
	ECALL NMXRBY		;READ BYTES
	STOR T1,NXVAL,+NMXVAR	;SAVE VALUE IN NX BLOCK
	RETSKP


NMXRNS:
	LOAD T1,NTLEN,(NT)	;GET SIZE OF FIELD
	ECALL NMXRBY		;READ THE BYTES
	JUMPE T1,NTEIPV		;ZERO IS AN ILLEGAL NUMBER
	LOAD T2,NTLEN,(NT)	;GET SIZE AGAIN
	IMULI T2,^D8		;CONVERT TO NUMBER OF BITS
	SETO T3,		;POSSIBLE SIGN EXTENSION
	ASH T3,(T2)		;SHIFT TO BECOME ONLY THE SIGN BITS
	TDNE T3,T1		;IS THE SIGN BIT ON?
	 IOR T1,T3		;YES, TURN ON ALL THE SIGN BITS
	STOR T1,NXVAL,+NMXVAR	;SAVE IN NX BLOCK
	RETSKP

NMXRBY:	CAXL T1,1		;RANGE CHECK NUMBER OF BYTES TO READ
	CAXLE T1,4		;TO ENSURE ONLY 1,2, AND 4
NMXRBE:	BUG.(CHK,NTMILN,NTMAN,SOFT,<Illegal number size>,,<

Cause:	We are going to read a numeric value from the user's string, and
	the format descriptor block for this item has specified an illegal
	number of bytes to read.
>,NTEMPE)
	CALLRET @.(T1)		;DISPATCH
	IFIW GETBYT		;GET A SINGLE BYTE
	IFIW GET2BT		;GET 2 BYTES OF INTEGER
	IFIW NMXRBE
	IFIW GET4BT		;GET 4 BYTES
	SUBTTL User strings -- Read and write milliseconds
;NMXWNM - Write milliseconds
;Call
;	NMXVAR/ NX block
;	NT/ Pointer to NT begstr
;Return
;	see NMXWNU

NMXWNM:	LOAD T1,NXVAL,+NMXVAR	;GET VALUE WE ARE GOING TO WRITE OUT
	IDIVI T1,TIMBAS		;CONVERT TO SECONDS
	STOR T1,NXVAL,+NMXVAR	;PUT BACK WHERE IT CAME FROM
	LOAD T1,NTLEN,(NT)	;GET THE LENGTH WE ARE GOING TO STORE
;	IOR T1,0_3		;NICE CODE INDICATING DECIMAL UNSIGNED
	ECALL PUTBYT		;PUT THE NICE HEADER IN
	JRST NMXWCN		;AND JOIN COMMON CODE

;NMXRNM - Read seconds, store milliseconds
;Call
;	NMXVAR/ NX block
;	NT/ Pointer to NT begstr

NMXRNM:	ECALL NMXRNU		;READ THE NUMBER AS DECIMAL UNSIGNED
	MOVX T1,TIMBAS		;CONVERSION FACTOR
	OPSTRM <IMULB T1,>,NXVAL,+NMXVAR ;CONVERT TO MILLISECONDS
	RETSKP			;AND RETURN SUCCESSFULLY



	SUBTTL User strings -- Copy STRINGID from user to exec

;GETSTR - Copy a number of bytes (String) to a place in monitor core.
;Call
;	NMXVAR/ NX block
;Return
;	Non-skip on address check, error already in NXERR
;	Skip if successfull, string starting at NXVAL

GETSTR:	XMOVEI T1,NX.DAT+NMXVAR	;GET POINTER TO DATA BP BLOCK
	JRST GETST0		;JUMP INTO MAIN CODE
GETSTI:	XMOVEI T1,NX.EID+NMXVAR	;GET POINTER TO ENITITY ID BP BLOCK
GETST0:	SAVEAC <P1,P2,NT>	;SAVE SOME DATA ACS
	MOVE P2,T1		;SAVE POINTER
	MOVE P1,[POINT 8,NX.VAL+NMXVAR] ;PUT STRING IN VALUE PART OF NX
	MOVE T2,P2		;GET POINTER TO BP BLOCK
	ECALL DNGUBT		;GET A SINGLE BYTE
	IDPB T1,P1		;PUT BYTE AWAY IN DESTINATION STRING
	CAXLE T1,^D32		;WILL THIS STRING FIT IN NXVAL?
	ERRRET NTEPVL		;NOPE. PARAMETER TOO LONG
	MOVE NT,T1		;SAVE NUMBER OF BYTES TO DO
GETST1:	SOJL NT,RSKP		;AT END, RETURN SUCCESS
	MOVE T2,P2		;GET POINTER TO BP BLOCK
	ECALL DNGUBT		;GET A BYTE
	IDPB T1,P1		;PUT BYTE AWAY.
	JRST GETST1		;DO ANOTHER BYTE
	SUBTTL User strings -- Copy STRINGID from exec to user
;PUTSTR - Copy string from exec space to user data string
;Call
;	P1/ Full word pointer to stringid in exec space
;Return
;	RET on address check
;	RETSKP with string in user address space

PUTSTR:	SAVEAC <NT,P2>		;SAVE AN AC FOR BYTE COUNT
	MOVX P2,<POINT 8,(P1)>	;MAKE AN 8-BIT BYTEPOINTER TO STRING
	ILDB T1,P2		;GET BYTE COUNT (FIRST BYTE)
	MOVE NT,T1		;SAVE BYTE COUNT FOR LATER
	ECALL PUTBYT		;PUT BYTE IN USER'S OUTPUT STRING
PUTST1:	SOJL NT,RSKP		;RETURN WHEN DONE
	ILDB T1,P2		;GET ANOTHER BYTE
	ECALL PUTBYT		;PUT IN USER DATA STRING
	JRST PUTST1		;DO ANOTHER BYTE
	SUBTTL User strings -- Get and put user byte routines.
;CALL
;	T1/ integer to deposit
;RETURN
;	RET on error, code in NXERR
;	RETSKP with number deposited/loaded from/to T1

PUTBYT::XMOVEI T2,NX.DAT+NMXVAR	;POINTER TO BYTE POINTER/COUNT STRUCTURE
	JRST DNPUBT		;PUT THE BYTE IN THE STREAM.

PUT4BT::SAVEAC <P1,P2>		;P1 IS OUR DATA, P2 IS THE NUMBER OF BYTES
	XMOVEI T2,NX.DAT+NMXVAR	;POINTER TO BYTE POINTER/COUNT STRUCTURE.
	MOVX P2,4		;DO 4 BYTES
	JRST PUTMBT		;PUT MULTIPLE BYTES
PUT2BT::SAVEAC <P1,P2>		;P1 IS DATA, P2 IS COUNT OF BYTES
	XMOVEI T2,NX.DAT+NMXVAR	;POINTER TO BYTE POINTER/COUNT STRUCTURE.
	MOVX P2,2		;WE ARE DOING 2 BYTES
;;	JRST PUTMBT		;PUT MULTIPLE BYTES
PUTMBT:
	MOVE P1,T1		;SAVE ORIGINAL BYTES
PUTMB1:	LDB T1,[POINT 8,P1,35]	;GET BOTTOM BYTE
	ECALL DNPUBT		;STORE IT IN USER'S DATA STRING
	SOJLE P2,RSKP		;IF DONE, RETURN SUCCESS.
	ASH P1,-10		;DROP (INTO BIT BUCKET) THE BYTE WE JUST PUT
	JRST PUTMB1		;AND PUT ANOTHER BYTE IN USER'S STRING

GETEBY::
	XMOVEI T2,NX.EID+NMXVAR	;POINTER TO BP FOR ENTITY ID
	CALLRET DNGUBT		;AND GET A BYTE FROM IT.
GETBYT::
	XMOVEI T2,NX.DAT+NMXVAR	;POINTER TO BYTE POINTER/COUNT STRUCTURE
	CALLRET DNGUBT		;AND GO GET THE BYTE
GET2BT::
	SAVEAC P1		;WE ARE GOING TO ACCUMULATE BYTES HERE
	XMOVEI T2,NX.DAT+NMXVAR	;POINTER TO BYTE POINTER/COUNT STRUCTURE.
	ECALL DNGUBT		;GET A BYTE OUT OF STREAM
	MOVE P1,T1		;SAVE WHILE WE GET HIGH ORDER BYTE
	ECALL DNGUBT		;GET SECOND BYTE
	ASH T1,8		;SINCE THIS IS HIGH ORDER, MAKE ROOM FOR LOW
	IOR T1,P1		;OR IT IN, MAKING A 2-BYTE AC
	RETSKP			;RETURN WITH 2 BYTES IN T1
GET4BT::
	SAVEAC P1		;THIS IS WHERE WE ACCUMULATE INCOMING BYTES
	XMOVEI T2,NX.DAT+NMXVAR	;POINTER TO BYTE POINTER/COUNT STRUCTURE.
	ECALL DNGUBT		;GET A BYTE OUT OF USER STREAM
	MOVE P1,T1		;COPY BYTE INTO SAFE AC
	ROT P1,-10		;NEXT BYTE IS HIGHER ORDER THAN THIS
	ECALL DNGUBT		;GET BYTE NUMBER 2
	IOR P1,T1		;ACCUMULATE THIS BYTE IN
	ROT P1,-10		;LET NEXT BYTE COME IN ABOVE THIS ONE
	ECALL DNGUBT		;GET BYTE NUMBER 3
	IOR P1,T1		;ACCUMULATE IT IN
	ROT P1,-10		;NEXT BYTE IS THE HIGHEST ORDER BYTE
	ECALL DNGUBT		;GET THE LAST (4TH) BYTE
	IOR T1,P1		;INCLUDE STUFF WE HAVE BEEN ACCUMULATING
	ROT T1,30		;ROTATE SO WE HAVE A REAL NUMBER
	RETSKP			;RETURN WITH THE ENTIRE NUMBER IN T1
	SUBTTL User strings -- Get and put single bytes into data strings.
;Call
;	T1/ Byte to be put, or byte returned.
;	T2/ Pointer to BP block
;Return
;	RET	on error, error code in NXERR
;	RETSKP	T1 deposited/loaded
;
;Note - These assume the caller has verified the byte pointer by calling
;CHKIND, to avoid the possibility of an indirect loop, and to insure that
;the destination byte stream is in core.
;For reasons of efficiency, T2 is guaranteed to be preserved.

DNPUBT::
	OPSTRM <SOS T3,>,BPBYT,(T2) ;DECREMENT COUNT OF AVAILABLE BYTES
	JUMPL T3,NTERES		;PARAMETERS TOO LONG
	XCTBU [IDPB T1,(T2)]	;DEPOSIT THE BYTE
	RETSKP

DNGUBT::
	OPSTRM <SOS T3,>,BPBYT,(T2) ;DECREMENT COUNT OF BYTES PERMITTED
	JUMPL T3,NTEPAM		;PARAMETER MISSING
	XCTBU [ILDB T1,(T2)]	;DO THE ILDB
	RETSKP			;GOT THE BYTE IN T1 - RETURN SUCCESS
	SUBTTL Miscellaneous -- Error returns
;;Error returns. Put error code in AC and .NTERR in user's block,
;and return non-skip.

DEFINE NMXERR(CODE),<
	MOVX T1,^D'CODE		;ERROR CODE
	JRST NTEERR		;AND DO ERROR
>

NTEUFO:	NMXERR(-1)		;UNRECOGNIZED FUNCTION OR OPTION
NTEIMF:	NMXERR(-2)		;INVALID MESSAGE FORMAT
NTEPRV:	NMXERR(-3)		;PRIVILEGE VIOLATION.
NTEMPE:	NMXERR(-5)		;MANAGEMENT PROGRAM ERROR
NTEUPT:	NMXERR(-6)		;UNRECOGNIZED PARAMETER TYPE
NTEURC:	NMXERR(-8)		;UNRECOGNIZED COMPONENT
NTEINI:	NMXERR(-9)		;INVALID IDENTIFICATION
;	NELCE%==-10		;LINE COMMUNICATION ERROR
;	NECWS%==-11		;COMPONENT IN WRONG STATE
NTERES:	NMXERR(-15)		;RESOURCE ERROR
NTEIPV:	NMXERR(-16)		;INVALID PARAMETER VALUE
NTENRM:	NMXERR(-20)		;NO ROOM (OR SLOT ALREADY TAKEN)
NTEPNA:	NMXERR(-22)		;PARAMETER NOT APPLICABLE
NTEPVL:	NMXERR(-23)		;PARAMETER VALUE TOO LONG
NTEOPF:	NMXERR(-25)		;OPERATION FAILURE
NTEFNS:	NMXERR(-26)		;FUNCTION NOT SUPPORTED
NTEIPG:	NMXERR(-27)		;INVALID PARAMETER GROUPING
NTEPAM:	NMXERR(-29)		;PARAMETER MISSING
NTEADC:	NMXERR(-47)		;ADDRESS CHECK

NTEERR::JN NXERR,+NMXVAR,RTN	;IF AN ERROR IS ALREADY THERE, LEAVE IT
				;  ALONE. IT IS MORE INTERESTING THAN
				;  ANY FOLLOW-UP ERRORS.
	TRACE NMX,<Failure in an NTMAN. uuo>
	STOR T1,NXERR,+NMXVAR	;SAVE IN OUR COPIED BLOCK
	RET			;NON SKIP RETURN. WILL POP ALL THE WAY BACK
				;  TO THE TOP, AND RETURN AS AN ERROR.

	SUBTTL Miscellaneous -- Name/number conversion.
;NMXA2N - Address to name conversion
;Call
;	T1/ Node address
;Return
;	RET			;No such node, illegal, ect.
;	RETSKP, name in NXVAL	;on success

NMXA2N:	CALL SCTA2N		;CONVERT NODE ADDRESS TO NODE NAME
	 JRST [SETZRO NXVAL,+NMXVAR;SET BYTE COUNT AND NODE NAME TO 0
		RET]		;AND RETURN AN ERROR
NMXA21:	SETZ T2,		;START OFF WITH ZERO BYTES RETURNED
	MOVE T3,[POINT 6,T1]	;POINTER TO THE NODE NAME RETURNED
	MOVEI T4,6		;MAXIMUM NUMBER OF CHARACTERS TO CHECK
	SOJGE T4,[ILDB T5,T3	;GET A BYTE FROM THE NAME
		JUMPE T5,.+1	;IF ZERO BYTE, END OF NAME
		AOJA T2,.]	;ELSE KEEP COUNTING.
	MOVE T4,[POINT 6,T1]	;BYTE POINTER TO THE NODE NAME
	MOVE T3,[POINT 8,NX.VAL+NMXVAR] ;BYTE POINTER TO WHERE WE WANT NAME
	IDPB T2,T3		;START OFF STRINGID WITH NUMBER OF CHARACTERS
NMXA22:	ILDB T5,T4		;GET A BYTE FROM THE NAME
	ADDI T5,^O40		;MAKE IT ASCII
	IDPB T5,T3		;STORE IT IN NMXVAR IN STRINGID FORMAT
	SOJG T2,NMXA22		;AND CONTINUE COPYING UNTIL DONE.
	RETSKP			;RETURN SUCCESS


;NMXN2A - Name to address conversion
;Call
;	NXVAL+NMXVAR/ Stringid for node name. Max 6 chars.
;Return
;	RET			;Unknown name. NTEURC.
;	RETSKP			;T1 contains node address.

NMXN2A:	SETZ T1,		;START OFF WITH A CLEAN NODE NAME
	MOVE T6,[POINT 8,NX.VAL+NMXVAR] ;BYTE POINTER TO STRINGID WITH NAME
	MOVE T5,[POINT 6,T1]	;BYTE POINTER TO CREATE SIXBIT NAME
	ILDB T4,T6		;GET COUNT OF BYTES
	JUMPE T4,RTN		;IF NOTHING, ERROR
NMXN2B:	ILDB T3,T6		;GET A BYTE FROM THE NODE NAME
	CAIL T3,^O140		;IS IT LOWER CASE
	SUBI T3,^O40		;MAKE IT UPPER CASE
	SUBI T3,^O40		;MAKE IT SIXBIT
	IDPB T3,T5		;STORE IT IN THE NODE NAME
	SOJG T4,NMXN2B		;AND LOOP UNTIL BYTES EXHAUSTED.

	CALL SCTN2A		;CONVERT NODE NAME TO NODE ADDRESS
	 RET			;SESSION CONTROL CAN'T FIND THE NAME. ERROR.
	RETSKP			;SUCCESS. T1 CONTAINS NODE ADDRESS.

	SUBTTL Data base -- Find an NSP node block
;FNDNOD - Find an NMX Node Block, if fail, make a new one
;
;Call:	T1/ Network Node Address of node
;	CALL	FNDNOD
;	  Error Return if no resources
;	Normal Return with pointer to node block in T1
;Changes T1,T2,T3,T4

;Note that the new node block goes on the end of the queue of node
;blocks.  This causes the blocks which we hear about soonest to be at
;the beginning of the queue.  These are the nodes we are most likely
;to converse with, so having them at the beginning of the queue is a
;convenience for DDT if nothing else.

FNDNOD::SAVEAC P1
	MOVE P1,T1		;SAVE THE ARG
	CALL SRHNOD		;FIRST, SEARCH FOR AN EXISTING ONE
	  JRST MAKND1		;CAN'T FIND IT, TRY TO MAKE ONE
	RETSKP			;FOUND IT, SUCCESS RETURN

MAKND1:	MOVEI T1,NN.LEN		;LENGTH OF A NMX NODE BLOCK
	CALL DNGWDZ		;ZERO SO MANY ZEROED WORDS
	  RET			;CAN'T, ERROR RETURN
	STOR P1,NNNOD,(T1)	;STORE NODE ID IN NEW NODE BLOCK
	MOVE P1,T1		;SAVE ADDRESS OF NODE BLOCK
	CALL DNGTIM		;GET A TIMESTAMP
	STOR T1,NNSLZ,(P1)	;STORE AS LAST TIME BLOCK WAS ZEROED

	ENDQUE P1,NMXNDQ,NN.NXT,T2

;Some initialization for NSP

	MOVEI T2,TIMBAS		;MACRO/LINK CAN'T MULTIPLY EXTERNAL RIGHT
	IMULI T2,5		;ESTIMATE 5 SECOND FOR INITIAL DELAY
	STOR T2,NNDLY,(P1)	;ZERO IS NOT GOOD FOR CONNECT CONFIRM!
				;SEE UPDELAY ABOUT THIS
	MOVE T1,P1		;RETURN PTR TO BLOCK IN T1
	RETSKP
	SUBTTL Data base -- Find an existing NSP node block
;SRHNOD - Search for an existing NMX Node Block
;
;Call:	T1/ Network Node Id
;	CALL	SRHNOD
;	  Error Return if not found
;	Normal Return with pointer to it in T1
;Changes T1,T2,T3
;This must save T5 and T6 if it evers changes them, since SCMUUO calls it.

SRHNOD::MOVE T2,T1		;COPY NODE ID TO T2
	LOAD T1,QHBEG,+NMXNDQ	;GET HEAD OF NMX NODES LIST
FNDND1:	JUMPE T1,RTN		;LIST IS EMPTY, ERROR RETURN
	OPSTR <CAMN T2,>,NNNOD,(T1) ;IS THIS THE NODE WE'RE LOOKING FOR?
	RETSKP			;YES, SUCCESS RET WITH PTR IN T1
	LOAD T1,QPNXT,+NN.NXT(T1) ;NO, GET THE NEXT ENTRY IN LIST
	JRST FNDND1		;AND TRY IT

	SUBTTL Data Base -- NMXNMI - Get node software ID.
;Copy system name
;Call
;	T1/ Local byte pointer to destination of string
;Return
;	RET			;hopefully never.
;	RETSKP			;Always

NMXNMI::
	SAVEAC <P1,P2>		;SAVE AN AC FOR BYTE COUNT
	JN NXWRM,+NMXVAR,NMXNI3	;IF SETTING, USE ALTERNATE CODE
	MOVE T1,[POINT 8,NX.VAL+NMXVAR] ;BYTE POINTER TO RECEIVE STRING
	MOVSI T2,(POINT 7,(P2))	;BYTE POINTER TO STRING
	SKIPN P2,NMXIDN		;DO WE HAVE A LOCALLY SET ID?
IFN FTOPS10,XMOVEI P2,CONFIG##	;NO, DEFAULT TO MONITOR NAME
IFN FTOPS20,XMOVEI P2,VTSVN##	;NO, DEFAULT TO SYSTEM NAME
	SETZ P1,		;ASSUME A ZERO LENGTH STRING
	IDPB P1,T1		;STORE LENGTH (TEMP, WILL BE REPLACED)
	MOVE T4,T1		;COPY BYTE POINTER TO LENGTH
NMXNI0:	CAIL P1,^D32		;IF WE ARE ABOUT TO RUN OVER
	 JRST NMXNI1		;FINISH THE STRING
	ILDB T3,T2		;GET NEXT BYTE FROM CONFIG
	JUMPE T3,NMXNI1		;IF END OF ASCIZ STRING, END
	IDPB T3,T1		;SAVE BYTE IN DESTINATION STRING
	AOJA P1,NMXNI0		;GO GET ANOTHER BYTE
NMXNI1:	DPB P1,T4		;STORE SIZE IN BEGINNING OF BYTE STRING
	RETSKP			;RETURN SUCCESS

NMXNI3:	JN NXZMC,+NMXVAR,NMXNI7	;IF CLEARING, RETURN BLOCK OF CORE
	SKIPE P2,NMXIDN		;GET POINTER TO CURRENT STRING, IF ANY
	JRST NMXNI4		;HAVE CURRENT STRING, DON'T GET ANOTHER BLOCK
	MOVEI T1,<^D32/5>+1	;GET ENOUGH SPACE TO STORE 32 CHARACTERS
	CALL DNGWDS		;GET THE SPACE
	 ERRRET NTERES		;NOT ENOUGH RESOURCES
	MOVE P2,T1		;SAVE POINTER
	MOVEM P2,NMXIDN		;AND SAVE FOR LATER
NMXNI4:	MOVE T3,[POINT 8,NX.VAL+NMXVAR] ;POINTER TO SOURCE STRING
	MOVSI T2,(POINT 7,(P2))	;DESTINATION BYTE POINTER
	ILDB P1,T3		;SAVE BYTE COUNT TO DECREMENT ON.
	CAXL P1,^D32		;WILL IT FIT IN DESTINATION BLOCK?
	 BUG.(CHK,NTMBSS,NTMAN,SOFT,<Bad string size in NMXNI4>,,<

Cause:	We are going to copy an identification string from NMXVAR into
	a freecore block, and the string claims to be longer than will
	fit in either block.

Cure:	Find out how this byte (length) got trashed.
>,NTEMPE)
NMXNI5:	ILDB T1,T3		;GET A BYTE FROM SOURCE
	IDPB T1,T2		;STORE IN DESTINATION STRING
	SOJG P1,NMXNI5		;AND LOOP
	IDPB P1,T2		;TERMINATE STRING WITH A ZERO BYTE
	RETSKP

NMXNI7:	SKIPE T1,NMXIDN		;GET POINTER TO ID STRING
	CALL DNFWDS		;FREE THE CORE
	SETZM NMXIDN		;CLEAR THE POINTER TO OBSOLETE CORE
	RETSKP			;AND RETURN SUCCESS


IFN FTOPS20,<
;GETWRD & GETWR1 - Get a word from user space
;Call
;	T6/ address desired
;Return
;	+2 always

GETWR1:	AOJ T6,			;POINT TO NEXT WORD
GETWRD:	UMOVE T1,(T6)		;GET WORD
	RETSKP			;AND RETURN

> ;END IFN FTOPS20


	LIT
IFN FTOPS10, .XCMSY
IFN FTOPS20, TNXEND
	END