                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Module: Spr1.B1
;>
;>      This module contains those sparing routines that must
;>      be located in bank1.
;>
;>      PROCEDURE Init_SprTbl
;>      PROCEDURE Load_SprTbl
;>      PROCEDURE SprChkSum
;>      FUNCTION Chk_SprChk
;>      FUNCTION Spr( SpareTableIndex : BYTE { !r8 } ) : 3 BYTES { !rC:E }
;>      PROCEDURE UpDate_SprTbl
;>      FUNCTION Chk_PassWord : BOOLEAN
;>      PROCEDURE Load_PassWord( Destination : PTR { !!rE } )
;>      PROCEDURE SpareCount( 2 BITS { !r0/Bits 1:0 } )
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Procedure: Init_SprTbl
;>
;>      BANK 1 PROCEDURE
;>
;>      This procedure initializes the spare table. It assumes
;>      that there is NO spare table on disk.
;>
;>      Inputs:
;>              FormatOffset : BYTE { !r4 }
;>              FormatInterLeave : BYTE { !r5 }
;>
;>      Outputs: { none }
;>
;>      Algorithm:
;>
;>      BEGIN
;>       SparePw1 := $F0783C1E
;>       SpareTmStmp := 0
;>       FOR i := 0 TO Length( SegPtrArray ) - 1 DO
;>        SegPtrArray[ i ].Nil := True
;>        SegPtrArray[ i ].Ptr := 0
;>       SpareCount := 0
;>       BadCount := 0
;>       FOR i := 0 TO Length( SpareBitMap ) - 1 DO
;>        SpareBitMap[ i ] := 0
;>       FOR i := 0 TO 1 DO
;>        AddSpare( SprTbl_Type, Spare, GetNewSpare( Spr( i ) ), Spr( i ) )
;>       SparePw2 := $F0783C1E
;>       UpDate_SprTbl
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN

Init_SprTbl:
                 Ld     !r2,#.HIBYTE. SpareArray
                 Ld     !r3,#.LOWBYTE. SpareArray
                Call    ZeroBlock
                
                Ld      !rE,#.HIBYTE. SparePw1
                Ld      !rF,#.LOWBYTE. SparePw1
                Call    Load_PassWord ;load SparePw1
                
                Ld      !r2,#.HIBYTE. FmtOffset
                Ld      !r3,#.LOWBYTE. FmtOffset
                
                Lde     @!!r2,!r4 ;store offset value
                Incw    !!r2
                Lde     @!!r2,!r5 ;store interleave value
                Incw    !!r2
                
                Ld      !r0,#Nil
                Ld      !r1,#( SprCount - SegPtrArray )
I_S_Tbl_Lp2:    Lde     @!!r2,!r0
                Incw    !!r2
                Djnz    !r1,I_S_Tbl_Lp2
                
                Ld      !r0,#$00
                Ld      !r4,#.HIBYTE. ( SpareCheck - SprCount )
                Ld      !r5,#.LOWBYTE. ( SpareCheck - SprCount )
I_S_Tbl_Lp4:    Lde     @!!r2,!r0
                Incw    !!r2
                Decw    !!r4
                Jr      Nz,I_S_Tbl_Lp4
                
                Ld      Data_Type,#SprTbl_Type
                Ld      !r5,#2 ;create two tables
                Clr     !r8
Create_Tbl:     Call    Spr
                 Ld     !r2,#.HIBYTE. GetNewSpare
                 Ld     !r3,#.LOWBYTE. GetNewSpare
                Call    Bank_Call
                Push    !r8 ;save counter
                 Ld     !rF,!r0
                 Ld     !r8,#SprTbl_Type
                 Or     !r8,#Spare
                 Ld     !r2,#.HIBYTE. AddSpare
                 Ld     !r3,#.LOWBYTE. AddSpare
                Call    Bank_Call
                Pop     !r8
                Inc     !r8 ;go to next table
                Djnz    !r5,Create_Tbl
                
                Ld      !r2,#.HIBYTE. Map_Table
                Ld      !r3,#.LOWBYTE. Map_Table
                Ld      !r1,#NbrSctrs
                Ld      !r0,#0
I_Map_Lp:       Lde     @!!r2,!r0
                Incw    !!r2
                Add     !r0,#Map_Dflt
                Cp      !r0,#NbrSctrs
                Jr      Lt,I_Map_Lp2
                Sub     !r0,#NbrSctrs
I_Map_Lp2:      Djnz    !r1,I_Map_Lp
                
                Ld      !rE,#.HIBYTE. SparePw2
                Ld      !rF,#.LOWBYTE. SparePw2
                Call    Load_PassWord
                
                Call    UpDate_SprTbl
                Jp      Bank_Ret

                .LSTOFF
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Procedure: Load_SprTbl
;>
;>      BANK 1 PROCEDURE
;>
;>      This procedure loads the spare table from disk. The table is 
;>      found by a linear search of all the spare blocks until a block
;>      is found where both the Spare Table Identifier field is present
;>      and the internal passwords and check byte are valid.
;>
;>      Inputs: { none }
;>
;>      Outputs: { none }
;>
;>      Algorithm:
;>
;>      BEGIN
;>       Seek_Type := Access_Offset
;>       InterLeaveFactor := Find_InterLeave
;>       Found := False
;>       Count := 0
;>       i := NumberOfSpareBlocks
;>       WHILE ( i > 0 ) AND ( Count < 2 ) DO
;>              Seek( CnvrtLogical( MulR0_m( i ) ) )
;>              J := 0
;>              Sector := 0
;>              WHILE NOT( Found ) AND ( j < NbrSctrs ) DO
;>                IF ReadCommon
;>                 THEN
;>                  IF ( BlockID = SprTblID ) AND 
;>                     ( PassWord1 = PassWord2 = PassWord ) AND
;>                     ( CheckByte is valid )
;>                   THEN
;>                        Found := True
;>                        Count := Count + 1
;>                        IF ( Count >   1 )
;>                         THEN
;>                          IF ( SpareTable.RunNumber < ReadBuffer.RunNumber )
;>                           THEN MoveBlock( SpareTable, ReadBuffer )
;>                         ELSE MoveBlock( SpareTable, ReadBuffer )
;>                 ELSE
;>                  IF ( RdErrCnt < 10 )
;>                   THEN
;>                    MoveBlock( ReadBuffer, Buffer2 )
;>                    IF ( BlockID = SprTblID ) AND 
;>                       ( PassWord1 = PassWord2 = PassWord ) AND
;>                       ( CheckByte is valid )
;>                     THEN
;>                          Found := True
;>                          Count := Count + 1
;>                          IF ( Count >     1 )
;>                           THEN
;>                            IF ( SpareTable.RunNumber < ReadBuffer.RunNumber )
;>                             THEN MoveBlock( SpareTable, ReadBuffer )
;>                           ELSE MoveBlock( SpareTable, ReadBuffer )
;>                 j := j + 1
;>                 Sector := ( Sector + InterLeaveFactor ) MOD NbrSctrs
;>               i := i - 1
;>        IF NOT( Found )
;>         THEN Abort
;>         ELSE
;>              UpDate_SprTbl
;>              Park
;>              SlfTst_Result.NoSpareTable := False
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN

Load_SprTbl:
                Ld      !r5,#76 ;i := NumberOfSpareBlocks
                Clr     !r4     ;SprTbl_Found := False
                Ld      DataType,#User_Type
                
L_SprTbl_Lp:    Call    Ext_Push
                 Ld      !r0,!r5
                Call    MulR0_m
                Call    Get_Cyl_H_S
                Ld      Seek_Type,#Access
                Call    Seek
                Call    Ext_Pop
                
                Ld      !r6,#NbrSctrs ;check the entire track
                Clr     Sector ;starting with sector 0
                
L_Rd_Lp:        Push    !r4
                Push    !r5
                Push    !r6
                 Ld     !r2,#.HIBYTE. RdBlk_Vector
                 Ld     !r3,#.LOWBYTE. RdBlk_Vector
                Call    Bank_Call
                Pop     !r6
                Pop     !r5
                Pop     !r4
                Jr      Nz,Chk_SprTbl
                
                Ld      !r0,RdErrCnt
                And     !r0,#$0F ;mask unwanted status
                Cp      !r0,#10 ;check for any successful reads
                Jr      Ge,L_SprTbl_More
                
                Call    Buf2_To_RBuf ;get good data back into ReadBuffer
                Jr      Chk_SprTbl
                 
L_SprTbl_More:  Inc     Sector
                Djnz    !r6,L_Rd_Lp
                Djnz    !r5,L_SprTbl_Lp
                
                Or      !r4,!r4 ;check if any spare table found
                Jr      Nz,L_Spr_End
                
                Call    Abort
                
Chk_SprTbl:      Ld     ScrReg2,#.HIBYTE. ( RBuffer1+BlockID )
                 Ld     ScrReg3,#.LOWBYTE. ( RBuffer1+BlockID )
                Call    Chk_PassWord
                Jr      Z,L_SprTbl_More
                
                 Ld     ScrReg2,#.HIBYTE. RBuffer1
                 Ld     ScrReg3,#.LOWBYTE. RBuffer1
                Call    Chk_PassWord
                Jr      Z,L_SprTbl_More
                
                Ld      !r2,#.HIBYTE. ( RBuffer1+SpareCheck-SpareArray )
                Ld      !r3,#.LOWBYTE. ( RBuffer1+SpareCheck-SpareArray )
                Lde     !r0,@!!r2 ;check possible check byte
                Incw    !!r2
                Lde     !r1,@!!r2
                
                Srp     #Wrk_Scr
                 Ld     !rC,#.HIBYTE. RBuffer1
                 Ld     !rD,#.LOWBYTE. RBuffer1
                Call    SprChk2
                
                Srp     #Wrk_Sys
                Call    Chk_Spr2
                Jr      Z,L_SprTbl_More
                
                Or      !r4,!r4 ;check for a SpareTable already found
                Jr      Z,L_Spr_Move
                 
                Srp     #Wrk_Scr
                 Ld     !r6,#.HIBYTE. SpareTmStmp
                 Ld     !r7,#.LOWBYTE. SpareTmStmp
                 Ld     !r4,#ScrReg0
                Call    Ld_TmStmp
                 Ld     !r6,#.HIBYTE. ( RBuffer1+SpareTmStmp-SpareArray )
                 Ld     !r7,#.LOWBYTE. ( RBuffer1+SpareTmStmp-SpareArray )
                 Ld     !r4,#ScrRegC
                Call    Ld_TmStmp
                Sub     !r3,!rF
                Sbc     !r2,!rE
                Sbc     !r1,!rD
                Sbc     !r0,!rC
                Srp     #Wrk_Sys
                Jr      Ge,L_Spr_Inc
                Dec     !r4     ;account for old, bogus spare table
                
L_Spr_Move:     Call    RBuf_To_Spr
                
L_Spr_Inc:      Inc     !r4     ;note the arrival of a SpareTable
                Cp      !r4,#2  ;see if that's all there is
                Jr      Nz,L_SprTbl_More
                
L_Spr_End:      Call    UpDate_SprTbl
                And     SlfTst_Result,#$FF-No_SprTbl
                
                 Ld     !r2,#.HIBYTE. Park_Heads
                 Ld     !r3,#.LOWBYTE. Park_Heads
                Call    Bank_Call
                Jp      Bank_Ret
                
;*******************************

Ld_TmStmp:      Ld     !r5,#4 ;load 4 bytes
Ld_Tm_Lp:       Ldei   @!r4,@!!r6
                Djnz   !r5,Ld_Tm_Lp
                Ret
                 
                .LSTOFF
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Procedure: SprChkSum
;>
;>      This procedure calculates a 16-bit checksum over the contents
;>      of the spare table, and stores the sum within the spare table.
;>
;>      Inputs: { none }
;>
;>      Outputs: { none }
;>
;>      Side Effect: ScrReg1, ScrReg2 hold the calculated check byte on return
;>
;>      Algorithm:
;>
;>      BEGIN
;>       Sum := 0
;>       SumPtr := SpareArray
;>       FOR i := 1 TO Length( SpareArray ) DO
;>        Sum := Sum + SpareArray[ i - 1 ]
;>       SpareArray.CheckSum := Sum
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN

SprChkSum:
                Ld      !rC,#.HIBYTE. SpareArray
                Ld      !rD,#.LOWBYTE. SpareArray
                
SprChk2:        Ld      !rE,#.HIBYTE. ( SpareCheck - SpareArray )
                Ld      !rF,#.LOWBYTE. ( SpareCheck - SpareArray )
                
                Clr     !r1
                Clr     !r2
                
SprChk_Lp:      Lde     !r0,@!!rC
                Add     !r2,!r0
                Adc     !r1,#0
                Incw    !!rC
                Decw    !!rE
                Jr      Nz,SprChk_Lp
                
                Lde     @!!rC,!r1 ;store hibyte of checksum
                Incw    !!rC
                Lde     @!!rC,!r2 ;store low byte of checksum
                
                Jp      Bank_Ret
                
                .LSTOFF
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Function: Chk_SprChk
;>
;>      This function is responsible for verifying that the checksum
;>      residing in the spare table is correct.
;>
;>      Inputs: { none }
;>
;>      Outputs:
;>              Chk_SprChk : BOOLEAN { zero flag }
;>
;>      Algorithm:
;>
;>      BEGIN
;>       TempSum := SpareTable.CheckSum
;>       SpareTable.CheckSum := SprChkSum
;>       IF ( TempSum = SpareTable.CheckSum )
;>        THEN Chk_SprChk := True
;>        ELSE Chk_SprChk := False
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN

Chk_SprChk:
                Ld      !r2,#.HIBYTE. SpareCheck
                Ld      !r3,#.LOWBYTE. SpareCheck
                Lde     !r0,@!!r2
                Incw    !!r2
                Lde     !r1,@!!r2
                
                 Srp    #Wrk_Scr
                Call    SprChkSum
                 Srp    #Wrk_Sys

Chk_Spr2:       Xor     !r0,ScrReg1 ;side effect: ScrReg2:3 hold new checkyte
                Xor     !r1,ScrReg2
                Or      !r0,!r1
                Clr     !r0
                Jr      Nz,Chk_Spr_End
                
                Ld      !r0,#1
                
Chk_Spr_End:    Or      !r0,!r0 ;set zero flag
                Jp      Bank_Ret
                
                .LSTOFF
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Function: Spr
;>
;>      This function returns the logical block number associated
;>      with the parameter passed in. Because there are only two spare
;>      blocks containing the spare table, this function accepts
;>      only ODD or EVEN input params.
;>
;>      Inputs:
;>              SpareTableIndex : BYTE { !r8 }
;>
;>      Outputs:
;>              Spr : 3 BYTES { !rC:E }
;>
;>      Algorithm:
;>
;>      BEGIN
;>       IF SpareTableIndex is EVEN
;>        THEN Spr := SprBlk0
;>        ELSE Spr := SprBlk1
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN

Spr:
                And     !r8,#$01 ;IF SpareTableIndex is EVEN
                Jr      Nz,Spr_Odd
                
                Ld      !rC,#HiSpr0
                Ld      !rD,#MidSpr0
                Ld      !rE,#LoSpr0
                Jr      Spr_End
                
Spr_Odd:        Ld      !rC,#HiSpr1
                Ld      !rD,#MidSpr1
                Ld      !rE,#LoSpr1
                
Spr_End:        Jp      Bank_Ret

                .LSTOFF
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Procedure: UpDate_SprTbl
;>
;>      This procedure is responsible for updating the spare table
;>      to both of its locations on disk after a change has been made
;>      to the table.
;>
;>      Inputs: { none }
;>
;>      Outputs: { none }
;>
;>      Algorithm:
;>
;>      BEGIN
;>       SpareTmStamp := SpareTmStamp + 1
;>       SprChkSum
;>       ZeroBlock
;>       WBuffer1.BlockID := PassWord
;>       FOR i := 0 TO 1 DO
;>         MoveBlock( WriteBuffer, SpareTable )
;>         TempCyl, TempHead, TempSector := Get_Cyl_H_S( 
;>                                       SrchSpTabl( SpareTable, Spr( i ) ) )
;>         IF table not found in SpareTable THEN Abort
;>         Seek( TempCyl, TempHead, TempSector )
;>         IF NOT( WriteVerify( Conservative ) )
;>          THEN
;>           IF Recovery AND ( WriteVerify.ErrorCode = Ex_ReadErr )
;>            THEN EXIT UpDate_SprTbl
;>            ELSE
;>             ZeroBlock
;>             WriteBlock
;>             MoveBlock( Buffer2, SpareTable )
;>             SpareBlock( True, SpareTable, Write_Op, Spr( i ) )
;>
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN
                
UpDate_SprTbl:  
                Ld      !rC,Cylinder ;save current seek address
                Ld      !rD,Cylinder+1
                Ld      !rE,Head
                Ld      !rF,Sector
                Call    Ext_Push
                
                Ld      !r2,#.HIBYTE. SpareTmStamp
                Ld      !r3,#.LOWBYTE. SpareTmStamp
                Ld      !r0,#Wrk_Sys+$C
                Ld      !r1,#4 ;get 4 bytes
UpDate_1:       Ldei    @!r0,@!!r2
                Djnz    !r1,UpDate_1
                Add     !rF,#1 ;increment the count
                Adc     !rE,#0
                Adc     !rD,#0
                Adc     !rC,#0
                Ld      !r0,#Wrk_Sys+$C
                Ld      !r1,#4 ;move 4 bytes
                Ld      !r2,#.HIBYTE. SpareTmStamp
                Ld      !r3,#.LOWBYTE. SpareTmStamp
UpDate_2:       Ldei    @!!r2,@!r0
                Djnz    !r1,UpDate_2
                
                Call    SprChkSum
                
                Ld      !r4,#2 ;write the table to the disk twice
                Clr     !r5 ;spare table index
                
SprB_Lp:        Call    Spr_To_WrBuf
                
                 Ld     !rE,#.HIBYTE. ( WBuffer1 + BlockID )
                 Ld     !rF,#.LOWBYTE. ( WBuffer1 + BlockID )
                Call    Load_PassWord
                
                 Ld     !r8,!r5
                Call    Spr
                
                Ld      Data_Type,#Spr_Tbl_Type
                 Ld     !r2,#.HIBYTE. CnvrtLogical
                 Ld     !r3,#.LOWBYTE. CnvrtLogical
                Call    Bank_Call
                Jr      Nz,SprB_Seek
                
                Call    Abort
                
SprB_Seek:      Ld      Seek_Type,#Access_Offset
                Call    Seek
                
                 Ld     BlkStat,#S_Block ;say that we've got a spare block
                 Ld     Data_Type,#SprTbl_Type ;ditto
                 Ld     RdErrCnt,#10 ;prime the counter for write error
                 Ld     !r2,#.HIBYTE. WrVer_Common
                 Ld     !r3,#.LOWBYTE. WrVer_Common
                Call    Bank_Call
                Jr      Nz,Spr_Next
                
                Tm      Excpt_Stat,#Recovery ;IF Recovery THEN ...
                Jr      Nz,Rcvr_SprTbl
                
                Call    Abort
                
Rcvr_SprTbl:    Ld      !r1,RdErrCnt ;check for noisy read
                And     !r1,#$0F
                Cp      !r1,#SprThresh
                Jr      Le,Spr_Next
                
                 Ld     !r2,#.HIBYTE. WBuffer1
                 Ld     !r3,#.LOWBYTE. WBuffer1
                Call    ZeroBlock
                
                 Ld     !r2,#.HIBYTE. Wr_Common
                 Ld     !r3,#.LOWBYTE. Wr_Common
                Call    Bank_Call
                
                 Ld     !r8,!r5
                 Call   Spr
                 Ld     !r2,#.HIBYTE. SprEnter
                 Ld     !r3,#.LOWBYTE. SprEnter
                Call    Bank_Call
                Jr      Z,Rcvr_SprTbl
                
Spr_Next:       Inc     !r5 ;do next table
                Djnz    !r4,SprB_Lp
                
                Call    Ext_Pop
                Call    Seek ;get back to original seek address
                Jp      Bank_Ret
                
                .LSTOFF
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Function: Chk_PassWord
;>
;>      This function is responsible for checking if the 32 bits
;>      pointed to by the input parameter match with the controller's
;>      32 bit password.
;>
;>      Inputs:
;>              PassWordPtr : PTR { ScrReg2:3 }
;>
;>      Outputs:
;>              Chk_PassWord : BOOLEAN { zero flag }
;>
;>      Algoritm:
;>
;>      BEGIN
;>       IF ( (PassWordPtr) = PassWord )
;>        THEN Chk_PassWord := True
;>        ELSE Chk_PassWord := False
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN
                
Chk_PassWord:
                Srp     #Wrk_Scr
                Ld      !r4,#4 ;check 4 bytes

                Ld      !rE,#.HIBYTE. PassWord
                Ld      !rF,#.LOWBYTE. PassWord
                
Chk_P_Lp:       Ldc     !r0,@!!rE ;get a byte of the password
                Incw    !!rE
                Lde     !r1,@!!r2 ;get a byte of test string
                Incw    !!r2
                Cp      !r0,!r1
                Clr     !r0 ;assume failure
                Jr      Nz,Chk_P_End
                Djnz    !r4,Chk_P_Lp
                
                Ld      !r0,#1
                
Chk_P_End:      Or      !r0,!r0 ;set flags
                Srp     #Wrk_Sys
                Jp      Bank_Ret
                
                .LSTOFF
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Procedure: Load_PassWord
;>
;>      This procedure loads the 32-bit password into the memory
;>      location pointed to by the input parameter.
;>
;>      Inputs:
;>              Destination : PTR { !!rE }
;>
;>      Outputs: { none }
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN

Load_PassWord:
                Ld     !r2,#.HIBYTE. PassWord
                Ld     !r3,#.LOWBYTE. PassWord
                Ld     !r1,#4 ;move 4 bytes
                 
Lpw_Lp:         Ldc     !r0,@!!r2
                Lde     @!!rE,!r0
                Incw    !!r2
                Incw    !!rE
                Djnz    !r1,Lpw_Lp
                
                Jp      Bank_Ret
                
                .LSTOFF
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Procedure: SpareCount
;>
;>      This procedure is responsible for incrementing/decrementing
;>      the Spare/Bad Block count. If the total count exceeds
;>      MaxSpares-5 then a status bit is set for this command only.
;>
;>      Inputs:
;>              Command : 2 BITS { !r0/Bits 1:0 }
;>
;>      Outputs: { none }
;>
;>      Algorithm:
;>
;>      BEGIN
;>       CASE Command OF
;>        0 : Increment the spare count
;>        1 : Increment the bad block count
;>        2 : Decrement the bad block count
;>       OTHERWISE Abort
;>
;>       IF ( SpareCount+BadBlockCount >= MaxSpares-5 )
;>        THEN 
;>              Excpt_Status.SprTbl_Warn := True
;>              SetStatus( SprBlk_Warn )
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN

SpareCount:
                Ld      !r1,!r0 ;get command
                And     !r1,#$FC ;check for illegal command
                Jr      Z,SprCnt_1
                
                Ld      !r9,!r0
                Call    Abort
                
SprCnt_1:       Ld      !r2,#.HIBYTE. SprCount
                Ld      !r3,#.LOWBYTE. SprCount
                Lde     !r1,@!!r2 ;assume spare count increment
                Inc     !r1
                
                Cp      !r0,#0 ;check for Inc_SpareCount
                Jr      Z,S_C_Spare
                
                Incw    !!r2 ;get address of BadCount
                Lde     !r1,@!!r2 ;get bad block count
                
                Cp      !r0,#01 ;check for Inc_BadBlock
                Jr      Z,S_C_BadInc
                
                Dec     !r1 ;otherwise Decrement bad block count
                Jr      S_C_BadEnd
                
S_C_BadInc:     Inc     !r1
S_C_BadEnd:     Lde     @!!r2,!r1 ;store new count
                Jr      SprCnt_End
                
S_C_Spare:      Lde     @!!r2,!r1 ;store new count
SprCnt_End:     Call    Chk_SprCnt
SprCnt_Ret:     Jp      Bank_Ret


Chk_SprCnt:     Ld      !r2,#.HIBYTE. SprCount
                Ld      !r3,#.LOWBYTE. SprCount
                Lde     !r0,@!!r2 ;get spare count
                Incw    !!r2
                Lde     !r1,@!!r2 ;get bad count
                Add     !r0,!r1 ;get total
                Cp      !r0,#71 ;check for spare count overflow
                Jr      Lt,Chk_Spr_Ret
                
                Or      Excpt_Stat,#SprTbl_Warn
                Call    SS_SprWarn
                
Chk_Spr_Ret:    Jp      Bank_Ret

                .LSTOFF
                
                
