!* !* !* !* TO MAKE A P SERIES COMMS CONTROLLER. !* 1) ENABLE ALL LINES COMMENTED !*P. !* 2) LEAVE ALL REFERENCES TO GPC. !* !* !* !* !* TO MAKE AN S SERIES COMMS CONTROLLER. !* 1) ENABLE ALL LINES COMMENTED !*S. !* 2) CHANGE ALL OCCURENCES OF GPC TO DCU. !* !* !* !* TO COMPILE IN THE STATEMENTS STARTING WITH "?" COMPILE THE FILE !* PRODUCED WITH THE PARM OPTION "PARMX". !* !* !* !* COMMUNICATIONS RECORD FORMAT - EXTANT FROM CHOPSUPE 20A ONWARDS * %RECORDFORMAT COMF(%INTEGER OCPTYPE,IPLDEV,SBLKS,SEPGS,NDISCS, %C DDTADDR,GPCTABSIZE,GPCA,SFCTABSIZE,SFCA,SFCK,DIRSITE, %C DCODEDA,SUPLVN,WASKLOKCORRECT,DATE0,DATE1,DATE2, %C TIME0,TIME1,TIME2,EPAGESIZE,USERS,CATTAD,DQADDR, %C %BYTEINTEGER NSACS,RESV1,SACPORT1,SACPORT0, %C NOCPS,RESV2,OCPPORT1,OCPPORT0, %C %INTEGER ITINT,CONTYPEA,GPCCONFA,FPCCONFA,SFCCONFA, %C BLKADDR,DPTADDR,SMACS,TRANS,%LONGINTEGER KMON, %C %INTEGER DITADDR,SMACPOS,SUPVSN,PSTVA,SECSFRMN,SECSTOCD, %C SYNC1DEST,SYNC2DEST,ASYNCDEST,MAXPROCS,INSPERSEC,ELAPHEAD, %C COMMSRECA,STOREAAD,PROCAAD,SFCCTAD,DRUMTAD,TSLICE,SP0,SP1, %C SP2,SP3,SP4,SP5,SP6,SP7,SP8, %C LSTL,LSTB,PSTL,PSTB,HKEYS,HOOT,SIM,CLKX,CLKY,CLKZ, %C HBIT,SLAVEOFF,INHSSR,SDR1,SDR2,SDR3, %C SDR4,SESR,HOFFBIT,S2,S3,S4,END) %RECORDFORMAT PE(%INTEGER DSERV, SSERV, P1, P2, P3, P4, P5, P6) %RECORDFORMAT PARMF(%INTEGER DSERV, SSERV, P1, P2, P3, P4, P5, P6, %C LINK) !* !*********************************************************************** !* SERVICE NUMBERS AND ACTIVITY NUMBERS * !*********************************************************************** !* %CONSTINTEGER CONNECT = 1 %CONSTINTEGER CONNECT REPLY = 1 %CONSTINTEGER ENABLE = 2 %CONSTINTEGER CLAIM AMT INDEX REPLY = 2 %CONSTINTEGER ENABLE REPLY = 3 %CONSTINTEGER DISABLE = 4 %CONSTINTEGER DISABLE REPLY = 4 %CONSTINTEGER DISCONNECT = 5 %CONSTINTEGER DISCONNECT REPLY = 5 %CONSTINTEGER CONTROL MSG6 = 6 %CONSTINTEGER CONTROL MSG6 REPLY = 6 %CONSTINTEGER CONTROL MSG7 = 7 %CONSTINTEGER CONTROL MSG7 REPLY = 7 %CONSTINTEGER TRANSFER REQUESTED = 10 %CONSTINTEGER PAGE HERE = 11 %CONSTINTEGER TRANSFER COMPLETED = 12 %CONSTINTEGER CALLED = X'80000000' %CONSTINTEGER COMMS COMMAND = X'00370000' %CONSTINTEGER COMMS REPLY = X'00380000' %CONSTINTEGER GPC COMMAND = X'00300000' %CONSTINTEGER CLAIM BLOCK = X'00080001' %CONSTINTEGER BLOCK CLAIMED = COMMS REPLY!CLAIM AMT INDEX REPLY %CONSTINTEGER FREE BLOCK = X'00080002' %CONSTINTEGER CLAIM PAGE = X'00040001' %CONSTINTEGER PAGE CLAIMED = COMMS REPLY!PAGE HERE %CONSTINTEGER FREE PAGE = X'00040002' %CONSTINTEGER INITIALIZE = COMMS COMMAND!X'00000000' %CONSTINTEGER REQUEST TRANSFER = COMMS REPLY!TRANSFER REQUESTED %CONSTINTEGER TRANSFER COMPLETE = COMMS REPLY!TRANSFER COMPLETED %CONSTINTEGER NORMAL TERMINATION = X'00000002' %CONSTINTEGER ATTENTION = X'00000003' %CONSTINTEGER INITIALISE = X'00000004' %CONSTINTEGER ABNORMAL TERMINATION = X'00000005' %CONSTINTEGER GO AHEAD = X'00000006' %CONSTINTEGER SEND CONTROL = X'00000007' %CONSTINTEGER LP SERVICE = X'33' %CONSTINTEGER CR SERVICE = X'34' %CONSTINTEGER CP SERVICE = X'35' %CONSTINTEGER MK1 FE SERVICE = X'39' %CONSTINTEGER LP COMMAND = LP SERVICE<<16 %CONSTINTEGER CR COMMAND = CR SERVICE<<16 %CONSTINTEGER CP COMMAND = CP SERVICE<<16 %CONSTINTEGER MK1 FE COMMAND = MK1 FE SERVICE<<16 %CONSTINTEGER ALLOCATE DEVICE = GPC COMMAND!X'00000004' %CONSTINTEGER LP ALLOCATED = LP COMMAND!CALLED %CONSTINTEGER CR ALLOCATED = CR COMMAND!CALLED %CONSTINTEGER CP ALLOCATED = CP COMMAND!CALLED %CONSTINTEGER MK1 FE ALLOCATED = MK1 FE COMMAND!CALLED %CONSTINTEGER DEALLOCATE DEVICE = GPC COMMAND!X'00000005' %CONSTINTEGER LP DEALLOCATED = LP COMMAND!CALLED %CONSTINTEGER CR DEALLOCATED = CR COMMAND!CALLED %CONSTINTEGER CP DEALLOCATED = CP COMMAND!CALLED %CONSTINTEGER MK1 FE DEALLOCATED = MK1 FE COMMAND!CALLED %CONSTINTEGER EXECUTE CHAIN = GPC COMMAND!X'0000000A' %CONSTINTEGER LP EXECUTED = LP COMMAND!CALLED %CONSTINTEGER CR EXECUTED = CR COMMAND!CALLED %CONSTINTEGER CP EXECUTED = CP COMMAND!CALLED %CONSTINTEGER MK1 FE EXECUTED = MK1 FE COMMAND!CALLED %CONSTINTEGER VIRTUAL = X'81000000' %CONSTINTEGER EMPTY = X'F0F0' %CONSTINTEGER NOT ALLOCATED = X'F0F0F0F0' %CONSTINTEGER EBC NL = 21 %CONSTINTEGER EBC FF = 12 %CONSTINTEGER EBC CR = 13 %CONSTINTEGER EBC MS = 32 !*S%CONSTINTEGER EBC SP = 64 !* ?%EXTERNALINTEGER QUEUED STREAMS = 0; !COUNT OF TIMES WE RAN OUT OF EPAGES ?%EXTRINSICLONGINTEGER KMON; !BIT 2**SNO IS SET WHEN SERVICE SNO IS TO BE MONITORED !* %EXTERNALROUTINESPEC DUMP TABLE(%INTEGER TABLE, ADDRESS, LENGTH) %EXTERNALROUTINESPEC DPON(%RECORDNAME MESS, %INTEGER SECS) %EXTERNALROUTINESPEC PON(%RECORDNAME MESS) %EXTERNALROUTINESPEC PT REC(%RECORDNAME MESS) %EXTERNALROUTINESPEC GPC(%RECORDNAME MESS) %EXTERNALROUTINESPEC OPMESS(%STRING (63) S) %SYSTEMROUTINESPEC MOVE(%INTEGER LENGTH, FROM, TO) %SYSTEMROUTINESPEC ETOI(%INTEGER ADDRESS, LENGTH) %SYSTEMROUTINESPEC ITOE(%INTEGER ADDRESS, LENGTH) %EXTERNALINTEGERFNSPEC REALISE(%INTEGER VIRTUAL ADDRESS) %EXTERNALINTEGERFNSPEC NEW PP CELL %EXTERNALROUTINESPEC RETURN PP CELL(%INTEGER CELL) !* !* !*********************************************************************** !* * !* STREAM TYPES. * !* * !* EVEN STREAMS: INPUT STREAMS * !* ODD STREAMS: OUTPUT STREAMS * !* * !* STREAM STATES. * !* * !* FROM STATE TITLE TO STATE * !* 1-> 0: UNUSED ->2 * !* 3-> 1: DISCONNECTING ->0 * !* 0-> 2: CONNECTING ->3 * !* 2,4,5-> 3: CONNECTED ->1,6 * !* 8-11-> 4: SUSPENDING ->3 * !* 8-11-> 5: ABORTING ->3 * !* 3-> 6: CLAIMING ->7 * !* 6-> 7: ENABLING ->8 * !* 7-> 8: ENABLED ->4,5,9-11 * !* 8-> 9: QUEUED ->4,5,10 * !* 8,9-> 10: PAGING IN ->4,5,11 * !* 8,10-> 11: ACTIVE ->4,5,8,10 * !* * !* * !* STREAM BUFFER MODES. * !* * !* BITS 2**0 TO 2**3 * !* 0: SEQUENTIAL 2: SEQUENTIAL CONTINUATION * !* 1: CIRCULAR * !* * !* BITS 2**4 TO 2**7 * !* 0: ISO 2: BINARY * !* 1: EBCIDIC * !* * !* ADAPTOR TYPES. * !* * !* DEVICE TYPE DEVICE MNEMONIC ADAPTOR NAME * !* 1 PT NOT AVAILABLE * !* 2 PR NOT AVAILABLE * !* 3 CP CP ADAPTOR * !* 4 CR CR ADAPTOR * !* 5 M0 NOT AVAILABLE * !* 6 LP LP ADAPTOR * !* 7 GP NOT AVAILABLE * !* 8 OP NOT AVAILABLE * !* 9 GU NOT AVAILABLE * !* 10 DR NOT AVAILABLE * !* 11 NA NOT AVAILABLE * !* 12 CT NOT AVAILABLE * !* 13 SU NOT AVAILABLE * !* 14 FE MK1 FE ADAPTOR * !* 15 LK NOT AVAILABLE * !* * !* DEVICE NO. * !* * !* CAN CURRENTLY BE IN THE RANGE 0 - 9. * !* WHEN COMBINED WITH AN ADAPTOR TYPE A DEVICE MNEMONIC IS PRODUCED * !* I.E. LP0 TO LP9 OR FE0 TO FE9. * !* * !*********************************************************************** !* !* %RECORDFORMAT SR(%HALFINTEGER STREAM NO, EXTERNAL STREAM NO, %C %BYTEINTEGER STATE, MODE, ADAPTOR NO, DEVICE NO, %C %INTEGER LENGTH, OWNER, CALLER, AMT INDEX, START, CURSOR, LINK) %RECORDFORMAT BR(%INTEGER STREAM NO, EXTERNAL STREAM NO, %C AMT INDEX, OFFSET, LENGTH, REAL ADDRESS, P5, P6, LINK) %RECORDFORMAT COMMS INFF( %C %INTEGER INDEX ADDR, NEXT FREE BUFFER, QUEUED STREAM HEAD, %C QUEUED STREAM TAIL) !* %CONSTINTEGER MAX STREAM = 511;!MAX USERS*2 + MAX RJE STREAMS? !*S%CONSTINTEGER MAX STREAM = 127;!MAX USERS*2 + MAX RJE STREAMS? %OWNHALFINTEGERARRAY STREAM INDEX(0 : MAX STREAM) = %C EMPTY(MAX STREAM+1) %OWNRECORDARRAYFORMAT SARF(0 : 2015)(SR); !MAPPED ONTO PARM TABLE %OWNRECORDARRAYNAME STREAM TAB(SR); !STREAM TABLE ARRAY %OWNRECORDARRAYFORMAT BARF(0 : 2015)(BR); !MAPPED ONTO THE PARM TABLE %OWNRECORDARRAYNAME BUFFER TAB(BR); !BUFFER TABLE ARRAY %OWNRECORDARRAYFORMAT PARF(0 : 2015)(PARMF); !MAPPED ONTO PARM TABLE %OWNRECORDARRAYNAME PARM TAB(PARMF); !PARM TABLE ARRAY %OWNRECORDNAME COM AREA(COMF) %OWNRECORD COMMS(COMMS INFF) !* !* %CONSTINTEGER DRUM UPDATE = 4; !PAGE OUT TYPE %CONSTINTEGER NO DRUM UPDATE = 0; !DITTO !* %CONSTINTEGER BYTE MASK = X'FF' %CONSTINTEGER SHORT MASK = X'FFFF' %CONSTINTEGER TOP SHORT MASK = X'FFFF0000' !* !* STREAM STATES !* %CONSTINTEGER DISCONNECTING = 1; !WAITING ON ADAPTOR ACTION %CONSTINTEGER CONNECTING = 2; !WAITING ON ADAPTOR ACTION %CONSTINTEGER CONNECTED = 3; !WAITING ON USER ACTION %CONSTINTEGER SUSPENDING = 4; !WAITING ON ADAPTOR ACTION %CONSTINTEGER ABORTING = 5; !WAITING ON ADAPTOR ACTION %CONSTINTEGER CLAIMING = 6; !WAITING ON GLOBAL CONTROLLER ACTION %CONSTINTEGER ENABLING = 7; !WAITING ON ADAPTOR ACTION %CONSTINTEGER ENABLED = 8; !WAITING ON USER ACTION %CONSTINTEGER QUEUED = 9; !WAITING ON A FREE EPAGE (BUFFER) %CONSTINTEGER PAGING IN = 10; !WAITING ON GLOBAL CONTROLLER ACTION %CONSTINTEGER ACTIVE = 11; !WAITING ON ADAPTOR ACTION !* !* STREAM BUFFER MODES !* %CONSTINTEGER SEQUENTIAL = 0; !FIRST ENABLE ON A STREAM POSSIBLE SPECIAL ADAPTOR ACTION %CONSTINTEGER CIRCULAR = 1 %CONSTINTEGER SEQUENTIAL CONTINUATION = 2; !A SUBSEQUENT SEQUENTIAL ENABLE NO SPECIAL ACTION !* %CONSTINTEGER ISO = 0 %CONSTINTEGER EBCIDIC = 1 %CONSTINTEGER BINARY = 2 !* !* ADAPTOR TYPES !* %CONSTINTEGER CP = 3 %CONSTINTEGER CR = 4 %CONSTINTEGER LP = 6 %CONSTINTEGER FE = 14 !* !*********************************************************************** !* THE NEXT ARRAY IS A MAPPING FROM ADAPTOR TYPES TO SERVICE NUMBERS * !*********************************************************************** !* %CONSTINTEGERARRAY ADAPT(0 : 15) = %C NOT ALLOCATED(3),CP COMMAND,CR COMMAND,NOT ALLOCATED,LP COMMAND, NOT ALLOCATED(7),MK1 FE COMMAND,NOT ALLOCATED !* !*********************************************************************** !* THE NEXT ARRAY IS A MAPPING FROM STATES TO REPLY ACTIVITIES * !*********************************************************************** !* %CONSTINTEGERARRAY SUB IDENT(0 : ACTIVE) = %C -1,DISCONNECT REPLY<<16,CONNECT REPLY<<16,-1,DISABLE REPLY<<16(2), -1,ENABLE REPLY<<16,-1(4) !* !* %EXTERNALROUTINE COMMS CONTROL(%RECORDNAME MESS) %RECORDSPEC MESS(PE) !* !*********************************************************************** !* * !* AFTER INITIALIZATION, ALL FREE BUFFER RECORDS ARE HELD ON A * !* LINKED LIST, THE FIRST ELEMENT OF WHICH IS POINTED AT BY "NEXT * !* FREE BUFFER". THE MAXIMUM BUFFER (E PAGE) ALLOCATION IS * !* GIVEN BY THE GLOBAL CONTROLLER AT INITIALISATION. THE COMMS * !* CONTROLLER CAN THEN OWN UP TO THIS ALLOCATION OF EPAGES. * !* IF THERE ARE NO FREE BUFFERS, STREAMS REQUIRING A BUFFER ARE * !* HELD ON A LINKED LIST, THE FIRST ELEMENT OF WHICH IS POINTED AT * !* BY "QUEUED STREAM HEAD" AND THE LAST ELEMENT OF WHICH IS POINTED * !* AT BY "QUEUED STREAM TAIL". * !* IF THE LIST IS EMPTY, BOTH THE HEAD AND TAIL POINTERS WILL * !* BE SET TO "EMPTY" (X'F0F0'). * !* SPACE FOR STREAM DESCRIPTORS AND BUFFER DESCRIPTORS IS ALLOCATED * !* DYNAMICALLY BY CLAIMING PARAM CELLS FROM THE DYNAMICALLY EXTENDABLE* !* PARAM TABLE VIA A CALL ON "NEW PP CELL". STREAM DESCRIPTORS ARE * !* ACCESSED INDIRECTLY THROUGH THE ARRAY "STREAM INDEX" BUT BUFFER * !* DESCRIPTORS ARE ACCESSED DIRECTLY. WHEN DESCRIPTORS ARE NO LONGER * !* REQUIRED THE SPACED IS RETURNED TO THE PARAM TABLE VIA A CALL ON * !* "RETURN PP CELL". * !* NOTE: ALL PAGE SHARING AND PAGE RECAPTURE IS HANDLED BY THE * !* GLOBAL CONTROLLER. THE COMMS CONTROLLER ONLY REQUESTS "PAGE INS" * !* AND "PAGE OUTS". IT IS UP TO THE GLOBAL CONTROLLER TO SUPPLY THE * !* LATEST COPY OF THE PAGE AND TO UPDATE THE RELEVANT COPIES. * !* * !*********************************************************************** !* !* %INTEGER STATUS %CONSTINTEGER SUCCESSFUL = 0, UNSUCCESSFUL = 1 !* %RECORDNAME STREAM(SR); %INTEGER STREAM NO %RECORDNAME BUFFER(BR); %INTEGER BUFFER NO !* %INTEGER TEMP, DSERV, DACT, OLD STATE, LINK !* %SWITCH COM(0 : CONTROL MSG7),REP(0 : TRANSFER COMPLETED) !* !* %ROUTINESPEC RELEASE PAGE(%INTEGER DRUM UP) %ROUTINESPEC RELEASE BUFFER(%INTEGER DRUM UP) %INTEGERFNSPEC UNLINK STREAM(%INTEGER STREAM NO) %ROUTINESPEC GET PAGE(%INTEGER STREAM NO) %ROUTINESPEC RELEASE BLOCK !* !* !* !* !*********************************************************************** !* MAIN PROGRAM * !*********************************************************************** !* DSERV = MESS_DSERV !* !** MONITOR !* ? %IF KMON&(LENGTHENI(1)<<(DSERV>>16)) # 0 %START ? PRINT STRING("COMMS CONTROL: ") ? PT REC(MESS) ? %FINISH !* !** INITIALISE !* %IF DSERV = INITIALIZE %START; !PULL OUT INITIALISATION AS A SPECIAL STREAM TAB == ARRAY(MESS_P3,SARF);!ADDRESS SUPPLIED BY GLOBAL CONTROLLER BUFFER TAB == ARRAY(MESS_P3,BARF);!ADDRESS OF PARM ARRAY SUPPLIED BY GLOBAL CONTROLLER PARM TAB == ARRAY(MESS_P3,PARF); !PARM TABLE ARRAY COM AREA == RECORD(X'80000000'+48<<18) COMMS_INDEX ADDR = ADDR(STREAM INDEX(0)) COMMS_QUEUED STREAM HEAD = EMPTY COMMS_QUEUED STREAM TAIL = EMPTY COM AREA_COMMSRECA = ADDR(COMMS) LINK = NEW PP CELL; !GET A BUFFER ENTRY FROM PARAM TABLE COMMS_NEXT FREE BUFFER = LINK; !HEAD OF LIST %CYCLE TEMP = 1,1,MESS_P2; !GET OTHER BUFFERS BUFFER == BUFFER TAB(LINK); !MAP BUFFER BUFFER = 0 BUFFER_STREAM NO = EMPTY %IF TEMP = MESS_P2 %THEN LINK = EMPTY %C %ELSE LINK = NEW PP CELL;!LAST BUFFER? BUFFER_LINK = LINK; !LINK BUFFERS TOGETHER %REPEAT %RETURN %FINISH; !INTIALISATION SEQUENCE !* !** NORMAL ENTRY SEQUENCE AFTER INITIALISATION !* STREAM NO = MESS_P1; !PULL OUT STREAM NUMBER FIRST ALWAYS IN P1 DACT = DSERV&SHORT MASK; !FIND ACTIVITY REQUESTED %IF DSERV&TOP SHORT MASK = COMMS COMMAND %START %IF DACT # CONNECT %START; !NOT A CONNECT STREAM TEMP = STREAM INDEX(STREAM NO) -> NO STREAM %IF TEMP = EMPTY STREAM == STREAM TAB(TEMP); !MAP STREAM TABLE ENTRY STREAM_CALLER = MESS_SSERV; !REMEMBER CALLER %FINISH %ELSE STREAM NO = STREAM NO&1;!MAKE IT ODD OR EVEN -> COM(DACT) %FINISH %ELSE %START TEMP = STREAM INDEX(STREAM NO) %RETURN %IF TEMP = EMPTY; !NOT MUCH ELSE CAN DO STREAM == STREAM TAB(TEMP) STATUS = MESS_P2 -> REP(DACT) %FINISH NO STREAM: MESS_DSERV = MESS_SSERV; !REPLY TO CALLER MESS_SSERV = DSERV MESS_P2 = UNSUCCESSFUL PON(MESS) %RETURN !* !* !* !*********************************************************************** !* * !* THIS SECTION HANDLES: * !* 1). COMMANDS FROM COMMUNICATIONS USERS. * !* 2). REPLIES FROM THE GLOBAL CONTROLLER IN RESPONSE * !* TO CALLS GENERATED BY COMMANDS. * !* 3). REPLIES FROM AN ADAPTOR IN RESPONSE * !* TO CALLS GENERATED BY A COMMAND. * !* * !*********************************************************************** !* !* COM(CONNECT):!** COMMAND: CONNECT STREAM TO COMMUNICATIONS USER %CYCLE STREAM NO = STREAM NO+2,2,MAX STREAM - (1-STREAM NO) -> GOT ONE %IF STREAM INDEX(STREAM NO) = EMPTY %REPEAT -> NO STREAM GOT ONE: STREAM INDEX(STREAM NO) = NEW PP CELL; !GET A STREAM TABLE ENTRY STREAM == STREAM TAB(STREAM INDEX(STREAM NO)) STREAM = 0 STREAM_STREAM NO = STREAM NO STREAM_CALLER = MESS_SSERV STREAM_OWNER = MESS_P2; !HIGH LEVEL CONTROL MESSAGES SENT ON THIS SERVICE STREAM_LENGTH = STREAM NO; !SET FOR REPLIES FROM FRONT END STREAM_CURSOR = MESS_P5; !SET FOR REPLY TO CONNECT ONLY STREAM_ADAPTOR NO = (MESS_P3>>24)&15 %IF ADAPT(STREAM_ADAPTOR NO) = NOT ALLOCATED %START STATUS = UNSUCCESSFUL -> RETURN CELL %FINISH STREAM_DEVICE NO = (MESS_P3>>16)&BYTE MASK STREAM_EXTERNAL STREAM NO = MESS_P3&SHORT MASK STREAM_LINK = EMPTY STREAM_STATE = CONNECTING -> UPDATE ADAPTOR !* !* REP(CONNECT REPLY):!** ADAPTOR REPLY: STREAM CONNECTED %IF STATUS = SUCCESSFUL %START STREAM_STATE = CONNECTED -> REPLY TO CALLER %FINISH %ELSE -> RETURN CELL !* !* COM(ENABLE):!** COMMAND: ENABLE STREAM %IF STREAM_STATE = CONNECTED %START STREAM_STATE = CLAIMING STREAM_MODE = MESS_P4&BYTEMASK STREAM_LENGTH = MESS_P6-1 STREAM_AMT INDEX = NOT ALLOCATED %IF STREAM_MODE = CIRCULAR %START STREAM_START = MESS_P5&SHORT MASK STREAM_CURSOR = MESS_P5>>16 %FINISH %ELSE %START STREAM_START = MESS_P5 STREAM_CURSOR = 0 %FINISH !** CLAIM BLOCK FROM THE GLOBAL CONTROLLER MESS_DSERV = CLAIM BLOCK MESS_SSERV = BLOCK CLAIMED !** P1=STREAM NO, P2=DISC ADDRESS, P3=FLAGS/EPAGES. USER SUPPLIED CANNOT CHECK PON(MESS) %RETURN %FINISH %ELSE STATUS = UNSUCCESSFUL -> REPLY TO CALLER !* !* REP(CLAIM AMT INDEX REPLY):!** GLOBAL CONTROLLER REPLY: BLOCK CLAIMED %IF STATUS <= 0 %START; !BLOCK UNSUCCESSFUL !* 0 CHANGE BLOCK SIZE IN SITU !* -1 NO AMT CELLS !* -2 NOT ENOUGH GARBAGE !* -3 CHANGE BLOCK SIZE WHILE STILL IN USE STREAM_STATE = CONNECTED STATUS = STATUS - 1;!ZERO NORMALLY SUCCESSFUL -> REPLY TO CALLER %FINISH STREAM_AMT INDEX = STATUS<<16 STREAM_STATE = ENABLING -> UPDATE ADAPTOR !* !* REP(ENABLE REPLY):!** ADAPTOR REPLY: STREAM ENABLED %IF STATUS = SUCCESSFUL %START STREAM_STATE = ENABLED %RETURN %IF STREAM_MODE&15 # CIRCULAR %FINISH %ELSE %START STREAM_STATE = CONNECTED RELEASE BLOCK %FINISH -> REPLY TO CALLER !* !* COM(DISABLE):!** COMMAND: DISABLE STREAM (SUSPEND OR ABORT) %IF STREAM_STATE >= ENABLED %START OLD STATE = STREAM_STATE; !REMEMBER STATE STREAM_STATE = MESS_P2; !SET TO SUSPENDING OR ABORTING %RETURN %IF OLD STATE >= PAGING IN; !WAIT FOR COMPLETION OF PAGE IN OR TRANSFER STREAM NO = UNLINK STREAM(STREAM NO) %IF OLD STATE = QUEUED RELEASE BLOCK -> UPDATE ADAPTOR %FINISH %ELSE STATUS = UNSUCCESSFUL -> REPLY TO CALLER !* !* REP(DISABLE REPLY):!** ADAPTOR REPLY: DISABLED STREAM_STATE = CONNECTED STATUS = SUCCESSFUL; !ALWAYS SUCCESSFUL -> REPLY TO CALLER !* !* COM(DISCONNECT):!** COMMAND: DISCONNECT STREAM %IF STREAM_STATE = CONNECTED %START STREAM_STATE = DISCONNECTING -> UPDATE ADAPTOR %FINISH %ELSE STATUS = UNSUCCESSFUL -> REPLY TO CALLER !* !* REP(DISCONNECT REPLY):!** ADAPTOR REPLY: STREAM DISCONNECTED STATUS = SUCCESSFUL; !ALWAYS SUCCESSFUL -> RETURN CELL !* !* COM(CONTROL MSG6):!** COMMAND: SEND HIGH LEVEL CONTROL MESSAGE !* !* COM(CONTROL MSG7): MESS_DSERV = SEND CONTROL!ADAPT(STREAM_ADAPTOR NO) MESS_SSERV = COMMS REPLY!DACT PON(MESS) %RETURN !* !* REP(CONTROL MSG6 REPLY):!** ADAPTOR REPLY: NO REPLY TO HIGH LEVEL CONTROL MESSAGE %RETURN %IF STATUS = SUCCESSFUL; !ONLY NO REPLY IF SUCCESSFULLY SENT !* !* REP(CONTROL MSG7 REPLY):!** ADAPTOR REPLY: REPLY WHEN HIGH LEVEL CONTROL MESSAGE SENT -> REPLY TO CALLER !* !* !* !*********************************************************************** !* * !* THIS SECTION HANDLES: * !* 1). TRANSFER REQUESTS FROM AN ADAPTOR. * !* 2). REPLIES FROM THE GLOBAL CONTROLLER IN RESPONSE * !* TO CALLS GENERATED BY TRANSFER REQUESTS. * !* 3). TRANSFER COMPLETE REPLIES FROM AN ADAPTOR. * !* * !*********************************************************************** !* !* REP(TRANSFER REQUESTED):!** ADAPTOR REQUEST: TRANSFER REQUEST %IF STREAM_STATE = ENABLED %START; !IGNORE IF SUSPENDING OR ABORTING STREAM_CURSOR = MESS_P2&SHORT MASK %C %IF MESS_P2 # 0 %AND STREAM_MODE&15 = CIRCULAR;!ADJUST CURSOR %IF COMMS_NEXT FREE BUFFER = EMPTY %START; !NO BUFFER AVAILABLE ? QUEUED STREAMS = QUEUED STREAMS+1 STREAM_STATE = QUEUED; !SO WAIT. STREAM_LINK = EMPTY %IF COMMS_QUEUED STREAM HEAD = EMPTY %C %THEN COMMS_QUEUED STREAM HEAD = STREAM NO %C %ELSE STREAM TAB(STREAM INDEX(COMMS_ %C QUEUED STREAM TAIL))_LINK = STREAM NO COMMS_QUEUED STREAM TAIL = STREAM NO %FINISH %ELSE %START; !BUFFER AVAILABLE BUFFER NO = COMMS_NEXT FREE BUFFER BUFFER == BUFFER TAB(BUFFER NO) COMMS_NEXT FREE BUFFER = BUFFER_LINK BUFFER_LINK = EMPTY STREAM_LINK = BUFFER NO GET PAGE(STREAM NO) %FINISH %FINISH %RETURN !* !* REP(PAGE HERE):!** GLOBAL CONTROLLER REPLY: CURRENT OWNER'S PAGE HERE %IF STREAM_STATE # PAGING IN %START; !BUFFER DISABLED (SUSPEND OR ABORT) RELEASE BLOCK -> UPDATE ADAPTOR %FINISH OP MESS("COMMS PAGE IN FAILS") %IF MESS_P3 # 0 !* SHOULD DEAL WITH TRANSFER FAILURES HERE? !* P_P3 = 0 OK !* P_P3 = 1 PARITY ERROR !* P_P3 > 1 ZERO PAGE BUFFER TAB(STREAM_LINK)_REAL ADDRESS = STATUS; !REAL PAGE ADDRESS STREAM_STATE = ACTIVE MESS_SSERV = TRANSFER COMPLETE MESS_DSERV = GO AHEAD!ADAPT(STREAM_ADAPTOR NO) MESS_P2 = STREAM_LINK PON(MESS) %RETURN !* !* REP(TRANSFER COMPLETED):!** ADAPTOR REPLY: TRANSFER COMPLETE BUFFER NO = STREAM_LINK BUFFER == BUFFER TAB(BUFFER NO) STREAM_CURSOR = STREAM_CURSOR+MESS_P3; !ADD IN LENGTH TRANSFERED %IF MESS_P3 = BUFFER_LENGTH %OR STREAM_STATE # ACTIVE %START;!END OF BUFFER OR BUFFER DISABLED %IF STREAM_CURSOR = (STREAM_LENGTH+1) %START;!END OF SECTION %IF STREAM_MODE&15 = CIRCULAR %C %THEN STREAM_CURSOR = 0 %C %ELSE STREAM_STATE = SUSPENDING %FINISH %IF STREAM_STATE = ACTIVE %START %IF MESS_P2 # 0 %START; !GET THE NEXT PAGE. RELEASE PAGE(NO DRUM UPDATE); !RELEASE PAGE TO GET ANOTHER GET PAGE(STREAM NO) %RETURN %FINISH %FINISH %ELSE RELEASE BLOCK %FINISH RELEASE BUFFER(DRUM UPDATE) %IF STREAM_LINK # EMPTY -> UPDATE ADAPTOR %IF STREAM_STATE # ACTIVE STREAM_STATE = ENABLED %RETURN !* !* UPDATE ADAPTOR: !SEND LOW LEVEL CONTROL INFO TO THE ADAPTOR MESS = 0 MESS_SSERV = DSERV MESS_DSERV = SEND CONTROL!ADAPT(STREAM_ADAPTOR NO) MESS_P1 = SUB IDENT(STREAM_STATE)!STREAM NO MESS_P2 = STREAM_STATE<<24!STREAM_MODE<<16!STREAM_LENGTH MESS_P3 = STREAM_CURSOR PON(MESS) %RETURN !* !* !* !* RETURN CELL: !* CANNOT USE THE CODE AT REPLY TO CALLER BECAUSE ON A MULTI PROCESSOR !* CONFIGURATION THE RETURNED PARAM CELL COULD BE REUSED MESS_SSERV = DSERV; !REPLY FIRST TO CALLER MESS_DSERV = STREAM_CALLER MESS_P2 = STATUS MESS_P3 = STREAM_OWNER MESS_P4 = STREAM_STATE MESS_P5 = STREAM_CURSOR PON(MESS) RETURN PP CELL(STREAM INDEX(STREAM NO)) STREAM INDEX(STREAM NO) = EMPTY %RETURN REPLY TO CALLER: MESS_SSERV = DSERV MESS_DSERV = STREAM_CALLER MESS_P2 = STATUS MESS_P3 = STREAM_OWNER MESS_P4 = STREAM_STATE MESS_P5 = STREAM_CURSOR PON(MESS) %RETURN !* !* %ROUTINE RELEASE PAGE(%INTEGER DRUM UP) !*********************************************************************** !* * !* SEND A PAGE OUT REQUEST TO THE GLOBAL CONTROLLER. SPECIFYING * !* WHETHER THE DRUM COPY IS TO BE UPDATED, WHETHER THE PAGE HAS BEEN * !* WRITTEN TO AND WHETHER THE PAGE IS TO BE RECAPTURED. * !* NO REPLY IS GIVEN BY THE GLOBAL CONTROLLER * !* BIT SIGNIFICANCE: * !* 2**0 - RECAPTURABLE * !* 2**1 - MAKE NEW * !* 2**2 - DRUM UPDATE * !* 2**3 - WRITTEN TO * !* * !*********************************************************************** %RECORD MESS(PE) MESS = 0 MESS_DSERV = FREE PAGE MESS_SSERV = COMMS REPLY MESS_P1 = BUFFER_AMT INDEX; !INDEX<<16!EPAGE MESS_P2 = (1-(STREAM NO&1))<<3!DRUM UP PON(MESS) %END; !OF ROUTINE RELEASE PAGE !* !* %ROUTINE RELEASE BUFFER(%INTEGER DRUM UP) !*********************************************************************** !* * !* RELEASE A COMMS PAGE FROM ITS ALLOCATION. IF A TRANSFER REQUEST IS * !* QUEUED REQUEST ANOTHER PAGE. * !* * !*********************************************************************** %INTEGER TEMPST NO RELEASE PAGE(DRUM UP) BUFFER_STREAM NO = EMPTY STREAM_LINK = EMPTY %IF COMMS_QUEUED STREAM HEAD # EMPTY %START;!PAGE FRAME REQUIRED TEMPST NO = UNLINK STREAM(COMMS_QUEUED STREAM HEAD) STREAM TAB(STREAM INDEX(TEMPST NO))_LINK = BUFFER NO GET PAGE(TEMPST NO) %FINISH %ELSE %START; !RETURN BUFFER TO FREE LIST BUFFER_LINK = COMMS_NEXT FREE BUFFER COMMS_NEXT FREE BUFFER = BUFFER NO %FINISH %END; !OF ROUTINE RELEASE BUFFER !* !* %INTEGERFN UNLINK STREAM(%INTEGER TEMPST NO) !*********************************************************************** !* * !* REMOVE A QUEUED TRANSFER FROM THE LINKED LIST * !* * !*********************************************************************** %INTEGER STREAM ID, STREAM LINK, LINK %RECORDNAME TEMPST(SR) LINK = STREAM TAB(STREAM INDEX(TEMPST NO))_LINK STREAM TAB(STREAM INDEX(TEMPST NO))_LINK = EMPTY %IF COMMS_QUEUED STREAM HEAD = TEMPST NO %START COMMS_QUEUED STREAM HEAD = LINK COMMS_QUEUED STREAM TAIL = EMPTY %C %IF COMMS_QUEUED STREAM HEAD = EMPTY %FINISH %ELSE %START STREAM LINK = COMMS_QUEUED STREAM HEAD %UNTIL STREAM LINK = TEMPST NO %CYCLE STREAM ID = STREAM LINK TEMPST == STREAM TAB(STREAM INDEX(STREAM ID)) STREAM LINK = TEMPST_LINK %REPEAT TEMPST_LINK = LINK COMMS_QUEUED STREAM TAIL = STREAM ID %C %IF COMMS_QUEUED STREAM TAIL = TEMPST NO %FINISH %RESULT = TEMPST NO %END; !OF INTEGERFN UNLINK STREAM !* !* %ROUTINE GET PAGE(%INTEGER TEMPST NO) !*********************************************************************** !* * !* CALCULATE THE NEXT PAGE REQUIRED AND REQUEST IT FROM THE GLOBAL * !* CONTROLLER. * !* * !*********************************************************************** %RECORD MESS(PE) %RECORDNAME TEMPST(SR) %INTEGER EPAGE, LENGTH, OFFSET, ESIZE TEMPST == STREAM TAB(STREAM INDEX(TEMPST NO)) TEMPST_STATE = PAGING IN ESIZE = COM AREA_EPAGESIZE<<10; !CALCULATE THE EPAGE SIZE IN BYTES OFFSET = TEMPST_CURSOR+TEMPST_START; !OFFSET IN THE FILE SECTION EPAGE = OFFSET//ESIZE; !CALCULATE IN WHICH PAGE OFFSET = OFFSET-EPAGE*ESIZE; !OFFSET IN PAGE LENGTH = (TEMPST_LENGTH+1)-TEMPST_CURSOR; !CALCULATE LENGTH LENGTH = ESIZE-OFFSET %IF OFFSET+LENGTH > ESIZE;!LENGTH WITHIN PAGE BUFFER_STREAM NO = TEMPST NO BUFFER_EXTERNAL STREAM NO = TEMPST_EXTERNAL STREAM NO BUFFER_AMT INDEX = TEMPST_AMT INDEX!EPAGE BUFFER_OFFSET = OFFSET BUFFER_LENGTH = LENGTH MESS = 0 MESS_DSERV = CLAIM PAGE MESS_SSERV = PAGE CLAIMED MESS_P1 = BUFFER_AMT INDEX MESS_P2 = TEMPST NO PON(MESS) %END; !OF ROUTINE GET PAGE !* !* %ROUTINE RELEASE BLOCK !*********************************************************************** !* * !* RELEASE THE PAGE AND BUFFER IF THE STREAM HAS ONE AND THEN RELEASE * !* THE FILE SECTION FROM THE ACTIVE MEMORY TABLE * !* * !*********************************************************************** %RECORD MESS(PE) %IF STREAM_LINK # EMPTY %START; !RELEASE PAGE AND BUFFER IF STREAM HAS ONE BUFFER NO = STREAM_LINK BUFFER == BUFFER TAB(BUFFER NO) RELEASE BUFFER(NO DRUM UPDATE) %FINISH MESS = 0 MESS_DSERV = FREE BLOCK MESS_SSERV = COMMS REPLY MESS_P1 = STREAM NO MESS_P2 = STREAM_AMT INDEX>>16 PON(MESS) STREAM_AMT INDEX = NOT ALLOCATED %END; !OF ROUTINE RELEASE BLOCK !* !* %END; !OF ROUTINE COMMS CONTROL !* !* !* !* !* !* !* !* %EXTERNALROUTINE MK1 FE ADAPTOR(%RECORDNAME MESS) !*********************************************************************** !* SERVICE 57 (X39) * !* DRIVES THE MK1 FRONT END TO COMMS CONTROLLER SPEC * !* CAN MANAGE UP TO 10 FRONT ENDS (FE0-FE9) USING A 512 BYTE AREA * !* FOR EACH WHICH IS PROVIDED AT GROPE TIME * !*********************************************************************** %RECORDSPEC MESS(PE) %RECORDFORMAT TR(%INTEGER LST0, LST1, RCB0, RCB1, RCB2, RCB3, %C RCB4, RCB5, RCB6, RCB7, LB0, LB1, AL00, AL01, AL10, %C AL11, STREAM, NAME, COB START, COB INDEX, HEAD, TAIL, %C QUEUED TRANSFERS, IDENT, CO HEAD, CO TAIL, %C %BYTEINTEGER ATTN SET, SPARE, DEVICE NO, FAILURES, %C %BYTEINTEGERARRAY CIB, COB(0 : 191)) !*S%RECORDFORMAT TR(%INTEGER TCB0 COMMAND, TCB0 STE, TCB0 LENGTH, %C TCB0 ADDRESS, TCB0 NEXT TCB, TCB0 RESPONSE, %C %INTEGERARRAY TCB0 PREAMBLE, TCB0 POSTAMBLE(0 : 3), %C %INTEGER TCB1 COMMAND, TCB1 STE, TCB1 LENGTH, TCB1 ADDRESS, %C TCB1 NEXT TCB, TCB1 RESPONSE, %INTEGERARRAY TCB1 PREAMBLE, %C TCB1 POSTAMBLE(0:3), %INTEGER %C STREAM, NAME, COB START, COB INDEX, HEAD, TAIL, %C QUEUED TRANSFERS, IDENT, CO HEAD, CO TAIL, %C %BYTEINTEGER ATTN SET, SPARE, DEVICE NO, FAILURES, %C %BYTEINTEGERARRAY CIB, COB(0 : 167)) %RECORDFORMAT GPCF(%INTEGER SER, GPTSM, PROPADDR, TICKS, CAA, %C GRCB AD, LBA, ALA, STATE, RESP0, RESP1, SENSE1, SENSE2, %C SENSE3, SENSE4, REPSNO, BASE, ID, DLVN, MNEMONIC, %C ENTSIZE, PAW, USAW0, URCB AD, SENSE AD, LOGMASK, TRT AD %C , UA SIZE, UA AD, TIMEOUT, PROPS0, PROPS1) %RECORDFORMAT CR(%INTEGER MESSAGE IDENT, P2, P3, P4, P5, P6) %OWNINTEGERARRAY DEVICE TO UA AD(0 : 9) = %C NOT ALLOCATED(10) %CONSTINTEGER CIB LENGTH = 192;!8 CONTROL MESSAGES %CONSTINTEGER COB LENGTH = 192 !*S%CONSTINTEGER CIB LENGTH = 168;!7 CONTROL MESSAGES !*S%CONSTINTEGER COB LENGTH = 168 %CONSTINTEGER MAX FAILURES = 5 %CONSTBYTEINTEGERARRAY RETRY DELAY(0 : MAX FAILURES) = %C 0,1,0,2,0,3 %CONSTINTEGER CONTROL MSG LENGTH = 24 %CONSTINTEGER CONTROL MSG DESCRIPTOR = CONTROL MSG LENGTH!X'18000000' %CONSTINTEGER CONTROL IN MSG DESCRIPTOR = CONTROL MSG DESCRIPTOR - 4 %CONSTINTEGER IDLE = X'F0F0F0F0' %CONSTINTEGER CONTROL IN=-2 %CONSTINTEGER CONTROL OUT=-1 %CONSTINTEGER DATA STREAM = 0 %CONSTINTEGER LONG BLOCK MASK = X'0400' %CONSTINTEGER X MASK = X'0200' %CONSTINTEGER Y MASK = X'0100' !*S%CONSTINTEGER LONG BLOCK MASK = X'04000000' !*S%CONSTINTEGER X MASK = X'02000000' !*S%CONSTINTEGER Y MASK = X'01000000' %INTEGER STREAM NO, BUFFER NO, DEVICE NO %INTEGER TEMP, LENGTH, MESSAGE IDENT, S IDENT, SEARCH INDEX, %C CIB INDEX, DACT, CONTROL ADDR, L, F, T %RECORD GPC REQ(PE) %RECORD CMES(PE) %RECORDNAME GPC ENTRY(GPCF) %RECORDNAME TRANSFER(TR) %RECORDNAME STREAM(SR) %RECORDNAME BUFFER(BR) %RECORDNAME CONTROL(CR) %RECORDNAME PARM CELL(PARMF) %SWITCH ACT(0 : SEND CONTROL) !* !* %ROUTINE START DEVICE(%INTEGER STREAM NO, EXT STREAM NO, %C REAL ADDRESS, START, LENGTH) %CONSTINTEGERARRAY LB MASK(0 : 1) = %C X'00F00202', X'80F00302' !*S%CONSTINTEGERARRAY LB MASK(0 : 1) = %C X'2F004002', X'2F004083' %RECORD MESS(PE) TRANSFER_LST1 = X'80000001'!REAL ADDRESS TRANSFER_LB1 = LB MASK(STREAM NO&1) TRANSFER_AL10 = LENGTH; TRANSFER_AL11 = START !*S TRANSFER_TCB0 RESPONSE = 0 !*S TRANSFER_TCB1 COMMAND = LB MASK(STREAM NO&1) !*S %IF REAL ADDRESS = 0 %THEN TRANSFER_TCB1 STE = %C TRANSFER_TCB0 STE %ELSE TRANSFER_TCB1 STE = REAL ADDRESS!1 !*S TRANSFER_TCB1 LENGTH = LENGTH !*S TRANSFER_TCB1 ADDRESS = START !*S TRANSFER_TCB1 RESPONSE = 0 TRANSFER_STREAM = STREAM NO TRANSFER_NAME = EXT STREAM NO<<16!LENGTH MESS = 0 MESS_DSERV = EXECUTE CHAIN MESS_SSERV = MK1 FE EXECUTED MESS_P1 = ADDR(TRANSFER_RCB0) !*S MESS_P1 = ADDR(TRANSFER_TCB0 COMMAND) MESS_P2 = TRANSFER_IDENT MESS_P3 = X'11';!PAW FUNCTION<<4!SAW FLAGS PON(MESS) %END; !OF ROUTINE START DEVICE !* !* %ROUTINE QUEUE !* QUEUE A HIGH OR LOW LEVEL CONTROL MESSAGE FOR OUTPUT AS THE COB IS FULL %INTEGER TEMP TEMP = NEW PP CELL PARM CELL == PARM TAB(TEMP) CONTROL ADDR = ADDR(PARM CELL_P1) %IF TRANSFER_CO HEAD = EMPTY %C %THEN TRANSFER_CO HEAD = TEMP %C %ELSE PARM TAB(TRANSFER_CO TAIL)_LINK = TEMP PARM CELL_LINK = EMPTY TRANSFER_CO TAIL = TEMP %END; !OF ROUTINE QUEUE !* !* !*********************************************************************** !* MAIN PROGRAM * !*********************************************************************** ? %IF KMON&(LENGTHENI(1)<>16 %C %ELSE CMES_DSERV = MESS_SSERV CMES_SSERV = MESS_DSERV CMES_P1 = STREAM NO CMES_P2 = 1 PON(CMES) %RETURN %FINISH %ELSE TRANSFER == RECORD(DEVICE TO UA AD( %C DEVICE NO)) %FINISH -> ACT(DACT) !* !* ACT(NORMAL TERMINATION):!** NORMAL TERMINATION INTERRUPT %IF TRANSFER_FAILURES # 0 %START OPMESS("FE".TO STRING(DEVICE NO+'0')." TRANSFER RECOVERED") TRANSFER_FAILURES = 0 %FINISH !* !* LENGTH = TRANSFER_AL10-GPC ENTRY_RESP1&SHORT MASK;!NUMBER OF BYTES TRANSFERED !*SLENGTH = TRANSFER_TCB1 LENGTH - TRANSFER_TCB1 RESPONSE&SHORT MASK;!NUMBER OF BYTES TRANSFERED !* !* %IF STREAM NO = CONTROL OUT %START; !CONTROL OUTPUT TERMINATION TRANSFER_COB INDEX = TRANSFER_COB INDEX-LENGTH !*MC MOVE(TRANSFER_COB INDEX,ADDR(TRANSFER_COB(LENGTH)),ADDR %C (TRANSFER_COB(0))) %IF TRANSFER_COB INDEX > 0;!SHUFFLE DOWN? %IF TRANSFER_COB INDEX > 0 %START L = TRANSFER_COB INDEX F = ADDR(TRANSFER_COB(LENGTH)) T = ADDR(TRANSFER_COB(0)) *LDTB_X'18000000' *LDB_L *LDA_F *CYD_0 *LDA_T *MV_%L=%DR %FINISH TRANSFER_COB START = 0 %WHILE TRANSFER_CO HEAD # EMPTY %C %AND TRANSFER_COB INDEX < COB LENGTH %CYCLE PARM CELL == PARM TAB(TRANSFER_CO HEAD) !*MC MOVE(CONTROL MSG LENGTH,ADDR(PARM CELL_P1),ADDR( %C TRANSFER_COB(TRANSFER_COB INDEX))) T = ADDR(TRANSFER_COB(TRANSFER_COB INDEX)) *LSD_PARM CELL *IAD_8 *LDTB_CONTROL MSG DESCRIPTOR *LDA_T *MV_%L=%DR TRANSFER_COB INDEX = TRANSFER_COB INDEX+ %C CONTROL MSG LENGTH TEMP = PARM CELL_LINK RETURN PP CELL(TRANSFER_CO HEAD) TRANSFER_CO HEAD = TEMP TRANSFER_CO TAIL = EMPTY %IF TEMP = EMPTY %REPEAT -> MAKE IDLE %FINISH !* !* %IF STREAM NO = CONTROL IN %START; !CONTROL INPUT TERMINATION CIB INDEX = 0 CMES_SSERV = MESS_DSERV %WHILE CIB INDEX < LENGTH %CYCLE CONTROL == RECORD(ADDR(TRANSFER_CIB(CIB INDEX))) TEMP = CONTROL_MESSAGE IDENT S IDENT = TEMP&SHORT MASK STREAM NO = TEMP>>16 %IF STREAM INDEX(STREAM NO) # EMPTY %START;!VALID STREAM? CMES_P1 = STREAM NO !*MC MOVE(CONTROL MSG LENGTH-4,ADDR(CONTROL_P2),ADDR(CMES_P2)) T = ADDR(CMES_P2) *LSD_CONTROL *IAD_4 *LDTB_CONTROL IN MSG DESCRIPTOR *LDA_T *MV_%L=%DR %IF S IDENT = 0 %THEN %C CMES_DSERV = STREAM TAB(STREAM INDEX(STREAM NO))_ %C OWNER %ELSE %C CMES_DSERV = COMMS REPLY!S IDENT PON(CMES) %FINISH CIB INDEX = CIB INDEX+CONTROL MSG LENGTH %REPEAT -> MAKE IDLE %FINISH !* !* CMES_SSERV = MESS_DSERV!CALLED CMES_DSERV = TRANSFER COMPLETE CMES_P1 = STREAM NO CMES_P2 = GPC ENTRY_RESP0&LONG BLOCK MASK;!NEXT PAGE REQUIRED !*S CMES_P2 = TRANSFER_TCB1 RESPONSE&LONG BLOCK MASK;!NEXT PAGE REQUIRED CMES_P3 = LENGTH COMMS CONTROL(CMES) %IF GPC ENTRY_RESP0&Y MASK # 0 %START;!SEND HIGH LEVEL CONTROL MESSAGE TO SIGNAL END OF MESSAGE !*S%IF TRANSFER_TCB1 RESPONSE&Y MASK # 0 %START;!SEND HIGH LEVEL CONTROL MESSAGE TO SIGNAL END OF MESSAGE %IF STREAM INDEX(STREAM NO) # EMPTY %START STREAM == STREAM TAB(STREAM INDEX(STREAM NO)) %IF STREAM_STATE >= ENABLED %START CMES = 0 CMES_SSERV = MESS_DSERV CMES_DSERV = STREAM_OWNER CMES_P1 = STREAM NO CMES_P2 = STREAM_CURSOR PON(CMES) %FINISH %FINISH %FINISH -> MAKE IDLE !* !* ACT(ATTENTION):!** ATTENTION INTERRUPT %IF MESS_P1&X'1FF00' = X'08000' %START; !EXPECTED ATTN ? %IF STREAM NO = IDLE %START %IF DEVICE TO UA AD(DEVICE NO) = NOT ALLOCATED %START MESS_DSERV = X'32000B' PON(MESS) OP MESS("FE".TO STRING(DEVICE NO + '0')." UP") DEVICE TO UA AD(DEVICE NO) = ADDR(TRANSFER) %RETURN %FINISH MAKE IDLE: TRANSFER_STREAM = IDLE %IF DACT = ATTENTION %OR GPC ENTRY_RESP0&X MASK # 0 %C %OR TRANSFER_ATTN SET # 0 %START; !CONTROL INPUT PENDING !*S %IF DACT = ATTENTION %OR TRANSFER_TCB1 RESPONSE&X MASK # 0 %C %OR TRANSFER_ATTN SET # 0 %START; !CONTROL INPUT PENDING TRANSFER_ATTN SET = 0 START DEVICE(CONTROL IN,CONTROL IN,0,ADDR(TRANSFER_CIB(0)), %C CIB LENGTH) %RETURN %FINISH !* !* %IF TRANSFER_COB INDEX > 0 %START; !CONTROL OUTPUT PENDING. START DEVICE(CONTROL OUT,CONTROL OUT,0,ADDR(TRANSFER_COB( %C 0)),TRANSFER_COB INDEX) TRANSFER_COB START = TRANSFER_COB INDEX %RETURN %FINISH !* !* %IF TRANSFER_HEAD # EMPTY %START; !DATA TRANSFER QUEUED BUFFER == BUFFER TAB(TRANSFER_HEAD) TRANSFER_HEAD = BUFFER_LINK TRANSFER_TAIL = EMPTY %IF TRANSFER_HEAD = EMPTY START DEVICE(BUFFER_STREAM NO,BUFFER_EXTERNAL STREAM NO, %C BUFFER_REAL ADDRESS,BUFFER_OFFSET,BUFFER_LENGTH) %RETURN %FINISH %FINISH %ELSE TRANSFER_ATTN SET = 1 %FINISH %ELSE %START OPMESS("FE".TO STRING(DEVICE NO +'0').%C " UNEXPT ATTN") PRINT STRING("MK1 FE ADAPTOR: ") PT REC(MESS) %FINISH %RETURN !* !* ACT(INITIALISE):!** INITIALIZE !*SCOM AREA == RECORD(X'80000000'+48<<18) %CYCLE DEVICE NO = 0,1,9; !UP TO 10 FES GPC REQ_DSERV = ALLOCATE DEVICE GPC REQ_SSERV = MK1 FE ALLOCATED GPC REQ_P1 = M'FE0'!DEVICE NO GPC REQ_P2 = 1; !PON ON INTERRUPT GPC(GPC REQ) %IF GPC REQ_P1 = 0 %START; !ALLOCATED GPC ENTRY == RECORD(GPC REQ_P3) TRANSFER == RECORD(GPC ENTRY_UA AD) DEVICE TO UA AD(DEVICE NO) = ADDR(TRANSFER) TRANSFER_LST0 = X'00010000';!LOCAL SEGMENT TABLE ENTRY TRANSFER_LST1 = X'00000000' TRANSFER_RCB0 = X'00084000';!RCB FLAGS ETC TRANSFER_RCB1 = REALISE(ADDR(TRANSFER_LST0));!SEGMENT TABLE (REAL ADDRESS) TRANSFER_RCB2 = 8;!LOGIC BLOCK BYTE COUNT; TRANSFER_RCB3 = ADDR(TRANSFER_LB0);!LOGIC BLOCK ADDRESS (VIRTUAL) TRANSFER_RCB4 = 16;!ADDRESS LIST BYTE COUNT TRANSFER_RCB5 = ADDR(TRANSFER_AL00);!ADDRESS LIST ADDRESS (VIRTUAL); TRANSFER_RCB6 = 0;!UNUSED TRANSFER_RCB7 = 0;!UNUSED TRANSFER_LB0 = X'84F00500';!WRITE CONTROL (EXT STREAM NO)<<16!LENGTH TRANSFER_LB1 = X'00000000';!READ OR WRITE DATA TRANSFER_AL00 = 4;!LENGTH OF EXT STREAM NO AND LENGTH FIELD TRANSFER_AL01 = ADDR(TRANSFER_NAME);!ADDRESS OF STREAM FIELD; TRANSFER_AL10 = 0;!LENGTH OF READ / WRITE AREA TRANSFER_AL11 = 0;!ADDRESS OF READ / WRITE AREA !*S TRANSFER_TCB0 COMMAND = X'2F404085';!WRITE CONTROL CHAINED !*S TRANSFER_TCB0 STE = %C INTEGER(ADDR(TRANSFER)<<1>>19<<3+COM AREA_PSTVA+4)!1 !*S TRANSFER_TCB0 LENGTH = 4 !*S TRANSFER_TCB0 ADDRESS = ADDR(TRANSFER_NAME) !*S TRANSFER_TCB0 NEXT TCB = ADDR(TRANSFER_TCB1 COMMAND) !*S TRANSFER_TCB0 RESPONSE = 0 !*S TRANSFER_TCB1 COMMAND = 0 !*S TRANSFER_TCB1 STE = 0 !*S TRANSFER_TCB1 LENGTH = 0 !*S TRANSFER_TCB1 ADDRESS = 0 !*S TRANSFER_TCB1 NEXT TCB = 0 !*S TRANSFER_TCB1 RESPONSE = 0 TRANSFER_IDENT = GPC REQ_P2 TRANSFER_NAME = 0; !CONTROL INFORMATION SENT WRITTEN HERE TRANSFER_STREAM = IDLE TRANSFER_COB START = 0 TRANSFER_COB INDEX = 0 TRANSFER_HEAD = EMPTY TRANSFER_TAIL = EMPTY TRANSFER_QUEUED TRANSFERS = 0 TRANSFER_CO HEAD = EMPTY TRANSFER_CO TAIL = EMPTY TRANSFER_ATTN SET = 0 TRANSFER_DEVICE NO = DEVICE NO TRANSFER_FAILURES = 0 %FINISH %REPEAT %RETURN !* !* ACT(ABNORMAL TERMINATION):!** ABNORMAL TERMINATION INTERRUPT PRINT STRING("MK1 FE ADAPTOR: ABTERM ") WRITE(TRANSFER_FAILURES,1) SPACES(2) PT REC(MESS) DUMP TABLE(80,GPC ENTRY_UA AD,GPC ENTRY_UA SIZE) %IF TRANSFER_FAILURES <= MAX FAILURES %START; !TRY AGAIN? GPC REQ = 0 GPC REQ_DSERV = EXECUTE CHAIN GPC REQ_SSERV = MK1 FE EXECUTED GPC REQ_P1 = ADDR(TRANSFER_RCB0) !*S GPC REQ_P1 = ADDR(TRANSFER_TCB0 COMMAND) GPC REQ_P2 = TRANSFER_IDENT GPC REQ_P3 = X'11';!PAW FUNCTION<<4!SAW FLAGS DPON(GPC REQ,RETRY DELAY(TRANSFER_FAILURES)); !TRY AGAIN IN ? SECONDS TRANSFER_FAILURES = TRANSFER_FAILURES+1 %FINISH %ELSE %START OPMESS("FE".TO STRING('0'+DEVICE NO)." DOWN".TO STRING(17));!FLASH %IF STREAM NO >= DATA STREAM %START; !FAIL TRANSFER IN PROGRESS CMES = 0 CMES_DSERV = TRANSFER COMPLETE CMES_SSERV = MESS_DSERV CMES_P1 = STREAM NO PON(CMES) %FINISH %WHILE TRANSFER_HEAD # EMPTY %CYCLE; !FAIL ALL QUEUED TRANSFERS BUFFER == BUFFER TAB(TRANSFER_HEAD) TRANSFER_HEAD = BUFFER_LINK TRANSFER_TAIL = EMPTY %IF TRANSFER_HEAD = EMPTY CMES = 0 CMES_DSERV = TRANSFER COMPLETE CMES_SSERV = MESS_DSERV CMES_P1 = BUFFER_STREAM NO PON(CMES) %REPEAT %CYCLE STREAM NO = 0,1,MAX STREAM %IF STREAM INDEX(STREAM NO) # EMPTY %START STREAM == STREAM TAB(STREAM INDEX(STREAM NO)) %IF STREAM_ADAPTOR NO = FE %C %AND STREAM_DEVICE NO = DEVICE NO %START;!CONNECTED THRU THIS FRONT END CMES = 0 CMES_SSERV = MESS_DSERV CMES_P1 = STREAM NO %IF STREAM NO&1 = 0 %AND SUB IDENT(STREAM_STATE) = - 1 %START;!INPUT STREAM NOT WAITING ON A REPLY CMES_DSERV = STREAM_OWNER;!THEN SEND A HIGH LEVEL CONTROL MSG CMES_P2 = STREAM_CURSOR CMES_P3 = X'01590000'; !CONTROL (E O T) Y PON(CMES) %FINISHELSESTART;!WAITING ON A REPLY %IF SUB IDENT(STREAM_STATE) # - 1 %START CMES_DSERV = COMMS REPLY!SUB IDENT(STREAM_STATE)>>16;!SIMUALTE ONE CMES_P2 = 1;!FAILURE PON(CMES) %FINISH %FINISH %FINISH %FINISH %REPEAT TRANSFER_STREAM = IDLE TRANSFER_COB START = 0 TRANSFER_COB INDEX = 0 TRANSFER_FAILURES = 0 DEVICE TO UA AD(DEVICE NO) = NOT ALLOCATED %FINISH %RETURN !* !* !* ABOVE ENTRIES ARE CALLED BY GPC !* !* BELOW ENTRIES ARE CALLED BY COMMS CONTROL !* !* ACT(GO AHEAD):!** TRANSFER GO AHEAD BUFFER NO = MESS_P2 BUFFER == BUFFER TAB(BUFFER NO) %IF TRANSFER_HEAD # EMPTY %OR TRANSFER_STREAM # IDLE %START;!QUEUE A TRANSFER BUFFER_LINK = EMPTY %IF TRANSFER_HEAD = EMPTY %C %THEN TRANSFER_HEAD = BUFFER NO %C %ELSE BUFFER TAB(TRANSFER_TAIL)_LINK = BUFFER NO TRANSFER_TAIL = BUFFER NO TRANSFER_QUEUED TRANSFERS = TRANSFER_QUEUED TRANSFERS+1 %FINISH %ELSE START DEVICE(STREAM NO,BUFFER_EXTERNAL STREAM NO, %C BUFFER_REAL ADDRESS,BUFFER_OFFSET,BUFFER_LENGTH) %RETURN !* !* ACT(SEND CONTROL):!** CONTROL MESSAGE MESSAGE IDENT = STREAM_EXTERNAL STREAM NO<<16!MESS_P1>>16 MESS_P1 = MESSAGE IDENT %IF MESSAGE IDENT&SHORT MASK = 0 %C %AND MESS_SSERV&SHORT MASK = CONTROL MSG7 %START;!HIGH LEVEL AND UPDATE MESSAGE SEARCH INDEX = TRANSFER_COB START %CYCLE CONTROL ADDR = ADDR(TRANSFER_COB(SEARCH INDEX)) %IF SEARCH INDEX = TRANSFER_COB INDEX %START;!END OF WHATS IN BUFFER? %IF TRANSFER_COB INDEX = COB LENGTH %START;!COB BUFFER FULL TEMP = TRANSFER_CO HEAD %WHILE TEMP # EMPTY %CYCLE; !SCAN DOWN EXISTING QUEUE PARM CELL == PARM TAB(TEMP) %IF MESSAGE IDENT = PARM CELL_P1 %START;!UPDATE? CONTROL ADDR = ADDR(PARM CELL_P1) -> OUT %FINISH %ELSE TEMP = PARM CELL_LINK %REPEAT QUEUE OUT: %FINISH %ELSE TRANSFER_COB INDEX = TRANSFER_COB INDEX+ %C CONTROL MSG LENGTH %EXIT %FINISH %EXIT %IF INTEGER(CONTROL ADDR) = MESSAGE IDENT SEARCH INDEX = SEARCH INDEX+CONTROL MSG LENGTH %REPEAT CMES_DSERV = MESS_SSERV CMES_SSERV = MESS_DSERV CMES_P1 = STREAM NO CMES_P2 = 0 PON(CMES); !REPLY MESSAGE UPDATED %FINISH %ELSE %START %IF TRANSFER_COB INDEX # COB LENGTH %START; !COB BUFFER FULL? CONTROL ADDR = ADDR(TRANSFER_COB(TRANSFER_COB INDEX)) TRANSFER_COB INDEX = TRANSFER_COB INDEX+CONTROL MSG LENGTH %FINISH %ELSE QUEUE %FINISH !*MCMOVE(CONTROL MSG LENGTH,ADDR(MESS_P1),CONTROL ADDR) *LSD_MESS *IAD_8 *LDTB_CONTROL MSG DESCRIPTOR *LDA_CONTROL ADDR *MV_%L=%DR START DEVICE(CONTROL OUT,CONTROL OUT,0,ADDR(TRANSFER_COB(0)), %C TRANSFER_COB INDEX) %AND TRANSFER_COB START = TRANSFER_ %C COB INDEX %IF TRANSFER_STREAM = IDLE %END; !OF ROUTINE MK1 FE ADAPTOR !* !* !* !* !* !* !* !* %EXTERNALROUTINE LP ADAPTOR(%RECORDNAME MESS) !*********************************************************************** !* SERVICE 51 (X33) * !* DRIVES THE LINE PRINTER TO COMMS CONTROLLER SPEC * !* ACCEPTS THE DATA AS ISO, EBCIDIC OR BINARY. ISO IS TRANSLATED TO * !* EBCIDIC USING THE MASTER TRANSLATE TABLES. EBCIDIC DATA IS * !* TRANSLATED TO A SUBSET OF EBCIDIC DEPENDING ON THE REP IN THE * !* PRINTER TO AVOID NON PRINTING CHARACTERS FOULING THINGS UP. * !* BINARY DATA IS LEFT ALONE. * !* CAN MANAGE UP TO 10 PRINTERS (LP0-LP9) USING A 128 BYTE AREA FOR * !* EACH WHICH IS PROVIDED AT GROPE TIME * !*********************************************************************** %RECORDSPEC MESS(PE) %RECORDFORMAT GPCF(%INTEGER SER, GPTSM, PROPADDR, TICKS, CAA, %C GRCB AD, LBA, ALA, STATE, RESP0, RESP1, SENSE1, SENSE2, %C SENSE3, SENSE4, REPSNO, BASE, ID, DLVN, MNEMONIC, %C ENTSIZE, PAW, USAW0, URCB AD, SENSE AD, LOGMASK, TRT AD %C , UA SIZE, UA AD, TIMEOUT, PROPS0, PROPS1) %RECORDFORMAT TR(%INTEGER LST0, LST1, RCB0, RCB1, RCB2, RCB3, %C RCB4, RCB5, RCB6, RCB7, LB0, LB1, LB2, AL00, AL01, %C STREAM, MODE, BUFFER NO, TRT AD, IDENT, DEVICE NO) !*S%RECORDFORMAT TR(%HALFINTEGER STREAM, BUFFER NO, %C %INTEGER TRT AD,ADDR TCB, %BYTEINTEGER MODE,IDENT,DEVICE NO,S, %C %INTEGER TCB0 COMMAND, TCB0 STE, TCB0 LENGTH, %C TCB0 ADDRESS, TCB0 NEXT TCB, TCB0 RESPONSE, %C %INTEGERARRAY TCB0 PREAMBLE, TCB0 POSTAMBLE(0 : 3), %C %INTEGER TCB1 COMMAND, TCB1 STE, TCB1 LENGTH, TCB1 ADDRESS, %C TCB1 NEXT TCB, TCB1 RESPONSE, %INTEGERARRAY TCB1 PREAMBLE(0 : 3) %C , TCB1 POSTAMBLE(0 : 2), %BYTEINTEGERARRAY CHARS(0 : 131)) %CONSTINTEGER AUTO = X'00008400' %OWNINTEGERARRAY DEVICE TO UA AD(0 : 9) = %C NOT ALLOCATED(10) %RECORD REQ(PE) %RECORD REP(PE) %RECORDNAME GPC ENTRY(GPCF) %RECORDNAME TRANSFER(TR) %RECORDNAME STREAM(SR) %RECORDNAME BUFFER(BR) %INTEGER STREAM NO, BUFFER NO, STATE, START %INTEGER BUFFER END, SENT, DEVICE NO, ACT %INTEGER I, CHAR, LINE, LONG LINE, LINE BEGIN %SWITCH DACT(0 : SEND CONTROL) %ROUTINESPEC E TO E(%INTEGER S, L) REP = 0; REQ = 0 ? %IF KMON&(LENGTHENI(1)< DACT(ACT) !* !* DACT(ABNORMAL TERMINATION):!** ABNORMAL TERMINATION I = (TRANSFER_RCB3-ADDR(TRANSFER_LB0))>>2+GPC ENTRY_RESP0& %C BYTE MASK %IF I = 2 %AND MESS_P2 # - 1 %START !*S%IF MESS_P5 = ADDR(TRANSFER_TCB1 COMMAND) %AND MESS_P2 # -1 %START;!ON A WRITE DATA? LONG LINE = 1 %IF INTEGER(GPC ENTRY_SENSE AD) = X'20000004' !* !* DACT(NORMAL TERMINATION):!** NORMAL TERMINATION SENT = TRANSFER_AL00-GPC ENTRY_RESP1&SHORT MASK !*S SENT = TRANSFER_TCB1 LENGTH - TRANSFER_TCB1 RESPONSE&SHORT MASK BUFFER == BUFFER TAB(TRANSFER_BUFFER NO) START = VIRTUAL+(BUFFER_REAL ADDRESS+BUFFER_OFFSET) %IF LONG LINE = 0 %START; !WAS IT A LONG LINE THEN NO NEED TO SCAN BACK %IF SENT > 0 %START BUFFER END = START+SENT-1 %IF BUFFER END-START > 132 %C %THEN LINE BEGIN = BUFFER END-132 %C %ELSE LINE BEGIN = START %CYCLE I = BUFFER END,-1,LINE BEGIN CHAR = BYTE INTEGER(I) %EXIT %IF CHAR = EBC NL %OR CHAR = EBC CR %C %OR CHAR = EBC FF %REPEAT !SET UP CHAIN TO MERGE THE END OF THE LINE ONTO THE HEAD LINE = BUFFER END-I %IF LINE = 0 %START TRANSFER_RCB3 = ADDR(TRANSFER_LB2) TRANSFER_LB2 = X'80700300' !*S TRANSFER_ADDR TCB = ADDR(TRANSFER_TCB1 COMMAND) %FINISH %ELSE %START TRANSFER_RCB3 = ADDR(TRANSFER_LB0) TRANSFER_LB1 = X'8A700000'!LINE TRANSFER_LB2 = X'80700000'; !*S TRANSFER_ADDR TCB = ADDR(TRANSFER_TCB0 COMMAND) !*S TRANSFER_TCB0 LENGTH = LINE !*S TRANSFER_ CHARS(0) = EBC SP %FINISH %FINISH %FINISH %ELSE %START; !TAG ON A NEW LINE TRANSFER_RCB3 = ADDR(TRANSFER_LB1) TRANSFER_LB1 = X'8A700300'!EBC NL TRANSFER_LB2 = X'80700000'; !*S TRANSFER_ADDR TCB = ADDR(TRANSFER_TCB0 COMMAND) !*S TRANSFER_TCB0 LENGTH = 1 !*S TRANSFER_CHARS(0) = EBC NL SENT = SENT-1; !SEND THE CHAR THAT CAUSED THE LONG LINE AGAIN %FINISH %FINISH %ELSE %START SENT = 0 BUFFER == BUFFER TAB(TRANSFER_BUFFER NO) START = VIRTUAL+(BUFFER_REAL ADDRESS+BUFFER_OFFSET) %FINISH !TRANSLATE THE BUFFER BACK TO ISO ETOI(START,BUFFER_LENGTH) %IF TRANSFER_MODE = ISO !SEND REPLY TO COMMS CONTROL MESS_SSERV = MESS_DSERV!CALLED MESS_DSERV = TRANSFER COMPLETE MESS_P1 = TRANSFER_STREAM MESS_P2 = 1; !GET NEXT PAGE MESS_P3 = SENT COMMS CONTROL(MESS) %IF ACT = ABNORMAL TERMINATION %START; !INFORM CONTROLLING PROCESS %IF LONG LINE = 0 %START; !UNLESS IT WAS A LONG LINE REP_DSERV = STREAM_OWNER REP_SSERV = LP COMMAND REP_P1 = STREAM NO REP_P2 = STREAM_CURSOR REP_P3 = GPC ENTRY_RESP0 REP_P4 = GPC ENTRY_RESP1 REP_P5 = INTEGER(GPC ENTRY_SENSE AD) REP_P6 = INTEGER(GPC ENTRY_SENSE AD+4) PON(REP) %FINISH %ELSE %START REQ_DSERV = REQUEST TRANSFER; !START TRANSFER AGAIN REQ_SSERV = LP COMMAND REQ_P1 = STREAM NO PON(REQ) %FINISH %FINISH %RETURN !* !* DACT(ATTENTION):!** ATTENTION INTERRUPT %IF MESS_P1&AUTO = AUTO %AND STREAM_STATE = ENABLED %START REQ_DSERV = REQUEST TRANSFER REQ_SSERV = LP COMMAND REQ_P1 = STREAM NO PON(REQ) %FINISH %RETURN !* !* DACT(GO AHEAD):!** TRANSFER GO AHEAD BUFFER NO = MESS_P2 BUFFER == BUFFER TAB(BUFFER NO) TRANSFER_BUFFER NO = BUFFER NO START = VIRTUAL+(BUFFER_REAL ADDRESS+BUFFER_OFFSET) I TO E(START,BUFFER_LENGTH) %IF TRANSFER_MODE = ISO E TO E(START,BUFFER_LENGTH) %IF TRANSFER_MODE # BINARY !AND INITIATE THE TRANSFER TRANSFER_LST1 = X'80000001'!BUFFER_REAL ADDRESS TRANSFER_AL00 = BUFFER_LENGTH TRANSFER_AL01 = BUFFER_OFFSET; !*STRANSFER_TCB0 RESPONSE = 0 !*STRANSFER_TCB1 STE = BUFFER_REAL ADDRESS!1 !*STRANSFER_TCB1 LENGTH = BUFFER_LENGTH !*STRANSFER_TCB1 ADDRESS = BUFFER_OFFSET !*STRANSFER_TCB1 RESPONSE = 0 REQ_DSERV = EXECUTE CHAIN REQ_SSERV = LP EXECUTED REQ_P1 = ADDR(TRANSFER_RCB0) !*SREQ_P1 = TRANSFER_ADDR TCB REQ_P2 = TRANSFER_IDENT REQ_P3 = 1<<4!1;!(PAW FUNCTION)<<4!SAW FLAGS PON(REQ) %RETURN !* !* DACT(SEND CONTROL):!** CONTROL MESSAGE STATE = MESS_P2>>24 REP_DSERV = COMMS REPLY!MESS_P1>>16; !REPLY TO COMMS CONTROLLER REP_SSERV = MESS_DSERV REP_P1 = STREAM NO %IF STATE = CONNECTING %START; !ALLOCATE DEVICE REQ_DSERV = ALLOCATE DEVICE REQ_SSERV = LP ALLOCATED REQ_P1 = M'LP0'!DEVICE NO REQ_P2 = 1; !PON ON RESP0NSE GPC(REQ) REP_P2 = REQ_P1; !HAND REPLY BACK TO COMMS CONTROLLER %IF REP_P2 = 0 %START; !ALLOC OK GPC ENTRY == RECORD(REQ_P3); !MAP AREA TRANSFER == RECORD(GPC ENTRY_UA AD) DEVICE TO UA AD(DEVICE NO) = ADDR(TRANSFER) TRANSFER_IDENT = REQ_P2; !SAVE GPC IDENTIFIER TRANSFER_MODE = 0; !ISO BY DEFAULT TRANSFER_STREAM = STREAM NO TRANSFER_DEVICE NO = DEVICE NO TRANSFER_TRT AD = GPC ENTRY_TRT AD TRANSFER_LST0 = X'00010000';!LOCAL SEGMENT TABLE ENTRY TRANSFER_LST1 = 0 TRANSFER_RCB0 = X'00080000';!RCB FLAGS ETC TRANSFER_RCB1 = REALISE(ADDR(TRANSFER_LST0)) TRANSFER_RCB2 = 12;!LOGIC BLOCK BYTE COUNT TRANSFER_RCB3 = ADDR(TRANSFER_LB2);!LOGIC BLOCK ADDRESS TRANSFER_RCB4 = 8;!ADDRESS_LIST BYTE COUNT; TRANSFER_RCB5 = ADDR(TRANSFER_AL00);!ADDRESS LIST ADDRESS TRANSFER_RCB6 = 0;!UNUSED TRANSFER_RCB7 = 0;!UNUSED TRANSFER_LB0 = X'8A700300'!EBC MS TRANSFER_LB1 = X'8A700000';!NUMBER OF SPACES TRANSFER_LB2 = X'80700300';!WRITE BUFFER TRANSFER_AL00 = 0;!BUFFER LENGTH TRANSFER_AL01 = 0;!BUFFER OFFSET !*S TRANSFER_TCB0 COMMAND = X'24404083' !*S TRANSFER_TCB0 STE = %C INTEGER(ADDR(TRANSFER)<<1>>19<<3+COM AREA_PSTVA+4)!1 !*S TRANSFER_TCB0 LENGTH = 0 !*S TRANSFER_TCB0 ADDRESS = ADDR(TRANSFER_CHARS(0)) !*S TRANSFER_TCB0 NEXT TCB = ADDR(TRANSFER_TCB1 COMMAND) !*S TRANSFER_TCB1 COMMAND = X'24004083' !*S TRANSFER_TCB1 STE = 0 !*S TRANSFER_TCB1 LENGTH = 0 !*S TRANSFER_TCB1 ADDRESS = 0 !*S TRANSFER_TCB1 NEXT TCB = 0 !*S TRANSFER_TCB0 RESPONSE = 0 !*S TRANSFER_ADDR TCB = ADDR(TRANSFER_TCB1 COMMAND) !*S %CYCLE I = 0,1,131 !*S TRANSFER_CHARS(I) = EBC SP !*S %REPEAT %FINISH %FINISH %IF STATE = ENABLING %START; !REQUEST FIRST PAGE REQ_DSERV = REQUEST TRANSFER REQ_SSERV = LP COMMAND REQ_P1 = STREAM NO PON(REQ) TRANSFER_MODE = MESS_P2>>20&3; !ISO EBCIDIC OR BINARY %IF MESS_P2>>16&3 = SEQUENTIAL %START;!INSERT A FORM FEED IF NOT A SEQUENTIAL CONTINUATION TRANSFER_RCB3 = ADDR(TRANSFER_LB1) TRANSFER_LB1 = X'8A700300'!EBC FF !*S TRANSFER_ADDR TCB = ADDR(TRANSFER_TCB0 COMMAND) !*S TRANSFER_TCB0 LENGTH = 1 !*S TRANSFER_CHARS(0) = EBC FF %FINISH %FINISH %IF STATE = DISCONNECTING %START; !DE ALLOCATE DEVICE REQ_DSERV = DEALLOCATE DEVICE REQ_SSERV = LP DEALLOCATED REQ_P1 = M'LP0'!DEVICE NO GPC(REQ) REP_P2 = REQ_P1; !HAND FLAG BACK TO COMMS CONTROLLER DEVICE TO UA AD(DEVICE NO) = NOT ALLOCATED %FINISH COMMS CONTROL(REP) %RETURN !* %ROUTINE E TO E(%INTEGER AD, L) %INTEGER TRT AD TRT AD = TRANSFER_TRTAD *LB_L ; *JAT_14, *LDTB_X'18000000'; *LDB_%B; *LDA_AD *LSS_TRT AD; *LUH_X'18000100' *TTR_%L=%DR L99: %END; !OF ROUTINE E TO E !* !* %END; !OF ROUTINE LP ADAPTOR !* !* !* !* !* !* !* !* %EXTERNALROUTINE CR ADAPTOR(%RECORDNAME P) !*********************************************************************** !* SERVICE 52 (X34) * !* DRIVES THE CARD READER TO COMMS CONTROLLER SPEC WITH SOME * !* NASTY FIDDLES WHEN A CARD WONT FIT INTO REMAINS OF AN EPAGE * !* CAN MANAGE UP TO 10 READERS (CR0-CR9) USING A 512 BYTE AREA FOR * !* EACH WHICH IS PROVIDED AT GROPE TIME * !*********************************************************************** %RECORDSPEC P(PE) %INTEGER I, J, STREAM NO, DEVICE NO, STATE, SENT, ACT, BUFFER NO %RECORDFORMAT GPCF(%INTEGER SER, GPTSM, PROPADDR, TICKS, CAA, %C GRCB AD, LBA, ALA, STATE, RESP0, RESP1, SENSE1, SENSE2, %C SENSE3, SENSE4, REPSNO, BASE, ID, DLVN, MNEMONIC, %C ENTSIZE, PAW, USAW0, URCB AD, SENSE AD, LOGMASK, TRT AD %C , UA SIZE, UA AD, TIMEOUT, PROPS0, PROPS1) %RECORDFORMAT UAF(%INTEGER LST0, LST1, RCB0, RCB1, RCB2, RCB3, %C RCB4, RCB5, RCB6, RCB7, STREAM NO, MODE, GOAH AD, %C GOAH LEN, CURTRLEN, BUFFER NO, GPCSER, BLOCKED, %C %INTEGERARRAY LBE(0 : 35), ALE(0 : 71)) %OWNINTEGERARRAY DEVICE TO UA AD(0 : 9) = %C NOT ALLOCATED(10) %ROUTINESPEC TRANSLATE AND SHUFFLE(%INTEGER ADDRESS, %C %INTEGERNAME LEN) %RECORDNAME GPC ENTRY(GPCF) %RECORDNAME USER AREA(UAF) %RECORDNAME STREAM(SR) %RECORDNAME BUFFER(BR) %RECORD REQ, REP(PE) %CONSTINTEGER AUTO = X'00008400' %CONSTINTEGERARRAY CARD SIZE( ISO : BINARY) = %C 81, 80, 0 %SWITCH DACT(0 : SEND CONTROL) REP = 0; REQ = 0 ? %IF KMON&(LENGTHENI(1)< DACT(ACT) DACT(NORMAL TERMINATION): !NORMAL TERMINATION BUFFER == BUFFER TAB(USER AREA_BUFFER NO) TRANSLATE AND SHUFFLE(VIRTUAL+(BUFFER_REAL ADDRESS+ %C USER AREA_GOAH AD),USER AREA_CUR TR LEN) %C %IF USER AREA_MODE = ISO USER AREA_GOAH LEN = USER AREA_GOAH LEN-USER AREA_CURTRLEN USER AREA_GOAH AD = USER AREA_GOAH AD+USER AREA_CURTRLEN -> READ; !READ MORE IF ROOM DACT(ATTENTION): !ATTENTION !IF 'AUTO' RESUME READING !IGNORE ALL OTHERS %IF P_P1&AUTO = AUTO %AND STREAM_STATE = ENABLED %C %AND USER AREA_BLOCKED = 0 %START REQ_DSERV = REQUEST TRANSFER REQ_SSERV = CR COMMAND REQ_P1 = STREAM NO PON(REQ) %FINISH %RETURN DACT(ABNORMAL TERMINATION): !ABNORMAL TERMINATION I = GPC ENTRY_RESP0&X'FF'; !FAILING LBE ENTRY SENT = CARD SIZE(USER AREA_MODE)*I; !BYTES READ OK BUFFER == BUFFER TAB(USER AREA_BUFFER NO) TRANSLATE AND SHUFFLE(VIRTUAL+(BUFFER_REAL ADDRESS+ %C USER AREA_GOAH AD),SENT) %C %IF SENT > 0 %AND USER AREA_MODE = ISO USER AREA_GOAH LEN = USER AREA_GOAH LEN-SENT !TELL COMMS CONTROL BY A CALL TO UPDATE CURSOR REQ_DSERV = TRANSFER COMPLETE REQ_SSERV = CR COMMAND!CALLED; !CALL NOT PON REQ_P1 = STREAM NO REQ_P2 = 0; !NEXT PAGE NOT REQD REQ_P3 = BUFFER_LENGTH-USER AREA_GOAH LEN COMMS CONTROL(REQ) !TELL SPOOLER WE HAVE FINISH & HOWMUCH IS AVAILABLE %IF SENT > 0 %START USER AREA_BLOCKED = 1 REQ_DSERV = STREAM_OWNER REQ_SSERV = CR COMMAND REQ_P1 = STREAM NO REQ_P2 = STREAM_CURSOR REQ_P3 = GPC ENTRY_RESP0 REQ_P4 = GPC ENTRY_RESP1 REQ_P5 = INTEGER(GPC ENTRY_SENSEAD) REQ_P6 = INTEGER(GPC ENTRY_SENSEAD+4) PON(REQ) %FINISH %RETURN DACT(GO AHEAD): !TRANSFER GO AHEAD !IE COMMS HAS PAGED IN BUFFER BUFFER NO = P_P2 BUFFER == BUFFER TAB(BUFFER NO) USER AREA_LST1 = X'80000001'!BUFFER_REAL ADDRESS USER AREA_GOAH LEN = BUFFER_LENGTH USER AREA_GOAH AD = BUFFER_OFFSET USER AREA_BUFFER NO = BUFFER NO READ: !TRY TO READ CARDS %IF USER AREA_GOAH LEN < CARD SIZE(USER AREA_MODE) %START !NOT ROOM FOR EVEN 1 CARD BUFFER == BUFFER TAB(USER AREA_BUFFER NO) %IF USER AREA_GOAH LEN > 0 %START J = VIRTUAL+(BUFFER_REAL ADDRESS+USER AREA_GOAH AD) %CYCLE I = 0,1,USER AREA_GOAH LEN-1 BYTE INTEGER(I+J) = 0; !FILL PARTCARD WITH NULLS %REPEAT %FINISH REQ_DSERV = TRANSFER COMPLETE REQ_SSERV = CR COMMAND REQ_P1 = STREAM NO REQ_P2 = 1; !PLEASE PROVIDE NEXT PAGE REQ_P3 = BUFFER_LENGTH PON(REQ) %RETURN %FINISH !THERE IS ROOM FOR AT LEAST ONE CARD. SET UP CHAIN I = 0 %CYCLE %EXIT %IF I > 35 %OR USER AREA_GOAH LEN-CARD SIZE( %C USER AREA_MODE)*(I+1) < 0 USER AREA_LBE(I) = X'04400200'+2*I; !CHAIN IGNRE LONGBLK&READ USER AREA_ALE(2*I+1) = USER AREA_GOAH AD+CARD SIZE( %C USER AREA_MODE)*I I = I+1 %REPEAT USER AREA_LBE(I-1) = USER AREA_LBE(I-1)&X'F3FFFFFF' !DECHAIN USER AREA_CUR TR LEN = CARD SIZE(USER AREA_MODE)*I REQ_DSERV = EXECUTE CHAIN REQ_SSERV = CR EXECUTED REQ_P1 = ADDR(USER AREA_RCB0) REQ_P2 = USER AREA_GPCSER REQ_P3 = 1<<4!1; !(PAW FUNCTION)<<4!SAW FLAGS REQ_P4 = 0 PON(REQ) %RETURN DACT(SEND CONTROL): !CONTROLL MESSAGE !P_P2=STATE MODE AND LENGTH STATE = P_P2>>24 REP_DSERV = COMMS REPLY!P_P1>>16 REP_SSERV = P_DSERV REP_P1 = STREAM NO %IF STATE = CONNECTING %THEN %START REQ_DSERV = ALLOCATE DEVICE REQ_SSERV = CR ALLOCATED REQ_P1 = M'CR0'!DEVICE NO REQ_P2 = 1; !PON DEVICE REPLIES GPC(REQ); !TRY TO ALLOCATE REP_P2 = REQ_P1; !PASS SUCCESS BACK TO COMMS %IF REP_P2 = 0 %THEN %START; !ALLOCATED OK GPC ENTRY == RECORD(REQ_P3); !REMAP AREA USER AREA == RECORD(GPC ENTRY_UA AD) DEVICE TO UA AD(DEVICE NO) = ADDR(USER AREA) USER AREA_GPCSER = REQ_P2; !GPC PRIVATE IDENT USER AREA_LST0 = X'00010000' USER AREA_STREAM NO = STREAM NO USER AREA_MODE = 0; !READ IN NON BINARY MODE USER AREA_BLOCKED = 0 USER AREA_RCB0 = X'0008C000' USER AREA_RCB1 = REALISE(ADDR(USER AREA_LST0)) USER AREA_RCB2 = 144; !BYTE OF LOGIC BLOCK USER AREA_RCB3 = ADDR(USER AREA_LBE(0)) USER AREA_RCB4 = 288; !BYTE OF ADDRESS LIST USER AREA_RCB5 = ADDR(USER AREA_ALE(0)) USER AREA_RCB6 = X'FF01'; !SET NR MODE USER AREA_RCB7 = 0 %CYCLE I = 0,2,70 USER AREA_ALE(I) = X'58000050'; !80 BYTE ENTRY %REPEAT %FINISH %FINISH %IF STATE = DISCONNECTING %START REQ_DSERV = DEALLOCATE DEVICE REQ_SSERV = CR DEALLOCATED REQ_P1 = M'CR0'!DEVICE NO GPC(REQ) REP_P2 = REQ_P1; !FAIL FLAG BACK TO COMMS DEVICE TO UA AD(DEVICE NO) = NOT ALLOCATED %FINISH %IF STATE = ENABLING %START %IF USER AREA_BLOCKED = 0 %START REQ_DSERV = REQUEST TRANSFER REQ_SSERV = CR COMMAND REQ_P1 = STREAM NO PON(REQ) %FINISHELSE USER AREA_BLOCKED = 0 USER AREA_MODE = P_P2>>20&3; !ISO EBCIDIC OR BINARY? %FINISH COMMS CONTROL(REP) %RETURN !* !* %ROUTINE TRANSLATE AND SHUFFLE(%INTEGER START, %INTEGERNAME LEN) %INTEGER CARD ADDR, L, TO E TO I(START,LEN); !TRANSLATE CARDS TO ISO TO = START; !PLACE CARD IS TO BE SHUFFLED TO %CYCLE CARD ADDR = START,81,START+LEN-81; !CYCLE UP EACH CARD %CYCLE L = 79,-1,0; !CYCLE DOWN EACH CHARACTER -> M %IF BYTEINTEGER(CARD ADDR+L) # ' ' !CHAR NOT A SPACE %REPEAT L = -1; !CARD ALL SPACES M: BYTEINTEGER(CARD ADDR+L+1) = NL L = L+2; !LENGTH OF CARD MOVE(L,CARD ADDR,TO) %IF CARD ADDR # TO TO = TO+L %REPEAT LEN = TO-START; !NUMBER OF CHARS REMAINING %END; !OF ROUTINE TRANSLATE AND SHUFFLE !* !* %END; !OF ROUTINE CR ADAPTOR !* !* !* !* !* !* !* !* %EXTERNALROUTINE CP ADAPTOR(%RECORDNAME P) !*********************************************************************** !* SERVICE 53 (X35) * !* DRIVES THE CARD PUNCH TO COMMS CONTROLLER SPEC WITH SOME * !* NASTY FIDDLES WHEN A CARD WONT FIT INTO REMAINS OF AN EPAGE * !* CARDS ARE JUST PUNCHED FROM DISC IN EBCDIC AND SPOOLER INFORMED * !* CAN MANAGE UP TO 10 PUNCHES (CP0-CP9) USING A 160 BYTE AREA FOR * !* EACH WHICH IS PROVIDED AT GROPE TIME * !*********************************************************************** %RECORDSPEC P(PE) %INTEGER I, J, STREAM NO, DEVICE NO, STATE, SENT, ACT, %C BUFFER NO, SYM %RECORDFORMAT GPCF(%INTEGER SER, GPTSM, PROPADDR, TICKS, CAA, %C GRCB AD, LBA, ALA, STATE, RESP0, RESP1, SENSE1, SENSE2, %C SENSE3, SENSE4, REPSNO, BASE, ID, DLVN, MNEMONIC, %C ENTSIZE, PAW, USAW0, URCB AD, SENSE AD, LOGMASK, TRT AD %C , UA SIZE, UA AD, TIMEOUT, PROPS0, PROPS1) %RECORDFORMAT UAF(%INTEGER LST0, LST1, GOAH AD, GOAH LEN, %C SPARE1, POSN, RCB0, RCB1, RCB2, RCB3, RCB4, RCB5, RCB6, %C RCB7, LBE0, ALE0, ALE1, %C STREAM NO, BUFFER NO, %HALFINTEGER SPARE2, %C %BYTEINTEGER MODE, GPCSER, %C %BYTEINTEGERARRAY CARD(0 : 79)) %OWNINTEGERARRAY DEVICE TO UA AD(0 : 9) = %C NOT ALLOCATED(10) %RECORDNAME GPC ENTRY(GPCF) %RECORDNAME USER AREA(UAF) %RECORDNAME STREAM(SR) %RECORDNAME BUFFER(BR) %RECORD REQ, REP(PE) %CONSTINTEGER AUTO = X'00008400' %SWITCH DACT(0 : SEND CONTROL) REP = 0; REQ = 0 ? %IF KMON&(LENGTHENI(1)< DACT(ACT) DACT(NORMAL TERMINATION): !NORMAL TERMINATION BUFFER == BUFFER TAB(USER AREA_BUFFER NO) USER AREA_POSN = 0; !NO UNPUCHED CARD IN BUFFER I = 0 %AND -> EPAGE USED %IF USER AREA_GOAH LEN = 0;!FINISHED BUFFER EMPTY -> PUNCH; !PUNCH MORE IF ROOM DACT(ATTENTION): !ATTENTION !IF 'AUTO' RESUME PUNCHING !IGNORE ALL OTHERS %IF P_P1&AUTO = AUTO %AND STREAM_STATE = ENABLED %START REQ_DSERV = REQUEST TRANSFER REQ_SSERV = CP COMMAND REQ_P1 = STREAM NO PON(REQ) %FINISH %RETURN DACT(ABNORMAL TERMINATION): !ABNORMAL TERMINATION BUFFER == BUFFER TAB(USER AREA_BUFFER NO) !TELL COMMS CONTROL BY A CALL TO UPDATE CURSOR REQ_DSERV = TRANSFER COMPLETE REQ_SSERV = CP COMMAND!CALLED; !CALL NOT PON REQ_P1 = STREAM NO REQ_P2 = 0; !NEXT PAGE NOT REQD REQ_P3 = BUFFER_LENGTH-USER AREA_GOAH LEN COMMS CONTROL(REQ) !TELL SPOOLER WE HAVE FINISH & HOWMUCH IS AVAILABLE REQ_DSERV = STREAM_OWNER REQ_SSERV = CP COMMAND REQ_P1 = STREAM NO REQ_P2 = STREAM_CURSOR REQ_P3 = GPC ENTRY_RESP0 REQ_P4 = GPC ENTRY_RESP1 REQ_P5 = INTEGER(GPC ENTRY_SENSEAD) REQ_P6 = INTEGER(GPC ENTRY_SENSEAD+4) PON(REQ) %RETURN DACT(GO AHEAD): !TRANSFER GO AHEAD !IE COMMS HAS PAGED IN BUFFER USER AREA == RECORD(DEVICE TO UA AD(DEVICE NO)) BUFFER NO = P_P2 BUFFER == BUFFER TAB(BUFFER NO) USER AREA_GOAH LEN = BUFFER_LENGTH USER AREA_GOAH AD = BUFFER_OFFSET USER AREA_BUFFER NO = BUFFER NO PUNCH: !TRY TO PUNCH CARDS !COPY A CARD INTO USER AREA_CARD AND SPACEFILL. SPANNED CARDS HAVE !1ST PART IN BUFFER AND USER AREA_POSN INDICATES NEXT FREE BYTE. !USER AREA_POSN=80 INDICATES COMPLETE CARD IN BUFFER IN EBCDIC !AS HAPPENS AFTER AN ABNORMAL TERMINATION I = USER AREA_POSN -> FIRE %IF I = 80; !CARD ALL READY TO FIRE IO J = 0 %CYCLE SYM = BYTE INTEGER(VIRTUAL+(USER AREA_GOAH AD+J+BUFFER_ %C REAL ADDRESS)) %EXIT %IF SYM = NL %OR SYM = 12; !CONTROL CHAR !IF BUFFER FULL THEN TREAT AS NEWLINE EXCEPT ARRANGE FOR THE LAST CHAR !TO BECOME THE FIRST CHAR ON THE NEXT(OVERFLOW) CARD UNLIKE THE NL CHAR !WHICH IS DISCARDED. NB CARE NEEDED NOT TO GET BLANK CARD UNNECESSARILY %IF I >= 80 %THEN J = J-1 %AND %EXIT USER AREA_CARD(I) = SYM I = I+1 J = J+1 -> EPAGE USED %IF J > USER AREA_GOAH LEN %REPEAT !CONTROL CHAR FOUND USER AREA_GOAH LEN = USER AREA_GOAH LEN-(J+1) USER AREA_GOAH AD = USER AREA_GOAH AD+J+1 %WHILE I < 80 %THEN USER AREA_CARD(I) = ' ' %AND I = I+1 ITOE(ADDR(USER AREA_CARD(0)),80) USER AREA_POSN = 80; !CARD READ IN EBCDIC FIRE: REQ_DSERV = EXECUTE CHAIN REQ_SSERV = CP EXECUTED REQ_P1 = ADDR(USER AREA_RCB0) REQ_P2 = USER AREA_GPCSER REQ_P3 = 1<<4!1 PON(REQ) %RETURN EPAGE USED: !AWAIT NEXT GO AHEAD USER AREA_POSN = I; !SOME ISO CHARS IN BUFFER SENT = BUFFER_LENGTH REQ_DSERV = TRANSFER COMPLETE REQ_SSERV = CP COMMAND REQ_P1 = STREAM NO REQ_P2 = 1; !PLEASE PROVIDE NEXT PAGE REQ_P3 = SENT PON(REQ) %RETURN DACT(SEND CONTROL): !CONTROLL MESSAGE !P_P2=STATE MODE AND LENGTH STATE = P_P2>>24 REP_DSERV = COMMS REPLY!P_P1>>16 REP_P1 = STREAM NO; !SET UP REPLY TO COMMS %IF STATE = CONNECTING %THEN %START REQ_DSERV = ALLOCATE DEVICE REQ_SSERV = CP ALLOCATED REQ_P1 = M'CP0'!DEVICE NO REQ_P2 = 1; !PON DEVICE REPLIES GPC(REQ); !TRY TO ALLOCATE J = REQ_P1 REP_P2 = J; !PASS SUCCESS BACK TO COMMS %IF J = 0 %THEN %START; !ALLOCATED OK GPC ENTRY == RECORD(REQ_P3); !REMAP AREA USER AREA == RECORD(GPC ENTRY_UA AD) DEVICE TO UA AD(DEVICE NO) = ADDR(USER AREA) USER AREA_GPCSER = REQ_P2; !GPC PRIVATE IDENT USER AREA_LST0 = X'00010000' USER AREA_STREAM NO = STREAM NO USER AREA_MODE = 0; !PUNCH IN NON BINARY MODE USER AREA_RCB0 = X'0008C000' USER AREA_RCB1 = REALISE(ADDR(USER AREA_LST0)) USER AREA_RCB2 = 8; !BYTE OF LOGIC BLOCK USER AREA_RCB3 = ADDR(USER AREA_LBE0) USER AREA_RCB4 = 8; !BYTE OF ADDRESS LIST USER AREA_RCB5 = ADDR(USER AREA_ALE0) USER AREA_RCB6 = X'FF01'; !SET NR MODE USER AREA_RCB7 = 0 USER AREA_LBE0 = X'80000300' USER AREA_ALE0 = X'58000050' USER AREA_ALE1 = ADDR(USER AREA_CARD(0)) USER AREA_GOAH AD = 0 USER AREA_GOAH LEN = 0 USER AREA_POSN = 0 %FINISH %FINISH %IF STATE = DISCONNECTING %START REQ_DSERV = DEALLOCATE DEVICE REQ_SSERV = CP DEALLOCATED REQ_P1 = M'CP0'!DEVICE NO GPC(REQ) REP_P2 = REQ_P1; !FAIL FLAG BACK TO COMMS DEVICE TO UA AD(DEVICE NO) = NOT ALLOCATED %FINISH %IF STATE = ENABLING %START REQ_DSERV = REQUEST TRANSFER REQ_SSERV = CP COMMAND REQ_P1 = STREAM NO PON(REQ) %FINISH COMMS CONTROL(REP) %RETURN %END; !OF ROUTINE CP ADAPTOR !* !* %ENDOFFILE