.TITLE MON - RSX-11M/M+ ACTIVITY MONITOR .IDENT /01/ ;+ ;*-MON - RSX-11M/M+ SYSTEM MONITORING TASK ; ; THIS TASK MONITORS SYSTEM ACTIVITY BY SAMPLING WHAT IS HAPPENING ON ; A RSX11M/M+ SYSTEM AT A USER SPECIFIED RATE. ; ; RESTRICTIONS: ; ; 1). USES ABOUT 42. DISK BLOCKS/MINUTE WHEN THE MONITOR IS ACTIVE ; 2). THE MONITOR DOES USE MEMORY AND CPU TIME (APROX. 7KW) ; 3). THE MONITOR USES A SAMPLING METHOD TO GATHER STATISTICS ; ; A). TASKS THAT RUN AT A CLOCK INTERVAL MAY NOT HAVE ACCURATE STATISTICS ; B). TASKS THAT RUN FOR ONLY A SHORT PERIOD OF TIME MAY NOT GET SAMPLED ; C). THE MORE SAMPLES THE MONITOR TAKES THE MORE ACCURATE IT WILL BE ; ; ; COMMAND SWITCHES: ; ; /NOPC NO TASK PC EXECUTION TRACE ; /NOME NO MEMORY STATISTICS ; /NOIO NO I/O STATISTICS ; /NODR NO DIRECTIVE STATISTICS ; /NOAL NONE OF THE ABOVE ; ; EXAMPLE: MCR>MON /NOPC/NOIO ; ; ; INFORMATION IS GATHERED ON: ; ; 1). WHAT TASK IS RUNNING ; 2). WHERE THE TASK IS RUNNING (64. WORD RANGE) ; 3). IN IDLE LOOP ; 4). RSX11M IN EXECUTION ; 5). A RSX DIRECTIVE IS BEING EXECUTED ; 6). COUNTS ALL RSX DIRECTIVES ; 7). EVERY 1 SECOND IT COUNTS TASK IN/OUT OF MEMORY AND MEMORY USED ; 8). EXECUTING IN A DEVICE DRIVER ; 9). COUNTS OF I/O REQUESTS PER DEVICE ; ; ; MONITOR FLOW: ; ; 1). RELOCATE TASK TO LOW OR HIGH MEMORY TO MINIMIZE MEMORY FRAGMENTATION ; 2). INIT -- ALLOCATE THREE INTERRUPT CONNECT BLOCKS ; ; 1). TO A USER SPECIFED TIMER VECTOR. ; ; A). DL11 -- USE DL11 UART CLOCK AS A TIMER (CLOCK RATE IS BAUD/10.) ; * CAN NOT BE USED AS AN OUTPUT DEVICE DURING MONITOR EXECUTION ; B). KW11-L -- SYSTEM LINE CLOCK (50. OR 60. HERTZ) ; C). KW11-P -- PROGRAMMABLE CLOCK (USER RATE SELECTABLE) ; ; 2). TO THE EMT TRAP VECTOR ; 3). TO THE IOT TRAP VECTOR ; ; A). TO GET CONTROL WHEN AN I/O IS COMPLETE ; ; 3). CLOCK ISR. ; ; 1). IF $$SKIP DEFINED DISREGARD $$SKIP INTERRUPTS ; 2). COUNT ALL INTERRUPTS (TOTCNT) ; 3). WHERE WAS THE CPU EXECUTING ; ; A). IDLE LOOP -- INCREMENT IDLCT ; B). RSX11M OS ; ; 1). IF DIRECTIVE PROCESSING THEN COUNT FOR TASK WHICH WAS EXECUTING ; 2). EXECUTION WAS IN A DEVICE DRIVER ; 3). IF NOT THEN SAVE PC INTO QUEUE FOR EXEC WITH NAME ' ' ; ; C). A TASK -- SAVE TASK NAME AND PC INTO QUEUE ; ; 4). EMT ISR ; ; 1). WHERE DID EMT TRAP COME FROM ; ; A). NON EMT 377 THEN DISREGARD ; B). IF USER EMT 377 ; ; 1). INCREMENT COUNT IN DIRBUF FOR THE DIRECTIVE ; 2). SAVE PC OF USER IN DIRPC FOR USE BY CLOCK ISR ; ; 5). QIO DEVICE COUNTS (PER DEVICE) ; ; 1). COUNT OF ALL I/O TO A DEVICE TYPE (ex: DBn:) ; 2). COUNT OF I/O TO A SPECIFIC DEVICE (ex: DB2:) ; ; 6). DATA FILE WRITER (EVERY 1 SECOND) ; ; 1). REMOVE ELEMENTS FROM DATA QUEUE AND WRITE TO DISK ; 2). WHAT TASKS ARE IN/OUT OF MEMORY ; ; A). IN MEMORY ; ; 1). LOWEST NUMBER OF TASKS ; 2). HIGHEST NUMBER OF TASKS ; 3). AVERAGE NUMBER OF TASKS ; 4). AVERAGE AMOUNT OF MEMORY USED IN 1K WORD CHUNKS ; ; B). OUT OF MEMORY ; ; 1). LOWEST NUMBER OF TASKS ; 2). HIGHEST NUMBER OF TASKS ; 3). AVERAGE NUMBER OF TASKS ; 4). AVERAGE AMOUNT OF MEMORY USED IN 1K WORD CHUNKS ; ; C). FOR EACH TASK ; ; 1). TASK IN MEMORY ; 2). TASK OUT OF MEMORY ; 3). SIZE OF TASK ; ; 7). TASK EXIT (TASK ...STM SETS EVENT FLAG 34. TO MAKE MON EXIT) ; ; 1). RESTORE TRAP VECTORS FOR CLOCK AND EMT ; 2). CLOSE OUTPUT FILE ; 3). REQUEST REPORT GENERATOR TO RUN ; ; ; QUEUE FORMAT FOR SAVED TASK/EXEC DATA (CIRCULAR QUEUE) ; ; IPTR => NEXT AVAILABLE QUEUE ENTRY ; QUECNT = NUMBER OF ELEMENTS IN QUEUE (MAX OF MAXELE ENTRIES) ; QUEBEG = START OF QUEUE ; QUEEND = END OF QUEUE ; ; ENTRY: ; ; .RAD50 'TSKNAM' ; TASK NAME OR ' ' FOR EXEC ; .WORD PC ; SAVED PC (-1 IF SAMPLE DURING A DIRECTIVE) ; ; SAVED DATA ; ; TSKCNT: .WORD 1 ; COUNT OF ALL TASKS SAVE ; ; ALWAYS AT LEAST 1 FOR RSX11M ; TOTDIR: .WORD 0,0 ; COUNT OF DIRECTIVES ISSUED ; USRTRP: .WORD 0,0 ; INCREMENTED IF TASK WAS EXECUTING A ; ; DIRECTIVE WHEN CPU WAS INTERRUPTED ; TSKLST: .WORD 0 ; COUNT OF TASKS LOST BECAUSE OF ; ; INSUFFICANT TASK BUFFER SPACE ; ERRCNT: .WORD 0,0 ; COUNT OF INTERRUPTS LOST BECAUSE OF ; ; INSUFFICANT QUEUE SPACE ; IDLCT: .WORD 0,0 ; COUNT OF SAMPLES CPU WAS IN IDLE LOOP ; TOTCNT: .WORD 0,0 ; COUNT OF TOTAL NUMBER OF SAMPLES ; HOUR: .WORD ; TOTAL TIME MONITOR WAS RUNNING ; MIN: .WORD ; SEC: .WORD ; MEMLO: .WORD 0 ; LOW # OF TASKS IN MEMORY ; MEMHI: .WORD 0 ; HIGH # OF TASKS IN MEMORY ; MEMNO: .WORD 0,0 ; AVERAGE # OF TASKS IN MEMORY ; MEMSIZ: .WORD 0,0 ; AVERAGE MEMORY USED BY TASKS IN MEMORY ; CKPLO: .WORD 0 ; LOW # OF TASKS OUT OF MEMORY ; CKPHI: .WORD 0 : HIGH # OF TASKS OUT OF MEMORY ; CKPNO: .WORD 0,0 ; AVERAGE # OF TASKS OUT OF MEMORY ; CKPSIZ: .WORD 0,0 ; AVERAGE MEMORY USE OF OUT OF MEMORY TASKS ; MEMCNT: .WORD 0 ; COUNT OF MEMORY SAMPLES TAKEN ; MONCNT: .WORD 0,0 ; COUNT OF TIMES IN MONITOR ; SWMASK: .WORD 0 ; COMMAND SWITCH VALUES ; TSKBUF: .WORD 0,0,0,0,0,0,0,0 ; RSX11M INFORMATION SAVE AREA ; ; (SAME FOR TASKS AS WELL) ; .BLKW N ; FOR OTHER TASKS ; ; ; FORMAT FOR TASK DATA: ; ; .RAD50 'TSKNAM' ; TASK NAME IN RAD50 ; .BLKW 2 ; LINK TO PC PACKETS ; .BLKW 2 ; TASK SAMPLE COUNT ; .BLKW 2 ; TASK DIRECTIVE COUNT ; .BLKW 1 ; TASK IN MEMORY ; .BLKW 1 ; TASK OUT OF MEMORY ; .BLKW 1 ; TASK SIZE ; .BLKW 1 ; HASHING LINK ; ; PC PACKET FORMAT: ; ; .BLKW 2 ; POINTER TO NEXT PACKET ; .BLKW 1 ; PC OF TASK AT SAMPLE ; ; DEVICE TABLE FORMAT: ; ; DEVTOT: .WORD 0,0 ; COUNT OF TOTAL DRIVER SAMPLES ; DEVCNT: .WORD 0 ; NUMBER OF DEVICES ; QIOTOT: .WORD 0,0 ; TOTAL OF ALL QIOS ; DEVBUF: .ASCII 'DB' ; DEVICE NAME ; .WORD 2345 ; APR 5 OF DB DRIVER ; .WORD 2 ; 2 DB:s IN THE SYSTEM ; .WORD DBUNIT ; POINTER TO UNIT COUNTS ; .WORD 0 ; SAMPLES WHILE IN DEIVER - HIGH ; .WORD 0 ; LOW ; .WORD 0,0 ; TOTAL NUMBER OF QIOS ; . ; . ; . ; ; DBUNIT: .WORD 0,0 ; I/O COUNTS FOR DB0: ; .WORD 0,0 ; I/O COUNTS FOR DB1: ; ; ; *** MONITOR OPTIONS ; $$DL11 = 64 ; DEFINED TO USE DL11 VECTOR FOR CLOCK ; BY OUTPUTTING A CHARACTER WITH ; INTERRUPTS ENABLED ; EXAMPLE: LA36 300 BAUD INTERRUPTS ; AT 1/30 OF A SECOND .IF DF,$$DL11 ; GET CSR ADDRESS FOR DL11 $DLCSR = 177564 ; DL CSR ADDRESS .ENDC ; $$PROG = 104 ; DEFINES PROGRAMMABLE CLOCK VECTOR $$LINE = 100 ; DEFINES LINE CLOCK VECTOR ; **** ONLY ONE OF THE ABOVE CAN BE CHOSSEN $$DL11,$$PROG,$$LINE ; $$SKIP = 4 ; IF DEFINED IT REDUCES THE EFFECTIVE ; CLOCK RATE BY 1/4 IN THIS EXAMPLE .PAGE .SBTTL MACROS .MCALL FCSMC$,QIO$S,WSIG$S,WTSE$S,ASTX$S,RQST$S .MCALL GTSK$S,SVTK$S,GTIM$S,DIR$,GMCR$ .MCALL MRKT$S,WTSE$S,EXIT$S,QIOW$S,FCSMC$ .IF DF,R$$MPL .MACRO SREX$S AST,ERR .MCALL MOV$,DIR$ MOV$ AST MOV (PC)+,-(SP) .BYTE 167.,2 DIR$ ,ERR .ENDM .ENDC .MCALL PCBDF$,HWDDF$,DCBDF$,PKTDF$,UCBDF$,TCBDF$,ABODF$ HWDDF$ ,= ; DEFINE HARDWARE REGISTERS PCBDF$ ; DEFINE PCB OFFSETS TCBDF$ ; DEFINE TCB OFFSETS ABODF$ ; DEFINE ABORT CODES FCSMC$ ; GET FCS MACROS DCBDF$ ; DCB OFFSETS UCBDF$ ; UCB OFFSETS PKTDF$ ; I/O PACKET OFFSETS .MACRO WRTIT,VALUE ;+ ; WRTIT -- THIS MACRO WRITES A WORD TO THE NEXT AVAILABLE LOCATION ; IN THE OUTPUT FILE ; ; VALUE - THE WORD WHICH IS TO BE WRITTEN ; ;- MOV VALUE,R4 CALL WRTWRD .ENDM WRTIT .MACRO ERROUT,MSG,MSGSIZ MOV MSG,R0 MOV MSGSIZ,R1 JMP ERROR .ENDM .PAGE .SBTTL EQUATES ; EQUATES PS = 177776 ; ADDRESS OF PS VA.5 = 120000 ; APR 5 OFFSET ST.EFM = 2 ; COMMON EVENT FLAG TO STOP MONITOR ; CLOCK INTERRUPT VECTOR .IIF DF,$$DL11 CLKVEC = $$DL11 .IIF DF,$$LINE CLKVEC = $$LINE .IIF DF,$$PROG CLKVEC = $$PROG IOTVEC = 20 ; VECTOR OF IOT EXTSIZ = 100. ; EXTEND SIZE OF OUTPUT FILE TSKBLK = 5. ; NUMBER OF BLOCKS FOR TASKS DEVBLK = 1 ; NUMBER OF BLOCKS IN DEVICE BUFFER TSKSIZ = 24. ; SIZE OF TASK PACKET IN OUTPUT FILE PTRSIZ = 6 ; SIZE OF POINTER PACKET IN OUTPUT FILE MAXTSK = <-HDRSIZ>/ ; MAX NUMBER OF TASKS PKTSIZ = 6 ; SIZE OF QUQUED PACKET BUFCNT = 2 ; COUNT OF WRITE BUFFERS ; TASK PACKET OFFSETS TS.NAM = 0 ; TASK NAME TS.PTR = 4 ; LINK TO PC PACKETS TS.CNT = 10 ; TOTAL ACTIVE COUNT TS.DIR = 14 ; TASK DIRECTIVE COUNT TS.IN = 20 ; TASK IN MEMORY COUNT TS.OU = 22 ; TASK OUT OF MEMORY COUNT TS.SIZ = 24 ; TASK SIZE TS.LNK = 26 ; HASHING LINK ; DEVICE PACKET OFFSETS DM.NAM = 0 ; DEVICE NAME DM.PAR = 2 ; DRIVER PAR FOR APR5 DM.NUM = 4 ; NUMBER OF UNITS DM.PTR = 6 ; PTR TO UNIT COUNTS DM.HIC = 10 ; DEVICE SAMPLE COUNT - HIGH DM.LOC = 12 ; LOW DM.QIO = 14 ; TOTAL # OF QIOS DM.SIZ = 20 ; SIZE OF PACKET .PAGE .SBTTL DATA AREA TIMBF1: .BLKW 8. ; START TIME TIMBF2: .BLKW 8. ; END TIME ERRFLG: .WORD 0 ; ERROR FLAG SSTVEC: .WORD SST,SST,SST,SST,SST,SST,SST,SST ; SST TRAP VECTOR SAVTCB: .WORD 0 ; OUR TCB ADDRESS DIRPC: .WORD 0 ; DIRECTIVE PC CLKNOD: .WORD 0 ; ADDRESS OF CLOCK ICB NODE EMTNOD: .WORD 0 ; ADDRESS OF EMT ICB NODE IOFINS: .WORD ; INSTRUCTION AT $IOFIN IOTSAV: .WORD ; IOT INTERRUPT ROUTINE ADDRESS SAVED IOKDR: .WORD ; PDR OF ADDRESS $IOFIN IONODE: .WORD ; ADDRESS OF IO ICB MRPTSK: .RAD50 '...MRP' ; TASK NAME OF REPORT TASK .IF DF,$$SKIP INTCNT: .WORD 0 ; COUNT OF INTERRUPTS TO SKIP .ENDC .PAGE .SBTTL CLOCK ISR ;+ ; CLKISR -- ISR TO GET SYSTEM INFORMATION ; ; INPUT: ; APR5 IS MAPPED TO TASK APR5 ; ; OUTPUT: ; NONE ; ; ALL REGISTERS ARE SAVED ; ;- PSOFF = 6 ; OFFSET ON STACK TO PS .IIF DF,K$$DAS PSOFF=PSOFF+2 CLKISR: .IF DF,$$SKIP CMP INTCNT,#$$SKIP ;;; TIME TO TAKE INTERRUPT? BEQ 1$ ;;; YES INC INTCNT ;;; COUNT INTERRUPT RETURN ;;; EXIT 1$: CLR INTCNT ;;; CLEAR COUNTER .ENDC ADD #1,TOTCNT+2 ;;; COUNT INTERRUPTS ADC TOTCNT ; WERE WERE WE INTERRUPTED FROM BIT #40000,PSOFF(SP) ;;; INTERRUPTED FROM USER MODE? BNE 20$ ;;; YES CMPB #1,$IDLFL ;;; WERE WE IN IDLE LOOP? BEQ 15$ ;;; YES ;;; WE WERE IN SYSTEM STATE MOV R4,-(SP) ;;; SAVE R4,R5 MOV R5,-(SP) BIT #10000,PSOFF+4(SP) ;;; WERE WE IN USER PREVIOUS TO THIS? BEQ 4$ ;;; DON'T THINK SO TST $TKTCB ;;; NO TCB? BEQ 4$ ;;; YES CMP @#$STACK-4,DIRPC ;;; WAS THE PC THE SAME AS EMT 377? BNE 4$ ;;; NOPE CALL SAVINF ;;; STORE NAME ETC MOV #-1,(R5) ;;; MAKE IT USER TRAP BR ISREXT ;;; SKIP SOME CODE ; SEE IT WE ARE WORKING ON I/O 4$: BIT #SW.IO,SWMASK ;;; NO IO? BNE 12$ ;;; SO DON'T LOOK FOR IT MOV #DEVBUF,R4 ;;; R4 => DEVICE TABLE MOV DEVCNT,R5 ;;; R5 = NUMBER OF DEVICES 10$: CMP PSOFF(SP),DM.PAR(R4) ;;; EXECUTING IN THIS DRIVER? BEQ 13$ ;;; YES ADD #DM.SIZ,R4 ;;; TRY NEXT DEVICE SOB R5,10$ ;;; LOOP ; IN THE EXEC SOMEWHERE 12$: MOV #EXEC-T.NAM,R4 ;;; POINT TO 0,0 FOR EXEC TASK NAME CALL SAVIN1 ;;; SAVE EXEC INFO. BR 45$ ;;; SKIP SOME CODE ; WE ARE IN A DRIVER 13$: ADD #1,DEVTOT+2 ;;; ADD TO TOTAL FOR DRIVERS ADC DEVTOT ADD #1,DM.LOC(R4) ;;; ADD TO DRIVER TOTAL ADC DM.HIC(R4) BR ISREXT ;;; EXIT ISR ;;; COUNT TIMES IDLE 15$: ADD #1,IDLCT+2 ;;; COUNT IDLE TIMES ADC IDLCT .IF DF,$$DL11 BIS #100,@#$DLCSR ;;; SET OUTPUT INTERRUPT CLRB @#$DLCSR+2 ;;; PRINT NULL .ENDC RETURN ;;; EXIT ; WE WERE IN USER MODE 20$: MOV R4,-(SP) ;;; SAVE REGISTERS MOV R5,-(SP) CALL SAVINF ;;; SAVE TASK INFORMATION 45$: MOV PSOFF+2(SP),(R5) ;;; SAVE INTERRUPT ADDRESS ;;; EXIT CLOCK ISR ISREXT: MOV (SP)+,R5 ;;; RESTORE REGISTERS MOV (SP)+,R4 .IF DF,$$DL11 BIS #100,@#$DLCSR ;;; SET FOR OUTPUT INTERRUPT CLRB @#$DLCSR+2 ;;; PRINT NULL .ENDC RETURN ;;; SAVE TASK INFO INTO QUEUE SAVINF: MOV $TKTCB,R4 ;;; R4 POINTS TO RUNNING TASKS TCB ;;; INSERT INFO INTO QUEUE SAVIN1: CMP QUECNT,#MAXELE ;;; ALREADY FULL? BNE 30$ ;;; NO ;;; IF NO SPACE THEN REPORT ERROR ADD #1,ERRCNT+2 ;;; COUNT FOR MISSED INTERRUPTS ADC ERRCNT ;;; COUNT FOR MISSED INTERRUPTS 20$: TST (SP)+ ;;; REMOVE SP JMP ISREXT ;;; JUST EXIT ISR 30$: MOV IPTR,R5 ;;; R5 => INSERT CMP R5,#QUEEND ;;; AT END OF QUEUE? BLO 40$ ;;; NO MOV #QUEBEG,R5 ;;; R5 => BEGINNING MOV R5,IPTR ;;; POINT TO BEGINNING ;;; STORE TASK NAME AND INTERRUPTED ADDRESS 40$: CMP R4,SAVTCB ;;; MON TASK? BNE 45$ ;;; NO ADD #1,MONCNT+2 ;;; COUNT # OF TIMES IN MONITOR ADC MONCNT BR 20$ ;;; EXIT 45$: MOV T.NAM(R4),(R5)+ ;;; STORE TASK NAME MOV T.NAM+2(R4),(R5)+ 200$: INC QUECNT ;;; SAVE COUNTER ADD #PKTSIZ,IPTR ;;; FOR NEXT TIME RETURN .PAGE .SBTTL EMT ISR ;+ ; EMTISR -- EMT ISR ROUTINE ; ; THIS ISR COUNTS USER DIRECTIVES ; ;- PSEMT = PSOFF+2 ; LOCATION OF PS ON STACK PCEMT = PSOFF ; LOCATION OF PC ON STACK EMTISR: CMP $STKDP,#1 ;;; CAME FROM TASK STATE BNE 200$ ;;; NO ;;; EMT WAS FROM A TASK MOV R5,-(SP) ;;; SAVE R5 MOV PCEMT(SP),R5 ;;; POINT TO PLACE EMT HAPPENED MFPI -(R5) ;;; GET EMT INSTRUCTION CMP #104377,(SP)+ ;;; WAS IT A EMT 377? BNE 150$ ;;; NOT THIS TIME ;;; WAS AN EMT 377 FROM A TASK MOV R4,-(SP) ;;; SAVE R4 MOV $TKTCB,R4 ;;; POINT TO OUR TCB ;;; IF EMT TRAP WAS FROM ...MON DISREGARD CMP R4,SAVTCB ;;; OUR TASK? BEQ 140$ ;;; YES -- SKIP TRAP ;;; IT WAS A GOOD EMT 377 SO SAVE PC 20$: MOV PCEMT+2(SP),DIRPC ;;; SAVE PC ;;; FIND OUT WHAT KIND OF DIRECTIVE IT WAS MFPI SP ;;; GET USER SP .IF DF,R$$MPL MFPD$ @(SP)+ .IFF MFPI @(SP)+ ;;; GET DIR .ENDC BIT #1,@SP ;;; ON STACK? BNE 10$ ;;; YES .IF DF,R$$MPL MFPD$ @(SP)+ .IFF MFPI @(SP)+ ;;; N0 - GET IT THERE .ENDC 10$: MOV (SP)+,R5 ;;; GET DIR CODE BIC #177400,R5 ;;; CLEAR HIGH BYTE DEC R5 ;;; START AT ZERO ASL R5 ;;; MAKE IT DOUBLE WORD OFFSET ;;; INCREMENT DIRECTIVE COUNTER FOR DIRECTIVE ADD #1,DIRBUF+2(R5) ;;; ADD TO TOTAL FOR DIRECTIVE ADC DIRBUF(R5) ;;; ;;; ADD TO TOTAL FOR DIRECTIVES ADD #1,@#TOTDIR+2 ;;; ADD IN 1 FOR TOTAL ADC @#TOTDIR 140$: MOV (SP)+,R4 ;;; RESTORE R4 150$: MOV (SP)+,R5 ;;; RESTORE R5 200$: RETURN .PAGE .SBTTL IOSTAT ;+ ; FNDDEV -- FIND DEVICE IN DEVICE TABLE ; ; INPUT ; R0 => DCB ; ; OUTPUT ; ; CC-C SET IF NOT FOUND IN DEVICE TABLE ; CC-C CLEAR IF DEVICE IS FOUND ; ; R1 => DEVICE TABLE ENTRY ; ; REGISTERS ALTERED: ; R5 ;- FNDDEV: MOV DEVCNT,R5 ; R5 = NUMBER OF DEVICES BEQ 100$ ; EXIT MOV #DEVBUF,R1 ; R1 => DEVICE TABLE 10$: CMP D.NAM(R0),@R1 ; SAME NAME? BEQ 200$ ; YES ADD #DM.SIZ,R1 ; POINT TO NEXT DEVICE SOB R5,10$ ; LOOP ; DEVICE NOT FOUND 100$: SEC RETURN ; DEVICE FOUND 200$: CLC RETURN ;+ ; IOSTAT -- GET I/O STATISTICS ;- IOSTAT: MOV R0,-(SP) ; SAVE SOME REGISTERS MOV R1,-(SP) MOV R2,-(SP) ; SAVE R2 MOV R4,-(SP) ; SAVE R4 MOV R5,-(SP) ; SAVE R5 MOV I.UCB(R0),R2 ; R1 => UCB MOV U.DCB(R2),R0 ; R0 => DCB CALL FNDDEV ; GET A DEVICE BCS 200$ ; NOPE ADD #1,QIOTOT+2 ; ADD TO TOTAL ADC QIOTOT ADD #1,DM.QIO+2(R1) ; ADD TO DEVICE TOTAL ADC DM.QIO(R1) MOVB D.UNIT(R0),-(SP) ; GET UNIT BIC #^C377,@SP ; CLEAR BYTE MOV R2,R5 ; GET OFFSET FROM START OF UCBS SUB D.UCB(R0),R5 ; CLR R4 ; MAKE SURE ITS CLEAR DIV D.UCBL(R0),R4 ; ADD (SP)+,R4 ; ADD IN OFFSET ASL R4 ; GET OFFSET ASL R4 ADD DM.PTR(R1),R4 ; POINT TO COUNT ADD #DEVBUF,R4 ; ADD IN START OF BUFFER ADD #1,2(R4) ; TOTAL IT ADC @R4 200$: MOV (SP)+,R5 ; RESTORE R5 MOV (SP)+,R4 ; RESTORE R4 MOV (SP)+,R2 ; RESTORE REGISTERS MOV (SP)+,R1 MOV (SP)+,R0 RETURN .PAGE .SBTTL SYSTEM DATA SAVE AREA ; TASK SAMPLE QUEUE IPTR: .WORD QUEBEG ; INSERT POINTER DPTR: .WORD QUEBEG ; DELETE POINTER QUECNT: .WORD 0 ; COUNT OF QUEUED DATA ELEMENTS MAXELE = 100. ; FOR 100 PACKETS QUEBEG: .BLKW <3*MAXELE> ; FOR QUEUED PACKETS QUEEND=. EXEC: .WORD 0,0 ; A TASK NAME OF ' ' IS THE EXEC ; TASK PACKET HASH TABLE HASHTB: .WORD TSKBUF ; POINT 1ST POINTER TO EXEC PACKET .BLKW 127. ; TOTAL OF 128. ENTRIES NXTFRE: .WORD TSKBUF+TSKSIZ ; POINT TO 1ST FREE TASK BUFFER ; THIS IS DATA TO BE WRITTEN TO THE DISK ; BEGINNING OF TASK OUTPUT FILE BUFFERS TSKCNT: .WORD 1 ; NUMBER OF TASKS WE HAVE STATS FOR TOTDIR: .WORD 0,0 ; COUNT OF DIRECTIVES USRTRP: .WORD 0,0 ; TOTAL COUNT OF SAMPLES WE WERE ; EXECUTING A DIRECTIVE IN KERNAL MODE TSKLST: .WORD 0 ; COUNT OF TASKS LOST SAMPLES FOR ERRCNT: .WORD 0,0 ; COUNT OF MISSED INTERRUPTS IDLCT: .WORD 0,0 ; IDLE COUNT TOTCNT: .WORD 0,0 ; TOTAL NUMBER OF INTERRUPTS HOUR: .WORD 0 ; TOTAL ELAPSED TIME MIN: .WORD 0 SEC: .WORD 0 MEMLO: .WORD -1 ; LOWEST # OF TASKS IN MEMORY MEMHI: .WORD 0 ; HIGHEST # OF TASKS IN MEMORY MEMNO: .WORD 0,0 ; AVERAGE # OF TASKS IN MEMORY MEMSIZ: .WORD 0,0 ; AVERAGE SIZE OF MEMORY IN USE CKPLO: .WORD -1 ; LOWEST # OF TASKS OUT OF MEMORY CKPHI: .WORD 0 ; HIGHEST # OF TASKS OUT OF MENORY CKPNO: .WORD 0,0 ; AVERAGE # OF TASKS OUT OF MEMORY CKPSIZ: .WORD 0,0 ; AVERAGE SIZE OF CHECKPOINTED MEMORY MEMCNT: .WORD 0 ; COUNT OF MEMORY SAMPLES TAKEN MONCNT: .WORD 0,0 ; COUNT OF TIMES IN MONITOR SWMASK: .WORD 0 ; SWITCH VALUES HDRSIZ=<.-TSKCNT>/2 TSKBUF: ; START OF TASK BUFFER .REPT TSKSIZ/2 ; FOR EXEC .WORD 0 .ENDR ;************ THE FOLLOWING ROUTINES ARE TO BE USED AS BUFFER SPACE **** ; ICB,EMTICB,RELOC,IOICB,INTDEV,CREDEV,INIT,OPNFIL .PAGE .SBTTL ICB -- ICB FOR CLOCK ;+ ; CLOCK ICB -- TO BE USED AS BUFFER SPACE LATER ;- ICB: MOV @#KINAR5,-(SP) ; SAVE APR 5 MAPPING .IIF DF,K$$DAS MOV @#KDSAR5,-(SP) MOV APR5,@#KINAR5 ; MAP TO TASK .IIF DF,K$$DAS MOV APR5,@#KDSAR5 JSR PC,@#CLKISR ; CALL ISR ROUTINE .IIF DF,K$$DAS MOV (SP)+,@#KDSAR5 MOV (SP)+,@#KINAR5 ; RESTORE KERNAL MAPPING .IF DF,$$DL11 RTI .IFF .WORD 137 ; JMP TO CLOCK SERVICE ROUTINE .ENDC CLKOFF = .-ICB .WORD 0 ; ADDRESS OF CLOCK ROUTINE APR5: .WORD ; USER APR5 VALUE ICBSIZ=.-ICB .PAGE .SBTTL EMTICB -- ICB FOR EMT TRAPS ; EMT ICB TO BE USED AS BUFFER SPACE LATER EMTICB: MOV @#KINAR5,-(SP) ; SAVE APR 5 MAPPING .IIF DF,K$$DAS MOV @#KDSAR5,-(SP) MOV EMAPR5,@#KINAR5 ; MAP TO TASK .IIF DF,K$$DAS MOV EMAPR5,@#KDSAR5 JSR PC,@#EMTISR ; CALL ISR ROUTINE .IIF DF,K$$DAS MOV (SP)+,@#KDSAR5 MOV (SP)+,@#KINAR5 ; RESTORE KERNAL MAPPING .WORD 137 ; JMP TO CLOCK SERVICE ROUTINE EMTOFF = .-EMTICB .WORD 0 ; ADDRESS OF CLOCK ROUTINE EMAPR5: .WORD ; USER APR5 VALUE EMTSIZ=.-EMTICB .PAGE .SBTTL RELOC -- RELOCATE OUR TASK ;+ ; RELOC -- RELOCATE THIS TASK SO IT DOESN'T FRAGMENT MEMORY ; ; THIS ROUTINE RELOCATES A TASK TO EITHER THE START OF THE TASKS MAIN ; PARTITION OR THE HIGHEST FREE SPACE IN THE MAIN PARTITION ; ; INPUT ; ; NONE ; ; OUTPUT ; ; THIS TASK IS RELOCATED TO HIGH MEMORY TO PREVENT IT FROM FRAGMENTING MEMORY ; ;- RELOC: ;************************************************************************** ;************************************************************************** ;*************** **************** ;*************** TEMP PATCH UNTIL FIXED FOR SYSTEMS WITH **************** ;*************** MORE THAN 124K WORDS OF MEMORY **************** ;*************** **************** ;************************************************************************** ;************************************************************************** RETURN ;************************************************************************** ;************************************************************************** ;*************** **************** ;*************** DELETE THESE COMMENTS AND ABOVE RETURN **************** ;*************** WHEN RELOC IS FIXED **************** ;*************** **************** ;************************************************************************** ;************************************************************************** CALL $SWSTK,100$ ; GET INTO SYSTEM STATE MOV $TKTCB,R5 ;; POINT TO OUR TCB MOV T.PCB(R5),R4 ;; R4 => OUR PCB MOV P.REL(R4),-(SP) ;; SAVE FOR LATER CLR -(SP) ;; GET US A TEMP LCATION MOV P.MAIN(R4),R3 ;; R3 => OUR MAIN PCB ; UNLINK US FROM THE PCB LIST 10$: CMP P.SUB(R3),R4 ;; POINTS TO US? BEQ 20$ ;; YES MOV P.SUB(R3),R3 ;; CONTINUE BR 10$ ;; LOOP 20$: MOV P.SUB(R4),P.SUB(R3) ;; REMOVE US FROM THE LIST ; TRY TO FIT US IN AT THE START OF MEMORY MOV P.MAIN(R4),R3 ;; POINT TO OUR MAIN PARTITION MOV P.SUB(R3),R2 ;; R2 => NEXT SUB PARTITION BEQ 30$ ;; PUT US AT THE BEGINNING MOV P.REL(R2),R0 ;; GET STARTING LOCATION OF THE PAR SUB P.REL(R3),R0 ;; GET SIZE CMP P.SIZE(R4),R0 ;; LARGE ENOUGH HOLE? BHI 40$ ;; NO ; INSERT US AT THE BEGINNING 30$: MOV P.SUB(R3),P.SUB(R4) ;; LINK US IN MOV R4,P.SUB(R3) ;; MOV P.REL(R3),P.REL(R4) ;; FIX PAR BR 90$ ;; EXIT ; FIND HIGH HOLE 40$: MOV P.SUB(R3),R2 ;; GET SUB PARTITION 50$: MOV P.SUB(R2),R1 ;; GET NEXT SUB PARTITION BEQ 70$ ;; NO MOV P.REL(R1),R0 ;; GET START OF NEXT SUB PAR SUB P.REL(R2),R0 ;; FIND SPACE BETWEEN PARTITIONS SUB P.SIZE(R2),R0 ;; CMP P.SIZE(R4),R0 ;; BIG ENOUGH HOLE? BHI 60$ ;; NO MOV R2,@SP ;; SAVE PCB 60$: MOV R1,R2 ;; TRY NEXT HOLE BR 50$ ; TRY AT TOP OF MEMORY 70$: MOV P.REL(R3),R0 ;; FIND TOP OF MEMORY ADD P.SIZE(R3),R0 MOV R0,R1 ;; SAVE IT SUB P.REL(R2),R0 ;; GET TOP OF LAST SUB PAR SUB P.SIZE(R2),R0 CMP P.SIZE(R4),R0 ;; LARGE ENOUGH? BHI 80$ ; PUT TASK AT TOP OF MEMORY SUB P.SIZE(R4),R1 ;; GET PLACE TO PLACE SUB PAR MOV R1,P.REL(R4) ;; STORE IT 75$: MOV P.SUB(R2),P.SUB(R4) ;; INSERT PCB MOV R4,P.SUB(R2) ;; BR 90$ ;; EXIT ; INSERT PCB AT LAST HOLE LARGE ENOUGH 80$: MOV @SP,R2 ;; GET SAVED PCB MOV P.SUB(R2),R1 ;; POINT TO NEXT SUB PAR MOV P.REL(R1),R0 ;; GET STARTING ADDRESS SUB P.SIZE(R4),R0 ;; GET NEW STARTING ADDRESS OF OUR PAR MOV R0,P.REL(R4) ;; STORE IT BR 75$ ;; INSERT IT 90$: MOV P.REL(R4),R0 ;; GET APR VALUE MOV R0,@#UISAR5 ;; RELOCATE APRS MOV R0,R3 ;; SAVE FOR LATER ADD #8192./64.,R0 ;; NEXT APR MOV R0,@#UISAR6 ;; RELOCATE APR6 ADD #2,SP ;; CLEAN UP SP MOV (SP)+,R1 ;; GET ORIGINAL APR CALL MOVEME ;; MOVE TASK TO NEW HOME RETURN ;; RETURN TO TASK STATE 100$: RETURN ; EXIT -- WITH US RELOCATED MEMLIM: .LIMIT ;; GET MEMORY LIMITS MOVEME: MOV P.SIZE(R4),R0 ;; SAVE ORIGINAL SIZE ASH #5,R0 ;; MAKE IT # OF WORDS BIS #30000,@#PS ;; MAKE PREVIOUS USER CMP R1,R3 ;; MAKE SURE WE MOVE DATA THE RIGHT WAY BLO 50$ ;; MOVE FROM LOW ADDRESS BEQ 100$ ;; TASK IS AT THE SAME ADDRESS -- DON'T MOVE ; MOVE TASK FROM THE TOP MOV MEMLIM+2,R1 ;; GET HIGH ADDRESS+1 10$: MOV -(R1),-(SP) ;; GET DATA ON THE STACK MTPI @R1 ;; STORE IT IN NEW USER SPACE SOB R0,10$ ;; LOOP BR 100$ ;; EXIT ; MOVE DATA FROM LOW ADDRESS 50$: MOV #120000,R1 ;; START AT APR5 60$: MOV (R1),-(SP) ;; GET DATA ON THE STACK MTPI (R1)+ ;; STORE IT IN NEW TASK SPACE SOB R0,60$ ;; LOOP ; WE'RE FINISHED 100$: RETURN .PAGE .SBTTL IOICB -- I/O ICB IOICB: BIT #140000,2(SP) ; FROM KERNAL MODE BEQ 3$ ; YES 1$: JMP @IOTADR ; GO TO REGULAR IOT TRAP PROCESSING 3$: CMP #$IOFIN+2,@SP ; IOT WHERE WE PUT IT? BNE 1$ ; NO .IF DF,K$$DAS MOV @KDRIOF,-(SP) ; SAVE PDR OF $IOFIN MOV #77406,@KDRIOF ; MAKE IT R/W .ENDC MOV SAVINS,-(SP) ;; RESTORE INSTRUCTION BIC #30000,@#PS ;; MAKE SURE IT IS KERNAL MTPI @#$IOFIN .IF DF,K$$DAS MOV (SP)+,@KDRIOF ; RESTORE PDR .ENDC MOV 2(SP),(SP) ; FIX STACK MOV #$IOFIN,-(SP) ; RETURN TO WHERE IOT WAS MOV RTNADR,4(SP) ; COME TO OUR ROUTINE WHEN FINISHED RTI ; RETURN TO $IOFIN ; RTN=.-IOICB ; CALL I/O ROUTINE MOV @#PS,-(SP) ;; SAVE PS .IF DF,K$$DAS MOV @#KDSAR5,-(SP) ; SAVE D-SPACE APR 5 MOV IOAPR5,@#KDSAR5 ; MAP TO TASK .ENDC MOV @#KINAR5,-(SP) ; SAVE APR 5 MOV IOAPR5,@#KINAR5 ; MAP IT TO US CALL @#IOSTAT ; GET COUNTS MOV (SP)+,@#KINAR5 ; RESTORE I-SPACE APR 5 .IF DF,K$$DAS MOV (SP)+,@#KDSAR5 ; RESTORE D-SPACE APR 5 .ENDC MOV #340,@#PS ;; MAKE SURE NO INTERRUPTS .IF DF,K$$DAS MOV @KDRIOF,-(SP) ; SAVE PDR OF IOFIN MOV #77406,@KDRIOF ; SET IF R/W .ENDC MOV #IOT,-(SP) ; RESTORE IOT MTPI @#$IOFIN ; INSERT AN IOT .IF DF,K$$DAS MOV (SP)+,@KDRIOF ; RESTORE PDR .ENDC MOV (SP)+,@#PS ;; RESTORE PS RETURN ; RETURN SAVINS: .WORD ; SAVED INSTRUCTION AT $IOFIN IOTADR: .WORD ; SAVE IOT ADDRESS RTNADR: .WORD RTN ; RETURN ADDRESS .IF DF,K$$DAS KDRIOF: .WORD ; ADDRESS OF PDR OF $IOFIN .ENDC IOAPR5: .WORD ; APR5 OF TASK IONSIZ=.-IOICB .PAGE .SBTTL INTDEV -- INITIALIZE DEVICE TABLE AND ICB ;+ ; INTDEV -- INITIALIZE DEVICE TABLE AND ICB ; ; THIS ROUTINE ALLOCATES AN ICB TO INTERCEPT I/O COMPLETES AND INITS ; A TABLE OF THE FOLLOWING FORM: ; ; DEVBUF: .ASCII 'DB' ; DEVICE NAME ; .WORD 2345 ; APR 5 OF DB DRIVER ; .WORD 2 ; 2 DB:s IN THE SYSTEM ; .WORD DBUNIT ; POINTER TO UNIT COUNTS ; .WORD 0 ; SAMPLES WHILE IN DEIVER - HIGH ; .WORD 0 ; LOW ; .WORD 0,0 ; TOTAL NUMBER OF QIOS ; . ; . ; . ; ; DBUNIT: .WORD 0,0 ; I/O COUNTS FOR DB0: ; .WORD 0,0 ; I/O COUNTS FOR DB1: ; ;- INTDEV: CALL $SWSTK,30$ ; GET A NODE .IF DF,K$$DAS MOV #$IOFIN,R0 ;; FIND PDR ADDRESS OF $IOFIN ASH #-12.,R0 ;; SHIFT IT BIC #^C<16>,R0 ;; CLEAR UNUSED BITS ADD #KINDR0,R0 ;; ADD IN STARTING LOCATION OF I-SPACE PDR0 MOV R0,KDRIOF ;; SAVE IT MOV R0,IOKDR .ENDC MOV #IONSIZ,R1 ;; FOR THE IO ICB .IF DF,K$$DAS MOV #$ICAVL-2,R0 CALL $ALOC1 ;; GET NODE .IFF CALL $ALOCB .ENDC BCS 20$ ;; EXIT MOV R0,IONODE ;; SAVE FOR LATER ADD R0,RTNADR ;; MAKE RETURN ADDRESS OK BIC #30000,@#PS ;; MAKE SURE WE ARE KERNAL PREVIOUS MFPI @#$IOFIN ;; GET INSTRUCTION MOV @SP,SAVINS ;; SAVE IOFIN INSTRUCTION MOV (SP)+,IOFINS ;; SAVE IT HERE TOO MOV @#IOTVEC,IOTADR ;; SAVE IOT INTERRUPT ROUTINE ADDRESS MOV @#IOTVEC,IOTSAV ;; COPY NODE MOV #IONSIZ/2,R3 ;; R3 = SIZE OF NODE IN WORDS MOV #IOICB,R4 ;; START MOVING HERE 10$: MOV (R4)+,(R0)+ ;; STORE NODE SOB R3,10$ ;; LOOP MOV IONODE,@#IOTVEC ;; REPLACE VECTOR ADDRESS .IF DF,K$$DAS MOV @IOKDR,-(SP) ;; SAVE PDR MOV #77406,@IOKDR ;; MAKE IT R/W .ENDC MOV #IOT,-(SP) ;; INSERT AN IOT INTO THE CODE MTPI @#$IOFIN ;; STORE AN IOT AT IOFIN .IF DF,K$$DAS MOV (SP)+,@IOKDR ;; RESTORE PDR .ENDC CALL CREDEV ;; FORMAT DEVICE TABLE 20$: RETURN 30$: TST IONODE ; NO NODE? BNE 40$ ; NO ERROUT #MSG1,#MSG1SZ ; REPORT ERROR 40$: RETURN .PAGE .SBTTL CREDEV -- FORMAT DEVICE TABLES CREDEV: MOV $DEVHD,R0 ; R0=> 1ST DCB MOV #DEVBUF,R1 ; R1 => DEVICE TABLE 10$: MOV D.UCB(R0),R2 ; R2 => UCB BIT #DV.PSE,U.CW1(R2) ; A PSEUDO DEVICE? BNE 25$ ; YES CALL FNDDEV ; DEVICE ALREADY ALLOCATED? BCC 20$ ; YES MOV D.NAM(R0),@R1 ; STORE NAME INC DEVCNT ; COUNT DEVICE MOV D.PCB(R0),R2 ; POINT TO PCB BEQ 20$ ; DOESN'T HAVE ONE MOV P.REL(R2),DM.PAR(R1) ; SAVE IT 20$: MOVB D.UNIT(R0),R2 ; FIND NUMBER OF UNITS MOVB D.UNIT+1(R0),R3 INC R3 SUB R2,R3 ADD R3,DM.NUM(R1) ; ADD INTO TOTAL ADD #DM.SIZ,R1 ; POINT TO NEXT ENTRY 25$: MOV D.LNK(R0),R0 ; NEXT DCB BNE 10$ ; MAKE UNIT ENTRIES MOV #DEVBUF,R0 ; START AT BEGINNING OF TABLE MOV DEVCNT,R2 ; THIS MANY TIMES THROUGH LOOP 30$: MOV R1,DM.PTR(R0) ; STORE UNIT POINTER SUB #DEVBUF,DM.PTR(R0) ; MAKE POINTER RELATIVE TO DEVBUF MOV DM.NUM(R0),R3 ; GET # OF UNITS ASL R3 ; MUL BY 4 ASL R3 ADD R3,R1 ; NEXT UNIT TABLE CMP R1,#DEVEND ; END OF BUFFER? BLOS 40$ ; NOT YET ERROUT #MSG6,#MSG6SZ ; REPORT ERROR 40$: ADD #DM.SIZ,R0 ; POINT TO NEXT DEVICE ENTRY SOB R2,30$ ; LOOP RETURN .PAGE .SBTTL GETSW -- GET COMMAND SWITCHES .MACRO SWITCH,NAME,VALUE .ASCII /NAME/ .WORD VALUE .ENDM SW.PC = 1 SW.ME = 2 SW.IO = 4 SW.DR = 10 SW.AL = -1 SWTABL: SWITCH PC,SW.PC ; NO TASK PC COUNTS SWITCH ME,SW.ME ; NO MEMORY COUNTS SWITCH IO,SW.IO ; NO I/O COUNTS SWITCH DR,SW.DR ; NO DIRECTIVE COUNTS SWITCH AL,SW.AL ; NONE OF THE ABOVE SWCNT = <.-SWTABL>/4 CMDERR: .ASCII 'MON -- INVALID COMMAND LINE' CMDERS=.-CMDERR .EVEN ;+ ; SKPSPA -- SKIP SPACES IN COMMAND LINE ; ; INPUT ; R0 => COMMAND LINE ; ; OUTPUT ; R0 => NEXT NON-BLANK CHARACTER ; CC-C CLEAR IF NOT AT END OF COMMAND LINE ; CC-C SET IF AT END OF COMMAND LINE ; REGISTERS SAVED ;- SKPSPA: CMPB @R0,#40 ; A SPACE? BNE 10$ ; NOPE INC R0 ; POINT PAST BLANK BR SKPSPA ; REPEAT 10$: TSTB @R0 ; AT END OF COMMAND BUFFER? BNE 20$ ; NOT YET SEC RETURN ; RETURN END-OF-BUFFER 20$: CLC RETURN ; WE'RE AT A NON-BLANK CHARACTER ;+ ; GETSW -- GET SWITCH VALUE ; ; INPUT ; R0 => SWITCH ; ; OUTPUT ; R0 => PAST SWITCH ; SWMASK = SWMASK!SWITCH AND CC OR ; CARRY IS SET IF INVALID SWITCH ; REGISTERS ALTERED: ; R1,R2 ; ;- GETSW: MOV #SWTABL,R1 ; R1 => SWITCH TABLE MOV #SWCNT,R2 ; R2 = NUMBER OF SWITCHES INC R0 ; POINT PAST '/' CMPB (R0)+,#'N ; /NO?? AT FIRST? BNE 25$ ; NO CMPB (R0)+,#'O BNE 25$ ; NO 10$: CMPB @R1,@R0 ; THIS SWITCH? BNE 20$ ; NO CMPB 1(R1),1(R0) ; 2ND HALF? BEQ 30$ ; YES 20$: ADD #4,R1 ; POINT TO NEXT SWITCH SOB R2,10$ ; KEEP SEARCHING 25$: SEC RETURN ; INVALID SWITCH 30$: BIS 2(R1),SWMASK ; SET BIT ADD #2,R0 ; POINT PAST SWITCH CLC RETURN ; SAY WE FOUND THE SWITCH ;+ ; CMDLIN -- GET MCR COMMAND LINE AND SWITCHES ; ; INPUT ; NONE ; ; OUTPUT ; SWMASK IS SET TO SWITCH VALUES ; REGISTERS ALTERED: ; R0,R1 ;- MCRLIN: GMCR$ ; MCR COMMAND DPB CMDLIN: DIR$ #MCRLIN ; GET COMMAND BCC 20$ ; OK 10$: ERROUT #CMDERR,#CMDERS ; REPORT COMMAND ERROR 20$: MOV #MCRLIN+G.MCRB,R0 ; POINT TO COMMAND MOV R0,R1 ; COPY ADD $DSW,R1 ; POINT PAST END CLRB @R1 ; MAKE IT NULL 30$: CMPB @R0,#40 ; FIND 1ST SPACE BEQ 40$ ; FOUND IT TSTB @R0 ; END OF COMMAND LINE? BEQ 50$ ; YES -- NO SWITCHES INC R0 ; NEXT CHARACTER BR 30$ ; LOOP 40$: CALL SKPSPA ; SKIP SPACES BCS 50$ ; FINISHED CMPB @R0,#'/ ; A SWITCH? BNE 10$ ; NO ITS AN ERROR CALL GETSW ; GET THE SWITCH BCS 10$ ; INVALID SWITCH BR 40$ ; TRY FOR MORE SWITCHES 50$: RETURN ; EXIT .PAGE .SBTTL INITIALIZATION ROUTINE ;+ ; INIT -- ICB AND I/O INITIALIZATION ; ;- INIT: BIC #ST.EFM,$COMEF ; MAKE SURE IT IS CLEAR SO WE DON'T STOP SVTK$S #SSTVEC,#8. ; RECEIVE ALL TRAPS GTIM$S #TIMBF1 ; GET START TIME .IF DF,R$$MPL SREX$S #EXTAST ; SPECIFY EXIT AST .ENDC CALL OPNFIL ; OPEN OUTPUT FILE ; GET NODE AND STORE ICB FOR CLOCK CALL $SWSTK,100$ ; GET INTO SYATEM MODE MOV @#UISAR5,APR5 ;;; SAVE APR5 VALUE MOV @#UISAR5,IOAPR5 ;;; SAVE APR 5 VALUE FOR I/O ICB MOV #ICBSIZ,R1 ;;; R1 = SIZE OF NODE TO GET .IF DF,K$$DAS MOV #$ICAVL-2,R0 ;;; R0 => POOL LISTHEAD CALL $ALOC1 ;;; GET BLOCK .IFF CALL $ALOCB ;;; GET NODE .ENDC BCC 3$ ; OK RETURN ; EXIT 3$: MOV R0,CLKNOD ; SAVE ADDRESS MOV @#CLKVEC,CLKOFF+ICB ; STORE CLOCK ADDRESS MOV #ICB,R1 ; R1 => CODE TO RELOCATE MOV #ICBSIZ/2,R2 ; R2 = SIZE OF NODE 5$: MOV (R1)+,(R0)+ ; STORE SOB R2,5$ ; LOOP MOV $TKTCB,R5 ; R5 => TO OUR TCB MOV R5,SAVTCB ; SAVE OUR TCB MOV T.PCB(R5),R0 ; R0 => PCB BIS #PS.CHK,P.STAT(R0) ; SET CHECKPOINTING DISABLED BIS #PS.NSF,P.STAT(R0) ; SET NON-SHUFFLABLE MOV CLKNOD,@#CLKVEC ; MAKE IT GO TO US RETURN ; EXIT SYATEM STATE 100$: TST CLKNOD ; NO NODE? BNE 10$ ; NO ERROUT #MSG1,#MSG1SZ ; ERROR EXIT ; GET ICB FOR EMT 10$: BIT #SW.DR,SWMASK ; NO DIRECTIVE STATS? BNE 210$ ; YES CALL $SWSTK,200$ ; GET INTO SYATEM MODE MOV @#UISAR5,EMAPR5 ;;; SAVE APR5 VALUE MOV #EMTSIZ,R1 ;;; R1 = SIZE OF NODE TO GET .IF DF,K$$DAS MOV #$ICAVL-2,R0 ;;; R0 => POOL LISTHEAD CALL $ALOC1 ;;; GET BLOCK .IFF CALL $ALOCB ;;; GET NODE .ENDC BCC 203$ ; OK RETURN ; EXIT 203$: MOV R0,EMTNOD ; SAVE ADDRESS MOV @#30,EMTOFF+EMTICB ; STORE EMT VECTOR ADDRESS MOV #EMTICB,R1 ; R1 => CODE TO RELOCATE MOV #EMTSIZ/2,R2 ; R2 = SIZE OF NODE 205$: MOV (R1)+,(R0)+ ; STORE SOB R2,205$ ; LOOP MOV EMTNOD,@#30 ; MAKE INTERRUPT COME TO US RETURN ; EXIT SYATEM STATE 200$: TST EMTNOD ; NO NODE? BNE 210$ ; NO ERROUT #MSG1,#MSG1SZ ; ERROR EXIT 210$: BIT #SW.IO,SWMASK ; NO IO? BNE 220$ ; YES CALL INTDEV ; INITIALIZE DEVICE TABLE AND ICB 220$: .IF DF,$$DL11 BIS #100,@#$DLCSR ; SET OUTPUT INTERRUPT CLRB @#$DLCSR+2 ; OUTPUT A NULL .ENDC RETURN .PAGE .SBTTL OPNFIL -- OPEN OUTPUT FILE OPNFIL: FINIT$ ; INITIALIZE FCS BIT #SW.PC,SWMASK ; DON'T ALLOCATE A BIG FILE IF NO PC BEQ 10$ ; WE ARE USING PC MOV #-,FDB+F.ALOC; ONLY ALLOCATE SMALL SPACE IF NO PC MOV #-,FDB+F.CNTG; ONLY ALLOCATE SMALL SPACE IF NO PC 10$: OPEN$W #FDB,,,,,,OPNERR ; OPEN FILE MOV #EXTSIZ,BLALOC ; SAVE ALLOCATION AMOUNT RETURN OPNERR: ERROUT #MSG2,#MSG2SZ ; FILE OPEN ERROR .PAGE .SBTTL SOME MORE BUFFER AREA .BLKB -<.-TSKCNT> ; REST OF BUFFER (TOT. OF TSKBLK BLOCKS) DIRBUF: .BLKW 256. ; BUFFER FOR DIRECTIVE STATISTICS DEVTOT: .WORD 0,0 ; COUNT OF TOTAL SAMPLES DEVCNT: .WORD 0 ; NUMBER OF DEVICES QIOTOT: .WORD 0,0 ; QIO TOTAL DEVBUF: .BLKW -<<.-DEVTOT>/2> ; DEVICE BUFFER DEVEND=. .PAGE .SBTTL CLOFIL -- CLOSE OUTPUT FILE ;+ ; CLOFIL -- CLOSE OUTPUT FILE AND FINISH WRITTING REST OF OUTPUT FILE ;- CLOFIL: MOV BLALOC,FDB+F.HIBK+2 ; STORE HIGH BLOCK NUMBER CLR FDB+F.HIBK ; CLEAR HIGH WORD CLR FDB+F.EFBK ; CLEAR HIGH WORD OF EOF BLOCK MOV NXTWRD,R0 ; FIND EOF BLOCK/BYTE MOV NXTWRD+2,R1 DIV #512.,R0 INC R0 ; MAKE IT VBN MOV R0,FDB+F.EFBK+2 ; STORE EOF BLOCK MOV R1,FDB+F.FFBY ; STORE EOF BYTE ; WRITE OUT FIXED PART OF OUTPUT FILE QIOW$S #IO.WVB,#1,#4,,#IOSB,,<#TSKCNT,#*512.,,#0,#1> BCS 5$ ; ERROR TSTB IOSB ; ERROR? BPL 10$ ; NO 5$: ERROUT #MSG3,#MSG3SZ ; ERROR 10$: MOV #IOSB1,R0 ; ANY PENDING I/O? MOV #BUFCNT,R1 ; ONLY 2 BUFFERS 20$: TSTB TBL.ST(R0) ; PENDING OPERATION? BEQ 40$ ; NOT THIS BUFFER BIT #BUF.WT,TBL.ST(R0) ; WAITING FOR A WRITE TO COMPLETE? BEQ 30$ ; NO MOVB TBL.ST+1(R0),R2 ; GET EF # WTSE$S R2 ; WAIT FOR IT TO COMPLETE BR 35$ ; CHECK FOR ERROR 30$: MOVB TBL.ST+1(R0),R2 ; GET EF # QIOW$S #IO.WVB,#1,R2,,R0,, ; WRITE IT BCS 5$ ; ERROR INC NXTVBN ; INCREMENT VIRTUAL BLOCK COUNTER 35$: TSTB @R0 ; AN ERROR? BMI 5$ ; ERROR 40$: ADD #BLKTBS,R0 ; NEXT BLOCK SOB R1,20$ ; LOOP CLOSE$ #FDB ; CLOSE FILE RETURN .PAGE .SBTTL GETCKP -- GET MEMORY USAGE INFORMATION ;+ ; GETCKP -- GET MEMORY USAGE INFORMATION FROM ACTIVE TASKS ;- TEMP: .BLKW 4. ; TEMP LOCATIONS IN: .WORD 0 ; COUNT OF TASKS IN MEMORY OUT: .WORD 0 ; COUNT OF TASKS OUT OF MEMORY TMPSIZ=.-TEMP CKPSAV: CALL GETPAR ; GET PARTITION INFO ; COMPARE HI/LOW VALUES CMP IN,MEMLO ; IS IT LOWER THIS TIME? BHIS 10$ ; NO MOV IN,MEMLO ; SAVE IT 10$: CMP IN,MEMHI ; IS IT HEIGHER THIS TIME? BLOS 20$ ; NOPE MOV IN,MEMHI ; STORE NEW VALUE 20$: CMP OUT,CKPLO ; IS IT LOWER THIS TIME? BHIS 30$ ; NO MOV OUT,CKPLO ; SAVE IT 30$: CMP OUT,CKPHI ; NEW HIGH VALUE? BLOS 40$ ; NO MOV OUT,CKPHI ; STORE NEW VALUE ; ADD IN/OUT TO TOTALS 40$: ADD IN,MEMNO+2 ; ADD TO TOTAL OF TASKS IN MEMORY ADC MEMNO ADD OUT,CKPNO+2 ; ADD TO TOTAL OF TASKS CHECKPOINTED ADC CKPNO ; TOTAL MEMORY USED/CHECKPOINTED ADD TEMP+2,MEMSIZ+2 ; TOTAL MEMORY USED ADC MEMSIZ ADD TEMP,MEMSIZ ADD TEMP+6,CKPSIZ+2 ; TOTAL SIZE OF CHECKOPOINTED FILES ADC CKPSIZ ADD TEMP+4,CKPSIZ RETURN ; SEARCH ATL TO GET MEMORY USAGE GETPAR: INC MEMCNT ; COUNT TIME WE'VE COME HERE MOV #TEMP,R0 ; CLEAR COUNTER WORDS MOV #TMPSIZ/2,R1 5$: CLR (R0)+ ; ZERO SOB R1,5$ CALL $SWSTK,200$ ; GET INTO SYSTEM MODE MOV $ACTHD,R0 ; POINT TO ATL 10$: TST T.ACTL(R0) ; AT END OF ATL? BEQ 40$ ; YES CMP R0,SAVTCB ; OUR TCB? BEQ 30$ ; SKIP OUR ATL ADD #T.NAM,R0 ; POINT TO NAME CALL FNDTSK ; FIND TASK SUB #T.NAM,R0 ; MAKE R0 OK MOV T.PCB(R0),R1 ; R1 => PCB MOV P.SIZE(R1),TS.SIZ(R2) ; STORE TASK SIZE .IF DF,R$$MPL BIT #PS.OUT,P.STAT(R1) ; TASK OUT OF MEMORY? .IFF BIT #TS.OUT,T.STAT(R0) ; TASK OUT OF MEMORY? .ENDC BNE 20$ ; YES ADD P.SIZE(R1),TEMP+2 ; TOTAL TASKS IN MEMORY ADC TEMP INC IN ; INCREMENT TOTAL COUNTER INC TS.IN(R2) ; COUNT TASK IN BR 30$ ; SKIP TASKS OUT OF MEMORY CODE 20$: ADD P.SIZE(R1),TEMP+6 ; ADD IN TOTAL BLOCKS OUT OF MEMORY ADC TEMP+4 INC OUT ; INCREMET TASK OUT COUNTER INC TS.OU(R2) ; ADD TO TIMES OUT 30$: MOV T.ACTL(R0),R0 ; GO TO NEXT ATL BR 10$ ; LOOP 40$: RETURN 200$: RETURN .PAGE .SBTTL SAVSTA -- SAVE STATISTICS ;+ ; SAVSTA -- SAVE STATISTICS GATHERED INTO OUTPUT FILE ;- SAVSTA: BIT #SW.ME,SWMASK ; NO MEMORY STATS? BNE SAVST1 ; YES CALL CKPSAV ; SAVE MEMORY STATS SAVST1: TST QUECNT ; SOMETHING IN THE QUE? BNE 1$ ; YES RETURN ; EXIT WITH QUEUE EMPTY 1$: MOV DPTR,R0 ; R0 => NEXT QUEUED NODE CALL FNDTSK ; FIND TASK IN TASK BUFFER BCS 255$ ; NOT ENOUGH SPACE ; WE FOUND THE TASK 200$: ADD #4,R0 ; SKIP PAST TASK NAME 250$: CMP @R0,#-1 ; DIRECTIVE? BNE 251$ ; NO ADD #1,TS.DIR+2(R2) ; ADD IN USER TRAP TOTAL ADC TS.DIR(R2) ADD #1,USRTRP+2 ; ADD INTO TOTAL ADC USRTRP BR 255$ ; SKIP SOME CODE 251$: ADD #1,TS.CNT+2(R2) ; INCREMENT TASK COUNTER ADC TS.CNT(R2) BIT #SW.PC,SWMASK ; NO PC STATS? BNE 255$ ; YES MOV TS.PTR+2(R2),-(SP) ; SAVE LINK WORDS MOV TS.PTR(R2),-(SP) MOV NXTWRD,TS.PTR(R2) ; SAVE OLD LINK MOV NXTWRD+2,TS.PTR+2(R2) WRTIT (R0) ; WRITE PC WRTIT (SP)+ ; WRITE HIGH WORD WRTIT (SP)+ ; WRITE LOW WORD OF LINK 255$: ADD #PKTSIZ,DPTR ; POINT TO NEXT QUEUE ADDRESS CMP DPTR,#QUEEND ; AT END OF QUEUE? BLO 260$ ; NO MOV #QUEBEG,DPTR ; POINT TO BEGINNING OF QUEUE 260$: DEC QUECNT ; DECREMENT QUEUED COUNTER JMP SAVST1 ; TRY FOR ANOTHER .PAGE .SBTTL FNDTSK -- SEARCH FOR TASK IN TASK BUFFER ;+ ; FNDTSK -- SEARCH FOR TASK IN TASK BUFFER ; ; INPUT ; R0 => TASK NAME ; ; OUTPUT ; R2 => TASK BUFFER ENTRY ; ; CC-C CLEAR IF FOUND OR ROOM TO INSERT ; CC-C SET IF NO ROOM FOR TASK ; ; NO REGISTERS DISTROYED ; ;- FNDTSK: MOV R1,-(SP) ; SAVE R1 ; HASH TASK NAME MOV @R0,R1 ; MAKE HASH INDEX ADD 2(R0),R1 BIC #^C376,R1 ; CLEAR BITS SO INDEX IS 0<= IDX <=254. MOV HASHTB(R1),R2 ; R2 = TASK PACKET POINTER BNE 20$ ; WE FOUND SOMETHING ; THIS IS THE 1ST TIME FOR THIS TASK CMP TSKCNT,#MAXTSK ; ALREADY FULL? BHI 10$ ; YES MOV NXTFRE,HASHTB(R1) ; STORE POINTER BR 100$ ; STORE IT ; NO ROOM EXIT WITH CC-C SET 10$: INC TSKLST ; COUNT LOST TASK MOV (SP)+,R1 ; RESTORE R1 SEC RETURN ; EXIT WITH TASK NOT FOUND ; SEARCH THROUGH TASK LIST 20$: CMP @R2,@R0 ; TASK NAMES THE SAME? BNE 30$ ; NO CMP 2(R0),2(R2) ; 2ND HALF? BEQ 200$ ; YES -- WE FOUND THE TASK ; TRY NEXT TASK IN CHAIN 30$: MOV R2,R1 ; GET NEXT TASK PACKET ADDRESS MOV TS.LNK(R2),R2 ; AND SAVE OLD ONE BNE 20$ ; WE HAVE 1 MORE AT LEAST ; TASK IS NOT THERE CMP TSKCNT,#MAXTSK ; MORE ROOM? BHI 10$ ; NO ERROR - EXIT MOV NXTFRE,TS.LNK(R1) ; STORE LINK ; MAKE A NEW ENTRY 100$: MOV NXTFRE,R2 ; R2 => FREE SPACE ADD #TSKSIZ,NXTFRE ; POINT TO NEXT AVAIL. SOACE MOV (R0),(R2)+ ; STORE TASK NAME MOV 2(R0),(R2)+ MOV #TSKSIZ/2-2,R1 ; CLEAR REST OF WORDS 110$: CLR (R2)+ ; CLEAR WORD SOB R1,110$ SUB #TSKSIZ,R2 ; POINT TO THE BEGINNING INC TSKCNT ; INCREMENT TASK COUNTER 200$: MOV (SP)+,R1 ; RESTORE R1 CLC RETURN ; RETURN WITH TASK FOUND .PAGE .SBTTL WRTWRD - WRITE A WORD TO DISK ;+ ; WRTWRD -- WRITE A WORD TO THE OUTPUT FILE ; ; INPUT ; ; R4 = WORD TO WRITE ; NXTWRD = ADDRESS ON DISK TO PUT THE WORD ; ; ; OUTPUT ; ; WORD IS WRITTEN ; ;- WRTWRD: MOV R0,-(SP) ; SAVE REGISTERS MOV R1,-(SP) MOV R2,-(SP) MOV R3,-(SP) MOV NXTWRD,R0 ; GET NEXT ADDRESS TO WRITE MOV NXTWRD+2,R1 DIV #512.,R0 ; GET BLOCK AND OFFSET INC R0 ; MAKE BLOCK VIRTUAL MOV BLKPTR,R2 ; POINT TO BLOCK TABLE 10$: BIT #BUF.WT,TBL.ST(R2) ; THIS BLOCK STILL BEING WRITTEN? BEQ 20$ ; NO MOVB TBL.ST+1(R2),R3 ; GET LUN WTSE$S R3 ; WAIT FOR I/0 TO COMPLETE 20$: MOV TBL.BF(R2),R3 ; GET BUFFER ADDRESS ADD R1,R3 ; STORE WORD AT R3 MOVB #BUF.NW,TBL.ST(R2) ; THIS BLOCK SHOULD BE WRITTEN BEFORE ; WE EXIT MOV R4,@R3 CMP R1,#510. ; TIME TO WRITE THIS BLOCK? BNE 50$ ; NOPE 22$: CMP R0,BLALOC ; NEED TO ALOCATE SOME MORE BLOCKS? BLO 30$ ; NOT NOW BHI 23$ ; YES TST EXTFLG ; WE ARE TRYING TO EXTEND FILE? BEQ 25$ ; NO BR 30$ ; DON'T TRY EXTEND AGAIN 23$: WTSE$S #10. ; WAIT FOR EXTEND TO COMPLETE BR 30$ ; WE SHOULD HAVE ENOUGH SPACE ALLOCATED 25$: INC EXTFLG ; SET WE'RE EXTENDING THE FILE NOW QIO$S #IO.EXT,#1,#10.,,#IOSB,#ASTEXT,<#FDB+F.FNB,,#100000,#EXTSIZ> ; EXTEND FILE BCC 30$ ; OK ERROUT #MSG4,#MSG4SZ ; EXTEND ERROR 30$: MOVB TBL.ST+1(R2),R3 ; GET EF # QIO$S #IO.WVB,#1,R3,,R2,#WRTAST, ; WRITE BLOCK BCC 35$ ; OK ERROUT #MSG3,#MSG3SZ ; FILE WRITE ERROR 35$: BIS #340,@#PS ; LOCK EVERYONE OUT MOVB #BUF.WT,TBL.ST(R2) ; SET WE ARE WRITTING THIS BLOCK INC NXTVBN ; COUNT THIS BLOCK BIC #340,@#PS ; BACK TO NORMAL ADD #BLKTBS,R2 ; POINT TO NEXT BLOCK CMP R2,#ENDTBL ; AT END OF TABLE? BNE 40$ ; YES MOV #IOSB1,R2 ; POINT TO THE BEGINNING 40$: MOV R2,BLKPTR ; RESTORE POINTER 50$: ADD #2,NXTWRD+2 ; POINT TO NEXT WORD ADC NXTWRD ; MOV (SP)+,R3 ; RESTORE REGISTERS MOV (SP)+,R2 MOV (SP)+,R1 MOV (SP)+,R0 RETURN ; EXIT .PAGE .SBTTL I/O AST ROUTINES ; EXTEND FILE AST EXTFLG: .WORD 0 ; EXTEND FLAG ASTEXT: TST (SP)+ ; CLEANUP STACK TSTB IOSB ; ERROR? BPL 10$ ; NO ERROUT #MSG4,#MSG4SZ ; EXTEND ERROR 10$: ADD #EXTSIZ,BLALOC ; ADD TO ALLOCATION CLR EXTFLG ; SET EXTEND COMPLETE ASTX$S ; BLOCK WRITE AST WRTAST: TST @(SP) ; ERROR? BPL 10$ ; NO ERROUT #MSG3,#MSG3SZ ; WRITE ERROR 10$: MOV R0,-(SP) ; SAVE R0 MOV 2(SP),R0 ; POINT TO BLOCK TABLE CLRB TBL.ST(R0) ; SET BUFFER INACTIVE MOV (SP)+,R0 ; RESTORE R0 TST (SP)+ ; CLEAR OFF IOSB ADDRESS ASTX$S ; EXIT AST .PAGE .SBTTL FCS & QIO DATA AREA IOSB: .BLKW 2 ; IOSB FOR EXTEND FILE QIO NXTVBN: .WORD TSKBLK+2+DEVBLK ; NEXT VNB TO WRITE BLALOC: .WORD 0 ; FILE SIZE NXTWRD: .WORD 0,*512. ; NEXT ADDRESS TO WRITE BUF.WT = 1 ; BUFFER IS BEING WRITTEN BUF.NW = 2 ; BUFFER HAS BEEN WRITTEN INTO TBL.ST = 4 ; OFFSET TO STATUS WORD TBL.BF = 6 ; OFFSET TO BUFFER POINTER BLKPTR: .WORD IOSB1 ; POINTER TO BLOCK CURRENT BLOCK ; TABLE ENTRY IOSB1: .BLKW 2 ; 1ST IOSB .BYTE 0,2 ; 1ST STATUS WORD .WORD BUF1 ; POINTER TO 1ST BUFFER BLKTBS=.-IOSB1 IOSB2: .BLKW 2 ; 2ND IOSB .BYTE 0,3 ; 2ND STATUS WORD .WORD BUF2 ; POINTER TO SECOND BUFFER ENDTBL = . BUF1: .BLKW 256. ; BUFFER 1 BUF2: .BLKW 256. ; BUFFER 2 FDB: FDBDF$ ; OUTPUT FILE FDB FDAT$A R.FIX,,6,-EXTSIZ,-EXTSIZ FDRC$A FD.RWM ; BLOCK MODE FDOP$A 1,DSPT,DFNB DSPT: 0,0,UICSIZ,UIC,0,0 UIC: .ASCII '[1,2]' UICSIZ=.-UIC .EVEN DFNB: NMBLK$ MONITOR,DAT,0,SY,0 ; 'SY0:[1,2]MONITOR.DAT;0' FSRSZ$ 0 .PAGE .SBTTL CLEAN UP FOR EXIT ;+ ; CLEANUP -- GET THINGS READY FOR EXIT ; ; THIS ROUTINE DEALLOCATES ICBS FOR CLOCK ,EMT AND I/O ; CLOSES THE OUTPUT FILE ; AND REQUESTS ...MRP TO RUN. ; ; INPUT: ; ; NONE ; ; OUTPUT: ; ; NONE ; ; NO REGISTERS ARE SAVED ; ;- RTNFLG: .WORD 0 ; ALREADY RETURNED NODE FLAG CLEANUP: TST RTNFLG ; ALREADY RETURNED NODES BEQ 5$ ; NO JMP 120$ ; YES 5$: GTIM$S #TIMBF2 ; GET ENDDING TIME ; DEALLOCATE ICBS CALL $SWSTK,120$ ; GET INTO SYSTEM STATE INC RTNFLG ;; SET NODES ALREADY RETURNED MOV CLKNOD,R0 ;; R0 => NODE TO RETURN BEQ 20$ ;; NO NODE TO RETURN MOV CLKOFF(R0),@#CLKVEC ;; RESTORE CLOCK VECTOR ; RETURN CLOCK ICB NODE TO POOL MOV #ICBSIZ,R1 ;; R1 = SIZE OF NODE TO RETURN .IF DF,K$$DAS MOV #$ICAVL-2,R3 ;; LIST HEAD CALL $DEAC1 .IFF CALL $DEACB .ENDC ; FIX TASK STATUS FLAGS 15$: MOV $TKTCB,R5 ;; R5 => TO MY TCB MOV T.PCB(R5),R0 ;; R0 => MY PCB BIT #T2.CHK,T.ST2(R5) ;; TASK CHECKPOINTABLE? BEQ 10$ ;; NO BIC #PS.CHK,P.STAT(R0) ;; ENABLE CHECKPOINTING 10$: CMP T.EFLG(R5),#S.PRTY ;; MEM. PARITY ERROR? BEQ 20$ ;; YES BIC #PS.NSF,P.STAT(R0) ;; MAKE TASK SHUFFABLE? ; RETURN EMT ICB NODE TO POOL 20$: MOV EMTNOD,R0 ;; R0 => NODE TO RETURN BEQ 115$ ;; NO NODE TO RETURN MOV EMTOFF(R0),@#30 ;; RESTORE EMT VECTOR MOV #EMTSIZ,R1 ;; R1 = SIZE OF NODE TO RETURN .IF DF,K$$DAS MOV #$ICAVL-2,R3 ;; LIST HEAD CALL $DEAC1 .IFF CALL $DEACB .ENDC ; RETURN I/O ICB 115$: MOV IONODE,R0 ;; R0 => NODE TO RETURN BEQ 117$ ;; NO NODE TO RETURN .IF DF,K$$DAS MOV @IOKDR,-(SP) ;; SAVE PDR MOV #77406,@IOKDR ;; MAKE IT R/W .ENDC BIC #30000,@#PS ;; MAKE SURE WE ARE IN KERNAL PREVIOUS MOV IOFINS,-(SP) ;; RESTORE INSTRUCTION MTPI @#$IOFIN ;; .IF DF,K$$DAS MOV (SP)+,@IOKDR ;; RESTORE PDR .ENDC MOV IOTSAV,@#IOTVEC ;; RESTORE IOT VECTOR MOV #IONSIZ,R1 ;; R1 = SIZE OF NODE TO RETURN .IF DF,K$$DAS MOV #$ICAVL-2,R3 ;; LIST HEAD CALL $DEAC1 .IFF CALL $DEACB .ENDC 117$: RETURN ;; EXIT SYSTEM STATE ; FINISH ALL QUEUED SAMPLES 120$: CALL SAVST1 ; MAKE SURE EVERYTHING IS CLEARED OUT CALL ELPTIM ; CALCULATE ELAPSED TIME CALL CLOFIL ; CLOSE FILE TST ERRFLG ; WAS THERE AN ERROR? BNE 130$ ; NO RQST$S #MRPTSK ; REQUEST REPORT TASK 130$: RETURN .PAGE .SBTTL ELPTIM -- GET ELAPSED TIME MONITOR WAS RUNNING ;+ ; ELPTIM -- CALCULATE ELAPSED TIME FROM START TO FINISH OF MONITOR ; ; INPUT ; ; TIMBF1 = STARTING TIME ; TIMBF2 = ENDDING TIME ; ; OUTPUT ; ; HOUR,MIN,SEC = ELAPSED TIME IN HMS FORMAT ; ;- ELPTIM: MOV #TIMBF1+14.,R0 ; POINT TO STARTING TIME MOV #TIMBF2+14.,R1 ; POINT TO ENDDING TIME ; TICKS SUB -(R0),-(R1) ; GET TIME DIFFERENCE FOR TICKS BPL 10$ ; NO BORROW FROM SECONDS DEC -2(R1) ; GET A SECOND ADD 2(R1),@R1 ; ADD IN TICKS/SECOND 10$: ASR 2(R1) ; GET 1/2 OF TICKS/SAECOND CMP @R1,2(R1) ; > HALF ? BLO 20$ ; NOPE INC -2(R1) ; MAKE SECONDS 1 GREATER ; SECONDS 20$: SUB -(R0),-(R1) ; SUBTRACT SECONDS BPL 30$ ; NO BORROW FROM MINUTES DEC -2(R1) ; GET A MINUTE ADD #60.,@R1 ; ADD 60. SECONDS 30$: CMP @R1,#60. ; > 1 MINUTE? BLO 40$ ; NO SUB #60.,@R1 ; REDUCE IT INC -2(R1) ; ADD TO MINUTES ; MINUTES 40$: SUB -(R0),-(R1) ; SUBTRACT MINUTES BPL 50$ ; NO BORROW FROM HOURS DEC -2(R1) ; GET AN HOUR ADD #60.,@R1 ; ADD IN 60. MINMUTES 50$: CMP @R1,#60. ; > AN HOUR? BLO 60$ ; NO SUB #60.,@R1 ; TAKE OUT AN HOUR INC -2(R1) ; ADD TO HOURS ; HOUR 60$: SUB -(R0),-(R1) ; SUBTRACT HOURS BPL 70$ ; OK ADD #24.,@R1 ; ADD IN 1 DAY 70$: MOV (R1)+,HOUR ; STORE INTO HEADER MOV (R1)+,MIN MOV (R1),SEC RETURN .PAGE .PAGE .SBTTL MAIN PROGRAM START: CALL CMDLIN ; GET MCR COMMAND LINE CALL RELOC ; RELOCATE OURSELVES CALL INIT ; INITIALIZE ; WAIT HERE FOR A WHILE 10$: MRKT$S #1,#1.,#2 ; WAIT FOR 1 SECOND WTSE$S #1 CALL SAVSTA ; SAVE STATISTICS BIT #ST.EFM,$COMEF ; STOP? BEQ 10$ ; NOPE ; EXIT TASK CALL CLEANUP ; MAKE EVERYTHING OK EXIT: EXIT$S .IF DF,R$$MPL ; COME HERE WHEN WE ARE ASKED TO EXIT EXTAST: ADD #4,SP ; TAKE SOME STUFF OFF THE STACK BIS #ST.EFM,$COMEF ; SET COMMON EF TO MAKE US STOP ASTX$S ; EXIT AST .ENDC .PAGE .SBTTL ERROR -- WRITE ERROR MESSAGE AND EXIT ;+ ; ERROR -- PRINT ERROR MESSAGE ; ; INPUT ; ; R0 => MESSAGE ; R1 = MESSAGE SIZE ; ;- MSG1: .ASCII 'MON -- UNABLE TO ALLOCATE ICB' MSG1SZ=.-MSG1 MSG2: .ASCII 'MON -- FILE OPEN ERROR' MSG2SZ=.-MSG2 MSG3: .ASCII 'MON -- OUTPUT FILE WRITE ERROR' MSG3SZ=.-MSG3 MSG4: .ASCII 'MON -- OUTPUT FILE EXTEND ERROR' MSG4SZ=.-MSG4 MSG5: .ASCII 'MON -- SST TRAP' MSG5SZ=.-MSG5 MSG6: .ASCII 'MON -- NOT ENOUGH SPACE IN DEVICE TABLE' MSG6SZ=.-MSG6 .EVEN SST: MOV #MSG5,R0 ; PRINT SST ERROR MESSAGE MOV #MSG5SZ,R1 ERROR: QIOW$S #IO.WVB,#5,#5,,,, TST ERRFLG ; ALREADY 1 ERROR? BNE 10$ ; NO INC ERRFLG ; SET ERROR FLAG CALL CLEANUP ; FIX THINGS 10$: JMP EXIT ; EXIT .END START