traffic_gen.cc revision 9241
19241Sandreas.hansson@arm.com/*
29241Sandreas.hansson@arm.com * Copyright (c) 2012 ARM Limited
39241Sandreas.hansson@arm.com * All rights reserved
49241Sandreas.hansson@arm.com *
59241Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall
69241Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual
79241Sandreas.hansson@arm.com * property including but not limited to intellectual property relating
89241Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software
99241Sandreas.hansson@arm.com * licensed hereunder.  You may use the software subject to the license
109241Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated
119241Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software,
129241Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form.
139241Sandreas.hansson@arm.com *
149241Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
159241Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are
169241Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright
179241Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer;
189241Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright
199241Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the
209241Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution;
219241Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its
229241Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from
239241Sandreas.hansson@arm.com * this software without specific prior written permission.
249241Sandreas.hansson@arm.com *
259241Sandreas.hansson@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
269241Sandreas.hansson@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
279241Sandreas.hansson@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
289241Sandreas.hansson@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
299241Sandreas.hansson@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
309241Sandreas.hansson@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
319241Sandreas.hansson@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
329241Sandreas.hansson@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
339241Sandreas.hansson@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
349241Sandreas.hansson@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
359241Sandreas.hansson@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
369241Sandreas.hansson@arm.com *
379241Sandreas.hansson@arm.com * Authors: Thomas Grass
389241Sandreas.hansson@arm.com *          Andreas Hansson
399241Sandreas.hansson@arm.com *          Sascha Bischoff
409241Sandreas.hansson@arm.com */
419241Sandreas.hansson@arm.com
429241Sandreas.hansson@arm.com#include <sstream>
439241Sandreas.hansson@arm.com
449241Sandreas.hansson@arm.com#include "base/random.hh"
459241Sandreas.hansson@arm.com#include "cpu/testers/traffic_gen/traffic_gen.hh"
469241Sandreas.hansson@arm.com#include "debug/Checkpoint.hh"
479241Sandreas.hansson@arm.com#include "debug/TrafficGen.hh"
489241Sandreas.hansson@arm.com#include "sim/stats.hh"
499241Sandreas.hansson@arm.com#include "sim/system.hh"
509241Sandreas.hansson@arm.com
519241Sandreas.hansson@arm.comusing namespace std;
529241Sandreas.hansson@arm.com
539241Sandreas.hansson@arm.comTrafficGen::TrafficGen(const TrafficGenParams* p)
549241Sandreas.hansson@arm.com    : MemObject(p),
559241Sandreas.hansson@arm.com      system(p->system),
569241Sandreas.hansson@arm.com      masterID(system->getMasterId(name())),
579241Sandreas.hansson@arm.com      port(name() + ".port", *this),
589241Sandreas.hansson@arm.com      stateGraph(*this, port, p->config_file, masterID),
599241Sandreas.hansson@arm.com      updateStateGraphEvent(this)
609241Sandreas.hansson@arm.com{
619241Sandreas.hansson@arm.com}
629241Sandreas.hansson@arm.com
639241Sandreas.hansson@arm.comTrafficGen*
649241Sandreas.hansson@arm.comTrafficGenParams::create()
659241Sandreas.hansson@arm.com{
669241Sandreas.hansson@arm.com    return new TrafficGen(this);
679241Sandreas.hansson@arm.com}
689241Sandreas.hansson@arm.com
699241Sandreas.hansson@arm.comMasterPort&
709241Sandreas.hansson@arm.comTrafficGen::getMasterPort(const string& if_name, int idx)
719241Sandreas.hansson@arm.com{
729241Sandreas.hansson@arm.com    if (if_name == "port") {
739241Sandreas.hansson@arm.com        return port;
749241Sandreas.hansson@arm.com    } else {
759241Sandreas.hansson@arm.com        return MemObject::getMasterPort(if_name, idx);
769241Sandreas.hansson@arm.com    }
779241Sandreas.hansson@arm.com}
789241Sandreas.hansson@arm.com
799241Sandreas.hansson@arm.comvoid
809241Sandreas.hansson@arm.comTrafficGen::init()
819241Sandreas.hansson@arm.com{
829241Sandreas.hansson@arm.com    if (!port.isConnected())
839241Sandreas.hansson@arm.com        fatal("The port of %s is not connected!\n", name());
849241Sandreas.hansson@arm.com
859241Sandreas.hansson@arm.com    Enums::MemoryMode mode = system->getMemoryMode();
869241Sandreas.hansson@arm.com
879241Sandreas.hansson@arm.com    // if the system is in timing mode active the request generator
889241Sandreas.hansson@arm.com    if (mode == Enums::timing) {
899241Sandreas.hansson@arm.com        DPRINTF(TrafficGen, "Timing mode, activating request generator\n");
909241Sandreas.hansson@arm.com
919241Sandreas.hansson@arm.com        // enter initial state
929241Sandreas.hansson@arm.com        stateGraph.enterState(stateGraph.currState);
939241Sandreas.hansson@arm.com    } else {
949241Sandreas.hansson@arm.com        DPRINTF(TrafficGen,
959241Sandreas.hansson@arm.com                "Traffic generator is only active in timing mode\n");
969241Sandreas.hansson@arm.com    }
979241Sandreas.hansson@arm.com}
989241Sandreas.hansson@arm.com
999241Sandreas.hansson@arm.comvoid
1009241Sandreas.hansson@arm.comTrafficGen::initState()
1019241Sandreas.hansson@arm.com{
1029241Sandreas.hansson@arm.com    // when not restoring from a checkpoint, make sure we kick things off
1039241Sandreas.hansson@arm.com    if (system->getMemoryMode() == Enums::timing) {
1049241Sandreas.hansson@arm.com        Tick nextStateGraphEvent = stateGraph.nextEventTick();
1059241Sandreas.hansson@arm.com        schedule(updateStateGraphEvent, nextStateGraphEvent);
1069241Sandreas.hansson@arm.com    } else {
1079241Sandreas.hansson@arm.com        DPRINTF(TrafficGen,
1089241Sandreas.hansson@arm.com                "Traffic generator is only active in timing mode\n");
1099241Sandreas.hansson@arm.com    }
1109241Sandreas.hansson@arm.com}
1119241Sandreas.hansson@arm.com
1129241Sandreas.hansson@arm.comunsigned int
1139241Sandreas.hansson@arm.comTrafficGen::drain(Event* drain_event)
1149241Sandreas.hansson@arm.com{
1159241Sandreas.hansson@arm.com    // @todo we should also stop putting new requests in the queue and
1169241Sandreas.hansson@arm.com    // either interrupt the current state or wait for a transition
1179241Sandreas.hansson@arm.com    return port.drain(drain_event);
1189241Sandreas.hansson@arm.com}
1199241Sandreas.hansson@arm.com
1209241Sandreas.hansson@arm.comvoid
1219241Sandreas.hansson@arm.comTrafficGen::serialize(ostream &os)
1229241Sandreas.hansson@arm.com{
1239241Sandreas.hansson@arm.com    DPRINTF(Checkpoint, "Serializing TrafficGen\n");
1249241Sandreas.hansson@arm.com
1259241Sandreas.hansson@arm.com    // save ticks of the graph event if it is scheduled
1269241Sandreas.hansson@arm.com    Tick nextStateGraphEvent = updateStateGraphEvent.scheduled() ?
1279241Sandreas.hansson@arm.com        updateStateGraphEvent.when() : 0;
1289241Sandreas.hansson@arm.com
1299241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "Saving nextStateGraphEvent=%llu\n",
1309241Sandreas.hansson@arm.com            nextStateGraphEvent);
1319241Sandreas.hansson@arm.com
1329241Sandreas.hansson@arm.com    SERIALIZE_SCALAR(nextStateGraphEvent);
1339241Sandreas.hansson@arm.com
1349241Sandreas.hansson@arm.com    Tick nextTransitionTick = stateGraph.nextTransitionTick;
1359241Sandreas.hansson@arm.com    SERIALIZE_SCALAR(nextTransitionTick);
1369241Sandreas.hansson@arm.com
1379241Sandreas.hansson@arm.com    // @todo: also serialise the current state, figure out the best
1389241Sandreas.hansson@arm.com    // way to drain and restore
1399241Sandreas.hansson@arm.com}
1409241Sandreas.hansson@arm.com
1419241Sandreas.hansson@arm.comvoid
1429241Sandreas.hansson@arm.comTrafficGen::unserialize(Checkpoint* cp, const string& section)
1439241Sandreas.hansson@arm.com{
1449241Sandreas.hansson@arm.com    // restore scheduled events
1459241Sandreas.hansson@arm.com    Tick nextStateGraphEvent;
1469241Sandreas.hansson@arm.com    UNSERIALIZE_SCALAR(nextStateGraphEvent);
1479241Sandreas.hansson@arm.com    if (nextStateGraphEvent != 0) {
1489241Sandreas.hansson@arm.com        schedule(updateStateGraphEvent, nextStateGraphEvent);
1499241Sandreas.hansson@arm.com    }
1509241Sandreas.hansson@arm.com
1519241Sandreas.hansson@arm.com    Tick nextTransitionTick;
1529241Sandreas.hansson@arm.com    UNSERIALIZE_SCALAR(nextTransitionTick);
1539241Sandreas.hansson@arm.com    stateGraph.nextTransitionTick = nextTransitionTick;
1549241Sandreas.hansson@arm.com}
1559241Sandreas.hansson@arm.com
1569241Sandreas.hansson@arm.comvoid
1579241Sandreas.hansson@arm.comTrafficGen::updateStateGraph()
1589241Sandreas.hansson@arm.com{
1599241Sandreas.hansson@arm.com    // schedule next update event based on either the next execute
1609241Sandreas.hansson@arm.com    // tick or the next transition, which ever comes first
1619241Sandreas.hansson@arm.com    Tick nextStateGraphEvent = stateGraph.nextEventTick();
1629241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "Updating state graph, next event at %lld\n",
1639241Sandreas.hansson@arm.com            nextStateGraphEvent);
1649241Sandreas.hansson@arm.com    schedule(updateStateGraphEvent, nextStateGraphEvent);
1659241Sandreas.hansson@arm.com
1669241Sandreas.hansson@arm.com    // perform the update associated with the current update event
1679241Sandreas.hansson@arm.com    stateGraph.update();
1689241Sandreas.hansson@arm.com}
1699241Sandreas.hansson@arm.com
1709241Sandreas.hansson@arm.comvoid
1719241Sandreas.hansson@arm.comTrafficGen::StateGraph::parseConfig(const string& file_name,
1729241Sandreas.hansson@arm.com                                    MasterID master_id)
1739241Sandreas.hansson@arm.com{
1749241Sandreas.hansson@arm.com    // keep track of the transitions parsed to create the matrix when
1759241Sandreas.hansson@arm.com    // done
1769241Sandreas.hansson@arm.com    vector<Transition> transitions;
1779241Sandreas.hansson@arm.com
1789241Sandreas.hansson@arm.com    // open input file
1799241Sandreas.hansson@arm.com    ifstream infile;
1809241Sandreas.hansson@arm.com    infile.open(file_name.c_str(), ifstream::in);
1819241Sandreas.hansson@arm.com    if (!infile.is_open()) {
1829241Sandreas.hansson@arm.com        fatal("Traffic generator %s config file not found at %s\n",
1839241Sandreas.hansson@arm.com              owner.name(), file_name);
1849241Sandreas.hansson@arm.com    }
1859241Sandreas.hansson@arm.com
1869241Sandreas.hansson@arm.com    // read line by line and determine the action based on the first
1879241Sandreas.hansson@arm.com    // keyword
1889241Sandreas.hansson@arm.com    string keyword;
1899241Sandreas.hansson@arm.com    string line;
1909241Sandreas.hansson@arm.com
1919241Sandreas.hansson@arm.com    while (getline(infile, line).good()) {
1929241Sandreas.hansson@arm.com        // see if this line is a comment line, and if so skip it
1939241Sandreas.hansson@arm.com        if (line.find('#') != 1) {
1949241Sandreas.hansson@arm.com            // create an input stream for the tokenization
1959241Sandreas.hansson@arm.com            istringstream is(line);
1969241Sandreas.hansson@arm.com
1979241Sandreas.hansson@arm.com            // determine the keyword
1989241Sandreas.hansson@arm.com            is >> keyword;
1999241Sandreas.hansson@arm.com
2009241Sandreas.hansson@arm.com            if (keyword == "STATE") {
2019241Sandreas.hansson@arm.com                // parse the behaviour of this state
2029241Sandreas.hansson@arm.com                uint32_t id;
2039241Sandreas.hansson@arm.com                Tick duration;
2049241Sandreas.hansson@arm.com                string mode;
2059241Sandreas.hansson@arm.com
2069241Sandreas.hansson@arm.com                is >> id >> duration >> mode;
2079241Sandreas.hansson@arm.com
2089241Sandreas.hansson@arm.com                if (mode == "TRACE") {
2099241Sandreas.hansson@arm.com                    string traceFile;
2109241Sandreas.hansson@arm.com                    Addr addrOffset;
2119241Sandreas.hansson@arm.com
2129241Sandreas.hansson@arm.com                    is >> traceFile >> addrOffset;
2139241Sandreas.hansson@arm.com
2149241Sandreas.hansson@arm.com                    states[id] = new TraceGen(port, master_id, duration,
2159241Sandreas.hansson@arm.com                                              traceFile, addrOffset);
2169241Sandreas.hansson@arm.com                    DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
2179241Sandreas.hansson@arm.com                } else if (mode == "IDLE") {
2189241Sandreas.hansson@arm.com                    states[id] = new IdleGen(port, master_id, duration);
2199241Sandreas.hansson@arm.com                    DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
2209241Sandreas.hansson@arm.com                } else if (mode == "LINEAR" || mode == "RANDOM") {
2219241Sandreas.hansson@arm.com                    uint32_t read_percent;
2229241Sandreas.hansson@arm.com                    Addr start_addr;
2239241Sandreas.hansson@arm.com                    Addr end_addr;
2249241Sandreas.hansson@arm.com                    Addr blocksize;
2259241Sandreas.hansson@arm.com                    Tick min_period;
2269241Sandreas.hansson@arm.com                    Tick max_period;
2279241Sandreas.hansson@arm.com                    Addr data_limit;
2289241Sandreas.hansson@arm.com
2299241Sandreas.hansson@arm.com                    is >> read_percent >> start_addr >> end_addr >>
2309241Sandreas.hansson@arm.com                        blocksize >> min_period >> max_period >> data_limit;
2319241Sandreas.hansson@arm.com
2329241Sandreas.hansson@arm.com                    DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
2339241Sandreas.hansson@arm.com                            " period %d to %d, %d%% reads\n",
2349241Sandreas.hansson@arm.com                            mode, start_addr, end_addr, blocksize, min_period,
2359241Sandreas.hansson@arm.com                            max_period, read_percent);
2369241Sandreas.hansson@arm.com
2379241Sandreas.hansson@arm.com                    if (read_percent > 100)
2389241Sandreas.hansson@arm.com                        panic("%s cannot have more than 100% reads", name());
2399241Sandreas.hansson@arm.com
2409241Sandreas.hansson@arm.com                    if (mode == "LINEAR") {
2419241Sandreas.hansson@arm.com                        states[id] = new LinearGen(port, master_id,
2429241Sandreas.hansson@arm.com                                                   duration, start_addr,
2439241Sandreas.hansson@arm.com                                                   end_addr, blocksize,
2449241Sandreas.hansson@arm.com                                                   min_period, max_period,
2459241Sandreas.hansson@arm.com                                                   read_percent, data_limit);
2469241Sandreas.hansson@arm.com                        DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
2479241Sandreas.hansson@arm.com                    } else if (mode == "RANDOM") {
2489241Sandreas.hansson@arm.com                        states[id] = new RandomGen(port, master_id,
2499241Sandreas.hansson@arm.com                                                   duration, start_addr,
2509241Sandreas.hansson@arm.com                                                   end_addr, blocksize,
2519241Sandreas.hansson@arm.com                                                   min_period, max_period,
2529241Sandreas.hansson@arm.com                                                   read_percent, data_limit);
2539241Sandreas.hansson@arm.com                        DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
2549241Sandreas.hansson@arm.com                    }
2559241Sandreas.hansson@arm.com                } else {
2569241Sandreas.hansson@arm.com                    fatal("%s: Unknown traffic generator mode: %s",
2579241Sandreas.hansson@arm.com                          name(), mode);
2589241Sandreas.hansson@arm.com                }
2599241Sandreas.hansson@arm.com            } else if (keyword == "TRANSITION") {
2609241Sandreas.hansson@arm.com                Transition transition;
2619241Sandreas.hansson@arm.com
2629241Sandreas.hansson@arm.com                is >> transition.from >> transition.to >> transition.p;
2639241Sandreas.hansson@arm.com
2649241Sandreas.hansson@arm.com                transitions.push_back(transition);
2659241Sandreas.hansson@arm.com
2669241Sandreas.hansson@arm.com                DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
2679241Sandreas.hansson@arm.com                        transition.to);
2689241Sandreas.hansson@arm.com            } else if (keyword == "INIT") {
2699241Sandreas.hansson@arm.com                // set the initial state as the active state
2709241Sandreas.hansson@arm.com                is >> currState;
2719241Sandreas.hansson@arm.com
2729241Sandreas.hansson@arm.com                DPRINTF(TrafficGen, "Initial state: %d\n", currState);
2739241Sandreas.hansson@arm.com            }
2749241Sandreas.hansson@arm.com        }
2759241Sandreas.hansson@arm.com    }
2769241Sandreas.hansson@arm.com
2779241Sandreas.hansson@arm.com    // resize and populate state transition matrix
2789241Sandreas.hansson@arm.com    transitionMatrix.resize(transitions.size());
2799241Sandreas.hansson@arm.com    for (size_t i = 0; i < transitions.size(); i++) {
2809241Sandreas.hansson@arm.com        transitionMatrix[i].resize(transitions.size());
2819241Sandreas.hansson@arm.com    }
2829241Sandreas.hansson@arm.com
2839241Sandreas.hansson@arm.com    for (vector<Transition>::iterator t = transitions.begin();
2849241Sandreas.hansson@arm.com         t != transitions.end(); ++t) {
2859241Sandreas.hansson@arm.com        transitionMatrix[t->from][t->to] = t->p;
2869241Sandreas.hansson@arm.com    }
2879241Sandreas.hansson@arm.com
2889241Sandreas.hansson@arm.com    // ensure the egress edges do not have a probability larger than
2899241Sandreas.hansson@arm.com    // one
2909241Sandreas.hansson@arm.com    for (size_t i = 0; i < transitions.size(); i++) {
2919241Sandreas.hansson@arm.com        double sum = 0;
2929241Sandreas.hansson@arm.com        for (size_t j = 0; j < transitions.size(); j++) {
2939241Sandreas.hansson@arm.com            sum += transitionMatrix[i][j];
2949241Sandreas.hansson@arm.com        }
2959241Sandreas.hansson@arm.com
2969241Sandreas.hansson@arm.com        // avoid comparing floating point numbers
2979241Sandreas.hansson@arm.com        if (abs(sum - 1.0) > 0.001)
2989241Sandreas.hansson@arm.com            fatal("%s has transition probability != 1 for state %d\n",
2999241Sandreas.hansson@arm.com                  name(), i);
3009241Sandreas.hansson@arm.com    }
3019241Sandreas.hansson@arm.com
3029241Sandreas.hansson@arm.com    // close input file
3039241Sandreas.hansson@arm.com    infile.close();
3049241Sandreas.hansson@arm.com}
3059241Sandreas.hansson@arm.com
3069241Sandreas.hansson@arm.comvoid
3079241Sandreas.hansson@arm.comTrafficGen::StateGraph::update()
3089241Sandreas.hansson@arm.com{
3099241Sandreas.hansson@arm.com    // if we have reached the time for the next state transition, then
3109241Sandreas.hansson@arm.com    // perform the transition
3119241Sandreas.hansson@arm.com    if (curTick() >= nextTransitionTick) {
3129241Sandreas.hansson@arm.com        transition();
3139241Sandreas.hansson@arm.com    } else {
3149241Sandreas.hansson@arm.com        // we are still in the current state and should execute it
3159241Sandreas.hansson@arm.com        states[currState]->execute();
3169241Sandreas.hansson@arm.com    }
3179241Sandreas.hansson@arm.com}
3189241Sandreas.hansson@arm.com
3199241Sandreas.hansson@arm.comvoid
3209241Sandreas.hansson@arm.comTrafficGen::StateGraph::transition()
3219241Sandreas.hansson@arm.com{
3229241Sandreas.hansson@arm.com    // exit the current state
3239241Sandreas.hansson@arm.com    states[currState]->exit();
3249241Sandreas.hansson@arm.com
3259241Sandreas.hansson@arm.com    // determine next state
3269241Sandreas.hansson@arm.com    double p = random_mt.gen_real1();
3279241Sandreas.hansson@arm.com    assert(currState < transitionMatrix.size());
3289241Sandreas.hansson@arm.com    double cumulative = transitionMatrix[currState][0];
3299241Sandreas.hansson@arm.com    size_t i = 1;
3309241Sandreas.hansson@arm.com    while (p < cumulative && i != transitionMatrix[currState].size()) {
3319241Sandreas.hansson@arm.com        cumulative += transitionMatrix[currState][i];
3329241Sandreas.hansson@arm.com        ++i;
3339241Sandreas.hansson@arm.com    }
3349241Sandreas.hansson@arm.com    enterState(i);
3359241Sandreas.hansson@arm.com}
3369241Sandreas.hansson@arm.com
3379241Sandreas.hansson@arm.comvoid
3389241Sandreas.hansson@arm.comTrafficGen::StateGraph::enterState(uint32_t newState)
3399241Sandreas.hansson@arm.com{
3409241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "Transition to state %d\n", newState);
3419241Sandreas.hansson@arm.com
3429241Sandreas.hansson@arm.com    currState = newState;
3439241Sandreas.hansson@arm.com    nextTransitionTick += states[currState]->duration;
3449241Sandreas.hansson@arm.com    states[currState]->enter();
3459241Sandreas.hansson@arm.com}
3469241Sandreas.hansson@arm.com
3479241Sandreas.hansson@arm.comTrafficGen::StateGraph::BaseGen::BaseGen(QueuedMasterPort& _port,
3489241Sandreas.hansson@arm.com                                         MasterID master_id,
3499241Sandreas.hansson@arm.com                                         Tick _duration)
3509241Sandreas.hansson@arm.com    : port(_port), masterID(master_id), duration(_duration)
3519241Sandreas.hansson@arm.com{
3529241Sandreas.hansson@arm.com}
3539241Sandreas.hansson@arm.com
3549241Sandreas.hansson@arm.comvoid
3559241Sandreas.hansson@arm.comTrafficGen::StateGraph::LinearGen::enter()
3569241Sandreas.hansson@arm.com{
3579241Sandreas.hansson@arm.com    // reset the address and the data counter
3589241Sandreas.hansson@arm.com    nextAddr = startAddr;
3599241Sandreas.hansson@arm.com    dataManipulated = 0;
3609241Sandreas.hansson@arm.com
3619241Sandreas.hansson@arm.com    // this test only needs to happen once, but cannot be performed
3629241Sandreas.hansson@arm.com    // before init() is called and the ports are connected
3639241Sandreas.hansson@arm.com    if (port.deviceBlockSize() && blocksize > port.deviceBlockSize())
3649241Sandreas.hansson@arm.com        fatal("TrafficGen %s block size (%d) is larger than port"
3659241Sandreas.hansson@arm.com              " block size (%d)\n", blocksize, port.deviceBlockSize());
3669241Sandreas.hansson@arm.com
3679241Sandreas.hansson@arm.com}
3689241Sandreas.hansson@arm.com
3699241Sandreas.hansson@arm.comvoid
3709241Sandreas.hansson@arm.comTrafficGen::StateGraph::LinearGen::execute()
3719241Sandreas.hansson@arm.com{
3729241Sandreas.hansson@arm.com    // choose if we generate a read or a write here
3739241Sandreas.hansson@arm.com    bool isRead = random_mt.random<uint8_t>(0, 100) < readPercent;
3749241Sandreas.hansson@arm.com
3759241Sandreas.hansson@arm.com    if (readPercent == 0)
3769241Sandreas.hansson@arm.com        assert(!isRead);
3779241Sandreas.hansson@arm.com
3789241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "LinearGen::execute: %c to addr %x, size %d\n",
3799241Sandreas.hansson@arm.com            isRead ? 'r' : 'w', nextAddr, blocksize);
3809241Sandreas.hansson@arm.com
3819241Sandreas.hansson@arm.com    // Create new request
3829241Sandreas.hansson@arm.com    Request::Flags flags;
3839241Sandreas.hansson@arm.com    Request *req = new Request(nextAddr, blocksize, flags, masterID);
3849241Sandreas.hansson@arm.com
3859241Sandreas.hansson@arm.com    PacketPtr pkt = new Packet(req, isRead ? MemCmd::ReadReq :
3869241Sandreas.hansson@arm.com                               MemCmd::WriteReq);
3879241Sandreas.hansson@arm.com
3889241Sandreas.hansson@arm.com    uint8_t* pkt_data = new uint8_t[req->getSize()];
3899241Sandreas.hansson@arm.com    pkt->dataDynamicArray(pkt_data);
3909241Sandreas.hansson@arm.com
3919241Sandreas.hansson@arm.com    if (!isRead) {
3929241Sandreas.hansson@arm.com        memset(pkt_data, 0xA, req->getSize());
3939241Sandreas.hansson@arm.com    }
3949241Sandreas.hansson@arm.com
3959241Sandreas.hansson@arm.com    port.schedTimingReq(pkt, curTick());
3969241Sandreas.hansson@arm.com
3979241Sandreas.hansson@arm.com    // increment the address
3989241Sandreas.hansson@arm.com    nextAddr += blocksize;
3999241Sandreas.hansson@arm.com
4009241Sandreas.hansson@arm.com    // Add the amount of data manipulated to the total
4019241Sandreas.hansson@arm.com    dataManipulated += blocksize;
4029241Sandreas.hansson@arm.com}
4039241Sandreas.hansson@arm.com
4049241Sandreas.hansson@arm.comTick
4059241Sandreas.hansson@arm.comTrafficGen::StateGraph::LinearGen::nextExecuteTick()
4069241Sandreas.hansson@arm.com{
4079241Sandreas.hansson@arm.com    // If we have reached the end of the address space, reset the
4089241Sandreas.hansson@arm.com    // address to the start of the range
4099241Sandreas.hansson@arm.com    if (nextAddr + blocksize > endAddr) {
4109241Sandreas.hansson@arm.com        DPRINTF(TrafficGen, "Wrapping address to the start of "
4119241Sandreas.hansson@arm.com                "the range\n");
4129241Sandreas.hansson@arm.com        nextAddr = startAddr;
4139241Sandreas.hansson@arm.com    }
4149241Sandreas.hansson@arm.com
4159241Sandreas.hansson@arm.com    // Check to see if we have reached the data limit. If dataLimit is
4169241Sandreas.hansson@arm.com    // zero we do not have a data limit and therefore we will keep
4179241Sandreas.hansson@arm.com    // generating requests for the entire residency in this state.
4189241Sandreas.hansson@arm.com    if (dataLimit && dataManipulated >= dataLimit) {
4199241Sandreas.hansson@arm.com        DPRINTF(TrafficGen, "Data limit for LinearGen reached.\n");
4209241Sandreas.hansson@arm.com        // there are no more requests, therefore return MaxTick
4219241Sandreas.hansson@arm.com        return MaxTick;
4229241Sandreas.hansson@arm.com    } else {
4239241Sandreas.hansson@arm.com        // return the time when the next request should take place
4249241Sandreas.hansson@arm.com        return curTick() + random_mt.random<Tick>(minPeriod, maxPeriod);
4259241Sandreas.hansson@arm.com    }
4269241Sandreas.hansson@arm.com}
4279241Sandreas.hansson@arm.com
4289241Sandreas.hansson@arm.comvoid
4299241Sandreas.hansson@arm.comTrafficGen::StateGraph::RandomGen::enter()
4309241Sandreas.hansson@arm.com{
4319241Sandreas.hansson@arm.com    // reset the counter to zero
4329241Sandreas.hansson@arm.com    dataManipulated = 0;
4339241Sandreas.hansson@arm.com
4349241Sandreas.hansson@arm.com    // this test only needs to happen once, but cannot be performed
4359241Sandreas.hansson@arm.com    // before init() is called and the ports are connected
4369241Sandreas.hansson@arm.com    if (port.deviceBlockSize() && blocksize > port.deviceBlockSize())
4379241Sandreas.hansson@arm.com        fatal("TrafficGen %s block size (%d) is larger than port"
4389241Sandreas.hansson@arm.com              " block size (%d)\n", name(), blocksize, port.deviceBlockSize());
4399241Sandreas.hansson@arm.com}
4409241Sandreas.hansson@arm.com
4419241Sandreas.hansson@arm.comvoid
4429241Sandreas.hansson@arm.comTrafficGen::StateGraph::RandomGen::execute()
4439241Sandreas.hansson@arm.com{
4449241Sandreas.hansson@arm.com    // choose if we generate a read or a write here
4459241Sandreas.hansson@arm.com    bool isRead = random_mt.random<uint8_t>(0, 100) < readPercent;
4469241Sandreas.hansson@arm.com
4479241Sandreas.hansson@arm.com    if (readPercent == 0)
4489241Sandreas.hansson@arm.com        assert(!isRead);
4499241Sandreas.hansson@arm.com
4509241Sandreas.hansson@arm.com    // address of the request
4519241Sandreas.hansson@arm.com    Addr addr = random_mt.random<Addr>(startAddr, endAddr - 1);
4529241Sandreas.hansson@arm.com
4539241Sandreas.hansson@arm.com    // round down to start address of block
4549241Sandreas.hansson@arm.com    addr -= addr % blocksize;
4559241Sandreas.hansson@arm.com
4569241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "RandomGen::execute: %c to addr %x, size %d\n",
4579241Sandreas.hansson@arm.com            isRead ? 'r' : 'w', addr, blocksize);
4589241Sandreas.hansson@arm.com
4599241Sandreas.hansson@arm.com    // create new request packet
4609241Sandreas.hansson@arm.com    Request::Flags flags;
4619241Sandreas.hansson@arm.com    Request *req = new Request(addr, blocksize, flags, masterID);
4629241Sandreas.hansson@arm.com
4639241Sandreas.hansson@arm.com    PacketPtr pkt = new Packet(req, isRead ? MemCmd::ReadReq :
4649241Sandreas.hansson@arm.com                               MemCmd::WriteReq);
4659241Sandreas.hansson@arm.com
4669241Sandreas.hansson@arm.com    uint8_t* pkt_data = new uint8_t[req->getSize()];
4679241Sandreas.hansson@arm.com    pkt->dataDynamicArray(pkt_data);
4689241Sandreas.hansson@arm.com
4699241Sandreas.hansson@arm.com    if (!isRead) {
4709241Sandreas.hansson@arm.com        memset(pkt_data, 0xA, req->getSize());
4719241Sandreas.hansson@arm.com    }
4729241Sandreas.hansson@arm.com
4739241Sandreas.hansson@arm.com    port.schedTimingReq(pkt, curTick());
4749241Sandreas.hansson@arm.com
4759241Sandreas.hansson@arm.com    // Add the amount of data manipulated to the total
4769241Sandreas.hansson@arm.com    dataManipulated += blocksize;
4779241Sandreas.hansson@arm.com}
4789241Sandreas.hansson@arm.com
4799241Sandreas.hansson@arm.comTick
4809241Sandreas.hansson@arm.comTrafficGen::StateGraph::RandomGen::nextExecuteTick()
4819241Sandreas.hansson@arm.com{
4829241Sandreas.hansson@arm.com    // Check to see if we have reached the data limit. If dataLimit is
4839241Sandreas.hansson@arm.com    // zero we do not have a data limit and therefore we will keep
4849241Sandreas.hansson@arm.com    // generating requests for the entire residency in this state.
4859241Sandreas.hansson@arm.com    if (dataLimit && dataManipulated >= dataLimit)
4869241Sandreas.hansson@arm.com    {
4879241Sandreas.hansson@arm.com        DPRINTF(TrafficGen, "Data limit for RandomGen reached.\n");
4889241Sandreas.hansson@arm.com        // No more requests. Return MaxTick.
4899241Sandreas.hansson@arm.com        return MaxTick;
4909241Sandreas.hansson@arm.com    } else {
4919241Sandreas.hansson@arm.com        // Return the time when the next request should take place.
4929241Sandreas.hansson@arm.com        return curTick() + random_mt.random<Tick>(minPeriod, maxPeriod);
4939241Sandreas.hansson@arm.com    }
4949241Sandreas.hansson@arm.com}
4959241Sandreas.hansson@arm.com
4969241Sandreas.hansson@arm.comTick
4979241Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::nextExecuteTick() {
4989241Sandreas.hansson@arm.com    // We need to look at the next line to calculate the next time an
4999241Sandreas.hansson@arm.com    // event occurs, or potentially return MaxTick to signal that
5009241Sandreas.hansson@arm.com    // nothing has to be done.
5019241Sandreas.hansson@arm.com    string buffer;
5029241Sandreas.hansson@arm.com    if (!traceComplete && trace.good()){
5039241Sandreas.hansson@arm.com        getline(trace, buffer);
5049241Sandreas.hansson@arm.com        DPRINTF(TrafficGen, "Input trace: %s\n", buffer);
5059241Sandreas.hansson@arm.com    } else {
5069241Sandreas.hansson@arm.com        // We are at the end of the file, thus we have no more data in
5079241Sandreas.hansson@arm.com        // the trace Return MaxTick to signal that there will be no
5089241Sandreas.hansson@arm.com        // more transactions in this active period for the state.
5099241Sandreas.hansson@arm.com        return MaxTick;
5109241Sandreas.hansson@arm.com    }
5119241Sandreas.hansson@arm.com
5129241Sandreas.hansson@arm.com    //Reset the nextElement to the default values
5139241Sandreas.hansson@arm.com    currElement = nextElement;
5149241Sandreas.hansson@arm.com    nextElement.clear();
5159241Sandreas.hansson@arm.com
5169241Sandreas.hansson@arm.com    // Check that we have something to process. This assume no EOF at
5179241Sandreas.hansson@arm.com    // the end of the line.
5189241Sandreas.hansson@arm.com    if (buffer.size() > 0 && !trace.eof()) {
5199241Sandreas.hansson@arm.com        istringstream iss(buffer);
5209241Sandreas.hansson@arm.com
5219241Sandreas.hansson@arm.com        char rOrW, ch;
5229241Sandreas.hansson@arm.com        iss >> rOrW;
5239241Sandreas.hansson@arm.com        iss >> ch; assert(ch == ',');
5249241Sandreas.hansson@arm.com        iss >> nextElement.addr;
5259241Sandreas.hansson@arm.com        iss >> ch; assert(ch == ',');
5269241Sandreas.hansson@arm.com        iss >> nextElement.blocksize;
5279241Sandreas.hansson@arm.com        iss >> ch; assert(ch == ',');
5289241Sandreas.hansson@arm.com        iss >> nextElement.tick;
5299241Sandreas.hansson@arm.com
5309241Sandreas.hansson@arm.com        if (rOrW == 'r') {
5319241Sandreas.hansson@arm.com            nextElement.cmd = MemCmd::ReadReq;
5329241Sandreas.hansson@arm.com        } else if (rOrW == 'w') {
5339241Sandreas.hansson@arm.com            nextElement.cmd = MemCmd::WriteReq;
5349241Sandreas.hansson@arm.com        } else {
5359241Sandreas.hansson@arm.com            fatal("Incorrect trace file format!\n");
5369241Sandreas.hansson@arm.com        }
5379241Sandreas.hansson@arm.com    }
5389241Sandreas.hansson@arm.com
5399241Sandreas.hansson@arm.com    // Check that we have a valid request
5409241Sandreas.hansson@arm.com    if (!nextElement.isValid()) {
5419241Sandreas.hansson@arm.com        // If it is not valid, assume that we have reached the end of
5429241Sandreas.hansson@arm.com        // the trace.  Even if this is not the case, we do not know
5439241Sandreas.hansson@arm.com        // what to do with the request as it makes no sense.
5449241Sandreas.hansson@arm.com        if (trace.good()) {
5459241Sandreas.hansson@arm.com            // Trace is good, therefore we are not at the end of the
5469241Sandreas.hansson@arm.com            // file. This means that the input trace cannot be read
5479241Sandreas.hansson@arm.com            // correctly or it contains data that makes no sense.
5489241Sandreas.hansson@arm.com            warn("Unable to read the trace file format\n");
5499241Sandreas.hansson@arm.com            warn("%s", buffer);
5509241Sandreas.hansson@arm.com        }
5519241Sandreas.hansson@arm.com
5529241Sandreas.hansson@arm.com        traceComplete = true;
5539241Sandreas.hansson@arm.com        return MaxTick;
5549241Sandreas.hansson@arm.com    }
5559241Sandreas.hansson@arm.com
5569241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "currElement: %c addr %d size %d tick %d (%d)\n",
5579241Sandreas.hansson@arm.com            currElement.cmd.isRead() ? 'r' : 'w',
5589241Sandreas.hansson@arm.com            currElement.addr,
5599241Sandreas.hansson@arm.com            currElement.blocksize,
5609241Sandreas.hansson@arm.com            currElement.tick + tickOffset,
5619241Sandreas.hansson@arm.com            currElement.tick);
5629241Sandreas.hansson@arm.com
5639241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "nextElement: %c addr %d size %d tick %d (%d)\n",
5649241Sandreas.hansson@arm.com            nextElement.cmd.isRead() ? 'r' : 'w',
5659241Sandreas.hansson@arm.com            nextElement.addr,
5669241Sandreas.hansson@arm.com            nextElement.blocksize,
5679241Sandreas.hansson@arm.com            nextElement.tick + tickOffset,
5689241Sandreas.hansson@arm.com            nextElement.tick);
5699241Sandreas.hansson@arm.com
5709241Sandreas.hansson@arm.com    return tickOffset + nextElement.tick;
5719241Sandreas.hansson@arm.com}
5729241Sandreas.hansson@arm.com
5739241Sandreas.hansson@arm.comvoid
5749241Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::enter() {
5759241Sandreas.hansson@arm.com    // update the trace offset to the time where the state was entered.
5769241Sandreas.hansson@arm.com    tickOffset = curTick();
5779241Sandreas.hansson@arm.com
5789241Sandreas.hansson@arm.com    // seek to the start of the input trace file
5799241Sandreas.hansson@arm.com    trace.seekg(0, ifstream::beg);
5809241Sandreas.hansson@arm.com    trace.clear();
5819241Sandreas.hansson@arm.com
5829241Sandreas.hansson@arm.com    // clear everything
5839241Sandreas.hansson@arm.com    nextElement.clear();
5849241Sandreas.hansson@arm.com    currElement.clear();
5859241Sandreas.hansson@arm.com
5869241Sandreas.hansson@arm.com    traceComplete = false;
5879241Sandreas.hansson@arm.com}
5889241Sandreas.hansson@arm.com
5899241Sandreas.hansson@arm.comvoid
5909241Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::execute() {
5919241Sandreas.hansson@arm.com    // it is the responsibility of nextExecuteTick to prevent the
5929241Sandreas.hansson@arm.com    // state graph from executing the state if it should not
5939241Sandreas.hansson@arm.com    assert(currElement.isValid());
5949241Sandreas.hansson@arm.com
5959241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "TraceGen::execute: %c %d %d %d\n",
5969241Sandreas.hansson@arm.com            currElement.cmd.isRead() ? 'r' : 'w',
5979241Sandreas.hansson@arm.com            currElement.addr,
5989241Sandreas.hansson@arm.com            currElement.blocksize,
5999241Sandreas.hansson@arm.com            currElement.tick);
6009241Sandreas.hansson@arm.com
6019241Sandreas.hansson@arm.com    Request::Flags flags;
6029241Sandreas.hansson@arm.com    Request *req = new Request(currElement.addr + addrOffset,
6039241Sandreas.hansson@arm.com                               currElement.blocksize, flags, masterID);
6049241Sandreas.hansson@arm.com
6059241Sandreas.hansson@arm.com    PacketPtr pkt = new Packet(req, currElement.cmd);
6069241Sandreas.hansson@arm.com
6079241Sandreas.hansson@arm.com    uint8_t* pkt_data = new uint8_t[req->getSize()];
6089241Sandreas.hansson@arm.com    pkt->dataDynamicArray(pkt_data);
6099241Sandreas.hansson@arm.com
6109241Sandreas.hansson@arm.com    if (currElement.cmd.isWrite()) {
6119241Sandreas.hansson@arm.com        memset(pkt_data, 0xA, req->getSize());
6129241Sandreas.hansson@arm.com    }
6139241Sandreas.hansson@arm.com
6149241Sandreas.hansson@arm.com    port.schedTimingReq(pkt, curTick());
6159241Sandreas.hansson@arm.com}
6169241Sandreas.hansson@arm.com
6179241Sandreas.hansson@arm.comvoid
6189241Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::exit() {
6199241Sandreas.hansson@arm.com    // Check if we reached the end of the trace file. If we did not
6209241Sandreas.hansson@arm.com    // then we want to generate a warning stating that not the entire
6219241Sandreas.hansson@arm.com    // trace was played.
6229241Sandreas.hansson@arm.com    if (!trace.eof()) {
6239241Sandreas.hansson@arm.com        warn("Trace player %s was unable to replay the entire trace!\n",
6249241Sandreas.hansson@arm.com             name());
6259241Sandreas.hansson@arm.com    }
6269241Sandreas.hansson@arm.com
6279241Sandreas.hansson@arm.com    // clear any previous error flags for the input trace file
6289241Sandreas.hansson@arm.com    trace.clear();
6299241Sandreas.hansson@arm.com}
6309241Sandreas.hansson@arm.com
6319241Sandreas.hansson@arm.combool
6329241Sandreas.hansson@arm.comTrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
6339241Sandreas.hansson@arm.com{
6349241Sandreas.hansson@arm.com    delete pkt->req;
6359241Sandreas.hansson@arm.com    delete pkt;
6369241Sandreas.hansson@arm.com
6379241Sandreas.hansson@arm.com    return true;
6389241Sandreas.hansson@arm.com}
639