/* Cache test */
|
/* Cache test */
|
#include "support.h"
|
#include "support.h"
|
#include "spr_defs.h"
|
#include "spr_defs.h"
|
|
|
#define MEM_RAM 0x40100000
|
#define MEM_RAM 0x40100000
|
|
|
/* Number of IC sets (power of 2) */
|
/* Number of IC sets (power of 2) */
|
#define IC_SETS 512
|
#define IC_SETS 512
|
#define DC_SETS 512
|
#define DC_SETS 512
|
|
|
/* Block size in bytes (1, 2, 4, 8, 16, 32 etc.) */
|
/* Block size in bytes (1, 2, 4, 8, 16, 32 etc.) */
|
#define IC_BLOCK_SIZE 16
|
#define IC_BLOCK_SIZE 16
|
#define DC_BLOCK_SIZE 16
|
#define DC_BLOCK_SIZE 16
|
|
|
/* Number of IC ways (1, 2, 3 etc.). */
|
/* Number of IC ways (1, 2, 3 etc.). */
|
#define IC_WAYS 1
|
#define IC_WAYS 1
|
#define DC_WAYS 1
|
#define DC_WAYS 1
|
|
|
/* Cache size */
|
/* Cache size */
|
#define IC_SIZE (IC_WAYS*IC_SETS*IC_BLOCK_SIZE)
|
#define IC_SIZE (IC_WAYS*IC_SETS*IC_BLOCK_SIZE)
|
#define DC_SIZE (DC_WAYS*DC_SETS*DC_BLOCK_SIZE)
|
#define DC_SIZE (DC_WAYS*DC_SETS*DC_BLOCK_SIZE)
|
|
|
/* Memory access macros */
|
/* Memory access macros */
|
#define REG8(add) *((volatile unsigned char *)(add))
|
#define REG8(add) *((volatile unsigned char *)(add))
|
#define REG16(add) *((volatile unsigned short *)(add))
|
#define REG16(add) *((volatile unsigned short *)(add))
|
#define REG32(add) *((volatile unsigned long *)(add))
|
#define REG32(add) *((volatile unsigned long *)(add))
|
|
|
extern void (*jalr)(void);
|
extern void (*jalr)(void);
|
extern void (*jr)(void);
|
extern void (*jr)(void);
|
|
|
/* Index on jump table */
|
/* Index on jump table */
|
unsigned long jump_indx;
|
unsigned long jump_indx;
|
|
|
/* Jump address table */
|
/* Jump address table */
|
unsigned long jump_add[15*IC_WAYS];
|
unsigned long jump_add[15*IC_WAYS];
|
|
|
void dummy();
|
void dummy();
|
|
|
void jump_and_link(void)
|
void jump_and_link(void)
|
{
|
{
|
asm("_jalr:");
|
asm("_jalr:");
|
}
|
}
|
|
|
void jump(void)
|
void jump(void)
|
{
|
{
|
asm("_jr:");
|
asm("_jr:");
|
/* Read and increment index */
|
/* Read and increment index */
|
asm("l.lwz\t\tr3,0(r11)");
|
asm("l.lwz\t\tr3,0(r11)");
|
asm("l.addi\t\tr3,r3,4");
|
asm("l.addi\t\tr3,r3,4");
|
asm("l.sw\t\t0(r11),r3");
|
asm("l.sw\t\t0(r11),r3");
|
/* Load next executin address from table */
|
/* Load next executin address from table */
|
asm("l.lwz\t\tr3,0(r3)");
|
asm("l.lwz\t\tr3,0(r3)");
|
/* Jump to that address */
|
/* Jump to that address */
|
asm("l.jr\t\tr3") ;
|
asm("l.jr\t\tr3") ;
|
/* Report that we succeeded */
|
/* Report that we succeeded */
|
asm("l.nop\t1");
|
asm("l.nop\t1");
|
}
|
}
|
|
|
void copy_jr(unsigned long add)
|
void copy_jr(unsigned long add)
|
{
|
{
|
memcpy((void *)add, (void *)&jr, 24);
|
memcpy((void *)add, (void *)&jr, 24);
|
}
|
}
|
|
|
void call(unsigned long add)
|
void call(unsigned long add)
|
{
|
{
|
asm("l.movhi\tr11,hi(_jump_indx)" : :);
|
asm("l.movhi\tr11,hi(_jump_indx)" : :);
|
asm("l.ori\tr11,r11,lo(_jump_indx)" : :);
|
asm("l.ori\tr11,r11,lo(_jump_indx)" : :);
|
asm("l.jr\t\t%0" : : "r" (add) : "r11");
|
asm("l.jr\t\t%0" : : "r" (add) : "r11");
|
asm("l.nop" : :);
|
asm("l.nop" : :);
|
}
|
}
|
|
|
void icache_enable(void)
|
void icache_enable(void)
|
{
|
{
|
unsigned long add;
|
unsigned long add;
|
|
|
/* First invalidate the cache. As at this point cache is disabled,
|
/* First invalidate the cache. As at this point cache is disabled,
|
the cache acts as it contains image of lowest memory block */
|
the cache acts as it contains image of lowest memory block */
|
for(add = 1; add <= IC_SIZE; add += IC_BLOCK_SIZE)
|
for(add = 1; add <= IC_SIZE; add += IC_BLOCK_SIZE)
|
mtspr(SPR_ICBIR, add);
|
mtspr(SPR_ICBIR, add);
|
|
|
mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_ICE);
|
mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_ICE);
|
}
|
}
|
|
|
void dcache_enable(void)
|
void dcache_enable(void)
|
{
|
{
|
unsigned long add;
|
unsigned long add;
|
|
|
/* First invalidate the cache. As at this point cache is disabled,
|
/* First invalidate the cache. As at this point cache is disabled,
|
the cache acts as it contains image of lowest memory block */
|
the cache acts as it contains image of lowest memory block */
|
for(add = 1; add <= DC_SIZE; add += DC_BLOCK_SIZE)
|
for(add = 1; add <= DC_SIZE; add += DC_BLOCK_SIZE)
|
mtspr(SPR_DCBIR, add);
|
mtspr(SPR_DCBIR, add);
|
|
|
mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_DCE);
|
mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_DCE);
|
}
|
}
|
|
|
void icache_disable(void)
|
void icache_disable(void)
|
{
|
{
|
|
|
/* This is write trough cache so we dont have to flush it */
|
/* This is write trough cache so we dont have to flush it */
|
mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_ICE);
|
mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_ICE);
|
}
|
}
|
|
|
void dcache_disable(void)
|
void dcache_disable(void)
|
{
|
{
|
|
|
/* This is write trough cache so we dont have to flush it */
|
/* This is write trough cache so we dont have to flush it */
|
mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_DCE);
|
mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_DCE);
|
}
|
}
|
|
|
int dc_test(void)
|
int dc_test(void)
|
{
|
{
|
int i;
|
int i;
|
unsigned long base, add, ul;
|
unsigned long base, add, ul;
|
|
|
base = (((unsigned long)MEM_RAM / (IC_SETS*IC_BLOCK_SIZE)) * IC_SETS*IC_BLOCK_SIZE) + IC_SETS*IC_BLOCK_SIZE;
|
base = (((unsigned long)MEM_RAM / (IC_SETS*IC_BLOCK_SIZE)) * IC_SETS*IC_BLOCK_SIZE) + IC_SETS*IC_BLOCK_SIZE;
|
|
|
dcache_enable();
|
dcache_enable();
|
|
|
/* Cache miss r */
|
/* Cache miss r */
|
add = base;
|
add = base;
|
for(i = 0; i < DC_WAYS; i++) {
|
for(i = 0; i < DC_WAYS; i++) {
|
ul = REG32(add);
|
ul = REG32(add);
|
ul = REG32(add + DC_BLOCK_SIZE);
|
ul = REG32(add + DC_BLOCK_SIZE);
|
ul = REG32(add + 2*DC_BLOCK_SIZE);
|
ul = REG32(add + 2*DC_BLOCK_SIZE);
|
ul = REG32(add + 3*DC_BLOCK_SIZE);
|
ul = REG32(add + 3*DC_BLOCK_SIZE);
|
add += DC_SETS*DC_BLOCK_SIZE;
|
add += DC_SETS*DC_BLOCK_SIZE;
|
}
|
}
|
|
|
/* Cache hit w */
|
/* Cache hit w */
|
add = base;
|
add = base;
|
for(i = 0; i < DC_WAYS; i++) {
|
for(i = 0; i < DC_WAYS; i++) {
|
REG32(add + 0) = 0x00000001;
|
REG32(add + 0) = 0x00000001;
|
REG32(add + DC_BLOCK_SIZE + 4) = 0x00000002;
|
REG32(add + DC_BLOCK_SIZE + 4) = 0x00000002;
|
REG32(add + 2*DC_BLOCK_SIZE + 8) = 0x00000003;
|
REG32(add + 2*DC_BLOCK_SIZE + 8) = 0x00000003;
|
REG32(add + 3*DC_BLOCK_SIZE + 12) = 0x00000004;
|
REG32(add + 3*DC_BLOCK_SIZE + 12) = 0x00000004;
|
add += DC_SETS*DC_BLOCK_SIZE;
|
add += DC_SETS*DC_BLOCK_SIZE;
|
}
|
}
|
|
|
/* Cache hit r/w */
|
/* Cache hit r/w */
|
add = base;
|
add = base;
|
for(i = 0; i < DC_WAYS; i++) {
|
for(i = 0; i < DC_WAYS; i++) {
|
REG8(add + DC_BLOCK_SIZE - 4) = REG8(add + 3);
|
REG8(add + DC_BLOCK_SIZE - 4) = REG8(add + 3);
|
REG8(add + 2*DC_BLOCK_SIZE - 8) = REG8(add + DC_BLOCK_SIZE + 7);
|
REG8(add + 2*DC_BLOCK_SIZE - 8) = REG8(add + DC_BLOCK_SIZE + 7);
|
REG8(add + 3*DC_BLOCK_SIZE - 12) = REG8(add + 2*DC_BLOCK_SIZE + 11);
|
REG8(add + 3*DC_BLOCK_SIZE - 12) = REG8(add + 2*DC_BLOCK_SIZE + 11);
|
REG8(add + 4*DC_BLOCK_SIZE - 16) = REG8(add + 3*DC_BLOCK_SIZE + 15);
|
REG8(add + 4*DC_BLOCK_SIZE - 16) = REG8(add + 3*DC_BLOCK_SIZE + 15);
|
add += DC_SETS*DC_BLOCK_SIZE;
|
add += DC_SETS*DC_BLOCK_SIZE;
|
}
|
}
|
|
|
/* Cache hit/miss r/w */
|
/* Cache hit/miss r/w */
|
add = base;
|
add = base;
|
for(i = 0; i < DC_WAYS; i++) {
|
for(i = 0; i < DC_WAYS; i++) {
|
REG16(add + (IC_SETS - 1)*IC_BLOCK_SIZE) = REG16(add + DC_BLOCK_SIZE - 4) + REG16(add + 2);
|
REG16(add + (IC_SETS - 1)*IC_BLOCK_SIZE) = REG16(add + DC_BLOCK_SIZE - 4) + REG16(add + 2);
|
REG16(add + (IC_SETS - 1)*IC_BLOCK_SIZE + 2) = REG16(add + DC_BLOCK_SIZE - 8) + REG16(add + DC_BLOCK_SIZE + 6);
|
REG16(add + (IC_SETS - 1)*IC_BLOCK_SIZE + 2) = REG16(add + DC_BLOCK_SIZE - 8) + REG16(add + DC_BLOCK_SIZE + 6);
|
REG16(add + (IC_SETS - 1)*IC_BLOCK_SIZE + 4) = REG16(add + DC_BLOCK_SIZE - 12) + REG16(add + 2*DC_BLOCK_SIZE + 10);
|
REG16(add + (IC_SETS - 1)*IC_BLOCK_SIZE + 4) = REG16(add + DC_BLOCK_SIZE - 12) + REG16(add + 2*DC_BLOCK_SIZE + 10);
|
REG16(add + (IC_SETS - 1)*IC_BLOCK_SIZE + 6) = REG16(add+ DC_BLOCK_SIZE - 16) + REG16(add + 2*DC_BLOCK_SIZE + 14);
|
REG16(add + (IC_SETS - 1)*IC_BLOCK_SIZE + 6) = REG16(add+ DC_BLOCK_SIZE - 16) + REG16(add + 2*DC_BLOCK_SIZE + 14);
|
add += DC_SETS*DC_BLOCK_SIZE;
|
add += DC_SETS*DC_BLOCK_SIZE;
|
}
|
}
|
|
|
/* Fill cache with unused data */
|
/* Fill cache with unused data */
|
add = base + DC_WAYS*DC_SETS*DC_BLOCK_SIZE;
|
add = base + DC_WAYS*DC_SETS*DC_BLOCK_SIZE;
|
for(i = 0; i < DC_WAYS; i++) {
|
for(i = 0; i < DC_WAYS; i++) {
|
ul = REG32(add);
|
ul = REG32(add);
|
ul = REG32(add + DC_BLOCK_SIZE);
|
ul = REG32(add + DC_BLOCK_SIZE);
|
ul = REG32(add + 2*DC_BLOCK_SIZE);
|
ul = REG32(add + 2*DC_BLOCK_SIZE);
|
ul = REG32(add + 3*DC_BLOCK_SIZE);
|
ul = REG32(add + 3*DC_BLOCK_SIZE);
|
add += DC_SETS*DC_BLOCK_SIZE;
|
add += DC_SETS*DC_BLOCK_SIZE;
|
}
|
}
|
|
|
/* Cache hit/miss r */
|
/* Cache hit/miss r */
|
ul = 0;
|
ul = 0;
|
add = base;
|
add = base;
|
for(i = 0; i < DC_WAYS; i++) {
|
for(i = 0; i < DC_WAYS; i++) {
|
ul += REG16(add + (IC_SETS - 1)*IC_BLOCK_SIZE) +
|
ul += REG16(add + (IC_SETS - 1)*IC_BLOCK_SIZE) +
|
REG16(add + DC_BLOCK_SIZE - 4) +
|
REG16(add + DC_BLOCK_SIZE - 4) +
|
REG16(add + 2);
|
REG16(add + 2);
|
ul += REG16(add + (IC_SETS - 1)*IC_BLOCK_SIZE + 2) +
|
ul += REG16(add + (IC_SETS - 1)*IC_BLOCK_SIZE + 2) +
|
REG16(add + DC_BLOCK_SIZE - 8) +
|
REG16(add + DC_BLOCK_SIZE - 8) +
|
REG16(add + DC_BLOCK_SIZE + 6);
|
REG16(add + DC_BLOCK_SIZE + 6);
|
ul += REG16(add + (IC_SETS - 1)*IC_BLOCK_SIZE + 4) +
|
ul += REG16(add + (IC_SETS - 1)*IC_BLOCK_SIZE + 4) +
|
REG16(add + DC_BLOCK_SIZE - 12) +
|
REG16(add + DC_BLOCK_SIZE - 12) +
|
REG16(add + 2*DC_BLOCK_SIZE + 10);
|
REG16(add + 2*DC_BLOCK_SIZE + 10);
|
ul += REG16(add + (IC_SETS - 1)*IC_BLOCK_SIZE + 6) +
|
ul += REG16(add + (IC_SETS - 1)*IC_BLOCK_SIZE + 6) +
|
REG16(add+ DC_BLOCK_SIZE - 16) +
|
REG16(add+ DC_BLOCK_SIZE - 16) +
|
REG16(add + 2*DC_BLOCK_SIZE + 14);
|
REG16(add + 2*DC_BLOCK_SIZE + 14);
|
add += DC_SETS*DC_BLOCK_SIZE;
|
add += DC_SETS*DC_BLOCK_SIZE;
|
}
|
}
|
|
|
dcache_disable();
|
dcache_disable();
|
|
|
return ul;
|
return ul;
|
}
|
}
|
|
|
int ic_test(void)
|
int ic_test(void)
|
{
|
{
|
int i;
|
int i;
|
unsigned long base, add;
|
unsigned long base, add;
|
|
|
base = (((unsigned long)MEM_RAM / (IC_SETS*IC_BLOCK_SIZE)) * IC_SETS*IC_BLOCK_SIZE) + IC_SETS*IC_BLOCK_SIZE;
|
base = (((unsigned long)MEM_RAM / (IC_SETS*IC_BLOCK_SIZE)) * IC_SETS*IC_BLOCK_SIZE) + IC_SETS*IC_BLOCK_SIZE;
|
|
|
/* Copy jr to various location */
|
/* Copy jr to various location */
|
add = base;
|
add = base;
|
for(i = 0; i < IC_WAYS; i++) {
|
for(i = 0; i < IC_WAYS; i++) {
|
copy_jr(add);
|
copy_jr(add);
|
copy_jr(add + 2*IC_BLOCK_SIZE + 4);
|
copy_jr(add + 2*IC_BLOCK_SIZE + 4);
|
copy_jr(add + 4*IC_BLOCK_SIZE + 8);
|
copy_jr(add + 4*IC_BLOCK_SIZE + 8);
|
copy_jr(add + 6*IC_BLOCK_SIZE + 12);
|
copy_jr(add + 6*IC_BLOCK_SIZE + 12);
|
|
|
copy_jr(add + (IC_SETS - 2)*IC_BLOCK_SIZE + 0);
|
copy_jr(add + (IC_SETS - 2)*IC_BLOCK_SIZE + 0);
|
copy_jr(add + (IC_SETS - 4)*IC_BLOCK_SIZE + 4);
|
copy_jr(add + (IC_SETS - 4)*IC_BLOCK_SIZE + 4);
|
copy_jr(add + (IC_SETS - 6)*IC_BLOCK_SIZE + 8);
|
copy_jr(add + (IC_SETS - 6)*IC_BLOCK_SIZE + 8);
|
copy_jr(add + (IC_SETS - 8)*IC_BLOCK_SIZE + 12);
|
copy_jr(add + (IC_SETS - 8)*IC_BLOCK_SIZE + 12);
|
add += IC_SETS*IC_BLOCK_SIZE;
|
add += IC_SETS*IC_BLOCK_SIZE;
|
}
|
}
|
|
|
/* Load execution table which starts at address 4 (at address 0 is table index) */
|
/* Load execution table which starts at address 4 (at address 0 is table index) */
|
add = base;
|
add = base;
|
for(i = 0; i < IC_WAYS; i++) {
|
for(i = 0; i < IC_WAYS; i++) {
|
/* Cache miss */
|
/* Cache miss */
|
jump_add[15*i + 0] = add + 2*IC_BLOCK_SIZE + 4;
|
jump_add[15*i + 0] = add + 2*IC_BLOCK_SIZE + 4;
|
jump_add[15*i + 1] = add + 4*IC_BLOCK_SIZE + 8;
|
jump_add[15*i + 1] = add + 4*IC_BLOCK_SIZE + 8;
|
jump_add[15*i + 2] = add + 6*IC_BLOCK_SIZE + 12;
|
jump_add[15*i + 2] = add + 6*IC_BLOCK_SIZE + 12;
|
/* Cache hit/miss */
|
/* Cache hit/miss */
|
jump_add[15*i + 3] = add;
|
jump_add[15*i + 3] = add;
|
jump_add[15*i + 4] = add + (IC_SETS - 2)*IC_BLOCK_SIZE + 0;
|
jump_add[15*i + 4] = add + (IC_SETS - 2)*IC_BLOCK_SIZE + 0;
|
jump_add[15*i + 5] = add + 2*IC_BLOCK_SIZE + 4;
|
jump_add[15*i + 5] = add + 2*IC_BLOCK_SIZE + 4;
|
jump_add[15*i + 6] = add + (IC_SETS - 4)*IC_BLOCK_SIZE + 4;
|
jump_add[15*i + 6] = add + (IC_SETS - 4)*IC_BLOCK_SIZE + 4;
|
jump_add[15*i + 7] = add + 4*IC_BLOCK_SIZE + 8;
|
jump_add[15*i + 7] = add + 4*IC_BLOCK_SIZE + 8;
|
jump_add[15*i + 8] = add + (IC_SETS - 6)*IC_BLOCK_SIZE + 8;
|
jump_add[15*i + 8] = add + (IC_SETS - 6)*IC_BLOCK_SIZE + 8;
|
jump_add[15*i + 9] = add + 6*IC_BLOCK_SIZE + 12;
|
jump_add[15*i + 9] = add + 6*IC_BLOCK_SIZE + 12;
|
jump_add[15*i + 10] = add + (IC_SETS - 8)*IC_BLOCK_SIZE + 12;
|
jump_add[15*i + 10] = add + (IC_SETS - 8)*IC_BLOCK_SIZE + 12;
|
/* Cache hit */
|
/* Cache hit */
|
jump_add[15*i + 11] = add + (IC_SETS - 2)*IC_BLOCK_SIZE + 0;
|
jump_add[15*i + 11] = add + (IC_SETS - 2)*IC_BLOCK_SIZE + 0;
|
jump_add[15*i + 12] = add + (IC_SETS - 4)*IC_BLOCK_SIZE + 4;
|
jump_add[15*i + 12] = add + (IC_SETS - 4)*IC_BLOCK_SIZE + 4;
|
jump_add[15*i + 13] = add + (IC_SETS - 6)*IC_BLOCK_SIZE + 8;
|
jump_add[15*i + 13] = add + (IC_SETS - 6)*IC_BLOCK_SIZE + 8;
|
jump_add[15*i + 14] = add + (IC_SETS - 8)*IC_BLOCK_SIZE + 12;
|
jump_add[15*i + 14] = add + (IC_SETS - 8)*IC_BLOCK_SIZE + 12;
|
|
|
add += IC_SETS*IC_BLOCK_SIZE;
|
add += IC_SETS*IC_BLOCK_SIZE;
|
}
|
}
|
|
|
/* Go home */
|
/* Go home */
|
jump_add[15*i] = (unsigned long)&jalr;
|
jump_add[15*i] = (unsigned long)&jalr;
|
|
|
/* Initilalize table index */
|
/* Initilalize table index */
|
jump_indx = &jump_add[0];
|
jump_indx = &jump_add[0];
|
|
|
icache_enable();
|
icache_enable();
|
|
|
/* Go */
|
/* Go */
|
call(base);
|
call(base);
|
|
|
icache_disable();
|
icache_disable();
|
|
|
return 0xdeaddead;
|
return 0xdeaddead;
|
}
|
}
|
|
|
int main(void)
|
int main(void)
|
{
|
{
|
int rc;
|
int rc;
|
|
|
rc = dc_test();
|
rc = dc_test();
|
report(rc + 0xdeaddca1);
|
report(rc + 0xdeaddca1);
|
|
|
/* Be aware that this test doesn't report result troug report call.
|
/* Be aware that this test doesn't report result troug report call.
|
It writes to spr 0x1234 directly (in jump function)!!!
|
It writes to spr 0x1234 directly (in jump function)!!!
|
|
|
This test can not be run on or1ksim. */
|
This test can not be run on or1ksim. */
|
rc = ic_test();
|
rc = ic_test();
|
report(rc);
|
report(rc);
|
|
|
exit(0);
|
return 0;
|
}
|
}
|
|
|
/* just for size calculation */
|
/* just for size calculation */
|
void dummy()
|
void dummy()
|
{
|
{
|
}
|
}
|
|
|