Google
 

Trailing-Edge - PDP-10 Archives - BB-X140B-BB_1986 - 10,7/703anf/dnncl.p11
There are 3 other files named dnncl.p11 in the archive. Click here to see a list.
.SBTTL	DNNCL - NCL ROUTINES  3 SEP 85

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1976,1977,1978,1979,1980,1981,1984 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.

VRNCL=057		 ;FILE EDIT NUMBER

;HERE ONCE A JIFFY.  SEE IF THERE ARE ANY MESSAGES THAT NEED TO BE RESENT.
;  IF NOT, RETURN, IF SO, RESEND THEM

NCLJIF:	MOV	MSGRSQ,R0		;GET ADDRESS OF FIRST MSG TO RESEND
	BEQ	NCLJI1			;IF NONE, CHECK SCB'S
	TWIDDLE				;COUNT THE MSGS RESENT
	MOV	CN.MLK(R0),MSGRSQ	;DELINK THIS MESSAGE
	ASSERT	CHUNK R0		;MAKE SURE THAT IT IS INDEED A MSG
	CLR	CN.MLK(R0)		;MAKE SURE WE ONLY HAVE 1 MESSAEG
	SAVE	<R0>			;SAVE MESSAGE POINTER
	MOV	R0,R3			;COPY CHUNK ADR
	MOV	CN.LEN(R0),R2		;GET MESSAGE LENGTH
	ASSERT	NE			;BETTER BE SOMETHING THERE
	ADD	#CN.NCT,R3		;POINT TO 1ST REAL CHAR
	JSR	PC,GETEXN		;GET THE NCT BYTE
	BIT	#7,R0			;IS THIS A NUMBERED MESSAGE?
	BNE	20$			;IF NOT NUMBERED, THEN DELETE IT
	JSR	PC,GETEXN		;GET DNA
	JSR	PC,FNDSCB		;SEE IF THE NODE IS STILL UP
	BEQ	20$			;IF NODE IS GONE, DELETE THE MSG
	MOV	SB,DNA			;SAVE DNA ADDRESS
	JSR	PC,GETEXN		;GET THE SNA
	JSR	PC,FNDSCB		;GET THE SOURCE'S SCB
	BEQ	20$			;IF SOURCE IS GONE, TOSS THE MESSAGE
	BIT	#SBF.SQ,@SB		;IF THE SOURCE CAN RE-XMIT HIMSELF
	BEQ	20$			; DON'T ADD TO THE CONFUSION
	MOV	SB,SNA			;REMEMBER THE SOURCE
	MOV	DNA,SB			;NOW, POINT TO THE APPROPRIATE
	MOV	#SQNTAB,R0		;GET ADDRESS OF THE FIRST IN SQNTAB
10$:	CMP	@R0,SNA			;IS THIS ONE THE SOURCE
	BEQ	15$			;IF THIS IS IT, SB IS AT RIGHT WINDOW
	ADD	#SQNSIZ,SB		;IF NOT, STEP TO THE NEXT WINDOW
	TST	(R0)+			;SKIP TO THE NEXT ENTRY
	ASSERT	NE			;DIE IF THE LAST ONE WAS ZERO
	BR	10$			; AND SEE IF THAT IS THE ONT
15$:	MOVB	SB.RMN(SB),@R3		;FIXUP THE ACK TO REFLECT NEW VALUE.
	RESTORE	<R0>			;GET MESSAGE POINTER BACK
	JSR	PC,DDQDAT		;SEND THE MESSAGE
	BR	NCLJIF			;TRY TO RESEND MORE MSGS

20$:	RESTORE	<R0>			;GET MESSAGE POINTER BACK
	JSR	PC,FRECKS		;FREE USLESS NODE-ID OR WHATEVER
	BR	NCLJIF			;TRY NEXT MSG
;HERE TO TRY TO ASSIGN NUMBERS TO MESSAGES
NCLJI1:	MOV	#OURSCB,SB		;START WITH THE FIRST SCB.
10$:	MOV	SB.WOQ(SB),-(SP)	;GET THE LIST OF MSGS TO SEND
	CLR	SB.WOQ(SB)		;CLEAR THE LIST SO NCLIN2 WILL WORK
20$:	MOV	(SP),R0			;GET THE NEXT MSG TO GO
	BEQ	30$			; IF NO MORE, THEN WE'RE DONE
	MOV	CN.MLK(R0),(SP)		;SAVE THE NEXT FOR NEXT TIME
	JSR	PC,NCLIN1		;TRY ONCE MORE TO SEND THE MSG
	BR	20$			; GO BACK FOR THE REST
30$:	TST	(SP)+			;POP THE ZERO OFF THE STACK
	SB.ADV	10$			;CHECK THE NEXT SCB
	RTS	PC			; AND WE'RE DONE



;HERE TO REQUEUE A MESSAGE (CALLED BY LINE DRIVERS WHEN LINE GOES DOWN)
;CALL WITH R0 := POINTER TO THE MESSAGE
MSGREQ:	PIOFF				;NO INTERRUPTS
	ASSERT	CHUNK R0		;MAKE SURE IT'S REALLY A MESSAGE
	MOV	MSGRSQ,CN.MLK(R0)	;MAKE MESSAGE POINT TO REST OF Q
	MOV	R0,MSGRSQ		;MAKE MESSAGE BE HEAD OF QUEUE
	PION				;ALL'S CLEAR NOW
	RTS	PC			;ALL DONE
;HERE WHEN REP TIMER GOES OFF
; WILL SEND A NODE-ID, START, OR REP MESSAGE

NCLSEC:	MOVB	#1,SB.TIM(SB)		;WHEN TO TRY AGAIN
	BIT	#SF.HID,@DNA		;DO I KNOW WHO IT IS ?
	BEQ	NCLS50			;IF NOT DON'T SEND NCL-START
					; CONSIDER PROBLEM OF 2 LINES TO SAME STATION
	MOV	#3,R1			;CODE FOR REP
	BIT	#SBF.SK,@SB		;DO WE NEED TO SEND NCL-STACK ?
	BNE	19$
	BIT	#SBF.IC,@SB		;HAVE WE SENT NCL START YET ?
	BEQ	20$
	JSR	PC,NCLBMS		;BEGIN BUILDING REP MESSAGE
	BEQ	NCLS50			;BRANCH IF COULDN'T
	TWIDDLE
	BIS	#SBF.RP,@SB		;FLAG REP IS OUTSTANDING
	MOVB	#TNCREP,SB.TIM(SB)	;WHEN TO TRY AGAIN
	BR	NCLS49			;SEND REP
;HERE TO SEND AN NCL-STACK MESSAGE
19$:	INC	R1
;HERE TO SEND AN NCL-START MESSAGE
20$:	INC	R1			;MAKE CODE FOR START
	JSR	PC,NCLBMS		;BEGIN MESSAGE
	BEQ	NCLS50			;IF NO CHUNKS TRY AGAIN LATER
	MOVB	#TNCREP,SB.TIM(SB)	;RESET TIMER
	JSR	PC,NCLS40		;FINISH OUT MESSAGE
NCLS49:	MOV	(P)+,R0			;GET ADR OF CHUNK BACK
	MOV	R2,CN.LEN(R0)		;SAVE LENGTH OF MSG
	PJMP	NCLIN1			;SEND MESSAGE
;HERE TO PUT <OUR NODE #><SOFTWARE ID><SOFTWARE DATE> INTO MSG
NCLS40:	MOV	SNA,R1			;SOURCE SCB ADR
	MOV	SB.NNM(R1),R0		;SOURCE NNM
	JSR	PC,PUTEXN		;PUT IT INTO THE MESSAGE
	MOV	#SB.SNM,R1		;POINT TO STATION NAME
	JSR	PC,46$			;COPY STATION NAME
	MOV	#SB.SID,R1		;MAKE ADR OF SOFTWARE ID
	JSR	PC,46$			;PUT INTO MESSAGE
.IF EQ DATESZ
	CLR	R0
	PJMP	PUTBYT			;DATE FIELD IS EMPTY
.IFF
	MOV	#SB.DAT,R1
	;JSR	PC,46$			;PUT INTO MESSAGE
	;RTS	PC
.ENDC;.IF EQ DATESZ
46$:	ADD	SNA,R1			;MAKE ABSOLUTE ADDR
47$:	MOVB	@R1,R0			;GET NEXT BYTE
	JSR	PC,PUTBYT		;PUT INTO THE MESSAGE
	TSTB	(R1)+			;WAS THAT LAST BYTE ?
	BMI	47$			;IF NOT LOOP BACK FOR MORE
	;RTS	PC			;ALL DONE

;HERE BECAUSE CAN'T SEND MESSAGE BECAUSE OUT OF CHUNKS
NCLS50:	RTS	PC
;HERE BECAUSE STATION HAD REQUEST IN QUEUE

NCLCHK:	SAVE	<SB>		;SAVE DESTINATION SCB
	MOV	#-SQNSIZ,-(P)	;INITIAL SOURCE OFFSET WILL BE ZERO
	MOV	#SQNTAB-2,-(P)	;LOCATE THE SEQUENTIAL NODE TABLE
10$:	ADD	#2,(P)		;MOVE ON TO THE NEXT STATION
	ADD	#SQNSIZ,2(P)
	MOV	@(P),SNA	;FETCH THE SOURCE NODE'S SCB
	BNE	11$
				;IF NONE EXIT
	CMP	(P)+,(P)+	;POP STACK
	RESTORE	<SB>
	RTS	PC

11$:
	MOV	2(P),SB		;GET OFFSET FOR NEW SCB
	MOV	SB,SNAOFF
	MOV	4(P),DNA	;SET DESTINATION
.IF NE FTASRT
;				CHECK TO BE SURE STACK IS GOOD
	CLR	R0
	MOV	#SQNTAB,R1
13$:	CMP	SNA,(R1)+
	BEQ	18$
	ADD	#SQNSIZ,R0
	BR	13$
18$:	ASSERT	R0 EQ SB
.ENDC
	ADD	DNA,SB		;MAKE OFFSET INTO ADDRESS
	JSR	PC,NCHK.A	;PERFORM THE NCL ACTION REQUIRED
	BR	10$		;LOOP ON NEXT NODE
;HERE TO FIGURE OUT WHAT CONTROL MSGS TO SEND

NCHK.A:	BIT	#SBF.IC,(SB)	;IF WE'RE NOT IN CONTACT,
	BEQ	NCHK3A		;THAT'S ALL
	MOV	#2,R1		;SET NAK CODE
	BIT	#SBF.NK,(SB)	;IF WE NEED TO NAK HIM, DO IT
	BNE	NCHK1A
	DEC	R1		;SET ACK CODE
	BIT	#SBF.RR,(SB)	;IF HE NEEDS REP RESPONSE, SEND AN ACK
	BNE	NCHK1A
	BIT	#SBF.RP!SBF.SK,(SB)	;IF HE WANTS A STACK, OR WE
				;WANT A REP RESPONSE
	BNE	NCHK0A		;SEND ONLY ACKS
	CMP	SNA,#OURSCB	;IF WE AREN'T THE SOURCE,
	BNE	NCHK0A		;BETTER NOT SEND ANYTHING BUT ACKS
	CMP	DNA,#OURSCB	;IF WE ARE THE DESTINATION,
	BEQ	NCHK0A		;BETTER NOT SEND ANYTHING BUT ACKS
	NCZ=SBF.NB		;NEIGHBORS REQUESTED
	.IIF NE DEVN,NCZ=NCZ!SF.XCN	;IF WE HAVE DEVICES,
				;WE MAY HAVE TO SEND CONFIG
	.IIF NE FTHOST,NCZ=NCZ!SF.XRC	;IF WE SUPPORT HOST,
				;WE MAY HAVE TO REQUEST CONFIG
	BIT	#NCZ,(SB)	;IF FUNNY MSGS ARE NOT REQUIRED,
	BEQ	NCHK0A		;CHECK IF ACK REQUIRED
	CLR	R1		;SET FUNNY MSG CODE
	BR	NCHK1A		;AND GET IT SENT
NCHK0A:	BIT	#SF.XAK,(SB)	;IF ACK NOT REQUIRED,
	BEQ	NCHK3A		;EXIT
NCHK1A:	MOV	R1,J		;SAVE CODE FOR A WHILE
	JSR	PC,NCLBMS	;START THE MSG
	  BEQ	NCHK3A		;COULDN'T START IT, SO EXIT
	TST	J
	BEQ	10$
				;THIS WAS NOT FUNNY MSG REQUEST, SO
	BIC	#SF.XAK!SBF.NK!SBF.RR,(SB)	;CLEAR THE REQUESTS
	BR	NCHK2A
10$:	JSR	PC,NCHK.C	;FINISH OFF THE FUNNY MSG
NCHK2A:	MOV	(P)+,R0		;GET THE MSG ADR
	MOV	R2,CN.LEN(R0)	;SET THE MSG LENGTH
	TRACE	NC
	JSR	PC,NCLIN1	;AND ROUTE IT
NCHK3A:	RTS	PC		;THEN EXIT
;HERE TO SEND NEIGHBOURS MESSAGE OR CONFIGURATION MESSAGE
NCHK.C:	CLRB	(R3)+		;=0 SINCE MESSAGE IS NUMBERED CONTROL
	INC	R2		;COUNT BYTE
	MOV	R3,R0		;SAVE ADR OF COUNT FIELD
	MOVB	#200,(R3)+	;SET COUNT TO EXTENSIBLE BINARY ZERO
	CLRB	(R3)+
	MOV	R2,-(P)		;SAVE CURRENT COUNT
	MOV	R0,-(P)		;SAVE ADR OF COUNT FIELD
	CLR	R2		;REINITIALIZE COUNT
	BIT	#SBF.NB,(SB)	;IF NEIGHBORS NOT REQUESTED,
	BEQ	NCHK1C		;WE NEED TO SEND CONFIG MSGS
	JSR	PC,NCK.NH	;GOT TO SEND NEIGHBORS
	BR	NCHK2C		;FINISH UP
NCHK1C:	JSR	PC,NCK.CF	;GOT TO SEND CONFIG
NCHK2C:	MOV	R2,R0		;COPY LENGTH
	MOV	(P)+,R3		;GET ADDRESS OF COUNT FIELD
	JSR	PC,PEXBYT	;INSERT LOW 7 BITS OF COUNT IN MSG
	MOV	R2,R0
	DEC	R0		;DON'T COUNT THIS BYTE
	ASL	R0
	SWAB	R0
	BIC	#^C177,R0	;INSERT NEXT 7 BITS OF COUNT IN MSG
	JSR	PC,PUTBYT
	ADD	(P)+,R2		;MAKE COUNT ADD UP TO TOTAL LENGTH
	RTS	PC		;AND EXIT
;HERE TO BUILD NEIGHBORS MSG

NCK.NH:	MOV	#NCLNGH,R0	;SET CODE FOR NEIGHBOURS MESSAGE
	JSR	PC,PUTBYT	;PUT IT INTO THE MESSAGE
	BIC	#SBF.NB,@SB	;CLEAR REQUEST, WE ARE SENDING NEIGHBOURS NOW
	SAVE	<SB>
	BIT	#SBF.SQ,@DNA	;SENDING TO SEQ-NEG
	BEQ	9$		;IF NOT
	CLR	R0		;YES - FIND WONDOW OFFSET
	MOV	#SQNTAB,R1	;POINT TO SEQ NGH TABLE
7$:	CMP	DNA,@R1		;IS THIS ONE THE ONE?
	BEQ	8$		;IF SO
	ADD	#SQNSIZ,R0	;NO - ADD SIZE OF WINDOW
	TST	(R1)+		;STEP ON TO NEXT ENTRY
	BEQ	SBRSTR		;?? NOT THERE ??
	BR	7$		;TRY NEXT
8$:	MOV	R0,-(P)		;SAVE WINDOW OFFSET FOR LATER
9$:
;				;IF WE HAVE A DL10, LET EVERYONE KNOW
.IF NE FTDL10!FT.DTE
	MOV	TENSCB,SB	;POINT TO SCB FOR 10, AND GET ITS LEVEL (LVL)
	BEQ	10$		;IF NONE, THEN THE 10 ISN'T UP YET
	BIT	#SBF.SQ,@DNA	;SENDING TO SEQ-NGH ?
	BEQ	21$		;IF NOT
	MOV	SB,R0		;YES - POINT TO TENSCB
	ADD	(P),R0		;POINT TO WINDOW
	TWIDDLE	
	BIT	#SBF.IC,@R0	;IN CONTACT?
	BEQ	10$		;NO - DON'T PUT TEN INTO NEIGHBOURS YET
	TWIDDLE
21$:
	MOV	#TENLVL,R1
	JSR	PC,NCKINH	;INSERT 10 AS NEIGHBOR IN MSG
10$:
.ENDC;.IF NE FTDL10!FT.DTE
	MOV	DNA,J		;GET DESTINATION ADDRESS
	BIT	#SBF.SQ,@J	;BRANCH ON NON SEQUENTIAL DESTINATIONS
				;THESE HAVE DIFFERENT DATA STRUCTURES
	BEQ	30$

.IF NE NTLINE
;HERE TO BUILD NEIGHBOURS MESSAGE TO SEND TO SEQUENTIAL NODE
	MOV	#SCB0,SB	;POINT TO FIRST SCB
20$:	CMP	SB.LBA(J),SB.LBA(SB)	;IF ROUTING IS THE SAME AS THAT
			;FOR THE DESTINATION, DON'T INCLUDE HIM AS A NEIGHBOR
	BEQ	22$
.IF NE FTDL10!FT.DTE
	CMP	TENSCB,SB	;IF THIS IS THE TEN'S SCB
	BEQ	22$		; THEN WE ALREADY SEND IT
.ENDC
	MOV	SB,R0		;POINT TO SCB TO CHECK
	ADD	(P),R0		;POINT TO WINDOW
	TWIDDLE
	BIT	#SBF.IC,@R0	;IN CONTACT YET?
	BEQ	22$		;IF NOT, DON'T INCLUDE IN NEIGHBOURS
	TWIDDLE
	MOV	SB.LBA+2(SB),R1	;GET THE LEVEL (LVL)
	JSR	PC,NCKINH	;AND INSERT IN THE MSG AS A NEIGHBOR
22$:	SB.ADV	20$
.ENDC ;.IF NE NTLINE
	TST	(P)+		;REMOVE WINDOW
	RESTORE	<SB>
	RTS	PC

;HERE TO BUILD NEIGHBOURS MESSAGE TO SEND TO NONSEQUENTIAL NODE
30$:
.IF NE NTLINE
	MOV	#FRSTLB,J	;GET FIRST LINE BLOCK
	BR	36$
34$:	MOV	LB.SCB(J),SB	;GET ASSOCIATED SCB ADR
	BEQ	36$
	MOV	LB.LVL(J),R1	;GET LEVEL FOR LINE
	JSR	PC,NCKINH	;INSERT HIM IN MSG AS A NEIGHBOR
36$:	MOV	LB.LNK(J),J	;GET NEXT LINE BLOCK
	BNE	34$
.ENDC;.IF NE NTLINE
SBRSTR:	RESTORE	<SB>
	RTS	PC
;HERE TO INSERT A NEIGHBOR IN NEIGHBORS MSG

NCKINH:	BIT	#SF.HID,@SB	;IF WE DON'T HAVE HIS ID, FORGET ABOUT IT
	BEQ	48$
	MOV	SB.NNM(SB),R0	;GET NODE NUMBER
	ASSERT	NE
	JSR	PC,PUTEXN	;PUT IT INTO THE MSG
	MOV	R1,R0		;COPY LEVEL
	ASSERT	NE
	JSR	PC,PUTBYT	;AND PUT IT IN THE MSG
48$:	RTS	PC

;HERE TO BUILD BODY OF CONFIGURATION MESSSAGE
NCK.CF:
.IF NE FTHOST
	BIT	#SF.XRC,@SB	;IF REQUEST CONFIG REQUIRED,
	BEQ	10$
	BIC	#SF.XRC,@SB	;CLEAR REQUEST
	MOV	#NCLRCN,R0	;SET CODE FOR REQUEST CONFIG
	JSR	PC,PUTBYT
	RTS	PC		;AND EXIT
.ENDC;.IF NE FTHOST
10$:	MOV	#NCLCNF,R0	;SET CODE FOR CONFIGURATION MESSAGE
	JSR	PC,PUTBYT
	BIC	#SF.XCN,@SB	;CLEAR REQUEST FOR CONFIG
.IF NE DEVN
	MOV	FIRDDB,J	;GET ADDRESS OF 1ST DEVICE BLOCK
42$:	MOVB	DB.OBJ(J),R0	;GET OBJECT TYPE
.IF EQ FTOLDC
;			NEW CONFIG MSG FORMAT (COUNT FOR UNITS)
	MOV	R0,R1		;COPY IT, AND PUT IT IN MSG
43$:	JSR	PC,PUTBYT
	CLR	R0		;CLEAR OBJECT COUNT
44$:	CMPB	DB.OBJ(J),R1	;IF OBJECT TYPE IS THE SAME,
	BNE	46$
	INC	R0		;COUNT IT
	MOV	DB.LNK(J),J	;GET NEXT DEVICE BLOCK
	BNE	44$
46$:	JSR	PC,PUTEXN	;PUT OUT COUNT FOR THIS ONE

.IFF
;			OLD CONFIG MSG FORMAT (BIT MAP FOR UNITS)
	MOV	R0,-(P)		;SAVE OBJECT TYPE
43$:	JSR	PC,PUTBYT	;AND PUT IT IN THE MSG
	CLR	R0		;START BIT MASK FOR DEVICE
	MOV	#1,R1		;SET BIT FOR FIRST
44$:	CMPB	DB.OBJ(J),(P)	;IF SAME OBJECT TYPE AS LAST,
	BNE	46$
	BISB	R1,R0		;INCLUDE IT
	BMI	43$		;IF BYTE IS FILLED, PUT IT OUT
	ASL	R1		;MOVE TO THE NEXT BIT
	MOV	DB.LNK(J),J	;AND THE NEXT DDB
	BNE	44$
46$:	TST	(P)+		;CLEAN THE STACK
	JSR	PC,PUTBYT	;PUT OUT THE MASK FOR THIS DEVICE
.ENDC	;IF EQ FTOLDC
	CLR	R0		; SET PID
	JSR	PC,PUTBYT
	TST	J
	BNE	42$		;IF DEVICES LEFT UNCOUNTED, GO COUNT THEM
.ENDC;.IF NE DEVN
	RTS	PC

;HERE TO BEGIN BUILDING A NCL MESSAGE
; CALL WITH NCT IN R1
;	WILL GET A CHUNK, PUT IN NCT, SNA, DNA, NCA, AND NCN
;	AND WILL RETURN WITH ADR OF CHUNK ON STACK
NCLBMS:	JSR	PC,GETCNK		;GET A CHUNK
	BNE	NCLBM1
	RTS	PC
NCLBM1:	CLR	R2			;INITIALIZE THE COUNT
	TRACE	NC			;PUT MESSAGE TYPE IN TRACE
	MOV	@P,-(P)			;PUT PC ON STACK AGAIN
	MOV	R0,2(P)			;AND PUT CHUNK ADR ON STACK
	MOV	R0,R3			;COPY CHUNK ADR TO RIGHT REG
	CLR	CN.MLK(R3)		;CLEAR LINK TO NEXT MESSAGE
.IIF NE DEVN!FT.DTE,	CLR	CN.DDB(R3)	;NO LINK ADDRESS YET
	ADD	#CN.NCT,R3		;POINT TO NCL PORTION OF MSG
	INC	R2			;COUNT NCT INTO THE MESSAGE
	CMPB	R1,#6			;IS THIS A NODE ID MESSAGE ?
	BEQ	20$			;IF SO NO SNA/DNA
	BIS	#110,R1			;BIT SAYING WE HAVE SNA & DNA
	MOVB	R1,(R3)+		;PUT TYPE INTO THE MESSAGE
	MOV	DNA,R0			;GET DESTINATION SCB ADR
	BEQ	NCLBME
	MOV	SB.NNM(R0),R0		;GET DESTINATION NNM
	BEQ	NCLBME
	JSR	PC,PUTEXN		;PUT IT INTO THE HEADER
	MOV	SNA,R0			;GET SCB ADR FOR SOURCE
	BEQ	NCLBME
	MOV	SB.NNM(R0),R0		;GET SOURCE NNM
	BEQ	NCLBME
	JSR	PC,PUTEXN		;PUT IT INTO THE HEADER
	BR	30$
20$:	MOVB	#106,(R3)+		;PUT MESSAGE TYPE INTO MESSAGE
30$:	CLRB	(R3)+
	INC	R2			;COUNT BYTE
	CLRB	(R3)+			;PUT LAST MSG# SENT IN HEADER
	INC	R2			;COUNT BYTE
99$:	RTS	PC

NCLBME:	RESTORE	<R1,R0>
	SAVE	<R1>
	JSR	PC,FRECKS		;CHUCK THE MSG AND REPORT THE ERROR
.IF NE DGUTS
	CTYMSG	BME
.ENDC
	SEZ				;SET ZERO CONDITION
	RTS	PC
;HERE TO PUT AN EXTENSIBLE NUMBER INTO A CHUNK
; CALL	MOV #<EXT NUMBER>,R0
;	JSR	PC,PUTEXN	(R2 IS BYTE COUNT, R3 IS BYTE POINTER)
PUTEXN:	BIT	#^C177,R0		;IF MORE THAN 7 BITS
	BEQ	PUTBYT
	MOV	R0,-(P)			;SAVE VALUE
	JSR	PC,PEXBYT		;INSERT FIRST BYTE
	MOV	(P)+,R0			;GET VALUE BACK
	SWAB	R0			;MOVE BITS 7-15 TO 0-8
	ASL	R0
	ADC	R0
	BIC	#<^C777>,R0		;STRIP EXTRA BITS
	BR	PUTEXN			;LOOP ON THE NEXT BYTE
;
;
PEXBYT:	BIS	#200,R0			;ADD EXTENSIBLE FLAG

;HERE TO PUT A BYTE INTO THE MESSAGE
PUTBYT:	MOVB	R0,(R3)+		;PUT BYTE INTO THE MESSAGE
	ADVCNK	R3 EXTEND		;ADVANCE TO NEXT CHARACTER
;					;ALLOCATING A NEW CHUNK IF REQUIRED
19$:	INC	R2			;COUNT CHAR INTO THE CHUNK
	RTS	PC



;HERE TO RESTORE THE J REGISTER
;
JRSTR:	RESTORE <J>		;RESTORE REG "J" AND EXIT
	RTS	PC
;HERE FROM DDCMP WHEN DDCMP HAS SUCCESSFULLY TRANSMITTED A MESSAGE
; CALL	MOV	<ADR>,R0		;ADDRESS OF MSG
;	JSR	PC,NCLODN		;DO GIVE IT BACK TO NCL
NCLODN:	MOV	R0,R1			;COPY CHUNK ADR
	MOV	R0,R3			;SET UP POINTER TO NCL MSG
	ADD	#CN.NCT,R3		;POINT TO NCL PORTION
	MOV	CN.LEN(R0),R2		;SET UP COUNTER
	JSR	PC,GETBYT		;GET NCT
	TRACE	NC
	BIT	#7,R0			;WAS THIS A NUMBERED MESSAGE
	BNE	90$			;IF NOT JUST THROW IT AWAY
	BIT	#10,R0			;CHECK FOR SNA PRESENT
	BEQ	90$			;IF NO SNA AND DNA WAS NODE ID
	JSR	PC,GETEXN		;GET DNA
	JSR	PC,FNDSCB		;FIND SCB FOR DESTINATION
	BEQ	90$			;THOSE I DON'T KNOW I DON'T CARE
	;BIT	#SBF.SQ,@SB		;IS DESTINATION SEQUENTIAL ?
	;BNE	90$			; IF SO HE GOT IT
	MOV	SB,DNA			;SAVE DESTINATION SCB ADR
	JSR	PC,GETEXN		;GET SOURCE NNM
	JSR	PC,FNDSCB		;AND FIND SCB ADR
	BEQ	90$			;MYSTERY PERSON
	BIT	#SBF.SQ,@SB		;WAS SOURCE SEQUENTIAL ?
	BEQ	90$			;IF NOT I CAN JUNK MSG
	MOV	SB,SNA			;SAVE SOURCE SCB ADR
	MOV	R1,-(P)			;SAVE POINTER TO MESSAGE
	MOV	#SQNTAB,R1		;SEQUENTIAL NODE TABLE
	CLR	R0			;LOWEST OFFSET
10$:	CMP	SB,(R1)+		;HAVE WE HIT SOURCE SCB YET
	BEQ	20$			;WHEN WE FIND IT
	ADD	#SQNSIZ,R0		;ADVANCE OFFSET SIZE
	BR	10$
20$:	MOV	R0,DNAOFF		;SAVE OFFSET
	MOV	(P)+,R1			;RESTORE POINTER TO CHUNK
	MOV	DNA,SB			;GET DESTINATION SCB ADR
	ADD	R0,SB			;POINT TO RIGHT WINDOW IN SCB
	BIT	#SBF.IC,@SB		;IN CONTACT ?
	BEQ	80$			;IF NOT DISCARD
	TRACE	NC
	JSR	PC,GETBYT		;GET NCA
	JSR	PC,GETBYT		;GET NCN
	MOVB	R0,CN.NCN(R1)		;SAVE NCN
	MOV	R2,CN.CNT(R1)		;SAVE COUNT
	MOV	R3,CN.ADR(R1)		;SAVE BYTE POINTER
;HERE WE MUST HOLD THE MESSAGE FOR AN ACK.  INSERT THE MESSAGE
;  INTO THE OMQ BEING CAREFUL TO KEEP THE MSGS IN ORDER.
	MOV	SB,R2			;MAKE A MESSAGE POINTER TO
	ADD	#SB.OMQ-CN.MLK,R2	; TO THE OMQ
30$:	MOV	CN.MLK(R2),R3		;STEP TO THE NEXT MESSAGE
	BEQ	40$			;IF NO MORE, PUT THIS AT THE END
	CMPB	CN.NCN(R3),CN.NCN(R1)	;COMPARE QUEUED MSG WITH THIS ONE
	ASSERT	NE			;STOP IF DUPLICATED
	BPL	40$			;IF QUEUED ONE IS >, THEN WE'RE FIRST
	MOV	R3,R2			;STEP TO THE NEXT MSG
	BR	30$			; AND COMPARE AGAINST THAT
40$:	MOV	R1,CN.MLK(R2)		;SPLICE OUR MSG IN FIRST
	MOV	R3,CN.MLK(R1)		; AND WE POINT AT THE NEXT
	JSR	PC,NCLCKA		;SEE IF THE MSG HAS BEEN ACKED.
	RTS	PC

;HERE TO DISCARD THE MESSAGE
80$:	TWIDDLE				;COUNT TIMES SOMEONE SCREWED UP
90$:	TRACE	NC
	MOV	R1,R0			;POINT TO CHUNKS AGAIN
	PJMP	FRECKS			;DISCARD CHUNKS
.SBTTL		NCL INPUT HANDLING

;HERE TO GET NODE IDENTIFIER FROM AN NCL MESSAGE
NCLIND:	JSR	PC,GETEXN		;GET THE DNA
	JSR	PC,FNDSCB		;FIND SCB FOR HIM
	BEQ	30$			;BRANCH IF DON'T KNOW NODE
	BIT	#SBF.SQ,@SB		;IS NODE SEQUENTIAL ?
	BEQ	20$			;IF NOT WE ARE DONE
	CLR	R0			;BUILD OFFSET
	MOV	#SQNTAB,R1		;POINT TO LIST OF SEQUENTIAL NODES
16$:	CMP	SB,@R1			;IS THIS THE ONE ?
	BEQ	20$
	ADD	#SQNSIZ,R0		;ADD TO OFFSET
	TST	(R1)+			;SKIP TO NEXT ENTRY IN SQNTAB
.IF EQ DGUTS
	ASSERT	NE
.IFF
	BEQ	30$
.ENDC ; .IF EQ DGUTS
	BR	16$

20$:	RTS	PC

30$:	TST	(P)+			;CLEAR RETURN
	TWIDDLE				;COUNT TIMES THIS HAPPENS
	TWIDDLE	R0			;REMEMBER STRANGE NODE NUMBER
	JMP	SCHRED			;NO SUCH PLACE IGNORE MESSAGE
;HERE FROM DDCMP WITH A MESSAGE
; CALLED WITH
;	SNA (DEFAULT VALUE) SETUP
;	R0 POINTING TO 1ST CHUNK OF MESSAGE
;	J POINTING TO LINE BLOCK
; REG USAGE IS:
;	R0 TEMP
;	R2 TOTAL MESSAGE LENGTH
;	R3 POINTER TO STRING
NCLIN0:	MOV	#OURSCB,DNA		;DESTINATION IF NO ROUTING HEADER
	CLR	CN.SCB(R0)		;CLEAR FLAG TO SAY MSG IF FROM OUTSIDE
	BR	NCLIN2			;GO JOIN COMMON CODE

;HERE FROM "INSIDE" TO NUMBER A MESSAGE AND SEND IT.
NCLIN1:	SAVE	<SB,#SBRSTR>		;SAVE SB  FOR CALLER
	MOV	#-1,CN.SCB(R0)		;FLAG THAT MESSAGE IS FROM "INSIDE"
;	NCLLOG	ALL
NCLIN2:	CLR	DNAOFF			;OFFSET FOR DESTINATION
	CLR	SNAOFF			;OFFSET FOR SOURCE
	ASSERT CHUNK R0			;BE SURE WE GOT A MSG
	CLR	CN.MLK(R0)		;MAKE SURE WE ONLY HAVE 1 MESSAGE
	MOV	R0,-(P)			;SAVE STRING POINTER
	MOV	R0,R3			;COPY CHUNK ADR
	MOV	CN.LEN(R3),R2		;GET MESSAGE LENGTH
	BNE	10$			;IF NO COUNT DO SOMETHING
	TWIDDLE				;COUNT BUM MESSAGES
	JMP	SCHRED
10$:	ADD	#CN.NCT,R3		;POINT TO 1ST REAL CHAR
	JSR	PC,GETBYT		;GET THE NCT BYTE
	TRACE	NC			;TRACK MESSAGE TYPES
	BIT	#NCFSNA,R0		;ARE SNA & DNA PRESENT ?
	BEQ	NCLIN4			;IF NOT MUST BE FOR US
	JSR	PC,NCLIND		;GET DNA
	MOV	SB,DNA			;SAVE DNA ADDRESS
	MOV	R0,DNAOFF		;SAVE OFFSET
	JSR	PC,NCLIND		;GET SNA
	MOV	SB,SNA			;SAVE IT
	MOV	R0,SNAOFF		;SAVE OFFSET
	MOV	(P),R0			;GET THE CHUNK POINTER BACK
	TST	CN.SCB(R0)		;IF THE MESSAGE IS FROM "INSIDE"
	BNE	30$			; THEN GO PROCESS IT
	MOV	SNA,SB			;GET THE ADDRESS OF THE SOURCE
	BIT	#SBF.SQ,(SB)		;IF HE'S NOT SEQUENTIAL,
	BEQ	30$			; THEN NO PROBLEM.
	CMP	#OURSCB,SB		;IF IT'S FROM US, THEN
	BEQ	20$			; THEN IT'S "RETURNED"
	CMP	J,SB.LBA(SB)		;IF IT'S FROM A SEQ NGH,
	BEQ	30$			; IT MUST COME IN ON HIS LINE
20$:	JMP	SCHRED			;OTHERWISE IT'S "RETURNED"
;HERE WHEN HAVE IDENTIFIED SOURCE AND DESTINATION NODES
30$:	BIT	#SBF.SQ,@SNA		;IS SOURCE SEQUENTIAL ?
	BEQ	NCLIN3			;BRANCH IF SOURCE IS GOOD GUY
	MOV	SNA,SB			;GET THE ADDRESS OF THE SOURCE
	TST	SB.WOQ(SB)		; AND IF WE HAVE ANY MSGS WAITING
	BNE	60$			; FOR NUMBERS, THIS MUST GO AFTER THEM
	MOV	DNA,SB			;GET DESTINATION SCB ADR
	ADD	SNAOFF,SB		;POINT TO RIGHT SUBWINDOW
	MOV	SB,CN.SCB(R0)		;SAVE THE SCB FOR THE MSG
	BIT	#7,CN.NCT(R0)		;IS MESSAGE NUMBERED ?
	BNE	40$
	INCB	SB.HXN(SB)		;HIGHEST MSG SENT BY THIS GUY
	CMPB	SB.LAP(SB),SB.HXN(SB)	;SEE IF WE HAVE MORE THAN 128.
	BPL	50$			;IF SO, THEN WE CAN'T NUMBER IT NOW
	MOVB	#TNCREP,SB.TIM(SB)	;RESET REP TIMER
40$:	MOVB	SB.RMN(SB),@R3		;PUT ACK INTO THE MESSAGE
	BIC	#SF.XAK,@SB		;HAVE SENT ACK NOW
	MOVB	SB.HXN(SB),1(R3)	;PUT INTO THE MESSAGE
	BR	NCLIN3			;MSG IS NUMBERED, GO FORWARD IT

;HERE IF WE CAN'T ASSIGN A MSG NUMBER.
50$:	DECB	SB.HXN(SB)		;COULDN'T SEND IT, FIXUP THE NUMBER
	TWIDDLE				;COUNT THE TIMES THIS HAPPENS
60$:	MOV	#SB.WOQ-CN.MLK,R1	;GET A POINTER TO
	ADD	SNA,R1			; THE ZERO-TH MSG ON THE QUEUE
70$:	MOV	CN.MLK(R1),R0		;GET THE NEXT MESSAGE
	BEQ	80$			; IF NONE, THEN MAKE THIS ONE LAST
	MOV	R0,R1			;STEP TO THE NEXT MSG
	BR	70$			; AND SEE IF THAT'S LAST

80$:	MOV	(SP)+,CN.MLK(R1)	;MAKE THIS MSG THE LAST
	RTS	PC			; AND WE'RE DONE

NCLIN3:
.IF NE FTROLL				;IF WE'RE TOSSING MESSAGES.
	DEC	TROLL			;SEE IF THE TROLL IS HUNGRY
	BLT	90$			;NO, HE IS HIBERNATING
	BGT	NCLIN4			;NO, STILL DIGESTING THE LAST MEAL
	MOV	(P),R0			;GET THE CHUNK POINTER BACK
	JSR	PC,NCLOKT		;MAKE SURE TROLL DOESN'T GAG
	BCS	90$			; (E.G., EAT OUTGOING MSGS FROM US)
	MOV	#FTROLL,TROLL		;THE TROLL IS ABOUT TO BE FED
	TWIDDLE				;FIGURE THE TROLL'S TAB
	JMP	SCHRED			; AND EAT THE MESSAGE

90$:	INC	TROLL			;DON'T COUNT THIS MESSAGE
.ENDC; IF NE FTROLL

NCLIN4:	BIT	#SBF.SQ,@DNA		;IS DESTINATION SEQUENTIAL ?
	BNE	10$			;IF SO, WE MUST PROCESS MSG NUMBERS
	MOV	(P)+,R0			;GET POINTER TO MESSAGE
	PJMP	DDQDAT			;AND ROUTE MSG ON
;HERE BECAUSE DESTINATION IS SEQUENTIAL
10$:	MOV	SNA,SB			;GET SOURCE SCB ADDR
	ADD	DNAOFF,SB		;POINT TO RIGHT SUBWINDOW
	MOV	@P,R0			;GET THE ADDRESS OF THE MESSAGE BACK
	MOV	CN.NCT(R0),R0		; AND FROM THAT FETCH THE FIRST BYTE
	BIC	#^C7,R0			;GET JUST THE TYPE
	CMP	R0,#4			;IF IT'S AN ACK, NAK, REP, OR DATA
	BLT	20$			; THEN GO PROCESS THE NCA FIELD
	JSR	PC,GETBYT		;OTHERWISE SKIP OVER THE NCA
	BR	NCLIN5			; AND GO PROCESS THE START/STACK MSG

20$:	BIT	#SBF.IC,@SB		;IF WE'RE IN CONTACT,
	BNE	30$			; THEN PROCESS THE MESSAGE
	BIT	#SBF.SK,@SB		;IF WE'RE SENDING STACKS,
	BNE	30$			; THEN IT'S OK TO PROCESS THE MSG
	TWIDDLE				;IF NOT IN CONTACT, IT'S AN ERROR
	JMP	SCHRED			; TO GET A DATA MESSAGE, DESTROY IT

30$:	BIC	#SBF.SK,@SB		;FIRST CONTROL MSG CLEARS "SEND STACKS"
	BIS	#SBF.IC,@SB		;WE'RE IN CONTACT NOW.
	JSR	PC,GETBYT		;GET THE IMPLICIT ACK (NCA)
;	CMPB	SB.LAP(SB),R0		;VALID ACK'S MUST NOT BE
;	BPL	NCLIN5			; BEFORE THE LAST ACK PROCESSED
	CMPB	SB.HXN(SB),R0		;AND THEY MUST NOT BE
	BMI	NCLIN5			; GREATER THAN THE LAST NUMBER ASSIGNED
	CMPB	SB.HAR(SB),R0		;IF THE HIGHEST ACK SO FAR IS
	BPL	NCLIN5			; GREATER THAN OR EQUAL, IGNORE THIS 1
	MOVB	R0,SB.HAR(SB)		;OTHERWISE BUMP UP THE ACK COUNT
	JSR	PC,NCLCKA		; AND TRY TO FREE MESSAGES.

NCLIN5:	JSR	PC,GETBYT		;GET NCN
	MOV	(P),R1			;GET MSG POINTER
	MOVB	R0,CN.NCN(R1)		;SAVE MSG NUMBER
	MOV	CN.NCT(R1),R0		;GET NCT AGAIN
	BIC	#^C7,R0			;LEAVE ONLY MSG TYPE CODE
	ASL	R0			;POSITION BITS FOR DISPATCH
	JMP	@NCRDSP(R0)

NCLIN8:
.IF NE DEVN
	TST	DNAOFF			;IF THIS IS US WILL BE 0
	BNE	20$
	MOV	CN.DDB(R0),J		;GET DEVICE BLOCK FOR MSG IF ANY
	BEQ	20$
	BIC	#DS.IQU,@J		;SO TTY'S CAN RUN AGAIN
	JSR	PC,QUEDEV		;WAKE DEVICE MAYBE
	TRACE	DV
.IF NE FT.TSK
	MOV	J,-(P)			;SAVE DDB ADR
	MOV	DB.TSK+6(J),J		;GET TASK BLOCK ADR
	BEQ	10$
	JSR	PC,TSKWAK		;WAKEN TASK IN CASE SLEEPING
10$:	MOV	(P)+,J
.ENDC;.IF NE FT.TSK
.ENDC;.IF NE DEVN
20$:	PJMP	FRECKS			;DISCARD CHUNKS

;HERE TO DISCARD A MESSAGE
SCHRED:	MOV	(P)+,R0			;GET ORIGINAL CHUNK POINTER
	JSR	PC,FRECKS		;RELEASE CHUNKS
CPOPJ:	RTS	PC
;HERE IF MESSAGE IS NUMBERED CONTROL OR DATA
NCR.10:	BIT	#SBF.IC,@SB		;IN CONTACT ?
	BNE	10$
	TWIDDLE	SB
	TWIDDLE	@P
	TWIDDLE
	JMP	SCHRED
10$:	MOV	(P)+,R0			;GET CHUNK ADR
	MOV	#TNCREP,CN.TIM(R0)	;TIME MSG
	MOV	R2,CN.CNT(R0)		;SAVE BYTE COUNT
	MOV	R3,CN.ADR(R0)		;SAVE BYTE POINTER
	MOV	SB.IMQ(SB),CN.MLK(R0)	;TAKE ALREADY WAITING MESSAGES
	MOV	R0,SB.IMQ(SB)		;AND PUT THIS AT HEAD
	MOV	SB,-(P)			;SAVE POINTER TO SCB
NCR.12:	MOV	@P,SB			;GET SCB ADR BACK
	MOVB	SB.RMN(SB),R1		;LAST NCL-MSG NUMBER RECEIVED
	INC	R1			;MAKE EXPECTED NCL-MSG NUMBER
	MOV	SB,R0			;COPY SCB ADR
	ADD	#SB.IMQ-CN.MLK,R0	;MAKE PHONY CHUNK POINTER
15$:	MOV	R0,R2			;SAVE ADR OF PREVIOUS MSG
	MOV	CN.MLK(R2),R0		;GET ADR OF NEXT MESSAGE
	BEQ	99$			;IF NOT WE ARE DONE
	TWIDDLE	R0
	TWIDDLE	SB
	Z=SB.RMN&177776
	TWIDDLE	Z(SB)
	TWIDDLE	R1
	CMPB	R1,CN.NCN(R0)		;IS THIS THE ONE WE WANTED ?
	BNE	15$
	INCB	SB.RMN(SB)		;ADVANCE LAST MSG RECEIVED OK
	BIS	#SF.XAK,@SB		;NEED TO SEND NCL-ACK MESSAGE
.IF NE 0	;REMOVING THIS CODE MAY WORSEN RESPONSE, BUT INCREASES THROUGHPUT
	MOV	SNA,SB
	JSR	PC,NCLQRQ		;SO WE SEND ACK LATER
	MOV	@P,SB			;GET RIGHT WINDOW POINTER
.ENDC
	MOV	CN.MLK(R0),CN.MLK(R2)	;DELINK THIS MESSAGE FROM SB.IMQ
	CLR	CN.MLK(R0)		;AND FLUSH OUR LINK
	MOV	CN.CNT(R0),R2		;GET OLD COUNT BACK
	MOV	CN.ADR(R0),R3		;GET OLD BYTE POINTER BACK
	CMP	DNA,#OURSCB		;ARE WE LUCKY RECPIENT ?
	BEQ	17$
	MOVB	#TNCREP,SB.TIM(SB)	;WHEN TO TRY AGAIN
	JSR	PC,DDQDAT		;SHIP MESSAGE OUT
	BR	NCR.12			;SEE IF MORE MESSAGES TO GO
17$:	MOVB	CN.NCT(R0),NCT		;SAVE NCT FOR FUTURE REFERENCT
	MOV	R0,-(P)			;SAVE 1ST CHUNK ADR
	JSR	PC,GETEXN		;GET CONNECTION NUMBER
	TST	R0
	BNE	NCRDAT			;IF NONZERO THIS IS DATA
32$:	JSR	PC,GETEXN		;GET COUNT FIELD
	SUB	R0,R2			;ADJUST COUNT
	MOV	R2,-(P)			;AND PUSH IT ON THE STACK
	MOV	R0,R2
	JSR	PC,GETBYT		;GET CONTROL TYPE
	TST	R0
	BLE	35$
	CMP	#7,R0			;RANGE CHECK TYPE
	BHIS	40$
35$:
.IF EQ DGUTS
	TRAP
.IFF
	TWIDDLE
	CTYMSG	IMT			;LOG ILL MSG TYPE
	TST	(P)+			;POP STACK
	BR	SCHRD1			;CHUCK MSG
.ENDC ; .IF EQ DGUTS
40$:	ASL	R0
	MOV	SB,-(P)			;SAVE WINDOW ON SCB
	JSR	PC,@NNCDSP-2(R0)	;DISPATCH ON CONTROL TYPE
	MOV	(P)+,SB
50$:	TST	R2			;MORE ROOM IN SUB MESSAGE ?
	BEQ	60$
	JSR	PC,GETBYT		;GET NEXT BYTE
	BR	50$
60$:	MOV	(P)+,R2			;GET COUNT BACK
	BNE	32$
	MOV	(P)+,R0			;GET CHUNK ADR
	JSR	PC,NCLODN		;RELEASE MESSAGE
	BR	NCR.12
99$:	MOV	(P)+,SB			;GET SCB ADR BACK AGAIN
	RTS	PC
Z=DGUTS
.IIF GE DEBUG,Z=Z!1
.IF NE Z
SCHRD1:	RESTORE	<R0,SB>			;RESTORE MSG ADDRESS AND SCB
	JMP	FRECKS			; AND CHUCK MSG
.ENDC;	.IF NE Z
;HERE WHEN WE HAVE RECCEIVED A DATA MESSAGE FOR THIS NODE
NCRDAT:
.IF NE DEVN
	JSR	PC,NCRDLA		;CONVERT DLA INTO DEVICE BLOCK ADR
Z=DGUTS
.IIF GE DEBUG,Z=Z!1
.IIF NE Z,	BEQ	SCHRD1		;IN CASE NO DEVICE
	MOV	(P)+,R0			;GET ADDRESS OF 1ST CHUNK
	BITB	#NCFINT,CN.NCT(R0)	;DOES THIS COUNT ON DATA REQ'S
	BNE	20$			;IF NOT DON'T COUNT IT
	DECB	DB.ODR(J)		;ADJUST DATA REQUEST COUNT
.IF EQ DGUTS
	ASSERT	PL			;DIE IF 10 SENT TOO MUCH
.IFF
	BPL	20$
	INCB	DB.ODR(J)		;RESET COUNT
	SAVE	<R0>
	TWIDDLE	CN.NCT+2(R0)
	MOV	DB.SCB(J),R0
	TWIDDLE	SB.NNM(R0)
	TWIDDLE
	RESTORE	<R0>
	JSR	PC,FRECKS		;DISCARD MESSAGE AND LOG IT
	CTYMSG	ODR
	BR	50$
.ENDC ; .IF EQ DGUTS
20$:	MOV	R2,CN.CNT(R0)		;SAVE COUNT LEFT IN MESSAGE
	MOV	R3,CN.ADR(R0)		;SAVE ALSO BUFFER POINTER
	MOV	J,R2
	ADD	#DB.OBF-CN.MLK,R2	;MAKE PHONEY BUFFER POINTER
	PIOFF
30$:	MOV	R2,R1			;COPY BUFFER POINTER
	MOV	CN.MLK(R1),R2		;GET ADDRESS OF NEXT BUFFER
	BNE	30$
	MOV	R0,CN.MLK(R1)		;LINK NEW BUFFER TO END
	PION
	JSR	PC,QUEDEV		;WAKE SERVICE ROUTINE
.IF NE FT.TSK
	MOV	J,-(P)			;SAVE DDB POINTER
	MOV	DB.TSK+0(J),J		;GETS FROM PRINTER?
	BEQ	44$
	JSR	PC,TSKWAK
44$:	MOV	(P)+,J			;GET DDB POINTER BACK
	MOV	DB.TSK+6(J),J		;PUTS TO KEYBOARD?
	BEQ	50$
	JSR	PC,TSKWAK		;REAWAKEN JOB
.ENDC	;.IF NE FT.TSK
50$:	JMP	NCR.12			;ON TO CHECK FOR MORE MESSAGES
;HERE TO CONVERT DLA INTO A DEVICE BLOCK ADDRESS
; CALL	MOVE DLA,R0
;	RETURNS WITH J SET UP
;	IF DEBUG STOPCDS ALLOWED, MUST TEST J ON RETURN
NCRDLA:	TRACE	DV			;TRACE DEVICE DATA
	TST	R0			;FIRST MAKE SURE IT'S NOT .LE. 0
	BLE	80$			;  IF .LE. 0 IT'S CERTIANLY A BAD DLA
	BIT	#1,R0			;IS THIS POSSIBLE ?
	BNE	80$			;IF NOT POSSIBLE PUNT
	CMP	R0,#<DEVN*2>+1		;CHECK FOR TOO LARGE
	BPL	80$			;IF OUT OF RANGE DIE
10$:	MOV	DLATAB-2(R0),J		;GET DEVICE BLOCK FOR THIS MESSAGE
	BIT	#DS.CON,(J)
	BEQ	80$			;IF NOT CONNECTED DIE
	CMP	SNA,DB.SCB(J)		;CHECK THIS WAS OWNER
	BNE	80$			;DIE IF NOT RIGHT CONNECTION
	JSR	PC,QUEDEV
	TST	J		;SET/CLEAR Z CONDITION CODE
	RTS	PC
.ENDC;.IF NE DEVN

80$:
.IF LT DEBUG
	STOPCD	NCN			;NO CONNECTION FOR THIS DATA ?
.IFF
	TWIDDLE
.IF NE DGUTS
	CTYMSG	NDV
.ENDC
	CLR	J
	RTS	PC
.ENDC ; .IF LT DEBUG
;NETWORK NUMBERED CONTROL DISPATCH TABLE
NNCDSP:	NCRCON				;(1) CONNECT
	NCRDIS				;(2) DISCONNECT
	NCRNGH				;(3) NEIGHBOURS
	NCRRCF				;(4) REQUEST CONFIGURATION
	NCRCNF				;(5) CONFIGURATION
	NCRDRQ				;(6) DATA REQUEST
	NCRSTC				;(7) STATION CONTROL

NCRDSP:	NCR.10				;(0) DEVICE CONTROL
	NCRACK				;(1) NCL ACK
	NCRNAK				;(2) NCL NAK
	NCRREP				;(3) NCL REP
	NCRSTR				;(4) NCL START
	NCRSTK				;(5) NCL STACK
	NCRNID				;(6) NODE ID
	SCHRED				;(7)
;HERE WHEN RECEIVE A NODE ID
NCRNID:	TWIDDLE
	JSR	PC,GETEXN		;GET NNM
	BIT	#SF.HID,@SB		;DID I ALREADY HAVE NODE ID'S ?
	BEQ	10$
	CMP	R0,SB.NNM(SB)		;SAME ?
	BEQ	90$			;IF SO IGNORE MESSAGE
	JSR	PC,FNDSCB		;HAVE I EVER HEARD OF HIM ?
	BNE	16$			;IF SO JUST REROUTE
	BR	90$
10$:	MOV	SB,-(P)			;SAVE SCB ADDR
	JSR	PC,FNDSCB		;SEE IF ANY OTHER NODE HAS SAME NAME
	BEQ	20$
	MOV	(P)+,R0			;GET BUM SCB
	CLR	(R0)			;CLEAR STATUS IN BUM SCB
.IF NE FTDL10!FT.DTE			;SEE IF THIS WAS THE -10 COMING ONLINE
	CMP	R0,TENSCB		;WAS THIS THE DTE/DL
	BNE	15$			;IF NOT, DON'T RE-DIRECT TENSCB
	MOV	SB,TENSCB		;TEN NOW UP.  MAKE TENSCB POINT TO SCB
	MOV	SB,SB.LBA(SB)		;SET UP IT'S INCESTOUS ROUTING
	BR	80$			;BACK TO COMMON CODE
15$:
.ENDC
.IIF NE NTLINE,	ASSERT	LB.SCB(J) NE SB
16$:
.IIF NE NTLINE,	MOV	SB,LB.SCB(J)		;REDIRECT LINE BLOCK
	BR	80$

;HERE IF HAVE NEVER HEARD OF THIS NODE NUMBER
20$:	MOV	(P)+,SB			;GET SCB ADR AGAIN
	MOV	R0,SB.NNM(SB)		;SAVE NODE NUMBER
	BEQ	90$
	MOV	SB,SNA			;SAVE SCB ADR

;NOW GET NODE NAME FROM MSG
	JSR	PC,NCRNAM		;GET NAME FROM MSG

	MOV	(P),R0			;GET MSG CHUNK POINTER AGAIN
.IF NE NTLINE
	BITB	#NCFSEQ,CN.NCT(R0)	;WAS THIS A NONSEQUENTIAL NODE ?
	BNE	70$
	CMP	J,SB.LBA(SB)		;DO I KNOW ANOTHER ROUTING
	BEQ	24$
	TWIDDLE				;COUNT THE TIMES I DO
	TWIDDLE	J
	JSR	PC,L.DOWN		;RESTART THE LINE
	BR	90$			;FORGET

24$:	JSR	PC,ADDSQN		;SETUP SCB FOR SEQUENTIAL NODE
	BIS	#SBF.NB!SF.XCN!SF.XRC,@SB;SEND NEIGHBORS AND CONFIGURATION
	JSR	PC,NCLQRQ		;QUEUE SCB UP
	BR	80$
.ENDC	;.IF NE NTLINE

70$:	JSR	PC,ADDNSQ		;SETUP SCB RIGHT

80$:	BIS	#SF.HID,(SB)		;HAVE NODE ID NOW
	JSR	PC,ROUTE		;ADJUST ROUTING INFORMATION
	JSR	PC,SNDNGH		;SEND NEIGHBOURS TO EVERYBODY
90$:	JMP	SCHRED			;DISCARD REST OF MESSAGE
;SNDNGH  --  SEND NEIGHBORS MESSAGE TO REST OF NETWORK
;
;SNDNGH IS USED TO CAUSE AN NCL NEIGHBORS MESSAGE TO BE SENT TO EVERY KNOWN
;NODE IN THE NETWORK.
;
;SNDNGD IS USED TO DO THE SAME, ONLY FLAGGING THAT THE REASON IS BECAUSE A
;NEIGHBOR HAS GONE AWAY (A "NEGATIVE" NEIGHBORS MESSAGE, AS IT WERE). THIS
;DISTINCTION IS IMPORTANT BECAUSE WE CAN'T ALLOW A NEW NEIGHBOR TO COME UP
;(PRESUMABLY ON THE SAME LINE, BUT ...) UNTIL THE NETWORK HAS BEEN INFORMED
;THAT THE LINE ACTUALLY WENT AWAY (OTHERWISE THE NETWORK MIGHT NEVER HAVE
;SEEN THE NODE GO DOWN, AND THINK THAT EVERYTHING IS STILL RUNNING).

SNDNGD:	MOV	SP,NEGNGH		;NOTE A "NEGATIVE" DELTA NEIGHBORS
SNDNGH:	MOV	#OURSCB,SB		;FIRST SCB ADR
	BR	20$
10$:	BIT	#SBF.IC,@SB		;ARE WE IN CONTACT ?
	BEQ	20$			;IF NE NOT DON'T SEND NEIGHBOURS
	ASSERT	#SBF.IU SET IN @SB	;BE SURE WE ARE USING BLOCK
	BIS	#SBF.NB,@SB		;SEND HIM NEIGHBOURS SOON
	JSR	PC,NCLQRQ		;START NCL
20$:	SB.ADV	10$			;ON TO NEXT BLOCK
	RTS	PC


;HERE BECAUSE WANT TO SEND ROUTING INFORMATION TO SEQUENTIAL NEIGHBOURS
.IF NE NTLINE
SNDSNB:	SAVE	<J,SB>
	MOV	#FRSTLB,J		;FIRST LINE BLOCK
	BR	20$
10$:	MOV	LB.SCB(J),SB		;GET ADR OF ASSOCIATED SCB
	BEQ	20$
	BIT	#SBF.SQ,@SB		;IS IT SEQUENTIAL ?
	BEQ	20$
	BIS	#SBF.NB,@SB		;SEND HIM NEIGHBOURS MESSAGE
	JSR	PC,NCLQRQ		;REQUEST NCL FOR HIM
20$:	MOV	LB.LNK(J),J		;GET NEXT LINE BLOCK
	BNE	10$
	RESTORE	<SB,J>
	RTS	PC
.ENDC	;.IF NE NTLINE
;HERE WHEN RECEIVE A NETWORK NAK
;  APPEND THE WAIT-ACK QUEUE TO THE RESEND QUEUE
NCRNAK:	TWIDDLE				;COUNT TIMES THIS HAPPENS
	SAVE	R0			;DON'T LOSE THE POINTER TO THE NAK MSG
	MOV	#MSGRSQ-CN.MLK,R0	;GET A MSG POINTER TO THE RESEND QUEUE
	PIOFF				;PROBABLY UNNECESSARY (BELT+SUSPENDERS)
10$:	MOV	CN.MLK(R0),R1		;GET NEXT MSG IN QUEUE
	BEQ	20$			;IF END, APPEND SB.OMQ'S MSGS
	MOV	R1,R0			;OTHERWISE STEP TO NEXT MSG
	BR	10$			; AND SEE IF IT'S THE LAST ONE
20$:	MOV	SB.OMQ(SB),CN.MLK(R0)	;APPEND THE LIST ON SB.OMQ
	CLR	SB.OMQ(SB)		; AND SAY THE OUTPUT QUEUE IS EMPTY
	PION				;MESSAGES WILL GET RESENT NEXT JIFFY
	RESTORE	R0			;GET THE NAK MSG BACK (FOR SCHRED)
;	BR	NCRACK			;GO STOP THE REP TIMER


;HERE WHEN RECEIVE A NETWORK ACK
NCRACK:	BIT	#SBF.SK,@SB		;NEED TIMER FOR STACK ?
	BNE	10$
	BIT	#SBF.IC,@SB		;ARE WE UP AND RUNNING ?
	BEQ	10$			;IF NOT IGNORE
	CMPB	SB.LAP(SB),SB.HXN(SB)	;ALL MESSAGES ACCOUNTED FOR ?
	BNE	10$
	BIC	#SBF.RP,@SB		;REP NO LONGER OUTSTANDING
	CLRB	SB.TIM(SB)		;STOP TIMER
10$:	JMP	SCHRED			;MESSAGE ALREADY USED

;HERE WHEN RECEIVE A NETWORK REP
NCRREP:
;	BIS	#SF.XAK,@SB		;SET FLAG TO SEND NCL-ACK
;	MOV	(P),R0			;GET ADR OF MSG CHUNK
;	CMPB	CN.NCN(R0),SB.RMN(SB)	;DOES HE WIN ACK OR NAK ?
;	BEQ	20$
	BIS	#SBF.NK,@SB		;SEND AN NCL-NAK
10$:	MOV	SB.IMQ(SB),R0		;GET NCL NUMBERED MSG
	BEQ	20$			;IF NO WE ARE DONE
	MOV	CN.MLK(R0),SB.IMQ(SB)	;REMEMBER NEXT
	JSR	PC,FRECKS
	BR	10$			;LOOP BACK FOR REST
20$:	MOV	SNA,SB			;SOURCE SCB ADR
	JSR	PC,NCLQRQ		;SO NCL WILL SEND AN ACK/NAK
	JMP	SCHRED			;AND DISCARD MESSAGE
;HERE WHEN RECEIVE A NETWORK START
NCRSTR:					;START MSG
.IF NE,FTDCP1
	BIT	#SF.NSP,@DNA		;IS THIS AN NSP DESTINATION?
	BEQ	10$			;NO, CONTINUE NORMALLY
	CMP	SNA,LB.DNA(J)		;IS SOURCE NODE THE ONE NSP TALKS TO?
	BEQ	10$			;YES, PROCESS START
	JMP	SCHRED			;NO, FLUSH IT
10$:					;HERE IF NORMAL START PROCESSING
.ENDC
	BIT	#SBF.IC,@SB		;HAD WE ALREADY EXCHANGED ?
	BEQ	20$			;IF NOT, THEN SCB IS "FRESH"
	CMP	SB,SNA			;WAS START FOR US OR A SEQ-NGH?
;	ASSERT	EQ			;AT THIS POINT, THINGS HAVE REALLY 
					; GOTTEN OUT OF HAND.  I NEED TO TELL
					; THE SEQ-NGH THAT THE NODE "SNA" HAS
					; GONE DOWN AND COME BACK UP, BUT THE
					; ONLY WAY TO DO THAT IS WITH NEIGHBORS
					; MESSAGES.  HENCE I NEED TO SEND ONE
					; WITHOUT "SNA" AND ONE WITH.  GIVEN
					; THE CURRENT STRUCTURE THIS IS NEARLY
					; IMPOSSIBLE.   S**T.
	BNE	20$			;IF FOR SEQ-NGH, LEAVE TOPOLOGY ALONE
	SAVE	SB.NNM(SB)		;REMEMBER THE NODE ID FOR A BIT
	JSR	PC,N.DOWN		;CLEAN SCB, RE-CALC ROUTING
	JSR	PC,CLRSCB		;CLEAN OUT NAME, NUMBER ETC.
	RESTORE	SB.NNM(SB)		;RECOVER THE NODE'S ID
	JSR	PC,ADDNSQ		; ADD THE NODE AGAIN
	JSR	PC,ROUTE		;FIGURE OUT PATHS WITHOUT HIM
20$:	BIS	#SBF.SK,@SB		;SO WE SEND A STACK
	BR	NCRSOS			;DO STUFF COMMON TO START OR STACK

;HERE WHEN RECEIVE A NETWORK STACK
NCRSTK:	BIT	#SBF.IC,@SB		;DID I ALREADY THINK WE WERE UP ?
	BEQ	10$			;GO READ THE MESSAGE BODY
	JMP	SCHRED			;JUST IGNORE IF WE ARE UP
10$:	BIS	#SBF.RP!SBF.IC,@SB	;IN CONTACT BUT SEND REP FIRST
	BIC	#SBF.SK,@SB		;NO MORE STACKS
NCRSOS:
	CMP	SNA,SB			;FOR US OR SEQ-NEG?
	BEQ	20$			;BR IF FOR US
	BIS	#SBF.NB,@DNA		;FOR SEQ-NGH, SO SEND HIM NEW NEIGHBOURS
20$:
	MOVB	#1,SB.TIM(SB)		;SO WE SEND IT QUICK
	JSR	PC,GETEXN		;GET NNM
	JSR	PC,NCRNAM		;GET NAME FROM MSG
	MOV	SB,-(P)			;SAVE POINTER TO SCB
	MOV	DNA,SB
	JSR	PC,NCLQRQ		;WAKE NCL
	MOV	SNA,SB
	JSR	PC,NCLQRQ
	MOV	(P)+,SB			;RESTORE SCB POINTER
	JMP	SCHRED
;HERE TO GET STATION NAME FROM MESSAGE
NCRNAM:	MOV	#SB.SNM,R1		;POINT TO NAME FIELD
	MOV	#SNMSIZ,-(P)		;MAX NUMBER OF CHARACTERS
	JSR	PC,30$			;GET STATION NAME FROM MESSAGE
	MOV	#SB.SID,R1		;POINT TO SOFTWARE ID
	MOV	#SIDSIZ,-(P)		;MAX SIZE FOR MESSAGE
	JSR	PC,30$			;GET SOFTWARE ID FROM MESSAGE
.IF NE DATESZ
	MOV	#SB.DATE,R1		;POINT TO DATE FIELD
	MOV	#DATESZ,-(P)
	JSR	PC,30$
.ENDC;.IF NE DATESZ
	RTS	PC
30$:	ADD	SNA,R1			;MAKE ABSOLUTE ADR
32$:	JSR	PC,GETBYT
	DEC	2(P)			;TOO MANY BYTES ?
	BMI	34$			;IF SO DON'T ADD THIS ONE
	MOVB	R0,(R1)+		;PUT NEXT BYTE INTO IT
34$:	TSTB	R0			;LAST BYTE ?
	BMI	32$			;NOT YET
	BICB	#200,-1(R1)		;CLEAR SIGN BIT ON LAST BYTE
	MOV	2(P),R0			;BYTES LEFT TO GO
	BLE	36$			;NONE LEFT
35$:	CLRB	(R1)+			;CLEAR NEXT BYTE
	SOB	R0,35$			;LOOP TILL DONE WITH FIELD
36$:	MOV	(P)+,@P
	RTS	PC
;HERE WHEN RECEIVE A CONNECT FROM ANOTHER STATION
NCRCON:	JSR	PC,GETEXN		;GET DESTINATION LINK ADDRESS
.IF NE FTHOST
	TST	R0			;WAS THIS A CONFIRM ?
	BEQ	12$
	MOV	DLATAB-2(R0),J		;GET ADR OF DEVICE BLOCK
	JSR	PC,GETEXN		;GET HIS LINK ADDRESS
	MOV	R0,DB.RLA(J)		;SAVE IT
	BR	50$
.ENDC;.IF NE FTHOST
12$:	JSR	PC,GETEXN		;GET SOURCE LINK ADDRESS
	MOV	R0,SLA			;SAVE IT
.IF NE DEVN
	JSR	PC,GETEXN		;GET OBJECT TYPE
	MOV	R0,R1			;SAVE OBJECT TYPE
.IF NE,FTECHO
	CMPB	R1,#OBJTSK		;IS IT A TASK?
	BNE	77$			;NO, CONTINUE NORMALLY
	JSR	PC,ECHSEL		;GO SEE IF WE CAN HANDLE REQUEST
	BR	76$			;WILL HAVE DDB NUMBER IN R0 ON RETURN
77$:
.ENDC;.IF NE,FTECHO
	JSR	PC,GETEXN		;GET UNIT NUMBER
76$:	CMPB	R0,#177			;ASKING FOR GENERIC ?
	BEQ	16$			;IF SO DONE
	BIS	#100000,R0		;FLAG SPECIFIC REQUEST
16$:	MOV	FIRDDB,J		;GET FIRST DEVICE BLOCK ADR
20$:	CMPB	R1,DB.OBJ(J)		;IS THIS THE RIGHT TYPE OF DEVICE ?
	BNE	25$			;IF NOT HE CAN'T HAVE IT
.IF NE FT.RNN
	TSTB	DB.RNN(J)		;IS THIS DEVICE RESTRICTED ?
	BEQ	22$			;IF NOT HE CAN HAVE IT MAYBE
	MOV	SNA,SB			;GET SCB ADR FOR REQUESTING NODE
	CMPB	SB.NNM(SB),DB.RNN(J)	;IS THIS RIGHT NODE REQUESTING ?
	BNE	25$			;IF NOT CAN'T HAVE THIS ONE
.ENDC;.IF NE FT.RNN
22$:	TST	R0			;ASK FOR PARTICULAR UNIT ?
	BPL	24$			;IF NOT GIVE HIM THIS ONE
	CMPB	R0,DB.UNI(J)		;IS THIS RIGHT ONE ?
	BNE	25$			;IF NOT KEEP LOOKING
24$:	TST	@J			;IS DEVICE CONNECTED ALREADY ?
	BPL	30$			;IF NOT HE WINS IT
25$:	MOV	DB.LNK(J),J		;GET NEXT DEVICE BLOCK
	BNE	20$			;KEEP LOOKING
	BR	60$			;DEVICE DOESN'T EXIST OR NOT AVAILABLE
30$:	MOV	SLA,DB.RLA(J)		;HE JUST WON A DEVICE !!!
	MOV	SNA,DB.SCB(J)		;REMEMBER WHICH NODE HE IS
	BIS	#DS.CAC!DS.CON!DS.XDS!DS.XCH,@J	;SEND CONNECT CONFIRM
40$:	JSR	PC,GETEXN		;GET SOURCE OBJECT TYPE
	MOVB	R0,DB.ROT(J)		;SAVE SOURCE OBJECT TYPE
42$:	JSR	PC,GETBYT		;GET NEXT BYTE OF SOURCE PID
	TST	R0			;WAS THIS LAST BYTE ?
	BMI	42$			;IF NOT KEEP FLUSHING
	JSR	PC,GETEXN		;GET MML
	MOV	R0,DB.MML(J)		;SAVE IT
50$:	JSR	PC,QUEDEV		;WAKE DEVICE SERVICE ROUTINE
	RTS	PC
.ENDC;.IF NE DEVN
;HERE WHEN CONNECT LOSES (DEVICE NOT AVAILABLE, OR BUSY)
60$:	JSR	PC,NCRESP		;BUILD RESPONSE MESSAGE
	BCS	65$			;EXIT IF CAN'T START MSG
	MOV	#NCLDIS,R0		;CODE FOR DISCONNECT MESSAGE
	JSR	PC,PUTBYT		;PUT INTO THE MESSAGE
	MOV	SLA,R0			;HIS LINK ADDRESS
	JSR	PC,PUTEXN
	CLR	R0			;OUR LINK ADDRESS NEVER ASSIGNED
	JSR	PC,PUTBYT
	MOV	#1,R0			;REASON IS DON'T HAVE ANY FREE
	JSR	PC,PUTBYT
	JSR	PC,@(P)+		;FINISH OFF MESSAGE
65$:	RTS	PC
;HERE WHEN RECEIVE A DISCONNECT FROM ANOTHER STATION
.IF NE DEVN
NCRDIS:
	JSR	PC,GETEXN		;GET DESTINATION LINK ADDRESS
	MOV	R0,DLA			;SAVE OUT LINK ADDRESS
	JSR	PC,NCRDLA		;GET DEVICE BLOCK FOR THAT ONE
	BEQ	91$			;IN CASE OF BUM DISCONNECT
	JSR	PC,GETEXN		;GET SOURCE LINK ADDRESS
	MOV	R0,SLA			;SAVE IT
.IF NE FT.CTY!TTYN
	BIT	#DS.TTY,(J)		;IF THIS ISN'T A TTY
	BEQ	70$			; THEN DON'T WORRY ABOUT SET HOST
	BIC	#TS.FRZ,DB.DCS(J)	;UNLOCK THE TERMINAL IF ^S'ED
	MOV	#1,DB.TIM(J)		;SET TIMER TO RESTART OUTPUT.
.IF NE FTHOST
	TST	DB.RLA(J)		;CHECK FOR SET HOST CASE
	BNE	30$			;IN CASE HOST COMMAND LOST
.IF NE FT.PFH				;IF PFH, SEE IF THE PFH IS SCHED 10
	MOV	SNA,SB			;GET ADDRESS OF THIS NODES SCB
	CMPB	SB.NNM(SB),DB.PFH(J)	;  AND SEE IF IT WAS THIS GUY'S PFH
	BNE	20$			;IF NOT HIS PFH, DON'T TRY ANOTHER CNCT
	JSR	PC,FNDHST		;TRY TO FIND A HOST
	BEQ	20$			;  IF NONE, JUST GIVE HIM THE DISCONNECT
	MOV	SB.NNM(SB),R0		;GET THE NUMBER OF THE NODE WE FOUND
	CMPB	R0,DB.PFH(J)		;  AND SEE IF IT IS THE PFH
	BNE	10$			;IF NOT, TRY A CONNECT TO THAT ONE.
	JSR	PC,FNDHST		;TRY ONCE MORE TO FIND A HOST
	BEQ	20$			;THIS SHOULDN'T FAIL...
	MOV	SB.NNM(SB),R0		;GET THE NUMBER AGAIN
	CMPB	R0,DB.PFH(J)		;IF WE DIDN'T GET A DIFFERENT ONE THIS
	BEQ	20$			;  TIME, GIVE UP.
10$:	MOVB	R0,DB.RCN(J)		;SET THE "RECONNECT" ADDRESS
.ENDC; IF NE FT.PFH
20$:	BIS	#DS.DIE,@J		;SO WE CLEAN UP
	BR	90$			;SO WE FIND WE DIED
30$:	JSR	PC,GETEXN		;GET DISCONNECT CODE
	CMP	R0,#10			;IS THIS A REASSIGN ?
	BNE	70$
	JSR	PC,GETEXN		;GET NODE TO REASSIGN TO
	MOVB	R0,DB.RCN(J)		;SAVE NODE NUMBER TO REASSIGN TO
	MOV	DB.LCB(J),R0		; POINT TO THE LCB
	MOVB	#LCS.RW,LC.STA(R0)	; WAITING FOR THE CONNECT FROM THE TEN
	BIS	#4*6,LC.CAR(R0)		; WAIT FOR 4 SECONDS
.ENDC;.IF NE FTHOST
.ENDC;.IF NE FT.CTY!TTYN
70$:	BIS	#DS.DSC,@J		;SET WANT TO DISCONNECT BIT
90$:	PJMP	QUEDEV			;SO WE GO AND CLEAN UP.
91$:	RTS	PC			;JUST RETURN
.IFF
	NCRDIS=CPOPJ
.ENDC;.IF NE DEVN
;HERE WHEN WE RECEIVE A NEIGHBOURS MESSAGE
NCRNGH:	TRACE	NC
	MOV	SNA,R1			;GET SCB ADR
	ASSERT	NE			;BE SURE WE HAVE ONE
	ADD	#SB.NGH,R1		;MAKE ADR OF 1ST NEIGHBOUR SLOT
	MOV	R1,-(P)			;SAVE POINTER TO THE
	ADD	#<NGHMAX*4>,(P)		;END OF NEIGHBORS AREA
20$:	TST	R2			;MORE NEIGHBOURS IN MSG ?
	BEQ	50$
	JSR	PC,GETEXN		;GET NNM
	JSR	PC,FNDSCB		;TRY TO FIND SCB FOR STATION
	BNE	30$
	MOV	R1,-(P)			;AND NGH POINTER
	MOV	R0,-(P)			;SAVE NNM
	JSR	PC,MAKSCB		;CREATE A SCB FOR NEW GUY
.IF NE DGUTS
	BCC	25$
	CMP	(P)+,(P)+		;POP STACK
	INC	R3			;SKIP LVL BYTE IN MSG
	DEC	R2
	BR	20$			;AND TRY NEXT ENTRY IN MSG
25$:
.ENDC ; .IF NE DGUTS
	MOV	(P)+,SB.NNM(SB)		;PUT NODE NUMBER IN SCB
	JSR	PC,ADDNSQ		;ADD NONSEQUENTIAL BLOCK
	MOV	(P)+,R1			;GET NGH POINTER BACK
30$:	JSR	PC,GETBYT		;GET LVL
	CMP	#OURSCB,SB		;WAS THAT NEIGHBOUR US ?
	BEQ	20$			;IF SO DON'T SAVE IT
	BIC	#^C377,R0		;STRIP EXTRA BITS
	CMP	R1,(P)			;INTO END OF AREA ?
.IF EQ DGUTS
	BHIS	20$			;YES, FORGET THIS NEIGHBOR
.IFF
	BHIS	21$			; TELL THE MAN
.ENDC
	MOV	SB,(R1)+		;PUT NGH-SCB ADR INTO SCB
	MOV	R0,(R1)+		;PUT LINK LVL INTO SCB
	BR	20$
50$:
	TST	(P)+			;CLEAR POINTER FROM STACK
	CLR	(R1)+			;FLAG END OF NEIGHBOURS
	PJMP	ROUTE			;REORGANIZE THE PATHS


.IF NE DGUTS
21$:	CTYMSG	NIL
	BR	20$
.ENDC
.IF NE DEVN
;REQUEST CONFIGURATION
NCRRCF:	BIS	#SF.XCN,@SB		;NEED TO SEND CONFIGURATION
	JSR	PC,NCLQRQ		;QUEUE SO NCL WILL SEND IT
NCR.XX:	RTS	PC

;CONFIGURATION
.IF EQ FTHOST
NCRCNF=NCR.XX
.IFF
NCRCNF:	TST	R2			;ANY MORE LEFT IN MSG ?
	BEQ	NCR.XX
	JSR	PC,GETEXN		;GET OBJECT TYPE
	CMP	#OBJMCR,R0		;IS THIS AN MCR ?
	BNE	20$
	BIS	#SF.MCR,@SB		;HE HAS AN MCR
.IF NE FT.CTY!TTYN
	SAVE	<R0,R1,R2,R3,J>			; LOOK FOR A TTY TO PRINT ON
	MOV	FIRDDB,J
5$:	TST	@J			; IS IT CONNECTED ?
	BMI	10$			; YES, LOOK FOR THE NEXT ONE
	BIT	#DS.TTY,@J		; IS THIS A TTY ?
	BEQ	10$			; NO, ALSO LOOK FOR NEXT ONE
	JSR	PC,TYPHIA		; SAY WE HAVE A HOST
10$:	MOV	DB.LNK(J),J		; NEXT DDB, PLEASE
	BNE	5$			; LOOP IF NEXT DDB THERE
	RESTORE	<J,R3,R2,R1,R0>
.ENDC
20$:	;JSR	PC,GETEXN		;GET COUNT
	JSR	PC,GETBYT		;GET NEXT BYTE OF BIT MAP
	TSTB	R0			;IS THAT LAST BYE OF MAP
	BMI	20$			;IF NOT KEEP FLUSHING
22$:	JSR	PC,GETBYT		;GET NEXT BYTE OF PID
	TSTB	R0			;WAS THAT LAST BYTE ?
	BMI	22$			;IF NOT KEEP FLUSHING
	BR	NCRCNF			;LOOP FOR REST OF DEVICES
.ENDC;.IF EQ FTHOST

;HERE WHEN RECEIVE A DATA REQUEST
NCRDRQ:
	JSR	PC,GETEXN		;GET DLA FROM MESSAGE
	JSR	PC,NCRDLA		;CONVERT THAT INTO DEVICE BLOCK ADR
.IF LT DEBUG
	BEQ	90$		;IGNORE IF NO DEVICE
.IFF
	BNE	50$
.IF NE DGUTS
	CTYMSG	NDV
.ENDC
	RTS	PC
.ENDC ; .IF LT DEBUG
50$:	JSR	PC,GETEXN		;GET COUNT
	ADD	DB.IDR(J),R0		;MAKE TOTAL REQUEST COUNT
	MOVB	R0,DB.IDR(J)		;RESTORE TO DEVICE BLOCK
90$:	RTS	PC			;ALL DONE
.IFF;.IF NE DEVN
	NCRRCF=CPOPJ			;IGNORE REQ FOR CONFIGS
	NCRDRQ=CPOPJ			; AND DATA REQUESTS
	NCRCNF=CPOPJ			; AND CONFIGURATION MSGS
.ENDC	;.IF NE DEVN
;HERE WHEN RECEIVE A BOOT MSG IN A STATION CONTROL MSG

.IF NE NTLINE
STCBOT:	JSR	PC,ERSGET		;GET CHUNK FOR MSG
	MOV	R0,-(P)			;SAVE ADDRESS OF FIRST CHUNK
	MOV	SNA,SB			;GET SCB ADR MSG CAME FROM
	MOVB	SB.NNM(SB),R0		;GET SNA
	ASSERT	PL
	MOV	R0,LB.BNN(J)		;REMEMBER WHICH NODE SENT MSG
	INCB	LB.BNN+1(J)		;AND BE SURE TO SET BOOTSTRAP MODE
	MOV	@P,SB			;COPY ADDRESS OF CHUNK
	ADD	#CN.NCT,SB		;POINT TO FIRST BYTE IN HEADER
	CLR	R1			;COUNTER FOR MSG LENGTH
	BR	44$			;PUT INTO MSG
30$:	JSR	PC,GETBYT		;GET NEXT BYTE FOR BOOT MSG
	ADVCNK	R4 EXTEND		;ALLOCATE ANOTHER CHUNK IF REQUIRED
44$:	MOVB	R0,(SB)+		;PUT NEXT BYTE INTO THE MESSAGE
	INC	R1			;COUNT BYTE
	TST	R2			;MORE BYTES LEFT ?
	BNE	30$			;IF SO LOOP BACK FOR EM
	MOV	(P)+,R0			;GET MESSAGE ADDRESS BACK
	MOV	R1,CN.LEN(R0)		;SAVE MESSAGE LENGTH
	SAVE	<R2,R3>
	JSR	PC,DDQBOO		;SEND BOOTSTRAP MSG
	RESTORE	<R3,R2>
	RTS	PC

.ENDC;.IF NE NTLINE
;HERE WHEN WE RECEIVE A STATION CONTROL MESSAGE
NCRSTC:
.IF EQ FT.STC
	RTS	PC
.IFF
	MOV	SNA,R1			;GET OUR SOURCE'S NODE
	MOV	SB.NNM(R1),R1		; NUMBER FOR STCRNN CHECKS.
	JSR	PC,GETBYT		;GET LINE NUMBER FOR REQUEST
	BIC	#^C377,R0		;GET 8 BITS WORTH OF LINE NUMBER
	MOV	R0,SB			;IS IT FOR US ?
	BEQ	50$			;IF SO GO DO IT
	BITB	#^C7,@R3		;IS CODE REASONABLE ?
	BNE	90$			;IF NOT IGNORE MSG
.IF NE NTLINE				;IF NO LINES, IGNORE BOOT MSGS
.IF NE BSTRNN				;IF WE'RE RESTRICTING BOOT MSGS
	CMP	#BSTRNN,R1		;SEE IF IT CAME FROM THE GOOD GUY
	BNE	30$			; IF NOT, REJECT IT
.ENDC
	MOV	#FRSTLB,J		;GET ADR OF FIRST LINE BLOCK
	BR	24$
12$:	DEC	R0			;HIT RIGHT ONE YET ?
	BNE	24$
	TSTB	LB.BNN(J)		;SOME NODE HAVE USE OF THIS BOOT ?
	BEQ	20$
	MOV	SNA,R1			;GET SOURCE NODE SCB
	CMPB	SB.NNM(R1),LB.BNN(J)	;IS THIS RIGHT ONE ?
	BNE	30$			;IF NOT SEND REJECT
20$:	TST	LB.BOO(J)		;IS THERE A BOOTSTRAP MSG PENDING ?
	BEQ	STCBOT			;SEND BOOT MSG
	BR	30$			;SEND REJECT
24$:	MOV	LB.LNK(J),J		;GET NEXT LINE BLOCK ADR
	BNE	12$			;LOOP BACK TO SEE IF THIS IS IT
.ENDC	;.IF NE NTLINE

;HERE TO SEND A REJECT MSG IN RESPONSE TO STATION CONTROL MSG
30$:	JSR	PC,NCRESP		;BEGIN BUILDING MESSAGE
	BCS	90$
	MOV	#7,R0			;STATION CONTROL IS TYPE 7
	JSR	PC,PUTBYT
	MOV	SB,R0			;LINE NUMBER REJECT IS FOR
	JSR	PC,PUTBYT
	MOV	#13,R0			;REJECT CODE
	JSR	PC,PUTBYT
	BR	66$			;FINISH MSG THEN DONE
;HERE WHEN STATION CONTROL IS FOR US
50$:
.IF NE STCRNN				;IF WE'RE BEING PICKY ABOUT WHO
	CMP	#STCRNN,R1		; CAN POKE US, SEE IF IT CAME FROM
	BNE	30$			; A GOOD GUY.  IF NOT, REJECT IT.
.ENDC ; NE STCRNN
	JSR	PC,GETBYT		;GET FUNCTION CODE
	BIC	#^C3,R0			;STRIP EXTRA BITS
	ASL	R0			;FOR DISPATCH
	JMP	@52$(R0)
52$:	30$				;CODE (0) = BOOT MSG (RESPOND WITH REJECT)
	60$				;CODE (1) = EXAMINE
	70$				;CODE (2) = DEPOSIT
	80$				;CODE (3) = GOTO

;HERE WHEN RECEIVE AN EXAMINE CORE STATION CONTROL MESSAGE
60$:	JSR	PC,94$			;GET ADDRESS IN J
	MOV	J,SB			;COPY FIRST ADR TO EXAMINE
	JSR	PC,94$			;GET LIMIT ADDRESS
	MOV	SB,STCADR		;SAVE 1ST ADR FOR RESPONSE
	SUB	SB,J			;LEAVES NUMBER OF BYTES TO EXAMINE
.REPT	0	;TO PROTECT FROM DUMB PRIVILEDGED PROGRAMS MAKE REPT 1
	BIC	#^C377,J		;STRIP EXTRA BITS
	BNE	61$
	MOV	#2,J			;DEFAULT IS 2 BYTES
61$:
.ENDR
	MOV	#12,R0			;EXAMINE DATA CODE
	JSR	PC,NRST50		;RESPOND
64$:	PIOFF
	MOV	NXMVEC,-(P)
	MOV	#68$,NXMVEC		;IN CASE OF BUM EXAMINE
	MOVB	(SB)+,R0		;GET NEXT DATA BYTE
	MOV	(P)+,NXMVEC		;RESTORE BUS TRAP ADR
	PION
	JSR	PC,PUTBYT
	SOB	J,64$			;LOOP BACK TO SEND REST OF BYTES
66$:	JSR	PC,@(P)+		;FINISH MESSAGE
	BR	90$
68$:	MOV	(P)+,(P)+		;CLEAR OFF STACK
	MOV	(P)+,NXMVEC
	PION
	MOVB	#13,@R1			;PUT REJECT CODE INTO THE MESSAGE
	BR	66$			;FINISH MSG
;HERE WHEN RECEIVE A DEPOSIT STATION CONTROL MESSAGE
70$:	JSR	PC,94$			;GET ADDRESS IN J
74$:	TST	R2			;CHECK FOR MORE TO DEPOSIT
	BEQ	86$			;WHEN DONE RESPOND WITH ACCEPT
	JSR	PC,GETBYT		;GET NEXT BYTE
	MOVB	R0,(J)+			;DEPOSIT
	BR	74$

;HERE WHEN GET A GOTO TYPE STATION CONTROL MESSAGE
80$:	JSR	PC,NRST95		;GET ADDR TO GO TO
	JSR	PC,@R0			;DO THE GO TO
					;AND RESPOND WITH ACCEPT

86$:	MOV	#11,R0			;CODE FOR ACCEPT
	JSR	PC,NRST50		;RESPOND
	JSR	PC,@(P)+		;FINISH MSG

90$:	RTS	PC

;HERE TO GET 24 BIT ADDRESSES
94$:	JSR	PC,NRST95		;GET LOW ORDER 16BITS OF ADDRESS
	MOV	R0,J			;SAVE ADDRESS
	MOV	J,STCADR		;SAVE LAST ADRESS
	JSR	PC,GETBYT		;GET HIGH ORDER BYTE
NRST49:	RTS	PC
;HERE TO BUILD STATION CONTROL RESPONSE
NRST50:	MOV	R0,TEMP0		;SAVE TYPE
	MOV	(P)+,TEMP1		;SAVE RETURN ADDRESS
	JSR	PC,NCRESP		;GO BUILD MESSAGE
	BCS	NRST49			;NO ROOM, RETURN TO CALLER OF CALLER
	MOV	#7,R0			;STATION CONTROL IS TYPE 7
	JSR	PC,PUTBYT
	CLR	R0
	JSR	PC,PUTBYT		;FOR DESTINATION NODE
	MOV	R3,R1			;SAVE POINTER TO CODE
	MOV	TEMP0,R0		;FETCH THE TYPE CODE
	JSR	PC,PUTBYT
	MOV	(PC)+,R0		;FETCH THE ADDRESS
STCADR=.
	.WORD	0
	JSR	PC,PUTBYT		;PUT INTO MESSAGE
	SWAB	R0			;NOW HIGH ORDER BITS
	JSR	PC,PUTBYT
	CLR	R0
	JSR	PC,PUTBYT		;PUT IN MESSAGE
NRST99:	JMP	@TEMP1			;AND RETURN

;HERE TO GET A SIXTEEN BIT QUANTITY FROM MSG
NRST95:	JSR	PC,GETBYT		;GET LOW ORDER BITS OF ADDRESSS
	BIC	#^C377,R0		;STRIP EXTRA BITS
	MOV	R0,-(P)			;SAVE EM
	JSR	PC,GETBYT		;GET MIDDLE 8 BITS
	MOVB	R0,1(P)			;INCLUDE
	MOV	(P)+,R0			;GET SIXTEEN BITS BACK
	RTS	PC
.ENDC;.IF EQ FT.STC
;HERE FROM NCRSTC OR NCRCON TO BUILD A RESPONSE MESSAGE
; CALL	JSR	PC,NCRESP
;	RETURN WITH MSG STARTED
;	TO FINISH MESSAGE JSR PC,@(P)+

.IF NE <FT.STC!DEVN>
NCRESP:	JSR	PC,80$			;SWAP SOURCE AND DESTINATION SCB ADRS
	MOV	R2,-(P)
	MOV	R3,-(P)
	CLR	R1			;BUILDING NUMBERED MESSAGE
	JSR	PC,NCLBMS		;BUILD A MESSAGE
	SEC
	BEQ	75$
	CLR	R0			;DLA IS ZERO
	JSR	PC,PUTBYT
	INC	R2
	MOV	R2,-(P)			;SAVE COUNT
	MOV	R3,-(P)			;SAVE POINTER TO COUNT FIELD
	JSR	PC,PUTBYT		;DUMMY COUNT FIELD
	CLR	R2			;RESET COUNT, ALSO CLEARS CARRY
	JSR	PC,@12(P)		;RETURN TO CALLER
	MOV	(P)+,12(P)		;PUT RETURN ADR ELSEWHERE
	MOVB	R2,@(P)+		;PUT COUNT INTO MESSAGE
	ADD	(P)+,R2			;MAKE TOTAL COUNT
	MOV	(P)+,R0			;GET ADDRESS OF 1ST CHUNK
	MOV	R2,CN.LEN(R0)		;PUT LENGTH INTO MESSAGE
	JSR	PC,NCLIN1		;TRANSMIT MESSAGE
	CLC
75$:	MOV	(P)+,R3
	MOV	(P)+,R2
80$:	MOV	SNA,-(P)		;SAVE SOURCE NODESCB ADR
	MOV	DNA,SNA			;DESTINATION IS NOW SOURCE
	MOV	(P)+,DNA		;AND OLD DEST IS NOW SOURCRE
	RTS	PC
.ENDC;.IF NE <FT.STC!DEVN>
;HERE TO GET THE NEXT BYTE FROM THE MESSAGE
GETBYT:	DEC	R2			;COUNT OUT THE NEXT BYTE
	BMI	10$			;AND BRANCH IF COUNTER OVERFLOW
	MOVB	(R3)+,R0		;GET THE NEXT BYTE
	ADVCNK	R3			;MOVE TO NEXT CHUNK IF NECESSARY
	RTS	PC
10$:	CLR	R0			;RETURN NULL VALUE
	CLR	R2			;RESET COUNTER OVERFLOW
	TWIDDLE				;COUNT THE ERRORS
	RTS	PC

;HERE TO GET AN EXTENSIBLE NUMBER FROM NCL HEADER
GETEXN:	JSR	PC,GETBYT		;GET 1ST BYTE
	TSTB	R0			;SEE IF EXTENDED FLAG IS SET IN BYTE
	BPL	92$			;IF NOT WE ARE DONE
	SAVE	<R0>
	JSR	PC,GETBYT		;GET 2ND BYTE
	SWAB	R0			;NOW PATCH THESE 14 BITS TOGETHER
	COM	R0
	ASR	R0
	BIC	#177,R0
	BIC	R0,(P)
	BPL	91$			;IF BITS 14,15 ARE ZERO, WE'RE DONE
	JSR	PC,GETBYT		;GET THE LAST TWO BITS
	SAVE	<R0>
	BPL	90$			;IF FLAG BIT IS OFF, WE'RE DONE
	TWIDDLE				;COUNT TOOOO LOOOONG FIELD ERRORS
89$:	JSR	PC,GETBYT		;ELSE EAT UP THE REST OF THIS GARBAGE
	TSTB	R0
	BMI	89$
90$:	RESTORE	<R0>			;GET BITS 14,15
	ASR	R0
	ROR	R0
	ROR	R0
	BIS	#37777,R0
	COM	R0
	BIC	R0,(P)
91$:	RESTORE	<R0>
92$:	RTS	PC
.SBTTL		HERE FROM DDCMP WHEN WE RECEIVE A START OR STACK ON A LINE

.IF NE NTLINE
NCLRSS:	MOV	LB.SCB(J),SB		;GET STATION BLOCK ADDRESS
	BEQ	20$
	BIT	#SF.HID,@SB		;DID I KNOW WHO HE WAS ?
	BEQ	24$			;IF NOT NO PROBLEM
	CLR	LB.SCB(J)		;NO LONGER GET HERE
	JSR	PC,ROUTE		;SCHEDULE ROUTES TO STATIONS
	JSR	PC,SNDNGH		;SEND NEIGHBOURS TO EVERYONE
20$:	JSR	PC,MAKSCB		;GET A SCB
.IF NE DGUTS
	BCS	NCQRQX			;EXIT IF CAN'T
.ENDC ; .IF NE DGUTS
	MOV	SB,LB.SCB(J)		;SAVE ADDRESS
24$:	;MOV	#SBF.NI!SBF.IU,@SB	;NEED TO SEND NODEID
	MOV	#SBF.IU,@SB		;NEED TO SEND NODEID
	MOV	J,SB.LBA(SB)		;SAVE ADDRESS OF LINE DATA BLOCK
.ENDC	;.IF NE NTLINE
NCLRS9:	MOVB	#1,SB.TIM(SB)		;START TIMER
	JSR	PC,NCLQRQ		;REQUEST NCL TO RUN
	MOV	#OURSCB,SNA		;SOURCE NODE IS US
	MOV	SB,DNA			;DESTINATION IS THIS GUY
	MOV	#6,R1			;CODE FOR NODE-ID MESSAGE
	JSR	PC,NCLBMS		;BEGIN BUILDING MSG
	BEQ	NCQRQX			;EXIT IF CAN'T
	JSR	PC,NCLS40		;PUT ON BODY OF MSG
	MOV	(P)+,R0			;GET POINTER TO MSG
	MOV	R2,CN.LEN(R0)		;SAVE LENGTH OF MSG
	PJMP	NCLIN1			;SEND MSG

;HERE TO PUT AN SCB ADR INTO THE NCL QUEUE
NCLQRQ:	TRACE	NC
	TST	SB
.IF EQ DGUTS
	ASSERT	NE
.IFF
	BEQ	NCQRQX
.ENDC ; .IF EQ DGUTS
	QUEPUT	NC 90$
NCQRQX:	RTS	PC
;HERE WHEN BUILDING A NEW NONSEQUENTIAL NODE SCB
; CALL	MOV	<ADR>,SB		;ADR OF NEW SCB
;	JSR	PC,ADDNSQ

ADDNSQ:	MOV	SB,R0			;COPY SCB POINTER
	MOV	R2,-(P)			;SAVE REG
	MOV	#SQNTAB+2,R2
	MOV	#SBF.IU!SF.HID,R1	;FLAGS FOR WINDOW
24$:	JSR	PC,ADDWIN		;INITIALIZE THE WINDOW
	TST	(R2)+			;IS THERE A NEXT SEQ NODE ?
	BNE	24$
	BIS	#SBF.NB!SF.XCN!SF.XRC,@SB	;SEND NEIGHBOURS & CONFIG
	JSR	PC,NCLQRQ		;QUEUE SCB UP
	MOV	(P)+,R2			;RESTORE REGISTER
	RTS	PC

;HERE TO INITIALIZE AN SCB WINDOW
ADDWIN:	MOV	R1,@R0			;FLAGS
	CLRB	SB.HXN(R0)		;INITIALIZE WINDOW
	CLRB	SB.HAR(R0)		;INITIALIZE WINDOW
	CLRB	SB.LAP(R0)		;INITIALIZE WINDOW
	CLRB	SB.RMN(R0)		;INITIALIZE WINDOW
	CLR	SB.IMQ(R0)		;INITIALIZE WINDOW
	CLR	SB.OMQ(R0)		;INITIALIZE WINDOW
	MOVB	#1,SB.TIM(R0)		;START THE CLOCK RUNNING
	ADD	#SQNSIZ,R0		;STEP TO THE NEXT WINDOW (CRAPPY CODE.)
	RTS	PC
;HERE WHEN BUILDING A NEW SEQUENTIAL NODE SCB
; CALL	MOV	<ADR>,SB		;ADR OF NEW SCB
;	JSR	PC,ADDSQN

ADDSQN:	MOV	R2,-(P)			;SAVE REGISTER
	MOV	SB,-(P)			;SAVE POINTER TO SCB
	MOV	SB,R0			;COPY SCB POINTER
	MOV	#SQNTAB+2,R2
	MOV	#SBF.SQ!SBF.IC!SBF.IU!SF.HID,R1	;FLAGS
24$:	JSR	PC,ADDWIN		;SET UP WINDOW
	TST	(R2)+			;IS THERE A NEXT SEQ NODE ?
	BNE	24$
	MOV	SB,-(R2)		;ADD OUR NODE TO SQNTAB
	SUB	SB,R0			;MAKES OFFSET FOR NEXT WINDOW
	MOV	R0,R2			;COPY OFFSET TO ANOTHER REG

;NOW ADD WINDOWS TO OLD SCB'S
	MOV	#OURSCB,SB		;FIRST SCB ADR
50$:	BIT	#SF.HID,@SB		;DO I KNOW THIS GUY ?
	BEQ	60$			;IF NOT LEAVE ALONE
	MOV	#SBF.IU!SF.HID,R1	;FLAGS
	BIT	#SBF.SQ,@SB		;IS NODE SEQUENTIAL ?
	BEQ	54$
	BIS	#SBF.SQ!SBF.IC,R1	;SEQ SO THIS IS CONTACT
54$:	MOV	SB,R0			;COPY SCB POINTER
	ADD	R2,R0			;POINT TO WINDOW
	JSR	PC,ADDWIN		;SET UP THE WINDOW
60$:	SB.ADV	50$

	MOV	(P)+,SB			;GET POINTER TO SCB BACK
	MOV	(P)+,R2			;RESTORE REGISTER
	RTS	PC
.SBTTL	THE ROUTING ROUTINE

ROUTE:	SAVE	<R0,R1,R2,SB,J>		;WE NO LONGER CLOBBER EVERYTHING
	MOV	#SCB0,SB		;FIRST, FOR ALL SCB'S
10$:	CLR	SB.LBA(SB)		;CLEAR THEIR ASSOCIATED LINE
	MOV	#77777,SB.LVL(SB)	; AND SET THEIR COST TO INFINITY
	SB.ADV	10$			;GET 'EM ALL

.IF NE FTDL10!FT.DTE			;IF WE HAVE A HIGH SPEED LINK
	MOV	TENSCB,SB		;SEE IF THE LINK IS UP
	BEQ	20$			;IF IT IS, THEN SET UP
	MOV	SB,SB.LBA(SB)		; IT'S PECULIAR INCESTUOUS ROUTING
	MOV	#TENLVL,SB.LVL(SB)	;(AND AT A BARGAIN PRICE...)
20$:
.ENDC; NE FTDL10!FTDTE

.IF NE NTLINE				;IF WE HAVE SYNCH LINES.
	MOV	#FRSTLB,J		; THEN FOR ALL LINES,
	BR	40$			; MARK OUR NEIGHBOR AS REACHABLE.
30$:	MOV	LB.SCB(J),SB		;GET THE LINE'S ASSOCIATED NODE ADR
	BEQ	40$			;IF NONE -- CURIOUS.
.IIF NE FTDL10!FT.DTE, ASSERT SB NE TENSCB ;THE TEN DOESN'T HAVE SYNCH LINES!
	MOV	SB.LBA(SB),LB.2ND(J)	;MAKE ANY PREVIOUS LINE A SECONDARY
	MOV	J,SB.LBA(SB)		;MAKE THIS THE PRIMARY
	MOV	LB.LVL(J),SB.LVL(SB)	;SET THE INITIAL COST
40$:	MOV	LB.LNK(J),J		;ADVANCE TO THE NEXT LINE
	BNE	30$			; AND MARK THAT NEIGHBOR.
.ENDC; NE NTLINE
;NOW "MARK" ALL REACHABLE NODES AND ASSIGN THE LOWEST COST PATHS
	MOV	#SCB0,SB		;FOR ALL REMOTE SCBS
50$:	BIT	#SBF.IC,@SB		;IF WE DON'T KNOW SHO HE IS,
	BEQ	60$			; DON'T USE A LEFT OVER NGH LIST
	TST	SB.LBA(SB)		;IF THERE IS NO PATH TO THIS GUY
	BEQ	60$			;THEN WE'RE NOT INTERESTED IN HIS NGHS
	MOV	SB,SB.RSB(SB)		;PRESERVE "SB" FROM MARK
	MOV	SB,R0			;SET R0 UP TO POINT TO
	ADD	#SB.NGH,R0		; OUR NEIGHBORS TABLE
	MOV	#60$,SB.RTN(SB)		;SET UP MARK'S RETURN ADDRESS
	BR	MARK			;MARK FROM ALL OUR NEIGHBORS.
60$:	SB.ADV	50$			;LOOP OVER THE REST OF THE SCBS

;NOW THAT WE'VE LOOKED AT ALL WE CAN REACH, DECLARE THE REST UNREACHABLE
	MOV	#SCB0,SB		;ONE LAST LOOP OVER ALL THE SCBS
70$:	TST	@SB			;IF NOT IN USE, THEN
	BEQ	80$			; WE DON'T NEED TO DECLARE HIM DEAD
	TST	SB.LBA(SB)		;SEE IF WE FOUND A LINE FOR HIM
	BNE	80$			;IF WE DID, THEN HE'S REACHABLE
	JSR	PC,N.DOWN		;IF NOT, DECLARE HIM DOWN
80$:	SB.ADV	70$			;LOOP OVER THE REST OF THE SCB'S

	RESTORE	<J,SB,R2,R1,R0>		;CLEAN UP
	RTS	PC			; AND WE'RE DONE
;MARK - ROUTINE TO TRACE OUT ALL OF A NODE'S NEIGHBORS
;CALL	SB := POINTER TO SCB TO MARK FROM
;	R0 := A POINTER TO THE NEXT ENTRY IN HIS NGH TABLE TO MARK
MARK:	MOV	(R0)+,R1		;GET THE ADDRESS OF THE NEIGHBOR
	BEQ	10$			;IF NONE, THEN WE'RE DONE
	MOV	(R0)+,R2		;GET THE COST FROM "SB" TO "R1"
	ADD	SB.LVL(SB),R2		;COMPUTE COST FROM "OURSCB" TO "R1"
	CMP	R2,SB.LVL(R1)		;SEE IF WE'VE FOUND A BETTER ROUTE
	BGE	MARK			;IF NOT, TRY THE NEXT NEIGHBOR

;HERE IF WE'VE FOUND A BETTER ROUTE.  CALL MARK RECURSIVLY ON THE NEIGHBOR
	MOV	SB.LBA(SB),SB.LBA(R1)	;SET THE NEW NODE'S LINE ASSIGNMENT
	MOV	R2,SB.LVL(R1)		;SET IT'S COST
	MOV	R0,SB.RR0(R1)		;STASH R0 AWAY OVER THE CALL
	MOV	SB,SB.RSB(R1)		;STASH SB AWAY TOO
	MOV	#MARK,SB.RTN(R1)	;RETURN TO "MARK" WHEN DONE
	MOV	R1,SB			;SET UP "SB" FOR CALL TO MARK
	MOV	SB,R0			;SET R0 UP TO POINT TO
	ADD	#SB.NGH,R0		; TO THE FIRST ENTRY IN THE NGH TABLE
	BR	MARK			;RECURSIVLY CALL "MARK"

;HERE TO "RETURN" FROM MARK.  RESTORE "SB" AND "R0"
10$:	MOV	SB.RR0(SB),R0		;RESTORE R0
	MOV	SB.RTN(SB),-(SP)	;PUSH THE RETURN ADDRESS FOR A BIT
	MOV	SB.RSB(SB),SB		;RESTORE "SB"
	RTS	PC			;AND "RETURN"

;HERE TO CLEAN OUT A STATION CONTROL BLOCK FOR NODE WHICH IS DOWN
N.DOWN:	TRACE	NC
	SAVE	<DNA>
	MOV	SB,DNA			;SAVE SCB ADR
.IIF NE NTLINE,	JSR	PC,SNDSNB	;SEND ROUTING MSG TO SEQ NGHBS

.IF NE DEVN
	SAVE	<J>
	MOV	FIRDDB,J		;GET FIRST DEVICE BLOCK
10$:	CMP	SB,DB.SCB(J)		;IS OWNER GUY WHO DIED ?
	BNE	15$
	BIS	#DS.DIE,@J		;SET ABORT FLAG
	JSR	PC,QUEDEV		;WAKE SERVICE ROUTINE
15$:	MOV	DB.LNK(J),J		;GET NEXT DEVICE BLOCK
	BNE	10$			;AND CHECK IT ALSO
	RESTORE	<J>
.ENDC;.IF NE DEVN

.IF NE FTDL10!FT.DTE
	CMP	SB,TENSCB		;IS THIS THE 10 ?
	BNE	22$
20$:	MOV	T10QUE,R0		;GET FIRST MSG IN QUEUE
	BEQ	22$			;BRANCH WHEN HAVE FLUSHED QUEUE
	MOV	CN.MLK(R0),T10QUE	;DELINK FIRST MESSAGE
	JSR	PC,FRECKS
	BR	20$
22$:
.ENDC;.IF NE FTDL10!FT.DTE

24$:	MOV	SB.WOQ(SB),R0		;GET ADDRESS OF NEXT MSG AWAITING A #
	BEQ	26$			; (IF THERE IS ONE)
	MOV	CN.MLK(R0),SB.WOQ(SB)	;TAKE IF OFF OF THE WOQ
	JSR	PC,FRECKS		;FREE IT
	BR	24$			; AND TRY FOR MORE
26$:

.IF NE,FTDCP3!FTDCP4
	JSR	PC,NSPDWL		;INFORM PORT THAT IT MAY HAVE TO BREAK CONNECTIONS
.ENDC

	BIT	#SBF.SQ,@SB		;IS NODE SEQUENTIAL ?
	BEQ	60$

;HERE WHEN A SEQUENTIAL NEIGHBOUR WENT AWAY
	MOV	#SQNTAB+2,R2
	CLR	R3			;OFFSET FOR THIS NODE
30$:	ADD	#SQNSIZ,R3		;INCREASE OFFSET
	ASSERT	NE (R2)
	CMP	SB,(R2)+		;LOOK FOR RIGHT NODE
	BNE	30$			;IF HAVEN'T FOUND IT KEEP LOOKING
	MOV	#OURSCB,SB		;ADDRESS OF FIRST SCB
32$:	;BIT	#SBF.SQ,@SB		;IS NODE SEQUENTIAL ?
	;BNE	38$			;IF SO NOT INTERESTING
	MOV	SB,-(P)			;SAVE POINTER TO SCB
	ADD	R3,SB			;POINT TO RIGHT SUBWINDOW
	JSR	PC,N.DWN6		;FLUSH QUEUES
	MOV	R2,R1			;GET POINTER TO SEQUENTIAL NODE TABLE
34$:	TST	(R1)+			;IS THERE ANOTHER SUB WINDOW ?
	BEQ	38$
	MOV	#<SQNSIZ/2>,R0		;COUNTER
36$:	MOV	SQNSIZ(SB),(SB)+	;SHUFFLE
	SOB	R0,36$
	BR	34$			;LOOP BACK FOR FURTHER SHUFFLES
38$:	MOV	(P)+,SB			;GET SCB POINTER BACK
	SB.ADV	32$			;ON TO NEXT NODE
39$:	MOV	(R2)+,-4(R2)		;SHUFFLE
	BNE	39$
	MOV	DNA,SB			;GET POINTER TO OUR SCB AGAIN

;HERE WHEN A NONSEQUENTIAL NODE GOES AWAY
60$:	MOV	#SQNTAB,R2		;MAKE POINTER TO SEQUENTIAL NODE TABLE
62$:	TST	(R2)+			;IS THERE ANOTHER SEQUENTIAL NODE ?
	BEQ	80$			;WHEN DONE WITH THIS BLOCK LOOK FOR OTHERS
	JSR	PC,N.DWN6		;CLEAN OUT MESSAGES FOR LINE
	ADD	#SQNSIZ,SB		;ADVANCE OFFSET
	BR	62$

80$:	MOV	DNA,SB			;IN CASE CALLER WAS USING THIS
	CLR	@SB			;FLAG SCB IS FREE
	RESTORE	<DNA>
N.DWN9:	RTS	PC

;DISCARD ALL MESSAGES IN INPUT AND OUTPUT QUEUES FOR AN SCB WINDOW
; CALL	MOV	<ADR OF WINDOW>,SB
;	JSR	PC,N.DWN6
;	RETURN		<USES R0, AND R1>
N.DWN6:	MOV	SB.IMQ(SB),R1		;GET ADR OF 1ST MSG IN INPUT QUEUE
	CLR	SB.IMQ(SB)		;AND FORGET QUEUE
	JSR	PC,10$			;DISPOSE OF EM
	MOV	SB.OMQ(SB),R1		;GET ADR OF 1ST MSG IN OUTPUT QUEUE
	CLR	SB.OMQ(SB)		;AND FORGET QUEUE
10$:	MOV	R1,R0			;COPY ADDRESS OF MSG
	BEQ	N.DWN9
	MOV	CN.MLK(R1),R1		;ADVANCE TO NEXT MSG
	JSR	PC,FRECKS		;DISPOSE OF CURRENT MSG
	BR	10$			;ON FOR REST OF MESSAGES
;HERE TO CREATE A NEW SCB
MAKSCB:	MOV	#SCB0,SB		;GET ADDRESS OF 1ST SCB
10$:	TST	@SB			;CHECK FOR SCB IN USE
	BEQ	40$
20$:	SB.ADV	10$			;GET ADR OF NEXT SCB
.IF EQ DGUTS
	TRAP				;RUN OUT OF SCB'S ?
.IFF
	CTYMSG	SBA
	CLR	SB			;ALSO CLEARS CARRY
	SEC				;SET CARRY (ERROR FLAG)
	RTS	PC
.ENDC ; .IF EQ DGUTS
40$:	;JSR	PC,CLRSCB		;CLEAR OUT BLOCK
	;RTS	PC

;HERE TO CLEAR A STATION CONTROL BLOCK
CLRSCB:	MOV	SB,R0			;COPY ADDRESS TO CLEAR
	MOV	#<<SB.SNM+1>/2>,R1	;NUMBER OF WORDS IN BLOCK
10$:	CLR	(R0)+			;CLEAR NEXT WORD
	SOB	R1,10$
	CLC				;CLEAR CARRY (SUCCESS FLAG)
	RTS	PC

;HERE TO FIND A STATION CONTROL BLOCK
; CALL	MOV	#NNM,R0
;	JSR	PC,FNDSCB
;	RETURN WITH (SB) = 0 OR POINTING TO STATION BLOCK
FNDSCB:	MOV	#OURSCB,SB		;FIRST STATION BLOCK
10$:	BIT	#SF.HID,@SB		;DO WE HAVE ID FOR STATION ?
	BEQ	20$
	CMP	R0,SB.NNM(SB)		;IS THIS OUR MATCH ?
	BEQ	90$
20$:	SB.ADV	10$			;ON TO NEXT SCB
	CLR	SB
90$:	TST	SB			;SET CONDITION CODES FOR RETURN
	RTS	PC
;NCLCKA	ROUTINE TO CHECK TO SEE IF ANY MESSAGES ON THE OMQ CAN
;  BE FREED.
;CALL 	SB := POINTER TO THE CORRECT SUB-WINDOW,
;	DNAOFF SET UP

NCLCKA:	CMPB	SB.HAR(SB),SB.LAP(SB)	;HAVE WE PROCESSED ALL ACKS?
	BEQ	99$			;IF SO, THEN CAN'T DO ANYMORE.
	ASSERT	PL			;BETTER NOT PROCESS MORE THAN WE GET!
	MOV	SB.OMQ(SB),R0		;GET NEXT MESSAGE AWAITING AN ACK
	BEQ	98$			;IF NONE, THEN DDCMP HAS IT.
	INCB	SB.LAP(SB)		;ASSUME WE CAN PROCESS THIS MSG
	CMPB	CN.NCN(R0),SB.LAP(SB)	;IS THIS MESSAGE THE NEXT ONE?
	BNE	97$			;IF NOT, RESET SB.LAP AND EXIT
	MOV	CN.MLK(R0),SB.OMQ(SB)	;SPLICE OUT THIS MESSAGE.
.IF NE DEVN
	TST	DNAOFF			;IF THE MESSAGE ISN'T FOR "US"
	BNE	20$			;THEN DON'T TRY TO WAKE DEVICES.
	SAVE	<R0,J>			;DON'T CLOBBER CALLERS DDB POINTER
	MOV	CN.DDB(R0),J		;IS THERE A DEVICE TO WAKE UP?
	BEQ	10$			;IF NOT, THEN DONE
	BIC	#DS.IQU,@J		;CLEAR THE "NCL IN THE PIPE" BIT
	JSR	PC,QUEDEV		; AND RESTART THE DEVICE
.IF NE FT.TSK
	MOV	DB.TSK+6(J),J		;IS THERE A TASK TO WAKE UP
	BEQ	10$			;IF NONE.
	JSR	PC,TSKWAK		;WAKE THE TASK.
.ENDC
10$:	RESTORE	<J,R0>			;GET ORIGIONAL DDB POINTER BACK
.ENDC ;IF NE DEVN
20$:	JSR	PC,FRECKS		;FREE THE MESSAGE
	BR	NCLCKA			; AND CHECK FOR MORE ACKS

97$:	ASSERT	PL			;MAKE SURE WE DIDN'T MISS A MESSAGE
	DECB	SB.LAP(SB)		;FIX UP THE LAST ACK PROCESSED FIELD
98$:	TWIDDLE				;COUNT TIMES WE COULDN'T FIND THE MSG
99$:	RTS	PC			;AND WE'RE DONE
;ROUTINE TO SEE IF IT IS OK TO "TOSS" A MESSAGE
;  THE RULE IS THAT YOU CAN TOSS ANY MESSAGE EXCEPT
;  A DATA MESSAGE FROM A SEQUENTIAL NODE.
;RETURN	CARRY SET => CAN'T TOSS, MUST WAIT FOR AN ACK
;	CARRY CLR => IT'S OK TO TOSS IT
;NOTE	THIS IS A SLOW ROUTINE.  CALL ONLY IN EMERGENCIES.
NCLOKT:	ASSERT	CHUNK R0		;MAKE SURE WE GOT A GOOD MSG
	SAVE	<R0,R1,R2,R3,SB>	;CLOBBER NO REGISTERS
	MOV	CN.LEN(R0),R2		;SET UP LENGTH FOR GETEXN
	ASSERT	NE			;BETTER BE A MESSAGE!
	MOV	R0,R3			;CONSTRUCT A POINTER
	ADD	#CN.NCT,R3		; TO THE NCL MESSAGE IN R3
	JSR	PC,GETEXN		;GET THE FLAGS BYTE
	BIT	#7,R0			;SEE IF IT'S A DATA MESSAGE
	BNE	10$			;ANY NCL CONTROL MSG CAN BE TOSSED.
	JSR	PC,GETEXN		;SKIP DNA.
	JSR	PC,GETEXN		;GET SOURCE
	JSR	PC,FNDSCB		; AND LOOKUP HIS NODE BLOCK
	BEQ	10$			;IF HE'S DEAD, THEN TOSS THE MSG
	BIT	#SBF.SQ,@SB		;IF HE IS NOT A SEQUENTIAL,
	BEQ	10$			; THEN HE CAN RESEND THE MESSAGE
	SEC				;OTHERWISE WE MUST HOLD MSG FOR ACK
	BR	20$			;GIVE ERROR RETURN

10$:	CLC				;SAY IT'S OK TO DELETE THE MSG
20$:	RESTORE	<SB,R3,R2,R1,R0>	;UN CLOBBER THE REGISTERS
	RTS	PC			; AND RETURN
.SBTTL	STATION CONTROL BLOCKS

.IF NE FTDL10!FT.DTE
TENSCB:	.WORD	0	;POINTER TO THE TEN'S SCB.
			; IF ZERO, THEN PORT NOT ENABLED, OR DTE
			; NOT IN PRIMARY PROTOCOL.
.ENDC

OURSCB:			;OUR STATION CONTROL BLOCK
;MACRO TO DEFINE OUR NODE NAME
.MACRO	OURSNM	ARG
	.=OURSCB+SB.SNM
	ZCHR=1
	EASCII	SNMSIZ,ARG
.ENDM	OURSNM
ZCHR=0
.IF NDF DFNAME
	.IIF NE FT.D75, OURSNM	<DC75NP>
	.IIF NE FT.D80, OURSNM	<DN80>
	.IIF NE FT.D81, OURSNM	<DN81>
	.IIF NE FT.D82, OURSNM	<DN82>
	.IIF NE FT.D85, OURSNM	<DN85>
	.IIF NE FT.87S, OURSNM	<DN87S>
	.IIF NE FT.D87, OURSNM	<DN87>
	.IIF NE FT.D20, OURSNM	<DN20>
	.IIF NE FT.200, OURSNM	<DN200>
	.IIF EQ ZCHR, OURSNM	<...>
.IFF
	NODE	OURSNM
.ENDC;.IF NDF DFNAME

;SOFTWARE ID
.MACRO	OURSID	CODE,VERSN,EDIT
	.=OURSCB+SB.SID
	ZCHR=1
	EASCII	SIDSIZ,<'CODE V'VERSN(EDIT)>
.ENDM	OURSID

	ZCHR=0
	.IIF NE FT.D75,	OURSID DC75NP,\VDAS85,\EDIT
	.IIF NE FT.D80,	OURSID DN80,\VDAS85,\EDIT
	.IIF NE FT.D81,	OURSID DN81,\VDAS85,\EDIT
	.IIF NE FT.D82,	OURSID DN82,\VDAS85,\EDIT
	.IIF NE FT.D85,	OURSID DN85,\VDAS85,\EDIT
	.IIF NE FT.D87,	OURSID DN87,\VDAS85,\EDIT
	.IIF NE FT.87S,	OURSID DN87S,\VDAS85,\EDIT
	.IIF NE FT.D20, OURSID DN20,\VDAS85,\EDIT
	.IIF NE FT.D22, OURSID DN22,\VDAS85,\EDIT
	.IIF NE FT.200, OURSID DN200,\VDAS85,\EDIT
	.IIF EQ ZCHR,	OURSID DNXX,\VDAS85,\EDIT

;INSERT SOFTWARE DATE
	SWDATE
	.=OURSCB+SB.NNM
	.WORD	OURNNM
	.=OURSCB+SB.SIZ
FIRSCB=.
.MACRO	X	N
	SCB'N:	.BLKB	SB.SIZ
.ENDM	X
Z=0		;FIRST REMOTE STATION BLOCK
.REPT	SCBMAX
	X	\Z
	Z=Z+1
.ENDR
SB.LIM=.					;END OF SCB'S