/*
 * 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.
 */

#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();
}
