diff options
Diffstat (limited to 'src/arch/riscv')
-rw-r--r-- | src/arch/riscv/faults.cc | 35 | ||||
-rw-r--r-- | src/arch/riscv/faults.hh | 30 | ||||
-rw-r--r-- | src/arch/riscv/interrupts.hh | 97 | ||||
-rw-r--r-- | src/arch/riscv/isa.cc | 17 | ||||
-rw-r--r-- | src/arch/riscv/isa/formats/standard.isa | 14 |
5 files changed, 146 insertions, 47 deletions
diff --git a/src/arch/riscv/faults.cc b/src/arch/riscv/faults.cc index a151334c4..2cf6d768f 100644 --- a/src/arch/riscv/faults.cc +++ b/src/arch/riscv/faults.cc @@ -61,13 +61,24 @@ RiscvFault::invoke(ThreadContext *tc, const StaticInstPtr &inst) 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 @@ -116,7 +127,10 @@ RiscvFault::invoke(ThreadContext *tc, const StaticInstPtr &inst) 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); @@ -126,11 +140,6 @@ RiscvFault::invoke(ThreadContext *tc, const StaticInstPtr &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; diff --git a/src/arch/riscv/faults.hh b/src/arch/riscv/faults.hh index 2176f889b..a69b75bc1 100644 --- a/src/arch/riscv/faults.hh +++ b/src/arch/riscv/faults.hh @@ -34,7 +34,6 @@ #ifndef __ARCH_RISCV_FAULTS_HH__ #define __ARCH_RISCV_FAULTS_HH__ -#include <map> #include <string> #include "arch/riscv/isa.hh" @@ -53,6 +52,15 @@ enum FloatException : MiscReg { 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, @@ -70,7 +78,18 @@ enum ExceptionCode : MiscReg { 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 @@ -106,6 +125,13 @@ class Reset : 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: diff --git a/src/arch/riscv/interrupts.hh b/src/arch/riscv/interrupts.hh index 60a5b5bc5..729af6fb9 100644 --- a/src/arch/riscv/interrupts.hh +++ b/src/arch/riscv/interrupts.hh @@ -31,8 +31,14 @@ #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" @@ -41,10 +47,16 @@ class ThreadContext; 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; @@ -55,64 +67,87 @@ class Interrupts : public SimObject 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 diff --git a/src/arch/riscv/isa.cc b/src/arch/riscv/isa.cc index 6824e7034..d99a74220 100644 --- a/src/arch/riscv/isa.cc +++ b/src/arch/riscv/isa.cc @@ -139,6 +139,12 @@ ISA::readMiscReg(int misc_reg, ThreadContext *tc) 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 @@ -175,7 +181,16 @@ ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc) // 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); + } } } diff --git a/src/arch/riscv/isa/formats/standard.isa b/src/arch/riscv/isa/formats/standard.isa index e9539fe52..b2f8ee4bf 100644 --- a/src/arch/riscv/isa/formats/standard.isa +++ b/src/arch/riscv/isa/formats/standard.isa @@ -256,11 +256,25 @@ def template CSRExecute {{ } 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; |