/*
 * Copyright (c) 2012-2013 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Thomas Grass
 *          Andreas Hansson
 *          Sascha Bischoff
 *          Neha Agarwal
 */

#include "base/random.hh"
#include "base/trace.hh"
#include "cpu/testers/traffic_gen/generators.hh"
#include "debug/TrafficGen.hh"
#include "proto/packet.pb.h"

BaseGen::BaseGen(const std::string& _name, MasterID master_id, Tick _duration)
    : _name(_name), masterID(master_id), duration(_duration)
{
}

PacketPtr
BaseGen::getPacket(Addr addr, unsigned size, const MemCmd& cmd,
                   Request::FlagsType flags)
{
    // Create new request
    Request *req = new Request(addr, size, flags, masterID);
    // Dummy PC to have PC-based prefetchers latch on; get entropy into higher
    // bits
    req->setPC(((Addr)masterID) << 2);

    // Embed it in a packet
    PacketPtr pkt = new Packet(req, cmd);

    uint8_t* pkt_data = new uint8_t[req->getSize()];
    pkt->dataDynamic(pkt_data);

    if (cmd.isWrite()) {
        memset(pkt_data, 0xA, req->getSize());
    }

    return pkt;
}

void
LinearGen::enter()
{
    // reset the address and the data counter
    nextAddr = startAddr;
    dataManipulated = 0;
}

PacketPtr
LinearGen::getNextPacket()
{
    // choose if we generate a read or a write here
    bool isRead = readPercent != 0 &&
        (readPercent == 100 || random_mt.random(0, 100) < readPercent);

    assert((readPercent == 0 && !isRead) || (readPercent == 100 && isRead) ||
           readPercent != 100);

    DPRINTF(TrafficGen, "LinearGen::getNextPacket: %c to addr %x, size %d\n",
            isRead ? 'r' : 'w', nextAddr, blocksize);

    // Add the amount of data manipulated to the total
    dataManipulated += blocksize;

    PacketPtr pkt = getPacket(nextAddr, blocksize,
                              isRead ? MemCmd::ReadReq : MemCmd::WriteReq);

    // increment the address
    nextAddr += blocksize;

    // If we have reached the end of the address space, reset the
    // address to the start of the range
    if (nextAddr > endAddr) {
        DPRINTF(TrafficGen, "Wrapping address to the start of "
                "the range\n");
        nextAddr = startAddr;
    }

    return pkt;
}

Tick
LinearGen::nextPacketTick(bool elastic, Tick delay) const
{
    // Check to see if we have reached the data limit. If dataLimit is
    // zero we do not have a data limit and therefore we will keep
    // generating requests for the entire residency in this state.
    if (dataLimit && dataManipulated >= dataLimit) {
        DPRINTF(TrafficGen, "Data limit for LinearGen reached.\n");
        // there are no more requests, therefore return MaxTick
        return MaxTick;
    } else {
        // return the time when the next request should take place
        Tick wait = random_mt.random(minPeriod, maxPeriod);

        // compensate for the delay experienced to not be elastic, by
        // default the value we generate is from the time we are
        // asked, so the elasticity happens automatically
        if (!elastic) {
            if (wait < delay)
                wait = 0;
            else
                wait -= delay;
        }

        return curTick() + wait;
    }
}

void
RandomGen::enter()
{
    // reset the counter to zero
    dataManipulated = 0;
}

PacketPtr
RandomGen::getNextPacket()
{
    // choose if we generate a read or a write here
    bool isRead = readPercent != 0 &&
        (readPercent == 100 || random_mt.random(0, 100) < readPercent);

    assert((readPercent == 0 && !isRead) || (readPercent == 100 && isRead) ||
           readPercent != 100);

    // address of the request
    Addr addr = random_mt.random(startAddr, endAddr - 1);

    // round down to start address of block
    addr -= addr % blocksize;

    DPRINTF(TrafficGen, "RandomGen::getNextPacket: %c to addr %x, size %d\n",
            isRead ? 'r' : 'w', addr, blocksize);

    // add the amount of data manipulated to the total
    dataManipulated += blocksize;

    // create a new request packet
    return getPacket(addr, blocksize,
                     isRead ? MemCmd::ReadReq : MemCmd::WriteReq);
}

PacketPtr
DramGen::getNextPacket()
{
    // if this is the first of the packets in series to be generated,
    // start counting again
    if (countNumSeqPkts == 0) {
        countNumSeqPkts = numSeqPkts;

        // choose if we generate a read or a write here
        isRead = readPercent != 0 &&
            (readPercent == 100 || random_mt.random(0, 100) < readPercent);

        assert((readPercent == 0 && !isRead) ||
               (readPercent == 100 && isRead) ||
               readPercent != 100);

        // pick a random bank
        unsigned int new_bank =
            random_mt.random<unsigned int>(0, nbrOfBanksUtil - 1);

        // pick a random rank
        unsigned int new_rank =
            random_mt.random<unsigned int>(0, nbrOfRanks - 1);

        // Generate the start address of the command series
        // routine will update addr variable with bank, rank, and col
        // bits updated for random traffic mode
        genStartAddr(new_bank, new_rank);

    } else {
        // increment the column by one
        if (addrMapping == 1)
            // addrMapping=1: RoRaBaCoCh/RoRaBaChCo
            // Simply increment addr by blocksize to increment the column by one
            addr += blocksize;

        else if (addrMapping == 0) {
            // addrMapping=0: RoCoRaBaCh
            // Explicity increment the column bits
            unsigned int new_col = ((addr / blocksize / nbrOfBanksDRAM / nbrOfRanks) %
                                    (pageSize / blocksize)) + 1;
            replaceBits(addr, blockBits + bankBits + rankBits + pageBits - 1,
                        blockBits + bankBits + rankBits, new_col);
        }
    }

    DPRINTF(TrafficGen, "DramGen::getNextPacket: %c to addr %x, "
            "size %d, countNumSeqPkts: %d, numSeqPkts: %d\n",
            isRead ? 'r' : 'w', addr, blocksize, countNumSeqPkts, numSeqPkts);

    // create a new request packet
    PacketPtr pkt = getPacket(addr, blocksize,
                              isRead ? MemCmd::ReadReq : MemCmd::WriteReq);

    // add the amount of data manipulated to the total
    dataManipulated += blocksize;

    // subtract the number of packets remained to be generated
    --countNumSeqPkts;

    // return the generated packet
    return pkt;
}

PacketPtr
DramRotGen::getNextPacket()
{
    // if this is the first of the packets in series to be generated,
    // start counting again
    if (countNumSeqPkts == 0) {
        countNumSeqPkts = numSeqPkts;

        // choose if we generate a read or a write here
        if (readPercent == 50) {
           if ((nextSeqCount % nbrOfBanksUtil) == 0) {
               // Change type after all banks have been rotated
               // Otherwise, keep current value
               isRead = !isRead;
           }
        } else {
           // Set randomly based on percentage
           isRead = readPercent != 0;
        }

        assert((readPercent == 0 && !isRead) ||
               (readPercent == 100 && isRead) ||
               readPercent != 100);

         // Overwrite random bank value
         // Rotate across banks
         unsigned int new_bank = nextSeqCount % nbrOfBanksUtil;

         // Overwrite random rank value
         // Will rotate to the next rank after rotating through all banks,
         // for each specified command type.

         // Use modular function to ensure that calculated rank is within
         // system limits after state transition
         unsigned int new_rank = (nextSeqCount / maxSeqCountPerRank) %
             nbrOfRanks;

         // Increment nextSeqCount
         // Roll back to 0 after completing a full rotation across
         // banks, command type, and ranks
         nextSeqCount = (nextSeqCount + 1) %
             (nbrOfRanks * maxSeqCountPerRank);

         DPRINTF(TrafficGen, "DramRotGen::getNextPacket nextSeqCount: %d "
                 "new_rank: %d  new_bank: %d\n",
                 nextSeqCount, new_rank, new_bank);

        // Generate the start address of the command series
        // routine will update addr variable with bank, rank, and col
        // bits updated for rotation scheme
        genStartAddr(new_bank, new_rank);

    } else {
        // increment the column by one
        if (addrMapping == 1)
            // addrMapping=1: RoRaBaCoCh/RoRaBaChCo
            // Simply increment addr by blocksize to increment the column by one
            addr += blocksize;

        else if (addrMapping == 0) {
            // addrMapping=0: RoCoRaBaCh
            // Explicity increment the column bits
            unsigned int new_col = ((addr / blocksize / nbrOfBanksDRAM / nbrOfRanks) %
                                    (pageSize / blocksize)) + 1;
            replaceBits(addr, blockBits + bankBits + rankBits + pageBits - 1,
                        blockBits + bankBits + rankBits, new_col);
        }
    }

    DPRINTF(TrafficGen, "DramRotGen::getNextPacket: %c to addr %x, "
            "size %d, countNumSeqPkts: %d, numSeqPkts: %d\n",
            isRead ? 'r' : 'w', addr, blocksize, countNumSeqPkts, numSeqPkts);

    // create a new request packet
    PacketPtr pkt = getPacket(addr, blocksize,
                              isRead ? MemCmd::ReadReq : MemCmd::WriteReq);

    // add the amount of data manipulated to the total
    dataManipulated += blocksize;

    // subtract the number of packets remained to be generated
    --countNumSeqPkts;

    // return the generated packet
    return pkt;
}

void
DramGen::genStartAddr(unsigned int new_bank, unsigned int new_rank)
{
    // start by picking a random address in the range
    addr = random_mt.random<Addr>(startAddr, endAddr - 1);

    // round down to start address of a block, i.e. a DRAM burst
    addr -= addr % blocksize;

    // insert the bank bits at the right spot, and align the
    // address to achieve the required hit length, this involves
    // finding the appropriate start address such that all
    // sequential packets target successive columns in the same
    // page

    // for example, if we have a stride size of 192B, which means
    // for LPDDR3 where burstsize = 32B we have numSeqPkts = 6,
    // the address generated previously can be such that these
    // 192B cross the page boundary, hence it needs to be aligned
    // so that they all belong to the same page for page hit
    unsigned int columns_per_page = pageSize / blocksize;

    // pick a random column, but ensure that there is room for
    // numSeqPkts sequential columns in the same page
    unsigned int new_col =
        random_mt.random<unsigned int>(0, columns_per_page - numSeqPkts);

    if (addrMapping == 1) {
        // addrMapping=1: RoRaBaCoCh/RoRaBaChCo
        // Block bits, then page bits, then bank bits, then rank bits
        replaceBits(addr, blockBits + pageBits + bankBits - 1,
                    blockBits + pageBits, new_bank);
        replaceBits(addr, blockBits + pageBits - 1, blockBits, new_col);
        if (rankBits != 0) {
            replaceBits(addr, blockBits + pageBits + bankBits +rankBits - 1,
                        blockBits + pageBits + bankBits, new_rank);
        }
    } else if (addrMapping == 0) {
        // addrMapping=0: RoCoRaBaCh
        // Block bits, then bank bits, then rank bits, then page bits
        replaceBits(addr, blockBits + bankBits - 1, blockBits, new_bank);
        replaceBits(addr, blockBits + bankBits + rankBits + pageBits - 1,
                    blockBits + bankBits + rankBits, new_col);
        if (rankBits != 0) {
            replaceBits(addr, blockBits + bankBits + rankBits - 1,
                        blockBits + bankBits, new_rank);
        }
    }
}

Tick
RandomGen::nextPacketTick(bool elastic, Tick delay) const
{
    // Check to see if we have reached the data limit. If dataLimit is
    // zero we do not have a data limit and therefore we will keep
    // generating requests for the entire residency in this state.
    if (dataLimit && dataManipulated >= dataLimit)
    {
        DPRINTF(TrafficGen, "Data limit for RandomGen reached.\n");
        // No more requests. Return MaxTick.
        return MaxTick;
    } else {
        // return the time when the next request should take place
        Tick wait = random_mt.random(minPeriod, maxPeriod);

        // compensate for the delay experienced to not be elastic, by
        // default the value we generate is from the time we are
        // asked, so the elasticity happens automatically
        if (!elastic) {
            if (wait < delay)
                wait = 0;
            else
                wait -= delay;
        }

        return curTick() + wait;
    }
}

TraceGen::InputStream::InputStream(const std::string& filename)
    : trace(filename)
{
    init();
}

void
TraceGen::InputStream::init()
{
    // Create a protobuf message for the header and read it from the stream
    ProtoMessage::PacketHeader header_msg;
    if (!trace.read(header_msg)) {
        panic("Failed to read packet header from trace\n");

        if (header_msg.tick_freq() != SimClock::Frequency) {
            panic("Trace was recorded with a different tick frequency %d\n",
                  header_msg.tick_freq());
        }
    }
}

void
TraceGen::InputStream::reset()
{
    trace.reset();
    init();
}

bool
TraceGen::InputStream::read(TraceElement& element)
{
    ProtoMessage::Packet pkt_msg;
    if (trace.read(pkt_msg)) {
        element.cmd = pkt_msg.cmd();
        element.addr = pkt_msg.addr();
        element.blocksize = pkt_msg.size();
        element.tick = pkt_msg.tick();
        element.flags = pkt_msg.has_flags() ? pkt_msg.flags() : 0;
        return true;
    }

    // We have reached the end of the file
    return false;
}

Tick
TraceGen::nextPacketTick(bool elastic, Tick delay) const
{
    if (traceComplete) {
        DPRINTF(TrafficGen, "No next tick as trace is finished\n");
        // We are at the end of the file, thus we have no more data in
        // the trace Return MaxTick to signal that there will be no
        // more transactions in this active period for the state.
        return MaxTick;
    }

    assert(nextElement.isValid());

    DPRINTF(TrafficGen, "Next packet tick is %d\n", tickOffset +
            nextElement.tick);

    // if the playback is supposed to be elastic, add the delay
    if (elastic)
        tickOffset += delay;

    return std::max(tickOffset + nextElement.tick, curTick());
}

void
TraceGen::enter()
{
    // update the trace offset to the time where the state was entered.
    tickOffset = curTick();

    // clear everything
    currElement.clear();

    // read the first element in the file and set the complete flag
    traceComplete = !trace.read(nextElement);
}

PacketPtr
TraceGen::getNextPacket()
{
    // shift things one step forward
    currElement = nextElement;
    nextElement.clear();

    // read the next element and set the complete flag
    traceComplete = !trace.read(nextElement);

    // it is the responsibility of the traceComplete flag to ensure we
    // always have a valid element here
    assert(currElement.isValid());

    DPRINTF(TrafficGen, "TraceGen::getNextPacket: %c %d %d %d 0x%x\n",
            currElement.cmd.isRead() ? 'r' : 'w',
            currElement.addr,
            currElement.blocksize,
            currElement.tick,
            currElement.flags);

    PacketPtr pkt = getPacket(currElement.addr + addrOffset,
                              currElement.blocksize,
                              currElement.cmd, currElement.flags);

    if (!traceComplete)
        DPRINTF(TrafficGen, "nextElement: %c addr %d size %d tick %d (%d)\n",
                nextElement.cmd.isRead() ? 'r' : 'w',
                nextElement.addr,
                nextElement.blocksize,
                nextElement.tick + tickOffset,
                nextElement.tick);

    return pkt;
}

void
TraceGen::exit()
{
    // Check if we reached the end of the trace file. If we did not
    // then we want to generate a warning stating that not the entire
    // trace was played.
    if (!traceComplete) {
        warn("Trace player %s was unable to replay the entire trace!\n",
             name());
    }

    // Clear any flags and start over again from the beginning of the
    // file
    trace.reset();
}
