Trailing-Edge
-
PDP-10 Archives
-
tops10_703a_sys_ap115_bb-ju01b-bb
-
dndcmp.x14
There are 3 other files named dndcmp.x14 in the archive. Click here to see a list.
.SBTTL DNDCMP - DDCMP PROTOCOL 29 APR 86
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1976,1977,1978,1979,1980,1981,1982,1983,1984 BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
VRDCMP=070 ;FILE EDIT NUMBER
.IF NE NTLINE
.IF NE,<NTLINE-DMCN>
SYNCHS:
.REPT FTNSYN
.BYTE SYN
.ENDR
.EVEN
.ENDC;.IF NE,<NTLINE-DMCN>
;HERE AT ONCE ONLY TIME
DDCINI: ;HERE TO INITIALIZE DDCMP
.IF NE,DMCN
.IF NE,<NTLINE-DMCN>
CMPB #LS..DM,LB.DVS(J) ;IS IT DMC11?
BNE 77$ ;NO, SKIP
.ENDC;.IF NE,<NTLINE-DMCN>
JMP DMCINI ;REALLY PJMP: GO HANDLE DMC11 DIFFERENTLY
77$:
.ENDC;..IF NE,DMCN
.IF NE,<NTLINE-DMCN>
MOV LB.SLA(J),R3 ;GET THE HARDWARE ACCESS ADDRESS FOR LINE
MOV #DDCI20,LB.XDN(J) ;SET DEFAULT FOR XMIT INTERRUPT SERVICE
JSR PC,SL.INI ;INITIALIZE THE LINE DRIVER
BIC #^C<LS..RQ!LS..XQ!LS.MPT>,@J ;CLEAR MOST STATUS BITS
BIS #LS..ST,@J ;NEED TO SEND START
MOV #REPSEC,LB.REP(J) ;RESET REP TIMER
CLRB LB.RDC(J) ; CLEAR REP COUNT
MOV #LB.IBF,LB.ITK(J) ;INITIALIZE INPUT TAKER
MOV #LB.IBF,LB.IPT(J) ;INITIALIZE INPUT PUTTER
CLR LB.IBF+10(J) ;CLEAR CHUNK POINTER
JSR PC,DDCQRQ ;POKE TRANSMITTER
QUEPUT QI 91$
RTS PC
.ENDC;.IF NE,<NTLINE-DMCN>
.ENDC ; .IF NE NTLINE
.SBTTL TIMER ACTION
.IF NE NTLINE
;HERE WHEN DDCMP SECOND TIMER GOES OFF
DDCSEC: ;HERE ONCE PER SECOND FOR DDCMP
.IF NE,DMCN
.IF NE,<NTLINE-DMCN>
CMPB #LS..DM,LB.DVS(J) ;IS IT DMC11?
BNE 77$ ;NO, ACT NORMAL
.ENDC;.IF NE,<NTLINE-DMCN>
JMP DMCTMR ;PJMP TO DMC11 TIMEOUT ROUTINE
77$:
.ENDC;.IF NE,DMCN
.IF NE,<NTLINE-DMCN>
INCB LB.RDC(J) ;COUNT TIMES WE SEND REP'S
.IIF NE <REPDWN&377>, CMPB #REPDWN,LB.RDC(J)
BNE 10$
JSR PC,L.DOWN ;LINE DOWN - SET FLAGS ETC.
10$: MOV #REPSEC,LB.REP(J) ;RESET REP TIMER
BIT #LS..ST!LS.STK,(J) ;IF START OR STACK, SPEED UP TIMER
BEQ 15$
MOV #JIFSEC/REPSPD*17,LB.REP(J) ; SEND START EVERY 15 SECONDS
15$: BIS #LS.NRP!LS.XRP,@J ;SET REP FLAG
.IIF NE FT.MPT,BISB #MP.SNM,LB.MPS(J) ;SET SELECT
JMP DDCQRQ ;WAKE TRANSMITTER
.ENDC;.IF NE,<NTLINE-DMCN>
.ENDC ;.IF NE NTLINE
.SBTTL QUEUE DATA OUT
;HERE TO QUEUE A MESSAGE OUT
; FORMAT OF 1ST CHUNK IS <LINK><MSG LINK><LENGTH>DATA
; FORMAT OF 2ND CHUNK IS <LINK>DATA
; CALL SETUP DNA
; MOV #ADR,R0
; JSR PC,DDQDAT
.IF NE NTLINE
DDQBOO: MOV R0,LB.BOO(J) ;SAVE ADR OF MSG
MOV #DLE,R2 ;BEGIN BOOTSTRAP MSGS WITH DLE
.IF NE FT.RDM ;IF RDE DEVICE WHICH CAN'T HANDLE
.IF EQ RDEDLL ;MAINTAINANCE MODE MESSAGES, WE
;MUST CHUCK THEM
BIT #LS.MPT,(J) ;IF NOT MULTIPOINT LINE
BEQ DDQ.00 ;THEN OK TO DO MAINT MODE
.IF NE FTTRIB
TST LB.MPL(J) ;AND IF NOT TRIBUTARY
BEQ DDQ.00 ;THEN OK TO DO MAINT MODE
.ENDC; NE,FTTRIB
TWIDDLE ;COUNT AND CHUCK MSGS
JMP FRECKS
.IFF; EQ,RDEDLL
BR DDQ.00
.ENDC; EQ,RDEDLL
.IFF; NE,FT.RDM
BR DDQ.00
.ENDC; NE,FT.RDM
.IF NE,FTDCP1!FTDCP3!FTDCP4
BIT #LS.NSP,(J) ;NSP LINE?
BEQ DDQ.00 ;NO, ACT NORMAL
TWIDDLE ;COUNT PEOPLE TRYING TO BOOT NSP
PJMP FRECKS ;AND THROW MESSAGE AWAY
.ENDC; NE,FTDCP1!FTDCP3!FTDCP4
DDQDAT: MOV #SOH,R2 ;BEGIN DATA MSGS WITH SOH
MOV DNA,SB ;GET DESTINATION SCB ADR
ASSERT NE
DDQ.00: CMP #DLE,R2 ;WAS THIS A BOOTSTRAP MSG ?
BEQ DDQ.02
SAVE <J,#JRSTR> ;SAVE "J" REGISTER AND ADDRESS
;WHERE IT WILL BE RESTORED
MOV SB.LBA(SB),J ;GET PRIMARY ROUTE
ASSERT NE
.IF NE FTDL10!FT.DTE
CMP TENSCB,SB ;IS THIS FOR THE 10 ?
BNE 20$
10$: JMP DLQDAT ;QUEUE DATA TO 10
20$: CMP TENSCB,J ;IF PRIMARY ROUTE IS THROUGH 10,
BEQ 10$ ;USE THE DL10 HIGH SPEED CHANNEL
.ENDC;.IF NE FTDL10!FT.DTE
.IF NE,FTDCP1!FTDCP3!FTDCP4
BIT #LS.NSP,(J) ;NSP LINE?
BEQ DDQSOL ;NO, FALL THROUGH
JSR PC,NSPOUT ;YES, GO MAKE NSP VERSION
.IF NE FTDCP3!FTDCP4
RTS PC ;DCP3 QUEUES NCL MESSAGES INSIDE ITSELF
.ENDC; NE,FTDCP3!FTDCP4
DDQNSP: MOV #SOH,R2 ;PROBABLY CLOBBERED BY NOW
.ENDC ;.IF NE FTDPC1!FTDCP3!FTDCP4
;NOW SELECT AN OUTPUT LINE
DDQSOL: TST LB.OBF(J) ;IF OUTPUT QUEUE EMPTY
BEQ 20$ ; THEN USE THIS LINE
MOV J,R1 ;ELSE LOOK FOR A SHORTER QUEUE
10$: MOV LB.2ND(R1),R1 ;GET NEXT LINE IN THE LIST
BEQ 20$ ;IF NO MORE, THEN "J" IS THE BEST
CMP LB.OBF+4(J),LB.OBF+4(R1);SEE WHO HAS THE SHORTEST QUEUE
BLE 10$ ;IF "J" DOES, THEN KEEP LOOKING
MOV R1,J ;OTHERWISE, REMEMBER NEW "BEST"
BR DDQSOL ; AND START FROM THERE
;NOW FOR A LITTLE CONGESTION CONTROL!
20$: CMP #40,LB.OBF+4(J) ;THIS SEEMS LIKE A GOOD LIMIT.
BGT DDQDDP ;IF WE'RE UNDER IT, QUEUE THE MSG
XXX=0
.IIF NE FT.MPT,XXX=XXX!LS.MPT
.IIF NE FTDCP1!FTDCP3!FTDCP4,XXX=XXX!LS.NSP
.IF NE XXX
BIT #XXX,@J ;IS THIS DATA IRREPLACABLE?
BNE DDQDDP ;YES, CAN'T TOSS IT
.ENDC ;.IF NE FT.MPT!FTDCP1!FTDCP3!FTDCP4
.IF NE FT.DDP
TST LB.ST2(J) ;IF THIS IS A DDP LINE
BLT DDQDDP ;THEN DATA IS IRREPLACABLE
.ENDC ;.IF NE FT.DDP
JSR PC,NCLOKT ;OTHERWISE SEE IF IT'S OK TO TOSS
BCS DDQDDP ;IF IT'S ONE OF OURS, DON'T DELETE
TWIDDLE ;COUNT THE NUMBER LOST
JMP FRECKS ;AND JUNK IT
DDQDDP: INCB LB.HSN(J) ;NEW HIGHEST MSG # SENT
DDQ.02: ASSERT CHUNK R0 ;BE SURE WE DIDN'T GET TRASH
MOV R0,-(P) ;SAVE MSG ADDR
MOV #DDHTIM,CN.TIM(R0) ;NUMBER OF SECONDS TO HOLD
.IF NE FT.MPT
BIT #LS.MPT,(J) ;IF A MULTIPOINT LINE
BEQ 05$
MOV #MPHTIM,CN.TIM(R0) ;NUMBER OF SECONDS TO HOLD
.IF NE FTTRIB
TST LB.MPL(J) ;IF NOT A TRIBUTARY WE MUST
BEQ 04$
.ENDC
.IF EQ FTSLCT-2
JSR PC,SLCTDO ;RECOMPUTE THE WEIGHTING FOR SELECTION
; ;GIVEN THAT DATA WAS XMITTED
.ENDC
BITB #MP.OFF!MP.SOL,LB.MPS(J) ;IF OFFLINE
BEQ 05$
JSR PC,SLCT.1 ;PUT IT ONLINE
.IF NE FTTRIB
04$: BICB #MP.OFF!MP.SOL,LB.MPS(J) ;CLEAR THE OFFLINE STATE
.ENDC
05$: MOV (P),R0 ;BE SURE R0 IS NOT ALTERED
.ENDC
MOV CN.LEN(R0),R1 ;GET SIZE OF MSG
ADD #CN.DDC,R0 ;POINT TO SOH
MOVB R2,(R0)+ ;PUT SOH OR DLE ON MESSAGE
.IF NE,DMCN
.IF NE,<NTLINE-DMCN>
CMPB #LS..DM,LB.DVS(J) ;IS IT DMC11?
BEQ 68$ ;YES, DON'T CALCULATE CRC
.ENDC;.IF NE,<NTLINE-DMCN>
.ENDC;.IF NE,DMCN
.IF NE,<NTLINE-DMCN>
MOVB R1,(R0)+ ;PUT LOW ORDER PART IN HEADER
SWAB R1
MOV R1,(R0)+ ;PUT HIGH ORDER BITS OF COUNT IN
;MOVB LB.ROK(J),(R0)+ ; TRASH FOR LB.ROK(FIXED LATER)
MOVB LB.HSN(J),(R0)+ ;PUT MESSAGE # INTO HEADER
.IF NE FT.MPT
MOVB LB.MPA(J),(R0)+ ;PUT DEST STATION ADDRESS IN HEADER
.IFF
MOVB #A0,(R0)+ ;PUT DEST STATION ADDRESS IN HEADER
.ENDC
CLR (R0)+ ;CLEAR BCC SLOT
;CALCULATE CRC FOR A MESSAGE TO BE TRANSMITTED
SWAB R1 ;GET COUNT BACK
JSR PC,DDDBCC
.IF EQ DGUTS
TRAP ;ZAPPED IF MESSAGE IS LONGER THAN ALLOCATION
.IFF
BR 70$ ;ZAPPED IF MESSAGE IS LONGER THAN ALLOCATION
.ENDC ; .IF EQ DGUTS
BR 67$ ;DUP DEVICE RETURN
65$: ADVCNK R0 EXTEND ;ADVANCE TO NEXT CHARACTER
; ;ALLOCATING A NEW CHUNK IF REQUIRED
MOVB (P),(R0)+ ;PUT 1ST HALF OF BCC IN MESSAGE
SWAB (P)
ADVCNK R0 EXTEND ;ADVANCE TO NEXT CHARACTER
; ;ALLOCATING A NEW CHUNK IF REQUIRED
MOVB (P)+,(R0)+ ;PUT LAST HALF OF BCC INTO MESSAGE
.ENDC;.IF NE,<NTLINE-DMCN>
68$: MOV (P)+,R0 ;GET ADR OF 1ST CHUNK AGAIN
CMPB #DLE,CN.DDC(R0) ;IS THIS A BOOTSTRAP MSG ?
BEQ DDCQRQ
TST LB.OBF(J) ;IS THE QUEUE EMPTY ?
BNE 50$
MOV R0,LB.OBF(J)
MOV R0,LB.OBF+2(J)
BR 60$
50$: MOV LB.OBF+2(J),R2 ;GET ADDRESS OF LAST MESSAGE IN QUE
MOV R0,CN.MLK(R2) ;SET LINK IN PREV LAST MSG
MOV R0,LB.OBF+2(J) ;REMEMBER NEW LAST MSG
60$: INC LB.OBF+4(J) ;COUNT MESSAGE INTO QUEUE
62$: BR DDCQRQ ;WAKE TRANSMITTER
67$: TST (P)+ ;CLEAR CRC
BR 68$ ;FROM STACK AND DONT STORE IN MESSAGE
.IF NE,<NTLINE-DMCN>
.IF NE DGUTS
70$: DECB LB.HSN(J) ;RESTORE MESSAGE COUNT
TST (P)+ ;POP WOULD BE BCC
MOV (P)+,R0 ;GET BACK MSG POINTER
JSR PC,FRECKS ;CHUCK MSG AND LOG ERROR
CTYMSG IML
RTS PC
.ENDC ;.IF NE DGUTS
.ENDC;IF NE,<NTLINE-DMCN>
;HERE TO QUEUE OUT TRANSMITTER
DDCQRQ: TRACE DD
PIOFF
BIT #LS.XDT!LS.XCT!LS..XQ,@J;IS XMITTER ALREADY QUEUED UP ?
BNE 70$ ;IF SO DONE FOR NOW
QUEPUT QO 69$
70$: PION
RTS PC
.ENDC ; .IF NE NTLINE
.SBTTL RECEIVER SERVICE
.IF NE,NTLINE
.IF NE,<NTLINE-DMCN>
;HERE TO PREPARE TO RESTART DDCMP LINE
DDCIGO: MOV J,R1 ;COPY LINE BLOCK ADR
ADD LB.IPT(J),R1 ;POINT TO NEW BUFFER
MOV 10(R1),R0 ;GET STALE CHUNK STRING IF ANY
BEQ 10$
TWIDDLE
CLR 10(R1) ;FORGET POINTER
TWIDDLE R0 ;REMEMBER STALE CHUNKS
JSR PC,FRECKS ;RELEASE THEM
10$: PIOFF ;DISABLE INTERRUPTS
JSR PC,SLRBEG ;RESTART SYNCHRONOUS LINE RECEIVER
PION
RTS PC
.ENDC;IF NE,<NTLINE-DMCN>
;HERE AT LOW LEVEL TO CHECK INPUT
DDCINP:
.IF NE,DMCN
.IF NE,<NTLINE-DMCN>
CMPB #LS..DM,LB.DVS(J) ;IS IT DMC11?
BNE 6$ ;NO, SKIP NEXT INSTRUCTION
.ENDC;.IF NE,<NTLINE-DMCN>
JMP DMCINP ;HANDLE DMC11 DIFFERENTLY
6$:
.ENDC;.IF NE,DMCN
.IF NE,<NTLINE-DMCN>
MOV LB.ITK(J),R0 ;GET INPUT TAKER
CMP R0,LB.IPT(J) ;ANY INPUT LEFT TO CHECK ?
BNE 5$ ;BRANCH IF MORE TO DO
BIT #LS..RG,@J ;IS RECEIVER ENABLED ?
BNE 99$ ;IF SO WE ARE DONE
JSR PC,DDCIGO ;RELEASE STALE CHUNKS
99$: JMP LOOP
;HERE WITH QUEUED DDCMP DATA MESSAGE WAITING
5$: HDRDMP I,DMPHLN,DMPHIN
ADD J,R0 ;MAKE ABS ADR OF MESSAGE
MOV R0,R3 ;COPY ADDRESS OF BUFFER
MOV R0,R2 ;COPY ADDRESS
;CHECK BCC ON 8 CHAR HEADER OR CONTROL MSG
.IF NE FT.CHK
CMPB #SOH,@R0 ;WAS FIRST CHAR OF HEADER SOH ?
BEQ DDCIN0
CMPB #ENQ,@R0 ;PERHAPS THIS IS CONTROL MSG ?
BEQ DDCIN0
CMPB #DLE,@R0 ;BOOTSTRAP MESSAGE ?
BEQ DDCIN0
.IF NE FTDUP11 ;GROSS HACK TO HANDLE DUP BCC
CMPB #252,@R0 ;WAS THIS THE ERROR FLAG FROM INT LEVEL?
BNE 20$ ; IF SO, THEN
JMP DDRADV ; CHUCK THE MESSAGE. (INT LEVEL HAS
; ALREADY SENT THE NAK)
20$:
.ENDC
TRAP ;INTERRUPT LEVEL GOOFED
.ENDC;.IF NE FT.CHK
DDCIN0:
; DONE AT INTERRUPT LEVEL FOR PROPER OPERATION
; JSR PC,DDBBCC ;CALCULATE THE BCC FOR THE HEADER
; CMP (P)+,(R0)+ ;CHECK BCC ON DDCMP HEADER
; BEQ .+6
; JMP DDRBBC ;IF NOT EQUAL MESSAGE IS TRASH
.IF EQ FT.CHK
.IF NE FTDUP11
CMPB #252,@R0 ;DUP CRC ERROR?
BNE 5$ ;IF NOT
JMP DDRADV ;YES-CHUCK THE MSG.
5$:
.ENDC ;.IF NE FTDUP11
.ENDC ;.IF EQ FT.CHK
.IF NE FT.MPT
BIT #LS.MPT,(J) ;IF A MULTIPOINT LINE
BEQ 14$
.IF NE FTTRIB
TST LB.MPL(J) ;IF TRIBUTARY
BNE 11$
CMPB LB.MPA(J),5(R2) ;AND ITS NOT FOR ME
BNE $29.1 ;(BNE DDRADV) ;CHUCK MSG
BR 12$
.ENDC ;.IF NE FTTRIB
11$: BITB #MP.OFF,LB.MPS(J) ;OR I AM AN OFFLINE MASTER
BNE $29.1 ;(BNE DDRADV) ;CHUCK MSG
12$:
BITB #SELBIT,2(R2) ;AND IF SELECT SET IN MSG
BEQ 14$
BICB #MP.SFF!MP.OFF!MP.SOL,LB.MPS(J)
;RESET THE SELECT FAILURE COUNTER
BISB #MP.SFC,LB.MPS(J)
13$: JSR PC,SELNXT ;THIS STATION IS NO LONGER IT
; ;OR IF TRIBUTARY THIS STATION IS NOW IT
.IF NE FTTRIB
TST LB.MPL(J) ;IF TRIBUTARY
BNE 14$
BIS #LS.XAK,(J) ;WE MUST SEND A RESPONSE
JSR PC,DDCQRQ
.ENDC
14$:
.ENDC
MOV (R2)+,R0 ;GET 1ST TWO CHARS
CMPB #DLE,R0 ;WAS THIS A BOOTSTRAP MSG ?
BEQ 23$ ;IF SO DON'T CHECK MSG NUMBERS
CLRB LB.BNN+1(J) ;NOT A BOOT MSG, SO RESET BOOT MODE
CMPB #ENQ,R0 ;WAS MESSAGE CONTROL ?
BEQ $50
BIT #LS..ST!LS.STK,(J) ;IF WE AREN'T STARTING OR STACKING
BEQ 20$ ;GO PROCESS THE MESSAGE
BIT #LS..ST,(J) ;IF WE ARE STARTING
BNE $29.1 ;(BNE DDRADV) ;CHUCK THE MSG IF IN THE START STATE
BIC #LS.STK,(J) ;CLEAR SENDING STACKS
BIS #LS.XAK,(J) ;SAY WE NEED TO ACK AND PROCESS MSG
;HERE IF GOOD HEADER ON A DATA MESSAGE
20$: MOVB 3(R3),R0 ;GET LAST MSG # HE GOT OK
JSR PC,DDRESP ;VERIFY SEQ NUMBERING
BR $29.1 ;(BR DDRADV) ;DUMP THE MSG IF BAD SEQUENCING
MOVB 4(R3),R0 ;GET MSG # FROM HEADER
DEC R0 ;MAKE PREVIOUS MSG #
CMPB R0,LB.ROK(J) ;IF THESE DON'T MATCH
BNE DDRADV ; JUST IGNORE
23$:
.IIF EQ FTSLCT-2, JSR PC,SLCTDI ;RECOMPUTE THE WEIGTHING FOR
; ;SELECTION ON DATA RECEPTION
MOV 10(R3),R0 ;GET ADR OF 1ST CHUNK IN DATA PORTION
BEQ DDRNRM ;IF NO CHUNKS NAK MESSAGE
ADD #CN.NCT,R0 ;MAKE ADR OF 1ST CHAR OF MESSAGE
MOV CN.LEN-CN.NCT(R0),R1 ;GET LENGTH OF MESSAGE
CMP R1,#MSGMAX ;IF MSG TO LOOOONG
BHI DDRTLM ;NAK IT
ADD #2,R1 ;ADD 2 CHARS FOR BCC
JSR PC,DDDBCC ;CALCULATE BCC
BR DRNRM0 ;INCONSISTENT LENGTHS FAILURE
BR 25$ ;DUP RET CLEAR STACK
TST (P)+ ;CHECK BCC
BNE DDRDBC
26$: MOV 10(R3),R0 ;GET ADR OF 1ST MSG CHUNK
CMPB #SOH,(R3) ;IF ORDINARY DATA
BEQ 27$ ;CONTINUE
JMP DRBOOT ;ELSE PROCESS BOOTSTRAP MSG
25$: TST (P)+ ;CLEAR STACK
BR 26$ ;RETURN TO NORMAL ROUTINE
27$: INCB LB.ROK(J) ;INCREMENT MSG # RECEIVED
BIS #LS.XAK,@J ;FLAG TO SEND AN ACK
INC LB.ICN(J) ;COUNT ALL MESSAGES IN
; JSR PC,DDCQRQ ;WAKE XMITTER SO IT SENDS ACK
CLR 10(R3) ;SO DDRADV DOESN'T TOUCH CHUNKS
MOV J,-(P) ;SAVE J IN CASE NCLINP WIPES IT
.IF NE FT.RDM
BIT #LS.MPT,(J) ;IF MULTIPOINT, MUST SIMULATE DEVICE
BEQ $28
.IF NE FTTRIB
TST LB.MPL(J) ;BUT NOT IF TRIBUTARY
BEQ $28
.ENDC
MOVB LB.MPA(J),CN.NCT-1(R0) ;SAVE THE STATION'S ADDRESS
JSR PC,RDEINP
BR $29.1
.ENDC ;.IF NE FT.RDM
$28:
JSR PC,DDDGIV ;GIVE DATA TO WHOMEVER
MOV (P)+,J ;RESTORE J
$29.1: BR DDRADV
.ENDC;.IF NE,<NTLINE-DMCN>
.IF NE,<NTLINE-DMCN>
;HERE IF CONTROL MESSAGE HAS GOOD BCC
$50: SWAB R0 ;WANT CODE IN RH
BIT #LS..ST!LS.STK,@J ;HAVE WE EXCHANGED START/STACK ?
BEQ 15$
CMPB R0,#STRT ;IS IT STRT OR STACK ?
BGE 15$ ;IF SO, THEN IT'S OK
BIT #LS..ST,(J) ;IF SENDING STARTS
BNE DDRADV ;THEN IGNORE MESSAGE
BIC #LS.STK,(J) ;OTHERWISE CLEAR SENDING STACKS
BIS #LS.XAK,(J) ;SAY WE NEED TO ACK AND PROCESS MSG
15$:
TRACE DD ;PUT MESSAGE TYPE IN TRACE
CMPB #STACK,R0 ;CHECK TYPE IS SMALL ENOUGH
BLO DRNAK0 ;BRANCH IF TOO LARGE
ASL R0 ;MULTIPLY BY 2
JMP @DDCDSP-<ENQ*1000>(R0)
DDCDSP: DRNAK0 ;(0) = FORMAT ERROR
DDRACK ;(1) = ACK
DDRNAK ;(2) = NAK
DDRREP ;(3) = REP
DDREST ;(4) = RESET
DDRSAK ;(5) = RESAK
DDRSTR ;(6) = START
DDRSTK ;(7) = STACK
;HERE BECAUSE WE RECEIVED A MESSAGE BUT DIDN'T HAVE ROOM FOR IT
DRNRM0: TST (P)+ ;POP BCC FROM STACK FIRST
TWIDDLE
DDRNRM: MOVB #NCDNRM,LB.NCD(J) ;REASON CODE
TWIDDLE
BR DDRKRD ;AND FLUSH MESSAGE
;HERE BECAUSE MSG TO LONG TO HANDLE
DDRTLM: MOVB #NCDTLM,LB.NCD(J) ;DATA LENGTH CODE
TWIDDLE
BR DDRKRD
;HERE BECAUSE BAD BCC ON HEADER OR DATA
DDRDBC: MOVB #NCDDBC,LB.NCD(J) ;DATA BCC CODE
TWIDDLE
BR DRNAK0
DDRBBC: MOVB #NCDBCC,LB.NCD(J) ;NAK CODE
TWIDDLE
DRNAK0: INC LB.ICN+2(J) ;COUNT BUM MESSAGES
TWIDDLE
DDRKRD: BIS #LS.XNK,@J ;SEND NAK TO OTHER GUY
TWIDDLE
; JSR PC,DDCQRQ ;SEND NAK
;HERE WHEN DONE PROCESSING LAST DDCMP MSG
DDRADV: MOV LB.ITK(J),R1 ;GET REL ADR OF BUFFER AGAIN
ADD J,R1 ;MAKE ABSOLUTE ADR
MOV 10(R1),R0 ;GET ADDR OF CHUNKS IF ANY
JSR PC,FRECKS ;AND THROW THEM AWAY
CLR 10(R1) ;SO WE DON'T NOTICE THEM LATER
MOV LB.ITK(J),R0 ;GET INPUT SLOT ADR AGAIN
ADD #12,R0 ;ADVANCE INPUT SLOT
CMP R0,#LB.IBF+<NINBUF*12> ;TIME TO WRAP AROUND ?
BNE 84$
MOV #LB.IBF,R0 ;YES
84$: MOV R0,LB.ITK(J) ;RESET TAKER
JSR PC,DDCQRQ ;POKE TRANSMITTER
JMP DDCINP ;SEE IF ANY MORE INPUT READY
;
;HERE BECAUSE BAD BCC ON HEADER AT INTERRUPT LEVEL
DRBCC0: MOVB #NCDBCC,LB.NCD(J) ;HEADER BCC NAK CODE
TWIDDLE
DRNAK1: INC LB.ICN+2(J) ;COUNT BUM MESSAGES
TWIDDLE
BIS #LS.XNK,@J ;SEND NAK TO OTHER GUY
JMP DDCQRQ ; AND RETURN TO INTERRUPT HANDLER
;HERE WHEN WE RECEIVE A NAK MESSAGE
DDRNAK: BIS #LS..RN,@J ;REMEMBER WE RECEIVED NAK
INC LB.OCN+2(J) ;COUNT ALL NAKS RECEIVED
MOVB (R2),R1 ;GET REASON AND STRIP EXTRA BITS
BIC #^C77,R1
BEQ 40$ ;ZERO CODE ???
CMP R1,#NCDREP ;IF BCC ERROR
BHIS 10$
INC LB.OCN+6(J) ;COUNT IT
.IF NE FT.BIG
INCB LB.TRY(J) ;COUNT BCC ERRORS FOR THIS MESSAGE
CMPB LB.TRY(J),#10 ;AN UNREASONABLE NUMBER YET?
BLT 40$ ;NO, GIVE IT A SECOND CHANCE
TWIDDLE J ;WE PROBABLY CLOBBERED OUR OWN MESSAGE
PJMP L.DOWN ; SO WE BETTER START FROM SCRATCH
.IFF
BR 40$ ;SEE IF ANYTHING WAS ACKED
.ENDC
10$: BHI 20$
CMPB 3(R3),LB.LAP(J) ;IS LAST ACKED OUR LAST SENT?
BEQ DDRACK ;YES, TREAT IT NOT AS A NAK, BUT AS
; A DMC'S "FUNNY-LOOKING ACK"
INC LB.OCN+4(J) ;COUNT NAKS
15$: BR 40$
20$: CMP #NCDTLM,R1 ;CHECK FOR REASON IS MSG LENGTH
BEQ 25$
CMP #NCDNRM,R1 ;CHECK FOR REASON IS NO ROOM
BNE 40$
25$: INC LB.OCN+10(J)
40$:
;HERE WHEN WE RECEIVE AN ACK MESSAGE
DDRACK: TSTB (R2)+ ;SKIP A FILL
MOVB @R2,R0 ;LAST MSG # HE GOT
JSR PC,DDRESP ;CHECK SEQUENCE NUMBERING
BR DDRADV ;CHUCK MSG IF SEQUENCING IS OFF
BR DDRADV ;ALSO IF SEQUENCING IS OK
;HERE WHEN RECEIVE A REP MESSAGE
DDRREP: TST (R2)+ ;SKIP FILLERS
CMPB @R2,LB.ROK(J) ;WAS LAST MSG HE SENT LAST I GOT?
BEQ 10$
BIS #LS.XNK,@J ;NEED TO SEND NAK
MOVB #NCDREP,LB.NCD(J) ;REASON CODE
INC LB.ICN+4(J) ;COUNT TIMES THIS HAPPENED
BR 20$
10$: BIS #LS.XAK,@J ;NEED TO SEND ACK
20$: BR DDRADV ;SEND MESSAGE TO HIM
;HERE WHEN WE RECEIVE A RESET MESSAGE
DDREST:
;HERE WHEN WE RECEIVE A RESET-ACK MESSAGE
DDRSAK: BR DRNAK0
;HERE TO CHECK SEQUENCING, R0 HAS # FROM ACK/NAK/DATA
DDRESP: CLR -(P)
MOVB LB.LAP(J),(P) ;GET LAST ACKED NUMBER
.IF NE FTWHYD
MOVB @P,LB.WHS(J) ;SAVE LAST ACKED #
MOVB LB.OBF+4(J),LB.WHN(J) ;SAVE QUEUE LENGTH BEFORE ITS CLEARED
.ENDC
MOVB R0,LB.LAR(J) ;UPDATE LAST ACKED NUMBER
.IF NE FT.BIG
CLRB LB.TRY(J) ;SUCCESSFULLY SENT LEAD MESSAGE
.ENDC
BIC #^C377,R0 ;ACKED NUMBER MUST BE POSITIVE
SUB (P)+,R0 ;GET NUMBER OF MSGS ACKED THIS TIME
BEQ 75$
BIC #^C377,R0 ;NUMBER MUST BE POSITIVE
;IF GREATER THAN ZERO, MUST CHECK THE MSG QUEUE
CMP LB.OBF+4(J),R0 ;COMPARE NUMBER ACKED WITH QUEUE LENGTH
BHIS 70$ ;IF QUEUE IS NOT SHORTER, WE'RE OK
BR 75$ ;ELSE IGNORE (AS PER DDCMP SPEC)
70$:
JSR PC,DDXMTD ;CLEAN OUT THE XMITTED MSGS
BR 78$ ;AND RESET REP TIMER
75$: TST LB.OBF+4(J) ;IF MORE REMAINS TO XMIT,
BNE 80$ ;THERE MAY HAVE BEEN AN ERROR
;SO LET REP TIMER RUN
78$: MOV #REPSEC,LB.REP(J) ;RESET REP TIMER
80$: CLRB LB.RDC(J) ;RESET LINE TIMEOUT COUNT DOWN
ADD #2,(P) ;SKIP ON RETURN
RTS PC
;HERE WHEN WE RECEIVE A START MESSAGE
DDRSTR:
.IF EQ FT3.02
.IF NE FT.MPT
BIT #LS.MPT,(J) ;IF NOT MULTIPOINT, THEN NOT DDCMP 3.02 SPEC
BNE DDRSSC
.ENDC ;.IF NE FT.MPT
BIT #LS..ST!LS.STK,(J) ;IF WE'RE NOT SENDING STARTS BEGIN NOW
BNE DDRSSB
JSR PC,L.DOWN ;BY DECLARING THE LINE DOWN
BR DDRQCT
DDRSSB: TST (R2)+ ;SKIP FILLERS
DDRSSK: MOVB @R2,LB.ROK(J) ;GET NEXT MESSAGE NUMBER TO RECEIVE
DECB LB.ROK(J) ;ADJUST IT
BIT #LS..ST,@J ;WAS I ALSO SENDING STARTS ?
BNE DDRSSD ;IF SO THEN JUST CLEAN UP
JSR PC,L.DOWN ;CLEAN OUT LINE BLOCK
.IFF
BIT #LS..ST!LS.STK,(J) ;TRYING TO START UP DDCMP?
BNE DDRSSC ;YES, JUST SEND A STACK
JSR PC,L.DOWN ;NO, DECLARE LINE "DOWN" FIRST
; BEFORE TRYING TO SEND A STACK
.ENDC ;.IF EQ FT3.02
DDRSSC:
.IF NE FT.MPT!FT3.02
.IF EQ FT3.02
BIT #LS.MPT,(J) ;IF A MULTIPOINT LINE
BEQ 20$
.ENDC ;.IF EQ FT3.02
CLR LB.ROK(J) ;RESET MSG NUMBERS
CLR LB.LAP(J)
TST LB.OBF+2(J) ;IF QUEUED MSGS,WE MUST FIX THEIR #S
BEQ 11$
MOV LB.OBF(J),R1
10$: INCB LB.HSN(J)
MOVB LB.HSN(J),CN.DDC+4(R1)
MOV CN.MLK(R1),R1
BNE 10$
11$: MOVB LB.OBF+4(J),LB.HSN(J) ;COUNT MSGS IN THE QUEUE AS UNACKED
CLR LB.COB(J) ;THERE IS NO LONGER A CURRENT DATA MSG
.ENDC ;.IF NE FT.MPT!FT3.02
DDRSSD:
JSR PC,DDRSNB ;ARE WE FORBIDDEN TO BRING THIS LINE UP?
BCS DD0ADV ;YES, CAN'T STACK YET, EAT THE START
10$: BIS #LS.XRP!LS.NRP!LS.STK,@J;SET SEND-STACK FLAG
BIC #LS..ST,@J ;CLEAR SEND-START FLAG
Z=REPSEC/2
.IIF EQ Z,Z=1
DDRSSE: MOV #Z,LB.REP(J) ;RESET REP TIMER & COUNTER
CLRB LB.RDC(J) ; CLEAR REP COUNT
.IF NE FT.RDM
BIT #LS.MPT,(J) ;IF MULTIPOINT,DON'T INFORM NCL
.IF NE FTTRIB
BEQ 30$
TST LB.MPL(J) ;BUT NOT IF TRIBUTARY
.ENDC
BNE DDRQCT
.ENDC ;.IF NE FT.RDM
;
;******* here is a convenient place for a sink macro call *****
;
30$: JSR PC,DDDRSS ;TELL WHOEVER THAT WE RESTARTED
DDRQCT:
.IF NE FT.RDM!FT.RDP
JSR R0,RDESST ;IF A RDE DEV, REPORT THE STATE
.BYTE 0,210
.ENDC
DD0ADV: JMP DDRADV
;HERE WHEN A STACK IS RECEIVED
DDRSTK: BIT #LS..ST!LS.STK,@J ;WERE WE IN START/STACK STATE?
BEQ DD0ADV ;NO, FUNNY PLACE FOR A STACK, EAT IT
.IF EQ FT3.02
.IF NE FT.MPT
BIT #LS.MPT,(J) ;IF A MULTIPOINT LINE
BNE DDRSSC ;RESTART THE RECEIVER
.ENDC
MOV (R2)+,R0 ;GET MSG # HE EXPECTS TO RECEIVE
SWAB R0 ;PUT # IN RH
DECB R0
CMPB R0,LB.LAP(J) ;DID HE HEAR ME ?
BEQ DDRSSK ;YES FOLLOWING CODE SAME AS START
TRAP
.IFF
JSR PC,DDRSNB ;ARE ANY [NCL] MEIGHBORS MSGS PENDING?
BCS DD0ADV ;YES, CAN'T ACK YET, EAT THE STACK
BIC #LS..ST!LS.STK,(J) ;NO LONGER SENDING START/STACK
BIS #LS.XAK,(J) ;BUT HAD BETTER SEND AN ACK
BR DDRSSE ;TELL NCL/NSP ABOUT NEW LINE
.ENDC
.ENDC;.IF NE,<NTLINE-DMCN>
;HERE TO TELL NEXT HIGHER LEVEL (NSP ! NCL) WE'VE RESTARTED
DDDRSS:
.IF NE FT.DDP
TST LB.ST2(J) ;IS THIS A DDP-DEDICATED LBLK?
BPL 10$ ;NO, NCL (OR NSP)
MOV J,-(P) ;YES, SAVE LBLK ADDRESS
MOV LB.DDB(J),J ;CONTEXT SWITCH TO DDB-NESS
JSR PC,DDPONL ;FLAG DDP DEVICE IS "ONLINE"
MOV (P)+,J ;CONTEXT SWITCH BACK TO LBLK-NESS
RTS PC ;ALL DONE
.ENDC ;.IF NE FT.DDP
10$:
.IF NE,FTDCP1!FTDCP3!FTDCP4
BIT #LS.NSP,(J) ;IS IT NSP LINE?
BEQ 20$ ;NO, GIVE TO NCL
PJMP NSPRSS ;TELL NSP ABOUT LINE STARTING
.ENDC; NE,FTDCP1!FTDCP3!FTDPC4
20$: PJMP NCLRSS ;TELL NCL ABOUT LINE STARTING
;DDRSNB -- SEE IF ANY NCL NEIGHBORS MESSAGES ARE PENDING.
;CALL IS:
; JSR PC,DDRSNB
; BCS NEIGHBORS-STILL-PENDING
;
;THIS ROUTINE IS USED BY START/STACK TO DEFER STARTING UP A DDCMP LINE UNTIL
;THE NET KNOWS THAT THIS LINE NO LONGER HAS A NEIGHBOR (I.E., SO THAT THE
;PROPOSED NEW NEIGHBOR TRYING TO COME UP ON THIS LINE WILL BE SURE TO BE
;SEEN COMING UP FRESH).
;
;IF THE LINE IS IN USE AS A "DDP" DEVICE, THEN UNLESS THE DEVICE IS CONNECTED
;TO A HOST THEN PROTOCOL STARTUP IS DEFERRED.
;
;ON RETURN, IF CARRY IS SET THEN THERE IS AT LEAST ONE NCL NEIGHBORS MESSAGE
;PENDING TRANSMISSION (WE DON'T COUNT A QUEUED NCL MESSAGE, ONLY THE SBF.NB
;"WANT TO SEND A NEIGHBORS MESSAGE" FLAG SINCE AS LONG AS THAT IS CLEAR A NEW
;NEIGHBORS MESSAGE REQUEST WILL GET THE NEW CONFIGURATION).
DDRSNB: MOV SB,-(P) ;PRESERVE THE REGS
.IF NE FT.DDP
TST LB.ST2(J) ;DEVICE OR COMM LINE?
BGE 50$ ;COMM LINE, CHECK FOR NCL NEIGHBORS
MOV LB.DDB(J),SB ;ADDRESS OF DDB
BIT #DS.DIE,@SB ;KROAKING OFF?
BNE 57$ ;YES, DON'T ACKNOWLEDGE THE START
BIT #DS.CON,@SB ;NO, IS CONNECTED TO A HOST?
BNE 15$ ;YES - MAYBE
12$: MOV J,-(P) ;NO, SAVE J FOR A BIT
MOV SB,J ;POSITION ADDRESS OF DDB FOR
JSR PC,QUEDEV ;QUEDEV TO NUDGE THE SERVICE ROUTINE
MOV (P)+,J ;RESTORE LB ADDRESS
BR 57$ ;AND REJECT THE START REQUEST FOR NOW
15$: TST DB.RLA(SB) ;IS DEVICE FULLY CONNECTED YET?
BEQ 57$ ;NO, NOT YET, HOLD OFF STARTING UP
;DAMN BIT #DS.XDS,@SB ;YES, CAN WE REPORT STATUS CHANGE?
;DAMN BNE 12$ ;NO, CAN'T CHANGE STATE JUST YET
;DAMN ; (BUT ENSURE STATUS GETS SENT SOON)
NOP ;DAMN
NOP ;DAMN
NOP ;DAMN
BR 92$ ;YES, HAPPY, SEND STACKS
.ENDC ;.IF NE FT.DDP
50$: TST NEGNGH ;ANY "NEGATIVE" NEIGHBORS RECENTLY?
BEQ 92$ ;NO, OK TO BRING UP A NEW NEIGHBOR
MOV #OURSCB,SB ;PRESET THE SCB LOOP
52$: BIT #SBF.IU,@SB ;THIS SCB ACTIVE?
BEQ 59$ ;NO, SKIP IT
BIT #SBF.NB,@SB ;YES, IS A NEIGHBORS MSG PENDING?
BEQ 59$ ;NO, SKIP TO NEXT CANDIDATE
57$: TWIDDLE ;YES, THIS IS AN INTERESTING OCCURANCE
SEC ;NEIGHBORS MESSAGES PENDING
BR 93$ ;TAKE EXCEPTION RETURN
59$: SB.ADV 52$ ;ADVANCE TO NEXT SCB
91$: CLR NEGNGH ;NO "NEGATIVE" NEIGHBORS MSGS PENDING
92$: CLC ;NO NEIGHBORS PENDING
93$: MOV (P)+,SB ;RESTORE REGS
RTS PC ;RETURN HAPPILY
;HERE WHEN RECEIVE A BOOTSTRAP MESSAGE
DRBOOT: TWIDDLE
.IF NE FT.STC
MOVB #1,LB.BNN+1(J) ;SET BOOT MODE FOR LINE
.IF NE FT.RDM
.IF EQ RDEDLL
BIT #LS.MPT,(J) ;IF RDE STATION, ZAP MSG
BEQ 10$
TST LB.MPL(J)
BNE 99$
10$:
.ENDC ;.IF EQ RDEDLL
.ENDC ;.IF NE FT.RDM
MOV R0,R3 ;COPY ADR OF MSG
MOV CN.LEN(R3),R2 ;GET LENGTH
ADD #CN.NCT,R3 ;POINT TO FIRST BYTE
;HERE TO DECIDE WHO GETS THE MESSAGE
JSR PC,GETEXN ;GET FIRST FIELD = DNA
TST R0 ;DID BOOT NODE INCLUDE IT ?
BEQ 22$
JSR PC,FNDSCB ;IS THERE SUCH A NODE ?
BEQ 99$ ;IF UNKNOWN IGNORE MSG
MOVB SB.NNM(SB),LB.BNN(J) ;LOCK WHO DOES BOOTS TO NODE
BR 50$
22$: MOVB LB.BNN(J),R0 ;GET WHO MIGHT CARE ABOUT THIS MESSAGE
BEQ 26$ ;IF NONE SEE WHO MIGHT CARE
JSR PC,FNDSCB ;SEE IF SUCH A NODE EXISTS
BNE 50$ ;IF SO USE IT
26$: MOV PATRON,SB ;GET PREVIOUS PATRONS ADR
BNE 32$ ;TRY FOR A NEW PATRON
MOV #FIRSCB,SB ;START WITH FIRST SCB
30$: BIT #SBF.IC,@SB ;ARE WE IN CONTACT ?
.IF NE FTHOST
BEQ 32$ ;NO, TRY NEXT SCB
BIT #SF.MCR,@SB ;ONLY SEND TO INTELLIGENT NODES
BNE 38$
.IFF
BNE 38$ ;IN CONTACT, SEND IT
.ENDC
32$: SB.ADV 30$
CLR PATRON ;START FROM BEGINNING ON NEXT MESSAGE
BR 99$ ;IF NO MORE SCBS, IGNORE MSG
38$: MOV SB,PATRON ;REMEMBER WHO GOT THE LAST BOOT MSG
;HERE WHEN HAVE DECIDED WHO TO SEND MSG TO
50$: MOV SB,SNA ;SAVE DESTINATION SCB ADR
; NCRESP WILL SWAP WITH DNA
MOV R3,SB ;COPY MSG POINTER
MOV R2,TEMP2 ;SAVE COUNT IN TEMPORARY LOCATION
MOV #OURSCB,DNA ;SOURCE NODE IS US (NCRESP WILL SWAP)
JSR PC,NCRESP ;BUILD MSG
BCS 99$ ;CHUCK MSG IF CANT FORWARD IT
MOV #7,R0 ;CODE FOR STATION CONTROL IS 7
JSR PC,PUTBYT ;PUT IT INTO MSG
MOV #FRSTLB,R1
CLR R0
52$: MOV LB.LNK(R1),R1
ASSERT NE ;TRAP IF J DOESN'T POINT TO LINE BLOCK
INC R0
CMP R1,J
BNE 52$ ;KEEP LOOKING IF WE HAVEN'T REACHED HOME
MOV TEMP2,R1 ;GET COUNT FOR BOOT MSG
JSR PC,PUTBYT ;PUT LINE NUMBER INTO MSG
54$: ADVCNK SB ;MOVE TO NEXT CHUNK IF NECESSARY
56$: MOVB (SB)+,R0 ;GET NEXT BYTE
JSR PC,PUTBYT
CMP #177,R2 ;HAS COUNT GOTTEN LARGE ?
BEQ 60$ ;IF SO PUNT
SOB R1,54$ ;LOOP BACK FOR REST OF BYTES
60$: JSR PC,@(P)+ ;FINISH MSG
.ENDC;.IF NE FT.STC
99$: ;HERE WHEN DONE
.IF NE,DMCN
.IF NE,<NTLINE-DMCN>
CMPB #LS..DM,LB.DVS(J) ;IS IT DMC11?
BNE 98$ ;NO, ACT NORMAL
.ENDC;.IF NE,<NTLINE-DMCN>
RTS PC ;RETURN TO DMC11 CODE
.ENDC;.IF NE,DMCN
.IF NE,<NTLINE-DMCN>
98$: JMP DDRADV ;IGNORE MESSAGE IF WE GET HERE
.ENDC;.IF NE,<NTLINE-DMCN>
;DDDGIV -- GIVE DDCMP DATA TO NEXT HIGHER LEVEL
;
;R0 IS ADDRESS OF FIRST CHUNK IN LINKED LIST OF RECEIVED DDCMP DATA
DDDGIV:
;
;******* here is a convenient place for a sink macro call *****
;
.IF NE FT.DDP
TST LB.ST2(J) ;IS THIS A DDP-CONTROLLED LBLK?
BPL 10$ ;NO, NCL (OR NSP)
MOV J,-(P) ;SAVE LBLK ADDRESS
MOV LB.DDB(J),J ;CONTEXT SWITCH TO DDP DEVICE LEVEL
JSR PC,DDPINP ;PROCESS DDP DATA INPUT READY
MOV (P)+,J ;RESTORE LBLK ADDRESS
RTS PC ;RETURN HAVING PROCESSED INPUT MESSAGE
.ENDC ;.IF NE FT.DDP
10$: MOV LB.SCB(J),SNA ;SET DEFAULT SOURCE NODE
.IF EQ DGUTS
ASSERT NE
.IFF
BNE 20$
JSR PC,FRECKS ;CHUCK THE MSG AND LOG THE ERROR
CTYMSG NCL
RTS PC
20$:
.ENDC ; .IF EQ DGUTS
.IF NE,FTDCP1!FTDCP3!FTDCP4
BIT #LS.NSP,(J) ;IS IT NSP LINE?
BEQ 40$ ;NO, CONTINUE NORMALLY
PJMP NSPINP ;YES, PASS INPUT TO NSP FIRST
.ENDC; NE,FTDCP1!FTDCP3!FTDPC4
40$: PJMP NCLIN0 ;GIVE IT TO NCL
.SBTTL DATA BCC
.IF NE,<NTLINE-DMCN>
; HERE TO CALCULATE BCC FOR A MSG
;
; CALLING SEQUENCE:
; R1=BYTE COUNT OF MESSAGE
; JSR PC,DDDBCC
; ERROR RETURN MESSAGE TOO LONG
; DUP DRIVER RETURN
; NORMAL RETURN
DDDBCC: MOV (P),-(P) ;COPY RETURN TO MAKE ROOM FOR BCC VALUE
CLR 2(P) ;FOR NULL MSGS
TST R1 ;IF LENGTH ZERO
BEQ 16$ ;ALL DONE
CMP R1,#MSGMAX ;ZAP HIM IF MSG TOO LOOOOONG
BHI 17$
.IF NE FTDUP11
CMPB #LS..UP,LB.DVS(J) ;IS THIS A DUP-11 DEVICE??
BNE 5$ ; GUESS NOT.
ADD #2,(P) ;EXIT DONT BOTHER WITH CRC STACK HAS 0
RTS PC
5$:
.ENDC ;IF NE FTDUP11
SAVE <R3,R1>
KGLOAD #0,WORD
;NOTE WE TAKE ADVANTAGE OF FACT THAT
; ;ALL MSGS BEGIN ON WORD BOUNDARY!!!
MOV #KGDATA,R3 ;HERE'S WHERE THE MSG GETS STUFFED
ASR R1 ;MAKE THE COUNT A WORD COUNT
BEQ 13$ ;SKIP WORD STUFFING IF ONE BYTE MSG
10$: ADVCNK R0 ;SKIP TO NEXT CHUNK IF NECESSARY
BNE 12$
11$: SUB #4,4(P) ;NO CHUNK?? BETTER ZAP HIM
BR 14$ ;FIX STACK, AND REGS THEN EXIT AT 14$
12$: MOV (R0)+,(R3) ;POINTER'S OK,SO FEED THE KG11
SOB R1,10$ ;AND LOOP IF STILL HUNGRY
BIT #1,(P) ;WAS LENGTH ODD
BEQ 14$
13$: ADVCNK R0 ;MOVE TO NEXT CHUNK IF NECESSARY
BEQ 11$ ;ZAP HIM IF THERE'S NO BYTE
BIC #KG.DDB,KG.STS ;EXTRA BYTE SO CHANGE KG TO BYTE MODE
MOVB (R0)+,(R3) ;AND FEED HIM THE LAST BYTE
14$: MOV (P)+,R1 ;RESTORE R1
MOV -(R3),4(P) ;SAVE THE BCC FROM THE KG
MOV (P)+,R3 ;RESTORE R3
16$: ADD #4,(P) ;FIX THE RETURN ADDRESS
17$: RTS PC ;AND EXIT
.ENDC;.IF NE,<NTLINE-DMCN>
.ENDC ; .IF NE NTLINE
.SBTTL LINK DOWN
.IF NE NTLINE
;HERE WHEN LINE GOES DOWN
L.DOWN: TRACE ;LEAVE TRACKS
TWIDDLE J ;LINE WHICH WENT DOWN
TWIDDLE
.IIF NE FTWHYD, MOV @P,LB.WHA(J) ;SAVE WHO CALLED US
;FIRST RESET THE LINE
;
;JSR PC,SL.INI
05$:
;FLUSH OUTPUT QUEUE
MOV #JIFSEC/REPSPD*17,LB.REP(J); DONT COME BACK FOR 15 SECONDS
CLRB LB.RDC(J) ;CLEAR REP DOWN COUNT
CMP LB.COB(J),LB.BOO(J) ;MUSTNT CAUSE BOOT MSG TO GET LOST
.IF NE FT.MPT
BNE 6$
BIT #LS.MPT,(J) ;EXCEPT IF MULTI POINT
BEQ 10$
MOV LB.BOO(J),R0 ;IN WHICH CASE BE SURE IT GETS LOST
JSR PC,FRECKS
CLR LB.BOO(J)
CLR LB.BNN(J)
.IFF
BEQ 10$
.ENDC; .IF NE FT.MPT
6$: CLR LB.COB(J) ;NO CURRENT BUFFER
10$: MOV LB.OBF(J),R0 ;GET FIRST OUTPUT BUFFER
BEQ 20$ ;BRANCH IF HAVE DONE ALL
MOV CN.MLK(R0),LB.OBF(J) ;DELINK MSG
.IF NE FT.DDP
TST LB.ST2(J) ;IS THIS A DDP-CONTROLLED LBLK?
BPL 11$ ;NO - MAYBE NCL DATA
JSR PC,FRECKS ;YES, JUST TOSS THE DATA
BR 14$ ;AND LET IT GO AT THAT
.ENDC ;.IF NE FT.DDP
11$:
.IF NE FTDCP1!FTDCP3!FTDCP4 ;DON'T REQUEUE DCP MSGS
BIT #LS.NSP,(J) ;IF THIS ISN'T A DCP LINE
BEQ 12$ ; THEN REQUEUE THE MSG
JSR PC,FRECKS ;OTHERWISE FREE THE MSG
BR 14$ ; AND CONTINUE
.ENDC; NE,FTDCP1!FTDCP3!FTDPC4
12$: JSR PC,MSGREQ ;REQUEUE THE MESSAGE NEXT TICK
;(WILL BE RE-ROUTED IF POSSIBLE)
14$: DEC LB.OBF+4(J) ;COUNT OUT MESSAGE WE FINISHED
BR 10$ ;AND LOOPBACK FOR REST OF MESSAGES
20$:
.IF NE FT.MPT
BIT #LS.MPT,(J) ;IF MULTIPOINT LINE
BEQ 27$
BISB #MP.OFF,LB.MPS(J) ;SET THE STATION OFFLINE
BICB #MP.SOL,LB.MPS(J) ;SET THE STATION OFFLINE
BITB #MP.SEL,LB.MPS(J) ;AND IF SELECTED
BEQ 25$
JSR PC,SELNXT ;SELECT THE NEXT STATION IF POSSIBLE
25$:
.IIF NE FTRDED, JSR PC,RPTDWN ;TELL CTY DROP IS DOWN
.IF NE FT.RDM!FTTRIB
.IF NE FTTRIB
TST LB.MPL(J) ;DO DIFFERENT THINGS FOR TRIBS AND RDES
BEQ 26$
JSR R0,RDESST ;IF A RDE DEV, REPORT THE STATE
.BYTE 0,203
BR 27$
26$:
MOVB #MP.OFF,LB.MPS(J) ;IF TRIB BE SURE ITS OFFLINE
.IFF ;.IF NE FTTRIB
JSR R0,RDESST ;IF A RDE DEV, REPORT THE STATE
.BYTE 0,203
.ENDC ;.IF NE FTTRIB
.IFF
TST LB.MPL(J) ;DO DIFFERENT THINGS FOR TRIBS AND RDES
BNE 27$
MOVB #MP.OFF,LB.MPS(J) ;IF TRIB BE SURE ITS OFFLINE
.ENDC ;.IF NE FT.RDM!FTTRIB
27$:
.ENDC ;.IF NE FT.MPT
ASSERT EQ LB.OBF+4(J) ;SHOULD HAVE RESET TO 0
CLR LB.OBF+2(J) ;CLEAR POINTER TO END OF QUEUE
BIC #^C<LS..RQ!LS..XQ!LS..XG!LS..RG!LS.MPT>,@J ;CLEAR MOST FLAGS
BIS #LS..ST!LS.XRP,@J ;NEED TO SEND A START
;*** ALTHOUGH THERE IS NOTHING REALLY IN THE DDCMP SPEC TO PROHIBIT SIMPLY
;*** STARTING OFF WITH WILD AND WIERD NUMBERS, SOME LESS-THAN-ROBUST SYSTEMS
;*** TEND TO GET TERRIBLY CONFUSED IF THE FIRST DDCMP NUMBERED MESSAGE ISN'T
;*** NUMBER "1", SO . . . RESET THE MESSAGE NUMBERS
;*** MOVB LB.LAP(J),LB.HSN(J) ;HIGHEST PROC IS HIGHEST SENT
;*** MOVB LB.HSN(J),LB.LAR(J)
CLR LB.ROK(J) ;RESET MSG NUMBERS
CLR LB.LAP(J)
.IF NE FT.DDP
TST LB.ST2(J) ;IS THIS A DDP-CONTROLLED LINE?
BPL 40$ ;NO, DO NCL'ISH STUFF
MOV J,-(P) ;YES, SAVE LBLK ADDRESS
MOV LB.DDB(J),J ;CONTEXT SWITCH TO DDP DEVICE LEVEL
JSR PC,DDPOFL ;SAY THE DDP DEVICE IS "OFFLINE"
MOV (P)+,J ;RESTORE DDB ADDRESS
RTS PC ;NOTHING MORE TO DO
.ENDC ;.IF NE FT.DDP
40$: MOV LB.SCB(J),SB ;IS THERE A SCB ADR
BEQ 90$ ;IF NOT DON'T NEED TO ROUTE
; CLR SB.LBA(SB) ;CLEAR ROUTE TO GET TO SCB
.IF NE FTDCP3!FTDCP4
BIT #LS.NSP,@J ;NSP LINE?
BEQ 60$ ;NO, NCL DOESN'T CARE
JSR PC,NSPDWN ;NSP HAS LBLK STUFF IT HAS TO CLEAR
60$:
.ENDC; NE,FTDCP3!FTDPC4
CLR LB.SCB(J) ;NEED DIFFERENT SCB FOR THIS LINE BLOCK
BIT #SF.HID,@SB ;DID I KNOW WHO HE WAS ?
BNE 70$ ;IF WE DID SEND NEIGHBOURS TO WORLD
CLR @SB ;RELEASE SCB
BR 90$
70$: JSR PC,ROUTE ;REROUTE THE WORLD
JSR PC,SNDNGD ;TELL EVERYONE A NEIGHBOR WENT DOWN
90$: RTS PC
COMODN: ;COMMON OUTPUT DONE
;
;******* here is a convenient place for a sink macro call *****
;
.IF NE FT.DDP
TST LB.ST2(J) ;IS THIS A DDP-CONTROLLED LINE?
BPL 10$ ;NO, NCL OR SIMILAR
MOV J,-(P) ;SAVE LBLK ADDRESS
MOV LB.DDB(J),J ;CONTEXT SWITCH TO DDP-DEVICE LEVEL
JSR PC,DDPODN ;PROCESS OUTPUT DONE
MOV (P)+,J ;RESTORE LBLK ADDRESS
RTS PC ;ALL DONE WITH THAT DATA
.ENDC ;.IF NE FT.DDP
10$:
.IF NE FT.RDM
BIT #LS.MPT,(J) ;IF RDE STATION, CHUCK MSGS
BEQ 20$
TST LB.MPL(J)
BEQ 20$
PJMP RDEODN
.ENDC ;.IF NE FT.RDM
20$:
.IF NE,FTDCP1!FTDCP3!FTDCP4
BIT #LS.NSP,(J) ;IS IT AN NSP LINE?
BEQ 30$ ;NO, PASS MESSAGES TO NCL
PJMP NSPODN ;TELL NSP THAT OUTPUT IS DONE
.ENDC; NE,FTDCP1!FTDCP3!FTDPC4
30$: PJMP NCLODN ;GIVE MESSAGE BACK TO NCL
.ENDC ; .IF NE NTLINE
.IF NE FTRDED
;ROUTINE TO TELL CTY A DROP WENT OFFLINE
RPTDWN: MOV LOWUP,LB.OFA+2(J) ;GET LOW ORDER UPTIME AND SAVE IT
MOV HIGHUP,LB.OFA(J) ;SAVE HIGH ORDER
MOVB LB..LN(J),R0 ;GET DH LINE #
JSR PC,GIVASC ;GET IT BACK PRINTABLE
MOVB R0,L.RDXL+1 ;SAVE IT AS RDA #
SWAB R0 ;GET HIGH ORDER
MOVB R0,L.RDXL ;SAVE IT
MOVB LB.MPA(J),R0 ;GET DROP #
JSR PC,GIVASC ;GET IT BACK PRINTABLE
MOVB R0,L.RDXD+1 ;SAVE IT IN STRING
SWAB R0 ;GET HIGH ORDER
MOVB R0,L.RDXD ;SAVE IT
SAVE <J,R1,R3>
MOV #CTYDDB,J ;THIS IS FOR THE CTY
MOV #DWNSTR,R1 ;NOW TYPE THE STRING AT THE CTY
10$: MOVB (R1)+,R0 ;GET A CHAR
BEQ 20$ ;DONE IF ZERO
JSR PC,QTYCHR ;TYPE IT
BR 10$ ;KEEP GOING
20$: JSR PC,BEGXMT ;START IT
RESTORE <R3,R1,J>
RTS PC ;RETURN
;ROUTINE TO RETURN IN R0 PRINTABLE CHARS. UP TO 77
GIVASC: MOV R0,-(P) ;SAVE VALUE
ASR R0 ;GET HIGH ORDER FIRST
ASR R0
ASR R0
BIC #^C7,R0 ;JUST 3 BITS PLEASE
ADD #60,R0 ;MAKE IT ASCII
MOVB R0,1(P) ;SAVE IT IN HIGH ORDER BYTE
MOV (P),R0 ;GET BACK VALUE
BIC #^C7,R0 ;JUST LOW ORDER 3 BITS
ADD #60,R0 ;MAKE IT ASCII
MOVB R0,(P) ;SAVE IT
MOV (P)+,R0 ;GET BACK BOTH BYTES
RTS PC ;AND RETURN THEM TO USER
DWNSTR: .BYTE 15,12,7,7 ;CR, LF,BELL,BELL
.ASCII /Drop /
L.RDXD: .BYTE 0,0 ;DROP #
.ASCII / on RDE /
L.RDXL: .BYTE 0,0 ;DH LINE # HERE
.ASCII / went offline?/
.BYTE 15,12,7,7,0 ;THATS ALL...
.EVEN
.ENDC ;.IF NE FTRDED
.SBTTL DDPSER - DDP DEVICE SERVICE ROUTINES
.IF NE FT.DDP
.IF NE DDPN
;THE DDP DEVICE ALLOWS THE VARIOUS DDCMP LINES TO BE USED AS DIRECT I/O
;DEVICES RATHER THAN AS NCL (OR NSP) NETWORK COMM LINES.
;DDP DEVICE PARAMETERS SETTABLE ON A "PER-LINE" BASIS
;
; DPnnWID ;"RECORD SIZE" OR MESSAGE SIZE
; DPnnCHK ;CHUNKS-PER-DATAREQUEST WEIGHTING
; DPnnRNN ;RESTRICTED HOST ASSIGNMENT
; DPnnPFH ;PREFERRED HOST ASSIGNMENT
;DB.DCS DDP-SPECIFIC DEVICE STATUS BITS
DPS.AV=000001 ;DDCMP IS AVAILABLE (L2.DDP IS SET)
DPS.RN=000002 ;DDCMP IS RUNNING (PROTOCOL UP)
DPS.BL=010000 ;"BLOCK TOO LARGE" ERROR
DPS.DT=020000 ;"DATA" ERROR (*)
DPS.DE=040000 ;"DEVICE" ERROR (*)
DPS.IP=100000 ;"IMPROPER MODE" ERROR (*)
; * = NOT USED BY -11, ONLY WITHIN THE -10
DPS.ER=DPS.BL!DPS.DT!DPS.DE!DPS.IP
;GENERATE DDB "UNIT-SPECIFIC" VALUES
.MACRO X XZZ
DP'XZZ'STS=LBLK'XZZ ;DUMMY DB.HDW "HARDWARE ADDRESS"
.IIF NDF DP'XZZ'WID,DP'XZZ'WID=DDPMML
.IIF NDF DP'XZZ'CHK,DP'XZZ'CHK=DDPCHK
.IIF NDF DP'XZZ'RNN,DP'XZZ'RNN=DDPRNN
.IIF NDF DP'XZZ'PFH,DP'XZZ'PFH=DDPPFH
.ENDM ;.MACRO X
ZZ=0
.REPT DDPN
X \ZZ
ZZ=ZZ+1
.ENDR ;.REPT DDPN
;DDB ENTRIES SPECIFIC TO DDP DEVICES
DB.LBK=DB.SIZ+00 ;ADDRESS OF ASSOCIATED LBLK
DB.DDI=DB.SIZ+02 ;ADDRESS OF FIRST QUEUED (TO -10) DDCMP DATA MESSAGE
; DB.SIZ+04 ;ADDRESS OF LAST QUEUED
; DB.SIZ+06 ;COUNT OF QUEUED DDCMP DATA MESSAGES WAITING
;MACRO TO GENERATE DEVICE-SPECIFIC DDB STUFF
.MACRO DDXGEN DEV,DV,DRQ,QBITS,XZZ
.WORD LBLK'XZZ ;DB.LBK
.WORD 0, 0, 0 ;DB.DDI
.ENDM ;.MACRO DDXGEN
;FINALLY, GENERATE THE DDP DDBS
DRESET=0
DDBGEN DDP,DP,DDPN,DDPDRQ,<DS.OUT>
;CLEAR DEFINITION OF DDXGEN
.MACRO DDXGEN DEV,DV,DRQ,QBITS,XZZ
.ENDM
;DDPSER - DDP DEVICE SERVICE ROUTINE
DDPSER: CMP #DDPMML,DB.MML(J) ;GOT A REASONABLE MESSAGE LIMIT?
BGE 10$ ;YES
MOV #DDPMML,DB.MML(J) ;NO, SET OUR MAXIMA
10$: MOV #DCM.IM,DB.DCM(J) ;SET DATA TYPE "IMAGE" DATA ONLY
MOVB #OBJDDP,DB.ROT(J) ;FORCE CONNECT TO HOST'S DDP SERVICE
MOV DB.LBK(J),R0 ;ADDRESS OF ASSOCIATED LINE BLOCK
MOVB LB.DVS(R0),R0 ;DEVICE-SERVICE TYPE
ASR R0 ;CONVERT TO DIRECT TYPE
CMPB #LS..AL,R0 ;SYNC OR ASYNC?
BHI 11$ ;SYNC, USE VALUE AS IS
ADD #200-LS..AL,R0 ;ASYNC, "SHIFT"
11$: MOVB R0,DB.DVV(J) ;SET "CONTROLLER" TYPE
JSR PC,DVCCFM ;DO DIS/CONNECT CONFIRM AS NEEDED
;REGENERATE DPS.AV AND DPS.RN ON GENERAL PRINCIPLES (THIS ENSURES NO
;SYNCHRONIZATION ERRORS BETWEEN ON/OFF LINE AND DIS/CONNECT, AS WELL AS
;PEOPLE POKING THE -11 WITH DDT11 . . .)
MOV DB.LBK(J),R0 ;ADDRESS OF ASSOCIATED LINE BLOCK
MOV DB.DCS(J),-(P) ;SAVE COPY OF CURRENT DCS
BIS #DPS.AV!DPS.RN,DB.DCS(J) ;ASSUME GOODNESS
BIT #LS..ST!LS.STK,LB.STS(R0) ;IS DDCMP RUNNING?
BEQ 17$ ;YES, GOOD SO FAR
BIC #DPS.RN,DB.DCS(J) ;DDCMP IS NOT RUNNING AFTER ALL
17$: BIT #L2.DDP,LB.ST2(R0) ;IS THE LBLK AVAILABLE TO US?
BNE 18$ ;YES
BIC #DPS.AV!DPS.RN,DB.DCS(J) ;NO, THE DDP IS USELESS
18$: CMP (P)+,DB.DCS(J) ;DID WE CHANGE ANYTHING?
BEQ 19$ ;NO, NO NEED TO BOTHER THE -10
BIS #DS.XDS,@J ;YES, MUST TELL THE -10
19$: JSR PC,DVXDCS ;SEND DEVICE STATUS IF NEEDED
BIC #DPS.ER,DB.DCS(J) ;CLEAR ERROR STATUS
TST DB.OBF(J) ;GOT ANY OUTPUT PROCESSING TO DO?
BNE DDPOS0 ;YES, PROCESS OUTPUT FIRST
DDPSI0: JMP DDPIS0 ;NO, JUST CHECK THE INPUT SIDE OF THINGS
;DDPOS0 - OUTPUT SERVICE
DDPOS0: CMP #ERSCNT,FRECNT ;GOT ROOM TO DO ANYTHING?
BLT DDPOS1 ;YES, FIRE UP NCL OUTPUT COPY
TWIDDLE ;NO, THIS IS INTERESTING
BIS #DS.COR,@J ;FLAG WE'D LIKE TO RUN AGAIN SOMEDAY
JMP DDPIS1 ;DON'T EVEN SEND DATA REQUESTS FOR NOW
DDPOS1: JSR PC,DVGBYT ;START READING NEXT NCL SUBMESSAGE
TRAP ;BETTER NOT STILL BE IN A MESSAGE!
BR 10$ ;START OF NEW SUBMESSAGE (EXPECTED)
BR DDPSI0 ;ALL DONE, DO INPUT SERVICE (AND DRQ)
;PROCESS NCL MESSAGE
10$: DEC R0 ;1
BEQ 13$ ; = DATA WITHOUT EOM
DEC R0 ;2
BEQ DDPOS5 ; = DATA WITH EOM
DEC R0 ;3
BEQ 30$ ; = STATUS
DEC R0 ;4
BEQ 40$ ; = CONTROL
;HERE IF UNKNOWN NCL MESSAGE TYPE
13$:
.IF EQ DGUTS
TRAP
.IFF
CTYMSG NCL ;COMPLAIN
15$: JSR PC,DVGBYT ;LOOP EATING UNKNOWN NCL
BR 15$ ;KEEP EATING
BR 10$ ;TRY NEXT NCL MESSAGE
BR DDPSI0 ;ALL DONE WITH OUTPUT SERVICE
.ENDC ;.IF EQ DGUTS
;HERE TO PROCESS RECEIVED NCL STATUS
30$: JSR PC,DVRSTS ;PROCESS RECEIVED STATUS
BR DDPOS1 ;SO MUCH FOR THAT
;HERE TO PROCESS RECEIVED NCL CONTROL
40$: BR 13$ ;NO CONTROL IMPLEMENTED YET
;HERE TO PROCESS RECEIVED DATA
DDPOS5: MOV DB.OCN(J),R2 ;COUNT OF SUBMESSAGE BYTES LEFT
BEQ DDPOS0 ;LOOP BACK FOR MORE DATA
BIT #DPS.AV,DB.DCS(J) ;CAN WE GIVE THE DATA TO THE LBLK?
BNE 50$ ;YES
10$: JSR PC,DVGBYT ;NO, EAT THE DATA MESSAGE
BR 11$ ;EAT EXPECTED DATA BYTE
TRAP ;++ START OF NEW MESSAGE BEFORE COUNT RAN OUT!
TRAP ;++ OUT OF DATA BEFORE COUNT RAN OUT!
11$: SOB R2,10$ ;EAT ANY DATA REMAINING
BIS #DPS.IP,DB.DCS(J) ;IT IS "IMPROPER" TO SEND DATA
PJMP QUEXDS ;COMPLAIN TO THE -10
50$: MOV DB.OAD(J),R1 ;ADDRESS OF SUBMESSAGE BYTES LEFT
JSR PC,CABLTB ;ALLOCATE AND COPY BYTE STREAM
MOV R1,DB.OAD(J) ;SET NEW CURRENT SUBMESSAGE BYTE GETTER
MOV R2,DB.OCN(J) ;AND NEW CURRENT SUBMESSAGE BYTE COUNTER
ASSERT EQ ;WHICH HAD BETTER BE EMPTY!
MOV J,-(P) ;SAVE DDB ADDRESS
MOV DB.LBK(J),J ;CONTEXT SWITCH TO LBLK
MOV #SOH,R2 ;DECLARE DDCMP "DATA" MESSAGE
JSR PC,DDQDDP ;GIVE OUTPUT (IN R0) TO DDCMP
MOV (P)+,J ;BACK TO DDB-LEVEL
BR DDPOS0 ;LOOP BACK FOR MORE OUTPUT
;DDPIS0 - INPUT SERVICE
DDPIS0: MOV DB.LBK(J),R3 ;ASSOCIATED LBLK
CMP #10,LB.OBF+4(R3) ;GOT TOO MUCH DATA BACKED UP?
BLE DDPIS1 ;YES, NO DATA REQUESTS YET
JSR PC,DVXDRQ ;SEND DATA REQUESTS AS NEEDED
;PROCESS ANY INPUT WAITING FOR THE -10
DDPIS1: MOV DB.DDI(J),R0 ;GOT ANY INPUT DATA TO SEND
BEQ 20$ ;NO
TST DB.RLA(J) ;YES, GOT ANYWHERE TO SEND IT?
BNE DDPIS5 ;YES, SEND INPUT DATA TO HOST
;DATA BUT NO HOST YET. EAT THE DATA
;RDH JSR PC,FRECNL ;CLEAR UP THE INPUT QUEUE
;RDH CLR DB.DDI(J) ;NO INPUT LEFT ANYMORE
;RDH CLR DB.DDI+2(J) ; . . .
;RDH CLR DB.DDI+4(J) ; ! ! !
;MAKE SURE A HOST IS FORTHCOMING
20$: BIT #DS.CON,@J ;ARE WE CONNECTED?
BNE DDPIS9 ;YES, FINE, JUST DISAPPEAR
JSR PC,FNDPFH ;LOOK FOR A SUITABLE HOST
BEQ DDPIS9 ;NONE, PLAIN OUT OF LUCK
JSR PC,SNDCON ;TRY TO CONNECT TO LUCKY HOST
BR DDPIS9 ;WAIT AND SEE WHAT HAPPENS
;PROCESS INPUT DATA QUEUED FOR THE HOST
DDPIS5: TSTB DB.IDR(J) ;GOT ANYTHING TO DO WITH THE DATA?
BEQ DDPIS9 ;NO DATA REQUESTS, NO FURTHER WE CAN GO
;PACKAGE THE DATA AND SHIP IT TO THE HOST
10$: MOV #002,R0 ;NCL DATA WITH EOM MESSAGE TYPE
JSR PC,DVDBSM ;BEGIN BIG NCL DATA SUBMESSAGE
BCS DDPIS9 ;ON SECOND THOUGHT, PUT IT OFF FOR AWHILE
20$: MOV DB.IAD(J),R0 ;NCL CHUNK-BYTE ADDRESS TO RECEIVE DATA
MOV DB.DDI(J),R1 ;CURRENT CHUNK ADDRESS HOLDING DATA
ASSERT NE ;MAKE SURE IT IS STILL THERE
MOV CN.MLK(R1),DB.DDI(J) ;DELINK FROM INPUT QUEUE
BNE 23$ ;SKIP IF STILL MORE TO COME
CLR DB.DDI+2(J) ;IF NO MORE FIRST, THEN NO LAST EITHER
23$: DEC DB.DDI+4(J) ;COUNT DOWN PENDING "DATAGRAMS"
MOV CN.LEN(R1),R2 ;COUNT OF DATA BYTES IN INPUT MESSAGE
BEQ 55$ ;NO DATA TO COPY
;*** CMP DB.MML(J),R2 ;MESSAGE SIZE WITHIN BOUNDS?
CMP #DDPMML,R2 ;*** SIGH CONNECT CONFIRM LEAVES THIS 0!
BHIS 25$ ;YES, STILL SAFE
BIS #DPS.BL,DB.DCS(J) ;NO, NOTE "BLOCK TOO LARGE" ERROR
;*** MOV DB.MML(J),R2 ;SEND AS MUCH AS WE CAN
MOV #DDPMML,R2 ;*** SIGH
25$: ADD R2,DB.ICN+4(J) ;PRECOUNT DATA BYTES TO BE COPYED
ADD #CN.NCT,R1 ;POINT R1 TO ACTUAL DATA BYTES
JSR PC,CNBLTB ;COPY DDCMP DATA INTO NCL MESSAGE
MOV R0,DB.IAD(J) ;UPDATE NCL MESSAGE POINTER
55$: MOV R1,R0 ;TRAILING CHUNK ADDRESS FOR DDCMP MESSAGE
BIC #CNKSIZ-1,R0 ;BACK UP TO START OF CHUNK
JSR PC,FRECKS ;DEALLOCATE WHATEVER'S LEFT
JSR PC,DVDSBM ;CLOSE OFF NCL SUBMESSAGE
JSR PC,NCLIN1 ;GIVE IT TO NCL TO ROUTE TO HOST
CLR DB.IBF(J) ;WE DON'T OWN IT ANYMORE
DECB DB.IDR(J) ;USED UP ONE DATA REQUEST
BIT #DPS.ER,DB.DCS(J) ;GOT ANY ERRORS PENDING?
BNE 59$ ;NO
PJMP QUEXDS ;YES, NEED TO TELL -10
59$: TST DB.DDI(J) ;GOT ANY MORE DDCMP DATA MESSAGES?
BNE DDPIS5 ;YES, TRY TO SHIP MORE
DDPIS9: RTS PC ;ALL DONE WITH THIS DDP DEVICE
;DDPINI - DDP SERVICE INITIALIZATION
DDPINI: RTS PC ;YAWN
;DDPTIM - DDP SERVICE TIMEOUT
DDPTIM: TRAP ;NOT IN USE
;DDPODN - DDP SERVICE "OUTPUT DONE" FROM DRIVER LEVEL
;
;CALLED WITH FINISHED MESSAGE IN R0
DDPODN: JSR PC,FRECKS ;FREE OUTPUT MESSAGE
JMP QUEDEV ;NUDGE THE DEVICE (DATA REQUESTS, ETC.)
;DDPINP - DDP SERVICE "INPUT DONE" FROM DRIVER LEVEL
;
;CALLED WITH NEWLY-RECEIVED MESSAGE IN R0
DDPINP: MOV DB.DDI+2(J),R1 ;ADDRESS OF LAST MESSAGE QUEUED UP
BNE 12$ ;ADD NEW MESSAGE TO END OF QUEUE
MOV R0,DB.DDI+0(J) ;SET NEW FIRST MESSAGE QUEUED UP
.IF EQ DGUTS
TST DB.DDI+4(J) ;IS COUNT ALSO 0?
BEQ 17$ ;YES, ALL SET
TRAP ;DISCREPANCY
.IFF
BR 17$ ;CAP OFF QUEUE
.ENDC ;.IF EQ DGUTS
12$: MOV R0,CN.MLK(R1) ;PUT LATEST ENTRY AT END OF INPUT QUEUE
17$: MOV R0,DB.DDI+2(J) ;SET NEW LAST MESSAGE IN QUEUE
INC DB.DDI+4(J) ;COUNT NUMBER OF QUEUED MESSAGES
PJMP QUEDEV ;QUEUE DEVICE FOR SERVICE
;DDPONL - DDP SERVICE "ONLINE CONDITION" FROM DRIVER LEVEL
DDPONL: BIS #DPS.RN,DB.DCS(J) ;NOTE THAT DDCMP IS RUNNING
PJMP QUEXDS ;TELL THE -10 THE GOOD NEWS
;DDPOFL - DDP SERVICE "OFFLINE CONDITION" FROM DRIVER LEVEL
DDPOFL: BIC #DPS.RN,DB.DCS(J) ;NOTE THAT DDCMP IS DOWN
PJMP QUEXDS ;TELL THE -10 THE BAD NEWS
.ENDC ;.IF NE DDPN
.ENDC ;.IF NE FT.DDP
;***** END OF THE DDP SERVICE ROUTINES
.SBTTL RECEIVER INTERRUPT
.IF NE NTLINE
.IF NE,<NTLINE-DMCN>
;HERE AT INTERRUPT LEVEL WHEN FINISH RECEIVING 8 CHARS OF JUNK
DDRJNK: MOV LB.IPT(J),R1 ;GET PUTTER ADR
ADD J,R1 ;MAKE ADR OF BUFFER
MOVB (R1)+,R0 ;GET 1ST CHAR OF HDR
CMPB R0,#SOH ;DID 1ST CHAR SAY DATA MSG ?
BEQ DRJ.30
CMPB R0,#DLE ;BEGINING OF BOOTSTRAP MSG ?
BEQ DRJ.30 ;IF SO TREAT AS NUMBERED MSG
CMPB R0,#ENQ ;DID 1ST CHAR SAY CONTROL MSG ?
BNE DRJ.26 ;IF NOT CONTROL CLEAR RECEIVER
CMPB (R1),#7 ;IF NOT A CONTROL CODE
BHI DRJ.26 ;CLEAR THE RECEIVER
;HERE AT WHEN HAVE RECEIVED 1ST 4 CHARS OF CONTROL MSG
MOV #DRJ.20,LB.RDN(J) ;WHERE TO GO WHEN FINISH MSG
DRJ.10: MOV LB.IPT(J),R0 ;GET INPUT PUTTER
.IIF NE FT.QSB, MOV R0,R1
ADD #12,R0 ;ADVANCE TO NEXT BUFFER
CMP R0,#LB.IBF+<NINBUF*12> ;TIME TO WRAP AROUND YET ?
BNE 10$
MOV #LB.IBF,R0 ;YES
10$: CMP R0,LB.ITK(J) ;HAVE WE CAUGHT UP TO TAKER ?
BEQ DRJ.25 ;IF SO CAN'T ACCEPT LAST
ADD J,R0 ;MAKE ABS ADR OF BUFFER
CLR (R0)
.IF NE FT.QSB
ADD J,R1
CMPB #DLE,@R1 ;WAS THIS A MAINT MSG
BEQ 20$ ; THEN ALWAYS ASSUME QSYNC EVEN
; THOUGH THE DMC WON'T SET IT.
BITB #QSYNC,2(R1)
BEQ 30$
.ENDC
20$: BIS #LS.SSY,@J ;STRIP SYNCH AGAIN
30$: MOV #-4,R1 ;LENGTH OF WHAT TO READ
.IF NE NALINE+NMPTL+NTRIB
CMPB #LS..AL,LB.DVS(J) ;IF ASYNC LINE, SCAN BY CHAR
BHI 40$
ADD #3,R1
40$:
.ENDC
RTS PC ;BACK TO SYNCHRONOUS LINE HANDLR
;HERE WHEN HAVE RECEIVED LAST 4 CHARS OF CONTROL MSG
DRJ.20: JSR PC,DRJ.90 ;CHECK THE BCC
DRJ.21: MOV LB.IPT(J),R0 ;GET REL ADR JUST FINISHED
ADD #12,R0 ;ADVANCE TO NEXT BUFFER
CMP R0,#LB.IBF+<NINBUF*12> ;TIME TO WRAP AROUND ?
BNE 22$
MOV #LB.IBF,R0 ;YES
22$: MOV R0,LB.IPT(J) ;REMEMBER NEW PUTTER
ADD J,R0 ;MAKE POINTER ABSOLUTE
CLR 10(R0) ;CLEAR CHUNK POINTER
QUEPUT QI 24$ ;PUT LAST MSG INTO QUEUE
.IF NE NALINE+NMPTL+NTRIB
CMPB #LS..AL,LB.DVS(J) ;IF ASYNC LINE, MUST FORCE RESYNCH
BHI 23$
.IF NE NDHMPT!NADHLN!NDHTRB
MOV #DHRSYN,R1
.IFF
MOV #ERRINT,R1 ;IF THIS HAPPENS, ITS DOOMERS
.ENDC
.IF NE NDZMPT!NADZLN!NDZTRB
CMPB #LS..DZ,LB.DVS(J) ;DZ LINE?
BNE 24$ ;NO
MOV #DZRSYN,R1 ;YES, SET FOR DZ SYNC INPUT
24$:
.ENDC
MOV R1,LB.RDN(J) ;SAVE ADDRESS
INC R0 ;NEXT BUFFER IS +1 CHAR
MOV #-1,R1 ;AND ITS LENGTH IS 1
RTS PC
23$:
.ENDC
ADD #4,R0 ;POINT TO 2ND HALF OF HEADER
MOV #-4,R1 ;TO FINISH NEXT HALF
MOV #DDRJNK,LB.RDN(J) ;WHEN THIS ONE FINISHES
RTS PC
;HERE IF LOW LEVEL CAN'T KEEP UP
DRJ.25: TWIDDLE ;COUNT TIMES THIS HAPPENS
MOVB #NCDNRM,LB.NCD(J) ;WE RAN OUT OF ROOM,
JSR PC,DRNAK1 ; SO SEND A NAK
BR DRJ.27
;HERE IF RECEIVED NONVALID MESSAGE BEGINER
DRJ.26:
TWIDDLE R0
TWIDDLE
DRJ.27: TRACE DD ;TRACE TIMES THIS HAPPENS
.IF NE NMPTL+NTRIB+NALINE
CMPB #LS..AL,LB.DVS(J)
BHI 19$
CLR LB.SRR+2(J) ;MUST FORCE THE RECEIVER TO STOP
;FOR RESYNCH ON MSG BOUNDARY
19$:
.ENDC
CLR R1 ;PASS 0 DATA COUNT
RTS PC
;HERE WHEN HAVE JUST RECEIVED 1ST FOUR CHARS OF DATA HEADER
DRJ.30: MOVB (R1)+,-(P) ;GET LOW ORDER BITS OF MSG SIZE
MOVB (R1)+,1(P) ;GET HIGH ORDER BITS OF SIZE
JSR PC,GETCNK ;GET A CHUNK TO PUT DATA INTO
BEQ 30$ ;IF NO CORE CAN'T HANDLE MESSAGE
MOV LB.IPT(J),R1 ;GET REL HEADER ADR
ADD J,R1 ;MAKE ABSOLUTE
ASSERT EQ 10(R1)
MOV R0,10(R1) ;SAVE LINK TO FIRST CHUNK
MOV R0,LB.CIB(J) ;ALSO SAVE CURRENT CHUNK ADR
CLR CN.MLK(R0) ;CLEAR LINK TO NEXT MSG
MOV (P)+,R1 ;GET SIZE BACK
BIC #<SELBIT!QSYNC>*400,R1 ;STRIP EXTRA BITS
MOV R1,CN.LEN(R0) ;PUT SIZE INTO THE CHUNK
ADD #2,R1 ;ADD 2 FOR BCC
MOV R1,LB.CIB+2(J) ;SAVE PARTIAL COUNT
ADD #CN.NCT,R0 ;ADR TO BEGIN PUTTING DATA
MOV #DRJ.39,LB.RDN(J) ;WHERE TO GO WHEN FINISH GETTING HDR
CMP R1,#CNKSIZ-CN.NCT ;WILL MESSAGE FIT IN A CHUNK ?
BLE DRJ.45
MOV #CN.NCT-CNKSIZ,R1 ;CHARS TO READ INTO 1ST CHUNK
ADD R1,LB.CIB+2(J) ;ADJUST CHARS LEFT
RTS PC
;HERE BECAUSE NO CHUNKS FOR MESSAGE
30$: MOV (P)+,R0 ;POP COUNT OFF STACK
;HERE WHEN RECEIVING A DATA MESSAGE AND RUN OUT OF CORE
DRJ.35: TWIDDLE
MOV LB.IPT(J),R0 ;GET INPUT PUTER
ADD #12,R0 ;ADVANCE IT
CMP R0,#LB.IBF+<12*NINBUF> ;HIT END ?
BNE 10$
MOV #LB.IBF,R0 ;YES SO POINT TO BEGINING
10$: CMP R0,LB.ITK(J) ;DID PUTER HIT TAKER ?
BEQ DRJ.27 ;IF SO CAN'T HELP HIM
MOV R0,LB.IPT(J) ;SO LOW LEVEL WILL NAK MESSAGE
BR DRJ.27
;HERE TO CHECK HEADER BCC FOR DATA
DRJ.39: JSR PC,DRJ.90 ;CHECK THE HEADER
MOV #DRJ.40,LB.RDN(J) ;CONTINUE READING DATA IF OK
;
;HERE TO READ ANOTHER BLOCK OF DATA
DRJ.40: JSR PC,GETCNK ;GET A CHUNK TO PUT STUFF IN
BEQ DRJ.35 ;IF NO CORE CAN'T HANDLE MESSAGE
MOV R0,@LB.CIB(J) ;SET LINK IN CURRENT CHUNK
MOV R0,LB.CIB(J) ;AND THIS BECOMES CURRENT CHUNK
TST (R0)+ ;SKIP LINK WORD
MOV LB.CIB+2(J),R1 ;LETS TRY TO READ EVERYTHING
CMP R1,#CNKSIZ-2 ;CHECK FOR TOO LARGE
BLE DRJ.46 ;BRANCH IF THAT FITS
MOV #2-CNKSIZ,R1 ;READ ONE CHUNK INSTEAD
ADD R1,LB.CIB+2(J) ;UPDATE COUNT LEFT TO GO
RTS PC ;AND RETURN TO SYNCHRONOUS LINE HANDLER
;HERE WHEN THIS CHUNK WILL SWALLOW REST OF MESSAGE
DRJ.45: MOV #DRJ.09,LB.RDN(J) ;GO HERE WHEN DONE WITH THIS
DRJ.50: CLR LB.CIB+2(J) ;SET NO MSG INCREMENT LEFT
NEG R1 ;COUNT IS JUST WHAT WE NEED
RTS PC
DRJ.46: MOV #DRJ.08,LB.RDN(J) ;WHERE TO GO WHEN FINISHED
BR DRJ.50
;
;HERE TO CHECK HEADER BCC
DRJ.90:
MOV LB.IPT(J),R0 ;GET THE BUFFER
ADD J,R0
.IF NE FTDUP11
CMPB #LS..UP,LB.DVS(J) ;IS THIS IS DUP-11. IF SO SKIP
BNE 5$ ; IF NOT, GO DO NORMAL BCC.
BIT #UP$RCC,LB.STY(J) ;IF IT IS A DUP. 'UP$BCC' => GOOD BCC
BEQ DRJ.94 ; IF IT ISN'T SET, WE HAVE BCC ERROR
RTS PC ;IF IT IS SET, GIVE GOOD RETURN
5$:
.ENDC ;IF NE FTDUP11
MOV #KG.STS,R1 ;SAVE KG11 STATE SINCE ALSO USED AT LOW LEVEL
MOV (R1)+,-(SP) ;KG.STS: SAVE OLD MODE
MOV @R1,-(SP) ;KGBCC: SAVE PARTIAL BCC
MOV #KG.INI!KG.DDB,-(R1) ;KG.STS: REINIT FOR CRC-16
MOV #KGDATA,R1 ;FASTER THAN CMP (R1)+,(R1)+
MOV (R0)+,@R1 ;KGDATA: CALCULATE HEADER BCC
MOV (R0)+,@R1
MOV (R0)+,@R1
MOV -(R1),R2 ;KGBCC: SAVE FOR COMPARE AFTER RESTORING STATE
MOV #KG.SEN!KG.CLR!KG.DDB!KG.LRC,-(R1);KG.STS: PREPARE TO RELOAD KGBCC
MOV (SP)+,KGDATA ;THIS RELOADS SAVED PARTIAL BCC
MOV (SP)+,@R1 ;KG.STS THIS RESTORES THE MODE
CMP R2,(R0)+ ;FINALLY - DO THE BCC'S MATCH?
BNE DRJ.91
RTS PC ;RETURN EVERY THING IS AOK
DRJ.94: ADD #10,R0 ;BUMP POINTER TO CHUNK LINK
DRJ.91: MOVB #NCDBCC,LB.NCD(J) ;HEADER ERROR
TWIDDLE
MOV #DRJ.27,(P) ;WHERE TO RETURN BECAUSE BCC IS SICK
MOV R0,R1
MOV (R0),R0 ;IF NON ZERO THERE IS A BUFFER TO DEAL WITH
BEQ 11$
CLR (R1)
JSR PC,FRECKS ;FREE THE BUFFER
CLR R0
11$: JMP DRNAK1 ;BE SURE TO NAK THE ERROR
;HERE TO CHECK BCC ON HEADER ON SHORT MSGS
DRJ.09: JSR PC,DRJ.90 ;CHECK THE BCC
DRJ.08: MOV #DRJ.21,LB.RDN(J) ;WHERE TO GO WHEN MESSAGE IS FINISHED
.IF NE FTDUP11 ;GROSS HACK FOR DUP-11 BCC
CMPB #LS..UP,LB.DVS(J) ;IS THIS A DUP-11?
BNE 10$ ; NO.
MOV #DRJ.07,LB.RDN(J) ;SPECIAL CODE TO CHECK BCC ON THE DUP
10$:
.ENDC ;END OF FTDUP11
JMP DRJ.10 ;NOW GO GIVE THE RECIEVER A SECOND 4 BYTE BUFFER
.IF NE FTDUP1 ;HACK FOR BCC
;SPECIAL HACK FOR THE DUP-11. SNICE THE BCC FOR DUP-11 DATA CAN (AND MUST)
; BE CHECKED AT INTERRUPT LEVEL, THIS CODE CHECKS THE BCC, AND IF IT IS
; VALID, JUST PASSES THE MESSAGE TO LOOP LEVEL. IF IT IS INVALID, THE
; HEADER CHAR IS SET TO #252 (CROCK) AND LOW-LEVEL NOTICES AND DISCARDS
; THE MESSAGE.
DRJ.07: ;HERE TO CHECK THE BCC ON A DUP-11 DATA MESSAGE
BIT #UP$RCC,LB.STY(J) ;IS THE CHECK SUM GOOD?
BNE 10$ ;IF GOOD BCC SKIP SENDING NAK
TWIDDLE ;COUNT THE NUMBER OF ERRORS
MOVB #NCDDBC,LB.NCD(J) ;SIGNAL A DATA BCC ERROR
JSR PC,DRNAK1 ;QUEUE THE XMITTER TO SEND THE NAK
MOV LB.IPT(J),R0 ;NOW GET THE ADDRESS OF THE
ADD J,R0 ; HEADER CHAR FOR THE MESSAGE, AND
MOVB #252,(R0) ; SMASH IT TO TELL LOW-LEVEL THAT MSG IS BAD
10$: JMP DRJ.21 ;GO TO COMMON END-OF-MESSAGE CODE
.ENDC ; .IF NE FTDUP11
.ENDC;.IF NE,<NTLINE-DMCN>
.ENDC ; .IF NE NTLINE
.SBTTL DEQUEUE ACKED DATA
.IF NE NTLINE
.IF NE,<NTLINE-DMCN>
;HERE WHEN SOME MSGS HAVE BEEN ACKED
DDXMTD:
SAVE <R3> ;MUST PRESERVE R3 FOR DDCIN0...
MOV R0,-(P) ;DISCARD ACKED MESSAGES
10$: MOV LB.OBF(J),R0 ;LOCATE THE FIRST MSG IN THE QUEUE
.IF EQ DGUTS
ASSERT NE
.IFF
BEQ 70$
.ENDC ; .IF EQ DGUTS
CMP R0,LB.COB(J) ;IS IT THE LAST DATA TRANSMISSION
BNE 20$
TST LB.COB+4(J) ;IF SO, IS IT STILL BEING TRANSMITTED
BGT 70$ ;IF SO, STOP DEQUEUING THE MSGS
CLR LB.COB(J) ;ELSE CLEAR THE LAST TRANSMISSION POINTER
20$: DEC LB.OBF+4(J) ;AND REMOVE THE MSG FROM THE QUEUE
MOV CN.MLK(R0),LB.OBF(J) ;IF THE QUEUE IS EMPTY
BNE 30$ ;STILL SOMETHING IN THE QUEUE
CLR LB.OBF+2(J) ;RESET THE QUEUE END POINTER
30$: JSR PC,COMODN
INCB LB.LAP(J) ;ADVANCE ONE MESSAGE
INC LB.OCN(J) ;COUNT MESSAGES ACKED
DEC (P)
BNE 10$
70$: TST (P)+ ;POP EXHAUSTED COUNT FROM STACK
RESTORE <R3>
RTS PC
.ENDC;.IF NE,<NTLINE-DMCN>
.ENDC ; .IF NE NTLINE
.SBTTL XMITTER SERVICE
.IF NE NTLINE
;HERE WHEN HAVE FINISHED TRANSMITTING A DDCMP MESSAGE
DDCXMT:
.IF NE,DMCN
.IF NE,<NTLINE-DMCN>
CMPB #LS..DM,LB.DVS(J) ;IS IT DMC11?
BNE 3$ ;NO, CONTINUE
.ENDC;.IF NE,<NTLINE-DMCN>
JMP DMCXMT ;GO HANDLE DMC11
3$:
.ENDC;.IF NE,DMCN
.IF NE,<NTLINE-DMCN>
.IF NE FT.MPT
BIT #LS.MPT,(J) ;IF MULTIPOINT LINE
BEQ DDCX10
BITB #MP.OFF!MP.SOL,LB.MPS(J) ;AND IF OFFLINE
BNE DDCX49 ;DO NOTHING AT ALL
BITB #MP.SEL,LB.MPS(J) ;IF NOT SELECTED
BEQ DDCX49 ;DO NOTHING AT ALL
.ENDC
DDCX10: BIT #LS.XCT!LS.XDT,@J ;ALREADY TRANSMITTING ?
BNE DDCX49 ;YES, NOTHING FURTHER WE CAN DO HERE
BIT #LS..RN,@J ;WAS LAST ACK A NAK ?
BEQ 12$
BIC #LS..RN,@J ;FORGET FLAG
CLR LB.COB(J) ;SO WE RETRANSMIT MESSAGE
CLR LB.COB+2(J)
12$:
.IF NE FT.MPT
MOVB LB.MPA(J),LB.CTL+5(J) ;SET DESTINATION ADDRESS
.IFF
MOVB #A0,LB.CTL+5(J) ;SET DEFAULT DESTINATION ADDRESS
.ENDC ;.IF NE FT.MPT
BIT #LS..ST!LS.STK!LS.XNK,@J ;BRANCH IF WE NEED
BNE DDCX15 ; A HIGH PRIORITY CNTL MSG
BIT #LS.XRP,(J) ; If REP not queued, check for data or ACK.
BEQ DDCX50
CMPB LB.LAP(J),LB.HSN(J) ; If IDLE REP, send with low priority.
BEQ DDCX50
DDCX15: BIT #LS.XCT,@J ;SENDING CONTROL MESSAGE ALREADY ?
BNE DDCX50 ;DON'T WRITE OVER THE LAST
MOV #ENQ,LB.CTL(J) ;PUT ENQ AT HEAD
CLR LB.CTL+2(J) ;PUT FILLS IN PROTOTYPE CONTROL MESSAGE
CLRB LB.CTL+4(J) ;PUT FILL IN PROTOTYPE CONTROL MESSAGE
BIT #LS..ST!LS.STK,@J ;BRANCH IF DON'T NEED
BEQ 40$ ; START OR STACK
BIT #LS.XRP,@J ;USE THIS SO DON'T SEND TOO MANY
BEQ DDCX50 ;IF DON'T NEED START SEND BOOT MSG'S
BIC #LS.XRP,@J ;SO WE DON'T SEND ANOTHER FOR A WHILE
.IF EQ FT3.02
.IF NE FT.MPT
TST #LS.MPT,(J) ;IF MULTIPOINT, ACT AS THOUGH DDCMP
;3.02 WAS IMPLEMENTED
BEQ 100$
.ENDC ;.IF NE FT.MPT
MOVB LB.LAP(J),LB.CTL+4(J) ;LAST MESSAGE NUMBER SENT
INCB LB.CTL+4(J) ;START & STACK ARE +1
BR 101$
100$: BISB #SELBIT,LB.CTL+2(J) ;MUST SET SELECT BIT IN START AND STACK
;FOR DDCMP 3.02 COMPATIBILITY
101$:
.IFF
BISB #SELBIT,LB.CTL+2(J) ;MUST SET SELECT BIT IN START AND STACK
;FOR DDCMP 3.02 COMPATIBILITY
.ENDC ;.IF EQ FT3.02
MOVB #STRT,R0
BIT #LS..ST,@J ;ARE WE GOING TO SEND A START ?
BEQ 39$ ;IF SO -
.IF NE FT.RDM!FT.RDP
JSR R0,RDESST ;IF A RDE DEV, REPORT THE STATE
.BYTE 0,210
.ENDC ;.IF NE FT.RDM!FT.RDP
.IF NE,FTDCP1
BIT #LS.NSP,@J ;IS IT AN NSP LINE?
BEQ 49$ ;NO, CONTINUE
INCB LB.CTL+4(J) ;MESSAGE TO SEND
.ENDC
BR 49$
39$: BIC #LS.STK,@J ;HERE TO SEND STACK
INC R0 ;MAKE START CODE INTO STACK
.IF EQ FT3.02
.IF NE FT.MPT
TST #LS.MPT,(J) ;IF MULTIPOINT, ACT AS THOUGH DDCMP
;3.02 WAS IMPLEMENTED
BEQ 102$
.ENDC ;.IF NE FT.MPT
MOVB LB.ROK(J),LB.CTL+3(J) ;PUT LAST MSG # RECEIVED OK IN MSG
INCB LB.CTL+3(J) ;START & STACK ARE +1
102$:
.ENDC ;.IF EQ FT3.02
.IF NE FT.RDM!FT.RDP
JSR R0,RDESST ;IF A RDE DEV, REPORT THE STATE
.BYTE 0,220
.ENDC ;.IF NE FT.RDM!FT.RDP
.IF NE,FTDCP1
BIT #LS.NSP,@J ;IS IT NSP LINE?
BEQ 49$ ;NO, CONTINUE
INCB LB.CTL+3(J) ;MESSAGE TO TO SEND
INCB LB.CTL+4(J) ;MESSAGE TO RECEIVE
.ENDC
BR 49$
;HERE TO SEND ACK, NAK, OR REP
40$: MOVB LB.ROK(J),LB.CTL+3(J) ;PUT LAST MSG # RECEIVED OK IN MSG
BIT #LS.XNK!LS.XAK,@J ;DO WE NEED TO SEND ACK OR NAK ?
BEQ 45$ ;IF NOT NEEDED TO SEND A REP
CLRB LB.CTL+4(J) ;DDCMP REQUIRES ZERO FILL FOR ACK/NAK
BIT #LS.XNK,@J ;WAS THAT ACK OR NAK ?
BNE 42$
BIC #LS.XAK!LS.NRP,@J ;CLEAR ACK FLAG
MOV #ACK,R0
BR 49$
42$: BIC #LS.XNK!LS.NRP,@J ;HERE TO SEND NAK
MOVB #NAK,R0
MOVB LB.NCD(J),LB.CTL+2(J) ;PUT REASON FOR NAKING IN MSG
BR 49$
45$: MOVB #REP,R0 ;HERE TO SEND REP
CLRB LB.CTL+3(J) ;THIS IS A FILL BYTE AND MUST BE 0
MOVB LB.HSN(J),LB.CTL+4(J) ;HIGHEST MSG # SENT
BIC #LS.XRP!LS.NRP,@J ;CLEAR REP FLAG
49$: MOV LB.CTL+2(J),R1
TRACE DD ;PUT MESSAGE TYPE IN TRACE
MOVB R0,LB.CTL+1(J) ;PUT MESSAGE TYPE IN MESSAGE
.IF NE FT.MPT
BIT #LS.MPT,(J) ;IF MULTIPOINT, CAN'T HAVE BOOT MODE
BNE 98$
.ENDC ; .IF NE FT.MPT
TSTB LB.BNN+1(J) ;FOR BOOT MODE,
;SEND MAINTAINANCE MODE MSGS ONLY
BEQ 98$
BIT #LS..ST,(J) ;IF IN BOOT MODE, LINE BETTER BE DOWN
BNE DDCX50
JSR PC,L.DOWN ;IF IT ISN'T, IT WILL BE NOW
BR DDCX50
98$: MOV #LB.CTL,R0 ;RELATIVE ADDRESS OF CONTROL BUFFER
ADD J,R0 ;MAKE ABSOLUTE
JSR PC,DDCBCC ;PUT BCC ON MSG
JSR PC,DDXCTL ;GO TRANSMIT CONTROL MESSAGE
DDCX49: JMP LOOP ;RETURN TO LOOP LEVEL
DDCX50: MOV LB.BOO(J),R0 ;GET ADR OF BOOTSTRAP MSG IF ANY
BEQ 10$
CMP R0,LB.COB(J) ;ALREADY SENT MSG ?
BNE 52$ ;IF NOT SEND IT NOW
JSR PC,FRECKS ;RELEASE MSG CHUNKS
CLR LB.BOO(J) ;MSG HAS BEEN SENT
MOV LB.OBF+2(J),LB.COB(J) ;DON'T RETRANSMIT MSGS
10$: BIT #LS..ST!LS.STK,@J ;IS DDCMP STARTED ?
BNE DDCX49 ;IF NOT DONE
MOV LB.OBF+2(J),R0 ;CHECK FOR ANY MESSAGES IN QUEUE
BEQ 60$
CMP R0,LB.COB(J) ;WAS LAST MESSAGE SENT LAST IN QUEUE ?
BEQ 60$ ;IF SO DONE
MOV LB.COB(J),R0 ;GET ADR OF LAST MSG SENT
BNE 50$
MOV LB.OBF(J),R0 ;SEND FIRST MSG IN QUEUE
BR 52$
50$: MOV CN.MLK(R0),R0 ;GET ADR OF NEXT MSG
52$: ASSERT CHUNK R0 ;BE SURE MSG ADR IS LEGAL
MOV R0,LB.COB(J) ;SAVE ADR OF CURRENT MSG
ADD #CN.DDC,R0 ;POINT TO SOH
CMPB #SOH,(R0) ;IF NUMBERED MSG, UNQUEUE WAITING ACK
BNE .+6
BIC #LS.XAK!LS.NRP,(J)
MOVB LB.ROK(J),3(R0) ;PUT RESPONSE INTO MESSAGE
TRACE DD
JSR PC,DDXBCC ;PUT CRC ON HEADER
JSR PC,DDXDAT ;TRANSMIT DATA
BR DDCX49
60$: BIT #LS.XAK!LS.XRP,@J ;DO WE NEED TO XMT AN ACK/REP ?
BEQ DDCX49 ;NO, RETURN TO LOOP LEVEL
JMP DDCX15
DDXBCC: BICB #SELBIT!QSYNC,2(R0) ;LETS NOT BE STUCK WITH A LEFTOVER FLAG
DDCBCC:
.IIF NE FT.QSB, BISB #QSYNC,2(R0) ;BETTER LET HIM EXPECT SYNCHS
.IF NE FT.MPT
BIT #LS.MPT,(J) ;IF A MULTIPOINT LINE
BEQ 11$
CMP (R0),#STRT*400+ENQ
BEQ 14$
CMP (R0),#STACK*400+ENQ
BEQ 14$ ;MUST ALWAYS SEND SELECT WITH START AND STACK
.IF NE FTTRIB
TST LB.MPL(J) ;IF TRIBUTARY
BNE 13$
CMPB LB.LAR(J),LB.HSN(J) ;AND IF DATA TO SEND,WE'RE OK
BNE 13$
BIT #LS.XNK!LS.XRP,(J) ;OR IF MORE CONTROL TO SEND
;WE'RE OK
BEQ 14$ ;ELSE SEND THE SELECT NOW
; ;NOTE ACKS DON'T COUNT
13$:
.ENDC
BITB #MP.SNM,LB.MPS(J) ;AND IF THE NEXT MSG REQUIRES A SELECT
BEQ 11$
14$: BISB #SELBIT,2(R0) ; SET THE SELECT BIT IN THE MSG
BICB #MP.SNM,LB.MPS(J) ;AND CLEAR THE NEXT SELECT FLAG
.IF NE FTTRIB
TST LB.MPL(J)
BNE 12$
BICB #MP.SEL,LB.MPS(J) ;IF TRIBUTARY,MUST NOT STAY SELECTED
12$:
.ENDC
.ENDC
11$:
.IF NE FT873 ;IF BM873 SUPPORT MOD REQUIRED
CMPB (R0),#DLE ;IF BOOTSTRAP MESSAGE
BNE 20$
CMPB LB.DVS(J),#LS..AL ;AND IF THIS IS FOR A SYNC LINE
BHIS 20$
BICB #SELBIT!QSYNC,2(R0) ;BM873 REQUIRES THESE BITS CLEARED
20$:
.ENDC ;.IF NE FT873
JSR PC,DDBBCC ;CALCULATE THE FOR THE HEADER
MOV (P)+,(R0)+
HDRDMP O,DMPHLN,DMPHOU
RTS PC
;
;
DDBBCC:
MOV (P),-(P) ;MAKE ROOM ON STACK FOR BCC
.IF NE FTDUP11
CMPB #LS..UP,LB.DVS(J) ;IF THIS IS NOT A DUP-11 LINE
BNE 5$ ; THEN DO NORMAL CHECK-SUM
CLR 2(P) ;OTHERWISE DUMMY CRC TO 0
ADD #6,R0 ;BUMP PTR TO CRC LOC IN MESSAGE
RTS PC ;AND LET THE DUP-11 DO THE REST
5$:
.ENDC ;IF NE FTDUP11
SAVE <R1>
PIOFF
KGLOAD #0,WORD ;INITIALIZE THE KG11
; KG IS NOT REENTRANT
MOV #KGDATA,R1 ;POINTER TO KG11 REGISTER
MOV (R0)+,@R1 ;CALCULATE THE BCC
MOV (R0)+,@R1
MOV (R0)+,@R1
MOV -(R1),6(P) ;SAVE THE BCC
PION
RESTORE <R1>
RTS PC
.ENDC;.IF NE,<NTLINE-DMCN>
.ENDC ; .IF NE NTLINE
.SBTTL XMITTER INTERRUPT
.IF NE NTLINE
.IF NE,<NTLINE-DMCN>
;HERE TO SEND A CONTROL MESSAGE
; CALL <PUT 8 CHAR CONTROL MESSAGE IN LB.CTL>
; JSR PC,DDXCTL
DDXCTL: PIOFF ;DISABLE INTERRUPTS FOR A WHILE
MOV #10$,LB.XDN(J) ;PLAN TO SEND SOME SYNCHS
BIS #LS.XCT,@J ;SENDING CONTROL MESSAGE
BIT #LS..XG,@J ;IS SYNCHRONOUS LINE RUNNING ?
BNE 7$ ;BRANCH IF ALREADY TRANSMITTING
MOV #20$,LB.XDN(J) ;SETUP CUZ SLXBEG WILL CALL RITE AWAY
JSR PC,SLXBEG ;POKE TRANSMITTER
7$: PION ;REENABLE INTERRUPTS
RTS PC ;COME BACK LATER
;HERE VIA LB.XDN WHEN READY TO SEND SOME SYNCHS AHEAD OF CONTROL MESSAGE
10$:
.IF NE NALINE!NMPTL!NTRIB
CMPB #LS..AL,LB.DVS(J) ;IF THE DEVICE IS AN ASYNC LINE
BLOS 20$ ;DON'T SEND SYNCS
.ENDC
MOV #20$,LB.XDN(J) ;GO HERE WHEN SYNCS HAVE BEEN SENT
.IF NE FTDUP11 ;HANDLE DUP SPECIAL TO DISABLE CRC
CMPB #LS..UP,LB.DVS(J) ;FIRST MAKE SURE THAT THIS IS A DUP-11
BNE 15$ ; IF IT ISN'T, THEN DO THE USUAL
MOV SYNCHS,R0 ;OTHERWISE GIVE THE DUP THE SYNC CHAR
; AS IMMEDIATE DATA
MOV #<37777&<-FTNSYN>>,R1 ;AND FLAG THE DATA AS 'SYNC' (WITH OUT
; BCC PROCESSING!)
RTS PC ;GIVE THIS BACK TO INTERRUPT LEVEL
15$: ;HERE IF NOT A DUP11
.ENDC; NE DUP11
MOV #SYNCHS,R0 ;ADDRESS OF SYNCH BUFFER
MOV #-FTNSYN,R1 ;SEND SEVERAL SYNCHS BEFORE CONTROL
;MSGS TO BE SURE THEY DON'T GET LOST
RTS PC
;HERE VIA LB.XDN WHEN READY TO TAKE CONTROL MESSAGE ADR
20$: QUEPUT QO 25$ ;SO WE SEND SOMETHING ELSE
MOV #30$,LB.XDN(J) ;WHERE TO GO WHEN CONTROL MSG IS STARTED
MOV #LB.CTL,R0 ;RELATIVE ADR OF MESSAGE
ADD J,R0 ;MAKE ADR ABSOLUTE
.IF NE FTDUP11
CMPB #LS..UP,LB.DVS(J) ;IF THIS ISN'T A DUP, THEN
BNE 22$ ;SHIP INTERRUPT LEVEL A NORMAL MSG
MOV #<-6&77777>,R1 ;IF IT IS A DUP, THEN ONLY SEND 6
; CHARS (IT PROVIDES THE BCC) AND
; SET THE FLAG THAT SAYS SEND BCC
RTS PC ;GIVE IT BACK TO INTERRUPT LEVEL
22$: ;HERE IF WE HAVE CALCULATED THE BCC
.ENDC ;.IF NE FTDUP11
MOV #-10,R1 ;COUNT FOR MESSAGE
RTS PC ;BACK TO SYNCHRONOUS LINE
;HERE WHEN SL IS ACTUALLY SENDING CONTROL MESSAGE
30$:
; ;FOR AN ASYNC LINE THIS SUPPLIES THE FIRST NULL BUFFER
; ;FOR SHUTTING THE XMITTER OFF - IT IS REQUIRED TO
; ;PREVENT CLEARING LS.XCT TOO SOON.
;
; ;FOR A SYNCHRONOUS LINE IT SENDS SOME SYNC CHARS
DDCIDL: MOV #40$,LB.XDN(J) ;WHERE TO GO WHEN DONE
BR DDCI19 ;SEND SYNCHS NEXT
;HERE WHEN HAVE FINISHED SENDING CONTROL MESSAGE
40$: ;NO LONGER SENDING CONTROL
;HERE VIA LB.XDN AT INTERRUPT LEVEL WHEN THERE IS NOTHING LEFT TO DO
DDCI18: MOV #DDCI20,LB.XDN(J)
BIC #LS.XDT!LS.XCT,@J
QUEPUT QO 19$
DDCI19: MOV #-FTQSYN,R1 ;MAKE THAT A SHORT SYNC SEQUENCE
BR DDCI21
DDCI20: MOV #-FTNSYN,R1 ;MAKE THAT AN ORDINARY SYNC SEQUENCE
DDCI21: MOV #SYNCHS,R0
.IF NE NALINE!NMPTL!NTRIB
CMPB #LS..AL,LB.DVS(J) ;IF THE DEVICE IS AN ASYNC
BHI 100$
CLR R0 ; NO SYNCS ARE REQUIRED
CLR R1
100$: ;IF NOT ASYNC, JOIN CODE HERE
.ENDC
.IF NE FTDUP11 ;DON'T SEND SYNCH'S FOR A DUP
CMPB #LS..UP,LB.DVS(J) ;IS THIS A DUP?
BNE 10$ ;IF NOT, DON'T DO IT SPECIAL
MOV #DDCI22,LB.XDN(J) ;ONLY SEND 1 SYNCH SEQUENCE IF IT'S
; A DUP. THIS IS BECAUSE OF A BUG
; IN THE DUP DRIVER WHERE IT CLOBBERS
; THE CHECKSUM OF THE LAST MESSAGE
; THE PROBLEM SHOULD BE FIXED THERE,
; BUT THIS IS EASIER
10$:
.ENDC
RTS PC
.IF NE FTDUP11
;HERE TO SHUT DOWN A DUP-11 AFTER IT HAS SENT A CLOSING SYNCH SEQUENCE
; (WHICH GIVES IT TIME TO GET THE CHECKSUM OF THE LAST MESSAGE OUT
DDCI22: CLR R0 ;IF IT'S A DUP, THEN
CLR R1 ; DON'T IDLE (INTS TAKE TIME)
RTS PC ;SHUT HIM DOWN
.ENDC
;HERE TO SEND A DATA MESSAGE
; CALL <PUT ADR OF 1ST CHUNK IN LB.COB(J)
; JSR PC,DDXDAT
DDXDAT: BIS #LS.XDT,@J ;WE ARE SENDING DATA !
PIOFF
BIC #LS.XCT,@J ;WHEN THIS IS DONE CAN SEND CONTROL
MOV #20$,LB.XDN(J) ;WHERE TO GO ON NEXT XMT INT
BIT #LS..XG,@J ;IS TRANSMITTER STILL RUNNING
BNE 10$ ;IF SO DON'T NEED TO SYNCH FIRST
JSR PC,SLXBEG ;START TRANSMITTER
10$: PION
RTS PC
;HERE AT INTERRUPT LEVEL TO GET ADR & COUNT FOR 1ST PART OF A MESSAGE
20$: MOV #30$,LB.XDN(J) ;WHERE TO GO ON NEXT INTERRUPT
MOV LB.COB(J),R0 ;GET ADDRESS OF 1ST CHUNK
BEQ DDCI18 ;CAN HAPPEN IF LINE RESET
ASSERT CHUNK R0 ;BE SURE CHUNK ADR IS KOSHER
MOV R0,LB.COB+2(J) ;WHICH IS ALSO CURRENT CHUNK
24$: MOV CN.LEN(R0),R1 ;GET SIZE OF MESSAGE SANS HEADER
.IF EQ DGUTS
ASSERT NE
.IFF
BNE 25$
INC CN.LEN(R0) ;TURN ZERO LENTGH MSG TO SINGLE NUL
CLR CN.NCT(R0)
MOV #SYN*400,CN.NCT+2(R0)
BR 24$
25$:
.ENDC ; .IF EQ DGUTS
ADD #CN.DDC,R0 ;POINT TO DDCMP HEADER
;DATA MESSAGES FOR THE DUP-11 MUST BE HANDLED IN AT LEAST TWO SECTIONS.
; THIS IS NECESSARY TO GIVE THE DUP A CHANCE TO PUT THE BCC ON THE
; HEADER SECTION OF THE MESSAGE.
.IF NE FTDUP11 ;TELL DUP TO PUT BCC ON MSG
CMPB #LS..UP,LB.DVS(J) ;IS THIS A DUP-11
BNE 3$ ;IF NOT, SEND NORMAL HEADER
MOV #23$,LB.XDN(J) ;RETURN HERE AFTER HEADER SENT
MOV #<-6&77777>,R1 ;HEADER (LESS BCC) WITH BCC
RTS PC ;SEND THE HEADER PORTION FIRST.
3$:
.ENDC ;IF NE FTDUP11
ADD #12,R1 ;ADD SIZE OF HEADER + BCC
MOV R1,LB.COB+4(J) ;REMEMBER SIZE OF MESSAGE
MOV #CN.DDC-CNKSIZ,R1 ;SIZE OF 1ST CHUNK
BR 35$
;
.IF NE FTDUP11 ;HERE AFTER DUP11 SENT HEADER PART OF MESSAGE
;
23$: MOV #30$,LB.XDN(J) ;RETURN HERE FOR NEXT MESSAGE
MOV LB.COB(J),R0 ;GET CURRENT CHUNK
BNE 21$ ;??? I DON'T KNOW HOW, BUT ???
JMP DDCI18 ;??? COB SOMETIMES GETS ZAPPED ???
21$: MOV CN.LEN(R0),LB.COB+4(J) ;REMEMBER SIZE OF DATA MESSAGE
ADD #10+CN.DDC,R0 ;POINT TO DATA MESSAGE
MOV #CN.DDC+10-CNKSIZ,R1 ;COUNT OF DATA LEFT IN THIS CHUNK
ADD R1,LB.COB+4(J) ;ADJUST REMAINING COUNT
BLE 26$ ;SKIP IF ONLY 1 CHUNK IN MSG
RTS PC ;IF LONG MSG, SEND THIS PART NOW.
26$: SUB LB.COB+4(J),R1 ;IF SHORT MSG, GET BACK LENGTH
BIC #100000,R1 ;TELL THE DUP TO SEND THE BCC
BR 36$ ;RE-QUEUE THE LINE AND RETURN
.ENDC ;IF NE FTDUP11
;HERE AT INTERRUPT LEVEL TO GET ADDITIONAL CHUNKS OF A MESSAGE
30$: MOV @LB.COB+2(J),R0 ;GET ADDRESS OF NEW CHUNK
ASSERT NE ;BE SURE WE HAVE A NEXT CHUNK
ASSERT CHUNK R0 ;BE SURE KOSHER ADR
MOV R0,LB.COB+2(J) ;SAVE NEW CURRENT CHUNK
TST (R0)+ ;ADVANCE TO DATA ADR
MOV #2-CNKSIZ,R1 ;NUMBER OF BYTES TO TRANSMIT
35$: ADD R1,LB.COB+4(J) ;ADJUST COUNT LEFT
BGT 99$ ;IF ANOTHER CHUNK DONE
SUB LB.COB+4(J),R1 ;ADJUST COUNT
.IF NE FTDUP11
CMPB #LS..UP,LB.DVS(J) ;IS THIS A DUP.
BNE 36$ ;IF NOT, HANDLE NORMALLY.
BIC #100000,R1 ;OTHERWISE TELL THE DUP TO SEND THE BCC
36$:
.ENDC ;IF NE FTDUP11
MOV #DDCIDL,LB.XDN(J) ;WHERE TO GO WHEN DONE WITH THIS
QUEPUT QO 98$
99$: RTS PC
.ENDC;.IF NE,<NTLINE-DMCN>
.ENDC ; .IF NE NTLINE
.SBTTL MULTIPOINT SELECTION
.IF NE NTLINE
.IF NE,<NTLINE-DMCN>
.IF NE FT.MPT
DESLCT: ;DESELECT THIS STATION AND SELECT NEXT ONE
SAVE <R0>
BR DSLCT1
SELNXT: ;SELECT THE NEXT STATION IF POSSIBLE
.IF NE FTTRIB
TST LB.MPL(J) ;IF TRIBUTARY
BNE SLCT.3
BITB #MP.OFF,LB.MPS(J) ;IF ONLINE
BEQ SLCT.4 ;FORCE A SELECT
RTS PC ;ELSE DO NOTHING
SLCT.3:
.ENDC
SAVE <R0>
BITB #MP.SEL,LB.MPS(J) ;IF NOT SELECTED DO NOTHING
BEQ SLCT.X
MOV LB.LCB(J),R0 ;GET LINE CONTROL BLOCK
CLR LC.INS(R0) ;AND INHIBIT FURTHER INPUT
BICB #MP.SEL,LB.MPS(J) ;STATION IS NO LONGER IT
BIT #LS..XG,(J) ;IF XMITTER IS RUNNING,WAIT FOR IT TO STOP
BNE SLCT.X
DSLCT1: ;DESELECT THIS STATION AND SELECT NEXT ONE
BIC #LS..XG,(J) ;XMITTER IS STOPPED
BICB #MP.SEL,LB.MPS(J) ;STATION IS NO LONGER IT
CLRB LB.MPT(J) ;CLEAR THE SELECT TIMER
BITB #MP.SOL,LB.MPS(J) ;IF STATION IS TO BE SET OFF LINE
BEQ SLCT.2
BITB #MP.OFF,LB.MPS(J) ;AND IF STATION IS NOT YET OFF LINE
BNE SLCT.2
SAVE <R1,R2,R3,R4,J> ;SAVE REGISTERS TO BE SAFE
JSR PC,L.DOWN ;DECLARE IT DOWN
RESTORE <J,R4,R3,R2,R1> ;RESTORE REGISTERS
SLCT.2:
.IF NE FTTRIB
TST LB.MPL(J) ;IF NOT TRIBUTARY
BEQ SLCT.X
.ENDC
MOV LB.LCB(J),R0 ;GET THE LINE CONTROL BLOCK
CLR LC.BLK(R0) ;AND UNDEFINE THE SELECTED STATION
CLR LC.INS(R0)
CLR LC.OUS(R0)
MOV J,-(P) ;SAVE J
.IIF EQ FTSLCT-1, MOVB LB.MPN+1(J),LB.MPN(J) ;RESET THE SELECTION WEIGTH
.IIF EQ FTSLCT-2, JSR PC,SLCTDN ;ADJUST AND RESET THE SELECTION WEIGHT
JSR PC,SLCTIT ;DETERMINE THE NEXT STATION
TST J ;IF THERE IS ONE
BEQ SLCT.5
.IF NE NDHMPT!NDHTRB
.IF NE NDZMPT!NDZTRB
CMPB LS..AL,LB.DVS(J)
BLOS SLEC2H
.ENDC
.IFF
MOV #DDDZOU,LC.OUS(R0)
MOV #DDDZIN,LC.INS(R0)
.IFT
.IIF NE NDZMPT!NDZTRB, BR SLEC2Z
SLEC2H:
MOV #DDDHOU,LC.OUS(R0) ;RESTORE THE LINE CONTROL
MOV #DDDHIN,LC.INS(R0)
SLEC2Z:
.ENDC
MOV J,LC.BLK(R0)
JSR PC,SLCT.4 ;SELECT THE STATION
SLCT.5: MOV (P)+,J ;RESTORE J
SLCT.X: RESTORE <R0>
RTS PC
;
;
SLCT.4:
SAVE <R0>
BITB #MP.OFF,LB.MPS(J) ;IF STATION IS OFFLINE
BEQ .+6
BIS #LS..ST!LS.XRP,(J) ;WE MUST SEND START
BICB #^C<MP.SFF>,LB.MPS(J)
BISB #MP.SEL!MP.SNM,LB.MPS(J) ;FLAG IT NEWLY SELECTED
MOVB #MP.STV,LB.MPT(J) ;RESET SELECTION TIMER
.IF NE FTTRIB
TST LB.MPL(J) ;IF TRIBUTARY
BNE 10$
MOVB #MP.TTV,LB.MPT(J) ;USE CORRECT VALUE
BICB #MP.SNM,LB.MPS(J) ;RESET THE SELECT IN NEXT MSG FLAG
10$:
.ENDC
BIT #LS..ST!LS.STK!LS.XNK!LS.XAK,(J)
; ;IF NO MESSAGE QUEUED
BNE 20$
TST LB.MPL(J) ;IF MASTER DELAY,THEN SEND REP
BEQ 20$
MOVB #SDLAY,LB.REP(J) ;RESET REP TIMER TO DELAY SELECT
BNE 21$
20$: BIS #LS.XAK,(J) ;SEND ACK
QUEPUT QO 11$
21$: BIT #LS..RG,(J) ;IF THE RECEIVER IS STOPPED
BNE SLCT.X
.IF NE NDHMPT!NDHTRB
.IF NE NDZMPT!NDZTRB
CMPB LS..DH,LB.DVS(J)
BEQ 22$
.ENDC
.IFTF
.IF NE NDZMPT!NDZTRB
JSR PC,DZRBEG ;START IT
BR SLCT.X
.ENDC
.IFT
22$: JSR PC,DHRBEG ;START IT
BR SLCT.X ;RESTORE R0 AND EXIT
.ENDC
;
;
SLCT.1: ;SELECT THIS ONE AS THE FIRST IF ALL OTHERS ARE OFFLINE
SAVE <R0,J>
CLR R0 ;ASSUME THIS IS THE ONLY ACTIVE DROP
10$: MOV LB.MPL(J),J ;SEARCH RING
BEQ 15$
CMP J,(P) ;DONE IF BACK WHERE WE STARTED,
BEQ 15$
BITB #MP.OFF,LB.MPS(J) ;LOOP IF DROP IS OFFLINE
BNE 10$
MOV J,R0 ;NOTE THE ONLINE DROP
15$: MOV (P)+,J ;RESTORE J
MOVB #MP.SFC,LB.MPS(J) ;SET THE SELECT FAILURE COUNTER
CLRB LB.MPT(J)
BIS #LS..ST!LS.XRP,(J) ;BE SURE TO SEND START
TST R0 ;IF NO STATION ONLINE
BEQ SLCT.2 ;ACTIVATE THE STATION
;STATION WILL BE SELECTED IN COURSE
BR SLCT.X ;RESTORE R0, AND EXIT
;
;
;
;
;FTSLCT IS - ;SET TO ZERO FOR ROUND ROBIN SELECTION
;SET TO ONE FOR WEIGHTED ROUND ROBIN
;SET TO TWO FOR DYNAMIC WEIGHTED ROUND ROBIN
;SET TO THREE FOR POLLING TABLE SELECTION
;
;
SLCTIT: ;SELECT THE NEXT STATION
;THIS MUST PRESERVE R0
.IF EQ FTSLCT
; ;FOR TIME BEING SIMPLE ROUND ROBIN OF ON LINE ONES
MOV LB.MPL(J),J ;GET NEXT STATION
BITB #MP.OFF!MP.SOL,LB.MPS(J) ;IF OFF LINE
BEQ 30$
CMP 2(P),J ;CHECK IF ITS THE ONE WE STARTED WITH
BNE SLCTIT ;IF NOT TRY NEXT ONE
CLR J ;NONE ARE ON LINE
30$: RTS PC
;
.ENDC
;
;
.IF GT FTSLCT
.IF LE FTSLCT-2
; ;WEIGHTED ROUND ROBIN SELECTION
CLR -(P) ;SET FLAG CLEAR
32$: MOV LB.MPL(J),J ;GET NEXT STATION
BITB #MP.OFF!MP.SOL,LB.MPS(J) ;IF ONLINE
BNE 30$
INC (P) ;SET ONLINE STATION FLAG
TSTB LB.MPN(J) ;IF PASS NOT SET
BEQ 31$ ;THIS IS IT
DECB LB.MPN(J) ;ELSE SKIP IT
30$: CMP 4(P),J ;CHECK IF ITS THE ONE WE STARTED WITH
BNE 32$ ;IF NOT TRY NEXT ONE
TST (P)+ ;POP THE FLAG
BNE SLCTIT ;IF SOME ONLINE TRY NEXT ONE
CLR J ;NONE ARE ON LINE
RTS PC
31$: TST (P)+ ;POP THE FLAG
RTS PC
.ENDC
.ENDC
;
;
.IF NE FT.RDM
.IF EQ FTSLCT-3
BIT #LS.MPT,(J) ;IS THIS A MULTI-POINT LINE?
BEQ 36$ ;NO, NO "SELECTION" THEN
JSR PC,RDEGTB ;GET THE DDB FOR THE RDE DEV
BEQ 36$
SAVE <R0,R1> ;IF THERE IS ONE CONTINUE
MOV #POLLSZ,R1 ;SET THE SEARCH LIMIT
MOV J,-(P) ;SET UP THE LIST END ADR
ADD #DB.POL+POLLSZ,(P)
30$: MOVB @DB..PX(J),R0 ;GET THE NEXT STATION FROM THE LIST
INC DB..PX(J) ;MOVE TO THE NEXT LIST ENTRY
CMP (P),DB..PX(J) ;CHECK WRAP ARROUND
BLO 31$
SUB #POLLSZ,DB..PX(J)
31$: TST R0
BEQ 33$ ;BRANCH IF BAD ENTRY
MOV DB.HDW(J),J ;IF THERE IS ONE,LETS FIND IT
JSR PC,GETMPA
BEQ 32$
BITB #MP.OFF!MP.SOL,LB.MPS(J) ;ITS OFFLINE, WASTED EFFORT
BEQ 34$
32$: MOV (P),J ;RESTORE THE DDB ADR
SUB #DB.POL+POLLSZ,J
33$: SOB R1,30$ ;AND LOOP
CLR J ;COULDN'T FIND ONE
34$: TST (P)+ ;GOT THE RESULT SO EXIT
RESTORE <R1,R0>
36$: RTS PC
.ENDC ;.IF EQ FTSLCT-3
.ENDC ;.IF NE FT.RDM
;
;
;
.IF EQ FTSLCT-2
SLCTDN: ;ADJUST AND RESET THE WEIGHTING FOR SELECTION
SAVE <R0>
MOVB LB.MPN+1(J),R0 ;FETCH THE WEIGHT SELECTION STATE
BIT #^C17,R0
BEQ 45$ ;BRANCH IF STATE NOT ADJUSTED
BPL 46$ ;BRANCH IF HOLDING WEIGHT
BIC #^C177,R0 ;IF ALREADY ADJUSTED CLEAR THE FLAG
BR SLCTDX
45$: INC R0 ;GET THE NEW ADJUSTED VALUE
MOVB SLCT.N(R0),R0
BR SLCTDX
46$: SUB #20,R0 ;DECREMENT THE HOLDING COUNT
SLCTDX: MOVB R0,LB.MPN+1(R0) ;SAVE THE ADJUSTED SELECTION STATE
BIC #^C17,R0 ;AND THE NEW WEIGHT
MOVB R0,LB.MPN(J)
RESTORE <R0>
RTS PC
;
;
SLCTDO: ;ADJUST THE WEIGHT WHEN DATA GOES OUT
MOV R0,-(P)
MOV #SLCT.O,-(P)
BR SLCTDB
;
SLCTDI: ;ADJUST THE WEIGHT WHEN DATA GOES IN
MOV R0,-(P)
MOV #SLCT.I,-(P)
SLCTDB: MOVB LB.MPN+1(J),R0 ;GET THE OLD WEIGTH
BIC #^C17,R0 ;BE SURE ITS CLEAN
ADD (P)+,R0 ;AND FETCH THE NEW VALUE
MOVB (R0),R0
BR SLCTDX ; EXIT
;
;
SLCT.I:
.BYTE 200,200,200,200,201,201,201,201
.BYTE 203,203,203,203,203,203,203,203
.EVEN
;
SLCT.O:
.BYTE 200,200,200,200,200,200,201,201
.BYTE 201,201,201,201,202,202,202,202
.EVEN
;
SLCT.N:
.BYTE 020,041,062,103,124,145,166,167
.BYTE 170,171,172,173,174,175,176,177,177
.EVEN
;
.ENDC
;
;
;
;
LOCMPA: ;LOCATE LINE BLOCK FOR STATION ADDRESSED
;ASSIGNING ONE IF NECESSARY
JSR PC,GT0MPA
RTS PC ;RETURN IF IT WAS FOUND
; ;ELSE ASSIGN IT
MOV (P),J ;GET THE REUSABLE LINE BLOCK
BEQ 39$ ;BRANCH IF NOTHING TO ASSIGN
MOVB R0,LB.MPA(J) ;SET THE STATION ADDRESS
MOVB #MP.OFF,LB.MPS(J) ;MAKING SURE THE STATE IS REASONABLE
CLRB LB.MPT(J)
39$: BR GTXMPA ;CLEAN THE STACK AND EXIT
;
;
;
; ;GET THE LINE BLOCK ASSIGNED TO THE STATION ADDRESS IN R0
GETMPA: JSR PC,GT0MPA ;GET THE LINE BLOCK
RTS PC ;RETURN IF ITS WAS FOUND
BR GTXMPA ;AND ALSO IF NONE FOUND
;
;
; ;GET THE LINE BLOCK ASSIGNED TO THE STATION ADDRESS IN R0
GT0MPA: MOV J,-(P) ;SAVE ADDRESS OF FIRST LINE BLOCK TO SEARCH
CLR -(P) ;DON'T KNOW IF WE CAN REUSE SOME BLOCK
40$: CMPB R0,LB.MPA(J) ;IF THIS IS IT
BEQ GTXMPA ;WE'RE DONE
BITB #MP.OFF,LB.MPS(J) ;IF STATION IS OFFLINE
BEQ 45$
MOV J,(P) ;SAVE IT FOR REUSE
45$: MOV LB.MPL(J),J ;GET THE NEXT LINE BLOCK
CMP J,2(P) ;IF NO MORE
BNE 40$
MOV (P),2(P) ;SHIFT THE STACK TOP DOWN ONE
MOV 4(P),(P) ;AND GET THE RETURN ADDRESS
ADD #2,(P) ;MUST SKIP IN THE FAILURE CASE
CMP -(P),-(P) ;PUT TWO DUMMIES ON THE STACK
GTXMPA: CMP (P)+,(P)+ ;POP THE STACK
TST J ;SET THE Z BIT FROM VALUE OF J
RTS PC
;
;
;
; ;GET THE LINE BLOCK ASSIGNED TO THE STATION ADDRESS IN R0
; ;LOCATING AN UNUSED BLOCK IF NONE ASSIGNED
GT1MPA: JSR PC,GT0MPA
RTS PC ;RETURN IF IT WAS FOUND
BR GTXMPA ;ELSE RETURN THE FREE ONE
MOV (P),J ;ELSE GET THE REUSEABLE ONE
BR GTXMPA ;AND EXIT
;
;
.ENDC ; .IF NE FT.MPT
.ENDC;.IF NE,<NTLINE-DMCN>
.ENDC ; .IF NE NTLINE
.SBTTL SELECTING THE DDCMP LINE SERVICE PROCS
.IF NE NTLINE
.IF NE,<NTLINE-DMCN>
.MACRO X QTAG
.MACRO XX QDV,QQTAG,QCN
.IF NE QCN
.IF NE FT'QDV'11
.WORD QDV'QQTAG
.IFF
.WORD -1
.ENDC
.IFF
.WORD -1
.ENDC
.ENDM XX
XX DP,QTAG,1
XX DS,QTAG,1
XX DU,QTAG,1
XX DV,QTAG,1
XX DQ,QTAG,1
XX DUP,QTAG,1
XX DMC,QTAG,1
XX DH,QTAG,NADHLN!NDHMPT!NDHTRB!RDPDHN
XX DZ,QTAG,NADZLN!NDZMPT!NDZTRB!RDPDZN
.ENDM X
;
;
;HERE TO SELECT THE LINE INITIALIZATION PROC
SL.INI: MOVB LB.DVS(J),R2
JMP @.+4(R2)
X DINI
;
;
;HERE TO SELECT THE RECEIVER START UP PROC
SLRBEG: MOVB LB.DVS(J),R3
JMP @.+4(R3)
X RBEG
;
;
;
;HERE TO SELECT THE XMITTER START UP PROC
SLXBEG: MOVB LB.DVS(J),R3
JMP @.+4(R3)
X XBEG
;
;
;SL.SEC: RTS ;NO DRIVER TIMER FUNCTIONS NOW;
;
.ENDC;IF NE,<NTLINE-DMCN>
.ENDC ;.IF NE NTLINE