!******************************** !* EMAS-2900 BSP INTERFACE * !* HANDLER * !* FILE: BSP5S * !* 24:11: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 = 'VSN005C' %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' %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' !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' !FLAG BITS ADDED INTO DATA COMMAND %CONSTINTEGER CONTROL DATA=8 %CONSTINTEGER EXPEDITED DATA=16 %CONSTINTEGER ODD=1 %CONSTINTEGER PUSH DATA=2 %CONSTINTEGER CLOSE REQUEST=4 !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 XEXPRDY=9 %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 RDY COMMAND,GAH, %C %RECORD (QF) BUFQ ) !GAH FIELD JUST USED FOR RECEIVER %CONSTINTEGER INITIALGAH=1; !NO OF RDYS SENT WITHOUT !INPUT ENABLES %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 %CONSTINTEGERNAME PKTS=K'100010' %CONSTINTEGERNAME SBR=K'100006' %CONSTINTEGERNAME BYT=K'100004' %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 %RECORD (R1F)R1; %RECORD (R2F) %NAME R2; %RECORD (R3F) %NAME R3 %RECORD (R4F) %NAME R4 !%ROUTINESPEC PUTTRACE !! %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 PROCESSDATA %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 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) ! %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 !ENABLE PORTS TO RING SERVER OP1_FN=ENABLE PORT OP1_SER=RING SER; OP1_REPLY=OWN ID; OP1_LPORT=1; OP1_HPORT=BSLIMIT ! PONT(OP) PON(OP) 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 %IF INT='T' %START ! PUTTRACE INT=0 %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 ! 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=16; !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 BSP_GAH=BSP_GAH+1 %IF BSP_STATE#NESENT %THEN %RETURN SEND TO RING( BSP_RDY COMMAND, 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 ) PKTS=PKTS+1 BYT=BYT+L !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 PUSH(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 ! 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("BSPS: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 %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)) %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#0 %START %IF IRCOMM&X'F000'=RDY %START DO I RDY %ELSE %IF IRCOMM&X'F000'=NOTRDY %START DO I NOT RDY %ELSE %IF IRCOMM&X'FF00'=RESET %START DO RESET %RETURN %ELSE %IF IRCOMM&X'FF00'=OPENACK %START DOOPENACK %ELSE %IF IRCOMM&X'FF00'=CLOSE %THENC DO CLOSE %RETURN %FINISH %FINISH %FINISH %FINISH %FINISH ! OBEY TRANSMITTER COMMAND %IF ITCOMM & X'F000'=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&X'FF00'=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, 19) 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 SWABA(MES_A(1), MES_LEN-2) MES_LEN=(MES_LEN<<1)-4-IRCOMM&1; !CONVERT TO BYTE 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_E==NIL BSP_RDY COMMAND=XRDY; !NORMAL (NOT EXPEDITED) RDY BSP_GAH=INITIALGAH; !NOTE- 1 GETS ADDED TO GAH WHEN PORT IS !SETUP, SEE END OF FNS(CALL REPLY): !IN ROUTINE FROM ABOVE %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 %IF TBSP_BUFQ_E==NIL %THEN TBSP_BUF==NIL %ELSEC TBSP_BUF==POP(TBSP_BUFQ) 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 OP_SER=RING SER; OP_REPLY=OWN ID OP_FN=OUTPUT TRACE %IF ISOURCE=30 %THENC PON(OP) %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 !SET NEW SEQUENCE NUMBER RBSP_SEQUENCE=(SQIN+1)&X'F' RBSP_TOUT=0 RBSP_STATE=NESENT %IF RBSP_FAULTCOUNT>0 %THENC RBSP_FAULTCOUNT=RBSP_FAULTCOUNT-1 %IF ITCOMM&EXPEDITED DATA#0 %START RBSP_RDY COMMAND=XEXPRDY %ELSE RBSP_RDY COMMAND=XRDY %FINISH %IF ITCOMM & CLOSE REQUEST#0 %START %IF ITCOMM&CONTROL DATA=0 %THEN PROCESS DATA RBSP_CLOSEFLAG=1 SEND(RBSP, CALL CLOSED) SEND TO RING(XNOTRDY, RBSP); !ACK OF CLOSE REQ %ELSE %IF ITCOMM & CONTROL DATA = 0 %START PROCESS DATA %FINISH %IF RBSP_GAH>0 %START SEND TO RING(RBSP_RDY COMMAND, RBSP) RBSP_STATE=ESENT RBSP_TOUT=TIME %ELSE SEND TO RING(XNOTRDY, RBSP) RBSP_STATE=NESENT RBSP_TOUT=0 %FINISH %FINISH %ELSE %IF RBSP_SEQUENCE=((SQIN+1)&X'F') %START !REPEATED DATA REQUEUE RDY OR NOTRDY %IF RBSP_STATE=ESENT %START SEND TO RING(RBSP_RDY COMMAND, 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 PROCESS DATA !---------------------- OP_MES==P_MES P_MES==NIL; !BUFFER TO BE RETAINED !SWAB THE DATA SWABA(OP_MES_A(0), OP_MES_LEN-1) !CONVERT BUFFER LENGTH TO BYTE COUNT OP_MES_LEN=(OP_MES_LEN <<1) - 2 - (ITCOMM & 1) BYT=BYT+OP_MES_LEN PKTS=PKTS+1 SEND(RBSP, INPUT DONE); !SEND MESSGAE UP RBSP_GAH=RBSP_GAH-1 %END %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_FAULTCOUNT=0 %START PRINTSTRING("BSP:T TIMEOUT DEST=") WRITE(BSP_DEST, 3) WRITE(BSP_NUMBER,3) WRITE(BSP_STATE,3) NEWLINE %FINISH 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 %IF BSP_FAULTCOUNT=0 %START PRINTSTRING("BSP:R TIMEOUT DEST=") WRITE(BSP_DEST, 3) WRITE(BSP_NUMBER,3) WRITE(BSP_STATE,3) NEWLINE %FINISH 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 !-------------- %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 %IF BSP_SEQUENCE=0 %START; !MESSAGE RESPONSE MES_LEN=(MES_LEN+1)>>1+2 SWABA(MES_A(1), MES_LEN-2) %ELSE MES_LEN=2 %FINISH 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 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 %WHILENOT BSP_BUFQ_E==NIL %CYCLE FREEBUFFER(POP(BSP_BUFQ)) %REPEAT %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 ! 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 PONT(%RECORD (PE) %NAME P) ! PTRACE(PTP)=P ! PTP=PTP+1 ! %IF PTP>300 %THEN PTP=0 !%END !%ROUTINE PUTTRACE !%RECORD (PE3) %NAME P !%INTEGER I,K ! ! SELECTOUTPUT(1) ! I=PTP ! %CYCLE K=1,1,300 ! I=I-1 ! %IF I<0 %THEN I=300 ! P==PTRACE(I) ! %IF P_SER=0 %THEN %EXIT ! %IF P_SER=BSP SER %OR P_SER=OWN ID %START ! PRINTSTRING(" ") ! WRITE(P_REPLY,3) ! %ELSE ! WRITE(P_SER,3) ! %FINISH ! WRITE(P_FN,3) ! WRITE(P_PORT, 3) ! WRITE(P_B<<8+P_A,6) ! WRITE(P_C,3) ! WRITE(P_D,3) ! NEWLINE ! %REPEAT ! CLOSEOUTPUT ! SELECTOUTPUT(0) ! !%END %ENDOFPROGRAM