%CONTROL K'100001' %BEGIN %RECORDFORMAT PF(%BYTEINTEGER SER, REPLY, %INTEGER A, B, C) %ROUTINE BSP(%RECORD (PF) %NAME PQ) !******************************** !* EMAS-2900 BSP INTERFACE * !* HANDLER * !* FILE: BSP4S * !* 18:3:80 * !********************************* !! STK = 300, STRM = 1 %SYSTEMROUTINESPEC LINKIN(%INTEGER SER) %SYSTEMROUTINESPEC MAP HWR(%INTEGER SEG) %SYSTEMROUTINESPEC ALARM(%INTEGER TICKS) %RECORDFORMAT DMF(%INTEGER I) %CONSTRECORD (DMF) %NAME NIL = 0 %CONSTSTRING (7)VSN = 'VSN004A' %OWNINTEGER DATAMARK=K'123456' %RECORDFORMAT MEF(%RECORD (MEF) %NAME LINK, %BYTEINTEGER LEN, %C TYPE, %INTEGER ADDRESS,PORT,RCOMM,TCOMM, %C %INTEGERARRAY A(0:100) ) ! THINK ABOUT THE POSITION OF ! 'LEN' !BUFFER QUEUES %RECORDFORMAT MEQF(%RECORD (MEF) %NAME LINK); %RECORDFORMAT PE(%BYTEINTEGER SER, REPLY, FN, PORT, %C %RECORD (MEF) %NAME MES, %BYTEINTEGER LEN, S1) %RECORDFORMAT PE2(%BYTEINTEGER SER, REPLY, FN, PORT, %C %INTEGER LPORT, HPORT ); !LOW ND HIGH PORT LIMITS %RECORDFORMAT PE3(%BYTEINTEGER SER,REPLY,FN,PORT,A,B,C,D) %RECORDFORMAT QF(%RECORD (MEF) %NAME E) %RECORDFORMAT R1F(%INTEGER X) %RECORDFORMAT R2F(%RECORD (MEF) %NAME MES) %RECORDFORMAT R3F(%BYTEINTEGERNAME B) %RECORDFORMAT R4F(%STRINGNAME S) !BYTE STREAM COMMAND CODES %CONSTINTEGER RDY=X'3000' %CONSTINTEGER NOTRDY=X'5000' %CONSTINTEGER RESET=X'6300' %CONSTINTEGER CLOSE=X'6600' %CONSTINTEGER DATA=X'A000' %CONSTINTEGER NODATA=X'C000' %CONSTINTEGER CLOSEREQ=4 !TRANSPORT SERVICE COMMAND CODES %CONSTINTEGER OPEN=X'6A00' %CONSTINTEGER SSPREQ=X'6C00' %CONSTINTEGER OPENACK=X'6500' %CONSTINTEGER LONGBLOCK=X'9000' %CONSTINTEGER LONGBLOCKCH=X'9000' %CONSTINTEGER LONGBLOCKCS0=X'9400' %CONSTINTEGER SINGLESHOT=X'9800' !BYTE STREAM STATES %CONSTINTEGER CLOSED=0; ! %CONSTINTEGER OPENING=1; !WAITING FOR OPEN ACK %CONSTINTEGER CLOSING=2; !WAITING FOR CLOSE %CONSTINTEGER IDLE=3; !BYTE STREAM STATE %CONSTINTEGER NESENT=4; !DITTO %CONSTINTEGER ESENT=5; !DITTO %CONSTINTEGER OPENINPUT=6; !OPEN OR SEND MESS HAS BEEN INPUT %CONSTINTEGER OPEN MESS=7; !WAITING FOR RESPONSE TO SEND MESS ! ARRAY TO DEFINE WHICH BS STATES ARE CLOSEABLE %OWNBYTEINTEGERARRAY CLOSEABLE(0:OPEN MESS)=0,1,0,1,1,1,0,0 %CONSTINTEGER BSLIMIT=15; !NUMBER OF BYTE STREAMS %CONSTINTEGER BSLIM2=31; !BSLIMIT*2+1 ! FUNCTION CODES TO AND FROM ! RING SER !VALUES BELOW ADDED TO FUNCTION CODES %CONSTINTEGER RELEASEFLAG=X'80'; !RELEASE BUFFER AFTER OUTPUT %CONSTINTEGER TELLFLAG=X'40'; !NOTIFY AT END OF OUTPUT %CONSTINTEGER CS0FLAG=X'20' %CONSTINTEGER COMMAND MASK=X'1F'; !TO MASK OUT VALUES ABOVE %CONSTINTEGER ENABLE PORT=0 %CONSTINTEGER XDATA=1 %CONSTINTEGER SSOUT=2; !NOT USED %CONSTINTEGER XRDY=3 %CONSTINTEGER XNOTRDY=4 %CONSTINTEGER XNODATA=5 %CONSTINTEGER XCLOSE=6 %CONSTINTEGER XRESET=7 %CONSTINTEGER XCLOSEREQ=8 %CONSTINTEGER OUTPUT TRACE=16; !FORCE OUTPUT OF RING TRACE %CONSTINTEGER R OUTPUT DONE=0 %CONSTINTEGER TRANSFER ERROR=1 %CONSTINTEGER R INPUT DONE=2 %CONSTINTEGER INPUT ERROR=3 %CONSTINTEGER RING DOWN=4 ! INCOMING FUNCTION CODES ! ------------------------- %CONSTINTEGER ENABLEFACILITY=1 %CONSTINTEGER DISABLEFACILITY=2 %CONSTINTEGER CALLREPLY=3 %CONSTINTEGER ENABLEINPUT=4 %CONSTINTEGER PUTOUTPUT=5 %CONSTINTEGER CLOSECALL=6 %CONSTINTEGER ABORTCALL=7 %CONSTINTEGER OPENCALL=8 %CONSTINTEGER OPENMESSAGE=9 ! OUTGOING FUNCTION CODES ! ----------------------- %CONSTINTEGER INCOMINGCALL=2 %CONSTINTEGER INPUTDONE=3 %CONSTINTEGER OUTPUTDONE=4 %CONSTINTEGER CALLCLOSED=5 %CONSTINTEGER CALLABORTED=6 %CONSTINTEGER OPENREPLY A=7 %CONSTINTEGER OPENREPLY B=8 %CONSTINTEGER MESSAGE R=9 %CONSTINTEGER MESSAGE REPLY=10 %CONSTINTEGER TIMEOUT=2; !NUMBER OF ALARM CALLS !TIMEOUT BETWEEN 1 AND 2 SECS. %CONSTINTEGER ME=15; !RING ADDRESS OF FEP %CONSTINTEGER FAULTLIMIT = 10; !BYTE STREAM IS CLOSED AFTER !THIS NUMBER OF ACCUMULATED ERRORS !STREAM 1 IS USED ONLY FOR OPEN/OPENACK TRANSFERS !FORMAT OF RECORDS DEFINING THE BYTE STREAMS !EACH BYTE STREAM HAS 2 BSF RECORDS. ONE FOR THE !RECEIVER AND ONE FOR THE TRANSMITTER. ALL THE !BS RECORDS ARE IN ARRAY BS, THE RECORDS FOR PORT !P ARE THE 2*P (TRANSMITTER) AND THE 2*P+1 (RECEIVER) !ELEMENTS OF THE ARRAY. %RECORDFORMAT BSF( %INTEGER TOUT, DESTPORT, %C %RECORD (MEF) %NAME BUF, %C %BYTEINTEGER STATE, SEQUENCE, DEST, REPLY, %C FAULTCOUNT, NUMBER, CLOSEFLAG, %C %RECORD (MEQF) BUFQ ) %OWNRECORD (BSF) %ARRAY BS(2:BSLIM2) !INFO DESCRIBING INPUT TRANSFER %OWNINTEGER ISOURCE,IPORT,IRCOMM,ITCOMM %OWNRECORD (BSF) %NAME TBSP,RBSP !TIME IS INCREMENTED ON EVERY ALARM CALL, ON OVERFLOW TO !ZERO IT IS SET TO 1 AS TIME 0 IMPLIES TIME-NOT-SET %OWNINTEGER TIME %CONSTINTEGER MAXFACILITY=25; !BS FUNCTION CODES %OWNBYTEINTEGERARRAY FACILITY(0:MAX FACILITY)=0(0) ! FACILITY CODES ARE :- ! 18 = ITP %INTEGER T,I %RECORD (BSF) %NAME BSP !************************************************************** !* BUFFER MANAGER CALLS (FROM AND TO) * !************************************************************** %CONSTINTEGER BUFFER HERE = 0 !********** TO BUFFER MANAGER *********** %CONSTINTEGER REQUEST BUFFER = 0 %CONSTINTEGER RELEASE BUFFER = 1 !**************************************************************** !********** VARIOUS SERVICE NUMBERS ************* %CONSTBYTEINTEGERNAME INT = K'160060' %CONSTBYTEINTEGERNAME OWN ID = K'160030' %CONSTINTEGER BSP SER = 16 %CONSTINTEGER RING SER = 10 %CONSTINTEGER BUFFER MANAGER = 17 %CONSTINTEGER TIME INT = 0 %CONSTBYTEINTEGERNAME CHANGE OUT ZERO = K'160310' %CONSTINTEGER T3 SER = 21 !************************************************************ %RECORD (PE2) %NAME PP; !POINTS TO P BELOW %RECORD (PE3) %NAME OP3; !POINTS TO OP BELOW %RECORD (PE2) %NAME OP1; !POINTS TO OP BELOW !%OWNRECORD (PE) %ARRAY PTRACE(0:300) !%OWNINTEGER PTP=0 %RECORD (PE)P %RECORD (PE) OP %OWNINTEGER X=0 %OWNRECORD (MEF) %NAME INBUFQ %OWNINTEGER MON = 0 %OWNINTEGER INITPAUSE = 20; !INITIAL PAUSE BEFORE STARTING ! RING INTERFACE %RECORD (R1F)R1; %RECORD (R2F) %NAME R2; %RECORD (R3F) %NAME R3 %RECORD (R4F) %NAME R4 ! %ROUTINESPEC PONT(%RECORD (PE) %NAME P) %ROUTINESPEC FROMABOVE %INTEGERFNSPEC FINDFREEPORT %ROUTINESPEC FROM BUFFER MANAGER %ROUTINESPEC FROM BELOW %ROUTINESPEC PERROR(%INTEGER I) %ROUTINESPEC PROCESSINPUT %ROUTINESPEC SSINPUT %ROUTINESPEC DOOPENACK %ROUTINESPEC OPENFAILED( %RECORD (BSF) %NAME BSP) %ROUTINESPEC ERROR(%INTEGER N,SOURCE) %ROUTINESPEC INIT P REC(%RECORD (BSF) %NAME BSP, %C %INTEGER SEQ,STATE,TOUT,REPLY, %C DEST,DESTPORT) %ROUTINESPEC INITPORT( %INTEGER I,DEST,DESTPORT,REPLY) %ROUTINESPEC DO I RDY %ROUTINESPEC DOINOTRDY %ROUTINESPEC DODATAACK %ROUTINESPEC DOIDATA %ROUTINESPEC DOINODATA %ROUTINESPEC TTIMEDOUT(%RECORD (BSF) %NAME BSP) %ROUTINESPEC RTIMEDOUT(%RECORD (BSF) %NAME BSP) %ROUTINESPEC SEND TO RING(%INTEGER FN, %RECORD (BSF) %NAME BSP) %ROUTINESPEC TSEND(%RECORD (BSF) %NAME BSP) %ROUTINESPEC INITIALISE %ROUTINESPEC DORESET %ROUTINESPEC DOCLOSE %ROUTINESPEC DOWN(%RECORD (BSF) %NAME BSP,%INTEGER TYPE) %ROUTINESPEC FREE BUFFER(%RECORD (MEF) %NAME MEF) %ROUTINESPEC SEND OPENACK(%RECORD (BSF) %NAME BSP, %INTEGER SUFLAG) %ROUTINESPEC FAULT(%RECORD (BSF) %NAME BSP) %ROUTINESPEC QPUSH(%RECORD (MEQF) %NAME Q, %RECORD (MEF) %NAME P) %ROUTINESPEC FORCECLOSE(%INTEGER PORT, TYPE) %ROUTINESPEC STARTCLOSE(%RECORD (BSF) %NAME BSP) %ROUTINESPEC FINISHCLOSE( %INTEGER PORT) %ROUTINESPEC CLEARBSPORT(%RECORD (BSF) %NAME BSP) %ROUTINESPEC SEND(%RECORD (BSF) %NAME BSP, %INTEGER FN) %ROUTINESPEC SWABA(%INTEGERNAME P,%INTEGER LEN) %ROUTINESPEC MONP(%RECORD (PE) %NAME P) !! %PERMRECORD (MEF) %MAPSPEC POP(%RECORD (QF) %NAME Q) %PERMROUTINESPEC PUSH(%RECORD (QF) %NAME Q, %RECORD (MEF) %NAME E) !********************************************** !* INITIALISATION * !********************************************** MAP VIRT(BUFFER MANAGER, 5, 4); ! MAP TO MY SEG 4 R2 == R1; R3 == R2; R4 == R3 LINKIN(BSP SER) CHANGE OUT ZERO = T3 SER INITIALISE; !INITIALISE DATA STRUCTURES ALARM(50) %CYCLE P_SER = 0; POFF(P) ! CLOCK CALL %IF P_SER = OWN ID %START; %IF P_REPLY=0 %START; !CLOCK CALL ALARM(50) TIME=TIME+1 %IF TIME=0 %THEN TIME=1; !TIME=0 => TIME NOT SET !***** SEE IF INITIAL PAUSE HAS EXPIRED %IF INITPAUSE > 0 %START INITPAUSE=INITPAUSE-1 %IF INITPAUSE = 0 %START; ! START OF RING !SEND STARTUP COMMAND TO RING HANDLER OP1_SER=RING SER; OP1_REPLY=OWN ID OP1_FN=ENABLE PORT OP1_LPORT=1; !LOW PORT LIMIT OP1_HPORT=BSLIMIT; !HIGH PORT LIMIT ! PONT(OP) PON(OP1) %FINISH %FINISH %IF 'M' <= INT <= 'P' %START MON = INT-'O'; INT = 0 %FINISH X=X+1 !LOOK FOR TIMEOUTS %CYCLE I=4,2,BSLIM2-1 T=BS(I)_TOUT %IF T#0 %AND TIME-T>TIMEOUT %THENC TTIMEDOUT(BS(I)) T=BS(I+1)_TOUT %IF T#0 %AND TIME-T>TIMEOUT %THENC RTIMEDOUT(BS(I+1)) %REPEAT %ELSE ! PONT(P) %IF P_REPLY=RING SER %START FROM BELOW %ELSE %IF P_REPLY=BUFFER MANAGER %START FROM BUFFER MANAGER %FINISH %FINISH %FINISH %ELSE %IF MON<0 %START PRINTSTRING("RI") MONP(P) %FINISH ! PONT(P) %IF P_SER = BSP SER %START FROM ABOVE %FINISH %FINISH %REPEAT !MISCELLANEOUS ROUTINES %ROUTINE FROM ABOVE !------------------ !DEOCDE MESSAGE FROM HIGHER LEVEL PROTOCOL SOFTWARE. !P-FN = FUNCTION CODE !P_PORT = BYTE STREAM NUMBER !P_MES = BUFFER POINTER !P_S1 USED ON CALL REPLY, #0 => OK, =0 => REJECT OPEN ! ALSO BS FUNCTION CODE ON ENABLE/DISABLE %INTEGER I,FN,S1,PORT,L %SWITCH FNS(ENABLE FACILITY : OPEN MESSAGE) FN=P_FN S1=P_S1 PORT=P_PORT %IF FN>OPEN MESSAGE %START PERROR(1) %RETURN %FINISH -> FNS(FN) FNS(ENABLE FACILITY): FNS(DISABLE FACILITY): %IF S1>MAX FACILITY %THEN PERROR(3) %AND %RETURN %IF FN=ENABLE FACILITY %THEN FACILITY(S1)=P_REPLY %ELSEC FACILITY(S1)=0 %RETURN FNS(CALL REPLY): BSP==BS(PORT<<1); !REPLY TO OPEN %IF BSP_STATE#OPEN INPUT %THEN PERROR(4) %AND %RETURN %IF S1#0 %START; !ACCEPTED I=0 %ELSE I=1; !FAILED %FINISH !SEND OPEN ACK REPLY SEND OPENACK(BSP , I) !IF OPEN FAILED OR SENDMESSAGE RESPONSE CLEAR THE PORT %IF S1=0 %OR S1=128 %THEN CLEARBSPORT(BSP) %AND %RETURN INITPORT(PORT<<1, BSP_REPLY, BSP_DEST, BSP_DESTPORT) !RUN THROUGH INTO ENABLE INPUT CASE TO SEND RDY FNS(ENABLE INPUT): BSP==BS( PORT<<1+1 ) %IF BSP_CLOSEFLAG#0 %START %RETURN %FINISH %IF BSP_STATE#NESENT %THEN %RETURN SEND TO RING( XRDY, BSP) BSP_STATE=ESENT BSP_TOUT=TIME %RETURN FNS(PUT OUTPUT): BSP==BS(PORT<<1) %IF BSP_STATEESENT %OR BSP_CLOSEFLAG #0 %START FREEBUFFER(P_MES) %RETURN %FINISH !SWAB THE DATA PART OF THE BUFFER L=P_MES_LEN SWABA(P_MES_A(0), (L+1)>>1 ) !CONVERT THE BUFFER LENGTH TO PACKET COUNT, LEAVING THE ODD BYTE !FLAG BIT IN TCOMM P_MES_LEN=(L+3)>>1 P_MES_TCOMM=(L&1) %IF BSP_STATE=NESENT %START BSP_BUF==P_MES TSEND(BSP) %ELSE QPUSH(BSP_BUFQ, P_MES); !QUEUE BUFFER ON BYTE STREAM %FINISH %RETURN FNS(CLOSECALL): BSP==BS(PORT<<1+1) !SEE IF RESPONSE TO CLOSE REQUEST %IF BSP_CLOSEFLAG#0 %START; !YES FORCECLOSE(PORT, 0); !SEND OUT CLOSE %RETURN %FINISH BSP==BS(PORT<<1) %IF BSP_STATE # CLOSING %START BSP_CLOSEFLAG=1 %IF BSP_BUF==NIL %AND BSP_STATE=NESENT %THEN TSEND(BSP) %FINISH %RETURN FNS(ABORT CALL): FORCECLOSE(PORT, CALL ABORTED) %RETURN FNS(OPEN MESSAGE): PORT=FIND FREE PORT %IF PORT#0 %START BSP==BS(PORT<<1) INIT P REC(BSP, 0, OPEN MESS, TIME, P_REPLY,P_LEN, 1) P_MES_ADDRESS=P_LEN P_MES_PORT=1 P_MES_RCOMM=SSPREQ+(P_MES_LEN & 1) P_MES_TCOMM=PORT P_MES_A(0)=P_S1; !FACILITY NUMBER P_MES_LEN=(P_MES_LEN+1)>>1+2; !CONVERT BYTE LEN TO BS HDR SWABA(P_MES_A(1), P_MES_LEN-2) OP_MES==P_MES SEND TO RING(XDATA+RELEASE FLAG, BSP) %ELSE FREEBUFFER(P_MES); !NO FREE PORT %FINISH %RETURN FNS(OPEN CALL): PORT=FIND FREE PORT %IF PORT#0 %START !S1 = DEST PORT (FACILITY) !LEN = DESTINATION ADDRESS BSP==BS(PORT<<1) BSP_STATE=OPENING BSP_REPLY=P_REPLY BSP_DEST=P_LEN !IF S1=255 THEN THE FACILITY CODE IS A 16 BIT VALUE IN !P_LPORT, S1 IS USED FOR BYTE VALUES FOR COMPATIBILITY WITH OLD !GATE %IF S1#255 %START BSP_DESTPORT=S1 %ELSE BSP_DESTPORT=PP_LPORT %FINISH OP_FN=REQUEST BUFFER; OP_SER=BUFFER MANAGER OP_REPLY=OWN ID; OP_PORT=PORT OP_LEN=0; !LONG BUFFER ! PONT(OP) PON(OP) %FINISH !REPLY BACK UP TO GIVE PORT NUMBER OP_SER=P_REPLY; OP_REPLY=BSP SER OP_S1=P_S1; OP_FN=OPEN REPLY A OP3_A=PORT; !RETURN PORT NUMBER OP_PORT=P_PORT; OP_LEN=P_LEN %IF MON<0 %START PRINTSTRING("RO") MONP(OP) %FINISH ! PONT(OP) PON(OP) %RETURN %END; !FROM ABOVE %INTEGERFN FINDFREEPORT !----------------------------- %INTEGER I %CYCLE I=4,2,BSLIM2-1 %IF BS(I)_STATE=CLOSED %THEN %RESULT=I>>1 %REPEAT %RESULT=0 %END %ROUTINE PERROR(%INTEGER NUMBER) !------------------------------- PRINTSTRING("RING:PERROR -"); WRITE(NUMBER,3) WRITE(P_REPLY,3) WRITE(P_FN,3) WRITE(P_PORT,3) WRITE(P_LEN,3) WRITE(P_S1,3) NEWLINE %END; !PERROR %ROUTINE FROM BUFFER MANAGER !----------------------------- !HAVE NOW GOT BUFFER IN WHICH TO SEND AN OPEN %RECORD (MEF) %NAME MES %RECORD (BSF) %NAME BSP BSP==BS(P_PORT << 1) %IF BSP_STATE#OPENING %START FREEBUFFER(P_MES) %RETURN %FINISH MES==P_MES MES_LEN=2 MES_PORT=1 MES_RCOMM=OPEN MES_TCOMM=P_PORT; !REPLY PORT NUMBER MES_A(0)=BSP_DESTPORT; !REQD FACILITY MES_ADDRESS=BSP_DEST OP_MES==MES SEND TO RING(XDATA+RELEASE FLAG, BSP) BSP_TOUT=TIME %END %ROUTINE FROM BELOW !------------------ ! MESSAGES ARE :- TRANSFER ERROR (WITH BSP PORT NUMBER IN P_PORT) ! R INPUT DONE ! RING DOWN %RECORD (MEF) %NAME MES %INTEGER FN, I2, I FN=P_FN %IF FN=R INPUT DONE %START !VALIDATE INPUT TRANSFER AND PUT BS INFO INTO GLOBAL VARIABLES MES==P_MES !AFTER PROCESSING THE INPUT THE BUFFER IN P_MES IS RELEASED !UNLESS P_MES IS SET TO NIL IPORT=MES_PORT I2=IPORT<<1 ISOURCE=MES_ADDRESS %IF MES_LEN<1 %THEN ->ERROR TBSP==BS(I2) RBSP==BS(I2+1) ITCOMM=MES_TCOMM IRCOMM=MES_RCOMM %IF IPORT=1 %START SSINPUT %ELSE %IF TBSP_DEST#ISOURCE %THEN ->ERROR PROCESS INPUT %FINISH %UNLESS P_MES==NIL %THEN FREEBUFFER(P_MES) %RETURN ERROR: FAULT(TBSP) PRINTSTRING("BSP:ILLEGAL INPUT FROM"); WRITE(ISOURCE, 3); NEWLINE FREEBUFFER(P_MES) %ELSE %IF FN=TRANSFER ERROR %START FAULT(BS(P_PORT<<1)) %ELSE %IF FN=RING DOWN %START; !CLOSE ALL THE BYTE STREAMS %CYCLE I=2, 1, BSLIMIT FORCECLOSE(I, CALL ABORTED) %REPEAT %FINISH %FINISH %FINISH %END %ROUTINE PROCESS INPUT !--------------------- !INPUT TRANSFER HAS JUST FINISHED ! ASSUME IT'S BYTE STREAM AND PROCESS THE COMMANDS !IF IT'S DATA THE DATA WILL HAVE BEEN INPUT INTO THE !REQUISITE BUFFER %IF IRCOMM&X'F000'=RDY %START DO I RDY %ELSE %IF IRCOMM&X'F000'=NOTRDY %START DO I NOT RDY %ELSE %IF IRCOMM=RESET %START DO RESET %ELSE %IF IRCOMM=OPENACK %START DOOPENACK %ELSE %IF IRCOMM=CLOSE %THENC DO CLOSE %FINISH %FINISH %FINISH %FINISH ! OBEY TRANSMITTER COMMAND %IF ITCOMM & X'F008'=DATA %START DO I DATA %ELSE %IF ITCOMM & X'F000' =NODATA %THENC DO I NODATA %FINISH %END; !PROCESS INPUT %ROUTINE SSINPUT !--------------------- %INTEGER I,OPENFLAG,PORTN,F, IFACNO, TYPE %RECORD (BSF) %NAME BSP !RECEIVED OPEN COMMAND OR SINGLE SHOT REQUEST !SEE IF THERE'S A FREE PORT !ALSO CHECK THERE'S NOT A BS OPEN TO THIS DEST,PORT %IF IRCOMM=OPEN %START TYPE=INCOMING CALL %ELSE %IF IRCOMM&X'FF00'=SSPREQ %START TYPE=MESSAGE R SWABA(P_MES_A(1), P_MES_LEN-2) P_MES_LEN=P_MES_LEN<<1-4-(IRCOMM&1) %ELSE %RETURN %FINISH %FINISH PORTN=0 %CYCLE I=4,2,BSLIM2-1 BSP==BS(I) %IF BSP_STATE=CLOSED %START PORTN=I >> 1 %ELSE %IF BSP_DEST=ISOURCE %ANDC BSP_DESTPORT=(ITCOMM & X'FFF') %THEN %RETURN %FINISH %REPEAT %IF PORTN#0 %START BSP==BS(PORTN<<1) F=0 IFACNO=P_MES_A(0) %IF 0<=IFACNO<=MAX FACILITY %THEN F=FACILITY(IFACNO) !F=TASK NUMBER OF BSP OWNER !IF MESSAGE THEN SET PORTN TO 0, THIS IS STORED !IN SEQ IN THE BS RECORD AND USED AS A REPLY PORT !ON OPENACK %IF TYPE=MESSAGE R %THEN PORTN=0 INIT P REC(BSP, PORTN, OPEN INPUT, 0, F, %C ISOURCE, ITCOMM & X'FFF') BSP_BUF==P_MES; !SAVE BUFFER TO SEND OPENACK P_MES==NIL; !DON'T RELEASE BUFFER %IF F#0 %START OP_S1=IFACNO OP_LEN=ISOURCE OP_MES==BSP_BUF SEND(BSP, TYPE) %ELSE SEND OPENACK(BSP, 1) CLEARBSPORT(BSP) %FINISH %FINISH %END; !DO OPEN REQUEST %ROUTINE DO OPEN ACK !--------------------- %RECORD (MEF) %NAME MES MES==P_MES %IF TBSP_STATE=OPEN MESS %START; !ACK OF MESSAGE OP_S1=0 %IF MES_A(0)#0 %THEN OP_S1=1; !FAILED OP_MES==MES; !PASS BUFFER UP P_MES==NIL SEND(TBSP, MESSAGE REPLY) CLEARBSPORT(TBSP) %RETURN %FINISH %IF TBSP_STATE#OPENING %OR MES_LEN<2 %START ERROR(6,ISOURCE) %RETURN %FINISH %IF MES_A(0)#0 %START; !FAIL FLAG ON OPENACK OPENFAILED(TBSP) %ELSE INITPORT(TBSP_NUMBER<<1,TBSP_REPLY,ISOURCE,ITCOMM&X'FFF') SEND TO RING(XRDY, RBSP) RBSP_STATE=ESENT RBSP_TOUT=TIME OP_S1=0 SEND(TBSP, OPEN REPLY B) %FINISH %END %ROUTINE OPEN FAILED(%RECORD (BSF) %NAME BSP) !-------------------------------------------- OP_S1=1; !FAILED FLAG SEND(BSP, OPEN REPLY B) CLEARBSPORT(BSP) %END %ROUTINE ERROR( %INTEGER N, SOURCE) !------------------------------------- PRINTSTRING("*********** ERROR-") WRITE(N, 3); WRITE(SOURCE,3) NEWLINE !SEND PON TO RING SER TO FORCE OUTPUT OF TRACE BUFFER OP_SER=RING SER OP_REPLY=OWN ID OP_FN=OUTPUT TRACE ! PONT(OP) PON(OP) %END %ROUTINE INIT P REC( %RECORD (BSF) %NAME BSP, %C %INTEGER SEQ,STATE,TOUT,REPLY,DEST,DESTPORT) !----------------------------------------------------------------- !INITIALISE ONE RECORD OF THE BYTE STREAM PAIR BSP_SEQUENCE=SEQ BSP_CLOSEFLAG=0 BSP_STATE=STATE BSP_TOUT=TOUT BSP_DEST=DEST BSP_REPLY=REPLY BSP_DESTPORT=DESTPORT BSP_BUF==NIL BSP_BUFQ_LINK==NIL %END %ROUTINE INIT PORT( %INTEGER I, REPLY, DEST, DESTPORT) !--------------------- !INITIALISE RECEIVER AND TRANSMITTER DATA FOR PORT I !TRANSMITTER INIT P REC(BS(I), X'F', IDLE, (TIME+20) ! 1, %C REPLY, DEST, DESTPORT) !RECEIVER INIT P REC(BS(I+1), 0, NESENT, 0, %C REPLY, DEST, DESTPORT) %END; !INITPORT %ROUTINE DO I RDY !--------------------- %INTEGER SQ,SQIN; !SEQUENCE NUMBERS !READY COMMAND HAS BEEN INPUT !CHECK SEQUENCE NUMBER SQ=TBSP_SEQUENCE SQIN=IRCOMM >> 8 &X'F' %IF (SQ+1)&X'F'=SQIN %START %IF TBSP_STATE=ESENT %START !RDY SIGNALS ACK OF PREVIOUS DATA -RELEASE BUFFER ETC. DO DATA ACK; %FINISH %IF TBSP_STATE=ESENT %OR TBSP_STATE=IDLE %START TBSP_SEQUENCE=SQIN; !INCREMENT SEQUENCE !REPLY 'DATA' OR 'NODATA' DEPENDING ON WHETHER BUFQ IS NIL OR NOT TBSP_BUF==TBSP_BUFQ_LINK %UNLESS TBSP_BUF==NIL %THEN TBSP_BUFQ_LINK==TBSP_BUF_LINK TSEND(TBSP) %ELSE ERROR(1, ISOURCE) %FINISH; !IGNORE IT IF STATE ILLEGAL %ELSE %IF SQ=SQIN %START !GOT REPEATED RDY - NEED TO RETRANSMIT %IF TBSP_STATE=ESENT %OR TBSP_STATE=NESENT %START TBSP_TOUT=0 TSEND(TBSP) %IF TBSP_STATE=ESENT %START PRINTSTRING("RETRANSMIT TO "); WRITE(ISOURCE,3) NEWLINE %FINISH %ELSE ERROR(2, ISOURCE) %FINISH %ELSE ERROR(3, ISOURCE) %FINISH %FINISH %END; !DO I RDY %ROUTINE DO I NOTRDY !--------------------- %INTEGER SQ,SQIN; !SEQUENCE NUMBERS !ACKNOWLEDGEMENT OF DATA SQ=TBSP_SEQUENCE SQIN=IRCOMM>>8&X'F' %IF (SQ+1)&X'F'=SQIN %START %IF TBSP_STATE=ESENT %START DO DATA ACK; !RELEASE BUFFERS ETC. TBSP_STATE=IDLE %FINISH %FINISH %END; !DO I NOTRDY %ROUTINE DO DATA ACK !--------------------- !RELEASE BUFFERS, AND RESET THE TIMEOUT %IF TBSP_BUF==NIL %START !SEE IF CLOSE REQUEST ACKNOWLEDGED %IF TBSP_CLOSEFLAG#0 %THEN TBSP_CLOSEFLAG=2 %ELSE SEND(TBSP, OUTPUT DONE) FREEBUFFER(TBSP_BUF) TBSP_BUF==NIL %IF TBSP_FAULTCOUNT>0 %THENC TBSP_FAULTCOUNT=TBSP_FAULTCOUNT-1 %FINISH TBSP_TOUT=0 %END; !DO DATA ACK %ROUTINE DO I DATA !--------------------- %INTEGER I,SQIN; !SEQUENCE NUMBER OF INPUT %RECORD (MEF) %NAME BUF !DATA HAS BEEN INPUT BUF==P_MES SQIN=ITCOMM>>8&X'F' %IF RBSP_SEQUENCE=SQIN %AND ( RBSP_STATE=ESENT %OR %C RBSP_STATE=IDLE) %START !SIGNAL LINE INPUT TO HIGHER LEVEL OP_MES==BUF P_MES==NIL; !BUFFER NOT TO BE RELEASED !SWAB THE DATA BYTES SWABA(BUF_A(0), BUF_LEN-1) !CONVERT BCOUNT FROM HEADER PACKET TO BYTE LENGTH BUF_LEN=(BUF_LEN << 1) -2 -(ITCOMM & 1) SEND(RBSP, INPUT DONE) !SET NEW SEQUENCE NUMBER RBSP_SEQUENCE=(SQIN+1)&X'F' !AT THIS POINT SHOULD REPLY NOTRDY AND WAIT FOR HIGHER LEVEL TO !PROCESS BUFFER AND GIVE INPUT ENABLE AND THEN SEND RDY. IN FACT !WE PRETEND TO SEND THE NOTRDY AND HOPE THE HIGHER LEVELS !RESPOND BEFORE THE DATA GETS RETRANSMITTED . IF IT DOES THEN !A NOTRDY IS SENT (SEE BELOW). RBSP_STATE=NESENT RBSP_TOUT=0 %IF RBSP_FAULTCOUNT>0 %THENC RBSP_FAULTCOUNT=RBSP_FAULTCOUNT-1 %IF ITCOMM & CLOSEREQ # 0 %START RBSP_CLOSEFLAG=1 SEND(RBSP, CALL CLOSED) SEND TO RING(XNOTRDY, RBSP); !ACK OF CLOSE REQ %FINISH %ELSE %IF RBSP_SEQUENCE=((SQIN+1)&X'F') %START !REPEATED DATA REQUEUE RDY OR NOTRDY %IF RBSP_STATE=ESENT %START SEND TO RING(XRDY, RBSP) RBSP_TOUT=TIME %ELSE %IF RBSP_STATE=NESENT %START SEND TO RING(XNOTRDY, RBSP) %ELSE ERROR(5, ISOURCE) %FINISH %FINISH %ELSE ERROR(4, ISOURCE) %FINISH %FINISH %END; !DO I DATA %ROUTINE DO I NODATA !--------------------- %INTEGER SQIN !NODATA RESPONSE INPUT SQIN=ITCOMM>>8&X'F' %IF RBSP_SEQUENCE=SQIN %AND RBSP_STATE=ESENT %START ! SET IDLE TIMEOUT TO 30 SECS RBSP_TOUT=TIME+30 %IF RBSP_TOUT=0 %THEN RBSP_TOUT=1 RBSP_STATE=IDLE %FINISH %END; !DO I NODATA %ROUTINE TTIMEDOUT(%RECORD (BSF) %NAME BSP) !------------------------------------------- BSP_TOUT=0 %IF BSP_STATE=OPENING %THEN OPENFAILED(BSP) %AND %RETURN PRINTSTRING("BSP:TIMEOUT DEST=") WRITE(BSP_DEST, 3); NEWLINE FAULT(BSP) %IF BSP_STATE=ESENT %START TSEND(BSP) %FINISH %END %ROUTINE RTIMEDOUT(%RECORD (BSF) %NAME BSP) !------------------------------------------- BSP_TOUT=0 %IF BSP_STATE#IDLE %START PRINTSTRING("BSP:TIMEOUT DEST=") WRITE(BSP_DEST, 3); NEWLINE FAULT(BSP) %FINISH %IF BSP_STATE=IDLE %OR BSP_STATE=ESENT %START SEND TO RING(XRDY, BSP) BSP_STATE=ESENT BSP_TOUT=TIME %FINISH %END %ROUTINE SEND TO RING(%INTEGER FN, %RECORD (BSF) %NAME BSP) !------------------------------------------------------------ OP_SER=RING SER; OP_REPLY=OWN ID OP_FN=FN OP_PORT=BSP_NUMBER; %IF FN&COMMAND MASK>= XRDY %START OP_LEN=BSP_DEST OP1_LPORT=BSP_DESTPORT OP_S1=BSP_SEQUENCE %FINISH ! PONT(OP) PON(OP) %END %ROUTINE TSEND(%RECORD (BSF) %NAME BSP) !--------------------- !SEND TRANSMITTER COMMAND (DATA OR NODATA) , IF DATA !THEN CALCULATE THE LENGTH OF THE TRANSFER FROM BUF_LEN %RECORD (MEF) %NAME M M==BSP_BUF %IF M==NIL %START !SEND NODATA %IF BSP_CLOSEFLAG=0 %START SEND TO RING(XNODATA, BSP) BSP_STATE=NESENT BSP_TOUT=0 %ELSE !IF CLOSEREQ HAS BEEN ACKNOWLEDGED THEN DON'T !SEND IT AGAIN %IF BSP_CLOSEFLAG=2 %THENRETURN SEND TO RING(XCLOSEREQ, BSP) BSP_STATE=ESENT BSP_TOUT=TIME %FINISH %ELSE BSP_STATE=ESENT M_ADDRESS=BSP_DEST M_PORT=BSP_DESTPORT M_RCOMM=0 M_TCOMM=BSP_SEQUENCE<<8 + DATA + (M_TCOMM&1) OP_MES==M !TRANSMIT DATA WITH BUFFER NOT RELEASED AND NO !NOTIFICATION AT EOT (UNLESS IT TIMEOUTS) SEND TO RING(XDATA, BSP) BSP_TOUT=TIME %FINISH %END; !TSEND %ROUTINE INITIALISE !------------------ %INTEGER I %RECORD (BSF) %NAME BSP PP==P OP3==OP OP1==OP !REST OF DATA INITIALISED TO 0 %CYCLE I=2,1,BSLIM2 BSP==BS(I) CLEARBSPORT(BSP) BSP_NUMBER=I>>1 %REPEAT %END; !INITIALISE %ROUTINE DORESET !-------------- DOCLOSE %END %ROUTINE DOCLOSE !-------------- %INTEGER N N=TBSP_NUMBER %IF CLOSEABLE(TBSP_STATE)=0 %START FINISHCLOSE(N) %ELSE %IF TBSP_CLOSEFLAG=2 %THEN FORCECLOSE(N,CALL CLOSED) %ELSEC FORCECLOSE(N, CALL ABORTED) FINISHCLOSE(N) %FINISH %END %ROUTINE DOWN(%RECORD (BSF) %NAME BSP, %INTEGER TYPE) !!---------------------------- OP_S1=BSP_DEST SEND(BSP, TYPE) %END %ROUTINE FREEBUFFER(%RECORD (MEF) %NAME MES) !!-------------------------------------------- %RECORD (PE) P P_SER=BUFFER MANAGER; P_REPLY=OWN ID P_FN=RELEASE BUFFER; P_MES==MES ! PONT(P) PON(P) %END %ROUTINE SEND OPENACK(%RECORD (BSF) %NAME BSP, %INTEGER SUFLAG) !-------------------------------------------------------------- ! BUFFER POINTER SAVED IN BSP_BUF %RECORD (MEF) %NAME MES MES==BSP_BUF BSP_BUF==NIL MES_ADDRESS=BSP_DEST MES_LEN=2 MES_PORT=BSP_DESTPORT MES_RCOMM=OPENACK MES_TCOMM= BSP_SEQUENCE; !REPLY PORT SAVED HERE(=0 IF MESSAGE RESP) MES_A(0)=SUFLAG OP_MES==MES SEND TO RING(XDATA + RELEASE FLAG, BSP) %END %ROUTINE FAULT(%RECORD (BSF) %NAME BSP) !-------------------------------------- %INTEGER I %IF BSP_STATE=OPEN MESS %THEN CLEARBSPORT(BSP) %AND %RETURN %IF BSP_STATE=CLOSING %THENC FINISHCLOSE(BSP_NUMBER) %AND %RETURN I=BSP_FAULTCOUNT %IF I>FAULTLIMIT %START FORCECLOSE(BSP_NUMBER, CALL ABORTED) %ELSE BSP_FAULTCOUNT=I+1 %FINISH %END %ROUTINE QPUSH(%RECORD (MEQF) %NAME Q, %RECORD (MEF) %NAME BUF) !------------------------------------------------------------- %RECORD (MEF) %NAME P, P ON %IF Q_LINK==NIL %START Q_LINK==BUF %ELSE P==Q_LINK; P ON==P_LINK %WHILE %NOT P ON== NIL %CYCLE P==P ON P ON==P_LINK %REPEAT P_LINK==BUF %FINISH BUF_LINK==NIL %END %ROUTINE FORCECLOSE(%INTEGER PORT, TYPE) !------------------------------------------- %RECORD (BSF) %NAME BSP BSP==BS(PORT << 1) %IF BSP_STATE=OPEN INPUT %OR BSP_STATE=OPEN MESS %THEN CLEARBSPORT(BSP) %IF CLOSEABLE(BSP_STATE) = 0 %THEN %RETURN %IF TYPE#0 %THEN DOWN(BSP, TYPE) STARTCLOSE(BSP); BSP==BS(PORT <<1 +1) STARTCLOSE(BSP); !SEND CLOSE TRANSFER SEND TO RING(XCLOSE, BSP) BSP_TOUT=TIME %END %ROUTINE STARTCLOSE(%RECORD (BSF) %NAME BSP) !----------------------------------------------------------- %RECORD (MEF) %NAME BUF,P BSP_STATE=CLOSING BSP_TOUT=0 !RETURN ACTIVE OUTPUT BUFFER (IF ANY) BUF==BSP_BUF BSP_BUF==NIL %UNLESS BUF==NIL %START FREEBUFFER(BUF) %FINISH BUF==BSP_BUFQ_LINK %WHILENOT BUF==NIL %CYCLE P==BUF_LINK FREEBUFFER(BUF) BUF==P %REPEAT BSP_BUFQ_LINK==NIL %END %ROUTINE FINISHCLOSE(%INTEGER PORT) !------------------------------------ %RECORD (BSF) %NAME BSP BSP==BS(PORT<<1) CLEARBSPORT(BSP) CLEARBSPORT(BS(PORT<<1+1)) %END %ROUTINE CLEARBSPORT(%RECORD (BSF) %NAME BSP) !----------------------------------------- BSP_TOUT=0 BSP_CLOSEFLAG=0 BSP_DEST=0 BSP_FAULTCOUNT=0 BSP_REPLY=0 BSP_STATE=CLOSED %END %ROUTINE SEND(%RECORD (BSF) %NAME BSP, %INTEGER FN) !-------------------------------------------------- %IF BSP_REPLY # 0 %START OP_SER=BSP_REPLY; OP_REPLY=BSP SER OP_FN=FN; OP_PORT=BSP_NUMBER %IF MON<0 %START PRINTSTRING("RO"); MONP(OP) %FINISH ! PONT(OP) PON(OP) %FINISH %END %ROUTINE SWABA(%INTEGERNAME ADDR,%INTEGER COUNT) !------------------------------------ !SWAB THE BYTES IN THE COUNT WORDS ADDRESSED BY ADDR *K'016501'; *K'000006'; !MOV ADDR,R1 *K'016500'; *K'000004'; !MOV COUNT,R0 *K'000321'; !LOOP: SWAB (R1)+ *K'005300'; !DEC R0 *K'003375'; !BGT LOOP %END %ROUTINE MONP(%RECORD (PE) %NAME P) !---------------------------------- %RECORD (MEF) %NAME BUF %INTEGER I,C WRITE(P_SER,3) WRITE(P_REPLY,3) WRITE(P_FN,3) WRITE(P_PORT,3) WRITE(P_LEN,3) WRITE(P_S1,3) NEWLINE %IF (P_SER=BSP SER %AND P_FN=PUT OUTPUT) %ORC P_FN=INPUT DONE %START BUF==P_MES %CYCLE I=0,1,BUF_LEN-1 C=BUF_A(I) WRITE(C,3) %IF C<32 %THEN C=' ' PRINTSYMBOL(C) %REPEAT %FINISH %END !%ROUTINE PONT(%RECORD (PE) %NAME P) ! PTRACE(PTP)=P ! PTP=PTP+1 ! %IF PTP>300 %THEN PTP=0 !%END %END %ROUTINE GATE(%RECORD (PF) %NAME PQ) ! FILE 'FEP_GATE5' %CONSTSTRING (7) VSN = "VSN005C" !**************************** !* EMAS-2900 FEP GATE * !* FILE: GATE5 * !* DATE: 10.SEP.80 * !**************************** !! STACK SIZE = 300 %RECORDFORMAT DMF(%INTEGER I) %SYSTEMROUTINESPEC LINKIN(%INTEGER SERVICE) %SYSTEMROUTINESPEC ALARM(%INTEGER TICKS) %CONSTRECORD (DMF) %NAME NULL = 0 %OWNINTEGER OWN TERM = 72; ! NETWORK ADDRESS %OWNINTEGER SUBATTACH FLAG = 74 %CONSTINTEGER KENT = 0; ! KENT=1 - NO NODE IN NET %CONTROL K'100001' %RECORDFORMAT NSI1F(%BYTEINTEGER FN, SUFL, ST, SS, SN, DN, DT, %C DS, FLAG, UFL, LEN1, DATA, %BYTEINTEGERARRAY A(2:238)) %RECORDFORMAT NSI2F(%BYTEINTEGER FN, SUFL, ST, SS, FLAG, UFLAG %C , FLEN, FDATA, FD2, FD3, FD4) %RECORDFORMAT NSI3F(%BYTEINTEGERARRAY A(0:100)) %RECORDFORMAT MEF(%RECORD (MEF) %NAME LINK, %C %BYTEINTEGER LEN, TYPE, %RECORD (NSI1F)NSL) %RECORDFORMAT PE(%BYTEINTEGER SER, REPLY, %C FN, PORT, %RECORD (MEF) %NAME MES, %BYTEINTEGER LEN, S1) %RECORDFORMAT P2F(%BYTEINTEGER SER, REPLY, FN, PORT, %C FACILITY, FLAG, NODE, TERM) %RECORDFORMAT QF(%RECORD (MEF) %NAME E) %RECORDFORMAT LINE STATEF(%INTEGER NODE STATE, ATT FLAG, %C LINE NO, SER NO, NODE NUMBER) %RECORDFORMAT PORTF(%BYTEINTEGER STATE, OWNER PORT, %C NODE, TERM, FL, RL, %INTEGER NO, %C OWNER, MAX FL, %RECORD (QF) OUT Q, %RECORD (LINE STATEF) %NAME LN) !********************************************** !* NSI FUNCTIONS FRON NODE * !********************************************** %CONSTINTEGER ATTACH = 1; ! NSI FN VALUES %CONSTINTEGER SEND MESS = 2 %CONSTINTEGER CONNECT = 3 %CONSTINTEGER SEND BLOCK = 4 %CONSTINTEGER STATUS = 5 %CONSTINTEGER NIF = 6 %CONSTINTEGER REMOVE = 7 %CONSTINTEGER SUBATTACH = 255 %CONSTINTEGER REPLY = 128; ! ADDED TO ABOVE FOR REPLY %CONSTINTEGER ATTACH R = 8; ! 'REAL' VALUE IS ATTACH+128 %CONSTINTEGER SEND MESS R = 9 %CONSTINTEGER CONNECT R = 10 %CONSTINTEGER SEND BLOCK R = 11 %CONSTINTEGER STATUS R = 12 %CONSTINTEGER NIF R = 13 %CONSTINTEGER REMOVE R = 14 !************************************************************ !* UPPER LEVEL (ITP&RJE) HANDLER MESSAGES TO GATE !************************************************************ %CONSTINTEGER ENABLE FACILITY = 1; ! ENABLE THE FACILITY %CONSTINTEGER DISABLE FACILITY = 2; ! THE REVERSE %CONSTINTEGER CALL REPLY = 3; ! REPLY TO A 'CALL CONNECT' %CONSTINTEGER ENABLE INPUT = 4; ! ALLOW A BLOCK TO BE READ %CONSTINTEGER PUT OUTPUT = 5; ! SEND A BLOCK OF OUTPUT %CONSTINTEGER CLOSE CALL = 6; ! TERMINATE A CALL %CONSTINTEGER ABORT CALL = 7; ! ABORT THE CALL %CONSTINTEGER OPEN CALL = 8; ! OPEN A VIRTUAL CIRCUIT %CONSTINTEGER OPEN MESSAGE = 9; ! SEND A MESSAGE !******** FROM BUFFER MANAGER ****** ! %CONSTINTEGER BUFFER HERE = 0 !********************************************************** !* MESSAGES FROM GATE TO UPPER LEVEL PROTOCOLS !********************************************************** %CONSTINTEGER OPEN CALL REPLY = 1 %CONSTINTEGER INCOMING CALL = 2 %CONSTINTEGER INPUT RECD = 3; ! BLOCK ARRIVED FROM NODE %CONSTINTEGER OUTPUT TRANSMITTED = 4; ! PREPARED TO ACCEPT MORE %CONSTINTEGER CALL CLOSED = 5; ! EITHER END HAS CLOSED DOWN %CONSTINTEGER CALL ABORTED = 6; ! OTHER END HAS ABORTED %CONSTINTEGER OPEN REPLY A = 7 %CONSTINTEGER OPEN REPLY B = 8 %CONSTINTEGER MESSAGE = 9 %CONSTINTEGER MESSAGE REPLY = 10 !********** TO BUFFER MANAGER *********** %CONSTINTEGER REQUEST BUFFER = 0 %CONSTINTEGER RELEASE BUFFER = 1 !************************************************************** !******* CALLS ON LINE (OR PROTOCOL) HANDLER ********* !************************************************************ %CONSTINTEGER LINE INPUT = 1 %CONSTINTEGER LINE OUTPUT = 2 %CONSTINTEGER HELLO = 2; ! IN P_LEN !************************************************************ !********** VARIOUS SERVICE NUMBERS ************* %CONSTBYTEINTEGERNAME OWN ID = K'160030' %CONSTINTEGER GATE SER = 16 %CONSTINTEGER FROM PROT = 10 %CONSTINTEGER BUFFER MANAGER = 17 %CONSTINTEGERNAME PKT = K'100010' %CONSTINTEGERNAME SBR = K'100006' %CONSTINTEGERNAME BYT = K'100004' %CONSTBYTEINTEGERNAME CHANGE OUT ZERO = K'160310' %CONSTINTEGER T3 SER = 21 !********************************************** !* PORT STATES * !********************************************** %CONSTINTEGER DOWN = 0 %CONSTINTEGER CONNECTING = 1 %CONSTINTEGER CONNECTED = 2 %CONSTINTEGER DISCONNECTING = 3 %CONSTINTEGER DISCON 2 = 4 %CONSTINTEGER ABORTING = 5 %CONSTINTEGER CLEARING = 6; ! LINE HAS GONE DOWN !**** REST ARE SUB STATES OF 'AWAITING BUFFER' %CONSTINTEGER PUT READ ON RB = 3 %CONSTINTEGER PUT READ ON LINE 1 RB = 4 %CONSTINTEGER ATTACH RB = 5 %CONSTINTEGER STATUS REPLY RB = 7 %CONSTINTEGER SEND STATUS RB = 8 %CONSTINTEGER SEND BL REPLY RB = 6 %CONSTINTEGER SEND BL REPLY DRB = 9; ! ALSO SET DISCONNECT %CONSTINTEGER SEND BL DRB = 10; ! SEND A BLOCK WITH DISCONNECT %CONSTINTEGER SEND MESSAGE = 11; ! SEND AN NSI MESSAGE %CONSTINTEGER SEND CONNECT = 12; ! SEND AN "NSI" CONNECT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! GENERAL VARIABLES !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! %RECORD (PE) P %RECORD (P2F) %NAME P2 !! %CONSTBYTEINTEGERNAME INT = K'160060' %OWNINTEGER MON = 0; ! MONITORING OFF %OWNINTEGER SBRF = 1; ! REMOVE SBR FLAG %CONSTINTEGER MAXT = 50 %OWNRECORD (PORTF) %NAME PORT %OWNRECORD (PORTF) %ARRAY PORTA(0:MAXT) %OWNINTEGER FORCE DOWN = 0; ! '1' WHEN IN DOWN STATE %RECORD (LINE STATEF) %NAME LN, L0, L1 %RECORD (LINE STATEF) %ARRAY LNA(0:1) !******************************************************** !* FACILITY: CONTAINES EITHER - ZERO - NOT ALLOCATED * !* OR - SER NO OF OWNER PROC * !******************************************************** %CONSTINTEGER FAC MAX = 25 %OWNBYTEINTEGERARRAY FACILITY(0:FAC MAX) = 0(0) !! %PERMROUTINESPEC PUSH(%RECORD (QF) %NAME Q, %RECORD (MEF) %NAME M) !! %PERMRECORD (MEF) %MAPSPEC POP(%RECORD (QF) %NAME Q) %ROUTINESPEC FROM HIGHER LEVEL %ROUTINESPEC DO ATT REM(%INTEGER TYPE, %RECORD (MEF) %NAME MES) %ROUTINESPEC FAULT(%INTEGER TYPE, PORT N) %ROUTINESPEC TO UPPER(%INTEGER CALL, %RECORD (MEF) %NAME MES) %ROUTINESPEC TO NODE(%RECORD (MEF) %NAME MES) %ROUTINESPEC ASK FOR BLOCK(%INTEGER REASON, PORT NO) %RECORD (MEF) %MAPSPEC NODE %ROUTINESPEC BUFFER ARRIVED %ROUTINESPEC TIDY PORTS %ROUTINESPEC FREE BUFFER(%RECORD (MEF) %NAME MES) %ROUTINESPEC NODE MONITOR(%RECORD (NSI3F) %NAME NSA) %RECORDFORMAT R1F(%INTEGER X) %RECORDFORMAT R2F(%RECORD (MEF) %NAME MES) %RECORD (R1F)R1; %RECORD (R2F) %NAME R2 %INTEGER I %RECORD (MEF) %NAME MES %OWNINTEGER TSL, IB, IC, OB, OC CHANGE OUT ZERO = T3 SER; ! SET 'SELECT OUTPUT(0)' TO COMMON R2 == R1 P2 == P MAP VIRT(BUFFER MANAGER, 5, 4) MAP VIRT(BUFFER MANAGER, 6, 5) ! MAP BUF MAN SEG 6 TO SEG 4 PORT == PORTA(1) LINKIN(GATE SER); LINKIN(FROM PROT) P_SER = 0; POFF(P); ! WAIT FOR INSTRUCTIONS OWN TERM = P_FN; SUB ATTACH FLAG = P_PORT ALARM(100) %CYCLE I = 1, 1, MAXT PORT == PORTA(I) PORT_NO = I %REPEAT L0 == LNA(0) L1 == LNA(1) %CYCLE P_SER = 0; POFF(P) %IF 'M' <= INT <='O' %START MON = INT-'O'; INT = 0 %FINISH %IF INT = 'D' %START; ! FORCE DOWN FORCE DOWN = 1 %IF KENT = 0 %START; ! PROPER NODE ASK FOR BLOCK(ATTACH RB, 0) %ELSE PRINTSTRING("GATE CLOSEDOWN ") TIDY PORTS %FINISH LN_ATT FLAG = 0 INT = 0 %FINISH !********************************* !* 1) MESSAGE FROM UPPER LEVEL * !* 2) MESSAGE FROM NODE * !********************************* %IF P_SER = GATE SER %THEN FROM HIGHER LEVEL %IF P_REPLY = BUFFER MANAGER %START BUFFER ARRIVED %ELSE %IF P_SER = OWN ID %START %IF P_REPLY = 0 %START; ! CLOCK TICK ALARM(100); ! 2 SECS %IF INT = 'S' %START SBRF = SBRF!!1; ! CHANGE SBR FLAG INT = 0 %FINISH %IF INT = '?' %START PRINTSTRING("SBRF:"); WRITE(SBRF, 1); NEWLINE %CYCLE I = 0, 1, 1 %IF I = 0 %THEN %C PRINTSTRING("LN0 ") %ELSE PRINTSTRING("LN1 ") LN == LNA(I) %IF LN_ATT FLAG = 0 %THEN PRINTSTRING("DOWN") %C %ELSE PRINTSTRING("ATT ") PRINTSTRING(" to Node") WRITE(LN_NODE NUMBER, 1); NEWLINE %REPEAT PRINTSTRING("Strm State T Line F/B Buff ") %CYCLE I = 1, 1, MAXT PORT == PORTA(I) %IF PORT_STATE # DOWN %START WRITE(I, 2); WRITE(PORT_STATE, 4) WRITE(PORT_TERM, 3) %IF PORT_LN == L0 %THEN PRINTSTRING(" LN0") %C %ELSE PRINTSTRING(" LN1") WRITE(PORT_MAX FL, 3); WRITE(PORT_RL, 1) NEWLINE %FINISH %REPEAT INT = 0 %FINISH TSL = TSL+1 %IF TSL = 15 %START; ! 30 SECS TSL = 0 %IF INT = 'P' %START PRINTSTRING("GATE: I,O") WRITE(IB, 3); WRITE(IC, 4) WRITE(OB, 4); WRITE(OC, 4); NEWLINE IB=0; IC=0; OB=0; OC=0 %FINISH %FINISH %CONTINUE %FINISH %ELSE %IF P_SER = FROM PROT %START; ! MESSAGE FROM PROT HAN LN == LNA(P_PORT) %IF P_FN = LINE INPUT MES == NODE %UNLESS MES == NULL %THEN FREE BUFFER(MES) %ELSE !! LINE OUTPUT %IF P_LEN = HELLO %START LN == LNA(P_PORT); ! ITS LINE NUMBER LN_LINE NO = P_PORT LN_SER NO = P_REPLY ! I = PUT READ ON RB+LN_LINE NO ! ASK FOR BLOCK(I, 0) ! ASK FOR BLOCK(I, 0) ! ASK FOR BLOCK(I, 0) ! ASK FOR BLOCK(I, 0) %CONTINUE %FINISH %IF P_LEN = 1 %START; ! NODE DOWN PRINTSTRING("LINE ") PRINTSYMBOL(LN_LINE NO+'0'); PRINTSTRING(" DOWN ") LN_NODE STATE = 0; LN_ATT FLAG = 0 TIDY PORTS %ELSE !! UP MESSAGE OR WRITE ACK %IF LN_NODE STATE = 0 %START PRINTSTRING("LINE ") PRINTSYMBOL(LN_LINE NO+'0'); PRINTSTRING(" UP ") FORCE DOWN = 0 ASK FOR BLOCK(ATTACH RB, LN_LINE NO) %IF KENT = 0 LN_NODE NUMBER = P_S1 LN_NODE STATE = 1 %FINISH %FINISH %FINISH %FINISH %REPEAT %ROUTINE TO NODE(%RECORD (MEF) %NAME MES) %IF LN_NODE STATE = 0 %START FREE BUFFER(MES); ! NODE IS DOWN %RETURN %FINISH %IF MON # 0 %START SELECT OUTPUT(1) PRINTSTRING('O '); WRITE(MES_LEN, 2); NODE MONITOR(MES_NSL) SELECT OUTPUT(0) %FINISH P_MES == MES; P_LEN = MES_LEN PKT = PKT+1; BYT = BYT+(P_LEN>>2) OB = OB+1; OC = OC+P_LEN !************************************************* !* MESSAGE TO NODE: P_MES POINTS TO HDLC SPACE * !************************************************* P_SER = LN_SER NO; P_REPLY = OWN ID P_FN = LINE OUTPUT PON(P) %END %ROUTINE ASK FOR BLOCK(%INTEGER REASON, PORT NO) %RECORD (PE) P P_SER = BUFFER MANAGER; P_REPLY = OWN ID P_FN = REQUEST BUFFER; P_S1 = REASON; P_PORT = PORT NO P_LEN = 0; ! ASK FOR LONG BLOCK PON(P) %END %RECORD (MEF) %MAP NODE %INTEGER FN, I, TERM, PORT N, DISCON, FAC NO, TYPE %RECORD (NSI1F) %NAME NSL %RECORD (NSI2F) %NAME NSS %RECORD (MEF) %NAME MES %CONSTBYTEINTEGERARRAY VALID(ATTACH:REMOVE R) = 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0 !! A "1" IN VALID SPECIFIES THAT NSS_SS = PORTN %SWITCH SW(0:15) !**************************************************** !* ALL MESSAGES FROM NODE COME TO HERE * !* P_A1 POINTS NO THE NSI HEADER * !* P_A2 IS THE LENGTH OF THE NSI PCKET * !**************************************************** MES == P_MES NSL == MES_NSL; NSS == NSL FN = NSL_FN %IF MON # 0 %START SELECT OUTPUT(1) PRINTSTRING('I '); WRITE(MES_LEN, 2); NODE MONITOR(NSL) SELECT OUTPUT(0) %FINISH IB = IB+1; IC = IC+MES_LEN %IF FN&128 # 0 %THEN FN = FN&127+7 PORT N = NSL_SS; ! PICK UP STREAM AS INDEX PORT == PORTA(PORT N); ! FOR THOSE WHO NEED IT %UNLESS 1<= FN <= 15 %START RUBBISH: FAULT(1, PORT N); NODE MONITOR(NSL) ->FREE %FINISH !! COMPILER FAULT WITH COMPLEX CONDITIO %IF FN = 7 %THEN -> RUBBISH %IF MES_LEN <= 5 %THEN -> RUBBISH %UNLESS 0<=PORT N<=MAXT %OR VALID(FN) = 0 %THEN -> RUBBISH -> SW(FN) SW(ATTACH): -> FAIL %IF KENT = 0 PRINTSTRING("TCP ATTACHED ") LN_ATT FLAG = 1 -> REPLY SW(SEND MESS): TYPE = MESSAGE -> GET SW(CONNECT): TYPE = INCOMING CALL GET: MES_NSL_FN = MES_NSL_FN!128; ! SET THE REPLY BIT FAC NO = MES_NSL_DS; ! GET THE FACILITY NUMBER %IF FAC NO <= FAC MAX %AND FACILITY(FAC NO) # 0 %START; ! ENABLED OK %CYCLE I = 1, 1, MAXT PORT == PORTA(I) %IF PORT_STATE = DOWN %START PORT_STATE = CONNECTING PORT_OWNER = FACILITY(FAC NO) P_LEN = MES_NSL_FLAG; ! PASS FORWARD/REV BUFF LIM P_S1 = MES_NSL_ST; ! PASS TERMINAL NO PORT_TERM = P_S1; ! COPY TO PORT TO UPPER(TYPE, MES) PORT_OUT Q_E == MES; ! RETAIN CONNECT MESSAGE PORT_LN == LN; ! REMEMBER WHICH LINE %RESULT == NULL %FINISH %REPEAT %FINISH !! EITHER FACILITY NOT ENABLED OR NO FREE PORTS MES_NSL_SUFL = 128+8; MES_NSL_LEN1 = 2 MES_NSL_DATA = 'N'; MES_NSL_A(2) = 'O' MES_LEN = 13; ! +2 ????? TO NODE(MES) %RESULT == NULL SW(SEND BLOCK): -> FAIL %UNLESS PORT_STATE > DOWN !! DEAL WITH INCOMING BUFFER ACK %IF NSS_FLAG&X'70'#0 %START I = NSS_FLAG>>4 %IF PORT_RL = 0 %THEN TO UPPER(OUTPUT TRANSMITTED, NULL) PORT_RL = PORT_RL+I !! DISCON 2 STATE ???? %FINISH DISCON = NSS_FLAG&128 TO UPPER(INPUT RECD, MES) %IF DISCON # 0 %START PORT_STATE = DISCONNECTING TO UPPER(CALL CLOSED, NULL) %FINISH %RESULT == NULL SW(STATUS): -> FAIL %UNLESS PORT_STATE > DOWN %IF NSS_FLAG&128 # 0 %START ! DISCONNECT SET DO STATUS: TO UPPER(CALL ABORTED, NULL) %IF PORT_STATE >= DISCONNECTING %THEN %C PORT_STATE = DOWN %ELSE %C PORT_STATE = ABORTING ->FREE %FINISH -> REPLY SW(NIF): PRINTSTRING('GATE> NIF') WRITE(NSL_SS, 2) WRITE(NSL_SUFL, 4); WRITE(NSL_FLAG, 2); WRITE(NSL_UFL, 2); NEWLINE %IF NSL_FLAG&128 # 0 %THEN -> DO STATUS !! WITHOUT DISCONNECT ->FREE SW(ATTACHR): -> FREE %IF NSL_ST = SUB ATTACH FLAG %IF NSL_SUFL # 0 %START ! FAILED DO ATT REM(REMOVE, MES) %RESULT == NULL %FINISH LN_ATT FLAG = 1 PRINTSTRING("ATTACHED OK ") %IF SUBATTACH FLAG#0 %AND LN == L0 %START DO ATT REM(SUBATTACH, MES) %RESULT == NULL %FINISH -> FREE SW(SEND MESSR): SW(CONNECT R): %IF PORT_STATE # CONNECTING %THEN -> FAIL P_S1 = NSL_SUFL %IF FN = SEND MESS R %START P_LEN = PORT_OWNER PORT; ! RETURN USERS INDEX NO TO UPPER(MESSAGE REPLY, MES) !! NB: UPPER MUST FREE 'MES' PORT_STATE = DOWN %RESULT == NULL %FINISH TO UPPER(OPEN REPLY B, NULL) %IF NSL_SUFL # 0 %C %THEN PORT_STATE = DOWN %ELSE PORT_STATE = CONNECTED PORT_RL = NSL_FLAG>>4; ! TECHNICALLY IS FLAG NOT RL(SEE PUT OUTPUT) PORT_MAX FL = (NSL_FLAG>>1)&7; ! SBR REMOVAL CODE PORT_FL = 0; ! PORT_FL CONTAINS THE NO OF UNACK BLOCKS -> FREE SW(SEND BLOCK R): %IF PORT_RL = 0 %THEN TO UPPER(OUTPUT TRANSMITTED, NULL) I = NSS_FLAG>>4 %IF I = 0 %THEN I = 1 PORT_RL = PORT_RL+I %IF PORT_STATE = DISCONNECTING %AND NSS_FLAG&128 # 0 %START TO UPPER(CALL CLOSED, NULL) PORT_STATE = DOWN %FINISH %IF PORT_STATE = DISCON 2 %START; ! WAITING TO SEND DISCONNECT PORT_STATE = DISCONNECTING NSS_FN = 4; NSS_FLAG = 128; MES_LEN = 6 -> SEND TO NODE %FINISH ->FREE SW(STATUS R): -> FAIL %UNLESS PORT_STATE = ABORTING TO UPPER(CALL ABORTED, NULL); ! CONFIRMATION OF ABORT PORT_STATE = DOWN -> FREE SW(NIF R):-> FAIL SW(REMOVE): -> FAIL %IF KENT = 0 FORCE DOWN = 1; ! GET IT TO TIDY PORTS SW(REMOVE R): %IF FORCE DOWN # 0 %START PRINTSTRING("GATE: REMOVED OK ") TIDY PORTS -> FREE %FINISH DO ATT REM(ATTACH, MES) %RESULT == NULL REPLY: NSL_FN = NSL_FN!128 SEND TO NODE: TO NODE(MES) %RESULT == NULL FREE: %RESULT == MES; ! BLOCK IS PASSED BACK FOR ! NEXT READ FAIL: FAULT(100+FN, PORT N) PRINTSTRING("STATE ="); WRITE(PORT_STATE, 1); NEWLINE NODE MONITOR(NSL) %RESULT == MES %END !! %ROUTINE FROM HIGHER LEVEL %RECORD (MEF) %NAME MES %RECORD (NSI2F) %NAME NSS %INTEGER FN, PORT N, FLAG, REASON %SWITCH FUNCTION(ENABLE FACILITY:OPEN MESSAGE) PORT N = P_PORT FN = P_FN %IF PORT N > MAXT %AND FN <= ABORT CALL %THEN %C FAULT(2, PORT N) %AND %RETURN PORT == PORTA(PORT N) LN == PORT_LN; ! PICK UP OUTPUT LINE MES == P_MES; NSS == MES_NSL ->FUNCTION(FN) FUNCTION(ENABLE FACILITY): FACILITY(P_S1) = P_REPLY %RETURN FUNCTION(DISABLE FACILITY): FACILITY(P_S1) = 0 %RETURN FUNCTION(CALL REPLY): ! REPLY TO A 'CONNECT' FLAG = P_S1; ! 0 - REJECT, OTHERWISE NSL_FLAG MES == PORT_OUT Q_E; ! RECOVER CONNECT MESS %IF FLAG&127 = 0 %START; ! FAILED %IF FLAG = 0 %THEN FLAG = 128+8 %ELSE FLAG = 0 MES_NSL_SUFL = FLAG PORT_STATE = DOWN %ELSE MES_NSL_SUFL = 0 MES_NSL_DS = PORT_NO MES_NSL_FLAG = FLAG PORT_RL = FLAG>>1&7 PORT_FL = 0; PORT_MAX FL =FLAG>>4 PORT_STATE = CONNECTED %FINISH TO NODE (MES) %RETURN FUNCTION(ENABLE INPUT): ! ALLOW A BLOCK TO BE READ PORT_FL = PORT_FL+1 !! SBR REMOVAL CODE %IF SBRF#0 %AND PORT_MAX FL>=2 %AND PORT_FL=1 %C %THEN %RETURN REASON = SEND BL REPLY RB; ! REQUEST BUFFER SBR = SBR+1 -> DO REQUEST BUFFER FUNCTION(PUT OUTPUT): ! P_MES TO BE SENT %IF PORT_RL > 0 %START; ! ALLOWED TO SEND ONE PORT_RL = PORT_RL-1 NSS_FN = 4; NSS_SUFL = 0 NSS_ST = OWN TERM; NSS_SS = PORT_NO !! SBR REMOVAL CODE %IF SBRF#0 %AND PORT_MAX FL >=2 %AND PORT_FL#0 %START NSS_FLAG = PORT_FL<<4; PORT_FL = 0 %ELSE NSS_FLAG = 0 TO NODE(MES) %IF PORT_RL > 0 %THEN TO UPPER(OUTPUT TRANSMITTED, NULL) %ELSE !! REVERSE BUFFER LIMIT IS ZERO ???? FAULT(3, PORT N); FREE BUFFER(MES) %FINISH %RETURN FUNCTION(CLOSE CALL): ! CLOSE IT DOWN %IF PORT_STATE = CONNECTED %START %IF PORT_RL = 0 %START; ! UNABLE TO SEND JUST NOW PORT_STATE = DISCON 2; ! HOLD IT %RETURN %FINISH REASON = SEND BL DRB; ! SEND IT NOW %ELSE REASON = SEND BL REPLY DRB; ! REPLY TO A DISCONNECT PORT_STATE = DISCONNECTING ->DO REQUEST BUFFER FUNCTION(ABORT CALL): %IF PORT_STATE = CLEARING %THEN PORT_STATE = DOWN %AND %RETURN ! CAUSED BY LINE DOWN, SO NO STATUS %IF PORT_STATE = CONNECTED %THEN %C REASON = SEND STATUS RB %ELSE %C REASON = STATUS REPLY RB PORT_STATE = ABORTING -> DO REQUEST BUFFER FUNCTION(OPEN MESSAGE): FUNCTION(OPEN CALL): PORT N = 0 %IF L0_ATT FLAG#0 %OR L1_ATT FLAG # 0 %C %START; ! ATTACHED OK %CYCLE PORT N = MAXT, -1, 0 PORT == PORTA(PORT N) %IF PORT_STATE = DOWN %THEN %EXIT %REPEAT %IF PORT N = 0 %START !! FULL UP !! PRINTSTRING("Gate: Ports full ") %ELSE PORT_OWNER = P_REPLY; PORT_OWNER PORT = P_PORT PORT_TERM = P2_TERM; PORT_NODE = P2_NODE PORT_FL = P2_FLAG; PORT_RL = P2_FACILITY %FINISH %FINISH P_SER = P_REPLY; P_REPLY = GATE SER P_S1 = PORT N; ! PASS THE GATE "PORT NO" P_FN = OPEN REPLY A PON(P) %UNLESS FN = OPEN MESSAGE %IF PORT N = 0 %START %IF FN = OPEN MESSAGE %START FLAG = P_PORT; FN = P_SER; ! HOLD FOR 'FREE' FREE BUFFER(MES) P_LEN = FLAG; P_SER = FN P_MES == NULL P_FN = MESSAGE REPLY PON(P) %FINISH %RETURN %FINISH PORT_STATE = CONNECTING; PORT_LN == NULL REASON = SEND CONNECT %IF FN = OPEN MESSAGE %START REASON = SEND MESSAGE PORT_RL = P_MES_NSL_DS; PORT_FL = 0 %FINISH DO REQUEST BUFFER: P_SER = BUFFER MANAGER; P_REPLY = OWN ID P_FN = REQUEST BUFFER P_PORT = PORT_NO; P_S1 = REASON P_LEN = 0; ! REQUEST A BIG BUFFER %IF FN = OPEN MESSAGE %THEN BUFFER ARRIVED %ELSE %C PON(P) %END %ROUTINE TO UPPER(%INTEGER CALL, %RECORD (MEF) %NAME MES) P_SER = PORT_OWNER; P_REPLY = GATE SER P_FN = CALL; P_MES == MES; P_PORT = PORT_NO PON(P) %END %ROUTINE BUFFER ARRIVED %SWITCH SUB STATE(PUT READ ON RB:SEND CONNECT) %RECORD (MEF) %NAME MES %RECORD (NSI2F) %NAME NSS %RECORD (NSI1F) %NAME NSL MES == P_MES NSS == MES_NSL; NSL == NSS PORT == PORTA(P_PORT); ! MAY BE ZERO NSS_SUFL = 0; NSS_ST = OWN TERM; NSS_SS = PORT_NO NSS_FLAG = 0 NSS_FN = SEND BLOCK+REPLY %IF P_S1 > ATTACH RB %THEN LN == PORT_LN ->SUB STATE(P_S1) SUB STATE(PUT READ ON RB): SUB STATE(PUT READ ON LINE 1 RB): P_MES == MES P_SER = LNA(P_S1-PUT READ ON RB)_SER NO; P_REPLY = OWN ID P_FN = LINE INPUT PON(P) %RETURN SUB STATE(ATTACH RB): LN == LNA(P_PORT) %IF FORCE DOWN = 0 %START DO ATT REM(ATTACH , MES) %ELSE DO ATT REM(REMOVE, MES) %FINISH %RETURN SUB STATE(STATUS REPLY RB): NSS_FN = 128+5; ! STATUS REPLY PORT_STATE = DOWN; ! FINISHED NOW -> SET DISC BIT; ! SET DISCONNECT AND SEND IT SUB STATE(SEND STATUS RB): !* ABORT THE CONNECTION NSS_FN = 5; ! STATUS -> SET DISC BIT; ! SET DISCONNECT AND SEND IT SUB STATE(SEND BL REPLY DRB): ! DISCONNECT REPLY NSS_FN = 4+128; ! SEND BLOCK REPLY PORT_STATE = DOWN; ! FINISHED NOW SET DISC BIT: NSS_FLAG = 128; ! SET THE NSI DISCONNECT BIT ->ONW SUB STATE(SEND BL REPLY RB): ! NORMAL REPLY NSS_FN = 128+4 ! SBR REMOVAL CODE %IF PORT_FL = 0 %START; ! ALREADY SENT ! FREE BUFFER(MES); %RETURN %FINISH %IF SBRF = 0 %START; ! NO SBR REMOVAL NSS_FLAG = X'10'; PORT_FL = PORT_FL-1 %ELSE NSS_FLAG = PORT_FL<<4; PORT_FL = 0 %FINISH ONW: NSS_FLEN = 0 MES_LEN = 6 ->SEND IT SUB STATE(SEND BL DRB): ! BLOCK WITH DISCONNECT NSS_FN = 4; ! SEND BLOCK -> SET DISC BIT; ! SET NSI DISCONNECT AND SEND IT SUB STATE(SEND MESSAGE): SUB STATE(SEND CONNECT): NSL_FN = P_S1-SEND CONNECT+3 NSL_SN = 0; NSL_DN = PORT_NODE NSL_DT = PORT_TERM; NSL_DS = PORT_RL; ! TERM+FACILITY NSL_FLAG = PORT_FL MES_LEN = 10 %UNLESS P_S1 = SEND MESSAGE PORT_FL = NSL_FN; ! REMEMBER TYPE %IF (L1_ATT FLAG # 0 %AND NSL_DN = L1_NODE NUMBER) %OR %C L0_ATT FLAG = 0 %THEN LN == L1 %ELSE LN == L0 PORT_LN == LN; ! NEEDED FOR REPLY ETC %IF L0_ATT FLAG=0 %AND L1_ATT FLAG=0 %START PORT_STATE = DOWN NSL_SUFL = X'81' TO UPPER(OPEN REPLY B, MES) %RETURN %FINISH SEND IT: TO NODE(MES) %END %ROUTINE TIDY PORTS %INTEGER I %CYCLE I = 1, 1, MAXT PORT == PORTA(I) %IF PORT_STATE # DOWN %AND PORT_LN == LN %START %IF PORT_STATE = CONNECTING %START %IF PORT_FL = SEND CONNECT %START; ! CONNECT P_S1 = 125; ! LINE DOWN TO UPPER(OPEN REPLY B, NULL) %ELSE; ! SEND MESSAGE P_LEN = PORT_OWNER PORT TO UPPER(MESSAGE REPLY, NULL) %FINISH PORT_STATE = DOWN; ! SHOULD REPLY %ELSE TO UPPER(CALL ABORTED, NULL) %IF DISCONNECTING <= PORT_STATE <= ABORTING %C %OR PORT_STATE = CONNECTING %THEN %C PORT_STATE = DOWN %ELSE %C PORT_STATE = CLEARING %FINISH %FINISH %REPEAT %END %ROUTINE FREE BUFFER(%RECORD (MEF) %NAME MES) P_SER = BUFFER MANAGER; P_REPLY = OWN ID P_FN = RELEASE BUFFER; P_MES == MES PON(P) %END %ROUTINE FAULT(%INTEGER N, PORT N) PRINTSTRING('GATE> FAULT'); WRITE(N, 1) PRINTSTRING(' STRM:'); WRITE(PORT N, 1) %IF LN == NULL %START PRINTSTRING(" LNX ") %ELSE %START %IF LN == L0 %THEN PRINTSTRING(" LN0 ") %C %ELSE PRINTSTRING(" LN1 ") %FINISH %END %ROUTINE DO ATT REM(%INTEGER TYPE, %RECORD (MEF) %NAME MES) %INTEGER TERM, NODE %IF TYPE = SUBATTACH %START TYPE = ATTACH; NODE=0; TERM = SUB ATTACH FLAG %ELSE NODE = OWN TERM; TERM = OWN TERM %FINISH MES_NSL_FN = TYPE MES_NSL_SUFL = 0 MES_NSL_ST = TERM; MES_NSL_SS = 0 MES_NSL_SN = NODE; MES_NSL_DN = NODE MES_NSL_DT = TERM; MES_NSL_DS = 255 MES_NSL_FLAG = 0 MES_LEN = 12 TO NODE(MES) %END %ROUTINE NODE MONITOR(%RECORD (NSI3F) %NAME NSA) %INTEGER I, N, J, K, P P = 11 SPACES(2) !! %IF NSI1_SUFL&X'80'#0 %THEN P=20 %CYCLE I = 0, 1, P N = NSA_A(I) %CYCLE J = 4, -4, 0 K = (N >> J)&15 %IF K > 9 %THEN PRINTSYMBOL(K+'A'-10) %ELSE %C PRINTSYMBOL(K+'0') %REPEAT SPACE %REPEAT NEWLINE %END %END %ENDOFPROGRAM %CYCLE I = 0, 1, P