ARM: Cache the misc regs at the TLB to limit readMiscReg() calls.

This commit is contained in:
Ali Saidi 2010-11-15 14:04:03 -06:00
parent 4c2e5c282b
commit 13931b9b82
4 changed files with 72 additions and 23 deletions

View file

@ -227,10 +227,20 @@ ISA::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
void void
ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
{ {
MiscReg newVal = val; MiscReg newVal = val;
if (misc_reg == MISCREG_CPSR) { if (misc_reg == MISCREG_CPSR) {
updateRegMap(val); updateRegMap(val);
CPSR old_cpsr = miscRegs[MISCREG_CPSR];
int old_mode = old_cpsr.mode;
CPSR cpsr = val; CPSR cpsr = val;
if (old_mode != cpsr.mode) {
tc->getITBPtr()->invalidateMiscReg();
tc->getDTBPtr()->invalidateMiscReg();
}
DPRINTF(Arm, "Updating CPSR from %#x to %#x f:%d i:%d a:%d mode:%#x\n", DPRINTF(Arm, "Updating CPSR from %#x to %#x f:%d i:%d a:%d mode:%#x\n",
miscRegs[misc_reg], cpsr, cpsr.f, cpsr.i, cpsr.a, cpsr.mode); miscRegs[misc_reg], cpsr, cpsr.f, cpsr.i, cpsr.a, cpsr.mode);
PCState pc = tc->pcState(); PCState pc = tc->pcState();
@ -309,6 +319,8 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
SCTLR new_sctlr = newVal; SCTLR new_sctlr = newVal;
new_sctlr.nmfi = (bool)sctlr.nmfi; new_sctlr.nmfi = (bool)sctlr.nmfi;
miscRegs[MISCREG_SCTLR] = (MiscReg)new_sctlr; miscRegs[MISCREG_SCTLR] = (MiscReg)new_sctlr;
tc->getITBPtr()->invalidateMiscReg();
tc->getDTBPtr()->invalidateMiscReg();
return; return;
} }
case MISCREG_TLBTR: case MISCREG_TLBTR:
@ -426,6 +438,14 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
} }
return; return;
} }
case MISCREG_CONTEXTIDR:
case MISCREG_PRRR:
case MISCREG_NMRR:
case MISCREG_DACR:
tc->getITBPtr()->invalidateMiscReg();
tc->getDTBPtr()->invalidateMiscReg();
break;
} }
} }
setMiscRegNoEffect(misc_reg, newVal); setMiscRegNoEffect(misc_reg, newVal);

View file

@ -69,7 +69,7 @@ TLB::TLB(const Params *p)
#if FULL_SYSTEM #if FULL_SYSTEM
, tableWalker(p->walker) , tableWalker(p->walker)
#endif #endif
, rangeMRU(1) , rangeMRU(1), miscRegValid(false)
{ {
table = new TlbEntry[size]; table = new TlbEntry[size];
memset(table, 0, sizeof(TlbEntry[size])); memset(table, 0, sizeof(TlbEntry[size]));
@ -88,8 +88,9 @@ TLB::~TLB()
bool bool
TLB::translateFunctional(ThreadContext *tc, Addr va, Addr &pa) TLB::translateFunctional(ThreadContext *tc, Addr va, Addr &pa)
{ {
uint32_t context_id = tc->readMiscReg(MISCREG_CONTEXTIDR); if (!miscRegValid)
TlbEntry *e = lookup(va, context_id, true); updateMiscReg(tc);
TlbEntry *e = lookup(va, contextId, true);
if (!e) if (!e)
return false; return false;
pa = e->pAddr(va); pa = e->pAddr(va);
@ -275,6 +276,7 @@ TLB::unserialize(Checkpoint *cp, const string &section)
for(int i = 0; i < size; i++){ for(int i = 0; i < size; i++){
table[i].unserialize(cp, csprintf("%s.TlbEntry%d", section, i)); table[i].unserialize(cp, csprintf("%s.TlbEntry%d", section, i));
} }
miscRegValid = false;
} }
void void
@ -398,9 +400,9 @@ Fault
TLB::translateSe(RequestPtr req, ThreadContext *tc, Mode mode, TLB::translateSe(RequestPtr req, ThreadContext *tc, Mode mode,
Translation *translation, bool &delay, bool timing) Translation *translation, bool &delay, bool timing)
{ {
// XXX Cache misc registers and have miscreg write function inv cache if (!miscRegValid)
updateMiscReg(tc);
Addr vaddr = req->getVaddr(); Addr vaddr = req->getVaddr();
SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR);
uint32_t flags = req->getFlags(); uint32_t flags = req->getFlags();
bool is_fetch = (mode == Execute); bool is_fetch = (mode == Execute);
@ -444,18 +446,18 @@ Fault
TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode, TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
Translation *translation, bool &delay, bool timing) Translation *translation, bool &delay, bool timing)
{ {
// XXX Cache misc registers and have miscreg write function inv cache if (!miscRegValid)
updateMiscReg(tc);
Addr vaddr = req->getVaddr(); Addr vaddr = req->getVaddr();
SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR);
CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
uint32_t flags = req->getFlags(); uint32_t flags = req->getFlags();
bool is_fetch = (mode == Execute); bool is_fetch = (mode == Execute);
bool is_write = (mode == Write); bool is_write = (mode == Write);
bool is_priv = (cpsr.mode != MODE_USER) && !(flags & UserMode); bool is_priv = isPriv && !(flags & UserMode);
DPRINTF(TLBVerbose, "CPSR is user:%d UserMode:%d\n", cpsr.mode == MODE_USER, flags DPRINTF(TLBVerbose, "CPSR is user:%d UserMode:%d\n",
& UserMode); isPriv, flags & UserMode);
// If this is a clrex instruction, provide a PA of 0 with no fault // If this is a clrex instruction, provide a PA of 0 with no fault
// This will force the monitor to set the tracked address to 0 // This will force the monitor to set the tracked address to 0
// a bit of a hack but this effectively clrears this processors monitor // a bit of a hack but this effectively clrears this processors monitor
@ -479,18 +481,13 @@ TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
} }
} }
uint32_t context_id = tc->readMiscReg(MISCREG_CONTEXTIDR);
Fault fault; Fault fault;
if (!sctlr.m) { if (!sctlr.m) {
req->setPaddr(vaddr); req->setPaddr(vaddr);
if (sctlr.tre == 0) { if (sctlr.tre == 0) {
req->setFlags(Request::UNCACHEABLE); req->setFlags(Request::UNCACHEABLE);
} else { } else {
PRRR prrr = tc->readMiscReg(MISCREG_PRRR);
NMRR nmrr = tc->readMiscReg(MISCREG_NMRR);
if (nmrr.ir0 == 0 || nmrr.or0 == 0 || prrr.tr0 != 0x2) if (nmrr.ir0 == 0 || nmrr.or0 == 0 || prrr.tr0 != 0x2)
req->setFlags(Request::UNCACHEABLE); req->setFlags(Request::UNCACHEABLE);
} }
@ -507,10 +504,10 @@ TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
return trickBoxCheck(req, mode, 0, false); return trickBoxCheck(req, mode, 0, false);
} }
DPRINTF(TLBVerbose, "Translating vaddr=%#x context=%d\n", vaddr, context_id); DPRINTF(TLBVerbose, "Translating vaddr=%#x context=%d\n", vaddr, contextId);
// Translation enabled // Translation enabled
TlbEntry *te = lookup(vaddr, context_id); TlbEntry *te = lookup(vaddr, contextId);
if (te == NULL) { if (te == NULL) {
if (req->isPrefetch()){ if (req->isPrefetch()){
//if the request is a prefetch don't attempt to fill the TLB //if the request is a prefetch don't attempt to fill the TLB
@ -529,8 +526,8 @@ TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
// start translation table walk, pass variables rather than // start translation table walk, pass variables rather than
// re-retreaving in table walker for speed // re-retreaving in table walker for speed
DPRINTF(TLB, "TLB Miss: Starting hardware table walker for %#x(%d)\n", DPRINTF(TLB, "TLB Miss: Starting hardware table walker for %#x(%d)\n",
vaddr, context_id); vaddr, contextId);
fault = tableWalker->walk(req, tc, context_id, mode, translation, fault = tableWalker->walk(req, tc, contextId, mode, translation,
timing); timing);
if (timing) { if (timing) {
delay = true; delay = true;
@ -540,7 +537,7 @@ TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
if (fault) if (fault)
return fault; return fault;
te = lookup(vaddr, context_id); te = lookup(vaddr, contextId);
if (!te) if (!te)
printTlb(); printTlb();
assert(te); assert(te);
@ -561,7 +558,7 @@ TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
setAttr(te->attributes); setAttr(te->attributes);
if (te->nonCacheable) if (te->nonCacheable)
req->setFlags(Request::UNCACHEABLE); req->setFlags(Request::UNCACHEABLE);
uint32_t dacr = tc->readMiscReg(MISCREG_DACR);
switch ( (dacr >> (te->domain * 2)) & 0x3) { switch ( (dacr >> (te->domain * 2)) & 0x3) {
case 0: case 0:
domainFaults++; domainFaults++;

View file

@ -208,6 +208,32 @@ class TLB : public BaseTLB
void unserialize(Checkpoint *cp, const std::string &section); void unserialize(Checkpoint *cp, const std::string &section);
void regStats(); void regStats();
// Caching misc register values here.
// Writing to misc registers needs to invalidate them.
// translateFunctional/translateSe/translateFs checks if they are
// invalid and call updateMiscReg if necessary.
protected:
SCTLR sctlr;
bool isPriv;
uint32_t contextId;
PRRR prrr;
NMRR nmrr;
uint32_t dacr;
bool miscRegValid;
void updateMiscReg(ThreadContext *tc)
{
sctlr = tc->readMiscReg(MISCREG_SCTLR);
CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
isPriv = cpsr.mode != MODE_USER;
contextId = tc->readMiscReg(MISCREG_CONTEXTIDR);
prrr = tc->readMiscReg(MISCREG_PRRR);
nmrr = tc->readMiscReg(MISCREG_NMRR);
dacr = tc->readMiscReg(MISCREG_DACR);
miscRegValid = true;
}
public:
inline void invalidateMiscReg() { miscRegValid = false; }
}; };
/* namespace ArmISA */ } /* namespace ArmISA */ }

View file

@ -48,6 +48,8 @@
#include "mem/vport.hh" #include "mem/vport.hh"
#endif #endif
#include "arch/arm/tlb.hh"
namespace ArmISA { namespace ArmISA {
void void
@ -148,7 +150,11 @@ copyRegs(ThreadContext *src, ThreadContext *dest)
// e.g. updateRegMap(val) // e.g. updateRegMap(val)
dest->setMiscReg(MISCREG_CPSR, src->readMiscRegNoEffect(MISCREG_CPSR)); dest->setMiscReg(MISCREG_CPSR, src->readMiscRegNoEffect(MISCREG_CPSR));
// Lastly copy PC/NPC // Copy over the PC State
dest->pcState(src->pcState()); dest->pcState(src->pcState());
// Invalidate the tlb misc register cache
dest->getITBPtr()->invalidateMiscReg();
dest->getDTBPtr()->invalidateMiscReg();
} }
} }