ARM: Implement the ARM TLB/Tablewalker. Needs performance improvements.
This commit is contained in:
@@ -1,8 +1,17 @@
|
||||
# -*- mode:python -*-
|
||||
|
||||
# Copyright (c) 2007-2008 The Florida State University
|
||||
# Copyright (c) 2009 ARM Limited
|
||||
# All rights reserved.
|
||||
#
|
||||
# The license below extends only to copyright in the software and shall
|
||||
# not be construed as granting a license to any other intellectual
|
||||
# property including but not limited to intellectual property relating
|
||||
# to a hardware implementation of the functionality of the software
|
||||
# licensed hereunder. You may use the software subject to the license
|
||||
# terms below provided that you ensure that this notice is replicated
|
||||
# unmodified and in its entirety in all distributions of the software,
|
||||
# modified or unmodified, in source code or in binary form.
|
||||
#
|
||||
# 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
|
||||
@@ -26,12 +35,28 @@
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Authors: Stephen Hines
|
||||
# Authors: Ali Saidi
|
||||
|
||||
from m5.defines import buildEnv
|
||||
from m5.SimObject import SimObject
|
||||
from m5.params import *
|
||||
from m5.proxy import *
|
||||
|
||||
if buildEnv['FULL_SYSTEM']:
|
||||
from MemObject import MemObject
|
||||
|
||||
class ArmTableWalker(MemObject):
|
||||
type = 'ArmTableWalker'
|
||||
cxx_class = 'ArmISA::TableWalker'
|
||||
port = Port("Port for TableWalker to do walk the translation with")
|
||||
sys = Param.System(Parent.any, "system object parameter")
|
||||
min_backoff = Param.Tick(0, "Minimum backoff delay after failed send")
|
||||
max_backoff = Param.Tick(100000, "Minimum backoff delay after failed send")
|
||||
|
||||
|
||||
class ArmTLB(SimObject):
|
||||
type = 'ArmTLB'
|
||||
cxx_class = 'ArmISA::TLB'
|
||||
size = Param.Int(64, "TLB size")
|
||||
if buildEnv['FULL_SYSTEM']:
|
||||
walker = Param.ArmTableWalker(ArmTableWalker(), "HW Table walker")
|
||||
|
||||
@@ -65,12 +65,14 @@ if env['TARGET_ISA'] == 'arm':
|
||||
SimObject('ArmTLB.py')
|
||||
|
||||
TraceFlag('Arm')
|
||||
TraceFlag('TLBVerbose')
|
||||
TraceFlag('Faults', "Trace Exceptions, interrupts, svc/swi")
|
||||
TraceFlag('Predecoder', "Instructions returned by the predecoder")
|
||||
if env['FULL_SYSTEM']:
|
||||
Source('interrupts.cc')
|
||||
Source('stacktrace.cc')
|
||||
Source('system.cc')
|
||||
Source('table_walker.cc')
|
||||
|
||||
SimObject('ArmInterrupts.py')
|
||||
SimObject('ArmSystem.py')
|
||||
|
||||
@@ -75,16 +75,17 @@ class ArmFault : public FaultBase
|
||||
Translation1 = 0x7,
|
||||
SynchronousExternalAbort0 = 0x8,
|
||||
Domain0 = 0x9,
|
||||
SynchronousExternalAbort1 = 0xa,
|
||||
Domain1 = 0xb,
|
||||
TranslationTableWalk0 = 0xc,
|
||||
TranslationTableWalkExtAbt0 = 0xc,
|
||||
Permission0 = 0xd,
|
||||
SynchronousExternalAbort1 = 0xe,
|
||||
TranslationTableWalkExtAbt1 = 0xe,
|
||||
Permission1 = 0xf,
|
||||
AsynchronousExternalAbort = 0x16,
|
||||
MemoryAccessAsynchronousParityError = 0x18,
|
||||
MemoryAccessSynchronousParityError = 0x19,
|
||||
TranslationTableWalk1 = 0x1c,
|
||||
SynchronousParityError = 0x1e
|
||||
TranslationTableWalkPrtyErr0 = 0x1c,
|
||||
TranslationTableWalkPrtyErr1 = 0x1e,
|
||||
};
|
||||
|
||||
struct FaultVals
|
||||
@@ -208,7 +209,7 @@ class DataAbort : public AbortFault<DataAbort>
|
||||
static const MiscRegIndex FsrIndex = MISCREG_DFSR;
|
||||
static const MiscRegIndex FarIndex = MISCREG_DFAR;
|
||||
|
||||
DataAbort(Addr _addr, bool _write, uint8_t _domain, uint8_t _status) :
|
||||
DataAbort(Addr _addr, uint8_t _domain, bool _write, uint8_t _status) :
|
||||
AbortFault<DataAbort>(_addr, _write, _domain, _status)
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -41,9 +41,10 @@
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_ARM_ISA_HH__
|
||||
#define __ARCH_MRM_ISA_HH__
|
||||
#define __ARCH_ARM_ISA_HH__
|
||||
|
||||
#include "arch/arm/registers.hh"
|
||||
#include "arch/arm/tlb.hh"
|
||||
#include "arch/arm/types.hh"
|
||||
|
||||
class ThreadContext;
|
||||
@@ -223,6 +224,8 @@ namespace ArmISA
|
||||
warn("The ccsidr register isn't implemented and "
|
||||
"always reads as 0.\n");
|
||||
break;
|
||||
case MISCREG_ID_PFR0:
|
||||
return 0x1031; // ThumbEE | !Jazelle | Thumb | ARM
|
||||
}
|
||||
return readMiscRegNoEffect(misc_reg);
|
||||
}
|
||||
@@ -347,6 +350,52 @@ namespace ArmISA
|
||||
case MISCREG_MPIDR:
|
||||
case MISCREG_FPSID:
|
||||
return;
|
||||
case MISCREG_TLBIALLIS:
|
||||
case MISCREG_TLBIALL:
|
||||
warn("Need to flush all TLBs in MP\n");
|
||||
tc->getITBPtr()->flushAll();
|
||||
tc->getDTBPtr()->flushAll();
|
||||
return;
|
||||
case MISCREG_ITLBIALL:
|
||||
tc->getITBPtr()->flushAll();
|
||||
return;
|
||||
case MISCREG_DTLBIALL:
|
||||
tc->getDTBPtr()->flushAll();
|
||||
return;
|
||||
case MISCREG_TLBIMVAIS:
|
||||
case MISCREG_TLBIMVA:
|
||||
warn("Need to flush all TLBs in MP\n");
|
||||
tc->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
|
||||
bits(newVal, 7,0));
|
||||
tc->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
|
||||
bits(newVal, 7,0));
|
||||
return;
|
||||
case MISCREG_TLBIASIDIS:
|
||||
case MISCREG_TLBIASID:
|
||||
warn("Need to flush all TLBs in MP\n");
|
||||
tc->getITBPtr()->flushAsid(bits(newVal, 7,0));
|
||||
tc->getDTBPtr()->flushAsid(bits(newVal, 7,0));
|
||||
return;
|
||||
case MISCREG_TLBIMVAAIS:
|
||||
case MISCREG_TLBIMVAA:
|
||||
warn("Need to flush all TLBs in MP\n");
|
||||
tc->getITBPtr()->flushMva(mbits(newVal, 31,12));
|
||||
tc->getDTBPtr()->flushMva(mbits(newVal, 31,12));
|
||||
return;
|
||||
case MISCREG_ITLBIMVA:
|
||||
tc->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
|
||||
bits(newVal, 7,0));
|
||||
return;
|
||||
case MISCREG_DTLBIMVA:
|
||||
tc->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
|
||||
bits(newVal, 7,0));
|
||||
return;
|
||||
case MISCREG_ITLBIASID:
|
||||
tc->getITBPtr()->flushAsid(bits(newVal, 7,0));
|
||||
return;
|
||||
case MISCREG_DTLBIASID:
|
||||
tc->getDTBPtr()->flushAsid(bits(newVal, 7,0));
|
||||
return;
|
||||
}
|
||||
setMiscRegNoEffect(misc_reg, newVal);
|
||||
}
|
||||
|
||||
@@ -138,47 +138,25 @@ let {{
|
||||
return new WarnUnimplemented(
|
||||
isRead ? "mrc bpiall" : "mcr bpiall", machInst);
|
||||
case MISCREG_TLBIALLIS:
|
||||
return new WarnUnimplemented(
|
||||
isRead ? "mrc tlbiallis" : "mcr tlbiallis", machInst);
|
||||
case MISCREG_TLBIMVAIS:
|
||||
return new WarnUnimplemented(
|
||||
isRead ? "mrc tlbimvais" : "mcr tlbimvais", machInst);
|
||||
case MISCREG_TLBIASIDIS:
|
||||
return new WarnUnimplemented(
|
||||
isRead ? "mrc tlbiasidis" : "mcr tlbiasidis", machInst);
|
||||
case MISCREG_TLBIMVAAIS:
|
||||
return new WarnUnimplemented(
|
||||
isRead ? "mrc tlbimvaais" : "mcr tlbimvaais", machInst);
|
||||
case MISCREG_ITLBIALL:
|
||||
return new WarnUnimplemented(
|
||||
isRead ? "mrc itlbiall" : "mcr itlbiall", machInst);
|
||||
case MISCREG_ITLBIMVA:
|
||||
return new WarnUnimplemented(
|
||||
isRead ? "mrc itlbimva" : "mcr itlbimva", machInst);
|
||||
case MISCREG_ITLBIASID:
|
||||
return new WarnUnimplemented(
|
||||
isRead ? "mrc itlbiasid" : "mcr itlbiasid", machInst);
|
||||
case MISCREG_DTLBIALL:
|
||||
return new WarnUnimplemented(
|
||||
isRead ? "mrc dtlbiall" : "mcr dtlbiall", machInst);
|
||||
case MISCREG_DTLBIMVA:
|
||||
return new WarnUnimplemented(
|
||||
isRead ? "mrc dtlbimva" : "mcr dtlbimva", machInst);
|
||||
case MISCREG_DTLBIASID:
|
||||
return new WarnUnimplemented(
|
||||
isRead ? "mrc dtlbiasid" : "mcr dtlbiasid", machInst);
|
||||
case MISCREG_TLBIALL:
|
||||
return new WarnUnimplemented(
|
||||
isRead ? "mrc tlbiall" : "mcr tlbiall", machInst);
|
||||
case MISCREG_TLBIMVA:
|
||||
return new WarnUnimplemented(
|
||||
isRead ? "mrc tlbimva" : "mcr tlbimva", machInst);
|
||||
case MISCREG_TLBIASID:
|
||||
return new WarnUnimplemented(
|
||||
isRead ? "mrc tlbiasid" : "mcr tlbiasid", machInst);
|
||||
case MISCREG_TLBIMVAA:
|
||||
return new WarnUnimplemented(
|
||||
isRead ? "mrc tlbimvaa" : "mcr tlbimvaa", machInst);
|
||||
if (isRead) {
|
||||
return new Unknown(machInst);
|
||||
} else {
|
||||
return new Mcr15(machInst, (IntRegIndex)miscReg, rt);
|
||||
}
|
||||
|
||||
default:
|
||||
if (isRead) {
|
||||
return new Mrc15(machInst, rt, (IntRegIndex)miscReg);
|
||||
|
||||
@@ -93,6 +93,9 @@ let {{
|
||||
eaCode += ";"
|
||||
|
||||
memFlags = ["ArmISA::TLB::MustBeOne", "%d" % (size - 1)]
|
||||
if user:
|
||||
memFlags.append("ArmISA::TLB::UserMode")
|
||||
|
||||
if prefetch:
|
||||
Name = "%s_%s" % (mnem.upper(), Name)
|
||||
memFlags.append("Request::PREFETCH")
|
||||
@@ -179,6 +182,9 @@ let {{
|
||||
eaCode += ";"
|
||||
|
||||
memFlags = ["%d" % (size - 1), "ArmISA::TLB::MustBeOne"]
|
||||
if user:
|
||||
memFlags.append("ArmISA::TLB::UserMode")
|
||||
|
||||
if prefetch:
|
||||
Name = "%s_%s" % (mnem.upper(), Name)
|
||||
memFlags.append("Request::PREFETCH")
|
||||
|
||||
@@ -107,6 +107,9 @@ let {{
|
||||
accCode += "Base = Base %s;\n" % offset
|
||||
|
||||
memFlags = ["ArmISA::TLB::MustBeOne", "%d" % (size - 1)]
|
||||
if user:
|
||||
memFlags.append("ArmISA::TLB::UserMode")
|
||||
|
||||
if strex:
|
||||
memFlags.append("Request::LLSC")
|
||||
Name = "%s_%s" % (mnem.upper(), Name)
|
||||
@@ -184,10 +187,14 @@ let {{
|
||||
accCode += "Base = Base %s;\n" % offset
|
||||
base = buildMemBase("MemoryReg", post, writeback)
|
||||
|
||||
emitStore(name, Name, False, eaCode, accCode, "",\
|
||||
["ArmISA::TLB::MustBeOne", \
|
||||
memFlags = ["ArmISA::TLB::MustBeOne", \
|
||||
"ArmISA::TLB::AllowUnaligned", \
|
||||
"%d" % (size - 1)], [], base)
|
||||
"%d" % (size - 1)]
|
||||
if user:
|
||||
memFlags.append("ArmISA::TLB::UserMode")
|
||||
|
||||
emitStore(name, Name, False, eaCode, accCode, "",\
|
||||
memFlags, [], base)
|
||||
|
||||
def buildDoubleImmStore(mnem, post, add, writeback, \
|
||||
strex=False, vstr=False):
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
*/
|
||||
|
||||
#include "arch/arm/miscregs.hh"
|
||||
#include "base/misc.hh"
|
||||
|
||||
namespace ArmISA
|
||||
{
|
||||
@@ -424,6 +425,8 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2)
|
||||
// Implementation defined
|
||||
break;
|
||||
}
|
||||
warn("Unknown miscreg: CRn: %d Opc1: %d CRm: %d opc2: %d\n",
|
||||
crn, opc1, crm, opc2);
|
||||
// Unrecognized register
|
||||
return NUM_MISCREGS;
|
||||
}
|
||||
|
||||
@@ -130,10 +130,13 @@ namespace ArmISA
|
||||
MISCREG_DFAR,
|
||||
MISCREG_IFAR,
|
||||
MISCREG_MPIDR,
|
||||
MISCREG_PRRR,
|
||||
MISCREG_NMRR,
|
||||
MISCREG_TTBCR,
|
||||
MISCREG_ID_PFR0,
|
||||
MISCREG_CP15_UNIMP_START,
|
||||
MISCREG_CTR = MISCREG_CP15_UNIMP_START,
|
||||
MISCREG_TCMTR,
|
||||
MISCREG_ID_PFR0,
|
||||
MISCREG_ID_PFR1,
|
||||
MISCREG_ID_DFR0,
|
||||
MISCREG_ID_AFR0,
|
||||
@@ -159,7 +162,6 @@ namespace ArmISA
|
||||
MISCREG_SCR,
|
||||
MISCREG_SDER,
|
||||
MISCREG_NSACR,
|
||||
MISCREG_TTBCR,
|
||||
MISCREG_V2PCWPR,
|
||||
MISCREG_V2PCWPW,
|
||||
MISCREG_V2PCWUR,
|
||||
@@ -168,8 +170,6 @@ namespace ArmISA
|
||||
MISCREG_V2POWPW,
|
||||
MISCREG_V2POWUR,
|
||||
MISCREG_V2POWUW,
|
||||
MISCREG_PRRR,
|
||||
MISCREG_NMRR,
|
||||
MISCREG_VBAR,
|
||||
MISCREG_MVBAR,
|
||||
MISCREG_ISR,
|
||||
@@ -205,18 +205,20 @@ namespace ArmISA
|
||||
"dtlbiall", "dtlbimva", "dtlbiasid",
|
||||
"tlbiall", "tlbimva", "tlbiasid", "tlbimvaa",
|
||||
"dfsr", "ifsr", "dfar", "ifar", "mpidr",
|
||||
"prrr", "nmrr", "ttbcr", "id_pfr0",
|
||||
// Unimplemented below
|
||||
"ctr", "tcmtr",
|
||||
"id_pfr0", "id_pfr1", "id_dfr0", "id_afr0",
|
||||
"id_pfr1", "id_dfr0", "id_afr0",
|
||||
"id_mmfr0", "id_mmfr1", "id_mmfr2", "id_mmfr3",
|
||||
"id_isar0", "id_isar1", "id_isar2", "id_isar3", "id_isar4", "id_isar5",
|
||||
"par", "aidr", "actlr",
|
||||
"adfsr", "aifsr",
|
||||
"dcimvac", "dcisw", "mccsw",
|
||||
"dccmvau",
|
||||
"scr", "sder", "nsacr", "ttbcr",
|
||||
"scr", "sder", "nsacr",
|
||||
"v2pcwpr", "v2pcwpw", "v2pcwur", "v2pcwuw",
|
||||
"v2powpr", "v2powpw", "v2powur", "v2powuw",
|
||||
"prrr", "nmrr", "vbar", "mvbar", "isr", "fceidr",
|
||||
"vbar", "mvbar", "isr", "fceidr",
|
||||
"nop", "raz"
|
||||
};
|
||||
|
||||
@@ -343,6 +345,49 @@ namespace ArmISA
|
||||
Bitfield<27, 24> vfpHalfPrecision;
|
||||
Bitfield<31, 28> raz;
|
||||
EndBitUnion(MVFR1)
|
||||
|
||||
BitUnion32(PRRR)
|
||||
Bitfield<1,0> tr0;
|
||||
Bitfield<3,2> tr1;
|
||||
Bitfield<5,4> tr2;
|
||||
Bitfield<7,6> tr3;
|
||||
Bitfield<9,8> tr4;
|
||||
Bitfield<11,10> tr5;
|
||||
Bitfield<13,12> tr6;
|
||||
Bitfield<15,14> tr7;
|
||||
Bitfield<16> ds0;
|
||||
Bitfield<17> ds1;
|
||||
Bitfield<18> ns0;
|
||||
Bitfield<19> ns1;
|
||||
Bitfield<24> nos0;
|
||||
Bitfield<25> nos1;
|
||||
Bitfield<26> nos2;
|
||||
Bitfield<27> nos3;
|
||||
Bitfield<28> nos4;
|
||||
Bitfield<29> nos5;
|
||||
Bitfield<30> nos6;
|
||||
Bitfield<31> nos7;
|
||||
EndBitUnion(PRRR)
|
||||
|
||||
BitUnion32(NMRR)
|
||||
Bitfield<1,0> ir0;
|
||||
Bitfield<3,2> ir1;
|
||||
Bitfield<5,4> ir2;
|
||||
Bitfield<7,6> ir3;
|
||||
Bitfield<9,8> ir4;
|
||||
Bitfield<11,10> ir5;
|
||||
Bitfield<13,12> ir6;
|
||||
Bitfield<15,14> ir7;
|
||||
Bitfield<17,16> or0;
|
||||
Bitfield<19,18> or1;
|
||||
Bitfield<21,20> or2;
|
||||
Bitfield<23,22> or3;
|
||||
Bitfield<25,24> or4;
|
||||
Bitfield<27,26> or5;
|
||||
Bitfield<29,28> or6;
|
||||
Bitfield<31,30> or7;
|
||||
EndBitUnion(NMRR)
|
||||
|
||||
};
|
||||
|
||||
#endif // __ARCH_ARM_MISCREGS_HH__
|
||||
|
||||
@@ -37,9 +37,7 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors: Nathan Binkert
|
||||
* Steve Reinhardt
|
||||
* Ali Saidi
|
||||
* Authors: Ali Saidi
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_ARM_PAGETABLE_H__
|
||||
@@ -73,22 +71,91 @@ struct PTE
|
||||
|
||||
};
|
||||
|
||||
struct TlbRange
|
||||
{
|
||||
Addr va;
|
||||
Addr size;
|
||||
int contextId;
|
||||
bool global;
|
||||
|
||||
inline bool
|
||||
operator<(const TlbRange &r2) const
|
||||
{
|
||||
if (!(global || r2.global)) {
|
||||
if (contextId < r2.contextId)
|
||||
return true;
|
||||
else if (contextId > r2.contextId)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (va < r2.va)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator==(const TlbRange &r2) const
|
||||
{
|
||||
return va == r2.va &&
|
||||
size == r2.size &&
|
||||
contextId == r2.contextId &&
|
||||
global == r2.global;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// ITB/DTB table entry
|
||||
struct TlbEntry
|
||||
{
|
||||
Addr tag; // virtual page number tag
|
||||
Addr ppn; // physical page number
|
||||
uint8_t asn; // address space number
|
||||
bool valid; // valid page table entry
|
||||
public:
|
||||
enum MemoryType {
|
||||
StronglyOrdered,
|
||||
Device,
|
||||
Normal
|
||||
};
|
||||
enum DomainType {
|
||||
DomainNoAccess = 0,
|
||||
DomainClient,
|
||||
DomainReserved,
|
||||
DomainManager
|
||||
};
|
||||
|
||||
// Matching variables
|
||||
Addr pfn;
|
||||
Addr size; // Size of this entry, == Type of TLB Rec
|
||||
Addr vpn; // Virtual Page Number
|
||||
uint32_t asid; // Address Space Identifier
|
||||
uint8_t N; // Number of bits in pagesize
|
||||
bool global;
|
||||
bool valid;
|
||||
|
||||
//Construct an entry that maps to physical address addr.
|
||||
// Type of memory
|
||||
bool nonCacheable; // Can we wrap this in mtype?
|
||||
bool sNp; // Section descriptor
|
||||
|
||||
// Access permissions
|
||||
bool xn; // Execute Never
|
||||
uint8_t ap:3; // Access permissions bits
|
||||
uint8_t domain:4; // Access Domain
|
||||
|
||||
TlbRange range; // For fast TLB searching
|
||||
|
||||
//Construct an entry that maps to physical address addr for SE mode
|
||||
TlbEntry(Addr _asn, Addr _vaddr, Addr _paddr)
|
||||
{
|
||||
tag = _vaddr >> PageShift;
|
||||
ppn = _paddr >> PageShift;
|
||||
asn = _asn;
|
||||
pfn = _paddr >> PageShift;
|
||||
size = PageBytes - 1;
|
||||
asid = _asn;
|
||||
global = false;
|
||||
valid = true;
|
||||
|
||||
vpn = _vaddr >> PageShift;
|
||||
|
||||
nonCacheable = sNp = false;
|
||||
|
||||
xn = 0;
|
||||
ap = 0; // ???
|
||||
domain = DomainClient; //???
|
||||
}
|
||||
|
||||
TlbEntry()
|
||||
@@ -97,13 +164,28 @@ struct TlbEntry
|
||||
void
|
||||
updateVaddr(Addr new_vaddr)
|
||||
{
|
||||
tag = new_vaddr >> PageShift;
|
||||
vpn = new_vaddr >> PageShift;
|
||||
}
|
||||
|
||||
Addr
|
||||
pageStart()
|
||||
{
|
||||
return ppn << PageShift;
|
||||
return pfn << PageShift;
|
||||
}
|
||||
|
||||
bool
|
||||
match(Addr va, uint8_t cid)
|
||||
{
|
||||
Addr v = vpn << N;
|
||||
if (valid && va >= v && va <= v + size && (global || cid == asid))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
Addr
|
||||
pAddr(Addr va)
|
||||
{
|
||||
return (pfn << N) | (va & size);
|
||||
}
|
||||
|
||||
void serialize(std::ostream &os) { panic("Need to Implement\n"); }
|
||||
|
||||
323
src/arch/arm/table_walker.cc
Normal file
323
src/arch/arm/table_walker.cc
Normal file
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Copyright (c) 2010 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Authors: Ali Saidi
|
||||
*/
|
||||
|
||||
#include "arch/arm/faults.hh"
|
||||
#include "arch/arm/table_walker.hh"
|
||||
#include "arch/arm/tlb.hh"
|
||||
#include "dev/io_device.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
|
||||
|
||||
using namespace ArmISA;
|
||||
|
||||
TableWalker::TableWalker(const Params *p)
|
||||
: MemObject(p), port(NULL), tlb(NULL), tc(NULL), req(NULL),
|
||||
doL1DescEvent(this), doL2DescEvent(this)
|
||||
{}
|
||||
|
||||
TableWalker::~TableWalker()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
drain(Event *de)
|
||||
{
|
||||
panic("Not implemented\n");
|
||||
}
|
||||
|
||||
Port*
|
||||
TableWalker::getPort(const std::string &if_name, int idx)
|
||||
{
|
||||
if (if_name == "port") {
|
||||
if (port != NULL)
|
||||
fatal("%s: port already connected to %s",
|
||||
name(), port->getPeer()->name());
|
||||
System *sys = params()->sys;
|
||||
Tick minb = params()->min_backoff;
|
||||
Tick maxb = params()->max_backoff;
|
||||
port = new DmaPort(this, sys, minb, maxb);
|
||||
return port;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Fault
|
||||
TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode mode,
|
||||
TLB::Translation *_trans, bool _timing)
|
||||
{
|
||||
// Right now 1 CPU == 1 TLB == 1 TLB walker
|
||||
// In the future we might want to change this as multiple
|
||||
// threads/contexts could share a walker and/or a TLB
|
||||
if (tc || req)
|
||||
panic("Overlapping TLB walks attempted\n");
|
||||
|
||||
tc = _tc;
|
||||
transState = _trans;
|
||||
req = _req;
|
||||
fault = NoFault;
|
||||
contextId = _cid;
|
||||
timing = _timing;
|
||||
|
||||
// XXX These should be cached or grabbed from cached copies in
|
||||
// the TLB, all these miscreg reads are expensive
|
||||
vaddr = req->getVaddr() & ~PcModeMask;
|
||||
sctlr = tc->readMiscReg(MISCREG_SCTLR);
|
||||
cpsr = tc->readMiscReg(MISCREG_CPSR);
|
||||
N = tc->readMiscReg(MISCREG_TTBCR);
|
||||
Addr ttbr = 0;
|
||||
|
||||
isFetch = (mode == TLB::Execute);
|
||||
isWrite = (mode == TLB::Write);
|
||||
isPriv = (cpsr.mode != MODE_USER);
|
||||
|
||||
// If translation isn't enabled, we shouldn't be here
|
||||
assert(sctlr.m);
|
||||
|
||||
if (N == 0 || mbits(vaddr, 31, 32-N)) {
|
||||
ttbr = tc->readMiscReg(MISCREG_TTBR0);
|
||||
} else {
|
||||
ttbr = tc->readMiscReg(MISCREG_TTBR0);
|
||||
N = 0;
|
||||
}
|
||||
|
||||
Addr l1desc_addr = mbits(ttbr, 31, 14-N) | (bits(vaddr,31-N,20) << 2);
|
||||
DPRINTF(TLB, "Begining table walk for address %#x at descriptor %#x\n",
|
||||
vaddr, l1desc_addr);
|
||||
|
||||
|
||||
// Trickbox address check
|
||||
fault = tlb->walkTrickBoxCheck(l1desc_addr, vaddr, sizeof(uint32_t),
|
||||
isFetch, 0, true);
|
||||
if (fault) {
|
||||
tc = NULL;
|
||||
req = NULL;
|
||||
return fault;
|
||||
}
|
||||
|
||||
if (timing) {
|
||||
port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
|
||||
&doL1DescEvent, (uint8_t*)&l1Desc.data, (Tick)0);
|
||||
} else {
|
||||
port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
|
||||
NULL, (uint8_t*)&l1Desc.data, (Tick)0);
|
||||
doL1Descriptor();
|
||||
}
|
||||
|
||||
return fault;
|
||||
}
|
||||
|
||||
void
|
||||
TableWalker::memAttrs(TlbEntry &te, uint8_t texcb)
|
||||
{
|
||||
|
||||
if (sctlr.tre == 0) {
|
||||
switch(texcb) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 4:
|
||||
case 8:
|
||||
te.nonCacheable = true;
|
||||
break;
|
||||
case 16:
|
||||
if (bits(texcb, 1,0) == 0 || bits(texcb, 3,2) == 0)
|
||||
te.nonCacheable = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
PRRR prrr = tc->readMiscReg(MISCREG_PRRR);
|
||||
NMRR nmrr = tc->readMiscReg(MISCREG_NMRR);
|
||||
switch(bits(texcb, 2,0)) {
|
||||
case 0:
|
||||
if (nmrr.ir0 == 0 || nmrr.or0 == 0 || prrr.tr0 != 0x2)
|
||||
te.nonCacheable = true;
|
||||
break;
|
||||
case 1:
|
||||
if (nmrr.ir1 == 0 || nmrr.or1 == 0 || prrr.tr1 != 0x2)
|
||||
te.nonCacheable = true;
|
||||
break;
|
||||
case 2:
|
||||
if (nmrr.ir2 == 0 || nmrr.or2 == 0 || prrr.tr2 != 0x2)
|
||||
te.nonCacheable = true;
|
||||
break;
|
||||
case 3:
|
||||
if (nmrr.ir3 == 0 || nmrr.or3 == 0 || prrr.tr3 != 0x2)
|
||||
te.nonCacheable = true;
|
||||
break;
|
||||
case 4:
|
||||
if (nmrr.ir4 == 0 || nmrr.or4 == 0 || prrr.tr4 != 0x2)
|
||||
te.nonCacheable = true;
|
||||
break;
|
||||
case 5:
|
||||
if (nmrr.ir5 == 0 || nmrr.or5 == 0 || prrr.tr5 != 0x2)
|
||||
te.nonCacheable = true;
|
||||
break;
|
||||
case 6:
|
||||
panic("Imp defined type\n");
|
||||
case 7:
|
||||
if (nmrr.ir7 == 0 || nmrr.or7 == 0 || prrr.tr7 != 0x2)
|
||||
te.nonCacheable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TableWalker::doL1Descriptor()
|
||||
{
|
||||
DPRINTF(TLB, "L1 descriptor for %#x is %#x\n", vaddr, l1Desc.data);
|
||||
TlbEntry te;
|
||||
|
||||
switch (l1Desc.type()) {
|
||||
case L1Descriptor::Ignore:
|
||||
case L1Descriptor::Reserved:
|
||||
tc = NULL;
|
||||
req = NULL;
|
||||
fault = new DataAbort(vaddr, NULL, isWrite, ArmFault::Translation0);
|
||||
return;
|
||||
case L1Descriptor::Section:
|
||||
if (sctlr.afe && bits(l1Desc.ap(), 0) == 0)
|
||||
panic("Haven't implemented AFE\n");
|
||||
|
||||
if (l1Desc.supersection()) {
|
||||
panic("Haven't implemented supersections\n");
|
||||
}
|
||||
te.N = 20;
|
||||
te.pfn = l1Desc.pfn();
|
||||
te.size = (1<<te.N) - 1;
|
||||
te.global = !l1Desc.global();
|
||||
te.valid = true;
|
||||
te.vpn = vaddr >> te.N;
|
||||
te.sNp = true;
|
||||
te.xn = l1Desc.xn();
|
||||
te.ap = l1Desc.ap();
|
||||
te.domain = l1Desc.domain();
|
||||
te.asid = contextId;
|
||||
memAttrs(te, l1Desc.texcb());
|
||||
|
||||
DPRINTF(TLB, "Inserting Section Descriptor into TLB\n");
|
||||
DPRINTF(TLB, " - N%d pfn:%#x size: %#x global:%d valid: %d\n",
|
||||
te.N, te.pfn, te.size, te.global, te.valid);
|
||||
DPRINTF(TLB, " - vpn:%#x sNp: %d xn:%d ap:%d domain: %d asid:%d\n",
|
||||
te.vpn, te.sNp, te.xn, te.ap, te.domain, te.asid);
|
||||
DPRINTF(TLB, " - domain from l1 desc: %d data: %#x bits:%d\n",
|
||||
l1Desc.domain(), l1Desc.data, (l1Desc.data >> 5) & 0xF );
|
||||
|
||||
tc = NULL;
|
||||
req = NULL;
|
||||
tlb->insert(vaddr, te);
|
||||
|
||||
return;
|
||||
case L1Descriptor::PageTable:
|
||||
Addr l2desc_addr;
|
||||
l2desc_addr = l1Desc.l2Addr() | (bits(vaddr, 19,12) << 2);
|
||||
DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n", l2desc_addr);
|
||||
|
||||
// Trickbox address check
|
||||
fault = tlb->walkTrickBoxCheck(l2desc_addr, vaddr, sizeof(uint32_t),
|
||||
isFetch, l1Desc.domain(), false);
|
||||
if (fault) {
|
||||
tc = NULL;
|
||||
req = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (timing) {
|
||||
port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
|
||||
&doL2DescEvent, (uint8_t*)&l2Desc.data, 0);
|
||||
} else {
|
||||
port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
|
||||
NULL, (uint8_t*)&l2Desc.data, 0);
|
||||
doL2Descriptor();
|
||||
}
|
||||
return;
|
||||
default:
|
||||
panic("A new type in a 2 bit field?\n");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TableWalker::doL2Descriptor()
|
||||
{
|
||||
DPRINTF(TLB, "L2 descriptor for %#x is %#x\n", vaddr, l2Desc.data);
|
||||
TlbEntry te;
|
||||
|
||||
if (sctlr.afe && bits(l1Desc.ap(), 0) == 0)
|
||||
panic("Haven't implemented AFE\n");
|
||||
|
||||
if (l2Desc.invalid()) {
|
||||
DPRINTF(TLB, "L2 descriptor invalid, causing fault\n");
|
||||
tc = NULL;
|
||||
req = NULL;
|
||||
fault = new DataAbort(vaddr, l1Desc.domain(), isWrite, ArmFault::Translation1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (l2Desc.large()) {
|
||||
te.N = 16;
|
||||
te.pfn = l2Desc.pfn();
|
||||
} else {
|
||||
te.N = 12;
|
||||
te.pfn = l2Desc.pfn();
|
||||
}
|
||||
|
||||
te.valid = true;
|
||||
te.size = (1 << te.N) - 1;
|
||||
te.asid = contextId;
|
||||
te.sNp = false;
|
||||
te.vpn = vaddr >> te.N;
|
||||
te.global = l2Desc.global();
|
||||
te.xn = l2Desc.xn();
|
||||
te.ap = l2Desc.ap();
|
||||
te.domain = l1Desc.domain();
|
||||
memAttrs(te, l2Desc.texcb());
|
||||
|
||||
tc = NULL;
|
||||
req = NULL;
|
||||
tlb->insert(vaddr, te);
|
||||
}
|
||||
|
||||
ArmISA::TableWalker *
|
||||
ArmTableWalkerParams::create()
|
||||
{
|
||||
return new ArmISA::TableWalker(this);
|
||||
}
|
||||
|
||||
272
src/arch/arm/table_walker.hh
Normal file
272
src/arch/arm/table_walker.hh
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (c) 2010 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
* not be construed as granting a license to any other intellectual
|
||||
* property including but not limited to intellectual property relating
|
||||
* to a hardware implementation of the functionality of the software
|
||||
* licensed hereunder. You may use the software subject to the license
|
||||
* terms below provided that you ensure that this notice is replicated
|
||||
* unmodified and in its entirety in all distributions of the software,
|
||||
* modified or unmodified, in source code or in binary form.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Authors: Ali Saidi
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_ARM_TABLE_WALKER_HH__
|
||||
#define __ARCH_ARM_TABLE_WALKER_HH__
|
||||
|
||||
#include "arch/arm/miscregs.hh"
|
||||
#include "arch/arm/tlb.hh"
|
||||
#include "mem/mem_object.hh"
|
||||
#include "mem/request.hh"
|
||||
#include "mem/request.hh"
|
||||
#include "params/ArmTableWalker.hh"
|
||||
#include "sim/faults.hh"
|
||||
#include "sim/eventq.hh"
|
||||
|
||||
class DmaPort;
|
||||
class ThreadContext;
|
||||
|
||||
namespace ArmISA {
|
||||
class Translation;
|
||||
class TLB;
|
||||
|
||||
class TableWalker : public MemObject
|
||||
{
|
||||
protected:
|
||||
struct L1Descriptor {
|
||||
/** Type of page table entry ARM DDI 0406B: B3-8*/
|
||||
enum EntryType {
|
||||
Ignore,
|
||||
PageTable,
|
||||
Section,
|
||||
Reserved
|
||||
};
|
||||
|
||||
uint32_t data;
|
||||
|
||||
EntryType type() const
|
||||
{
|
||||
return (EntryType)(data & 0x3);
|
||||
}
|
||||
|
||||
/** Is the page a Supersection (16MB)?*/
|
||||
bool supersection() const
|
||||
{
|
||||
return bits(data, 18);
|
||||
}
|
||||
|
||||
/** Return the physcal address of the entry, bits in position*/
|
||||
Addr paddr() const
|
||||
{
|
||||
if (supersection())
|
||||
panic("Super sections not implemented\n");
|
||||
return mbits(data, 31,20);
|
||||
}
|
||||
|
||||
/** Return the physical frame, bits shifted right */
|
||||
Addr pfn() const
|
||||
{
|
||||
if (supersection())
|
||||
panic("Super sections not implemented\n");
|
||||
return bits(data, 31,20);
|
||||
}
|
||||
|
||||
/** Is the translation global (no asid used)? */
|
||||
bool global() const
|
||||
{
|
||||
return bits(data, 17);
|
||||
}
|
||||
|
||||
/** Is the translation not allow execution? */
|
||||
bool xn() const
|
||||
{
|
||||
return bits(data, 17);
|
||||
}
|
||||
|
||||
/** Three bit access protection flags */
|
||||
uint8_t ap() const
|
||||
{
|
||||
return (bits(data, 15) << 2) | bits(data,11,10);
|
||||
}
|
||||
|
||||
/** Domain Client/Manager: ARM DDI 0406B: B3-31 */
|
||||
uint8_t domain() const
|
||||
{
|
||||
return bits(data,8,5);
|
||||
}
|
||||
|
||||
/** Address of L2 descriptor if it exists */
|
||||
Addr l2Addr() const
|
||||
{
|
||||
return mbits(data, 31,10);
|
||||
}
|
||||
|
||||
/** Memory region attributes: ARM DDI 0406B: B3-32 */
|
||||
uint8_t texcb() const
|
||||
{
|
||||
return bits(data, 2) | bits(data,3) << 1 | bits(data, 12, 14) << 2;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/** Level 2 page table descriptor */
|
||||
struct L2Descriptor {
|
||||
|
||||
uint32_t data;
|
||||
|
||||
/** Is the entry invalid */
|
||||
bool invalid() const
|
||||
{
|
||||
return bits(data, 1,0) == 0;;
|
||||
}
|
||||
|
||||
/** What is the size of the mapping? */
|
||||
bool large() const
|
||||
{
|
||||
return bits(data, 1) == 0;
|
||||
}
|
||||
|
||||
/** Is execution allowed on this mapping? */
|
||||
bool xn() const
|
||||
{
|
||||
return large() ? bits(data, 15) : bits(data, 0);
|
||||
}
|
||||
|
||||
/** Is the translation global (no asid used)? */
|
||||
bool global() const
|
||||
{
|
||||
return !bits(data, 11);
|
||||
}
|
||||
|
||||
/** Three bit access protection flags */
|
||||
uint8_t ap() const
|
||||
{
|
||||
return bits(data, 5, 4) | (bits(data, 9) << 2);
|
||||
}
|
||||
|
||||
/** Memory region attributes: ARM DDI 0406B: B3-32 */
|
||||
uint8_t texcb() const
|
||||
{
|
||||
return large() ?
|
||||
(bits(data, 2) | (bits(data,3) << 1) | (bits(data, 12, 14) << 2)) :
|
||||
(bits(data, 2) | (bits(data,3) << 1) | (bits(data, 6, 8) << 2));
|
||||
}
|
||||
|
||||
/** Return the physical frame, bits shifted right */
|
||||
Addr pfn() const
|
||||
{
|
||||
return large() ? bits(data, 31, 16) : bits(data, 31, 12);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/** Port to issue translation requests from */
|
||||
DmaPort *port;
|
||||
|
||||
/** TLB that is initiating these table walks */
|
||||
TLB *tlb;
|
||||
|
||||
/** Thread context that we're doing the walk for */
|
||||
ThreadContext *tc;
|
||||
|
||||
/** Request that is currently being serviced */
|
||||
RequestPtr req;
|
||||
|
||||
/** Context ID that we're servicing the request under */
|
||||
uint8_t contextId;
|
||||
|
||||
/** Translation state for delayed requests */
|
||||
TLB::Translation *transState;
|
||||
|
||||
/** The fault that we are going to return */
|
||||
Fault fault;
|
||||
|
||||
/** The virtual address that is being translated */
|
||||
Addr vaddr;
|
||||
|
||||
/** Cached copy of the sctlr as it existed when translation began */
|
||||
SCTLR sctlr;
|
||||
|
||||
/** Cached copy of the cpsr as it existed when the translation began */
|
||||
CPSR cpsr;
|
||||
|
||||
/** Width of the base address held in TTRB0 */
|
||||
uint32_t N;
|
||||
|
||||
/** If the access is a write */
|
||||
bool isWrite;
|
||||
|
||||
/** If the access is not from user mode */
|
||||
bool isPriv;
|
||||
|
||||
/** If the access is a fetch (for execution, and no-exec) must be checked?*/
|
||||
bool isFetch;
|
||||
|
||||
/** If the mode is timing or atomic */
|
||||
bool timing;
|
||||
|
||||
L1Descriptor l1Desc;
|
||||
L2Descriptor l2Desc;
|
||||
|
||||
public:
|
||||
typedef ArmTableWalkerParams Params;
|
||||
TableWalker(const Params *p);
|
||||
virtual ~TableWalker();
|
||||
|
||||
const Params *
|
||||
params() const
|
||||
{
|
||||
return dynamic_cast<const Params *>(_params);
|
||||
}
|
||||
|
||||
virtual unsigned int drain(Event *de) { panic("write me\n"); }
|
||||
virtual Port *getPort(const std::string &if_name, int idx = -1);
|
||||
|
||||
Fault walk(RequestPtr req, ThreadContext *tc, uint8_t cid, TLB::Mode mode,
|
||||
TLB::Translation *_trans, bool timing);
|
||||
|
||||
void setTlb(TLB *_tlb) { tlb = _tlb; }
|
||||
|
||||
private:
|
||||
void memAttrs(TlbEntry &te, uint8_t texcb);
|
||||
|
||||
void doL1Descriptor();
|
||||
EventWrapper<TableWalker, &TableWalker::doL1Descriptor> doL1DescEvent;
|
||||
|
||||
void doL2Descriptor();
|
||||
EventWrapper<TableWalker, &TableWalker::doL2Descriptor> doL2DescEvent;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace ArmISA
|
||||
|
||||
#endif //__ARCH_ARM_TABLE_WALKER_HH__
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
|
||||
#include "arch/arm/faults.hh"
|
||||
#include "arch/arm/pagetable.hh"
|
||||
#include "arch/arm/table_walker.hh"
|
||||
#include "arch/arm/tlb.hh"
|
||||
#include "arch/arm/utility.hh"
|
||||
#include "base/inifile.hh"
|
||||
@@ -57,16 +58,19 @@
|
||||
#include "params/ArmTLB.hh"
|
||||
#include "sim/process.hh"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace ArmISA;
|
||||
|
||||
TLB::TLB(const Params *p)
|
||||
: BaseTLB(p), size(p->size), nlu(0)
|
||||
#if FULL_SYSTEM
|
||||
, tableWalker(p->walker)
|
||||
#endif
|
||||
{
|
||||
table = new ArmISA::PTE[size];
|
||||
memset(table, 0, sizeof(ArmISA::PTE[size]));
|
||||
table = new TlbEntry[size];
|
||||
memset(table, 0, sizeof(TlbEntry[size]));
|
||||
|
||||
tableWalker->setTlb(this);
|
||||
}
|
||||
|
||||
TLB::~TLB()
|
||||
@@ -75,50 +79,157 @@ TLB::~TLB()
|
||||
delete [] table;
|
||||
}
|
||||
|
||||
ArmISA::PTE *
|
||||
TLB::lookup(Addr vpn, uint8_t asn) const
|
||||
TlbEntry*
|
||||
TLB::lookup(Addr va, uint8_t cid)
|
||||
{
|
||||
panic("lookup() not implemented for ARM\n");
|
||||
// XXX This should either turn into a TlbMap or add caching
|
||||
|
||||
TlbEntry *retval = NULL;
|
||||
|
||||
// Do some kind of caching, fast indexing, anything
|
||||
|
||||
int x = 0;
|
||||
while (retval == NULL && x < size) {
|
||||
if (table[x].match(va, cid)) {
|
||||
retval = &table[x];
|
||||
if (x == nlu)
|
||||
nextnlu();
|
||||
|
||||
break;
|
||||
}
|
||||
x++;
|
||||
}
|
||||
|
||||
DPRINTF(TLBVerbose, "Lookup %#x, cid %#x -> %s ppn %#x size: %#x pa: %#x ap:%d\n",
|
||||
va, cid, retval ? "hit" : "miss", retval ? retval->pfn : 0,
|
||||
retval ? retval->size : 0, retval ? retval->pAddr(va) : 0,
|
||||
retval ? retval->ap : 0);
|
||||
;
|
||||
return retval;
|
||||
}
|
||||
|
||||
// insert a new TLB entry
|
||||
void
|
||||
TLB::insert(Addr addr, ArmISA::PTE &pte)
|
||||
TLB::insert(Addr addr, TlbEntry &entry)
|
||||
{
|
||||
fatal("TLB Insert not yet implemented\n");
|
||||
DPRINTF(TLB, "Inserting entry into TLB with pfn:%#x size:%#x vpn: %#x"
|
||||
" asid:%d N:%d global:%d valid:%d nc:%d sNp:%d xn:%d ap:%#x"
|
||||
" domain:%#x\n", entry.pfn, entry.size, entry.vpn, entry.asid,
|
||||
entry.N, entry.global, entry.valid, entry.nonCacheable, entry.sNp,
|
||||
entry.xn, entry.ap, entry.domain);
|
||||
|
||||
if (table[nlu].valid)
|
||||
DPRINTF(TLB, " - Replacing Valid entry %#x, asn %d ppn %#x size: %#x ap:%d\n",
|
||||
table[nlu].vpn << table[nlu].N, table[nlu].asid, table[nlu].pfn << table[nlu].N,
|
||||
table[nlu].size, table[nlu].ap);
|
||||
|
||||
// XXX Update caching, lookup table etc
|
||||
table[nlu] = entry;
|
||||
|
||||
// XXX Figure out how entries are generally inserted in ARM
|
||||
nextnlu();
|
||||
}
|
||||
|
||||
void
|
||||
TLB::printTlb()
|
||||
{
|
||||
int x = 0;
|
||||
TlbEntry *te;
|
||||
DPRINTF(TLB, "Current TLB contents:\n");
|
||||
while (x < size) {
|
||||
te = &table[x];
|
||||
if (te->valid)
|
||||
DPRINTF(TLB, " * %#x, asn %d ppn %#x size: %#x ap:%d\n",
|
||||
te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TLB::flushAll()
|
||||
{
|
||||
DPRINTF(TLB, "flushAll\n");
|
||||
memset(table, 0, sizeof(ArmISA::PTE[size]));
|
||||
lookupTable.clear();
|
||||
DPRINTF(TLB, "Flushing all TLB entries\n");
|
||||
int x = 0;
|
||||
TlbEntry *te;
|
||||
while (x < size) {
|
||||
te = &table[x];
|
||||
if (te->valid)
|
||||
DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
|
||||
te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
|
||||
x++;
|
||||
}
|
||||
|
||||
memset(table, 0, sizeof(TlbEntry[size]));
|
||||
nlu = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TLB::flushMvaAsid(Addr mva, uint64_t asn)
|
||||
{
|
||||
DPRINTF(TLB, "Flushing mva %#x asid: %#x\n", mva, asn);
|
||||
TlbEntry *te;
|
||||
|
||||
te = lookup(mva, asn);
|
||||
while (te != NULL) {
|
||||
DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
|
||||
te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
|
||||
te->valid = false;
|
||||
te = lookup(mva,asn);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TLB::flushAsid(uint64_t asn)
|
||||
{
|
||||
DPRINTF(TLB, "Flushing all entries with asid: %#x\n", asn);
|
||||
|
||||
int x = 0;
|
||||
TlbEntry *te;
|
||||
|
||||
while (x < size) {
|
||||
te = &table[x];
|
||||
if (te->asid == asn) {
|
||||
te->valid = false;
|
||||
DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
|
||||
te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
|
||||
}
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TLB::flushMva(Addr mva)
|
||||
{
|
||||
DPRINTF(TLB, "Flushing all entries with mva: %#x\n", mva);
|
||||
|
||||
int x = 0;
|
||||
TlbEntry *te;
|
||||
|
||||
while (x < size) {
|
||||
te = &table[x];
|
||||
Addr v = te->vpn << te->N;
|
||||
if (mva >= v && mva < v + te->size) {
|
||||
te->valid = false;
|
||||
DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
|
||||
te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
|
||||
}
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TLB::serialize(ostream &os)
|
||||
{
|
||||
SERIALIZE_SCALAR(size);
|
||||
SERIALIZE_SCALAR(nlu);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
nameOut(os, csprintf("%s.PTE%d", name(), i));
|
||||
table[i].serialize(os);
|
||||
}
|
||||
panic("Implement Serialize\n");
|
||||
}
|
||||
|
||||
void
|
||||
TLB::unserialize(Checkpoint *cp, const string §ion)
|
||||
{
|
||||
UNSERIALIZE_SCALAR(size);
|
||||
UNSERIALIZE_SCALAR(nlu);
|
||||
|
||||
panic("Need to properly unserialize TLB\n");
|
||||
for (int i = 0; i < size; i++) {
|
||||
table[i].unserialize(cp, csprintf("%s.PTE%d", section, i));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -182,50 +293,227 @@ TLB::regStats()
|
||||
}
|
||||
|
||||
Fault
|
||||
TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode)
|
||||
TLB::trickBoxCheck(RequestPtr req, Mode mode, uint8_t domain, bool sNp)
|
||||
{
|
||||
return NoFault;
|
||||
}
|
||||
|
||||
Fault
|
||||
TLB::walkTrickBoxCheck(Addr pa, Addr va, Addr sz, bool is_exec,
|
||||
uint8_t domain, bool sNp)
|
||||
{
|
||||
return NoFault;
|
||||
}
|
||||
|
||||
#if !FULL_SYSTEM
|
||||
Fault
|
||||
TLB::translateSe(RequestPtr req, ThreadContext *tc, Mode mode,
|
||||
Translation *translation, bool &delay, bool timing)
|
||||
{
|
||||
// XXX Cache misc registers and have miscreg write function inv cache
|
||||
Addr vaddr = req->getVaddr() & ~PcModeMask;
|
||||
SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR);
|
||||
uint32_t flags = req->getFlags();
|
||||
|
||||
if (mode != Execute) {
|
||||
assert(flags & MustBeOne);
|
||||
bool is_fetch = (mode == Execute);
|
||||
bool is_write = (mode == Write);
|
||||
|
||||
if (sctlr.a || (flags & AllowUnaligned) == 0) {
|
||||
if ((vaddr & flags & AlignmentMask) != 0) {
|
||||
return new DataAbort(vaddr, (mode == Write), 0,
|
||||
ArmFault::AlignmentFault);
|
||||
if (!is_fetch) {
|
||||
assert(flags & MustBeOne);
|
||||
if (sctlr.a || !(flags & AllowUnaligned)) {
|
||||
if (vaddr & flags & AlignmentMask) {
|
||||
return new DataAbort(vaddr, 0, is_write, ArmFault::AlignmentFault);
|
||||
}
|
||||
}
|
||||
}
|
||||
#if !FULL_SYSTEM
|
||||
Process * p = tc->getProcessPtr();
|
||||
|
||||
Addr paddr;
|
||||
Process *p = tc->getProcessPtr();
|
||||
|
||||
if (!p->pTable->translate(vaddr, paddr))
|
||||
return Fault(new GenericPageTableFault(vaddr));
|
||||
req->setPaddr(paddr);
|
||||
|
||||
return NoFault;
|
||||
#else
|
||||
if (!sctlr.m) {
|
||||
req->setPaddr(vaddr);
|
||||
return NoFault;
|
||||
}
|
||||
warn_once("MPU translation not implemented\n");
|
||||
req->setPaddr(vaddr);
|
||||
return NoFault;
|
||||
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
#else // FULL_SYSTEM
|
||||
|
||||
Fault
|
||||
TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
|
||||
Translation *translation, bool &delay, bool timing)
|
||||
{
|
||||
// XXX Cache misc registers and have miscreg write function inv cache
|
||||
Addr vaddr = req->getVaddr() & ~PcModeMask;
|
||||
SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR);
|
||||
CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
|
||||
uint32_t flags = req->getFlags();
|
||||
|
||||
bool is_fetch = (mode == Execute);
|
||||
bool is_write = (mode == Write);
|
||||
bool is_priv = (cpsr.mode != MODE_USER) && !(flags & UserMode);
|
||||
|
||||
DPRINTF(TLBVerbose, "CPSR is user:%d UserMode:%d\n", cpsr.mode == MODE_USER, flags
|
||||
& UserMode);
|
||||
if (!is_fetch) {
|
||||
assert(flags & MustBeOne);
|
||||
if (sctlr.a || !(flags & AllowUnaligned)) {
|
||||
if (vaddr & flags & AlignmentMask) {
|
||||
return new DataAbort(vaddr, 0, is_write, ArmFault::AlignmentFault);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t context_id = tc->readMiscReg(MISCREG_CONTEXTIDR);
|
||||
Fault fault;
|
||||
|
||||
|
||||
if (!sctlr.m) {
|
||||
req->setPaddr(vaddr);
|
||||
if (sctlr.tre == 0) {
|
||||
req->setFlags(Request::UNCACHEABLE);
|
||||
} else {
|
||||
PRRR prrr = tc->readMiscReg(MISCREG_PRRR);
|
||||
NMRR nmrr = tc->readMiscReg(MISCREG_NMRR);
|
||||
|
||||
if (nmrr.ir0 == 0 || nmrr.or0 == 0 || prrr.tr0 != 0x2)
|
||||
req->setFlags(Request::UNCACHEABLE);
|
||||
}
|
||||
return trickBoxCheck(req, mode, 0, false);
|
||||
}
|
||||
|
||||
DPRINTF(TLBVerbose, "Translating vaddr=%#x context=%d\n", vaddr, context_id);
|
||||
// Translation enabled
|
||||
|
||||
TlbEntry *te = lookup(vaddr, context_id);
|
||||
if (te == NULL) {
|
||||
// start translation table walk, pass variables rather than
|
||||
// re-retreaving in table walker for speed
|
||||
DPRINTF(TLB, "TLB Miss: Starting hardware table walker for %#x(%d)\n",
|
||||
vaddr, context_id);
|
||||
fault = tableWalker->walk(req, tc, context_id, mode, translation,
|
||||
timing);
|
||||
if (timing)
|
||||
delay = true;
|
||||
if (fault)
|
||||
return fault;
|
||||
|
||||
te = lookup(vaddr, context_id);
|
||||
if (!te)
|
||||
printTlb();
|
||||
assert(te);
|
||||
}
|
||||
|
||||
uint32_t dacr = tc->readMiscReg(MISCREG_DACR);
|
||||
switch ( (dacr >> (te->domain * 2)) & 0x3) {
|
||||
case 0:
|
||||
DPRINTF(TLB, "TLB Fault: Data abort on domain. DACR: %#x domain: %#x"
|
||||
" write:%d sNp:%d\n", dacr, te->domain, is_write, te->sNp);
|
||||
if (is_fetch)
|
||||
return new PrefetchAbort(vaddr,
|
||||
(te->sNp ? ArmFault::Domain0 : ArmFault::Domain1));
|
||||
else
|
||||
return new DataAbort(vaddr, te->domain, is_write,
|
||||
(te->sNp ? ArmFault::Domain0 : ArmFault::Domain1));
|
||||
case 1:
|
||||
// Continue with permissions check
|
||||
break;
|
||||
case 2:
|
||||
panic("UNPRED domain\n");
|
||||
case 3:
|
||||
req->setPaddr(te->pAddr(vaddr));
|
||||
fault = trickBoxCheck(req, mode, te->domain, te->sNp);
|
||||
if (fault)
|
||||
return fault;
|
||||
return NoFault;
|
||||
}
|
||||
|
||||
uint8_t ap = te->ap;
|
||||
|
||||
if (sctlr.afe == 1)
|
||||
ap |= 1;
|
||||
|
||||
bool abt;
|
||||
|
||||
switch (ap) {
|
||||
case 0:
|
||||
abt = true;
|
||||
break;
|
||||
case 1:
|
||||
abt = !is_priv;
|
||||
break;
|
||||
case 2:
|
||||
abt = !is_priv && is_write;
|
||||
break;
|
||||
case 3:
|
||||
abt = false;
|
||||
break;
|
||||
case 4:
|
||||
panic("UNPRED premissions\n");
|
||||
case 5:
|
||||
abt = !is_priv || is_write;
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
abt = is_write;
|
||||
break;
|
||||
default:
|
||||
panic("Unknown permissions\n");
|
||||
}
|
||||
if ((is_fetch) && (abt || te->xn)) {
|
||||
DPRINTF(TLB, "TLB Fault: Prefetch abort on permission check. AP:%d priv:%d"
|
||||
" write:%d sNp:%d\n", ap, is_priv, is_write, te->sNp);
|
||||
return new PrefetchAbort(vaddr,
|
||||
(te->sNp ? ArmFault::Permission0 :
|
||||
ArmFault::Permission1));
|
||||
} else if (abt) {
|
||||
DPRINTF(TLB, "TLB Fault: Data abort on permission check. AP:%d priv:%d"
|
||||
" write:%d sNp:%d\n", ap, is_priv, is_write, te->sNp);
|
||||
return new DataAbort(vaddr, te->domain, is_write,
|
||||
(te->sNp ? ArmFault::Permission0 :
|
||||
ArmFault::Permission1));
|
||||
}
|
||||
|
||||
req->setPaddr(te->pAddr(vaddr));
|
||||
// Check for a trickbox generated address fault
|
||||
fault = trickBoxCheck(req, mode, te->domain, te->sNp);
|
||||
if (fault)
|
||||
return fault;
|
||||
|
||||
return NoFault;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Fault
|
||||
TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode)
|
||||
{
|
||||
bool delay = false;
|
||||
Fault fault;
|
||||
#if FULL_SYSTEM
|
||||
fault = translateFs(req, tc, mode, NULL, delay, false);
|
||||
#else
|
||||
fault = translateSe(req, tc, mode, NULL, delay, false);
|
||||
#endif
|
||||
assert(!delay);
|
||||
return fault;
|
||||
}
|
||||
|
||||
Fault
|
||||
TLB::translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation, Mode mode)
|
||||
{
|
||||
assert(translation);
|
||||
translation->finish(translateAtomic(req, tc, mode), req, tc, mode);
|
||||
bool delay = false;
|
||||
Fault fault;
|
||||
#if FULL_SYSTEM
|
||||
fault = translateFs(req, tc, mode, translation, delay, true);
|
||||
#else
|
||||
fault = translateSe(req, tc, mode, translation, delay, true);
|
||||
#endif
|
||||
if (!delay)
|
||||
translation->finish(fault, req, tc, mode);
|
||||
return fault;
|
||||
}
|
||||
|
||||
ArmISA::TLB *
|
||||
|
||||
@@ -59,6 +59,8 @@ class ThreadContext;
|
||||
|
||||
namespace ArmISA {
|
||||
|
||||
class TableWalker;
|
||||
|
||||
class TLB : public BaseTLB
|
||||
{
|
||||
public:
|
||||
@@ -71,21 +73,24 @@ class TLB : public BaseTLB
|
||||
AlignDoubleWord = 0x7,
|
||||
|
||||
AllowUnaligned = 0x8,
|
||||
// Priv code operating as if it wasn't
|
||||
UserMode = 0x10,
|
||||
// Because zero otherwise looks like a valid setting and may be used
|
||||
// accidentally, this bit must be non-zero to show it was used on
|
||||
// purpose.
|
||||
MustBeOne = 0x10
|
||||
MustBeOne = 0x20
|
||||
};
|
||||
protected:
|
||||
typedef std::multimap<Addr, int> PageTable;
|
||||
PageTable lookupTable; // Quick lookup into page table
|
||||
|
||||
ArmISA::PTE *table; // the Page Table
|
||||
TlbEntry *table; // the Page Table
|
||||
int size; // TLB Size
|
||||
int nlu; // not last used entry (for replacement)
|
||||
TableWalker *tableWalker;
|
||||
|
||||
void nextnlu() { if (++nlu >= size) nlu = 0; }
|
||||
ArmISA::PTE *lookup(Addr vpn, uint8_t asn) const;
|
||||
TlbEntry *lookup(Addr vpn, uint8_t asn);
|
||||
|
||||
// Access Stats
|
||||
mutable Stats::Scalar read_hits;
|
||||
@@ -101,6 +106,7 @@ class TLB : public BaseTLB
|
||||
Stats::Formula invalids;
|
||||
Stats::Formula accesses;
|
||||
|
||||
|
||||
public:
|
||||
typedef ArmTLBParams Params;
|
||||
TLB(const Params *p);
|
||||
@@ -108,17 +114,49 @@ class TLB : public BaseTLB
|
||||
virtual ~TLB();
|
||||
int getsize() const { return size; }
|
||||
|
||||
void insert(Addr vaddr, ArmISA::PTE &pte);
|
||||
void insert(Addr vaddr, TlbEntry &pte);
|
||||
|
||||
/** Reset the entire TLB */
|
||||
void flushAll();
|
||||
|
||||
/** Remove any entries that match both a va and asn
|
||||
* @param mva virtual address to flush
|
||||
* @param asn contextid/asn to flush on match
|
||||
*/
|
||||
void flushMvaAsid(Addr mva, uint64_t asn);
|
||||
|
||||
/** Remove any entries that match the asn
|
||||
* @param asn contextid/asn to flush on match
|
||||
*/
|
||||
void flushAsid(uint64_t asn);
|
||||
|
||||
/** Remove all entries that match the va regardless of asn
|
||||
* @param mva address to flush from cache
|
||||
*/
|
||||
void flushMva(Addr mva);
|
||||
|
||||
Fault trickBoxCheck(RequestPtr req, Mode mode, uint8_t domain, bool sNp);
|
||||
Fault walkTrickBoxCheck(Addr pa, Addr va, Addr sz, bool is_exec, uint8_t
|
||||
domain, bool sNp);
|
||||
|
||||
void printTlb();
|
||||
|
||||
void demapPage(Addr vaddr, uint64_t asn)
|
||||
{
|
||||
panic("demapPage unimplemented.\n");
|
||||
flushMvaAsid(vaddr, asn);
|
||||
}
|
||||
|
||||
static bool validVirtualAddress(Addr vaddr);
|
||||
|
||||
#if FULL_SYSTEM
|
||||
Fault translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
|
||||
Translation *translation, bool &delay, bool timing);
|
||||
#else
|
||||
Fault translateSe(RequestPtr req, ThreadContext *tc, Mode mode,
|
||||
Translation *translation, bool &delay, bool timing);
|
||||
#endif
|
||||
Fault translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode);
|
||||
void translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Fault translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation, Mode mode);
|
||||
|
||||
// Checkpointing
|
||||
|
||||
@@ -114,7 +114,6 @@ class BaseCPU(MemObject):
|
||||
interrupts = Param.MipsInterrupts(
|
||||
MipsInterrupts(), "Interrupt Controller")
|
||||
elif buildEnv['TARGET_ISA'] == 'arm':
|
||||
UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?")
|
||||
dtb = Param.ArmTLB(ArmTLB(), "Data TLB")
|
||||
itb = Param.ArmTLB(ArmTLB(), "Instruction TLB")
|
||||
if buildEnv['FULL_SYSTEM']:
|
||||
@@ -158,6 +157,10 @@ class BaseCPU(MemObject):
|
||||
"interrupts.pio",
|
||||
"interrupts.int_port"]
|
||||
|
||||
if buildEnv['TARGET_ISA'] == 'arm' and buildEnv['FULL_SYSTEM']:
|
||||
_mem_ports = ["itb.walker.port",
|
||||
"dtb.walker.port"]
|
||||
|
||||
def connectMemPorts(self, bus):
|
||||
for p in self._mem_ports:
|
||||
if p != 'physmem_port':
|
||||
@@ -170,8 +173,9 @@ class BaseCPU(MemObject):
|
||||
self.icache_port = ic.cpu_side
|
||||
self.dcache_port = dc.cpu_side
|
||||
self._mem_ports = ['icache.mem_side', 'dcache.mem_side']
|
||||
if buildEnv['TARGET_ISA'] == 'x86' and buildEnv['FULL_SYSTEM']:
|
||||
self._mem_ports += ["itb.walker_port", "dtb.walker_port"]
|
||||
if buildEnv['FULL_SYSTEM']:
|
||||
if buildEnv['TARGET_ISA'] in ['x86', 'arm']:
|
||||
self._mem_ports += ["itb.walker.port", "dtb.walker.port"]
|
||||
|
||||
def addTwoLevelCacheHierarchy(self, ic, dc, l2c):
|
||||
self.addPrivateSplitL1Caches(ic, dc)
|
||||
|
||||
Reference in New Issue
Block a user