Google
 

Trailing-Edge - PDP-10 Archives - bb-d868b-bm_tops20_v3a_2020_dist - 3a-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
SUBTTL	Larry Samberg	13 Nov 77




;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1974, 1975, 1976, 1977, 1978 BY
;	DIGITAL EQUIPMENT CORPORATION, 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)			;*<SECTION-1>
	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 FIRST BLOCK
	ADDI	S1,FSSFIB		;AND MAKE INTO DPA OF 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
	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