diff options
Diffstat (limited to 'src/mem')
-rw-r--r-- | src/mem/Bridge.py | 6 | ||||
-rw-r--r-- | src/mem/bridge.cc | 33 | ||||
-rw-r--r-- | src/mem/bridge.hh | 6 | ||||
-rw-r--r-- | src/mem/bus.cc | 82 | ||||
-rw-r--r-- | src/mem/bus.hh | 106 | ||||
-rw-r--r-- | src/mem/cache/BaseCache.py | 4 | ||||
-rw-r--r-- | src/mem/cache/base_cache.cc | 5 | ||||
-rw-r--r-- | src/mem/cache/base_cache.hh | 16 | ||||
-rw-r--r-- | src/mem/cache/cache.hh | 6 | ||||
-rw-r--r-- | src/mem/cache/cache_builder.cc | 3 | ||||
-rw-r--r-- | src/mem/cache/cache_impl.hh | 23 |
11 files changed, 219 insertions, 71 deletions
diff --git a/src/mem/Bridge.py b/src/mem/Bridge.py index 8377221cd..b48e1684d 100644 --- a/src/mem/Bridge.py +++ b/src/mem/Bridge.py @@ -40,5 +40,7 @@ class Bridge(MemObject): delay = Param.Latency('0ns', "The latency of this bridge") nack_delay = Param.Latency('0ns', "The latency of this bridge") write_ack = Param.Bool(False, "Should this bridge ack writes") - fix_partial_write_a = Param.Bool(False, "Should this bridge fixup partial block writes") - fix_partial_write_b = Param.Bool(False, "Should this bridge fixup partial block writes") + filter_ranges_a = VectorParam.AddrRange([], + "What addresses shouldn't be passed through the side of the bridge") + filter_ranges_b = VectorParam.AddrRange([], + "What addresses shouldn't be passed through the side of the bridge") diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc index 6cfa5a2ac..c502c5130 100644 --- a/src/mem/bridge.cc +++ b/src/mem/bridge.cc @@ -37,6 +37,7 @@ #include <algorithm> +#include "base/range_ops.hh" #include "base/trace.hh" #include "mem/bridge.hh" #include "params/Bridge.hh" @@ -44,9 +45,10 @@ Bridge::BridgePort::BridgePort(const std::string &_name, Bridge *_bridge, BridgePort *_otherPort, int _delay, int _nack_delay, int _req_limit, - int _resp_limit, bool fix_partial_write) + int _resp_limit, + std::vector<Range<Addr> > filter_ranges) : Port(_name), bridge(_bridge), otherPort(_otherPort), - delay(_delay), nackDelay(_nack_delay), fixPartialWrite(fix_partial_write), + delay(_delay), nackDelay(_nack_delay), filterRanges(filter_ranges), outstandingResponses(0), queuedRequests(0), inRetry(false), reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this) { @@ -55,9 +57,9 @@ Bridge::BridgePort::BridgePort(const std::string &_name, Bridge::Bridge(Params *p) : MemObject(p->name), portA(p->name + "-portA", this, &portB, p->delay, p->nack_delay, - p->req_size_a, p->resp_size_a, p->fix_partial_write_a), + p->req_size_a, p->resp_size_a, p->filter_ranges_a), portB(p->name + "-portB", this, &portA, p->delay, p->nack_delay, - p->req_size_b, p->resp_size_b, p->fix_partial_write_b), + p->req_size_b, p->resp_size_b, p->filter_ranges_b), ackWrites(p->write_ack), _params(p) { if (ackWrites) @@ -243,17 +245,6 @@ Bridge::BridgePort::trySend() PacketPtr pkt = buf->pkt; - // Ugly! @todo When multilevel coherence works this will be removed - if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite && - !pkt->wasNacked()) { - PacketPtr funcPkt = new Packet(pkt->req, MemCmd::WriteReq, - Packet::Broadcast); - funcPkt->dataStatic(pkt->getPtr<uint8_t>()); - sendFunctional(funcPkt); - pkt->cmd = MemCmd::WriteReq; - delete funcPkt; - } - DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n", buf->origSrc, pkt->getDest(), pkt->getAddr()); @@ -313,17 +304,6 @@ Bridge::BridgePort::recvRetry() Tick Bridge::BridgePort::recvAtomic(PacketPtr pkt) { - // fix partial atomic writes... similar to the timing code that does the - // same... will be removed once our code gets this right - if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite) { - - PacketPtr funcPkt = new Packet(pkt->req, MemCmd::WriteReq, - Packet::Broadcast); - funcPkt->dataStatic(pkt->getPtr<uint8_t>()); - otherPort->sendFunctional(funcPkt); - delete funcPkt; - pkt->cmd = MemCmd::WriteReq; - } return delay + otherPort->sendAtomic(pkt); } @@ -355,6 +335,7 @@ Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp, bool &snoop) { otherPort->getPeerAddressRanges(resp, snoop); + FilterRangeList(filterRanges, resp); // we don't allow snooping across bridges snoop = false; } diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh index d3bbf2ddf..82001948e 100644 --- a/src/mem/bridge.hh +++ b/src/mem/bridge.hh @@ -70,7 +70,8 @@ class Bridge : public MemObject /** Min delay to respond to a nack. */ Tick nackDelay; - bool fixPartialWrite; + /** Pass ranges from one side of the bridge to the other? */ + std::vector<Range<Addr> > filterRanges; class PacketBuffer : public Packet::SenderState { @@ -156,7 +157,8 @@ class Bridge : public MemObject /** Constructor for the BusPort.*/ BridgePort(const std::string &_name, Bridge *_bridge, BridgePort *_otherPort, int _delay, int _nack_delay, - int _req_limit, int _resp_limit, bool fix_partial_write); + int _req_limit, int _resp_limit, + std::vector<Range<Addr> > filter_ranges); protected: diff --git a/src/mem/bus.cc b/src/mem/bus.cc index cb359734b..42c4431bb 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. @@ -201,25 +211,28 @@ Bus::recvTiming(PacketPtr pkt) dest_port_id = findPort(pkt->getAddr()); dest_port = (dest_port_id == defaultId) ? defaultPort : interfaces[dest_port_id]; - for (SnoopIter s_iter = snoopPorts.begin(); - s_iter != snoopPorts.end(); - s_iter++) { + SnoopIter s_end = snoopPorts.end(); + for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { BusPort *p = *s_iter; if (p != dest_port && p != src_port) { -#ifndef NDEBUG // cache is not allowed to refuse snoop - bool success = p->sendTiming(pkt); + bool success M5_VAR_USED = p->sendTiming(pkt); assert(success); -#else - // avoid unused variable warning - p->sendTiming(pkt); -#endif } } } else { 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,15 +304,19 @@ 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) { - for (AddrRangeIter iter = defaultRange.begin(); - iter != defaultRange.end(); iter++) { - if (*iter == addr) { + AddrRangeIter a_end = defaultRange.end(); + for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) { + if (*i == addr) { DPRINTF(Bus, " found addr %#llx on default\n", addr); return defaultId; } @@ -340,8 +357,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++) { @@ -406,9 +431,8 @@ Bus::recvFunctional(PacketPtr pkt) assert(pkt->isRequest()); // hasn't already been satisfied - for (SnoopIter s_iter = snoopPorts.begin(); - s_iter != snoopPorts.end(); - s_iter++) { + SnoopIter s_end = snoopPorts.end(); + for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { BusPort *p = *s_iter; if (p != port && p->getId() != src_id) { p->sendFunctional(pkt); @@ -433,11 +457,16 @@ Bus::recvStatusChange(Port::Status status, int id) bool snoops; AddrRangeIter iter; + if (inRecvStatusChange.count(id)) + return; + inRecvStatusChange.insert(id); + assert(status == Port::RangeChange && "The other statuses need to be implemented."); 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. @@ -499,6 +528,7 @@ Bus::recvStatusChange(Port::Status status, int id) if (id != defaultId && defaultPort) defaultPort->sendStatusChange(Port::RangeChange); + inRecvStatusChange.erase(id); } void @@ -557,14 +587,14 @@ Bus::findBlockSize(int id) int max_bs = -1; - for (PortIter portIter = portMap.begin(); - portIter != portMap.end(); portIter++) { - int tmp_bs = interfaces[portIter->second]->peerBlockSize(); + PortIter p_end = portMap.end(); + for (PortIter p_iter = portMap.begin(); p_iter != p_end; p_iter++) { + int tmp_bs = interfaces[p_iter->second]->peerBlockSize(); if (tmp_bs > max_bs) max_bs = tmp_bs; } - for (SnoopIter s_iter = snoopPorts.begin(); - s_iter != snoopPorts.end(); s_iter++) { + SnoopIter s_end = snoopPorts.end(); + for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) { int tmp_bs = (*s_iter)->peerBlockSize(); if (tmp_bs > max_bs) max_bs = tmp_bs; diff --git a/src/mem/bus.hh b/src/mem/bus.hh index 06ccd4ac0..0c594c463 100644 --- a/src/mem/bus.hh +++ b/src/mem/bus.hh @@ -38,6 +38,7 @@ #define __MEM_BUS_HH__ #include <string> +#include <set> #include <list> #include <inttypes.h> @@ -180,6 +181,60 @@ 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; + } + if (portCache[1].valid && addr >= portCache[1].start && + addr < portCache[1].end) { + return portCache[1].id; + } + 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 @@ -199,6 +254,7 @@ class Bus : public MemObject BusFreeEvent busIdle; bool inRetry; + std::set<int> inRecvStatusChange; /** max number of bus ids we've handed out so far */ short maxId; @@ -246,6 +302,54 @@ 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; + } + if (busCache[1].valid && id == busCache[1].id) { + return busCache[1].port; + } + 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() { + 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 +374,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(); } }; diff --git a/src/mem/cache/BaseCache.py b/src/mem/cache/BaseCache.py index 2bf44cdf9..f6d42b1ef 100644 --- a/src/mem/cache/BaseCache.py +++ b/src/mem/cache/BaseCache.py @@ -81,4 +81,8 @@ class BaseCache(MemObject): "Only prefetch on data not on instruction accesses") cpu_side = Port("Port on side closer to CPU") mem_side = Port("Port on side closer to MEM") + cpu_side_filter_ranges = VectorParam.AddrRange([], + "What addresses shouldn't be passed through the side of the bridge") + mem_side_filter_ranges = VectorParam.AddrRange([], + "What addresses shouldn't be passed through the side of the bridge") addr_range = VectorParam.AddrRange(AllMemory, "The address range in bytes") diff --git a/src/mem/cache/base_cache.cc b/src/mem/cache/base_cache.cc index b44468486..0c8b02cb3 100644 --- a/src/mem/cache/base_cache.cc +++ b/src/mem/cache/base_cache.cc @@ -40,9 +40,10 @@ using namespace std; -BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache) +BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache, + std::vector<Range<Addr> > filter_ranges) : SimpleTimingPort(_name, _cache), cache(_cache), otherPort(NULL), - blocked(false), mustSendRetry(false) + blocked(false), mustSendRetry(false), filterRanges(filter_ranges) { } diff --git a/src/mem/cache/base_cache.hh b/src/mem/cache/base_cache.hh index 719ab0245..6a4eec43e 100644 --- a/src/mem/cache/base_cache.hh +++ b/src/mem/cache/base_cache.hh @@ -98,7 +98,8 @@ class BaseCache : public MemObject BaseCache *cache; protected: - CachePort(const std::string &_name, BaseCache *_cache); + CachePort(const std::string &_name, BaseCache *_cache, + std::vector<Range<Addr> > filter_ranges); virtual void recvStatusChange(Status status); @@ -124,6 +125,9 @@ class BaseCache : public MemObject bool mustSendRetry; + /** filter ranges */ + std::vector<Range<Addr> > filterRanges; + void requestBus(RequestCause cause, Tick time) { DPRINTF(CachePort, "Asserting bus request for cause %d\n", cause); @@ -367,15 +371,21 @@ class BaseCache : public MemObject */ Counter maxMisses; + std::vector<Range<Addr> > cpuSideFilterRanges; + std::vector<Range<Addr> > memSideFilterRanges; /** * Construct an instance of this parameter class. */ Params(int _hitLatency, int _blkSize, int _numMSHRs, int _numTargets, int _numWriteBuffers, - Counter _maxMisses) + Counter _maxMisses, + std::vector<Range<Addr> > cpu_side_filter_ranges, + std::vector<Range<Addr> > mem_side_filter_ranges) : hitLatency(_hitLatency), blkSize(_blkSize), numMSHRs(_numMSHRs), numTargets(_numTargets), - numWriteBuffers(_numWriteBuffers), maxMisses(_maxMisses) + numWriteBuffers(_numWriteBuffers), maxMisses(_maxMisses), + cpuSideFilterRanges(cpu_side_filter_ranges), + memSideFilterRanges(mem_side_filter_ranges) { } }; diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh index 57028a05e..821fa9702 100644 --- a/src/mem/cache/cache.hh +++ b/src/mem/cache/cache.hh @@ -72,7 +72,8 @@ class Cache : public BaseCache { public: CpuSidePort(const std::string &_name, - Cache<TagStore> *_cache); + Cache<TagStore> *_cache, + std::vector<Range<Addr> > filterRanges); // BaseCache::CachePort just has a BaseCache *; this function // lets us get back the type info we lost when we stored the @@ -95,7 +96,8 @@ class Cache : public BaseCache { public: MemSidePort(const std::string &_name, - Cache<TagStore> *_cache); + Cache<TagStore> *_cache, + std::vector<Range<Addr> > filterRanges); // BaseCache::CachePort just has a BaseCache *; this function // lets us get back the type info we lost when we stored the diff --git a/src/mem/cache/cache_builder.cc b/src/mem/cache/cache_builder.cc index 4c9592a1b..0f8b52af2 100644 --- a/src/mem/cache/cache_builder.cc +++ b/src/mem/cache/cache_builder.cc @@ -241,7 +241,8 @@ BaseCacheParams::create() // Build BaseCache param object BaseCache::Params base_params(latency, block_size, mshrs, tgts_per_mshr, write_buffers, - max_miss_count); + max_miss_count, cpu_side_filter_ranges, + mem_side_filter_ranges); //Warnings about prefetcher policy if (prefetch_policy == Enums::none) { diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh index d144266ed..402e34db2 100644 --- a/src/mem/cache/cache_impl.hh +++ b/src/mem/cache/cache_impl.hh @@ -39,6 +39,7 @@ #include "sim/host.hh" #include "base/misc.hh" +#include "base/range_ops.hh" #include "mem/cache/cache.hh" #include "mem/cache/cache_blk.hh" @@ -61,8 +62,10 @@ Cache<TagStore>::Cache(const std::string &_name, tempBlock = new BlkType(); tempBlock->data = new uint8_t[blkSize]; - cpuSidePort = new CpuSidePort(_name + "-cpu_side_port", this); - memSidePort = new MemSidePort(_name + "-mem_side_port", this); + cpuSidePort = new CpuSidePort(_name + "-cpu_side_port", this, + params.baseParams.cpuSideFilterRanges); + memSidePort = new MemSidePort(_name + "-mem_side_port", this, + params.baseParams.memSideFilterRanges); cpuSidePort->setOtherPort(memSidePort); memSidePort->setOtherPort(cpuSidePort); @@ -88,7 +91,8 @@ Cache<TagStore>::getPort(const std::string &if_name, int idx) } else if (if_name == "mem_side") { return memSidePort; } else if (if_name == "functional") { - return new CpuSidePort(name() + "-cpu_side_funcport", this); + return new CpuSidePort(name() + "-cpu_side_funcport", this, + std::vector<Range<Addr> >()); } else { panic("Port name %s unrecognized\n", if_name); } @@ -1221,6 +1225,7 @@ getDeviceAddressRanges(AddrRangeList &resp, bool &snoop) // CPU side port doesn't snoop; it's a target only. bool dummy; otherPort->getPeerAddressRanges(resp, dummy); + FilterRangeList(filterRanges, resp); snoop = false; } @@ -1262,8 +1267,9 @@ Cache<TagStore>::CpuSidePort::recvFunctional(PacketPtr pkt) template<class TagStore> Cache<TagStore>:: CpuSidePort::CpuSidePort(const std::string &_name, - Cache<TagStore> *_cache) - : BaseCache::CachePort(_name, _cache) + Cache<TagStore> *_cache, std::vector<Range<Addr> > + filterRanges) + : BaseCache::CachePort(_name, _cache, filterRanges) { } @@ -1279,6 +1285,8 @@ Cache<TagStore>::MemSidePort:: getDeviceAddressRanges(AddrRangeList &resp, bool &snoop) { otherPort->getPeerAddressRanges(resp, snoop); + FilterRangeList(filterRanges, resp); + // Memory-side port always snoops, so unconditionally set flag for // caller. snoop = true; @@ -1416,8 +1424,9 @@ Cache<TagStore>::MemSidePort::processSendEvent() template<class TagStore> Cache<TagStore>:: -MemSidePort::MemSidePort(const std::string &_name, Cache<TagStore> *_cache) - : BaseCache::CachePort(_name, _cache) +MemSidePort::MemSidePort(const std::string &_name, Cache<TagStore> *_cache, + std::vector<Range<Addr> > filterRanges) + : BaseCache::CachePort(_name, _cache, filterRanges) { // override default send event from SimpleTimingPort delete sendEvent; |