trace_cpu.cc revision 11253
111249Sradhika.jagtap@ARM.com/*
211249Sradhika.jagtap@ARM.com * Copyright (c) 2013 - 2015 ARM Limited
311249Sradhika.jagtap@ARM.com * All rights reserved
411249Sradhika.jagtap@ARM.com *
511249Sradhika.jagtap@ARM.com * The license below extends only to copyright in the software and shall
611249Sradhika.jagtap@ARM.com * not be construed as granting a license to any other intellectual
711249Sradhika.jagtap@ARM.com * property including but not limited to intellectual property relating
811249Sradhika.jagtap@ARM.com * to a hardware implementation of the functionality of the software
911249Sradhika.jagtap@ARM.com * licensed hereunder.  You may use the software subject to the license
1011249Sradhika.jagtap@ARM.com * terms below provided that you ensure that this notice is replicated
1111249Sradhika.jagtap@ARM.com * unmodified and in its entirety in all distributions of the software,
1211249Sradhika.jagtap@ARM.com * modified or unmodified, in source code or in binary form.
1311249Sradhika.jagtap@ARM.com *
1411249Sradhika.jagtap@ARM.com * Redistribution and use in source and binary forms, with or without
1511249Sradhika.jagtap@ARM.com * modification, are permitted provided that the following conditions are
1611249Sradhika.jagtap@ARM.com * met: redistributions of source code must retain the above copyright
1711249Sradhika.jagtap@ARM.com * notice, this list of conditions and the following disclaimer;
1811249Sradhika.jagtap@ARM.com * redistributions in binary form must reproduce the above copyright
1911249Sradhika.jagtap@ARM.com * notice, this list of conditions and the following disclaimer in the
2011249Sradhika.jagtap@ARM.com * documentation and/or other materials provided with the distribution;
2111249Sradhika.jagtap@ARM.com * neither the name of the copyright holders nor the names of its
2211249Sradhika.jagtap@ARM.com * contributors may be used to endorse or promote products derived from
2311249Sradhika.jagtap@ARM.com * this software without specific prior written permission.
2411249Sradhika.jagtap@ARM.com *
2511249Sradhika.jagtap@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2611249Sradhika.jagtap@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2711249Sradhika.jagtap@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2811249Sradhika.jagtap@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2911249Sradhika.jagtap@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3011249Sradhika.jagtap@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3111249Sradhika.jagtap@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3211249Sradhika.jagtap@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3311249Sradhika.jagtap@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3411249Sradhika.jagtap@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3511249Sradhika.jagtap@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3611249Sradhika.jagtap@ARM.com *
3711249Sradhika.jagtap@ARM.com * Authors: Radhika Jagtap
3811249Sradhika.jagtap@ARM.com *          Andreas Hansson
3911249Sradhika.jagtap@ARM.com *          Thomas Grass
4011249Sradhika.jagtap@ARM.com */
4111249Sradhika.jagtap@ARM.com
4211249Sradhika.jagtap@ARM.com#include "cpu/trace/trace_cpu.hh"
4311249Sradhika.jagtap@ARM.com
4411249Sradhika.jagtap@ARM.com#include "sim/sim_exit.hh"
4511249Sradhika.jagtap@ARM.com
4611249Sradhika.jagtap@ARM.com// Declare and initialize the static counter for number of trace CPUs.
4711249Sradhika.jagtap@ARM.comint TraceCPU::numTraceCPUs = 0;
4811249Sradhika.jagtap@ARM.com
4911249Sradhika.jagtap@ARM.comTraceCPU::TraceCPU(TraceCPUParams *params)
5011249Sradhika.jagtap@ARM.com    :   BaseCPU(params),
5111249Sradhika.jagtap@ARM.com        icachePort(this),
5211249Sradhika.jagtap@ARM.com        dcachePort(this),
5311249Sradhika.jagtap@ARM.com        instMasterID(params->system->getMasterId(name() + ".inst")),
5411249Sradhika.jagtap@ARM.com        dataMasterID(params->system->getMasterId(name() + ".data")),
5511249Sradhika.jagtap@ARM.com        instTraceFile(params->instTraceFile),
5611249Sradhika.jagtap@ARM.com        dataTraceFile(params->dataTraceFile),
5711249Sradhika.jagtap@ARM.com        icacheGen(*this, ".iside", icachePort, instMasterID, instTraceFile),
5811249Sradhika.jagtap@ARM.com        dcacheGen(*this, ".dside", dcachePort, dataMasterID, dataTraceFile,
5911249Sradhika.jagtap@ARM.com                    params->sizeROB, params->sizeStoreBuffer,
6011249Sradhika.jagtap@ARM.com                    params->sizeLoadBuffer),
6111249Sradhika.jagtap@ARM.com        icacheNextEvent(this),
6211249Sradhika.jagtap@ARM.com        dcacheNextEvent(this),
6311249Sradhika.jagtap@ARM.com        oneTraceComplete(false),
6411249Sradhika.jagtap@ARM.com        firstFetchTick(0),
6511249Sradhika.jagtap@ARM.com        execCompleteEvent(nullptr)
6611249Sradhika.jagtap@ARM.com{
6711249Sradhika.jagtap@ARM.com    // Increment static counter for number of Trace CPUs.
6811249Sradhika.jagtap@ARM.com    ++TraceCPU::numTraceCPUs;
6911249Sradhika.jagtap@ARM.com
7011249Sradhika.jagtap@ARM.com    // Check that the python parameters for sizes of ROB, store buffer and load
7111249Sradhika.jagtap@ARM.com    // buffer do not overflow the corresponding C++ variables.
7211249Sradhika.jagtap@ARM.com    fatal_if(params->sizeROB > UINT16_MAX, "ROB size set to %d exceeds the "
7311249Sradhika.jagtap@ARM.com                "max. value of %d.\n", params->sizeROB, UINT16_MAX);
7411249Sradhika.jagtap@ARM.com    fatal_if(params->sizeStoreBuffer > UINT16_MAX, "ROB size set to %d "
7511249Sradhika.jagtap@ARM.com                "exceeds the max. value of %d.\n", params->sizeROB,
7611249Sradhika.jagtap@ARM.com                UINT16_MAX);
7711249Sradhika.jagtap@ARM.com    fatal_if(params->sizeLoadBuffer > UINT16_MAX, "Load buffer size set to"
7811249Sradhika.jagtap@ARM.com                " %d exceeds the max. value of %d.\n",
7911249Sradhika.jagtap@ARM.com                params->sizeLoadBuffer, UINT16_MAX);
8011249Sradhika.jagtap@ARM.com}
8111249Sradhika.jagtap@ARM.com
8211249Sradhika.jagtap@ARM.comTraceCPU::~TraceCPU()
8311249Sradhika.jagtap@ARM.com{
8411249Sradhika.jagtap@ARM.com
8511249Sradhika.jagtap@ARM.com}
8611249Sradhika.jagtap@ARM.com
8711249Sradhika.jagtap@ARM.comTraceCPU*
8811249Sradhika.jagtap@ARM.comTraceCPUParams::create()
8911249Sradhika.jagtap@ARM.com{
9011249Sradhika.jagtap@ARM.com    return new TraceCPU(this);
9111249Sradhika.jagtap@ARM.com}
9211249Sradhika.jagtap@ARM.com
9311249Sradhika.jagtap@ARM.comvoid
9411249Sradhika.jagtap@ARM.comTraceCPU::takeOverFrom(BaseCPU *oldCPU)
9511249Sradhika.jagtap@ARM.com{
9611249Sradhika.jagtap@ARM.com    // Unbind the ports of the old CPU and bind the ports of the TraceCPU.
9711249Sradhika.jagtap@ARM.com    assert(!getInstPort().isConnected());
9811249Sradhika.jagtap@ARM.com    assert(oldCPU->getInstPort().isConnected());
9911249Sradhika.jagtap@ARM.com    BaseSlavePort &inst_peer_port = oldCPU->getInstPort().getSlavePort();
10011249Sradhika.jagtap@ARM.com    oldCPU->getInstPort().unbind();
10111249Sradhika.jagtap@ARM.com    getInstPort().bind(inst_peer_port);
10211249Sradhika.jagtap@ARM.com
10311249Sradhika.jagtap@ARM.com    assert(!getDataPort().isConnected());
10411249Sradhika.jagtap@ARM.com    assert(oldCPU->getDataPort().isConnected());
10511249Sradhika.jagtap@ARM.com    BaseSlavePort &data_peer_port = oldCPU->getDataPort().getSlavePort();
10611249Sradhika.jagtap@ARM.com    oldCPU->getDataPort().unbind();
10711249Sradhika.jagtap@ARM.com    getDataPort().bind(data_peer_port);
10811249Sradhika.jagtap@ARM.com}
10911249Sradhika.jagtap@ARM.com
11011249Sradhika.jagtap@ARM.comvoid
11111249Sradhika.jagtap@ARM.comTraceCPU::init()
11211249Sradhika.jagtap@ARM.com{
11311249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUInst, "Instruction fetch request trace file is \"%s\"."
11411249Sradhika.jagtap@ARM.com            "\n", instTraceFile);
11511249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUData, "Data memory request trace file is \"%s\".\n",
11611249Sradhika.jagtap@ARM.com            dataTraceFile);
11711249Sradhika.jagtap@ARM.com
11811249Sradhika.jagtap@ARM.com    BaseCPU::init();
11911249Sradhika.jagtap@ARM.com
12011249Sradhika.jagtap@ARM.com    // Get the send tick of the first instruction read request and schedule
12111249Sradhika.jagtap@ARM.com    // icacheNextEvent at that tick.
12211249Sradhika.jagtap@ARM.com    Tick first_icache_tick = icacheGen.init();
12311249Sradhika.jagtap@ARM.com    schedule(icacheNextEvent, first_icache_tick);
12411249Sradhika.jagtap@ARM.com
12511249Sradhika.jagtap@ARM.com    // Get the send tick of the first data read/write request and schedule
12611249Sradhika.jagtap@ARM.com    // dcacheNextEvent at that tick.
12711249Sradhika.jagtap@ARM.com    Tick first_dcache_tick = dcacheGen.init();
12811249Sradhika.jagtap@ARM.com    schedule(dcacheNextEvent, first_dcache_tick);
12911249Sradhika.jagtap@ARM.com
13011249Sradhika.jagtap@ARM.com    // The static counter for number of Trace CPUs is correctly set at this
13111249Sradhika.jagtap@ARM.com    // point so create an event and pass it.
13211249Sradhika.jagtap@ARM.com    execCompleteEvent = new CountedExitEvent("end of all traces reached.",
13311249Sradhika.jagtap@ARM.com                                                numTraceCPUs);
13411249Sradhika.jagtap@ARM.com    // Save the first fetch request tick to dump it as tickOffset
13511249Sradhika.jagtap@ARM.com    firstFetchTick = first_icache_tick;
13611249Sradhika.jagtap@ARM.com}
13711249Sradhika.jagtap@ARM.com
13811249Sradhika.jagtap@ARM.comvoid
13911249Sradhika.jagtap@ARM.comTraceCPU::schedIcacheNext()
14011249Sradhika.jagtap@ARM.com{
14111249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUInst, "IcacheGen event.\n");
14211249Sradhika.jagtap@ARM.com
14311249Sradhika.jagtap@ARM.com    // Try to send the current packet or a retry packet if there is one
14411249Sradhika.jagtap@ARM.com    bool sched_next = icacheGen.tryNext();
14511249Sradhika.jagtap@ARM.com    // If packet sent successfully, schedule next event
14611249Sradhika.jagtap@ARM.com    if (sched_next) {
14711249Sradhika.jagtap@ARM.com        DPRINTF(TraceCPUInst, "Scheduling next icacheGen event "
14811249Sradhika.jagtap@ARM.com                "at %d.\n", curTick() + icacheGen.tickDelta());
14911249Sradhika.jagtap@ARM.com        schedule(icacheNextEvent, curTick() + icacheGen.tickDelta());
15011249Sradhika.jagtap@ARM.com        ++numSchedIcacheEvent;
15111249Sradhika.jagtap@ARM.com    } else {
15211249Sradhika.jagtap@ARM.com        // check if traceComplete. If not, do nothing because sending failed
15311249Sradhika.jagtap@ARM.com        // and next event will be scheduled via RecvRetry()
15411249Sradhika.jagtap@ARM.com        if (icacheGen.isTraceComplete()) {
15511249Sradhika.jagtap@ARM.com            // If this is the first trace to complete, set the variable. If it
15611249Sradhika.jagtap@ARM.com            // is already set then both traces are complete to exit sim.
15711249Sradhika.jagtap@ARM.com            checkAndSchedExitEvent();
15811249Sradhika.jagtap@ARM.com        }
15911249Sradhika.jagtap@ARM.com    }
16011249Sradhika.jagtap@ARM.com    return;
16111249Sradhika.jagtap@ARM.com}
16211249Sradhika.jagtap@ARM.com
16311249Sradhika.jagtap@ARM.comvoid
16411249Sradhika.jagtap@ARM.comTraceCPU::schedDcacheNext()
16511249Sradhika.jagtap@ARM.com{
16611249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUData, "DcacheGen event.\n");
16711249Sradhika.jagtap@ARM.com
16811249Sradhika.jagtap@ARM.com    dcacheGen.execute();
16911249Sradhika.jagtap@ARM.com    if (dcacheGen.isExecComplete()) {
17011249Sradhika.jagtap@ARM.com        checkAndSchedExitEvent();
17111249Sradhika.jagtap@ARM.com    }
17211249Sradhika.jagtap@ARM.com}
17311249Sradhika.jagtap@ARM.com
17411249Sradhika.jagtap@ARM.comvoid
17511249Sradhika.jagtap@ARM.comTraceCPU::checkAndSchedExitEvent()
17611249Sradhika.jagtap@ARM.com{
17711249Sradhika.jagtap@ARM.com    if (!oneTraceComplete) {
17811249Sradhika.jagtap@ARM.com        oneTraceComplete = true;
17911249Sradhika.jagtap@ARM.com    } else {
18011249Sradhika.jagtap@ARM.com        // Schedule event to indicate execution is complete as both
18111249Sradhika.jagtap@ARM.com        // instruction and data access traces have been played back.
18211249Sradhika.jagtap@ARM.com        inform("%s: Execution complete.\n", name());
18311249Sradhika.jagtap@ARM.com
18411249Sradhika.jagtap@ARM.com        // Record stats which are computed at the end of simulation
18511249Sradhika.jagtap@ARM.com        tickOffset = firstFetchTick;
18611249Sradhika.jagtap@ARM.com        numCycles = (clockEdge() - firstFetchTick) / clockPeriod();
18711249Sradhika.jagtap@ARM.com        numOps = dcacheGen.getMicroOpCount();
18811249Sradhika.jagtap@ARM.com        schedule(*execCompleteEvent, curTick());
18911249Sradhika.jagtap@ARM.com    }
19011249Sradhika.jagtap@ARM.com}
19111249Sradhika.jagtap@ARM.com
19211249Sradhika.jagtap@ARM.comvoid
19311249Sradhika.jagtap@ARM.comTraceCPU::regStats()
19411249Sradhika.jagtap@ARM.com{
19511249Sradhika.jagtap@ARM.com
19611249Sradhika.jagtap@ARM.com    BaseCPU::regStats();
19711249Sradhika.jagtap@ARM.com
19811249Sradhika.jagtap@ARM.com    numSchedDcacheEvent
19911249Sradhika.jagtap@ARM.com    .name(name() + ".numSchedDcacheEvent")
20011249Sradhika.jagtap@ARM.com    .desc("Number of events scheduled to trigger data request generator")
20111249Sradhika.jagtap@ARM.com    ;
20211249Sradhika.jagtap@ARM.com
20311249Sradhika.jagtap@ARM.com    numSchedIcacheEvent
20411249Sradhika.jagtap@ARM.com    .name(name() + ".numSchedIcacheEvent")
20511249Sradhika.jagtap@ARM.com    .desc("Number of events scheduled to trigger instruction request generator")
20611249Sradhika.jagtap@ARM.com    ;
20711249Sradhika.jagtap@ARM.com
20811249Sradhika.jagtap@ARM.com    numOps
20911249Sradhika.jagtap@ARM.com    .name(name() + ".numOps")
21011249Sradhika.jagtap@ARM.com    .desc("Number of micro-ops simulated by the Trace CPU")
21111249Sradhika.jagtap@ARM.com    ;
21211249Sradhika.jagtap@ARM.com
21311249Sradhika.jagtap@ARM.com    cpi
21411249Sradhika.jagtap@ARM.com    .name(name() + ".cpi")
21511249Sradhika.jagtap@ARM.com    .desc("Cycles per micro-op used as a proxy for CPI")
21611249Sradhika.jagtap@ARM.com    .precision(6)
21711249Sradhika.jagtap@ARM.com    ;
21811249Sradhika.jagtap@ARM.com    cpi = numCycles/numOps;
21911249Sradhika.jagtap@ARM.com
22011249Sradhika.jagtap@ARM.com    tickOffset
22111249Sradhika.jagtap@ARM.com    .name(name() + ".tickOffset")
22211249Sradhika.jagtap@ARM.com    .desc("The first execution tick for the root node of elastic traces")
22311249Sradhika.jagtap@ARM.com    ;
22411249Sradhika.jagtap@ARM.com
22511249Sradhika.jagtap@ARM.com    icacheGen.regStats();
22611249Sradhika.jagtap@ARM.com    dcacheGen.regStats();
22711249Sradhika.jagtap@ARM.com}
22811249Sradhika.jagtap@ARM.com
22911249Sradhika.jagtap@ARM.comvoid
23011249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::regStats()
23111249Sradhika.jagtap@ARM.com{
23211249Sradhika.jagtap@ARM.com    using namespace Stats;
23311249Sradhika.jagtap@ARM.com
23411249Sradhika.jagtap@ARM.com    maxDependents
23511249Sradhika.jagtap@ARM.com    .name(name() + ".maxDependents")
23611249Sradhika.jagtap@ARM.com    .desc("Max number of dependents observed on a node")
23711249Sradhika.jagtap@ARM.com    ;
23811249Sradhika.jagtap@ARM.com
23911249Sradhika.jagtap@ARM.com    maxReadyListSize
24011249Sradhika.jagtap@ARM.com    .name(name() + ".maxReadyListSize")
24111249Sradhika.jagtap@ARM.com    .desc("Max size of the ready list observed")
24211249Sradhika.jagtap@ARM.com    ;
24311249Sradhika.jagtap@ARM.com
24411249Sradhika.jagtap@ARM.com    numSendAttempted
24511249Sradhika.jagtap@ARM.com    .name(name() + ".numSendAttempted")
24611249Sradhika.jagtap@ARM.com    .desc("Number of first attempts to send a request")
24711249Sradhika.jagtap@ARM.com    ;
24811249Sradhika.jagtap@ARM.com
24911249Sradhika.jagtap@ARM.com    numSendSucceeded
25011249Sradhika.jagtap@ARM.com    .name(name() + ".numSendSucceeded")
25111249Sradhika.jagtap@ARM.com    .desc("Number of successful first attempts")
25211249Sradhika.jagtap@ARM.com    ;
25311249Sradhika.jagtap@ARM.com
25411249Sradhika.jagtap@ARM.com    numSendFailed
25511249Sradhika.jagtap@ARM.com    .name(name() + ".numSendFailed")
25611249Sradhika.jagtap@ARM.com    .desc("Number of failed first attempts")
25711249Sradhika.jagtap@ARM.com    ;
25811249Sradhika.jagtap@ARM.com
25911249Sradhika.jagtap@ARM.com    numRetrySucceeded
26011249Sradhika.jagtap@ARM.com    .name(name() + ".numRetrySucceeded")
26111249Sradhika.jagtap@ARM.com    .desc("Number of successful retries")
26211249Sradhika.jagtap@ARM.com    ;
26311249Sradhika.jagtap@ARM.com
26411249Sradhika.jagtap@ARM.com    numSplitReqs
26511249Sradhika.jagtap@ARM.com    .name(name() + ".numSplitReqs")
26611249Sradhika.jagtap@ARM.com    .desc("Number of split requests")
26711249Sradhika.jagtap@ARM.com    ;
26811249Sradhika.jagtap@ARM.com
26911249Sradhika.jagtap@ARM.com    numSOLoads
27011249Sradhika.jagtap@ARM.com    .name(name() + ".numSOLoads")
27111249Sradhika.jagtap@ARM.com    .desc("Number of strictly ordered loads")
27211249Sradhika.jagtap@ARM.com    ;
27311249Sradhika.jagtap@ARM.com
27411249Sradhika.jagtap@ARM.com    numSOStores
27511249Sradhika.jagtap@ARM.com    .name(name() + ".numSOStores")
27611249Sradhika.jagtap@ARM.com    .desc("Number of strictly ordered stores")
27711249Sradhika.jagtap@ARM.com    ;
27811249Sradhika.jagtap@ARM.com
27911249Sradhika.jagtap@ARM.com    dataLastTick
28011249Sradhika.jagtap@ARM.com    .name(name() + ".dataLastTick")
28111249Sradhika.jagtap@ARM.com    .desc("Last tick simulated from the elastic data trace")
28211249Sradhika.jagtap@ARM.com    ;
28311249Sradhika.jagtap@ARM.com}
28411249Sradhika.jagtap@ARM.com
28511249Sradhika.jagtap@ARM.comTick
28611249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::init()
28711249Sradhika.jagtap@ARM.com{
28811249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUData, "Initializing data memory request generator "
28911249Sradhika.jagtap@ARM.com            "DcacheGen: elastic issue with retry.\n");
29011249Sradhika.jagtap@ARM.com
29111249Sradhika.jagtap@ARM.com    if (!readNextWindow())
29211249Sradhika.jagtap@ARM.com        panic("Trace has %d elements. It must have at least %d elements.\n",
29311249Sradhika.jagtap@ARM.com              depGraph.size(), 2 * windowSize);
29411249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUData, "After 1st read, depGraph size:%d.\n",
29511249Sradhika.jagtap@ARM.com            depGraph.size());
29611249Sradhika.jagtap@ARM.com
29711249Sradhika.jagtap@ARM.com    if (!readNextWindow())
29811249Sradhika.jagtap@ARM.com        panic("Trace has %d elements. It must have at least %d elements.\n",
29911249Sradhika.jagtap@ARM.com              depGraph.size(), 2 * windowSize);
30011249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUData, "After 2st read, depGraph size:%d.\n",
30111249Sradhika.jagtap@ARM.com            depGraph.size());
30211249Sradhika.jagtap@ARM.com
30311249Sradhika.jagtap@ARM.com    // Print readyList
30411249Sradhika.jagtap@ARM.com    if (DTRACE(TraceCPUData)) {
30511249Sradhika.jagtap@ARM.com        printReadyList();
30611249Sradhika.jagtap@ARM.com    }
30711249Sradhika.jagtap@ARM.com    auto free_itr = readyList.begin();
30811249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUData, "Execute tick of the first dependency free node %lli"
30911249Sradhika.jagtap@ARM.com            " is %d.\n", free_itr->seqNum, free_itr->execTick);
31011249Sradhika.jagtap@ARM.com    // Return the execute tick of the earliest ready node so that an event
31111249Sradhika.jagtap@ARM.com    // can be scheduled to call execute()
31211249Sradhika.jagtap@ARM.com    return (free_itr->execTick);
31311249Sradhika.jagtap@ARM.com}
31411249Sradhika.jagtap@ARM.com
31511249Sradhika.jagtap@ARM.comvoid
31611249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::exit()
31711249Sradhika.jagtap@ARM.com{
31811249Sradhika.jagtap@ARM.com    trace.reset();
31911249Sradhika.jagtap@ARM.com}
32011249Sradhika.jagtap@ARM.com
32111249Sradhika.jagtap@ARM.combool
32211249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::readNextWindow()
32311249Sradhika.jagtap@ARM.com{
32411249Sradhika.jagtap@ARM.com
32511249Sradhika.jagtap@ARM.com    // Read and add next window
32611249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUData, "Reading next window from file.\n");
32711249Sradhika.jagtap@ARM.com
32811249Sradhika.jagtap@ARM.com    if (traceComplete) {
32911249Sradhika.jagtap@ARM.com        // We are at the end of the file, thus we have no more records.
33011249Sradhika.jagtap@ARM.com        // Return false.
33111249Sradhika.jagtap@ARM.com        return false;
33211249Sradhika.jagtap@ARM.com    }
33311249Sradhika.jagtap@ARM.com
33411249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUData, "Start read: Size of depGraph is %d.\n",
33511249Sradhika.jagtap@ARM.com            depGraph.size());
33611249Sradhika.jagtap@ARM.com
33711249Sradhika.jagtap@ARM.com    uint32_t num_read = 0;
33811249Sradhika.jagtap@ARM.com    while (num_read != windowSize) {
33911249Sradhika.jagtap@ARM.com
34011249Sradhika.jagtap@ARM.com        // Create a new graph node
34111249Sradhika.jagtap@ARM.com        GraphNode* new_node = new GraphNode;
34211249Sradhika.jagtap@ARM.com
34311249Sradhika.jagtap@ARM.com        // Read the next line to get the next record. If that fails then end of
34411249Sradhika.jagtap@ARM.com        // trace has been reached and traceComplete needs to be set in addition
34511249Sradhika.jagtap@ARM.com        // to returning false.
34611249Sradhika.jagtap@ARM.com        if (!trace.read(new_node)) {
34711249Sradhika.jagtap@ARM.com            DPRINTF(TraceCPUData, "\tTrace complete!\n");
34811249Sradhika.jagtap@ARM.com            traceComplete = true;
34911249Sradhika.jagtap@ARM.com            return false;
35011249Sradhika.jagtap@ARM.com        }
35111249Sradhika.jagtap@ARM.com
35211249Sradhika.jagtap@ARM.com        // Annotate the ROB dependencies of the new node onto the parent nodes.
35311249Sradhika.jagtap@ARM.com        addDepsOnParent(new_node, new_node->robDep, new_node->numRobDep);
35411249Sradhika.jagtap@ARM.com        // Annotate the register dependencies of the new node onto the parent
35511249Sradhika.jagtap@ARM.com        // nodes.
35611249Sradhika.jagtap@ARM.com        addDepsOnParent(new_node, new_node->regDep, new_node->numRegDep);
35711249Sradhika.jagtap@ARM.com
35811249Sradhika.jagtap@ARM.com        num_read++;
35911249Sradhika.jagtap@ARM.com        // Add to map
36011249Sradhika.jagtap@ARM.com        depGraph[new_node->seqNum] = new_node;
36111249Sradhika.jagtap@ARM.com        if (new_node->numRobDep == 0 && new_node->numRegDep == 0) {
36211249Sradhika.jagtap@ARM.com            // Source dependencies are already complete, check if resources
36311249Sradhika.jagtap@ARM.com            // are available and issue. The execution time is approximated
36411249Sradhika.jagtap@ARM.com            // to current time plus the computational delay.
36511249Sradhika.jagtap@ARM.com            checkAndIssue(new_node);
36611249Sradhika.jagtap@ARM.com        }
36711249Sradhika.jagtap@ARM.com    }
36811249Sradhika.jagtap@ARM.com
36911249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUData, "End read: Size of depGraph is %d.\n",
37011249Sradhika.jagtap@ARM.com            depGraph.size());
37111249Sradhika.jagtap@ARM.com    return true;
37211249Sradhika.jagtap@ARM.com}
37311249Sradhika.jagtap@ARM.com
37411249Sradhika.jagtap@ARM.comtemplate<typename T> void
37511249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::addDepsOnParent(GraphNode *new_node,
37611249Sradhika.jagtap@ARM.com                                            T& dep_array, uint8_t& num_dep)
37711249Sradhika.jagtap@ARM.com{
37811249Sradhika.jagtap@ARM.com    for (auto& a_dep : dep_array) {
37911249Sradhika.jagtap@ARM.com        // The convention is to set the dependencies starting with the first
38011249Sradhika.jagtap@ARM.com        // index in the ROB and register dependency arrays. Thus, when we reach
38111249Sradhika.jagtap@ARM.com        // a dependency equal to the initialisation value of zero, we know have
38211249Sradhika.jagtap@ARM.com        // iterated over all dependencies and can break.
38311249Sradhika.jagtap@ARM.com        if (a_dep == 0)
38411249Sradhika.jagtap@ARM.com            break;
38511249Sradhika.jagtap@ARM.com        // We look up the valid dependency, i.e. the parent of this node
38611249Sradhika.jagtap@ARM.com        auto parent_itr = depGraph.find(a_dep);
38711249Sradhika.jagtap@ARM.com        if (parent_itr != depGraph.end()) {
38811249Sradhika.jagtap@ARM.com            // If the parent is found, it is yet to be executed. Append a
38911249Sradhika.jagtap@ARM.com            // pointer to the new node to the dependents list of the parent
39011249Sradhika.jagtap@ARM.com            // node.
39111249Sradhika.jagtap@ARM.com            parent_itr->second->dependents.push_back(new_node);
39211249Sradhika.jagtap@ARM.com            auto num_depts = parent_itr->second->dependents.size();
39311249Sradhika.jagtap@ARM.com            maxDependents = std::max<double>(num_depts, maxDependents.value());
39411249Sradhika.jagtap@ARM.com        } else {
39511249Sradhika.jagtap@ARM.com            // The dependency is not found in the graph. So consider
39611249Sradhika.jagtap@ARM.com            // the execution of the parent is complete, i.e. remove this
39711249Sradhika.jagtap@ARM.com            // dependency.
39811249Sradhika.jagtap@ARM.com            a_dep = 0;
39911249Sradhika.jagtap@ARM.com            num_dep--;
40011249Sradhika.jagtap@ARM.com        }
40111249Sradhika.jagtap@ARM.com    }
40211249Sradhika.jagtap@ARM.com}
40311249Sradhika.jagtap@ARM.com
40411249Sradhika.jagtap@ARM.comvoid
40511249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::execute()
40611249Sradhika.jagtap@ARM.com{
40711249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUData, "Execute start occupancy:\n");
40811249Sradhika.jagtap@ARM.com    DPRINTFR(TraceCPUData, "\tdepGraph = %d, readyList = %d, "
40911249Sradhika.jagtap@ARM.com            "depFreeQueue = %d ,", depGraph.size(), readyList.size(),
41011249Sradhika.jagtap@ARM.com            depFreeQueue.size());
41111249Sradhika.jagtap@ARM.com    hwResource.printOccupancy();
41211249Sradhika.jagtap@ARM.com
41311249Sradhika.jagtap@ARM.com    // Read next window to make sure that dependents of all dep-free nodes
41411249Sradhika.jagtap@ARM.com    // are in the depGraph
41511249Sradhika.jagtap@ARM.com    if (nextRead) {
41611249Sradhika.jagtap@ARM.com        readNextWindow();
41711249Sradhika.jagtap@ARM.com        nextRead = false;
41811249Sradhika.jagtap@ARM.com    }
41911249Sradhika.jagtap@ARM.com
42011249Sradhika.jagtap@ARM.com    // First attempt to issue the pending dependency-free nodes held
42111249Sradhika.jagtap@ARM.com    // in depFreeQueue. If resources have become available for a node,
42211249Sradhika.jagtap@ARM.com    // then issue it, i.e. add the node to readyList.
42311249Sradhika.jagtap@ARM.com    while (!depFreeQueue.empty()) {
42411249Sradhika.jagtap@ARM.com        if (checkAndIssue(depFreeQueue.front(), false)) {
42511249Sradhika.jagtap@ARM.com            DPRINTF(TraceCPUData, "Removing from depFreeQueue: seq. num "
42611249Sradhika.jagtap@ARM.com                "%lli.\n", (depFreeQueue.front())->seqNum);
42711249Sradhika.jagtap@ARM.com            depFreeQueue.pop();
42811249Sradhika.jagtap@ARM.com        } else {
42911249Sradhika.jagtap@ARM.com            break;
43011249Sradhika.jagtap@ARM.com        }
43111249Sradhika.jagtap@ARM.com    }
43211249Sradhika.jagtap@ARM.com    // Proceed to execute from readyList
43311249Sradhika.jagtap@ARM.com    auto graph_itr = depGraph.begin();
43411249Sradhika.jagtap@ARM.com    auto free_itr = readyList.begin();
43511249Sradhika.jagtap@ARM.com    // Iterate through readyList until the next free node has its execute
43611249Sradhika.jagtap@ARM.com    // tick later than curTick or the end of readyList is reached
43711249Sradhika.jagtap@ARM.com    while (free_itr->execTick <= curTick() && free_itr != readyList.end()) {
43811249Sradhika.jagtap@ARM.com
43911249Sradhika.jagtap@ARM.com        // Get pointer to the node to be executed
44011249Sradhika.jagtap@ARM.com        graph_itr = depGraph.find(free_itr->seqNum);
44111249Sradhika.jagtap@ARM.com        assert(graph_itr != depGraph.end());
44211249Sradhika.jagtap@ARM.com        GraphNode* node_ptr = graph_itr->second;
44311249Sradhika.jagtap@ARM.com
44411249Sradhika.jagtap@ARM.com        // If there is a retryPkt send that else execute the load
44511249Sradhika.jagtap@ARM.com        if (retryPkt) {
44611249Sradhika.jagtap@ARM.com            // The retryPkt must be the request that was created by the
44711249Sradhika.jagtap@ARM.com            // first node in the readyList.
44811249Sradhika.jagtap@ARM.com            if (retryPkt->req->getReqInstSeqNum() != node_ptr->seqNum) {
44911249Sradhika.jagtap@ARM.com                panic("Retry packet's seqence number does not match "
45011249Sradhika.jagtap@ARM.com                      "the first node in the readyList.\n");
45111249Sradhika.jagtap@ARM.com            }
45211249Sradhika.jagtap@ARM.com            if (port.sendTimingReq(retryPkt)) {
45311249Sradhika.jagtap@ARM.com                ++numRetrySucceeded;
45411249Sradhika.jagtap@ARM.com                retryPkt = nullptr;
45511249Sradhika.jagtap@ARM.com            }
45611252Sradhika.jagtap@ARM.com        } else if (node_ptr->isLoad() || node_ptr->isStore()) {
45711249Sradhika.jagtap@ARM.com            // If there is no retryPkt, attempt to send a memory request in
45811249Sradhika.jagtap@ARM.com            // case of a load or store node. If the send fails, executeMemReq()
45911249Sradhika.jagtap@ARM.com            // returns a packet pointer, which we save in retryPkt. In case of
46011249Sradhika.jagtap@ARM.com            // a comp node we don't do anything and simply continue as if the
46111249Sradhika.jagtap@ARM.com            // execution of the comp node succedded.
46211249Sradhika.jagtap@ARM.com            retryPkt = executeMemReq(node_ptr);
46311249Sradhika.jagtap@ARM.com        }
46411249Sradhika.jagtap@ARM.com        // If the retryPkt or a new load/store node failed, we exit from here
46511249Sradhika.jagtap@ARM.com        // as a retry from cache will bring the control to execute(). The
46611249Sradhika.jagtap@ARM.com        // first node in readyList then, will be the failed node.
46711249Sradhika.jagtap@ARM.com        if (retryPkt) {
46811249Sradhika.jagtap@ARM.com            break;
46911249Sradhika.jagtap@ARM.com        }
47011249Sradhika.jagtap@ARM.com
47111249Sradhika.jagtap@ARM.com        // Proceed to remove dependencies for the successfully executed node.
47211249Sradhika.jagtap@ARM.com        // If it is a load which is not strictly ordered and we sent a
47311249Sradhika.jagtap@ARM.com        // request for it successfully, we do not yet mark any register
47411249Sradhika.jagtap@ARM.com        // dependencies complete. But as per dependency modelling we need
47511249Sradhika.jagtap@ARM.com        // to mark ROB dependencies of load and non load/store nodes which
47611249Sradhika.jagtap@ARM.com        // are based on successful sending of the load as complete.
47711252Sradhika.jagtap@ARM.com        if (node_ptr->isLoad() && !node_ptr->isStrictlyOrdered()) {
47811249Sradhika.jagtap@ARM.com            // If execute succeeded mark its dependents as complete
47911249Sradhika.jagtap@ARM.com            DPRINTF(TraceCPUData, "Node seq. num %lli sent. Waking up "
48011249Sradhika.jagtap@ARM.com                    "dependents..\n", node_ptr->seqNum);
48111249Sradhika.jagtap@ARM.com
48211249Sradhika.jagtap@ARM.com            auto child_itr = (node_ptr->dependents).begin();
48311249Sradhika.jagtap@ARM.com            while (child_itr != (node_ptr->dependents).end()) {
48411249Sradhika.jagtap@ARM.com                // ROB dependency of a store on a load must not be removed
48511249Sradhika.jagtap@ARM.com                // after load is sent but after response is received
48611252Sradhika.jagtap@ARM.com                if (!(*child_itr)->isStore() &&
48711249Sradhika.jagtap@ARM.com                    (*child_itr)->removeRobDep(node_ptr->seqNum)) {
48811249Sradhika.jagtap@ARM.com
48911249Sradhika.jagtap@ARM.com                    // Check if the child node has become dependency free
49011249Sradhika.jagtap@ARM.com                    if ((*child_itr)->numRobDep == 0 &&
49111249Sradhika.jagtap@ARM.com                        (*child_itr)->numRegDep == 0) {
49211249Sradhika.jagtap@ARM.com
49311249Sradhika.jagtap@ARM.com                        // Source dependencies are complete, check if
49411249Sradhika.jagtap@ARM.com                        // resources are available and issue
49511249Sradhika.jagtap@ARM.com                        checkAndIssue(*child_itr);
49611249Sradhika.jagtap@ARM.com                    }
49711249Sradhika.jagtap@ARM.com                    // Remove this child for the sent load and point to new
49811249Sradhika.jagtap@ARM.com                    // location of the element following the erased element
49911249Sradhika.jagtap@ARM.com                    child_itr = node_ptr->dependents.erase(child_itr);
50011249Sradhika.jagtap@ARM.com                } else {
50111249Sradhika.jagtap@ARM.com                    // This child is not dependency-free, point to the next
50211249Sradhika.jagtap@ARM.com                    // child
50311249Sradhika.jagtap@ARM.com                    child_itr++;
50411249Sradhika.jagtap@ARM.com                }
50511249Sradhika.jagtap@ARM.com            }
50611249Sradhika.jagtap@ARM.com        } else {
50711249Sradhika.jagtap@ARM.com            // If it is a strictly ordered load mark its dependents as complete
50811249Sradhika.jagtap@ARM.com            // as we do not send a request for this case. If it is a store or a
50911249Sradhika.jagtap@ARM.com            // comp node we also mark all its dependents complete.
51011249Sradhika.jagtap@ARM.com            DPRINTF(TraceCPUData, "Node seq. num %lli done. Waking"
51111249Sradhika.jagtap@ARM.com                    " up dependents..\n", node_ptr->seqNum);
51211249Sradhika.jagtap@ARM.com
51311249Sradhika.jagtap@ARM.com            for (auto child : node_ptr->dependents) {
51411249Sradhika.jagtap@ARM.com                // If the child node is dependency free removeDepOnInst()
51511249Sradhika.jagtap@ARM.com                // returns true.
51611249Sradhika.jagtap@ARM.com                if (child->removeDepOnInst(node_ptr->seqNum)) {
51711249Sradhika.jagtap@ARM.com                    // Source dependencies are complete, check if resources
51811249Sradhika.jagtap@ARM.com                    // are available and issue
51911249Sradhika.jagtap@ARM.com                    checkAndIssue(child);
52011249Sradhika.jagtap@ARM.com                }
52111249Sradhika.jagtap@ARM.com            }
52211249Sradhika.jagtap@ARM.com        }
52311249Sradhika.jagtap@ARM.com
52411249Sradhika.jagtap@ARM.com        // After executing the node, remove from readyList and delete node.
52511249Sradhika.jagtap@ARM.com        readyList.erase(free_itr);
52611249Sradhika.jagtap@ARM.com        // If it is a cacheable load which was sent, don't delete
52711249Sradhika.jagtap@ARM.com        // just yet.  Delete it in completeMemAccess() after the
52811249Sradhika.jagtap@ARM.com        // response is received. If it is an strictly ordered
52911249Sradhika.jagtap@ARM.com        // load, it was not sent and all dependencies were simply
53011249Sradhika.jagtap@ARM.com        // marked complete. Thus it is safe to delete it. For
53111249Sradhika.jagtap@ARM.com        // stores and non load/store nodes all dependencies were
53211249Sradhika.jagtap@ARM.com        // marked complete so it is safe to delete it.
53311252Sradhika.jagtap@ARM.com        if (!node_ptr->isLoad() || node_ptr->isStrictlyOrdered()) {
53411249Sradhika.jagtap@ARM.com            // Release all resources occupied by the completed node
53511249Sradhika.jagtap@ARM.com            hwResource.release(node_ptr);
53611249Sradhika.jagtap@ARM.com            // clear the dynamically allocated set of dependents
53711249Sradhika.jagtap@ARM.com            (node_ptr->dependents).clear();
53811249Sradhika.jagtap@ARM.com            // delete node
53911249Sradhika.jagtap@ARM.com            delete node_ptr;
54011249Sradhika.jagtap@ARM.com            // remove from graph
54111249Sradhika.jagtap@ARM.com            depGraph.erase(graph_itr);
54211249Sradhika.jagtap@ARM.com        }
54311249Sradhika.jagtap@ARM.com        // Point to first node to continue to next iteration of while loop
54411249Sradhika.jagtap@ARM.com        free_itr = readyList.begin();
54511249Sradhika.jagtap@ARM.com    } // end of while loop
54611249Sradhika.jagtap@ARM.com
54711249Sradhika.jagtap@ARM.com    // Print readyList, sizes of queues and resource status after updating
54811249Sradhika.jagtap@ARM.com    if (DTRACE(TraceCPUData)) {
54911249Sradhika.jagtap@ARM.com        printReadyList();
55011249Sradhika.jagtap@ARM.com        DPRINTF(TraceCPUData, "Execute end occupancy:\n");
55111249Sradhika.jagtap@ARM.com        DPRINTFR(TraceCPUData, "\tdepGraph = %d, readyList = %d, "
55211249Sradhika.jagtap@ARM.com                "depFreeQueue = %d ,", depGraph.size(), readyList.size(),
55311249Sradhika.jagtap@ARM.com                depFreeQueue.size());
55411249Sradhika.jagtap@ARM.com        hwResource.printOccupancy();
55511249Sradhika.jagtap@ARM.com    }
55611249Sradhika.jagtap@ARM.com
55711249Sradhika.jagtap@ARM.com    if (retryPkt) {
55811249Sradhika.jagtap@ARM.com        DPRINTF(TraceCPUData, "Not scheduling an event as expecting a retry"
55911249Sradhika.jagtap@ARM.com                "event from the cache for seq. num %lli.\n",
56011249Sradhika.jagtap@ARM.com                retryPkt->req->getReqInstSeqNum());
56111249Sradhika.jagtap@ARM.com        return;
56211249Sradhika.jagtap@ARM.com    }
56311249Sradhika.jagtap@ARM.com    // If the size of the dependency graph is less than the dependency window
56411249Sradhika.jagtap@ARM.com    // then read from the trace file to populate the graph next time we are in
56511249Sradhika.jagtap@ARM.com    // execute.
56611249Sradhika.jagtap@ARM.com    if (depGraph.size() < windowSize && !traceComplete)
56711249Sradhika.jagtap@ARM.com        nextRead = true;
56811249Sradhika.jagtap@ARM.com
56911249Sradhika.jagtap@ARM.com    // If cache is not blocked, schedule an event for the first execTick in
57011249Sradhika.jagtap@ARM.com    // readyList else retry from cache will schedule the event. If the ready
57111249Sradhika.jagtap@ARM.com    // list is empty then check if the next pending node has resources
57211249Sradhika.jagtap@ARM.com    // available to issue. If yes, then schedule an event for the next cycle.
57311249Sradhika.jagtap@ARM.com    if (!readyList.empty()) {
57411249Sradhika.jagtap@ARM.com        Tick next_event_tick = std::max(readyList.begin()->execTick,
57511249Sradhika.jagtap@ARM.com                                        curTick());
57611249Sradhika.jagtap@ARM.com        DPRINTF(TraceCPUData, "Attempting to schedule @%lli.\n",
57711249Sradhika.jagtap@ARM.com                next_event_tick);
57811249Sradhika.jagtap@ARM.com        owner.schedDcacheNextEvent(next_event_tick);
57911249Sradhika.jagtap@ARM.com    } else if (readyList.empty() && !depFreeQueue.empty() &&
58011249Sradhika.jagtap@ARM.com                hwResource.isAvailable(depFreeQueue.front())) {
58111249Sradhika.jagtap@ARM.com        DPRINTF(TraceCPUData, "Attempting to schedule @%lli.\n",
58211249Sradhika.jagtap@ARM.com                owner.clockEdge(Cycles(1)));
58311249Sradhika.jagtap@ARM.com        owner.schedDcacheNextEvent(owner.clockEdge(Cycles(1)));
58411249Sradhika.jagtap@ARM.com    }
58511249Sradhika.jagtap@ARM.com
58611249Sradhika.jagtap@ARM.com    // If trace is completely read, readyList is empty and depGraph is empty,
58711249Sradhika.jagtap@ARM.com    // set execComplete to true
58811249Sradhika.jagtap@ARM.com    if (depGraph.empty() && readyList.empty() && traceComplete &&
58911249Sradhika.jagtap@ARM.com        !hwResource.awaitingResponse()) {
59011249Sradhika.jagtap@ARM.com        DPRINTF(TraceCPUData, "\tExecution Complete!\n");
59111249Sradhika.jagtap@ARM.com        execComplete = true;
59211249Sradhika.jagtap@ARM.com        dataLastTick = curTick();
59311249Sradhika.jagtap@ARM.com    }
59411249Sradhika.jagtap@ARM.com}
59511249Sradhika.jagtap@ARM.com
59611249Sradhika.jagtap@ARM.comPacketPtr
59711249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::executeMemReq(GraphNode* node_ptr)
59811249Sradhika.jagtap@ARM.com{
59911249Sradhika.jagtap@ARM.com
60011253Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUData, "Executing memory request %lli (phys addr %d, "
60111253Sradhika.jagtap@ARM.com            "virt addr %d, pc %#x, size %d, flags %d).\n",
60211253Sradhika.jagtap@ARM.com            node_ptr->seqNum, node_ptr->physAddr, node_ptr->virtAddr,
60311249Sradhika.jagtap@ARM.com            node_ptr->pc, node_ptr->size, node_ptr->flags);
60411249Sradhika.jagtap@ARM.com
60511249Sradhika.jagtap@ARM.com    // If the request is strictly ordered, do not send it. Just return nullptr
60611249Sradhika.jagtap@ARM.com    // as if it was succesfully sent.
60711249Sradhika.jagtap@ARM.com    if (node_ptr->isStrictlyOrdered()) {
60811252Sradhika.jagtap@ARM.com        node_ptr->isLoad() ? ++numSOLoads : ++numSOStores;
60911249Sradhika.jagtap@ARM.com        DPRINTF(TraceCPUData, "Skipping strictly ordered request %lli.\n",
61011249Sradhika.jagtap@ARM.com                node_ptr->seqNum);
61111249Sradhika.jagtap@ARM.com        return nullptr;
61211249Sradhika.jagtap@ARM.com    }
61311249Sradhika.jagtap@ARM.com
61411249Sradhika.jagtap@ARM.com    // Check if the request spans two cache lines as this condition triggers
61511249Sradhika.jagtap@ARM.com    // an assert fail in the L1 cache. If it does then truncate the size to
61611249Sradhika.jagtap@ARM.com    // access only until the end of that line and ignore the remainder. The
61711249Sradhika.jagtap@ARM.com    // stat counting this is useful to keep a check on how frequently this
61811249Sradhika.jagtap@ARM.com    // happens. If required the code could be revised to mimick splitting such
61911249Sradhika.jagtap@ARM.com    // a request into two.
62011249Sradhika.jagtap@ARM.com    unsigned blk_size = owner.cacheLineSize();
62111253Sradhika.jagtap@ARM.com    Addr blk_offset = (node_ptr->physAddr & (Addr)(blk_size - 1));
62211249Sradhika.jagtap@ARM.com    if (!(blk_offset + node_ptr->size <= blk_size)) {
62311249Sradhika.jagtap@ARM.com        node_ptr->size = blk_size - blk_offset;
62411249Sradhika.jagtap@ARM.com        ++numSplitReqs;
62511249Sradhika.jagtap@ARM.com    }
62611249Sradhika.jagtap@ARM.com
62711249Sradhika.jagtap@ARM.com    // Create a request and the packet containing request
62811253Sradhika.jagtap@ARM.com    Request* req = new Request(node_ptr->physAddr, node_ptr->size,
62911253Sradhika.jagtap@ARM.com                               node_ptr->flags, masterID, node_ptr->seqNum,
63011249Sradhika.jagtap@ARM.com                               ContextID(0), ThreadID(0));
63111249Sradhika.jagtap@ARM.com    req->setPC(node_ptr->pc);
63211253Sradhika.jagtap@ARM.com    // If virtual address is valid, set the asid and virtual address fields
63311253Sradhika.jagtap@ARM.com    // of the request.
63411253Sradhika.jagtap@ARM.com    if (node_ptr->virtAddr != 0) {
63511253Sradhika.jagtap@ARM.com        req->setVirt(node_ptr->asid, node_ptr->virtAddr, node_ptr->size,
63611253Sradhika.jagtap@ARM.com                        node_ptr->flags, masterID, node_ptr->pc);
63711253Sradhika.jagtap@ARM.com        req->setPaddr(node_ptr->physAddr);
63811253Sradhika.jagtap@ARM.com        req->setReqInstSeqNum(node_ptr->seqNum);
63911253Sradhika.jagtap@ARM.com    }
64011253Sradhika.jagtap@ARM.com
64111249Sradhika.jagtap@ARM.com    PacketPtr pkt;
64211249Sradhika.jagtap@ARM.com    uint8_t* pkt_data = new uint8_t[req->getSize()];
64311252Sradhika.jagtap@ARM.com    if (node_ptr->isLoad()) {
64411249Sradhika.jagtap@ARM.com        pkt = Packet::createRead(req);
64511249Sradhika.jagtap@ARM.com    } else {
64611249Sradhika.jagtap@ARM.com        pkt = Packet::createWrite(req);
64711249Sradhika.jagtap@ARM.com        memset(pkt_data, 0xA, req->getSize());
64811249Sradhika.jagtap@ARM.com    }
64911249Sradhika.jagtap@ARM.com    pkt->dataDynamic(pkt_data);
65011249Sradhika.jagtap@ARM.com
65111249Sradhika.jagtap@ARM.com    // Call MasterPort method to send a timing request for this packet
65211249Sradhika.jagtap@ARM.com    bool success = port.sendTimingReq(pkt);
65311249Sradhika.jagtap@ARM.com    ++numSendAttempted;
65411249Sradhika.jagtap@ARM.com
65511249Sradhika.jagtap@ARM.com    if (!success) {
65611249Sradhika.jagtap@ARM.com        // If it fails, return the packet to retry when a retry is signalled by
65711249Sradhika.jagtap@ARM.com        // the cache
65811249Sradhika.jagtap@ARM.com        ++numSendFailed;
65911249Sradhika.jagtap@ARM.com        DPRINTF(TraceCPUData, "Send failed. Saving packet for retry.\n");
66011249Sradhika.jagtap@ARM.com        return pkt;
66111249Sradhika.jagtap@ARM.com    } else {
66211249Sradhika.jagtap@ARM.com        // It is succeeds, return nullptr
66311249Sradhika.jagtap@ARM.com        ++numSendSucceeded;
66411249Sradhika.jagtap@ARM.com        return nullptr;
66511249Sradhika.jagtap@ARM.com    }
66611249Sradhika.jagtap@ARM.com}
66711249Sradhika.jagtap@ARM.com
66811249Sradhika.jagtap@ARM.combool
66911249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::checkAndIssue(const GraphNode* node_ptr, bool first)
67011249Sradhika.jagtap@ARM.com{
67111249Sradhika.jagtap@ARM.com    // Assert the node is dependency-free
67211249Sradhika.jagtap@ARM.com    assert(node_ptr->numRobDep == 0 && node_ptr->numRegDep == 0);
67311249Sradhika.jagtap@ARM.com
67411249Sradhika.jagtap@ARM.com    // If this is the first attempt, print a debug message to indicate this.
67511249Sradhika.jagtap@ARM.com    if (first) {
67611249Sradhika.jagtap@ARM.com        DPRINTFR(TraceCPUData, "\t\tseq. num %lli(%s) with rob num %lli is now"
67711252Sradhika.jagtap@ARM.com            " dependency free.\n", node_ptr->seqNum, node_ptr->typeToStr(),
67811249Sradhika.jagtap@ARM.com            node_ptr->robNum);
67911249Sradhika.jagtap@ARM.com    }
68011249Sradhika.jagtap@ARM.com
68111249Sradhika.jagtap@ARM.com    // Check if resources are available to issue the specific node
68211249Sradhika.jagtap@ARM.com    if (hwResource.isAvailable(node_ptr)) {
68311249Sradhika.jagtap@ARM.com        // If resources are free only then add to readyList
68411249Sradhika.jagtap@ARM.com        DPRINTFR(TraceCPUData, "\t\tResources available for seq. num %lli. Adding"
68511249Sradhika.jagtap@ARM.com            " to readyList, occupying resources.\n", node_ptr->seqNum);
68611249Sradhika.jagtap@ARM.com        // Compute the execute tick by adding the compute delay for the node
68711249Sradhika.jagtap@ARM.com        // and add the ready node to the ready list
68811249Sradhika.jagtap@ARM.com        addToSortedReadyList(node_ptr->seqNum,
68911249Sradhika.jagtap@ARM.com                                owner.clockEdge() + node_ptr->compDelay);
69011249Sradhika.jagtap@ARM.com        // Account for the resources taken up by this issued node.
69111249Sradhika.jagtap@ARM.com        hwResource.occupy(node_ptr);
69211249Sradhika.jagtap@ARM.com        return true;
69311249Sradhika.jagtap@ARM.com
69411249Sradhika.jagtap@ARM.com    } else {
69511249Sradhika.jagtap@ARM.com        if (first) {
69611249Sradhika.jagtap@ARM.com            // Although dependencies are complete, resources are not available.
69711249Sradhika.jagtap@ARM.com            DPRINTFR(TraceCPUData, "\t\tResources unavailable for seq. num %lli."
69811249Sradhika.jagtap@ARM.com                " Adding to depFreeQueue.\n", node_ptr->seqNum);
69911249Sradhika.jagtap@ARM.com            depFreeQueue.push(node_ptr);
70011249Sradhika.jagtap@ARM.com        } else {
70111249Sradhika.jagtap@ARM.com            DPRINTFR(TraceCPUData, "\t\tResources unavailable for seq. num %lli. "
70211249Sradhika.jagtap@ARM.com                "Still pending issue.\n", node_ptr->seqNum);
70311249Sradhika.jagtap@ARM.com        }
70411249Sradhika.jagtap@ARM.com        return false;
70511249Sradhika.jagtap@ARM.com    }
70611249Sradhika.jagtap@ARM.com}
70711249Sradhika.jagtap@ARM.com
70811249Sradhika.jagtap@ARM.comvoid
70911249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::completeMemAccess(PacketPtr pkt)
71011249Sradhika.jagtap@ARM.com{
71111249Sradhika.jagtap@ARM.com    // Release the resources for this completed node.
71211249Sradhika.jagtap@ARM.com    if (pkt->isWrite()) {
71311249Sradhika.jagtap@ARM.com        // Consider store complete.
71411249Sradhika.jagtap@ARM.com        hwResource.releaseStoreBuffer();
71511249Sradhika.jagtap@ARM.com        // If it is a store response then do nothing since we do not model
71611249Sradhika.jagtap@ARM.com        // dependencies on store completion in the trace. But if we were
71711249Sradhika.jagtap@ARM.com        // blocking execution due to store buffer fullness, we need to schedule
71811249Sradhika.jagtap@ARM.com        // an event and attempt to progress.
71911249Sradhika.jagtap@ARM.com    } else {
72011249Sradhika.jagtap@ARM.com        // If it is a load response then release the dependents waiting on it.
72111249Sradhika.jagtap@ARM.com        // Get pointer to the completed load
72211249Sradhika.jagtap@ARM.com        auto graph_itr = depGraph.find(pkt->req->getReqInstSeqNum());
72311249Sradhika.jagtap@ARM.com        assert(graph_itr != depGraph.end());
72411249Sradhika.jagtap@ARM.com        GraphNode* node_ptr = graph_itr->second;
72511249Sradhika.jagtap@ARM.com
72611249Sradhika.jagtap@ARM.com        // Release resources occupied by the load
72711249Sradhika.jagtap@ARM.com        hwResource.release(node_ptr);
72811249Sradhika.jagtap@ARM.com
72911249Sradhika.jagtap@ARM.com        DPRINTF(TraceCPUData, "Load seq. num %lli response received. Waking up"
73011249Sradhika.jagtap@ARM.com                " dependents..\n", node_ptr->seqNum);
73111249Sradhika.jagtap@ARM.com
73211249Sradhika.jagtap@ARM.com        for (auto child : node_ptr->dependents) {
73311249Sradhika.jagtap@ARM.com            if (child->removeDepOnInst(node_ptr->seqNum)) {
73411249Sradhika.jagtap@ARM.com                checkAndIssue(child);
73511249Sradhika.jagtap@ARM.com            }
73611249Sradhika.jagtap@ARM.com        }
73711249Sradhika.jagtap@ARM.com
73811249Sradhika.jagtap@ARM.com        // clear the dynamically allocated set of dependents
73911249Sradhika.jagtap@ARM.com        (node_ptr->dependents).clear();
74011249Sradhika.jagtap@ARM.com        // delete node
74111249Sradhika.jagtap@ARM.com        delete node_ptr;
74211249Sradhika.jagtap@ARM.com        // remove from graph
74311249Sradhika.jagtap@ARM.com        depGraph.erase(graph_itr);
74411249Sradhika.jagtap@ARM.com    }
74511249Sradhika.jagtap@ARM.com
74611249Sradhika.jagtap@ARM.com    if (DTRACE(TraceCPUData)) {
74711249Sradhika.jagtap@ARM.com        printReadyList();
74811249Sradhika.jagtap@ARM.com    }
74911249Sradhika.jagtap@ARM.com
75011249Sradhika.jagtap@ARM.com    // If the size of the dependency graph is less than the dependency window
75111249Sradhika.jagtap@ARM.com    // then read from the trace file to populate the graph next time we are in
75211249Sradhika.jagtap@ARM.com    // execute.
75311249Sradhika.jagtap@ARM.com    if (depGraph.size() < windowSize && !traceComplete)
75411249Sradhika.jagtap@ARM.com        nextRead = true;
75511249Sradhika.jagtap@ARM.com
75611249Sradhika.jagtap@ARM.com    // If not waiting for retry, attempt to schedule next event
75711249Sradhika.jagtap@ARM.com    if (!retryPkt) {
75811249Sradhika.jagtap@ARM.com        // We might have new dep-free nodes in the list which will have execute
75911249Sradhika.jagtap@ARM.com        // tick greater than or equal to curTick. But a new dep-free node might
76011249Sradhika.jagtap@ARM.com        // have its execute tick earlier. Therefore, attempt to reschedule. It
76111249Sradhika.jagtap@ARM.com        // could happen that the readyList is empty and we got here via a
76211249Sradhika.jagtap@ARM.com        // last remaining response. So, either the trace is complete or there
76311249Sradhika.jagtap@ARM.com        // are pending nodes in the depFreeQueue. The checking is done in the
76411249Sradhika.jagtap@ARM.com        // execute() control flow, so schedule an event to go via that flow.
76511249Sradhika.jagtap@ARM.com        Tick next_event_tick = readyList.empty() ? owner.clockEdge(Cycles(1)) :
76611249Sradhika.jagtap@ARM.com            std::max(readyList.begin()->execTick, owner.clockEdge(Cycles(1)));
76711249Sradhika.jagtap@ARM.com        DPRINTF(TraceCPUData, "Attempting to schedule @%lli.\n",
76811249Sradhika.jagtap@ARM.com                next_event_tick);
76911249Sradhika.jagtap@ARM.com        owner.schedDcacheNextEvent(next_event_tick);
77011249Sradhika.jagtap@ARM.com    }
77111249Sradhika.jagtap@ARM.com}
77211249Sradhika.jagtap@ARM.com
77311249Sradhika.jagtap@ARM.comvoid
77411249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::addToSortedReadyList(NodeSeqNum seq_num,
77511249Sradhika.jagtap@ARM.com                                                    Tick exec_tick)
77611249Sradhika.jagtap@ARM.com{
77711249Sradhika.jagtap@ARM.com    ReadyNode ready_node;
77811249Sradhika.jagtap@ARM.com    ready_node.seqNum = seq_num;
77911249Sradhika.jagtap@ARM.com    ready_node.execTick = exec_tick;
78011249Sradhika.jagtap@ARM.com
78111249Sradhika.jagtap@ARM.com    // Iterator to readyList
78211249Sradhika.jagtap@ARM.com    auto itr = readyList.begin();
78311249Sradhika.jagtap@ARM.com
78411249Sradhika.jagtap@ARM.com    // If the readyList is empty, simply insert the new node at the beginning
78511249Sradhika.jagtap@ARM.com    // and return
78611249Sradhika.jagtap@ARM.com    if (itr == readyList.end()) {
78711249Sradhika.jagtap@ARM.com        readyList.insert(itr, ready_node);
78811249Sradhika.jagtap@ARM.com        maxReadyListSize = std::max<double>(readyList.size(),
78911249Sradhika.jagtap@ARM.com                                              maxReadyListSize.value());
79011249Sradhika.jagtap@ARM.com        return;
79111249Sradhika.jagtap@ARM.com    }
79211249Sradhika.jagtap@ARM.com
79311249Sradhika.jagtap@ARM.com    // If the new node has its execution tick equal to the first node in the
79411249Sradhika.jagtap@ARM.com    // list then go to the next node. If the first node in the list failed
79511249Sradhika.jagtap@ARM.com    // to execute, its position as the first is thus maintained.
79611249Sradhika.jagtap@ARM.com    if (retryPkt)
79711249Sradhika.jagtap@ARM.com        if (retryPkt->req->getReqInstSeqNum() == itr->seqNum)
79811249Sradhika.jagtap@ARM.com            itr++;
79911249Sradhika.jagtap@ARM.com
80011249Sradhika.jagtap@ARM.com    // Increment the iterator and compare the node pointed to by it to the new
80111249Sradhika.jagtap@ARM.com    // node till the position to insert the new node is found.
80211249Sradhika.jagtap@ARM.com    bool found = false;
80311249Sradhika.jagtap@ARM.com    while (!found && itr != readyList.end()) {
80411249Sradhika.jagtap@ARM.com        // If the execution tick of the new node is less than the node then
80511249Sradhika.jagtap@ARM.com        // this is the position to insert
80611249Sradhika.jagtap@ARM.com        if (exec_tick < itr->execTick)
80711249Sradhika.jagtap@ARM.com            found = true;
80811249Sradhika.jagtap@ARM.com        // If the execution tick of the new node is equal to the node then
80911249Sradhika.jagtap@ARM.com        // sort in ascending order of sequence numbers
81011249Sradhika.jagtap@ARM.com        else if (exec_tick == itr->execTick) {
81111249Sradhika.jagtap@ARM.com            // If the sequence number of the new node is less than the node
81211249Sradhika.jagtap@ARM.com            // then this is the position to insert
81311249Sradhika.jagtap@ARM.com            if (seq_num < itr->seqNum)
81411249Sradhika.jagtap@ARM.com                found = true;
81511249Sradhika.jagtap@ARM.com            // Else go to next node
81611249Sradhika.jagtap@ARM.com            else
81711249Sradhika.jagtap@ARM.com                itr++;
81811249Sradhika.jagtap@ARM.com        }
81911249Sradhika.jagtap@ARM.com        // If the execution tick of the new node is greater than the node then
82011249Sradhika.jagtap@ARM.com        // go to the next node
82111249Sradhika.jagtap@ARM.com        else
82211249Sradhika.jagtap@ARM.com            itr++;
82311249Sradhika.jagtap@ARM.com    }
82411249Sradhika.jagtap@ARM.com    readyList.insert(itr, ready_node);
82511249Sradhika.jagtap@ARM.com    // Update the stat for max size reached of the readyList
82611249Sradhika.jagtap@ARM.com    maxReadyListSize = std::max<double>(readyList.size(),
82711249Sradhika.jagtap@ARM.com                                          maxReadyListSize.value());
82811249Sradhika.jagtap@ARM.com}
82911249Sradhika.jagtap@ARM.com
83011249Sradhika.jagtap@ARM.comvoid
83111249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::printReadyList() {
83211249Sradhika.jagtap@ARM.com
83311249Sradhika.jagtap@ARM.com    auto itr = readyList.begin();
83411249Sradhika.jagtap@ARM.com    if (itr == readyList.end()) {
83511249Sradhika.jagtap@ARM.com        DPRINTF(TraceCPUData, "readyList is empty.\n");
83611249Sradhika.jagtap@ARM.com        return;
83711249Sradhika.jagtap@ARM.com    }
83811249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUData, "Printing readyList:\n");
83911249Sradhika.jagtap@ARM.com    while (itr != readyList.end()) {
84011249Sradhika.jagtap@ARM.com        auto graph_itr = depGraph.find(itr->seqNum);
84111249Sradhika.jagtap@ARM.com        GraphNode* node_ptr M5_VAR_USED = graph_itr->second;
84211249Sradhika.jagtap@ARM.com        DPRINTFR(TraceCPUData, "\t%lld(%s), %lld\n", itr->seqNum,
84311252Sradhika.jagtap@ARM.com            node_ptr->typeToStr(), itr->execTick);
84411249Sradhika.jagtap@ARM.com        itr++;
84511249Sradhika.jagtap@ARM.com    }
84611249Sradhika.jagtap@ARM.com}
84711249Sradhika.jagtap@ARM.com
84811249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::HardwareResource::HardwareResource(
84911249Sradhika.jagtap@ARM.com    uint16_t max_rob, uint16_t max_stores, uint16_t max_loads)
85011249Sradhika.jagtap@ARM.com  : sizeROB(max_rob),
85111249Sradhika.jagtap@ARM.com    sizeStoreBuffer(max_stores),
85211249Sradhika.jagtap@ARM.com    sizeLoadBuffer(max_loads),
85311249Sradhika.jagtap@ARM.com    oldestInFlightRobNum(UINT64_MAX),
85411249Sradhika.jagtap@ARM.com    numInFlightLoads(0),
85511249Sradhika.jagtap@ARM.com    numInFlightStores(0)
85611249Sradhika.jagtap@ARM.com{}
85711249Sradhika.jagtap@ARM.com
85811249Sradhika.jagtap@ARM.comvoid
85911249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::HardwareResource::occupy(const GraphNode* new_node)
86011249Sradhika.jagtap@ARM.com{
86111249Sradhika.jagtap@ARM.com    // Occupy ROB entry for the issued node
86211249Sradhika.jagtap@ARM.com    // Merely maintain the oldest node, i.e. numerically least robNum by saving
86311249Sradhika.jagtap@ARM.com    // it in the variable oldestInFLightRobNum.
86411249Sradhika.jagtap@ARM.com    inFlightNodes[new_node->seqNum] = new_node->robNum;
86511249Sradhika.jagtap@ARM.com    oldestInFlightRobNum = inFlightNodes.begin()->second;
86611249Sradhika.jagtap@ARM.com
86711249Sradhika.jagtap@ARM.com    // Occupy Load/Store Buffer entry for the issued node if applicable
86811252Sradhika.jagtap@ARM.com    if (new_node->isLoad()) {
86911249Sradhika.jagtap@ARM.com        ++numInFlightLoads;
87011252Sradhika.jagtap@ARM.com    } else if (new_node->isStore()) {
87111249Sradhika.jagtap@ARM.com        ++numInFlightStores;
87211249Sradhika.jagtap@ARM.com    } // else if it is a non load/store node, no buffer entry is occupied
87311249Sradhika.jagtap@ARM.com
87411249Sradhika.jagtap@ARM.com    printOccupancy();
87511249Sradhika.jagtap@ARM.com}
87611249Sradhika.jagtap@ARM.com
87711249Sradhika.jagtap@ARM.comvoid
87811249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::HardwareResource::release(const GraphNode* done_node)
87911249Sradhika.jagtap@ARM.com{
88011249Sradhika.jagtap@ARM.com    assert(!inFlightNodes.empty());
88111249Sradhika.jagtap@ARM.com    DPRINTFR(TraceCPUData, "\tClearing done seq. num %d from inFlightNodes..\n",
88211249Sradhika.jagtap@ARM.com        done_node->seqNum);
88311249Sradhika.jagtap@ARM.com
88411249Sradhika.jagtap@ARM.com    assert(inFlightNodes.find(done_node->seqNum) != inFlightNodes.end());
88511249Sradhika.jagtap@ARM.com    inFlightNodes.erase(done_node->seqNum);
88611249Sradhika.jagtap@ARM.com
88711249Sradhika.jagtap@ARM.com    if (inFlightNodes.empty()) {
88811249Sradhika.jagtap@ARM.com        // If we delete the only in-flight node and then the
88911249Sradhika.jagtap@ARM.com        // oldestInFlightRobNum is set to it's initialized (max) value.
89011249Sradhika.jagtap@ARM.com        oldestInFlightRobNum = UINT64_MAX;
89111249Sradhika.jagtap@ARM.com    } else {
89211249Sradhika.jagtap@ARM.com        // Set the oldest in-flight node rob number equal to the first node in
89311249Sradhika.jagtap@ARM.com        // the inFlightNodes since that will have the numerically least value.
89411249Sradhika.jagtap@ARM.com        oldestInFlightRobNum = inFlightNodes.begin()->second;
89511249Sradhika.jagtap@ARM.com    }
89611249Sradhika.jagtap@ARM.com
89711249Sradhika.jagtap@ARM.com    DPRINTFR(TraceCPUData, "\tCleared. inFlightNodes.size() = %d, "
89811249Sradhika.jagtap@ARM.com        "oldestInFlightRobNum = %d\n", inFlightNodes.size(),
89911249Sradhika.jagtap@ARM.com        oldestInFlightRobNum);
90011249Sradhika.jagtap@ARM.com
90111249Sradhika.jagtap@ARM.com    // A store is considered complete when a request is sent, thus ROB entry is
90211249Sradhika.jagtap@ARM.com    // freed. But it occupies an entry in the Store Buffer until its response
90311249Sradhika.jagtap@ARM.com    // is received. A load is considered complete when a response is received,
90411249Sradhika.jagtap@ARM.com    // thus both ROB and Load Buffer entries can be released.
90511252Sradhika.jagtap@ARM.com    if (done_node->isLoad()) {
90611249Sradhika.jagtap@ARM.com        assert(numInFlightLoads != 0);
90711249Sradhika.jagtap@ARM.com        --numInFlightLoads;
90811249Sradhika.jagtap@ARM.com    }
90911249Sradhika.jagtap@ARM.com    // For normal writes, we send the requests out and clear a store buffer
91011249Sradhika.jagtap@ARM.com    // entry on response. For writes which are strictly ordered, for e.g.
91111249Sradhika.jagtap@ARM.com    // writes to device registers, we do that within release() which is called
91211249Sradhika.jagtap@ARM.com    // when node is executed and taken off from readyList.
91311252Sradhika.jagtap@ARM.com    if (done_node->isStore() && done_node->isStrictlyOrdered()) {
91411249Sradhika.jagtap@ARM.com        releaseStoreBuffer();
91511249Sradhika.jagtap@ARM.com    }
91611249Sradhika.jagtap@ARM.com}
91711249Sradhika.jagtap@ARM.com
91811249Sradhika.jagtap@ARM.comvoid
91911249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::HardwareResource::releaseStoreBuffer()
92011249Sradhika.jagtap@ARM.com{
92111249Sradhika.jagtap@ARM.com    assert(numInFlightStores != 0);
92211249Sradhika.jagtap@ARM.com    --numInFlightStores;
92311249Sradhika.jagtap@ARM.com}
92411249Sradhika.jagtap@ARM.com
92511249Sradhika.jagtap@ARM.combool
92611249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::HardwareResource::isAvailable(
92711249Sradhika.jagtap@ARM.com    const GraphNode* new_node) const
92811249Sradhika.jagtap@ARM.com{
92911249Sradhika.jagtap@ARM.com    uint16_t num_in_flight_nodes;
93011249Sradhika.jagtap@ARM.com    if (inFlightNodes.empty()) {
93111249Sradhika.jagtap@ARM.com        num_in_flight_nodes = 0;
93211249Sradhika.jagtap@ARM.com        DPRINTFR(TraceCPUData, "\t\tChecking resources to issue seq. num %lli:"
93311249Sradhika.jagtap@ARM.com            " #in-flight nodes = 0", new_node->seqNum);
93411249Sradhika.jagtap@ARM.com    } else if (new_node->robNum > oldestInFlightRobNum) {
93511249Sradhika.jagtap@ARM.com        // This is the intuitive case where new dep-free node is younger
93611249Sradhika.jagtap@ARM.com        // instruction than the oldest instruction in-flight. Thus we make sure
93711249Sradhika.jagtap@ARM.com        // in_flight_nodes does not overflow.
93811249Sradhika.jagtap@ARM.com        num_in_flight_nodes = new_node->robNum - oldestInFlightRobNum;
93911249Sradhika.jagtap@ARM.com        DPRINTFR(TraceCPUData, "\t\tChecking resources to issue seq. num %lli:"
94011249Sradhika.jagtap@ARM.com            " #in-flight nodes = %d - %d =  %d", new_node->seqNum,
94111249Sradhika.jagtap@ARM.com             new_node->robNum, oldestInFlightRobNum, num_in_flight_nodes);
94211249Sradhika.jagtap@ARM.com    } else {
94311249Sradhika.jagtap@ARM.com        // This is the case where an instruction older than the oldest in-
94411249Sradhika.jagtap@ARM.com        // flight instruction becomes dep-free. Thus we must have already
94511249Sradhika.jagtap@ARM.com        // accounted for the entry in ROB for this new dep-free node.
94611249Sradhika.jagtap@ARM.com        // Immediately after this check returns true, oldestInFlightRobNum will
94711249Sradhika.jagtap@ARM.com        // be updated in occupy(). We simply let this node issue now.
94811249Sradhika.jagtap@ARM.com        num_in_flight_nodes = 0;
94911249Sradhika.jagtap@ARM.com        DPRINTFR(TraceCPUData, "\t\tChecking resources to issue seq. num %lli:"
95011249Sradhika.jagtap@ARM.com            " new oldestInFlightRobNum = %d, #in-flight nodes ignored",
95111249Sradhika.jagtap@ARM.com            new_node->seqNum, new_node->robNum);
95211249Sradhika.jagtap@ARM.com    }
95311249Sradhika.jagtap@ARM.com    DPRINTFR(TraceCPUData, ", LQ = %d/%d, SQ  = %d/%d.\n",
95411249Sradhika.jagtap@ARM.com        numInFlightLoads, sizeLoadBuffer,
95511249Sradhika.jagtap@ARM.com        numInFlightStores, sizeStoreBuffer);
95611249Sradhika.jagtap@ARM.com    // Check if resources are available to issue the specific node
95711249Sradhika.jagtap@ARM.com    if (num_in_flight_nodes >= sizeROB) {
95811249Sradhika.jagtap@ARM.com        return false;
95911249Sradhika.jagtap@ARM.com    }
96011252Sradhika.jagtap@ARM.com    if (new_node->isLoad() && numInFlightLoads >= sizeLoadBuffer) {
96111249Sradhika.jagtap@ARM.com        return false;
96211249Sradhika.jagtap@ARM.com    }
96311252Sradhika.jagtap@ARM.com    if (new_node->isStore() && numInFlightStores >= sizeStoreBuffer) {
96411249Sradhika.jagtap@ARM.com        return false;
96511249Sradhika.jagtap@ARM.com    }
96611249Sradhika.jagtap@ARM.com    return true;
96711249Sradhika.jagtap@ARM.com}
96811249Sradhika.jagtap@ARM.com
96911249Sradhika.jagtap@ARM.combool
97011249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::HardwareResource::awaitingResponse() const {
97111249Sradhika.jagtap@ARM.com    // Return true if there is at least one read or write request in flight
97211249Sradhika.jagtap@ARM.com    return (numInFlightStores != 0 || numInFlightLoads != 0);
97311249Sradhika.jagtap@ARM.com}
97411249Sradhika.jagtap@ARM.com
97511249Sradhika.jagtap@ARM.comvoid
97611249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::HardwareResource::printOccupancy() {
97711249Sradhika.jagtap@ARM.com    DPRINTFR(TraceCPUData, "oldestInFlightRobNum = %d, "
97811249Sradhika.jagtap@ARM.com            "LQ = %d/%d, SQ  = %d/%d.\n",
97911249Sradhika.jagtap@ARM.com            oldestInFlightRobNum,
98011249Sradhika.jagtap@ARM.com            numInFlightLoads, sizeLoadBuffer,
98111249Sradhika.jagtap@ARM.com            numInFlightStores, sizeStoreBuffer);
98211249Sradhika.jagtap@ARM.com}
98311249Sradhika.jagtap@ARM.com
98411249Sradhika.jagtap@ARM.comvoid
98511249Sradhika.jagtap@ARM.comTraceCPU::FixedRetryGen::regStats()
98611249Sradhika.jagtap@ARM.com{
98711249Sradhika.jagtap@ARM.com    using namespace Stats;
98811249Sradhika.jagtap@ARM.com
98911249Sradhika.jagtap@ARM.com    numSendAttempted
99011249Sradhika.jagtap@ARM.com    .name(name() + ".numSendAttempted")
99111249Sradhika.jagtap@ARM.com    .desc("Number of first attempts to send a request")
99211249Sradhika.jagtap@ARM.com    ;
99311249Sradhika.jagtap@ARM.com
99411249Sradhika.jagtap@ARM.com    numSendSucceeded
99511249Sradhika.jagtap@ARM.com    .name(name() + ".numSendSucceeded")
99611249Sradhika.jagtap@ARM.com    .desc("Number of successful first attempts")
99711249Sradhika.jagtap@ARM.com    ;
99811249Sradhika.jagtap@ARM.com
99911249Sradhika.jagtap@ARM.com    numSendFailed
100011249Sradhika.jagtap@ARM.com    .name(name() + ".numSendFailed")
100111249Sradhika.jagtap@ARM.com    .desc("Number of failed first attempts")
100211249Sradhika.jagtap@ARM.com    ;
100311249Sradhika.jagtap@ARM.com
100411249Sradhika.jagtap@ARM.com    numRetrySucceeded
100511249Sradhika.jagtap@ARM.com    .name(name() + ".numRetrySucceeded")
100611249Sradhika.jagtap@ARM.com    .desc("Number of successful retries")
100711249Sradhika.jagtap@ARM.com    ;
100811249Sradhika.jagtap@ARM.com
100911249Sradhika.jagtap@ARM.com    instLastTick
101011249Sradhika.jagtap@ARM.com    .name(name() + ".instLastTick")
101111249Sradhika.jagtap@ARM.com    .desc("Last tick simulated from the fixed inst trace")
101211249Sradhika.jagtap@ARM.com    ;
101311249Sradhika.jagtap@ARM.com}
101411249Sradhika.jagtap@ARM.com
101511249Sradhika.jagtap@ARM.comTick
101611249Sradhika.jagtap@ARM.comTraceCPU::FixedRetryGen::init()
101711249Sradhika.jagtap@ARM.com{
101811249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUInst, "Initializing instruction fetch request generator"
101911249Sradhika.jagtap@ARM.com            " IcacheGen: fixed issue with retry.\n");
102011249Sradhika.jagtap@ARM.com
102111249Sradhika.jagtap@ARM.com    if (nextExecute()) {
102211249Sradhika.jagtap@ARM.com        DPRINTF(TraceCPUInst, "\tFirst tick = %d.\n", currElement.tick);
102311249Sradhika.jagtap@ARM.com        return currElement.tick;
102411249Sradhika.jagtap@ARM.com    } else {
102511249Sradhika.jagtap@ARM.com        panic("Read of first message in the trace failed.\n");
102611249Sradhika.jagtap@ARM.com        return MaxTick;
102711249Sradhika.jagtap@ARM.com    }
102811249Sradhika.jagtap@ARM.com}
102911249Sradhika.jagtap@ARM.com
103011249Sradhika.jagtap@ARM.combool
103111249Sradhika.jagtap@ARM.comTraceCPU::FixedRetryGen::tryNext()
103211249Sradhika.jagtap@ARM.com{
103311249Sradhika.jagtap@ARM.com    // If there is a retry packet, try to send it
103411249Sradhika.jagtap@ARM.com    if (retryPkt) {
103511249Sradhika.jagtap@ARM.com
103611249Sradhika.jagtap@ARM.com        DPRINTF(TraceCPUInst, "Trying to send retry packet.\n");
103711249Sradhika.jagtap@ARM.com
103811249Sradhika.jagtap@ARM.com        if (!port.sendTimingReq(retryPkt)) {
103911249Sradhika.jagtap@ARM.com            // Still blocked! This should never occur.
104011249Sradhika.jagtap@ARM.com            DPRINTF(TraceCPUInst, "Retry packet sending failed.\n");
104111249Sradhika.jagtap@ARM.com            return false;
104211249Sradhika.jagtap@ARM.com        }
104311249Sradhika.jagtap@ARM.com        ++numRetrySucceeded;
104411249Sradhika.jagtap@ARM.com    } else {
104511249Sradhika.jagtap@ARM.com
104611249Sradhika.jagtap@ARM.com        DPRINTF(TraceCPUInst, "Trying to send packet for currElement.\n");
104711249Sradhika.jagtap@ARM.com
104811249Sradhika.jagtap@ARM.com        // try sending current element
104911249Sradhika.jagtap@ARM.com        assert(currElement.isValid());
105011249Sradhika.jagtap@ARM.com
105111249Sradhika.jagtap@ARM.com        ++numSendAttempted;
105211249Sradhika.jagtap@ARM.com
105311249Sradhika.jagtap@ARM.com        if (!send(currElement.addr, currElement.blocksize,
105411249Sradhika.jagtap@ARM.com                    currElement.cmd, currElement.flags, currElement.pc)) {
105511249Sradhika.jagtap@ARM.com            DPRINTF(TraceCPUInst, "currElement sending failed.\n");
105611249Sradhika.jagtap@ARM.com            ++numSendFailed;
105711249Sradhika.jagtap@ARM.com            // return false to indicate not to schedule next event
105811249Sradhika.jagtap@ARM.com            return false;
105911249Sradhika.jagtap@ARM.com        } else {
106011249Sradhika.jagtap@ARM.com            ++numSendSucceeded;
106111249Sradhika.jagtap@ARM.com        }
106211249Sradhika.jagtap@ARM.com    }
106311249Sradhika.jagtap@ARM.com    // If packet was sent successfully, either retryPkt or currElement, return
106411249Sradhika.jagtap@ARM.com    // true to indicate to schedule event at current Tick plus delta. If packet
106511249Sradhika.jagtap@ARM.com    // was sent successfully and there is no next packet to send, return false.
106611249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUInst, "Packet sent successfully, trying to read next "
106711249Sradhika.jagtap@ARM.com        "element.\n");
106811249Sradhika.jagtap@ARM.com    retryPkt = nullptr;
106911249Sradhika.jagtap@ARM.com    // Read next element into currElement, currElement gets cleared so save the
107011249Sradhika.jagtap@ARM.com    // tick to calculate delta
107111249Sradhika.jagtap@ARM.com    Tick last_tick = currElement.tick;
107211249Sradhika.jagtap@ARM.com    if (nextExecute()) {
107311249Sradhika.jagtap@ARM.com        assert(currElement.tick >= last_tick);
107411249Sradhika.jagtap@ARM.com        delta = currElement.tick - last_tick;
107511249Sradhika.jagtap@ARM.com    }
107611249Sradhika.jagtap@ARM.com    return !traceComplete;
107711249Sradhika.jagtap@ARM.com}
107811249Sradhika.jagtap@ARM.com
107911249Sradhika.jagtap@ARM.comvoid
108011249Sradhika.jagtap@ARM.comTraceCPU::FixedRetryGen::exit()
108111249Sradhika.jagtap@ARM.com{
108211249Sradhika.jagtap@ARM.com    trace.reset();
108311249Sradhika.jagtap@ARM.com}
108411249Sradhika.jagtap@ARM.com
108511249Sradhika.jagtap@ARM.combool
108611249Sradhika.jagtap@ARM.comTraceCPU::FixedRetryGen::nextExecute()
108711249Sradhika.jagtap@ARM.com{
108811249Sradhika.jagtap@ARM.com    if (traceComplete)
108911249Sradhika.jagtap@ARM.com        // We are at the end of the file, thus we have no more messages.
109011249Sradhika.jagtap@ARM.com        // Return false.
109111249Sradhika.jagtap@ARM.com        return false;
109211249Sradhika.jagtap@ARM.com
109311249Sradhika.jagtap@ARM.com
109411249Sradhika.jagtap@ARM.com    //Reset the currElement to the default values
109511249Sradhika.jagtap@ARM.com    currElement.clear();
109611249Sradhika.jagtap@ARM.com
109711249Sradhika.jagtap@ARM.com    // Read the next line to get the next message. If that fails then end of
109811249Sradhika.jagtap@ARM.com    // trace has been reached and traceComplete needs to be set in addition
109911249Sradhika.jagtap@ARM.com    // to returning false. If successful then next message is in currElement.
110011249Sradhika.jagtap@ARM.com    if (!trace.read(&currElement)) {
110111249Sradhika.jagtap@ARM.com        traceComplete = true;
110211249Sradhika.jagtap@ARM.com        instLastTick = curTick();
110311249Sradhika.jagtap@ARM.com        return false;
110411249Sradhika.jagtap@ARM.com    }
110511249Sradhika.jagtap@ARM.com
110611249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUInst, "inst fetch: %c addr %d pc %#x size %d tick %d\n",
110711249Sradhika.jagtap@ARM.com            currElement.cmd.isRead() ? 'r' : 'w',
110811249Sradhika.jagtap@ARM.com            currElement.addr,
110911249Sradhika.jagtap@ARM.com            currElement.pc,
111011249Sradhika.jagtap@ARM.com            currElement.blocksize,
111111249Sradhika.jagtap@ARM.com            currElement.tick);
111211249Sradhika.jagtap@ARM.com
111311249Sradhika.jagtap@ARM.com    return true;
111411249Sradhika.jagtap@ARM.com}
111511249Sradhika.jagtap@ARM.com
111611249Sradhika.jagtap@ARM.combool
111711249Sradhika.jagtap@ARM.comTraceCPU::FixedRetryGen::send(Addr addr, unsigned size, const MemCmd& cmd,
111811249Sradhika.jagtap@ARM.com              Request::FlagsType flags, Addr pc)
111911249Sradhika.jagtap@ARM.com{
112011249Sradhika.jagtap@ARM.com
112111249Sradhika.jagtap@ARM.com    // Create new request
112211249Sradhika.jagtap@ARM.com    Request* req = new Request(addr, size, flags, masterID);
112311249Sradhika.jagtap@ARM.com    req->setPC(pc);
112411249Sradhika.jagtap@ARM.com
112511249Sradhika.jagtap@ARM.com    // If this is not done it triggers assert in L1 cache for invalid contextId
112611249Sradhika.jagtap@ARM.com    req->setThreadContext(ContextID(0), ThreadID(0));
112711249Sradhika.jagtap@ARM.com
112811249Sradhika.jagtap@ARM.com    // Embed it in a packet
112911249Sradhika.jagtap@ARM.com    PacketPtr pkt = new Packet(req, cmd);
113011249Sradhika.jagtap@ARM.com
113111249Sradhika.jagtap@ARM.com    uint8_t* pkt_data = new uint8_t[req->getSize()];
113211249Sradhika.jagtap@ARM.com    pkt->dataDynamic(pkt_data);
113311249Sradhika.jagtap@ARM.com
113411249Sradhika.jagtap@ARM.com    if (cmd.isWrite()) {
113511249Sradhika.jagtap@ARM.com        memset(pkt_data, 0xA, req->getSize());
113611249Sradhika.jagtap@ARM.com    }
113711249Sradhika.jagtap@ARM.com
113811249Sradhika.jagtap@ARM.com    // Call MasterPort method to send a timing request for this packet
113911249Sradhika.jagtap@ARM.com    bool success = port.sendTimingReq(pkt);
114011249Sradhika.jagtap@ARM.com    if (!success) {
114111249Sradhika.jagtap@ARM.com        // If it fails, save the packet to retry when a retry is signalled by
114211249Sradhika.jagtap@ARM.com        // the cache
114311249Sradhika.jagtap@ARM.com        retryPkt = pkt;
114411249Sradhika.jagtap@ARM.com    }
114511249Sradhika.jagtap@ARM.com    return success;
114611249Sradhika.jagtap@ARM.com}
114711249Sradhika.jagtap@ARM.com
114811249Sradhika.jagtap@ARM.comvoid
114911249Sradhika.jagtap@ARM.comTraceCPU::icacheRetryRecvd()
115011249Sradhika.jagtap@ARM.com{
115111249Sradhika.jagtap@ARM.com    // Schedule an event to go through the control flow in the same tick as
115211249Sradhika.jagtap@ARM.com    // retry is received
115311249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUInst, "Icache retry received. Scheduling next IcacheGen"
115411249Sradhika.jagtap@ARM.com            " event @%lli.\n", curTick());
115511249Sradhika.jagtap@ARM.com    schedule(icacheNextEvent, curTick());
115611249Sradhika.jagtap@ARM.com}
115711249Sradhika.jagtap@ARM.com
115811249Sradhika.jagtap@ARM.comvoid
115911249Sradhika.jagtap@ARM.comTraceCPU::dcacheRetryRecvd()
116011249Sradhika.jagtap@ARM.com{
116111249Sradhika.jagtap@ARM.com    // Schedule an event to go through the execute flow in the same tick as
116211249Sradhika.jagtap@ARM.com    // retry is received
116311249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUData, "Dcache retry received. Scheduling next DcacheGen"
116411249Sradhika.jagtap@ARM.com            " event @%lli.\n", curTick());
116511249Sradhika.jagtap@ARM.com    schedule(dcacheNextEvent, curTick());
116611249Sradhika.jagtap@ARM.com}
116711249Sradhika.jagtap@ARM.com
116811249Sradhika.jagtap@ARM.comvoid
116911249Sradhika.jagtap@ARM.comTraceCPU::schedDcacheNextEvent(Tick when)
117011249Sradhika.jagtap@ARM.com{
117111249Sradhika.jagtap@ARM.com    if (!dcacheNextEvent.scheduled()) {
117211249Sradhika.jagtap@ARM.com        DPRINTF(TraceCPUData, "Scheduling next DcacheGen event at %lli.\n",
117311249Sradhika.jagtap@ARM.com                when);
117411249Sradhika.jagtap@ARM.com        schedule(dcacheNextEvent, when);
117511249Sradhika.jagtap@ARM.com        ++numSchedDcacheEvent;
117611249Sradhika.jagtap@ARM.com    } else if (when < dcacheNextEvent.when()) {
117711249Sradhika.jagtap@ARM.com        DPRINTF(TraceCPUData, "Re-scheduling next dcache event from %lli"
117811249Sradhika.jagtap@ARM.com                " to %lli.\n", dcacheNextEvent.when(), when);
117911249Sradhika.jagtap@ARM.com        reschedule(dcacheNextEvent, when);
118011249Sradhika.jagtap@ARM.com    }
118111249Sradhika.jagtap@ARM.com
118211249Sradhika.jagtap@ARM.com}
118311249Sradhika.jagtap@ARM.com
118411249Sradhika.jagtap@ARM.combool
118511249Sradhika.jagtap@ARM.comTraceCPU::IcachePort::recvTimingResp(PacketPtr pkt)
118611249Sradhika.jagtap@ARM.com{
118711249Sradhika.jagtap@ARM.com    // All responses on the instruction fetch side are ignored. Simply delete
118811249Sradhika.jagtap@ARM.com    // the request and packet to free allocated memory
118911249Sradhika.jagtap@ARM.com    delete pkt->req;
119011249Sradhika.jagtap@ARM.com    delete pkt;
119111249Sradhika.jagtap@ARM.com
119211249Sradhika.jagtap@ARM.com    return true;
119311249Sradhika.jagtap@ARM.com}
119411249Sradhika.jagtap@ARM.com
119511249Sradhika.jagtap@ARM.comvoid
119611249Sradhika.jagtap@ARM.comTraceCPU::IcachePort::recvReqRetry()
119711249Sradhika.jagtap@ARM.com{
119811249Sradhika.jagtap@ARM.com    owner->icacheRetryRecvd();
119911249Sradhika.jagtap@ARM.com}
120011249Sradhika.jagtap@ARM.com
120111249Sradhika.jagtap@ARM.comvoid
120211249Sradhika.jagtap@ARM.comTraceCPU::dcacheRecvTimingResp(PacketPtr pkt)
120311249Sradhika.jagtap@ARM.com{
120411249Sradhika.jagtap@ARM.com    DPRINTF(TraceCPUData, "Received timing response from Dcache.\n");
120511249Sradhika.jagtap@ARM.com    dcacheGen.completeMemAccess(pkt);
120611249Sradhika.jagtap@ARM.com}
120711249Sradhika.jagtap@ARM.com
120811249Sradhika.jagtap@ARM.combool
120911249Sradhika.jagtap@ARM.comTraceCPU::DcachePort::recvTimingResp(PacketPtr pkt)
121011249Sradhika.jagtap@ARM.com{
121111249Sradhika.jagtap@ARM.com    // Handle the responses for data memory requests which is done inside the
121211249Sradhika.jagtap@ARM.com    // elastic data generator
121311249Sradhika.jagtap@ARM.com    owner->dcacheRecvTimingResp(pkt);
121411249Sradhika.jagtap@ARM.com    // After processing the response delete the request and packet to free
121511249Sradhika.jagtap@ARM.com    // memory
121611249Sradhika.jagtap@ARM.com    delete pkt->req;
121711249Sradhika.jagtap@ARM.com    delete pkt;
121811249Sradhika.jagtap@ARM.com
121911249Sradhika.jagtap@ARM.com    return true;
122011249Sradhika.jagtap@ARM.com}
122111249Sradhika.jagtap@ARM.com
122211249Sradhika.jagtap@ARM.comvoid
122311249Sradhika.jagtap@ARM.comTraceCPU::DcachePort::recvReqRetry()
122411249Sradhika.jagtap@ARM.com{
122511249Sradhika.jagtap@ARM.com    owner->dcacheRetryRecvd();
122611249Sradhika.jagtap@ARM.com}
122711249Sradhika.jagtap@ARM.com
122811249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::InputStream::InputStream(const std::string& filename)
122911249Sradhika.jagtap@ARM.com    : trace(filename),
123011249Sradhika.jagtap@ARM.com      microOpCount(0)
123111249Sradhika.jagtap@ARM.com{
123211249Sradhika.jagtap@ARM.com    // Create a protobuf message for the header and read it from the stream
123311249Sradhika.jagtap@ARM.com    ProtoMessage::InstDepRecordHeader header_msg;
123411249Sradhika.jagtap@ARM.com    if (!trace.read(header_msg)) {
123511249Sradhika.jagtap@ARM.com        panic("Failed to read packet header from %s\n", filename);
123611249Sradhika.jagtap@ARM.com
123711249Sradhika.jagtap@ARM.com        if (header_msg.tick_freq() != SimClock::Frequency) {
123811249Sradhika.jagtap@ARM.com            panic("Trace %s was recorded with a different tick frequency %d\n",
123911249Sradhika.jagtap@ARM.com                  header_msg.tick_freq());
124011249Sradhika.jagtap@ARM.com        }
124111249Sradhika.jagtap@ARM.com    } else {
124211249Sradhika.jagtap@ARM.com        // Assign window size equal to the field in the trace that was recorded
124311249Sradhika.jagtap@ARM.com        // when the data dependency trace was captured in the o3cpu model
124411249Sradhika.jagtap@ARM.com        windowSize = header_msg.window_size();
124511249Sradhika.jagtap@ARM.com    }
124611249Sradhika.jagtap@ARM.com}
124711249Sradhika.jagtap@ARM.com
124811249Sradhika.jagtap@ARM.comvoid
124911249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::InputStream::reset()
125011249Sradhika.jagtap@ARM.com{
125111249Sradhika.jagtap@ARM.com    trace.reset();
125211249Sradhika.jagtap@ARM.com}
125311249Sradhika.jagtap@ARM.com
125411249Sradhika.jagtap@ARM.combool
125511249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::InputStream::read(GraphNode* element)
125611249Sradhika.jagtap@ARM.com{
125711249Sradhika.jagtap@ARM.com    ProtoMessage::InstDepRecord pkt_msg;
125811249Sradhika.jagtap@ARM.com    if (trace.read(pkt_msg)) {
125911249Sradhika.jagtap@ARM.com        // Required fields
126011249Sradhika.jagtap@ARM.com        element->seqNum = pkt_msg.seq_num();
126111252Sradhika.jagtap@ARM.com        element->type = pkt_msg.type();
126211249Sradhika.jagtap@ARM.com        element->compDelay = pkt_msg.comp_delay();
126311249Sradhika.jagtap@ARM.com
126411249Sradhika.jagtap@ARM.com        // Repeated field robDepList
126511249Sradhika.jagtap@ARM.com        element->clearRobDep();
126611249Sradhika.jagtap@ARM.com        assert((pkt_msg.rob_dep()).size() <= element->maxRobDep);
126711249Sradhika.jagtap@ARM.com        for (int i = 0; i < (pkt_msg.rob_dep()).size(); i++) {
126811249Sradhika.jagtap@ARM.com            element->robDep[element->numRobDep] = pkt_msg.rob_dep(i);
126911249Sradhika.jagtap@ARM.com            element->numRobDep += 1;
127011249Sradhika.jagtap@ARM.com        }
127111249Sradhika.jagtap@ARM.com
127211249Sradhika.jagtap@ARM.com        // Repeated field
127311249Sradhika.jagtap@ARM.com        element->clearRegDep();
127411249Sradhika.jagtap@ARM.com        assert((pkt_msg.reg_dep()).size() <= TheISA::MaxInstSrcRegs);
127511249Sradhika.jagtap@ARM.com        for (int i = 0; i < (pkt_msg.reg_dep()).size(); i++) {
127611249Sradhika.jagtap@ARM.com            // There is a possibility that an instruction has both, a register
127711249Sradhika.jagtap@ARM.com            // and order dependency on an instruction. In such a case, the
127811249Sradhika.jagtap@ARM.com            // register dependency is omitted
127911249Sradhika.jagtap@ARM.com            bool duplicate = false;
128011249Sradhika.jagtap@ARM.com            for (int j = 0; j < element->numRobDep; j++) {
128111249Sradhika.jagtap@ARM.com                duplicate |= (pkt_msg.reg_dep(i) == element->robDep[j]);
128211249Sradhika.jagtap@ARM.com            }
128311249Sradhika.jagtap@ARM.com            if (!duplicate) {
128411249Sradhika.jagtap@ARM.com                element->regDep[element->numRegDep] = pkt_msg.reg_dep(i);
128511249Sradhika.jagtap@ARM.com                element->numRegDep += 1;
128611249Sradhika.jagtap@ARM.com            }
128711249Sradhika.jagtap@ARM.com        }
128811249Sradhika.jagtap@ARM.com
128911249Sradhika.jagtap@ARM.com        // Optional fields
129011253Sradhika.jagtap@ARM.com        if (pkt_msg.has_p_addr())
129111253Sradhika.jagtap@ARM.com            element->physAddr = pkt_msg.p_addr();
129211249Sradhika.jagtap@ARM.com        else
129311253Sradhika.jagtap@ARM.com            element->physAddr = 0;
129411253Sradhika.jagtap@ARM.com
129511253Sradhika.jagtap@ARM.com        if (pkt_msg.has_v_addr())
129611253Sradhika.jagtap@ARM.com            element->virtAddr = pkt_msg.v_addr();
129711253Sradhika.jagtap@ARM.com        else
129811253Sradhika.jagtap@ARM.com            element->virtAddr = 0;
129911253Sradhika.jagtap@ARM.com
130011253Sradhika.jagtap@ARM.com        if (pkt_msg.has_asid())
130111253Sradhika.jagtap@ARM.com            element->asid = pkt_msg.asid();
130211253Sradhika.jagtap@ARM.com        else
130311253Sradhika.jagtap@ARM.com            element->asid = 0;
130411249Sradhika.jagtap@ARM.com
130511249Sradhika.jagtap@ARM.com        if (pkt_msg.has_size())
130611249Sradhika.jagtap@ARM.com            element->size = pkt_msg.size();
130711249Sradhika.jagtap@ARM.com        else
130811249Sradhika.jagtap@ARM.com            element->size = 0;
130911249Sradhika.jagtap@ARM.com
131011249Sradhika.jagtap@ARM.com        if (pkt_msg.has_flags())
131111249Sradhika.jagtap@ARM.com            element->flags = pkt_msg.flags();
131211249Sradhika.jagtap@ARM.com        else
131311249Sradhika.jagtap@ARM.com            element->flags = 0;
131411249Sradhika.jagtap@ARM.com
131511249Sradhika.jagtap@ARM.com        if (pkt_msg.has_pc())
131611249Sradhika.jagtap@ARM.com            element->pc = pkt_msg.pc();
131711249Sradhika.jagtap@ARM.com        else
131811249Sradhika.jagtap@ARM.com            element->pc = 0;
131911249Sradhika.jagtap@ARM.com
132011249Sradhika.jagtap@ARM.com        // ROB occupancy number
132111249Sradhika.jagtap@ARM.com        ++microOpCount;
132211249Sradhika.jagtap@ARM.com        if (pkt_msg.has_weight()) {
132311249Sradhika.jagtap@ARM.com            microOpCount += pkt_msg.weight();
132411249Sradhika.jagtap@ARM.com        }
132511249Sradhika.jagtap@ARM.com        element->robNum = microOpCount;
132611249Sradhika.jagtap@ARM.com        return true;
132711249Sradhika.jagtap@ARM.com    }
132811249Sradhika.jagtap@ARM.com
132911249Sradhika.jagtap@ARM.com    // We have reached the end of the file
133011249Sradhika.jagtap@ARM.com    return false;
133111249Sradhika.jagtap@ARM.com}
133211249Sradhika.jagtap@ARM.com
133311249Sradhika.jagtap@ARM.combool
133411249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::GraphNode::removeRegDep(NodeSeqNum reg_dep)
133511249Sradhika.jagtap@ARM.com{
133611249Sradhika.jagtap@ARM.com    for (auto& own_reg_dep : regDep) {
133711249Sradhika.jagtap@ARM.com        if (own_reg_dep == reg_dep) {
133811249Sradhika.jagtap@ARM.com            // If register dependency is found, make it zero and return true
133911249Sradhika.jagtap@ARM.com            own_reg_dep = 0;
134011249Sradhika.jagtap@ARM.com            --numRegDep;
134111249Sradhika.jagtap@ARM.com            assert(numRegDep >= 0);
134211249Sradhika.jagtap@ARM.com            DPRINTFR(TraceCPUData, "\tFor %lli: Marking register dependency %lli "
134311249Sradhika.jagtap@ARM.com                    "done.\n", seqNum, reg_dep);
134411249Sradhika.jagtap@ARM.com            return true;
134511249Sradhika.jagtap@ARM.com        }
134611249Sradhika.jagtap@ARM.com    }
134711249Sradhika.jagtap@ARM.com
134811249Sradhika.jagtap@ARM.com    // Return false if the dependency is not found
134911249Sradhika.jagtap@ARM.com    return false;
135011249Sradhika.jagtap@ARM.com}
135111249Sradhika.jagtap@ARM.com
135211249Sradhika.jagtap@ARM.combool
135311249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::GraphNode::removeRobDep(NodeSeqNum rob_dep)
135411249Sradhika.jagtap@ARM.com{
135511249Sradhika.jagtap@ARM.com    for (auto& own_rob_dep : robDep) {
135611249Sradhika.jagtap@ARM.com        if (own_rob_dep == rob_dep) {
135711249Sradhika.jagtap@ARM.com            // If the rob dependency is found, make it zero and return true
135811249Sradhika.jagtap@ARM.com            own_rob_dep = 0;
135911249Sradhika.jagtap@ARM.com            --numRobDep;
136011249Sradhika.jagtap@ARM.com            assert(numRobDep >= 0);
136111249Sradhika.jagtap@ARM.com            DPRINTFR(TraceCPUData, "\tFor %lli: Marking ROB dependency %lli "
136211249Sradhika.jagtap@ARM.com                "done.\n", seqNum, rob_dep);
136311249Sradhika.jagtap@ARM.com            return true;
136411249Sradhika.jagtap@ARM.com        }
136511249Sradhika.jagtap@ARM.com    }
136611249Sradhika.jagtap@ARM.com    return false;
136711249Sradhika.jagtap@ARM.com}
136811249Sradhika.jagtap@ARM.com
136911249Sradhika.jagtap@ARM.comvoid
137011249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::GraphNode::clearRegDep() {
137111249Sradhika.jagtap@ARM.com    for (auto& own_reg_dep : regDep) {
137211249Sradhika.jagtap@ARM.com        own_reg_dep = 0;
137311249Sradhika.jagtap@ARM.com    }
137411249Sradhika.jagtap@ARM.com    numRegDep = 0;
137511249Sradhika.jagtap@ARM.com}
137611249Sradhika.jagtap@ARM.com
137711249Sradhika.jagtap@ARM.comvoid
137811249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::GraphNode::clearRobDep() {
137911249Sradhika.jagtap@ARM.com    for (auto& own_rob_dep : robDep) {
138011249Sradhika.jagtap@ARM.com        own_rob_dep = 0;
138111249Sradhika.jagtap@ARM.com    }
138211249Sradhika.jagtap@ARM.com    numRobDep = 0;
138311249Sradhika.jagtap@ARM.com}
138411249Sradhika.jagtap@ARM.com
138511249Sradhika.jagtap@ARM.combool
138611249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::GraphNode::removeDepOnInst(NodeSeqNum done_seq_num)
138711249Sradhika.jagtap@ARM.com{
138811249Sradhika.jagtap@ARM.com    // If it is an rob dependency then remove it
138911249Sradhika.jagtap@ARM.com    if (!removeRobDep(done_seq_num)) {
139011249Sradhika.jagtap@ARM.com        // If it is not an rob dependency then it must be a register dependency
139111249Sradhika.jagtap@ARM.com        // If the register dependency is not found, it violates an assumption
139211249Sradhika.jagtap@ARM.com        // and must be caught by assert.
139311249Sradhika.jagtap@ARM.com        bool regdep_found M5_VAR_USED = removeRegDep(done_seq_num);
139411249Sradhika.jagtap@ARM.com        assert(regdep_found);
139511249Sradhika.jagtap@ARM.com    }
139611249Sradhika.jagtap@ARM.com    // Return true if the node is dependency free
139711249Sradhika.jagtap@ARM.com    return (numRobDep == 0 && numRegDep == 0);
139811249Sradhika.jagtap@ARM.com}
139911249Sradhika.jagtap@ARM.com
140011249Sradhika.jagtap@ARM.comvoid
140111249Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::GraphNode::writeElementAsTrace() const
140211249Sradhika.jagtap@ARM.com{
140311249Sradhika.jagtap@ARM.com    DPRINTFR(TraceCPUData, "%lli", seqNum);
140411252Sradhika.jagtap@ARM.com    DPRINTFR(TraceCPUData, ",%s", typeToStr());
140511252Sradhika.jagtap@ARM.com    if (isLoad() || isStore()) {
140611253Sradhika.jagtap@ARM.com        DPRINTFR(TraceCPUData, ",%i", physAddr);
140711249Sradhika.jagtap@ARM.com        DPRINTFR(TraceCPUData, ",%i", size);
140811249Sradhika.jagtap@ARM.com        DPRINTFR(TraceCPUData, ",%i", flags);
140911249Sradhika.jagtap@ARM.com    }
141011249Sradhika.jagtap@ARM.com    DPRINTFR(TraceCPUData, ",%lli", compDelay);
141111249Sradhika.jagtap@ARM.com    int i = 0;
141211249Sradhika.jagtap@ARM.com    DPRINTFR(TraceCPUData, "robDep:");
141311249Sradhika.jagtap@ARM.com    while (robDep[i] != 0) {
141411249Sradhika.jagtap@ARM.com        DPRINTFR(TraceCPUData, ",%lli", robDep[i]);
141511249Sradhika.jagtap@ARM.com        i++;
141611249Sradhika.jagtap@ARM.com    }
141711249Sradhika.jagtap@ARM.com    i = 0;
141811249Sradhika.jagtap@ARM.com    DPRINTFR(TraceCPUData, "regDep:");
141911249Sradhika.jagtap@ARM.com    while (regDep[i] != 0) {
142011249Sradhika.jagtap@ARM.com        DPRINTFR(TraceCPUData, ",%lli", regDep[i]);
142111249Sradhika.jagtap@ARM.com        i++;
142211249Sradhika.jagtap@ARM.com    }
142311249Sradhika.jagtap@ARM.com    auto child_itr = dependents.begin();
142411249Sradhika.jagtap@ARM.com    DPRINTFR(TraceCPUData, "dependents:");
142511249Sradhika.jagtap@ARM.com    while (child_itr != dependents.end()) {
142611249Sradhika.jagtap@ARM.com        DPRINTFR(TraceCPUData, ":%lli", (*child_itr)->seqNum);
142711249Sradhika.jagtap@ARM.com        child_itr++;
142811249Sradhika.jagtap@ARM.com    }
142911249Sradhika.jagtap@ARM.com
143011249Sradhika.jagtap@ARM.com    DPRINTFR(TraceCPUData, "\n");
143111249Sradhika.jagtap@ARM.com}
143211249Sradhika.jagtap@ARM.com
143311252Sradhika.jagtap@ARM.comstd::string
143411252Sradhika.jagtap@ARM.comTraceCPU::ElasticDataGen::GraphNode::typeToStr() const
143511252Sradhika.jagtap@ARM.com{
143611252Sradhika.jagtap@ARM.com    return Record::RecordType_Name(type);
143711252Sradhika.jagtap@ARM.com}
143811252Sradhika.jagtap@ARM.com
143911249Sradhika.jagtap@ARM.comTraceCPU::FixedRetryGen::InputStream::InputStream(const std::string& filename)
144011249Sradhika.jagtap@ARM.com    : trace(filename)
144111249Sradhika.jagtap@ARM.com{
144211249Sradhika.jagtap@ARM.com    // Create a protobuf message for the header and read it from the stream
144311249Sradhika.jagtap@ARM.com    ProtoMessage::PacketHeader header_msg;
144411249Sradhika.jagtap@ARM.com    if (!trace.read(header_msg)) {
144511249Sradhika.jagtap@ARM.com        panic("Failed to read packet header from %s\n", filename);
144611249Sradhika.jagtap@ARM.com
144711249Sradhika.jagtap@ARM.com        if (header_msg.tick_freq() != SimClock::Frequency) {
144811249Sradhika.jagtap@ARM.com            panic("Trace %s was recorded with a different tick frequency %d\n",
144911249Sradhika.jagtap@ARM.com                  header_msg.tick_freq());
145011249Sradhika.jagtap@ARM.com        }
145111249Sradhika.jagtap@ARM.com    }
145211249Sradhika.jagtap@ARM.com}
145311249Sradhika.jagtap@ARM.com
145411249Sradhika.jagtap@ARM.comvoid
145511249Sradhika.jagtap@ARM.comTraceCPU::FixedRetryGen::InputStream::reset()
145611249Sradhika.jagtap@ARM.com{
145711249Sradhika.jagtap@ARM.com    trace.reset();
145811249Sradhika.jagtap@ARM.com}
145911249Sradhika.jagtap@ARM.com
146011249Sradhika.jagtap@ARM.combool
146111249Sradhika.jagtap@ARM.comTraceCPU::FixedRetryGen::InputStream::read(TraceElement* element)
146211249Sradhika.jagtap@ARM.com{
146311249Sradhika.jagtap@ARM.com    ProtoMessage::Packet pkt_msg;
146411249Sradhika.jagtap@ARM.com    if (trace.read(pkt_msg)) {
146511249Sradhika.jagtap@ARM.com        element->cmd = pkt_msg.cmd();
146611249Sradhika.jagtap@ARM.com        element->addr = pkt_msg.addr();
146711249Sradhika.jagtap@ARM.com        element->blocksize = pkt_msg.size();
146811249Sradhika.jagtap@ARM.com        element->tick = pkt_msg.tick();
146911249Sradhika.jagtap@ARM.com        element->flags = pkt_msg.has_flags() ? pkt_msg.flags() : 0;
147011249Sradhika.jagtap@ARM.com        element->pc = pkt_msg.has_pc() ? pkt_msg.pc() : 0;
147111249Sradhika.jagtap@ARM.com        return true;
147211249Sradhika.jagtap@ARM.com    }
147311249Sradhika.jagtap@ARM.com
147411249Sradhika.jagtap@ARM.com    // We have reached the end of the file
147511249Sradhika.jagtap@ARM.com    return false;
147611249Sradhika.jagtap@ARM.com}
1477