diff -r 3b3b94536547 -r 16cf2c2e4731 configs/common/Caches.py --- a/configs/common/Caches.py Thu Jul 18 08:31:19 2013 -0400 +++ b/configs/common/Caches.py Thu Jul 18 11:33:02 2013 -0700 @@ -49,6 +49,7 @@ class L1Cache(BaseCache): assoc = 2 hit_latency = 2 + write_latency = 2 response_latency = 2 mshrs = 4 tgts_per_mshr = 20 @@ -57,6 +58,7 @@ class L2Cache(BaseCache): assoc = 8 hit_latency = 20 + write_latency = 20 response_latency = 20 mshrs = 20 tgts_per_mshr = 12 @@ -65,6 +67,7 @@ class IOCache(BaseCache): assoc = 8 hit_latency = 50 + write_latency = 50 response_latency = 50 mshrs = 20 size = '1kB' @@ -75,6 +78,7 @@ class PageTableWalkerCache(BaseCache): assoc = 2 hit_latency = 2 + write_latency = 2 response_latency = 2 mshrs = 10 size = '1kB' diff -r 3b3b94536547 -r 16cf2c2e4731 configs/common/Options.py --- a/configs/common/Options.py Thu Jul 18 08:31:19 2013 -0400 +++ b/configs/common/Options.py Thu Jul 18 11:33:02 2013 -0700 @@ -103,6 +103,30 @@ parser.add_option("--l1i_assoc", type="int", default=2) parser.add_option("--l2_assoc", type="int", default=8) parser.add_option("--l3_assoc", type="int", default=16) + parser.add_option("--l1_read_lat", type="int", default="2", + help="L1 read latency.") + parser.add_option("--l2_read_lat", type="int", default="10", + help="L2 read latency.") + parser.add_option("--l3_read_lat", type="int", default="40", + help="L3 read latency.") + parser.add_option("--l1_write_lat", type="int", default="2", + help="L1 write latency.") + parser.add_option("--l2_write_lat", type="int", default="10", + help="L2 write latency.") + parser.add_option("--l3_write_lat", type="int", default="40", + help="L3 write latency.") + parser.add_option("--l1_num_banks", type="int", default="2", + help="L1 bank count.") + parser.add_option("--l2_num_banks", type="int", default="2", + help="L2 bank count.") + parser.add_option("--l3_num_banks", type="int", default="2", + help="L3 bank count.") + parser.add_option("--l1_intlv_bit", type="int", default="6", + help="L1 bank interleave highest bit.") + parser.add_option("--l2_intlv_bit", type="int", default="6", + help="L2 bank interleave highest bit.") + parser.add_option("--l3_intlv_bit", type="int", default="6", + help="L3 bank interleave highest bit.") parser.add_option("--cacheline_size", type="int", default=64) # Enable Ruby diff -r 3b3b94536547 -r 16cf2c2e4731 src/mem/cache/BaseCache.py --- a/src/mem/cache/BaseCache.py Thu Jul 18 08:31:19 2013 -0400 +++ b/src/mem/cache/BaseCache.py Thu Jul 18 11:33:02 2013 -0700 @@ -48,9 +48,13 @@ type = 'BaseCache' cxx_header = "mem/cache/base.hh" assoc = Param.Int("associativity") - hit_latency = Param.Cycles("The hit latency for this cache") + hit_latency = Param.Cycles("The read latency for this cache") + write_latency = Param.Cycles("The write latency for this cache") response_latency = Param.Cycles( - "Additional cache latency for the return path to core on a miss"); + "Additional cache latency for the return path to core on a miss") + num_banks = Param.Int(2, "Number of cache data array banks") + bank_intlv_high_bit = Param.Int(6, + "Cache data array bank interleave highest bit") max_miss_count = Param.Counter(0, "number of misses to handle before calling exit") mshrs = Param.Int("number of MSHRs (max outstanding requests)") diff -r 3b3b94536547 -r 16cf2c2e4731 src/mem/cache/SConscript --- a/src/mem/cache/SConscript Thu Jul 18 08:31:19 2013 -0400 +++ b/src/mem/cache/SConscript Thu Jul 18 11:33:02 2013 -0700 @@ -43,6 +43,7 @@ DebugFlag('Cache') DebugFlag('CachePort') +DebugFlag('CacheBank') DebugFlag('CacheRepl') DebugFlag('CacheTags') DebugFlag('HWPrefetch') diff -r 3b3b94536547 -r 16cf2c2e4731 src/mem/cache/base.hh --- a/src/mem/cache/base.hh Thu Jul 18 08:31:19 2013 -0400 +++ b/src/mem/cache/base.hh Thu Jul 18 11:33:02 2013 -0700 @@ -61,6 +61,7 @@ #include "base/types.hh" #include "debug/Cache.hh" #include "debug/CachePort.hh" +#include "debug/CacheBank.hh" #include "mem/cache/mshr_queue.hh" #include "mem/mem_object.hh" #include "mem/packet.hh" @@ -180,9 +181,46 @@ bool mustSendRetry; + EventWrapper sendRetryEvent; + + }; + + /** + * Cache data array bank. + */ + class CacheBank + { + private: + /** Descriptive name (for DPRINTF output) */ + std::string bankName; - EventWrapper sendRetryEvent; + bool inService; + + Tick nextIdleTick; + + public: + + void markInService(Tick); + + void clearInService(); + + void extendService(Tick); + + CacheBank(const std::string &_name) : + bankName(_name), + inService(false), + nextIdleTick(0) + {} + + bool serviceDone() const; + + bool isBusy() const { return inService; } + + Tick finishTick() const { return nextIdleTick; } + + /** Return port name (for DPRINTF). */ + const std::string name() const { return bankName; } }; @@ -191,6 +229,9 @@ protected: + /** Data array banks */ + std::vector bank; + /** Miss status registers */ MSHRQueue mshrQueue; @@ -246,9 +287,14 @@ const unsigned blkSize; /** - * The latency of a hit in this device. + * The latency of a read in this device. */ - const Cycles hitLatency; + const Cycles hitLatency; //@todo: rename to readLatency later + + /** + * The latency of a write in this device. + */ + const Cycles writeLatency; /** * The latency of sending reponse to its upper level cache/core on a @@ -258,6 +304,16 @@ */ const Cycles responseLatency; + /** + * The number of cache data array banks. + */ + const unsigned numBanks; + + /** + * Cache data array bank interleave bit (lower bit if numBanks>2) + */ + const unsigned bankIntlvHighBit; + /** The number of targets for each MSHR. */ const int numTarget; @@ -461,6 +517,15 @@ return blkSize; } + /** + * Return bank ID according to interleave bits + */ + unsigned + getBankId(Addr addr) const + { + uint32_t bankIntlvBits = ceilLog2(numBanks); + return (addr >> (bankIntlvHighBit + 1 - bankIntlvBits) ) % numBanks; + } Addr blockAlign(Addr addr) const { return (addr & ~(Addr(blkSize - 1))); } diff -r 3b3b94536547 -r 16cf2c2e4731 src/mem/cache/base.cc --- a/src/mem/cache/base.cc Thu Jul 18 08:31:19 2013 -0400 +++ b/src/mem/cache/base.cc Thu Jul 18 11:33:02 2013 -0700 @@ -68,12 +68,16 @@ BaseCache::BaseCache(const Params *p) : MemObject(p), + bank(p->num_banks), mshrQueue("MSHRs", p->mshrs, 4, MSHRQueue_MSHRs), writeBuffer("write buffer", p->write_buffers, p->mshrs+1000, MSHRQueue_WriteBuffer), blkSize(p->system->cacheLineSize()), hitLatency(p->hit_latency), + writeLatency(p->write_latency), responseLatency(p->response_latency), + numBanks(p->num_banks), + bankIntlvHighBit(p->bank_intlv_high_bit), numTarget(p->tgts_per_mshr), forwardSnoops(p->forward_snoops), isTopLevel(p->is_top_level), @@ -83,6 +87,49 @@ addrRanges(p->addr_ranges.begin(), p->addr_ranges.end()), system(p->system) { + uint32_t bankIntlvBits = ceilLog2(numBanks); + + if (ULL(1) << bankIntlvBits != numBanks) + fatal("%s number of banks is not a power of 2", name()); + + uint64_t granularity = ULL(1) << (bankIntlvHighBit + 1 - bankIntlvBits); + if (granularity < blkSize) + fatal("%s bank interleave granuarity (%ld) smaller than line size " + " (%ld)", name(), granularity, blkSize); +} + +void +BaseCache::CacheBank::markInService(Tick finishTick) +{ + assert(!inService); + nextIdleTick = finishTick; + DPRINTF(CacheBank, "In service until Tick %ld\n", + nextIdleTick); + inService = true; +} + +void +BaseCache::CacheBank::clearInService() +{ + assert(inService); + DPRINTF(CacheBank, "Service done, become idle\n"); + inService = false; +} + +void +BaseCache::CacheBank::extendService(Tick extraTick) +{ + assert(inService); + assert(nextIdleTick > curTick()); + nextIdleTick += extraTick; + DPRINTF(CacheBank, "Extend service to Tick %ld\n", + nextIdleTick); +} + +bool +BaseCache::CacheBank::serviceDone() const +{ + return inService && nextIdleTick <= curTick(); } void diff -r 3b3b94536547 -r 16cf2c2e4731 src/mem/cache/cache_impl.hh --- a/src/mem/cache/cache_impl.hh Thu Jul 18 08:31:19 2013 -0400 +++ b/src/mem/cache/cache_impl.hh Thu Jul 18 11:33:02 2013 -0700 @@ -56,6 +56,7 @@ #include "debug/Cache.hh" #include "debug/CachePort.hh" #include "debug/CacheTags.hh" +#include "debug/CacheBank.hh" #include "mem/cache/prefetch/base.hh" #include "mem/cache/blk.hh" #include "mem/cache/cache.hh" @@ -78,6 +79,10 @@ memSidePort = new MemSidePort(p->name + ".mem_side", this, "MemSidePort"); + for (unsigned i = 0; i < bank.size(); ++i) { + bank[i] = new CacheBank(csprintf("%s.bank%d", p->name, i)); + } + tags->setCache(this); if (prefetcher) prefetcher->setCache(this); @@ -91,6 +96,9 @@ delete cpuSidePort; delete memSidePort; + + for (unsigned i = 0; i < bank.size(); ++i) + delete bank[i]; } template @@ -299,6 +307,11 @@ int id = pkt->req->hasContextId() ? pkt->req->contextId() : -1; blk = tags->accessBlock(pkt->getAddr(), lat, id); + // Update latency decided by if it's read or write + if (pkt->isRead()) + lat = hitLatency; + else if (pkt->isWrite()) + lat = writeLatency; DPRINTF(Cache, "%s%s %x %s %s\n", pkt->cmdString(), pkt->req->isInstFetch() ? " (ifetch)" : "", @@ -511,16 +524,21 @@ next_pf_time = prefetcher->notify(pkt, time); } + unsigned bankId = getBankId(pkt->getAddr()); if (needsResponse) { pkt->makeTimingResponse(); // @todo: Make someone pay for this pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; cpuSidePort->schedTimingResp(pkt, clockEdge(lat)); + // Mark the corresponding bank in service + bank[bankId]->markInService(clockEdge(lat)); } else { /// @todo nominally we should just delete the packet here, /// however, until 4-phase stuff we can't because sending /// cache is still relying on it pendingDelete.push_back(pkt); + // Mark the corresponding bank in service + bank[bankId]->markInService(clockEdge(lat)); } } else { // miss @@ -908,6 +926,14 @@ blk = handleFill(pkt, blk, writebacks); assert(blk != NULL); + + // mark the corresponding bank in service + unsigned bankId = getBankId(pkt->getAddr()); + if (bank[bankId]->isBusy()) { + bank[bankId]->extendService(writeLatency * clockPeriod()); + } else { + bank[bankId]->markInService(clockEdge(writeLatency)); + } } // First offset for critical word first calculations @@ -1768,11 +1794,32 @@ bool Cache::CpuSidePort::recvTimingReq(PacketPtr pkt) { + // unmark bank in service + // NOTE: Ideally, the bank status should be updated immedidately after the + // nextIdleTick expires, but we will need to create new events to do that. + // Instead, we only check-and-unmark the inService bit before we really + // want to know the bank status. + for (unsigned i = 0; i < cache->bank.size(); ++i) + if (cache->bank[i]->serviceDone()) + cache->bank[i]->clearInService(); + + unsigned bankId = cache->getBankId(pkt->getAddr()); + bool inService = cache->bank[bankId]->isBusy(); // always let inhibited requests through even if blocked - if (!pkt->memInhibitAsserted() && blocked) { + if (!pkt->memInhibitAsserted() && (blocked || inService)) { assert(!cache->system->bypassCaches()); DPRINTF(Cache,"Scheduling a retry while blocked\n"); - mustSendRetry = true; + if (!inService) { + // not because of bank in service + mustSendRetry = true; + } else { + DPRINTF(CachePort, "Cache port %s denying new requests because the accessing bank is busy\n", name()); + // because of bank in service + // precisely know which tick the service will finish + if (!sendRetryEvent.scheduled()) + owner.schedule(sendRetryEvent, + cache->bank[bankId]->finishTick()); + } return false; } @@ -1813,6 +1860,15 @@ bool Cache::MemSidePort::recvTimingResp(PacketPtr pkt) { + // unmark bank in service + // NOTE: Ideally, the bank status should be updated immedidately after the + // nextIdleTick expires, but we will need to create new events to do that. + // Instead, we only check-and-unmark the inService bit before we really + // want to know the bank status. + for (unsigned i = 0; i < cache->bank.size(); ++i) + if (cache->bank[i]->serviceDone()) + cache->bank[i]->clearInService(); + cache->recvTimingResp(pkt); return true; }