%SYSTEMROUTINESPEC LINKIN(%INTEGER SER) %SYSTEMROUTINESPEC ALARM(%INTEGER TICKS) %RECORDFORMAT DMF(%INTEGER I) %CONSTRECORD (DMF) %NAME NIL = 0 %CONTROL K'100001' %BEGIN %CONSTSTRING (7)VSN = 'VSN004A' %RECORDFORMAT MEF(%RECORD (MEF) %NAME LINK, %BYTEINTEGER LEN, %C TYPE, %INTEGER ADDRESS,PORT,COMMAND,RPORT,FN, %C %INTEGERARRAY A(0:60) ) ! 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 A,B) !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' ! INCOMING FUNCTION CODES ! ------------------------- !HE FOLLOWING VALUES MAY BE ADDED TO THE OUTPUT CODES %CONSTINTEGER RELEASE FLAG=X'80'; !RELEASE BUFFER AT END OF OUTPUT %CONSTINTEGER TELL FLAG=X'40'; !NOTIFY AT END OF TRANSFER %CONSTINTEGER CS0FLAG=X'20' %CONSTINTEGER COMMAND MASK=X'1F'; !TO GET COMMAND CODE %CONSTINTEGER ENABLE PORT=0 %CONSTINTEGER XDATA=1 %CONSTINTEGER SSOUT=2; !SINGLE SHOT OUTPUT %CONSTINTEGER XRDY=3 %CONSTINTEGER XNOTRDY=4 %CONSTINTEGER XNODATA=5 %CONSTINTEGER XCLOSE=6 %CONSTINTEGER XRESET=7 %CONSTINTEGER XCLOSEREQ=8 %CONSTINTEGER DISABLE PORT=15 %CONSTINTEGER OUTPUT TRACE=16; !FORCE OUTPUT OF TRACE BUFFER ! OUTGOING FUNCTION CODES ! ----------------------- %CONSTINTEGER OUTPUT DONE=0 %CONSTINTEGER TRANSFER ERROR=1 %CONSTINTEGER R INPUT DONE=2 %CONSTINTEGER INPUT ERROR=3 %CONSTINTEGER RING DOWN=4 !NAME SERVER FUNCTIONS !----------------------- %CONSTINTEGER LOOKUP=0 %CONSTINTEGER ADDNAME=1 %CONSTINTEGER REMOVENAME=2 %CONSTINTEGER REMOVEALL=3 %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 NAME SER=15 %CONSTINTEGER RING SER = 10 %CONSTINTEGER BUFFER MANAGER = 17 %CONSTINTEGER TIME INT = 0 %CONSTBYTEINTEGERNAME CHANGE OUT ZERO = K'160310' %CONSTINTEGER T3 SER = 21 !************************************************************ %OWNRECORD (PE) P %CONSTINTEGER EOT=4 %OWNRECORD (PE2) %NAME PP %OWNRECORD (PE) %NAME HOLDP %CONSTINTEGER PQMAX=31; !SIZE OF REQUEST QUEUE %CONSTINTEGER NAMES REPLY=0 %CONSTINTEGER NAMES FAIL=1 %OWNRECORD (PE) %ARRAY PQ(0:PQMAX) %OWNINTEGER PQN,PQS,PQE; !PQN=NUMBER OF PS ON QUEUE !PQS=INDEX OF QUEUE START !PQE=INDEX OF QUEUE END %OWNINTEGER REPLY PORT,STATE,T,C; !STATE=IDLE OR BUSY !T COUNTS CLOCK TICKS WHILE BUSY !C=REPETION COUNT %CONSTINTEGER TIMEOUT=2 %CONSTINTEGER MAXRETRIES=3 %CONSTINTEGER IDLE=0 %CONSTINTEGER BUSY=1 %CONSTINTEGER MINRPORT=256; !REPLY PORT LIMITS %CONSTINTEGER MAXRPORT=511 %ROUTINESPEC FROM RING %ROUTINESPEC FROM CLOCK %ROUTINESPEC FROM ABOVE %ROUTINESPEC SENDUP(%INTEGER REPLY,FN) %ROUTINESPEC FREEBUFFER(%RECORD (MEF) %NAME BUF) %ROUTINESPEC START NEW %ROUTINESPEC DO TRANSFER %ROUTINESPEC FINISH REQ(%INTEGER F) %ROUTINESPEC TO RING(%INTEGER F) %ROUTINESPEC SWABA(%INTEGERNAME A,%INTEGER L) PQN=0; PQS=0; PQE=0; !INIT QUEUE POINTERS PP==P LINKIN(NAME SER) MAP VIRT(BUFFER MANAGER, 5, 4) STATE=IDLE !PLUG INTO REPLY PORTS PP_A=MIN RPORT PP_B=MAX RPORT TO RING(ENABLE PORT) REPLY PORT=MIN RPORT ALARM(50) %CYCLE P_SER=0; POFF(P) %IF P_SER=OWN ID %START %IF P_REPLY=RING SER %START FROM RING %ELSE FROM CLOCK %FINISH %ELSE FROM ABOVE %FINISH %REPEAT %ROUTINE FROM RING; !IGNORE ALL BUT INPUT DONES %IF P_FN=R INPUT DONE %START %IF STATE=BUSY %AND P_MES_PORT=REPLY PORT %ANDC P_MES_ADDRESS=X'AA' %AND (P_MES_COMMAND&X'FF00')= %C OPENACK %START; !VALIDATE REPLY %IF (HOLDP_FN=LOOKUP %AND P_MES_LEN>4) %ORC P_MES_LEN>1 %C %START %IF P_MES_LEN>5 %START SWABA(P_MES_A(3),P_MES_LEN-5) P_MES_LEN=P_MES_A(3) &X'FF' %FINISH FINISH REQ(NAMES REPLY) STARTNEW %RETURN %FINISH %FINISH FREEBUFFER(P_MES); !IGNORE INPUT %FINISH %END %ROUTINE FROM CLOCK %IF STATE=BUSY %START T=T+1 %IF T>TIMEOUT %START C=C+1 %IF C>MAXRETRIES %START FINISH REQ(NAMES FAIL) START NEW; !IF QUEUE NOT EMPTY %ELSE DO TRANSFER; !SEND IT AGAIN %FINISH %FINISH %FINISH ALARM(50) %END %ROUTINE FROM ABOVE %IF PQN>=PQMAX %OR P_FN>REMOVEALL %START; !QUEUE FULL FREE BUFFER(P_MES) SENDUP(P_REPLY, NAMES FAIL) %ELSE PQ(PQS)=P PQS=(PQS+1) & PQMAX PQN=PQN+1 %FINISH %IF STATE=IDLE %THEN START NEW %END %ROUTINE SEND UP(%INTEGER REPLY, FN) P_SER=REPLY; P_REPLY=NAME SER P_FN=FN PON(P) %END %ROUTINE FREEBUFFER(%RECORD (MEF) %NAME BUF) %RECORD (PE) P P_SER=BUFFER MANAGER P_REPLY=OWN ID P_MES==BUF P_FN=RELEASE BUFFER PON(P) %END %ROUTINE START NEW %RECORD (MEF) %NAME BUF %INTEGER L,PORT,F %IF PQN>0 %START HOLDP==PQ(PQE) C=1 BUF==HOLDP_MES BUF_ADDRESS=X'AA' BUF_COMMAND=SSPREQ BUF_RPORT=REPLY PORT BUF_FN=0 F=HOLDP_FN %IF F=LOOKUP %OR F=REMOVENAME %START %IF F=LOOKUP %THEN PORT=1 %ELSE PORT=6 L=(BUF_A(0)&X'FF'+2)>>1; !LENGTH OF NAME INCL COUNT SWABA( BUF_A(0), L) %ELSE %IF F=ADDNAME %START L=(BUF_A(3)&X'FF'+2)>>1; !LENGTH OF NAME INCL COUNT SWABA(BUF_A(3), L) L=L+3; !LENGTH OF DATA PART OF SSPREQ PORT=5 %ELSE BUF_A(0)=X'AAAA'; PORT=7 L=1 %FINISH BUF_LEN=L+2 BUF_PORT=PORT DO TRANSFER %FINISH %END %ROUTINE DO TRANSFER STATE=BUSY; T=0 P_MES==HOLDP_MES TO RING(XDATA) %END %ROUTINE FINISH REQ(%INTEGER F) !TRANSFER FINISHED-REMOVE FROM !QUEUE AND REPLY STATE=IDLE PQE=(PQE+1)&PQMAX PQN=PQN-1 FREE BUFFER(HOLDP_MES) REPLY PORT=REPLY PORT+1 %IF REPLY PORT>MAX RPORT %THEN REPLY PORT=MIN RPORT SEND UP(HOLDP_REPLY, F) %END %ROUTINE TO RING(%INTEGER F) P_SER=RING SER; P_REPLY=OWN ID P_FN=F PON(P) %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 %ENDOFPROGRAM