/*
 * 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),
      memSidePort(name() + "-memSidePort", *this),
      cpuSidePort(name() + "-cpuSidePort", *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 (!cpuSidePort.isConnected() || !memSidePort.isConnected())
        fatal("Communication monitor is not connected on both sides.\n");
}

Port &
MemCheckerMonitor::getPort(const std::string &if_name, PortID idx)
{
    if (if_name == "request" || if_name == "mem_side_port") {
        return memSidePort;
    } else if (if_name == "response" || if_name == "cpu_side_port") {
        return cpuSidePort;
    } 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);

    memSidePort.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);

    cpuSidePort.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 = memSidePort.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 memSidePort 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 = cpuSidePort.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)
{
    cpuSidePort.sendTimingSnoopReq(pkt);
}

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

bool
MemCheckerMonitor::isSnooping() const
{
    // check if the connected memSidePort is snooping
    return cpuSidePort.isSnooping();
}

AddrRangeList
MemCheckerMonitor::getAddrRanges() const
{
    // get the address ranges of the connected cpuSidePort
    return memSidePort.getAddrRanges();
}

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

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

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