/*
 * Copyright (c) 2012-2014 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
 *          Marco Elver
 */

#include "mem/mem_checker_monitor.hh"

#include <memory>

#include "base/logging.hh"
#include "base/output.hh"
#include "base/trace.hh"
#include "debug/MemCheckerMonitor.hh"

MemCheckerMonitor::MemCheckerMonitor(Params* params)
    : SimObject(params),
      masterPort(name() + "-master", *this),
      slavePort(name() + "-slave", *this),
      warnOnly(params->warn_only),
      memchecker(params->memchecker)
{}

MemCheckerMonitor::~MemCheckerMonitor()
{}

MemCheckerMonitor*
MemCheckerMonitorParams::create()
{
    return new MemCheckerMonitor(this);
}

void
MemCheckerMonitor::init()
{
    // make sure both sides of the monitor are connected
    if (!slavePort.isConnected() || !masterPort.isConnected())
        fatal("Communication monitor is not connected on both sides.\n");
}

Port &
MemCheckerMonitor::getPort(const std::string &if_name, PortID idx)
{
    if (if_name == "master" || if_name == "mem_side") {
        return masterPort;
    } else if (if_name == "slave" || if_name == "cpu_side") {
        return slavePort;
    } else {
        return SimObject::getPort(if_name, idx);
    }
}

void
MemCheckerMonitor::recvFunctional(PacketPtr pkt)
{
    Addr addr = pkt->getAddr();
    unsigned size = pkt->getSize();

    // Conservatively reset this address-range. Alternatively we could try to
    // update the values seen by the memchecker, however, there may be other
    // reads/writes to these location from other devices we do not see.
    memchecker->reset(addr, size);

    masterPort.sendFunctional(pkt);

    DPRINTF(MemCheckerMonitor,
            "Forwarded functional access: addr = %#llx, size = %d\n",
            addr, size);
}

void
MemCheckerMonitor::recvFunctionalSnoop(PacketPtr pkt)
{
    Addr addr = pkt->getAddr();
    unsigned size = pkt->getSize();

    // See above.
    memchecker->reset(addr, size);

    slavePort.sendFunctionalSnoop(pkt);

    DPRINTF(MemCheckerMonitor,
            "Received functional snoop: addr = %#llx, size = %d\n",
            addr, size);
}

Tick
MemCheckerMonitor::recvAtomic(PacketPtr pkt)
{
    panic("Atomic not supported");
}

Tick
MemCheckerMonitor::recvAtomicSnoop(PacketPtr pkt)
{
    panic("Atomic not supported");
}

bool
MemCheckerMonitor::recvTimingReq(PacketPtr pkt)
{
    // should always see a request
    assert(pkt->isRequest());

    // Store relevant fields of packet, because packet may be modified
    // or even deleted when sendTiming() is called.
    //
    // For reads we are only interested in real reads, and not prefetches, as
    // it is not guaranteed that the prefetch returns any useful data.
    bool is_read = pkt->isRead() && !pkt->req->isPrefetch();
    bool is_write = pkt->isWrite();
    unsigned size = pkt->getSize();
    Addr addr = pkt->getAddr();
    bool expects_response = pkt->needsResponse() && !pkt->cacheResponding();
    std::unique_ptr<uint8_t[]> pkt_data;
    MemCheckerMonitorSenderState* state = NULL;

    if (expects_response && is_write) {
        // On receipt of a request, only need to allocate pkt_data if this is a
        // write. For reads, we have no data yet, so it doesn't make sense to
        // allocate.
        pkt_data.reset(new uint8_t[size]);
        pkt->writeData(pkt_data.get());
    }

    // If a cache miss is served by a cache, a monitor near the memory
    // would see a request which needs a response, but this response
    // would not come back from the memory. Therefore
    // we additionally have to check the inhibit flag.
    if (expects_response && (is_read || is_write)) {
        state = new MemCheckerMonitorSenderState(0);
        pkt->pushSenderState(state);
    }

    // Attempt to send the packet
    bool successful = masterPort.sendTimingReq(pkt);

    // If not successful, restore the sender state
    if (!successful && expects_response && (is_read || is_write)) {
        delete pkt->popSenderState();
    }

    if (successful && expects_response) {
        if (is_read) {
            MemChecker::Serial serial = memchecker->startRead(curTick(),
                                                              addr,
                                                              size);

            // At the time where we push the sender-state, we do not yet know
            // the serial the MemChecker class will assign to this request. We
            // cannot call startRead at the time we push the sender-state, as
            // the masterPort may not be successful in executing sendTimingReq,
            // and in case of a failure, we must not modify the state of the
            // MemChecker.
            //
            // Once we know that sendTimingReq was successful, we can set the
            // serial of the newly constructed sender-state. This is legal, as
            // we know that nobody else will touch nor is responsible for
            // deletion of our sender-state.
            state->serial = serial;

            DPRINTF(MemCheckerMonitor,
                    "Forwarded read request: serial = %d, addr = %#llx, "
                    "size = %d\n",
                    serial, addr, size);
        } else if (is_write) {
            MemChecker::Serial serial = memchecker->startWrite(curTick(),
                                                               addr,
                                                               size,
                                                               pkt_data.get());

            state->serial = serial;

            DPRINTF(MemCheckerMonitor,
                    "Forwarded write request: serial = %d, addr = %#llx, "
                    "size = %d\n",
                    serial, addr, size);
        } else {
            DPRINTF(MemCheckerMonitor,
                    "Forwarded non read/write request: addr = %#llx\n", addr);
        }
    } else if (successful) {
        DPRINTF(MemCheckerMonitor,
                "Forwarded request marked for cache response: addr = %#llx\n",
                addr);
    }

    return successful;
}

bool
MemCheckerMonitor::recvTimingResp(PacketPtr pkt)
{
    // should always see responses
    assert(pkt->isResponse());

    // Store relevant fields of packet, because packet may be modified
    // or even deleted when sendTiming() is called.
    bool is_read = pkt->isRead() && !pkt->req->isPrefetch();
    bool is_write = pkt->isWrite();
    bool is_failed_LLSC = pkt->isLLSC() && pkt->req->getExtraData() == 0;
    unsigned size = pkt->getSize();
    Addr addr = pkt->getAddr();
    std::unique_ptr<uint8_t[]> pkt_data;
    MemCheckerMonitorSenderState* received_state = NULL;

    if (is_read) {
        // On receipt of a response, only need to allocate pkt_data if this is
        // a read. For writes, we have already given the MemChecker the data on
        // the request, so it doesn't make sense to allocate on write.
        pkt_data.reset(new uint8_t[size]);
        pkt->writeData(pkt_data.get());
    }

    if (is_read || is_write) {
        received_state =
            dynamic_cast<MemCheckerMonitorSenderState*>(pkt->senderState);

        // Restore initial sender state
        panic_if(received_state == NULL,
                 "Monitor got a response without monitor sender state\n");

        // Restore the state
        pkt->senderState = received_state->predecessor;
    }

    // Attempt to send the packet
    bool successful = slavePort.sendTimingResp(pkt);

    // If packet successfully send, complete transaction in MemChecker
    // instance, and delete sender state, otherwise restore state.
    if (successful) {
        if (is_read) {
            DPRINTF(MemCheckerMonitor,
                    "Received read response: serial = %d, addr = %#llx, "
                    "size = %d\n",
                    received_state->serial, addr, size);

            bool result = memchecker->completeRead(received_state->serial,
                                                   curTick(),
                                                   addr,
                                                   size,
                                                   pkt_data.get());

            if (!result) {
                warn("%s: read of %#llx @ cycle %d failed:\n%s\n",
                     name(),
                     addr, curTick(),
                     memchecker->getErrorMessage().c_str());

                panic_if(!warnOnly, "MemChecker violation!");
            }

            delete received_state;
        } else if (is_write) {
            DPRINTF(MemCheckerMonitor,
                    "Received write response: serial = %d, addr = %#llx, "
                    "size = %d\n",
                    received_state->serial, addr, size);

            if (is_failed_LLSC) {
                // The write was not successful, let MemChecker know.
                memchecker->abortWrite(received_state->serial,
                                       addr,
                                       size);
            } else {
                memchecker->completeWrite(received_state->serial,
                                          curTick(),
                                          addr,
                                          size);
            }

            delete received_state;
        } else {
            DPRINTF(MemCheckerMonitor,
                    "Received non read/write response: addr = %#llx\n", addr);
        }
    } else if (is_read || is_write) {
        // Don't delete anything and let the packet look like we
        // did not touch it
        pkt->senderState = received_state;
    }

    return successful;
}

void
MemCheckerMonitor::recvTimingSnoopReq(PacketPtr pkt)
{
    slavePort.sendTimingSnoopReq(pkt);
}

bool
MemCheckerMonitor::recvTimingSnoopResp(PacketPtr pkt)
{
    return masterPort.sendTimingSnoopResp(pkt);
}

bool
MemCheckerMonitor::isSnooping() const
{
    // check if the connected master port is snooping
    return slavePort.isSnooping();
}

AddrRangeList
MemCheckerMonitor::getAddrRanges() const
{
    // get the address ranges of the connected slave port
    return masterPort.getAddrRanges();
}

void
MemCheckerMonitor::recvReqRetry()
{
    slavePort.sendRetryReq();
}

void
MemCheckerMonitor::recvRespRetry()
{
    masterPort.sendRetryResp();
}

void
MemCheckerMonitor::recvRangeChange()
{
    slavePort.sendRangeChange();
}
