TITLE QSRFSS -- Failsoft System for QUASAR SUBTTL Larry Samberg 6 Aug 76 ;***Copyright (C) 1974, 1975, 1976, Digital Equipment Corp., Maynard, Mass.*** SEARCH QSRMAC ;PARAMETER FILE PROLOGUE(QSRFSS) ;GENERATE THE NECESSARY SYMBOLS ; ;NOTES: ; ;ALL GLOBAL ROUTINES IN THIS MODULE USE "ONLY" ACS S1 AND S2. ; CALLERS ARE GUARANTEED THAT ALL OTHER ACS WILL BE ; RETURNED INTACT. ; ;THE GLOBAL ROUTINES IN THIS MODULE MAKE ONLY ONE ASSUMPTION ; ABOUT THE CONTENTS OF THE QUEUE REQUESTS THAT THEY ; FAILSOFT, THAT IS THAT THEY CONTAIN A STANDARD MESSAGE ; HEADER. ; ;THIS ROUTINE USES A DATA-STRUCTURE CALLED THE "FILE INDEX" OR JUST ; "INDEX". UNFORTUNATELY, THE TERM "INDEX" IS USED TO DESCRIBE ; A TYPE OF REGISTER (ACCUMULATOR) IN AN INSTRUCTION. WHEN THIS ; USAGE APPEARS, AN ATTEMPT HAS BEEN MADE TO SPECIFICALLY REFER ; TO IT AS AN "INDEX REGISTER". THE TWO USAGES OF THIS WORD ARE ; DIFFERENT AND DISTINCT, AND SHOULD NOT BE CONFUSED. COMMENT\ STOPCDs found in QSRFSS BRS BAD REQUEST SIZE CRF CREATE REJECTED FAILSOFT DATA CUD CLEARING UNUSED DPA DTL DPA TOO LARGE DTS DPA TOO SMALL FUD FOUND UNUSED DPA NMF NO MORE FILESPACE RCN REQUEST COUNT NEGATIVE RCW REBUILD COUNT WRONG TMS TOO MANY SECTIONS WQV WRONG QUEUE VERSION \ SUBTTL Description of Failsoft Files COMMENT ? ; !=======================================================! ; ! ! ; ! INDEX AND UNUSED BLOCKS FOR THIS SECTION ! ; ! ! ; ! ! ; !-------------------------------------------------------! ; ! ! ; ! ! ; / DATA BLOCKS FOR THIS SECTION / ; / / ; / / ; ! ! ; ! ! ; !=======================================================! ; !=======================================================! ; !FORMAT VERSION OF THE QUEUE!NO. OF REQUESTS IN SECTION ! ; !-------------------------------------------------------! ; ! UNUSED (CONTAINS 0) ! ; !-------------------------------------------------------! ; ! ! ; ! INDEX SAT MARKERS ! ; ! FOR THIS INDEX BLOCK ! ; ! ! ; !-------------------------------------------------------! ; ! ! ; / / ; / DESCRIPTION OF THE DATA BLOCKS IN THIS SECTION / ; / / ; ! ! ; !=======================================================! ? SUBTTL Storage Cells INDEX: BLOCK 1 ;ADDRESS OF CURRENT INDEX INDTAB: BLOCK FSSMNS ;TABLE OF INDEX ADDRESSES SUBTTL Global Routines ;THE FOLLOWING ARE GLOBAL ENTRY POINTS IN QSRFSS INTERN F$INIT ;INITIALIZE THE FAILSOFT SYSTEM INTERN F$WRRQ ;WRITE OUT A REQUEST INTERN F$RDRQ ;READ IN A REQUEST INTERN F$RLRQ ;RELEASE A REQUEST SUBTTL Initialization ;FAILSOFT SYSTEM INITIALIZATION F$INIT: PUSHJ P,.SAVE1## ;SAVE P1 PUSHJ P,I$OQUE## ;GO OPEN UP THE MASTER QUEUES PUSHJ P,REDIDX ;AND GO READ THE MASTER HLRZ S1,@INDTAB ;GET INDEX VERSION NUMBER CAIE S1,FSSQFV ;IS IT RIGHT? STOPCD (WQV,FATAL) ;++WRONG QUEUE VERSION INIT.1: CLEAR P1, ;CLEAR OUT AN INDEX REG INIT.2: MOVE S1,P1 ;COPY ARGUMENT FOR REBILD SKIPN INDTAB(S1) ;IS THERE ANOTHER INDEX? POPJ P, ;NO, RETURN PUSHJ P,REBILD ;REBUILD THIS SECTION CAIGE P1,FSSMNS-1 ;GOT THEM ALL? AOJA P1,INIT.2 ;NO, LOOP POPJ P, ;YES, RETURN ;REBILD -- LOCAL ROUTINE TO REBUILD THE IN-CORE QUEUES FROM THE ; CURRENT SECTION. ; ;REBILD IS CALLED DURING INITIALIZATION (ONLY) TO READ IN AND "RE-CREATE" ; ALL THE REQUESTS IN THE SECTION WHOSE NUMBER IS IN S1. REBILD: PUSHJ P,.SAVE4## ;SAVE P1-P4 SETZM G$ERR## ;CLEAR GLOBAL ERROR FLAG MOVE S2,INDTAB(S1) ;GET ADR OF SECTION INDEX MOVEM S2,INDEX ;SAVE AS CURRENT SECTION IMULI S1,FSSBPS ;GET BASE DPA MOVEM S1,REBI.E ;AND SAVE IT HRRZ P1,@INDEX ;GET THE NUMBER OF REQUESTS PJUMPE P1,.POPJ## ;RETURN IF ZERO MOVEM P1,REBI.B ;AND SAVE IT MOVE P2,INDEX ;GET ADDRESS OF INDEX ADDI P2,FSSFDB ;POINT TO FIRST DATA BLOCK MOVEM P2,REBI.A ;AND SAVE IT MOVE P3,INDEX ;GET ADDRESS OF INDEX ADDI P3,777 ;POINT TO LAST WORD MOVEM P3,REBI.C ;AND STORE IT REBI.1: SKIPN S1,0(P2) ;GET THE NEXT ENTRY REBI.2: JRST REBI.3 ;ZERO, GO ON TO NEXT AOJE S1,REBI.3 ;-1 MEANS CONTINUATION, IGNORE MOVE S1,P2 ;GET THE ADDRESS SUB S1,INDEX ;MAKE IT A DPA ADD S1,REBI.E ;ADD IN THE BASE MOVE P3,S1 ;SAVE DPA IN P3 PUSHJ P,F$RDRQ ;AND READ THE REQUEST MOVEM S1,REBI.D ;SAVE THE ADDRESS MOVE M,S1 ;AND PUT IT IN M TXO P3,.QIFNC ;SET "INTERNAL FUNCTION" BIT STORE P3,.MSTYP(M),MS.TYP ;AND STORE IN FUNCTION FIELD ; THE CREATE ROUTINE TREATS THE ; LOW ORDER 17 BITS OF THE MSG ; TYPE AS THE DPA ON AN INTERNAL ; CALL PUSHJ P,Q$CREATE## ;DO THE CREATE SKIPE G$ERR## ;DID AN ERROR OCCUR STOPCD(CRF,FATAL) ;++CREATE REJECTED FAILSOFT DATA MOVE AP,REBI.D ;GET THE ADDRESS OF THE REQEST ADR2PG AP ;CONVERT TO A PAGE PUSHJ P,M$RELP## ;RELEASE THE PAGE SOSG P1,REBI.B ;DECREMENT AND LOAD REQUEST CNT POPJ P, ;NO MORE, DONE REBI.3: AOS P2,REBI.A ;INCREMENT AND LOAD INDEX-REGISTER CAMG P2,REBI.C ;MORE, IS THERE ROOM? JRST REBI.1 ;YES, LOOP STOPCD (RCW,FATAL) ;++REBUILD COUNT WRONG REBI.A: BLOCK 1 ;LOCAL STORAGE REBI.B: BLOCK 1 ;LOCAL STORAGE REBI.C: BLOCK 1 ;LOCAL STORAGE REBI.D: BLOCK 1 ;LOCAL STORAGE REBI.E: BLOCK 1 ;LOCAL STORAGE SUBTTL F$WRRQ -- Write out a Request ;F$WRRQ IS CALLED TO FAILSOFT A REQUEST. CALL WITH S1 CONTAINING ; THE ADDRESS OF A REQUEST, AND RETURN WITH S1 CONTAINING ; A DPA FOR IT. F$WRRQ: MOVEM S1,WRRQ.A ;SAVE THE ADDRESS LOAD S1,.MSTYP(S1),MS.CNT ;GET THE SIZE OF THE REQUEST MOVEM S1,WRRQ.C ;AND SAVE IT PUSHJ P,GETDPA ;GET SOME FILE SPACE MOVEM S1,WRRQ.B ;AND SAVE THE DPA HRLZ S2,WRRQ.C ;GET LENGTH,,0 HRR S2,WRRQ.A ;GET LEN,,ADR PUSHJ P,I$WRIT## ;AND WRITE IT PUSHJ P,WRTIDX ;WRITE THE INDEX MOVE S1,WRRQ.B ;GET THE DPA POPJ P, ;AND RETURN IT WRRQ.A: BLOCK 1 ;HOLDS THE ADDRESS WRRQ.B: BLOCK 1 ;HOLDS THE DPA WRRQ.C: BLOCK 1 ;HOLDS THE SIZE SUBTTL F$RDRQ -- Read in a Request ;F$RDRQ IS CALLED TO READ A REQUEST FROM THE FAILSOFT SYSTEM. CALL ; F$FDRQ WITH THE DPA IN S1, AND RETURN WITH S1 CONTAINING ; THE ADDRESS OF A PAGE CONTAINING THE REQUEST. F$RDRQ: MOVEM S1,RDRQ.B ;SAVE THE DPA PUSHJ P,FNDDPA ;GET THE REQUEST LENGTH HRLZM S1,RDRQ.C ;SAVE LEN,,0 MOVEM AP,RDRQ.A ;SAVE AP PUSHJ P,M$ACQP## ;GET A PAGE PG2ADR AP ;MAKE AN ADDRESS EXCH AP,RDRQ.A ;GET AP BACK AND SAVE ADR MOVE S1,RDRQ.B ;GET THE DPA MOVE S2,RDRQ.C ;GET LEN,,0 HRR S2,RDRQ.A ;GET LEN,,ADDRESS PUSHJ P,I$READ## ;READ THE REQUEST MOVE S1,RDRQ.A ;GET THE ADDRESS POPJ P, ;AND RETURN IT RDRQ.A: BLOCK 1 ;HOLDS THE ADDRESS RDRQ.B: BLOCK 1 ;HOLDS THE DPA RDRQ.C: BLOCK 1 ;HOLDS LENGTH,,0 SUBTTL F$RLRQ -- Release a Request ;F$RLRQ IS CALLED TO RELEASE THE FAILSOFT SPACE FOR A REQUEST. ; IT SIMPLY WRITES OUT AN UPDATED INDEX BLOCK. CALL WITH ; S1 CONTAINING THE DPA OF THE REQUEST. F$RLRQ: PUSHJ P,CLRDPA ;CLEAR THE INDEX WORDS OUT PJRST WRTIDX ;WRITE THE INDEX AND RETURN SUBTTL Index Handling Routines ; REDIDX -- READ THE INDICES DURING INITIALIZATION ; GETDPA -- ALLOCATE FAILSOFT SPACE FOR A REQUEST ; SRHIDX -- SEARCH THE INDEX FOR "N" FREE BLOCKS ; CLRDPA -- RELEASE FAILSOFT SPACE FOR A REQUEST ; FNDDPA -- FIND A FAILSOFT REQUEST IN INDEX ; WRTIDX -- WRITE OUT THE INDICES ; MRKIDX -- MARK INDEX BLOCKS FOR WRITING SUBTTL REDIDX -- Read INDICES during initialization ;REDIDX IS CALLED DURING THE FAILSOFT SYSTEM INITIALIZATION (F$INIT) ; TO READ IN ALL THE INDICES FROM THE MASTER QUEUE FILE. IT ; ASSUMES THAT THHE MASTER QUEUE(S) HAVE BEEN OPENED AND THAT ; THE GLOBAL VARIABLE G$NBW CONTAINS THE TOTAL NUMBER OF BLOCKS ; WRITTEN IN THE FILE. ; ;IF THE FILE IS BRAND NEW, IT CREATES THE FIRST INDEX PAGE AND WRITES ; IT OUT, SO WHEN REDIDX RETURNS THERE IS ALWAYS A VALID INDEX PAGE. REDIDX: PUSHJ P,.SAVET## ;SAVE T REGS CLEARM INDTAB ;CLEAR THE FIRST WORD IFG FSSMNS-1,< MOVE S1,[INDTAB,,INDTAB+1] ;MAKE A BLT POINTER BLT S1,INDTAB+FSSMNS-1 ;AND BLT THE BLOCK TO ZEROS > ;END IFG FSSMNS-1 MOVE T1,G$NBW## ;GET NUMBER OF BLOCKS WRITTEN ADDI T1,FSSBPS-1 ;ROUND UP IDIVI T1,FSSBPS ;CONVERT TO NUMBER OF SECTIONS CAILE T1,FSSMNS ;COMPARE AGAINST THE MAX STOPCD (TMS,FATAL) ;++TOO MANY SECTIONS JUMPE T1,REDI.2 ;IF BRAND NEW, CREATE IT CLEAR T2, ;ELSE, CLEAR A COUNTER REDI.1: PUSH P,AP ;SAVE AP PUSHJ P,M$ACQP## ;GET A PAGE PG2ADR AP ;CONVERT TO AN ADDRESS MOVEM AP,INDTAB(T2) ;AND SAVE THE ADDRESS MOVEI S1,FSSBPS ;GET BLOCKS/SECTION IMULI S1,(T2) ;* ADDI S1,FSSFIB ;+FIRST BLOCK = DPA MOVSI S2,FSSWPI ;WORDS/INDEX,,0 HRR S2,AP ;WORDS/INDEX,,ADDRESS PUSHJ P,I$READ## ;AND READ IT POP P,AP ;RESTORE AP SOJLE T1,.POPJ## ;RETURN IF DONE AOJA T2,REDI.1 ;ELSE LOOP ;HERE ON A BRAND NEW FILE ; REDI.2: PUSHJ P,GETIPG ;GET AN INDEX PAGE MOVEM S1,INDTAB ;AND STORE IT'S ADDRESS MOVEI S1,FSSQFV ;GET A VERSION NUMBER HRLM S1,@INDTAB ;AND SAVE IT MOVEI S1,FSSFIB ;DPA OF FIRST INDEX BLOCK HRRZ S2,INDTAB ;GET ADDRESS OF INDEX PAGE PJRST I$CRIP## ;CREATE IT AND RETURN SUBTTL GETDPA -- Routine to allocate space in INDEX ;CALL GETDPA WITH THE SIZE OF THE REQUEST IN S1, AND RETURN WITH ; A DPA IN S1. IT PERFORMS THE FOLLOWING FUNCTIONS: ; 1)FIND FAILSOFT SPACE AND MARK IT IN USE ; 2)MARK INDEX BLOCKS FOR WRITING ; 3)INCREMENT REQUEST COUNT GETDPA: PUSHJ P,.SAVE2## ;SAVE P1 CLEAR P1, ;AND CLEAR IT MOVEM S1,GETD.A ;SAVE NUMBER OF WORDS NEEDED SKIPLE S1 ;MAKE SURE IT'S REASONABLE CAILE S1,1000 ;AS BEING NOT TOO SMALL OR TOO LARGE STOPCD (BRS,FATAL) ;++BAD REQUEST SIZE ADDI S1,FSSBKS-1 ;ROUND UP FIRST IDIVI S1,FSSBKS ;AND FIND OUT HOW MANY BLOCKS MOVEM S1,GETD.B ;AND SAVE THAT GETD.1: MOVE S1,INDTAB(P1) ;GET NEXT INDEX MOVEM S1,INDEX ;AND SAVE AS CURRENT INDEX JUMPN S1,GETD.2 ;JUMP IF IT EXISTS PUSHJ P,GETIPG ;GET AN INDEX PAGE MOVEM S1,INDTAB(P1) ;SAVE IN INDTAB MOVEM S1,INDEX ;AND ALSO AS CURRENT INDEX MOVE S2,S1 ;GET ADR IN S2 MOVE S1,P1 ;GET SECTION NUMBER IMULI S1,FSSBPS ;CONVERT TO DPA OF INDEX PUSHJ P,I$CRIP## ;AND CREATE THE PAGE IN THE FILE GETD.2: MOVE S1,GETD.B ;GET NUMBER OF BLOCKS NEEDED PUSHJ P,SRHIDX ;SEARCH THIS INDEX FOR THEM JUMPN S1,GETD.3 ;GOT THEM!! CAIGE P1,FSSMNS-1 ;NO, ANY MORE INDICES? AOJA P1,GETD.1 ;YUP, LOOP STOPCD (NMF,FATAL) ;++NO MORE FILESPACE ;"GETDPA" IS CONTINUED ON THE NEXT PAGE ;CONTINUED FROM THE PREVIOUS PAGE GETD.3: AOS @INDEX ;INCREMENT REQUEST COUNT MOVE P2,S1 ;SAVE OFFSET OF 1ST AVAIL BLOCK IMULI P1,FSSBPS ;GET BASE DPA FOR THIS SECTION ADDB P1,S1 ;GET ABSOLUTE DPA OF NEW ENTRY MOVEM P1,GETD.C ;AND SAVE IT PUSHJ P,MRKIDX ;MARK IT AS WRITTEN MOVEI S1,-1(P1) ;GET FIRST BLOCK - 1 ADD S1,GETD.B ;ADD # BLKS TO GET #LAST BLK PUSHJ P,MRKIDX ;AND MARK IT ADD P2,INDEX ;GET ADDRESS OF INDEX WORD HRLZ S1,GETD.B ;GET #BLKS,,0 HRR S1,GETD.A ;GET #BLKS,,#WORDS MOVEM S1,0(P2) ;SAVE IN INDEX MOVE S2,GETD.B ;GET NUMBER OF BLOCKS MOVE S1,GETD.C ;GET RETURN ARGUMENT GETD.4: SOJLE S2,.POPJ## ;RETURN IF DONE AOS P2 ;POINT TO NEXT WORD SETOM (P2) ;MARK IT JRST GETD.4 ;AND LOOP GETD.A: BLOCK 1 ;LOCAL STORAGE GETD.B: BLOCK 1 ;LOCAL STORAGE GETD.C: BLOCK 1 ;LOCAL STORAGE SUBTTL SRHIDX -- Routine to search INDEX for space ;CALL SRHIDX WITH S1 CONTAINING THE NUMBER OF FREE CONTIGUOUS BLOCKS ; NEEDED IN THE CURRENT INDEX. RETURNS WITH S1 CONTAINING THE ; OFFSET OF THE FIRST WORD OF THE GROUP FOUND, OR ZERO IF NO ; SPACE IS FOUND. SRHIDX: PUSHJ P,.SAVET## ;SAVE THE T ACS MOVE T1,INDEX ;GET ADDRESS OF THE INDEX ADDI T1,FSSFDB ;MAKE IT ADR OF FIRST DATA BLOCK MOVE T2,INDEX ;GET ADDRESS OF INDEX ADDI T2,FSSWPI-1 ;GET ADR OF LAST WORD IN IT MOVE S2,S1 ;GET NUMBER OF BLOCKS INTO S2 MOVE T4,S2 ;AND INTO T4 MOVE S1,T1 ;GET "FIRST ZERO" INTO S1 ; ;HERE TO LOOP FOR THE NECESSARY NUMBER OF FREE ENTRIES ; SRHI.1: SKIPE (T1) ;GOT A ZERO? JRST SRHI.2 ;NO, GO SEARCH FOR ONE SOJE T4,SRHI.4 ;YES, ALL WE NEED? CAMGE T1,T2 ;NO, ANYTHING ELSE TO SEARCH? AOJA T1,SRHI.1 ;YES, LOOP JRST SRHI.3 ;NO, RETURN ZERO ; ;HERE IF WE FIND A NON-ZERO WORD ; SRHI.2: CAMGE T1,T2 ;REACHED THE END? AOSA T1 ;NO, BUMP THE POINTER AND SKIP JRST SRHI.3 ;YES, RETURN FAILURE MOVE T4,S2 ;RELOAD #BLKS NEEDED MOVE S1,T1 ;RELOAD "FIRST ZERO" JRST SRHI.1 ;AND GO BACK TO THE LOOP ; ;HERE TO RETURN A ZERO ; SRHI.3: CLEAR S1, ;CLEAR THE AC POPJ P, ;AND RETURN ; ;HERE WHEN WE FIND "N" CONSECUTIVE ZEROS. S1 CONTAINS THE "FIRST ZERO". ;SUBTRACT THE BASE ADDRESS AND RETURN THE OFFSET. ; SRHI.4: SUB S1,INDEX ;SUBTRACT THE ADR OF THE INDEX POPJ P, ;AND RETURN SUBTTL CLRDPA -- Release Failsoft Space for a request ;CLRDPA IS CALLED WITH A DPA IN S1. IT PERFORMS THE FOLLOWING FUNCTIONS: ; 1) CLEAR SPECIFIED FAILSOFT ENTRIES ; 2) DECREMENT REQUEST COUNT ; 3) MARK INDEX BLOCK FOR WRITING CLRDPA: MOVEM S1,CLRD.A ;SAVE DPA PUSHJ P,VALDPA ;INSURE A CORRECT DPA MOVE S1,INDTAB(S1) ;GET ADR OF THE SECTION INDEX MOVEM S1,INDEX ;AND SAVE AS CURRENT INDEX ADD S2,S1 ;GET ADDRESS OF ENTRY INTO S2 HLRZ S1,(S2) ;GET NUMBER OF BLOCKS IN ENTRY MOVEM S1,CLRD.B ;AND SAVE IT CLRD.1: SKIPN (S2) ;MAKE SURE IT WAS IN USE STOPCD (CUD,FATAL) ;++CLEARING UNUSED DPA CLEARM (S2) ;CLEAR A WORD SOJLE S1,CLRD.2 ;DONE? AOJA S2,CLRD.1 ;NO, LOOP FOR ALL BLOCKS CLRD.2: SOS S1,@INDEX ;DECREMENT REQUEST COUNT TRNE S1,400000 ;DID WE GO PAST 0? STOPCD (RCN,FATAL) ;++REQUEST COUNT NEGATIVE MOVE S1,CLRD.A ;GET DPA OF FIRST BLOCK PUSHJ P,MRKIDX ;MAKE IT MOVE S1,CLRD.A ;GET DPA OF FIRST BLOCK ADD S1,CLRD.B ;ADD NUMBER OF BLOCKS SUBI S1,1 ;AND BACK OFF BY ONE PJRST MRKIDX ;MARK THE INDEX AND RETURN CLRD.A: BLOCK 1 ;LOCAL STORAGE CLRD.B: BLOCK 1 ;LOCAL STORAGE SUBTTL FNDDPA -- Find a failsoft entry in the INDEX ;FNDDPA IS CALLED WITH S1 CONTAING A DPA AND RETURNS WITH S1 ; CONTAINING THE INDEX ENTRY FOR THAT DPA, I.E. ; XWD #BLOCKS,,#WORDS. FNDDPA: PUSHJ P,VALDPA ;INSURE A CORRECT DPA MOVE S1,INDTAB(S1) ;GET ADR OF SECTION INDEX ADD S1,S2 ;NO, ADD IT IN MOVE S1,0(S1) ;AND GET THE ENTRY JUMPN S1,.POPJ## ;RETURN IF GOOD STOPCD (FUD,FATAL) ;++FOUND UNUSED DPA SUBTTL WRTIDX -- Routine to write out the INDEX ;WRTIDX LOOPS THRU THE INDEX-SAT TABLE LOOKING FOR INDEX BLOCKS WHICH ; HAVE BEEN CHANGED, AND CAUSES EACH CHANGED INDEX BLOCK TO BE ; RE-WRITTEN. WRTIDX: PUSHJ P,.SAVET## ;SAVE THE T REGS CLEAR T3, ;CLEAR THE SECTION INDEX REG WRTI.1: MOVE T1,INDTAB(T3) ;GET ADR OF SECTION INDEX MOVEM T1,INDEX ;AND SAVE AS CURRENT JUMPE T1,.POPJ## ;IF ZERO, WE ARE DONE MOVEI T2,FSSFIB ;GET NUMBER OF FIRST INDEX BLOCK ADD T2,INDEX ;GET ADR OF ITS SAT-WORD CLEAR T1, ;CLEAR AN INDEX REG WRTI.2: SKIPE S2,(T2) ;WAS THIS BLOCK CHANGED? CLEARM (T2) ;YES, CLEAR THE FLAG JUMPE S2,WRTI.3 ;IF NOT, KEEP LOOPING MOVEI S2,FSSBKS ;GET WORDS/BLOCK IMUL S2,T1 ;MAKE OFFSET INTO INDEX ADD S2,INDEX ;MAKE ABSOLUTE ADDRESS HRLI S2,FSSBKS ;MAKE S2, AND IO-POINTER MOVEI S1,FSSFIB(T1) ;GET THE DPA FOR THE BLOCK MOVEI T4,FSSBPS ;GET NUMBER OF BLOCKS/SECTION IMUL T4,T3 ;GET BASE BLOCK # FOR THIS SEC ADD S1,T4 ;ADD IT IN PUSHJ P,I$WRIT## ;WRITE THEM OUT WRTI.3: AOS T2 ;AOS A POINTER CAIGE T1,FSSNIB-1 ;GOT ALL THE BLOCKS? AOJA T1,WRTI.2 ;NO, LOOP CAIGE T3,FSSMNS-1 ;GOT ALL THE SECTIONS? AOJA T3,WRTI.1 ;NO, LOOP POPJ P, ;YES, RETURN SUBTTL MRKIDX -- Routine to mark INDEX blocks to write ;MRKIDX IS CALLED TO MARK AN INDEX BLOCK AS HAVING BEEN CHANGED. ; CALL WITH THE DPA WHICH HAS CHANGED. ; ;MRKIDX ALWAYS MARKS THE FIRST INDEX BLOCK IN THE SECTION AS HAVING ; BEEN CHANGED, SINCE THE REQUEST COUNT IS THERE. MRKIDX: PUSH P,T1 ;SAVE T1 PUSHJ P,VALDPA ;INSURE A CORRECT DPA MOVE T1,INDTAB(S1) ;AND GET ADR OF IT'S INDEX MOVE S1,S2 ;COPY OFFSET INTO S1 IDIVI S1,FSSBKS ;CONVERT IT TO A BLOCK SETOM FSSFIB(T1) ;MARK THE FIRST BLOCK ADD T1,S1 ;ADD THE BLOCK NUMBER IN SETOM FSSFIB(T1) ;AND MARK THE BLOCK POP P,T1 ;RESTORE T1 POPJ P, ;AND RETURN SUBTTL Utility Routines ; GETIPG -- GET A ZEROED PAGE FOR AN INDEX ; VALDPA -- VALIDATE A DPA GIVEN AS AN ARGUMENT TO THE FAILSOFT ROUTINES SUBTTL GETIPG -- Get a zeroed page for an index ;GETIPG CALLS M$ACQP TO GET A FREE PAGE, ZEROES IT OUT AND RETURNS ; THE ADDRESS OF THE FIRST WORD OF THE PAGE IN S1. GETIPG: SAVE AP ;SAVE AP PUSHJ P,M$ACQP## ;GET A PAGE PG2ADR AP ;MAKE IT AN ADDRESS MOVE S1,AP ;GET ARG IN S1 PUSHJ P,.ZPAGA## ;ZERO IT MOVE S1,AP ;RETURN ADDRESS IN S1 POPJ P, ;AND RETURN SUBTTL VALDPA -- Validate a DPA ;VALDPA IS CALLED WITH S1 AS A DPA GIVEN AS AN ARGUMENT TO THE FAILSOFT ; SYSTEM ROUTINES. IF THE DPA IS INVALID, A STOPCD RESULTS, ; OTHERWISE, S1 IS RETURNED AS THE CORRECT SECTION NUMBER FOR THAT ; DPA AND S2 IS THE OFFSET INTO THAT SECTION. VALDPA: MOVEM S1,VALD.A ;SAVE IN CASE OF STOPCD IDIVI S1,FSSBPS ;S1 = SECTION NUMBER, S2 = OFFSET CAIL S1,FSSMNS ;SECTION TOO LARGE STOPCD(DTL,FATAL) ;++DPA TOO LARGE CAIGE S2,FSSFDB ;BELOW THE FIRST DATA BLOCK STOPCD(DTS,FATAL) ;++DPA TOO SMALL POPJ P, ;RETURN WITH S1 AND S2 SET VALD.A: BLOCK 1 ;LOOK HERE IF A STOPCD RESULTED END