arch-arm: Provide SVE support to the TarmacTracer

Change-Id: I86ff5f49a0c0aa126d53076964f208716e70aacb
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/21561
Reviewed-by: Ciro Santilli <ciro.santilli@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
diff --git a/src/arch/arm/tracers/tarmac_record.cc b/src/arch/arm/tracers/tarmac_record.cc
index d3df689..3acc32f 100644
--- a/src/arch/arm/tracers/tarmac_record.cc
+++ b/src/arch/arm/tracers/tarmac_record.cc
@@ -178,6 +178,12 @@
       case MiscRegClass:
         updateMisc(tarmCtx, regRel);
         break;
+      case VecRegClass:
+        updateVec(tarmCtx, regRel);
+        break;
+      case VecPredRegClass:
+        updatePred(tarmCtx, regRel);
+        break;
       default:
         // If unsupported format, do nothing: non updating
         // the register will prevent it to be printed.
diff --git a/src/arch/arm/tracers/tarmac_record.hh b/src/arch/arm/tracers/tarmac_record.hh
index d253473..8c43de4 100644
--- a/src/arch/arm/tracers/tarmac_record.hh
+++ b/src/arch/arm/tracers/tarmac_record.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018 ARM Limited
+ * Copyright (c) 2017-2019 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -149,6 +149,12 @@
         virtual void
         updateInt(const TarmacContext& tarmCtx, RegIndex regRelIdx);
 
+        virtual void
+        updateVec(const TarmacContext& tarmCtx, RegIndex regRelIdx) {};
+
+        virtual void
+        updatePred(const TarmacContext& tarmCtx, RegIndex regRelIdx) {};
+
       public:
         /** True if register entry is valid */
         bool regValid;
diff --git a/src/arch/arm/tracers/tarmac_record_v8.cc b/src/arch/arm/tracers/tarmac_record_v8.cc
index f170161..5193b7f 100644
--- a/src/arch/arm/tracers/tarmac_record_v8.cc
+++ b/src/arch/arm/tracers/tarmac_record_v8.cc
@@ -126,6 +126,59 @@
 }
 
 void
+TarmacTracerRecordV8::TraceRegEntryV8::updateVec(
+    const TarmacContext& tarmCtx,
+    RegIndex regRelIdx
+)
+{
+    auto thread = tarmCtx.thread;
+    const auto& vec_container = thread->readVecReg(
+        RegId(regClass, regRelIdx));
+    auto vv = vec_container.as<VecElem>();
+
+    regWidth = ArmStaticInst::getCurSveVecLenInBits(thread);
+    auto num_elements = regWidth / (sizeof(VecElem) * 8);
+
+    // Resize vector of values
+    values.resize(num_elements);
+
+    for (auto i = 0; i < num_elements; i++) {
+        values[i] = vv[i];
+    }
+
+    regValid = true;
+    regName = "Z" + std::to_string(regRelIdx);
+}
+
+void
+TarmacTracerRecordV8::TraceRegEntryV8::updatePred(
+    const TarmacContext& tarmCtx,
+    RegIndex regRelIdx
+)
+{
+    auto thread = tarmCtx.thread;
+    const auto& pred_container = thread->readVecPredReg(
+        RegId(regClass, regRelIdx));
+
+    // Predicate registers are always 1/8 the size of related vector
+    // registers. (getCurSveVecLenInBits(thread) / 8)
+    regWidth = ArmStaticInst::getCurSveVecLenInBits(thread) / 8;
+    auto num_elements = regWidth / 16;
+
+    // Resize vector of values
+    values.resize(num_elements);
+
+    // Get a copy of pred_container as a vector of half-words
+    auto vv = pred_container.as<uint16_t>();
+    for (auto i = 0; i < num_elements; i++) {
+        values[i] = vv[i];
+    }
+
+    regValid = true;
+    regName = "P" + std::to_string(regRelIdx);
+}
+
+void
 TarmacTracerRecordV8::addInstEntry(std::vector<InstPtr>& queue,
                                    const TarmacContext& tarmCtx)
 {
@@ -236,12 +289,35 @@
     // Print the register record formatted according
     // to the Tarmac specification
     if (regValid) {
-        ccprintf(outs, "%s clk %s R %s %0*x\n",
+        ccprintf(outs, "%s clk %s R %s %s\n",
                  curTick(),            /* Tick time */
                  cpuName,              /* Cpu name */
                  regName,              /* Register name */
-                 regWidth >> 2,        /* Register value padding */
-                 values[Lo]);          /* Register value */
+                 formatReg());         /* Register value */
+    }
+}
+
+std::string
+TarmacTracerRecordV8::TraceRegEntryV8::formatReg() const
+{
+    if (regWidth <= 64) {
+        // Register width is < 64 bit (scalar register).
+        return csprintf("%0*x", regWidth / 4, values[Lo]);
+    } else {
+
+        // Register width is > 64 bit (vector).  Iterate over every vector
+        // element. Since the vector values are stored in Little Endian, print
+        // starting from the last element.
+        std::string reg_val;
+        for (auto it = values.rbegin(); it != values.rend(); it++) {
+            reg_val += csprintf("%0*x_",
+                static_cast<int>(sizeof(VecElem) * 2), *it);
+        }
+
+        // Remove trailing underscore
+        reg_val.pop_back();
+
+        return reg_val;
     }
 }
 
diff --git a/src/arch/arm/tracers/tarmac_record_v8.hh b/src/arch/arm/tracers/tarmac_record_v8.hh
index a727ea6..8743b61 100644
--- a/src/arch/arm/tracers/tarmac_record_v8.hh
+++ b/src/arch/arm/tracers/tarmac_record_v8.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018 ARM Limited
+ * Copyright (c) 2017-2019 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -108,7 +108,23 @@
         void updateMisc(const TarmacContext& tarmCtx,
                         RegIndex regRelIdx) override;
 
-        uint8_t regWidth;
+        void updateVec(const TarmacContext& tarmCtx,
+                       RegIndex regRelIdx) override;
+
+        void updatePred(const TarmacContext& tarmCtx,
+                        RegIndex regRelIdx) override;
+
+        /**
+         * Returning a string which contains the formatted
+         * register value: transformed in hex, 0 padded or/and
+         * split in chunks separated by underscores in case of
+         * vector register.
+         * @return str formatted string
+         */
+        std::string formatReg() const;
+
+        /** Size in bits of arch register */
+        uint16_t regWidth;
     };
 
     /**