arch-riscv: Extend wfi behavior (#1364)
At the moment, a hart does not halt if there are pending interrupts. However, an implementation can also consider the enable status of the individual interrupts, i.e., a halted hart would only resume if there are locally enabled pending interrupts. This commit introduces this behavior. The wfi behavior is controlled by the new configuration variable wfi_pending_resume of RiscvISA. Change-Id: I316239f9732c6e73e6ad692491bca08d773dd995 --------- Signed-off-by: Robert Hauser <robert.hauser@uni-rostock.de>
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
# Copyright (c) 2016 RISC-V Foundation
|
||||
# Copyright (c) 2016 The University of Virginia
|
||||
# Copyright (c) 2023 The Regents of the University of California
|
||||
# Copyright (c) 2024 University of Rostock
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@@ -114,6 +115,16 @@ class RiscvISA(BaseISA):
|
||||
enable_Zicbom_fs = Param.Bool(True, "Enable Zicbom extension in FS mode")
|
||||
enable_Zicboz_fs = Param.Bool(True, "Enable Zicboz extension in FS mode")
|
||||
|
||||
wfi_resume_on_pending = Param.Bool(
|
||||
False,
|
||||
"If wfi_resume_on_pending is set to True, the hart will resume "
|
||||
"execution when interrupt becomes pending. The local enabled status "
|
||||
"is not considered.\n"
|
||||
"If wfi_resume_on_pending is set to False, the hart will only "
|
||||
"resume the execution when an locally enabled interrupt becomes "
|
||||
"pending.",
|
||||
)
|
||||
|
||||
def get_isa_string(self):
|
||||
isa_extensions = []
|
||||
# check for the base ISA type
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Copyright (c) 2016 The University of Virginia
|
||||
* Copyright (c) 2020 Barkhausen Institut
|
||||
* Copyright (c) 2022 Google LLC
|
||||
* Copyright (c) 2024 University of Rostock
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -258,7 +259,8 @@ RegClass ccRegClass(CCRegClass, CCRegClassName, 0, debug::IntRegs);
|
||||
|
||||
ISA::ISA(const Params &p) : BaseISA(p, "riscv"),
|
||||
_rvType(p.riscv_type), enableRvv(p.enable_rvv), vlen(p.vlen), elen(p.elen),
|
||||
_privilegeModeSet(p.privilege_mode_set)
|
||||
_privilegeModeSet(p.privilege_mode_set),
|
||||
_wfiResumeOnPending(p.wfi_resume_on_pending)
|
||||
{
|
||||
_regClasses.push_back(&intRegClass);
|
||||
_regClasses.push_back(&floatRegClass);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* Copyright (c) 2016 RISC-V Foundation
|
||||
* Copyright (c) 2016 The University of Virginia
|
||||
* Copyright (c) 2020 Barkhausen Institut
|
||||
* Coypright (c) 2024 University of Rostock
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -98,6 +99,15 @@ class ISA : public BaseISA
|
||||
*/
|
||||
PrivilegeModeSet _privilegeModeSet;
|
||||
|
||||
/**
|
||||
* The WFI instruction can halt the execution of a hart.
|
||||
* If this variable is set true, the execution resumes if
|
||||
* an interrupt becomes pending. If this variable is set
|
||||
* to false, the execution only resumes if an locally enabled
|
||||
* interrupt becomes pending.
|
||||
*/
|
||||
const bool _wfiResumeOnPending;
|
||||
|
||||
public:
|
||||
using Params = RiscvISAParams;
|
||||
|
||||
@@ -170,6 +180,8 @@ class ISA : public BaseISA
|
||||
|
||||
PrivilegeModeSet getPrivilegeModeSet() { return _privilegeModeSet; }
|
||||
|
||||
bool resumeOnPending() { return _wfiResumeOnPending; }
|
||||
|
||||
virtual Addr getFaultHandlerAddr(
|
||||
RegIndex idx, uint64_t cause, bool intr) const;
|
||||
};
|
||||
|
||||
@@ -4873,16 +4873,29 @@ decode QUADRANT default Unknown::unknown() {
|
||||
"wfi in user mode or TW enabled",
|
||||
machInst);
|
||||
}
|
||||
// Go to sleep only if there's no pending interrupt
|
||||
// at all, including masked interrupts.
|
||||
auto tc = xc->tcBase();
|
||||
auto cpu = tc->getCpuPtr();
|
||||
auto ic = dynamic_cast<RiscvISA::Interrupts*>(
|
||||
cpu->getInterruptController(tc->threadId()));
|
||||
auto isa = dynamic_cast<RiscvISA::ISA*>(
|
||||
tc->getIsaPtr());
|
||||
panic_if(!ic, "Invalid Interrupt Controller.");
|
||||
if (ic->readIP() == 0
|
||||
if (isa->resumeOnPending()) {
|
||||
// Go to sleep only if there are no pending
|
||||
// interrupts at all, and no non-maskable
|
||||
// interrupts.
|
||||
if (ic->readIP() == 0
|
||||
&& xc->readMiscReg(MISCREG_NMIP) == 0) {
|
||||
tc->quiesce();
|
||||
tc->quiesce();
|
||||
}
|
||||
} else {
|
||||
// Go to sleep only if there are no enabled
|
||||
// pending interrupts at all, and no
|
||||
// non-maskable interrupts
|
||||
if (!(ic->readIP() & ic->readIE())
|
||||
&& xc->readMiscReg(MISCREG_NMIP) == 0) {
|
||||
tc->quiesce();
|
||||
}
|
||||
}
|
||||
}}, IsNonSpeculative, IsQuiesce,
|
||||
IsSerializeAfter, No_OpClass, IsSquashAfter);
|
||||
|
||||
Reference in New Issue
Block a user