diff --git a/DRAMSys/library/library.pro b/DRAMSys/library/library.pro index a1c1b07a..8063b653 100644 --- a/DRAMSys/library/library.pro +++ b/DRAMSys/library/library.pro @@ -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 += \ diff --git a/DRAMSys/library/src/simulation/Dram.cpp b/DRAMSys/library/src/simulation/Dram.cpp new file mode 100644 index 00000000..68b3acb0 --- /dev/null +++ b/DRAMSys/library/src/simulation/Dram.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#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; +} diff --git a/DRAMSys/library/src/simulation/Dram.h b/DRAMSys/library/src/simulation/Dram.h index 7c383498..20817be9 100644 --- a/DRAMSys/library/src/simulation/Dram.h +++ b/DRAMSys/library/src/simulation/Dram.h @@ -40,39 +40,24 @@ #ifndef DRAM_H_ #define DRAM_H_ -#include #include #include -#include #include -#include -#include -#include -#include -#include -#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 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 tSocket; + + Dram(sc_module_name); + SC_HAS_PROCESS(Dram); + + ~Dram(); + + void setDramController(Controller *contr); }; #endif /* DRAM_H_ */ diff --git a/DRAMSys/library/src/simulation/RecordableDram.cpp b/DRAMSys/library/src/simulation/RecordableDram.cpp new file mode 100644 index 00000000..7ba789ef --- /dev/null +++ b/DRAMSys/library/src/simulation/RecordableDram.cpp @@ -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); +} + diff --git a/DRAMSys/library/src/simulation/RecordableDram.h b/DRAMSys/library/src/simulation/RecordableDram.h index 00a2d073..669eb3cc 100644 --- a/DRAMSys/library/src/simulation/RecordableDram.h +++ b/DRAMSys/library/src/simulation/RecordableDram.h @@ -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_ */