Files
DRAMSys/DRAMSys/library/src/simulation/Dram.cpp
2019-06-27 16:02:24 +02:00

422 lines
18 KiB
C++

/*
* 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/dramExtensions.h"
#include "../controller/Controller.h"
#include "../controller/core/timingCalculations.h"
#include "../controller/core/configuration/Configuration.h"
#include "../common/protocol.h"
#include "../common/utils.h"
#include "../common/third_party/DRAMPower/src/libdrampower/LibDRAMPower.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);
tSocket.register_nb_transport_fw(this, &Dram::nb_transport_fw);
tSocket.register_transport_dbg(this, &Dram::transport_dbg);
// Parameters for DRAMPower
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);
}
Dram::~Dram()
{
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;
if (Configuration::getInstance().UseMalloc)
free(memory);
}
tlm_sync_enum Dram::nb_transport_fw(tlm_generic_payload &payload,
tlm_phase &phase, sc_time &delay)
{
MemSpec *memSpec = Configuration::getInstance().memSpec;
unsigned int bank = DramExtension::getExtension(payload).getBank().ID();
// This is only needed for power simulation:
unsigned long long cycle = sc_time_stamp().value() / memSpec->clk.value();
if (phase == BEGIN_PREB)
{
DRAMPower->doCommand(MemCommand::PREB, bank, cycle);
sendToController(payload, END_PREB, delay + memSpec->getExecutionTime(Command::PreB,
payload));
}
else if (phase == BEGIN_PRE)
{
DRAMPower->doCommand(MemCommand::PRE, bank, cycle);
sendToController(payload, END_PRE, delay + memSpec->getExecutionTime(Command::Precharge,
payload));
}
else if (phase == BEGIN_PRE_ALL)
{
DRAMPower->doCommand(MemCommand::PREA, bank, cycle);
sendToController(payload, END_PRE_ALL,
delay + memSpec->getExecutionTime(Command::PrechargeAll, payload));
}
else if (phase == BEGIN_ACTB)
{
DRAMPower->doCommand(MemCommand::ACTB, bank, cycle);
sendToController(payload, END_ACTB, delay + memSpec->getExecutionTime(Command::ActB,
payload));
}
else if (phase == BEGIN_ACT)
{
DRAMPower->doCommand(MemCommand::ACT, bank, cycle);
sendToController(payload, END_ACT, delay + memSpec->getExecutionTime(Command::Activate,
payload));
}
else if (phase == BEGIN_WR)
{
DRAMPower->doCommand(MemCommand::WR, bank, cycle);
// save data:
if (StoreMode == StorageMode::Store) // Use Storage
{
unsigned char *phyAddr = memory + payload.get_address();
memcpy(phyAddr, payload.get_data_ptr(), payload.get_data_length());
}
sendToController(payload, END_WR, delay + memSpec->getExecutionTime(Command::Write,
payload));
}
else if (phase == BEGIN_RD)
{
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());
}
sendToController(payload, END_RD, delay + memSpec->getExecutionTime(Command::Read,
payload));
}
else if (phase == BEGIN_WRA)
{
DRAMPower->doCommand(MemCommand::WRA, bank, cycle);
// save data:
if (StoreMode == StorageMode::Store) // Use Storage
{
unsigned char *phyAddr = memory + payload.get_address();
memcpy(phyAddr, payload.get_data_ptr(), payload.get_data_length());
}
sendToController(payload, END_WRA, delay + memSpec->getExecutionTime(Command::WriteA,
payload));
}
else if (phase == BEGIN_RDA)
{
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());
}
sendToController(payload, END_RDA, delay + memSpec->getExecutionTime(Command::ReadA,
payload));
}
else if (phase == BEGIN_REFA)
{
DRAMPower->doCommand(MemCommand::REF, bank, cycle);
sendToController(payload, END_REFA,
delay + memSpec->getExecutionTime(Command::AutoRefresh, payload));
}
else if (phase == BEGIN_REFB)
{
DRAMPower->doCommand(MemCommand::REFB, bank, cycle);
sendToController(payload, END_REFB,
delay + memSpec->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)
{
DRAMPower->doCommand(MemCommand::PDN_S_ACT, bank, cycle);
}
else if (phase == END_PDNA)
{
DRAMPower->doCommand(MemCommand::PUP_ACT, bank, cycle);
}
else if (phase == BEGIN_PDNAB)
{
SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported");
}
else if (phase == END_PDNAB)
{
SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported");
}
else if (phase == BEGIN_PDNP)
{
DRAMPower->doCommand(MemCommand::PDN_S_PRE, bank, cycle);
}
else if (phase == END_PDNP)
{
DRAMPower->doCommand(MemCommand::PUP_PRE, bank, cycle);
}
else if (phase == BEGIN_PDNPB)
{
SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported");
}
else if (phase == END_PDNPB)
{
SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported");
}
else if (phase == BEGIN_SREF)
{
DRAMPower->doCommand(MemCommand::SREN, bank, cycle);
}
else if (phase == END_SREF)
{
DRAMPower->doCommand(MemCommand::SREX, bank, cycle);
}
else if (phase == BEGIN_SREFB)
{
SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported");
}
else if (phase == END_SREFB)
{
SC_REPORT_FATAL("DRAM", "Power calculation for bankwise logic not supported");
}
else
{
SC_REPORT_FATAL("DRAM", "DRAM PEQ was called with unknown phase");
}
return 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);
}