cpu: Added the Multiperspective Perceptron Predictor with TAGE (8KB and 64KB)

Described by the following article:
  Jiménez, D. "Multiperspective perceptron predictor with TAGE."
  Championship Branch Prediction (CBP-5) (2016).

Change-Id: Ica3c121a4c94657d9015573085040e8a1984b069
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/19188
Tested-by: kokoro <noreply+kokoro@google.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Ilias Vougioukas <ilias.vougioukas@arm.com>
diff --git a/src/cpu/pred/BranchPredictor.py b/src/cpu/pred/BranchPredictor.py
index 967489a..1196405 100644
--- a/src/cpu/pred/BranchPredictor.py
+++ b/src/cpu/pred/BranchPredictor.py
@@ -133,6 +133,7 @@
     logUResetPeriod = Param.Unsigned(18,
         "Log period in number of branches to reset TAGE useful counters")
     numUseAltOnNa = Param.Unsigned(1, "Number of USE_ALT_ON_NA counters")
+    initialTCounterValue = Param.Int(1 << 17, "Initial value of tCounter")
     useAltOnNaBits = Param.Unsigned(4, "Size of the USE_ALT_ON_NA counter(s)")
 
     maxNumAlloc = Param.Unsigned(1,
@@ -210,6 +211,7 @@
     pathHistBits = 27
     maxNumAlloc = 2
     logUResetPeriod = 10
+    initialTCounterValue = 1 << 9
     useAltOnNaBits = 5
     # TODO No speculation implemented as of now
     speculativeHistUpdate = False
@@ -334,14 +336,20 @@
     bwnb = Param.Unsigned("Num global backward branch GEHL lengths")
     bwm = VectorParam.Int("Global backward branch GEHL lengths")
     logBwnb = Param.Unsigned("Log num of global backward branch GEHL entries")
+    bwWeightInitValue = Param.Int(
+     "Initial value of the weights of the global backward branch GEHL entries")
 
     lnb = Param.Unsigned("Num first local history GEHL lenghts")
     lm = VectorParam.Int("First local history GEHL lengths")
     logLnb = Param.Unsigned("Log number of first local history GEHL entries")
+    lWeightInitValue = Param.Int(
+        "Initial value of the weights of the first local history GEHL entries")
 
     inb = Param.Unsigned(1, "Num IMLI GEHL lenghts")
     im = VectorParam.Int([8], "IMLI history GEHL lengths")
     logInb = Param.Unsigned("Log number of IMLI GEHL entries")
+    iWeightInitValue = Param.Int(
+        "Initial value of the weights of the IMLI history GEHL entries")
 
     logBias = Param.Unsigned("Log size of Bias tables")
 
@@ -362,6 +370,9 @@
 
     scCountersWidth = Param.Unsigned(6, "Statistical corrector counters width")
 
+    initialUpdateThresholdValue = Param.Int(0,
+        "Initial pUpdate threshold counter value")
+
 # TAGE-SC-L branch predictor as desribed in
 # https://www.jilp.org/cbp2016/paper/AndreSeznecLimited.pdf
 # It is a modified LTAGE predictor plus a statistical corrector predictor
@@ -425,12 +436,15 @@
     bwnb = 3
     bwm = [40, 24, 10]
     logBwnb = 10
+    bwWeightInitValue = 7
 
     lnb = 3
     lm = [11, 6, 3]
     logLnb = 10
+    lWeightInitValue = 7
 
     logInb = 8
+    iWeightInitValue = 7
 
 class TAGE_SC_L_8KB_StatisticalCorrector(StatisticalCorrector):
     type = 'TAGE_SC_L_8KB_StatisticalCorrector'
@@ -447,12 +461,15 @@
     bwnb = 2
     logBwnb = 7
     bwm = [16, 8]
+    bwWeightInitValue = 7
 
     lnb = 2
     logLnb = 7
     lm = [6, 3]
+    lWeightInitValue = 7
 
     logInb = 7
+    iWeightInitValue = 7
 
 # 64KB TAGE-SC-L branch predictor as described in
 # http://www.jilp.org/cbp2016/paper/AndreSeznecLimited.pdf
@@ -536,6 +553,9 @@
     speculative_update = Param.Bool(False,
         "Use speculative update for histories")
 
+    initial_ghist_length = Param.Int(1, "Initial GHist length value")
+    ignore_path_size = Param.Bool(False, "Ignore the path storage")
+
 class MultiperspectivePerceptron8KB(MultiperspectivePerceptron):
     type = 'MultiperspectivePerceptron8KB'
     cxx_class = 'MultiperspectivePerceptron8KB'
@@ -557,3 +577,177 @@
     imli_mask1 = 0xc1000
     imli_mask4 = 0x80008000
     recencypos_mask = 0x100000090
+
+class MPP_TAGE(TAGEBase):
+    type = 'MPP_TAGE'
+    cxx_class = 'MPP_TAGE'
+    cxx_header = 'cpu/pred/multiperspective_perceptron_tage.hh'
+    nHistoryTables = 15
+    pathHistBits = 27
+    instShiftAmt = 0
+    histBufferSize = 16384
+    maxHist = 4096;
+    tagTableTagWidths = [0, 7, 9, 9, 9, 10, 11, 11, 12, 12,
+                         12, 13, 14, 15, 15, 15]
+    logTagTableSizes = [14, 10, 11, 11, 11, 11, 11, 12, 12,
+                         10, 11, 11, 9, 7, 7, 8]
+    tunedHistoryLengths = VectorParam.Unsigned([0, 5, 12, 15, 21, 31, 43, 64,
+        93, 137, 200, 292, 424, 612, 877, 1241], "Tuned history lengths")
+
+    logUResetPeriod = 10
+    initialTCounterValue = 0
+    numUseAltOnNa = 512
+    speculativeHistUpdate = False
+
+class MPP_LoopPredictor(LoopPredictor):
+    type = 'MPP_LoopPredictor'
+    cxx_class = 'MPP_LoopPredictor'
+    cxx_header = 'cpu/pred/multiperspective_perceptron_tage.hh'
+    useDirectionBit = True
+    useHashing = True
+    useSpeculation = False
+    loopTableConfidenceBits = 4
+    loopTableAgeBits = 4
+    initialLoopAge = 7
+    initialLoopIter = 0
+    loopTableIterBits = 12
+    optionalAgeReset = False
+    restrictAllocation = True
+    logSizeLoopPred = 6
+    loopTableTagBits = 10
+
+class MPP_StatisticalCorrector(StatisticalCorrector):
+    type = 'MPP_StatisticalCorrector'
+    cxx_class = 'MPP_StatisticalCorrector'
+    cxx_header = 'cpu/pred/multiperspective_perceptron_tage.hh'
+    abstract = True
+
+    # Unused in this Statistical Corrector
+    bwnb = 0
+    bwm = [ ]
+    logBwnb = 0
+    bwWeightInitValue = -1
+
+    # Unused in this Statistical Corrector
+    logInb = 0
+    iWeightInitValue = -1
+
+    extraWeightsWidth = 0
+    pUpdateThresholdWidth = 10
+    initialUpdateThresholdValue = 35
+    logSizeUp = 5
+
+    lnb = 3
+    lm = [11, 6, 3]
+    logLnb = 10
+    lWeightInitValue = -1
+
+    gnb = Param.Unsigned(4, "Num global branch GEHL lengths")
+    gm = VectorParam.Int([27, 22, 17, 14], "Global branch GEHL lengths")
+    logGnb = Param.Unsigned(10, "Log number of global branch GEHL entries")
+
+    pnb = Param.Unsigned(4, "Num variation global branch GEHL lengths")
+    pm = VectorParam.Int([16, 11, 6, 3],
+        "Variation global branch GEHL lengths")
+    logPnb = Param.Unsigned(9,
+        "Log number of variation global branch GEHL entries")
+
+class MultiperspectivePerceptronTAGE(MultiperspectivePerceptron):
+    type = 'MultiperspectivePerceptronTAGE'
+    cxx_class = 'MultiperspectivePerceptronTAGE'
+    cxx_header = 'cpu/pred/multiperspective_perceptron_tage.hh'
+    abstract = True
+    instShiftAmt = 4
+
+    imli_mask1 = 0x70
+    imli_mask4 = 0
+    num_filter_entries = 0
+    num_local_histories = 0
+    recencypos_mask = 0 # Unused
+    threshold = -1
+    initial_ghist_length = 0
+    ignore_path_size = True
+    n_sign_bits = 1;
+
+    tage = Param.TAGEBase("Tage object")
+    loop_predictor = Param.LoopPredictor("Loop predictor")
+    statistical_corrector = Param.StatisticalCorrector("Statistical Corrector")
+
+class MPP_StatisticalCorrector_64KB(MPP_StatisticalCorrector):
+    type = 'MPP_StatisticalCorrector_64KB'
+    cxx_class = 'MPP_StatisticalCorrector_64KB'
+    cxx_header = 'cpu/pred/multiperspective_perceptron_tage_64KB.hh'
+
+    logBias = 8
+
+    snb = Param.Unsigned(4, "Num second local history GEHL lenghts")
+    sm = VectorParam.Int([16, 11, 6, 3], "Second local history GEHL lengths")
+    logSnb = Param.Unsigned(9,
+        "Log number of second local history GEHL entries")
+
+    tnb = Param.Unsigned(3, "Num third local history GEHL lenghts")
+    tm = VectorParam.Int([22, 17, 14], "Third local history GEHL lengths")
+    logTnb = Param.Unsigned(9,
+        "Log number of third local history GEHL entries")
+
+    numEntriesSecondLocalHistories = Param.Unsigned(16,
+        "Number of entries for second local histories")
+    numEntriesThirdLocalHistories = Param.Unsigned(16,
+        "Number of entries for second local histories")
+
+    numEntriesFirstLocalHistories = 256
+
+class MultiperspectivePerceptronTAGE64KB(MultiperspectivePerceptronTAGE):
+    type = 'MultiperspectivePerceptronTAGE64KB'
+    cxx_class = 'MultiperspectivePerceptronTAGE64KB'
+    cxx_header = 'cpu/pred/multiperspective_perceptron_tage_64KB.hh'
+
+    budgetbits = 65536 * 8 + 2048
+
+    tage = MPP_TAGE()
+    loop_predictor = MPP_LoopPredictor()
+    statistical_corrector = MPP_StatisticalCorrector_64KB()
+
+class MPP_TAGE_8KB(MPP_TAGE):
+    type = 'MPP_TAGE_8KB'
+    cxx_class = 'MPP_TAGE_8KB'
+    cxx_header = 'cpu/pred/multiperspective_perceptron_tage_8KB.hh'
+    nHistoryTables = 10
+    tagTableTagWidths = [0, 7, 7, 7, 8, 9, 10, 10, 11, 13, 13]
+    logTagTableSizes = [12, 8, 8, 9, 9, 8, 8, 8, 7, 6, 7]
+    tunedHistoryLengths = [0, 4, 8, 13, 23, 36, 56, 93, 145, 226, 359]
+
+class MPP_LoopPredictor_8KB(MPP_LoopPredictor):
+    type = 'MPP_LoopPredictor_8KB'
+    cxx_class = 'MPP_LoopPredictor_8KB'
+    cxx_header = 'cpu/pred/multiperspective_perceptron_tage_8KB.hh'
+    loopTableIterBits = 10
+    logSizeLoopPred = 4
+
+class MPP_StatisticalCorrector_8KB(MPP_StatisticalCorrector):
+    type = 'MPP_StatisticalCorrector_8KB'
+    cxx_class = 'MPP_StatisticalCorrector_8KB'
+    cxx_header = 'cpu/pred/multiperspective_perceptron_tage_8KB.hh'
+
+    logBias = 7
+
+    lnb = 2
+    lm = [8, 3]
+    logLnb = 9
+
+    logGnb = 9
+
+    logPnb = 7
+
+    numEntriesFirstLocalHistories = 64
+
+class MultiperspectivePerceptronTAGE8KB(MultiperspectivePerceptronTAGE):
+    type = 'MultiperspectivePerceptronTAGE8KB'
+    cxx_class = 'MultiperspectivePerceptronTAGE8KB'
+    cxx_header = 'cpu/pred/multiperspective_perceptron_tage_8KB.hh'
+
+    budgetbits = 8192 * 8 + 2048
+
+    tage = MPP_TAGE_8KB()
+    loop_predictor = MPP_LoopPredictor_8KB()
+    statistical_corrector = MPP_StatisticalCorrector_8KB()
diff --git a/src/cpu/pred/SConscript b/src/cpu/pred/SConscript
index 27821a4..9775d4c 100644
--- a/src/cpu/pred/SConscript
+++ b/src/cpu/pred/SConscript
@@ -51,6 +51,9 @@
 Source('multiperspective_perceptron.cc')
 Source('multiperspective_perceptron_8KB.cc')
 Source('multiperspective_perceptron_64KB.cc')
+Source('multiperspective_perceptron_tage.cc')
+Source('multiperspective_perceptron_tage_8KB.cc')
+Source('multiperspective_perceptron_tage_64KB.cc')
 Source('statistical_corrector.cc')
 Source('tage_sc_l.cc')
 Source('tage_sc_l_8KB.cc')
diff --git a/src/cpu/pred/loop_predictor.cc b/src/cpu/pred/loop_predictor.cc
index bd32e41..abcaac4 100644
--- a/src/cpu/pred/loop_predictor.cc
+++ b/src/cpu/pred/loop_predictor.cc
@@ -360,6 +360,15 @@
               "the prediction is wrong");
 }
 
+size_t
+LoopPredictor::getSizeInBits() const
+{
+    return (1ULL << logSizeLoopPred) *
+        ((useSpeculation ? 3 : 2) * loopTableIterBits +
+        loopTableConfidenceBits + loopTableTagBits +
+        loopTableAgeBits + useDirectionBit);
+}
+
 LoopPredictor *
 LoopPredictorParams::create()
 {
diff --git a/src/cpu/pred/loop_predictor.hh b/src/cpu/pred/loop_predictor.hh
index bc62698..5706c45 100644
--- a/src/cpu/pred/loop_predictor.hh
+++ b/src/cpu/pred/loop_predictor.hh
@@ -259,5 +259,7 @@
     void regStats() override;
 
     LoopPredictor(LoopPredictorParams *p);
+
+    size_t getSizeInBits() const;
 };
 #endif//__CPU_PRED_LOOP_PREDICTOR_HH__
diff --git a/src/cpu/pred/multiperspective_perceptron.cc b/src/cpu/pred/multiperspective_perceptron.cc
index 47bbb02..d081b49 100644
--- a/src/cpu/pred/multiperspective_perceptron.cc
+++ b/src/cpu/pred/multiperspective_perceptron.cc
@@ -38,6 +38,7 @@
 
 #include "cpu/pred/multiperspective_perceptron.hh"
 
+#include "base/random.hh"
 #include "debug/Branch.hh"
 
 int
@@ -121,15 +122,21 @@
     tuneonly(p->tuneonly), extra_rounds(p->extra_rounds), speed(p->speed),
     budgetbits(p->budgetbits), speculative_update(p->speculative_update),
     threadData(p->numThreads, nullptr), doing_local(false),
-    doing_recency(false), assoc(0), ghist_length(1), modghist_length(1),
-    path_length(1), randSeed(0xdeadbeef), thresholdCounter(0),
-    theta(p->initial_theta), imli_counter_bits(4), modhist_indices(),
-    modhist_lengths(), modpath_indices(), modpath_lengths()
+    doing_recency(false), assoc(0), ghist_length(p->initial_ghist_length),
+    modghist_length(1), path_length(1), thresholdCounter(0),
+    theta(p->initial_theta), extrabits(0), imli_counter_bits(4),
+    modhist_indices(), modhist_lengths(), modpath_indices(), modpath_lengths()
 {
     fatal_if(speculative_update, "Speculative update not implemented");
 }
 
 void
+MultiperspectivePerceptron::setExtraBits(int bits)
+{
+    extrabits = bits;
+}
+
+void
 MultiperspectivePerceptron::init()
 {
     createSpecs();
@@ -147,7 +154,7 @@
         static_cast<const MultiperspectivePerceptronParams *>(params());
 
     computeBits(p->num_filter_entries, p->num_local_histories,
-                p->local_history_length);
+                p->local_history_length, p->ignore_path_size);
 
     for (int i = 0; i < threadData.size(); i += 1) {
         threadData[i] = new ThreadData(p->num_filter_entries,
@@ -163,19 +170,24 @@
 
 void
 MultiperspectivePerceptron::computeBits(int num_filter_entries,
-        int nlocal_histories, int local_history_length) {
-    int totalbits = 0;
+        int nlocal_histories, int local_history_length, bool ignore_path_size)
+{
+    int totalbits = extrabits;
     for (auto &imli_bits : imli_counter_bits) {
         totalbits += imli_bits;
     }
     totalbits += ghist_length;
-    totalbits += path_length * 16;
+    if (!ignore_path_size) {
+        totalbits += path_length * 16;
+    }
     totalbits += (threshold >= 0) ? (tunebits * specs.size()) : 0;
     for (auto &len : modhist_lengths) {
         totalbits += len;
     }
-    for (auto &len : modpath_lengths) {
-        totalbits += 16 * len;
+    if (!ignore_path_size) {
+        for (auto &len : modpath_lengths) {
+            totalbits += 16 * len;
+        }
     }
     totalbits += doing_local ? (nlocal_histories * local_history_length) : 0;
     totalbits += doing_recency ? (assoc * 16) : 0;
@@ -482,7 +494,7 @@
             do {
                 // udpate a random weight
                 int besti = -1;
-                int nrand = rand_r(&randSeed) % specs.size();
+                int nrand = random_mt.random<int>() % specs.size();
                 int pout;
                 found = false;
                 for (int j = 0; j < specs.size(); j += 1) {
@@ -645,7 +657,8 @@
         // filter, blow a random filter entry away
         if (decay && transition &&
             ((threadData[tid]->occupancy > decay) || (decay == 1))) {
-            int rnd = rand_r(&randSeed) % threadData[tid]->filterTable.size();
+            int rnd = random_mt.random<int>() %
+                      threadData[tid]->filterTable.size();
             FilterEntry &frand = threadData[tid]->filterTable[rnd];
             if (frand.seenTaken && frand.seenUntaken) {
                 threadData[tid]->occupancy -= 1;
diff --git a/src/cpu/pred/multiperspective_perceptron.hh b/src/cpu/pred/multiperspective_perceptron.hh
index e81bd8e..9d45032 100644
--- a/src/cpu/pred/multiperspective_perceptron.hh
+++ b/src/cpu/pred/multiperspective_perceptron.hh
@@ -358,9 +358,9 @@
     int ghist_length;
     int modghist_length;
     int path_length;
-    unsigned int randSeed;
     int thresholdCounter;
     int theta;
+    int extrabits;
     std::vector<int> imli_counter_bits;
     std::vector<int> modhist_indices;
     std::vector<int> modhist_lengths;
@@ -416,9 +416,10 @@
      * @param num_filter_entries number of entries of the filter
      * @param nlocal_histories number of local history entries
      * @param local_history_length size of each local history entry
+     * @param ignore_path_size ignore the path length storage
      */
     void computeBits(int num_filter_entries, int nlocal_histories,
-            int local_history_length);
+            int local_history_length, bool ignore_path_size);
 
     /**
      * Creates the tables of the predictor
@@ -1013,6 +1014,13 @@
     public:
     MultiperspectivePerceptron(const MultiperspectivePerceptronParams *params);
 
+    /**
+     * Sets the starting number of storage bits to compute the number of
+     * table entries
+     * @param bits number of bits used
+     */
+    void setExtraBits(int bits);
+
     void init() override;
 
     void uncondBranch(ThreadID tid, Addr pc, void * &bp_history) override;
diff --git a/src/cpu/pred/multiperspective_perceptron_tage.cc b/src/cpu/pred/multiperspective_perceptron_tage.cc
new file mode 100644
index 0000000..3ef5f4f
--- /dev/null
+++ b/src/cpu/pred/multiperspective_perceptron_tage.cc
@@ -0,0 +1,697 @@
+/*
+ * Copyright 2019 Texas A&M University
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. Neither the name of the copyright holder 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
+ *  HOLDER 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.
+ *
+ *  Author: Daniel A. Jiménez
+ *  Adapted to gem5 by: Javier Bueno Hedo
+ *
+ */
+
+/*
+ * Multiperspective Perceptron Predictor with TAGE (by Daniel A. Jiménez)
+ */
+
+#include "cpu/pred/multiperspective_perceptron_tage.hh"
+
+#include "base/random.hh"
+
+void
+MPP_TAGE::calculateParameters()
+{
+   assert(tunedHistoryLengths.size() == (nHistoryTables+1));
+   for (int i = 0; i <= nHistoryTables; i += 1) {
+      histLengths[i] = tunedHistoryLengths[i];
+   }
+}
+
+void
+MPP_TAGE::handleTAGEUpdate(Addr branch_pc, bool taken,
+                           TAGEBase::BranchInfo* bi)
+{
+    if (bi->hitBank > 0) {
+        if (abs (2 * gtable[bi->hitBank][bi->hitBankIndex].ctr + 1) == 1) {
+            if (bi->longestMatchPred != taken) {
+                // acts as a protection
+                if (bi->altBank > 0) {
+                    ctrUpdate(gtable[bi->altBank][bi->altBankIndex].ctr, taken,
+                              tagTableCounterBits);
+                }
+                if (bi->altBank == 0){
+                    baseUpdate(branch_pc, taken, bi);
+                }
+            }
+        }
+
+        ctrUpdate(gtable[bi->hitBank][bi->hitBankIndex].ctr, taken,
+                  tagTableCounterBits);
+
+        //sign changes: no way it can have been useful
+        if (abs (2 * gtable[bi->hitBank][bi->hitBankIndex].ctr + 1) == 1) {
+            gtable[bi->hitBank][bi->hitBankIndex].u = 0;
+        }
+    } else {
+        baseUpdate(branch_pc, taken, bi);
+    }
+
+    if ((bi->longestMatchPred != bi->altTaken) &&
+        (bi->longestMatchPred == taken) &&
+        (gtable[bi->hitBank][bi->hitBankIndex].u < (1 << tagTableUBits) -1)) {
+            gtable[bi->hitBank][bi->hitBankIndex].u++;
+    }
+}
+
+void
+MPP_TAGE::handleAllocAndUReset(bool alloc, bool taken,
+                               TAGEBase::BranchInfo* bi, int nrand)
+{
+    if (!alloc) {
+        return;
+    }
+
+    int a = 1;
+
+    if ((random_mt.random<int>() & 127) < 32) {
+        a = 2;
+    }
+    int dep = bi->hitBank + a;
+
+    int penalty = 0;
+    int numAllocated = 0;
+    int T = 1;
+
+    for (int i = dep; i <= nHistoryTables; i += 1) {
+        if (noSkip[i]) {
+            if (gtable[i][bi->tableIndices[i]].u == 0) {
+                gtable[i][bi->tableIndices[i]].tag = bi->tableTags[i];
+                gtable[i][bi->tableIndices[i]].ctr = taken ? 0 : -1;
+                numAllocated++;
+                if (T <= 0) {
+                    break;
+                }
+                i += 1;
+                T -= 1;
+            } else {
+                penalty++;
+            }
+        } else { assert(false); }
+    }
+
+    tCounter += (penalty - numAllocated);
+
+    handleUReset();
+}
+
+void
+MPP_TAGE::handleUReset()
+{
+    //just the best formula for the Championship:
+    //In practice when one out of two entries are useful
+    if (tCounter < 0) {
+        tCounter = 0;
+    }
+
+    if (tCounter >= ((ULL(1) << logUResetPeriod))) {
+        // Update the u bits for the short tags table
+        for (int i = 1; i <= nHistoryTables; i++) {
+            for (int j = 0; j < (ULL(1) << logTagTableSizes[i]); j++) {
+                resetUctr(gtable[i][j].u);
+            }
+        }
+
+        tCounter = 0;
+    }
+}
+
+void
+MPP_TAGE::resetUctr(uint8_t &u)
+{
+    // On real HW it should be u >>= 1 instead of if > 0 then u--
+    if (u > 0) {
+        u--;
+    }
+}
+
+
+int
+MPP_TAGE::bindex(Addr pc_in) const
+{
+    uint32_t pc = (uint32_t) pc_in;
+    return ((pc ^ (pc >> 4)) &
+            ((ULL(1) << (logTagTableSizes[0])) - 1));
+}
+
+unsigned
+MPP_TAGE::getUseAltIdx(TAGEBase::BranchInfo* bi, Addr branch_pc)
+{
+    uint32_t hpc = ((uint32_t) branch_pc);
+    hpc = (hpc ^(hpc >> 4));
+    return 2 * ((hpc & ((numUseAltOnNa/2)-1)) ^ bi->longestMatchPred) +
+           ((bi->hitBank > (nHistoryTables / 3)) ? 1 : 0);
+}
+
+void
+MPP_TAGE::adjustAlloc(bool & alloc, bool taken, bool pred_taken)
+{
+    // Do not allocate too often if the prediction is ok
+    if ((taken == pred_taken) && ((random_mt.random<int>() & 31) != 0)) {
+        alloc = false;
+    }
+}
+
+void
+MPP_TAGE::updateHistories(
+    ThreadID tid, Addr branch_pc, bool taken, TAGEBase::BranchInfo* b,
+    bool speculative, const StaticInstPtr &inst, Addr target)
+{
+    if (speculative != speculativeHistUpdate) {
+        return;
+    }
+    // speculation is not implemented
+    assert(! speculative);
+
+    ThreadHistory& tHist = threadHistory[tid];
+
+    int brtype = inst->isDirectCtrl() ? 0 : 2;
+    if (! inst->isUncondCtrl()) {
+        ++brtype;
+    }
+    updatePathAndGlobalHistory(tHist, brtype, taken, branch_pc, target);
+}
+
+void
+MPP_TAGE::updatePathAndGlobalHistory(
+    ThreadHistory& tHist, int brtype, bool taken, Addr branch_pc, Addr target)
+{
+    // TAGE update
+    int tmp = (branch_pc << 1) + taken;
+    int path = branch_pc;
+
+    int maxt = (brtype & 1) ? 1 : 4;
+
+    for (int t = 0; t < maxt; t++) {
+        bool dir = (tmp & 1);
+        tmp >>= 1;
+        int pathbit = (path & 127);
+        path >>= 1;
+        updateGHist(tHist.gHist, dir, tHist.globalHistory, tHist.ptGhist);
+        tHist.pathHist = (tHist.pathHist << 1) ^ pathbit;
+        for (int i = 1; i <= nHistoryTables; i++) {
+            tHist.computeIndices[i].update(tHist.gHist);
+            tHist.computeTags[0][i].update(tHist.gHist);
+            tHist.computeTags[1][i].update(tHist.gHist);
+        }
+    }
+}
+
+bool
+MPP_TAGE::isHighConfidence(TAGEBase::BranchInfo *bi) const
+{
+    if (bi->hitBank > 0) {
+        return (abs(2 * gtable[bi->hitBank][bi->hitBankIndex].ctr + 1)) >=
+               ((1 << tagTableCounterBits) - 1);
+    } else {
+        int bim = (btablePrediction[bi->bimodalIndex] << 1)
+            + btableHysteresis[bi->bimodalIndex >> logRatioBiModalHystEntries];
+        return (bim == 0) || (bim == 3);
+    }
+
+}
+
+MPP_TAGE*
+MPP_TAGEParams::create()
+{
+    return new MPP_TAGE(this);
+}
+
+bool
+MPP_LoopPredictor::calcConf(int index) const
+{
+    return LoopPredictor::calcConf(index) ||
+           (ltable[index].confidence * ltable[index].numIter > 128);
+}
+
+bool
+MPP_LoopPredictor::optionalAgeInc() const
+{
+    return ((random_mt.random<int>() & 7) == 0);
+}
+
+MPP_LoopPredictor*
+MPP_LoopPredictorParams::create()
+{
+    return new MPP_LoopPredictor(this);
+}
+
+MPP_StatisticalCorrector::MPP_StatisticalCorrector(
+        const MPP_StatisticalCorrectorParams *p) : StatisticalCorrector(p),
+    thirdH(0), pnb(p->pnb), logPnb(p->logPnb), pm(p->pm), gnb(p->gnb),
+    logGnb(p->logGnb), gm(p->gm)
+{
+    initGEHLTable(pnb, pm, pgehl, logPnb, wp, -1);
+    initGEHLTable(gnb, gm, ggehl, logGnb, wg, -1);
+
+    for (int8_t &pos : wl) {
+        pos = -1;
+    }
+}
+
+void
+MPP_StatisticalCorrector::initBias()
+{
+    for (int j = 0; j < (1 << logBias); j++) {
+        if (j & 1) {
+            bias[j] = 15;
+            biasSK[j] = 15;
+        } else {
+            bias[j] = -16;
+            biasSK[j] = -16;
+        }
+    }
+}
+
+unsigned
+MPP_StatisticalCorrector::getIndBias(Addr branch_pc,
+        StatisticalCorrector::BranchInfo* bi, bool bias) const
+{
+    unsigned int truncated_pc = branch_pc;
+    return ((truncated_pc << 1) + bi->predBeforeSC) & ((1 << logBias) - 1);
+}
+
+unsigned
+MPP_StatisticalCorrector::getIndBiasSK(Addr branch_pc,
+        StatisticalCorrector::BranchInfo* bi) const
+{
+    return (((branch_pc ^ (branch_pc >> (logBias - 1))) << 1)
+            + bi->predBeforeSC) & ((1 << logBias) - 1);
+}
+
+unsigned
+MPP_StatisticalCorrector::getIndBiasBank(Addr branch_pc,
+        StatisticalCorrector::BranchInfo* bi, int hitBank, int altBank) const
+{
+    return 0;
+}
+
+int
+MPP_StatisticalCorrector::gIndexLogsSubstr(int nbr, int i)
+{
+    return (i >= (nbr - 2)) ? 1 : 0;
+}
+
+unsigned
+MPP_StatisticalCorrector::getIndUpd(Addr branch_pc) const
+{
+    return ((branch_pc ^ (branch_pc >> 4)) & ((1 << (logSizeUp)) - 1));
+}
+
+void
+MPP_StatisticalCorrector::gUpdate(Addr branch_pc, bool taken, int64_t hist,
+                   std::vector<int> & length, std::vector<int8_t> * tab,
+                   int nbr, int logs, std::vector<int8_t> & w,
+                   StatisticalCorrector::BranchInfo* bi)
+{
+    int percsum = 0;
+    for (int i = 0; i < nbr; i++) {
+        int64_t bhist = hist & ((int64_t) ((1 << length[i]) - 1));
+        int64_t index = gIndex(branch_pc, bhist, logs, nbr, i);
+        percsum += (2 * tab[i][index] + 1);
+        ctrUpdate(tab[i][index], taken, scCountersWidth - (i < (nbr - 1)));
+    }
+}
+
+bool
+MPP_StatisticalCorrector::scPredict(ThreadID tid, Addr branch_pc,
+        bool cond_branch, StatisticalCorrector::BranchInfo* bi,
+        bool prev_pred_taken, bool bias_bit, bool use_conf_ctr,
+        int8_t conf_ctr, unsigned conf_bits, int hitBank, int altBank,
+        int64_t phist, int init_lsum)
+{
+    bool pred_taken = prev_pred_taken;
+    if (cond_branch) {
+
+        bi->predBeforeSC = prev_pred_taken;
+
+        int lsum = init_lsum;
+
+        getBiasLSUM(branch_pc, bi, lsum);
+
+        int thres = gPredictions(tid, branch_pc, bi, lsum, phist);
+
+        // These will be needed at update time
+        bi->lsum = lsum;
+        bi->thres = thres;
+        bi->scPred = (lsum >= 0);
+
+        if (pred_taken != bi->scPred) {
+            pred_taken = bi->scPred;
+
+            if (bi->highConf /* comes from tage prediction */) {
+              if ((abs(lsum) < thres / 3))
+                pred_taken = (firstH < 0) ? bi->scPred : prev_pred_taken;
+              else if ((abs(lsum) < 2 * thres / 3))
+                pred_taken = (secondH < 0) ? bi->scPred : prev_pred_taken;
+              else if ((abs(lsum) < thres))
+                pred_taken = (thirdH < 0) ? bi->scPred : prev_pred_taken;
+            }
+        }
+    }
+
+    return pred_taken;
+}
+
+MultiperspectivePerceptronTAGE::MultiperspectivePerceptronTAGE(
+    const MultiperspectivePerceptronTAGEParams *p)
+  : MultiperspectivePerceptron(p), tage(p->tage),
+    loopPredictor(p->loop_predictor),
+    statisticalCorrector(p->statistical_corrector)
+{
+    fatal_if(tage->isSpeculativeUpdateEnabled(),
+        "Speculative updates support is not implemented");
+}
+
+void
+MultiperspectivePerceptronTAGE::init()
+{
+    tage->init();
+    int numBitsTage = tage->getSizeInBits();
+    int numBitsLoopPred = loopPredictor->getSizeInBits();
+    int numBitsStatisticalCorrector = statisticalCorrector->getSizeInBits();
+
+    setExtraBits(numBitsTage + numBitsLoopPred + numBitsStatisticalCorrector);
+    MultiperspectivePerceptron::init();
+}
+
+
+unsigned int
+MultiperspectivePerceptronTAGE::getIndex(ThreadID tid, MPPTAGEBranchInfo &bi,
+        const HistorySpec &spec, int index) const
+{
+    // get the hash for the feature
+    unsigned int g = spec.getHash(tid, bi.getPC(), bi.getPC() >> 2, index);
+    // shift it and xor it with the hashed PC
+    unsigned long long int h = g;
+    h <<= 20;
+    h ^= (bi.getPC() ^ (bi.getPC() >> 2));
+
+    // maybe xor in an IMLI counter
+    if ((1ull << index) & imli_mask1) {
+        h += threadData[tid]->imli_counter[0];
+    }
+    if ((1ull << index) & imli_mask4) {
+        h += threadData[tid]->imli_counter[3];
+    }
+
+    // return it modulo the table size
+    return h % table_sizes[index];
+}
+
+
+int
+MultiperspectivePerceptronTAGE::computePartialSum(ThreadID tid,
+                                                  MPPTAGEBranchInfo &bi) const
+{
+    int yout = 0;
+    for (int i = 0; i < specs.size(); i += 1) {
+        yout += specs[i]->coeff *
+            threadData[tid]->tables[i][getIndex(tid, bi, *specs[i], i)];
+    }
+    return yout;
+}
+
+void
+MultiperspectivePerceptronTAGE::updatePartial(ThreadID tid,
+                                              MPPTAGEBranchInfo &bi,
+                                              bool taken)
+{
+    // update tables
+    for (int i = 0; i < specs.size(); i += 1) {
+        unsigned int idx = getIndex(tid, bi, *specs[i], i);
+        short int *c =
+            &threadData[tid]->tables[i][idx];
+        short int max_weight = (1 << (specs[i]->width - 1)) - 1;
+        short int min_weight = -(1 << (specs[i]->width - 1));
+        if (taken) {
+            if (*c < max_weight) {
+                *c += 1;
+            }
+        } else {
+            if (*c > min_weight) {
+                *c -= 1;
+            }
+        }
+    }
+}
+
+void
+MultiperspectivePerceptronTAGE::updateHistories(ThreadID tid,
+                                                MPPTAGEBranchInfo &bi,
+                                                bool taken)
+{
+    unsigned int hpc = (bi.getPC() ^ (bi.getPC() >> 2));
+    unsigned int pc = bi.getPC();
+
+    // update recency stack
+    unsigned short recency_pc = pc >> 2;
+    threadData[tid]->insertRecency(recency_pc, assoc);
+
+    // update acyclic history
+    threadData[tid]->updateAcyclic(taken, hpc);
+
+    // update modpath histories
+    for (int ii = 0; ii < modpath_indices.size(); ii +=1) {
+        int i = modpath_indices[ii];
+        if (hpc % (i + 2) == 0) {
+            memmove(&threadData[tid]->modpath_histories[i][1],
+                    &threadData[tid]->modpath_histories[i][0],
+                    sizeof(unsigned short int) * (modpath_lengths[ii] - 1));
+            threadData[tid]->modpath_histories[i][0] = hpc;
+        }
+    }
+
+    // update modulo histories
+    for (int ii = 0; ii < modhist_indices.size(); ii += 1) {
+        int i = modhist_indices[ii];
+        if (hpc % (i + 2) == 0) {
+            for (int j = modhist_lengths[ii] - 1; j > 0; j -= 1) {
+                threadData[tid]->mod_histories[i][j] =
+                    threadData[tid]->mod_histories[i][j-1];
+            }
+            threadData[tid]->mod_histories[i][0] = taken;
+        }
+    }
+
+    // update blurry history
+    std::vector<std::vector<unsigned int>> &blurrypath_histories =
+        threadData[tid]->blurrypath_histories;
+    for (int i = 0; i < blurrypath_histories.size(); i += 1)
+    {
+        if (blurrypath_histories[i].size() > 0) {
+            unsigned int z = pc >> i;
+            if (blurrypath_histories[i][0] != z) {
+                memmove(&blurrypath_histories[i][1],
+                        &blurrypath_histories[i][0],
+                        sizeof(unsigned int) *
+                        (blurrypath_histories[i].size() - 1));
+                blurrypath_histories[i][0] = z;
+            }
+        }
+    }
+}
+
+bool
+MultiperspectivePerceptronTAGE::lookup(ThreadID tid, Addr instPC,
+                                   void * &bp_history)
+{
+    MPPTAGEBranchInfo *bi =
+        new MPPTAGEBranchInfo(instPC, pcshift, true, *tage, *loopPredictor,
+                              *statisticalCorrector);
+    bp_history = (void *)bi;
+    bool pred_taken = tage->tagePredict(tid, instPC, true, bi->tageBranchInfo);
+
+    pred_taken = loopPredictor->loopPredict(tid, instPC, true,
+            bi->lpBranchInfo, pred_taken, instShiftAmt);
+
+    bi->scBranchInfo->highConf = tage->isHighConfidence(bi->tageBranchInfo);
+
+    int init_lsum = 22;
+    if (!pred_taken) {
+        init_lsum = -init_lsum;
+    }
+    init_lsum += computePartialSum(tid, *bi);
+
+    pred_taken = statisticalCorrector->scPredict(tid, instPC, true,
+            bi->scBranchInfo, pred_taken, false /* bias_bit: unused */,
+            false /* use_tage_ctr: unused */, 0 /* conf_ctr: unused */,
+            0 /* conf_bits: unused */, 0 /* hitBank: unused */,
+            0 /* altBank: unused */, tage->getPathHist(tid), init_lsum);
+    bi->predictedTaken = pred_taken;
+    bi->lpBranchInfo->predTaken = pred_taken;
+    return pred_taken;
+}
+
+
+void
+MPP_StatisticalCorrector::condBranchUpdate(ThreadID tid, Addr branch_pc,
+        bool taken, StatisticalCorrector::BranchInfo *bi, Addr corrTarget,
+        bool bias_bit, int hitBank, int altBank, int64_t phist)
+{
+    bool scPred = (bi->lsum >= 0);
+
+    if (bi->predBeforeSC != scPred) {
+        if (abs(bi->lsum) < bi->thres) {
+            if (bi->highConf) {
+                if (abs(bi->lsum) < bi->thres / 3) {
+                    ctrUpdate(firstH, (bi->predBeforeSC == taken),
+                              chooserConfWidth);
+                } else if (abs(bi->lsum) < 2 * bi->thres / 3) {
+                    ctrUpdate(secondH, (bi->predBeforeSC == taken),
+                              chooserConfWidth);
+                } else if (abs(bi->lsum) < bi->thres) {
+                    ctrUpdate(thirdH, (bi->predBeforeSC == taken),
+                              chooserConfWidth);
+                }
+            }
+        }
+    }
+
+    if ((scPred != taken) || ((abs(bi->lsum) < bi->thres))) {
+
+        ctrUpdate(pUpdateThreshold[getIndUpd(branch_pc)], (scPred != taken),
+                  pUpdateThresholdWidth + 1); //+1 because the sign is ignored
+        if (pUpdateThreshold[getIndUpd(branch_pc)] < 0)
+            pUpdateThreshold[getIndUpd(branch_pc)] = 0;
+
+        unsigned indBias = getIndBias(branch_pc, bi, false);
+        unsigned indBiasSK = getIndBiasSK(branch_pc, bi);
+
+        ctrUpdate(bias[indBias], taken, scCountersWidth);
+        ctrUpdate(biasSK[indBiasSK], taken, scCountersWidth);
+
+        gUpdates(tid, branch_pc, taken, bi, phist);
+    }
+}
+
+void
+MultiperspectivePerceptronTAGE::update(ThreadID tid, Addr instPC, bool taken,
+                                   void *bp_history, bool squashed,
+                                   const StaticInstPtr & inst,
+                                   Addr corrTarget)
+{
+    assert(bp_history);
+    MPPTAGEBranchInfo *bi = static_cast<MPPTAGEBranchInfo*>(bp_history);
+
+    assert(corrTarget != MaxAddr);
+
+    if (squashed) {
+        if (tage->isSpeculativeUpdateEnabled()) {
+            // This restores the global history, then update it
+            // and recomputes the folded histories.
+            tage->squash(tid, taken, bi->tageBranchInfo, corrTarget);
+            if (bi->tageBranchInfo->condBranch) {
+                loopPredictor->squashLoop(bi->lpBranchInfo);
+            }
+        }
+        return;
+    }
+
+    if (bi->isUnconditional()) {
+        statisticalCorrector->scHistoryUpdate(instPC, inst, taken,
+                bi->scBranchInfo, corrTarget);
+        tage->updateHistories(tid, instPC, taken, bi->tageBranchInfo, false,
+                inst, corrTarget);
+    } else {
+        tage->updateStats(taken, bi->tageBranchInfo);
+        loopPredictor->updateStats(taken, bi->lpBranchInfo);
+        statisticalCorrector->updateStats(taken, bi->scBranchInfo);
+
+        loopPredictor->condBranchUpdate(tid, instPC, taken,
+                bi->tageBranchInfo->tagePred, bi->lpBranchInfo, instShiftAmt);
+
+        bool scPred = (bi->scBranchInfo->lsum >= 0);
+        if ((scPred != taken) ||
+            ((abs(bi->scBranchInfo->lsum) < bi->scBranchInfo->thres))) {
+            updatePartial(tid, *bi, taken);
+        }
+        statisticalCorrector->condBranchUpdate(tid, instPC, taken,
+                bi->scBranchInfo, corrTarget, false /* bias_bit: unused */,
+                0 /* hitBank: unused */, 0 /* altBank: unused*/,
+                tage->getPathHist(tid));
+
+        tage->condBranchUpdate(tid, instPC, taken, bi->tageBranchInfo,
+                               random_mt.random<int>(), corrTarget,
+                               bi->predictedTaken, true);
+
+        updateHistories(tid, *bi, taken);
+
+        if (!tage->isSpeculativeUpdateEnabled()) {
+            if (inst->isCondCtrl() && inst->isDirectCtrl()
+                && !inst->isCall() && !inst->isReturn()) {
+                uint32_t truncated_target = corrTarget;
+                uint32_t truncated_pc = instPC;
+                if (truncated_target < truncated_pc) {
+                    if (!taken) {
+                        threadData[tid]->imli_counter[0] = 0;
+                    } else {
+                        threadData[tid]->imli_counter[0] += 1;
+                    }
+                } else {
+                    if (taken) {
+                        threadData[tid]->imli_counter[3] = 0;
+                    } else {
+                        threadData[tid]->imli_counter[3] += 1;
+                    }
+                }
+            }
+
+            statisticalCorrector->scHistoryUpdate(instPC, inst, taken,
+                    bi->scBranchInfo, corrTarget);
+
+            tage->updateHistories(tid, instPC, taken, bi->tageBranchInfo,
+                                  false, inst, corrTarget);
+        }
+    }
+    delete bi;
+}
+
+void
+MultiperspectivePerceptronTAGE::uncondBranch(ThreadID tid, Addr pc,
+                                             void * &bp_history)
+{
+    MPPTAGEBranchInfo *bi =
+        new MPPTAGEBranchInfo(pc, pcshift, false, *tage, *loopPredictor,
+                              *statisticalCorrector);
+    bp_history = (void *) bi;
+}
+
+void
+MultiperspectivePerceptronTAGE::squash(ThreadID tid, void *bp_history)
+{
+    assert(bp_history);
+    MPPTAGEBranchInfo *bi = static_cast<MPPTAGEBranchInfo*>(bp_history);
+    delete bi;
+}
diff --git a/src/cpu/pred/multiperspective_perceptron_tage.hh b/src/cpu/pred/multiperspective_perceptron_tage.hh
new file mode 100644
index 0000000..b18774e
--- /dev/null
+++ b/src/cpu/pred/multiperspective_perceptron_tage.hh
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2019 Texas A&M University
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. Neither the name of the copyright holder 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
+ *  HOLDER 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.
+ *
+ *  Author: Daniel A. Jiménez
+ *  Adapted to gem5 by: Javier Bueno Hedo
+ *
+ */
+
+/*
+ * Multiperspective Perceptron Predictor with TAGE (by Daniel A. Jiménez)
+ */
+
+#ifndef __CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_TAGE_HH__
+#define __CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_TAGE_HH__
+
+#include "cpu/pred/loop_predictor.hh"
+#include "cpu/pred/multiperspective_perceptron.hh"
+#include "cpu/pred/statistical_corrector.hh"
+#include "cpu/pred/tage_base.hh"
+#include "params/MPP_LoopPredictor.hh"
+#include "params/MPP_StatisticalCorrector.hh"
+#include "params/MPP_TAGE.hh"
+#include "params/MultiperspectivePerceptronTAGE.hh"
+
+class MPP_TAGE : public TAGEBase {
+    std::vector<unsigned int> tunedHistoryLengths;
+  public:
+    struct BranchInfo : public TAGEBase::BranchInfo {
+        BranchInfo(TAGEBase &tage) : TAGEBase::BranchInfo(tage)
+        {}
+        virtual ~BranchInfo()
+        {}
+    };
+
+    MPP_TAGE(const MPP_TAGEParams *p) : TAGEBase(p),
+        tunedHistoryLengths(p->tunedHistoryLengths)
+    {}
+
+    void calculateParameters() override;
+    void handleTAGEUpdate(Addr branch_pc, bool taken, TAGEBase::BranchInfo* bi)
+        override;
+    void handleAllocAndUReset(bool alloc, bool taken, TAGEBase::BranchInfo* bi,
+                              int nrand) override;
+    void handleUReset() override;
+    void resetUctr(uint8_t &u) override;
+    int bindex(Addr pc_in) const override;
+    bool isHighConfidence(TAGEBase::BranchInfo *bi) const override;
+
+    unsigned getUseAltIdx(TAGEBase::BranchInfo* bi, Addr branch_pc) override;
+    void adjustAlloc(bool & alloc, bool taken, bool pred_taken) override;
+    void updateHistories(ThreadID tid, Addr branch_pc, bool taken,
+                         TAGEBase::BranchInfo* b, bool speculative,
+                         const StaticInstPtr &inst, Addr target) override;
+
+    void updatePathAndGlobalHistory(ThreadHistory& tHist, int brtype,
+                                    bool taken, Addr branch_pc, Addr target);
+};
+
+class MPP_LoopPredictor : public LoopPredictor {
+  public:
+    MPP_LoopPredictor(MPP_LoopPredictorParams *p) : LoopPredictor(p)
+    {}
+
+    bool calcConf(int index) const override;
+    bool optionalAgeInc() const override;
+};
+
+class MPP_StatisticalCorrector : public StatisticalCorrector {
+  protected:
+    int8_t thirdH;
+    // global branch history variation GEHL
+    const unsigned pnb;
+    const unsigned logPnb;
+    std::vector<int> pm;
+    std::vector<int8_t> * pgehl;
+    std::vector<int8_t> wp;
+
+    // global branch history GEHL
+    const unsigned gnb;
+    const unsigned logGnb;
+    std::vector<int> gm;
+    std::vector<int8_t> * ggehl;
+    std::vector<int8_t> wg;
+
+    struct MPP_SCThreadHistory : public StatisticalCorrector::SCThreadHistory
+    {
+        MPP_SCThreadHistory() : globalHist(0), historyStack(16, 0),
+            historyStackPointer(0) {}
+        int64_t globalHist; // global history
+        std::vector<int64_t> historyStack;
+        unsigned int historyStackPointer;
+
+        int64_t getHistoryStackEntry() const
+        {
+            return historyStack[historyStackPointer];
+        }
+
+        void updateHistoryStack(Addr target, bool taken, bool is_call,
+                                bool is_return)
+        {
+            unsigned int truncated_target = target;
+            historyStack[historyStackPointer] =
+                (historyStack[historyStackPointer] << 1) ^ (truncated_target ^
+                (truncated_target >> 5) ^ taken);
+            if (is_return) {
+                historyStackPointer = (historyStackPointer - 1) %
+                    historyStack.size();
+            }
+            if (is_call) {
+                int index = (historyStackPointer + 1) % historyStack.size();
+                historyStack[index] = historyStack[historyStackPointer];
+                historyStackPointer = index;
+            }
+        }
+        unsigned int getPointer() const { return historyStackPointer; }
+    };
+
+  public:
+    struct BranchInfo : public StatisticalCorrector::BranchInfo {
+        virtual ~BranchInfo()
+        {}
+    };
+    MPP_StatisticalCorrector(const MPP_StatisticalCorrectorParams *p);
+
+    void initBias() override;
+    unsigned getIndBias(Addr branch_pc, StatisticalCorrector::BranchInfo* bi,
+                        bool bias) const override;
+    unsigned getIndBiasSK(Addr branch_pc, StatisticalCorrector::BranchInfo* bi)
+            const override;
+    unsigned getIndBiasBank(Addr branch_pc,
+                            StatisticalCorrector::BranchInfo* bi, int hitBank,
+                            int altBank) const override;
+    unsigned getIndUpd(Addr branch_pc) const override;
+    int gIndexLogsSubstr(int nbr, int i) override;
+
+    bool scPredict(ThreadID tid, Addr branch_pc, bool cond_branch,
+                   StatisticalCorrector::BranchInfo* bi, bool prev_pred_taken,
+                   bool bias_bit, bool use_conf_ctr, int8_t conf_ctr,
+                   unsigned conf_bits, int hitBank, int altBank, int64_t phist,
+                   int init_lsum) override;
+
+    void condBranchUpdate(ThreadID tid, Addr branch_pc, bool taken,
+                          StatisticalCorrector::BranchInfo *bi,
+                          Addr corrTarget, bool b, int hitBank, int altBank,
+                          int64_t phist) override;
+
+    virtual void getBiasLSUM(Addr branch_pc,
+            StatisticalCorrector::BranchInfo *bi, int &lsum) const = 0;
+
+    void gUpdate(
+        Addr branch_pc, bool taken, int64_t hist, std::vector<int> & length,
+        std::vector<int8_t> * tab, int nbr, int logs,
+        std::vector<int8_t> &w, StatisticalCorrector::BranchInfo* bi) override;
+};
+
+class MultiperspectivePerceptronTAGE : public MultiperspectivePerceptron
+{
+    TAGEBase *tage;
+    LoopPredictor *loopPredictor;
+    StatisticalCorrector *statisticalCorrector;
+
+    /**
+     * Branch information data type
+     */
+    struct MPPTAGEBranchInfo : public MPPBranchInfo
+    {
+        TAGEBase::BranchInfo *tageBranchInfo;
+        LoopPredictor::BranchInfo *lpBranchInfo;
+        StatisticalCorrector::BranchInfo *scBranchInfo;
+        bool predictedTaken;
+        MPPTAGEBranchInfo(Addr pc, int pcshift, bool cond, TAGEBase &tage,
+                          LoopPredictor &loopPredictor,
+                          StatisticalCorrector &statisticalCorrector)
+          : MPPBranchInfo(pc, pcshift, cond),
+            tageBranchInfo(tage.makeBranchInfo()),
+            lpBranchInfo(loopPredictor.makeBranchInfo()),
+            scBranchInfo(statisticalCorrector.makeBranchInfo()),
+            predictedTaken(false)
+        {}
+        virtual ~MPPTAGEBranchInfo()
+        {
+            delete tageBranchInfo;
+            delete lpBranchInfo;
+            delete scBranchInfo;
+        }
+    };
+
+    unsigned int getIndex(ThreadID tid, MPPTAGEBranchInfo &bi,
+                          const HistorySpec &spec, int index) const;
+    int computePartialSum(ThreadID tid, MPPTAGEBranchInfo &bi) const;
+    void updatePartial(ThreadID tid, MPPTAGEBranchInfo &bi, bool taken);
+    void updateHistories(ThreadID tid, MPPTAGEBranchInfo &bi, bool taken);
+
+  public:
+    MultiperspectivePerceptronTAGE(
+        const MultiperspectivePerceptronTAGEParams *p);
+
+    void init() override;
+
+    bool lookup(ThreadID tid, Addr instPC, void * &bp_history) override;
+
+    void update(ThreadID tid, Addr instPC, bool taken,
+            void *bp_history, bool squashed,
+            const StaticInstPtr & inst,
+            Addr corrTarget = MaxAddr) override;
+    void uncondBranch(ThreadID tid, Addr pc, void * &bp_history) override;
+    void squash(ThreadID tid, void *bp_history) override;
+
+};
+#endif//__CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_TAGE_HH__
diff --git a/src/cpu/pred/multiperspective_perceptron_tage_64KB.cc b/src/cpu/pred/multiperspective_perceptron_tage_64KB.cc
new file mode 100644
index 0000000..9da2167
--- /dev/null
+++ b/src/cpu/pred/multiperspective_perceptron_tage_64KB.cc
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2019 Texas A&M University
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. Neither the name of the copyright holder 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
+ *  HOLDER 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.
+ *
+ *  Author: Daniel A. Jiménez
+ *  Adapted to gem5 by: Javier Bueno Hedo
+ *
+ */
+
+/*
+ * Multiperspective Perceptron Predictor with TAGE (by Daniel A. Jiménez)
+ * 64 KB version
+ */
+
+#include "cpu/pred/multiperspective_perceptron_tage_64KB.hh"
+
+MPP_StatisticalCorrector_64KB::MPP_StatisticalCorrector_64KB(
+    const MPP_StatisticalCorrector_64KBParams *p)
+  : MPP_StatisticalCorrector(p),
+    numEntriesSecondLocalHistories(p->numEntriesSecondLocalHistories),
+    numEntriesThirdLocalHistories(p->numEntriesThirdLocalHistories),
+    snb(p->snb),
+    logSnb(p->logSnb),
+    sm(p->sm),
+    tnb(p->tnb),
+    logTnb(p->logTnb),
+    tm(p->tm)
+{
+    initGEHLTable(snb, sm, sgehl, logSnb, ws, -1);
+    initGEHLTable(tnb, tm, tgehl, logTnb, wt, -1);
+}
+
+MPP_StatisticalCorrector_64KB::SCThreadHistory*
+MPP_StatisticalCorrector_64KB::makeThreadHistory()
+{
+    MPP_SCThreadHistory *sh = new MPP_SCThreadHistory();
+
+    sh->setNumOrdinalHistories(3);
+    sh->initLocalHistory(1, numEntriesFirstLocalHistories, 4);
+    sh->initLocalHistory(2, numEntriesSecondLocalHistories, 5);
+    sh->initLocalHistory(3, numEntriesThirdLocalHistories, 3);
+
+    return sh;
+}
+
+
+void
+MPP_StatisticalCorrector_64KB::getBiasLSUM(Addr branch_pc,
+        StatisticalCorrector::BranchInfo* bi, int &lsum) const
+{
+    int8_t ctr = bias[getIndBias(branch_pc, bi, false /* unused */)];
+    lsum += 2.09 * ctr;
+    ctr = biasSK[getIndBiasSK(branch_pc, bi)];
+    lsum += 2.08 * ctr;
+}
+
+int
+MPP_StatisticalCorrector_64KB::gPredictions(ThreadID tid, Addr branch_pc,
+        StatisticalCorrector::BranchInfo* bi, int & lsum, int64_t phist)
+{
+    MPP_SCThreadHistory *sh = static_cast<MPP_SCThreadHistory *>(scHistory);
+    unsigned int pc = branch_pc;
+    lsum += gPredict((pc << 1) + bi->predBeforeSC, sh->globalHist << 11,
+                      gm, ggehl, gnb, logGnb, wg);
+
+    // Local History #1
+    lsum += 2.02 * gPredict(branch_pc, sh->getLocalHistory(1, branch_pc),
+                            lm, lgehl, lnb, logLnb, wl);
+    if (sh->getLocalHistory(1, branch_pc) == 2047) lsum += 4;
+    if (sh->getLocalHistory(1, branch_pc) == 0) lsum -= 4;
+
+    // Local History #3
+    lsum += gPredict(branch_pc, sh->getLocalHistory(3, branch_pc) << 11,
+                     tm, tgehl, tnb, logTnb, wt);
+
+    // Local History #2
+    lsum += gPredict(branch_pc, sh->getLocalHistory(2, branch_pc),
+                     sm, sgehl, snb, logSnb, ws);
+
+    lsum += gPredict(branch_pc, sh->getHistoryStackEntry(),
+                     pm, pgehl, pnb, logPnb, wp);
+
+    int thres = pUpdateThreshold[getIndUpd(branch_pc)];
+
+    return thres;
+}
+
+void
+MPP_StatisticalCorrector_64KB::gUpdates(ThreadID tid, Addr pc, bool taken,
+        StatisticalCorrector::BranchInfo* bi, int64_t phist)
+{
+    MPP_SCThreadHistory *sh = static_cast<MPP_SCThreadHistory *>(scHistory);
+
+    gUpdate((pc << 1) + bi->predBeforeSC, taken, sh->globalHist << 11,
+            gm, ggehl, gnb, logGnb, wg, bi);
+
+    gUpdate(pc, taken, sh->getLocalHistory(1, pc),
+            lm, lgehl, lnb, logLnb, wl, bi);
+
+    gUpdate(pc, taken, sh->getLocalHistory(2, pc),
+            sm, sgehl, snb, logSnb, ws, bi);
+
+    gUpdate(pc, taken, sh->getLocalHistory(3, pc) << 11,
+            tm, tgehl, tnb, logTnb, wt, bi);
+
+    gUpdate(pc, taken, sh->getHistoryStackEntry(),
+            pm, pgehl, pnb, logPnb, wp, bi);
+}
+
+void
+MPP_StatisticalCorrector_64KB::scHistoryUpdate(Addr branch_pc,
+        const StaticInstPtr &inst, bool taken,
+        StatisticalCorrector::BranchInfo *bi, Addr corrTarget)
+{
+    int brtype = inst->isDirectCtrl() ? 0 : 2;
+    if (! inst->isUncondCtrl()) {
+        ++brtype;
+    }
+
+    MPP_SCThreadHistory *sh = static_cast<MPP_SCThreadHistory *>(scHistory);
+
+    if (brtype & 1) {
+        sh->globalHist = (sh->globalHist << 1) + taken;
+        sh->updateLocalHistory(2, branch_pc, taken,
+                              (branch_pc ^ (branch_pc >> 4)) & 15);
+        sh->updateLocalHistory(3, branch_pc, taken);
+    }
+    sh->updateHistoryStack(corrTarget, taken, inst->isCall(),
+                           inst->isReturn());
+
+    StatisticalCorrector::scHistoryUpdate(branch_pc, inst, taken, bi,
+                                          corrTarget);
+}
+
+size_t
+MPP_StatisticalCorrector_64KB::getSizeInBits() const
+{
+    size_t bits = 16; //global histories
+
+    bits += (1 << logSizeUp) * pUpdateThresholdWidth;
+
+    bits += scCountersWidth * 2 * (1 << logBias); //2 bias arrays
+
+    bits += (gnb - 2) * (1 << logGnb) * (scCountersWidth - 1) +
+            (1 << (logGnb - 1)) * (2 * scCountersWidth - 1);
+
+    bits += (pnb - 2) * (1 << logPnb) * (scCountersWidth - 1) +
+            (1 << (logPnb - 1)) * (2 * scCountersWidth - 1);
+
+    bits += (lnb - 2) * (1 << logLnb) * (scCountersWidth - 1) +
+            (1 << (logLnb - 1)) * (2 * scCountersWidth - 1);
+
+    bits += numEntriesFirstLocalHistories * lm[0];
+
+    bits += (snb - 2) * (1 << logSnb) * (scCountersWidth - 1) +
+            (1 << (logSnb - 1)) * (2 * scCountersWidth - 1);
+
+    bits += numEntriesSecondLocalHistories * sm[0];
+
+    bits += (tnb - 2) * (1 << logTnb) * (scCountersWidth - 1) +
+            (1 << (logTnb - 1)) * (2 * scCountersWidth - 1);
+
+    /* tm[0] is artificially increased by 11 to accomodate IMLI */
+    bits += numEntriesThirdLocalHistories * (tm[0] - 11);
+
+    bits += 16 * 16; // History stack
+    bits += 4;       // History stack pointer
+
+    bits += 3 * chooserConfWidth; // 3 chooser counters
+
+    return bits;
+}
+
+MPP_StatisticalCorrector_64KB*
+MPP_StatisticalCorrector_64KBParams::create()
+{
+    return new MPP_StatisticalCorrector_64KB(this);
+}
+
+
+MultiperspectivePerceptronTAGE64KB::MultiperspectivePerceptronTAGE64KB(
+        const MultiperspectivePerceptronTAGE64KBParams *p)
+    : MultiperspectivePerceptronTAGE(p)
+{
+}
+
+void
+MultiperspectivePerceptronTAGE64KB::createSpecs()
+{
+    addSpec(new BLURRYPATH(5, 15, -1, 2.25, 0, 6, *this));
+    addSpec(new BLURRYPATH(8, 10, -1, 2.25, 0, 6, *this));
+    addSpec(new RECENCYPOS(31, 3.5, 0, 6, *this));
+    addSpec(new GHISTMODPATH(3, 7, 1, 2.24, 0, 6, *this));
+    addSpec(new MODPATH(3, 20, 3, 2.24, 0, 6, *this));
+    addSpec(new IMLI(1, 2.23, 0, 6, *this));
+    addSpec(new IMLI(4, 1.98, 0, 6, *this));
+    addSpec(new RECENCY(9, 3, -1, 2.51, 0, 6, *this));
+    addSpec(new ACYCLIC(12, -1, -1, 2.0, 0, 6, *this));
+}
+
+MultiperspectivePerceptronTAGE64KB*
+MultiperspectivePerceptronTAGE64KBParams::create()
+{
+    return new MultiperspectivePerceptronTAGE64KB(this);
+}
diff --git a/src/cpu/pred/multiperspective_perceptron_tage_64KB.hh b/src/cpu/pred/multiperspective_perceptron_tage_64KB.hh
new file mode 100644
index 0000000..aa5d37a
--- /dev/null
+++ b/src/cpu/pred/multiperspective_perceptron_tage_64KB.hh
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2019 Texas A&M University
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. Neither the name of the copyright holder 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
+ *  HOLDER 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.
+ *
+ *  Author: Daniel A. Jiménez
+ *  Adapted to gem5 by: Javier Bueno Hedo
+ *
+ */
+
+/*
+ * Multiperspective Perceptron Predictor with TAGE (by Daniel A. Jiménez)
+ * 64 KB version
+ */
+#ifndef __CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_TAGE_64KB_HH__
+#define __CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_TAGE_64KB_HH__
+
+#include "cpu/pred/multiperspective_perceptron_tage.hh"
+#include "params/MPP_StatisticalCorrector_64KB.hh"
+#include "params/MultiperspectivePerceptronTAGE64KB.hh"
+
+class MPP_StatisticalCorrector_64KB : public MPP_StatisticalCorrector {
+    const unsigned numEntriesSecondLocalHistories;
+    const unsigned numEntriesThirdLocalHistories;
+
+    // Second local history GEHL
+    const unsigned snb;
+    const unsigned logSnb;
+    std::vector<int> sm;
+    std::vector<int8_t> * sgehl;
+    std::vector<int8_t> ws;
+
+    // Third local history GEHL
+    const unsigned tnb;
+    const unsigned logTnb;
+    std::vector<int> tm;
+    std::vector<int8_t> * tgehl;
+    std::vector<int8_t> wt;
+
+    StatisticalCorrector::SCThreadHistory *makeThreadHistory() override;
+    int gPredictions(ThreadID tid, Addr branch_pc,
+            StatisticalCorrector::BranchInfo* bi, int &lsum, int64_t phist)
+            override;
+    void getBiasLSUM(Addr branch_pc,
+            StatisticalCorrector::BranchInfo *bi, int &lsum) const override;
+    void gUpdates(ThreadID tid, Addr pc, bool taken,
+            StatisticalCorrector::BranchInfo* bi, int64_t phist) override;
+    void scHistoryUpdate(Addr branch_pc, const StaticInstPtr &inst, bool taken,
+            StatisticalCorrector::BranchInfo *bi, Addr corrTarget) override;
+  public:
+    MPP_StatisticalCorrector_64KB(
+            const MPP_StatisticalCorrector_64KBParams *p);
+    size_t getSizeInBits() const override;
+};
+
+class MultiperspectivePerceptronTAGE64KB :
+        public MultiperspectivePerceptronTAGE {
+    void createSpecs() override;
+  public:
+    MultiperspectivePerceptronTAGE64KB(
+            const MultiperspectivePerceptronTAGE64KBParams *p);
+};
+
+#endif // __CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_TAGE_64KB_HH__
diff --git a/src/cpu/pred/multiperspective_perceptron_tage_8KB.cc b/src/cpu/pred/multiperspective_perceptron_tage_8KB.cc
new file mode 100644
index 0000000..872d817
--- /dev/null
+++ b/src/cpu/pred/multiperspective_perceptron_tage_8KB.cc
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2019 Texas A&M University
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. Neither the name of the copyright holder 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
+ *  HOLDER 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.
+ *
+ *  Author: Daniel A. Jiménez
+ *  Adapted to gem5 by: Javier Bueno Hedo
+ *
+ */
+
+/*
+ * Multiperspective Perceptron Predictor with TAGE (by Daniel A. Jiménez)
+ * 8 KB version
+ */
+
+#include "cpu/pred/multiperspective_perceptron_tage_8KB.hh"
+
+MPP_TAGE_8KB*
+MPP_TAGE_8KBParams::create()
+{
+    return new MPP_TAGE_8KB(this);
+}
+
+MPP_LoopPredictor_8KB*
+MPP_LoopPredictor_8KBParams::create()
+{
+    return new MPP_LoopPredictor_8KB(this);
+}
+
+MPP_StatisticalCorrector_8KB::MPP_StatisticalCorrector_8KB(
+        const MPP_StatisticalCorrector_8KBParams *p)
+  : MPP_StatisticalCorrector(p)
+{
+}
+
+MPP_StatisticalCorrector_8KB::SCThreadHistory*
+MPP_StatisticalCorrector_8KB::makeThreadHistory()
+{
+    MPP_SCThreadHistory *sh = new MPP_SCThreadHistory();
+
+    sh->setNumOrdinalHistories(1);
+    sh->initLocalHistory(1, numEntriesFirstLocalHistories, 4);
+
+    return sh;
+}
+
+void
+MPP_StatisticalCorrector_8KB::getBiasLSUM(Addr branch_pc,
+        StatisticalCorrector::BranchInfo* bi, int &lsum) const
+{
+    int8_t ctr = bias[getIndBias(branch_pc, bi, false /* unused */)];
+    lsum += 2 * ctr + 1;
+    ctr = biasSK[getIndBiasSK(branch_pc, bi)];
+    lsum += 2 * ctr + 1;
+}
+
+int
+MPP_StatisticalCorrector_8KB::gPredictions(ThreadID tid, Addr branch_pc,
+        StatisticalCorrector::BranchInfo* bi, int & lsum, int64_t phist)
+{
+    MPP_SCThreadHistory *sh = static_cast<MPP_SCThreadHistory *>(scHistory);
+    unsigned int pc = branch_pc;
+    lsum += gPredict((pc << 1) + bi->predBeforeSC, sh->globalHist << 11,
+                     gm, ggehl, gnb, logGnb, wg);
+
+    // Local History #1
+    lsum += 2 * gPredict(branch_pc, sh->getLocalHistory(1, branch_pc),
+                         lm, lgehl, lnb, logLnb, wl);
+    if (sh->getLocalHistory(1, branch_pc) == 2047) lsum += 4;
+    if (sh->getLocalHistory(1, branch_pc) == 0) lsum -= 4;
+
+    lsum += gPredict(branch_pc, sh->getHistoryStackEntry(),
+                     pm, pgehl, pnb, logPnb, wp);
+
+    int thres = pUpdateThreshold[getIndUpd(branch_pc)];
+
+    return thres;
+}
+
+void
+MPP_StatisticalCorrector_8KB::gUpdates(ThreadID tid, Addr pc, bool taken,
+        StatisticalCorrector::BranchInfo* bi, int64_t phist)
+{
+    MPP_SCThreadHistory *sh = static_cast<MPP_SCThreadHistory *>(scHistory);
+
+    gUpdate((pc << 1) + bi->predBeforeSC, taken, sh->globalHist << 11,
+            gm, ggehl, gnb, logGnb, wg, bi);
+
+    gUpdate(pc, taken, sh->getLocalHistory(1, pc),
+            lm, lgehl, lnb, logLnb, wl, bi);
+
+    gUpdate(pc, taken, sh->getHistoryStackEntry(),
+            pm, pgehl, pnb, logPnb, wp, bi);
+}
+
+void
+MPP_StatisticalCorrector_8KB::scHistoryUpdate(Addr branch_pc,
+        const StaticInstPtr &inst, bool taken,
+        StatisticalCorrector::BranchInfo *bi, Addr corrTarget)
+{
+    int brtype = inst->isDirectCtrl() ? 0 : 2;
+    if (! inst->isUncondCtrl()) {
+        ++brtype;
+    }
+
+    MPP_SCThreadHistory *sh = static_cast<MPP_SCThreadHistory *>(scHistory);
+
+    if (brtype & 1) {
+        sh->globalHist = (sh->globalHist << 1) + taken;
+    }
+    sh->updateHistoryStack(corrTarget, taken, inst->isCall(),
+                           inst->isReturn());
+
+    StatisticalCorrector::scHistoryUpdate(branch_pc, inst, taken, bi,
+                                          corrTarget);
+}
+
+size_t
+MPP_StatisticalCorrector_8KB::getSizeInBits() const
+{
+    size_t bits = 16; //global histories
+
+    bits += (1 << logSizeUp) * pUpdateThresholdWidth;
+
+    bits += scCountersWidth * 2 * (1 << logBias); //2 bias arrays
+
+    bits += (gnb - 2) * (1 << logGnb) * (scCountersWidth - 1) +
+            (1 << (logGnb - 1)) * (2 * scCountersWidth - 1);
+
+    bits += (pnb - 2) * (1 << logPnb) * (scCountersWidth - 1) +
+            (1 << (logPnb - 1)) * (2 * scCountersWidth - 1);
+
+    bits += (lnb - 2) * (1 << logLnb) * (scCountersWidth - 1) +
+            (1 << (logLnb - 1)) * (2 * scCountersWidth - 1);
+
+    bits += numEntriesFirstLocalHistories * lm[0];
+
+    bits += 16 * 16; // History stack
+    bits += 4;       // History stack pointer
+
+    bits += 3 * chooserConfWidth; // 3 chooser counters
+
+    return bits;
+}
+
+MPP_StatisticalCorrector_8KB*
+MPP_StatisticalCorrector_8KBParams::create()
+{
+    return new MPP_StatisticalCorrector_8KB(this);
+}
+
+MultiperspectivePerceptronTAGE8KB::MultiperspectivePerceptronTAGE8KB(
+        const MultiperspectivePerceptronTAGE8KBParams *p)
+    : MultiperspectivePerceptronTAGE(p)
+{
+}
+
+void
+MultiperspectivePerceptronTAGE8KB::createSpecs()
+{
+    addSpec(new BLURRYPATH(5, 15, -1, 2.25, 0, 6, *this));
+    addSpec(new RECENCYPOS(31, 3.5, 0, 6, *this));
+    addSpec(new GHISTMODPATH(3, 7, 1, 2.24, 0, 6, *this));
+    addSpec(new IMLI(1, 2.23, 0, 6, *this));
+    addSpec(new IMLI(4, 1.98, 0, 6, *this));
+}
+
+MultiperspectivePerceptronTAGE8KB*
+MultiperspectivePerceptronTAGE8KBParams::create()
+{
+    return new MultiperspectivePerceptronTAGE8KB(this);
+}
diff --git a/src/cpu/pred/multiperspective_perceptron_tage_8KB.hh b/src/cpu/pred/multiperspective_perceptron_tage_8KB.hh
new file mode 100644
index 0000000..1bfec93
--- /dev/null
+++ b/src/cpu/pred/multiperspective_perceptron_tage_8KB.hh
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019 Texas A&M University
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. Neither the name of the copyright holder 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
+ *  HOLDER 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.
+ *
+ *  Author: Daniel A. Jiménez
+ *  Adapted to gem5 by: Javier Bueno Hedo
+ *
+ */
+
+/*
+ * Multiperspective Perceptron Predictor with TAGE (by Daniel A. Jiménez)
+ * 8 KB version
+ */
+
+#ifndef __CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_TAGE_8KB_HH__
+#define __CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_TAGE_8KB_HH__
+
+#include "cpu/pred/multiperspective_perceptron_tage.hh"
+#include "params/MPP_LoopPredictor_8KB.hh"
+#include "params/MPP_StatisticalCorrector_8KB.hh"
+#include "params/MPP_TAGE_8KB.hh"
+#include "params/MultiperspectivePerceptronTAGE8KB.hh"
+
+class MPP_TAGE_8KB : public MPP_TAGE {
+  public:
+    MPP_TAGE_8KB(const MPP_TAGE_8KBParams *p) : MPP_TAGE(p) {}
+};
+
+class MPP_LoopPredictor_8KB : public MPP_LoopPredictor {
+  public:
+    MPP_LoopPredictor_8KB(MPP_LoopPredictor_8KBParams *p) :
+        MPP_LoopPredictor(p) {}
+};
+
+class MPP_StatisticalCorrector_8KB : public MPP_StatisticalCorrector {
+    StatisticalCorrector::SCThreadHistory *makeThreadHistory() override;
+    int gPredictions(ThreadID tid, Addr branch_pc,
+            StatisticalCorrector::BranchInfo* bi, int &lsum, int64_t phist)
+            override;
+    void getBiasLSUM(Addr branch_pc,
+            StatisticalCorrector::BranchInfo *bi, int &lsum) const override;
+    void gUpdates(ThreadID tid, Addr pc, bool taken,
+            StatisticalCorrector::BranchInfo* bi, int64_t phist) override;
+    void scHistoryUpdate(Addr branch_pc, const StaticInstPtr &inst, bool taken,
+            StatisticalCorrector::BranchInfo *bi, Addr corrTarget) override;
+  public:
+    MPP_StatisticalCorrector_8KB(const MPP_StatisticalCorrector_8KBParams *p);
+    size_t getSizeInBits() const override;
+};
+
+class MultiperspectivePerceptronTAGE8KB :
+        public MultiperspectivePerceptronTAGE {
+    void createSpecs() override;
+  public:
+    MultiperspectivePerceptronTAGE8KB(
+            const MultiperspectivePerceptronTAGE8KBParams *p);
+};
+
+#endif // __CPU_PRED_MULTIPERSPECTIVE_PERCEPTRON_TAGE_8KB_HH__
diff --git a/src/cpu/pred/statistical_corrector.cc b/src/cpu/pred/statistical_corrector.cc
index ebacd4d..8ddae9b 100644
--- a/src/cpu/pred/statistical_corrector.cc
+++ b/src/cpu/pred/statistical_corrector.cc
@@ -69,17 +69,34 @@
 {
     wb.resize(1 << logSizeUps, 4);
 
-    initGEHLTable(lnb, lm, lgehl, logLnb, wl, 7);
-    initGEHLTable(bwnb, bwm, bwgehl, logBwnb, wbw, 7);
-    initGEHLTable(inb, im, igehl, logInb, wi, 7);
+    initGEHLTable(lnb, lm, lgehl, logLnb, wl, p->lWeightInitValue);
+    initGEHLTable(bwnb, bwm, bwgehl, logBwnb, wbw, p->bwWeightInitValue);
+    initGEHLTable(inb, im, igehl, logInb, wi, p->iWeightInitValue);
 
     updateThreshold = 35 << 3;
 
-    pUpdateThreshold.resize(1 << logSizeUp, 0);
+    pUpdateThreshold.resize(1 << logSizeUp, p->initialUpdateThresholdValue);
 
     bias.resize(1 << logBias);
     biasSK.resize(1 << logBias);
     biasBank.resize(1 << logBias);
+}
+
+StatisticalCorrector::BranchInfo*
+StatisticalCorrector::makeBranchInfo()
+{
+    return new BranchInfo();
+}
+
+StatisticalCorrector::SCThreadHistory*
+StatisticalCorrector::makeThreadHistory()
+{
+    return new SCThreadHistory();
+}
+
+void
+StatisticalCorrector::initBias()
+{
     for (int j = 0; j < (1 << logBias); j++) {
         switch (j & 3) {
           case 0:
@@ -106,18 +123,6 @@
     }
 }
 
-StatisticalCorrector::BranchInfo*
-StatisticalCorrector::makeBranchInfo()
-{
-    return new BranchInfo();
-}
-
-StatisticalCorrector::SCThreadHistory*
-StatisticalCorrector::makeThreadHistory()
-{
-    return new SCThreadHistory();
-}
-
 void
 StatisticalCorrector::initGEHLTable(unsigned numLenghts,
     std::vector<int> lengths, std::vector<int8_t> * & table,
@@ -218,7 +223,7 @@
 StatisticalCorrector::scPredict(ThreadID tid, Addr branch_pc, bool cond_branch,
                      BranchInfo* bi, bool prev_pred_taken, bool bias_bit,
                      bool use_conf_ctr, int8_t conf_ctr, unsigned conf_bits,
-                     int hitBank, int altBank, int64_t phist)
+                     int hitBank, int altBank, int64_t phist, int init_lsum)
 {
     bool pred_taken = prev_pred_taken;
     if (cond_branch) {
@@ -232,7 +237,7 @@
             bi->highConf = (abs(2 * conf_ctr + 1) >= (1<<conf_bits) - 1);
         }
 
-        int lsum = 0;
+        int lsum = init_lsum;
 
         int8_t ctr = bias[getIndBias(branch_pc, bi, bias_bit)];
         lsum += (2 * ctr + 1);
@@ -280,9 +285,14 @@
 }
 
 void
-StatisticalCorrector::scHistoryUpdate(Addr branch_pc, int brtype, bool taken,
-                           BranchInfo * tage_bi, Addr corrTarget)
+StatisticalCorrector::scHistoryUpdate(Addr branch_pc,
+        const StaticInstPtr &inst, bool taken, BranchInfo * tage_bi,
+        Addr corrTarget)
 {
+    int brtype = inst->isDirectCtrl() ? 0 : 2;
+    if (! inst->isUncondCtrl()) {
+        ++brtype;
+    }
     // Non speculative SC histories update
     if (brtype & 1) {
         if (corrTarget < branch_pc) {
@@ -376,6 +386,14 @@
 StatisticalCorrector::init()
 {
     scHistory = makeThreadHistory();
+    initBias();
+}
+
+size_t
+StatisticalCorrector::getSizeInBits() const
+{
+    // Not implemented
+    return 0;
 }
 
 void
diff --git a/src/cpu/pred/statistical_corrector.hh b/src/cpu/pred/statistical_corrector.hh
index f966843..2e8e502 100644
--- a/src/cpu/pred/statistical_corrector.hh
+++ b/src/cpu/pred/statistical_corrector.hh
@@ -44,24 +44,27 @@
 
 #include "base/statistics.hh"
 #include "base/types.hh"
+#include "cpu/static_inst.hh"
 #include "sim/sim_object.hh"
 
 struct StatisticalCorrectorParams;
 
 class StatisticalCorrector : public SimObject
 {
+  protected:
     template<typename T>
     inline void ctrUpdate(T & ctr, bool taken, int nbits) {
         assert(nbits <= sizeof(T) << 3);
-        if (taken) {
-            if (ctr < ((1 << (nbits - 1)) - 1))
-                ctr++;
-        } else {
-            if (ctr > -(1 << (nbits - 1)))
-                ctr--;
+        if (nbits > 0) {
+            if (taken) {
+                if (ctr < ((1 << (nbits - 1)) - 1))
+                    ctr++;
+            } else {
+                if (ctr > -(1 << (nbits - 1)))
+                    ctr--;
+            }
         }
     }
-  protected:
     // histories used for the statistical corrector
     struct SCThreadHistory {
         SCThreadHistory() {
@@ -209,20 +212,22 @@
     virtual BranchInfo *makeBranchInfo();
     virtual SCThreadHistory *makeThreadHistory();
 
-    bool scPredict(
+    virtual void initBias();
+
+    virtual bool scPredict(
         ThreadID tid, Addr branch_pc, bool cond_branch, BranchInfo* bi,
         bool prev_pred_taken, bool bias_bit, bool use_conf_ctr,
         int8_t conf_ctr, unsigned conf_bits, int hitBank, int altBank,
-        int64_t phist);
+        int64_t phist, int init_lsum = 0);
 
-    unsigned getIndBias(Addr branch_pc, BranchInfo* bi, bool b) const;
+    virtual unsigned getIndBias(Addr branch_pc, BranchInfo* bi, bool b) const;
 
-    unsigned getIndBiasSK(Addr branch_pc, BranchInfo* bi) const;
+    virtual unsigned getIndBiasSK(Addr branch_pc, BranchInfo* bi) const;
 
     virtual unsigned getIndBiasBank( Addr branch_pc, BranchInfo* bi,
         int hitBank, int altBank) const = 0;
 
-    unsigned getIndUpd(Addr branch_pc) const;
+    virtual unsigned getIndUpd(Addr branch_pc) const;
     unsigned getIndUpds(Addr branch_pc) const;
 
     virtual int gPredictions(ThreadID tid, Addr branch_pc, BranchInfo* bi,
@@ -237,7 +242,7 @@
         std::vector<int8_t> * tab, int nbr, int logs,
         std::vector<int8_t> & w);
 
-    void gUpdate(
+    virtual void gUpdate(
         Addr branch_pc, bool taken, int64_t hist, std::vector<int> & length,
         std::vector<int8_t> * tab, int nbr, int logs,
         std::vector<int8_t> & w, BranchInfo* bi);
@@ -248,8 +253,8 @@
         std::vector<int8_t> & w, int8_t wInitValue);
 
     virtual void scHistoryUpdate(
-        Addr branch_pc, int brtype, bool taken, BranchInfo * tage_bi,
-        Addr corrTarget);
+        Addr branch_pc, const StaticInstPtr &inst , bool taken,
+        BranchInfo * tage_bi, Addr corrTarget);
 
     virtual void gUpdates( ThreadID tid, Addr pc, bool taken, BranchInfo* bi,
         int64_t phist) = 0;
@@ -258,8 +263,10 @@
     void regStats() override;
     void updateStats(bool taken, BranchInfo *bi);
 
-    void condBranchUpdate(ThreadID tid, Addr branch_pc, bool taken,
+    virtual void condBranchUpdate(ThreadID tid, Addr branch_pc, bool taken,
                           BranchInfo *bi, Addr corrTarget, bool bias_bit,
                           int hitBank, int altBank, int64_t phist);
+
+    virtual size_t getSizeInBits() const;
 };
 #endif//__CPU_PRED_STATISTICAL_CORRECTOR_HH
diff --git a/src/cpu/pred/tage_base.cc b/src/cpu/pred/tage_base.cc
index 2d149ea..4f6091b 100644
--- a/src/cpu/pred/tage_base.cc
+++ b/src/cpu/pred/tage_base.cc
@@ -59,12 +59,14 @@
      logTagTableSizes(p->logTagTableSizes),
      threadHistory(p->numThreads),
      logUResetPeriod(p->logUResetPeriod),
+     initialTCounterValue(p->initialTCounterValue),
      numUseAltOnNa(p->numUseAltOnNa),
      useAltOnNaBits(p->useAltOnNaBits),
      maxNumAlloc(p->maxNumAlloc),
      noSkip(p->noSkip),
      speculativeHistUpdate(p->speculativeHistUpdate),
-     instShiftAmt(p->instShiftAmt)
+     instShiftAmt(p->instShiftAmt),
+     initialized(false)
 {
     if (noSkip.empty()) {
         // Set all the table to enabled by default
@@ -80,6 +82,9 @@
 void
 TAGEBase::init()
 {
+    if (initialized) {
+       return;
+    }
     // Current method for periodically resetting the u counter bits only
     // works for 1 or 2 bits
     // Also make sure that it is not 0
@@ -91,7 +96,7 @@
 
     // initialize the counter to half of the period
     assert(logUResetPeriod != 0);
-    tCounter = ULL(1) << (logUResetPeriod - 1);
+    tCounter = initialTCounterValue;
 
     assert(histBufferSize > maxHist * 2);
 
@@ -134,6 +139,7 @@
 
     tableIndices = new int [nHistoryTables+1];
     tableTags = new int [nHistoryTables+1];
+    initialized = true;
 }
 
 void
@@ -339,7 +345,7 @@
 }
 
 unsigned
-TAGEBase::getUseAltIdx(BranchInfo* bi)
+TAGEBase::getUseAltIdx(BranchInfo* bi, Addr branch_pc)
 {
     // There is only 1 counter on the base TAGE implementation
     return 0;
@@ -397,8 +403,8 @@
             //if the entry is recognized as a newly allocated entry and
             //useAltPredForNewlyAllocated is positive use the alternate
             //prediction
-            if ((useAltPredForNewlyAllocated[getUseAltIdx(bi)] < 0) ||
-                ! bi->pseudoNewAlloc) {
+            if ((useAltPredForNewlyAllocated[getUseAltIdx(bi, branch_pc)] < 0)
+                || ! bi->pseudoNewAlloc) {
                 bi->tagePred = bi->longestMatchPred;
                 bi->provider = TAGE_LONGEST_MATCH;
             } else {
@@ -501,11 +507,16 @@
 
 void
 TAGEBase::condBranchUpdate(ThreadID tid, Addr branch_pc, bool taken,
-                       BranchInfo* bi, int nrand, Addr corrTarget, bool pred)
+    BranchInfo* bi, int nrand, Addr corrTarget, bool pred, bool preAdjustAlloc)
 {
     // TAGE UPDATE
     // try to allocate a  new entries only if prediction was wrong
     bool alloc = (bi->tagePred != taken) && (bi->hitBank < nHistoryTables);
+
+    if (preAdjustAlloc) {
+        adjustAlloc(alloc, taken, pred);
+    }
+
     if (bi->hitBank > 0) {
         // Manage the selection between longest matching and alternate
         // matching for "pseudo"-newly allocated longest matching entry
@@ -519,13 +530,16 @@
             // if it was delivering the correct prediction, no need to
             // allocate new entry even if the overall prediction was false
             if (bi->longestMatchPred != bi->altTaken) {
-                ctrUpdate(useAltPredForNewlyAllocated[getUseAltIdx(bi)],
-                     bi->altTaken == taken, useAltOnNaBits);
+                ctrUpdate(
+                    useAltPredForNewlyAllocated[getUseAltIdx(bi, branch_pc)],
+                    bi->altTaken == taken, useAltOnNaBits);
             }
         }
     }
 
-    adjustAlloc(alloc, taken, pred);
+    if (!preAdjustAlloc) {
+        adjustAlloc(alloc, taken, pred);
+    }
 
     handleAllocAndUReset(alloc, taken, bi, nrand);
 
@@ -789,6 +803,23 @@
     return speculativeHistUpdate;
 }
 
+size_t
+TAGEBase::getSizeInBits() const {
+    size_t bits = 0;
+    for (int i = 1; i <= nHistoryTables; i++) {
+        bits += (1 << logTagTableSizes[i]) *
+            (tagTableCounterBits + tagTableUBits + tagTableTagWidths[i]);
+    }
+    uint64_t bimodalTableSize = ULL(1) << logTagTableSizes[0];
+    bits += numUseAltOnNa * useAltOnNaBits;
+    bits += bimodalTableSize;
+    bits += (bimodalTableSize >> logRatioBiModalHystEntries);
+    bits += histLengths[nHistoryTables];
+    bits += pathHistBits;
+    bits += logUResetPeriod;
+    return bits;
+}
+
 TAGEBase*
 TAGEBaseParams::create()
 {
diff --git a/src/cpu/pred/tage_base.hh b/src/cpu/pred/tage_base.hh
index 48daaf9..9d5451e 100644
--- a/src/cpu/pred/tage_base.hh
+++ b/src/cpu/pred/tage_base.hh
@@ -318,10 +318,12 @@
      * @nrand Random int number from 0 to 3
      * @param corrTarget The correct branch target
      * @param pred Final prediction for this branch
+     * @param preAdjustAlloc call adjustAlloc before checking
+     * pseudo newly allocated entries
      */
     virtual void condBranchUpdate(
         ThreadID tid, Addr branch_pc, bool taken, BranchInfo* bi,
-        int nrand, Addr corrTarget, bool pred);
+        int nrand, Addr corrTarget, bool pred, bool preAdjustAlloc = false);
 
     /**
      * TAGE prediction called from TAGE::predict
@@ -364,7 +366,7 @@
      * Calculation of the index for useAltPredForNewlyAllocated
      * On this base TAGE implementation it is always 0
      */
-    virtual unsigned getUseAltIdx(BranchInfo* bi);
+    virtual unsigned getUseAltIdx(BranchInfo* bi, Addr branch_pc);
 
     /**
      * Extra calculation to tell whether TAGE allocaitons may happen or not
@@ -401,12 +403,18 @@
      */
     virtual void extraAltCalc(BranchInfo* bi);
 
+    virtual bool isHighConfidence(BranchInfo* bi) const
+    {
+        return false;
+    }
+
     void btbUpdate(ThreadID tid, Addr branch_addr, BranchInfo* &bi);
     unsigned getGHR(ThreadID tid, BranchInfo *bi) const;
     int8_t getCtr(int hitBank, int hitBankIndex) const;
     unsigned getTageCtrBits() const;
     int getPathHist(ThreadID tid) const;
     bool isSpeculativeUpdateEnabled() const;
+    size_t getSizeInBits() const;
 
   protected:
     const unsigned logRatioBiModalHystEntries;
@@ -462,6 +470,7 @@
     std::vector<int8_t> useAltPredForNewlyAllocated;
     int64_t tCounter;
     uint64_t logUResetPeriod;
+    const int64_t initialTCounterValue;
     unsigned numUseAltOnNa;
     unsigned useAltOnNaBits;
     unsigned maxNumAlloc;
@@ -475,6 +484,8 @@
 
     const unsigned instShiftAmt;
 
+    bool initialized;
+
     // stats
     Stats::Scalar tageLongestMatchProviderCorrect;
     Stats::Scalar tageAltMatchProviderCorrect;
diff --git a/src/cpu/pred/tage_sc_l.cc b/src/cpu/pred/tage_sc_l.cc
index 5f17b81..de7c2f2 100644
--- a/src/cpu/pred/tage_sc_l.cc
+++ b/src/cpu/pred/tage_sc_l.cc
@@ -168,7 +168,7 @@
 }
 
 unsigned
-TAGE_SC_L_TAGE::getUseAltIdx(TAGEBase::BranchInfo* bi)
+TAGE_SC_L_TAGE::getUseAltIdx(TAGEBase::BranchInfo* bi, Addr branch_pc)
 {
     BranchInfo *tbi = static_cast<BranchInfo *>(bi);
     unsigned idx;
@@ -457,12 +457,7 @@
     }
 
     if (!tage->isSpeculativeUpdateEnabled()) {
-        int brtype = inst->isDirectCtrl() ? 0 : 2;
-        if (! inst->isUncondCtrl()) {
-            ++brtype;
-        }
-
-        statisticalCorrector->scHistoryUpdate(branch_pc, brtype, taken,
+        statisticalCorrector->scHistoryUpdate(branch_pc, inst, taken,
                                               bi->scBranchInfo, corrTarget);
 
         tage->updateHistories(tid, branch_pc, taken, bi->tageBranchInfo, false,
diff --git a/src/cpu/pred/tage_sc_l.hh b/src/cpu/pred/tage_sc_l.hh
index c96cc89..b3629ab 100644
--- a/src/cpu/pred/tage_sc_l.hh
+++ b/src/cpu/pred/tage_sc_l.hh
@@ -94,7 +94,7 @@
     void calculateIndicesAndTags(
         ThreadID tid, Addr branch_pc, TAGEBase::BranchInfo* bi) override;
 
-    unsigned getUseAltIdx(TAGEBase::BranchInfo* bi) override;
+    unsigned getUseAltIdx(TAGEBase::BranchInfo* bi, Addr branch_pc) override;
 
     void updateHistories(
         ThreadID tid, Addr branch_pc, bool taken, TAGEBase::BranchInfo* b,
diff --git a/src/cpu/pred/tage_sc_l_64KB.cc b/src/cpu/pred/tage_sc_l_64KB.cc
index 164d587..72676e7 100644
--- a/src/cpu/pred/tage_sc_l_64KB.cc
+++ b/src/cpu/pred/tage_sc_l_64KB.cc
@@ -139,8 +139,13 @@
 
 void
 TAGE_SC_L_64KB_StatisticalCorrector::scHistoryUpdate(Addr branch_pc,
-        int brtype, bool taken, BranchInfo* tage_bi, Addr corrTarget)
+        const StaticInstPtr &inst, bool taken, BranchInfo* tage_bi,
+        Addr corrTarget)
 {
+    int brtype = inst->isDirectCtrl() ? 0 : 2;
+    if (! inst->isUncondCtrl()) {
+        ++brtype;
+    }
     // Non speculative SC histories update
     if (brtype & 1) {
         SC_64KB_ThreadHistory *sh =
@@ -152,7 +157,7 @@
         sh->updateLocalHistory(3, branch_pc, taken);
     }
 
-    StatisticalCorrector::scHistoryUpdate(branch_pc, brtype, taken, tage_bi,
+    StatisticalCorrector::scHistoryUpdate(branch_pc, inst, taken, tage_bi,
                                           corrTarget);
 }
 
diff --git a/src/cpu/pred/tage_sc_l_64KB.hh b/src/cpu/pred/tage_sc_l_64KB.hh
index 21dd170..4928ba5 100644
--- a/src/cpu/pred/tage_sc_l_64KB.hh
+++ b/src/cpu/pred/tage_sc_l_64KB.hh
@@ -118,7 +118,7 @@
 
     int gIndexLogsSubstr(int nbr, int i) override;
 
-    void scHistoryUpdate(Addr branch_pc, int brtype, bool taken,
+    void scHistoryUpdate(Addr branch_pc, const StaticInstPtr &inst, bool taken,
                          BranchInfo * tage_bi, Addr corrTarget) override;
 
     void gUpdates(ThreadID tid, Addr pc, bool taken, BranchInfo* bi,
diff --git a/src/cpu/pred/tage_sc_l_8KB.cc b/src/cpu/pred/tage_sc_l_8KB.cc
index 9af21e1..2455990 100644
--- a/src/cpu/pred/tage_sc_l_8KB.cc
+++ b/src/cpu/pred/tage_sc_l_8KB.cc
@@ -101,9 +101,14 @@
 }
 
 void
-TAGE_SC_L_8KB_StatisticalCorrector::scHistoryUpdate(Addr branch_pc, int brtype,
-    bool taken, BranchInfo * tage_bi, Addr corrTarget)
+TAGE_SC_L_8KB_StatisticalCorrector::scHistoryUpdate(Addr branch_pc,
+    const StaticInstPtr &inst, bool taken, BranchInfo *tage_bi,
+    Addr corrTarget)
 {
+    int brtype = inst->isDirectCtrl() ? 0 : 2;
+    if (! inst->isUncondCtrl()) {
+        ++brtype;
+    }
     // Non speculative SC histories update
     if (brtype & 1) {
         SC_8KB_ThreadHistory *sh =
@@ -111,7 +116,7 @@
         sh->globalHist = (sh->globalHist << 1) + taken;
     }
 
-    StatisticalCorrector::scHistoryUpdate(branch_pc, brtype, taken, tage_bi,
+    StatisticalCorrector::scHistoryUpdate(branch_pc, inst, taken, tage_bi,
                                           corrTarget);
 }
 
diff --git a/src/cpu/pred/tage_sc_l_8KB.hh b/src/cpu/pred/tage_sc_l_8KB.hh
index 74193b0..7730463 100644
--- a/src/cpu/pred/tage_sc_l_8KB.hh
+++ b/src/cpu/pred/tage_sc_l_8KB.hh
@@ -99,8 +99,8 @@
     int gIndexLogsSubstr(int nbr, int i) override;
 
     void scHistoryUpdate(
-        Addr branch_pc, int brtype, bool taken, BranchInfo * tage_bi,
-        Addr corrTarget) override;
+        Addr branch_pc, const StaticInstPtr &inst, bool taken,
+        BranchInfo * tage_bi, Addr corrTarget) override;
 
     void gUpdates(ThreadID tid, Addr pc, bool taken, BranchInfo* bi,
         int64_t phist) override;