Trailing-Edge
-
PDP-10 Archives
-
BB-D868C-BM
-
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
; 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