dev-arm: Factory SimObject for generating ArmInterruptPin
authorGiacomo Travaglini <giacomo.travaglini@arm.com>
Thu, 30 Aug 2018 15:43:02 +0000 (16:43 +0100)
committerGiacomo Travaglini <giacomo.travaglini@arm.com>
Mon, 10 Sep 2018 10:24:10 +0000 (10:24 +0000)
With this patch the python ArmInterruptPin SimObject matches to the
C++ ArmInterruptPinGen. The latter is in charge of generating
the ArmInterruptPin (which is not a SimObject anymore).
This is meant to ease the generation of ArmInterruptPins: by
not being SimObjects we are not forced to instantiate them
in the configuration script; we can generate them dynamically
instead throughout simulation.

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

src/arch/arm/pmu.cc
src/dev/arm/Gic.py
src/dev/arm/base_gic.cc
src/dev/arm/base_gic.hh
src/dev/arm/vio_mmio.cc

index 13b23c745971c05eaf84c641453c575274c128eb..b569b6967e8ed4006c88be25d77de4d8af246103 100644 (file)
@@ -67,7 +67,7 @@ PMU::PMU(const ArmPMUParams *p)
       cycleCounterEventId(p->cycleEventId),
       swIncrementEvent(nullptr),
       reg_pmcr_conf(0),
-      interrupt(p->interrupt)
+      interrupt(p->interrupt->get())
 {
     DPRINTF(PMUVerbose, "Initializing the PMU.\n");
 
index 5f756639e269d7e7f5b7538372b86f1d6e41a686..4cc661f0b9518abae8e8cc28917a2faed770e735 100644 (file)
@@ -52,6 +52,7 @@ class BaseGic(PioDevice):
 class ArmInterruptPin(SimObject):
     type = 'ArmInterruptPin'
     cxx_header = "dev/arm/base_gic.hh"
+    cxx_class = "ArmInterruptPinGen"
     abstract = True
 
     platform = Param.Platform(Parent.any, "Platform with interrupt controller")
@@ -60,11 +61,12 @@ class ArmInterruptPin(SimObject):
 class ArmSPI(ArmInterruptPin):
     type = 'ArmSPI'
     cxx_header = "dev/arm/base_gic.hh"
+    cxx_class = "ArmSPIGen"
 
 class ArmPPI(ArmInterruptPin):
     type = 'ArmPPI'
     cxx_header = "dev/arm/base_gic.hh"
-
+    cxx_class = "ArmPPIGen"
 
 class Pl390(BaseGic):
     type = 'Pl390'
index 65754d0184dafcb17e401ff6b7df33b960198696..864bad38fbd915950429369733b9fbce53a11aed 100644 (file)
@@ -70,12 +70,53 @@ BaseGic::params() const
     return dynamic_cast<const Params *>(_params);
 }
 
+ArmInterruptPinGen::ArmInterruptPinGen(const ArmInterruptPinParams *p)
+  : SimObject(p)
+{
+}
+
+ArmSPIGen::ArmSPIGen(const ArmSPIParams *p)
+    : ArmInterruptPinGen(p), pin(new ArmSPI(p->platform, p->num))
+{
+}
+
+ArmInterruptPin*
+ArmSPIGen::get(ThreadContext* tc)
+{
+    return pin;
+}
+
+ArmPPIGen::ArmPPIGen(const ArmPPIParams *p)
+    : ArmInterruptPinGen(p)
+{
+}
 
-ArmInterruptPin::ArmInterruptPin(const ArmInterruptPinParams *p)
-    : SimObject(p),
-      threadContext(nullptr),
-      platform(dynamic_cast<RealView*>(p->platform)),
-      intNum(p->num)
+ArmInterruptPin*
+ArmPPIGen::get(ThreadContext* tc)
+{
+    panic_if(!tc, "Invalid Thread Context\n");
+    ContextID cid = tc->contextId();
+
+    auto pin_it = pins.find(cid);
+
+    if (pin_it != pins.end()) {
+        // PPI Pin Already generated
+        return pin_it->second;
+    } else {
+        // Generate PPI Pin
+        auto p = static_cast<const ArmPPIParams *>(_params);
+        ArmPPI *pin = new ArmPPI(p->platform, tc, p->num);
+
+        pins.insert({cid, pin});
+
+        return pin;
+    }
+}
+
+ArmInterruptPin::ArmInterruptPin(
+    Platform  *_platform, ThreadContext *tc, uint32_t int_num)
+      : threadContext(tc), platform(dynamic_cast<RealView*>(_platform)),
+        intNum(int_num)
 {
     fatal_if(!platform, "Interrupt not connected to a RealView platform");
 }
@@ -97,10 +138,9 @@ ArmInterruptPin::targetContext() const
     return threadContext->contextId();
 }
 
-
-
-ArmSPI::ArmSPI(const ArmSPIParams *p)
-    : ArmInterruptPin(p)
+ArmSPI::ArmSPI(
+    Platform  *_platform, uint32_t int_num)
+      : ArmInterruptPin(_platform, nullptr, int_num)
 {
 }
 
@@ -116,8 +156,9 @@ ArmSPI::clear()
     platform->gic->clearInt(intNum);
 }
 
-ArmPPI::ArmPPI(const ArmPPIParams *p)
-    : ArmInterruptPin(p)
+ArmPPI::ArmPPI(
+    Platform  *_platform, ThreadContext *tc, uint32_t int_num)
+      : ArmInterruptPin(_platform, tc, int_num)
 {
 }
 
@@ -133,15 +174,14 @@ ArmPPI::clear()
     platform->gic->clearPPInt(intNum, targetContext());
 }
 
-
-ArmSPI *
+ArmSPIGen *
 ArmSPIParams::create()
 {
-    return new ArmSPI(this);
+    return new ArmSPIGen(this);
 }
 
-ArmPPI *
+ArmPPIGen *
 ArmPPIParams::create()
 {
-    return new ArmPPI(this);
+    return new ArmPPIGen(this);
 }
index c5dfa3e827bc9b0ac367ac4a87b34422443383dc..f18539fe8bde39623d80c2efa581608050c1eb6b 100644 (file)
 #ifndef __DEV_ARM_BASE_GIC_H__
 #define __DEV_ARM_BASE_GIC_H__
 
+#include <unordered_map>
+
 #include "dev/io_device.hh"
 
 class Platform;
 class RealView;
 class ThreadContext;
+class ArmInterruptPin;
+class ArmSPI;
+class ArmPPI;
 
 struct ArmInterruptPinParams;
 struct ArmPPIParams;
@@ -111,12 +116,59 @@ class BaseGicRegisters
 };
 
 /**
- * Generic representation of an Arm interrupt pin.
+ * This SimObject is instantiated in the python world and
+ * serves as an ArmInterruptPin generator. In this way it
+ * is possible to instantiate a single generator per component
+ * during configuration, and to dynamically spawn ArmInterruptPins.
+ * See ArmPPIGen for more info on how this is used.
+ */
+class ArmInterruptPinGen : public SimObject
+{
+  public:
+    ArmInterruptPinGen(const ArmInterruptPinParams *p);
+
+    virtual ArmInterruptPin* get(ThreadContext *tc = nullptr) = 0;
+};
+
+/**
+ * Shared Peripheral Interrupt Generator
+ * It is capable of generating one interrupt only: it maintains a pointer
+ * to it and returns it every time it is asked for it (via the get metod)
+ */
+class ArmSPIGen : public ArmInterruptPinGen
+{
+  public:
+    ArmSPIGen(const ArmSPIParams *p);
+
+    ArmInterruptPin* get(ThreadContext *tc = nullptr) override;
+  protected:
+    ArmSPI* pin;
+};
+
+/**
+ * Private Peripheral Interrupt Generator
+ * Since PPIs are banked in the GIC, this class is capable of generating
+ * more than one interrupt (one per ContextID).
  */
-class ArmInterruptPin : public SimObject
+class ArmPPIGen : public ArmInterruptPinGen
 {
   public:
-    ArmInterruptPin(const ArmInterruptPinParams *p);
+    ArmPPIGen(const ArmPPIParams *p);
+
+    ArmInterruptPin* get(ThreadContext* tc = nullptr) override;
+  protected:
+    std::unordered_map<ContextID, ArmPPI*> pins;
+};
+
+/**
+ * Generic representation of an Arm interrupt pin.
+ */
+class ArmInterruptPin
+{
+    friend class ArmInterruptPinGen;
+  protected:
+    ArmInterruptPin(Platform *platform, ThreadContext *tc,
+                    uint32_t int_num);
 
   public: /* Public interface */
     /**
@@ -153,27 +205,31 @@ class ArmInterruptPin : public SimObject
 
     /** Arm platform to use for interrupt generation */
     RealView *const platform;
+
     /** Interrupt number to generate */
     const uint32_t intNum;
 };
 
 class ArmSPI : public ArmInterruptPin
 {
-  public:
-    ArmSPI(const ArmSPIParams *p);
+    friend class ArmSPIGen;
+  private:
+    ArmSPI(Platform *platform, uint32_t int_num);
 
+  public:
     void raise() override;
     void clear() override;
 };
 
 class ArmPPI : public ArmInterruptPin
 {
-  public:
-    ArmPPI(const ArmPPIParams *p);
+    friend class ArmPPIGen;
+  private:
+    ArmPPI(Platform *platform, ThreadContext *tc, uint32_t int_num);
 
+  public:
     void raise() override;
     void clear() override;
 };
 
-
 #endif
index 1dcaf8cd9c5e69e27528b4ace2df86dd860d8ca9..9f7bf1333eadfcfb62a93d1809f7b23bd00f43f5 100644 (file)
@@ -48,7 +48,8 @@ MmioVirtIO::MmioVirtIO(const MmioVirtIOParams *params)
     : BasicPioDevice(params, params->pio_size),
       hostFeaturesSelect(0), guestFeaturesSelect(0), pageSize(0),
       interruptStatus(0),
-      callbackKick(this), vio(*params->vio), interrupt(params->interrupt)
+      callbackKick(this), vio(*params->vio),
+      interrupt(params->interrupt->get())
 {
     fatal_if(!interrupt, "No MMIO VirtIO interrupt specified\n");