summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2007-08-07 15:31:36 -0700
committerGabe Black <gblack@eecs.umich.edu>2007-08-07 15:31:36 -0700
commit0fd999ca403f427ab5278bf69b005ed1ce851876 (patch)
tree71b8758cd0140466c1a52ff47d1d4ccc6b92e4b5
parente85144bff21445ef19864c38be87055045d95c35 (diff)
parent1db9e1fb8f8921a599a0b2933d682a20f97abdb8 (diff)
downloadgem5-0fd999ca403f427ab5278bf69b005ed1ce851876.tar.xz
Merge with head.
--HG-- extra : convert_revision : ae7b3df573368c29a66d5b027ecad9ffb3a99104
-rw-r--r--src/arch/alpha/tlb.cc38
-rw-r--r--src/arch/alpha/tlb.hh4
-rw-r--r--src/cpu/static_inst.hh7
-rw-r--r--src/mem/bus.cc44
-rw-r--r--src/mem/bus.hh101
5 files changed, 174 insertions, 20 deletions
diff --git a/src/arch/alpha/tlb.cc b/src/arch/alpha/tlb.cc
index 214b2579f..205b81baf 100644
--- a/src/arch/alpha/tlb.cc
+++ b/src/arch/alpha/tlb.cc
@@ -64,6 +64,7 @@ TLB::TLB(const string &name, int s)
{
table = new PTE[size];
memset(table, 0, sizeof(PTE[size]));
+ flushCache();
}
TLB::~TLB()
@@ -79,18 +80,29 @@ TLB::lookup(Addr vpn, uint8_t asn) const
// assume not found...
PTE *retval = NULL;
- PageTable::const_iterator i = lookupTable.find(vpn);
- if (i != lookupTable.end()) {
- while (i->first == vpn) {
- int index = i->second;
- PTE *pte = &table[index];
- assert(pte->valid);
- if (vpn == pte->tag && (pte->asma || pte->asn == asn)) {
- retval = pte;
- break;
- }
+ if (PTECache[0] && vpn == PTECache[0]->tag &&
+ (PTECache[0]->asma || PTECache[0]->asn == asn))
+ retval = PTECache[0];
+ else if (PTECache[1] && vpn == PTECache[1]->tag &&
+ (PTECache[1]->asma || PTECache[1]->asn == asn))
+ retval = PTECache[1];
+ else if (PTECache[2] && vpn == PTECache[2]->tag &&
+ (PTECache[2]->asma || PTECache[2]->asn == asn))
+ retval = PTECache[2];
+ else {
+ PageTable::const_iterator i = lookupTable.find(vpn);
+ if (i != lookupTable.end()) {
+ while (i->first == vpn) {
+ int index = i->second;
+ PTE *pte = &table[index];
+ assert(pte->valid);
+ if (vpn == pte->tag && (pte->asma || pte->asn == asn)) {
+ retval = pte;
+ break;
+ }
- ++i;
+ ++i;
+ }
}
}
@@ -142,6 +154,7 @@ TLB::checkCacheability(RequestPtr &req)
void
TLB::insert(Addr addr, PTE &pte)
{
+ flushCache();
VAddr vaddr = addr;
if (table[nlu].valid) {
Addr oldvpn = table[nlu].tag;
@@ -178,6 +191,7 @@ TLB::flushAll()
{
DPRINTF(TLB, "flushAll\n");
memset(table, 0, sizeof(PTE[size]));
+ flushCache();
lookupTable.clear();
nlu = 0;
}
@@ -185,6 +199,7 @@ TLB::flushAll()
void
TLB::flushProcesses()
{
+ flushCache();
PageTable::iterator i = lookupTable.begin();
PageTable::iterator end = lookupTable.end();
while (i != end) {
@@ -208,6 +223,7 @@ TLB::flushProcesses()
void
TLB::flushAddr(Addr addr, uint8_t asn)
{
+ flushCache();
VAddr vaddr = addr;
PageTable::iterator i = lookupTable.find(vaddr.vpn());
diff --git a/src/arch/alpha/tlb.hh b/src/arch/alpha/tlb.hh
index ea5ba5539..20f0037fd 100644
--- a/src/arch/alpha/tlb.hh
+++ b/src/arch/alpha/tlb.hh
@@ -88,6 +88,10 @@ namespace AlphaISA
// Checkpointing
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+ // Most recently used page table entries
+ PTE *PTECache[2];
+ inline void flushCache() { memset(PTECache, 0, 2 * sizeof(PTE*)); }
};
class ITB : public TLB
diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh
index f32b61ee5..2e1ebd766 100644
--- a/src/cpu/static_inst.hh
+++ b/src/cpu/static_inst.hh
@@ -353,9 +353,7 @@ class StaticInst : public StaticInstBase
StaticInst(const char *_mnemonic, ExtMachInst _machInst, OpClass __opClass)
: StaticInstBase(__opClass),
machInst(_machInst), mnemonic(_mnemonic), cachedDisassembly(0)
- {
- memset(&recentDecodes, 0, 2 * sizeof(cacheElement));
- }
+ { }
public:
@@ -459,6 +457,9 @@ class StaticInst : public StaticInstBase
struct cacheElement {
Addr page_addr;
AddrDecodePage *decodePage;
+
+ cacheElement()
+ :decodePage(NULL) { }
} ;
/// An array of recently decoded instructions.
diff --git a/src/mem/bus.cc b/src/mem/bus.cc
index cb359734b..9fa61a76d 100644
--- a/src/mem/bus.cc
+++ b/src/mem/bus.cc
@@ -84,6 +84,7 @@ Bus::deletePortRefs(Port *p)
if (funcPort == bp)
return;
interfaces.erase(bp->getId());
+ clearBusCache();
delete bp;
}
@@ -176,7 +177,16 @@ Bus::recvTiming(PacketPtr pkt)
DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n",
src, pkt->getDest(), pkt->getAddr(), pkt->cmdString());
- BusPort *src_port = (src == defaultId) ? defaultPort : interfaces[src];
+ BusPort *src_port;
+ if (src == defaultId)
+ src_port = defaultPort;
+ else {
+ src_port = checkBusCache(src);
+ if (src_port == NULL) {
+ src_port = interfaces[src];
+ updateBusCache(src, src_port);
+ }
+ }
// If the bus is busy, or other devices are in line ahead of the current
// one, put this device on the retry list.
@@ -220,6 +230,15 @@ Bus::recvTiming(PacketPtr pkt)
assert(dest >= 0 && dest < maxId);
assert(dest != src); // catch infinite loops
dest_port_id = dest;
+ if (dest_port_id == defaultId)
+ dest_port = defaultPort;
+ else {
+ dest_port = checkBusCache(dest);
+ if (dest_port == NULL) {
+ dest_port = interfaces[dest_port_id];
+ // updateBusCache(dest_port_id, dest_port);
+ }
+ }
dest_port = (dest_port_id == defaultId) ?
defaultPort : interfaces[dest_port_id];
}
@@ -291,9 +310,13 @@ Bus::findPort(Addr addr)
/* An interval tree would be a better way to do this. --ali. */
int dest_id = -1;
- PortIter i = portMap.find(RangeSize(addr,1));
- if (i != portMap.end())
- dest_id = i->second;
+ dest_id = checkPortCache(addr);
+ if (dest_id == -1) {
+ PortIter i = portMap.find(RangeSize(addr,1));
+ if (i != portMap.end())
+ dest_id = i->second;
+ updatePortCache(dest_id, i->first.start, i->first.end);
+ }
// Check if this matches the default range
if (dest_id == -1) {
@@ -340,8 +363,16 @@ Bus::recvAtomic(PacketPtr pkt)
int orig_src = pkt->getSrc();
int target_port_id = findPort(pkt->getAddr());
- Port *target_port = (target_port_id == defaultId) ?
- defaultPort : interfaces[target_port_id];
+ BusPort *target_port;
+ if (target_port_id == defaultId)
+ target_port = defaultPort;
+ else {
+ target_port = checkBusCache(target_port_id);
+ if (target_port == NULL) {
+ target_port = interfaces[target_port_id];
+ updateBusCache(target_port_id, target_port);
+ }
+ }
SnoopIter s_end = snoopPorts.end();
for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
@@ -438,6 +469,7 @@ Bus::recvStatusChange(Port::Status status, int id)
DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
+ clearPortCache();
if (id == defaultId) {
defaultRange.clear();
// Only try to update these ranges if the user set a default responder.
diff --git a/src/mem/bus.hh b/src/mem/bus.hh
index 06ccd4ac0..f5cad0586 100644
--- a/src/mem/bus.hh
+++ b/src/mem/bus.hh
@@ -180,6 +180,58 @@ class Bus : public MemObject
*/
int findPort(Addr addr);
+ // Cache for the findPort function storing recently used ports from portMap
+ struct PortCache {
+ bool valid;
+ int id;
+ Addr start;
+ Addr end;
+ };
+
+ PortCache portCache[3];
+
+ // Checks the cache and returns the id of the port that has the requested
+ // address within its range
+ inline int checkPortCache(Addr addr) {
+ if (portCache[0].valid && addr >= portCache[0].start &&
+ addr < portCache[0].end) {
+ return portCache[0].id;
+ } else if (portCache[1].valid && addr >= portCache[1].start &&
+ addr < portCache[1].end) {
+ return portCache[1].id;
+ } else if (portCache[2].valid && addr >= portCache[2].start &&
+ addr < portCache[2].end) {
+ return portCache[2].id;
+ }
+
+ return -1;
+ }
+
+ // Clears the earliest entry of the cache and inserts a new port entry
+ inline void updatePortCache(short id, Addr start, Addr end) {
+ portCache[2].valid = portCache[1].valid;
+ portCache[2].id = portCache[1].id;
+ portCache[2].start = portCache[1].start;
+ portCache[2].end = portCache[1].end;
+
+ portCache[1].valid = portCache[0].valid;
+ portCache[1].id = portCache[0].id;
+ portCache[1].start = portCache[0].start;
+ portCache[1].end = portCache[0].end;
+
+ portCache[0].valid = true;
+ portCache[0].id = id;
+ portCache[0].start = start;
+ portCache[0].end = end;
+ }
+
+ // Clears the cache. Needs to be called in constructor.
+ inline void clearPortCache() {
+ portCache[2].valid = false;
+ portCache[1].valid = false;
+ portCache[0].valid = false;
+ }
+
/** Process address range request.
* @param resp addresses that we can respond to
* @param snoop addresses that we would like to snoop
@@ -246,6 +298,53 @@ class Bus : public MemObject
int cachedBlockSize;
bool cachedBlockSizeValid;
+ // Cache for the peer port interfaces
+ struct BusCache {
+ bool valid;
+ short id;
+ BusPort *port;
+ };
+
+ BusCache busCache[3];
+
+ // Checks the peer port interfaces cache for the port id and returns
+ // a pointer to the matching port
+ inline BusPort* checkBusCache(short id) {
+ if (busCache[0].valid && id == busCache[0].id) {
+ return busCache[0].port;
+ } else if (busCache[1].valid && id == busCache[1].id) {
+ return busCache[1].port;
+ } else if (busCache[2].valid && id == busCache[2].id) {
+ return busCache[2].port;
+ }
+
+ return NULL;
+ }
+
+ // Replaces the earliest entry in the cache with a new entry
+ inline void updateBusCache(short id, BusPort *port) {
+ busCache[2].valid = busCache[1].valid;
+ busCache[2].id = busCache[1].id;
+ busCache[2].port = busCache[1].port;
+
+ busCache[1].valid = busCache[0].valid;
+ busCache[1].id = busCache[0].id;
+ busCache[1].port = busCache[0].port;
+
+ busCache[0].valid = true;
+ busCache[0].id = id;
+ busCache[0].port = port;
+ }
+
+ // Invalidates the cache. Needs to be called in constructor.
+ inline void clearBusCache() {
+ // memset(busCache, 0, 3 * sizeof(BusCache));
+ busCache[2].valid = false;
+ busCache[1].valid = false;
+ busCache[0].valid = false;
+ }
+
+
public:
/** A function used to return the port associated with this bus object. */
@@ -270,6 +369,8 @@ class Bus : public MemObject
fatal("Bus width must be positive\n");
if (clock <= 0)
fatal("Bus clock period must be positive\n");
+ clearBusCache();
+ clearPortCache();
}
};