/*
+ * Copyright (c) 2012-2013 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.
+ *
* Copyright (c) 2003-2005 The Regents of The University of Michigan
* All rights reserved.
*
#ifndef __BASE_CACHE_HH__
#define __BASE_CACHE_HH__
-#include <vector>
-#include <string>
-#include <list>
#include <algorithm>
-#include <inttypes.h>
+#include <list>
+#include <string>
+#include <vector>
#include "base/misc.hh"
#include "base/statistics.hh"
#include "base/trace.hh"
+#include "base/types.hh"
+#include "debug/Cache.hh"
+#include "debug/CachePort.hh"
#include "mem/cache/mshr_queue.hh"
#include "mem/mem_object.hh"
#include "mem/packet.hh"
-#include "mem/tport.hh"
+#include "mem/qport.hh"
#include "mem/request.hh"
#include "params/BaseCache.hh"
#include "sim/eventq.hh"
+#include "sim/full_system.hh"
#include "sim/sim_exit.hh"
+#include "sim/system.hh"
class MSHR;
/**
MSHRQueue_WriteBuffer
};
+ public:
/**
* Reasons for caches to be blocked.
*/
Blocked_NoMSHRs = MSHRQueue_MSHRs,
Blocked_NoWBBuffers = MSHRQueue_WriteBuffer,
Blocked_NoTargets,
+ Blocked_PendingWriteInvalidate,
NUM_BLOCKED_CAUSES
};
- public:
/**
* Reasons for cache to request a bus.
*/
NUM_REQUEST_CAUSES
};
- private:
+ protected:
- class CachePort : public SimpleTimingPort
+ /**
+ * A cache master port is used for the memory-side port of the
+ * cache, and in addition to the basic timing port that only sends
+ * response packets through a transmit list, it also offers the
+ * ability to schedule and send request packets (requests &
+ * writebacks). The send event is scheduled through requestBus,
+ * and the sendDeferredPacket of the timing port is modified to
+ * consider both the transmit list and the requests from the MSHR.
+ */
+ class CacheMasterPort : public QueuedMasterPort
{
- public:
- BaseCache *cache;
-
- protected:
- CachePort(const std::string &_name, BaseCache *_cache,
- const std::string &_label);
- virtual void recvStatusChange(Status status);
+ public:
- virtual int deviceBlockSize();
+ /**
+ * Schedule a send of a request packet (from the MSHR). Note
+ * that we could already have a retry or a transmit list of
+ * responses outstanding.
+ */
+ void requestBus(RequestCause cause, Tick time)
+ {
+ DPRINTF(CachePort, "Asserting bus request for cause %d\n", cause);
+ queue.schedSendEvent(time);
+ }
- bool recvRetryCommon();
+ protected:
- typedef EventWrapper<Port, &Port::sendRetry>
- SendRetryEvent;
+ CacheMasterPort(const std::string &_name, BaseCache *_cache,
+ MasterPacketQueue &_queue) :
+ QueuedMasterPort(_name, _cache, _queue)
+ { }
+
+ /**
+ * Memory-side port always snoops.
+ *
+ * @return always true
+ */
+ virtual bool isSnooping() const { return true; }
+ };
- const std::string label;
+ /**
+ * A cache slave port is used for the CPU-side port of the cache,
+ * and it is basically a simple timing port that uses a transmit
+ * list for responses to the CPU (or connected master). In
+ * addition, it has the functionality to block the port for
+ * incoming requests. If blocked, the port will issue a retry once
+ * unblocked.
+ */
+ class CacheSlavePort : public QueuedSlavePort
+ {
public:
- void setOtherPort(CachePort *_otherPort) { otherPort = _otherPort; }
+ /** Do not accept any new requests. */
void setBlocked();
+ /** Return to normal operation and accept new requests. */
void clearBlocked();
- bool checkFunctional(PacketPtr pkt);
+ bool isBlocked() const { return blocked; }
- CachePort *otherPort;
+ protected:
+
+ CacheSlavePort(const std::string &_name, BaseCache *_cache,
+ const std::string &_label);
+
+ /** A normal packet queue used to store responses. */
+ SlavePacketQueue queue;
bool blocked;
bool mustSendRetry;
- void requestBus(RequestCause cause, Tick time)
- {
- DPRINTF(CachePort, "Asserting bus request for cause %d\n", cause);
- if (!waitingOnRetry) {
- schedSendEvent(time);
- }
- }
+ private:
+
+ void processSendRetry();
+
+ EventWrapper<CacheSlavePort,
+ &CacheSlavePort::processSendRetry> sendRetryEvent;
- void respond(PacketPtr pkt, Tick time) {
- schedSendTiming(pkt, time);
- }
};
- public: //Made public so coherence can get at it.
- CachePort *cpuSidePort;
- CachePort *memSidePort;
+ CacheSlavePort *cpuSidePort;
+ CacheMasterPort *memSidePort;
protected:
return mshr;
}
- void markInServiceInternal(MSHR *mshr)
+ void markInServiceInternal(MSHR *mshr, PacketPtr pkt)
{
MSHRQueue *mq = mshr->queue;
bool wasFull = mq->isFull();
- mq->markInService(mshr);
+ mq->markInService(mshr, pkt);
if (wasFull && !mq->isFull()) {
clearBlocked((BlockedCause)mq->index);
}
}
+ /**
+ * Write back dirty blocks in the cache using functional accesses.
+ */
+ virtual void memWriteback() = 0;
+ /**
+ * Invalidates all blocks in the cache.
+ *
+ * @warn Dirty cache lines will not be written back to
+ * memory. Make sure to call functionalWriteback() first if you
+ * want the to write them to memory.
+ */
+ virtual void memInvalidate() = 0;
+ /**
+ * Determine if there are any dirty blocks in the cache.
+ *
+ * \return true if at least one block is dirty, false otherwise.
+ */
+ virtual bool isDirty() const = 0;
+
/** Block size of this cache */
- const int blkSize;
+ const unsigned blkSize;
/**
* The latency of a hit in this device.
*/
- int hitLatency;
+ const Cycles hitLatency;
+
+ /**
+ * The latency of sending reponse to its upper level cache/core on a
+ * linefill. In most contemporary processors, the return path on a cache
+ * miss is much quicker that the hit latency. The responseLatency parameter
+ * tries to capture this latency.
+ */
+ const Cycles responseLatency;
/** The number of targets for each MSHR. */
const int numTarget;
/** Do we forward snoops from mem side port through to cpu side port? */
- bool forwardSnoops;
+ const bool forwardSnoops;
+
+ /** Is this cache a toplevel cache (e.g. L1, I/O cache). If so we should
+ * never try to forward ownership and similar optimizations to the cpu
+ * side */
+ const bool isTopLevel;
/**
* Bit vector of the blocking reasons for the access path.
uint64_t order;
/** Stores time the cache blocked for statistics. */
- Tick blockedCycle;
+ Cycles blockedCycle;
/** Pointer to the MSHR that has no targets. */
MSHR *noTargetMSHR;
/** The number of misses to trigger an exit event. */
Counter missCount;
- /** The drain event. */
- Event *drainEvent;
-
/**
* The address range to which the cache responds on the CPU side.
* Normally this is all possible memory addresses. */
- Range<Addr> addrRange;
+ const AddrRangeList addrRanges;
public:
+ /** System we are currently operating in. */
+ System *system;
+
// Statistics
/**
* @addtogroup CacheStatistics
/** Total cycle latency of overall MSHR misses. */
Stats::Formula overallMshrUncacheableLatency;
+#if 0
/** The total number of MSHR accesses per command and thread. */
Stats::Formula mshrAccesses[MemCmd::NUM_MEM_CMDS];
/** The total number of demand MSHR accesses. */
Stats::Formula demandMshrAccesses;
/** The total number of MSHR accesses. */
Stats::Formula overallMshrAccesses;
+#endif
/** The miss rate in the MSHRs pre command and thread. */
Stats::Formula mshrMissRate[MemCmd::NUM_MEM_CMDS];
virtual void init();
+ virtual BaseMasterPort &getMasterPort(const std::string &if_name,
+ PortID idx = InvalidPortID);
+ virtual BaseSlavePort &getSlavePort(const std::string &if_name,
+ PortID idx = InvalidPortID);
+
/**
* Query block size of a cache.
* @return The block size
*/
- int getBlockSize() const
+ unsigned
+ getBlockSize() const
{
return blkSize;
}
- Addr blockAlign(Addr addr) const { return (addr & ~(blkSize - 1)); }
+ Addr blockAlign(Addr addr) const { return (addr & ~(Addr(blkSize - 1))); }
- const Range<Addr> &getAddrRange() const { return addrRange; }
+ const AddrRangeList &getAddrRanges() const { return addrRanges; }
MSHR *allocateMissBuffer(PacketPtr pkt, Tick time, bool requestBus)
{
/**
* Returns true if the cache is blocked for accesses.
*/
- bool isBlocked()
+ bool isBlocked() const
{
return blocked != 0;
}
uint8_t flag = 1 << cause;
if (blocked == 0) {
blocked_causes[cause]++;
- blockedCycle = curTick;
+ blockedCycle = curCycle();
cpuSidePort->setBlocked();
}
blocked |= flag;
blocked &= ~flag;
DPRINTF(Cache,"Unblocking for cause %d, mask=%d\n", cause, blocked);
if (blocked == 0) {
- blocked_cycles[cause] += curTick - blockedCycle;
+ blocked_cycles[cause] += curCycle() - blockedCycle;
cpuSidePort->clearBlocked();
}
}
// interesting again.
}
- virtual unsigned int drain(Event *de);
+ virtual unsigned int drain(DrainManager *dm);
- virtual bool inCache(Addr addr) = 0;
+ virtual bool inCache(Addr addr, bool is_secure) const = 0;
- virtual bool inMissQueue(Addr addr) = 0;
+ virtual bool inMissQueue(Addr addr, bool is_secure) const = 0;
void incMissCount(PacketPtr pkt)
{
- misses[pkt->cmdToIndex()][0/*pkt->req->threadId()*/]++;
-
+ assert(pkt->req->masterId() < system->maxMasters());
+ misses[pkt->cmdToIndex()][pkt->req->masterId()]++;
+ pkt->req->incAccessDepth();
if (missCount) {
--missCount;
if (missCount == 0)
exitSimLoop("A cache reached the maximum miss count");
}
}
+ void incHitCount(PacketPtr pkt)
+ {
+ assert(pkt->req->masterId() < system->maxMasters());
+ hits[pkt->cmdToIndex()][pkt->req->masterId()]++;
+
+ }
};