.SBTTL DATA AREA .TITLE TSKLOG .IDENT /03.2/ ; ; G.A. BASSETT 5-MAY-77 ; ; MODIFIED: ; J. DOWNWARD 13-MAR-79 MAKE COMPATABLE WITH BL25 V3.2 ; MEMRORY MANAGEMENT ONLY. ; ACCOUNT LOGGING TASK ; ; ASSEMBLY PARAMETERS ; ; THE SYMBOL "$$CVEC" SHOULD BE SET EQUAL TO THE SYSTEM CLOCK ; INTERRUPT VECTOR ADDRESS. THE STANDARD ADDRESSES FOLLOW: ; ; KW-11L LINE FREQUENCY CLOCK 100 ; KW-11P PROGRAMMABLE CLOCK 104 ; $$CVEC=104 ; STANDARD LINE FREQUENCY CLOCK $$TKPS=100. ; CLOCK INTERRUPTS PER SECOND $$STAT=0 ; ACCUMULATE SYSTEM STATISTICS ( IF DF ) ;$$FILE=0 ; OUTPUT INFO. TO A FILE. LUN #1 ( IF DF ) .MCALL QIOW$C,QIOW$,DIR$,EXIT$S,GTIM$C .MCALL PKTDF$,TCBDF$,HWDDF$ PKTDF$ ; DEFINE PACKET OFFSETS TCBDF$ ; DEFINE TCB OFFSETS HWDDF$ ; DEFINE HARDWARE .IF DF $$FILE .MCALL FSRSZ$,FDBDF$,FDAT$A,FDOP$A,NMBLK$ .MCALL OPEN$W,CLOSE$,PUT$ .ENDC ; ; ACCOUNTING DATA STRUCTURES ; BLKSIZ=24 ; ACCOUNTING DATA BLOCK SIZE ; CODNOD: .WORD 0 ; CODE NODE ADDRESS ; IOST: .BLKW 2 ; I/O STATUS BLOCK ; NODADD: .WORD 0 ; NODE ADDRESS TO REPORT ON ; TSKLST: .BLKW 25. ; TASK TCB LIST ; TSKCNT: .WORD 0 ; # OF TASKS IN TSKLST ; INPBUF: .BLKB 20. ; INPUT BUFFER ; TSKR50: .BLKW 2 ; TEMP. BUFFER ; ERROR: .WORD 0 ; ALLOCATION FAILURE ERROR SWITCH ; MACRO DEFINITIONS .MACRO PRINT STRING MOV #STRING,R0 CALL PNTLIN .ENDM PRINT .MACRO OUTPUT STRING .IF DF $$FILE MOV #STRING,R0 CALL OUTLIN .IFF ; $$FILE PRINT STRING .ENDC ; $$FILE .ENDM OUTPUT .IF DF $$FILE FSRSZ$ 1 ; ONE RECORD BUFFER ACCFDB: FDBDF$ ; DEFINE AN FDB FDAT$A R.VAR,FD.CR!FD.BLK ; GIVE THE FILE SOME ATTRIBUTES FDOP$A 1,,ACCNAM ; AND A NAME ACCNAM: NMBLK$ ACCOUNT,DAT ; THIS NAME! .IFTF ; $$FILE .PAGE .SBTTL ACCOUNTING INITALIZATION CODE .ENABL LSB START: ; REF. LABEL TST $ACMSK ; IS CPU ACCOUNTING(SYSLOG) ACTIVE BEQ 1$ ; IF EQ, NO, CONTINUE PRINT M18 ; WARN USER, SYSLOG MUST BE STOPPED FIRST EXIT$S ; EXIT 1$: ; REF LABLE .IFT ; $$FILE OPEN$W #ACCFDB,,,,,,OPNERR ; OPEN THE OUTPUT FILE .IFTF ; $$FILE CLR ERROR ; CLEAR ERROR INDICATOR CLR TSKCNT ; CLEAR NUMBER OF TASKS REQUESTED MOV #TSKLST,R5 ; GET TCB LIST ADDRESS CLR INPBUF ; CLEAR THE INPUT BUFFER CLR INPBUF+2 CLR INPBUF+4 CALL $LOCKL ; LOCK THE LISTS 10$: QIOW$C IO.RPR,2,2,,IOST,, BCS 13$ ; IF QIO FAILS TSTB IOST ; WAS READ SUCCESSFUL? BPL 15$ ; YES. CONTINUE WITH CHECK 13$: JMP DEVERR ; JMP TO DEVICE ERROR 15$: TST IOST+2 ; IS THIS A NULL LINE? BEQ 30$ ; YES. NO MORE TASK NAMES MOV #INPBUF,R0 ; GET INPUT BUFFER ADDRESS CALL $CAT5 ; CONVERT TO RADIX 50 MOV #TSKR50,R4 ; GET BUFFER ADDRESS TO STORE R50 NAME MOV R1,(R4) ; STORE FIRST 3 CHARS. CALL $CAT5 ; CONVERT NEXT 3 MOV R1,2(R4) ; AND STORE THEM MOV R4,R3 ; COPY R50 BUFFER ADDRESS CALL $SRSTD ; SCAN THE STD FOR A MATCH BCC 20$ ; GOT ONE! PRINT M2 ; PRINT TASK NOT INSTALLED BR 10$ ; TRY AGAIN 20$: MOV R0,(R5)+ ; STORE TCB ADDRESS AWAY INC TSKCNT ; COUNT THIS TCB BR 10$ ; GET ANOTHER ONE 30$: TST TSKCNT ; ANY TASKS TO ACCOUNT BNE 35$ ; YES. BEGIN JMP 106$ ; NO. EXIT 35$: ; REF. LABEL .IF NDF M$$MGE MOV #CODST,CODNOD ; ASSUME NO NODE NEEDED MOV $TKTCB,R5 ; GET OUR TCB ADDRESS BIT #T2.CHK,T.ST2(R5) ; ARE WE CHECKPOINTABLE? BNE 50$ ; IF NO, THEN NO NODE NEEDED .ENDC ; NDF M$$MGE CLR CODNOD ; CLEAR FLAG TO STORE CODE NODE MOV #CODSIZ,R1 ; GET CODE SIZE CALL $SWSTK,50$ ; SWITCH TO SYSTEM STATE CALL $ALOCB ;; ALLOCATE THE CODE BLOCK FROM DSR BCS 40$ ;; IF UNABLE THEN LEAVE FLAG 0 MOV R0,CODNOD ;; STORE NODE ADDRESS 40$: RETURN ;; EXIT FROM SYSTEM STATE 50$: MOV CODNOD,R5 ; GET NODE ADDRESS MOV R5,R0 ; COPY TO R0 BNE 55$ ; IF .NE. 0 THEN WE GOT ONE INC ERROR ; INDICATE AN ERROR HAS OCCURRED JMP 106$ ; ALLOCATION FAILURE 55$: MOV #CODSIZ,R1 ; GET TOTAL CODE SIZE INC R1 ; ROUND UP TO WORD BOUNDARY ASR R1 ; CONVERT TO WORDS MOV #CODST,R2 ; GET CODE STARTING ADDRESS 60$: MOV (R2)+,(R0)+ ; STORE WORD DEC R1 ; ANY MORE TO TRANSFER? BNE 60$ ; YES. CONTINUE MOV $TKTCB,ACCPTR-CODST(R5) ; SAVE TSKLOG TCB ADDRESS ; ; SET UP CLOCK INTERRUPT VECTOR ; BIS #340,PS ; RAISE PRIORITY TO 7 MOV R5,@#$$CVEC ;;; STORE NODE ADDRESS IN VECTOR ADD #TIMINT-CODST,@#$$CVEC ;;; ADD OFFSET TO TIME ISR MOV #341,@#$$CVEC+2 ;;; SET NEW PS (WITH C BIT SET) CLRB PS ;;; DROP PRIORITY TO ZERO ; ; INSERT INTERCEPTS INTO THE EXEC ; CLR ERROR ; CLEAR ALLOCATION ERROR SWITCH MOV #ADDTAB,R1 ; GET ADDRESS OF INTERC. ADDRESS TABLE MOV #OFFTAB,R2 ; GET NODE OFFSETS TABLE ADDRESS MOV #4,R3 ; GET # OF INTERCEPTS MOV #4737,R4 ; PUT A "JSR PC" INTO R4 CALL $SWSTK,75$ ; SWITCH TO SYSTEM STATE 65$: MOV (R1)+,R0 ;; GET INTERCEPT ADDRESS MOV R4,(R0)+ ;; PUT A "JSR PC" THERE MOV R5,(R0) ;; PLACE NODE ADDRESS IN THERE ADD (R2)+,(R0) ;; ADD OFFSET INTO NODE DEC R3 ;; ARE WE DONE YET? BNE 65$ ;; NO. CONTINUE ON ; ; ALLOCATE CONTROL BLOCK FOR EACH TASK REQUESTED ; ADD #ACCHD-CODST,R5 ;; POINT R5 TO ACCOUNT LISTHEAD MOV R5,R4 ;; COPY IT TO R4 MOV R4,2(R4) ;; SET UP LISTHEAD ADDRESS MOV #TSKLST,R4 ;; GET POINTER TO TCB LIST 70$: MOV #BLKSIZ,R1 ;; GET CONTROL BLOCK SIZE CALL $ALOCB ;; ALLOCATE A BLOCK FROM DSR BCS ALLERR ;; IF FAILURE THEN CLEANUP MOV (R4)+,2(R0) ;; STORE NEXT TCB ADDRESS IN PACKET MOV R0,R1 ;; MOVE BLOCK ADDRESS INTO R1 MOV R5,R0 ;; GET LISTHEAD ADDRESS CALL $QINSF ;; INSERT INTO ACCOUNTING LIST DEC TSKCNT ;; ANY MORE TO ACCOUNT FOR? BNE 70$ ;; YUP. WE'ED BETTER CONTINUE RETURN ;; EXIT FROM SYSTEM STATE ALLERR: INC ERROR ;; INDICATE AN ERROR HAS OCCURED RETURN ;; EXIT FROM SYSTEM STATE .PAGE .SBTTL TASK ACCOUNTING CODE ; ; NOW WE GO TO SLEEP AND WAIT FOR A TASK TO EXIT, AT WHICH TIME ; THE STOP CODE (IN THE NODE) WILL QUEUE IT TO OUR ; RECEIVE QUEUE AND START US BACK UP AGAIN. ; 75$: CALL $UNLKL ; UNLOCK THE SYSTEM LISTS TST ERROR ; DID AN ERROR OCCUR? BEQ 80$ ; NO. CONTINUE JMP 105$ ; YES. PRINT, CLEAN UP AND EXIT 80$: MOV $TKTCB,R0 ; GET OUR TCB ADDRESS ADD #T.RCVL,R0 ; POINT R0 TO OUR RECEIVE LISTHEAD CLR NODADD ; CLEAR THE NODE FOUND SWITCH CALL $SWSTK,100$ ; SWITCH TO SYSTEM STATE CALL $QRMVF ;; REMOVE ENTRY FROM RECEIVE LIST BCC 90$ ;; GOT ONE! REMEMBER IT CALLR $STPCT ;; NOTHING THERE. GO TO SLEEP....... 90$: MOV R1,NODADD ;; SAVE THE NODE ADDRESS RETURN ;; EXIT FROM SYSTEM STATE 100$: MOV NODADD,R5 ; DID WE GET ONE? BEQ 80$ ; NOPE. TRY AGAIN. BIT #1,2(R5) ; IS THIS AN EXIT NODE FROM ACCOFF? BNE EXIT ; YES. CLEANUP AND EXIT MOV R5,-(SP) ; STORE NODE ADDRESS FOR FUTURE USE MOV R5,$QIOCT+4 ;**** ; ; A TASK HAS EXITED. TAKE THE NODE GIVEN TO US AND PROCESS THE INFORMATION ; IN IT AND PRINT IT OUT. THEN RESTORE THE PACKET TO THE LIST ; AND ENABLE IT TO BE ACCOUNTED AGAIN. ; CALL $LOCKL ; LOCK THE SYSTEM LISTS MOV 2(R5),R0 ; PICK UP THE TCB ADDRESS MOV T.NAM(R0),R1 ; GET THE FIRST HALF OF THE TASK NAME MOV T.NAM+2(R0),-(SP) ; SAVE THE SECOND HALF FOR A LITTLE LATER CALL $UNLKL ; UNLOCK THE SYSTEM LISTS .IFF ; $$FILE DIR$ #ATTDPB ; ATTACH TO THE TERMINAL .IFTF ; $$FILE MOV #TNAME,R0 ; GET TASK NAME BUFFER ADDRESS CALL $C5TA ; CONVERT TO ASCII MOV (SP)+,R1 ; GET THE SECOND HALF OF THE NAME CALL $C5TA ; CONVERT IT TO ASCII GTIM$C INPBUF ; GET THE CURRENT TIME AND DATE MOV #INPBUF,R1 ; POINT TO THE DATE MOV #DATE,R0 ; GET OUTPUT STRING ADDRESS CALL $DAT ; CONVERT TO ASCII MOVB #' ,(R0)+ ; INSERT A SPACE MOV #4,R2 ; MAKE THE FORMAT "HH:MM:SS.S" CALL $TIM ; AND CONVERT THE TIME OUTPUT M3 ; OUTPUT TASK NAME MESSAGE OUTPUT M31 ; OUTPUT ELAPSED TIME HEADER MOV (SP),R0 ; GET NODE ADDRESS MOV 4(R0),R1 ; GET HIGH ORDER START TIME MOV 6(R0),R2 ; AND LOW ORDER CLR 4(R0) ;**** CLR 6(R0) ;**** CALL PRNTIM ; PRINT ELAPSED TIME OUTPUT M8 ; OUTPUT CPU HEADER MESSAGE MOV (SP),R0 ; RESTORE NODE ADDRESS MOV 14(R0),R1 ; GET HIGH ORDER CPU TIME MOV 16(R0),R2 ; AND LOW ORDER CLR 10(R0) ;**** CLR 12(R0) ;**** CLR 14(R0) ;**** CLR 16(R0) ;**** CALL PRNTIM ; AND PRINT IT MOV (SP)+,R1 ; RESTORE NODE ADDRESS ONE LAST TIME ADD #20,R1 ; POINT R1 TO NUMBER OF QIO'S MOV #QIOS,R0 ; POINT R0 TO RIGHT PLACE IN BUFFER CLR R2 ; SUPPRESS ZERO'S CALL $CDDMG ; CONVERT TO D.P. ASCII MOVB #'.,(R0)+ ; END IT WITH PERIOD CLRB (R0) ; MAKE IT ASCIZ OUTPUT M9 ; AND OUTPUT IT .IFF ; $$FILE DIR$ #DETDPB ; DETACH THE TERMINAL .ENDC ; $$FILE ; ; REPLACE NODE INTO ACCOUNTING LIST ; CALL $SWSTK,80$ ; SWITCH TO SYSTEM STATE MOV NODADD,R1 ;; GET NODE ADDRESS MOV CODNOD,R0 ;; POINT TO CODE NODE ADDRESS ADD #ACCHD-CODST,R0 ;; POINT TO ACCOUNTING LISTHEAD CALLR $QINSF ;; INSERT INTO QUEUE AND RETURN .PAGE .SBTTL ACCOUNTING RUNDOWN CODE ; ; THIS CODE WILL DEALLOCATE ALL NODES TO THE POOL, ; PRINT SYSTEM STATISTICS, AND ; WILL EXIT TSKLOG. ; EXIT: ; REF. LABEL .IF DF $$STAT MOV CODNOD,R0 ; PUT CODE ADDRESS IN R0 ADD #TIME-CODST,R0 ; POINT IT TO INFO MOV #INPBUF,R4 ; PUT DATA BUFFER ADDRESS INTO R4 MOV R4,R1 ; POINT R1 TO NUMBERS MOV #10,R2 ; GET NUMBER OF NUMBERS TO COPY BIS #340,PS ; RAISE THE PRIORITY TO 7 102$: MOV (R0)+,(R1)+ ;;; COPY THE TIMES DEC R2 ;;; DONE? BNE 102$ ;;; NOPE. KEEP GOING CLRB PS ;;; DROP IT BACK DOWN .IF NDF $$FILE DIR$ #ATTDPB ; ATTACH TO THE TERMINAL .IFTF ; NDF $$FILE MOV R4,R0 ; GET POINTER TO TIME ADD #4,R0 ; POINT R0 TO FIRST STATISTIC MOV #USRTIC,R3 ; GET OUTPUT BUFFER POINTER CALL PERPNT ; PRINT PERCENTAGE OUTPUT M13 ; OUTPUT USER PERCENT MOV R4,R0 ; GET INFO ADDRESS ADD #10,R0 ; POINT TO KERNEL INFO MOV #KNLTIC,R3 ; OUTPUT BUFFER ADDRESS CALL PERPNT ; PRINT KERNEL PERCENTAGE OUTPUT M14 ; AND OUTPUT MOV R4,R0 ; GET INFO POINTER ADD #14,R0 ; POINT TO NULL TIME MOV #NULTIC,R3 ; OUTPUT POINTER CALL PERPNT ; PRINT PERCENTAGE OF NULL TIME OUTPUT M15 ; OUTPUT IT 104$: ; REF LABEL .IFT ; NDF $$FILE DIR$ #DETDPB ; DETACH THE TERMINAL .ENDC ; $$FILE .ENDC ; $$STAT MOV R5,R0 ; COPY NODE ADDRESS MOV #BLKSIZ,R1 ; GET EXIT NODE SIZE CALL $SWSTK,105$ ; SWITCH TO SYSTEM STATE CALLR $DEACB ;; RETURN IT TO THE POOL 105$: CALL CLEAN ; RETURN ALL NODES TO THE POOL 106$: TST ERROR ; IS THIS AN ERROR CONDITION? BEQ 107$ ; NO. SKIP ERROR MESSAGE PRINT M10 ; ALLOCATION FAILURE 107$: ; REF. LABEL .IF DF $$FILE CLOSE$ #ACCFDB ; CLOSE THE ACCOUNT FILE .IFTF ; $$FILE PRINT M12 ; PRINT TASK EXITING MESSAGE EXIT$S ; AND DO IT ; ; INPUT DEVICE ERROR ; DEVERR: PRINT M11 ; PRINT DEVICE ERROR MESSAGE BR 107$ ; AND EXIT .IFT ; $$FILE ; ; OPEN ERROR ON OUTPUT FILE ; OPNERR: PRINT M16 ; PRINT OPEN FAILURE BR 107$ ; AND EXIT ; ; PUT ERROR ON OUTPUT FILE ; PUTERR: PRINT M17 ; PRINT PUT FAILURE BR 105$ ; AND EXIT .IFTF ; $$FILE .PAGE .SBTTL RUNDOWN CLEAN UP ROUTINE ; ; THIS ROUTINE WILL CLEAN UP ALL THE NODES AND RETURN THEM TO THE POOL ; CLEAN: MOV #ADDTAB,R0 ; GET INTERCEPT ADDRESS TABLE MOV #INTTAB,R1 ; GET INTERCEPT INSTRUCTION TABLE MOV #4,R2 ; GET COUNTER CALL $SWSTK,125$ ; SWITCH TO SYSTEM STATE 108$: MOV (R0)+,R3 ;; GET INTERCEPT ADDRESS MOV (R1)+,(R3)+ ;; MOVE FIRST WORD OF INSTRUCTION MOV (R1)+,(R3) ;; " SECOND " " " DEC R2 ;; IS THIS THE LAST INTERCEPT? BNE 108$ ;; NO. CONTINUE MOV #$CKINT,@#$$CVEC ;;; RESTORE CLOCK INTERRUPT SERVICE ROUTINE MOV CODNOD,R5 ;; GET CODE NODE ADDRESS MOV R5,R4 ;; SAVE IT IN R4 ADD #ACCHD-CODST,R4 ;; POINT IT TO THE LISTHEAD CALL REMOVE ;; REMOVE ALL ENTRIES MOV $TKTCB,R4 ;; GET OUR TCB ADDRESS ADD #T.RCVL,R4 ;; POINT IT TO OUR RECEIVE QUEUE CALL REMOVE ;; REMOVE ALL ENTRIES .IF NDF M$$MGE CMP #CODST,R5 ;; IS THIS CODE IN A NODE? BEQ 125$ ;; NO. DON'T RETURN IT .ENDC ;; NDF M$$MGE MOV R5,R0 ;; RETRIEVE THE NODE ADDRESS MOV #CODSIZ,R1 ;; GET THE SIZE OF IT CALLR $DEACB ;; AND RETURN IT TO THE POOL 125$: RETURN ; ; THIS ROUTINE REMOVES ALL ENTRIES FROM A PARTICULAR QUEUE ; REMOVE: MOV R4,R0 ;; GET LISTHEAD ADDRESS CALL $QRMVF ;; REMOVE AN ENTRY BCS 125$ ;; IF NONE, THEN RETURN MOV R1,R0 ;; COPY ENTRY ADDRESS TO R0 MOV #BLKSIZ,R1 ;; GET SIZE OF ENTRY CALL $DEACB ;; RETURN IT TO THE POOL BR REMOVE ;; KEEP GOING ; ; INTERCEPT ADDRESS TABLE ; ADDTAB: .WORD $TSKRT+STOFF ; START TASK TIME INTERCEPT(IN REQSB) .WORD $CEXIT ; STOP TASK TIME INTERCEPT(IN DREIF) .WORD $NONSI+CSOFF ; CONTEXT SWITCH INTERCEPT .WORD $IOFIN ; I/O COUNT INTERCEPT ; ; INTERCEPT INSTRUCTION TABLE ; INTTAB: BIC (SP),(R3)+ CLR (SP) CALL @#$DRCMT MOV R5,@#$TKTCB MOV I.IOSB+4(R3),R2 ; ; CODE OFFSETS IN NODE ; OFFTAB: .WORD SETSTT-CODST ; START TASK INTERCEPT .WORD STPTIM-CODST ; STOP TASK INTERCEPT .WORD CNTSW-CODST ; CONTEXT SWITCH INTERCEPT .WORD CNTQIO-CODST ; COUNT QIO'S INTERCEPT .PAGE .SBTTL PRINTING ROUTINES ; ; THIS ROUTINE WILL PRINT THE TIME ON THE TERMINAL ; AND SUPPRESS ANY ZERO VALUES ; ; INPUTS: ; ; R1 - HIGH ORDER TIME ; R2 - LOW ORDER TIME ; PRNTIM: MOV #$$TKPS,R0 ; GET TICKS/SECOND CALL $DDIV ; DO D.P. DIVIDE MOV R0,-(SP) ; STORE IT MOV #60.,R0 ; GET SECONDS/MINUTE CALL $DDIV ; DO DIVIDE MOV R0,-(SP) ; STORE # OF SECONDS MOV #60.,R0 ; GET MINUTES/HOUR CALL $DDIV ; DO DIVIDE MOV R0,-(SP) ; STORE # OF MINUTES MOV R2,R1 ; COPY HOURS TO R1 BEQ 130$ ; IF NO HOURS THEN SKIP MOV #HOURS,R0 ; GET ADDRESS FOR HOURS CALL CNVT ; CONVERT OUTPUT M4 ; OUTPUT HOURS: NNN 130$: MOV (SP)+,R1 ; GET MINUTES BEQ 140$ ; IF NONE, THEN SKIP MOV #MINS,R0 ; GET BUFFER ADDRSS CALL CNVT ; CONVERT OUTPUT M5 ; OUTPUT MINUTES: 140$: MOV (SP)+,R1 ; GET NUMBER OF SECONDS BEQ 150$ ; IS NONE THEN SKIP MOV #SECNDS,R0 ; GET BUFFER ADDRESS CALL CNVT ; CONVERT OUTPUT M6 ; OUTPUT SECONDS: 150$: MOV (SP)+,R1 ; GET TICKS MOV #TICKS,R0 ; BUFFER ADDRESS CALL CNVT ; CONVERT OUTPUT M7 ; OUTPUT TICKS: 160$: RETURN ; ; THIS ROUTINE WILL CONVERT A NUMBER, ADD A '.' AND MAKE IT ASCIZ ; CNVT: CLR R2 ; SUPPRESS ZEROES CALL $CBDMG ; CONVERT TO ASCII MOVB #'.,(R0)+ ; ADD A '.' CLRB (R0) ; MAKE IT ASCIZ RETURN ; AND RETURN ; ; THIS ROUTINE WILL PRINT AN ASCIZ LINE ; PNTLIN: MOV #-1,R1 ; GET COUNT INITIALIZED MOV R0,QIODPB+Q.IOPL ; STORE BUFFER ADDRESS 170$: INC R1 ; INCREMENT COUNTER TSTB (R0)+ ; IS THIS THE LAST BYTE? BNE 170$ ; NO. KEEP GOING MOV R1,QIODPB+Q.IOPL+2 ; STORE BYTE COUNT DIR$ #QIODPB RETURN ; ; THIS ROUTINE WILL OUTPUT A LINE TO THE OUTPUT DEVICE (ONLY NESS. ; WHEN $$FILE IS DEFINED) . ; .IFT ; $$FILE OUTLIN: MOV #-1,R1 ; SETUP COUNT MOV R0,R2 ; COPY BUFFER POINTER 175$: INC R1 ; INCREMENT COUNTER TSTB (R0)+ ; IS THIS THE LAST BYTE? BNE 175$ ; NO. KEEP COUNTING PUT$ #ACCFDB,R2,R1,PUTERR RETURN ; RETURN TO USER .ENDC ; ; THIS ROUTINE WILL FORMAT THE TIME POINTED TO BY R0 ; INTO THE FOLLOWING FORMAT: ; ; XX.X% ; .IF DF $$STAT PERPNT: MOV R3,-(SP) ; SAVE BUFFER ADDRESS ON THE STACK MOV (R0)+,R2 ; GET HIGH ORDER NUMBER MOV (R0),R3 ; GET LOW ORDER MOV #1000.,R0 ; GET SCALE FACTOR CALL $DMUL ; AND MULTIPLY MOV R1,R2 ; GET THE INFO WHERE IT BELONGS MOV R0,R1 ; BMI 190$ ; IF < 0 , THEN AN OVERFLOW OCCURED MOV 2(R4),R0 ; GET LOW ORDER TOTAL TIME MOV (R4),-(SP) ; PUT HIGH ORDER TIME ON STACK 176$: TST (SP) ; IS THERE ANY HIGH ORDER TIME LEFT? BNE 177$ ; YES. CONTINUE SCALING TST R0 ; IS THE LOW ORDER UNSIGNED YET? BPL 180$ ; YES. DO IT! 177$: ASR R1 ; DIVIDE HIGH ORDER BY 2 ROR R2 ; AND CONTINUE WITH LOW ORDER ASR (SP) ; SHIFT HIGH ORDER TOTAL ALSO ROR R0 ; AND LOW ORDER BR 176$ ; DO THE TEST. 180$: TST (SP)+ ; CLEAN THE STACK AND CONTINUE CALL $DDIV ; DO D.P. DIVIDE MOV R2,R1 ; GET RESULT (PERCENT * 10.) CLR R2 ; SUPPRESS ZEROES MOV (SP)+,R0 ; GET OUTPUT BUFFER POINTER CALL $CBDMG ; CONVERT TO ASCII MOVB -(R0),1(R0) ; MOVE LAST BYTE OVER TO MAKE ROOM MOVB #'.,(R0)+ ; PUT IN A DECIMAL POINT INC R0 ; STEP PAST LAST NUMBER MOVB #'%,(R0)+ ; MAKE IT A PERCENT CLRB (R0) ; AND ASCIZ RETURN ; AND RETURN 190$: PRINT M151 ; PRINT OVER FLOW ERROR TST (SP)+ ; CLEAN THE STACK JMP 104$ ; AND CONTINUE .IFTF ; $$STAT .PAGE .SBTTL INTERCEPT CODE (IN THE NODE) ; ; START OF INTERCEPT CODE. ; CODST=. ; ; THIS IS THE CODE TO INTERCEPT A TASK REQUEST. THE FOLLOWING ; THINGS ARE DONE: ; ; 1. SEE IF THE TASK BEING REQUESTED IS IN THE ACCOUNT LIST. ; ; 2. IF YES, THEN INIT. ALL ACCUM. TIMES AND SET START TIME. ; ; 3. RESTORE REGISTERS, EXECUTE THE INTERCEPTED INSTRUCTION, AND RETURN ; SETSTT: MOV R0,-(SP) ; SAVE R0 MOV R1,-(SP) ; SAVE R1 MOV R2,-(SP) ; SAVE R2 CALL MATCH ; LOOK FOR A MATCHING TCB ADDRESS BEQ OUT1 ; IF = 0, THEN NO MATCH ADD #4,R1 ; POINT TO START TIME LOCATION BIS #340,@#PS ; RAISE PRIORITY TO 7 MOV TIME,(R1)+ ;;; SET HIGH ORDER TIME MOV TIME+2,(R1)+ ;;; SET LOW ORDER TIME CLRB @#PS ;;; DROP PRIORITY TO 0 .REPT 4 CLR (R1)+ ; CLEAR INITITIAL TIMES .ENDR .REPT 2 CLR (R1)+ ; RESET QIO COUNTERS .ENDR OUT1: MOV (SP)+,R2 ; RESTORE R2 MOV (SP)+,R1 ; RESTORE R1 MOV (SP)+,R0 ; RESTORE R0 BIC 2(SP),(R3)+ ;*INTERCEPTED INSTRUCTION CLR 2(SP) ;*INTERCEPTED INSTRUCTION RETURN ; RETURN TO NORMAL CODE ; ; THIS INTERCEPT CODE IS ENTERED WHEN A TASK EXITS. ; IT DOES THE FOLLOWING: ; ; 1. CHECKS FOR A MATCHING TCB ADDRESS ; ; 2. ADDS IN THE REMAINING CPU TIME ; ; 3. CALCULATES THE TOTAL RUN TIME ; ; 4. REMOVES ENTRY FORM ACCOUNTING LIST ; ; 5. QUEUES ENTRY TO TSKLOG'S RECEIVE LIST AND STARTS IT ; STPTIM: MOV R5,-(SP) ; SAVE R5 MOV R5,R0 ; COPY TCB ADDRESS CALL MATCH ; IS THERE A MATCH? BEQ OUT2 ; NOPE. FORGET IT CALL 203$ ; ADD IN REMAINING CPU TIME BIS #340,@#PS ; RAISE PRIORITY TO 7 MOV TIME,-(SP) ;;; SAVE HIGH ORDER TIME MOV TIME+2,R0 ;;; PICK UP LOW ORDER TIME CLRB @#PS ;;; AND DROP PRIORITY SUB 6(R1),R0 ; SUBTRACT LOW ORDER TIME SBC (SP) ; AND DON'T FORGET THE CARRY MOV R0,6(R1) ; STORE FINAL TIME SUB 4(R1),(SP) ; SUBTRACT HIGH ORDER TIME MOV (SP)+,4(R1) ; STORE FINAL TIME MOV (R1),(R2) ; CLOSE UP LIST BNE 200$ ; IF NOT AT END THEN CONTINUE MOV R2,ACCHD+2 ; AT END SO CORRECT POINTER 200$: MOV ACCPTR,R0 ; GET TSKLOG TCB ADDRESS CALL @#$EXRQF ; QUEUE NODE AND START TSKLOG OUT2: MOV (SP)+,R5 ; RESTORE R5 CALLR @#$DRCMT ;*INTERCEPTED INSTRUCTION ; ; THIS CODE INTERCEPTS A CONTEXT SWITCH. A CHECK IS DONE ON BOTH ; THE OLD AND THE NEW TASK. ; ; 1. IF OLD TASK MATCHES, THEN THE ELAPSED CPU TIME ; IS CALCULATED. ; ; 2. IF NEW TASK MATCHES, THEN THE START TIME IS PLACED ; IN THE START CPU TIME SLOT ; CNTSW: MOV R0,-(SP) ; SAVE R0 MOV @#$TKTCB,R0 ; GET CURRENT TCB ADDRESS CALL MATCH ; IS IT A MATCH? BEQ CONT1 ; NO. SO CONTINUE AND TRY THE NEW ONE CALL 203$ ; ADD IN CPU TIME ; ; NOW CHECK THE NEW TASK FOR A MATCH ; CONT1: MOV R5,R0 ; COPY NEW TCB ADDRESS TO R0 CALL MATCH ; IS IT A MATCH? BEQ CONT2 ; NOPE. OH WELL. BIS #340,@#PS ; RAISE PRIORITY TO 7 MOV TIME,10(R1) ;;; STORE HIGH ORDER TIME MOV TIME+2,12(R1) ;;; AND LOW ORDER TIME CLRB @#PS ;;; AND DROP IT AGAIN CONT2: MOV (SP)+,R0 ; RESTORE R0 MOV R5,@#$TKTCB ;*INTERCEPTED INSTRUCTION RETURN ; BACK TO NORMAL CODE ; ; THIS ROUTINE CALCULATES THE ELAPSED CPU TIME ; 203$: BIS #340,@#PS ; SET PRIORITY TO 7 MOV TIME,-(SP) ;;; STORE HIGH ORDER TIME MOV TIME+2,R0 ;;; AND GET LOW ORDER CLRB @#PS ;;; AND DROP PRIORITY SUB 12(R1),R0 ; CALCULATE ELAPSED CPU TIME (LOW) SBC (SP) ; AND REMEMBER THE CARRY ADD R0,16(R1) ; ADD IT TO TOTAL ADC 14(R1) ; AND THE CARRY SUB 10(R1),(SP) ; THE HIGH ORDER ADD (SP)+,14(R1) ; ADD IN THE HIGH ORDER RETURN ; AND RETURN ; ; THIS CODE COUNT THE NUMBER OF QIO'S FINISHED FOR THE TASKS ; CNTQIO: MOV R0,-(SP) ; SAVE R0 MOV R1,-(SP) ; SAVE R1 MOV I.TCB(R3),R0 ; PICK UP TCB ADDRESS FROM I/O PACKET CALL MATCH ; IS IT A MATCH? BEQ OUT3 ; NO. CONTINUE NORMALLY ADD #1,22(R1) ; ADD ONE TO COUNT (ADD BECAUSE C BIT) ADC 20(R1) ; AND DON'T FORGET THE CARRY OUT3: MOV (SP)+,R1 ; RESTORE R1 MOV (SP)+,R0 ; RESTORE R0 MOV I.IOSB+4(R3),R2 ;*INTERCEPTED INSTRUCTION RETURN ; AND BACK TO NORMAL CODE ; ; THIS THE CLOCK ISR. IT MERELY KEEP COUNT IN TICKS AND CONTINUES ; TIMINT: ADC TIME+2 ;;; COUNT LOW ORDER (C BIT MUST BE SET) ADC TIME ;;; AND DON'T FORGET THE CARRY .IFT ;;; $$STAT ; BIT #PMODE,@#PS ;;; DID WE COME FROM THE EXEC? ; BNE 205$ ;;; NO. COUNT THE TIME AS USER TIME ; JGD ; TSTB $CURPR ;;; IS THIS NULL TASK(CURRENT PRIORITY=0) ; JGD ; BGT 2045$ ;;; NO, JUST NORMAL EXEC TIME ; JGD ; ADD #1,NULTIM+2 ;;; YES, COUNT AS NULL TIME ; JGD ; ADC NULTIM ;;; ; JGD ; BR 207$ ;;; AND EXIT ; JGD ;2045$: ; ADD #1,KNLTIM+2 ;;; YES. COUNT IT AS KERNEL TIME ; JGD ; ADC KNLTIM ;;; AND HIGH ORDER ; BR 207$ ;;; CONTINUE ;205$: ADD #1,USRTIM+2 ;;; COUNT USER TIME ; ADC USRTIM ;;; AND HIGH ORDER CMP #$HEADR,@#$RQSCH ;;; ARE WE POINTING AT THE NULL TASK BEQ 205$ ;;; IF EQ, YES BIT #PMODE,@#PS ;;; DID WE COME FROM THE EXEC? BEQ 206$ ;;; IF EQ, YES, COUNT AS KERNAL TIME ADD #1,USRTIM+2 ;;; COUNT USER TIME ADC USRTIM ;;; AND HIGH ORDER BR 207$ ;;; GO AND RETURN 205$: ADD #1,NULTIM+2 ;;; YES, COUNT AS NULL TIME ADC NULTIM ;;; AND HIGH ORDER PART BR 207$ ;;; AND EXIT 206$: ADD #1,KNLTIM+2 ;;; YES. COUNT IT AS KERNEL TIME ADC KNLTIM ;;; AND HIGH ORDER .IFTF ;;; $STAT 207$: JMP @#$CKINT ;;; JUMP TO CLOCK ISR IN TDSCH ; ; THIS ROUTINE SEARCHES FOR A MATCH IN THE ACCOUNTING LIST ; ; INPUTS: ; ; R0 -- CONTAINS TCB ADDRESS TO SCAN FOR ; ; OUTPUTS: ; ; Z=1 -- NO ENTRY FOUND ; ; Z=0 -- FOUND ENTRY ; R0 -- TCB ADDRESS ; R1 -- ACCOUNTING BLOCK ADDRESS ; R2 -- PREVIOUS ENTRY IN LIST ; MATCH: MOV PC,R2 ; GET CURRENT PC (BECAUSE WE ARE PIC CODE) ADD #ACCHD-MATCH-2,R2 ; CALCULATE ACTUAL ADDRESS 210$: MOV (R2),R1 ; GET NEXT ENTRY ADDRESS BEQ 230$ ; IF = 0, THEN NO MATCH CMP R0,2(R1) ; DOES THIS ONE MATCH? BEQ 220$ ; YES. GIVE IT BACK TO USER MOV R1,R2 ; NO. CONTINUE LOOKING BR 210$ ; TRY AGAIN 220$: CLZ ; LET USER KNOW THAT WE GOT ONE 230$: RETURN ; AND RETURN ; ; DATA BASES ; ACCHD: .WORD 0 ; ACCOUNTING LISTHEAD .WORD .-2 ; ACCPTR: .WORD 0 ; TSKLOG TCB ADDRESS ; TIME: .WORD 0,0 ; TIME FROM START OF TSKLOG .IFT ; $$STAT USRTIM: .WORD 0,0 ; USER TIME KNLTIM: .WORD 0,0 ; KERNEL TIME NULTIM: .WORD 0,0 ; NULL TIME .IFTF ; $$STAT ; ; END OF CODE (IN NODE) ; CODEN=. ; ; SIZE OF ALL CODE ; CODSIZ=CODEN-CODST .PAGE .SBTTL OFFSETS TO INTERCEPTS ; ; OFFSET IN REQSB FOR INTERCEPT ; .IF NDF M$$MUP STOFF=19.*2 .IFF STOFF=25.*2 .ENDC ; ; OFFSET IN SYSXT FOR INTERCEPT OFFSET ; CSOFF=11.*2 .IF DF L$$DRV&M$$MGE CSOFF=CSOFF+<4.*2> .IFTF CSOFF=CSOFF+<3.*2> .IFT CSOFF=CSOFF+<2*2> .ENDC CSOFF=CSOFF+<11.*2> .IF NDF M$$MGE CSOFF=CSOFF+<12.*2> ; THIS VALUE WRONG??? .ENDC CSOFF=CSOFF+<9.*2> .IF DF C$$CKP&T$$BUF!A$$TRP CSOFF=CSOFF+<9.*2> .IFTF CSOFF=CSOFF+<16.*2> .IF DF S$$TOP CSOFF=CSOFF+<10.*2> .ENDC ; S$$TOP CSOFF=CSOFF+<10.*2> .IF DF P$$P45 CSOFF=CSOFF+<10.*2> .ENDC CSOFF=CSOFF+<9.*2> .IF DF G$$EFN CSOFF=CSOFF+<2.*2> .ENDC ;G$$EFN CSOFF=CSOFF+<2.*2> .IF DF S$$TOP CSOFF=CSOFF+<4.*2> .ENDC ; S$$TOP .IFT CSOFF=CSOFF+<1*2> .ENDC CSOFF=CSOFF+<20.*2> .IF DF M$$MGE CSOFF=CSOFF+<6*2> .IFF .IF DF E$$EAE CSOFF=CSOFF+<9.*2> .ENDC .IFTF CSOFF=CSOFF+<2*2> .IF DF F$$LPP CSOFF=CSOFF+<3*2> .IF DF M$$MGE CSOFF=CSOFF+<7*2> .IF DF P$$LAS CSOFF=CSOFF+<3*2> .ENDC .ENDC CSOFF=CSOFF+<10.*2> .ENDC .ENDC ; ; END OF OFFSETS ; .PAGE .SBTTL TEXT MESSAGES QIODPB: QIOW$ IO.WVB,2,2,,,,<0,0,40> .IF NDF $$FILE ATTDPB: QIOW$ IO.ATT,2,2 DETDPB: QIOW$ IO.DET,2,2 .ENDC .NLIST BEX ; M1: .ASCII /ENTER TASK NAME: / M1S=.-M1 ; M2: .ASCIZ /TSKLOG -- TASK NOT INSTALLED/ M3: .ASCII <15>/*****************/<15><12> .ASCII /TASK NAME: / TNAME: .BLKB 6 .ASCII / TIME: / DATE: .BLKB 21. M31: .BYTE 12 .ASCIZ /TOTAL ELAPSED TIME/ ; M4: .ASCII /HOURS: / HOURS: .BLKB 6 ; M5: .ASCII /MINUTES: / MINS: .BLKB 4 ; M6: .ASCII /SECONDS: / SECNDS: .BLKB 4 ; M7: .ASCII /TICKS: / TICKS: .BLKB 4 ; M8: .ASCIZ <12>/TOTAL CPU TIME/ ; M9: .ASCII <12>/TOTAL QIO'S ISSUED: / QIOS: .BLKB 12. ; M10: .ASCIZ /TSKLOG -- MEMORY ALLOCATION FAILURE/ M11: .ASCIZ /TSKLOG -- INPUT ERROR/ M12: .ASCIZ /TSKLOG -- EXITING/ .IFT ; $$STAT M13: .ASCII <15>/*****************/<15><12> .ASCII /PERCENT USER TIME: / USRTIC: .BLKB 12. M14: .ASCII /PERCENT EXEC TIME: / KNLTIC: .BLKB 12. M15: .ASCII /PERCENT NULL TIME: / NULTIC: .BLKB 12. M151: .ASCIZ /TSKLOG -- STATISTICS OVERFLOW ERROR/ .ENDC ; $$STAT .IF DF $$FILE M16: .ASCIZ /TSKLOG -- OPEN FAILURE ON OUTPUT FILE/ M17: .ASCIZ /TSKLOG -- PUT FAILURE ON OUTPUT FILE/ .ENDC ; $$FILE M18: .ASCIZ /TSKLOG -- SYSTEM ACCOUNTING(SYSLOG) MUST FIRST BE DISABLED/ ; .LIST BEX ; .END START