;*** Needs to be Tested and Debugged ****

;C02 library block.h02 assembly language subroutines
;Requires External Zero Page Variables 
;BLKLO, BLKHI, DSTPTR, SRCPTR
;External Variables 
;BLKSLO, BLKSHI, BLKELO, BLKEHI, BLKLEN, TEMP0, TEMP1, TEMP2
;External Routines 
;MEMCMP, MEMCPY, MEMSRC, RESDST, SAVDST, SETDST, SETSRC, SETSRD

        SUBROUTINE  BLOCK

;blkbgn(&b) - Set Block Start Address
;Args: X,Y = Address
;Sets: BLKSLO, BLKSHI = Block Start Address
;Affects: Z, N
BLKBGN: STX BLKSLO  ;Save Block Start LSB
        STY BLKSHI  ;Save Block Start MSB
        RTS

;blkend(&b) - Set Block End Address (+1)
;Args: X,Y = Address
;Sets: BLKELO, BLKEHI = Block End Address
;Affects: Z, N
BLKEND: STX BLKELO  ;Save Block End LSB
        STY BLKEHI  ;Save Block End MSB
        RTS

;blkrst() - Reset Block Segment Pointer to Start Address
;Uses: BLKSLO, BLKSHI = Block Start Address
;Sets: BLKLO, BLKHI = Block Pointer
;Affects: Z, N
;Returns: X = Block Pointer LSB
;         Y = Block Pointer MSB
BLKRST: LDX BLKSLO    ;Load X with Block Start LSB
        LDY BLKSHI    ;Load Y with Block Start MSB
                      ;and fall into BLKPTR

;blkptr() - Set Block Pointer Address
;Args: X,Y = Address LSB, MSN
;Sets: BLKLO, BLKHI = Block Pointer
;Affects: Z, N
;Returns: X = Block Pointer LSB
;         Y = Block Pointer MSB
BLKPTR: STX BLKLO     ;Store X in Block Pointer LSB
        STY BLKHI     ;Store Y in Block Pointer MSB
        RTS           ;Exit Routine

;blkcpe() - Compare Block Pointer to Block End
;Uses: BLKLO, BLKHI = Block Pointer
;      BLKELO, BLKEHI = Block End Address
;Affects: X,N
;Returns: C=0,Z=0 if Pointer before End
;         C=1,Z=1 if Pointer at End
;         C=1,Z=0 if Pointer after End
BLKCPE: LDX BLKHI       ;Get Block Pointer MSB
        CPX BLKEHI      ;Compare to Block End MSB
        BCC BLKCPX      ;If Pointer Not Less than
        BNE BLKCPX      ;or Equal to End
        LDX BLKLO       ;  Get Block Pointer LSB
        CPX BLKELO      ;  Compare to Block End LSB
BLKCPX: RTS

;blkset(c) - Set All Bytes in Block to Character c
;Args: c - Value to Set all Bytes to
;Uses: BLKSLO, BLKSHI - Block Start Address
;      BLKELO, BLKEHI - Block End Address
;Sets: BLKLO, BLKHI = Start of Block
;Returns: A - Value of Argument n
BLKSET: JSR BLKRST      ;Reset Block Pointer
        LDY #0          ;Initialize Index
BLKSEL: JSR BLKCPE      ;Compare Pointer to Block End
        BCS BLKSEX      ;If Past End, Exit Routine
        STA (BLKLO),Y   ;Store Value at Block Pointer Address
        INC BLKLO       ;Increment Block Pointer LSB
        BNE BLKSEL      ;If Not End of Page, Loop
        INC BLKHI       ;Increment Block Pointer MSB
        BNE BLKSEL      ;If Not End of Memory, Loop
BLKSEX: JMP BLKRST      ;Reset Block Pointer and Return

;blkput(n, &m) - Append n Bytes of m to Block
;Args: n = Number of Bytes to Append
;      m = Array of Bytes to Append
;Uses: BLKELO, BLKEHI - Block End Address
;Sets: DSTPTR = Pointer to Bytes in Block
;      SRCPTR = Pointer to m
;      TEMP0 = Number of Bytes to Append
;Updates: BLKLO, BLKHI = Block Pointer
;Returns: A=$FF - Append Successful
;         A=$00 - Block Overflow 
BLKPUT: JSR MEMSRC    ;Set Source Address & Number of Bytes
        JSR BLKDST    ;Set Destination to Block Pointer
        JMP BLKNCP    ;Move Block Pointer and Copy

;blkget(n, &m) - Read n Bytes of Current Segment into Array m
;Args: A = Number of Bytes to Read 
;      Y,X = Address of Array
;Uses: BLKELO, BLKEHI = Block End Address
;Sets: DSTPTR = Address of Array
;      SRCPTR = Current Pointer in Block
;      TEMP0 = Number of Bytes to Append
;Updates: BLKLO, BLKHI = Next Segment in Block
;Returns: A=$FF - Append Successful
;         A=$00 - Block Overflow 
BLKGET: JSR SETDST      ;Set Destination Address
        JSR MEMSRA      ;Save Number of Bytes to Copy
        JSR BLKSRC      ;Set Source Pointer to Block Pointer
BLKNCP: JSR BLKNXT      ;Move Block Pointer
        BEQ BLKRTS      ;If Past End of Block, Return False
BLKCPY: LDY #0          ;Copy Source To Destination
        JSR MEMCPL      ;
        LDA #$FF        ;Return TRUE
        RTS

;blkmem(n, &m) - Search for n Bytes of m in Block
;Args: n = Number of Bytes to Compare
;      m = Array of Bytes to Search For
;Sets: DSTPTR = Pointer to Segment in Block
;      SRCPTR = Pointer to m
;      TEMP0 = Number of Bytes to Compare
;Returns: A=$FF - Bytes found
;         A=$00 - Bytes not found
BLKMEM: JSR MEMSRC      ;Initialize Source, Index, and Count
        JSR BLKDSS      ;Set Destination Pointer To Block Start
        LDX #DSTPTR     ;Set BLKNXX Pointer to DSTPTR
BLKMEL: LDY #0          ;Initialize Index
        JSR MEMCML      ;Compare Source to Destination
        BEQ BLKTRU      ;If Equal, Exit TRUE
        JSR BLKNXX      ;Move Destination Pointer
        BNE BLKMEL      ;If Not Past Block End, Loop
BLKFLS: LDA #FALSE      ;  Return FALSE
        RTS

;blkseg(n) - Set Block Segment Length
;Args: n - Segment Length
;Sets: TEMP0 = Segment Size
;Returns: A=$FF - Segment Length Successfully Set
;         A=$00 - Error: Segment Length not Set
BLKSEG: STA BLKLEN      ;Store Argument in Block Length
        ORA #0          ;If Segment Length is Zero
        BEQ BLKFLS      ;  Return False
BLKTRU: LDA #TRUE       ;Return TRUE
BLKRTS: RTS

;BLKNXD() - Move Destination Pointer to Next Segment
;Uses: BLKLEN - Block Segment Length
;Updates: DSTPTR, DSTPTR+1 = Block Pointer
;Affects: C,N,Z
;Returns: A=$FF - Destination Pointer Moved
;         A=$00 - Error: Pointer Overflow or Length 0 
BLKNXD: LDX #DSTPTR      ;Set X to Destination Pointer
        JMP BLKNXX      ;and Move to Next Segment
 
;blknxx() - Move Pointer to Next Segment
;Args: X = Zero Page Address of Pointer
;Uses: BLKLEN - Block Segment Length
;Updates: DSTPTR, DSTPTR+1 = Block Pointer
;Affects: C,N,Z
;Returns: A=$FF - Destination Pointer Moved
;         A=$00 - Error: Pointer Overflow or Length 0 
BLKNXX: LDA BLKLEN      ;Get Segment Length
        BEQ BLKRTS      ;If 0 Return False
        CLC      
        ADC 0,X         ;Add to Pointer LSB
        STA 0,X        
        LDA 1,X         ;Add Carry 
        ADC #0          ;to Pointer MSB
        STA 1,X         ;If Destination MSB
        CMP BLKEHI      ;  < Block End MSB
        BCC BLKTRU      ;  Return True
        LDA 0,X         ;If Destination LSB 
        CMP BLKELO      ;  < Block End LSB
        BCC BLKTRU      ;  Return True
        BCS BLKFLS      ;Return False

 ;blknxt(n) - Move Block Pointer to Next Segment
;Uses: BLKLEN - Block Segment Length
;Updates: BLKLO, BLKHI = Block Pointer
;Affects: C,N,Z
;Returns: A=$FF - Destination Pointer Moved
;         A=$00 - Error: Pointer Overflow or Length 0 
BLKNXT: LDA BLKLEN      ;Get Segment Length
        BEQ BLKRTS      ;If 0 Return False
        CLC
        ADC BLKLO       ;Add to Block Pointer LSB
        STA BLKLO
        LDA BLKHI       ;Add Carry
        ADC #0          ;to Block Pointer MSB
        STA BLKHI       ;If Block Pointer MSB
        JSR BLKCPE      ;Compare Pointer to End
        BCC BLKTRU      ;  Return True
        BCS BLKFLS      ;Else Return False

;blkprv(n) - Move Block Pointer to Previous Segment
;Uses: BLKLEN - Block Segment Length
;Updates: BLKLO, BLKHI = Block Pointer
;Affects: C,N,Z
;Returns: A=$FF - Destination Pointer Moved
;         A=$00 - Error: Pointer Underflow or Length 0 
BLKPRV: LDA BLKLEN      ;Get Segment Length
        BEQ BLKRTS      ;If 0 Return False
        LDA BLKLO       ;From Block Pointer LSB
        SEC
        SBC BLKLEN      ;Subtract Segment Length
        STA BLKLO
        LDA BLKHI       ;Subtract Borrow
        SBC #0          ;from Block Pointer MSB
        STA BLKHI       ;If Block Pointer MSB
        CMP BLKEHI      ;  >= Block Start MSB
        BCS BLKTRU      ;  Exit True
        LDA BLKLO       ;Else If Destination LSB
BLKPRL: CMP BLKELO      ;  >= Block End LSB
        BCS BLKTRU      ;  Return True
        BCC BLKFLS      ;Else Return False

;blksrt(&m) - Sort Block 
;Args: m = Array of at least n Bytes for Temporary Storage
;Sets: TEMP1,TEMP2 = Pointer to Array m
;Uses: BLKLO, BLKHI = Block Pointer
;      BLKSLO, BLKSHI = Block Start Address
;      BLKELO, BLKEHI = Block End Address
;      BLKLEN = Block Segment Size
;      DSTPTR = Pointer to Segment in Block
;      SRCPTR = Pointer to Segment in Block
;Affects: A,Y,C,N,Z
BLKSRT: LDA BLKLEN      ;Get Segment Length
        BEQ BLKRTS      ;If 0 Return
        STA TEMP0       ;Else Set Memory Swap Byte Count
        JSR BLKRST      ;Set Block Pointer to Block Start
BLKSRP: LDY #0          ;If First Byte of
        LDA (BLKLO),Y   ;  Current Segment is Null
        BEQ BLKRTS      ;  Return
        JSR BLKSRC      ;Copy Block Pointer to Source Pointer
        JSR BLKDST      ;Copy Block Pointer and Destination Pointer
BLKSRD: JSR BLKNXD      ;Move Destination Pointer
        BCS BLKSRE      ;If Not Past Block End
        LDY #0          ;
        LDA (DSTPTR),Y   ;and Destination String Populated
        BEQ BLKSRE      ;    
        JSR STRCML      ;  Compare Destination String with Source String
        BPL BLKSRD      ;  If Destination < Source
        JSR SETSRD      ;    Set Source Pointer to Destination Pointer
        JMP BLKSRD      ;  Check Next Destination Segment
BLKSRE: LDA SRCPTR+1    ;If Source Pointer
        CMP BLKHI       ;  <> Block Pointer
        BNE BLKSRS
        LDA SRCPTR
        CMP BLKLO
        BEQ BLKSRN 
BLKSRS: JSR BLKSWL      ;  Swap Source and Pointer
BLKSRN: JSR BLKNXT      ;Move Block Pointer
        BNE BLKSRP      ;If Not Past End, Check Next Segment
        RTS             ;Return

;blkstr(&s) - Search for String s in Block and
;             Copy Segment to Destination Array if Found
;Args: Y,X = Address of Search String
;Uses: DSTPTR = Address of Destination Array
;Sets: SRCPTR = Pointer to Segment in Block (if found)
;      TEMP0 = Index within segment
;      TEMP1,TEMP2 = Destination String Pointer
;Affects: Y,C
;Returns: A=$FF,N=1,Z=0 if Found
;         A=$00,N=0,Z=1 if Not Found
BLKSTR: JSR SETSRC      ;Set Source Pointer to Search String
        JSR SAVDST      ;Save Destination Pointer
        JSR GETSRC
        LDA BLKLEN      ;Get Segment Length
        JSR MEMSRC      ;Save Number of Bytes to Copy
        JSR SETDSS      ;Set Destination Pointer to Search String
        LDX BLKSLO      ;Set Source Pointer To Block Start
        LDY BLKSHI
        JSR SETSRC
        LDX #SRCPTR      ;Set BLKNXX Pointer to SRCPTR
BLKSTL: LDY #0          ;Initialize Index
        JSR STRCML      ;Compare Source to Destination
        BEQ BLKSTS      ;If Not Equal
        JSR BLKNXX      ;  Move Source Pointer to Next Segment
        BNE BLKSTL      ;  If Not Past Block End, Loop
        JSR RESDST      ;  Else Restore Destination String and Return
        LDA #$00        ;  and Return FALSE
        RTS             ;Else
BLKSTS: JSR RESDST      ;  Restore Destination Pointer
        JMP BLKCPY      ;  Copy Source to Destination

;blkswp(n, &m) - Swap n Bytes of Array with Block Segment
;Args: n = Number of bytes to swap
;      m = Array to swap bytes from
;Sets: TEMP0 = Number of Bytes to Swap
;Uses: BLKLO, BLKHI = Block Pointer
;      DSTPTR, DSTPTR+1 = Pointer to Temporary Storage Array
;Affects: A,Y,C,N,Z
BLKSWP: JSR MEMSRC      ;Set Source Address and Index
BLKSWL: JSR BLKDST      ;Set Destination Pointer to Block Pointer
        LDY #0          ;Initialize Index
        JMP MEMSWL      ;Swap Bytes

;blksrc() - Set Source Pointer to Block Pointer
;Uses: BLKLO,BLKHI = Block Segment Pointer
;Sets: SRCPTR = Source Array Pointer
;Affects: X,N,Z
;Returns: Y = 0
BLKSRC: LDX BLKLO
        LDY BLKHI
        JMP SETSRC      ;Set Source and Return

;blkdst() - Set Destination Pointer to Block Pointer
;Uses: BLKLO,BLKHI = Block Segment Pointer
;Sets: DSTPTR,DSTPTR+1 = Destination Array Pointer
;Affects: N,Z
;Returns: X = Block Pointer LSB
;         Y = Block Pointer MSB
BLKDST: LDX BLKLO
        LDY BLKHI     
        JMP SETDST      ;Set Destination and Return

;blkdst() - Set Destination Pointer to Block Start
;Uses: BLKSLO,BLKSHI = Block Start Address
;Sets: DSTPTR,DSTPTR+1 = Destination Array Pointer
;Affects: N,Z
;Returns: X = Block Start LSB
;         Y = Block Start MSB
BLKDSS: LDX BLKSLO
        LDY BLKSHI     
        JMP SETDST      ;Set Destination and Return

;Block Debug Routine
BLKDBG: LDA DSTPTR+1
        CMP #$43
        BNE BLKDBX      
        LDA DSTPTR
        CMP #$57
        BNE BLKDBX      
        NOP             ;Break Point
BLKDBX: RTS

;Print Destination Address
BLKPDA  LDA DSTPTR+1    ;Print Destination MSB
        JSR PRBYTE
        LDA DSTPTR      ;Print Destination LSB
        JSR PRBYTE
        JMP PUTSPC      ;Print Space

;Print Destination Address
BLKPSA  LDA SRCPTR+1    ;Print Source MSB
        JSR PRBYTE
        LDA SRCPTR      ;Print Source LSB
        JSR PRBYTE
        JMP PUTSPC      ;Print Space

        ENDSUBROUTINE
