ARM: Cache the misc regs at the TLB to limit readMiscReg() calls.
This commit is contained in:
parent
4c2e5c282b
commit
13931b9b82
4 changed files with 72 additions and 23 deletions
|
@ -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);
|
||||||
|
|
|
@ -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 §ion)
|
||||||
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++;
|
||||||
|
|
|
@ -208,6 +208,32 @@ class TLB : public BaseTLB
|
||||||
void unserialize(Checkpoint *cp, const std::string §ion);
|
void unserialize(Checkpoint *cp, const std::string §ion);
|
||||||
|
|
||||||
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 */ }
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue