Google
 

Trailing-Edge - PDP-10 Archives - bb-v895a-bm_tops20_v41_2020_dist_2of2 - language-sources/qsrfss.mac
There are 31 other files named qsrfss.mac in the archive. Click here to see a list.
	TITLE	QSRFSS  --  Failsoft System for QUASAR

;
;
;        COPYRIGHT (c) 1975,1976,1977,1978,1979,1980,1981,1982
;                    DIGITAL EQUIPMENT CORPORATION
;
;     THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY  BE  USED
;     AND COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE
;     AND WITH THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE.   THIS
;     SOFTWARE  OR ANY OTHER COPIES THEREOF MAY NOT BE PROVIDED OR
;     OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON.  NO  TITLE  TO
;     AND OWNERSHIP OF THE SOFTWARE IS HEREBY TRANSFERRED.
;
;     THE INFORMATION  IN  THIS  SOFTWARE  IS  SUBJECT  TO  CHANGE
;     WITHOUT  NOTICE  AND SHOULD NOT BE CONSTRUED AS A COMMITMENT
;     BY DIGITAL EQUIPMENT CORPORATION.
;
;     DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY
;     OF  ITS  SOFTWARE  ON  EQUIPMENT  WHICH  IS  NOT SUPPLIED BY
;     DIGITAL.

	SEARCH	QSRMAC,GLXMAC		;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.
SUBTTL	Description of Failsoft Files

COMMENT	?


The QUASAR failsoft file is organized in 512 block sections (where the
term 'block' is an operating system dependent quantity).  Each section
consists  of a set  of 'index' blocks followed by a set of data blocks
as shown in the following diagram.

     !=======================================================!
     !                                                       !
     !       INDEX AND UNUSED BLOCKS FOR THIS SECTION        !
     !                                                       !
     !                                                       !
     !-------------------------------------------------------!
     !                                                       !
     !                                                       !
     /             DATA BLOCKS FOR THIS SECTION              /
     /                                                       /
     /                                                       /
     !                                                       !
     !                                                       !
     !=======================================================!


Block 0 of each  section is unused.   The index  is arranged  with one word
per data block such that word 'n' of the index  represents block 'n' of the
section (given the 'same' counting origin).  Word 7 of the index represents
block 7 of the section, for example, but only if the counting origin is the
same i.e. if blocks are counted starting at 0, then so must index words.



     !=======================================================!
     !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


;TABLE OF REBUILD ROUTINES

REBTBL:	$BUILD	3
	  $SET(%RBBAT,,Q$CRER##)
	  $SET(%RBDEL,,Q$DLFR##)
	$EOB
SUBTTL	Global Routines

;THE FOLLOWING ARE GLOBAL ENTRY POINTS IN QSRFSS

	INTERN	F$INIT			;INITIALIZE THE FAILSOFT SYSTEM
	INTERN	F$WRRQ			;WRITE OUT A BATCH REQUEST
	INTERN	F$FSRQ			;FAILSOFT 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?
	$STOP(WQV,Wrong version of master queue file)


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?
	$RETT				;NO, RETURN
	PUSHJ	P,REBILD		;REBUILD THIS SECTION
	CAIGE	P1,FSSMNS-1		;GOT THEM ALL?
	AOJA	P1,INIT.2		;NO, LOOP
	$RETT				;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
	JUMPE	P1,.RETT		;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	S2,0(P2)		;GET THE NEXT ENTRY
REBI.2:	JRST	REBI.3			;ZERO, GO ON TO NEXT
	AOJE	S2,REBI.3		;-1 MEANS CONTINUATION, IGNORE
	HLRZ	P4,S2			;GET THE REBUILD CODE
	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	S2,P3			;PUT THE DPA IN S2
	PUSHJ	P,@REBTBL(P4)		;DISPATCH THE MESSAGE
	SKIPE	G$ERR##			;CHECK FOR ERROR
	$STOP(RRF,Rebuild Routine Failed)
	MOVE	S1,REBI.D		;GET THE ADDRESS OF THE REQEST
	ADR2PG	S1			;CONVERT TO A PAGE
	PUSHJ	P,M%RELP		;RELEASE THE PAGE
	SOSG	P1,REBI.B		;DECREMENT AND LOAD REQUEST CNT
	$RETT				;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
	$STOP(RCW,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:	LOAD	S2,.MSTYP(S1),MS.CNT	;GET THE MESSAGE LENGTH
	HRL	S1,S2			;GET LEN,,ADR
	MOVX	S2,%RBBAT		;LOAD THE REBUILD CODE
	PJRST	F$FSRQ			;AND FAILSOFT THE REQUEST
SUBTTL	F$FSRQ  --  Failsoft a request

;F$FSRQ is the routine to failsoft a given request (i.e. remember it in
;	the failsoft file.
;
;Call:	S1/  length of request ,, address of request
;	S2/  rebuild code
;
;T Ret:	S1/  the DPA  (i.e. the handle to reference the request)

F$FSRQ:	MOVEM	S1,FSRQ.A		;SAVE THE LEN,,ADR
	HLRZS	S1			;GET 0,,LEN
	PUSHJ	P,GETDPA		;GET A DPA
	MOVEM	S1,FSRQ.B		;SAVE THE DPA
	MOVE	S2,FSRQ.A		;GET REQUEST POINTER
	PUSHJ	P,I$WRIT##		;WRITE IT OUT
	PUSHJ	P,WRTIDX		;WRITE THE INDEX OUT
	MOVE	S1,FSRQ.B		;GET THE DPA
	$RETT				;AND RETURN

FSRQ.A:	BLOCK	1			;LEN,, ADR
FSRQ.B:	BLOCK	1			;THE DPA
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
	PUSHJ	P,M%ACQP		;GET A PAGE
	PG2ADR	S1			;MAKE AN ADDRESS
	MOVEM	S1,RDRQ.A		;STORE ADDRESS FOR CALLER
	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
	$RETT				;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
	$STOP(TMS,TOO MANY SECTIONS)
	JUMPE	T1,REDI.2		;IF BRAND NEW, CREATE IT
	CLEAR	T2,			;ELSE, CLEAR A COUNTER

REDI.1:	PUSHJ	P,M%ACQP		;GET A PAGE
	PG2ADR	S1			;CONVERT TO AN ADDRESS
	MOVEM	S1,INDTAB(T2)		;AND SAVE THE ADDRESS
	MOVE	S2,S1			;COPY FOR READ BELOW
	MOVEI	S1,FSSBPS		;GET BLOCKS/SECTION
	IMULI	S1,(T2)			;*<SECTION-1>
	ADDI	S1,FSSFIB		;+FIRST BLOCK = DPA
	HRLI	S2,FSSWPI		;WORDS/INDEX,,ADDRESS
	PUSHJ	P,I$READ##		;AND READ IT
	SOJLE	T1,.RETT		;RETURN IF DONE
	AOJA	T2,REDI.1		;ELSE LOOP

;HERE ON A BRAND NEW FILE
;
REDI.2:	PUSHJ	P,M%ACQP		;GET AN INDEX PAGE
	PG2ADR	S1			;TO AN ADDRESS
	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

;GETDPA is called to allocated space for a request in the failsoft file.
;	It performs the following functions:
;		1)FIND FAILSOFT SPACE AND MARK IT IN USE
;		2)MARK INDEX BLOCKS FOR WRITING
;		3)INCREMENT REQUEST COUNT
;
;Call:	S1/  length of the request
;	S2/  rebuild code
;
;T Ret:	S1/  DPA

GETDPA:	PUSHJ	P,.SAVE2		;SAVE P1
	CLEAR	P1,			;AND CLEAR IT
	MOVEM	S1,GETD.A		;SAVE NUMBER OF WORDS NEEDED
	MOVEM	S2,GETD.D		;SAVE REBUILD CODE
	SKIPLE	S1			;MAKE SURE IT'S REASONABLE
	CAILE	S1,1000			;AS BEING NOT TOO SMALL OR TOO LARGE
	$STOP(BRS,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,M%ACQP		;GET AN INDEX PAGE
	PG2ADR	S1			;TO AN ADDRESS
	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
	ADDI	S1,FSSFIB		;ADD OFFSET TO FIRST INDEX BLOCK
	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
	JUMPT	GETD.3			;GOT THEM!!
	CAIGE	P1,FSSMNS-1		;NO, ANY MORE INDICES?
	AOJA	P1,GETD.1		;YUP, LOOP
	$STOP(NMF,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.D		;GET REBUILD CODE,,0
	HRR	S1,GETD.A		;GET CODE,,#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,.RETT		;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
GETD.D:	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.
;TRUE   RETURN WITH S1 CONTAINING THE
;	OFFSET OF THE FIRST WORD OF THE GROUP FOUND
;FALSE RETURN:	SPACE IS NOT AVAILABLE

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.3		;YES, ALL WE NEED?
	CAMGE	T1,T2			;NO, ANYTHING ELSE TO SEARCH?
	AOJA	T1,SRHI.1		;YES, LOOP
	$RETF				;NO, RETURN FALSE

;
;HERE IF WE FIND A NON-ZERO WORD
;
SRHI.2:	CAMGE	T1,T2			;REACHED THE END?
	AOSA	T1			;NO, BUMP THE POINTER AND SKIP
	$RETF				;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 WHEN WE FIND "N" CONSECUTIVE ZEROS.  S1 CONTAINS THE "FIRST ZERO".
;SUBTRACT THE BASE ADDRESS AND RETURN THE OFFSET.
;
SRHI.3:	SUB	S1,INDEX		;SUBTRACT THE ADR OF THE INDEX
	$RETT				;AND TAKE A GOOD 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:	PUSHJ	P,.SAVE2		;SAVE P1 AND P2
	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
	HRRZ	P1,(S2)			;GET NUMBER OF WORDS IN ENTRY
	ADDI	P1,FSSBKS-1		;ROUND UP TO A BLOCK
	IDIVI	P1,FSSBKS		;GET NUMBER OF BLOCKS
	MOVEM	P1,CLRD.B		;AND SAVE IT

CLRD.1:	SKIPN	(S2)			;MAKE SURE IT WAS IN USE
	$STOP(CUD,CLEARING UNUSED DPA)
	CLEARM	(S2)			;CLEAR A WORD
	SOJLE	P1,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?
	$STOP(RCN,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,.RETT		;RETURN IF GOOD
	$STOP(FUD,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,.RETT		;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
	$RETT				;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
	$RETT				;AND RETURN
SUBTTL	Utility Routines

;	VALDPA  --	VALIDATE A DPA GIVEN AS AN ARGUMENT TO THE FAILSOFT ROUTINES
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
	  $STOP(DTL,DPA TOO LARGE)
	CAIGE	S2,FSSFDB		;BELOW THE FIRST DATA BLOCK
	  $STOP(DTS,DPA TOO SMALL)
	$RETT				;RETURN WITH S1 & S2 SET UP

VALD.A:	BLOCK	1			;LOOK HERE IF A STOPCD RESULTED
	END