!***************************** !* * !* DZ11 HANDLER * !* DATE: 10.FEB.82 * !* FOR ERTE: DATA GENERAL * !***************************** ! STK = 300, STREAMS = 0 %CONTROL K'100001' %CONSTSTRING (13) VSN = "Dz11:vsn001a " %RECORDFORMAT DUMF(%INTEGER D) %CONSTRECORD (DUMF) %NAME NULL = 0 %SYSTEMROUTINESPEC ALARM(%INTEGER TICKS) %SYSTEMROUTINESPEC LINKIN(%INTEGER SER) %SYSTEMROUTINESPEC MAPHWR(%INTEGER SEGS) %BEGIN %RECORDFORMAT DZ11F(%INTEGER CSR, RBUF, TCR, TDR) ! Definition of DZ11_CSR %CONSTINTEGER CLR = K'20'; ! MASTER CLEAR %CONSTINTEGER MSE = K'40'; ! MASTER SCAN ENABLE %CONSTINTEGER RIE = K'100'; ! RECEIVER INTERRUPT ENABLE %CONSTINTEGER RXDONE = K'200'; ! RECEIVER RREADY ! BITS 8-10 (K'400'-K'200') - TRANSMITTER READY NUMBER %CONSTINTEGER SAE = K'10000'; ! SILO ALARM ENABLE %CONSTINTEGER SALARM = K'20000'; ! SILO ALARM %CONSTINTEGER TIE = K'40000'; ! TRANSMITTER INTERRUPT ENABLE %CONSTINTEGER TXRDY = K'100000'; ! TRANSMITTER READY ! Definition of DZ11_RBUF (READ ONLY) ! BITS 0 - 7 INPUT CHARACTER ! 8 - 10 IINPUT LINE NUMBER (K'400'-K'2000') %CONSTINTEGER PARITY ERROR = K'10000', %C FRAMING ERROR = K'20000', %C OVERRUN = K'40000', %C DATA VALID = K'100000' ! Definition of DZ11_Line Parameter Register (WRITE PART OF _RBUF) ! BITS 0 - 2 LINE NUMBER BEING LOADED ! 3 - 4 CHARACTER LENGTH (11 = 8 BITS) %CONSTINTEGER EIGHT BITS = K'30', %C STOP CODE = K'40'; ! 0 = 1 STOP, 1 = 2 STOP %CONSTINTEGER PARITY = K'100'; ! 1 = ON %CONSTINTEGER ODD PARITY = K'200'; ! 1 = ODD PARITY, 0 = EVEN %CONSTINTEGER SPEED 2400 = K'5000' %CONSTINTEGER REC ON = K'10000'; ! PUTS THE REC ON ! ! Character Definitions ! %CONSTINTEGER SOH = 1, STX = 2, ETX = 3, EOT = 4, ACK = 6, %C DLE = X'10', ETB = X'17', NAK = X'15' %CONSTINTEGER NO SPEC = 6 %CONSTBYTEINTEGERARRAY SPEC(1:NO SPEC) = SOH, ACK, EOT, NAK, ETX, ETB %CONSTINTEGERARRAY T LINE EN(0:7) = 1, 2, 4, 8, 16, 32, 64, 128 ! RELEVANT TRANSMITTER ENABLE BIT FOR EACH LINE IN DZ_TCR ! NB: DTR BITS MAY HAVE TO BE SET AS WELL %RECORDFORMAT DZZ(%INTEGER INDEX, %RECORD (DZ11F) %NAME DZ11) %OWNRECORD (DZ11F) %NAME DZ %OWNRECORD (DZZ) %NAME DZD %OWNRECORD (DZZ) %ARRAY DZ11A(0:3) ! ! Record format for a single dz line ! %RECORDFORMAT LINEF(%INTEGER INDEX, STATE, O STATE, %C INCOUNT, INMAX, OUTCOUNT, %C OUTMAX, INBUFF, OUTBUFF, LASTICHAR, ICKSM, RICKSM, OCKSM, CKSM ERR, %C NO INPUT, I SER, O SER, TERM CH) %OWNRECORD (LINEF) %NAME L %OWNRECORD (LINEF) %ARRAY LINEA(0:31) %RECORDFORMAT MEF(%BYTEINTEGERARRAY A(0:199)) %RECORDFORMAT PF(%BYTEINTEGER SER, REPLY, A1, A2, %INTEGER B, %C %BYTEINTEGER C1, C2) %RECORDFORMAT P2F(%BYTEINTEGER SER, REPLY, %INTEGER A, %RECORD (MEF) %C %NAME B, %INTEGER C) %RECORD (PF) P %RECORD (P2F) %NAME P2 %CONSTINTEGER PROT SER = 26 %CONSTINTEGER DZSER = 27; ! HANDLERS MAIN SERVICE NUMBER %CONSTBYTEINTEGERNAME ID = K'160030' %CONSTBYTEINTEGERNAME INT = K'160060' ! CALLS & REPLIES TO LINE HANDLER ROUTINES %CONSTINTEGER LINE INPUT = 1 %CONSTINTEGER LINE OUTPUT = 2 %CONSTINTEGER INPUT HERE = 3 %CONSTINTEGER OUTPUT DONE = 4 %OWNINTEGER RXINT, TXINT, I %OWNINTEGER MON = -1; ! 0=OFF %ROUTINESPEC INTS OFF %ROUTINESPEC INTS ON %ROUTINESPEC RECEIVE %ROUTINESPEC TRANSMIT %ROUTINESPEC INITIALISE %ROUTINE DO ALL INTERRUPTS ! ! Whatever interrupt actually comes in, all DZs are serviced ! %INTEGER I, J, N INTS OFF; ! PUT ALL INTS OFF %CYCLE N = 1, 1, 2; ! SERVICE ALL TWICE %CYCLE I = 0, 1, 3 DZD == DZ11A(I); DZ == DZD_DZ11 %UNLESS DZ == NULL %START RECEIVE; ! CHECK RECEIVE TRANSMIT; ! CHECK TRANSMIT %FINISH %REPEAT %REPEAT INTS ON %END %ROUTINE TELL PRINTSTRING("DZ11 Line"); WRITE(L_INDEX, 1); PRINTSYMBOL(':') %END %ROUTINE INTS ON %INTEGER I %RECORD (DZ11F) %NAME DZ %CYCLE I = 0, 1, 3 DZ == DZ11A(I)_DZ11 %UNLESS DZ == NULL %START DZ_CSR = DZ_CSR!RIE!TIE %FINISH %REPEAT %END %ROUTINE INTS OFF %INTEGER I %RECORD (DZ11F) %NAME DZ %CYCLE I = 0, 1, 3 DZ == DZ11A(I)_DZ11 %UNLESS DZ == NULL %START DZ_CSR = DZ_CSR&(\(RIE!TIE)) %FINISH %REPEAT %END %ROUTINE DO INPUT REPLY(%INTEGER FAULT) ! ! Tell Prot that the buffer has arrived ! P_SER = PROT SER; P_REPLY = DZSER P_A1 = INPUT HERE; P_A2 = L_INDEX P_B = L_IN BUFF P_C1 = L_IN COUNT; P_C2 = FAULT; ! 0 = OK, OTHERS ARE ERRORS PON(P) L_IN COUNT = 0; L_STATE = 0; ! NO BUFFER PRESENT ! NB: On an error would it be better ! to hang onto the buffer ??? %END %ROUTINE DO OUTPUT REPLY ! ! Tell Prot that the output transfer has terminated ! P_SER = PROT SER; P_REPLY = DZSER P_A1 = OUTPUT DONE; P_A2 = L_INDEX PON(P) %END %ROUTINE PUT READ ON ! ! Accept a buffer to put input in from the protocol handler ! %IF L_INBUFF # 0 %START TELL; PRINTSTRING("Read already on! ") %CYCLE; %REPEAT %FINISH L_IN BUFF = P_B; ! GET BUFFER ADDRESS L_I SER = P_C2; ! GET THE OWNER'S ID L_IN COUNT = 0 L_STATE = 1; ! 1 = GOT BUFFER L_IN MAX = 200; ! GET IT OUT OF P_C1 ? %END %ROUTINE PUT WRITE ON ! ! Accept a buffer with output in from the protocol handler ! Nb: The buffer may not belong to the protocol handler - see p_c2 ! %IF L_O STATE # 0 %START TELL; PRINTSTRING("Already outputting, STATE =") WRITE(L_O STATE, 1); NEWLINE %CYCLE; %REPEAT %FINISH L_OUT BUFF = P_B; ! PICKUP THE BUFFER ADDRESS L_O SER = P_C2; ! OWNER OF THE BUFFER L_OUT MAX = P_C1; ! LENGTH OF DATA IN BUFFER L_OUT COUNT = 0 %IF P_A2&128 # 0 %THEN L_TERM CH = ETB %ELSE L_TERM CH = ETX L_O STATE = 1; ! READY TO GO ! NOW KICK THE DZ11 DZD == DZ11A(L_INDEX>>3); ! FIND THE DZ DESCRIPTOR DZ == DZD_DZ11 %IF DZ == NULL %START TELL; PRINTSTRING("No DZ11 for this line! ") %ELSE DZ_TCR = DZ_TCR!T LINE EN(L_INDEX&7); ! ENABLE THE TRANSMITTER %FINISH %END %RECORD (MEF) %MAP MAP TO(%INTEGER AD, SER) %OWNINTEGER MSEG, MSER %INTEGER I, SEG %RECORDFORMAT R1F(%INTEGER X); %RECORDFORMAT R2F(%RECORD (MEF) %NAME M) %RECORD (R1F) R1; %RECORD (R2F) %NAME R2 R2 == R1 SEG = AD>>13; ! GET BUFFERS SEG ADDRESS %IF SEG # MSEG %OR SER # MSER %START ! IF NOT MAPPED ALREADY TO THAT SEG MAP VIRT(0, -1, 4); ! MAP OFF IT MAP VIRT(SER, SEG, 4); ! AND ON TO DESIRED SEG MSEG = SEG; MSER = SER; ! REMEMBER WHO & WHAT %FINISH R1_X = AD&K'17777'+K'100000'; ! CONSTRUCT BUFF ADDRESS IN SEG #4 %RESULT == R2_M; ! AND PASS IT BACK AS A RECORD %END ! ! R O U T I N E R E C E I V E ! %ROUTINE RECEIVE ! Assumes that DZ has been set up pointing to a relevant dz11 %INTEGER I, N, SYM, LINE NO, FAULT %RECORD (MEF) %NAME IBUF %SWITCH SW(0:4) %INTEGERFN ADD TO BUFFER(%INTEGER SYM) %INTEGER I L_I CKSM = L_I CKSM+SYM; ! SUM CHECK BEFORE DLE REMOVAL %IF SYM = DLE %START %IF L_LAST I CHAR # DLE %START; ! 1ST DLE SEEN L_LAST I CHAR = DLE; ! NOTE THE DLE %RESULT = 0; ! OTHERWISE, ITS NOT SIGNIFICANT %FINISH L_LAST I CHAR = 0; ! PAST THE SIGNIFICANCE OF LAST DLE %FINISH IBUF == MAP TO(L_IN BUFF, L_I SER); ! MAP ONTO THE INPUT BUFFER IBUF_A(L_INCOUNT) = SYM; ! PT CHAR IN BUFFER L_IN COUNT = L_IN COUNT+1; ! AND COUNT IT %RESULT = 0 %IF SYM > ETB; ! NOT A SPECIAL CHAR %CYCLE I = 1, 1, NO SPEC; ! TEST FOR SPECIAL CHAR %RESULT = I %IF SPEC(I) = SYM %REPEAT %RESULT = 0; ! NOT A SPECIAL CHAR %END ! Interrupts should already be off %CYCLE SYM = DZ_RBUF; ! Find out if there is a valid char %EXIT %IF SYM&DATA VALID # 0; ! There wasn't %IF SYM&(PARITY ERROR!FRAMING ERROR!OVERRUN) # 0 %START FAULT = 4; ! ASSUME PARITY ERROR %IF SYM&FRAMING ERROR # 0 %THEN FAULT = 2 %IF SYM&OVERRUN # 0 %THEN FAULT = 1 DO INPUT REPLY(FAULT) %ELSE; ! Char valid LINE NO = (SYM>>8)&7+DZD_INDEX<<3; ! GET ITS FULL LINE NO L == LINEA(LINE NO) SYM = SYM&X'FF'; ! Only interestred in data bits now -> SW(L_STATE); ! Action dependant on state ! ! Nb: Spec says that if a char is received when transmitting, ! the Transmission should be aborted ! ! SW(0): ! NO Input buffer L_NO INPUT = L_NO INPUT+1 ->OUT; ! DITCH IT SW(1): ! BUFFER, IN DATA MODE I = ADD TO BUFFER(SYM) %IF I # 0 %START; ! SIGNIFICANT CHAR RECD %IF I < NOSPEC-1 %START DO INPUT REPLY(0); ! NO SUM CHECK SOH-NAK %ELSE L_STATE = L_STATE+1; ! SUM CHECK ON ETB/ETX %FINISH %FINISH -> OUT SW(2): ! 1ST BYTE OF SUM CHECK L_RICKSM = SYM L_STATE = L_STATE+1; ! WAIT FOR 2ND BYTE -> OUT SW(3): ! 2ND BYTE OF SUM CHECK FAULT = 0 L_RICKSM = L_RICKSM!SYM<<8 %IF L_RICKSM # L_ICKSM %START; ! SUM CHECKS DO NOT AGREE L_CKSM ERR = L_CKSM ERR+1 FAULT = 3 %FINISH DO INPUT REPLY(FAULT); ! TELL UPPER LEVEL OUT: %FINISH %REPEAT %END %ROUTINE TRANSMIT ! Check the DZ11, pointed at by DZ, to see if any line requires ! attention. ! It may be that nothing needs to be done - they are checked on any ! interrupt %INTEGER I, LINE, LINE NO, N %RECORD (MEF) %NAME OBUF %SWITCH SW(0:5) %CYCLE; ! KEEP GOING TILL ITS 'IDLE' %RETURN %UNLESS DZ_CSR < 0; ! IE IF NOT TR READY LINE = (DZ_CSR>>8)&7; ! PICK UP THE LINE NUMBER LINE NO = DZD_INDEX<<3+LINE;! AND MY OVERALL LINE NUMBER L == LINEA(LINE NO); ! THE LINE DESCIPTOR -> SW(L_O STATE); ! ACTION DEPENDANT ON STATE SW(1): ! 1ST AND SUBSEQUENT CHARACTERS OBUF == MAP TO(L_OUT BUFF, L_O SER); ! MAP TO THE OUTPUT BUFFER N = OBUF_A(L_OUT COUNT); ! GET THE NEXT CHARACTER TO GO DZ_TDR = N; ! AND PUT IT OUT L_OUT COUNT = L_OUT COUNT+1 %IF L_OUT COUNT = L_OUT MAX %START; ! ALL DONE DO OUTPUT REPLY; ! SIGNAL IT TO PROT L_OUT BUFF = 0; ! PUT LINE TO IDLE ON NEXT INT %IF L_OUT MAX = 1 %THEN L_O STATE = 5-1 L_O STATE = L_O STATE+1 ! CKSM ONLY ON BLOCKS > 1 CHAR %FINISH L_O CKSM = L_O CKSM+N %CONTINUE SW(2): ! FINAL CHAR ETB/ETX - NOT IN CKSM DZ_TDR = L_TERM CH L_O STATE = L_O STATE+1 %CONTINUE SW(3): ! 1ST CHAR OF CKSM DZ_TDR = L_O CKSM>>8 L_O STATE = L_O STATE+1 %CONTINUE SW(4): ! 2ND CHAR OF CKSM DZ_TDR = L_O CKSM&X'FF' L_O STATE = L_O STATE+1 %CONTINUE SW(0): ! SHOULD NOT OCCUR (IDLE) SW(5): ! GOING IDLE DZ_TCR = DZ_TCR&(\T LINE EN(LINE)) ! KNOCK DOWN ITS TRANSMITTER ENABLE L_O STATE = 0 %REPEAT %END %ROUTINE INITIALISE %INTEGER I, LINE, LINE NO %CYCLE I = 0, 1, 3; ! OVER THE DZ11S DZ == DZ11A(I)_DZ11 %CONTINUE %IF DZ == NULL %CYCLE LINE = 0, 1, 7; ! INDIVIDUAL LINES LINE NO = I<<3+LINE L == LINEA(LINE NO) DZ_RBUF = LINE!EIGHT BITS!PARITY!ODD PARITY!SPEED 2400!REC ON ! INITIALISE IT %REPEAT %REPEAT %END ! ! Main Program Starts Here ! LINKIN(DZSER); ! ACCEPT MESSAGES HERE LINEA(I)_INDEX = I %FOR I = 0, 1, 31 DZ11A(I)_INDEX = I %FOR I = 0, 1, 3 PRINTSTRING(VSN) P2 == P %CYCLE P_SER = 0; POFF(P); ! WAIT FOR INSTRUCTIONS HERE I = P_A1; ! LINE NUMBER %EXIT %IF I = 255; ! NO MORE DZ11'S DZ11A(I)_DZ11 == P2_B; ! GET ITS HARDWARE ADDRESS RXINT = P_C1!X'FF00'; TXINT = P_C2!X'FF00'; ! INTERRUPTS LINKIN(RXINT); LINKIN(TXINT); ! GET READY FOR INTERRUPTS %REPEAT INITIALISE; ! Start up the DZ11s ALARM(50); ! WAKE UP EVERY SECOND INTS ON; ! PUT ALL THE INTS ON %CYCLE; ! MAIN LOOP P_SER = 0; POFF(P); ! WAIT FOR MESSGE %IF P_SER&X'80' # 0 %START; ! INTERRUPT DO ALL INTERRUPTS %CONTINUE %FINISH %IF P_SER = DZSER %START; ! INSTRUCTIONS FROM ABOVE L == LINEA(P_A2&31); ! PICKUP LINE DESCRIPTOR %IF P_A1 = LINE INPUT %THEN PUT READ ON %IF P_A1 = LINE OUTPUT %THEN PUT WRITE ON %CONTINUE %FINISH %IF P_REPLY = 0 %START; ! CLOCK ALARM(50); ! REPEAT THE CLOCK CALL %IF 'M' <= INT <= 'P' %START; ! LOOK FOR INTS MON = 'O'-INT; ! O IS OFF INT = 0 %FINISH %FINISH %REPEAT %ENDOFPROGRAM