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:
aperais
2024-09-11 17:43:31 +02:00
committed by GitHub
parent 0da65b31c2
commit ba5886aee7
4 changed files with 60 additions and 2 deletions

View File

@@ -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());

View File

@@ -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]; }

View File

@@ -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

View File

@@ -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;