/*
 * Copyright (c) 2012 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: Andreas Hansson
 */

#include "mem/addr_mapper.hh"

AddrMapper::AddrMapper(const AddrMapperParams* p)
    : SimObject(p),
      masterPort(name() + "-master", *this),
      slavePort(name() + "-slave", *this)
{
}

void
AddrMapper::init()
{
    if (!slavePort.isConnected() || !masterPort.isConnected())
        fatal("Address mapper is not connected on both sides.\n");
}

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

void
AddrMapper::recvFunctional(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    masterPort.sendFunctional(pkt);
    pkt->setAddr(orig_addr);
}

void
AddrMapper::recvFunctionalSnoop(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    slavePort.sendFunctionalSnoop(pkt);
    pkt->setAddr(orig_addr);
}

Tick
AddrMapper::recvAtomic(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    Tick ret_tick =  masterPort.sendAtomic(pkt);
    pkt->setAddr(orig_addr);
    return ret_tick;
}

Tick
AddrMapper::recvAtomicSnoop(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    pkt->setAddr(remapAddr(orig_addr));
    Tick ret_tick = slavePort.sendAtomicSnoop(pkt);
    pkt->setAddr(orig_addr);
    return ret_tick;
}

bool
AddrMapper::recvTimingReq(PacketPtr pkt)
{
    Addr orig_addr = pkt->getAddr();
    bool needsResponse = pkt->needsResponse();
    bool cacheResponding = pkt->cacheResponding();

    if (needsResponse && !cacheResponding) {
        pkt->pushSenderState(new AddrMapperSenderState(orig_addr));
    }

    pkt->setAddr(remapAddr(orig_addr));

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

    // If not successful, restore the address and sender state
    if (!successful) {
        pkt->setAddr(orig_addr);

        if (needsResponse) {
            delete pkt->popSenderState();
        }
    }

    return successful;
}

bool
AddrMapper::recvTimingResp(PacketPtr pkt)
{
    AddrMapperSenderState* receivedState =
        dynamic_cast<AddrMapperSenderState*>(pkt->senderState);

    // Restore initial sender state
    if (receivedState == NULL)
        panic("AddrMapper %s got a response without sender state\n",
              name());

    Addr remapped_addr = pkt->getAddr();

    // Restore the state and address
    pkt->senderState = receivedState->predecessor;
    pkt->setAddr(receivedState->origAddr);

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

    // If packet successfully sent, delete the sender state, otherwise
    // restore state
    if (successful) {
        delete receivedState;
    } else {
        // Don't delete anything and let the packet look like we did
        // not touch it
        pkt->senderState = receivedState;
        pkt->setAddr(remapped_addr);
    }
    return successful;
}

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

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

bool
AddrMapper::isSnooping() const
{
    if (slavePort.isSnooping())
        fatal("AddrMapper doesn't support remapping of snooping requests\n");
    return false;
}

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

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

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

RangeAddrMapper::RangeAddrMapper(const RangeAddrMapperParams* p) :
    AddrMapper(p),
    originalRanges(p->original_ranges),
    remappedRanges(p->remapped_ranges)
{
    if (originalRanges.size() != remappedRanges.size())
        fatal("AddrMapper: original and shadowed range list must "
              "be same size\n");

    for (size_t x = 0; x < originalRanges.size(); x++) {
        if (originalRanges[x].size() != remappedRanges[x].size())
            fatal("AddrMapper: original and shadowed range list elements"
                  " aren't all of the same size\n");
    }
}

RangeAddrMapper*
RangeAddrMapperParams::create()
{
    return new RangeAddrMapper(this);
}

Addr
RangeAddrMapper::remapAddr(Addr addr) const
{
    for (int i = 0; i < originalRanges.size(); ++i) {
        if (originalRanges[i].contains(addr)) {
            Addr offset = addr - originalRanges[i].start();
            return offset + remappedRanges[i].start();
        }
    }

    return addr;
}

AddrRangeList
RangeAddrMapper::getAddrRanges() const
{
    // Simply return the original ranges as given by the parameters
    AddrRangeList ranges(originalRanges.begin(), originalRanges.end());
    return ranges;
}


