Google
 

Trailing-Edge - PDP-10 Archives - bb-x130a-sb - swinet.mac
There are 4 other files named swinet.mac in the archive. Click here to see a list.
	TITLE	.NET	SWIL network operations
	SUBTTL	Robert Houk/RDH

	SEARCH	SWIDEF,	SWIL		;SWIL PACKAGE DEFINITIONS
	SEARCH	JOBDAT,	MACTEN,	UUOSYM	;STANDARD DEFINITIONS

	SALL				;PRETTY LISTINGS
	.DIREC	FLBLST			;PRETTIER LISTINGS

	TWOSEG	400000

Copyright (C) Digital Equipment Corporation 1984.

	COMMENT	\

Copyright (C) 1984
Digital Equipment Corporation, Maynard, Massachusetts, U.S.A.

This software is furnished under a license and may be used and copied only
in accordance with the terms of such license and with the inclusion of the
above copyright notice.  This software or any other copies thereof may not
be provided or otherwise made available to any other person.   No title to
and ownership of the software is hereby transferred.

The information in this software is subject to change  without  notice and
should not be construed as a commitment by Digital Equipment Corporation.

Digital  assumes  no  responsibility  for  the  use  or reliability of its
software on equipment which is not supplied by Digital.

\


;SWINET VERSION IDENTIFICATION

MAJVER==1	;MAJOR VERSION LEVEL
MINVER==0	;MINOR (MAINTENANCE RELEASE) LEVEL
CSTVER==0	;CUSTOMER VERSION (WHO LAST . . .)
EDTVER==0	;EDIT LEVEL

%%SNET==:<BYTE (3)CSTVER(9)MAJVER(6)MINVER(18)EDTVER>

IF2,<	PURGE	CSTVER,MAJVER,MINVER,EDTVER>
	SUBTTL	Revision History

;INITIAL CREATION 21-MAR-80
	SUBTTL	DAP Message Service Routines

;RDSTS  --  READ AND TRY TO MAKE SENSE OF RECEIVED DAP STATUS
;CALL IS:
;
;	PUSHJ	P,RDSTS
;	 error return
;	normal return
;
;RDSTS will read in the status message from the network stream via
;RDDAP, so call RDSTS upon receipt of the $DHSTS code.
;
;The error return is taken if the network dies or the status message
;makes no sense (uses a reserved code, etc.)
;
;On normal return M0 will contain the translated 18-bit status code.
;
;Uses T1 - T4.

	ENTRY	.RDSTS
	INTERN	RDSTS0,	RDSTS1

.RDSTS:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
RDSTS0:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
RDSTS1:	SKIPLE	T2,.IODIM(IO)	;GET INPUT MESSAGE TYPE FROM RDMSG
	CAIE	T2,$DHSTS	;IT HAD BETTER BE STATUS!
	STOPCD	<RDSTS called without a status message>
	SETZB	T3,T4		;INITIALIZE SOME 0 VALUES
	MOVDM	T3,STC		;CLEAR OUT STATUS CODE FIELD
	MOVDM	T3,SRA		;CLEAR OUT RECORD ADDRESS FIELD
	MOVDM	T3,SRN		;CLEAR OUT RECORD NUMBER FIELD
	MOVDM	T3,STV		;CLEAR OUT SECONDARY STATUS FIELD

;READ IN THE STATUS MESSAGE

	PUSHJ	P,RDDAP1	;SLURP UP THE STATUS MESSAGE
	 POPJ	P,		;SIGH
	PJRST	RDSTC1		;AND CONVERT IT TO ERROR/EXCEPTION CODE
;RDSTC  --  TRANSLATE DAP STATUS CODE INTO INTERNAL ERROR/EXCEPTION CODE
;CALL IS:
;
;	PUSHJ	P,RDSTC
;	 error return
;	normal return
;
;RDSTC takes the DAP error status from the I/O CDB (as read in by RDSTS)
;and translates it into NIP/NFT internal error/exception code. The new
;code is always returned in register M0.
;
;The error return is taken if the DAP status code is illegal or otherwise
;unintelligible.
;
;Uses T1 - T4.

	ENTRY	.RDSTC
	INTERN	RDSTC0,	RDSTC1

.RDSTC:	PUSHJ	P,.SACIO##	;CONVERT TO I/O CONTEXT
RDSTC0:				;WE DON'T STOMP ON THE P'S HERE
RDSTC1:	LDB	T1,PDPEMA	;DAP "MACCODE" FIELD
	LDB	T2,PDPEMI	;DAP "MICCODE" FIELD
	LDB	T3,PDPEMT	;MESSAGE TYPE WITHIN MICCODE
	LDB	T4,PDPEMF	;MESSAGE FIELD WITHIN MESSAGE TYPE
	PJRST	@RDSTCX(T1)	;DISPATCH ON STATUS CLASS


;STATUS CODE FIELD POINTERS

PDPEMA::POINT	04,.IDSTC(IO),23;DAP "MACCODE" FIELD
PDPEMI::POINT	12,.IDSTC(IO),35;DAP "MICCODE" FIELD
PDPEMT::POINT	06,.IDSTC(IO),29;MESSAGE TYPE WITHIN MICCODE
PDPEMF::POINT	06,.IDSTC(IO),35;MESSAGE FIELD WITHIN MESSAGE TYPE


;STATUS MACRO-CODE DISPATCH

RDSTCX:	IFIW	RD00S		;OPERATION IN PROGRESS
	IFIW	RD01S		;OPERATION SUCCESSFUL
	IFIW	RD02S		;UNSUPPORTED FUNCTION
	IFIW	RD03S		;RESERVED
	IFIW	RD04S		;FILE ACCESS
	IFIW	RD05S		;I/O TRANSMISSION ERROR
	IFIW	RD06S		;I/O OPERATION WARNING
	IFIW	RD07S		;ERROR CLOSING FILE
	IFIW	RD10S		;DAP MESSAGE SYNTAX ERROR
	IFIW	RD11S		;DAP MESSAGE FIELD ERROR
	IFIW	RD12S		;DAP MESSAGE OUT OF SYNC
	IFIW	RD13S		;RESERVED
	IFIW	RD14S		;RESERVED
	IFIW	RD15S		;RESERVED
	IFIW	RD16S		;CUSTOMER-DEFINED
	IFIW	RD17S		;CUSTOMER-DEFINED
;00 - OPERATION PENDING

RD00S:	MOVEI	M0,$EGOIP	;"OPERATION IN PROGRESS" (AS A WILD GUESS)
	JRST	.POPJ1##	;RETURN STATUS



;01 - OPERATION SUCCESSFUL

RD01S:	MOVEI	M0,$EGAOK	;"A-OK" (AS A WILD GUESS)
	JRST	.POPJ1##	;RETURN STATUS



;02 - UNSUPPORTED DAP FUNCTION

RD02S:	MOVEI	M0,$EERDE	;REMOTE DAP ERROR
	JRST	.POPJ1##	;RETURN STATUS



;03 - XXX - RESERVED

RD03S:	MOVEI	M0,$EEUDS	;UNKNOWN DAP STATUS
	POPJ	P,		;RETURN ERROR



;04 - FILE ACCESS ERROR

RD04S:	MOVEI	T4,DS2EF	;CONVERSION TABLE
	PUSHJ	P,.CFIND##	;TRY TO CONVERT TO FILE ACCESS ERROR
	 MOVEI	T1,$EFDAP	;BIZARRE DAP STATUS ERROR
	MOVE	M0,T1		;RETURN STATUS IN M0
	JRST	.POPJ1##	;RETURN STATUS



;05 - I/O DATA TRANSMISSION ERROR

RD05S:	MOVEI	T4,DS2EI	;CONVERSION TABLE
	PUSHJ	P,.CFIND##	;TRY TO CONVERT TO I/O ERROR
	 JRST	RD05S2		;NOT I/O CODE - MAYBE FILE CODE?
	MOVE	M0,T1		;POSITION IN M0
	JRST	.POPJ1##	;AND RETURN STATUS

RD05S2:	MOVEI	T4,DS2EF	;FILE-LEVEL CONVERSION TABLE
	PUSHJ	P,.CFIND##	;TRY TO CONVERT TO FILE ERROR
	 MOVEI	T1,$EIDAP	;BIZARRE DAP I/O STATUS ERROR
	MOVE	M0,T1		;POSITION IN M0
	JRST	.POPJ1##	;AND RETURN STATUS



;06 - I/O DATA TRANSMISSION WARNING

RD06S:	MOVEI	T4,DS2EI	;CONVERSION TABLE
	PUSHJ	P,.CFIND##	;TRY TO CONVERT TO I/O ERROR
	 JRST	RD06S2		;TRY FOR FILE ERROR
	MOVE	M0,T1		;POSITION IN M0
	JRST	.POPJ1##	;AND RETURN STATUS

RD06S2:	MOVEI	T4,DS2EF	;FILE-LEVEL CONVERSION TABLE
	PUSHJ	P,.CFIND##	;TRY TO CONVERT TO FILE ERROR
	 MOVEI	T1,$EIDAP	;BIZARRE DAP I/O STATUS ERROR
	MOVE	M0,T1		;POSITION IN M0
	JRST	.POPJ1##	;AND RETURN STATUS



;07 - FILE/I/O CLOSE ERROR

RD07S:	MOVEI	T4,DS2EI	;CONVERSION TABLE
	PUSHJ	P,.CFIND##	;TRY TO CONVERT TO I/O ERROR
	 JRST	RD07S2		;TRY FOR FILE ERROR
	MOVE	M0,T1		;POSITION IN M0
	JRST	.POPJ1##	;AND RETURN STATUS

RD07S2:	MOVEI	T4,DS2EF	;FILE-LEVEL CONVERSION TABLE
	PUSHJ	P,.CFIND##	;TRY TO CONVERT TO FILE ERROR
	 MOVEI	T1,$EFDAP	;BIZARRE DAP FILE STATUS ERROR
	MOVE	M0,T1		;POSITION IN M0
	JRST	.POPJ1##	;AND RETURN STATUS



;10 - DAP SYNTAX ERROR

RD10S:	MOVEI	M0,$EERDE	;REMOTE DAP ERROR
	JRST	.POPJ1##	;RETURN STATUS



;11 - DAP FIELD ERROR

RD11S:	MOVEI	M0,$EERDE	;REMOTE DAP ERROR
	JRST	.POPJ1##	;RETURN STATUS



;12 - DAP MESSAGE OUT OF SYNC

RD12S:	MOVEI	M0,$EERDE	;REMOTE DAP ERROR
	JRST	.POPJ1##	;RETURN STATUS



;13 - XXX - RESERVED

RD13S:	MOVEI	M0,$EEUDS	;UNKNOWN DAP STATUS
	JRST	.POPJ1##	;RETURN STATUS



;14 - XXX - RESERVED

RD14S:	MOVEI	M0,$EEUDS	;UNKNOWN DAP STATUS
	JRST	.POPJ1##	;RETURN STATUS



;15 - XXX - RESERVED

RD15S:	MOVEI	M0,$EEUDS	;UNKNOWN DAP STATUS
	JRST	.POPJ1##	;RETURN STATUS



;16 - XXX - CUSTOMER DEFINED

RD16S:	MOVEI	M0,$EEUDS	;UNKNOWN DAP STATUS
	JRST	.POPJ1##	;RETURN STATUS



;17 - XXX - CUSTOMER DEFINED

RD17S:	MOVEI	M0,$EEUDS	;UNKNOWN DAP STATUS
	JRST	.POPJ1##	;RETURN STATUS
;CONVERSION TABLE: DAP STATUS TO FILE ACCESS ERROR

DS2EF::	$EFRAE,,$DSACC		;"GENERIC" REMOTE FILE ACCESS ERROR
	$EFNSD,,$DSDEV		;BAD DEVICE; NO SUCH DEVICE
	$EFTBL,,$DSDME		;SYSTEM DYNAMIC MEMORY EXHAUSTED
	$EFDNF,,$DSDNF		;DIRECTORY NOT FOUND
	$EFAEF,,$DSFEX		;(DUPL) ALREADY EXISTING FILE
	$EFFLK,,$DSFLK		;FILE LOCKED BY ANOTHER USER
	$EFFNF,,$DSFNF		;FILE NOT FOUND
	$EFNRM,,$DSFUL		;NO ROOM - DEVICE/FILE IS FULL
	$EFFUL,,$DSFUL		;DEVICE/FILE IS FULL
	$EFPRT,,$DSPRV		;PRIVILEGE VIOLATION
	$EFILU,,$DSSYS		;SYSTEM DIRECTIVE ERROR
	$EFWLK,,$DSWLK		;DEVICE IS WRITE-LOCKED
	$EFRIB,,$DSIFA		;ILL FILE ATTR; CORRUPT FILE HEADER
	$EFQTA,,$DSQTA		;QUOTA EXCEEDED
	$EFFBM,,$DSFBM		;FILE BEING MODIFIED (ANOTHER WRITER)
	$EFDNA,,$DSDNA		;DEVICE NOT AVAILABLE
	$EFNSD,,$DSDNF		;DEVICE NOT FOUND (NO SUCH DEVICE)
	$EFPOA,,$DSPOA		;PARTIAL ALLOCATION ONLY
	$EFBNF,,$DSBNF		;SPECIFIED BLOCK NOT FREE
	$EFCSD,,$DSCSD		;CAN'T SUPERSEDE DIRECTORY FILE
	$EFDNE,,$DSDNE		;CAN'T DELETE NON-EMPTY DIRECTORY FILE
	$EFSNF,,$DSSNF		;SUB-FILE-DIRECTORY NOT FOUND
	$EFSLE,,$DSSLE		;SEARCH LIST EMPTY
	$EFLVL,,$DSLVL		;SUB-FILE-DIRECTORIES NESTED TOO DEEPLY
	$EFNCE,,$DSNCE		;NO-CREATE FOR ENTIRE SEARCH LIST
	$EFFCU,,$DSFCU		;CAN'T UPDATE FILE
	$EFENC,,$DSENC		;EXCEEDED NETWORK CAPACITY
	$EFTNA,,$DSTNA		;TSK DEVICE NOT AVAILABLE
	$EFNSN,,$DSNSN		;NO SUCH NODE
	$EFSIU,,$DSSIU		;SUB-FILE-DIRECTORY IN USE ON RENAME
	$EFNDR,,$DSNDR		;CAN'T DELETE FILE - NDR LOCK SET
	$EFJCH,,$DSJCH		;TOO MANY SIMULTANEOUS FILE ACCESSES
	$EFSSL,,$DSSSL		;CAN'T RENAME SUB-FILE-DIRECTORY TO LOWER LVL
	$EFDDU,,$DSDDU		;DEVICE "DOWN" AND UNUSEABLE
	$EFDRS,,$DSDRS		;DEVICE IS RESTRICTED
	$EFDCM,,$DSDCM		;DEVICE CONTROLLED BY MDA, NOT ASSIGNABLE
	$EFDAJ,,$DSDAJ		;DEVICE ASSIGNED TO ANOTHER JOB
	$EFIDM,,$DSIDM		;ILLEGAL I/O DATA MODE

;"DUPLICATES", SEPARATED TO PRIORITIZE ERRORS FOR FAL

	$EFAEF,,$DSCFS		;CREATED FILE SUPERSEDED EXTANT FILE
	$EFAEF,,$DSRFE		;RENAME TO EXTANT FILE
	0



;CONVERSION TABLE: DAP STATUS TO I/O TRANSMISSION ERROR

DS2EI::	$EIEOF,,$DSEOF	;END OF FILE
	$EIFUL,,$DSFUL	;DEVICE FULL
	$EIBKT,,$DSRTB	;RECORD/BLOCK TOO LARGE
	$EIHWL,,$DSWLK	;DEVICE IS (HARDWARE) WRITE-LOCKED
	$EIDEV,,$DSHDE	;HARD DEVICE ERROR
	$EIDAT,,$DSPAR	;DEVICE PARITY ERROR
	$EIEOV,,$DSEOV	;END OF VOLUME
	$EICKE,,$DSCKE	;NETWORK FILE DATA CRC (CHECKSUM) ERROR
	$EIQTA,,$DSQTA	;USER QUOTA EXCEEDED
	$EILLE,,$DSLLE	;LINEPRINTER PAGE LIMIT EXCEEDED
	$EIVFE,,$DSVFE	;LINEPRINTER VFU FORMAT ERROR
	$EILUC,,$DSLUC	;LINEPRINTER "UNDEFINED CHARACTER" ERROR
	$EIVRP,,$DSVRP	;LINEPRINTER VFU RAM PARITY ERROR

	$EIRIE,,$DSRER	;GENERIC/UNSPECIFIED READ ERROR
	$EIRIE,,$DSWER	;GENERIC/UNSPECIFIED WRITE ERROR

;"DUPLICATES", SEPARATED TO PRIORITIZE ERRORS FOR FAL

	$EISWL,,$DSWLK	;DEVICE IS (SOFTWARE) WRITE-LOCKED
	0
;RDDAT  --  START READING A DAP DATA MESSAGE
;CALL IS:
;
;	MOVX	T2,<CDB>
;	PUSHJ	P,RDDAT
;	 error return
;	normal return
;
;Where <CDB> is the address of the associated I/O CDB.
;
;On error return M0 contains an error code (network died, etc.).
;
;On normal return the DAP input routines (i.e., RDBYT) are ready to
;read and return data bytes. The DAP DATA RCN (record number) field
;returned in T2/T3.
;
;Uses T1 - T4.

	ENTRY	.RDDAT
	INTERN	RDDAT0,	RDDAT1

.RDDAT:	PUSHJ	P,.SACIO##	;SETUP I/O CDB ADDRESS
RDDAT0:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
RDDAT1:	SKIPLE	T2,.IODIM(IO)	;GET CURRENT INPUT MESSAGE TYPE
	CAIE	T2,$DHDAT	;IS IT DATA?
	STOPCD	<Not a DAP DATA message in RDDAT>
	PUSHJ	P,RDDAP2	;HANDLE TEMPLATED PORTION OF DATA MESSAGE
	 POPJ	P,		;SOMETHING BAD HAPPENED
	MOVD	T2,RCN		;GET RECORD NUMBER (IF ANY)
	JRST	.POPJ1##	;READY TO EXTRACT THE DATA BYTES
;RDDAP  --  READ AND STORE A GENERIC DAP MESSAGE
;CALL IS:
;
;	MOVX	T1,<CDB>
;	MOVX	T2,<code>
;	PUSHJ	P,RDDAP
;	 error return
;	normal return
;
;Where <CDB> is the address of the associated I/O CDB, and <code> is the
;DAP message code of the incoming DAP message. Data messages
;(<code> = $DHDAT) are illegal.
;
;On error return, M0 contains an error code (network died or some sort
;of DAP error such as message too short). If the error was DAPpish in
;origin, a status message will have been sent to the other side telling
;of the error.
;
;On normal return the DAP message has been read into the .IODAP area in
;the I/O CDB, ready to be translated into the usual CDB stuff.
;
;Uses acs T1, T2, T3, T4

	ENTRY	.RDDAP
	INTERN	RDDAP0,	RDDAP1

.RDDAP:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
RDDAP0:	PUSHJ	P,.SAVE4##	;SAVE LOTS OF ACS
RDDAP1:	CAIN	T2,$DHDAT	;BETTER NOT BE A DATA MESSAGE
	STOPCD	<RDDAP called for DATA message>
RDDAP2:	MOVEI	T4,DAPIDX	;DAP INDEX TABLE
	PUSHJ	P,.CFIND##	;FIND THE INDEX ENTRY FOR THIS MESSAGE TYPE
	 PJRST	RDEUM		;ERROR - UNKNOWN MESSAGE TYPE
	HRRZM	T1,.IODRX(IO)	;SET CURRENT RDDAP EXECUTION INDEX
	HRRZM	T2,.IODIM(IO)	;SET CURRENT INPUT MESSAGE TYPE

;LOOP READING FIELDS FROM THE DAP INPUT MESSAGE

RDDAP3:	PUSHJ	P,RDBYT0	;GET NEXT DAP BYTE
	 JRST	RDDAP7		;END OF MESSAGE ACCEPTABLE HERE
	PUSHJ	P,RDBYR0	;SAVE BYTE TO BE RE-READ
	 STOPCD			;CAN'T HAPPEN
	AOS	P1,.IODRX(IO)	;ADVANCE TO NEXT FIELD
	MOVE	T1,DAPXCT(P1)	;EXECUTION TABLE ENTRY FOR THIS FIELD
	LDB	T2,[POINTR T1,DX$COD]  ;FIELD "NUMBER"
	LDB	T3,[POINTR T1,DX$TYP]  ;FIELD "TYPE"
	CAILE	T3,$DXTMX	;RANGE CHECK AGAINST KNOWN FIELDS
	STOPCD	<RDDAP DX$TYP field entry too big>
	JUMPE	T3,RDDAP5	;END OF MESSAGE TEMPLATE?
		.XCREF	$DXTMS	;CREF REFERENCE TO SYMBOLIC NAME
	MOVEM	T2,.IODRF(IO)	;SAVE IN CASE OF ERROR

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;CALL FIELD PROCESSOR WITH P1/DAPXCT INDEX AND T1/DAPXCT TABLE ENTRY

	PUSHJ	P,@RDDAPX(T3)	;DISPATCH ON FIELD TYPE
	 POPJ	P,		;ERROR SOMEWHERE
	JRST	RDDAP3		;LOOP BACK FOR REST OF THE MESSAGE

;HERE WHEN THE INPUT DAP MESSAGE SHOULD BE EXHAUSTED (SINCE OUR TEMPLATE
;USED UP ALL ITS FIELD DEFINITIONS).

RDDAP5:	MOVE	T2,.IODIM(IO)	;GET INPUT MESSAGE TYPE
	CAIN	T2,$DHDAT	;DATA MESSAGE?
	JRST	.POPJ1##	;YES, SOMEONE ELSE READS THE REST
	PUSHJ	P,RDBYT1	;SEE IF ANY MORE DATA
	 JRST	RDDAP7		;PROBABLY NOT
	HRRZ	T1,.IODIM(IO)	;TOO MUCH DATA PRESENT
	CAIE	T1,$DHCFG	;IN CONFIGURATION MESSAGE?
	PJRST	RDEUF		;NO, ERROR - UNKNOWN FIELD IN MESSAGE
	PJRST	RDEAT1		;YES, OK, JUST EAT EXCESS CONFIGURATION

RDDAP7:	JUMPE	M0,.POPJ1##	;IF OUT OF DAP DATA THEN WE'RE HAPPY
	POPJ	P,		;OTHERWISE NETWORK DIED, ERROR


;DAP MESSAGE FIELD PROCESSOR DISPATCH TABLE

;EACH FIELD PROCESSING ROUTINE IS ENTERED WITH:
;	T1/DAPXCT TABLE ENTRY FOR THE FIELD
;	P1/DAPXCT TABLE INDEX FOR THE FIELD
;ACS T1 - T4, AND P1 - P4 ARE AVAILABLE FOR USAGE WITHIN THE VARIOUS
;FIELD PROCESSING ROUTINES

RDDAPX:	RD00T			;00 - START OF DAP MESSAGE TEMPLATE
	RD01T			;01 - ASCII TEXT
	RD02T			;02 - BINARY DATA
	RD03T			;03 - COMPRESSED (1 WORD/5 BYTES) BINARY
	RD04T			;04 - FLAGS (OR BIT MAP)
	RD05T			;05 - IMAGE 8-BIT BYTES
	RD06T			;06 - MENU FIELD FOR REST OF MESSAGE
	RD07T			;07 - DATE/TIME IN ASCII
;RD00T  -  START OF MESSAGE TEMPLATE IN EXECUTION TABLE

RD00T:	STOPCD	<RD00T dispatch in RDDAP>
;RD01T  -  ASCII TEXT FIELD

RD01T:	PUSHJ	P,TSAV11##	;NEED A SCRATCH LOCATION
	LDB	T3,[POINTR T1,DX$LNB]  ;FIELD LENGTH (DAP BYTES)
	LDB	T4,[POINTR T1,DX$IOX]  ;FIELD OFFSET INTO .IODAP
	ADD	T4,[POINT 7,.IODAP(IO)]  ;MAKE INTO BYTE POINTER
	SETZM	-T1(P)		;NO TRAILING SPACE YET
	TXNE	T1,DX$XTN	;EXTENSIBLE ASCII?
	JRST	RD01T5		;YES
	TXNN	T1,DX$VAR	;VARIABLE LENGTH ASCII STRING?
	JRST	RD01T3		;NO, FIXED LENGTH
	PUSHJ	P,RDBYT1	;YES, READ STRING LENGTH
	 PJRST	RDEIE		;ERROR IN FIELD
	CAMLE	T2,T3		;FIELD LENGTH WITHIN SPECS?
	PJRST	RDEIE		;NO, TOO BIG, ERROR IN FIELD
	EXCH	T3,T2		;YES, OK, SET REAL FIELD LENGTH
	SUB	T2,T3		;T2:=SPACE LEFT OVER
	MOVEM	T2,-T1(P)	;SET TRAILING SPACE NEEDING CLEARING
	JRST	RD01T3		;ENTER LOOP

;LOOP READING FIXED/VARIABLE ASCII INPUT

RD01T2:	PUSHJ	P,RDBYT1	;READ NEXT ASCII BYTE
	 PJRST	RDEIE		;SOMETHING'S WRONG
	IDPB	T2,T4		;STASH AWAY THIS CHARACTER
RD01T3:	SOJGE	T3,RD01T2	;LOOP FOR REST OF FIELD
	MOVE	T3,-T1(P)	;AMOUNT OF SPACE STILL NEEDING CLEARING
	SETZ	T2,		;INPUT DONE, A TERMINATING NULL
	IDPB	T2,T4		;TERMINATE THE STRING
	SOJGE	T3,.-1		;CLEAR THE REST OF THE STRING
	JRST	.POPJ1##	;SUCCESSFUL RETURN

;LOOP READING EXTENSIBLE ASCII INPUT

RD01T5:	PUSHJ	P,RDBYT1	;READ NEXT INPUT BYTE
	 PJRST	RDEIE		;ERROR SOMEWHERE
	IDPB	T2,T4		;STASH AWAY THIS CHARACTER
	TRNE	T2,200		;EXTENDED BYTE?
	SOJG	T3,RD01T5	;YES, READ MORE
	TRNE	T2,200		;TRULY END OF INPUT?
	PJRST	RDEIF		;NO, TOO MUCH, ERROR IN FIELD
	SETZ	T2,		;YES, A TERMINATING NULL
	IDPB	T2,T4		;TO TERMINATE THE STRING
	SOJGE	T3,.-1		;CLEAR REST OF STRING
	JRST	.POPJ1##	;SUCCESSFUL RETURN
;RD02T  -  BINARY INPUT FIELD
;RD03T  -  COMPRESSED BINARY INPUT FIELD

RD02T:				;THEY'RE THE SAME, ALMOST
RD03T:	LDB	P3,[POINTR T1,DX$LNB]  ;FIELD LENGTH (MAX IN DAP BYTES)
	CAILE	P3,^D9		;WILL IT FIT THE ALGORITHM BELOW?
	 STOPCD	<Binary DAP field larger than 9 bytes in RD03T>
	SETZB	T2,T3		;INITIALIZE BINARY VALUE
	TXNE	T1,DX$XTN	;EXTENSIBLE BINARY FORMAT?
	JRST	RD03T5		;YES
	MOVEI	P4,^D9		;MAXIMUM POSSIBLE LENGTH
	SUB	P4,P3		;P4:=BYTES NOT USED IN 72-BIT DOUBLE-WORD
	TXNN	T1,DX$VAR	;VARIABLE LENGTH BINARY FORMAT?
	JRST	RD03T3		;NO, FIXED LENGTH
	PUSHJ	P,RDBYT1	;READ FIELD LENGTH
	 PJRST	RDEIE		;ERROR IN FIELD
	MOVE	P3,T2		;SET ACTUAL FIELD LENGTH
	MOVEI	P4,^D9		;MAX FIELD LENGTH (FOR TWO WORDS)
	SUB	P4,P3		;BYTES NOT USED
	SETZB	T3,T4		;INITIALIZE BINARY VALUE
	JRST	RD03T3		;ENTER LOOP
;LOOP READING FIXED/VARIABLE BINARY INPUT BYTES

RD03T2:	PUSHJ	P,RDBYT1	;READ NEXT BYTE
	 PJRST	RDEIE		;ERROR IN FIELD
	LSHC	T3,-^D8		;MAKE ROOM FOR NEXT HIGHER-ORDER BYTE
	LSH	T3,^D8		;SLIP BACK AND
	LSHC	T2,-^D8		;PICK UP THE BYTE
RD03T3:	SOJGE	P3,RD03T2	;LOOP FOR REST OF FIELD
	IMULI	P4,^D8		;COUNT OF BITS NOT USED IN DOUBLE-WORD VALUE
	MOVNS	P4		;NEGATIVE BIT COUNT
	LSHC	T3,0(P4)	;RIGHT-JUSTIFY FIELD
	TLNE	T3,(1B0!1B1)	;MORE THAN 70 BITS?
	STOPCD	<Binary DAP value greater than 70 bits in RD03T>
	LSHC	T3,1		;PUT 35-BITS PER WORD
	LSH	T4,-1		;-10 FORMAT DOUBLE PRECISION INTEGER
	LDB	T1,[POINTR DAPXCT(P1),DX$LNB]  ;SIZE OF FIELD IN 8-BIT BYTES
	CAIG	T1,4		;MORE THAN ONE -10 WORDS' WORTH?
	MOVEI	T1,1		;NO, ONE WORD IS SUFFICIENT
	CAILE	T1,4		;LESS THAN TWO -10 WORDS' WORTH?
	MOVEI	T1,2		;NO, TWO WORDS NEEDED
	LDB	T2,[POINTR DAPXCT(P1),DX$TYP]  ;FIELD TYPE
	CAIN	T2,$DXTCN	;COMPRESSED 1 WORD VALUE?
	MOVEI	T1,1		;YES, SIZE IS ONE WORD THEN
	LDB	T2,[POINTR DAPXCT(P1),DX$IOX]  ;OFFSET INTO .IODAP AREA
	ADDI	T2,.IODAP(IO)	;RELOCATE INTO I/O CDB
	CAIN	T1,1		;ONE-WORD VALUE?
	MOVEM	T4,(T2)		;YES
	CAIN	T1,2		;TWO-WORD VALUE?
	DMOVEM	T3,(T2)		;YES
	LDB	T1,[POINTR DAPXCT(P1),DX$TYP]  ;FIELD TYPE AGAIN
	CAIN	T1,$DXTCN	;COMPRESSED BINARY?
	CAIN	T3,0		;YES, DID DAP INPUT FIT?
	JRST	.POPJ1##	;SUCCESSFUL RETURN
	STOPCD	<Compressed DAP binary field exceeded 36 bits in RD03T>

;LOOP READING EXTENSIBLE BINARY FIELD

RD03T5:	STOPCD	<Extensible DAP binary field encountered in RD03T>
;RD04T  -  FLAGS FIELD (ALSO MENU, SEE RD06T)

RD04T:	LDB	T3,[POINTR T1,DX$LNB]  ;FIELD LENGTH (DAP BYTES)
	LDB	T4,[POINTR T1,DX$IOX]  ;FIELD STORAGE IN .IODAP
	ADD	T4,[POINT 7,.IODAP(IO)]  ;MAKE INTO BYTE POINTER
	TXNE	T1,DX$XTN	;EXTENSIBLE FIELD?
	JRST	RD04T5		;YES
	STOPCD	<Fixed/variable length DAP flags field encountered in RD04T>

;LOOP READING EXTENSIBLE FLAG BYTES

RD04T5:	PUSHJ	P,RDBYT1	;READ NEXT FLAG BYTE
	 PJRST	RDEIE		;ERROR IN FIELD
	IDPB	T2,T4		;STORE FLAGS
	TRNE	T2,200		;EXTENDED BYTE?
	SOJG	T3,RD04T5	;YES, LOOP BACK AND FINISH THE FIELD
	TRNE	T2,200		;REALLY THE END?
	PJRST	RDEIF		;ERROR IN FIELD - TOO BIG
	TDZA	T2,T2		;NULL BYTE
	IDPB	T2,T4		;CLEAR SOME FLAGS
	SOJG	T3,.-1		;CLEAR REST OF FIELD
	JRST	.POPJ1##	;SUCCESSFUL RETURN
;RD05T  -  IMAGE BYTE FIELD

RD05T:	LDB	T3,[POINTR T1,DX$LNB]  ;FIELD LENGTH (BYTES)
	LDB	T4,[POINTR T1,DX$IOX]  ;FIELD STORAGE IN .IODAP
	ADD	T4,[POINT 8,.IODAP(IO)]  ;MAKE INTO BYTE POINTER
	TXNE	T1,DX$XTN	;EXTENSIBLE IMAGE FIELD?
	JRST	RD05T5		;YES
	TXNN	T1,DX$VAR	;NO, VARIABLE LENGTH FIELD?
	JRST	RD05T3		;NO, FIXED LENGTH
	PUSHJ	P,RDBYT1	;YES, READ ACTUAL FIELD SIZE
	 PJRST	RDEIE		;ERROR IN FIELD
	CAMLE	T2,T3		;WITHIN SPECS?
	PJRST	RDEIE		;NO, TOO BIG, ERROR IN FIELD
	MOVE	T3,T2		;SET ACTUAL FIELD SIZE
	JRST	RD05T3		;AND ENTER LOOP

;LOOP READING IMAGE BYTES

RD05T2:	PUSHJ	P,RDBYT1	;NEXT IMAGE BYTE
	 PJRST	RDEIE		;ERROR IN FIELD
	IDPB	T2,T4		;STORE THIS BYTE
RD05T3:	SOJGE	T3,RD05T2	;LOOP FOR REST OF FIELD
	TDZA	T2,T2		;TRAILING NULL
	IDPB	T2,T4		;WIPE OUT TRAILING FIELD
	SOJGE	T3,.-1		;CLEAR OUT REST OF FIELD
	JRST	.POPJ1##	;SUCCESSFUL RETURN

;LOOP READING EXTENSIBLE IMAGE BYTES

RD05T5:	STOPCD	<Extensible DAP image field encountered in RD05T>
;RD06T  -  MENU FIELD

RD06T:	TXNE	T1,DX$SKP	;IS THIS AN "INVISIBLE" MENU?
	JRST	.POPJ1##	;*** YES, JUST IGNORE IT HERE
	LDB	T3,[POINTR T1,DX$LNB]  ;FIELD LENGTH
	LDB	T4,[POINTR T1,DX$IOX]  ;FIELD STORAGE IN .IODAP
	ADD	T4,[POINT 7,.IODAP(IO)]  ;MAKE INTO BYTE POINTER
	DMOVEM	T3,.IODRM(IO)	;SAVE FOR PROCESSING THE MENU FIELD
	TXNE	T1,DX$XTN	;EXTENSIBLE FIELD?
	JRST	RD06T5		;YES
	STOPCD	<Fixed/variable length DAP menu field encountered in RD06T>

;LOOP READING EXTENSIBLE MENU FIELD

RD06T5:	PUSHJ	P,RDBYT1	;NEXT DAP BYTE
	 PJRST	RDEIE		;ERROR IN FIELD
	IDPB	T2,T4		;STORE AWAY MENU BYTE
	TRNE	T2,200		;END OF EXTENSIBLE FIELD?
	SOJG	T3,RD06T5	;NO, LOOP BACK AND FINISH IT OFF
	TRNE	T2,200		;REALLY THE END?
	PJRST	RDEIF		;NO, ERROR IN FIELD
	TDZA	T2,T2		;YES, A NULL
	IDPB	T2,T4		;TO TERMINATE THE FIELD
	SOJG	T3,.-1		;CLEAR REST OF FIELD

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;NOW LOOP PROCESSING REST OF MESSAGE AS DESCRIBED BY THE MENU

RD06M1:	ILDB	P2,.IODRM+1(IO)	;GET A MENU BYTE
	TROA	P2,200		;FORCE 7-BITS-WORTH OF LOOP

;LOOP WITHIN 7-BIT MENU SUBFIELD

RD06M2:	LSH	P2,-1		;ADVANCE TO NEXT MENU BIT
	AOS	P1,.IODRX(IO)	;CORRESPONDING EXECUTION TABLE INDEX
	TRZN	P2,1		;THIS FIELD PRESENT?
	JUMPN	P2,RD06M5	;NO, TRY CHECK FOR REST OF MENU'ED MESSAGE
	JUMPE	P2,RD06M7	;YES, UNLESS FAKE BIT ("TROA" ABOVE)

;READ IN MENU-SPECIFIED FIELD

	MOVE	T1,DAPXCT(P1)	;PICK UP EXECUTION TABLE ENTRY
	LDB	T2,[POINTR T1,DX$COD]  ;FIELD "NUMBER"
	LDB	T3,[POINTR T1,DX$TYP]  ;FIELD "TYPE"
	CAILE	T3,$DXTMX	;WITHIN MAXIMUM LIMITS?
	 STOPCD	<DX$TYP menued DAP field type too big in RD06M>
	MOVEM	T2,.IODRF(IO)	;SET CURRENT INPUT FIELD "NUMBER"
	CAIE	T3,$DXTMS	;IF START OF MESSAGE,
	CAIN	T3,$DXTMN	; OR MENU
	JRST	RDEIF		;THEN ERROR IN FIELD
	PUSH	P,P2		;SAVE P2
	PUSHJ	P,@RDDAPX(T3)	;DISPATCH ON FIELD TYPE
	 JRST	[POP	P,P2		;ERROR, ADJUST STACK
		POPJ	P,]		;AND PROPAGATE THE ERROR
	POP	P,P2		;RESTORE P2
RD06M5:	LDB	T3,[POINTR DAPXCT+1(P1),DX$TYP]  ;PEEK AT NEXT FIELD TYPE
	CAIE	T3,$DXTMS	;END OF CURRENT MESSAGE?
	JRST	RD06M2		;NO, STILL MORE FIELDS POSSIBLE
	MOVE	T1,P2		;CURRENT MENU BYTE
	JFFO	T1,.+1		;FIND THE FIRST BIT
	LSH	T1,1(T2)	;GET RID OF JUNK ("TROA") BIT
	JUMPN	T1,RDEIF	;IF STILL BITS (ALLEGING FIELDS) THEN ERROR
	ILDB	T1,.IODRM+1(IO)	;NEXT MENU BYTE
	SOSLE	.IODRM+0(IO)	;COUNT DOWN MENU BYTES LEFT
	JRST	.-3		;CHECK THEM ALL OUT
	JRST	.POPJ1##	;SUCCESSFUL RETURN

RD06M7:	SOS	.IODRX(IO)	;THE "TROA" BIT DOESN'T COUNT AGAINST INDEX
	SOSLE	.IODRM+0(IO)	;COUNT DOWN MENU BYTES
	JRST	RD06M1		;AND KEEP PROCESSING THEM
	PJRST	RDEIF		;ERROR IN FIELD
;RD0T7  -  TIME FIELD

RD07T:	LDB	P3,[POINTR T1,DX$LNB]  ;DAP FIELD LENGTH (BYTES)
	MOVE	P4,[POINT 7,.IODTM(IO)];TEMP HOLDING AREA POINTER

;FIRST STRIP OFF ANY LEADING SPACES (E.G., " 1-MAY-...") SO IT/THEY DON'T
;GET CONVERTED INTO COLONS . . .

RD07T1:	PUSHJ	P,RDBYT1	;GET A DATE/TIME CHARACTER
	 JRST	RDEIE		;ERROR IN FIELD
	CAIE	T2," "		;IS THIS A LEADING SPACE?
	JRST	RD07T4		;NO, VALID CHARACTER
	SOJG	P3,RD07T1	;YES, LOOP EATING SPACES
	SETZ	T2,		;NO?????????????????
	JRST	RD07T7		;SO RETURN A ZERO DATE/TIME

;READ IN ASCII DATE/TIME STRING INTO SCRATCH HOLDING AREA

RD07T3:	PUSHJ	P,RDBYT1	;NEXT ASCII DATE/TIME CHARACTER
	 JRST	RDEIE		;ERROR IN FIELD
	CAIN	T2," "		;IS THIS DAP'S SPACE 'TWEEN DATE AND TIME?
	MOVEI	T2,":"		;YES, SCAN WANTS A COLON THERE
RD07T4:	IDPB	T2,P4		;STASH THIS CHARACTER
	SOJG	P3,RD07T3	;LOOP FOR REST OF FIELD
	IDPB	P3,P4		;ASCIZIZE THE STRING

;TRANSLATE ASCII STRING INTO 36-BIT INTERNAL DATE/TIME FORMAT

	PUSHJ	P,RD07X0	;GET INTERNAL FORMAT DATE/TIME
	 JRST	RDEIE		;ERROR IN FIELD
RD07T7:	LDB	T4,[POINTR DAPXCT(P1),DX$IOX]  ;GET CDB OFFSET FOR THIS FIELD
	ADDI	T4,.IODAP(IO)	;RELOCATE INTO MEMORY
	MOVEM	T2,0(T4)	;SET DATE/TIME FIELD IN DAP BLOCK
	JRST	.POPJ1##	;SUCCESSFUL RETURN
;HELPER TO TRANSLATE ASCIZ STRING INTO BINARY ("INTERNAL") DATE/TIME

RD07X0:	PUSHJ	P,.SAVE4##	;SCAN'S CH AND NM ARE OUR P3 AND P4 !!!
	SETZM	.IOXTO(IO)	;USE IOXTO AS COUNTER/FLAG HERE
	XMOVEI	T1,RD07XI	;OUR VERY OWN INPUT TYPER
	PUSHJ	P,.XTYPI##	;INTERCEPT "COMMAND" INPUT
	XMOVEI	T1,RD07XO	;OUR VERY OWN OUTPUT TYPER
	PUSHJ	P,.XTYPO##	;INTERCEPT "COMMAND" OUTPUT
	MOVE	T1,[POINT 7,[0]];A DUMMY STRING
	MOVEM	T1,.IOXTI(IO)	;SET IN CASE .CLRTI NEEDS SOMETHING
	PUSHJ	P,.CLRTI##	;SETUP LOWLEVEL COMMAND INPUT ROUTINES
	MOVE	T1,[POINT 7,.IODTM(IO)]  ;BYTE POINTER TO ASCIZ STRING
	MOVEM	T1,.IOXTI(IO)	;SET FOR RD07XI

;NOW PARSE THE ASCIZ DATE/TIME STRING

RD07X3:	PUSHJ	P,.DYTIM##	;LET SCAN DO ITS THING
	 JRST	RD07X7		;ERROR - DIE
	MOVE	T2,NM		;POSITION DATE/TIME FOR CALLER
	SKIPN	.IOXTO(IO)	;IT BETTER NOT HAVE COMPLAINED
	JRST	.POPJ1##	;RETURN WITH DATE/TIME IN T2
RD07X7:	STOPCD	<Error in parsing received DATE/TIME message in RD07X>


;THE "COMMAND" INPUT ROUTINE

RD07XI:	ILDB	CH,.IOXTI(IO)	;GET NEXT CHARACTER FROM NAME STRING
	JUMPN	CH,.POPJ##	;RETURN IT
	MOVEI	CH,.CHLFD	;END OF STRING, RETURN EOL TO SCAN
	POPJ	P,		; . . .


;THE "COMMAND" OUTPUT ROUTINE

RD07XO:	OUTCHR	T1		;OH WELL
	AOS	.IOXTO(IO)	;COUNT OCCURENCES
	POPJ	P,		;RETURN TO SCAN
;ERRORS READING DAP PROTOCOL

;UNKNOWN DAP MESSAGE TYPE

RDEUM:	STOPCD	<Unknown DAP message type>


;UNKNOWN DAP MESSAGE FIELD

RDEUF:	STOPCD	<Unknown DAP message field>


;ERROR (UNSPECIFIED) IN FIELD

RDEIE:	STOPCD	<Error in DAP field>
RDEIF:	STOPCD	<Error in DAP field>
;RDEAT  --  EAT [REST OF] DAP MESSAGE
;CALL IS:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,RDEAT
;	 error return
;	normal return
;
;Where <CDB> is the address of the associated I/O CDB.
;
;On error return the network died whilst reading whatever is left of the
;DAP input message.
;
;On normal return the DAP input message has been completely read, and
;is now ready for the next DAP input message (i.e., RDBYT will return
;with no data available, RDMSG must be called to start the next input
;message processing). If called to eat a data message the file data
;CRC will be updated to reflect the data bytes "eaten" (note that the
;caller is responsible to ensure that the RCN field of the data message
;has already been read).
;
;Uses ac T2.

	ENTRY	.RDEAT
	INTERN	RDEAT0,	RDEAT1

.RDEAT:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
RDEAT0:
RDEAT1:	MOVE	T2,.IODIM(IO)	;GET CURRENT DAP MESSAGE TYPE
	CAIN	T2,$DHDAT	;EATING INPUT FILE DATA?
	JRST	RDEAT4		;YES, MUST KEEP CRC UPDATED

;HERE TO EAT NON-DATA DAP MESSAGES

RDEAT2:	PUSHJ	P,RDBYT1	;READ ANOTHER DAP BYTE
	 CAIA			;NONE AVAILABLE
	JRST	RDEAT2		;TRY FOR MORE
	JUMPE	M0,.POPJ1##	;IF NO DATA THEN SUCCESSFUL RETURN
	POPJ	P,		;OTHERWISE THE NETWORK DIED

;HERE TO EAT DAP DATA MESSAGES

RDEAT4:	PUSHJ	P,RDBYC1	;READ ANOTHER DAP BYTE, UPDATING THE CRC
	 CAIA			;NONE AVAILABLE
	JRST	RDEAT4		;TRY FOR MORE
	JUMPE	M0,.POPJ1##	;IF NO DATA THEN SUCCESSFUL RETURN
	POPJ	P,		;OTHERWISE THE NETWORK DIED
;RDBYC  --  READ ONE DAP FILE DATA BYTE, CALCULATING CRC
;CALL IS:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,RDBYC
;	 error return
;	normal return
;
;Where <CDB> is the address of the associated I/O CDB.
;
;On error return either the network died or the current input DAP
;data message is exhausted (M0 has 0).
;
;On normal return the next available file data byte is in T2,
;and the running file data CRC has been updated.
;
;This routine is functionally identical to RDBYT, except that the
;file data CRC is updated.
;
;Uses T2.

	ENTRY	.RDBYC
	INTERN	RDBYC0,	RDBYC1

	INTERN	RDCRC1

.RDBYC:	PUSHJ	P,.SACIO##	;SETUP I/O CONTEXT
RDBYC0:
RDBYC1:	PUSHJ	P,RDBYT1	;GET NEXT DAP BYTE
	 POPJ	P,		;PROPAGATE EXCEPTION RETURN
RDCRC1:	PUSH	P,T2		;SAVE RETURN DATA BYTE
	ANDI	T2,377		;REDUCE TO JUST INTERESTING DATA
	MOVE	M0,.IODIK(IO)	;GET LAST FILE DATA CRC
	XORB	M0,T2		;INCLUDE BYTE IN CRC
	ANDI	T2,377		;COMPUTE OFFSET INTO CRC TABLE
	LSH	M0,-^D08	;XOR REMAINING CRC FROM TABLE
	XOR	M0,DAPCRC(T2)	;COMPUTE NEW CRC
	MOVEM	M0,.IODIK(IO)	;AND STASH IT AWAY
	POP	P,T2		;RESTORE DAP FILE DATA BYTE
	JRST	.POPJ1##	;AND SUCCESSFUL RETURN
;RDBYT  --  READ ONE DAP BYTE
;CALL IS:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,RDBYT
;	 error return
;	normal return
;
;Where <CDB> is the address of the associated I/O CDB.
;
;On error return either the network died or the current input DAP
;message is exhausted (M0 has 0).
;
;On normal return the next available DAP byte is in T2.
;
;This routine handles continuation messages (DF$MOR) internally - the
;caller is not required to be aware of them (and in fact is not even told
;if a continuation message is encountered).
;
;Uses ac T2.

	ENTRY	.RDBYT
	INTERN	RDBYT0,	RDBYT1

.RDBYT:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
RDBYT0:
RDBYT1:	SKIPE	T2,.IODIR(IO)	;GOT A BYTE TO BE RE-READ?
	JFFO	P,[SETZM .IODIR(IO)	;CLEAR OUT STALE BYTE
		TLNE	T2,(1B1)	;SAVED ERROR CODE (400000,,ERROR)?
		TLZA	T2,-1		;NO, CLEAR OUT FLAG, LEAVING DATA BYTE
		TROA	M0,(T2)		;YES, POSITION ERROR CODE
		AOS	0(P)		;SUCCESS RETURN
		POPJ	P,]		;FAILURE RETURN
	SOSGE	.IODIC(IO)	;ANY DAP BYTES LEFT?
	JRST	RDBYT4		;PROBABLY NOT, BUT MIGHT BE CONTINUATION
	PUSHJ	P,RNBYT1	;YES, READ NEXT BYTE FROM NETWORK
	 JRST	RDBYT2		;HMMM. PROBABLY BAD NEWS
	AOS	(P)		;SKIP
	POPJ	P,		; RETURN
;NETWORK REFUSED TO GIVE US A BYTE

RDBYT2:	PJUMPN	M0,.POPJ##	;IF NETWORK DIED, LET HIGHER UPS HANDLE IT
	HLRZ	T2,.IODIC(IO)	;GET DAP BYTE COUNT
	CAIE	T2,223344	;WAS IT A DUMMY COUNT?
	STOPCD	<Network EOM before DAP EOM - DAP data lost>
	SETZM	.IODIC(IO)	;FLAG OK END OF DAP MESSAGE

;HERE WHEN THE CURRENT DAP MESSAGE IS EXHAUSTED. CHECK FOR A CONTINUATION
;MESSAGE (I.E., A DAP MESSAGE WHICH WAS BROKEN UP INTO SEGMENTS AND ACTUALLY
;TRANSMITTED AS SEVERAL DISTINCT (PRESUMABLY PHYSICAL NETWORK) MESSAGES.)

RDBYT4:	SKIPE	.IODIX(IO)	;IS THIS A RETRY?
	JRST	RDBYT6		;YES
	MOVE	T2,.IODIF(IO)	;GET DAP INPUT HEADER FLAGS
	TFNN	T2,MOR		;ARE THERE MORE SEGMENTS COMING?
	JRST	RDBYT8		;NO, RETURN EMPTY
	SKIPE	.IODIB(IO)	;IF CONTINUED, BETTER NOT BE RANDOM BITS LEFT
	PJRST	RDEID4		;THERE WERE, ERROR IN FIELD
	SKIPG	T2,.IODIM(IO)	;GET CURRENT INPUT MESSAGE TYPE
	STOPCD	<XDBYT but no DAP message in progress>
	MOVEM	T2,.IODIX(IO)	;SAVE AND SET STATE FLAG
RDBYT6:	PUSHJ	P,RDBYU0	;READ IN AND STARTUP A NEW MESSAGE
	 POPJ	P,		;NETWORK DIED
	MOVE	M0,.IODIX(IO)	;GET PREVIOUS MESSAGE TYPE
	SETZM	.IODIX(IO)	;CLEAR CONTINUATION STATE
	CAME	T2,M0		;IS CONTINUED MESSAGE SAME AS BEFORE?
	PJRST	RDEOS		;NO, DAP MESSAGE OUT OF SEQUENCE
	JRST	RDBYT1		;YES, GO BACK AND FINISH READING IT

;HERE WHEN DAP MESSAGE IS EMPTY

RDBYT8:	HRROS	.IODIM(IO)	;NEGATIVE LH TO INDICATE OUT OF DAP MESSAGE
				; (LEAVE CODE IN RH FOR ERROR ROUTINES)
	SETZ	M0,		;RETURN NULL
	POPJ	P,		;EMPTY RETURN


;HELPER TO READ CONTINUATION MESSAGE

RDBYU0:	PUSHJ	P,TSAV14##	;NEED TO PROTECT THE T'S
	PUSHJ	P,RDMSG0	;START UP A NEW DAP MESSAGE
	 POPJ	P,		;NET DIED?
	MOVEM	T2,-T2(P)	;PASS BACK THE NEW MESSAGE TYPE
	JRST	.POPJ1##	;AND RETURN WITH NEW MESSAGE READY TO CONTINUE
;RDBYR  --  RE-READ DAP MESSAGE/DATA BYTE
;CALL IS:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,RDBYR
;	 error return
;	normal return
;
;Where <CDB> is the address of the associated I/O CDB.
;
;RDBYR assumes that a call to RDBYT has been successfully executed,
;leaving a valid 8-bit DAP byte in T2. This byte will be set, and
;returned on the next call to RDBYT.
;
;The error return is not exercised.
;
;On normal return the next call to RDBYT will re-read the just-read
;(i.e., in T2) DAP 8-bit byte.
;
;Uses no acs.

	ENTRY	.RDBYR
	INTERN	RDBYR0,	RDBYR1

.RDBYR:	PUSHJ	P,.SACIO##	;SETUP I/O CONTEXT
RDBYR0:
RDBYR1:	HRROM	T2,.IODIR(IO)	;SAVE CURRENT DAP BYTE
	JRST	.POPJ1##	;SUCCESSFUL RETURN
;RDCLR  --  CLEAR OUT DAP MESSAGE BASE
;CALL IS:
;
;	MOVX	T1,<CDB>
;	MOVX	T2,<MSG>
;	PUSHJ	P,RDCLR
;	 error return
;	normal return
;
;Where <CDB> is the address of the associated I/O CDB; and <MSG> is
;the DAP message type ($DHxxx) whose base area within the .IODAP
;block is to be cleared.
;
;RDCLR zeroes all parameters, fields, values, etc. associated with
;the specified DAP message type contained within the .IODAP block
;within the I/O CDB (for example the attributes fields of the main
;attributes DAP message).
;
;On error return the specified <MSG> is illegal (error code in M0).
;
;On normal return the .IODAP area associated with the message type
;has been zeroed.
;
;Uses T1, T2, T3, T4.

	ENTRY	.RDCLR
	INTERN	RDCLR0,	RDCLR1

.RDCLR:	PUSHJ	P,.SACIO##	;SET UP I/O CONTEXT
RDCLR0:				;WE DON'T USE THE P'S
RDCLR1:	PUSHJ	P,TSAV14##	;PRESERVE THE TEAS (ESPECIALLY T2!)
	MOVEI	T4,DAPIDX	;THE MESSAGE INDEX INTO THE EXECUTION TABLE
	PUSHJ	P,.CFIND##	;LOCATE THE MESSAGE WITHIN THE TEMPLATE
	 STOPCD	<Unknown DAP message in RDCLR>
	LDB	T1,[POINTR DAPXCT(T1),DX$IOX]  ;GET FIRST .IODAP ENTRY
	HLRZ	T2,1(T4)	;GET POINTER TO NEXT MESSAGE TYPE FIRST ENTRY
	SKIPN	T2		;AT END OF TABLE?
	SKIPA	T2,[$DLDAP]	;YES, POINT TO END OF .IODAP AREA
	LDB	T2,[POINTR DAPXCT(T2),DX$IOX]  ;NO, FETCH NEXT FIRST ENTRY
	ADDI	T1,.IODAP(IO)	;RELOCATE TO REAL MEMORY
	SETZM	(T1)		;CLEAR FIRST WORD
	HRL	T1,T1		;CONCOCT A
	ADDI	T1,1		; BLT POINTER
	ADDI	T2,.IODAP(IO)	;RELOCATE LAST WORD TO REAL MEMORY
	BLT	T1,-1(T2)	;CLEAR OUT DAP MESSAGE BASE
	JRST	.POPJ1##	;SUCCESSFUL RETURN
;RDMSG  --  READ IN AND STARTUP ONE DAP MESSAGE
;CALL IS:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,RDMSG
;	 error return
;	normal return
;
;Where <CDB> is the address of the associated I/O CDB.
;
;On error return the network died
;
;On normal return the DAP message code is in T2. Subsequent calls to
;RDBYT will read the rest of the DAP message.
;
;Uses ac T2.

	ENTRY	.RDMSG
	INTERN	RDMSG0,	RDMSG1

.RDMSG:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
RDMSG0:	PUSHJ	P,.SAVE4##	;WE NEED A FEW ACS HERE
RDMSG1:	SKIPLE	.IODIC(IO)	;ANY DAP BYTES STILL OUTSTANDING?
	STOPCD	<RDMSG called before end of current DAP message>
	SKIPE	.IODRS(IO)	;GOT A SAVED (RDREA) MESSAGE?
	JRST	[MOVSI	T3,.IODRS(IO)	;YES,
		HRRI	T3,.IODIM(IO)	;CONCOCT A BLT POINTER
		BLT	T3,.IODIM+.IODRL-1(IO)  ;TO BRING BACK INPUT MESSAGE
		SETZM	.IODRS(IO)	;CLEAR SAVED INPUT STATE
		JRST	RDMSZ]		;AND RETURN "NEW" INPUT MESSAGE
	SETZM	.IODIF(IO)	;RESET HEADER FLAGS
	SETZM	.IODIS(IO)	;RESET STREAM ID FIELD
	SETZM	.IODIB(IO)	;RESET TRAILING UNUSED BITS

;READ IN MESSAGE TYPE

	PUSHJ	P,RNBYT1	;ANY NETWORK BYTES LEFT?
	 CAIA			;APPARENTLY NOT
	JRST	RDMSG2		;YES, T2 HAS MESSAGE TYPE
	JUMPN	M0,.POPJ##	;ERROR RETURN IF NETWORK DIED
	PUSHJ	P,RNMSG0	;READ IN A NEW NETWORK MESSAGE
	 POPJ	P,		;NETWORK DIED
RDMSG2:	HRRZM	T2,.IODIM(IO)	;SET NEW MESSAGE TYPE

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;READ IN DAP MESSAGE HEADER FLAGS

	MOVEI	P3,$DBMHF	;LENGTH OF MESSAGE HEADER FLAGS
	MOVE	P4,[POINT 7,.IODIF(IO)]  ;AND WHERE TO STORE THEM
	SETZ	P1,		;NO BYTE SEEN YET
RDMSG3:	PUSHJ	P,RNBYT0	;READ A NETWORK BYTE
	 JRST	[JUMPN	M0,.POPJ##	;IF ERROR, PASS THE WORD
		MOVE	T2,.IODIF(IO)	;GET HEADER FLAGS SO FAR
		TFZ	T2,MOR		;CLEAR OK FLAG BIT
		TRNN	P1,200		;SHOULD THERE BE ANOTHER BYTE?
		JUMPE	T2,RDMSZ	;MESSAGE OK IF NO FIELDS EXPECTED
		PJRST	RDEID0]		;ELSE ERROR IN FLAGS FIELD
	IDPB	T2,P4		;STASH THIS FLAG BYTE
	MOVE	P1,T2		;SAVE EXTENSIBILITY FLAG
	TRNE	T2,200		;END OF FLAGS?
	SOJG	P3,RDMSG3	;NO, READ REST OF FIELD
	TRNE	T2,200		;REALLY END OF FLAGS?
	PJRST	RDEID0		;NO, FIELD TOO BIG, ERROR
	MOVE	P1,.IODIF(IO)	;PICK UP HEADER FLAGS

;READ STREAM ID FIELD, IF PRESENT

	TFZN	P1,SID		;STREAM ID FIELD PRESENT?
	JRST	RDMSG4		;NO
	PUSHJ	P,RNBYT0	;YES, READ IT IN
	 JRST	[JUMPE	M0,RDEID1	;ERROR IN SID FIELD
		POPJ	P,]		;ERROR IN NETWORK
	MOVEM	T2,.IODIS(IO)	;SET STREAM ID FIELD
	JUMPN	T2,RDEID1	;WE DON'T SUPPORT MULTIPLE SID'S

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;READ IN LENGTH FIELD

RDMSG4:	TFNN	P1,HLN		;HEADER LENGTH FIELD PRESENT?
	JRST	RDMSG5		;NO
	PUSHJ	P,RNBYT0	;YES, READ IT
	 JRST	[JUMPE	M0,RDEID2	;ERROR IN LENGTH FIELD
		POPJ	P,]		;NETWORK DIED
	MOVEM	T2,.IODIC(IO)	;SET LENGTH OF DAP DATA

;READ IN SECOND HALF OF LENGTH FIELD

RDMSG5:	TFNN	P1,HL2		;HIGH-ORDER HEADER LENGTH PRESENT?
	JRST	RDMSG6		;NO
	PUSHJ	P,RNBYT0	;YES, READ IT
	 JRST	[JUMPE	M0,RDEID3	;ERROR IN EXTENDED LENGTH FIELD
		POPJ	P,]		;NETWORK DIED
	DPB	T2,[POINT 8,.IODIC(IO),27]  ;SET HIGH-ORDER BYTE COUNT

RDMSG6:	HRLOI	T2,223344	;DUMMY DAP BYTE COUNT
				; (THIS WILL LEAVE A "223344" IN THE LH, OUR
				;  "INDICATION" THAT THE DAP COUNT IS NOT
				;  REALLY VALID, BUT KEPT POSITIVE JUST TO
				;  KEEP EVERYONE ELSE HAPPY - SEE RDBYT)
	TFZN	P1,<HLN,HL2>	;DAP MESSAGE HEADER CONTAIN ITS LENGTH?
	MOVEM	T2,.IODIC(IO)	;NO, USE DEFAULT

;READ IN TRAILING UNUSED BIT COUNT

	TFZN	P1,BCT		;ANY UNUSED BITS?
	JRST	RDMSG7		;NO
	PUSHJ	P,RNBYT0	;YES, READ THE COUNT
	 JRST	[JUMPE	M0,RDEID4	;ERROR IN UNUSED BIT COUNT
		POPJ	P,]		;NETWORK DIED
	MOVEM	T2,.IODIB(IO)	;SET TRAILING UNUSED BIT COUNT

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;CHECK FOR SYSPEC (SYSTEM-SPECIFIC) FIELD

RDMSG7:	TFZN	P1,SHX		;SYSTEM-SPECIFIC HEADER FIELD?
	JRST	RDMSG8		;NO
	PUSHJ	P,RNBYT0	;YES, GET LENGTH OF FOLLOWING IMAGE FIELD
	 JRST	[JUMPE	M0,RDEID5	;ERROR IN SYSPEC FIELD
		POPJ	P,]		;NETWORK DIED
	SKIPG	T4,T2		;COUNT OF IMAGE BYTES FOLLOWING
	JRST	RDMSG8		;NONE, ALL DONE HERE
	PUSHJ	P,RNBYT0	;GET NEXT SYSPEC IMAGE BYTE
	 JRST	[JUMPE	M0,RDEID5	;ERROR IS SYSPEC FIELD
		POPJ	P,]		;NETWORK DIED
	SOJG	T4,.-2		;EAT THE WHOLE SILLY THING

;NOW SEE IF THERE IS ANYTHING LEFT OVER

RDMSG8:	TFZ	P1,MOR		;CLEAR OK BIT
	JUMPN	P1,RDEID0	;ANYTHING LEFT OVER IS AN ERROR

;NOW VERIFY THAT ALL THE FIELDS FIT TOGETHER

RDMSZ:	MOVE	T3,.IODIC(IO)	;GET INPUT BYTE COUNT
	MOVEM	T3,.IODRC(IO)	;AND SET IN CASE .RDREA IS CALLED
	HRRZ	T2,.IODIM(IO)	;RETURN NEW CURRENT INPUT MESSAGE TYPE
	JRST	.POPJ1##	;SUCCESSFUL RETURN
;RDMSR  --  RE-READ THE CURRENT DAP MESSAGE
;CALL IS:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,RDMSR
;	 error return
;	normal return
;
;Where <CDB> is the address of the associated I/O CDB.
;
;RDMSR assumes that a DAP message has just been started (i.e., RDMSG
;has been called, T2 has the current DAP message code, and no DAP
;data bytes have been read, which is to say neither RDDAP nor RDBYT
;have been called). RDMSR will "undo" the current message such that
;the next call to RDMSG will re-read it.
;
;On error return either a message was not in progress, or had been
;already partially read.
;
;On normal return the current DAP message will be readable via the
;next call to RDMSG.
;
;Uses T1, T2, T3, T4.

	ENTRY	.RDMSR
	INTERN	RDMSR0,	RDMSR1

.RDMSR:	PUSHJ	P,.SACIO##	;SETUP I/O CONTEXT
RDMSR0:
RDMSR1:	MOVE	T3,.IODRC(IO)	;GET SAVED INITIAL DAP BYTE COUNT
	CAME	T3,.IODIC(IO)	;WON'T HAVE CHANGED UNLESS RDBYT CALLED
	STOPCD	<RDMSR not called immediately after RDMSG>
	MOVSI	T3,.IODIM(IO)	;START OF DAP INPUT MESSAGE STUFF
	HRRI	T3,.IODRS(IO)	;WHERE TO SAVE IT
	BLT	T3,.IODRS+.IODRL-1(IO)  ;SAVE INPUT MESSAGE CONTEXT
	SETZM	.IODIM(IO)	;CLEAR START OF INPUT MESSAGE CONTEXT
	MOVSI	T3,.IODIM(IO)	;CONCOCT
	HRRI	T3,.IODIM+1(IO)	; A BLT POINTER TO
	BLT	T3,.IODIM+.IODRL-1(IO)  ;CLEAR CURRENT INPUT MESSAGE CONTEXT
	JRST	.POPJ1##	;READY TO CALL .RDMSG AGAIN
;ERRORS READING DAP FIELDS

;ERROR IN DAP MESSAGE HEADER FLAGS

RDEID0:	STOPCD	<Error in received DAP message header flags>


;ERROR IN DAP MESSAGE HEADER STREAM ID FIELD

RDEID1:	STOPCD	<Error in received DAP message header stream ID field>


;ERROR IN DAP MESSAGE HEADER LENGTH FIELD

RDEID2:	STOPCD	<Error in received DAP message header length field>


;ERROR IN DAP MESSAGE HEADER LEN256 (EXTENDED LENGTH) FIELD

RDEID3:	STOPCD	<Error in received DAP message header length-256 field>


;ERROR IN DAP MESSAGE HEADER BITCNT FIELD

RDEID4:	STOPCD	<Error in received DAP message header trailing bit count field>


;ERROR ID DAP MESSAGE HEADER SYSPEC FIELD

RDEID5:	STOPCD	<Error in received DAP message header SYSPEC field>


;DAP MESSAGE OUT OF SEQUENCE

.RDEOS::
RDEOS:	STOPCD	<DAP message received out of sequence>
;XDACK  --  SEND ACKNOWLEDGE MESSAGE
;CALL IS:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,XDACK
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O CDB.
;
;On error return the network aborted.
;
;On successful return an ACKNOWLEDGE message has been built and is
;ready to be shipped to the remote.
;
;	THE CALLER MUST CALL XDFLS TO FORCE TRANSMISSION OF THE ACK
;
;Historically, before DAP %6.0, any ACK implied a line turnaround.
;With version 6 the DELETE/EXECUTE/RENAME functions can block multiple
;NAME/ATTRIBUTES/ACK sequences together, so XDACK doesn't flush the
;output automatically.
;
;Uses T1 - T4.

	ENTRY	.XDACK
	INTERN	XDACK0,	XDACK1

.XDACK:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XDACK0:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
XDACK1:	MOVEI	T2,$DHACK	;ACKNOWLEDGE MESSAGE CODE
	PUSHJ	P,XDMSG1	;START UP A NEW DAP MESSAGE
	 JRST	XDACK9		;CAN'T, GO CHECK IT OUT
	PUSHJ	P,XDEOM1	;CAP OFF THE DAP ACKNOWLEDGE MESSAGE
	 POPJ	P,		;OOPS
	JRST	.POPJ1##	;SUCCESSFUL RETURN

XDACK9:	CAIE	M0,$ECTRA	;SHOULD WE TRY AGAIN?
	POPJ	P,		;NO, FATAL ERROR
	JRST	XDACK1		;YES
;XDACL  --  SEND SHORT-FORM ACCESS COMPLETE (CLOSE) MESSAGE
;XDAKL  --  SEND SHORT-FORM ACCESS COMPLETE (KILL) MESSAGE
;XDARS  --  SEND SHORT-FORM ACCESS COMPLETE (RESPONSE) MESSAGE
;XDASK  --  SEND SHORT-FORM ACCESS COMPLETE (SKIP) MESSAGE
;CALL IS:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,XDACL/AKL/ARS/ASK
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O CDB.
;
;On error return the network aborted.
;
;On successful return an ACCOMP(xxx) message has been shipped to the
;remote file service. This access complete message will have only the
;A2F field set - neither the access options nor the file data checksum
;fields will be sent.
;
;Uses T1 - T4.

;ACCOMP(CLOSE)

	ENTRY	.XDACL
	INTERN	XDACL0,	XDACL1

.XDACL:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XDACL0:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
XDACL1:	MOVEI	T2,$DVACL	;"CLOSE" FUNCTION (NORMAL COMPLETION)
	PJRST	XDA2F1		;CAP OFF SHORT-FORM ACCOMP(CLOSE)



;ACCOMP(KILL)

	ENTRY	.XDAKL
	INTERN	XDAKL0,	XDAKL1

.XDAKL:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XDAKL0:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
XDAKL1:	MOVEI	T2,$DVAKL	;"KILL/RESET" FUNCTION
	PJRST	XDA2F1		;CAP OFF SHORT-FORM ACCOMP(KILL)
;ACCOMP(RESPONSE)

	ENTRY	.XDARS
	INTERN	XDARS0,	XDARS1

.XDARS:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XDARS0:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
XDARS1:	MOVEI	T2,$DVARS	;"RESPONSE" FUNCTION
	PJRST	XDA2F1		;SHIP THE ACCOMP(RESPONSE)



;ACCOMP(SKIP)

	ENTRY	.XDASK
	INTERN	XDASK0,	XDASK1

.XDASK:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XDASK0:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
XDASK1:	MOVEI	T2,$DVASK	;"SKIP" FUNCTION
	PJRST	XDA2F1		;CAP OFF SHORT-FORM ACCOMP(SKIP)



;MAIN BODY OF SHORT-FORM ACCOMP(XXX)

XDA2F1:	MOVD1M	T2,A2F		;SET ACCOMP FUNCTION CODE
	MOVDII	T2,M07,A2F	;FLAG ONLY THE FUNCTION FIELD
	MOVDM	T2,M07		;IN THE ACCOMP "HIDDEN" MENU
	MOVEI	T2,$DHACM	;ACCESS COMPLETE MESSAGE CODE
	PUSHJ	P,XDDAP1	;PACKAGE THE ACCOMP MESSAGE
	 POPJ	P,		;ERROR
	PJRST	XDFLS1		;AND FORCE IT OUT INTO THE COLD CRUEL WORLD
;XDCAB  --  SEND CONTINUE (ABORT) MESSAGE
;XDCRS  --  SEND CONTINUE (RESUME) MESSAGE
;XDCTA  --  SEND CONTINUE (TRY AGAIN) MESSAGE
;XDCSK  --  SEND CONTINUE (SKIP AND CONTINUE) MESSAGE
;CALL IS:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,XDCTA/CRS/CTA/CSK
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O CDB.
;
;On error return the network aborted.
;
;On successful return a CONTINUE(xxx) message has been shipped to the
;remote file service.
;
;Uses T1 - T4.

;CONTINUE(ABORT)

	ENTRY	.XDCAB
	INTERN	XDCAB0,	XDCAB1

.XDCAB:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XDCAB0:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
XDCAB1:	MOVEI	T2,$DVCAB	;"ABORT" FUNCTION
	PJRST	XDC2F1		;SKIP A CONTINUE(ABORT) MESSAGE



;CONTINUE(RESUME)

	ENTRY	.XDCRS
	INTERN	XDCRS0,	XDCRS1

.XDCRS:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XDCRS0:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
XDCRS1:	MOVEI	T2,$DVCRS	;"RESUME" FUNCTION
	PJRST	XDC2F1		;SHIP OFF THE CONTINUE(RESUME) MESSAGE
;CONTINUE(TRY AGAIN)

	ENTRY	.XDCTA
	INTERN	XDCTA0,	XDCTA1

.XDCTA:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XDCTA0:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
XDCTA1:	MOVEI	T2,$DVCTA	;"TRY AGAIN" FUNCTION
	PJRST	XDC2F1		;PACKAGE AND SHIP A CONTINUE(TRY AGAIN)



;CONTINUE(SKIP)

	ENTRY	.XDCSK
	INTERN	XDCSK0,	XDCSK1

.XDCSK:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XDCSK0:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
XDCSK1:	MOVEI	T2,$DVCSK	;"SKIP AND CONTINUE" FUNCTION
	PJRST	XDC2F1		;SHIP A CONTINUE(SKIP) MESSAGE



;COMMON CONTINUE(XXX)

XDC2F1:	MOVD1M	T2,C2F		;SAVE THE "CONTINUE" FUNCTION
	MOVDII	T2,M05,C2F	;MENU FIELD: FUNCTION ONLY
	MOVDM	T2,M05		;SET CONTINUE "HIDDEN" MENU
	MOVEI	T2,$DHCNT	;DAP CONTINUE MESSAGE CODE
	PUSHJ	P,XDDAP1	;PACKAGE THE CONTINUE MESSAGE
	 POPJ	P,		;SOMETHING BROKE
	PJRST	XDFLS1		;AND FORCE IT OUT NOW
;XDEOF  --  SEND "END OF FILE" STATUS MESSAGE
;CALL IS:
;
;	PUSHJ	P,XDEOF
;	 error return
;	normal return
;
;On error return the network aborted
;
;On normal return a DAP STATUS "EOF" has been packaged and transmitted to
;the remote. This status message contains only the status code, no other
;fields are transmitted.
;
;Uses T1 - T4.

	ENTRY	.XDEOF
	INTERN	XDEOF0,	XDEOF1

.XDEOF:	PUSHJ	P,.SACIO##	;SETUP I/O CONTEXT
XDEOF0:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
XDEOF1:	MOVEI	T2,50000+$DSEOF	;DAP "EOF" STATUS CODE
	MOVD1M	T2,STC		;SET STATUS CODE
	MOVDII	T2,M09,STC	;FLAG ONLY THE STATUS CODE IN THE MENU
	MOVDM	T2,M09		;AND SET THE "HIDDEN" MENU FIELD
	MOVEI	T2,$DHSTS	;DAP STATUS MESSAGE TYPE
	PJRST	XDDAP1		;OFF TO THE GENERAL DAP MESSAGE SENDER
;XDDAT  --  START UP A DATA MESSAGE
;Call is:
;
;	MOVX	T1,<CDB>
;	MOVX	T2/T3,<RECN>
;	PUSHJ	P,XDDAT
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O CDB; and <RECN> is the
;64-bit double-precision integer record number to use in the DATA message.
;
;On error return the network died.
;
;On normal return a data message (code = $DHDAT) has been started
;and may be filled via calls to XDBYT.
;
;Uses T1 - T4

	ENTRY	.XDDAT
	INTERN	XDDAT0,	XDDAT1

.XDDAT:	PUSHJ	P,.SACIO##	;SET UP I/O CDB INDEX
XDDAT0:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
XDDAT1:	MOVDM	T2,RCN		;SET OUTPUT RECORD NUMBER TEMPLATE
	MOVEI	T2,$DHDAT	;DATA MESSAGE CODE
	PUSHJ	P,XDDAP2	;START UP A DATA MESSAGE
	 POPJ	P,		;ERROR
	JRST	.POPJ1##	;READY FOR DATA BYTES
;XDDAP  --  BUILD AND SEND A GENERIC DAP MESSAGE
;Call is:
;
;	MOVX	T1,<CDB>
;	MOVX	T2,<code>
;	PUSHJ	P,XDDAP
;	 error return
;	normal return
;
;Where  <CDB> is the address of the I/O CDB; <code> is the DAP message
;code for the message to be sent. Data messages (<code> = $DHDAT)
;are illegal.
;
;On error return either the network died (M0 has the error code) or
;an input message has been received and needs to be processed (in which
;case no data has been sent - the XDDAP call must be re-executed in
;order to send the desired DAP message).
;
;On normal return the DAP message has been built and is in the network
;output buffer (a call to XDFLS must be executed if the message must
;be guaranteed transmitted - otherwise the message may be kept in the
;network buffer in order to "piggyback" multiple DAP messages into one
;physical network transmission message).
;
;Uses T1, T2, T3, T4

	ENTRY	.XDDAP
	INTERN	XDDAP0,	XDDAP1

.XDDAP:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XDDAP0:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
XDDAP1:	PUSHJ	P,TSAV12##	;SAVE T1 AND T2
	CAIN	T2,$DHDAT	;DATA MESSAGE?
	STOPCD	<XDDAP called for DATA message>
XDDAP2:	MOVEI	T4,DAPIDX	;INDEX TABLE
	PUSHJ	P,.CFIND##	;FIND STARTING INDEX INTO EXECUTION TABLE
	 STOPCD	<XDDAP called with unknown DAP message>
	HRRZM	T1,.IODXX(IO)	;SET XDDAP EXECUTION TABLE INDEX
	PUSHJ	P,XDMSG1	;START A NEW DAP MESSAGE
	 JRST	XDDAP9		;CAN'T, CHECK IT OUT

;LOOP BUILDING FIELDS IN THE DAP OUTPUT MESSAGE

XDDAP4:	AOS	P1,.IODXX(IO)	;NEXT MESSAGE FIELD
	MOVE	T1,DAPXCT(P1)	;FETCH COPY OF EXECUTION TABLE ENTRY
	LDB	T3,[POINTR T1,DX$TYP]  ;FIELD "TYPE"
	CAILE	T3,$DXTMX	;WITHIN OUR LIMITS?
	STOPCD	<DX$TYP field type too big in XDDAP>
	JUMPE	T3,XDDAP7	;EXIT IF END OF MESSAGE TEMPLATE
		.XCREF	$DXTMS	;CREF REFERENCE TO SYMBOLIC NAME

;DISPATCH TO FIELD HANDLER WITH P1/INDEX AND T1/DAPXCT TABLE ENTRY

	TXNE	T1,DX$ILM!DX$SKP;A FIELD THAT WE SHOULD IGNORE?
	JRST	[CAIN	T3,$DXTMN	;YES - EXCEPT THAT
		JRST	.+1		;MENUS REQUIRE SPECIAL ATTENTION
		JRST	XDDAP4]		;JUST SKIP THIS DAP FIELD
	PUSHJ	P,@XDDAPX(T3)	;DISPATCH ON FIELD TYPE
	 JRST	XDDAP9		;POSSIBLE ERROR SOMEWHERE
	JRST	XDDAP4		;ADVANCE TO NEXT FIELD

;HERE WHEN DAP OUTPUT MESSAGE COMPLETED

XDDAP7:	MOVE	T2,.IODOM(IO)	;GET MESSAGE CODE
	CAIN	T2,$DHDAT	;IS IT A DATA MESSAGE?
	JRST	.POPJ1##	;YES, THEN MORE STILL TO COME
	PJRST	XDEOM1		;NO, CAP OFF THE OUTPUT MESSAGE.

;HERE WHEN WE COULDN'T COMPLETE THE OUTPUT MESSAGE

XDDAP9:	CAIE	M0,$ECTRA	;SHOULD WE TRY AGAIN?
	POPJ	P,		;NO, HIGHER-UP'S INTERVENTION REQUIRED
	MOVE	T2,-T2(P)	;YES, FETCH MESSAGE CODE BACK
				; EVEN THOUGH IT MIGHT SEEM LIKE AN ERROR
				; TO DO THIS IF ENTERED AT XDMSG2 FROM XDDAT,
				; $ECTRA SHOULD NEVER HAPPEN FOR DATA SINCE
				; DATA MESSAGES ONLY NEED A FEW BYTES TO
				; GET STARTED, WHICH THEY ARE GUARANTEED
				; IF XDMSG RETURNS SUCCESSFULLY . . .
	JRST	XDDAP2		;TRY AGAIN

;DAP MESSAGE FIELD PROCESSOR DISPATCH TABLE

;EACH FIELD PROCESSING ROUTINE IS ENTERED WITH:
;	T1/DAPXCT TABLE ENTRY FOR THE FIELD
;	P1/DAPXCT TABLE INDEX FOR THE FIELD
;ACS T1 - T4, AND P1 - P4 ARE AVAILABLE FOR USAGE WITHIN THE VARIOUS
;FIELD PROCESSING ROUTINES

XDDAPX:	XD00T			;00 - START OF DAP MESSAGE TEMPLATE
	XD01T			;01 - ASCII TEXT
	XD02T			;02 - BINARY [INTEGER] DATA
	XD03T			;03 - COMPRESSED (1 WORD/5 BYTES) BINARY
	XD04T			;04 - FLAGS (BIT MAP)
	XD05T			;05 - IMAGE 8-BIT BYTES
	XD06T			;06 - MENU FIELD
	XD07T			;07 - DATE/TIME FIELD
;XD00T  -  START OF NEW DAP MESSAGE TEMPLATE

XD00T:	STOPCD	<XD00T dispatch in XDDAP>
;XD01T  -  ASCII TEXT FIELD

XD01T:	MOVE	P2,T1		;PROTECT COPY OF EXECUTION TABLE ENTRY
	LDB	T3,[POINTR T1,DX$LNB]  ;FIELD LENGTH (DAP BYTES)
	LDB	T4,[POINTR T1,DX$IOX]  ;DAP AREA OFFSET
	ADD	T4,[POINT 7,.IODAP(IO)];MAKE INTO BYTE POINTER
	TXNE	T1,DX$XTN	;EXTENSIBLE ASCII?
	JRST	XD01T5		;YES
	TXNN	T1,DX$VAR	;VARIABLE LENGTH ASCII?
	JRST	XD01T3		;NO, FIXED LENGTH
	PUSHJ	P,XDBYT0	;YES, ALLOCATE COUNT BYTE
	 POPJ	P,		;OOPS
	MOVE	T1,.IONOP(IO)	;REMEMBER POINTER TO THE COUNT BYTE
	JRST	XD01T3		;ENTER BYTE LOOP

;LOOP SENDING FIXED/VARIABLE ASCII OUTPUT FIELD

XD01T2:	SOJL	T3,XD01T9	;FIELD SIZE OK?
	PUSHJ	P,XDBYT0	;YES, STUFF THIS ASCII CHARACTER
	 POPJ	P,		;OOPS
XD01T3:	ILDB	T2,T4		;GET ANOTHER POSSIBLE ASCII CHARACTER
	JUMPN	T2,XD01T2	;STORE IF NOT YET END OF STRING
	LDB	T2,[POINTR P2,DX$LNB]  ;LENGTH (MAXIMUM) OF FIELD
	SUB	T2,T3		;T2:=ACTUAL FIELD LENGTH
	TXNE	P2,DX$VAR	;VARIABLE LENGTH FIELD?
	DPB	T2,T1		;YES, SET COUNT BYTE
	TXNE	P2,DX$VAR	;FIXED LENGTH FIELD?
	JRST	.POPJ1##	;NO, ALL DONE HERE
	JUMPE	T3,.POPJ1##	;YES, FIELD STILL LEFT?
	SETZ	T2,		;YES, NULL-FILL REMAINDER OF FIELD
	PUSHJ	P,XDBYT1	;FILL WITH ANOTHER NULL
	 POPJ	P,		;OOPS
	SOJG	T3,.-2		;LOOP FOR REST OF FIELD
	JRST	.POPJ1##	;SUCCESSFUL RETURN
;LOOP SENDING EXTENSIBLE ASCII OUTPUT

XD01T5:	ILDB	T2,T4		;FIRST CHARACTER
	JUMPN	T2,XD01T7	;OK IF NON-NULL STRING
	PUSHJ	P,XDBYT1	;NULL STRING, FILL OUT THE FIELD
	 POPJ	P,		;OOPS
	JRST	.POPJ1##	;THAT'S ALL HERE

XD01T7:	SOJL	T3,XD01T9	;MAKE SURE STILL ROOM
	TRO	T2,200		;MAKE EXTENSIBLE BYTE
	PUSHJ	P,XDBYT1	;AND PUT IN OUTPUT MESSAGE
	 POPJ	P,		;OOPS
	ILDB	T2,T4		;NEXT BYTE
	JUMPN	T2,XD01T7	;LOOP WHILE STRING LASTS
	LDB	T2,.IONOP(IO)	;RE-FETCH LAST CHARACTER
	TRZ	T2,200		;MARK END OF EXTENSIBLE STRING
	DPB	T2,.IONOP(IO)	;RE-STORE LAST CHARACTER OF FIELD
	JRST	.POPJ1##	;SUCCESSFUL RETURN

;STRING FIELD SIZE EXCEEDED

XD01T9:	STOPCD	<ASCII string too long for DAP field in XD01T>
;XD02T  -  BINARY DATA FIELD
;XD03T  -  COMPRESSED BINARY DATA

XD02T:				;THEY'RE THE SAME (ALMOST)
XD03T:	MOVE	P2,T1		;SAVE A COPY OF THE EXECUTION TABLE ENTRY
	LDB	P3,[POINTR P2,DX$LNB]  ;FIELD LENGTH (DAP BYTES)
	CAILE	P3,^D9		;WILL IT FIT OUR ALGORITHM?
	STOPCD	<Binary DAP field larger than 9 bytes in XD03T>
	LDB	T1,[POINTR P2,DX$LNB]  ;SIZE OF FIELD IN 8-BIT BYTES
	CAIG	T1,4		;MORE THAN ONE -10 WORDS' WORTH?
	MOVEI	T1,1		;NO, ONE WORD IS SUFFICIENT
	CAILE	T1,4		;LESS THAN TWO -10 WORDS' WORTH?
	MOVEI	T1,2		;NO, TWO WORDS NEEDED
	LDB	T4,[POINTR P2,DX$TYP]  ;FIELD TYPE
	CAIN	T4,$DXTCN	;COMPRESSED 1 WORD VALUE?
	MOVEI	T1,1		;YES, SIZE IS ONE WORD THEN
	LDB	T2,[POINTR P2,DX$IOX]  ;DAP AREA OFFSET
	ADDI	T2,.IODAP(IO)	;RELOCATE ADDRESS
	SETZ	T3,		;ASSUME ONLY ONE-WORD VALUE
	CAIN	T1,1		;ONE-WORD FIELD?
	MOVE	T4,(T2)		;YES
	CAIN	T1,2		;TWO-WORD FIELD?
	DMOVE	T3,(T2)		;YES
	LSH	T4,1		;POSITION AND
	LSHC	T3,-1		;CONCATENATE TWO HALVES
	TXNE	P2,DX$XTN	;EXTENSIBLE BINARY?
	JRST	XD03T5		;YES
	TXNN	P2,DX$VAR	;NO, VARIABLE-LENGTH BINARY?
	JRST	XD03T3		;NO, FIXED-LENGTH FIELD
	PUSHJ	P,XDBYT0	;YES, ALLOCATE COUNT BYTE
	 POPJ	P,		;OOPS
	MOVE	P4,.IONOP(IO)	;REMEMBER WHERE COUNT BYTE IS
	JRST	XD03T3		;ENTER LOOP
;LOOP SENDING FIXED/VARIABLE BINARY FIELD

XD03T2:	ROTC	T3,-^D8		;POSITION NEXT LEAST SIGNIFICANT BYTE
	LSHC	T2,^D8		;AND PUT THE BYTE IN T2
	LSH	T3,-^D8		;CORRECT T3
	SOJL	P3,XD03T9	;MAKE SURE STILL FITS
	PUSHJ	P,XDBYT0	;STUFF AWAY THIS BYTE
	 POPJ	P,		;OOPS
XD03T3:	JUMPN	T3,XD03T2	;LOOP FOR ALL OF FIELD
	JUMPN	T4,XD03T2	; (ALL TWO WORDS' WORTH)
	LDB	T2,[POINTR P2,DX$LNB]  ;FIELD LENGTH (DAP BYTES)
	SUB	T2,P3		;ACTUAL FIELD LENGTH
	TXNE	P2,DX$VAR	;VARIABLE-LENGTH FIELD?
	DPB	T2,P4		;YES, SET BYTE COUNT
	TXNE	P2,DX$VAR	;FIXED-LENGTH FIELD?
	JRST	.POPJ1##	;NO, ALL DONE
	JUMPLE	P3,.POPJ1##	;YES, FIELD FULL?
	SETZ	T2,		;NO, NEED NULL-FILL
	PUSHJ	P,XDBYT0	;FILL REST OF FIELD
	 POPJ	P,		;OOPS
	SOJG	P3,.-2		;LOOP FOR REST OF FIELD
	JRST	.POPJ1##	;ALL DONE

;LOOP FOR EXTENSIBLE BINARY FIELD

XD03T5:	STOPCD	<Extensible DAP binary field encountered in XD03T>

;BINARY FIELD TOO LARGE

XD03T9:	STOPCD	<Binary value exceeded DAP binary field size in XD03T>
;XD04T  -  SEND FLAGS (BIT MAP) FIELD

XD04T:	LDB	T3,[POINTR T1,DX$LNB]  ;FIELD LENGTH (DAP BYTES)
	LDB	T4,[POINTR T1,DX$IOX]  ;DAP AREA OFFSET
	ADD	T4,[POINT 7,.IODAP(IO)];MAKE INTO BYTE POINTER
	TXNE	T1,DX$XTN	;EXTENSIBLE FIELD?
	JRST	XD04T5		;YES
	STOPCD	<Fixed/variable length DAP flags field encountered in XD04T>

;LOOP SENDING EXTENSIBLE FLAGS FIELD

XD04T5:	ILDB	T2,T4		;FIRST FLAG BYTE
	TROA	T2,200		;GUARANTEE AT LEAST ONE BYTE
XD04T6:	ILDB	T2,T4		;NEXT FLAG BYTE
	JUMPE	T2,XD04T9	;SEE IF TRAILING NULL
XD04T7:	TRO	T2,200		;SET EXTENSIBLE BIT
	PUSHJ	P,XDBYT1	;PUT INTO OUTPUT MESSAGE
	 POPJ	P,		;OOPS
	SOJG	T3,XD04T6	;LOOP FOR REST OF FIELD
XD04T8:	LDB	T2,.IONOP(IO)	;RE-FETCH LAST BYTE
	TRZ	T2,200		;CLEAR EXTENSIBLE BIT
	DPB	T2,.IONOP(IO)	;RE-STORE LAST BYTE OF EXTENSIBLE FIELD
	JRST	.POPJ1##	;SUCCESSFUL RETURN

XD04T9:	MOVE	T1,T3		;SAVE BYTE COUNT
	SOJLE	T3,XD04T8	;COUNT DOWN TRAILING NULLS
	ILDB	T2,T4		;FETCH NEXT BYTE'S WORTH OF FLAGS
	JUMPE	T2,.-2		;COMPRESS OUT NULLS
	SUB	T1,T3		;NON-NULL FLAG,
	MOVEI	T2,200		;EXTENSIBLE NULL BYTE
	PUSHJ	P,XDBYT1	;FILL OUT NULL BYTES
	 POPJ	P,		;OOPS
	SOJG	T1,.-2		;LOOP FOR EMBEDDED NULLS
	LDB	T2,T4		;RE-FETCH NON-NULL FLAG BYTE
	JRST	XD04T7		;AND SEND IT OUT
;XD05T  -  IMAGE 8-BIT BYTES

XD05T:	LDB	T3,[POINTR T1,DX$LNB]  ;FIELD LENGTH
	LDB	T4,[POINTR T1,DX$IOX]  ;DAP AREA OFFSET
	ADD	T4,[POINT 8,.IODAP(IO)];MAKE INTO BYTE POINTER
	TXNE	T1,DX$XTN	;EXTENSIBLE IMAGE?
	JRST	XD05T5		;YES
	TXNN	T1,DX$VAR	;NO, VARIABLE-LENGTH IMAGE FIELD?
	JRST	XD05T2		;NO, FIXED-LENGTH
	MOVE	T2,T3		;VARIABLE-LENGTH, GET SIZE OF FIELD
	PUSHJ	P,XDBYT1	;ALLOCATE BYTE COUNT BYTE
	 POPJ	P,		;OOPS

;LOOP SENDING ENTIRE IMAGE FIELD (FOR NOW AT LEAST)

XD05T2:	ILDB	T2,T4		;NEXT IMAGE BYTE
	PUSHJ	P,XDBYT1	;STUFF INTO MESSAGE
	 POPJ	P,		;OOPS
	SOJG	T3,XD05T2	;LOOP FOR REST OF MESSAGE FIELD
	JRST	.POPJ1##	;SUCCESSFUL RETURN

;LOOP SENDING EXTENSIBLE IMAGE FIELD

XD05T5:	STOPCD	<Extensible DAP image field encountered in XD05T>
;XD06T  -  MENU FIELD

XD06T:	TXNE	T1,DX$SKP	;"INVISIBLE" MENU?
	JRST	XD06T1		;YES, DON'T TRANSMIT IT, BUT STILL PROCESS IT
	PUSHJ	P,XD04T		;SEND MENU AS FLAGS
	 POPJ	P,		;OOPS
XD06T1:	MOVE	P1,.IODXX(IO)	;RESTORE DAPXCT INDEX (JUST TO BE SURE)
	LDB	T3,[POINTR DAPXCT(P1),DX$LNB]  ;FIELD LENGTH (DAP BYTES)
	LDB	T4,[POINTR DAPXCT(P1),DX$IOX]  ;FIELD OFFSET WITHIN DAP AREA
	ADD	T4,[POINT 7,.IODAP(IO)]  ;MAKE INTO BYTE POINTER
	DMOVEM	T3,.IODXM(IO)	;SET DAP MENU COUNTER/POINTER

;LOOP BUILDING REST OF MESSAGE AS DESCRIBED BY THE MENU

XD06M1:	ILDB	P2,.IODXM+1(IO)	;GET A MENU BYTE
	TROA	P2,200		;FORCE 7-BITS-WORTH OF LOOP

;LOOP WITHIN 7-BIT MENU BYTE

XD06M2:	LSH	P2,-1		;NEXT MENU BIT
	AOS	P1,.IODXX(IO)	;CORRESPONDING EXECUTION TABLE INDEX
	TRZN	P2,1		;THIS FIELD WANT TO BE SENT?
	JUMPN	P2,XD06M5	;NO, SEE IF ANYTHING MORE
	JUMPE	P2,XD06M7	;YES - UNLESS FAKE BIT ("TROA" ABOVE)

;BUILD MENU-SPECIFIED FIELD AND PUT IT IN THE OUTPUT MESSAGE

	MOVE	T1,DAPXCT(P1)	;EXECUTION TABLE ENTRY FOR THIS FIELD
	LDB	T3,[POINTR T1,DX$TYP]  ;FIELD "TYPE"
	CAILE	T3,$DXTMX	;ONE WE KNOW ABOUT?
	STOPCD	<DX$TYP field too large in XD06M>
	CAIE	T3,$DXTMS	;YES, START OF MESSAGE?
	CAIN	T3,$DXTMN	;OR MENU?
	STOPCD	<SOM or MENU field encountered within menu in XD06M>
	PUSH	P,P2		;SAVE P2
	PUSHJ	P,@XDDAPX(T3)	;OK MESSAGE TYPE, BUILD THE FIELD
	 JRST	[POP	P,P2		;ERROR, ADJUST STACK
		POPJ	P,]		;PROPAGATE THE ERROR
	POP	P,P2		;RESTORE MENU BYTE
XD06M5:	LDB	T3,[POINTR DAPXCT+1(P1),DX$TYP]  ;PEEK AT NEXT FIELD TYPE
	CAIE	T3,$DXTMS	;END OF CURRENT MESSAGE TEMPLATE?
	JRST	XD06M2		;NO, MORE FIELDS TO TRY
	MOVE	T1,P2		;YES, WHAT'S LEFT OF CURRENT MENU BYTE
	JFFO	T1,.+1		;FIND THE FIRST BIT SET
	LSH	T1,1(T2)	;AND TOSS IT OUT ("TROA" ABOVE)
	JUMPN	T1,XD06M9	;IF ANY BITS SET THEN ERROR
	ILDB	T1,.IODXM+1(IO)	;NEXT MENU BYTE
	SOSLE	.IODXM+0(IO)	;MAKE SURE IT'S OK (BLANK) TOO
	JRST	.-3		; . . .
	JRST	.POPJ1##	;SUCCESSFUL RETURN

XD06M7:	SOS	.IODXX(IO)	;THE "TROA" BIT DOESN'T COUNT AGAINST INDEX
	SOSLE	.IODXM+0(IO)	;COUNT DOWN MENU BYTES
	JRST	XD06M1		;AND PROCESS THE NEXT ONE
XD06M9:	STOPCD	<Too many menu bits/bytes in XD06M>
;XD07T  -  SEND DATE/TIME FIELD

XD07T:	LDB	P3,[POINTR T1,DX$LNB]  ;DAP FIELD LENGTH
	LDB	P4,[POINTR T1,DX$IOX]  ;DAP AREA OFFSET
	ADDI	P4,.IODAP(IO)	;P4:=ADDRESS OF DATE/TIME WORD
	XMOVEI	T1,XD07TO	;HELPER TYPEOUT
	PUSHJ	P,.XTYPO##	;SET OUTPUT ROUTINE
	SKIPE	T1,(P4)		;GET THE DATE/TIME WORD
	TLNN	T1,700000	;DOES IT LOOK REASONABLE?
	STOPCD	<Null/Archaic universal date/time value in XD07T>
	MOVE	P4,[POINT 7,.IODTM(IO)]  ;POINTER TO HOLDING AREA
	MOVEM	P4,.IOXTO(IO)	;SET OUTPUT STUFFER
	PUSHJ	P,.TDTTM##	;TYPE OUT DATE/TIME
	SETZ	T1,		;NULL
	IDPB	T1,.IOXTO(IO)	;ASCIZIZE THE STRING

;NOW CAN SAFELY SEND THE ASCIZ STRING (AND GET BLOCKED IF NEEDED)

	SKIPA	P2,[":"]	;MARK DATE/TIME TRANSITION
XD07T4:	CAIE	T2,0		;IF STRING TERMINATED LEAVE TRAILING NULLS
	ILDB	T2,P4		;GET NEXT ASCII CHARACTER
	CAME	T2,P2		;DATE/TIME TRANSITION?
	JRST	XD07T5		;NO, TAKE CHARACTER VERBATIM
	MOVEI	T2," "		;YES, DAP WANTS A SPACE HERE
	SETO	P2,		;ONLY ONE TRANSITION
XD07T5:	PUSHJ	P,XDBYT0	;SEND THIS DATE/TIME CHARACTER
	 POPJ	P,		;OOPS
	SOJG	P3,XD07T4	;LOOP FOR ENTIRE FIELD'S WORTH

	JRST	.POPJ1##	;SUCCESS RETURN


;SLAVE HELPER CALLED BY SCAN WITH T1/ASCII CHARACTER

XD07TO:	CAIL	T1,"a"		;LOWER-CASE LETTER?
	CAILE	T1,"z"		; (I.E., FROM MONTH)
	CAIA			;NO
	XORI	T1,"a"-"A"	;YES, SHIFT TO UPPER CASE
	IDPB	T1,.IOXTO(IO)	;STASH THIS CHARACTER
	POPJ	P,		;RETURN TO WHENCE-EVER
;XDBYC  --  OUTPUT ONE DAP FILE-DATA-LEVEL BYTE, HANDLING CRC
;Call is:
;
;	MOVX	T1,<CDB>
;	MOVX	T2,<byte>
;	PUSHJ	P,XDBYC
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O CDB; <byte> is the 8-bit DAP
;file data byte to be sent (eventually) to the remote DAP receiver.
;
;On error return T1 and T2 are preserved. The error or exception code is in
;M0. If the error is recoverable (e.g., output aborted due to arrival
;of input message) then the call to XDBYC may simply be re-executed.
;
;On successful return the DAP file data byte is safely enscounced away
;in the output data message being built.
;
;XDBYC is functionally identical to XDBYT but the file data CRC is
;updated to reflect the file data flow.
;
;Preserves all acs.

	ENTRY	.XDBYC
	INTERN	XDBYC0,	XDBYC1

	INTERN	XDCRC1

.XDBYC:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XDBYC0:
XDBYC1:	PUSHJ	P,XDBYT0	;FIRST STUFF THE FILE DATA BYTE
	 POPJ	P,		;PROPAGATE EXCEPTION RETURN
XDCRC1:	PUSH	P,T2		;SAVE FILE DATA BYTE
	ANDI	T2,377		;REDUCE TO JUST INTERESTING DATA
	MOVE	M0,.IODOK(IO)	;RETRIEVE OLD FILE DATA CRC
	XORB	M0,T2		;INCLUDE BYTE IN CRC
	ANDI	T2,377		;COMPUTE OFFSET INTO CRC TABLE
	LSH	M0,-^D08	;XOR REMAINING CRC FROM TABLE
	XOR	M0,DAPCRC(T2)	;COMPUTE NEW CRC
	MOVEM	M0,.IODOK(IO)	;SAVE UPDATED CRC
	POP	P,T2		;RESTORE CALLER'S BYTE
	JRST	.POPJ1##	;AND SUCCESSFULLY RETURN
;XDBYT  --  OUTPUT ONE DAP MESSAGE-LEVEL BYTE
;Call is:
;
;	MOVX	T1,<CDB>
;	MOVX	T2,<byte>
;	PUSHJ	P,XDBYT
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O CDB; <byte> is the 8-bit DAP
;message byte to be sent (eventually) to the remote DAP receiver.
;
;On error return T1 and T2 are preserved. The error or exception code is in
;M0. If the error is recoverable (e.g., non-blocking return) then the call
;to XDBYT may simply be re-executed.
;
;On successful return the DAP message byte is safely enscounced away
;in the output message being built.
;
;XDBYT will take care of shipping either continuation messages (i.e.,
;DAP "MOR" flag set, segmenting a single logical DAP message into multiple
;physical messages) or large messages sans the length field as needed -
;the caller does not need to worry about message blocking.
;
;Preserves all acs.

	ENTRY	.XDBYT
	INTERN	XDBYT0,	XDBYT1

.XDBYT:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XDBYT0:
XDBYT1:	SOSGE	.IODOC(IO)	;ROOM FOR ANOTHER MESSAGE BYTE?
	JRST	XDBYT2		;NO, NEED TO MAKE ROOM
	PUSHJ	P,XNBYT0	;YES, OUTPUT ANOTHER NETWORK BYTE
	 AOSA	.IODOC(IO)	;OOPS - FAILED, ADJUST DAP BYTE COUNT BACK
	AOS	(P)		;SUCCESSFUL
	POPJ	P,		; RETURN
;HERE WHEN OUT OF ROOM TO SHIP THE DAP MESSAGE

XDBYT2:	PUSHJ	P,TSAV14##	;WE NEED SOME ACS HERE
	SKIPLE	T2,.IODOX(IO)	;BEEN HERE ALREADY?
	JRST	XDBYT6		;YES, SKIP THIS PART THEN
	JUMPL	T2,XDBYU0	;IF FUNNY BUSINESS, TRY TO RESUME
	SKIPG	T2,.IODOM(IO)	;NO, GET CURRENT OUTPUT MESSAGE TYPE
	STOPCD	<XDBYT called but no DAP message in progress>
	MOVD	T3,CNF		;GET CONFIGURATION FLAGS
	CAIN	T2,$DHDAT	;IS OVERFLOW DATA OR NON-DATA MESSAGE?
	TFNN	T3,DSG		;DATA - CAN REMOTE HANDLE DAP SEGMENTATION?
	JRST	XDBYV0		;NO, DRASTIC MEASURES ARE NEEDED

;HERE TO SEGMENT THE OUTPUT DATA MESSAGE INTO MULTIPLE CONTINUED MESSAGES

XDBYT4:	MOVEM	T2,.IODOX(IO)	;SET FLAG IN CASE "INTERRUPTED"
	PUSHJ	P,XDMOR0	;SHIP CURRENT MESSAGE AS A CONTINUED MESSAGE
	 POPJ	P,		;BLETCH
	MOVE	T2,.IODOX(IO)	;RETRIEVE MESSAGE TYPE TO BE CONTINUED

;HERE TO START A NEW MESSAGE SEGMENT

XDBYT6:	PUSHJ	P,XDMSG0	;STARTUP A NEW DAP MESSAGE
	 POPJ	P,		;BLETCH
XDBYT8:	SKIPG	.IODOC(IO)	;MAKE SURE WE HAVE A BUFFER
	STOPCD	<XDMSG returned successfully with 0-length buffer in XDBYT>
	SETZM	.IODOX(IO)	;CLEAR INTERLOCK
	MOVE	T2,-T2(P)	;RESTORE ORIGINAL MESSAGE BYTE
	JRST	XDBYT1		;AND STUFF IT IN THE OUTPUT BUFFER
;HERE ON "CONTINUATION" FROM SOME SORT OF BUFFER COMPRESSION

XDBYU0:	PUSHJ	P,XNFLS0	;FLUSH OUT THE NETWORK BUFFER
	 POPJ	P,		;STILL NO GO
XDBYU2:	MOVE	T1,.IODOX(IO)	;GET "STATE" VARIABLE
	AOJE	T1,XDBYV2	;TIME TO "TRY AGAIN"
	AOJE	T1,XDBYV6	;"BLT" THE INCOMPLETE MESSAGE UP
	STOPCD	<Confusion reigns in XDBYT at XDBYU2>



;HERE WHEN EITHER THE DAP MESSAGE LENGTH FIELD OVERFLOWS OR THE
;NETWORK BUFFER OVERFLOWS (AND THE REMOTE CAN'T HANDLE DATA MESSAGE
;SEGMENTATION). TRY TO SHIP WHAT WE HAVE AND FINISH THE REST OF THE
;CURRENT DAP MESSAGE LATER.

XDBYV0:	SETOM	.IODOX(IO)	;FLAG STATE AT FLUSHING AND TRY AGAIN
	DMOVE	T3,.IODXA(IO)	;FETCH IONOC/IONOP AT LAST DAP BOM TIME
	CAME	T3,.IONLM(IO)	;IS THIS THE ONLY MESSAGE IN THE BUFFER?
	SKIPLE	.IONOC(IO)	;OR IS THERE STILL ROOM IN THE BUFFER?
	JRST	XDBYW0		;YES, SEND SANS LENGTH/LEN256/BITCNT FIELDS

;DAP MESSAGES ALREADY STASHED IN THE BUFFER, FLUSH THEM OUT

	CAIN	T2,$DHDAT	;WORKING ON A DATA OR OTHERWISE MESSAGE?
	JRST	XDBYV4		;DATA, CAN'T THROW IT AWAY, LOTS OF WORK

;HERE ON NON-DATA MESSAGE OVERFLOWING, THROW THE CURRENT ATTEMPT AWAY,
;SHIP WHAT'S IN THE BUFFER, THEN TRY THE NON-DATA MESSAGE AGAIN

	PUSHJ	P,XDABM0	;ABORT THE CURRENT NON-DATA MESSAGE
				; NOTE - NEVER "SUCCEEDS"
	PUSHJ	P,XDFLS0	;FLUSH OUT PRECEDING DAP MESSAGES
	 POPJ	P,		;NET DIED?
XDBYV2:	SETZM	.IODOX(IO)	;CLEAR ABORTING STATE
	MOVEI	M0,$ECTRA	;THE "TRY AGAIN" EXCEPTION RETURN
	POPJ	P,		;TELL XDDAP/ET AL TO TRY AGAIN
;HERE ON A DATA MESSAGE THAT OVERFLOWED THE NETWORK BUFFER, FLUSH OUT
;PRECEDING DAP MESSAGES THEN "BLT" THE CURRENT DATA MESSAGE UP TO THE
;TOP OF THE BUFFER AND CONTINUE ON OUR MERRY WAY.

XDBYV4:	SOS	.IODOX(IO)	;SET STATE TO DATA MESSAGE FLUSHING
	MOVEM	T3,.IONOC(IO)	;RESTORE COUNTER AND
	MOVEM	T4,.IONOP(IO)	; POINTER TO PRECEDE CURRENT [INCOMPLETE]
	PUSHJ	P,XNEOM0	; MESSAGE AND FLUSH PRECEDING DATA OUT
	 POPJ	P,		;NET DIED?

;MOVE INCOMPLETE DATA MESSAGE TO TOP OF BUFFER AND CONTINUE

XDBYV6:	DMOVE	T2,.IODXA(IO)	;T2:=COUNT OF SAVED MESSAGE BYTES
				;T3:=START OF SAVED MESSAGE BYTES
	MOVE	T4,.IONOP(IO)	;T4:=START OF FRESH MESSAGE BUFFER
	PUSHJ	P,.BYBLT##	;SHUFFLE OLD MESSAGE TO TOP OF BUFFER
	 STOPCD			;CAN'T HAPPEN
	MOVE	T3,.IONOC(IO)	;FRESH COUNTER
	EXCH	T4,.IONOP(IO)	;FRESH POINTER (UPDATING CURRENT)
	MOVN	T1,.IODXA(IO)	;REFETCH SAVED COUNT
	ADDM	T1,.IONOC(IO)	;UPDATE BYTES LEFT IN "FRESH" BUFFER
	DMOVEM	T3,.IODXA(IO)	;AND SET NEW ABORTION POINTERS

;NOW TO RELOCATE ALL THE "SAVED" DAP MESSAGE BYTE POINTERS

	MOVE	T1,.IONOC(IO)	;DISTANCE THE MESSAGE SHIFTED
	ADDM	T1,.IODO0(IO)	;RELOCATE SAVED BOD COUNTER
	MOVN	T1,.IONOC(IO)	;DISTANCE THE MESSAGE SHIFTED
	ADJBP	T1,.IODO1(IO)	;RELOCATE "HEADER" FLAGS BYTE POINTER
	MOVEM	T1,.IODO1(IO)	; AND SAVE IT FOR OTHERS
;	MOVN	T1,.IONOC(IO)	;DISTANCE THE MESSAGE SHIFTED
;	ADJBP	T1,.IODO2(IO)	;RELOCATE "STREAMID" BYTE POINTER
;	MOVEM	T1,.IODO2(IO)	; AND SAVE IT FOR OTHERS
	MOVN	T1,.IONOC(IO)	;DISTANCE THE MESSAGE SHIFTED
	ADJBP	T1,.IODO3(IO)	;RELOCATE "LENGTH" BYTE POINTER
	MOVEM	T1,.IODO3(IO)	; AND SAVE IT FOR OTHERS
	MOVN	T1,.IONOC(IO)	;DISTANCE THE MESSAGE SHIFTED
	ADJBP	T1,.IODO4(IO)	;RELOCATE "LEN256" BYTE POINTER
	MOVEM	T1,.IODO4(IO)	; AND SAVE IT FOR OTHERS
	MOVN	T1,.IONOC(IO)	;DISTANCE THE MESSAGE SHIFTED
	ADJBP	T1,.IODO5(IO)	;RELOCATE "BITCNT" BYTE POINTER
	MOVEM	T1,.IODO5(IO)	; AND SAVE IT FOR OTHERS
	MOVN	T1,.IONOC(IO)	;DISTANCE THE MESSAGE SHIFTED
	ADJBP	T1,.IODO9(IO)	;RELOCATE "BOD" BYTE POINTER
	MOVEM	T1,.IODO9(IO)	; AND SAVE IT FOR OTHERS

;NOW CALCULATE THE NEW DAP BYTE COUNT

	MOVE	T4,.IODOF(IO)	;DAP MESSAGE HEADER FLAGS
	TFNN	T4,HLN		;GOT A LENGTH FIELD?
	JRST	XDBYW5		;NO, NO LIMIT
	MOVEI	T2,377		;YES, ASSUME 2**8 BYTE LIMIT
	TFNE	T4,HL2		;GOT A LEN256 FIELD?
	MOVEI	T2,177777	;YES, THEN 2**16 BYTE LIMIT
	SUB	T2,.IODO0(IO)	;CALCULATE MAX POSSIBLE ROOM LEFT
	ADD	T2,.IONOC(IO)	; BASED ON ALREADY-PRESENT DATA
	CAMLE	T2,.IONOC(IO)	;LIMITED BY BUFFER SIZE STILL?
	MOVE	T2,.IONOC(IO)	;YES, CHOOSE SMALLER LIMIT
	PJRST	XDBYW8		;FINISH OFF AND OUTPUT THE DAP BYTE
;SINGLE DAP MESSAGE OVERFLOWS THE NETWORK BUFFER, STRIP OFF THE LENGTH
;AND UNUSED BITCOUNT FIELDS, AND START SHIPPING NETWORK BUFFERS AS THEY
;ARE FILLED (ASSUME THE MESSAGE SIZE IS UNLIMITED).

XDBYW0:	SKIPN	.IODO3(IO)	;GOT A LENGTH FIELD?
	JRST	XDBYW5		;NO, NOTHING TO COMPRESS, JUST OUTPUT
				; (ACTUALLY WE MIGHT STILL BE ABLE TO COMPRESS
				;  OUT A BITCOUNT FIELD, BYT WHY BOTHER?)
	MOVEI	T1,1		;ONE BYTE FOR THE "LENGTH" FIELD
	SKIPE	.IODO4(IO)	;GOT A "LEN256" FIELD?
	ADDI	T1,1		;ONE MORE BYTE
	SKIPE	.IODO5(IO)	;GOT A BITCOUNT FIELD?
	ADDI	T1,1		;YEAH, COMPRESS IT OUT TOO ON G.P.S
	MOVE	T2,T1		;COUNT OF BYTES TO SHIFT
	ADDB	T1,.IONOC(IO)	;ADJUST NETWORK BYTE COUNTER
	ADDB	T2,.IODO0(IO)	;ADJUST SAVED DAP BOD BYTE COUNTER
	SUB	T2,T1		;T2:=AMOUNT OF BYTES TO COMPRESS UP
	MOVNI	T3,1		;ALLOW FOR THE "I" OF .BYBLT'S ILDB LOOP
	ADJBP	T3,.IODO9(IO)	;T3:= ILDB POINTER TO PRE-COMPRESSION DATA
	MOVNI	T4,1		;ALLOW FOR THE "I" OF .BYBLT'S IDPB LOOP
	ADJBP	T4,.IODO3(IO)	;T4:= IDPB POINTER TO POST-COMPRESSION DATA
	PUSHJ	P,.BYBLT##	;COMPRESS OUT THE LENGTH/ETC. FIELDS
	 STOPCD			;CAN'T HAPPEN
	MOVEM	T4,.IONOP(IO)	;SET COMPRESSED NETWORK BUFFER STUFFER

;NOW ADJUST OUR COPIES OF WHAT FIELDS ARE LEFT

	MOVE	T4,.IODOF(IO)	;DAP HEADER FLAGS
	TFZ	T4,<HLN,HL2,BCT>;CLEAR NEWLY-NON-EX FIELDS
	MOVEM	T4,.IODOF(IO)	;SAVE UPDATED FLAGS
	SETZ	T3,		;CLEAR EXTRANEOUS BITS
	LSHC	T4,^D07		;POSITION FIRST BYTE OF FLAGS
	DPB	T3,.IODO1(IO)	;SAVE UPDATED FLAGS IN DAP MESSAGE TOO

;SETUP FOR "EXTENDED" MESSAGE SIZE

XDBYW5:	SETZM	.IODO3(IO)	;NO "LENGTH" FIELD LEFT
	SETZM	.IODO4(IO)	;NO "LEN256" FIELD LEFT
	SETZM	.IODO5(IO)	;NO "BITCNT" FIELD LEFT (EVEN IF SHIPPED)
	MOVX	T2,ID.SNM	;THE OK-TO-SEGMENT-NETWORK-MESSAGES FLAG
	IORM	T2,.IODPF(IO)	;TELL XNBYT WE KNOW WHAT WE'RE DOING
	HRLOI	T2,223344	;AN ARBITRARILY LARGE BYTE COUNT
XDBYW8:	MOVEM	T2,.IODOC(IO)	;SET NEW DAP BYTE COUNT
	JRST	XDBYT8		;TRY TO OUTPUT THE BYTE AGAIN
;XDMSG  --  START UP A NEW DAP OUTPUT MESSAGE
;Call is:
;
;	MOVX	T1,<CDB>
;	MOVX	T2,<code>
;	PUSHJ	P,XDMSG
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O CDB; and<code> is the DAP
;message type to be started.
;
;On error return the network died.
;
;On successful return a new DAP message has been started and calls
;may be made to XDBYT.
;
;Uses acs T1, T2, T3, T4.

	ENTRY	.XDMSG
	INTERN	XDMSG0,	XDMSG1

.XDMSG:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XDMSG0:	PUSHJ	P,.SAVE4##	;NEED A FEW MORE ACS
XDMSG1:	PUSHJ	P,TSAV14##	;SAVE THE T'S TOO
XDMSG2:	SKIPLE	.IODOM(IO)	;IN MIDDLE OF A DAP MESSAGE ALREADY?
	STOPCD	<XDMSG called before current DAP message finished>

;START UP A NEW MESSAGE

XDMSG4:	MOVE	T3,.IONOC(IO)	;CURRENT OUTPUT COUNTER
	MOVE	T4,.IONOP(IO)	;AND POINTER AT START OF DAP MESSAGE
	DMOVEM	T3,.IODXA(IO)	;SAVE FOR XDABM
	HRRZM	T2,.IODOM(IO)	;SET NEW CURRENT OUTPUT MESSAGE TYPE
	PUSHJ	P,XNBYT1	;AND PUT IN THE OUTPUT BUFFER
	 STOPCD	<XNBYT failed at XDMSG4>
	MOVD	T3,CNF		;GENERIC [REMOTE] CONFIGURATION
	MOVDII	P1,MHF,<HLN,HL2>;INITIAL DAP MESSAGE HEADER FLAGS
	CAIE	T2,$DHCFG	;IF A CONFIGURATION MESSAGE,
	TFNN	T3,<BLR,BLU>	;OR IF NOT ALLOWED TO BLOCK MESSAGES,
	TFZ	P1,<HLN,HL2>	;THEN DON'T SEND LENGTH FIELDS
	TFNN	T3,C25		;IS "LEN256" FIELD SUPPORTED?
	TFZ	P1,HL2		;NO, THEN DON'T SEND ONE
	CAIE	T2,$DHDAT	;DATA MESSAGE?
	JRST	XDMSH		;NO, ALL SET
	MOVD	T2,DTY		;GET DATA TYPE
	TFNN	T2,ASC		;IF ASCII DATA
	TFNN	T3,BTC		;OR IF BITCOUNT NOT SUPPORTED BY REMOTE
	JRST	XDMSH		;THEN DON'T REQUEST BITCOUNT FIELD
	MOVD1	T2,BSZ		;DAP DATA BYTE SIZE
	TRNE	T2,7		;DATA A MULTIPLE OF 8?
	TFO	P1,BCT		;NO, SUPPLY UNUSED BITCOUNT FIELD

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;BUILD REST OF DAP MESSAGE HEADER BASED ON "MENU" IN P1

;NOTE THAT THE SAVE DAP MESSAGE HEADER BYTE POINTERS ARE SUBJECT TO
;DYNAMIC RELOCATION. THEY SHOULD THEREFORE NEVER BE SAVED ON THE STACK
;OR ANYWHERE ELSE. IF ANY NEW ONES ARE ADDED, BY SURE TO ALSO UPDATE
;XDBYT TO RELOCATE THEM AS WELL.

XDMSH:	MOVE	T3,P1		;POSITION WORKING COPY
	MOVEM	P1,.IODOF(IO)	;ALSO SAVE FOR OTHERS
	SETZ	T2,		;CLEAR EXTRANEOUS BITS
	LSHC	T2,^D7		;POSITION FIRST BYTE OF FLAGS
	CAIE	T3,0		;MORE FOLLOWING?
	STOPCD	<Too many DAP message header flags in XDMSH>
	PUSHJ	P,XDMSB1	;OUTPUT FLAGS BYTE
	 JRST	XDMSK9		;PROBLEM, CHECK IT OUT
	MOVE	T4,.IONOP(IO)	;OUTPUT BYTE POINTER
	MOVEM	T4,.IODO1(IO)	;SAVE FOR XDMOR

;SEND STREAM ID FIELD

	TFNN	P1,SID		;STREAM ID WANTED?
	JRST	XDMSH4		;NO
	STOPCD	<DAP stream ID requested in XDMSH>

;SEND LENGTH FIELD

XDMSH4:	TFNN	P1,HLN		;NEED TO SEND A HEADER LENGTH?
	JRST	XDMSH5		;NO
	PUSHJ	P,XDMSB0	;YES, ALLOCATE A BYTE
	 JRST	XDMSK9		;PROBLEM, CHECK IT OUT
	SKIPA	T2,.IONOP(IO)	;GET BYTE POINTER
XDMSH5:	SETZ	T2,		;NO LENGTH FIELD
	MOVEM	T2,.IODO3(IO)	;SAVE FOR XDEOM

;SEND LEN256 FIELD

	TFNN	P1,HL2		;NEED TO SEND EXTENDED HEADER LENGTH FIELD?
	JRST	XDMSH6		;NO
	PUSHJ	P,XDMSB0	;YES, ALLOCATE A BYTE
	 JRST	XDMSK9		;PROBLEM, CHECK IT OUT
	SKIPA	T2,.IONOP(IO)	;GET BYTE POINTER
XDMSH6:	SETZ	T2,		;NO LEN256 FIELD
	MOVEM	T2,.IODO4(IO)	;SAVE FOR XDEOM

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;SEND TRAILING UNUSED BIT COUNT

	TFNN	P1,BCT		;WANT TRAILING UNUSED BITS?
	JRST	XDMSH7		;NO
	PUSHJ	P,XDMSB0	;YES, ALLOCATE A BYTE
	 JRST	XDMSK9		;PROBLEM, CHECK IT OUT
	SKIPA	T2,.IONOP(IO)	;GET BYTE POINTER
XDMSH7:	SETZ	T2,		;NO BITCNT FIELD
	MOVEM	T2,.IODO5(IO)	;SAVE FOR XDEOM

;NOW SET DAP BYTE COUNTER

	MOVE	T2,.IONOC(IO)	;INITIALLY, LIMIT AT BUFFER END
				; (XDBYT WILL TAKE CARE OF MESSAGE OVERFLOW
				;  FROM A "SHORT" COUNT HERE)
	TFNN	P1,HLN		;SENDING HEADER LENGTH FIELD?
	JRST	XDMSH9		;NO
	TFNN	P1,HL2		;YES, LIMITED TO ONE BYTE?
	CAIG	T2,377		;YES, WILL WE FIT?
	CAIA			;ALL SET
	MOVEI	T2,377		;USE SMALLER ONE-BYTE LIMIT
XDMSH9:	MOVEM	T2,.IODOC(IO)	;SET DAP OUTPUT BYTE COUNTER
	MOVE	T2,.IONOC(IO)	;CURRENT OUTPUT BUFFER BYTE COUNTER
	MOVEM	T2,.IODO0(IO)	;SAVE FOR XDEOM
	MOVE	T2,.IONOP(IO)	;CURRENT OUTPUT BUFFER BYTE POINTER
	IBP	T2		;POINT TO FIRST DAP MESSAGE BYTE
	MOVEM	T2,.IODO9(IO)	;SAVE FOR XDBYT
	JRST	.POPJ1##	;SUCCESSFUL RETURN



;HERE WHEN CAN'T SHIP A MESSAGE HEADER BYTE

XDMSK9:	CAIE	M0,$ECTRA	;XDMSB WANT US TO TRY AGAIN?
	POPJ	P,		;NOPE, BAD ERROR
	MOVE	T2,-T2(P)	;YES, FETCH ORIGINAL MESSAGE TYPE
	JRST	XDMSG4		;AND TRY AGAIN



;HERE TO SHIP ONE MESSAGE HEADER BYTE

XDMSB0:	SETZ	T2,		;A NICE NULL FILLER BYTE
XDMSB1:	SKIPLE	.IONOC(IO)	;ROOM LEFT IN THE NETWORK BUFFER?
	PJRST	XNBYT0		;YES, ALL SET
	PUSHJ	P,XDABM2	;NO, ABORT CURRENT EMBYRIONIC MESSAGE
				; NOTE -NEVER SUCCEEDS
	PUSHJ	P,XDFLS1	;FLUSH OUT PRECEDING DAP DATA
	 POPJ	P,		;OOPS
	MOVEI	M0,$ECTRA	;TRY TRY AGAIN
	POPJ	P,		;EXCEPTION RETURN
;XDABM  --  ABORT THE CURRENT OUTPUT DAP MESSAGE
;Call is:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,XDABM
;	 error return
;
;Where <CDB> is the address of the associated I/O CDB.
;
;Note that this routine always take the error return, preserving caller's M0!
;
;Uses acs T1, T2.

	ENTRY	.XDABM
	INTERN	XDABM0,	XDABM1

.XDABM:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XDABM0:
XDABM1:	SKIPG	T1,.IODOM(IO)	;GET MESSAGE TYPE
	POPJ	P,		;NOTHING TO ABORT, PROPAGATE THE ERROR
	CAIN	T1,$DHDAT	;DATA MESSAGE?
	STOPCD	<Can't abort data message in XDABM>
	MOVE	T1,.IODPF(IO)	;GET DAP LOGIC CONTROL FLAGS
	TXNE	T1,ID.SNM	;HAVE WE ALREADY COMMITTED TO THIS MESSAGE?
	STOPCD	<Can't abort already-partially-transmitted DAP message in XDABM>
XDABM2:	DMOVE	T1,.IODXA(IO)	;SAVED MESSAGE ABORTION POINTER
	JUMPE	T1,XDABM5	;SKIP IF NO SAVED POINTER
	MOVEM	T1,.IONOC(IO)	;RESET NETWORK BYTE COUNTER AND
	MOVEM	T2,.IONOP(IO)	;POINTER TO EAT CURRENT MESSAGE
XDABM5:	SETZM	.IODOM(IO)	;NO MESSAGE BEING BUILT NOW
	SETOM	.IODOC(IO)	;JUST TO MAKE SURE
	SETZM	.IODOB(IO)	;CLEAR TRAILING UNUSED BIT COUNT
	POPJ	P,		;PROPAGATE ERROR RETURN
;XDMOR  --  SEND A MESSAGE SEGMENT (MESSAGE WITH "MOR" FLAG)
;XDEOM  --  SEND DAP MESSAGE
;Call is:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,XDEOM/XDMOR
;	 error return
;	normal return
;
;Where <CDB> is the address of the associated I/O CDB.
;
;On error return the network died.
;
;On normal return the current DAP output message has been closed off.
;If needed (can't piggyback messages or data message) the output message
;will be shipped to the remote.
;
;Uses T1, T2, T3, T4

	ENTRY	.XDMOR
	INTERN	XDMOR0,	XDMOR1

.XDMOR:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XDMOR0:
XDMOR1:	SKIPG	.IODOM(IO)	;IN MIDDLE OF MESSAGE PROCESSING?
	STOPCD	<XDMOR but no DAP message in progress>
	MOVD	T3,CNF		;GET REMOTE'S CONFIGURATION
	TFNN	T3,DSG		;DAP SEGMENTATION SUPPORTED?
	STOPCD	<XDMOR called but remote doesn't support segmentation>
	MOVE	T2,.IODOF(IO)	;GET DAP HEADER FLAGS
	TFO	T2,MOR		;FLAG MORE TO COME AFTER THIS SEGMENT
	SETZ	T1,		;CLEAR EXTRANEOUS BITS
	LSHC	T1,^D07		;POSITION FIRST BYTE OF FLAGS
	DPB	T1,.IODO1(IO)	;SET IN MESSAGE HEADER FLAGS
	JRST	XDEOM0		;GO SEND THE MESSAGE [SEGMENT]
	ENTRY	.XDEOM
	INTERN	XDEOM0,	XDEOM1

.XDEOM:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XDEOM0:
XDEOM1:	SKIPG	.IODOM(IO)	;IN MIDDLE OF MESSAGE PROCESSING?
	STOPCD	<XDEOM but no DAP message in progress>
	SKIPN	T2,.IODO3(IO)	;SENDING LENGTH FIELD?
	JRST	XDEOM3		;NO
	MOVE	T1,.IODO0(IO)	;YES, GET SAVED BYTE COUNT
	SUB	T1,.IONOC(IO)	;T1:=SIZE OF DAP "OPERAND"
	DPB	T1,T2		;SET LOW ORDER LENGTH
	LSH	T1,-^D8		;POSITION HIGH ORDER LENGTH
	SKIPE	T2,.IODO4(IO)	;HIGH ORDER FIELD PRESENT?
	JRST	XDEOM2		;YES
	JUMPE	T1,XDEOM3	;NO, OK UNLESS SIZE .GT. ^O377
	STOPCD	<DAP length greater than ^D255 but no LEN256 field in XDEOM>

XDEOM2:	DPB	T1,T2		;SET HIGH ORDER LENGTH FIELD
XDEOM3:	SETZ	T1,		;RESET COUNT TO 0
	EXCH	T1,.IODOB(IO)	;UNUSED BIT COUNT FIELD
	SKIPE	T2,.IODO5(IO)	;WANT UNUSED BITS?
	JRST	XDEOM4		;YES
	JUMPE	T1,XDEOM7	;NO, OK UNLESS THERE ARE UNUSED BITS
	MOVE	T2,.IODOM(IO)	;NO UNUSED BITCNT POINTER
	CAIE	T2,$DHDAT	;ENDING A DATA MESSAGE?
	JRST	XDEOM7		;NO, THEN IT DOESN'T REALLY MATTER
	STOPCD	<DAP data bits unused but no BITCNT field in XDEOM>

XDEOM4:	DPB	T1,T2		;YES
XDEOM7:	SETOM	.IODOC(IO)	;NO MORE DAP BYTES UNTIL XDMSG
	SETZM	.IODOM(IO)	;NOT IN MESSAGE ANYMORE
	SETZM	.IODXA(IO)	;JUST TO MAKE SURE
	SKIPE	.IODO3(IO)	;IS LENGTH FIELD MISSING?
	SKIPG	.IONOC(IO)	;OR NETWORK BUFFER EMPTY?
	PJRST	XNEOM1		;YES, THEN FORCE THIS BUFFER OUT NOW
;***	MOVD1	T1,FST		;*** GET REMOTE FILE SYSTEM TYPE
;***	CAIN	T1,$DVFF1	;*** IS THIS FCS-11 (RSX-11)?
;***	PJRST	XNEOM1		;*** YES, NEVER BLOCK MESSAGES TOGETHER
;***				;***  FCS-11 FAL HAS SOME OBSCURE BUG THAT
;***				;***  DOESN'T ALWAYS LIKE BLOCKED MESSAGES
;***				;***  EVEN THOUGH IT SOMETIMES WORKS . . .
	JRST	.POPJ1##	;TRY TO PIGGYBACK FOLLOWING DAP MESSAGES
;XDFLS  --  FLUSH OUT ANY PENDING DAP OUTPUT
;Call is:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,XDFLS
;	 error return
;	normal return
;
;Where <CDB> is the address of the associated I/O CDB.
;
;On error return either the network died or an input message has been
;received and awaits processing.
;
;On normal return all pending DAP output messages have been given to
;the monitor to be sent to the remote receiver.
;
;Uses T1.

	ENTRY	.XDFLS
	INTERN	XDFLS0,	XDFLS1

.XDFLS:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XDFLS0:
XDFLS1:	SKIPLE	.IODOM(IO)	;IN MESSAGE PROCESSING?
	STOPCD	<XDFLS called with DAP output message is progress>
	SETOM	.IODOC(IO)	;MAKE SURE XDBYT NOT CONFUSED
XDFLS3:	SKIPLE	T1,.IONOC(IO)	;GET OUTPUT BUFFER SPACE LEFT
	CAME	T1,.IONLM(IO)	;[MAXIMUM-MESSAGE-SIZE] BUFFER EMPTY?
	PJRST	XNEOM0		;NO, SEND IT OUT
	JRST	.POPJ1##	;YES, ALL DONE
	SUBTTL	DAP Protocol Tables

;***	SOME RANDOM DEFINITIONS FOR EASE OF DEBUGGING

	.CREF	.IDRCN		;DATA MESSAGE RECORD NUMBER
	.CREF	.IDSTC		;STATUS MESSAGE STATUS CODE
	.CREF	.IDSRA		;STATUS MESSAGE RECORD ADDRESS
	.CREF	.IDSRN		;STATUS MESSAGE RECORD NUMBER
	.CREF	.IDSTV		;STATUS MESSAGE SECODARY STATUS
	SUBTTL	DAP Protocol Tables - Execution table index table

;THE DAP EXECUTION TABLE INDEX

DAPIDX::DODAP(IDX)
	SUBTTL	DAP Protocol Tables - Execution table

;AND THE DAP EXECUTION TABLE

DAPXCT::DODAP(XCT)
	SUBTTL	DAP Protocol Tables - Field-text table

;THE DAP MESSAGE/FIELD TEXT DESCRIPTION TABLE

DAPXTX::DODAP(XTX)
	SUBTTL	DAP Protocol Tables - Status-code text table

;THE DAP STATUS CODE TEXT DESCRIPTION TABLE

DAPSTS::DODAP(STS)
	SUBTTL	DAP Protocol Tables - CRC polynomial table

;THE DAP CRC POLYNOMIAL TABLE

DAPCRC::BLDCRC	(164405)	;X^16 + X^15 + X^13 + X^7 + X^4 + X^2 + X^1 + 1
	SUBTTL	Network Link Control - Link initialization

;NTNIA  --  INITIALIZE ACTIVE NETWORK CHANNEL
;CALL IS:
;
;	MOVX	T1,<CDB>
;	MOVX	T2,<NOD>
;	PUSHJ	P,NTNIA
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O CDB; and <NOD> is the SIXBIT
;node name with whom communications are desired.
;
;The caller is responsible for setting up all other network parameters
;such as object type and name, optional user data, etc.
;
;On error return, a connection could not be established, an error code
;is in M0.
;
;On normal return, a network channel has been assigned (and is returned
;in .IONCH) and the "Connect Initiate" message has been posted to the
;specified node.
;
;Note that NTNIA only requests a network logical link, it does not in any
;way ensure that the specified node will accept the request - a call to
;NTNCW must be executed to "block" waiting for completion of the request.
;
;Uses T1, T2, T3, T4.

	ENTRY	.NTNIA
	INTERN	NTNIA0,	NTNIA1

.NTNIA:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
NTNIA0:	PUSHJ	P,.SAVE4##	;PRESERVE A FEW ACS
NTNIA1:	SKIPE	.IONCH(IO)	;MAKE SURE CDB NOT ALREADY ACTIVE
	STOPCD	<NTNIA called with outstanding network channel>

;SELECT THE DESTINATION NETWORK NODE

	MOVE	T3,T2		;POSITION NODE SPECIFIER
	PUSHJ	P,.NDNAM##	;TRY TO MAKE SENSE OF IT
	MOVEM	T1,.ION6M(IO)	;SET NODE NAME (SIXBIT) FOR INTEREST
	JUMPL	T2,NDNIA1	;IF NOT KNOWN ANF, THEN ASSUME DECNET
;	JRST	NANIA1		;USE ANF NETWORK

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;HERE FOR ANF ENTER ACTIVE

NANIA1:	MOVEM	T2,.I1NSC+0(IO)	;SET TSK. NODE NUMBER IN DESTINATION NPD
	SKIPN	.IONDF(IO)	;WE REQUIRE A DESTINATION NPD FROM CALLER
	STOPCD	<No destination NPD in NANIA1>

;SETUP AND BUILD THE TSK.-STYLE CONNECT INFO

	PUSHJ	P,NAS1I1	;INITIALIZE FOR STRING BUILDING
	 STOPCD	<NAS1I1 failed in NANIA1>
	PUSHJ	P,.XTYPO##	;SELECT BYTE TYPER
	MOVEI	P2,"0"		;DEFAULT IS RANDOM TASK
	PUSHJ	P,NAS2I1	;ENCODE THE SOURCE AND DESTINATION NPD
	 STOPCD	<NAS2I1 failed in NANIA1>
	MOVEI	P2,0		;NO DEFAULT FOR USER ID STUFF
	PUSHJ	P,NAS3I1	;ENCODE USER ID/PASSWORD/AD NAUSEUM
	 STOPCD	<NAS3I1 failed in NANAI1>
	SKIPL	T1,.IONP3(IO)	;DID IT ALL FIT?
	STOPCD	<Strings too big in NANIA1>
	HRRZM	T1,.I1NSC+1(IO)	;SET TSK. NPD BYTE COUNT

;NOW ASSIGN A TASK CHANNEL AND REQUEST A NETWORK CONNECT INIT

NANIA5:	MOVX	M0,IO.NET!IO.ANF;FLAG ANF-STYLE NETWORK CHANNEL
	IORM	M0,.IOCCF(IO)	;UPDATE CHANNEL CONTROL
	PUSHJ	P,NAS4I1	;ASSIGN A TSK: CHANNEL, ETC
	 POPJ	P,		;ERROR
	MOVX	P1,.TKFEA	;FUNCTION: ENTER ACTIVE
	MOVE	T1,[4,,P1]	;TSK. ARG POINTER TO
	TSK.	T1,		;SEND A CONNECT INIT
	 JRST	NACIE1		;PROCESS TSK. CONNECT ERROR
	JRST	.POPJ1##	;CONNECT INIT POSTED
;HERE FOR DECNET-STYLE ENTER ACTIVE

NDNIA1:	MOVE	T2,T1		;POSITION SIXBIT NAME IN T2
	MOVE	P3,[6,,.IONNM]	;8-BIT NAME POINTER
	PUSHJ	P,N6TO8		;CONVERT 6-BIT TO 8-BIT NAME
	 STOPCD	<Node name N6TO8 failed in NTNIA>
	HRLI	P3,$NTNBL	;SET MAXIMUM "NAME BLOCK LENGTH"
	MOVSM	P3,.IONNM(IO)	;SET BYTE,,WORD COUNTS FOR NODE NAME BLOCK

;COMMON CODE TO INITIALIZE FOR NSP.

	PUSHJ	P,NDS1I1	;SETUP NSP. ARGUMENTS
	 STOPCD	<NDS1I1 failed in NDNAI1>

;"QUEUE" THE REQUEST WITH NETWORK SERVICES VIA THE MONITOR

	MOVX	M0,IO.NET!IO.DCN;FLAG ACTIVE DECNET CHANNEL
	IORM	M0,.IOCCF(IO)	;SET IN THE CDB
	XMOVEI	P3,.I1NSC(IO)	;NSP. CONNECT BLOCK ADDRESS
	SETZ	P2,		;NO CHANNEL YET
	MOVE	P1,[.NSFEA,,.NSAA1+1]  ;"ENTER ACTIVE" FUNCTION
	TXO	P1,NS.WAI	;*** IT STILL DOESN'T WORK!!!!!!!!!!
	XMOVEI	M0,P1		;NSP. ARG BLOCK TO
	NSP.	M0,		;ASK FOR AN ACTIVE NETWORK CHANNEL
	 JRST	NDCIE1		;PROCESS NSP. CONNECT ERROR
	HRRZM	P2,.IONCH(IO)	;SUCCESS, SAVE NETWORK CHANNEL
	JRST	.POPJ1##	;SUCCESSFUL RETURN
;NTNIP  --  INITIALIZE PASSIVE NETWORK CHANNEL
;CALL IS:
;
;	MOVX	T1,<CDB>
;	MOVX	T2,<NOD>
;	PUSHJ	P,NTNIP
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O CDB; and <NOD> is the SIXBIT
;node name with whom communications are desired (or 0 (or "*") if any
;node is acceptable).
;
;The caller is responsible for setting such information as the source
;and/or destination process descriptors, and so forth.
;
;On error return, a network channel could not be established (e.g., not
;enough monitor resources, etc.), an error code in in M0.
;
;On normal return, a network channel has been assigned (and is returned
;in .IONCH) and is awaiting a "Connect Initiate" message.
;
;Note that NTNIP only requests a network logical link, it does not in any
;way ensure that anyone has connected to the logical link - a call to
;.NTNCW will "block" waiting for a connection.
;
;Uses T1, T2, T3, T4.

	ENTRY	.NTNIP
	INTERN	NTNIP0,	NTNIP1

.NTNIP:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
NTNIP0:	PUSHJ	P,.SAVE4##	;PRESERVE A FEW ACS
NTNIP1:	SKIPE	.IONCH(IO)	;MAKE SURE CDB NOT ALREADY ACTIVE
	STOPCD	<NTNIP called with outstanding network channel>
	MOVEM	T2,.ION6M(IO)	;SET NODE NAME (SIXBIT) FOR INTEREST
	MOVE	T1,.IOCCF(IO)	;CHANNEL CONTROL FLAGS
	TXNE	T1,IO.ANF	;ANF-STYLE NETWORK?
	JRST	NANIP1		;YES
	TXNE	T1,IO.DCN	;DECNET-STYLE NETWORK?
	JRST	NDNIP1		;YES
	STOPCD	<Neither ANF nor DECnet selected in NTNIP>
;HERE FOR ANF ENTER PASSIVE

NANIP1:	CAME	T2,['*     ']	;EXPLICITLY WILD NODE?
	CAIN	T2,0		;IMPLICITLY WILD NODE?
	SETO	T2,		;TSK.-STYLE WILD NODE!
	MOVEM	T2,.I1NSC+0(IO)	;SET NODE SPECIFIER IN TSK. ARG BLOCK
	SKIPN	.IONDF(IO)	;"DESTINATION" NPD IS REQUIRED
	STOPCD	<No destination NPD in NDNIP1>

;NOW SETUP TSK.-STYLE ARGUMENTS

	PUSHJ	P,NAS1I1	;INITIALIZE FOR STRING WIZARDRY
	 STOPCD	<NAS1I1 failed in NANIP1>
	PUSHJ	P,.XTYPO##	;SELECT BYTE TYPER
	MOVEI	P2,"*"		;DEFAULT HERE IS FULLY WILD
	PUSHJ	P,NAS2I1	;SETUP SOURCE/DESTINATION NPDS
	 STOPCD	<NAS2I1 failed in NANIP1>
	MOVEI	P2,"*"		;ACCEPT ANYTHING BY DEFAULT HERE TOO
	PUSHJ	P,NAS3I1	;SETUP USER ID/ET AL
	 STOPCD	<NAS3I1 failed in NANIP1>
	SKIPL	T1,.IONP3(IO)	;DID IT ALL FIT?
	STOPCD	<Strings too big in NANIP1>
	HRRZM	T1,.I1NSC+1(IO)	;SET TSK.-STYLE NPD BYTE COUNT

;NOW GET A TASK CHANNEL

	MOVX	M0,IO.NET!IO.ANF!IO.NEP;FLAG PASSIVE ANF-STYLE NETWORK CHANNEL
	IORM	M0,.IOCCF(IO)	;UPDATE CHANNEL CONTROL
	PUSHJ	P,NAS4I1	;ASSIGN TSK: CHANNEL
	 POPJ	P,		;ERROR
	MOVX	P1,.TKFEP	;FUNCTION: ENTER PASSIVE
	MOVE	T1,[4,,P1]	;TSK. ARG POINTER TO
	TSK.	T1,		;ENTER PASSIVE CONNECT WAIT
	 JRST	NACIE1		;PROCESS TSK. CONNECT ERROR

;ALL DONE HERE

	JRST	.POPJ1##	;RETURN AWAITING A CONNECTION
;HERE FOR DECNET-STYLE ENTER PASSIVE

NDNIP1:	MOVE	P3,[6,,.IONNM]	;8-BIT POINTER
	PUSHJ	P,N6TO8		;CONVERT TO 8-BIT NODE NAME
	 STOPCD	<Node name N6TO8 failed in NTNIP>
	HRLI	P3,$NTNBL	;SELECT MAXIMUM NAME BLOCK LENGTH
	MOVSM	P3,.IONNM(IO)	;SET BYTE,,WORD COUNTER IN NAME BLOCK

;COMMON CODE TO SETUP THE NSP. ARGUMENTS

	PUSHJ	P,NDS1I1	;INITIALIZE THE NSP. ARG BLOCK
	 STOPCD	<NDS1I1 failed in NDNIP1>

;"QUEUE" THE REQUEST WITH NETWORK SERVICES VIA THE MONITOR

	MOVX	M0,IO.NET!IO.DCN;THE "NETWORK-BASED COMMUNICATIONS" BIT
	IORM	M0,.IOCCF(IO)	;SET IN THE CDB
	XMOVEI	P3,.I1NSC(IO)	;NSP. CONNECT BLOCK ADDRESS
	SETZ	P2,		;NO CHANNEL YET
	MOVE	P1,[.NSFEP,,.NSAA1+1]  ;"ENTER PASSIVE" FUNCTION
	TXO	P1,NS.WAI	;*** IT STILL DOESN'T WORK!!!!!!!!!
	XMOVEI	M0,P1		;NSP. ARG BLOCK TO
	NSP.	M0,		;ASK FOR A PASSIVE NETWORK CHANNEL
	 JRST	NDCIE1		;PROCESS NSP CONNECT ERROR
	HRRZM	P2,.IONCH(IO)	;SUCCESS, SAVE NETWORK CHANNEL
	MOVX	P1,IO.NET!IO.NEP;"PASSIVE NETWORK COMMUNICATIONS" BITS
	IORM	P1,.IOCCF(IO)	;ADJUST THE CDB ACCORDINGLY
	JRST	.POPJ1##	;SUCCESSFUL RETURN
;RANDOM SUBROUTINES FOR ENTER ACTIVE/PASSIVE

;As ANF-10 basically doesn't support any of the "wonderous" errata of
;DECnet such as user-id, password, ad nauseum, the TSK. monitor call
;was invented to give the user fuller control over the network logical
;link. In particular, in conjunction with versions 3 and later of the
;DECnet Compatible Port (in the DN8x), the "network process descriptor"
;was made available to the "user" in order to encode all that stuff in
;such a way that the DCP can convert it into something the DECnet side
;understood. The result is a very arcane NPD string (for which honesty
;requires that I not claim any credit) given to the TSK. in the active
;and passive init functions. The form of that NPD string, for the first
;time anywhere ever put in writing, is:
;
;	<0>		;leading null byte
;	DST		;"destination" process identifier
;	<0>		;punctuation byte
;	SRC		;"source" process identifier
;	<0>		;punctuation byte
;	USERID		;user id string
;	<0>		;punctuation byte
;	PASSWORD	;password string for user id
;	<0>		;punctuation byte
;	ACCOUNT		;account string for user id
;	<0>		;punctuation byte
;	OPTDATA		;"optional user data" a la DECnet connect init
;	<0>		;punctuation byte
;
;DST and SRC both are one of the following forms:
;
;	OBJ		;format 0: DECnet object type
;	OBJ.NAM		;format 1: DECnet object type and task name
;			;	   note the "." punctuation character
;	OBJ.[P,PN]NAM	;format 2: DECnet object type, user ppn and name
;			;	   note the ".", "[" and "]" punctuation
;
;OBJ is the object type as an ASCII octal number - e.g., "21" for DAP.
;NAM, USERID, PASSWORD, ACCOUNT, and OPTDATA are all "ASCII" character
;strings - i.e., 7-bit bytes (with no nulls).
;NAS1I1 - INITIALIZE FOR STRING MAGIC

NAS1I1:	MOVE	P3,[XWD <<.NSCUD+.NSDPN+.NSDPN>*5>,.I1NSC+2]
	PUSHJ	P,NP3P4		;SET BYTE COUNTER AND POINTER
	 STOPCD	<NP3P4 failed in NAS1I1>
	MOVSI	T1,(POINT 7,(IO))  ;TSK. USES 7-BIT BYTES
	HLLM	T1,.IONP4(IO)	;SO OVERRIDE .IONP4
	XMOVEI	T1,NTYPO	;BYTE TYPER
	JRST	.POPJ1##	;RETURN



;NAS2I1 - ENCODE SOURCE AND DESTINATION "NPD"S

NAS2I1:	XMOVEI	P1,.IONDF(IO)	;ADDRESS DESTINATION NPD FIELDS
	PUSHJ	P,NAS1N0	;ENCODE ONE "NPD"
	 STOPCD	<NAS1N0 failed in NAS2I1>
	XMOVEI	P1,.IONSF(IO)	;ADDRESS SOURCE NPD FIELDS
	PUSHJ	P,NAS1N0	;ENCODE ONE MORE "NPD"
	 STOPCD	<NAS1N0 failed in NAS2I1>
	JRST	.POPJ1##	;SUCCESSFUL SO FAR



;NAS3I1 - ENCODE USER ID, PASSWORD, ACCOUNT STRING, OPTIONAL DATA

NAS3I1:	XMOVEI	P1,.IONUS(IO)	;ADDRESS OF USER ID STRING BLOCK
	PUSHJ	P,NAS8S0	;ENCODE USER ID STRING
	 STOPCD	<NAS8S0 - user id - failed in NAS3I1>
	XMOVEI	P1,.IONPW(IO)	;ADDRESS OF PASSWORD STRING BLOCK
	PUSHJ	P,NAS8S0	;ENCODE PASSWORD STRING
	 STOPCD	<NAS8S0 - password - failed in NAS3I1>
	XMOVEI	P1,.IONAC(IO)	;ADDRESS OF ACCOUNT STRING BLOCK
	PUSHJ	P,NAS8S0	;ENCODE ACCOUNT STRING
	 STOPCD	<NAS8S0 - account - failed in NAS3I1>
	XMOVEI	P1,.IONUD(IO)	;ADDRESS OF OPTIONAL DATA STRING BLOCK
	PUSHJ	P,NAS8S0	;ENCODE OPTIONAL DATA
	 STOPCD	<NAS8S0 - optional data - failed in NAS3I1>
	PJRST	NAS0B0		;CAP OFF WITH A NULL
;NAS4I1 - GET TASK CHANNEL, SETUP FOR TSK.

;Note that ANF TSK: channels must be run UU.AIO (non-blocking) so that
;a "dummy" IN can be performed in order to kick the monitor into sending
;data requests to the "other" guy. If the dummy IN is not performed, then
;both sides end up "deadlocked" trying to send the initial DAP CONFIG
;message, with neither side having sent any data requests!

NAS4I1:	MOVX	P1,FO.ASC!.FOCRE;ASSIGN CHANNEL, CREATE CHANNEL
	MOVX	P2,UU.PHY!UU.AIO!UU.IBC!.IOBYT  ;DEVIOS WORD
	MOVSI	P3,'TSK'	;DEVICE NAME IS TSK:
	MOVSI	P4,.IONOH(IO)	;OUTPUT RING HEADER ADDRESS
	HRRI	P4,.IONIH(IO)	;INPUT RING HEADER ADDRESS
	MOVE	T1,[4,,P1]	;FILOP. ARG POINTER TO
	FILOP.	T1,		;ASSIGN A TSK CHANNEL
	 JRST	NAS4I9		;FILOP. ERROR
	LDB	P2,[POINTR P1,FO.CHN]  ;EXTRACT CHANNEL NUMBER RETURNED
	MOVEM	P2,.IONCH(IO)	;SAVE FOR POSTERITY
	SETOM	.I1NSP+0(IO)	;DUMMY SOURCE NPD NODE NUMBER
	SETZM	.I1NSP+1(IO)	;DUMMY SOURCE NPD PROCESS ID STRING
	MOVEI	P3,.I1NSP(IO)	;ADDRESS OF "SOURCE" NPD FOR TSK.
	HRLI	P3,3		;LENGTH OF SAME
	MOVEI	P4,.I1NSC(IO)	;ADDRESS OF "DESTINATION" NPD FOR TSK.
	HRLI	P4,<.NSCUD+1+.NSDPN+1+.NSDPN+1>  ;LENGTH OF SAME

	JRST	.POPJ1##	;SUCCESSFUL RETURN

;HERE WHEN FILOP. OPEN TSK: FAILS

NAS4I9:	LDB	P2,[POINTR P1,FO.CHN]  ;EXTRACT CHANNEL NUMBER, IF ANY
	CAIE	P2,0		;DID MONITOR ASSIGN US A CHANNEL?
	RESDV.	P2,		;YES (PROBABLY), STOMP IT
	 JFCL			;HO HUM
	SETZ	M0,		;NO ERROR CODE SELECTED YET
	MOVE	T2,T1		;POSITION ERROR CODE
	XMOVEI	T4,NAS4IT	;AND ERROR CODE TRANSLATION TABLE
	PUSHJ	P,.CFIND##	;TRY TO MAP FILOP. ERROR
	 MOVEI	T1,$EFTNA	;FALLBACK "TASK DEVICE NOT AVAILABLE"
	MOVE	M0,T1		;POSITION ERROR CODE IN ERROR AC
	POPJ	P,		;ERROR RETURN

;FILOP. OPEN ERRORS

NAS4IT:	$EFISU,,ERISU%		;ILLEGAL SEQUENCE OF UUOS
	$EFILU,,ERILU%		;ILLEGAL FILOP. CALL
	$EFNLI,,ERNLI%		;ILLEGAL NOT LOGGED IN
	$EFENC,,ERENC%		;EXCEEDED NETWORK CAPACITY
	$EFTNA,,ERTNA%		;TASK DEVICE NOT AVAILABLE
	$EFNSN,,ERUNN%		;NO SUCH NODE NAME
	$EFNPC,,ERNPC%		;NO PER-PROCESS SPACE AVAILABLE
	$EFNFC,,ERNFC%		;NO FREE I/O CHANNELS
	0			;THAT ABOUT DOES IT
;NAS1N0 - ENCODE ONE "NPD"

NAS1N0:	PUSHJ	P,NAS0B0	;START OFF WITH A NULL
	 JFCL			;CAN'T HAPPEN
NAS1N1:	HRRZ	T1,0(P1)	;OBJECT TYPE
	JUMPE	T1,[SKIPE T1,P2		;NONE, SELECT DEFAULT
		PUSHJ	P,.TCHAR##	;OUTPUT DEFAULT, IF ANY
		JRST	.POPJ1##]	;THAT'S ALL FOR THIS NPD
	XMOVEI	T2,.TOCTW##	;OBJECT TYPE IS OUTPUT IS OCTAL
	CAIN	T1,-1		;UNLESS -1,
	XMOVEI	T2,.TASTR##	;IN WHICH CASE OUTPUT IS "*"
	PUSHJ	P,0(T2)		;DO WHATEVER'S APPROPRIATE
	HLRZ	T1,0(P1)	;FORMAT TYPE
	JUMPE	T1,.POPJ1##	;0 = OBJECT TYPE ONLY
	SOJE	T1,NASIN3	;1 = OBJECT TYPE AND NAME
	SOJE	T1,NASIN5	;2 = OBJECT TYPE, PPN, AND NAME
	STOPCD	<Illegal format type in NASIN1>


;HERE FOR FORMAT 1 - OBJ.NAM

NASIN3:	PUSHJ	P,.TDOT##	;SEPARATE OBJECT TYPE AND NAME
	ADDI	P1,.IONSN-.IONSF;RELOCATE P1 TO NAME STRING BLOCK ADDRESS
	JRST	NAS8S1		;COPY NAME STRING


;HERE FOR FORMAT 2 - OBJ.[P,PN]NAM

NASIN5:	PUSHJ	P,.TDOT##	;SEPARATE OBJECT TYPE AND PPN/NAME
	ADDI	P1,.IONSP-.IONSF;RELOCATE P1 TO PPN
	MOVE	T1,0(P1)	;FETCH USER PPN
	PUSHJ	P,.TPPNW##	;AND TYPE IT OUT AS "[P,PN]"
	ADDI	P1,.IONSN-.IONSP;RELOCATE P1 TO NAME STRING BLOCK ADDRESS
	JRST	NAS8S1		;COPY NAME STRING
;NAS8S0 - COPY 8-BIT STRING BLOCK

NAS8S0:	PUSHJ	P,NAS0B0	;START OFF WITH A NULL
	 JFCL			;CAN'T HAPPEN
NAS8S1:	HLRZ	T4,0(P1)	;GET ACTUAL BYTE COUNT
	JUMPE	T4,[SKIPE T1,P2		;NONE, SELECT DEFAULT NAME
		PUSHJ	P,.TCHAR##	;ISSUE DEFAULT NAME
		JRST	.POPJ1##]	;AND THAT'S THAT
	MOVE	T3,[POINT 8,1(P1)]  ;BYTE POINTER TO 8-BIT NAME STRING
NAS8S4:	ILDB	T1,T3		;GET NEXT NAME CHARACTER
	CAIE	T1,0		;COMPRESS OUT NULLS
	PUSHJ	P,.TCHAR##	;ISSUE ONE MORE CHARACTER
	SOJG	T4,NAS8S4	;LOOP FOR WHOLE NAME
	JRST	.POPJ1##	;SUCCESSFUL RETURN



;NAS0B0 - OUTPUT NULL BYTE

NAS0B0:	SETZ	T1,		;A NULL BYTE
NAS0B1:	PUSHJ	P,NTYPO		;ISSUE ONE CHARACTER
	JRST	.POPJ1##	;SUCCESSFUL RETURN ALWAYS
;NDS1I1 - SETUP FOR DECNET NSP. ENTER ACTIVE OR PASSIVE

;SETUP THE SOURCE PROCESS DESCRIPTOR BLOCK

NDS1I1:	MOVEI	P1,.NSDPN+1	;LENGTH OF PROCESS DESCRIPTOR BLOCK
	MOVEM	P1,.I1NSS+.NSDFL(IO)  ;SET IN PROCESS BLOCK
	MOVE	P1,.IONSF(IO)	;SOURCE FORMAT,,OBJECT TYPE
	HLREM	P1,.I1NSS+.NSDFM(IO)  ;SET FORMAT TYPE IN PROCESS BLOCK
	HRREM	P1,.I1NSS+.NSDOB(IO)  ;SET OBJECT TYPE IN PROCESS BLOCK
	MOVE	P1,.IONSP(IO)	;SOURCE "PPN"
	MOVEM	P1,.I1NSS+.NSDPP(IO)  ;SET IN PROCESS BLOCK
	XMOVEI	P1,.IONSN(IO)	;SOURCE NAME BLOCK ADDRESS
	MOVEM	P1,.I1NSS+.NSDPN(IO)  ;SET IN SOURCE PROCESS BLOCK
	MOVEI	M0,$NTNBL	;LENGTH OF A NAME BLOCK
	HRRM	M0,@P1		;SET WORD COUNT OF SOURCE TASK NAME

;SETUP THE DESTINATION PROCESS DESCRIPTOR BLOCK

NDS1I3:	MOVEI	P1,.NSDPN+1	;LENGTH OF PROCESS DESCRIPTOR BLOCK
	MOVEM	P1,.I1NSD+.NSDFL(IO)  ;SET IN PROCESS BLOCK
	MOVE	P1,.IONDF(IO)	;DESTINATION FORMAT,,OBJECT TYPE
	HLREM	P1,.I1NSD+.NSDFM(IO)  ;SET FORMAT TYPE IN PROCESS BLOCK
	HRREM	P1,.I1NSD+.NSDOB(IO)  ;SET OBJECT TYPE IN PROCESS BLOCK
	MOVE	P1,.IONDP(IO)	;DESTINATION "PPN"
	MOVEM	P1,.I1NSD+.NSDPP(IO)  ;SET IN PROCESS BLOCK
	XMOVEI	P1,.IONDN(IO)	;DESTINATION NAME BLOCK ADDRESS
	MOVEM	P1,.I1NSD+.NSDPN(IO)  ;SET IN DESTINATION PROCESS BLOCK
	MOVEI	M0,$NTNBL	;LENGTH OF A NAME BLOCK
	HRRM	M0,@P1		;SET WORD COUNT OF DESTINATION TASK NAME

;SETUP NSP. CONNECT BLOCK POINTERS

NDS1I5:	MOVEI	P1,.NSCUD+1	;LENGTH OF CONNECT BLOCK
	MOVEM	P1,.I1NSC+.NSCNL(IO)  ;SET CONNECT BLOCK LENGTH (WORDS)
	XMOVEI	P1,.IONNM(IO)	;NODE NAME ADDRESS
	MOVEM	P1,.I1NSC+.NSCND(IO)  ;SET IN CONNECT BLOCK
	XMOVEI	P1,.I1NSS(IO)	;SOURCE PROCESS BLOCK ADDRESS
	MOVEM	P1,.I1NSC+.NSCSD(IO)  ;SET IN CONNECT BLOCK
	XMOVEI	P1,.I1NSD(IO)	;DESTINATION PROCESS BLOCK ADDRESS
	MOVEM	P1,.I1NSC+.NSCDD(IO)  ;SET IN CONNECT BLOCK
	MOVEI	M0,$NTSBL	;MAXIMUM "STRING BLOCK ADDRESS"
	XMOVEI	P1,.IONUS(IO)	;USER ID ADDRESS
	MOVEM	P1,.I1NSC+.NSCUS(IO)  ;SET IN CONNECT BLOCK
	HRRM	M0,@P1		;SET STRING BLOCK WORD COUNT
	XMOVEI	P1,.IONPW(IO)	;USER PASSWORD ADDRESS
	MOVEM	P1,.I1NSC+.NSCPW(IO)  ;SET IN CONNECT BLOCK
	HRRM	M0,@P1		;SET STRING BLOCK WORD COUNT
	XMOVEI	P1,.IONAC(IO)	;USER ACCOUNT DATA ADDRESS
	MOVEM	P1,.I1NSC+.NSCAC(IO)  ;SET IN CONNECT BLOCK
	HRRM	M0,@P1		;SET STRING BLOCK WORD COUNT
	XMOVEI	P1,.IONUD(IO)	;USER DATA ADDRESS
	MOVEM	P1,.I1NSC+.NSCUD(IO)  ;SET IN CONNECT BLOCK
	HRRM	M0,@P1		;SET STRING BLOCK WORD COUNT

	JRST	.POPJ1##	;RETURN HAPPILY
;NTNCW  --  WAIT FOR CONNECT CONFIRM/CONNECT INITIATE
;CALL IS:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,NTNCW
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O CDB.
;
;On error return the network died (channel aborted), error code is returned
;in M0.
;
;On normal return, an active channel has successfully connected to a
;remote network process, or a passive channel has received a "Connect
;Initiate" request and must either accept or reject it.
;
;The connect block is filled in accordingly.
;
;Uses T1, T2, T3, T4.

	ENTRY	.NTNCW
	INTERN	NTNCW0,	NTNCW1

.NTNCW:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
NTNCW0:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
NTNCW1:	SKIPN	P2,.IONCH(IO)	;NETWORK CHANNEL
	STOPCD	<No network channel in NTNCW>
	MOVE	T1,.IOCCF(IO)	;CHANNEL CONTROL
	TXNE	T1,IO.ANF	;ANF NETWORK CHANNEL?
	JRST	NANCW1		;YES
	TXNE	T1,IO.DCN	;DECNET NETWORK CHANNEL?
	JRST	NDNCW1		;YES
	STOPCD	<Neither ANF nor DECnet in NTNCW>
;HERE FOR ANF CONNECT WAIT

NANCW1:	MOVX	P1,.TKFWT	;FUNCTION: WAIT FOR CONNECT EVENT
	MOVE	T1,[2,,P1]	;TSK. ARG POINTER TO
	TSK.	T1,		;WAIT FOR A CONNECT EVENT
	 JRST	NACIE1		;PROCESS TSK. CONNECT ERROR

;LINK IS UP AND ACTIVE, READ IN TSKSER'S NPD

NANCW3:	MOVEI	P4,.I1NSC(IO)	;ADDRESS OF OUR TSK. NPD BLOCK
	HRLI	P4,<.NSCUD+1+.NSDPN+1+.NSDPN+1>  ;LENGTH OF SAME
	SETZ	P3,		;NO SOURCE WANTED
	MOVX	P1,.TKFRS	;FUNCTION: READ STATUS
	MOVE	T1,[4,,P1]	;TSK. ARG POINTER TO
	TSK.	T1,		;READ IN STATUS AND NPD STRING
	 JRST	NACIE1		;PROCESS TSK. CONNECT ERROR
	CAIN	P3,.TKSOK	;IS THE LINK ESTABLISHED AND "RUNNING"
	JRST	NANCW5		;YES
	PUSHJ	P,NTZAP0	;*** NO, GET RID OF IT
	 JFCL			;*** HO HUM
	MOVEI	M0,$EFURO	;*** ASSUME "NO FILE SERVICE" FOR NOW
	POPJ	P,		;*** NO LINK

;SET NODE NAME FOR INTERESTED PARTIES

NANCW5:	MOVE	T3,.I1NSC(IO)	;RETURNED NODE NAME (OCTAL)
	PUSHJ	P,.NDNAM##	;TRY TO MAKE A PRINTABLE NAME OUT OF IT
	MOVEM	T1,.ION6M(IO)	;SAVE IN CASE ANYONE IS INTERESTED

;DO A "DUMMY" IN TO TRICK MONITOR INTO SENDING DATA REQUESTS

NANCW6:	MOVS	T2,.IONCH(IO)	;NETWORK TSK CHANNEL NUMBER
	HRRI	T2,.FOINP	;FUNCTION: INPUT
	MOVE	T1,[1,,T2]	;FILOP. ARG POINTER TO
	FILOP.	T1,		;EXECUTE A "DUMMY" IN (IT MIGHT EVEN WORK!)
	 JFCL			;IGNORE ERRORS HERE, CATCH 'EM LATER

;ALL DONE IF AN "ACTIVE" LINK, GRUNDGE IF A PASSIVE ONE

	MOVE	T1,.IOCCF(IO)	;CHANNEL CONTROL FLAGS
	TXNN	T1,IO.NEP	;ACTIVE OR PASSIVE?
	JRST	.POPJ1##	;ACTIVE (DCP RETURNS USELESS NPD)

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;PASSIVE LINK, DECODE THE NPD "CONNECT" INFORMATION

NANCW7:	MOVE	P3,.I1NSC+1(IO)	;RETURNED NPD BYTE COUNT
	MOVE	P4,[POINT 7,.I1NSC+2(IO)]  ;POINTER TO RETURNED NPD STRING
	PUSHJ	P,NAS0R0	;READ IN FIRST BYTE
	CAIE	T1,0		;MUST BE A NULL
	STOPCD	<Junk returned NPD in NANCW5>
	XMOVEI	P1,.IONDF(IO)	;ADDRESS OF "DESTINATION" NPD STUFF
	PUSHJ	P,NAS3R0	;DECODE DESTINATION INFO
	 STOPCD	<NAS3R0 (dest) failed in NANCW5>
	XMOVEI	P1,.IONSF(IO)	;ADDRESS OF "SOURCE" NPD STUFF
	PUSHJ	P,NAS3R0	;DECODE SOURCE INFO
	 STOPCD	<NAS3R0 (source) failed in NANCW5>
	XMOVEI	P1,.IONUS(IO)	;ADDRESS OF USER ID STRING BLOCK
	PUSHJ	P,NAS2R0	;DECODE USER ID
	 STOPCD	<NAS2R0 (userid) failed in NANCW5>
	XMOVEI	P1,.IONPW(IO)	;ADDRESS OF PASSWORD STRING BLOCK
	PUSHJ	P,NAS2R0	;DECODE PASSWORD
	 STOPCD	<NAS2R0 (password) failed in NANCW5>
	XMOVEI	P1,.IONAC(IO)	;ADDRESS OF ACCOUNT STRING BLOCK
	PUSHJ	P,NAS2R0	;DECODE ACCOUNT STRING
	 STOPCD	<NAS2R0 (account) failed in NANCW5>
	XMOVEI	P1,.IONUD(IO)	;ADDRESS OF USER DATA STRING BLOCK
	PUSHJ	P,NAS2R0	;DECODE USER DATA
	 STOPCD	<NAS2R0 (usrdata) failed in NANCW5>

;ALL CONNECT INFO RETURNED

	JRST	.POPJ1##	;RETURN SUCCESSFULLY
;HERE FOR DECNET CONNECT WAIT

NDNCW1:	TXNE	T1,IO.NEP	;NETWORK PASSIVE CHANNEL?
	JRST	NDNCW3		;YES

;HERE TO WAIT FOR ACTIVE LINK TO BE READY

	XMOVEI	P3,.IONUD(IO)	;OPTIONAL CONNECT CONFIRM DATA BLOCK ADDRESS
	MOVEI	M0,$NTSBL	;MAXIMUM "STRING BLOCK LENGTH"
	HRRM	M0,@P3		;SET DATA BLOCK MAXIMUM WORD COUNT
	MOVE	P1,[NS.WAI!<.NSFRC,,.NSAA1+1>]  ;READ CONNECT INFO
	XMOVEI	M0,P1		;ADDRESS OF NSP. ARG BLOCK TO
	NSP.	M0,		;READ CONNECT CONFIRM DATA, WAIT IF NEEDED
	 JRST	NDCXE1		;FAILED
	LDB	P2,[POINTR P2,NS.STA]  ;GET CURRENT LINK STATE
	CAIN	P2,.NSSRN	;LINK STATE READY?
	JRST	.POPJ1##	;YES, LINK IS UP AND RUNNING, ALL SET THEN
	MOVEI	M0,NSRBO%	;ASSUME CONNECT REJECTED
	CAIN	P1,.NSSDR	;"DISCONNECT RECEIVED"?
	JRST	NDCXE1		;PROCESS "NSP. ERROR"
	STOPCD	<Funny state in active NDNCW>



;HERE TO WAIT FOR PASSIVE LINK TO BE READY
;
;ASSUMES CONNECT BLOCK IS CORRECTLY SETUP BY NTNIP

NDNCW3:	XMOVEI	P3,.I1NSC(IO)	;CONNECT BLOCK ADDRESS
	MOVE	P1,[NS.WAI!<.NSFRI,,.NSAA1+1>]  ;READ CONNECT INIT ARGUMENT
	XMOVEI	M0,P1		;NSP. ARG POINTER TO
	NSP.	M0,		;READ CONNECT INIT DATA
	 JRST	NDCXE1		;FAILED
	PUSHJ	P,TSAV12##	;SAVE T2
	MOVEI	P4,.IONNM	;8-BIT NODE NAME OFFSET
	PUSHJ	P,N8TO6		;MAKE A 6-BIT NAME OUT OF IT
	 JFCL			;DUH?
	MOVEM	T2,.ION6M(IO)	;SET 6-BIT NAME FOR INTERESTED PARTIES
	JRST	.POPJ1##	;RETURN WITH PASSIVE CONNECTION READY
;ANF SUBROUTINES FOR NANCW

;NAS0R0 - READ NEXT NPD BYTE

NAS0R0:	SOSGE	P3		;ANY MORE DATA?
	TDZA	T1,T1		;NO, RETURN A NULL
	ILDB	T1,P4		;YES, RETURN NEXT NPD BYTE
	POPJ	P,		;RETURN



;NAS0R3 - READ OCTAL NPD SUBSTRING

NAS0R3:	SETZ	T2,		;INITIALIZE OCTAL VALUE
NAS0R4:	PUSHJ	P,NAS0R0	;READ NEXT BYTE
	CAIL	T1,"0"		;IS IT OCTAL?
	CAILE	T1,"7"		; . . .
	POPJ	P,		;NO, END OF SUBSTRING
	LSH	T1,^D33		;YES, POSITION AND
	ROTC	T1,^D03		;ACCUMULATE OCTAL OBJECT TYPE
	JRST	NAS0R4		;READ IN REST OF OBJECT TYPE



;NAS2R0 - READ STRING

NAS2R0:	SETZ	T3,		;INITIALIZE ACTUAL BYTE COUNTER
	MOVE	T4,[POINT 8,1(P1)]  ;AND BYTE POINTER
NAS2R1:	PUSHJ	P,NAS0R0	;READ NEXT BYTE
	JUMPE	T1,NAS2R3	;NULL TERMINATES STRING
	IDPB	T1,T4		;ACCUMULATE STRING
	AOJA	T3,NAS2R1	;AND COUNT IT UP

NAS2R3:	HRLM	T3,0(P1)	;STORE ACTUAL BYTE COUNT
	JRST	.POPJ1##	;SUCCESSFUL RETURN
;NAS3R0 - READ ENCODED NPD STRING

NAS3R0:	PUSHJ	P,NAS0R3	;READ IN OCTAL SUBSTRING
	HRRZM	T2,0(P1)	;ASSUME FORMAT = 0; OBJECT TYPE RETURNED
	JUMPE	T1,.POPJ1##	;IF FORMAT 0 THEN ALL DONE
	CAIE	T1,"."		;ELSE MUST HAVE PUNCTUATION HERE
	STOPCD	<Junk encoded NPD string in NAS3R3>
	MOVE	T2,P4		;PRESERVE COPY OF BYTE POINTER
	PUSHJ	P,NAS0R0	;READ FIRST "NAME" STRING CHARACTER
	CAIN	T1,"["		;LOOK LIKE A PPN?
	JRST	NAS3R5		;YUP, MUST BE FORMAT 2

;FORMAT 1, SIMPLE NAME

NAS3R3:	MOVEI	T1,1		;TASK NAME COMING UP, FORMAT TYPE 1
	HRLM	T1,0(P1)	;SET NEW FORMAT TYPE
	ADDI	P1,.IONDN-.IONDF;SET P1 TO TASK NAME STRING BLOCK
	MOVE	P4,T2		;RESTORE BYTE POINTER TO FIRST NAME CHAR
	AOJA	P3,NAS2R0	;AND READ NAME STRING

;FORMAT 2 - PPN AND NAME

NAS3R5:	ADDI	P1,.IONDP-.IONDF;RELOCATE P1 TO PPN WORD
	PUSHJ	P,NAS0R3	;READ IN OCTAL SUBSTRING (PROJECT)
	CAIE	T2,0		;MUST NOT BE BLANK
	CAIE	T1,","		;AND MUST BE PROPERLY PUNCTUATED
	STOPCD	<Junk encoded project NPD string in NAS3R5>
	HRLM	T2,0(P1)	;STORE PROJECT NUMBER
	PUSHJ	P,NAS0R3	;READ IN ANOTHER OCTAL SUBSTRING (PROGRAMMER)
	CAIE	T2,0		;MUST NOT BE BLANK
	CAIE	T1,"]"		;AND MUST BE PROPERLY PUNCTUATED
	STOPCD	<Junk encoded programmer NPD string in NAS3R5>
	HRRM	T2,0(P1)	;STORE PROGRAMMER NUMBER
	ADDI	P1,.IONDN-.IONDP;RELOCATE P1 TO NAME STRING BLOCK
	JRST	NAS2R0		;AND READ REMAINING NPD NAME STRING
;NTNCA  --  PASSIVE CHANNEL CONNECT ACCEPT
;CALL IS:
;
;	MOVX	T1,<CDB>
;	MOVX	T3,<DAT>
;	PUSHJ	P,NTNCA
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O CDB; and <DAT> is the address
;of any optional connect data to be sent as part of the connect accept
;(must be 0 if no optional data).
;
;On error return the network aborted.
;
;On successful return the network channel is "up and running". Normal
;communications may take place.
;
;Uses T1, T2, T3, T4.

	ENTRY	.NTNCA
	INTERN	NTNCA0,	NTNCA1

.NTNCA:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
NTNCA0:	PUSHJ	P,.SAVE4##	;SAVE SOME ACS
NTNCA1:	SKIPN	P2,.IONCH(IO)	;ASSURE NETWORK CHANNEL
	STOPCD	<No network channel in NTNCA>
	MOVE	T1,.IOCCF(IO)	;CHANNEL CONTROL
	TXNE	T1,IO.ANF	;ANF NETWORK CHANNEL?
	JRST	NANCA1		;YES
	TXNE	T1,IO.DCN	;DECNET NETWORK CHANNEL?
	JRST	NDNCA1		;YES
	STOPCD	<Neither ANF nor DECnet in NTNCA>
;HERE FOR ANF CONNECT ACCEPT

NANCA1:	JRST	.POPJ1##	;CONFIRM FAIT ACCOMPLI



;HERE FOR DECNET CONNECT ACCEPT

NDNCA1:	MOVE	P3,T3		;OPTIONAL USER CONNECT DATA
	MOVE	P1,[.NSFAC,,.NSAA1+1]  ;"ACCEPT CONNECT" FUNCTION
	XMOVEI	M0,P1		;NSP. ARG POINTER TO
	NSP.	M0,		;ACCEPT THE CONNECT INITIATE
	 JRST	NDCXE1		;FAILED, CLEAN UP
	JRST	.POPJ1##	;CHANNEL UP AND RUNNING
;NTNCR  --  PASSIVE CHANNEL CONNECT REJECT
;CALL IS:
;
;	MOVX	T1,<CDB>
;	MOVX	T2,<DAT>
;	MOVX	T3,<RSN>
;	PUSHJ	P,NTNCR
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O CDB; <RSN> is the NSP reason why
;the connection is being rejected; and <DAT> is the address
;of any optional connect data to be sent as part of the connect reject
;(must be 0 if no optional data).
;
;On error return the network aborted.
;
;On successful return the connect initiate has been rejected. The
;network channel has been aborted and released.
;
;Uses T1, T2, T3, T4.

	ENTRY	.NTNCR
	INTERN	NTNCR0,	NTNCR1

.NTNCR:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
NTNCR0:	PUSHJ	P,.SAVE4##	;SAVE SOME ACS
NTNCR1:	SKIPN	P2,.IONCH(IO)	;ASSURE NETWORK CHANNEL
	STOPCD	<No network channel in NTNCR>
	MOVE	T1,.IOCCF(IO)	;CHANNEL CONTROL
	TXNE	T1,IO.ANF	;ANF NETWORK CHANNEL?
	JRST	NANCR1		;YES
	TXNE	T1,IO.DCN	;DECNET NETWORK CHANNEL?
	JRST	NDNCR1		;YES
	STOPCD	<Neither ANF nor DECnet in NTNCR>
;HERE FOR ANF CONNECT REJECT

NANCR1:	MOVEI	P3,100(T3)	;POSITION "ABORT" CODE
	MOVEI	P1,.TKFEI	;FUNCTION: ENTER IDLE STATE (DISCONNECT)
	MOVE	M0,[3,,P1]	;TSK. ARG POINTER TO
	TSK.	M0,		;BREAK (SEND DISCONNECT) THE NET LINK
	 JRST	NANAB1		;ABORT THE LINK
	PJRST	NTNRL1		;AND RELEASE THE TASK CHANNEL
				; (CONSISTENT WITH SILLY DECNET NSP. UUO)



;HERE FOR DECNET CONNECT REJECT

NDNCR1:	DMOVE	P3,T2		;OPTIONAL USER REJECT DATA, REASON
	MOVE	P1,[.NSFRJ,,.NSAA2+1]  ;"REJECT CONNECT" FUNCTION
	XMOVEI	M0,P1		;NSP. ARG POINTER TO
	NSP.	M0,		;REJECT THE CONNECT INITIATE
	 PJRST	NTNRL1		;HUH?? WE DON'T WANT IT!!!!!
	PJRST	NTFIN1		;MARK NETWORK CHANNEL DEFUNCT
	SUBTTL	Network Link Control - Link management

;NTNRS  --  RETURN NETWORK CHANNEL STATUS
;CALL IS:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,NTNRS
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O CDB.
;
;On error return the network died.
;
;On normal return the network status is returned in T2.
;
;Uses T1, T2, T3, T4.

	ENTRY	.NTNRS
	INTERN	NTNRS0,	NTNRS1

.NTNRS:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
NTNRS0:	PUSHJ	P,.SAVE4##	;NEED SOME ACS
NTNRS1:	STOPCD	<NTNRS called but not yet implemented>
	SKIPN	P2,.IONCH(IO)	;ASSURE NETWORK CHANNEL
	STOPCD	<No network channel in NTNRS>
	MOVE	T1,.IOCCF(IO)	;CHANNEL CONTROL
	TXNE	T1,IO.ANF	;ANF NETWORK CHANNEL?
	JRST	NANRS1		;YES
	TXNE	T1,IO.DCN	;DECNET NETWORK CHANNEL?
	JRST	NDNRS1		;YES
	STOPCD	<Neither ANF nor DECnet in NTNRS>
;HERE FOR ANF RETURN STATUS

NANRS1:	HALT



;HERE FOR DECNET RETURN STATUS

NDNRS1:	MOVE	P1,[.NSFRS,,.NSAA1+1]  ;"READ STATE" FUNCTION
	XMOVEI	M0,P1		;NSP. ARG POINTER TO
	NSP.	M0,		;READ NETWORK STATE
	 JRST	NDRXE1		;CONVERT ERROR CODE
	MOVE	T2,P3		;RETURN STATE IN T2
	HALT
;NTNSQ  --  SET NETWORK CHANNEL QUOTA AND PERCENTAGES
;CALL IS:
;
;	MOVX	T1,<CDB>
;	MOVX	T2,<QTA>
;	MOVX	T3,<PCT>
;	PUSHJ	P,NTNSQ
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O CDB; <QTA> is the "link quota"
;for the current network channel; <PCT> is the relative percentage of
;the link quota to be devoted to input buffering (integer range 1 to 99).
;
;On error return the monitor would not accept the range specified; error
;code is in M0.
;
;On normal return the channel parameters have been set as requested.
;
;Uses T1, T2, T3, T4.

	ENTRY	.NTNSQ
	INTERN	NTNSQ0,	NTNSQ1

.NTNSQ:	PUSHJ	P,.SACIO##	;SWITCH TO IO CONTEXT
NTNSQ0:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
NTNSQ1:	SKIPN	P2,.IONCH(IO)	;GET NETWORK CHANNEL
	STOPCD	<No network channel in NTNSQ>
	MOVE	T1,.IOCCF(IO)	;GET CHANNEL CONTROL FLAGS
	TXNE	T1,IO.ANF	;ANF NETWORK PROTOCOL?
	JRST	NANSQ1		;YES
	TXNE	T1,IO.DCN	;DECNET NETWORK PROTOCOL?
	JRST	NDNSQ1		;YES
	STOPCD	<Neither ANF nor DECnet in NTNSQ>
;HERE FOR ANF SET LINK QUOTAS

NANSQ1:	JRST	.POPJ1##	;SO MUCH FOR THAT



;HERE FOR DECNET SET LINK QUOTAS

NDNSQ1:	MOVE	P1,[.NSFSQ,,.NSAA2+1]  ;NSP. FUNCTION WORD
	SKIPG	P3,T2		;LINK QUOTA
	SETO	P3,		;NONE SPECIFIED
	SKIPG	P4,T3		;RELATIVE PERCENT INPUT
	SETO	P4,		;NONE SPECIFIED
	XMOVEI	M0,P1		;NSP. ARG POINTER TO
	NSP.	M0,		;SET LINK QUOTA AND PERCENTAGE
	 JRST	NDRXE1		;FAILED?
	JRST	.POPJ1##	;SUCCESSFUL RETURN
	SUBTTL	Network Link Control - Link termination

;NTNSD  --  NETWORK DISCONNECT
;CALL IS:
;
;	MOVE	T1,<CDB>
;	MOVX	T3,<DAT>
;	PUSHJ	P,NTNSD
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O <CDB>; <RSN> is the NSP reason
;code for why the network link is disconnecting;  and <DAT> is the address
;of any optional disconnect data to be sent as part of the disconnect
;process (must be 0 if no optional data).
;
;On error return the network died.
;
;On successful return the disconnect has been sent (but the network
;channel is still "active" and able to receive data sent by the other
;side).
;
;Uses T1, T2, T3, T4.

	ENTRY	.NTNSD
	INTERN	NTNSD0,	NTNSD1

.NTNSD:	PUSHJ	P,.SACIO##	;SETUP I/O CDB ADDRESS
NTNSD0:	PUSHJ	P,.SAVE4##	;SAVE A FEW ACS
NTNSD1:	SKIPN	P2,.IONCH(IO)	;ASSURE NETWORK CHANNEL
	STOPCD	<No network channel in NTNSD>
	MOVE	T1,.IOCCF(IO)	;CHANNEL CONTROL
	TXNE	T1,IO.ANF	;ANF NETWORK CHANNEL?
	JRST	NANSD1		;YES
	TXNE	T1,IO.DCN	;DECNET NETWORK CHANNEL?
	JRST	NDNSD1		;YES
	STOPCD	<Neither ANF nor DECnet in NTNSD>
;HERE FOR ANF SYNCHRONOUS DISCONNECT

NANSD1:	MOVX	P1,.TKFEI	;FUNCTION: ENTER "IDLE" STATE
	MOVE	T1,[2,,P1]	;TSK. ARG POINTER TO
	TSK.	T1,		;SEND A DISCONNECT INITIATE
	 JRST	NARXE1		;CONVERT TSK. ERROR CODE
	JRST	.POPJ1##	;SUCCESSFUL



;HERE FOR DECNET SYNCHRONOUS DISCONNECT

NDNSD1:	MOVE	P3,T3		;OPTIONAL USER DATA
	MOVE	P1,[.NSFSD,,.NSAA1+1]  ;"SYCHRONOUS DISCONNECT" FUNCTION
	XMOVEI	M0,P1		;NSP. ARG POINTER TO
	NSP.	M0,		;SEND DISCONNECT INITIATE
	 JRST	NDRXE1		;CONVERT ERROR CODE
	JRST	.POPJ1##	;SUCCESSFUL RETURN
;NTNAB  --  NETWORK ABORT
;CALL IS:
;
;	MOVE	T1,<CDB>
;	MOVX	T3,<DAT>
;	PUSHJ	P,NTNAB
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O <CDB>; <RSN> is the NSP reason
;code for aborting the network link; and <DAT> is the address
;of any optional disconnect data to be sent as part of the disconnect
;and abort process (must be 0 if no optional data).
;
;On error return the network died.
;
;On successful return the network channel has been aborted and
;released.
;
;Uses T1, T2, T3, T4.

	ENTRY	.NTNAB
	INTERN	NTNAB0,	NTNAB1

.NTNAB:	PUSHJ	P,.SACIO##	;SETUP I/O CDB ADDRESS
NTNAB0:	PUSHJ	P,.SAVE4##	;SAVE A FEW ACS
NTNAB1:	SKIPN	P2,.IONCH(IO)	;ASSURE NETWORK CHANNEL
	STOPCD	<No network channel in NTNAB>
	MOVE	T1,.IOCCF(IO)	;CHANNEL CONTROL
	TXNE	T1,IO.ANF	;ANF NETWORK CHANNEL?
	JRST	NANAB1		;YES
	TXNE	T1,IO.DCN	;DECNET NETWORK CHANNEL?
	JRST	NDNAB1		;YES
	STOPCD	<Neither ANF nor DECnet in NTNAB>
;HERE FOR ANF ABORT

NANAB1:	RESDV.	P2,		;ZAPETH THE I/O CHANNEL DEAD
	 JFCL			;HUH?
	PJRST	NTFIN1		;AND CLEAN OUT THE NETWORK DATABASE



;HERE FOR DECNET ABORT

NDNAB1:	MOVE	P3,T3		;OPTIONAL USER DATA
	MOVE	P1,[.NSFAB,,.NSAA1+1]  ;"ABORT" FUNCTION
	XMOVEI	M0,P1		;NSP. ARG POINTER TO
	NSP.	M0,		;ABORT THE CHANNEL
	 PJRST	NTNRL1		;HUH?? BY DAMN, GET RID OF THE BLOODY THING
	PJRST	NTFIN1		;MARK THE NETWORK CHANNEL DEFUNCT
;NTNRD  --  READ DISCONNECT REASON AND OPTIONAL DATA
;CALL IS:
;
;	MOVX	T1,<CDB>
;	MOVX	T3,<ADR>
;	PUSHJ	P,NTNRD
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O CDB; and <ADR> is the address
;to receive any optional user disconnect data (returned in 8-bit format).
;
;The error return is taken if ???
;
;On normal return, any "Optional User Data" has been read into the
;specified string block in normal 8-bit format. The disconnect reason
;(as supplied by the network services) is returned in T2.
;
;Uses T1, T2, T3, T4.

	ENTRY	.NTNRD
	INTERN	NTNRD0,	NTNRD1

.NTNRD:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
NTNRD0:	PUSHJ	P,.SAVE4##	;SAVE A FEW ACS
NTNRD1:	SKIPN	P2,.IONCH(IO)	;ASSURE NETWORK CHANNEL
	STOPCD	<No network channel in NTNRD>
	MOVE	T1,.IOCCF(IO)	;CHANNEL CONTROL
	TXNE	T1,IO.ANF	;ANF NETWORK CHANNEL?
	JRST	NANRD1		;YES
	TXNE	T1,IO.DCN	;DECNET NETWORK CHANNEL?
	JRST	NDNRD1		;YES
	STOPCD	<Neither ANF nor DECnet in NTNRD>
;HERE FOR ANF READ DISCONNECT REASON

NANRD1:	JRST	.POPJ1##	;SO MUCH FOR THAT



;HERE FOR DECNET READ DISCONNECT REASON

NDNRD1:	MOVE	P3,T3		;ADDRESS OF "STRING" BLOCK
	MOVE	P1,[.NSFRC,,.NSAA2+1]  ;READ DISCONNECT DATA
	XMOVEI	M0,P1		;NSP. ARG POINTER TO
	NSP.	M0,		;READ OPTIONAL DISCONNECT DATA
	 JRST	NDRXE1		;CONVERT ERROR CODE
	MOVE	T2,P3		;RETURN DISCONNECT REASON
	JRST	.POPJ1##	;SUCCESSFUL RETURN
;NTNRL  --  RELEASE NETWORK CHANNEL
;CALL IS:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,NTNRL
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O CDB.
;
;On error return the network died first.
;
;On normal return the network channel has been released.
;
;Uses T1, T2, T3, T4.

	ENTRY	.NTNRL
	INTERN	NTNRL0,	NTNRL1

.NTNRL:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
NTNRL0:	PUSHJ	P,.SAVE4	;SAVE SOME ACS
NTNRL1:	SKIPN	P2,.IONCH(IO)	;ASSURE NETWORK CHANNEL
	STOPCD	<No network channel in NTNRL>
	MOVE	T1,.IOCCF(IO)	;CHANNEL CONTROL
	TXNE	T1,IO.ANF	;ANF NETWORK CHANNEL?
	JRST	NANRL1		;YES
	TXNE	T1,IO.DCN	;DECNET NETWORK CHANNEL?
	JRST	NDNRL1		;YES
	STOPCD	<Neither ANF nor DECnet in NTNRL>
;HERE FOR ANF RELEASE

NANRL1:	MOVS	P1,P2		;POSITION CHANNEL IN LH FOR FILOP.
	HRRI	P1,.FOREL	;FUNCTION: RELEASE
	MOVE	T1,[1,,P1]	;FILOP. ARG POINTER TO
	FILOP.	T1,		;RELEASE TSK CHANNEL
	 PJRST	NTZAP1		;*** HO HUM, JUST BLOW IT AWAY
	PJRST	NTFIN1		;CLEAN OUT THE NETWORK DATABASE



;HERE FOR DECNET RELEASE

NDNRL1:	MOVE	P1,[.NSFRL,,.NSACH+1]  ;"RELEASE CHANNEL" FUNCTION
	XMOVEI	M0,P1		;NSP. ARG POINTER TO
	NSP.	M0,		;RELEASE THE CHANNEL
	 JRST	NDRXE1		;ERROR, CONVERT CODE
	JRST	NTFIN1		;FINISH OFF THE NETWORK
;NTZAP  --  ZAP A NETWORK CHANNEL
;CALL IS:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,NTZAP
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O CDB.
;
;NTZAP is used to unconditionally "ZAP" any network I/O in progress.
;If the CDB is not currently network-active, NTZAP simply returns. If
;any network activity is pending, it is thrown away, the network link
;(or channel if you prefer) is RELEASed/RESET, I/O buffers are de-al-
;located, and so on.
;
;NTZAP should be used as a unknown-state cleanup mechanism which doesn't
;care what happens, just as long as the CDB is cleaned up. Errors are
;suppressed.
;
;The error return is not utilized.
;
;On normal return, any network I/O has been RESET, buffers deallocated,
;and the CDB cleaned up (network-wise).
;
;Uses T1, T2, T3, T4.

	ENTRY	.NTZAP
	INTERN	NTZAP0,	NTZAP1

.NTZAP:	PUSHJ	P,.SACIO##	;SWITCH TO I/O CONTEXT
NTZAP0:	PUSHJ	P,.SAVE4##	;PRESERVE THE PRESERVED REGISTERS
NTZAP1:				;FEEL FREE TO TRASH THE TEMPS
	SKIPN	P2,.IONCH(IO)	;GOT A NETWORK CHANNEL IN USE?
	PJRST	NTFIN6		;NO, JUST BLAST SOME BITS ON G.P.'S
	MOVE	T1,.IOCCF(IO)	;CHANNEL CONTROL
	TXNE	T1,IO.ANF	;ANF NETWORK CHANNEL?
	JRST	NAZAP1		;YES
	TXNE	T1,IO.DCN	;DECNET NETWORK CHANNEL?
	JRST	NDZAP1		;YES
	STOPCD	<Neither ANF nor DECnet in NTZAP>
;HERE FOR ANF ZAP

NAZAP1:	RESDV.	P2,		;STOMPETH UPON WHATEVER IS THERE
	 JFCL			;WELL, I TRIED!
	PJRST	NTFIN1		;CLEAN OUT THE NETWORK DATABASE



;HERE FOR DECNET ZAP

NDZAP1:	MOVE	P1,[.NSFRL,,.NSACH+1]  ;"RELEASE CHANNEL" FUNCTION
	XMOVEI	M0,P1		;NSP. ARG POINTER TO
	NSP.	M0,		;RELEASE THE CHANNEL
	 JFCL			;WELL, I TRIED!
	JRST	NTFIN1		;FINISH OFF THE NETWORK
	SUBTTL	Network Link Control - Support routines

;NTINI - COMMON ACTIVE/PASSIVE NETWORK COMMUNICATIONS INITIALIZATION

	ENTRY	.NTINI
	INTERN	NTINI0,	NTINI1

.NTINI:	PUSHJ	P,.SACIO##	;SET UP I/O CDB INDEX
NTINI0:	PUSHJ	P,.SAVE4##	;SAVE THE P'S
NTINI1:	PUSHJ	P,TSAV14##	;SAVE THE T'S, ON G.P.S
	SKIPN	P2,.IONCH(IO)	;ASSURE NETWORK CHANNEL
	STOPCD	<No network channel in NTINI>
	MOVE	T1,.IOCCF(IO)	;CHANNEL CONTROL
	TXNE	T1,IO.ANF	;ANF NETWORK CHANNEL?
	JRST	NAINI1		;YES
	TXNE	T1,IO.DCN	;DECNET NETWORK CHANNEL?
	JRST	NDINI1		;YES
	STOPCD	<Neither ANF nor DECnet in NTINI>
;HERE FOR ANF INITIALIZATION

NAINI1:	TXNE	T1,IO.NBA	;NETWORK BUFFERS ALLOCATED?
	STOPCD	<IO.NBA in NAINI1>

;ALLOCATE NETWORK INPUT AND OUTPUT BUFFERS

NAINI2:	MOVEI	P1,.TKFRX	;FUNCTION: READ STATUS AND MESSAGE SIZES
	SETZB	P3,P4		;JUST TO MAKE SURE . . .
	MOVE	T1,[4,,P1]	;TSK. ARG POINTER TO
	TSK.	T1,		;READ STATE OF TASK CHANNEL
	 JRST	[MOVEI	P1,.TKFRS	;FUNCTION: READ STATUS
		MOVE	T1,[3,,P1]	;TSK. ARG POINTER TO
		TSK.	T1,		;READ STATE OF TASK CHANNEL
		 STOPCD <TSK. (.TKFRS) failed in NAINI2>
		MOVEI	P4,$NABFS	;FAKE UP A DEFAULT SEGMENT SIZE
		JRST	.+1]		;CONTINUE ONWARDS
	CAIE	P3,.TKSOK	;IS THE LINK "UP AND RUNNING"?
	JRST	[CAIE	P3,.TKSID	;"IDLE" (RECEIVED DISCONNECT)?
		STOPCD	<Network link status not "RUNNING" in NAINI>
		JRST	NARXS1]		;TRANSLATE DISCONNECT REASON
	ANDI	P4,-1		;WANT JUST MESSAGE LENGTH (IGNORE RLN FIELD)
	MOVEM	P4,.IONLB(IO)	;SET NETWORK BUFFER SIZE (8-BIT BYTES)
	MOVEM	P4,.IONLM(IO)	;WHICH IS ALSO PRELIMINARY MAXIMUM MESSAGE SIZE
	ADDI	P4,3		;ROUND UP, AND
	LSH	P4,-2		;TRUNCATE TO -10 WORD COUNT
	MOVEM	P4,.IONLW(IO)	;SET NETWORK BUFFER SIZE (-10 WORDS)
	MOVSI	T2,$NAIBF	;NUMBER OF INPUT BUFFERS TO USE
	HRRI	T2,$NAIBX(P4)	;SIZE OF INDIVIDUAL INPUT BUFFER
	XMOVEI	T4,.IONIH(IO)	;ADDRESS OF INPUT BUFFER RING HEADER
	PUSHJ	P,IOBFA1##	;ALLOCATE INPUT BUFFERS
	 STOPCD	<Can't allocate ANF input buffer(s)>
	DMOVEM	T2,.IONIB(IO)	;SAVE BUFFER ID FOR DEALLOCATION
	MOVSI	T2,1		;ALWAYS USE ONE OUTPUT BUFFER (IT'S A LONG
				; STORY, THAT'S JUST THE WAY TOPS10 WORKS)
	HRR	T2,P4		;SIZE OF INDIVIDUAL OUTPUT BUFFER
	XMOVEI	T4,.IONOH(IO)	;ADDRESS OF OUTPUT BUFFER RING HEADER
	PUSHJ	P,IOBFA1##	;ALLOCATE OUTPUT BUFFERS
	 STOPCD	<Can't allocate ANF output buffer(s)>
	DMOVEM	T2,.IONOB(IO)	;SAVE BUFFER ID FOR DEALLOCATION
	MOVX	T1,BF.IBC	;THE INHIBIT-BUFFER-CLEARING BIT
	IORM	T1,.IONOH(IO)	;LEAVE MY BUFFER ALONE!!!
	MOVX	T1,IO.NBA	;THE NETWORK-BUFFERS-ALLOCATED BIT
	IORM	T1,.IOCCF(IO)	;SET IN CDB
	MOVX	T1,NS.EOM	;THE END-OF-MESSAGE FLAG
	MOVEM	T1,.IONIS(IO)	;PRESET FOR RNMSG
	JRST	.POPJ1##	;READY FOR ANF NETWORK I/O
;HERE FOR DECNET INITIALIZATION

NDINI1:	TXNE	T1,IO.NBA	;NETWORK BUFFERS ALLOCATED?
	JRST	NDINI6		;YES, JUST RESET COUNTERS

;ALLOCATE NETWORK INPUT AND OUTPUT BUFFERS

NDINI2:	MOVE	P1,[.NSFRS,,.NSAA2+1]  ;RETURN STATUS FUNCTION
	SETZB	P3,P4		;ON G.P.'S
	XMOVEI	M0,P1		;NSP. ARG POINTER TO
	NSP.	M0,		;READ NETWORK MESSAGE SEGMENT SIZE
	 JRST	NDRXE1		;OOPS
	LDB	T1,[POINTR P2,NS.STA]  ;EXTRACT THE LINK STATE
	CAIE	T1,.NSSRN	;LINK HAD BETTER BE "RUNNING" AT THIS POINT
	STOPCD	<Network link status not "RUNNING" in NDINI>
	MOVEM	P3,.IONLB(IO)	;SET NETWORK BUFFER SIZE (8-BIT BYTES)
	MOVEM	P3,.IONLM(IO)	;WHICH IS ALSO PRELIMINARY MAXIMUM MESSAGE SIZE
	ADDI	P3,3		;ROUND UP, AND
	LSH	P3,-2		;TRUNCATE TO -10 WORD COUNT
	MOVEM	P3,.IONLW(IO)	;SET NETWORK BUFFER SIZE (-10 WORDS)
	MOVE	T1,P3		;NETWORK BUFFER LENGTH (-10 WORDS)
	LSH	T1,1		;ONE INPUT, AND ONE OUTPUT BUFFER
	SKIPN	T2,.IOXFF(IO)	;DOES THE CDB HAVE ANY EXTRA SPACE?
	JRST	NDINI3		;NO, MUST ALLOCATE FROM MANAGED MEMORY
	ADD	T2,T1		;YES, T2:=PROPOSED NEW .IOXFF
	CAML	T2,.IOXSZ(IO)	;WILL THE TWO BUFFERS FIT?
	JRST	NDINI3		;NO, MUST ALLOCATE FROM MANAGED MEMORY
	EXCH	T2,.IOXFF(IO)	;YES, GLOM ONTO IT
	ADD	T2,IO		;RELOCATE INTO PHYSICAL (RELATIVELY) MEMORY
	JRST	NDINI4		;SET ADDRESS(S)

;ALLOCATE BUFFERS FROM MANAGED MEMORY

NDINI3:	PUSHJ	P,.MMGWD##	;ALLOCATE SOME MANAGED MEMORY
	 STOPCD	<Network buffer memory allocation failed in NDINI3>

NDINI4:	SETZM	(T2)		;CLEAR START OF BUFFER
	HRLZ	M0,T2		;CONCOCT A
	HRRI	M0,1(T2)	; BLT POINTER TO
	MOVE	T1,.IONLW(IO)	;LENGTH OF ONE BUFFER (-10 WORDS)
	LSH	T1,1		;ALLOW FOR TWO BUFFERS
	ADD	T1,T2		;T1:=END (+1) OF NETWORK BUFFERS
	BLT	M0,-1(T1)	;CLEAR NETWORK BUFFERS
	MOVEM	T2,.IONIB(IO)	;SET ADDRESS OF NETWORK INPUT BUFFER
	ADD	T2,.IONLW(IO)	;OFFSET TO NEXT BUFFER
	MOVEM	T2,.IONOB(IO)	;WHICH BECOMES THE NETWORK OUTPUT BUFFER
	MOVX	T1,IO.NBA	;THE NETWORK-BUFFERS-ALLOCATED BIT
	IORM	T1,.IOCCF(IO)	;SET IN THE CDB

NDINI6:	MOVX	T1,NS.EOM	;END-OF-MESSAGE-SEEN FLAG
	MOVEM	T1,.IONIS(IO)	;PRESET TO KEEP RNMSG HAPPY
	SETZM	.IONIC(IO)	;CURRENTLY HAVE NO INPUT DATA BYTES
	PJRST	XDBUF6		;SETUP OUTPUT BUFFER COUNTER/POINTER
;NTFIN - FINISH OFF THE NETWORK CHANNEL

	ENTRY	.NTFIN
	INTERN	NTFIN0,	NTFIN1

.NTFIN:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
NTFIN0:	PUSHJ	P,.SAVE4##	;PROTECT THE P'S
NTFIN1:	MOVE	T1,.IOCCF(IO)	;CHANNEL CONTROL FLAGS
	SETZM	.IONCH(IO)	;NOTE NO MORE CHANNEL
	SETZM	.ION6M(IO)	; . . .
	TXNE	T1,IO.ANF	;ANF NETWORK CHANNEL?
	JRST	NAFIN1		;YES
	TXNE	T1,IO.DCN	;DECNET NETWORK CHANNEL?
	JRST	NDFIN1		;YES
	STOPCD	<Neither ANF nor DECnet in NTFIN>
;HERE FOR ANF CLEANUP

NAFIN1:	TXNN	T1,IO.NBA	;NETWORK BUFFERS ALLOCATED?
	JRST	NAFIN6		;NO, NOTHING TO DEALLOCATE
	DMOVE	T2,.IONOB(IO)	;OUTPUT BUFFER ID
	XMOVEI	T4,.IONOH(IO)	;ADDRESS OF OUTPUT BUFFER RING HEADER
	PUSHJ	P,IOBFZ1##	;DEALLOCATE THE OUTPUT BUFFERS
	 STOPCD	<Can't deallocate ANF output buffer(s)>
	DMOVE	T2,.IONIB(IO)	;INPUT BUFFER ID
	XMOVEI	T4,.IONIH(IO)	;ADDRESS OF INPUT BUFFER RING HEADER
	PUSHJ	P,IOBFZ1##	;DEALLOCATE THE INPUT BUFFERS
	 STOPCD	<Can't deallocate ANF input buffer(s)>
NAFIN6:	PJRST	NTFIN6		;FINAL CLEAN UP
;HERE FOR DECNET CLEANUP

NDFIN1:	TXNN	T1,IO.NBA	;NETWORK BUFFERS ALLOCATED?
	JRST	NDFIN6		;NO, NOTHING TO DEALLOCATE
	SKIPLE	T2,.IONIB(IO)	;ADDRESS OF NETWORK INPUT BUFFER
	CAIGE	T2,.JBDA	;REASONABLE ADDRESS?
	STOPCD	<Network input buffer trashed in NDFIN1>
	SKIPLE	T3,.IONOB(IO)	;ADDRESS OF NETWORK OUTPUT BUFFER
	CAIGE	T2,.JBDA	;REASONABLE ADDRESS?
	STOPCD	<Network output buffer trashed in NDFIN1>
	SUB	T3,.IONLW(IO)	;BACK UP ONE BUFFERS' WORTH
	CAMN	T2,T3		;ARE THE TWO BUFFERS ADJACENT?
	JRST	NDFIN3		;YES

;RANDOM BUFFER ALLOCATION, MUST HAVE COME FROM MANAGED MEMORY AS SEPARATE HUNKS

	MOVE	T1,.IONLW(IO)	;SIZE OF ONE NETWORK BUFFER
	PUSHJ	P,.MMFWD##	;FREE UP NETWORK INPUT BUFFER
	 STOPCD	<Network input buffer deallocation failed in NDFIN1>
	MOVE	T1,.IONLW(IO)	;SIZE OF ONE NETWORK BUFFER
	MOVE	T2,.IONOB(IO)	;ADDRESS OF OUTPUT BUFFER
	PUSHJ	P,.MMFWD##	;FREE UP NETWORK OUTPUT BUFFER
	 STOPCD	<Network output buffer deallocation failed in NDFIN1>
	JRST	NDFIN6		;NO MORE BUFFERS

;NETWORK BUFFERS CONTIGUOUS, MUST HAVE COME AS ONE HUNK

NDFIN3:	MOVE	T1,.IONLW(IO)	;SIZE OF SINGLE NETWORK BUFFER
	LSH	T1,1		;SIZE OF BOTH NETWORK BUFFERS
	ADD	T3,T1		;T3:=END ADDRESS OF BUFFER ALLOCATION
	SUB	T3,IO		;TURN INTO RELATIVE OFFSET INTO CDB
	JUMPLE	T3,NDFIN5	;IF NOT WITHIN CDB THEN FROM MANAGED MEMORY
	CAMLE	T3,.IOXSZ(IO)	;WITHIN CDB EXTRA SPACE?
	JRST	NDFIN5		;NO, MUST BE FROM MANAGED MEMORY
	CAIGE	T3,.IOMAX	;ENSURE NOT WITHIN FIXED PART OF CDB
	STOPCD	<Network buffers trashed in NDFIN3>
	CAMN	T3,.IOXFF(IO)	;NETWORK BUFFERS LAST THING ALLOCATED?
	MOVEM	T2,.IOXFF(IO)	;YES, RECLAIM "EXTRA" SPACE
	JRST	NDFIN6		;MARK BUFFERS DEALLOCATED

NDFIN5:	PUSHJ	P,.MMFWD##	;FREE UP COMBINED NETWORK BUFFERS
	 STOPCD	<Network buffers deallocation failed in NDFIN5>
NDFIN6:;PJRST	NTFIN6		;FINAL CLEANUP


;HERE FOR FINAL CLEANUP OF THE CDB

NTFIN6:	SETZM	.IONIB(IO)	;NO MORE INPUT BUFFERS
	SETZM	.IONOB(IO)	;NO MORE OUTPUT BUFFERS
	MOVX	T1,IO.CNR!IO.NBA;BITS TO CLEAR ON NETWORK RELEASE
	ANDCAM	T1,.IOCCF(IO)	;CLEAR UP THE CDB

	JRST	.POPJ1##	;SUCCESSFUL RETURN
;N6TO8 - CONVERT 6-BIT FORMAT INTO 8-BIT FORMAT
;CALL IS:
;
;	MOVX	T2,<N6M>
;	MOVX	P3,<N8P>
;	PUSHJ	P,N6TO8
;	 error return
;	normal return
;
;Where <N6M> is the 6-bit name (implicit maximum of 6 characters); and
;<N8P> is the 8-bit storage pointer in the form count,,offset where
;"count" is the maximum byte count for the string, and "offset" is the
;offset in the I/O CDB for the 8-bit format string.
;
;The error return is taken if the 6-bit name is too big for the 8-bit
;string maximum length (with code $EFRSB in M0).
;
;On normal return, the name has been stored as an 8-bit byte string
;in standard format (first word assumed byte count but left untouched).
;The RH(P3) contains the actual byte count of the converted byte string.
;
;Uses P3, P4.

N6TO8:	PUSHJ	P,NP3P4		;SETUP .IONP3/.IONP4 AS COUNTER/POINTER
	 POPJ	P,		;OOPS, ERROR
N6TO80:	PUSHJ	P,TSAV12##	;SAVE T1 AND T2
	XMOVEI	T1,NTYPO	;OUR SPECIAL "TYPEOUT" ROUTINE
	PUSHJ	P,.XTYPO##	;SET IT UP
	MOVE	T1,T2		;POSITION 6-BIT NAME
	PUSHJ	P,.TSIXN##	;AND "TYPE" THE NAME
	DMOVE	P3,.IONP3(IO)	;FETCH TERMINAL BYTE COUNTER/POINTER
	JUMPL	P3,.POPJ1##	;SUCCESSFUL IF NAME FIT
	MOVEI	M0,$EFRSB	;STRING TOO BIG
	POPJ	P,		;ERROR
;N6XO8 - CONVERT 6-BIT (DOUBLE-WORD) FORMAT INTO 8-BIT FORMAT
;CALL IS:
;
;	MOVX	T2,<N6X>
;	MOVX	P3,<N8P>
;	PUSHJ	P,N6XO8
;	 error return
;	normal return
;
;Where <N6X> is the 6-bit name (implicit maximum of 12 characters); and
;<N8P> is the 8-bit storage pointer in the form count,,offset where
;"count" is the maximum byte count for the string, and "offset" is the
;offset in the I/O CDB for the 8-bit format string.
;
;The error return is taken if the 6-bit name is too big for the 8-bit
;string maximum length (with code $EFRSB in M0).
;
;On normal return, the name has been stored as an 8-bit byte string
;in standard format (first word assumed byte count but left untouched).
;The RH(P3) contains the actual byte count of the converted byte string.
;
;Uses P3, P4.

	ENTRY	.N6XO8

.N6XO8:
N6XO8:	PUSHJ	P,NP3P4		;SETUP .IONP3/.IONP4 AS COUNTER/POINTER
	 POPJ	P,		;OOPS, ERROR
N6XO80:	PUSHJ	P,TSAV13##	;SAVE THE T'S
	JUMPE	T2,N6XO85	;ENTER LOOP, SUPPRESSING NULL NAME
N6XO82:	SETZ	T1,		;CLEAR CHAR ACCUMULATOR
	LSHC	T1,6		;NEXT NAME CHARACTER
	ADDI	T1,"0"-'0'	;ASCIIZE IT
	PUSHJ	P,NTYPO		;AND ADD IT TO THE STRING
	LSH	T2,-6		;RE-POSITION NAME FRAGMENT
	LSHC	T2,6		;AND POSITION WHOLE NAME
N6XO85:	JUMPN	T2,N6XO82	;LOOP IF MORE TO DO
	JUMPN	T3,N6XO82	;LOOP IF MORE TO DO
	DMOVE	P3,.IONP3(IO)	;FETCH TERMINAL BYTE COUNTER/POINTER
	JUMPL	P3,.POPJ1##	;SUCCESSFUL IF NAME FIT
	MOVEI	M0,$EFRSB	;STRING TOO BIG
	POPJ	P,		;ERROR
;N7TO8 - CONVERT 7-BIT FORMAT INTO 8-BIT FORMAT
;CALL IS:
;
;	MOVX	T2,<ADR>
;	MOVX	P3,<N8P>
;	PUSHJ	P,N6TO8
;	 error return
;	normal return
;
;Where <ADR> is the address of the 7-bit ASCIZ string; and
;<N8P> is the 8-bit storage pointer in the form count,,offset where
;"count" is the maximum byte count for the string, and "offset" is the
;offset in the I/O CDB for the 8-bit format string.
;
;The error return is taken if the 7-bit string is too big for the 8-bit
;string maximum length (with code $EFRSB in M0).
;
;On normal return, the string has been stored as an 8-bit byte string
;in standard format (first word assumed byte count but left untouched).
;The RH(P3) contains the actual byte count of the converted byte string.
;
;Uses P3, P4.

	ENTRY	.N7TO8

.N7TO8:	PUSHJ	P,NP3P4		;SETUP .IONP3/.IONP4 AS COUNTER/POINTER
	 POPJ	P,		;OOPS, ERROR
N7TO80:	PUSHJ	P,TSAV12##	;SAVE T1 AND T2
	XMOVEI	T1,NTYPO	;OUR SPECIAL "TYPEOUT" ROUTINE
	PUSHJ	P,.XTYPO##	;SET IT UP
	MOVE	T1,T2		;POSITION 7-BIT STRING ADDRESS
	PUSHJ	P,.TSTRG##	;AND "TYPE" THE STRING
	DMOVE	P3,.IONP3(IO)	;FETCH TERMINAL BYTE COUNTER/POINTER
	JUMPL	P3,.POPJ1##	;SUCCESSFUL IF NAME FIT
	MOVEI	M0,$EFRSB	;STRING TOO BIG
	POPJ	P,		;ERROR
;N8TO6 - CONVERT 8-BIT FORMAT STRING INTO 6-BIT NAME
;CALL IS:
;
;	MOVX	P4,<NDX>
;	PUSHJ	P,N8TO6
;	 error return
;	normal return
;
;Where <NDX> is the index into the I/O CDB of the 8-bit format byte
;string.
;
;The error return is not utilized.
;
;On normal return T2 contains the 6-bit name (or at least the first
;6 characters' worth).
;
;Uses T1, T2, P2, P3, P4.

N8TO6:	ADD	P4,IO		;CONVERT TO WORD ADDRESS
	HLRZ	P3,@P4		;GET BYTE COUNT
	HRLI	P4,(POINT 8,,32);CONCOCT A BYTE POINTER
N8TO60:	MOVE	P2,[POINT 6,T2]	;6-BIT NAMIFIER
	SETZ	T2,		;INITIALIZE NAME
	JRST	N8TO65		;ENTER LOOP

N8TO62:	TLNE	P2,770000	;ROOM IN WORD FOR ANOTHER CHARACTER?
	IDPB	T1,P2		;YES, STUFF IN NEXT CHARACTER
N8TO65:	ILDB	T1,P4		;NEXT 8-BIT BYTE
	SUBI	T1,"A"-'A'	;SIXBITIFY THE SEVEN-BIT ASCII CHARACTER
	SOJGE	P3,N8TO62	;LOOP FOR REST OF STRING
	JRST	.POPJ1##	;SUCCESSFUL RETURN
;NP3P4 - SETUP .IONP3/.IONP4 AS BYTE COUNT/BYTE POINTER
;CALL IS:
;
;	MOVX	P3,<8BP>
;	PUSHJ	P,NP3P4
;	 error return
;	normal return
;
;Where <8BP> is the prototype 8-bit format pointer in the form count,,offset
;where "count" is the maximum byte count of the string and "offset" is the
;byte string offset into the I/O CDB.
;
;On error return the specified index was outside of all possible CDB offsets
;
;On normal return .IONP3 will contain an AOBJN counter of the form -max,,0 and
;.IONP4 will contain the byte pointer for IDPBs.
;
;Uses P3 and P4.

NP3P4:	HRRZ	P4,P3		;WORD OFFSET INTO THE CDB
	ANDCMI	P3,-1		;MAXIMUM OFFSET,,0
	CAILE	P4,.IOMAX	;WITHIN RANGE?
	STOPCD	<8-bit format index outside of I/O CDB bounds in NP3P4>
	HRLI	P4,(POINT 8,(IO),32)  ;CONVERT TO 8-BIT BYTE POINTER
	TLC	P3,-1		;MAKE COUNT INTO AOBJN POINTER
	DMOVEM	P3,.IONP3(IO)	;SETUP COUNTER/POINTER
				; (THIS WAY THE RH(.IONP3) IS AN UP-TO-DATE
				;  COUNT OF BYTES ACTUALLY STORED, WHILE
				;  LH IS NEGATIVE IF NOT YET OVERFLOWED)
	JRST	.POPJ1##	;READY FOR CALLS TO NTYPO



;NTYPO - HELPER FOR N6TO8, ETC.

NTYPO:	EXCH	P3,.IONP3(IO)	;GET CUMULATIVE COUNTER
	AOBJP	P3,.+2		;ROOM FOR ANOTHER 8-BIT BYTE?
	IDPB	T1,.IONP4(IO)	;YES
	EXCH	P3,.IONP3(IO)	;RESTORE CALLER'S P3
	POPJ	P,		;RETURN
	SUBTTL	Network I/O Control

;RNEAT  --  EAT [REST OF] NETWORK MESSAGE
;CALL IS:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,RNEAT
;	 error return
;	normal return
;
;Where <CDB> is the address of the associated I/O CDB.
;
;On error return the network died.
;
;On normal return the network input message has been completely read, and
;is now ready for the next input message (i.e., RNBYT will return
;with no data available, RNMSG must be called to start the next input
;message processing).
;
;Uses ac T2.

RNEAT:	SETZM	.IONIC(IO)	;WE CAN CHEAT A BIT HERE
	PUSHJ	P,RNBYT1	;READ A NETWORK BYTE
	 CAIA			;PROBABLY NONE LEFT
	JRST	RNEAT		;LOOP BACK FOR MORE DATA
	JUMPE	M0,.POPJ1##	;SUCCESSFUL RETURN
	POPJ	P,		;NETWORK DIED
;RNBYT  --  READ ONE NETWORK BYTE
;CALL IS:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,RNBYT
;	 error return
;	normal return
;
;Where <CDB> is the address of the associated I/O CDB.
;
;On error return either the network died (M0 has the error code) or there
;are no more bytes left in the current input message (M0 has 0).
;
;On normal return the next data byte from the network channel is in T2.
;
;Uses ac T2.

	ENTRY	.RNBYT
	INTERN	RNBYT0,	RNBYT1

.RNBYT:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
RNBYT0:
RNBYT1:	SOSGE	.IONIC(IO)	;ANY BYTES LEFT?
	JRST	RNBYT2		;NO, AT LEAST NOT IN OUR BUFFER
	ILDB	T2,.IONIP(IO)	;YES, READ THE NEXT BYTE
	AOS	(P)		;SUCCESSFUL
	POPJ	P,		; RETURN

;HERE TO SEE IF NETWORK MESSAGE ENDED, OR MERELY SEGMENTED AND STILL MORE
;BYTES LEFT.

RNBYT2:	MOVE	T2,.IONIS(IO)	;GET INPUT STATE
	TXNE	T2,NS.EOM	;MORE INPUT COMING?
	JRST	RNBYT5		;NO, END OF MESSAGE SEEN,  NULL RETURN

;READ IN NEXT MESSAGE SEGMENT FROM MONITOR

	PUSHJ	P,RNBUF0	;REFILL OUR BYTE BUFFER
	 POPJ	P,		;NETWORK DIED
	JRST	RNBYT1		;TRY AGAIN

RNBYT5:	SETZ	M0,		;RETURN NULL TO INDICATE END OF MESSAGE
	POPJ	P,		;EMPTY RETURN
;RNMSG  --  READ IN ONE NETWORK MESSAGE
;CALL IS:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,RNMSG
;	 error return
;	normal return
;
;Where <CDB> is the address of the associated I/O CDB.
;
;On error return the network died (M0 has error code).
;
;On successful return the first byte of the message is in T2.
;
;Uses T2.

	ENTRY	.RNMSG
	INTERN	RNMSG0,	RNMSG1

.RNMSG:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
RNMSG0:
RNMSG1:	MOVE	T2,.IONIS(IO)	;LAST INPUT STATE
	TXNE	T2,NS.EOM	;DOES THE MONITOR STILL HAVE DATA?
	SKIPLE	.IONIC(IO)	;NO, DO WE STILL HAVE DATA?
	STOPCD	<RNMSG called with network data still outstanding>

;HIGHER-UP'S ARE IN SYNC, START UP A NEW MESSAGE

RNMSG4:	PUSHJ	P,RNBUF0	;FILL UP OUR INPUT BUFFER
	 POPJ	P,		;NETWORK DIED
	PUSHJ	P,RNBYT0	;GET FIRST BYTE OF NEW MESSAGE
	 CAIA			;OH YEAH?
	JRST	.POPJ1##	;SUCCESSFUL RETURN
	JUMPN	M0,.POPJ##	;ERROR RETURN IF ERROR
	WARNCD	<Null network message returned in RNMSG4>
	JRST	RNMSG4		;HO HUM GO TRY AGAIN
;RNBUF  --  READ BUFFER OF NETWORK DATA FROM MONITOR
;CALL IS:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,RNBUF
;	 error return
;	normal return
;
;Where <CDB> is the address of the associated I/O CDB.
;
;On error return the network died (error code is in M0).
;
;On normal return network bytes are available via RNMSG/RNBYT.
;
;Uses T1.

	ENTRY	.RNBUF
	INTERN	RNBUF0,	RNBUF1

.RNBUF:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
RNBUF0:
RNBUF1:	PUSHJ	P,TSAV14##	;SAVE THE T'S AS ADVERTISED
RNBUF2:	SKIPN	T2,.IONCH(IO)	;GET NETWORK CHANNEL
	STOPCD	<No network channel in RNBUF>
	MOVE	T1,.IOCCF(IO)	;GET CHANNEL CONTROL
	TXNE	T1,IO.ANF	;ANF CHANNEL?
	JRST	RABUF1		;YES
	TXNE	T1,IO.DCN	;DECNET CHANNEL?
	JRST	RDBUF1		;YES
	STOPCD	<Neither ANF nor DECnet in RNBUF>
;HERE FOR ANF NETWORK INPUT

RABUF1:	MOVX	T1,.TKFIN	;FUNCTION: INPUT
	MOVE	M0,[3,,T1]	;TSK. ARG POINTER TO
	TSK.	M0,		;READ NETWORK INPUT DATA
	 JRST	RABUF4		;ERROR
	SKIPG	.IONIC(IO)	;DID WE GET ANYTHING BACK?
	WARNCD	<Null network buffer returned in RABUF1>,,,RABUF1
	CAIE	T3,.TKTDR	;DATA WITH EOM?
	TDZA	T1,T1		;NO
	MOVX	T1,NS.EOM	;YES
	MOVEM	T1,.IONIS(IO)	;SET EOM FLAG FOR RNMSG
	JRST	.POPJ1##	;RETURN WITH NETWORK INPUT DATA

;TSK. INPUT FAILED

RABUF4:	CAIE	M0,TKUDW%	;"IN UUO" DIDN'T WORK?
	JRST	RABUF6		;NO, MORE SERIOUS
	TXNE	T3,IO.ERR	;ERROR OR NON-BLOCKING?
	JRST	NAIOE1		;NETWORK I/O FAILURE
	MOVE	T1,[HB.RIO+^D10000]  ;WAKE ON ASYNC I/O, TIMEOUT IN 10 SEC
	HIBER	T1,		;WAIT FOR ACTIVITY
	 STOPCD			;HIBER UUOS JUST SIMPLY DO NOT FAIL
	JRST	RABUF1		;TRY AGAIN

;TSK. FAILED, NOT "I/O ERROR"

RABUF6:	CAIE	M0,TKILS%	;MAYBE FUNNY STATE (E.G., DISCONNECTED)?
	JRST	NARXE1		;TSK. UUO FAILED
	JRST	NARXS1		;BAD STATE - LOOK FOR DISCONNECT REASON
;HERE FOR DECNET NETWORK INPUT

RDBUF1:	MOVE	T1,[<.NSFDR,,.NSAA2+1>!NS.WAI]  ;NETWORK READ FUNCTION
	MOVE	T3,.IOCCF(IO)	;CHANNEL CONTROL FLAGS
	TXNN	T3,IO.NBT	;WANT THIS READ NON-BLOCKING?
	SKIPE	.IOSCH(IO)	;OR IS THERE A I/O SCHEDULER LURKING ABOUT?
	TXZ	T1,NS.WAI	;YES TO ONE OF THE ABOVE, NON-BLOCKING READ
	MOVE	T3,.IONLB(IO)	;NUMBER OF BYTES WE CAN HANDLE
	SKIPN	T4,.IONIB(IO)	;ADDRESS OF NETWORK INPUT BUFFER
	STOPCD	<No network input buffer in RNBUF>
	HRLI	T4,(POINT 8,)	;NICE BYTE POINTER
	XMOVEI	M0,T1		;ARG BLOCK POINTER TO
	NSP.	M0,		;READ IN NETWORK DATA
	 JRST	NDRXE1		;NETWORK MUST HAVE DIED
	TXNN	T2,NS.IDA!NS.NDA;INPUT DATA AVAILABLE?
	TDZA	M0,M0		;NO
	HRRZ	M0,P		;YES
	MOVEM	M0,.IONIA(IO)	;SET NETWORK DATA AVAILABLITY FLAG
	CAIGE	T3,0		;DID DATA OVERFLOW THE BUFFER?
	STOPCD	<NSP. receive overflowed data buffer in RNBUF>
	MOVN	T3,T3		;NEGATE COUNT NOT USED
	ADD	T3,.IONLB(IO)	;P3:=COUNT OF BYTES RETURNED
	JUMPG	T3,RNBUF4	;PROCESS RETURNED DATA

;NO DATA AVAILABLE, SEE WHAT TO DO (CALL SCHEDULER OR RETURN NON-BLOCKING)

	MOVEI	M0,$EINTI	;NON-BLOCKING NETWORK INPUT
	MOVX	T2,IO.NBT	;THE NON-BLOCKING FLAG
	TDNE	T2,.IOCCF(IO)	;CALLER WANT NON-BLOCKING?
	POPJ	P,		;YES
	SKIPN	.IOSCH(IO)	;IS SCHEDULER SUPPLIED?
	STOPCD	<Non-blocking return in RNBUF>

;NO DATA AVAILABLE, MUST "BLOCK" THIS PROCESS VIA THE I/O SCHEDULER

	MOVX	T1,$SCNTI	;NETWORK INPUT WAIT
	PUSHJ	P,@.IOSCH(IO)	;CALL THE SCHEDULER
	 POPJ	P,		;BEING ABORTED?
	JRST	RNBUF1		;TRY TRY AGAIN

;GOT SOME DATA

RNBUF4:	MOVEM	T3,.IONIC(IO)	;SET NEW INPUT BYTE COUNT
	MOVE	T4,.IONIB(IO)	;START ADDRESS OF NETWORK INPUT BUFFER
	HRLI	T4,(POINT 8,)	;REGENERATE INPUT BUFFER BYTE POINTER
	MOVEM	T4,.IONIP(IO)	;AND BYTE POINTER TOO
	MOVEM	T1,.IONIS(IO)	;AND THE STATE (NS.EOM)
	JRST	.POPJ1##	;SUCCESSFUL RETURN
;XNBYT  --  SEND OUT ONE NETWORK BYTE
;Call is:
;
;	MOVX	T1,<CDB>
;	MOVX	T2,<byte>
;	PUSHJ	P,XNBYT
;	 error return
;	normal return
;
;Where <CDB> is the address of the I/O CDB; and <byte> is the 8-bit byte
;to be shipped verbatim over the network channel.
;
;On error return the network died. T1 and T2 are preserved such that the
;call to XNBYT may be re-executed.
;
;On normal return the data byte has been placed in the pending output
;buffer awaiting transmission.
;
;XNBYT will automatically send message segments (transmit sans EOM) if
;network buffer fills up.
;
;Preserves all acs.

	ENTRY	.XNBYT
	INTERN	XNBYT0,	XNBYT1

.XNBYT:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XNBYT0:
XNBYT1:	SOSGE	.IONOC(IO)	;ROOM FOR MORE DATA?
	JRST	XNBYT2		;NO
	IDPB	T2,.IONOP(IO)	;YES, STUFF AWAY THIS BYTE
	AOS	(P)		;SUCCESSFUL
	POPJ	P,		; RETURN
;BUFFER FULL, TRY TO OUTPUT IT AND MAKE ROOM FOR MORE DATA

XNBYT2:	SKIPN	.IONOP(IO)	;FIRST CALL?
	JRST	XNBYT6		;YES
	MOVE	M0,.IOCCF(IO)	;CHANNEL CONTROL FLAGS
	TXNN	M0,IO.DAP	;THIS CHANNEL TALKING DAPESE?
	JRST	XNBYT6		;NO, IMAGE BYTE STREAM
	MOVE	M0,.IODPF(IO)	;YES, GET DAP CONTROL FLAGS
	TXNE	M0,ID.SNM	;OK TO SEGMENT NETWORK MESSAGES
	JRST	XNBYT5		;YES (BUT DOUBLE-CHECK POINTERS)
	STOPCD	<DAP logic overran network buffer in XNBYT>

;TRANSMIT OLD BUFFER, MAKE ROOM FOR NEW DATA

XNBYT5:	SKIPN	.IODO3(IO)	;GOT A "LENGTH" FIELD SAVED?
	SKIPE	.IODO5(IO)	;OR A "BITCNT" FIELD SAVED?
	STOPCD	<XNBYT5-segmented DAP message with length/bitcount fields>
XNBYT6:	MOVX	M0,IO.ENM	;THE END-NETWORK-MESSAGE BIT
	ANDCAM	M0,.IOCCF(IO)	;CLEAR IN THE CDB
	PUSHJ	P,XNBUF0	;SEND WHAT WE HAVE, MAKE NEW BUFFER READY
	 POPJ	P,		;BLETCH
	SKIPG	.IONOC(IO)	;BETTER BE ROOM!
	STOPCD	<XNBUF returned successfully with a 0-length buffer in XNBYT>
	JRST	XNBYT1		;NOW GO TRY AGAIN
;XNFLS  --  FLUSH OUT THE NETWORK BUFFER
;Call is:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,XNFLS
;	 error return
;	normal return
;
;Where <CDB> is the address of the associated I/O CDB.
;
;On error return the network died.
;
;On successful return the network output buffer is empty and ready
;to be filled via calls to XNBYT.
;
;Preserves all acs.

	ENTRY	.XNFLS
	INTERN	XNFLS0,	XNFLS1

.XNFLS:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XNFLS0:
XNFLS1:	MOVE	M0,.IONOC(IO)	;CURRENT NETWORK BYTE COUNT
	SKIPN	.IONOX(IO)	;IF PARTIALLY-OUTPUT BUFFER PENDING
	CAME	M0,.IONLM(IO)	;OR IF CURRENT BUFFER IS NOT EMPTY
	PJRST	XNBUF0		;THEN SHIP CURRENT NETWORK DATA
	JRST	.POPJ1##	;NO NETWORK DATA, SUCCESSFUL BY DEFINITION
;XNEOM  --  SEND ONE NETWORK MESSAGE
;Call is:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,XNEOM
;	 error return
;	normal return
;
;Where <CDB> is the address of the associated I/O CDB.
;
;On error return the network died.
;
;On successful return the current network output message has been given
;to the monitor for transmission to the remote receiver.
;
;Preserves all acs.

	ENTRY	.XNEOM
	INTERN	XNEOM0,	XNEOM1

.XNEOM:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XNEOM0:
XNEOM1:	MOVX	M0,ID.SNM	;THE OK-TO-SEGMENT BIT
	ANDCAM	M0,.IODPF(IO)	;ALERT THE CONSISTENCY CHECKER (XNBYT)
	MOVX	M0,IO.ENM	;THE END-NETWORK-MESSAGE BIT
	IORM	M0,.IOCCF(IO)	;SET IN THE CDB FOR XNBUF TO SEE
	PJRST	XNBUF0		;AND OUTPUT WHAT IS THERE
;XNBUF  --  SEND BUFFER OF NETWORK DATA
;Call is:
;
;	MOVX	T1,<CDB>
;	PUSHJ	P,XNBUF
;	 error return
;	normal return
;
;Where <CDB> is the address of the associated I/O CDB.
;
;On error return the network died.
;
;On successful return the current output buffer has been given to the
;monitor for transmission to the remote receiver.
;
;If the flag IO.ENM in .IOCCF(IO) has been set non-zero then the message
;will be sent as complete, otherwise it will be sent as a partial message
;segment with end of message to come later.
;
;Preserves all acs.

	ENTRY	.XNBUF
	INTERN	XNBUF0,	XNBUF1

.XNBUF:	PUSHJ	P,.SACIO##	;SETUP I/O CDB INDEX
XNBUF0:
XNBUF1:	PUSHJ	P,TSAV14##	;SAVE THE T'S AS ADVERTISED
	SKIPN	T2,.IONCH(IO)	;FETCH NETWORK CHANNEL NUMBER
	STOPCD	<No network channel in XNBUF>
	MOVE	T1,.IOCCF(IO)	;CHANNEL CONTROL
	TXNE	T1,IO.ANF	;ANF NETWORK?
	JRST	XABUF1		;YES
	TXNE	T1,IO.DCN	;DECNET NETWORK?
	JRST	XDBUF1		;YES
	STOPCD	<Neither ANF nor DECnet in XNBUF>
;HERE FOR ANF NETWORK OUTPUT

XABUF1:	MOVX	T3,.TKTDR	;ASSUME DATA WITH EOM
	MOVE	T4,.IOCCF(IO)	;CHANNEL CONTROL FLAGS
	TXNN	T4,IO.ENM	;WANT EOM SENT?
	MOVX	T3,.TKTDT	;NO, DATA WITHOUT EOM
	MOVX	T1,.TKFOT	;FUNCTION: OUTPUT
	MOVE	M0,[3,,T1]	;TSK. ARG POINTER TO
	TSK.	M0,		;OUTPUT NETWORK DATA
	 JRST	XABUF4		;ERROR
	MOVX	T4,IO.ENM	;THE EOM REQUEST FLAG
	ANDCAM	T4,.IOCCF(IO)	;CLEAR FOR NEXT TIME
	JRST	.POPJ1##	;SUCCESSFUL

XABUF4:	CAIE	M0,TKUDW%	;"OUT UUO" DIDN'T WORK?
	JRST	XABUF6		;CHECK FOR DISCONNECTED
	TXNE	T3,IO.ERR	;ERROR OR NON-BLOCKING?
	JRST	NAIOE1		;NETWORK I/O ERROR
	SETOM	.IONOC(IO)	;MAKE SURE NOONE GETS CONFUSED
	MOVE	T1,[HB.RIO+^D10000]  ;WAKE ON ASYNC I/O, TIMEOUT IN 10 SEC
	HIBER	T1,		;WAIT FOR ACTIVITY
	 STOPCD			;HIBER UUOS ALWAYS WORK THESE DAYS!
	JRST	XABUF1		;TRY AGAIN

;TSK. FAILED, NOT "I/O ERROR"

XABUF6:	CAIE	M0,TKILS%	;MAYBE FUNNY STATE (E.G., DISCONNECTED)?
	JRST	NARXE1		;TSK. UUO FAILED
	JRST	NARXS1		;BAD STATE - LOOK FOR DISCONNECT REASON
;HERE FOR DECNET NETWORK OUTPUT

XDBUF1:	SKIPE	T3,.IONOX(IO)	;PARTIALLY-OUTPUT BUFFER?
	JRST	XDBUF3		;YES
	MOVE	T3,.IONLM(IO)	;SIZE OF OUTPUT [MESSAGE-SIZE-LIMITED] BUFFER
	SKIPLE	T2,.IONOC(IO)	;OUTPUT BUFFER FULL?
	SUB	T3,T2		;NO, CALCULATE AMOUNT OF DATA PRESENT
	SETOM	.IONOC(IO)	;IN CASE "INTERRUPTED"
	SKIPN	T4,.IONOB(IO)	;ADDRESS OF OUTPUT BUFFER
	STOPCD	<No network output buffer in XDBUF1>
	TLOA	T4,(POINT 8,)	;MAKE INTO BYTE POINTER
XDBUF3:	MOVE	T4,.IONOY(IO)	;PICK UP SAVED BYTE POINTER
	CAIGE	T3,0		;BETTER HAVE A NON-NEGATIVE LENGTH
	STOPCD	<Byte count negative in XDBUF3> ;***
	MOVE	T2,.IONCH(IO)	;NO, HAVE DATA, GET NETWORK CHANNEL NUMBER
	MOVE	T1,[.NSFDS,,.NSAA2+1]  ;SEND FUNCTION
	SKIPN	.IOSCH(IO)	;GOT AN I/O SCHEDULER?
	TXO	T1,NS.WAI	;NO, THEN BLOCKING SEND
	MOVX	M0,IO.ENM	;THE END-NETWORK-MESSAGE BIT
	TDNE	M0,.IOCCF(IO)	;IS IT SET IN THE CHANNEL CONTROL WORD?
	TXO	T1,NS.EOM	;YES
	ANDCAM	M0,.IOCCF(IO)	;IN ANY CASE, CLEAR IT WHEN DONE
	XMOVEI	M0,T1		;ARG POINTER TO
	NSP.	M0,		;SEND BUFFER OF DATA
	 JRST	NDRXE1		;NETWORK MUST HAVE DIED
	MOVEM	T1,.IONOS(IO)	;SAVE NETWORK OUTPUT STATUS (NS.EOM)
	DMOVEM	T3,.IONOX(IO)	;SET COMPLETION CODE
	TXNN	T2,NS.IDA!NS.NDA;IS THERE INPUT PENDING?
	TDZA	M0,M0		;NO
	HRRZ	M0,P		;YES
	MOVEM	M0,.IONIA(IO)	;SET INPUT AVAILABILITY FLAG

;SETUP BYTE POINTER/COUNTER FOR XNBYT

XDBUF4:	JUMPN	T3,XDBUF8	;WAIT FOR COMPLETION IF NEEDED
XDBUF6:	MOVE	T1,.IONLM(IO)	;NETWORK [MESSAGE-SIZE-LIMITED] BUFFER SIZE
	MOVEM	T1,.IONOC(IO)	;SET IN CDB
	MOVE	T2,.IONOB(IO)	;ADDRESS OF OUTPUT BUFFER
	HRLI	T2,(POINT 8,)	;MAKE INTO BYTE POINTER
	MOVEM	T2,.IONOP(IO)	;SET IN CDB
	JRST	.POPJ1##	;SUCCESS RETURN

;COULDN'T OUTPUT ENTIRE BUFFER, MUST WAIT

XDBUF8:	MOVEI	M0,$EINTO	;NON-BLOCKING NETWORK OUTPUT STATUS
	SKIPN	.IOSCH(IO)	;UNLESS AN I/O SCHEDULER IS SUPPLIED
	STOPCD	<Non-blocking return in XDBUF8>

;CALL THE SCHEDULER

	MOVX	T1,$SCNTO	;NETWORK OUTPUT WAIT
	PUSHJ	P,@.IOSCH(IO)	;WAIT FOR SOMETHING TO HAPPEN
	 POPJ	P,		;MUST BE ABORT
	JRST	XDBUF1		;TRY OUTPUTTING AGAIN
	SUBTTL	Network Error Handling

;NACIE - TSK. error cleanup.

NACIE1:	MOVEM	T1,P4		;SAVE TSK. ERROR CODE
	PUSHJ	P,NTZAP0	;BLAST AWAY THE TSK. CHANNEL (IF ANY)
	 STOPCD	<NTZAP failed in NACIE1>
	CAIL	P4,0		;NEGATIVE ERROR CODE ILLEGAL
	CAILE	P4,NAERRL	;KNOWN TSK. ERROR CODE?
	SETO	P4,		;NO
	HLRZ	M0,NAERRT(P4)	;FETCH CONNECT ERROR CODE
	POPJ	P,		;PROPAGATE ERROR TO CALLER



;NARXE - TSK. error cleanup (sending/receiving data)

NARXE1:	PUSHJ	P,.SAVE4##	;RABUF/XABUF DON'T SAVE THE PEAS
	MOVEM	M0,P4		;SAVE TSK. ERROR CODE
	MOVE	P3,.IOCCF(IO)	;PRESERVE A COPY OF CCF FLAGS
NARXE3:	PUSHJ	P,NTZAP0	;BLAST AWAY THE TSK. CHANNEL
	 STOPCD	<NTZAP failed in NARXE1>
	CAIL	P4,0		;NEGATIVE ERROR CODE ILLEGAL
	CAILE	P4,NAERRL	;KNOWN TSK. ERROR CODE?
	SETO	P4,		;NO
	HRRZ	M0,NAERRT(P4)	;FETCH I/O ERROR CODE
NARXE7:	MOVEM	M0,.IOER2(IO)	;SAVE "SUB-STATE" CODE
	MOVEI	M0,$EINLA	;GENERIC "NETWORK LINK ABORTED"
	POPJ	P,		;PASS ERROR TO CALLER



;TSK. error table

	$EFXXX,,$EIXXX		;-- - UNKNOWN ERROR CODE
NAERRT:	$EFXXX,,$EIXXX		;00 - UNKNOWN ERROR CODE
	$EFNNS,,$EIXXX		;01 - NO NETWORK (TSKSER) SUPPORT
	$EFABE,,$EIABE		;02 - ARGUMENT BLOCK ERROR (TOO SHORT)
	$EFPRV,,$EIPRV		;03 - NO PRIVILEGES
	$EFILF,,$EIILF		;04 - ILLEGAL FUNCTION
	$EFBCN,,$EIBCN		;05 - ILLEGAL CHANNEL (NOT TSK:, ETC)
	$EFPBL,,$EIXXX		;06 - ILLEGAL NPD (PROCESS DESCRIPTOR)
	$EFPBL,,$EIXXX		;07 - ILLEGAL NPD (TOO SHORT)
	$EFWRS,,$EIWRS		;10 - ILLEGAL CHANNEL STATE FOR FUNCTION
	$EFALF,,$EIALF		;11 - ALLOCATION FAILURE
	$EFALF,,$EIXXX		;12 - NO FREE LINKS (SHOULDN'T HAPPEN)
	$EFNSN,,$EIXXX		;13 - NO SUCH NODE
	$EFXXX,,$EINLK		;14 - I/O REQUEST FAILED (NO LINK?)

	NAERRL==.-NAERRT	;LENGTH OF ERROR TABLE
;NARXS - TSK. error (sending/receiving data) -- wrong state

NARXS1:	PUSHJ	P,.SAVE4##	;RABUF/XABUF DON'T SAVE THE PEAS
	MOVEM	M0,P4		;SAVE TSK. ERROR CODE
	MOVE	P3,.IOCCF(IO)	;PRESERVE A COPY OF CCF FLAGS
	MOVEI	T1,.TKFRS	;FUNCTION: READ STATE
	MOVE	T2,.IONCH(IO)	;SET TASK CHANNEL
	SETOB	T3,T4		;JUST TO MAKE SURE SOMETHING RETURNED
	MOVE	M0,[3,,T1]	;TSK. ARG POINTER TO
	TSK.	M0,		;READ TASK CHANNEL STATE
	 JRST	NARXE3		;FORGET IT, BLOW IT AWAY
	CAIE	T3,.TKSID	;IS THE LINK NOW "IDLE" (I.E., DISCONNECTED)?
	JRST	NARXE3		;NO, STRANGE STATE, BLOW IT AWAY
	MOVE	M0,[4,,T1]	;YES, CAN NOW SETUP TO SAFELY
	TSK.	M0,		;READ LINK STATE AND DISCONNECT CODE
	 JRST	NARXE3		;OH WELL, WE TRIED
	MOVE	T2,T4		;POSITION ANF DISCONNECT CODE
	MOVEI	T4,NARXST	;ANF-TO-NFT DISCONNECT TRANSLATION TABLE
	PUSHJ	P,.CFIND##	;TRY TO TRANSLATE THE DISCONNECT REASON
	 MOVEI	T1,$EIUXS	;HO HUM
	MOVE	P4,T1		;POSITION NFT ERROR/EXCEPTION CODE
	PUSHJ	P,NTZAP0	;BLOW AWAY THE TSK CHANNEL ON OUR SIDE
	 JFCL			;HAH!
	MOVE	M0,P4		;POSITION OUR TRANSLATED ERROR/EXCEPTION CODE
	JRST	NARXE7		;RETURN ERROR CODE



;TSK. disconnect reason translation table (I/O transfer level)

NARXST:	$EIDBO,,^O00		;"NORMAL" DISCONNECT (E.G., FILOP./RELEASE)
	$EIURO,,^O01		;NO SUCH OBJECT TYPE
	$EIRES,,^O02		;NO RESOURCES/TOO MANY CONNECTS
	$EIOTB,,^O03		;OBJECT BUSY
	$EIURO,,^O04		;OBJECT NOT AVAILABLE
	$EILNS,,^D03 + 100	;NODE SHUTTING DOWN
	$EIABM,,^D09 + 100	;ABORT BY DIALOG PROCESS
	$EIUID,,^D34 + 100	;INVALID USERID/PASSWORD
	$EIUAC,,^D36 + 100	;INVALID ACCOUNT STRING
	$EIIMG,,^D43 + 100	;ERROR IN IMAGE FIELD/STRING
	0
;NAIOE - TSK. error cleanup (I/O errors)

NAIOE1:	MOVEM	T3,.IOER3(IO)	;REMEMBER TSK I/O STATUS AS TERTIARY STATUS
	PUSHJ	P,NTZAP0	;BLOW AWAY WHATEVER'S LEFT
	 JFCL			;HOHUM
	MOVE	T3,.IOER3(IO)	;RETRIEVE TSK I/O STATUS WORD
	TXCE	T3,IO.IMP	;"IMPROPER MODE"
	MOVEI	M0,$EIIMP	;YUP
	TXCE	T3,IO.DER	;"DEVICE ERROR"
	MOVEI	M0,$EIDEV	;YUP
	TXCE	T3,IO.DTE	;"DATA ERROR"
	MOVEI	M0,$EIDAT	;YUP
	TXCE	T3,IO.BKT	;"BLOCK TOO LARGE"
	MOVEI	M0,$EIBKT	;YUP
	TXCE	T3,IO.ERR	;ALL ERROR BITS LIT?
	JRST	NAIOE4		;NO, SET ERROR AS TRANSLATED
	MOVEI	M0,$EIUCM	;*** YEAH, CALL IT "NO COMMUNICATION"
				;*** SHOULD DO DEVOP. AND TRANSLATE!
				;*** BUT THIS IS ONLY MEANINGFUL NETWORK
				;*** ERROR, SO . . .
NAIOE4:	MOVEM	M0,.IOER2(IO)	;SET "NLA" SUBSTATE AS SECONDARY STATUS
	MOVEI	M0,$EINLA	;RETURN A "LINK ABORTED" ERROR
	POPJ	P,		;TO WHOMEVER...
;NDCIE - NSP. error cleanup, call with P2/Channel number if any

NDCIE1:	CAIE	M0,P1		;POSSIBLY THE "UNIMPLEMENTED" ERROR RETURN?
	JRST	NDCXE1		;NO
	MOVX	T1,%CNST2	;YES
	GETTAB	T1,		;GET MONITOR "CONFIG" FLAGS
	 STOPCD	<GETTAB(%CNST2) failed in NDCIE1>
	TXNE	T1,ST%D36	;IS DECNET-36 IMPLEMENTED?
	JRST	NDCXE1		;YES
	MOVEI	M0,$EFNNS	;NO, THEN ERROR IS "NO NETWORK SOFTWARE"
	POPJ	P,		;AND THAT IS THAT

NDCXE1:	MOVEM	M0,P4		;PRESERVE NSP. ERROR CODE
	HRRZM	P2,.IONCH(IO)	;STORE CHANNEL IF THE MONITOR GAVE US ONE
	PUSHJ	P,NTZAP0	;AND BLAST IT TO SMITHEREENS
	 STOPCD	<NTZAP failed in NDCIE1>
	CAIL	P4,0		;NEGATIVE ERROR CODE UNKNOWN
	CAILE	P4,NDERRL	;KNOWN NSP ERROR CODE?
	SETO	P4,		;NO
	HLRZ	M0,NDERRT(P4)	;FETCH CONNECT ERROR CODE
	POPJ	P,		;PASS ERROR TO CALLER



;NDRXE - NSP. error cleanup (sending/receiving data)

NDRXE1:	MOVEM	M0,P4		;PRESERVE NSP. ERROR CODE
	MOVE	P3,.IOCCF(IO)	;PRESERVE COPY OF CHANNEL CONTROL FLAGS
	PUSHJ	P,NTZAP0	;BLAST NSP CHANNEL TO SMITHEREENS
	 STOPCD	<NTZAP failed in NDRXE1>
	CAIL	P4,0		;NEGATIVE ERROR CODE UNKNOWN
	CAILE	P4,NDERRL	;KNOWN NSP ERROR CODE?
	SETO	P4,		;NO
	HRRZ	M0,NDERRT(P4)	;FETCH ERROR CODE
	MOVEM	M0,.IOER2(IO)	;SAVE "SUB-STATE" CODE
	MOVEI	M0,$EINLA	;GENERIC "NETWORK LINK ABORTED"
	POPJ	P,		;PASS ERROR TO CALLER
;NSP. error table

	$EFXXX,,$EIXXX		;-- - UNKNOWN ERROR CODE
NDERRT:	$EFXXX,,$EIXXX		;00 - UNKNOWN ERROR CODE
	$EFABE,,$EIABE		;01 - ARGUMENT BLOCK ERROR
	$EFALF,,$EIALF		;02 - ALLOCATION FAILURE
	$EFBCN,,$EIBCN		;03 - BAD CHANNEL NUMBER
	$EFBFT,,$EIBFT		;04 - BAD FORMAT TYPE IN PROCESS BLOCK
	$EFCFE,,$EICFE		;05 - CONNECT BLOCK FORMAT ERROR
	$EFIDL,,$EIIDL		;06 - INTERRUPT DATA TOO LONG
	$EFIFM,,$EIIFM		;07 - ILLEGAL FLOW CONTROL MODE
	$EFILF,,$EIILF		;10 - ILLEGAL NSP. FUNCTION CODE
	$EFJQX,,$EIJQX		;11 - JOB QUOTA EXHAUSTED
	$EFLQX,,$EILQX		;12 - LINK QUOTA EXHAUSTED
	$EFNCD,,$EINCD		;13 - NO CONNECT DATA TO READ
	$EFPIO,,$EIPIO		;14 - PERCENTAGE INPUT OUT OF BOUNDS
	$EFPRV,,$EIPRV		;15 - NO PRIVILEGES
	$EFSTB,,$EISTB		;16 - SEGMENT SIZE TOO BIG
	$EFNSN,,$EINSN		;17 - UNKNOWN NODE NAME
	$EFUXS,,$EIUXS		;20 - UNEXPECTED STATE: UNSPECIFIED
	$EFWNA,,$EIWNA		;21 - WRONG NUMBER OF ARGUMENTS
	$EFWRS,,$EIWRS		;22 - LINK IN WRONG STATE
	$EFCBL,,$EICBL		;23 - CONNECT BLOCK LENGTH ERROR
	$EFPBL,,$EIPBL		;24 - PROCESS BLOCK LENGTH ERROR
	$EFSBL,,$EISBL		;25 - STRING BLOCK LENGTH ERROR
	$EFUDS,,$EIUDS		;26 - UNEXPECTED STATE: DISCONNECT SENT
	$EFUDC,,$EIUDC		;27 - UNEXPECTED STATE: DISCONNECT CONFIRMED
	$EFUCF,,$EIUCF		;30 - UNEXPECTED STATE: NO CONFIDENCE
	$EFULK,,$EIULK		;31 - UNEXPECTED STATE: NO LINK
	$EFUCM,,$EIUCM		;32 - UNEXPECTED STATE: NO COMMUNICATION
	$EFUNR,,$EIUNR		;33 - UNEXPECTED STATE: NO RESOURCES
	$EFRBO,,$EIRBO		;34 - CONNECT REJECTED: REJECTED BY OBJECT
	$EFDBO,,$EIDBO		;35 - DISCONNECTED BY OBJECT
	$EFRES,,$EIRES		;36 - CONNECT REJECTED: NO RESOURCES
	$EFUXN,,$EIUXN		;37 - CONNECT REJECTED: UNKNOWN NAME
	$EFRNS,,$EIRNS		;40 - CONNECT REJECTED: NODE SHUT DOWN
	$EFURO,,$EIURO		;41 - CONNECT REJECTED: UNRECOGNIZED OBJECT
	$EFIOF,,$EIIOF		;42 - CONNECT REJECTED: BAD OBJECT NAME FORMAT
	$EFOTB,,$EIOTB		;43 - CONNECT REJECTED: OBJECT FULL/BUSY
	$EFABM,,$EIABM		;44 - CONNECT REJECTED: ABORTED BY MANAGEMENT
	$EFABO,,$EIABO		;45 - CONNECT REJECTED: ABORTED BY OBJECT
	$EFINF,,$EIINF		;46 - CONNECT REJECTED: INVALID NODE NAME FORMAT
	$EFLNS,,$EILNS		;47 - CONNECT REJECTED: LOCAL NODE SHUT DOWN
	$EFUID,,$EIUID		;50 - CONNECT REJECTED: INVALID USERID
	$EFNRO,,$EINRO		;51 - CONNECT REJECTED: NO RESPONSE FROM OBJECT
	$EFNUR,,$EINUR		;52 - NODE UNREACHABLE
	$EFNLK,,$EINLK		;53 - NO LINK
	$EFDSC,,$EIDSC		;54 - DISCONNECT COMPLETE
	$EFIMG,,$EIIMG		;55 - IMAGE FIELD TOO LONG
	$EFUAC,,$EIUAC		;56 - CONNECT REJECTED: INVALID ACCOUNT DATA
	$EFBCF,,$EIBCF		;57 - BAD COMBINATION OF FLAGS
	$EFADE,,$EIADE		;60 - ADDRESS CHECK

	NDERRL==.-NDERRT	;LENGTH OF ERROR TRANSLATION TABLE
	END