TITLE D8SINT - INTERRUPT SERVICE ROUTINE FOR DN87S - V036 SUBTTL ERIC WERME/EJW/JBS/EGF 09-FEB-88 SEARCH F,S,DTEPRM,NETPRM $RELOC $HIGH ;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED ; OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE. ; ;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION ; 1976,1977,1978,1979,1980,1982,1984,1986,1988. ;ALL RIGHTS RESERVED. .CPYRT<1976,1988> XP VD8SINT,036 ;VERSION NUMBER ENTRY D8SINT ;REFERENCED IN COMNET TO FORCE LOADING D8SINT:: Comment @ This module is meant to be a carbon copy of D85INT, the DL10/NETSER interface. Since D85INT is oriented around single message transfers, so is D8SINT even though DTESER is willing to queue any number of messages. End of Comment @ LN.MOR==1B17 ;LINE NUMBER BIT SAYING ANOTHER ; FRAGMENT IS COMING SUBTTL FEKDSP -- D8SINT ENTRY VECTOR D8SDSP::CAIL T1,FF.ONC ;RANGE CHECK THE FUNCTION CAILE T1,FF.CPW ; CODE AND STOP IF BAD PUSHJ P,NTDSTP## ;++ ERROR: BAD FUNCTION CODE TO FEK JRST @.+1(T1) ;DISPATCH TO APPROPRIATE ROUTINE IFIW NTFONC## ;USE NETSER'S DEFAULT ONCE-ONLY CODE IFIW D8SSEC ;CHECK FOR DOWN FE IFIW D8SRDD ;SET UP A READ REQUEST IFIW D8SWRT ;SET UP A WRITE REQUEST IFIW D8SCRS ;CRASH THE FEK (CPU WENT DOWN -- 11 HUNG) IFIW D8SDWN ;CALLED WHEN LEAVE PRIMARY PROTOCOL IFIW D8SUP ;CALLED WHEN ENTER PRIMARY PROTOCOL IFIW CPOPJ## ;CALLED WITH STATION CONTROL (WE DON'T WANT IT) IFIW D8SCPS ;OUR CPU IS GOING TO SLEEP IFIW D8SCPW ;OUR CPU IS WAKING UP. ;D8SSEC ROUTINE TO CHECK FOR A DOWN FE ;CALL: J := FEK ;RETURN CPOPJ (THROUGH NETSER'S NTFSEC ROUTINE) D8SSEC: SKIPN DTRJOB## ;AUTO RELOAD JOB (DTELDR)? SKIPL FEKBLK(J) ;FEK ALREADY DOWN? PJRST NTFSEC## ;DO NETSER ONCE-A-SECOND CODE PUSH P,F ;SAVE F MOVE F,FEKUNI(J) ;GET CPU,,DTE TRNN F,-1 ;WERE WE EVER UP AND RUNNING? JRST D8SSE1 ;NO PUSHJ P,GTETDS## ;FETCH ETD MOVSI T1,(ED.RLD) ;BIT TO TEST TDNN T1,ETDSTS(F) ;NEED TO RELOAD? JRST D8SSE1 ;NO MOVEI T1,FI.DWN ;FUNCTION CODE FOR NETSER PUSHJ P,FEKINT## ;DECLARE FEK DEAD D8SSE1: POP P,F ;RESTORE F PJRST NTFSEC## ;ENTER COMMON FEK CODE ;D8SRDD ROUTINE TO BY NETSER TO POST A READ REQUEST (INPUT BUFFER) ;CALL J := FEK ; FEKIAD(J) := INPUT BUFFER TO FILL ;RETURN CPOPJ D8SRDD: IFN FTMP,< HLRZ T1,FEKUNI(J) ;GET OUR CPU NUMBER, AND IF THIS IS CAME T1,.CPCPN## ; NOT "OUR" CPU, THEN SET "FK.STI" PJRST SETSTI ; SO THAT CLOCK LEVEL WILL RE-START US > AOSE FEKBSI(J) ;GET THE INPUT INTERLOCK (WE GET HERE FROM ; BOTH UUO AND INTERRUPT LEVEL) POPJ P, ;IF ALREADY DOING INPUT, EXIT SKIPN FEKIAD(J) ;MAKE SURE WE HAVE A BUFFER TO FILL JRST [SETOM FEKBSI(J);IF NO BUFFERS, SET THIS FEK IDLE (INPUT) POPJ P,] ; AND EXIT. HRRZ U,FEKIAD(J) ;GET ADDRESS OF INPUT BUFFER MOVE T1,PCBPTR(U) ;GET BYTE POINTER TO BUFFER TO FILL MOVEM T1,FEKIBP(J) ;SAVE BYTE POINTER IF FEK (FOR STRING DATA) SETZM PCBCTR(U) ;CLEAR THE COUNT IN THE PCB (NO DATA YET) AOS FEKAKC(J) ;COUNT ONE MORE QPR-ACK TO BE SENT PJRST D8SWRT ; AND CALL D8SWRT TO SEND IT SETSTI: MOVSI T1,FK.STI ;GET THE "KICK ME FOR INPUT" BIT IORM T1,FEKBLK(J) ; AND SET IT IN THE STATUS BLOCK OF THE FEK POPJ P, ; NEXT JIFFY NETSER WILL CALL AGAIN ;D8SWRT ROUTINE TO POST AN OUTPUT BUFFER TO D8SINT ;CALL J := FEK POINTER ; FEKOAD(J) := OUTPUT MESSAGE ;RETURN CPOPJ D8SWRT: IFN FTMP,< HLRZ T1,FEKUNI(J) ;GET THIS FEK'S CPU NUMBER, AND IF IT'S CAME T1,.CPCPN## ; NOT THE SAME AS THE CPU WE'RE ON, THEN JRST SETSTO ; SET "FK.STO" SO CLOCK LEVEL WILL KICK US > AOSE FEKBSO(J) ;GET THE "OUTPUT BUSY" INTERLOCK POPJ P, ; IF ALREADY DOING OUTPUT, EXIT NOW PUSHJ P,SAVE4## ;SAVE THE P'S (DTESER USES THEM ALL) PUSH P,S ;SAVE S (UUO LEVEL CALLS HERE) PUSHJ P,SNDACK ;SEND QPR-ACK'S IF NECESSARY SKIPG FEKOCT(J) ;MAKE SURE WE HAVE SOMETHING TO OUTPUT JRST [SETOM FEKBSO(J); IF NOTHING, CLEAR OUTPUT BUSY JRST SPOPJ] ; AND RETURN HRRZ U,FEKOAD(J) ;GET ADDRESS OF THE PCB TO SEND MOVSI S,T11DON ;POST ADDRESS FOR WHEN MESSAGE IS DONE MOVE P1,FEKUNI(J) ;GET "XWD CPU,DTE" MOVE P2,[XWD .EMNCL,EM.IND!.EMSTR] ;SEND INDIRECT STRING DATA MOVE P3,PCBCTR(U) ;GET THE COUNT OF THE NCL HEADER PORTION MOVE P4,PCBPTR(U) ;GET THE B.P. TO THE NCL HEADER PORTION SKIPE PCBCT2(U) ;GET THE LENGTH OF THE SECOND FRAGMENT JRST [MOVSI S,CPOPJ## ;IF THERE IS MORE, ZAP THE POST ADDR HRLI P3,(LN.MOR) ; AND SET THE "THERE IS MORE" FLAG JRST .+1] ;BACK TO MAIN CODE S0PSHJ DTEQUE## ;GIVE THE FIRST FRAGMENT TO DTESER. JRST [PUSHJ P,SETSTO ;IF NO CORE. SET THE "KICK ME" BIT SETOM FEKBSO(J) ; CLEAR OUTPUT IN PROGRESS FLAG JRST SPOPJ] ; AND EXIT. WILL TRY AGAIN LATER SKIPN P3,PCBCT2(U) ;GET THE LENGTH OF THE SECONDARY OUTPUT BUFFER JRST SPOPJ ;EXIT NOW UNLESS SECOND FRAGMENT TO BE SENT MOVSI S,T11DON ;GET THE POST ADDRESS MOVE P4,PCBPT2(U) ;GET THE ADDRESS OF THE FRAGMENT (EVA) LDB T1,PCBPCV## ;GET THE COMPRESSION CODE. CAIN T1,PCV.BN ;IF IT IS BINARY, THEN WE MUST JRST [IORI P2,EM.16B ; REQUEST WORD MODE TRANSFERR. LSH P3,1 ; AND DOUBLE COUNT (MAKE IT # OF -11 BYTES) JRST .+1] ;BACK TO MAIN FLOW DPB T1,[POINT 2,P3,16] ; PUT THE COMPRESSION CODE IN THE LINE ; NUMBER FIELD S0PSHJ DTEQUE## ;SEND THE MESSAGE JRST [POP P,S ;IF WE FAIL ON THE SECOND PART, FIX UP STACK JRST D8SCRS] ; AND CRASH THE FEK (WE CAN'T RESTART PART ; WAY THROUGH...) SPOPJ: POP P,S ; POPJ P, ;ALL DONE SETSTO: MOVSI T1,FK.STO ;GET THE "CLOCK LEVEL PLEASE KICK ME" FLAG IORM T1,FEKBLK(J) ; AND SET IT SO WE GET TO TRY OUTPUT AGAIN POPJ P, ;ALL DONE FOR NOW. CLOCK LEVEL WILL CALL ; IN A JIFFY OR SO... ;HERE AFTER DTESER HAS SUCCESSFULLY TRANSMITTED THE MESSAGE T11DON: HLRZ T1,P1 ;ISOLATE CPU # MOVE J,@DTEFEK##(T1) ;GET FEK ADDRESS SKIPGE FEKBLK(J) ;IF WE THINK THE FEK IS DOWN, TLNE P3,(LN.MOR) ; OR IF THIS IS JUST THE HEADER OF A POPJ P, ; 2 PART MESSAGE, DON'T CALL NETSER IFN PARANOID&P$FEK,< SKIPGE FEKBSO(J) ;MAKE SURE THAT WE ARE OUTPUT ACTIVE PUSHJ P,NTDSTP## ;++ ERROR: OUTPUT DONE INTERRUPT BUT NOT ACTIVE > HRRZ U,FEKOAD(J) ;GET THE OUTPUT BUFFER NETOFF ;DON'T LET OTHER CPU HACK QUEUES HRRZM U,FEKODN(J) ;GIVE THE "SENT" MESSAGE TO NETSER HRRZ U,PCBBLK(U) ;GET THE "NEXT" OUTPUT BUFFER HRRZM U,FEKOAD(J) ;MAKE THE NEXT THE NEW "FIRST" SOS FEKOCT(J) ;COUNT DOWN ONE LESS BUFFER NETON ;QUEUE IS CONSISTANT SETOM FEKBSO(J) ;CLEAR THE "OUTPUT BUSY" FLAG MOVEI T1,FI.ODN ;GET THE "OUTPUT DONE" CODE PUSHJ P,FEKINT## ; AND TELL NETSER THAT BUFFER IS OUT PJRST D8SWRT ;TRY TO SET UP ANOTHER WRITE REQUEST AND EXIT ;Here when D8SWRT has queued all the fragments of the ncl message it can so ; it is now safe to see if the interrupt code (D8SRDD) wanted to send ; an ack to request another message. It cannot do so between the time we ; send the first and last fragments because the ack will look like a ; message termination and the next data fragment will look like the start ; of an NCL message. SNDACK: SKIPN FEKAKC(J) ;SEE IF WE NEED TO SEND ANY ACK'S POPJ P, ; IF NO QPR-ACK'S TO SEND, RETURN SOS FEKAKC(J) ;DECREMENT NUMBER OF QPR-ACK'S TO SEND MOVSI S,CPOPJ## ;DON'T NEED TO KNOW IT'S SENT MOVE P1,FEKUNI(J) ;GET "XWD CPU,DTE" TO SEND MESSAGE THROUGH DMOVE P2,[XWD .EMNCL,.EMACK ;SEND AN ACK EXP 2] ;AND 2 BYTES DATA SETZ P4, ;SNEAKY WAY TO SEND 0 DATA S0PSHJ DTEQUE## ;NO, JUST SEND THIS PIECE PJRST D8SCRS ;NEED BETTER CODE - CALL IT DEAD FOR NOW JRST SNDACK ;SEE IF WE NEED TO SEND ANY MORE ;TO DTESTR WHEN THE MESSAGE DOES ARRIVE ;D8SCRS ROUTINE CALLED WHEN NETSER BELIEVES THAT THE FRONT END -11 ; IS SICK. THIS ROUTINE PUTS THE -11 IN SECONDARY PROTOCOL. ;CALL J := FEK POINTER ;RETURN CPOPJ D8SCRS: MOVE F,FEKUNI(J) ;GET "XWD CPU,DTE" TRNN F,-1 ;MAKE SURE WE'RE UP POPJ P, ;IF DTE# NOT SET UP, WE'RE NOT UP PUSHJ P,GTETDS## ;GET F := ETD POINTER PUSHJ P,DTECLR## ;PUT THE DTE IN SECONDARY PROTOCOL PJSP T1,DTERLD## ;NOW SET THE RELOAD BIT FOR DTELDR ;D8SCPS ROUTINE CALLED WHEN THIS CPU IS GOING TO SLEEP. ; CURRENTLY, THIS ROUTINE JUST TERMINATES PROTOCOL. DOING THIS ; CAUSES DTESER TO DECLARE THE FEK DOWN. SO WE END UP CALLING NETSER ;CALL J := POINTER TO THE FEK ;RETURN CPOPJ D8SCPS: MOVE F,FEKUNI(J) ;GET "XWD CPU,DTE" TRNN F,-1 ;MAKE SURE WE'RE UP POPJ P, ;IF DTE# NOT SET UP, WE'RE NOT UP PUSHJ P,GTETDS## ;GET F := ETD POINTER PJRST DTECLR## ;PUT THE DTE IN SECONDARY PROTOCOL ;D8SCPW ROUTINE CALLED WHEN OUR CPU WAKES UP FROM SYSTEM SLEEP ; CURRENTLY A NO-OP ;CALL J := POINTER TO THE FEK ;RETURN CPOPJ D8SCPW: POPJ P, ;CURRENTLY SPRINI DOES ALL THE WORK ;ROUTINE CALLED WHEN DTESER DISCOVERS ANOTHER -11 IS UP. IF THAT ; -11 HAS A FEK BLOCK, THEN IT IS A DN87S AND NETSER WILL ; BE TOLD ABOUT IT. D8SUP: HLRZ T1,P1 ;ISOLATE CPU # SKIPN J,@DTEFEK##(T1) ;DOES THIS -11 HAVE A FEK? POPJ P, ;NOPE, DON'T WORRY ABOUT IT HRRM P1,FEKUNI(J) ;REMEMBER WHICH DTE IS ASSOCIATED WITH FEK SETOM FEKBSO(J) ;NO LONGER EXPECTING OUTPUT SETOM FEKBSI(J) ;NO LONGER EXPECTING INPUT SETZM FEKAKC(J) ;CLEAR THE "ACK INTERLOCK" MOVSI T1,FK.ONL ;SET ONLINE FLAG FOR NETSER'S ONCE PER IORM T1,FEKBLK(J) ; SECOND CODE WHICH WILL START THINGS UP POPJ P, ;RETURN TO DTESER ;ROUTINE CALLED FROM DTESER WHEN THE -11 ENTERS SECONDARY PROTOCOL ; WHICH ONLY HAPPENS WHEN IT IS BEING RELOADED. D8SDWN: HLRZ T1,P1 ;ISOLATE CPU # SKIPN J,@DTEFEK##(T1) ;DOES THIS -11 HAVE A FEK? POPJ P, ;NOPE, NETSER WON'T BE INTERESTED PUSH P,F ;SAVE ETD ADDRESS FROM DTESER MOVEI T1,FI.DWN ;GET THE "FRONT END DIED" FUNCTION CODE PUSHJ P,FEKINT## ; AND TELL NETSER THE NEWS. PJRST FPOPJ## ;RESTORE F BEFORE RETURNING TO DTESER ;TO-10 DISPATCH TABLE IFIW CPOPJ## ;(-1) LOST TO-10 INDIRECT MESSAGE NCLDSP::DTEFNC ;(??) GENERATE DUMMY TABLE ENTRIES DTEFNC (STR,D8SSTR) ;(03) HERE IS STRING DATA ;ROUTINE TO HANDLE INCOMING STRING DATA MESSAGE. HERE WHEN HEADER ; HAS ARRIVED. D8SSTR: HLRZ T1,P1 ;ISOLATE CPU # SKIPN J,@DTEFEK##(T1) ;GET FEK ADDRESS FOR THIS DTE PJRST EATMSG## ;IGNORE IF WE DON'T THINK IT IS A DN87S SKIPL FEKBLK(J) ;DID I KNOW I WAS UP? PUSHJ P,D8SFST ;FIRST MESSAGE, DO SETUP HRRZ U,FEKIAD(J) ;GET THE PCB WE'RE SUPPOSED TO BE FILLING SKIPGE FEKBSI(J) ;MAKE SURE WE'RE EXPECTING (BUSY INPUT) PJRST EATMSG## ;NOT EXPECTING IT, DISCARD IT MOVE P4,FEKIBP(J) ;TELL DTESER WHERE TO PUT MESSAGE HRRZ T1,P3 ;LENGTH OF NEXT SEGMENT ADDB T1,PCBCTR(U) ;ACCUMULATE PROPOSED TOTAL LENGTH OF MESSAGE ADDI T1,3 ;ROUND UP BYTE COUNT AND LSH T1,-2 ;TRUNCATE TO TOTAL WORD LENGTH OF MESSAGE CAMLE T1,PCBALN(U) ;WILL DTE'S MESSAGE STILL FIT? PJRST D8SCRS ;NO, KROAK OFF THE -11 HRRZ T1,P3 ;GET SIZE OF NEXT SEGMENT AGAIN ADJBP T1,FEKIBP(J) ;READY POINTER FOR NEXT MESSAGE MOVEM T1,FEKIBP(J) ;AND REMEMBER IT MOVSI S,T10DON ;POST ADDRESS FOR WHEN DATA COMES IN POPJ P, ;RETURN TO HAVE DTESER XFER INDIRECT PORTION ;CONTINUE AFTER HERE WHEN DATA IS IN T10DON: HLRZ T1,P1 ;ISOLATE CPU # SKIPN J,@DTEFEK##(T1) ;GET FEK ADDRESS AGAIN POPJ P, ;I MET A MAN WHO WASN'T THERE... SKIPGE FEKBLK(J) ;IF THIS FEK ISN'T UP, OR TLNE P3,(LN.MOR) ; THERE IS MORE TO COME, POPJ P, ; DON'T CALL NETSER IFN PARANOID&P$FEK,< ;IF WE FEAR DTESER IS SCREWING US, SKIPGE FEKBSI(J) ;MAKE SURE THAT WE EXPECT A MESSAGE STOPCD .+1,DEBUG,UID, ;++ UNEXPECTED INPUT DONE > SETOM FEKBSI(J) ;CLEAR "INPUT BUSY" MOVEI T1,FI.RDD ;FLAG FOR INPUT DONE PJRST FEKINT## ;AND TELL NETSER WE HAVE A MESSAGE ;HERE TO INITIALIZE A D8S FEK WHEN RECEIVING A NODE-ID D8SFST: PUSHJ P,SAVE4## ;PRESERVE SOME ACS PUSHJ P,SAVT## ;AND SOME MORE MOVE T1,[PUSHJ P,D8SDSP] ;PROPER FEKDSP INSTRUCTION CAMN T1,FEKDSP(J) ;ARE WE REALLY OFF-LINE? POPJ P, ;OOPS. GET OUT BEFORE WE DO DAMAGE PUSH P,F ;PRESERVE DTESER'S FAVORITE AC MOVEI T2,DD.ANF ;LINE-USER TYPE FOR ANF10 PUSHJ P,DFKSET## ;CALL D8SUSR WITH ACS SETUP MOVEI T1,FF.UP ;WE'RE UP NOW XCT FEKDSP(J) ;DO THIS ONE, TOO POPJ P, ;RETURN AFTER INITIALIZING ;HERE TO INITIALIZE A D8S FEK ON DTE. SET-LINE-USER D8SUSR::MOVE T4,DFKNAM##(T2) ;GET NAME OF TYPE MOVEM T4,DLXNMT##(T1) ;SET IN BASE BLOCK MOVEI T4,.C1D8S ;MY TYPE MOVEM T4,DLXTYP##(T1) ;SET IN BLOCK SETZM DLXCAL##(T1) ;USE DEFAULT CAL11. DISPATCH IN COMDEV PUSHJ P,SAVE4## ;PRESERVE SOME ACS PUSHJ P,SAVT## ;AND SOME MORE MOVE T2,[PUSHJ P,D8SDSP] ;PROPER FEKDSP INSTRUCTION MOVEM T2,FEKDSP(T3) ;SET IT PUSH P,J ;PRESERVE J MOVE J,T3 ;USE PROPER AC FOR FEK ADDRESS MOVEI T1,FF.ONC ;ONCE-ONLY CALL XCT FEKDSP(J) ;DO IT JRST JPOPJ## ;RESTORE AND RETURN TO DTESER XLIST $LIT LIST END