Trailing-Edge
-
PDP-10 Archives
-
BB-X140B-BB_1986
-
10,7/703anf/dndcp4.p11
There are 3 other files named dndcp4.p11 in the archive. Click here to see a list.
.SBTTL DECNET COMPATIBLE PORT (MARK IV) FOR NSP 15 JAN 85
.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=036 ;FILE EDIT NUMBER
;RDH .PRINT VRNSP3 ;VERSION 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 OR 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
.SBTTL CONNECT MESSAGE TRANSLATION CONVENTIONS
.REPT 0
NSP -> NCL
CI
THE "DPN" OF THE NCL CONNECT MESSAGE IS CONSTRUCTED FROM THE
VARIOUS FIELDS OF THE NSP MESSAGE AS FOLLOWS
<0>DST-OBJ<0>SRC-OBJ<0>RQID<0>PSWD<0>ACCT<0>USRDATA<0>
THE "SPN" FIELD IS USELESS
CC
THE "DPN" FIELD IS USELESS
THE "SPN" FIELD IS OF THE FORM
<0>USER-DATA<0>
NCL -> NSP
CI
THE DPN, IF IT'S A "TSK" OBJECT GETS PARSED AS
<0>DST-OBJ<0>SRC-OBJ<0>RQID<0>PSWD<0>ACCT<0>USRDATA<0>
AND IS USED TO BUILD THE NSP CONNECT-INIT
THS "SPN" IS IGNORED.
CC
THE "DPN" IS IGNORED
THE "SPN" IS PARSED AS
<0>USER-DATA<0>
AND FORMS THE USER DATA FIELD OF THE CONNECT-CONFIRM
.ENDR
.REPT 0
HENCE, ONE SHOULD USE THE TSK. UUO AS FOLLOWS.
PASSIVE CASE.
NPD1 <- THE "USER DATA" TO RETURN UPON A SUCCESSFUL CONNECT
NPD2 <- THE "PATTERN" TO MATCH (NULLS SEPARATE THE FIELDS)
AFTER A SUCCESSFUL CONNECT,
NPD1 <- THE "ACTUAL" THAT MATCHED THE "PATTERN"
NPD2 <- RANDOM TRASH CONSTRUCTED BY THE PORT
ACTIVE CASE
NPD1 <- GETS IGNORED BY THE PORT
NPD2 <- IS THE BIG MESS (PUNCTUATED BY ZEROS) TO SEND
AFTER A SUCCESSFUL CONNECTION
NPD1 <- TRASH CONSTRUCTED BY THE PORT
NPD2 <- THE CONNECT CONFIRM "USER-DATA"
.ENDR
.REPT 0
This version of the DCP node-init's as a Phase II DECnet node
The NSPLST macro is
DCP4LN QLN,QOB,QVN,QVS,QHN,QHS,QCN
Where
QLN Sync line number
QOB Object-type,count pairs, enclosed in <>
QVN ANF node number to present DCP node
QVS ANF node name to present DCP node
QHN DECNET node number to claim to be
QHS DECNET node name to claim to be
QCN ANF node number to receive DECNET connects
The following rules hold.
1) All NSP connect init's get sent to the node "QCN"
2) All NCL connects will appear to the NSP system to come
from the node QHN/QHS, but the DCP will remember who
really sent them and process all data on that link
accordingly.
.ENDR
.IF EQ,FTDCP4
.PRINT 7;Wrong version of DCP software loaded!!!!!!
.ENDC
.SBTTL MACROS
.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
ND NSPMAX,MSGMAX ;MAXIMUM NSP MESSAGE SIZE (AND YOU TAKES YOUR
; CHANCES IF NSPMAX .NE. MSGMAX!!!)
ND 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 IN 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 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 DCP4LN,QLN,QOB,QVN,QVS,QHN,QHS,QCN
.IRP Q,<QOB>
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.RVF =1 ;REQUEST VERIFICATION MESSAGE
;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
CMP @R0,#LES.DR ;IF THIS IS FOR SENDING NCL DRQS
BEQ 35$ ; THEN LET THAT ROUTINE ALLOCATE THE MSG
JSR PC,NSPBMG ;THE REST ALWAYS NEED A NSP MESSAGE
BCS 40$ ;NO MEMORY - DEFER UNTIL THERE IS SOME
35$: 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
MOV J,NSPLB ;REMEMBER THIS FOR SENDING NODE INIT
JSR PC,NSPXNI ;SEND A NODE INIT
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 CLEAR 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
.IF NE FTDCPT
MOV NSPPMG,R0 ;GIVE THE PRINT ROUTINES SOMETHING TO PRINT
JSR PC,NSPBTP ;NOTE WE DISLIKED IT
.ENDC
MOV NSPSP,SP ;RESTORE STACK TO NSPINP LEVEL
NSPIFL: MOV NSPPMG,R0 ;CHANGE THIS TO POSSIBLY
CLR NSPPMG ;MAKE SURE WE DON'T POINT
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.
.ENABL LSB
NSPIRT: BIT #NM.RFMT/4,R0 ;ASCII ROUTING HEADERS?
BEQ 20$ ;BINARY - CAN'T HANDLE!
BIT #NM.EFMT/4,R0 ;WHICH VERSION OF ROUTING FORMAT?
BNE 20$ ;ONLY 0 IS DEFINED
MOV #NSPDNA,R0 ;POINT TO DESTINATION STRING
JSR PC,NSPIIM ;COPY THE IMAGE NAME INTO NSPDNA
.WORD SNMSIZ ;MAX OF THIS LONG
MOV #NSPDNA,R0 ;GET ADDRESS OF DNA AGAIN
MOV NSPLB,R1 ;ADDRESS OF LINE BLOCK
ADD #LB.HNM,R1 ;GET ADDRESS OF "OUR" NAME
JSR PC,NSPCEA ;COMPARE THE STRINGS
BCS 20$ ;IF NOT FOR US, TOSS IT.
CLR DNA ;NO DNA SET UP YET.
CLR DNAOFF ; NOR OFFSET EITHER
MOV #NSPSNA,R0 ;DO SAME WITH SOURCE NODE
JSR PC,NSPIR1 ;FIND SOURCE NODE
MOV SB,SNA
MOV R0,SNAOFF
RTS PC ;DONE
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
.EVEN
.DSABL LSB
.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
;RDH BIC #^C77,R0 ;LIMIT TO 6 BITS (ALA REST OF OUR NET)
;RDH BNE 20$ ;STILL SOMETHING LEFT, USE IT
MOVB LB.VNN(J),R0 ;MUST BE AN END NODE, GET USER SUPPLIED NUMBER
ASSERT NE ;BETTER BE THERE!
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
JSR PC,GETBYT ;GET LENGTH OF ASCII NAME (IF ANY)
MOV R0,R1 ;SAVE IN R1 FOR GETBYT CALLS
BEQ 42$ ;DONE IF NO STRING PRESENT
41$: JSR PC,GETBYT ;READ ASCII NAME BYTE FROM NSP MESSAGE
SOB R1,41$ ;LOOP FOR REST OF THE NAME FIELD
42$: MOV SB,R0 ;GET ADDR OF SCB FOR NSP NODE
ADD #SB.SNM,R0 ;POINT TO NAME AREA
MOV J,R1 ;ADDRESS OF LINE BLOCK
ADD #LB.VNM,R1 ;OFFSET TO NAME STRING
MOV #SNMSIZ,-(SP) ;SIZE OF NAME STRING
44$: MOVB (R1)+,(R0)+ ;COPY ANF NAME TO USE FOR DECNET NODE
DEC (SP) ;COUNT DOWN STRING
BGT 44$ ;LOOP BACK FOR THE REST OF THE NAME STRING
JSR PC,GETEXN ;DISCARD FUNCTIONS
JSR PC,GETEXN ;GET REQUESTS
MOV R0,(SP) ;SAVE REQUESTS TO CHECK FOR VERIFICATION
BIT #NM.RNT!NM.LNT,R0 ;IS OTHER END A LEVEL 1 IMPLEMENTATION?
BNE 50$ ;NO, NOTHING SPECIAL TO DO
BIS #LBS.L1,LB.NSS(J) ;MARK IT (ONLY USE IS TO NOT TIME OUT MSGS)
50$: MOV #6,R1 ;DISCARD A LOT OF THE MESSAGE
60$: JSR PC,NSPI2B ; NAMELY MSG LENGTHS, MAX LINKS, AND VERSIONS
SOB R1,60$ ;(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,NSPIFL ;DELETE THE INPUT MSG .. WE'RE DONE WITH IT
BIT #NM.RVF,(SP)+ ;IF VERIFICATION WASN'T REQUESTED
BEQ 70$ ; THEN DON'T SEND THE PASSWORD MSG
JSR PC,NSPBMG ;START A NEW NSP MESSAGE
MOV #NM.STR+<400*NM.VER>,R0 ;GET THE START-TYPE, VERIFY
JSR PC,NSPO2B ;SEND THE TWO BYTES
JSR R1,NSPOC7 ;WRITE THE 8 CHARACTER PASSWORD
.ASCIZ /PISSWORD/ ;...
.EVEN
JSR PC,NSPSNS ;SEND THE VERIFICATION MESSAGE
70$: MOV #LBS.IC,LB.NSS(J);SET LINE BLOCK IN CONTACT
MOV LB.SCB(J),SB ;SET UP THE SCB ADDRESS
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
;ROUTINE TO SEND A NSP NODE INITIALIZATION
NSPXNI: JSR PC,NSPBMG ;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 NSPLB,R0 ;ADDRESS OF DECNET (NSP) LINE BLOCK
MOVB LB.HNN(R0),R0 ;"OUR" NODE NUMBER
ASSERT NE ;BETTER BE THERE!
JSR PC,NSPPEX ;TELL HIM WHO WE ARE
JSR PC,NSPOC4 ;START AN IMAGE FIELD
MOV NSPLB,R1 ;ADDRESS OF LINE BLOCK
ADD #LB.HNM,R1 ;ADDRESS OF "OUR" NODE NAME
JSR PC,NSPOEI ;OUTPUT NODE NAME (EXTENSIBLE TO IMAGE)
JSR PC,NSPOC5 ; AND WRITE IN THE LENGTH OF OUR NAME
CLR R0 ;WE PROVIDE NO FUNCTIONS.
JSR PC,NSPPEX
CLR R0
JSR PC,NSPPEX ;AND ASK FOR NONE
MOV #NSPMAX,R0 ;MAX NSP 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
JSR PC,NSPO2B ;PUT INTO MESSAGE
MOV #2,R2 ;ONCE FOR COMM VER AND ONCE FOR ROUTE VER
10$: 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,10$ ;BACK TO DO ROUT VER
MOV #OURSCB+SB.SID,R1 ;GET ADDR OF OUR NODE IDENT
JSR PC,NSPOIM ;COPY IT TO MESSAGE
JSR PC,NSPSNS ;SEND THE MESSAGE
RTS PC ; AND WE'RE DONE
.SBTTL NSPICI NSP CONNECT INITIATE MESSAGE
;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 70$ ;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 50$ ;CAN'T USE IT IF WE GOT THE MAGIC LEB
30$: MOV R1,NSPLEB ;IN CASE WE FOUND ON ON THE LIST
MOVB LB.CNN(J),R0 ;NODE TO WHOM CI'S ARE TO BE DIRECTED
ASSERT NE ;BETTER HAVE SOMETHING!
JSR PC,FNDSCB ;SEE IF DESIGNATED HOST IS UP
BEQ 60$ ;IF NOT, WE CAN'T FOWARD THE CONNECT
MOV SB,NSPSB ;OTHERWISE, REMEMBER THE SCB
MOV SB,DNA ; AND THE DESTINATION OF THIS MSG
MOV NSPSB,LE.SCB(R1);REMEMBER THE NCL SIDE IN THE LEB
MOVB LE.STT(R1),R0 ;GET STATE WE'RE IN
JSR PC,@40$(R0) ;AND DISPATCH ON IT.
RTS PC
40$: .WORD NSPCI0 ;A NEW LINK IS BEING SETUP
.WORD NSPERP ;WE DON'T HAVE A NCL LINK, WE SHOULD NEVER GET HERE
.WORD NSPIFL ;DON'T PASS THE SECOND CONNECT. NCL DOESN'T LOSE THEM
.WORD NSPIFL ;ASSUME NSP TIMED OUT AFTER NCL CONNECTED
.WORD NSPIFL ;ASSUME SAME AFTER NCL DISCONNECTED
50$: 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 (AT LEAST TO US!)
JSR PC,NSPO2B ;FINISH DC MESSAGE
JMP NSPSNS ;SEND IT
60$: JSR PC,50$ ;SEND A "DC" TO UN-HANG THE MCB
PJMP NSPFLB ;FREE THE USLESS LEB
70$: NSPIBD ;(ACTUALLY, PROBABLY SHOULD RETURN DC)
;HERE TO FINISH PROCESSING A CONNECT INITIATE FROM NSP
NSPCI0: MOVB #LES.PI,LE.STT(R1) ;ENTER "PI" STATE
JSR PC,NSPCX1 ;GO PROCESS ALL FIELDS UP TO "USER-CTL"
SAVE <R0,R1> ;SAVE THE SEGSIZ. NCL'S MML COMES LATER
;NOW TRANSLATE THE PROCESS NAMES. FIRST THE "DPN" (A BITCH)
JSR PC,NSPCX6 ;FIRST WRITE THE "TSK" OBJECT TYPE
JSR PC,NSPCX5 ;START THE "NAME" OFF WITH A ZERO BYTE
JSR PC,NSPCX8 ;COPY THE "DESTINATION" PROCESS NAME
JSR PC,NSPCX5 ;USE ANOTHER ZERO AS PUNCTUATION
JSR PC,NSPCX8 ;WRITE THE "SOURCE" PROCESS NAME
JSR PC,NSPCX5 ;CLOSE THAT OFF WITH A ZERO ALSO
;NOW TRANSLATE THE USERID -> USERDATA FIELDS
JSR PC,GETEXN ;GET THE MENU FIELD
MOV R0,-(SP) ; AND PUT IT IN A RELATIVLY SAFE PLACE
BIT #^C3,(SP) ;MAKE SURE THAT ALL THE "RESERVED" BITS
BNE 99$ ; ARE ZERO. IF NOT, THEN TOSS THIS BAD MSG
MOV #3,R1 ;GET THE LOOP COUNT
10$: BIT #1,(SP) ;SEE IF MENU SPECIFIED USR,PISS&ACCT
BEQ 20$ ; IF NOT CONTAINED IN MSG, JUST PUNCTUATE
JSR PC,NSPCX3 ;COPY THE IMAGE FIELD
.WORD 16. ;FIELDS ARE 16. BYTES LONG
20$: JSR PC,NSPCX5 ;PUNCTUATE WITH A ZERO
SOB R1,10$ ;LOOP OVER ALL SUB-FIELDS
BIT #2,(SP)+ ;SEE IF WE'RE SUPPOSED TO COPY USERDATA
BEQ 30$ ; IF NO USER DATA, JUST CLOSE OFF THE "DPN"
JSR PC,NSPCX3 ;COPY THE IMAGE "USER DATA" FIELD
.WORD 16. ;16 BYTES OF USER DATA
30$: CLR R0 ;GET A ZERO
JSR PC,NSPPBY ; AND WRITE IT WITH THE EXTENSIBLE BIT OFF
;NOW DO THE "SPN" FIELD OF THE NCL MESSAGE. (AFTER THE DPN IT'S A BREEZE)
JSR PC,NSPCX6 ;THE OBJECT TYPE IS 11 (OBJTSK)
JSR R1,NSPCX4 ;THE SPN IS JUST ALONG FOR THE RIDE
.ASCIZ /The EJW memorial FROB lives!/
.EVEN
BICB #200,-1(R5) ;MAKE SURE WE CLEAR THE EXTENSIBLE BIT
RESTORE <R1,R0> ;GET THE SEGSIZ BACK
JSR PC,NSPCX2 ;FILL OUT THE REST OF THE CONNECT MSG
RTS PC ; AND WE'RE DONE.
99$: JSR PC,NSPERR ;SIGNAL AN ERROR
NSPIBD ; AND TOSS THE MESSAGE
.SBTTL NSPICI NSP CONNECT CONFIRM MESSAGE
;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,@10$(R0) ;CALL PROCESSOR
RTS PC
10$: .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
;HERE TO CONTINUE PROCESSING A CONNECT CONFIRM
NSPCC0: JSR PC,NSPI2B ;GET THE SRCADDR
MOV R0,LE.NSP(R1) ;WE DIDN'T KNOW THIS BEFORE. SAVE IT
MOVB #LES.RN,LE.STT(R1) ;ENTER THE RUN STATE
JSR PC,NSPCX1 ;GO READ EVERYTHING UPTO THE SEGSIZ
SAVE <R0,R1> ;PRESERVE SEGSIZ AND LEB ADDRESS
;DPN
JSR PC,NSPCX6 ;WRITE THE OBJECT TYPE (OBJTSK = 11)
JSR R1,NSPCX4 ;WRITE THE "DPN" OF THE NCL MESSSAGE
; (IF TSKSER EVER CARES ABOUT THE "DPN"
; ON A CC, WE WILL HAVE TO TO THIS RIGHT)
.ASCIZ /Courtesy of the EJW memorial FROB./
.EVEN
BICB #200,-1(R5) ;CLEAR THE LAST EXTENSIBLE BIT
;SPN
JSR PC,NSPCX6 ;WRITE THE OBJECT TYPE (= 11)
JSR PC,NSPCX5 ;START THE "SPN" NAME WITH A ZERO
JSR PC,NSPCX3 ;COPY THE IMAGE "USER DATA"
.WORD 16. ; WHICH IS AT MOST 16 BYTES LONG
CLR R0 ;GET ANOTHER ZERO
JSR PC,NSPPBY ;AND CLOSE OFF THE "SPN" WITH IT.
RESTORE <R1,R0> ;GET THE LEB AND SEGSIZ BACK
JSR PC,NSPCX2 ;WRITE THE REST OF THE NCL MSG AND SEND IT
RTS PC ;ALL DONE WITH THE CONNECT CONFIRM
.SBTTL NSP CONNECT SURBOUTINES
;NSPCX1 PROCESS NSP MSG UP TO SEGSIZ. WRITES NCL MSG UP TO DPN
;NSPCX2 PUTS SEGSIZ IN NCL MESSAGE AND FINISHES IT OFF
;NSPCX3 COPIES AN IMAGE FIELD FROM THE NSP MESSAGE TO THE NCL
;NSPCX4 COPIES AN INLINE ASCIZ FIELD TO THE NCL MESSAGE
;NSPCX5 WRITES AN EXTENSIBLE ZERO INTO THE NCL MESSAGE (PUNCTUATION)
;NSPCX6 WRITES A NON-EXTENSIBLE "11" INTO THE MSG (OBJTSK)
;NSPCX7 OUTPUTS AN OCTAL NUMBER TO THE NCL MESSAGE
;NSPCX8 COPIES A "PROCESS" NAME FROM THE NSP MESSAGE TO THE NCL ONE.
;ROUTINE CALLED ONLY BY THE CI & CC PROCESSORS. THIS ROUTINE PROCESSES
; THE NSP MSG UP TO THE "DATA-CTL" FIELD.
; RETURNS R0 := SETSIZ.
.ENABL LSB
NSPCX1: 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?
BEQ 10$ ;IF SO, THEN OK
JMP NSPRCN ;OTHERWISE DON'T ALLOW IT
10$: 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
BEQ 20$ ;SEE IF THE Z BIT IS SET
JMP NSPRCN ;NOT LOGICAL LINK, CAN'T HANDLE
20$: JSR PC,GETEXN ;GET INFO AND DISCARD
JSR PC,NSPI2B ;GET SEGSIZE
RTS PC ;RETURN R0 := SEGSIZ
;ROUTINE TO FINISH OFF A NCL CONNECT MESSAGE. CALLED WITH R0 = SEGSIZ BY
; THE CI & CC PROCESSORS AFTER THE SPN & DPN HAVE BEEN WRITTEN
NSPCX2: MOV R0,-(SP) ;PRESERVE SEGSIZE FOR A BIT
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
;ROUTINE TO READ THE IMAGE DATA FIELDS FROM THE NSP CONNECT
; MESSAGE AND OUTPUT THEM AS PART OF THE EXTENSIBLE ASCII
; "DPN" STRING IN THE NCL CONNECT MSG.
;CALL:
; JSR PC,NSPCX3
; .WORD MAX-FIELD-LENGTH ;FLUSHES CONNECTION IF TOO LONG
NSPCX3: MOV @0(SP),-(SP) ;GET THE MESSAGE LENGTH
ADD #2,2(SP) ;SKIP OVER LENGTH UPON RETURNING
JSR PC,GETBYT ;GET THE LENGTH OF THE IMAGE FIELD
CMP R0,(SP)+ ;SEE IF THE LENGTH IS REASONABLE
BGT 30$ ;IF UNREASONABLE LENGTH, LOG THE ERROR
SAVE <R1> ;WE RESPECT R1
MOV R0,R1 ;PUT THE FIELD LENGTH IN A SAFER PLACE
BEQ 20$ ;IF A NULL FIELD, DON'T COPY ANYTHING
10$: JSR PC,GETBYT ;GET THE NEXT BYTE
JSR PC,NSPEXB ; AND COPY IT TO THE MESSAGE
SOB R1,10$ ;LOOP OVER THE ENTIRE STRING
20$: RESTORE <R1> ;PUT R1 BACK.
RTS PC ; AND WE'RE DONE
30$: JSR PC,NSPERR ;IF BAD LENGTH, QUEUE DISCONNECTS
NSPIBD ; AND GET OUT OF HERE VIA THE "ESCAPE"
;ROUTINE TO COPY AN INLINE ASCIZ STRING INTO THE OUTPUT STREAM
;CALL
; JSR R1,NSPCX4
NSPCX4: MOVB (R1)+,R0 ;GET THE NEXT BYTE TO GO
BEQ 10$ ;IF NO MORE, CLEAN UP AND RETURN
JSR PC,NSPEXB ;STORE THE BYTE (WITH THE EXTENSIBLE BIT ON)
BR NSPCX4 ; AND GO BACK FOR MORE
10$: INC R1 ;MAKE SURE THAT R1 POINTS TO THE
BIC #1,R1 ; NEXT WHOLE WORD ADDRESS
RTS R1 ; AND RETURN
;ROUTINE TO PUT AN EXTENSIBLE "NULL" INTO THE OUTPUT STREAM
NSPCX5: CLR R0 ;GET THE NULL
PJMP NSPEXB ; AND WRITE IT OUT.
;ROUTINE TO OUTPUT A NON-EXTENSIBLE "11" (= OBJTSK)
NSPCX6: MOV #11,R0 ;GET THE TSK OBJECT TYPE
PJMP NSPPBY ; AND WRITE IT OUT
;ROUTINE TO OUTPUT AN EXTENSIBLE OCTAL NUMBER.
NSPCX7: SAVE <R0> ;SAVE THE NUMBER. ACTUALLY ONLY LOW 3 BITS
ASR R0 ;ONE
ASR R0 ; TWO
ASR R0 ; THREE (TO DIVIDE BY EIGHT)
BIC #160000,R0 ;MAKE SURE CARRY DOESN'T PROPOGATE
BEQ 10$ ;IF NO MORE, WE ARE DONE
JSR PC,NSPCX7 ; OTHERWISE RECURSE ON THE REST OF THE NUMBER
10$: RESTORE <R0> ;GET THE DIGIT BACK
BIC #^C7,R0 ; AND ISOLATE THE 3 IMPORTANT BITS
BIS #'0,R0 ;ASCII-IZE IT
PJMP NSPEXB ; AND OUTPUT IT AS ANOTHER EXTENSIBLE CHAR
;ROUTINE TO PROCESS THE NSP "NAME FIELD FORMATS" (PROCESS NAMES)
; THE ENTIRE FORMAT FIELD IS COPIED INTO ONE "SUBFIELD" IN THE NCL
; MESSAGE. THE CONVENTIONS ARE.
; FORMAT BECOMES THE STRING
; 0 OCTAL-OBJECT-NUMBER
; 1 OCTAL-OBJECT-NUMBER.IMAGE-DESCRIPTOR
; 2 OCTAL-OBJECT-NUMBER.[PROG,PPN].IMAGE-DESCRIPTOR
NSPCX8: JSR PC,GETBYT ;GET THE FORMAT TYPE
DEC R0 ;SET THE CONDITION CODE
BMI 10$ ;BRANCH IF FORMAT 0
BEQ 20$ ;BRANCH IF FORMAT 1
DEC R0 ;JUST TO MAKE SURE THE FORMAT IS REASONABLE
BEQ 30$ ;BRANCH IF FORMAT 2
JSR PC,NSPERR ;IF UNKNOWN FORMAT, DECLARE A LINK ERROR
NSPIBD ; AND GET THE HELL OUT OF HERE
;FORMAT 0 - OBJ
10$: JSR PC,GETBYT ;GET THE OBJECT TYPE
BIC #^C377,R0 ;JUST ONE BYTE'S WORTH PLEASE.
PJMP NSPCX7 ; AND PUT IT OUT AS AN OCTAL NUMBER
;FORMAT 1 - OBJ.DESC
20$: JSR PC,10$ ;FIRST OUTPUT THE "OBJ" PART
JSR R1,NSPCX4 ;NOW OUTPUT AN ASCIZ STRING
.ASCIZ /./ ; CONSISTING OF A DOT
.EVEN
JSR PC,NSPCX3 ;NOW COPY THE IMAGE DATA FIELD
.WORD 16. ; WHICH IS AT MOST 16 BYTES LONG
RTS PC ;RETURN WITH FIELD COMPLETE.
;FORMAT 2 - OBJ.[P,PN].DESC
30$: JSR PC,10$ ;FIRST DO THE OBJECT PART
JSR R1,NSPCX4 ;NOW OUTPUT THE
.ASCIZ /.[/ ; DOT AND THE OPEN SQUARE.
.EVEN
JSR PC,NSPI2B ;READ THE GRPCODE
JSR PC,NSPCX7 ; AND WRITE THE "P" (OF PN FAME)
JSR R1,NSPCX4 ;NOW OUTPUT THE
.ASCIZ /,/ ; SEPARATING COMMA
.EVEN
JSR PC,NSPI2B ;GET THE USRCODE
JSR PC,NSPCX7 ; AND WRITE THE "PN"
JSR R1,NSPCX4 ;NOW OUTPUT THE
.ASCIZ /]./ ; CLOSE SQUARE AND THE DOT
.EVEN
JSR PC,NSPCX3 ;COPY THE IMAGE DESCRIPTOR DATA
.WORD 12. ;WHICH IS AT MOST 12 WORDS LONG
RTS PC ;ALL DONE
;HERE TO REJECT THE CONNECT. REASON IS "SERVICES MISMATCH"
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
.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 NSPFGC ;NOTHING TO DO BUT IGNORE IT
.WORD NSPID0 ;CONVERT DC INTO DISC
.WORD NSPFGC ;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
NSPFGC: MOV NSPPMG,R0 ;GET THE CHUNK ADDRESS
JSR PC,FRECKS ;AND FREE IT, WE ARE DISCARDING MESSAGE
JMP NSPFLB ;GO FREE THE LINK BLOCK
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.PDE,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
.IF NE FTDCPT
MOV NSPLMG,R0 ;FETCH THE IMCOMING MESSAGE
JSR PC,NSPBTP ;NOTE IF ANYONE'S INTERESTED
.ENDC
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 #NSPTCF/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
;HERE TO PROCESS A NCL CONNECT MESSAGE.
;FIRST DETERMINE IF IT IS A CONNECT INIT, OR CONFIRM, THEN SEND THE
;PROPER NSP MESSAGE. ALWAYS REQUEST SEGMENT DATA REQUESTS SINCE THAT
;IS DIRECTLY COMPATIBLE WITH NCL'S WAY OF DOING BUSINESS. IF THERE
;ARE NO FREE LEBS, A DISCONNECT IS SENT TO NCL.
NSPOCN: JSR PC,NSPBMG ;START THE NCL MSG SO WE CAN COPY AS WE GO
BCS 30$ ;IF NO CORE, DELAY PROCESSING FOR A BIT
JSR PC,NSPORT ;WRITE THE NSP ROUTINE HEADER
JSR PC,GETEXN ;GET THE LINK ADDRESS
TST R0 ; AND IF IT'S NON-ZERO,
BNE 10$ ; THEN GO PROCESS THIS CONNECT-CONFIRM
;HERE WHEN MESSAGE IS A CONNECT INIT
JSR PC,GETEXN ;GET THE "SLA"
MOV R0,-(SP) ; AND PROTECT IT FOR A BIT
JSR PC,NSPALB ;ALLOCATE A LEB FOR THIS LINK, AND COPY IN
MOV (SP)+,LE.NCL(R1); THE SLA INCASE WE NEED TO ABORT (DISCONNECT)
BCS 20$ ;IF NO FREE LEBS USE MAGIC TO REJECT THE CNCT
MOVB #LES.LI,LE.STT(R1) ;ENTER "LI" STATE
MOV #NM.CI,R0 ;GET THE "CONNECT INITIATE" MESSAGE FLAG
JSR PC,NSPOC1 ;WRITE MSGFLG -> SEGSIZ
JSR PC,NSPOC2 ;WRITE THE "DATA-CTRL" FIELD
RTS PC ;ALL DONE, SEND NSP MSG, FREE NCL.
;HERE IF WE ARE PROCESSING A CONNECT CONFIRM
10$: JSR PC,NSPSLB ;FIND THIS GUY'S LINE BLOCK
JSR PC,GETEXN ;GET THE "SLA"
MOV R0,LE.NCL(R1) ; AND REMEMBER IT
CMPB #LES.PI,LE.STT(R1) ;IF WE'RE NOT IN "PI" STATE,
BNE 20$ ; THEN SOMETHING'S WRONG. ABORT THE CONNECTION
MOVB #LES.RN,LE.STT(R1) ;GO TO THE "RUN" STATE
MOV #NM.CC,R0 ;GET THE CONNECT CONFIRM MESSAGE TYPE
JSR PC,NSPOC1 ;WRITE THE FIELDS MSGFLG -> SEGSIZ
JSR PC,NSPOC3 ;COPY THE "USER DATA" FROM THE "SPN"
RTS PC ;ALL DONE.
;HERE TO JUST ABORT THE CONNECTION
20$: JSR PC,NSPLTL ;REVERST THE DIRECTION TO SEND "REJECT"
JMP NSPERR ;QUEUE UP THE NECESSARY DISCONNECTS
;HERE TO DELAY PROCESSING UNTIL MEMORY BECOMES AVAILABLE
30$: NSPODF ;DEFER OUTPUT PROCESSING
.SBTTL NCL CONNECT MESSAGE SUBROUTINES.
;NSPOC1 WRITES THE NSP MESSAGE FROM "MSGFLAG" -> "SIGSIZE"
;NSPOC2 TRANSLATES A CONNECT INITIATE'S "HAIRY" DPN
;NSPOC3 TRANSLATES A CONNECT CONFIRMS "SPN" INTO IMAGE "USRDATA"
;NSPOC4 STARTS AN NSP IMAGE DATA FIELD (WRITES THE "COUNT" BYTE)
;NSPOC5 CLOSES AN NSP IMAGE DATA FIELD (FIXED UP THE "COUNT" BYTE)
;NSPOC6 OUTPUTS AN OCTAL NUMBER (EXTENSIBLE BITS OFF)
;NSPOC7 COPY AN ASCII STRING FROM "INLINE" TO THE NSP MESSAGE
;NSPOC8 PARSES A "PROCESS NAME" FROM THE NCL MSG AND WRITES IT TO NSP
;NSPOC9 COPIES AN IMAGE FIELD FROM THE NCL MESSAGE TO THE NSP MESSAGE
;NSPOCT PARSES AN OCTAL FIELD FROM THE NCL MESSAGE
;GETBY7 GETS A BYTE FROM THE NCL MESSAGE AND CLEARS THE EXTENSIBLE BIT
;ROUTINE TO WRITE THE "MSGFLG" THRU "SEGSIZ" FIELDS OF A NSP CI/CC MSG
;CALL WITH R0 := "MSGFLG"
NSPOC1: JSR PC,NSPPBY ;WRITE THE "MSGFLG" FIELD
MOV R1,NSPLEB ;REMEMBER THE LEB
MOV LE.NSP(R1),R0 ;GET THE "DSTADDR"
JSR PC,NSPO2B ; AND WRITE THAT
MOV LE.DCP(R1),R0 ;GET THE "SRCADDR"
JSR PC,NSPO2B ; AND WRITE THAT
MOV #NM.LNK!NM.SRQ+<1*400>,R0 ;GET BOTH "SERVICES" AND "INFO"
JSR PC,NSPO2B ; AND WRITE THEM BOTH IN ONE FELL SWOOP
MOV #MSGMAX,R0 ;USE MSGMAX FOR "SEGSIZ"
JSR PC,NSPO2B ; WRITE SEGSIZE
RTS PC ;ALL DONE
NSPOC2: JSR PC,GETBYT ;GET OBJECT TYPE
CMP #11,R0 ;TASK?
BEQ 20$ ;YES, GO PARSE HAIRY NCL "DPN" FIELD
BIS #LES.DV,LE.STS(R1);SET DEVICE BIT IN LINK ENTRY
MOV R0,R1 ;SAVE OBJECT TYPE FOR LATER
MOV #1!<0*400>,R0 ;USE FMT 1, OBJTYPE 0
JSR PC,NSPO2B ;PUT FORMAT, OBJTYPE
JSR PC,NSPOC4 ;START AN IMAGE SUB-FIELD
SAVE <R1> ;PROTECT OUR OBJECT TYPE
JSR R1,NSPOC7 ;COPY THE FIRST PART OF THE NAME
.ASCIZ /OBJ/ ; FOR "OBJOON" WHERE OO = OBJECT TYPE
.EVEN ; AND N = UNIT NUMBER
RESTORE <R1> ;GET THE OBJECT TYPE BACK IN R1
MOV R1,R0 ;GET OBJECT TYPE
ROR R0 ;SHIFT
ROR R0 ; SECOND DIGIT
ROR R0 ; TO CORRECT PLACE
BIC #^C7,R0 ;CLEAR EXTRA BITS
BIS #'0,R0 ;MAKE INTO ASCII NUMBER
JSR PC,NSPPBY ;PUT 1ST DIGIT OF OBJECT TYPE INTO NAME
MOV R1,R0 ;GET OBJECT TYPE BACK
BIC #^C7,R0 ;CLEAR EXTRANEOUS BITS
BIS #'0,R0 ;MAKE INTO NUMBER
JSR PC,NSPPBY ;STORE IN MESSAGE
JSR PC,GETEXN ;GET UNIT NUMBER
CMP R0,#177 ;GENERIC UNIT?
BEQ 10$ ;YES, DON'T WRITE UNIT NUMBER
JSR PC,NSPOC6 ;WRITE THE OCTAL NUMBER
10$: JSR PC,NSPOC5 ; AND CLOSE OFF THE IMAGE FIELD.
;NOW WRITE SRCNAME FIELD (USLESS FIELD. JUST PUT JUNK THERE)
MOV #1!<0*400>,R0 ;USE FMT 1, OBJTYPE 0
JSR PC,NSPO2B ;PUT FORMAT, OBJTYPE
JSR PC,NSPOC4 ;START THE OBJECT FIELD FOR THE NAME
JSR R1,NSPOC7 ;COPY THE NAME
.ASCIZ /EJW's Compatible FROB says hello./
.EVEN
JSR PC,NSPOC5 ;CLOSE OFF THE NAME FIELD
CLR R0 ;GET A ZERO
JSR PC,NSPPBY ; AND WRITE AN EMPTY MENU
MOV NSPLEB,R1 ;RESTORE R1
RTS PC ; AND WE'RE DONE.
;HERE IF WE ARE PARSING A NCL "DPN" AS A FULL NSP CONNECT MESSAGE
20$: JSR PC,GETBY7 ;GET THE FIRST BYTE FROM THE MESSAGE
BNE 99$ ; IF "DPN" DOESN'T START WITH ZERO, BAD MSG
JSR PC,NSPOC8 ;COPY THE "DSTNAM" FIELD
JSR PC,NSPOC8 ; AND THE "SRCNAM" (THEY LOOK ALIKE)
MOV #3,R0 ;FOR THE "MENU", SAY WE
JSR PC,NSPPEX ; HAVE ALL 4 FIELDS (RQSTRID -> USRDATA)
.REPT 4
JSR PC,NSPOC9 ;COPY ALL 4 FIELDS
.ENDR
RTS PC ; AND WE'RE DONE
99$: JSR PC,NSPLTL ;REVERSE DIRECTION FOR "DISCONNECT"
JSR PC,NSPERR ;DECLARE AN ERROR
NSPOBD ; AND TOSS THE MESSAGE
;ROUTINE TO PARSE THE NCL MESSAGE TO EXTRACT THE "USER DATA" IN THE "SPN"
; CALLED ONLY BY A CONNECT CONFIRM.
NSPOC3: JSR PC,GETEXN ;SKIP DEST OBJECT TYPE.
10$: JSR PC,GETBYT ;GET A BYTE FROM THE "DPN"
BIT #200,R0 ;IF IT IS STILL EXTENSIBLE
BNE 10$ ; KEEP SKIPPING OVER THE "DPN"
JSR PC,GETEXN ;GET THE "OBJECT" OF THE SPN
CMP #11,R0 ;AND MAKE SURE IT'S "TSK"
BNE 99$ ;IF NOT, WE CAN'T PARSE THIS MESSAGE
JSR PC,NSPOC9 ;GO COPY THE IMAGE FIELD
RTS PC ; AND RETURN
99$: JSR PC,NSPLTL ;GET READY TO SEND A DISCONNECT TO NCL
JSR PC,NSPERR ;SIGNAL THE ERROR
NSPOBD ; AND GET THE HELL OUT OF HERE
;ROUTINE TO START AN "IMAGE" FIELD. WRITES THE COUNT BYTE,
; AND RETURNS WITH IT'S ADDRESS ON THE STACK
NSPOC4: JSR PC,NSPPBY ;WRITE A USELESS BYTE (AND COUNT IT)
MOV (SP)+,R0 ;GET OUR RETURN ADDRESS OFF THE STACK
MOV R5,-(SP) ; AND SAVE THE ADDRESS OF THE COUNT
DEC (SP) ; FIXUP THE ADDRESS (WAS ONE TO FAR)
MOVB R4,@0(SP) ;SAVE THE COUNT SO FAR.
JMP @R0 ;RETURN WITH "ADDR" ON THE STACK
;ROUTINE TO CLOSE OFF AN "IMAGE" FIELD. EXPECTS THE ADDRESS
; OF THE "COUNT BYTE TO BE ON THE STACK.
NSPOC5: MOVB @2(SP),R0 ;GET THE CONTENTS OF THE "COUNT" BYTE
SUB R4,R0 ;GET MINUS THE NUMBER OF BYTES WRITTEN
NEG R0 ;COMPLEMENT TO GET THE REAL NUMBER
MOVB R0,@2(SP) ;STORE THE CORRECTED COUNT
MOV (SP)+,R0 ;GET OUR RETURN ADDRESS
RTS R0 ;CLEAN UP THE STACK AND RETURN
;ROUTINE TO WRITE OUT AN OCTAL NUMBER (EXTENSIBLE BITS OFF)
NSPOC6: MOV R0,-(SP) ;SAVE THE LOW ORDER DIGIT (THE REST AS WELL...)
ASR R0 ;SHIFT THE
ASR R0 ; NEXT DIGIT
ASR R0 ; DOWN
BIC #160000,R0 ;MAKE SURE WE DIDN'T PROPAGATE THE SIGN
BEQ 10$ ;IF ALL DONE, GO PRINT THE DIGIT
JSR PC,NSPOC6 ; OTHERWISE PRINT THE REST OF THE NUMBER
10$: MOV (SP)+,R0 ;GET THE DIGIT TO PRINT
BIC #^C7,R0 ; AND JUST THE DIGIT
BIS #'0,R0 ;ASCII-IZE IT
JMP NSPPBY ; AND PUT IT IN THE MESSAGE
;ROUTINE TO COPY AN INLINE ASCIZ STRING INTO THE OUTPUT STREAM
;CALL
; JSR R1,NSPOC7
NSPOC7: MOVB (R1)+,R0 ;GET THE NEXT BYTE TO GO
BEQ 10$ ;IF NO MORE, CLEAN UP AND RETURN
JSR PC,NSPPBY ;STORE THE BYTE
BR NSPOC7 ; AND GO BACK FOR MORE
10$: INC R1 ;MAKE SURE THAT R1 POINTS TO THE
BIC #1,R1 ; NEXT WHOLE WORD ADDRESS
RTS R1 ; AND RETURN
;ROUTINE TO COPY EXTENSIBLE STRING FROM R1 INTO IMAGE OUTPUT STREAM
NSPOEI: MOVB (R1)+,R0 ;NEXT BYTE
BPL 90$ ;HANDLE LAST BYTE
BIC #^C177,R0 ;REDUCE TO NORMAL ASCII CHARACTER
BEQ 99$ ;END IF NULL ASCII CHARACTER
JSR PC,NSPPBY ;STASH THIS BYTE
BR NSPOEI ;LOOP BACK FOR MORE
90$: BEQ 99$ ;IGNORE IF NULL
JMP NSPPBY ;OUTPUT FINAL IMAGE BYTE
99$: RTS PC ;JUST RETURN
;ROUTINE TO PARSE THE "SRC/DST-NAME" FIELD OF THE NCL "DPN"
; AND WRITE THE APPROPRIATE NSP "DST/SRC-NAME".
NSPOC8: SAVE <R1,R2,R3> ;SAVE R1, REMEMBER OUR "READER" POSITION
;FIRST LOOP OVER THE NAME COUNTING THE PERIODS (GIVES US THE FORMAT TYPE)
CLR R1 ;START WITH NO PERIODS
10$: JSR PC,GETBY7 ;GET THE NEXT BYTE
BEQ 20$ ;IF IT'S ZERO, WE'VE FINISHED THE FIELD
CMP #'.,R0 ;SEE IF IT'S A PERIOD
BNE 10$ ;IF NOT A PERIOD, JUST KEEP SCANNING
INC R1 ;IF IT IS A PERIOD, COUNT IT
BR 10$ ; AND SCAN FOR MIRE
20$: RESTORE <R3,R2> ;JUMP BACK TO THE BEGINNING OF THE FIELD
CMP R1,#3 ;MAKE SURE THE COUNT OF PERIODS IS REASONABLE
BGE 99$ ;DIE IF TOO MANY PERIODS
MOV R1,R0 ;GET THE NUMBER (= THE FORMAT)
JSR PC,NSPPBY ; AND WRITE THE FORMAT TYPE BYTE
ASL R1 ;CONVERT INTO A WORD OFFSET.
JSR PC,@30$(R1) ;DISPATCH TO THE ROUTINE TO PROCESS THE FORMAT
RESTORE <R1> ;GET THE REGISTER BACK
RTS PC ; AND WE'RE DONE
30$: .WORD 40$, 50$, 60$ ;DISPATCH VECTOR INDEXED BY FORMAT TYPE.
;FORMAT 0 = "OBJECT"
40$: JSR PC,NSPOCT ;PARSE THE OCTAL NUMBER
TST R0 ;SEE WHAT CHARACTER ENTED THE FIELD
BNE 99$ ;IF FIELD DOESN'T END WITH ZERO, MSG IS BAD
MOV R1,R0 ;COPY THE OBJECT TYPE
JMP NSPPBY ;WRITE THE OBJECT TYPE
;FORMAT 1 = "OBJECT", "DESCRPT"
50$: JSR PC,55$ ;PROCESS THE "OBJECT" FIELD
JMP NSPOC9 ; GO COPY THE IMAGE "DESCRPT" FIELD
55$: JSR PC,NSPOCT ;PARSE THE OCTAL NUMBER
CMP #'.,R0 ;MAKE SURE THE NUMBER ENDED WITH A "."
BNE 99$ ;IF GARBAGE IN MESSAGE, TOSS IT
MOV R1,R0 ;COPY THE OBJECT TYPE FOR NSPPBY
JMP NSPPBY ;OUTPUT THE OBJECT TYPE AND RETURN
;FORMAT 2 = "OBJECT", "GRPCODE", "USRCODE", "DESCRPT"
60$: JSR PC,55$ ;GO PROCESS THE "OBJECT"
JSR PC,GETBY7 ;GET THE NEXT BYTE OF THE MESSAGE
CMP #'[,R0 ; AND MAKE SURE IT'S THE OPEN SQUARE
BNE 99$ ;IF NOT, CHUCK THE MESSAGE
JSR PC,NSPOCT ;GET THE OCTAL "P"
CMP #',,R0 ;MAKE SURE THE PUNCTUATION IS RIGHT
BNE 99$ ;IF NOT, TOSS THE MESSAGE
MOV R1,R0 ;COPY THE PROJECT
JSR PC,NSPO2B ; AND CALL IT A GROUP
JSR PC,NSPOCT ;GET THE OCTAL "PN"
CMP #'],R0 ;MAKE SURE THE TERMINATOR IS A CLOSE SQUARE
BNE 99$ ;IF IT ISN'T, THE MESSAGE IS TRASH
MOV R1,R0 ;COPY THE PROGRAMMER-NUMBER
JSR PC,NSPO2B ; AND CALL IT A "USRCODE"
JSR PC,GETBY7 ;GET THE FIELD SEPARATOR
CMP #'.,R0 ; AND MAKE SURE THAT IT'S A PERIOD
BNE 99$ ;IF IT ISN'T, THE MESSAGE IS BAD
PJMP NSPOC9 ;COPY THE IMAGE "DESCRPT" FIELD AND RETURN
99$: JSR PC,NSPLTL ;REVERSE THE DIRECTION FOR THE DISCONNECT
JSR PC,NSPERR ;DECLARE THE LINK AS DEAD
NSPOBD ;DECLARE THE MESSAGE AS BAD TOO.
;ROUTINE TO COPY AN IMAGE FIELD FROM THE NCL MESSAGE TO THE NSP ONE
NSPOC9: JSR PC,NSPOC4 ;START THE OUTPUT IMAGE FIELD
10$: JSR PC,GETBY7 ;GET THE NEXT BYTE
BEQ 20$ ;IF IT'S THE TERMINATOR, RETURN
JSR PC,NSPPBY ;WRITE THE NEXT BYTE OF THE MESSAGE
BR 10$ ; AND GO BACK FOR MORE
20$: JSR PC,NSPOC5 ;CLOSE OFF THE IMAGE FIELD
RTS PC ; AND RETURN
;ROUTINE TO PARSE AN OCTAL NUMBER FROM THE NCL MESSAGE
NSPOCT: CLR R1 ;WE RETURN THE NUMBER IN R1
10$: JSR PC,GETBY7 ;GET THE NEXT BYTE
CMP #'0,R0 ;SEE IF IT IS LESS THAN
BGT 20$ ; ZERO, IF SO, IT'S NOT A NUMBER
CMP #'7,R0 ;IF ITS GREATER THAN SEVEN
BLT 20$ ; IT'S NOT A NUMBER EITHER
BIC #^C7,R0 ;GET JUST THE "NUMBER" PART
ASL R1 ;MULTIPLY
ASL R1 ; THE ACCUMULATOR
ASL R1 ; BY EIGHT
BIS R0,R1 ; AND ADD IT THIS DIGIE
BR 10$ ;GO SEE IF THERE ARE ANY MORE
20$: RTS PC ;RETURN WITH R1 = NUMBER, R0 = LAST CHAR
;ROUTINE TO GET THE NEXT CHAR FROM THE NCL MESSAGE AND CLEAR THE EXT BIT
GETBY7: JSR PC,GETBYT ;GET THE NEXT BYTE
BIC #^C177,R0 ; AND CLEAR THE EXTENSIBLE BIT
RTS PC ;RETURN WITH THE "Z" BIT SET/CLEAR
;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.PDE,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
TRAP ;FOR NOW
; 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
JSR PC,NSPOC4 ;START THE IMAGE FIELD FOR OUR NAME
MOV NSPLB,R1 ;ADDRESS OF LINE BLOCK
ADD #LB.HNM,R1 ;ADDRESS OF "OUR" NODE NAME
JSR PC,NSPOEI ;OUTPUT NODE NAME (EXTENSIBLE TO IMAGE)
JSR PC,NSPOC5 ;CLOSE OFF THE FIELD
RTS PC ; AND RETURN
;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: 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 "BLT" EXTENSIBLE BYTE STRING
;CALL:
; R0/ ADDR OF SOURCE STRING
; R1/ ADDR OF DESTINATION STRING
; JSR PC,NSPBLB
NSPBLB: MOVB (R0)+,(R1)+ ;MOVE FIRST/NEXT BYTE
BMI NSPBLB ;LOOP WHILE EXTENSIBLE BIT IS SET
RTS PC ;RETURN HAVING COPIED STRING
;ROUTINE TO CALL REST OF CALLER FOR EACH 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
;20 BAD MESSAGES.
NSPBTP: BIT #25,@NSPFGA ;ONLY IF INTERESTED IN NSP/NCL INPUT
BEQ NSPTYR
JSR R1,NSPTYP
.ASCIZ \NSPBTP CALLED \
.EVEN
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.
.IF NE,FTDCPT
NSPFGA: .WORD NSPTFG ;PATCH TO 177570 FOR SWITCHES
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)
.ENDC;.IF NE FTDCPT
;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