.MCALL .MODULE .MODULE EL,VERSION=24,COMMENT=,AUDIT=YES ; Copyright (c) 1998 by Mentec, Inc., Nashua, NH. ; All rights reserved ; ; This software is furnished under a license for use only on a ; single computer system and may be copied only with the ; inclusion of the above copyright notice. This software, or ; any other copies thereof, may not be provided or otherwise ; made available to any other person except for use on such ; system and to one who agrees to these license terms. Title ; to and ownership of the software shall at all times remain ; in Mentec, Inc. ; ; The information in this document is subject to change without ; notice and should not be construed as a commitment by Digital ; Equipment Corporation, or Mentec, Inc. ; ; Digital and Mentec assume no responsibility for the use or ; reliability of its software on equipment which is not supplied ; by Digital or Mentec, and listed in the Software Product ; Description. ;++ ; ; Edit Who Date Description of modification ; ---- --- ---- --------------------------- ; 001 WLD 23-OCT-90 In installation/verification code, ; replace check of FBMON$ with ; test on #jobs supported. ; 002 WLD 10-JUN-92 Replace .GTIM & .DATE in GETDAT ; subroutine with call to monitor. ; 003 WLD 11-JUN-92 Remove .PRINTs. ; 004 WLD 26-JUN-92 MSCP21-8 compliance. ; ;-- ; Edit History: ; ; 001 01-Apr-82 03:23 PM Martin Gentry [40,121] ; Alterations due to code review ; (001) ; ; 002 ?? JFW? alter .MODULE? ; ; 003 4-Aug-85 Jim Williams ; Add .DRPTR amd .DREST ; ; 004 11-Sep-85 Jim Williams ; Add UNLOAD EP to .DRPTR to clear $ELHND on UNLOAD ; ; 005 15-Oct-85 Jim Williams ; Fix multi-def of ELDSIZ ; Add COND comment ; ; 006 AUG-87 Matthew Sacks ; 64-unit suport ; ; 007 AUG-87 Matthew Sacks ; make the elcopy code reentrant ; ; 009 JUN-88 Matthew Sacks ; code review changes ; ; 011 SEP-88 Matthew Sacks ; add SPFUN error logging, specifically the routines LOGSUC and GETSPF ; ; 013 OCT-88 Matthew Sacks ; clean up ; ; 024 AUG-92 Don Bridgewater ; strip out memory error logging, reentrancy code, fix 64-unit and ; other bugs .SBTTL ABSTRACT .ENABL LC ;+ ; ; AUTHOR: ; Martin Gentry ; Small Systems Software Group ; ; ABSTRACT: ; This handler is used to implement error logging support under ; the RT-11 base-line and single-job monitors. ; ; USE: ; This handler must be loaded before any of the SET commands ; will take effect. Once loaded, the user enters the monitor ; command 'SET EL LOG' after which the subsystem is enabled. ; If the logging buffer becomes full, the user is notified, and, ; except for updating device/memory statistics and maintaining ; a count of missed errors, subsequent error reports are ignored. ; To re-enable logging (losing the reports in the logging buffer ; but retaining the totals in the header), the user enters the ; monitor 'SET EL PURGE' command. To suspend logging, the user ; enters the monitor 'SET EL NOLOG command. To resume logging, ; the user enters the monitor 'SET EL LOG command. ; ;- .SBTTL COMDITIONAL ASSEMBLY SUMMARY ;+ ;COND ; ; ERL$U (10.) number of loggable units ; ; ERL$S (1) number of buffer blocks ; ; EL$U64 (1) build in 64 unit support ; ; MMG$T std conditional ; TIM$T std conditional (no code effects) ; ERL$G 1 std conditional (required = 1) ;- .SBTTL DEFINITIONS ; INCLUDE SYSTEM.MLB .LIBRARY "SRC:SYSTEM.MLB" .IIF NDF EIS$I EIS$I = 0 ;Decide to use SOB instr or macro. .IF NE MMG$T EIS$I = 1 .GLOBL $PTWRD .ENDC ;NE MMG$T ; RT-11 MACROS TO BE USED .MCALL .DATE .DRDEF .GTIM .EXIT .MCALL .PRINT .DSTAT .Assume .CHAIN .MCALL .LOOKUP .READW .CLOSE .CF1DF .CF2DF .MCALL .ADDR .MTPS .MFPS .CF3DF .FIXDF .DSPDF .MCALL .DSCDF .DSTDF .HANDF .SYCDF .CHADF .MCALL .ELDDF .ELMDF .ELIDF .ELSDF .IIF EQ EIS$I .MCALL SOB ; INVOKE SYSTEM.MLB macros .FIXDF ;monitor fixed offsets .CF1DF ;system configuration word #1 .CF2DF ;system configuration word #2 .CF3DF ;system configuration word #3 .DSPDF ;special function definition word bit masks .DSCDF ;flags returned by .DSTAT programmed request .DSTDF ;.DSTAT programmed request return area format .HANDF ;handler offsets .SYCDF ;system communications area .CHADF ;.CHAIN programmed request parameters .ELDDF ;device error record .ELMDF ;memory error record .ELIDF ;record types .ELSDF ;device statistics entry record ; SOME DEFAULTS ERL$G = 1 ;MUST FORCE THIS .IIF NDF ERL$U ERL$U = 10. ;MAXIMUM NUMBER OF LOGABLE UNITS .IIF NDF ERL$S ERL$S = 1 ;SIZE OF LOGGING BUFFER (BLOCKS) .IIF NDF EL$U64 EL$U64 = 1 ;64 unit defaults to On .Assume ERL$U LE 22.,MESSAGE=<;EL: Too Many Loggable Units> ; LETS GET THIS SHOW ON THE ROAD! .DRDEF EL,2,RONLY$,ERL$S+1,0,0,DMA=NO .DRPTR LOAD=LOAD,UNLOAD=UNLOAD,FETCH=*NO* .DREST CLASS=DVC.PS ; NOW FOR SOME OF OUR OWN MACROS .MACRO BCS. LABEL,?ALT BCC ALT JMP LABEL ALT: .ENDM ; RANDOM DEFINITIONS UNITMK = 7 ;UNIT MASK U64MSK = 160 ;64 unit mask .IF EQ MMG$T ELPRI = 40 ;Offset in RMON's LST16 to monitor's ; PRINTR routine to emulate .PRINT .IFF ;EQ MMG$T ELPRI = 42 ;Offset in RMON's LST16 to monitor's ; PRINTR routine to emulate .PRINT .ENDC ;EQ MMG$T PS = 177776 ;Processor Status Register PMODE = 30000 ;Previous mode bits in PS DU$COD = 50 ;DU device ID MU$COD = 60 ;MU device ID MSGTYP = 000360 ;UQSSP message type bits L.FMT = 10 ;(B) Error Log format flags LF.INF = 2 ;Informational Error Log flag ; CACHE MEMORY CONTROL REGISTERS MSYSER = 177744 ;CACHE MEMORY SYSTEM ERROR REGISTER MCONRG = 177746 ;CACHE CONTROL REGISTER MHITMS = 177752 ;CACHE HIT/MISS REGISTER ; STACK FRAME OFFSETS ;these are offsets from the top of the stack to some data that ;is kept around but not in registers ;this is where on the stack that temp word resides X.TMP = 0 ;this is where we keep a device's unit number X.UNI = 2 .SBTTL INSTALLATION CODE .ASECT . = 200 .ENABL LSB BR 10$ ;OKAY AS LOADED DEVICE BR 30$ ;MAY NOT BE INSTALLED AS SYSTEM DEVICE 10$: MOV @#$SYPTR,R0 ;R0->BASE OF RMON CMPB #1,$JOBS(R0) ;SB Monitor? BNE 30$ ;BR if not SB monitor: error. 20$: TST (PC)+ ;GOOD RETURN 30$: SEC ;ERROR RETURN RETURN LOAD: MOV @R5,R5 ;R5->ELLQE MOV @#$SYPTR,R1 ;R1->$RMON ADD $E16LS(R1),R1 ;R1->LST16 (EMT 16 table) ADD ELPRI(R1),R1 ;R1->PRINTR routine MOV R1,(R5) ;Plug into EL's linkage routine .IF NE EL$U64 JMP LOADX ;Go do GTXUNI initialization .IFF ;NE EL$U64 BR 20$ ;Take successful return .ENDC ;NE EL$U64 UNLOAD: MOV @R5,R5 ;R5->ELLQE MOV $ELPTR-ELLQE(R5),R0 ;R0->$ERLOG IN RMON TST (R0)+ ;R0->$ELHND CLR @R0 ;CLEAR $ELHND IN RMON ;CLC ;CLR cleared the c-bit RETURN ;SAFE TO UNLOAD NOW .DSABL LSB ;the following code is jumped to by the SET EL LOG code, it chains ;off to GETSPF, to make a job enviroment. CHNJMP: MOV #CH.PGM,R2 ;store name of program we are .ADDR #ELNAME,R3 ;chaining to: EL.SYS MOV (R3)+,(R2)+ MOV (R3)+,(R2)+ MOV (R3)+,(R2)+ MOV (R3)+,(R2)+ MOV #CH.ARG,R2 ;store arguments to GETSPF. recall MOV R1,(R2) ;that we are executing in the USR ADD #CODTAB-ELLQE,(R2)+ MOV R1,(R2) ADD #SPFUNS-ELLQE,(R2)+ MOV R1,(R2) ADD #SPFEND-ELLQE,(R2)+ MOV R1,(R2) ADD #$ELCPY-ELLQE,(R2)+ ;address of ELCPY code that the ;monitor calls MOV $ELPTR-ELLQE(R1),(R2) ; (R2) -> $ERLOG IN RMON ADD #2,(R2) ; (R2) -> error logger hook .CHAIN .IF EQ MMG$T ELNAME: .RAD50 /SY/ .RAD50 /EL / .RAD50 / / .RAD50 /SYS/ .IFF ;EQ MMG$T ELNAME: .RAD50 /SY/ .RAD50 /ELX/ .RAD50 / / .RAD50 /SYS/ .ENDC ;EQ MMG$T .Assume . LE 400,MESSAGE=<;Installation area overflow> .SBTTL SET OPTIONS .DRSET LOG, NOP, O.LOG, NO .DRSET PURGE, NOP, O.PURG .ENABL LSB O.LOG: BR 20$ ;'LOG' ENTRY POINT NOP ;** FILLER ** BR O.NLOG ;'NOLOG' ENTRY POINT 20$: CALL FINDRV ;IS THE DRIVER LOADED? BCS O.BAD ;NOPE... MOV @#$SYPTR,R2 ;R2->$RMON MOV R1,R0 ;ASSEMBLE POINTER TO CONFIG INFO ADD #CNFGW1-ELLQE,R0 ; AREA IN HEADER TST (R0) ;HAS HEADER BEEN INITIALIZED? BNE 30$ ;YES, JUST RESUMING LOGGING ; (DONT RELOAD CONFIG OR DATE INFO) MOV $CNFG1(R2),(R0)+ ;LOAD CONFIGURATION INFO MOV $SYSGE(R2),(R0)+ MOV R1,-(SP) ;NOW FOR DATE, ASSEMBLE A POINTER ADD #GETDAT-ELLQE,(SP) ; TO DATE ROUTINE INSIDE HANDLER CALL @(SP)+ ;AND USE IT TO LOAD DATE/TIME INFO ;we want to call the routine GETSPF which initializes CODTAB ;and SPFUNS, the tables in which the error logger looks up ;special function codes and types to do spfun logging. Since ;GETSPF does various programmed requests, we cannot run it in ;a SET enviroment so we must chain to it so it is run in a ;job enviroment. CHNJMP sets up and invokes the .CHAIN. Note ;that GETSPF knows to stuff the RMON error logger hook with the ;address of the $ELCPY code. JMP CHNJMP 30$: MOV R1,R2 ;ASSEMBLE POINTER TO START OF ADD #$ELCPY-ELLQE,R2 ; COPY CODE INSIDE HANDLER BR 40$ O.NLOG: CALL FINDRV ;IS THE DRIVER LOADED? BCS O.GOOD ;NOPE...THEN IT'S NOT RUNNING, IS IT? CLR R2 ;YES...MAKE SURE IT'S OFF 40$: MOV $ELPTR-ELLQE(R1),R0 ;R0->$ERLOG IN RMON TST (R0)+ ;R0->$ELHND MOV R2,(R0) ;SET/CLEAR $ELHND IN RMON BR O.GOOD .DSABL LSB O.PURG: CALL FINDRV ;IS THE DRIVER LOADED? BCS O.BAD ;NOPE... .MFPS ;save current priority .MTPS #340 MOV #1,PNXREC-ELLQE(R1) ;YES, RESET PHYSICAL RECORD NUMBER, MOV #1,PNXBLK-ELLQE(R1) ; ACTIVE BLOCK, CLR PNXWRD-ELLQE(R1) ; OFFSET INTO ACTIVE BLOCK CLR $ELFLG-ELLQE(R1) ; AND FINALLY, RESET MESSAGE FLAG ; CLR clears carry ;now do the same thing for the ;copies of these pointers .MTPS CLC RETURN FINDRV: .ADDR #DEVNAM,R0 ;R0->DEVICE NAME .ADDR #DAREA,-(SP) ;(SP)->.DSTATUS INFO AREA EMT 342 ;*** (.DSTAT #DAREA,#DEVNAM) *** ;this was not a physical .DSTAT, but ;recall that the operator may NOT ;not change the name of the error ;logger, anyway. BCS O.BAD ;IN CASE IT'S NOT KNOWN MOV DAREA+4,R1 ;RETURN THE ENTRY POINT BEQ O.BAD ;UNLESS HANDLER'S NOT LOADED O.GOOD: TST (PC)+ ;GOOD RETURN (C-BIT CLEAR) O.BAD: SEC ;BAD RETURN (C-BIT SET) RETURN .IF NE EL$U64 LOADX: MOV @#$SYPTR,R1 ;R1 -> $RMON CLR R0 ;Clear to assume no monitor support BIT #CF3.64,$CNFG3(R1) ;Does monitor support extended units? BEQ 10$ ;Branch if not BISB $SLOT2(R1),R0 ;Get number of device slots * 2 10$: MOV R0,(R5) ;Save # of dev slots * 2 (or 0 flag) ;Other variables are junk if SLOT2 = 0 ADD $PNPTR(R1),R1 ;R1 -> $PNAME table ADD R0,R1 ;R1 -> $ENTRY table MOV R1,(R5) ;Save -> after $PNAME table ADD R0,R1 ;R1 -> $ENTRY table terminator (-1) TST (R1)+ ;R1 -> $STAT table MOV R1,(R5) ;Save -> $STAT table ADD R0,R1 ASL R0 ;Skip $DVREC and $HSIZE tables ASL R0 ;Skip $DVSIZ and $PNAM2 tables ADD R0,R1 ;R1 -> after $PNAM2 table MOV R1,(R5) ;Save -> $STAT table BR O.GOOD ;CLC and return (success) .ENDC ;NE EL$U64 DAREA: .BLKW 4 ;.DSTAT INFORMATION BLOCK DEVNAM: .RAD50 /EL / ;DEVICE NAME -- must be EL .Assume . LE 1000,MESSAGE=<;Set area overflow> .SBTTL DRIVER REQUEST ENTRY POINT ;+ ; ; The following code handles requests of the EL handler. A write sets ; the hard-error bit in the CSW, seeks are ignored. A read of block 0 ; returns the EL header block while reads of blocks 1 through ERL$S ; return the equivalent blocks of the logging buffer. A read of any ; block greater than ERL$S sets the hard-error bit in the CSW. ; ;- .DRBEG EL MOV ELCQE,R4 ;R4->QUEUE ELEMENT (Q.BLKN) MOV Q$WCNT(R4),R2 ;R2=WORD COUNT BEQ ELDONE ;DONE IF SEEK (Q.WCNT=0) BLT ELERR ;NO WRITES ALLOWED MOV Q$BUFF(R4),R1 ;R1->USER'S BUFFER .ADDR #$ELHDR,R0 ;ASSEMBLE POINTER TO HEADER MOV (R4),R3 ;R3=BLOCK TO READ BGT 10$ ;READ IS FROM BUFFER IF Q.BLKN>0 CMP R2,#$HDLEN ;IS THE READ TOO LONG? BLE 30$ ;NOPE... MOV #$HDLEN,R2 ;YES, SHORTEN IT TO THE HEADER BR 30$ ;BR to move data to user buffer. 10$: ADD #$ELBFR-$ELHDR,R0 ;ADJUST POINTER TO START OF BUFFER CMP (R4),#ERL$S ;IS READ WITHIN LIMITS? BGT ELEOF ;NOPE...END OF FILE (PSEUDO-DEVICE) DEC R3 ;LOW LIMIT IS, SET TO CHECK HI LIMIT SWAB R3 ;CHANGE BLOCK TO WORD OFFSET ASL R3 ; CONVERT FROM WORD TO BYTE OFFSET ADD R3,R0 ;ADD OFFSET TO POINTER ADD R2,R3 ;ADD WORD COUNT ADD R2,R3 ; (TWICE FOR BYTES) SUB #ERL$S*256.*2,R3 ;DETERMINE AMOUNT OF BUFFER OVERRUN BLE 30$ ;THERE IS NONE, REQUEST IS OK ASR R3 ;YES THERE IS, CONVERT BYTES TO WORDS SUB R3,R2 ; AND TRUNCATE REQUEST BY THAT AMOUNT .IF EQ MMG$T 30$: MOV (R0)+,(R1)+ ;Move a word to user buffer. .IFF ;EQ MMG$T 30$: MOV (R0)+,-(SP) ;Move a word to user buffer. CALL @$PTWRD .ENDC ;EQ MMG$T SOB R2,30$ ;BR if more data to be moved. BR ELDONE ;BR when done. ELEOF: BIS #EOF$,@-(R4) ;SET END-OF-FILE BIT BR ELDONE ELERR: BIS #HDERR$,@-(R4) ;SET HARD ERROR BIT ; NO, WE ARE NOT GOING TO LOG ERRORS ; TO OURSELF! ELINT: ;SO LINK DOESN'T COMPLAIN ELDONE: .DRFIN EL .SBTTL $ELCPY - START OF COPY CODE ;+ ; ; The following code is used to move the error information passed by ; the handler to the error logging buffer while updating the header. ; (Entered as a result of a handler doing a 'JSR PC,@$ELPTR'.) ; ; Successful transfers are not placed in the logging buffer but they ; cause the appropriate entries in the statistics entry for the device ; to be incremented. ; ; Successful device transfer: ; R4 = Device ID/-1 ; R5 -> 3rd word of queue element (Q.BLKN) ; ;- $ELCPY: MOV R0,-(SP) ;SAVE SOME REGISTERS MOV R1,-(SP) MOV R2,-(SP) MOV R3,-(SP) MOV R4,-(SP) MOV R5,-(SP) CMPB R4,#GD.IO ;WHAT KIND OF REPORT? BEQ 8$ ;branch for a success I/O log CLR -(SP) ;will later be referenced as x.uni(sp) CLR -(SP) ;will later be referenced as x.tmp(sp) ;X.TMP(SP) : USED FOR DEVICE ;STATISTICS ; (HYBRID DATA - ZERO INDICATES ; NO STATISTICS ENTRY FOR DEVICE, ; NON-ZERO INDICATES STATISTICS ; ARE BEING KEPT, VALUE IS POINTER ; TO STATISTICS ENTRY) CMPB R4,#GD.IO ;this sets flags to indicate ;error type BGT DEVERR ;>-1, DEVICE ERROR JMP MEMERR ;<-1, MEMORY ERROR ;here for success I/O case 8$: CALL GESTAT ;KEEPING STATISTICS ON THIS DEVICE? BCS 20$ ;NOPE... CALL LOGSUC 20$: JMP $EXIT2 ;all done... .SBTTL DEVERR - DEVICE ERROR RECORD LOGGER ;+ ; ; "PATIENT: Doctor, it hurts when I do this. ; DOCTOR: Then don't do that." ; ; For an unsuccessful device transfer: ; R2 -> Device register save area in handler ; R3 = Maximum retries/# of device registers ; R4 = Device ID/retry count ; R5 -> 3rd word of queue element (Q.BLKN) ; ; When logging soft errors, a retry count is passed to the logger. ; One expectation is that the retry count passed from the handler ; must decrease to zero, zero indicating a transfer failure. ; ; If the current error being reported is for the same device/unit as ; the last one in the logging buffer AND the retry count is less than ; the previous one AND the device registers are the same, a new record ; is not built but the occurance count of the previous record is ; incremented and the new retry count is saved. ; ;- DEVERR: INC CERECR ;Increment count of errors received BISB Q$UNIT(R5),X.UNI(SP) ;Isolate unit number bits in place BICB #^c,X.UNI(SP) ; reserved on stack (already cleared) .IF NE EL$U64 CALL GTXUNI ;Get possible extended unit bits BIS R1,X.UNI(SP) ; and merge with low-order unit bits .ENDC ;NE EL$U64 CALL GESTAT ;KEEPING STATISTICS ON THIS DEVICE? BCS 60$ ;NOPE, NO ENTRY... MOV R4,R1 ;Isolate device ID in SWAB R1 ; low byte of R1 (high byte is junk) CMPB R1,# ;Is device type MSCP? BEQ 30$ ;BR if yes: MSCP. CMPB R1,# ;Is device type TMSCP? BNE 40$ ;BR if no: not TMSCP 30$: TST @R2 ;T/MSCP: SAR Packet? BEQ 40$ ;BR if yes. BIT #MSGTYP,2(R2) ;End Message? BEQ 40$ ;BR if yes. BIT #LF.INF,4+L.FMT(R2) ;Informational Error Log? BEQ 40$ ;BR if not. DEC CERECR ;Adjust overall count. BR 50$ ;Don't count Error Log as error. 40$: INC ELS.ER(R0) ;YES, BUMP COUNT OF ERRORS RECEIVED .ASSUME X.TMP EQ 0 50$: MOV R0,@SP ;save pointer to the entry ;a nil pointer indicates statistics ;are not kept for the device - any ;other pointer points to a statistics ;entry. 60$: TST PNXWRD ;any records in active block? BEQ 120$ ;no, so skip comparison with previous ;error log record CLR R1 ;yes, ready to find pointer to word CALL CHKSIZ ; following last record entered BCS 120$ ;Branch if buffer held/not available ADD @R0,R0 ;R0->PREVIOUS RECORD (BY ADDING ; NEGATED LENGTH OF PREVIOUS RECORD) MOV R4,R1 ;R1=DEVICE ID CLRB R1 BISB X.UNI(SP),R1 ;ADD THE UNIT NUMBER CMP R1,ELD.UN(R0) ;SAME DEVICE/UNIT AS LAST TIME? BNE 120$ ;NOPE...NO MORE CHECKING CMPB R4,ELD.RT(R0) ;THIS RETRY LESS THAN LAST ONE? BGE 120$ ;NOPE, BUILD A NEW RECORD MOV R0,-(SP) ;SAVE SOME REGISTERS MOV R2,-(SP) .IF EQ MMG$T ADD #ELD.RG,R0 ;R0->PREVIOUS RECORD REGISTERS .IFF ;EQ MMG$T ADD #ELD.RX,R0 ;R0->PREVIOUS RECORD REGISTERS .ENDC ;EQ MMG$T MOVB R3,R1 ;GET NUMBER OF REGISTERS 100$: CMP (R0)+,(R2)+ ;REGISTERS THE SAME? BNE 110$ ;NOPE... SOB R1,100$ ;BRANCH IF MORE REGISTERS TO CHECK? 110$: MOV (SP)+,R2 ;RESTORE THE REGISTERS WE SAVED MOV (SP)+,R0 TST R1 ;WERE ANY REGISTERS LEFT UNCHECKED? BNE 120$ ;YES, THEN ONE DIDN'T MATCH INCB ELD.OC(R0) ;NOPE...SAME REGISTERS, SO BUMP ; THE MULTIPLE OCCURANCE COUNT MOVB R4,ELD.RT(R0) ;UPDATE THE RETRY COUNT .ASSUME X.TMP EQ 0 TST @SP ;keeping statistics? BEQ 200$ ;NOPE, NO ENTRY .ASSUME X.TMP EQ 0 ADD #ELS.EL,@SP ;yes, point at count of errors logged INC @X.TMP(SP) ;and bump it BR 200$ 120$: ;calculate word size of new record MOVB R3,R1 ;get the number of words passed to us .IF EQ MMG$T ADD #,R1 ;add in record fixed size .IFF ;EQ MMG$T ADD #,R1 ;add in record fixed size .ENDC ;EQ MMG$T CALL CHKSIZ ;Is there enough room for this record? BCS $ELERR ;Branch if not .ASSUME X.TMP EQ 0 TST @SP ;keeping statistics for the device? BEQ 140$ ;NOPE, NO ENTRY FOR THE DEVICE... .ASSUME X.TMP EQ 0 ADD #ELS.EL,@SP ;yes, point at count of errors logged INC @X.TMP(SP) ;and bump it 140$: ; HERE TO BUILD A DEVICE ERROR RECORD IN THE LOGGING BUFFER MOVB R1,(R0)+ ; - RECORD SIZE MOVB PNXREC,(R0)+ ; - RECORD NUMBER INC PNXREC ;(KEEP RECORD NUMBER UP TO DATE) MOVB X.UNI(SP),(R0)+ ; - UNIT NUMBER SWAB R4 ;SET TO GET DEVICE ID MOVB R4,(R0)+ ; - DEVICE ID CODE SWAB R4 ;SET TO GET RETRY COUNT MOVB R4,(R0)+ ; - RETRY COUNT MOVB #1,(R0)+ ; - DUPLICATION COUNT (STARTS AT 1) CALL GETDAT ;INSERT THE DATE AND TIME MOV (R5)+,(R0)+ ; - Q.BLKN (FROM QUEUE ELEMENT) TST (R5)+ ;BYPASS Q.FUNC/Q.UNIT/Q.JNUM MOV (R5)+,(R0)+ ; - Q.BUFF (FROM QUEUE ELEMENT) ;we would like now to store the Q.WCNT field from the queue element ;but if we are logging an .SPFUN which is of type=other or type= ;motion, then we store 0 for the word count so that ERROUT knows ;that it is not a read or a write operation that failed. We also ;store the 0 if it is a "special directory operation." MOV R1,-(SP) ;Save record size TSTB Q$FUNC-Q$WCNT(R5) ;test the FUNC byte BEQ 160$ ;if zero then keep the word count BPL 150$ ;if positive then pass a zero for ;the word count ;if negative, it is an spfun operation ;so we call FNDFUN to get the TYPE ;of the SPFUN MOV R4,-(SP) ;Save R4 and R5 around FNDFUN call MOV R5,-(SP) ; because we need to use them for CLRB R4 ; parameter passing SWAB R4 ;R4 = device code SUB #Q$BLKN-Q$WCNT,R5 ;move R5 back to Q$BLKN CALL FNDFUN MOV (SP)+,R5 MOV (SP)+,R4 TST (R1) ;did FNDFUN find the type of the BEQ 150$ ;spfun? branch if not INC R1 CMPB (R1),#DSP.MV ;is the type=motion? BEQ 150$ ;branch if yes TSTB (R1) ;is the type=other? BNE 160$ ;branch if no 150$: .IF NE MMG$T TST (R5)+ ;Skip over Q.WCNT .ENDC ;NE MMG$T CLR (R0)+ ;Clear the word count BR 170$ 160$: MOV (R5)+,(R0)+ ; - Q.WCNT (FROM QUEUE ELEMENT) 170$: MOV (SP)+,R1 ;Restore record size .IF NE MMG$T CMP (R5)+,(R5)+ ;SKIP OVER Q.COMP AND Q.PAR MOV (R5)+,(R0)+ ; - Q.MEM (FROM QUEUE ELEMENT) .ENDC ;NE MMG$T 180$: MOV R3,(R0)+ ; - MAX RETRIES/# OF REGISTERS MOVB R3,R3 ;GET COUNT OF REGISTERS 190$: MOV (R2)+,(R0)+ ; - A DEVICE REGISTER SOB R3,190$ ;LOOP UNTIL ALL DEV REGISTERS COPIED ASL R1 ;R1 = length of record (in bytes) ADD R1,PNXWRD ; and update 'next word' offset NEG R1 ;Negate the size MOV R1,@R0 ; and save it (for use in checking ; previous record for duplicate ; register/PC values) 200$: JMP $ELXIT ;AND TAKE COMMON EXIT .SBTTL MEMERR - MEMORY ERROR RECORD LOGGER ;+ ; Memory errors are no longer logged by the error logger. The monitor ; has been changed not to call the error logger on memory errors. ;- MEMERR: JMP $ELXIT ;AND TAKE COMMON EXIT .SBTTL $ELXIT - EXIT ROUTINES ; $ELXIT is the success exit from an invokation of the error logger, ; we come here when an error has been logged ; ; $ELERR is the error exit ; .ENABL LSB $ELERR: TST (PC)+ ;SHOULD WE PRINT A MESSAGE? $ELFLG: .WORD 0 BNE 10$ ;NOPE, USER ALREADY KNOWS MOV SP,$ELFLG ;YES...FIRST SET ONCE-ONLY FLAG .ADDR #E.FULL,R0 ;R0->BUFFER FULL MESSAGE CALL PRINTR ;PRINT IT 10$: INC CMENTB ;BUMP COUNT OF MISSED ERRORS $ELXIT: MOV (SP)+,(SP)+ ;remove X.TMP and X.UNI from stack $EXIT2: MOV (SP)+,R5 ;RESTORE REGISTERS WE SAVED MOV (SP)+,R4 MOV (SP)+,R3 MOV (SP)+,R2 MOV (SP)+,R1 MOV (SP)+,R0 RETURN .DSABL LSB .SBTTL LOGSUC - Log a successful I/O event ;+ ; ; LOGSUC ; Increment the appropriate success I/O count, to do so we ; examine the queue element to what kind of operation it was ; ; INPUT ; R0 -> to the device statistics entry for the device ; R4 high byte is device ID ; R5 -> the queue element ;- .ENABL LSB LOGSUC: MOV R1,-(SP) ;protect registers MOV R4,-(SP) TSTB Q$FUNC(R5) BEQ 30$ ;0 means decide on the basis of Q$WCNT BGT 10$ ;special directroy operations are ;logged as type = other/unknown SWAB R4 ;put desired device id in low byte CALL FNDFUN ;find this device in the table CODTAB TST (R1) BEQ 10$ ;0 means no entry in table, treat as ;type=other INC R1 ;point to high byte of entry CMPB (R1),#DSP.RD ;find the "type" of the .spfun BEQ 50$ CMPB (R1),#DSP.WR BEQ 40$ CMPB (R1),#DSP.RW BEQ 30$ CMPB (R1),#DSP.MV BEQ 20$ 10$: ADD #ELS.OS,R0 ;R0 -> count of "other" successes BR 60$ 20$: ADD #ELS.MS,R0 ;R0 -> count of "motion successes BR 60$ 30$: TST Q$WCNT(R5) ;READ, WRITE OR SEEK? BEQ 20$ ;SEEK is a motion BPL 50$ ;READ, 40$: ADD #ELS.WS,R0 ;WRITE BR 60$ 50$: ADD #ELS.RS,R0 ;ASSUME SUCCESSFUL READ 60$: ADD #1,(R0)+ ;BUMP SUCCESS COUNT ADC (R0) ; (DOUBLE PRECISION INTEGER) 70$: MOV (SP)+,R4 MOV (SP)+,R1 RETURN .DSABL LSB .SBTTL FNDFUN - Find an entry in CODTAB for a device's spfun ;+ ; ; FNDFUN - find an entry in CODTAB for a device's spfun ; ; INPUT: R4 = device ID ; R5 -> queue element ; ; OUTPUT: R1 -> spfun's entry in CODTAB (success) ; R1 -> 0 (failure) ; ; .ENABL LSB FNDFUN: .ADDR #CODTAB,R1 10$: TST (R1) ;end of table? BEQ 50$ ;branch if this device isn't in ;the SPFUN table CMPB (R1),R4 ;is this the device? BNE 20$ ;branch if not MOV 2(R1),R1 ;R1 -> spfun list for this device BR 30$ 20$: ADD #CTBSIZ,R1 ;go to next entry in CODTAB BR 10$ 30$: TST (R1) ;end of spfun list? BEQ 50$ ;if yes, branch and treat as other CMPB Q$FUNC(R5),(R1)+ ;is this the SPFUN? BEQ 40$ ;branch if yes INC R1 BR 30$ 40$: DEC R1 50$: RETURN .DSABL LSB .SBTTL GESTAT - GET POINTER TO DEVICE STATISTICS ENTRY ;+ ; ; GESTAT ; Determines if an entry exists in the device statistics ; table for the device currently being reported. If an ; entry exists, an address is returned which is a pointer ; to the entry. If an entry does not exist, one is created ; and its address is returned. If an entry does not exist ; and there is no room to build one, the user is informed. ; ; CALL: ; R4 = Device Id/Retry count ; R5 -> Queue element (Q.BLKN) ; ; RETURNS: ; R0 -> Statistics entry ; R1 is munged ; R4,R5 are unchanged ; ; ERRORS: ; no entry if carry=1 ; ;- .ENABL LSB GESTAT: MOVB Q$UNIT(R5),-(SP) ;GET THE UNIT NUMBER BIC #<^CUNITMK>,(SP) ;STRIP THE EXTRANEOUS BITS .IF NE EL$U64 CALL GTXUNI ;Get possible extended unit bits BIS R1,@SP ; and merge with low-order unit bits .ENDC ;NE EL$U64 MOV R4,R0 ;R0=DEVICE ID/RETRY COUNT CLRB R0 ;STRIP TO DEVICE-ID BIS R0,(SP) ;COMBINE IT WITH UNIT NUMBER .ADDR #DEVSTS,R0 ;->device stat table MOV #ERL$U,R1 ;R1=MAXIMUM NUMBER OF STAT ENTRIES 10$: CMP (R0),#-1 ;END OF STATISTICS ENTRIES? BEQ 40$ ;YES, HAVE TO ADD A NEW ENTRY... CMP (R0),(SP) ;NOPE, IS THIS THE ENTRY WE WANT? BEQ 60$ ;YES... ADD #ELS.SZ*2,R0 ;NOPE, ON TO NEXT ENTRY SOB R1,10$ ;BR if more entries. TST (PC)+ ;NOPE, PRINTED THIS MESSAGE ALREADY? 20$: .WORD 0 BNE 30$ ;YES, DON'T ANNOY USER WITH IT AGAIN .ADDR #E.STAT,R0 ; IN A PIC FASHION CALL PRINTR ;INFORM THE USER MOV SP,20$ ;DISABLE THE MESSAGE 30$: TST (SP)+ ;DISCARD SEARCH IDENTIFIER BR 70$ 40$: MOV #ELS.SZ,R1 ;R1=LENGTH OF STATISTICS ENTRY 50$: CLR (R0)+ ;PREPARE THE NEW ENTRY SOB R1,50$ ;BR if more entries. MOV #-1,(R0) ;YES, SET THE NEW FENCE SUB #ELS.SZ*2,R0 ;R0->START OF ENTRY MOV (SP),(R0) ;SET ENTRY IDENTIFIER 60$: TST (SP)+ ;DISCARD SEARCH IDENTIFIER TST (PC)+ ;ENTRY FOUND (CARRY CLEAR) 70$: SEC ;ENTRY NOT FOUND (CARRY SET) RETURN .DSABL LSB .IF NE EL$U64 .SBTTL GTXUNI - GET EXTENDED UNIT NUMBER (HIGH 3 BITS ONLY) ;+ ; ; GTXUNI ; Gets high three bits of extended unit number (if handler is ; an extended unit handler) and returns these three bits in ; bits 3-5 of R1. All other bits in R1 are cleared. ; ; CALL: ; R4 = Device Id/Retry count ; R5 -> Queue element (Q.BLKN) ; ; RETURNS: ; R1 is high 3 bits of extended unit number in bits 3-5 ; R0 is munged ; R4,R5 are unchanged ; ; ERRORS: ; none ;- .ENABL LSB GTXUNI: MOV (PC)+,R0 ;Get number of device slots * 2 SLOT2: .WORD 0 ;*LOAD* # dev slots * 2 or 0 BEQ 40$ ;Branch if monitor doesn't support ; extended units MOV (PC)+,R1 ;R1 -> beginning of $STAT table STAT: .WORD 0 ;*LOAD* -> beginning of $STAT table ASR R0 ;Convert to number of slots (words) 10$: MOV R4,-(SP) ;Get device code SWAB @SP ; in low byte of @SP CMPB (SP)+,@R1 ;Does our dev code match $STAT entry? BEQ 20$ ;Branch if so TST (R1)+ ;Skip to next $STAT entry SOB R0,10$ ;Check until $STAT table exhausted BR 40$ ;If not found, extended unit bits = 0 20$: ASL R0 ;Neg. byte offset from end of dev tbl CMP .-.(R0),.-.(R0) ;Are $PNAME and $PNAM2 entries equal? APNAME =: .-4 ;*LOAD* -> after $PNAME table APNAM2 =: .-2 ;*LOAD* -> after $PNAM2 table BEQ 40$ ;Branch if so -- no extended unit MOVB Q$FUNC(R5),R1 ;Get function code BPL 30$ ;If non-negative, leave as is COM R1 ; else, one's complement it 30$: BIC #^c,R1 ;Isolate high 3 bits of extended unit ASR R1 ; number and shift to bit pos 3-5 BR 50$ ;Go restore registers and return 40$: CLR R1 ;No extended unit number 50$: RETURN .DSABL LSB .ENDC ;NE EL$U64 .SBTTL CHKSIZ - CHECK FOR ROOM IN LOGGING BUFFER ;+ ; ; CHKSIZ ; Determines if there is room in the logging buffer for ; another record. If there is room, an address is returned ; which is a pointer to where the record may be inserted. ; A "fence" (-1) is placed after the last record of any ; unfilled block. ; ; CALL: ; R1 = size of record to add (in words) ; ; RETURN: ; R0 -> start of area for new record ; R1 unchanged ; ; ERRORS: ; no room in buffer if carry=1 ; ;- CHKSIZ: MOV PNXWRD,R0 ;R0=OFFSET INTO CURRENT BLOCK ADD R1,R0 ;ADD LENGTH OF RECORD TO BE LOGGED ADD R1,R0 ; (ADD TWICE, LENGTH IS IN WORDS) CMP R0,#255.*2 ;WOULD RECORD OVERFLOW THIS BLOCK? ; (ALLOW ROOM FOR -1 FENCE) BLT 10$ ;NOPE... CMP PNXBLK,SMAXSZ ;YES, CAN IT GO IN THE NEXT BLOCK? BGE 20$ ;NOPE, WE'VE RUN OUT OF BLOCKS CALL 10$ ;YES, GET POINTER TO 'NEXT WORD' OF MOV #-1,(R0) ; CURRENT BLOCK SO WE CAN SET FENCE INC PNXBLK ;NOW BUMP 'NEXT BLOCK' COUNTER CLR PNXWRD ; OFFSET STARTS AT THE BEGINNING 10$: MOV PNXBLK,R0 ;R0=ACTIVE LOGGING BLOCK DEC R0 SWAB R0 ;DETERMINE WORD OFFSET INTO $ELBFR ASL R0 ;CONVERT WORD TO BYTE OFFSET ADD PNXWRD,R0 ; ADD OFFSET INTO ACTIVE BLOCK .ADDR #$ELBFR,R0,ADD ;ADD ABS START OF LOGGING BUF TST (PC)+ ;ROOM IN BUFFER (C-BIT CLEAR) 20$: SEC ;NO ROOM (C-BIT SET) RETURN ;+ ; ; GETDAT ; Places the current date/time in an error record. ; ; CALL: ; R0 -> 3 successive words to receive date and time ; (will be returned in order date, high-order ; time, low-order time) ; ; RETURN: ; R0 = (R0 before call)+6 ; ; ERRORS: ; none ; ; NOTE: ; The following routine uses the RTEM time hook as the ; location to jump to in the monitor in order to obtain ; the time (and update the date). ; ; Because we are in system state - we must call monitor routines ; directly instead of using system macros ;- GETDAT: MOV R1,-(SP) ;SAVE R1 FOR AWHILE MOV @#$SYPTR,R1 ;R1->$RMON .MFPS ;SAVE CURRENT PRIORITY MOV R1,-(SP) ADD $ELTIM(R1),(SP) ;(SP)->'GTIHOK' TIME ROUTINE ADD #2,R0 ;R0->WHERE TO PUT TIME .MTPS #340 ;SET IT HIGH JSR PC,@(SP)+ ;GO GET IT FROM THE MONITOR .MTPS ;RESTORE PREVIOUS PRIORITY MOV @#$SYPTR,R1 ;R1->$RMON MOV $DATE(R1),-4(R0) ;GET THE DATE MOV (SP)+,R1 ;RESTORE PREVIOUSLY SAVED R1 TST (R0)+ ;UPDATE R0 RETURN ;+ ; ; PRINTR ; Prints the string whose address is in R0 on console terminal ; ; CALL: ; R0 -> .ASCII or .ASCIZ string to print on console terminal ; ; RETURN: ; All registers (R0 - R5) preserved ; ; ERRORS: ; none ; ; NOTE: ; The following routine uses the EMT16 .PRINT hook that BA and SL ; also use. ; ; Because we are in system state - we must call monitor routines ; directly instead of using system calls. ;- PRINTR: MOV R0,-(SP) ;Save all registers (R0 - R5) MOV R1,-(SP) MOV R2,-(SP) MOV R3,-(SP) MOV R4,-(SP) MOV R5,-(SP) .IF NE MMG$T MOV @#PS,-(SP) ;Save PS to preserve previous mode bits BIC #,@#PS ;Make previous mode = kernel .ENDC ;NE MMG$T CALL @(PC)+ ;Call monitor's PRINTR routine (.PRINT) MONPRT: .WORD 0 ;Stuffed by EL's load code .IF NE MMG$T MOV (SP)+,@#PS ;Restore PS .ENDC ;NE MMG$T MOV (SP)+,R5 ;Restore all registers (R0 - R5) MOV (SP)+,R4 MOV (SP)+,R3 MOV (SP)+,R2 MOV (SP)+,R1 MOV (SP)+,R0 RETURN .SBTTL TEXT .NLIST BEX E.FULL: .NLCSI TYPE=I,PART=PREFIX .ASCIZ /W-Buffer is full, logging suspended/ E.STAT: .NLCSI TYPE=I,PART=PREFIX .ASCIZ /W-Device statistics table is full/ .EVEN .LIST BEX .SBTTL Spfun Tables ; CODTAB is a table of two word entries. The first word of an entry is ; a device code, the second word is a pointer into another table, ; SPFUNS. For each class (high byte) of .spfuns in each installed ; handler in the system, there is entry in CODTAB; the entry's first ; word is the handler's device code, the second word points to a ; special function definition word which can be used to lookup a ; an spfun's CTBSIZ =: 4 CODTAB::.BLKW 65. SPFUNS::.BLKW 191. SPFEND: .SBTTL IMPURE DATA AREA ; HEADER BLOCK ; ** BEGIN CRITICAL ORDERING ** ; The following information is ordered and defined the same ; as the header block of the logging file, ERRLOG.DAT. This ; is done so that ERROUT can open EL in non file-structured ; mode and use the information is as. $ELHDR: ;EL HEADER BLOCK OFIXED: .WORD <*2> ;OFFSET TO FIXED PART OF HEADER DEVSTS: .WORD -1 ;FENCE .BLKW ;DEVICE STATISTICS CERECR: .WORD 0 ;TOTAL ERROR RECORDS RECEIVED CMENTB: .WORD 0 ;MISSED ENTRIES - BUFFER FULL CMENTF: .WORD 0 ;MISSED ENTRIES - FILE FULL CMENTR: .WORD 0 ;MISSED ENTRIES - TASK NOT READY CMPARE: .WORD 0 ;COUNT OF MEMORY PARITY ERRORS CCPARE: .WORD 0 ;COUNT OF CACHE PARITY ERRORS PNXREC: .WORD 1 ;NEXT RECORD NUMBER PNXBLK: .WORD 1 ;BLOCK NUMBER OF NEXT RECORD PNXWRD: .WORD 0 ;OFFSET WITHIN BLOCK OF NEXT RECORD SMAXSZ: .WORD ERL$S ;MAXIMUM SIZE OF ERROR (PSEUDO)FILE CNFGW1: .WORD 0 ;CONFIG WORD 1 CNFGW2: .WORD 0 ;CONFIG WORD 2 INIDAT: .WORD 0 ;DATE OF INITIALIZATION INTIM1: .WORD 0 ;TIME OF INITIALIZATION (WORD 1) INTIM2: .WORD 0 ;TIME OF INITIALIZATION (WORD 2) $HDLEN = <.-$ELHDR>/2 .Assume $HDLEN LE 256.,MESSAGE=<;Header too long> ; ** END CRITICAL ORDERING ** $ELBFR: .BLKW ;LOGGING BUFFER .DREND EL .PSECT GETSPF .SBTTL GETSPF - Initialize the Spfun tables ;GETSPF - Fill the SPFUN tables ; ; initialize tables about the installed handlers' .spfuns ; ; ; ; ON INPUT ; the chain argument area contains five addresses: ; ; ---------- ; | CODTAB | (search table) ; ---------- ; | SPFUNS | (table of lists) ; ---------- ; | SPFEND | (first word after SPFUNS) ; ---------- ; | $ELCPY | (error ; ---------- ; |$ERLOG+2| (rmon hook) ; ---------- ; ; ; ON OUTPUT ; --------------- -------------- ; CODTAB: | device code | (low byte) SPFUNS: | spfun code | (byte) ; | reserved | (high byte) | type code | (byte) ; --------------- -------------- ; | pointer into| | spfun code | ; | SPFUNS table| | type code | ; --------------- -------------- ; | device code | (low byte) | spfun code | ; | reserved | (high byte) | type code | ; --------------- -------------- ; | pointer into| | 0 | ; | SPFUNS table| | 0 | ; --------------- -------------- ; | device code | (low byte) | spfun code | (byte) ; | reserved | (high byte) | type code | (byte) ; --------------- -------------- ; | pointer into| . . ; | SPFUNS table| . . ; . . . . ; . . . . ; . . . . ; . . . . ; | 0 | | 0 | ; | 0 | | 0 | ; --------------- -------------- ; .ENABL LSB INICHN = 3 GETSPF: MOV @#$SYPTR,R5 MOV $SLOT2(R5),R3 ;get length of PNAME table ADD $PNPTR(R5),R5 MOV CH.ARG,R1 ;R1 -> CODTAB MOV CH.ARG+2,R2 ;R2 -> SPFUNS MOV CH.ARG+4,SPFCHK ;SPFCHK -> end of spfun codes table CLR (R1) ;initialize the null terminators CLR (R2) ;of the tables ;step through the PNAME table and for ;each handler in the table, get its ;device code, use DVREC to read in ;block 0 of the handler and copy the ;special function definition words ;into our table, SPFUNS MOV R3,R4 ASL R3 ;*2 ADD R4,R3 ;= *3 ADD #2,R3 ;R3 = (($SLOT*2)*3)+2 ADD R5,R3 ;R3 -> points into the DVREC table ;which contains the sy: block numbers ;of the first block of the ASR R4 ;R4 = length of PNAME table ($SLOT) .LOOKUP #AREA,#INICHN,#SYSNAM ;get a channel to SY: BCS 60$ 10$: TST (R5) ;is this entry in PNAME empty BEQ 55$ ;branch if yes MOV (R5),DNAM ;Do DSTAT on this device .DSTAT #DSTAT,#DNAM BCS 55$ MOV #DSTAT,R0 BIT #SPFUN$,(R0) ;does handler support spfuns? BEQ 55$ ;branch if not - see .DSTAT doc MOV (R3),AREA+2 ;read block 0 of handler DEC AREA+2 .READW #AREA,#INICHN,#$ELBFR,#256. BCS 55$ MOV #$ELBFR,R0 ;go through spfun descriptors ADD #H.SPF1,R0 MOVB DSTAT+DS.COD,(R1)+ ;move device code into CODTAB CLRB (R1)+ MOV R2,(R1)+ CLR (R1) CLR -(SP) ;handler has 3 spfun descriptors MOV #3,(SP) ;in block 0, use (SP) as a counter 20$: TSTB 1(R0) ;test the NNX byte BEQ 30$ ;branch if this word defines no ;Spfuns. CALL 70$ ; 70$ disects Spfun words BCS 110$ 30$: TST (R0)+ ;ADD #2 advance to next .SPFUN word DEC @SP ;Was SOB (SP),20$ BNE 20$ TST (SP)+ ;done with counter TST (R0) ;.spfun extension table? BEQ 50$ ;branch if not MOV (R0),R0 ;offset (in bytes) to extenstion ;table. MOV R0,-(SP) BIC #^C777,(SP) BIC #777,R0 ;convert high byte of offset into SWAB R0 ;a disk block number ASR R0 ADD R0,AREA+2 ;change .read argument area to ;the appropriate block .READW #AREA,#INICHN,#$ELBFR,#256. BCS 50$ MOV #$ELBFR,R0 ADD (SP)+,R0 ;R0 points to extension table 40$: TST (R0) ;do not auto-inc in case we call 70$ BEQ 50$ ;branch if end of extension table CALL 70$ ; 70$ disects .spfun words BCS 120$ TST (R0)+ ; add #2 BR 40$ 50$: CLR (R2)+ CMP R2,SPFCHK ;is table full? BHIS 120$ ;branch if yes 55$: ADD #2,R5 ADD #2,R3 DEC R4 ;Was SOB R4,10$ BNE 10$ .CLOSE #INICHN 57$: MOV CH.ARG+6,@ ;stuff RMON error logger hook .EXIT 60$: BR 57$ ;here if .lookup failed ;ACTION: print a message? ;come here to disect .Spfuns ; R2 points into the table SPFUNS ; R0 points to the actual .spfun descriptor word ; must protect any register used ; ; return with the C-bit set if and only if the table ; is now full 70$: MOV R1,-(SP) MOV R4,-(SP) MOV R5,-(SP) CLR R5 ;make R5 = next entry in SPFUNS table BISB 1(R0),R5 ;first do low byte MOV R5,R4 BIC #7,R5 ;isolate the NN part of NNX BIC #370,R4 ;isolate the X part of NNX SWAB R5 ;one part for each byte BISB R4,R5 SWAB R5 CLR R4 ;now do high byte BISB (R0),R4 CLR R1 80$: ROR R4 BCC 90$ MOV R5,(R2) ADD R1,(R2)+ CMP R2,SPFCHK ;table full? BLO 90$ SEC BR 100$ 90$: CMP R1,#7 ;8 bits per byte BHIS 100$ INC R1 BR 80$ CLC 100$: MOV (SP)+,R5 ;*C* MOV (SP)+,R4 ;*C* MOV (SP)+,R1 ;*C* RETURN ;here if the SPFUNS table is now full 110$: TST (SP)+ 120$: .PRINT #E.SPF ;Special Function table is full" BR 57$ AREA: .BLKW 5 SYSNAM: .RAD50 /SY/ .WORD 0,0,0 DNAM: .WORD DSTAT: .BLKW 4 SPFCHK: .WORD E.SPF: .NLCSI TYPE=I,PART=PREFIX .ASCIZ /W-Special Function table is full/ .EVEN .DSABL LSB ;we must define GETSPF as the entry point, this is the entry point used ;for EL.SYS when O.LOG chains to it as a job, not a handler. .END GETSPF