Google
 

Trailing-Edge - PDP-10 Archives - tops10_703a_sys_atpch16_bb-fr67f-bb - swinet.x16
There are 2 other files named swinet.x16 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


	COMMENT	\

COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1984,1987.  ALL RIGHTS RESERVED.


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.

\
	SUBTTL	Version and Revision History

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

%%NET==:<BYTE (3)CSTVER(9)MAJVER(6)MINVER(18)EDTVER>
%%SWIL==:%%SWIL	;SHOW (AND SYNCHRONIZE) SWIL VERSION

IF2,<	PURGE	CSTVER,MAJVER,MINVER,EDTVER>



;INITIAL CREATION

;1000	RDH	01-Jan-84
;	Incorporate into SWIL %12(1000), sync edit level at 1000.

;1012	DRB	25-Jan-85
;	Add scheduler calls to ANF-10 non-blocking I/O.  Allow non-blocking
;	NSP. enter passive.

;1013	DRB	25-Jan-85
;	XDBUF3 is clearing IO.ENM, before we're sure that the message is
;	going to make it out.  If we retry, due to non-blocking I/O, EOM
;	isn't getting set.  Rearrange code so that it works.

;1020	RDH	12-Aug-85
;	"Managed Memory" is lost when doing ANF network I/O.

;1022	LEO	09-Sep-85
;	Do Copyrights.

;1043	BSC	24-Apr-86
;	Add a DAP message trace feature which is useful for debugging.
;	Refer to edit [1043] in SWIL.MAC for full details.

;1045	BSC	18-Jun-86
;	Add code to support transmission of CONTINUE interrupt messages.

;1050	BAH	21-Jan-87
;	Change TRC macro to $TRACE.
	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)
RCV <	PUSHJ	P,TRCRCV    >	;TRACE RECEIVED DATA
	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

RCV <	PUSHJ	P,TRCFIL	;DIRECT TRACE, IF ANY, AS DETERMINED BY .JBOPC
	PUSHJ	P,.XTYPO##	; . . .
	PUSHJ	P,.TTABC##	;TAB ACROSS
	MOVE	T1,DAPXTX(P1)	;ADDR OF FIELD DESCRIPTIVE TEXT
	PUSHJ	P,.TSTRG##	;TYPE THAT TEXT
	MOVE	T1,DAPXCT(P1) >	;WE USED T1 SO RETRIEVE EXECUTION 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?
NORCV <	JRST	RD01T4	    >	;NO, FIXED LENGTH
RCV   <	JRST	RD01T2	    >	;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
RCV <	MOVEI	T1,[ASCIZ \ [var len ASCII, len= \]
	PUSHJ	P,.TSTRG##	;TELL USER IT IS VAR LENGTH ASCII
	PUSHJ	P,VARLEN    >	;TYPE OUT THE VARIABLE LENGTH FROM T3
	JRST	RD01T4		;ENTER LOOP

RCV <
RD01T2:	MOVEI	T1,[ASCIZ \ [fix len ASCII, len from DAP spec= \]
	PUSHJ	P,.TSTRG##	;TELL USER IT IS FIXED LENGTH ASCII
	PUSHJ	P,FIXLEN	;TYPE OUT THE FIXED LENGTH
	JRST	RD01T4	    >	;ENTER LOOP

;LOOP READING FIXED/VARIABLE ASCII INPUT

RD01T3:	PUSHJ	P,RDBYT1	;READ NEXT ASCII BYTE
	 PJRST	RDEIE		;SOMETHING'S WRONG
RCV <	PUSHJ	P,.TSPAC##	;SPACE BETWEEN BYTES IS NEATER
	PUSHJ	P,.THEXB    >	;TYPE-OUT BYTE FROM T2
	IDPB	T2,T4		;STASH AWAY THIS CHARACTER
RD01T4:	SOJGE	T3,RD01T3	;LOOP FOR REST OF FIELD
	MOVE	T3,-T1(P)	;AMOUNT OF SPACE STILL NEEDING CLEARING
	JRST	RD01T7		;GO CLEAR THAT SPACE

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;LOOP READING EXTENSIBLE ASCII INPUT

RD01T5:
RCV <	MOVEI	T1,[ASCIZ \ [extensible ASCII]\]
	PUSHJ	P,.TSTRG##  >	;TELL USER IT IS EXTENSIBLE ASCII

RD01T6:	PUSHJ	P,RDBYT1	;READ NEXT INPUT BYTE
	 PJRST	RDEIE		;ERROR SOMEWHERE
RCV <	PUSHJ	P,EXTENS    >	;TYPE EXTENSIBLE BYTE FROM T2
	IDPB	T2,T4		;STASH AWAY THIS CHARACTER
	TRNE	T2,200		;EXTENDED BYTE?
	SOJG	T3,RD01T6	;YES, READ MORE
	TRNE	T2,200		;TRULY END OF INPUT?
	PJRST	RDEIF		;NO, TOO MUCH, ERROR IN FIELD
RD01T7:	SETZ	T2,		;YES, A TERMINATING NULL
	IDPB	T2,T4		;TO TERMINATE THE STRING
	SOJGE	T3,.-1		;CLEAR REST OF STRING
RCV <	PUSHJ	P,ASCSTR	;TYPE ASCII STRING FROM .IODAP(IO)
	PUSHJ	P,.TCRLF##  >	;FINISH THE LINE NEATLY
	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	T3,T4		;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?
NORCV <	JRST	RD03T3	    >	;NO, FIXED LENGTH
RCV   <	JRST	RD03T1	    >	;NO, FIXED LENGTH
	PUSHJ	P,RDBYT1	;READ FIELD LENGTH
	 PJRST	RDEIE		;ERROR IN FIELD
	MOVE	P3,T2		;SET ACTUAL FIELD LENGTH
RCV <	MOVEI	T1,[ASCIZ \ [var len bin, len= \]
	PUSHJ	P,.TSTRG##	;TELL USER IT IS VAR LENGTH BINARY
	MOVE	T3,P3		;GET LENGTH IN T3 FOR TYPING BY VARLEN
	PUSHJ	P,VARLEN    >	;TYPE THE VARIABLE 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


RCV <
RD03T1:	MOVEI	T1,[ASCIZ \ [fix len bin, len from DAP spec= \]
	PUSHJ	P,.TSTRG##	;TELL USER IT IS FIXED LENGTH BINARY
	PUSHJ	P,FIXLEN	;TYPE THE FIXED LENGTH
	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
RCV <	PUSHJ	P,.TSPAC##	;SPACE BETWEEN BYTES IS NEATER
	PUSHJ	P,.THEXB    >	;TYPE-OUT BYTE FROM T2
	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>
RCV <	PUSHJ	P,BINFLD	;TYPE OUT BINARY FIELD FROM T3 & T4
	PUSHJ	P,.TCRLF##  >	;FINISH OFF THE LINE
	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:
RCV <	MOVEI	T1,[ASCIZ \ [extensible flags field]\] ;TELL USER EXTENSIBLE FIELD
	PUSHJ	P,.TSTRG##  >	; . . .
RD04T6:	PUSHJ	P,RDBYT1	;READ NEXT FLAG BYTE
	 PJRST	RDEIE		;ERROR IN FIELD
RCV <	PUSHJ	P,EXTENS    >	;TYPE OUT EXTENSIBLE BYTE FROM T2
	IDPB	T2,T4		;STORE FLAGS
	TRNE	T2,200		;EXTENDED BYTE?
	SOJG	T3,RD04T6	;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
RCV <	PUSHJ	P,.TCRLF##	;FINISH THE LINE
	PUSHJ	P,FLGFLD    >	;TYPE OUT FLAGS FROM THIS 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?
NORCV <	JRST	RD05T3	    >	;NO, FIXED LENGTH
RCV   <	JRST	RD05T1	    >	;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
RCV <	MOVEI	T1,[ASCIZ \ [var len image, len= \]
	PUSHJ	P,.TSTRG##	;TELL USER IT IS VAR LENGTH IMAGE
	PUSHJ	P,VARLEN    >	;TYPE OUT THE LENGTH
	JRST	RD05T3		;AND ENTER LOOP

RCV <
RD05T1:	MOVEI	T1,[ASCIZ \ [fix len image, len from DAP spec= \]
	PUSHJ	P,.TSTRG##	;TELL USER IT IS FIXED LENGTH IMAGE
	PUSHJ	P,FIXLEN	;TYPE OUT THE LENGTH
	JRST	RD05T3	    >	;ENTER LOOP

;LOOP READING IMAGE BYTES

RD05T2:	PUSHJ	P,RDBYT1	;NEXT IMAGE BYTE
	 PJRST	RDEIE		;ERROR IN FIELD
	IDPB	T2,T4		;STORE THIS BYTE
RCV <	PUSHJ	P,.TSPAC##	;SPACE BETWEEN BYTES IS NEATER
	PUSHJ	P,.THEXB    >	;TYPE-OUT BYTE FROM T2
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
RCV <	PUSHJ	P,.TCRLF##  >	;FINISH OFF THE LINE
	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?
NORCV <	JRST	.POPJ1##    >	;*** YES, JUST IGNORE IT HERE
RCV   <	JRST	[MOVEI	T1,[ASCIZ \ ("invisible" menu, ignored)\]
		 PUSHJ	P,.TSTRG##
		 PUSHJ	P,.TCRLF##
		 JRST	.POPJ1##] >
	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:
RCV <	MOVEI	T1,[ASCIZ \ [extensible menu field]\] ;TELL USER EXTENSIBLE FIELD
	PUSHJ	P,.TSTRG##  >	; . . .
RD06T6:	PUSHJ	P,RDBYT1	;READ NEXT MENU BYTE
	 PJRST	RDEIE		;ERROR IN FIELD
RCV <	PUSHJ	P,EXTENS    >	;TYPE OUT EXTENSIBLE BYTE FROM T2
	IDPB	T2,T4		;STORE AWAY MENU BYTE
	TRNE	T2,200		;END OF EXTENSIBLE FIELD?
	SOJG	T3,RD06T6	;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
RCV <	PUSHJ	P,.TCRLF##  >	;FINISHED LINE OF HEX MENU BYTES

;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
RCV <	PUSHJ	P,.TTABC##	;TAB ACROSS
	MOVE	T1,DAPXTX(P1)	;ADDR OF FIELD DESCRIPTIVE TEXT
	PUSHJ	P,.TSTRG##	;TYPE THAT TEXT
	MOVE	T1,DAPXCT(P1) >	;PICK UP EXECUTION TABLE ENTRY
	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:
RCV <	MOVEI	T1,[ASCIZ \ [ASCII date/time field] \]
	PUSHJ	P,.TSTRG##  >	;INFORM USER OF DATE/TIME FIELD
RD07T2:	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,RD07T2	;YES, LOOP EATING SPACES
	SETZ	T2,		;NO?????????????????
RCV <	MOVEI	T1,[ASCIZ \ ?? field is null ?? \]
	PUSHJ	P,.TSTRG##  >	;INFORM USER OF DATE/TIME FIELD
	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
RCV <	MOVE	T1,T2		;GET THE CHAR
	PUSHJ	P,.TCHAR##  >	;INFORM USER OF DATE/TIME FIELD	CHAR
	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
RCV <	PUSHJ	P,.TCRLF##  >	;FINISH LINE TO USER
	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

RCV <	PUSHJ	P,TRCFIL	;DIRECT TRACE, IF ANY, AS DETERMINED BY .JBOPC
	PUSHJ	P,.XTYPO##	; . . .
	PUSHJ	P,.TCRLF	;SPACE TO MAKE NEW MESSAGE PROMINENT
	MOVE	T1,DAPXTX	;ADDR OF "DAP message type" TEXT
	PUSHJ	P,.TSTRG##	;TYPE THAT
	MOVEI	T1,[ASCIZ / - /];A DASH
	PUSHJ	P,.TSTRG##	;TYPE THE DASH
	MOVE	T1,.IODIM(IO)	;GET THE DAP MESSAGE TYPE
	MOVEI	T2,"0"		;USE ZEROES FOR FILLER
	PUSHJ	P,.TDEC2##	;TYPE OUT THE MESSAGE TYPE
	PUSHJ	P,.TSPAC##	;A SPACE MAKES MESSAGE PRETTY
	HRRZ	T2,.IODIM(IO)	;GET MESSAGE TYPE
	MOVEI	T4,DAPIDX	;DAP INDEX TABLE
	PUSHJ	P,.CFIND##	;FIND THE INDEX ENTRY FOR THIS MESSAGE TYPE
	 PJRST	RDEUM		;ERROR - UNKNOWN MESSAGE TYPE
	MOVE	T1,DAPXTX(T1)	;GET TEXT DESCRIBING DAP MESSAGE TYPE
 	PUSHJ	P,.TSTRG##	;TYPE TEXT DESCRIPTION OF DAP MESSAGE
	PUSHJ	P,.TSPAC##	;SPACE

;TYPE <<From REMOTE to US>>   WHERE US=OUR NODE NAME, REMOTE=REMOTE NODE NAME

	PUSHJ	P,.TLANG##	   ;<
	PUSHJ	P,.TLANG##	   ;<
	MOVEI	T1,[ASCIZ \From \] ;From
	PUSHJ	P,.TSTRG##
	MOVE	T1,.ION6M(IO)	   ;From REMOTE
	PUSHJ	P,.TSIXN##
	MOVEI	T1,[ASCIZ \ to \]  ;From REMOTE to
	PUSHJ	P,.TSTRG##
	MOVE	T1,.MYNOD##	   ;From REMOTE to US
	PUSHJ	P,.TSIXN##
	PUSHJ	P,.TRANG##	   ;>
	PUSHJ	P,.TRANG##	   ;>
	PUSHJ	P,.TCRLF##	;FINISH OFF THE LINE

	PUSHJ	P,.TTABC##	;TAB ACROSS
	MOVE	T1,DAPXTX+1	;ADDR OF "Message header flags" TEXT
	PUSHJ	P,.TSTRG##  	;TYPE THAT
> ;END RCV

;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
		TRNE	P1,200		;SHOULD THERE BE ANOTHER BYTE?
		PJRST	RDEID0		;YES, ERROR IN FLAGS FIELD
RCV  <	        PUSHJ	P,.TCRLF## >	;MAKE THE MESSAGE NEAT
		JUMPE	T2,RDMSZ	;MESSAGE OK IF NO FIELDS EXPECTED
		PJRST	RDEID0]		;ELSE ERROR IN FLAGS FIELD
	IDPB	T2,P4		;STASH THIS FLAG BYTE
RCV <	PUSHJ	P,.TSPAC##	;SPACE BETWEEN BYTES IS NEATER
	PUSHJ	P,.THEXB    >	;TYPE-OUT FLAG BYTE FROM T2
	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
RCV <	MOVEI	P1,1            ;SO .TFLAG GETS HEADER FLAG MESSAGES
	MOVE	P2,.IODIF(IO)	;PICK UP HEADER FLAGS
	CLEAR	P3,		;ONLY ONE WORD OF FLAGS
	PUSHJ	P,.TCRLF##	;FINISH THE LINE OF HEX FLAGS
	PUSHJ	P,.TFLAG    >	;TYPE CORRESP. DAP MESSAGES
	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
RCV <	PUSHJ	P,.TTABC##	;TAB ACROSS
	MOVE	T1,DAPXTX+2	;ADDR OF "Stream identification" TEXT
	PUSHJ	P,.TSTRG##	;TYPE THAT TEXT
	PUSHJ	P,.TSPAC##	;SPACE ACROSS
	PUSHJ	P,.THEXB	;TYPE THE HEX BYTE FROM T2
	PUSHJ	P,.TCRLF##  >	;FINISH WITH <CR><LF>
	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
RCV <	PUSHJ	P,.TTABC##	;TAB ACROSS
	MOVE	T1,DAPXTX+3	;ADDR OF "MSG data length (LSB)" TEXT
	PUSHJ	P,.TSTRG##	;TYPE THAT TEXT
	PUSHJ	P,.TSPAC##	;SPACE ACROSS
	PUSHJ	P,.THEXB	;TYPE THE HEX BYTE FROM T2
	PUSHJ	P,.TCRLF##  >	;FINISH WITH <CR><LF>

;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
RCV <	PUSHJ	P,.TTABC##	;TAB ACROSS
	MOVE	T1,DAPXTX+4	;ADDR OF "MSG data length (MSB)" TEXT
	PUSHJ	P,.TSTRG##	;TYPE THAT TEXT
	PUSHJ	P,.TSPAC##	;SPACE ACROSS
	PUSHJ	P,.THEXB	;TYPE THE HEX BYTE FROM T2
	PUSHJ	P,.TCRLF##  >	;FINISH WITH <CR><LF>

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
RCV <	PUSHJ	P,.TTABC##	;TAB ACROSS
	MOVE	T1,DAPXTX+5	;ADDR OF "Trailing bit count" TEXT
	PUSHJ	P,.TSTRG##	;TYPE THAT TEXT
	PUSHJ	P,.TSPAC##	;SPACE ACROSS
	PUSHJ	P,.THEXB	;TYPE THE HEX BYTE FROM T2
	PUSHJ	P,.TCRLF##  >	;FINISH WITH <CR><LF>

;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
RCV <	PUSHJ	P,.TTABC##	;TAB ACROSS
	MOVE	T1,DAPXTX+6	;ADDR OF "SYSPEC sys-specific data" TEXT
	PUSHJ	P,.TSTRG##	;TYPE THAT TEXT
	PUSHJ	P,.TSPAC##	;SPACE ACROSS
	PUSHJ	P,.THEXB    >	;TYPE THE HEX BYTE FROM T2
	SKIPG	T4,T2		;COUNT OF IMAGE BYTES FOLLOWING
	JRST	RDMSG8		;NONE, ALL DONE HERE
RDM7.1:	PUSHJ	P,RNBYT0	;GET NEXT SYSPEC IMAGE BYTE
	 JRST	[JUMPE	M0,RDEID5	;ERROR IS SYSPEC FIELD
		POPJ	P,]		;NETWORK DIED
RCV <	PUSHJ	P,.TSPAC##	;SPACE ACROSS
	PUSHJ	P,.THEXB    >	;TYPE THE HEX BYTE FROM T2
	SOJG	T4,RDM7.1	;EAT THE WHOLE SILLY THING
RCV <	PUSHJ	P,.TCRLF##  >	;FINISH OFF WITH <CR><LF>

;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:	MOVX	T3,IO.SID	;GET SEND-INTERRUPT-DATA FLAG
	TDNE	T3,.IOCCF(IO)	;WANT THIS CONTINUE(XXX) SENT AS INTERRUPT ?
	JRST	XDC2F2		;YES, GO PACKAGE AS INTERRUPT DATA AND SHIP IT
	MOVD1M	T2,C2F		;NO, 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

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

XDC2F2:	ANDCAM	T3,.IOCCF(IO)	;CLEAR THE SEND-INTERRUPT-DATA FLAG
	MOVEI	P2,$DHCNT	;GET THE CONTINUE MESSAGE TYPE
	LSH	P2,^D28		;POSITION IN THE MESSAGE IN P2
	LSH	T2,^D12		;POSITION THE "CONTINUE" FUNCTION
	IOR	P2,T2		;INCLUDE IN MESSAGE IN P2

	MOVE	P1,[XWD 3,2]	;<NO. BYTES,,NO. WORDS> IN P1/P2 STRING BLOCK

	MOVE	T2,[.NSFIS,,.NSAA1+1] ;.NSAFN  SEND-INTERRUPT-DATA,,ARG COUNT
	MOVE	T3,.IONCH(IO)	      ;.NSACH  DECNET CHANNEL
	XMOVEI	T4,P1		      ;.NSAA1  POINTER TO STRING BLOCK

	XMOVEI	M0,T2		;ARG POINTER TO SEND INTERRUPT DATA
	NSP.	M0,		;SEND IT
	 JRST	NDRXE1		;GO SEE WHY THIS DIED
	JRST	.POPJ1##	;RETURN HAPPILY
;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
XMT <	PUSHJ	P,TRCFIL	;DIRECT TRACE, IF ANY, AS DETERMINED BY .JBOPC
	PUSHJ	P,.XTYPO##	; . . .
	PUSHJ	P,.TTABC##  	;TAB ACROSS BEFORE TYPING DATA BYTES
	MOVEI	T1,[ASCIZ \<XMT> \] ;ENSURE USER KNOWS THIS IS TRANSMITTED DATA
	PUSHJ	P,.TSTRG##  >
	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
XMT <	PUSHJ	P,TRCFIL	;DIRECT TRACE, IF ANY, AS DETERMINED BY .JBOPC
	PUSHJ	P,.XTYPO##	; . . .
	PUSHJ	P,.TTABC##	;TAB ACROSS
	MOVE	T1,DAPXTX(P1)	;ADDR OF FIELD DESCRIPTIVE TEXT
	PUSHJ	P,.TSTRG##	;TYPE THAT TEXT
	MOVE	T1,DAPXCT(P1) >	;WE USED T1 SO RETRIEVE EXECUTION TABLE ENTRY
	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	P3,.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,P3		;YES, SET COUNT BYTE
	TXNE	P2,DX$VAR	;FIXED LENGTH FIELD?
NOXMT <	JRST	.POPJ1##	;NO, ALL DONE HERE
	JUMPE	T3,.POPJ1## >	;YES, FIELD STILL LEFT?
XMT   <	JRST	XD01TV          ;NO, ALL DONE HERE
	JUMPE	T3,XD01TF   >	;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
NOXMT <	JRST	.POPJ1##    >	;SUCCESSFUL RETURN
XMT   <
XD01TF:	MOVEI	T1,[ASCIZ \ [fix len ASCII, len from DAP spec= \]
	PUSHJ	P,.TSTRG##	;TELL USER IT IS FIXED LENGTH ASCII
	PUSHJ	P,FIXLEN	;TYPE THE LENGTH
	LDB	T3,[POINTR DAPXCT(P1),DX$LNB] ;RETRIEVE FIELD LENGTH TO T3
	JRST	XD01T4	    >	;ENTER LOOP


XMT <
XD01TV:	MOVEI	T1,[ASCIZ \ [var len ASCII, len= \]
	PUSHJ	P,.TSTRG##	;TELL USER IT IS VAR LENGTH ASCII
	LDB	T3,P3		;GET LENGTH OF VAR LENGTH STRING IN T3
	PUSHJ	P,VARLEN	;TYPE OUT FIELD LENGTH
	JUMPN	T3,XD01T4	;IF ANY BYTES, GO TYPE THEM
	PUSHJ	P,.TCRLF##	;NO BYTES SO FINISH LINE
	JRST	.POPJ1##	;RETURN

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

XD01T4:	ILDB	T2,P3		;GET A DATA BYTE FROM XMT BUFFER
	PUSHJ	P,.TSPAC##	;TYPE A SPACE
	PUSHJ	P,.THEXB	;TYPE THE HEX BYTE
	SOJG	T3,XD01T4	;TYPE ALL THE HEX BYTES
	JRST	XD01T8	    >	;GO TYPE OUT ASCII STRING OF THESE BYTES

;LOOP SENDING EXTENSIBLE ASCII OUTPUT

XD01T5:
XMT <	MOVE	P3,.IONOP(IO)	;REMEMBER POINTER TO CURRENT BYTE
	MOVE	P4,T3	    >	;REMEMBER FIELD LENGTH
	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
XMT <	JRST	XD01EX	    >	;TELL USER THIS IS EXTENSIBLE ASCII
	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
XMT <
XD01EX:	MOVEI	T1,[ASCIZ \ [extensible ASCII]\]
	PUSHJ	P,.TSTRG##	;TELL USER IT IS EXTENSIBLE ASCII
	ILDB	T2,P3		;RETRIEVE BYTE FROM XMT BUFFER
	PUSHJ	P,EXTENS	;TYPE OUT EXTENSIBLE BYTE
	TRNE	T2,200		;ALL DONE IF "0" EXTENSIBLE FLAG
	SOJG	P4,.-3		;LOOP FOR ALL BYTES

XD01T8:	PUSHJ	P,ASCSTR	;TYPE OUT ASCII STRING FOR THIS FIELD
	PUSHJ	P,.TCRLF##  >	;FINISH THE LINE NEATLY
	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	XD03T7		;YES
	TXNN	P2,DX$VAR	;NO, VARIABLE-LENGTH BINARY?
NOXMT <	JRST	XD03T3	    >	;NO, FIXED-LENGTH FIELD
XMT   <	JRST	XD03T1	    >	;NO, FIXED-LENGTH FIELD
	PUSHJ	P,XDBYT0	;YES, ALLOCATE COUNT BYTE
	 POPJ	P,		;OOPS
XMT <
XD03T1:	PUSH	P,T3		;SAVE THE BINARY VALUE FROM T3, T4 ON STACK
	PUSH	P,T4	    >	; . . .
	MOVE	P4,.IONOP(IO)	;REMEMBER WHERE COUNT BYTE IS
	JRST	XD03T3		;ENTER LOOP

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;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
NOXMT <	 POPJ	P,	    >	;OOPS
XMT   <	 JRST	[ADJSP	P,-2	;FIX STACK
		 POPJ	P,  ] >	;TAKE THE ERROR RETURN
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?
NOXMT <	JRST	.POPJ1##	;NO, ALL DONE HERE
	JUMPLE	P3,.POPJ1## >	;YES, FIELD FULL?
XMT   <	JRST	XD03TV          ;NO, ALL DONE HERE
	JUMPLE	P3,XD03TF   >	;YES, FIELD FULL?
	SETZ	T2,		;NO, NEED NULL-FILL
	PUSHJ	P,XDBYT0	;FILL REST OF FIELD
NOXMT <	 POPJ	P,	    >	;OOPS
XMT   <	 JRST	[ADJSP	P,-2	;FIX STACK
		 POPJ	P,  ] >	;TAKE THE ERROR RETURN
	SOJG	P3,.-2		;LOOP FOR REST OF FIELD
NOXMT <	JRST	.POPJ1##    >	;ALL DONE

XMT <
XD03TF:	MOVEI	T1,[ASCIZ \ [fix len bin, len from DAP spec= \]
	PUSHJ	P,.TSTRG##	;TELL USER IT IS FIXED LENGTH BINARY
	PUSHJ	P,FIXLEN	;TELL USER THE LENGTH
	LDB	T3,[POINTR DAPXCT(P1),DX$LNB]  ;GET THE LENGTH IN T3
	JRST	XD03T5	    >	;ENTER LOOP

XMT <
XD03TV:	MOVEI	T1,[ASCIZ \ [var len bin, len= \]
	PUSHJ	P,.TSTRG##	;TELL USER IT IS VAR LENGTH BINARY
	LDB	T3,P4		;GET THE FIELD LENGTH IN T3
	PUSHJ	P,VARLEN	;TYPE OUT FIELD LENGTH
	JUMPN	T3,XD03T5	;TYPE OUT BYTES IF ANY
	ADJSP	P,-2		;NO BYTES, WANT TO POP STACK TWICE
	JRST	XD03T6		;GO FINISH THE LINE

XD03T5:	ILDB	T2,P4		;GET A DATA BYTE FROM XMT BUFFER
	PUSHJ	P,.TSPAC##	;TYPE A SPACE
	PUSHJ	P,.THEXB	;TYPE THE HEX BYTE
	SOJG	T3,XD03T5	;TYPE ALL THE HEX BYTES

	POP	P,T4		;GET SECOND WORD OF BINARY NO.
	POP	P,T3		;GET FIRST  WORD OF BINARY NO.
	PUSHJ	P,BINFLD	;TYPE OUT BINARY VALUE
XD03T6:	PUSHJ	P,.TCRLF##	;FINISH OFF THE LINE
	JRST	.POPJ1##    >	;SUCCESSFUL RETURN

;EXTENSIBLE BINARY FIELD

XD03T7:	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	XD04T2		;YES
	STOPCD	<Fixed/variable length DAP flags field encountered in XD04T>

;LOOP SENDING EXTENSIBLE FLAGS FIELD

XD04T2:
XMT <	MOVEI	T1,[ASCIZ \ [extensible flags field]\] ;ASSUME EXTENS FLAGS
	LDB	T2,[POINTR DAPXCT(P1),DX$TYP] ;GET FIELD TYPE
	CAIE	T2,$DXTFL	;REALLY EXTENSIBLE FLAGS ?
	MOVEI	T1,[ASCIZ \ [extensible menu field]\] ;NO, MUST BE MENU
	PUSHJ	P,.TSTRG##	; . . .
	MOVE	P3,.IONOP(IO)	;SAVE POINTER TO OUTPUT BUFFER IN P3
	MOVE	P4,T3	    >	;SAVE FIELD LENGTH IN P4
	ILDB	T2,T4		;FIRST FLAG BYTE
	TROA	T2,200		;GUARANTEE AT LEAST ONE BYTE
XD04T3:	ILDB	T2,T4		;NEXT FLAG BYTE
	JUMPE	T2,XD04T9	;SEE IF TRAILING NULL
XD04T4:	TRO	T2,200		;SET EXTENSIBLE BIT
	PUSHJ	P,XDBYT1	;PUT INTO OUTPUT MESSAGE
	 POPJ	P,		;OOPS
	SOJG	T3,XD04T3	;LOOP FOR REST OF FIELD
XD04T5:	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
XMT <	MOVE	T4,P4		;GET FIELD LENGTH IN T4
XD04T6:	ILDB	T2,P3		;GET EXTENSIBLE FLAG BYTE
	PUSHJ	P,EXTENS	;TYPE OUT THE EXTENSIBLE BYTE
	TRNE	T2,200		;ALL DONE IF "0" EXTENSIBLE FLAG
	SOJG	T4,XD04T6	;LOOP IF FIELD NOT EXHAUSTED

	PUSHJ	P,.TCRLF##	;FINISH THE LINE
	LDB	T1,[POINTR DAPXCT(P1),DX$TYP] ;GET FIELD TYPE
	CAIN	T1,$DXTFL	;EXTENSIBLE FLAGS ?
	PUSHJ	P,FLGFLD    >	;YES,TYPE CORRESP. FLAG MESSAGES
	JRST	.POPJ1##	;SUCCESSFUL RETURN

XD04T9:	MOVE	T1,T3		;SAVE BYTE COUNT
	SOJLE	T3,XD04T5	;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	XD04T4		;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?
NOXMT <	JRST	XD05T2	    >	;NO, FIXED LENGTH
XMT   <	JRST	XD05T1	    >	;NO, FIXED LENGTH
	MOVE	T2,T3		;VARIABLE-LENGTH, GET SIZE OF FIELD
	PUSHJ	P,XDBYT1	;ALLOCATE BYTE COUNT BYTE
	 POPJ	P,		;OOPS
XMT <	MOVEI	T1,[ASCIZ \ [var len image, len= \]
	PUSHJ	P,.TSTRG##	;TELL USER IT IS VAR LENGTH IMAGE
	PUSHJ	P,VARLEN	;TYPE OUT FIELD LENGTH
	JRST	XD05T2	    >	;ENTER LOOP

XMT <
XD05T1:	MOVEI	T1,[ASCIZ \ [fix len image, len from DAP spec= \]
	PUSHJ	P,.TSTRG##	;TELL USER IT IS FIXED LENGTH IMAGE
	PUSHJ	P,FIXLEN    >	;TYPE OUT FIELD LENGTH

;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
XMT <	PUSHJ	P,.TSPAC##	;SPACE BETWEEN BYTES IS NEATER
	PUSHJ	P,.THEXB    >	;TYPE-OUT BYTE FROM T2
	SOJG	T3,XD05T2	;LOOP FOR REST OF MESSAGE FIELD
XMT <	PUSHJ	P,.TCRLF##  >	;FINISH LINE
	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?
NOXMT <	JRST	XD06T1	    >	;YES, DON'T TRANSMIT IT, BUT STILL PROCESS IT
XMT   <	JRST	[MOVEI	T1,[ASCIZ \ ("invisible" menu, ignored)\]
		 PUSHJ	P,.TSTRG##
		 PUSHJ	P,.TCRLF##
		 JRST	XD06T1]>;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>
XMT <	PUSHJ	P,.TTABC##	;TAB ACROSS
	MOVE	T1,DAPXTX(P1)	;ADDR OF FIELD DESCRIPTIVE TEXT
	PUSHJ	P,.TSTRG##	;TYPE THAT TEXT
	MOVE	T1,DAPXCT(P1) >	;PICK UP EXECUTION TABLE ENTRY
	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

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

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
XMT <	MOVEI	T1,[ASCIZ \ [ASCII date/time field] \]
	PUSHJ	P,.TSTRG##  >	;INFORM USER OF DATE/TIME FIELD
	PUSHJ	P,XD07DT	;PUT ASCIZ DATE/TIME IN .IODTM(IO)

;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
XMT <	MOVE	T1,T2		;GET THE CHAR
	PUSHJ	P,.TCHAR##  >	;INFORM USER OF DATE/TIME FIELD	CHAR
	SOJG	P3,XD07T4	;LOOP FOR ENTIRE FIELD'S WORTH

XMT <	PUSHJ	P,.TCRLF##  >	;FINISH LINE
	JRST	.POPJ1##	;SUCCESS RETURN

;ROUTINE TO MOVE DATE TO .IODTM(IO) AS ASCIZ STRING

XD07DT:	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
	POPJ	P,		;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
XMT <	PUSHJ	P,TSAV11##	;PRESERVE T1 (CONTAINS ADDRESS I/O CDB)
	PUSHJ	P,TRCFIL	;DIRECT TRACE, IF ANY, AS DETERMINED BY .JBOPC
	PUSHJ	P,.XTYPO##  	; . . .
	PUSHJ	P,.THEXB	;TYPE-OUT BYTE FROM T2
	PUSHJ	P,.TLPRN##	;TYPE LEFT PARENTHESIS
	LDB	T1,[POINT 7,T2,35] ;GET 7 BITS OF THE DATA BYTE
	JUMPN	T1,XDCRC2	;IF NOT A NULL GO TYPE IT
	MOVEI   T1,[ASCIZ \<NUL>\] ;KLUDGE BECAUSE .TFCHR
	PUSHJ   P,.TSTRG##	   ;CALLS NULLS ALTMODES
	SKIPA		           ;AND SWISCN NEEDS THAT
XDCRC2:	PUSHJ	P,.TFCHR##	;TYPE THE BYTE
	PUSHJ	P,.TRPRN##	;FINISH OFF WITH RIGHT PARENTHESIS
	PUSHJ	P,.TSPAC##  >	;SPACE BETWEEN BYTES IS NEATER
	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

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;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, BUT 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
XMT <	PUSHJ	P,TRCFIL	;DIRECT TRACE, IF ANY, AS DETERMINED BY .JBOPC
	PUSHJ	P,.XTYPO##	; . . .
	PUSHJ	P,.TCRLF	;SPACE TO MAKE NEW MESSAGE PROMINENT
	MOVE	T1,DAPXTX	;ADDR OF "DAP message type" TEXT
	PUSHJ	P,.TSTRG##	;TYPE THAT
	MOVEI	T1,[ASCIZ / - /];A DASH
	PUSHJ	P,.TSTRG##	;TYPE THE DASH
	MOVE	T1,.IODOM(IO)	;GET THE DAP MESSAGE TYPE
	MOVEI	T2,"0"		;USE ZEROES FOR FILLER
	PUSHJ	P,.TDEC2##	;TYPE OUT THE MESSAGE TYPE
	PUSHJ	P,.TSPAC##	;A SPACE MAKES MESSAGE PRETTY
	HRRZ	T2,.IODOM(IO)	;GET MESSAGE TYPE
	MOVEI	T4,DAPIDX	;DAP INDEX TABLE
	PUSHJ	P,.CFIND##	;FIND THE INDEX ENTRY FOR THIS MESSAGE TYPE
	 STOPCD	<XDMSG called with unknown DAP message>

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

	MOVE	T1,DAPXTX(T1)	;GET TEXT DESCRIBING DAP MESSAGE TYPE
 	PUSHJ	P,.TSTRG##	;TYPE TEXT DESCRIPTION OF DAP MESSAGE
	PUSHJ	P,.TSPAC##	;SPACE

;TYPE <<From US to REMOTE>>   WHERE US=OUR NODE NAME, REMOTE=REMOTE NODE NAME

	PUSHJ	P,.TLANG##	   ;<
	PUSHJ	P,.TLANG##	   ;<
	MOVEI	T1,[ASCIZ \From \] ;From
	PUSHJ	P,.TSTRG##
	MOVE	T1,.MYNOD##	   ;From US
	PUSHJ	P,.TSIXN##
	MOVEI	T1,[ASCIZ \ to \]  ;From US to
	PUSHJ	P,.TSTRG##
	MOVE	T1,.ION6M(IO)	   ;From US to REMOTE
	PUSHJ	P,.TSIXN##
	PUSHJ	P,.TRANG##	   ;>
	PUSHJ	P,.TRANG##	   ;>
	PUSHJ	P,.TCRLF##	;FINISH OFF THE LINE

	HRRZ	T2,.IODOM(IO) 	;RESTORE CURRENT OUTPUT MESSAGE TYPE
> ;END XMT
	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>
XMT <	PUSHJ	P,TRCFIL	;DIRECT TRACE, IF ANY, AS DETERMINED BY .JBOPC
	PUSHJ	P,.XTYPO##	; . . .
	MOVE	T1,.IODOM(IO)	;GET THE MESSAGE TYPE JUST ENDED
	CAIN	T1,$DHDAT	;WAS IT A DATA MESSAGE ?
	PUSHJ	P,.TCRLF##	;YES, FINISH LINE OF DATA NEATLY
	PUSHJ	P,.TTABC##	;TAB ACROSS
	PUSHJ	P,.TLBRK##	;TYPE LEFT BRACKET
	MOVE	T1,DAPXTX+1	;ADDR OF "Message header flags" TEXT
	PUSHJ	P,.TSTRG##	;TYPE THAT
	PUSHJ	P,.TSPAC##	;SPACE BETWEEN BYTES IS NEATER
	LDB	T2,.IODO1(IO)	;GET MESSAGE HEADER FLAGS IN T2
	PUSHJ	P,.THEXB	;TYPE-OUT FLAG BYTE FROM T2
	PUSHJ	P,.TRBRK##	;TYPE RIGHT BRACKET
	PUSHJ	P,.TCRLF##	;FINISH WITH <CR><LF>
	MOVEI	P1,1            ;SO .TFLAG GETS HEADER FLAG MESSAGES
	MOVE	P2,.IODOF(IO)	;GET MESSAGE HEADER FLAGS IN P2
	CLEAR	P3,		;ONLY ONE WORD OF FLAGS
	PUSHJ	P,.TFLAG    >	;TYPE CORRESP. DAP MESSAGES
	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
XMT <	PUSH	P,T1		;SAVE T1
	PUSH	P,T2		;SAVE T2
	PUSHJ	P,.TTABC##	;TAB ACROSS
	PUSHJ	P,.TLBRK##	;TYPE LEFT BRACKET
	MOVE	T1,DAPXTX+3	;ADDR OF "MSG data length (LSB)" TEXT
	PUSHJ	P,.TSTRG##	;TYPE THAT TEXT
	PUSHJ	P,.TSPAC##	;SPACE ACROSS
	LDB	T2,T2		;GET LSB IN T2
	PUSHJ	P,.THEXB	;TYPE THE HEX BYTE FROM T2
	PUSHJ	P,.TRBRK##	;TYPE RIGHT BRACKET
	PUSHJ	P,.TCRLF##	;FINISH WITH <CR><LF>
	POP	P,T2		;RESTORE T2
	POP	P,T1	    >	;RESTORE T1
	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>

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

XDEOM2:	DPB	T1,T2		;SET HIGH ORDER LENGTH FIELD
XMT <	PUSHJ	P,.TTABC##	;TAB ACROSS
	PUSHJ	P,.TLBRK##	;TYPE LEFT BRACKET
	MOVE	T1,DAPXTX+4	;ADDR OF "MSG data length (MSB)" TEXT
	PUSHJ	P,.TSTRG##	;TYPE THAT TEXT
	PUSHJ	P,.TSPAC##	;SPACE ACROSS
	LDB	T2,T2		;GET MSB
	PUSHJ	P,.THEXB	;TYPE THE HEX BYTE FROM T2
	PUSHJ	P,.TRBRK##	;TYPE RIGHT BRACKET
	PUSHJ	P,.TCRLF##  >	;FINISH WITH <CR><LF>
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
XMT <	PUSHJ	P,.TTABC##	;TAB ACROSS
	PUSHJ	P,.TLBRK##	;TYPE LEFT BRACKET
	MOVE	T1,DAPXTX+5	;ADDR OF "Trailing bit count" TEXT
	PUSHJ	P,.TSTRG##	;TYPE THAT TEXT
	PUSHJ	P,.TSPAC##	;SPACE ACROSS
	LDB	T2,T2		;GET TRAILING BIT COUNT
	PUSHJ	P,.THEXB	;TYPE THE HEX BYTE FROM T2
	PUSHJ	P,.TRBRK##	;TYPE RIGHT BRACKET
	PUSHJ	P,.TCRLF##  >	;FINISH WITH <CR><LF>
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	Miscellaneous routines used for DAP message trace

;VARLEN  --  TYPE LENGTH PORTION OF A VARIABLE LENGTH DAP FIELD
;Call is:
;
;	MOVX	T3,<LEN>
;	PUSHJ	P,VARLEN
;	 always return here
;
;Where <LEN> is the length of the variable length field.
;
;Preserves all AC's

$TRACE <
VARLEN:	PUSHJ	P,TSAV13	;SAVE T1 - T3
	MOVE	T2,T3		;GET FIELD LENGTH IN T2 FOR .THEXB
	PUSHJ	P,.THEXB	;TELL THE LENGTH IN HEX
	MOVEI	T1,[ASCIZ \ (\]	;TYPE A LEFT PARENTHESIS
	PUSHJ	P,.TSTRG##	; . . .
	MOVE	T1,T3		;GET THE LENGTH IN T1
	PUSHJ	P,.TDECW##	;TYPE THE DECIMAL LENGTH (SMASHES T1-T3)
	PUSHJ	P,.TDOT##	;TYPE A DECIMAL POINT
	PUSHJ	P,.TRPRN##	;TYPE A RIGHT PARENTHESIS
	PUSHJ	P,.TRBRK##	;TYPE A RIGHT BRACKET
	POPJ	P,		;RETURN
>

;FIXLEN  --  TYPE LENGTH PORTION OF A FIXED LENGTH DAP FIELD
;Call is:
;
;	MOVX	P1,<IDX>
;	PUSHJ	P,FIXLEN
;	 always return here
;
;Where <IDX> is the current RDDAP (for rcv) or XDDAP (for xmt) execution index.
;
;Preserves all AC's

$TRACE <
FIXLEN:	PUSHJ	P,TSAV13	;SAVE T1 - T3
	LDB	T1,[POINTR DAPXCT(P1),DX$LNB]  ;GET THE LENGTH IN T1
	PUSHJ	P,.TDECW##	;TYPE THE DECIMAL LENGTH (SMASHES T1-T3)
	PUSHJ	P,.TDOT##	;TYPE A DECIMAL POINT
	PUSHJ	P,.TRBRK##	;TYPE A RIGHT BRACKET
	POPJ	P,		;RETURN
>
;EXTENS  --  TYPE AN EXTENSIBLE BYTE AS HEX FOLLOWED BY THE EXTENSIBLE
;	      FLAG BIT AND THE 7-BIT OCTAL BYTE
;Call is:
;
;	MOVX	T2,<BYT>
;	PUSHJ	P,EXTENS
;	 always return here
;
;Where <BYT> is the extensible byte.
;
;Preserves all AC's

$TRACE <
EXTENS:	PUSHJ	P,TSAV13	;SAVE T1 - T3
	PUSHJ	P,.TSPAC##	;SPACE BETWEEN BYTES IS NEATER
	PUSHJ	P,.THEXB	;TYPE-OUT BYTE FROM T2
	PUSHJ	P,.TLPRN##	;TYPE LEFT PARENTHESIS
	MOVEI	T1,"0"		;ASSUME NOT AN EXTENSIBLE BYTE
	TRNE	T2,200		;AN EXTENSIBLE BYTE ?
	MOVEI	T1,"1"		;YES, THEN WE SHALL TYPE THE EXTENSIBLE FLAG
	PUSHJ	P,.TCHAR##	;INDICATE IF EXTENSIBLE OR NOT
	PUSHJ	P,.TSPAC##	;SPACE AFTER EXTENSIBILITY FLAG
	LDB	T1,[POINT 7,T2,35] ;GET 7 BITS OF THE EXTENSIBLE BYTE
	PUSHJ	P,.TOCTW##	;TYPE THE OCTAL VALUE (SMASHES T1-T3)
	PUSHJ	P,.TRPRN##	;FINISH OFF WITH RIGHT PARENTHESIS
	POPJ	P,		;RETURN
>

;ASCSTR  --  TYPE ASCIZ STRING FROM .IODAP FIELD IN I/O CDB
;Call is:
;
;	MOVX	P1,<IDX>
;	PUSHJ	P,ASCSTR
;	 always return here
;
;Where <IDX> is the current RDDAP (for rcv) or XDDAP (for xmt) execution index.
;
;Preserves all AC's

$TRACE <
ASCSTR:	PUSHJ	P,TSAV11	;SAVE T1
	MOVEI	T1,[ASCIZ \ (\]	;TYPE A LEFT PARENTHESIS
	PUSHJ	P,.TSTRG##	; . . .
	LDB	T1,[POINTR DAPXCT(P1),DX$IOX] ;FIELD STORAGE IN .IODAP
	ADDI	T1,.IODAP(IO)                 ; . . .
	PUSHJ	P,.TSTRG##	;TYPE THE STRING
	PUSHJ	P,.TRPRN##	;TYPE A RIGHT PARENTHESIS
	POPJ	P,		;RETURN
>
;BINFLD  --  TYPE OCTAL AND DECIMAL REPRESENTATIONS OF BINARY DAP FIELD
;	      AND CALL .TVALU TO GIVE TEXTUAL DESCRIPTION IF FIELD HAS ONE
;Call is:
;
;	MOVX	T3,<MSW>
;	MOVX	T4,<LSW>
;	MOVX	P1,<IDX>
;	PUSHJ	P,BINFLD
;	 always return here
;
;Where <MSW> is the most  significant word of the binary number.
;      <LSW> is the least significant word of the binary number.
;      <IDX> is the current RDDAP (for rcv) or XDDAP (for xmt) execution index.
;
;Preserves all AC's

$TRACE <
BINFLD:	PUSHJ	P,.SAVE4	;SAVE P1 - P4
	PUSHJ	P,TSAV13	;SAVE T1 - T3
	DMOVEM	T3,P3		;SAVE BINARY NO. FROM T3 & T4 IN P3 & P4
	MOVEI	T1,[ASCIZ \ (\]	;TYPE A LEFT PARENTHESIS
	PUSHJ	P,.TSTRG##	; . . .
	DMOVE	T1,P3		;GET THE BINARY FIELD IN T1 & T2
	PUSHJ	P,.TOCTD##	;TYPE FIELD AS SIGNED OCTAL DOUBLE-WORD NUMBER
	MOVEI	T1,"="		;TYPE AN EQUALS SIGN
	PUSHJ	P,.TCHAR##	; . . .
	DMOVE	T1,P3		;GET THE BINARY FIELD IN T1 & T2
	PUSHJ	P,.TDECD##	;TYPE FIELD AS SIGNED DECIMAL DOUBLE-WORD NUMBER
	PUSHJ	P,.TDOT##	;TYPE A DECIMAL POINT
	PUSHJ	P,.TRPRN##	;TYPE A RIGHT PARENTHESIS
	DMOVE	T3,P3		;RESTORE THE BINARY NO. INTO T3 & T4
	MOVE	T1,DAPXCT(P1)	;GET EXECUTION TABLE ENTRY FOR THIS FIELD
	TXNN	T1,DX$VAR	;VARIABLE LENGTH FIELD?
	PUSHJ	P,.TVALU	;NO, TYPE MESSAGE DESCRIBING FIELD VALUE
	POPJ	P,		;RETURN
>
;FLGFLD  --  EXTRACT FLAG BITS FROM .IODAP FIELD IN I/O CDB
;	     AND CALL .TFLAG TO TYPE FLAG DESCRIPTIONS.
;Call is:
;
;	MOVX	P1,<IDX>
;	PUSHJ	P,FLGFLD
;	 always return here
;
;Where <IDX> is the current RDDAP (for rcv) or XDDAP (for xmt) execution index.
;
;Preserves all AC's

$TRACE <
FLGFLD:	PUSHJ	P,.SAVE3##	;SAVE P1 - P3
	PUSHJ	P,TSAV13##	;SAVE T1 - T3
	LDB	T3,[POINTR DAPXCT(P1),DX$LNB] ;FIELD LENGTH (DAP BYTES)
	LDB	T1,[POINTR DAPXCT(P1),DX$IOX] ;FIELD STORAGE IN .IODAP
	ADDI	T1,.IODAP(IO)                 ; . . .
	MOVE	P2,(T1)		;GET 1ST FLAGS WORD
	CLEAR	P3,		;ASSUME NO 2ND FLAGS WORD
	CAILE	T3,^D5		;DO THEY FIT IN ONE WORD ?
	MOVE	P3,1(T1)	;NO, THEN GET 2ND FLAGS WORD
	PUSHJ	P,.TFLAG	;TYPE CORRESP. DAP MESSAGES
	POPJ	P,		;RETURN
>
;TRCRCV  --  TRACE A RECEIVED DAP DATA MESSAGE
;
;Call is:
;
;	PUSHJ	P,TRCRCV	or	PUSHJ	P,TRCRC0
;	 always return here		 always return here
;
;This routine has two entry points: TRCRCV and TRCRC0
;
;The call to TRCRCV is made from RDDAT to trace a DAP data message received.
;If the data message is incomplete when the NSP data buffer is emptied, the
;rest of the data message is traced by a call to TRCRC0 from RNBYT after
;RNBUF has filled the NSP data buffer with the rest of the message.
;
;Unfortunately, when simultaneously tracing messages received and transmitted,
;for example COPY REMOTE::FOO.BAR=REMOTE::FRED.BAR, the call to TRCRC0 may
;come after a trace of data transmitted. Thus the trace of the remainder of
;received data is appended to the trace of transmitted data. This is a minor
;inconvenience because <RCV> and <XMT> text is prepended to received and
;transmitted message trace making it easy to recognise when this situation has
;occurred and still possible to see where data belongs in the trace.
;
;Preserves all AC's


RCV <

TRCRCV:	PUSHJ	P,TSAV14##	;SAVE T1 - T4
	PUSHJ	P,TRCFIL	;DIRECT TRACE, IF ANY, AS DETERMINED BY .JBOPC
	PUSHJ	P,.XTYPO##	; . . .
	PUSHJ	P,.TTABC##  	;TAB ACROSS BEFORE TYPING DATA BYTES
	MOVE	T3,.IODIC(IO)	;GET COUNT OF DAP DATA BYTES IN MESSAGE
	CAMLE	T3,.IONIC(IO)	;FEWER DAP MESSAGE BYTES THAN BYTES IN BUFFER ?
	MOVE	T3,.IONIC(IO)	;NO, THEN TRACE OUT BYTES LEFT IN BUFFER
	AOJ	T3,		;FIX BECAUSE RDBYT HAS READ AHEAD
	SETO	T4,		;GET POINTER TO FIRST BYTE
	ADJBP	T4,.IONIP(IO)	;AND FIX BECAUSE RDBYT HAS READ AHEAD
	JRST	TRCRC3

TRCRC0:	PUSHJ	P,TSAV14##	;SAVE T1 - T4
	PUSHJ	P,TRCFIL	;DIRECT TRACE, IF ANY, AS DETERMINED BY .JBOPC
	PUSHJ	P,.XTYPO##	; . . .
	MOVE	T3,.IODIC(IO)	;GET COUNT OF DATA BYTES IN BUFFER
	AOJ	T3,		;FIX BECAUSE RDBYT HAS READ AHEAD
	CAMLE	T3,.IONIC(IO)	;FEWER DAP MESSAGE BYTES THAN BYTES IN BUFFER ?
	MOVE	T3,.IONIC(IO)	;NO, THEN TRACE OUT BYTES LEFT IN BUFFER
	MOVE	T4,.IONIP(IO)	;GET POINTER TO FIRST BYTE

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

TRCRC3:	MOVEI	T1,[ASCIZ \<RCV> \] ;ENSURE USER KNOWS THIS IS RECEIVED DATA
	PUSHJ	P,.TSTRG##
TRCRC4:	SOSGE	T3		;ANY BYTES LEFT ?
	 POPJ	P,		;NO, RETURN
	ILDB	T2,T4		;YES, PUT THE BYTE IN T2
	PUSHJ	P,.THEXB	;TYPE-OUT BYTE FROM T2
	PUSHJ	P,.TLPRN##	;TYPE LEFT PARENTHESIS
	LDB	T1,[POINT 7,T2,35] ;GET 7 BITS OF THE DATA BYTE
	JUMPN	T1,TRCRC5	;IF NOT A NULL GO TYPE IT
	MOVEI   T1,[ASCIZ \<NUL>\] ;KLUDGE BECAUSE .TFCHR
	PUSHJ   P,.TSTRG##	   ;CALLS NULLS ALTMODES
	SKIPA		           ;AND SWISCN NEEDS THAT
TRCRC5:	PUSHJ	P,.TFCHR##	;TYPE THE BYTE
	PUSHJ	P,.TRPRN##	;FINISH OFF WITH RIGHT PARENTHESIS
	PUSHJ	P,.TSPAC##  	;SPACE BETWEEN BYTES IS NEATER
	JRST	TRCRC4		;LOOP FOR MORE DATA BYTES

> ;END RCV
	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	Expand tables used to trace DAP messages

$TRACE <	DFVMSG:	FVMSG	    >	;THE ACTUAL MESSAGES
$TRACE <	DFVIDX:	FVIDX	    >	;POINTERS TO MESSAGES PARALLEL TO DAPXCT
	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,[NS.WAI!<.NSFEP,,.NSAA1+1>]  ;"ENTER PASSIVE" FUNCTION
	TXNN	T3,IO.NBT	;WANT THIS NON-BLOCKING?
	SKIPE	.IOSCH(IO)	;OR IS THERE AN I/O SCHEDULER LURKING ABOUT?
	TXZ	P1,NS.WAI	;YES TO ONE OF THE ABOVE, NON-BLOCKING
	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

;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,[.NSFRD,,.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

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

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

NAINI6:	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

	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
RCV <	MOVE	T2,.IODIM(IO)	;GET THE MESSAGE TYPE
	CAIN	T2,$DHDAT	;DATA MESSAGE ?
	PUSHJ	P,TRCRC0    >	;YES, TRACE RECEIVED DATA
	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

;NO DATA AVAILABLE, SEE IF THERE IS A SCHEDULER TO CALL.

	SKIPN	.IOSCH(IO)	;IS SCHEDULER SUPPLIED?
	JRST	RABUF5		;NO, GO SLEEP FOR A WHILE

;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	RABUF1		;OK, GO TRY AGAIN

;DON'T WANT NON-BLOCKING, AND HAVE NO SCHEDULER.  JUST SLEEP UNTIL WE
;GET OUR INPUT.

RABUF5:	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 AN 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

;CALL THE SCHEDULER

	SKIPN	.IOSCH(IO)	;IS THERE A SCHEDULER?
	JRST	XABUF5		;NO, GO TO SLEEP FOR A WHILE

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

;NO SCHEDULER TO CALL.  SINCE WE ALWAYS DO NON-BLOCKING TO ANF, JUST SLEEP
;FOR A WHILE.

XABUF5:	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
	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
	MOVX	M0,IO.ENM	;THE END-NETWORK-MESSAGE BIT
	ANDCAM	M0,.IOCCF(IO)	;CLEAR END OF MESSAGE REQUEST
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
	SUBTTL	Routine to type out descriptive messages for DAP msg flags.

;.TFLAG -- TYPE OUT ALL MESSAGES DESCRIBING DAP FLAGS IN A DAP MSG FIELD
;CALL IS:
;
;	MOVE	P1,<IDX>
;	MOVE  	P2,<FLG1>
;	MOVE	P3,<FLG2>
;	PUSHJ	P,.TFLAG
;
;Where <IDX> is the current RDDAP (for rcv) or XDDAP (for xmt) execution index.
;      <FLG1> is the first  word of flag bits (i.e.  0 to 34)
;      <FLG2> is the second word of flag bits (i.e. 35 to 70)
;
;Preserves all AC's

$TRACE <

.TFLAG:	PUSHJ	P,TSAV14##	;SAVE T1 - T4
	PUSHJ	P,.SAVE4##	;SAVE P1 - P4
	MOVE	T2,P2		;GET FIRST WORD OF FLAG BITS
	MOVEI	P4,^D0		;
	PUSHJ	P,.TFLG0	;INDEX INTO DFVIDX AND TYPE MESSAGES
	MOVE	T2,P3		;GET SECOND WORD OF FLAG BITS
	MOVEI	P4,^D35		;
	PUSHJ	P,.TFLG0	;INDEX INTO DFVIDX AND TYPE MESSAGES
	POPJ	P,		;RETURN

.TFLG0:	JFFO	T2,.+2		;PUT BIT POSITION OF FLAG IN T2 INTO T3
	 POPJ	P,		;NO MORE FLAGS, SO RETURN
	MOVSI	T4,400000	;LIGHT BIT AT BIT POSITION ZERO IN T4
	MOVN	T3,T3		;MOVE BIT IN T4 TO SAME POSITION AS FLAG IN T2
	LSH	T4,(T3)		; . . .
	TDZ	T2,T4		;ZERO FLAG BIT IN T2 SO WE IGNORE NEXT TIME

	MOVN	T3,T3		;MAKE T3 POSITIVE AGAIN

> ;END $TRACE

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

;THE NEXT PIECE OF MATHEMATICS TRANSLATES THE -10 BIT TO THE CORRESPONDING
;DAP BIT. SEE THE DEFINITION OF THE XF MACRO IN SWIL FOR THE EQUATION. IT IS
;INVARIANT SO THAT IT TRANSLATES A -10 BIT TO A DAP BIT AND VICE VERSA.

$TRACE <
	IDIVI	T3,^D7		;MAKE T3 AN OFFSET WITHIN PART OF DFVMSG WANTED
	IMULI	T3,^D7		; . . .
	ADDI	T3,^D6		; . . .
	SUBI	T3,(T4)		; . . .
	ADD	T3,P4		; . . .
	HLRE	T1,DFVIDX(P1)	;GET MAX BIT DEFINED FOR THIS FLAG
	JUMPL	T1,.TFLG1     	;OUR MAXIMUM MUST BE .GE. 0  TO MAKE SENSE
	CAMLE	T3,T1		;WITHIN LIMIT OF SPEC. DEFINED BY DAP MACRO ?
	JRST	.TFLG2		;NO, COMPLAIN TO USER
	PUSHJ	P,.TTABC##	;TAB ACROSS
	PUSHJ	P,.TTABC##	;TAB ACROSS AGAIN
	HRRZ	T1,DFVIDX(P1)	;GET ADR. OF ADR. OF MSG TABLE FOR FLAG FIELD
	ADDI	T3,(T1)         ;GET ADR. OF ADR. OF MSG FOR THIS FLAG
	MOVE	T1,(T3)         ;GET MSG ADR. IN T1
	PUSHJ	P,.TSTRG##	;TYPE THE MESSAGE FOR THIS FLAG
	PUSHJ	P,.TCRLF##	;MAKE IT NEAT
	JRST	.TFLG0		;RETURN FOR ANY REMAINING FLAG BITS

.TFLG1:	PUSHJ	P,.TTABC##	;TAB ACROSS
	PUSHJ	P,.TTABC##	;TAB AGAIN
	MOVEI	T1,[ASCIZ \?? Error in SWINET - found neg. maximum flag value ??\]
	JRST	.TFLG3		;GO TELL USER

.TFLG2:	PUSHJ	P,.TTABC##	;TAB ACROSS
	PUSHJ	P,.TTABC##	;TAB AGAIN
	MOVEI	T1,[ASCIZ \?? Flag value \]
	PUSHJ	P,.TSTRG##	;TYPE FIRST PART OF ERROR MESSAGE
	MOVE	T1,T3		;GET THE ERRONEOUS VALUE IN T1
	PUSHJ	P,.TDECW##	;TELL USER THE ERRONEOUS VALUE
	PUSHJ	P,.TDOT##	;TYPE A DECIMAL POINT
	MOVEI	T1,[ASCIZ \ not within DAP spec. for this field ??\]
.TFLG3:	PUSHJ	P,.TSTRG##	;TYPE END OF ERROR MESSAGE
	PUSHJ	P,.TCRLF##	;MAKE LINE NEAT
	POPJ	P,		;RETURN NOW AND ABANDON REST OF FLAGS

> ;END $TRACE
	SUBTTL	Routine to type out message describing value field

;.TVALU -- TYPE OUT DESCRIPTION OF VALUE FIELD
;CALL IS:
;
;	DMOVE  	T3,<VAL>
;	PUSHJ	P,.TVALU
;
;Where <VAL> is a positive integer in T3 and T4
;
;Preserves all AC's

$TRACE <

.TVALU:	JUMPN	T3,.POPJ##	;JUMP IF NUMBER MUCH TOO BIG FOR US
	PUSHJ	P,TSAV13	;SAVE T1 - T3
	MOVE	T2,DFVIDX(P1)	;PICK UP POSSIBLE AOBJN POINTER INTO DFVMSG
	HLRE	T3,T2		;GET EXPECTED NEGATIVE PART OF AOBJN POINTER
	JUMPGE	T3,.POPJ##	;THIS VALUE HAS NO DESCRIPTIVE MESSAGE
	PUSHJ	P,.TSPAC##	;SPACE ACROSS
	HLRZ	T1,(T2)		;GET A LEGAL VALUE FOR THIS FIELD
	CAMN	T1,T4		;SAME AS THE VALUE FOUND IN DAP PACKET ?
	JRST	.TVAL0		;YES, GO TYPE OUT DESCRIPTIVE MESSAGE
	AOBJN	T2,.-3		;NO, LOOP THROUGH ALL POSSIBLE VALUES FOR FIELD
	MOVEI	T1,[ASCIZ \?? Value not legal for this field ??\]
	SKIPA			;TELL BAD NEWS TO USER
.TVAL0:	HRRZ	T1,(T2)		;FOUND VALUE, PUT ADDRESS OF MESSAGE IN T1
	PUSHJ	P,.TSTRG##	;TYPE THE MESSAGE
	POPJ	P,		;RETURN

> ;END $TRACE
	SUBTTL	Routine to type out one 8 bit byte in hex.

;.THEXB -- TYPE OUT ONE HEX BYTE
;CALL IS:
;
;	LDB   	T2,<PTR>
;	PUSHJ	P,.THEXB
;
;Where <PTR> is a pointer to an 8 bit byte.
;
;Preserves all AC's

$TRACE <

.THEXB:	PUSHJ	P,TSAV14	;SAVE T1 - T4
	MOVEM	T2,T4		;SAVE T2 IN A SAFE PLACE
	LDB	T1,[POINT 4,T4,31] ;GET LEFT HALF OF BYTE
	MOVEI	T3,^D16		;SET RADIX ^D16 FOR CALL TO .TRDXW
	PUSHJ	P,.TRDXW##	;OUTPUT THAT IN HEX
	LDB	T1,[POINT 4,T4,35] ;GET RIGHT HALF OF BYTE
	MOVEI	T3,^D16		;SET RADIX ^D16 FOR CALL TO .TRDXW
	PUSHJ	P,.TRDXW##	;OUTPUT THAT IN HEX
	POPJ	P,		;RETURN

> ;END $TRACE
	SUBTTL	TRCFIL - Examine .JBOPC and determine DAP trace type-out rtne.

;TRCFIL -- DETERMINE DAP TRACE OUTPUT ROUTINE
;CALL IS:
;
;	PUSHJ	P,TRCFIL
;	 always return here
;
;On return T1 contains address of DAP trace type-out routine.
;
;Location .JBOPC is examined and the type-out routine determined thus:
; .JBOPC/ 0  type-out rtne is .POPJ## i.e. type-out is discarded
; .JBOPC/ 1  type-out rtne is 0 i.e. type-out goes to attached TTY:
; .JBOPC/ 2  type-out rtne is DAPTRC i.e. type-out goes to DSK:DAPTRC.LST
;
;Preserves all AC's

$TRACE <

TRCFIL:	PUSHJ	P,TSAV14##	;SAVE T1 - T4
	MOVEI	T1,.POPJ##	;ASSUME ZERO IN .JBOPC MEANING NO TRACE WANTED
	MOVEM	T1,-T1(P)	; . . .
	SKIPN	T2,.JBOPC	;IS .JBOPC ZERO ?
	POPJ	P,              ;YES, NO TRACE WANTED SO .POPJ## IS TRACE RTNE

	CLEARM	-T1(P)		;NO, ASSUME 1 IN .JBOPC MEANING TRACE TO TTY
	CAIN	T2,1		;IS .JBOPC 1 ?
	POPJ	P,		;YES, TRACE TO TTY WANTED SO 0 IS TRACE RTNE
	CAIE	T2,2		;NO, IS .JBOPC 2 FOR TRACE TO 'DAPTRC.LST' ?
	 WARNCD	<.JBOPC should be 0=no trace, 1=TTY trace, 2=DAPTRC.LST>

	SKIPL	TRCOPN		;IS DAPTRC.LST OPEN ALREADY ?
	JRST	TRCFL1		;NO, GO ENTER DAPTRC.LST FOR OUTPUT
	MOVEI	T1,DAPTRC	;YES, GET THE OUTPUT TRACE ROUTINE
	MOVEM	T1,-T1(P)	;RETURN OUTPUT TRACE RTNE IN T1
	POPJ	P,		;RETURN

TRCFL1:	MOVE	T1,[.FOPAT+1,,TRCFLP]  ;[LENGTH,,ADDR] OF FILOP. BLOCK
	FILOP.	T1,		       ;ENTER 'DAPTRC.LST' FOR WRITING
	 STOPCD	<FILOP. failed in TRCFIL, tracing to TTY>,,,.POPJ##

	CLEAR	T1,		;REQUIRE MANAGED MEMORY ALLOCATION
	MOVE	T2,[3,,200]	;REQUIRE 3 BUFFERS EACH 200 WORDS
	MOVEI	T4,TRCBHD	;ADDRESS BUFFER RING HEADER BLOCK
	PUSHJ	P,IOBFA1	;ALLOCATE BUFFERS AND LINK TOGETHER
	 STOPCD	<Call to IOBFA1 failed in TRCFIL, tracing to TTY>,,,.POPJ##

	MOVEI	T1,DAPTRC	;GET THE OUTPUT TRACE ROUTINE
	MOVEM	T1,-T1(P)	;PLACE OUTPUT TRACE RTNE IN T1
	SETOM	TRCOPN		;FLAG TRACE FILE OPEN FOR OUTPUT
	POPJ	P,		;RETURN

> ;END $TRACE

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

$TRACE <

DAPTRC:	SOSGE	TRCBHD+.BFCTR	;ROOM LEFT IN OUTPUT BUFFER ?
	JRST	DAPTR1		;NO, EMPTY A BUFFER
	IDPB	T1,TRCBHD+.BFPTR ;YES, DEPOSIT CHAR IN OUTPUT BUFFER
	POPJ	P,              ;RETURN

DAPTR1:	PUSHJ	P,TSAV13##	;SAVE T1 - T3
	LDB	T3,[POINTR TRCFLP+.FOFNC,FO.CHN] ;GET CHANNEL FROM ENTER
	LSH	T3,^D18		;POSITION IN CORRECT PLACE
	HRRI	T3,.FOOUT	;NEED THE OUTPUT FILOP. FUNCTION
	MOVE	T2,[XWD 1,T3]	;OUTPUT THE BUFFER TO 'DAPTRC.LST'
	FILOP.	T2,		; . . .
	 STOPCD	<FILOP. failed to write buffer to DAPTRC.LST in DAPTRC>
	JRST	DAPTRC		;TRY AGAIN

> ;END $TRACE

;CONTINUED ON NEXT PAGE
;CONTINUED FROM PREVIOUS PAGE

$TRACE <	XLIST		;LITERALS
	LIT
	LIST
	RELOC		;SWITCH TO LOSEG

TRCFLP: FO.PRV+FO.ASC+.FOWRT    ;WANT MONITOR ASSIGNED CHAN TO WRITE FILE
	.IOASC	                ;WANT ASCII MODE
	'DSK   '                ;WANT GENERIC DISK
	TRCBHD,,0		;ADDR OF ^D3 WORD BUFFER RING HEADER BLOCK
	0                       ;NO BUFFERS TO BE ALLOCATED YET
	TRCENT                  ;ADDR OF ENTER BLOCK
	0                       ;PATH (DEFAULT)

TRCBHD:	BLOCK	3		;BUFFER RING HEADER BLOCK

TRCENT: .RBEXT                  ;NO. OF ARGUMENTS FOLLOWING
	0                       ;ENTER BLOCK PPN/PATH (DEFAULT)
	'DAPTRC'                ;FILE NAME
	'LST   '                ;EXTENSION

TRCOPN:	BLOCK	1		;FLAG -1 IF TRACE FILE IS OPEN

> ;END $TRACE

	END