Trailing-Edge
-
PDP-10 Archives
-
BB-F492Z-DD_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