arch-arm: raise/clear IRQ when writing to PMOVSCLR/SET
authorGiacomo Travaglini <giacomo.travaglini@arm.com>
Tue, 4 Sep 2018 11:17:15 +0000 (13:17 +0200)
committerGiacomo Travaglini <giacomo.travaglini@arm.com>
Fri, 28 Sep 2018 10:13:05 +0000 (10:13 +0000)
Writing a 1 to the Overflow Flag Status register should trigger an
interrupt raise/clear depending on the register we are currently using
(PMOVSCLR for clearing and PMOVSSET for raising).

Change-Id: I2091456685a245712045cf7a4932ac36b7dded1d
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/12531
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>

src/arch/arm/pmu.cc
src/arch/arm/pmu.hh

index b569b6967e8ed4006c88be25d77de4d8af246103..90d9f1a087cb29fe179bd7fb2132d788fc762393 100644 (file)
@@ -214,7 +214,7 @@ PMU::setMiscReg(int misc_reg, MiscReg val)
 
       case MISCREG_PMOVSCLR_EL0:
       case MISCREG_PMOVSR:
-        reg_pmovsr &= ~val;
+        setOverflowStatus(reg_pmovsr & ~val);
         return;
 
       case MISCREG_PMSWINC_EL0:
@@ -286,7 +286,7 @@ PMU::setMiscReg(int misc_reg, MiscReg val)
 
       case MISCREG_PMOVSSET_EL0:
       case MISCREG_PMOVSSET:
-        reg_pmovsr |= val;
+        setOverflowStatus(reg_pmovsr | val);
         return;
 
       default:
@@ -644,6 +644,20 @@ PMU::setCounterTypeRegister(CounterId id, PMEVTYPER_t val)
     }
 }
 
+void
+PMU::setOverflowStatus(MiscReg new_val)
+{
+    const bool int_old = reg_pmovsr != 0;
+    const bool int_new = new_val != 0;
+
+    reg_pmovsr = new_val;
+    if (int_old && !int_new) {
+        clearInterrupt();
+    } else if (!int_old && int_new && (reg_pminten & reg_pmovsr)) {
+        raiseInterrupt();
+    }
+}
+
 void
 PMU::raiseInterrupt()
 {
@@ -656,6 +670,18 @@ PMU::raiseInterrupt()
     }
 }
 
+void
+PMU::clearInterrupt()
+{
+    if (interrupt) {
+        DPRINTF(PMUVerbose, "Clearing PMU interrupt.\n");
+        interrupt->clear();
+    } else {
+        warn_once("Dropping PMU interrupt as no interrupt has "
+                  "been specified\n");
+    }
+}
+
 void
 PMU::serialize(CheckpointOut &cp) const
 {
index 61516cffd4a853d937f29ad71b15a2f9ba1f5d66..ee68272e73ef2bdfbda6ed21ebeb3524228aa27e 100644 (file)
@@ -218,6 +218,11 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
      */
     void raiseInterrupt();
 
+    /**
+     * Clear a PMU interrupt.
+     */
+    void clearInterrupt();
+
     /**
      * Get the value of a performance counter.
      *
@@ -269,6 +274,18 @@ class PMU : public SimObject, public ArmISA::BaseISADevice {
      */
     void setCounterTypeRegister(CounterId id, PMEVTYPER_t type);
 
+    /**
+     * Used for writing the Overflow Flag Status Register (SET/CLR)
+     *
+     * This method implements a write to the PMOVSSET/PMOVSCLR registers.
+     * It is capturing change of state in the register bits so that
+     * the overflow interrupt can be raised/cleared as a side effect
+     * of the write.
+     *
+     * @param new_val New value of the Overflow Status Register
+     */
+    void setOverflowStatus(MiscReg new_val);
+
   protected: /* Probe handling and counter state */
     struct CounterState;