!******************************** !* EMAS-2900 FEP AM1 HANDLER * !* FILE: EAM7 * !* DATE: 22.FEB.80 10.00 * !* MODIFIED FOR PCB INTERFACE * !******************************** !! STACK SIZE = 300 %OWNINTEGER FEP NO = 0 %RECORDFORMAT DMF(%INTEGER I) %CONSTRECORD (DMF) %NAME NULL = 0 %SYSTEMROUTINESPEC LINKIN(%INTEGER SER) %SYSTEMROUTINESPEC MAP HWR(%INTEGER SEG) %SYSTEMROUTINESPEC ALARM(%INTEGER TICKS) %CONTROL K'100001' %BEGIN %CONSTSTRING (7)VSN = 'VSN07E' %RECORDFORMAT AM1 LINKF(%INTEGER RXS, RXD, TXS, TXD) %CONSTRECORD (AM1 LINKF) %NAME L = K'064000'; ! IN SEG 3 ? ! %CONSTRECORD (AM1 LINKF) %NAME L = K'075170'; ! I/F #2 %RECORDFORMAT NSI3F(%BYTEINTEGERARRAY A(0:100)) %RECORDFORMAT MEF(%RECORD (MEF) %NAME LINK, %C %BYTEINTEGER LEN, TYPE, %RECORD (NSI3F)NSS) ! THINK ABOUT THE POSITION OF 'LEN' %RECORDFORMAT M2900F(%RECORD (MEF) %NAME LINK, %BYTEINTEGER LEN, TYPE, %C %INTEGER STREAM, SUB IDENT, %C P2A, P2B, P3A, P3B, P4A, P4B, P5A, P5B, P6A, P6B) %RECORDFORMAT M2900CF(%RECORD (MEF) %NAME LINK, %BYTEINTEGER LEN, TYPE, %C %BYTEINTEGERARRAY B(0:23)) %RECORDFORMAT PE(%BYTEINTEGER SER, REPLY, %C FN, PORT, %RECORD (MEF) %NAME MES, %INTEGER STR) %RECORDFORMAT P2F(%BYTEINTEGER SER, REPLY, %C FN, PORT, %RECORD (MEF) %NAME MES, %INTEGER STR) %RECORDFORMAT QF(%RECORD (MEF) %NAME E) %RECORDFORMAT R1F(%INTEGER X) %RECORDFORMAT R2F(%RECORD (MEF) %NAME MES) %RECORDFORMAT R3F(%BYTEINTEGERNAME B) !******************************************************** !* FORMATS OF TABLES, IE STREAM DESCRIPTORS, TCPS ETC * !******************************************************** %RECORDFORMAT STREAMF(%INTEGER OWNER, ID 2900) !************************************************************* !* AM1 COMMANDS (WHEN THE NINTH BIT IS SET) !************************************************************* %CONSTINTEGER PRIMARY = X'00' %CONSTINTEGER FUNNY = 1 %CONSTINTEGER READ = X'02' %CONSTINTEGER WRITE C = X'03' %CONSTINTEGER SENSE = X'04' %CONSTINTEGER WRITE CONTROL = X'05' %CONSTINTEGER IDENTIFY = X'0A' %CONSTINTEGER LIMIT = X'0C' %CONSTINTEGER PROPERTY = X'0E' !***** PRIMARY STATUS BITS (11/34 -> 2900) %CONSTINTEGER UNSUCCESSFUL = X'80' %CONSTINTEGER ATTENTION = X'20' %CONSTINTEGER TERMINATED = X'10' %CONSTINTEGER SHORT BLOCK = X'08' %CONSTINTEGER LONG BLOCK = X'04' %CONSTINTEGER CONDITION X = X'02' %CONSTINTEGER CONDITION Y = X'01' !****************************************** !* 2900 CONSTANTS !****************************************** %CONSTINTEGER PROPERTY CODE = 14; ! AS DEFINED BY K.Y. %CONSTINTEGER ATTN BYTE = X'80' !******************************************************** !* 2900 AM1 LINK TRANSMITTER & RECEIVER BITS !******************************************************** %CONSTINTEGER INT ON = K'100'; ! BOTH %CONSTINTEGER READY = K'200'; ! BOTH %CONSTINTEGER SCFY = K'010'; ! TRANSMITTER ONLY (TXFY) %CONSTINTEGER MAINT = K'002'; ! FORCE PARITY INBOUND ERROR %CONSTINTEGER OPERABLE = K'004'; ! TRANSMITTER ONLY %CONSTINTEGER COMM BIT = K'001' %CONSTINTEGER ACCEPT CHAR = K'002' %CONSTINTEGER RSET = K'004' %CONSTINTEGER ACFY = K'010'; ! PETER CALLS IT RXFY %CONSTINTEGER XOPL = K'020'; ! X OPERABLE - LATCHED %CONSTINTEGER XOP = K'040'; ! X OPERABLE !************************************************************** !* BUFFER MANAGER CALLS (FROM AND TO) * !************************************************************** %CONSTINTEGER BUFFER HERE = 0 !********** TO BUFFER MANAGER *********** %CONSTINTEGER REQUEST BUFFER = 0 %CONSTINTEGER RELEASE BUFFER = 1 !************************************************************** !* CALLS TO 2900 LINK HANDLER * !************************************************************** %CONSTINTEGER SEND DATA = 0 %CONSTINTEGER LOW LEVEL CONTROL = 1 %CONSTINTEGER HERE I AM = 2 %CONSTINTEGER RETURN CONTROL = 3 %CONSTINTEGER STOP = 4 %CONSTINTEGER HIGH LEV CON LEN = 24 ! %CONSTINTEGER LOW LEV CON LEN = 8 !************************************************************** !* REPLIES FROM 2900 LINK HANDLER * !**************************************************************** %CONSTINTEGER INTERF ADDR = 0 %CONSTINTEGER DO INPUT = 1 %CONSTINTEGER DO OUTPUT = 2 %CONSTINTEGER MESSAGE = 3 %CONSTINTEGER MAINFRAME UP = 4 %CONSTINTEGER MAINFRAME DOWN = 5 !*************************************************** !* AM1 LINK STATES !*************************************************** %CONSTINTEGER IDLE = 0 %CONSTINTEGER USER READING = 2 %CONSTINTEGER USER WRITING = 3 %CONSTINTEGER TERMINATE = 4; ! -> IDLE %CONSTINTEGER PROP 1 = 5; ! -> PROP 2 %CONSTINTEGER PROP 2 = 6; ! -> PROP 3 %CONSTINTEGER PROP 3 = 7; ! -> PROP 4 %CONSTINTEGER PROP 4 = 8; ! -> TERMINATE %CONSTINTEGER IDENT 1 = 9; ! -> IDENT 2 %CONSTINTEGER IDENT 2 = 10; ! -> TERMINATE %CONSTINTEGER NEXT CONTROL = 11; ! -> CONTROL M %CONSTINTEGER CONTROL M = 12; ! -> CONTROL M 2 %CONSTINTEGER CONTROL M2 = 13; ! -> CONTROL M 2, OR TERMINATE %CONSTINTEGER TERM X PEND = 14; ! -> TERM X BIT ? %CONSTINTEGER TERM X BIT = 15; ! (?) -> IDLE %CONSTINTEGER ERROR = 16; ! -> IDLE !! IN STATE STATES %CONSTINTEGER INITIAL 4 = 1; ! STATES OF IN STATE %CONSTINTEGER USER READ = 2 %CONSTINTEGER USER WRITE = 3 %CONSTINTEGER CONTROL INPUT TRF = 4 %CONSTINTEGER CONTROL OUTPUT TRF 1 = 5 %CONSTINTEGER CONTROL OUTPUT TRF 2 = 6 %CONSTINTEGERARRAY NEXT STATE(IDLE:ERROR) = IDLE, ERROR, ERROR, ERROR, IDLE, PROP 2,PROP 3, PROP 4, TERMINATE, IDENT 2, TERMINATE, CONTROL M, CONTROL M2, CONTROL M2, TERM X BIT, IDLE, IDLE !**************************************************************** !********** VARIOUS SERVICE NUMBERS ************* %CONSTBYTEINTEGERNAME INT = K'160060' %CONSTBYTEINTEGERNAME OWN ID = K'160030' %CONSTINTEGER GATE SER = 16 %CONSTINTEGER BUFFER MANAGER = 17 %CONSTINTEGER LINK HANDLER = 18 %CONSTBYTEINTEGER AM1 RX INT = -13; ! ???????????????????????? %CONSTBYTEINTEGER AM1 TX INT = -14; ! ???????????????????????/ %CONSTINTEGER T3 SER = 21 %CONSTBYTEINTEGERNAME CHANGE OUT ZERO = K'160310' !************************************************************ !! STATE VARIABLES %OWNINTEGER STATE = 0; ! TRANSMITTER STATE %OWNINTEGER IN STATE = IDLE; ! INPUT STATE %OWNINTEGER TO 2900 CONTROL; ! END OF OUTWARD TRANSFER BUFF %OWNINTEGER CONTROL PT; ! START OF SAME %OWNINTEGER X BIT SENT; ! 1 = X BIT SENT (OR ABOUT TO) %OWNINTEGER TX INT EXPECTED; ! 1 = INTERRUPT EXPECTED %OWNINTEGER TERM COND = TERMINATED; ! HOLDS CONDITION TO GO ON TERMINATE %OWNINTEGER DOWN = 0; ! 0 = UP, 1 = DOWN %OWNINTEGER CLOCK = 0; ! MISSING INTERRUPT COUNT %OWNINTEGER MON = 1; ! MONITORING FLAG %OWNINTEGER SWABF = 1; ! SWAB FLAG %OWNINTEGER TOT OUT L = 0; ! COUNTS CONTROL OUTPUT MESS %OWNINTEGER XOP STATUS = 0 %CONSTBYTEINTEGERARRAY SWABX(0:23) = 1, 0, 3, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 !! %OWNRECORD (STREAMF) %ARRAY STA(-2:350) %OWNRECORD (STREAMF) %NAME STR %OWNRECORD (M2900CF) %NAME OUTM %OWNRECORD (QF) MQ; ! = K'143362' %RECORD (PE) P %OWNRECORD (QF) %NAME BUFFER POOL %OWNINTEGER NO OF BUFF = 0 %RECORD (R1F) R1; %RECORD (R2F) %NAME R2; %RECORD (R3F) %NAME R3 %INTEGER I %OWNINTEGER MON PT = 0 %CONSTINTEGER MON LIM = 63 %OWNBYTEINTEGERARRAY MON1(0:MON LIM) %OWNINTEGERARRAY MON2(0:MON LIM) !************************************************** !* ROUTINE SPECS !************************************************** %ROUTINESPEC INPUT INTERRUPT %ROUTINESPEC OUTPUT INTERRUPT %ROUTINESPEC OUTPUT %ROUTINESPEC INTERRUPT AM1 %ROUTINESPEC USER CALL %ROUTINESPEC CLOCK INT %ROUTINESPEC UP DOWN(%INTEGER WHICH) %ROUTINESPEC FREE BUFFER(%RECORD (MEF) %NAME MES) %RECORD (M2900F) %MAPSPEC GET BUFFER %ROUTINESPEC FAULT(%INTEGER STREAM, TYPE, ADD) %ROUTINESPEC MONITOR(%INTEGER TYPE, INFO) %ROUTINESPEC OCTAL(%INTEGER I) %ROUTINESPEC DUMP REGS !********************************************** !* INITIALISATION * !********************************************** MAP HWR(3); ! MAP TOP SEG TO SEG 3 LINKIN(LINK HANDLER) LINKIN(AM1 RX INT); LINKIN(AM1 TX INT) MAP VIRT(BUFFER MANAGER, 5, 4); ! MAP TO MY SEG 4 MAP VIRT(BUFFER MANAGER, 6, 5); ! AND SEG 6 TO MY 5 STA(2)_ID 2900 = 2; ! ARTIFICIALLY SET STREAM 2 UP ALARM(50) CHANGE OUT ZERO = T3 SER; ! SWITCH O/P TO COMM !! REMOVE THE TX INT BIT, SET THE RX INT BIT AND ACCEPT CHAR? L_TXS=OPERABLE; L_RXS=ACCEPT CHAR!INT ON INTERRUPT AM1 X BIT SENT = 0; ! DONT REALLY WANT A TRANSFER %CYCLE P_SER = 0; POFF(P) %IF P_SER = OWN ID %AND P_REPLY = 0 %START; ! CLOCK INT ALARM(50) %IF 'M' <= INT <= 'O' %START MON = INT-'O'; INT = 0 %FINISH %IF INT = 'F' %START INT = 0 I = MON PT %UNTIL I = MON PT %CYCLE %IF MON1(I) # 0 %START PRINTSYMBOL(MON1(I)); WRITE(MON2(I), 3); NEWLINE %FINISH I = (I+1)&MON LIM %REPEAT NEWLINE %FINISH %IF INT = 'X' %START DUMP REGS INT = 0 %FINISH CLOCK INT %CONTINUE %FINISH %IF MON # 0 %START; ! MONITORING %IF P_REPLY = 0 %THEN I = P_SER %ELSE I = P_FN MONITOR('M', I) %FINISH %IF P_SER = LINK HANDLER %START USER CALL %ELSE %IF P_SER = AM1 RX INT&X'FF' %START INPUT INTERRUPT %ELSE %IF P_SER = AM1 TX INT&X'FF' %THEN OUTPUT INTERRUPT %REPEAT !******************************************************** !* ROUTINES * !******************************************************** %ROUTINE INPUT INTERRUPT !************************************************* !* FIRST PART OF ANY TRANSFER IS FOUR BYTES * !* TWO BYTE STREAM NO, TWO BYTE MAX LENGTH * !************************************************* %INTEGER PP, ERROR TYPE, NINTH BIT, SYM, STREAM, MAX %INTEGER IND, S2, SUB IDENT, EXTRA, I %RECORDFORMAT BYTEAF(%BYTEINTEGERARRAY B(0:200)) %RECORDFORMAT INTAF(%INTEGERARRAY A(0:100)) %RECORDFORMAT R3F(%INTEGERNAME X) %RECORDFORMAT R4F(%RECORD (M2900F) %NAME M) %RECORDFORMAT M2900DF(%BYTEINTEGERARRAY B(0:23)) %RECORDFORMAT MBF(%INTEGER LINK, TWO, %RECORD (M2900DF) M) %OWNRECORD (BYTEAF) HEADER %RECORD (INTAF) %NAME HEAD2 %RECORD (M2900F) %NAME M2900 %RECORD (R3F) R3; %RECORD (R4F) %NAME R4 %RECORD (MBF) %NAME MB %RECORD (P2F) P2 %SWITCH STATE SW(IDLE:CONTROL OUTPUT TRF 2) %SWITCH CONTROL(0:15) PP = 0 HEAD2 == HEADER L_RXS = L_RXS&(\INT ON) %CYCLE I = 1000 %WHILE L_RXS&(READY!XOPL) = 0 %AND I > 0 %CYCLE; I = I-1; %REPEAT %IF I = 0 %START; ! TIMEOUT DUMP REGS FAULT(INSTATE, 'T', STATE) INSTATE = IDLE %EXIT %FINISH %IF L_RXS&XOPL # 0 %START; ! X OPERABLE HAS GONE DOWN PRINTSTRING("XOP DOWN!"); DUMP REGS MONITOR('R', INSTATE) L_RXS = L_RXS&(\XOPL)!ACCEPT CHAR L_TXS = L_TXS&(\INT ON) IN STATE = IDLE TX INT EXPECTED = 0 %UNLESS OUTM == NULL %START PUSH(MQ, OUTM) OUTM == NULL; ! PUT MESSAGE BACK ON Q %FINISH XOP STATUS = 0 %EXIT %FINISH %IF XOP STATUS = 0 # L_RXS&XOP %START; ! XOP HAS COME BACK L_RXS = L_RXS&(\RSET); ! I/F LEAVES RSET ON AFTER XOP BACK %CYCLE I = 1,1,200; %REPEAT; ! WAIT TWO MILLISECS. %IF L_RXS&(READY!ACFY!COMM BIT) %C = (READY!ACFY!COMM BIT) %START PRINT STRING("XOP UP AGAIN ") XOP STATUS = 1 %FINISH %ELSE %START EXTRA = L_RXD; L_RXS = L_RXS!ACCEPT CHAR ERROR TYPE = 6; ->FAIL IT %FINISH %FINISH NINTH BIT = L_RXS&COMM BIT SYM = L_RXD %IF L_RXS&ACFY # 0 %START; ! FAILED TO READ SYM = L_RXD; ! RETRY %IF L_RXS&ACFY # 0 %START; ! HARD FAILURE PRINTSTRING("AM1: PARITY ERROR "); ERROR TYPE = 5; EXTRA = L_RXD; -> FAIL IT %FINISH %FINISH L_RXS = L_RXS!ACCEPT CHAR %IF NINTH BIT = 0 %START; ! 'TRUE' DATA HEADER_B(PP+SWABF) = SYM PP = PP+1; SWABF = SWABF!!X'FFFE'; ! FLIP 1 -> -1 -> 1 !************************************************* !* NOTE: ALL 'DATA' BYTES SWAPPED ON ENTRY * !************************************************* MONITOR('I', SYM) %IF MON # 0 %CONTINUE; ! GET NEXT CHAR %FINISH %IF MON # 0 %THEN MONITOR('C', SYM) ->CONTROL(SYM&15); ! CONTROL COMMAND CONTROL(LIMIT): %IF STATE # IDLE %START MONITOR('X', STATE) STATE = TERMINATE %EXIT %IF TX INT EXPECTED # 0; ! WILL BE COMING ->CHECK TRANSMITTER %FINISH CONTROL(WRITE C): CONTROL(READ): ->STATE SW(IN STATE) CONTROL(PROPERTY): TO 2900 CONTROL = 0; TERM COND = TERMINATED; X BIT SENT = 0 UP DOWN(0); ! NOW UP STATE = PROP 1; ->CHECK TRANSMITTER CONTROL(IDENTIFY): STATE = IDENT 1; -> CHECK TRANSMITTER CONTROL(SENSE): STATE = PROP 3; ! SENDS 0, 0 CHECK TRANSMITTER: ! ATTEMPT TO SEND A CHARACTER OUTPUT %EXIT STATE SW(INITIAL 4): %IF DOWN = 1 %START; ! WAS DOWN ! UP DOWN(0); ! PUT IT BACK UP %FINISH %IF PP # 4 %START ERROR TYPE = 1; EXTRA = PP; -> FAIL IT %FINISH STREAM = HEAD2_A(0); MAX = HEAD2_A(1) MONITOR('S', STREAM) STR == STA(STREAM) %IF STREAM > 0 %START; ! DATA COMING/GOING %IF STR_OWNER # 0 %START P_SER = STR_OWNER; P_REPLY = LINK HANDLER P_MES == NULL P_PORT = MAX P_STR = STREAM PP = 0 IN STATE = (STREAM&1)+USER READ ! EVEN = AM1 INPUT, ODD = AM1 OUTPUT STATE = TERMINATE; OUTPUT; ! SEND A 'PRIM STAT' %CONTINUE !* IE PICK UP THE 'WRITE C' OR 'READ' BEFORE GOING TO USER %FINISH ERROR TYPE = 2; EXTRA = STREAM; ->FAIL IT; ! STREAM NOT IN USE %FINISH !* MUST BE A CONTROL STREAM TRANSFER ******** PP = 0 %IF STREAM = -2 %START !! INWARD CONTROL STREAM IN STATE = CONTROL INPUT TRF %ELSE !! OUTWARD CONTROL STREAM (-1) IN STATE = CONTROL OUTPUT TRF 1 %FINISH STATE = TERMINATE OUTPUT %EXIT STATE SW(USER READ): ! PICK UP 'READ' COMMAND STATE SW(USER WRITE): ! PICK UP 'WRITE' COMMAND %IF PP # 0 %START ERROR TYPE = 3; EXTRA = PP; ->FAIL IT; ! DATA NOT EXPECTED %FINISH P_FN = IN STATE-1; ! READ=2=DOINPUT, WRITE=3=DOOUTPUT PON(P) STATE = IN STATE; ! TRANSFER 11/34 -> AM1 OR REVERSE %RETURN STATE SW(CONTROL INPUT TRF): ! IE 11/34 -> 2900 CONTROL PT = 0 IN STATE = IDLE; ! NOTHING MORE COMING IN STATE = CONTROL M %IF MQ_E == NULL %START MONITOR('?', TO 2900 CONTROL) STATE = TERMINATE %FINISH -> CHECK TRANSMITTER STATE SW(CONTROL OUTPUT TRF 2): ! IE 2900 -> 11/34 !* AFTER THE 'LIMIT' - DATA HAS BEEN READ !! NOW CYCLE UP THE BUFFER, FIRING THE REQUESTS IND = 0; R4 == R3 %CYCLE S2 = HEAD2_A(IND); R3_X == HEAD2_A(IND) SUB IDENT = HEAD2_A(IND+1) %IF MON # 0 %THEN MONITOR('L', S2) STR == STA(S2) %IF STR_OWNER = 0 %THEN FAULT(S2, 'S', IND) %ELSESTART M2900 == GET BUFFER MB == M2900; ! ALIGN IT TO DATA AREA MB_M = R4_M; ! AND COPY IT ACCROSS !! PICK UP "ID 2900" IF ITS A CONNECTING MESSGAE %IF MB_M_B(5)=2 %THEN STR_ID 2900 = M2900_P2B P2_SER = STR_OWNER; P2_REPLY = LINK HANDLER P2_FN = MESSAGE P2_MES == M2900 PON(P2) %FINISH IND = IND+HIGH LEV CON LEN//2 %EXIT %IF IND >= PP//2 %REPEAT IN STATE = IDLE STATE = TERM X BIT; ! SEND X BIT IF NECESSARY OUTPUT %EXIT CONTROL(WRITE CONTROL): ! WRITE CONTROL FROM 2900 !! THIS CAN ONLY HAPPEN AT THE BEGINNING OF A TRANSFER !! FROM THE 2900, SO WHATEVER THE STATE, FORCE IT TO IDLE STATE SW(IDLE): EXTRA = PP %IF PP # 0 %THEN ERROR TYPE = 6 %AND -> FAIL IT ! NO CONTROL CHAR ?? CLOCK = 0 SWABF = 1; ! USED TO "SWAB" THE BYTES IN STATE = INITIAL 4; %CONTINUE STATE SW(CONTROL OUTPUT TRF 1): ! SEEN THE 'WRITE' COMMAND IN STATE = CONTROL OUTPUT TRF 2 %REPEAT L_RXS = L_RXS!INT ON %RETURN CONTROL(FUNNY): ! SHOULD NOT OCCUR CONTROL(6):CONTROL(7):CONTROL(8): CONTROL(9):CONTROL(11):CONTROL(13):CONTROL(15): ERROR TYPE = 5; EXTRA = SYM FAIL IT: FAULT(ERROR TYPE, 'I', EXTRA) L_RXS = L_RXS!INT ON; IN STATE = IDLE TERM COND = UNSUCCESSFUL!TERMINATED; STATE = TERMINATE OUTPUT %END %ROUTINE OUTPUT INTERRUPT !******************************************** !* ROUTINE HANDLES OUTPUT INTERRUPT FROM AM1 * !********************************************* L_TXS = L_TXS&(\INT ON) %IF TX INT EXPECTED = 0 %START FAULT(0, 'O', STATE) %ELSE !! SHOULD BE TERMINATE, SO BACK TO START !! WHAT IF IT CROSSED WITH THE 1ST LOW LEVEL CONTROL?? TX INT EXPECTED = 0; CLOCK = 0 OUTPUT; ! SEE WHATS UP %FINISH %END %ROUTINE OUTPUT !! THIS ROUTINE IS ENTERED TO CHECK WHETHER A CHARACTER CAN !! BE SEND TO THE 2900 !! IF IT CAN, THEN CHARACTERS ARE SENT UNTIL - !! 1) IT GOES 'BUSY' - IN WHICH CASE AN INTERRUPT IS REQUESTED !! 2) ALL HAS GONE - THE STATE THEN GOES TO IDLE %INTEGER I, SYM, OSTATE %SWITCH TS(IDLE:ERROR) %CYCLE %IF L_TXS&READY = 0 %START; ! 'BUSY' L_TXS = L_TXS!INT ON; ! PUT INTS ON TX INT EXPECTED = 1; ! SET THE FLAG %RETURN %FINISH L_TXS = L_TXS&(\COMM BIT); ! ENSURE NINTH BIT OFF OSTATE = STATE -> TS(STATE) TS(TERM X BIT): ! SEND TERMINATE+X BIT IF NECESSARY SYM = TERM COND!X BIT SENT -> SET COMM BIT TS(TERMINATE): SYM = TERM COND SET COMM BIT: L_TXS = L_TXS!COMM BIT MONITOR('D', -SYM) %IF MON # 0 TERM COND = TERMINATED -> SEND TS(PROP 1): SYM = PROPERTY CODE; -> SEND TS(PROP 2): SYM = FEP NO; -> SEND TS(PROP 3): TS(PROP 4): TS(IDENT 1): SYM = 0; -> SEND TS(IDENT 2): SYM = ATTN BYTE; -> SEND TS(CONTROL M): ! SET UP TRANSFER OUTM == POP(MQ); ! GET NEXT ENTRY TO 2900 CONTROL = OUTM_LEN; ! GET THE LENGTH CONTROL PT = 0; ! START AT BEGINNING TS(CONTROL M2): SYM = OUTM_B(SWABX(CONTROL PT)) CONTROL PT = CONTROL PT+1; TOT OUT L = TOT OUT L+1 %IF CONTROL PT = TO 2900 CONTROL %START FREE BUFFER(OUTM) OUTM == NULL %UNLESS MQ_E == NULL %OR TOT OUT L > 180 %START STATE = NEXT CONTROL; ! GET THE NEXT BUFFER %ELSE STATE = TERM X PEND !! ** NEXT STATE = TERM X BIT - SEND X BIT IF NECESSARY TO 2900 CONTROL = 0 X BIT SENT = 0 %UNLESS MQ_E == NULL %THEN INTERRUPT AM1 %FINISH %FINISH SEND: %IF L_TXS&COMM BIT # 0 %AND SYM = (UNSUCCESSFUL!TERMINATED) %START ! PRINT STRING("ABTERM")! DUMP REGS L_TXD = SYM L_RXS = L_RXS!ACCEPT CHAR %IF L_RXS&ACFY = 0 %FINISH %ELSE L_TXD = SYM MONITOR('D', SYM) %IF MON # 0 STATE = NEXT STATE(STATE) %REPEAT TS(ERROR): FAULT(STATE, 'E', OSTATE) TS(IDLE): %END %ROUTINE INTERRUPT AM1 %IF STATE = IDLE %AND IN STATE = IDLE %START TERM COND = ATTENTION; STATE = TERMINATE OUTPUT; ! KICK THE TRANSMITTER %FINISH X BIT SENT = CONDITION X TOT OUT L = 0 %END %ROUTINE USER CALL !**************************************************** !* REASONS * !* 0) SEND DATA - HIGH LEVEL CONTROL * !* 1) LOW LEVEL CONTROL * !* 2) HERE I AM - IPL INFO WANTED * !* 3) RETURN CONTROL - WAS READING/WRITING * !**************************************************** %CONSTINTEGERARRAY TYPEA(0:5) = TERMINATED, SHORT BLOCK, LONG BLOCK, UNSUCCESSFUL, CONDITION Y, TERMINATED %INTEGER FN, I, LEN, PP, STREAM %BYTEINTEGER IND %RECORD (M2900F) %NAME M2900 %RECORD (M2900CF) %NAME M2900C %SWITCH USER SW(SEND DATA:STOP) ->USER SW(P_FN) USER SW(SEND DATA): ! HIGH LEVEL CONTROL ->2900 USER SW(LOW LEVEL CONTROL): LEN = HIGH LEV CON LEN M2900C == P_MES; M2900 == M2900C STREAM = STA(M2900_STREAM)_ID 2900 %IF STREAM = 0 %START; ! ERROR PRINTSTRING("AM1: ATTEMPT TO SEND ZERO STREAM, STREAM = ") WRITE(M2900_STREAM, 1); WRITE(M2900_SUB IDENT, 1) WRITE(M2900_P2A, 1); NEWLINE FREE BUFFER(M2900); %RETURN; ! JUNK IT %FINISH M2900_STREAM = STREAM M2900_LEN = LEN; ! HOLD ITS LENGTH %IF DOWN = 0 %START; ! 2900 IS UP %IF MQ_E == NULL %THEN INTERRUPT AM1 PUSH(MQ, M2900) !****************************************************** !* NOTE: STREAM & SUB IDENT ARE ALWYS SWABBED !******************************************************* %ELSE FREE BUFFER(M2900); ! JUNK IT %RETURN USER SW(RETURN CONTROL): %UNLESS USER READING <= STATE <=USER WRITING %START FAULT(IN STATE, 'R', STATE) %ELSE IND = P_STR; ! TYPE OF TERMINATION %IF IND&64 = 0 %START; ! XOPL NOT SET. TERM COND = TYPEA(IND&7)!TERMINATED; ! SEND THE TERMINATE STATE = TERM X BIT; ! APPEND X BIT AS NECESSARY OUTPUT %IF IND&128 # 0 %START; ! CHAR TO ACCEPT %WHILE L_TXS&READY = 0 %CYCLE; %REPEAT L_RXS = L_RXS!ACCEPT CHAR MONITOR('U', I) %IF MON # 0 %FINISH %FINISH INTS ON: L_RXS = L_RXS!INT ON; IN STATE = IDLE %FINISH %RETURN USER SW(HERE I AM): STREAM = P_STR STA(STREAM)_OWNER = P_REPLY; ! ENABLE THE STREAM %IF STREAM < 10 %START; ! CONTROL STREAMS P_SER = P_REPLY; P_REPLY = LINK HANDLER P_FN = INTERF ADDR; P_MES == L; ! PASS ADDR OF "L" PON(P) %FINISH %RETURN USER SW(STOP): ! STOP THE AM1 L = 0; ! CLEAR INT BITS %STOP %END !* ROUTINE CLOCK INT %ROUTINE CLOCK INT !! HANDLES CLOCK INTERRUPTS %IF TX INT EXPECTED # 0 %OR X BIT SENT # 0 %START CLOCK = CLOCK+1 MONITOR('W', CLOCK) %IF CLOCK = 5 %START; ! EMERGENCY ACTION PRINTSTRING("AM1:DYING") DUMP REGS L_TXS = L_TXS&(\OPERABLE); ! DROP OPERABLE %CYCLE I = 1,1,10; %REPEAT; ! DELAY L_TXS = L_TXS!OPERABLE %RETURN %FINISH %IF CLOCK = 15 %AND L_TXS&READY#0 %THEN INTERRUPT AM1 %IF CLOCK = 30 %START; ! 30 SEC TIMEOUT FAULT(X BIT SENT, 'C', TX INT EXPECTED) UP DOWN(1) STATE = IDLE; IN STATE = IDLE L_TXS = L_TXS&(\INT ON) INT = 'F' %FINISH %ELSE CLOCK = 0 %END !* ROUTINE UP DOWN %ROUTINE UP DOWN(%INTEGER WHICH) %INTEGER I DOWN = WHICH %CYCLE I = 2, 1, 4 %IF STA(I)_OWNER # 0 %START P_SER = STA(I)_OWNER; P_REPLY = LINK HANDLER P_FN = MAINFRAME UP+WHICH P_MES == NULL PON(P) %FINISH %REPEAT !* TIDY UP VARIABLES X BIT SENT = 0; TX INT EXPECTED = 0 %WHILE %NOT MQ_E == NULL %CYCLE FREE BUFFER(POP(MQ)) %REPEAT %END %ROUTINE FREE BUFFER(%RECORD (MEF) %NAME MES) %RECORD (PE) P %IF NO OF BUFF > 13 %START P_SER = BUFFER MANAGER; P_REPLY = OWN ID P_FN = RELEASE BUFFER; P_MES == MES PON(P) %ELSE !! Q IT MES_LINK == BUFFER POOL; BUFFER POOL == MES NO OF BUFF = NO OF BUFF+1 %FINISH %END %RECORD (M2900F) %MAP GET BUFFER %IF BUFFER POOL == NULL %START; ! ASK FOR IT P_SER = BUFFER MANAGER; P_REPLY = OWN ID P_FN = REQUEST BUFFER; P_STR = 1; ! SHORT BUFFER PONOFF(P) %ELSE P_MES == BUFFER POOL; BUFFER POOL == P_MES_LINK P_MES_LINK == NULL NO OF BUFF = NO OF BUFF-1 %FINISH %RESULT == P_MES %END %ROUTINE FAULT(%INTEGER STREAM, TYPE, ADD) PRINTSTRING('AM1: FAULT '); PRINTSYMBOL(TYPE) WRITE(STREAM, 3) PRINTSTRING(', '); WRITE(ADD, 1); NEWLINE MONITOR('F', TYPE) %IF INT # 'A' %END %ROUTINE MONITOR(%INTEGER TYPE, INFO) MON1(MON PT) = TYPE; MON2(MON PT) = INFO MON PT = (MON PT+1)&MON LIM %END %ROUTINE OCTAL(%INTEGER I) %INTEGER N SPACE %CYCLE N = 15, -3, 0 PRINTSYMBOL((I>>N)&7+'0') %REPEAT %END %ROUTINE DUMP REGS PRINTSTRING(" R"); OCTAL(L_RXS) PRINTSTRING(" T"); OCTAL(L_TXS) NEWLINE %END %ENDOFPROGRAM