.TITLE PAC Terminal Driver Pool Analyzer .MACRO ID STRING .IDENT /'STRING/ .PSECT A5DATA PACID: .ASCII /'STRING/ .ASCII / / .EVEN .ENDM ; Enter the version number here. It can be 1 - 6 ASCII characters ID 01 ;************************************************************************ ; ; PAC ; Program to report on status of terminal driver buffers ; ; Syntax: PAC TT:[/FULL] or PAC KB:[/FULL] ; ; Date: November 28, 1984 ; Author: Mark Hartigan - Bankers Trust Company, New York ; ; Note: The KB driver is a PSI communications product ; which we have purchased from Cableshare, Inc. ; in London, Ontario. The reason why it is ; referenced in this program is that it uses data ; structures very similar to the TT driver. This ; program was in fact originally developed to solve ; a packet eating problem with KB:. ; ; ; Modified ; -------- ; ; ;************************************************************************ .ENABL LC .NLIST BEX .NLIST ME .MCALL EXIT$S,QIOW$,DIR$,EXST$S,GMCR$,SWSTK$ .MCALL DCBDF$,PCBDF$,UCBDF$,HWDDF$,GTIM$S .MCALL ISTAT$,STATE$,TRAN$ DCBDF$ ; Get Device Control Block offsets PCBDF$ ; Get Partition Control Block offsets UCBDF$ ; Get Unit Control Block offsets HWDDF$ ; Get hardware addresses (KDSAR6) .PAGE .SBTTL Local Macros and symbols ;+ ; ; Macro definitions ; ;- .MACRO MSG NAM,MESSAGE MSG'NAM: .ASCII "MESSAGE" MSL'NAM=.-MSG'NAM .EVEN .ENDM .MACRO MSGBEG NAM MSG'NAM: .ENDM MSGBEG .MACRO MSGEND NAM MSL'NAM=.-MSG'NAM .EVEN .ENDM MSGEND ; ; Print a formatted line .MACRO PRINTF FMT,VAR,VAREXT MOV R1,-(SP) MOV R2,-(SP) ; Save the registers we'll be using MOV R3,-(SP) MOV #FMT,R1 .IIF NB MOV #VAR,R2 .IIF B CLR R2 .IIF NB MOV #VAREXT,R3 .IIF B CLR R3 CALL FMTMSG MOV (SP)+,R3 MOV (SP)+,R2 MOV (SP)+,R1 ; Restore the registers .ENDM PRINTF .MACRO PRINT NAM,RESTORE MOV #MSG'NAM,QIO+Q.IOPL MOV #MSL'NAM,QIO+Q.IOPL+2 DIR$ #QIO .ENDM PRINT ;+ ; ; Symbol definitions ; ;- MAXCOM = 256. ; Maximum number of terminal buffers MAXTRM = 128. ; Maximum number of terminal lines DCBCNT = 32. ; Maximum number of terminal controllers LOSCNT = 256. ; Maximum number of lost buffers we expect UCXBAS = 140000 ; Address where UCB extensions are mapped .PAGE .SBTTL MAIN - Code Section .PSECT TERMIO,RW,D,REL,CON ; PSECT for formats and variables ; The PAC PSECT is used for code which can be in either APR .PSECT PAC,RW,I,LCL,REL,CON ; The A5INST PSECT is so named to force its allocation in the first APR .PSECT A5INST,RW,I,LCL,REL,CON ;+ ; This is the main program stream. ; ;- START: CALL INIT CALL GETCMD ; Get MCR command line CALL GETCOM ; Get info on terminal common CALL GETDCB ; Get table of terminal DCBs CALL $SWSTK, 10$ ;;; Switch to system state ;------------------------------------------------------------------------------ ; Start the SYSTEM STATE TRAP CATCHER MOV SP,OKSP ;;; Save SP for restore on odd or mem prot trap MOV @#PS,OKPS ;;; Save valid PSW too MOV @#4,OLDODD ;;; Save old odd addr. trap vector MOV @#250,OLDMPV ;;; Same for mem. prot. violation MOV #ODDTRP,@#4 ;;; Put in our own trap vectors MOV #MPVTRP,@#250 ;;; CLR BADPC ;;; Clear flag/bad pc location ;------------------------------------------------------------------------------ CALL FRELST ;;; Scan and tag free buffer list CALL DCBLST ;;; Scan and tag all terminal buffers thru DCBs CALL LOSBLD ;;; Build the lost buffer table JMP XITSYS ;;; Leave system state 10$: CALL CHKERR ; Report system state errors BCS 20$ ; Exit on system state error ; CALL DMPTML ; Dump (print out) the terminal table CALL ANALYZ ; Analyze terminal table and print brief report TST FULL ; Full report wanted? BEQ 20$ ; If eq, no TST LOSTBF ; Are any buffers lost? BEQ 20$ ; If eq, no CALL DOFULL ; Print full report on lost buffers 20$: CALLR EXIT ; Exit .PAGE .SBTTL INIT -- Initialize data areas ;+ ; ; Initialize data areas and buffers. ; ; INPUT ; None. ; ; OUTPUT ; None. ; ;- .PSECT PAC INIT: CLR PARNAM ; Clear pointer to name of partition (xxCOM) CLR FULL ; Clear brief/full display indicator CLR MAXUNT ; Clear maximum terminal number MOV #BUFMAP, R0 ; Clear buffer map MOV #MAXCOM/2,R1 1$: CLR (R0)+ SOB R1,1$ MOV #TMLTBL,R0 ; Clear terminal table MOV #TTBLSZ*MAXTRM,R1 2$: CLR (R0)+ SOB R1,2$ MOV #DCBTBL,R0 ; Clear DCB table MOV #DCBCNT,R1 3$: CLR (R0)+ SOB R1,3$ MOV #T$$BFL,PKTSIZ ; Packet size field for header RETURN .PAGE .SBTTL GETCMD -- Get MCR Command. ;+ ; ; Get the MCR command line typed. ; ; INPUT ; None. ; ; OUTPUT ; PARNAM = Pointer to RAD50 name of selected common ; DEVNAM = ASCII name of selected device (TT or KB) ; FULL = 0 unless full display selected ; ;- .PSECT PAC GETCMD: DIR$ #GETMCR ; Get MCR command line MOV $DSW,R2 ; Char counter BLT 2$ ; Failed CMP R2,#3 BNE 1$ ; Default to TT: MOV #TTPAR,PARNAM MOV #"TT,DEVNAM CALL TTDATA ; Default to KB: ; MOV #KBPAR,PARNAM ; MOV #"KB,DEVNAM ; CALL KBDATA RETURN 1$: SUB #7, R2 ; Less than 7 characters (PAC xx:) ? BLT 6$ ; If lt, yes, failed BR 3$ ; Okay 2$: PRINT 1 ; Read failed CALLR EXIT ; 3$: CMP #"TT,MCRBUF ; Command line start with TT? BEQ 4$ ; If eq, yes CMP #"KB,MCRBUF ; Start with KB? BNE 6$ ; If ne, no, illegal command MOV #KBPAR,PARNAM ; Store name of KBCOM CALL KBDATA ; Get the base address of KBCOM BR 5$ ; 4$: MOV #TTPAR,PARNAM ; Store name of TTCOM CALL TTDATA ; Get the base address of TTCOM 5$: MOV MCRBUF,DEVNAM ; Save ASCII name of device (TT or KB) CMPB #':,MCRBUF+2 ; Followed by a colon? BEQ 7$ ; If eq, yes 6$: PRINT 2 ; Illegal command line CALLR EXIT ; 7$: TST R2 ; End of command? BEQ 10$ ; If eq, yes, brief display MOV #FSWIT, R0 ; R0 -> /FULL string MOV #MCRBUF+3, R1 ; R1 -> command line following colon 8$: CMPB (R0)+, (R1)+ ; Compare a character BNE 6$ ; If ne, no match, illegal command TSTB (R0) ; End of matching string? BEQ 9$ ; If eq, yes, a-okay SOB R2, 8$ ; Loop until end of command BR 6$ ; Command ended early, error 9$: INC FULL ; Remember request for full display 10$: RETURN .PAGE .SBTTL GETCOM -- Get information about xxCOM ;+ ; ; Get information about xxCOM ; ; INPUT ; PARNAM -> RAD50 name of selected common ; ; OUTPUT ; PARBAS = base address of common (in 32W blocks) ; PARSIZ = size of common (in 32W blocks) ; TOTBUF = number of terminal driver buffers in xxCOM ; ;- .PSECT PAC GETCOM: MOV PARNAM, R1 ; R1 -> RAD50 name of common MOV $CBDHD,R0 ; R0 -> Common block directory BEQ 3$ ; If eq, no commons, error 1$: CMP P.NAM(R0),@R1 ; Does first half of name match? BNE 2$ ; If ne, no, try next CMP P.NAM+2(R0),2(R1) ; Second half match? BEQ 4$ ; If eq, yes 2$: MOV P.CBDL(R0),R0 ; Get next common PCB in list BNE 1$ ; If ne, not end of list yet 3$: MOV #COMNAM, R0 ; R0 -> Start of common name, in message MOV PARNAM, R3 ; R3 -> RAD50 name of partition MOV (R3)+, R1 ; Get first half of name CALL $C5TA ; Convert MOV (R3)+, R1 ; Get second half of name CALL $C5TA ; Convert PRINT COM ; Common not found CALLR EXIT 4$: MOV P.REL(R0),PARBAS ; Store base address of common MOV P.SIZE(R0),R1 ; R1 / size of common MOV R1, PARSIZ ; Store size ASH #6,R1 ; Convert size to bytes SUB POOL,R1 ; Subtract base of buffer pool in common ADD #140000,R1 ; Compensate for POOL's offset bias CLR R0 ; Prepare to divide DIV #T$$BFL, R0 ; Divide by size of a terminal buffer MOV R0, TOTBUF ; Store number of buffers ; ; The TT driver doesn't use the last packet for some reason ; ; DEC TOTBUF RETURN .PAGE .SBTTL GETDCB -- Get table of DCBs for device ;+ ; ; Get table of DCBs for device TT:/KB: ; ; INPUT ; DEVNAM = ASCII name of device ; ; OUTPUT ; DCBTBL contains table of pointers to DCBs ; ;- .PSECT A5INST GETDCB: CLR R1 ; Offset in various tables MOV $DEVHD,R0 ; Head of system device list 1$: TST R0 ; End of DCB list BEQ 3$ ; Yes CMP D.NAM(R0),DEVNAM ; Is this the device we want? BNE 2$ ; No MOV R0,DCBTBL(R1) ; Store the DCB address ; CALL PRTDCB ; Print out some info on DCB TST (R1)+ ; Bump pointer to tables 2$: MOV D.LNK(R0),R0 ; Link through DCB listhead BR 1$ ; Continue 3$: CLR DCBTBL(R1) ; Mark end of various tables RETURN ; ; The following subroutine is used to print out the range of terminal ; numbers for a given DCB. .PSECT A5DATA .EVEN DCBFMT: .ASCII /DCB for / DEV1: .ASCII /TT%(R8W2Z) through / DEV2: .ASCIZ /TT%(R8W2Z)/ .EVEN DCBDAT: DLOW: .WORD 0 DHIGH: .WORD 0 .PSECT A5INST PRTDCB: MOVB D.UNIT (R0),DLOW ; Low unit on DCB MOVB D.UNIT+1(R0),DHIGH ; High unit on DCB MOVB DEVNAM,DEV1 MOVB DEVNAM+1,DEV1+1 MOVB DEVNAM,DEV2 MOVB DEVNAM+1,DEV2+1 PRINTF DCBFMT,,DCBDAT RETURN .PAGE .SBTTL FRELST -- Count buffers in free list ;+ ; ; Count and tag buffers in free list ; ; ***** Assumes running in system state with PR7 set ***** ; ; INPUT ; PARBAS = KDSAR6 value to map to xxCOM ; FREE = xxDRV free list head address ; ; OUTPUT ; FREBUF = number of free buffers ; ;- .PSECT A5INST FRELST: MOV PARBAS,KDSAR6 ;;; Map to common CLR R1 ;;; R1 / Free buffer counter MOV FREE,R0 ;;; Address of free buffer list MOV (R0),R0 ;;; R0 -> Free buffer list BEQ 3$ ;;; If eq, end of list 1$: INC R1 ;;; Increment counter MOV R0,R5 ;;; R5 -> address of buffer SUB POOL,R5 ;;; R5 / offset into pool CLR R4 ;;; Prepare to divide DIV #T$$BFL,R4 ;;; Divide by buffer size BMI 2$ ;;; Branch if buffer number less than zero CMP R4,TOTBUF ;;; Is it too high? ; BHIS 2$ ;;; Branch if yes INCB BUFMAP(R4) ;;; Mark buffer as free (M.FRE = 1) 2$: MOV (R0),R0 ;;; Get next buffer BNE 1$ ;;; If ne, not end of list yet 3$: MOV R1, FREBUF ;;; Save number of free buffers RETURN .PAGE .SBTTL DCBLST -- Scan UCB extensions ;+ ; ; Scan all UCB extensions in DCB table, counting and tagging buffers. ; ; ***** Assumes running in system state ***** ; ; INPUT ; DCBTBL = Table of DCBs to be scanned. ; ; OUTPUT ; None. ; ;- .PSECT A5INST .ENABL LSB DCBLST: CLR MAXUNT ;;; Clear highest unit number MOV #DCBTBL,DCBPTR ;;; DCBPTR -> Table of selected DCBs ; ; Loop through the DCB's ; NXTDCB: MOV @DCBPTR,R2 ;;; Get the next DCB address to process BEQ DCBRET ;;; If eq, no more. ADD #2,DCBPTR ;;; Bump the pointer for the next time ; We have another DCB; process it MOV D.UCBL(R2),UCBLEN ;;; Save length of a UCB MOVB D.UNIT+1(R2),R1 ;;; R1 / Highest unit # on this DCB CMP R1, MAXUNT ;;; Compare with highest unit # BLT 2$ ;;; If le, no need to update MOV R1, MAXUNT ;;; Store new highest unit # 2$: MOV D.UCB(R2),R0 ;;; R0 -> UCB MOVB D.UNIT(R2),R2 ;;; R2 / Low unit # on this DCB SUB R2, R1 ;;; Get range of unit #s INC R1 ;;; Add one to get number of units ; ; Loop through all the UCB's for the current DCB ; NXTUCB: MOV R1, UNITS ;;; Store number of units on this DCB MOV R2, CURUNT ;;; Store current unit # ; Calculate the offset in the terminal table MOV R2,R1 ;;; Prepare for multiplication MUL #TTBLSZ*2,R1 ;;; Cur unit # * SIZE for term tbl off MOV R1,R2 ;;; Put in a different place ADD #TMLTBL, R2 ;;; R2 -> Terminal table counters MOV R0,TBLUCB(R2) ;;; Save UCB address for this terminal MOV U.TUX(R0),R1 ;;; R1 -> UCB extension BEQ 10$ ;;; If eq, no UCBX, do next UCB ; Map to the UCB extension and copy it to local storage MOV R1, KDSAR6 ;;; Map to UCBX MOV #T$$UXL/2,R1 ;;; Get length to copy MOV #UCXBAS,R4 ;;; Get the address of the actual UCB extension MOV #UEXTBF,R3 ;;; Get address of the local storage for it UELOOP: MOV (R4)+,(R3)+ ;;; Copy the UCB extension SOB R1,UELOOP ;;; Loop until through MOV PARBAS,KDSAR6 ;;; Map to xxCOM (where the buffers are) ; We've gotten the UCB extension; analyze it MOV UEXTBF+U.TFPB,TBLPAD(R2);;; Store first prmpt buf add in table ; Check for an input buffer ; BIT #S1.IBY,U.TSTA(R0) ;;; Is input busy? BEQ 6$ ;;; If eq, no BIT #S1.IBF,U.TSTA(R0) ;;; Buffered input? BEQ 6$ ;;; Branch if not MOV UEXTBF+U.TFIB,PKTADD ;;; Point to list of input buffers CALL DOQUE ;;; Scan and tag them ADD PKTCOM,TBLINP(R2) ;;; Store buffer count in terminal table ADD PKTPOO,TBLPOO(R2) ;;; Add in the pool buffer count ;------------------------------------------------------------------------------ ; ; In the following sections check for an output buffer or a prompt buffer ; Note that there can only be one or the other. Also note that the output ; is also marked as busy if there is a prompt. It's important not to count ; the prompt buffers twice. 6$: BIT #S1.OBY,U.TSTA(R0) ;;; Is output busy? BEQ 8$ ;;; If eq, no BIT #S3.RPO,U.TSTA+4(R0) ;;; Check for READ/PROMPT in progress BNE 7$ ;;; Branch if READ with PROMPT in progress ; We have NORMAL OUTPUT in progress ; MOV UEXTBF+U.TFOB,PKTADD ;;; Point to list of output buffers CALL DOQUE ;;; Scan and tag them ADD PKTCOM,TBLOUT(R2) ;;; Store buffer count in terminal table ADD PKTPOO,TBLPOO(R2) ;;; Add in the pool buffer count BR 8$ ; We have PROMPT OUTPUT in progress ; 7$: MOV UEXTBF+U.TFPB,PKTADD ;;; Point to prompt buffer CALL DOQUE ;;; Scan and tag them ADD PKTCOM,TBLPRM(R2) ;;; Store prompt buffer count ADD PKTPOO,TBLPOO(R2) ;;; Add in the pool buffer count ; Check for terminator table (there can only be one of these) ; 8$: MOV UEXTBF+U.TRTT,PKTADD ;;; Point to terminator table CALL DOONE ;;; Scan and tag it ADD PKTCOM,TBLTRM(R2) ;;; Count one term table buffer ADD PKTPOO,TBLPOO(R2) ;;; Add in the pool buffer count 10$: MOV CURUNT,R2 ;;; Restore current unit number MOV UNITS,R1 ;;; Restore # units on DCB DEC R1 ;;; One more unit done BEQ NXTDCB ;;; If eq, this DCB is all done INC R2 ;;; Increment current unit number ADD UCBLEN,R0 ;;; Point to next UCB BR NXTUCB ;;; DCBRET: RETURN .DSABL LSB .PAGE .SBTTL LOSBLD -- Build the table of lost buffers ;+ ; ; LOSBLD ; ; Assume that this routine runs in system state ; ; When we find a lost buffer, ; scan through the TMLTBL and see if it matches up with a first prompt buffer ; address. If so, follow it through with the DOQUE routine. When finished, add ; total into the prompt buffer count for the terminal. If not found, leave it ; as a lost buffer. ; ;- .PSECT A5INST .ENABL LSB LOSBLD: MOV PARBAS,KDSAR6 ;;; Map to xxCOM (where the buffers are) MOV #LOSTBL, R2 ;;; R2 -> Table of lost buffer addresses MOV #BUFMAP, R3 ;;; R3 -> Terminal buffer byte map MOV TOTBUF,R4 ;;; R4 will be the loop counter ; ; Loop through the entire buffer map (BUFMAP) ; ; This is a 2 pass process. On the first pass, we loop through ; the buffer map and find all buffers which are not accounted ; for. We search for these in the first prompt buffer field of ; every unit. If found, the chain of buffers is followed to the ; end and all the buffers in the chain are marked off as found ; in the buffer map. ; ; On the second pass, the buffer map is scanned again and the ; lost buffer list (LOSTBL) is generated. ; ---- PASS 1 ---- 10$: TSTB (R3) ;;; Test status of a buffer BNE 45$ ;;; If non-zero, not lost ; We might have a lost buffer, find its address MOV R3,R1 ;;; Copy address of the byte SUB #BUFMAP, R1 ;;; Convert into byte offset into map MUL #T$$BFL,R1 ;;; Multiply by size of a buffer ADD POOL, R1 ;;; Add base of buffer pool in xxCOM ; Now that we have the address, see if there are any prompt buffers ; Note that we are only interested in the prompt buffer address if ; there is active input for the terminal. This is the only way that ; the buffer would have been marked as lost in the first place. That is, ; the prompt output was finished, but the input still in progress leaving ; the prompt buffers still allocated. MOV #TMLTBL,R5 ;;; Get the base address of terminal table ; Loop through all the terminals looking for this packet NXTTER: MOV TBLUCB(R5),R0 ;;; Get this terminal's UCB address BIT #S1.IBY,U.TSTA(R0) ;;; Is input busy? BEQ 30$ ;;; Branch if input not busy CMP R1,TBLPAD(R5) ;;; Compare our "lost" address with prmpt buffer BEQ 40$ ;;; Branch if prompt buffer matches 30$: ADD #TTBLSZ*2,R5 ;;; Move to next entry in terminal table CMP R5,#TMLTOP ;;; Have we reached the end of table? BLO NXTTER ;;; If not at end, loop again BR 45$ ; End of loop through the terminals ; We found a packet; trace it through 40$: MOV R1,PKTADD CALL DOQUE ADD PKTCOM,TBLPRM(R5) ADD PKTPOO,TBLPOO(R5) 45$: INC R3 ;;; Bump pointer in BUFMAP SOB R4,10$ ;;; Loop ; ; End of PASS 1 ; PASS 2 --- Go through the BUFMAP and generate the lost buffer list MOV #LOSTBL, R2 ;;; R2 -> Table of lost buffer addresses MOV #BUFMAP, R3 ;;; R3 -> Terminal buffer byte map MOV TOTBUF,R4 ;;; R4 will be the loop counter 50$: TSTB (R3) ;;; Test status of a buffer BNE 60$ ;;; If non-zero, not lost ; We have a lost buffer, find its address MOV R3,R1 ;;; Copy address of the byte SUB #BUFMAP, R1 ;;; Convert into byte offset into map MUL #T$$BFL,R1 ;;; Multiply by size of a buffer ADD POOL, R1 ;;; Add base of buffer pool in xxCOM MOV R1, (R2)+ ;;; Store in list of lost buffers 60$: INC R3 ;;; Bump pointer in BUFMAP SOB R4,50$ ;;; Loop CLR (R2) ;;; Mark end of lost buffer table RETURN ;;; .DSABL LSB .PAGE .SBTTL DOQUE, DOONE -- Count and tag terminal buffers ;+ ; ; DOQUE ; Count and tag a linked list of terminal buffers ; ; Note: This routine preserves ALL registers ; ; INPUT ; Address of first packet to count ---> PKTADD ; ; OUTPUT ; Number of packets found in xxCOM ---> PKTCOM ; Number of packets found in Pool ---> PKTPOO ; ;- .PSECT A5DATA ; --Input to routine PKTADD: .WORD 0 ; Address of the first packet to count ; --Output from routine PKTCOM: .WORD 0 ; Number of packets found in xxCOM PKTPOO: .WORD 0 ; Number of packets found in primary pool ONEFLG: .WORD 0 ; The "Doing Only One" flag .PSECT A5INST .ENABL LSB DOONE: MOV #1,ONEFLG ;;; Flag which means we're doing only one BR CHKQUE DOQUE: CLR ONEFLG ;;; Flag which means we're doing a chain CHKQUE: CALL $SAVAL ;;; Save all registers CLR PKTCOM ;;; Initialize the result counters CLR PKTPOO ;;; Ditto MOV PKTADD,R1 ;;; Get the address of the packet ; Process next packet in chain. PROPKT: TST R1 ;;; Is this a valid packet? BEQ ENDQUE ;;; Branch if we're done CMP R1,#160000 ;;; Make sure we've got a real address BHIS ENDQUE ;;; Branch if we haven't CMP R1,#140000 ;;; Analyze the address of this packet BLO INPOOL ;;; Branch if in primary pool ; The packet is in xxTCOM INCOM: INC PKTCOM ;;; Increment the xxCOM buffer count MOV R1,R3 ;;; Copy the address of the buffer SUB POOL,R3 ;;; Get the offset into pool CLR R2 ;;; Prepare to divide DIV #T$$BFL,R2 ;;; Divide by buffer size INCB BUFMAP(R2) ;;; Mark the buffer "found" in BUFMAP BR NXTBUF ;;; Go look for the next buffer in chain ; The packet is in PRIMARY POOL INPOOL: INC PKTPOO ;;; Increment the pool buffer count ; ; At this point, we get the next buffer in the chain NXTBUF: TST ONEFLG ;;; See if we're only supposed to do one BNE ENDQUE ;;; Branch if yes MOV (R1),R1 ;;; Get the address of next buffer BR PROPKT ;;; Process this buffer ; ; We've finished with the current queue ENDQUE: RETURN .DSABL LSB .PAGE .SBTTL DMPTML -- Octal dump of terminal ;+ ; ; Dump the terminal table ; ; INPUT ; TMLTBL = terminal table ; ; OUTPUT ; None. ; ;- ; ; Local data and formats for this routine ; .PSECT TERMIO DMPDAT: ; Data to be dumped DMPTT: .BLKW 1 DMPOUT: .BLKW 4 ; Data block for the FMTMSG routine DMPPOO: .BLKW 1 ; Address of pool packet count DMPPAD: .BLKW 1 ; Address of the first prompt buffer DMPUCB: .BLKW 1 ; Address of terminal's UCB DMPEND: ; End marker DHFMT: .ASCIZ / Terminal Table Dump - MAXUNT = %(BZR8W3)/ .EVEN DMPFMT: .ASCII /TT%(ZR8W2): In= %(BZW3) Out= %(BZW3)/ .ASCII / Prompt= %(BZW3) Term= %(BZW3)/ .ASCIZ / Pool=%(BZW3) PAD=%(R8ZW6) UCB=%(R8ZW6)/ .EVEN DMPFLG: .WORD 0 ; Flag to indicate if something on line .PSECT PAC DMPTML: PRINTF DHFMT,,MAXUNT ; Print header for table MOV MAXUNT, R5 ; R5 / highest terminal number found INC R5 ; Change to number of terminals CLR DMPTT ; Clear TT number counter MOV #TMLTBL, R4 ; R4 -> terminal table 1$: MOV #TTBLSZ, R3 ; R3 / number of words per line MOV #DMPOUT,R1 ; R1 gets the address of output block ; Transfer an entry for the next terminal 2$: MOV (R4)+, (R1)+ ; R1 / word from table SOB R3, 2$ ; Loop for three words ; Determine if we have something to print ; CMP DMPPAD,#140000 ; Is it a real address? ; BLO 23$ ; Branch if not ; CLR DMPFLG ; Clear the "we got something" flag ; MOV #DMPOUT,R3 ; Starting address of output data ;21$: TST (R3)+ ; Test the data ; BEQ 22$ ; INC DMPFLG ; Set the flag; we got something ;22$: CMP R3,#DMPEND ; BLO 21$ ; TST DMPFLG ; Did we get anything? ; BEQ 23$ ; Branch if not MOV DEVNAM,DMPFMT ; Store the proper device name PRINTF DMPFMT,,DMPDAT 23$: INC DMPTT ; Bump the terminal number CMP #TMLTOP, R4 ; At end of table? BLOS 3$ ; If los, yes SOB R5, 1$ ; Loop until all terminals done 3$: RETURN .PAGE .SBTTL ANALYZ -- Analyze terminal table and print brief report ;+ ; ; Analyze contents of terminal table and print brief report ; ; INPUT ; TMLTBL = table of counters by terminal unit number. ; ; OUTPUT ; None. ; ;- .PSECT PAC ANALYZ: PRINT SKP ; Skip a line MOV @#$VERSN,SYSVER ; Get the first part of version MOV @#$VERSN+2,SYSVER+2 ; Get the last part of version MOV @#$SYSID,SYSBL ; Get the first part of base line MOV @#$SYSID+2,SYSBL+2 ; Get the last part of base line GTIM$S #TIMBUF ; Get the current time of day PRINTF HDRFMT,HDRDAT ; Print the report header PRINTF SYSFMT,VERDAT ; Print the system version + base line PRINT SKP ; Skip a line PRINT COL ; Print column heads PRINT SKP ; Skip a line MOV #TOTALS,R0 ; Zero total input, output, other buffers CLR (R0)+ ; Input buffer CLR (R0)+ ; Output CLR (R0)+ ; Prompt CLR (R0)+ ; Terminator table CLR (R0) ; Primary Pool MOV FREBUF,GRTOT ; Copy free count to grand total PRINTF FREFMT,,FREBUF PRINT SKP ; Skip a line 1$: MOV #TMLTBL, R3 ; R3 -> Terminal counter table CLR TERNUM ; R4 / Terminal number 2$: CMP R3, #TMLTOP ; At end of terminal buffer? BHIS 7$ ; If his, yes, done CMP TERNUM,MAXUNT ; Past last terminal found? BGT 7$ ; If gt, yes, done CLR TMLTOT ; Clear total count for terminal CLR INTTOT ; Clear the internal term total counter MOV #TOTALS,R1 ; Category totals MOV #TINPUT,R5 ; Output formatting buffers MOV #5,R0 ; Loop counter 3$: CMP R0,#1 ; Is this the last pass? BEQ 4$ ; If yes, don't add to grand total ADD (R3),GRTOT ; First add into the grand total ADD (R3),TMLTOT ; Add in this category for terminal 4$: ADD (R3),INTTOT ; Add category to internal total for term ADD (R3),(R1)+ ; Add into category totals for all terminals MOV (R3)+,(R5)+ ; Move to output formatting buffers SOB R0,3$ ADD #4,R3 ; Bump R3 (7 words in terminal table) 5$: TST INTTOT ; Anything of interest for this terminal? BEQ 6$ ; If eq, no, skip MOV DEVNAM,TERFMT ; Move in the string "KB" or "TT" PRINTF TERFMT,,TERNUM ; Print the line for this terminal 6$: INC TERNUM ; Increment terminal number BR 2$ ; Loop 7$: PRINT SKP ; Skip a line MOV TOTBUF,LOSTBF ; Get the total number of availble buffers SUB GRTOT,LOSTBF ; Subtract number found to get lost BEQ 8$ ; If eq, none lost PRINTF LSTFMT,,LOSTBF ; Print out the number of lost buffers PRINT SKP ; Skip a line 8$: PRINT DSH ; Print a line of dashes PRINT SKP ; Skip a line PRINTF TOTFMT,,TOTLIN PRINT SKP ; Skip a final line RETURN .PAGE .SBTTL DOFULL -- Display lost buffers ;+ ; ; Display contents of lost buffers ; ; INPUT ; LOSTBL = Table of lost terminal buffers ; ; OUTPUT ; None. ; ;- .PSECT PAC DOFULL: PRINT SKP ; Skip a line PRINT LHD ; Print lost buffer header MOV #LOSTBL,R3 ; Point back at beginning of list 1$: MOV (R3)+,BUFADR ; Get a buffer pointer BEQ 2$ ; If eq, done MOV BUFADR,R5 ; Copy the packet address SUB POOL,R5 ; Convert it to packet number CLR R4 DIV #T$$BFL,R4 INC R4 MOV R4,BUFNUM ; Store in output formatting block CALL GETBUF ; Get a copy of the buffer CALL FMTLOS ; Print contents of the buffer BR 1$ 2$: RETURN .PAGE .SBTTL GETBUF -- Make a copy of a terminal buffer .PSECT A5INST GETBUF: CALL $SWSTK, 3$ ;;; Switch to system state MOV SP,OKSP ;;; Save SP for restore on odd or mem prot trap MOV @#PS,OKPS ;;; Save valid PSW too MOV @#4,OLDODD ;;; Save old odd addr. trap vector MOV @#250,OLDMPV ;;; Same for mem. prot. violation MOV #ODDTRP,@#4 ;;; Put in our own trap vectors MOV #MPVTRP,@#250 ;;; CLR BADPC ;;; Clear flag/bad pc location MOV PARBAS,KDSAR6 ;;; Map to xxCOM MOV BUFADR,R3 ;;; Move address of packet to copy MOV #BUFCPY, R4 ;;; R4 -> Area to copy lost buffer into MOV #T$$BFL/2, R5 ;;; R3 / length of a buffer in words 2$: MOV (R3)+, (R4)+ ;;; Copy a word SOB R5, 2$ ;;; Loop JMP XITSYS ;;; Leave system state 3$: RETURN .PAGE .SBTTL FMTLOS -- Format and print contents of a terminal buffer .PSECT PAC FMTLOS: PRINT SKP ;Skip a line PRINTF LBHFMT,,BUFNUM ; Print the lost packet header PRINTF LBDFMT,PKTADR RETURN .PAGE .SBTTL FMTMSG -- Format and print a message ;+ ; ; FMTMSG ; Format a message using $EDMSG and print it ; ; INPUT ; R1 -> Format string ; R2 -> $EDMSG argument block ; R3 -> EDMSGX argument block ; ; OUTPUT ; None. ; ;- .PSECT PAC FMTMSG: CALL $SAVAL ; Save registers MOV R1,R4 ; Save start of format string MOV #OUTBUF, R0 ; R0 -> Common output buffer MOV R0, QIO+Q.IOPL ; Store its address in QIO buffer TST R3 ; Test for extended formatting BEQ NOREDT ; Branch if none MOV R2,-(SP) ; Save $EDMSG argument block MOV R3,R2 ; Argument block for EDMSGX MOV R4,R1 ; Get address of format string CALL EDMSGX ; Extended message formatting MOV (SP)+,R2 ; Restore $EDMSG argument block NOREDT: TST R2 ; Test for normal editing BEQ FMTOUT ; Branch if none MOV R4,R1 ; Get address of format string CALL $EDMSG ; Format message FMTOUT: MOV R1, QIO+Q.IOPL+2 ; Save its length in QIO buffer DIR$ #QIO ; Print message RETURN ; Return .PAGE .SBTTL EXIT -- Exit to user ;+ ; ; Exit this program ; ;- .PSECT A5INST EXIT: EXIT$S ; Exit back to user .PAGE .SBTTL ODDTRP, MPVTRP -- System state trap handlers ;+ ; ; ODDTRP ; Odd address trap handler ; MPVTRP ; Memory protection violation trap handler ; ; INPUT ; @SP = PC after trap occurred ; OKSP = Kernel stack pointer on entry to system state ; OKPS = Processor status word on entry to system state ; OUTPUT ; None. ; ;- .PSECT A5INST MPVTRP: INC (SP) ;FLAG MEM. PROTECT VIOLATIONS W/ ODD PC ODDTRP: MOV KINAR5,KDSAR5 ; RESTORE MAPPING OF KERNAL DATA APR 5 ; (TO SAME AS I-SPACE APR 5) MOV (SP),BADPC ;SAVE MOST RECENT PC FOR ERROR MESSAGE MOV OKSP,SP ;RESTORE VALID SP (ELIMINATE JUNK ON STACK) MOV OKPS,@#PS ; SAME FOR PSW MOV R0,BADR0 ; SAVE R0 OF FAILURE MOV #BADR1,R0 MOV R1,(R0)+ ; AND ALL OTHER REGS MOV R2,(R0)+ MOV R3,(R0)+ MOV R4,(R0)+ MOV R5,(R0)+ .PAGE .SBTTL XITSYS -- Turn off system state trap handlers ;+ ; ; Turn off system state trap handler ; ; INPUT ; @SP = Real return address ; OLDODD = Normal kernel odd address trap handler ; OLDMPV = Normal kernel memory protection trap handler ; OUTPUT ; None. ; ;- .PSECT A5INST XITSYS: MOV OLDODD,@#4 ;;; Restore standard trap vectors MOV OLDMPV,@#250 ;;; RETURN ; Return to user state .PAGE .SBTTL System state trap reporter ;+ ; ; System state trap reported ; ; ****** Executed in user state ****** ; ; INPUT ; BADPC = PC of trap (0 if none occurred) ; ; OUTPUT ; None. ; ;- .PSECT PAC CHKERR: MOV BADPC,R1 ;CHECK FOR TRAP WHILE ON SYSTEM STACK BEQ NOERR MOV R1,R2 ; R2 NON 0 IS NO 0 SUPPRESS MOV #ODDNUM,R0 ;OOPS, DEFAULT TO ODD ADDRESS MESSAGE ASR R2 ;CHECK FOR FLAG FOR MEM. PROT VIOLATION BCC 10$ ;FLAG CLEAR IF EVEN ADDRESS MOV #MPVNUM,R0 ;WAS MEM. PROT. VIOLATION, CHANGE MESSAGE MOV R2,R1 ASL R1 ;CONVERT BACK TO VALID PC CALL $CBOMG ;CONVERT PC TO ASCII PRINT MPV ; PRINT THE MESSAGE BR 15$ 10$: CALL $CBOMG ;CONVERT THE PC PRINT ODD ; PRINT THE ODD ADDRESS MESSAGE 15$: MOV #REGNUM,R0 ;DO REGISTER PRINTOUT MOV #BADR0,R4 ; REGISTER STORAGE MOV #6,R5 ; LOOP COUNTER 20$: MOV R4,R2 ; NO 0 SUPPRESS CMPB (R0)+,(R0)+ ; ADVANCE BUFFER PTR MOV (R4)+,R1 ; NUMBER TO CONVERT CALL $CBOMG ; CONVERT IT SOB R5,20$ PRINT REG ; PRINT REGISTERS SEC ; Tell the caller that an error occurred RETURN NOERR: CLC ; Indicate that no error occurred RETURN .SBTTL xxCOM LINK AREA .PSECT COMDAT,D,GBL,OVR,REL POOL: .WORD 0 ; Base address of xxPOOL FREE: .WORD 0 ; Base address of XX: free list .SBTTL DATA -- Teriminal I/O related data .PSECT TERMIO ; The following data block is used for the formatted report header HDRDAT: .WORD DEVNAM ; The address of our device name PKTSIZ: .WORD 0 ; Will be size of packet TIMBUF: ; Buffer to receive the time of day TBDATE: .BLKW 3 TBTIME: .BLKW 5 VERDAT: .WORD PACID .WORD SYSVER .WORD SYSBL SYSVER: .BLKB 4 ; To receive the system version number SYSBL: .BLKB 4 ; To receive the system base line level QIO: QIOW$ IO.WVB,5,1,,IOSB,, ; QIO output directive buffer MSGODD: .ASCII /Odd address trap @ PC / ODDNUM: .ASCII /000000/ MSLODD= .-MSGODD MSGMPV: .ASCII /Memory protect violation @ PC / MPVNUM: .ASCII /000000/ MSLMPV= .-MSGMPV MSGREG: .ASCII /Registers:/ REGNUM: .REPT 6 .ASCII / 000000/ .ENDR MSLREG= .-MSGREG MSG BAD, MSG NBD, MSG 1, MSG 2, MSGBEG COM .ASCII /PAC -- Common / COMNAM: .ASCII /XXXXXX not found./ MSGEND COM FSWIT: .ASCIZ "/FULL" ; /FULL switch template HDRFMT: .ASCII <33>/[H/ ; Home .ASCII <33>/[J/ ; Erase Screen HDRDEV: .ASCIZ /%2ACOM Packet Analysis - [Packet size = %M. bytes] - %Y %3Z/ SYSFMT: .ASCIZ /PAC (Version %6A) RSX11M-PLUS-V%4A BL%4A/ MSG COL,< Total Input Output Prompt Termtable Pool> FREFMT: .ASCIZ /Free %(BZW4)/ TERFMT: .ASCII /xx%(ZR8W2): %(BZW3) %(BZW3)/ .ASCIZ / %(BZW3) %(BZW3) %(BZW3) (%(BZW3))/ LSTFMT: .ASCIZ /Lost %(BZW4)/ TOTFMT: .ASCII /Total %(BZW3) %(BZW3) %(BZW3)/ .ASCIZ / %(BZW3) %(BZW3) (%(BZW3))/ MSG LHD, LBHFMT: .ASCII /Lost buffer # %(W3BZ) at address %(W6ZR8):/ .ASCIZ / Word 1(8): %(W6ZR8) Word 2(10): %(W6ZR10)/ LBDFMT: .ASCIZ /%20B%N%20B%N%10B%N/ .EVEN OUTBUF: .BLKB 512. MSG SKP,< > MSGBEG DSH .REPT 61. .BYTE '- .ENDR MSGEND DSH .SBTTL Data which must remain in APR 5 .PSECT A5DATA,D,CON,REL,RW GETMCR: GMCR$ ; Get-command-line directive buffer MCRBUF= GETMCR+G.MCRB+4 ; Ptr to number after UCB DEVNAM: .WORD 0 ; Name of device (KB or TT) PARNAM: .WORD 0 ; Points to RAD50 name of common KBPAR: .RAD50 /KBCOM / ; RAD50 name of KBCOM TTPAR: .RAD50 /TTCOM / ; RAD50 name of TTCOM FULL: .WORD 0 ; If zero, brief display selected, else full ; Local buffer for copying lost packet ; PKTADR: .WORD BUFCPY .WORD BUFCPY+20. .WORD BUFCPY+40. BUFNUM: .WORD 0 ; Number of packet BUFADR: .WORD 0 ; Address of copied packet BUFCPY: .BLKB T$$BFL ; The packet itself IOSB: .BLKW 2 ; I/O status block PARBAS: .WORD 0 ; Base address of xxCOM (in 32W blocks) PARSIZ: .WORD 0 ; Size of xxCOM (in 32W blocks) FREBUF: .WORD 0 ; Number of free terminal buffers in xxCOM LOSTBF: .WORD 0 ; Number of lost terminal buffers DCBPTR: .WORD 0 ; Pointer into table of DCBs to scan UCBLEN: .WORD 0 ; Length of a UCB on the current DCB UNITS: .WORD 0 ; Number of terminal units on DCB CURUNT: .WORD 0 ; Current terminal unit number MAXUNT: .WORD 0 ; Maximum terminal unit number found GRTOT: .WORD 0 ; Grand total number of buffers in use and free INTTOT: .WORD 0 ; Internal total for current terminal (ANALYZ) ; The following six words must stay together for Terminal line formatting TERNUM: .WORD 0 ; The terminal number TMLTOT: .WORD 0 ; Total number of buffers for current terminal TINPUT: .WORD 0 TOTPUT: .WORD 0 TPRMPT: .WORD 0 TTERMR: .WORD 0 TPPOOL: .WORD 0 ; The following four words must stay together for Total line formatting TOTLIN: TOTBUF: .WORD 0 ; Number of terminal buffers in xxCOM TOTALS: .BLKW 5 ; Total # input, output, prompt, ; terminator table and primary pool packets LOSTBL: .BLKW LOSCNT ; Table of lost buffer pointers DCBTBL: .BLKW DCBCNT ; Table of terminal DCB pointers ; The following buffer is used to store the UCB extension UEXTBF: .BLKB T$$UXL BUFMAP: .BLKB MAXCOM ; Byte map of terminal buffers in xxCOM ; If byte is 1, buffer is not lost MAPTOP: ; Ref label .SBTTL TRPDAT -- Trap catcher data. BADPC: .WORD 0 ;PC WHERE TRAP OCCURRED BADR0: .WORD 0 ; R0 OF FAILURE BADR1: .BLKW 5 ; R1-R5 AT FAILURE OKPS: .WORD 0 ;SAVED PSW BEFORE TRAP OCCURS OKSP: .WORD 0 ; SAME FOR SP AFTER SWITCHING TO SYSTEM STATE OLDODD: .WORD 0 ;ORIGINAL TRAP VECTOR CONTENTS OLDMPV: .WORD 0 APR7OK = . ; The following is a table for storing the totals for each terminal .EVEN TBLINP = 0 ; Input buffer count TBLOUT = 2 ; Output buffer count TBLPRM = 4 ; Prompt buffer count TBLTRM = 6 ; Terminator table count TBLPOO = 10 ; Count of packets in primary pool for terminal TBLPAD = 12 ; First prompt buffer address TBLUCB = 14 ; UCB address for this terminal TTBLSZ = 7. ; Number of words in terminal table TMLTBL: .BLKW TTBLSZ*MAXTRM ; Counters for each terminal: ; Word 0: Input buffer count ; Word 1: Output buffer count ; Word 2: Prompt buffer count ; Word 3: Terminator table count ; Word 4: Count of packets in pool ; Word 5: First prompt buffer address ; Word 6: UCB address for this terminal TMLTOP: ; Ref label .END START