#include "types.h" #include "CPU.h" #include "icache.h" //#define ICACHE_DEBUGGING #ifdef ICACHE_DEBUGGING #define _icache_fetch_func icacheFetch_ #define _icache_test_func icacheFetch #else #define _icache_fetch_func icacheFetch #define _icache_test_func icacheFetch_test #endif void icacheInval(icache* ic){ UInt8 i, j; for(i = 0; i < ICACHE_BUCKET_NUM; i++){ for(j = 0; j < ICACHE_BUCKET_SZ; j++) ic->lines[i][j].info = 0; ic->ptr[i] = 0; } } void icacheInit(icache* ic, ArmCpu* cpu, ArmCpuMemF memF){ ic->cpu = cpu; ic->memF = memF; icacheInval(ic); } static UInt8 icachePrvHash(UInt32 addr){ addr >>= ICACHE_L; addr &= (1UL << ICACHE_S) - 1UL; return addr; } void icacheInvalAddr(icache* ic, UInt32 va){ UInt32 off = va % ICACHE_LINE_SZ; Int8 i, j, bucket; icacheLine* lines; va -= off; bucket = icachePrvHash(va); lines = ic->lines[bucket]; for(i = 0, j = ic->ptr[bucket]; (UInt8)i < ICACHE_BUCKET_SZ; i++){ if(--j == -1) j = ICACHE_BUCKET_SZ - 1; if((lines[j].info & (ICACHE_ADDR_MASK | ICACHE_USED_MASK)) == (va | ICACHE_USED_MASK)){ //found it! lines[j].info = 0; } } } /* we cannot have data overlap cachelines since data is self aligned (word on 4-byte boundary, halfwords on2, etc. this is enforced elsewhere */ Boolean _icache_fetch_func(icache* ic, UInt32 va, UInt8 sz, Boolean priviledged, UInt8* fsrP, void* buf){ UInt32 off = va % ICACHE_LINE_SZ; Int8 i, j, bucket; icacheLine* lines; icacheLine* line; va -= off; bucket = icachePrvHash(va); lines = ic->lines[bucket]; for(i = 0, j = ic->ptr[bucket]; (UInt8)i < ICACHE_BUCKET_SZ; i++){ if(--j == -1) j = ICACHE_BUCKET_SZ - 1; if((lines[j].info & (ICACHE_ADDR_MASK | ICACHE_USED_MASK)) == (va | ICACHE_USED_MASK)){ //found it! if(sz == 4){ *(UInt32*)buf = *(UInt32*)(lines[j].data + off); } else if(sz == 2){ *(UInt16*)buf = *(UInt16*)(lines[j].data + off); } else __mem_copy(buf, lines[j].data + off, sz); return priviledged || !(lines[j].info & ICACHE_PRIV_MASK); } } //if we're here, we found nothing - time to populate the cache j = ic->ptr[bucket]++; if(ic->ptr[bucket] == ICACHE_BUCKET_SZ) ic->ptr[bucket] = 0; line = lines + j; line->info = va | (priviledged ? ICACHE_PRIV_MASK : 0); if(!ic->memF(ic->cpu, line->data, va, ICACHE_LINE_SZ, false, priviledged, fsrP)){ return false; } line->info |= ICACHE_USED_MASK; if(sz == 4){ *(UInt32*)buf = *(UInt32*)(line->data + off); } else if(sz == 2){ *(UInt16*)buf = *(UInt16*)(line->data + off); } else __mem_copy(buf, line->data + off, sz); return true; } #include "stdio.h" Boolean _icache_test_func(icache* ic, UInt32 va, UInt8 sz, Boolean priviledged, UInt8* fsrP, void* buf){ UInt8 fsrO = -1, fsrT = -1; UInt8 dataO[4] = {0}, dataT[4] = {0}; Boolean retO, retT; UInt8 i; retO = _icache_fetch_func(ic, va, sz, priviledged, &fsrO, dataO); retT = ic->memF(ic->cpu, dataT, va, sz, false, priviledged, &fsrT); if((retT != retO) || (fsrT != fsrO) || (dataT[0] != dataO[0]) || (dataT[1] != dataO[1]) || (dataT[2] != dataO[2]) || (dataT[3] != dataO[3])){ fprintf(stderr, "icache fail!"); } for(i = 0; i < sz; i++) ((UInt8*)buf)[i] = dataT[i]; if(retT) *fsrP = fsrT; return retT; }