#include "cpu/base.hh"
#include "mem/packet_access.hh"
#include "mem/request.hh"
-#include "params/SparcDTB.hh"
-#include "params/SparcITB.hh"
#include "sim/system.hh"
/* @todo remove some of the magic constants. -- ali
* */
namespace SparcISA {
-TLB::TLB(const std::string &name, int s)
- : SimObject(name), size(s), usedEntries(0), lastReplaced(0),
+TLB::TLB(const Params *p)
+ : BaseTLB(p), size(p->size), usedEntries(0), lastReplaced(0),
cacheValid(false)
{
// To make this work you'll have to change the hypervisor and OS
if (size > 64)
- fatal("SPARC T1 TLB registers don't support more than 64 TLB entries.");
+ fatal("SPARC T1 TLB registers don't support more than 64 TLB entries");
tlb = new TlbEntry[size];
std::memset(tlb, 0, sizeof(TlbEntry) * size);
TLB::insert(Addr va, int partition_id, int context_id, bool real,
const PageTableEntry& PTE, int entry)
{
-
-
MapIter i;
TlbEntry *new_entry = NULL;
// TlbRange tr;
tr.real = real;
*/
- DPRINTF(TLB, "TLB: Inserting TLB Entry; va=%#x pa=%#x pid=%d cid=%d r=%d entryid=%d\n",
- va, PTE.paddr(), partition_id, context_id, (int)real, entry);
+ DPRINTF(TLB,
+ "TLB: Inserting Entry; va=%#x pa=%#x pid=%d cid=%d r=%d entryid=%d\n",
+ va, PTE.paddr(), partition_id, context_id, (int)real, entry);
// Demap any entry that conflicts
for (x = 0; x < size; x++) {
}
}
-
/*
i = lookupTable.find(tr);
if (i != lookupTable.end()) {
new_entry->valid = true;
usedEntries++;
-
-
i = lookupTable.insert(new_entry->range, new_entry);
assert(i != lookupTable.end());
- // If all entries have there used bit set, clear it on them all, but the
- // one we just inserted
+ // If all entries have their used bit set, clear it on them all,
+ // but the one we just inserted
if (usedEntries == size) {
clearUsedBits();
new_entry->used = true;
usedEntries++;
}
-
}
TlbEntry*
-TLB::lookup(Addr va, int partition_id, bool real, int context_id, bool
- update_used)
+TLB::lookup(Addr va, int partition_id, bool real, int context_id,
+ bool update_used)
{
MapIter i;
TlbRange tr;
va, partition_id, context_id, real);
// Assemble full address structure
tr.va = va;
- tr.size = MachineBytes;
+ tr.size = 1;
tr.contextId = context_id;
tr.partitionId = partition_id;
tr.real = real;
DPRINTF(TLB, "TLB: Valid entry found pa: %#x size: %#x\n", t->pte.paddr(),
t->pte.size());
- // Update the used bits only if this is a real access (not a fake one from
- // virttophys()
+ // Update the used bits only if this is a real access (not a fake
+ // one from virttophys()
if (!t->used && update_used) {
t->used = true;
usedEntries++;
// Assemble full address structure
tr.va = va;
- tr.size = MachineBytes;
+ tr.size = 1;
tr.contextId = context_id;
tr.partitionId = partition_id;
tr.real = real;
void
TLB::demapContext(int partition_id, int context_id)
{
- int x;
DPRINTF(IPR, "TLB: Demapping Context pid=%#d cid=%d\n",
partition_id, context_id);
cacheValid = false;
- for (x = 0; x < size; x++) {
+ for (int x = 0; x < size; x++) {
if (tlb[x].range.contextId == context_id &&
tlb[x].range.partitionId == partition_id) {
if (tlb[x].valid == true) {
void
TLB::demapAll(int partition_id)
{
- int x;
DPRINTF(TLB, "TLB: Demapping All pid=%#d\n", partition_id);
cacheValid = false;
- for (x = 0; x < size; x++) {
- if (!tlb[x].pte.locked() && tlb[x].range.partitionId == partition_id) {
- if (tlb[x].valid == true){
- freeList.push_front(&tlb[x]);
- }
+ for (int x = 0; x < size; x++) {
+ if (tlb[x].valid && !tlb[x].pte.locked() &&
+ tlb[x].range.partitionId == partition_id) {
+ freeList.push_front(&tlb[x]);
tlb[x].valid = false;
if (tlb[x].used) {
tlb[x].used = false;
void
TLB::invalidateAll()
{
- int x;
cacheValid = false;
-
- freeList.clear();
lookupTable.clear();
- for (x = 0; x < size; x++) {
+
+ for (int x = 0; x < size; x++) {
if (tlb[x].valid == true)
freeList.push_back(&tlb[x]);
tlb[x].valid = false;
}
uint64_t
-TLB::TteRead(int entry) {
+TLB::TteRead(int entry)
+{
if (entry >= size)
panic("entry: %d\n", entry);
}
uint64_t
-TLB::TagRead(int entry) {
+TLB::TagRead(int entry)
+{
assert(entry < size);
uint64_t tag;
if (!tlb[entry].valid)
if (cacheEntry) {
if (cacheEntry->range.va < vaddr + sizeof(MachInst) &&
cacheEntry->range.va + cacheEntry->range.size >= vaddr) {
- req->setPaddr(cacheEntry->pte.paddr() & ~(cacheEntry->pte.size()-1) |
- vaddr & cacheEntry->pte.size()-1 );
- return NoFault;
+ req->setPaddr(cacheEntry->pte.translate(vaddr));
+ return NoFault;
}
} else {
req->setPaddr(vaddr & PAddrImplMask);
if (real)
return new InstructionRealTranslationMiss;
else
+#if FULL_SYSTEM
return new FastInstructionAccessMMUMiss;
+#else
+ return new FastInstructionAccessMMUMiss(req->getVaddr());
+#endif
}
// were not priviledged accesing priv page
cacheState = tlbdata;
cacheEntry = e;
- req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
- vaddr & e->pte.size()-1 );
+ req->setPaddr(e->pte.translate(vaddr));
DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
return NoFault;
}
-
-
Fault
DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
{
- /* @todo this could really use some profiling and fixing to make it faster! */
+ /*
+ * @todo this could really use some profiling and fixing to make
+ * it faster!
+ */
uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
Addr vaddr = req->getVaddr();
Addr size = req->getSize();
asi = (ASI)req->getAsi();
bool implicit = false;
bool hpriv = bits(tlbdata,0,0);
+ bool unaligned = vaddr & (size - 1);
DPRINTF(TLB, "TLB: DTB Request to translate va=%#x size=%d asi=%#x\n",
vaddr, size, asi);
if (asi == ASI_IMPLICIT)
implicit = true;
- if (hpriv && implicit) {
- req->setPaddr(vaddr & PAddrImplMask);
- return NoFault;
- }
+ // Only use the fast path here if there doesn't need to be an unaligned
+ // trap later
+ if (!unaligned) {
+ if (hpriv && implicit) {
+ req->setPaddr(vaddr & PAddrImplMask);
+ return NoFault;
+ }
- // Be fast if we can!
- if (cacheValid && cacheState == tlbdata) {
+ // Be fast if we can!
+ if (cacheValid && cacheState == tlbdata) {
- if (cacheEntry[0]) {
- TlbEntry *ce = cacheEntry[0];
- Addr ce_va = ce->range.va;
- if (cacheAsi[0] == asi &&
- ce_va < vaddr + size && ce_va + ce->range.size > vaddr &&
- (!write || ce->pte.writable())) {
- req->setPaddr(ce->pte.paddrMask() | vaddr & ce->pte.sizeMask());
+ if (cacheEntry[0]) {
+ TlbEntry *ce = cacheEntry[0];
+ Addr ce_va = ce->range.va;
+ if (cacheAsi[0] == asi &&
+ ce_va < vaddr + size && ce_va + ce->range.size > vaddr &&
+ (!write || ce->pte.writable())) {
+ req->setPaddr(ce->pte.translate(vaddr));
if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1)
- req->setFlags(req->getFlags() | UNCACHEABLE);
+ req->setFlags(Request::UNCACHEABLE);
DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
return NoFault;
- } // if matched
- } // if cache entry valid
- if (cacheEntry[1]) {
- TlbEntry *ce = cacheEntry[1];
- Addr ce_va = ce->range.va;
- if (cacheAsi[1] == asi &&
- ce_va < vaddr + size && ce_va + ce->range.size > vaddr &&
- (!write || ce->pte.writable())) {
- req->setPaddr(ce->pte.paddrMask() | vaddr & ce->pte.sizeMask());
+ } // if matched
+ } // if cache entry valid
+ if (cacheEntry[1]) {
+ TlbEntry *ce = cacheEntry[1];
+ Addr ce_va = ce->range.va;
+ if (cacheAsi[1] == asi &&
+ ce_va < vaddr + size && ce_va + ce->range.size > vaddr &&
+ (!write || ce->pte.writable())) {
+ req->setPaddr(ce->pte.translate(vaddr));
if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1)
- req->setFlags(req->getFlags() | UNCACHEABLE);
+ req->setFlags(Request::UNCACHEABLE);
DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
return NoFault;
- } // if matched
- } // if cache entry valid
- }
+ } // if matched
+ } // if cache entry valid
+ }
+ }
bool red = bits(tlbdata,1,1);
bool priv = bits(tlbdata,2,2);
TlbEntry *e;
DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsudm:%d part_id: %#X\n",
- priv, hpriv, red, lsu_dm, part_id);
+ priv, hpriv, red, lsu_dm, part_id);
if (implicit) {
if (tl > 0) {
}
// If the asi is unaligned trap
- if (vaddr & size-1) {
+ if (unaligned) {
writeSfsr(vaddr, false, ct, false, OtherFault, asi);
return new MemAddressNotAligned;
}
return new DataAccessException;
}
-
if ((!lsu_dm && !hpriv && !red) || AsiIsReal(asi)) {
real = true;
context = 0;
- };
+ }
if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) {
req->setPaddr(vaddr & PAddrImplMask);
if (real)
return new DataRealTranslationMiss;
else
+#if FULL_SYSTEM
return new FastDataAccessMMUMiss;
+#else
+ return new FastDataAccessMMUMiss(req->getVaddr());
+#endif
}
return new DataAccessException;
}
-
if (e->pte.sideffect() || (e->pte.paddr() >> 39) & 1)
- req->setFlags(req->getFlags() | UNCACHEABLE);
+ req->setFlags(Request::UNCACHEABLE);
// cache translation date for next translation
cacheState = tlbdata;
cacheAsi[0] = (ASI)0;
}
cacheValid = true;
- req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
- vaddr & e->pte.size()-1);
+ req->setPaddr(e->pte.translate(vaddr));
DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
return NoFault;
return new PrivilegedAction;
}
- if (asi == ASI_SWVR_UDB_INTR_W && !write ||
- asi == ASI_SWVR_UDB_INTR_R && write) {
+ if ((asi == ASI_SWVR_UDB_INTR_W && !write) ||
+ (asi == ASI_SWVR_UDB_INTR_R && write)) {
writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
return new DataAccessException;
}
writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
return new PrivilegedAction;
}
- if (!hpriv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) {
+ if ((!hpriv && vaddr & 0xF) || vaddr > 0x3f8 || vaddr < 0x3c0) {
writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
return new DataAccessException;
}
return NoFault;
};
+#if FULL_SYSTEM
+
Tick
DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
{
DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n",
(uint32_t)pkt->req->getAsi(), pkt->getAddr());
- ITB * itb = tc->getITBPtr();
+ ITB *itb = tc->getITBPtr();
switch (asi) {
case ASI_LSU_CONTROL_REG:
itb->cx_config));
break;
case ASI_SWVR_INTR_RECEIVE:
- pkt->set(tc->getCpuPtr()->get_interrupts(IT_INT_VEC));
+ {
+ SparcISA::Interrupts * interrupts =
+ dynamic_cast<SparcISA::Interrupts *>(
+ tc->getCpuPtr()->getInterruptController());
+ pkt->set(interrupts->get_vec(IT_INT_VEC));
+ }
break;
case ASI_SWVR_UDB_INTR_R:
- temp = findMsbSet(tc->getCpuPtr()->get_interrupts(IT_INT_VEC));
- tc->getCpuPtr()->clear_interrupt(IT_INT_VEC, temp);
- pkt->set(temp);
+ {
+ SparcISA::Interrupts * interrupts =
+ dynamic_cast<SparcISA::Interrupts *>(
+ tc->getCpuPtr()->getInterruptController());
+ temp = findMsbSet(interrupts->get_vec(IT_INT_VEC));
+ tc->getCpuPtr()->clearInterrupt(IT_INT_VEC, temp);
+ pkt->set(temp);
+ }
break;
default:
doMmuReadError:
(uint32_t)asi, va);
}
pkt->makeAtomicResponse();
- return tc->getCpuPtr()->cycles(1);
+ return tc->getCpuPtr()->ticks(1);
}
Tick
DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n",
(uint32_t)asi, va, data);
- ITB * itb = tc->getITBPtr();
+ ITB *itb = tc->getITBPtr();
switch (asi) {
case ASI_LSU_CONTROL_REG:
real_insert = bits(va, 9,9);
pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
PageTableEntry::sun4u);
- insert(va_insert, part_insert, ct_insert, real_insert, pte, entry_insert);
+ insert(va_insert, part_insert, ct_insert, real_insert, pte,
+ entry_insert);
break;
case ASI_IMMU_DEMAP:
ignore = false;
}
break;
case ASI_SWVR_INTR_RECEIVE:
- int msb;
- // clear all the interrupts that aren't set in the write
- while(tc->getCpuPtr()->get_interrupts(IT_INT_VEC) & data) {
- msb = findMsbSet(tc->getCpuPtr()->get_interrupts(IT_INT_VEC) & data);
- tc->getCpuPtr()->clear_interrupt(IT_INT_VEC, msb);
+ {
+ int msb;
+ // clear all the interrupts that aren't set in the write
+ SparcISA::Interrupts * interrupts =
+ dynamic_cast<SparcISA::Interrupts *>(
+ tc->getCpuPtr()->getInterruptController());
+ while (interrupts->get_vec(IT_INT_VEC) & data) {
+ msb = findMsbSet(interrupts->get_vec(IT_INT_VEC) & data);
+ tc->getCpuPtr()->clearInterrupt(IT_INT_VEC, msb);
+ }
}
break;
case ASI_SWVR_UDB_INTR_W:
tc->getSystemPtr()->threadContexts[bits(data,12,8)]->getCpuPtr()->
- post_interrupt(bits(data,5,0),0);
+ postInterrupt(bits(data, 5, 0), 0);
break;
- default:
+ default:
doMmuWriteError:
panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n",
(uint32_t)pkt->req->getAsi(), pkt->getAddr(), data);
}
pkt->makeAtomicResponse();
- return tc->getCpuPtr()->cycles(1);
+ return tc->getCpuPtr()->ticks(1);
}
+#endif
+
void
DTB::GetTsbPtr(ThreadContext *tc, Addr addr, int ctx, Addr *ptrs)
{
itb->cx_config);
}
-
-
-
-
uint64_t
DTB::MakeTsbPtr(TsbPageSize ps, uint64_t tag_access, uint64_t c0_tsb,
uint64_t c0_config, uint64_t cX_tsb, uint64_t cX_config)
return ptr;
}
-
void
TLB::serialize(std::ostream &os)
{
SERIALIZE_SCALAR(cntr);
SERIALIZE_ARRAY(free_list, cntr);
- for (int x = 0; x < size; x++) {
- nameOut(os, csprintf("%s.PTE%d", name(), x));
- tlb[x].serialize(os);
- }
-
SERIALIZE_SCALAR(c0_tsb_ps0);
SERIALIZE_SCALAR(c0_tsb_ps1);
SERIALIZE_SCALAR(c0_config);
SERIALIZE_SCALAR(cx_config);
SERIALIZE_SCALAR(sfsr);
SERIALIZE_SCALAR(tag_access);
+
+ for (int x = 0; x < size; x++) {
+ nameOut(os, csprintf("%s.PTE%d", name(), x));
+ tlb[x].serialize(os);
+ }
}
void
for (int x = 0; x < cntr; x++)
freeList.push_back(&tlb[free_list[x]]);
- lookupTable.clear();
- for (int x = 0; x < size; x++) {
- tlb[x].unserialize(cp, csprintf("%s.PTE%d", section, x));
- if (tlb[x].valid)
- lookupTable.insert(tlb[x].range, &tlb[x]);
-
- }
-
UNSERIALIZE_SCALAR(c0_tsb_ps0);
UNSERIALIZE_SCALAR(c0_tsb_ps1);
UNSERIALIZE_SCALAR(c0_config);
UNSERIALIZE_SCALAR(cx_config);
UNSERIALIZE_SCALAR(sfsr);
UNSERIALIZE_SCALAR(tag_access);
+
+ lookupTable.clear();
+ for (int x = 0; x < size; x++) {
+ tlb[x].unserialize(cp, csprintf("%s.PTE%d", section, x));
+ if (tlb[x].valid)
+ lookupTable.insert(tlb[x].range, &tlb[x]);
+
+ }
}
void
SparcISA::ITB *
SparcITBParams::create()
{
- return new SparcISA::ITB(name, size);
+ return new SparcISA::ITB(this);
}
SparcISA::DTB *
SparcDTBParams::create()
{
- return new SparcISA::DTB(name, size);
+ return new SparcISA::DTB(this);
}