/*
 * Copyright (c) 2018, University of Kaiserslautern
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. Neither the name of the copyright holder 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 HOLDER
 * 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:
 *    Johannes Feldmann
 */

#ifndef CONGENADDRESSDECODER_H
#define CONGENADDRESSDECODER_H

#include "AddressDecoder.h"

#include "third_party/tinyxml2/tinyxml2.h"

#include <vector>
#include <map>

using std::vector;
using std::pair;
using std::map;

class CongenAddressDecoder
    : private AddressDecoder
{
    // Friendship needed so that the AddressDecoder can access the
    // constructor of this class to create the object in CreateInstance.
    friend class AddressDecoder;

public:
    struct XOR {
        unsigned nBank;
        unsigned nRow;
        XOR() {};
        XOR(unsigned bank, unsigned row) : nBank(bank), nRow(row) {};
    };

// Member variables
private:
    std::string m_strName;                               // The Name of this mapping

    unsigned int
    m_nCost;                           // Number of row misses produced by this mapping

    unsigned int
    m_nBankBits;                       // Number of Bank bits used by this mapping
    unsigned int
    m_nRowBits;                        // Number of Row bits used by this mapping
    unsigned int
    m_nColumnBits;                     // Number of Column bits used by this mapping
    unsigned int
    m_nBurstLengthBits;                // Number of Burst length bits used by this mapping
    unsigned int
    m_nByteBits;                       // Number of Byte bits used by this mapping


    vector<XOR>
    m_vXor;            // This container stores for each used xor gate a pair which consists of "First/Number of an address bit which corresponds to a bank" and "Second/Number of an address bit which corresponds to a row"
    vector<pair<unsigned, unsigned>>
                                  m_vBankBits;       // This container stores for each bank bit a pair which consists of "First/Number of the bank bit" and "Second/Number of the address bit"
    vector<pair<unsigned, unsigned>>
                                  m_vRowBits;        // This container stores for each row bit a pair which consists of "First/Number of the row bit" and "Second/Number of the address bit"
    vector<pair<unsigned, unsigned>>
                                  m_vColumnBits;     // This container stores for each column bit a pair which consists of "First/Number of the column bit" and "Second/Number of the address bit"

//Methods
private:
    tinyxml2::XMLElement *GetXMLNode(tinyxml2::XMLElement *pRoot,
                                     std::string strName);
    unsigned int GetUnsignedTextFromXMLNode(tinyxml2::XMLElement *pRoot);
    unsigned int GetUnsignedAttrFromXMLNode(tinyxml2::XMLElement *pRoot,
                                            std::string strName);
public:
    CongenAddressDecoder();

    virtual void setConfiguration(std::string url);

    virtual DecodedAddress decodeAddress(sc_dt::uint64 addr);
    virtual sc_dt::uint64 encodeAddress(DecodedAddress n);

    static bool testConfigFile(std::string url);

    virtual void print();
};

#endif // CONGENADDRESSDECODER_H
