Alec Roelke has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/14377

Change subject: arch-riscv: Add interrupt handling
......................................................................

arch-riscv: Add interrupt handling

Implement the Interrupts SimObject for RISC-V. This basically just
handles setting and getting the values of the interrupt-pending and
interrupt-enable CSRs according to the privileged ISA reference chapter
3.1.14. Note that it does NOT implement the PLIC as defined in chapter
7, as that is used for handling external interrupts which are defined
based on peripherals that are available.

Change-Id: Ia1321430f870ff5a3950217266fde0511332485b
---
M src/arch/riscv/faults.cc
M src/arch/riscv/faults.hh
M src/arch/riscv/interrupts.hh
M src/arch/riscv/isa.cc
M src/arch/riscv/isa/formats/standard.isa
5 files changed, 137 insertions(+), 39 deletions(-)



diff --git a/src/arch/riscv/faults.cc b/src/arch/riscv/faults.cc
index 5f949b3..2cf6d76 100644
--- a/src/arch/riscv/faults.cc
+++ b/src/arch/riscv/faults.cc
@@ -61,13 +61,24 @@
         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 @@
         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);
diff --git a/src/arch/riscv/faults.hh b/src/arch/riscv/faults.hh
index 2176f88..7a05cb3 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"
@@ -70,7 +69,18 @@
     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 +116,13 @@
         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 f593eb6..729af6f 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 @@

 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,61 +67,87 @@
         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) { cpu = _cpu; }

-    bool
-    checkInterrupts(ThreadContext *tc) const
+    std::bitset<NumInterruptTypes>
+    globalMask(ThreadContext *tc) const
     {
-        return tc->readMiscReg(MISCREG_IP) != 0;
+        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)
+    getInterrupt(ThreadContext *tc) const
     {
         assert(checkInterrupts(tc));
-        panic("Interrupts::getInterrupt not implemented.\n");
+        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)
-    {
-        panic("Interrupts::updateIntrInfo not implemented.\n");
-    }
-
-    // Deprecated but still necessary for compatibility
+    void updateIntrInfo(ThreadContext *tc) {}

     void
     post(int int_num, int index)
     {
- 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;
+        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()
     {
-        panic("Interrupts::clearAll not implemented.\n");
+        DPRINTF(Interrupt, "All interrupts cleared\n");
+        ip = 0;
+    }
+
+    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; }
+
+    void
+    serialize(CheckpointOut &cp)
+    {
+        SERIALIZE_SCALAR(ip.to_ulong());
+        SERIALIZE_SCALAR(ie.to_ulong());
+    }
+
+    void
+    unserialize(CheckpointIn &cp)
+    {
+        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 6824e70..d99a742 100644
--- a/src/arch/riscv/isa.cc
+++ b/src/arch/riscv/isa.cc
@@ -139,6 +139,12 @@
             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 @@
         // 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 e9539fe..b2f8ee4 100644
--- a/src/arch/riscv/isa/formats/standard.isa
+++ b/src/arch/riscv/isa/formats/standard.isa
@@ -256,11 +256,25 @@
                     } 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;

--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/14377
To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: master
Gerrit-Change-Id: Ia1321430f870ff5a3950217266fde0511332485b
Gerrit-Change-Number: 14377
Gerrit-PatchSet: 1
Gerrit-Owner: Alec Roelke <[email protected]>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev

Reply via email to