Line 38... |
Line 38... |
#include "sim-config.h"
|
#include "sim-config.h"
|
#include "debug.h"
|
#include "debug.h"
|
|
|
DEFAULT_DEBUG_CHANNEL(immu);
|
DEFAULT_DEBUG_CHANNEL(immu);
|
|
|
extern int cont_run;
|
|
|
|
/* Insn MMU */
|
/* Insn MMU */
|
|
|
static inline oraddr_t immu_simulate_tlb(oraddr_t virtaddr)
|
static inline oraddr_t immu_simulate_tlb(oraddr_t virtaddr)
|
{
|
{
|
int set, way = -1;
|
int set, way = -1;
|
int i;
|
int i;
|
oraddr_t tagaddr;
|
oraddr_t tagaddr;
|
oraddr_t vpn, ppn;
|
oraddr_t vpn, ppn;
|
|
|
if (!(mfspr(SPR_SR) & SPR_SR_IME) || !(testsprbits(SPR_UPR, SPR_UPR_IMP))) {
|
if (!(cpu_state.sprs[SPR_SR] & SPR_SR_IME) ||
|
|
!(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP)) {
|
insn_ci = (virtaddr >= 0x80000000);
|
insn_ci = (virtaddr >= 0x80000000);
|
return virtaddr;
|
return virtaddr;
|
}
|
}
|
|
|
TRACE("IMMU enabled, checking mmu ways\n");
|
TRACE("IMMU enabled, checking mmu ways\n");
|
Line 64... |
Line 63... |
vpn = virtaddr / (config.immu.pagesize * config.immu.nsets);
|
vpn = virtaddr / (config.immu.pagesize * config.immu.nsets);
|
|
|
/* Scan all ways and try to find a matching way. */
|
/* Scan all ways and try to find a matching way. */
|
for (i = 0; i < config.immu.nways; i++)
|
for (i = 0; i < config.immu.nways; i++)
|
if (((mfspr(SPR_ITLBMR_BASE(i) + set) / (config.immu.pagesize * config.immu.nsets)) == vpn) &&
|
if (((mfspr(SPR_ITLBMR_BASE(i) + set) / (config.immu.pagesize * config.immu.nsets)) == vpn) &&
|
testsprbits(SPR_ITLBMR_BASE(i) + set, SPR_ITLBMR_V))
|
(cpu_state.sprs[SPR_ITLBMR_BASE(i) + set] & SPR_ITLBMR_V))
|
way = i;
|
way = i;
|
|
|
/* Did we find our tlb entry? */
|
/* Did we find our tlb entry? */
|
if (way >= 0) { /* Yes, we did. */
|
if (way >= 0) { /* Yes, we did. */
|
immu_stats.fetch_tlbhit++;
|
immu_stats.fetch_tlbhit++;
|
TRACE("ITLB hit (virtaddr=%"PRIxADDR").\n", virtaddr);
|
TRACE("ITLB hit (virtaddr=%"PRIxADDR").\n", virtaddr);
|
|
|
/* Set LRUs */
|
/* Set LRUs */
|
for (i = 0; i < config.immu.nways; i++)
|
for (i = 0; i < config.immu.nways; i++) {
|
if (testsprbits(SPR_ITLBMR_BASE(i) + set, SPR_ITLBMR_LRU))
|
uorreg_t lru = cpu_state.sprs[SPR_ITLBMR_BASE(i) + set];
|
setsprbits(SPR_ITLBMR_BASE(i) + set, SPR_ITLBMR_LRU, getsprbits(SPR_ITLBMR_BASE(i) + set, SPR_ITLBMR_LRU) - 1);
|
if (lru & SPR_ITLBMR_LRU) {
|
setsprbits(SPR_ITLBMR_BASE(way) + set, SPR_ITLBMR_LRU, config.immu.nsets - 1);
|
lru = (lru & ~SPR_ITLBMR_LRU) | ((lru & SPR_ITLBMR_LRU) - 0x40);
|
|
cpu_state.sprs[SPR_ITLBMR_BASE(i) + set] = lru;
|
|
}
|
|
}
|
|
cpu_state.sprs[SPR_ITLBMR_BASE(way) + set] &= ~SPR_ITLBMR_LRU;
|
|
cpu_state.sprs[SPR_ITLBMR_BASE(way) + set] |= (config.immu.nsets - 1) << 6;
|
|
|
/* Check if page is cache inhibited */
|
/* Check if page is cache inhibited */
|
insn_ci = (mfspr(SPR_ITLBTR_BASE(way) + set) & SPR_ITLBTR_CI) == SPR_ITLBTR_CI;
|
insn_ci = (mfspr(SPR_ITLBTR_BASE(way) + set) & SPR_ITLBTR_CI) == SPR_ITLBTR_CI;
|
|
|
runtime.sim.mem_cycles += config.immu.hitdelay;
|
runtime.sim.mem_cycles += config.immu.hitdelay;
|
Line 99... |
Line 103... |
}
|
}
|
else { /* No, we didn't. */
|
else { /* No, we didn't. */
|
immu_stats.fetch_tlbmiss++;
|
immu_stats.fetch_tlbmiss++;
|
#if 0
|
#if 0
|
for (i = 0; i < config.immu.nways; i++)
|
for (i = 0; i < config.immu.nways; i++)
|
if (getsprbits(SPR_ITLBMR_BASE(i) + set, SPR_ITLBMR_LRU) < minlru)
|
if (((cpu_state.sprs[SPR_ITLBMR_BASE(i) + set] & SPR_ITLBMR_LRU) >> 6) < minlru)
|
minway = i;
|
minway = i;
|
|
|
setsprbits(SPR_ITLBMR_BASE(minway) + set, SPR_ITLBMR_VPN, vpn);
|
cpu_state.sprs[SPR_ITLBMR_BASE(minway) + set] &= ~SPR_ITLBMR_VPN;
|
for (i = 0; i < config.immu.nways; i++)
|
cpu_state.sprs[SPR_ITLBMR_BASE(minway) + set] |= vpn << 12;
|
if (testsprbits(SPR_ITLBMR_BASE(i) + set, SPR_ITLBMR_LRU))
|
for (i = 0; i < config.immu.nways; i++) {
|
setsprbits(SPR_ITLBMR_BASE(i) + set, SPR_ITLBMR_LRU, getsprbits(SPR_ITLBMR_BASE(i) + set, SPR_ITLBMR_LRU) - 1);
|
uorreg_t lru = cpu_state.sprs[SPR_ITLBMR_BASE(i) + set];
|
setsprbits(SPR_ITLBMR_BASE(minway) + set, SPR_ITLBMR_LRU, config.immu.ustates - 1);
|
if (lru & SPR_ITLBMR_LRU) {
|
setsprbits(SPR_ITLBTR_BASE(minway) + set, SPR_ITLBTR_PPN, vpn); /* 1 to 1 */
|
lru = (lru & ~SPR_ITLBMR_LRU) | ((lru & SPR_ITLBMR_LRU) - 0x40);
|
setsprbits(SPR_ITLBMR_BASE(minway) + set, SPR_ITLBMR_V, 1);
|
cpu_state.sprs[SPR_ITLBMR_BASE(i) + set] = lru;
|
|
}
|
|
}
|
|
cpu_state.sprs[SPR_ITLBMR_BASE(way) + set] &= ~SPR_ITLBMR_LRU;
|
|
cpu_state.sprs[SPR_ITLBMR_BASE(way) + set] |= (config.immu.nsets - 1) << 6;
|
|
|
|
/* 1 to 1 mapping */
|
|
cpu_state.sprs[SPR_ITLBTR_BASE(minway) + set] &= ~SPR_ITLBTR_PPN;
|
|
cpu_state.sprs[SPR_ITLBTR_BASE(minway) + set] |= vpn << 12;
|
|
|
|
cpu_state.sprs[SPR_ITLBMR_BASE(minway) + set] |= SPR_ITLBMR_V;
|
#endif
|
#endif
|
|
|
/* if tlb refill implemented in HW */
|
/* if tlb refill implemented in HW */
|
/* return getsprbits(SPR_ITLBTR_BASE(minway) + set, SPR_ITLBTR_PPN) * config.immu.pagesize + (virtaddr % config.immu.pagesize); */
|
/* return ((cpu_state.sprs[SPR_ITLBTR_BASE(minway) + set] & SPR_ITLBTR_PPN) >> 12) * config.immu.pagesize + (virtaddr % config.immu.pagesize); */
|
runtime.sim.mem_cycles += config.immu.missdelay;
|
runtime.sim.mem_cycles += config.immu.missdelay;
|
|
|
except_handle(EXCEPT_ITLBMISS, virtaddr);
|
except_handle(EXCEPT_ITLBMISS, virtaddr);
|
return 0;
|
return 0;
|
}
|
}
|
Line 137... |
Line 151... |
int set, way = -1;
|
int set, way = -1;
|
int i;
|
int i;
|
oraddr_t tagaddr;
|
oraddr_t tagaddr;
|
oraddr_t vpn, ppn;
|
oraddr_t vpn, ppn;
|
|
|
if (!(mfspr(SPR_SR) & SPR_SR_IME) || !(testsprbits(SPR_UPR, SPR_UPR_IMP))) {
|
if (!(cpu_state.sprs[SPR_SR] & SPR_SR_IME) ||
|
|
!(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP)) {
|
return(virtaddr);
|
return(virtaddr);
|
}
|
}
|
|
|
/* Which set to check out? */
|
/* Which set to check out? */
|
set = (virtaddr / config.immu.pagesize) % config.immu.nsets;
|
set = (virtaddr / config.immu.pagesize) % config.immu.nsets;
|
Line 149... |
Line 164... |
vpn = virtaddr / (config.immu.pagesize * config.immu.nsets);
|
vpn = virtaddr / (config.immu.pagesize * config.immu.nsets);
|
|
|
/* Scan all ways and try to find a matching way. */
|
/* Scan all ways and try to find a matching way. */
|
for (i = 0; i < config.immu.nways; i++)
|
for (i = 0; i < config.immu.nways; i++)
|
if (((mfspr(SPR_ITLBMR_BASE(i) + set) / (config.immu.pagesize * config.immu.nsets)) == vpn) &&
|
if (((mfspr(SPR_ITLBMR_BASE(i) + set) / (config.immu.pagesize * config.immu.nsets)) == vpn) &&
|
testsprbits(SPR_ITLBMR_BASE(i) + set, SPR_ITLBMR_V))
|
(cpu_state.sprs[SPR_ITLBMR_BASE(i) + set] & SPR_ITLBMR_V))
|
way = i;
|
way = i;
|
|
|
/* Did we find our tlb entry? */
|
/* Did we find our tlb entry? */
|
if (way >= 0) { /* Yes, we did. */
|
if (way >= 0) { /* Yes, we did. */
|
|
|
Line 188... |
Line 203... |
|
|
/* PRINTF("IMMU translate(%x) = %x\n", virtaddr, phyaddr);*/
|
/* PRINTF("IMMU translate(%x) = %x\n", virtaddr, phyaddr);*/
|
return phyaddr;
|
return phyaddr;
|
}
|
}
|
|
|
void itlb_info()
|
void itlb_info(void)
|
{
|
{
|
if (!testsprbits(SPR_UPR, SPR_UPR_IMP)) {
|
if (!(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP)) {
|
PRINTF("IMMU not implemented. Set UPR[IMP].\n");
|
PRINTF("IMMU not implemented. Set UPR[IMP].\n");
|
return;
|
return;
|
}
|
}
|
|
|
PRINTF("Insn MMU %dKB: ", config.immu.nsets * config.immu.entrysize * config.immu.nways / 1024);
|
PRINTF("Insn MMU %dKB: ", config.immu.nsets * config.immu.entrysize * config.immu.nways / 1024);
|
Line 218... |
Line 233... |
{
|
{
|
int set;
|
int set;
|
int way;
|
int way;
|
int end_set = config.immu.nsets;
|
int end_set = config.immu.nsets;
|
|
|
if (!testsprbits(SPR_UPR, SPR_UPR_IMP)) {
|
if (!(cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP)) {
|
PRINTF("IMMU not implemented. Set UPR[IMP].\n");
|
PRINTF("IMMU not implemented. Set UPR[IMP].\n");
|
return;
|
return;
|
}
|
}
|
|
|
if ((start_set >= 0) && (start_set < end_set))
|
if ((start_set >= 0) && (start_set < end_set))
|
Line 252... |
Line 267... |
}
|
}
|
|
|
/*---------------------------------------------------[ IMMU configuration ]---*/
|
/*---------------------------------------------------[ IMMU configuration ]---*/
|
void immu_enabled(union param_val val, void *dat)
|
void immu_enabled(union param_val val, void *dat)
|
{
|
{
|
setsprbits (SPR_UPR, SPR_UPR_IMP, val.int_val ? 1 : 0);
|
if(val.int_val)
|
|
cpu_state.sprs[SPR_UPR] |= SPR_UPR_IMP;
|
|
else
|
|
cpu_state.sprs[SPR_UPR] &= ~SPR_UPR_IMP;
|
config.immu.enabled = val.int_val;
|
config.immu.enabled = val.int_val;
|
}
|
}
|
|
|
void immu_nsets(union param_val val, void *dat)
|
void immu_nsets(union param_val val, void *dat)
|
{
|
{
|
if (is_power2(val.int_val) && val.int_val <= 256) {
|
if (is_power2(val.int_val) && val.int_val <= 256) {
|
config.immu.nsets = val.int_val;
|
config.immu.nsets = val.int_val;
|
setsprbits (SPR_IMMUCFGR, SPR_IMMUCFGR_NTS, log2(val.int_val));
|
cpu_state.sprs[SPR_IMMUCFGR] &= ~SPR_IMMUCFGR_NTS;
|
|
cpu_state.sprs[SPR_IMMUCFGR] |= log2(val.int_val) << 3;
|
}
|
}
|
else
|
else
|
CONFIG_ERROR("value of power of two and lower or equal than 256 expected.");
|
CONFIG_ERROR("value of power of two and lower or equal than 256 expected.");
|
}
|
}
|
|
|
void immu_nways(union param_val val, void *dat)
|
void immu_nways(union param_val val, void *dat)
|
{
|
{
|
if (val.int_val >= 1 && val.int_val <= 4) {
|
if (val.int_val >= 1 && val.int_val <= 4) {
|
config.immu.nways = val.int_val;
|
config.immu.nways = val.int_val;
|
setsprbits (SPR_DMMUCFGR, SPR_DMMUCFGR_NTW, val.int_val-1);
|
cpu_state.sprs[SPR_IMMUCFGR] &= ~SPR_IMMUCFGR_NTW;
|
|
cpu_state.sprs[SPR_IMMUCFGR] |= val.int_val - 1;
|
}
|
}
|
else
|
else
|
CONFIG_ERROR("value 1, 2, 3 or 4 expected.");
|
CONFIG_ERROR("value 1, 2, 3 or 4 expected.");
|
}
|
}
|
|
|