arch-arm: Add support for Tarmac trace generation

This patch introduces the TarmacTracer: an instruction tracer which
allows to dump a gem5 execution trace in Tarmac format [1]. The new
tracer is supporting either Tarmac and TarmacV8 format specifications.
Not every traceable information has been implemented:

Implemented Trace Type:
    Instruction Trace
    Register Trace
    Processor Memory Access Trace

Unimplemented Trace Type:
    Program Flow Trace
    Event Trace
    Memory Bus Trace

[1]: https://developer.arm.com/docs/dui0845/f/tarmac-trace-file-format

Change-Id: I8799d8e5852e868673f728971db3fe8c63961f5e
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/9382
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
diff --git a/src/arch/arm/tracers/SConscript b/src/arch/arm/tracers/SConscript
index 1491e1a..ad11b0a 100644
--- a/src/arch/arm/tracers/SConscript
+++ b/src/arch/arm/tracers/SConscript
@@ -42,3 +42,6 @@
     SimObject('TarmacTrace.py')
     Source('tarmac_base.cc')
     Source('tarmac_parser.cc')
+    Source('tarmac_tracer.cc')
+    Source('tarmac_record.cc')
+    Source('tarmac_record_v8.cc')
diff --git a/src/arch/arm/tracers/TarmacTrace.py b/src/arch/arm/tracers/TarmacTrace.py
index c2bcbb3..8955fad 100644
--- a/src/arch/arm/tracers/TarmacTrace.py
+++ b/src/arch/arm/tracers/TarmacTrace.py
@@ -64,3 +64,14 @@
 
     ignore_mem_addr = Param.AddrRange(AddrRange(0, size=0),
         "Range of unverifiable memory addresses")
+
+class TarmacTracer(InstTracer):
+    type = 'TarmacTracer'
+    cxx_class = 'Trace::TarmacTracer'
+    cxx_header = "arch/arm/tracers/tarmac_tracer.hh"
+
+    start_tick = Param.Tick(0,
+        "tracing starts when the tick time gets this value")
+
+    end_tick = Param.Tick(MaxTick,
+        "tracing ends when the tick time gets this value")
diff --git a/src/arch/arm/tracers/tarmac_record.cc b/src/arch/arm/tracers/tarmac_record.cc
new file mode 100644
index 0000000..7034d25
--- /dev/null
+++ b/src/arch/arm/tracers/tarmac_record.cc
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2017-2018 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * 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: Giacomo Travaglini
+ */
+
+#include "arch/arm/tracers/tarmac_record.hh"
+
+#include "arch/arm/insts/static_inst.hh"
+#include "tarmac_tracer.hh"
+
+namespace Trace {
+
+// TARMAC Instruction Record static variables
+uint64_t TarmacTracerRecord::TraceInstEntry::instCount = 0;
+
+std::string
+iSetStateToStr(TarmacBaseRecord::ISetState isetstate)
+{
+    switch (isetstate) {
+      case TarmacBaseRecord::ISET_ARM:
+        return "A";
+      case TarmacBaseRecord::ISET_THUMB:
+        return "T";
+      case TarmacBaseRecord::ISET_A64:
+        return "O";
+      default:
+        return "Unsupported";
+    }
+}
+
+std::string
+opModeToStr(OperatingMode opMode)
+{
+    switch (opMode) {
+      case MODE_EL0T:
+        return "EL0t";
+      case MODE_EL1T:
+        return "EL1t";
+      case MODE_EL1H:
+        return "EL1h";
+      case MODE_EL2T:
+        return "EL2t";
+      case MODE_EL2H:
+        return "EL2h";
+      case MODE_EL3T:
+        return "EL3t";
+      case MODE_EL3H:
+        return "EL3h";
+      case MODE_USER:
+        return "usr";
+      case MODE_FIQ:
+        return "fiq";
+      case MODE_IRQ:
+        return "irq";
+      case MODE_SVC:
+        return "svc";
+      case MODE_MON:
+        return "mon";
+      case MODE_ABORT:
+        return "abt";
+      case MODE_HYP:
+        return "hyp";
+      case MODE_UNDEFINED:
+        return "und";
+      case MODE_SYSTEM:
+        return "sys";
+      default:
+        return "Unsupported";
+    }
+}
+
+// TarmacTracerRecord ctor
+TarmacTracerRecord::TarmacTracerRecord(Tick _when, ThreadContext *_thread,
+                                     const StaticInstPtr _staticInst,
+                                     PCState _pc,
+                                     TarmacTracer& _tracer,
+                                     const StaticInstPtr _macroStaticInst)
+    : TarmacBaseRecord(_when, _thread, _staticInst,
+                       _pc,  _macroStaticInst),
+      tracer(_tracer)
+{
+}
+
+TarmacTracerRecord::TraceInstEntry::TraceInstEntry(
+    const TarmacContext& tarmCtx,
+    bool predicate)
+      : InstEntry(tarmCtx.thread, tarmCtx.pc, tarmCtx.staticInst, predicate)
+{
+    secureMode = inSecureState(tarmCtx.thread);
+
+    auto arm_inst = static_cast<const ArmStaticInst*>(
+        tarmCtx.staticInst.get()
+    );
+
+    // Get the instruction size as a number of bits:
+    // (multiply byte size by 8)
+    instSize = (arm_inst->instSize() << 3);
+
+    // Mask the opcode using the instruction size: the
+    // opcode field will otherwise be 32 bit wide even
+    // for 16bit (Thumb) instruction.
+    opcode = arm_inst->encoding();
+
+    // Update the instruction count: number of executed
+    // instructions.
+    instCount++;
+}
+
+TarmacTracerRecord::TraceMemEntry::TraceMemEntry(
+    const TarmacContext& tarmCtx,
+    uint8_t _size, Addr _addr, uint64_t _data)
+      :  MemEntry(_size, _addr, _data),
+         loadAccess(tarmCtx.staticInst->isLoad())
+{
+}
+
+TarmacTracerRecord::TraceRegEntry::TraceRegEntry(
+    const TarmacContext& tarmCtx,
+    const RegId& reg)
+      : RegEntry(tarmCtx.pc),
+        regValid(false),
+        regClass(reg.classValue()),
+        regRel(reg.index())
+{
+}
+
+void
+TarmacTracerRecord::TraceRegEntry::update(
+    const TarmacContext& tarmCtx
+)
+{
+    // Fill the register entry data, according to register
+    // class.
+    switch (regClass) {
+      case CCRegClass:
+        updateCC(tarmCtx, regRel);
+        break;
+      case FloatRegClass:
+        updateFloat(tarmCtx, regRel);
+        break;
+      case IntRegClass:
+        updateInt(tarmCtx, regRel);
+        break;
+      case MiscRegClass:
+        updateMisc(tarmCtx, regRel);
+        break;
+      default:
+        // If unsupported format, do nothing: non updating
+        // the register will prevent it to be printed.
+        break;
+    }
+}
+
+void
+TarmacTracerRecord::TraceRegEntry::updateMisc(
+    const TarmacContext& tarmCtx,
+    RegIndex regRelIdx
+)
+{
+    auto thread = tarmCtx.thread;
+
+    regValid = true;
+    regName = miscRegName[regRelIdx];
+    valueLo = thread->readMiscRegNoEffect(regRelIdx);
+
+    // If it is the CPSR:
+    // update the value of the CPSR register and add
+    // the CC flags on top of the value
+    if (regRelIdx == MISCREG_CPSR) {
+        CPSR cpsr = thread->readMiscRegNoEffect(MISCREG_CPSR);
+        cpsr.nz = thread->readCCReg(CCREG_NZ);
+        cpsr.c = thread->readCCReg(CCREG_C);
+        cpsr.v = thread->readCCReg(CCREG_V);
+        cpsr.ge = thread->readCCReg(CCREG_GE);
+
+        // update the entry value
+        valueLo = cpsr;
+    }
+}
+
+void
+TarmacTracerRecord::TraceRegEntry::updateCC(
+    const TarmacContext& tarmCtx,
+    RegIndex regRelIdx
+)
+{
+    auto thread = tarmCtx.thread;
+
+    regValid = true;
+    regName = ccRegName[regRelIdx];
+    valueLo = thread->readCCReg(regRelIdx);
+}
+
+void
+TarmacTracerRecord::TraceRegEntry::updateFloat(
+    const TarmacContext& tarmCtx,
+    RegIndex regRelIdx
+)
+{
+    auto thread = tarmCtx.thread;
+
+    regValid = true;
+    regName  = "f" + std::to_string(regRelIdx);
+    valueLo = thread->readFloatReg(regRelIdx);
+}
+
+void
+TarmacTracerRecord::TraceRegEntry::updateInt(
+    const TarmacContext& tarmCtx,
+    RegIndex regRelIdx
+)
+{
+    auto thread = tarmCtx.thread;
+
+    // Reading operating mode from CPSR.
+    // This is needed when printing the register name in case
+    // of banked register (e.g. lr_svc)
+    CPSR cpsr = thread->readMiscRegNoEffect(MISCREG_CPSR);
+    OperatingMode mode = (OperatingMode)(uint8_t)cpsr.mode;
+
+    std::string reg_suffix;
+    if (mode != MODE_USER) {
+        reg_suffix = "_"  + opModeToStr(mode);
+    }
+
+    regValid = true;
+    switch (regRelIdx) {
+      case PCReg:
+        regName = "pc";
+        break;
+      case StackPointerReg:
+        regName = "sp" + reg_suffix ;
+        break;
+      case FramePointerReg:
+        regName = "fp" + reg_suffix;
+        break;
+      case ReturnAddressReg:
+        regName = "lr" + reg_suffix;
+        break;
+      default:
+        regName  = "r" + std::to_string(regRelIdx);
+        break;
+    }
+    valueLo = thread->readIntReg(regRelIdx);
+}
+
+void
+TarmacTracerRecord::addInstEntry(std::vector<InstPtr>& queue,
+                                 const TarmacContext& tarmCtx)
+{
+    // Generate an instruction entry in the record and
+    // add it to the Instruction Queue
+    queue.push_back(
+        m5::make_unique<TraceInstEntry>(tarmCtx, predicate)
+    );
+}
+
+void
+TarmacTracerRecord::addMemEntry(std::vector<MemPtr>& queue,
+                                const TarmacContext& tarmCtx)
+{
+    // Generate a memory entry in the record if the record
+    // implies a valid memory access, and add it to the
+    // Memory Queue
+    if (getMemValid()) {
+        queue.push_back(
+            m5::make_unique<TraceMemEntry>(tarmCtx,
+                                           static_cast<uint8_t>(getSize()),
+                                           getAddr(), getIntData())
+        );
+    }
+}
+
+void
+TarmacTracerRecord::addRegEntry(std::vector<RegPtr>& queue,
+                                const TarmacContext& tarmCtx)
+{
+    // Generate an entry for every ARM register being
+    // written by the current instruction
+    for (auto reg = 0; reg < staticInst->numDestRegs(); ++reg) {
+
+        RegId reg_id = staticInst->destRegIdx(reg);
+
+        // Creating a single register change entry
+        auto single_reg = genRegister<TraceRegEntry>(tarmCtx, reg_id);
+
+        // Copying the entry and adding it to the "list"
+        // of entries to be dumped to trace.
+        queue.push_back(
+            m5::make_unique<TraceRegEntry>(single_reg)
+        );
+    }
+
+    // Gem5 is treating CPSR flags as separate registers (CC registers),
+    // in contrast with Tarmac specification: we need to merge the gem5 CC
+    // entries altogether with the CPSR register and produce a single entry.
+    mergeCCEntry<TraceRegEntry>(queue, tarmCtx);
+}
+
+void
+TarmacTracerRecord::dump()
+{
+    // Generate and print all the record's entries.
+    auto &instQueue = tracer.instQueue;
+    auto &memQueue = tracer.memQueue;
+    auto &regQueue = tracer.regQueue;
+
+    const TarmacContext tarmCtx(
+        thread,
+        staticInst->isMicroop()? macroStaticInst : staticInst,
+        pc
+    );
+
+    if (!staticInst->isMicroop()) {
+        // Current instruction is NOT a micro-instruction:
+        // Generate Tarmac entries and dump them immediately
+
+        // Generate Tarmac entries and add them to the respective
+        // queues.
+        addInstEntry(instQueue, tarmCtx);
+        addMemEntry(memQueue, tarmCtx);
+        addRegEntry(regQueue, tarmCtx);
+
+        // Flush (print) any queued entry.
+        flushQueues(instQueue, memQueue, regQueue);
+
+    } else {
+        // Current instruction is a micro-instruction:
+        // save micro entries into dedicated queues and flush them
+        // into the tracefile only when the MACRO-instruction
+        // has completed.
+
+        if (staticInst->isFirstMicroop()) {
+            addInstEntry(instQueue, tarmCtx);
+        }
+
+        addRegEntry(regQueue, tarmCtx);
+        addMemEntry(memQueue, tarmCtx);
+
+        if (staticInst->isLastMicroop()) {
+            // Flush (print) any queued entry.
+            flushQueues(instQueue, memQueue, regQueue);
+        }
+    }
+}
+
+template<typename Queue>
+void
+TarmacTracerRecord::flushQueues(Queue& queue)
+{
+    std::ostream &outs = Trace::output();
+
+    for (const auto &single_entry : queue) {
+        single_entry->print(outs);
+    }
+
+    queue.clear();
+}
+
+template<typename Queue, typename... Args>
+void
+TarmacTracerRecord::flushQueues(Queue& queue, Args & ... args)
+{
+    flushQueues(queue);
+    flushQueues(args...);
+}
+
+void
+TarmacTracerRecord::TraceInstEntry::print(
+    std::ostream& outs,
+    int verbosity,
+    const std::string &prefix) const
+{
+    // Pad the opcode
+    std::string opcode_str = csprintf("%0*x", instSize >> 2, opcode);
+
+    // Print the instruction record formatted according
+    // to the Tarmac specification
+    ccprintf(outs, "%s clk %s (%u) %08x %s %s %s_%s : %s\n",
+             curTick(),                   /* Tick time */
+             taken? "IT" : "IS",          /* Instruction taken/skipped */
+             instCount,                   /* Instruction count */
+             addr,                        /* Instruction address */
+             opcode_str,                  /* Instruction opcode */
+             iSetStateToStr(isetstate),   /* Instruction Set */
+             opModeToStr(mode),           /* Exception level */
+             secureMode? "s" : "ns",      /* Security */
+             disassemble);                /* Instruction disass */
+}
+
+void
+TarmacTracerRecord::TraceMemEntry::print(
+    std::ostream& outs,
+    int verbosity,
+    const std::string &prefix) const
+{
+    // Print the memory record formatted according
+    // to the Tarmac specification
+    ccprintf(outs, "%s clk M%s%d %08x %0*x\n",
+             curTick(),                 /* Tick time */
+             loadAccess? "R" : "W",     /* Access type */
+             size,                      /* Access size */
+             addr,                      /* Memory address */
+             size*2,                    /* Padding with access size */
+             data);                     /* Memory data */
+}
+
+void
+TarmacTracerRecord::TraceRegEntry::print(
+    std::ostream& outs,
+    int verbosity,
+    const std::string &prefix) const
+{
+    // Print the register record formatted according
+    // to the Tarmac specification
+    if (regValid)
+        ccprintf(outs, "%s clk R %s %08x\n",
+                 curTick(),                 /* Tick time */
+                 regName,                   /* Register name */
+                 valueLo);                  /* Register value */
+}
+
+} // namespace Trace
diff --git a/src/arch/arm/tracers/tarmac_record.hh b/src/arch/arm/tracers/tarmac_record.hh
new file mode 100644
index 0000000..f54abf5
--- /dev/null
+++ b/src/arch/arm/tracers/tarmac_record.hh
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2017-2018 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * 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: Giacomo Travaglini
+ */
+
+/**
+ * @file: The file contains the informations used to generate records
+ *        for the pre-ARMv8 cores.
+ */
+
+#ifndef __ARCH_ARM_TRACERS_TARMAC_RECORD_HH__
+#define __ARCH_ARM_TRACERS_TARMAC_RECORD_HH__
+
+#include "arch/arm/tracers/tarmac_base.hh"
+#include "base/printable.hh"
+#include "config/the_isa.hh"
+#include "cpu/reg_class.hh"
+#include "cpu/static_inst.hh"
+
+namespace Trace {
+
+class TarmacContext;
+
+class TarmacTracer;
+
+/**
+ * Returns the string representation of the instruction set being
+ * currently run according to the Tarmac format.
+ *
+ * @param isetstate: enum variable (ISetState) specifying an ARM
+ *                   instruction set.
+ * @return instruction set in string format.
+ */
+std::string
+iSetStateToStr(TarmacBaseRecord::ISetState isetstate);
+
+/**
+ * Returns the string representation of the ARM Operating Mode
+ * (CPSR.M[3:0] field) according to the Tarmac format.
+ *
+ * @param opMode: ARM operating mode.
+ * @return operating mode in string format.
+ */
+std::string
+opModeToStr(ArmISA::OperatingMode opMode);
+
+/**
+ * TarmacTracer Record:
+ * Record generated by the TarmacTracer for every executed instruction.
+ * The record is composed by a set of entries, matching the tracing
+ * capabilities provided by the Tarmac specifications:
+ *
+ * - Instruction Entry
+ * - Register Entry
+ * - Memory Entry
+ */
+class TarmacTracerRecord : public TarmacBaseRecord
+{
+  public:
+    /** Instruction Entry */
+    struct TraceInstEntry: public InstEntry, Printable
+    {
+        TraceInstEntry(const TarmacContext& tarmCtx, bool predicate);
+
+        virtual void print(std::ostream& outs,
+                           int verbosity = 0,
+                           const std::string &prefix = "") const override;
+
+      protected:
+        /** Number of instructions being traced */
+        static uint64_t instCount;
+
+        /** True if instruction is executed in secure mode */
+        bool secureMode;
+        /**
+         * Instruction size:
+         * 16 for 16-bit Thumb Instruction
+         * 32 otherwise (ARM and BigThumb)
+         */
+        uint8_t instSize;
+    };
+
+    /** Register Entry */
+    struct TraceRegEntry: public RegEntry, Printable
+    {
+      public:
+        TraceRegEntry(const TarmacContext& tarmCtx, const RegId& reg);
+
+        /**
+         * This updates the register entry using the update table. It is
+         * a required step after the register entry generation.
+         * If unupdated, the entry will be marked as invalid.
+         * The entry update cannot be done automatically at TraceRegEntry
+         * construction: the entries are extended by consequent Tarmac
+         * Tracer versions (like V8), and virtual functions should
+         * be avoided during construction.
+         */
+        void update(const TarmacContext& tarmCtx);
+
+        virtual void print(std::ostream& outs,
+                           int verbosity = 0,
+                           const std::string &prefix = "") const override;
+
+      protected:
+        /** Register update functions. */
+        virtual void
+        updateMisc(const TarmacContext& tarmCtx, RegIndex regRelIdx);
+
+        virtual void
+        updateCC(const TarmacContext& tarmCtx, RegIndex regRelIdx);
+
+        virtual void
+        updateFloat(const TarmacContext& tarmCtx, RegIndex regRelIdx);
+
+        virtual void
+        updateInt(const TarmacContext& tarmCtx, RegIndex regRelIdx);
+
+      public:
+        /** True if register entry is valid */
+        bool regValid;
+        /** Register class */
+        RegClass regClass;
+        /** Register arch number */
+        RegIndex regRel;
+        /** Register name to be printed */
+        std::string regName;
+    };
+
+    /** Memory Entry */
+    struct TraceMemEntry: public MemEntry, Printable
+    {
+      public:
+        TraceMemEntry(const TarmacContext& tarmCtx,
+                      uint8_t _size, Addr _addr, uint64_t _data);
+
+        virtual void print(std::ostream& outs,
+                           int verbosity = 0,
+                           const std::string &prefix = "") const override;
+
+      protected:
+        /** True if memory access is a load */
+        bool loadAccess;
+    };
+
+  public:
+    TarmacTracerRecord(Tick _when, ThreadContext *_thread,
+                       const StaticInstPtr _staticInst, TheISA::PCState _pc,
+                       TarmacTracer& _tracer,
+                       const StaticInstPtr _macroStaticInst = NULL);
+
+    virtual void dump() override;
+
+    using InstPtr = std::unique_ptr<TraceInstEntry>;
+    using MemPtr = std::unique_ptr<TraceMemEntry>;
+    using RegPtr = std::unique_ptr<TraceRegEntry>;
+
+  protected:
+    /** Generates an Entry for the executed instruction. */
+    virtual void addInstEntry(std::vector<InstPtr>& queue,
+                              const TarmacContext& ptr);
+
+    /** Generates an Entry for every triggered memory access */
+    virtual void addMemEntry(std::vector<MemPtr>& queue,
+                             const TarmacContext& ptr);
+
+    /** Generate an Entry for every register being written. */
+    virtual void addRegEntry(std::vector<RegPtr>& queue,
+                             const TarmacContext& ptr);
+
+  protected:
+    /** Generate and update a register entry. */
+    template<typename RegEntry>
+    RegEntry
+    genRegister(const TarmacContext& tarmCtx, const RegId& reg)
+    {
+        RegEntry single_reg(tarmCtx, reg);
+        single_reg.update(tarmCtx);
+
+        return single_reg;
+    }
+
+    template<typename RegEntry>
+    void
+    mergeCCEntry(std::vector<RegPtr>& queue, const TarmacContext& tarmCtx)
+    {
+        // Find all CC Entries and move them at the end of the queue
+        auto it = std::remove_if(
+            queue.begin(), queue.end(),
+            [] (RegPtr& reg) ->bool { return (reg->regClass == CCRegClass); }
+        );
+
+        if (it != queue.end()) {
+            // Remove all CC Entries.
+            queue.erase(it, queue.end());
+
+            auto is_cpsr = [] (RegPtr& reg) ->bool
+            {
+                return (reg->regClass == MiscRegClass) &&
+                       (reg->regRel == ArmISA::MISCREG_CPSR);
+            };
+
+            // Looking for the presence of a CPSR register entry.
+            auto cpsr_it = std::find_if(
+                queue.begin(), queue.end(), is_cpsr
+            );
+
+            // If CPSR entry not present, generate one
+            if (cpsr_it == queue.end()) {
+                RegId reg(MiscRegClass, ArmISA::MISCREG_CPSR);
+                queue.push_back(
+                    m5::make_unique<RegEntry>(
+                        genRegister<RegEntry>(tarmCtx, reg))
+                );
+            }
+        }
+    }
+
+    /** Flush queues to the trace output */
+    template<typename Queue>
+    void flushQueues(Queue& queue);
+    template<typename Queue, typename... Args>
+    void flushQueues(Queue& queue, Args & ... args);
+
+  protected:
+    /** Reference to tracer */
+    TarmacTracer& tracer;
+};
+
+} // namespace Trace
+
+#endif // __ARCH_ARM_TRACERS_TARMAC_RECORD_HH__
diff --git a/src/arch/arm/tracers/tarmac_record_v8.cc b/src/arch/arm/tracers/tarmac_record_v8.cc
new file mode 100644
index 0000000..dea0409
--- /dev/null
+++ b/src/arch/arm/tracers/tarmac_record_v8.cc
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2017-2018 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * 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: Giacomo Travaglini
+ */
+
+#include "arch/arm/tracers/tarmac_record_v8.hh"
+
+#include "arch/arm/insts/static_inst.hh"
+#include "arch/arm/tlb.hh"
+#include "arch/arm/tracers/tarmac_tracer.hh"
+
+namespace Trace {
+
+TarmacTracerRecordV8::TraceInstEntryV8::TraceInstEntryV8(
+    const TarmacContext& tarmCtx,
+    bool predicate)
+      : TraceInstEntry(tarmCtx, predicate),
+        TraceEntryV8(tarmCtx.tarmacCpuName()),
+        paddr(0),
+        paddrValid(false)
+{
+    const auto thread = tarmCtx.thread;
+
+    // Evaluate physical address
+    TheISA::TLB* dtb = static_cast<TLB*>(thread->getDTBPtr());
+    paddrValid = dtb->translateFunctional(thread, addr, paddr);
+}
+
+TarmacTracerRecordV8::TraceMemEntryV8::TraceMemEntryV8(
+    const TarmacContext& tarmCtx,
+    uint8_t _size, Addr _addr, uint64_t _data)
+      : TraceMemEntry(tarmCtx, _size, _addr, _data),
+        TraceEntryV8(tarmCtx.tarmacCpuName()),
+        paddr(_addr)
+{
+    const auto thread = tarmCtx.thread;
+
+    // Evaluate physical address
+    TheISA::TLB* dtb = static_cast<TLB*>(thread->getDTBPtr());
+    dtb->translateFunctional(thread, addr, paddr);
+}
+
+TarmacTracerRecordV8::TraceRegEntryV8::TraceRegEntryV8(
+    const TarmacContext& tarmCtx,
+    const RegId& reg)
+      : TraceRegEntry(tarmCtx, reg),
+        TraceEntryV8(tarmCtx.tarmacCpuName()),
+        regWidth(64)
+{
+}
+
+void
+TarmacTracerRecordV8::TraceRegEntryV8::updateInt(
+    const TarmacContext& tarmCtx,
+    RegIndex regRelIdx
+)
+{
+    // Do not trace pseudo register accesses: invalid
+    // register entry.
+    if (regRelIdx > NUM_ARCH_INTREGS) {
+        regValid = false;
+        return;
+    }
+
+    TraceRegEntry::updateInt(tarmCtx, regRelIdx);
+
+    if ((regRelIdx != PCReg) || (regRelIdx != StackPointerReg) ||
+        (regRelIdx != FramePointerReg) || (regRelIdx != ReturnAddressReg)) {
+
+        const auto* arm_inst = static_cast<const ArmStaticInst*>(
+            tarmCtx.staticInst.get()
+        );
+
+        regWidth = (arm_inst->getIntWidth());
+        if (regWidth == 32) {
+            regName = "W" + std::to_string(regRelIdx);
+        } else {
+            regName = "X" + std::to_string(regRelIdx);
+        }
+    }
+}
+
+void
+TarmacTracerRecordV8::TraceRegEntryV8::updateMisc(
+    const TarmacContext& tarmCtx,
+    RegIndex regRelIdx
+)
+{
+    TraceRegEntry::updateMisc(tarmCtx, regRelIdx);
+    // System registers are 32bit wide
+    regWidth = 32;
+}
+
+void
+TarmacTracerRecordV8::addInstEntry(std::vector<InstPtr>& queue,
+                                   const TarmacContext& tarmCtx)
+{
+    // Generate an instruction entry in the record and
+    // add it to the Instruction Queue
+    queue.push_back(
+        m5::make_unique<TraceInstEntryV8>(tarmCtx, predicate)
+    );
+}
+
+void
+TarmacTracerRecordV8::addMemEntry(std::vector<MemPtr>& queue,
+                                  const TarmacContext& tarmCtx)
+{
+    // Generate a memory entry in the record if the record
+    // implies a valid memory access, and add it to the
+    // Memory Queue
+    if (getMemValid()) {
+        queue.push_back(
+            m5::make_unique<TraceMemEntryV8>(tarmCtx,
+                                             static_cast<uint8_t>(getSize()),
+                                             getAddr(), getIntData())
+        );
+    }
+}
+
+void
+TarmacTracerRecordV8::addRegEntry(std::vector<RegPtr>& queue,
+                                  const TarmacContext& tarmCtx)
+{
+    // Generate an entry for every ARM register being
+    // written by the current instruction
+    for (auto reg = 0; reg < staticInst->numDestRegs(); ++reg) {
+
+        RegId reg_id = staticInst->destRegIdx(reg);
+
+        // Creating a single register change entry
+        auto single_reg = genRegister<TraceRegEntryV8>(tarmCtx, reg_id);
+
+        // Copying the entry and adding it to the "list"
+        // of entries to be dumped to trace.
+        queue.push_back(
+            m5::make_unique<TraceRegEntryV8>(single_reg)
+        );
+    }
+
+    // Gem5 is treating CPSR flags as separate registers (CC registers),
+    // in contrast with Tarmac specification: we need to merge the gem5 CC
+    // entries altogether with the CPSR register and produce a single entry.
+    mergeCCEntry<TraceRegEntryV8>(queue, tarmCtx);
+}
+
+void
+TarmacTracerRecordV8::TraceInstEntryV8::print(
+    std::ostream& outs,
+    int verbosity,
+    const std::string &prefix) const
+{
+    // If there is a valid vaddr->paddr translation, print the
+    // physical address, otherwise print the virtual address only.
+    std::string paddr_str = paddrValid? csprintf(":%012x",paddr) :
+                                        std::string();
+
+    // Pad the opcode.
+    std::string opcode_str = csprintf("%0*x", instSize >> 2, opcode);
+
+    // Print the instruction record formatted according
+    // to the Tarmac specification
+    ccprintf(outs, "%s clk %s %s (%u) %08x%s %s %s %s_%s : %s\n",
+             curTick(),                     /* Tick time */
+             cpuName,                       /* Cpu name */
+             taken? "IT" : "IS",            /* Instruction taken/skipped */
+             instCount,                     /* Instruction count */
+             addr,                          /* Instruction virt address */
+             paddr_str,                     /* Instruction phys address */
+             opcode_str,                    /* Instruction opcode */
+             iSetStateToStr(isetstate),     /* Instruction Set */
+             opModeToStr(mode),             /* Exception level */
+             secureMode? "s" : "ns",        /* Security */
+             disassemble);                  /* Instruction disass */
+}
+
+void
+TarmacTracerRecordV8::TraceMemEntryV8::print(
+    std::ostream& outs,
+    int verbosity,
+    const std::string &prefix) const
+{
+    // Print the memory record formatted according
+    // to the Tarmac specification
+    ccprintf(outs, "%s clk %s M%s%d %08x:%012x %0*x\n",
+             curTick(),                 /* Tick time */
+             cpuName,                   /* Cpu name */
+             loadAccess? "R" : "W",     /* Access type */
+             size,                      /* Access size */
+             addr,                      /* Virt Memory address */
+             paddr,                     /* Phys Memory address */
+             size*2,                    /* Padding with access size */
+             data);                     /* Memory data */
+}
+
+void
+TarmacTracerRecordV8::TraceRegEntryV8::print(
+    std::ostream& outs,
+    int verbosity,
+    const std::string &prefix) const
+{
+    // Print the register record formatted according
+    // to the Tarmac specification
+    if (regValid) {
+        ccprintf(outs, "%s clk %s R %s %0*x\n",
+                 curTick(),            /* Tick time */
+                 cpuName,              /* Cpu name */
+                 regName,              /* Register name */
+                 regWidth >> 2,        /* Register value padding */
+                 valueLo);             /* Register value */
+    }
+}
+
+} // namespace Trace
diff --git a/src/arch/arm/tracers/tarmac_record_v8.hh b/src/arch/arm/tracers/tarmac_record_v8.hh
new file mode 100644
index 0000000..adf638f
--- /dev/null
+++ b/src/arch/arm/tracers/tarmac_record_v8.hh
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2017-2018 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * 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: Giacomo Travaglini
+ */
+
+/**
+ * @file: The file contains the informations used to generate records
+ *        for ARMv8 cores.
+ */
+
+#ifndef __ARCH_ARM_TRACERS_TARMAC_RECORD_V8_HH__
+#define __ARCH_ARM_TRACERS_TARMAC_RECORD_V8_HH__
+
+#include "tarmac_record.hh"
+
+namespace Trace {
+
+/**
+ * TarmacTracer record for ARMv8 CPUs:
+ * The record is adding some data to the base TarmacTracer
+ * record.
+ */
+class TarmacTracerRecordV8 : public TarmacTracerRecord
+{
+  public:
+
+    /**
+     * General data shared by all v8 entries
+     */
+    struct TraceEntryV8
+    {
+      public:
+        TraceEntryV8(std::string _cpuName)
+          : cpuName(_cpuName)
+        {}
+
+      protected:
+        std::string cpuName;
+    };
+
+    /**
+     * Instruction entry for v8 records
+     */
+    struct TraceInstEntryV8: public TraceInstEntry, TraceEntryV8
+    {
+      public:
+        TraceInstEntryV8(const TarmacContext& tarmCtx, bool predicate);
+
+        virtual void print(std::ostream& outs,
+                           int verbosity = 0,
+                           const std::string &prefix = "") const override;
+
+      protected:
+        Addr paddr;
+        bool paddrValid;
+    };
+
+    /**
+     * Register entry for v8 records
+     */
+    struct TraceRegEntryV8: public TraceRegEntry, TraceEntryV8
+    {
+      public:
+        TraceRegEntryV8(const TarmacContext& tarmCtx, const RegId& reg);
+
+        virtual void print(std::ostream& outs,
+                           int verbosity = 0,
+                           const std::string &prefix = "") const override;
+
+      protected:
+        void updateInt(const TarmacContext& tarmCtx,
+                       RegIndex regRelIdx) override;
+
+        void updateMisc(const TarmacContext& tarmCtx,
+                        RegIndex regRelIdx) override;
+
+        uint8_t regWidth;
+    };
+
+    /**
+     * Memory Entry for V8
+     */
+    struct TraceMemEntryV8: public TraceMemEntry, TraceEntryV8
+    {
+      public:
+        TraceMemEntryV8(const TarmacContext& tarmCtx,
+                        uint8_t _size, Addr _addr, uint64_t _data);
+
+        virtual void print(std::ostream& outs,
+                           int verbosity = 0,
+                           const std::string &prefix = "") const override;
+
+      protected:
+        Addr paddr;
+    };
+
+  public:
+    TarmacTracerRecordV8(Tick _when, ThreadContext *_thread,
+                         const StaticInstPtr _staticInst, TheISA::PCState _pc,
+                         TarmacTracer& _parent,
+                         const StaticInstPtr _macroStaticInst = NULL)
+      : TarmacTracerRecord(_when, _thread, _staticInst, _pc,
+                           _parent, _macroStaticInst)
+    {}
+
+  protected:
+    /** Generates an Entry for the executed instruction. */
+    void addInstEntry(std::vector<InstPtr>& queue, const TarmacContext& ptr);
+
+    /** Generates an Entry for every memory access triggered */
+    void addMemEntry(std::vector<MemPtr>& queue, const TarmacContext& ptr);
+
+    /** Generate a Record for every register being written */
+    void addRegEntry(std::vector<RegPtr>& queue, const TarmacContext& ptr);
+};
+
+} // namespace Trace
+
+#endif // __ARCH_ARM_TRACERS_TARMAC_RECORD_V8_HH__
diff --git a/src/arch/arm/tracers/tarmac_tracer.cc b/src/arch/arm/tracers/tarmac_tracer.cc
new file mode 100644
index 0000000..b6f876d
--- /dev/null
+++ b/src/arch/arm/tracers/tarmac_tracer.cc
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017-2018 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * 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: Giacomo Travaglini
+ */
+
+#include "tarmac_tracer.hh"
+
+#include <string>
+
+#include "arch/arm/system.hh"
+#include "cpu/base.hh"
+
+namespace Trace {
+
+std::string
+TarmacContext::tarmacCpuName() const
+{
+    auto id = thread->getCpuPtr()->cpuId();
+    return "cpu" + std::to_string(id);
+}
+
+TarmacTracer::TarmacTracer(const Params *p)
+  : InstTracer(p),
+    startTick(p->start_tick),
+    endTick(p->end_tick)
+{
+    // Wrong parameter setting: The trace end happens before the
+    // trace start.
+    panic_if(startTick > endTick,
+             "Tarmac start point: %lu is bigger than "
+             "Tarmac end point: %lu\n", startTick, endTick);
+
+    // By default cpu tracers in gem5 are not tracing faults
+    // (exceptions).
+    // This is not in compliance with the Tarmac specification:
+    // instructions like SVC, SMC, HVC have to be traced.
+    // Tarmac Tracer is then automatically enabling this behaviour.
+    setDebugFlag("ExecFaulting");
+}
+
+InstRecord *
+TarmacTracer::getInstRecord(Tick when, ThreadContext *tc,
+                           const StaticInstPtr staticInst,
+                           TheISA::PCState pc,
+                           const StaticInstPtr macroStaticInst)
+{
+    // Check if we need to start tracing since we have passed the
+    // tick start point.
+    if (when < startTick || when > endTick)
+        return nullptr;
+
+    if (ArmSystem::highestELIs64(tc)) {
+        // TarmacTracerV8
+        return new TarmacTracerRecordV8(when, tc, staticInst, pc, *this,
+                                        macroStaticInst);
+    } else {
+        // TarmacTracer
+        return new TarmacTracerRecord(when, tc, staticInst, pc, *this,
+                                      macroStaticInst);
+    }
+}
+
+} // namespace Trace
+
+Trace::TarmacTracer *
+TarmacTracerParams::create()
+{
+    return new Trace::TarmacTracer(this);
+}
diff --git a/src/arch/arm/tracers/tarmac_tracer.hh b/src/arch/arm/tracers/tarmac_tracer.hh
new file mode 100644
index 0000000..7873999
--- /dev/null
+++ b/src/arch/arm/tracers/tarmac_tracer.hh
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2017-2018 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * 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: Giacomo Travaglini
+ */
+
+/**
+ * @file: This file declares the interface of the Tarmac Tracer:
+ *        the tracer based on the Tarmac specification.
+ */
+
+#ifndef __ARCH_ARM_TRACERS_TARMAC_TRACER_HH__
+#define __ARCH_ARM_TRACERS_TARMAC_TRACER_HH__
+
+#include "arch/arm/tracers/tarmac_record.hh"
+#include "arch/arm/tracers/tarmac_record_v8.hh"
+#include "params/TarmacTracer.hh"
+#include "sim/insttracer.hh"
+
+class ThreadContext;
+
+namespace Trace {
+
+/**
+ * This object type is encapsulating the informations needed by
+ * a Tarmac record to generate it's own entries.
+ */
+class TarmacContext
+{
+  public:
+    TarmacContext(ThreadContext* _thread,
+                  const StaticInstPtr _staticInst,
+                  TheISA::PCState _pc)
+      : thread(_thread), staticInst(_staticInst), pc(_pc)
+    {}
+
+    std::string tarmacCpuName() const;
+
+  public:
+    ThreadContext* thread;
+    const StaticInstPtr staticInst;
+    TheISA::PCState pc;
+};
+
+/**
+ * Tarmac Tracer: this tracer generates a new Tarmac Record for
+ * every instruction being executed in gem5.
+ * The record is made by a collection of entries which are stored
+ * in the tracer queues.
+ */
+class TarmacTracer : public InstTracer
+{
+    friend class TarmacTracerRecord;
+    friend class TarmacTracerRecordV8;
+
+  public:
+    typedef TarmacTracerParams Params;
+
+    TarmacTracer(const Params *p);
+
+    /**
+     * Generates a TarmacTracerRecord, depending on the Tarmac version.
+     * At the moment supported formats are:
+     * - Tarmac
+     * - TarmacV8
+     */
+    InstRecord* getInstRecord(Tick when, ThreadContext *tc,
+                              const StaticInstPtr staticInst,
+                              TheISA::PCState pc,
+                              const StaticInstPtr macroStaticInst = NULL);
+
+  protected:
+    typedef std::unique_ptr<Printable> PEntryPtr;
+    typedef TarmacTracerRecord::InstPtr InstPtr;
+    typedef TarmacTracerRecord::MemPtr MemPtr;
+    typedef TarmacTracerRecord::RegPtr RegPtr;
+
+    /**
+     * startTick and endTick allow to trace a specific window of ticks
+     * rather than the entire CPU execution.
+     */
+    Tick startTick;
+    Tick endTick;
+
+    /**
+     * Collection of heterogeneous printable entries: could be
+     * representing either instructions, register or memory entries.
+     * When dealing with MacroInstructions the following separate queues
+     * will be used. micro-instruction entries will be buffered and
+     * dumped to the tracefile only at the end of the Macro.
+     */
+    std::vector<InstPtr> instQueue;
+    std::vector<MemPtr> memQueue;
+    std::vector<RegPtr> regQueue;
+};
+
+} // namespace Trace
+
+#endif // __ARCH_ARM_TRACERS_TARMAC_TRACER_HH__