!******************************** !* 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 %CONTROL K'100001' %BEGIN %CONSTSTRING (7)VSN = 'VSN004C' %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=30; !NUMBER OF BYTE STREAMS %CONSTINTEGER BSLIM2=61; !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, %INTEGER FLAG) %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 GET BUFFER(%INTEGER PORT) %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 MAP VIRT(BUFFER MANAGER, 6, 5); !AND TO SEG 5 R2 == R1; R3 == R2; R4 == R3 LINKIN(BSP SER) CHANGE OUT ZERO = T3 SER INITIALISE; !INITIALISE DATA STRUCTURES ALARM(100) %CYCLE P_SER = 0; POFF(P) ! CLOCK CALL %IF P_SER = OWN ID %START; %IF P_REPLY=0 %START; !CLOCK CALL ALARM(100) 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+10)!1,%C P_REPLY,P_LEN, 1); !TIMEOUT AFTER 10 SECS 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 GET BUFFER(PORT) %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+2) ! 1 %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&31<=MAX FACILITY %THEN F=FACILITY(IFACNO&31) !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 %INTEGER FLAG MES==P_MES FLAG=MES_A(0) %IF TBSP_STATE=OPEN MESS %START; !ACK OF MESSAGE OP_S1=0 %IF FLAG#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 ITCOMM&X'FFF'=0 %THEN %RETURN; !MESSAGE REPLY!!!!! %IF FLAG#0 %START; !FAIL FLAG ON OPENACK OPENFAILED(TBSP, FLAG & X'FF') %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, %INTEGER FLAG) !-------------------------------------------- %IF FLAG=0 %THEN FLAG=18; !ASSUME OUT OIF ORDER OP_S1=FLAG; !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 PRINTSTRING("BSP:TIMEOUT DEST=") WRITE(BSP_DEST, 3); NEWLINE FAULT(BSP) %IF BSP_STATE=ESENT %START TSEND(BSP) %FINISH %IF BSP_STATE=OPENING %START GET BUFFER(BSP_NUMBER); !SEND OPEN AGAIN %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 GET BUFFER(%INTEGER PORT) !----------------------------------- OP_FN=REQUEST BUFFER; OP_SER=BUFFER MANAGER OP_REPLY=OWN ID; OP_PORT=PORT OP_LEN=0; !LONG BUFFER ! PONT(OP) PON(OP) %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 %IF BSP_STATE=OPENING %START OPEN FAILED(BSP, 18); !OUT OF ORDER %RETURN %FINISH 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 %ENDOFPROGRAM