Code refactoring.
This commit is contained in:
@@ -144,6 +144,8 @@ SOURCES += \
|
||||
src/common/AddressDecoder.cpp \
|
||||
src/controller/scheduler/grp.cpp \
|
||||
src/common/congenAddressDecoder.cpp \
|
||||
src/simulation/Dram.cpp \
|
||||
src/simulation/RecordableDram.cpp \
|
||||
src/simulation/Arbiter.cpp
|
||||
|
||||
HEADERS += \
|
||||
|
||||
602
DRAMSys/library/src/simulation/Dram.cpp
Normal file
602
DRAMSys/library/src/simulation/Dram.cpp
Normal file
@@ -0,0 +1,602 @@
|
||||
/*
|
||||
* 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:
|
||||
* Robert Gernhardt
|
||||
* Matthias Jung
|
||||
* Peter Ehses
|
||||
* Eder F. Zulian
|
||||
* Felipe S. Prado
|
||||
*/
|
||||
|
||||
#include "Dram.h"
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <tlm>
|
||||
#include <systemc>
|
||||
#include <tlm_utils/simple_target_socket.h>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <stdlib.h>
|
||||
#include "../common/DebugManager.h"
|
||||
#include "../common/dramExtension.h"
|
||||
#include "../controller/Controller.h"
|
||||
#include "../controller/core/TimingCalculation.h"
|
||||
#include "../controller/core/configuration/Configuration.h"
|
||||
#include "../common/protocol.h"
|
||||
#include "../common/Utils.h"
|
||||
#include "../common/third_party/DRAMPower/src/libdrampower/LibDRAMPower.h"
|
||||
#include "../error/errormodel.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace tlm;
|
||||
using namespace Data;
|
||||
|
||||
|
||||
Dram::Dram(sc_module_name) : tSocket("socket")
|
||||
{
|
||||
// Adjust number of bytes per burst dynamically to the selected ecc controller
|
||||
bytesPerBurst = Configuration::getInstance().adjustNumBytesAfterECC(
|
||||
bytesPerBurst);
|
||||
dramController = NULL;
|
||||
|
||||
std::uint64_t memorySize = Configuration::getInstance().getSimMemSizeInBytes();
|
||||
if (Configuration::getInstance().UseMalloc)
|
||||
{
|
||||
memory = (unsigned char *)malloc(memorySize);
|
||||
if (!memory)
|
||||
{
|
||||
SC_REPORT_FATAL(this->name(), "Memory allocation failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// allocate and model storage of one DRAM channel using memory map
|
||||
memory = (unsigned char *)mmap(NULL, memorySize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0);
|
||||
}
|
||||
|
||||
tSocket.register_nb_transport_fw(this, &Dram::nb_transport_fw);
|
||||
tSocket.register_transport_dbg(this, &Dram::transport_dbg);
|
||||
|
||||
if (powerAnalysis)
|
||||
{
|
||||
sc_time clk = Configuration::getInstance().memSpec.clk;
|
||||
|
||||
MemArchitectureSpec memArchSpec;
|
||||
memArchSpec.burstLength =
|
||||
Configuration::getInstance().memSpec.BurstLength;
|
||||
memArchSpec.dataRate = Configuration::getInstance().memSpec.DataRate;
|
||||
memArchSpec.nbrOfRows =
|
||||
Configuration::getInstance().memSpec.NumberOfRows;
|
||||
memArchSpec.nbrOfBanks =
|
||||
Configuration::getInstance().memSpec.NumberOfBanks;
|
||||
memArchSpec.nbrOfColumns =
|
||||
Configuration::getInstance().memSpec.NumberOfColumns;
|
||||
memArchSpec.nbrOfRanks =
|
||||
Configuration::getInstance().memSpec.NumberOfRanks;
|
||||
memArchSpec.width = Configuration::getInstance().memSpec.bitWidth;
|
||||
memArchSpec.nbrOfBankGroups =
|
||||
Configuration::getInstance().memSpec.NumberOfBankGroups;
|
||||
memArchSpec.twoVoltageDomains = (Configuration::getInstance().memSpec.vDD2 == 0
|
||||
? false : true);
|
||||
memArchSpec.dll = Configuration::getInstance().memSpec.DLL;
|
||||
|
||||
MemTimingSpec memTimingSpec;
|
||||
memTimingSpec.FAWB = Configuration::getInstance().tfawbclk;
|
||||
memTimingSpec.RASB = Configuration::getInstance().trasbclk;
|
||||
memTimingSpec.RCB = Configuration::getInstance().trcbclk;
|
||||
memTimingSpec.RPB = Configuration::getInstance().trpbclk;
|
||||
memTimingSpec.RRDB = Configuration::getInstance().trrdblclk;
|
||||
memTimingSpec.RRDB_L = Configuration::getInstance().trrdblclk;
|
||||
memTimingSpec.RRDB_S = Configuration::getInstance().trrdblclk;
|
||||
memTimingSpec.AL = Configuration::getInstance().memSpec.tAL / clk;
|
||||
memTimingSpec.CCD = Configuration::getInstance().memSpec.tCCD_S / clk;
|
||||
memTimingSpec.CCD_L = Configuration::getInstance().memSpec.tCCD_L / clk;
|
||||
memTimingSpec.CCD_S = Configuration::getInstance().memSpec.tCCD_S / clk;
|
||||
memTimingSpec.CKE = Configuration::getInstance().memSpec.tCKE / clk;
|
||||
memTimingSpec.CKESR = Configuration::getInstance().memSpec.tCKESR / clk;
|
||||
memTimingSpec.clkMhz = Configuration::getInstance().memSpec.clkMHz;
|
||||
// See also MemTimingSpec.cc in DRAMPower
|
||||
memTimingSpec.clkPeriod = 1000.0 / Configuration::getInstance().memSpec.clkMHz;
|
||||
memTimingSpec.DQSCK = Configuration::getInstance().memSpec.tDQSCK / clk;
|
||||
memTimingSpec.FAW = Configuration::getInstance().memSpec.tNAW / clk;
|
||||
memTimingSpec.RAS = Configuration::getInstance().memSpec.tRAS / clk;
|
||||
memTimingSpec.RC = Configuration::getInstance().memSpec.tRC / clk;
|
||||
memTimingSpec.RCD = Configuration::getInstance().memSpec.tRCD / clk;
|
||||
memTimingSpec.REFI = Configuration::getInstance().memSpec.tREFI / clk;
|
||||
auto m = Configuration::getInstance().getRefMode();
|
||||
if (m == 4)
|
||||
memTimingSpec.RFC = Configuration::getInstance().memSpec.tRFC4 / clk;
|
||||
else if (m == 2)
|
||||
memTimingSpec.RFC = Configuration::getInstance().memSpec.tRFC2 / clk;
|
||||
else
|
||||
memTimingSpec.RFC = Configuration::getInstance().memSpec.tRFC / clk;
|
||||
memTimingSpec.RL = Configuration::getInstance().memSpec.tRL / clk;
|
||||
memTimingSpec.RP = Configuration::getInstance().memSpec.tRP / clk;
|
||||
memTimingSpec.RRD = Configuration::getInstance().memSpec.tRRD_S / clk;
|
||||
memTimingSpec.RRD_L = Configuration::getInstance().memSpec.tRRD_L / clk;
|
||||
memTimingSpec.RRD_S = Configuration::getInstance().memSpec.tRRD_S / clk;
|
||||
memTimingSpec.RTP = Configuration::getInstance().memSpec.tRTP / clk;
|
||||
memTimingSpec.TAW = Configuration::getInstance().memSpec.tNAW / clk;
|
||||
memTimingSpec.WL = Configuration::getInstance().memSpec.tWL / clk;
|
||||
memTimingSpec.WR = Configuration::getInstance().memSpec.tWR / clk;
|
||||
memTimingSpec.WTR = Configuration::getInstance().memSpec.tWTR_S / clk;
|
||||
memTimingSpec.WTR_L = Configuration::getInstance().memSpec.tWTR_L / clk;
|
||||
memTimingSpec.WTR_S = Configuration::getInstance().memSpec.tWTR_S / clk;
|
||||
memTimingSpec.XP = Configuration::getInstance().memSpec.tXP / clk;
|
||||
memTimingSpec.XPDLL = Configuration::getInstance().memSpec.tXPDLL / clk;
|
||||
memTimingSpec.XS = Configuration::getInstance().memSpec.tXSR / clk;
|
||||
memTimingSpec.XSDLL = Configuration::getInstance().memSpec.tXSRDLL / clk;
|
||||
|
||||
MemPowerSpec memPowerSpec;
|
||||
memPowerSpec.idd0 = Configuration::getInstance().memSpec.iDD0;
|
||||
memPowerSpec.idd02 = Configuration::getInstance().memSpec.iDD02;
|
||||
memPowerSpec.idd2p0 = Configuration::getInstance().memSpec.iDD2P0;
|
||||
memPowerSpec.idd2p02 = Configuration::getInstance().memSpec.iDD2P02;
|
||||
memPowerSpec.idd2p1 = Configuration::getInstance().memSpec.iDD2P1;
|
||||
memPowerSpec.idd2p12 = Configuration::getInstance().memSpec.iDD2P12;
|
||||
memPowerSpec.idd2n = Configuration::getInstance().memSpec.iDD2N;
|
||||
memPowerSpec.idd2n2 = Configuration::getInstance().memSpec.iDD2N2;
|
||||
memPowerSpec.idd3p0 = Configuration::getInstance().memSpec.iDD3P0;
|
||||
memPowerSpec.idd3p02 = Configuration::getInstance().memSpec.iDD3P02;
|
||||
memPowerSpec.idd3p1 = Configuration::getInstance().memSpec.iDD3P1;
|
||||
memPowerSpec.idd3p12 = Configuration::getInstance().memSpec.iDD3P12;
|
||||
memPowerSpec.idd3n = Configuration::getInstance().memSpec.iDD3N;
|
||||
memPowerSpec.idd3n2 = Configuration::getInstance().memSpec.iDD3N2;
|
||||
memPowerSpec.idd4r = Configuration::getInstance().memSpec.iDD4R;
|
||||
memPowerSpec.idd4r2 = Configuration::getInstance().memSpec.iDD4R2;
|
||||
memPowerSpec.idd4w = Configuration::getInstance().memSpec.iDD4W;
|
||||
memPowerSpec.idd4w2 = Configuration::getInstance().memSpec.iDD4W2;
|
||||
memPowerSpec.idd5 = Configuration::getInstance().memSpec.iDD5;
|
||||
memPowerSpec.idd52 = Configuration::getInstance().memSpec.iDD52;
|
||||
memPowerSpec.idd6 = Configuration::getInstance().memSpec.iDD6;
|
||||
memPowerSpec.idd62 = Configuration::getInstance().memSpec.iDD62;
|
||||
memPowerSpec.vdd = Configuration::getInstance().memSpec.vDD;
|
||||
memPowerSpec.vdd2 = Configuration::getInstance().memSpec.vDD2;
|
||||
|
||||
MemorySpecification memSpec;
|
||||
memSpec.id = Configuration::getInstance().memSpec.MemoryId;
|
||||
memSpec.memoryType = Configuration::getInstance().memSpec.MemoryType;
|
||||
memSpec.memTimingSpec = memTimingSpec;
|
||||
memSpec.memPowerSpec = memPowerSpec;
|
||||
memSpec.memArchSpec = memArchSpec;
|
||||
|
||||
DRAMPower = new libDRAMPower(memSpec, 0);
|
||||
}
|
||||
|
||||
// Bandwidth Calculation:
|
||||
numberOfTransactionsServed = 0;
|
||||
firstAccess = SC_ZERO_TIME;
|
||||
lastAccess = SC_ZERO_TIME;
|
||||
|
||||
// For each bank in a channel a error Model is created:
|
||||
if (StoreMode == StorageMode::ErrorModel)
|
||||
{
|
||||
for (unsigned i = 0; i < Configuration::getInstance().memSpec.NumberOfBanks;
|
||||
i++)
|
||||
{
|
||||
errorModel *em;
|
||||
std::string errorModelStr = "errorModel_bank" + std::to_string(i);
|
||||
if (powerAnalysis)
|
||||
em = new errorModel(errorModelStr.c_str(), DRAMPower);
|
||||
else
|
||||
em = new errorModel(errorModelStr.c_str());
|
||||
ememory.push_back(em);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dram::~Dram()
|
||||
{
|
||||
if (powerAnalysis)
|
||||
{
|
||||
if (!Configuration::getInstance().DatabaseRecording)
|
||||
DRAMPower->calcEnergy();
|
||||
|
||||
// Print the final total energy and the average power for
|
||||
// the simulation:
|
||||
cout << name() << string(" Total Energy: ")
|
||||
<< fixed << std::setprecision( 2 )
|
||||
<< DRAMPower->getEnergy().total_energy
|
||||
* Configuration::getInstance().NumberOfDevicesOnDIMM
|
||||
<< string(" pJ")
|
||||
<< endl;
|
||||
|
||||
cout << name() << string(" Average Power: ")
|
||||
<< fixed << std::setprecision( 2 )
|
||||
<< DRAMPower->getPower().average_power
|
||||
* Configuration::getInstance().NumberOfDevicesOnDIMM
|
||||
<< string(" mW") << endl;
|
||||
}
|
||||
|
||||
// Bandwidth:
|
||||
|
||||
sc_time activeTime = numberOfTransactionsServed
|
||||
* Configuration::getInstance().memSpec.BurstLength
|
||||
/ Configuration::getInstance().memSpec.DataRate
|
||||
* Configuration::getInstance().memSpec.clk;
|
||||
|
||||
sc_time idleTime = dramController->getIdleTime();
|
||||
sc_time endTime = dramController->getEndTime();
|
||||
sc_time startTime = dramController->getStartTime();
|
||||
|
||||
double bandwidth = (activeTime / (endTime - startTime) * 100);
|
||||
double bandwidth_IDLE = ((activeTime) / (endTime - startTime - idleTime) * 100);
|
||||
|
||||
double maxBandwidth = (
|
||||
// clk in Mhz e.g. 800 [MHz]:
|
||||
(1000000 / Configuration::getInstance().memSpec.clk.to_double())
|
||||
// DataRate e.g. 2
|
||||
* Configuration::getInstance().memSpec.DataRate
|
||||
// BusWidth e.g. 8 or 64
|
||||
* Configuration::getInstance().memSpec.bitWidth
|
||||
// Number of devices on a DIMM e.g. 8
|
||||
* Configuration::getInstance().NumberOfDevicesOnDIMM ) / ( 1024 );
|
||||
|
||||
cout << name() << string(" Total Time: ")
|
||||
<< (endTime - startTime).to_string()
|
||||
<< endl;
|
||||
cout << name() << string(" AVG BW: ")
|
||||
<< std::fixed << std::setprecision(2)
|
||||
<< ((bandwidth / 100)*maxBandwidth)
|
||||
<< " Gibit/s (" << bandwidth << " %)"
|
||||
<< endl;
|
||||
cout << name() << string(" AVG BW/IDLE: ")
|
||||
<< std::fixed << std::setprecision(2)
|
||||
<< ((bandwidth_IDLE / 100)*maxBandwidth)
|
||||
<< " Gibit/s (" << (bandwidth_IDLE) << " %)"
|
||||
<< endl;
|
||||
cout << name() << string(" MAX BW: ")
|
||||
<< std::fixed << std::setprecision(2)
|
||||
<< maxBandwidth << " Gibit/s"
|
||||
<< endl;
|
||||
// Clean up:
|
||||
for (auto e : ememory)
|
||||
delete e;
|
||||
|
||||
if (Configuration::getInstance().UseMalloc)
|
||||
free(memory);
|
||||
}
|
||||
|
||||
tlm_sync_enum Dram::nb_transport_fw(tlm_generic_payload &payload,
|
||||
tlm_phase &phase, sc_time &delay)
|
||||
{
|
||||
if (numberOfTransactionsServed == 0)
|
||||
firstAccess = sc_time_stamp();
|
||||
else
|
||||
lastAccess = sc_time_stamp();
|
||||
|
||||
unsigned int bank = DramExtension::getExtension(payload).getBank().ID();
|
||||
|
||||
// This is only needed for power simulation:
|
||||
unsigned long long cycle = 0;
|
||||
if (powerAnalysis)
|
||||
{
|
||||
cycle = sc_time_stamp().value() /
|
||||
Configuration::getInstance().memSpec.clk.value();
|
||||
}
|
||||
|
||||
if (phase == BEGIN_PREB)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
DRAMPower->doCommand(MemCommand::PREB, bank, cycle);
|
||||
|
||||
sendToController(payload, END_PREB, delay + getExecutionTime(Command::PreB,
|
||||
payload));
|
||||
}
|
||||
else if (phase == BEGIN_PRE)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
DRAMPower->doCommand(MemCommand::PRE, bank, cycle);
|
||||
|
||||
sendToController(payload, END_PRE, delay + getExecutionTime(Command::Precharge,
|
||||
payload));
|
||||
}
|
||||
else if (phase == BEGIN_PRE_ALL)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
DRAMPower->doCommand(MemCommand::PREA, bank, cycle);
|
||||
|
||||
sendToController(payload, END_PRE_ALL,
|
||||
delay + getExecutionTime(Command::PrechargeAll, payload));
|
||||
}
|
||||
else if (phase == BEGIN_ACTB)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
DRAMPower->doCommand(MemCommand::ACTB, bank, cycle);
|
||||
|
||||
sendToController(payload, END_ACTB, delay + getExecutionTime(Command::ActB,
|
||||
payload));
|
||||
unsigned int row = DramExtension::getExtension(payload).getRow().ID();
|
||||
if (StoreMode == StorageMode::ErrorModel)
|
||||
ememory[bank]->activate(row);
|
||||
}
|
||||
else if (phase == BEGIN_ACT)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
DRAMPower->doCommand(MemCommand::ACT, bank, cycle);
|
||||
|
||||
sendToController(payload, END_ACT, delay + getExecutionTime(Command::Activate,
|
||||
payload));
|
||||
unsigned int row = DramExtension::getExtension(payload).getRow().ID();
|
||||
|
||||
if (StoreMode == StorageMode::ErrorModel)
|
||||
ememory[bank]->activate(row);
|
||||
}
|
||||
else if (phase == BEGIN_WR)
|
||||
{
|
||||
#if !defined (DRAMSYS_PCT) && !defined (DRAMSYS_GEM5)
|
||||
assert(payload.get_data_length() == bytesPerBurst);
|
||||
#endif
|
||||
|
||||
if (powerAnalysis)
|
||||
DRAMPower->doCommand(MemCommand::WR, bank, cycle);
|
||||
|
||||
numberOfTransactionsServed++;
|
||||
|
||||
// save data:
|
||||
if (StoreMode == StorageMode::NoStorage) // Don't store data
|
||||
{}
|
||||
else if (StoreMode == StorageMode::Store) // Use Storage
|
||||
{
|
||||
unsigned char *phyAddr = memory + payload.get_address();
|
||||
memcpy(phyAddr, payload.get_data_ptr(), payload.get_data_length());
|
||||
}
|
||||
else // if (StoreMode == StorageMode::ErrorModel) // Use Storage with Error Model
|
||||
{
|
||||
ememory[bank]->store(payload);
|
||||
}
|
||||
sendToController(payload, END_WR, delay + getExecutionTime(Command::Write,
|
||||
payload));
|
||||
}
|
||||
else if (phase == BEGIN_RD)
|
||||
{
|
||||
#if !defined (DRAMSYS_PCT) && !defined (DRAMSYS_GEM5)
|
||||
assert(payload.get_data_length() == bytesPerBurst);
|
||||
#endif
|
||||
|
||||
numberOfTransactionsServed++;
|
||||
if (powerAnalysis)
|
||||
DRAMPower->doCommand(MemCommand::RD, bank, cycle);
|
||||
|
||||
// load data:
|
||||
if (StoreMode == StorageMode::Store) // use StorageMode
|
||||
{
|
||||
unsigned char *phyAddr = memory + payload.get_address();
|
||||
memcpy(payload.get_data_ptr(), phyAddr, payload.get_data_length());
|
||||
}
|
||||
else if (StoreMode == StorageMode::ErrorModel) // use StorageMode with errormodel
|
||||
{
|
||||
ememory[bank]->load(payload);
|
||||
}
|
||||
sendToController(payload, END_RD, delay + getExecutionTime(Command::Read,
|
||||
payload));
|
||||
}
|
||||
else if (phase == BEGIN_WRA)
|
||||
{
|
||||
numberOfTransactionsServed++;
|
||||
if (powerAnalysis)
|
||||
DRAMPower->doCommand(MemCommand::WRA, bank, cycle);
|
||||
|
||||
// save data:
|
||||
if (StoreMode == StorageMode::NoStorage) // Don't store data
|
||||
{}
|
||||
else if (StoreMode == StorageMode::Store) // Use Storage
|
||||
{
|
||||
unsigned char *phyAddr = memory + payload.get_address();
|
||||
memcpy(phyAddr, payload.get_data_ptr(), payload.get_data_length());
|
||||
}
|
||||
else // if (StoreMode == StorageMode::ErrorModel) // Use Storage with Error Model
|
||||
{
|
||||
ememory[bank]->store(payload);
|
||||
}
|
||||
sendToController(payload, END_WRA, delay + getExecutionTime(Command::WriteA,
|
||||
payload));
|
||||
}
|
||||
else if (phase == BEGIN_RDA)
|
||||
{
|
||||
numberOfTransactionsServed++;
|
||||
if (powerAnalysis)
|
||||
DRAMPower->doCommand(MemCommand::RDA, bank, cycle);
|
||||
|
||||
// Load data:
|
||||
if (StoreMode == StorageMode::Store) // use StorageMode
|
||||
{
|
||||
unsigned char *phyAddr = memory + payload.get_address();
|
||||
memcpy(payload.get_data_ptr(), phyAddr, payload.get_data_length());
|
||||
}
|
||||
else if (StoreMode == StorageMode::ErrorModel) // use StorageMode with errormodel
|
||||
{
|
||||
ememory[bank]->load(payload);
|
||||
}
|
||||
sendToController(payload, END_RDA, delay + getExecutionTime(Command::ReadA,
|
||||
payload));
|
||||
}
|
||||
else if (phase == BEGIN_REFA)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
DRAMPower->doCommand(MemCommand::REF, bank, cycle);
|
||||
|
||||
sendToController(payload, END_REFA,
|
||||
delay + getExecutionTime(Command::AutoRefresh, payload));
|
||||
unsigned int row = DramExtension::getExtension(payload).getRow().ID();
|
||||
|
||||
if (StoreMode == StorageMode::ErrorModel)
|
||||
ememory[bank]->refresh(row);
|
||||
}
|
||||
else if (phase == BEGIN_REFB)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
DRAMPower->doCommand(MemCommand::REFB, bank, cycle);
|
||||
|
||||
sendToController(payload, END_REFB,
|
||||
delay + getExecutionTime(Command::AutoRefresh, payload));
|
||||
}
|
||||
// Powerdown phases have to be started and ended by the controller, because they do not have a fixed length
|
||||
else if (phase == BEGIN_PDNA)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
DRAMPower->doCommand(MemCommand::PDN_S_ACT, bank, cycle);
|
||||
}
|
||||
else if (phase == END_PDNA)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
DRAMPower->doCommand(MemCommand::PUP_ACT, bank, cycle);
|
||||
}
|
||||
else if (phase == BEGIN_PDNAB)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported");
|
||||
}
|
||||
else if (phase == END_PDNAB)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported");
|
||||
}
|
||||
else if (phase == BEGIN_PDNP)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
DRAMPower->doCommand(MemCommand::PDN_S_PRE, bank, cycle);
|
||||
}
|
||||
else if (phase == END_PDNP)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
DRAMPower->doCommand(MemCommand::PUP_PRE, bank, cycle);
|
||||
}
|
||||
else if (phase == BEGIN_PDNPB)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported");
|
||||
}
|
||||
else if (phase == END_PDNPB)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported");
|
||||
}
|
||||
else if (phase == BEGIN_SREF)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
DRAMPower->doCommand(MemCommand::SREN, bank, cycle);
|
||||
}
|
||||
else if (phase == END_SREF)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
DRAMPower->doCommand(MemCommand::SREX, bank, cycle);
|
||||
}
|
||||
else if (phase == BEGIN_SREFB)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported");
|
||||
}
|
||||
else if (phase == END_SREFB)
|
||||
{
|
||||
if (powerAnalysis)
|
||||
SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (powerAnalysis)
|
||||
SC_REPORT_FATAL("DRAM", "DRAM PEQ was called with unknown phase");
|
||||
}
|
||||
|
||||
return tlm::TLM_ACCEPTED;
|
||||
}
|
||||
|
||||
unsigned int Dram::transport_dbg(tlm_generic_payload &trans)
|
||||
{
|
||||
printDebugMessage("transport_dgb");
|
||||
|
||||
// TODO: This part is not tested yet, neither with traceplayers nor with GEM5 coupling
|
||||
if (StoreMode == StorageMode::NoStorage)
|
||||
{
|
||||
SC_REPORT_FATAL("DRAM",
|
||||
"Debug Transport is used in combination with NoStorage");
|
||||
}
|
||||
else
|
||||
{
|
||||
tlm_command cmd = trans.get_command();
|
||||
//sc_dt::uint64 adr = trans.get_address(); // TODO: - offset;
|
||||
unsigned char *ptr = trans.get_data_ptr();
|
||||
unsigned int len = trans.get_data_length();
|
||||
//unsigned int bank = DramExtension::getExtension(trans).getBank().ID();
|
||||
|
||||
//cout << "cmd " << (cmd ? "write" : "read") << " adr " << hex << adr << " len " << len << endl;
|
||||
|
||||
if (cmd == TLM_READ_COMMAND)
|
||||
{
|
||||
if (StoreMode == StorageMode::Store)
|
||||
{ // Use Storage
|
||||
unsigned char *phyAddr = memory + trans.get_address();
|
||||
memcpy(ptr, phyAddr, trans.get_data_length());
|
||||
}
|
||||
else
|
||||
{
|
||||
//ememory[bank]->load(trans);
|
||||
SC_REPORT_FATAL("DRAM", "Debug transport not supported with error model yet.");
|
||||
}
|
||||
}
|
||||
else if (cmd == TLM_WRITE_COMMAND)
|
||||
{
|
||||
if (StoreMode == StorageMode::Store)
|
||||
{ // Use Storage
|
||||
unsigned char *phyAddr = memory + trans.get_address();
|
||||
memcpy(phyAddr, ptr, trans.get_data_length());
|
||||
}
|
||||
else
|
||||
{
|
||||
//ememory[bank]->store(trans);
|
||||
SC_REPORT_FATAL("DRAM", "Debug transport not supported with error model yet.");
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Dram::sendToController(tlm_generic_payload &payload, const tlm_phase &phase,
|
||||
const sc_time &delay)
|
||||
{
|
||||
tlm_phase TPhase = phase;
|
||||
sc_time TDelay = delay;
|
||||
tSocket->nb_transport_bw(payload, TPhase, TDelay);
|
||||
}
|
||||
|
||||
void Dram::printDebugMessage(string message)
|
||||
{
|
||||
DebugManager::getInstance().printDebugMessage(name(), message);
|
||||
}
|
||||
|
||||
void Dram::setDramController(Controller *contr)
|
||||
{
|
||||
dramController = contr;
|
||||
}
|
||||
@@ -40,39 +40,24 @@
|
||||
#ifndef DRAM_H_
|
||||
#define DRAM_H_
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <tlm>
|
||||
#include <systemc>
|
||||
#include <tlm_utils/peq_with_cb_and_phase.h>
|
||||
#include <tlm_utils/simple_target_socket.h>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <stdlib.h>
|
||||
#include "../common/DebugManager.h"
|
||||
#include "../common/dramExtension.h"
|
||||
#include "../controller/Controller.h"
|
||||
#include "../controller/core/TimingCalculation.h"
|
||||
#include "../controller/core/configuration/Configuration.h"
|
||||
#include "../common/protocol.h"
|
||||
#include "../common/Utils.h"
|
||||
#include "../common/third_party/DRAMPower/src/libdrampower/LibDRAMPower.h"
|
||||
#include "../error/errormodel.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace tlm;
|
||||
using namespace Data;
|
||||
|
||||
struct Dram : sc_module {
|
||||
class Dram : public sc_module
|
||||
{
|
||||
private:
|
||||
unsigned int bytesPerBurst = Configuration::getInstance().getBytesPerBurst();
|
||||
|
||||
// TLM Related:
|
||||
tlm_utils::simple_target_socket<Dram> tSocket;
|
||||
|
||||
// Power Model related
|
||||
bool powerAnalysis = Configuration::getInstance().PowerAnalysis;
|
||||
libDRAMPower *DRAMPower;
|
||||
|
||||
// Bandwidth realted:
|
||||
unsigned long long int numberOfTransactionsServed;
|
||||
@@ -88,499 +73,28 @@ struct Dram : sc_module {
|
||||
|
||||
Controller *dramController;
|
||||
|
||||
SC_CTOR(Dram) : tSocket("socket")
|
||||
{
|
||||
// Adjust number of bytes per burst dynamically to the selected ecc controller
|
||||
bytesPerBurst = Configuration::getInstance().adjustNumBytesAfterECC(
|
||||
bytesPerBurst);
|
||||
dramController = NULL;
|
||||
protected:
|
||||
libDRAMPower *DRAMPower;
|
||||
|
||||
std::uint64_t memorySize = Configuration::getInstance().getSimMemSizeInBytes();
|
||||
if (Configuration::getInstance().UseMalloc) {
|
||||
memory = (unsigned char *)malloc(memorySize);
|
||||
if (!memory) {
|
||||
SC_REPORT_FATAL(this->name(), "Memory allocation failed");
|
||||
}
|
||||
} else {
|
||||
// allocate and model storage of one DRAM channel using memory map
|
||||
memory = (unsigned char *)mmap(NULL, memorySize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0);
|
||||
}
|
||||
virtual tlm_sync_enum nb_transport_fw(tlm_generic_payload &payload,
|
||||
tlm_phase &phase, sc_time &delay);
|
||||
|
||||
tSocket.register_nb_transport_fw(this, &Dram::nb_transport_fw);
|
||||
tSocket.register_transport_dbg(this, &Dram::transport_dbg);
|
||||
|
||||
if (powerAnalysis == true) {
|
||||
sc_time clk = Configuration::getInstance().memSpec.clk;
|
||||
|
||||
MemArchitectureSpec memArchSpec;
|
||||
memArchSpec.burstLength =
|
||||
Configuration::getInstance().memSpec.BurstLength;
|
||||
memArchSpec.dataRate = Configuration::getInstance().memSpec.DataRate;
|
||||
memArchSpec.nbrOfRows =
|
||||
Configuration::getInstance().memSpec.NumberOfRows;
|
||||
memArchSpec.nbrOfBanks =
|
||||
Configuration::getInstance().memSpec.NumberOfBanks;
|
||||
memArchSpec.nbrOfColumns =
|
||||
Configuration::getInstance().memSpec.NumberOfColumns;
|
||||
memArchSpec.nbrOfRanks =
|
||||
Configuration::getInstance().memSpec.NumberOfRanks;
|
||||
memArchSpec.width = Configuration::getInstance().memSpec.bitWidth;
|
||||
memArchSpec.nbrOfBankGroups =
|
||||
Configuration::getInstance().memSpec.NumberOfBankGroups;
|
||||
memArchSpec.twoVoltageDomains = (Configuration::getInstance().memSpec.vDD2 == 0
|
||||
? false : true);
|
||||
memArchSpec.dll = Configuration::getInstance().memSpec.DLL;
|
||||
|
||||
MemTimingSpec memTimingSpec;
|
||||
memTimingSpec.FAWB = Configuration::getInstance().tfawbclk;
|
||||
memTimingSpec.RASB = Configuration::getInstance().trasbclk;
|
||||
memTimingSpec.RCB = Configuration::getInstance().trcbclk;
|
||||
memTimingSpec.RPB = Configuration::getInstance().trpbclk;
|
||||
memTimingSpec.RRDB = Configuration::getInstance().trrdblclk;
|
||||
memTimingSpec.RRDB_L = Configuration::getInstance().trrdblclk;
|
||||
memTimingSpec.RRDB_S = Configuration::getInstance().trrdblclk;
|
||||
memTimingSpec.AL = Configuration::getInstance().memSpec.tAL / clk;
|
||||
memTimingSpec.CCD = Configuration::getInstance().memSpec.tCCD_S / clk;
|
||||
memTimingSpec.CCD_L = Configuration::getInstance().memSpec.tCCD_L / clk;
|
||||
memTimingSpec.CCD_S = Configuration::getInstance().memSpec.tCCD_S / clk;
|
||||
memTimingSpec.CKE = Configuration::getInstance().memSpec.tCKE / clk;
|
||||
memTimingSpec.CKESR = Configuration::getInstance().memSpec.tCKESR / clk;
|
||||
memTimingSpec.clkMhz = Configuration::getInstance().memSpec.clkMHz;
|
||||
// See also MemTimingSpec.cc in DRAMPower
|
||||
memTimingSpec.clkPeriod = 1000.0 / Configuration::getInstance().memSpec.clkMHz;
|
||||
memTimingSpec.DQSCK = Configuration::getInstance().memSpec.tDQSCK / clk;
|
||||
memTimingSpec.FAW = Configuration::getInstance().memSpec.tNAW / clk;
|
||||
memTimingSpec.RAS = Configuration::getInstance().memSpec.tRAS / clk;
|
||||
memTimingSpec.RC = Configuration::getInstance().memSpec.tRC / clk;
|
||||
memTimingSpec.RCD = Configuration::getInstance().memSpec.tRCD / clk;
|
||||
memTimingSpec.REFI = Configuration::getInstance().memSpec.tREFI / clk;
|
||||
auto m = Configuration::getInstance().getRefMode();
|
||||
if (m == 4)
|
||||
memTimingSpec.RFC = Configuration::getInstance().memSpec.tRFC4 / clk;
|
||||
else if (m == 2)
|
||||
memTimingSpec.RFC = Configuration::getInstance().memSpec.tRFC2 / clk;
|
||||
else
|
||||
memTimingSpec.RFC = Configuration::getInstance().memSpec.tRFC / clk;
|
||||
memTimingSpec.RL = Configuration::getInstance().memSpec.tRL / clk;
|
||||
memTimingSpec.RP = Configuration::getInstance().memSpec.tRP / clk;
|
||||
memTimingSpec.RRD = Configuration::getInstance().memSpec.tRRD_S / clk;
|
||||
memTimingSpec.RRD_L = Configuration::getInstance().memSpec.tRRD_L / clk;
|
||||
memTimingSpec.RRD_S = Configuration::getInstance().memSpec.tRRD_S / clk;
|
||||
memTimingSpec.RTP = Configuration::getInstance().memSpec.tRTP / clk;
|
||||
memTimingSpec.TAW = Configuration::getInstance().memSpec.tNAW / clk;
|
||||
memTimingSpec.WL = Configuration::getInstance().memSpec.tWL / clk;
|
||||
memTimingSpec.WR = Configuration::getInstance().memSpec.tWR / clk;
|
||||
memTimingSpec.WTR = Configuration::getInstance().memSpec.tWTR_S / clk;
|
||||
memTimingSpec.WTR_L = Configuration::getInstance().memSpec.tWTR_L / clk;
|
||||
memTimingSpec.WTR_S = Configuration::getInstance().memSpec.tWTR_S / clk;
|
||||
memTimingSpec.XP = Configuration::getInstance().memSpec.tXP / clk;
|
||||
memTimingSpec.XPDLL = Configuration::getInstance().memSpec.tXPDLL / clk;
|
||||
memTimingSpec.XS = Configuration::getInstance().memSpec.tXSR / clk;
|
||||
memTimingSpec.XSDLL = Configuration::getInstance().memSpec.tXSRDLL / clk;
|
||||
|
||||
MemPowerSpec memPowerSpec;
|
||||
memPowerSpec.idd0 = Configuration::getInstance().memSpec.iDD0;
|
||||
memPowerSpec.idd02 = Configuration::getInstance().memSpec.iDD02;
|
||||
memPowerSpec.idd2p0 = Configuration::getInstance().memSpec.iDD2P0;
|
||||
memPowerSpec.idd2p02 = Configuration::getInstance().memSpec.iDD2P02;
|
||||
memPowerSpec.idd2p1 = Configuration::getInstance().memSpec.iDD2P1;
|
||||
memPowerSpec.idd2p12 = Configuration::getInstance().memSpec.iDD2P12;
|
||||
memPowerSpec.idd2n = Configuration::getInstance().memSpec.iDD2N;
|
||||
memPowerSpec.idd2n2 = Configuration::getInstance().memSpec.iDD2N2;
|
||||
memPowerSpec.idd3p0 = Configuration::getInstance().memSpec.iDD3P0;
|
||||
memPowerSpec.idd3p02 = Configuration::getInstance().memSpec.iDD3P02;
|
||||
memPowerSpec.idd3p1 = Configuration::getInstance().memSpec.iDD3P1;
|
||||
memPowerSpec.idd3p12 = Configuration::getInstance().memSpec.iDD3P12;
|
||||
memPowerSpec.idd3n = Configuration::getInstance().memSpec.iDD3N;
|
||||
memPowerSpec.idd3n2 = Configuration::getInstance().memSpec.iDD3N2;
|
||||
memPowerSpec.idd4r = Configuration::getInstance().memSpec.iDD4R;
|
||||
memPowerSpec.idd4r2 = Configuration::getInstance().memSpec.iDD4R2;
|
||||
memPowerSpec.idd4w = Configuration::getInstance().memSpec.iDD4W;
|
||||
memPowerSpec.idd4w2 = Configuration::getInstance().memSpec.iDD4W2;
|
||||
memPowerSpec.idd5 = Configuration::getInstance().memSpec.iDD5;
|
||||
memPowerSpec.idd52 = Configuration::getInstance().memSpec.iDD52;
|
||||
memPowerSpec.idd6 = Configuration::getInstance().memSpec.iDD6;
|
||||
memPowerSpec.idd62 = Configuration::getInstance().memSpec.iDD62;
|
||||
memPowerSpec.vdd = Configuration::getInstance().memSpec.vDD;
|
||||
memPowerSpec.vdd2 = Configuration::getInstance().memSpec.vDD2;
|
||||
|
||||
MemorySpecification memSpec;
|
||||
memSpec.id = Configuration::getInstance().memSpec.MemoryId;
|
||||
memSpec.memoryType = Configuration::getInstance().memSpec.MemoryType;
|
||||
memSpec.memTimingSpec = memTimingSpec;
|
||||
memSpec.memPowerSpec = memPowerSpec;
|
||||
memSpec.memArchSpec = memArchSpec;
|
||||
|
||||
DRAMPower = new libDRAMPower( memSpec, 0 );
|
||||
}
|
||||
|
||||
// Bandwidth Calculation:
|
||||
numberOfTransactionsServed = 0;
|
||||
firstAccess = SC_ZERO_TIME;
|
||||
lastAccess = SC_ZERO_TIME;
|
||||
|
||||
// For each bank in a channel a error Model is created:
|
||||
if (StoreMode == StorageMode::ErrorModel) {
|
||||
for (unsigned i = 0; i < Configuration::getInstance().memSpec.NumberOfBanks;
|
||||
i++) {
|
||||
errorModel *em;
|
||||
std::string errorModelStr = "errorModel_bank" + std::to_string(i);
|
||||
if (powerAnalysis == true) {
|
||||
em = new errorModel(errorModelStr.c_str(), DRAMPower);
|
||||
} else {
|
||||
em = new errorModel(errorModelStr.c_str());
|
||||
}
|
||||
ememory.push_back(em);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void end_of_simulation()
|
||||
{
|
||||
}
|
||||
|
||||
~Dram()
|
||||
{
|
||||
if (powerAnalysis == true) {
|
||||
if (!Configuration::getInstance().DatabaseRecording)
|
||||
DRAMPower->calcEnergy();
|
||||
|
||||
// Print the final total energy and the average power for
|
||||
// the simulation:
|
||||
cout << name() << string(" Total Energy: ")
|
||||
<< fixed << std::setprecision( 2 )
|
||||
<< DRAMPower->getEnergy().total_energy
|
||||
* Configuration::getInstance().NumberOfDevicesOnDIMM
|
||||
<< string(" pJ")
|
||||
<< endl;
|
||||
|
||||
cout << name() << string(" Average Power: ")
|
||||
<< fixed << std::setprecision( 2 )
|
||||
<< DRAMPower->getPower().average_power
|
||||
* Configuration::getInstance().NumberOfDevicesOnDIMM
|
||||
<< string(" mW") << endl;
|
||||
}
|
||||
|
||||
// Bandwidth:
|
||||
|
||||
sc_time activeTime = numberOfTransactionsServed
|
||||
* Configuration::getInstance().memSpec.BurstLength
|
||||
/ Configuration::getInstance().memSpec.DataRate
|
||||
* Configuration::getInstance().memSpec.clk;
|
||||
|
||||
sc_time idleTime = dramController->getIdleTime();
|
||||
sc_time endTime = dramController->getEndTime();
|
||||
sc_time startTime = dramController->getStartTime();
|
||||
|
||||
double bandwidth = (activeTime / (endTime - startTime) * 100);
|
||||
double bandwidth_IDLE = ((activeTime) / (endTime - startTime - idleTime) * 100);
|
||||
|
||||
double maxBandwidth = (
|
||||
// clk in Mhz e.g. 800 [MHz]:
|
||||
(1000000 / Configuration::getInstance().memSpec.clk.to_double())
|
||||
// DataRate e.g. 2
|
||||
* Configuration::getInstance().memSpec.DataRate
|
||||
// BusWidth e.g. 8 or 64
|
||||
* Configuration::getInstance().memSpec.bitWidth
|
||||
// Number of devices on a DIMM e.g. 8
|
||||
* Configuration::getInstance().NumberOfDevicesOnDIMM ) / ( 1024 );
|
||||
|
||||
cout << name() << string(" Total Time: ")
|
||||
<< (endTime - startTime).to_string()
|
||||
<< endl;
|
||||
cout << name() << string(" AVG BW: ")
|
||||
<< std::fixed << std::setprecision(2)
|
||||
<< ((bandwidth / 100)*maxBandwidth)
|
||||
<< " Gibit/s (" << bandwidth << " %)"
|
||||
<< endl;
|
||||
cout << name() << string(" AVG BW/IDLE: ")
|
||||
<< std::fixed << std::setprecision(2)
|
||||
<< ((bandwidth_IDLE / 100)*maxBandwidth)
|
||||
<< " Gibit/s (" << (bandwidth_IDLE) << " %)"
|
||||
<< endl;
|
||||
cout << name() << string(" MAX BW: ")
|
||||
<< std::fixed << std::setprecision(2)
|
||||
<< maxBandwidth << " Gibit/s"
|
||||
<< endl;
|
||||
// Clean up:
|
||||
for (auto e : ememory) {
|
||||
delete e;
|
||||
}
|
||||
|
||||
if (Configuration::getInstance().UseMalloc) {
|
||||
free(memory);
|
||||
}
|
||||
}
|
||||
|
||||
virtual tlm::tlm_sync_enum nb_transport_fw(tlm::tlm_generic_payload &payload,
|
||||
tlm::tlm_phase &phase, sc_time &delay)
|
||||
{
|
||||
if (numberOfTransactionsServed == 0) {
|
||||
firstAccess = sc_time_stamp();
|
||||
} else {
|
||||
lastAccess = sc_time_stamp();
|
||||
}
|
||||
|
||||
unsigned int bank = DramExtension::getExtension(payload).getBank().ID();
|
||||
|
||||
// This is only needed for power simulation:
|
||||
unsigned long long cycle = 0;
|
||||
if (powerAnalysis == true) {
|
||||
cycle = sc_time_stamp().value() /
|
||||
Configuration::getInstance().memSpec.clk.value();
|
||||
}
|
||||
if (phase == BEGIN_PREB) {
|
||||
if (powerAnalysis == true) {
|
||||
DRAMPower->doCommand(MemCommand::PREB, bank, cycle);
|
||||
}
|
||||
sendToController(payload, END_PREB, delay + getExecutionTime(Command::PreB,
|
||||
payload));
|
||||
} else if (phase == BEGIN_PRE) {
|
||||
if (powerAnalysis == true) {
|
||||
DRAMPower->doCommand(MemCommand::PRE, bank, cycle);
|
||||
}
|
||||
sendToController(payload, END_PRE, delay + getExecutionTime(Command::Precharge,
|
||||
payload));
|
||||
} else if (phase == BEGIN_PRE_ALL) {
|
||||
if (powerAnalysis == true) {
|
||||
DRAMPower->doCommand(MemCommand::PREA, bank, cycle);
|
||||
}
|
||||
sendToController(payload, END_PRE_ALL,
|
||||
delay + getExecutionTime(Command::PrechargeAll, payload));
|
||||
} else if (phase == BEGIN_ACTB) {
|
||||
if (powerAnalysis == true) {
|
||||
DRAMPower->doCommand(MemCommand::ACTB, bank, cycle);
|
||||
}
|
||||
sendToController(payload, END_ACTB, delay + getExecutionTime(Command::ActB,
|
||||
payload));
|
||||
unsigned int row = DramExtension::getExtension(payload).getRow().ID();
|
||||
if (StoreMode == StorageMode::ErrorModel) {
|
||||
ememory[bank]->activate(row);
|
||||
}
|
||||
} else if (phase == BEGIN_ACT) {
|
||||
if (powerAnalysis == true) {
|
||||
DRAMPower->doCommand(MemCommand::ACT, bank, cycle);
|
||||
}
|
||||
sendToController(payload, END_ACT, delay + getExecutionTime(Command::Activate,
|
||||
payload));
|
||||
unsigned int row = DramExtension::getExtension(payload).getRow().ID();
|
||||
|
||||
if (StoreMode == StorageMode::ErrorModel) {
|
||||
ememory[bank]->activate(row);
|
||||
}
|
||||
} else if (phase == BEGIN_WR) {
|
||||
#if !defined (DRAMSYS_PCT) && !defined (DRAMSYS_GEM5)
|
||||
assert(payload.get_data_length() == bytesPerBurst);
|
||||
#endif
|
||||
|
||||
if (powerAnalysis == true) {
|
||||
DRAMPower->doCommand(MemCommand::WR, bank, cycle);
|
||||
}
|
||||
numberOfTransactionsServed++;
|
||||
|
||||
//save data:
|
||||
if (StoreMode == StorageMode::NoStorage) {
|
||||
// Don't store data
|
||||
} else if (StoreMode == StorageMode::Store) { // Use Storage
|
||||
unsigned char *phyAddr = memory + payload.get_address();
|
||||
memcpy(phyAddr, payload.get_data_ptr(), payload.get_data_length());
|
||||
} else { // == 2 Use Storage with Error Model
|
||||
ememory[bank]->store(payload);
|
||||
}
|
||||
sendToController(payload, END_WR, delay + getExecutionTime(Command::Write,
|
||||
payload));
|
||||
} else if (phase == BEGIN_RD) {
|
||||
#if !defined (DRAMSYS_PCT) && !defined (DRAMSYS_GEM5)
|
||||
assert(payload.get_data_length() == bytesPerBurst);
|
||||
#endif
|
||||
|
||||
numberOfTransactionsServed++;
|
||||
if (powerAnalysis == true) {
|
||||
DRAMPower->doCommand(MemCommand::RD, bank, cycle);
|
||||
}
|
||||
|
||||
// Load data:
|
||||
if (StoreMode == StorageMode::Store) { //use StorageMode
|
||||
unsigned char *phyAddr = memory + payload.get_address();
|
||||
memcpy(payload.get_data_ptr(), phyAddr, payload.get_data_length());
|
||||
} else if (StoreMode ==
|
||||
StorageMode::ErrorModel) { // use StorageMode with errormodel
|
||||
ememory[bank]->load(payload);
|
||||
}
|
||||
|
||||
sendToController(payload, END_RD, delay + getExecutionTime(Command::Read,
|
||||
payload));
|
||||
} else if (phase == BEGIN_WRA) {
|
||||
numberOfTransactionsServed++;
|
||||
if (powerAnalysis == true) {
|
||||
DRAMPower->doCommand(MemCommand::WRA, bank, cycle);
|
||||
}
|
||||
|
||||
//save data:
|
||||
if (StoreMode == StorageMode::NoStorage) {
|
||||
// Don't store data
|
||||
} else if (StoreMode == StorageMode::Store) { // Use Storage
|
||||
unsigned char *phyAddr = memory + payload.get_address();
|
||||
memcpy(phyAddr, payload.get_data_ptr(), payload.get_data_length());
|
||||
} else { // == 2 Use Storage with Error Model
|
||||
ememory[bank]->store(payload);
|
||||
}
|
||||
sendToController(payload, END_WRA, delay + getExecutionTime(Command::WriteA,
|
||||
payload));
|
||||
} else if (phase == BEGIN_RDA) {
|
||||
numberOfTransactionsServed++;
|
||||
if (powerAnalysis == true) {
|
||||
DRAMPower->doCommand(MemCommand::RDA, bank, cycle);
|
||||
}
|
||||
|
||||
// Load data:
|
||||
if (StoreMode == StorageMode::Store) { //use StorageMode
|
||||
unsigned char *phyAddr = memory + payload.get_address();
|
||||
memcpy(payload.get_data_ptr(), phyAddr, payload.get_data_length());
|
||||
} else if (StoreMode ==
|
||||
StorageMode::ErrorModel) { // use StorageMode with errormodel
|
||||
ememory[bank]->load(payload);
|
||||
}
|
||||
|
||||
sendToController(payload, END_RDA, delay + getExecutionTime(Command::ReadA,
|
||||
payload));
|
||||
} else if (phase == BEGIN_REFA) {
|
||||
if (powerAnalysis == true) {
|
||||
DRAMPower->doCommand(MemCommand::REF, bank, cycle);
|
||||
}
|
||||
sendToController(payload, END_REFA,
|
||||
delay + getExecutionTime(Command::AutoRefresh, payload));
|
||||
unsigned int row = DramExtension::getExtension(payload).getRow().ID();
|
||||
|
||||
if (StoreMode == StorageMode::ErrorModel) {
|
||||
ememory[bank]->refresh(row);
|
||||
}
|
||||
}
|
||||
|
||||
else if (phase == BEGIN_REFB) {
|
||||
if (powerAnalysis == true) {
|
||||
DRAMPower->doCommand(MemCommand::REFB, bank, cycle);
|
||||
}
|
||||
sendToController(payload, END_REFB,
|
||||
delay + getExecutionTime(Command::AutoRefresh, payload));
|
||||
}
|
||||
|
||||
//Powerdown phases have to be started and ended by the controller, because they do not have a fixed length
|
||||
else if (phase == BEGIN_PDNA) {
|
||||
if (powerAnalysis == true) {
|
||||
DRAMPower->doCommand(MemCommand::PDN_S_ACT, bank, cycle);
|
||||
}
|
||||
} else if (phase == END_PDNA) {
|
||||
if (powerAnalysis == true) {
|
||||
DRAMPower->doCommand(MemCommand::PUP_ACT, bank, cycle);
|
||||
}
|
||||
} else if (phase == BEGIN_PDNAB) {
|
||||
if (powerAnalysis == true) {
|
||||
SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported");
|
||||
}
|
||||
} else if (phase == END_PDNAB) {
|
||||
if (powerAnalysis == true) {
|
||||
SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported");
|
||||
}
|
||||
} else if (phase == BEGIN_PDNP) {
|
||||
if (powerAnalysis == true) {
|
||||
DRAMPower->doCommand(MemCommand::PDN_S_PRE, bank, cycle);
|
||||
}
|
||||
} else if (phase == END_PDNP) {
|
||||
if (powerAnalysis == true) {
|
||||
DRAMPower->doCommand(MemCommand::PUP_PRE, bank, cycle);
|
||||
}
|
||||
} else if (phase == BEGIN_PDNPB) {
|
||||
if (powerAnalysis == true) {
|
||||
SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported");
|
||||
}
|
||||
} else if (phase == END_PDNPB) {
|
||||
if (powerAnalysis == true) {
|
||||
SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported");
|
||||
}
|
||||
} else if (phase == BEGIN_SREF) {
|
||||
if (powerAnalysis == true) {
|
||||
DRAMPower->doCommand(MemCommand::SREN, bank, cycle);
|
||||
}
|
||||
} else if (phase == END_SREF) {
|
||||
if (powerAnalysis == true) {
|
||||
DRAMPower->doCommand(MemCommand::SREX, bank, cycle);
|
||||
}
|
||||
} else if (phase == BEGIN_SREFB) {
|
||||
if (powerAnalysis == true) {
|
||||
SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported");
|
||||
}
|
||||
} else if (phase == END_SREFB) {
|
||||
if (powerAnalysis == true) {
|
||||
SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported");
|
||||
}
|
||||
} else {
|
||||
if (powerAnalysis == true) {
|
||||
SC_REPORT_FATAL("DRAM", "DRAM PEQ was called with unknown phase");
|
||||
}
|
||||
}
|
||||
|
||||
return tlm::TLM_ACCEPTED;
|
||||
}
|
||||
|
||||
virtual unsigned int transport_dbg(tlm::tlm_generic_payload &trans)
|
||||
{
|
||||
printDebugMessage("transport_dgb");
|
||||
|
||||
// TODO: This part is not tested yet, neither with traceplayers neither with GEM5 coupling
|
||||
if (StoreMode == StorageMode::NoStorage) {
|
||||
SC_REPORT_FATAL("DRAM",
|
||||
"Debug Transport is used in combination with NoStorage");
|
||||
} else {
|
||||
tlm::tlm_command cmd = trans.get_command();
|
||||
//sc_dt::uint64 adr = trans.get_address(); // TODO: - offset;
|
||||
unsigned char *ptr = trans.get_data_ptr();
|
||||
unsigned int len = trans.get_data_length();
|
||||
//unsigned int bank = DramExtension::getExtension(trans).getBank().ID();
|
||||
|
||||
//cout << "cmd " << (cmd ? "write" : "read") << " adr " << hex << adr << " len " << len << endl;
|
||||
|
||||
if ( cmd == tlm::TLM_READ_COMMAND ) {
|
||||
if (StoreMode == StorageMode::Store) { // Use Storage
|
||||
unsigned char *phyAddr = memory + trans.get_address();
|
||||
memcpy(ptr, phyAddr, trans.get_data_length());
|
||||
} else {
|
||||
//ememory[bank]->load(trans);
|
||||
SC_REPORT_FATAL("DRAM", "Debug transport not supported with error model yet.");
|
||||
}
|
||||
} else if ( cmd == tlm::TLM_WRITE_COMMAND ) {
|
||||
|
||||
if (StoreMode == StorageMode::Store) { // Use Storage
|
||||
unsigned char *phyAddr = memory + trans.get_address();
|
||||
memcpy(phyAddr, ptr, trans.get_data_length());
|
||||
} else {
|
||||
//ememory[bank]->store(trans);
|
||||
SC_REPORT_FATAL("DRAM", "Debug transport not supported with error model yet.");
|
||||
}
|
||||
|
||||
}
|
||||
return len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
virtual unsigned int transport_dbg(tlm_generic_payload &trans);
|
||||
|
||||
void sendToController(tlm_generic_payload &payload, const tlm_phase &phase,
|
||||
const sc_time &delay)
|
||||
{
|
||||
tlm_phase TPhase = phase;
|
||||
sc_time TDelay = delay;
|
||||
tSocket->nb_transport_bw(payload, TPhase, TDelay);
|
||||
}
|
||||
const sc_time &delay);
|
||||
|
||||
void printDebugMessage(string message)
|
||||
{
|
||||
DebugManager::getInstance().printDebugMessage(name(), message);
|
||||
}
|
||||
void printDebugMessage(string message);
|
||||
|
||||
void setDramController(Controller *contr)
|
||||
{
|
||||
dramController = contr;
|
||||
}
|
||||
public:
|
||||
tlm_utils::simple_target_socket<Dram> tSocket;
|
||||
|
||||
Dram(sc_module_name);
|
||||
SC_HAS_PROCESS(Dram);
|
||||
|
||||
~Dram();
|
||||
|
||||
void setDramController(Controller *contr);
|
||||
};
|
||||
|
||||
#endif /* DRAM_H_ */
|
||||
|
||||
135
DRAMSys/library/src/simulation/RecordableDram.cpp
Normal file
135
DRAMSys/library/src/simulation/RecordableDram.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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:
|
||||
* Felipe S. Prado
|
||||
* Matthias Jung
|
||||
*/
|
||||
|
||||
#include "RecordableDram.h"
|
||||
|
||||
using namespace tlm;
|
||||
|
||||
RecordableDram::RecordableDram(sc_module_name name, TlmRecorder *tlmRecorder)
|
||||
: Dram(name), tlmRecorder(tlmRecorder)
|
||||
{
|
||||
// Create a thread that is triggered every $powerWindowSize
|
||||
// to generate a Power over Time plot in the Trace analyzer:
|
||||
if (Configuration::getInstance().PowerAnalysis
|
||||
&& Configuration::getInstance().EnableWindowing)
|
||||
SC_THREAD(powerWindow);
|
||||
}
|
||||
|
||||
RecordableDram::~RecordableDram()
|
||||
{
|
||||
if (Configuration::getInstance().PowerAnalysis)
|
||||
{
|
||||
// Obtain the residual energy which was not covered by
|
||||
// previous windows
|
||||
DRAMPower->calcEnergy();
|
||||
recordPower();
|
||||
}
|
||||
tlmRecorder->closeConnection();
|
||||
}
|
||||
|
||||
|
||||
tlm_sync_enum RecordableDram::nb_transport_fw(tlm_generic_payload &payload,
|
||||
tlm_phase &phase, sc_time &delay)
|
||||
{
|
||||
// Recording time used by the traceAnalyzer
|
||||
sc_time recTime = sc_time_stamp() + delay;
|
||||
|
||||
// These are terminating phases recorded by the DRAM. The execution
|
||||
// time of the related command must be taken into consideration.
|
||||
if (phase == END_PDNA || phase == END_PDNAB) {
|
||||
recTime += getExecutionTime(Command::PDNAX, payload);
|
||||
} else if (phase == END_PDNP || phase == END_PDNPB) {
|
||||
recTime += getExecutionTime(Command::PDNPX, payload);
|
||||
} else if (phase == END_SREF || phase == END_SREFB) {
|
||||
recTime += getExecutionTime(Command::SREFX, payload);
|
||||
}
|
||||
|
||||
unsigned int thr = DramExtension::getExtension(payload).getThread().ID();
|
||||
unsigned int ch = DramExtension::getExtension(payload).getChannel().ID();
|
||||
unsigned int bg = DramExtension::getExtension(payload).getBankGroup().ID();
|
||||
unsigned int bank = DramExtension::getExtension(payload).getBank().ID();
|
||||
unsigned int row = DramExtension::getExtension(payload).getRow().ID();
|
||||
unsigned int col = DramExtension::getExtension(payload).getColumn().ID();
|
||||
|
||||
printDebugMessage("Recording " + phaseNameToString(phase) + " thread " +
|
||||
to_string(thr) + " channel " + to_string(ch) + " bank group " + to_string(
|
||||
bg) + " bank " + to_string(bank) + " row " + to_string(row) + " column " +
|
||||
to_string(col) + " at " + recTime.to_string());
|
||||
|
||||
tlmRecorder->recordPhase(payload, phase, recTime);
|
||||
|
||||
return Dram::nb_transport_fw(payload, phase, delay);
|
||||
}
|
||||
|
||||
// This Thread is only triggered when Power Simulation is enabled.
|
||||
// It estimates the current average power which will be stored in the trace database for visualization purposes.
|
||||
void RecordableDram::powerWindow()
|
||||
{
|
||||
unsigned long long clk_cycles = 0;
|
||||
|
||||
do {
|
||||
// At the very beginning (zero clock cycles) the energy is 0, so we wait first
|
||||
wait(powerWindowSize);
|
||||
|
||||
clk_cycles = sc_time_stamp().value() /
|
||||
Configuration::getInstance().memSpec.clk.value();
|
||||
|
||||
DRAMPower->calcWindowEnergy(clk_cycles);
|
||||
|
||||
// During operation the energy should never be zero since the device is always consuming
|
||||
assert(!is_equal(DRAMPower->getEnergy().window_energy, 0.0));
|
||||
|
||||
// Store the time (in seconds) and the current average power (in mW) into the database
|
||||
recordPower();
|
||||
|
||||
// Here considering that DRAMPower provides the energy in pJ and the power in mW
|
||||
printDebugMessage(string("\tWindow Energy: \t") + to_string(
|
||||
DRAMPower->getEnergy().window_energy *
|
||||
Configuration::getInstance().NumberOfDevicesOnDIMM) + string("\t[pJ]"));
|
||||
printDebugMessage(string("\tWindow Average Power: \t") + to_string(
|
||||
DRAMPower->getPower().window_average_power *
|
||||
Configuration::getInstance().NumberOfDevicesOnDIMM) + string("\t[mW]"));
|
||||
|
||||
} while (true);
|
||||
}
|
||||
|
||||
void RecordableDram::recordPower()
|
||||
{
|
||||
tlmRecorder->recordPower(sc_time_stamp().to_seconds(),
|
||||
DRAMPower->getPower().window_average_power
|
||||
* Configuration::getInstance().NumberOfDevicesOnDIMM);
|
||||
}
|
||||
|
||||
@@ -40,66 +40,25 @@
|
||||
#include "Dram.h"
|
||||
#include "../common/TlmRecorder.h"
|
||||
|
||||
struct RecordableDram : public Dram {
|
||||
using namespace tlm;
|
||||
|
||||
class RecordableDram : public Dram
|
||||
{
|
||||
public:
|
||||
RecordableDram(sc_module_name, TlmRecorder *tlmRecorder);
|
||||
SC_HAS_PROCESS(RecordableDram);
|
||||
RecordableDram(sc_module_name name, TlmRecorder *tlmRecorder):
|
||||
Dram(name), tlmRecorder(tlmRecorder)
|
||||
{
|
||||
// Create a thread that is triggered every $powerWindowSize
|
||||
// to generate a Power over Time plot in the Trace analyzer:
|
||||
if (Configuration::getInstance().PowerAnalysis
|
||||
&& Configuration::getInstance().EnableWindowing)
|
||||
SC_THREAD(powerWindow);
|
||||
}
|
||||
|
||||
~RecordableDram()
|
||||
{
|
||||
if (Configuration::getInstance().PowerAnalysis) {
|
||||
// Obtain the residual energy which was not covered by
|
||||
// previous windows
|
||||
DRAMPower->calcEnergy();
|
||||
recordPower();
|
||||
}
|
||||
tlmRecorder->closeConnection();
|
||||
}
|
||||
~RecordableDram();
|
||||
|
||||
protected:
|
||||
virtual tlm_sync_enum nb_transport_fw(tlm_generic_payload &payload,
|
||||
tlm_phase &phase, sc_time &delay);
|
||||
|
||||
private:
|
||||
TlmRecorder *tlmRecorder;
|
||||
sc_time powerWindowSize = Configuration::getInstance().memSpec.clk *
|
||||
Configuration::getInstance().WindowSize;
|
||||
|
||||
virtual tlm::tlm_sync_enum nb_transport_fw(tlm::tlm_generic_payload &payload,
|
||||
tlm::tlm_phase &phase, sc_time &delay)
|
||||
{
|
||||
// Recording time used by the traceAnalyzer
|
||||
sc_time recTime = sc_time_stamp() + delay;
|
||||
|
||||
// These are terminating phases recorded by the DRAM. The execution
|
||||
// time of the related command must be taken into consideration.
|
||||
if (phase == END_PDNA || phase == END_PDNAB) {
|
||||
recTime += getExecutionTime(Command::PDNAX, payload);
|
||||
} else if (phase == END_PDNP || phase == END_PDNPB) {
|
||||
recTime += getExecutionTime(Command::PDNPX, payload);
|
||||
} else if (phase == END_SREF || phase == END_SREFB) {
|
||||
recTime += getExecutionTime(Command::SREFX, payload);
|
||||
}
|
||||
|
||||
unsigned int thr = DramExtension::getExtension(payload).getThread().ID();
|
||||
unsigned int ch = DramExtension::getExtension(payload).getChannel().ID();
|
||||
unsigned int bg = DramExtension::getExtension(payload).getBankGroup().ID();
|
||||
unsigned int bank = DramExtension::getExtension(payload).getBank().ID();
|
||||
unsigned int row = DramExtension::getExtension(payload).getRow().ID();
|
||||
unsigned int col = DramExtension::getExtension(payload).getColumn().ID();
|
||||
|
||||
printDebugMessage("Recording " + phaseNameToString(phase) + " thread " +
|
||||
to_string(thr) + " channel " + to_string(ch) + " bank group " + to_string(
|
||||
bg) + " bank " + to_string(bank) + " row " + to_string(row) + " column " +
|
||||
to_string(col) + " at " + recTime.to_string());
|
||||
|
||||
tlmRecorder->recordPhase(payload, phase, recTime);
|
||||
|
||||
return Dram::nb_transport_fw(payload, phase, delay);
|
||||
}
|
||||
|
||||
// When working with floats, we have to decide ourselves what is an
|
||||
// acceptable definition for "equal". Here the number is compared with a
|
||||
// suitable error margin (0.00001).
|
||||
@@ -110,42 +69,9 @@ struct RecordableDram : public Dram {
|
||||
|
||||
// This Thread is only triggered when Power Simulation is enabled.
|
||||
// It estimates the current average power which will be stored in the trace database for visualization purposes.
|
||||
void powerWindow()
|
||||
{
|
||||
unsigned long long clk_cycles = 0;
|
||||
void powerWindow();
|
||||
|
||||
do {
|
||||
// At the very beginning (zero clock cycles) the energy is 0, so we wait first
|
||||
wait(powerWindowSize);
|
||||
|
||||
clk_cycles = sc_time_stamp().value() /
|
||||
Configuration::getInstance().memSpec.clk.value();
|
||||
|
||||
DRAMPower->calcWindowEnergy(clk_cycles);
|
||||
|
||||
// During operation the energy should never be zero since the device is always consuming
|
||||
assert(!is_equal(DRAMPower->getEnergy().window_energy, 0.0));
|
||||
|
||||
// Store the time (in seconds) and the current average power (in mW) into the database
|
||||
recordPower();
|
||||
|
||||
// Here considering that DRAMPower provides the energy in pJ and the power in mW
|
||||
printDebugMessage(string("\tWindow Energy: \t") + to_string(
|
||||
DRAMPower->getEnergy().window_energy *
|
||||
Configuration::getInstance().NumberOfDevicesOnDIMM) + string("\t[pJ]"));
|
||||
printDebugMessage(string("\tWindow Average Power: \t") + to_string(
|
||||
DRAMPower->getPower().window_average_power *
|
||||
Configuration::getInstance().NumberOfDevicesOnDIMM) + string("\t[mW]"));
|
||||
|
||||
} while (true);
|
||||
}
|
||||
|
||||
void recordPower()
|
||||
{
|
||||
tlmRecorder->recordPower(sc_time_stamp().to_seconds(),
|
||||
DRAMPower->getPower().window_average_power
|
||||
* Configuration::getInstance().NumberOfDevicesOnDIMM);
|
||||
}
|
||||
void recordPower();
|
||||
};
|
||||
|
||||
#endif /* RECORDABLEDRAM_H_ */
|
||||
|
||||
Reference in New Issue
Block a user