cpu: Unify error handling for address generators

Unify error handling and create factory methods for address
generators.

Change-Id: Ic3ab705e1bb58affd498a7db176536ebc721b904
Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/11516
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
diff --git a/src/cpu/testers/traffic_gen/base.cc b/src/cpu/testers/traffic_gen/base.cc
index 9ea6c93..95878f0 100644
--- a/src/cpu/testers/traffic_gen/base.cc
+++ b/src/cpu/testers/traffic_gen/base.cc
@@ -44,7 +44,14 @@
 
 #include "base/intmath.hh"
 #include "base/random.hh"
+#include "config/have_protobuf.hh"
 #include "cpu/testers/traffic_gen/base_gen.hh"
+#include "cpu/testers/traffic_gen/dram_gen.hh"
+#include "cpu/testers/traffic_gen/dram_rot_gen.hh"
+#include "cpu/testers/traffic_gen/exit_gen.hh"
+#include "cpu/testers/traffic_gen/idle_gen.hh"
+#include "cpu/testers/traffic_gen/linear_gen.hh"
+#include "cpu/testers/traffic_gen/random_gen.hh"
 #include "debug/Checkpoint.hh"
 #include "debug/TrafficGen.hh"
 #include "params/BaseTrafficGen.hh"
@@ -52,6 +59,11 @@
 #include "sim/stats.hh"
 #include "sim/system.hh"
 
+#if HAVE_PROTOBUF
+#include "cpu/testers/traffic_gen/trace_gen.hh"
+#endif
+
+
 using namespace std;
 
 BaseTrafficGen::BaseTrafficGen(const BaseTrafficGenParams* p)
@@ -297,6 +309,105 @@
         .desc("Time spent waiting due to back-pressure (ticks)");
 }
 
+std::shared_ptr<BaseGen>
+BaseTrafficGen::createIdle(Tick duration)
+{
+    return std::shared_ptr<BaseGen>(new IdleGen(*this, duration));
+}
+
+std::shared_ptr<BaseGen>
+BaseTrafficGen::createExit(Tick duration)
+{
+    return std::shared_ptr<BaseGen>(new ExitGen(*this, duration));
+}
+
+std::shared_ptr<BaseGen>
+BaseTrafficGen::createLinear(Tick duration,
+                             Addr start_addr, Addr end_addr, Addr blocksize,
+                             Tick min_period, Tick max_period,
+                             uint8_t read_percent, Addr data_limit)
+{
+    return std::shared_ptr<BaseGen>(new LinearGen(*this,
+                                                  duration, start_addr,
+                                                  end_addr, blocksize,
+                                                  min_period, max_period,
+                                                  read_percent, data_limit));
+}
+
+std::shared_ptr<BaseGen>
+BaseTrafficGen::createRandom(Tick duration,
+                             Addr start_addr, Addr end_addr, Addr blocksize,
+                             Tick min_period, Tick max_period,
+                             uint8_t read_percent, Addr data_limit)
+{
+    return std::shared_ptr<BaseGen>(new RandomGen(*this,
+                                                  duration, start_addr,
+                                                  end_addr, blocksize,
+                                                  min_period, max_period,
+                                                  read_percent, data_limit));
+}
+
+std::shared_ptr<BaseGen>
+BaseTrafficGen::createDram(Tick duration,
+                           Addr start_addr, Addr end_addr, Addr blocksize,
+                           Tick min_period, Tick max_period,
+                           uint8_t read_percent, Addr data_limit,
+                           unsigned int num_seq_pkts, unsigned int page_size,
+                           unsigned int nbr_of_banks_DRAM,
+                           unsigned int nbr_of_banks_util,
+                           unsigned int addr_mapping,
+                           unsigned int nbr_of_ranks)
+{
+    return std::shared_ptr<BaseGen>(new DramGen(*this,
+                                                duration, start_addr,
+                                                end_addr, blocksize,
+                                                min_period, max_period,
+                                                read_percent, data_limit,
+                                                num_seq_pkts, page_size,
+                                                nbr_of_banks_DRAM,
+                                                nbr_of_banks_util,
+                                                addr_mapping,
+                                                nbr_of_ranks));
+}
+
+std::shared_ptr<BaseGen>
+BaseTrafficGen::createDramRot(Tick duration,
+                              Addr start_addr, Addr end_addr, Addr blocksize,
+                              Tick min_period, Tick max_period,
+                              uint8_t read_percent, Addr data_limit,
+                              unsigned int num_seq_pkts,
+                              unsigned int page_size,
+                              unsigned int nbr_of_banks_DRAM,
+                              unsigned int nbr_of_banks_util,
+                              unsigned int addr_mapping,
+                              unsigned int nbr_of_ranks,
+                              unsigned int max_seq_count_per_rank)
+{
+    return std::shared_ptr<BaseGen>(new DramRotGen(*this,
+                                                   duration, start_addr,
+                                                   end_addr, blocksize,
+                                                   min_period, max_period,
+                                                   read_percent, data_limit,
+                                                   num_seq_pkts, page_size,
+                                                   nbr_of_banks_DRAM,
+                                                   nbr_of_banks_util,
+                                                   addr_mapping,
+                                                   nbr_of_ranks,
+                                                   max_seq_count_per_rank));
+}
+
+std::shared_ptr<BaseGen>
+BaseTrafficGen::createTrace(Tick duration,
+                            const std::string& trace_file, Addr addr_offset)
+{
+#if HAVE_PROTOBUF
+    return std::shared_ptr<BaseGen>(
+        new TraceGen(*this, duration, trace_file, addr_offset));
+#else
+    panic("Can't instantiate trace generation without Protobuf support!\n");
+#endif
+}
+
 bool
 BaseTrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
 {
diff --git a/src/cpu/testers/traffic_gen/base.hh b/src/cpu/testers/traffic_gen/base.hh
index a2cad87..080bd78 100644
--- a/src/cpu/testers/traffic_gen/base.hh
+++ b/src/cpu/testers/traffic_gen/base.hh
@@ -64,6 +64,8 @@
  */
 class BaseTrafficGen : public MemObject
 {
+    friend class BaseGen;
+
   protected: // Params
     /**
      * The system used to determine which mode we are currently operating
@@ -191,6 +193,47 @@
     /** Register statistics */
     void regStats() override;
 
+  public: // Generator factory methods
+    std::shared_ptr<BaseGen> createIdle(Tick duration);
+    std::shared_ptr<BaseGen> createExit(Tick duration);
+
+    std::shared_ptr<BaseGen> createLinear(
+        Tick duration,
+        Addr start_addr, Addr end_addr, Addr blocksize,
+        Tick min_period, Tick max_period,
+        uint8_t read_percent, Addr data_limit);
+
+    std::shared_ptr<BaseGen> createRandom(
+        Tick duration,
+        Addr start_addr, Addr end_addr, Addr blocksize,
+        Tick min_period, Tick max_period,
+        uint8_t read_percent, Addr data_limit);
+
+    std::shared_ptr<BaseGen> createDram(
+        Tick duration,
+        Addr start_addr, Addr end_addr, Addr blocksize,
+        Tick min_period, Tick max_period,
+        uint8_t read_percent, Addr data_limit,
+        unsigned int num_seq_pkts, unsigned int page_size,
+        unsigned int nbr_of_banks_DRAM, unsigned int nbr_of_banks_util,
+        unsigned int addr_mapping,
+        unsigned int nbr_of_ranks);
+
+    std::shared_ptr<BaseGen> createDramRot(
+        Tick duration,
+        Addr start_addr, Addr end_addr, Addr blocksize,
+        Tick min_period, Tick max_period,
+        uint8_t read_percent, Addr data_limit,
+        unsigned int num_seq_pkts, unsigned int page_size,
+        unsigned int nbr_of_banks_DRAM, unsigned int nbr_of_banks_util,
+        unsigned int addr_mapping,
+        unsigned int nbr_of_ranks,
+        unsigned int max_seq_count_per_rank);
+
+    std::shared_ptr<BaseGen> createTrace(
+        Tick duration,
+        const std::string& trace_file, Addr addr_offset);
+
   protected:
     void start();
 
diff --git a/src/cpu/testers/traffic_gen/base_gen.cc b/src/cpu/testers/traffic_gen/base_gen.cc
index 7963574..ccab17a 100644
--- a/src/cpu/testers/traffic_gen/base_gen.cc
+++ b/src/cpu/testers/traffic_gen/base_gen.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013, 2016-2017 ARM Limited
+ * Copyright (c) 2012-2013, 2016-2018 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -44,12 +44,17 @@
 
 #include <algorithm>
 
+#include "base/logging.hh"
 #include "base/random.hh"
 #include "base/trace.hh"
+#include "cpu/testers/traffic_gen/base.hh"
 #include "debug/TrafficGen.hh"
+#include "sim/system.hh"
 
-BaseGen::BaseGen(const std::string& _name, MasterID master_id, Tick _duration)
-    : _name(_name), masterID(master_id), duration(_duration)
+BaseGen::BaseGen(BaseTrafficGen &gen, Tick _duration)
+    : _name(gen.name()), masterID(gen.masterID),
+      cacheLineSize(gen.system->cacheLineSize()),
+      duration(_duration)
 {
 }
 
@@ -75,3 +80,26 @@
 
     return pkt;
 }
+
+StochasticGen::StochasticGen(BaseTrafficGen &gen,
+                             Tick _duration,
+                             Addr start_addr, Addr end_addr, Addr _blocksize,
+                             Tick min_period, Tick max_period,
+                             uint8_t read_percent, Addr data_limit)
+        : BaseGen(gen, _duration),
+          startAddr(start_addr), endAddr(end_addr),
+          blocksize(_blocksize), minPeriod(min_period),
+          maxPeriod(max_period), readPercent(read_percent),
+          dataLimit(data_limit)
+{
+    if (blocksize > cacheLineSize)
+        fatal("TrafficGen %s block size (%d) is larger than "
+              "cache line size (%d)\n", name(),
+              blocksize, cacheLineSize);
+
+    if (read_percent > 100)
+        fatal("%s cannot have more than 100% reads", name());
+
+    if (min_period > max_period)
+        fatal("%s cannot have min_period > max_period", name());
+}
diff --git a/src/cpu/testers/traffic_gen/base_gen.hh b/src/cpu/testers/traffic_gen/base_gen.hh
index 5f1c2af..b7c3363 100644
--- a/src/cpu/testers/traffic_gen/base_gen.hh
+++ b/src/cpu/testers/traffic_gen/base_gen.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013, 2017 ARM Limited
+ * Copyright (c) 2012-2013, 2017-2018 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -52,6 +52,8 @@
 #include "base/intmath.hh"
 #include "mem/packet.hh"
 
+class BaseTrafficGen;
+
 /**
  * Base class for all generators, with the shared functionality and
  * virtual functions for entering, executing and leaving the
@@ -68,6 +70,9 @@
     /** The MasterID used for generating requests */
     const MasterID masterID;
 
+    /** Cache line size in the simulated system */
+    const Addr cacheLineSize;
+
     /**
      * Generate a new request and associated packet
      *
@@ -91,7 +96,7 @@
      * @param master_id MasterID set on each request
      * @param _duration duration of this state before transitioning
      */
-    BaseGen(const std::string& _name, MasterID master_id, Tick _duration);
+    BaseGen(BaseTrafficGen &gen, Tick _duration);
 
     virtual ~BaseGen() { }
 
@@ -132,4 +137,35 @@
 
 };
 
+class StochasticGen : public BaseGen
+{
+  public:
+    StochasticGen(BaseTrafficGen &gen, Tick _duration,
+                  Addr start_addr, Addr end_addr, Addr _blocksize,
+                  Tick min_period, Tick max_period,
+                  uint8_t read_percent, Addr data_limit);
+
+  protected:
+    /** Start of address range */
+    const Addr startAddr;
+
+    /** End of address range */
+    const Addr endAddr;
+
+    /** Blocksize and address increment */
+    const Addr blocksize;
+
+    /** Request generation period */
+    const Tick minPeriod;
+    const Tick maxPeriod;
+
+    /**
+     * Percent of generated transactions that should be reads
+     */
+    const uint8_t readPercent;
+
+    /** Maximum amount of data to manipulate */
+    const Addr dataLimit;
+};
+
 #endif
diff --git a/src/cpu/testers/traffic_gen/dram_gen.cc b/src/cpu/testers/traffic_gen/dram_gen.cc
index 8bbf9b8..fb82126 100644
--- a/src/cpu/testers/traffic_gen/dram_gen.cc
+++ b/src/cpu/testers/traffic_gen/dram_gen.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013, 2016-2017 ARM Limited
+ * Copyright (c) 2012-2013, 2016-2018 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -48,6 +48,39 @@
 #include "base/trace.hh"
 #include "debug/TrafficGen.hh"
 
+
+DramGen::DramGen(BaseTrafficGen &gen, Tick _duration,
+                 Addr start_addr, Addr end_addr, Addr _blocksize,
+                 Tick min_period, Tick max_period,
+                 uint8_t read_percent, Addr data_limit,
+                 unsigned int num_seq_pkts, unsigned int page_size,
+                 unsigned int nbr_of_banks_DRAM,
+                 unsigned int nbr_of_banks_util,
+                 unsigned int addr_mapping,
+                 unsigned int nbr_of_ranks)
+        : RandomGen(gen, _duration, start_addr, end_addr,
+          _blocksize, min_period, max_period, read_percent, data_limit),
+          numSeqPkts(num_seq_pkts), countNumSeqPkts(0), addr(0),
+          isRead(true), pageSize(page_size),
+          pageBits(floorLog2(page_size / _blocksize)),
+          bankBits(floorLog2(nbr_of_banks_DRAM)),
+          blockBits(floorLog2(_blocksize)),
+          nbrOfBanksDRAM(nbr_of_banks_DRAM),
+          nbrOfBanksUtil(nbr_of_banks_util), addrMapping(addr_mapping),
+          rankBits(floorLog2(nbr_of_ranks)),
+          nbrOfRanks(nbr_of_ranks)
+{
+    if (addrMapping != 1 && addrMapping != 0) {
+        addrMapping = 1;
+        warn("Unknown address mapping specified, using RoRaBaCoCh\n");
+    }
+
+    if (nbr_of_banks_util > nbr_of_banks_DRAM)
+        fatal("Attempting to use more banks (%d) than "
+              "what is available (%d)\n",
+              nbr_of_banks_util, nbr_of_banks_DRAM);
+}
+
 PacketPtr
 DramGen::getNextPacket()
 {
diff --git a/src/cpu/testers/traffic_gen/dram_gen.hh b/src/cpu/testers/traffic_gen/dram_gen.hh
index b431408..6809c3b 100644
--- a/src/cpu/testers/traffic_gen/dram_gen.hh
+++ b/src/cpu/testers/traffic_gen/dram_gen.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013, 2017 ARM Limited
+ * Copyright (c) 2012-2013, 2017-2018 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -67,8 +67,7 @@
     /**
      * Create a DRAM address sequence generator.
      *
-     * @param _name Name to use for status and debug
-     * @param master_id MasterID set on each request
+     * @param gen Traffic generator owning this sequence generator
      * @param _duration duration of this state before transitioning
      * @param start_addr Start address
      * @param end_addr End address
@@ -86,31 +85,14 @@
      *                     0: RoCoRaBaCh, 1: RoRaBaCoCh/RoRaBaChCo
      *                     assumes single channel system
      */
-    DramGen(const std::string& _name, MasterID master_id, Tick _duration,
+    DramGen(BaseTrafficGen &gen, Tick _duration,
             Addr start_addr, Addr end_addr, Addr _blocksize,
             Tick min_period, Tick max_period,
             uint8_t read_percent, Addr data_limit,
             unsigned int num_seq_pkts, unsigned int page_size,
             unsigned int nbr_of_banks_DRAM, unsigned int nbr_of_banks_util,
             unsigned int addr_mapping,
-            unsigned int nbr_of_ranks)
-        : RandomGen(_name, master_id, _duration, start_addr, end_addr,
-          _blocksize, min_period, max_period, read_percent, data_limit),
-          numSeqPkts(num_seq_pkts), countNumSeqPkts(0), addr(0),
-          isRead(true), pageSize(page_size),
-          pageBits(floorLog2(page_size / _blocksize)),
-          bankBits(floorLog2(nbr_of_banks_DRAM)),
-          blockBits(floorLog2(_blocksize)),
-          nbrOfBanksDRAM(nbr_of_banks_DRAM),
-          nbrOfBanksUtil(nbr_of_banks_util), addrMapping(addr_mapping),
-          rankBits(floorLog2(nbr_of_ranks)),
-          nbrOfRanks(nbr_of_ranks)
-    {
-        if (addrMapping != 1 && addrMapping != 0) {
-            addrMapping = 1;
-            warn("Unknown address mapping specified, using RoRaBaCoCh\n");
-        }
-    }
+            unsigned int nbr_of_ranks);
 
     PacketPtr getNextPacket();
 
diff --git a/src/cpu/testers/traffic_gen/dram_rot_gen.hh b/src/cpu/testers/traffic_gen/dram_rot_gen.hh
index 2b5d960..9c9a6ce 100644
--- a/src/cpu/testers/traffic_gen/dram_rot_gen.hh
+++ b/src/cpu/testers/traffic_gen/dram_rot_gen.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013, 2017 ARM Limited
+ * Copyright (c) 2012-2013, 2017-2018 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -66,8 +66,7 @@
      * 2) Command type (if applicable)
      * 3) Ranks per channel
      *
-     * @param _name Name to use for status and debug
-     * @param master_id MasterID set on each request
+     * @param gen Traffic generator owning this sequence generator
      * @param _duration duration of this state before transitioning
      * @param start_addr Start address
      * @param end_addr End address
@@ -86,7 +85,7 @@
      *                     0: RoCoRaBaCh, 1: RoRaBaCoCh/RoRaBaChCo
      *                     assumes single channel system
      */
-    DramRotGen(const std::string& _name, MasterID master_id, Tick _duration,
+    DramRotGen(BaseTrafficGen &gen, Tick _duration,
             Addr start_addr, Addr end_addr, Addr _blocksize,
             Tick min_period, Tick max_period,
             uint8_t read_percent, Addr data_limit,
@@ -95,7 +94,7 @@
             unsigned int addr_mapping,
             unsigned int nbr_of_ranks,
             unsigned int max_seq_count_per_rank)
-        : DramGen(_name, master_id, _duration, start_addr, end_addr,
+        : DramGen(gen, _duration, start_addr, end_addr,
           _blocksize, min_period, max_period, read_percent, data_limit,
           num_seq_pkts, page_size, nbr_of_banks_DRAM,
           nbr_of_banks_util, addr_mapping,
diff --git a/src/cpu/testers/traffic_gen/exit_gen.hh b/src/cpu/testers/traffic_gen/exit_gen.hh
index 45087e6..bf46653 100644
--- a/src/cpu/testers/traffic_gen/exit_gen.hh
+++ b/src/cpu/testers/traffic_gen/exit_gen.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 ARM Limited
+ * Copyright (c) 2017-2018 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -56,8 +56,8 @@
 
   public:
 
-    ExitGen(const std::string& _name, MasterID master_id, Tick _duration)
-        : BaseGen(_name, master_id, _duration)
+    ExitGen(BaseTrafficGen &gen, Tick _duration)
+        : BaseGen(gen, _duration)
     { }
 
     void enter();
diff --git a/src/cpu/testers/traffic_gen/idle_gen.hh b/src/cpu/testers/traffic_gen/idle_gen.hh
index 0e43940..44a3bc0 100644
--- a/src/cpu/testers/traffic_gen/idle_gen.hh
+++ b/src/cpu/testers/traffic_gen/idle_gen.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013, 2017 ARM Limited
+ * Copyright (c) 2012-2013, 2017-2018 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -61,8 +61,8 @@
 
   public:
 
-    IdleGen(const std::string& _name, MasterID master_id, Tick _duration)
-        : BaseGen(_name, master_id, _duration)
+    IdleGen(BaseTrafficGen &gen, Tick _duration)
+        : BaseGen(gen, _duration)
     { }
 
     void enter();
diff --git a/src/cpu/testers/traffic_gen/linear_gen.hh b/src/cpu/testers/traffic_gen/linear_gen.hh
index 8af9e83..c77830e 100644
--- a/src/cpu/testers/traffic_gen/linear_gen.hh
+++ b/src/cpu/testers/traffic_gen/linear_gen.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013, 2017 ARM Limited
+ * Copyright (c) 2012-2013, 2017-2018 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -61,7 +61,7 @@
  * read percent. There is an optional data limit for when to
  * stop generating new requests.
  */
-class LinearGen : public BaseGen
+class LinearGen : public StochasticGen
 {
 
   public:
@@ -71,8 +71,7 @@
      * min_period == max_period for a fixed inter-transaction
      * time.
      *
-     * @param _name Name to use for status and debug
-     * @param master_id MasterID set on each request
+     * @param gen Traffic generator owning this sequence generator
      * @param _duration duration of this state before transitioning
      * @param start_addr Start address
      * @param end_addr End address
@@ -82,15 +81,15 @@
      * @param read_percent Percent of transactions that are reads
      * @param data_limit Upper limit on how much data to read/write
      */
-    LinearGen(const std::string& _name, MasterID master_id, Tick _duration,
+    LinearGen(BaseTrafficGen &gen, Tick _duration,
               Addr start_addr, Addr end_addr, Addr _blocksize,
               Tick min_period, Tick max_period,
               uint8_t read_percent, Addr data_limit)
-        : BaseGen(_name, master_id, _duration),
-          startAddr(start_addr), endAddr(end_addr),
-          blocksize(_blocksize), minPeriod(min_period),
-          maxPeriod(max_period), readPercent(read_percent),
-          dataLimit(data_limit), nextAddr(startAddr), dataManipulated(0)
+        : StochasticGen(gen, _duration, start_addr, end_addr,
+                        _blocksize, min_period, max_period, read_percent,
+                        data_limit),
+          nextAddr(0),
+          dataManipulated(0)
     { }
 
     void enter();
@@ -100,28 +99,6 @@
     Tick nextPacketTick(bool elastic, Tick delay) const;
 
   private:
-
-    /** Start of address range */
-    const Addr startAddr;
-
-    /** End of address range */
-    const Addr endAddr;
-
-    /** Blocksize and address increment */
-    const Addr blocksize;
-
-    /** Request generation period */
-    const Tick minPeriod;
-    const Tick maxPeriod;
-
-    /**
-     * Percent of generated transactions that should be reads
-     */
-    const uint8_t readPercent;
-
-    /** Maximum amount of data to manipulate */
-    const Addr dataLimit;
-
     /** Address of next request */
     Addr nextAddr;
 
diff --git a/src/cpu/testers/traffic_gen/random_gen.hh b/src/cpu/testers/traffic_gen/random_gen.hh
index ec60b35..590094d 100644
--- a/src/cpu/testers/traffic_gen/random_gen.hh
+++ b/src/cpu/testers/traffic_gen/random_gen.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013, 2017 ARM Limited
+ * Copyright (c) 2012-2013, 2017-2018 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -59,7 +59,7 @@
  * not generate sequential addresses. Instead it randomly
  * picks an address in the range, aligned to the block size.
  */
-class RandomGen : public BaseGen
+class RandomGen : public StochasticGen
 {
 
   public:
@@ -69,8 +69,7 @@
      * min_period == max_period for a fixed inter-transaction
      * time.
      *
-     * @param _name Name to use for status and debug
-     * @param master_id MasterID set on each request
+     * @param gen Traffic generator owning this sequence generator
      * @param _duration duration of this state before transitioning
      * @param start_addr Start address
      * @param end_addr End address
@@ -80,15 +79,13 @@
      * @param read_percent Percent of transactions that are reads
      * @param data_limit Upper limit on how much data to read/write
      */
-    RandomGen(const std::string& _name, MasterID master_id, Tick _duration,
+    RandomGen(BaseTrafficGen &gen, Tick _duration,
               Addr start_addr, Addr end_addr, Addr _blocksize,
               Tick min_period, Tick max_period,
               uint8_t read_percent, Addr data_limit)
-        : BaseGen(_name, master_id, _duration),
-          startAddr(start_addr), endAddr(end_addr),
-          blocksize(_blocksize), minPeriod(min_period),
-          maxPeriod(max_period), readPercent(read_percent),
-          dataLimit(data_limit), dataManipulated(0)
+        : StochasticGen(gen, _duration, start_addr, end_addr, _blocksize,
+                        min_period, max_period, read_percent, data_limit),
+          dataManipulated(0)
     { }
 
     void enter();
@@ -98,28 +95,6 @@
     Tick nextPacketTick(bool elastic, Tick delay) const;
 
   protected:
-
-    /** Start of address range */
-    const Addr startAddr;
-
-    /** End of address range */
-    const Addr endAddr;
-
-    /** Block size */
-    const Addr blocksize;
-
-    /** Request generation period */
-    const Tick minPeriod;
-    const Tick maxPeriod;
-
-    /**
-     * Percent of generated transactions that should be reads
-     */
-    const uint8_t readPercent;
-
-    /** Maximum amount of data to manipulate */
-    const Addr dataLimit;
-
     /**
      * Counter to determine the amount of data
      * manipulated. Used to determine if we should continue
diff --git a/src/cpu/testers/traffic_gen/trace_gen.hh b/src/cpu/testers/traffic_gen/trace_gen.hh
index cf4d4dd..05d366e 100644
--- a/src/cpu/testers/traffic_gen/trace_gen.hh
+++ b/src/cpu/testers/traffic_gen/trace_gen.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013, 2017 ARM Limited
+ * Copyright (c) 2012-2013, 2017-2018 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -152,15 +152,14 @@
     /**
      * Create a trace generator.
      *
-     * @param _name Name to use for status and debug
-     * @param master_id MasterID set on each request
+     * @param gen Traffic generator owning this sequence generator
      * @param _duration duration of this state before transitioning
      * @param trace_file File to read the transactions from
      * @param addr_offset Positive offset to add to trace address
      */
-    TraceGen(const std::string& _name, MasterID master_id, Tick _duration,
+    TraceGen(BaseTrafficGen &gen, Tick _duration,
              const std::string& trace_file, Addr addr_offset)
-        : BaseGen(_name, master_id, _duration),
+        : BaseGen(gen, _duration),
           trace(trace_file),
           tickOffset(0),
           addrOffset(addr_offset),
diff --git a/src/cpu/testers/traffic_gen/traffic_gen.cc b/src/cpu/testers/traffic_gen/traffic_gen.cc
index b3f73e2..db1569b 100644
--- a/src/cpu/testers/traffic_gen/traffic_gen.cc
+++ b/src/cpu/testers/traffic_gen/traffic_gen.cc
@@ -43,17 +43,11 @@
 #include <libgen.h>
 #include <unistd.h>
 
+#include <fstream>
 #include <sstream>
 
 #include "base/intmath.hh"
 #include "base/random.hh"
-#include "cpu/testers/traffic_gen/dram_gen.hh"
-#include "cpu/testers/traffic_gen/dram_rot_gen.hh"
-#include "cpu/testers/traffic_gen/exit_gen.hh"
-#include "cpu/testers/traffic_gen/idle_gen.hh"
-#include "cpu/testers/traffic_gen/linear_gen.hh"
-#include "cpu/testers/traffic_gen/random_gen.hh"
-#include "cpu/testers/traffic_gen/trace_gen.hh"
 #include "debug/TrafficGen.hh"
 #include "params/TrafficGen.hh"
 #include "sim/stats.hh"
@@ -183,14 +177,13 @@
                     is >> traceFile >> addrOffset;
                     traceFile = resolveFile(traceFile);
 
-                    states[id].reset(new TraceGen(name(), masterID, duration,
-                                                  traceFile, addrOffset));
+                    states[id] = createTrace(duration, traceFile, addrOffset);
                     DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
                 } else if (mode == "IDLE") {
-                    states[id].reset(new IdleGen(name(), masterID, duration));
+                    states[id] = createIdle(duration);
                     DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
                 } else if (mode == "EXIT") {
-                    states[id].reset(new ExitGen(name(), masterID, duration));
+                    states[id] = createExit(duration);
                     DPRINTF(TrafficGen, "State: %d ExitGen\n", id);
                 } else if (mode == "LINEAR" || mode == "RANDOM" ||
                            mode == "DRAM"   || mode == "DRAM_ROTATE") {
@@ -211,30 +204,17 @@
                             max_period, read_percent);
 
 
-                    if (blocksize > system->cacheLineSize())
-                        fatal("TrafficGen %s block size (%d) is larger than "
-                              "cache line size (%d)\n", name(),
-                              blocksize, system->cacheLineSize());
-
-                    if (read_percent > 100)
-                        fatal("%s cannot have more than 100% reads", name());
-
-                    if (min_period > max_period)
-                        fatal("%s cannot have min_period > max_period", name());
-
                     if (mode == "LINEAR") {
-                        states[id].reset(new LinearGen(name(), masterID,
-                                                   duration, start_addr,
-                                                   end_addr, blocksize,
-                                                   min_period, max_period,
-                                                   read_percent, data_limit));
+                        states[id] = createLinear(duration, start_addr,
+                                                  end_addr, blocksize,
+                                                  min_period, max_period,
+                                                  read_percent, data_limit);
                         DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
                     } else if (mode == "RANDOM") {
-                        states[id].reset(new RandomGen(name(), masterID,
-                                                   duration, start_addr,
-                                                   end_addr, blocksize,
-                                                   min_period, max_period,
-                                                   read_percent, data_limit));
+                        states[id] = createRandom(duration, start_addr,
+                                                  end_addr, blocksize,
+                                                  min_period, max_period,
+                                                  read_percent, data_limit);
                         DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
                     } else if (mode == "DRAM" || mode == "DRAM_ROTATE") {
                         // stride size (bytes) of the request for achieving
@@ -255,11 +235,6 @@
                                  "than page size (%d)  of the memory\n",
                                  blocksize, page_size);
 
-                        if (nbr_of_banks_util > nbr_of_banks_DRAM)
-                            fatal("Attempting to use more banks (%d) than "
-                                  "what is available (%d)\n",
-                                  nbr_of_banks_util, nbr_of_banks_DRAM);
-
                         // count the number of sequential packets to
                         // generate
                         unsigned int num_seq_pkts = 1;
@@ -272,16 +247,15 @@
                         }
 
                         if (mode == "DRAM") {
-                            states[id].reset(new DramGen(name(), masterID,
-                                                     duration, start_addr,
-                                                     end_addr, blocksize,
-                                                     min_period, max_period,
-                                                     read_percent, data_limit,
-                                                     num_seq_pkts, page_size,
-                                                     nbr_of_banks_DRAM,
-                                                     nbr_of_banks_util,
-                                                     addr_mapping,
-                                                     nbr_of_ranks));
+                            states[id] = createDram(duration, start_addr,
+                                                    end_addr, blocksize,
+                                                    min_period, max_period,
+                                                    read_percent, data_limit,
+                                                    num_seq_pkts, page_size,
+                                                    nbr_of_banks_DRAM,
+                                                    nbr_of_banks_util,
+                                                    addr_mapping,
+                                                    nbr_of_ranks);
                             DPRINTF(TrafficGen, "State: %d DramGen\n", id);
                         } else {
                             // Will rotate to the next rank after rotating
@@ -292,17 +266,17 @@
                                 (read_percent == 50) ? nbr_of_banks_util * 2
                                                      : nbr_of_banks_util;
 
-                            states[id].reset(new DramRotGen(name(), masterID,
-                                                     duration, start_addr,
-                                                     end_addr, blocksize,
-                                                     min_period, max_period,
-                                                     read_percent, data_limit,
-                                                     num_seq_pkts, page_size,
-                                                     nbr_of_banks_DRAM,
-                                                     nbr_of_banks_util,
-                                                     addr_mapping,
-                                                     nbr_of_ranks,
-                                                     max_seq_count_per_rank));
+                            states[id] = createDramRot(duration, start_addr,
+                                                       end_addr, blocksize,
+                                                       min_period, max_period,
+                                                       read_percent,
+                                                       data_limit,
+                                                       num_seq_pkts, page_size,
+                                                       nbr_of_banks_DRAM,
+                                                       nbr_of_banks_util,
+                                                       addr_mapping,
+                                                       nbr_of_ranks,
+                                                       max_seq_count_per_rank);
                             DPRINTF(TrafficGen, "State: %d DramRotGen\n", id);
                         }
                     }