fastmodel: Make CortexA76x1's interrupts use gem5's mechanisms.

This makes it easier to wire up CPUs to the interrupt controller, and
makes things more modular.

Change-Id: I8d3ab26e4bb588b8efb198ed145d0f58b7ee04cb
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/21049
Reviewed-by: Chun-Chen TK Hsu <chunchenhsu@google.com>
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/FastModelCortexA76x1.py b/src/arch/arm/fastmodel/CortexA76x1/FastModelCortexA76x1.py
index 925e3ee..215189f 100644
--- a/src/arch/arm/fastmodel/CortexA76x1/FastModelCortexA76x1.py
+++ b/src/arch/arm/fastmodel/CortexA76x1/FastModelCortexA76x1.py
@@ -31,10 +31,10 @@
 from m5.objects.ArmInterrupts import ArmInterrupts
 from m5.objects.ArmISA import ArmISA
 from m5.objects.FastModel import AmbaInitiatorSocket, AmbaTargetSocket
-from m5.objects.FastModel import ScMasterPort
 from m5.objects.FastModelArch import FastModelArmCPU
 from m5.objects.FastModelGIC import Gicv3CommsInitiatorSocket
 from m5.objects.FastModelGIC import Gicv3CommsTargetSocket
+from m5.objects.Gic import ArmPPI
 from m5.objects.SystemC import SystemC_ScModule
 
 class FastModelCortexA76x1(SystemC_ScModule):
@@ -53,18 +53,26 @@
             isa = [ ArmISA() ],
     )
 
+    cnthpirq = Param.ArmInterruptPin(ArmPPI(num=10),
+            "EL2 physical timer event")
+    cnthvirq = Param.ArmInterruptPin(ArmPPI(num=12), "EL2 virtual timer event")
+    cntpsirq = Param.ArmInterruptPin(ArmPPI(num=13),
+            "EL1 Secure physical timer event")
+    cntvirq = Param.ArmInterruptPin(ArmPPI(num=11), "Virtual timer event")
+    commirq = Param.ArmInterruptPin(ArmPPI(num=6),
+            "Interrupt signal from debug communications channel")
+    ctidbgirq = Param.ArmInterruptPin(ArmPPI(num=8),
+            "Cross Trigger Interface (CTI) interrupt trigger output")
+    pmuirq = Param.ArmInterruptPin(ArmPPI(num=7),
+            "Interrupt from performance monitoring unit")
+    vcpumntirq = Param.ArmInterruptPin(ArmPPI(num=9),
+            "Interrupt signal for virtual CPU maintenance IRQ")
+    cntpnsirq = Param.ArmInterruptPin(ArmPPI(num=14),
+            "Non-secure physical timer event")
+
     amba = AmbaInitiatorSocket(64, 'AMBA initiator socket')
     redistributor_m = Gicv3CommsInitiatorSocket('GIC communication initiator')
     redistributor_s = Gicv3CommsTargetSocket('GIC communication target')
-    cnthpirq = ScMasterPort("Master port for CPU-to-GIC signal", "bool")
-    cnthvirq = ScMasterPort("Master port for CPU-to-GIC signal", "bool")
-    cntpsirq = ScMasterPort("Master port for CPU-to-GIC signal", "bool")
-    cntvirq = ScMasterPort("Master port for CPU-to-GIC signal", "bool")
-    commirq = ScMasterPort("Master port for CPU-to-GIC signal", "bool")
-    ctidbgirq = ScMasterPort("Master port for CPU-to-GIC signal", "bool")
-    pmuirq = ScMasterPort("Master port for CPU-to-GIC signal", "bool")
-    vcpumntirq = ScMasterPort("Master port for CPU-to-GIC signal", "bool")
-    cntpnsirq = ScMasterPort("Master port for CPU-to-GIC signal", "bool")
 
     # These parameters are described in "Fast Models Reference Manual" section
     # 3.4.19, "ARMCortexA7x1CT".
diff --git a/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.cc b/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.cc
index 1ac0acb..15021e7 100644
--- a/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.cc
+++ b/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.cc
@@ -29,8 +29,10 @@
 
 #include "arch/arm/fastmodel/CortexA76x1/cortex_a76x1.hh"
 
+#include "arch/arm/fastmodel/arm/cpu.hh"
 #include "arch/arm/fastmodel/iris/cpu.hh"
 #include "base/logging.hh"
+#include "dev/arm/base_gic.hh"
 #include "params/FastModelCortexA76x1.hh"
 #include "sim/core.hh"
 #include "systemc/tlm_bridge/gem5_to_tlm.hh"
@@ -45,24 +47,25 @@
 }
 
 CortexA76x1::CortexA76x1(const sc_core::sc_module_name &mod_name,
-        const FastModelCortexA76x1Params &params)
+        const FastModelCortexA76x1Params &p)
     : scx_evs_CortexA76x1(mod_name),
-      amba(scx_evs_CortexA76x1::amba, params.name + ".amba", -1),
-      redistributorM(redistributor_m, params.name + ".redistributor_m", -1),
-      redistributorS(redistributor_s, params.name + ".redistributor_s", -1),
-      cnthpirqWrapper(cnthpirq, params.name + ".cnthpirq", -1),
-      cnthvirqWrapper(cnthvirq, params.name + ".cnthvirq", -1),
-      cntpsirqWrapper(cntpsirq, params.name + ".cntpsirq", -1),
-      cntvirqWrapper(cntvirq, params.name + ".cntvirq", -1),
-      commirqWrapper(commirq, params.name + ".commirq", -1),
-      ctidbgirqWrapper(ctidbgirq, params.name + ".ctidbgirq", -1),
-      pmuirqWrapper(pmuirq, params.name + ".pmuirq", -1),
-      vcpumntirqWrapper(vcpumntirq, params.name + ".vcpumntirq", -1),
-      cntpnsirqWrapper(cntpnsirq, params.name + ".cntpnsirq", -1),
+      amba(scx_evs_CortexA76x1::amba, p.name + ".amba", -1),
+      redistributorM(redistributor_m, p.name + ".redistributor_m", -1),
+      redistributorS(redistributor_s, p.name + ".redistributor_s", -1),
+      cnthpirq("cnthpirq"),
+      cnthvirq("cnthvirq"),
+      cntpsirq("cntpsirq"),
+      cntvirq("cntvirq"),
+      commirq("commirq"),
+      ctidbgirq("ctidbgirq"),
+      pmuirq("pmuirq"),
+      vcpumntirq("vcpumntirq"),
+      cntpnsirq("cntpnsirq"),
       clockChanged(Iris::ClockEventName.c_str()),
       clockPeriod(Iris::PeriodAttributeName.c_str()),
       gem5Cpu(Iris::Gem5CpuAttributeName.c_str()),
-      sendFunctional(Iris::SendFunctionalAttributeName.c_str())
+      sendFunctional(Iris::SendFunctionalAttributeName.c_str()),
+      params(p)
 {
     clockRateControl.bind(clock_rate_s);
 
@@ -206,6 +209,16 @@
 
     sendFunctional.value = [this](PacketPtr pkt) { sendFunc(pkt); };
     add_attribute(sendFunctional);
+
+    scx_evs_CortexA76x1::cnthpirq.bind(cnthpirq.signal_in);
+    scx_evs_CortexA76x1::cnthvirq.bind(cnthvirq.signal_in);
+    scx_evs_CortexA76x1::cntpsirq.bind(cntpsirq.signal_in);
+    scx_evs_CortexA76x1::cntvirq.bind(cntvirq.signal_in);
+    scx_evs_CortexA76x1::commirq.bind(commirq.signal_in);
+    scx_evs_CortexA76x1::ctidbgirq.bind(ctidbgirq.signal_in);
+    scx_evs_CortexA76x1::pmuirq.bind(pmuirq.signal_in);
+    scx_evs_CortexA76x1::vcpumntirq.bind(vcpumntirq.signal_in);
+    scx_evs_CortexA76x1::cntpnsirq.bind(cntpnsirq.signal_in);
 }
 
 void
@@ -217,6 +230,35 @@
     trans->release();
 }
 
+void
+CortexA76x1::before_end_of_elaboration()
+{
+    scx_evs_CortexA76x1::before_end_of_elaboration();
+
+    auto *gem5_cpu = gem5Cpu.value;
+    auto set_on_change = [gem5_cpu](SignalReceiver &recv,
+                                    ArmInterruptPinGen *gen,
+                                    int ctx_num)
+    {
+        auto *pin = gen->get(gem5_cpu->getContext(ctx_num));
+        auto handler = [pin](bool status)
+        {
+            status ? pin->raise() : pin->clear();
+        };
+        recv.onChange(handler);
+    };
+
+    set_on_change(cnthpirq, params.cnthpirq, 0);
+    set_on_change(cnthvirq, params.cnthvirq, 0);
+    set_on_change(cntpsirq, params.cntpsirq, 0);
+    set_on_change(cntvirq, params.cntvirq, 0);
+    set_on_change(commirq, params.commirq, 0);
+    set_on_change(ctidbgirq, params.ctidbgirq, 0);
+    set_on_change(pmuirq, params.pmuirq, 0);
+    set_on_change(vcpumntirq, params.vcpumntirq, 0);
+    set_on_change(cntpnsirq, params.cntpnsirq, 0);
+}
+
 Port &
 CortexA76x1::gem5_getPort(const std::string &if_name, int idx)
 {
@@ -226,24 +268,6 @@
         return redistributorM;
     else if (if_name == "redistributor_s")
         return redistributorS;
-    else if (if_name == "cnthpirq")
-        return cnthpirqWrapper;
-    else if (if_name == "cnthvirq")
-        return cnthvirqWrapper;
-    else if (if_name == "cntpsirq")
-        return cntpsirqWrapper;
-    else if (if_name == "cntvirq")
-        return cntvirqWrapper;
-    else if (if_name == "commirq")
-        return commirqWrapper;
-    else if (if_name == "ctidbgirq")
-        return ctidbgirqWrapper;
-    else if (if_name == "pmuirq")
-        return pmuirqWrapper;
-    else if (if_name == "vcpumntirq")
-        return vcpumntirqWrapper;
-    else if (if_name == "cntpnsirq")
-        return cntpnsirqWrapper;
     else
         return scx_evs_CortexA76x1::gem5_getPort(if_name, idx);
 }
diff --git a/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.hh b/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.hh
index 0d20479..73f04ea 100644
--- a/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.hh
+++ b/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.hh
@@ -30,24 +30,17 @@
 #ifndef __ARCH_ARM_FASTMODEL_CORTEXA76X1_CORETEX_A76X1_HH__
 #define __ARCH_ARM_FASTMODEL_CORTEXA76X1_CORETEX_A76X1_HH__
 
-#include <type_traits>
-
 #include "arch/arm/fastmodel/amba_ports.hh"
+#include "arch/arm/fastmodel/common/signal_receiver.hh"
 #include "arch/arm/fastmodel/protocol/exported_clock_rate_control.hh"
 #include "mem/port_proxy.hh"
 #include "params/FastModelCortexA76x1.hh"
 #include "scx_evs_CortexA76x1.h"
 #include "systemc/ext/core/sc_event.hh"
 #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.
-#define IFACE_TYPE(x) std::decay<decltype(*(x).operator->())>::type
-
 namespace FastModel
 {
 
@@ -67,15 +60,15 @@
 
     ClockRateControlInitiatorSocket clockRateControl;
 
-    sc_gem5::ScPortWrapper<IFACE_TYPE(cnthpirq)> cnthpirqWrapper;
-    sc_gem5::ScPortWrapper<IFACE_TYPE(cnthvirq)> cnthvirqWrapper;
-    sc_gem5::ScPortWrapper<IFACE_TYPE(cntpsirq)> cntpsirqWrapper;
-    sc_gem5::ScPortWrapper<IFACE_TYPE(cntvirq)> cntvirqWrapper;
-    sc_gem5::ScPortWrapper<IFACE_TYPE(commirq)> commirqWrapper;
-    sc_gem5::ScPortWrapper<IFACE_TYPE(ctidbgirq)> ctidbgirqWrapper;
-    sc_gem5::ScPortWrapper<IFACE_TYPE(pmuirq)> pmuirqWrapper;
-    sc_gem5::ScPortWrapper<IFACE_TYPE(vcpumntirq)> vcpumntirqWrapper;
-    sc_gem5::ScPortWrapper<IFACE_TYPE(cntpnsirq)> cntpnsirqWrapper;
+    SignalReceiver cnthpirq;
+    SignalReceiver cnthvirq;
+    SignalReceiver cntpsirq;
+    SignalReceiver cntvirq;
+    SignalReceiver commirq;
+    SignalReceiver ctidbgirq;
+    SignalReceiver pmuirq;
+    SignalReceiver vcpumntirq;
+    SignalReceiver cntpnsirq;
 
     sc_core::sc_event clockChanged;
     sc_core::sc_attribute<Tick> clockPeriod;
@@ -86,12 +79,16 @@
 
     void clockChangeHandler();
 
+    const FastModelCortexA76x1Params &params;
+
   public:
     CortexA76x1(const sc_core::sc_module_name &mod_name,
-            const FastModelCortexA76x1Params &params);
+            const FastModelCortexA76x1Params &p);
 
     Port &gem5_getPort(const std::string &if_name, int idx=-1) override;
 
+    void before_end_of_elaboration() override;
+
     void
     end_of_elaboration() override
     {
diff --git a/src/arch/arm/fastmodel/GIC/FastModelGIC.py b/src/arch/arm/fastmodel/GIC/FastModelGIC.py
index 79c6d48..82f2d28 100644
--- a/src/arch/arm/fastmodel/GIC/FastModelGIC.py
+++ b/src/arch/arm/fastmodel/GIC/FastModelGIC.py
@@ -29,7 +29,6 @@
 from m5.SimObject import SimObject
 
 from m5.objects.FastModel import AmbaInitiatorSocket, AmbaTargetSocket
-from m5.objects.FastModel import ScSlavePort
 from m5.objects.Gic import BaseGic
 from m5.objects.SystemC import SystemC_ScModule
 
@@ -460,13 +459,3 @@
 
     redistributor_m = Gicv3CommsInitiatorSocket('GIC communication initiator')
     redistributor_s = Gicv3CommsTargetSocket('GIC communication target')
-
-    cnthpirq = ScSlavePort("Slave port for CPU-to-GIC signal", "bool")
-    cnthvirq = ScSlavePort("Slave port for CPU-to-GIC signal", "bool")
-    cntpsirq = ScSlavePort("Slave port for CPU-to-GIC signal", "bool")
-    cntvirq = ScSlavePort("Slave port for CPU-to-GIC signal", "bool")
-    commirq = ScSlavePort("Slave port for CPU-to-GIC signal", "bool")
-    ctidbgirq = ScSlavePort("Slave port for CPU-to-GIC signal", "bool")
-    pmuirq = ScSlavePort("Slave port for CPU-to-GIC signal", "bool")
-    vcpumntirq = ScSlavePort("Slave port for CPU-to-GIC signal", "bool")
-    cntpnsirq = ScSlavePort("Slave port for CPU-to-GIC signal", "bool")
diff --git a/src/arch/arm/fastmodel/GIC/GIC.lisa b/src/arch/arm/fastmodel/GIC/GIC.lisa
index bb1e564..f691b26 100644
--- a/src/arch/arm/fastmodel/GIC/GIC.lisa
+++ b/src/arch/arm/fastmodel/GIC/GIC.lisa
@@ -43,17 +43,6 @@
         gic_gic2pv : GICv3CommsPVBus();
         gic_pv2amba : PVBus2AMBAPV();
         gic_amba2pv : AMBAPV2PVBus();
-
-        // Adapters for CPU-to-GIC signals
-        cnthpirqBridge : AMBAPVSignal2SGSignal();
-        cnthvirqBridge : AMBAPVSignal2SGSignal();
-        cntpnsirqBridge : AMBAPVSignal2SGSignal();
-        cntpsirqBridge : AMBAPVSignal2SGSignal();
-        cntvirqBridge : AMBAPVSignal2SGSignal();
-        commirqBridge : AMBAPVSignal2SGSignal();
-        ctidbgirqBridge : AMBAPVSignal2SGSignal();
-        pmuirqBridge : AMBAPVSignal2SGSignal();
-        vcpumntirqBridge : AMBAPVSignal2SGSignal();
     }
 
     connection
@@ -330,26 +319,6 @@
         self.ppi_255 => gic.ppi_in_255;
 
         self.spi => gic.spi_in;
-
-        // Connections from CPU
-        self.cnthpirq => cnthpirqBridge.amba_pv_signal_s;
-        cnthpirqBridge.sg_signal_m => gic.ppi_in_0[10];
-        self.cnthvirq => cnthvirqBridge.amba_pv_signal_s;
-        cnthvirqBridge.sg_signal_m => gic.ppi_in_0[12];
-        self.cntpnsirq => cntpnsirqBridge.amba_pv_signal_s;
-        cntpnsirqBridge.sg_signal_m => gic.ppi_in_0[14];
-        self.cntpsirq => cntpsirqBridge.amba_pv_signal_s;
-        cntpsirqBridge.sg_signal_m => gic.ppi_in_0[13];
-        self.cntvirq => cntvirqBridge.amba_pv_signal_s;
-        cntvirqBridge.sg_signal_m => gic.ppi_in_0[11];
-        self.commirq => commirqBridge.amba_pv_signal_s;
-        commirqBridge.sg_signal_m => gic.ppi_in_0[6];
-        self.ctidbgirq => ctidbgirqBridge.amba_pv_signal_s;
-        ctidbgirqBridge.sg_signal_m => gic.ppi_in_0[8];
-        self.pmuirq => pmuirqBridge.amba_pv_signal_s;
-        pmuirqBridge.sg_signal_m => gic.ppi_in_0[7];
-        self.vcpumntirq => vcpumntirqBridge.amba_pv_signal_s;
-        vcpumntirqBridge.sg_signal_m => gic.ppi_in_0[9];
     }
 
     properties
@@ -439,17 +408,6 @@
         }
     }
 
-    // CPU-side connections
-    slave port<AMBAPVSignal> cnthpirq;
-    slave port<AMBAPVSignal> cnthvirq;
-    slave port<AMBAPVSignal> cntpnsirq;
-    slave port<AMBAPVSignal> cntpsirq;
-    slave port<AMBAPVSignal> cntvirq;
-    slave port<AMBAPVSignal> commirq;
-    slave port<AMBAPVSignal> ctidbgirq;
-    slave port<AMBAPVSignal> pmuirq;
-    slave port<AMBAPVSignal> vcpumntirq;
-
     internal slave port<Signal> spi[988];
 
     internal slave port<Signal> ppi_0[16];
diff --git a/src/arch/arm/fastmodel/GIC/gic.cc b/src/arch/arm/fastmodel/GIC/gic.cc
index cd332c6..62a82b2 100644
--- a/src/arch/arm/fastmodel/GIC/gic.cc
+++ b/src/arch/arm/fastmodel/GIC/gic.cc
@@ -37,16 +37,7 @@
 {
 
 SCGIC::SCGIC(const SCFastModelGICParams &params,
-             sc_core::sc_module_name _name) : scx_evs_GIC(_name),
-    cnthpirqWrapper(cnthpirq, params.name + ".cnthpirq", -1),
-    cnthvirqWrapper(cnthvirq, params.name + ".cnthvirq", -1),
-    cntpnsirqWrapper(cntpnsirq, params.name + ".cntpnsirq", -1),
-    cntpsirqWrapper(cntpsirq, params.name + ".cntpsirq", -1),
-    cntvirqWrapper(cntvirq, params.name + ".cntvirq", -1),
-    commirqWrapper(commirq, params.name + ".commirq", -1),
-    ctidbgirqWrapper(ctidbgirq, params.name + ".ctidbgirq", -1),
-    pmuirqWrapper(pmuirq, params.name + ".pmuirq", -1),
-    vcpumntirqWrapper(vcpumntirq, params.name + ".vcpumntirq", -1)
+             sc_core::sc_module_name _name) : scx_evs_GIC(_name)
 {
     signalInterrupt.bind(signal_interrupt);
 
@@ -289,24 +280,6 @@
         return redistributorM;
     else if (if_name == "redistributor_s")
         return redistributorS;
-    else if (if_name == "cnthpirq")
-        return scGIC->cnthpirqWrapper;
-    else if (if_name == "cnthvirq")
-        return scGIC->cnthvirqWrapper;
-    else if (if_name == "cntpnsirq")
-        return scGIC->cntpnsirqWrapper;
-    else if (if_name == "cntpsirq")
-        return scGIC->cntpsirqWrapper;
-    else if (if_name == "cntvirq")
-        return scGIC->cntvirqWrapper;
-    else if (if_name == "commirq")
-        return scGIC->commirqWrapper;
-    else if (if_name == "ctidbgirq")
-        return scGIC->ctidbgirqWrapper;
-    else if (if_name == "pmuirq")
-        return scGIC->pmuirqWrapper;
-    else if (if_name == "vcpumntirq")
-        return scGIC->vcpumntirqWrapper;
     else
         return BaseGic::getPort(if_name, idx);
 }
diff --git a/src/arch/arm/fastmodel/GIC/gic.hh b/src/arch/arm/fastmodel/GIC/gic.hh
index b5d37c4..11209ab 100644
--- a/src/arch/arm/fastmodel/GIC/gic.hh
+++ b/src/arch/arm/fastmodel/GIC/gic.hh
@@ -40,11 +40,6 @@
 #include "systemc/ext/core/sc_module_name.hh"
 #include "systemc/sc_port_wrapper.hh"
 
-// 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.
-#define IFACE_TYPE(x) std::decay<decltype(*(x).operator->())>::type
-
 namespace FastModel
 {
 
@@ -60,16 +55,6 @@
 
     SignalInterruptInitiatorSocket signalInterrupt;
 
-    sc_gem5::ScInterfaceWrapper<IFACE_TYPE(cnthpirq)> cnthpirqWrapper;
-    sc_gem5::ScInterfaceWrapper<IFACE_TYPE(cnthvirq)> cnthvirqWrapper;
-    sc_gem5::ScInterfaceWrapper<IFACE_TYPE(cntpnsirq)> cntpnsirqWrapper;
-    sc_gem5::ScInterfaceWrapper<IFACE_TYPE(cntpsirq)> cntpsirqWrapper;
-    sc_gem5::ScInterfaceWrapper<IFACE_TYPE(cntvirq)> cntvirqWrapper;
-    sc_gem5::ScInterfaceWrapper<IFACE_TYPE(commirq)> commirqWrapper;
-    sc_gem5::ScInterfaceWrapper<IFACE_TYPE(ctidbgirq)> ctidbgirqWrapper;
-    sc_gem5::ScInterfaceWrapper<IFACE_TYPE(pmuirq)> pmuirqWrapper;
-    sc_gem5::ScInterfaceWrapper<IFACE_TYPE(vcpumntirq)> vcpumntirqWrapper;
-
     void
     end_of_elaboration() override
     {