diff --git a/src/cpu/o3/commit.cc b/src/cpu/o3/commit.cc index 84a92997a1..1752fdc60a 100644 --- a/src/cpu/o3/commit.cc +++ b/src/cpu/o3/commit.cc @@ -964,6 +964,17 @@ Commit::commitInsts() // Record that the number of ROB entries has changed. changedROBNumEntries[tid] = true; + // Inst at head of ROB cannot execute because the CPU + // does not know how to (lack of FU). This is a misconfiguration, + // so panic. + } else if (head_inst->noCapableFU() && + head_inst->getFault() == NoFault) { + panic("CPU cannot execute [sn:%llu] op_class: %u but" + " did not trigger a fault. Do you need to update" + " the configuration and add a functional unit for" + " that op class?\n", + head_inst->seqNum, + head_inst->opClass()); } else { set(pc[tid], head_inst->pcState()); diff --git a/src/cpu/o3/dyn_inst.hh b/src/cpu/o3/dyn_inst.hh index 63bf5ac59d..9cb3d3caa9 100644 --- a/src/cpu/o3/dyn_inst.hh +++ b/src/cpu/o3/dyn_inst.hh @@ -187,6 +187,8 @@ class DynInst : public ExecContext, public RefCounted ReqMade, MemOpDone, HtmFromTransaction, + NoCapableFU, /// Processor does not have capability to + /// execute the instruction MaxFlags }; @@ -841,6 +843,16 @@ class DynInst : public ExecContext, public RefCounted /** Returns whether or not this instruction is squashed in the ROB. */ bool isSquashedInROB() const { return status[SquashedInROB]; } + /** Mark this instruction as having attempted to execute + * but CPU did not have a capable functional unit. + */ + void setNoCapableFU() { instFlags.set(NoCapableFU); } + + /** Returns whether or not this instruction attempted + * to execute and found not capable FU. + */ + bool noCapableFU() const { return instFlags[NoCapableFU]; } + /** Returns whether pinned registers are renamed */ bool isPinnedRegsRenamed() const { return status[PinnedRegsRenamed]; } diff --git a/src/cpu/o3/fu_pool.hh b/src/cpu/o3/fu_pool.hh index 3c88a694b0..f0f01c38d4 100644 --- a/src/cpu/o3/fu_pool.hh +++ b/src/cpu/o3/fu_pool.hh @@ -139,8 +139,31 @@ class FUPool : public SimObject FUPool(const Params &p); ~FUPool(); + /** + * Named constants to differentiate cases where an + * instruction asked the FUPool for a free FU + * but did not get one + */ + + /** + * Instruction asked for a FU but does not actually + * need any (e.g., NOP) + */ + static constexpr auto NoNeedFU = -3; + + /** + * Instruction asked for a FU but this FUPool does + * not have a FU for this instruction op type + */ static constexpr auto NoCapableFU = -2; + + /** + * Instruction asked for a FU but all FU for + * this op type have already been allocated to + * other instructions this cycle + */ static constexpr auto NoFreeFU = -1; + /** * Gets a FU providing the requested capability. Will mark the * unit as busy, but leaves the freeing of the unit up to the IEW diff --git a/src/cpu/o3/inst_queue.cc b/src/cpu/o3/inst_queue.cc index b236b7518e..b3cf330c37 100644 --- a/src/cpu/o3/inst_queue.cc +++ b/src/cpu/o3/inst_queue.cc @@ -812,7 +812,7 @@ InstructionQueue::scheduleReadyInsts() continue; } - int idx = FUPool::NoCapableFU; + int idx = FUPool::NoNeedFU; Cycles op_latency = Cycles(1); ThreadID tid = issuing_inst->threadNumber; @@ -832,7 +832,8 @@ InstructionQueue::scheduleReadyInsts() // If we have an instruction that doesn't require a FU, or a // valid FU, then schedule for execution. - if (idx != FUPool::NoFreeFU) { + if (idx > FUPool::NoFreeFU || idx == FUPool::NoNeedFU || + idx == FUPool::NoCapableFU) { if (op_latency == Cycles(1)) { i2e_info->size++; instsToExecute.push_back(issuing_inst); @@ -841,7 +842,17 @@ InstructionQueue::scheduleReadyInsts() // cycle if we used one. if (idx >= 0) fuPool->freeUnitNextCycle(idx); + + // CPU has no capable FU for the instruction + // but this may be OK if the instruction gets + // squashed. Remember this and give IEW + // the opportunity to trigger a fault + // if the instruction is unsupported. + // Otherwise, commit will panic. + if (idx == FUPool::NoCapableFU) + issuing_inst->setNoCapableFU(); } else { + assert(idx != FUPool::NoCapableFU); bool pipelined = fuPool->isPipelined(op_class); // Generate completion event for the FU ++wbOutstanding; @@ -898,6 +909,7 @@ InstructionQueue::scheduleReadyInsts() listOrder.erase(order_it++); iqStats.statIssuedInstType[tid][op_class]++; } else { + assert(idx == FUPool::NoFreeFU); iqStats.statFuBusy[op_class]++; iqStats.fuBusy[tid]++; ++order_it;