/*
 * Copyright (c) 2017 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.
 *
 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
 * Copyright (c) 2017 Google Inc.
 * All rights reserved.
 *
 * 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: Lena Olson
 */

#include "mem/ruby/structures/DirectoryMemory.hh"

#include "base/addr_range.hh"
#include "base/intmath.hh"
#include "debug/RubyCache.hh"
#include "debug/RubyStats.hh"
#include "mem/ruby/slicc_interface/RubySlicc_Util.hh"
#include "mem/ruby/system/RubySystem.hh"
#include "sim/system.hh"

using namespace std;

DirectoryMemory::DirectoryMemory(const Params *p)
    : SimObject(p), addrRanges(p->addr_ranges.begin(), p->addr_ranges.end())
{
    m_size_bytes = 0;
    for (const auto &r: addrRanges) {
        m_size_bytes += r.size();
    }
    m_size_bits = floorLog2(m_size_bytes);
    m_num_entries = 0;
}

void
DirectoryMemory::init()
{
    m_num_entries = m_size_bytes / RubySystem::getBlockSizeBytes();
    m_entries = new AbstractCacheEntry*[m_num_entries];
    for (int i = 0; i < m_num_entries; i++)
        m_entries[i] = NULL;
}

DirectoryMemory::~DirectoryMemory()
{
    // free up all the directory entries
    for (uint64_t i = 0; i < m_num_entries; i++) {
        if (m_entries[i] != NULL) {
            delete m_entries[i];
        }
    }
    delete [] m_entries;
}

bool
DirectoryMemory::isPresent(Addr address)
{
    for (const auto& r: addrRanges) {
        if (r.contains(address)) {
            return true;
        }
    }
    return false;
}

uint64_t
DirectoryMemory::mapAddressToLocalIdx(Addr address)
{
    uint64_t ret = 0;
    for (const auto& r: addrRanges) {
        if (r.contains(address)) {
            ret += r.getOffset(address);
            break;
        }
        ret += r.size();
    }
    return ret >> RubySystem::getBlockSizeBits();
}

AbstractCacheEntry*
DirectoryMemory::lookup(Addr address)
{
    assert(isPresent(address));
    DPRINTF(RubyCache, "Looking up address: %#x\n", address);

    uint64_t idx = mapAddressToLocalIdx(address);
    assert(idx < m_num_entries);
    return m_entries[idx];
}

AbstractCacheEntry*
DirectoryMemory::allocate(Addr address, AbstractCacheEntry *entry)
{
    assert(isPresent(address));
    uint64_t idx;
    DPRINTF(RubyCache, "Looking up address: %#x\n", address);

    idx = mapAddressToLocalIdx(address);
    assert(idx < m_num_entries);
    entry->changePermission(AccessPermission_Read_Only);
    m_entries[idx] = entry;

    return entry;
}

void
DirectoryMemory::print(ostream& out) const
{
}

void
DirectoryMemory::recordRequestType(DirectoryRequestType requestType) {
    DPRINTF(RubyStats, "Recorded statistic: %s\n",
            DirectoryRequestType_to_string(requestType));
}

DirectoryMemory *
RubyDirectoryMemoryParams::create()
{
    return new DirectoryMemory(this);
}
