/*
 * Copyright (c) 2015, 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:
 *    Janik Schlemminger
 *    Matthias Jung
 */

#include "ConfigurationLoader.h"
#include "MemSpec.h"
#include "../TimingCalculation.h"

using namespace tinyxml2;
using namespace std;

void ConfigurationLoader::loadSimConfig(Configuration &config,
                                        string simconfigUri)
{
    tinyxml2::XMLDocument doc;

    loadXML(simconfigUri, doc);
    XMLElement *simconfig = doc.FirstChildElement("simconfig");
    loadConfig(config, simconfig);
}

void ConfigurationLoader::loadSimConfig(Configuration &config,
                                        XMLElement *simconfig)
{
    if (simconfig->Attribute("src")) {
        XMLDocument doc;
        string src(simconfig->Attribute("src"));
        loadXML(src, doc);
        loadSimConfig(config, doc.FirstChildElement("simconfig"));
    }
    loadConfig(config, simconfig);
}

void ConfigurationLoader::loadTemperatureSimConfig(Configuration &config,
                                                   std::string thermalsimconfigUri)
{
    loadConfigFromUri(config, thermalsimconfigUri, "thermalsimconfig");
}

void ConfigurationLoader::loadTemperatureSimConfig(Configuration &config,
                                                   XMLElement *thermalsimconfig)
{
    if (thermalsimconfig->Attribute("src")) {
        // Configuration is inside another a file
        std::string uri(thermalsimconfig->Attribute("src"));
        loadConfigFromUri(config, uri, "thermalsimconfig");
    } else {
        loadConfig(config, thermalsimconfig);
    }
}

void ConfigurationLoader::loadConfig(Configuration &config,
                                     XMLElement *configNode)
{
    XMLElement *element;
    for (element = configNode->FirstChildElement(); element != NULL;
            element = element->NextSiblingElement()) {
        config.setParameter(element->Name(), element->Attribute("value"));

    }
}

void ConfigurationLoader::loadConfigFromUri(Configuration &config,
                                            std::string uri, std::string first_element)
{
    tinyxml2::XMLDocument doc;
    loadXML(uri, doc);
    XMLElement *e = doc.FirstChildElement(first_element.c_str());
    loadConfig(config, e);
}

void ConfigurationLoader::loadMemSpec(Configuration &config, string memspecUri)
{
    tinyxml2::XMLDocument doc;
    config.memspecUri = memspecUri;
    loadXML(memspecUri, doc);
    XMLElement *memspec = doc.FirstChildElement("memspec");
    loadMemSpec(config, memspec);
}

void ConfigurationLoader::loadMemSpec(Configuration &config,
                                      XMLElement *memspec)
{
    config.memSpec.MemoryId = queryStringParameter(memspec, "memoryId");
    config.memSpec.MemoryType = queryStringParameter(memspec, "memoryType");

    if (config.memSpec.MemoryType == "DDR4") {
        loadDDR4(config, memspec);
    } else if (config.memSpec.MemoryType == "DDR3") {
        loadDDR3(config, memspec);
    } else if (config.memSpec.MemoryType == "LPDDR4") {
        loadLPDDR4(config, memspec);
    } else if (config.memSpec.MemoryType == "WIDEIO_SDR") {
        loadWideIO(config, memspec);
    } else {
        reportFatal("ConfigurationLoader", "Unsupported DRAM type");
    }
}

void ConfigurationLoader::loadMCConfig(Configuration &config,
                                       string mcconfigUri)
{
    tinyxml2::XMLDocument doc;
    config.mcconfigUri = mcconfigUri;
    loadXML(mcconfigUri, doc);
    XMLElement *mcconfig = doc.FirstChildElement("mcconfig");
    loadConfig(config, mcconfig);
}

void ConfigurationLoader::loadMCConfig(Configuration &config,
                                       XMLElement *mcconfig)
{
    if (mcconfig->Attribute("src")) {
        XMLDocument doc;
        string src(mcconfig->Attribute("src"));
        config.mcconfigUri = src;
        loadXML(src, doc);
        loadMCConfig(config, doc.FirstChildElement("mcconfig"));
    } else {
        loadConfig(config, mcconfig);
    }


}

void ConfigurationLoader::loadDDR3(Configuration &config, XMLElement *memspec)
{
    //MemArchitecture
    XMLElement *architecture = memspec->FirstChildElement("memarchitecturespec");

    config.memSpec.NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks");
    config.memSpec.NumberOfBankGroups = 1;
    config.memSpec.NumberOfRanks = queryUIntParameter(architecture, "nbrOfRanks");
    config.memSpec.BurstLength = queryUIntParameter(architecture, "burstLength");
    config.memSpec.nActivate = 4;
    config.memSpec.DataRate = queryUIntParameter(architecture, "dataRate");
    config.memSpec.NumberOfRows = queryUIntParameter(architecture, "nbrOfRows");
    config.memSpec.NumberOfColumns = queryUIntParameter(architecture,
                                                        "nbrOfColumns");
    config.memSpec.bitWidth = queryUIntParameter(architecture, "width");
    config.memSpec.DLL = true;
    config.memSpec.termination = true;

    //MemTimings
    XMLElement *timings = memspec->FirstChildElement("memtimingspec");
    config.memSpec.clkMHz = queryDoubleParameter(timings, "clkMhz");
    config.memSpec.clk = FrequencyToClk(config.memSpec.clkMHz);
    sc_time clk = config.memSpec.clk;
    config.memSpec.tRP = clk * queryUIntParameter(timings, "RP");
    config.memSpec.tRAS = clk * queryUIntParameter(timings, "RAS");
    config.memSpec.tRC = clk * queryUIntParameter(timings, "RC");
    config.memSpec.tRTP = clk * queryUIntParameter(timings, "RTP");
    config.memSpec.tRRD_S = clk * queryUIntParameter(timings, "RRD");
    config.memSpec.tRRD_L = clk * queryUIntParameter(timings, "RRD");
    config.memSpec.tCCD_S = clk * queryUIntParameter(timings, "CCD");
    config.memSpec.tCCD_L = clk * queryUIntParameter(timings, "CCD");
    config.memSpec.tRCD = clk * queryUIntParameter(timings, "RCD");
    config.memSpec.tNAW = clk * queryUIntParameter(timings, "FAW");
    config.memSpec.tRL = clk * queryUIntParameter(timings, "RL");
    config.memSpec.tWL = clk * queryUIntParameter(timings, "WL");
    config.memSpec.tWR = clk * queryUIntParameter(timings, "WR");
    config.memSpec.tWTR_S = clk * queryUIntParameter(timings, "WTR");
    config.memSpec.tWTR_L = clk * queryUIntParameter(timings, "WTR");
    config.memSpec.tCKESR = clk * queryUIntParameter(timings, "CKESR");
    config.memSpec.tCKE = clk * queryUIntParameter(timings, "CKE");
    config.memSpec.tXP = clk * queryUIntParameter(timings, "XP");
    config.memSpec.tXPDLL = clk * queryUIntParameter(timings, "XPDLL");
    config.memSpec.tXSR = clk * queryUIntParameter(timings, "XS");
    config.memSpec.tXSRDLL = clk * queryUIntParameter(timings, "XSDLL");
    config.memSpec.tAL = clk * queryUIntParameter(timings, "AL");
    config.memSpec.tRFC = clk * queryUIntParameter(timings, "RFC");
    config.memSpec.tREFI = clk * queryUIntParameter(timings, "REFI");
    config.memSpec.tDQSCK = clk * queryUIntParameter(timings, "DQSCK");

    config.memSpec.refreshTimings.clear();
    for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; ++i) {
        config.memSpec.refreshTimings[Bank(i)] = RefreshTiming(config.memSpec.tRFC,
                                                               config.memSpec.tREFI);
    }

    // Currents and Volatages: TODO Check if this is correct.
    XMLElement *powers = memspec->FirstChildElement("mempowerspec");
    config.memSpec.iDD0    = queryDoubleParameter(powers, "idd0");
    config.memSpec.iDD02   = 0;
    config.memSpec.iDD2P0  = queryDoubleParameter(powers, "idd2p0");
    config.memSpec.iDD2P1  = queryDoubleParameter(powers, "idd2p1");
    config.memSpec.iDD2N   = queryDoubleParameter(powers, "idd2n");
    config.memSpec.iDD3P0  = queryDoubleParameter(powers, "idd3p0");
    config.memSpec.iDD3P1  = queryDoubleParameter(powers, "idd3p1");
    config.memSpec.iDD3N   = queryDoubleParameter(powers, "idd3n");
    config.memSpec.iDD4R   = queryDoubleParameter(powers, "idd4r");
    config.memSpec.iDD4W   = queryDoubleParameter(powers, "idd4w");
    config.memSpec.iDD5    = queryDoubleParameter(powers, "idd5");
    config.memSpec.iDD6    = queryDoubleParameter(powers, "idd6");
    config.memSpec.iDD62   = 0;
    config.memSpec.vDD     = queryDoubleParameter(powers, "vdd");
    config.memSpec.vDD2    = 0;
}


void ConfigurationLoader::loadDDR4(Configuration &config, XMLElement *memspec)
{
    //MemArchitecture
    XMLElement *architecture = memspec->FirstChildElement("memarchitecturespec");

    config.memSpec.NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks");
    config.memSpec.NumberOfBankGroups = queryUIntParameter(architecture,
                                                           "nbrOfBankGroups");
    config.memSpec.NumberOfRanks = queryUIntParameter(architecture, "nbrOfRanks");
    config.memSpec.BurstLength = queryUIntParameter(architecture, "burstLength");
    config.memSpec.nActivate = 4;
    config.memSpec.DataRate = queryUIntParameter(architecture, "dataRate");
    config.memSpec.NumberOfRows = queryUIntParameter(architecture, "nbrOfRows");
    config.memSpec.NumberOfColumns = queryUIntParameter(architecture,
                                                        "nbrOfColumns");
    config.memSpec.bitWidth = queryUIntParameter(architecture, "width");
    config.memSpec.DLL = true;
    config.memSpec.termination = true;

    //MemTimings
    XMLElement *timings = memspec->FirstChildElement("memtimingspec");
    config.memSpec.clkMHz = queryDoubleParameter(timings, "clkMhz");
    config.memSpec.clk = FrequencyToClk(config.memSpec.clkMHz);
    sc_time clk = config.memSpec.clk;
    config.memSpec.tRP = clk * queryUIntParameter(timings, "RP");
    config.memSpec.tRAS = clk * queryUIntParameter(timings, "RAS");
    config.memSpec.tRC = clk * queryUIntParameter(timings, "RC");
    config.memSpec.tRTP = clk * queryUIntParameter(timings, "RTP");
    config.memSpec.tRRD_S = clk * queryUIntParameter(timings, "RRD_S");
    config.memSpec.tRRD_L = clk * queryUIntParameter(timings, "RRD_L");
    config.memSpec.tCCD_S = clk * queryUIntParameter(timings, "CCD_S");
    config.memSpec.tCCD_L = clk * queryUIntParameter(timings, "CCD_L");
    config.memSpec.tRCD = clk * queryUIntParameter(timings, "RCD");
    config.memSpec.tNAW = clk * queryUIntParameter(timings, "FAW");
    config.memSpec.tRL = clk * queryUIntParameter(timings, "RL");
    config.memSpec.tWL = clk * queryUIntParameter(timings, "WL");
    config.memSpec.tWR = clk * queryUIntParameter(timings, "WR");
    config.memSpec.tWTR_S = clk * queryUIntParameter(timings, "WTR_S");
    config.memSpec.tWTR_L = clk * queryUIntParameter(timings, "WTR_L");
    config.memSpec.tCKESR = clk * queryUIntParameter(timings, "CKESR");
    config.memSpec.tCKE = clk * queryUIntParameter(timings, "CKE");
    config.memSpec.tXP = clk * queryUIntParameter(timings, "XP");
    config.memSpec.tXPDLL = clk * queryUIntParameter(timings, "XPDLL");
    config.memSpec.tXSR = clk * queryUIntParameter(timings, "XS");
    config.memSpec.tXSRDLL = clk * queryUIntParameter(timings, "XSDLL");
    config.memSpec.tAL = clk * queryUIntParameter(timings, "AL");
    config.memSpec.tRFC = clk * queryUIntParameter(timings, "RFC");
    config.memSpec.tRFC2 = clk * queryUIntParameter(timings, "RFC2");
    config.memSpec.tRFC4 = clk * queryUIntParameter(timings, "RFC4");
    config.memSpec.tREFI = clk * queryUIntParameter(timings, "REFI");
    config.memSpec.tDQSCK = clk * queryUIntParameter(timings, "DQSCK");

    config.memSpec.refreshTimings.clear();
    for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; ++i) {
        config.memSpec.refreshTimings[Bank(i)] = RefreshTiming(config.memSpec.tRFC,
                                                               config.memSpec.tRFC2,
                                                               config.memSpec.tRFC4,
                                                               config.memSpec.tREFI);
    }

    // Currents and Volatages:
    XMLElement *powers = memspec->FirstChildElement("mempowerspec");
    config.memSpec.iDD0    = queryDoubleParameter(powers, "idd0");
    config.memSpec.iDD02   = queryDoubleParameter(powers, "idd02");
    config.memSpec.iDD2P0  = queryDoubleParameter(powers, "idd2p0");
    config.memSpec.iDD2P1  = queryDoubleParameter(powers, "idd2p1");
    config.memSpec.iDD2N   = queryDoubleParameter(powers, "idd2n");
    config.memSpec.iDD3P0  = queryDoubleParameter(powers, "idd3p0");
    config.memSpec.iDD3P1  = queryDoubleParameter(powers, "idd3p1");
    config.memSpec.iDD3N   = queryDoubleParameter(powers, "idd3n");
    config.memSpec.iDD4R   = queryDoubleParameter(powers, "idd4r");
    config.memSpec.iDD4W   = queryDoubleParameter(powers, "idd4w");
    config.memSpec.iDD5    = queryDoubleParameter(powers, "idd5");
    config.memSpec.iDD6    = queryDoubleParameter(powers, "idd6");
    config.memSpec.iDD62   = queryDoubleParameter(powers, "idd62");
    config.memSpec.vDD     = queryDoubleParameter(powers, "vdd");
    config.memSpec.vDD2    = queryDoubleParameter(powers, "vdd2");
}

// TODO: fix this for LPDDR4
void ConfigurationLoader::loadLPDDR4(Configuration &config, XMLElement *memspec)
{
    //MemArchitecture:
    XMLElement *architecture = memspec->FirstChildElement("memarchitecturespec");

    config.memSpec.NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks");
    config.memSpec.NumberOfBankGroups = 1;
    config.memSpec.NumberOfRanks = queryUIntParameter(architecture, "nbrOfRanks");
    config.memSpec.BurstLength = queryUIntParameter(architecture, "burstLength");
    config.memSpec.nActivate = 4;
    config.memSpec.DataRate = queryUIntParameter(architecture, "dataRate");
    config.memSpec.NumberOfRows = queryUIntParameter(architecture, "nbrOfRows");
    config.memSpec.NumberOfColumns = queryUIntParameter(architecture,
                                                        "nbrOfColumns");
    config.memSpec.bitWidth = queryUIntParameter(architecture, "width");
    config.memSpec.DLL = false; // TODO: Correct?
    config.memSpec.termination = true; // TODO: Correct?

    //MemTimings
    XMLElement *timings = memspec->FirstChildElement("memtimingspec");
    config.memSpec.clkMHz = queryDoubleParameter(timings, "clkMhz");
    config.memSpec.clk = FrequencyToClk(config.memSpec.clkMHz);
    sc_time clk = config.memSpec.clk;
    config.memSpec.tRP = clk * queryUIntParameter(timings, "RPPB");
    config.memSpec.tRPAB = clk * queryUIntParameter(timings, "RPAB");
    config.memSpec.tRAS = clk * queryUIntParameter(timings, "RAS");
    config.memSpec.tRC = clk * queryUIntParameter(timings, "RC");
    config.memSpec.tRTP = clk * queryUIntParameter(timings, "RTP");
    config.memSpec.tRRD_S = clk * queryUIntParameter(timings, "RRD");
    config.memSpec.tRRD_L = clk * queryUIntParameter(timings, "RRD");
    config.memSpec.tCCD_S = clk * queryUIntParameter(timings, "CCD");
    config.memSpec.tCCD_L = clk * queryUIntParameter(timings, "CCD");
    config.memSpec.tRCD = clk * queryUIntParameter(timings, "RCD");
    config.memSpec.tNAW = clk * queryUIntParameter(timings, "FAW");
    config.memSpec.tRL = clk * queryUIntParameter(timings, "RL");
    config.memSpec.tWL = clk * queryUIntParameter(timings, "WL");
    config.memSpec.tWR = clk * queryUIntParameter(timings, "WR");
    config.memSpec.tWTR_S = clk * queryUIntParameter(timings, "WTR");
    config.memSpec.tWTR_L = clk * queryUIntParameter(timings, "WTR");
    config.memSpec.tCKESR = clk * queryUIntParameter(timings, "CKESR");
    config.memSpec.tCKE = clk * queryUIntParameter(timings, "CKE");
    config.memSpec.tXP = clk * queryUIntParameter(timings, "XP");
    config.memSpec.tXPDLL = clk * queryUIntParameter(timings, "XP");
    config.memSpec.tXSR = clk * queryUIntParameter(timings, "XS");
    config.memSpec.tXSRDLL = clk * queryUIntParameter(timings, "XS");
    config.memSpec.tAL = clk * queryUIntParameter(timings, "AL");
    config.memSpec.tRFC = clk * queryUIntParameter(timings, "RFCAB");
    // TODO: config.memSpec.tRFCPB = clk * queryUIntParameter(timings, "RFCPB");
    config.memSpec.tREFI = clk * queryUIntParameter(timings, "REFIAB");
    // TODO: config.memSpec.tREFIPB = clk * queryUIntParameter(timings, "RFCPB");
    config.memSpec.tDQSCK = clk * queryUIntParameter(timings, "DQSCK");

    config.memSpec.refreshTimings.clear();
    for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; ++i) {
        config.memSpec.refreshTimings[Bank(i)] = RefreshTiming(config.memSpec.tRFC,
                                                               config.memSpec.tREFI);
    }

    // Currents and Volatages:
    XMLElement *powers = memspec->FirstChildElement("mempowerspec");
    config.memSpec.iDD0    = queryDoubleParameter(powers, "idd0");
    config.memSpec.iDD02   = queryDoubleParameter(powers, "idd02");
    config.memSpec.iDD2P0  = queryDoubleParameter(powers, "idd2p");
    config.memSpec.iDD2P1  = queryDoubleParameter(powers, "idd2p2");
    config.memSpec.iDD2N   = queryDoubleParameter(powers, "idd2n");
    config.memSpec.iDD3P0  = queryDoubleParameter(powers, "idd3p");
    config.memSpec.iDD3P1  = queryDoubleParameter(powers, "idd3p2");
    config.memSpec.iDD3N   = queryDoubleParameter(powers, "idd3n");
    config.memSpec.iDD4R   = queryDoubleParameter(powers, "idd4r");
    config.memSpec.iDD4W   = queryDoubleParameter(powers, "idd4w");
    config.memSpec.iDD5    = queryDoubleParameter(powers, "idd5");
    config.memSpec.iDD6    = queryDoubleParameter(powers, "idd6");
    config.memSpec.iDD62   = queryDoubleParameter(powers, "idd62");
    config.memSpec.vDD     = queryDoubleParameter(powers, "vdd");
    config.memSpec.vDD2    = queryDoubleParameter(powers, "vdd2");
}

void ConfigurationLoader::loadWideIO(Configuration &config, XMLElement *memspec)
{
    //MemSpecification
    XMLElement *architecture = memspec->FirstChildElement("memarchitecturespec");

    config.memSpec.NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks");
    config.memSpec.NumberOfBankGroups = 1;
    config.memSpec.NumberOfRanks = 1;
    config.memSpec.BurstLength = queryUIntParameter(architecture, "burstLength");
    config.memSpec.nActivate = 2;
    config.memSpec.DataRate = queryUIntParameter(architecture, "dataRate");
    config.memSpec.NumberOfRows = queryUIntParameter(architecture, "nbrOfRows");
    config.memSpec.NumberOfColumns = queryUIntParameter(architecture,
                                                        "nbrOfColumns");
    config.memSpec.bitWidth = queryUIntParameter(architecture, "width");
    config.memSpec.DLL = false;
    config.memSpec.termination = false;

    //MemTimings
    XMLElement *timings = memspec->FirstChildElement("memtimingspec");
    config.memSpec.clkMHz = queryDoubleParameter(timings, "clkMhz");
    config.memSpec.clk = FrequencyToClk(config.memSpec.clkMHz);
    sc_time clk = config.memSpec.clk;
    config.memSpec.tRP = clk * queryUIntParameter(timings, "RP");
    config.memSpec.tRAS = clk * queryUIntParameter(timings, "RAS");
    config.memSpec.tRC = clk * queryUIntParameter(timings, "RC");
    config.memSpec.tRRD_S = clk * queryUIntParameter(timings, "RRD");
    config.memSpec.tRRD_L = config.memSpec.tRRD_S;
    config.memSpec.tCCD_S = clk * queryUIntParameter(timings, "CCD");
    config.memSpec.tCCD_L = config.memSpec.tCCD_S;
    config.memSpec.tRCD = clk * queryUIntParameter(timings, "RCD");
    config.memSpec.tNAW = clk * queryUIntParameter(timings, "TAW");
    config.memSpec.tRL = clk * queryUIntParameter(timings, "RL");
    config.memSpec.tWL = clk * queryUIntParameter(timings, "WL");
    config.memSpec.tWR = clk * queryUIntParameter(timings, "WR");
    config.memSpec.tWTR_S = clk * queryUIntParameter(timings, "WTR");
    config.memSpec.tWTR_L = config.memSpec.tWTR_S;
    config.memSpec.tRTP = clk * queryUIntParameter(timings, "RTP");
    config.memSpec.tCKESR = clk * queryUIntParameter(timings, "CKESR");
    config.memSpec.tCKE = clk * queryUIntParameter(timings, "CKE");
    config.memSpec.tXP = clk * queryUIntParameter(timings, "XP");
    config.memSpec.tXPDLL = config.memSpec.tXP;
    config.memSpec.tXSR = clk * queryUIntParameter(timings, "XS");
    config.memSpec.tXSRDLL = config.memSpec.tXSR;
    config.memSpec.tAL = clk * queryUIntParameter(timings, "AL");
    config.memSpec.tRFC = clk * queryUIntParameter(timings, "RFC");
    config.memSpec.tREFI = clk * queryUIntParameter(timings, "REFI");

    config.memSpec.refreshTimings.clear();
    for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; ++i) {
        config.memSpec.refreshTimings[Bank(i)] = RefreshTiming(config.memSpec.tRFC,
                                                               config.memSpec.tREFI);
    }

    // Currents and Volatages:
    XMLElement *powers = memspec->FirstChildElement("mempowerspec");
    config.memSpec.iDD0    = queryDoubleParameter(powers, "idd0");
    config.memSpec.iDD02   = queryDoubleParameter(powers, "idd02");
    config.memSpec.iDD2P0  = queryDoubleParameter(powers, "idd2p0");
    config.memSpec.iDD2P02 = queryDoubleParameter(powers, "idd2p02");
    config.memSpec.iDD2P1  = queryDoubleParameter(powers, "idd2p1");
    config.memSpec.iDD2P12 = queryDoubleParameter(powers, "idd2p12");
    config.memSpec.iDD2N   = queryDoubleParameter(powers, "idd2n");
    config.memSpec.iDD2N2  = queryDoubleParameter(powers, "idd2n2");
    config.memSpec.iDD3P0  = queryDoubleParameter(powers, "idd3p0");
    config.memSpec.iDD3P02 = queryDoubleParameter(powers, "idd3p02");
    config.memSpec.iDD3P1  = queryDoubleParameter(powers, "idd3p1");
    config.memSpec.iDD3P12 = queryDoubleParameter(powers, "idd3p12");
    config.memSpec.iDD3N   = queryDoubleParameter(powers, "idd3n");
    config.memSpec.iDD3N2  = queryDoubleParameter(powers, "idd3n2");
    config.memSpec.iDD4R   = queryDoubleParameter(powers, "idd4r");
    config.memSpec.iDD4R2  = queryDoubleParameter(powers, "idd4r2");
    config.memSpec.iDD4W   = queryDoubleParameter(powers, "idd4w");
    config.memSpec.iDD4W2  = queryDoubleParameter(powers, "idd4w2");
    config.memSpec.iDD5    = queryDoubleParameter(powers, "idd5");
    config.memSpec.iDD52   = queryDoubleParameter(powers, "idd52");
    config.memSpec.iDD6    = queryDoubleParameter(powers, "idd6");
    config.memSpec.iDD62   = queryDoubleParameter(powers, "idd62");
    config.memSpec.vDD     = queryDoubleParameter(powers, "vdd");
    config.memSpec.vDD2    = queryDoubleParameter(powers, "vdd2");
}
