/** The kind of fault this instruction has generated. */
Fault fault;
- /** The memory request. */
- Request *req;
-
/** Pointer to the data for the memory access. */
uint8_t *memData;
/** The effective virtual address (lds & stores only). */
Addr effAddr;
+ /** Is the effective virtual address valid. */
+ bool effAddrValid;
+
/** The effective physical address. */
Addr physEffAddr;
/** Returns whether or not this instruction is ready to issue. */
bool readyToIssue() const { return status[CanIssue]; }
+ /** Clears this instruction being able to issue. */
+ void clearCanIssue() { status.reset(CanIssue); }
+
/** Sets this instruction as issued from the IQ. */
void setIssued() { status.set(Issued); }
/** Returns whether or not this instruction has issued. */
bool isIssued() const { return status[Issued]; }
+ /** Clears this instruction as being issued. */
+ void clearIssued() { status.reset(Issued); }
+
/** Sets this instruction as executed. */
void setExecuted() { status.set(Executed); }
*/
bool eaCalcDone;
+ /** Is this instruction's memory access uncacheable. */
+ bool isUncacheable;
+
+ /** Has this instruction generated a memory request. */
+ bool reqMade;
+
public:
/** Sets the effective address. */
void setEA(Addr &ea) { instEffAddr = ea; eaCalcDone = true; }
/** Whether or not the memory operation is done. */
bool memOpDone;
+ /** Is this instruction's memory access uncacheable. */
+ bool uncacheable() { return isUncacheable; }
+
+ /** Has this instruction generated a memory request. */
+ bool hasRequest() { return reqMade; }
+
public:
/** Load queue index. */
int16_t lqIdx;
inline Fault
BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
{
- // Sometimes reads will get retried, so they may come through here
- // twice.
- if (!req) {
- req = new Request();
- req->setVirt(asid, addr, sizeof(T), flags, this->PC);
- req->setThreadContext(thread->readCpuId(), threadNumber);
- } else {
- assert(addr == req->getVaddr());
- }
+ reqMade = true;
+ Request *req = new Request();
+ req->setVirt(asid, addr, sizeof(T), flags, this->PC);
+ req->setThreadContext(thread->readCpuId(), threadNumber);
if ((req->getVaddr() & (TheISA::VMPageSize - 1)) + req->getSize() >
TheISA::VMPageSize) {
+ delete req;
return TheISA::genAlignmentFault();
}
fault = cpu->translateDataReadReq(req, thread);
+ if (req->isUncacheable())
+ isUncacheable = true;
+
if (fault == NoFault) {
effAddr = req->getVaddr();
+ effAddrValid = true;
physEffAddr = req->getPaddr();
memReqFlags = req->getFlags();
// Commit will have to clean up whatever happened. Set this
// instruction as executed.
this->setExecuted();
+ delete req;
}
if (traceData) {
traceData->setData(data);
}
- assert(req == NULL);
-
- req = new Request();
+ reqMade = true;
+ Request *req = new Request();
req->setVirt(asid, addr, sizeof(T), flags, this->PC);
req->setThreadContext(thread->readCpuId(), threadNumber);
if ((req->getVaddr() & (TheISA::VMPageSize - 1)) + req->getSize() >
TheISA::VMPageSize) {
+ delete req;
return TheISA::genAlignmentFault();
}
fault = cpu->translateDataWriteReq(req, thread);
+ if (req->isUncacheable())
+ isUncacheable = true;
+
if (fault == NoFault) {
effAddr = req->getVaddr();
+ effAddrValid = true;
physEffAddr = req->getPaddr();
memReqFlags = req->getFlags();
#if 0
#else
fault = cpu->write(req, data, sqIdx);
#endif
- }
-
- if (res) {
- // always return some result to keep misspeculated paths
- // (which will ignore faults) deterministic
- *res = (fault == NoFault) ? req->getScResult() : 0;
+ } else {
+ delete req;
}
return fault;
void
BaseDynInst<Impl>::initVars()
{
- req = NULL;
memData = NULL;
effAddr = 0;
+ effAddrValid = false;
physEffAddr = 0;
+ isUncacheable = false;
+ reqMade = false;
readyRegs = 0;
instResult.integer = 0;
template <class Impl>
BaseDynInst<Impl>::~BaseDynInst()
{
- if (req) {
- delete req;
- }
-
if (memData) {
delete [] memData;
}
BaseDynInst<Impl>::markSrcRegReady()
{
if (++readyRegs == numSrcRegs()) {
- status.set(CanIssue);
+ setCanIssue();
}
}
fault = TheISA::genMachineCheckFault();
delete mem_req;
memReq[tid] = NULL;
+ warn("Bad address!\n");
}
assert(retryPkt == NULL);
assert(retryTid == -1);
// Get rid of the retrying packet if it was from this thread.
if (retryTid == tid) {
assert(cacheBlocked);
- cacheBlocked = false;
- retryTid = -1;
- delete retryPkt->req;
- delete retryPkt;
+ if (retryPkt) {
+ delete retryPkt->req;
+ delete retryPkt;
+ }
retryPkt = NULL;
+ retryTid = -1;
}
fetchStatus[tid] = Squashing;
///FIXME This needs to be more robust in dealing with delay slots
#if !ISA_HAS_DELAY_SLOT
- predicted_branch |=
+// predicted_branch |=
#endif
lookupAndUpdateNextPC(instruction, next_PC, next_NPC);
predicted_branch |= (next_PC != fetch_NPC);
// until commit handles the fault. The only other way it can
// wake up is if a squash comes along and changes the PC.
#if FULL_SYSTEM
- assert(numInst != fetchWidth);
+ assert(numInst < fetchWidth);
// Get a sequence number.
inst_seq = cpu->getAndIncrementInstSeq();
// We will use a nop in order to carry the fault.
(load_idx != loadHead || !load_inst->isAtCommit())) {
iewStage->rescheduleMemInst(load_inst);
++lsqRescheduledLoads;
+
+ // Must delete request now that it wasn't handed off to
+ // memory. This is quite ugly. @todo: Figure out the proper
+ // place to really handle request deletes.
+ delete req;
return TheISA::genMachineCheckFault();
}
if (store_size == 0)
continue;
+ else if (storeQueue[store_idx].inst->uncacheable())
+ continue;
+
+ assert(storeQueue[store_idx].inst->effAddrValid);
// Check if the store data is within the lower and upper bounds of
// addresses that the request needs.
storeQueue[store_idx].inst->effAddr;
// If the store's data has all of the data needed, we can forward.
- if (store_has_lower_limit && store_has_upper_limit) {
+ if ((store_has_lower_limit && store_has_upper_limit)) {
// Get shift amount for offset into the store's data.
int shift_amt = req->getVaddr() & (store_size - 1);
// @todo: Magic number, assumes byte addressing
// If it's already been written back, then don't worry about
// stalling on it.
if (storeQueue[store_idx].completed) {
+ panic("Should not check one of these");
continue;
}
// rescheduled eventually
iewStage->rescheduleMemInst(load_inst);
iewStage->decrWb(load_inst->seqNum);
+ load_inst->clearIssued();
++lsqRescheduledLoads;
// Do not generate a writeback event as this instruction is not
"Store idx %i to load addr %#x\n",
store_idx, req->getVaddr());
- ++lsqBlockedLoads;
+ // Must delete request now that it wasn't handed off to
+ // memory. This is quite ugly. @todo: Figure out the
+ // proper place to really handle request deletes.
+ delete req;
+
return NoFault;
}
}
// Delete state and data packet because a load retry
// initiates a pipeline restart; it does not retry.
delete state;
+ delete data_pkt->req;
delete data_pkt;
+ req = NULL;
+
if (result == Packet::BadAddress) {
return TheISA::genMachineCheckFault();
}
// If the cache was blocked, or has become blocked due to the access,
// handle it.
if (lsq->cacheBlocked()) {
+ if (req)
+ delete req;
+
++lsqCacheBlocked;
iewStage->decrWb(load_inst->seqNum);
if (isSwitchedOut() || inst->isSquashed()) {
iewStage->decrWb(inst->seqNum);
delete state;
+ delete pkt->req;
delete pkt;
return;
} else {
}
delete state;
+ delete pkt->req;
delete pkt;
}
Fault
LSQUnit<Impl>::executeLoad(DynInstPtr &inst)
{
+ using namespace TheISA;
// Execute a specific load.
Fault load_fault = NoFault;
DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n",
inst->readPC(),inst->seqNum);
+ assert(!inst->isSquashed());
+
load_fault = inst->initiateAcc();
// If the instruction faulted, then we need to send it along to commit
// realizes there is activity.
// Mark it as executed unless it is an uncached load that
// needs to hit the head of commit.
- if (!(inst->req && inst->req->isUncacheable()) ||
+ if (!(inst->hasRequest() && inst->uncacheable()) ||
inst->isAtCommit()) {
inst->setExecuted();
}
iewStage->instToCommit(inst);
iewStage->activityThisCycle();
+ } else if (!loadBlocked()) {
+ assert(inst->effAddrValid);
+ int load_idx = inst->lqIdx;
+ incrLdIdx(load_idx);
+ while (load_idx != loadTail) {
+ // Really only need to check loads that have actually executed
+
+ // @todo: For now this is extra conservative, detecting a
+ // violation if the addresses match assuming all accesses
+ // are quad word accesses.
+
+ // @todo: Fix this, magic number being used here
+ if (loadQueue[load_idx]->effAddrValid &&
+ (loadQueue[load_idx]->effAddr >> 8) ==
+ (inst->effAddr >> 8)) {
+ // A load incorrectly passed this load. Squash and refetch.
+ // For now return a fault to show that it was unsuccessful.
+ DynInstPtr violator = loadQueue[load_idx];
+ if (!memDepViolator ||
+ (violator->seqNum < memDepViolator->seqNum)) {
+ memDepViolator = violator;
+ } else {
+ break;
+ }
+
+ ++lsqMemOrderViolation;
+
+ return genMachineCheckFault();
+ }
+
+ incrLdIdx(load_idx);
+ }
}
return load_fault;
DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n",
store_inst->readPC(), store_inst->seqNum);
+ assert(!store_inst->isSquashed());
+
// Check the recently completed loads to see if any match this store's
// address. If so, then we have a memory ordering violation.
int load_idx = store_inst->lqIdx;
++storesToWB;
}
- if (!memDepViolator) {
- while (load_idx != loadTail) {
- // Really only need to check loads that have actually executed
- // It's safe to check all loads because effAddr is set to
- // InvalAddr when the dyn inst is created.
-
- // @todo: For now this is extra conservative, detecting a
- // violation if the addresses match assuming all accesses
- // are quad word accesses.
-
- // @todo: Fix this, magic number being used here
- if ((loadQueue[load_idx]->effAddr >> 8) ==
- (store_inst->effAddr >> 8)) {
- // A load incorrectly passed this store. Squash and refetch.
- // For now return a fault to show that it was unsuccessful.
- memDepViolator = loadQueue[load_idx];
- ++lsqMemOrderViolation;
-
- return genMachineCheckFault();
+ assert(store_inst->effAddrValid);
+ while (load_idx != loadTail) {
+ // Really only need to check loads that have actually executed
+ // It's safe to check all loads because effAddr is set to
+ // InvalAddr when the dyn inst is created.
+
+ // @todo: For now this is extra conservative, detecting a
+ // violation if the addresses match assuming all accesses
+ // are quad word accesses.
+
+ // @todo: Fix this, magic number being used here
+ if (loadQueue[load_idx]->effAddrValid &&
+ (loadQueue[load_idx]->effAddr >> 8) ==
+ (store_inst->effAddr >> 8)) {
+ // A load incorrectly passed this store. Squash and refetch.
+ // For now return a fault to show that it was unsuccessful.
+ DynInstPtr violator = loadQueue[load_idx];
+ if (!memDepViolator ||
+ (violator->seqNum < memDepViolator->seqNum)) {
+ memDepViolator = violator;
+ } else {
+ break;
}
- incrLdIdx(load_idx);
+ ++lsqMemOrderViolation;
+
+ return genMachineCheckFault();
}
- // If we've reached this point, there was no violation.
- memDepViolator = NULL;
+ incrLdIdx(load_idx);
}
return store_fault;
panic("LSQ sent out a bad address for a completed store!");
}
// Need to handle becoming blocked on a store.
- DPRINTF(IEW, "D-Cache became blcoked when writing [sn:%lli], will"
+ DPRINTF(IEW, "D-Cache became blocked when writing [sn:%lli], will"
"retry later\n",
inst->seqNum);
isStoreBlocked = true;
}
}
+ if (memDepViolator && squashed_num < memDepViolator->seqNum) {
+ memDepViolator = NULL;
+ }
+
int store_idx = storeTail;
decrStIdx(store_idx);
storeQueue[store_idx].inst = NULL;
storeQueue[store_idx].canWB = 0;
+ // Must delete request now that it wasn't handed off to
+ // memory. This is quite ugly. @todo: Figure out the proper
+ // place to really handle request deletes.
+ delete storeQueue[store_idx].req;
+
storeQueue[store_idx].req = NULL;
--stores;