! VERSION OF 04/12/79 ! DEC 79: INCLUDE AN OPER ADAPTOR ! HAVE ONLY ONE SERVICE NUMBER, X'37' ! OTHER POSSIBLE CHANGES ! MAKE INITIALISATION CALL OF CC INITIALISE ADAPTORS AS WELL ! MAKE IT POSSIBLE TO DEALLOCATE/ALLOCATE ALL DEVICES !* 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 * !*********************************************************************** !* !* GLOBAL CONSTANTS !* %CONSTINTEGER VIRTUAL = X'81000000' %CONSTINTEGER NOT ALLOCATED = X'F0F0F0F0' %CONSTINTEGER EMPTY = X'F0F0' %CONSTINTEGER ATTENTION = 1 %CONSTINTEGER NORMAL TERMINATION = 8 %CONSTINTEGER AUTO = X'00008400' %CONSTINTEGER EBC NL = 21 %CONSTINTEGER EBC LF = 37 %CONSTINTEGER EBC FF = 12 %CONSTINTEGER EBC CR = 13 %CONSTINTEGER EBC VP = 34 %IF SSERIES = NO %START %CONSTINTEGER EBC MS = 32 %FINISH %CONSTINTEGER EBC SP = 64 !* !* !* COMMS CONTROLLER ACTIVITIES !* %CONSTINTEGER INIT = 0 %CONSTINTEGER CONNECT = 1 %CONSTINTEGER CONNECT REPLY = 13 %CONSTINTEGER ENABLE = 2 %CONSTINTEGER CLAIM AMT INDEX REPLY = 14 %CONSTINTEGER ENABLE REPLY = 15 %CONSTINTEGER DISABLE = 4 %CONSTINTEGER DISABLE REPLY = 16 %CONSTINTEGER DISCONNECT = 5 %CONSTINTEGER DISCONNECT REPLY = 17 %CONSTINTEGER CONTROL MSG6 = 6 %CONSTINTEGER CONTROL MSG6 REPLY = 18 %CONSTINTEGER CONTROL MSG7 = 7 %CONSTINTEGER CONTROL MSG7 REPLY = 19 %CONSTINTEGER TRANSFER REQUESTED = 10 %CONSTINTEGER PAGE HERE = 11 %CONSTINTEGER TRANSFER COMPLETED = 12 !* !* COMMS CONTROLLER REQUESTS AND REPLY SERVICE NUMBERS !* %CONSTINTEGER COMMS COMMAND = X'00370000' %CONSTINTEGER CLAIM BLOCK = X'00080001' %CONSTINTEGER BLOCK CLAIMED = COMMS COMMAND!CLAIM AMT INDEX REPLY %CONSTINTEGER FREE BLOCK = X'00080002' %CONSTINTEGER CLAIM PAGE = X'00040001' %CONSTINTEGER PAGE CLAIMED = COMMS COMMAND!PAGE HERE %CONSTINTEGER FREE PAGE = X'00040002' %CONSTINTEGER REQUEST TRANSFER = COMMS COMMAND!TRANSFER REQUESTED %CONSTINTEGER TRANSFER COMPLETE = COMMS COMMAND!TRANSFER COMPLETED !* !* ADAPTOR ACTIVITIES !* %CONSTINTEGER DEALLOCATED = X'00000001' %CONSTINTEGER ALLOCATED = X'00000002' %CONSTINTEGER EXECUTE FAILS = X'00000003' %CONSTINTEGER INITIALISE = X'00000004' %CONSTINTEGER INTERRUPT = X'00000005' %CONSTINTEGER GO AHEAD = X'00000006' %CONSTINTEGER SEND CONTROL = X'00000007' !* !* ADAPTOR SERVICE NUMBERS !* %CONSTINTEGER OP SERVICE = X'32' %CONSTINTEGER LP SERVICE = X'33' %CONSTINTEGER CR SERVICE = X'34' %IF CP FITTED = YES %START %CONSTINTEGER CP SERVICE = X'35' %FINISH %CONSTINTEGER MK1 FE SERVICE = X'39' %CONSTINTEGER OP COMMAND = OP SERVICE<<16 %CONSTINTEGER LP COMMAND = LP SERVICE<<16 %CONSTINTEGER CR COMMAND = CR SERVICE<<16 %IF CP FITTED = YES %START %CONSTINTEGER CP COMMAND = CP SERVICE<<16 %FINISH %ELSE %START %CONSTINTEGER CP COMMAND = NOT ALLOCATED %FINISH %CONSTINTEGER MK1 FE COMMAND = MK1 FE SERVICE<<16 !* !* ADAPTOR REQUESTS AND REPLIES SERVICE NUMBERS !* %CONSTINTEGER GPC COMMAND = X'00300000' %CONSTINTEGER ALLOCATE DEVICE = GPC COMMAND!X'0000000B' %CONSTINTEGER LP ALLOCATED = LP COMMAND!ALLOCATED %CONSTINTEGER CR ALLOCATED = CR COMMAND!ALLOCATED %IF CP FITTED = YES %START %CONSTINTEGER CP ALLOCATED = CP COMMAND!ALLOCATED %FINISH %CONSTINTEGER MK1 FE ALLOCATED = MK1 FE COMMAND!ALLOCATED %CONSTINTEGER DEALLOCATE DEVICE = GPC COMMAND!X'00000005' %CONSTINTEGER LP DEALLOCATED = LP COMMAND!DEALLOCATED %CONSTINTEGER CR DEALLOCATED = CR COMMAND!DEALLOCATED %IF CP FITTED = YES %START %CONSTINTEGER CP DEALLOCATED = CP COMMAND!DEALLOCATED %FINISH %CONSTINTEGER MK1 FE DEALLOCATED = MK1 FE COMMAND!DEALLOCATED %CONSTINTEGER EXECUTE CHAIN = GPC COMMAND!X'0000000C' %CONSTINTEGER LP EXECUTED = LP COMMAND!EXECUTE FAILS %CONSTINTEGER CR EXECUTED = CR COMMAND!EXECUTE FAILS %IF CP FITTED = YES %START %CONSTINTEGER CP EXECUTED = CP COMMAND!EXECUTE FAILS %FINISH %CONSTINTEGER MK1 FE EXECUTED = MK1 FE COMMAND!EXECUTE FAILS %CONSTINTEGER LP INTERRUPT = LP COMMAND!INTERRUPT %CONSTINTEGER CR INTERRUPT = CR COMMAND!INTERRUPT %IF CP FITTED = YES %START %CONSTINTEGER CP INTERRUPT = CP COMMAND!INTERRUPT %FINISH %CONSTINTEGER MK1 FE INTERRUPT = MK1 FE COMMAND!INTERRUPT !* !* %IF MON LEVEL&2 # 0 %START %EXTRINSICLONGINTEGER KMON; !BIT 2**SNO IS SET WHEN SERVICE SNO IS TO BE MONITORED %FINISH !* %EXTERNALROUTINESPEC DUMP TABLE(%INTEGER TABLE, ADDRESS, LENGTH) %EXTERNALROUTINESPEC DPON(%RECORDNAME MESS, %INTEGER SECS) %EXTERNALROUTINESPEC PON(%RECORDNAME MESS) %EXTERNALROUTINESPEC GPC(%RECORDNAME MESS) %EXTERNALROUTINESPEC PT REC(%RECORDNAME MESS) %EXTERNALROUTINESPEC OP MESS(%STRING (63) S) %EXTERNALROUTINESPEC MONITOR(%STRING (63) S) %SYSTEMROUTINESPEC MOVE(%INTEGER LENGTH, FROM, TO) %SYSTEMROUTINESPEC ETOI(%INTEGER ADDRESS, LENGTH) %SYSTEMROUTINESPEC I TO E(%INTEGER ADDRESS, LENGTH) %EXTERNALINTEGERFNSPEC REALISE(%INTEGER VIRTUAL ADDRESS) %EXTERNALINTEGERFNSPEC NEW PP CELL !* !* %IF MULTI OCP = NO %START %ROUTINESPEC COMMS CONTROL(%RECORDNAME MESS) %ROUTINESPEC MK1 FE ADAPTOR(%RECORDNAME MESS) %FINISH %EXTERNALROUTINESPEC RETURN PP CELL(%INTEGER CELL) !* !* %IF MON LEVEL&256 # 0 %START; !include harvesting? %EXTERNALROUTINESPEC HARVEST( %C %INTEGER EVENT, PROCESS, LEN, A, B, C, D, E) %EXTRINSICINTEGER TRACE EVENTS %EXTRINSICINTEGER TRACE PROCESS %EXTRINSICINTEGER TRACE %FINISH !* !* !*********************************************************************** !* * !* 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 OPER ADAPTOR * !* 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 = MAXPROCS*4-1 %OWNINTEGERARRAY STREAM INDEX(0 : MAX STREAM) = %C EMPTY(MAX STREAM+1) %OWNRECORDARRAYFORMAT SARF(0 : 4095)(SR); !MAPPED ONTO PARM TABLE %OWNRECORDARRAYNAME STREAM TAB(SR); !STREAM TABLE ARRAY %OWNRECORDARRAYFORMAT BARF(0 : 4095)(BR); !MAPPED ONTO THE PARM TABLE %OWNRECORDARRAYNAME BUFFER TAB(BR); !BUFFER TABLE ARRAY %OWNRECORDARRAYFORMAT PARF(0 : 4095)(PARMF); !MAPPED ONTO PARM TABLE %OWNRECORDARRAYNAME PARM TAB(PARMF); !PARM TABLE ARRAY %OWNRECORDNAME COM AREA(COMF) %OWNRECORD COMMS(COMMS INFF) !* !* %IF SFC FITTED = YES %START %CONSTINTEGER DRUM UPDATE = 5; !DRUM UPDATE AND RECAPTURE %FINISH %ELSE %START %CONSTINTEGER DRUM UPDATE = 1; !ONLY RECAPTURE %FINISH %CONSTINTEGER NO DRUM UPDATE = 0; !NO DRUM UPDATE AND NO RECAPTURE !* %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 OP = 8 %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,OP COMMAND, NOT ALLOCATED(5),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 SPACE 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. * !* * !*********************************************************************** !* !* %IF MON LEVEL&256 # 0 %START; !include harvesting? %INTEGER PROC NO %FINISH !* !* %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(INIT : CONTROL MSG7 REPLY) !* !* %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 * !*********************************************************************** !* !** MONITOR !* %IF MON LEVEL&2 # 0 %AND (KMON>>(COMMS COMMAND>>16))&1 # 0 %START PRINT STRING("Comms Control: ") PT REC(MESS) %FINISH !* !* DSERV = MESS_DSERV DACT = DSERV&SHORT MASK -> COM(DACT) %IF DACT <= CONNECT; !CONNECT OR INIT? STREAM NO = MESS_P1; !PULL OUT STREAM NUMBER FIRST ALWAYS IN P1 %IF 0 < STREAM NO <= MAX STREAM %START; !WITHIN RANGE? TEMP = STREAM INDEX(STREAM NO) %IF TEMP # EMPTY %START; !ALLOCATED? STREAM == STREAM TAB(TEMP) %IF DACT < TRANSFER REQUESTED %C %THEN STREAM_CALLER = MESS_SSERV %C %ELSE STATUS = MESS_P2 %IF MON LEVEL&256 # 0 %START; !include harvesting? PROC NO = ((STREAM_OWNER>>16)-64)&(MAX PROCS-1) %FINISH -> COM(DACT) %FINISH %FINISH NO STREAM: PRINT STRING("Comms Control: Stream not allocated ") PT REC(MESS) %RETURN %UNLESS DACT < TRANSFER REQUESTED MESS_DSERV = MESS_SSERV; !REPLY TO CALLER MESS_SSERV = DSERV MESS_P2 = UNSUCCESSFUL PON(MESS) %RETURN !* !* !* !*********************************************************************** !* * !* THIS SECTION HANDLES: * !* 1). COMMUNICATIONS CONTROLLER INITIALISATION * !* * !*********************************************************************** !* !* COM(INIT):!** COMMAND: INITIALISE 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 !* !* !* !*********************************************************************** !* * !* 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 STREAM NO = MESS_P1&1; !MAKE EVEN OR ODD I.E. INPUT OR OUTPUT %CYCLE STREAM NO = STREAM NO+2,2,MAX STREAM-(1-STREAM NO) %IF STREAM INDEX(STREAM NO) = EMPTY %START; !FOUND A FREE STREAM 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 %IF MON LEVEL&256 # 0 %START; !include harvesting? PROC NO = ((STREAM_OWNER>>16)-64)&(MAX PROCS-1) HARVEST(14,PROC NO,8,STREAM NO,MESS_P3,0,0,0) %C %IF TRACE = YES %AND TRACE EVENTS!1<<14 # 0 %C %AND (TRACE PROCESS = -1 %C %OR TRACE PROCESS = PROC NO) %FINISH 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_AMT INDEX = NOT ALLOCATED STREAM_LINK = EMPTY STREAM_STATE = CONNECTING -> UPDATE ADAPTOR %FINISH %REPEAT -> NO STREAM !* !* COM(CONNECT REPLY):!** ADAPTOR REPLY: STREAM CONNECTED %IF MON LEVEL&256 # 0 %START; !include harvesting? HARVEST(15,PROC NO,4,STREAM NO,0,0,0,0) %C %IF TRACE = YES %AND TRACE EVENTS!1<<15 # 0 %C %AND (TRACE PROCESS = -1 %OR TRACE PROCESS = PROC NO) %FINISH %IF STATUS = SUCCESSFUL %START STREAM_STATE = CONNECTED -> REPLY TO CALLER %FINISH %ELSE -> RETURN CELL !* !* COM(ENABLE):!** COMMAND: ENABLE STREAM %IF MON LEVEL&256 # 0 %START; !include harvesting? HARVEST(16,PROC NO,12,STREAM NO,MESS_P4&BYTE MASK,MESS_ %C P6,0,0) %IF TRACE = YES %C %AND TRACE EVENTS!1<<16 # 0 %C %AND (TRACE PROCESS = -1 %OR TRACE PROCESS = PROC NO) %FINISH %IF STREAM_STATE = CONNECTED %START STREAM_STATE = CLAIMING STREAM_MODE = MESS_P4&BYTEMASK STREAM_LENGTH = MESS_P6-1 %IF STREAM_MODE&15 = 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 !* !* COM(CLAIM AMT INDEX REPLY):!** GLOBAL CONTROLLER REPLY: BLOCK CLAIMED %IF MON LEVEL&256 # 0 %START; !include harvesting? HARVEST(17,PROC NO,8,STREAM NO,STATUS,0,0,0) %C %IF TRACE = YES %AND TRACE EVENTS!1<<17 # 0 %C %AND (TRACE PROCESS = -1 %OR TRACE PROCESS = PROC NO) %FINISH %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 !* !* COM(ENABLE REPLY):!** ADAPTOR REPLY: STREAM ENABLED %IF MON LEVEL&256 # 0 %START; !include harvesting? HARVEST(18,PROC NO,4,STREAM NO,0,0,0,0) %C %IF TRACE = YES %AND TRACE EVENTS!1<<18 # 0 %C %AND (TRACE PROCESS = -1 %OR TRACE PROCESS = PROC NO) %FINISH %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 MON LEVEL&256 # 0 %START; !include harvesting? HARVEST(19,PROC NO,12,STREAM NO,MESS_P2,STREAM_STATE,0,0 %C ) %IF TRACE = YES %AND TRACE EVENTS!1<<19 # 0 %C %AND (TRACE PROCESS = -1 %OR TRACE PROCESS = PROC NO) %FINISH %IF STREAM_STATE >= ENABLED %C %AND SUSPENDING <= MESS_P2 <= ABORTING %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 !* !* COM(DISABLE REPLY):!** ADAPTOR REPLY: DISABLED %IF MON LEVEL&256 # 0 %START; !include harvesting? HARVEST(20,PROC NO,4,STREAM NO,0,0,0,0) %C %IF TRACE = YES %AND TRACE EVENTS!1<<20 # 0 %C %AND (TRACE PROCESS = -1 %OR TRACE PROCESS = PROC NO) %FINISH STREAM_STATE = CONNECTED STATUS = SUCCESSFUL; !ALWAYS SUCCESSFUL -> REPLY TO CALLER !* !* COM(DISCONNECT):!** COMMAND: DISCONNECT STREAM %IF MON LEVEL&256 # 0 %START; !include harvesting? HARVEST(21,PROC NO,4,STREAM NO,0,0,0,0) %C %IF TRACE = YES %AND TRACE EVENTS!1<<21 # 0 %C %AND (TRACE PROCESS = -1 %OR TRACE PROCESS = PROC NO) %FINISH %IF STREAM_STATE = CONNECTED %START STREAM_STATE = DISCONNECTING -> UPDATE ADAPTOR %FINISH %ELSE STATUS = UNSUCCESSFUL -> REPLY TO CALLER !* !* COM(DISCONNECT REPLY):!** ADAPTOR REPLY: STREAM DISCONNECTED %IF MON LEVEL&256 # 0 %START; !include harvesting? HARVEST(22,PROC NO,4,STREAM NO,0,0,0,0) %C %IF TRACE = YES %AND TRACE EVENTS!1<<22 # 0 %C %AND (TRACE PROCESS = -1 %OR TRACE PROCESS = PROC NO) %FINISH STATUS = SUCCESSFUL; !ALWAYS SUCCESSFUL -> RETURN CELL !* !* COM(CONTROL MSG6):!** COMMAND: SEND HIGH LEVEL CONTROL MESSAGE WHICH GENERATES NO REPLY %IF MON LEVEL&256 # 0 %START; !include harvesting? HARVEST(23,PROC NO,12,STREAM NO,DACT,STREAM_STATE,0,0) %C %IF TRACE = YES %AND TRACE EVENTS!1<<23 # 0 %C %AND (TRACE PROCESS = -1 %OR TRACE PROCESS = PROC NO) %FINISH MESS_SSERV = COMMS COMMAND!CONTROL MSG6 REPLY -> PON ADAPTOR !* !* COM(CONTROL MSG7):!** COMMAND: SEND HIGH LEVEL CONTROL MESSAGE WHICH GENERATES A REPLY %IF MON LEVEL&256 # 0 %START; !include harvesting? HARVEST(23,PROC NO,12,STREAM NO,DACT,STREAM_STATE,0,0) %C %IF TRACE = YES %AND TRACE EVENTS!1<<23 # 0 %C %AND (TRACE PROCESS = -1 %OR TRACE PROCESS = PROC NO) %FINISH MESS_SSERV = COMMS COMMAND!CONTROL MSG7 REPLY -> PON ADAPTOR !* !* !* !* !* !*********************************************************************** !* * !* 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. * !* * !*********************************************************************** !* !* COM(TRANSFER REQUESTED):!** ADAPTOR REQUEST: TRANSFER REQUEST %IF STREAM_STATE = ENABLED %START; !IGNORE IF SUSPENDING OR ABORTING STREAM_CURSOR = STATUS&SHORT MASK %C %IF STATUS # 0 %AND STREAM_MODE&15 = CIRCULAR %AND %C 0 <= STATUS&SHORT MASK <= STREAM_LENGTH %IF COMMS_NEXT FREE BUFFER = EMPTY %START; !NO BUFFER AVAILABLE %IF MON LEVEL&256 # 0 %START; !include harvesting? HARVEST(27,PROC NO,4,STREAM NO,0,0,0,0) %C %IF TRACE = YES %AND TRACE EVENTS!1<<27 # 0 %C %AND (TRACE PROCESS = -1 %C %OR TRACE PROCESS = PROC NO) %FINISH 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 = 0 BUFFER_LINK = EMPTY STREAM_LINK = BUFFER NO GET PAGE(STREAM NO) %FINISH %FINISH %RETURN !* !* COM(PAGE HERE):!** GLOBAL CONTROLLER REPLY: CURRENT OWNER'S PAGE HERE %IF STREAM_STATE = PAGING IN %START;!CHECK BUFFER NOT DISABLED (SUSPEND OR ABORT) %IF MON LEVEL&256 # 0 %START;!include harvesting? HARVEST(30, PROC NO, 8, STREAM NO, %C (MESS_SSERV&255)<<24!(MESS_P5&255)<<16!(MESS_P6&SHORT MASK),0 ,0, 0) %IF %C TRACE = YES %AND TRACE EVENTS!1<<30 # 0 %AND (TRACE PROCESS = -1 %C %OR TRACE PROCESS = PROC NO) %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 MONITOR("COMMS DEADLOCK PAGE?") %IF STATUS = -1 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 MESS_P5 = STREAM_DEVICE NO; ! for use by OPER %IF MULTI OCP = NO %AND STREAM_ADAPTOR NO = FE %THEN %C MK1 FE ADAPTOR(MESS) %ELSE PON(MESS) %RETURN %FINISH %ELSE %START; !BUFFER DISABLED BUFFER NO = STREAM_LINK BUFFER == BUFFER TAB(BUFFER NO) RELEASE BUFFER(NO DRUM UPDATE) RELEASE BLOCK -> UPDATE ADAPTOR %FINISH !* !* COM(TRANSFER COMPLETED):!** ADAPTOR REPLY: TRANSFER COMPLETE %IF MON LEVEL&256 # 0 %START; !include harvesting? HARVEST(31,PROC NO,12,STREAM NO,MESS_P2,MESS_P3,0,0) %C %IF TRACE = YES %AND TRACE EVENTS!1<<31 # 0 %C %AND (TRACE PROCESS = -1 %OR TRACE PROCESS = PROC NO) %FINISH !* !* P2 HAS BITS SET WITH SIGNIFICANCE 2**0 NEXT PAGE REQUIRED !* 2**1 PAGE NOT ELIGIBLE FOR RECAPTURE !* 2**2 UPDATE USERS CURSOR !* P3 HAS NUMBER OF BYTES TRANSFERED !* 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 (WRAP ROUND OR SUSPEND) %IF STREAM_MODE&15 = CIRCULAR %C %THEN STREAM_CURSOR = 0 %ELSE STREAM_STATE = SUSPENDING %FINISH %IF STREAM_STATE = ACTIVE %START; !CHECK NOT DISABLED (SUSPEND OR ABORT) %IF STATUS&1 # 0 %START; !GET THE NEXT PAGE. RELEASE PAGE(NO DRUM UPDATE); !RELEASE PAGE TO GET ANOTHER GET PAGE(STREAM NO) %RETURN %FINISH %FINISH %ELSE %START; !DISABLED (SUSPEND OR ABORT) RELEASE BUFFER(NO DRUM UPDATE) RELEASE BLOCK -> UPDATE ADAPTOR %FINISH %FINISH %IF STATUS&2 = 0 %THEN TEMP = DRUM UPDATE %C %ELSE TEMP = NO DRUM UPDATE RELEASE BUFFER(TEMP) STREAM_STATE = ENABLED %IF STATUS&4 # 0 %START; !UPDATE USERS CURSOR MESS_DSERV = STREAM_OWNER MESS_SSERV = DSERV MESS_P2 = STREAM_CURSOR MESS_P3 = 0;!MUST BE ZERO OTHERWISE SIGNIFIES AN ABORT PON(MESS) %FINISH %RETURN !* !* UPDATE ADAPTOR: !SEND LOW LEVEL CONTROL INFO TO THE ADAPTOR MESS = 0 MESS_P1 = SUB IDENT(STREAM_STATE)!STREAM NO MESS_P2 = STREAM_STATE<<24!STREAM_MODE<<16!(STREAM_LENGTH& %C X'FFFF') MESS_P3 = STREAM_CURSOR MESS_P4 = STREAM INDEX(STREAM NO); ! when connecting, set to cell MESS_P5 = STREAM_DEVICE NO; ! for OPER MESS_P6 = STREAM_LENGTH MESS_SSERV = DSERV PON ADAPTOR: MESS_DSERV = SEND CONTROL!ADAPT(STREAM_ADAPTOR NO) %IF MULTI OCP = NO %AND STREAM_ADAPTOR NO = FE %THEN %C MK1 FE ADAPTOR(MESS) %ELSE PON(MESS) %RETURN !* !* COM(CONTROL MSG6 REPLY):!** ADAPTOR REPLY: CONTROL MESSAGE 6 REPLY %IF MON LEVEL&256 # 0 %START; !include harvesting? HARVEST(24,PROC NO,12,STREAM NO,DACT-12,STREAM_STATE,0,0) %C %IF TRACE = YES %AND TRACE EVENTS!1<<24 # 0 %C %AND (TRACE PROCESS = -1 %OR TRACE PROCESS = PROC NO) %FINISH %IF STATUS = SUCCESSFUL %THEN %RETURN %ELSE -> REPLY TO CALLER !* !* COM(CONTROL MSG7 REPLY):!** ADAPTOR REPLY: CONTROL MESSAGE 7 REPLY %IF MON LEVEL&256 # 0 %START; !include harvesting? HARVEST(24,PROC NO,12,STREAM NO,DACT-12,STREAM_STATE,0,0) %C %IF TRACE = YES %AND TRACE EVENTS!1<<24 # 0 %C %AND (TRACE PROCESS = -1 %OR TRACE PROCESS = PROC NO) %FINISH !* !* !* REPLY TO CALLER: STREAM NO = -1 RETURN CELL: MESS_SSERV = DSERV MESS_DSERV = STREAM_CALLER MESS_P2 = STATUS MESS_P3 = STREAM_OWNER MESS_P4 = STREAM_STATE MESS_P5 = STREAM_CURSOR PON(MESS) %UNLESS STREAM NO < 0 %START RETURN PP CELL(STREAM INDEX(STREAM NO)) STREAM INDEX(STREAM NO) = EMPTY %FINISH %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 ELIGIBLE FOR RECAPTURE. * !* 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 = DSERV MESS_P1 = BUFFER_AMT INDEX; !INDEX<<16!EPAGE MESS_P2 = (1-(STREAM NO&1))<<3!DRUM UP %IF MON LEVEL&256 # 0 %START; !include harvesting? HARVEST(25,PROC NO,12,STREAM NO,MESS_P1,MESS_P2,0,0) %C %IF TRACE = YES %AND TRACE EVENTS!1<<25 # 0 %C %AND (TRACE PROCESS = -1 %OR TRACE PROCESS = PROC NO) %FINISH 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) %IF MON LEVEL&256 # 0 %START; !include harvesting? HARVEST(28,PROC NO,4,TEMPST NO,0,0,0,0) %C %IF TRACE = YES %AND TRACE EVENTS!1<<28 # 0 %C %AND (TRACE PROCESS = -1 %OR TRACE PROCESS = PROC NO) %FINISH 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 %IF MON LEVEL&256 # 0 %START; !include harvesting? HARVEST(29,PROC NO,12,STREAM NO,MESS_P1,BUFFER_LENGTH,0 %C ,0) %IF TRACE = YES %AND TRACE EVENTS!1<<29 # 0 %C %AND (TRACE PROCESS = -1 %OR TRACE PROCESS = PROC NO) %FINISH 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) MESS = 0 MESS_DSERV = FREE BLOCK MESS_SSERV = DSERV MESS_P1 = STREAM NO MESS_P2 = STREAM_AMT INDEX>>16 %IF MON LEVEL&256 # 0 %START; !include harvesting? HARVEST(26,PROC NO,8,STREAM NO,MESS_P2,0,0,0) %C %IF TRACE = YES %AND TRACE EVENTS!1<<26 # 0 %C %AND (TRACE PROCESS = -1 %OR TRACE PROCESS = PROC NO) %FINISH 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 ON ALLOCATION * !*********************************************************************** %RECORDSPEC MESS(PE) %IF SSERIES = NO %START %RECORDFORMAT DAF(%INTEGER LST0, LST1, RCB0, RCB1, RCB2, %C RCB3, RCB4, RCB5, RCB6, RCB7, LB0, LB1, AL00, AL01, %C AL10, AL11, STREAM, NAME, COB START, COB INDEX, %C HEAD, TAIL, IDENT, CO HEAD, CO TAIL, MAX QD TRANSFERS, %C MAX QD CONTROL MSGS, TOTAL QD TRANSFERS, TOTAL QD CONTROL MSGS, %C BYTES OF CONTROL INPUT, BYTES OF CONTROL OUTPUT, BYTES OF DATA INPUT, %C BYTES OF DATA OUTPUT, CONTROL INPUT TRANSFERS, %C CONTROL OUTPUT TRANSFERS, DATA INPUT TRANSFERS, %C DATA OUTPUT TRANSFERS, OUTPUT UPDATES, UPDATE OVERWRITES, %C CONTROL INPUT XBIT SET, CONTROL OUTPUT XBIT SET, %C DATA INPUT XBIT SET, DATA OUTPUT XBIT SET, %C %BYTEINTEGER ATTN SET, SPARE, DEVICE NO, FAILURES, %C %BYTEINTEGERARRAY CIB, COB(0 : 167)) %FINISH %ELSE %START %RECORDFORMAT DAF(%INTEGER TCB0 COMMAND, TCB0 STE, %C TCB0 LENGTH, TCB0 ADDRESS, TCB0 NEXT TCB, %C TCB0 RESPONSE, %INTEGERARRAY TCB0 PREAMBLE, %C TCB0 POSTAMBLE(0 : 3), %C %INTEGER TCB1 COMMAND, TCB1 STE, TCB1 LENGTH, %C TCB1 ADDRESS, TCB1 NEXT TCB, TCB1 RESPONSE, %C %INTEGERARRAY TCB1 PREAMBLE, TCB1 POSTAMBLE(0 : 3), %C %INTEGER STREAM, NAME, COB START, COB INDEX, HEAD, %C TAIL, QUEUED TRANSFERS, IDENT, CO HEAD, CO TAIL, %C %BYTEINTEGER ATTN SET, SPARE, DEVICE NO, FAILURES, %C %BYTEINTEGERARRAY CIB, COB(0 : 167)) %FINISH %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 DA AD(0 : 9) = %C NOT ALLOCATED(10) %CONSTINTEGER CIB LENGTH = 168; !7 CONTROL MESSAGES %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 %IF SSERIES = NO %START %CONSTINTEGER LONG BLOCK MASK = X'0400' %CONSTINTEGER X MASK = X'0200' %CONSTINTEGER Y MASK = X'0100' %FINISH %ELSE %START %CONSTINTEGER LONG BLOCK MASK = X'04000000' %CONSTINTEGER X MASK = X'02000000' %CONSTINTEGER Y MASK = X'01000000' %FINISH %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, X, %C INTERRUPT ANALYSIS FLAGS, XBIT SET %RECORD GPC REQ(PE) %RECORD CMES(PE) %RECORDNAME GPC ENTRY(GPCF) %RECORDNAME DEVICE AREA(DAF) %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) %IF SSERIES = NO %START %CONSTINTEGERARRAY LB MASK(0 : 1) = %C X'00F00202', X'80F00302' %FINISH %ELSE %START %CONSTINTEGERARRAY LB MASK(0 : 1) = %C X'2F004002', X'2F004083' %FINISH %IF SSERIES = NO %START DEVICE AREA_LST1 = X'80000001'!REAL ADDRESS DEVICE AREA_LB1 = LB MASK(STREAM NO&1) DEVICE AREA_AL10 = LENGTH DEVICE AREA_AL11 = START %FINISH %ELSE %START DEVICE AREA_TCB0 RESPONSE = 0 DEVICE AREA_TCB1 COMMAND = LB MASK(STREAM NO&1) %IF REAL ADDRESS = 0 %THEN DEVICE AREA_TCB1 STE = %C DEVICE AREA_TCB0 STE %ELSE DEVICE AREA_TCB1 STE = %C REAL ADDRESS!1 DEVICE AREA_TCB1 LENGTH = LENGTH DEVICE AREA_TCB1 ADDRESS = START DEVICE AREA_TCB1 RESPONSE = 0 %FINISH DEVICE AREA_STREAM = STREAM NO DEVICE AREA_NAME = EXT STREAM NO<<16!LENGTH GPC REQ = 0 GPC REQ_DSERV = EXECUTE CHAIN GPC REQ_SSERV = MK1 FE EXECUTED %IF SSERIES = NO %START GPC REQ_P1 = ADDR(DEVICE AREA_RCB0) %FINISH %ELSE %START GPC REQ_P1 = ADDR(DEVICE AREA_TCB0 COMMAND) %FINISH GPC REQ_P2 = DEVICE AREA_IDENT %IF SSERIES = NO %START GPC REQ_P3 = X'11'; !PAW FUNCTION<<4!SAW FLAGS %FINISH %IF MULTI OCP = NO %THEN GPC(GPC REQ) %ELSE PON(GPC REQ) %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 DEVICE AREA_CO HEAD = EMPTY %C %THEN DEVICE AREA_CO HEAD = TEMP %C %ELSE PARM TAB(DEVICE AREA_CO TAIL)_LINK = TEMP PARM CELL_LINK = EMPTY DEVICE AREA_CO TAIL = TEMP %IF MON LEVEL&4 # 0 %START DEVICE AREA_TOTAL QD CONTROL MSGS = DEVICE AREA_ %C TOTAL QD CONTROL MSGS+1 L = DEVICE AREA_CO HEAD F = 1 %WHILE L # DEVICE AREA_CO TAIL %CYCLE F = F+1 L = PARM TAB(L)_LINK %REPEAT %IF F > DEVICE AREA_MAX QD CONTROL MSGS %C %THEN DEVICE AREA_MAX QD CONTROL MSGS = F %FINISH %END; !OF ROUTINE QUEUE !* !* !*********************************************************************** !* MAIN PROGRAM * !*********************************************************************** %IF MON LEVEL&2 # 0 %AND (KMON>>MK1 FE SERVICE)&1 # 0 %START PRINT STRING("Mk1 FE Adaptor: ") PT REC(MESS) %FINISH DACT = MESS_DSERV&SHORT MASK %IF DACT = INTERRUPT %START; !FROM GPC MESS_P3=GPC AREA ADRRESS INTERRUPT ANALYSIS FLAGS = MESS_P1>>20&15 GPC ENTRY == RECORD(MESS_P3); !MAP DEVICE AREA DEVICE AREA == RECORD(GPC ENTRY_UA AD);!MAP PRIVATE DEVICE AREA DEVICE NO = DEVICE AREA_DEVICE NO STREAM NO = DEVICE AREA_STREAM %FINISH %ELSE %START %IF DACT >= GO AHEAD %START; !FROM COMMS MESS_P1=STRM&SHORT MASK STREAM NO = MESS_P1&SHORT MASK STREAM == STREAM TAB(STREAM INDEX(STREAM NO)) DEVICE NO = STREAM_DEVICE NO %IF DEVICE TO DA AD(DEVICE NO) = NOT ALLOCATED %START !SEND FAILURE REPLIES CMES = 0 %IF MESS_P1&TOP SHORT MASK # 0 %C %THEN CMES_DSERV = COMMS COMMAND!MESS_P1>>16 %C %ELSE CMES_DSERV = MESS_SSERV CMES_SSERV = MESS_DSERV CMES_P1 = STREAM NO CMES_P2 = 1 PON(CMES) %RETURN %FINISH %ELSE DEVICE AREA == RECORD(DEVICE TO DA AD( %C DEVICE NO)) %FINISH %FINISH -> ACT(DACT) !* !* ACT(0):!** PRINT MONITORING IF COLLECTED %IF MON LEVEL&4 # 0 %START %CYCLE DEVICE NO = 0,1,9 %IF DEVICE TO DA AD(DEVICE NO) # NOT ALLOCATED %START DEVICE AREA == RECORD(DEVICE TO DA AD(DEVICE NO)) NEWLINES(2) PRINT STRING("FE".TO STRING(DEVICE NO+'0'). %C " Log Bytes Transfers XBIT Set Bytes/Transfer") NEWLINE PRINT STRING("Data Input ") F = DEVICE AREA_BYTES OF DATA INPUT WRITE(DEVICE AREA_BYTES OF DATA INPUT,10) T = DEVICE AREA_DATA INPUT TRANSFERS WRITE(DEVICE AREA_DATA INPUT TRANSFERS,10) X = DEVICE AREA_DATA INPUT XBIT SET WRITE(DEVICE AREA_DATA INPUT XBIT SET,10) WRITE(DEVICE AREA_BYTES OF DATA INPUT// %C DEVICE AREA_DATA INPUT TRANSFERS,10) %C %IF DEVICE AREA_DATA INPUT TRANSFERS # 0 NEWLINE PRINT STRING("Data Output ") F = F+DEVICE AREA_BYTES OF DATA OUTPUT WRITE(DEVICE AREA_BYTES OF DATA OUTPUT,10) T = T+DEVICE AREA_DATA OUTPUT TRANSFERS WRITE(DEVICE AREA_DATA OUTPUT TRANSFERS,10) X = X+DEVICE AREA_DATA OUTPUT XBIT SET WRITE(DEVICE AREA_DATA OUTPUT XBIT SET,10) WRITE(DEVICE AREA_BYTES OF DATA OUTPUT// %C DEVICE AREA_DATA OUTPUT TRANSFERS,10) %C %IF DEVICE AREA_DATA OUTPUT TRANSFERS # 0 NEWLINE PRINT STRING("Control Input ") F = F+DEVICE AREA_BYTES OF CONTROL INPUT WRITE(DEVICE AREA_BYTES OF CONTROL INPUT,10) T = T+DEVICE AREA_CONTROL INPUT TRANSFERS WRITE(DEVICE AREA_CONTROL INPUT TRANSFERS,10) X = X+DEVICE AREA_CONTROL INPUT XBIT SET WRITE(DEVICE AREA_CONTROL INPUT XBIT SET,10) WRITE(DEVICE AREA_BYTES OF CONTROL INPUT// %C DEVICE AREA_CONTROL INPUT TRANSFERS,10) %C %IF DEVICE AREA_CONTROL INPUT TRANSFERS # 0 NEWLINE PRINT STRING("Control Output ") F = F+DEVICE AREA_BYTES OF CONTROL OUTPUT WRITE(DEVICE AREA_BYTES OF CONTROL OUTPUT,10) T = T+DEVICE AREA_CONTROL OUTPUT TRANSFERS WRITE(DEVICE AREA_CONTROL OUTPUT TRANSFERS,10) X = X+DEVICE AREA_CONTROL OUTPUT XBIT SET WRITE(DEVICE AREA_CONTROL OUTPUT XBIT SET,10) WRITE(DEVICE AREA_BYTES OF CONTROL OUTPUT// %C DEVICE AREA_CONTROL OUTPUT TRANSFERS,10) %C %IF DEVICE AREA_CONTROL OUTPUT TRANSFERS # 0 NEWLINE PRINT STRING("Totals ") WRITE(F,10) WRITE(T,10) WRITE(X,10) WRITE(F//T,10) %IF T # 0 NEWLINE PRINT STRING("Output Updates ") WRITE(DEVICE AREA_OUTPUT UPDATES,10) NEWLINE PRINT STRING("Update Overwrites") WRITE(DEVICE AREA_UPDATE OVERWRITES,8) NEWLINE PRINT STRING("Overwrite Ratio") %IF DEVICE AREA_UPDATE OVERWRITES > 0 %THEN %C WRITE(DEVICE AREA_OUTPUT UPDATES//DEVICE AREA_ %C UPDATE OVERWRITES,10) %ELSE WRITE(0,10) PRINT STRING(":1") NEWLINE PRINT STRING("Queued Transfers") WRITE(DEVICE AREA_TOTAL QD TRANSFERS,9) NEWLINE PRINT STRING("Queued Control ") WRITE(DEVICE AREA_TOTAL QD CONTROL MSGS,10) NEWLINE PRINT STRING("Max Queued Trans") WRITE(DEVICE AREA_MAX QD TRANSFERS,9) NEWLINE PRINT STRING("Max Queued Control") WRITE(DEVICE AREA_MAX QD CONTROL MSGS,8) NEWLINES(2) DEVICE AREA_MAX QD TRANSFERS = 0 DEVICE AREA_MAX QD CONTROL MSGS = 0 DEVICE AREA_TOTAL QD TRANSFERS = 0 DEVICE AREA_TOTAL QD CONTROL MSGS = 0 DEVICE AREA_BYTES OF CONTROL INPUT = 0 DEVICE AREA_BYTES OF CONTROL OUTPUT = 0 DEVICE AREA_BYTES OF DATA INPUT = 0 DEVICE AREA_BYTES OF DATA OUTPUT = 0 DEVICE AREA_CONTROL INPUT TRANSFERS = 0 DEVICE AREA_CONTROL OUTPUT TRANSFERS = 0 DEVICE AREA_DATA INPUT TRANSFERS = 0 DEVICE AREA_DATA OUTPUT TRANSFERS = 0 DEVICE AREA_OUTPUT UPDATES = 0 DEVICE AREA_UPDATE OVERWRITES = 0 DEVICE AREA_CONTROL INPUT XBIT SET = 0 DEVICE AREA_CONTROL OUTPUT XBIT SET = 0 DEVICE AREA_DATA INPUT XBIT SET = 0 DEVICE AREA_DATA OUTPUT XBIT SET = 0 %FINISH %REPEAT %FINISH %RETURN !* !* ACT(INTERRUPT):!** DEVICE INTERRUPT (NORMAL, ABNORMAL OR ATTENTION) -> ATTEN %IF INTERRUPT ANALYSIS FLAGS = ATTENTION -> ABNORMAL TERMINATION %UNLESS INTERRUPT ANALYSIS FLAGS& %C NORMAL TERMINATION = NORMAL TERMINATION !** NORMAL TERMINATION INTERRUPT %IF DEVICE AREA_FAILURES # 0 %START OP MESS("FE".TO STRING(DEVICE NO+'0'). %C " Transfer Recovered") DEVICE AREA_FAILURES = 0 %FINISH !* !* %IF SSERIES = NO %START LENGTH = DEVICE AREA_AL10-GPC ENTRY_RESP1&SHORT MASK !NUMBER OF BYTES TRANSFERED XBIT SET = GPC ENTRY_RESP0&X MASK %FINISH %ELSE %START LENGTH = DEVICE AREA_TCB1 LENGTH-DEVICE AREA_ %C TCB1 RESPONSE&SHORT MASK !NUMBER OF BYTES TRANSFERED XBIT SET = DEVICE AREA_TCB1 RESPONSE&X MASK %FINISH !* !* %IF STREAM NO = CONTROL OUT %START; !CONTROL OUTPUT TERMINATION %IF MON LEVEL&4 # 0 %START DEVICE AREA_BYTES OF CONTROL OUTPUT = DEVICE AREA_ %C BYTES OF CONTROL OUTPUT+LENGTH DEVICE AREA_CONTROL OUTPUT TRANSFERS = DEVICE AREA_ %C CONTROL OUTPUT TRANSFERS+1 DEVICE AREA_CONTROL OUTPUT XBIT SET = DEVICE AREA_ %C CONTROL OUTPUT XBIT SET + 1 %IF XBIT SET # 0 %FINISH DEVICE AREA_COB INDEX = DEVICE AREA_COB INDEX-LENGTH !*MC MOVE(DEVICE AREA_COB INDEX,ADDR(DEVICE AREA_COB(LENGTH)), %C ADDR(DEVICE AREA_COB(0))) %IF DEVICE AREA_COB INDEX > 0 !SHUFFLE DOWN? %IF DEVICE AREA_COB INDEX > 0 %START L = DEVICE AREA_COB INDEX F = ADDR(DEVICE AREA_COB(LENGTH)) T = ADDR(DEVICE AREA_COB(0)) *LDTB_X'18000000' *LDB_L *LDA_F *CYD_0 *LDA_T *MV_%L=%DR %FINISH DEVICE AREA_COB START = 0 %WHILE DEVICE AREA_CO HEAD # EMPTY %C %AND DEVICE AREA_COB INDEX < COB LENGTH %CYCLE PARM CELL == PARM TAB(DEVICE AREA_CO HEAD) !*MC MOVE(CONTROL MSG LENGTH,ADDR(PARM CELL_P1),ADDR( %C DEVICE AREA_COB(DEVICE AREA_COB INDEX))) T = ADDR(DEVICE AREA_COB(DEVICE AREA_COB INDEX)) *LSD_PARM CELL *IAD_8 *LDTB_CONTROL MSG DESCRIPTOR *LDA_T *MV_%L=%DR DEVICE AREA_COB INDEX = DEVICE AREA_COB INDEX+ %C CONTROL MSG LENGTH TEMP = PARM CELL_LINK RETURN PP CELL(DEVICE AREA_CO HEAD) DEVICE AREA_CO HEAD = TEMP DEVICE AREA_CO TAIL = EMPTY %IF TEMP = EMPTY %REPEAT -> MAKE IDLE %FINISH !* !* %IF STREAM NO = CONTROL IN %START; !CONTROL INPUT TERMINATION %IF MON LEVEL&4 # 0 %START DEVICE AREA_BYTES OF CONTROL INPUT = DEVICE AREA_ %C BYTES OF CONTROL INPUT+LENGTH DEVICE AREA_CONTROL INPUT TRANSFERS = DEVICE AREA_ %C CONTROL INPUT TRANSFERS+1 DEVICE AREA_CONTROL INPUT XBIT SET = DEVICE AREA_ %C CONTROL INPUT XBIT SET + 1 %IF XBIT SET # 0 %FINISH CIB INDEX = 0 CMES_SSERV = MESS_DSERV %WHILE CIB INDEX < LENGTH %CYCLE CONTROL == RECORD(ADDR(DEVICE AREA_CIB(CIB INDEX))) TEMP = CONTROL_MESSAGE IDENT S IDENT = TEMP&SHORT MASK STREAM NO = TEMP>>16 %IF 0 <= STREAM NO <= MAX STREAM %C %AND 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 CMES_DSERV = STREAM TAB( %C STREAM INDEX(STREAM NO))_OWNER %C %ELSE CMES_DSERV = COMMS COMMAND!S IDENT PON(CMES) %FINISH %ELSE %START PRINT STRING("Mk1 FE Adaptor: FE".TO STRING( %C DEVICE NO+'0')." Bad stream number") WRITE(STREAM NO,4) NEWLINE %FINISH CIB INDEX = CIB INDEX+CONTROL MSG LENGTH %REPEAT -> MAKE IDLE %FINISH !* !* %IF MON LEVEL&4 # 0 %START %IF STREAM NO&1 = 1 %START; !OUTPUT DEVICE AREA_BYTES OF DATA OUTPUT = DEVICE AREA_ %C BYTES OF DATA OUTPUT+LENGTH DEVICE AREA_DATA OUTPUT TRANSFERS = DEVICE AREA_ %C DATA OUTPUT TRANSFERS+1 DEVICE AREA_DATA OUTPUT XBIT SET = DEVICE AREA_ %C DATA OUTPUT XBIT SET + 1 %IF XBIT SET # 0 %FINISH %ELSE %START DEVICE AREA_BYTES OF DATA INPUT = DEVICE AREA_ %C BYTES OF DATA INPUT+LENGTH DEVICE AREA_DATA INPUT TRANSFERS = DEVICE AREA_ %C DATA INPUT TRANSFERS+1 DEVICE AREA_DATA INPUT XBIT SET = DEVICE AREA_ %C DATA INPUT XBIT SET+1 %IF XBIT SET # 0 %FINISH %FINISH CMES = 0 CMES_SSERV = MESS_DSERV CMES_DSERV = TRANSFER COMPLETE CMES_P1 = STREAM NO %IF SSERIES = NO %START CMES_P2 = 3 %IF GPC ENTRY_RESP0&LONG BLOCK MASK # 0 !NEXT PAGE REQUIRED AND DONT RECAPTURE %FINISH %ELSE %START CMES_P2 = 3 %IF DEVICE AREA_TCB1 RESPONSE& %C LONG BLOCK MASK # 0 !NEXT PAGE REQUIRED AND DONT RECAPTURE %FINISH CMES_P3 = LENGTH %IF SSERIES = NO %START TEMP = GPC ENTRY_RESP0&Y MASK; !SEND HIGH LEVEL CONTROL MESSAGE TO SIGNAL END OF MESSAGE %FINISH %ELSE %START TEMP = DEVICE AREA_TCB1 RESPONSE&Y MASK; !SEND HIGH LEVEL CONTROL MESSAGE TO SIGNAL END OF MESSAGE %FINISH CMES_P2 = CMES_P2!4 %IF TEMP # 0 PON(CMES) -> MAKE IDLE !* !* ABNORMAL TERMINATION:!** ABNORMAL TERMINATION INTERRUPT PRINT STRING("Mk1 FE Adaptor: Abterm FE".TO STRING( %C DEVICE NO+'0')) WRITE(DEVICE AREA_FAILURES,1) SPACES(2) PT REC(MESS) %IF DEVICE AREA_FAILURES <= MAX FAILURES %START !TRY AGAIN? GPC REQ = 0 GPC REQ_DSERV = EXECUTE CHAIN GPC REQ_SSERV = MK1 FE EXECUTED %IF SSERIES = NO %START GPC REQ_P1 = ADDR(DEVICE AREA_RCB0) %FINISH %ELSE %START GPC REQ_P1 = ADDR(DEVICE AREA_TCB0 COMMAND) %FINISH GPC REQ_P2 = DEVICE AREA_IDENT %IF SSERIES = NO %START GPC REQ_P3 = X'11'; !PAW FUNCTION<<4!SAW FLAGS %FINISH DPON(GPC REQ,RETRY DELAY(DEVICE AREA_FAILURES)) !TRY AGAIN IN ? SECONDS DEVICE AREA_FAILURES = DEVICE AREA_FAILURES+1 %FINISH %ELSE %START OP MESS("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 CMES_P2 = 2; !DONT RECAPTURE PON(CMES) %FINISH %WHILE DEVICE AREA_HEAD # EMPTY %CYCLE;!FAIL ALL QUEUED TRANSFERS BUFFER == BUFFER TAB(DEVICE AREA_HEAD) DEVICE AREA_HEAD = BUFFER_LINK DEVICE AREA_TAIL = EMPTY %IF DEVICE AREA_HEAD = EMPTY CMES = 0 CMES_DSERV = TRANSFER COMPLETE CMES_SSERV = MESS_DSERV CMES_P1 = BUFFER_STREAM NO CMES_P2 = 2; !DONT RECAPTURE 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_ %C 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) %FINISH %ELSE %START; !WAITING ON A REPLY %IF SUB IDENT(STREAM_STATE) # -1 %START CMES_DSERV = COMMS COMMAND!SUB IDENT( %C STREAM_STATE)>>16 !SIMULATE ONE CMES_P2 = 1; !FAILURE PON(CMES) %FINISH %FINISH %FINISH %FINISH %REPEAT DEVICE AREA_STREAM = IDLE DEVICE AREA_COB START = 0 DEVICE AREA_COB INDEX = 0 DEVICE AREA_FAILURES = 0 DEVICE TO DA AD(DEVICE NO) = NOT ALLOCATED %FINISH %RETURN !* !* ATTEN:!** ATTENTION INTERRUPT %IF MESS_P1&X'1FF00' = X'08000' %START; !EXPECTED ATTN ? %IF STREAM NO = IDLE %START %IF DEVICE TO DA AD(DEVICE NO) = NOT ALLOCATED %START OP MESS("FE".TO STRING(DEVICE NO+'0')." UP") DEVICE TO DA AD(DEVICE NO) = ADDR(DEVICE AREA) %FINISH MAKE IDLE: DEVICE AREA_STREAM = IDLE %IF INTERRUPT ANALYSIS FLAGS = ATTENTION %C %OR XBIT SET # 0 %OR DEVICE AREA_ATTN SET # 0 %START !CONTROL INPUT PENDING DEVICE AREA_ATTN SET = 0 START DEVICE(CONTROL IN,CONTROL IN,0,ADDR( %C DEVICE AREA_CIB(0)),CIB LENGTH) %RETURN %FINISH !* !* %IF DEVICE AREA_COB INDEX > 0 %START; !CONTROL OUTPUT PENDING. START DEVICE(CONTROL OUT,CONTROL OUT,0,ADDR( %C DEVICE AREA_COB(0)),DEVICE AREA_COB INDEX) DEVICE AREA_COB START = DEVICE AREA_COB INDEX %RETURN %FINISH !* !* %IF DEVICE AREA_HEAD # EMPTY %START;!DATA TRANSFER QUEUED BUFFER == BUFFER TAB(DEVICE AREA_HEAD) DEVICE AREA_HEAD = BUFFER_LINK DEVICE AREA_TAIL = EMPTY %IF DEVICE AREA_HEAD = EMPTY START DEVICE(BUFFER_STREAM NO,BUFFER_ %C EXTERNAL STREAM NO,BUFFER_REAL ADDRESS,BUFFER_ %C OFFSET,BUFFER_LENGTH) %RETURN %FINISH %FINISH %ELSE DEVICE AREA_ATTN SET = 1 %FINISH %ELSE %START OP MESS("FE".TO STRING(DEVICE NO +'0').%C " Unexpected attention") PRINT STRING("Mk1 FE Adaptor: ") PT REC(MESS) %FINISH %RETURN !* !* ACT(ALLOCATED):!** DEVICE ALLOCATED BY GPC %IF MESS_P1 = 0 %START; !ALLOCATED GPC ENTRY == RECORD(MESS_P3) DEVICE AREA == RECORD(GPC ENTRY_UA AD) DEVICE NO = GPC ENTRY_MNEMONIC&BYTE MASK-'0' DEVICE TO DA AD(DEVICE NO) = GPC ENTRY_UA AD %IF SSERIES = NO %START DEVICE AREA_LST0 = X'02201000';!LOCAL SEGMENT TABLE ENTRY R2, W2, MAX LEN 1 EPAGE DEVICE AREA_LST1 = X'00000000' DEVICE AREA_RCB0 = X'00000002';!RCB FLAGS ETC DEVICE AREA_RCB1 = REALISE(ADDR(DEVICE AREA_LST0)) !SEGMENT TABLE (REAL ADDRESS) DEVICE AREA_RCB2 = 8; !LOGIC BLOCK BYTE COUNT DEVICE AREA_RCB3 = ADDR(DEVICE AREA_LB0);!LOGIC BLOCK ADDRESS (VIRTUAL) DEVICE AREA_RCB4 = 16; !ADDRESS LIST BYTE COUNT DEVICE AREA_RCB5 = ADDR(DEVICE AREA_AL00) !ADDRESS LIST ADDRESS (VIRTUAL) DEVICE AREA_RCB6 = 0; !UNUSED DEVICE AREA_RCB7 = 0; !UNUSED DEVICE AREA_LB0 = X'84F00500'; !WRITE CONTROL (EXT STREAM NO)<<16!LENGTH DEVICE AREA_LB1 = X'00000000'; !READ OR WRITE DATA DEVICE AREA_AL00 = 4; !LENGTH OF EXT STREAM NO AND LENGTH FIELD DEVICE AREA_AL01 = ADDR(DEVICE AREA_NAME) !ADDRESS OF STREAM FIELD DEVICE AREA_AL10 = 0; !LENGTH OF READ / WRITE AREA DEVICE AREA_AL11 = 0; !ADDRESS OF READ / WRITE AREA %FINISH %ELSE %START COM AREA == RECORD(X'80000000'!48<<18) DEVICE AREA_TCB0 COMMAND = X'2F404085'; !WRITE CONTROL CHAINED DEVICE AREA_TCB0 STE = INTEGER(ADDR(DEVICE AREA)<<1>>19<< %C 3+COM AREA_PSTVA+4)!1 DEVICE AREA_TCB0 LENGTH = 4 DEVICE AREA_TCB0 ADDRESS = ADDR(DEVICE AREA_NAME) DEVICE AREA_TCB0 NEXT TCB = ADDR(DEVICE AREA_ %C TCB1 COMMAND) DEVICE AREA_TCB0 RESPONSE = 0 DEVICE AREA_TCB1 COMMAND = 0 DEVICE AREA_TCB1 STE = 0 DEVICE AREA_TCB1 LENGTH = 0 DEVICE AREA_TCB1 ADDRESS = 0 DEVICE AREA_TCB1 NEXT TCB = 0 DEVICE AREA_TCB1 RESPONSE = 0 %FINISH DEVICE AREA_IDENT = MESS_P2 DEVICE AREA_NAME = 0; !CONTROL INFORMATION SENT WRITTEN HERE DEVICE AREA_STREAM = IDLE DEVICE AREA_COB START = 0 DEVICE AREA_COB INDEX = 0 DEVICE AREA_HEAD = EMPTY DEVICE AREA_TAIL = EMPTY %IF MON LEVEL&4 # 0 %START DEVICE AREA_MAX QD TRANSFERS = 0 DEVICE AREA_MAX QD CONTROL MSGS = 0 DEVICE AREA_TOTAL QD TRANSFERS = 0 DEVICE AREA_TOTAL QD CONTROL MSGS = 0 DEVICE AREA_BYTES OF CONTROL INPUT = 0 DEVICE AREA_BYTES OF CONTROL OUTPUT = 0 DEVICE AREA_BYTES OF DATA INPUT = 0 DEVICE AREA_BYTES OF DATA OUTPUT = 0 DEVICE AREA_CONTROL INPUT TRANSFERS = 0 DEVICE AREA_CONTROL OUTPUT TRANSFERS = 0 DEVICE AREA_DATA INPUT TRANSFERS = 0 DEVICE AREA_DATA OUTPUT TRANSFERS = 0 DEVICE AREA_OUTPUT UPDATES = 0 DEVICE AREA_UPDATE OVERWRITES = 0 DEVICE AREA_CONTROL INPUT XBIT SET = 0 DEVICE AREA_CONTROL OUTPUT XBIT SET = 0 DEVICE AREA_DATA INPUT XBIT SET = 0 DEVICE AREA_DATA OUTPUT XBIT SET = 0 %FINISH DEVICE AREA_CO HEAD = EMPTY DEVICE AREA_CO TAIL = EMPTY DEVICE AREA_ATTN SET = 0 DEVICE AREA_DEVICE NO = DEVICE NO DEVICE AREA_FAILURES = 0 %FINISH %RETURN !* !* ACT(EXECUTE FAILS):!** EXECUTE CHAIN FAILS GPC ENTRY == RECORD(MESS_P3) DUMP TABLE(80,MESS_P3,GPC ENTRY_ENT SIZE) DEVICE AREA == RECORD(GPC ENTRY_UA AD) DEVICE AREA_STREAM = IDLE DEVICE AREA_COB START = 0 DEVICE AREA_COB INDEX = 0 %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 DEVICE AREA_STREAM # IDLE %START;!QUEUE A TRANSFER BUFFER_LINK = EMPTY %IF DEVICE AREA_HEAD = EMPTY %C %THEN DEVICE AREA_HEAD = BUFFER NO %C %ELSE BUFFER TAB(DEVICE AREA_TAIL)_LINK = BUFFER NO DEVICE AREA_TAIL = BUFFER NO %IF MON LEVEL&4 # 0 %START DEVICE AREA_TOTAL QD TRANSFERS = DEVICE AREA_ %C TOTAL QD TRANSFERS+1 L = DEVICE AREA_HEAD F = 1 %WHILE L # DEVICE AREA_TAIL %CYCLE F = F+1 L = BUFFER TAB(L)_LINK %REPEAT %IF F > DEVICE AREA_MAX QD TRANSFERS %C %THEN DEVICE AREA_MAX QD TRANSFERS = F %FINISH %FINISH %ELSE START DEVICE(STREAM NO,BUFFER_ %C EXTERNAL STREAM NO,BUFFER_REAL ADDRESS,BUFFER_OFFSET, %C 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 REPLY %START !HIGH LEVEL AND UPDATE MESSAGE DEVICE AREA_OUTPUT UPDATES = DEVICE AREA_OUTPUT UPDATES+1 %C %IF MON LEVEL&4 # 0 SEARCH INDEX = DEVICE AREA_COB START %CYCLE CONTROL ADDR = ADDR(DEVICE AREA_COB(0))+SEARCH INDEX %IF SEARCH INDEX = DEVICE AREA_COB INDEX %START !END OF WHATS IN BUFFER? %IF DEVICE AREA_COB INDEX = COB LENGTH %START !COB BUFFER FULL TEMP = DEVICE AREA_CO HEAD %WHILE TEMP # EMPTY %CYCLE; !SCAN DOWN EXISTING QUEUE PARM CELL == PARM TAB(TEMP) %IF MESSAGE IDENT = PARM CELL_P1 %START !UPDATE? DEVICE AREA_UPDATE OVERWRITES = %C DEVICE AREA_UPDATE OVERWRITES+1 %C %IF MON LEVEL&4 # 0 CONTROL ADDR = ADDR(PARM CELL_P1) -> OUT %FINISH %ELSE TEMP = PARM CELL_LINK %REPEAT QUEUE OUT: %FINISH %ELSE DEVICE AREA_COB INDEX = DEVICE AREA %C _COB INDEX+CONTROL MSG LENGTH %EXIT %FINISH %IF INTEGER(CONTROL ADDR) = MESSAGE IDENT %START DEVICE AREA_UPDATE OVERWRITES = DEVICE AREA_ %C UPDATE OVERWRITES+1 %IF MON LEVEL&4 # 0 %EXIT %FINISH SEARCH INDEX = SEARCH INDEX+CONTROL MSG LENGTH %REPEAT CMES = 0 CMES_DSERV = MESS_SSERV CMES_SSERV = MESS_DSERV CMES_P1 = STREAM NO %IF MULTI OCP = NO %THEN COMMS CONTROL(CMES) %ELSE PON(CMES); !REPLY MESSAGE UPDATED %FINISH %ELSE %START %IF DEVICE AREA_COB INDEX # COB LENGTH %START !COB BUFFER FULL? CONTROL ADDR = ADDR(DEVICE AREA_COB(DEVICE AREA_ %C COB INDEX)) DEVICE AREA_COB INDEX = DEVICE AREA_COB INDEX+ %C 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(DEVICE AREA_ %C COB(0)),DEVICE AREA_COB INDEX) %C %AND DEVICE AREA_COB START = DEVICE AREA_COB INDEX %C %IF DEVICE AREA_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 ON ALLOCATION * !*********************************************************************** %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) %IF SSERIES = NO %START %RECORDFORMAT DAF(%INTEGER LST0, LST1, RCB0, RCB1, RCB2, %C RCB3, RCB4, RCB5, RCB6, RCB7, LB0, LB1, LB2, AL00, %C AL01, STREAM NO, MODE, BUFFER NO, TRT AD, IDENT) %FINISH %ELSE %START %RECORDFORMAT DAF(%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)) %FINISH %ROUTINESPEC REPLY TO COMMS CONTROL( %C %INTEGER ACT, STREAM NO, FLAG) %ROUTINESPEC GET NEXT BUFFER %OWNINTEGERARRAY DEVICE TO DA AD(0 : 9) = %C NOT ALLOCATED(10) %RECORD REQ(PE) %RECORD REP(PE) %RECORDNAME GPC ENTRY(GPCF) %RECORDNAME DEVICE AREA(DAF) %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, TRT AD, %C INTERRUPT ANALYSIS FLAGS %SWITCH DACT(0 : SEND CONTROL) %SWITCH STATES(0 : ACTIVE) %IF MON LEVEL&2 # 0 %AND KMON&(LENGTHENI(1)<>20&15 GPC ENTRY == RECORD(MESS_P3) DEVICE AREA == RECORD(GPC ENTRY_UA AD) STREAM NO = DEVICE AREA_STREAM NO %FINISH %ELSE %START %IF ACT >= GO AHEAD %START; !FROM COMMS MESS_P1=STRM&SHORT MASK STREAM NO = MESS_P1&SHORT MASK STREAM == STREAM TAB(STREAM INDEX(STREAM NO)) DEVICE NO = STREAM_DEVICE NO %FINISH %FINISH -> DACT(ACT) !* !* DACT(INTERRUPT):!** DEVICE INTERRUPT (NORMAL, ABNORMAL, ATTENTION) %UNLESS INTERRUPT ANALYSIS FLAGS = ATTENTION %START %IF SSERIES = NO %START I = (DEVICE AREA_RCB3-ADDR(DEVICE AREA_LB0))>>2+ %C GPC ENTRY_RESP0&BYTE MASK %FINISH %ELSE %START %IF MESS_P5 = ADDR(DEVICE AREA_TCB1 COMMAND) %C %THEN I = 2 %ELSE I = 0 %FINISH %IF INTERRUPT ANALYSIS FLAGS&NORMAL TERMINATION # %C NORMAL TERMINATION %AND INTEGER(GPC ENTRY_SENSE AD) = %C X'20000004' %THEN LONG LINE = YES %ELSE LONG LINE = NO %IF I = 2 %AND MESS_P2 # -1 %START; !ON THE WRITE DATA AND NOT A TIME OUT %IF SSERIES = NO %START SENT = DEVICE AREA_AL00-GPC ENTRY_RESP1&SHORT MASK %FINISH %ELSE %START SENT = DEVICE AREA_TCB1 LENGTH-DEVICE AREA_ %C TCB1 RESPONSE&SHORT MASK %FINISH %IF LONG LINE = NO %START; !WAS IT A LONG LINE THEN NO NEED TO SCAN BACK %IF SENT > 0 %START BUFFER == BUFFER TAB(DEVICE AREA_BUFFER NO) START = VIRTUAL+BUFFER_REAL ADDRESS+BUFFER_OFFSET BUFFER END = START+SENT-1 %IF SENT > 133 %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 %IF SSERIES = NO %START DEVICE AREA_RCB3 = ADDR(DEVICE AREA_LB2) DEVICE AREA_LB2 = X'80700300' %FINISH %ELSE %START DEVICE AREA_ADDR TCB = ADDR(DEVICE AREA_ %C TCB1 COMMAND) %FINISH %FINISH %ELSE %START %IF SSERIES = NO %START DEVICE AREA_RCB3 = ADDR(DEVICE AREA_LB0) DEVICE AREA_LB1 = X'8A700000'!LINE DEVICE AREA_LB2 = X'80700000' %FINISH %ELSE %START DEVICE AREA_ADDR TCB = ADDR(DEVICE AREA_ %C TCB0 COMMAND) DEVICE AREA_TCB0 LENGTH = LINE DEVICE AREA_CHARS(0) = EBC SP %FINISH %FINISH %FINISH %FINISH %ELSE %START; !TAG ON A NEW LINE %IF SSERIES = NO %START DEVICE AREA_RCB3 = ADDR(DEVICE AREA_LB1) DEVICE AREA_LB1 = X'8A700300'!EBC NL DEVICE AREA_LB2 = X'80700000' %FINISH %ELSE %START DEVICE AREA_ADDR TCB = ADDR(DEVICE AREA_ %C TCB0 COMMAND) DEVICE AREA_TCB0 LENGTH = 1 DEVICE AREA_CHARS(0) = EBC NL %FINISH SENT = SENT-1; !SEND THE CHAR THAT CAUSED THE LONG LINE AGAIN %FINISH %FINISH %ELSE SENT = 0 !SEND REPLY TO COMMS CONTROL REQ = 0 REQ_SSERV = MESS_DSERV REQ_DSERV = TRANSFER COMPLETE REQ_P1 = STREAM NO REQ_P2 = 3; !GET NEXT PAGE AND DONT RECAPTURE %IF INTERRUPT ANALYSIS FLAGS&NORMAL TERMINATION = 0 %C %AND LONG LINE = NO %START REQ_P2 = REQ_P2!4; !INFORM USER REQ_P5 = INTEGER(GPC ENTRY_SENSE AD) REQ_P6 = INTEGER(GPC ENTRY_SENSE AD+4) %FINISH REQ_P3 = SENT PON(REQ) GET NEXT BUFFER %IF LONG LINE = YES %C %AND INTERRUPT ANALYSIS FLAGS&NORMAL TERMINATION = 0 %FINISH %ELSE %START !** ATTENTION INTERRUPT GET NEXT BUFFER %IF MESS_P1&AUTO = AUTO %FINISH %RETURN !* !* DACT(EXECUTE FAILS):!** EXECUTE CHAIN FAILS GPC ENTRY == RECORD(MESS_P3) DUMP TABLE(81,MESS_P3,GPC ENTRY_ENT SIZE) %RETURN !* !* DACT(ALLOCATED):!** DEVICE ALLOCATED BY GPC %IF MESS_P1 = 0 %START; !ALLOCATED GPC ENTRY == RECORD(MESS_P3) DEVICE AREA == RECORD(GPC ENTRY_UA AD) DEVICE NO = GPC ENTRY_MNEMONIC&BYTE MASK-'0' DEVICE TO DA AD(DEVICE NO) = GPC ENTRY_UA AD DEVICE AREA_IDENT = MESS_P2; !SAVE GPC IDENTIFIER DEVICE AREA_MODE = 0; !ISO BY DEFAULT DEVICE AREA_STREAM NO = MESS_P5 DEVICE AREA_BUFFER NO = 0 DEVICE AREA_TRT AD = GPC ENTRY_TRT AD %IF SSERIES = NO %START DEVICE AREA_LST0 = X'00F01000';!LOCAL SEGMENT TABLE ENTRY R15 MAX LEN 1 EPAGE DEVICE AREA_LST1 = 0 DEVICE AREA_RCB0 = X'0000000F';!RCB FLAGS ETC DEVICE AREA_RCB1 = REALISE(ADDR(DEVICE AREA_LST0)) DEVICE AREA_RCB2 = 12; !LOGIC BLOCK BYTE COUNT DEVICE AREA_RCB3 = ADDR(DEVICE AREA_LB2);!LOGIC BLOCK ADDRESS DEVICE AREA_RCB4 = 8; !ADDRESS_LIST BYTE COUNT DEVICE AREA_RCB5 = ADDR(DEVICE AREA_AL00) !ADDRESS LIST ADDRESS DEVICE AREA_RCB6 = 0; !UNUSED DEVICE AREA_RCB7 = 0; !UNUSED DEVICE AREA_LB0 = X'8A700300'!EBC MS DEVICE AREA_LB1 = X'8A700000'; !NUMBER OF SPACES DEVICE AREA_LB2 = X'80700300'; !WRITE BUFFER DEVICE AREA_AL00 = 0; !BUFFER LENGTH DEVICE AREA_AL01 = 0; !BUFFER OFFSET %FINISH %ELSE %START DEVICE AREA_TCB0 COMMAND = X'24404083' DEVICE AREA_TCB0 STE = INTEGER(ADDR(DEVICE AREA)<<1>>19<< %C 3+COM AREA_PSTVA+4)!1 DEVICE AREA_TCB0 LENGTH = 0 DEVICE AREA_TCB0 ADDRESS = ADDR(DEVICE AREA_CHARS(0)) DEVICE AREA_TCB0 NEXT TCB = ADDR(DEVICE AREA_ %C TCB1 COMMAND) DEVICE AREA_TCB1 COMMAND = X'24004083' DEVICE AREA_TCB1 STE = 0 DEVICE AREA_TCB1 LENGTH = 0 DEVICE AREA_TCB1 ADDRESS = 0 DEVICE AREA_TCB1 NEXT TCB = 0 DEVICE AREA_TCB0 RESPONSE = 0 DEVICE AREA_ADDR TCB = ADDR(DEVICE AREA_TCB1 COMMAND) %CYCLE I = 0,1,131 DEVICE AREA_CHARS(I) = EBC SP %REPEAT %FINISH %FINISH REPLY TO COMMS CONTROL(MESS_P4,MESS_P5,MESS_P1) %RETURN !* !* DACT(DEALLOCATED):!** DEVICE DEALLOCATED BY GPC DEVICE NO = MESS_P6 DEVICE TO DA AD(DEVICE NO) = NOT ALLOCATED REPLY TO COMMS CONTROL(MESS_P4,MESS_P5,MESS_P1) %RETURN !* !* DACT(GO AHEAD):!** TRANSFER GO AHEAD BUFFER NO = MESS_P2 BUFFER == BUFFER TAB(BUFFER NO) DEVICE AREA == RECORD(DEVICE TO DA AD(DEVICE NO)) DEVICE AREA_BUFFER NO = BUFFER NO START = VIRTUAL+BUFFER_REAL ADDRESS+BUFFER_OFFSET I TO E(START,BUFFER_LENGTH) %IF DEVICE AREA_MODE = ISO %IF DEVICE AREA_MODE # BINARY %START;!TRANSLATE IT TO THE EBCIDIC CHARACTERS IN THE CURRENT REP I = BUFFER_LENGTH TRT AD = DEVICE AREA_TRTAD %IF BYTEINTEGER(START) = EBC VP %C %AND DEVICE AREA_MODE = EBCIDIC %AND I > 1 %START !DO NOT TRANSLATE VP AND QUALIFIER I = I-2 START = START+2 %FINISH *LB_I ; *JAT_14, *LDTB_X'18000000'; *LDB_%B; *LDA_START *LSS_TRT AD; *LUH_X'18000100' *TTR_%L=%DR L99: %FINISH !AND INITIATE THE TRANSFER %IF SSERIES = NO %START DEVICE AREA_LST1 = X'80000001'!BUFFER_REAL ADDRESS DEVICE AREA_AL00 = BUFFER_LENGTH DEVICE AREA_AL01 = BUFFER_OFFSET %FINISH %ELSE %START DEVICE AREA_TCB0 RESPONSE = 0 DEVICE AREA_TCB1 STE = BUFFER_REAL ADDRESS!1 DEVICE AREA_TCB1 LENGTH = BUFFER_LENGTH DEVICE AREA_TCB1 ADDRESS = BUFFER_OFFSET DEVICE AREA_TCB1 RESPONSE = 0 %FINISH REQ = 0 REQ_DSERV = EXECUTE CHAIN REQ_SSERV = LP EXECUTED %IF SSERIES = NO %START REQ_P1 = ADDR(DEVICE AREA_RCB0) %FINISH %ELSE %START REQ_P1 = DEVICE AREA_ADDR TCB %FINISH REQ_P2 = DEVICE AREA_IDENT %IF SSERIES = NO %START REQ_P3 = 1<<4!1; !(PAW FUNCTION)<<4!SAW FLAGS %FINISH PON(REQ) %RETURN !* !* DACT(SEND CONTROL):!** CONTROL MESSAGE STATE = MESS_P2>>24 -> STATES(STATE) !* !* STATES(CONNECTING):!** ALLOCATE DEVICE REQ = 0 REQ_DSERV = ALLOCATE DEVICE REQ_SSERV = LP ALLOCATED REQ_P1 = M'LP0'!DEVICE NO REQ_P2 = LP INTERRUPT REQ_P4 = MESS_P1>>16 REQ_P5 = STREAM NO PON(REQ) %RETURN !* !* STATES(ENABLING):!** REQUEST FIRST PAGE REPLY TO COMMS CONTROL(MESS_P1>>16,STREAM NO,0) DEVICE AREA == RECORD(DEVICE TO DA AD(DEVICE NO)) DEVICE AREA_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 %IF SSERIES = NO %START DEVICE AREA_RCB3 = ADDR(DEVICE AREA_LB1) DEVICE AREA_LB1 = X'8A700300'!EBC FF %FINISH %ELSE %START DEVICE AREA_ADDR TCB = ADDR(DEVICE AREA_TCB0 COMMAND) DEVICE AREA_TCB0 LENGTH = 1 DEVICE AREA_CHARS(0) = EBC FF %FINISH %FINISH GET NEXT BUFFER %RETURN !* !* STATES(DISCONNECTING):!** DEALLOCATE DEVICE REQ = 0 REQ_DSERV = DEALLOCATE DEVICE REQ_SSERV = LP DEALLOCATED REQ_P1 = M'LP0'!DEVICE NO REQ_P4 = MESS_P1>>16 REQ_P5 = STREAM NO REQ_P6 = DEVICE NO PON(REQ) %RETURN !* !* STATES(SUSPENDING): STATES(ABORTING): REPLY TO COMMS CONTROL(MESS_P1>>16,STREAM NO,0) !ALWAYS REPLY %RETURN !* !* %ROUTINE REPLY TO COMMS CONTROL( %C %INTEGER ACT, STREAM NO, FLAG) REP = 0 REP_DSERV = COMMS COMMAND!ACT REP_SSERV = MESS_DSERV REP_P1 = STREAM NO REP_P2 = FLAG PON(REP) %END; !OF ROUTINE REPLY TO COMMS CONTROL !* !* %ROUTINE GET NEXT BUFFER REQ = 0 REQ_DSERV = REQUEST TRANSFER REQ_SSERV = LP COMMAND REQ_P1 = STREAM NO PON(REQ) %END; !OF ROUTINE GET NEXT BUFFER !* !* %END; !OF ROUTINE LP ADAPTOR !* !* !* !* !* !* !* !* %EXTERNALROUTINE CR ADAPTOR(%RECORDNAME MESS) !*********************************************************************** !* 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 ON ALLOCATION * !*********************************************************************** %RECORDSPEC MESS(PE) %INTEGER I, J, STREAM NO, DEVICE NO, STATE, SENT, ACT, %C BUFFER NO, INTERRUPT ANALYSIS FLAGS, START %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 DAF(%INTEGER LST0, LST1, RCB0, RCB1, RCB2, RCB3, %C RCB4, RCB5, RCB6, RCB7, STREAM NO, MODE, GOAH AD, %C GOAH LEN, CURTRLEN, BUFFER NO, IDENT, BLOCKED, %C %INTEGERARRAY LBE(0 : 35), ALE(0 : 71)) %OWNINTEGERARRAY DEVICE TO DA AD(0 : 9) = %C NOT ALLOCATED(10) %ROUTINESPEC TRANSLATE AND SHUFFLE(%INTEGER ADDRESS, %C %INTEGERNAME LEN) %ROUTINESPEC REPLY TO COMMS CONTROL( %C %INTEGER ACT, STREAM NO, FLAG) %ROUTINESPEC GET NEXT BUFFER %RECORDNAME GPC ENTRY(GPCF) %RECORDNAME DEVICE AREA(DAF) %RECORDNAME STREAM(SR) %RECORDNAME BUFFER(BR) %RECORD REQ, REP(PE) %CONSTINTEGERARRAY CARD SIZE( ISO : BINARY) = %C 81, 80, 160 %SWITCH DACT(0 : SEND CONTROL) %SWITCH STATES(0 : ACTIVE) %IF MON LEVEL&2 # 0 %AND KMON&(LENGTHENI(1)<>20&15 GPC ENTRY == RECORD(MESS_P3) DEVICE AREA == RECORD(GPC ENTRY_UA AD) STREAM NO = DEVICE AREA_STREAM NO %FINISH %ELSE %START %IF ACT >= GO AHEAD %START; !FROM COMMS MESS_P1=STRM&SHORT MASK STREAM NO = MESS_P1&SHORT MASK STREAM == STREAM TAB(STREAM INDEX(STREAM NO)) DEVICE NO = STREAM_DEVICE NO %FINISH %FINISH -> DACT(ACT) !* !* DACT(INTERRUPT):!** DEVICE INTERRUPT (NORMAL, ABNORMAL, ATTENTION) %UNLESS INTERRUPT ANALYSIS FLAGS = ATTENTION %START BUFFER == BUFFER TAB(DEVICE AREA_BUFFER NO) START = VIRTUAL+BUFFER_REAL ADDRESS+DEVICE AREA_GOAH AD %IF INTERRUPT ANALYSIS FLAGS&NORMAL TERMINATION = %C NORMAL TERMINATION %START TRANSLATE AND SHUFFLE(START,DEVICE AREA_CUR TR LEN) %C %IF DEVICE AREA_MODE = ISO DEVICE AREA_GOAH LEN = DEVICE AREA_GOAH LEN- %C DEVICE AREA_CURTRLEN DEVICE AREA_GOAH AD = DEVICE AREA_GOAH AD+DEVICE AREA_ %C CURTRLEN -> READ; !READ MORE IF ROOM %FINISH %ELSE %START I = GPC ENTRY_RESP0&X'FF'; !FAILING LBE ENTRY SENT = CARD SIZE(DEVICE AREA_MODE)*I; !BYTES READ OK TRANSLATE AND SHUFFLE(START,SENT) %C %IF SENT > 0 %AND DEVICE AREA_MODE = ISO DEVICE AREA_GOAH LEN = DEVICE AREA_GOAH LEN-SENT !TELL COMMS CONTROL BY A CALL TO UPDATE CURSOR REQ = 0 REQ_DSERV = TRANSFER COMPLETE REQ_SSERV = MESS_DSERV REQ_P1 = STREAM NO REQ_P2 = 2; !NEXT PAGE NOT REQD AND DONT RECAPTURE %IF SENT > 0 %START REQ_P2 = REQ_P2!4 REQ_P5 = INTEGER(GPC ENTRY_SENSE AD) REQ_P6 = INTEGER(GPC ENTRY_SENSE AD+4) DEVICE AREA_BLOCKED = 1 %FINISH REQ_P3 = BUFFER_LENGTH-DEVICE AREA_GOAH LEN PON(REQ) %FINISH %FINISH %ELSE %START !** ATTENTION INTERRUPT GET NEXT BUFFER %IF MESS_P1&AUTO = AUTO %C %AND DEVICE AREA_BLOCKED = 0 %FINISH %RETURN !* !* DACT(EXECUTE FAILS):!** EXECUTE CHAIN FAILS GPC ENTRY == RECORD(MESS_P3) DUMP TABLE(82,MESS_P3,GPC ENTRY_ENT SIZE) %RETURN !* !* DACT(ALLOCATED):!** DEVICE ALLOCATED BY GPC %IF MESS_P1 = 0 %START; !ALLOCATED GPC ENTRY == RECORD(MESS_P3) DEVICE AREA == RECORD(GPC ENTRY_UA AD) DEVICE NO = GPC ENTRY_MNEMONIC&BYTE MASK-'0' DEVICE TO DA AD(DEVICE NO) = GPC ENTRY_UA AD DEVICE AREA_IDENT = MESS_P2; !SAVE GPC IDENTIFIER DEVICE AREA_STREAM NO = MESS_P5 DEVICE AREA_MODE = 0; !READ IN NON BINARY MODE DEVICE AREA_BLOCKED = 0 DEVICE AREA_GOAH LEN = 0 DEVICE AREA_GOAH AD = 0 DEVICE AREA_CURTR LEN = 0 DEVICE AREA_BUFFER NO = 0 DEVICE AREA_LST0 = X'0FF01000' DEVICE AREA_LST1 = X'00000000' DEVICE AREA_RCB0 = X'0000800F' DEVICE AREA_RCB1 = REALISE(ADDR(DEVICE AREA_LST0)) DEVICE AREA_RCB2 = 144; !BYTES OF LOGIC BLOCK DEVICE AREA_RCB3 = ADDR(DEVICE AREA_LBE(0)) DEVICE AREA_RCB4 = 288; !BYTES OF ADDRESS LIST DEVICE AREA_RCB5 = ADDR(DEVICE AREA_ALE(0)) DEVICE AREA_RCB6 = X'FC01'; !SET NR MODE DEVICE AREA_RCB7 = 0 %CYCLE I = 0,2,70 DEVICE AREA_ALE(I) = X'58000050'; !80 BYTE ENTRY %REPEAT %FINISH REPLY TO COMMS CONTROL(MESS_P4,MESS_P5,MESS_P1) %RETURN !* !* DACT(DEALLOCATED):!** DEVICE DEALLOCATED BY GPC DEVICE NO = MESS_P6 DEVICE TO DA AD(DEVICE NO) = NOT ALLOCATED REPLY TO COMMS CONTROL(MESS_P4,MESS_P5,MESS_P1) %RETURN !* !* DACT(GO AHEAD):!** TRANSFER GO AHEAD !IE COMMS HAS PAGED IN BUFFER BUFFER NO = MESS_P2 BUFFER == BUFFER TAB(BUFFER NO) DEVICE AREA == RECORD(DEVICE TO DA AD(DEVICE NO)) DEVICE AREA_LST1 = X'80000001'!BUFFER_REAL ADDRESS DEVICE AREA_GOAH LEN = BUFFER_LENGTH DEVICE AREA_GOAH AD = BUFFER_OFFSET DEVICE AREA_BUFFER NO = BUFFER NO READ: !TRY TO READ CARDS %IF DEVICE AREA_GOAH LEN < CARD SIZE(DEVICE AREA_MODE) %START !NOT ROOM FOR EVEN 1 CARD %IF DEVICE AREA_GOAH LEN > 0 %START J = VIRTUAL+BUFFER_REAL ADDRESS+DEVICE AREA_GOAH AD %CYCLE I = 0,1,DEVICE AREA_GOAH LEN-1 BYTE INTEGER(I+J) = 0; !FILL PARTCARD WITH NULLS %REPEAT %FINISH REQ = 0 REQ_DSERV = TRANSFER COMPLETE REQ_SSERV = CR COMMAND REQ_P1 = STREAM NO REQ_P2 = 3; !PLEASE PROVIDE NEXT PAGE AND DONT RECAPTURE THIS ONE 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 DEVICE AREA_GOAH LEN-CARD SIZE( %C DEVICE AREA_MODE)*(I+1) < 0 DEVICE AREA_LBE(I) = X'04400200'+2*I; !CHAIN IGNRE LONGBLK&READ DEVICE AREA_ALE(2*I+1) = DEVICE AREA_GOAH AD+CARD SIZE( %C DEVICE AREA_MODE)*I I = I+1 %REPEAT DEVICE AREA_LBE(I-1) = DEVICE AREA_LBE(I-1)&X'F3FFFFFF' !DECHAIN DEVICE AREA_CUR TR LEN = CARD SIZE(DEVICE AREA_MODE)*I %IF DEVICE AREA_MODE # BINARY %C %THEN DEVICE AREA_RCB6 = X'FC01' %C %ELSE DEVICE AREA_RCB6 = X'FC02' REQ = 0 REQ_DSERV = EXECUTE CHAIN REQ_SSERV = CR EXECUTED REQ_P1 = ADDR(DEVICE AREA_RCB0) REQ_P2 = DEVICE AREA_IDENT REQ_P3 = 1<<4!1; !(PAW FUNCTION)<<4!SAW FLAGS PON(REQ) %RETURN !* !* DACT(SEND CONTROL):!** CONTROL MESSAGE STATE = MESS_P2>>24 -> STATES(STATE) !* !* STATES(CONNECTING):!** ALLOCATE DEVICE REQ = 0 REQ_DSERV = ALLOCATE DEVICE REQ_SSERV = CR ALLOCATED REQ_P1 = M'CR0'!DEVICE NO REQ_P2 = CR INTERRUPT REQ_P4 = MESS_P1>>16 REQ_P5 = STREAM NO PON(REQ); !TRY TO ALLOCATE %RETURN !* !* STATES(DISCONNECTING):!** DEALLOCATE DEVICE REQ = 0 REQ_DSERV = DEALLOCATE DEVICE REQ_SSERV = CR DEALLOCATED REQ_P1 = M'CR0'!DEVICE NO REQ_P4 = MESS_P1>>16 REQ_P5 = STREAM NO REQ_P6 = DEVICE NO PON(REQ) %RETURN !* !* STATES(ENABLING):!** REQUEST FIRST PAGE REPLY TO COMMS CONTROL(MESS_P1>>16,STREAM NO,0) DEVICE AREA == RECORD(DEVICE TO DA AD(DEVICE NO)) DEVICE AREA_MODE = MESS_P2>>20&3; !ISO EBCIDIC OR BINARY? %IF DEVICE AREA_BLOCKED = 0 %THEN GET NEXT BUFFER %C %ELSE DEVICE AREA_BLOCKED = 0 %RETURN !* !* STATES(SUSPENDING): STATES(ABORTING): REPLY TO COMMS CONTROL(MESS_P1>>16,STREAM NO,0) %RETURN !* !* %ROUTINE REPLY TO COMMS CONTROL( %C %INTEGER ACT, STREAM NO, FLAG) REP = 0 REP_DSERV = COMMS COMMAND!ACT REP_SSERV = MESS_DSERV REP_P1 = STREAM NO REP_P2 = FLAG PON(REP) %END; !OF ROUTINE REPLY TO COMMS CONTROL !* !* %ROUTINE GET NEXT BUFFER REQ = 0 REQ_DSERV = REQUEST TRANSFER REQ_SSERV = CR COMMAND REQ_P1 = STREAM NO PON(REQ) %END; !OF ROUTINE GET NEXT BUFFER !* !* %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 !* !* !* !* !* !* %IF CP FITTED = YES %START !* !* %EXTERNALROUTINE CP ADAPTOR(%RECORDNAME MESS) !*********************************************************************** !* 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 ON ALLOCATION * !*********************************************************************** %RECORDSPEC MESS(PE) %INTEGER I, J, STREAM NO, DEVICE NO, STATE, ACT, BUFFER NO, %C SYM, INTERRUPT ANALYSIS FLAGS %RECORDFORMAT GPCF(%INTEGER SER, GPTSM, PROPADDR, TICKS, %C CAA, GRCB AD, LBA, ALA, STATE, RESP0, RESP1, SENSE1, %C SENSE2, SENSE3, SENSE4, REPSNO, BASE, ID, DLVN, %C MNEMONIC, ENTSIZE, PAW, USAW0, URCB AD, SENSE AD, %C LOGMASK, TRT AD, UA SIZE, UA AD, TIMEOUT, PROPS0, %C PROPS1) %RECORDFORMAT DAF(%INTEGER LST0, LST1, RCB0, RCB1, RCB2, %C RCB3, RCB4, RCB5, RCB6, RCB7, LBE0, ALE0, ALE1, %C STREAM NO, BUFFER NO, GOAH AD, GOAH LEN, POSN, MODE, %C IDENT, %BYTEINTEGERARRAY CARD(0 : 79)) %OWNINTEGERARRAY DEVICE TO DA AD(0 : 9) = %C NOT ALLOCATED(10) %ROUTINESPEC REPLY TO COMMS CONTROL( %C %INTEGER ACT, STREAM NO, FLAG) %ROUTINESPEC GET NEXT BUFFER %RECORDNAME GPC ENTRY(GPCF) %RECORDNAME DEVICE AREA(DAF) %RECORDNAME STREAM(SR) %RECORDNAME BUFFER(BR) %RECORD REQ, REP(PE) %SWITCH DACT(0 : SEND CONTROL) %SWITCH STATES(0 : ACTIVE) %IF MON LEVEL&2 # 0 %AND KMON&(LENGTHENI(1)<>20&15 GPC ENTRY == RECORD(MESS_P3) DEVICE AREA == RECORD(GPC ENTRY_UA AD) STREAM NO = DEVICE AREA_STREAM NO %FINISH %ELSE %START %IF ACT >= GO AHEAD %START; !FROM COMMS MESS_P1=STRM&SHORT MASK STREAM NO = MESS_P1&SHORT MASK STREAM == STREAM TAB(STREAM INDEX(STREAM NO)) DEVICE NO = STREAM_DEVICE NO %FINISH %FINISH -> DACT(ACT) !* !* DACT(INTERRUPT):!** DEVICE INTERRUPT (NORMAL, ABNORMAL, ATTENTION) %UNLESS INTERRUPT ANALYSIS FLAGS = ATTENTION %START BUFFER == BUFFER TAB(DEVICE AREA_BUFFER NO) %IF INTERRUPT ANALYSIS FLAGS&NORMAL TERMINATION = %C NORMAL TERMINATION %START DEVICE AREA_POSN = 0; !NO UNPUCHED CARD IN BUFFER I = 0 %AND -> EPAGE USED %IF DEVICE AREA_GOAH LEN = 0 !FINISHED BUFFER EMPTY -> PUNCH; !PUNCH MORE IF ROOM %FINISH %ELSE %START !TELL COMMS CONTROL BY A CALL TO UPDATE CURSOR REQ = 0 REQ_DSERV = TRANSFER COMPLETE REQ_SSERV = CP COMMAND REQ_P1 = STREAM NO REQ_P2 = 6; !NEXT PAGE NOT REQD AND DONT RECAPTURE THIS ONE REQ_P3 = BUFFER_LENGTH-DEVICE AREA_GOAH LEN REQ_P5 = INTEGER(GPC ENTRY_SENSE AD) REQ_P6 = INTEGER(GPC ENTRY_SENSE AD+4) PON(REQ) %FINISH %FINISH %ELSE %START !** ATTENTION INTERRUPT GET NEXT BUFFER %IF MESS_P1&AUTO = AUTO %FINISH %RETURN !* !* DACT(EXECUTE FAILS):!** EXECUTE CHAIN FAILS GPC ENTRY == RECORD(MESS_P3) DUMP TABLE(83,MESS_P3,GPC ENTRY_ENT SIZE) %RETURN !* !* DACT(ALLOCATED):!** DEVICE ALLOCATED BY GPC %IF MESS_P1 = 0 %START; !ALLOCATED GPC ENTRY == RECORD(MESS_P3) DEVICE AREA == RECORD(GPC ENTRY_UA AD) DEVICE NO = GPC ENTRY_MNEMONIC&BYTE MASK-'0' DEVICE TO DA AD(DEVICE NO) = GPC ENTRY_UA AD DEVICE AREA_IDENT = MESS_P2; !SAVE GPC IDENTIFIER DEVICE AREA_STREAM NO = MESS_P5 DEVICE AREA_MODE = 0; !READ IN NON BINARY MODE DEVICE AREA_LST0 = X'00000000';!NOT USED DEVICE AREA_LST1 = X'00000000';!NOT USED DEVICE AREA_RCB0 = X'00008002' DEVICE AREA_RCB1 = X'00000000';!NOT USED DEVICE AREA_RCB2 = 4; !BYTES OF LOGIC BLOCK DEVICE AREA_RCB3 = ADDR(DEVICE AREA_LBE0) DEVICE AREA_RCB4 = 8; !BYTES OF ADDRESS LIST DEVICE AREA_RCB5 = ADDR(DEVICE AREA_ALE0) DEVICE AREA_RCB6 = X'FC01'; !SET NR MODE DEVICE AREA_RCB7 = 0 DEVICE AREA_LBE0 = X'80000300' DEVICE AREA_ALE0 = X'58000050' DEVICE AREA_ALE1 = ADDR(DEVICE AREA_CARD(0)) DEVICE AREA_BUFFER NO = 0 DEVICE AREA_GOAH AD = 0 DEVICE AREA_GOAH LEN = 0 DEVICE AREA_POSN = 0 %FINISH REPLY TO COMMS CONTROL(MESS_P4,MESS_P5,MESS_P1) %RETURN !* !* DACT(DEALLOCATED):!** DEVICE DEALLOCATED BY GPC DEVICE NO = MESS_P6 DEVICE TO DA AD(DEVICE NO) = NOT ALLOCATED REPLY TO COMMS CONTROL(MESS_P4,MESS_P5,MESS_P1) %RETURN !* !* DACT(GO AHEAD): !TRANSFER GO AHEAD !IE COMMS HAS PAGED IN BUFFER BUFFER NO = MESS_P2 BUFFER == BUFFER TAB(BUFFER NO) DEVICE AREA == RECORD(DEVICE TO DA AD(DEVICE NO)) DEVICE AREA_GOAH LEN = BUFFER_LENGTH DEVICE AREA_GOAH AD = BUFFER_OFFSET DEVICE AREA_BUFFER NO = BUFFER NO PUNCH: !TRY TO PUNCH CARDS !COPY A CARD INTO DEVICE AREA_CARD AND SPACEFILL. SPANNED CARDS HAVE !1ST PART IN BUFFER AND DEVICE AREA_POSN INDICATES NEXT FREE BYTE. !DEVICE AREA_POSN=80 INDICATES COMPLETE CARD IN BUFFER IN EBCDIC !AS HAPPENS AFTER AN ABNORMAL TERMINATION I = DEVICE AREA_POSN -> FIRE %IF I = 80; !CARD ALL READY TO FIRE IO J = 0 %CYCLE SYM = BYTE INTEGER(VIRTUAL+DEVICE AREA_GOAH AD+J+ %C BUFFER_REAL ADDRESS) %IF DEVICE AREA_MODE # BINARY %START %IF DEVICE AREA_MODE = ISO %START %EXIT %IF SYM = NL %OR SYM = 12; !CONTROL CHAR %FINISH %ELSE %START %EXIT %IF SYM = EBC NL %OR SYM = EBC LF %OR SYM = 12 %FINISH %FINISH !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 DEVICE AREA_CARD(I) = SYM I = I+1 J = J+1 -> EPAGE USED %IF J >= DEVICE AREA_GOAH LEN %REPEAT !CONTROL CHAR FOUND DEVICE AREA_GOAH LEN = DEVICE AREA_GOAH LEN-(J+1) DEVICE AREA_GOAH AD = DEVICE AREA_GOAH AD+J+1 %IF DEVICE AREA_MODE # BINARY %START %IF DEVICE AREA_MODE = ISO %THEN SYM = ' ' %C %ELSE SYM = EBC SP %WHILE I < 80 %THEN DEVICE AREA_CARD(I) = SYM %C %AND I = I+1 I TO E(ADDR(DEVICE AREA_CARD(0)),80) %C %IF DEVICE AREA_MODE = ISO %FINISH DEVICE AREA_POSN = 80; !CARD READ IN EBCDIC FIRE: REQ = 0 REQ_DSERV = EXECUTE CHAIN REQ_SSERV = CP EXECUTED REQ_P1 = ADDR(DEVICE AREA_RCB0) REQ_P2 = DEVICE AREA_IDENT REQ_P3 = 1<<4!1 PON(REQ) %RETURN EPAGE USED: !AWAIT NEXT GO AHEAD DEVICE AREA_POSN = I; !SOME ISO CHARS IN BUFFER REQ = 0 REQ_DSERV = TRANSFER COMPLETE REQ_SSERV = CP COMMAND REQ_P1 = STREAM NO REQ_P2 = 3; !PLEASE PROVIDE NEXT PAGE AND DONT RECAPTURE THIS ONE REQ_P3 = BUFFER_LENGTH PON(REQ) %RETURN !* !* DACT(SEND CONTROL):!** CONTROL MESSAGE STATE = MESS_P2>>24 -> STATES(STATE) !* !* STATES(CONNECTING):!** ALLOCATE DEVICE REQ = 0 REQ_DSERV = ALLOCATE DEVICE REQ_SSERV = CP ALLOCATED REQ_P1 = M'CP0'!DEVICE NO REQ_P2 = CP INTERRUPT REQ_P4 = MESS_P1>>16 REQ_P5 = STREAM NO PON(REQ); !TRY TO ALLOCATE %RETURN !* !* STATES(DISCONNECTING):!** DEALLOCATE DEVICE REQ = 0 REQ_DSERV = DEALLOCATE DEVICE REQ_SSERV = CP DEALLOCATED REQ_P1 = M'CP0'!DEVICE NO REQ_P4 = MESS_P1>>16 REQ_P5 = STREAM NO REQ_P6 = DEVICE NO PON(REQ) %RETURN !* !* STATES(ENABLING):!** REQUEST FIRST PAGE REPLY TO COMMS CONTROL(MESS_P1>>16,STREAM NO,0) DEVICE AREA == RECORD(DEVICE TO DA AD(DEVICE NO)) DEVICE AREA_MODE = (MESS_P2>>20)&3; !ISO EBC OR BINARY GET NEXT BUFFER %RETURN !* !* STATES(SUSPENDING): STATES(ABORTING): REPLY TO COMMS CONTROL(MESS_P1>>16,STREAM NO,0) %RETURN !* !* %ROUTINE REPLY TO COMMS CONTROL( %C %INTEGER ACT, STREAM NO, FLAG) REP = 0 REP_DSERV = COMMS COMMAND!ACT REP_SSERV = MESS_DSERV REP_P1 = STREAM NO REP_P2 = FLAG PON(REP) %END; !OF ROUTINE REPLY TO COMMS CONTROL !* !* %ROUTINE GET NEXT BUFFER REQ = 0 REQ_DSERV = REQUEST TRANSFER REQ_SSERV = CP COMMAND REQ_P1 = STREAM NO PON(REQ) %END; !OF ROUTINE GET NEXT BUFFER !* !* %END; !OF ROUTINE CP ADAPTOR %FINISH %ENDOFFILE