/*
 * Copyright (c) 2004-2005 The Regents of The University of Michigan
 * 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 <vector>

#include "cpu/o3/rename_map.hh"

using namespace std;

// Todo: Consider making functions inline.  Avoid having things that are
// using the zero register or misc registers from adding on the registers
// to the free list.  Possibly remove the direct communication between
// this and the freelist.  Considering making inline bool functions that
// determine if the register is a logical int, logical fp, physical int,
// physical fp, etc.

SimpleRenameMap::SimpleRenameMap(unsigned _numLogicalIntRegs,
                                 unsigned _numPhysicalIntRegs,
                                 unsigned _numLogicalFloatRegs,
                                 unsigned _numPhysicalFloatRegs,
                                 unsigned _numMiscRegs,
                                 RegIndex _intZeroReg,
                                 RegIndex _floatZeroReg)
    : numLogicalIntRegs(_numLogicalIntRegs),
      numPhysicalIntRegs(_numPhysicalIntRegs),
      numLogicalFloatRegs(_numLogicalFloatRegs),
      numPhysicalFloatRegs(_numPhysicalFloatRegs),
      numMiscRegs(_numMiscRegs),
      intZeroReg(_intZeroReg),
      floatZeroReg(_floatZeroReg)
{
    DPRINTF(Rename, "Rename: Creating rename map.  Phys: %i / %i, Float: "
            "%i / %i.\n", numLogicalIntRegs, numPhysicalIntRegs,
            numLogicalFloatRegs, numPhysicalFloatRegs);

    numLogicalRegs = numLogicalIntRegs + numLogicalFloatRegs;

    numPhysicalRegs = numPhysicalIntRegs + numPhysicalFloatRegs;

    //Create the rename maps, and their scoreboards.
    intRenameMap = new RenameEntry[numLogicalIntRegs];
    floatRenameMap = new RenameEntry[numLogicalRegs];

    // Should combine this into one scoreboard.
    intScoreboard.resize(numPhysicalIntRegs);
    floatScoreboard.resize(numPhysicalRegs);
    miscScoreboard.resize(numPhysicalRegs + numMiscRegs);

    // Initialize the entries in the integer rename map to point to the
    // physical registers of the same index, and consider each register
    // ready until the first rename occurs.
    for (RegIndex index = 0; index < numLogicalIntRegs; ++index)
    {
        intRenameMap[index].physical_reg = index;
        intScoreboard[index] = 1;
    }

    // Initialize the rest of the physical registers (the ones that don't
    // directly map to a logical register) as unready.
    for (PhysRegIndex index = numLogicalIntRegs;
         index < numPhysicalIntRegs;
         ++index)
    {
        intScoreboard[index] = 0;
    }

    int float_reg_idx = numPhysicalIntRegs;

    // Initialize the entries in the floating point rename map to point to
    // the physical registers of the same index, and consider each register
    // ready until the first rename occurs.
    // Although the index refers purely to architected registers, because
    // the floating reg indices come after the integer reg indices, they
    // may exceed the size of a normal RegIndex (short).
    for (PhysRegIndex index = numLogicalIntRegs;
         index < numLogicalRegs; ++index)
    {
        floatRenameMap[index].physical_reg = float_reg_idx++;
    }

    for (PhysRegIndex index = numPhysicalIntRegs;
         index < numPhysicalIntRegs + numLogicalFloatRegs; ++index)
    {
        floatScoreboard[index] = 1;
    }

    // Initialize the rest of the physical registers (the ones that don't
    // directly map to a logical register) as unready.
    for (PhysRegIndex index = numPhysicalIntRegs + numLogicalFloatRegs;
         index < numPhysicalRegs;
         ++index)
    {
        floatScoreboard[index] = 0;
    }

    // Initialize the entries in the misc register scoreboard to be ready.
    for (PhysRegIndex index = numPhysicalRegs;
         index < numPhysicalRegs + numMiscRegs; ++index)
    {
        miscScoreboard[index] = 1;
    }
}

SimpleRenameMap::~SimpleRenameMap()
{
    // Delete the rename maps as they were allocated with new.
    delete [] intRenameMap;
    delete [] floatRenameMap;
}

void
SimpleRenameMap::setFreeList(SimpleFreeList *fl_ptr)
{
    //Setup the interface to the freelist.
    freeList = fl_ptr;
}


// Don't allow this stage to fault; force that check to the rename stage.
// Simply ask to rename a logical register and get back a new physical
// register index.
SimpleRenameMap::RenameInfo
SimpleRenameMap::rename(RegIndex arch_reg)
{
    PhysRegIndex renamed_reg;
    PhysRegIndex prev_reg;

    if (arch_reg < numLogicalIntRegs) {

        // Record the current physical register that is renamed to the
        // requested architected register.
        prev_reg = intRenameMap[arch_reg].physical_reg;

        // If it's not referencing the zero register, then mark the register
        // as not ready.
        if (arch_reg != intZeroReg) {
            // Get a free physical register to rename to.
            renamed_reg = freeList->getIntReg();

            // Update the integer rename map.
            intRenameMap[arch_reg].physical_reg = renamed_reg;

            assert(renamed_reg >= 0 && renamed_reg < numPhysicalIntRegs);

            // Mark register as not ready.
            intScoreboard[renamed_reg] = false;
        } else {
            // Otherwise return the zero register so nothing bad happens.
            renamed_reg = intZeroReg;
        }
    } else if (arch_reg < numLogicalRegs) {
        // Subtract off the base offset for floating point registers.
//        arch_reg = arch_reg - numLogicalIntRegs;

        // Record the current physical register that is renamed to the
        // requested architected register.
        prev_reg = floatRenameMap[arch_reg].physical_reg;

        // If it's not referencing the zero register, then mark the register
        // as not ready.
        if (arch_reg != floatZeroReg) {
            // Get a free floating point register to rename to.
            renamed_reg = freeList->getFloatReg();

            // Update the floating point rename map.
            floatRenameMap[arch_reg].physical_reg = renamed_reg;

            assert(renamed_reg < numPhysicalRegs &&
                   renamed_reg >= numPhysicalIntRegs);

            // Mark register as not ready.
            floatScoreboard[renamed_reg] = false;
        } else {
            // Otherwise return the zero register so nothing bad happens.
            renamed_reg = floatZeroReg;
        }
    } else {
        // Subtract off the base offset for miscellaneous registers.
        arch_reg = arch_reg - numLogicalRegs;

        // No renaming happens to the misc. registers.  They are simply the
        // registers that come after all the  physical registers; thus
        // take the base architected register and add the physical registers
        // to it.
        renamed_reg = arch_reg + numPhysicalRegs;

        // Set the previous register to the same register; mainly it must be
        // known that the prev reg was outside the range of normal registers
        // so the free list can avoid adding it.
        prev_reg = renamed_reg;

        assert(renamed_reg < numPhysicalRegs + numMiscRegs);

        miscScoreboard[renamed_reg] = false;
    }

    return RenameInfo(renamed_reg, prev_reg);
}

//Perhaps give this a pair as a return value, of the physical register
//and whether or not it's ready.
PhysRegIndex
SimpleRenameMap::lookup(RegIndex arch_reg)
{
    if (arch_reg < numLogicalIntRegs) {
        return intRenameMap[arch_reg].physical_reg;
    } else if (arch_reg < numLogicalRegs) {
        // Subtract off the base FP offset.
//        arch_reg = arch_reg - numLogicalIntRegs;

        return floatRenameMap[arch_reg].physical_reg;
    } else {
        // Subtract off the misc registers offset.
        arch_reg = arch_reg - numLogicalRegs;

        // Misc. regs don't rename, so simply add the base arch reg to
        // the number of physical registers.
        return numPhysicalRegs + arch_reg;
    }
}

bool
SimpleRenameMap::isReady(PhysRegIndex phys_reg)
{
    if (phys_reg < numPhysicalIntRegs) {
        return intScoreboard[phys_reg];
    } else if (phys_reg < numPhysicalRegs) {

        // Subtract off the base FP offset.
//        phys_reg = phys_reg - numPhysicalIntRegs;

        return floatScoreboard[phys_reg];
    } else {
        // Subtract off the misc registers offset.
//        phys_reg = phys_reg - numPhysicalRegs;

        return miscScoreboard[phys_reg];
    }
}

// In this implementation the miscellaneous registers do not actually rename,
// so this function does not allow you to try to change their mappings.
void
SimpleRenameMap::setEntry(RegIndex arch_reg, PhysRegIndex renamed_reg)
{
    if (arch_reg < numLogicalIntRegs) {
        DPRINTF(Rename, "Rename Map: Integer register %i being set to %i.\n",
                (int)arch_reg, renamed_reg);

        intRenameMap[arch_reg].physical_reg = renamed_reg;
    } else {
        assert(arch_reg < (numLogicalIntRegs + numLogicalFloatRegs));

        DPRINTF(Rename, "Rename Map: Float register %i being set to %i.\n",
                (int)arch_reg - numLogicalIntRegs, renamed_reg);

        floatRenameMap[arch_reg].physical_reg = renamed_reg;
    }
}

void
SimpleRenameMap::squash(vector<RegIndex> freed_regs,
                        vector<UnmapInfo> unmaps)
{
    panic("Not sure this function should be called.");

    // Not sure the rename map should be able to access the free list
    // like this.
    while (!freed_regs.empty()) {
        RegIndex free_register = freed_regs.back();

        if (free_register < numPhysicalIntRegs) {
            freeList->addIntReg(free_register);
        } else {
            // Subtract off the base FP dependence tag.
            free_register = free_register - numPhysicalIntRegs;
            freeList->addFloatReg(free_register);
        }

        freed_regs.pop_back();
    }

    // Take unmap info and roll back the rename map.
}

void
SimpleRenameMap::markAsReady(PhysRegIndex ready_reg)
{
    DPRINTF(Rename, "Rename map: Marking register %i as ready.\n",
            (int)ready_reg);

    if (ready_reg < numPhysicalIntRegs) {
        assert(ready_reg >= 0);

        intScoreboard[ready_reg] = 1;
    } else if (ready_reg < numPhysicalRegs) {

        // Subtract off the base FP offset.
//        ready_reg = ready_reg - numPhysicalIntRegs;

        floatScoreboard[ready_reg] = 1;
    } else {
        //Subtract off the misc registers offset.
//        ready_reg = ready_reg - numPhysicalRegs;

        miscScoreboard[ready_reg] = 1;
    }
}

int
SimpleRenameMap::numFreeEntries()
{
    int free_int_regs = freeList->numFreeIntRegs();
    int free_float_regs = freeList->numFreeFloatRegs();

    if (free_int_regs < free_float_regs) {
        return free_int_regs;
    } else {
        return free_float_regs;
    }
}
