cpu-o3: Panic if no FU exists for an instruction needing to issue (#1516)
At present, if an instruction requires a functional unit that is not present in the O3CPU config, O3CPU treats it as a 1-cycle operation that does not consume an FU. This seems like a silent failure : if I forgot to add a FU for a new operation type I added, then I don't want it to silently work "for free". The problem is that the code treats the FU allocator returning `NoCapableFU` for a given DynInst as equivalent to the case where the DynInst obtained an FU, with default latency of 1. This is because there is a single if statement that checks whether the FU allocator returned `NoFreeFU` or not, and `NoCapableFU` happens to be different. The change is to introduce `NoNeedFU` and to panic if the FU allocator returns `NoCapableFU` An improvement would be to use a strongly typed enum rather than integer constants. Thoughts ? In addition to unit tests, I have tested this with `main.py run` and get panics if I remove support for `IntMul` type in `O3CPU.py` in: ``` ./SuiteUID-asm-riscv-rv32um-ps-mul-o3-ALL-x86_64-opt/TestUID-asm-riscv-rv32um-ps-mul-o3-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-asm-riscv-rv32um-ps-mulh-o3-ALL-x86_64-opt/TestUID-asm-riscv-rv32um-ps-mulh-o3-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-asm-riscv-rv32um-ps-mulhsu-o3-ALL-x86_64-opt/TestUID-asm-riscv-rv32um-ps-mulhsu-o3-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-asm-riscv-rv32um-ps-mulhu-o3-ALL-x86_64-opt/TestUID-asm-riscv-rv32um-ps-mulhu-o3-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-asm-riscv-rv64um-ps-mul-o3-ALL-x86_64-opt/TestUID-asm-riscv-rv64um-ps-mul-o3-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-asm-riscv-rv64um-ps-mulh-o3-ALL-x86_64-opt/TestUID-asm-riscv-rv64um-ps-mulh-o3-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-asm-riscv-rv64um-ps-mulhsu-o3-ALL-x86_64-opt/TestUID-asm-riscv-rv64um-ps-mulhsu-o3-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-asm-riscv-rv64um-ps-mulhu-o3-ALL-x86_64-opt/TestUID-asm-riscv-rv64um-ps-mulhu-o3-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-asm-riscv-rv64um-ps-mulw-o3-ALL-x86_64-opt/TestUID-asm-riscv-rv64um-ps-mulw-o3-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-BaseCPUProcessor-arm-hello-ALL-x86_64-opt/TestUID-BaseCPUProcessor-arm-hello-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-cpu_test_ArmDerivO3CPU_Bubblesort-ALL-x86_64-opt/TestUID-cpu_test_ArmDerivO3CPU_Bubblesort-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-cpu_test_ArmDerivO3CPU_FloatMM-ALL-x86_64-opt/TestUID-cpu_test_ArmDerivO3CPU_FloatMM-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-cpu_test_RiscvDerivO3CPU_Bubblesort-ALL-x86_64-opt/TestUID-cpu_test_RiscvDerivO3CPU_Bubblesort-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-cpu_test_RiscvDerivO3CPU_FloatMM-ALL-x86_64-opt/TestUID-cpu_test_RiscvDerivO3CPU_FloatMM-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-o3-cpu_1-cores_classic_DualChannelDDR3_1600_arm_boot_test_to-tick-ALL-x86_64-opt/TestUID-o3-cpu_1-cores_classic_DualChannelDDR3_1600_arm_boot_test_to-tick-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-o3-cpu_1-cores_classic_DualChannelDDR3_1600_riscv-boot-test_to-tick-ALL-x86_64-opt/TestUID-o3-cpu_1-cores_classic_DualChannelDDR3_1600_riscv-boot-test_to-tick-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-test-arm-hello32-static-o3-ALL-x86_64-opt/TestUID-test-arm-hello32-static-o3-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-test-arm-hello64-static-o3-ALL-x86_64-opt/TestUID-test-arm-hello64-static-o3-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-test-mips-hello-o3-ALL-x86_64-opt/TestUID-test-mips-hello-o3-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-test-riscv-hello-o3-ALL-x86_64-opt/TestUID-test-riscv-hello-o3-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ./SuiteUID-test-riscv-print-this-o3-ALL-x86_64-opt/TestUID-test-riscv-print-this-o3-ALL-x86_64-opt/simerr.txt:src/cpu/o3/inst_queue.cc:905: panic: Processor cannot execute opclass:2 ``` Co-authored-by: Arthur perais <arthur.perais@univ-grenoble-alpes.fr>
This commit is contained in:
@@ -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());
|
||||
|
||||
|
||||
@@ -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]; }
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user