2006-06-28 17:02:14 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2002-2005 The Regents of The University of Michigan
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are
|
|
|
|
* met: redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer;
|
|
|
|
* redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution;
|
|
|
|
* neither the name of the copyright holders nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived from
|
|
|
|
* this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* Authors: Erik Hallnor
|
|
|
|
* Dave Greene
|
|
|
|
* Nathan Binkert
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
* Cache definitions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include <cassert>
|
|
|
|
#include <iostream>
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
#include "sim/host.hh"
|
|
|
|
#include "base/misc.hh"
|
|
|
|
#include "cpu/smt.hh"
|
|
|
|
|
|
|
|
#include "mem/cache/cache.hh"
|
|
|
|
#include "mem/cache/cache_blk.hh"
|
|
|
|
#include "mem/cache/miss/mshr.hh"
|
|
|
|
#include "mem/cache/prefetch/prefetcher.hh"
|
|
|
|
|
|
|
|
#include "sim/sim_events.hh" // for SimExitEvent
|
|
|
|
|
|
|
|
template<class TagStore, class Buffering, class Coherence>
|
|
|
|
bool
|
|
|
|
Cache<TagStore,Buffering,Coherence>::
|
2006-06-28 23:28:33 +02:00
|
|
|
doTimingAccess(Packet *pkt, CachePort *cachePort, bool isCpuSide)
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
|
|
|
if (isCpuSide)
|
|
|
|
{
|
2006-08-22 22:09:34 +02:00
|
|
|
if (pkt->isWrite() && (pkt->req->getFlags() & LOCKED)) {
|
|
|
|
pkt->req->setScResult(1);
|
|
|
|
}
|
2006-10-06 03:10:03 +02:00
|
|
|
if (!(pkt->flags & SATISFIED)) {
|
|
|
|
access(pkt);
|
|
|
|
}
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-06-28 23:28:33 +02:00
|
|
|
if (pkt->isResponse())
|
2006-06-28 17:02:14 +02:00
|
|
|
handleResponse(pkt);
|
2006-10-06 03:10:03 +02:00
|
|
|
else {
|
|
|
|
//Check if we are in phase1
|
|
|
|
if (!snoopPhase2) {
|
|
|
|
snoopPhase2 = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
//Check if we should do the snoop
|
|
|
|
if (pkt->flags && SNOOP_COMMIT)
|
|
|
|
snoop(pkt);
|
|
|
|
snoopPhase2 = false;
|
|
|
|
}
|
|
|
|
}
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
2006-08-15 20:24:49 +02:00
|
|
|
return true;
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Buffering, class Coherence>
|
|
|
|
Tick
|
|
|
|
Cache<TagStore,Buffering,Coherence>::
|
2006-06-30 22:25:35 +02:00
|
|
|
doAtomicAccess(Packet *pkt, bool isCpuSide)
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
|
|
|
if (isCpuSide)
|
|
|
|
{
|
2006-08-22 22:09:34 +02:00
|
|
|
//Temporary solution to LL/SC
|
|
|
|
if (pkt->isWrite() && (pkt->req->getFlags() & LOCKED)) {
|
|
|
|
pkt->req->setScResult(1);
|
|
|
|
}
|
|
|
|
|
2006-06-28 17:02:14 +02:00
|
|
|
probe(pkt, true);
|
2006-06-30 23:21:58 +02:00
|
|
|
//TEMP ALWAYS SUCCES FOR NOW
|
|
|
|
pkt->result = Packet::Success;
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-06-28 23:28:33 +02:00
|
|
|
if (pkt->isResponse())
|
2006-06-28 17:02:14 +02:00
|
|
|
handleResponse(pkt);
|
|
|
|
else
|
|
|
|
snoopProbe(pkt, true);
|
|
|
|
}
|
2006-06-29 22:07:19 +02:00
|
|
|
//Fix this timing info
|
|
|
|
return hitLatency;
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Buffering, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Buffering,Coherence>::
|
2006-06-30 22:25:35 +02:00
|
|
|
doFunctionalAccess(Packet *pkt, bool isCpuSide)
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
|
|
|
if (isCpuSide)
|
|
|
|
{
|
2006-06-30 23:21:58 +02:00
|
|
|
//TEMP USE CPU?THREAD 0 0
|
|
|
|
pkt->req->setThreadContext(0,0);
|
2006-08-22 22:09:34 +02:00
|
|
|
|
|
|
|
//Temporary solution to LL/SC
|
|
|
|
if (pkt->isWrite() && (pkt->req->getFlags() & LOCKED)) {
|
|
|
|
assert("Can't handle LL/SC on functional path\n");
|
|
|
|
}
|
|
|
|
|
2006-10-06 03:10:03 +02:00
|
|
|
probe(pkt, false);
|
2006-06-30 23:21:58 +02:00
|
|
|
//TEMP ALWAYS SUCCESFUL FOR NOW
|
|
|
|
pkt->result = Packet::Success;
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-06-28 23:28:33 +02:00
|
|
|
if (pkt->isResponse())
|
2006-06-28 17:02:14 +02:00
|
|
|
handleResponse(pkt);
|
|
|
|
else
|
2006-10-06 03:10:03 +02:00
|
|
|
snoopProbe(pkt, false);
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Buffering, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Buffering,Coherence>::
|
|
|
|
recvStatusChange(Port::Status status, bool isCpuSide)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<class TagStore, class Buffering, class Coherence>
|
|
|
|
Cache<TagStore,Buffering,Coherence>::
|
2006-06-28 23:28:33 +02:00
|
|
|
Cache(const std::string &_name,
|
2006-06-28 17:02:14 +02:00
|
|
|
Cache<TagStore,Buffering,Coherence>::Params ¶ms)
|
2006-06-28 23:28:33 +02:00
|
|
|
: BaseCache(_name, params.baseParams),
|
2006-06-28 17:02:14 +02:00
|
|
|
prefetchAccess(params.prefetchAccess),
|
|
|
|
tags(params.tags), missQueue(params.missQueue),
|
|
|
|
coherence(params.coherence), prefetcher(params.prefetcher),
|
|
|
|
doCopy(params.doCopy), blockOnCopy(params.blockOnCopy)
|
|
|
|
{
|
2006-06-29 22:07:19 +02:00
|
|
|
//FIX BUS POINTERS
|
|
|
|
// if (params.in == NULL) {
|
2006-06-28 17:02:14 +02:00
|
|
|
topLevelCache = true;
|
2006-06-29 22:07:19 +02:00
|
|
|
// }
|
|
|
|
//PLEASE FIX THIS, BUS SIZES NOT BEING USED
|
|
|
|
tags->setCache(this, blkSize, 1/*params.out->width, params.out->clockRate*/);
|
2006-06-28 17:02:14 +02:00
|
|
|
tags->setPrefetcher(prefetcher);
|
|
|
|
missQueue->setCache(this);
|
|
|
|
missQueue->setPrefetcher(prefetcher);
|
|
|
|
coherence->setCache(this);
|
|
|
|
prefetcher->setCache(this);
|
|
|
|
prefetcher->setTags(tags);
|
|
|
|
prefetcher->setBuffer(missQueue);
|
2006-06-29 22:07:19 +02:00
|
|
|
#if 0
|
2006-06-28 17:02:14 +02:00
|
|
|
invalidatePkt = new Packet;
|
2006-06-28 23:28:33 +02:00
|
|
|
invalidatePkt->cmd = Packet::InvalidateReq;
|
2006-06-29 22:07:19 +02:00
|
|
|
#endif
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Buffering, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Buffering,Coherence>::regStats()
|
|
|
|
{
|
|
|
|
BaseCache::regStats();
|
|
|
|
tags->regStats(name());
|
|
|
|
missQueue->regStats(name());
|
|
|
|
coherence->regStats(name());
|
|
|
|
prefetcher->regStats(name());
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Buffering, class Coherence>
|
2006-06-28 23:28:33 +02:00
|
|
|
bool
|
|
|
|
Cache<TagStore,Buffering,Coherence>::access(PacketPtr &pkt)
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
2006-06-28 23:28:33 +02:00
|
|
|
//@todo Add back in MemDebug Calls
|
|
|
|
// MemDebug::cacheAccess(pkt);
|
2006-06-28 17:02:14 +02:00
|
|
|
BlkType *blk = NULL;
|
2006-06-28 23:28:33 +02:00
|
|
|
PacketList writebacks;
|
2006-06-28 17:02:14 +02:00
|
|
|
int size = blkSize;
|
|
|
|
int lat = hitLatency;
|
|
|
|
if (prefetchAccess) {
|
|
|
|
//We are determining prefetches on access stream, call prefetcher
|
|
|
|
prefetcher->handleMiss(pkt, curTick);
|
|
|
|
}
|
2006-06-28 20:35:00 +02:00
|
|
|
if (!pkt->req->isUncacheable()) {
|
2006-06-28 23:28:33 +02:00
|
|
|
if (pkt->isInvalidate() && !pkt->isRead()
|
|
|
|
&& !pkt->isWrite()) {
|
2006-06-28 17:02:14 +02:00
|
|
|
//Upgrade or Invalidate
|
|
|
|
//Look into what happens if two slave caches on bus
|
2006-08-15 22:21:46 +02:00
|
|
|
DPRINTF(Cache, "%s %x ? blk_addr: %x\n", pkt->cmdString(),
|
|
|
|
pkt->getAddr() & (((ULL(1))<<48)-1),
|
2006-06-29 22:07:19 +02:00
|
|
|
pkt->getAddr() & ~((Addr)blkSize - 1));
|
2006-06-28 17:02:14 +02:00
|
|
|
|
|
|
|
//@todo Should this return latency have the hit latency in it?
|
|
|
|
// respond(pkt,curTick+lat);
|
2006-06-29 22:07:19 +02:00
|
|
|
pkt->flags |= SATISFIED;
|
2006-06-28 23:28:33 +02:00
|
|
|
// return MA_HIT; //@todo, return values
|
|
|
|
return true;
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
blk = tags->handleAccess(pkt, lat, writebacks);
|
|
|
|
} else {
|
2006-06-29 22:07:19 +02:00
|
|
|
size = pkt->getSize();
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
// If this is a block size write/hint (WH64) allocate the block here
|
|
|
|
// if the coherence protocol allows it.
|
|
|
|
/** @todo make the fast write alloc (wh64) work with coherence. */
|
|
|
|
/** @todo Do we want to do fast writes for writebacks as well? */
|
2006-06-29 22:07:19 +02:00
|
|
|
if (!blk && pkt->getSize() >= blkSize && coherence->allowFastWrites() &&
|
2006-06-28 23:28:33 +02:00
|
|
|
(pkt->cmd == Packet::WriteReq || pkt->cmd == Packet::WriteInvalidateReq) ) {
|
2006-06-28 17:02:14 +02:00
|
|
|
// not outstanding misses, can do this
|
2006-08-15 22:21:46 +02:00
|
|
|
MSHR* outstanding_miss = missQueue->findMSHR(pkt->getAddr());
|
2006-06-28 23:28:33 +02:00
|
|
|
if (pkt->cmd == Packet::WriteInvalidateReq || !outstanding_miss) {
|
2006-06-28 17:02:14 +02:00
|
|
|
if (outstanding_miss) {
|
|
|
|
warn("WriteInv doing a fastallocate"
|
|
|
|
"with an outstanding miss to the same address\n");
|
|
|
|
}
|
|
|
|
blk = tags->handleFill(NULL, pkt, BlkValid | BlkWritable,
|
|
|
|
writebacks);
|
|
|
|
++fastWrites;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (!writebacks.empty()) {
|
|
|
|
missQueue->doWriteback(writebacks.front());
|
|
|
|
writebacks.pop_front();
|
|
|
|
}
|
2006-08-15 22:21:46 +02:00
|
|
|
DPRINTF(Cache, "%s %x %s blk_addr: %x pc %x\n", pkt->cmdString(),
|
|
|
|
pkt->getAddr() & (((ULL(1))<<48)-1), (blk) ? "hit" : "miss",
|
2006-06-29 22:07:19 +02:00
|
|
|
pkt->getAddr() & ~((Addr)blkSize - 1), pkt->req->getPC());
|
2006-06-28 17:02:14 +02:00
|
|
|
if (blk) {
|
|
|
|
// Hit
|
2006-06-28 20:35:00 +02:00
|
|
|
hits[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
|
2006-06-28 17:02:14 +02:00
|
|
|
// clear dirty bit if write through
|
2006-06-28 23:28:33 +02:00
|
|
|
if (pkt->needsResponse())
|
2006-06-28 17:02:14 +02:00
|
|
|
respond(pkt, curTick+lat);
|
2006-06-28 23:28:33 +02:00
|
|
|
// return MA_HIT;
|
|
|
|
return true;
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Miss
|
2006-06-28 20:35:00 +02:00
|
|
|
if (!pkt->req->isUncacheable()) {
|
|
|
|
misses[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
|
2006-06-28 17:02:14 +02:00
|
|
|
/** @todo Move miss count code into BaseCache */
|
|
|
|
if (missCount) {
|
|
|
|
--missCount;
|
|
|
|
if (missCount == 0)
|
2006-06-29 22:07:19 +02:00
|
|
|
new SimLoopExitEvent(curTick, "A cache reached the maximum miss count");
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
missQueue->handleMiss(pkt, size, curTick + hitLatency);
|
2006-06-28 23:28:33 +02:00
|
|
|
// return MA_CACHE_MISS;
|
|
|
|
return true;
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<class TagStore, class Buffering, class Coherence>
|
|
|
|
Packet *
|
|
|
|
Cache<TagStore,Buffering,Coherence>::getPacket()
|
|
|
|
{
|
|
|
|
Packet * pkt = missQueue->getPacket();
|
|
|
|
if (pkt) {
|
2006-06-28 20:35:00 +02:00
|
|
|
if (!pkt->req->isUncacheable()) {
|
2006-06-28 23:28:33 +02:00
|
|
|
if (pkt->cmd == Packet::HardPFReq) misses[Packet::HardPFReq][pkt->req->getThreadNum()]++;
|
2006-06-28 17:02:14 +02:00
|
|
|
BlkType *blk = tags->findBlock(pkt);
|
|
|
|
Packet::Command cmd = coherence->getBusCmd(pkt->cmd,
|
|
|
|
(blk)? blk->status : 0);
|
|
|
|
missQueue->setBusCmd(pkt, cmd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-06-28 23:28:33 +02:00
|
|
|
assert(!doMasterRequest() || missQueue->havePending());
|
2006-06-28 17:02:14 +02:00
|
|
|
assert(!pkt || pkt->time <= curTick);
|
|
|
|
return pkt;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Buffering, class Coherence>
|
|
|
|
void
|
2006-06-28 23:28:33 +02:00
|
|
|
Cache<TagStore,Buffering,Coherence>::sendResult(PacketPtr &pkt, bool success)
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
|
|
|
if (success) {
|
|
|
|
missQueue->markInService(pkt);
|
|
|
|
//Temp Hack for UPGRADES
|
2006-06-28 23:28:33 +02:00
|
|
|
if (pkt->cmd == Packet::UpgradeReq) {
|
2006-06-28 17:02:14 +02:00
|
|
|
handleResponse(pkt);
|
|
|
|
}
|
2006-06-28 20:35:00 +02:00
|
|
|
} else if (pkt && !pkt->req->isUncacheable()) {
|
2006-06-28 17:02:14 +02:00
|
|
|
missQueue->restoreOrigCmd(pkt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Buffering, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Buffering,Coherence>::handleResponse(Packet * &pkt)
|
|
|
|
{
|
|
|
|
BlkType *blk = NULL;
|
|
|
|
if (pkt->senderState) {
|
2006-06-28 23:28:33 +02:00
|
|
|
// MemDebug::cacheResponse(pkt);
|
2006-06-29 22:07:19 +02:00
|
|
|
DPRINTF(Cache, "Handling reponse to %x, blk addr: %x\n",pkt->getAddr(),
|
|
|
|
pkt->getAddr() & (((ULL(1))<<48)-1));
|
2006-06-28 17:02:14 +02:00
|
|
|
|
|
|
|
if (pkt->isCacheFill() && !pkt->isNoAllocate()) {
|
|
|
|
blk = tags->findBlock(pkt);
|
|
|
|
CacheBlk::State old_state = (blk) ? blk->status : 0;
|
2006-06-28 23:28:33 +02:00
|
|
|
PacketList writebacks;
|
2006-06-29 22:07:19 +02:00
|
|
|
blk = tags->handleFill(blk, (MSHR*)pkt->senderState,
|
2006-06-28 17:02:14 +02:00
|
|
|
coherence->getNewState(pkt,old_state),
|
|
|
|
writebacks);
|
|
|
|
while (!writebacks.empty()) {
|
|
|
|
missQueue->doWriteback(writebacks.front());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
missQueue->handleResponse(pkt, curTick + hitLatency);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Buffering, class Coherence>
|
|
|
|
void
|
2006-08-15 22:21:46 +02:00
|
|
|
Cache<TagStore,Buffering,Coherence>::pseudoFill(Addr addr)
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
|
|
|
// Need to temporarily move this blk into MSHRs
|
2006-08-15 22:21:46 +02:00
|
|
|
MSHR *mshr = missQueue->allocateTargetList(addr);
|
2006-06-28 17:02:14 +02:00
|
|
|
int lat;
|
2006-06-28 23:28:33 +02:00
|
|
|
PacketList dummy;
|
2006-06-28 17:02:14 +02:00
|
|
|
// Read the data into the mshr
|
|
|
|
BlkType *blk = tags->handleAccess(mshr->pkt, lat, dummy, false);
|
|
|
|
assert(dummy.empty());
|
2006-06-29 22:07:19 +02:00
|
|
|
assert(mshr->pkt->flags & SATISFIED);
|
2006-06-28 17:02:14 +02:00
|
|
|
// can overload order since it isn't used on non pending blocks
|
|
|
|
mshr->order = blk->status;
|
|
|
|
// temporarily remove the block from the cache.
|
2006-08-15 22:21:46 +02:00
|
|
|
tags->invalidateBlk(addr);
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Buffering, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Buffering,Coherence>::pseudoFill(MSHR *mshr)
|
|
|
|
{
|
|
|
|
// Need to temporarily move this blk into MSHRs
|
2006-06-28 23:28:33 +02:00
|
|
|
assert(mshr->pkt->cmd == Packet::ReadReq);
|
2006-06-28 17:02:14 +02:00
|
|
|
int lat;
|
2006-06-28 23:28:33 +02:00
|
|
|
PacketList dummy;
|
2006-06-28 17:02:14 +02:00
|
|
|
// Read the data into the mshr
|
|
|
|
BlkType *blk = tags->handleAccess(mshr->pkt, lat, dummy, false);
|
|
|
|
assert(dummy.empty());
|
2006-06-29 22:07:19 +02:00
|
|
|
assert(mshr->pkt->flags & SATISFIED);
|
2006-06-28 17:02:14 +02:00
|
|
|
// can overload order since it isn't used on non pending blocks
|
|
|
|
mshr->order = blk->status;
|
|
|
|
// temporarily remove the block from the cache.
|
2006-08-15 22:21:46 +02:00
|
|
|
tags->invalidateBlk(mshr->pkt->getAddr());
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<class TagStore, class Buffering, class Coherence>
|
|
|
|
Packet *
|
2006-07-06 22:52:05 +02:00
|
|
|
Cache<TagStore,Buffering,Coherence>::getCoherencePacket()
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
|
|
|
return coherence->getPacket();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<class TagStore, class Buffering, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Buffering,Coherence>::snoop(Packet * &pkt)
|
|
|
|
{
|
2006-10-06 03:10:03 +02:00
|
|
|
DPRINTF(Cache, "SNOOPING");
|
2006-06-29 22:07:19 +02:00
|
|
|
Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1));
|
2006-06-28 17:02:14 +02:00
|
|
|
BlkType *blk = tags->findBlock(pkt);
|
2006-08-15 22:21:46 +02:00
|
|
|
MSHR *mshr = missQueue->findMSHR(blk_addr);
|
2006-06-28 17:02:14 +02:00
|
|
|
if (isTopLevel() && coherence->hasProtocol()) { //@todo Move this into handle bus req
|
|
|
|
//If we find an mshr, and it is in service, we need to NACK or invalidate
|
|
|
|
if (mshr) {
|
|
|
|
if (mshr->inService) {
|
2006-06-28 23:28:33 +02:00
|
|
|
if ((mshr->pkt->isInvalidate() || !mshr->pkt->isCacheFill())
|
|
|
|
&& (pkt->cmd != Packet::InvalidateReq && pkt->cmd != Packet::WriteInvalidateReq)) {
|
2006-06-28 17:02:14 +02:00
|
|
|
//If the outstanding request was an invalidate (upgrade,readex,..)
|
|
|
|
//Then we need to ACK the request until we get the data
|
|
|
|
//Also NACK if the outstanding request is not a cachefill (writeback)
|
2006-10-06 03:10:03 +02:00
|
|
|
pkt->flags |= SATISFIED;
|
2006-06-29 22:07:19 +02:00
|
|
|
pkt->flags |= NACKED_LINE;
|
2006-10-06 03:10:03 +02:00
|
|
|
assert("Don't detect these on the other side yet\n");
|
|
|
|
respondToSnoop(pkt, curTick + hitLatency);
|
2006-06-28 17:02:14 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
//The supplier will be someone else, because we are waiting for
|
|
|
|
//the data. This should cause this cache to be forced to go to
|
|
|
|
//the shared state, not the exclusive even though the shared line
|
|
|
|
//won't be asserted. But for now we will just invlidate ourselves
|
|
|
|
//and allow the other cache to go into the exclusive state.
|
|
|
|
//@todo Make it so a read to a pending read doesn't invalidate.
|
|
|
|
//@todo Make it so that a read to a pending read can't be exclusive now.
|
|
|
|
|
|
|
|
//Set the address so find match works
|
2006-10-06 03:10:03 +02:00
|
|
|
assert("Don't have invalidates yet\n");
|
2006-06-29 22:07:19 +02:00
|
|
|
invalidatePkt->addrOverride(pkt->getAddr());
|
2006-06-28 17:02:14 +02:00
|
|
|
|
|
|
|
//Append the invalidate on
|
|
|
|
missQueue->addTarget(mshr,invalidatePkt);
|
2006-06-29 22:07:19 +02:00
|
|
|
DPRINTF(Cache, "Appending Invalidate to blk_addr: %x\n", pkt->getAddr() & (((ULL(1))<<48)-1));
|
2006-06-28 17:02:14 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//We also need to check the writeback buffers and handle those
|
|
|
|
std::vector<MSHR *> writebacks;
|
2006-08-15 22:21:46 +02:00
|
|
|
if (missQueue->findWrites(blk_addr, writebacks)) {
|
2006-06-29 22:07:19 +02:00
|
|
|
DPRINTF(Cache, "Snoop hit in writeback to blk_addr: %x\n", pkt->getAddr() & (((ULL(1))<<48)-1));
|
2006-06-28 17:02:14 +02:00
|
|
|
|
|
|
|
//Look through writebacks for any non-uncachable writes, use that
|
|
|
|
for (int i=0; i<writebacks.size(); i++) {
|
|
|
|
mshr = writebacks[i];
|
|
|
|
|
2006-06-28 20:35:00 +02:00
|
|
|
if (!mshr->pkt->req->isUncacheable()) {
|
2006-06-28 23:28:33 +02:00
|
|
|
if (pkt->isRead()) {
|
2006-06-28 17:02:14 +02:00
|
|
|
//Only Upgrades don't get here
|
|
|
|
//Supply the data
|
2006-06-29 22:07:19 +02:00
|
|
|
pkt->flags |= SATISFIED;
|
2006-06-28 17:02:14 +02:00
|
|
|
|
|
|
|
//If we are in an exclusive protocol, make it ask again
|
|
|
|
//to get write permissions (upgrade), signal shared
|
2006-06-29 22:07:19 +02:00
|
|
|
pkt->flags |= SHARED_LINE;
|
2006-06-28 17:02:14 +02:00
|
|
|
|
2006-06-28 23:28:33 +02:00
|
|
|
assert(pkt->isRead());
|
2006-06-29 22:07:19 +02:00
|
|
|
Addr offset = pkt->getAddr() & ~(blkSize - 1);
|
|
|
|
assert(offset < blkSize);
|
|
|
|
assert(pkt->getSize() <= blkSize);
|
|
|
|
assert(offset + pkt->getSize() <=blkSize);
|
|
|
|
memcpy(pkt->getPtr<uint8_t>(), mshr->pkt->getPtr<uint8_t>() + offset, pkt->getSize());
|
2006-06-28 17:02:14 +02:00
|
|
|
|
2006-10-06 03:10:03 +02:00
|
|
|
respondToSnoop(pkt, curTick + hitLatency);
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
|
2006-06-28 23:28:33 +02:00
|
|
|
if (pkt->isInvalidate()) {
|
2006-06-28 17:02:14 +02:00
|
|
|
//This must be an upgrade or other cache will take ownership
|
|
|
|
missQueue->markInService(mshr->pkt);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CacheBlk::State new_state;
|
|
|
|
bool satisfy = coherence->handleBusRequest(pkt,blk,mshr, new_state);
|
|
|
|
if (satisfy) {
|
|
|
|
tags->handleSnoop(blk, new_state, pkt);
|
2006-10-06 03:10:03 +02:00
|
|
|
respondToSnoop(pkt, curTick + hitLatency);
|
2006-06-28 17:02:14 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
tags->handleSnoop(blk, new_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Buffering, class Coherence>
|
|
|
|
void
|
|
|
|
Cache<TagStore,Buffering,Coherence>::snoopResponse(Packet * &pkt)
|
|
|
|
{
|
|
|
|
//Need to handle the response, if NACKED
|
2006-06-29 22:07:19 +02:00
|
|
|
if (pkt->flags & NACKED_LINE) {
|
2006-06-28 17:02:14 +02:00
|
|
|
//Need to mark it as not in service, and retry for bus
|
|
|
|
assert(0); //Yeah, we saw a NACK come through
|
|
|
|
|
|
|
|
//For now this should never get called, we return false when we see a NACK
|
|
|
|
//instead, by doing this we allow the bus_blocked mechanism to handle the retry
|
|
|
|
//For now it retrys in just 2 cycles, need to figure out how to change that
|
|
|
|
//Eventually we will want to also have success come in as a parameter
|
|
|
|
//Need to make sure that we handle the functionality that happens on successufl
|
|
|
|
//return of the sendAddr function
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Buffering, class Coherence>
|
|
|
|
void
|
2006-08-15 22:21:46 +02:00
|
|
|
Cache<TagStore,Buffering,Coherence>::invalidateBlk(Addr addr)
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
2006-08-15 22:21:46 +02:00
|
|
|
tags->invalidateBlk(addr);
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @todo Fix to not assume write allocate
|
|
|
|
*/
|
|
|
|
template<class TagStore, class Buffering, class Coherence>
|
|
|
|
Tick
|
|
|
|
Cache<TagStore,Buffering,Coherence>::probe(Packet * &pkt, bool update)
|
|
|
|
{
|
2006-06-28 23:28:33 +02:00
|
|
|
// MemDebug::cacheProbe(pkt);
|
2006-06-28 20:35:00 +02:00
|
|
|
if (!pkt->req->isUncacheable()) {
|
2006-06-28 23:28:33 +02:00
|
|
|
if (pkt->isInvalidate() && !pkt->isRead()
|
|
|
|
&& !pkt->isWrite()) {
|
2006-06-28 17:02:14 +02:00
|
|
|
//Upgrade or Invalidate, satisfy it, don't forward
|
2006-08-15 22:21:46 +02:00
|
|
|
DPRINTF(Cache, "%s %x ? blk_addr: %x\n", pkt->cmdString(),
|
|
|
|
pkt->getAddr() & (((ULL(1))<<48)-1),
|
2006-06-29 22:07:19 +02:00
|
|
|
pkt->getAddr() & ~((Addr)blkSize - 1));
|
|
|
|
pkt->flags |= SATISFIED;
|
2006-06-28 17:02:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-06-28 23:28:33 +02:00
|
|
|
PacketList writebacks;
|
2006-06-28 17:02:14 +02:00
|
|
|
int lat;
|
|
|
|
BlkType *blk = tags->handleAccess(pkt, lat, writebacks, update);
|
|
|
|
|
|
|
|
if (!blk) {
|
|
|
|
// Need to check for outstanding misses and writes
|
2006-06-29 22:07:19 +02:00
|
|
|
Addr blk_addr = pkt->getAddr() & ~(blkSize - 1);
|
2006-06-28 17:02:14 +02:00
|
|
|
|
|
|
|
// There can only be one matching outstanding miss.
|
2006-08-15 22:21:46 +02:00
|
|
|
MSHR* mshr = missQueue->findMSHR(blk_addr);
|
2006-06-28 17:02:14 +02:00
|
|
|
|
|
|
|
// There can be many matching outstanding writes.
|
2006-08-15 11:07:15 +02:00
|
|
|
std::vector<MSHR*> writes;
|
2006-08-15 22:21:46 +02:00
|
|
|
missQueue->findWrites(blk_addr, writes);
|
2006-06-28 17:02:14 +02:00
|
|
|
|
|
|
|
if (!update) {
|
2006-10-06 03:10:03 +02:00
|
|
|
memSidePort->sendFunctional(pkt);
|
2006-06-28 17:02:14 +02:00
|
|
|
// Check for data in MSHR and writebuffer.
|
|
|
|
if (mshr) {
|
|
|
|
warn("Found outstanding miss on an non-update probe");
|
|
|
|
MSHR::TargetList *targets = mshr->getTargetList();
|
|
|
|
MSHR::TargetList::iterator i = targets->begin();
|
|
|
|
MSHR::TargetList::iterator end = targets->end();
|
|
|
|
for (; i != end; ++i) {
|
|
|
|
Packet * target = *i;
|
|
|
|
// If the target contains data, and it overlaps the
|
|
|
|
// probed request, need to update data
|
2006-06-29 22:07:19 +02:00
|
|
|
if (target->isWrite() && target->intersect(pkt)) {
|
2006-06-28 17:02:14 +02:00
|
|
|
uint8_t* pkt_data;
|
|
|
|
uint8_t* write_data;
|
|
|
|
int data_size;
|
2006-06-29 22:07:19 +02:00
|
|
|
if (target->getAddr() < pkt->getAddr()) {
|
|
|
|
int offset = pkt->getAddr() - target->getAddr();
|
|
|
|
pkt_data = pkt->getPtr<uint8_t>();
|
|
|
|
write_data = target->getPtr<uint8_t>() + offset;
|
|
|
|
data_size = target->getSize() - offset;
|
2006-06-28 17:02:14 +02:00
|
|
|
assert(data_size > 0);
|
2006-06-29 22:07:19 +02:00
|
|
|
if (data_size > pkt->getSize())
|
|
|
|
data_size = pkt->getSize();
|
2006-06-28 17:02:14 +02:00
|
|
|
} else {
|
2006-06-29 22:07:19 +02:00
|
|
|
int offset = target->getAddr() - pkt->getAddr();
|
|
|
|
pkt_data = pkt->getPtr<uint8_t>() + offset;
|
|
|
|
write_data = target->getPtr<uint8_t>();
|
|
|
|
data_size = pkt->getSize() - offset;
|
|
|
|
assert(data_size > pkt->getSize());
|
|
|
|
if (data_size > target->getSize())
|
|
|
|
data_size = target->getSize();
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
|
2006-06-28 23:28:33 +02:00
|
|
|
if (pkt->isWrite()) {
|
2006-06-28 17:02:14 +02:00
|
|
|
memcpy(pkt_data, write_data, data_size);
|
|
|
|
} else {
|
|
|
|
memcpy(write_data, pkt_data, data_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int i = 0; i < writes.size(); ++i) {
|
|
|
|
Packet * write = writes[i]->pkt;
|
2006-06-29 22:07:19 +02:00
|
|
|
if (write->intersect(pkt)) {
|
2006-06-28 17:02:14 +02:00
|
|
|
warn("Found outstanding write on an non-update probe");
|
|
|
|
uint8_t* pkt_data;
|
|
|
|
uint8_t* write_data;
|
|
|
|
int data_size;
|
2006-06-29 22:07:19 +02:00
|
|
|
if (write->getAddr() < pkt->getAddr()) {
|
|
|
|
int offset = pkt->getAddr() - write->getAddr();
|
|
|
|
pkt_data = pkt->getPtr<uint8_t>();
|
|
|
|
write_data = write->getPtr<uint8_t>() + offset;
|
|
|
|
data_size = write->getSize() - offset;
|
2006-06-28 17:02:14 +02:00
|
|
|
assert(data_size > 0);
|
2006-06-29 22:07:19 +02:00
|
|
|
if (data_size > pkt->getSize())
|
|
|
|
data_size = pkt->getSize();
|
2006-06-28 17:02:14 +02:00
|
|
|
} else {
|
2006-06-29 22:07:19 +02:00
|
|
|
int offset = write->getAddr() - pkt->getAddr();
|
|
|
|
pkt_data = pkt->getPtr<uint8_t>() + offset;
|
|
|
|
write_data = write->getPtr<uint8_t>();
|
|
|
|
data_size = pkt->getSize() - offset;
|
|
|
|
assert(data_size > pkt->getSize());
|
|
|
|
if (data_size > write->getSize())
|
|
|
|
data_size = write->getSize();
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
|
2006-06-28 23:28:33 +02:00
|
|
|
if (pkt->isWrite()) {
|
2006-06-28 17:02:14 +02:00
|
|
|
memcpy(pkt_data, write_data, data_size);
|
|
|
|
} else {
|
|
|
|
memcpy(write_data, pkt_data, data_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
// update the cache state and statistics
|
|
|
|
if (mshr || !writes.empty()){
|
|
|
|
// Can't handle it, return pktuest unsatisfied.
|
|
|
|
return 0;
|
|
|
|
}
|
2006-06-28 20:35:00 +02:00
|
|
|
if (!pkt->req->isUncacheable()) {
|
2006-06-28 17:02:14 +02:00
|
|
|
// Fetch the cache block to fill
|
|
|
|
BlkType *blk = tags->findBlock(pkt);
|
2006-06-29 22:07:19 +02:00
|
|
|
Packet::Command temp_cmd = coherence->getBusCmd(pkt->cmd,
|
2006-06-28 17:02:14 +02:00
|
|
|
(blk)? blk->status : 0);
|
|
|
|
|
2006-06-29 22:07:19 +02:00
|
|
|
Packet * busPkt = new Packet(pkt->req,temp_cmd, -1, blkSize);
|
|
|
|
|
2006-06-30 17:34:27 +02:00
|
|
|
busPkt->allocate();
|
2006-06-29 22:07:19 +02:00
|
|
|
|
2006-06-28 17:02:14 +02:00
|
|
|
busPkt->time = curTick;
|
|
|
|
|
2006-06-29 22:07:19 +02:00
|
|
|
lat = memSidePort->sendAtomic(busPkt);
|
2006-06-28 17:02:14 +02:00
|
|
|
|
2006-06-30 23:21:58 +02:00
|
|
|
/* if (!(busPkt->flags & SATISFIED)) {
|
2006-06-28 17:02:14 +02:00
|
|
|
// blocked at a higher level, just return
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-06-30 23:21:58 +02:00
|
|
|
*/ misses[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
|
2006-06-28 17:02:14 +02:00
|
|
|
|
|
|
|
CacheBlk::State old_state = (blk) ? blk->status : 0;
|
|
|
|
tags->handleFill(blk, busPkt,
|
|
|
|
coherence->getNewState(busPkt, old_state),
|
|
|
|
writebacks, pkt);
|
|
|
|
// Handle writebacks if needed
|
|
|
|
while (!writebacks.empty()){
|
2006-06-29 22:07:19 +02:00
|
|
|
memSidePort->sendAtomic(writebacks.front());
|
2006-06-28 17:02:14 +02:00
|
|
|
writebacks.pop_front();
|
|
|
|
}
|
|
|
|
return lat + hitLatency;
|
|
|
|
} else {
|
2006-06-29 22:07:19 +02:00
|
|
|
return memSidePort->sendAtomic(pkt);
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// There was a cache hit.
|
|
|
|
// Handle writebacks if needed
|
|
|
|
while (!writebacks.empty()){
|
2006-06-29 22:07:19 +02:00
|
|
|
memSidePort->sendAtomic(writebacks.front());
|
2006-06-28 17:02:14 +02:00
|
|
|
writebacks.pop_front();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (update) {
|
2006-06-28 20:35:00 +02:00
|
|
|
hits[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
|
2006-06-28 23:28:33 +02:00
|
|
|
} else if (pkt->isWrite()) {
|
2006-06-28 17:02:14 +02:00
|
|
|
// Still need to change data in all locations.
|
2006-06-29 22:07:19 +02:00
|
|
|
return memSidePort->sendAtomic(pkt);
|
2006-06-28 17:02:14 +02:00
|
|
|
}
|
|
|
|
return curTick + lat;
|
|
|
|
}
|
|
|
|
fatal("Probe not handled.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class TagStore, class Buffering, class Coherence>
|
|
|
|
Tick
|
2006-06-28 23:28:33 +02:00
|
|
|
Cache<TagStore,Buffering,Coherence>::snoopProbe(PacketPtr &pkt, bool update)
|
2006-06-28 17:02:14 +02:00
|
|
|
{
|
2006-06-29 22:07:19 +02:00
|
|
|
Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1));
|
2006-06-28 17:02:14 +02:00
|
|
|
BlkType *blk = tags->findBlock(pkt);
|
2006-08-15 22:21:46 +02:00
|
|
|
MSHR *mshr = missQueue->findMSHR(blk_addr);
|
2006-06-28 17:02:14 +02:00
|
|
|
CacheBlk::State new_state = 0;
|
2006-06-29 22:07:19 +02:00
|
|
|
bool satisfy = coherence->handleBusRequest(pkt,blk,mshr, new_state);
|
2006-06-28 17:02:14 +02:00
|
|
|
if (satisfy) {
|
|
|
|
tags->handleSnoop(blk, new_state, pkt);
|
|
|
|
return hitLatency;
|
|
|
|
}
|
|
|
|
tags->handleSnoop(blk, new_state);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|