config: Add fastmodel cluster in fs_bigLITTLE.py

One can create a system with ARM FastModels CPU and GICv3 with
--cpu-type fastmodel --machine-type VExpressFastmodel options.
Currently the FastmodelCluster only supports one CPU.

Change-Id: I2e985f08f9df01a703e21441c6f9bc1fbae4a222
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/20901
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/configs/example/arm/devices.py b/configs/example/arm/devices.py
index b73e7ae..16312eb 100644
--- a/configs/example/arm/devices.py
+++ b/configs/example/arm/devices.py
@@ -48,6 +48,7 @@
 from common import ObjectList
 
 have_kvm = "ArmV8KvmCPU" in ObjectList.cpu_list.get_names()
+have_fastmodel = "FastModelCortexA76" in ObjectList.cpu_list.get_names()
 
 class L1I(L1_ICache):
     tag_latency = 1
@@ -185,6 +186,74 @@
     def addL1(self):
         pass
 
+class FastmodelCluster(SubSystem):
+    def __init__(self, system,  num_cpus, cpu_clock, cpu_voltage="1.0V"):
+        super(FastmodelCluster, self).__init__()
+
+        # Setup GIC
+        gic = system.realview.gic
+        gic.sc_gic.cpu_affinities = ','.join(
+            [ '0.0.%d.0' % i for i in range(num_cpus) ])
+
+        # Parse the base address of redistributor.
+        redist_base = gic.get_redist_bases()[0]
+        redist_frame_size = 0x40000 if gic.sc_gic.has_gicv4_1 else 0x20000
+        gic.sc_gic.reg_base_per_redistributor = ','.join([
+            '0.0.%d.0=%#x' % (i, redist_base + redist_frame_size * i)
+            for i in range(num_cpus)
+        ])
+
+        gic_a2t = AmbaToTlmBridge64(amba=gic.amba_m)
+        gic_t2g = TlmToGem5Bridge64(tlm=gic_a2t.tlm, gem5=system.iobus.slave)
+        gic_g2t = Gem5ToTlmBridge64(gem5=system.membus.master)
+        gic_g2t.addr_ranges = gic.get_addr_ranges()
+        gic_t2a = AmbaFromTlmBridge64(tlm=gic_g2t.tlm)
+        gic.amba_s = gic_t2a.amba
+
+        system.gic_hub = SubSystem()
+        system.gic_hub.gic_a2t = gic_a2t
+        system.gic_hub.gic_t2g = gic_t2g
+        system.gic_hub.gic_g2t = gic_g2t
+        system.gic_hub.gic_t2a = gic_t2a
+
+        self.voltage_domain = VoltageDomain(voltage=cpu_voltage)
+        self.clk_domain = SrcClockDomain(clock=cpu_clock,
+                                         voltage_domain=self.voltage_domain)
+
+        # Setup CPU
+        assert num_cpus <= 4
+        CpuClasses = [FastModelCortexA76x1, FastModelCortexA76x2,
+                      FastModelCortexA76x3, FastModelCortexA76x4]
+        CpuClass = CpuClasses[num_cpus - 1]
+
+        cpu = CpuClass(GICDISABLE=False)
+        for core in cpu.cores:
+            core.semihosting_enable = False
+            core.RVBARADDR = 0x10
+            core.redistributor = gic.redistributor
+        self.cpus = [ cpu ]
+
+        a2t = AmbaToTlmBridge64(amba=cpu.amba)
+        t2g = TlmToGem5Bridge64(tlm=a2t.tlm, gem5=system.membus.slave)
+        system.gic_hub.a2t = a2t
+        system.gic_hub.t2g = t2g
+
+        system.addCpuCluster(self, num_cpus)
+
+    def requireCaches(self):
+        return False
+
+    def memoryMode(self):
+        return 'atomic_noncaching'
+
+    def addL1(self):
+        pass
+
+    def addL2(self, clk_domain):
+        pass
+
+    def connectMemSide(self, bus):
+        pass
 
 def simpleSystem(BaseSystem, caches, mem_size, platform=None, **kwargs):
     """
diff --git a/configs/example/arm/fs_bigLITTLE.py b/configs/example/arm/fs_bigLITTLE.py
index 378ac0d..94e2846 100644
--- a/configs/example/arm/fs_bigLITTLE.py
+++ b/configs/example/arm/fs_bigLITTLE.py
@@ -57,7 +57,7 @@
 from common.cores.arm import ex5_big, ex5_LITTLE
 
 import devices
-from devices import AtomicCluster, KvmCluster
+from devices import AtomicCluster, KvmCluster, FastmodelCluster
 
 
 default_disk = 'aarch64-ubuntu-trusty-headless.img'
@@ -156,6 +156,9 @@
 if devices.have_kvm:
     cpu_types["kvm"] = (KvmCluster, KvmCluster)
 
+# Only add the FastModel CPU if it has been compiled into gem5
+if devices.have_fastmodel:
+    cpu_types["fastmodel"] = (FastmodelCluster, FastmodelCluster)
 
 def addOptions(parser):
     parser.add_argument("--restore-from", type=str, default=None,
@@ -284,6 +287,15 @@
     else:
         system.generateDtb(m5.options.outdir, 'system.dtb')
 
+    if devices.have_fastmodel and issubclass(big_model, FastmodelCluster):
+        from m5 import arm_fast_model as fm, systemc as sc
+        # setup FastModels for simulation
+        fm.setup_simulation("cortexa76")
+        # setup SystemC
+        root.systemc_kernel = m5.objects.SystemC_Kernel()
+        m5.tlm.tlm_global_quantum_instance().set(
+            sc.sc_time(10000.0 / 100000000.0, sc.sc_time.SC_SEC))
+
     return root
 
 def _build_kvm(system, cpus):
diff --git a/src/arch/arm/fastmodel/GIC/FastModelGIC.py b/src/arch/arm/fastmodel/GIC/FastModelGIC.py
index 53b7e1a..72618b9 100644
--- a/src/arch/arm/fastmodel/GIC/FastModelGIC.py
+++ b/src/arch/arm/fastmodel/GIC/FastModelGIC.py
@@ -464,3 +464,38 @@
 
     redistributor = VectorGicv3CommsInitiatorSocket(
             'GIC communication initiator')
+
+    def get_redist_bases(self):
+        """
+        The format of reg_base_per_redistributor is
+        '0.0.0.0=0x2c010000,0.0.0.1=0x2c020000...'
+        Return an array of base addresses
+        """
+        redists = self.sc_gic.reg_base_per_redistributor.split(",")
+        # make sure we have at least one redistributor
+        assert len(redists) > 0 and "=" in redists[0]
+        return [ int(r.split('=')[1], 16) for r in redists ]
+
+    def get_addr_ranges(self):
+        """ Return address ranges that should be served by this GIC """
+        sc_gic = self.sc_gic
+        gic_frame_size = 0x10000
+        # Add range of distributor
+        ranges = [AddrRange(sc_gic.reg_base, size=gic_frame_size)]
+        # Add ranges of redistributors
+        redist_frame_size = gic_frame_size * (4 if sc_gic.has_gicv4_1 else 2)
+        ranges += [
+            AddrRange(redist_base, size=redist_frame_size)
+            for redist_base in self.get_redist_bases()
+        ]
+        # Add ranges of ITSs
+        its_bases = [
+            sc_gic.its0_base, sc_gic.its1_base, sc_gic.its2_base,
+            sc_gic.its3_base
+        ]
+        ranges += [
+            AddrRange(its_bases[i], size=2 * gic_frame_size)
+            for i in xrange(sc_gic.its_count)
+        ]
+
+        return ranges