/*
- * Copyright (c) 2010-2012 ARM Limited
+ * Copyright (c) 2010-2012, 2014 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
/** Re-executes all rescheduled memory instructions. */
void replayMemInst(DynInstPtr &inst);
+ /** Moves memory instruction onto the list of cache blocked instructions */
+ void blockMemInst(DynInstPtr &inst);
+
+ /** Notifies that the cache has become unblocked */
+ void cacheUnblocked();
+
/** Sends an instruction to commit through the time buffer. */
void instToCommit(DynInstPtr &inst);
*/
void squashDueToMemOrder(DynInstPtr &inst, ThreadID tid);
- /** Sends commit proper information for a squash due to memory becoming
- * blocked (younger issued instructions must be retried).
- */
- void squashDueToMemBlocked(DynInstPtr &inst, ThreadID tid);
-
/** Sets Dispatch to blocked, and signals back to other stages to block. */
void block(ThreadID tid);
}
}
-template<class Impl>
-void
-DefaultIEW<Impl>::squashDueToMemBlocked(DynInstPtr &inst, ThreadID tid)
-{
- DPRINTF(IEW, "[tid:%i]: Memory blocked, squashing load and younger insts, "
- "PC: %s [sn:%i].\n", tid, inst->pcState(), inst->seqNum);
- if (!toCommit->squash[tid] ||
- inst->seqNum < toCommit->squashedSeqNum[tid]) {
- toCommit->squash[tid] = true;
-
- toCommit->squashedSeqNum[tid] = inst->seqNum;
- toCommit->pc[tid] = inst->pcState();
- toCommit->mispredictInst[tid] = NULL;
-
- // Must include the broadcasted SN in the squash.
- toCommit->includeSquashInst[tid] = true;
-
- ldstQueue.setLoadBlockedHandled(tid);
-
- wroteToTimeBuffer = true;
- }
-}
-
template<class Impl>
void
DefaultIEW<Impl>::block(ThreadID tid)
instQueue.replayMemInst(inst);
}
+template<class Impl>
+void
+DefaultIEW<Impl>::blockMemInst(DynInstPtr& inst)
+{
+ instQueue.blockMemInst(inst);
+}
+
+template<class Impl>
+void
+DefaultIEW<Impl>::cacheUnblocked()
+{
+ instQueue.cacheUnblocked();
+}
+
template<class Impl>
void
DefaultIEW<Impl>::instToCommit(DynInstPtr &inst)
squashDueToMemOrder(violator, tid);
++memOrderViolationEvents;
- } else if (ldstQueue.loadBlocked(tid) &&
- !ldstQueue.isLoadBlockedHandled(tid)) {
- fetchRedirect[tid] = true;
-
- DPRINTF(IEW, "Load operation couldn't execute because the "
- "memory system is blocked. PC: %s [sn:%lli]\n",
- inst->pcState(), inst->seqNum);
-
- squashDueToMemBlocked(inst, tid);
}
} else {
// Reset any state associated with redirects that will not
++memOrderViolationEvents;
}
- if (ldstQueue.loadBlocked(tid) &&
- !ldstQueue.isLoadBlockedHandled(tid)) {
- DPRINTF(IEW, "Load operation couldn't execute because the "
- "memory system is blocked. PC: %s [sn:%lli]\n",
- inst->pcState(), inst->seqNum);
- DPRINTF(IEW, "Blocked load will not be handled because "
- "already squashing\n");
-
- ldstQueue.setLoadBlockedHandled(tid);
- }
-
}
}
/*
- * Copyright (c) 2011-2012 ARM Limited
+ * Copyright (c) 2011-2012, 2014 ARM Limited
* Copyright (c) 2013 Advanced Micro Devices, Inc.
* All rights reserved.
*
*/
DynInstPtr getInstToExecute();
- /** Returns a memory instruction that was referred due to a delayed DTB
- * translation if it is now ready to execute.
+ /** Gets a memory instruction that was referred due to a delayed DTB
+ * translation if it is now ready to execute. NULL if none available.
*/
DynInstPtr getDeferredMemInstToExecute();
+ /** Gets a memory instruction that was blocked on the cache. NULL if none
+ * available.
+ */
+ DynInstPtr getBlockedMemInstToExecute();
+
/**
* Records the instruction as the producer of a register without
* adding it to the rest of the IQ.
*/
void deferMemInst(DynInstPtr &deferred_inst);
+ /** Defers a memory instruction when it is cache blocked. */
+ void blockMemInst(DynInstPtr &blocked_inst);
+
+ /** Notify instruction queue that a previous blockage has resolved */
+ void cacheUnblocked();
+
/** Indicates an ordering violation between a store and a load. */
void violation(DynInstPtr &store, DynInstPtr &faulting_load);
*/
std::list<DynInstPtr> deferredMemInsts;
+ /** List of instructions that have been cache blocked. */
+ std::list<DynInstPtr> blockedMemInsts;
+
+ /** List of instructions that were cache blocked, but a retry has been seen
+ * since, so they can now be retried. May fail again go on the blocked list.
+ */
+ std::list<DynInstPtr> retryMemInsts;
+
/**
* Struct for comparing entries to be added to the priority queue.
* This gives reverse ordering to the instructions in terms of
/*
- * Copyright (c) 2011-2013 ARM Limited
+ * Copyright (c) 2011-2014 ARM Limited
* Copyright (c) 2013 Advanced Micro Devices, Inc.
* All rights reserved.
*
nonSpecInsts.clear();
listOrder.clear();
deferredMemInsts.clear();
+ blockedMemInsts.clear();
+ retryMemInsts.clear();
}
template <class Impl>
IssueStruct *i2e_info = issueToExecuteQueue->access(0);
- DynInstPtr deferred_mem_inst;
- int total_deferred_mem_issued = 0;
- while (total_deferred_mem_issued < totalWidth &&
- (deferred_mem_inst = getDeferredMemInstToExecute()) != 0) {
- issueToExecuteQueue->access(0)->size++;
- instsToExecute.push_back(deferred_mem_inst);
- total_deferred_mem_issued++;
+ DynInstPtr mem_inst;
+ while (mem_inst = getDeferredMemInstToExecute()) {
+ addReadyMemInst(mem_inst);
+ }
+
+ // See if any cache blocked instructions are able to be executed
+ while (mem_inst = getBlockedMemInstToExecute()) {
+ addReadyMemInst(mem_inst);
}
// Have iterator to head of the list
// Increment the iterator.
// This will avoid trying to schedule a certain op class if there are no
// FUs that handle it.
+ int total_issued = 0;
ListOrderIt order_it = listOrder.begin();
ListOrderIt order_end_it = listOrder.end();
- int total_issued = 0;
- while (total_issued < (totalWidth - total_deferred_mem_issued) &&
- order_it != order_end_it) {
+ while (total_issued < totalWidth && order_it != order_end_it) {
OpClass op_class = (*order_it).queueType;
assert(!readyInsts[op_class].empty());
// @todo If the way deferred memory instructions are handeled due to
// translation changes then the deferredMemInsts condition should be removed
// from the code below.
- if (total_issued || total_deferred_mem_issued || deferredMemInsts.size()) {
+ if (total_issued || !retryMemInsts.empty() || !deferredMemInsts.empty()) {
cpu->activityThisCycle();
} else {
DPRINTF(IQ, "Not able to schedule any instructions.\n");
void
InstructionQueue<Impl>::replayMemInst(DynInstPtr &replay_inst)
{
- memDepUnit[replay_inst->threadNumber].replay(replay_inst);
+ memDepUnit[replay_inst->threadNumber].replay();
}
template <class Impl>
deferredMemInsts.push_back(deferred_inst);
}
+template <class Impl>
+void
+InstructionQueue<Impl>::blockMemInst(DynInstPtr &blocked_inst)
+{
+ blocked_inst->translationStarted(false);
+ blocked_inst->translationCompleted(false);
+
+ blocked_inst->clearIssued();
+ blocked_inst->clearCanIssue();
+ blockedMemInsts.push_back(blocked_inst);
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::cacheUnblocked()
+{
+ retryMemInsts.splice(retryMemInsts.end(), blockedMemInsts);
+ // Get the CPU ticking again
+ cpu->wakeCPU();
+}
+
template <class Impl>
typename Impl::DynInstPtr
InstructionQueue<Impl>::getDeferredMemInstToExecute()
for (ListIt it = deferredMemInsts.begin(); it != deferredMemInsts.end();
++it) {
if ((*it)->translationCompleted() || (*it)->isSquashed()) {
- DynInstPtr ret = *it;
+ DynInstPtr mem_inst = *it;
deferredMemInsts.erase(it);
- return ret;
+ return mem_inst;
}
}
- return NULL;
+ return nullptr;
+}
+
+template <class Impl>
+typename Impl::DynInstPtr
+InstructionQueue<Impl>::getBlockedMemInstToExecute()
+{
+ if (retryMemInsts.empty()) {
+ return nullptr;
+ } else {
+ DynInstPtr mem_inst = retryMemInsts.front();
+ retryMemInsts.pop_front();
+ return mem_inst;
+ }
}
template <class Impl>
/*
- * Copyright (c) 2011-2012 ARM Limited
+ * Copyright (c) 2011-2012, 2014 ARM Limited
* Copyright (c) 2013 Advanced Micro Devices, Inc.
* All rights reserved
*
bool violation(ThreadID tid)
{ return thread[tid].violation(); }
- /** Returns if a load is blocked due to the memory system for a specific
- * thread.
- */
- bool loadBlocked(ThreadID tid)
- { return thread[tid].loadBlocked(); }
-
- bool isLoadBlockedHandled(ThreadID tid)
- { return thread[tid].isLoadBlockedHandled(); }
-
- void setLoadBlockedHandled(ThreadID tid)
- { thread[tid].setLoadBlockedHandled(); }
-
/** Gets the instruction that caused the memory ordering violation. */
DynInstPtr getMemDepViolator(ThreadID tid)
{ return thread[tid].getMemDepViolator(); }
bool willWB(ThreadID tid)
{ return thread[tid].willWB(); }
- /** Returns if the cache is currently blocked. */
- bool cacheBlocked() const
- { return retryTid != InvalidThreadID; }
-
- /** Sets the retry thread id, indicating that one of the LSQUnits
- * tried to access the cache but the cache was blocked. */
- void setRetryTid(ThreadID tid)
- { retryTid = tid; }
-
/** Debugging function to print out all instructions. */
void dumpInsts() const;
/** Debugging function to print out instructions from a specific thread. */
/** Number of Threads. */
ThreadID numThreads;
-
- /** The thread id of the LSQ Unit that is currently waiting for a
- * retry. */
- ThreadID retryTid;
};
template <class Impl>
/*
- * Copyright (c) 2011-2012 ARM Limited
+ * Copyright (c) 2011-2012, 2014 ARM Limited
* Copyright (c) 2013 Advanced Micro Devices, Inc.
* All rights reserved
*
: cpu(cpu_ptr), iewStage(iew_ptr),
LQEntries(params->LQEntries),
SQEntries(params->SQEntries),
- numThreads(params->numThreads),
- retryTid(-1)
+ numThreads(params->numThreads)
{
assert(numThreads > 0 && numThreads <= Impl::MaxThreads);
drained = false;
}
- if (retryTid != InvalidThreadID) {
- DPRINTF(Drain, "Not drained, the LSQ has blocked the caches.\n");
- drained = false;
- }
-
return drained;
}
void
LSQ<Impl>::recvRetry()
{
- if (retryTid == InvalidThreadID)
- {
- //Squashed, so drop it
- return;
+ iewStage->cacheUnblocked();
+
+ for (ThreadID tid : *activeThreads) {
+ thread[tid].recvRetry();
}
- int curr_retry_tid = retryTid;
- // Speculatively clear the retry Tid. This will get set again if
- // the LSQUnit was unable to complete its access.
- retryTid = -1;
- thread[curr_retry_tid].recvRetry();
}
template <class Impl>
/*
- * Copyright (c) 2012-2013 ARM Limited
+ * Copyright (c) 2012-2014 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
/** Returns the memory ordering violator. */
DynInstPtr getMemDepViolator();
- /** Returns if a load became blocked due to the memory system. */
- bool loadBlocked()
- { return isLoadBlocked; }
-
- /** Clears the signal that a load became blocked. */
- void clearLoadBlocked()
- { isLoadBlocked = false; }
-
- /** Returns if the blocked load was handled. */
- bool isLoadBlockedHandled()
- { return loadBlockedHandled; }
-
- /** Records the blocked load as being handled. */
- void setLoadBlockedHandled()
- { loadBlockedHandled = true; }
-
/** Returns the number of free LQ entries. */
unsigned numFreeLoadEntries();
/** Default constructor. */
LSQSenderState()
: mainPkt(NULL), pendingPacket(NULL), outstanding(1),
- noWB(false), isSplit(false), pktToSend(false)
+ noWB(false), isSplit(false), pktToSend(false), cacheBlocked(false)
{ }
/** Instruction who initiated the access to memory. */
bool isSplit;
/** Whether or not there is a packet that needs sending. */
bool pktToSend;
+ /** Whether or not the second packet of this split load was blocked */
+ bool cacheBlocked;
/** Completes a packet and returns whether the access is finished. */
inline bool complete() { return --outstanding == 0; }
/** Whehter or not a store is blocked due to the memory system. */
bool isStoreBlocked;
- /** Whether or not a load is blocked due to the memory system. */
- bool isLoadBlocked;
-
- /** Has the blocked load been handled. */
- bool loadBlockedHandled;
-
/** Whether or not a store is in flight. */
bool storeInFlight;
- /** The sequence number of the blocked load. */
- InstSeqNum blockedLoadSeqNum;
-
/** The oldest load that caused a memory ordering violation. */
DynInstPtr memDepViolator;
memcpy(data, storeQueue[store_idx].data + shift_amt,
req->getSize());
- assert(!load_inst->memData);
- load_inst->memData = new uint8_t[req->getSize()];
+ // Allocate memory if this is the first time a load is issued.
+ if (!load_inst->memData) {
+ load_inst->memData = new uint8_t[req->getSize()];
+ }
if (storeQueue[store_idx].isAllZeros)
memset(load_inst->memData, 0, req->getSize());
else
DPRINTF(LSQUnit, "Doing memory access for inst [sn:%lli] PC %s\n",
load_inst->seqNum, load_inst->pcState());
- assert(!load_inst->memData);
- load_inst->memData = new uint8_t[req->getSize()];
+ // Allocate memory if this is the first time a load is issued.
+ if (!load_inst->memData) {
+ load_inst->memData = new uint8_t[req->getSize()];
+ }
++usedPorts;
// if we the cache is not blocked, do cache access
bool completedFirst = false;
- if (!lsq->cacheBlocked()) {
- MemCmd command =
- req->isLLSC() ? MemCmd::LoadLockedReq : MemCmd::ReadReq;
- PacketPtr data_pkt = new Packet(req, command);
- PacketPtr fst_data_pkt = NULL;
- PacketPtr snd_data_pkt = NULL;
-
- data_pkt->dataStatic(load_inst->memData);
-
- LSQSenderState *state = new LSQSenderState;
- state->isLoad = true;
- state->idx = load_idx;
- state->inst = load_inst;
- data_pkt->senderState = state;
-
- if (!TheISA::HasUnalignedMemAcc || !sreqLow) {
-
- // Point the first packet at the main data packet.
- fst_data_pkt = data_pkt;
- } else {
-
- // Create the split packets.
- fst_data_pkt = new Packet(sreqLow, command);
- snd_data_pkt = new Packet(sreqHigh, command);
-
- fst_data_pkt->dataStatic(load_inst->memData);
- snd_data_pkt->dataStatic(load_inst->memData + sreqLow->getSize());
-
- fst_data_pkt->senderState = state;
- snd_data_pkt->senderState = state;
+ MemCmd command = req->isLLSC() ? MemCmd::LoadLockedReq : MemCmd::ReadReq;
+ PacketPtr data_pkt = new Packet(req, command);
+ PacketPtr fst_data_pkt = NULL;
+ PacketPtr snd_data_pkt = NULL;
+
+ data_pkt->dataStatic(load_inst->memData);
+
+ LSQSenderState *state = new LSQSenderState;
+ state->isLoad = true;
+ state->idx = load_idx;
+ state->inst = load_inst;
+ data_pkt->senderState = state;
+
+ if (!TheISA::HasUnalignedMemAcc || !sreqLow) {
+ // Point the first packet at the main data packet.
+ fst_data_pkt = data_pkt;
+ } else {
+ // Create the split packets.
+ fst_data_pkt = new Packet(sreqLow, command);
+ snd_data_pkt = new Packet(sreqHigh, command);
+
+ fst_data_pkt->dataStatic(load_inst->memData);
+ snd_data_pkt->dataStatic(load_inst->memData + sreqLow->getSize());
+
+ fst_data_pkt->senderState = state;
+ snd_data_pkt->senderState = state;
+
+ state->isSplit = true;
+ state->outstanding = 2;
+ state->mainPkt = data_pkt;
+ }
- state->isSplit = true;
- state->outstanding = 2;
- state->mainPkt = data_pkt;
+ bool successful_load = true;
+ if (!dcachePort->sendTimingReq(fst_data_pkt)) {
+ successful_load = false;
+ } else if (TheISA::HasUnalignedMemAcc && sreqLow) {
+ completedFirst = true;
+
+ // The first packet was sent without problems, so send this one
+ // too. If there is a problem with this packet then the whole
+ // load will be squashed, so indicate this to the state object.
+ // The first packet will return in completeDataAccess and be
+ // handled there.
+ ++usedPorts;
+ if (!dcachePort->sendTimingReq(snd_data_pkt)) {
+ // The main packet will be deleted in completeDataAccess.
+ state->complete();
+ // Signify to 1st half that the 2nd half was blocked via state
+ state->cacheBlocked = true;
+ successful_load = false;
}
+ }
- if (!dcachePort->sendTimingReq(fst_data_pkt)) {
- // Delete state and data packet because a load retry
- // initiates a pipeline restart; it does not retry.
+ // If the cache was blocked, or has become blocked due to the access,
+ // handle it.
+ if (!successful_load) {
+ if (!sreqLow) {
+ // Packet wasn't split, just delete main packet info
delete state;
- delete data_pkt->req;
+ delete req;
delete data_pkt;
- if (TheISA::HasUnalignedMemAcc && sreqLow) {
- delete fst_data_pkt->req;
+ }
+
+ if (TheISA::HasUnalignedMemAcc && sreqLow) {
+ if (!completedFirst) {
+ // Split packet, but first failed. Delete all state.
+ delete state;
+ delete req;
+ delete data_pkt;
delete fst_data_pkt;
- delete snd_data_pkt->req;
delete snd_data_pkt;
+ delete sreqLow;
+ delete sreqHigh;
sreqLow = NULL;
sreqHigh = NULL;
- }
-
- req = NULL;
-
- // If the access didn't succeed, tell the LSQ by setting
- // the retry thread id.
- lsq->setRetryTid(lsqID);
- } else if (TheISA::HasUnalignedMemAcc && sreqLow) {
- completedFirst = true;
-
- // The first packet was sent without problems, so send this one
- // too. If there is a problem with this packet then the whole
- // load will be squashed, so indicate this to the state object.
- // The first packet will return in completeDataAccess and be
- // handled there.
- ++usedPorts;
- if (!dcachePort->sendTimingReq(snd_data_pkt)) {
-
- // The main packet will be deleted in completeDataAccess.
- delete snd_data_pkt->req;
+ } else {
+ // Can't delete main packet data or state because first packet
+ // was sent to the memory system
+ delete data_pkt;
+ delete req;
+ delete sreqHigh;
delete snd_data_pkt;
-
- state->complete();
-
- req = NULL;
sreqHigh = NULL;
-
- lsq->setRetryTid(lsqID);
}
}
- }
-
- // If the cache was blocked, or has become blocked due to the access,
- // handle it.
- if (lsq->cacheBlocked()) {
- if (req)
- delete req;
- if (TheISA::HasUnalignedMemAcc && sreqLow && !completedFirst) {
- delete sreqLow;
- delete sreqHigh;
- }
++lsqCacheBlocked;
- // There's an older load that's already going to squash.
- if (isLoadBlocked && blockedLoadSeqNum < load_inst->seqNum)
- return NoFault;
+ iewStage->blockMemInst(load_inst);
- // Record that the load was blocked due to memory. This
- // load will squash all instructions after it, be
- // refetched, and re-executed.
- isLoadBlocked = true;
- loadBlockedHandled = false;
- blockedLoadSeqNum = load_inst->seqNum;
// No fault occurred, even though the interface is blocked.
return NoFault;
}
/*
- * Copyright (c) 2010-2013 ARM Limited
+ * Copyright (c) 2010-2014 ARM Limited
* Copyright (c) 2013 Advanced Micro Devices, Inc.
* All rights reserved
*
DPRINTF(IEW, "Writeback event [sn:%lli].\n", inst->seqNum);
DPRINTF(Activity, "Activity: Writeback event [sn:%lli].\n", inst->seqNum);
- //iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum);
+ if (state->cacheBlocked) {
+ // This is the first half of a previous split load,
+ // where the 2nd half blocked, ignore this response
+ DPRINTF(IEW, "[sn:%lli]: Response from first half of earlier "
+ "blocked split load recieved. Ignoring.\n", inst->seqNum);
+ delete state;
+ delete pkt->req;
+ delete pkt;
+ return;
+ }
// If this is a split access, wait until all packets are received.
if (TheISA::HasUnalignedMemAcc && !state->complete()) {
template <class Impl>
LSQUnit<Impl>::LSQUnit()
: loads(0), stores(0), storesToWB(0), cacheBlockMask(0), stalled(false),
- isStoreBlocked(false), isLoadBlocked(false),
- loadBlockedHandled(false), storeInFlight(false), hasPendingPkt(false)
+ isStoreBlocked(false), storeInFlight(false), hasPendingPkt(false)
{
}
retryPkt = NULL;
memDepViolator = NULL;
- blockedLoadSeqNum = 0;
-
stalled = false;
- isLoadBlocked = false;
- loadBlockedHandled = false;
cacheBlockMask = ~(cpu->cacheLineSize() - 1);
}
}
iewStage->instToCommit(inst);
iewStage->activityThisCycle();
- } else if (!loadBlocked()) {
+ } else {
assert(inst->effAddrValid());
int load_idx = inst->lqIdx;
incrLdIdx(load_idx);
((!needsTSO) || (!storeInFlight)) &&
usedPorts < cachePorts) {
- if (isStoreBlocked || lsq->cacheBlocked()) {
+ if (isStoreBlocked) {
DPRINTF(LSQUnit, "Unable to write back any more stores, cache"
" is blocked!\n");
break;
++lsqSquashedLoads;
}
- if (isLoadBlocked) {
- if (squashed_num < blockedLoadSeqNum) {
- isLoadBlocked = false;
- loadBlockedHandled = false;
- blockedLoadSeqNum = 0;
- }
- }
-
if (memDepViolator && squashed_num < memDepViolator->seqNum) {
memDepViolator = NULL;
}
++lsqCacheBlocked;
assert(retryPkt == NULL);
retryPkt = data_pkt;
- lsq->setRetryTid(lsqID);
return false;
}
return true;
}
retryPkt = NULL;
isStoreBlocked = false;
- lsq->setRetryTid(InvalidThreadID);
// Send any outstanding packet.
if (TheISA::HasUnalignedMemAcc && state->pktToSend) {
} else {
// Still blocked!
++lsqCacheBlocked;
- lsq->setRetryTid(lsqID);
}
- } else if (isLoadBlocked) {
- DPRINTF(LSQUnit, "Loads squash themselves and all younger insts, "
- "no need to resend packet.\n");
- } else {
- DPRINTF(LSQUnit, "Retry received but LSQ is no longer blocked.\n");
}
}
/*
- * Copyright (c) 2012 ARM Limited
+ * Copyright (c) 2012, 2014 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
/** Replays all instructions that have been rescheduled by moving them to
* the ready list.
*/
- void replay(DynInstPtr &inst);
+ void replay();
/** Completes a memory instruction. */
void completed(DynInstPtr &inst);
/*
- * Copyright (c) 2012 ARM Limited
+ * Copyright (c) 2012, 2014 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
template <class MemDepPred, class Impl>
void
-MemDepUnit<MemDepPred, Impl>::replay(DynInstPtr &inst)
+MemDepUnit<MemDepPred, Impl>::replay()
{
DynInstPtr temp_inst;