2006-11-08 06:32:40 +01:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2001-2005 The Regents of The University of Michigan
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are
|
|
|
|
* met: redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer;
|
|
|
|
* redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution;
|
|
|
|
* neither the name of the copyright holders nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived from
|
|
|
|
* this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*
|
2006-11-23 07:42:57 +01:00
|
|
|
* Authors: Ali Saidi
|
2006-11-08 06:32:40 +01:00
|
|
|
*/
|
|
|
|
|
2006-11-23 07:42:57 +01:00
|
|
|
#include "arch/sparc/asi.hh"
|
2006-11-08 06:32:40 +01:00
|
|
|
#include "arch/sparc/tlb.hh"
|
|
|
|
#include "sim/builder.hh"
|
2006-11-23 07:42:57 +01:00
|
|
|
#include "arch/sparc/miscregfile.hh"
|
|
|
|
#include "cpu/thread_context.hh"
|
2006-11-08 06:32:40 +01:00
|
|
|
|
2006-11-23 07:42:57 +01:00
|
|
|
/* @todo remove some of the magic constants. -- ali
|
|
|
|
* */
|
2006-11-08 06:32:40 +01:00
|
|
|
namespace SparcISA
|
|
|
|
{
|
|
|
|
|
2006-11-23 07:42:57 +01:00
|
|
|
TLB::TLB(const std::string &name, int s)
|
|
|
|
: SimObject(name), size(s)
|
|
|
|
{
|
|
|
|
// 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.");
|
|
|
|
|
|
|
|
tlb = new TlbEntry[size];
|
|
|
|
memset(tlb, 0, sizeof(TlbEntry) * size);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TLB::clearUsedBits()
|
|
|
|
{
|
|
|
|
MapIter i;
|
|
|
|
for (i = lookupTable.begin(); i != lookupTable.end();) {
|
|
|
|
TlbEntry *t = i->second;
|
|
|
|
if (!t->pte.locked()) {
|
|
|
|
t->used = false;
|
|
|
|
usedEntries--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
TLB::insert(Addr va, int partition_id, int context_id, bool real,
|
|
|
|
const PageTableEntry& PTE)
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
MapIter i;
|
|
|
|
TlbEntry *new_entry;
|
|
|
|
int x = -1;
|
|
|
|
for (x = 0; x < size; x++) {
|
|
|
|
if (!tlb[x].valid || !tlb[x].used) {
|
|
|
|
new_entry = &tlb[x];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the last ently if their all locked
|
|
|
|
if (x == -1)
|
|
|
|
x = size - 1;
|
|
|
|
|
|
|
|
assert(PTE.valid());
|
|
|
|
new_entry->range.va = va;
|
|
|
|
new_entry->range.size = PTE.size();
|
|
|
|
new_entry->range.partitionId = partition_id;
|
|
|
|
new_entry->range.contextId = context_id;
|
|
|
|
new_entry->range.real = real;
|
|
|
|
new_entry->pte = PTE;
|
|
|
|
new_entry->used = true;;
|
|
|
|
new_entry->valid = true;
|
|
|
|
usedEntries++;
|
|
|
|
|
|
|
|
|
|
|
|
// Demap any entry that conflicts
|
|
|
|
i = lookupTable.find(new_entry->range);
|
|
|
|
if (i != lookupTable.end()) {
|
|
|
|
i->second->valid = false;
|
|
|
|
if (i->second->used) {
|
|
|
|
i->second->used = false;
|
|
|
|
usedEntries--;
|
|
|
|
}
|
|
|
|
lookupTable.erase(i);
|
|
|
|
}
|
2006-11-08 06:32:40 +01:00
|
|
|
|
2006-11-23 07:42:57 +01:00
|
|
|
lookupTable.insert(new_entry->range, new_entry);;
|
2006-11-08 06:32:40 +01:00
|
|
|
|
2006-11-23 07:42:57 +01:00
|
|
|
// If all entries have there used bit set, clear it on them all, but the
|
|
|
|
// one we just inserted
|
|
|
|
if (usedEntries == size) {
|
|
|
|
clearUsedBits();
|
|
|
|
new_entry->used = true;
|
|
|
|
usedEntries++;
|
|
|
|
}
|
2006-11-08 06:32:40 +01:00
|
|
|
|
2006-11-23 07:42:57 +01:00
|
|
|
}
|
2006-11-08 06:32:40 +01:00
|
|
|
|
|
|
|
|
2006-11-23 07:42:57 +01:00
|
|
|
TlbEntry*
|
|
|
|
TLB::lookup(Addr va, int partition_id, bool real, int context_id)
|
|
|
|
{
|
|
|
|
MapIter i;
|
|
|
|
TlbRange tr;
|
|
|
|
TlbEntry *t;
|
2006-11-08 06:32:40 +01:00
|
|
|
|
2006-11-23 07:42:57 +01:00
|
|
|
// Assemble full address structure
|
|
|
|
tr.va = va;
|
|
|
|
tr.size = va + MachineBytes;
|
|
|
|
tr.contextId = context_id;
|
|
|
|
tr.partitionId = partition_id;
|
|
|
|
tr.real = real;
|
2006-11-08 06:32:40 +01:00
|
|
|
|
2006-11-23 07:42:57 +01:00
|
|
|
// Try to find the entry
|
|
|
|
i = lookupTable.find(tr);
|
|
|
|
if (i == lookupTable.end()) {
|
|
|
|
return NULL;
|
2006-11-08 06:32:40 +01:00
|
|
|
}
|
|
|
|
|
2006-11-23 07:42:57 +01:00
|
|
|
// Mark the entries used bit and clear other used bits in needed
|
|
|
|
t = i->second;
|
|
|
|
if (!t->used) {
|
|
|
|
t->used = true;
|
|
|
|
usedEntries++;
|
|
|
|
if (usedEntries == size) {
|
|
|
|
clearUsedBits();
|
|
|
|
t->used = true;
|
|
|
|
usedEntries++;
|
|
|
|
}
|
|
|
|
}
|
2006-11-08 06:32:40 +01:00
|
|
|
|
2006-11-23 07:42:57 +01:00
|
|
|
return t;
|
|
|
|
}
|
2006-11-08 06:32:40 +01:00
|
|
|
|
|
|
|
|
2006-11-23 07:42:57 +01:00
|
|
|
void
|
|
|
|
TLB::demapPage(Addr va, int partition_id, bool real, int context_id)
|
|
|
|
{
|
|
|
|
TlbRange tr;
|
|
|
|
MapIter i;
|
|
|
|
|
|
|
|
// Assemble full address structure
|
|
|
|
tr.va = va;
|
|
|
|
tr.size = va + MachineBytes;
|
|
|
|
tr.contextId = context_id;
|
|
|
|
tr.partitionId = partition_id;
|
|
|
|
tr.real = real;
|
2006-11-08 06:32:40 +01:00
|
|
|
|
2006-11-23 07:42:57 +01:00
|
|
|
// Demap any entry that conflicts
|
|
|
|
i = lookupTable.find(tr);
|
|
|
|
if (i != lookupTable.end()) {
|
|
|
|
i->second->valid = false;
|
|
|
|
if (i->second->used) {
|
|
|
|
i->second->used = false;
|
|
|
|
usedEntries--;
|
|
|
|
}
|
|
|
|
lookupTable.erase(i);
|
|
|
|
}
|
|
|
|
}
|
2006-11-08 06:32:40 +01:00
|
|
|
|
2006-11-23 07:42:57 +01:00
|
|
|
void
|
|
|
|
TLB::demapContext(int partition_id, int context_id)
|
|
|
|
{
|
|
|
|
int x;
|
|
|
|
for (x = 0; x < size; x++) {
|
|
|
|
if (tlb[x].range.contextId == context_id &&
|
|
|
|
tlb[x].range.partitionId == partition_id) {
|
|
|
|
tlb[x].valid = false;
|
|
|
|
if (tlb[x].used) {
|
|
|
|
tlb[x].used = false;
|
|
|
|
usedEntries--;
|
|
|
|
}
|
|
|
|
lookupTable.erase(tlb[x].range);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-11-08 06:32:40 +01:00
|
|
|
|
2006-11-23 07:42:57 +01:00
|
|
|
void
|
|
|
|
TLB::demapAll(int partition_id)
|
|
|
|
{
|
|
|
|
int x;
|
|
|
|
for (x = 0; x < size; x++) {
|
|
|
|
if (!tlb[x].pte.locked() && tlb[x].range.partitionId == partition_id) {
|
|
|
|
tlb[x].valid = false;
|
|
|
|
if (tlb[x].used) {
|
|
|
|
tlb[x].used = false;
|
|
|
|
usedEntries--;
|
|
|
|
}
|
|
|
|
lookupTable.erase(tlb[x].range);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-11-08 06:32:40 +01:00
|
|
|
|
2006-11-23 07:42:57 +01:00
|
|
|
void
|
|
|
|
TLB::invalidateAll()
|
|
|
|
{
|
|
|
|
int x;
|
|
|
|
for (x = 0; x < size; x++) {
|
|
|
|
tlb[x].valid = false;
|
|
|
|
}
|
|
|
|
usedEntries = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t
|
|
|
|
TLB::TteRead(int entry) {
|
|
|
|
assert(entry < size);
|
|
|
|
return tlb[entry].pte();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t
|
|
|
|
TLB::TagRead(int entry) {
|
|
|
|
assert(entry < size);
|
|
|
|
uint64_t tag;
|
|
|
|
|
|
|
|
tag = tlb[entry].range.contextId | tlb[entry].range.va |
|
|
|
|
(uint64_t)tlb[entry].range.partitionId << 61;
|
|
|
|
tag |= tlb[entry].range.real ? ULL(1) << 60 : 0;
|
|
|
|
tag |= (uint64_t)~tlb[entry].pte._size() << 56;
|
|
|
|
return tag;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
TLB::validVirtualAddress(Addr va, bool am)
|
|
|
|
{
|
|
|
|
if (am)
|
|
|
|
return true;
|
|
|
|
if (va >= StartVAddrHole && va <= EndVAddrHole)
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TLB::writeSfsr(ThreadContext *tc, int reg, bool write, ContextType ct,
|
|
|
|
bool se, FaultTypes ft, int asi)
|
|
|
|
{
|
|
|
|
uint64_t sfsr;
|
|
|
|
sfsr = tc->readMiscReg(reg);
|
|
|
|
|
|
|
|
if (sfsr & 0x1)
|
|
|
|
sfsr = 0x3;
|
|
|
|
else
|
|
|
|
sfsr = 1;
|
|
|
|
|
|
|
|
if (write)
|
|
|
|
sfsr |= 1 << 2;
|
|
|
|
sfsr |= ct << 4;
|
|
|
|
if (se)
|
|
|
|
sfsr |= 1 << 6;
|
|
|
|
sfsr |= ft << 7;
|
|
|
|
sfsr |= asi << 16;
|
|
|
|
tc->setMiscReg(reg, sfsr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
ITB::writeSfsr(ThreadContext *tc, bool write, ContextType ct,
|
|
|
|
bool se, FaultTypes ft, int asi)
|
|
|
|
{
|
|
|
|
TLB::writeSfsr(tc, MISCREG_MMU_ITLB_SFSR, write, ct, se, ft, asi);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DTB::writeSfr(ThreadContext *tc, Addr a, bool write, ContextType ct,
|
|
|
|
bool se, FaultTypes ft, int asi)
|
|
|
|
{
|
|
|
|
TLB::writeSfsr(tc, MISCREG_MMU_DTLB_SFSR, write, ct, se, ft, asi);
|
|
|
|
tc->setMiscReg(MISCREG_MMU_DTLB_SFAR, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Fault
|
|
|
|
ITB::translate(RequestPtr &req, ThreadContext *tc)
|
|
|
|
{
|
|
|
|
uint64_t hpstate = tc->readMiscReg(MISCREG_HPSTATE);
|
|
|
|
uint64_t pstate = tc->readMiscReg(MISCREG_PSTATE);
|
|
|
|
bool lsuIm = tc->readMiscReg(MISCREG_MMU_LSU_CTRL) >> 2 & 0x1;
|
|
|
|
uint64_t tl = tc->readMiscReg(MISCREG_TL);
|
|
|
|
uint64_t part_id = tc->readMiscReg(MISCREG_MMU_PART_ID);
|
|
|
|
bool addr_mask = pstate >> 3 & 0x1;
|
|
|
|
bool priv = pstate >> 2 & 0x1;
|
|
|
|
Addr vaddr = req->getVaddr();
|
|
|
|
int context;
|
|
|
|
ContextType ct;
|
|
|
|
int asi;
|
|
|
|
bool real = false;
|
|
|
|
TlbEntry *e;
|
|
|
|
|
|
|
|
assert(req->getAsi() == ASI_IMPLICIT);
|
|
|
|
|
|
|
|
if (tl > 0) {
|
|
|
|
asi = ASI_N;
|
|
|
|
ct = Nucleus;
|
|
|
|
context = 0;
|
|
|
|
} else {
|
|
|
|
asi = ASI_P;
|
|
|
|
ct = Primary;
|
|
|
|
context = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( hpstate >> 2 & 0x1 || hpstate >> 5 & 0x1 ) {
|
|
|
|
req->setPaddr(req->getVaddr() & PAddrImplMask);
|
|
|
|
return NoFault;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the asi is unaligned trap
|
|
|
|
if (vaddr & 0x7) {
|
|
|
|
writeSfsr(tc, false, ct, false, OtherFault, asi);
|
|
|
|
return new MemAddressNotAligned;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addr_mask)
|
|
|
|
vaddr = vaddr & VAddrAMask;
|
|
|
|
|
|
|
|
if (!validVirtualAddress(vaddr, addr_mask)) {
|
|
|
|
writeSfsr(tc, false, ct, false, VaOutOfRange, asi);
|
|
|
|
return new InstructionAccessException;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lsuIm) {
|
|
|
|
e = lookup(req->getVaddr(), part_id, true);
|
|
|
|
real = true;
|
|
|
|
context = 0;
|
|
|
|
} else {
|
|
|
|
e = lookup(vaddr, part_id, false, context);
|
|
|
|
}
|
2006-11-08 06:32:40 +01:00
|
|
|
|
2006-11-23 07:42:57 +01:00
|
|
|
if (e == NULL || !e->valid) {
|
|
|
|
tc->setMiscReg(MISCREG_MMU_ITLB_TAG_ACCESS,
|
|
|
|
vaddr & ~BytesInPageMask | context);
|
|
|
|
if (real)
|
|
|
|
return new InstructionRealTranslationMiss;
|
|
|
|
else
|
|
|
|
return new FastInstructionAccessMMUMiss;
|
2006-11-08 06:32:40 +01:00
|
|
|
}
|
|
|
|
|
2006-11-23 07:42:57 +01:00
|
|
|
// were not priviledged accesing priv page
|
|
|
|
if (!priv && e->pte.priv()) {
|
|
|
|
writeSfsr(tc, false, ct, false, PrivViolation, asi);
|
|
|
|
return new InstructionAccessException;
|
|
|
|
}
|
|
|
|
|
|
|
|
req->setPaddr(e->pte.paddr() & ~e->pte.size() |
|
|
|
|
req->getVaddr() & e->pte.size());
|
|
|
|
return NoFault;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fault
|
|
|
|
DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
|
|
|
|
{
|
|
|
|
/* @todo this could really use some profiling and fixing to make it faster! */
|
|
|
|
uint64_t hpstate = tc->readMiscReg(MISCREG_HPSTATE);
|
|
|
|
uint64_t pstate = tc->readMiscReg(MISCREG_PSTATE);
|
|
|
|
bool lsuDm = tc->readMiscReg(MISCREG_MMU_LSU_CTRL) >> 3 & 0x1;
|
|
|
|
uint64_t tl = tc->readMiscReg(MISCREG_TL);
|
|
|
|
uint64_t part_id = tc->readMiscReg(MISCREG_MMU_PART_ID);
|
|
|
|
bool hpriv = hpstate >> 2 & 0x1;
|
|
|
|
bool red = hpstate >> 5 >> 0x1;
|
|
|
|
bool addr_mask = pstate >> 3 & 0x1;
|
|
|
|
bool priv = pstate >> 2 & 0x1;
|
|
|
|
bool implicit = false;
|
|
|
|
bool real = false;
|
|
|
|
Addr vaddr = req->getVaddr();
|
|
|
|
ContextType ct;
|
|
|
|
int context;
|
|
|
|
ASI asi;
|
|
|
|
|
|
|
|
TlbEntry *e;
|
|
|
|
|
|
|
|
|
|
|
|
asi = (ASI)req->getAsi();
|
|
|
|
if (asi == ASI_IMPLICIT)
|
|
|
|
implicit = true;
|
|
|
|
|
|
|
|
if (implicit) {
|
|
|
|
if (tl > 0) {
|
|
|
|
asi = ASI_N;
|
|
|
|
ct = Nucleus;
|
|
|
|
context = 0;
|
|
|
|
} else {
|
|
|
|
asi = ASI_P;
|
|
|
|
ct = Primary;
|
|
|
|
context = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
|
|
|
|
}
|
|
|
|
} else if (!hpriv && !red) {
|
|
|
|
if (tl > 0) {
|
|
|
|
ct = Nucleus;
|
|
|
|
context = 0;
|
|
|
|
} else if (AsiIsSecondary(asi)) {
|
|
|
|
ct = Secondary;
|
|
|
|
context = tc->readMiscReg(MISCREG_MMU_S_CONTEXT);
|
|
|
|
} else {
|
|
|
|
context = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
|
|
|
|
ct = Primary; //???
|
|
|
|
}
|
|
|
|
|
|
|
|
// We need to check for priv level/asi priv
|
|
|
|
if (!priv && !AsiIsUnPriv(asi)) {
|
|
|
|
// It appears that context should be Nucleus in these cases?
|
|
|
|
writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi);
|
|
|
|
return new PrivilegedAction;
|
|
|
|
}
|
|
|
|
if (priv && AsiIsHPriv(asi)) {
|
|
|
|
writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi);
|
|
|
|
return new DataAccessException;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the asi is unaligned trap
|
|
|
|
if (AsiIsBlock(asi) && vaddr & 0x3f || vaddr & 0x7) {
|
|
|
|
writeSfr(tc, vaddr, false, ct, false, OtherFault, asi);
|
|
|
|
return new MemAddressNotAligned;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addr_mask)
|
|
|
|
vaddr = vaddr & VAddrAMask;
|
|
|
|
|
|
|
|
if (!validVirtualAddress(vaddr, addr_mask)) {
|
|
|
|
writeSfr(tc, vaddr, false, ct, true, VaOutOfRange, asi);
|
|
|
|
return new DataAccessException;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!implicit) {
|
|
|
|
if (AsiIsLittle(asi))
|
|
|
|
panic("Little Endian ASIs not supported\n");
|
|
|
|
if (AsiIsBlock(asi))
|
|
|
|
panic("Block ASIs not supported\n");
|
|
|
|
if (AsiIsNoFault(asi))
|
|
|
|
panic("No Fault ASIs not supported\n");
|
|
|
|
if (AsiIsTwin(asi))
|
|
|
|
panic("Twin ASIs not supported\n");
|
|
|
|
if (AsiIsPartialStore(asi))
|
|
|
|
panic("Partial Store ASIs not supported\n");
|
|
|
|
if (AsiIsMmu(asi))
|
|
|
|
goto handleMmuRegAccess;
|
|
|
|
|
|
|
|
if (AsiIsScratchPad(asi))
|
|
|
|
goto handleScratchRegAccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((!lsuDm && !hpriv) || AsiIsReal(asi)) {
|
|
|
|
real = true;
|
|
|
|
context = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) {
|
|
|
|
req->setPaddr(req->getVaddr() & PAddrImplMask);
|
|
|
|
return NoFault;
|
|
|
|
}
|
|
|
|
|
|
|
|
e = lookup(req->getVaddr(), part_id, real, context);
|
|
|
|
|
|
|
|
if (e == NULL || !e->valid) {
|
|
|
|
tc->setMiscReg(MISCREG_MMU_DTLB_TAG_ACCESS,
|
|
|
|
vaddr & ~BytesInPageMask | context);
|
|
|
|
if (real)
|
|
|
|
return new DataRealTranslationMiss;
|
|
|
|
else
|
|
|
|
return new FastDataAccessMMUMiss;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (write && !e->pte.writable()) {
|
|
|
|
writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), OtherFault, asi);
|
|
|
|
return new FastDataAccessProtection;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e->pte.nofault() && !AsiIsNoFault(asi)) {
|
|
|
|
writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi);
|
|
|
|
return new DataAccessException;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e->pte.sideffect())
|
|
|
|
req->setFlags(req->getFlags() | UNCACHEABLE);
|
|
|
|
|
|
|
|
|
|
|
|
if (!priv && e->pte.priv()) {
|
|
|
|
writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi);
|
|
|
|
return new DataAccessException;
|
|
|
|
}
|
|
|
|
|
|
|
|
req->setPaddr(e->pte.paddr() & ~e->pte.size() |
|
|
|
|
req->getVaddr() & e->pte.size());
|
|
|
|
return NoFault;
|
|
|
|
/*** End of normal Path ***/
|
|
|
|
|
|
|
|
handleMmuRegAccess:
|
|
|
|
handleScratchRegAccess:
|
|
|
|
panic("How are we ever going to deal with this?\n");
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
TLB::serialize(std::ostream &os)
|
|
|
|
{
|
|
|
|
panic("Need to implement serialize tlb for SPARC\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TLB::unserialize(Checkpoint *cp, const std::string §ion)
|
|
|
|
{
|
|
|
|
panic("Need to implement unserialize tlb for SPARC\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DEFINE_SIM_OBJECT_CLASS_NAME("SparcTLB", TLB)
|
|
|
|
|
|
|
|
BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITB)
|
|
|
|
|
|
|
|
Param<int> size;
|
|
|
|
|
|
|
|
END_DECLARE_SIM_OBJECT_PARAMS(ITB)
|
|
|
|
|
|
|
|
BEGIN_INIT_SIM_OBJECT_PARAMS(ITB)
|
|
|
|
|
|
|
|
INIT_PARAM_DFLT(size, "TLB size", 48)
|
|
|
|
|
|
|
|
END_INIT_SIM_OBJECT_PARAMS(ITB)
|
|
|
|
|
|
|
|
|
|
|
|
CREATE_SIM_OBJECT(ITB)
|
|
|
|
{
|
|
|
|
return new ITB(getInstanceName(), size);
|
|
|
|
}
|
|
|
|
|
|
|
|
REGISTER_SIM_OBJECT("SparcITB", ITB)
|
|
|
|
|
|
|
|
BEGIN_DECLARE_SIM_OBJECT_PARAMS(DTB)
|
|
|
|
|
|
|
|
Param<int> size;
|
|
|
|
|
|
|
|
END_DECLARE_SIM_OBJECT_PARAMS(DTB)
|
|
|
|
|
|
|
|
BEGIN_INIT_SIM_OBJECT_PARAMS(DTB)
|
|
|
|
|
|
|
|
INIT_PARAM_DFLT(size, "TLB size", 64)
|
|
|
|
|
|
|
|
END_INIT_SIM_OBJECT_PARAMS(DTB)
|
|
|
|
|
|
|
|
|
|
|
|
CREATE_SIM_OBJECT(DTB)
|
|
|
|
{
|
|
|
|
return new DTB(getInstanceName(), size);
|
|
|
|
}
|
|
|
|
|
|
|
|
REGISTER_SIM_OBJECT("SparcDTB", DTB)
|
2006-11-08 06:32:40 +01:00
|
|
|
}
|