fastmodel: Add a gem5Cpu attribute to the CortexA76x1.

This attribute is to let the fast model EVS CPU find and talk to the
gem5 CPU in case it needs a pointer to one of its ThreadContexts for
instance.

Also move the code that finds the clock period attribute/event to the
constructor. gem5 guarantees that the EVS is constructed before its
pointer is passed to the iris CPU wrapper, and so the EVS will have
had a chance to install those controls if it's going to.

Change-Id: I389ef0ba0f9d528140f40444baa5091a9ec338cd
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/21045
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
diff --git a/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.cc b/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.cc
index 3b5da01..b680ce4 100644
--- a/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.cc
+++ b/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.cc
@@ -59,7 +59,8 @@
       vcpumntirqWrapper(vcpumntirq, params.name + ".vcpumntirq", -1),
       cntpnsirqWrapper(cntpnsirq, params.name + ".cntpnsirq", -1),
       clockChanged(Iris::ClockEventName.c_str()),
-      clockPeriod(Iris::PeriodAttributeName.c_str())
+      clockPeriod(Iris::PeriodAttributeName.c_str()),
+      gem5Cpu(Iris::Gem5CpuAttributeName.c_str())
 {
     clockRateControl.bind(clock_rate_s);
 
@@ -195,6 +196,7 @@
     set_parameter("core.cpu0.vfp-enable_at_reset",
                   params.cpu0_vfp_enable_at_reset);
 
+    add_attribute(gem5Cpu);
     add_attribute(clockPeriod);
     SC_METHOD(clockChangeHandler);
     dont_initialize();
diff --git a/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.hh b/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.hh
index ab42529..00f843b 100644
--- a/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.hh
+++ b/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.hh
@@ -40,6 +40,8 @@
 #include "systemc/ext/core/sc_module.hh"
 #include "systemc/sc_port_wrapper.hh"
 
+class BaseCPU;
+
 // This macro is to get the type IF of a sc_export<IF> variable x. It relies on
 // the fact that the "operator->()" function returns the "IF*" type and
 // std::decay to remove cv-qualifiers and reference.
@@ -76,6 +78,7 @@
 
     sc_core::sc_event clockChanged;
     sc_core::sc_attribute<Tick> clockPeriod;
+    sc_core::sc_attribute<::BaseCPU *> gem5Cpu;
 
     void clockChangeHandler();
 
diff --git a/src/arch/arm/fastmodel/iris/cpu.cc b/src/arch/arm/fastmodel/iris/cpu.cc
index 67de40e..234a1ca 100644
--- a/src/arch/arm/fastmodel/iris/cpu.cc
+++ b/src/arch/arm/fastmodel/iris/cpu.cc
@@ -34,6 +34,35 @@
 namespace Iris
 {
 
+BaseCPU::BaseCPU(BaseCPUParams *params, sc_core::sc_module *_evs) :
+    ::BaseCPU::BaseCPU(params), evs(_evs),
+    clockEvent(nullptr), periodAttribute(nullptr)
+{
+    sc_core::sc_attr_base *base;
+
+    base = evs->get_attribute(Gem5CpuAttributeName);
+    auto *gem5_cpu_attr =
+        dynamic_cast<sc_core::sc_attribute<::BaseCPU *> *>(base);
+    panic_if(base && !gem5_cpu_attr,
+             "The EVS gem5 CPU attribute was not of type "
+             "sc_attribute<::BaesCPU *>.");
+    if (gem5_cpu_attr)
+        gem5_cpu_attr->value = this;
+
+    const auto &event_vec = evs->get_child_events();
+    auto event_it = std::find_if(event_vec.begin(), event_vec.end(),
+            [](const sc_core::sc_event *e) -> bool {
+                return e->basename() == ClockEventName; });
+    if (event_it != event_vec.end())
+        clockEvent = *event_it;
+
+    base = evs->get_attribute(PeriodAttributeName);
+    periodAttribute = dynamic_cast<sc_core::sc_attribute<Tick> *>(base);
+    panic_if(base && !periodAttribute,
+            "The EVS clock period attribute is not of type "
+            "sc_attribute<Tick>.");
+}
+
 BaseCPU::~BaseCPU()
 {
     for (auto &tc: threadContexts)
diff --git a/src/arch/arm/fastmodel/iris/cpu.hh b/src/arch/arm/fastmodel/iris/cpu.hh
index 01c25af..c6c75a2 100644
--- a/src/arch/arm/fastmodel/iris/cpu.hh
+++ b/src/arch/arm/fastmodel/iris/cpu.hh
@@ -46,6 +46,9 @@
 // The name of the attribute the subsystem should create which can be set to
 // the desired clock period, in gem5's Ticks.
 static const std::string PeriodAttributeName = "gem5_clock_period_attribute";
+// The name of the attribute the subsystem should create which will be set to
+// a pointer to its corresponding gem5 CPU.
+static const std::string Gem5CpuAttributeName = "gem5_cpu";
 
 // This CPU class adds some mechanisms which help attach the gem5 and fast
 // model CPUs to each other. It acts as a base class for the gem5 CPU, and
@@ -54,10 +57,7 @@
 class BaseCPU : public ::BaseCPU
 {
   public:
-    BaseCPU(BaseCPUParams *params, sc_core::sc_module *_evs) :
-        ::BaseCPU::BaseCPU(params), evs(_evs),
-        clockEvent(nullptr), periodAttribute(nullptr)
-    {}
+    BaseCPU(BaseCPUParams *params, sc_core::sc_module *_evs);
     virtual ~BaseCPU();
 
     Port &
@@ -90,34 +90,11 @@
     sc_core::sc_event *clockEvent;
     sc_core::sc_attribute<Tick> *periodAttribute;
 
-    bool
-    findClockControls()
-    {
-        if (!clockEvent) {
-            const auto &event_vec = evs->get_child_events();
-            auto event_it = std::find_if(event_vec.begin(), event_vec.end(),
-                    [](const sc_core::sc_event *e) -> bool {
-                        return e->basename() == ClockEventName; });
-            if (event_it != event_vec.end())
-                clockEvent = *event_it;
-        }
-        if (!periodAttribute) {
-            sc_core::sc_attr_base *base =
-                evs->get_attribute(PeriodAttributeName);
-            periodAttribute =
-                dynamic_cast<sc_core::sc_attribute<Tick> *>(base);
-            panic_if(base && !periodAttribute,
-                    "The EVS clock period attribute is not of type "
-                    "sc_attribute<Tick>.");
-        }
-        return clockEvent && periodAttribute;
-    }
-
   protected:
     void
     clockPeriodUpdated() override
     {
-        if (!findClockControls()) {
+        if (!clockEvent || !periodAttribute) {
             warn("Unable to notify EVS of clock change, missing:");
             warn_if(!clockEvent, "  Clock change event");
             warn_if(!periodAttribute, "  Clock period attribute");