.TITLE USE .IDENT /V7.11/ ;******************************************************************** ; ; THE USE COMMAND GIVES DETAILS OF SYSTEM USAGE AVERAGED OVER THE ; PREVIOUS 6 MINUTES (THE RESCHEDULE INTERVAL FOR THE TASK UPD... ; IN THE CLOCK QUEUE). IF THERE IS NO ENTRY FOR UPD... IN THE CLOCK ; QUEUE, OR IT IS NOT INSTALLED, NO UPDATING OF SYSTEM USAGE STATISTICS ; WILL BE PERFORMED. ; ; INFORMATION DISPLAYED INCLUDES: ; ; (1) PERCENT OF TIME SPENT EXECUTING USER TASKS, AND BATCH ; (2) PRECENT OF TIME PROCESSOR WAS IN KERNEL MODE ; (3) PERCENT OF NULL TIME ; (4) AVERAGE RATE OF ISSUANCE OF QIOS ; (5) AVERAGE LOADER RATE ; (6) AVERAGE CONTEXT SWITCHING RATE ; ; IF THE SWITCH /FU IS USED, THE STATISTICS ARE DISPLAYED AS ; AVERAGES SINCE SYSTEM BOOT. THIS VERSION IS INDEPENDANT OF ; UPD... AND PRESENTS A CONTINUOUS UPDATE. ; ; THE /FU SWITCH CAN BE A PRIVILEGED OPTION IF REQUIRED. ; ; ; VERSION: V6 OCTOBER 1979 ; VERSION: V7 JANUARY 1981 ; ; STEVE THOMPSON ; SCHOOL OF CHEMICAL ENGINEERING ; OLIN HALL ; CORNELL UNIVERSITY ; ITHACA NY 14853 ; ; REVISION HISTORY ; ---------------- ; ; SMT736 6-AUG-81 REMOVED CALLS TO $LOCKL/$UNLKL ; ; SMT739 12-AUG-81 CHANGED REFERENCES TO $DDEC TO FM.QIO ; ; SMT753 7-OCT-81 CHANGED NAMES OF CONDITIONAL ASSEMBLY ; PARAMETERS; SEE THE FILES MODIFY.TXT AND ; CONDEF.MAC FOR DETAILS. ; ; SMT759 8-OCT-81 FIXED EXIT WITH STATUS SO THAT IT WORKS. ; ; SMT760 8-OCT-81 CHANGED THE OUTPUT FORMAT AND MADE A FEW ; COSMETIC CHANGES. ; ; SMT762 9-OCT-81 ADDED SUPPORT FOR BATCH/INTERACTIVE LOAD ; FEATURE. ; ; SMT780 3-NOV-81 MODIFIED PERCENTAGE CALCULATION TO GIVE ; TWO DECIMAL PLACES INSTEAD OF ONE WITHOUT ; CAUSING OVERFLOWS. ALSO ADDED ONE DECIMAL ; PLACE TO DISPLAY OF LOADER RATE. ; ; SMT788 13-NOV-81 ALLOW GMCR$ ERROR ACT AS IF A NULL COMMAND ; LINE WAS SPECIFIED ; ; SMT798 9-JAN-82 ALLOW SWITCH AFTER COMMAND NAME WITHOUT A ; SEPARATING SPACE. ; ; SMT814 12-APR-82 LOWER CASE MESSAGES FOR RSX-11M V4.0 ; ; SMT821 23-APR-82 CHANGED ENTRY POINT NAMES OF ACCOUNTING ; SUPPORT ROUTINES (SEE MODIFY.TXT) ; ;******************************************************************* .MCALL DIR$,EXIT$S,QIOW$ .MCALL GMCR$ .MCALL EXST$ ACCDF$ ; DEFINE ACCOUNTING PACKET OFFSETS BITDF$ ; DEFINE ACCOUNTING BITS .PAGE ; ; LOCAL DATA ; LUN=1 ; TI: LUN EFN=1 ; EVENT FLAG FOR TI: I/O DPT='. ; DECIMAL POINT SPA=40 ; SPACE PCN='% ; PERCENT FWID = 30. ; FIELD WIDTH FOR FORMATTING ROUTINES SHMASK= ; BIT MASK FOR SHORT COMMAND FUMASK= ; BIT MASK FOR /FU ; ; TEXT MESSAGES ; .NLIST BEX .ENABL LC .IF DF AA$USE UPNM: .ASCIZ /Statistics Update #/ WHEN: .ASCIZ /. Last update was at / FULL: .ASCIZ /Full Statistics: System Uptime = / CPU: .ASCIZ /User CPU time:/ .IF DF AA$BAT BATCH: .ASCIZ <11>/(Batch / .ENDC ; DF AA$BAT EXEC: .ASCIZ /Executive CPU time:/ NULL: .ASCIZ /Idle CPU time:/ .IF DF AA$LDR LDR: .ASCIZ /Loader Rate:/ .ENDC ; DF AA$LDR .IF DF AA$QIO QIO: .ASCIZ %I/O Rate:% .ENDC ; DF AA$QIO .IF DF AA$CSW SWT: .ASCIZ /Context Switching Rate:/ .ENDC .IF DF AA$QIO ! AA$LDR ! AA$CSW MIN: .ASCIZ / per minute/ .ENDC ; DF AA$QIO ! AA$LDR ! AA$CSW .IFTF .EVEN GMCR: GMCR$ BUF = GMCR+2 .BLKB 20. ; BUFFER EXTENSION .IFT .EVEN LOGNAM: .RAD50 /LOG.../ ; LOGGING TASK NAME LOGPTR: .WORD 0 ; TCB ADDRESS OF LOGGING TASK PKTADR: .WORD 0 ; DATA PACKET ADDRESS BITMSK: .WORD 0 ; COMMAND BIT MASK ELAP: .WORD 0,0 ; ELAPSED TIME (SECS), /FU COMMAND .IFTF ; ; MACRO ; .MACRO PRINT MSG,MSGSZ MOV MSG,IODPB+Q.IOPL .IF B MSGSZ MOV MSG'SZ,IODPB+Q.IOPL+2 .IFF MOV MSGSZ,IODPB+Q.IOPL+2 .ENDC ; B MSGSZ DIR$ #IODPB .ENDM ; ; ERROR MESSAGES ; .IFTF .IIF DF AA$V40, .ENABL LC .IFF ERR0: .ASCII /USE -- Feature not supported/ ERR0SZ=.-ERR0 .IFT ERR1: .ASCII /USE -- Logging task not installed/ ERR1SZ=.-ERR1 ERR2: .ASCII /USE -- Logging task not active/ ERR2SZ=.-ERR2 ERR3: .ASCII /USE -- Memory allocation failure/ ERR3SZ=.-ERR3 ERR4: .ASCII /USE -- No data available - please try again later/ ERR4SZ=.-ERR4 ERR5: .ASCII /USE -- Statistics overflow - please inform operator/ ERR5SZ=.-ERR5 .IFTF ERR6: .ASCII /USE -- Syntax error/ ERR6SZ=.-ERR6 ERR7: .ASCII /USE -- Bad switch/ ERR7SZ=.-ERR7 .IFT .IF DF AA$PFU ERR8: .ASCII /USE -- Privileged option/ ERR8SZ=.-ERR8 .ENDC ; DF AA$PFU .IFTF .EVEN IODPB: QIOW$ IO.WVB,LUN,EFN,,,,<0,0,40> ; OUTPUT DPB EXST: EXST$ EX$SUC .IFT IOATT: QIOW$ IO.ATT,LUN,EFN ; ATTACH DPB IODET: QIOW$ IO.DET,LUN,EFN ; DETACH DPB .IFTF .PAGE .SBTTL MAIN PROGRAM $USEEP: ; XFR ADDRESS .IFT MOV #SHMASK,BITMSK ; ASSUME SHORT PERIOD AVS. .IFTF ; ; GET COMMAND LINE AND PARSE IT ; DIR$ #GMCR ; GET COMMAND LINE BCS START ; IF CS NONE THERE, USE AC.USE MOV #BUF,R0 ; GET BUFFER ADDRESS 20$: CALL $GNBLK ; GET NEXT NON-BLANK BCS START ; EOL MEANS USE AC.USE CMPB R2,#'/ ; SWITCH COMING BEFORE A SPACE? BEQ 30$ ; IF EQ YES TST R1 ; NO SWITCH, ANY BLANKS? BEQ 20$ ; IF EQ NO, CONTINUE CMPB R2,#'/ ; SWITCH COMING? BEQ 30$ ; IF EQ YES PRINT #ERR6 ; NO, SYNTAX ERROR MOV #EX$SEV,EXST+E.XSTS ; SET SEVERE EXIT STATUS JMP STOP ; SO EXIT 30$: CALL $GNBLK ; GET FIRST CHAR. OF SWITCH BCC 50$ ; OK 40$: PRINT #ERR7 ; ERROR, BAD SWITCH MOV #EX$SEV,EXST+E.XSTS ; SET SEVERE EXIT STATUS JMP STOP ; EXIT 50$: CMPB R2,#'F ; /FU? BNE 40$ ; IF NE NO, ERROR CALL $GNBLK ; GET 2ND CHAR OF SWITCH BCS 40$ ; EOL IS ERROR CMPB R2,#'U ; /FU? BNE 40$ ; IF NE NO, ERROR CALL $GNBLK ; CHECK FOR EOL HERE BCC 40$ ; ANYTHING FOUND IS ERROR! .IFT MOV #FUMASK,BITMSK ; IT'S /FU, SO SET BIT MASK .IF DF AA$PFU MOV $TKTCB,R0 ; GET OUR TCB ADDRESS MOV T.UCB(R0),R0 ; AND OUR TI: UCB ADDRESS BIT #U2.PRV,U.CW2(R0) ; PRIVILEGED TERMINAL? BNE START ; IF NE YES PRINT #ERR8 ; PRIVILEGE VIOLATION MOV #EX$SEV,EXST+E.XSTS ; SET SEVERE EXIT STATUS JMP STOP ; SO EXIT .ENDC ; DF AA$PFU ; ; TRANSMIT REQUEST TO LOGGING TASK LOG... ; .IFF START: PRINT #ERR0 ; FEATURE NOT SUPPORTED .IFT START: DIR$ #IOATT ; ATTACH TI: MOV #LOGNAM,R3 ; GET NAME OF LOGGING TASK CALL $SRSTD ; LOOK IN STD FOR LOGGING TASK BCC 5$ ; OK, GOT IT PRINT #ERR1 ; IT'S NOT INSTALLED 4$: JMP EXIT ; EXIT 5$: BIT #TS.EXE,T.STAT(R0) ; IS THE LOGGING TASK ACTIVE? BEQ 6$ ; IF EQ YES PRINT #ERR2 ; NO IS BAD BR 4$ ; EXIT 6$: MOV R0,LOGPTR ; SAVE ITS TCB ADDRESS CLR PKTADR ; SET NO PACKET MOV #B.LUSE,R1 ; GET LENGTH OF PACKET TO ALLOCATE CALL $SWSTK,8$ ; SWITCH STACKS CALL $ALOCB ;; GET A BUFFER BCS 7$ ;; CS IS ERROR MOV R0,PKTADR ;; SAVE BUFFER ADDRESS 7$: RETURN ;; BACK TO TASK LEVEL 8$: MOV PKTADR,R5 ; RETRIEVE PACKET ADDRESS BNE 9$ ; NON ZERO IS GOOD PRINT #ERR3 ; MEMORY ALLOCATION FAILURE BR 4$ ; 9$: MOV R5,R1 ; COPY PACKET ADDRESS TO R1 MOV BITMSK,B.MASK(R5) ; SET BIT MASK IN PACKET MOV $TKTCB,B.STCB(R5) ; SET OUR TCB ADDRESS IN PACKET MOV LOGPTR,R0 ; RETRIEVE LOG...'S TCB ADDRESS CALL $SWSTK,10$ ; SWITCH STACKS CALL $EXRQF ;; QUEUE PACKET AND START LOG... CALLR $STPCT ;; STOP US UNTIL WE GET A REPLY 10$: ; REF. LABEL ; ; ANALYSE DATA RETURNED BY LOG... ; CMP #SHMASK,BITMSK ; FULL OR SHORT UPDATE VERSION? BEQ 102$ ; IF EQ, SHORT VERSION! MOV #K$$TPS,R0 ; SET TICKS TO SECONDS CONVERSION FACTOR MOV R5,R4 ; POINT R4 TO ELAPSED TIME+2 ADD #,R4 ; MOV (R4),ELAP+2 ; SAVE TICKS VALUE FOR LATER MOV -(R4),ELAP ; CALL DIVIDE ; CONVERT TO SECONDS ADD #,R4 ; POINT R4 TO NULL TIME CALL DIVIDE ; CONVERT TO SECONDS ADD #,R4 ; POINT R4 TO EXECUTIVE TIME CALL DIVIDE ; CONVERT TO SECONDS .IF DF AA$QIO ! AA$LDR ! AA$CSW SUB #B.EXEC,R4 ; POINT BACK TO START OF PACKET .ENDC ; DF AA$QIO ! AA$LDR ! AA$CSW .IF DF AA$QIO ADD #B.TQIO,R4 ; POINT TO TOTAL QIO'S CALL DIVIDE ; CONVERT SUB #B.TQIO,R4 ; RESTORE R4 TO FORMER VALUE .ENDC ; DF AA$QIO .IF DF AA$LDR ADD #B.LOAD,R4 ; CONVERT TOTAL LOADER REQUESTS CALL DIVIDE ; SUB #B.LOAD,R4 ; .ENDC ; DF AA$LDR .IF DF AA$CSW ADD #B.CSWT,R4 ; CONVERT TOTAL CONTEXT SWITCHES CALL DIVIDE ; SUB #B.CSWT,R4 ; .ENDC ; DF AA$CSW .IF DF AA$BAT ADD #B.BATU,R4 ; CONVERT BATCH CPU TIME CALL DIVIDE ; SUB #B.BATU,R4 ; .ENDC ; DF AA$BAT 102$: MOV B.ELAP+2(R5),R0 ; GET LOW ORDER ELAPSED TIME BIS B.ELAP(R5),R0 ; IS IT ZERO? BNE 13$ ; IF NE NO PRINT #ERR4 ; YES - TRY LATER JMP EXIT1 ; DEALLOCATE PACKET AND EXIT 13$: ; REF. LABEL ; ; PRINT OUTPUT HEADER MESSAGE ; MOV #BUF,R0 ; GET OUTPUT BUFFER ADDRESS CMP #FUMASK,BITMSK ; FULL STATS.? BEQ 200$ ; IF EQ YES, DIFFERENT HEADER MESSAGE MOVSTR #UPNM ; MOVE IN UPDATE STRING MOV R5,R1 ; POINT R1 TO TOTAL UPDATES ADD #B.STAT,R1 ; CALL FM.QIO ; FORMAT THE UPDATE NUMBER MOVSTR #WHEN ; MOVE IN "LAST UPDATE AT" MOV R5,R1 ; POINT R1 TO TIME PARAMETERS ADD #B.USER,R1 ; MOV #2,R2 ; SET FORMAT TO HH:MM CALL $TIM ; FORMAT THE TIME SUB #BUF,R0 ; CALCULATE MESSAGE LENGTH PRINT #BUF,R0 ; TYPE IT OUT BR 201$ ; CONTINUE AS NORMAL 200$: MOVSTR #FULL ; INSERT MESSAGE TEXT IN BUFFER MOV #ELAP,R1 ; POINT R1 TO TOTAL ELAPSED TIME CALL FM.CON ; FORMAT AS HOURS,MINUTES AND SECONDS SUB #BUF,R0 ; CALCULATE MESSAGE LENGTH PRINT #BUF,R0 ; TYPE IT OUT ; ; CALCULATE USER TIME AND TIMES SO THAT WE GET THE USAGE ; PERCENTAGE TIMES 10. ; 201$: MOV B.ELAP(R5),B.USER(R5) ; COPY ELAPSED TIME TO USER TIME MOV B.ELAP+2(R5),B.USER+2(R5) ; SUB B.EXEC+2(R5),B.USER+2(R5) ; SUBTRACT EXEC TIME SBC B.USER(R5) ; SUB B.EXEC(R5),B.USER(R5) ; SUB B.NULL+2(R5),B.USER+2(R5) ; SUBTRACT NULL TIME SBC B.USER(R5) ; SUB B.NULL(R5),B.USER(R5) ; USER TIME IS NOW IN PACKET MOV #1000.,R0 ; SET MULTIPLIER MOV R5,R4 ; POINT R4 TO USER TIME ADD #B.USER,R4 ; CALL MLTPLY ; MULTIPLY IT BY 1000. BCS 88$ ; OVERFLOW ADD #,R4 ; POINT R4 TO NULL TIME CALL MLTPLY ; MULTIPLY BY 1000. BCS 88$ ; OVERFLOW ADD #,R4 ; POINT R4 TO EXEC TIME CALL MLTPLY ; MULTIPLY BY 1000. .IF DF AA$BAT BCS 88$ ; IF CS OVERFLOW ADD #,R4 ; POINT R4 TO BATCH CPU TIME CALL MLTPLY ; MULTIPLY BY 1000 BCC 89$ ; OK .IFF BCC 89$ ; OK .ENDC ; DF AA$BAT 88$: PRINT #ERR5 ; OVERFLOW MESSAGE MOV #EX$SEV,EXST+E.XSTS ; SET SEVERE EXIT STATUS JMP STOP ; 89$: ; REF. LABEL ; ; PRINT USER AND BATCH PERCENTAGE OF CPU USED ; MOV #BUF,R0 ; GET OUTPUT BUFFER ADDRESS MOVSTR #CPU ; INSERT LEADING MESSAGE IN BUFFER MOV #BUF+FWID,R2 ; SET FIELD WIDTH SUB R0,R2 ; MOV R5,R1 ; POINT R1 TO USER TIME*1000. ADD #B.USER,R1 ; MOV #PERCNT,R3 ; SET ADDRESS OF CONVERSION ROUTINE CALL FM.FFW ; PERFORM PADDED CONVERSION .IF DF AA$BAT MOVSTR #BATCH ; INSERT "(BATCH" TEXT MOV R5,R1 ; POINT R1 TO BATCH CPU TIME*1000. ADD #B.BATU,R1 ; CALL PERCNT ; FORMAT BATCH PERCENTAGE MOVB #'),(R0)+ ; TERMINATE MESSAGE .ENDC ; DF AA$BAT SUB #BUF,R0 ; CALCULATE MESSAGE LENGTH PRINT #BUF,R0 ; AND PRINT THE MESSAGE ; ; PRINT EXECUTIVE PERCENTAGE OF CPU USED ; MOV #BUF,R0 ; SET OUTPUT BUFFER ADDRESS MOVSTR #EXEC ; INSERT "EXECUTIVE CPU" MESSAGE MOV #BUF+FWID,R2 ; SET FIELD WIDTH SUB R0,R2 ; MOV R5,R1 ; POINT R1 TO EXEC TIME*1000. ADD #B.EXEC,R1 ; MOV #PERCNT,R3 ; SET ADDRESS OF CONVERSION ROUTINE CALL FM.FFW ; PERFORM PADDED CONVERSION SUB #BUF,R0 ; CALCULATE MESSAGE LENGTH PRINT #BUF,R0 ; AND PRINT THE MESSAGE ; ; PRINT OUT PERCENTAGE OF IDLE TIME ; MOV #BUF,R0 ; SET OUTPUT BUFFER ADDRESS MOVSTR #NULL ; INSERT "NULL=" MESSAGE MOV #BUF+FWID,R2 ; SET FIELD WIDTH SUB R0,R2 ; MOV R5,R1 ; POINT R1 TO NULL TIME*1000. ADD #B.NULL,R1 ; MOV #PERCNT,R3 ; SET ADDRESS OF CONVERSION ROUTINE CALL FM.FFW ; PERFORM PADDED CONVERSION SUB #BUF,R0 ; CALCULATE MESSAGE LENGTH PRINT #BUF,R0 ; AND TYPE IT OUT ; ; RENORMALISE LOADER, I/O AND CONTEXT SWITCHING RATES FOR DISPLAY ; MOV #<60.*K$$TPS>,R0 ; SET TICKS TO MINUTES CONVERSION FACTOR .IF DF AA$LDR MOV R5,R4 ; POINT R4 TO LOADER REQUESTS ADD #B.LOAD,R4 ; CALL MLTPLY ; MULTIPLY BY TICKS PER MINUTE BCS 90$ ; OVERFLOW MOV #10.,R0 ; MULTIPLY THIS ONE BY TEN AGAIN CALL MLTPLY ; (TWO MULTIPLIES SIMPLIFIES THINGS) BCS 90$ ; IF CS, OVERFLOW (NOT LIKELY TO HAPPEN) MOV #<60.*K$$TPS>,R0 ; RESET CONVERSION FACTOR .ENDC ; DF AA$LDR .IF DF AA$QIO MOV R5,R4 ; POINT R4 TO TOTAL QIOS ADD #B.TQIO,R4 ; CALL MLTPLY ; MULTIPLY BY TICKS PER MINUTE BCS 90$ ; OVERFLOW .ENDC ; DF AA$QIO .IF DF AA$CSW MOV R5,R4 ; POINT R4 TO TOTAL CONTEXT SWITCHES ADD #B.CSWT,R4 ; CALL MLTPLY ; MULTIPLY BY TICKS PER MINUTE BCS 90$ ; IF CS OVERFLOW .ENDC ; DF AA$CSW BR 92$ ; 90$: JMP 88$ ; OVERFLOW ERROR 92$: ; REF. LABEL ; ; PRINT LOADER RATE ; .IF DF AA$LDR MOV #BUF,R0 ; GET OUTPUT BUFFER ADDRESS MOVSTR #LDR ; INSERT LOADER MESSAGE TEXT MOV R0,-(SP) ; SAVE BUFFER POINTER MOV R5,R0 ; POINT R0 TO TOTAL TIME ADD #B.ELAP,R0 ; MOV R5,R1 ; AND R1 TO LOADER RATE ADD #B.LOAD,R1 ; CALL DP.DIV ; CALCULATE LOADER RATE MOV (SP)+,R0 ; RESTORE BUFFER POINTER MOV R2,R1 ; PUT RESULT IN R1 MOV #BUF+FWID,R2 ; SET FIELD WIDTH SUB R0,R2 ; MOV #F1DEC,R3 ; SET ADDRESS OF CONVERSION ROUTINE CALL FM.FFW ; FORMAT RESULT WITH SPACE PAD MOVSTR #MIN ; INSERT "PER MINUTE" MESSAGE SUB #BUF,R0 ; CALCULATE MESSAGE LENGTH PRINT #BUF,R0 ; AND PRINT IT .ENDC ; DF AA$LDR ; ; PRINT I/O RATE ; .IF DF AA$QIO MOV #BUF,R0 ; SET OUTPUT BUFFER ADDRESS MOVSTR #QIO ; INSERT "I/O" MESSAGE MOV R0,-(SP) ; SAVE BUFFER POINTER MOV R5,R0 ; POINT R0 TO TOTAL TIME ADD #B.ELAP,R0 ; MOV R5,R1 ; POINT R1 TO TOTAL QIOS ADD #B.TQIO,R1 ; CALL DP.DIV ; CALCULATE QIO RATE MOV (SP)+,R0 ; RESTORE BUFFER POINTER MOV R2,R1 ; PUT RESULT IN R1 MOV #BUF+FWID,R2 ; SET FIELD WIDTH SUB R0,R2 ; MOV #DE.CML,R3 ; SET ADDRESS OF CONVERSION ROUTINE CALL FM.FFW ; PERFORM PADDED CONVERSION MOVSTR #MIN ; INSERT "PER MINUTE" MESSAGE SUB #BUF,R0 ; CALCULATE MESSAGE LENGTH PRINT #BUF,R0 ; AND PRINT IT .ENDC ; DF AA$QIO ; ; PRINT CONTEXT SWITCHING RATE ; .IF DF AA$CSW MOV #BUF,R0 ; SET BUFFER ADDRESS MOVSTR #SWT ; INSERT INITIAL MESSAGE TEXT MOV R0,-(SP) ; SAVE BUFFER POINTER MOV R5,R0 ; POINT R0 TO TOTAL TIME ADD #B.ELAP,R0 ; MOV R5,R1 ; POINT R1 TO TOTAL CONTEXT SWITCHES ADD #B.CSWT,R1 ; CALL DP.DIV ; CALCULATE CONTEXT SWITCHING RATE MOV (SP)+,R0 ; RESTORE BUFFER POINTER MOV R2,R1 ; COPY RESULT TO R1 MOV #BUF+FWID,R2 ; SET FIELD WIDTH SUB R0,R2 ; MOV #DE.CML,R3 ; SET ADDRESS OF CONVERSION ROUTINE CALL FM.FFW ; PERFORM PADDED CONVERSION MOVSTR #MIN ; INSERT "PER MINUTE" MESSAGE SUB #BUF,R0 ; CALCULATE MESSAGE LENGTH PRINT #BUF,R0 ; AND PRINT IT OUT .ENDC ; DF AA$CSW EXIT1: MOV PKTADR,R0 ; COPY PACKET ADDRESS TO R0 MOV #B.LUSE,R1 ; AND GET ITS LENGTH CALL $SWSTK,EXIT ; SWITCH STACKS CALLR $DEACB ;; DEALLOCATE THE PACKET EXIT: DIR$ #IODET ; DETACH TI: .IFTF STOP: DIR$ #EXST ; EXIT WITH STATUS EXIT$S ; JUST IN CASE .IFT .PAGE .SBTTL SUBROUTINES ;+ ; *** PERCNT ; ; THIS ROUTINE FORMATS A PERCENTAGE FOR CPU TIME USE. ; THE DIVIDEND COMES IN ALREADY MULTIPLIED BY 1000., SO WE GET ; THE PERCENTAGE*10 ON PERFORMING A DIVIDE. IF THE RESULT AND ; THE REMAINDER FROM THE DIVISION ARE BOTH MULTIPLIED BY TEN, ; PERFORMING ANOTHER DIVISION WILL LEAD TO ANOTHER DECIMAL PLACE ; IN THE FINAL RESULT WITHOUT HAVING TO MULTIPLY THE ORIGINAL ; FIGURE BY 10000. INSTEAD OF 1000. (WHICH CAUSES OVERFLOWS). ; ; INPUTS: ; R0 BUFFER POINTER ; R1 TIME USAGE*1000. ; R5 TOTAL TIME AT OFFSET B.ELAP ; ; OUTPUTS: ; R0 UPDATED ; R1,R2,R5 PRESERVED ; ;- PERCNT: MOV R1,-(SP) ; SAVE R1 MOV R2,-(SP) ; SAVE R2 MOV R0,-(SP) ; SAVE R0 MOV B.ELAP(R5),-(SP) ; PUT HIGH ORDER DIVISOR ON STACK MOV B.ELAP+2(R5),R0 ; AND LOW ORDER IN R0 MOV 2(R1),R2 ; LOW ORDER DIVIDEND GOES IN R2 MOV (R1),R1 ; AND HIGH ORDER IN R1 10$: TST (SP) ; HIGH ORDER DIVISOR ZERO? BNE 20$ ; IF NE NO, CONTINUE TO SHIFT TST R0 ; LOW ORDER DIVISOR STILL SIGNED? BPL 30$ ; IF PL NO 20$: ASR R1 ; DIVIDE DIVIDEND BY 2 ROR R2 ; ASR (SP) ; DIVIDE DIVISOR BY 2 ROR R0 ; BR 10$ ; LOOP 30$: TST (SP)+ ; CLEAN THE STACK MOV R0,-(SP) ; SAVE CURRENT DIVISOR CALL $DDIV ; DO D.P. BY S.P DIVIDE (HIGH ORDER RESULT ; IS ALWAYS ZERO) MOV R0,-(SP) ; SAVE THE REMAINDER ASL R2 ; MULTIPLY RESULT BY 2 MOV R2,-(SP) ; SAVE THE ANSWER (PERCENTAGE*10.) ASL R2 ; *4. ASL R2 ; *8. ADD (SP)+,R2 ; *10. (PERCENTAGE*100.) MOV R2,R4 ; AND SAVE IT IN R4 MOV (SP)+,R0 ; RESTORE THE REMAINDER MOV #10.,R1 ; SET UP TO MULTIPLY BY TEN CALL $MUL ; AND DO IT MOV R1,R2 ; SHIFT RESULTS FOR $DDIV MOV R0,R1 ; MOV (SP)+,R0 ; RESTORE THE DIVISOR CALL $DDIV ; PERFORM THE DIVISION (THE HIGH ORDER RESULT ; WILL ALWAYS BE ZERO) ADD R4,R2 ; COMPUTE FINAL PERCENTAGE*100. MOV R2,R1 ; AND TRANSFER TO R1 MOV (SP)+,R0 ; RESTORE R0 (BUFFER POINTER) CMP R1,#100. ; LESS THAN 1.00 PERCENT? BGE 40$ ; IF GE NO MOVB #'0,(R0)+ ; YES, ADD A SINGLE LEADING ZERO CMP R1,#10. ; LESS THAN 0.10 PERCENT? BGE 40$ ; IF GE NO MOVB #'0,(R0)+ ; YES, PUT IN ANOTHER DIGIT 40$: CALL DE.CML ; FORMAT PERCENTAGE MOVB -(R0),1(R0) ; MOVE OVER LAST DIGIT MOVB -(R0),1(R0) ; AND LAST BUT ONE MOVB #DPT,(R0)+ ; PUT IN DECIMAL POINT ADD #2,R0 ; STEP PAST LAST DIGIT MOVB #PCN,(R0)+ ; PUT IN "%" MOV (SP)+,R2 ; RESTORE R2 MOV (SP)+,R1 ; RESTORE R1 RETURN ; ;+ ; *** F1DEC ; ; FORMATTER ROUTINE USED DISPLAY OF LOADER RATE. ; ; INPUTS: ; R0 BUFFER ADDRESS ; R1 LOADER RATE PER MIN. *10. ; ; OUTPUTS: ; R0 UPDATED ; ;- .IF DF AA$LDR F1DEC: CALL DE.CML ; FORMAT AS ASCII DECIMAL MOVB -(R0),1(R0) ; MOVE OVER LAST DIGIT MOVB #DPT,(R0)+ ; INSERT A DECIMAL POINT INC R0 ; STEP PAST LAST DIGIT RETURN ; AND RETURN TO CALLER .ENDC ; DF AA$LDR ;+ ; *** DIVIDE -- DIVIDE A DOUBLE PRECISION NUMBER BY THE NUMBER ; CONTAINED IN R0 AND REPLACE THE NUMBER. ; ; INPUTS: ; R0 - DIVISOR ; R4 - POINTS TO DOUBLE PRECISION NUMBER ; ; OUTPUT: ; R0,R4,R5 PRESERVED ; R1,R2,R3 USED ; ;- DIVIDE: MOV R0,-(SP) ; SAVE R0 ON STACK MOV (R4)+,R1 ; PUT HIGH ORDER NUMBER IN R1 MOV (R4),R2 ; AND LOW ORDER IN R2 CALL $DDIV ; DO THE DIVIDE MOV R2,(R4) ; REPLACE LOW ORDER WITH RESULT MOV R1,-(R4) ; AND HIGH ORDER MOV (SP)+,R0 ; RESTORE R0 RETURN ; ;+ ; *** MLTPLY -- MULTIPLY A DOUBLE PRECISION NUMBER BY THE NUMBER ; CONTAINED IN R0 AND REPLACE THE NUMBER. ; ; INPUTS: ; R0 MULTIPLIER ; R4 POINTS TO DOUBLE PRECISION MULTIPLICAND ; ; OUTPUT: ; R0,R4,R5 PRESERVED ; R1,R2,R3 USED AND MODIFIED ; C=0 NO OVERFLOW ; C=1 OVERFLOW OCCURRED ; ;- MLTPLY: MOV R0,-(SP) ; SAVE MULTIPLIER ON STACK MOV (R4)+,R2 ; GET HIGH ORDER NUMBER MOV (R4),R3 ; AND LOW ORDER CALL $DMUL ; DO THE MULTIPLY MOV R1,(R4) ; REPLACE LOW ORDER WITH RESULT MOV R0,-(R4) ; AND HIGH ORDER BMI 5$ ; IF MI, OVERFLOW CLC ; SET OK BR 6$ ; RETURN 5$: SEC ; OVERFLOW 6$: MOV (SP)+,R0 ; RESTORE MULTIPLIER RETURN ; .ENDC ; DF AA$USE .END $USEEP