/*
 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
 * 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.
 */

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

using namespace std;

// randomize so that handoffs are not locality-aware
#if 0
int persistent_randomize[] = {0, 4, 8, 12, 1, 5, 9, 13, 2, 6,
                              10, 14, 3, 7, 11, 15};
int persistent_randomize[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
                              10, 11, 12, 13, 14, 15};
#endif

PersistentTable::PersistentTable()
{
}

PersistentTable::~PersistentTable()
{
}

void
PersistentTable::persistentRequestLock(const Address& address,
                                       MachineID locker,
                                       AccessType type)
{
#if 0
    if (locker == m_chip_ptr->getID())
        cout << "Chip " << m_chip_ptr->getID() << ": " << llocker
             << " requesting lock for " << address << endl;

    MachineID locker = (MachineID) persistent_randomize[llocker];
#endif

    assert(address == line_address(address));

    static const PersistentTableEntry dflt;
    pair<AddressMap::iterator, bool> r =
        m_map.insert(AddressMap::value_type(address, dflt));
    bool present = !r.second;
    AddressMap::iterator i = r.first;
    PersistentTableEntry &entry = i->second;

    if (present) {
        // Make sure we're not already in the locked set
        assert(!(entry.m_starving.isElement(locker)));
    }

    entry.m_starving.add(locker);
    if (type == AccessType_Write)
        entry.m_request_to_write.add(locker);

    if (present)
        assert(entry.m_marked.isSubset(entry.m_starving));
}

void
PersistentTable::persistentRequestUnlock(const Address& address,
                                         MachineID unlocker)
{
#if 0
    if (unlocker == m_chip_ptr->getID())
        cout << "Chip " << m_chip_ptr->getID() << ": " << uunlocker
             << " requesting unlock for " << address << endl;

    MachineID unlocker = (MachineID) persistent_randomize[uunlocker];
#endif

    assert(address == line_address(address));
    assert(m_map.count(address));
    PersistentTableEntry& entry = m_map[address];

    //
    // Make sure we're in the locked set
    //
    assert(entry.m_starving.isElement(unlocker));
    assert(entry.m_marked.isSubset(entry.m_starving));
    entry.m_starving.remove(unlocker);
    entry.m_marked.remove(unlocker);
    entry.m_request_to_write.remove(unlocker);
    assert(entry.m_marked.isSubset(entry.m_starving));

    // Deallocate if empty
    if (entry.m_starving.isEmpty()) {
        assert(entry.m_marked.isEmpty());
        m_map.erase(address);
    }
}

bool
PersistentTable::okToIssueStarving(const Address& address,
                                   MachineID machId) const
{
    assert(address == line_address(address));

    AddressMap::const_iterator i = m_map.find(address);
    if (i == m_map.end()) {
        // No entry present
        return true;
    }

    const PersistentTableEntry &entry = i->second;

    if (entry.m_starving.isElement(machId)) {
        // We can't issue another lockdown until are previous unlock
        // has occurred
        return false;
    }

    return entry.m_marked.isEmpty();
}

MachineID
PersistentTable::findSmallest(const Address& address) const
{
    assert(address == line_address(address));
    AddressMap::const_iterator i = m_map.find(address);
    assert(i != m_map.end());
    const PersistentTableEntry& entry = i->second;
    return entry.m_starving.smallestElement();
}

AccessType
PersistentTable::typeOfSmallest(const Address& address) const
{
    assert(address == line_address(address));
    AddressMap::const_iterator i = m_map.find(address);
    assert(i != m_map.end());
    const PersistentTableEntry& entry = i->second;
    if (entry.m_request_to_write.
        isElement(entry.m_starving.smallestElement())) {
        return AccessType_Write;
    } else {
        return AccessType_Read;
    }
}

void
PersistentTable::markEntries(const Address& address)
{
    assert(address == line_address(address));
    AddressMap::iterator i = m_map.find(address);
    if (i == m_map.end())
        return;

    PersistentTableEntry& entry = i->second;

    // None should be marked
    assert(entry.m_marked.isEmpty());

    // Mark all the nodes currently in the table
    entry.m_marked = entry.m_starving;
}

bool
PersistentTable::isLocked(const Address& address) const
{
    assert(address == line_address(address));

    // If an entry is present, it must be locked
    return m_map.count(address) > 0;
}

int
PersistentTable::countStarvingForAddress(const Address& address) const
{
    assert(address == line_address(address));
    AddressMap::const_iterator i = m_map.find(address);
    if (i == m_map.end())
        return 0;

    const PersistentTableEntry& entry = i->second;
    return entry.m_starving.count();
}

int
PersistentTable::countReadStarvingForAddress(const Address& address) const
{
    assert(address == line_address(address));
    AddressMap::const_iterator i = m_map.find(address);
    if (i == m_map.end())
        return 0;

    const PersistentTableEntry& entry = i->second;
    return entry.m_starving.count() - entry.m_request_to_write.count();
}

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

