Trailing-Edge
-
PDP-10 Archives
-
BB-X140B-BB_1986
-
10,7/703anf/dnnsp3.p11
There are 3 other files named dnnsp3.p11 in the archive. Click here to see a list.
.SBTTL DECNET COMPATIBLE PORT FOR NSP 18 NOV 81
.IF NE,FT.DCP
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1977, 1978,1979,1980,1981,1984 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
VRNSP3=013 ;FILE EDIT NUMBER
.REPT 0
NOTES ON READING THIS MODULE
REGISTER USAGE
R0 ABOUT THE ONLY REGISTER THAT IS TRULY USED AS A TEMPORARY. A THIRD OF THE
CODE TRIES TO LOAD THIS WITH THE RIGHT VALUES, ANOTHER THIRD STORES IT.
R1 EXCEPT WHEN THE CODE NEEDS TWO TEMPORARIES, THIS USUALLY POINTS TO THE
LEB FOR THE LINK WE ARE HANDLING.
R2,R3 THESE POINT TO THE MESSAGE WE ARE DECODING. THE STANDARD NCL ROUTINES
GETBYT, GETEXN, ETC. ARE HOW WE LOOK AT EACH FIELD.
R4,R5 ONLY RARELY DO THESE POINT TO THE STATION AND LINE BLOCKS (SB AND J).
MOST OF THE TIME THEY POINT TO THE MESSAGE THE CODE IS GENERATING.
FIELDS ARE ADDED VIA ANALOGUES OF SIMILAR NCL ROUTINES (NSPPBY, NSPPEX
INSTEAD OF PUTBYT, PUTEXN).
IMPORTANT LOCATIONS
THESE MUST BE SETUP AS SOON AS POSSIBLE. DUE TO THE DEARTH OF REGISTERS, SEVERAL
VARIABLES ARE USED TO KEEP TRACK OF IMPORTANT DATA.
NSPLEB THIS POINTS TO THE CURRENT LEB. THE LEB SEARCH ROUTINES SET IT
UP SO IT'S ALMOST ALWAYS AVAILABLE.
NSPSB THIS IS THE ADDRESS OF THE NCL SCB RELATED TO THE LEB. (NOTE: IT COULD
JUST AS EASILY BE ANOTHER NSP SCB, HOWEVER ALL THE COMMENTS WILL REFER
TO IT AS AN NCL NODE.)
NSPLB THIS IS THE ADDRESS OF THE LINK BLOCK ASSOCIATED WITH THE NSP SIDE OF
THE LEB.
DNA,SNA THESE ARE USUALLY WHAT ONE WOULD EXPECT. THEY HARDLY EVER HAVE TO BE
REFERENCED.
NSPLMG THIS IS THE ADDRESS OF THE FIRST CHUNK OF THE CURRENT NCL MESSAGE,
BE IT FOR READING TO CREATING. ONCE MESSAGES ARE DECODED COMPLETELY,
THEY MUST BE PASSED TO NCLODN TO BE FREED.
NSPPMG SAME AS NSPLMG, BUT FOR NSP MESSAGES. SEVERAL PLACES IN THE CODE USE
THE "L" SUFFIX TO DENOTE INVOLVEMENT WITH NCP AND "P" FOR INVOLVEMENT
WITH NSP.
.ENDR
.IIF LT SNMSIZ-6,.PRINT SNMSIZ; MUST BE GEQ 6 FOR NSP V3.0
;MACRO TO USE TO ABORT A RECEIVED NSP MESSAGE
.MACRO NSPIBD
JSR PC,NSPIB0
.ENDM
;MACRO TO ABORT PROCESSING OF A NCL MESSAGE
.MACRO NSPOBD
JSR PC,NSPOB0
.ENDM
;MACRO TO DEFER PROCESSING OF A NCL MESSAGE UNTIL THERE IS ROOM
.MACRO NSPODF
JMP NSPOD0
.ENDM
CN.SEG =CN.SCB ;WHERE WE KEEP NSP SEGMENT NUMBER
NSPTIM =10. ;SECONDS BEFORE WE RETRANSMIT NUMBERED MESSAGES
.SBTTL DCP LINK ENTRY DEFS
BLOCK LE
X STS ; STATUS FOR THIS LINK
LES.DC=B4 ;HAVE TO SEND DC
LES.DV=B5 ; CONNECTION IS FOR A DEVICE, NOT TASK
LES.DS=B6 ;CONNECTION IS BEING BROKEN
LES.LA=B7 ;HAVE TO SEND LS/INT ACK
LES.LN=B8 ;HAVE TO SEND LS/INT NAK
LES.DA=B9 ;HAVE TO SEND DATA ACK
LES.DN=B10 ;HAVE TO SEND DATA NAK
LES.LS=B11 ;HAVE TO SEND LS TO REQUEST AN INTERRUPT MSG
LES.DR=B12 ;HAVE TO SEND AN EXTRA DATA REQUEST
LES.MD=B13 ;THIS IS 1 IF WE ARE INT THE MIDDLE OF A DIALOG MSG
LES.MR=B14 ;THIS IS 1 IF OTHER SIDE IS DOING MESSAGE REQUESTING
LES.NR=B15 ;THIS IS 1 IF OTHER SIDE IS DOING NO REQUESTING AT ALL
X LNK ; LINK TO NEXT LEB FOR THIS NODE
X SCB ; POINTER TO SCB FOR THIS NODE
X NCL ;LINK ADDRESS NCL IS USING
X DCP ;LINK ADDRESS THAT NCL AND NSP THINK IS THE DESTINATION
X NSP ;LINK ADDRESS NSP IS USING
X DPN ;DESTINATION DEVICE THAT NCL IS ASKING ABOUT
X LIL ;LAST INPUT LS/INT MESSAGE
X LID ;LAST INPUT DATA MESSAGE
X LOL ;LAST OUTPUT INT/LS MESSAGE
X LOD ;LAST OUTPUT DATA MESSAGE
X OQL ;LIST HEADER OF OUTPUT BUT NOT ACKNOWLEDGED LS/INT MSGS
X OQD ;SAME, BUT FOR DATA MESSAGES
X BUF ; BUFFER FOR THIS LINK
X IIK ; LAST INPUT INTERUPT ACKED
X IDK ; LAST INPUT DATA ACKED
X ODK ; LAST OUTPUT DATA ACKED
X ODS ; LAST OUTPUT DATA SENT
XX STT ;CURRENT LINK STATE:
LES.ID =0 ;IDLE HARDLY A STATE, BUT WHY NOT?
LES.LI =2 ;NCL IS TRYING TO INIT A LOGICAL LINK
LES.PI =4 ;NSP IS TRYING TI INIT A LOGICAL LINK
LES.RN =6 ;LINK SETUP, DATA MESSAGES SHOULD BE FLYING
LES.DS =10 ;EITHER SIDE IS TRYING TO DISCONNECT
XX RSN ;REASON TO SEND TO NSP FOR DISCONNECT
XX MDR ; MAXX NUMBER OF DATA REQUESTS FOR THIS LINK
XX ODR ; OUTSTANDING DATA REQUESTS FOR THIS LINK
XX TIM ;LOGICAL LINK TIMER
X SIZ,0 ; SIZE OF LEB
.SBTTL DATA BASE FOR LINKS
.MACRO NSP3,A,B,NOD
.IRP Q,<B>
COUNT Q
.ENDR
.ENDM
.MACRO COUNT,TYPE,NUM
QQQ=QQQ+NUM
.ENDM
QQQ=0
NSPLST
;LEBS ARE ALLOCATED BELOW HERE
LEBMGC: .BLKB LE.SIZ ;SPECIAL LEB TO USE WHEN ALL OUT OF THE REST
.MACRO LEBX,A
.EVEN
LEB'A: .=.+LE.DCP
.WORD A
.=LEB'A+LE.SIZ
.ENDM
QQN=1 ;START LEBS AT 1 SINCE LINK ADDR 0 IS ILLEGAL
.REPT QQQ ; BUILD ALL THE LEB'S
LEBX \QQN
QQN=QQN+1
.ENDR
LEBEND:
;NOW DEFINE SYMBOLS USED TO LET US INDEX INTO THE LEBS. LE.DCP, THE INTERNAL
;LINK ADDRESS, HAS THE LEB NUMBER IN THE LOW BITS AND AN INCREMENTING
;NUMBER IN THE HIGH BITS. TOGETHER THEY FORM A LINK ADDRESS LEGAL TO
;BOTH NCL AND NSP. LED.OF IS A MASK THAT EXTRACTS THE LEB NUMBER,
;LED.IN IS THE INCREMENT TO AFFECT THE HIGH BITS.
LED.IN =100000 ;THERE MAY BE A FASTER WAY OF DOING THIS...
.REPT 20
.IIF EQ LED.IN&QQQ, LED.IN=LED.IN/2
.ENDR
LED.IN =-LED.IN*2 ;MAKE LED.IN BE FIRST BIT NOT USED IN LEB NUMBER
LED.OF =LED.IN-1 ;THEREFORE THE NUMBER MASK IS ONE LESS THAN LED.OF
.SBTTL FLAGS, MASKS, AND VALUES FOR NSP MESSAGES
;RTHDR FIELD (OPTIONAL)
;EXTEN BIT MASK
NM.RTF =2 ;BIT THAT SAYS ROUTING HEADER
NM.RFMT=100 ;SET INDICATES ASCII ROUTE HEADER FORM
NM.EFMT=60 ;PROTOCOL TYPE
NM.EF3=0 ; PROTOCOL IS NSP 3.0
NM.MPRI=4 ;VALUE FOR A PRIORITY 1 MESSAGE
NM.ROU =NM.RTF!NM.RFMT!NM.EF3!<NM.MPRI*1> ;WE BUILD ASCII ROUTING HEADERS
;MSGFLG FIELD (REQUIRED)
;1 BYTE BIT MASK
;FOR TYPE 0
NM.BOM =40 ;BEGIN OF MESSAGE SEGMENT
NM.EOM =100 ;END OF MESSAGE SEGMENT
NM.IDT =60 ;INTERRUPT DATA
NM.LS =20 ;LINK SERVICES
;LSFLAGS FIELD:
NM.MAK =60 ;MASK FOR MSGFLG FIELD
NM.STP =1 ;STOP DATA FLOW
NM.FCI =14 ;MASK FOR FCVAL INTERPRETATION FIELD
NM.IRC =4 ;INTERRUPT REQUEST COUNT
;FOR TYPE 1
NM.LSA =24 ;LS/INT ACK
NM.NAK =B12 ;BIT IN ACKNUM THAT SAYS NAK
NM.DTA =4 ;DATA ACK
;FOR TYPE 2
NM.CI =30 ;CONNECT INIT
NM.CC =50 ;CONNECT CONFIRM
;SERVICES FIELD:
NM.MSA =20 ;MESSAGE ACKNOWLEDGEMENT REQUESTED IF SET
NM.LNK =1 ;LOGICAL LINK (NOT SINGLE MESSAGE)
NM.SRQ =4 ;SEGMENT REQUEST COUNTS
NM.DI =70 ;DISCONNECT INITIATE
NM.DC =110 ;DISCONNECT CONFIRM
NM.NOE =0 ;NO ERROR
NM.RAF =1 ;RESOURCE ALLOCATION FAILURE
NM.NDE =2 ;DESTINATION NODE DOES NOT EXIST
NM.NSD =3 ;NODE SHUTTING DOWN
NM.PDE =4 ;PROCESS DOESN'T EXIST
NM.IPN =5 ;INVALID PROCESS NAME
NM.UEC =7 ;UNSPECIFIED ERROR CONDITION
NM.TCN =32. ;TOO MANY CONNECTIONS TO NODE
NM.TCP =33. ;TOO MANY CONNECTIONS TO PROCESS
NM.SER =35. ;CI, CC SERVICES MISMATCH
NM.NPT =39. ;NO PATH TO DESTINATION
NM.NXL =41. ;DSTADDR LOGICAL LINK DOES NOT EXIST
NM.CNF =42. ;CONFIRMATION OF DI
NM.STRT =130 ;START UP MESSAGE
;SUB TYPES
NM.INI =1 ;INIT MESSAGE
NM.VER =2 ;VERIFY
;FUNCTIONS FIELD
NM.RNT =4 ;ROUTE INTERCEPT
NM.LNT =2 ;LINK INTERCEPT
NM.RTE =1 ;ROUTE THROUGH
;MISC
NM.NMM =4095. ;MASK FOR MSG NUMBER FIELDS
.SBTTL STATE MACHINE DESCRIPTION
.REPT 0
A STATE MACHINE IS USE TO CONTROL LOGICAL LINK USAGE. SEVERAL STATES AND
STATE CONDITIONS DESCRIBED IN NSP HAVE NO MEANING HERE AND NCL IS SIMPLE
ENOUGH TO NOT COMPLICATE MATTERS TOO FAR. THEREFORE, WE CAN GET AWAY WITH
ONLY 5 STATES. ABOUT HALF OF THE STATE CONDITIONS CAN BE HANDLED WITHOUT
RESORTING TO A STATE DISPATCH TABLE.
STATE DESCRIPTIONS:
IDLE WHILE THIS HAS A STATE CODE, A LEB IS REALLY IDLE IF IT IS NOT
ALLOCATED. IN FACT, A COMMON WAY TO ENTER THE IDLE STATE IN THE
CODE IS TO LEAVE LE.STT ALONE BUT CALL NSPFLB.
LI A LEB IS IN THIS STATE AFTER PROCESSING A NCL CONNECT INIT MESSAGE
AND BEFORE THE REPLY COMES BACK FROM NSP.
PI THIS IS THE CONVERSE OF THE LI STATE AND IS IN EFFECT WHEN NSP HAS
SENT A CI MESSAGE.
RUN AS ONE MIGHT EXPECT, THIS STATE IS WHEN THE LINK IS FULLY CONNECTED
AND DATA, LS/INT, ACK, AND DRQ MESSAGES ARE EXPECTED IN EITHER
DIRECTION.
DSC THIS STATE IS ENTERED WHENEVER EITHER SIDE INITIATES A LINK DISCONNECT.
WHILE IT TAKES A BIT OF HAND WAVING, WE DON'T NEED SEPARATE STATES
FOR BOTH NCL AND NSP INITIATED DISCONNECTS.
BELOW IS THE STATE TRANSITION TABLE USED FOR LOGICAL LINKS. STATE EVENTS ARE
THE VERTICAL AXIS, THE ACTUAL STATES ARE THE X AXIS. EACH ENTRY IS OF THE FORM
"NEW STATE"/"NSP RESPONSE"/"NCL RESPONSE" ALTHOUGH SPECIAL HANDLING NOT
INDICATED WILL TAKE PLACE IF ERRORS OCCUR.
IDLE LI PI RUN DSC
NSP RCVD:
CI PI/ACK/CONN CAN'T HAPPEN PI/ACK/CONN RUN// DSC//
CC IDLE/DC/ RUN/ACK/CONN IDLE/DC/ RUN// DSC//
DI IDLE/DC IDLE/DC/DISC IDLE/DC/ DSC//DISC DSC//DISC
DC IDLE// IDLE//DISC IDLE// IDLE//DISC IDLE//DISC
ACK IDLE/DC/ LI// PI// RUN// DSC//
NAK IDLE/DC/ LI// PI// RUN// DSC//
DATA, LS IDLE/DC/ LI// PI// RUN/ACK/DATA,DRQ DSC//
NCL RCVD:
CONN INIT LI/CI/ LI/CI/ CAN'T HAPPEN IDLE/DC/DISC IDLE//DISC
CONN CONF IDLE//DISC IDLE//DISC RUN/CC/ IDLE/DC/DISC IDLE/DC/DISC
DISC IDLE// IDLE// DSC/DI/ DSC/DI/ IDLE/DC/
NODE OFFLINE IDLE// IDLE/DC/ IDLE/DC/ IDLE/DC/ IDLE/DC/
STATE TIMEOUT IDLE// IDLE/DC/DISC IDLE/DC/DISC RUN// IDLE/DC/DISC
THERE ARE NO SUBROUTINES DEDICATED TO CONTROLLING LINK STATES, RATHER ALL
CODE CHANGING STATES WILL EITHER MOVE THE NEW STATE DIRECTLY INTO THE LEB
OR CALL NSPFLB TO FREE THE LEB WHICH IMPLIES ENTERING THE IDLE STATE.
.ENDR
.SBTTL INITIALIZATION
;THE ONLY THING WE HAVE TO DO FOR INITIALIZATION IS MARK ALL THE LEBS AS
;FREE AND THE EASIEST WAY TO DO THAT IS TO CLEAR OUT ALL OF THEM. SOME OF
;THE LBLK LOCATIONS WE USED ALSO HAVE TO BE ZEROED, BUT THE LBLK INITIALIZATION
;CODE WILL DO THAT.
NSPINI: MOV #LEBMGC,R1 ;THE MAGIC LEB IS THE FIRST LEB
10$: JSR PC,NSPZLB ;CLEAR LEB
ADD #LE.SIZ,R1 ;POINT TO NEXT
CMP R1,#LEBEND ;DONE WHOLE AREA?
BLO 10$ ;NO, DO REST
CLR NSPOQL ;INITIALLY NOTHING TO PROCESS
RTS PC
.SBTTL LOOP LEVEL CODE
;ROUTINE CALLED AT LOOP LEVEL TO CHECK FOR NSP ACTIVITY
;THIS EXTRACTS A LINE BLOCK FROM THE CIRCULAR QUEUE OF ACTIVE ONES AND
;ATTEMPTS TO SERVICE ALL REQUESTED FUNCTIONS. ALL FUNCTIONS ARE RELATED TO
;SENDING MESSAGES SO IF MEMORY IS NOT AVAILABLE THE LINE BLOCK IS REQUEUED
;AND NSPCHK EXITS SINCE THERE IS NO POINT IN GOING ANY FURTHER.
NSPCHK: JSR PC,NSPOUX ;TRANSLATE ANY NCL MESSAGES IN NSPOQL
CMP NS.PTR,NS.TKR ;ANYTHING IN QUEUE?
BEQ 90$ ;NO, RETURN
CMP NS.TKR,#<NS.QUE+NS.SIZ> ;TAKER PAST END?
BLO 10$ ;NO, SKIP NEXT INSTRUCTION
MOV #NS.QUE,NS.TKR ;POINT IT BACK TO BEGINNING
10$: MOV @NS.TKR,J ;GET LINE BLOCK ADDRESS
ADD #2,NS.TKR ;ADVANCE TAKER
BIC #LBS.NQ,LB.NSS(J) ;CLEAR QUEUED BIT
SAVE <SB> ;SAVE POINTER TO SCB
MOV LB.SCB(J),SB ;GET OUR SCB
MOV J,NSPLB ;MOST OF THE CODE EXPECTS THIS HERE
MOV LB.LEB(J),R1 ;GET POINTER TO LINK TABLE
20$: MOV R1,NSPLEB ;SAVE LEB WE ARE LOOKING AT NOW
BEQ 80$ ;STOP WHEN LIST RUNS OUT
;LOOP THROUGH LINKS
MOV SB,DNA ;FIRST SET UP WHERE WE'RE GOING
MOV LE.SCB(R1),SNA ;AND WHERE WE'RE COMING FROM
MOV #NSPCBT,R0 ;GET LIST OF BITS TO LOOK AT
;..
;..
30$: BIT @R0,@R1 ;NEED TO DO THIS FUNCTION?
BEQ 50$ ;NO, LOOK AT NEXT
SAVE <R1,R0> ;WE NEED THESE LATER
JSR PC,NSPBMG ;WE WILL ALWAYS NEED A NSP MESSAGE
BCS 40$ ;NO MEMORY - DEFER UNTIL THERE IS SOME
MOV @SP,R0 ;RECOVER TABLE INDEX
JSR PC,@NSPCDS-NSPCBT(R0) ; CALL FUNCTION ROUTINE TO SEND MESSAGE
40$: RESTORE <R0,R1>
BCS 70$ ;CAN'T DO IT NOW, REQUE LEB, SKIP REST
BIC @R0,@R1 ;DONE WITH THAT ONE
50$: TST (R0)+ ;STEP TO NEXT
BNE 30$ ;MAY BE MORE TO DO, CHECK
MOV LE.LNK(R1),-(SP) ;STEP TO NEXT LEB
TSTB LE.STT(R1) ;DID OLD LEB BECOME IDLE?
BNE 60$ ;NO, KEEP GOING
JSR PC,NSPFLB ;IT DID, REMOVE IT FROM FUTURE CONSIDERATION
60$: MOV (SP)+,R1 ;RECOVER NEXT LEB
BR 20$ ;LOOP
70$: JSR PC,NSPQ ;CAN'T ALLOCATE A MESSAGE, REDO THIS LEB LATER
80$: RESTOR <SB> ;DONE WITH LINE
90$: RTS PC
NSPCBT: .WORD LES.DR,LES.LN,LES.LA,LES.DN,LES.DA,LES.LS,LES.DC,0
NSPCDS: .WORD NSPCDR,NSPCLN,NSPCLA,NSPCDN,NSPCDA,NSPCLS,NSPCDC
;ROUTINES TO DO VARIOUS LOW LEVEL FUNCTIONS TO NSP NODES
;CALL WITH R4, R5 POINTING TO A NSP MESSAGE READY TO BE FILLED
;FUNCTIONS:
;NSPCLS - SEND A LS MESSAGE TO REQUEST A NEW INTERRUPT MESSAGE. WILL BE CALLED
;NSPCLS - CALLED AFTER THE RECEIPT OF AN INTERRUPT MESSAGE FROM NSP. THIS WILL
; REQUEST ANOTHER, KEEPING WITH THE GOAL OF HAVING ONE OUTSTANDING REQUEST
; AT ALL TIMES
;NSPCDC - PART OF THE LINK ERROR MECHANISM AND ANYTHING ELSE THAT NEEDS TO
; SEND A DC TO NSP. THIS SENDS A DC AND PUTS THE LINK INTO IDLE STATE
; WHICH WILL CAUSE NSPCHK TO FREE THE LEB
;NSPCLN - THIS SENDS A LS/INT NAK BASED ON THE HIGHEST MESSAGE NUMBER WE'VE PROCESSED.
; SINCE NAKS ALSO ACK MESSAGES, THE ACK REQUEST BIT IS CLEARED.
;NSPCLA - SENDS A LS/INT ACK
;NSPCDN,NSPCLA - ANALOGS TO THE ABOVE BUT FOR THE DATA STREAM
.ENABL LSB
NSPCLS: JSR PC,NSPBLS ;START A LS MESSAGE UP TO SEGNUM
MOV #NM.IRC,R0 ;INTERRUPT REQUEST COUNT
JSR PC,NSPPEX ;PUT LSFLAGS
MOV #1,R0 ;REQUEST ONE MESSAGE AT A TIME
JSR PC,NSPPBY ;PUT FCVAL
BR 90$ ;SEND IT
NSPCDC: CLRB LE.STT(R1) ;MAKE LEB IDLE (NSPCHK WILL FREE)
TST LE.NSP(R1) ;DO WE HAVE A NSP LINK ADDRESS?
BNE 5$ ;YES, GO AHEAD AND SEND IT
MOV NSPPMG,R0 ;DISCARD MESSAGE WE WERE BUILDING
JSR PC,FRECKS
BR 95$ ;AND DON'T SEND IT
5$: MOV #NM.DC,R0 ;TO SEND A DISCONNECT CONFIRM
JSR PC,NSPRML ;BUILD MOST OF IT
MOVB LE.RSN(R1),R0 ;GET REASON FOR DISCONNECT
BR 80$ ;SEND MESSAGE
NSPCLN: MOV LE.LIL(R1),-(SP) ;SEND THIS IN ACKNUM FIELD
BIS #B12,@SP ;MAKE IT A NAK
BIC #LES.LA,@R1 ;NO NEED TO SEND ACK NOW
BR 10$ ;GET ACK CODE AND SEND
NSPCLA: MOV LE.LIL(R1),-(SP) ;SEND THIS IN ACKNUM FIELD
10$: MOV #NM.LSA,-(SP) ;MSGFLG FOR LS/INT ACK
BR 30$ ;BUILD AND TRANSMIT MESSAGE
NSPCDN: MOV LE.LID(R1),-(SP) ;ACK UP TO THIS FAR FOR DATA MESSAGES
BIS #B12,@SP ;BUT NAK ANY OTHERS
BIC #LES.DA,@R1 ;AND DON'T BOTHER TO SEND USELESS ACK
BR 20$ ;GET MSGFLG AND TRANSMIT
NSPCDA: MOV LE.LID(R1),-(SP) ;ACK UP TO HERE
20$: MOV #NM.DTA,-(SP) ;MSGFLG FOR DATA ACK
30$: MOV (SP)+,R0 ;GET MSGFLG FOR WHAT EVER ACK WE'RE BUILDING
JSR PC,NSPMDS ;BUILD UP TO SRCADDR
MOV (SP)+,R0 ;RECOVER ACK VALUE
BIS #B15,R0 ;MAKE IT INTO ACKNUM
80$: JSR PC,NSPO2B ;PUT ACKNUM (OR DC REASON)
90$: JSR PC,NSPSNS ;SEND IT TO NSP
95$: CLC ;TELL NSPCHK WE DID IT
RTS PC
.DSABL LSB
;ANOTHER NSPCHK ROUTINE, THIS ONE TO SEND A FREE DATA REQUEST TO THE
;-10 FOR MESSAGES WE PASSED TO THE THE -11 THAT WILL NOT RESULT IN NEW REQUESTS
;FROM LINK SERVICES MESSAGES.
NSPCDR: JSR PC,NSPPTP ;REVERSE MESSAGE DIRECTION, SEND TO NCL
MOV #NCLDRQ,R1 ;WE NEED A DATA REQUEST MESSAGE
JSR PC,NSPBNC ;START NCL HEADER
BCS 10$ ;NO MEMORY AVAILABLE, TRY LATER
MOV NSPLEB,R1 ;NEED THIS AGAIN
MOV LE.NCL(R1),R0 ;RETRIEVE DLA TO REQUEST DATA FROM
JSR PC,NSPPEX ;PUT DLA
MOVB LE.ODR(R1),R0 ;RETRIEVE DATA REQUESTS THAT HAVE PILED UP
CLRB LE.ODR(R1) ;NO MORE
JSR PC,NSPPEX ;PUT COUNT
JSR PC,NSPSNC ;SEND REQUEST
JSR PC,NSPPTP ;RIGHT DIRECTION
CLC ;MARK SUCCESS
10$: RTS PC ;CHEAT - NSPCHK WILL NOT NEED SNA AND DNA IF WE RETURN CS
.SBTTL HOOKS TO REST OF DN8X
;HERE WHEN DDCMP ENTERS THE RUNNING STATE ON A LINE MARKED AS A NSP LINE.
;THIS ROUTINE ALLOCATES A SCB TO THE LINE IN PREPARATION FOR RECEIVING THE
;NODE INIT MESSAGE
NSPRSS: ASSERT EQ LB.SCB(J) ;I THINK THIS WILL NEVER DIE....
JSR PC,MAKSCB ;TRY TO ALLOCATE A SCB
BCS 10$ ;NONE AVAILABLE, TAKE DOWN LINE
MOV #SBF.IU!SF.NSP,@SB ;MARK SCB IN USE AS A NSP NODE
MOV SB,LB.SCB(J) ;SAVE ASSOCIATION BETWEEN SCB AND LBLK
MOV J,SB.LBA(SB) ;BOTH WAYS
RTS PC ;RETURN
10$: JMP L.DOWN ;TAKE DOWN LINE SO A RESTART WILL OCCUR
;HERE WHEN DDCMP ON A LINE TERMINATES. THE ONLY SIGNIFICANT
;ACTION TAKEN IS TO FREE LEBS IN USE AT THE TIME.
NSPDWN: CLR LB.NSS(J) ;CLEAR STATUS OUT
MOV LB.LEB(J),-(SP) ;SAVE ADDRESS OF FIRST LEB TO FREE
CLR LB.LEB(J) ;NO ACTIVE LEBS NOW
10$: MOV (SP)+,R1 ;GET ADDRESS OF NEXT LEB TO FREE
BEQ 20$ ;STOP WHEN DONE
MOV LE.LNK(R1),-(SP) ;SAVE NEXT TO FREE
JSR PC,NSPZLB ;FREE CURRENT ONE
BR 10$ ;DO REST
20$: RTS PC ;ALL GONE
;CALLED WHENEVER A NCL NODE GOES OFFLINE. SINCE NSP HAS NO PROVISION TO
;TELL OTHER NODES THAT NODES HAVE GONE OFFLINE, WE HAVE TO INVENT DC MESSAGES
;FOR EACH OF THE LEBS THAT ARE INVOLVED. WE HAVE NO DATABASE TO DO THIS
;EASILY, SO WE HAVE TO SEARCH ALL LBLKS LOOKING FOR NSP LINES AND THEN ALL
;LEBS LOOKING FOR CONNECTIONS TO THE DOWN NODE. NOTE THAT AN ALTERNATE
;IMPLEMENTATION WOULD HAVE BEEN TO DO THIS WHEN WE RECEIVE THE NEIGHBORS
;MESSAGE FROM OUR NODE, BUT THAT HAS THE RACE CONDITION WHERE A NODE COULD
;HAVE GONE DOWN AND COME BACK UP BEFORE THE NEIGHBORS MESSAGE IS SENT.
;THIS IMPLEMENTS ROUTING INTERCEPT.
NSPDWL: JSR PC,NSPALL ;CALL THE REST OF US FOR ALL NSP LOGICAL LINKS
CMP SB,LE.SCB(R1) ;IS THIS LINK TO THE NODE THAT JUST WENT DOWN?
BNE 10$ ;NO, LEAVE IT ALONE
MOV #NM.NPT,R0 ;SEND A NO PATH MESSAGE TO NSP SIDE
JSR PC,NSPQDC ;QUEUE IT
10$: RTS PC
;ROUTINE TO HANDLE LINK TIMING, I. E. MESSAGE RETRANSMISSION.
;THIS IS DONE ONLY FOR NUMBERED MESSAGES SINCE DOING THINGS LIKE LOOKING FOR
;REPLYS TO CONNECTS AND WHATNOT AREN'T ALL THAT EASY. WHENEVER ANY
;NUMBERED MESSAGE IS SENT, BE IT DATA OR LS/INT, THE LINK TIMER IS SET
;TO ITS FULL VALUE. ONCE A SECOND ALL NON-ZERO TIMERS
;ARE DECREMENTED AND IF THEY REACH ZERO THEN ALL MESSAGES IN THE OUTPUT BUT
;NOT ACKNOWLEDGED QUEUES ARE RETRANSMITTED.
;THE TIMER IS NEVER CLEARED. WHEN BOTH OUTPUT
;QUEUES EMPTY AND CONTROL COMES HERE, THE CALLS TO NSPRT? SEND NOTHING
;SO THE TIMERS STAY AT 0.
;THIS APPROACH DIFFERS MARKEDLY FROM WHAT THE NSP SPEC DESCRIBES
;UNDER LINK INTERCEPT BUT NO SIGNIFICANT LOSS OF PERFORMANCE SHOULD OCCUR.
NSPSEC: JSR PC,NSPALL ;CALL REST OF ROUTINE FOR ALL NSP LOGICAL LINKS
TSTB LE.TIM(R1) ;TIMIMG THIS LINK?
BEQ 10$ ;NO, IGNORE IT
DECB LE.TIM(R1) ;TIME IT OUT
BNE 10$ ;STILL RUNNING, IGNORE IT
JSR PC,NSPRTL ;EXPIRED! RETRANSMIT LS/INT MESSAGES
JSR PC,NSPRTD ;AND DATA MESSAGES. TRANSMIT WILL SETUP LE.TIM
10$: RTS PC
;CALLED FROM DDCMP AFTER IT HAS SUCCESSFULLY TRANSMITTED A NSP MESSAGE.
;UNNUMBERED MESSAGES ARE FREED IMMEDIATELY, NUMBERED ONES ARE QUEUED UNTIL
;ACKNOWLEDGED FROM THE OTHER END. THIS ROUTINE IS RESPONSIBLE FOR
;KEEPING THE MESSAGE QUEUES ORDERED, BOTH TO MAKE THE ACKNOWLEDGEMENT CODE
;SIMPLER AND TO LET RETRANSMITTED MESSAGES GO OUT IN ORDER.
;INCIDENTALLY, EVEN THOUGH MESSAGES GO OUT ON ONLY ONE LINK, IT IS NOT HARD
;TO GET MESSAGES HERE OUT OF ORDER. SUPPOSE MSG 1 IS QUEUED AND MSG 2 IS IN
;DDCMP. FOR SOME REASON (RECEIPT OF A NAK IS THE MOST LIKELY), MSG 1 GETS
;RETRANSMITTED. IF NOTHING ELSE HAPPENS FOR A WHILE, DDCMP WILL RETURN FIRST
;MSG 2 THEN MSG 1 AND THE QUEUE WILL BE DISORDERED.
NSPODN: MOV R0,NSPPMG ;REMEMBER WHICH MESSAGE
.IIF NE FTDCPT,JSR PC,NSPOTP ;PRINT MSG IF DEBUGGING
TST CN.SEG(R0) ;IS THIS AN IMPORTANT MESSAGE?
BEQ 99$ ;NO, JUST FREE IT
MOV SP,NSPSP ;IN CASE NSPIMS CALLS NSPIBD
CLR SNA ;NO IDEA WHERE IT CAME FROM YET
MOV J,NSPLB ;MOST OF THE CODE REFERENCES THIS
JSR PC,NSPIMS ;READ UP TO MSGFLG
MOV SNA,NSPSB ;IN CASE WE FOUND OUT WHO IS THE NCL NODE
JSR PC,NSPI2B ;SKIP DSTADDR
JSR PC,NSPI2B ;GET SRCADDR (US)
JSR PC,NSPSLB ;CONVERT THAT TO LEB
CMPB #LES.RN,LE.STT(R1) ;IS LINK RUNNING?
BNE 30$ ;NO, NO POINT IN SAVING MESSAGE
CLRB LE.TIM(R1) ;CLEAR TIMER IN CASE THE OTHER NSP IS LEVEL 1
BIT #LBS.L1,LB.NSS(J) ;IS IT LEVEL 1?
BEQ 5$ ;YES, SPEC. DOESN'T LET US TIME OUT MESSAGES
MOVB #NSPTIM,LE.TIM(R1) ;SET TIMER TO RETRANSMIT MESSAGE
5$: ADD #LE.OQD-CN.MLK,R1 ;MAKE A FAKE LIST HEADER TO QUEUED MESSAGES
MOV NSPPMG,R0 ;HAVE TO GO BACK AND CHECK TO SEE IF MSG IS LS/INT
TST CN.SEG(R0) ;WHICH IS SIGN BIT HERE
BPL 10$ ;DATA MESSAGE, ALL SET
ADD #LE.OQL-LE.OQD,R1 ;CONVERT POINTER TO LS/INT QUEUE
10$: MOV CN.MLK(R1),R2 ;GET NEXT MESSAGE IN QUEUE
BEQ 20$ ;REACHED END, PUT MESSAGE HERE
MOV CN.SEG(R0),R3 ;GET THIS MESSAGE'S NUMBER
SUB CN.SEG(R2),R3 ;SEE WHICH WAY THEY'RE SEPARATED
ASSERT NE ;BETTER NOT BE FOR A MESSAGE IN THE QUEUE!
BIT #<NM.NMM+1>/2,R3 ;BIT WILL BE ON IF WE'VE FOUND A MESSAGE
BNE 20$ ; BEYOND THE ONE R0 REFERENCES
MOV R2,R1 ;NOT YET, POINT TO MESSAGE WE JUST CHECKED
BR 10$ ;AND SEE IF WE CAN INSERT AFTER IT
20$: MOV R0,CN.MLK(R1) ;PUT NEW MESSAGE AT LIST'S END
CLR CN.MLK(R0) ;MAKE SURE NEW MESSAGE IS END
RTS PC
30$: TSTB LE.STT(R1) ;IDLE LINK?
BNE 40$ ;NO, KEEP LEB AROUND
JSR PC,NSPFLB ;MESSAGE MUST BE FROM DISCONNECTED LINK!
40$: MOV NSPPMG,R0 ;RECOVER ADDRESS OF MESSAGE
99$: JMP FRECKS ;FREE IT
.SBTTL NSP PROCESSOR
; CALLED BY: DDCINP IN DNDCMP
;
; STACK LOOKS LIKE:
; 0 DDCMP RETURN ADDR
;
; CALLED WITH:
; J LINE BLOCK
; R0 ADDR OF FIRST CHUNK
;
; DESTROYED: R1, R2, R3, CARRY
;
;THIS ROUTINE LOOKS AT EVERY NSP MESSAGE RECEIVED AND SETS UP ALL DEFAULTS,
;PROCESSES THE COUNT AND RTHDR FIELDS IF THEY EXIST AND DISPATCHES TO THE
;PROCESSING ROUTINE TO HANDLE EACH MSGFLG TYPE.
NSPINP:
.IIF NE FTDCPT,JSR PC,NSPITP ;PRINT MESSAGE IF DEBUGGING
MOV R0,NSPPMG ;SAVE STARTING CHUNK OF MESSAGE
MOV J,NSPLB ; SAVE POINTER TO LINE BLOCK
CLR DNA ;SAY WE DON'T KNOW NCL ASSOCIATION YET
CLR NSPLEB ;INDICATE NO LEB YET (NSPIER NEEDS TO KNOW)
MOV LB.SCB(J),SNA ;SETUP DEFAULT SOURCE NODE
MOV SP,NSPSP ;SAVE SP FOR MESSAGE FORMAT ERROR RECOVERY
JSR PC,NSPIMS ;READ UP TO MSGFLG
MOV DNA,NSPSB ;SETUP NCL ASSOCIATION IF NSPIRT WAS CALLED
MOV R0,R1 ;MSGFLG - POSITION SUBTYPE FIELD
ASR R0 ;TO DO A WORD DISPATCH
BIC #^C16,R0 ;THESE BITS SHOULD BE OFF ALREADY
ASL R1 ;SHIFT TYPE FIELD FOR WORD DISPATCH
BIC #^C6,R1 ;JUST THE TYPE
JSR PC,@40$(R1) ;PROCESS MESSSAGE
RTS PC ;DONE
40$: .WORD NSPIDA,NSPIAC,NSPICM,NSPIB0
NSPICM: JMP @10$(R0) ; DISPATCH ON TYPE
10$: .WORD NSPIFL ;NOPS ARE EASY, JUST DISCARD
.WORD NSPICI
.WORD NSPICC
.WORD NSPIDI
.WORD NSPIDC
.WORD NSPSTR
.WORD NSPIB0 ;UNKNOWN MSG TYPES
.WORD NSPIB0
;ROUTINE TO READ NSP FROM BEGINNING TO MSGFLG
NSPIMS: MOV CN.LEN(R0),R2 ;GET LENGTH
MOV R0,R3 ;POINT TO FIRST CHUNK
ADD #CN.NCT,R3 ;NOW MAKE THAT FIRST DATA
10$: JSR PC,GETEXN ;GET FIRST FIELD
ASR R0 ;IS THIS A COUNT FIELD?
BCC 20$ ;NO, LOOK AT NEXT BIT
NSPIBD ;WE DON'T SUPPORT UNBLOCKING
20$: ASR R0 ;IS THIS A RTHDR?
BCC 30$ ;NO, MUST BE MSGFLG
JSR PC,NSPIRT ;FIGURE OUT SNA AND DNA
BR 10$ ;NEXT FIELD
30$: RTS PC
;ROUTINE CALLED BY NSPIBD MACRO TO LOG ERROR AND DISCARD MESSAGE
;NSPIB0- THIS MAY BE CALLED BY ANY ROUTINE CALLED FROM NSPINP NO MATTER
; HOW MUCH DATA HAS BEEN PUT ON THE STACK. IT WILL LOG THE ERROR AND DISCARD
; THE MESSAGE. THE PREFERED CALLING MECHANISM IS VIA THE NSPIBD MACRO.
;NSPIFL- CALL (USUALLY VIA JMP) WHEN WHEN DONE WITH A RECEIVED NSP MESSAGE
; TO RETURN IT TO THE FREELIST. DO NOT CALL THIS IF THE MESSAGE HAS BEEN
; REUSED FOR A NCL TRANSLATION OR NSP REPLY UNLESS NSPPMG IS ZEROED.
NSPIB0: TWIDDLE (SP)+ ;SAVE PC OF CALLER
TWIDDLE
.IIF NE FTDCPT,JSR PC,NSPBTP ;NOTE WE DISLIKED IT
MOV NSPSP,SP ;RESTORE STACK TO NSPINP LEVEL
NSPIFL: MOV NSPPMG,R0 ;CHANGE THIS TO POSSIBLY
JMP FRECKS ;SAVE THE LAST BAD MESSAGE
;ROUTINE TO DECODE NSP ROUTING HEADER. IF EITHER NODE ISN'T KNOWN, THE
;MESSAGE IS IGNORED. WHAT REALLY SHOULD HAPPEN IS FOR A DC MESSAGE TO BE
;GENERATED AND RETURNED TO THE SENDER BUT THAT MEANS PARSING MOST OF THE
;MESSAGE ANYWAY TO DETERMINE THE SOURCE AND DESTINATION ADDRESSES.
;IT IS A PUZZLEMENT.
NSPIRT: BIT #NM.RFMT/4,R0 ;ASCII ROUTING HEADERS?
BEQ 10$ ;BINARY - CAN'T HANDLE!
BIT #NM.EFMT/4,R0 ;WHICH VERSION OF ROUTING FORMAT?
BNE 10$ ;ONLY 0 IS DEFINED
MOV #NSPDNA,R0 ;POINT TO DESTINATION STRING
JSR PC,NSPIR1 ;FIND DESTINATION NODE
MOV SB,DNA ;SAVE IT
MOV R0,DNAOFF ;AND OFFSET IF IT IS SEQUENTIAL
MOV #NSPSNA,R0 ;DO SAME WITH SOURCE NODE
JSR PC,NSPIR1 ;FIND SOURCE NODE
MOV SB,SNA
MOV R0,SNAOFF
RTS PC ;DONE
10$: NSPIBD
NSPIR1: MOV R0,-(SP) ;SAVE START OF DEST. STRING
JSR PC,NSPIIM ;GET NAME OF DEST OR SOURCE NODE
.WORD SNMSIZ ;NO MORE THAN THIS MANY CHARACTERS
MOV #OURSCB,SB ;SEARCH SCBS LOOKING FOR NODE
10$: MOV @SP,R0 ;GET START OF NAME FROM MESSAGE
MOV SB,R1 ;CALCULATE ADDR OF NAME OF THIS NODE
ADD #SB.SNM,R1
JSR PC,NSPCEA ;COMPARE THE TWO EXTENSIBLE STRINGS
BCC 30$ ;A MATCH, GREAT.
SB.ADV 10$ ;TRY NEXT SCB
20$: NSPIBD ;NO MATCH, DISCARD MESSAGE
30$: TST (SP)+ ;NO NEED FOR THIS NOW
CLR R0 ;R0 WILL RETURN WINDOW ADDRESS WITHIN SCB
BIT #SBF.SQ,@SB ;SEQUENTIAL NODE?
BEQ 50$ ;NO, ALL SET
MOV #SQNTAB,R1 ;SEARCH SQNTAB FOR THIS NODE
40$: CMP SB,@R1 ;THIS ONE?
BEQ 50$ ;YES, RETURN
ADD #SQNSIZ,R0 ;STEP TO NEXT WINDOW
TST (R1)+ ;AND NEXT SEQUENTIAL NODE
BEQ 20$ ;RAN OUT!
BR 40$ ;TRY NEXT
50$:
NSPRTS: RTS PC
.SBTTL NSPSTR NSP START UP MESSAGE
; CALLED BY: NSPICM IN DNNSP3
;
; STACK LOOKS LIKE:
; 0 POINTER TO FIRST CHUNK OF MESSAGE
; 2 DDCMP RETURN ADDRESS
NSPSTR: JSR PC,GETBYT ;GET START TYPE
CMP R0,#NM.INI ;ONLY ONE WE KNOW NOW
BEQ 10$ ;OKAY, HANDLE IT
NSPIBD ;DISCARD MESSAGE
10$: BIT #LBS.IC,LB.NSS(J) ;ARE WE IN CONTACT ?
BNE 30$ ;YES, RESTART DDCMP TO CLEANUP EVERYTHING
JSR PC,GETEXN ;GET NODE ADDR
BIC #^C77,R0 ;LIMIT TO 6 BITS (ALA REST OF OUR NET)
BNE 20$ ;STILL SOMETHING LEFT, USE IT
MOVB LB.VNN(J),R0 ;MUST BE AN END NODE, GET USER SUPPLIED NUMBER
20$: MOV LB.SCB(J),SB ;POINT TO SCB
MOV R0,SB.NNM(SB) ;OK TO SAVE NNM NOW, FNDSCB WON'T SEE IT
JSR PC,FNDSCB ;SEE IF ANOTHER NODE BY SAME NAME
BEQ 40$ ;NO, OKAY TO LET THIS ONE IN
30$: JSR PC,L.DOWN ;REALLY SHOULD BE MORE CLEVER
NSPIBD ;DISCARD MESSAGE
40$: MOV LB.SCB(J),SB ;RESTORE THIS
CLRB SB.DAT(SB) ;NODE INIT WON'T GIVE US THIS
MOV SB,R0 ;GET ADDR OF SCB FOR NSP NODE
ADD #SB.SNM,R0 ;POINT TO NAME AREA
JSR PC,NSPIIM ;COPY IMAGE DATA
.WORD SNMSIZ ;MAXIMUM AMOUNT TO COPY
JSR PC,GETEXN ;DISCARD FUNCTIONS
JSR PC,GETEXN ;GET REQUESTS
BIT #NM.RNT!NM.LNT,R0 ;IS OTHER END A LEVEL 1 IMPLEMENTATION?
BNE 45$ ;NO, NOTHING SPECIAL TO DO
BIS #LBS.L1,LB.NSS(J) ;MARK IT (ONLY USE IS TO NOT TIME OUT MSGS)
45$: MOV #6,R1 ;DISCARD A LOT OF THE MESSAGE
50$: JSR PC,NSPI2B ; NAMELY MSG LENGTHS, MAX LINKS, AND VERSIONS
SOB R1,50$ ;(WE REALLY SHOULD HANDLE MSG LENGTHS...)
MOV LB.SCB(J),R0 ;GET ADDR OF SCB AGAIN
ADD #SB.SID,R0 ;NOW READ IN STATION ID
JSR PC,NSPIIM
.WORD SIDSIZ ;LIMIT OF HOW MANY BYTES TO COPY
;..
;..
JSR PC,NSPBM1 ;USE THAT MESSAGE TO MAKE A RETURN NODE INIT
MOV #NM.STRT,R0 ;MESSAGE TYPE 2, START UP SUB TYPE
JSR PC,NSPPEX ;PUT MSGFLG
MOV #NM.INI,R0 ;INIT START UP
JSR PC,NSPPEX
MOV #OURNNM,R0 ;OUR NODE NUMBER
JSR PC,NSPPEX ;TELL HIM WHO WE ARE
MOV #OURSCB+SB.SNM,R1 ;GET ADDR OF OUR NAME
JSR PC,NSPOIM ;COPY TO MESSAGE
MOV #NM.RNT!NM.LNT!NM.RTE,R0;PROVIDE ALL BUT UNBLOCKING
JSR PC,NSPPEX
CLR R0
JSR PC,NSPPEX ;AND ASK FOR NOTHING
MOV #MSGMAX,R0 ;MAX MESSAGE SIZE
JSR PC,NSPO2B ;PUT IT OUT
JSR PC,NSPO2B ;AND REPEAT FOR NSP MESSAGES
MOV #4095.,R0 ;SAY WE SUPPORT THIS MANY TO DEFEAT POSSIBLE MASKING
; AND LINK TABLE INDEXING BY THE OTHER NSP
70$: JSR PC,NSPO2B ;PUT INTO MESSAGE
MOV #2,R2 ;ONCE FOR COMM VER AND ONCE FOR ROUTE VER
80$: MOV #3+<400*1>,R0 ;3,1
JSR PC,NSPO2B ;STORE FIRST 2 BYTES
CLR R0 ;I FORGET WHAT THE THIRD BYTE IS
JSR PC,NSPPBY ;BUT HAVE TO STORE IT ANYWAY
SOB R2,80$ ;BACK TO DO ROUT VER
MOV #OURSCB+SB.SID,R1 ;GET ADDR OF OUR NODE IDENT
JSR PC,NSPOIM ;COPY IT TO MESSAGE
MOV NSPLB,J ;MESSAGE COMPLETE, GET LBLK BACK
MOV NSPPMG,R0 ;GET FIRST CHUNK BACK
MOV R4,CN.LEN(R0) ;SET LENGTH FOR DDCMP OUTPUT
MOV LB.SCB(J),SB ;POINT TO SCB AGAIN
JSR PC,DDQNSP ;SHIP IT OUT !
MOV #LBS.IC,LB.NSS(J);SET LINE BLOCK IN CONTACT
JSR PC,ADDSQN ;ADD SEQUENTIAL NODE
BIS #SF.NSP,@SB ;GOT TURNED OFF, IT DID!
JSR PC,ROUTE ;DO ROUTING
JSR PC,SNDNGH ;SEND NEIGHBORS 'BOUT US
RTS PC
.SBTTL NSPICI AND NSPICC NSP CONNECT MESSAGES
;ROUTINE TO TRANSLATE NSP CONNECT MESSAGES INTO NCL CONNECT MESSAGES.
;IF A CONNECT INITIATE, THERE IS A CHANCE THAT NSPSLP WILL RETURN THE MAGIC
;LEB. IF SO, WE RETURN A DC.
NSPICI: JSR PC,NSPI2B ;GET DESTADDR
TST R0 ;ON AN INIT DEST MUST BE 0
BNE 60$ ;IT ISN'T, IGNORE MESSAGE
JSR PC,NSPI2B ;GET SRCADDR
MOV LB.LEB(J),R1 ;SEE IF LINK ADDRESS ALREADY IN USE
10$: BEQ 20$ ;NO LEBS, CAN'T IN USE, OKAY TO ALLOCATE ONE
CMP R0,LE.NSP(R1) ;SAME?
BEQ 30$ ;YES, THIS SHOULD BE AN EXTRA CI
MOV LE.LNK(R1),R1 ;POINT TO NEXT LEB
BR 10$ ;AND TRY IT
20$: MOV R0,-(SP) ;PROTECT SRCADDR
JSR PC,NSPALB ;ALLOCATE A LEB
MOV (SP)+,LE.NSP(R1) ;REMEMBER NSP ADDRESS
BCS 40$ ;CAN'T USE IT IF WE GOT THE MAGIC LEB
30$: MOV R1,NSPLEB ;IN CASE WE FOUND ON ON THE LIST
TST NSPSB ;DO WE KNOW DESTINATION YET?
BEQ 50$ ;NO, BE UPSET
MOVB LE.STT(R1),R0 ;GET STATE WE'RE IN
JSR PC,@NSPCIX(R0) ;AND CALL APPROPRIATE ROUTINE
RTS PC
40$: JSR PC,NSPI2B ;GET SRCADDR
MOV R0,LE.NSP(R1) ;NEED FOR NSPRML
JSR PC,NSPPTP ;REVERSE MESSAGE FLOW DIRECTION SO WE CAN REPLY
JSR PC,NSPBM1 ;USE THIS MESSAGE FOR REPLY
MOV #NM.DC,R0 ;START A DC MESSAGE
JSR PC,NSPRML ;BUILD MOST OF MESSAGE
MOV #NM.TCN,R0 ;SAY TOO MANY CONNECTS TO DEST. (AT LEAST TO US!)
JSR PC,NSPO2B ;FINISH DC MESSAGE
JMP NSPSNS ;SEND IT
50$: JSR PC,NSPFLB ;WE DON'T KNOW DEST, CAN'T KNOW SOURCE, FREE LEB
60$: NSPIBD ;(ACTUALLY, PROBABLY SHOULD RETURN DC)
NSPCIX: .WORD NSPCI0 ;A NEW LINK IS BEING SETUP
.WORD NSPERP ;WE DON'T HAVE A NCL LINK, WE SHOULD NEVER GET HERE
.WORD NSPCI0 ;SEND ANOTHER CONNECT FOR THIS DSTADDR
.WORD NSPIFL ;ASSUME NSP TIMED OUT AFTER NCL CONNECTED
.WORD NSPIFL ;ASSUME SAME AFTER NCL DISCONNECTED
;ROUTINE TO TRANSLATE CONNECT CONFIRM MESSAGES
NSPICC: JSR PC,NSPI2B ;GET DESTADDR
JSR PC,NSPSLB ;FIND LEB FOR IT
MOVB LE.STT(R1),R0 ;GET CURRENT STATE
JSR PC,@NSPCCX(R0) ;CALL PROCESSOR
RTS PC
NSPCCX: .WORD NSPERP ;SHOULDN'T GET FREE CONNECT CONFIRMS
.WORD NSPCC0 ;NSP LIKED THE CI WE PASSED ON!
.WORD NSPERP ;WE JUST GOT A CI FROM NSP!!??
.WORD NSPIFL ;ASSUME A LATE ARRIVAL
.WORD NSPIFL ;ASSUME A LATE ARRIVAL
.ENABL LSB
NSPCC0: JSR PC,NSPI2B ;GET SRCADDR
MOV R0,LE.NSP(R1) ;NEW INFO, SAVE IT
MOVB #LES.RN,LE.STT(R1) ;ENTER RUN STATE
BR 20$ ;JOIN COMMON CODE
NSPCI0: MOVB #LES.PI,LE.STT(R1) ;ENTER PI (NSP INITTING LINK) STATE
20$: MOV #NCLCON,R1 ;START BUILDING AN NCL MESSAGE
JSR PC,NSPBNC ;BUILD HEADER
BCS 99$ ;THROW IT AWAY FOR NOW
MOV NSPLEB,R1 ;RECOVER LEB ADDRESS
MOV LE.NCL(R1),R0 ;SINCE NCL IS DESTINATION, THIS MUST BE DLA
JSR PC,NSPPEX ;PUT DLA (MAY BE ZERO)
MOV LE.DCP(R1),R0 ;USE INTERNAL LINK FOR SOURCE
JSR PC,NSPPEX ;PUT SLA
JSR PC,GETEXN ;GET SERVICES
BIT #NM.MSA,R0 ;REQUESTING MESSAGE ACKNOWLEDGEMENT?
BNE NSPRCN ;DISALLOW
SAVE <R0>
BIC #^C14,R0 ;ONLY FCOPT FIELD
ASR R0 ;MAKE INTO WORD INDEX
BIS NSPFCB(R0),@R1 ;REMEMBER FLOW CONTROL TYPE
RESTORE <R0>
BIC #^C3,R0 ;ISOLATE LTYPE FIELD
DEC R0 ;SET Z BIT IF LOGICAL LINK TYPE
BNE NSPRCN ;NOT LOGICAL LINK, CAN'T HANDLE
JSR PC,GETEXN ;GET INFO AND DISCARD
JSR PC,NSPI2B ;GET SEGSIZE
MOV R0,-(SP) ;SAVE IT SINCE MML IS A WAYS AWAY
TST LE.NCL(R1) ;MAKING A CONNECT CONFIRM?
BNE 30$ ;YES, FUDGE DPN AND SPN
JSR PC,NSPIC1 ;GET DSTNAME, PUT DPN
JSR PC,NSPIC1 ;GET SRCNAME, PUT SPN
BR 40$ ;CONTINUE WITH MML
;HERE ON A CONNECT CONFIRM, FAKE THE DPN AND SPN FIELD IN THE NCL MSG
30$: MOV #OBJTSK+<0*400>,R0 ;NSP DIDN'T SEND US ALL THE DATA WE NEED TO
; PROPERLY BUILD THE DPN AND SPN FIELDS.
; HOWEVER, SINCE NETSER IGNORES THEM ON A CONNECT
; CONFIRM, PUT IN NULL FIELDS AND EVERYTHING
; SHOULD WORK!
JSR PC,NSPO2B ;PUT DPN
BIT #LES.DV,LE.STS(R1);IF IT WAS A DEVICE CONNECT
BEQ 35$ ;NO - CONTINUE
MOV LE.DPN(R1),R0 ;DEVICE CONNECT - GET CONNECT TYPE
35$:
JSR PC,NSPO2B ;PUT SPN
JSR PC,NSPCNR ;SEE IF A NO SEGMENT REQUEST CONNECTION HAS BEEN SET UP
40$: MOV @SP,R0 ;RECOVER SEGSIZE
JSR PC,NSPPEX ;PUT MML
MOV #B2,R0 ;SAY DATA IS IN IMAGE MODE
JSR PC,NSPPEX ;PUT DCM
MOV (SP)+,R0 ;USE SEGSIZE IN RLN FIELD TOO
JSR PC,NSPPEX ;PUT RLN
CLR R0 ;TASKS HAVE NO ATTRIBUTES
JSR PC,NSPPEX ;PUT DVT
JSR PC,NSPSNC ;SEND IT
99$: JMP NSPIFL ;DISCARD NSP MESSAGE
.DSABL LSB
NSPRCN: MOVB #NM.SER,LE.RSN(R1) ;SAY WHY WE'RE SENDING A DC
MOV NSPLMG,R0 ;HAVE TO FREE BOTH NCL AND NSP MESSAGES
JSR PC,FRECKS ;DISCARD NCL
JMP NSPERP ;FREE NSP MESSAGE AND DISCONNECT LINK
NSPFCB: .WORD LES.NR ;NO FLOW CONTROL
.WORD 0 ;SEGMENT REQUEST COUNTS
.WORD LES.MR ;MESSAGE REQUEST COUNTS
.WORD 0 ;UNDEFINED, DON'T WORRY ABOUT IT
;ROUTINE CALLED BY NSPICI AND NSPICN TO COPY NAME FIELDS
NSPIC1: JSR PC,GETBYT ;GET FORMAT OF NAME FIELD
MOV R0,R1 ;SAVE FOR AFTER OBJTYPE TEST
JSR PC,GETBYT ;GET OBJTYPE
TST R0 ;0 IS GENERAL TASK
BNE 5$ ;DISALLOW ALL OTHERS
MOV #OBJTSK,R0 ;ALWAYS CONNECT TO A TSK
JSR PC,NSPPBY ;PUT OBJTYPE
DEC R1 ;ONLY ALLOW 1 AND 2
BEQ 10$ ;1: (OBJTYPE, DESCRP)
DEC R1
BEQ 40$ ;2: (OBJTYPE, GRPCODE, USRCODE, DESCRPT)
5$: MOV NSPLEB,R1 ;POINT TO LEB AGAIN
MOVB #NM.IPN,LE.RSN(R1) ;TO SAY INVALID DESTINATION
JSR PC,NSPERL ;SEND A DC BACK
NSPIBD
10$: JSR PC,GETBYT ;GET LENGTH OF DESCRP
MOV R0,R1 ;COPY TO SAFE AC
BEQ 70$ ;NOTHING! JUST STORE 0
20$: JSR PC,GETBYT ;GET A BYTE OF IT
CMP R1,#1 ;LAST CHARACTER?
BEQ 30$ ;YES, DON'T MAKE EXTENSIBLE
BIS #200,R0 ;CONVERT TO EXTENSIBLE
30$: JSR PC,NSPPBY ;PUT IN NCL MESSAGE
SOB R1,20$ ;DO REST
RTS PC ;DONE WITH NAME FIELD FOR FORMAT 1
40$: JSR PC,NSPI2B ;GET GRPCODE
MOV R0,-(SP) ;SAVE FOR AFTER DESCRPT
JSR PC,NSPI2B ;GET USRCODE
MOV R0,-(SP) ;SAVE THAT TOO
JSR PC,GETBYT ;GET LENGTH OF DESCRPT
MOV R0,R1 ;COPY TO SAFE AC
BEQ 60$ ;NOTHING! JUST STORE PPN
50$: JSR PC,GETBYT ;GET NEXT BYTE OF NAME
BIS #200,R0 ;MAKE ALL BYTES EXTENSIBLE
JSR PC,NSPPBY ;PUT INTO DPN OR SPN
SOB R1,50$ ;LOOP OVER REST OF NAME
60$: MOV #'[!200,R0 ;FOR START OF PPN FIELD
MOV 2(SP),R1 ;RECOVER GRPCODE
JSR PC,NSPIC2 ;MAKE "[10"
MOV #',!200,R0 ;SEPARATE WITH COMMA
MOV (SP)+,R1 ;RECOVER USRCODE
JSR PC,NSPIC2 ;PUT INTO MESSAGE
TST (SP)+ ;DISCARD GRPCODE
MOV #'],R0 ;TERMINATE PPN AND EXTENSIBLE STRING
70$: JMP NSPPBY
;ROUTINE CALLED ONLY BY NSPIC1 TO STORE PART OF A PPN
NSPIC2: JSR PC,NSPPBY ;PUT OPEN BRACKET OR COMMA ON NAME
10$: MOV R1,R0 ;PUT NUMBER TO BE CONVERTED IN R0
BIC #^C7,R0 ;ISOLATE LAST DIGIT
CLC ;TO ENSURE WE ONLY GET VISIBLE BITS
ROR R1 ;REMOVE LAST DIGIT FROM R1
ASR R1
ASR R1
BEQ 20$ ;REACHED FIRST DIGIT, PUT DATA IN MESSAGE
MOV R0,-(SP) ;PROTECT DIGIT TO BE PRINTED
JSR PC,10$ ;LOOP OVER NUMBER
MOV (SP)+,R0 ;RECOVER DIGIT
20$: BIS #'0!200,R0 ;ASCIIZE AND EXTENSIBLIZE IT
JMP NSPPBY ;STUFF IN MESSAGE
.SBTTL NSPIDI AND NSPIDC NSP DISCONNECT MESSAGES
.ENABL LSB
NSPIDI: MOV #NSPDIX,-(SP) ;SAVE WHICH DISPATCH TABLE TO USE
BR 10$ ;JOIN COMMON CODE
NSPIDC: MOV #NSPDCX,-(SP) ;LIKEWISE
10$: JSR PC,NSPI2B ;GET DSTADDR
JSR PC,NSPSLB ;FIND LEB FOR LINK
JSR PC,NSPI2B ;GET SRCADDR FIELD
MOV R0,LE.NSP(R1) ;IF THIS HAPPENS IN LI STATE, THEN WE HAVE TO USE
; THIS LINK ADDRESS WHEN WE MAKE THE DC
; WE SEND BACK
MOVB LE.STT(R1),R0 ;GET CURRENT STATE
ADD (SP)+,R0 ;CONVERT TO ADDRESS OF SERVICE ROUTINE
JMP @(R0)+ ;DO WHATEVER IS APPROPRIATE
.DSABL LSB
NSPDIX: .WORD NSPERP ;SAY WE CAN'T DO IT AND FORGET IT
.WORD NSPID2 ;CAN'T CREATE LINK, FORWARD A DISC, REPLY WITH DC
.WORD NSPERP ;WE SHOULDN'T GET DI RIGHT AFTER CI!
.WORD NSPID1 ;NSP WANTS TO BRING DOWN LINK. START IT
.WORD NSPID2 ;BOTH ENDS SHUTTING DOWN SIMULTANEOUSLY?
NSPDCX: .WORD NSPFLB ;NOTHING TO DO BUT IGNORE IT
.WORD NSPID0 ;CONVERT DC INTO DISC
.WORD NSPFLB ;DC AFTER CI!?
.WORD NSPID0 ;ABORTING
.WORD NSPID0 ;NSP DC AFTER NCL DISC
NSPID2: MOV #NM.CNF,R0 ;RETURN NORMAL CONFIRMATION
JSR PC,NSPQDC ; FROM LOW LEVEL
BR NSPID1 ;DON'T CALL NSPFLB, LOW LEVEL WILL DO SO
NSPID0: MOV #NSPFLB,-(SP) ;TO CLEANUP AFTER OURSELVES
TST LE.NCL(R1) ;IF THIS IS A CONFIRM FROM A
BNE NSPID1 ; CONNECT REJECT, THEN NCL-DLA IS ZERO
RTS PC ; AND WE ARE DONE WITH THIS LINK FOREVER
NSPID1: MOVB #LES.DS,LE.STT(R1) ;ENTER DSC STATE
MOV NSPPMG,R0 ;RECOVER START OF NSP MESSAGE
MOV #NCLDIS,R1 ;TO BUILD DISCONNECT MESSAGE
JSR PC,NSPBN2 ;USE IT FOR NCL MESSAGE
MOV NSPLEB,R1 ;RECOVER LEB
MOV LE.NCL(R1),R0 ;RECOVER DSTADDR
JSR PC,NSPPEX ;PUT DLA
MOV LE.DCP(R1),R0 ;USE INTERNAL ADDRESS FOR SRCADDR
JSR PC,NSPPEX ;PUT SLA
JSR PC,NSPI2B ;GET REASON CODE
MOV #NSPRST,R1 ;PREPARE TO SEARCH REASON PAIR TABLE
10$: CMPB R0,(R1)+ ;MATCH HERE?
BEQ 20$ ;YES, USE NEXT BYTE
TSTB (R1)+ ;AT END OF TABLE?
BGE 10$ ;YES
20$: MOVB @R1,R0 ;USE NEXT BYTE AS REASON
JSR PC,NSPPEX ;PUT RSN
JMP NSPSNC ;SEND IT
NSPRST: .BYTE NM.NOE,0 ;TABLE THAT MATCHES NSP REASONS WITH NCL
.BYTE NM.RAF,2 ; ENTRIES NOT IN TABLE WILL RESULT IN "NO SUCH
.BYTE NM.NSD,2 ; PROCESS" CODES
.BYTE NM.IPN,1
.BYTE NM.TCN,2
.BYTE NM.TCP,3
.BYTE -1,-1,4
.EVEN
.SBTTL NSP ACKNOWLEDGEMENT MESSAGE PROCESSING
;ALL THIS HAS TO DO IS GET THE ACKNUM FIELD AND PASS IT TO THE RIGHT
;MESSAGE FREEING ROUTINE
NSPIAC: BIT #14,R0 ;MAKE SURE HIGH 2 BITS OF SUBTYPE FIELD ARE 0
BNE 20$ ;THEY AREN'T, DISCARD MESSAGE
MOV 30$(R0),-(SP) ;PUT ACTION ROUTINE ON STACK TO HANDLE MESSAGE
JSR PC,NSPI2B ;GET DSTADDR
JSR PC,NSPSLB ;SEARCH FOR NCL LINK
JSR PC,NSPI2B ;NSP ADDR BETTER MATCH
CMP R0,LE.NSP(R1) ;COMPARE
BNE 10$
JSR PC,NSPI2B ;GET ACKNUM
JSR PC,@(SP)+ ;CALL FREEING ROUTINE
JMP NSPIFL ;DISCARD THIS ONE TOO
10$: TSTB LE.STT(R1) ;IDLE?
BNE 20$ ;NO, SOMEONE ELSE WILL CLEANUP (?)
MOV R0,LE.NSP(R1) ;NEED THIS FOR DC
MOV #NM.NXL,R0 ;RETURN A DC FOR THIS TYPE
JSR PC,NSPQDC
20$: NSPIBD
30$: .WORD NSPFRD,NSPFRL
.SBTTL NSP NUMBERED MESSAGE PROCESSING
;CALLED TO PROCESS NSP TYPE 0 MESSAGES (DATA, INTERRUPT, LS). THE DISPATCH DONE
;IS BASED ON THE SUBTYPE BITS, INCLUDING BOM AND EOM. IF THE MESSAGE IS DATA,
;THE STATE OF THE EOM BIT IS USED TO DETERMINE WHICH OF THE DAP DATA TYPES WILL
;BE USED TO START THE MESSAGE.
NSPIDA: MOV 30$(R0),-(SP) ;SAVE ROUTINE TO CALL TO PROCESS MESSAGE
JSR PC,NSPI2B ;GET DSTADDR
JSR PC,NSPSLB ;FIND LEB FOR IT
CMPB LE.STT(R1),#LES.RN ;ONLY ACCEPT WHEN RUNNING
BNE 10$ ;BUT DON'T GET TOO UPSET
JSR PC,NSPI2B ;GET SRCADDR
CMP R0,LE.NSP(R1) ;PARANOIA
BNE 20$
RTS PC ;"RETURN" TO CALLER
10$: TSTB LE.STT(R1) ;IDLE?
BNE 20$ ;NO, OKAY TO IGNORE MESSAGE
JSR PC,NSPI2B ;GET SRCADDR
MOV R0,LE.NSP(R1) ;NEED FOR DC
MOV #NM.NXL,R0 ;SAY NON EXISTANT LINK
JSR PC,NSPQDC ;SEND IT SOON
20$: NSPIBD
30$: .WORD NSPDA0,NSPILS
.WORD NSPDA0,NSPIIN
.WORD NSPDA1,NSPIB0
.WORD NSPDA1,NSPIB0
.ENABL LSB
NSPDA0: MOVB #1,NSPDAP ;USE DATA WITHOUT EOR
BR 10$
NSPDA1: MOVB #2,NSPDAP ;OR USE DATA WITH EOR
10$: JSR PC,NSPI2B ;GET ACKNUM
TST R0 ;OR IS IT SEGNUM?
BPL 20$ ;IT IS
JSR PC,NSPFRD ;FREE ANY DATA MESSAGES IT ACKS
JSR PC,NSPI2B ;GET SEGNUM
20$: MOV #LE.LID,R1 ;CHECK TO SEE IF WELL SEQUENCED
JSR PC,NSPISC ;LET INPUT SEQUENCE CHECKER CHECK
BCS 30$ ;NOT THIS ONE!
MOV #B15,R1 ;TO SAY WE NEED A DATA MESSAGE
JSR PC,NSPICD ;COPY DATA INTO NCL MESSAGE AND SEND IT
BCS 30$ ;NO BUFFERS, NAK IT
JSR PC,NSPQDA ;REMIND OURSELVES TO SEND AN ACK
BR NSPINC ;INCREMENT HIGHEST MESSAGE NUMBER RECEIVED
30$: JSR PC,NSPQDN ;REQUEST A NAK EVEN THOUGH DDCMP WOULDN'T
NSPIBD ;THROW IT AWAY
.DSABL LSB
;HERE IF MESSAGE IS INTERRUPT. IT WILL BE TRANSLATED INTO A NCL INTERRUPT
;MESSAGE WITH THE DAP DATA WITH EOR MESSAGE TYPE.
NSPIIN: MOVB #2,NSPDAP ;ALWAYS USE DATA WITH END OF RECORD
JSR PC,NSPI2B ;GET ACKNUM
TST R0 ;OR IS IT SEGNUM?
BPL 10$ ;IT IS
JSR PC,NSPFRL ;FREE LS/INT MESSAGES MAYBE
JSR PC,NSPI2B ;GET SEGNUM
10$: MOV #LE.LIL,R1 ;READY TO CHECK THIS SIDE
JSR PC,NSPISC ;CHECK INPUT SEQUENCING
BCS 20$ ;OUT OF ORDER, SEND NAK
MOV #B15!NCFINT,R1 ;TO REQUEST INTERRUPT HEADER
JSR PC,NSPICD ;COPY DATA AND SEND TO NCL
BCS 20$ ;HAVE TO NAK IT
JSR PC,NSPQLA ;TO SEND LS/INT ACK SOMEDAY
JSR PC,NSPQLS ;ALSO SEND LS TO REQUEST ANOTHER INTERRUPT MESSAGE
BR NSPINC ;INCREMENT RECEIVED MESSAGE NUMBER AND DISCARD MSG
20$: JSR PC,NSPQLN ;REQUEST A NAK
NSPIBD ;CALL IT A BAD MESSAGE SO SOMEONE SEES IT
;ROUTINE TO PROCESS THE NSP LS MESSAGE. IF IT ASKS FOR SOME DATA MESSAGES,
;IT WILL TRANSLATE INTO A DATA REQUEST. PRESENTLY REQUESTS FOR INTERRUPT MESSAGES
;ARE IGNORED, IF NCL INTERRUPT MESSAGES ARRIVE, THEY WILL ALWAYS BE PASSED TO
;NSP.
NSPILS: JSR PC,NSPI2B ;GET ACKNUM
TST R0 ;SIGH, DO IT ALL AGAIN
BPL 10$ ;SEGNUM
JSR PC,NSPFRL ;FREE LS/INT MESSAGES
JSR PC,NSPI2B ;GET SEGNUM
10$: MOV #LE.LIL,R1 ;TO CHECK LS/INT SEQUENCING
JSR PC,NSPISC ;CHECK IT
BCS 30$ ;OUT OF ORDER
JSR PC,GETEXN ;GET LSFLAGS
BIT #NM.MAK!NM.STP,R0 ;DISALLOW MESSAGE ACK OR STOPPING DATA FLOW
BNE 40$ ;CALL IT A LINK ERROR IF IT HAPPENS
BIT #NM.IRC,R0 ;REQUESTING INTERRUPT MESSAGE?
BNE 20$ ;ALWAYS ALLOW THOSE
JSR PC,GETBYT ;GET FCVAL
TST R0
ASSERT PL ;CAN'T HANDLE NEGATIVE YET
BEQ 20$ ;AND IGNORE NO CHANGE
MOV R0,-(SP) ;SAVE VALUE
MOV #NCLDRQ,R1 ;ASK FOR DATA REQUEST HEADER
MOV NSPPMG,R0 ;REUSE NSP MESSAGE FOR NCL
JSR PC,NSPBN2 ;BUILD HEADER
MOV NSPLEB,R3 ;OKAY TO USE R3 HERE
MOV LE.NCL(R3),R0 ;GET DEST LINK ADDR
JSR PC,NSPPEX ;PUT DLA
MOV (SP)+,R0 ;RECOVER DATA REQUEST COUNT
JSR PC,NSPPEX ;PUT DRQ
JSR PC,NSPSNC ;SEND IT TO NCL
CLR NSPPMG ;THIS PREVENTS NSPINC FROM FREEING REUSED MESSAGE
20$: JSR PC,NSPQLA ;REQUEST TO SEND LS/INT ACK SOMETIME
BR NSPINC ;INCREMENT RECEIVED MESSAGE NUMBER
30$: JSR PC,NSPQLN ;HAVE TO NAK IT
NSPIBD ;NOTE WE COULDN'T PROCESS IT
40$: JSR PC,NSPERR ;DECLARE A LINK ERROR
NSPIBD
.SBTTL INPUT SEQUENCING
;ROUTINE TO ENFORCE MESSAGE SEQUENCING. EVEN THOUGH WE TALK ONLY TO END
;NODES, WE STILL HAVE TO DO MESSAGE SEQUENCING BECAUSE THERE ARE CASES (USUALLY
;NO MEMORY) WHERE WE HAVE TO DISCARD A MESSAGE AND SEND A NAK TO TRY IT AGAIN
;LATER. THIS ROUTINE ENFORCES MESSAGE ORDERING AND IS DESIGNED FOR AN
;ENVIRONMENT WHERE OUT OF ORDER MESSAGES ARE DISCARDED INSTEAD OF QUEUED.
;(AFTER ALL, WE COULDN'T PROCESS THE PREVIOUS MESSAGE OR SO BECAUSE WE WERE
;OUT OF MEMEORY). THIS ROUTINE NEITHER DISPOSES MESSAGES NOR INCREMENTS
;SEGMENT COUNTERS, SEE NSPINC FOR THAT.
;CALL:
; R0/ SEGNUM FIELD
; R1/ #LE.LID OR #LE.LIL (LAST INPUT MESSAGE PROCESSED)
; JSR PC,NSPISC
; CARRY SET IF OUT OF ORDER
NSPISC: ADD NSPLEB,R1 ;MAKE ADDRESS OF SEGMENT COUNTER
MOV R1,NSPLIX ;REMEMBER FOR NSPINC
MOV @R1,R1 ;GET LAST MESSAGE PROCESSED
INC R1 ;FIGURE WHAT THIS SHOULD BE
SUB R0,R1 ;IF RIGHT, THIS WILL BE ZERO
BIT #NM.NMM,R1 ;WELL, THESE BITS WILL BE
BEQ 10$ ;THEY ARE, RETURN CARRY CLEAR
SEC ;OUT OF ORDER, RETURN CARRY SET
10$: RTS PC
;HERE WHEN INPUT MESSAGE HAS BEEN SUCCESSFULLY PROCESSED. THIS WILL FINALLY
;INCREMENT THE MESSAGE COUNTER TO MAKE US LOOK FOR THE NEXT AND JUMP OFF
;TO NSPIFL TO DISCARD THE MESSAGE. (IF THE MESSAGE SPACE HAS BEEN REUSED,
;NSPPMG MAY BE ZEROED AND EVERYTHING WILL WORK, I. E. NOTHING WILL BE FREED.)
;CALL:
; NSPPMG/ MESSAGE TO FREE OR ZERO IF NONE
; JSR PC,NSPISC (TO SET NSPLIX)
; <PROCESS MESSAGE>
; JSR PC,NSPINC (IF MESSAGE SUCCESSFULLY PROCESSED)
NSPINC: INC @NSPLIX ;INCREMENT MESSAGE COUNTER
BIC #^CNM.NMM,@NSPLIX ;RESTRICT TO 12 BITS OR WHATEVER
JMP NSPIFL ;DISCARD MESSAGE
.SBTTL NSP TO NCL DATA COPY
;ROUTINE CALLED BY NSP DATA AND INTERRUPT PROCESSORS TO COPY DATA PORTION
;OF MESSAGES. THE RESULT WILL BE SENT TO NCL FOR ROUTING TO THE DESTINATION.
;CARRY IS SET ON RETURN IF SPACE FOR THE NCL MESSAGE IS NOT AVAILABLE
NSPICD: JSR PC,NSPBNC ;START A NCL MESSAGE
BCS 99$ ;NAK IT SOMETIME
MOV NSPLEB,R1 ;GET LEB AGAIN
MOV LE.NCL(R1),R0 ;RECOVER DSTADDR
JSR PC,NSPPEX ;PUT DLA
BIT #LES.DV,@R1 ;HAVE TO ADD DAP?
BNE 20$ ;NO, SHOULD ALREADY BE ON
MOV R2,R0 ;GET LENGTH
INC R0 ;AUGMENT FOR TYPE
JSR PC,NSPPEX ;STORE COUNT
MOVB NSPDAP,R0 ;GET DAP MSG TYPE
JSR PC,NSPPBY ;STORE TYPE
20$: TST R2 ;ANY MORE TO COPY?
BEQ 30$ ;NO, FINISH UP
JSR PC,GETBYT ;GET NEXT BYTE
JSR PC,NSPPBY ;PUT INTO MESSAGE
BR 20$ ;KEEP LOOKING FOR DATA
30$: JSR PC,NSPSDL ;SEND IT TO NCL
CLC ;TELL CALLER IT WORKED
99$: RTS PC
.SBTTL NCL MESSAGE PROCESSOR
;CALLED BY DDCMP WHEN NCL GIVES IT A MESSAGE TO SEND TO A NSP
;NODE. THIS ROUTINE PERFORMS DIFFERENT ACTIONS DEPENDING ON THE SORT
;OF MESSAGE RECEIVED. ONLY NUMBERED MESSAGES REACH HERE, UNNUMBERED
;ONES ARE PROCESSED BY THE SEQUENTIAL CODE IN NCL.
;NSPOUT QUEUES MESSAGES AS IT RECEIVES THEM. IT CANNOT PROCESS THEM IMMEDIATELY
;BECAUSE SEVERAL NCL VARIABLES MAY BE CHANGED (NOTABLY SNA, SNAOFF, ETC.)
;THE LIST USED HAS BOTH A LIST HEADER THAT POINTS TO THE FIRST MESSAGE
;QUEUED AND A CELL THAT POINTS TO THE LAST MESSAGE QUEUED SO MESSAGES MAY BE
;ADDED TO THE LIST WITHOUT SEARCHING IT.
;NSPOUX IS CALLED BY NSPCHK TO PROCESS ANY QUEUED NCL MESSAGES. IT SETS UP ALL
;VARIBALES FROM THE DATA IN THE NCL HEADER THEN CALLS NSPOU1 TO GET AND
;DISPATCH ON THE DLA FIELD. MESSAGE PROCESSING USUALLY REQUIRES AT LEAST A
;CHUNK OF MEMORY TO BUILD THE TRANSLATION OR REPLY. IF IT ISN'T AVAILABLE,
;THE MESSAGE IS REQUEUED IN HOPES OF MEMORY FREEING UP SOON.
;MESSAGE TYPE TRANSLATE REPLY MODIFY DATA BASE
;DATA *
;CONNECT * *
;DISCONNECT * *
;NEIGHBORS
;REQ CONFIG *
;CONFIG
;DATA REQ *
;STATION CTRL *
;CALL:
; R0/ ADDRESS OF NCL MESSAGE
; JSR PC,NSPOUT
; ... ;MESSAGE QUEUED FOR NSPOUX
; JSR PC,NSPOUX ;PROCESS QUEUED MESSAGES
NSPOUT:
.IF NE DEBUG
BITB #7,CN.NCT(R0) ;MAKE SURE WE WEREN'T PASSED AN UNNUMBERED CTRL MSG
ASSERT EQ ;NCL SHOULD FILTER THEM ALL
.ENDC
CLR CN.MLK(R0) ;THIS MESSAGE WILL BE LAST ON QUEUE
TST NSPOQL ;ANYTHING THERE NOW?
BNE 10$ ;YES, ADD TO END
MOV R0,NSPOQL ;NO, MAKE THIS MESSAGE BE THE QUEUE
BR 20$ ;SET POINTER TO LAST MESSAGE
10$: MOV NSPOQL+2,R1 ;GET ADDRESS OF LAST MESSAGE
MOV R0,CN.MLK(R1) ;PUT THIS ON END OF QUEUE
20$: MOV R0,NSPOQL+2 ;AND REMEMBER IT'S END OF QUEUE
SEC ;NEVER PASS ANYTHING (CODED THIS WAY FOR DCP1 COMPATIBILITY)
RTS PC ;GO AWAY, RETURN BELOW FROM NSPCHK
.ENABL LSB
NSPOUX: MOV NSPOQL,R0 ;GET ADDRESS OF FIRST MESSAGE
BEQ 99$ ;NOTHING THERE, RETURN
MOV CN.MLK(R0),NSPOQL ;DELINK IT (NOTE - WE MAY PUT IT BACK ON AT NSPOD0)
MOV R0,NSPLMG ;THIS WILL BE THE MESSAGE OF THE HOUR
CLR NSPPMG ;WE'LL SEND ANYTHING THIS BECOMES
.IIF NE FTDCPT,JSR PC,NSPITL ;PRINT IT
MOV SP,NSPSP ;IN CASE NSPOBD IS CALLED
MOV CN.LEN(R0),R2 ;SETUP LENGTH AND ADDRESS OF
MOV R0,R3 ; MSG FOR FOR GETBYT AND FRIENDS
ADD #CN.NCT,R3
JSR PC,GETBYT ;SKIP NCT
JSR PC,GETBYT ;GET DNA
JSR PC,FNDSCB ;FIND ITS SCB
BEQ 10$ ;WENT OFFLINE? DISCARD MSG
MOV SB,DNA ;REMEMBER WHERE IT'S HEADING
MOV SB.LBA(SB),NSPLB ;REMEMBER THE PATH TO IT (THERE SHOULD ONLY BE THIS ONE)
JSR PC,GETBYT ;GET SNA
JSR PC,FNDSCB ;FIND ITS SCB
BEQ 10$ ;SIGH
MOV SB,SNA ;REMEMBER SOURCE
MOV SB,NSPSB ;AND NCL NODE ASSOCIATED WITH MESSAGE
JSR PC,NSPI2B ;SKIP NCA AND NCN
.IF LT DEBUG ;IF WE WANT TO DIE ON EVERYTHING,
MOV NSPLMG,R0 ;GET START OF MESSAGE AGAIN
CMP R2,CN.CNT(R0) ;WE SHOULD MATCH THESE NOW
ASSERT EQ ;COMPLAIN IF NOT
.ENDC
JSR PC,NSPOU1 ;PROCESS CONTROL OR DATA PORTION OF MESSAGE
10$: MOV NSPLMG,R0 ;GET ADDRESS OF FIRST CHUNK
JSR PC,NCLODN ;RETURN TO NCL TO FREE IT
BR NSPOUX ;DO ANOTHER
;HERE VIA NSPOBD MACRO TO ABORT PROCESSING OF THE CURRENT NCL MESSAGE WHEN
;PROTOCOL ERORS ARE DETECTED. (NOTE THIS MAY REFLECT MERELY ONE OF THE UNAVOIDABLE
;RACE CONDITIONS INHERENT IN NETWORKS SO THE TWIDDLE DATA SHOULD BE TAKEN
;WITH A GRAIN OF SALT. THE STACK IS RESET TO THE NSPOUX LEVEL, BOTH NCL AND NSP
;MESSAGES ARE DISCARDED AND THE NEXT MESSAGE ON THE QUEUE IS PROCESSED.
NSPOB0: TWIDDLE (SP)+ ;REMEMBER WHO CALLED US
TWIDDLE ;AND HOW OFTEN
.IIF NE FTDCPT,JSR PC,NSPBTP ;NOTE IF ANYONE'S INTERESTED
MOV NSPSP,SP ;RESET STACK TO WHERE WE WERE
MOV NSPPMG,R0 ;DISCARD NSP MESSAGE WE WERE TRYING TO BUILD
JSR PC,FRECKS ;SINCE THERE'S NO POINT IN SENDING IT
BR 10$ ;GO DISCARD THE NCL MESSAGE
;HERE VIA THE NSPODF MACRO TO DEFER PROCESSING OF THE CURRENT NCL MESSAGE IF
;MEMORY IS NOT AVAILABLE. THIS RESETS THE STACK, REQUES THE MESSAGE ON THE BEGINNING
;OF THE NSPOQL, AND RETURNS TO NSPOUX'S CALLER SINCE THERE IS NO POINT IN
;CONTINUING NCL PROCESSING (I.E. ANY OTHER MESSAGES WILL MEET THE SAME FATE).
NSPOD0: MOV NSPSP,SP ;RESET STACK
.IIF NE DEBUG,ASSERT EQ NSPPMG ;WE SHOULDN'T HAVE BEEN ABLE TO SET THIS
MOV NSPLMG,R0 ;TAKE THE NCL MESSAGE WE WERE WORKING ON
MOV NSPOQL,CN.MLK(R0) ; AND QUEUE IT BACK ON TO START OF NCL MESSAGES
MOV R0,NSPOQL
99$: RTS PC ;NO POINT IN TRYING TO CONTINUE NCL PROCESSING
.DSABL LSB
;ROUTINE TO READ DLA AND DISPATCH TO EITHER DATA OR CONTROL MESSAGE PROCESSOR
NSPOU1: JSR PC,GETEXN ;GET DLA
TST R0 ;NONZERO IF DATA
BEQ NSPOCM ;IT'S ZERO, A CONTROL MESSAGE
.SBTTL DATA MESSAGES
;ROUTINE TO HANDLE TRANSLATION OF DATA MESSAGE. THIS WILL RESULT IN
;GENERATING A NSP DATA OR INTERRUPT MESSAGE.
;IF IT MAKES A DATA MESSAGE, THE BOM AND EOM BITS WILL BE DETERMINED BY
;THE DAP DATA TYPE AND PAST HISTORY OF THE MESSAGES.
NSPODM: JSR PC,NSPSLB ;FIND LEB
CMPB LE.STT(R1),#LES.RN ;ONLY ALLOW IN RUN STATE
BEQ 10$ ;BUT RACES LET THIS HAPPEN OFTEN (DSC STATE)
TSTB LE.STT(R1) ;IDLE?
BNE 5$ ;NO, SOMEONE ELSE IS INVOLVED
JSR PC,NSPFLB ;NO ONE NEEDS THIS NOW
5$: NSPOBD ;THROW IT AWAY IF IT HAPPENS
10$: JSR PC,NSPBMG ;START NSP MESSAGE
BCC 15$ ;GOT A CHUNK, CONTINUE PROCESSING
NSPODF ;FAILED, DEFER FOR A WHILE
15$: MOV NSPLMG,R0 ;LOOK BACK AT START OF NCL MESSAGE
BITB #NCFINT,CN.NCT(R0) ; TO SEE IF IT IS AN INTERRUPT MESSAGE
BEQ 20$ ;NO, ORDINARY DATA MESSAGE
JSR PC,NSPBID ;START BUILDING A INT. DATA MESSAGE
BR 70$ ;REJOIN COMMON CODE
20$: SAVE <R2,R3> ;HAVE TO SNEAK A PEAK AT DAP TYPE
CLR -(SP) ;SAVE A CELL TO MAKE MSGFLG IN
BIT #LES.MD,@R1 ;ARE WE IN THE MIDDLE OF A MESSAGE?
BNE 30$ ;YES, CAN'T SET BOM
MOV #NM.BOM,@SP ;NOTE THIS IS BEGINNING OF MESSAGE
30$: JSR PC,GETEXN ;SKIP COUNT
JSR PC,GETBYT ;GET TYPE
CMP R0,#1 ;IS THIS DATA WITH-OUT END-OF-RECORD?
BEQ 40$ ;IF NOT END-OF-RECORD, DON'T SET EOM BITS
;*** NOTE ***
; BECAUSE NO MONITORS BEFORE THE 700 SERIES EVER SEND DATA
;WITH END-OF-RECORD, THE ABOVE "BEQ" MUST BE NO-OP'ED TO WORK
;PROPERLY WITH 6.03A AND BEFORE.
BIC #LES.MD,@R1 ;WE'RE AT END OF MESSAGE, NO LONGER IN MIDDLE
BIS #NM.EOM,@SP ;NOTE IN MSGFLG
BIT #LES.NR,@R1 ;DOES NSP REQUEST MESSAGES?
BEQ 60$ ;YES, DON'T HAVE TO SEND A FREE DATA REQUEST
BR 50$ ;REQUEST LOW LEVEL SEND A DATA REQUEST
40$: BIS #LES.MD,@R1 ;NOTE WE'RE SOMEWHERE IN THE MIDDLE NOW
BIT #LES.NR!LES.MR,@R1 ;IF NSP IS REQUESTING MESSAGES OR NOTHING
BEQ 60$
50$: JSR PC,NSPQDR ;THEN WE HAVE TO TELL NCL TO KEEP SENDING
60$: MOV (SP)+,R0 ;RECOVER MSGFLG
RESTORE <R3,R2> ;REREAD DATA
;..
;..
JSR PC,NSPBDT ;BUILD START OF DATA MESSAGE
70$: CLR -(SP) ;CLEAR COUNTER (FOR STRIPPING)
80$: TST R2 ;ANY MORE DATA IN NCL MESSAGE?
BEQ 100$ ;NO, BRANCH WHEN DONE
BIT #LES.DV,@R1 ;ARE WE STRIPPING COUNT AND TYPE FIELDS?
BNE 90$ ;NO, CONTINUE
TST @SP ;CHECK COUNT OF SUB-MESSAGE
BNE 90$ ;IF MORE TO GO, BRANCH
JSR PC,GETEXN ;GET NEXT COUNT FIELD
DEC R0 ;SUBTRACT ONE FOR TYPE BYTE
MOV R0,@SP ;SAVE COUNT
JSR PC,GETBYT ;THROW AWAY TYPE
BR 80$ ;AND TRY AGAIN (IN CASE NO DATA)
90$: ;HERE FOR REAL DATA BYTE
JSR PC,GETBYT ;GET DATA BYTE
DEC @SP ;DECREMENT SUB-MESSAGE BYTE COUNTER
JSR PC,NSPPBY ;STORE BYTE IN NSP MESSAGE
BR 80$ ;CONTINUE LOOPING ON DATA
100$: TST (SP)+ ;DISCARD COUNT LOCATION
BR NSPONS ;SEND IT
.SBTTL NCL CONTROL MESSAGE PROCESSING
;CONTROL MESSAGE PROCESSING AND DDCMP RETURN.
;NSPOCM CONTROLS THE CONTROL MESSAGE DISPATCH AND FALLS INTO
;NSPONS, THE CODE WHICH RETURNS THE TRANSLATED MESSAGE TO DDCMP.
;THE NCL MESSAGE WE STARTED WITH IS PASSED TO NCLODN WHERE IT GETS FREED
;PRETTY QUICKLY.
;ONE THING WE SHOULD DO BUT DON'T IS PROCESS MORE THAN ONE CONTROL MESSAGE.
NSPOCM: JSR PC,GETEXN ;GET LENGTH OF CONTROL PORTION
JSR PC,GETBYT ;GET TYPE
CMP R0,#NSPMNC ;IN RANGE?
BLO 10$ ;IN RANGE, KEEP AT IT
NSPOBD ;SOMEONE CHANGED THE PROTOCOL!
10$: ASL R0 ;WORD INDEXING
JSR PC,@NSPOCD(R0) ;CALL APPROPRIATE ROUTINE
NSPONS: MOV NSPPMG,R0 ;GET ADDRESS OF FIRST CHUNK OF NSP MESSAGE
BEQ 10$ ;NO MESSAGE TO SEND
JSR PC,NSPSNS ;FINISH OFF MESSAGE
10$: RTS PC ;RETURN TO DDCMP TO SEND MSG
NSPOCD: .WORD NSPOB0 ;ILLEGAL
.WORD NSPOCN ;CONNECT - SEND CI OR CC
.WORD NSPODC ;DISCONNECT - SEND DI OR DC
.WORD NSPRTS ;NEIGHBORS - IGNORE
.WORD NSPORC ;REQ CONFIG - RETURN CONFIG
.WORD NSPRTS ;CONFIG - IGNORE (WE DIDN'T REQUEST IT)
.WORD NSPODR ;DATA REQUEST - SEND LS
.WORD NSPOST ;STATION CTRL - RETURN STC REJECTION
NSPMNC=<.-NSPOCD>/2
;ROUTINES TO HANDLE STATION CONTROL AND REQ CONFIG MESSAGES. BOTH OF THESE
;RESULT IN NO NSP MESSAGE TO PASS ON BUT DO RESULT IN REPLIES TO THE SOURCE.
;THESE ROUTINES SWITCH THE DIRECTION OF MESSAGE FLOW, PROTECT NSPLMG (THE ADDRESS
;OF THE ORIGINAL MESSAGE) BUILD A NEW NCL MESSAGE AND SEND IT. ALL STATION
;CONTROL MESSAGES ARE REJECTED, ALL REQ CONFIG MESSAGES RESULT IN A CONFIG MESSAGE
;BASED ON DATA ORGINALLY PROVIDED IN THE NSP MACRO.
.ENABL LSB
NSPOST: JSR PC,NSPLTL ;SWITCH DIRECTIONS
SAVE <NSPLMG> ;HAVE TO SAVE THIS WHILE WE REPLY
MOV #NCLSTC,R1 ;MAKE A STATION CTRL MESSAGE
JSR PC,NSPBNC ;WELL, TRY TO AT LEAST
BCS 30$ ;NO SPACE, IGNORE IT
JSR PC,GETBYT ;GET LINE NUMBER
JSR PC,NSPPBY ;PUT LINE NUMBER
MOV #13,R0 ;REJECT STATION CTRL MSG TYPE
JSR PC,NSPPBY ;PUT CODE
BR 20$ ;SEND IT
NSPORC: JSR PC,NSPLTL ;CHANGE A NCL MESSAGE INTO A REPLY
MOV #NCLCNF,R1 ;TO MAKE A CONFIG MESSAGE
SAVE <NSPLMG> ;JUGGLE TWO NCL MESSAGES
JSR PC,NSPBNC ;WRITE NEW HEADER
BCS 30$ ;FORGET IT IF NO ROOM
MOV NSPLB,R2 ;NSPBMG WIPED OUT J ON US
ADD #LB.CNF,R2 ;POINT TO CONFIG DATA
MOV #NSP$MX/2,R1 ;NUMBER OF CONFIG PAIRS
10$: MOVB (R2)+,R0 ;GET OBJTYPE
BLT 20$ ;NEGATIVE MEANS WE'VE RUN OUT
JSR PC,NSPPBY ;PUT INTO NCL MESSAGE
MOVB (R2)+,R0 ;GET COUNT
JSR PC,NSPPBY
CLR R0 ;ZERO PID
JSR PC,NSPPBY
SOB R1,10$ ;DO REST
20$: JSR PC,NSPSNC ;SEND CONFIG MESSAGE
30$: RESTORE <NSPLMG> ;RESTORE MESSAGE TO FREE
RTS PC
.DSABL LSB
;ROUTINE TO PROCESS NCL CONNECT MESSAGES. NOTE THAT NCL USES THE SAME
;MESSAGE TYPE FOR CONNECT INITS AND CONNECT CONFIRMS, SO THIS ROUTINE
;HAS TO DETERMINE WHICH TO SEND. IN THE CASE OF A CONNECT INIT, A DISCONNECT
;IS RETURNED IF ALL NORMAL LEBS ARE IN USE. IN EITHER CASE, THE NSP MESSAGE
;GENERATED WILL REQUEST SEGMENT DATA REQUESTS SINCE THEY HAVE A ONE TO ONE
;CORRESPONDENCE WITH NCL'S DATA REQUEST MECHANISM.
NSPOCN: JSR PC,NSPBMG ;BUILD NSP AS WE DECODE NCL
BCS 70$ ;FORGET IT IF COULDN'T GET SPACE
JSR PC,NSPORT ;PUT RTHDR
JSR PC,GETEXN ;GET DLA
MOV R0,-(SP) ;SAVE WHILE WE DECIDE WHAT SORT MSG
BEQ 10$ ;ZERO - MEANS CONNECT INIT
MOV #NM.CC-NM.CI,R0 ;THIS WILL BECOME A CONNECT CONFIRM
10$: ADD #NM.CI,R0 ;MAKE MSGFLG FOR INIT OR CONF
JSR PC,NSPPBY ;PUT MSGFLG
MOV (SP)+,R0 ;RECOVER DLA
BEQ 20$ ;CONNECT INIT
JSR PC,NSPSLB ;FIND LEB, DLA IS KNOWN DCP LINK ADDR
CMPB LE.STT(R1),#LES.PI ;ONLY ALLOW CONNECT CONFIRM WHEN EXPECTING IT
BNE 60$ ;OTHERWISE DISALLOW
MOV LE.NSP(R1),R0 ;RECOVER THE NSP LINK ADDRESS
JSR PC,NSPO2B ;PUT DSTADDR
JSR PC,GETEXN ;GET SLA
MOV R0,LE.NCL(R1) ;SAVE NCL'S LINK ADDRESS
MOVB #LES.RN,LE.STT(R1) ;ENTER RUN STATE
JSR PC,NSPCNR ;CHECK TO SEE IF THIS IS A NO SEGMENT REQUEST NODE
BR 40$ ;CONTINUE WITH COMMON CODE
20$: JSR PC,GETEXN ;GET SLA
MOV NSPLB,R1 ;FIND START OF LEB LIST FOR THAT SOURCE
MOV LB.LEB(R1),R1 ;ADDRESS OF FIRST LEB ON LIST
25$: BEQ 30$ ;IF NOTHING THERE, LINK ADDR CAN'T BE IN USE
CMP R0,LE.NCL(R1) ;RIGHT LINK ADDRESS?
BEQ 35$ ;YES, USE THIS LEB
MOV LE.LNK(R1),R1 ;GET NEXT LEB
BR 25$ ;AND TRY AGAIN
30$: MOV R0,-(SP) ;PROTECT SLA
JSR PC,NSPALB ;TRY TO ALLOCATE A LEB
MOV (SP)+,LE.NCL(R1) ;REMEMBER LINK ADDRESS
BCS 65$ ;CAN'T USE MAGIC LEB
35$: MOV R1,NSPLEB ;REMEMBER LEB WE FOUND
CLR R0 ;USE A ZERO DESTADDR
JSR PC,NSPO2B ;PUT DSTADDR
CMPB LE.STT(R1),#LES.LI ;ONLY ALLOW IF IDLE OR LI STATES
BGT 65$ ;NOPE, ONE OF THESE HAPPENED:
; PI - CONN TO LINK IN PI STATE (IMPOSSIBLE)
; RUN - NCL SHOULD GUARANTEE THAT EXTRA CONNECTS DON'T ARRIVE
; DSC - LIKEWISE, DISCONNECTS SHOULD COMPLETE FIRST
MOVB #LES.LI,LE.STT(R1) ;ENTER LI STATE
40$: MOV LE.DCP(R1),R0 ;USE INTERNAL ADDRESS FOR SOURCE
JSR PC,NSPO2B ;PUT SRCADDR
MOV #NM.LNK!NM.SRQ+<0*400>,R0
JSR PC,NSPO2B ;PUT SERVICES, INFO BOTH AT ONCE
MOV #MSGMAX,R0 ;TOPS-10 DOESN'T USE MML FIELD, BETTER FAKE IT
JSR PC,NSPO2B ;PUT SEGSIZE
CMPB #LES.RN,LE.STT(R1) ;IF WE'RE IN RUN STATE
BEQ 50$ ;THEN WE'RE SENDING A CC AND HAVE TO ADD DATA FIELD
JSR PC,NSPOC1 ;COPY PROCESS NAME TO NSP MESSAGE
CLR R1 ;NO LEB INDICATES DON'T SET LES.DV THIS CALL
JSR PC,NSPOC1 ;AGAIN FOR SOURCE NAME
50$: CLR R0 ;NO MENU ITEMS IN NCL OR NULL DATA FIELD
JSR PC,NSPPBY ;PUT MENU
RTS PC ;RELEASE NCL MESSAGE AND SEND NSP
60$: JSR PC,GETEXN ;GET SLA
MOV R0,LE.NCL(R1) ;NEED SO WE CAN BUILD DISC MSG.
65$: JMP NSPERP ;LINK ERROR
70$: NSPODF ;DEFER UNTIL MEMORY FREES UP
;ROUTINE TO COPY PROCESS NAME FROM NCL MESSAGE INTO NSP MESSAGE
NSPOC1: JSR PC,GETBYT ;GET OBJECT TYPE
TST R1 ;IS IT A DESTINATION PROCESS NAME
BEQ 5$ ;NO - DONT SAVE IT
MOVB R0,LE.DPN(R1) ;YES - SAVE IT FOR LATER
5$:
CMP #11,R0 ;TASK?
BEQ 30$ ;YES, GO COPY IN NAME
MOV R0,-(SP) ;SAVE OBJECT TYPE FOR LATER
MOV #1!<0*400>,R0 ;USE FMT 1, OBJTYPE 0
JSR PC,NSPO2B ;PUT FORMAT, OBJTYPE
TST R1 ;WERE WE PASSED A LEB?
BEQ 10$ ;NO, DON'T TRY SETTING LES.DV
BIS #LES.DV,LE.STS(R1);SET DEVICE BIT IN LINK ENTRY
10$: MOV R5,-(SP) ;SAVE POSITION OF COUNT FIELD IN IMAGE STRING
MOV #5,R0 ;WILL BE AT LEAST 5 CHARACTERS
JSR PC,NSPPBY ;PUT THAT IN AS INITIAL COUNT
MOV #'O,R0 ;PUT TASK NAME OBJOON INTO MESSAGE
;WHERE "OO" IS OBJECT TYPE, "N" IS NUMBER
JSR PC,NSPPBY ;PUT "O" INTO MESSAGE
MOV #'B,R0 ;GET "B"
JSR PC,NSPPBY ;PUT "B" INTO MESSAGE
MOV #'J,R0 ;GET "J"
JSR PC,NSPPBY ;PUT "J" INTO MESSAGE
MOV 2(SP),R0 ;GET OBJECT TYPE
ROR R0 ;SHIFT
ROR R0 ; SECOND DIGIT
ROR R0 ; TO CORRECT PLACE
BIC #177770,R0 ;CLEAR EXTRA BITS
ADD #'0,R0 ;MAKE INTO ASCII NUMBER
JSR PC,NSPPBY ;PUT 1ST DIGIT OF OBJECT TYPE INTO NAME
MOV 2(SP),R0 ;GET OBJECT TYPE BACK
BIC #177770,R0 ;CLEAR EXTRANEOUS BITS
ADD #'0,R0 ;MAKE INTO NUMBER
JSR PC,NSPPBY ;STORE IN MESSAGE
JSR PC,GETBYT ;GET UNIT NUMBER
TST R1 ;IS IT THE DPN FIELD?
BEQ 15$ ;NO - SKIP THIS
MOVB R0,LE.DPN+1(R1) ;SAVE THE UNIT FIELD FOR LATER
15$:
MOV (SP)+,R1 ;RESTORE ADDRESS OF IMAGE COUNT
CMP R0,#177 ;GENERIC UNIT?
BEQ 20$ ;DONE WITH CONNECT
JSR PC,NSPOC2 ;PUT NUMBER INTO FIELD, INC LENGTH
20$: TST (SP)+ ;DISCARD OBJTYPE
RTS PC ;DONE WITH THIS NAME FIELD
30$: MOV #NSPLPN,R1 ;SAVE PROCESS NAME HERE WHILE WE HANDLE PPN
40$: JSR PC,GETBYT ;GET BYTE OF NAME
CMPB R0,#'[!200 ;START OF PPN?
BEQ 50$ ;YES, FIX NAME, PARSE PPN
MOVB R0,(R1)+ ;SAVE IT
BMI 40$ ;LOOP ON REST OF NAME
BR 60$ ;REACHED END OF PROCESS NAME, STOP
50$: BICB #200,-1(R1) ;YES, END OF NAME, CLEAR EXTENSIBLE BIT
;HERE TO PROCESS PPN
MOV #2,R0 ;USE FORMAT 2 (OBJ, NAME, GROUP, USER)
JSR PC,NSPO2B ;FORMAT, OBJTYPE
JSR PC,NSPOCP ;CONVERT ASCII PROJECT TO GROUP
JSR PC,NSPOCP ;AND PROGRAMMER TO USER
TST R0 ;SHOULD BE CLOSE BRACKET NOW
BPL 70$ ;WHICH SHOULD BE END OF STRING
JSR PC,NSPERR ;WE AREN'T, CALL IT A LINK ERROR TO DISCONNECT
NSPOBD ;DISCARD THIS AND THE NSP MESSAGE
60$: MOV #1,R0 ;USE FORMAT 1 (OBJ, NAME)
JSR PC,NSPO2B ;FORMAT, OBJTYPE
70$: MOV #NSPLPN,R1 ;ADDR WHERE WE HID NAME
JMP NSPOIM ;NOW WE CAN COPY IT
NSPOC2: MOV R0,-(SP) ;SAVE NUMBER WE'RE STORING
ASR R0 ;DISCARD
ASR R0 ; LOW
ASR R0 ; DIGIT
BLE 10$ ;STOP IF THAT WAS ALL
JSR PC,NSPOC2 ;STUFF REST OF NUMBER
10$: MOV (SP)+,R0 ;RECOVER OUR DIGIT
BIC #177770,R0 ;JUST OUR DIGIT...
BIS #60,R0 ;ASCIIZE IT
INCB @R1 ;COUNT IN LENGTH FIELD
JMP NSPPBY ;PUT IN MESSAGE
;HERE TO TRANSLATE DISCONNECT MESSAGE. THE REASON FIELD WILL BE TRANSLATED
;INTO SOMETHING FAIRLY CLOSE TO WHAT NSP SHOULD GET.
NSPODC: JSR PC,GETEXN ;GET DLA
JSR PC,NSPSLB ;FIND LEB FOR IT
JSR PC,GETEXN ;GET SLA (IN NCL (WELL, NETSER) THIS IS 0)
MOVB LE.STT(R1),R0 ;RECOVER CURRENT STATE
JMP @NSPDSX(R0) ;FIGURE OUT WHAT TO DO
NSPDSX: .WORD NSPFLB ;IGNORE
.WORD NSPFLB ;DISCONNECT AFTER CONNECT? NSP SAYS TO FORGET LINK
.WORD NSPDS2 ;REQUEST REJECTED, RETURN DI
.WORD NSPDS2 ;RUNNING - SEND DI, ENTER DSC
.WORD NSPDS1 ;DSC - SEND DC, ENTER IDLE
.ENABL LSB
NSPDS1: MOV #NM.DC,R0 ;SEND DC
10$: CLRB LE.STT(R1) ;ENTER IDLE STATE
MOV #NSPFLB,-(SP) ;FREE LEB WHEN DONE
BR 20$ ;JOIN COMMON CODE
NSPDS2: MOV #NM.DI,R0 ;SEND DI
MOVB #LES.DS,LE.STT(R1) ;AND ENTER DSC STATE
20$: SAVE <R0>
JSR PC,NSPBMG ;MAKE NSP MESSAGE BUFFER
RESTORE <R0> ;RECOVER MSGFLG
BCS 50$ ;JUST HAVE LOW LEVEL SEND DC
JSR PC,NSPRML ;BUILD MOST OF MESSAGE
TSTB LE.STT(R1) ;HAVE WE GONE BACK TO IDLE?
BEQ 40$ ;YES, GET CONFIRM REASON
JSR PC,GETEXN ;GET NCL REASON
CMP R0,#NSPRSM ;BEYOND RANGE?
BLO 30$ ;NO, MAP REASON CODE
CLR R0 ;YES, USE A NO ERROR CODE
30$: MOVB NSPRXL(R0),R0 ;MAP REASON
JSR PC,NSPO2B ;PUT RSN
CLR R0 ;DI NEEDS A DATA FIELD
JMP NSPPBY ;PUT DATA
40$: MOV #NM.CNF,R0 ;USE CONFIRM REASON FOR DC
JMP NSPO2B ;JUST PUT IT ON
50$: NSPODF ;DEFER UNTIL MEMORY IS AVAILABLE TO SEND A PROPER DISCONNECT
NSPRXL: .BYTE NM.NOE,NM.IPN,NM.TCN,NM.TCP,NM.PDE
NSPRSM =.-NSPRXL
.EVEN
.DSABL LSB
;ROUTINE TO CONVERT DATA REQUESTS INTO LINK SERVICE MESSAGES. SINCE THE PORT
;SPECIFIES SEGMENT REQUESTS ON ALL CONNECTIONS IT SETS UP, THERE IS A ONE
;TO ONE CORRESPONDENCE BETWEEN DATA REQUESTS AND SEGMENT REQUESTS.
NSPODR: JSR PC,GETEXN ;GET DLA
JSR PC,NSPSLB ;FIND LEB FOR IT
CMPB LE.STT(R1),#LES.RN ;ONLY ALLOW WHEN RUNNING
BNE 10$ ;PROBABLY IN DSC STATE, THROW IT AWAY
JSR PC,GETEXN ;GET DRQ
SAVE <R0>
JSR PC,NSPBMG ;MAKE HEADER
BCS 30$ ;DEFER IT
JSR PC,NSPBLS ;BUILD MOST OF LS MESSAGE
CLR R0 ;SAY NO CHANGE IN FLOW CONTROL PARAMS
JSR PC,NSPPEX ;PUT LSFLAGS
RESTORE <R0> ;RECOVER DRQ
JMP NSPPBY ;PUT FCVAL
10$: TSTB LE.STT(R1) ;IDLE?
BNE 20$ ;NO
JSR PC,NSPFLB ;NO ONE ELSE WILL FREE THIS, SO WE MUST
20$: NSPOBD
30$: NSPODF ;WAIT FOR MEMORY
.SBTTL LINK ERROR PROCESSOR
;HERE TO HANDLE LINK ERROR EVENTS. ENTER AT NSPERL IF THERE IS A NCL
;MESSAGE THAT MUST BE FREED OR AT NSPERP IF THERE IS A NSP MESSAGE THAT
;MUST BE FREED. IN EITHER CASE, A DC MESSAGE WILL BE SENT FROM LOW LEVEL
;AND A NCL DISCONNECT WILL BE SENT IMMEDIATELY IF THERE IS SPACE TO BUILD IT.
NSPERL: MOV NSPLMG,R0 ;GET NCL MESSAGE WE WERE READING
JSR PC,NCLODN ;TRY TO FREE IT
BR NSPERR ;ENTER AT COMMON CODE
NSPERP: MOV NSPPMG,R0 ;RECOVER OLD NSP MESSAGE
JSR PC,FRECKS ;DISCARD IT
CLR NSPPMG ;SO NSPOUT WON'T TRY TO SEND FREE CORE
NSPERR: MOV #NM.UEC,R0 ;TRY TO SEND RANDOM REASON DC
JSR PC,NSPQDC ; AT LOW LEVEL IF NOTHING ELSE HAS BEEN SPECIFIED
TST LE.NCL(R1) ;IS THERE A NCL SIDE?
BEQ 30$ ;NO, RETURN
SAVE <NSPLMG> ;IF CALLED BY NSPOUT, IT WILL FREE THIS LATER
MOV #NCLDIS,R1 ;GET MESSAGE TYPE TO SEND
JSR PC,NSPBNC ;TRY TO START NCL MESSAGE
BCS 20$ ;SIGH
MOV NSPLEB,R1
MOV LE.NCL(R1),R0 ;RECOVER DLA
JSR PC,NSPPEX ;PUT DLA
MOV LE.DCP(R1),R0 ;AND OUR END
JSR PC,NSPPEX ;PUT SLA
MOV #3,R0 ;NETWORK CAPACITY EXCEEDED?
JSR PC,NSPPBY ;PUT RSN
JSR PC,NSPSNC ;SEND IT
20$: RESTORE <NSPLMG>
30$: RTS PC ;DONE, LOW LEVEL WILL FREE LEB
.SBTTL SEGMENT ACKNOWLEDGEMENT/ RETRANSMISSION
;ROUTINES TO FREE ACKED MESSAGES FROM LEB QUEUES
;ENTER AT NSPFRL TO FREE LS MESSAGES OR AT NSPFRD TO FREE DATA MESSAGES.
;CALL WITH R0/ ACKNUM FIELD OF LS, DATA, OR ACK MESSAGE.
;ACKNUM FIELDS ALSO IMPLY NEGATIVE ACKNOWLEDGEMENT AND THESE ROUTINES WILL
;DETECT THAT AND RETRANSMIT ALL NAKED MESSAGES.
;WHEN THE OUTPUT QUEUES ARE EMPTIED THE LINK TIMER SHOULD BE CLEARED BUT
;ISN'T (THE CODE THIS SAVES SHOULD BE ADDED IF ANY TROUBLE IS SEEN AT
;ALL). WHEN LINK TIMEOUT OCCURS, THE RETRANSMIT ROUTINES WILL BE CALLED BUT
;SINCE THEY WON'T DO ANYTHING THE LINK TIMER WILL BE LEFT AT ZERO.
.ENABL LSB
NSPFRL: MOV #LE.OQL,R1 ;OFFSET FOR A LIST POINTER TO MSGS
BR 10$ ;JOIN COMMON CODE
NSPFRD: MOV #LE.OQD,R1 ;OR FOR DATA QUEUE
10$: SAVE <R2> ;DON'T LET COUNT BE WIPED OUT
ADD NSPLEB,R1 ;POINT TO LIST HEAD
MOV R0,-(SP) ;SAVE ACKNUM FIELD
MOV R1,-(SP) ;SAVE FOR REUSE IN NAK PROCESSING
20$: MOV @R1,R0 ;GET NEXT MESSAGE
BEQ 30$ ;STOP WHEN WE RUN OUT
MOV CN.SEG(R0),R2 ;GET SEGNUM FOR THIS MESSAGE
DEC R2 ;TO MAKE SUB BELOW SET "SIGN" IF FREEABLE
SUB 2(SP),R2 ;HOW FAR AWAY ARE THE 2?
BIT #<NM.NMM+1>/2,R2 ;IF SET, THEN IT'S WITHIN THE LAST 2048
BEQ 30$ ;NOT SET, LEAVE IT
MOV CN.MLK(R0),@R1 ;DEQUEUE MESSAGE
JSR PC,FRECKS ;DISCARD IT
BR 20$ ;LOOK FOR MORE
30$: MOV (SP)+,R0 ;GET LIST HEADER ADDR FOR NAK PROCESSING
BIT #NM.NAK,(SP)+ ;WHAT SORT OF ACK WAS THAT?
BEQ 80$ ;PURE ACK, ALL DONE
BR 50$ ;MAKE ABS. AND RETRANSMIT REMAINDER
;ROUTINES TO RETRANSMIT OUTPUT QUEUES. THESE ARE ENTERED FROM TWO
;PLACES. FIRST, THE ACKNUM PROCESSORS (NSPFRL, NSPFRD) WILL ENTER HERE IF
;THE NAK BIT IS ON IN ACKNUM, SECOND, THE LINK TIMING CODE WILL ENTER HERE
;TO RETRANSMIT MESSAGES WHEN LINK TIMEOUT OCCURS.
NSPRTL: MOV #LE.OQL,R0 ;HEADER OF LS/INT MESSAGES
BR 40$ ;MAKE ABS. ADDR AND RETRANSMIT
NSPRTD: MOV #LE.OQD,R0 ;HEADER OF DATA MESSAGES
40$: ADD NSPLEB,R0 ;MAKE ABSOLUTE ADDR
SAVE <R2> ;PROTECT ALL REGISTERS
50$: SAVE <R3,R4,R5> ;R2 ON STACK FROM ALL ENTRIES HERE
MOV NSPLB,J ;POINT TO LINE BLOCK
MOV LB.SCB(J),SB ; AND SCB
MOV @R0,-(SP) ;SAVE ADDR OF FIRST MESSAGE TO BE RETRANSMITTED
CLR @R0 ;WIPEOUT LIST OF UNACKNOWLEDGED MESSAGES IN LEB
BR 70$ ;GO TRANSMIT THEM OVER AGAIN
60$: MOV CN.MLK(R0),-(SP) ;SAVE ADDRESS OF NEXT MESSAGE
JSR PC,DDQNSP ;SEND IT, LE.TIM WILL BE SET AT NSPODN
70$: MOV (SP)+,R0 ;RECOVER ADDRESS OF NEXT MESSAGE
BNE 60$ ;SEND IT IF THERE IS ONE
RESTORE <R5,R4,R3>
80$: RESTORE <R2>
RTS PC ;ALL DONE
.DSABL LSB
.SBTTL NSP DECODING SUBROUTINES
;ROUTINE TO READ IMAGE FORMAT FIELDS IN NSP MESSAGES
;CALL:
; R0/ADDR OF DEST STRING
; JSR PC,NSPIIM
; .WORD LENGTH OF DEST STRING
NSPIIM: MOV R0,R4 ;PROTECT DEST STRING ADDR
MOV @0(SP),-(SP) ;GET LENGTH OF DEST STRING
ADD #2,2(SP) ;SO RTS HITS AN INSTRUCTION
JSR PC,GETBYT ;GET LENGTH OF SOURCE STRING
MOV R0,R1 ;PROTECT FROM FUTURE GETBYT CALLS
BEQ 15$ ;IF A NULL STRING, JUST CLEAR OUTPUT AREA
SUB R1,@SP ;@SP_HOW MUCH LONGER DEST IS THAN SOURCE
BGT 10$ ;WELL, IT SHOULD BE
ADD @SP,R1 ;SOURCE LONGER, LIMIT COPY TO DEST'S LENGTH (@SP-R1)+R1
10$: JSR PC,GETBYT ;GET BYTE FROM SOURCE
BIS #200,R0 ;MAKE EXTENSIBLE
MOVB R0,(R4)+ ;PUT IN OUTPUT STRING
SOB R1,10$ ;DO REST
BICB #200,-1(R4) ;LAST BYTE MUSTN'T HAVE EXTENSIBLE BIT ON
15$: MOV (SP)+,R1 ;GET STRING LENGTH DIFFERENCE
BLE 30$ ;TRIM NSP MESSAGE IF SOURCE WAS LONGER
20$: CLRB (R4)+ ;OTHERWISE CLEAR REST OF DESTINATION STRING
SOB R1,20$ ;LOOP
99$: RTS PC ;AND DONE
30$: BEQ 99$ ;STOP WHEN READ WHOLE STRING
JSR PC,GETBYT ;GET NEXT BYTE
INC R1 ;COUNT IT
BR 30$ ;LOOP
;ROUTINE TO READ B-2 FIELDS IN NSP MESSAGES:
;CALL:
; JSR PC,NSPI2B
; R0/ CONTENTS OF 2 BYTE FIELD
NSPI2B: JSR PC,GETBYT ; GET LOW HALF OF FIELD
MOV R0,-(SP)
JSR PC,GETBYT ; AND HIGH HALF
MOVB R0,1(SP) ;BUILD FULL WORD
MOV (SP)+,R0 ;GET TOTAL RESULT
RTS PC ;RETURN IT
.SBTTL NSP BUILDING SUBROUTINES
NSPBMG: JSR PC,GETCNK ;GET A CHUNK
BNE 10$ ;GOT ONE, USE IT
SEC ;SAY WE LOST
RTS PC
10$: MOV R0,NSPPMG ;SAVE START OF MESSAGE
NSPBM1: MOV NSPPMG,R0 ;GET ADDRESS OF CURRENT MESSAGE
CLR R4 ;CLEAR COUNT REGISTER
MOV R0,R5 ;PUT START ADDRESS INTO BYTE POINTER REGISTER
CLR CN.MLK(R5) ;CLEAR MESSAGE LINK
.IIF NE,DEVN, CLR CN.DDB(R5) ;AND DDB LINK
ADD #CN.NCT,R5 ;POINT TO FIRST DATA BYTE
CLR CN.SEG(R0) ;SAY MESSAGE NEED NOT BE QUEUED AT NSPODN FOR NOW
RTS PC ;RETURN CARRY CLEAR
NSPSNS: MOV #DDQNSP,-(SP) ;SHORTEST WAY TO CALL BELOW THEN DDQNSP
NSPSN0: MOV NSPPMG,R0 ;GET MESSAGE ADDRESS
ASSERT NE
MOV R4,CN.LEN(R0) ;TELL DDCMP HOW LONG IT IS
MOV NSPLB,J ;AND ADDR OF LINE BLOCK
MOV LB.SCB(J),SB ;AND SCB OF DEST
RTS PC ;NSPODM WILL SET LE.TIM
;ROUTINE TO BUILD A INTERRUPT OR LS MESSAGE UP TO SEGNUM FIELD. ONLY IF
;IT WILL DO ANY GOOD WILL AN ACKNUM FIELD BE GENERATED. IF ONE IS GENERATED,
;THE REQUEST BIT WILL BE CLEARED SO THAT LOW LEVEL WILL NOT SEND A DUPLICATE.
.ENABL LSB
NSPBID: MOV #NM.IDT,R0 ;INTERRUPT DATA MESSAGE TYPE
BR 10$
NSPBLS: MOV #NM.LS,R0 ;GET APPROPRIATE MSGFLG
10$: JSR PC,NSPMDS ;PUT MSGFLG, DSTADDR, SRCADDR
BIT #LES.LA,@R1 ;HAVE TO SEND AN ACK SOMEDAY?
BEQ 20$ ;NOPE, DON'T WASTE THE SPACE
MOV LE.LIL(R1),R0 ;GET LAST LS MESSAGE WE SAW
BIS #B15,R0 ;MAKE ACKNUM VALUE
JSR PC,NSPO2B ;PUT ACKNUM
BIC #LES.LA,@R1 ;NO NEED TO SEND AN ACK
20$: MOV LE.LOL(R1),R0 ;TAKE LAST SEGNUM WE USED
INC R0 ;STEP TO NEXT
BIC #^CNM.NMM,R0 ;MODULO 4096
MOV R0,LE.LOL(R1) ;MAKE SURE THE LEB VERSION IS SAME
JSR PC,NSPO2B ;PUT SEGNUM
MOV NSPPMG,R0 ;PUT INTO MESSAGE BLOCK
MOV LE.LOL(R1),CN.SEG(R0) ;SO NSPODN QUEUES THIS
BIS #B15,CN.SEG(R0) ;FLAG A LS/INT MSG
RTS PC ;LET CALLER FILL REST
.DSABL LSB
;ROUTINE TO BUILD A DATA MESSAGE UP TO SEGNUM FIELD. ESSENTIALLY A
;CARBON COPY OF NSPBID/BLS
NSPBDT: JSR PC,NSPMDS ;PUT MSGFLG, DSTADDR, SRCADDR
BIT #LES.DA,@R1 ;HAVE TO SEND AN ACK?
BEQ 10$ ;NO, SAVE THE SPACE
MOV LE.LID(R1),R0 ;GET LAST DATA MESSAGE WE SAW
BIS #B15,R0 ;MAKE ACKNUM VALUE
JSR PC,NSPO2B ;PUT ACKNUM
BIC #LES.DA,@R1 ;NO NEED TO SEND AN ACK
10$: MOV LE.LOD(R1),R0 ;TAKE LAST SEGNUM WE USED
INC R0 ;STEP TO NEXT
BIC #^CNM.NMM,R0 ;MODULO 4096
MOV R0,LE.LOD(R1) ;MAKE SURE THE LEB VERSION IS SAME
JSR PC,NSPO2B ;PUT SEGNUM
MOV NSPPMG,R0 ;PUT INTO MESSAGE BLOCK
MOV LE.LOD(R1),CN.SEG(R0) ;SO NSPODN QUEUES THIS
RTS PC ;LET CALLER FILL REST
;ROUTINE TO PUT ON RTHDR, MSGFLG, DSTADDR, AND SRCADDR FIELDS OF NSP
;CALL:
; R0/MSGFLG VALUE, R4,R5/ POINTING TO START OF NSP MSG
; JSR PC,NSPRML ;FOR RTHDR, MSGFLG, DSTADDR, SRCADDR
; JSR PC,NSPMDS ;FOR MSGFLG, DSTADDR, SRCADDR
NSPRML: SAVE <R0> ;PROTECT MSGFLG
JSR PC,NSPORT ;PUT ON RTHDR
RESTORE <R0> ;RECOVER MSGFLG
NSPMDS: JSR PC,NSPPBY ;PUT MSGFLG
MOV NSPLEB,R1 ;RECOVER LEB ADDRESS
MOV LE.NSP(R1),R0 ;RECOVER LINK ADDRESSES
JSR PC,NSPO2B ;PUT DESTADDR
MOV LE.DCP(R1),R0
BR NSPO2B ;PUT SRCADDR
;ROUTINE TO PUT NSP ASCII ROUTING HEADER ON MESSAGE
NSPORT: MOV #NM.ROU,R0 ;READY ROUTING FLAG BYTE
JSR PC,NSPPEX ;RTFLG
MOV DNA,R1 ;POINT TO DESTINATION NAME
ADD #SB.SNM,R1
JSR PC,NSPOIM ;DSTNODE PUT INTO NSP MESSAGE
MOV SNA,R1 ;DO SAME WITH SOURCE
ADD #SB.SNM,R1
BR NSPOIM ;SRCNODE
;ROUTINE TO CONVERT EXTENSIBLE ASCII INTO IMAGE DATA IN OUTPUT STRING
;CALL:
; R1/ADDRESS OF STRING
; JSR PC,NSPOIM
; R2, R3 PRESERVED, ALL ELSE CLOBBERED
NSPOIM: SAVE <R2> ;SOME CALLERS USE THIS
MOV R5,-(SP) ;SAVE PLACE IN OUTPUT
JSR PC,NSPPBY ;OUTPUT LENGTH FIELD
CLR R2
10$: MOVB (R1)+,R0 ;GET NEXT BYTE OF NAME
INC R2 ;COUNT IT
BITB #200,R0 ;LAST ?
BEQ 20$ ;YES, DONE
BICB #200,R0 ;CLEAR EXTEND BIT
JSR PC,NSPPBY ;PUT IT OUT
BR 10$ ;AND GET THE NEXT ONE
20$: JSR PC,NSPPBY ;OUTPUT LAST ONE
MOVB R2,@(SP)+ ;SET COUNT RIGHT
RESTORE <R2>
RTS PC
;ROUTINE TO TRANSLATE AN ASCII, EXTENSIBLE OCTAL NUMBER INTO BINARY
;AND STORE THAT IN A 2 BYTE NSP FIELD.
;CALL:
; R2,R3/POINT TO NCL MESSAGE
; R4,R5/POINT TO NSP MESSAGE
; JSR PC,NSPOCP
; R0/TERMINATING CHARACTER WITH EXTENSIBLE BIT STILL ON
NSPOCP: CLR R1 ;ACCUMULATE NUMBER HERE
10$: JSR PC,GETBYT ;GET A DIGIT
CMPB R0,#'0!200 ;SMALLER THAN A 0?
BLO 20$ ;YES, TERMINATOR
CMPB R0,#'7!200 ;BIGGER THAN A 7?
BHI 20$ ;YES, ALSO MUST BE A TERMINATOR
ASL R1 ;SHIFT
ASL R1 ;A
ASL R1 ;DIGIT
BIC #^C7,R0 ;EXTRACT BINARY VALUE
ADD R0,R1 ; AND MERGE WITH WHAT WAS THERE
BR 10$ ;BACK FOR MORE
20$: SAVE <R0> ;MUST RETURN TERMINATOR TO CALLER
MOV R1,R0 ;COPY TO RIGHT REGISTER
JSR PC,NSPO2B ;PUT GROUP OR USER
MOV (SP)+,R0 ;RESTORE TERMINATOR
RTS PC ;GIVE TO CALLER
;ROUTINE TO PUT A 16 BIT VALUE INTO A NSP MESSAGE AS TWO BYTES
;CALL:
; R0/VALUE
; JSR PC,NSPO2B
; R0,R1 RETURNED UNCHANGED
NSPO2B: JSR PC,NSPPBY
SWAB R0 ; GET HIGH HALF
JSR PC,NSPPBY
SWAB R0 ;RETURN R0 UNCHANGED
RTS PC
.SBTTL NCL BUILD SUBROUTINES
;ROUTINE TO CALL WHEN PROCESSING A MESSAGE AND WANT TO GENERATE A REPLY
;TO THE ORIGINAL SENDER. ENTER AT NSPLTL IF NCL, NSPPTP IF NSP. PRESENTLY
;BOTH ROUTINES ARE THE SAME.
NSPPTP:
NSPLTL: MOV SNA,R0 ;EXCHANGE SNA AND DNA
MOV DNA,SNA
MOV R0,DNA
RTS PC
;ROUTINE CALLED TO BUILD THE HEADER OF A NCL NUMBERED CONTROL
;MESSAGE
;CALL:
; R0/ADDRESS OF FIRST CHUNK OF OLD MESSAGE IF CALLING NSPBN1
; R1/MESSAGE TYPE:
; IF B15 SET, THEN NCT BITS,
; IF B15 CLEAR THEN NUMBERED CONTROL MSG TYPE
; JSR PC,NSPBNC ;TO ALLOCATE NEW MESSAGE
; JSR PC,NSPBN1 ;IF OLD MESSAGE EXISTS
; R4/COUNT; R5/ADDR FOR NSPPBY AND FRIENDS
; NSPCNT,NSPADR POINTING TO END OF HEADER, USED BY NSPSNC
NSPBNC: JSR PC,GETCNK ;GET A CHUNK TO START THE MESSAGE
NSPBN2: MOV R0,NSPLMG ;REMEMBER START OF NCL MESSAGE
BNE NSPBN1 ;FILL IT
SEC ;SAY ERROR
RTS PC
NSPBN1: MOV NSPLMG,R0 ;GET START OF NCL MESSAGE
MOV R1,-(SP) ;SAVE CONTROL MSG TYPE
BMI 10$ ;MINUS MEANS DATA MESSAGE
CLR R1 ;TO TELL NCLBM1 WE WANT A NUMBERED MESSAGE
10$: SAVE <R2,R3> ;PROTECT POINTERS TO MESSAGE WE MAY BE READING
JSR PC,NCLBM1 ;WRITE HEADER
TST (SP)+ ;REMOVE START OF MESSAGE NCLBM1 HID ON STACK
MOV R2,R4 ;MOVE STRING POINTER TO OUTPUT ACS
MOV R3,R5
RESTORE <R3,R2> ;RESTORE POINTERS TO POSSIBLE INPUT MESSAGE
MOV (SP)+,R0 ;RECOVER MESSAGE TYPE
BMI 20$ ;MINUS MEANS DATA, SO WE'RE DONE
MOV R0,-(SP) ;SAVE IT A WHILE LONGER
CLR R0
JSR PC,NSPPBY ;PUT IN ZERO DLA
MOV R4,NSPCNT ;REMEMBER WHERE COUNT FIELD IS
MOV R5,NSPADR
JSR PC,NSPPBY ;HOLD A BYTE FOR COUNT LATER
CLR R4 ;REINIT COUNT
MOV (SP)+,R0 ;GET BACK MESSAGE TYPE
JSR PC,NSPPBY ;STORE AND RETURN. CALL NSPSNC TO SEND
20$: RTS PC
;ROUTINE TO SEND NCL MESSAGE TO DNNCL. CALL AFTER LAST BYTE IS PUT
;IN NCL MESSAGE AND READY TO SEND. THIS WILL FIX THE COUNT FIELD AND PASS
;IT ON.
;CALL:
; NSPCNT/ LENGTH OF CONTROL SUBMESSAGE
; NSPADR/ ADDR OF COUNT FIELD
; JSR PC,NSPSNC
; <MESSAGE GIVEN TO NCL>
NSPSNC: ASSERT #^C177 CLEAR IN R4 ;CHECK SIZE
MOVB R4,@NSPADR ;PUT COUNT IN MESSAGE
INC R4 ;THAT PLUS LENGTH OF COUNT FIELD
ADD NSPCNT,R4 ; PLUS LENGTH OF HEADER IS LENGTH OF WHOLE
NSPSDL: MOV NSPLMG,R0 ;GET START OF MESSAGE
MOV R4,CN.LEN(R0) ;SAVE LENGTH FOR DDCMP
.IIF NE FTDCPT,JSR PC,NSPOTL ;PRINT IT FIRST
JSR PC,NCLIN1 ;SEND IT
RTS PC
.SBTTL RANDOM SUBROUTINES
;ROUTINE TO STORE EXTENSIBLE FILED IN A LITTLE SPACE AS POSSIBLE.
;THIS WILL HANDLE UP TO 16 BITS OF EXTENSIBLE DATA.
NSPPEX: BIT #^C177,R0 ;MORE THAN 7 BITS?
BEQ NSPPBY ;NO, JUST USE ONE BYTE
MOV R0,-(SP) ;SAVE VALUE
JSR PC,NSPEXB ;PUT BYTE WITH EXTENSIBLE BIT ON
MOV (SP)+,R0 ;GET VALUE BACK
SWAB R0 ;SHIFTING 7 BITS IS A TASK AN -11
ASL R0 ; JUST WASN'T DESIGNED TO DO....
ADC R0 ;DON'T LET THAT HIGH BIT ESCAPE!
BIC #^C777,R0 ;CLEAR BITS WE'VE DONE
BR NSPPEX ;DO NEXT BYTE OR TWO
NSPEXB: ;TURN ON EXTENSIBLE BIT AND PUT INTO MESSAGE
BIS #200,R0 ;TURN ON EXTENSIBLE BIT
;ROUTINE TO PUT A BYTE OF DATA INTO THE OUTPUT MESSAGE. EXTRA CHUNKS WILL BE
;ALLOCATED AS NECESSARY.
;CALL:
; R0/BYTE TO BE OUTPUT
; JSR PC,NSPPBY
; R0-R3 PRESERVED
NSPPBY: BIT #CNKSIZ-1,R5 ;IS IT NOW POINTING PAST END?
BNE 20$ ;NO, OKAY TO STORE BYTE
MOV R0,-(SP) ;SAVE DATA ON STACK
MOV -CNKSIZ(R5),R0 ;IS THERE A CHUNK ALREADY?
BNE 10$ ;YES, USE IT
JSR PC,ERSGET ;GET A CHUNK IF AT ALL POSSIBLE
MOV R0,-CNKSIZ(R5) ;LINK NEW CHUNK TO OLD
10$: MOV R0,R5 ;POINT TO NEW CHUNK
TST (R5)+ ;CLEAR ITS FOWARD LINK
MOV (SP)+,R0 ;RESTORE DATA
20$: MOVB R0,(R5)+ ;PUT BYTE AT POINTER AND ADVANCE POINTER
INC R4 ;INCREMENT BYTE COUNT
RTS PC ;RETURN
;ROUTINE TO COMPARE TWO EXTENSIBLE STRINGS
;CALL:
; R0/ ADDR OF ONE STRING
; R1/ ADDR OF OTHER STRING
; JSR PC,NSPCEA
; BCS MISMATCH
NSPCEA: CMPB (R0)+,@R1 ;COMPARE FIRST TWO BYTES
BNE 10$ ;MISMATCH, SET CARRY AND RETURN
TSTB (R1)+ ;MORE OF STRING TO LOOK AT?
BMI NSPCEA ;YES
RTS PC ;RETURN CARRY CLEAR
10$: SEC ;SET CARRY BIT
RTS PC
;ROUTINE TO CALL REST OF CALLER FOR EACK NSP LOGICAL LINK IN WE KNOW
;OPERATION IS BY RUNNING DOWN THE LIST OF LEBS FOUND IN THE LIST OF LINE BLOCKS
;AND PASSING THEM TO THE CALLER OF THIS ROUTINE. WHEN THE SEARCH IS
;COMPLETE WE RETURN TO THE CALLER'S CALLER TO AVOID PASSING A BAD LEB TO THE
;CALLER. NOTE THAT THERE IS NO WAY TO CALL THIS WITH DATA SAVED
;ON THE STACK.
NSPALL: SAVE <J,SB>
MOV #FRSTLB,J ;HAVE TO SCAN ALL LINE BLOCKS
10$: MOV LB.LNK(J),J ; TO FIND LEBS THAT CALLER MAY HAVE TO PROCESS
BEQ 90$ ;NO MORE LINE BLOCKS
MOV LB.LEB(J),R1 ;GET LEB LIST FOR THIS LINE BLOCK
BEQ 10$ ;NO LIST
MOV J,NSPLB ;ROUTINES WE CALL LOOK IN MEMORY
20$: MOV R1,NSPLEB ;ROUTINES LOOK HERE
JSR PC,@4(SP) ;CALL CALLER
MOV NSPLEB,R1 ;R1 PROBABLY GOT CLOBBERED...
30$: MOV LE.LNK(R1),R1 ;STEP TO NEXT LEB
BNE 20$ ;LOOP IF MORE TO LOOK AT
MOV NSPLB,J ;J PROBABLY GOT CLOBBERED TOO
BR 10$ ;LOOP ON LINE BLOCKS
90$: RESTORE <SB,J> ;CALLER NEEDS THESE
TST (SP)+ ;REMOVE CALLER'S RETURN ADDRESS
RTS PC ;RETURN TO CALLER'S CALLER
.SBTTL LEB (LINK ENTRY BLOCK) CONTROL
;ROUTINE TO MATCH THE PASSED NSP DSTADDR OR NCL DLA WITH ONE OF THE ACTIVE
;LEBS. THE LEB NUMBER IS EXTRACTED FROM THE LINK ADDRESS (SEE NSPALB FOR FORMAT)
;AND IS CONVERTED INTO THE LEB ADDRESS. IF THE LEB IS NOT ASSIGNED, WHICH
;GENERALLY MEANS THAT THE SENDER IS CONFUSED, IT WILL BE ASSIGNED AND THE
;CALLER WILL DECIDE WHETHER TO IGNORE IT OR RETURN A DISCONNECT. IF THE LEB
;IS ALREADY ASSIGNED, WE VERIFY THAT THE COMPLETE ADDRESS MATCHES AND THAT
;THE NCL SCBS MATCH BEFORE RETURNING THE LEB TO THE CALLER. IF THE MATCH FAILS
;OR IF THE LEB IS NOT ADDRESSIBLE, WE RETURN THE MAGIC LEB SO THAT MESSAGE
;PROCESSING CAN CONTINUE EVEN THOUGH WE MAY NOT BE ABLE TO REPLY.
;CALL:
; R0/ DLA OR DSTADDR
; JSR PC,NSPSLB
; R1/ LEB ADDRESS MATCHED OR ASSIGNED
; NSPLEB/ DITTO
NSPSLB: SAVE <R0> ;SAVE OUR SIDE LINK ADDRESS
MOV #LEB1-LE.SIZ,R1 ;CAN'T DO A MULTIPLY, SO LETS ADD A LOT
BIC #^C<LED.OF>,R0 ;EXTRACT LEB NUMBER
BEQ 40$ ;ZERO ISN'T LEGAL
10$: ADD #LE.SIZ,R1 ;STEP TO NEXT
SOB R0,10$ ;COUNT SOME MORE
TST LE.SCB(R1) ;ASSIGNED?
BEQ 50$ ;NO, TRY TO ASSIGN IT (CALLERS WILL HANDLE)
CMP @SP,LE.DCP(R1) ;ADDRESSES BETTER MATCH
BNE 40$ ;CAN'T HANDLE, RETURN MAGIC LEB
TST NSPSB ;KNOW WHO NCL END IS YET?
BEQ 30$ ;NO, USE ADDRESS IN LEB
CMP LE.SCB(R1),NSPSB ;NCL SIDES MATCH?
BNE 40$ ;NO, CAN'T HANDLE, RETURN MAGIC
30$: MOV LE.SCB(R1),NSPSB ;ASSUME THIS IS NCL SIDE
TST DNA ;HAVE WE FIGURED OUT A DESTINATION YET?
BNE 60$ ;YES
MOV LE.SCB(R1),DNA ;HERE IF PROCESSING A NSP MESSAGE (NCL
; MESSAGES ALWAYS HAVE ROUTING HEADERS)
; THAT DOES NOT HAVE A ROUTING HEADER. THEREFORE
; THE DESTINATION MUST BE THE NCL SIDE. THIS
; INSTRUCTION IS USUALLY HIT FOR DATA MESSAGES
; AND ITS RELATIVES
BR 60$ ;CLEANUP AND RETURN
40$: MOV #LEBMGC,R1 ;HAVE TO RETURN MAGIC LEB
50$: JSR PC,NSPAL1 ;ASSIGN LEB
MOV @SP,LE.DCP(R1) ;USE MESSAGE'S ADDRESS FOR OURS
60$: MOV R1,NSPLEB ;CALLERS NEED THIS HERE
RESTORE <R0> ;RECOVER TRUE LINK ADDRESS
RTS PC
;ROUTINE TO ALLOCATE A FREE LEB TO A NEW LOGICAL LINK. CALLED BY THE CONNECT
;INITIATE PROCESSERS, THIS ROUTINE SEARCHES FOR A FREE LEB, CLEARS OUT OLD
;INFORMATION AND FILLS IN WHAT IT CAN INCLUDING A DCP LINK ADDRESS. THIS THIRD
;ADDRESS SERVES TWO PURPOSES. FIRST, IF WE PASSED NCL LINK ADDRESSES TO THE
;NSP NODE, A CASE COULD ARISE WHERE TWO LINKS COULD SHARE THE SAME NCL LINK
;ADDRESS BY TERMINATING IN DIFFERENT NCL NODES. THIS INTRODUCES AMBIGUITIES
;IF WE RECEIVE A MESSAGE FROM NSP WITHOUT A ROUTING HEADER FOR ONE OF THESE
;LINKS. THE DCP LINK ADDRESS SOLVES THE PROBLEM BY GUARANTEEING A UNIQUE
;LINK ADDRESS FOR EACH LINK IN USE. SECOND, THE LINK ADDRESS CAN BE MADE
;TO FIT THE RESTRICTIONS OF BOTH NCL AND NSP, I. E. A LOW REUSE RATE FOR NSP
;AND A 14 BIT LENGTH FOR NCL. THE HIGH 2 BITS ARE 0, THE NEXT N INCREMENT
;EACH TIME THAT LEB IS ASSIGNED, AND THE LOW 14-N BITS ARE THE LEB NUMBER. IF
;ALL LEBS ARE IN USE, THE MAGIC LEB IS RETURNED BUT NOT LINKED INTO A LBLK
;LIST. THIS IS SO IT IS ALWAYS AVAILABLE TO BE RETURNED. THE PURPOSE OF
;THE MAGIC LEB IS TO PROVIDE A PIECE OF LINK DATA BASE TO ANY CALLER SO IT
;CAN CONTINUE TO PROCESS THE MESSAGE AS NEARLY LIKE ANY OTHER MESSAGE AS
;POSSIBLE.
NSPALB: MOV #LEB1,R1 ;TRY TO FIND A FREE LEB
10$: TST LE.SCB(R1) ;FREE?
BEQ NSPAL1 ;YES, USE IT
ADD #LE.SIZ,R1 ;STEP TO NEXT
CMP R1,#LEBEND ;TOO FAR?
BLO 10$ ;NO, TRY NEXT
MOV #LEBMGC,R1 ;ALL IN USE, RETURN THE MAGIC LEB
NSPAL1: JSR PC,NSPZLB ;CLEAR OUT WHOLE THING
CMP R1,#LEBMGC ;MAGIC LEB?
BEQ 20$ ;YES, DON'T LINK IT
SAVE <J> ;HAVE TO PRESERVE J HERE
ADD #LED.IN,LE.DCP(R1) ;CREATE NEXT FREE LINK ADDRESS
BIC #140000,LE.DCP(R1) ;RESTRICT RANGE FOR NCL (NETSER'S) SAKE
MOV NSPLB,J ;HAVE TO REFERENCE LBLK
MOV LB.LEB(J),LE.LNK(R1) ;PUT OLD LEB LIST AFTER NEW GUY
MOV R1,LB.LEB(J) ;MAKE NEW LIST WITH NEW GUY AT HEAD
RESTORE <J>
20$: MOV NSPSB,LE.SCB(R1) ;TRY TO ASSIGN IT
BNE 30$ ;OKAY IF WE ASSIGNED IT
COM LE.SCB(R1) ;DON'T KNOW THE NCL SIDE YET, MAKE IT NONZERO ANYWAY
30$: MOV R1,NSPLEB ;SAVE FOR FUTURE USERS
CMP R1,#LEBMGC+1 ;SET CARRY IF MAGIC LEB WITH A MAGIC INSTRUCTION
RTS PC ; ADDRESS OF CMP INSTRUCTION FROM STACK
;ROUTINE TO FREE A LEB WE NO LONGER NEED. THIS ROUTINE FREES THE LEB
;CURRENTLY IN USE. (PROBABLY THE LAST ON NSPSL? RETURNED). IT ALSO FREES
;ANY MESSAGES STILL ON THE OUTPUT BUT NOT ACKNOWLEDGED QUEUES SINCE OTHERWISE
;THEIR SPACE WILL BECOME DEALLOCATED.
NSPFLB: SAVE <R0> ;A COUPLE CALLERS REALLY WANT THIS INTACT
MOV NSPLEB,R1 ;GET LEB EVERYONE'S BEEN USING
MOV NSPLB,R0 ;MAKE A PSEUDO LEB POINTER
ADD #LB.LEB-LE.LNK,R0 ; SO LOOP CAN HANDLE IT
10$: CMP LE.LNK(R0),R1 ;IS NEXT LEB THE ONE WE'RE FREEING?
BEQ 20$ ;YES, DIDDLE LINKS
MOV LE.LNK(R0),R0 ;NOT YET, STEP TO NEXT
BNE 10$ ;KEEP LOOKING
CMP R1,#LEBMGC ;MAGIC LEB?
BEQ 30$ ;NO WONDER WE DIDN'T FIND IT
STOPCD DCP ;SHOULDN'T GET HERE
20$: MOV LE.LNK(R1),LE.LNK(R0) ;REMOVE LEB FROM LIST
30$: MOV LE.OQL(R1),R0 ;GET LIST OF UNACKED LS/INT MSGS
JSR PC,NSPFL0 ;AND FREE THEM
MOV LE.OQD(R1),R0 ;ALSO FREE UNACKED DATA MESSAGES
JSR PC,NSPFL0
CLR LE.SCB(R1) ;LET SOMEONE ELSE GET LEB
RESTORE <R0>
RTS PC
;ROUTINE TO RELEASE LIST OF MESSAGES
NSPFL0: BEQ 10$ ;NOTHING TO DO IF NONE ALREADY
MOV CN.MLK(R0),-(SP) ;SAVE ADDRESS OF NEXT
JSR PC,FRECKS ;RELEASE FIRST MSG
MOV (SP)+,R0 ;GET NEXT
BNE NSPFL0 ;RELEASE IT TOO
10$: RTS PC
;ROUTINE TO CLEAR OUT THE LEB POINTED AT BY R1. MAINLY CALLED BY NSPSL? TO
;CLEAR A LEB BEFORE RETURNING IT TO THE CALLER.
NSPZLB: SAVE <LE.DCP(R1),R1>
MOV #<<LE.SIZ+1>/2>,R0 ;NUMBER OF WORDS TO STUFF
10$: CLR (R1)+
SOB R0,10$
RESTORE <R1,LE.DCP(R1)>
RTS PC
.SBTTL LEB QUEUING ROUTINES
;THESE ROUTINES ARE CALLED WHENVER A PIECE OF CODE WANTS SOMETHING PERFORMED
;AT LOW LEVEL, USUALLY SOMETHING THAT NEEDS VERY LITTLE DATA ASSOCIATED WITH
;WITH THE ACTION AND MUST BE DONE SOMETIME, EVEN IF THERE IS NO MEMORY
;AVAILABLE NOW. EACH ACTION HAS ITS OWN REQUEST BIT AND THE QUEUING MECHANISM
;HAS A GLOBAL BIT TO KEEP LEBS QUEUED ONLY ONCE (EXACTLY LIKE ALL THE OTHER
;CIRCULAR QUEUES IN THE DN8X). BITS ARE CHECKED BY THE NSPCHK ROUTINE AND IF
;THE ACTIONS CAN BE PERFORMED, THE BITS WILL BE TURNED OFF. SOME BITS,
;NOTABLY THE MESSAGE ACKNOWLEDGEMENT BITS, ARE TURNED OFF IF THERE IS NO NEED
;TO PERFORM THE FUNCTION ANY MORE.
;ROUTINES:
;NSPQDA REQUEST A DATA ACK BE SENT
;NSPQDN REQUEST A DATA NAK BE SENT
;NSPQLA REQUEST A LS/INT ACK BE SENT
;NSPQLN REQUEST A LS/INT NAK BE SENT
;NSPQDR REQUEST ONE MORE DATA REQUEST BE SENT TO THE NCL NODE. THIS IS
; IS USED BY CODE THAT IMPLEMENTS MESSAGE REQUESTING AND NO REQUESTING
; NSPCNR IS SPECIAL CODE TO SEND INITIAL DRQS.
;NSPQDC REQUEST A DC MESSAGE BE SENT TO THE NSP NODE. R0 SHOULD BE SETUP
; WITH A PLAUSIBLE REASON CODE WHICH WILL BE USED IF ONE HASN'T
; ALREADY BEEN STORED IN THE LEB.
;NSPQLS THE CODE TRIES TO KEEP THE NSP SIDE ALWAYS READY TO SEND ANOTHER
; INTERRUPT MESSAGE IF IT SO DESIRES. THIS IS CALLED EVERYTIME
; WE RECEIVE AN INTERRUPT MESSAGE TO REQUEST ANOTHER.
.ENABL LSB
NSPQDA: MOV #LES.DA,R0 ;TO SEND A DATA ACK
BR 10$ ;SET BIT AND QUEUE LBLK
NSPQDN: MOV #LES.DN,R0 ;DATA NAK
BR 10$
NSPQLA: MOV #LES.LA,R0 ;LS/INT ACK
BR 10$
NSPQLN: MOV #LES.LN,R0 ;LS/INT NAK
BR 10$
NSPCNR: BIT #LES.NR,@R1 ;IS THIS LINK USING NO REQUESTING?
BEQ 99$ ;USING SEGMENT OR MESSAGE REQUESTS, SKIP THIS
INCB LE.ODR(R1) ;START LINK OFF WITH 2 DATA REQUESTS
NSPQDR: INCB LE.ODR(R1) ;INCREMENT NUMBER OF FREE DATA REQS WE HAVE TO SEND
MOV #LES.DR,R0 ;THEN REMIND LOW LEVEL TO REQUEST THEM
BR 10$
NSPQDC: MOV NSPLEB,R1 ;CALLERS EXPECT THIS BACK
TSTB LE.RSN(R1) ;HAS A REASON ALREADY BEEN SPECIFIED?
BNE 5$ ;YES, DON'T USE NEW ONE
MOVB R0,LE.RSN(R1) ;SAVE IT
5$: MOV #LES.DC,R0 ;REMINDER FOR LOW LEVEL
BR 10$
NSPQLS: MOV #LES.LS,R0 ;LINK SERVICES
10$: BIS R0,@NSPLEB ;LIGHT BIT IN LEB
NSPQ: SAVE <J,R2> ;SAVE REGS
MOV NSPLB,J ;POINT TO LINE BLOCK
PIOFF ;TURN OFF INTERRUPTS
BIT #LBS.NQ,LB.NSS(J) ;ALREADY SOMETHING QUEUED?
BNE 30$ ;YES, EXIT
BIS #LBS.NQ,LB.NSS(J) ;NO, INDICATE THAT NOW THERE IS
CMP NS.PTR,#<NS.QUE+NS.SIZ> ;IS PUTTER PAST END?
BLO 20$ ;NO, BRANCH
MOV #NS.QUE,NS.PTR ;YES, RESET TO BEGINNING
20$: ;HERE TO ACTUALLY PUT DATA INTO QUEUE
MOV J,@NS.PTR ;LINE BLOCK ADDRESS AT PUTTER
ADD #2,NS.PTR ;ADVANCE PUTTER
30$: ;HERE WHEN DONE
PION ;ALLOW INTERRUPTS AGAIN
RESTORE <R2,J> ;RESTORE REGS
99$: RTS PC ;RETURN
.DSABL LSB
.SBTTL DEBUGGING ROUTINES
.IF NE FTDCPT ;ASSEMBLE IF WANT MESSAGE TRACE
;THESE ROUTINES ARE MEANT FOR DEBUGGING ONLY AND SHOULD NOT BE USED DURING
;NORMAL OPERATION AS THEY CAN WIPE OUT FREE MEMORY IN NOTHING FLAT.
;CONTROLLED BY THE CONTENTS OF NSPTFG, THEY WILL PRINT MESSAGES RECEIVED AS FOLLOWS:
;BIT MESSAGE CASE
;1 NSP RECEPTION
;2 NSP TRANSMIT DONE (AT NSPOBD, NOT DDQNSP!)
;4 NCL RECEPTION
;10 NCL TRANSMISSION
NSPBTP: BIT #5,@(PC)+ ;ONLY IF INTERESTED IN NSP/NCL INPUT
NSPFGA: .WORD NSPTFG ;PATCH THIS TO POINT AT SWITCH REG
BEQ NSPTYR
MOV #NSPBT0,R1 ;GET MESSAGE ABOUT BAD MESSAGE
MOV #CT0DDB,J ;PRINT ON CTY
10$: MOVB (R1)+,R0 ;GET NEXT CHARACTER
BEQ NSPTYR ;STOP ON NULL. DON'T BOTHER TO CALL BEGXMT...
JSR PC,QTYCHR
BR 10$ ;DO REST
NSPBT0: .ASCIZ \NSPBTP CALLED\<15><12>
NSPITP: BIT #1,@NSPFGA ;INPUT BIT ON IN FLAG WORD?
BEQ NSPTYR
JSR R1,NSPTYP
.ASCIZ \NSP RCV \
.EVEN
NSPOTP: BIT #2,@NSPFGA ;OUTPUT BIT ON?
BEQ NSPTYR
JSR R1,NSPTYP
.ASCIZ \NSP XMT \
.EVEN
NSPITL: BIT #4,@NSPFGA
BEQ NSPTYR
JSR R1,NSPTYP
.ASCIZ \NCL REC \
.EVEN
NSPOTL: BIT #10,@NSPFGA
BEQ NSPTYR
JSR R1,NSPTYP
.ASCIZ \NCL XMT \
.EVEN
;STILL IN .IF NE FTDCPT
NSPTYP: SAVE <R0,R2,R3,R4,R5>
MOV #CT0DDB,J ;OUTPUT TO CTY
JSR PC,NSPCRL ;START OFF WITH A BLANK LINE
10$: MOVB (R1)+,R0
BEQ 20$
JSR PC,QTYCHR
BR 10$
20$: MOV 10(SP),R0
MOV CN.LEN(R0),R2 ;SETUP GET POINTERS
MOV R0,R3 ;COPY MESSAGE START
ADD #CN.NCT,R3 ;POINT TO FIRST BYTE
30$: JSR PC,GETBYT ;GET A CHAR
SAVE <R2,R3> ;DISTRUST QTYCHR
MOV #214,R1 ;MAGIC NUMBER
SEC
40$: ROLB R0 ;GET A BIT
50$: ROLB R1 ;PUT IN CHAR
BCS 60$ ;DO IT AGAIN
SAVE <R0> ;SAVE REST OF BYTE
MOV R1,R0 ;PUT WHERE QTYCHR EXPECTS
JSR PC,QTYCHR ;PUT IN CTY BUFFER
RESTORE <R0> ;RECOVER REST OF BYTE
MOV #306,R1 ;MORE MAGIC
60$: ASLB R0 ;TIME TO STOP?
BEQ 70$ ;YES, DO NEXT BYTE
BR 50$ ;NOT YET
70$: MOV #40,R0 ;NEED SPACE BETWEEN BYTES
JSR PC,QTYCHR
RESTORE <R3,R2>
BNE 30$ ;LOOP WHILE MORE TO DO
JSR PC,NSPCRL ;AND END WITH CRLF
JSR PC,BEGXMT ;START OUTPUT
RESTORE <R5,R4,R3,R2,R0,R1>
NSPTYR: RTS PC
NSPCRL: SAVE <R2,R3>
MOV #15,R0
JSR PC,QTYCHR
MOV #12,R0
JSR PC,QTYCHR
RESTORE <R3,R2>
RTS PC
.ENDC ;.IF NE FTDCPT
.SBTTL NSPDAT WORKING DATA AREAS
;WORD DATA:
NSPADR: .BLKW 1 ;ADDRESS OF COUNT FIELD TO FILL WHEN FINISHED WITH MESSAGE
NSPCNT: .WORD 0 ;COUNT OF NCL SUBMESSAGE
NSPPMG: .WORD 0 ;ADDRESS OF MESSAGE FOR NSP
NSPLMG: .BLKW 1 ;ADDRESS OF MESSAGE FOR/FROM NCL
NSPLEB: .BLKW 1 ;ADDR OF LEB FOR THE LINK FOR CURRENT MSG
NSPLIX: .BLKW 1 ;LOC OF LE.LID OR LE.LIL TO INCREMENT AFTER NSP PROCESSING
NSPLB: .WORD 0 ;ADDRESS OF LINE BLOCK FOR DCP LINE
NSPSP: .BLKW 1 ;SP TO RESTORE IF WE FIND MSG FORMAT ERROR
NSPSB: .BLKW 1 ;NCL NODE ASSOCIATED WITH MESSAGE
NSPOQL: .BLKW 2 ;QUEUE HEADER OF NCL MESSAGES WAITING TO BE TRANSLATED.
; THE FIRST WORD IS A LIST HEAD, THE SECOND POINTS
; TO THE LAST CHUNK IN THE LIST, IF ANY.
.IIF NE,FTDCPT,NSPTFG: .WORD FTDCPT ;PATCH THIS TO BE WHICH MESSAGES YOU WANT LOGGED, OR
; PATCH NSPFGA TO POINT TO THE CONSOLE SWITCHES
; IF YOU HAVE A PDP-11/40 AND YOU CAN CONTROL WHAT
; PRINTS WITH THEM. (SWITCH REG IS LOC 177570)
;BYTE DATA:
NSPLPN: .BLKB 12. ;TEMPORARY STORAGE FOR PROCESS NAME
NSPDNA: .BLKB SNMSIZ ;DESTINATION OF NSP MESSAGE
NSPSNA: .BLKB SNMSIZ ;SOURCE OF NSP MESSAGE
NSPDAP: .BLKB 1 ;TYPE DAP TO SEND TO NCL
.EVEN
.ENDC;.IF NE FTDCP3