/*
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * For use for simulation and test purposes only
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Tuan Ta
 */

#include "cpu/testers/gpu_ruby_test/Thread.hh"

#include <fstream>

#include "debug/ProtocolTest.hh"

Thread::Thread(const Params* p)
      : ClockedObject(p),
        threadEvent(this, "Thread tick"),
        deadlockCheckEvent(this),
        threadId(p->thread_id),
        numLanes(p->num_lanes),
        deadlockThreshold(p->deadlock_threshold)
{
    tester = nullptr;       // set by attachThreadToPorts()
    addrManager = nullptr;  // set by attachThreadToPorts()
    port = nullptr;         // set by attachThreadToPorts()
    scalarPort = nullptr;  // set by attachThreadToPorts()
    sqcPort = nullptr;     // set by attachThreadToPorts()

    curEpisode = nullptr;
    curAction = nullptr;

    pendingLdStCount = 0;
    pendingFenceCount = 0;
    pendingAtomicCount = 0;

    lastActiveCycle = Cycles(0);
}

Thread::~Thread()
{
    for (auto ep : episodeHistory) {
        assert(ep != nullptr);
        delete ep;
    }
}

void
Thread::wakeup()
{
    // this thread is waken up by one of the following events
    //      - hitCallback is called
    //      - a new episode is created

    // check if this is the first episode in this thread
    if (curEpisode == nullptr) {
        issueNewEpisode();
        assert(curEpisode);
    }

    if (isNextActionReady()) {
        // isNextActionReady should check if the action list is empty
        assert(curAction != nullptr);

        // issue the next action
        issueNextAction();
    } else {
        // check for completion of the current episode
        // completion = no outstanding requests + not having more actions
        if (!curEpisode->hasMoreActions() &&
            pendingLdStCount == 0 &&
            pendingFenceCount == 0 &&
            pendingAtomicCount == 0) {

            curEpisode->completeEpisode();

            // check if it's time to stop the tester
            if (tester->checkExit()) {
                // no more event is scheduled for this thread
                return;
            }

            // issue the next episode
            issueNewEpisode();
            assert(curEpisode);

            // now we get a new episode
            // let's wake up the thread in the next cycle
            if (!threadEvent.scheduled()) {
                scheduleWakeup();
            }
        }
    }
}

void
Thread::scheduleWakeup()
{
    assert(!threadEvent.scheduled());
    schedule(threadEvent, nextCycle());
}

void
Thread::scheduleDeadlockCheckEvent()
{
    // after this first schedule, the deadlock event is scheduled by itself
    assert(!deadlockCheckEvent.scheduled());
    schedule(deadlockCheckEvent, nextCycle());
}

void
Thread::attachThreadToPorts(ProtocolTester *_tester,
                            ProtocolTester::SeqPort *_port,
                            ProtocolTester::SeqPort *_scalarPort,
                            ProtocolTester::SeqPort *_sqcPort)
{
    tester = _tester;
    port = _port;
    scalarPort = _scalarPort;
    sqcPort = _sqcPort;

    assert(tester && port);
    addrManager = tester->getAddressManager();
    assert(addrManager);
}

void
Thread::issueNewEpisode()
{
    int num_reg_loads = random() % tester->getEpisodeLength();
    int num_reg_stores = tester->getEpisodeLength() - num_reg_loads;

    // create a new episode
    curEpisode = new Episode(tester, this, num_reg_loads, num_reg_stores);
    episodeHistory.push_back(curEpisode);
}

bool
Thread::isNextActionReady()
{
    if (!curEpisode->hasMoreActions()) {
        return false;
    } else {
        curAction = curEpisode->peekCurAction();

        switch(curAction->getType()) {
            case Episode::Action::Type::ATOMIC:
                // an atomic action must wait for all previous requests
                // to complete
                if (pendingLdStCount == 0 &&
                    pendingFenceCount == 0 &&
                    pendingAtomicCount == 0) {
                    return true;
                }

                return false;
            case Episode::Action::Type::ACQUIRE:
                // we should not see any outstanding ld_st or fence here
                assert(pendingLdStCount == 0 &&
                       pendingFenceCount == 0);

                // an acquire action must wait for all previous atomic
                // requests to complete
                if (pendingAtomicCount == 0) {
                    return true;
                }

                return false;
            case Episode::Action::Type::RELEASE:
                // we should not see any outstanding atomic or fence here
                assert(pendingAtomicCount == 0 &&
                       pendingFenceCount == 0);

                // a release action must wait for all previous ld/st
                // requests to complete
                if (pendingLdStCount == 0) {
                    return true;
                }

                return false;
            case Episode::Action::Type::LOAD:
            case Episode::Action::Type::STORE:
                // we should not see any outstanding atomic here
                assert(pendingAtomicCount == 0);

                // can't issue if there is a pending fence
                if (pendingFenceCount > 0) {
                    return false;
                }

                // a Load or Store is ready if it doesn't overlap
                // with any outstanding request
                for (int lane = 0; lane < numLanes; ++lane) {
                    Location loc = curAction->getLocation(lane);

                    if (loc != AddressManager::INVALID_LOCATION) {
                        Addr addr = addrManager->getAddress(loc);

                        if (outstandingLoads.find(addr) !=
                            outstandingLoads.end()) {
                            return false;
                        }

                        if (outstandingStores.find(addr) !=
                            outstandingStores.end()) {
                            return false;
                        }

                        if (outstandingAtomics.find(addr) !=
                            outstandingAtomics.end()) {
                            // this is not an atomic action, so the address
                            // should not be in outstandingAtomics list
                            assert(false);
                        }
                    }
                }

                return true;
            default:
                panic("The tester got an invalid action\n");
        }
    }
}

void
Thread::issueNextAction()
{
    switch(curAction->getType()) {
        case Episode::Action::Type::ATOMIC:
            issueAtomicOps();
            break;
        case Episode::Action::Type::ACQUIRE:
            issueAcquireOp();
            break;
        case Episode::Action::Type::RELEASE:
            issueReleaseOp();
            break;
        case Episode::Action::Type::LOAD:
            issueLoadOps();
            break;
        case Episode::Action::Type::STORE:
            issueStoreOps();
            break;
        default:
            panic("The tester got an invalid action\n");
    }

    // the current action has been issued, pop it from the action list
    curEpisode->popAction();
    lastActiveCycle = curCycle();

    // we may be able to schedule the next action
    // just wake up this thread in the next cycle
    if (!threadEvent.scheduled()) {
        scheduleWakeup();
    }
}

void
Thread::addOutstandingReqs(OutstandingReqTable& req_table, Addr address,
                           int lane, Location loc, Value stored_val)
{
    OutstandingReqTable::iterator it = req_table.find(address);
    OutstandingReq req(lane, loc, stored_val, curCycle());

    if (it == req_table.end()) {
        // insert a new list of requests for this address
        req_table.insert(std::pair<Addr, OutstandingReqList>(address,
                                                OutstandingReqList(1, req)));
    } else {
        // add a new request
        (it->second).push_back(req);
    }
}

Thread::OutstandingReq
Thread::popOutstandingReq(OutstandingReqTable& req_table, Addr addr)
{
    OutstandingReqTable::iterator it = req_table.find(addr);

    // there must be exactly one list of requests for this address in the table
    assert(it != req_table.end());

    // get the request list
    OutstandingReqList& req_list = it->second;
    assert(!req_list.empty());

    // save a request
    OutstandingReq ret_req = req_list.back();

    // remove the request from the list
    req_list.pop_back();

    // if the list is now empty, remove it from req_table
    if (req_list.empty()) {
        req_table.erase(it);
    }

    return ret_req;
}

void
Thread::validateAtomicResp(Location loc, int lane, Value ret_val)
{
    if (!addrManager->validateAtomicResp(loc, ret_val)) {
        std::stringstream ss;
        Addr addr = addrManager->getAddress(loc);

        // basic info
        ss << threadName << ": Atomic Op returned unexpected value\n"
           << "\tEpisode " << curEpisode->getEpisodeId() << "\n"
           << "\tLane ID " << lane << "\n"
           << "\tAddress " << printAddress(addr) << "\n"
           << "\tAtomic Op's return value " << ret_val << "\n";

        // print out basic info
        warn("%s\n", ss.str());

        // TODO add more detailed info

        // dump all error info and exit the simulation
        tester->dumpErrorLog(ss);
    }
}

void
Thread::validateLoadResp(Location loc, int lane, Value ret_val)
{
    if (ret_val != addrManager->getLoggedValue(loc)) {
        std::stringstream ss;
        Addr addr = addrManager->getAddress(loc);

        // basic info
        ss << threadName << ": Loaded value is not consistent with "
           << "the last stored value\n"
           << "\tThread " << threadId << "\n"
           << "\tEpisode " << curEpisode->getEpisodeId() << "\n"
           << "\tLane ID " << lane << "\n"
           << "\tAddress " << printAddress(addr) << "\n"
           << "\tLoaded value " << ret_val << "\n"
           << "\tLast writer " << addrManager->printLastWriter(loc) << "\n";

        // print out basic info
        warn("%s\n", ss.str());

        // TODO add more detailed info

        // dump all error info and exit the simulation
        tester->dumpErrorLog(ss);
    }
}

bool
Thread::checkDRF(Location atomic_loc, Location loc, bool isStore) const
{
    if (curEpisode && curEpisode->isEpsActive()) {
        // check against the current episode this thread is executing
        return curEpisode->checkDRF(atomic_loc, loc, isStore, numLanes);
    }

    return true;
}

void
Thread::checkDeadlock()
{
    if ((curCycle() - lastActiveCycle) > deadlockThreshold) {
        // deadlock detected
        std::stringstream ss;

        ss << threadName << ": Deadlock detected\n"
           << "\tLast active cycle: " <<  lastActiveCycle << "\n"
           << "\tCurrent cycle: " << curCycle() << "\n"
           << "\tDeadlock threshold: " << deadlockThreshold << "\n";

        // print out basic info
        warn("%s\n", ss.str());

        // dump all error info and exit the simulation
        tester->dumpErrorLog(ss);
    } else if (!tester->checkExit()) {
        // schedule a future deadlock check event
        assert(!deadlockCheckEvent.scheduled());
        schedule(deadlockCheckEvent,
                 deadlockThreshold * clockPeriod() + curTick());
    }
}

void
Thread::printOutstandingReqs(const OutstandingReqTable& table,
                             std::stringstream& ss) const
{
    Cycles cur_cycle = curCycle();

    for (const auto& m : table) {
        for (const auto& req : m.second) {
            ss << "\t\t\tAddr " << printAddress(m.first)
               << ": delta (curCycle - issueCycle) = "
               << (cur_cycle - req.issueCycle) << std::endl;
        }
    }
}

void
Thread::printAllOutstandingReqs(std::stringstream& ss) const
{
    // dump all outstanding requests of this thread
    ss << "\t\tOutstanding Loads:\n";
    printOutstandingReqs(outstandingLoads, ss);
    ss << "\t\tOutstanding Stores:\n";
    printOutstandingReqs(outstandingStores, ss);
    ss << "\t\tOutstanding Atomics:\n";
    printOutstandingReqs(outstandingAtomics, ss);
    ss << "\t\tNumber of outstanding acquires & releases: "
       << pendingFenceCount << std::endl;
}
