STATUS status = tc->readMiscReg(MISCREG_STATUS);
// Set fault handler privilege mode
- if (pp != PRV_M &&
- bits(tc->readMiscReg(MISCREG_MEDELEG), _code) != 0) {
- prv = PRV_S;
- }
- if (pp == PRV_U &&
- bits(tc->readMiscReg(MISCREG_SEDELEG), _code) != 0) {
- prv = PRV_U;
+ if (isInterrupt()) {
+ if (pp != PRV_M &&
+ bits(tc->readMiscReg(MISCREG_MIDELEG), _code) != 0) {
+ prv = PRV_S;
+ }
+ if (pp == PRV_U &&
+ bits(tc->readMiscReg(MISCREG_SIDELEG), _code) != 0) {
+ prv = PRV_U;
+ }
+ } else {
+ if (pp != PRV_M &&
+ bits(tc->readMiscReg(MISCREG_MEDELEG), _code) != 0) {
+ prv = PRV_S;
+ }
+ if (pp == PRV_U &&
+ bits(tc->readMiscReg(MISCREG_SEDELEG), _code) != 0) {
+ prv = PRV_U;
+ }
}
// Set fault registers and status
tc->setMiscReg(MISCREG_STATUS, status);
// Set PC to fault handler address
- pcState.set(tc->readMiscReg(tvec) >> 2);
+ Addr addr = tc->readMiscReg(tvec) >> 2;
+ if (isInterrupt() && bits(tc->readMiscReg(tvec), 1, 0) == 1)
+ addr += 4 * _code;
+ pcState.set(addr);
} else {
invokeSE(tc, inst);
advancePC(pcState, inst);
void Reset::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{
- if (FullSystem) {
- tc->getCpuPtr()->clearInterrupts(tc->threadId());
- tc->clearArchRegs();
- }
-
tc->setMiscReg(MISCREG_PRV, PRV_M);
STATUS status = tc->readMiscReg(MISCREG_STATUS);
status.mie = 0;
#ifndef __ARCH_RISCV_FAULTS_HH__
#define __ARCH_RISCV_FAULTS_HH__
-#include <map>
#include <string>
#include "arch/riscv/isa.hh"
FloatInvalid = 0x10
};
+/*
+ * In RISC-V, exception and interrupt codes share some values. They can be
+ * differentiated by an 'Interrupt' flag that is enabled for interrupt faults
+ * but not exceptions. The full fault cause can be computed by placing the
+ * exception (or interrupt) code in the least significant bits of the CAUSE
+ * CSR and then setting the highest bit of CAUSE with the 'Interrupt' flag.
+ * For more details on exception causes, see Chapter 3.1.20 of the RISC-V
+ * privileged specification v 1.10. Codes are enumerated in Table 3.6.
+ */
enum ExceptionCode : MiscReg {
INST_ADDR_MISALIGNED = 0,
INST_ACCESS = 1,
INST_PAGE = 12,
LOAD_PAGE = 13,
STORE_PAGE = 15,
- AMO_PAGE = 15
+ AMO_PAGE = 15,
+
+ INT_SOFTWARE_USER = 0,
+ INT_SOFTWARE_SUPER = 1,
+ INT_SOFTWARE_MACHINE = 3,
+ INT_TIMER_USER = 4,
+ INT_TIMER_SUPER = 5,
+ INT_TIMER_MACHINE = 7,
+ INT_EXT_USER = 8,
+ INT_EXT_SUPER = 9,
+ INT_EXT_MACHINE = 11,
+ NumInterruptTypes
};
class RiscvFault : public FaultBase
StaticInst::nullStaticInstPtr) override;
};
+class InterruptFault : public RiscvFault
+{
+ public:
+ InterruptFault(ExceptionCode c) : RiscvFault("interrupt", true, c) {}
+ InterruptFault(int c) : InterruptFault(static_cast<ExceptionCode>(c)) {}
+};
+
class InstFault : public RiscvFault
{
protected:
#ifndef __ARCH_RISCV_INTERRUPT_HH__
#define __ARCH_RISCV_INTERRUPT_HH__
+#include <bitset>
+#include <memory>
+
+#include "arch/riscv/faults.hh"
+#include "arch/riscv/registers.hh"
#include "base/logging.hh"
#include "cpu/thread_context.hh"
+#include "debug/Interrupt.hh"
#include "params/RiscvInterrupts.hh"
#include "sim/sim_object.hh"
namespace RiscvISA {
+/*
+ * This is based on version 1.10 of the RISC-V privileged ISA reference,
+ * chapter 3.1.14.
+ */
class Interrupts : public SimObject
{
private:
BaseCPU * cpu;
+ std::bitset<NumInterruptTypes> ip;
+ std::bitset<NumInterruptTypes> ie;
public:
typedef RiscvInterruptsParams Params;
return dynamic_cast<const Params *>(_params);
}
- Interrupts(Params * p) : SimObject(p), cpu(nullptr)
- {}
+ Interrupts(Params * p) : SimObject(p), cpu(nullptr), ip(0), ie(0) {}
- void
- setCPU(BaseCPU * _cpu)
+ void setCPU(BaseCPU * _cpu) { cpu = _cpu; }
+
+ std::bitset<NumInterruptTypes>
+ globalMask(ThreadContext *tc) const
+ {
+ INTERRUPT mask;
+ STATUS status = tc->readMiscReg(MISCREG_STATUS);
+ if (status.mie)
+ mask.mei = mask.mti = mask.msi = 1;
+ if (status.sie)
+ mask.sei = mask.sti = mask.ssi = 1;
+ if (status.uie)
+ mask.uei = mask.uti = mask.usi = 1;
+ return std::bitset<NumInterruptTypes>(mask);
+ }
+
+ bool checkInterrupt(int num) const { return ip[num] && ie[num]; }
+ bool checkInterrupts(ThreadContext *tc) const
+ {
+ return (ip & ie & globalMask(tc)).any();
+ }
+
+ Fault
+ getInterrupt(ThreadContext *tc) const
{
- cpu = _cpu;
+ assert(checkInterrupts(tc));
+ std::bitset<NumInterruptTypes> mask = globalMask(tc);
+ for (int c = 0; c < NumInterruptTypes; c++)
+ if (checkInterrupt(c) && mask[c])
+ return std::make_shared<InterruptFault>(c);
+ return NoFault;
}
+ void updateIntrInfo(ThreadContext *tc) {}
+
void
post(int int_num, int index)
{
- panic("Interrupts::post not implemented.\n");
+ DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
+ ip[int_num] = true;
}
void
clear(int int_num, int index)
{
- panic("Interrupts::clear not implemented.\n");
+ DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
+ ip[int_num] = false;
}
void
clearAll()
{
- warn_once("Interrupts::clearAll not implemented.\n");
+ DPRINTF(Interrupt, "All interrupts cleared\n");
+ ip = 0;
}
- bool
- checkInterrupts(ThreadContext *tc) const
- {
- warn_once("Interrupts::checkInterrupts just rudimentary implemented");
- /**
- * read the machine interrupt register in order to check if interrupts
- * are pending
- * should be sufficient for now, as interrupts
- * are not implemented at all
- */
- if (tc->readMiscReg(MISCREG_IP))
- return true;
-
- return false;
- }
+ MiscReg readIP() const { return (MiscReg)ip.to_ulong(); }
+ MiscReg readIE() const { return (MiscReg)ie.to_ulong(); }
+ void setIP(const MiscReg& val) { ip = val; }
+ void setIE(const MiscReg& val) { ie = val; }
- Fault
- getInterrupt(ThreadContext *tc)
+ void
+ serialize(CheckpointOut &cp)
{
- assert(checkInterrupts(tc));
- panic("Interrupts::getInterrupt not implemented.\n");
+ SERIALIZE_SCALAR(ip.to_ulong());
+ SERIALIZE_SCALAR(ie.to_ulong());
}
void
- updateIntrInfo(ThreadContext *tc)
+ unserialize(CheckpointIn &cp)
{
- panic("Interrupts::updateIntrInfo not implemented.\n");
+ long reg;
+ UNSERIALIZE_SCALAR(reg);
+ ip = reg;
+ UNSERIALIZE_SCALAR(reg);
+ ie = reg;
}
};
} // namespace RiscvISA
-#endif // __ARCH_RISCV_INTERRUPT_HH__
-
+#endif // __ARCH_RISCV_INTERRUPT_HH__
\ No newline at end of file
warn("Instruction counter disabled.\n");
return 0;
}
+ case MISCREG_IP:
+ return tc->getCpuPtr()->getInterruptController(tc->threadId())
+ ->readIP();
+ case MISCREG_IE:
+ return tc->getCpuPtr()->getInterruptController(tc->threadId())
+ ->readIE();
default:
// Try reading HPM counters
// As a placeholder, all HPM counters are just cycle counters
// Ignore writes to HPM counters for now
warn("Ignoring write to %s.\n", CSRData.at(misc_reg).name);
} else {
- setMiscRegNoEffect(misc_reg, val);
+ switch (misc_reg) {
+ case MISCREG_IP:
+ return tc->getCpuPtr()->getInterruptController(tc->threadId())
+ ->setIP(val);
+ case MISCREG_IE:
+ return tc->getCpuPtr()->getInterruptController(tc->threadId())
+ ->setIE(val);
+ default:
+ setMiscRegNoEffect(misc_reg, val);
+ }
}
}
} else {
DPRINTF(RiscvMisc, "Writing %#x to CSR %s.\n", data,
CSRData.at(csr).name);
+ INTERRUPT oldinterrupt = olddata;
+ INTERRUPT newinterrupt = data;
switch (csr) {
case CSR_FCSR:
xc->setMiscReg(MISCREG_FFLAGS, bits(data, 4, 0));
xc->setMiscReg(MISCREG_FRM, bits(data, 7, 5));
break;
+ case CSR_MIP: case CSR_MIE:
+ if (oldinterrupt.mei == newinterrupt.mei &&
+ oldinterrupt.mti == newinterrupt.mti &&
+ oldinterrupt.msi == newinterrupt.msi) {
+ xc->setMiscReg(CSRData.at(csr).physIndex,data);
+ } else {
+ std::string error = "Interrupt m bits are "
+ "read-only\n";
+ fault = make_shared<IllegalInstFault>(error,
+ machInst);
+ }
+ break;
default:
xc->setMiscReg(CSRData.at(csr).physIndex, data);
break;