// memory should be 0; no need to initialize them.
}
-static void
-printData(ostream &os, uint8_t *data, int nbytes)
-{
- os << hex << setfill('0');
- // assume little-endian: print bytes from highest address to lowest
- for (uint8_t *dp = data + nbytes - 1; dp >= data; --dp) {
- os << setw(2) << (unsigned)*dp;
- }
- os << dec;
-}
void
MemTest::completeRequest(PacketPtr pkt)
{
+ Request *req = pkt->req;
+
+ DPRINTF(MemTest, "completing %s at address %x (blk %x)\n",
+ pkt->isWrite() ? "write" : "read",
+ req->getPaddr(), blockAddr(req->getPaddr()));
+
MemTestSenderState *state =
dynamic_cast<MemTestSenderState *>(pkt->senderState);
uint8_t *data = state->data;
uint8_t *pkt_data = pkt->getPtr<uint8_t>();
- Request *req = pkt->req;
//Remove the address from the list of outstanding
- std::set<unsigned>::iterator removeAddr = outstandingAddrs.find(req->getPaddr());
+ std::set<unsigned>::iterator removeAddr =
+ outstandingAddrs.find(req->getPaddr());
assert(removeAddr != outstandingAddrs.end());
outstandingAddrs.erase(removeAddr);
}
if (numReads >= maxLoads)
- exitSimLoop("Maximum number of loads reached!");
+ exitSimLoop("maximum number of loads reached");
break;
case MemCmd::WriteResp:
numWritesStat++;
break;
-/*
- case Copy:
- //Also remove dest from outstanding list
- removeAddr = outstandingAddrs.find(req->dest);
- assert(removeAddr != outstandingAddrs.end());
- outstandingAddrs.erase(removeAddr);
- numCopiesStat++;
- break;
-*/
+
default:
panic("invalid command %s (%d)", pkt->cmdString(), pkt->cmd.toInt());
}
- if (blockAddr(req->getPaddr()) == traceBlockAddr) {
- cerr << name() << ": completed "
- << (pkt->isWrite() ? "write" : "read")
- << " access of "
- << dec << pkt->getSize() << " bytes at address 0x"
- << hex << req->getPaddr()
- << " (0x" << hex << blockAddr(req->getPaddr()) << ")"
- << ", value = 0x";
- printData(cerr, pkt_data, pkt->getSize());
- cerr << " @ cycle " << dec << curTick;
-
- cerr << endl;
- }
-
noResponseCycles = 0;
delete state;
delete [] data;
//mem tester
//We can eliminate the lower bits of the offset, and then use the id
//to offset within the blks
- offset &= ~63; //Not the low order bits
+ offset = blockAddr(offset);
offset += id;
access_size = 0;
if (cmd < percentReads) {
// read
- //For now we only allow one outstanding request per addreess per tester
- //This means we assume CPU does write forwarding to reads that alias something
- //in the cpu store buffer.
+ // For now we only allow one outstanding request per address
+ // per tester This means we assume CPU does write forwarding
+ // to reads that alias something in the cpu store buffer.
if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) {
delete [] result;
delete req;
return;
}
- else outstandingAddrs.insert(paddr);
+
+ outstandingAddrs.insert(paddr);
// ***** NOTE FOR RON: I'm not sure how to access checkMem. - Kevin
funcPort.readBlob(req->getPaddr(), result, req->getSize());
- if (blockAddr(paddr) == traceBlockAddr) {
- cerr << name()
- << ": initiating read "
- << ((probe) ? "probe of " : "access of ")
- << dec << req->getSize() << " bytes from addr 0x"
- << hex << paddr
- << " (0x" << hex << blockAddr(paddr) << ")"
- << " at cycle "
- << dec << curTick << endl;
- }
+ DPRINTF(MemTest,
+ "initiating read at address %x (blk %x) expecting %x\n",
+ req->getPaddr(), blockAddr(req->getPaddr()), *result);
PacketPtr pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
pkt->dataDynamicArray(new uint8_t[req->getSize()]);
pkt->makeAtomicResponse();
completeRequest(pkt);
} else {
-// req->completionEvent = new MemCompleteEvent(req, result, this);
sendPkt(pkt);
}
} else {
// write
- //For now we only allow one outstanding request per addreess per tester
- //This means we assume CPU does write forwarding to reads that alias something
- //in the cpu store buffer.
+ // For now we only allow one outstanding request per addreess
+ // per tester. This means we assume CPU does write forwarding
+ // to reads that alias something in the cpu store buffer.
if (outstandingAddrs.find(paddr) != outstandingAddrs.end()) {
delete [] result;
delete req;
return;
}
- else outstandingAddrs.insert(paddr);
+ outstandingAddrs.insert(paddr);
+
+ DPRINTF(MemTest, "initiating write at address %x (blk %x) value %x\n",
+ req->getPaddr(), blockAddr(req->getPaddr()), data & 0xff);
-/*
- if (blockAddr(req->getPaddr()) == traceBlockAddr) {
- cerr << name() << ": initiating write "
- << ((probe)?"probe of ":"access of ")
- << dec << req->getSize() << " bytes (value = 0x";
- printData(cerr, data_pkt->getPtr(), req->getSize());
- cerr << ") to addr 0x"
- << hex << req->getPaddr()
- << " (0x" << hex << blockAddr(req->getPaddr()) << ")"
- << " at cycle "
- << dec << curTick << endl;
- }
-*/
PacketPtr pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast);
uint8_t *pkt_data = new uint8_t[req->getSize()];
pkt->dataDynamicArray(pkt_data);
pkt->makeAtomicResponse();
completeRequest(pkt);
} else {
-// req->completionEvent = new MemCompleteEvent(req, NULL, this);
sendPkt(pkt);
}
}
-/* else {
- // copy
- unsigned source_align = random() % 100;
- unsigned dest_align = random() % 100;
- unsigned offset2 = random() % size;
-
- Addr source = ((base) ? baseAddr1 : baseAddr2) + offset;
- Addr dest = ((base) ? baseAddr2 : baseAddr1) + offset2;
- if (outstandingAddrs.find(source) != outstandingAddrs.end()) return;
- else outstandingAddrs.insert(source);
- if (outstandingAddrs.find(dest) != outstandingAddrs.end()) return;
- else outstandingAddrs.insert(dest);
-
- if (source_align >= percentSourceUnaligned) {
- source = blockAddr(source);
- }
- if (dest_align >= percentDestUnaligned) {
- dest = blockAddr(dest);
- }
- req->cmd = Copy;
- req->flags &= ~UNCACHEABLE;
- req->paddr = source;
- req->dest = dest;
- delete [] req->data;
- req->data = new uint8_t[blockSize];
- req->size = blockSize;
- if (source == traceBlockAddr || dest == traceBlockAddr) {
- cerr << name()
- << ": initiating copy of "
- << dec << req->size << " bytes from addr 0x"
- << hex << source
- << " (0x" << hex << blockAddr(source) << ")"
- << " to addr 0x"
- << hex << dest
- << " (0x" << hex << blockAddr(dest) << ")"
- << " at cycle "
- << dec << curTick << endl;
- }*
- cacheInterface->access(req);
- uint8_t result[blockSize];
- checkMem->access(Read, source, &result, blockSize);
- checkMem->access(Write, dest, &result, blockSize);
- }
-*/
}
void
template<class TagStore, class Coherence>
MSHR *
Cache<TagStore,Coherence>::allocateBuffer(PacketPtr pkt, Tick time,
- bool isFill, bool requestBus)
+ bool requestBus)
{
- int size = isFill ? blkSize : pkt->getSize();
- Addr addr = isFill ? tags->blkAlign(pkt->getAddr()) : pkt->getAddr();
+ MSHRQueue *mq = NULL;
- MSHR *mshr = NULL;
-
- if (pkt->isWrite()) {
+ if (pkt->isWrite() && !pkt->isRead()) {
/**
* @todo Add write merging here.
*/
- mshr = writeBuffer.allocate(addr, size, pkt, isFill);
- mshr->order = order++;
-
- if (writeBuffer.isFull()) {
- setBlocked(Blocked_NoWBBuffers);
- }
-
- if (requestBus) {
- requestMemSideBus(Request_WB, time);
- }
+ mq = &writeBuffer;
} else {
- mshr = mshrQueue.allocate(addr, size, pkt, isFill);
- mshr->order = order++;
- if (mshrQueue.isFull()) {
- setBlocked(Blocked_NoMSHRs);
- }
- if (requestBus) {
- requestMemSideBus(Request_MSHR, time);
- }
+ mq = &mshrQueue;
}
- assert(mshr != NULL);
- return mshr;
+ return allocateBufferInternal(mq, pkt->getAddr(), pkt->getSize(),
+ pkt, time, requestBus);
}
void
Cache<TagStore,Coherence>::markInService(MSHR *mshr)
{
- bool unblock = false;
- BlockedCause cause = NUM_BLOCKED_CAUSES;
-
- /**
- * @todo Should include MSHRQueue pointer in MSHR to select the correct
- * one.
- */
- if (mshr->queue == &writeBuffer) {
- // Forwarding a write/ writeback, don't need to change
- // the command
- unblock = writeBuffer.isFull();
- writeBuffer.markInService(mshr);
- if (!writeBuffer.havePending()){
- deassertMemSideBusRequest(Request_WB);
- }
- if (unblock) {
- // Do we really unblock?
- unblock = !writeBuffer.isFull();
- cause = Blocked_NoWBBuffers;
- }
- } else {
- assert(mshr->queue == &mshrQueue);
- unblock = mshrQueue.isFull();
- mshrQueue.markInService(mshr);
- if (!mshrQueue.havePending()){
- deassertMemSideBusRequest(Request_MSHR);
- }
+ markInServiceInternal(mshr);
#if 0
if (mshr->originalCmd == MemCmd::HardPFReq) {
DPRINTF(HWPrefetch, "%s:Marking a HW_PF in service\n",
}
}
#endif
- if (unblock) {
- unblock = !mshrQueue.isFull();
- cause = Blocked_NoMSHRs;
- }
- }
- if (unblock) {
- clearBlocked(cause);
- }
}
template<class TagStore, class Coherence>
bool
-Cache<TagStore,Coherence>::access(PacketPtr pkt, BlkType *blk, int &lat)
+Cache<TagStore,Coherence>::access(PacketPtr pkt, BlkType *&blk, int &lat)
{
+ if (pkt->req->isUncacheable()) {
+ blk = NULL;
+ lat = hitLatency;
+ return false;
+ }
+
bool satisfied = false; // assume the worst
+ blk = tags->findBlock(pkt->getAddr(), lat);
if (prefetchAccess) {
//We are determining prefetches on access stream, call prefetcher
hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
satisfied = true;
+ // Check RMW operations first since both isRead() and
+ // isWrite() will be true for them
if (pkt->cmd == MemCmd::SwapReq) {
cmpAndSwap(blk, pkt);
} else if (pkt->isWrite()) {
blk->status |= BlkDirty;
pkt->writeDataToBlock(blk->data, blkSize);
}
- } else {
- assert(pkt->isRead());
+ } else if (pkt->isRead()) {
if (pkt->isLocked()) {
blk->trackLoadLocked(pkt);
}
pkt->setDataFromBlock(blk->data, blkSize);
+ } else {
+ // Not a read or write... must be an upgrade. it's OK
+ // to just ack those as long as we have an exclusive
+ // copy at this level.
+ assert(pkt->cmd == MemCmd::UpgradeReq);
}
} else {
// permission violation... nothing to do here, leave unsatisfied
// we charge hitLatency for doing just about anything here
Tick time = curTick + hitLatency;
+ if (pkt->memInhibitAsserted()) {
+ DPRINTF(Cache, "mem inhibited on 0x%x: not responding\n",
+ pkt->getAddr());
+ assert(!pkt->req->isUncacheable());
+ return true;
+ }
+
if (pkt->req->isUncacheable()) {
- allocateBuffer(pkt, time, false, true);
+ allocateBuffer(pkt, time, true);
assert(pkt->needsResponse()); // else we should delete it here??
return true;
}
PacketList writebacks;
int lat = hitLatency;
- BlkType *blk = tags->findBlock(pkt->getAddr(), lat);
bool satisfied = false;
Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1));
-
MSHR *mshr = mshrQueue.findMatch(blk_addr);
if (!mshr) {
// cache block... a more aggressive system could detect the
// overlap (if any) and forward data out of the MSHRs, but we
// don't do that yet)
+ BlkType *blk = NULL;
satisfied = access(pkt, blk, lat);
}
// copy writebacks to write buffer
while (!writebacks.empty()) {
PacketPtr wbPkt = writebacks.front();
- allocateBuffer(wbPkt, time, false, true);
+ allocateBuffer(wbPkt, time, true);
writebacks.pop_front();
}
// always mark as cache fill for now... if we implement
// no-write-allocate or bypass accesses this will have to
// be changed.
- allocateBuffer(pkt, time, true, true);
+ allocateMissBuffer(pkt, time, true);
}
}
}
+template<class TagStore, class Coherence>
+PacketPtr
+Cache<TagStore,Coherence>::getBusPacket(PacketPtr cpu_pkt, BlkType *blk,
+ bool needsExclusive)
+{
+ bool blkValid = blk && blk->isValid();
+
+ if (cpu_pkt->req->isUncacheable()) {
+ assert(blk == NULL);
+ return NULL;
+ }
+
+ if (!blkValid &&
+ (cpu_pkt->cmd == MemCmd::Writeback ||
+ cpu_pkt->cmd == MemCmd::UpgradeReq)) {
+ // For now, writebacks from upper-level caches that
+ // completely miss in the cache just go through. If we had
+ // "fast write" support (where we could write the whole
+ // block w/o fetching new data) we might want to allocate
+ // on writeback misses instead.
+ return NULL;
+ }
+
+ MemCmd cmd;
+ const bool useUpgrades = true;
+ if (blkValid && useUpgrades) {
+ // only reason to be here is that blk is shared
+ // (read-only) and we need exclusive
+ assert(needsExclusive && !blk->isWritable());
+ cmd = MemCmd::UpgradeReq;
+ } else {
+ // block is invalid
+ cmd = needsExclusive ? MemCmd::ReadExReq : MemCmd::ReadReq;
+ }
+ PacketPtr pkt = new Packet(cpu_pkt->req, cmd, Packet::Broadcast, blkSize);
+
+ pkt->allocate();
+ return pkt;
+}
+
+
template<class TagStore, class Coherence>
Tick
Cache<TagStore,Coherence>::atomicAccess(PacketPtr pkt)
{
+ int lat = hitLatency;
+
+ if (pkt->memInhibitAsserted()) {
+ DPRINTF(Cache, "mem inhibited on 0x%x: not responding\n",
+ pkt->getAddr());
+ assert(!pkt->req->isUncacheable());
+ return lat;
+ }
+
// should assert here that there are no outstanding MSHRs or
// writebacks... that would mean that someone used an atomic
// access in timing mode
- if (pkt->req->isUncacheable()) {
- // Uncacheables just go through
- return memSidePort->sendAtomic(pkt);
- }
-
- PacketList writebacks;
- int lat = hitLatency;
- BlkType *blk = tags->findBlock(pkt->getAddr(), lat);
- bool satisfied = access(pkt, blk, lat);
+ BlkType *blk = NULL;
- if (!satisfied) {
+ if (!access(pkt, blk, lat)) {
// MISS
- CacheBlk::State old_state = (blk) ? blk->status : 0;
- MemCmd cmd = coherence->getBusCmd(pkt->cmd, old_state);
- Packet busPkt = Packet(pkt->req, cmd, Packet::Broadcast, blkSize);
- busPkt.allocate();
+ PacketPtr busPkt = getBusPacket(pkt, blk, pkt->needsExclusive());
- DPRINTF(Cache, "Sending a atomic %s for %x\n",
- busPkt.cmdString(), busPkt.getAddr());
+ bool isCacheFill = (busPkt != NULL);
- lat += memSidePort->sendAtomic(&busPkt);
+ if (busPkt == NULL) {
+ // just forwarding the same request to the next level
+ // no local cache operation involved
+ busPkt = pkt;
+ }
- DPRINTF(Cache, "Receive response: %s for addr %x in state %i\n",
- busPkt.cmdString(), busPkt.getAddr(), old_state);
+ DPRINTF(Cache, "Sending an atomic %s for %x\n",
+ busPkt->cmdString(), busPkt->getAddr());
- blk = handleFill(&busPkt, blk, writebacks);
- bool status = satisfyCpuSideRequest(pkt, blk);
- assert(status);
- }
+#if TRACING_ON
+ CacheBlk::State old_state = blk ? blk->status : 0;
+#endif
- // We now have the block one way or another (hit or completed miss)
+ lat += memSidePort->sendAtomic(busPkt);
- // Handle writebacks if needed
- while (!writebacks.empty()){
- PacketPtr wbPkt = writebacks.front();
- memSidePort->sendAtomic(wbPkt);
- writebacks.pop_front();
- delete wbPkt;
+ DPRINTF(Cache, "Receive response: %s for addr %x in state %i\n",
+ busPkt->cmdString(), busPkt->getAddr(), old_state);
+
+ if (isCacheFill) {
+ PacketList writebacks;
+ blk = handleFill(busPkt, blk, writebacks);
+ bool status = satisfyCpuSideRequest(pkt, blk);
+ assert(status);
+ delete busPkt;
+
+ // Handle writebacks if needed
+ while (!writebacks.empty()){
+ PacketPtr wbPkt = writebacks.front();
+ memSidePort->sendAtomic(wbPkt);
+ writebacks.pop_front();
+ delete wbPkt;
+ }
+ }
}
+ // We now have the block one way or another (hit or completed miss)
+
if (pkt->needsResponse()) {
pkt->makeAtomicResponse();
pkt->result = Packet::Success;
//
/////////////////////////////////////////////////////
+
template<class TagStore, class Coherence>
-void
-Cache<TagStore,Coherence>::handleResponse(PacketPtr pkt, Tick time)
+bool
+Cache<TagStore,Coherence>::satisfyCpuSideRequest(PacketPtr pkt, BlkType *blk)
{
- MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState);
-#ifndef NDEBUG
- int num_targets = mshr->getNumTargets();
-#endif
-
- bool unblock = false;
- bool unblock_target = false;
- BlockedCause cause = NUM_BLOCKED_CAUSES;
-
- if (mshr->isCacheFill) {
-#if 0
- mshr_miss_latency[mshr->originalCmd.toInt()][0/*pkt->req->getThreadNum()*/] +=
- curTick - pkt->time;
-#endif
- // targets were handled in the cache tags
- if (mshr == noTargetMSHR) {
- // we always clear at least one target
- unblock_target = true;
- cause = Blocked_NoTargets;
- noTargetMSHR = NULL;
- }
+ if (blk && (pkt->needsExclusive() ? blk->isWritable() : blk->isValid())) {
+ assert(pkt->isWrite() || pkt->isReadWrite() || pkt->isRead());
+ assert(pkt->getOffset(blkSize) + pkt->getSize() <= blkSize);
- if (mshr->hasTargets()) {
- // Didn't satisfy all the targets, need to resend
- mshrQueue.markPending(mshr);
- mshr->order = order++;
- requestMemSideBus(Request_MSHR, time);
- }
- else {
- unblock = mshrQueue.isFull();
- mshrQueue.deallocate(mshr);
- if (unblock) {
- unblock = !mshrQueue.isFull();
- cause = Blocked_NoMSHRs;
+ if (pkt->isWrite()) {
+ if (blk->checkWrite(pkt)) {
+ blk->status |= BlkDirty;
+ pkt->writeDataToBlock(blk->data, blkSize);
}
+ } else if (pkt->isReadWrite()) {
+ cmpAndSwap(blk, pkt);
+ } else {
+ if (pkt->isLocked()) {
+ blk->trackLoadLocked(pkt);
+ }
+ pkt->setDataFromBlock(blk->data, blkSize);
}
+
+ return true;
} else {
- if (pkt->req->isUncacheable()) {
- mshr_uncacheable_lat[pkt->cmd.toInt()][0/*pkt->req->getThreadNum()*/] +=
- curTick - pkt->time;
- }
- if (mshr->hasTargets() && pkt->req->isUncacheable()) {
- // Should only have 1 target if we had any
- assert(num_targets == 1);
- MSHR::Target *target = mshr->getTarget();
- assert(target->cpuSide);
- mshr->popTarget();
- if (pkt->isRead()) {
- target->pkt->setData(pkt->getPtr<uint8_t>());
- }
- cpuSidePort->respond(target->pkt, time);
- assert(!mshr->hasTargets());
+ return false;
+ }
+}
+
+
+template<class TagStore, class Coherence>
+bool
+Cache<TagStore,Coherence>::satisfyTarget(MSHR::Target *target, BlkType *blk)
+{
+ assert(target != NULL);
+ assert(target->isCpuSide());
+ return satisfyCpuSideRequest(target->pkt, blk);
+}
+
+template<class TagStore, class Coherence>
+bool
+Cache<TagStore,Coherence>::satisfyMSHR(MSHR *mshr, PacketPtr pkt,
+ BlkType *blk)
+{
+ // respond to MSHR targets, if any
+
+ // First offset for critical word first calculations
+ int initial_offset = 0;
+
+ if (mshr->hasTargets()) {
+ initial_offset = mshr->getTarget()->pkt->getOffset(blkSize);
+ }
+
+ while (mshr->hasTargets()) {
+ MSHR::Target *target = mshr->getTarget();
+
+ if (!satisfyTarget(target, blk)) {
+ // Invalid access, need to do another request
+ // can occur if block is invalidated, or not correct
+ // permissions
+ MSHRQueue *mq = mshr->queue;
+ mq->markPending(mshr);
+ mshr->order = order++;
+ requestMemSideBus((RequestCause)mq->index, pkt->finishTime);
+ return false;
}
- else if (mshr->hasTargets()) {
- //Must be a no_allocate with possibly more than one target
- assert(!mshr->isCacheFill);
- while (mshr->hasTargets()) {
- MSHR::Target *target = mshr->getTarget();
- assert(target->isCpuSide());
- mshr->popTarget();
- if (pkt->isRead()) {
- target->pkt->setData(pkt->getPtr<uint8_t>());
- }
- cpuSidePort->respond(target->pkt, time);
- }
+
+
+ // How many bytes pass the first request is this one
+ int transfer_offset = target->pkt->getOffset(blkSize) - initial_offset;
+ if (transfer_offset < 0) {
+ transfer_offset += blkSize;
}
- if (pkt->isWrite()) {
- // If the wrtie buffer is full, we might unblock now
- unblock = writeBuffer.isFull();
- writeBuffer.deallocate(mshr);
- if (unblock) {
- // Did we really unblock?
- unblock = !writeBuffer.isFull();
- cause = Blocked_NoWBBuffers;
- }
- } else {
- unblock = mshrQueue.isFull();
- mshrQueue.deallocate(mshr);
- if (unblock) {
- unblock = !mshrQueue.isFull();
- cause = Blocked_NoMSHRs;
- }
+ // If critical word (no offset) return first word time
+ Tick completion_time = tags->getHitLatency() +
+ transfer_offset ? pkt->finishTime : pkt->firstWordTime;
+
+ if (!target->pkt->req->isUncacheable()) {
+ missLatency[target->pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/] +=
+ completion_time - target->time;
}
+ target->pkt->makeTimingResponse();
+ cpuSidePort->respond(target->pkt, completion_time);
+ mshr->popTarget();
}
- if (unblock || unblock_target) {
- clearBlocked(cause);
- }
+
+ return true;
}
assert(pkt->result == Packet::Success);
DPRINTF(Cache, "Handling reponse to %x\n", pkt->getAddr());
+ MSHRQueue *mq = mshr->queue;
+ bool wasFull = mq->isFull();
+
+ if (mshr == noTargetMSHR) {
+ // we always clear at least one target
+ clearBlocked(Blocked_NoTargets);
+ noTargetMSHR = NULL;
+ }
+
+ // Can we deallocate MSHR when done?
+ bool deallocate = false;
+
if (mshr->isCacheFill) {
+#if 0
+ mshr_miss_latency[mshr->originalCmd.toInt()][0/*pkt->req->getThreadNum()*/] +=
+ curTick - pkt->time;
+#endif
DPRINTF(Cache, "Block for addr %x being updated in Cache\n",
pkt->getAddr());
BlkType *blk = tags->findBlock(pkt->getAddr());
PacketList writebacks;
blk = handleFill(pkt, blk, writebacks);
- satisfyMSHR(mshr, pkt, blk);
+ deallocate = satisfyMSHR(mshr, pkt, blk);
// copy writebacks to write buffer
while (!writebacks.empty()) {
PacketPtr wbPkt = writebacks.front();
- allocateBuffer(wbPkt, time, false, true);
+ allocateBuffer(wbPkt, time, true);
writebacks.pop_front();
}
+ } else {
+ if (pkt->req->isUncacheable()) {
+ mshr_uncacheable_lat[pkt->cmd.toInt()][0/*pkt->req->getThreadNum()*/] +=
+ curTick - pkt->time;
+ }
+
+ while (mshr->hasTargets()) {
+ MSHR::Target *target = mshr->getTarget();
+ assert(target->isCpuSide());
+ mshr->popTarget();
+ if (pkt->isRead()) {
+ target->pkt->setData(pkt->getPtr<uint8_t>());
+ }
+ cpuSidePort->respond(target->pkt, time);
+ }
+ assert(!mshr->hasTargets());
+ deallocate = true;
+ }
+
+ if (deallocate) {
+ mq->deallocate(mshr);
+ if (wasFull && !mq->isFull()) {
+ clearBlocked((BlockedCause)mq->index);
+ }
}
- handleResponse(pkt, time);
}
Addr addr = pkt->getAddr();
if (blk == NULL) {
+ // better have read new data
+ assert(pkt->isRead());
// need to do a replacement
blk = tags->findReplacement(addr, writebacks);
blk->tag = tags->extractTag(addr);
blk->status = coherence->getNewState(pkt);
- assert(pkt->isRead());
} else {
// existing block... probably an upgrade
assert(blk->tag == tags->extractTag(addr));
}
-template<class TagStore, class Coherence>
-bool
-Cache<TagStore,Coherence>::satisfyCpuSideRequest(PacketPtr pkt, BlkType *blk)
-{
- if (blk && (pkt->needsExclusive() ? blk->isWritable() : blk->isValid())) {
- assert(pkt->isWrite() || pkt->isReadWrite() || pkt->isRead());
- assert(pkt->getOffset(blkSize) + pkt->getSize() <= blkSize);
-
- if (pkt->isWrite()) {
- if (blk->checkWrite(pkt)) {
- blk->status |= BlkDirty;
- pkt->writeDataToBlock(blk->data, blkSize);
- }
- } else if (pkt->isReadWrite()) {
- cmpAndSwap(blk, pkt);
- } else {
- if (pkt->isLocked()) {
- blk->trackLoadLocked(pkt);
- }
- pkt->setDataFromBlock(blk->data, blkSize);
- }
-
- return true;
- } else {
- return false;
- }
-}
-
-
-template<class TagStore, class Coherence>
-bool
-Cache<TagStore,Coherence>::satisfyTarget(MSHR::Target *target, BlkType *blk)
-{
- assert(target != NULL);
- assert(target->isCpuSide());
- return satisfyCpuSideRequest(target->pkt, blk);
-}
-
-template<class TagStore, class Coherence>
-void
-Cache<TagStore,Coherence>::satisfyMSHR(MSHR *mshr, PacketPtr pkt,
- BlkType *blk)
-{
- // respond to MSHR targets, if any
-
- // First offset for critical word first calculations
- int initial_offset = 0;
-
- if (mshr->hasTargets()) {
- initial_offset = mshr->getTarget()->pkt->getOffset(blkSize);
- }
-
- while (mshr->hasTargets()) {
- MSHR::Target *target = mshr->getTarget();
-
- if (!satisfyTarget(target, blk)) {
- // Invalid access, need to do another request
- // can occur if block is invalidated, or not correct
- // permissions
- break;
- }
-
-
- // How many bytes pass the first request is this one
- int transfer_offset = target->pkt->getOffset(blkSize) - initial_offset;
- if (transfer_offset < 0) {
- transfer_offset += blkSize;
- }
-
- // If critical word (no offset) return first word time
- Tick completion_time = tags->getHitLatency() +
- transfer_offset ? pkt->finishTime : pkt->firstWordTime;
-
- if (!target->pkt->req->isUncacheable()) {
- missLatency[target->pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/] +=
- completion_time - target->time;
- }
- target->pkt->makeTimingResponse();
- cpuSidePort->respond(target->pkt, completion_time);
- mshr->popTarget();
- }
-}
-
-
/////////////////////////////////////////////////////
//
// Snoop path: requests coming in from the memory side
// (hwpf_mshr_misses)
mshr_misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
// Don't request bus, since we already have it
- return allocateBuffer(pkt, curTick, true, false);
+ return allocateMissBuffer(pkt, curTick, false);
}
}
template<class TagStore, class Coherence>
PacketPtr
-Cache<TagStore,Coherence>::getPacket()
+Cache<TagStore,Coherence>::getTimingPacket()
{
MSHR *mshr = getNextMSHR();
BlkType *blk = tags->findBlock(mshr->addr);
// use request from 1st target
- MSHR::Target *tgt1 = mshr->getTarget();
- PacketPtr tgt1_pkt = tgt1->pkt;
- PacketPtr pkt;
+ PacketPtr tgt_pkt = mshr->getTarget()->pkt;
+ PacketPtr pkt = getBusPacket(tgt_pkt, blk, mshr->needsExclusive);
- if (mshr->isCacheFill) {
- MemCmd cmd;
- if (blk && blk->isValid()) {
- // only reason to be here is that blk is shared
- // (read-only) and we need exclusive
- assert(mshr->needsExclusive && !blk->isWritable());
- cmd = MemCmd::UpgradeReq;
- } else {
- // block is invalid
- cmd = mshr->needsExclusive ? MemCmd::ReadExReq : MemCmd::ReadReq;
+ mshr->isCacheFill = (pkt != NULL);
+
+ if (pkt == NULL) {
+ // make copy of current packet to forward
+ pkt = new Packet(tgt_pkt);
+ pkt->allocate();
+ if (pkt->isWrite()) {
+ pkt->setData(tgt_pkt->getPtr<uint8_t>());
}
- pkt = new Packet(tgt1_pkt->req, cmd, Packet::Broadcast);
- } else {
- assert(blk == NULL);
- assert(mshr->getNumTargets() == 1);
- pkt = new Packet(tgt1_pkt->req, tgt1_pkt->cmd, Packet::Broadcast);
}
pkt->senderState = mshr;
- pkt->allocate();
return pkt;
}
waitingOnRetry = !success;
} else {
// check for non-response packets (requests & writebacks)
- PacketPtr pkt = myCache()->getPacket();
+ PacketPtr pkt = myCache()->getTimingPacket();
MSHR *mshr = dynamic_cast<MSHR*>(pkt->senderState);
bool success = sendTiming(pkt);