/**   asm_utils.S
 **
 **   This module includes a number of assembly language utilities
 ** to support the low-level DDR2 RAM tests for the NPA-56x4 AMC card 
 ** which contains a Cavium processor.
 **
 **
 ** Created by Ted Schmitz, May 1, 2009
 **
 **/
#include <config.h>
#include <version.h>
#include <asm/regdef.h>
#include <asm/mipsregs.h>
#include "common_mem_test_defs.h"
#include "ll_bist.h"
        
        .text
        .align 8

/*****************************************************************************
 **                   64-Bit High Speed Fill Ram Routine (Debugged)
 **
 **    This function fills RAM at high speed and is used by the various RAM 
 ** test functions, although it can be used by any "C" or assembly function.
 **
 ** NOTE: This function writes 64-bits at a time so the beginning address must
 **       be located on a 64-bit boundary and the last address written must
 **       be on a 64-bit boundary as well.
 **
 ** void ll_fill_ram(u64 beg_adr, u64 end_adr, u64 fill data)
 **
 ** a0 = beg address of fill
 ** a1 = end address of fill
 ** a2 = 64-bit fill data
 **
 ****************************************************************************/
        .globl  ll_fill_ram
        
ll_fill_ram:    
        addiu   sp, sp, -24             #make space on stack for storage
        sd      a0, 16(sp)              #save regs on stack
        sd      a1, 8(sp)
        sd      a2, 0(sp)

1:      sd      a2,0(a0)                #store next pat in next loc
#        addu    a0, 8                   #inc to next loc
        daddiu    a0, 8                   #inc to next loc
        blt     a0, a1, 1b              #done? no, jump
        sync
        syncw
        nop
        
        ld      a0, 16(sp)              #recall regs off the stack
        ld      a1, 8(sp)
        ld      a2, 0(sp)
        
        addiu   sp, sp, 24              #restore stack pointer
        jr      ra                      #return to calling code
        nop                             #delay - slot
        nop
        
/*****************************************************************************
 **                   16-Bit High Speed Fill Ram Routine
 **
 **    This function fills RAM at high speed and is used by the various RAM 
 ** test functions, although it can be used by any "C" or assembly function.
 **
 ** NOTE: This function writes 16-bits at a time so the beginning address must
 **       be located on a 16-bit boundary and the last address written must
 **       be on a 16-bit boundary as well.
 **
 ** void ll_fill_ram_16(u64 beg_adr, u64 end_adr, u64 fill data)
 **
 ** a0 = beg address of fill
 ** a1 = end address of fill
 ** a2 = 16-bit fill data
 **
 ****************************************************************************/
        .globl  ll_fill_ram_16
        
ll_fill_ram_16:    
        addiu   sp, sp, -24             #make space on stack for storage
        sd      a0, 16(sp)              #save regs on stack
        sd      a1, 8(sp)
        sd      a2, 0(sp)

1:      sh      a2,0(a0)                #store next pat in next loc
        daddiu  a0, 2                   #inc to next loc
        blt     a0, a1, 1b              #done? no, jump
        sync
        syncw
        nop
        
        ld      a0, 16(sp)              #recall regs off the stack
        ld      a1, 8(sp)
        ld      a2, 0(sp)
        
        addiu   sp, sp, 24              #restore stack pointer
        jr      ra                      #return to calling code
        nop                             #delay - slot
        nop
        
/*****************************************************************************
 **      64-Bit High Speed Address Lines Fill Ram Routine
 **
 **    This function fills RAM at high speed and is used by the various RAM 
 ** test functions, although it can be used by any "C" or assembly function.
 **    Each 64-bit location is filled with it's own address.  This is the Ted's
 ** Address Lines Test (TALT) algorithm.
 **
 ** NOTE: This function writes 64-bits at a time so the beginning address must
 **       be located on a 64-bit boundary and the last address written must
 **       be on a 64-bit boundary as well.
 **
 ** void ll_ram_adrs_lines_fill(u64 beg_adr, u64 end_adr)
 **
 ** a0 = beg address of fill
 ** a1 = end address of fill
 **
 ****************************************************************************/
        .globl  ll_ram_adrs_lines_fill_talt
        
ll_ram_adrs_lines_fill_talt:    
        addiu   sp, sp, -24             #make space on stack for storage
        sd      a0, 16(sp)              #save regs on stack
        sd      a1, 8(sp)
        sd      a2, 0(sp)

1:      sd      a0,0(a0)                #store own adrs in each location
        daddiu  a0, 8                   #inc to next loc
        blt     a0, a1, 1b              #done? no, jump
        sync
        syncw
        nop
        
        ld      a0, 16(sp)              #recall regs off the stack
        ld      a1, 8(sp)
        ld      a2, 0(sp)
        
        addiu   sp, sp, 24              #restore stack pointer
        jr      ra                      #return to calling code
        nop                             #delay - slot
        nop
        
/*****************************************************************************
 **      64-Bit High Speed Address Lines Fill Ram Routine
 **
 **    This function relocates itself to the address specified by the calling
 ** code then fills RAM at high speed and is used by the various RAM 
 ** test functions, although it can be used by any "C" or assembly function.
 **    Each 64-bit location is filled with it's own address.  This is the Ted's
 ** Address Lines Test (TALT) algorithm.
 **
 ** NOTE: This function writes 64-bits at a time so the beginning address must
 **       be located on a 64-bit boundary and the last address written must
 **       be on a 64-bit boundary as well.
 **
 ** void ll_ram_adrs_lines_fill(u64 beg_adr, u64 end_adr, u64 rel_adrs)
 **
 ** Parameters
 ** a0 = beg address of fill
 ** a1 = end address of fill
 ** a2 = relocation address
 **
 ** Interm registers Used
 ** a0 = source adrs of copy
 ** a1 = temp working reg
 **
 ** Other registers used
 ** s0 - length of copy in bytes
 ** s1 = last source adrs to be copied
 **
 ****************************************************************************/
        .globl  ll_ram_adrs_lines_fill_talt_rel
        
ll_ram_adrs_lines_fill_talt_rel:    
        addiu   sp, sp, -(6*8)          #make space on stack for storage
        sd      s1, 40(sp)              #save regs on stack
        sd      s0, 32(sp)
        sd      ra, 24(sp)
        sd      a0, 16(sp)
        sd      a1, 8(sp)
        sd      a2, 0(sp)

# copy this routine below to destination address and jump to it
        jal     lralftr_jmp             #get cur pc contents
        nop
#        daddu   
lralftr_jmp:       #<- reg 'ra' contains this locations's adrs
/* unlock L2 cache */
        dli     s0,0x8001180080000058   #load adrs of L2C_LCKBASE reg
        dli     s1,0x0000000000000000
        sd      s1, 0(s0)               #unlock L2 Cache
        ld      s1, 0(s0)               #read it back to force the last write
#        
        daddiu  s0,zero,(lralftr_end -  lralftr_beg) #cal length of copy
        daddiu  a0,ra,(lralftr_beg-lralftr_jmp) #calc src adrs of copy
        daddu   s1,a0,s0                #calc last src adrs to be copied
        daddiu  a0, 4                   #inc to next source instruction

1:      lw      a1,0(a0)                #load next source loc
        sw      a1,0(a2)                #write it to dest adrs
        daddiu  a0, 4                   #inc to next src loc
        daddiu  a2, 4                   #inc to next dest loc
        blt     a0, s1, 1b              #done? no, jump

# copy is done, reload parameters and call the relocated routine


/* Lock L2 cache (for our region only) */
#        dli     s0,0x8001180080000058   #load adrs of L2C_LCKBASE reg
#        dli     s1,0x0000000000000004   #locking 4 cache blocks
#        sd      s1, 8(s0)               #set up to lock 4 blocks (512 B)
#        ld      s1, 8(s0)               #read it back to force th last write
#        dli     s1,0x0000000010000001   #ld base lock adrs & lock bit
#        sd      s1, 0(s0)               #lock the cache
#        ld      s1, 0(s0)               #read it back to force the last write
/* L2 should be locked now */
                
        ld      a0, 16(sp)              #recall beg address of fill
        ld      a1, 8(sp)               #recall end address of fill
        ld      a2, 0(sp)               #recall dest adrs
        jalr    a2                      #jump to re-located routine
        b       lralftr_end             #jump around fill logic to exit
        
lralftr_beg:
3:      sd      a0,0(a0)                #store own adrs in each location
        daddiu  a0, 8                   #inc to next loc
        blt     a0, a1, 3b              #done? no, jump
        sync
        syncw
        jr      ra                      #return to calling code
        nop
        nop
        
lralftr_end:   

#if 0
/* debug - cause a failure to test error logic.  This bug does not 
           always work at high-speed */
        ld      a0, 16(sp)              #recall beg address of fill
        ld      a1, 16(sp)              #get a 2nd copy of beg adrs
        daddiu  a0, 0x100               #calc beg adrs
        daddiu  a1, 0x7000              #calc end adrs
        dli     a2,0x1122334455667788
4:      sd      a2,0(a0)                #store garbage in each location
        sync
        daddiu  a0, 8                   #inc to next loc
        daddiu  a2, 8                   #inc to next pattern
        blt     a0, a1, 4b              #done? no, jump
        sync
        sync
        syncw
#        syncw
#        syncs
#        syncws
/* end special debug code */
#endif
                
        ld      s1, 40(sp)              #recall regs off the stack
        ld      s0, 32(sp)
        ld      ra, 24(sp)
        ld      a0, 16(sp)
        ld      a1, 8(sp)
        ld      a2, 0(sp)
        
        addiu   sp, sp, (6*8)           #restore stack pointer
        jr      ra                      #return to calling code
        nop                             #delay - slot
lralftr_exit:   
        nop
        
/*****************************************************************************
 **            High Speed Verify RAM Address Lines Data Routine
 **
 **    This function reads RAM at high speed and verifies the data at each 
 ** location contains that location's address (Teds Address Lines Test (TALT) 
 ** algorithm).  The results of the verify are reported back to the calling code.
 **
 ** NOTE: This function reads 64-bits at a time so the beginning address must
 **       be located on a 64-bit boundary.
 **       The first address to be verified is caclucated by OR'ing the
 **       beginning of the region with the 1st po2 boundary.
 **
 ** void ll_asm_adrs_lines_data_verify_talt(u64 beg_adr, u64 end address, 
 **                                         u64 * results_ptr)
 **
 ** Parameters
 ** a0 = beg adrs of region to be verified
 ** a1 = last location to be verified
 ** a2 = pointer to results array.
 **
 ** Other registers
 ** a4 s0 = next po2 adrs
 ** a5 s1 = Expected fill data
 ** a6 s2 = Data read from RAM
 ** s3 = Pointer to next 64-bit value to be read
 **
 ****************************************************************************/
        .globl  ll_asm_adrs_lines_data_verify_talt
        
ll_asm_adrs_lines_data_verify_talt:    
        addiu   sp, sp, -(8*8)          #make space on stack for storage
        sd      s3, 56(sp)              #save regs on stack
        sd      s2, 48(sp)
        sd      s1, 40(sp)
        sd      a0, 32(sp)
        sd      a1, 24(sp)
        sd      a2, 16(sp)
        sd      a3, 8(sp)
        sd      s0, 0(sp)
        
#if 0 /* debug - cause a failure to test error logic */
        dli     s2,0x1122334455667788
        sd      s2,0x230(s3)            #store bad data
#endif
        daddu   s3,a0,zero              #save a copy of next adrs to be read
        
laaldvt_10:      
        ld      s2,0(s3)                #read next 64-bit location
        bne     s3,s2,laaldvt_err       #contains its own adrs? No, jmp to err
        nop
        
        daddiu  s3, 8                   #inc to next loc
        blt     s3, a1,laaldvt_10       #done? no, jump to read next adrs
        nop
        b       laaldvt_exit_good       #exit with good status
        nop

# Enter here to report an error        
# s2 = bad data read
# s1 = expected data
# a3 = pointer to asm test results array
# s3 = address that contains bad data
#
laaldvt_err:
        sd      s3,(ASM_TEST_ADRS_AT_FAULT*8)(a2) #save adrs that failed
        sd      s3,(ASM_TEST_EXP_DATA*8)(a2)      #save exp data in array
        sd      s2,(ASM_TEST_BAD_DATA*8)(a2)      #save bad data read
        dli     s0,ASM_TEST_FAILED
        sd      s0,(ASM_TEST_RESULTS*8)(a2)       #flag test failed
        b       laaldvt_exit
        nop

laaldvt_exit_good:
        dli     s0,ASM_TEST_PASSED
        sd      s0,(ASM_TEST_RESULTS*8)(a3) #flag test passed
        b       laaldvt_exit
        
laaldvt_exit:    
        ld      s3, 56(sp)              #recall regs off the stack
        ld      s2, 48(sp)
        ld      s1, 40(sp)
        ld      a0, 32(sp)
        ld      a1, 24(sp)
        ld      a2, 16(sp)
        ld      a3, 8(sp)
        ld      s0, 0(sp)
        
        addiu   sp, sp, (8*8)           #restore stack pointer
        jr      ra                      #return to calling code
        nop                             #delay - slot

/*****************************************************************************
 **     High Speed Verify RAM Address Lines Data Routine (TALT-Relocatable) (DEBUGGED)
 **
 **    This function relocates itself to the address specifiec by the calling
 ** code then reads RAM at high speed and verifies the data at each 
 ** location contains that location's address (Teds Address Lines Test (TALT) 
 ** algorithm).  The results of the verify are reported back to the calling code.
 **
 ** NOTE: This function reads 64-bits at a time so the beginning address must
 **       be located on a 64-bit boundary.
 **
 ** void ll_asm_adrs_lines_data_verify_talt_rel(u64 beg_adr, u64 end address, 
 **                                             u64 * results_ptr, u64 rel_adrs)
 **
 ** Parameters
 ** a0 = beg adrs of region to be verified
 ** a1 = last location to be verified
 ** a2 = pointer to results array.
 ** a3 = relocation address
 **
 ** Other registers
 ** s0 = working register
 ** s1 = calc last adrs to be copied
 ** s2 = Data read from RAM
 ** s3 = Pointer to next 64-bit value to be read
 **
 ****************************************************************************/
        .globl  ll_asm_adrs_lines_data_verify_talt_rel
        
ll_asm_adrs_lines_data_verify_talt_rel:    
        addiu   sp, sp, -(9*8)          #make space on stack for storage
        sd      ra, 64(sp)              #save regs on stack
        sd      s3, 56(sp)
        sd      s2, 48(sp)
        sd      s1, 40(sp)
        sd      a0, 32(sp)
        sd      a1, 24(sp)
        sd      a2, 16(sp)
        sd      a3, 8(sp)
        sd      s0, 0(sp)
        
#if 0 /* debug - cause a failure to test error logic.  This bug does not 
        always work at high-speed */
        dli     s2,0x1122334455667788
        sd      s2,0x230(a0)            #store bad data
        sync
        syncs
        syncws
#endif
#
# copy the routine below to destination address and jump to it
        jal     laaldvtr_jmp            #get cur pc contents
        nop
#        daddu   
laaldvtr_jmp:       #<- reg 'ra' contains this locations's adrs
        daddiu  s0,zero,(laaldvtr_end -  laaldvtr_beg) #cal length of copy
        daddiu  a0,ra,(laaldvtr_beg-laaldvtr_jmp) #calc src adrs of copy
        daddu   s1,a0,s0                #calc last src adrs to be copied
        daddiu  a0, 4                   #inc to next source instruction
        
# Boot PROM region does not support 64-bit transfers. So use 32-bit read/writes
        
1:      lw      a1,0(a0)                #load next source loc
        sw      a1,0(a3)                #write it to dest adrs
        daddiu  a0, 4                   #inc to next src loc
        daddiu  a3, 4                   #inc to next dest loc
        blt     a0, s1, 1b              #done? no, jump

# copy is done, reload parameters and call the relocated routine
        
        ld      a0, 32(sp)              #recall all parameters
        ld      a1, 24(sp)
        ld      a2, 16(sp) 
        ld      a3, 8(sp)
        jalr    a3                      #jump to re-located routine
        nop
        b       laaldvtr_end            #jump around fill logic to exit
        nop
#
#
laaldvtr_beg:   #beginning of copied code
        
        daddu   s3,a0,zero              #save a copy of next adrs to be read
        
laaldvtr_10:      
        ld      s2,0(s3)                #read next 64-bit location
        bne     s3,s2,laaldvtr_err      #contains its own adrs? No, jmp to err
        nop
        
        daddiu  s3, 8                   #inc to next loc
        blt     s3, a1,laaldvtr_10      #done? no, jump to read next adrs
        nop
        b       laaldvtr_exit_good      #exit with good status
        nop

# Enter here to report an error        
# s2 = bad data read
# s3 = expected data
# a2 = pointer to asm test results array
# s3 = address that contains bad data
#
laaldvtr_err:
        sd      s3,(ASM_TEST_ADRS_AT_FAULT*8)(a2) #save adrs that failed
        sd      s3,(ASM_TEST_EXP_DATA*8)(a2)      #save exp data in array
        sd      s2,(ASM_TEST_BAD_DATA*8)(a2)      #save bad data read
        dli     s0,ASM_TEST_FAILED
        sd      s0,(ASM_TEST_RESULTS*8)(a2)       #flag test failed
        b       laaldvtr_exit
        nop

laaldvtr_exit_good:
        dli     s0,ASM_TEST_PASSED
        sd      s0,(ASM_TEST_RESULTS*8)(a2) #flag test passed
        b       laaldvtr_exit
        
laaldvtr_exit:
        nop
        sync
        syncw
        jr      ra                      #return to calling code
        nop
        nop
        
laaldvtr_end:   #end of copied code
        nop

        ld      ra, 64(sp)              #recall regs off the stack
        ld      s3, 56(sp)
        ld      s2, 48(sp)
        ld      s1, 40(sp)
        ld      a0, 32(sp)
        ld      a1, 24(sp)
        ld      a2, 16(sp)
        ld      a3, 8(sp)
        ld      s0, 0(sp)
        
        addiu   sp, sp, (9*8)           #restore stack pointer
        jr      ra                      #return to calling code
        nop                             #delay - slot

/*****************************************************************************
 **                                Read TLB
 **
 **    This subroutine reads up the TLB requested by the calling code and fills
 ** in the tlb array point to by the calling code.
 **
 ** void ll_read_tlv(u64 * tlb_array)
 **
 ** Parameters
 ** a0 = pointer to tlb array.  Each element in the TLB array is a 64-entry.
 **      See tlb array format in "common_mem_test_defs.h".
 ** 
 ****************************************************************************/
        .globl  ll_read_tlv
        
ll_read_tlv:    
        addiu   sp, sp, -(8*8)          #make space on stack for storage
        sd      s3, 56(sp)              #save regs on stack
        sd      s2, 48(sp)
        sd      s1, 40(sp)
        sd      a0, 32(sp)
        sd      a1, 24(sp)
        sd      a2, 16(sp)
        sd      a3, 8(sp)
        sd      s0, 0(sp)

        ld      a2,(TLB_INDEX*8)(a0)        #get index of tlb
        mtc0    a2,COP0_INDEX_REG
        tlbr
        syncws
        nop
        nop
        mfc0    a2,COP0_PAGEMASK_REG
        nop
        nop
        sd      a2,(TLB_MASK_REG*8)(a0)     #save mask reg in tlb array
        
        mfc0    a2,COP0_ENTRYLO0_REG
        nop
        nop
        sd      a2,(TLB_ENTRY_LO_0*8)(a0)   #save reg in tlb array
        
        mfc0    a2,COP0_ENTRYLO1_REG
        nop
        nop
        sd      a2,(TLB_ENTRY_LO_1*8)(a0)   #save reg in tlb array
        
 
        mfc0    a2,COP0_ENTRYHI_REG
        nop
        nop
        sd      a2,(TLB_ENTRY_HI_REG*8)(a0)   #save reg in tlb array
        syncws
        nop
        nop
        
        ld      s3, 56(sp)              #recall regs off the stack
        ld      s2, 48(sp)
        ld      s1, 40(sp)
        ld      a0, 32(sp)
        ld      a1, 24(sp)
        ld      a2, 16(sp)
        ld      a3, 8(sp)
        ld      s0, 0(sp)
        
        addiu   sp, sp, (8*8)           #restore stack pointer
        jr      ra                      #return to calling code
        nop                             #delay - slot

/*****************************************************************************
 **                             Write TLB
 **
 **    This subroutine writes a TLB requested by the calling code into the
 ** Octeon processor TLB table.
 **
 ** void ll_write_tlv(u64 * tlb_array)
 **
 ** Parameters
 ** a0 = pointer to tlb array.  Each element in the TLB array is a 64-entry.
 **      See tlb array format in "common_mem_test_defs.h".
 ** 
 ****************************************************************************/
        .globl  ll_write_tlv
        
ll_write_tlv:    
        addiu   sp, sp, -(8*8)          #make space on stack for storage
        sd      s3, 56(sp)              #save regs on stack
        sd      s2, 48(sp)
        sd      s1, 40(sp)
        sd      a0, 32(sp)
        sd      a1, 24(sp)
        sd      a2, 16(sp)
        sd      a3, 8(sp)
        sd      s0, 0(sp)

        ld      a2,(TLB_MASK_REG*8)(a0)    #get tlb mask reg
        mtc0    a2,COP0_PAGEMASK_REG
        nop
        nop
        
        ld      a2,(TLB_ENTRY_LO_0*8)(a0)  #get tlb EntryLo0 reg
        dmtc0    a2,COP0_ENTRYLO0_REG
        nop
        nop
        
        ld      a2,(TLB_ENTRY_LO_1*8)(a0)  #get tlb EntryLo0 reg
        dmtc0    a2,COP0_ENTRYLO1_REG
        nop
        nop
 
        ld      a2,(TLB_ENTRY_HI_REG*8)(a0)  #get tlb EntryLo0 reg
        dmtc0    a2,COP0_ENTRYHI_REG
        nop
        nop
        mfc0    a2, COP0_INDEX_REG      #not sure I need the read
        ld      a2,(TLB_INDEX*8)(a0)        #get index of tlb
        mtc0    a2,COP0_INDEX_REG
        nop
        nop
        syncws
        nop
        nop
        ehb
        tlbwi                           #write tlb to table
        ehb
        syncws
        nop
        nop
        
        ld      s3, 56(sp)              #recall regs off the stack
        ld      s2, 48(sp)
        ld      s1, 40(sp)
        ld      a0, 32(sp)
        ld      a1, 24(sp)
        ld      a2, 16(sp)
        ld      a3, 8(sp)
        ld      s0, 0(sp)
        
        addiu   sp, sp, (8*8)           #restore stack pointer
        jr      ra                      #return to calling code
        nop                             #delay - slot

/*****************************************************************************
 **                       64-Bit FLUSH Dcache Rountine (Debugged)
 **
 **    This function flushes Dcache by reading RAM from a location specified
 ** by the calling code for a length specified by the calling code.
 **
    ** NOTE: This function reads 64-bits at a time so the beginning address must
 **       be located on a 64-bit boundary AND must be located on a cache-line
 **
 ** void ll_asm_flush_cache(u64 beg_adr, u64 length)
 **
 ** a0 = 1st location to be read
 ** a1 = number of bytes to be read/eritten
 **
 ****************************************************************************/
        .globl  ll_asm_flush_cache
        
ll_asm_flush_cache:    
        addiu   sp, sp, -24             #make space on stack for storage
        sd      a0, 16(sp)              #save regs on stack
        sd      a1, 8(sp)
        sd      a2, 0(sp)
        
        dadd    a2,a0,a1                #add beg adrs to length
        daddu   a1,a2,zero              #move result to end adrs reg
#        move    a1,a2                   #move to end adrs reg
        
#1:      ld      a2,0(a0)                #read next 64-bit location
1:      sd      a2,0(a0)                #writenext 64-bit location
        daddiu  a0, 8                   #inc to next loc
        blt     a0, a1, 1b              #done? no, jump
        sync
        syncw
        nop
        
        ld      a0, 16(sp)              #recall regs off the stack
        ld      a1, 8(sp)
        ld      a2, 0(sp)
        
        addiu   sp, sp, 24              #restore stack pointer
        jr      ra                      #return to calling code
        nop                             #delay - slot
        nop
        
/*****************************************************************************
 **            High Speed Verify RAM Address Lines Data Routine
 **
 **    This function reads RAM at high speed and verifies the data at each 
 ** location contains either that location's address or a fill value.  The
 ** results of the verify are reported back to the calling code.
 **
 ** NOTE: This function reads 64-bits at a time so the beginning address must
 **       be located on a 64-bit boundary.
 **       The first address to be verified is caclucated by OR'ing the
 **       beginning of the region with the 1st po2 boundary.
 **
 ** void ll_asm_adrs_lines_data_verify(u64 beg_adr, u64 end address, 
 **                                    u64 beg_po2_pattern, u64 * results_ptr)
 **
 ** Parameters
 ** a0 = beg adrs of region to be verified
 ** a1 = last location to be verified
 ** a2 = Starting Power-of-2 boundary
 ** a3 = pointer to results array.
 **
 ** Other registers
 ** a4 s0 = next po2 adrs
 ** a5 s1 = Expected fill data
 ** a6 s2 = Data read from RAM
 ** s3 = Pointer to next 64-bit value to be read
 **
 ****************************************************************************/
        .globl  ll_asm_adrs_lines_data_verify
        
ll_asm_adrs_lines_data_verify:    
        addiu   sp, sp, -(8*8)          #make space on stack for storage
        sd      s3, 56(sp)              #save regs on stack
        sd      s2, 48(sp)
        sd      s1, 40(sp)
        sd      a0, 32(sp)
        sd      a1, 24(sp)
        sd      a2, 16(sp)
        sd      a3, 8(sp)
        sd      s0, 0(sp)
        
        dadd    s3,a0,a2                #calc next po2 adrs (in this region)
        daddu   s0,s3,zero              #save a copy in *next po2 adrs* var
        dadd    s3,a0,a2                #calc next po2 adrs (in this region)
        ld      s1,(ASM_TEST_EXP_DATA*8)(a3) #pre-load expected fill data
        
#if 0 /* debug - cause a failure to test error logic */
        dli     s2,0x1122334455667788
        sd      s2,0x230(s3)            #store bad data
#endif
        
laaldv_10:      
        ld      s2,0(s3)                #read next 64-bit location
        beq     s0,s3,laaldv_20         #this next po2 adrs to be verified?
        nop                             #yes, jump
        
#  enter here if not next po2 adrs to verify it conatins filler value
        
        bne     s1,s2,laaldv_err_5      #contains fill data?  No, jump to err
        nop
laaldv_15:      
        addu    s3, 8                   #inc to next loc
        blt     s3, a1,laaldv_10        #done? no, jump to read next adrs
        nop
        b       laaldv_exit_good        #exit with good status
        nop
        
# verify this location contains next po2 adrs
laaldv_20:     
        bne     s0,s2,laaldv_err        #contains po2 adrs?  No, jump to err
        sll     a2,a2,1                 #calc next po2 boundary
        dadd    s0,a0,a2                #calc next po2 adrs (in this region)
        b       laaldv_15               #jmp to cacl next adrs to be read
        nop
        
# Fall into this code if fill data was incorrect in some location
# s0 = po2 adrs that failed
laaldv_err:
        daddu   s1,s0,zero             #move exp data to appropriate reg &
                                       # fall through to error handler
        
# s2 = bad data read
# s1 = expected data
# a3 = pointer to asm test results array
# s3 = address that contains bad data
#
laaldv_err_5:
        sd      s3,(ASM_TEST_ADRS_AT_FAULT*8)(a3) #save adrs that failed
        sd      s1,(ASM_TEST_EXP_DATA*8)(a3)      #save exp data in array
        sd      s2,(ASM_TEST_BAD_DATA*8)(a3)      #save bad data read
        dli     s0,ASM_TEST_FAILED
        sd      s0,(ASM_TEST_RESULTS*8)(a3)       #flag test failed
        b       laaldv_exit
        nop

laaldv_exit_good:
        dli     s0,ASM_TEST_PASSED
        sd      s0,(ASM_TEST_RESULTS*8)(a3) #flag test passed
        b       laaldv_exit
        
laaldv_exit:    
        ld      s3, 56(sp)              #recall regs off the stack
        ld      s2, 48(sp)
        ld      s1, 40(sp)
        ld      a0, 32(sp)
        ld      a1, 24(sp)
        ld      a2, 16(sp)
        ld      a3, 8(sp)
        ld      s0, 0(sp)
        
        addiu   sp, sp, (8*8)           #restore stack pointer
        jr      ra                      #return to calling code
        nop                             #delay - slot

/*****************************************************************************
 **      64-Bit High Speed RAM Cells Fill Routine - Relocatable
 **
 **    This function relocates itself to the address specified by the calling
 ** code then fills RAM at high speed and is used by the various RAM 
 ** test functions, although it can be used by any "C" or assembly function.
 **    Each 64-bit location is filled with the 64-bit data pattern supplied 
 ** by the calling code.
 **
 ** NOTE: This function writes 64-bits at a time so the beginning address must
 **       be located on a 64-bit boundary and the last address written must
 **       be on a 64-bit boundary as well.
 **
 ** void ll_ram_fill_rel(u64 beg_adr, u64 end_adr, u64 rel_adrs, 
 **                      u64 data_pattern)
 **
 ** Parameters
 ** a0 = beg address of fill
 ** a1 = end address of fill
 ** a2 = relocation address
 ** a3 = 64-bit fill data
 **
 ** Interm registers Used
 ** a0 = source adrs of copy
 ** a1 = temp working reg
 **
 ** Other registers used
 ** s0 - length of copy in bytes
 ** s1 = last source adrs to be copied
 **
 ****************************************************************************/
        .globl  ll_ram_fill_rel
        
ll_ram_fill_rel:    
        addiu   sp, sp, -(7*8)          #make space on stack for storage
        sd      a3, 48(sp)              #save regs on stack
        sd      s1, 40(sp)
        sd      s0, 32(sp)
        sd      ra, 24(sp)
        sd      a0, 16(sp)
        sd      a1, 8(sp)
        sd      a2, 0(sp)

# copy this routine below to destination address and jump to it
        jal     lrfr_jmp                #get cur pc contents
        nop
#        daddu   
lrfr_jmp:       #<- reg 'ra' contains this locations's adrs
/* unlock L2 cache */
        dli     s0,0x8001180080000058   #load adrs of L2C_LCKBASE reg
        dli     s1,0x0000000000000000
        sd      s1, 0(s0)               #unlock L2 Cache
        ld      s1, 0(s0)               #read it back to force the last write
#        
        daddiu  s0,zero,(lrfr_end -  lrfr_beg) #cal length of copy
        daddiu  a0,ra,(lrfr_beg-lrfr_jmp) #calc src adrs of copy
        daddu   s1,a0,s0                #calc last src adrs to be copied
        daddiu  a0, 4                   #inc to next source instruction

1:      lw      a1,0(a0)                #load next source loc
        sw      a1,0(a2)                #write it to dest adrs
        daddiu  a0, 4                   #inc to next src loc
        daddiu  a2, 4                   #inc to next dest loc
        blt     a0, s1, 1b              #done? no, jump

# copy is done, reload parameters and call the relocated routine


#if 0
/* Lock L2 cache (for our region only).
   Designed this code from tracing the "cvmx_l2c_lock_line():  " function
   in moodule "lib_mips/cvmx-l2c.c".  However,this does not seem to work. */
        ld      a2, 0(sp)               #recall relocation drs of asm code
        
        dli     s0,0x8001180080000008   #reg L2T_ERR adrs
        ld      a0,0(s0)                #load the reg
        dli     s1,0x0000000005000000
        or      s1,s1,a0
        sd      s1,0(s0)                #clr LCKERR & LCKERR2 bits
        sync
        
        dli     s0,0x8001180080000030   #reg L2C_DBG adrs
        dli     s1,0x0000000000000000
        sd      s1,0(s0)                #sel proc 0 as debug proc
        ld      s1,0(s0)                #force write to occur
        
        dli     s0,0x8001180080000060   #reg L2C_LCKOFF adrs
        dli     s1,0x0000000000000000
        sd      s1,0(s0)                #clr lock 0ffset
        ld      s1,0(s0)                #force write to occur
        
        dli     s0,0x8001180080000058   #reg L2C_LCKBASE adrs
        dli     s1,0x0000000070000001
        sd      s1,0(s0)                #set lock base adrs
        ld      s1,0(s0)                #force write to occur
        
        ld      s0,0(a2)                #load the locked cachline
       
        dli     s0,0x8001180080000058   #reg L2C_LCKBASE adrs
        dli     s1,0x0000000070000000
        sd      s1,0(s0)                #clear lock en (but leave base set up)
        ld      s1,0(s0)                #force write to occur
        sync
        
        dli     s0,0x8001180080000008   #reg L2T_ERR adrs
        ld      a0,0(s0)                #load the reg
        
#        dli     s1,0x0000000000000004   #locking 4 cache blocks
#        sd      s1, 8(s0)               #set up to lock 4 blocks (512 B)
#        ld      s1, 8(s0)               #read it back to force th last write
#        dli     s1,0x0000000010000001   #ld base lock adrs & lock bit
#        sd      s1, 0(s0)               #lock the cache
#        ld      s1, 0(s0)               #read it back to force the last write
/* L2 should be locked now */
#endif
                
        ld      a3, 48(sp)              #recall beg address of fill
        ld      a0, 16(sp)              #recall beg address of fill
        ld      a1, 8(sp)               #recall end address of fill
        ld      a2, 0(sp)               #recall dest adrs
        jalr    a2                      #jump to re-located routine
        nop
        nop
        nop
        b       lrfr_end                #jump around fill logic to exit
        nop
        
lrfr_beg:
3:      sd      a3,0(a0)                #store test pat in next location
        daddiu  a0, 8                   #inc to next loc
        blt     a0, a1, 3b              #done? no, jump
        sync
#        syncs
#        ehb
        syncw
        jr      ra                      #return to calling code
        nop
        nop
        
lrfr_end:   
#if 0
/* debug - cause a failure to test error logic.  This bug does not 
           always work at high-speed */
        ld      a0, 16(sp)              #recall beg address of fill
        ld      a1, 16(sp)              #get a 2nd copy of beg adrs
        daddiu  a0, 0x100               #calc beg adrs
        daddiu  a1, 0x7000              #calc end adrs
        dli     a2,0x1122334455667788
4:      sd      a2,0(a0)                #store garbage in each location
        sync
        daddiu  a0, 8                   #inc to next loc
        daddiu  a2, 8                   #inc to next pattern
        blt     a0, a1, 4b              #done? no, jump
        sync
        sync
        syncw
#        syncw
#        syncs
#        syncws
/* end special debug code */
#endif
                
        ld      a3, 48(sp)              #recall regs off the stack
        ld      s1, 40(sp)
        ld      s0, 32(sp)
        ld      ra, 24(sp)
        ld      a0, 16(sp)
        ld      a1, 8(sp)
        ld      a2, 0(sp)
        
        addiu   sp, sp, (7*8)           #restore stack pointer
        jr      ra                      #return to calling code
        nop                             #delay - slot
lrfr_exit:   
        nop
        
/*****************************************************************************
 **          High Speed Verify RAM Cells Routine (Relocatable) 
 **
 **    This function relocates itself to the address specifiec by the calling
 ** code then reads RAM at high speed and verifies the data at each 
 ** location contains the test pattern supplied by the calling code.  The 
 ** results of the verify are reported back to the calling code.
 **
 ** NOTE: This function reads 64-bits at a time so the beginning address must
 **       be located on a 64-bit boundary.
 **
 ** void ll_asm_ram_cells_verify_rel(u64 beg_adr, u64 end address, 
 **                                  u64 * results_ptr, u64 rel_adrs,
 **                                  u64 exp_data)
 **
 ** Parameters
 ** a0 = beg adrs of region to be verified
 ** a1 = last location to be verified
 ** a2 = pointer to results array.
 ** a3 = relocation address
 ** t0 = data expected in each cell
 **
 ** Other registers
 ** s0 = working register
 ** s1 = calc last adrs to be copied
 ** s2 = Data read from RAM
 ** s3 = Pointer to next 64-bit value to be read
 **
 ****************************************************************************/
        .globl  ll_asm_ram_cells_verify_rel
        
ll_asm_ram_cells_verify_rel:    
        addiu   sp, sp, -(10*8)         #make space on stack for storage
        sd      t0, 72(sp)              #save regs on stack
        sd      ra, 64(sp)
        sd      s3, 56(sp)
        sd      s2, 48(sp)
        sd      s1, 40(sp)
        sd      a0, 32(sp)
        sd      a1, 24(sp)
        sd      a2, 16(sp)
        sd      a3, 8(sp)
        sd      s0, 0(sp)
        
#if 0 /* debug - cause a failure to test error logic.  This bug does not 
        always work at high-speed */
        dli     s2,0x1122334455667788
        sd      s2,0x230(a0)            #store bad data
        sync
        syncs
        syncws
#endif
#
# copy the routine below to destination address and jump to it
        jal     larcvr_jmp              #get cur pc contents
        nop
#        daddu   
larcvr_jmp:       #<- reg 'ra' contains this locations's adrs
        daddiu  s0,zero,(larcvr_end -  larcvr_beg) #cal length of copy
        daddiu  a0,ra,(larcvr_beg-larcvr_jmp) #calc src adrs of copy
        daddu   s1,a0,s0                #calc last src adrs to be copied
        daddiu  a0, 4                   #inc to next source instruction
        
# Boot PROM region does not support 64-bit transfers. So use 32-bit read/writes
        
1:      lw      a1,0(a0)                #load next source loc
        sw      a1,0(a3)                #write it to dest adrs
        daddiu  a0, 4                   #inc to next src loc
        daddiu  a3, 4                   #inc to next dest loc
        blt     a0, s1, 1b              #done? no, jump

# copy is done, reload parameters and call the relocated routine
        
        ld      t0, 72(sp)              #recall all parameters
        ld      a0, 32(sp)
        ld      a1, 24(sp)
        ld      a2, 16(sp) 
        ld      a3, 8(sp)
        jalr    a3                      #jump to re-located routine
        nop
        b       larcvr_end              #jump around fill logic to exit
        nop
#
#
larcvr_beg:   #beginning of copied code
        
        daddu   s3,a0,zero              #save a copy of next adrs to be read
        
larcvr_10:      
        ld      s2,0(s3)                #read next 64-bit location
        bne     t0,s2,larcvr_err        #contains exp pattern? No, jmp to err
        nop
        
        daddiu  s3, 8                   #inc to next loc
        blt     s3, a1,larcvr_10        #done? no, jump to read next adrs
        nop
        b       larcvr_exit_good        #exit with good status
        nop

# Enter here to report an error        
# s2 = bad data read
# a4 = expected data
# a2 = pointer to asm test results array
# s3 = address that contains bad data
#
larcvr_err:
        sd      s3,(ASM_TEST_ADRS_AT_FAULT*8)(a2) #save adrs that failed
        sd      t0,(ASM_TEST_EXP_DATA*8)(a2)      #save exp data in array
        sd      s2,(ASM_TEST_BAD_DATA*8)(a2)      #save bad data read
        dli     s0,ASM_TEST_FAILED
        sd      s0,(ASM_TEST_RESULTS*8)(a2)       #flag test failed
        b       larcvr_exit
        nop

larcvr_exit_good:
        dli     s0,ASM_TEST_PASSED
        sd      s0,(ASM_TEST_RESULTS*8)(a2) #flag test passed
        b       larcvr_exit
        
larcvr_exit:
        nop
        sync
        syncw
        jr      ra                      #return to calling code
        nop
        nop
        
larcvr_end:   #end of copied code
        nop

        ld      t0, 72(sp)              #recall regs off the stack
        ld      ra, 64(sp)
        ld      s3, 56(sp)
        ld      s2, 48(sp)
        ld      s1, 40(sp)
        ld      a0, 32(sp)
        ld      a1, 24(sp)
        ld      a2, 16(sp)
        ld      a3, 8(sp)
        ld      s0, 0(sp)
        
        addiu   sp, sp, (10*8)          #restore stack pointer
        jr      ra                      #return to calling code
        nop                             #delay - slot

/*****************************************************************************
 **          High Speed Verify RAM Cells Routine (NOT-Relocatable) 
 **
 **    This function reads RAM at high speed and verifies the data at each 
 ** location contains the test pattern supplied by the calling code.  The 
 ** results of the verify are reported back to the calling code.
 **
 ** NOTE: This function reads 64-bits at a time so the beginning address must
 **       be located on a 64-bit boundary.
 **
 ** void ll_asm_ram_cells_verify(u64 beg_adr, u64 end address, 
 **                                  u64 * results_ptr, u64 exp_data)
 **
 ** Parameters
 ** a0 = beg adrs of region to be verified
 ** a1 = last location to be verified
 ** a2 = pointer to results array.
 ** a3 = relocation address
 ** t0 = data expected in each cell
 **
 ** Other registers
 ** s0 = working register
 ** s1 = calc last adrs to be copied
 ** s2 = Data read from RAM
 ** s3 = Pointer to next 64-bit value to be read
 **
 ****************************************************************************/
        .globl  ll_asm_ram_cells_verify
        
ll_asm_ram_cells_verify:    
        addiu   sp, sp, -(10*8)         #make space on stack for storage
        sd      t0, 72(sp)              #save regs on stack
        sd      ra, 64(sp)
        sd      s3, 56(sp)
        sd      s2, 48(sp)
        sd      s1, 40(sp)
        sd      a0, 32(sp)
        sd      a1, 24(sp)
        sd      a2, 16(sp)
        sd      a3, 8(sp)
        sd      s0, 0(sp)
        
#if 0 /* debug - cause a failure to test error logic.  This bug does not 
        always work at high-speed */
        dli     s2,0x1122334455667788
        sd      s2,0x230(a0)            #store bad data
        sync
        syncs
        syncws
#endif
#
        daddu   s3,a0,zero              #save a copy of next adrs to be read
        
larcv_10:      
        ld      s2,0(s3)                #read next 64-bit location
        bne     a3,s2,larcv_err        #contains exp pattern? No, jmp to err
        nop
        
        daddiu  s3, 8                   #inc to next loc
        blt     s3, a1,larcv_10        #done? no, jump to read next adrs
        nop
        b       larcv_exit_good        #exit with good status
        nop

# Enter here to report an error        
# s2 = bad data read
# a3 = expected data
# a2 = pointer to asm test results array
# s3 = address that contains bad data
#
larcv_err:
        sd      s3,(ASM_TEST_ADRS_AT_FAULT*8)(a2) #save adrs that failed
        sd      a3,(ASM_TEST_EXP_DATA*8)(a2)      #save exp data in array
        sd      s2,(ASM_TEST_BAD_DATA*8)(a2)      #save bad data read
        dli     s0,ASM_TEST_FAILED
        sd      s0,(ASM_TEST_RESULTS*8)(a2)       #flag test failed
        b       larcv_exit
        nop

larcv_exit_good:
        dli     s0,ASM_TEST_PASSED
        sd      s0,(ASM_TEST_RESULTS*8)(a2) #flag test passed
        b       larcv_exit
        
larcv_exit:
        nop
        
        ld      t0, 72(sp)              #recall regs off the stack
        ld      ra, 64(sp)
        ld      s3, 56(sp)
        ld      s2, 48(sp)
        ld      s1, 40(sp)
        ld      a0, 32(sp)
        ld      a1, 24(sp)
        ld      a2, 16(sp)
        ld      a3, 8(sp)
        ld      s0, 0(sp)
        
        addiu   sp, sp, (10*8)          #restore stack pointer
        jr      ra                      #return to calling code
        nop                             #delay - slot
        nop

/*****************************************************************************
 **        High Speed Verify RAM 16-Bit Cells Routine (NOT-Relocatable) 
 **
 **    This function reads RAM at high speed and verifies the data at each 
 ** location contains the test pattern supplied by the calling code.  The 
 ** results of the verify are reported back to the calling code.
 **
 ** NOTE: This function reads 16-bits at a time so the beginning address must
 **       be located on a 16-bit boundary.
 **
 ** void ll_asm_ram_cells_verify(u64 beg_adr, u64 end address, 
 **                                  u64 * results_ptr, u64 exp_data)
 **
 ** Parameters
 ** a0 = beg adrs of region to be verified
 ** a1 = last location to be verified
 ** a2 = pointer to results array.
 ** a3 = data expected in each cell
 **
 ** Other registers
 ** s0 = working register
 ** s1 = calc last adrs to be copied
 ** s2 = Data read from RAM
 ** s3 = Pointer to next 64-bit value to be read
 **
 ****************************************************************************/
        .globl  ll_asm_ram_cells_16_verify
        
ll_asm_ram_cells_16_verify:    
        addiu   sp, sp, -(10*8)         #make space on stack for storage
        sd      t0, 72(sp)              #save regs on stack
        sd      ra, 64(sp)
        sd      s3, 56(sp)
        sd      s2, 48(sp)
        sd      s1, 40(sp)
        sd      a0, 32(sp)
        sd      a1, 24(sp)
        sd      a2, 16(sp)
        sd      a3, 8(sp)
        sd      s0, 0(sp)
        
#if 0 /* debug - cause a failure to test error logic.  This bug does not 
        always work at high-speed */
        dli     s2,0x1122334455667788
        sd      s2,0x230(a0)            #store bad data
        sync
        syncs
        syncws
#endif
#
        dli     t0,0x000000000000FFFF   #data mask
        daddu   s3,a0,zero              #save a copy of next adrs to be read
        
larcsv_10:      
        lh      s2,0(s3)                #read next 64-bit location
        and     s2,s2,t0                #mask off bits we don't need
        bne     a3,s2,larcsv_err        #contains exp pattern? No, jmp to err
        nop
        
        daddiu  s3, 2                   #inc to next loc
        blt     s3, a1,larcsv_10        #done? no, jump to read next adrs
        nop
        b       larcsv_exit_good        #exit with good status
        nop

# Enter here to report an error        
# s2 = bad data read
# a3 = expected data
# a2 = pointer to asm test results array
# s3 = address that contains bad data
#
larcsv_err:
        sd      s3,(ASM_TEST_ADRS_AT_FAULT*8)(a2) #save adrs that failed
        sd      a3,(ASM_TEST_EXP_DATA*8)(a2)      #save exp data in array
        sd      s2,(ASM_TEST_BAD_DATA*8)(a2)      #save bad data read
        dli     s0,ASM_TEST_FAILED
        sd      s0,(ASM_TEST_RESULTS*8)(a2)       #flag test failed
        b       larcsv_exit
        nop

larcsv_exit_good:
        dli     s0,ASM_TEST_PASSED
        sd      s0,(ASM_TEST_RESULTS*8)(a2) #flag test passed
        b       larcsv_exit
        
larcsv_exit:
        nop
        
        ld      t0, 72(sp)              #recall regs off the stack
        ld      ra, 64(sp)
        ld      s3, 56(sp)
        ld      s2, 48(sp)
        ld      s1, 40(sp)
        ld      a0, 32(sp)
        ld      a1, 24(sp)
        ld      a2, 16(sp)
        ld      a3, 8(sp)
        ld      s0, 0(sp)
        
        addiu   sp, sp, (10*8)          #restore stack pointer
        jr      ra                      #return to calling code
        nop                             #delay - slot
        nop

/*****************************************************************************
 **                                Reset Unit
 **
 **    This function causes the BIST code to start at the restart vector again
 ** by whatever means possible.  This code may execute a soft reset or may just
 ** jumpt back to the restart vector in boot PROM space.
 **
 ** NOTE: This function reads 64-bits at a time so the beginning address must
 **       be located on a 64-bit boundary.
 **
 ** void ll_asm_reset_unit(void)
 **
 ** Parameters
 ** None
 **
 ** Other registers
 ** s0 = working register
 ** s1 = calc last adrs to be copied
 ** s2 = Data read from RAM
 ** s3 = Pointer to next 64-bit value to be read
 **
 ****************************************************************************/
        .globl  ll_asm_reset_unit
        
ll_asm_reset_unit:    
        addiu   sp, sp, -(3*8)         #make space on stack for storage
        sd      a2, 16(sp)              #save working registers
        sd      a1, 8(sp)
        sd      a0, 0(sp)
#if 1 /* do a soft reset */
//        dli     a0,0x8001070000000740   #ld reg adrs
//        dli     a1,0x0000000000000001   #ld write data
       dli     a0,CIU_SOFT_RST_REG     #ld soft reset reg adrs
       dli     a1,CIU_SOFT_RST_BIT     #ld write data
        ld      a2,0(a0)                #read it first
        syncw
        sd      a1,0(a0)                #reset the unit
        syncw
        ld      a2,0(a0)                #read it back to force the write
        syncw
        nop
        b       .                       #loop here until Octeon resets
#else /* just jump to restart vector */
        dli     a0,0xFFFFFFFFBFC00000   #ld loc of restart vector
        jr      a0
        nop
#endif
        ld      a2, 16(sp)              #restore working regs
        ld      a1, 8(sp)
        ld      s0, 0(sp)
        
        addiu   sp, sp, (3*8)          #restore stack pointer
        jr      ra                      #return to calling code
        nop                             #delay - slot
        nop

/*****************************************************************************
 **      16-Bit High Speed RAM Cells Fill Routine - Relocatable
 **
 **    This function relocates itself to the address specified by the calling
 ** code then fills RAM at high speed and is used by the various RAM 
 ** test functions, although it can be used by any "C" or assembly function.
 **    Each 16-bit location is filled with the 16-bit data pattern supplied 
 ** by the calling code.
 **
 ** NOTE: This function writes 16-bits at a time so the beginning address must
 **       be located on a 16-bit boundary and the last address written must
 **       be on a 16-bit boundary as well.
 **
 ** void ll_ram_fill_16_rel(u64 beg_adr, u64 end_adr, u64 rel_adrs, 
 **                         u64 data_pattern)
 **
 ** Parameters
 ** a0 = beg address of fill
 ** a1 = end address of fill
 ** a2 = relocation address
 ** a3 = 64-bit fill data
 **
 ** Interm registers Used
 ** a0 = source adrs of copy
 ** a1 = temp working reg
 **
 ** Other registers used
 ** s0 - length of copy in bytes
 ** s1 = last source adrs to be copied
 **
 ****************************************************************************/
        .globl  ll_ram_fill_16_rel
        
ll_ram_fill_16_rel:    
        addiu   sp, sp, -(7*8)          #make space on stack for storage
        sd      a3, 48(sp)              #save regs on stack
        sd      s1, 40(sp)
        sd      s0, 32(sp)
        sd      ra, 24(sp)
        sd      a0, 16(sp)
        sd      a1, 8(sp)
        sd      a2, 0(sp)

# copy this routine below to destination address and jump to it
        jal     lrfsr_jmp               #get cur pc contents
        nop
#        daddu   
lrfsr_jmp:       #<- reg 'ra' contains this locations's adrs
/* unlock L2 cache */
        dli     s0,0x8001180080000058   #load adrs of L2C_LCKBASE reg
        dli     s1,0x0000000000000000
        sd      s1, 0(s0)               #unlock L2 Cache
        ld      s1, 0(s0)               #read it back to force the last write
#        
        daddiu  s0,zero,(lrfsr_end -  lrfsr_beg) #cal length of copy
        daddiu  a0,ra,(lrfsr_beg-lrfsr_jmp) #calc src adrs of copy
        daddu   s1,a0,s0                #calc last src adrs to be copied
        daddiu  a0, 4                   #inc to next source instruction

1:      lw      a1,0(a0)                #load next source loc
        sw      a1,0(a2)                #write it to dest adrs
        daddiu  a0, 4                   #inc to next src loc
        daddiu  a2, 4                   #inc to next dest loc
        blt     a0, s1, 1b              #done? no, jump

# copy is done, reload parameters and call the relocated routine


#if 0
/* Lock L2 cache (for our region only).
   Designed this code from tracing the "cvmx_l2c_lock_line():  " function
   in moodule "lib_mips/cvmx-l2c.c".  However,this does not seem to work. */
        ld      a2, 0(sp)               #recall relocation drs of asm code
        
        dli     s0,0x8001180080000008   #reg L2T_ERR adrs
        ld      a0,0(s0)                #load the reg
        dli     s1,0x0000000005000000
        or      s1,s1,a0
        sd      s1,0(s0)                #clr LCKERR & LCKERR2 bits
        sync
        
        dli     s0,0x8001180080000030   #reg L2C_DBG adrs
        dli     s1,0x0000000000000000
        sd      s1,0(s0)                #sel proc 0 as debug proc
        ld      s1,0(s0)                #force write to occur
        
        dli     s0,0x8001180080000060   #reg L2C_LCKOFF adrs
        dli     s1,0x0000000000000000
        sd      s1,0(s0)                #clr lock 0ffset
        ld      s1,0(s0)                #force write to occur
        
        dli     s0,0x8001180080000058   #reg L2C_LCKBASE adrs
        dli     s1,0x0000000070000001
        sd      s1,0(s0)                #set lock base adrs
        ld      s1,0(s0)                #force write to occur
        
        ld      s0,0(a2)                #load the locked cachline
       
        dli     s0,0x8001180080000058   #reg L2C_LCKBASE adrs
        dli     s1,0x0000000070000000
        sd      s1,0(s0)                #clear lock en (but leave base set up)
        ld      s1,0(s0)                #force write to occur
        sync
        
        dli     s0,0x8001180080000008   #reg L2T_ERR adrs
        ld      a0,0(s0)                #load the reg
        
#        dli     s1,0x0000000000000004   #locking 4 cache blocks
#        sd      s1, 8(s0)               #set up to lock 4 blocks (512 B)
#        ld      s1, 8(s0)               #read it back to force th last write
#        dli     s1,0x0000000010000001   #ld base lock adrs & lock bit
#        sd      s1, 0(s0)               #lock the cache
#        ld      s1, 0(s0)               #read it back to force the last write
/* L2 should be locked now */
#endif
                
        ld      a3, 48(sp)              #recall beg address of fill
        ld      a0, 16(sp)              #recall beg address of fill
        ld      a1, 8(sp)               #recall end address of fill
        ld      a2, 0(sp)               #recall dest adrs
        jalr    a2                      #jump to re-located routine
        nop
        nop
        nop
        b       lrfsr_end               #jump around fill logic to exit
        nop
        
lrfsr_beg:
3:      sh      a3,0(a0)                #store test pat in next location
        daddiu  a0, 2                   #inc to next loc
        blt     a0, a1, 3b              #done? no, jump
        sync
#        syncs
#        ehb
        syncw
        jr      ra                      #return to calling code
        nop
        nop
        
lrfsr_end:   
#if 0
/* debug - cause a failure to test error logic.  This bug does not 
           always work at high-speed */
        ld      a0, 16(sp)              #recall beg address of fill
        ld      a1, 16(sp)              #get a 2nd copy of beg adrs
        daddiu  a0, 0x100               #calc beg adrs
        daddiu  a1, 0x7000              #calc end adrs
        dli     a2,0x1122334455667788
4:      sd      a2,0(a0)                #store garbage in each location
        sync
        daddiu  a0, 8                   #inc to next loc
        daddiu  a2, 8                   #inc to next pattern
        blt     a0, a1, 4b              #done? no, jump
        sync
        sync
        syncw
#        syncw
#        syncs
#        syncws
/* end special debug code */
#endif
                
        ld      a3, 48(sp)              #recall regs off the stack
        ld      s1, 40(sp)
        ld      s0, 32(sp)
        ld      ra, 24(sp)
        ld      a0, 16(sp)
        ld      a1, 8(sp)
        ld      a2, 0(sp)
        
        addiu   sp, sp, (7*8)           #restore stack pointer
        jr      ra                      #return to calling code
        nop                             #delay - slot
lrfsr_exit:   
        nop
        
/*****************************************************************************
 **          High Speed Verify RAM Cells Routine (Relocatable) 
 **
 **    This function relocates itself to the address specifiec by the calling
 ** code then reads RAM at high speed and verifies the data at each 
 ** location contains the test pattern supplied by the calling code.  The 
 ** results of the verify are reported back to the calling code.
 **
 ** NOTE: This function reads 16-bits at a time so the beginning address must
 **       be located on a 16-bit boundary.
 **
 ** void ll_asm_ram_cells_verify_16_rel(u64 beg_adr, u64 end address, 
 **                                     u64 * results_ptr, u64 rel_adrs,
 **                                     u64 exp_data)
 **
 ** Parameters
 ** a0 = beg adrs of region to be verified
 ** a1 = last location to be verified
 ** a2 = pointer to results array.
 ** a3 = relocation address
 ** t0 = data expected in each cell
 **
 ** Other registers
 ** s0 = working register
 ** s1 = calc last adrs to be copied
 ** s2 = Data read from RAM
 ** s3 = Pointer to next 64-bit value to be read
 **
 ****************************************************************************/
        .globl  ll_asm_ram_cells_verify_16_rel
        
ll_asm_ram_cells_verify_16_rel:    
        addiu   sp, sp, -(10*8)         #make space on stack for storage
        sd      t0, 72(sp)              #save regs on stack
        sd      ra, 64(sp)
        sd      s3, 56(sp)
        sd      s2, 48(sp)
        sd      s1, 40(sp)
        sd      a0, 32(sp)
        sd      a1, 24(sp)
        sd      a2, 16(sp)
        sd      a3, 8(sp)
        sd      s0, 0(sp)
        
#if 0 /* debug - cause a failure to test error logic.  This bug does not 
        always work at high-speed */
        dli     s2,0x1122334455667788
        sd      s2,0x230(a0)            #store bad data
        sync
        syncs
        syncws
#endif
#
# copy the routine below to destination address and jump to it
        jal     larcvsr_jmp             #get cur pc contents
        nop
#        daddu   
larcvsr_jmp:       #<- reg 'ra' contains this locations's adrs
        daddiu  s0,zero,(larcvsr_end -  larcvsr_beg) #cal length of copy
        daddiu  a0,ra,(larcvsr_beg-larcvsr_jmp) #calc src adrs of copy
        daddu   s1,a0,s0                #calc last src adrs to be copied
        daddiu  a0, 4                   #inc to next source instruction
        
# Boot PROM region does not support 64-bit transfers. So use 32-bit read/writes
        
1:      lw      a1,0(a0)                #load next source loc
        sw      a1,0(a3)                #write it to dest adrs
        daddiu  a0, 4                   #inc to next src loc
        daddiu  a3, 4                   #inc to next dest loc
        blt     a0, s1, 1b              #done? no, jump

# copy is done, reload parameters and call the relocated routine
        
        ld      t0, 72(sp)              #recall all parameters
        ld      a0, 32(sp)
        ld      a1, 24(sp)
        ld      a2, 16(sp) 
        ld      a3, 8(sp)
        jalr    a3                      #jump to re-located routine
        nop
        b       larcvsr_end             #jump around fill logic to exit
        nop
#
#
larcvsr_beg:   #beginning of copied code
        nop
        syncw
    
        dli     s0,0x000000000000FFFF   #data mask
        daddu   s3,a0,zero              #save a copy of next adrs to be read
#if 0 /* debug - cause a failure */
        dli     t0,0x1122334455667788   #mess up expected data
#endif
larcvsr_10:
        syncw
        lh      s2,0(s3)                #read next 16-bit location
        and     s2,s2,s0                #mask off bits we don't need
        syncw
        sync
        bne     t0,s2,larcvsr_err       #contains exp pattern? No, jmp to err
        nop
        
        daddiu  s3, 2                   #inc to next loc
        blt     s3, a1,larcvsr_10       #done? no, jump to read next adrs
        nop
        b       larcvsr_exit_good       #exit with good status
        nop

# Enter here to report an error        
# s2 = bad data read
# a4 = expected data
# a2 = pointer to asm test results array
# s3 = address that contains bad data
#
larcvsr_err:
        sd      s3,(ASM_TEST_ADRS_AT_FAULT*8)(a2) #save adrs that failed
        sd      t0,(ASM_TEST_EXP_DATA*8)(a2)      #save exp data in array
        sd      s2,(ASM_TEST_BAD_DATA*8)(a2)      #save bad data read
        dli     s0,ASM_TEST_FAILED
        sd      s0,(ASM_TEST_RESULTS*8)(a2)       #flag test failed
        b       larcvsr_exit
        nop

larcvsr_exit_good:
        dli     s0,ASM_TEST_PASSED
        sd      s0,(ASM_TEST_RESULTS*8)(a2) #flag test passed
        b       larcvsr_exit
        nop
        
larcvsr_exit:
        nop
        sync
        syncw
        jr      ra                      #return to calling code
        nop
        nop
        
larcvsr_end:   #end of copied code
        nop

        ld      t0, 72(sp)              #recall regs off the stack
        ld      ra, 64(sp)
        ld      s3, 56(sp)
        ld      s2, 48(sp)
        ld      s1, 40(sp)
        ld      a0, 32(sp)
        ld      a1, 24(sp)
        ld      a2, 16(sp)
        ld      a3, 8(sp)
        ld      s0, 0(sp)
        
        addiu   sp, sp, (10*8)          #restore stack pointer
        jr      ra                      #return to calling code
        nop                             #delay - slot





