First set of changes for reorganized cache coherence support.
Compiles but doesn't work... committing just so I can merge
(stupid bk!).
src/mem/bridge.cc:
Get rid of SNOOP_COMMIT.
src/mem/bus.cc:
src/mem/packet.hh:
Get rid of SNOOP_COMMIT & two-pass snoop.
First bits of EXPRESS_SNOOP support.
src/mem/cache/base_cache.cc:
src/mem/cache/base_cache.hh:
src/mem/cache/cache.hh:
src/mem/cache/cache_impl.hh:
src/mem/cache/miss/blocking_buffer.cc:
src/mem/cache/miss/miss_queue.cc:
src/mem/cache/prefetch/base_prefetcher.cc:
Big reorg of ports and port-related functions & events.
src/mem/cache/cache.cc:
src/mem/cache/cache_builder.cc:
src/mem/cache/coherence/SConscript:
Get rid of UniCoherence object.
--HG--
extra : convert_revision : 7672434fa3115c9b1c94686f497e57e90413b7c3
This commit is contained in:
317
src/mem/cache/base_cache.cc
vendored
317
src/mem/cache/base_cache.cc
vendored
@@ -40,29 +40,38 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache,
|
||||
bool _isCpuSide)
|
||||
: Port(_name, _cache), cache(_cache), isCpuSide(_isCpuSide)
|
||||
BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache)
|
||||
: Port(_name, _cache), cache(_cache), otherPort(NULL)
|
||||
{
|
||||
blocked = false;
|
||||
waitingOnRetry = false;
|
||||
//Start ports at null if more than one is created we should panic
|
||||
//cpuSidePort = NULL;
|
||||
//memSidePort = NULL;
|
||||
}
|
||||
|
||||
|
||||
BaseCache::BaseCache(const std::string &name, Params ¶ms)
|
||||
: MemObject(name),
|
||||
blocked(0), blockedSnoop(0),
|
||||
blkSize(params.blkSize),
|
||||
missCount(params.maxMisses), drainEvent(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
BaseCache::CachePort::recvStatusChange(Port::Status status)
|
||||
{
|
||||
cache->recvStatusChange(status, isCpuSide);
|
||||
if (status == Port::RangeChange) {
|
||||
otherPort->sendStatusChange(Port::RangeChange);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BaseCache::CachePort::getDeviceAddressRanges(AddrRangeList &resp,
|
||||
AddrRangeList &snoop)
|
||||
{
|
||||
cache->getAddressRanges(resp, snoop, isCpuSide);
|
||||
AddrRangeList dummy;
|
||||
otherPort->getPeerAddressRanges(resp, dummy);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -115,92 +124,99 @@ BaseCache::CachePort::checkAndSendFunctional(PacketPtr pkt)
|
||||
sendFunctional(pkt);
|
||||
}
|
||||
|
||||
void
|
||||
BaseCache::CachePort::recvRetry()
|
||||
{
|
||||
PacketPtr pkt;
|
||||
assert(waitingOnRetry);
|
||||
if (!drainList.empty()) {
|
||||
DPRINTF(CachePort, "%s attempting to send a retry for response (%i waiting)\n"
|
||||
, name(), drainList.size());
|
||||
//We have some responses to drain first
|
||||
pkt = drainList.front();
|
||||
drainList.pop_front();
|
||||
if (sendTiming(pkt)) {
|
||||
DPRINTF(CachePort, "%s sucessful in sending a retry for"
|
||||
"response (%i still waiting)\n", name(), drainList.size());
|
||||
if (!drainList.empty() ||
|
||||
!isCpuSide && cache->doMasterRequest() ||
|
||||
isCpuSide && cache->doSlaveRequest()) {
|
||||
|
||||
DPRINTF(CachePort, "%s has more responses/requests\n", name());
|
||||
new BaseCache::RequestEvent(this, curTick + 1);
|
||||
}
|
||||
waitingOnRetry = false;
|
||||
}
|
||||
else {
|
||||
drainList.push_front(pkt);
|
||||
}
|
||||
// Check if we're done draining once this list is empty
|
||||
if (drainList.empty())
|
||||
cache->checkDrain();
|
||||
}
|
||||
else if (!isCpuSide)
|
||||
{
|
||||
DPRINTF(CachePort, "%s attempting to send a retry for MSHR\n", name());
|
||||
if (!cache->doMasterRequest()) {
|
||||
//This can happen if I am the owner of a block and see an upgrade
|
||||
//while the block was in my WB Buffers. I just remove the
|
||||
//wb and de-assert the masterRequest
|
||||
waitingOnRetry = false;
|
||||
void
|
||||
BaseCache::CachePort::respond(PacketPtr pkt, Tick time)
|
||||
{
|
||||
assert(time >= curTick);
|
||||
if (pkt->needsResponse()) {
|
||||
if (transmitList.empty()) {
|
||||
assert(!responseEvent->scheduled());
|
||||
responseEvent->schedule(time);
|
||||
transmitList.push_back(std::pair<Tick,PacketPtr>(time,pkt));
|
||||
return;
|
||||
}
|
||||
pkt = cache->getPacket();
|
||||
MSHR* mshr = (MSHR*) pkt->senderState;
|
||||
//Copy the packet, it may be modified/destroyed elsewhere
|
||||
PacketPtr copyPkt = new Packet(*pkt);
|
||||
copyPkt->dataStatic<uint8_t>(pkt->getPtr<uint8_t>());
|
||||
mshr->pkt = copyPkt;
|
||||
|
||||
bool success = sendTiming(pkt);
|
||||
DPRINTF(Cache, "Address %x was %s in sending the timing request\n",
|
||||
pkt->getAddr(), success ? "succesful" : "unsuccesful");
|
||||
|
||||
waitingOnRetry = !success;
|
||||
if (waitingOnRetry) {
|
||||
DPRINTF(CachePort, "%s now waiting on a retry\n", name());
|
||||
// something is on the list and this belongs at the end
|
||||
if (time >= transmitList.back().first) {
|
||||
transmitList.push_back(std::pair<Tick,PacketPtr>(time,pkt));
|
||||
return;
|
||||
}
|
||||
// Something is on the list and this belongs somewhere else
|
||||
std::list<std::pair<Tick,PacketPtr> >::iterator i =
|
||||
transmitList.begin();
|
||||
std::list<std::pair<Tick,PacketPtr> >::iterator end =
|
||||
transmitList.end();
|
||||
bool done = false;
|
||||
|
||||
cache->sendResult(pkt, mshr, success);
|
||||
|
||||
if (success && cache->doMasterRequest())
|
||||
{
|
||||
DPRINTF(CachePort, "%s has more requests\n", name());
|
||||
//Still more to issue, rerequest in 1 cycle
|
||||
new BaseCache::RequestEvent(this, curTick + 1);
|
||||
while (i != end && !done) {
|
||||
if (time < i->first) {
|
||||
if (i == transmitList.begin()) {
|
||||
//Inserting at begining, reschedule
|
||||
responseEvent->reschedule(time);
|
||||
}
|
||||
transmitList.insert(i,std::pair<Tick,PacketPtr>(time,pkt));
|
||||
done = true;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(cache->doSlaveRequest());
|
||||
//pkt = cache->getCoherencePacket();
|
||||
//We save the packet, no reordering on CSHRS
|
||||
pkt = cache->getCoherencePacket();
|
||||
MSHR* cshr = (MSHR*)pkt->senderState;
|
||||
bool success = sendTiming(pkt);
|
||||
cache->sendCoherenceResult(pkt, cshr, success);
|
||||
waitingOnRetry = !success;
|
||||
if (success && cache->doSlaveRequest())
|
||||
else {
|
||||
assert(0);
|
||||
// this code was on the cpuSidePort only... do we still need it?
|
||||
if (pkt->cmd != MemCmd::UpgradeReq)
|
||||
{
|
||||
DPRINTF(CachePort, "%s has more requests\n", name());
|
||||
//Still more to issue, rerequest in 1 cycle
|
||||
new BaseCache::RequestEvent(this, curTick + 1);
|
||||
delete pkt->req;
|
||||
delete pkt;
|
||||
}
|
||||
}
|
||||
if (waitingOnRetry) DPRINTF(CachePort, "%s STILL Waiting on retry\n", name());
|
||||
else DPRINTF(CachePort, "%s no longer waiting on retry\n", name());
|
||||
return;
|
||||
}
|
||||
|
||||
bool
|
||||
BaseCache::CachePort::drainResponse()
|
||||
{
|
||||
DPRINTF(CachePort,
|
||||
"%s attempting to send a retry for response (%i waiting)\n",
|
||||
name(), drainList.size());
|
||||
//We have some responses to drain first
|
||||
PacketPtr pkt = drainList.front();
|
||||
if (sendTiming(pkt)) {
|
||||
drainList.pop_front();
|
||||
DPRINTF(CachePort, "%s sucessful in sending a retry for"
|
||||
"response (%i still waiting)\n", name(), drainList.size());
|
||||
if (!drainList.empty() || isBusRequested()) {
|
||||
|
||||
DPRINTF(CachePort, "%s has more responses/requests\n", name());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
waitingOnRetry = true;
|
||||
DPRINTF(CachePort, "%s now waiting on a retry\n", name());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BaseCache::CachePort::recvRetryCommon()
|
||||
{
|
||||
assert(waitingOnRetry);
|
||||
waitingOnRetry = false;
|
||||
if (!drainList.empty()) {
|
||||
if (!drainResponse()) {
|
||||
// more responses to drain... re-request bus
|
||||
scheduleRequestEvent(curTick + 1);
|
||||
}
|
||||
// Check if we're done draining once this list is empty
|
||||
if (drainList.empty()) {
|
||||
cache->checkDrain();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BaseCache::CachePort::setBlocked()
|
||||
{
|
||||
@@ -225,143 +241,6 @@ BaseCache::CachePort::clearBlocked()
|
||||
}
|
||||
}
|
||||
|
||||
BaseCache::RequestEvent::RequestEvent(CachePort *_cachePort, Tick when)
|
||||
: Event(&mainEventQueue, CPU_Tick_Pri), cachePort(_cachePort)
|
||||
{
|
||||
this->setFlags(AutoDelete);
|
||||
schedule(when);
|
||||
}
|
||||
|
||||
void
|
||||
BaseCache::RequestEvent::process()
|
||||
{
|
||||
if (cachePort->waitingOnRetry) return;
|
||||
//We have some responses to drain first
|
||||
if (!cachePort->drainList.empty()) {
|
||||
DPRINTF(CachePort, "%s trying to drain a response\n", cachePort->name());
|
||||
if (cachePort->sendTiming(cachePort->drainList.front())) {
|
||||
DPRINTF(CachePort, "%s drains a response succesfully\n", cachePort->name());
|
||||
cachePort->drainList.pop_front();
|
||||
if (!cachePort->drainList.empty() ||
|
||||
!cachePort->isCpuSide && cachePort->cache->doMasterRequest() ||
|
||||
cachePort->isCpuSide && cachePort->cache->doSlaveRequest()) {
|
||||
|
||||
DPRINTF(CachePort, "%s still has outstanding bus reqs\n", cachePort->name());
|
||||
this->schedule(curTick + 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
cachePort->waitingOnRetry = true;
|
||||
DPRINTF(CachePort, "%s now waiting on a retry\n", cachePort->name());
|
||||
}
|
||||
}
|
||||
else if (!cachePort->isCpuSide)
|
||||
{ //MSHR
|
||||
DPRINTF(CachePort, "%s trying to send a MSHR request\n", cachePort->name());
|
||||
if (!cachePort->cache->doMasterRequest()) {
|
||||
//This can happen if I am the owner of a block and see an upgrade
|
||||
//while the block was in my WB Buffers. I just remove the
|
||||
//wb and de-assert the masterRequest
|
||||
return;
|
||||
}
|
||||
|
||||
PacketPtr pkt = cachePort->cache->getPacket();
|
||||
MSHR* mshr = (MSHR*) pkt->senderState;
|
||||
//Copy the packet, it may be modified/destroyed elsewhere
|
||||
PacketPtr copyPkt = new Packet(*pkt);
|
||||
copyPkt->dataStatic<uint8_t>(pkt->getPtr<uint8_t>());
|
||||
mshr->pkt = copyPkt;
|
||||
|
||||
bool success = cachePort->sendTiming(pkt);
|
||||
DPRINTF(Cache, "Address %x was %s in sending the timing request\n",
|
||||
pkt->getAddr(), success ? "succesful" : "unsuccesful");
|
||||
|
||||
cachePort->waitingOnRetry = !success;
|
||||
if (cachePort->waitingOnRetry) {
|
||||
DPRINTF(CachePort, "%s now waiting on a retry\n", cachePort->name());
|
||||
}
|
||||
|
||||
cachePort->cache->sendResult(pkt, mshr, success);
|
||||
if (success && cachePort->cache->doMasterRequest())
|
||||
{
|
||||
DPRINTF(CachePort, "%s still more MSHR requests to send\n",
|
||||
cachePort->name());
|
||||
//Still more to issue, rerequest in 1 cycle
|
||||
this->schedule(curTick+1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//CSHR
|
||||
assert(cachePort->cache->doSlaveRequest());
|
||||
PacketPtr pkt = cachePort->cache->getCoherencePacket();
|
||||
MSHR* cshr = (MSHR*) pkt->senderState;
|
||||
bool success = cachePort->sendTiming(pkt);
|
||||
cachePort->cache->sendCoherenceResult(pkt, cshr, success);
|
||||
cachePort->waitingOnRetry = !success;
|
||||
if (cachePort->waitingOnRetry)
|
||||
DPRINTF(CachePort, "%s now waiting on a retry\n", cachePort->name());
|
||||
if (success && cachePort->cache->doSlaveRequest())
|
||||
{
|
||||
DPRINTF(CachePort, "%s still more CSHR requests to send\n",
|
||||
cachePort->name());
|
||||
//Still more to issue, rerequest in 1 cycle
|
||||
this->schedule(curTick+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
BaseCache::RequestEvent::description()
|
||||
{
|
||||
return "Cache request event";
|
||||
}
|
||||
|
||||
BaseCache::ResponseEvent::ResponseEvent(CachePort *_cachePort)
|
||||
: Event(&mainEventQueue, CPU_Tick_Pri), cachePort(_cachePort)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BaseCache::ResponseEvent::process()
|
||||
{
|
||||
assert(cachePort->transmitList.size());
|
||||
assert(cachePort->transmitList.front().first <= curTick);
|
||||
PacketPtr pkt = cachePort->transmitList.front().second;
|
||||
cachePort->transmitList.pop_front();
|
||||
if (!cachePort->transmitList.empty()) {
|
||||
Tick time = cachePort->transmitList.front().first;
|
||||
schedule(time <= curTick ? curTick+1 : time);
|
||||
}
|
||||
|
||||
if (pkt->flags & NACKED_LINE)
|
||||
pkt->result = Packet::Nacked;
|
||||
else
|
||||
pkt->result = Packet::Success;
|
||||
pkt->makeTimingResponse();
|
||||
DPRINTF(CachePort, "%s attempting to send a response\n", cachePort->name());
|
||||
if (!cachePort->drainList.empty() || cachePort->waitingOnRetry) {
|
||||
//Already have a list, just append
|
||||
cachePort->drainList.push_back(pkt);
|
||||
DPRINTF(CachePort, "%s appending response onto drain list\n", cachePort->name());
|
||||
}
|
||||
else if (!cachePort->sendTiming(pkt)) {
|
||||
//It failed, save it to list of drain events
|
||||
DPRINTF(CachePort, "%s now waiting for a retry\n", cachePort->name());
|
||||
cachePort->drainList.push_back(pkt);
|
||||
cachePort->waitingOnRetry = true;
|
||||
}
|
||||
|
||||
// Check if we're done draining once this list is empty
|
||||
if (cachePort->drainList.empty() && cachePort->transmitList.empty())
|
||||
cachePort->cache->checkDrain();
|
||||
}
|
||||
|
||||
const char *
|
||||
BaseCache::ResponseEvent::description()
|
||||
{
|
||||
return "Cache response event";
|
||||
}
|
||||
|
||||
void
|
||||
BaseCache::init()
|
||||
|
||||
Reference in New Issue
Block a user