2103 lines
47 KiB
ArmAsm
2103 lines
47 KiB
ArmAsm
/*
|
|
* File: pod_cache.s
|
|
* Purpose: Cache testing, initializeation and error processing routine for
|
|
* R10K boot prom.
|
|
*
|
|
* Copyright 1995, Silicon Graphics, Inc.
|
|
* ALL RIGHTS RESERVED
|
|
*
|
|
* UNPUBLISHED -- Rights reserved under the copyright laws of the United
|
|
* States. Use of a copyright notice is precautionary only and does not
|
|
* imply publication or disclosure.
|
|
*
|
|
* U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
|
|
* Use, duplication or disclosure by the Government is subject to restrictions
|
|
* as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
|
|
* in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
|
|
* in similar or successor clauses in the FAR, or the DOD or NASA FAR
|
|
* Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
|
|
* 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
|
|
*
|
|
* THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
|
|
* INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
|
|
* DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
|
|
* PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
|
|
* GRAPHICS, INC.
|
|
*/
|
|
|
|
#include <asm.h>
|
|
|
|
#include <sys/regdef.h>
|
|
#include <sys/sbd.h>
|
|
#include <sys/mips_addrspace.h>
|
|
|
|
#include <sys/EVEREST/IP25.h>
|
|
#include <sys/EVEREST/evdiag.h>
|
|
|
|
#include "ip25prom.h"
|
|
#include "prom_leds.h"
|
|
#include "pod.h"
|
|
#include "cache.h"
|
|
|
|
#define K0_BASE 0xa800000000000000
|
|
|
|
/*
|
|
* The following patterns of data are used for cache testing. Each entry
|
|
* Has the form:
|
|
*
|
|
* +----------+----------+-------+-------------+------------+
|
|
* | Tag Hi | Tag Lo | ECC | Reserved | Data |
|
|
* +----------+----------+-------+-------------+------------+
|
|
* Byte 0 0 0 0 0 1 1 1 1 2
|
|
* Offset 0 3 4 7 8 1 2 5 6 3
|
|
*
|
|
* Tag Hi: Pattern to test the upper 32-bits of the tag with.
|
|
* Tag Lo: Patterns to test lower 32-bits of tag with.
|
|
* ECC: Pattern to use in ECC register.
|
|
* Data: 64 bits of data to test cache data fields.
|
|
*/
|
|
|
|
#define CP_TAG 0 /* Double word access */
|
|
#define CP_TAG_HI 0 /* Word Access, high order 32 bits */
|
|
#define CP_TAG_LO 4 /* Word access, low order 32 bits */
|
|
#define CP_ECC 8
|
|
#define CP_DATA 16
|
|
#define CP_DATA_HI 16 /* First 4 bytes for 4-byte access */
|
|
#define CP_DATA_LO 20 /* Last 4 bytes for 4-byte access */
|
|
#define CP_SIZE 24 /* Total size of entry */
|
|
|
|
/*
|
|
* Macro: CACHE_PATTERN
|
|
* Purpose: Form a cache pattern entry.
|
|
*/
|
|
#define CACHE_PATTERN(taghi, taglo, ecc, datahi, datalo) \
|
|
.word taghi; .word taglo; .word ecc; .word 0; .word datahi; .word datalo
|
|
|
|
#define SCACHE_PATTERN(taghi, taglo, ecc, data) \
|
|
CACHE_PATTERN(taghi & CTS_TAGHI_MASK, taglo & CTS_TAGLO_MASK, ecc, data, data)
|
|
|
|
#define ICACHE_PATTERN(taghi, taglo, ecc, data) \
|
|
CACHE_PATTERN(taghi & CTP_ICACHE_TAGHI_MASK, taglo & CTP_ICACHE_TAGLO_MASK,\
|
|
ecc & 1, data & 0xf, data)
|
|
#define DCACHE_PATTERN(taghi, taglo, ecc, data) \
|
|
CACHE_PATTERN(taghi & CTP_DCACHE_TAGHI_MASK & 0x0fffffff, taglo & CTP_DCACHE_TAGLO_MASK,\
|
|
ecc & 0xf, data, data)
|
|
|
|
#define SCCTAG_PATTERN(tag) .dword (tag & 0x00ffffff)
|
|
#define SCC_SIZE 8
|
|
|
|
.data
|
|
|
|
.align 8
|
|
scache_patternStart:
|
|
#if !defined(SABLE )
|
|
SCACHE_PATTERN(0xaaaaaaaa, 0xaaaaaaaa, 0x2aa, 0xaaaaaaaa)
|
|
SCACHE_PATTERN(0x55555555, 0x55555555, 0x155, 0x55555555)
|
|
SCACHE_PATTERN(0x00000000, 0x00000000, 0x000, 0x00000000)
|
|
#endif
|
|
scache_patternEnd:
|
|
|
|
icache_patternStart:
|
|
#if !defined(SABLE)
|
|
ICACHE_PATTERN(0xffffffff, 0xffffffff, 0xff, 0xffffffff)
|
|
ICACHE_PATTERN(0xaaaaaaaa, 0xaaaaaaaa, 0xaa, 0xaaaaaaaa)
|
|
ICACHE_PATTERN(0x55555555, 0x55555555, 0x55, 0x55555555)
|
|
ICACHE_PATTERN(0x00000000, 0x00000000, 0x00, 0x00000000)
|
|
#endif
|
|
icache_patternEnd:
|
|
|
|
dcache_patternStart:
|
|
#ifndef SABLE
|
|
DCACHE_PATTERN(0xffffffff, 0xffffffff, 0xff, 0xffffffff)
|
|
DCACHE_PATTERN(0xaaaaaaaa, 0xaaaaaaaa, 0xaa, 0xaaaaaaaa)
|
|
DCACHE_PATTERN(0x55555555, 0x55555555, 0x55, 0x55555555)
|
|
DCACHE_PATTERN(0x00000000, 0x00000000, 0x00, 0x00000000)
|
|
#endif
|
|
dcache_patternEnd:
|
|
|
|
scctag_patternStart:
|
|
#ifndef SABLE
|
|
SCCTAG_PATTERN(0xffffffffffffffff)
|
|
SCCTAG_PATTERN(0xaaaaaaaaaaaaaaaa)
|
|
SCCTAG_PATTERN(0x5555555555555555)
|
|
SCCTAG_PATTERN(0x0000000000000000)
|
|
#endif
|
|
scctag_patternEnd:
|
|
|
|
#undef CACHE_PATTERN
|
|
#undef SCACHE_PATTERN
|
|
#undef ICACHE_PATTERN
|
|
#undef DCACHE_PATTERN
|
|
#undef SCCTAG_PATTERN
|
|
|
|
.text
|
|
.set reorder
|
|
.set at
|
|
|
|
/*
|
|
* Function: sCacheSize
|
|
* Purpose: To read and return the size of the secondary cache
|
|
* Parameters:
|
|
* Returns: Cache size in bytes in v0
|
|
* Clobbers: v0,v1
|
|
*/
|
|
LEAF(sCacheSize)
|
|
.set noreorder
|
|
MFC0(v1, C0_CONFIG) # Pick of config register value
|
|
and v1,CONFIG_SS # isolate cache size
|
|
srl v1,CONFIG_SS_SHFT
|
|
add v1,CONFIG_SCACHE_POW2_BASE
|
|
li v0,1
|
|
j ra
|
|
sll v0,v1 # Calculate # bytes
|
|
END(sCacheSize)
|
|
/*
|
|
* Function: iCacheSize
|
|
* Purpose: To read and return the size of the primary instruction cache
|
|
* Parameters: none
|
|
* Returns: Cache size in bytes in v0
|
|
* Clobbers: v0,v1
|
|
*/
|
|
LEAF(iCacheSize)
|
|
.set noreorder
|
|
MFC0(v1, C0_CONFIG) # Pick of config register value
|
|
and v1,CONFIG_IC # isolate cache size
|
|
srl v1,CONFIG_IC_SHFT
|
|
add v1,CONFIG_PCACHE_POW2_BASE
|
|
li v0,1
|
|
j ra
|
|
sll v0,v1 # Calculate # bytes
|
|
END(iCacheSize)
|
|
|
|
/*
|
|
* Function: dCacheSize
|
|
* Purpose: To read and return the size of the primary data cache
|
|
* Parameters: none
|
|
* Returns: Cache size in bytes in v0
|
|
* Clobbers: v0,v1
|
|
*/
|
|
LEAF(dCacheSize)
|
|
.set noreorder
|
|
MFC0(v1, C0_CONFIG) # Pick up config register value
|
|
and v1,CONFIG_DC # isolate cache size
|
|
srl v1,CONFIG_DC_SHFT
|
|
add v1,CONFIG_PCACHE_POW2_BASE
|
|
li v0,1
|
|
j ra
|
|
sll v0,v1 # Calculate # bytes
|
|
END(dCacheSize)
|
|
|
|
/*
|
|
* Function: testIcache
|
|
* Purpose: verify we can write and read the Icache.
|
|
* Parameters: None
|
|
* Returns: v0 = 0 - success
|
|
* = !0- failed
|
|
* Notes: The data patterns 0xaaaaaaaaa and 0x55555555 are used
|
|
* to try and check for bits stuck to 0 or 1.
|
|
*/
|
|
LEAF(testIcache)
|
|
.set noreorder
|
|
|
|
LEDS(PLED_TESTICACHE)
|
|
|
|
/* Figure out the number of lines */
|
|
|
|
move t0,ra /* save our way home */
|
|
jal iCacheSize
|
|
nop
|
|
move ra,t0 /* And Back! */
|
|
divu t0,v0,CACHE_ILINE_SIZE*2 /* # lines in t0/# ways */
|
|
|
|
dla v0,icache_patternStart /* Set first pattern */
|
|
1:
|
|
/*
|
|
* Check if we are done at the top of the loop. This means that
|
|
* we can have NO test patterns if desired.
|
|
*/
|
|
dla v1,icache_patternEnd
|
|
bge v0,v1,testIcacheData
|
|
nop
|
|
lw v1,CP_TAG_HI(v0) /* Pick up pattern */
|
|
lw t3,CP_TAG_LO(v0)
|
|
|
|
/*
|
|
* Loop through all lines and write the TAG and Data. Note that
|
|
* the parity may be incorrect, but we ONLY access the tags at
|
|
* this point using the cache instruction which ignores parity.
|
|
*/
|
|
|
|
move t1,t0 /* # lines */
|
|
dli t2,K0_BASE
|
|
|
|
MTC0(v1, C0_TAGHI)
|
|
MTC0(t3, C0_TAGLO)
|
|
2:
|
|
ICACHE(C_IST, 0(t2)) /* Hit both ways */
|
|
ICACHE(C_IST, 1(t2))
|
|
|
|
sub t1,1
|
|
bgtz t1,2b /* See if more to do ... */
|
|
daddu t2,CACHE_ILINE_SIZE
|
|
|
|
/*
|
|
* At this point, the tags have been written. Read them
|
|
* back to see what happened. Note that above, we have
|
|
* saved expected values in v0/v1.
|
|
*/
|
|
|
|
move t1,t0 /* Number of lines */
|
|
dli t2,K0_BASE
|
|
3:
|
|
ICACHE(C_ILT, 0(t2)) /* one way */
|
|
MFC0(a0,C0_TAGHI)
|
|
bne a0,v1,testIcacheFailAddrWay0
|
|
MFC0(a1,C0_TAGLO)
|
|
bne a1,t3,testIcacheFailAddrWay0
|
|
ICACHE(C_ILT, 1(t2)) /* or the other */
|
|
MFC0(a0,C0_TAGHI)
|
|
bne a0,v1,testIcacheFailAddrWay1
|
|
MFC0(a1,C0_TAGLO)
|
|
bne a1,t3,testIcacheFailAddrWay1
|
|
|
|
sub t1,1
|
|
bgtz t1,3b
|
|
daddu t2,CACHE_ILINE_SIZE
|
|
|
|
/*
|
|
* Move onto next test pattern.
|
|
*/
|
|
j 1b
|
|
dadd v0,CP_SIZE
|
|
|
|
testIcacheData:
|
|
/*
|
|
* Now test the data part of the ICACHE, t0 still contains the
|
|
* # of lines.
|
|
*/
|
|
dla v0,icache_patternStart
|
|
1:
|
|
/*
|
|
* Check if we are done at the top of the loop. This means that
|
|
* we can have NO test patterns if desired.
|
|
*/
|
|
dla v1,icache_patternEnd
|
|
bge v0,v1,testIcacheDone
|
|
nop
|
|
lw ta1,CP_DATA_HI(v0) /* Pick up pattern */
|
|
lw ta2,CP_DATA_LO(v0)
|
|
lw ta3,CP_ECC(v0) /* ECC info */
|
|
|
|
/*
|
|
* Loop through all lines and write the Data. Note that
|
|
* the parity may be incorrect, but we ONLY access the data at
|
|
* this point using the cache instruction which ignores parity.
|
|
*/
|
|
|
|
move t1,t0 /* # lines */
|
|
dli t2,K0_BASE
|
|
|
|
MTC0(ta1, C0_TAGHI)
|
|
MTC0(ta2, C0_TAGLO)
|
|
MTC0(ta3, C0_ECC)
|
|
|
|
/*
|
|
* Fill the line with the pattern in both "ways". t2 has the
|
|
* virtual address of the start of the cache line.
|
|
*/
|
|
2:
|
|
li ta0,CACHE_ILINE_SIZE/4
|
|
4:
|
|
ICACHE(C_ISD, 0(t2))
|
|
ICACHE(C_ISD, 1(t2))
|
|
3: /* Loop over all words in line */
|
|
ICACHE(C_ILD, 0(t2))
|
|
MFC0(a1, C0_TAGHI)
|
|
MFC0(a2, C0_TAGLO)
|
|
MFC0(a3, C0_ECC)
|
|
bne a1,ta1,testIcacheFailDataWay0
|
|
nop
|
|
bne a2,ta2,testIcacheFailDataWay0
|
|
nop
|
|
bne a3,ta3,testIcacheFailDataWay0
|
|
|
|
ICACHE(C_ILD, 1(t2))
|
|
MFC0(a1, C0_TAGHI)
|
|
MFC0(a2, C0_TAGLO)
|
|
MFC0(a3, C0_ECC)
|
|
bne a1,ta1,testIcacheFailDataWay1
|
|
nop
|
|
bne a2,ta2,testIcacheFailDataWay1
|
|
nop
|
|
bne a3,ta3,testIcacheFailDataWay1
|
|
|
|
sub ta0,1
|
|
bgtz ta0,4b /* more words in line */
|
|
daddiu t2,4 /* DELAY: Up 4 bytes */
|
|
|
|
sub t1,1
|
|
bgtz t1,2b /* See if more to do ... */
|
|
nop
|
|
|
|
/*
|
|
* Move onto next test pattern.
|
|
*/
|
|
j 1b
|
|
daddu v0,CP_SIZE
|
|
|
|
testIcacheDone:
|
|
j ra
|
|
move v0,zero /* success */
|
|
|
|
testIcacheFailAddrWay0:
|
|
MESSAGE(a2, "I-cache tag compare error: way 0:");
|
|
b testIcacheFailAddr
|
|
nop
|
|
testIcacheFailAddrWay1:
|
|
MESSAGE(a2, "I-cache tag compare error: way 1:");
|
|
testIcacheFailAddr:
|
|
/*
|
|
* Tag compare error:
|
|
* a0/a1 - taghi/taglo read values
|
|
* v1,t3 - taghi/taglo expected values
|
|
* t2 - address
|
|
*/
|
|
dsll a0,32
|
|
dsll a1,32
|
|
dsrl a1,32
|
|
or t0,a1,a0 /* 64-bit read back value */
|
|
|
|
dsll v1,32
|
|
dsll t3,32
|
|
dsrl t3,32
|
|
or t3,v1 /* 64-bit expected value */
|
|
|
|
move t1,ra /* Save return address */
|
|
|
|
PMESSAGE_PTR(a2); PMESSAGE(" address: 0x"); PHEX(t2)
|
|
PMESSAGE("\n\r\twrote: 0x"); PHEX(t3);
|
|
PMESSAGE(" read: 0x"); PHEX(t0);
|
|
PMESSAGE("\n\r")
|
|
|
|
j t1
|
|
ori v0,zero,EVDIAG_ICACHE_ADDR
|
|
|
|
testIcacheFailDataWay0:
|
|
MESSAGE(a0, "\r\n I-cache data compare error: way 0:")
|
|
b testIcacheFailData
|
|
nop
|
|
testIcacheFailDataWay1:
|
|
MESSAGE(a0, "\r\n I-cache data compare error: way 1:")
|
|
testIcacheFailData:
|
|
/*
|
|
* Data Compare error:
|
|
* v0 - address of pattern in table.
|
|
* a1/a2/a3 - read HI/LO/ECC
|
|
* t2 - address
|
|
*/
|
|
|
|
dsll a1,32
|
|
dsll a2,32
|
|
dsrl a2,32
|
|
or a2,a1 /* 64-bit read value */
|
|
|
|
move t0,ra
|
|
move t1,a1 /* Gets lots in print calls */
|
|
move t3,v0 /* Save pointer to table */
|
|
move k0,a3 /* zapped in HEX output */
|
|
|
|
PMESSAGE_PTR(a0); PMESSAGE(" address: 0x"); PHEX(t2)
|
|
PMESSAGE("\n\r\twrote(data/ecc): 0x");
|
|
lwu a0,CP_DATA_HI(t3)
|
|
lwu a1,CP_DATA_LO(t3)
|
|
or a0,a1
|
|
PHEX(a0)
|
|
PMESSAGE("/0x");
|
|
lwu a0,CP_ECC(t3)
|
|
PHEX32(a0)
|
|
|
|
PMESSAGE(" read(data/ecc): 0x")
|
|
PHEX32(a2); PMESSAGE("/0x"); PHEX32(k0)
|
|
|
|
j t0
|
|
ori v0,zero,EVDIAG_ICACHE_DATA
|
|
END(testIcache)
|
|
|
|
/*
|
|
* Function: testDcache
|
|
* Purpose: Verify we can write/read the Dcache
|
|
* Parameters: none
|
|
* Returns: v0 = 0 - success
|
|
* v0 !=0 = failed
|
|
*/
|
|
LEAF(testDcache)
|
|
.set noreorder
|
|
LEDS(PLED_TESTDCACHE)
|
|
|
|
/* figure out # of lines */
|
|
|
|
move t0,ra /* save way back */
|
|
jal dCacheSize
|
|
nop
|
|
move ra,t0 /* Restore return path */
|
|
divu t0,v0,CACHE_DLINE_SIZE*2 /* # lines in t0/#ways */
|
|
|
|
dla v0,dcache_patternStart
|
|
1:
|
|
/*
|
|
* Check if we are done at the top of the loop. This means that
|
|
* we can have NO test patterns if desired.
|
|
*/
|
|
dla v1,dcache_patternEnd
|
|
bge v0,v1,testDcacheData
|
|
nop
|
|
lw v1,CP_TAG_HI(v0) /* Pick up pattern */
|
|
lw t3,CP_TAG_LO(v0)
|
|
|
|
/*
|
|
* Loop through all lines and write the TAG and Data. Note that
|
|
* the parity may be incorrect, but we ONLY access the tags at
|
|
* this point using the cache instruction which ignores parity.
|
|
*/
|
|
|
|
move t1,t0 /* # lines */
|
|
dli t2,K0_BASE
|
|
|
|
MTC0(v1, C0_TAGHI)
|
|
MTC0(t3, C0_TAGLO)
|
|
2:
|
|
DCACHE(C_IST, 0(t2)) /* Hit both ways */
|
|
DCACHE(C_IST, 1(t2))
|
|
|
|
sub t1,1
|
|
daddu t2,CACHE_DLINE_SIZE
|
|
bgtz t1,2b /* See if more to do ... */
|
|
nop
|
|
|
|
/*
|
|
* At this point, the tags have been written. Read them
|
|
* back to see what happened. Note that above, we have
|
|
* saved expected values in v1/t3.
|
|
*/
|
|
|
|
move t1,t0 /* Number of lines */
|
|
dli t2,K0_BASE
|
|
3:
|
|
DCACHE(C_ILT, 0(t2)) /* one way */
|
|
MFC0(a2,C0_TAGHI)
|
|
bne a2,v1,testDcacheFailAddrWay0
|
|
MFC0(a1,C0_TAGLO) /* DELAY */
|
|
bne a1,t3,testDcacheFailAddrWay0
|
|
DCACHE(C_ILT, 1(t2)) /* or the other */
|
|
MFC0(a2,C0_TAGHI)
|
|
bne a2,v1,testDcacheFailAddrWay1
|
|
MFC0(a1,C0_TAGLO) /* DELAY */
|
|
bne a1,t3,testDcacheFailAddrWay1
|
|
|
|
sub t1,1
|
|
bgtz t1,3b
|
|
daddu t2,CACHE_DLINE_SIZE
|
|
|
|
/*
|
|
* Move onto next test pattern.
|
|
*/
|
|
j 1b
|
|
daddu v0,CP_SIZE
|
|
|
|
testDcacheData:
|
|
/*
|
|
* Now test the data part of the ICACHE, t0 still contains the
|
|
* # of lines.
|
|
*/
|
|
dla v0,dcache_patternStart
|
|
|
|
1:
|
|
/*
|
|
* Check if we are done at the top of the loop. This means that
|
|
* we can have NO test patterns if desired.
|
|
*/
|
|
dla v1,dcache_patternEnd
|
|
bge v0,v1,testDcacheDone
|
|
nop
|
|
lw v1,CP_DATA_LO(v0) /* Pick up pattern */
|
|
lw t3,CP_ECC(v0)
|
|
|
|
/*
|
|
* Loop through all lines and write the Data. Note that
|
|
* the parity may be incorrect, but we ONLY access the data at
|
|
* this point using the cache instruction which ignores parity.
|
|
*/
|
|
|
|
move a3,t0 /* # lines */
|
|
dli t2,K0_BASE
|
|
|
|
DMTC0(v1, C0_TAGLO)
|
|
DMTC0(t3, C0_ECC)
|
|
2:
|
|
/*
|
|
* Fill the line with the pattern in both "ways". t2 has the
|
|
* virtual address of the start of the cache line.
|
|
*/
|
|
li a0,CACHE_DLINE_SIZE/4
|
|
|
|
DCACHE(C_ISD, 0(t2))
|
|
DCACHE(C_ISD, 1(t2))
|
|
|
|
3: /* Loop over all words in line */
|
|
DCACHE(C_ILD, 0(t2))
|
|
MFC0(a1,C0_ECC)
|
|
bne a1,t3,testDcacheFailDataWay0
|
|
MFC0(a2,C0_TAGLO) /* DELAY */
|
|
bne a2,v1,testDcacheFailDataWay0
|
|
nop
|
|
|
|
DCACHE(C_ILD, 1(t2))
|
|
MFC0(a1,C0_ECC)
|
|
bne a1,t3,testDcacheFailDataWay1
|
|
MFC0(a2,C0_TAGLO) /* DELAY */
|
|
bne a2,v1,testDcacheFailDataWay1
|
|
nop
|
|
|
|
sub a0,1
|
|
bgtz a0,3b /* more words in line */
|
|
nop
|
|
|
|
sub a3,1
|
|
bgtz a3,2b /* See if more to do ... */
|
|
daddu t2,CACHE_DLINE_SIZE
|
|
|
|
/*
|
|
* Move onto next test pattern.
|
|
*/
|
|
j 1b
|
|
daddu v0,CP_SIZE
|
|
|
|
testDcacheDone:
|
|
j ra
|
|
move v0,zero /* success */
|
|
|
|
testDcacheFailAddrWay0:
|
|
MESSAGE(a0, "\r\n D-cache tag compare error: Way 0:")
|
|
b testDcacheFailAddr
|
|
nop
|
|
testDcacheFailAddrWay1:
|
|
MESSAGE(a0, "\r\n D-cache tag compare error: Way 1:")
|
|
testDcacheFailAddr:
|
|
/*
|
|
* Dump information on the failure:
|
|
* a1/a2 - read taglo/taghi
|
|
* t3/v1 - expected taglo/taghi
|
|
* t2 - address
|
|
*/
|
|
|
|
dsll a2,32
|
|
dsll a1,32
|
|
dsrl a1,32
|
|
or a2,a1 /* 64-bit read value */
|
|
|
|
dsll v1,32
|
|
dsll t3,32
|
|
dsrl t3,32
|
|
or t3,v1 /* 64-bit expected value */
|
|
|
|
move t1, ra
|
|
|
|
PMESSAGE_PTR(a0); PMESSAGE(" address: 0x"); PHEX(t2);
|
|
PMESSAGE("\n\r\t wrote: 0x"); PHEX(t3);
|
|
PMESSAGE(" read: 0x"); PHEX(a2);
|
|
PMESSAGE("\n\r");
|
|
j t1
|
|
ori v0,zero,EVDIAG_DCACHE_ADDR /* DELAY */
|
|
|
|
testDcacheFailDataWay0:
|
|
MESSAGE(a0, "\r\n D-cache data compare error: Way 0:")
|
|
b testDcacheFailData
|
|
nop
|
|
testDcacheFailDataWay1:
|
|
MESSAGE(a0, "\r\n D-cache data compare error: Way 1:")
|
|
testDcacheFailData:
|
|
/*
|
|
* Dump information on the failure:
|
|
* a1/a2 - read ecc/taglo
|
|
* t3/v1 - expected ecc/taglo
|
|
* t2 - address
|
|
*/
|
|
move a3,a1 /* A1 - clobber by I/O */
|
|
move t0,v1 /* Clobbered by I/O */
|
|
|
|
move t1, ra
|
|
|
|
PMESSAGE_PTR(a0); PMESSAGE(" address: 0x"); PHEX(t2);
|
|
PMESSAGE("\n\r\t wrote(data/parity): 0x"); PHEX32(t0);
|
|
PMESSAGE("/0x"); PHEX32(t3);
|
|
PMESSAGE(" read(data/parity): 0x"); PHEX32(a2);
|
|
PMESSAGE("/0x"); PHEX32(a3);
|
|
PMESSAGE("\n\r");
|
|
|
|
j t1
|
|
ori v0,zero,EVDIAG_DCACHE_DATA /* DELAY */
|
|
|
|
testDcacheFail:
|
|
|
|
END(testDcache)
|
|
|
|
|
|
.text
|
|
|
|
/*
|
|
* Function: invalidateIcache
|
|
* Purpsoe: To invalidate the primary icache and leave it in a consistent
|
|
* state.
|
|
* Parameters: none
|
|
* Returns: nothing
|
|
* Notes: uses t0,t1,v0,v1
|
|
*/
|
|
LEAF(invalidateIcache)
|
|
.set noreorder
|
|
LEDS(PLED_INVICACHE)
|
|
move t0,ra /* Remeber way home */
|
|
jal iCacheSize
|
|
nop
|
|
move ra,t0 /* Back to its place */
|
|
divu v0,CACHE_ILINE_SIZE*2 /* # of lines/ways */
|
|
|
|
/*
|
|
* For each cache line, we build a valid looking tag, except
|
|
* that the state indicates the line is invalid. As it turns out,
|
|
* parity fields are even, and "0" is an invalid line.
|
|
*/
|
|
|
|
MTC0(zero, C0_TAGLO)
|
|
MTC0(zero, C0_TAGHI) /* Tag registers */
|
|
DMTC0(zero, C0_ECC) /* 0's - even parity */
|
|
|
|
/* first the tags */
|
|
|
|
move t0,zero
|
|
dli t1,K0_BASE
|
|
1:
|
|
ICACHE(C_IST, 0(t1)) /* way 0 */
|
|
ICACHE(C_IST, 1(t1)) /* way 1 */
|
|
daddu t1, CACHE_ILINE_SIZE
|
|
add t0,1
|
|
ble t0,v0,1b
|
|
nop
|
|
|
|
/*
|
|
* Now for safty, the data - even parity, so taglo/hi are
|
|
* still ok.
|
|
*/
|
|
|
|
dli t1,K0_BASE
|
|
dli t0,CACHE_ILINE_SIZE
|
|
mult v0,t0 /* Total # bytes per way */
|
|
mflo v0
|
|
1:
|
|
ICACHE(C_ISD, 0(t1))
|
|
ICACHE(C_ISD, 1(t1))
|
|
sub v0,4 /* count -= word size */
|
|
daddu t1,4 /* DELAY: address += word size */
|
|
bgtz v0,1b
|
|
nop
|
|
|
|
j ra
|
|
nop
|
|
END(invalidateIcache)
|
|
|
|
/*
|
|
* Function: invalidateDcache
|
|
* Purpsoe: To invalidate the primary icache and leave it in a consistent
|
|
* state.
|
|
* Parameters: none
|
|
* Returns: nothing
|
|
* Notes: uses v0,v1 t0/t1 registers.
|
|
*/
|
|
LEAF(invalidateDcache)
|
|
.set noreorder
|
|
LEDS(PLED_INVDCACHE)
|
|
move t0,ra /* Remeber way home */
|
|
jal dCacheSize
|
|
nop
|
|
move ra,t0 /* Back to its place */
|
|
divu v0,CACHE_DLINE_SIZE*2 /* # of lines/ways */
|
|
|
|
/*
|
|
* For each cache line, we build a valid looking tag, except
|
|
* that the state indicates the line is invalid. As it turns out,
|
|
* parity fields are even, and "0" is an invalid line - except
|
|
* for the statemod field, which must be "NORMAL" or 1.
|
|
*/
|
|
|
|
dli t0,(CTP_STATEMOD_N << CTP_STATEMOD_SHFT) >> 32
|
|
|
|
MTC0(zero, C0_TAGLO)
|
|
MTC0(t0, C0_TAGHI) /* Tag registers */
|
|
DMTC0(zero, C0_ECC) /* 0's - even parity */
|
|
|
|
/* first the tags */
|
|
|
|
move t0,zero
|
|
dli t1,K0_BASE
|
|
1:
|
|
DCACHE(C_IST, 0(t1)) /* way 0 */
|
|
DCACHE(C_IST, 1(t1)) /* way 1 */
|
|
daddu t1, CACHE_DLINE_SIZE
|
|
add t0,1
|
|
ble t0,v0,1b
|
|
nop
|
|
|
|
/*
|
|
* Now for safty, the data. TAGLO and ECC used, but even
|
|
* parity so 0's works out well.
|
|
*/
|
|
|
|
dli t1,K0_BASE
|
|
dli t0,CACHE_DLINE_SIZE
|
|
mult v0,t0 /* total bytes per way */
|
|
mflo v0
|
|
1:
|
|
DCACHE(C_ISD, 0(t1))
|
|
DCACHE(C_ISD, 1(t1))
|
|
sub v0,4 /* count -= word size */
|
|
daddu t1,4 /* DELAY: address += word size */
|
|
bge v0,zero,1b
|
|
nop
|
|
|
|
j ra
|
|
nop
|
|
END(invalidateDcache)
|
|
|
|
/*
|
|
* Function: invalidateIDcache
|
|
* Purpose: To invalidate the primary I & D cache and leave them
|
|
* in a consistent state.
|
|
* Parameters: none
|
|
* Returns: nothing
|
|
* Notes: uses t0/t1 registers.
|
|
*/
|
|
LEAF(invalidateIDcache)
|
|
move t2,ra
|
|
jal invalidateIcache
|
|
nop
|
|
jal invalidateDcache
|
|
nop
|
|
j t2
|
|
nop
|
|
END(invalidateIDcache)
|
|
|
|
LEAF(invalidateCCtags)
|
|
/*
|
|
* Function: invalidateCCtags
|
|
* Purpose: To invalidate the SCC duplicate tags.
|
|
* Parameters: none
|
|
* Returns: nothing
|
|
* Notes: uses .... lots
|
|
* This routine copies a segment of code to the Scache and
|
|
* then the icache.
|
|
*/
|
|
.set noreorder
|
|
#if !defined(SABLE)
|
|
move s7,ra
|
|
LEDS(PLED_INVCCTAGS)
|
|
/*
|
|
* Due to a CC chip "feature", we must configure the cache
|
|
* as maximum size (for shiva) and clear all the duplicate
|
|
* tags - even if the cache is not full size.
|
|
*/
|
|
|
|
EV_GET_SPNUM(k0,k1) /* our address */
|
|
EV_GET_PROCREG(k0, k1, EV_CFG_CACHE_SZ, a4)
|
|
dli a0,5
|
|
EV_GET_SPNUM(k0,k1) /* our address */
|
|
EV_SET_PROCREG(k0, k1, EV_CFG_CACHE_SZ, a0)
|
|
GET_CC_REV(a0, a1)
|
|
bne a0,zero,invalidateCCtagsUncached
|
|
nop
|
|
/*
|
|
* Now copy the code segment to the Icache, and run it.
|
|
*/
|
|
dla a0,1f
|
|
dla a1,2f
|
|
jal copyToICache
|
|
dsubu a1,a0 /* DELAY: */
|
|
b invalidateCCtagsDoit
|
|
nop
|
|
invalidateCCtagsUncached:
|
|
dla v0, 1f
|
|
invalidateCCtagsDoit:
|
|
|
|
/* v0 - has cached address of routine on return */
|
|
|
|
li a0,4*1024*1024/CACHE_SLINE_SIZE
|
|
dli a1,EV_BTRAM_BASE
|
|
jal v0
|
|
nop
|
|
|
|
j 2f
|
|
nop /* And continue on */
|
|
/* Pad out to start of secondary cache line */
|
|
.align 7
|
|
1:
|
|
/*
|
|
* THIS CODE MAY BE EXECUTED OUT OF ICACHE.
|
|
*/
|
|
nop
|
|
sd zero,0(a1)
|
|
daddiu a1,CTD_SIZE
|
|
sub a0,1
|
|
bgtz a0,1b
|
|
nop
|
|
/*
|
|
* These instructions ensure that all store to the
|
|
* CC tags are complete before we do a read (instruction
|
|
* fetch). The GET_PROCREG makes sure of this, the SET_PROCREG
|
|
* is required to reset the cache size to its correct value.
|
|
*/
|
|
EV_GET_SPNUM(k0,k1) /* our address */
|
|
EV_SET_PROCREG(k0, k1, EV_CFG_CACHE_SZ, a4)
|
|
EV_GET_SPNUM(k0,k1) /* our address */
|
|
EV_GET_PROCREG(k0, k1, EV_CFG_CACHE_SZ, a4)
|
|
/*
|
|
* Now serialize and be sure the 4 decoded instructions do not cause
|
|
* a cache prefetch.
|
|
*/
|
|
DMFC0(zero, C0_SR)
|
|
j ra
|
|
nop
|
|
nop
|
|
nop
|
|
/* Pad out to end of secondary cache line */
|
|
.align 7
|
|
2:
|
|
move ra,s7
|
|
#endif
|
|
j ra
|
|
nop
|
|
END(invalidateCCtags)
|
|
|
|
/*
|
|
* Function: invalidateScache
|
|
* Purpose: To invalidate the secondary cache, both duplicate and
|
|
* T5 tags.
|
|
* Parameters: none
|
|
* Returns: nothing
|
|
* Notes: uses v0,t0
|
|
*/
|
|
LEAF(invalidateScache)
|
|
.set noreorder
|
|
|
|
LEDS(PLED_INVSCACHE)
|
|
#if !defined(SABLE)
|
|
move t0,ra /* Save return address */
|
|
|
|
jal sCacheSize /* go get cache size */
|
|
nop /* DELAY */
|
|
move ra,t0 /* Back to normal */
|
|
ddivu t0,v0,CACHE_SLINE_SIZE*2 /* # lines / way */
|
|
/*
|
|
* Set T5 cache tag in TAGLO/TAGHI registers.
|
|
*/
|
|
MTC0(zero, C0_TAGLO)
|
|
MTC0(zero, C0_TAGHI)
|
|
MTC0(zero, C0_ECC)
|
|
/*
|
|
* For each cache line, store an invalid tag with valid ECC,
|
|
*/
|
|
dli v0,K0_BASE
|
|
1:
|
|
SCACHE(C_IST, 0(v0)) /* T5: way 0 */
|
|
SCACHE(C_IST, 1(v0)) /* T5: way 1 */
|
|
SCACHE(C_ISD, 0x0(v0))
|
|
SCACHE(C_ISD, 0x1(v0))
|
|
SCACHE(C_ISD, 0x10(v0))
|
|
SCACHE(C_ISD, 0x11(v0))
|
|
SCACHE(C_ISD, 0x20(v0))
|
|
SCACHE(C_ISD, 0x21(v0))
|
|
SCACHE(C_ISD, 0x30(v0))
|
|
SCACHE(C_ISD, 0x31(v0))
|
|
SCACHE(C_ISD, 0x40(v0))
|
|
SCACHE(C_ISD, 0x41(v0))
|
|
SCACHE(C_ISD, 0x50(v0))
|
|
SCACHE(C_ISD, 0x51(v0))
|
|
SCACHE(C_ISD, 0x60(v0))
|
|
SCACHE(C_ISD, 0x61(v0))
|
|
SCACHE(C_ISD, 0x70(v0))
|
|
SCACHE(C_ISD, 0x71(v0))
|
|
|
|
daddiu v0,CACHE_SLINE_SIZE
|
|
sub t0,1
|
|
bgez t0,1b
|
|
nop
|
|
#endif
|
|
|
|
j ra
|
|
nop
|
|
END(invalidateScache)
|
|
|
|
/*
|
|
* Function: testScache
|
|
* Purpose: To test the secondary cache, without writting back to
|
|
* main memory. This does NOT touch CC duplicate tags.
|
|
* Parameters: none
|
|
* Returns: v0 - 0 OK, !0 failed
|
|
*/
|
|
LEAF(testScache)
|
|
LEDS(PLED_TESTSCACHE)
|
|
.set noreorder
|
|
|
|
/* Figure out # of lines */
|
|
|
|
move t0,ra /* save return address */
|
|
jal sCacheSize /* pick up scache size */
|
|
nop /* DELAY */
|
|
move ra,t0 /* Put back in nice place */
|
|
divu gp,v0,CACHE_SLINE_SIZE*2 /* 2-way remember */
|
|
|
|
dla v0,scache_patternStart
|
|
1:
|
|
/*
|
|
* Check if done at top of loop. This means that we can have
|
|
* no test patterns if desired.
|
|
*/
|
|
|
|
|
|
dla v1,scache_patternEnd
|
|
bge v0,v1,testScacheData
|
|
nop
|
|
|
|
/*
|
|
* First test all of the cache tags.
|
|
*/
|
|
dli v1,K0_BASE
|
|
move a3,gp /* Count # pairs of lines */
|
|
lw t1,CP_TAG_LO(v0)
|
|
lw t2,CP_TAG_HI(v0)
|
|
MTC0(t1, C0_TAGLO)
|
|
MTC0(t2, C0_TAGHI) /* top 32 bits */
|
|
2:
|
|
SCACHE(C_IST, 0(v1)) /* Store tag - way 0 */
|
|
SCACHE(C_IST, 1(v1)) /* - way 1 */
|
|
subu a3,1
|
|
daddiu v1,CACHE_SLINE_SIZE /* Next line(s) please */
|
|
bgtz a3,2b
|
|
nop
|
|
|
|
/*
|
|
* Read back all tags, note that the "correct" value of the 64-bit
|
|
* tag is in t1.
|
|
*/
|
|
dli v1,K0_BASE
|
|
move a3,gp /* Count # pairs of lines */
|
|
2:
|
|
|
|
SCACHE(C_ILT, 0(v1)) /* WAY 0 */
|
|
MFC0(a1, C0_TAGLO)
|
|
MFC0(a2, C0_TAGHI)
|
|
bne t1,a1,testScacheFailedTagWay0
|
|
nop
|
|
bne t2,a2,testScacheFailedTagWay0
|
|
nop
|
|
|
|
SCACHE(C_ILT, 1(v1)) /* WAY 1 */
|
|
MFC0(a1, C0_TAGLO)
|
|
MFC0(a2, C0_TAGHI)
|
|
bne t1,a1,testScacheFailedTagWay1
|
|
nop
|
|
bne t2,a2,testScacheFailedTagWay1
|
|
nop
|
|
|
|
subu a3, 1
|
|
daddiu v1,CACHE_SLINE_SIZE
|
|
bgtz a3,2b
|
|
nop
|
|
daddiu v0,CP_SIZE /* DELAY */
|
|
b 1b /* Back to top of loop */
|
|
nop
|
|
|
|
testScacheData:
|
|
/*
|
|
* The INDEX STORE_DATA for the secondary cache only stores
|
|
* 2 of the 4 words in each quad word. Thus, for each quad
|
|
* word, we must first test the first 2 words, then the second
|
|
* 2. We double check the ECC at both phases - just for fun.
|
|
* v1 is really a boolean value that indicates if we are on the
|
|
* upper 8 bytes or lower eight bytes.
|
|
*/
|
|
dla v0,scache_patternStart
|
|
1:
|
|
dla v1,scache_patternEnd
|
|
bge v0,v1,testScacheAddrs
|
|
nop
|
|
dli v1,8 /* # bytes left in quad */
|
|
2:
|
|
dli t3,K0_BASE
|
|
daddu t3,v1 /* Which quad word */
|
|
|
|
3:
|
|
lw a3,CP_ECC(v0) /* ECC bits */
|
|
DMTC0(a3, C0_ECC)
|
|
lw a1, CP_DATA_LO(v0)
|
|
lw a2, CP_DATA_HI(v0)
|
|
MTC0(a1,C0_TAGLO)
|
|
MTC0(a2,C0_TAGHI)
|
|
/*
|
|
* Compute # of stores to execute. Each secondary cache line
|
|
* is made up of some number of quadwords. For the first pass,
|
|
* write the first 8-bytes of the quadwords for the entire
|
|
* cache, and in the second pass write the last 8-bytes of
|
|
* each quadword. # Quadwords is (#lines x #quads per line)
|
|
*/
|
|
li a0,CACHE_SLINE_SIZE/CACHE_SLINE_SUBSIZE
|
|
multu a0,gp /* total sublines per way */
|
|
mflo a0
|
|
4:
|
|
SCACHE(C_ISD, 0(t3)) /* Way 0 */
|
|
SCACHE(C_ISD, 1(t3)) /* Way 1 */
|
|
subu a0, 1
|
|
daddiu t3,CACHE_SLINE_SUBSIZE /* Next subline */
|
|
bgtz a0,4b
|
|
nop
|
|
/*
|
|
* Now read back and verify the results with what we wrote. At
|
|
* this point the expected values are:
|
|
* ECC - a3, taghi - a2, taglo - a1
|
|
*/
|
|
dli t3,K0_BASE
|
|
daddu t3,v1
|
|
li a0,CACHE_SLINE_SIZE/CACHE_SLINE_SUBSIZE
|
|
multu a0,gp /* Total sublines */
|
|
mflo a0
|
|
4:
|
|
SCACHE(C_ILD, 0(t3)) /* Way 0 */
|
|
MFC0(t0, C0_ECC)
|
|
MFC0(t1, C0_TAGHI)
|
|
MFC0(t2, C0_TAGLO)
|
|
bne t0,a3,testScacheFailedWay0
|
|
nop
|
|
bne t1,a2,testScacheFailedWay0
|
|
nop
|
|
bne t2,a1,testScacheFailedWay0
|
|
nop
|
|
SCACHE(C_ILD, 1(t3)) /* Way 1 */
|
|
MFC0(t0, C0_ECC)
|
|
MFC0(t1, C0_TAGHI)
|
|
MFC0(t2, C0_TAGLO)
|
|
bne t0,a3,testScacheFailedWay1
|
|
nop
|
|
bne t1,a2,testScacheFailedWay1
|
|
nop
|
|
bne t2,a1,testScacheFailedWay1
|
|
nop
|
|
|
|
subu a0,1 /* Next offset into sublines*/
|
|
bgtz a0,4b
|
|
daddiu t3,CACHE_SLINE_SUBSIZE
|
|
|
|
bnez v1,2b
|
|
move v1,zero /* DELAY */
|
|
|
|
/*
|
|
* End of outer loop.
|
|
*/
|
|
b 1b
|
|
daddiu v0,CP_SIZE /* Next pattern */
|
|
|
|
/*
|
|
* Do address test, writing then reading back the address used to
|
|
* access the array. This should catch the wrong cache size being
|
|
* set.
|
|
*/
|
|
testScacheAddrs:
|
|
dli v1,8 /* # bytes left in quad */
|
|
2:
|
|
dli t3,K0_BASE
|
|
daddu t3,v1 /* Which quad word */
|
|
3:
|
|
DMTC0(zero, C0_ECC) /* Don't care about this guy*/
|
|
/*
|
|
* compute # of stores to execute.
|
|
*/
|
|
li a0,CACHE_SLINE_SIZE/CACHE_SLINE_SUBSIZE
|
|
multu a0,gp /* total sublines per way */
|
|
mflo a0
|
|
|
|
4:
|
|
move a1,t3
|
|
daddiu a2,t3,4
|
|
MTC0(a1,C0_TAGLO)
|
|
MTC0(a2,C0_TAGHI)
|
|
SCACHE(C_ISD, 0(t3)) /* Way 0 */
|
|
SCACHE(C_ISD, 1(t3)) /* Way 1 */
|
|
subu a0, 1
|
|
daddiu t3,CACHE_SLINE_SUBSIZE /* Next subline */
|
|
bgtz a0,4b
|
|
nop
|
|
|
|
/*
|
|
* Now read back and verify the results with what we wrote.
|
|
*/
|
|
dli t3,K0_BASE
|
|
daddu t3,v1
|
|
li a0,CACHE_SLINE_SIZE/CACHE_SLINE_SUBSIZE
|
|
multu a0,gp /* Total sublines */
|
|
mflo a0
|
|
move t0,zero
|
|
move a3,zero
|
|
4:
|
|
move a1,t3
|
|
daddiu a2,t3,4
|
|
dli v0,0xffffffff
|
|
and a1,v0
|
|
and a2,v0
|
|
|
|
SCACHE(C_ILD, 0(t3)) /* Way 0 */
|
|
MFC0(t1, C0_TAGHI)
|
|
MFC0(t2, C0_TAGLO)
|
|
bne t1,a2,testScacheFailedWay0
|
|
nop
|
|
bne t2,a1,testScacheFailedWay0
|
|
nop
|
|
SCACHE(C_ILD, 1(t3)) /* Way 1 */
|
|
MFC0(t1, C0_TAGHI)
|
|
MFC0(t2, C0_TAGLO)
|
|
bne t1,a2,testScacheFailedWay1
|
|
nop
|
|
bne t2,a1,testScacheFailedWay1
|
|
nop
|
|
|
|
subu a0,1 /* Next offset into sublines*/
|
|
bgtz a0,4b
|
|
daddiu t3,CACHE_SLINE_SUBSIZE
|
|
|
|
bnez v1,2b
|
|
move v1,zero /* DELAY */
|
|
|
|
testScacheSuccess:
|
|
j ra
|
|
move v0,zero
|
|
|
|
testScacheFailedWay0:
|
|
MESSAGE(a0, "\r\n 2ndry data compare error: Way 0:")
|
|
b testScacheFailed
|
|
nop
|
|
testScacheFailedWay1:
|
|
MESSAGE(a0, "\r\n 2ndry data compare error: Way 1:")
|
|
testScacheFailed:
|
|
/*
|
|
* For debug proms, attempt to dump information to
|
|
* CC serial port. At this point:
|
|
* t3 - address
|
|
* t0 - read ECC value
|
|
* t1/t2 - read taghi/taglo values (8 bytes)
|
|
* a3 - expected ECC value
|
|
* a1/a2 - expected taghi/taglo values (8 bytes)
|
|
*/
|
|
|
|
dsll t1,32
|
|
dsll t2,32
|
|
dsrl t2,32
|
|
or t1,t2
|
|
|
|
dsll a1,32
|
|
dsll a2,32
|
|
dsrl a2,32
|
|
or k1,a2,a1
|
|
move k0,a3
|
|
|
|
move t2,ra
|
|
|
|
PMESSAGE_PTR(a0); PMESSAGE(" address: "); PHEX(t3);
|
|
PMESSAGE("\n\r\twrote(data/ecc): 0x"); PHEX(k1);
|
|
PMESSAGE("/"); PHEX32(k0);
|
|
PMESSAGE("\n\r\tread (data/ecc): 0x"); PHEX(t1);
|
|
PMESSAGE("/"); PHEX32(t0);
|
|
|
|
PMESSAGE("\n\r")
|
|
|
|
j t2
|
|
ori v0,zero,EVDIAG_SCACHE_DATA /* DELAY */
|
|
|
|
testScacheFailedTagWay0:
|
|
MESSAGE(a0, "\r\n 2ndry Tag compare error: way 0:")
|
|
b testScacheFailedTag
|
|
nop
|
|
testScacheFailedTagWay1:
|
|
MESSAGE(a0, "\r\n 2ndry Tag compare error: way 1:")
|
|
testScacheFailedTag:
|
|
/*
|
|
* For debug proms, attempt to dump information to
|
|
* CC serial port. At this point,
|
|
* v1 - address
|
|
* a1/a2 - pattern read back
|
|
* t1/t2 - pattern written
|
|
*/
|
|
dsll a2,32 /* Top 32 bits */
|
|
dsll a1,32
|
|
dsrl a1,32 /* isolate lower 32 bits */
|
|
or k0,a2,a1 /* a2 - read 64-bit value */
|
|
|
|
dsll t2,32 /* Top 32 bits */
|
|
dsll t1,32
|
|
dsrl t1,32 /* isolate lower 32 bits */
|
|
or t1,t2 /* t1 - expected value */
|
|
|
|
move t2,ra /* Save way home */
|
|
move k1,v1
|
|
|
|
PMESSAGE_PTR(a0); PMESSAGE(" address: "); PHEX(k1);
|
|
PMESSAGE("\r\n\twrote: 0x"); PHEX(t1);
|
|
PMESSAGE("\r\n\tread: 0x"); PHEX(k0);
|
|
PMESSAGE("\n\r")
|
|
|
|
j t2
|
|
ori v0,zero,EVDIAG_SCACHE_TAG /* DELAY */
|
|
|
|
.set reorder
|
|
END(testScache)
|
|
|
|
/*
|
|
* Function: testCCtags
|
|
* Purpose: verify the duplicate cache tags in the SCC
|
|
* Parameters: none
|
|
* Returns: 0 - OK
|
|
* 1 - failed
|
|
* Notes: The SCC duplicate tages are addressed as follows:
|
|
* line way address (EV_BTRAM_BASE +)
|
|
* 0 0 0
|
|
* 0 1 8
|
|
* 1 0 16
|
|
* 1 1 24
|
|
* ...
|
|
* Thus, we look at the SCC tags as 1 way for this test, and having
|
|
* a size of 8 (CTD_SIZE).
|
|
*
|
|
*/
|
|
.align 7 /* Align on scache boundary */
|
|
LEAF(testCCtags)
|
|
.set noreorder
|
|
#if !defined(SABLE)
|
|
/*
|
|
* Compute SCC cache tag mask ---- use the SR because it has the
|
|
* log2 value as it stands.
|
|
*/
|
|
|
|
MFC0(v0,C0_CONFIG)
|
|
and v0,CONFIG_SS
|
|
srl v0,CONFIG_SS_SHFT
|
|
|
|
/*
|
|
* SCC needs to know the size of the secondary cache at
|
|
* this point to correctly mask bits and generate
|
|
* Parity.
|
|
*/
|
|
|
|
dli t2,0x00ffffff
|
|
srl t2,v0
|
|
sll t2,v0 /* Mask for tags */
|
|
|
|
li v1,5
|
|
sub v0,v1,v0 /* SCC value:CACHE_SZ */
|
|
EV_GET_SPNUM(k0,k1) /* our address */
|
|
EV_SET_PROCREG(k0, k1, EV_CFG_CACHE_SZ, v0)
|
|
|
|
/*
|
|
* We assume the maximum cache size for the purpose of
|
|
* the testing. The total number of lines is used.
|
|
*/
|
|
li v0,1024*1024*4/CACHE_SLINE_SIZE
|
|
|
|
dla t0,scctag_patternStart
|
|
1:
|
|
dla t1,scctag_patternEnd
|
|
bge t0,t1,testCCtagsSuccess /* Done */
|
|
nop
|
|
|
|
/*
|
|
* Fill tag rams with pattern.
|
|
*/
|
|
move a2,v0 /* # lines */
|
|
ld v1,0(t0) /* Current pattern */
|
|
and v1,t2
|
|
dli a0,EV_BTRAM_BASE
|
|
2:
|
|
sd v1,0(a0)
|
|
daddiu a0,CTD_SIZE
|
|
sub a2,1
|
|
bgtz a2,2b
|
|
nop
|
|
|
|
/*
|
|
* Due to an SCC problem, we can not read the CC tags to soon after
|
|
* a write from the CPU. For that reason, we serialize, and cause a
|
|
* stall - by loading the cache_size config register.
|
|
*/
|
|
EV_GET_SPNUM(k0,k1) /* Cause a stall */
|
|
EV_GET_PROCREG(k0, k1, EV_CFG_CACHE_SZ, zero)
|
|
MFC0(zero, C0_SR) /* serialize */
|
|
|
|
/*
|
|
* Check patterns in tag rams.
|
|
*/
|
|
dli a0,EV_BTRAM_BASE
|
|
move a2,v0 /* Count */
|
|
2:
|
|
ld t1,0(a0)
|
|
beq v1,t1,3f
|
|
DMFC0(zero, C0_SR) /* Serialize */
|
|
DMFC0(zero, C0_SR) /* Serialize */
|
|
dla t3,testCCtagsFail
|
|
jr t3
|
|
nop
|
|
3:
|
|
daddiu a0,CTD_SIZE /* DELAY: */
|
|
sub a2,1 /* DELAY: */
|
|
bgtz a2,2b
|
|
nop
|
|
b 1b /* Check for more */
|
|
daddiu t0,SCC_SIZE
|
|
|
|
#endif /* !defined(SABLE) */
|
|
|
|
testCCtagsSuccess:
|
|
/*
|
|
* Up to 4 instructions after the serialization instruction
|
|
* may be speculated since they are already decoded etc. Thus,
|
|
* we put nops is just ro be sure we know what is going on.
|
|
*/
|
|
DMFC0(zero, C0_SR) /* Serialize */
|
|
nop
|
|
nop
|
|
j ra
|
|
move v0,zero
|
|
|
|
.align 7 /* Pad out Align on scache boundary */
|
|
|
|
testCCtagsFail:
|
|
.set noreorder
|
|
/*
|
|
* Attempt to dump the address/wrote/read value to the CC uart.
|
|
* At this point, registers are as follows:
|
|
* a0 - address
|
|
* v1 - pattern written
|
|
* t1 - pattern read
|
|
*/
|
|
|
|
move t3, ra /* save way home */
|
|
move t2,a0 /* address */
|
|
|
|
move t0,v1 /* Pattern written */
|
|
PMESSAGE("\r\n CC Tag Compare Error: Address: ")
|
|
PHEX(t2)
|
|
PMESSAGE("\n\r\tWrote: ")
|
|
PHEX32(t0)
|
|
PMESSAGE( "\r\n\tRead: ")
|
|
PHEX32(t1)
|
|
PMESSAGE("\n\r")
|
|
move ra,t3 /* Restore way home */
|
|
|
|
j ra
|
|
ori v0,zero,EVDIAG_BUSTAG_DATA
|
|
.globl testCCtags_END
|
|
testCCtags_END:
|
|
.set reorder
|
|
END(testCCtags)
|
|
|
|
/*
|
|
* Function: parity
|
|
* Purpose: Compute parity of 64-bit value
|
|
* Parameters: a0 - 64-bit value to compute parity on
|
|
* a1 - 0 for EVEN parity, 1 for ODD parity
|
|
* Returns: v0 - parity bit in LSB
|
|
* Notes: uses a0,a1,v0
|
|
*/
|
|
LEAF(parity)
|
|
.set noreorder
|
|
dsrl v0, a0, 32
|
|
xor a0, v0
|
|
dsrl v0, a0, 16
|
|
xor a0, v0
|
|
dsrl v0, a0, 8
|
|
xor a0, v0
|
|
dsrl v0, a0, 4
|
|
xor a0, v0
|
|
dsrl v0, a0, 2
|
|
xor a0, v0
|
|
dsrl v0, a0, 1
|
|
xor a0, v0
|
|
xor v0, a0, a1
|
|
j ra
|
|
and v0, 1
|
|
.set reorder
|
|
END(parity)
|
|
|
|
/*
|
|
* Function: initDcacheStack
|
|
* Purpose: Set up the primary data cache to has valid (zero'd)
|
|
* exlusive dirty cache lines starting at
|
|
* POD_STACKADDR. Also set stack pointer.
|
|
* Parameters: none
|
|
* Returns: sp updated.
|
|
* Notes: The size of the stack is sizeof(dcache) / 2, ie, we don't
|
|
* bother to initialize both ways.
|
|
*
|
|
* Virtual address of stack = POD_STACKADDR
|
|
* Physical address of stack = POD_STACKPADDR
|
|
*/
|
|
LEAF(initDcacheStack)
|
|
.set noreorder
|
|
move a3,ra /* Save RA */
|
|
LEDS(PLED_MAKESTACK)
|
|
dli t2,POD_STACKSIZE/CACHE_DLINE_SIZE /* #lines */
|
|
dli sp,POD_STACKVADDR /* Start of stack */
|
|
dli a2,POD_STACKPADDR /* Stack physical address */
|
|
/*
|
|
* Build tag for virtual address in sp, physical address in
|
|
* a2. State, SC way, State Parity, LRU are constant. We use:
|
|
*
|
|
* State Mod = 1 <normal>
|
|
* State = dirty, exclusive, inconsistent <CTP_STATE_DEI>
|
|
* State Parity = EVEN_PARITY(state) = <constant>
|
|
* LRU = 0
|
|
* SC way = 0
|
|
*
|
|
* TAG[39:36] = <variable>
|
|
* TAG[35: 12] = <variable>
|
|
* Tag Parity = <variable>
|
|
*/
|
|
dli a0,CTP_STATE_DE
|
|
jal parity /* Compute state parity */
|
|
move a1,zero /* DELAY: Even please */
|
|
|
|
dsll v0,CTP_STATEPARITY_SHFT
|
|
dli t1,(CTP_STATE_DE<<CTP_STATE_SHFT) + \
|
|
(CTP_STATEMOD_N<<CTP_STATEMOD_SHFT)
|
|
or t1,v0 /* State with parity */
|
|
/*
|
|
* t1 holds the constant parts of the tag, with parity. The actual
|
|
* TAG address must now be computed and loaded.
|
|
*/
|
|
1:
|
|
dsrl t0,a2,4 /* NOTYET */
|
|
and t0,CTP_TAG_MASK /* Physical address */
|
|
/* in correct place */
|
|
move a0,t0
|
|
jal parity
|
|
move a1,zero /* DELAY: even parity */
|
|
dsll v0,CTP_TAGPARITY_SHFT
|
|
or t0,v0 /* Tag with tag parity */
|
|
or t0,t1 /* Tag complete with parity */
|
|
|
|
/* Now set the dcache entry for the specified line */
|
|
|
|
MTC0(t0,C0_TAGLO) /* Low order 32 bits */
|
|
dsrl t0,32
|
|
MTC0(t0,C0_TAGHI) /* High orger 32 bits */
|
|
DCACHE(C_IST, 0(sp)) /* Set tag! */
|
|
|
|
/*
|
|
* Must be sure data in cache line does not have a parity
|
|
* error.
|
|
*/
|
|
|
|
DMTC0(zero, C0_ECC) /* Even parity, ECC=0 */
|
|
MTC0(zero, C0_TAGLO) /* 0 data */
|
|
|
|
li a1,CACHE_DLINE_SIZE-4 /* # of stores */
|
|
2:
|
|
daddu a0,a1,sp /* Virtual address of word */
|
|
DCACHE(C_ISD, 0(a0)) /* Store 0 */
|
|
daddi a1,-4 /* DELAY: next word */
|
|
bgez a1,2b
|
|
nop
|
|
|
|
daddiu sp,CACHE_DLINE_SIZE /* Bump virtual address */
|
|
daddiu a2,CACHE_DLINE_SIZE /* Bump physical address */
|
|
sub t2,1
|
|
bgtz t2,1b /* next or are we done ? */
|
|
nop
|
|
|
|
dli sp,POD_STACKVADDR+POD_STACKSIZE-8
|
|
j a3 /* Home James */
|
|
nop
|
|
.set reorder
|
|
END(initDcacheStack)
|
|
/*
|
|
* Function: iLine
|
|
* Purpose: Fetch an instruction line from the icache.
|
|
* Parameters: a0 - vaddr (low order bit signals way)
|
|
* a1 - ptr to il_t buffer
|
|
* Returns: a1-> filled in.
|
|
*/
|
|
LEAF(iLine)
|
|
.set noreorder
|
|
|
|
ICACHE(C_ILT, 0(a0)) /* Store Tag */
|
|
MFC0(v0, C0_TAGLO)
|
|
MFC0(v1, C0_TAGHI)
|
|
dsll v1,32
|
|
or v0,v1
|
|
sd v0,IL_TAG(a1)
|
|
|
|
daddiu t0,a1,IL_DATA /* Data pointer */
|
|
daddiu t1,a1,IL_PARITY /* Parity pointer */
|
|
|
|
daddiu a2,a0,CACHE_ILINE_SIZE
|
|
1:
|
|
ICACHE(C_ILD, 0(a0))
|
|
MFC0(v0, C0_TAGLO)
|
|
MFC0(v1, C0_TAGHI)
|
|
dsll v1,32
|
|
or v0,v1
|
|
sd v0,0(t0)
|
|
|
|
MFC0(v0, C0_ECC)
|
|
sb v0,0(t1)
|
|
daddiu t0,8 /* 8-bytes stored */
|
|
daddiu a0,4
|
|
blt a0, a2, 1b
|
|
daddiu t1,1 /* 1-bit of parity */
|
|
|
|
j ra
|
|
nop
|
|
.set reorder
|
|
END(iLine)
|
|
|
|
/*
|
|
* Function: dLine
|
|
* Purpose: Fetch primary data cache line.
|
|
* Parameters: a0 - vaddr (low order bit signals way)
|
|
* a1 - ptr to dl_t
|
|
* Returns: a1--> filled in.
|
|
*/
|
|
LEAF(dLine)
|
|
.set noreorder
|
|
|
|
DCACHE(C_ILT, 0(a0)) /* Read and store tag */
|
|
MFC0(v0, C0_TAGHI)
|
|
MFC0(v1, C0_TAGLO)
|
|
dsll v0,32
|
|
or v0,v1
|
|
sd v0,DL_TAG(a1)
|
|
|
|
daddiu a2,a0,CACHE_DLINE_SIZE
|
|
daddiu t0,a1,DL_DATA /* Data pointer */
|
|
daddiu t1,a1,DL_ECC /* ECC pointer */
|
|
|
|
1:
|
|
DCACHE(C_ILD, 0(a0))
|
|
MFC0(v0, C0_TAGLO)
|
|
sw v0,0(t0)
|
|
MFC0(v0, C0_ECC)
|
|
sb v0,0(t1)
|
|
daddiu a0,4 /* Next word - vaddr */
|
|
daddiu t0,4 /* Next word - buffer */
|
|
blt a0,a2,1b
|
|
daddiu t1,1 /* DELAY: Next ECC field */
|
|
|
|
j ra
|
|
nop
|
|
|
|
.set reorder
|
|
END(dLine)
|
|
|
|
/*
|
|
* Function: sLine
|
|
* Purpose: Fetch a cache line from the secondary cache.
|
|
* Parameters: a0 - vaddr (low order bit signals way)
|
|
* a1 - pointer to sl_t area.
|
|
* Returns: nothing
|
|
*/
|
|
LEAF(sLine)
|
|
|
|
.set noreorder
|
|
|
|
SCACHE(C_ILT, 0(a0)) /* Pick up T5 TAG */
|
|
MFC0(v0, C0_TAGHI)
|
|
MFC0(v1, C0_TAGLO)
|
|
dsll v0,32
|
|
dsll v1,32 /* Clear high order 32 bits */
|
|
dsrl v1,32
|
|
or v0,v1
|
|
sd v0, SL_TAG(a1)
|
|
|
|
move t0,ra /* Pick up CC tag */
|
|
jal sCacheSize
|
|
nop
|
|
move ra,t0
|
|
|
|
srl v0,1 /* div by 2 for # ways */
|
|
sub v0,1 /* scachesize/2 - 1 */
|
|
and v0,a0,v0 /* V0 - normalizes virtual address */
|
|
|
|
divu v0,CACHE_SLINE_SIZE /* Compute index */
|
|
sll v0,4 /* Index into duplicate tags */
|
|
and v1,a0,1 /* Look at way */
|
|
sll v1,3 /* add 8-bytes for way 1 */
|
|
daddu v1,v0 /* Offset into TAGS */
|
|
daddu v1,EV_BTRAM_BASE /* address of TAG */
|
|
#if SABLE
|
|
move v0,zero
|
|
#else
|
|
ld v0,0(v1) /* duplicate tag */
|
|
#endif
|
|
sd v0,SL_CCTAG(a1) /* and store for the caller */
|
|
|
|
/* OK - lets get the data */
|
|
|
|
li v0,CACHE_SLINE_SIZE/16 /* # fetches */
|
|
daddiu t0,a1,SL_DATA
|
|
daddiu t1,a1,SL_ECC
|
|
2:
|
|
SCACHE(C_ILD, 0(a0))
|
|
MFC0(v1, C0_TAGLO) /* Store 8-bytes of data */
|
|
sw v1,0(t0)
|
|
MFC0(v1, C0_TAGHI)
|
|
sw v1,4(t0)
|
|
MFC0(v1, C0_ECC)
|
|
sh v1,0(t1) /* Store ECC for this 8 bytes */
|
|
|
|
SCACHE(C_ILD, 8(a0))
|
|
MFC0(v1, C0_TAGLO) /* Store 8-bytes of data */
|
|
sw v1,8(t0)
|
|
MFC0(v1, C0_TAGHI)
|
|
sw v1,12(t0)
|
|
|
|
sub v0,1
|
|
daddu a0,16 /* Increment address */
|
|
daddu t0,16 /* Increment data array. */
|
|
bgt v0,zero,2b
|
|
daddiu t1,2 /* DELAY: Increment ECC array */
|
|
1:
|
|
/* All done ... */
|
|
j ra
|
|
nop
|
|
.set reorder
|
|
END(sLine)
|
|
|
|
LEAF(stagECC)
|
|
/*
|
|
* Function: stagECC
|
|
* Purpose: Compute the secondary cache tag ECC value given
|
|
* the tag (without the ECC).
|
|
* Parameters: a0 - The 26-bit cache tag value.
|
|
* Retruns: v0 - ECC value.
|
|
*
|
|
* Notes: The following table is from the "R10000 User's Manual", in the
|
|
* section on secondary cache error protection handling. It indicates
|
|
* the bits selected to look at for each of the check bits.
|
|
*/
|
|
.data
|
|
tagECC:
|
|
.dword 0x00a8f888
|
|
.dword 0x0114ff04
|
|
.dword 0x02620f42
|
|
.dword 0x029184f0
|
|
.dword 0x010a40ff
|
|
.dword 0x0245222f
|
|
.dword 0x01ff1111
|
|
tagECC_end:
|
|
|
|
.text
|
|
.set noreorder
|
|
|
|
move v0,zero /* Start out with 0 result */
|
|
dla a1,tagECC /* Current bit selector pointer */
|
|
|
|
stagECC_loop: /* Loop for all bits set */
|
|
|
|
dla a2, tagECC_end
|
|
beq a1,a2,stagECC_loopDone
|
|
nop
|
|
move v1,zero /* Result is always 0 to start */
|
|
lwu a2, 0(a1)
|
|
and a2,a0 /* Select the bits we want */
|
|
1:
|
|
beqz a2,2f /* Done with this one */
|
|
nop
|
|
xor v1,a2
|
|
srl a2,1
|
|
b 1b
|
|
nop
|
|
2:
|
|
/*
|
|
* Shift the running result, and or the new bit into the bottom
|
|
* position. This means we actually do bit 6 first, and bit 0 last.
|
|
*/
|
|
and v1, 0x1 /* Pick up bit */
|
|
sll v0,1 /* Shift into position */
|
|
or v0,v1 /* And put into result */
|
|
daddiu a1, 4 /* Next check bit please ... */
|
|
b stagECC_loop /* Next one */
|
|
nop
|
|
|
|
stagECC_loopDone: /* All done ... */
|
|
j ra
|
|
nop
|
|
|
|
END(stagECC)
|
|
|
|
LEAF(copyToICache)
|
|
/*
|
|
* Function: copyToIcache
|
|
* Purpose: To copy PIC code to the icache, execute it, and return.
|
|
* Parameters: a0 - pointer to address to copy
|
|
* a1 - length (# of bytes to copy - must be multiple of
|
|
* 4.
|
|
* Returns: v0 - virtual address corresponding to first instruction
|
|
* as pointed to by a0.
|
|
* Notes: Build texts in primary dcache, then flushes to secondary
|
|
* cache.
|
|
*/
|
|
.set noreorder
|
|
move a3,ra /* save RA */
|
|
move t0,a0
|
|
|
|
/*
|
|
* Be sure to fill an entire s-line, otherwise, we could get
|
|
* errors on non-initialized parts of the sline since the T5
|
|
* likes to prefetch stuff.
|
|
*/
|
|
|
|
daddiu t1, a1, CACHE_SLINE_SIZE-1
|
|
and t1, ~(CACHE_SLINE_SIZE - 1) /* Mutiple of s-lines */
|
|
divu t3, t1, CACHE_DLINE_SIZE /* # primary d-lines. */
|
|
|
|
LEDS(PLED_INITICACHE) /* Do after a0/a1 saved */
|
|
|
|
dli a0, CTP_STATE_DE
|
|
jal parity
|
|
move a1,zero
|
|
|
|
/* Build constant part of dtag into t2 */
|
|
|
|
dsll v0,CTP_STATEPARITY_SHFT
|
|
dli t2,(CTP_STATE_DE<<CTP_STATE_SHFT) + \
|
|
(CTP_STATEMOD_N<<CTP_STATEMOD_SHFT)
|
|
or t2,v0 /* State with parity */
|
|
|
|
/*
|
|
* Loop through the primary d-cache lines marking the tags.
|
|
*/
|
|
move ta2,t3
|
|
dli t8, POD_CODEVADDR /* Start of virt address */
|
|
dli t9, POD_CODEPADDR /* Start of phys address */
|
|
1:
|
|
dsrl ta3, t9, 4
|
|
and ta3, CTP_TAG_MASK /* Physical address portion */
|
|
move a0, ta3
|
|
jal parity
|
|
move a1,zero
|
|
dsll v0,CTP_TAGPARITY_SHFT
|
|
or ta3,v0
|
|
or ta3,t2 /* Tag - with parity */
|
|
|
|
MTC0(ta3, C0_TAGLO)
|
|
dsrl ta3,32
|
|
MTC0(ta3, C0_TAGHI)
|
|
DCACHE(C_IST, 0(t8))
|
|
|
|
daddiu t8, CACHE_DLINE_SIZE
|
|
daddiu t9, CACHE_DLINE_SIZE
|
|
sub ta2, 1
|
|
bgtz ta2, 1b
|
|
nop
|
|
|
|
/*
|
|
* Now compute and store the secondary cache tags - first round
|
|
* up # bytes to mutiple of secondary cache lines.
|
|
*/
|
|
|
|
daddiu ta2, t1, CACHE_SLINE_SIZE - 1
|
|
and ta2, ~(CACHE_SLINE_SIZE - 1) /* # secondary bytes */
|
|
dli t9, POD_CODEPADDR
|
|
dli t8, POD_CODEVADDR
|
|
|
|
/*
|
|
* Set the phsyical address bits - the secondary cache state
|
|
* is marked XXX to allow a cache HIT in the secondary cache when
|
|
* we flush the primary cache.
|
|
*/
|
|
1:
|
|
dsrl ta3, t9, 4
|
|
and ta3, CTS_TAG_MASK /* Physical address bits */
|
|
|
|
or ta3, 3 << CTS_STATE_SHFT
|
|
or ta3, /* VIDX %%% */ 0
|
|
|
|
jal stagECC
|
|
move a0, ta3
|
|
or ta3,v0 /* Or in ECC */
|
|
|
|
/* TAG is now in ta3 with ECC set - write it and continue. */
|
|
|
|
MTC0(ta3, C0_TAGLO)
|
|
dsrl ta3, 32
|
|
MTC0(ta3, C0_TAGHI)
|
|
SCACHE(C_IST, 0(t8))
|
|
|
|
MTC0(zero, C0_TAGLO) /* Clear other way */
|
|
MTC0(zero, C0_TAGHI)
|
|
MTC0(zero, C0_ECC)
|
|
SCACHE(C_IST, 1(t8))
|
|
|
|
daddiu t9, CACHE_SLINE_SIZE /* Increment physical addr */
|
|
daddiu t8, CACHE_SLINE_SIZE /* Increment virtual addr */
|
|
sub ta2, CACHE_SLINE_SIZE
|
|
bgtz ta2, 1b
|
|
nop
|
|
|
|
/*
|
|
* At this point, the primary D-cache tags are marked dirty
|
|
* exclusive, and the secondary cache tags are marked the same.
|
|
* We now copy the data into the primary data cache. Since parity
|
|
* is on a byte basis, we store words - no read/modify/write
|
|
* is required by the R10K. Here we assume the length is a
|
|
* MULTIPLE NUMBER OF d-cache lines.
|
|
*/
|
|
dli t8, POD_CODEVADDR /* Destination */
|
|
move ta3, t0 /* Source */
|
|
move ta1, t1 /* Length */
|
|
1:
|
|
lw v0,0(ta3)
|
|
sw v0,0(t8)
|
|
daddiu ta3, 4
|
|
daddiu t8, 4
|
|
sub ta1,4
|
|
bgtz ta1,1b
|
|
nop
|
|
|
|
/*
|
|
* Now flush the newly copied data out of the data cache,
|
|
* and into the secondary cache.
|
|
*/
|
|
|
|
dli t8, POD_CODEVADDR
|
|
move ta1,t1 /* Length */
|
|
1:
|
|
DCACHE(C_HWBINV, 0(t8)) /* Flush from d-cache */
|
|
ICACHE(C_HINV, 0(t8)) /* Be sure out of i-cache */
|
|
daddiu t8, CACHE_DLINE_SIZE
|
|
sub ta1, CACHE_DLINE_SIZE
|
|
bgtz ta1, 1b
|
|
nop
|
|
|
|
/*
|
|
* Everything is now flushed to secondary cache - we can return
|
|
* to the caller and let them know all is OK.
|
|
*/
|
|
|
|
dli v0,POD_CODEVADDR
|
|
j a3
|
|
nop
|
|
END(copyToICache)
|
|
|
|
LEAF(cacheFlush)
|
|
/*
|
|
* Routine: cacheFlush
|
|
* Purpose: To flush the current contents of the entire cache.
|
|
* Parameters: none
|
|
* Returns: Nothing
|
|
* Notes: Uses v0, v1, a0, a1
|
|
*/
|
|
.set reorder
|
|
move a0,ra /* Save way back */
|
|
jal sCacheSize
|
|
dsrl v0,1 /* divide by 2 - 2-way */
|
|
dli v1,K0BASE /* Use unmapped space */
|
|
daddu v0,v1 /* Ending address */
|
|
|
|
.set noreorder
|
|
1:
|
|
SCACHE(C_HWBINV, 0(v1)) /* Way 0 */
|
|
SCACHE(C_HWBINV, 1(v1)) /* Way 1 */
|
|
daddu v1,CACHE_SLINE_SIZE
|
|
bltu v1,v0,1b
|
|
nop
|
|
.set reorder
|
|
|
|
j a0
|
|
END(cacheFlush)
|
|
|
|
LEAF(cacheError)
|
|
/*
|
|
* Routine: cacheError
|
|
* Purpose: Process a cache error exception.
|
|
* Parameters: None
|
|
* Returns: Does not return
|
|
* Notes: Since we do not return, no registers need be saved.
|
|
*/
|
|
.set reorder
|
|
#if 0
|
|
MFC0(s0, C0_CACHERR)
|
|
|
|
/* Check for I-cache/D-cache/S-cache, and do the "right" thing. */
|
|
|
|
srl s1,s0,CE_TYPE_SHFT
|
|
andi s1,(CE_TYPE_MASK>>CE_TYPE_SHFT)
|
|
be s1,CE_TYPE_I>>CE_TYPE_SHFT,cacheError_I
|
|
nop
|
|
be s1,CE_TYPE_D>>CE_TYPE_SHFT,cacheError_D
|
|
nop
|
|
be s1,CE_TYPE_S>>CE_TYPE_SHFT,cacheError_S
|
|
nop
|
|
#endif
|
|
/* Must be SIE */
|
|
END(cacheError)
|
|
|
|
LEAF(cacheOP)
|
|
/*
|
|
* Routine: cacheOP
|
|
* Purpose: Perform a cache operation
|
|
* Parameters: a0 - cacheop_t * - pointer to cache op structure.
|
|
* Returns: v0 - undefined, for Load data, taghi, taglo, and ECC
|
|
* values filled in.
|
|
*/
|
|
.set noreorder
|
|
lw v0,COP_TAGLO(a0) /* First setup CP0 */
|
|
MTC0(v0, C0_TAGLO)
|
|
lw v0,COP_TAGHI(a0)
|
|
MTC0(v0, C0_TAGHI)
|
|
lw v0,COP_ECC(a0)
|
|
MTC0(v0, C0_ECC)
|
|
|
|
ld a1,COP_ADDRESS(a0) /* Address to use */
|
|
lw v1,COP_OP(a0) /* Operation */
|
|
dla v0,cacheOP_table
|
|
sll v1,3 /* Index into table. */
|
|
daddu v0,v1
|
|
jalr a2,v0
|
|
nop
|
|
MFC0(v0, C0_TAGLO)
|
|
sw v0,COP_TAGLO(a0)
|
|
MFC0(v0, C0_TAGHI)
|
|
sw v0,COP_TAGHI(a0)
|
|
MFC0(v0, C0_ECC)
|
|
j ra
|
|
sw v0,COP_ECC(a0)
|
|
.set reorder
|
|
|
|
/*
|
|
* There are 32 possible operations to perform, each is
|
|
* defined in the table below, and uses 2 instructions (8 bytes).
|
|
*/
|
|
|
|
cacheOP_table:
|
|
.set noreorder
|
|
jr a2
|
|
cache 0, 0(a1)
|
|
jr a2
|
|
cache 1, 0(a1)
|
|
jr a2
|
|
cache 2, 0(a1)
|
|
jr a2
|
|
cache 3, 0(a1)
|
|
jr a2
|
|
cache 4, 0(a1)
|
|
jr a2
|
|
cache 5, 0(a1)
|
|
jr a2
|
|
cache 6, 0(a1)
|
|
jr a2
|
|
cache 7, 0(a1)
|
|
jr a2
|
|
cache 8, 0(a1)
|
|
jr a2
|
|
cache 9, 0(a1)
|
|
jr a2
|
|
cache 10, 0(a1)
|
|
jr a2
|
|
cache 11, 0(a1)
|
|
jr a2
|
|
cache 12, 0(a1)
|
|
jr a2
|
|
cache 13, 0(a1)
|
|
jr a2
|
|
cache 14, 0(a1)
|
|
jr a2
|
|
cache 15, 0(a1)
|
|
jr a2
|
|
cache 16, 0(a1)
|
|
jr a2
|
|
cache 17, 0(a1)
|
|
jr a2
|
|
cache 18, 0(a1)
|
|
jr a2
|
|
cache 19, 0(a1)
|
|
jr a2
|
|
cache 20, 0(a1)
|
|
jr a2
|
|
cache 21, 0(a1)
|
|
jr a2
|
|
cache 22, 0(a1)
|
|
jr a2
|
|
cache 23, 0(a1)
|
|
jr a2
|
|
cache 24, 0(a1)
|
|
jr a2
|
|
cache 25, 0(a1)
|
|
jr a2
|
|
cache 26, 0(a1)
|
|
jr a2
|
|
cache 27, 0(a1)
|
|
jr a2
|
|
cache 28, 0(a1)
|
|
jr a2
|
|
cache 29, 0(a1)
|
|
jr a2
|
|
cache 30, 0(a1)
|
|
jr a2
|
|
cache 31, 0(a1)
|
|
.set reorder
|
|
END(cacheOP)
|
|
#if 0
|
|
LEAF(setupScache)
|
|
/*
|
|
* Routine: fillScache
|
|
* Purpose: Set up a specific region of the SCACHE with dirty
|
|
* exlusive tags.
|
|
* Parameters: a0 - physical address
|
|
* a1 - length (in bytes)
|
|
* Returns: nothing
|
|
*/
|
|
/*
|
|
* Be sure to fill an entire s-line, otherwise, we could get
|
|
* errors on non-initialized parts of the sline since the T5
|
|
* likes to prefetch stuff.
|
|
*/
|
|
|
|
daddiu t1, a1, CACHE_SLINE_SIZE-1
|
|
and t1, ~(CACHE_SLINE_SIZE - 1) /* Mutiple of s-lines */
|
|
divu t3, t1, CACHE_SLINE_SIZE /* # primary d-lines. */
|
|
dand a0,~(CACHE_SLINE_SIZE-1)+1 /* Align please - save way */
|
|
|
|
1:
|
|
/* Set physical address bits */
|
|
|
|
dsrl a2, t0, 4
|
|
and a2, CTS_TAG_MASK /* Physical address bits */
|
|
|
|
or a2, 3 << CTS_STATE_SHFT
|
|
|
|
jal stagECC
|
|
move a0, a2 /* Compute ECC */
|
|
or a2,v0 /* Or in ECC */
|
|
|
|
/* TAG is now in a2 with ECC set - write it and continue. */
|
|
|
|
.set noreorder
|
|
MTC0(ta3, C0_TAGLO)
|
|
dsrl ta3, 32
|
|
MTC0(ta3, C0_TAGHI)
|
|
SCACHE(C_IST, 0(t8)) %%%
|
|
.set reorder
|
|
|
|
sub L,CACHE_SLINE_SIZE
|
|
daddiu A,CACHE_SLINE_SIZE
|
|
bgt L,zero,1b
|
|
|
|
j ra
|
|
END(setupScache)
|
|
|
|
|
|
#endif
|