Code refactoring.

This commit is contained in:
Lukas Steiner
2019-06-11 23:11:39 +02:00
parent 02803de97c
commit e7704a74e6
5 changed files with 772 additions and 593 deletions

View File

@@ -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 += \

View 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;
}

View File

@@ -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_ */

View 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);
}

View File

@@ -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_ */