fastmodel: Add glue code which adapts fastmodels to run in gem5.

Fast Models are models written by ARM which emulate different
components of a computer system. They can be combined into small
subsystems and then exported as systemc modules.

To enable this code, you'll need to set USE_ARM_FASTMODEL variable to
true. This CL does not include the fast models themselves, or a license
to use them or the associated tools. To build these fast models, you'll
need to set some scons variables. These variables should be set as
described in the fast model distribution.

* PVLIB_HOME
* MAXCORE_HOME
* ARMLMD_LICENSE_FILE

Some minor patches to source filesdistributed with the fast model code
may be necessary since their use of systemc is not necessarily 100%
standards compliant.

Change-Id: Id53814b95d8aa320da4d4f2159be0736fc12eb73
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/20799
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/CortexA76x1.lisa b/src/arch/arm/fastmodel/CortexA76x1/CortexA76x1.lisa
new file mode 100644
index 0000000..28c0bd9
--- /dev/null
+++ b/src/arch/arm/fastmodel/CortexA76x1/CortexA76x1.lisa
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+component CortexA76x1
+{
+
+    composition
+    {
+        core : ARMCortexA76x1CT();
+
+        // Bridges for the core.
+        ambaBridge : PVBus2AMBAPV();
+        gic_pv2gic : PVBusGICv3Comms();
+        gic_pv2amba : PVBus2AMBAPV();
+        gic_amba2pv : AMBAPV2PVBus();
+
+        // Adapters for CPU-to-GIC signals
+        CNTHPIRQ : SGSignal2AMBAPVSignal();
+        CNTHVIRQ : SGSignal2AMBAPVSignal();
+        CNTPNSIRQ : SGSignal2AMBAPVSignal();
+        CNTPSIRQ : SGSignal2AMBAPVSignal();
+        CNTVIRQ : SGSignal2AMBAPVSignal();
+        COMMIRQ : SGSignal2AMBAPVSignal();
+        CTIDBGIRQ : SGSignal2AMBAPVSignal();
+        PMUIRQ : SGSignal2AMBAPVSignal();
+        VCPUMNTIRQ : SGSignal2AMBAPVSignal();
+
+        // Clocks.
+        clock1Hz : MasterClock();
+        clockDiv : ClockDivider();
+        clockDivPeriph : ClockDivider(mul=0x01800000);
+    }
+
+    connection
+    {
+        // The main interface with memory.
+        core.pvbus_m0 => ambaBridge.pvbus_s;
+        ambaBridge.amba_pv_m => self.amba;
+
+        // Connection to the GIC.
+        self.redistributor_s => gic_amba2pv.amba_pv_s;
+        // Bridges coming in.
+        gic_amba2pv.pvbus_m => gic_pv2gic.pvbus_s;
+        // Bridge to GICV3Comms.
+        gic_pv2gic.distributor_m[0] => core.gicv3_redistributor_s[0];
+        // Bridges going out.
+        gic_pv2gic.pvbus_m => gic_pv2amba.pvbus_s;
+        gic_pv2amba.amba_pv_m => self.redistributor_m;
+
+        // Connections from CPU to adapters
+        core.CNTHPIRQ[0] => CNTHPIRQ.sg_signal_s;
+        CNTHPIRQ.amba_pv_signal_m => self.cnthpirq;
+        core.CNTHVIRQ[0] => CNTHVIRQ.sg_signal_s;
+        CNTHVIRQ.amba_pv_signal_m => self.cnthvirq;
+        core.CNTPNSIRQ[0] => CNTPNSIRQ.sg_signal_s;
+        CNTPNSIRQ.amba_pv_signal_m => self.cntpnsirq;
+        core.CNTPSIRQ[0] => CNTPSIRQ.sg_signal_s;
+        CNTPSIRQ.amba_pv_signal_m => self.cntpsirq;
+        core.CNTVIRQ[0] => CNTVIRQ.sg_signal_s;
+        CNTVIRQ.amba_pv_signal_m => self.cntvirq;
+        core.commirq[0] => COMMIRQ.sg_signal_s;
+        COMMIRQ.amba_pv_signal_m => self.commirq;
+        core.ctidbgirq[0] => CTIDBGIRQ.sg_signal_s;
+        CTIDBGIRQ.amba_pv_signal_m => self.ctidbgirq;
+        core.pmuirq[0] => PMUIRQ.sg_signal_s;
+        PMUIRQ.amba_pv_signal_m => self.pmuirq;
+        core.vcpumntirq[0] => VCPUMNTIRQ.sg_signal_s;
+        VCPUMNTIRQ.amba_pv_signal_m => self.vcpumntirq;
+
+        // Clocks.
+        clock1Hz.clk_out => clockDiv.clk_in;
+        clock1Hz.clk_out => clockDivPeriph.clk_in;
+        clockDiv.clk_out => core.core_clk_in[0];
+        clockDivPeriph.clk_out => core.clk_in;
+    }
+
+    properties
+    {
+        component_type = "System";
+    }
+
+    master port<AMBAPV> amba;
+    slave port<ExportedClockRateControl> clock_rate_s
+    {
+        behavior set_mul_div(uint64_t mul, uint64_t div)
+        {
+            clockDiv.rate.set64(mul, div);
+        }
+    }
+    slave port<AMBAPV> redistributor_s;
+    master port<AMBAPV> redistributor_m;
+
+    // External ports for CPU-to-GIC signals
+    master port<AMBAPVSignal> cnthpirq;
+    master port<AMBAPVSignal> cnthvirq;
+    master port<AMBAPVSignal> cntpsirq;
+    master port<AMBAPVSignal> cntvirq;
+    master port<AMBAPVSignal> commirq;
+    master port<AMBAPVSignal> ctidbgirq;
+    master port<AMBAPVSignal> pmuirq;
+    master port<AMBAPVSignal> vcpumntirq;
+    master port<AMBAPVSignal> cntpnsirq;
+}
diff --git a/src/arch/arm/fastmodel/CortexA76x1/CortexA76x1.sgproj b/src/arch/arm/fastmodel/CortexA76x1/CortexA76x1.sgproj
new file mode 100644
index 0000000..e391251
--- /dev/null
+++ b/src/arch/arm/fastmodel/CortexA76x1/CortexA76x1.sgproj
@@ -0,0 +1,28 @@
+sgproject "CortexA76x1.sgproj"
+{
+TOP_LEVEL_COMPONENT = "CortexA76x1";
+ACTIVE_CONFIG_LINUX  = "gcc";
+ACTIVE_CONFIG_WINDOWS  = "Win64-Release-VC2015";
+config "gcc"
+{
+    ADDITIONAL_COMPILER_SETTINGS = "-O3 -Wall -std=c++11 -Wno-deprecated -Wno-unused-function";
+    ADDITIONAL_LINKER_SETTINGS = "-Wl,--no-undefined";
+    BUILD_DIR = "./gcc";
+    COMPILER = "gcc-6.4";
+    CONFIG_DESCRIPTION = "";
+    CONFIG_NAME = "gcc";
+    PLATFORM = "Linux64";
+    PREPROCESSOR_DEFINES = "NDEBUG";
+    SIMGEN_COMMAND_LINE = "--num-comps-file 50";
+    TARGET_MAXVIEW = "0";
+    TARGET_SYSTEMC = "1";
+
+    INCLUDE_DIRS="../../../../";
+}
+files
+{
+    path = "CortexA76x1.lisa";
+    path = "${PVLIB_HOME}/etc/sglib.sgrepo";
+    path = "../protocol/ExportedClockRateControlProtocol.lisa";
+}
+}
diff --git a/src/arch/arm/fastmodel/CortexA76x1/FastModelCortexA76x1.py b/src/arch/arm/fastmodel/CortexA76x1/FastModelCortexA76x1.py
new file mode 100644
index 0000000..925e3ee
--- /dev/null
+++ b/src/arch/arm/fastmodel/CortexA76x1/FastModelCortexA76x1.py
@@ -0,0 +1,342 @@
+# Copyright 2019 Google, Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Gabe Black
+
+from m5.params import *
+from m5.SimObject import SimObject
+
+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.SystemC import SystemC_ScModule
+
+class FastModelCortexA76x1(SystemC_ScModule):
+    type = 'FastModelCortexA76x1'
+    cxx_class = 'FastModel::CortexA76x1'
+    cxx_header = 'arch/arm/fastmodel/CortexA76x1/cortex_a76x1.hh'
+
+    _core_paths = [ 'core.cpu0' ]
+    cpu_wrapper = FastModelArmCPU(
+            core_paths=_core_paths,
+
+            cntfrq = 0x1800000,
+
+            # We shouldn't need these, but gem5 gets mad without them.
+            interrupts = [ ArmInterrupts() ],
+            isa = [ ArmISA() ],
+    )
+
+    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".
+    BROADCASTATOMIC = Param.Bool(True, "Enable broadcasting of atomic "\
+            "operation. The broadcastatomic signal will override this value "\
+            "if used")
+    BROADCASTCACHEMAINT = Param.Bool(True, "Enable broadcasting of cache "\
+            "maintenance operations to downstream caches. The "\
+            "broadcastcachemaint signal will override this value if used.")
+    BROADCASTOUTER = Param.Bool(True, "Enable broadcasting of Outer "\
+            "Shareable transactions. The broadcastouter signal will override "\
+            "this value if used.")
+    BROADCASTPERSIST = Param.Bool(True, "Enable broadcasting  of cache clean "\
+            "to the point of persistence operations. The broadcastpersist "\
+            "signal will override this value if used")
+    CLUSTER_ID = Param.UInt16(0x0, "Processor cluster ID value")
+    GICDISABLE = Param.Bool(True, "Disable the new style GICv3 CPU interface "\
+            "in each core model. Should be left enabled unless the platform "\
+            "contains a GICv3 distributor.")
+    cpi_div = Param.UInt32(1,
+            "Divider for calculating CPI (Cycles Per Instruction)")
+    cpi_mul = Param.UInt32(1,
+            "Multiplier for calculating CPI (Cycles Per Instruction)")
+    dcache_hit_latency = Param.UInt64(0, "L1 D-Cache timing annotation "\
+            "latency for hit.  Intended to model the tag-lookup time.  This "\
+            "is only used when dcache-state_modelled=true.")
+    dcache_maintenance_latency = Param.UInt64(0, "L1 D-Cache timing "\
+            "annotation latency for cache maintenance operations given in "\
+            "total ticks. This is only used when dcache-state_modelled=true.")
+    dcache_miss_latency = Param.UInt64(0, "L1 D-Cache timing annotation "\
+            "latency for miss.  Intended to model the time for failed "\
+            "tag-lookup and allocation of intermediate buffers.  This is "\
+            "only used when dcache-state_modelled=true.")
+    dcache_prefetch_enabled = Param.Bool(False, "Enable simulation of data "\
+            "cache prefetching.  This is only used when "\
+            "dcache-state_modelled=true")
+    dcache_read_access_latency = Param.UInt64(0, "L1 D-Cache timing "\
+            "annotation latency for read accesses given in ticks per access "\
+            "(of size dcache-read_bus_width_in_bytes).  If this parameter is "\
+            "non-zero, per-access latencies will be used instead of per-byte "\
+            "even if dcache-read_latency is set. This is in addition to the "\
+            "hit or miss latency, and intended to correspond to the time "\
+            "taken to transfer across the cache upstream bus, this is only "\
+            "used when dcache-state_modelled=true.")
+    dcache_read_latency = Param.UInt64(0, "L1 D-Cache timing annotation "\
+            "latency for read accesses given in ticks per byte "\
+            "accessed.dcache-read_access_latency must be set to 0 for "\
+            "per-byte latencies to be applied.  This is in addition to the "\
+            "hit or miss latency, and intended to correspond to the time "\
+            "taken to transfer across the cache upstream bus. This is only "\
+            "used when dcache-state_modelled=true.")
+    dcache_snoop_data_transfer_latency = Param.UInt64(0, "L1 D-Cache timing "\
+        "annotation latency for received snoop accesses that perform a data "\
+        "transfer given in ticks per byte accessed. This is only used when "\
+        "dcache-state_modelled=true.")
+    dcache_state_modelled = Param.Bool(False,
+        "Set whether D-cache has stateful implementation")
+    dcache_write_access_latency = Param.UInt64(0, "L1 D-Cache timing "\
+        "annotation latency for write accesses given in ticks per access "\
+        "(of size dcache-write_bus_width_in_bytes). If this parameter is "\
+        "non-zero, per-access latencies will be used instead of per-byte "\
+        "even if dcache-write_latency is set. This is only used when "\
+        "dcache-state_modelled=true.")
+    dcache_write_latency = Param.UInt64(0, "L1 D-Cache timing annotation "\
+        "latency for write accesses given in ticks per byte accessed. "\
+        "dcache-write_access_latency must be set to 0 for per-byte latencies "\
+        "to be applied. This is only used when dcache-state_modelled=true.")
+    default_opmode = Param.Unsigned(4, "Operating mode of DynamIQ coming out "\
+            "of reset. 0: SFONLY ON, 1: 1/4 CACHE ON, 2: 1/2 CACHE ON, 3: "\
+            "3/4 CACHE ON, 4: FULL CACHE ON")
+    diagnostics = Param.Bool(False, "Enable DynamIQ diagnostic messages")
+    enable_simulation_performance_optimizations = Param.Bool(True,
+            "With this option enabled, the model will run more quickly, but "\
+            "be less accurate to exact CPU behavior. The model will still be "\
+            "functionally accurate for software, but may increase "\
+            "differences seen between hardware behavior and model behavior "\
+            "for certain workloads (it changes the micro-architectural value "\
+            "of stage12_tlb_size parameter to 1024).")
+    ext_abort_device_read_is_sync = Param.Bool(False,
+            "Synchronous reporting of device-nGnRE read external aborts")
+    ext_abort_device_write_is_sync = Param.Bool(False,
+            "Synchronous reporting of device-nGnRE write external aborts")
+    ext_abort_so_read_is_sync = Param.Bool(False,
+            "Synchronous reporting of device-nGnRnE read external aborts")
+    ext_abort_so_write_is_sync = Param.Bool(False,
+            "Synchronous reporting of device-nGnRnE write external aborts")
+    gicv3_cpuintf_mmap_access_level = Param.Unsigned(0, "Allowed values are: "\
+            "0-mmap access is supported for GICC,GICH,GICV registers. 1-mmap "\
+            "access is supported only for GICV registers. 2-mmap access is "\
+            "not supported.")
+    has_peripheral_port = Param.Bool(False,
+            "If true, additional AXI peripheral port is configured.")
+    has_statistical_profiling = Param.Bool(True,
+            "Whether Statistical Based Profiling is implemented")
+    icache_hit_latency = Param.UInt64(0, "L1 I-Cache timing annotation "\
+            "latency for hit.  Intended to model the tag-lookup time.  This "\
+            "is only used when icache-state_modelled=true.")
+    icache_maintenance_latency = Param.UInt64(0, "L1 I-Cache timing "\
+            "annotation latency for cache maintenance operations given in "\
+            "total ticks. This is only used when icache-state_modelled=true.")
+    icache_miss_latency = Param.UInt64(0, "L1 I-Cache timing annotation "\
+            "latency for miss.  Intended to model the time for failed "\
+            "tag-lookup and allocation of intermediate buffers.  This is "\
+            "only used when icache-state_modelled=true.")
+    icache_prefetch_enabled = Param.Bool(False, "Enable simulation of "\
+            "instruction cache prefetching. This is only used when "\
+            "icache-state_modelled=true.")
+    icache_read_access_latency = Param.UInt64(0, "L1 I-Cache timing "\
+            "annotation latency for read accesses given in ticks per access "\
+            "(of size icache-read_bus_width_in_bytes).  If this parameter is "\
+            "non-zero, per-access latencies will be used instead of per-byte "\
+            "even if icache-read_latency is set. This is in addition to the "\
+            "hit or miss latency, and intended to correspond to the time "\
+            "taken to transfer across the cache upstream bus, this is only "\
+            "used when icache-state_modelled=true.")
+    icache_read_latency = Param.UInt64(0, "L1 I-Cache timing annotation "\
+            "latency for read accesses given in ticks per byte "\
+            "accessed.icache-read_access_latency must be set to 0 for "\
+            "per-byte latencies to be applied.  This is in addition to the "\
+            "hit or miss latency, and intended to correspond to the time "\
+            "taken to transfer across the cache upstream bus. This is only "\
+            "used when icache-state_modelled=true.")
+    icache_state_modelled = Param.Bool(False,
+            "Set whether I-cache has stateful implementation")
+    l3cache_hit_latency = Param.UInt64(0, "L3 Cache timing annotation "\
+            "latency for hit.  Intended to model the tag-lookup time.  This "\
+            "is only used when l3cache-state_modelled=true.")
+    l3cache_maintenance_latency = Param.UInt64(0, "L3 Cache timing "\
+            "annotation latency for cache maintenance operations given in "\
+            "total ticks. This is only used when dcache-state_modelled=true.")
+    l3cache_miss_latency = Param.UInt64(0, "L3 Cache timing annotation "\
+            "latency for miss.  Intended to model the time for failed "\
+            "tag-lookup and allocation of intermediate buffers.  This is "\
+            "only used when l3cache-state_modelled=true.")
+    l3cache_read_access_latency = Param.UInt64(0, "L3 Cache timing "\
+            "annotation latency for read accesses given in ticks per access "\
+            "(of size l3cache-read_bus_width_in_bytes).  If this parameter "\
+            "is non-zero, per-access latencies will be used instead of "\
+            "per-byte even if l3cache-read_latency is set. This is in "\
+            "addition to the hit or miss latency, and intended to correspond "\
+            "to the time taken to transfer across the cache upstream bus, "\
+            "this is only used when l3cache-state_modelled=true.")
+    l3cache_read_latency = Param.UInt64(0, "L3 Cache timing annotation "\
+            "latency for read accesses given in ticks per byte "\
+            "accessed.l3cache-read_access_latency must be set to 0 for "\
+            "per-byte latencies to be applied.  This is in addition to the "\
+            "hit or miss latency, and intended to correspond to the time "\
+            "taken to transfer across the cache upstream bus. This is only "\
+            "used when l3cache-state_modelled=true.")
+    l3cache_size = Param.MemorySize('0x100000', "L3 Cache size in bytes.")
+    l3cache_snoop_data_transfer_latency = Param.UInt64(0, "L3 Cache timing "\
+            "annotation latency for received snoop accesses that perform a "\
+            "data transfer given in ticks per byte accessed. This is only "\
+            "used when dcache-state_modelled=true.")
+    l3cache_snoop_issue_latency = Param.UInt64(0, "L3 Cache timing "\
+            "annotation latency for snoop accesses issued by this cache in "\
+            "total ticks. This is only used when dcache-state_modelled=true.")
+    l3cache_write_access_latency = Param.UInt64(0, "L3 Cache timing "\
+            "annotation latency for write accesses given in ticks per access "\
+            "(of size l3cache-write_bus_width_in_bytes). If this parameter "\
+            "is non-zero, per-access latencies will be used instead of "\
+            "per-byte even if l3cache-write_latency is set. This is only "\
+            "used when l3cache-state_modelled=true.")
+    l3cache_write_latency = Param.UInt64(0, "L3 Cache timing annotation "\
+            "latency for write accesses given in ticks per byte accessed. "\
+            "l3cache-write_access_latency must be set to 0 for per-byte "\
+            "latencies to be applied. This is only used when "\
+            "l3cache-state_modelled=true.")
+    pchannel_treat_simreset_as_poreset = Param.Bool(False,
+            "Register core as ON state to cluster with simulation reset.")
+    periph_address_end = Param.Addr(0x0, "End address for peripheral port "\
+            "address range exclusive(corresponds to AENDMP input signal).")
+    periph_address_start = Param.Addr(0x0, "Start address for peripheral "\
+            "port address range inclusive(corresponds to ASTARTMP input "\
+            "signal).")
+    ptw_latency = Param.UInt64(0, "Page table walker latency for TA "\
+            "(Timing Annotation), expressed in simulation ticks")
+    tlb_latency = Param.UInt64(0, "TLB latency for TA (Timing Annotation), "\
+            "expressed in simulation ticks")
+    treat_dcache_cmos_to_pou_as_nop = Param.Bool(False, "Whether dcache "\
+            "invalidation to the point of unification is required for "\
+            "instruction to data coherence. true - Invalidate operations not "\
+            "required")
+    walk_cache_latency = Param.UInt64(0, "Walk cache latency for TA (Timing "\
+            "Annotation), expressed in simulation ticks")
+
+    cpu0_CFGEND = Param.Bool(False, "Endianness configuration at reset.  "\
+            "0, little endian. 1, big endian.")
+    cpu0_CFGTE = Param.Bool(False, "Instruction set state when resetting "\
+            "into AArch32.  0, A32. 1, T32.")
+    cpu0_CRYPTODISABLE = Param.Bool(False, "Disable cryptographic features.")
+    cpu0_RVBARADDR = Param.Addr(0x0, "Value of RVBAR_ELx register.")
+    cpu0_VINITHI = Param.Bool(False, "Reset value of SCTLR.V.")
+    cpu0_enable_trace_special_hlt_imm16 = Param.Bool(False,
+            "Enable usage of parameter trace_special_hlt_imm16")
+    cpu0_l2cache_hit_latency = Param.UInt64(0, "L2 Cache timing annotation "\
+            "latency for hit.  Intended to model the tag-lookup time.  This "\
+            "is only used when l2cache-state_modelled=true.")
+    cpu0_l2cache_maintenance_latency = Param.UInt64(0, "L2 Cache timing "\
+            "annotation latency for cache maintenance operations given in "\
+            "total ticks. This is only used when dcache-state_modelled=true.")
+    cpu0_l2cache_miss_latency = Param.UInt64(0, "L2 Cache timing annotation "\
+            "latency for miss.  Intended to model the time for failed "\
+            "tag-lookup and allocation of intermediate buffers.  This is "\
+            "only used when l2cache-state_modelled=true.")
+    cpu0_l2cache_read_access_latency = Param.UInt64(0, "L2 Cache timing "\
+            "annotation latency for read accesses given in ticks per "\
+            "access.  If this parameter is non-zero, per-access latencies "\
+            "will be used instead of per-byte even if l2cache-read_latency "\
+            "is set. This is in addition to the hit or miss latency, and "\
+            "intended to correspond to the time taken to transfer across the "\
+            "cache upstream bus, this is only used when "\
+            "l2cache-state_modelled=true.")
+    cpu0_l2cache_read_latency = Param.UInt64(0, "L2 Cache timing annotation "\
+            "latency for read accesses given in ticks per byte "\
+            "accessed.l2cache-read_access_latency must be set to 0 for "\
+            "per-byte latencies to be applied.  This is in addition to the "\
+            "hit or miss latency, and intended to correspond to the time "\
+            "taken to transfer across the cache upstream bus. This is only "\
+            "used when l2cache-state_modelled=true.")
+    cpu0_l2cache_size = Param.MemorySize32('0x80000',
+            "L2 Cache size in bytes.")
+    cpu0_l2cache_snoop_data_transfer_latency = Param.UInt64(0, "L2 Cache "\
+            "timing annotation latency for received snoop accesses that "\
+            "perform a data transfer given in ticks per byte accessed. This "\
+            "is only used when dcache-state_modelled=true.")
+    cpu0_l2cache_snoop_issue_latency = Param.UInt64(0, "L2 Cache timing "\
+            "annotation latency for snoop accesses issued by this cache in "\
+            "total ticks. This is only used when dcache-state_modelled=true.")
+    cpu0_l2cache_write_access_latency = Param.UInt64(0, "L2 Cache timing "\
+            "annotation latency for write accesses given in ticks per "\
+            "access. If this parameter is non-zero, per-access latencies "\
+            "will be used instead of per-byte even if l2cache-write_latency "\
+            "is set. This is only used when l2cache-state_modelled=true.")
+    cpu0_l2cache_write_latency = Param.UInt64(0, "L2 Cache timing annotation "\
+            "latency for write accesses given in ticks per byte accessed. "\
+            "l2cache-write_access_latency must be set to 0 for per-byte "\
+            "latencies to be applied. This is only used when "\
+            "l2cache-state_modelled=true.")
+    cpu0_max_code_cache_mb = Param.MemorySize32('0x100', "Maximum size of "\
+            "the simulation code cache (MiB). For platforms with more than 2 "\
+            "cores this limit will be scaled down. (e.g 1/8 for 16 or more "\
+            "cores)")
+    cpu0_min_sync_level = Param.Unsigned(0, "Force minimum syncLevel "\
+            "(0=off=default,1=syncState,2=postInsnIO,3=postInsnAll)")
+    cpu0_semihosting_A32_HLT = Param.UInt16(0xf000,
+            "A32 HLT number for semihosting calls.")
+    cpu0_semihosting_A64_HLT = Param.UInt16(0xf000,
+            "A64 HLT number for semihosting calls.")
+    cpu0_semihosting_ARM_SVC = Param.UInt32(0x123456,
+            "A32 SVC number for semihosting calls.")
+    cpu0_semihosting_T32_HLT = Param.Unsigned(60,
+            "T32 HLT number for semihosting calls.")
+    cpu0_semihosting_Thumb_SVC = Param.Unsigned(171,
+            "T32 SVC number for semihosting calls.")
+    cpu0_semihosting_cmd_line = Param.String("",
+            "Command line available to semihosting calls.")
+    cpu0_semihosting_cwd = Param.String("",
+            "Base directory for semihosting file access.")
+    cpu0_semihosting_enable = Param.Bool(True,
+            "Enable semihosting SVC/HLT traps.")
+    cpu0_semihosting_heap_base = Param.Addr(0x0,
+            "Virtual address of heap base.")
+    cpu0_semihosting_heap_limit = Param.Addr(0xf000000,
+            "Virtual address of top of heap.")
+    cpu0_semihosting_stack_base = Param.Addr(0x10000000,
+            "Virtual address of base of descending stack.")
+    cpu0_semihosting_stack_limit = Param.Addr(0xf000000,
+            "Virtual address of stack limit.")
+    cpu0_trace_special_hlt_imm16 = Param.UInt16(0xf000, "For this HLT "\
+            "number, IF enable_trace_special_hlt_imm16=true, skip performing "\
+            "usual HLT execution but call MTI trace if registered")
+    cpu0_vfp_enable_at_reset = Param.Bool(False, "Enable VFP in CPACR, "\
+            "CPPWR, NSACR at reset. Warning: Arm recommends going through "\
+            "the implementation's suggested VFP power-up sequence!")
diff --git a/src/arch/arm/fastmodel/CortexA76x1/SConscript b/src/arch/arm/fastmodel/CortexA76x1/SConscript
new file mode 100644
index 0000000..a33049a
--- /dev/null
+++ b/src/arch/arm/fastmodel/CortexA76x1/SConscript
@@ -0,0 +1,41 @@
+# Copyright 2019 Google, Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Gabe Black
+
+Import('*')
+
+if not env['USE_ARM_FASTMODEL'] or env['TARGET_ISA'] != 'arm':
+    Return()
+
+protocol_dir = Dir('..').Dir('protocol')
+
+ArmFastModelComponent(File('CortexA76x1.sgproj'),
+                      File('CortexA76x1.lisa'),
+                      protocol_dir.File(
+                          'ExportedClockRateControlProtocol.lisa')
+                      ).prepare_env(env)
+SimObject('FastModelCortexA76x1.py')
+Source('cortex_a76x1.cc')
diff --git a/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.cc b/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.cc
new file mode 100644
index 0000000..3b5da01
--- /dev/null
+++ b/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.cc
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#include "arch/arm/fastmodel/CortexA76x1/cortex_a76x1.hh"
+
+#include "arch/arm/fastmodel/iris/cpu.hh"
+#include "base/logging.hh"
+#include "params/FastModelCortexA76x1.hh"
+#include "sim/core.hh"
+
+namespace FastModel
+{
+
+void
+CortexA76x1::clockChangeHandler()
+{
+    clockRateControl->set_mul_div(SimClock::Int::s, clockPeriod.value);
+}
+
+CortexA76x1::CortexA76x1(const sc_core::sc_module_name &mod_name,
+        const FastModelCortexA76x1Params &params)
+    : 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),
+      clockChanged(Iris::ClockEventName.c_str()),
+      clockPeriod(Iris::PeriodAttributeName.c_str())
+{
+    clockRateControl.bind(clock_rate_s);
+
+    set_parameter("core.BROADCASTATOMIC", params.BROADCASTATOMIC);
+    set_parameter("core.BROADCASTCACHEMAINT", params.BROADCASTCACHEMAINT);
+    set_parameter("core.BROADCASTOUTER", params.BROADCASTOUTER);
+    set_parameter("core.BROADCASTPERSIST", params.BROADCASTPERSIST);
+    set_parameter("core.CLUSTER_ID", params.CLUSTER_ID);
+    set_parameter("core.GICDISABLE", params.GICDISABLE);
+    set_parameter("core.cpi_div", params.cpi_div);
+    set_parameter("core.cpi_mul", params.cpi_mul);
+    set_parameter("core.dcache-hit_latency", params.dcache_hit_latency);
+    set_parameter("core.dcache-maintenance_latency",
+                  params.dcache_maintenance_latency);
+    set_parameter("core.dcache-miss_latency", params.dcache_miss_latency);
+    set_parameter("core.dcache-prefetch_enabled",
+                  params.dcache_prefetch_enabled);
+    set_parameter("core.dcache-read_access_latency",
+                  params.dcache_read_access_latency);
+    set_parameter("core.dcache-read_latency", params.dcache_read_latency);
+    set_parameter("core.dcache-snoop_data_transfer_latency",
+                  params.dcache_snoop_data_transfer_latency);
+    set_parameter("core.dcache-state_modelled", params.dcache_state_modelled);
+    set_parameter("core.dcache-write_access_latency",
+                  params.dcache_write_access_latency);
+    set_parameter("core.dcache-write_latency", params.dcache_write_latency);
+    set_parameter("core.default_opmode", params.default_opmode);
+    set_parameter("core.diagnostics", params.diagnostics);
+    set_parameter("core.enable_simulation_performance_optimizations",
+                  params.enable_simulation_performance_optimizations);
+    set_parameter("core.ext_abort_device_read_is_sync",
+                  params.ext_abort_device_read_is_sync);
+    set_parameter("core.ext_abort_device_write_is_sync",
+                  params.ext_abort_device_write_is_sync);
+    set_parameter("core.ext_abort_so_read_is_sync",
+                  params.ext_abort_so_read_is_sync);
+    set_parameter("core.ext_abort_so_write_is_sync",
+                  params.ext_abort_so_write_is_sync);
+    set_parameter("core.gicv3.cpuintf-mmap-access-level",
+                  params.gicv3_cpuintf_mmap_access_level);
+    set_parameter("core.has_peripheral_port", params.has_peripheral_port);
+    set_parameter("core.has_statistical_profiling",
+                  params.has_statistical_profiling);
+    set_parameter("core.icache-hit_latency", params.icache_hit_latency);
+    set_parameter("core.icache-maintenance_latency",
+                  params.icache_maintenance_latency);
+    set_parameter("core.icache-miss_latency", params.icache_miss_latency);
+    set_parameter("core.icache-prefetch_enabled",
+                  params.icache_prefetch_enabled);
+    set_parameter("core.icache-read_access_latency",
+                  params.icache_read_access_latency);
+    set_parameter("core.icache-read_latency", params.icache_read_latency);
+    set_parameter("core.icache-state_modelled", params.icache_state_modelled);
+    set_parameter("core.l3cache-hit_latency", params.l3cache_hit_latency);
+    set_parameter("core.l3cache-maintenance_latency",
+                  params.l3cache_maintenance_latency);
+    set_parameter("core.l3cache-miss_latency", params.l3cache_miss_latency);
+    set_parameter("core.l3cache-read_access_latency",
+                  params.l3cache_read_access_latency);
+    set_parameter("core.l3cache-read_latency", params.l3cache_read_latency);
+    set_parameter("core.l3cache-size", params.l3cache_size);
+    set_parameter("core.l3cache-snoop_data_transfer_latency",
+                  params.l3cache_snoop_data_transfer_latency);
+    set_parameter("core.l3cache-snoop_issue_latency",
+                  params.l3cache_snoop_issue_latency);
+    set_parameter("core.l3cache-write_access_latency",
+                  params.l3cache_write_access_latency);
+    set_parameter("core.l3cache-write_latency", params.l3cache_write_latency);
+    set_parameter("core.pchannel_treat_simreset_as_poreset",
+                  params.pchannel_treat_simreset_as_poreset);
+    set_parameter("core.periph_address_end", params.periph_address_end);
+    set_parameter("core.periph_address_start", params.periph_address_start);
+    set_parameter("core.ptw_latency", params.ptw_latency);
+    set_parameter("core.tlb_latency", params.tlb_latency);
+    set_parameter("core.treat-dcache-cmos-to-pou-as-nop",
+                  params.treat_dcache_cmos_to_pou_as_nop);
+    set_parameter("core.walk_cache_latency", params.walk_cache_latency);
+
+    set_parameter("core.cpu0.CFGEND", params.cpu0_CFGEND);
+    set_parameter("core.cpu0.CFGTE", params.cpu0_CFGTE);
+    set_parameter("core.cpu0.CRYPTODISABLE", params.cpu0_CRYPTODISABLE);
+    set_parameter("core.cpu0.RVBARADDR", params.cpu0_RVBARADDR);
+    set_parameter("core.cpu0.VINITHI", params.cpu0_VINITHI);
+    set_parameter("core.cpu0.enable_trace_special_hlt_imm16",
+                  params.cpu0_enable_trace_special_hlt_imm16);
+    set_parameter("core.cpu0.l2cache-hit_latency",
+                  params.cpu0_l2cache_hit_latency);
+    set_parameter("core.cpu0.l2cache-maintenance_latency",
+                  params.cpu0_l2cache_maintenance_latency);
+    set_parameter("core.cpu0.l2cache-miss_latency",
+                  params.cpu0_l2cache_miss_latency);
+    set_parameter("core.cpu0.l2cache-read_access_latency",
+                  params.cpu0_l2cache_read_access_latency);
+    set_parameter("core.cpu0.l2cache-read_latency",
+                  params.cpu0_l2cache_read_latency);
+    set_parameter("core.cpu0.l2cache-size", params.cpu0_l2cache_size);
+    set_parameter("core.cpu0.l2cache-snoop_data_transfer_latency",
+                  params.cpu0_l2cache_snoop_data_transfer_latency);
+    set_parameter("core.cpu0.l2cache-snoop_issue_latency",
+                  params.cpu0_l2cache_snoop_issue_latency);
+    set_parameter("core.cpu0.l2cache-write_access_latency",
+                  params.cpu0_l2cache_write_access_latency);
+    set_parameter("core.cpu0.l2cache-write_latency",
+                  params.cpu0_l2cache_write_latency);
+    set_parameter("core.cpu0.max_code_cache_mb",
+                  params.cpu0_max_code_cache_mb);
+    set_parameter("core.cpu0.min_sync_level", params.cpu0_min_sync_level);
+    set_parameter("core.cpu0.semihosting-A32_HLT",
+                  params.cpu0_semihosting_A32_HLT);
+    set_parameter("core.cpu0.semihosting-A64_HLT",
+                  params.cpu0_semihosting_A64_HLT);
+    set_parameter("core.cpu0.semihosting-ARM_SVC",
+                  params.cpu0_semihosting_ARM_SVC);
+    set_parameter("core.cpu0.semihosting-T32_HLT",
+                  params.cpu0_semihosting_T32_HLT);
+    set_parameter("core.cpu0.semihosting-Thumb_SVC",
+                  params.cpu0_semihosting_Thumb_SVC);
+    set_parameter("core.cpu0.semihosting-cmd_line",
+                  params.cpu0_semihosting_cmd_line);
+    set_parameter("core.cpu0.semihosting-cwd", params.cpu0_semihosting_cwd);
+    set_parameter("core.cpu0.semihosting-enable",
+                  params.cpu0_semihosting_enable);
+    set_parameter("core.cpu0.semihosting-heap_base",
+                  params.cpu0_semihosting_heap_base);
+    set_parameter("core.cpu0.semihosting-heap_limit",
+                  params.cpu0_semihosting_heap_limit);
+    set_parameter("core.cpu0.semihosting-stack_base",
+                  params.cpu0_semihosting_stack_base);
+    set_parameter("core.cpu0.semihosting-stack_limit",
+                  params.cpu0_semihosting_stack_limit);
+    set_parameter("core.cpu0.trace_special_hlt_imm16",
+                  params.cpu0_trace_special_hlt_imm16);
+    set_parameter("core.cpu0.vfp-enable_at_reset",
+                  params.cpu0_vfp_enable_at_reset);
+
+    add_attribute(clockPeriod);
+    SC_METHOD(clockChangeHandler);
+    dont_initialize();
+    sensitive << clockChanged;
+}
+
+Port &
+CortexA76x1::gem5_getPort(const std::string &if_name, int idx)
+{
+    if (if_name == "amba")
+        return amba;
+    else if (if_name == "redistributor_m")
+        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);
+}
+
+} // namespace FastModel
+
+FastModel::CortexA76x1 *
+FastModelCortexA76x1Params::create()
+{
+    return new FastModel::CortexA76x1(name.c_str(), *this);
+}
diff --git a/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.hh b/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.hh
new file mode 100644
index 0000000..ab42529
--- /dev/null
+++ b/src/arch/arm/fastmodel/CortexA76x1/cortex_a76x1.hh
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#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/protocol/exported_clock_rate_control.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"
+
+// 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
+{
+
+// The fast model exports a class called scx_evs_CortexA76x1 which represents
+// the subsystem described in LISA+. This class specializes it to export gem5
+// ports and interface with its peer gem5 CPU. The gem5 CPU inherits from the
+// gem5 BaseCPU class and implements its API, while this class actually does
+// the work.
+class CortexA76x1 : public scx_evs_CortexA76x1
+{
+  private:
+    SC_HAS_PROCESS(CortexA76x1);
+
+    AmbaInitiator amba;
+    AmbaInitiator redistributorM;
+    AmbaTarget redistributorS;
+
+    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;
+
+    sc_core::sc_event clockChanged;
+    sc_core::sc_attribute<Tick> clockPeriod;
+
+    void clockChangeHandler();
+
+  public:
+    CortexA76x1(const sc_core::sc_module_name &mod_name,
+            const FastModelCortexA76x1Params &params);
+
+    Port &gem5_getPort(const std::string &if_name, int idx=-1) override;
+
+    void
+    end_of_elaboration() override
+    {
+        scx_evs_CortexA76x1::end_of_elaboration();
+        scx_evs_CortexA76x1::start_of_simulation();
+    }
+    void start_of_simulation() override {}
+};
+
+} // namespace FastModel
+
+#endif // __ARCH_ARM_FASTMODEL_CORTEXA76X1_CORETEX_A76X1_HH__
diff --git a/src/arch/arm/fastmodel/FastModel.py b/src/arch/arm/fastmodel/FastModel.py
new file mode 100644
index 0000000..ccc5e2c4
--- /dev/null
+++ b/src/arch/arm/fastmodel/FastModel.py
@@ -0,0 +1,110 @@
+# Copyright 2019 Google, Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Gabe Black
+
+from m5.params import *
+from m5.proxy import *
+
+from m5.objects.SystemC import SystemC_ScModule
+from m5.objects.Tlm import TlmInitiatorSocket, TlmTargetSocket
+
+def AMBA_TARGET_ROLE(width):
+    return 'AMBA TARGET %d' % width
+
+def AMBA_INITIATOR_ROLE(width):
+    return 'AMBA INITIATOR %d' % width
+
+def SC_MASTER_PORT_ROLE(port_type):
+    return 'SC MASTER PORT for %s' % port_type
+
+def SC_SLAVE_PORT_ROLE(port_type):
+    return 'SC SLAVE PORT for %s' % port_type
+
+class AmbaTargetSocket(Port):
+    def __init__(self, width, desc):
+        my_role = AMBA_INITIATOR_ROLE(width)
+        peer_role = AMBA_TARGET_ROLE(width)
+        Port.compat(my_role, peer_role)
+
+        super(AmbaTargetSocket, self).__init__(my_role, desc)
+
+class VectorAmbaTargetSocket(VectorPort):
+    def __init__(self, width, desc):
+        my_role = AMBA_INITIATOR_ROLE(width)
+        peer_role = AMBA_TARGET_ROLE(width)
+        Port.compat(my_role, peer_role)
+
+        super(VectorAmbaTargetSocket, self).__init__(my_role, desc)
+
+class AmbaInitiatorSocket(Port):
+    def __init__(self, width, desc):
+        my_role = AMBA_TARGET_ROLE(width)
+        peer_role = AMBA_INITIATOR_ROLE(width)
+        Port.compat(my_role, peer_role)
+
+        super(AmbaInitiatorSocket, self).__init__(
+                my_role, desc, is_source=True)
+
+class VectorAmbaInitiatorSocket(VectorPort):
+    def __init__(self, width, desc):
+        my_role = AMBA_TARGET_ROLE(width)
+        peer_role = AMBA_INITIATOR_ROLE(width)
+        Port.compat(my_role, peer_role)
+
+        super(VectorAmbaInitiatorSocket, self).__init__(
+                my_role, desc, is_source=True)
+
+class ScMasterPort(Port):
+    def __init__(self, desc, port_type):
+        my_role = SC_MASTER_PORT_ROLE(port_type)
+        peer_role = SC_SLAVE_PORT_ROLE(port_type)
+        Port.compat(my_role, peer_role)
+
+        super(ScMasterPort, self).__init__(my_role, desc)
+
+class ScSlavePort(Port):
+    def __init__(self, desc, port_type):
+        my_role = SC_SLAVE_PORT_ROLE(port_type)
+        peer_role = SC_MASTER_PORT_ROLE(port_type)
+        Port.compat(my_role, peer_role)
+
+        super(ScSlavePort, self).__init__(my_role, desc)
+
+class AmbaToTlmBridge64(SystemC_ScModule):
+    type = 'AmbaToTlmBridge64'
+    cxx_class = 'FastModel::AmbaToTlmBridge64'
+    cxx_header = 'arch/arm/fastmodel/amba_to_tlm_bridge.hh'
+
+    amba = AmbaTargetSocket(64, 'AMBA PV target socket')
+    tlm = TlmInitiatorSocket(64, 'TLM initiator socket')
+
+class AmbaFromTlmBridge64(SystemC_ScModule):
+    type = 'AmbaFromTlmBridge64'
+    cxx_class = 'FastModel::AmbaFromTlmBridge64'
+    cxx_header = 'arch/arm/fastmodel/amba_from_tlm_bridge.hh'
+
+    tlm = TlmTargetSocket(64, 'TLM target socket')
+    amba = AmbaInitiatorSocket(64, 'AMBA PV initiator socket')
diff --git a/src/arch/arm/fastmodel/GIC/FastModelGIC.py b/src/arch/arm/fastmodel/GIC/FastModelGIC.py
new file mode 100644
index 0000000..79c6d48
--- /dev/null
+++ b/src/arch/arm/fastmodel/GIC/FastModelGIC.py
@@ -0,0 +1,472 @@
+# Copyright 2019 Google, Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Gabe Black
+
+from m5.params import *
+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
+
+GICV3_COMMS_TARGET_ROLE = 'GICV3 COMMS TARGET'
+GICV3_COMMS_INITIATOR_ROLE = 'GICV3 COMMS INITIATOR'
+
+Port.compat(GICV3_COMMS_TARGET_ROLE, GICV3_COMMS_INITIATOR_ROLE)
+
+class Gicv3CommsTargetSocket(Port):
+    def __init__(self, desc):
+        super(Gicv3CommsTargetSocket, self).__init__(
+                GICV3_COMMS_INITIATOR_ROLE, desc)
+
+class Gicv3CommsInitiatorSocket(Port):
+    def __init__(self, desc):
+        super(Gicv3CommsInitiatorSocket, self).__init__(
+                GICV3_COMMS_TARGET_ROLE, desc, is_source=True)
+
+
+class SCFastModelGIC(SystemC_ScModule):
+    type = 'SCFastModelGIC'
+    cxx_class = 'FastModel::SCGIC'
+    cxx_header = 'arch/arm/fastmodel/GIC/gic.hh'
+
+    enabled = Param.Bool(True, "Enable GICv3 functionality; when false the "
+            "component is inactive. has_gicv3 will replace this when GIC_IRI "
+            "replaces GICv3IRI.")
+    has_gicv3 = Param.Bool(False, "Enable GICv3 functionality; when false "
+            "the component is inactive. This will replace \"enabled\" "
+            "parameter.")
+    has_gicv4_1 = Param.Bool(False, "Enable GICv4.1 functionality; when "
+            "false the component is inactive.")
+    vPEID_bits = Param.Unsigned(16, "Number of bits of vPEID with GICv4.1.")
+    print_mmap = Param.Bool(False, "Print memory map to stdout")
+    monolithic = Param.Bool(False, "Indicate that the implementation is not "
+            "distributed")
+    direct_lpi_support = Param.Bool(False, "Enable support for LPI "
+            "operations through GICR registers")
+    cpu_affinities = Param.String("", "A comma separated list of dotted quads "
+            "containing the affinities of all PEs connected to this IRI.")
+    non_ARE_core_count = Param.Unsigned(8, "Maximum number of non-ARE cores; "
+            "normally used to pass the cluster-level NUM_CORES parameter to "
+            "the top-level redistributor.")
+    reg_base = Param.Addr(0x2c010000, "Base for decoding GICv3 registers.")
+    reg_base_per_redistributor = Param.String("", "Base address for each "
+            "redistributor in the form "
+            "'0.0.0.0=0x2c010000, 0.0.0.1=0x2c020000'.  All redistributors "
+            "must be specified and this overrides the reg-base parameter "
+            "(except that reg-base will still be used for the top-level "
+            "redistributor).")
+    gicd_alias = Param.Addr(0x0, "In GICv2 mode: the base address for a 4k "
+            "page alias of the first 4k of the Distributor page, in GICv3 "
+            "mode. the base address of a 64KB page containing message based "
+            "SPI signalling register aliases(0:Disabled)")
+    has_two_security_states = Param.Bool(True, "If true, has two security "
+            "states")
+    DS_fixed_to_zero = Param.Bool(False, "Enable/disable support of single "
+            "security state")
+    IIDR = Param.UInt32(0x0, "GICD_IIDR and GICR_IIDR value")
+    gicv2_only = Param.Bool(False, "If true, when using the GICv3 model, "
+            "pretend to be a GICv2 system")
+    STATUSR_implemented = Param.Bool(True, "Determines whether the "
+            "GICR_STATUSR register is implemented.")
+    priority_bits_implemented = Param.Unsigned(5, "Number of implemented "
+            "priority bits")
+    itargets_razwi = Param.Bool(False, "If true, the GICD_ITARGETS registers "
+            "are RAZ/WI")
+    icfgr_sgi_mask = Param.UInt32(0x0, "Mask for writes to ICFGR registers "
+            "that configure SGIs")
+    icfgr_ppi_mask = Param.UInt32(0xaaaaaaaa, "Mask for writes to ICFGR "
+            "registers that configure PPIs")
+    icfgr_spi_mask = Param.UInt32(0xaaaaaaaa, "Mask for writes to ICFGR "
+            "registers that configure SPIs")
+    icfgr_sgi_reset = Param.UInt32(0xaaaaaaaa, "Reset value for ICFGR "
+            "registers that configure SGIs")
+    icfgr_ppi_reset = Param.UInt32(0x0, "Reset value for ICFGR regesters "
+            "that configure PPIs")
+    icfgr_spi_reset = Param.UInt32(0x0, "Reset value for ICFGR regesters "
+            "that configure SPIs")
+    icfgr_ppi_rsvd_bit = Param.Bool(False, "If ARE=0, the value of reserved "
+            "bits i.e. bit 0,2,4..30 of ICFGRn for n>0")
+    igroup_sgi_mask = Param.UInt16(0xffff, "Mask for writes to SGI bits in "
+            "IGROUP registers")
+    igroup_ppi_mask = Param.UInt16(0xffff, "Mask for writes to PPI bits in "
+            "IGROUP registers")
+    igroup_sgi_reset = Param.UInt16(0x0, "Reset value for SGI bits in IGROUP "
+            "registers")
+    igroup_ppi_reset = Param.UInt16(0x0, "Reset value for SGI bits in IGROUP "
+            "registers")
+    ppi_implemented_mask = Param.UInt16(0xffff, "Mask of PPIs that are "
+            "implemented. One bit per PPI bit 0 == PPI 16 (first PPI). This "
+            "will affect other masks.")
+    spi_count = Param.UInt16(224, "Number of SPIs that are implemented.")
+    lockable_spi_count = Param.Unsigned(0, "Number of SPIs that are locked "
+            "down when CFGSDISABLE signal is asserted.  Only applies for "
+            "GICv2.")
+    iri_id_bits = Param.Unsigned(16, "Number of bits used to represent "
+            "interrupts IDs in the Distributor and Redistributors, forced to "
+            "10 if LPIs are not supported")
+    delay_redistributor_accesses = Param.Bool(True, "Delay memory accesses "
+            "from the redistributor until GICR_SYNCR is read.")
+    gicd_pidr = Param.UInt64(0x0, "The value for the GICD_PIDR registers, if "
+            "non-zero. Note: fixed fields (device type etc.) will be "
+            "overriden in this value.")
+    gicr_pidr = Param.UInt64(0x0, "The value for the GICR_PIDR registers, if "
+            "non-zero. Note: fixed fields (device type etc.) will be "
+            "overriden in this value.")
+    its_count = Param.Unsigned(0, "Number of Interrupt Translation Services "
+            "to be instantiated (0=none)")
+    its0_base = Param.Addr(0, "Register base address for ITS0 "
+            "(automatic if 0).")
+    its1_base = Param.Addr(0, "Register base address for ITS1 "
+            "(automatic if 0).")
+    its2_base = Param.Addr(0, "Register base address for ITS2 "
+            "(automatic if 0).")
+    its3_base = Param.Addr(0, "Register base address for ITS3 "
+            "(automatic if 0).")
+    gits_pidr = Param.UInt64(0x0, "The value for the GITS_PIDR registers, if "
+            "non-zero. Note: fixed fields (device type etc.) will be "
+            "overriden in this value.")
+    gits_baser0_type = Param.Unsigned(0, "Type field for GITS_BASER0 "
+            "register. 0 = Unimplemented; 1 = Devices; "
+            "2 = Virtual Processors; 3 = Physical Processors; 4 = Collections")
+    gits_baser1_type = Param.Unsigned(0, "Type field for GITS_BASER1 "
+            "register. 0 = Unimplemented; 1 = Devices; "
+            "2 = Virtual Processors; 3 = Physical Processors; 4 = Collections")
+    gits_baser2_type = Param.Unsigned(0, "Type field for GITS_BASER2 "
+            "register. 0 = Unimplemented; 1 = Devices; "
+            "2 = Virtual Processors; 3 = Physical Processors; 4 = Collections")
+    gits_baser3_type = Param.Unsigned(0, "Type field for GITS_BASER3 "
+            "register. 0 = Unimplemented; 1 = Devices; "
+            "2 = Virtual Processors; 3 = Physical Processors; 4 = Collections")
+    gits_baser4_type = Param.Unsigned(0, "Type field for GITS_BASER4 "
+            "register. 0 = Unimplemented; 1 = Devices; "
+            "2 = Virtual Processors; 3 = Physical Processors; 4 = Collections")
+    gits_baser5_type = Param.Unsigned(0, "Type field for GITS_BASER5 "
+            "register. 0 = Unimplemented; 1 = Devices; "
+            "2 = Virtual Processors; 3 = Physical Processors; 4 = Collections")
+    gits_baser6_type = Param.Unsigned(0, "Type field for GITS_BASER6 "
+            "register. 0 = Unimplemented; 1 = Devices; "
+            "2 = Virtual Processors; 3 = Physical Processors; 4 = Collections")
+    gits_baser7_type = Param.Unsigned(0, "Type field for GITS_BASER7 "
+            "register. 0 = Unimplemented; 1 = Devices; "
+            "2 = Virtual Processors; 3 = Physical Processors; 4 = Collections")
+    gits_baser0_entry_bytes = Param.Unsigned(8, "Number of bytes required per "
+            "entry for GITS_BASER0 register.")
+    gits_baser1_entry_bytes = Param.Unsigned(8, "Number of bytes required per "
+            "entry for GITS_BASER1 register.")
+    gits_baser2_entry_bytes = Param.Unsigned(8, "Number of bytes required per "
+            "entry for GITS_BASER2 register.")
+    gits_baser3_entry_bytes = Param.Unsigned(8, "Number of bytes required per "
+            "entry for GITS_BASER3 register.")
+    gits_baser4_entry_bytes = Param.Unsigned(8, "Number of bytes required per "
+            "entry for GITS_BASER4 register.")
+    gits_baser5_entry_bytes = Param.Unsigned(8, "Number of bytes required per "
+            "entry for GITS_BASER5 register.")
+    gits_baser6_entry_bytes = Param.Unsigned(8, "Number of bytes required per "
+            "entry for GITS_BASER6 register.")
+    gits_baser7_entry_bytes = Param.Unsigned(8, "Number of bytes required per "
+            "entry for GITS_BASER7 register.")
+    gits_baser0_indirect_raz = Param.Bool(False, "Indirect field for "
+            "GITS_BASER0 register is RAZ/WI.")
+    gits_baser1_indirect_raz = Param.Bool(False, "Indirect field for "
+            "GITS_BASER1 register is RAZ/WI.")
+    gits_baser2_indirect_raz = Param.Bool(False, "Indirect field for "
+            "GITS_BASER2 register is RAZ/WI.")
+    gits_baser3_indirect_raz = Param.Bool(False, "Indirect field for "
+            "GITS_BASER3 register is RAZ/WI.")
+    gits_baser4_indirect_raz = Param.Bool(False, "Indirect field for "
+            "GITS_BASER4 register is RAZ/WI.")
+    gits_baser5_indirect_raz = Param.Bool(False, "Indirect field for "
+            "GITS_BASER5 register is RAZ/WI.")
+    gits_baser6_indirect_raz = Param.Bool(False, "Indirect field for "
+            "GITS_BASER6 register is RAZ/WI.")
+    gits_baser7_indirect_raz = Param.Bool(False, "Indirect field for "
+            "GITS_BASER7 register is RAZ/WI.")
+    its_baser_force_page_alignement = Param.Bool(True, "Force alignement of "
+            "address writen to a GITS_BASER register to the page size "
+            "configured")
+    processor_numbers = Param.String("", "Specify processor numbers (as "
+            "appears in GICR_TYPER) in the form 0.0.0.0=0,0.0.0.1=1 etc.) If "
+            "not specified, will number processors starting at 0.")
+    supports_shareability = Param.Bool(True, "Device supports shareability "
+            "attributes on outgoing memory bus (i.e. is modelling an ACElite "
+            "port rather than an AXI4 port).")
+    a3_affinity_supported = Param.Bool(False, "Device supports affinity "
+            "level 3 values that are non-zero.")
+    SGI_RSS_support = Param.Bool(False, "Device has support for the Range "
+            "Selector feature for SGI")
+    gicr_propbaser_read_only = Param.Bool(False, "GICR_PROPBASER register is "
+            "read-only.")
+    gicr_propbaser_reset = Param.UInt64(0x0, "Value of GICR_PROPBASER on "
+            "reset.")
+    its_device_bits = Param.Unsigned(16, "Number of bits supported for ITS "
+            "device IDs.")
+    its_entry_size = Param.Unsigned(8, "Number of bytes required to store "
+            "each entry in the ITT tables.")
+    its_id_bits = Param.Unsigned(16, "Number of interrupt bits supported by "
+            "ITS.")
+    its_collection_id_bits = Param.Unsigned(0, "Number of collection bits "
+            "supported by ITS (optional parameter, 0 => 16bits support and "
+            "GITS_TYPER.CIL=0")
+    its_cumulative_collection_tables = Param.Bool(True, "When true, the "
+            "supported amount of collections is the sum of GITS_TYPER.HCC and "
+            "the number of collections supported in memory, otherwise, simply "
+            "the number supported in memory only. Irrelevant when HCC=0")
+    delay_ITS_accesses = Param.Bool(True, "Delay accesses from the ITS until "
+            "GICR_SYNCR is read.")
+    local_SEIs = Param.Bool(False, "Generate SEI to signal internal issues")
+    local_VSEIs = Param.Bool(False, "Generate VSEI to signal internal issues")
+    ITS_use_physical_target_addresses = Param.Bool(True, "Use physical "
+            "hardware adresses for targets in ITS commands -- must be true "
+            "for distributed implementations")
+    ITS_hardware_collection_count = Param.Unsigned(0, "Number of hardware "
+            "collections held exclusively in the ITS")
+    ITS_MOVALL_update_collections = Param.Bool(False, "Whether MOVALL command "
+            "updates the collection entires")
+    ITS_TRANSLATE64R = Param.Bool(False, "Add an implementation specific "
+            "register at 0x10008 supporting 64 bit TRANSLATER (dev[63:32], "
+            "interupt[31:0])")
+    enable_protocol_checking = Param.Bool(False, "Enable/disable protocol "
+            "checking at cpu interface")
+    fixed_routed_spis = Param.String("", "Value of IROUTER[n] register in the "
+            "form 'n=a.b.c.d, n=*'. The RM bit of IROUTER is 0 when n=a.b.c.d "
+            "is used else 1 when n=* is used. n can be >= 32 and <= 1019")
+    irouter_default_mask = Param.String("", "Default Mask value for "
+            "IROUTER[32..1019] register in the form 'a.b.c.d'")
+    irouter_default_reset = Param.String("", "Default Reset Value of "
+            "IROUTER[32..1019] register in the form 'a.b.c.d' or *")
+    irouter_reset_values = Param.String("", "Reset Value of IROUTER[n] "
+            "register in the form 'n=a.b.c.d or n=*'.n can be >= 32 and "
+            "<= 1019")
+    irouter_mask_values = Param.String("", "Mask Value of IROUTER[n] register "
+            "in the form 'n=a.b.c.d'.n can be >= 32 and <= 1019")
+    ITS_threaded_command_queue = Param.Bool(True, "Enable execution of ITS "
+            "commands in a separate thread which is sometimes required for "
+            "cosimulation")
+    ITS_legacy_iidr_typer_offset = Param.Bool(False, "Put the GITS_IIDR and "
+            "GITS_TYPER registers at their older offset of 0x8 and 0x4 "
+            "respectively")
+    redistributor_threaded_command_queue = Param.Bool(True, "Enable execution "
+            "of redistributor delayed transactions in a separate thread which "
+            "is sometimes required for cosimulation")
+    ignore_generate_sgi_when_no_are = Param.Bool(False, "Ignore GenerateSGI "
+            "packets coming form the CPU interface if both ARE_S and ARE_NS "
+            "are 0")
+    trace_speculative_lpi_property_updates = Param.Bool(False, "Trace LPI "
+            "propery updates performed on speculative accesses (useful for "
+            "debuging LPI)")
+    virtual_lpi_support = Param.Bool(False, "GICv4 Virtual LPIs and Direct "
+            "injection of Virtual LPIs supported")
+    virtual_priority_bits = Param.Unsigned(5, "Number of implemented virtual "
+            "priority bits")
+    LPI_cache_type = Param.Unsigned(1, "Cache type for LPIs, 0:No caching, "
+            "1:Full caching")
+    LPI_cache_check_data = Param.Bool(False, "Enable Cached LPI data against "
+             "memory checking when available for cache type")
+    DPG_bits_implemented = Param.Bool(False, "Enable implementation of "
+            "interrupt group participation bits or DPG bits in GICR_CTLR")
+    DPG_ARE_only = Param.Bool(False, "Limit application of DPG bits to "
+            "interrupt groups for which ARE=1")
+    ARE_fixed_to_one = Param.Bool(False, "GICv2 compatibility is not "
+            "supported and GICD_CTLR.ARE_* is always one")
+    legacy_sgi_enable_rao = Param.Bool(False, "Enables for SGI associated "
+            "with an ARE=0 regime are RAO/WI")
+    pa_size = Param.Unsigned(48, "Number of valid bits in physical address")
+    MSI_IIDR = Param.UInt32(0x0, "Value returned in MSI_IIDR registers.")
+    MSI_NS_frame0_base = Param.Addr(0x0, "If non-zero, sets the base "
+            "address used for non-secure MSI frame 0 registers.")
+    MSI_NS_frame0_max_SPI = Param.UInt16(0, "Maximum SPI ID supported by "
+            "non-secure MSI frame 0. Set to 0 to disable frame.")
+    MSI_NS_frame0_min_SPI = Param.UInt16(0, "Minimum SPI ID supported by "
+            "non-secure MSI frame 0. Set to 0 to disable frame.")
+    MSI_NS_frame1_base = Param.Addr(0x0, "If non-zero, sets the base "
+            "address used for non-secure MSI frame 1 registers.")
+    MSI_NS_frame1_max_SPI = Param.UInt16(0, "Maximum SPI ID supported by "
+            "non-secure MSI frame 1. Set to 0 to disable frame.")
+    MSI_NS_frame1_min_SPI = Param.UInt16(0, "Minimum SPI ID supported by "
+            "non-secure MSI frame 1. Set to 0 to disable frame.")
+    MSI_NS_frame2_base = Param.Addr(0x0, "If non-zero, sets the base address "
+            "used for non-secure MSI frame 2 registers.")
+    MSI_NS_frame2_max_SPI = Param.UInt16(0, "Maximum SPI ID supported by "
+            "non-secure MSI frame 2. Set to 0 to disable frame.")
+    MSI_NS_frame2_min_SPI = Param.UInt16(0, "Minimum SPI ID supported by "
+            "non-secure MSI frame 2. Set to 0 to disable frame.")
+    MSI_NS_frame3_base = Param.Addr(0x0, "If non-zero, sets the base address "
+            "used for non-secure MSI frame 3 registers.")
+    MSI_NS_frame3_max_SPI = Param.UInt16(0, "Maximum SPI ID supported by "
+            "non-secure MSI frame 3. Set to 0 to disable frame.")
+    MSI_NS_frame3_min_SPI = Param.UInt16(0, "Minimum SPI ID supported by "
+            "non-secure MSI frame 3. Set to 0 to disable frame.")
+    MSI_NS_frame4_base = Param.Addr(0x0, "If non-zero, sets the base address "
+            "used for non-secure MSI frame 4 registers.")
+    MSI_NS_frame4_max_SPI = Param.UInt16(0, "Maximum SPI ID supported by "
+            "non-secure MSI frame 4. Set to 0 to disable frame.")
+    MSI_NS_frame4_min_SPI = Param.UInt16(0, "Minimum SPI ID supported by "
+            "non-secure MSI frame 4. Set to 0 to disable frame.")
+    MSI_NS_frame5_base = Param.Addr(0x0, "If non-zero, sets the base address "
+            "used for non-secure MSI frame 5 registers.")
+    MSI_NS_frame5_max_SPI = Param.UInt16(0, "Maximum SPI ID supported by "
+            "non-secure MSI frame 5. Set to 0 to disable frame.")
+    MSI_NS_frame5_min_SPI = Param.UInt16(0, "Minimum SPI ID supported by "
+            "non-secure MSI frame 5. Set to 0 to disable frame.")
+    MSI_NS_frame6_base = Param.Addr(0x0, "If non-zero, sets the base address "
+            "used for non-secure MSI frame 6 registers.")
+    MSI_NS_frame6_max_SPI = Param.UInt16(0, "Maximum SPI ID supported by "
+            "non-secure MSI frame 6. Set to 0 to disable frame.")
+    MSI_NS_frame6_min_SPI = Param.UInt16(0, "Minimum SPI ID supported by "
+            "non-secure MSI frame 6. Set to 0 to disable frame.")
+    MSI_NS_frame7_base = Param.Addr(0x0, "If non-zero, sets the base address "
+            "used for non-secure MSI frame 7 registers.")
+    MSI_NS_frame7_max_SPI = Param.UInt16(0, "Maximum SPI ID supported by "
+            "non-secure MSI frame 7. Set to 0 to disable frame.")
+    MSI_NS_frame7_min_SPI = Param.UInt16(0, "Minimum SPI ID supported by "
+            "non-secure MSI frame 7. Set to 0 to disable frame.")
+    MSI_PIDR = Param.UInt64(0x0, "The value for the MSI_PIDR registers, if "
+            "non-zero and distributor supports GICv2m. Note: fixed fields "
+            "(device type etc.) will be overriden in this value.")
+    MSI_S_frame0_base = Param.Addr(0x0, "If non-zero, sets the base address "
+            "used for secure MSI frame 0 registers.")
+    MSI_S_frame0_max_SPI = Param.UInt16(0, "Maximum SPI ID supported by "
+            "secure MSI frame 0. Set to 0 to disable frame.")
+    MSI_S_frame0_min_SPI = Param.UInt16(0, "Minimum SPI ID supported by "
+            "secure MSI frame 0. Set to 0 to disable frame.")
+    MSI_S_frame1_base = Param.Addr(0x0, "If non-zero, sets the base address "
+            "used for secure MSI frame 1 registers.")
+    MSI_S_frame1_max_SPI = Param.UInt16(0, "Maximum SPI ID supported by "
+            "secure MSI frame 1. Set to 0 to disable frame.")
+    MSI_S_frame1_min_SPI = Param.UInt16(0, "Minimum SPI ID supported by "
+            "secure MSI frame 1. Set to 0 to disable frame.")
+    MSI_S_frame2_base = Param.Addr(0x0, "If non-zero, sets the base address "
+            "used for secure MSI frame 2 registers.")
+    MSI_S_frame2_max_SPI = Param.UInt16(0, "Maximum SPI ID supported by "
+            "secure MSI frame 2. Set to 0 to disable frame.")
+    MSI_S_frame2_min_SPI = Param.UInt16(0, "Minimum SPI ID supported by "
+            "secure MSI frame 2. Set to 0 to disable frame.")
+    MSI_S_frame3_base = Param.Addr(0x0, "If non-zero, sets the base address "
+            "used for secure MSI frame 3 registers.")
+    MSI_S_frame3_max_SPI = Param.UInt16(0, "Maximum SPI ID supported by "
+            "secure MSI frame 3. Set to 0 to disable frame.")
+    MSI_S_frame3_min_SPI = Param.UInt16(0, "Minimum SPI ID supported by "
+            "secure MSI frame 3. Set to 0 to disable frame.")
+    MSI_S_frame4_base = Param.Addr(0x0, "If non-zero, sets the base address "
+            "used for secure MSI frame 4 registers.")
+    MSI_S_frame4_max_SPI = Param.UInt16(0, "Maximum SPI ID supported by "
+            "secure MSI frame 4. Set to 0 to disable frame.")
+    MSI_S_frame4_min_SPI = Param.UInt16(0, "Minimum SPI ID supported by "
+            "secure MSI frame 4. Set to 0 to disable frame.")
+    MSI_S_frame5_base = Param.Addr(0x0, "If non-zero, sets the base address "
+            "used for secure MSI frame 5 registers.")
+    MSI_S_frame5_max_SPI = Param.UInt16(0, "Maximum SPI ID supported by "
+            "secure MSI frame 5. Set to 0 to disable frame.")
+    MSI_S_frame5_min_SPI = Param.UInt16(0, "Minimum SPI ID supported by "
+            "secure MSI frame 5. Set to 0 to disable frame.")
+    MSI_S_frame6_base = Param.Addr(0x0, "If non-zero, sets the base address "
+            "used for secure MSI frame 6 registers.")
+    MSI_S_frame6_max_SPI = Param.UInt16(0, "Maximum SPI ID supported by "
+            "secure MSI frame 6. Set to 0 to disable frame.")
+    MSI_S_frame6_min_SPI = Param.UInt16(0, "Minimum SPI ID supported by "
+            "secure MSI frame 6. Set to 0 to disable frame.")
+    MSI_S_frame7_base = Param.Addr(0x0, "If non-zero, sets the base address "
+            "used for secure MSI frame 7 registers.")
+    MSI_S_frame7_max_SPI = Param.UInt16(0, "Maximum SPI ID supported by "
+            "secure MSI frame 7. Set to 0 to disable frame.")
+    MSI_S_frame7_min_SPI = Param.UInt16(0, "Minimum SPI ID supported by "
+            "secure MSI frame 7. Set to 0 to disable frame.")
+    outer_cacheability_support = Param.Bool(False, "Allow configuration of "
+            "outer cachability attributes in ITS and Redistributor")
+    wakeup_on_reset = Param.Bool(False, "Go against specification and start "
+            "redistributors in woken-up state at reset. This allows software "
+            "that was written for previous versions of the GICv3 "
+            "specification to work correctly. This should not be used for "
+            "production code or when the distributor is used separately from "
+            "the core fast model.")
+    SPI_MBIS = Param.Bool(True, "Distributor supports meassage based "
+            "signaling of SPI")
+    SPI_unimplemented = Param.String("", "A comma spearated list of "
+            "unimplemented SPIs ranges for sparse SPI defintion(for ex: "
+            "'35, 39-42, 73)'")
+    irm_razwi = Param.Bool(False, "GICD_IROUTERn.InterruptRoutingMode is "
+            "RAZ/WI")
+    common_LPI_configuration = Param.Unsigned(0, "Describes which "
+            "re-distributors share (and must be configured with the same) "
+            "LPI configuration table as described in GICR_TYPER( 0:All, "
+            "1:A.x.x.x, 2:A.B.x.x, 3:A.B.C.x")
+    single_set_support = Param.Bool(False, "When true, forces redistributors "
+            "to recall interrupts with a clear rather than issue a second Set "
+            "command")
+    has_mpam = Param.Unsigned(0, "Implement ARMv8.4 MPAM Registers and "
+            "associated functionality.\n\nPossible values of this parameter "
+            "are:\n  - 0, feature is not enabled.\n  - 1, feature is "
+            "implemented if ARMv8.4 is enabled.\n  - 2, feature is "
+            "implemented.")
+    mpam_max_partid = Param.UInt16(0xffff, "MPAM Maximum PARTID Supported")
+    mpam_max_pmg = Param.Unsigned(255, "MPAM Maximum PMG Supported")
+    output_attributes = Param.String("ExtendedID[62:55]=MPAM_PMG, "
+            "ExtendedID[54:39]=MPAM_PARTID, ExtendedID[38]=MPAM_NS",
+            "User-defined transform to be applied to bus attributes like "
+            "MasterID, ExtendedID or UserFlags. Currently, only works for "
+            "MPAM Attributes encoding into bus attributes.")
+    has_DirtyVLPIOnLoad = Param.Bool(False, "GICR_VPENDBASER.Dirty reflects "
+            "transient loading state when valid=1")
+    allow_LPIEN_clear = Param.Bool(False, "Allow RW behaviour on "
+            "GICR_CTLR.LPIEN isntead of set once")
+    GICD_legacy_reg_reserved = Param.Bool(False, "When ARE is RAO/WI, makes "
+            "superfluous registers in GICD reserved (including for the "
+            "purpose of STATUSR updates)")
+    extended_spi_count = Param.Unsigned(0, "Number of extended SPI supported")
+    extended_ppi_count = Param.Unsigned(0, "Number of extended PPI supported")
+    consolidators = Param.String("", "Specify consolidators' base addresses, "
+            "interrupt line counts and base interrupt IDs, in the form "
+            "'baseAddr0:itlineCount0:baseINTID0, "
+            "baseAddr1:itlineCount1:baseINTID1, [etc]' "
+            "(eg '0x3f100000:64:4096, 0x3f200000:64:4224'). The "
+            "consolidators' count is inferred from the list (maximum of 4). "
+            "If not specified, the component contains no consolidators.")
+
+class FastModelGIC(BaseGic):
+    type = 'FastModelGIC'
+    cxx_class = 'FastModel::GIC'
+    cxx_header = 'arch/arm/fastmodel/GIC/gic.hh'
+
+    sc_gic = Param.SCFastModelGIC(SCFastModelGIC(),
+                                  'SystemC version of the GIC')
+
+    amba_m = AmbaInitiatorSocket(64, 'Memory initiator socket')
+    amba_s = AmbaTargetSocket(64, 'Memory target socket')
+
+    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
new file mode 100644
index 0000000..b15c9ef
--- /dev/null
+++ b/src/arch/arm/fastmodel/GIC/GIC.lisa
@@ -0,0 +1,756 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ *          Chun-Chen TK Hsu
+ */
+
+protocol AMBAPVPPICommand
+{
+    properties
+    {
+        sc_master_port_class_name =
+            "amba_pv::signal_master_port<FastModel::PPICommand>";
+        sc_slave_base_class_name =
+            "amba_pv::signal_slave_base<FastModel::PPICommand>";
+        sc_slave_export_class_name =
+            "amba_pv::signal_slave_export<FastModel::PPICommand>";
+    }
+
+    includes
+    {
+        #include <amba_pv.h>
+        #include "arch/arm/fastmodel/GIC/commands.hh"
+    }
+
+    slave behavior set_state(
+            int export_id, const FastModel::PPICommand &value);
+}
+
+protocol AMBAPVSPICommand
+{
+    properties
+    {
+        sc_master_port_class_name =
+            "amba_pv::signal_master_port<FastModel::SPICommand>";
+        sc_slave_base_class_name =
+            "amba_pv::signal_slave_base<FastModel::SPICommand>";
+        sc_slave_export_class_name =
+            "amba_pv::signal_slave_export<FastModel::SPICommand>";
+    }
+
+    includes
+    {
+        #include <amba_pv.h>
+        #include "arch/arm/fastmodel/GIC/commands.hh"
+    }
+
+    slave behavior set_state(
+            int export_id, const FastModel::SPICommand &value);
+}
+
+component GIC
+{
+    composition
+    {
+        gic : GIC_IRI();
+
+        // Bridges
+        // For the main interface with memory.
+        mem_out : PVBus2AMBAPV();
+        mem_in : AMBAPV2PVBus();
+
+        // For the CPU interfaces.
+        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
+    {
+        // For the main interface with memory.
+        gic.pvbus_m => mem_out.pvbus_s;
+        mem_out.amba_pv_m => self.amba_m;
+        self.amba_s => mem_in.amba_pv_s;
+        mem_in.pvbus_m => gic.pvbus_s;
+
+        // For the CPU interface.
+        gic.redistributor_m => gic_gic2pv.distributor_s;
+        gic_gic2pv.pvbus_m => gic_pv2amba.pvbus_s;
+        gic_pv2amba.amba_pv_m => self.redistributor_m;
+        self.redistributor_s => gic_amba2pv.amba_pv_s;
+        gic_amba2pv.pvbus_m => gic_gic2pv.pvbus_s;
+
+        // Internal ports for PPI and SPI programmatic access.
+        self.ppi_0 => gic.ppi_in_0;
+        self.ppi_1 => gic.ppi_in_1;
+        self.ppi_2 => gic.ppi_in_2;
+        self.ppi_3 => gic.ppi_in_3;
+        self.ppi_4 => gic.ppi_in_4;
+        self.ppi_5 => gic.ppi_in_5;
+        self.ppi_6 => gic.ppi_in_6;
+        self.ppi_7 => gic.ppi_in_7;
+        self.ppi_8 => gic.ppi_in_8;
+        self.ppi_9 => gic.ppi_in_9;
+        self.ppi_10 => gic.ppi_in_10;
+        self.ppi_11 => gic.ppi_in_11;
+        self.ppi_12 => gic.ppi_in_12;
+        self.ppi_13 => gic.ppi_in_13;
+        self.ppi_14 => gic.ppi_in_14;
+        self.ppi_15 => gic.ppi_in_15;
+        self.ppi_16 => gic.ppi_in_16;
+        self.ppi_17 => gic.ppi_in_17;
+        self.ppi_18 => gic.ppi_in_18;
+        self.ppi_19 => gic.ppi_in_19;
+        self.ppi_20 => gic.ppi_in_20;
+        self.ppi_21 => gic.ppi_in_21;
+        self.ppi_22 => gic.ppi_in_22;
+        self.ppi_23 => gic.ppi_in_23;
+        self.ppi_24 => gic.ppi_in_24;
+        self.ppi_25 => gic.ppi_in_25;
+        self.ppi_26 => gic.ppi_in_26;
+        self.ppi_27 => gic.ppi_in_27;
+        self.ppi_28 => gic.ppi_in_28;
+        self.ppi_29 => gic.ppi_in_29;
+        self.ppi_30 => gic.ppi_in_30;
+        self.ppi_31 => gic.ppi_in_31;
+        self.ppi_32 => gic.ppi_in_32;
+        self.ppi_33 => gic.ppi_in_33;
+        self.ppi_34 => gic.ppi_in_34;
+        self.ppi_35 => gic.ppi_in_35;
+        self.ppi_36 => gic.ppi_in_36;
+        self.ppi_37 => gic.ppi_in_37;
+        self.ppi_38 => gic.ppi_in_38;
+        self.ppi_39 => gic.ppi_in_39;
+        self.ppi_40 => gic.ppi_in_40;
+        self.ppi_41 => gic.ppi_in_41;
+        self.ppi_42 => gic.ppi_in_42;
+        self.ppi_43 => gic.ppi_in_43;
+        self.ppi_44 => gic.ppi_in_44;
+        self.ppi_45 => gic.ppi_in_45;
+        self.ppi_46 => gic.ppi_in_46;
+        self.ppi_47 => gic.ppi_in_47;
+        self.ppi_48 => gic.ppi_in_48;
+        self.ppi_49 => gic.ppi_in_49;
+        self.ppi_50 => gic.ppi_in_50;
+        self.ppi_51 => gic.ppi_in_51;
+        self.ppi_52 => gic.ppi_in_52;
+        self.ppi_53 => gic.ppi_in_53;
+        self.ppi_54 => gic.ppi_in_54;
+        self.ppi_55 => gic.ppi_in_55;
+        self.ppi_56 => gic.ppi_in_56;
+        self.ppi_57 => gic.ppi_in_57;
+        self.ppi_58 => gic.ppi_in_58;
+        self.ppi_59 => gic.ppi_in_59;
+        self.ppi_60 => gic.ppi_in_60;
+        self.ppi_61 => gic.ppi_in_61;
+        self.ppi_62 => gic.ppi_in_62;
+        self.ppi_63 => gic.ppi_in_63;
+        self.ppi_64 => gic.ppi_in_64;
+        self.ppi_65 => gic.ppi_in_65;
+        self.ppi_66 => gic.ppi_in_66;
+        self.ppi_67 => gic.ppi_in_67;
+        self.ppi_68 => gic.ppi_in_68;
+        self.ppi_69 => gic.ppi_in_69;
+        self.ppi_70 => gic.ppi_in_70;
+        self.ppi_71 => gic.ppi_in_71;
+        self.ppi_72 => gic.ppi_in_72;
+        self.ppi_73 => gic.ppi_in_73;
+        self.ppi_74 => gic.ppi_in_74;
+        self.ppi_75 => gic.ppi_in_75;
+        self.ppi_76 => gic.ppi_in_76;
+        self.ppi_77 => gic.ppi_in_77;
+        self.ppi_78 => gic.ppi_in_78;
+        self.ppi_79 => gic.ppi_in_79;
+        self.ppi_80 => gic.ppi_in_80;
+        self.ppi_81 => gic.ppi_in_81;
+        self.ppi_82 => gic.ppi_in_82;
+        self.ppi_83 => gic.ppi_in_83;
+        self.ppi_84 => gic.ppi_in_84;
+        self.ppi_85 => gic.ppi_in_85;
+        self.ppi_86 => gic.ppi_in_86;
+        self.ppi_87 => gic.ppi_in_87;
+        self.ppi_88 => gic.ppi_in_88;
+        self.ppi_89 => gic.ppi_in_89;
+        self.ppi_90 => gic.ppi_in_90;
+        self.ppi_91 => gic.ppi_in_91;
+        self.ppi_92 => gic.ppi_in_92;
+        self.ppi_93 => gic.ppi_in_93;
+        self.ppi_94 => gic.ppi_in_94;
+        self.ppi_95 => gic.ppi_in_95;
+        self.ppi_96 => gic.ppi_in_96;
+        self.ppi_97 => gic.ppi_in_97;
+        self.ppi_98 => gic.ppi_in_98;
+        self.ppi_99 => gic.ppi_in_99;
+        self.ppi_100 => gic.ppi_in_100;
+        self.ppi_101 => gic.ppi_in_101;
+        self.ppi_102 => gic.ppi_in_102;
+        self.ppi_103 => gic.ppi_in_103;
+        self.ppi_104 => gic.ppi_in_104;
+        self.ppi_105 => gic.ppi_in_105;
+        self.ppi_106 => gic.ppi_in_106;
+        self.ppi_107 => gic.ppi_in_107;
+        self.ppi_108 => gic.ppi_in_108;
+        self.ppi_109 => gic.ppi_in_109;
+        self.ppi_110 => gic.ppi_in_110;
+        self.ppi_111 => gic.ppi_in_111;
+        self.ppi_112 => gic.ppi_in_112;
+        self.ppi_113 => gic.ppi_in_113;
+        self.ppi_114 => gic.ppi_in_114;
+        self.ppi_115 => gic.ppi_in_115;
+        self.ppi_116 => gic.ppi_in_116;
+        self.ppi_117 => gic.ppi_in_117;
+        self.ppi_118 => gic.ppi_in_118;
+        self.ppi_119 => gic.ppi_in_119;
+        self.ppi_120 => gic.ppi_in_120;
+        self.ppi_121 => gic.ppi_in_121;
+        self.ppi_122 => gic.ppi_in_122;
+        self.ppi_123 => gic.ppi_in_123;
+        self.ppi_124 => gic.ppi_in_124;
+        self.ppi_125 => gic.ppi_in_125;
+        self.ppi_126 => gic.ppi_in_126;
+        self.ppi_127 => gic.ppi_in_127;
+        self.ppi_128 => gic.ppi_in_128;
+        self.ppi_129 => gic.ppi_in_129;
+        self.ppi_130 => gic.ppi_in_130;
+        self.ppi_131 => gic.ppi_in_131;
+        self.ppi_132 => gic.ppi_in_132;
+        self.ppi_133 => gic.ppi_in_133;
+        self.ppi_134 => gic.ppi_in_134;
+        self.ppi_135 => gic.ppi_in_135;
+        self.ppi_136 => gic.ppi_in_136;
+        self.ppi_137 => gic.ppi_in_137;
+        self.ppi_138 => gic.ppi_in_138;
+        self.ppi_139 => gic.ppi_in_139;
+        self.ppi_140 => gic.ppi_in_140;
+        self.ppi_141 => gic.ppi_in_141;
+        self.ppi_142 => gic.ppi_in_142;
+        self.ppi_143 => gic.ppi_in_143;
+        self.ppi_144 => gic.ppi_in_144;
+        self.ppi_145 => gic.ppi_in_145;
+        self.ppi_146 => gic.ppi_in_146;
+        self.ppi_147 => gic.ppi_in_147;
+        self.ppi_148 => gic.ppi_in_148;
+        self.ppi_149 => gic.ppi_in_149;
+        self.ppi_150 => gic.ppi_in_150;
+        self.ppi_151 => gic.ppi_in_151;
+        self.ppi_152 => gic.ppi_in_152;
+        self.ppi_153 => gic.ppi_in_153;
+        self.ppi_154 => gic.ppi_in_154;
+        self.ppi_155 => gic.ppi_in_155;
+        self.ppi_156 => gic.ppi_in_156;
+        self.ppi_157 => gic.ppi_in_157;
+        self.ppi_158 => gic.ppi_in_158;
+        self.ppi_159 => gic.ppi_in_159;
+        self.ppi_160 => gic.ppi_in_160;
+        self.ppi_161 => gic.ppi_in_161;
+        self.ppi_162 => gic.ppi_in_162;
+        self.ppi_163 => gic.ppi_in_163;
+        self.ppi_164 => gic.ppi_in_164;
+        self.ppi_165 => gic.ppi_in_165;
+        self.ppi_166 => gic.ppi_in_166;
+        self.ppi_167 => gic.ppi_in_167;
+        self.ppi_168 => gic.ppi_in_168;
+        self.ppi_169 => gic.ppi_in_169;
+        self.ppi_170 => gic.ppi_in_170;
+        self.ppi_171 => gic.ppi_in_171;
+        self.ppi_172 => gic.ppi_in_172;
+        self.ppi_173 => gic.ppi_in_173;
+        self.ppi_174 => gic.ppi_in_174;
+        self.ppi_175 => gic.ppi_in_175;
+        self.ppi_176 => gic.ppi_in_176;
+        self.ppi_177 => gic.ppi_in_177;
+        self.ppi_178 => gic.ppi_in_178;
+        self.ppi_179 => gic.ppi_in_179;
+        self.ppi_180 => gic.ppi_in_180;
+        self.ppi_181 => gic.ppi_in_181;
+        self.ppi_182 => gic.ppi_in_182;
+        self.ppi_183 => gic.ppi_in_183;
+        self.ppi_184 => gic.ppi_in_184;
+        self.ppi_185 => gic.ppi_in_185;
+        self.ppi_186 => gic.ppi_in_186;
+        self.ppi_187 => gic.ppi_in_187;
+        self.ppi_188 => gic.ppi_in_188;
+        self.ppi_189 => gic.ppi_in_189;
+        self.ppi_190 => gic.ppi_in_190;
+        self.ppi_191 => gic.ppi_in_191;
+        self.ppi_192 => gic.ppi_in_192;
+        self.ppi_193 => gic.ppi_in_193;
+        self.ppi_194 => gic.ppi_in_194;
+        self.ppi_195 => gic.ppi_in_195;
+        self.ppi_196 => gic.ppi_in_196;
+        self.ppi_197 => gic.ppi_in_197;
+        self.ppi_198 => gic.ppi_in_198;
+        self.ppi_199 => gic.ppi_in_199;
+        self.ppi_200 => gic.ppi_in_200;
+        self.ppi_201 => gic.ppi_in_201;
+        self.ppi_202 => gic.ppi_in_202;
+        self.ppi_203 => gic.ppi_in_203;
+        self.ppi_204 => gic.ppi_in_204;
+        self.ppi_205 => gic.ppi_in_205;
+        self.ppi_206 => gic.ppi_in_206;
+        self.ppi_207 => gic.ppi_in_207;
+        self.ppi_208 => gic.ppi_in_208;
+        self.ppi_209 => gic.ppi_in_209;
+        self.ppi_210 => gic.ppi_in_210;
+        self.ppi_211 => gic.ppi_in_211;
+        self.ppi_212 => gic.ppi_in_212;
+        self.ppi_213 => gic.ppi_in_213;
+        self.ppi_214 => gic.ppi_in_214;
+        self.ppi_215 => gic.ppi_in_215;
+        self.ppi_216 => gic.ppi_in_216;
+        self.ppi_217 => gic.ppi_in_217;
+        self.ppi_218 => gic.ppi_in_218;
+        self.ppi_219 => gic.ppi_in_219;
+        self.ppi_220 => gic.ppi_in_220;
+        self.ppi_221 => gic.ppi_in_221;
+        self.ppi_222 => gic.ppi_in_222;
+        self.ppi_223 => gic.ppi_in_223;
+        self.ppi_224 => gic.ppi_in_224;
+        self.ppi_225 => gic.ppi_in_225;
+        self.ppi_226 => gic.ppi_in_226;
+        self.ppi_227 => gic.ppi_in_227;
+        self.ppi_228 => gic.ppi_in_228;
+        self.ppi_229 => gic.ppi_in_229;
+        self.ppi_230 => gic.ppi_in_230;
+        self.ppi_231 => gic.ppi_in_231;
+        self.ppi_232 => gic.ppi_in_232;
+        self.ppi_233 => gic.ppi_in_233;
+        self.ppi_234 => gic.ppi_in_234;
+        self.ppi_235 => gic.ppi_in_235;
+        self.ppi_236 => gic.ppi_in_236;
+        self.ppi_237 => gic.ppi_in_237;
+        self.ppi_238 => gic.ppi_in_238;
+        self.ppi_239 => gic.ppi_in_239;
+        self.ppi_240 => gic.ppi_in_240;
+        self.ppi_241 => gic.ppi_in_241;
+        self.ppi_242 => gic.ppi_in_242;
+        self.ppi_243 => gic.ppi_in_243;
+        self.ppi_244 => gic.ppi_in_244;
+        self.ppi_245 => gic.ppi_in_245;
+        self.ppi_246 => gic.ppi_in_246;
+        self.ppi_247 => gic.ppi_in_247;
+        self.ppi_248 => gic.ppi_in_248;
+        self.ppi_249 => gic.ppi_in_249;
+        self.ppi_250 => gic.ppi_in_250;
+        self.ppi_251 => gic.ppi_in_251;
+        self.ppi_252 => gic.ppi_in_252;
+        self.ppi_253 => gic.ppi_in_253;
+        self.ppi_254 => gic.ppi_in_254;
+        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
+    {
+        component_type = "System";
+    }
+
+    master port<AMBAPV> amba_m;
+    slave port<AMBAPV> amba_s;
+
+    slave port<AMBAPV> redistributor_s;
+    master port<AMBAPV> redistributor_m;
+
+    #define setPPI(C) \
+          case C: ppi_##C[num].setValue(state); \
+          break
+    slave port<AMBAPVPPICommand> ppi_command
+    {
+        behavior set_state(int export_id, const FastModel::PPICommand &value)
+        {
+            sg::Signal::State state = value.state();
+            uint32_t num = value.num();
+            uint8_t cpu = value.cpu();
+
+            switch (cpu) {
+              setPPI(0); setPPI(1); setPPI(2); setPPI(3); setPPI(4);
+              setPPI(5); setPPI(6); setPPI(7); setPPI(8); setPPI(9);
+              setPPI(10); setPPI(11); setPPI(12); setPPI(13); setPPI(14);
+              setPPI(15); setPPI(16); setPPI(17); setPPI(18); setPPI(19);
+              setPPI(20); setPPI(21); setPPI(22); setPPI(23); setPPI(24);
+              setPPI(25); setPPI(26); setPPI(27); setPPI(28); setPPI(29);
+              setPPI(30); setPPI(31); setPPI(32); setPPI(33); setPPI(34);
+              setPPI(35); setPPI(36); setPPI(37); setPPI(38); setPPI(39);
+              setPPI(40); setPPI(41); setPPI(42); setPPI(43); setPPI(44);
+              setPPI(45); setPPI(46); setPPI(47); setPPI(48); setPPI(49);
+              setPPI(50); setPPI(51); setPPI(52); setPPI(53); setPPI(54);
+              setPPI(55); setPPI(56); setPPI(57); setPPI(58); setPPI(59);
+              setPPI(60); setPPI(61); setPPI(62); setPPI(63); setPPI(64);
+              setPPI(65); setPPI(66); setPPI(67); setPPI(68); setPPI(69);
+              setPPI(70); setPPI(71); setPPI(72); setPPI(73); setPPI(74);
+              setPPI(75); setPPI(76); setPPI(77); setPPI(78); setPPI(79);
+              setPPI(80); setPPI(81); setPPI(82); setPPI(83); setPPI(84);
+              setPPI(85); setPPI(86); setPPI(87); setPPI(88); setPPI(89);
+              setPPI(90); setPPI(91); setPPI(92); setPPI(93); setPPI(94);
+              setPPI(95); setPPI(96); setPPI(97); setPPI(98); setPPI(99);
+              setPPI(100); setPPI(101); setPPI(102); setPPI(103); setPPI(104);
+              setPPI(105); setPPI(106); setPPI(107); setPPI(108); setPPI(109);
+              setPPI(110); setPPI(111); setPPI(112); setPPI(113); setPPI(114);
+              setPPI(115); setPPI(116); setPPI(117); setPPI(118); setPPI(119);
+              setPPI(120); setPPI(121); setPPI(122); setPPI(123); setPPI(124);
+              setPPI(125); setPPI(126); setPPI(127); setPPI(128); setPPI(129);
+              setPPI(130); setPPI(131); setPPI(132); setPPI(133); setPPI(134);
+              setPPI(135); setPPI(136); setPPI(137); setPPI(138); setPPI(139);
+              setPPI(140); setPPI(141); setPPI(142); setPPI(143); setPPI(144);
+              setPPI(145); setPPI(146); setPPI(147); setPPI(148); setPPI(149);
+              setPPI(150); setPPI(151); setPPI(152); setPPI(153); setPPI(154);
+              setPPI(155); setPPI(156); setPPI(157); setPPI(158); setPPI(159);
+              setPPI(160); setPPI(161); setPPI(162); setPPI(163); setPPI(164);
+              setPPI(165); setPPI(166); setPPI(167); setPPI(168); setPPI(169);
+              setPPI(170); setPPI(171); setPPI(172); setPPI(173); setPPI(174);
+              setPPI(175); setPPI(176); setPPI(177); setPPI(178); setPPI(179);
+              setPPI(180); setPPI(181); setPPI(182); setPPI(183); setPPI(184);
+              setPPI(185); setPPI(186); setPPI(187); setPPI(188); setPPI(189);
+              setPPI(190); setPPI(191); setPPI(192); setPPI(193); setPPI(194);
+              setPPI(195); setPPI(196); setPPI(197); setPPI(198); setPPI(199);
+              setPPI(200); setPPI(201); setPPI(202); setPPI(203); setPPI(204);
+              setPPI(205); setPPI(206); setPPI(207); setPPI(208); setPPI(209);
+              setPPI(210); setPPI(211); setPPI(212); setPPI(213); setPPI(214);
+              setPPI(215); setPPI(216); setPPI(217); setPPI(218); setPPI(219);
+              setPPI(220); setPPI(221); setPPI(222); setPPI(223); setPPI(224);
+              setPPI(225); setPPI(226); setPPI(227); setPPI(228); setPPI(229);
+              setPPI(230); setPPI(231); setPPI(232); setPPI(233); setPPI(234);
+              setPPI(235); setPPI(236); setPPI(237); setPPI(238); setPPI(239);
+              setPPI(240); setPPI(241); setPPI(242); setPPI(243); setPPI(244);
+              setPPI(245); setPPI(246); setPPI(247); setPPI(248); setPPI(249);
+              setPPI(250); setPPI(251); setPPI(252); setPPI(253); setPPI(254);
+              setPPI(255);
+              default:
+                sc_assert(false);
+            }
+        }
+    }
+    // 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;
+
+    slave port<AMBAPVSPICommand> spi_command
+    {
+        behavior set_state(int export_id, const FastModel::SPICommand &value)
+        {
+            spi[value.num()].setValue(value.state());
+        }
+    }
+
+    internal slave port<Signal> spi[988];
+
+    internal slave port<Signal> ppi_0[16];
+    internal slave port<Signal> ppi_1[16];
+    internal slave port<Signal> ppi_2[16];
+    internal slave port<Signal> ppi_3[16];
+    internal slave port<Signal> ppi_4[16];
+    internal slave port<Signal> ppi_5[16];
+    internal slave port<Signal> ppi_6[16];
+    internal slave port<Signal> ppi_7[16];
+    internal slave port<Signal> ppi_8[16];
+    internal slave port<Signal> ppi_9[16];
+    internal slave port<Signal> ppi_10[16];
+    internal slave port<Signal> ppi_11[16];
+    internal slave port<Signal> ppi_12[16];
+    internal slave port<Signal> ppi_13[16];
+    internal slave port<Signal> ppi_14[16];
+    internal slave port<Signal> ppi_15[16];
+    internal slave port<Signal> ppi_16[16];
+    internal slave port<Signal> ppi_17[16];
+    internal slave port<Signal> ppi_18[16];
+    internal slave port<Signal> ppi_19[16];
+    internal slave port<Signal> ppi_20[16];
+    internal slave port<Signal> ppi_21[16];
+    internal slave port<Signal> ppi_22[16];
+    internal slave port<Signal> ppi_23[16];
+    internal slave port<Signal> ppi_24[16];
+    internal slave port<Signal> ppi_25[16];
+    internal slave port<Signal> ppi_26[16];
+    internal slave port<Signal> ppi_27[16];
+    internal slave port<Signal> ppi_28[16];
+    internal slave port<Signal> ppi_29[16];
+    internal slave port<Signal> ppi_30[16];
+    internal slave port<Signal> ppi_31[16];
+    internal slave port<Signal> ppi_32[16];
+    internal slave port<Signal> ppi_33[16];
+    internal slave port<Signal> ppi_34[16];
+    internal slave port<Signal> ppi_35[16];
+    internal slave port<Signal> ppi_36[16];
+    internal slave port<Signal> ppi_37[16];
+    internal slave port<Signal> ppi_38[16];
+    internal slave port<Signal> ppi_39[16];
+    internal slave port<Signal> ppi_40[16];
+    internal slave port<Signal> ppi_41[16];
+    internal slave port<Signal> ppi_42[16];
+    internal slave port<Signal> ppi_43[16];
+    internal slave port<Signal> ppi_44[16];
+    internal slave port<Signal> ppi_45[16];
+    internal slave port<Signal> ppi_46[16];
+    internal slave port<Signal> ppi_47[16];
+    internal slave port<Signal> ppi_48[16];
+    internal slave port<Signal> ppi_49[16];
+    internal slave port<Signal> ppi_50[16];
+    internal slave port<Signal> ppi_51[16];
+    internal slave port<Signal> ppi_52[16];
+    internal slave port<Signal> ppi_53[16];
+    internal slave port<Signal> ppi_54[16];
+    internal slave port<Signal> ppi_55[16];
+    internal slave port<Signal> ppi_56[16];
+    internal slave port<Signal> ppi_57[16];
+    internal slave port<Signal> ppi_58[16];
+    internal slave port<Signal> ppi_59[16];
+    internal slave port<Signal> ppi_60[16];
+    internal slave port<Signal> ppi_61[16];
+    internal slave port<Signal> ppi_62[16];
+    internal slave port<Signal> ppi_63[16];
+    internal slave port<Signal> ppi_64[16];
+    internal slave port<Signal> ppi_65[16];
+    internal slave port<Signal> ppi_66[16];
+    internal slave port<Signal> ppi_67[16];
+    internal slave port<Signal> ppi_68[16];
+    internal slave port<Signal> ppi_69[16];
+    internal slave port<Signal> ppi_70[16];
+    internal slave port<Signal> ppi_71[16];
+    internal slave port<Signal> ppi_72[16];
+    internal slave port<Signal> ppi_73[16];
+    internal slave port<Signal> ppi_74[16];
+    internal slave port<Signal> ppi_75[16];
+    internal slave port<Signal> ppi_76[16];
+    internal slave port<Signal> ppi_77[16];
+    internal slave port<Signal> ppi_78[16];
+    internal slave port<Signal> ppi_79[16];
+    internal slave port<Signal> ppi_80[16];
+    internal slave port<Signal> ppi_81[16];
+    internal slave port<Signal> ppi_82[16];
+    internal slave port<Signal> ppi_83[16];
+    internal slave port<Signal> ppi_84[16];
+    internal slave port<Signal> ppi_85[16];
+    internal slave port<Signal> ppi_86[16];
+    internal slave port<Signal> ppi_87[16];
+    internal slave port<Signal> ppi_88[16];
+    internal slave port<Signal> ppi_89[16];
+    internal slave port<Signal> ppi_90[16];
+    internal slave port<Signal> ppi_91[16];
+    internal slave port<Signal> ppi_92[16];
+    internal slave port<Signal> ppi_93[16];
+    internal slave port<Signal> ppi_94[16];
+    internal slave port<Signal> ppi_95[16];
+    internal slave port<Signal> ppi_96[16];
+    internal slave port<Signal> ppi_97[16];
+    internal slave port<Signal> ppi_98[16];
+    internal slave port<Signal> ppi_99[16];
+    internal slave port<Signal> ppi_100[16];
+    internal slave port<Signal> ppi_101[16];
+    internal slave port<Signal> ppi_102[16];
+    internal slave port<Signal> ppi_103[16];
+    internal slave port<Signal> ppi_104[16];
+    internal slave port<Signal> ppi_105[16];
+    internal slave port<Signal> ppi_106[16];
+    internal slave port<Signal> ppi_107[16];
+    internal slave port<Signal> ppi_108[16];
+    internal slave port<Signal> ppi_109[16];
+    internal slave port<Signal> ppi_110[16];
+    internal slave port<Signal> ppi_111[16];
+    internal slave port<Signal> ppi_112[16];
+    internal slave port<Signal> ppi_113[16];
+    internal slave port<Signal> ppi_114[16];
+    internal slave port<Signal> ppi_115[16];
+    internal slave port<Signal> ppi_116[16];
+    internal slave port<Signal> ppi_117[16];
+    internal slave port<Signal> ppi_118[16];
+    internal slave port<Signal> ppi_119[16];
+    internal slave port<Signal> ppi_120[16];
+    internal slave port<Signal> ppi_121[16];
+    internal slave port<Signal> ppi_122[16];
+    internal slave port<Signal> ppi_123[16];
+    internal slave port<Signal> ppi_124[16];
+    internal slave port<Signal> ppi_125[16];
+    internal slave port<Signal> ppi_126[16];
+    internal slave port<Signal> ppi_127[16];
+    internal slave port<Signal> ppi_128[16];
+    internal slave port<Signal> ppi_129[16];
+    internal slave port<Signal> ppi_130[16];
+    internal slave port<Signal> ppi_131[16];
+    internal slave port<Signal> ppi_132[16];
+    internal slave port<Signal> ppi_133[16];
+    internal slave port<Signal> ppi_134[16];
+    internal slave port<Signal> ppi_135[16];
+    internal slave port<Signal> ppi_136[16];
+    internal slave port<Signal> ppi_137[16];
+    internal slave port<Signal> ppi_138[16];
+    internal slave port<Signal> ppi_139[16];
+    internal slave port<Signal> ppi_140[16];
+    internal slave port<Signal> ppi_141[16];
+    internal slave port<Signal> ppi_142[16];
+    internal slave port<Signal> ppi_143[16];
+    internal slave port<Signal> ppi_144[16];
+    internal slave port<Signal> ppi_145[16];
+    internal slave port<Signal> ppi_146[16];
+    internal slave port<Signal> ppi_147[16];
+    internal slave port<Signal> ppi_148[16];
+    internal slave port<Signal> ppi_149[16];
+    internal slave port<Signal> ppi_150[16];
+    internal slave port<Signal> ppi_151[16];
+    internal slave port<Signal> ppi_152[16];
+    internal slave port<Signal> ppi_153[16];
+    internal slave port<Signal> ppi_154[16];
+    internal slave port<Signal> ppi_155[16];
+    internal slave port<Signal> ppi_156[16];
+    internal slave port<Signal> ppi_157[16];
+    internal slave port<Signal> ppi_158[16];
+    internal slave port<Signal> ppi_159[16];
+    internal slave port<Signal> ppi_160[16];
+    internal slave port<Signal> ppi_161[16];
+    internal slave port<Signal> ppi_162[16];
+    internal slave port<Signal> ppi_163[16];
+    internal slave port<Signal> ppi_164[16];
+    internal slave port<Signal> ppi_165[16];
+    internal slave port<Signal> ppi_166[16];
+    internal slave port<Signal> ppi_167[16];
+    internal slave port<Signal> ppi_168[16];
+    internal slave port<Signal> ppi_169[16];
+    internal slave port<Signal> ppi_170[16];
+    internal slave port<Signal> ppi_171[16];
+    internal slave port<Signal> ppi_172[16];
+    internal slave port<Signal> ppi_173[16];
+    internal slave port<Signal> ppi_174[16];
+    internal slave port<Signal> ppi_175[16];
+    internal slave port<Signal> ppi_176[16];
+    internal slave port<Signal> ppi_177[16];
+    internal slave port<Signal> ppi_178[16];
+    internal slave port<Signal> ppi_179[16];
+    internal slave port<Signal> ppi_180[16];
+    internal slave port<Signal> ppi_181[16];
+    internal slave port<Signal> ppi_182[16];
+    internal slave port<Signal> ppi_183[16];
+    internal slave port<Signal> ppi_184[16];
+    internal slave port<Signal> ppi_185[16];
+    internal slave port<Signal> ppi_186[16];
+    internal slave port<Signal> ppi_187[16];
+    internal slave port<Signal> ppi_188[16];
+    internal slave port<Signal> ppi_189[16];
+    internal slave port<Signal> ppi_190[16];
+    internal slave port<Signal> ppi_191[16];
+    internal slave port<Signal> ppi_192[16];
+    internal slave port<Signal> ppi_193[16];
+    internal slave port<Signal> ppi_194[16];
+    internal slave port<Signal> ppi_195[16];
+    internal slave port<Signal> ppi_196[16];
+    internal slave port<Signal> ppi_197[16];
+    internal slave port<Signal> ppi_198[16];
+    internal slave port<Signal> ppi_199[16];
+    internal slave port<Signal> ppi_200[16];
+    internal slave port<Signal> ppi_201[16];
+    internal slave port<Signal> ppi_202[16];
+    internal slave port<Signal> ppi_203[16];
+    internal slave port<Signal> ppi_204[16];
+    internal slave port<Signal> ppi_205[16];
+    internal slave port<Signal> ppi_206[16];
+    internal slave port<Signal> ppi_207[16];
+    internal slave port<Signal> ppi_208[16];
+    internal slave port<Signal> ppi_209[16];
+    internal slave port<Signal> ppi_210[16];
+    internal slave port<Signal> ppi_211[16];
+    internal slave port<Signal> ppi_212[16];
+    internal slave port<Signal> ppi_213[16];
+    internal slave port<Signal> ppi_214[16];
+    internal slave port<Signal> ppi_215[16];
+    internal slave port<Signal> ppi_216[16];
+    internal slave port<Signal> ppi_217[16];
+    internal slave port<Signal> ppi_218[16];
+    internal slave port<Signal> ppi_219[16];
+    internal slave port<Signal> ppi_220[16];
+    internal slave port<Signal> ppi_221[16];
+    internal slave port<Signal> ppi_222[16];
+    internal slave port<Signal> ppi_223[16];
+    internal slave port<Signal> ppi_224[16];
+    internal slave port<Signal> ppi_225[16];
+    internal slave port<Signal> ppi_226[16];
+    internal slave port<Signal> ppi_227[16];
+    internal slave port<Signal> ppi_228[16];
+    internal slave port<Signal> ppi_229[16];
+    internal slave port<Signal> ppi_230[16];
+    internal slave port<Signal> ppi_231[16];
+    internal slave port<Signal> ppi_232[16];
+    internal slave port<Signal> ppi_233[16];
+    internal slave port<Signal> ppi_234[16];
+    internal slave port<Signal> ppi_235[16];
+    internal slave port<Signal> ppi_236[16];
+    internal slave port<Signal> ppi_237[16];
+    internal slave port<Signal> ppi_238[16];
+    internal slave port<Signal> ppi_239[16];
+    internal slave port<Signal> ppi_240[16];
+    internal slave port<Signal> ppi_241[16];
+    internal slave port<Signal> ppi_242[16];
+    internal slave port<Signal> ppi_243[16];
+    internal slave port<Signal> ppi_244[16];
+    internal slave port<Signal> ppi_245[16];
+    internal slave port<Signal> ppi_246[16];
+    internal slave port<Signal> ppi_247[16];
+    internal slave port<Signal> ppi_248[16];
+    internal slave port<Signal> ppi_249[16];
+    internal slave port<Signal> ppi_250[16];
+    internal slave port<Signal> ppi_251[16];
+    internal slave port<Signal> ppi_252[16];
+    internal slave port<Signal> ppi_253[16];
+    internal slave port<Signal> ppi_254[16];
+    internal slave port<Signal> ppi_255[16];
+}
diff --git a/src/arch/arm/fastmodel/GIC/GIC.sgproj b/src/arch/arm/fastmodel/GIC/GIC.sgproj
new file mode 100644
index 0000000..2213bff
--- /dev/null
+++ b/src/arch/arm/fastmodel/GIC/GIC.sgproj
@@ -0,0 +1,25 @@
+sgproject "GIC.sgproj"
+{
+TOP_LEVEL_COMPONENT = "GIC";
+ACTIVE_CONFIG_LINUX  = "gcc";
+ACTIVE_CONFIG_WINDOWS  = "Win64-Release-VC2015";
+config "gcc"
+{
+    ADDITIONAL_COMPILER_SETTINGS = "-O3 -Wall -std=c++11 -Wno-deprecated -Wno-unused-function -I../../../../../";
+    ADDITIONAL_LINKER_SETTINGS = "-Wl,--no-undefined";
+    BUILD_DIR = "./gcc";
+    COMPILER = "gcc-6.4";
+    CONFIG_DESCRIPTION = "";
+    CONFIG_NAME = "gcc";
+    PLATFORM = "Linux64";
+    PREPROCESSOR_DEFINES = "NDEBUG";
+    SIMGEN_COMMAND_LINE = "--num-comps-file 50";
+    TARGET_MAXVIEW = "0";
+    TARGET_SYSTEMC = "1";
+}
+files
+{
+    path = "GIC.lisa";
+    path = "${PVLIB_HOME}/etc/sglib.sgrepo";
+}
+}
diff --git a/src/arch/arm/fastmodel/GIC/SConscript b/src/arch/arm/fastmodel/GIC/SConscript
new file mode 100644
index 0000000..c52304d
--- /dev/null
+++ b/src/arch/arm/fastmodel/GIC/SConscript
@@ -0,0 +1,36 @@
+# Copyright 2019 Google, Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Gabe Black
+
+Import('*')
+
+if not env['USE_ARM_FASTMODEL'] or env['TARGET_ISA'] != 'arm':
+    Return()
+
+ArmFastModelComponent(File('GIC.sgproj'), File('commands.hh'),
+                      File('GIC.lisa')).prepare_env(env)
+SimObject('FastModelGIC.py')
+Source('gic.cc')
diff --git a/src/arch/arm/fastmodel/GIC/commands.hh b/src/arch/arm/fastmodel/GIC/commands.hh
new file mode 100644
index 0000000..70f69c8
--- /dev/null
+++ b/src/arch/arm/fastmodel/GIC/commands.hh
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#ifndef __ARCH_ARM_FASTMODEL_GIC_COMMANDS_HH__
+#define __ARCH_ARM_FASTMODEL_GIC_COMMANDS_HH__
+
+#include <cstdint>
+
+#include "base/logging.hh"
+#include "sg/SGSignal.h"
+
+namespace FastModel
+{
+
+class PPICommand
+{
+  private:
+    uint8_t _cpu;
+    uint32_t _num;
+    sg::Signal::State _state;
+
+  public:
+    PPICommand(uint8_t c, uint32_t n, bool set) :
+        _cpu(c), _num(n), _state(set ? sg::Signal::Set : sg::Signal::Clear)
+    {
+        panic_if(_cpu > 255, "PPICommand CPU out of bounds");
+        panic_if(_num > 15, "PPICommand number out of bounds");
+    }
+
+    PPICommand() : PPICommand(0, 0, false) {}
+
+    uint8_t cpu() const { return _cpu; }
+    uint32_t num() const { return _num; }
+    sg::Signal::State state() const { return _state; }
+};
+
+class SPICommand
+{
+  private:
+    uint32_t _num;
+    sg::Signal::State _state;
+
+  public:
+    SPICommand(uint32_t n, bool set) :
+        _num(n), _state(set ? sg::Signal::Set : sg::Signal::Clear)
+    {
+        panic_if(_num > 987, "SPICommand number out of bounds");
+    }
+
+    SPICommand() : SPICommand(0, false) {}
+
+    uint32_t num() const { return _num; }
+    sg::Signal::State state() const { return _state; }
+};
+
+} // namespace FastModel
+
+#endif // __ARCH_ARM_FASTMODEL_GIC_COMMANDS_HH__
diff --git a/src/arch/arm/fastmodel/GIC/gic.cc b/src/arch/arm/fastmodel/GIC/gic.cc
new file mode 100644
index 0000000..2041e41
--- /dev/null
+++ b/src/arch/arm/fastmodel/GIC/gic.cc
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#include "arch/arm/fastmodel/GIC/gic.hh"
+
+#include "base/trace.hh"
+#include "params/FastModelGIC.hh"
+#include "params/SCFastModelGIC.hh"
+
+namespace FastModel
+{
+
+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)
+{
+    ppiCommand.bind(ppi_command);
+    spiCommand.bind(spi_command);
+
+    set_parameter("gic.enabled", params.enabled);
+    set_parameter("gic.has-gicv3", params.has_gicv3);
+    set_parameter("gic.has-gicv4.1", params.has_gicv4_1);
+    set_parameter("gic.vPEID-bits", params.vPEID_bits);
+    set_parameter("gic.print-memory-map", params.print_mmap);
+    set_parameter("gic.monolithic", params.monolithic);
+    set_parameter("gic.direct-lpi-support", params.direct_lpi_support);
+    set_parameter("gic.CPU-affinities", params.cpu_affinities);
+    set_parameter("gic.non-ARE-core-count", params.non_ARE_core_count);
+    set_parameter("gic.reg-base", params.reg_base);
+    set_parameter("gic.reg-base-per-redistributor",
+                  params.reg_base_per_redistributor);
+    set_parameter("gic.GICD-alias", params.gicd_alias);
+    set_parameter("gic.has-two-security-states",
+                  params.has_two_security_states);
+    set_parameter("gic.DS-fixed-to-zero", params.DS_fixed_to_zero);
+    set_parameter("gic.IIDR", params.IIDR);
+    set_parameter("gic.gicv2-only", params.gicv2_only);
+    set_parameter("gic.STATUSR-implemented", params.STATUSR_implemented);
+    set_parameter("gic.priority-bits",
+                  params.priority_bits_implemented);
+    set_parameter("gic.GICD_ITARGETSR-RAZWI", params.itargets_razwi);
+    set_parameter("gic.ICFGR-SGI-mask", params.icfgr_sgi_mask);
+    set_parameter("gic.ICFGR-PPI-mask", params.icfgr_ppi_mask);
+    set_parameter("gic.ICFGR-SPI-mask", params.icfgr_spi_mask);
+    set_parameter("gic.ICFGR-SGI-reset", params.icfgr_sgi_reset);
+    set_parameter("gic.ICFGR-PPI-reset", params.icfgr_ppi_reset);
+    set_parameter("gic.ICFGR-SPI-reset", params.icfgr_spi_reset);
+    set_parameter("gic.ICFGR-rsvd-bit", params.icfgr_ppi_rsvd_bit);
+    set_parameter("gic.IGROUP-SGI-mask", params.igroup_sgi_mask);
+    set_parameter("gic.IGROUP-PPI-mask", params.igroup_ppi_mask);
+    set_parameter("gic.IGROUP-SGI-reset", params.igroup_sgi_reset);
+    set_parameter("gic.IGROUP-PPI-reset", params.igroup_ppi_reset);
+    set_parameter("gic.PPI-implemented-mask", params.ppi_implemented_mask);
+    set_parameter("gic.SPI-count", params.spi_count);
+    set_parameter("gic.lockable-SPI-count", params.lockable_spi_count);
+    set_parameter("gic.IRI-ID-bits", params.iri_id_bits);
+    set_parameter("gic.delay-redistributor-accesses",
+                  params.delay_redistributor_accesses);
+    set_parameter("gic.GICD_PIDR", params.gicd_pidr);
+    set_parameter("gic.GICR_PIDR", params.gicr_pidr);
+    set_parameter("gic.ITS-count", params.its_count);
+    set_parameter("gic.ITS0-base", params.its0_base);
+    set_parameter("gic.ITS1-base", params.its1_base);
+    set_parameter("gic.ITS2-base", params.its2_base);
+    set_parameter("gic.ITS3-base", params.its3_base);
+    set_parameter("gic.GITS_PIDR", params.gits_pidr);
+    set_parameter("gic.GITS_BASER0-type", params.gits_baser0_type);
+    set_parameter("gic.GITS_BASER1-type", params.gits_baser1_type);
+    set_parameter("gic.GITS_BASER2-type", params.gits_baser2_type);
+    set_parameter("gic.GITS_BASER3-type", params.gits_baser3_type);
+    set_parameter("gic.GITS_BASER4-type", params.gits_baser4_type);
+    set_parameter("gic.GITS_BASER5-type", params.gits_baser5_type);
+    set_parameter("gic.GITS_BASER6-type", params.gits_baser6_type);
+    set_parameter("gic.GITS_BASER7-type", params.gits_baser7_type);
+    set_parameter("gic.GITS_BASER0-entry-bytes",
+                  params.gits_baser0_entry_bytes);
+    set_parameter("gic.GITS_BASER1-entry-bytes",
+                  params.gits_baser1_entry_bytes);
+    set_parameter("gic.GITS_BASER2-entry-bytes",
+                  params.gits_baser2_entry_bytes);
+    set_parameter("gic.GITS_BASER3-entry-bytes",
+                  params.gits_baser3_entry_bytes);
+    set_parameter("gic.GITS_BASER4-entry-bytes",
+                  params.gits_baser4_entry_bytes);
+    set_parameter("gic.GITS_BASER5-entry-bytes",
+                  params.gits_baser5_entry_bytes);
+    set_parameter("gic.GITS_BASER6-entry-bytes",
+                  params.gits_baser6_entry_bytes);
+    set_parameter("gic.GITS_BASER7-entry-bytes",
+                  params.gits_baser7_entry_bytes);
+    set_parameter("gic.GITS_BASER0-indirect-RAZ",
+                  params.gits_baser0_indirect_raz);
+    set_parameter("gic.GITS_BASER1-indirect-RAZ",
+                  params.gits_baser1_indirect_raz);
+    set_parameter("gic.GITS_BASER2-indirect-RAZ",
+                  params.gits_baser2_indirect_raz);
+    set_parameter("gic.GITS_BASER3-indirect-RAZ",
+                  params.gits_baser3_indirect_raz);
+    set_parameter("gic.GITS_BASER4-indirect-RAZ",
+                  params.gits_baser4_indirect_raz);
+    set_parameter("gic.GITS_BASER5-indirect-RAZ",
+                  params.gits_baser5_indirect_raz);
+    set_parameter("gic.GITS_BASER6-indirect-RAZ",
+                  params.gits_baser6_indirect_raz);
+    set_parameter("gic.GITS_BASER7-indirect-RAZ",
+                  params.gits_baser7_indirect_raz);
+    set_parameter("gic.ITS-BASER-force-page-alignement",
+                  params.its_baser_force_page_alignement);
+    set_parameter("gic.processor-numbers", params.processor_numbers);
+    set_parameter("gic.supports-shareability", params.supports_shareability);
+    set_parameter("gic.A3-affinity-supported", params.a3_affinity_supported);
+    set_parameter("gic.sgi-range-selector-support", params.SGI_RSS_support);
+    set_parameter("gic.GICR_PROPBASER-read-only",
+                  params.gicr_propbaser_read_only);
+    set_parameter("gic.GICR_PROPBASER-reset-value",
+                  params.gicr_propbaser_reset);
+    set_parameter("gic.ITS-device-bits", params.its_device_bits);
+    set_parameter("gic.ITS-entry-size", params.its_entry_size);
+    set_parameter("gic.ITS-ID-bits", params.its_id_bits);
+    set_parameter("gic.ITS-collection-ID-bits", params.its_collection_id_bits);
+    set_parameter("gic.ITS-cumulative-collection-tables",
+                  params.its_cumulative_collection_tables);
+    set_parameter("gic.delay-ITS-accesses", params.delay_ITS_accesses);
+    set_parameter("gic.local-SEIs", params.local_SEIs);
+    set_parameter("gic.local-VSEIs", params.local_VSEIs);
+    set_parameter("gic.ITS-use-physical-target-addresses",
+                  params.ITS_use_physical_target_addresses);
+    set_parameter("gic.ITS-hardware-collection-count",
+                  params.ITS_hardware_collection_count);
+    set_parameter("gic.ITS-MOVALL-update-collections",
+                  params.ITS_MOVALL_update_collections);
+    set_parameter("gic.ITS-TRANSLATE64R", params.ITS_TRANSLATE64R);
+    set_parameter("gic.enable_protocol_checking",
+                  params.enable_protocol_checking);
+    set_parameter("gic.fixed-routed-spis", params.fixed_routed_spis);
+    set_parameter("gic.irouter-default-mask", params.irouter_default_mask);
+    if (params.irouter_default_reset != "") {
+        set_parameter("gic.irouter-default-reset",
+                      params.irouter_default_reset);
+    }
+    if (params.irouter_reset_values != "")
+        set_parameter("gic.irouter-reset-values", params.irouter_reset_values);
+    set_parameter("gic.irouter-mask-values", params.irouter_mask_values);
+    set_parameter("gic.ITS-threaded-command-queue",
+                  params.ITS_threaded_command_queue);
+    set_parameter("gic.ITS-legacy-iidr-typer-offset",
+                  params.ITS_legacy_iidr_typer_offset);
+    set_parameter("gic.redistributor-threaded-sync",
+                  params.redistributor_threaded_command_queue);
+    set_parameter("gic.ignore-generate-sgi-when-no-are",
+                  params.ignore_generate_sgi_when_no_are);
+    set_parameter("gic.trace-speculative-lpi-property-update",
+                  params.trace_speculative_lpi_property_updates);
+    set_parameter("gic.virtual-lpi-support", params.virtual_lpi_support);
+    set_parameter("gic.virtual-priority-bits", params.virtual_priority_bits);
+    set_parameter("gic.LPI-cache-type", params.LPI_cache_type);
+    set_parameter("gic.LPI-cache-check-data", params.LPI_cache_check_data);
+    set_parameter("gic.DPG-bits-implemented", params.DPG_bits_implemented);
+    set_parameter("gic.DPG-ARE-only", params.DPG_ARE_only);
+    set_parameter("gic.ARE-fixed-to-one", params.ARE_fixed_to_one);
+    set_parameter("gic.legacy-sgi-enable-rao", params.legacy_sgi_enable_rao);
+    set_parameter("gic.PA_SIZE", params.pa_size);
+    set_parameter("gic.MSI_IIDR", params.MSI_IIDR);
+    set_parameter("gic.MSI_NS-frame0-base", params.MSI_NS_frame0_base);
+    set_parameter("gic.MSI_NS-frame0-max-SPI", params.MSI_NS_frame0_max_SPI);
+    set_parameter("gic.MSI_NS-frame0-min-SPI", params.MSI_NS_frame0_min_SPI);
+    set_parameter("gic.MSI_NS-frame1-base", params.MSI_NS_frame1_base);
+    set_parameter("gic.MSI_NS-frame1-max-SPI", params.MSI_NS_frame1_max_SPI);
+    set_parameter("gic.MSI_NS-frame1-min-SPI", params.MSI_NS_frame1_min_SPI);
+    set_parameter("gic.MSI_NS-frame2-base", params.MSI_NS_frame2_base);
+    set_parameter("gic.MSI_NS-frame2-max-SPI", params.MSI_NS_frame2_max_SPI);
+    set_parameter("gic.MSI_NS-frame2-min-SPI", params.MSI_NS_frame2_min_SPI);
+    set_parameter("gic.MSI_NS-frame3-base", params.MSI_NS_frame3_base);
+    set_parameter("gic.MSI_NS-frame3-max-SPI", params.MSI_NS_frame3_max_SPI);
+    set_parameter("gic.MSI_NS-frame3-min-SPI", params.MSI_NS_frame3_min_SPI);
+    set_parameter("gic.MSI_NS-frame4-base", params.MSI_NS_frame4_base);
+    set_parameter("gic.MSI_NS-frame4-max-SPI", params.MSI_NS_frame4_max_SPI);
+    set_parameter("gic.MSI_NS-frame4-min-SPI", params.MSI_NS_frame4_min_SPI);
+    set_parameter("gic.MSI_NS-frame5-base", params.MSI_NS_frame5_base);
+    set_parameter("gic.MSI_NS-frame5-max-SPI", params.MSI_NS_frame5_max_SPI);
+    set_parameter("gic.MSI_NS-frame5-min-SPI", params.MSI_NS_frame5_min_SPI);
+    set_parameter("gic.MSI_NS-frame6-base", params.MSI_NS_frame6_base);
+    set_parameter("gic.MSI_NS-frame6-max-SPI", params.MSI_NS_frame6_max_SPI);
+    set_parameter("gic.MSI_NS-frame6-min-SPI", params.MSI_NS_frame6_min_SPI);
+    set_parameter("gic.MSI_NS-frame7-base", params.MSI_NS_frame7_base);
+    set_parameter("gic.MSI_NS-frame7-max-SPI", params.MSI_NS_frame7_max_SPI);
+    set_parameter("gic.MSI_NS-frame7-min-SPI", params.MSI_NS_frame7_min_SPI);
+    set_parameter("gic.MSI_PIDR", params.MSI_PIDR);
+    set_parameter("gic.MSI_S-frame0-base", params.MSI_S_frame0_base);
+    set_parameter("gic.MSI_S-frame0-max-SPI", params.MSI_S_frame0_max_SPI);
+    set_parameter("gic.MSI_S-frame0-min-SPI", params.MSI_S_frame0_min_SPI);
+    set_parameter("gic.MSI_S-frame1-base", params.MSI_S_frame1_base);
+    set_parameter("gic.MSI_S-frame1-max-SPI", params.MSI_S_frame1_max_SPI);
+    set_parameter("gic.MSI_S-frame1-min-SPI", params.MSI_S_frame1_min_SPI);
+    set_parameter("gic.MSI_S-frame2-base", params.MSI_S_frame2_base);
+    set_parameter("gic.MSI_S-frame2-max-SPI", params.MSI_S_frame2_max_SPI);
+    set_parameter("gic.MSI_S-frame2-min-SPI", params.MSI_S_frame2_min_SPI);
+    set_parameter("gic.MSI_S-frame3-base", params.MSI_S_frame3_base);
+    set_parameter("gic.MSI_S-frame3-max-SPI", params.MSI_S_frame3_max_SPI);
+    set_parameter("gic.MSI_S-frame3-min-SPI", params.MSI_S_frame3_min_SPI);
+    set_parameter("gic.MSI_S-frame4-base", params.MSI_S_frame4_base);
+    set_parameter("gic.MSI_S-frame4-max-SPI", params.MSI_S_frame4_max_SPI);
+    set_parameter("gic.MSI_S-frame4-min-SPI", params.MSI_S_frame4_min_SPI);
+    set_parameter("gic.MSI_S-frame5-base", params.MSI_S_frame5_base);
+    set_parameter("gic.MSI_S-frame5-max-SPI", params.MSI_S_frame5_max_SPI);
+    set_parameter("gic.MSI_S-frame5-min-SPI", params.MSI_S_frame5_min_SPI);
+    set_parameter("gic.MSI_S-frame6-base", params.MSI_S_frame6_base);
+    set_parameter("gic.MSI_S-frame6-max-SPI", params.MSI_S_frame6_max_SPI);
+    set_parameter("gic.MSI_S-frame6-min-SPI", params.MSI_S_frame6_min_SPI);
+    set_parameter("gic.MSI_S-frame7-base", params.MSI_S_frame7_base);
+    set_parameter("gic.MSI_S-frame7-max-SPI", params.MSI_S_frame7_max_SPI);
+    set_parameter("gic.MSI_S-frame7-min-SPI", params.MSI_S_frame7_min_SPI);
+    set_parameter("gic.outer-cacheability-support",
+                  params.outer_cacheability_support);
+    set_parameter("gic.wakeup-on-reset", params.wakeup_on_reset);
+    set_parameter("gic.SPI-message-based-support", params.SPI_MBIS);
+    set_parameter("gic.SPI-unimplemented", params.SPI_unimplemented);
+    set_parameter("gic.IROUTER-IRM-RAZ-WI", params.irm_razwi);
+    set_parameter("gic.common-lpi-configuration",
+                  params.common_LPI_configuration);
+    set_parameter("gic.single-set-support", params.single_set_support);
+    set_parameter("gic.has_mpam", params.has_mpam);
+    set_parameter("gic.mpam_partid_max", params.mpam_max_partid);
+    set_parameter("gic.mpam_pmg_max", params.mpam_max_pmg);
+    set_parameter("gic.output_attributes", params.output_attributes);
+    set_parameter("gic.has_VPENDBASER-dirty-flag-on-load",
+                  params.has_DirtyVLPIOnLoad);
+    set_parameter("gic.allow-LPIEN-clear", params.allow_LPIEN_clear);
+    set_parameter("gic.GICD-legacy-registers-as-reserved",
+                  params.GICD_legacy_reg_reserved);
+    set_parameter("gic.extended-spi-count", params.extended_spi_count);
+    set_parameter("gic.extended-ppi-count", params.extended_ppi_count);
+    set_parameter("gic.consolidators", params.consolidators);
+}
+
+GIC::GIC(const FastModelGICParams &params) :
+    BaseGic(&params),
+    ambaM(params.sc_gic->amba_m, params.name + ".amba_m", -1),
+    ambaS(params.sc_gic->amba_s, params.name + ".amba_s", -1),
+    redistributorM(params.sc_gic->redistributor_m,
+                   params.name + ".redistributor_m", -1),
+    redistributorS(params.sc_gic->redistributor_s,
+                   params.name + ".redistributor_s", -1),
+    scGIC(params.sc_gic)
+{
+}
+
+Port &
+GIC::getPort(const std::string &if_name, PortID idx)
+{
+    if (if_name == "amba_m")
+        return ambaM;
+    else if (if_name == "amba_s")
+        return ambaS;
+    else if (if_name == "redistributor_m")
+        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);
+}
+
+void
+GIC::sendInt(uint32_t num)
+{
+    scGIC->spiCommand.set_state(0, SPICommand(num - 32, true));
+}
+
+void
+GIC::clearInt(uint32_t num)
+{
+    scGIC->spiCommand.set_state(0, SPICommand(num - 32, false));
+}
+
+void
+GIC::sendPPInt(uint32_t num, uint32_t cpu)
+{
+    scGIC->ppiCommand.set_state(0, PPICommand(cpu, num, true));
+}
+
+void
+GIC::clearPPInt(uint32_t num, uint32_t cpu)
+{
+    scGIC->ppiCommand.set_state(0, PPICommand(cpu, num, false));
+}
+
+} // namespace FastModel
+
+FastModel::SCGIC *
+SCFastModelGICParams::create()
+{
+    return new FastModel::SCGIC(*this, name.c_str());
+}
+
+FastModel::GIC *
+FastModelGICParams::create()
+{
+    return new FastModel::GIC(*this);
+}
diff --git a/src/arch/arm/fastmodel/GIC/gic.hh b/src/arch/arm/fastmodel/GIC/gic.hh
new file mode 100644
index 0000000..7910686
--- /dev/null
+++ b/src/arch/arm/fastmodel/GIC/gic.hh
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#ifndef __ARCH_ARM_FASTMODEL_GIC_GIC_HH__
+#define __ARCH_ARM_FASTMODEL_GIC_GIC_HH__
+
+#include "arch/arm/fastmodel/GIC/commands.hh"
+#include "arch/arm/fastmodel/amba_ports.hh"
+#include "dev/arm/base_gic.hh"
+#include "params/FastModelGIC.hh"
+#include "params/SCFastModelGIC.hh"
+#include "scx_evs_GIC.h"
+#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
+{
+
+// The fast model exports a class called scx_evs_GIC which represents
+// the subsystem described in LISA+. This class specializes it to export gem5
+// ports and interface with its peer gem5 GIC. The gem5 GIC inherits from the
+// gem5 BaseGic class and implements its API, while this class actually does
+// the work.
+class SCGIC : public scx_evs_GIC
+{
+  public:
+    SCGIC(const SCFastModelGICParams &params, sc_core::sc_module_name _name);
+
+    amba_pv::signal_master_port<PPICommand> ppiCommand;
+    amba_pv::signal_master_port<SPICommand> spiCommand;
+
+    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
+    {
+        scx_evs_GIC::end_of_elaboration();
+        scx_evs_GIC::start_of_simulation();
+    }
+    void start_of_simulation() override {}
+};
+
+// This class pairs with the one above to implement the receiving end of gem5's
+// GIC API. It acts as an interface which passes work to the fast model GIC,
+// and lets the fast model GIC interact with the rest of the system.
+class GIC : public BaseGic
+{
+  private:
+    AmbaInitiator ambaM;
+    AmbaTarget ambaS;
+    AmbaInitiator redistributorM;
+    AmbaTarget redistributorS;
+
+    SCGIC *scGIC;
+
+  public:
+    GIC(const FastModelGICParams &params);
+
+    Port &getPort(const std::string &if_name,
+                  PortID idx=InvalidPortID) override;
+
+    void sendInt(uint32_t num) override;
+    void clearInt(uint32_t num) override;
+
+    void sendPPInt(uint32_t num, uint32_t cpu) override;
+    void clearPPInt(uint32_t num, uint32_t cpu) override;
+
+    AddrRangeList getAddrRanges() const override { return AddrRangeList(); }
+    Tick read(PacketPtr pkt) override { return 0; }
+    Tick write(PacketPtr pkt) override { return 0; }
+};
+
+} // namespace FastModel
+
+#endif // __ARCH_ARM_FASTMODEL_GIC_GIC_HH__
diff --git a/src/arch/arm/fastmodel/SConscript b/src/arch/arm/fastmodel/SConscript
new file mode 100644
index 0000000..17d931f
--- /dev/null
+++ b/src/arch/arm/fastmodel/SConscript
@@ -0,0 +1,368 @@
+# Copyright 2019 Google, Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Gabe Black
+
+from __future__ import print_function
+
+Import('*')
+
+from m5.util.terminal import termcap
+from m5.util.grammar import Grammar
+
+from gem5_scons import Transform
+
+import os.path
+
+if env['USE_ARM_FASTMODEL']:
+    if not env['USE_SYSTEMC']:
+        print(termcap.Yellow + termcap.Bold +
+                'Warning: ARM Fast Models require systemc support' +
+                termcap.Normal)
+        env['USE_ARM_FASTMODEL'] = False
+        Return()
+
+if not env['USE_ARM_FASTMODEL']:
+    Return()
+
+
+systemc_home = Dir('#/src/systemc/ext/systemc_home')
+env['ENV']['SYSTEMC_HOME'] = systemc_home.abspath
+
+def extract_var(name):
+    if name not in env:
+        print(termcap.Red + termcap.Bold +
+                ('Error: %s is not set' % name) +
+                termcap.Normal)
+        Exit(1)
+    print('%s = %s' % (name, env[name]))
+    # Make sure the value of this variable shows up as an environment variable
+    # for commands scons runs.
+    env['ENV'][name] = env[name]
+    return env[name]
+
+pvlib_home, maxcore_home, armlmd_license_file = \
+    list(map(extract_var, ('PVLIB_HOME', 'MAXCORE_HOME',
+                           'ARMLMD_LICENSE_FILE')))
+
+pvlib_home = Dir(pvlib_home)
+maxcore_home = Dir(maxcore_home)
+armlmd_license_file = File(armlmd_license_file)
+
+
+pvlib_flavor = env['PVLIB_FLAVOR']
+pvlib_lib_dir = pvlib_home.Dir('lib').Dir(pvlib_flavor)
+
+simulation_engine_name = 'libMAXCOREInitSimulationEngine.3.so'
+simulation_engine_lib = pvlib_lib_dir.File(simulation_engine_name)
+
+
+def staticify(env, name):
+    ''' Check for a static version of the library named 'name', and if it
+        exists return a File node for it explicitly. Otherwise pass 'name'
+        through for normal processing.'''
+
+    static_name = env.subst('${LIBPREFIX}' + name + '${LIBSUFFIX}')
+
+    for path in env.Flatten(env['LIBPATH']):
+        full_name = Dir(path).File(static_name).get_abspath()
+        if os.path.isfile(full_name):
+            return File(full_name)
+
+    return name
+
+
+# Adjust the build environment to support building in Fast Models.
+
+env.Append(CCFLAGS='-pthread')
+
+cpppaths = (
+    pvlib_home.Dir('include/fmruntime'),
+    pvlib_home.Dir('include/fmruntime/eslapi'),
+    pvlib_home.Dir('Iris/include'),
+
+    systemc_home.Dir('include'),
+
+    maxcore_home.Dir('AMBA-PV/include'),
+)
+env.Append(CPPPATH=cpppaths)
+
+lib_paths = (
+    pvlib_lib_dir,
+    pvlib_home.Dir('Iris').Dir(pvlib_flavor),
+)
+env.Append(LIBPATH=lib_paths)
+env.Append(RPATH=lib_paths)
+
+libs = (
+    'components',
+    'pvbus',
+    'armctmodel',
+    'fmruntime',
+    'IrisSupport',
+    'dl',
+    'rt',
+)
+env.Append(LIBS=list(staticify(env, lib) for lib in libs))
+
+
+class ProjectFileParser(Grammar):
+    class Param(object):
+        def __init__(self, is_object):
+            self.is_object = is_object
+
+        def __str__(self):
+            return self._to_str(0)
+
+    class StringParam(Param):
+        def __init__(self, name, value):
+            super(ProjectFileParser.StringParam, self).__init__(
+                    is_object=False)
+            self.name = name
+            self.value = value
+
+        def _to_str(self, indent):
+            indent_str = "    " * indent
+            return indent_str + self.name + ' = \"' + self.value + '\"'
+
+    class ObjectParam(Param):
+        def __init__(self, type_name, name, params):
+            super(ProjectFileParser.ObjectParam, self).__init__(
+                    is_object=True)
+            self.type_name = type_name
+            self.name = name
+            self.params = params
+
+        def _to_str(self, indent):
+            indent_str = "    " * indent
+            val = indent_str + self.type_name
+            if self.name is not None:
+                val += ' "' + self.name + '"'
+            val += "\n" + indent_str + "{\n"
+            for param in self.params:
+                val += param._to_str(indent + 1) + "\n"
+            val += indent_str + "}"
+            return val
+
+    #########
+    # Lexer #
+    #########
+
+    tokens = (
+        # identifier
+        'ID',
+
+        # string literal
+        'STRLIT',
+
+        # = { } ;
+        'EQUALS',
+        'LBRACE',
+        'RBRACE',
+        'SEMI',
+    )
+
+    t_ID = r'[A-Za-z_]\w*'
+
+    def t_STRLIT(self, t):
+        r'(?m)"([^"])*"'
+        # strip off quotes
+        t.value = t.value[1:-1]
+        t.lexer.lineno += t.value.count('\n')
+        return t
+
+    t_EQUALS = r'='
+    t_LBRACE = r'\{'
+    t_RBRACE = r'\}'
+    t_SEMI = r';'
+
+    def t_NEWLINE(self, t):
+        r'\n+'
+        t.lexer.lineno += t.value.count('\n')
+
+    t_ignore = ' \t\x0c'
+
+    ##########
+    # Parser #
+    ##########
+
+    def p_object(self, t):
+        'object : object_heading LBRACE params RBRACE'
+        t[0] = self.ObjectParam(t[1][0], t[1][1], t[3])
+
+    def p_object_heading_0(self, t):
+        'object_heading : ID STRLIT'
+        t[0] = (t[1], t[2])
+
+    def p_object_heading_1(self, t):
+        'object_heading : ID'
+        t[0] = (t[1], None)
+
+    def p_params_0(self, t):
+        'params : '
+        t[0] = []
+
+    def p_params_1(self, t):
+        'params : param params'
+        t[0] = [t[1]] + t[2]
+
+    def p_param_0(self, t):
+        'param : ID EQUALS STRLIT SEMI'
+        t[0] = self.StringParam(t[1], t[3])
+
+    def p_param_1(self, t):
+        'param : object'
+        t[0] = t[1]
+
+
+class ArmFastModelComponent(object):
+    def __init__(self, project_file, *extra_deps):
+        project_file = File(project_file)
+        project_file_dir = project_file.Dir('.')
+
+        parser = ProjectFileParser()
+        proj = parser.parse_file(project_file.srcnode().abspath)
+
+        # Top level component.
+        tlc = None
+        # Config name.
+        config_name = None
+
+        # Scan for particular properties of the project.
+        for param in proj.params:
+            if not param.is_object:
+                if param.name == 'TOP_LEVEL_COMPONENT':
+                    tlc = param.value
+                elif param.name == 'ACTIVE_CONFIG_LINUX':
+                    config_name = param.value
+
+        assert tlc is not None and config_name is not None
+
+        simgen_dir = project_file_dir.Dir(config_name)
+
+        def simgen_static(name):
+            return simgen_dir.File(env.subst(
+                        '${LIBPREFIX}%s${LIBSUFFIX}' % name))
+
+        def simgen_shared(name):
+            return simgen_dir.File(env.subst(
+                        '${SHLIBPREFIX}%s${SHLIBSUFFIX}' % name))
+
+        static_libs = [
+            'scx-%s-%s' % (tlc, config_name),
+            'scx',
+        ]
+        shared_libs = [
+            '%s-%s' % (tlc, config_name),
+        ]
+
+        static_lib_nodes = map(simgen_static, static_libs)
+        shared_lib_nodes = map(simgen_shared, shared_libs)
+        # We need to use the static libraries as files so that the linker
+        # doesn't use the shared versions of them instead. We need to use
+        # the shared libraries by name so that the linker will apply RPATH
+        # and be able to find them at run time. If a shared libary includes
+        # a path, the dynamic linker will apparently ignore RPATH when looking
+        # for it.
+        lib_nodes = static_lib_nodes + shared_lib_nodes
+
+        gen_dir = simgen_dir.Dir('gen')
+
+        header = gen_dir.File('scx_evs_%s.h' % tlc)
+
+        self.headers = [header]
+        self.headerpaths = [gen_dir]
+        self.libs = static_lib_nodes + shared_libs
+        self.libpaths = [simgen_dir]
+        self.rpaths = [simgen_dir]
+
+        simgen_cmd = env.subst('${SIMGEN} -p %s --configuration %s -b ' +
+            '--verbose off --num-build-cpus 100 --build-dir %s') % \
+            (project_file.srcnode().abspath, config_name, simgen_dir.abspath)
+        if not GetOption('verbose'):
+            simgen_cmd += ' > /dev/null'
+        simgen_action = MakeAction(simgen_cmd, Transform('SIMGEN'))
+        sources = [project_file]
+        sources.extend(extra_deps)
+        env.Command(lib_nodes + self.headers, sources, simgen_action)
+
+    def prepare_env(self, env):
+        env.Append(LIBPATH=self.libpaths)
+        env.AddLocalRPATH(*self.rpaths)
+        env.Append(CPPPATH=self.headerpaths)
+        env.Prepend(LIBS=self.libs)
+
+
+class ArmFastModelBin(Executable):
+    def __init__(self, target, *components_and_sources):
+        def is_component(x):
+            return isinstance(x, ArmFastModelComponent)
+
+        def not_component(x):
+            return not is_component(x)
+
+        components = list(filter(is_component, components_and_sources))
+        sources = list(filter(not_component, components_and_sources))
+
+        self.components = components
+        super(ArmFastModelBin, self).__init__(target, *sources)
+
+    @classmethod
+    def declare_all(cls, env):
+        env = env.Clone()
+        env.Prepend(LIBS=env['STATIC_LIB'][0])
+        super(ArmFastModelBin, cls).declare_all(env)
+
+    def declare(self, env):
+        env = env.Clone()
+
+        sources = list(self.sources)
+        for f in self.filters:
+            sources += Source.all.apply_filter(f)
+
+        objs = self.srcs_to_objs(env, sources)
+        objs = objs + env['MAIN_OBJS']
+
+        for component in self.components:
+            component.prepare_env(env)
+
+        binary = super(ArmFastModelBin, self).declare(env, objs)[0]
+
+        # We need a copy of the simulation engine lib alongside the executable
+        # so that the license check works properly.
+        local_engine = binary.File(simulation_engine_name)
+        Depends(binary, local_engine)
+        main.Command(local_engine, simulation_engine_lib,
+                MakeAction("cp ${SOURCE} ${TARGET}", Transform('COPY')))
+
+Export('ArmFastModelComponent')
+Export('ArmFastModelBin')
+
+PySource('m5', 'arm_fast_model.py')
+Source('fastmodel.cc')
+
+SimObject('FastModel.py')
+Source('amba_to_tlm_bridge.cc')
+Source('amba_from_tlm_bridge.cc')
diff --git a/src/arch/arm/fastmodel/SConsopts b/src/arch/arm/fastmodel/SConsopts
new file mode 100644
index 0000000..39e8a3f
--- /dev/null
+++ b/src/arch/arm/fastmodel/SConsopts
@@ -0,0 +1,53 @@
+# Copyright 2019 Google, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Gabe Black
+
+Import('*')
+
+import os
+
+default_simgen = os.path.join('${MAXCORE_HOME}', 'bin', 'simgen')
+
+sticky_vars.AddVariables(
+    BoolVariable('USE_ARM_FASTMODEL',
+        'Build support for integrating ARM Fast Models', False),
+    ('PVLIB_HOME', 'Fast Model portfolio directory',
+     os.environ.get('PVLIB_HOME', '')),
+    ('PVLIB_FLAVOR', 'What build flavor of the Fast Model pvlib to use',
+     'Linux64_GCC-6.4'),
+    ('MAXCORE_HOME', 'Fast Model tools directory',
+     os.environ.get('MAXCORE_HOME', '')),
+    ('ARMLMD_LICENSE_FILE', 'ARM license file location',
+     os.environ.get('ARMLMD_LICENSE_FILE', '')),
+    ('SIMGEN', 'simgen executable', os.environ.get('SIMGEN', default_simgen)),
+)
+
+export_vars.extend([
+        'ARMLMD_LICENSE_FILE',
+        'PVLIB_HOME',
+        'PVLIB_FLAVOR',
+])
diff --git a/src/arch/arm/fastmodel/amba_from_tlm_bridge.cc b/src/arch/arm/fastmodel/amba_from_tlm_bridge.cc
new file mode 100644
index 0000000..c8cbd81
--- /dev/null
+++ b/src/arch/arm/fastmodel/amba_from_tlm_bridge.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#include "arch/arm/fastmodel/amba_from_tlm_bridge.hh"
+
+#include "params/AmbaFromTlmBridge64.hh"
+
+namespace FastModel
+{
+
+AmbaFromTlmBridge64::AmbaFromTlmBridge64(const char *name) :
+    amba_pv::amba_pv_from_tlm_bridge<64>(name),
+    ambaWrapper(amba_pv_m, std::string(name) + ".amba", -1),
+    tlmWrapper(tlm_s, std::string(name) + ".tlm", -1)
+{}
+
+Port &
+AmbaFromTlmBridge64::gem5_getPort(const std::string &if_name, int idx)
+{
+    if (if_name == "tlm") {
+        return tlmWrapper;
+    } else if (if_name == "amba") {
+        return ambaWrapper;
+    } else {
+        return amba_pv::amba_pv_from_tlm_bridge<64>::gem5_getPort(
+                if_name, idx);
+    }
+}
+
+} // namespace FastModel
+
+FastModel::AmbaFromTlmBridge64 *
+AmbaFromTlmBridge64Params::create()
+{
+    return new FastModel::AmbaFromTlmBridge64(name.c_str());
+}
diff --git a/src/arch/arm/fastmodel/amba_from_tlm_bridge.hh b/src/arch/arm/fastmodel/amba_from_tlm_bridge.hh
new file mode 100644
index 0000000..a0d65e7
--- /dev/null
+++ b/src/arch/arm/fastmodel/amba_from_tlm_bridge.hh
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#ifndef __ARCH_ARM_FASTMODEL_AMBA_FROM_TLM_BRIDGE_HH__
+#define __ARCH_ARM_FASTMODEL_AMBA_FROM_TLM_BRIDGE_HH__
+
+#include "amba_pv.h"
+#include "arch/arm/fastmodel/amba_ports.hh"
+#include "systemc/tlm_port_wrapper.hh"
+
+namespace FastModel
+{
+
+// A wrapper around the fast model AMBA -> TLM bridge which provides
+// gem5_getPort.
+class AmbaFromTlmBridge64 : public amba_pv::amba_pv_from_tlm_bridge<64>
+{
+  public:
+    AmbaFromTlmBridge64(const char *name);
+
+    ::Port &gem5_getPort(const std::string &if_name, int idx=-1) override;
+
+  private:
+    AmbaInitiator ambaWrapper;
+    sc_gem5::TlmTargetWrapper<64> tlmWrapper;
+};
+
+} // namespace FastModel
+
+#endif // __ARCH_ARM_FASTMODEL_AMBA_FROM_TLM_BRIDGE_HH__
diff --git a/src/arch/arm/fastmodel/amba_ports.hh b/src/arch/arm/fastmodel/amba_ports.hh
new file mode 100644
index 0000000..43c1525
--- /dev/null
+++ b/src/arch/arm/fastmodel/amba_ports.hh
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#ifndef __ARCH_ARM_FASTMODEL_AMBA_PORTS_HH__
+#define __ARCH_ARM_FASTMODEL_AMBA_PORTS_HH__
+
+#include <amba_pv.h>
+
+#include "systemc/tlm_port_wrapper.hh"
+
+namespace FastModel
+{
+
+typedef sc_gem5::TlmInitiatorWrapper<
+    64, amba_pv::amba_pv_protocol_types> AmbaInitiator;
+typedef sc_gem5::TlmTargetWrapper<
+    64, amba_pv::amba_pv_protocol_types> AmbaTarget;
+
+} // namespace FastModel
+
+#endif // __ARCH_ARM_FASTMODEL_AMBA_PORTS_HH__
diff --git a/src/arch/arm/fastmodel/amba_to_tlm_bridge.cc b/src/arch/arm/fastmodel/amba_to_tlm_bridge.cc
new file mode 100644
index 0000000..d811645
--- /dev/null
+++ b/src/arch/arm/fastmodel/amba_to_tlm_bridge.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#include "arch/arm/fastmodel/amba_to_tlm_bridge.hh"
+
+#include "params/AmbaToTlmBridge64.hh"
+
+namespace FastModel
+{
+
+AmbaToTlmBridge64::AmbaToTlmBridge64(const char *name) :
+    amba_pv::amba_pv_to_tlm_bridge<64>(name),
+    tlmWrapper(tlm_m, std::string(name) + ".tlm", -1),
+    ambaWrapper(amba_pv_s, std::string(name) + ".amba", -1)
+{}
+
+Port &
+AmbaToTlmBridge64::gem5_getPort(const std::string &if_name, int idx)
+{
+    if (if_name == "tlm")
+        return tlmWrapper;
+    else if (if_name == "amba")
+        return ambaWrapper;
+    else
+        return amba_pv::amba_pv_to_tlm_bridge<64>::gem5_getPort(if_name, idx);
+}
+
+} // namespace FastModel
+
+FastModel::AmbaToTlmBridge64 *
+AmbaToTlmBridge64Params::create()
+{
+    return new FastModel::AmbaToTlmBridge64(name.c_str());
+}
diff --git a/src/arch/arm/fastmodel/amba_to_tlm_bridge.hh b/src/arch/arm/fastmodel/amba_to_tlm_bridge.hh
new file mode 100644
index 0000000..f3ccef5
--- /dev/null
+++ b/src/arch/arm/fastmodel/amba_to_tlm_bridge.hh
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#ifndef __ARCH_ARM_FASTMODEL_AMBA_TO_TLM_BRIDGE_HH__
+#define __ARCH_ARM_FASTMODEL_AMBA_TO_TLM_BRIDGE_HH__
+
+#include "amba_pv.h"
+#include "arch/arm/fastmodel/amba_ports.hh"
+#include "systemc/tlm_port_wrapper.hh"
+
+namespace FastModel
+{
+
+// A wrapper around the fast model TLM -> AMBA bridge which provides
+// gem5_getPort.
+class AmbaToTlmBridge64 : public amba_pv::amba_pv_to_tlm_bridge<64>
+{
+  public:
+    AmbaToTlmBridge64(const char *name);
+
+    ::Port &gem5_getPort(const std::string &if_name, int idx=-1) override;
+
+  private:
+    sc_gem5::TlmInitiatorWrapper<64> tlmWrapper;
+    AmbaTarget ambaWrapper;
+};
+
+} // namespace FastModel
+
+#endif // __ARCH_ARM_FASTMODEL_AMBA_TO_TLM_BRIDGE_HH__
diff --git a/src/arch/arm/fastmodel/arm/FastModelArch.py b/src/arch/arm/fastmodel/arm/FastModelArch.py
new file mode 100644
index 0000000..efc40b2
--- /dev/null
+++ b/src/arch/arm/fastmodel/arm/FastModelArch.py
@@ -0,0 +1,40 @@
+# Copyright 2019 Google, Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Gabe Black
+
+from m5.params import *
+from m5.proxy import *
+
+from m5.objects.IrisArch import IrisArmCPU
+
+class FastModelArmCPU(IrisArmCPU):
+    type = 'FastModelArmCPU'
+    cxx_class = 'FastModel::ArmCPU'
+    cxx_header = 'arch/arm/fastmodel/arm/cpu.hh'
+
+    cntfrq = Param.UInt64("Value for the CNTFRQ timer register")
+
+    mem = RequestPort('Port for port proxies to attach to.')
diff --git a/src/arch/arm/fastmodel/arm/SConscript b/src/arch/arm/fastmodel/arm/SConscript
new file mode 100644
index 0000000..e312b62
--- /dev/null
+++ b/src/arch/arm/fastmodel/arm/SConscript
@@ -0,0 +1,34 @@
+# Copyright 2019 Google, Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Gabe Black
+
+Import('*')
+
+if not env['USE_ARM_FASTMODEL'] or env['TARGET_ISA'] != 'arm':
+    Return()
+
+SimObject('FastModelArch.py')
+Source('cpu.cc')
diff --git a/src/arch/arm/fastmodel/arm/cpu.cc b/src/arch/arm/fastmodel/arm/cpu.cc
new file mode 100644
index 0000000..4742036
--- /dev/null
+++ b/src/arch/arm/fastmodel/arm/cpu.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#include "arch/arm/fastmodel/arm/cpu.hh"
+
+#include "scx/scx_iris.h"
+
+namespace FastModel
+{
+
+ArmCPU::ArmCPU(FastModelArmCPUParams *params) :
+    Iris::ArmCPU(params, scx::scx_get_iris_connection_interface()),
+    mem(name() + ".mem", this)
+{
+}
+
+void
+ArmCPU::initState()
+{
+    auto cntfrq = static_cast<const FastModelArmCPUParams *>(params())->cntfrq;
+    for (auto *tc : threadContexts)
+        tc->setMiscRegNoEffect(ArmISA::MISCREG_CNTFRQ_EL0, cntfrq);
+}
+
+Port &
+ArmCPU::getPort(const std::string &if_name, PortID idx)
+{
+    if (if_name == "mem")
+        return mem;
+    return Iris::ArmCPU::getPort(if_name, idx);
+}
+
+} // namespace FastModel
+
+FastModel::ArmCPU *
+FastModelArmCPUParams::create()
+{
+    return new FastModel::ArmCPU(this);
+}
diff --git a/src/arch/arm/fastmodel/arm/cpu.hh b/src/arch/arm/fastmodel/arm/cpu.hh
new file mode 100644
index 0000000..1d9d585
--- /dev/null
+++ b/src/arch/arm/fastmodel/arm/cpu.hh
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#ifndef __ARCH_ARM_FASTMODEL_ARM_CPU_HH__
+#define __ARCH_ARM_FASTMODEL_ARM_CPU_HH__
+
+#include "arch/arm/fastmodel/iris/arm/cpu.hh"
+#include "params/FastModelArmCPU.hh"
+
+namespace FastModel
+{
+
+// This class adds non-Iris, gem5 functionality to this CPU model.
+class ArmCPU : public Iris::ArmCPU
+{
+  private:
+    class MemPort : public MasterPort
+    {
+      public:
+        using MasterPort::MasterPort;
+
+        bool
+        recvTimingResp(PacketPtr pkt) override
+        {
+            panic("%s.%s not implemented.\n", name(), __FUNCTION__);
+        }
+
+        void
+        recvReqRetry() override
+        {
+            panic("%s.%s not implemented.\n", name(), __FUNCTION__);
+        }
+    };
+
+    MemPort mem;
+
+  public:
+    ArmCPU(FastModelArmCPUParams *params);
+
+    void initState() override;
+    Port &getPort(const std::string &if_name,
+                  PortID idx=InvalidPortID) override;
+
+    Port &getDataPort() override { return mem; }
+    Port &getInstPort() override { return mem; }
+};
+
+} // namespace FastModel
+
+#endif // __ARCH_ARM_FASTMODEL_ARM_CPU_HH__
diff --git a/src/arch/arm/fastmodel/arm_fast_model.py b/src/arch/arm/fastmodel/arm_fast_model.py
new file mode 100644
index 0000000..d666b7f
--- /dev/null
+++ b/src/arch/arm/fastmodel/arm_fast_model.py
@@ -0,0 +1,130 @@
+# Copyright 2019 Google, Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Gabe Black
+
+import os
+
+from m5.defines import buildEnv
+import _m5.arm_fast_model
+
+def set_armlmd_license_file(force=False):
+    '''Set the ARMLMD_LICENSE_FILE environment variable. If "force" is
+       False, then it will only be set if it wasn't already set in the
+       environment. The value it's set to is the one gem5 was built with.
+       '''
+    key = 'ARMLMD_LICENSE_FILE'
+    license_file = buildEnv[key]
+    if force or key not in os.environ:
+        os.environ[key] = license_file
+
+# These methods wrap much of the SystemC Export API described in section
+# 7.6 of the Fast Models User Guide.
+
+def scx_initialize(id):
+    # Change our working directory to where the simulation engine library
+    # is so that the fast model code can find it. It looks in the binary
+    # directory and in the current working directory, and we can change
+    # the later. This avoids having to make copies of that library all
+    # over the place.
+    cwd = os.getcwd()
+    os.chdir(os.path.join(buildEnv['PVLIB_HOME'], 'lib',
+                          buildEnv['PVLIB_FLAVOR']))
+
+    # Actually run scx_initialize.
+    _m5.arm_fast_model.scx_initialize(id)
+
+    # Restore the previous working directory.
+    os.chdir(cwd)
+
+def scx_load_application(instance, application):
+    _m5.arm_fast_model.scx_load_application(instance, application)
+
+def scx_load_application_all(application):
+    _m5.arm_fast_model.scx_load_application_all(application)
+
+def scx_load_data(instance, data, address):
+    _m5.arm_fast_model.scx_load_data(instance, data, address)
+
+def scx_load_data_all(data, address):
+    _m5.arm_fast_model.scx_load_data_all(data, address)
+
+def scx_set_parameter(name, value):
+    _m5.arm_fast_model.scx_set_parameter(name, value)
+
+def scx_get_parameter(name):
+    value = ""
+    _m5.arm_fast_model.scx_get_parameter(name, value)
+    return value
+
+def scx_get_parameter_list(self):
+    return _m5.arm_fast_model.scx_get_parameter_list()
+
+def scx_set_cpi_file(cpi_file_path):
+    _m5.arm_fast_model.scx_set_cpi_file(cpi_file_path)
+
+def scx_cpulimit(t):
+    _m5.arm_fast_model.scx_cpulimit(t)
+
+def scx_timelimit(t):
+    _m5.arm_fast_model.scx_timelimit(t)
+
+def scx_simlimit(t):
+    _m5.arm_fast_model.scx_simlimit(t)
+
+def scx_parse_and_configure(
+        self, argc, argv, trailer=None, sig_handler=True):
+    _m5.arm_fast_model.scx_parse_and_configure(
+            argc, argv, trailer, sig_handler)
+
+def scx_start_cadi_server(start=True, run=True, debug=False):
+    _m5.arm_fast_model.scx_start_cadi_server(start, run, debug)
+
+def scx_enable_cadi_log(log=True):
+    _m5.arm_fast_model.scx_enable_cadi_log(log)
+
+def scx_prefix_appli_output(prefix=True):
+    _m5.arm_fast_model.scx_prefix_appli_output(prefix)
+
+def scx_print_port_number(print_=True):
+    _m5.arm_fast_model.scx_print_port_number(print_)
+
+def scx_print_statistics(print_=True):
+    _m5.arm_fast_model.scx_print_statistics(print_)
+
+def scx_load_plugin(file_):
+    _m5.arm_fast_model.scx_load_plugin(file_)
+
+def scx_sync(sync_time):
+    _m5.arm_fast_model.scx_sync(sync_time)
+
+def scx_set_min_sync_latency(latency):
+    _m5.arm_fast_model.scx_set_min_sync_latency(latency)
+
+def scx_get_min_sync_latency(arg=None):
+    if arg:
+        return _m5.arm_fast_model.scx_get_min_sync_latency(arg)
+    else:
+        return _m5.arm_fast_model.scx_get_min_sync_latency()
diff --git a/src/arch/arm/fastmodel/fastmodel.cc b/src/arch/arm/fastmodel/fastmodel.cc
new file mode 100644
index 0000000..4a66bbb
--- /dev/null
+++ b/src/arch/arm/fastmodel/fastmodel.cc
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#include "python/pybind11/pybind.hh"
+#include "scx/scx.h"
+#include "sim/init.hh"
+
+namespace
+{
+
+void
+arm_fast_model_pybind(pybind11::module &m_internal)
+{
+    auto arm_fast_model = m_internal.def_submodule("arm_fast_model");
+    arm_fast_model
+        .def("scx_initialize", [](std::string id) {
+                scx::scx_initialize(id);
+             })
+
+        // Loading of applications or raw data.
+        .def("scx_load_application", &scx::scx_load_application)
+        .def("scx_load_application_all", &scx::scx_load_application_all)
+        .def("scx_load_data", &scx::scx_load_data)
+        .def("scx_load_data_all", &scx::scx_load_data_all)
+
+        // Only expose the string based versions of these functions. Exposing
+        // specializations of the templated versions is likely overkill,
+        // especially since there are other preferred methods for setting up
+        // the parameters of a component.
+        .def("scx_set_parameter",
+             static_cast<bool (*)(const std::string &, const std::string &)>(
+                 &scx::scx_set_parameter))
+        .def("scx_get_parameter",
+             static_cast<bool (*)(const std::string &, std::string &)>(
+                 &scx::scx_get_parameter))
+        .def("scx_get_parameter_list", &scx::scx_get_parameter_list)
+
+        .def("scx_set_cpi_file", &scx::scx_set_cpi_file)
+
+        // These might be used internally by the gem5 fast model wrapper, and
+        // may not be worth exposing.
+        .def("scx_cpulimit", &scx::scx_cpulimit)
+        .def("scx_timelimit", &scx::scx_timelimit)
+        .def("scx_simlimit", &scx::scx_simlimit)
+
+        .def("scx_parse_and_configure",
+             [](int argc, std::vector<char *> argv,
+                const char *trailer=NULL, bool sig_handler=true) {
+                 scx::scx_parse_and_configure(argc, argv.data(),
+                                              trailer, sig_handler);
+             },
+             pybind11::arg("argc"),
+             pybind11::arg("argv"),
+             pybind11::arg("trailer") = NULL,
+             pybind11::arg("sig_handler") = true)
+
+        // CADI stuff.
+        .def("scx_start_cadi_server", &scx::scx_start_cadi_server,
+             pybind11::arg("start") = true,
+             pybind11::arg("run") = true,
+             pybind11::arg("debug") = false)
+        .def("scx_enable_cadi_log", &scx::scx_enable_cadi_log,
+             pybind11::arg("log") = true)
+        .def("scx_prefix_appli_output", &scx::scx_prefix_appli_output,
+             pybind11::arg("prefix") = true)
+        .def("scx_print_port_number", &scx::scx_print_port_number,
+             pybind11::arg("print") = true)
+
+        .def("scx_print_statistics", &scx::scx_print_statistics,
+             pybind11::arg("print") = true)
+        .def("scx_load_plugin", &scx::scx_load_plugin)
+        .def("scx_sync", &scx::scx_sync)
+        .def("scx_set_min_sync_latency",
+             static_cast<void (*)(double)>(&scx::scx_set_min_sync_latency))
+        .def("scx_set_min_sync_latency",
+             static_cast<void (*)(sg::ticks_t)>(
+                 &scx::scx_set_min_sync_latency))
+        .def("scx_get_min_sync_latency",
+             static_cast<double (*)()>(&scx::scx_get_min_sync_latency))
+        .def("scx_get_min_sync_latency",
+             static_cast<sg::ticks_t (*)(sg::Tag<sg::ticks_t> *)>(
+                 &scx::scx_get_min_sync_latency))
+        ;
+}
+EmbeddedPyBind embed_("arm_fast_model", &arm_fast_model_pybind);
+
+} // anonymous namespace
diff --git a/src/arch/arm/fastmodel/iris/Iris.py b/src/arch/arm/fastmodel/iris/Iris.py
new file mode 100644
index 0000000..781a146
--- /dev/null
+++ b/src/arch/arm/fastmodel/iris/Iris.py
@@ -0,0 +1,55 @@
+# Copyright 2019 Google, Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Gabe Black
+
+from m5.params import *
+from m5.proxy import *
+
+from m5.objects.BaseCPU import BaseCPU
+
+class IrisBaseCPU(BaseCPU):
+    type = 'IrisBaseCPU'
+    abstract = True
+    cxx_class = 'Iris::BaseCPU'
+    cxx_header = 'arch/arm/fastmodel/iris/cpu.hh'
+
+    @classmethod
+    def memory_mode(cls):
+        return 'atomic_noncaching'
+
+    @classmethod
+    def require_caches(cls):
+        return False
+
+    @classmethod
+    def support_take_over(cls):
+        #TODO Make this work.
+        return False
+
+    evs = Param.SystemC_ScModule(Parent.any,
+            "Fast model exported virtual subsystem holding cores")
+    core_paths = VectorParam.String(
+            "Sub-paths to elements in the EVS which are cores")
diff --git a/src/arch/arm/fastmodel/iris/SConscript b/src/arch/arm/fastmodel/iris/SConscript
new file mode 100644
index 0000000..666e040
--- /dev/null
+++ b/src/arch/arm/fastmodel/iris/SConscript
@@ -0,0 +1,36 @@
+# Copyright 2019 Google, Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Gabe Black
+
+Import('*')
+
+if not env['USE_ARM_FASTMODEL']:
+    Return()
+
+SimObject('Iris.py')
+Source('cpu.cc')
+
+Source('thread_context.cc')
diff --git a/src/arch/arm/fastmodel/iris/arm/IrisArch.py b/src/arch/arm/fastmodel/iris/arm/IrisArch.py
new file mode 100644
index 0000000..4d2856f
--- /dev/null
+++ b/src/arch/arm/fastmodel/iris/arm/IrisArch.py
@@ -0,0 +1,37 @@
+# Copyright 2019 Google, Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Gabe Black
+
+from m5.params import *
+from m5.proxy import *
+
+from m5.objects.Iris import IrisBaseCPU
+
+class IrisArmCPU(IrisBaseCPU):
+    type = 'IrisArmCPU'
+    abstract=True
+    cxx_class = 'Iris::ArmCPU'
+    cxx_header = "arch/arm/fastmodel/iris/arm/cpu.hh"
diff --git a/src/arch/arm/fastmodel/iris/arm/SConscript b/src/arch/arm/fastmodel/iris/arm/SConscript
new file mode 100644
index 0000000..a8cb24b
--- /dev/null
+++ b/src/arch/arm/fastmodel/iris/arm/SConscript
@@ -0,0 +1,35 @@
+# Copyright 2019 Google, Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Gabe Black
+
+Import('*')
+
+if not env['USE_ARM_FASTMODEL'] or env['TARGET_ISA'] != 'arm':
+    Return()
+
+SimObject('IrisArch.py')
+
+Source('thread_context.cc')
diff --git a/src/arch/arm/fastmodel/iris/arm/cpu.cc b/src/arch/arm/fastmodel/iris/arm/cpu.cc
new file mode 100644
index 0000000..7ffafc3
--- /dev/null
+++ b/src/arch/arm/fastmodel/iris/arm/cpu.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#include "arch/arm/fastmodel/iris/arm/cpu.hh"
+
+Iris::ArmCPU *
+IrisCPUParams::create()
+{
+    return new Iris::ArmCPU(this);
+}
diff --git a/src/arch/arm/fastmodel/iris/arm/cpu.hh b/src/arch/arm/fastmodel/iris/arm/cpu.hh
new file mode 100644
index 0000000..8abbbba
--- /dev/null
+++ b/src/arch/arm/fastmodel/iris/arm/cpu.hh
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#ifndef __ARCH_ARM_FASTMODEL_IRIS_ARM_CPU_HH__
+#define __ARCH_ARM_FASTMODEL_IRIS_ARM_CPU_HH__
+
+#include "arch/arm/fastmodel/iris/arm/thread_context.hh"
+#include "arch/arm/fastmodel/iris/cpu.hh"
+
+namespace Iris
+{
+
+// This class specializes the generic Iris CPU template to use the Arm
+// Iris ThreadContext.
+class ArmCPU : public CPU<ArmThreadContext>
+{
+  public:
+    using CPU<ArmThreadContext>::CPU;
+
+    void
+    clockPeriodUpdated() override
+    {
+        CPU<ArmThreadContext>::clockPeriodUpdated();
+
+        // FIXME(b/139447397): this is a workaround since CNTFRQ_EL0 should not
+        // be modified after clock is changed in real hardwares. Remove or
+        // modify this after a more reasonable solution is found.
+        for (auto *tc : threadContexts) {
+            tc->setMiscRegNoEffect(ArmISA::MISCREG_CNTFRQ_EL0, frequency());
+        }
+    }
+};
+
+} // namespace Iris
+
+#endif // __ARCH_ARM_FASTMODEL_IRIS_ARM_CPU_HH__
diff --git a/src/arch/arm/fastmodel/iris/arm/thread_context.cc b/src/arch/arm/fastmodel/iris/arm/thread_context.cc
new file mode 100644
index 0000000..270adca
--- /dev/null
+++ b/src/arch/arm/fastmodel/iris/arm/thread_context.cc
@@ -0,0 +1,827 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#include "arch/arm/fastmodel/iris/arm/thread_context.hh"
+
+#include "iris/detail/IrisCppAdapter.h"
+#include "iris/detail/IrisObjects.h"
+
+namespace Iris
+{
+
+ArmThreadContext::ArmThreadContext(
+        ::BaseCPU *cpu, int id, System *system,
+        iris::IrisConnectionInterface *iris_if,
+        const std::string &iris_path) :
+    ThreadContext(cpu, id, system, iris_if, iris_path),
+    pcRscId(iris::IRIS_UINT64_MAX)
+{}
+
+void
+ArmThreadContext::initFromIrisInstance(const ResourceMap &resources)
+{
+    ThreadContext::initFromIrisInstance(resources);
+
+    pcRscId = extractResourceId(resources, "PC");
+    icountRscId = extractResourceId(resources, "icount");
+
+    extractResourceMap(miscRegIds, resources, miscRegIdxNameMap);
+
+    extractResourceMap(intReg32Ids, resources, intReg32IdxNameMap);
+    extractResourceMap(intReg64Ids, resources, intReg64IdxNameMap);
+}
+
+TheISA::PCState
+ArmThreadContext::pcState() const
+{
+    ArmISA::CPSR cpsr = readMiscRegNoEffect(ArmISA::MISCREG_CPSR);
+    ArmISA::PCState pc;
+
+    pc.thumb(cpsr.t);
+    pc.nextThumb(pc.thumb());
+    pc.jazelle(cpsr.j);
+    pc.nextJazelle(cpsr.j);
+    pc.aarch64(!cpsr.width);
+    pc.nextAArch64(!cpsr.width);
+    pc.illegalExec(false);
+
+    iris::ResourceReadResult result;
+    call().resource_read(_instId, result, pcRscId);
+    Addr addr = result.data.at(0);
+    if (cpsr.width && cpsr.t)
+        addr = addr & ~0x1;
+    pc.set(addr);
+
+    return pc;
+}
+void
+ArmThreadContext::pcState(const TheISA::PCState &val)
+{
+    Addr pc = val.pc();
+
+    ArmISA::CPSR cpsr = readMiscRegNoEffect(ArmISA::MISCREG_CPSR);
+    if (cpsr.width && cpsr.t)
+        pc = pc | 0x1;
+
+    iris::ResourceWriteResult result;
+    call().resource_write(_instId, result, pcRscId, pc);
+}
+
+Addr
+ArmThreadContext::instAddr() const
+{
+    return pcState().instAddr();
+}
+
+Addr
+ArmThreadContext::nextInstAddr() const
+{
+    return pcState().nextInstAddr();
+}
+
+Counter
+ArmThreadContext::totalInsts()
+{
+    iris::ResourceReadResult result;
+    call().resource_read(_instId, result, icountRscId);
+    return result.data.at(0);
+}
+
+uint64_t
+ArmThreadContext::readIntReg(RegIndex reg_idx) const
+{
+    ArmISA::CPSR cpsr = readMiscRegNoEffect(ArmISA::MISCREG_CPSR);
+
+    iris::ResourceReadResult result;
+    if (cpsr.width)
+        call().resource_read(_instId, result, intReg32Ids.at(reg_idx));
+    else
+        call().resource_read(_instId, result, intReg64Ids.at(reg_idx));
+    return result.data.at(0);
+}
+
+void
+ArmThreadContext::setIntReg(RegIndex reg_idx, uint64_t val)
+{
+    ArmISA::CPSR cpsr = readMiscRegNoEffect(ArmISA::MISCREG_CPSR);
+
+    iris::ResourceWriteResult result;
+    if (cpsr.width)
+        call().resource_write(_instId, result, intReg32Ids.at(reg_idx), val);
+    else
+        call().resource_write(_instId, result, intReg64Ids.at(reg_idx), val);
+}
+
+Iris::ThreadContext::IdxNameMap ArmThreadContext::miscRegIdxNameMap({
+        { ArmISA::MISCREG_CPSR, "CPSR" },
+        { ArmISA::MISCREG_SPSR, "SPSR" },
+        { ArmISA::MISCREG_SPSR_FIQ, "SPSR_fiq" },
+        { ArmISA::MISCREG_SPSR_IRQ, "SPSR_irq" },
+        // ArmISA::MISCREG_SPSR_SVC?
+        // ArmISA::MISCREG_SPSR_MON?
+        { ArmISA::MISCREG_SPSR_ABT, "SPSR_abt" },
+        // ArmISA::MISCREG_SPSR_HYP?
+        { ArmISA::MISCREG_SPSR_UND, "SPSR_und" },
+        // ArmISA::MISCREG_ELR_HYP?
+        // ArmISA::MISCREG_FPSID?
+        { ArmISA::MISCREG_FPSCR, "FPSCR" },
+        { ArmISA::MISCREG_MVFR1, "MVFR1_EL1" }, //XXX verify
+        { ArmISA::MISCREG_MVFR0, "MVFR1_EL1" }, //XXX verify
+        // ArmISA::MISCREG_FPEXC?
+
+        // Helper registers
+        { ArmISA::MISCREG_CPSR_MODE, "CPSR.MODE" },
+        { ArmISA::MISCREG_CPSR_Q, "CPSR.Q" },
+        // ArmISA::MISCREG_FPSCR_EXC?
+        { ArmISA::MISCREG_FPSCR_QC, "FPSR.QC" },
+        // ArmISA::MISCREG_LOCKADDR?
+        // ArmISA::MISCREG_LOCKFLAG?
+        // ArmISA::MISCREG_PRRR_MAIR0?
+        // ArmISA::MISCREG_PRRR_MAIR0_NS?
+        // ArmISA::MISCREG_PRRR_MAIR0_S?
+        // ArmISA::MISCREG_NMRR_MAIR1?
+        // ArmISA::MISCREG_NMRR_MAIR1_NS?
+        // ArmISA::MISCREG_NMRR_MAIR1_S?
+        // ArmISA::MISCREG_PMXEVTYPER_PMCCFILTR?
+        // ArmISA::MISCREG_SCTLR_RST?
+        // ArmISA::MISCREG_SEV_MAILBOX?
+
+        // AArch32 CP14 registers (debug/trace/ThumbEE/Jazelle control)
+        // ArmISA::MISCREG_DBGDIDR?
+        // ArmISA::MISCREG_DBGDSCRint?
+        // ArmISA::MISCREG_DBGDCCINT?
+        // ArmISA::MISCREG_DBGDTRTXint?
+        // ArmISA::MISCREG_DBGDTRRXint?
+        { ArmISA::MISCREG_DBGWFAR, "DBGWFAR" },
+        // ArmISA::MISCREG_DBGVCR?
+        { ArmISA::MISCREG_DBGDTRRXext, "DBGDTRRXext" },
+        // ArmISA::MISCREG_DBGDSCRext?
+        { ArmISA::MISCREG_DBGDTRTXext, "DBGDTRTXext" },
+        // ArmISA::MISCREG_DBGOSECCR?
+        { ArmISA::MISCREG_DBGBVR0, "DBGBVR0" },
+        { ArmISA::MISCREG_DBGBVR1, "DBGBVR1" },
+        { ArmISA::MISCREG_DBGBVR2, "DBGBVR2" },
+        { ArmISA::MISCREG_DBGBVR3, "DBGBVR3" },
+        { ArmISA::MISCREG_DBGBVR4, "DBGBVR4" },
+        { ArmISA::MISCREG_DBGBVR5, "DBGBVR5" },
+        { ArmISA::MISCREG_DBGBCR0, "DBGBCR0" },
+        { ArmISA::MISCREG_DBGBCR1, "DBGBCR1" },
+        { ArmISA::MISCREG_DBGBCR2, "DBGBCR2" },
+        { ArmISA::MISCREG_DBGBCR3, "DBGBCR3" },
+        { ArmISA::MISCREG_DBGBCR4, "DBGBCR4" },
+        { ArmISA::MISCREG_DBGBCR5, "DBGBCR5" },
+        { ArmISA::MISCREG_DBGWVR0, "DBGWVR0" },
+        { ArmISA::MISCREG_DBGWVR1, "DBGWVR1" },
+        { ArmISA::MISCREG_DBGWVR2, "DBGWVR2" },
+        { ArmISA::MISCREG_DBGWVR3, "DBGWVR3" },
+        { ArmISA::MISCREG_DBGWCR0, "DBGWCR0" },
+        { ArmISA::MISCREG_DBGWCR1, "DBGWCR1" },
+        { ArmISA::MISCREG_DBGWCR2, "DBGWCR2" },
+        { ArmISA::MISCREG_DBGWCR3, "DBGWCR3" },
+        // ArmISA::MISCREG_DBGDRAR?
+        { ArmISA::MISCREG_DBGBXVR4, "DBGBXVR4" },
+        { ArmISA::MISCREG_DBGBXVR5, "DBGBXVR5" },
+        { ArmISA::MISCREG_DBGOSLAR, "DBGOSLAR" },
+        // ArmISA::MISCREG_DBGOSLSR?
+        // ArmISA::MISCREG_DBGOSDLR?
+        { ArmISA::MISCREG_DBGPRCR, "DBGPRCR_EL1" }, //XXX verify
+        // ArmISA::MISCREG_DBGDSAR?
+        { ArmISA::MISCREG_DBGCLAIMSET, "DBGCLAIMSET" },
+        { ArmISA::MISCREG_DBGCLAIMCLR, "DBGCLAIMCLR" },
+        { ArmISA::MISCREG_DBGAUTHSTATUS, "DBGAUTHSTATUS" },
+        // ArmISA::MISCREG_DBGDEVID2?
+        // ArmISA::MISCREG_DBGDEVID1?
+        // ArmISA::MISCREG_DBGDEVID0?
+        // ArmISA::MISCREG_TEECR? not in ARM DDI 0487A.b+
+        // ArmISA::MISCREG_JIDR?
+        // ArmISA::MISCREG_TEEHBR? not in ARM DDI 0487A.b+
+        // ArmISA::MISCREG_JOSCR?
+        // ArmISA::MISCREG_JMCR?
+
+        // AArch32 CP15 registers (system control)
+        { ArmISA::MISCREG_MIDR, "MIDR" },
+        { ArmISA::MISCREG_CTR, "CTR" },
+        { ArmISA::MISCREG_TCMTR, "TCMTR" },
+        { ArmISA::MISCREG_TLBTR, "TLBTR" },
+        { ArmISA::MISCREG_MPIDR, "MPIDR" },
+        { ArmISA::MISCREG_REVIDR, "REVIDR" },
+        { ArmISA::MISCREG_ID_PFR0, "ID_PFR0" },
+        { ArmISA::MISCREG_ID_PFR1, "ID_PFR1" },
+        { ArmISA::MISCREG_ID_DFR0, "ID_DFR0" },
+        { ArmISA::MISCREG_ID_AFR0, "ID_AFR0" },
+        { ArmISA::MISCREG_ID_MMFR0, "ID_MMFR0" },
+        { ArmISA::MISCREG_ID_MMFR1, "ID_MMFR1" },
+        { ArmISA::MISCREG_ID_MMFR2, "ID_MMFR2" },
+        { ArmISA::MISCREG_ID_MMFR3, "ID_MMFR3" },
+        { ArmISA::MISCREG_ID_ISAR0, "ID_ISAR0" },
+        { ArmISA::MISCREG_ID_ISAR1, "ID_ISAR1" },
+        { ArmISA::MISCREG_ID_ISAR2, "ID_ISAR2" },
+        { ArmISA::MISCREG_ID_ISAR3, "ID_ISAR3" },
+        { ArmISA::MISCREG_ID_ISAR4, "ID_ISAR4" },
+        { ArmISA::MISCREG_ID_ISAR5, "ID_ISAR5" },
+        { ArmISA::MISCREG_CCSIDR, "CCSIDR" },
+        { ArmISA::MISCREG_CLIDR, "CLIDR" },
+        { ArmISA::MISCREG_AIDR, "AIDR" },
+        { ArmISA::MISCREG_CSSELR, "CSSELR_EL1" }, //XXX verify
+        // ArmISA::MISCREG_CSSELR_NS?
+        // ArmISA::MISCREG_CSSELR_S?
+        { ArmISA::MISCREG_VPIDR, "VPIDR" },
+        { ArmISA::MISCREG_VMPIDR, "VMPIDR" },
+        // ArmISA::MISCREG_SCTLR?
+        // ArmISA::MISCREG_SCTLR_NS?
+        // ArmISA::MISCREG_SCTLR_S?
+        // ArmISA::MISCREG_ACTLR?
+        // ArmISA::MISCREG_ACTLR_NS?
+        // ArmISA::MISCREG_ACTLR_S?
+        { ArmISA::MISCREG_CPACR, "CPACR" },
+        { ArmISA::MISCREG_SCR, "SCR" },
+        { ArmISA::MISCREG_SDER, "SDER" },
+        { ArmISA::MISCREG_NSACR, "NSACR" },
+        { ArmISA::MISCREG_HSCTLR, "HSCTLR" },
+        { ArmISA::MISCREG_HACTLR, "HACTLR" },
+        { ArmISA::MISCREG_HCR, "HCR" },
+        { ArmISA::MISCREG_HDCR, "HDCR" },
+        { ArmISA::MISCREG_HCPTR, "HCPTR" },
+        { ArmISA::MISCREG_HSTR, "HSTR_EL2" }, //XXX verify
+        { ArmISA::MISCREG_HACR, "HACR" },
+        // ArmISA::MISCREG_TTBR0?
+        { ArmISA::MISCREG_TTBR0_NS, "NS_TTBR0" }, //XXX verify
+        // ArmISA::MISCREG_TTBR0_S?
+        // ArmISA::MISCREG_TTBR1?
+        { ArmISA::MISCREG_TTBR1_NS, "NS_TTBR1" }, //XXX verify
+        // ArmISA::MISCREG_TTBR1_S?
+        // ArmISA::MISCREG_TTBCR?
+        { ArmISA::MISCREG_TTBCR_NS, "NS_TTBCR" }, //XXX verify
+        // ArmISA::MISCREG_TTBCR_S?
+        // ArmISA::MISCREG_HTCR?
+        // ArmISA::MISCREG_VTCR?
+        // ArmISA::MISCREG_DACR?
+        { ArmISA::MISCREG_DACR_NS, "NS_DACR" }, //XXX verify
+        // ArmISA::MISCREG_DACR_S?
+        // ArmISA::MISCREG_DFSR?
+        { ArmISA::MISCREG_DFSR_NS, "NS_DFSR" }, //XXX verify
+        // ArmISA::MISCREG_DFSR_S?
+        // ArmISA::MISCREG_IFSR?
+        { ArmISA::MISCREG_IFSR_NS, "NS_IFSR" },
+        // ArmISA::MISCREG_IFSR_S?
+        { ArmISA::MISCREG_ADFSR, "ADFSR" },
+        // ArmISA::MISCREG_ADFSR_NS?
+        // ArmISA::MISCREG_ADFSR_S?
+        { ArmISA::MISCREG_AIFSR, "AIFSR" },
+        // ArmISA::MISCREG_AIFSR_NS?
+        // ArmISA::MISCREG_AIFSR_S?
+        // ArmISA::MISCREG_HADFSR?
+        // ArmISA::MISCREG_HAIFSR?
+        { ArmISA::MISCREG_HSR, "HSR" },
+        // ArmISA::MISCREG_DFAR?
+        { ArmISA::MISCREG_DFAR_NS, "NS_DFAR" }, //XXX verify
+        // ArmISA::MISCREG_DFAR_S?
+        // ArmISA::MISCREG_IFAR?
+        { ArmISA::MISCREG_IFAR_NS, "NS_IFAR" }, //XXX verify
+        // ArmISA::MISCREG_IFAR_S?
+        { ArmISA::MISCREG_HDFAR, "HDFAR" },
+        { ArmISA::MISCREG_HIFAR, "HIFAR" },
+        { ArmISA::MISCREG_HPFAR, "HPFAR" },
+        { ArmISA::MISCREG_ICIALLUIS, "ICIALLUIS" },
+        // ArmISA::MISCREG_BPIALLIS?
+        // ArmISA::MISCREG_PAR?
+        { ArmISA::MISCREG_PAR_NS, "NS_PAR" }, //XXX verify
+        // ArmISA::MISCREG_PAR_S?
+        { ArmISA::MISCREG_ICIALLU, "ICIALLU" },
+        { ArmISA::MISCREG_ICIMVAU, "ICIMVAU" },
+        // ArmISA::MISCREG_CP15ISB?
+        // ArmISA::MISCREG_BPIALL?
+        // ArmISA::MISCREG_BPIMVA?
+        { ArmISA::MISCREG_DCIMVAC, "DCIMVAC" },
+        { ArmISA::MISCREG_DCISW, "DCISW" },
+        { ArmISA::MISCREG_ATS1CPR, "ATS1CPR" },
+        { ArmISA::MISCREG_ATS1CPW, "ATS1CPW" },
+        { ArmISA::MISCREG_ATS1CUR, "ATS1CUR" },
+        { ArmISA::MISCREG_ATS1CUW, "ATS1CUW" },
+        { ArmISA::MISCREG_ATS12NSOPR, "ATS12NSOPR" },
+        { ArmISA::MISCREG_ATS12NSOPW, "ATS12NSOPW" },
+        { ArmISA::MISCREG_ATS12NSOUR, "ATS12NSOUR" },
+        { ArmISA::MISCREG_ATS12NSOUW, "ATS12NSOUW" },
+        { ArmISA::MISCREG_DCCMVAC, "DCCMVAC" },
+        { ArmISA::MISCREG_DCCSW, "DCCSW" },
+        // ArmISA::MISCREG_CP15DSB?
+        // ArmISA::MISCREG_CP15DMB?
+        { ArmISA::MISCREG_DCCMVAU, "DCCMVAU" },
+        // ArmISA::MISCREG_DCCIMVAC?
+        { ArmISA::MISCREG_DCCISW, "DCCISW" },
+        { ArmISA::MISCREG_ATS1HR, "ATS1HR" },
+        { ArmISA::MISCREG_ATS1HW, "ATS1HW" },
+        // ArmISA::MISCREG_TLBIALLIS?
+        // ArmISA::MISCREG_TLBIMVAIS?
+        // ArmISA::MISCREG_TLBIASIDIS?
+        // ArmISA::MISCREG_TLBIMVAAIS?
+        // ArmISA::MISCREG_TLBIMVALIS?
+        // ArmISA::MISCREG_TLBIMVAALIS?
+        // ArmISA::MISCREG_ITLBIALL?
+        // ArmISA::MISCREG_ITLBIMVA?
+        // ArmISA::MISCREG_ITLBIASID?
+        // ArmISA::MISCREG_DTLBIALL?
+        // ArmISA::MISCREG_DTLBIMVA?
+        // ArmISA::MISCREG_DTLBIASID?
+        // ArmISA::MISCREG_TLBIALL?
+        // ArmISA::MISCREG_TLBIMVA?
+        // ArmISA::MISCREG_TLBIASID?
+        // ArmISA::MISCREG_TLBIMVAA?
+        // ArmISA::MISCREG_TLBIMVAL?
+        // ArmISA::MISCREG_TLBIMVAAL?
+        // ArmISA::MISCREG_TLBIIPAS2IS?
+        // ArmISA::MISCREG_TLBIIPAS2LIS?
+        // ArmISA::MISCREG_TLBIALLHIS?
+        // ArmISA::MISCREG_TLBIMVAHIS?
+        // ArmISA::MISCREG_TLBIALLNSNHIS?
+        // ArmISA::MISCREG_TLBIMVALHIS?
+        // ArmISA::MISCREG_TLBIIPAS2?
+        // ArmISA::MISCREG_TLBIIPAS2L?
+        // ArmISA::MISCREG_TLBIALLH?
+        // ArmISA::MISCREG_TLBIMVAH?
+        // ArmISA::MISCREG_TLBIALLNSNH?
+        // ArmISA::MISCREG_TLBIMVALH?
+        { ArmISA::MISCREG_PMCR, "PMCR" },
+        { ArmISA::MISCREG_PMCNTENSET, "PMCNTENSET" },
+        { ArmISA::MISCREG_PMCNTENCLR, "PMCNTENCLR" },
+        { ArmISA::MISCREG_PMOVSR, "PMOVSR" },
+        { ArmISA::MISCREG_PMSWINC, "PMSWINC" },
+        { ArmISA::MISCREG_PMSELR, "PMSELR" },
+        { ArmISA::MISCREG_PMCEID0, "PMCEID0" },
+        { ArmISA::MISCREG_PMCEID1, "PMCEID1" },
+        { ArmISA::MISCREG_PMCCNTR, "PMCCNTR" },
+        { ArmISA::MISCREG_PMXEVTYPER, "PMXEVTYPER" },
+        { ArmISA::MISCREG_PMCCFILTR, "PMCCFILTR" },
+        { ArmISA::MISCREG_PMXEVCNTR, "PMXEVCNTR_EL0" }, //XXX verify
+        { ArmISA::MISCREG_PMUSERENR, "PMUSERENR" },
+        { ArmISA::MISCREG_PMINTENSET, "PMINTENSET" },
+        { ArmISA::MISCREG_PMINTENCLR, "PMINTENCLR" },
+        { ArmISA::MISCREG_PMOVSSET, "PMOVSSET" },
+        // ArmISA::MISCREG_L2CTLR?
+        // ArmISA::MISCREG_L2ECTLR?
+        // ArmISA::MISCREG_PRRR?
+        { ArmISA::MISCREG_PRRR_NS, "NS_PRRR" }, //XXX verify
+        // ArmISA::MISCREG_PRRR_S?
+        // ArmISA::MISCREG_MAIR0?
+        // ArmISA::MISCREG_MAIR0_NS?
+        // ArmISA::MISCREG_MAIR0_S?
+        // ArmISA::MISCREG_NMRR?
+        { ArmISA::MISCREG_NMRR_NS, "NS_NMRR" }, //XXX verify
+        // ArmISA::MISCREG_NMRR_S?
+        // ArmISA::MISCREG_MAIR1?
+        // ArmISA::MISCREG_MAIR1_NS?
+        // ArmISA::MISCREG_MAIR1_S?
+        // ArmISA::MISCREG_AMAIR0?
+        { ArmISA::MISCREG_AMAIR0_NS, "NS_AMAIR0" }, //XXX verify
+        // ArmISA::MISCREG_AMAIR0_S?
+        // ArmISA::MISCREG_AMAIR1?
+        { ArmISA::MISCREG_AMAIR1_NS, "NS_AMAIR1" }, //XXX verify
+        // ArmISA::MISCREG_AMAIR1_S?
+        { ArmISA::MISCREG_HMAIR0, "HMAIR0" },
+        { ArmISA::MISCREG_HMAIR1, "HMAIR1" },
+        { ArmISA::MISCREG_HAMAIR0, "HAMAIR0" },
+        { ArmISA::MISCREG_HAMAIR1, "HAMAIR1" },
+        // ArmISA::MISCREG_VBAR?
+        { ArmISA::MISCREG_VBAR_NS, "NS_VBAR" }, //XXX verify
+        // ArmISA::MISCREG_VBAR_S?
+        { ArmISA::MISCREG_MVBAR, "MVBAR" },
+        { ArmISA::MISCREG_RMR, "RMR" },
+        { ArmISA::MISCREG_ISR, "ISR" },
+        { ArmISA::MISCREG_HVBAR, "HVBAR" },
+        { ArmISA::MISCREG_FCSEIDR, "FCSEIDR" },
+        // ArmISA::MISCREG_CONTEXTIDR?
+        { ArmISA::MISCREG_CONTEXTIDR_NS, "NS_CONTEXTIDR" }, //XXX verify
+        // ArmISA::MISCREG_CONTEXTIDR_S?
+        // ArmISA::MISCREG_TPIDRURW?
+        { ArmISA::MISCREG_TPIDRURW_NS, "NS_TPIDRURW" }, //XXX verify
+        // ArmISA::MISCREG_TPIDRURW_S?
+        // ArmISA::MISCREG_TPIDRURO?
+        { ArmISA::MISCREG_TPIDRURO_NS, "NS_TPIDRURO" }, //XXX verify
+        // ArmISA::MISCREG_TPIDRURO_S?
+        // ArmISA::MISCREG_TPIDRPRW?
+        { ArmISA::MISCREG_TPIDRPRW_NS, "NS_TPIDRPRW" }, //XXX verify
+        /// ArmISA::MISCREG_TPIDRPRW_S?
+        { ArmISA::MISCREG_HTPIDR, "HTPIDR" },
+        { ArmISA::MISCREG_CNTFRQ, "CNTFRQ" },
+        { ArmISA::MISCREG_CNTKCTL, "CNTKCTL" },
+        { ArmISA::MISCREG_CNTP_TVAL, "CNTP_TVAL" },
+        // ArmISA::MISCREG_CNTP_TVAL_NS?
+        // ArmISA::MISCREG_CNTP_TVAL_S?
+        { ArmISA::MISCREG_CNTP_CTL, "CNTP_CTL" },
+        // ArmISA::MISCREG_CNTP_CTL_NS?
+        // ArmISA::MISCREG_CNTP_CTL_S?
+        { ArmISA::MISCREG_CNTV_TVAL, "CNTV_TVAL" },
+        { ArmISA::MISCREG_CNTV_CTL, "CNTV_CTL" },
+        { ArmISA::MISCREG_CNTHCTL, "CNTHCTL" },
+        { ArmISA::MISCREG_CNTHP_TVAL, "CNTHP_TVAL" },
+        { ArmISA::MISCREG_CNTHP_CTL, "CNTHP_CTL" },
+        // ArmISA::MISCREG_IL1DATA0?
+        // ArmISA::MISCREG_IL1DATA1?
+        // ArmISA::MISCREG_IL1DATA2?
+        // ArmISA::MISCREG_IL1DATA3?
+        // ArmISA::MISCREG_DL1DATA0?
+        // ArmISA::MISCREG_DL1DATA1?
+        // ArmISA::MISCREG_DL1DATA2?
+        // ArmISA::MISCREG_DL1DATA3?
+        // ArmISA::MISCREG_DL1DATA4?
+        { ArmISA::MISCREG_RAMINDEX, "RAMIDX" }, //XXX verify
+        // ArmISA::MISCREG_L2ACTLR?
+        // ArmISA::MISCREG_CBAR?
+        { ArmISA::MISCREG_HTTBR, "HTTBR" },
+        { ArmISA::MISCREG_VTTBR, "VTTBR" },
+        { ArmISA::MISCREG_CNTPCT, "CNTPCT" },
+        { ArmISA::MISCREG_CNTVCT, "CNTVCT" },
+        { ArmISA::MISCREG_CNTP_CVAL, "CNTP_CVAL" },
+        // ArmISA::MISCREG_CNTP_CVAL_NS?
+        // ArmISA::MISCREG_CNTP_CVAL_S?
+        { ArmISA::MISCREG_CNTV_CVAL, "CNTV_CVAL" },
+        { ArmISA::MISCREG_CNTVOFF, "CNTVOFF" },
+        { ArmISA::MISCREG_CNTHP_CVAL, "CNTHP_CVAL" },
+        { ArmISA::MISCREG_CPUMERRSR, "CPUMERRSR" },
+        { ArmISA::MISCREG_L2MERRSR, "L2MERRSR" },
+
+        // AArch64 registers (Op0=2)
+        { ArmISA::MISCREG_MDCCINT_EL1, "MDCCINT_EL1" },
+        { ArmISA::MISCREG_OSDTRRX_EL1, "OSDTRRX_EL1" },
+        { ArmISA::MISCREG_MDSCR_EL1, "MDSCR_EL1" },
+        { ArmISA::MISCREG_OSDTRTX_EL1, "OSDTRTX_EL1" },
+        { ArmISA::MISCREG_OSECCR_EL1, "OSECCR_EL1" },
+        { ArmISA::MISCREG_DBGBVR0_EL1, "DBGBVR0_EL1" },
+        { ArmISA::MISCREG_DBGBVR1_EL1, "DBGBVR1_EL1" },
+        { ArmISA::MISCREG_DBGBVR2_EL1, "DBGBVR2_EL1" },
+        { ArmISA::MISCREG_DBGBVR3_EL1, "DBGBVR3_EL1" },
+        { ArmISA::MISCREG_DBGBVR4_EL1, "DBGBVR4_EL1" },
+        { ArmISA::MISCREG_DBGBVR5_EL1, "DBGBVR5_EL1" },
+        { ArmISA::MISCREG_DBGBCR0_EL1, "DBGBCR0_EL1" },
+        { ArmISA::MISCREG_DBGBCR1_EL1, "DBGBCR1_EL1" },
+        { ArmISA::MISCREG_DBGBCR2_EL1, "DBGBCR2_EL1" },
+        { ArmISA::MISCREG_DBGBCR3_EL1, "DBGBCR3_EL1" },
+        { ArmISA::MISCREG_DBGBCR4_EL1, "DBGBCR4_EL1" },
+        { ArmISA::MISCREG_DBGBCR5_EL1, "DBGBCR5_EL1" },
+        { ArmISA::MISCREG_DBGWVR0_EL1, "DBGWVR0_EL1" },
+        { ArmISA::MISCREG_DBGWVR1_EL1, "DBGWVR1_EL1" },
+        { ArmISA::MISCREG_DBGWVR2_EL1, "DBGWVR2_EL1" },
+        { ArmISA::MISCREG_DBGWVR3_EL1, "DBGWVR3_EL1" },
+        { ArmISA::MISCREG_DBGWCR0_EL1, "DBGWCR0_EL1" },
+        { ArmISA::MISCREG_DBGWCR1_EL1, "DBGWCR1_EL1" },
+        { ArmISA::MISCREG_DBGWCR2_EL1, "DBGWCR2_EL1" },
+        { ArmISA::MISCREG_DBGWCR3_EL1, "DBGWCR3_EL1" },
+        { ArmISA::MISCREG_MDCCSR_EL0, "MDCCSR_EL0" },
+        // ArmISA::MISCREG_MDDTR_EL0?
+        // ArmISA::MISCREG_MDDTRTX_EL0?
+        // ArmISA::MISCREG_MDDTRRX_EL0?
+        // ArmISA::MISCREG_DBGVCR32_EL2?
+        { ArmISA::MISCREG_MDRAR_EL1, "MDRAR_EL1" },
+        { ArmISA::MISCREG_OSLAR_EL1, "OSLAR_EL1" },
+        { ArmISA::MISCREG_OSLSR_EL1, "OSLSR_EL1" },
+        { ArmISA::MISCREG_OSDLR_EL1, "OSDLR_EL1" },
+        { ArmISA::MISCREG_DBGPRCR_EL1, "DBGPRCR_EL1" },
+        { ArmISA::MISCREG_DBGCLAIMSET_EL1, "DBGCLAIMSET_EL1" },
+        { ArmISA::MISCREG_DBGCLAIMCLR_EL1, "DBGCLAIMCLR_EL1" },
+        { ArmISA::MISCREG_DBGAUTHSTATUS_EL1, "DBGAUTHSTATUS_EL1" },
+        // ArmISA::MISCREG_TEECR32_EL1? not in ARM DDI 0487A.b+
+        // ArmISA::MISCREG_TEEHBR32_EL1? not in ARM DDI 0487A.b+
+
+        // AArch64 registers (Op0=1)
+        { ArmISA::MISCREG_MIDR_EL1, "MIDR_EL1" },
+        { ArmISA::MISCREG_MPIDR_EL1, "MPIDR_EL1" },
+        { ArmISA::MISCREG_REVIDR_EL1, "REVIDR_EL1" },
+        { ArmISA::MISCREG_ID_PFR0_EL1, "ID_PFR0_EL1" },
+        { ArmISA::MISCREG_ID_PFR1_EL1, "ID_PFR1_EL1" },
+        { ArmISA::MISCREG_ID_DFR0_EL1, "ID_DFR0_EL1" },
+        { ArmISA::MISCREG_ID_AFR0_EL1, "ID_AFR0_EL1" },
+        { ArmISA::MISCREG_ID_MMFR0_EL1, "ID_MMFR0_EL1" },
+        { ArmISA::MISCREG_ID_MMFR1_EL1, "ID_MMFR1_EL1" },
+        { ArmISA::MISCREG_ID_MMFR2_EL1, "ID_MMFR2_EL1" },
+        { ArmISA::MISCREG_ID_MMFR3_EL1, "ID_MMFR3_EL1" },
+        { ArmISA::MISCREG_ID_ISAR0_EL1, "ID_ISAR0_EL1" },
+        { ArmISA::MISCREG_ID_ISAR1_EL1, "ID_ISAR1_EL1" },
+        { ArmISA::MISCREG_ID_ISAR2_EL1, "ID_ISAR2_EL1" },
+        { ArmISA::MISCREG_ID_ISAR3_EL1, "ID_ISAR3_EL1" },
+        { ArmISA::MISCREG_ID_ISAR4_EL1, "ID_ISAR4_EL1" },
+        { ArmISA::MISCREG_ID_ISAR5_EL1, "ID_ISAR5_EL1" },
+        { ArmISA::MISCREG_MVFR0_EL1, "MVFR0_EL1" },
+        { ArmISA::MISCREG_MVFR1_EL1, "MVFR1_EL1" },
+        { ArmISA::MISCREG_MVFR2_EL1, "MVFR2_EL1" },
+        { ArmISA::MISCREG_ID_AA64PFR0_EL1, "ID_AA64PFR0_EL1" },
+        { ArmISA::MISCREG_ID_AA64PFR1_EL1, "ID_AA64PFR1_EL1" },
+        { ArmISA::MISCREG_ID_AA64DFR0_EL1, "ID_AA64DFR0_EL1" },
+        { ArmISA::MISCREG_ID_AA64DFR1_EL1, "ID_AA64DFR1_EL1" },
+        { ArmISA::MISCREG_ID_AA64AFR0_EL1, "ID_AA64AFR0_EL1" },
+        { ArmISA::MISCREG_ID_AA64AFR1_EL1, "ID_AA64AFR1_EL1" },
+        { ArmISA::MISCREG_ID_AA64ISAR0_EL1, "ID_AA64ISAR0_EL1" },
+        { ArmISA::MISCREG_ID_AA64ISAR1_EL1, "ID_AA64ISAR1_EL1" },
+        { ArmISA::MISCREG_ID_AA64MMFR0_EL1, "ID_AA64MMFR0_EL1" },
+        { ArmISA::MISCREG_ID_AA64MMFR1_EL1, "ID_AA64MMFR1_EL1" },
+        { ArmISA::MISCREG_CCSIDR_EL1, "CCSIDR_EL1" },
+        { ArmISA::MISCREG_CLIDR_EL1, "CLIDR_EL1" },
+        { ArmISA::MISCREG_AIDR_EL1, "AIDR_EL1" },
+        { ArmISA::MISCREG_CSSELR_EL1, "CSSELR_EL1" },
+        { ArmISA::MISCREG_CTR_EL0, "CTR_EL0" },
+        { ArmISA::MISCREG_DCZID_EL0, "DCZID_EL0" },
+        { ArmISA::MISCREG_VPIDR_EL2, "VPIDR_EL2" },
+        { ArmISA::MISCREG_VMPIDR_EL2, "VMPIDR_EL2" },
+        { ArmISA::MISCREG_SCTLR_EL1, "SCTLR_EL1" },
+        { ArmISA::MISCREG_ACTLR_EL1, "ACTLR_EL1" },
+        { ArmISA::MISCREG_CPACR_EL1, "CPACR_EL1" },
+        { ArmISA::MISCREG_SCTLR_EL2, "SCTLR_EL2" },
+        { ArmISA::MISCREG_ACTLR_EL2, "ACTLR_EL2" },
+        { ArmISA::MISCREG_HCR_EL2, "HCR_EL2" },
+        { ArmISA::MISCREG_MDCR_EL2, "MDCR_EL2" },
+        { ArmISA::MISCREG_CPTR_EL2, "CPTR_EL2" },
+        { ArmISA::MISCREG_HSTR_EL2, "HSTR_EL2" },
+        { ArmISA::MISCREG_HACR_EL2, "HACR_EL2" },
+        { ArmISA::MISCREG_SCTLR_EL3, "SCTLR_EL3" },
+        { ArmISA::MISCREG_ACTLR_EL3, "ACTLR_EL3" },
+        { ArmISA::MISCREG_SCR_EL3, "SCR_EL3" },
+        // ArmISA::MISCREG_SDER32_EL3?
+        { ArmISA::MISCREG_CPTR_EL3, "CPTR_EL3" },
+        { ArmISA::MISCREG_MDCR_EL3, "MDCR_EL3" },
+        { ArmISA::MISCREG_TTBR0_EL1, "TTBR0_EL1" },
+        { ArmISA::MISCREG_TTBR1_EL1, "TTBR1_EL1" },
+        { ArmISA::MISCREG_TCR_EL1, "TCR_EL1" },
+        { ArmISA::MISCREG_TTBR0_EL2, "TTBR0_EL2" },
+        { ArmISA::MISCREG_TCR_EL2, "TCR_EL2" },
+        { ArmISA::MISCREG_VTTBR_EL2, "VTTBR_EL2" },
+        { ArmISA::MISCREG_VTCR_EL2, "VTCR_EL2" },
+        { ArmISA::MISCREG_TTBR0_EL3, "TTBR0_EL3" },
+        { ArmISA::MISCREG_TCR_EL3, "TCR_EL3" },
+        // ArmISA::MISCREG_DACR32_EL2?
+        { ArmISA::MISCREG_SPSR_EL1, "SPSR_EL1" },
+        { ArmISA::MISCREG_ELR_EL1, "ELR_EL1" },
+        { ArmISA::MISCREG_SP_EL0, "SP_EL0" },
+        // ArmISA::MISCREG_SPSEL?
+        // ArmISA::MISCREG_CURRENTEL?
+        // ArmISA::MISCREG_NZCV?
+        // ArmISA::MISCREG_DAIF?
+        { ArmISA::MISCREG_FPCR, "FPCR" },
+        { ArmISA::MISCREG_FPSR, "FPSR" },
+        { ArmISA::MISCREG_DSPSR_EL0, "DSPSR_EL0" },
+        { ArmISA::MISCREG_DLR_EL0, "DLR_EL0" },
+        { ArmISA::MISCREG_SPSR_EL2, "SPSR_EL2" },
+        { ArmISA::MISCREG_ELR_EL2, "ELR_EL2" },
+        { ArmISA::MISCREG_SP_EL1, "SP_EL1" },
+        // ArmISA::MISCREG_SPSR_IRQ_AA64?
+        // ArmISA::MISCREG_SPSR_ABT_AA64?
+        // ArmISA::MISCREG_SPSR_UND_AA64?
+        // ArmISA::MISCREG_SPSR_FIQ_AA64?
+        { ArmISA::MISCREG_SPSR_EL3, "SPSR_EL3" },
+        { ArmISA::MISCREG_ELR_EL3, "ELR_EL3" },
+        { ArmISA::MISCREG_SP_EL2, "SP_EL2" },
+        { ArmISA::MISCREG_AFSR0_EL1, "AFSR0_EL1" },
+        { ArmISA::MISCREG_AFSR1_EL1, "AFSR1_EL1" },
+        { ArmISA::MISCREG_ESR_EL1, "ESR_EL1" },
+        // ArmISA::MISCREG_IFSR32_EL2?
+        { ArmISA::MISCREG_AFSR0_EL2, "AFSR0_EL2" },
+        { ArmISA::MISCREG_AFSR1_EL2, "AFSR1_EL2" },
+        { ArmISA::MISCREG_ESR_EL2, "ESR_EL2" },
+        // ArmISA::MISCREG_FPEXC32_EL2?
+        { ArmISA::MISCREG_AFSR0_EL3, "AFSR0_EL3" },
+        { ArmISA::MISCREG_AFSR1_EL3, "AFSR1_EL3" },
+        { ArmISA::MISCREG_ESR_EL3, "ESR_EL3" },
+        { ArmISA::MISCREG_FAR_EL1, "FAR_EL1" },
+        { ArmISA::MISCREG_FAR_EL2, "FAR_EL2" },
+        { ArmISA::MISCREG_HPFAR_EL2, "HPFAR_EL2" },
+        { ArmISA::MISCREG_FAR_EL3, "FAR_EL3" },
+        { ArmISA::MISCREG_IC_IALLUIS, "IC IALLUIS" },
+        { ArmISA::MISCREG_PAR_EL1, "PAR_EL1" },
+        { ArmISA::MISCREG_IC_IALLU, "IC IALLU" },
+        { ArmISA::MISCREG_DC_IVAC_Xt, "DC IVAC" }, //XXX verify
+        { ArmISA::MISCREG_DC_ISW_Xt, "DC ISW" }, //XXX verify
+        { ArmISA::MISCREG_AT_S1E1R_Xt, "AT S1E1R" }, //XXX verify
+        { ArmISA::MISCREG_AT_S1E1W_Xt, "AT S1E1W" }, //XXX verify
+        { ArmISA::MISCREG_AT_S1E0R_Xt, "AT S1E0R" }, //XXX verify
+        { ArmISA::MISCREG_AT_S1E0W_Xt, "AT S1E0W" }, //XXX verify
+        { ArmISA::MISCREG_DC_CSW_Xt, "DC CSW" }, //XXX verify
+        { ArmISA::MISCREG_DC_CISW_Xt, "DC CISW" }, //XXX verify
+        { ArmISA::MISCREG_DC_ZVA_Xt, "DC ZVA" }, //XXX verify
+        { ArmISA::MISCREG_IC_IVAU_Xt, "IC IVAU" }, //XXX verify
+        { ArmISA::MISCREG_DC_CVAC_Xt, "DC CVAC" }, //XXX verify
+        { ArmISA::MISCREG_DC_CVAU_Xt, "DC CVAU" }, //XXX verify
+        { ArmISA::MISCREG_DC_CIVAC_Xt, "DC CIVAC" }, //XXX verify
+        { ArmISA::MISCREG_AT_S1E2R_Xt, "AT S1E2R" }, //XXX verify
+        { ArmISA::MISCREG_AT_S1E2W_Xt, "AT S1E2W" }, //XXX verify
+        { ArmISA::MISCREG_AT_S12E1R_Xt, "AT S12E1R" }, //XXX verify
+        { ArmISA::MISCREG_AT_S12E1W_Xt, "AT S12E1W" }, //XXX verify
+        { ArmISA::MISCREG_AT_S12E0R_Xt, "AT S12E0R" }, //XXX verify
+        { ArmISA::MISCREG_AT_S12E0W_Xt, "AT S12E0W" }, //XXX verify
+        { ArmISA::MISCREG_AT_S1E3R_Xt, "AT S1E3R" }, //XXX verify
+        { ArmISA::MISCREG_AT_S1E3W_Xt, "AT S1E3W" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_VMALLE1IS, "TLBI VMALLE1IS" },
+        { ArmISA::MISCREG_TLBI_VAE1IS_Xt, "TLBI VAE1IS" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_ASIDE1IS_Xt, "TLBI ASIDE1IS" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_VAAE1IS_Xt, "TLBI VAAE1IS" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_VALE1IS_Xt, "TLBI VALE1IS" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_VAALE1IS_Xt, "TLBI VAALE1IS" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_VMALLE1, "TLBI VMALLE1" },
+        { ArmISA::MISCREG_TLBI_VAE1_Xt, "TLBI VAE1" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_ASIDE1_Xt, "TLBI ASIDE1" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_VAAE1_Xt, "TLBI VAAE1" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_VALE1_Xt, "TLBI VALE1" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_VAALE1_Xt, "TLBI VAALE1" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_IPAS2E1IS_Xt, "TLBI IPAS2E1IS" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_IPAS2LE1IS_Xt, "TLBI IPAS2LE1IS" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_ALLE2IS, "TLBI ALLE2IS" },
+        { ArmISA::MISCREG_TLBI_VAE2IS_Xt, "TLBI VAE2IS" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_ALLE1IS, "TLBI ALLE1IS" },
+        { ArmISA::MISCREG_TLBI_VALE2IS_Xt, "TLBI VALE2IS" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_VMALLS12E1IS, "TLBI VMALLS12E1IS" },
+        { ArmISA::MISCREG_TLBI_IPAS2E1_Xt, "TLBI IPAS2E1" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_IPAS2LE1_Xt, "TLBI IPAS2LE1" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_ALLE2, "TLBI ALLE2" },
+        { ArmISA::MISCREG_TLBI_VAE2_Xt, "TLBI VAE2" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_ALLE1, "TLBI ALLE1" },
+        { ArmISA::MISCREG_TLBI_VALE2_Xt, "TLBI VALE2" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_VMALLS12E1, "TLBI VMALLS12E1" },
+        { ArmISA::MISCREG_TLBI_ALLE3IS, "TLBI ALLE3IS" },
+        { ArmISA::MISCREG_TLBI_VAE3IS_Xt, "TLBI VAE3IS" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_VALE3IS_Xt, "TLBI VALE3IS" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_ALLE3, "TLBI ALLE3" },
+        { ArmISA::MISCREG_TLBI_VAE3_Xt, "TLBI VAE3" }, //XXX verify
+        { ArmISA::MISCREG_TLBI_VALE3_Xt, "TLBI VALE3" }, //XXX verify
+        { ArmISA::MISCREG_PMINTENSET_EL1, "PMINTENSET_EL1" },
+        { ArmISA::MISCREG_PMINTENCLR_EL1, "PMINTENCLR_EL1" },
+        { ArmISA::MISCREG_PMCR_EL0, "PMCR_EL0" },
+        { ArmISA::MISCREG_PMCNTENSET_EL0, "PMCNTENSET_EL0" },
+        { ArmISA::MISCREG_PMCNTENCLR_EL0, "PMCNTENCLR_EL0" },
+        { ArmISA::MISCREG_PMOVSCLR_EL0, "PMOVSCLR_EL0" },
+        { ArmISA::MISCREG_PMSWINC_EL0, "PMSWINC_EL0" },
+        { ArmISA::MISCREG_PMSELR_EL0, "PMSELR_EL0" },
+        { ArmISA::MISCREG_PMCEID0_EL0, "PMCEID0_EL0" },
+        { ArmISA::MISCREG_PMCEID1_EL0, "PMCEID1_EL0" },
+        { ArmISA::MISCREG_PMCCNTR_EL0, "PMCCNTR_EL0" },
+        { ArmISA::MISCREG_PMXEVTYPER_EL0, "PMXEVTYPER_EL0" },
+        { ArmISA::MISCREG_PMCCFILTR_EL0, "PMCCFILTR_EL0" },
+        { ArmISA::MISCREG_PMXEVCNTR_EL0, "PMXEVCNTR_EL0" },
+        { ArmISA::MISCREG_PMUSERENR_EL0, "PMUSERENR_EL0" },
+        { ArmISA::MISCREG_PMOVSSET_EL0, "PMOVSSET_EL0" },
+        { ArmISA::MISCREG_MAIR_EL1, "MAIR_EL1" },
+        { ArmISA::MISCREG_AMAIR_EL1, "AMAIR_EL1" },
+        { ArmISA::MISCREG_MAIR_EL2, "MAIR_EL2" },
+        { ArmISA::MISCREG_AMAIR_EL2, "AMAIR_EL2" },
+        { ArmISA::MISCREG_MAIR_EL3, "MAIR_EL3" },
+        { ArmISA::MISCREG_AMAIR_EL3, "AMAIR_EL3" },
+        // ArmISA::MISCREG_L2CTLR_EL1?
+        // ArmISA::MISCREG_L2ECTLR_EL1?
+        { ArmISA::MISCREG_VBAR_EL1, "VBAR_EL1" },
+        // ArmISA::MISCREG_RVBAR_EL1?
+        { ArmISA::MISCREG_ISR_EL1, "ISR_EL1" },
+        { ArmISA::MISCREG_VBAR_EL2, "VBAR_EL2" },
+        // ArmISA::MISCREG_RVBAR_EL2?
+        { ArmISA::MISCREG_VBAR_EL3, "VBAR_EL3" },
+        { ArmISA::MISCREG_RVBAR_EL3, "RVBAR_EL3" },
+        { ArmISA::MISCREG_RMR_EL3, "RMR_EL3" },
+        { ArmISA::MISCREG_CONTEXTIDR_EL1, "CONTEXTIDR_EL1" },
+        { ArmISA::MISCREG_TPIDR_EL1, "TPIDR_EL1" },
+        { ArmISA::MISCREG_TPIDR_EL0, "TPIDR_EL0" },
+        { ArmISA::MISCREG_TPIDRRO_EL0, "TPIDRRO_EL0" },
+        { ArmISA::MISCREG_TPIDR_EL2, "TPIDR_EL2" },
+        { ArmISA::MISCREG_TPIDR_EL3, "TPIDR_EL3" },
+        { ArmISA::MISCREG_CNTKCTL_EL1, "CNTKCTL_EL1" },
+        { ArmISA::MISCREG_CNTFRQ_EL0, "CNTFRQ_EL0" },
+        { ArmISA::MISCREG_CNTPCT_EL0, "CNTPCT_EL0" },
+        { ArmISA::MISCREG_CNTVCT_EL0, "CNTVCT_EL0" },
+        { ArmISA::MISCREG_CNTP_TVAL_EL0, "CNTP_TVAL_EL0" },
+        { ArmISA::MISCREG_CNTP_CTL_EL0, "CNTP_CTL_EL0" },
+        { ArmISA::MISCREG_CNTP_CVAL_EL0, "CNTP_CVAL_EL0" },
+        { ArmISA::MISCREG_CNTV_TVAL_EL0, "CNTV_TVAL_EL0" },
+        { ArmISA::MISCREG_CNTV_CTL_EL0, "CNTV_CTL_EL0" },
+        { ArmISA::MISCREG_CNTV_CVAL_EL0, "CNTV_CVAL_EL0" },
+        { ArmISA::MISCREG_PMEVCNTR0_EL0, "PMEVCNTR0_EL0" },
+        { ArmISA::MISCREG_PMEVCNTR1_EL0, "PMEVCNTR1_EL0" },
+        { ArmISA::MISCREG_PMEVCNTR2_EL0, "PMEVCNTR2_EL0" },
+        { ArmISA::MISCREG_PMEVCNTR3_EL0, "PMEVCNTR3_EL0" },
+        { ArmISA::MISCREG_PMEVCNTR4_EL0, "PMEVCNTR4_EL0" },
+        { ArmISA::MISCREG_PMEVCNTR5_EL0, "PMEVCNTR5_EL0" },
+        { ArmISA::MISCREG_PMEVTYPER0_EL0, "PMEVTYPER0_EL0" },
+        { ArmISA::MISCREG_PMEVTYPER1_EL0, "PMEVTYPER1_EL0" },
+        { ArmISA::MISCREG_PMEVTYPER2_EL0, "PMEVTYPER2_EL0" },
+        { ArmISA::MISCREG_PMEVTYPER3_EL0, "PMEVTYPER3_EL0" },
+        { ArmISA::MISCREG_PMEVTYPER4_EL0, "PMEVTYPER4_EL0" },
+        { ArmISA::MISCREG_PMEVTYPER5_EL0, "PMEVTYPER5_EL0" },
+        { ArmISA::MISCREG_CNTVOFF_EL2, "CNTVOFF_EL2" },
+        { ArmISA::MISCREG_CNTHCTL_EL2, "CNTHCTL_EL2" },
+        { ArmISA::MISCREG_CNTHP_TVAL_EL2, "CNTHP_TVAL_EL2" },
+        { ArmISA::MISCREG_CNTHP_CTL_EL2, "CNTHP_CTL_EL2" },
+        { ArmISA::MISCREG_CNTHP_CVAL_EL2, "CNTHP_CVAL_EL2" },
+        { ArmISA::MISCREG_CNTPS_TVAL_EL1, "CNTPS_TVAL_EL1" },
+        { ArmISA::MISCREG_CNTPS_CTL_EL1, "CNTPS_CTL_EL1" },
+        { ArmISA::MISCREG_CNTPS_CVAL_EL1, "CNTPS_CVAL_EL1" },
+        // ArmISA::MISCREG_IL1DATA0_EL1?
+        // ArmISA::MISCREG_IL1DATA1_EL1?
+        // ArmISA::MISCREG_IL1DATA2_EL1?
+        // ArmISA::MISCREG_IL1DATA3_EL1?
+        // ArmISA::MISCREG_DL1DATA0_EL1?
+        // ArmISA::MISCREG_DL1DATA1_EL1?
+        // ArmISA::MISCREG_DL1DATA2_EL1?
+        // ArmISA::MISCREG_DL1DATA3_EL1?
+        // ArmISA::MISCREG_DL1DATA4_EL1?
+        // ArmISA::MISCREG_L2ACTLR_EL1?
+        { ArmISA::MISCREG_CPUACTLR_EL1, "CPUACTLR_EL1" },
+        { ArmISA::MISCREG_CPUECTLR_EL1, "CPUECTLR_EL1" },
+        { ArmISA::MISCREG_CPUMERRSR_EL1, "CPUMERRSR_EL1" },
+        { ArmISA::MISCREG_L2MERRSR_EL1, "L2MERRSR_EL1" },
+        // ArmISA::MISCREG_CBAR_EL1?
+        { ArmISA::MISCREG_CONTEXTIDR_EL2, "CONTEXTIDR_EL2" },
+
+        // Introduced in ARMv8.1
+        { ArmISA::MISCREG_TTBR1_EL2, "TTBR1_EL2" },
+        { ArmISA::MISCREG_CNTHV_CTL_EL2, "CNTHV_CTL_EL2" },
+        { ArmISA::MISCREG_CNTHV_CVAL_EL2, "CNTHV_CVAL_EL2" },
+        { ArmISA::MISCREG_CNTHV_TVAL_EL2, "CNTHV_TVAL_EL2" },
+
+        // RAS extension (unimplemented)
+        { ArmISA::MISCREG_ERRIDR_EL1, "ERRIDR_EL1" },
+        { ArmISA::MISCREG_ERRSELR_EL1, "ERRSELR_EL1" },
+        { ArmISA::MISCREG_ERXFR_EL1, "ERXFR_EL1" },
+        { ArmISA::MISCREG_ERXCTLR_EL1, "ERXCTLR_EL1" },
+        { ArmISA::MISCREG_ERXSTATUS_EL1, "ERXSTATUS_EL1" },
+        { ArmISA::MISCREG_ERXADDR_EL1, "ERXADDR_EL1" },
+        { ArmISA::MISCREG_ERXMISC0_EL1, "ERXMISC0_EL1" },
+        { ArmISA::MISCREG_ERXMISC1_EL1, "ERXMISC1_EL1" },
+        { ArmISA::MISCREG_DISR_EL1, "DISR_EL1" },
+        { ArmISA::MISCREG_VSESR_EL2, "VSESR_EL2" },
+        { ArmISA::MISCREG_VDISR_EL2, "VDISR_EL2" }
+});
+
+Iris::ThreadContext::IdxNameMap ArmThreadContext::intReg32IdxNameMap({
+        { ArmISA::INTREG_R0, "R0" },
+        { ArmISA::INTREG_R1, "R1" },
+        { ArmISA::INTREG_R2, "R2" },
+        { ArmISA::INTREG_R3, "R3" },
+        { ArmISA::INTREG_R4, "R4" },
+        { ArmISA::INTREG_R5, "R5" },
+        { ArmISA::INTREG_R6, "R6" },
+        { ArmISA::INTREG_R7, "R7" },
+        { ArmISA::INTREG_R8, "R8" },
+        { ArmISA::INTREG_R9, "R9" },
+        { ArmISA::INTREG_R10, "R10" },
+        { ArmISA::INTREG_R11, "R11" },
+        { ArmISA::INTREG_R12, "R12" },
+        { ArmISA::INTREG_R13, "R13" },
+        { ArmISA::INTREG_R14, "R14" },
+        { ArmISA::INTREG_R15, "R15" }
+});
+
+Iris::ThreadContext::IdxNameMap ArmThreadContext::intReg64IdxNameMap({
+        { ArmISA::INTREG_X0, "X0" },
+        { ArmISA::INTREG_X1, "X1" },
+        { ArmISA::INTREG_X2, "X2" },
+        { ArmISA::INTREG_X3, "X3" },
+        { ArmISA::INTREG_X4, "X4" },
+        { ArmISA::INTREG_X5, "X5" },
+        { ArmISA::INTREG_X6, "X6" },
+        { ArmISA::INTREG_X7, "X7" },
+        { ArmISA::INTREG_X8, "X8" },
+        { ArmISA::INTREG_X9, "X9" },
+        { ArmISA::INTREG_X10, "X10" },
+        { ArmISA::INTREG_X11, "X11" },
+        { ArmISA::INTREG_X12, "X12" },
+        { ArmISA::INTREG_X13, "X13" },
+        { ArmISA::INTREG_X14, "X14" },
+        { ArmISA::INTREG_X15, "X15" },
+        { ArmISA::INTREG_X16, "X16" },
+        { ArmISA::INTREG_X17, "X17" },
+        { ArmISA::INTREG_X18, "X18" },
+        { ArmISA::INTREG_X19, "X19" },
+        { ArmISA::INTREG_X20, "X20" },
+        { ArmISA::INTREG_X21, "X21" },
+        { ArmISA::INTREG_X22, "X22" },
+        { ArmISA::INTREG_X23, "X23" },
+        { ArmISA::INTREG_X24, "X24" },
+        { ArmISA::INTREG_X25, "X25" },
+        { ArmISA::INTREG_X26, "X26" },
+        { ArmISA::INTREG_X27, "X27" },
+        { ArmISA::INTREG_X28, "X28" },
+        { ArmISA::INTREG_X29, "X29" },
+        { ArmISA::INTREG_X30, "X30" },
+        { ArmISA::INTREG_SPX, "SP" },
+});
+
+} // namespace Iris
diff --git a/src/arch/arm/fastmodel/iris/arm/thread_context.hh b/src/arch/arm/fastmodel/iris/arm/thread_context.hh
new file mode 100644
index 0000000..c747eba
--- /dev/null
+++ b/src/arch/arm/fastmodel/iris/arm/thread_context.hh
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#ifndef __ARCH_ARM_FASTMODEL_IRIS_ARM_THREAD_CONTEXT_HH__
+#define __ARCH_ARM_FASTMODEL_IRIS_ARM_THREAD_CONTEXT_HH__
+
+#include "arch/arm/fastmodel/iris/thread_context.hh"
+
+namespace Iris
+{
+
+// This ThreadContext class translates accesses to state using gem5's native
+// to the Iris API. This includes extracting and translating register indices.
+class ArmThreadContext : public Iris::ThreadContext
+{
+  protected:
+    static IdxNameMap miscRegIdxNameMap;
+    static IdxNameMap intReg32IdxNameMap;
+    static IdxNameMap intReg64IdxNameMap;
+
+  public:
+    ArmThreadContext(::BaseCPU *cpu, int id, System *system,
+                     iris::IrisConnectionInterface *iris_if,
+                     const std::string &iris_path);
+
+    void initFromIrisInstance(const ResourceMap &resources) override;
+
+    TheISA::PCState pcState() const override;
+    void pcState(const TheISA::PCState &val) override;
+    Addr instAddr() const override;
+    Addr nextInstAddr() const override;
+
+    iris::ResourceId pcRscId;
+    iris::ResourceId icountRscId;
+
+    ResourceIds intReg32Ids;
+    ResourceIds intReg64Ids;
+
+    Counter totalInsts() override;
+
+    void setIntReg(RegIndex reg_idx, RegVal val) override;
+    RegVal readIntReg(RegIndex reg_idx) const override;
+    TheISA::ISA *
+    getIsaPtr() override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+};
+
+} // namespace Iris
+
+#endif // __ARCH_ARM_FASTMODEL_IRIS_ARM_THREAD_CONTEXT_HH__
diff --git a/src/arch/arm/fastmodel/iris/cpu.cc b/src/arch/arm/fastmodel/iris/cpu.cc
new file mode 100644
index 0000000..67de40e
--- /dev/null
+++ b/src/arch/arm/fastmodel/iris/cpu.cc
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#include "arch/arm/fastmodel/iris/cpu.hh"
+
+#include "arch/arm/fastmodel/iris/thread_context.hh"
+
+namespace Iris
+{
+
+BaseCPU::~BaseCPU()
+{
+    for (auto &tc: threadContexts)
+        delete tc;
+    threadContexts.clear();
+}
+
+Counter
+BaseCPU::totalInsts() const
+{
+    Counter count = 0;
+    for (auto *tc: threadContexts) {
+        auto *itc = dynamic_cast<Iris::ThreadContext *>(tc);
+        count += itc->totalInsts();
+    }
+    return count;
+}
+
+} // namespace Iris
diff --git a/src/arch/arm/fastmodel/iris/cpu.hh b/src/arch/arm/fastmodel/iris/cpu.hh
new file mode 100644
index 0000000..01c25af
--- /dev/null
+++ b/src/arch/arm/fastmodel/iris/cpu.hh
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#ifndef __ARCH_ARM_FASTMODEL_IRIS_CPU_HH__
+#define __ARCH_ARM_FASTMODEL_IRIS_CPU_HH__
+
+#include "cpu/base.hh"
+#include "iris/detail/IrisInterface.h"
+#include "params/IrisBaseCPU.hh"
+#include "systemc/ext/core/sc_attr.hh"
+#include "systemc/ext/core/sc_event.hh"
+#include "systemc/ext/core/sc_module.hh"
+
+namespace Iris
+{
+
+// The name of the event that should be notified when the CPU subsystem needs
+// to adjust it's clock.
+static const std::string ClockEventName = "gem5_clock_period_event";
+// 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";
+
+// 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
+// holds a pointer to the EVS. It also has some methods for setting up some
+// attributes in the fast model CPU to control its clock rate.
+class BaseCPU : public ::BaseCPU
+{
+  public:
+    BaseCPU(BaseCPUParams *params, sc_core::sc_module *_evs) :
+        ::BaseCPU::BaseCPU(params), evs(_evs),
+        clockEvent(nullptr), periodAttribute(nullptr)
+    {}
+    virtual ~BaseCPU();
+
+    Port &
+    getDataPort() override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    Port &
+    getInstPort() override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    void
+    wakeup(ThreadID tid) override
+    {
+        auto *tc = threadContexts.at(tid);
+        if (tc->status() == ::ThreadContext::Suspended)
+            tc->activate();
+    }
+
+    Counter totalInsts() const override;
+    Counter totalOps() const override { return totalInsts(); }
+
+  protected:
+    sc_core::sc_module *evs;
+
+  private:
+    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()) {
+            warn("Unable to notify EVS of clock change, missing:");
+            warn_if(!clockEvent, "  Clock change event");
+            warn_if(!periodAttribute, "  Clock period attribute");
+            return;
+        }
+
+        periodAttribute->value = clockPeriod();
+        clockEvent->notify();
+    }
+};
+
+// This class specializes the one above and sets up ThreadContexts based on
+// its template parameters. These ThreadContexts provide the standard gem5
+// interface and translate those accesses to use the Iris API to access that
+// state in the target context.
+template <class TC>
+class CPU : public Iris::BaseCPU
+{
+  public:
+    CPU(IrisBaseCPUParams *params, iris::IrisConnectionInterface *iris_if) :
+        BaseCPU(params, params->evs)
+    {
+        const std::string parent_path = evs->name();
+        System *sys = params->system;
+
+        int thread_id = 0;
+        for (const std::string &sub_path: params->core_paths) {
+            std::string path = parent_path + "." + sub_path;
+            auto *tc = new TC(this, thread_id++, sys, iris_if, path);
+            threadContexts.push_back(tc);
+        }
+    }
+};
+
+} // namespace Iris
+
+#endif // __ARCH_ARM_FASTMODEL_IRIS_CPU_HH__
diff --git a/src/arch/arm/fastmodel/iris/thread_context.cc b/src/arch/arm/fastmodel/iris/thread_context.cc
new file mode 100644
index 0000000..79c9062
--- /dev/null
+++ b/src/arch/arm/fastmodel/iris/thread_context.cc
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#include "arch/arm/fastmodel/iris/thread_context.hh"
+
+#include "iris/detail/IrisCppAdapter.h"
+#include "iris/detail/IrisObjects.h"
+
+namespace Iris
+{
+
+void
+ThreadContext::initFromIrisInstance(const ResourceMap &resources)
+{
+    bool enabled = false;
+    call().perInstanceExecution_getState(_instId, enabled);
+    _status = enabled ? Active : Suspended;
+
+    suspend();
+}
+
+iris::ResourceId
+ThreadContext::extractResourceId(
+        const ResourceMap &resources, const std::string &name)
+{
+    return resources.at(name).rscId;
+}
+
+void
+ThreadContext::extractResourceMap(
+        ResourceIds &ids, const ResourceMap &resources,
+        const IdxNameMap &idx_names)
+{
+    for (const auto &idx_name: idx_names) {
+        int idx = idx_name.first;
+        const std::string &name = idx_name.second;
+
+        if (idx >= ids.size())
+            ids.resize(idx + 1, iris::IRIS_UINT64_MAX);
+
+        ids[idx] = extractResourceId(resources, name);
+    }
+}
+
+iris::IrisErrorCode
+ThreadContext::instanceRegistryChanged(
+        uint64_t esId, const iris::IrisValueMap &fields, uint64_t time,
+        uint64_t sInstId, bool syncEc, std::string &error_message_out)
+{
+    const std::string &event = fields.at("EVENT").getString();
+    const iris::InstanceId id = fields.at("INST_ID").getU64();
+    const std::string &name = fields.at("INST_NAME").getString();
+
+    if (name != "component." + _irisPath)
+        return iris::E_ok;
+
+    if (event == "added")
+        _instId = id;
+    else if (event == "removed")
+        _instId = iris::IRIS_UINT64_MAX;
+    else
+        panic("Unrecognized event type %s", event);
+
+    return iris::E_ok;
+}
+
+iris::IrisErrorCode
+ThreadContext::phaseInitLeave(
+        uint64_t esId, const iris::IrisValueMap &fields, uint64_t time,
+        uint64_t sInstId, bool syncEc, std::string &error_message_out)
+{
+    std::vector<iris::ResourceInfo> resources;
+    call().resource_getList(_instId, resources);
+
+    ResourceMap resourceMap;
+    for (auto &resource: resources)
+        resourceMap[resource.name] = resource;
+
+    initFromIrisInstance(resourceMap);
+
+    return iris::E_ok;
+}
+
+ThreadContext::ThreadContext(
+        BaseCPU *cpu, int id, System *system,
+        iris::IrisConnectionInterface *iris_if, const std::string &iris_path) :
+    _cpu(cpu), _threadId(id), _system(system), _irisPath(iris_path),
+    _instId(iris::IRIS_UINT64_MAX), _status(Active),
+    client(iris_if, "client." + iris_path)
+{
+    iris::InstanceInfo info;
+    auto ret_code = noThrow().instanceRegistry_getInstanceInfoByName(
+                info, "component." + iris_path);
+    if (ret_code == iris::E_ok) {
+        // The iris instance registry already new about this path.
+        _instId = info.instId;
+    } else {
+        // This path doesn't (yet) exist. Set the ID to something invalid.
+        _instId = iris::IRIS_UINT64_MAX;
+    }
+
+    typedef ThreadContext Self;
+    iris::EventSourceInfo evSrcInfo;
+
+    client.registerEventCallback<Self, &Self::instanceRegistryChanged>(
+            this, "ec_IRIS_INSTANCE_REGISTRY_CHANGED",
+            "Install the iris instance ID", "Iris::ThreadContext");
+    call().event_getEventSource(iris::IrisInstIdGlobalInstance, evSrcInfo,
+            "IRIS_INSTANCE_REGISTRY_CHANGED");
+    regEventStreamId = iris::IRIS_UINT64_MAX;
+    static const std::vector<std::string> fields =
+        { "EVENT", "INST_ID", "INST_NAME" };
+    call().eventStream_create(iris::IrisInstIdGlobalInstance, regEventStreamId,
+            evSrcInfo.evSrcId, client.getInstId(), &fields);
+
+    client.registerEventCallback<Self, &Self::phaseInitLeave>(
+            this, "ec_IRIS_SIM_PHASE_INIT_LEAVE",
+            "Initialize register contexts", "Iris::ThreadContext");
+    call().event_getEventSource(iris::IrisInstIdSimulationEngine, evSrcInfo,
+            "IRIS_SIM_PHASE_INIT_LEAVE");
+    initEventStreamId = iris::IRIS_UINT64_MAX;
+    call().eventStream_create(
+            iris::IrisInstIdSimulationEngine, initEventStreamId,
+            evSrcInfo.evSrcId, client.getInstId());
+}
+
+ThreadContext::~ThreadContext()
+{
+    call().eventStream_destroy(
+            iris::IrisInstIdSimulationEngine, initEventStreamId);
+    initEventStreamId = iris::IRIS_UINT64_MAX;
+    client.unregisterEventCallback("ec_IRIS_SIM_PHASE_INIT_LEAVE");
+
+    call().eventStream_destroy(
+            iris::IrisInstIdGlobalInstance, regEventStreamId);
+    regEventStreamId = iris::IRIS_UINT64_MAX;
+    client.unregisterEventCallback("ec_IRIS_INSTANCE_REGISTRY_CHANGED");
+}
+
+ThreadContext::Status
+ThreadContext::status() const
+{
+    return _status;
+}
+
+void
+ThreadContext::setStatus(Status new_status)
+{
+    if (new_status == Active) {
+        if (_status != Active)
+            call().perInstanceExecution_setState(_instId, true);
+    } else {
+        if (_status == Active)
+            call().perInstanceExecution_setState(_instId, false);
+    }
+    _status = new_status;
+}
+
+RegVal
+ThreadContext::readMiscRegNoEffect(RegIndex misc_reg) const
+{
+    iris::ResourceReadResult result;
+    call().resource_read(_instId, result, miscRegIds.at(misc_reg));
+    return result.data.at(0);
+}
+
+void
+ThreadContext::setMiscRegNoEffect(RegIndex misc_reg, const RegVal val)
+{
+    iris::ResourceWriteResult result;
+    call().resource_write(_instId, result, miscRegIds.at(misc_reg), val);
+}
+
+RegVal
+ThreadContext::readIntReg(RegIndex reg_idx) const
+{
+    iris::ResourceReadResult result;
+    call().resource_read(_instId, result, intRegIds.at(reg_idx));
+    return result.data.at(0);
+}
+
+void
+ThreadContext::setIntReg(RegIndex reg_idx, RegVal val)
+{
+    iris::ResourceWriteResult result;
+    call().resource_write(_instId, result, intRegIds.at(reg_idx), val);
+}
+
+} // namespace Iris
diff --git a/src/arch/arm/fastmodel/iris/thread_context.hh b/src/arch/arm/fastmodel/iris/thread_context.hh
new file mode 100644
index 0000000..5be5e71
--- /dev/null
+++ b/src/arch/arm/fastmodel/iris/thread_context.hh
@@ -0,0 +1,505 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#ifndef __ARCH_ARM_FASTMODEL_IRIS_THREAD_CONTEXT_HH__
+#define __ARCH_ARM_FASTMODEL_IRIS_THREAD_CONTEXT_HH__
+
+#include "cpu/base.hh"
+#include "cpu/thread_context.hh"
+#include "iris/IrisInstance.h"
+#include "iris/detail/IrisErrorCode.h"
+#include "iris/detail/IrisObjects.h"
+#include "sim/system.hh"
+
+namespace Iris
+{
+
+// This class is the base for ThreadContexts which read and write state using
+// the Iris API.
+class ThreadContext : public ::ThreadContext
+{
+  public:
+    typedef std::map<std::string, iris::ResourceInfo> ResourceMap;
+
+    typedef std::vector<iris::ResourceId> ResourceIds;
+    typedef std::map<int, std::string> IdxNameMap;
+
+  protected:
+    ::BaseCPU *_cpu;
+    int _threadId;
+    ContextID _contextId;
+    System *_system;
+
+    std::string _irisPath;
+    iris::InstanceId _instId;
+
+    Status _status;
+
+    virtual void initFromIrisInstance(const ResourceMap &resources);
+
+    iris::ResourceId extractResourceId(
+            const ResourceMap &resources, const std::string &name);
+    void extractResourceMap(ResourceIds &ids,
+            const ResourceMap &resources, const IdxNameMap &idx_names);
+
+
+    ResourceIds miscRegIds;
+    ResourceIds intRegIds;
+
+
+    iris::IrisErrorCode instanceRegistryChanged(
+            uint64_t esId, const iris::IrisValueMap &fields, uint64_t time,
+            uint64_t sInstId, bool syncEc, std::string &error_message_out);
+    iris::IrisErrorCode phaseInitLeave(
+            uint64_t esId, const iris::IrisValueMap &fields, uint64_t time,
+            uint64_t sInstId, bool syncEc, std::string &error_message_out);
+
+    iris::EventStreamId regEventStreamId;
+    iris::EventStreamId initEventStreamId;
+
+    mutable iris::IrisInstance client;
+    iris::IrisCppAdapter &call() const { return client.irisCall(); }
+    iris::IrisCppAdapter &noThrow() const { return client.irisCallNoThrow(); }
+
+  public:
+    ThreadContext(::BaseCPU *cpu, int id, System *system,
+                  iris::IrisConnectionInterface *iris_if,
+                  const std::string &iris_path);
+    virtual ~ThreadContext();
+
+    virtual Counter
+    totalInsts()
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    ::BaseCPU *getCpuPtr() override { return _cpu; }
+    int cpuId() const override { return _cpu->cpuId(); }
+    uint32_t socketId() const override { return _cpu->socketId(); }
+
+    int threadId() const override { return _threadId; }
+    void setThreadId(int id) override { _threadId = id; }
+
+    int contextId() const override { return _contextId; }
+    void setContextId(int id) override { _contextId = id; }
+
+    BaseTLB *
+    getITBPtr() override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    BaseTLB *
+    getDTBPtr() override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    CheckerCPU *
+    getCheckerCpuPtr() override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    TheISA::Decoder *
+    getDecoderPtr() override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    System *getSystemPtr() override { return _cpu->system; }
+
+    Kernel::Statistics *
+    getKernelStats() override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    PortProxy &
+    getPhysProxy() override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    PortProxy &
+    getVirtProxy() override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    void
+    initMemProxies(::ThreadContext *tc) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    Process *
+    getProcessPtr() override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    void
+    setProcessPtr(Process *p) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    Status status() const override;
+    void setStatus(Status new_status) override;
+    void activate() override { setStatus(Active); }
+    void suspend() override { setStatus(Suspended); }
+    void halt() override { setStatus(Halted); }
+
+    void
+    dumpFuncProfile() override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    void
+    takeOverFrom(::ThreadContext *old_context) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    void regStats(const std::string &name) override {}
+
+    EndQuiesceEvent *
+    getQuiesceEvent() override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    // Not necessarily the best location for these...
+    // Having an extra function just to read these is obnoxious
+    Tick
+    readLastActivate() override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    Tick readLastSuspend() override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    void
+    profileClear() override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    void
+    profileSample() override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    void
+    copyArchRegs(::ThreadContext *tc) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    void
+    clearArchRegs() override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    //
+    // New accessors for new decoder.
+    //
+    RegVal readIntReg(RegIndex reg_idx) const override;
+
+    RegVal
+    readFloatReg(RegIndex reg_idx) const override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    const VecRegContainer &
+    readVecReg(const RegId &reg) const override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    VecRegContainer &
+    getWritableVecReg(const RegId &reg) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    /** Vector Register Lane Interfaces. */
+    /** @{ */
+    /** Reads source vector 8bit operand. */
+    ConstVecLane8
+    readVec8BitLaneReg(const RegId &reg) const override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    /** Reads source vector 16bit operand. */
+    ConstVecLane16
+    readVec16BitLaneReg(const RegId &reg) const override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    /** Reads source vector 32bit operand. */
+    ConstVecLane32
+    readVec32BitLaneReg(const RegId &reg) const override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    /** Reads source vector 64bit operand. */
+    ConstVecLane64
+    readVec64BitLaneReg(const RegId &reg) const override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    /** Write a lane of the destination vector register. */
+    void
+    setVecLane(const RegId &reg, const LaneData<LaneSize::Byte> &val) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    void
+    setVecLane(const RegId &reg,
+               const LaneData<LaneSize::TwoByte> &val) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    void
+    setVecLane(const RegId &reg,
+               const LaneData<LaneSize::FourByte> &val) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    void
+    setVecLane(const RegId &reg,
+               const LaneData<LaneSize::EightByte> &val) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    /** @} */
+
+    const VecElem &
+    readVecElem(const RegId &reg) const override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    const VecPredRegContainer &
+    readVecPredReg(const RegId &reg) const override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    VecPredRegContainer &
+    getWritableVecPredReg(const RegId &reg) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    RegVal
+    readCCReg(RegIndex reg_idx) const override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    void setIntReg(RegIndex reg_idx, RegVal val) override;
+
+    void
+    setFloatReg(RegIndex reg_idx, RegVal val) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    void
+    setVecReg(const RegId &reg, const VecRegContainer &val) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    void
+    setVecElem(const RegId& reg, const VecElem& val) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    void
+    setVecPredReg(const RegId &reg,
+                  const VecPredRegContainer &val) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    void
+    setCCReg(RegIndex reg_idx, RegVal val) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    void pcStateNoRecord(const TheISA::PCState &val) override { pcState(val); }
+    MicroPC microPC() const override { return 0; }
+
+    RegVal readMiscRegNoEffect(RegIndex misc_reg) const override;
+    RegVal
+    readMiscReg(RegIndex misc_reg) override
+    {
+        return readMiscRegNoEffect(misc_reg);
+    }
+
+    void setMiscRegNoEffect(RegIndex misc_reg, const RegVal val) override;
+    void
+    setMiscReg(RegIndex misc_reg, const RegVal val) override
+    {
+        setMiscRegNoEffect(misc_reg, val);
+    }
+
+    RegId
+    flattenRegId(const RegId& regId) const override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    // Also not necessarily the best location for these two.  Hopefully will go
+    // away once we decide upon where st cond failures goes.
+    unsigned
+    readStCondFailures() const override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    void
+    setStCondFailures(unsigned sc_failures) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    // Same with st cond failures.
+    Counter
+    readFuncExeInst() const override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    void
+    syscall(int64_t callnum, Fault *fault) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    /** @{ */
+    /**
+     * Flat register interfaces
+     *
+     * Some architectures have different registers visible in
+     * different modes. Such architectures "flatten" a register (see
+     * flattenRegId()) to map it into the
+     * gem5 register file. This interface provides a flat interface to
+     * the underlying register file, which allows for example
+     * serialization code to access all registers.
+     */
+
+    uint64_t
+    readIntRegFlat(RegIndex idx) const override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    void
+    setIntRegFlat(RegIndex idx, uint64_t val) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    RegVal
+    readFloatRegFlat(RegIndex idx) const override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    void
+    setFloatRegFlat(RegIndex idx, RegVal val) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    const VecRegContainer &
+    readVecRegFlat(RegIndex idx) const override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    VecRegContainer &
+    getWritableVecRegFlat(RegIndex idx) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    void
+    setVecRegFlat(RegIndex idx, const VecRegContainer &val) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    const VecElem&
+    readVecElemFlat(RegIndex idx, const ElemIndex& elemIdx) const override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    void
+    setVecElemFlat(RegIndex idx, const ElemIndex &elemIdx,
+                   const VecElem &val) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    const VecPredRegContainer &
+    readVecPredRegFlat(RegIndex idx) const override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    VecPredRegContainer &
+    getWritableVecPredRegFlat(RegIndex idx) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    void
+    setVecPredRegFlat(RegIndex idx, const VecPredRegContainer &val) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+
+    RegVal
+    readCCRegFlat(RegIndex idx) const override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    void
+    setCCRegFlat(RegIndex idx, RegVal val) override
+    {
+        panic("%s not implemented.", __FUNCTION__);
+    }
+    /** @} */
+
+};
+
+} // namespace Iris
+
+#endif // __ARCH_ARM_FASTMODEL_IRIS_THREAD_CONTEXT_HH__
diff --git a/src/arch/arm/fastmodel/protocol/ExportedClockRateControlProtocol.lisa b/src/arch/arm/fastmodel/protocol/ExportedClockRateControlProtocol.lisa
new file mode 100644
index 0000000..141d047
--- /dev/null
+++ b/src/arch/arm/fastmodel/protocol/ExportedClockRateControlProtocol.lisa
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+protocol ExportedClockRateControl
+{
+    includes
+    {
+        #include "arch/arm/fastmodel/protocol/exported_clock_rate_control.hh"
+    }
+    properties
+    {
+        description = "Exportable version of the clock rate control protocol.";
+        version = "1.0";
+        dso_safe = 0;
+        sc_slave_base_class_name = "ClockRateControlSlaveBase";
+        sc_slave_socket_class_name = "ClockRateControlTargetSocket";
+    }
+
+    slave behavior set_mul_div(uint64_t mul, uint64_t div);
+}
diff --git a/src/arch/arm/fastmodel/protocol/SConscript b/src/arch/arm/fastmodel/protocol/SConscript
new file mode 100644
index 0000000..b0171f1
--- /dev/null
+++ b/src/arch/arm/fastmodel/protocol/SConscript
@@ -0,0 +1,29 @@
+# Copyright 2019 Google, Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Gabe Black
+
+Depends('ExportedClockRateControlProtocol.lisa',
+        'exported_clock_rate_control.hh')
diff --git a/src/arch/arm/fastmodel/protocol/exported_clock_rate_control.hh b/src/arch/arm/fastmodel/protocol/exported_clock_rate_control.hh
new file mode 100644
index 0000000..4cedd00
--- /dev/null
+++ b/src/arch/arm/fastmodel/protocol/exported_clock_rate_control.hh
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2019 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabe Black
+ */
+
+#ifndef __ARCH_ARM_FASTMODEL_PROTOCOL_EXPORTED_CLOCK_RATE_CONTROL_HH__
+#define __ARCH_ARM_FASTMODEL_PROTOCOL_EXPORTED_CLOCK_RATE_CONTROL_HH__
+
+#include <string>
+#include <systemc>
+#include <tlm>
+
+// This protocol is an exportable version of the clock rate protocol native to
+// fast models. It's identical to the original, except it has some extra info
+// which lets it be exported into systemc.
+
+struct ClockRateControlDummyProtocolType {};
+
+class ClockRateControlFwIf : public virtual sc_core::sc_interface
+{
+  public:
+    virtual ~ClockRateControlFwIf() {}
+    virtual void set_mul_div(uint64_t mul, uint64_t div) = 0;
+};
+
+class ClockRateControlBwIf : public virtual sc_core::sc_interface
+{
+  public:
+    virtual ~ClockRateControlBwIf() {}
+};
+
+class ClockRateControlSlaveBase : public ClockRateControlFwIf
+{
+  public:
+    ClockRateControlSlaveBase(const std::string &name) {}
+};
+
+class ClockRateControlInitiatorSocket :
+    public tlm::tlm_base_initiator_socket<64, ClockRateControlFwIf,
+                                          ClockRateControlBwIf>
+{
+  private:
+    ClockRateControlBwIf dummyBwIf;
+
+  public:
+    typedef tlm::tlm_base_initiator_socket<64, ClockRateControlFwIf,
+                                           ClockRateControlBwIf> Base;
+
+    using Base::bind;
+    using Base::operator();
+
+    ClockRateControlInitiatorSocket() : Base()
+    {
+        get_base_export().bind(dummyBwIf);
+    }
+    ClockRateControlInitiatorSocket(const char *name) : Base(name)
+    {
+        get_base_export().bind(dummyBwIf);
+    }
+
+    const char *
+    kind() const override
+    {
+        return "ClockRateControlInitiatorSocket";
+    }
+
+    std::type_index
+    get_protocol_types() const override
+    {
+        return typeid(ClockRateControlDummyProtocolType);
+    }
+};
+
+class ClockRateControlTargetSocket :
+    public tlm::tlm_base_target_socket<64, ClockRateControlFwIf,
+                                       ClockRateControlBwIf>
+{
+  public:
+    typedef tlm::tlm_base_target_socket<64, ClockRateControlFwIf,
+                                        ClockRateControlBwIf> Base;
+
+    using Base::bind;
+    using Base::operator();
+
+    using Base::Base;
+
+    const char *
+    kind() const override
+    {
+        return "ClockRateControlInitiatorSocket";
+    }
+
+    std::type_index
+    get_protocol_types() const override
+    {
+        return typeid(ClockRateControlDummyProtocolType);
+    }
+};
+
+#endif // __ARCH_ARM_FASTMODEL_PROTOCOL_EXPORTED_CLOCK_RATE_CONTROL_HH__