Merge branch 'master' of git.rhrk.uni-kl.de:EIT-Wehn/dram.vp.system
This commit is contained in:
@@ -112,7 +112,6 @@ SOURCES += \
|
||||
src/error/errormodel.cpp \
|
||||
src/controller/Controller.cpp \
|
||||
src/simulation/TracePlayer.cpp \
|
||||
src/simulation/StlPlayer.cpp \
|
||||
src/controller/core/powerdown/PowerDownManagerTimeoutBankwise.cpp \
|
||||
src/simulation/TraceSetup.cpp \
|
||||
src/simulation/DRAMSys.cpp \
|
||||
@@ -124,6 +123,7 @@ SOURCES += \
|
||||
src/error/ecchamming.cpp \
|
||||
src/controller/scheduler/Fr_Fcfs_read_priority.cpp \
|
||||
src/controller/scheduler/Fr_Fcfs_grouper.cpp \
|
||||
src/controller/RecordableController.cpp \
|
||||
src/common/AddressDecoder.cpp \
|
||||
src/common/jsonAddressDecoder.cpp \
|
||||
src/controller/scheduler/Fifo_grouper.cpp
|
||||
@@ -203,6 +203,8 @@ HEADERS += \
|
||||
src/controller/scheduler/Fr_Fcfs_grouper.h \
|
||||
src/simulation/IArbiter.h \
|
||||
src/simulation/SimpleArbiter.h \
|
||||
src/controller/RecordableController.h \
|
||||
src/simulation/RecordableDram.h \
|
||||
src/common/AddressDecoder.h \
|
||||
src/common/jsonAddressDecoder.h
|
||||
#src/common/third_party/json/include/nlohmann/json.hpp \
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
<BankwiseLogic value="0"/>
|
||||
<!-- Refresh yes, no -->
|
||||
<ControllerCoreDisableRefresh value="0"/>
|
||||
<!-- Refresh Mode. 1: 1X, 2: 2X, 4: 4X (e.g., DDR4) -->
|
||||
<ControllerCoreRefMode value="1"/>
|
||||
<!-- RGR -->
|
||||
<ControllerCoreRowGranularRef value="1"/>
|
||||
<ControllerCoreRowGranularRef value="0"/>
|
||||
<ControllerCoreRowGranularRefNumAR value="8192"/>
|
||||
<ControllerCoreRowGranularRefRowInc value="1"/>
|
||||
<!-- Banks to be refreshed in RGR mode. 1: yes, 0: no (max. 16 banks) -->
|
||||
@@ -38,7 +40,7 @@
|
||||
<ControllerCoreRowGranularRefRCBInClkCycles value="37"/>
|
||||
<ControllerCoreRowGranularRefFAWBInClkCycles value="0"/>
|
||||
<!-- Postpone, pull-in -->
|
||||
<ControllerCoreEnableRefPostpone value="1"/>
|
||||
<ControllerCoreEnableRefPostpone value="0"/>
|
||||
<ControllerCoreEnableRefPullIn value="0"/>
|
||||
<ControllerCoreMaxPostponedARCmd value="8"/>
|
||||
<ControllerCoreMaxPulledInARCmd value="8"/>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<!DOCTYPE memspec SYSTEM "memspec.dtd">
|
||||
<memspec>
|
||||
<parameter id="memoryId" type="string" value="rgrspec" />
|
||||
<parameter id="memoryType" type="string" value="DDR3" />
|
||||
<parameter id="memoryType" type="string" value="DDR4" />
|
||||
<memarchitecturespec>
|
||||
<parameter id="width" type="uint" value="16" />
|
||||
<parameter id="nbrOfBankGroups" type="uint" value="1" />
|
||||
<parameter id="nbrOfBanks" type="uint" value="8" />
|
||||
<parameter id="nbrOfRanks" type="uint" value="1" />
|
||||
<parameter id="nbrOfColumns" type="uint" value="1024" />
|
||||
@@ -25,18 +26,18 @@
|
||||
<parameter id="RL" type="uint" value="18" />
|
||||
<parameter id="RP" type="uint" value="18" />
|
||||
<parameter id="RFC" type="uint" value="673" />
|
||||
<parameter id="RFC2" type="uint" value="420" />
|
||||
<parameter id="RFC4" type="uint" value="312" />
|
||||
<parameter id="RAS" type="uint" value="34" />
|
||||
<parameter id="WL" type="uint" value="12" />
|
||||
<parameter id="AL" type="uint" value="0" />
|
||||
<parameter id="DQSCK" type="uint" value="0" />
|
||||
<parameter id="RTP" type="uint" value="6" />
|
||||
<parameter id="WR" type="uint" value="15" />
|
||||
<!-- doesn't matter (exit self-refresh) -->
|
||||
<parameter id="XP" type="uint" value="4" />
|
||||
<parameter id="XPDLL" type="uint" value="13" />
|
||||
<parameter id="XS" type="uint" value="64" />
|
||||
<parameter id="XSDLL" type="uint" value="512" />
|
||||
<!-- -->
|
||||
<parameter id="REFI" type="uint" value="9364" />
|
||||
<parameter id="CL" type="uint" value="15" />
|
||||
|
||||
@@ -46,39 +47,30 @@
|
||||
<parameter id="WTR" type="uint" value="8" />
|
||||
<parameter id="CKE" type="uint" value="8" />
|
||||
<parameter id="CKESR" type="uint" value="8" />
|
||||
|
||||
<parameter id="RRD_S" type="uint" value="4" />
|
||||
<parameter id="RRD_L" type="uint" value="6" />
|
||||
<parameter id="CCD_S" type="uint" value="4" />
|
||||
<parameter id="CCD_L" type="uint" value="6" />
|
||||
<parameter id="WTR_S" type="uint" value="3" />
|
||||
<parameter id="WTR_L" type="uint" value="9" />
|
||||
</memtimingspec>
|
||||
<mempowerspec>
|
||||
<parameter id="idd0" type="double" value="210.5" />
|
||||
<!-- doesn't matter (power down) -->
|
||||
<parameter id="idd2p0" type="double" value="16.0" />
|
||||
<parameter id="idd2p1" type="double" value="55.0" />
|
||||
<!-- -->
|
||||
<parameter id="idd2n" type="double" value="99.0" />
|
||||
<!-- doesn't matter (power down) -->
|
||||
<parameter id="idd3p0" type="double" value="70.0" />
|
||||
<parameter id="idd3p1" type="double" value="70.0" />
|
||||
<!-- -->
|
||||
<parameter id="idd3n" type="double" value="115.0" />
|
||||
<parameter id="idd4w" type="double" value="1511.4" />
|
||||
<parameter id="idd4r" type="double" value="1470.8" />
|
||||
<parameter id="idd5" type="double" value="2000.0" />
|
||||
<!-- doesn't matter (self-refresh) -->
|
||||
<parameter id="idd6" type="double" value="22.0" />
|
||||
<!-- -->
|
||||
<parameter id="vdd" type="double" value="1.2" />
|
||||
<!--
|
||||
For the paper tests were made with memory type DDR3.
|
||||
There was a problem with DDR3 memspec loading discussed in
|
||||
https://git.rhrk.uni-kl.de/EIT-Wehn/dram.vp.system/issues/202
|
||||
In summary, when loading DDR3 specs the values of vdd, idd0 and
|
||||
idd6 were assigned to vdd2, idd02 and idd62 (second voltage
|
||||
domain).
|
||||
The specs provided for testing considered only one voltage
|
||||
domain. It was required to treat the DDR3 problem like a feature.
|
||||
Since the problem was fixed this specs will not produce the same
|
||||
behavior.
|
||||
See also:
|
||||
https://git.rhrk.uni-kl.de/EIT-Wehn/dram.vp.system/pull/203
|
||||
-->
|
||||
|
||||
<parameter id="idd02" type="double" value="4.05" />
|
||||
<parameter id="idd62" type="double" value="2.6" />
|
||||
<parameter id="vdd2" type="double" value="2.5" />
|
||||
</mempowerspec>
|
||||
</memspec>
|
||||
|
||||
@@ -130,6 +130,7 @@ OTHER_FILES += resources/traces/ddr3_postpone_ref_test_1.stl
|
||||
OTHER_FILES += resources/traces/ddr3_postpone_ref_test_2.stl
|
||||
OTHER_FILES += resources/traces/ddr3_postpone_ref_test_3.stl
|
||||
OTHER_FILES += resources/traces/ip*.stl
|
||||
OTHER_FILES += resources/traces/rgr*.stl
|
||||
|
||||
# Memory Controller Configs
|
||||
OTHER_FILES += resources/configs/mcconfigs/fifoStrict.xml
|
||||
|
||||
@@ -48,90 +48,90 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
TlmRecorder::TlmRecorder(sc_module_name /*name*/, string uri, string dbname,
|
||||
bool recenable) : sqlScriptURI(uri), dbName(dbname),
|
||||
recordingEnabled(recenable), totalNumTransactions(1),
|
||||
|
||||
TlmRecorder::TlmRecorder(sc_module_name /*name*/, string uri,
|
||||
string dbname) : sqlScriptURI(uri), dbName(dbname), totalNumTransactions(1),
|
||||
simulationTimeCoveredByRecording(SC_ZERO_TIME)
|
||||
{
|
||||
if (TlmRecorder::recordingEnabled == true) {
|
||||
recordedData.reserve(transactionCommitRate);
|
||||
setUpTransactionTerminatingPhases();
|
||||
openDB(TlmRecorder::dbName.c_str());
|
||||
char *sErrMsg;
|
||||
sqlite3_exec(db, "PRAGMA main.page_size = 4096", NULL, NULL, &sErrMsg);
|
||||
sqlite3_exec(db, "PRAGMA main.cache_size=10000", NULL, NULL, &sErrMsg);
|
||||
sqlite3_exec(db, "PRAGMA main.locking_mode=EXCLUSIVE", NULL, NULL, &sErrMsg);
|
||||
sqlite3_exec(db, "PRAGMA main.synchronous=OFF", NULL, NULL, &sErrMsg);
|
||||
sqlite3_exec(db, "PRAGMA journal_mode = OFF", NULL, NULL, &sErrMsg);
|
||||
recordedData.reserve(transactionCommitRate);
|
||||
setUpTransactionTerminatingPhases();
|
||||
openDB(TlmRecorder::dbName.c_str());
|
||||
char *sErrMsg;
|
||||
sqlite3_exec(db, "PRAGMA main.page_size = 4096", NULL, NULL, &sErrMsg);
|
||||
sqlite3_exec(db, "PRAGMA main.cache_size=10000", NULL, NULL, &sErrMsg);
|
||||
sqlite3_exec(db, "PRAGMA main.locking_mode=EXCLUSIVE", NULL, NULL, &sErrMsg);
|
||||
sqlite3_exec(db, "PRAGMA main.synchronous=OFF", NULL, NULL, &sErrMsg);
|
||||
sqlite3_exec(db, "PRAGMA journal_mode = OFF", NULL, NULL, &sErrMsg);
|
||||
|
||||
createTables(TlmRecorder::sqlScriptURI);
|
||||
prepareSqlStatements();
|
||||
createTables(TlmRecorder::sqlScriptURI);
|
||||
prepareSqlStatements();
|
||||
|
||||
printDebugMessage("Starting new database transaction");
|
||||
}
|
||||
printDebugMessage("Starting new database transaction");
|
||||
}
|
||||
|
||||
TlmRecorder::~TlmRecorder()
|
||||
{
|
||||
if (db)
|
||||
closeConnection();
|
||||
sqlite3_finalize(insertTransactionStatement);
|
||||
sqlite3_finalize(insertRangeStatement);
|
||||
sqlite3_finalize(updateRangeStatement);
|
||||
sqlite3_finalize(insertPhaseStatement);
|
||||
sqlite3_finalize(updatePhaseStatement);
|
||||
sqlite3_finalize(insertGeneralInfoStatement);
|
||||
sqlite3_finalize(insertDebugMessageStatement);
|
||||
sqlite3_finalize(updateDataStrobeStatement);
|
||||
sqlite3_finalize(insertPowerStatement);
|
||||
}
|
||||
|
||||
void TlmRecorder::recordPower(double timeInSeconds, double averagePower)
|
||||
{
|
||||
if (TlmRecorder::recordingEnabled) {
|
||||
sqlite3_bind_double(insertPowerStatement, 1, timeInSeconds);
|
||||
sqlite3_bind_double(insertPowerStatement, 2, averagePower);
|
||||
executeSqlStatement(insertPowerStatement);
|
||||
}
|
||||
sqlite3_bind_double(insertPowerStatement, 1, timeInSeconds);
|
||||
sqlite3_bind_double(insertPowerStatement, 2, averagePower);
|
||||
executeSqlStatement(insertPowerStatement);
|
||||
}
|
||||
|
||||
void TlmRecorder::recordPhase(tlm::tlm_generic_payload &trans,
|
||||
tlm::tlm_phase phase, sc_time time)
|
||||
{
|
||||
if (TlmRecorder::recordingEnabled) {
|
||||
if (currentTransactionsInSystem.count(&trans) == 0)
|
||||
introduceTransactionSystem(trans);
|
||||
if (currentTransactionsInSystem.count(&trans) == 0)
|
||||
introduceTransactionSystem(trans);
|
||||
|
||||
string phaseName = phaseNameToString(phase);
|
||||
string phaseBeginPrefix = "BEGIN_";
|
||||
string phaseEndPrefix = "END_";
|
||||
string phaseName = phaseNameToString(phase);
|
||||
string phaseBeginPrefix = "BEGIN_";
|
||||
string phaseEndPrefix = "END_";
|
||||
|
||||
if (phaseName.find(phaseBeginPrefix) != string::npos) {
|
||||
phaseName.erase(0, phaseBeginPrefix.length());
|
||||
assert(currentTransactionsInSystem.count(&trans) != 0);
|
||||
currentTransactionsInSystem[&trans].insertPhase(phaseName, time);
|
||||
} else {
|
||||
phaseName.erase(0, phaseEndPrefix.length());
|
||||
assert(currentTransactionsInSystem.count(&trans) != 0);
|
||||
currentTransactionsInSystem[&trans].setPhaseEnd(phaseName, time);
|
||||
}
|
||||
|
||||
bool phaseTerminatesTransaction = count(transactionTerminatingPhases.begin(),
|
||||
transactionTerminatingPhases.end(), phase) == 1;
|
||||
if (phaseTerminatesTransaction)
|
||||
removeTransactionFromSystem(trans);
|
||||
|
||||
simulationTimeCoveredByRecording = time;
|
||||
if (phaseName.find(phaseBeginPrefix) != string::npos) {
|
||||
phaseName.erase(0, phaseBeginPrefix.length());
|
||||
assert(currentTransactionsInSystem.count(&trans) != 0);
|
||||
currentTransactionsInSystem[&trans].insertPhase(phaseName, time);
|
||||
} else {
|
||||
phaseName.erase(0, phaseEndPrefix.length());
|
||||
assert(currentTransactionsInSystem.count(&trans) != 0);
|
||||
currentTransactionsInSystem[&trans].setPhaseEnd(phaseName, time);
|
||||
}
|
||||
|
||||
bool phaseTerminatesTransaction = count(transactionTerminatingPhases.begin(),
|
||||
transactionTerminatingPhases.end(), phase) == 1;
|
||||
if (phaseTerminatesTransaction)
|
||||
removeTransactionFromSystem(trans);
|
||||
|
||||
simulationTimeCoveredByRecording = time;
|
||||
}
|
||||
|
||||
|
||||
void TlmRecorder::updateDataStrobe(const sc_time &begin, const sc_time &end,
|
||||
tlm::tlm_generic_payload &trans)
|
||||
{
|
||||
if (TlmRecorder::recordingEnabled) {
|
||||
assert(currentTransactionsInSystem.count(&trans) != 0);
|
||||
currentTransactionsInSystem[&trans].timeOnDataStrobe.start = begin;
|
||||
currentTransactionsInSystem[&trans].timeOnDataStrobe.end = end;
|
||||
}
|
||||
assert(currentTransactionsInSystem.count(&trans) != 0);
|
||||
currentTransactionsInSystem[&trans].timeOnDataStrobe.start = begin;
|
||||
currentTransactionsInSystem[&trans].timeOnDataStrobe.end = end;
|
||||
}
|
||||
|
||||
|
||||
void TlmRecorder::recordDebugMessage(std::string message, sc_time time)
|
||||
{
|
||||
if (TlmRecorder::recordingEnabled)
|
||||
insertDebugMessageInDB(message, time);
|
||||
insertDebugMessageInDB(message, time);
|
||||
}
|
||||
|
||||
|
||||
@@ -434,24 +434,13 @@ void TlmRecorder::printDebugMessage(std::string message)
|
||||
|
||||
void TlmRecorder::closeConnection()
|
||||
{
|
||||
if (TlmRecorder::recordingEnabled) {
|
||||
commitRecordedDataToDB();
|
||||
insertGeneralInfo();
|
||||
printDebugMessage(
|
||||
"Number of transactions written to DB: " + std::to_string(
|
||||
totalNumTransactions - 1));
|
||||
printDebugMessage("tlmPhaseRecorder:\tEnd Recording");
|
||||
sqlite3_finalize(insertTransactionStatement);
|
||||
sqlite3_finalize(insertRangeStatement);
|
||||
sqlite3_finalize(updateRangeStatement);
|
||||
sqlite3_finalize(insertPhaseStatement);
|
||||
sqlite3_finalize(updatePhaseStatement);
|
||||
sqlite3_finalize(insertGeneralInfoStatement);
|
||||
sqlite3_finalize(insertDebugMessageStatement);
|
||||
sqlite3_finalize(updateDataStrobeStatement);
|
||||
sqlite3_finalize(insertPowerStatement);
|
||||
sqlite3_close(db);
|
||||
db = NULL;
|
||||
}
|
||||
commitRecordedDataToDB();
|
||||
insertGeneralInfo();
|
||||
printDebugMessage(
|
||||
"Number of transactions written to DB: " + std::to_string(
|
||||
totalNumTransactions - 1));
|
||||
printDebugMessage("tlmPhaseRecorder:\tEnd Recording");
|
||||
sqlite3_close(db);
|
||||
db = NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,9 +60,8 @@ class TlmRecorder : public sc_module
|
||||
public:
|
||||
std::string sqlScriptURI;
|
||||
std::string dbName;
|
||||
bool recordingEnabled;
|
||||
|
||||
TlmRecorder(sc_module_name /*name*/, string uri, string dbname, bool recenable);
|
||||
TlmRecorder(sc_module_name /*name*/, string uri, string dbname);
|
||||
~TlmRecorder();
|
||||
|
||||
void recordMCconfig(string mcconfig)
|
||||
|
||||
@@ -46,15 +46,13 @@ using std::pair;
|
||||
using std::map;
|
||||
|
||||
class JSONAddressDecoder
|
||||
: public AddressDecoder
|
||||
: private AddressDecoder
|
||||
{
|
||||
// Friendship needed so that the AddressDecoder can access the
|
||||
// constructor of this class to create the object in CreateInstance.
|
||||
friend class AddressDecoder;
|
||||
|
||||
private:
|
||||
JSONAddressDecoder();
|
||||
|
||||
vector<pair<unsigned, unsigned>>
|
||||
m_vXor; // This container stores for each used xor gate a pair which consists of "First/Number of an address bit which corresponds to a bank"
|
||||
// and "Second/Number of an address bit which corresponds to a row"
|
||||
@@ -66,6 +64,8 @@ private:
|
||||
m_vColumnBits; // This container stores for each column bit a pair which consists of "First/Number of the column bit" and "Second/Number of the address bit"
|
||||
|
||||
public:
|
||||
JSONAddressDecoder();
|
||||
|
||||
virtual void setConfiguration(std::string url);
|
||||
|
||||
virtual DecodedAddress decodeAddress(sc_dt::uint64 addr);
|
||||
|
||||
@@ -45,21 +45,21 @@
|
||||
#include "AddressDecoder.h"
|
||||
|
||||
class xmlAddressDecoder
|
||||
: public AddressDecoder
|
||||
: private AddressDecoder
|
||||
{
|
||||
// Friendship needed so that the AddressDecoder can access the
|
||||
// constructor of this class to create the object in CreateInstance.
|
||||
friend class AddressDecoder;
|
||||
|
||||
private:
|
||||
xmlAddressDecoder();
|
||||
|
||||
std::map<std::string, sc_dt::uint64> masks;
|
||||
std::map<std::string, unsigned int> shifts;
|
||||
|
||||
tinyxml2::XMLElement *addressmapping;
|
||||
|
||||
public:
|
||||
xmlAddressDecoder();
|
||||
|
||||
virtual DecodedAddress decodeAddress(sc_dt::uint64 addr);
|
||||
virtual sc_dt::uint64 encodeAddress(DecodedAddress n);
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ std::string commandToString(Command command)
|
||||
return "PRE_ALL";
|
||||
break;
|
||||
case Command::AutoRefresh:
|
||||
return "AUTO_REFRESH";
|
||||
return "REF";
|
||||
break;
|
||||
|
||||
case Command::PDNA:
|
||||
|
||||
@@ -75,114 +75,83 @@ void Controller::send(const ScheduledCommand &command,
|
||||
tlm_generic_payload &payload)
|
||||
{
|
||||
sc_assert(command.getStart() >= sc_time_stamp());
|
||||
TimeInterval dataStrobe;
|
||||
|
||||
tlm_phase phase;
|
||||
|
||||
switch (command.getCommand()) {
|
||||
//TODO: refactor tlm recorder
|
||||
case Command::Read:
|
||||
dataStrobe = command.getIntervalOnDataStrobe();
|
||||
tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload);
|
||||
controllerCorePEQ.notify(payload, BEGIN_RD,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = BEGIN_RD;
|
||||
break;
|
||||
case Command::ReadA:
|
||||
dataStrobe = command.getIntervalOnDataStrobe();
|
||||
tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload);
|
||||
controllerCorePEQ.notify(payload, BEGIN_RDA,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = BEGIN_RDA;
|
||||
break;
|
||||
case Command::Write:
|
||||
dataStrobe = command.getIntervalOnDataStrobe();
|
||||
tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload);
|
||||
controllerCorePEQ.notify(payload, BEGIN_WR,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = BEGIN_WR;
|
||||
break;
|
||||
case Command::WriteA:
|
||||
dataStrobe = command.getIntervalOnDataStrobe();
|
||||
tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload);
|
||||
controllerCorePEQ.notify(payload, BEGIN_WRA,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = BEGIN_WRA;
|
||||
break;
|
||||
case Command::AutoRefresh:
|
||||
if (!Configuration::getInstance().BankwiseLogic) {
|
||||
controllerCorePEQ.notify(payload, BEGIN_REFA,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = BEGIN_REFA;
|
||||
} else
|
||||
controllerCorePEQ.notify(payload, BEGIN_REFB,
|
||||
command.getStart() - sc_time_stamp());
|
||||
break;
|
||||
case Command::ActB:
|
||||
controllerCorePEQ.notify(payload, BEGIN_ACTB,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = BEGIN_REFB;
|
||||
break;
|
||||
case Command::Activate:
|
||||
controllerCorePEQ.notify(payload, BEGIN_ACT,
|
||||
command.getStart() - sc_time_stamp());
|
||||
break;
|
||||
case Command::PreB:
|
||||
controllerCorePEQ.notify(payload, BEGIN_PREB,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = BEGIN_ACT;
|
||||
break;
|
||||
case Command::Precharge:
|
||||
controllerCorePEQ.notify(payload, BEGIN_PRE,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = BEGIN_PRE;
|
||||
break;
|
||||
case Command::PrechargeAll:
|
||||
controllerCorePEQ.notify(payload, BEGIN_PRE_ALL,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = BEGIN_PRE_ALL;
|
||||
break;
|
||||
case Command::PDNA:
|
||||
if (!Configuration::getInstance().BankwiseLogic) {
|
||||
controllerCorePEQ.notify(payload, BEGIN_PDNA,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = BEGIN_PDNA;
|
||||
} else
|
||||
controllerCorePEQ.notify(payload, BEGIN_PDNAB,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = BEGIN_PDNAB;
|
||||
break;
|
||||
case Command::PDNAX:
|
||||
if (!Configuration::getInstance().BankwiseLogic) {
|
||||
controllerCorePEQ.notify(payload, END_PDNA,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = END_PDNA;
|
||||
} else
|
||||
controllerCorePEQ.notify(payload, END_PDNAB,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = END_PDNAB;
|
||||
break;
|
||||
case Command::PDNP:
|
||||
if (!Configuration::getInstance().BankwiseLogic) {
|
||||
controllerCorePEQ.notify(payload, BEGIN_PDNP,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = BEGIN_PDNP;
|
||||
} else
|
||||
controllerCorePEQ.notify(payload, BEGIN_PDNPB,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = BEGIN_PDNPB;
|
||||
break;
|
||||
case Command::PDNPX:
|
||||
if (!Configuration::getInstance().BankwiseLogic) {
|
||||
controllerCorePEQ.notify(payload, END_PDNP,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = END_PDNP;
|
||||
} else
|
||||
controllerCorePEQ.notify(payload, END_PDNPB,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = END_PDNPB;
|
||||
break;
|
||||
case Command::SREF:
|
||||
if (!Configuration::getInstance().BankwiseLogic) {
|
||||
controllerCorePEQ.notify(payload, BEGIN_SREF,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = BEGIN_SREF;
|
||||
} else
|
||||
controllerCorePEQ.notify(payload, BEGIN_SREFB,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = BEGIN_SREFB;
|
||||
break;
|
||||
case Command::SREFX:
|
||||
if (!Configuration::getInstance().BankwiseLogic) {
|
||||
controllerCorePEQ.notify(payload, END_SREF,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = END_SREF;
|
||||
} else
|
||||
controllerCorePEQ.notify(payload, END_SREFB,
|
||||
command.getStart() - sc_time_stamp());
|
||||
phase = END_SREFB;
|
||||
break;
|
||||
default:
|
||||
SC_REPORT_FATAL(0, "unsupported command was sent by controller");
|
||||
break;
|
||||
}
|
||||
|
||||
sc_time notDelay = command.getStart() - sc_time_stamp();
|
||||
printDebugMessage(phaseNameToString(phase) + " notification in " +
|
||||
notDelay.to_string());
|
||||
controllerCorePEQ.notify(payload, phase, notDelay);
|
||||
}
|
||||
|
||||
//Trigger the next planned refresh or the power down mode on the DRAM
|
||||
@@ -191,14 +160,20 @@ void Controller::send(Trigger trigger, sc_time time,
|
||||
{
|
||||
sc_assert(time >= sc_time_stamp());
|
||||
|
||||
sc_time delay = time - sc_time_stamp();
|
||||
tlm_phase phase;
|
||||
|
||||
if (trigger == Trigger::REFTrigger) {
|
||||
controllerCorePEQ.notify(payload, REF_TRIGGER, delay);
|
||||
phase = REF_TRIGGER;
|
||||
} else if (trigger == Trigger::PDNTrigger) {
|
||||
controllerCorePEQ.notify(payload, PDN_TRIGGER, delay);
|
||||
phase = PDN_TRIGGER;
|
||||
} else {
|
||||
SC_REPORT_FATAL("controller wrapper", "unknown trigger");
|
||||
}
|
||||
|
||||
sc_time delay = time - sc_time_stamp();
|
||||
printDebugMessage(phaseNameToString(phase) + " notification in " +
|
||||
delay.to_string());
|
||||
controllerCorePEQ.notify(payload, phase, delay);
|
||||
}
|
||||
|
||||
void Controller::controllerCorePEQCallback(tlm_generic_payload &payload,
|
||||
@@ -237,63 +212,33 @@ void Controller::controllerCorePEQCallback(tlm_generic_payload &payload,
|
||||
}
|
||||
else
|
||||
SC_REPORT_FATAL(0,
|
||||
"refreshTriggerPEQCallback queue in controller wrapper was triggered with unsupported phase");
|
||||
"Controller Core PEQ in controller wrapper was triggered with unsupported phase");
|
||||
}
|
||||
}
|
||||
|
||||
tlm_sync_enum Controller::nb_transport_fw(tlm_generic_payload &payload,
|
||||
tlm_phase &phase, sc_time &fwDelay)
|
||||
{
|
||||
sc_time recTime;
|
||||
sc_time notDelay;
|
||||
|
||||
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();
|
||||
sc_time notDelay = fwDelay;
|
||||
|
||||
if (phase == BEGIN_REQ) {
|
||||
recTime = fwDelay + sc_time_stamp();
|
||||
notDelay = clkAlign(sc_time_stamp() + fwDelay) - (sc_time_stamp() + fwDelay) +
|
||||
Configuration::getInstance().memSpec.clk;
|
||||
|
||||
printDebugMessage("[fw] 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() + " notification in " +
|
||||
notDelay.to_string());
|
||||
|
||||
tlmRecorder->recordPhase(payload, phase, recTime);
|
||||
frontendPEQ.notify(payload, phase, notDelay);
|
||||
notDelay += Configuration::getInstance().memSpec.clk;
|
||||
|
||||
//Bandwidth IDLE
|
||||
if ((getTotalNumberOfPayloadsInSystem() == 0) && idleState) {
|
||||
endBandwidthIdleCollector();
|
||||
}
|
||||
} else if (phase == END_RESP) {
|
||||
|
||||
recTime = fwDelay + sc_time_stamp() + Configuration::getInstance().memSpec.clk;
|
||||
notDelay = clkAlign(sc_time_stamp() + fwDelay) - (sc_time_stamp() + fwDelay);
|
||||
|
||||
printDebugMessage("[fw] 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() + " notification in " +
|
||||
notDelay.to_string());
|
||||
|
||||
// Badnwith IDLE
|
||||
if (getTotalNumberOfPayloadsInSystem() == 1) {
|
||||
startBandwidthIdleCollector();
|
||||
}
|
||||
|
||||
tlmRecorder->recordPhase(payload, phase, recTime);
|
||||
frontendPEQ.notify(payload, phase, notDelay);
|
||||
|
||||
}
|
||||
|
||||
printDebugMessage("[fw] " + phaseNameToString(phase) + " notification in " +
|
||||
notDelay.to_string());
|
||||
frontendPEQ.notify(payload, phase, notDelay);
|
||||
|
||||
return TLM_ACCEPTED;
|
||||
}
|
||||
|
||||
@@ -319,7 +264,7 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload,
|
||||
payload.set_response_status(tlm::TLM_OK_RESPONSE);
|
||||
sendToFrontend(payload, END_REQ, SC_ZERO_TIME);
|
||||
|
||||
scheduler->schedule(&payload);
|
||||
scheduler->storeRequest(&payload);
|
||||
scheduleNextFromScheduler(DramExtension::getExtension(payload).getBank());
|
||||
} else if (phase == PendingRequest) {
|
||||
// Schedule a pending request.
|
||||
@@ -330,7 +275,7 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload,
|
||||
backpressure->set_response_status(tlm::TLM_OK_RESPONSE);
|
||||
sendToFrontend(*backpressure, END_REQ, SC_ZERO_TIME);
|
||||
|
||||
scheduler->schedule(backpressure);
|
||||
scheduler->storeRequest(backpressure);
|
||||
scheduleNextFromScheduler(DramExtension::getExtension(backpressure).getBank());
|
||||
backpressure = NULL;
|
||||
}
|
||||
@@ -339,7 +284,7 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload,
|
||||
payload.release();
|
||||
} else {
|
||||
SC_REPORT_FATAL(0,
|
||||
"Frontend PEQ event queue in controller wrapper was triggered with unknown phase");
|
||||
"Front-end PEQ in controller wrapper was triggered with unknown phase");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,7 +326,6 @@ unsigned int Controller::getTotalNumberOfPayloadsInSystem()
|
||||
|
||||
void Controller::scheduleNextFromScheduler(Bank bank)
|
||||
{
|
||||
|
||||
if (controllerCore->bankIsBusy(bank)) {
|
||||
return;
|
||||
}
|
||||
@@ -390,11 +334,7 @@ void Controller::scheduleNextFromScheduler(Bank bank)
|
||||
pair<Command, tlm::tlm_generic_payload *> nextRequest =
|
||||
scheduler->getNextRequest(bank);
|
||||
if (nextRequest.second != NULL) {
|
||||
controllerCore->powerDownManager->wakeUp(DramExtension::getExtension(
|
||||
nextRequest.second).getBank(), sc_time_stamp());
|
||||
controllerCore->scheduleRequest(nextRequest.first, *nextRequest.second);
|
||||
printDebugMessage("\t-> Next payload was scheduled by core [" + commandToString(
|
||||
nextRequest.first) + "]");
|
||||
schedule(nextRequest.first, *nextRequest.second);
|
||||
} else {
|
||||
gp *pendingRequest = scheduler->getPendingRequest(bank);
|
||||
if (pendingRequest != NULL) {
|
||||
@@ -412,11 +352,7 @@ void Controller::scheduleNextFromScheduler(Bank bank)
|
||||
pair<Command, tlm::tlm_generic_payload *> nextRequest =
|
||||
scheduler->getNextRequest(bank);
|
||||
if (nextRequest.second != NULL) {
|
||||
controllerCore->powerDownManager->wakeUp(DramExtension::getExtension(
|
||||
nextRequest.second).getBank(), sc_time_stamp());
|
||||
controllerCore->scheduleRequest(nextRequest.first, *nextRequest.second);
|
||||
printDebugMessage("\t-> Next payload was scheduled by core [" + commandToString(
|
||||
nextRequest.first) + "] (unblocked)");
|
||||
schedule(nextRequest.first, *nextRequest.second);
|
||||
} else {
|
||||
gp *pendingRequest = scheduler->getPendingRequest(bank);
|
||||
if (pendingRequest != NULL) {
|
||||
@@ -433,6 +369,16 @@ void Controller::scheduleNextFromScheduler(Bank bank)
|
||||
blockedRequests = blocked;
|
||||
}
|
||||
|
||||
void Controller::schedule(Command command, gp &payload)
|
||||
{
|
||||
controllerCore->powerDownManager->wakeUp(DramExtension::getBank(payload),
|
||||
sc_time_stamp());
|
||||
if (controllerCore->scheduleRequest(command, payload)) {
|
||||
printDebugMessage("\t-> Next payload was scheduled by core [" + commandToString(
|
||||
command) + "] (unblocked)");
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::sendToFrontend(tlm_generic_payload &payload,
|
||||
const tlm_phase &phase, const sc_time &delay)
|
||||
{
|
||||
@@ -444,26 +390,9 @@ void Controller::sendToFrontend(tlm_generic_payload &payload,
|
||||
tlm_sync_enum Controller::nb_transport_bw(tlm_generic_payload &payload,
|
||||
tlm_phase &phase, sc_time &bwDelay)
|
||||
{
|
||||
sc_time recTime = bwDelay + sc_time_stamp();
|
||||
sc_time notDelay = bwDelay;
|
||||
|
||||
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("[bw] 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() + " notification in " +
|
||||
notDelay.to_string());
|
||||
|
||||
dramPEQ.notify(payload, phase, notDelay);
|
||||
tlmRecorder->recordPhase(payload, phase, recTime);
|
||||
|
||||
printDebugMessage("[bw] " + phaseNameToString(phase) + " notification in " +
|
||||
bwDelay.to_string());
|
||||
dramPEQ.notify(payload, phase, bwDelay);
|
||||
return TLM_ACCEPTED;
|
||||
}
|
||||
|
||||
@@ -510,7 +439,7 @@ void Controller::dramPEQCallback(tlm_generic_payload &payload,
|
||||
// scheduler implementation)
|
||||
} else {
|
||||
string str =
|
||||
string("dramPEQCallback queue in controller wrapper was triggered with unsupported phase ")
|
||||
string("DRAM PEQ in controller wrapper was triggered with unsupported phase ")
|
||||
+ phaseNameToString(phase);
|
||||
SC_REPORT_FATAL(0, str.c_str());
|
||||
}
|
||||
|
||||
@@ -80,11 +80,11 @@ DECLARE_EXTENDED_PHASE(PendingRequest);
|
||||
class Controller: public sc_module, public IController
|
||||
{
|
||||
public:
|
||||
Controller(sc_module_name /*name*/, TlmRecorder *rec) :
|
||||
Controller(sc_module_name /*name*/) :
|
||||
frontendPEQ(this, &Controller::frontendPEQCallback), dramPEQ(this,
|
||||
&Controller::dramPEQCallback), controllerCorePEQ(this,
|
||||
&Controller::controllerCorePEQCallback),
|
||||
debugManager(DebugManager::getInstance()), tlmRecorder(rec)
|
||||
debugManager(DebugManager::getInstance())
|
||||
{
|
||||
controllerCore = new ControllerCore("core", *this, numberOfPayloadsInSystem);
|
||||
buildScheduler();
|
||||
@@ -121,27 +121,28 @@ public:
|
||||
return controllerThreadId;
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
void buildScheduler();
|
||||
void payloadEntersSystem(tlm_generic_payload &payload);
|
||||
void payloadLeavesSystem(tlm_generic_payload &payload);
|
||||
|
||||
// --- FRONTEND ------
|
||||
tlm_sync_enum nb_transport_fw(tlm_generic_payload &payload, tlm_phase &phase,
|
||||
sc_time &fwDelay);
|
||||
virtual tlm_sync_enum nb_transport_fw(tlm_generic_payload &payload,
|
||||
tlm_phase &phase, sc_time &fwDelay);
|
||||
virtual unsigned int transport_dbg(tlm::tlm_generic_payload &trans);
|
||||
void frontendPEQCallback(tlm_generic_payload &payload, const tlm_phase &phase);
|
||||
void sendToFrontend(tlm_generic_payload &payload, const tlm_phase &phase,
|
||||
const sc_time &delay);
|
||||
virtual void sendToFrontend(tlm_generic_payload &payload,
|
||||
const tlm_phase &phase, const sc_time &delay);
|
||||
|
||||
// --- DRAM ------
|
||||
tlm_sync_enum nb_transport_bw(tlm_generic_payload &payload, tlm_phase &phase,
|
||||
sc_time &bwDelay);
|
||||
virtual tlm_sync_enum nb_transport_bw(tlm_generic_payload &payload,
|
||||
tlm_phase &phase, sc_time &bwDelay);
|
||||
void dramPEQCallback(tlm_generic_payload &payload, const tlm_phase &phase);
|
||||
void sendToDram(tlm_generic_payload &payload, const tlm_phase &phase,
|
||||
const sc_time &delay);
|
||||
|
||||
// ------- CONTROLLER CORE ---------
|
||||
virtual void schedule(Command command, gp &payload);
|
||||
void controllerCorePEQCallback(tlm_generic_payload &payload,
|
||||
const tlm_phase &phase);
|
||||
|
||||
@@ -161,7 +162,6 @@ private:
|
||||
tlm_utils::peq_with_cb_and_phase<Controller> controllerCorePEQ;
|
||||
|
||||
DebugManager &debugManager;
|
||||
TlmRecorder *tlmRecorder;
|
||||
|
||||
// Bandwidth realted:
|
||||
sc_time idleStart;
|
||||
|
||||
92
DRAMSys/library/src/controller/RecordableController.cpp
Normal file
92
DRAMSys/library/src/controller/RecordableController.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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 "RecordableController.h"
|
||||
|
||||
tlm_sync_enum RecordableController::nb_transport_fw(tlm_generic_payload
|
||||
&payload, tlm_phase &phase, sc_time &fwDelay)
|
||||
{
|
||||
recordPhase(payload, phase, fwDelay);
|
||||
|
||||
return Controller::nb_transport_fw(payload, phase, fwDelay);
|
||||
}
|
||||
|
||||
void RecordableController::sendToFrontend(tlm_generic_payload &payload,
|
||||
const tlm_phase &phase, const sc_time &delay)
|
||||
{
|
||||
recordPhase(payload, phase, delay);
|
||||
|
||||
Controller::sendToFrontend(payload, phase, delay);
|
||||
}
|
||||
|
||||
tlm_sync_enum RecordableController::nb_transport_bw(tlm_generic_payload
|
||||
&payload, tlm_phase &phase, sc_time &bwDelay)
|
||||
{
|
||||
recordPhase(payload, phase, bwDelay);
|
||||
|
||||
return Controller::nb_transport_bw(payload, phase, bwDelay);
|
||||
}
|
||||
|
||||
void RecordableController::recordPhase(tlm::tlm_generic_payload &trans,
|
||||
tlm::tlm_phase phase, sc_time delay)
|
||||
{
|
||||
sc_time recTime = delay + sc_time_stamp();
|
||||
|
||||
unsigned int thr = DramExtension::getExtension(trans).getThread().ID();
|
||||
unsigned int ch = DramExtension::getExtension(trans).getChannel().ID();
|
||||
unsigned int bg = DramExtension::getExtension(trans).getBankGroup().ID();
|
||||
unsigned int bank = DramExtension::getExtension(trans).getBank().ID();
|
||||
unsigned int row = DramExtension::getExtension(trans).getRow().ID();
|
||||
unsigned int col = DramExtension::getExtension(trans).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(trans, phase, recTime);
|
||||
}
|
||||
|
||||
void RecordableController::schedule(Command command, gp &payload)
|
||||
{
|
||||
Controller::schedule(command, payload);
|
||||
if (commandIsIn(command, {Command::Read, Command::ReadA, Command::Write, Command::WriteA})) {
|
||||
ScheduledCommand scheduledCommand = controllerCore->state->getLastCommand(
|
||||
command, DramExtension::getBank(payload));
|
||||
TimeInterval dataStrobe = scheduledCommand.getIntervalOnDataStrobe();
|
||||
tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload);
|
||||
}
|
||||
}
|
||||
64
DRAMSys/library/src/controller/RecordableController.h
Normal file
64
DRAMSys/library/src/controller/RecordableController.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef RECORDABLECONTROLLER_H
|
||||
#define RECORDABLECONTROLLER_H
|
||||
|
||||
#include "Controller.h"
|
||||
|
||||
struct RecordableController: public Controller {
|
||||
public:
|
||||
RecordableController(sc_module_name name, TlmRecorder *rec) :
|
||||
Controller(name), tlmRecorder(rec)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
TlmRecorder *tlmRecorder;
|
||||
|
||||
virtual tlm_sync_enum nb_transport_fw(tlm_generic_payload &payload,
|
||||
tlm_phase &phase, sc_time &fwDelay) override;
|
||||
virtual tlm_sync_enum nb_transport_bw(tlm_generic_payload &payload,
|
||||
tlm_phase &phase, sc_time &bwDelay) override;
|
||||
virtual void sendToFrontend(tlm_generic_payload &payload,
|
||||
const tlm_phase &phase, const sc_time &delay) override;
|
||||
virtual void schedule(Command command, tlm_generic_payload &payload) override;
|
||||
|
||||
void recordPhase(tlm::tlm_generic_payload &trans, tlm::tlm_phase phase,
|
||||
sc_time delay);
|
||||
};
|
||||
|
||||
#endif // RECORDABLECONTROLLER_H
|
||||
@@ -166,7 +166,7 @@ void ControllerCore::triggerRefresh(tlm::tlm_generic_payload &payload)
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerCore::scheduleRequest(Command command,
|
||||
bool ControllerCore::scheduleRequest(Command command,
|
||||
tlm::tlm_generic_payload &payload)
|
||||
{
|
||||
sc_time start = clkAlign(sc_time_stamp());
|
||||
@@ -175,13 +175,16 @@ void ControllerCore::scheduleRequest(Command command,
|
||||
if (config.ControllerCoreDisableRefresh == true) {
|
||||
state->change(scheduledCommand);
|
||||
controller.send(scheduledCommand, payload);
|
||||
return true;
|
||||
} else {
|
||||
if (!((command == Command::Precharge || command == Command::Activate)
|
||||
&& refreshManager->hasCollision(scheduledCommand))) {
|
||||
state->change(scheduledCommand);
|
||||
controller.send(scheduledCommand, payload);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ScheduledCommand ControllerCore::schedule(Command command, sc_time start,
|
||||
@@ -236,7 +239,6 @@ bool ControllerCore::bankIsBusy(Bank bank)
|
||||
SC_REPORT_FATAL("Core", "Last command unkown");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const std::vector<Bank> &ControllerCore::getBanks()
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
std::map<Bank, int> &numberOfPayloads);
|
||||
virtual ~ControllerCore();
|
||||
|
||||
void scheduleRequest(Command command, tlm::tlm_generic_payload &payload);
|
||||
bool scheduleRequest(Command command, tlm::tlm_generic_payload &payload);
|
||||
void triggerRefresh(tlm::tlm_generic_payload &payload);
|
||||
|
||||
const std::vector<Bank> &getBanks();
|
||||
|
||||
@@ -90,8 +90,15 @@ sc_time getExecutionTime(Command command, tlm::tlm_generic_payload &payload)
|
||||
} else if (command == Command::PrechargeAll) {
|
||||
return config.tRP;
|
||||
} else if (command == Command::AutoRefresh) {
|
||||
return getElementFromMap(config.refreshTimings,
|
||||
DramExtension::getExtension(payload).getBank()).tRFC;
|
||||
if (Configuration::getInstance().getRefMode() == 4)
|
||||
return getElementFromMap(config.refreshTimings,
|
||||
DramExtension::getExtension(payload).getBank()).tRFC4;
|
||||
else if (Configuration::getInstance().getRefMode() == 2)
|
||||
return getElementFromMap(config.refreshTimings,
|
||||
DramExtension::getExtension(payload).getBank()).tRFC2;
|
||||
else
|
||||
return getElementFromMap(config.refreshTimings,
|
||||
DramExtension::getExtension(payload).getBank()).tRFC;
|
||||
} else if (command == Command::PDNAX || command == Command::PDNPX
|
||||
|| command == Command::SREFX) {
|
||||
return config.clk;
|
||||
|
||||
@@ -202,7 +202,12 @@ void Configuration::setParameter(std::string name, std::string value)
|
||||
RowGranularRef = string2bool(value);
|
||||
else if (name == "ControllerCoreRowGranularRefRowInc")RowInc = string2int(
|
||||
value);
|
||||
else if (name == "ControllerCoreRowGranularRefNumAR")NumAR = string2int(value);
|
||||
else if (name == "ControllerCoreRefMode") {
|
||||
RefMode = string2int(value);
|
||||
if (RefMode != 1 && RefMode != 2 && RefMode != 4)
|
||||
SC_REPORT_FATAL("Configuration", (name + " invalid value.").c_str());
|
||||
} else if (name == "ControllerCoreRowGranularRefNumAR")NumAR = string2int(
|
||||
value);
|
||||
else if (name == "ControllerCoreRowGranularRefB0")RGRB0 = string2bool(value);
|
||||
else if (name == "ControllerCoreRowGranularRefB1")RGRB1 = string2bool(value);
|
||||
else if (name == "ControllerCoreRowGranularRefB2")RGRB2 = string2bool(value);
|
||||
@@ -235,20 +240,8 @@ void Configuration::setParameter(std::string name, std::string value)
|
||||
ControllerCoreForceMaxRefBurst = string2bool(value);
|
||||
else if (name == "ControllerCoreEnableRefPostpone") {
|
||||
ControllerCoreEnableRefPostpone = string2bool(value);
|
||||
// Refresh postpone feature available for DDR3 only in the current
|
||||
// version of DRAMsys.
|
||||
if (ControllerCoreEnableRefPostpone && memSpec.MemoryType != "DDR3") {
|
||||
SC_REPORT_FATAL("Configuration",
|
||||
(name + " requires memory type DDR3.").c_str());
|
||||
}
|
||||
} else if (name == "ControllerCoreEnableRefPullIn") {
|
||||
ControllerCoreEnableRefPullIn = string2bool(value);
|
||||
// Refresh pull-in feature available for DDR3 only in the current
|
||||
// version of DRAMsys.
|
||||
if (ControllerCoreEnableRefPullIn && memSpec.MemoryType != "DDR3") {
|
||||
SC_REPORT_FATAL("Configuration",
|
||||
(name + " requires memory type DDR3.").c_str());
|
||||
}
|
||||
} else if (name == "ControllerCoreMaxPostponedARCmd")
|
||||
ControllerCoreMaxPostponedARCmd = string2int(value);
|
||||
else if (name == "ControllerCoreMaxPulledInARCmd")
|
||||
@@ -423,6 +416,11 @@ unsigned int Configuration::getRowInc(void)
|
||||
return RowInc;
|
||||
}
|
||||
|
||||
unsigned int Configuration::getRefMode(void)
|
||||
{
|
||||
return RefMode;
|
||||
}
|
||||
|
||||
// Changes the number of bytes depeding on the ECC Controller. This function is needed for modules which get data directly or indirectly from the ECC Controller
|
||||
unsigned int Configuration::adjustNumBytesAfterECC(unsigned nBytes)
|
||||
{
|
||||
|
||||
@@ -116,10 +116,12 @@ struct Configuration {
|
||||
bool RGRB14 = true;
|
||||
bool RGRB15 = true;
|
||||
unsigned int NumAR = 8192;
|
||||
unsigned int RefMode = 1;
|
||||
unsigned int RowInc = 1;
|
||||
bool getRGRBank(unsigned int);
|
||||
unsigned int getNumAR(void);
|
||||
unsigned int getRowInc(void);
|
||||
unsigned int getRefMode(void);
|
||||
bool ControllerCoreForceMaxRefBurst = false;
|
||||
bool ControllerCoreEnableRefPostpone = false;
|
||||
bool ControllerCoreEnableRefPullIn = false;
|
||||
|
||||
@@ -277,12 +277,16 @@ void ConfigurationLoader::loadDDR4(Configuration &config, XMLElement *memspec)
|
||||
config.memSpec.tXSRDLL = clk * queryUIntParameter(timings, "XSDLL");
|
||||
config.memSpec.tAL = clk * queryUIntParameter(timings, "AL");
|
||||
config.memSpec.tRFC = clk * queryUIntParameter(timings, "RFC");
|
||||
config.memSpec.tRFC2 = clk * queryUIntParameter(timings, "RFC2");
|
||||
config.memSpec.tRFC4 = clk * queryUIntParameter(timings, "RFC4");
|
||||
config.memSpec.tREFI = clk * queryUIntParameter(timings, "REFI");
|
||||
config.memSpec.tDQSCK = clk * queryUIntParameter(timings, "DQSCK");
|
||||
|
||||
config.memSpec.refreshTimings.clear();
|
||||
for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; ++i) {
|
||||
config.memSpec.refreshTimings[Bank(i)] = RefreshTiming(config.memSpec.tRFC,
|
||||
config.memSpec.tRFC2,
|
||||
config.memSpec.tRFC4,
|
||||
config.memSpec.tREFI);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,8 +44,13 @@
|
||||
|
||||
struct RefreshTiming {
|
||||
RefreshTiming() {}
|
||||
RefreshTiming(sc_time tRFC, sc_time tREFI) : tRFC(tRFC), tREFI(tREFI) {}
|
||||
RefreshTiming(sc_time tRFC, sc_time tREFI) : tRFC(tRFC), tRFC2(SC_ZERO_TIME),
|
||||
tRFC4(SC_ZERO_TIME), tREFI(tREFI) {}
|
||||
RefreshTiming(sc_time tRFC, sc_time tRFC2, sc_time tRFC4,
|
||||
sc_time tREFI) : tRFC(tRFC), tRFC2(tRFC2), tRFC4(tRFC4), tREFI(tREFI) {}
|
||||
sc_time tRFC;
|
||||
sc_time tRFC2;
|
||||
sc_time tRFC4;
|
||||
sc_time tREFI;
|
||||
};
|
||||
|
||||
@@ -109,7 +114,9 @@ struct MemSpec {
|
||||
sc_time tAL; //additive delay (delayed execution in dram)
|
||||
sc_time tDQSCK;
|
||||
|
||||
sc_time tRFC; //min ref->act delay
|
||||
sc_time tRFC; //min ref->act delay 1X mode
|
||||
sc_time tRFC2; //min ref->act delay 2X mode
|
||||
sc_time tRFC4; //min ref->act delay 4X mode
|
||||
sc_time tREFI; //auto refresh must be issued at an average periodic interval tREFI
|
||||
|
||||
// Currents and Voltages:
|
||||
|
||||
@@ -172,7 +172,6 @@ void PowerDownManager::sendPowerDownPayload(ScheduledCommand &pdnToSend)
|
||||
pdnToSend.getCommand()) + " on bank " + to_string(pdnToSend.getBank().ID()) +
|
||||
" start time " + pdnToSend.getStart().to_string() + " end time " +
|
||||
pdnToSend.getEnd().to_string());
|
||||
|
||||
}
|
||||
|
||||
void PowerDownManager::setPowerDownState(PowerDownState state)
|
||||
|
||||
@@ -42,18 +42,17 @@ using namespace std;
|
||||
RGR::RGR(sc_module_name, ControllerCore &ctrlcore) : ccore(ctrlcore),
|
||||
timing(ctrlcore.config.memSpec.refreshTimings[ccore.getBanks()[0]])
|
||||
{
|
||||
if (ccore.config.ControllerCoreEnableRefPostpone) {
|
||||
maxpostpone = ccore.config.ControllerCoreMaxPostponedARCmd;
|
||||
}
|
||||
if (ccore.config.ControllerCoreEnableRefPullIn) {
|
||||
maxpullin = ccore.config.ControllerCoreMaxPulledInARCmd;
|
||||
}
|
||||
auto m = ccore.config.getRefMode();
|
||||
tREFIx = timing.tREFI / m;
|
||||
if (ccore.config.ControllerCoreEnableRefPostpone)
|
||||
maxpostpone = ccore.config.ControllerCoreMaxPostponedARCmd * m;
|
||||
if (ccore.config.ControllerCoreEnableRefPullIn)
|
||||
maxpullin = ccore.config.ControllerCoreMaxPulledInARCmd * m;
|
||||
#if 0
|
||||
if (Configuration::getInstance().BankwiseLogic) {
|
||||
if (ccore.config.BankwiseLogic) {
|
||||
for (Bank b : ccore.getBanks()) {
|
||||
sc_time refi = Configuration::getInstance().memSpec.refreshTimings[b].tREFI;
|
||||
nextPlannedRefreshs[b] = b.ID() * refi /
|
||||
Configuration::getInstance().memSpec.NumberOfBanks;
|
||||
auto nbs = ccore.config.memSpec.NumberOfBanks;
|
||||
nextPlannedRefreshs[b] = b.ID() * tREFIx / nbs;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -66,12 +65,12 @@ RGR::RGR(sc_module_name, ControllerCore &ctrlcore) : ccore(ctrlcore),
|
||||
nextState[b] = ST_REFRESH;
|
||||
setUpDummy(rps[b], b);
|
||||
}
|
||||
if (Configuration::getInstance().BankwiseLogic) {
|
||||
if (ccore.config.BankwiseLogic) {
|
||||
for (Bank b : ccore.getBanks()) {
|
||||
planNextRefresh(b, timing.tREFI);
|
||||
planNextRefresh(b, tREFIx);
|
||||
}
|
||||
} else {
|
||||
planNextRefresh(ccore.getBanks()[0], timing.tREFI);
|
||||
planNextRefresh(ccore.getBanks()[0], tREFIx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,16 +82,14 @@ bool RGR::hasCollision(const ScheduledCommand __attribute__((unused)) &cmd)
|
||||
{
|
||||
#if 0
|
||||
bool r = false;
|
||||
nbs = Configuration::getInstance().memSpec.NumberOfBanks;
|
||||
nbs = ccore.config.memSpec.NumberOfBanks;
|
||||
for (unsigned b = 0; b < nbs; b++) {
|
||||
if (cmd.getStart() < currentRefresh[b] && cmd.getEnd() > currentRefresh[b])
|
||||
r = true;
|
||||
|
||||
if (cmd.getStart() < nextPlannedRefreshs[b]
|
||||
&& cmd.getEnd() > nextPlannedRefreshs[b])
|
||||
r = true;
|
||||
}
|
||||
|
||||
return r;
|
||||
#else
|
||||
return false;
|
||||
@@ -102,12 +99,13 @@ bool RGR::hasCollision(const ScheduledCommand __attribute__((unused)) &cmd)
|
||||
void RGR::doRefresh(tlm::tlm_generic_payload &p, sc_time t)
|
||||
{
|
||||
sc_assert(!isInvalidated(p, t));
|
||||
auto nr = Configuration::getInstance().memSpec.NumberOfRows;
|
||||
auto nar = Configuration::getInstance().getNumAR();
|
||||
auto ri = Configuration::getInstance().getRowInc();
|
||||
assert((nr / nar) > 0);
|
||||
auto nr = ccore.config.memSpec.NumberOfRows;
|
||||
auto nar = ccore.config.getNumAR();
|
||||
auto ri = ccore.config.getRowInc();
|
||||
auto m = ccore.config.getRefMode();
|
||||
assert(((nr / m) / nar) > 0);
|
||||
Bank b = DramExtension::getExtension(p).getBank();
|
||||
bool bwl = Configuration::getInstance().BankwiseLogic;
|
||||
bool bwl = ccore.config.BankwiseLogic;
|
||||
bool o = ccore.state->rowBufferStates->rowBufferIsOpen(b);
|
||||
bool ac = ccore.state->rowBufferStates->allRowBuffersAreClosed();
|
||||
bool pre = !!(bwl ? o : (!ac));
|
||||
@@ -123,28 +121,28 @@ void RGR::doRefresh(tlm::tlm_generic_payload &p, sc_time t)
|
||||
if (pre) {
|
||||
if (!bwl) {
|
||||
for (Bank b : ccore.getBanks()) {
|
||||
auto rgrb = Configuration::getInstance().getRGRBank(b.ID());
|
||||
auto rgrb = ccore.config.getRGRBank(b.ID());
|
||||
if (ccore.state->rowBufferStates->rowBufferIsOpen(b) && rgrb) {
|
||||
ccore.scheduleRequest(Command::PreB, rps[Bank(b)]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (Configuration::getInstance().getRGRBank(b.ID())) {
|
||||
if (ccore.config.getRGRBank(b.ID())) {
|
||||
ccore.scheduleRequest(Command::PreB, rps[b]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned r = 0; r < (nr / nar); r += ri) {
|
||||
for (unsigned r = 0; r < ((nr / m) / nar); r += ri) {
|
||||
if (!!bwl) {
|
||||
if (Configuration::getInstance().getRGRBank(b.ID())) {
|
||||
if (ccore.config.getRGRBank(b.ID())) {
|
||||
ccore.scheduleRequest(Command::ActB, rps[b]);
|
||||
ccore.scheduleRequest(Command::PreB, rps[b]);
|
||||
}
|
||||
DramExtension::getExtension(p).incrementRow();
|
||||
} else {
|
||||
for (Bank b : ccore.getBanks()) {
|
||||
if (Configuration::getInstance().getRGRBank(b.ID())) {
|
||||
if (ccore.config.getRGRBank(b.ID())) {
|
||||
ccore.scheduleRequest(Command::ActB, rps[b]);
|
||||
ccore.scheduleRequest(Command::PreB, rps[b]);
|
||||
}
|
||||
@@ -158,7 +156,7 @@ void RGR::scheduleRefresh(tlm::tlm_generic_payload &p, sc_time t)
|
||||
{
|
||||
sc_time nrt;
|
||||
Bank b = DramExtension::getExtension(p).getBank();
|
||||
auto bwl = Configuration::getInstance().BankwiseLogic;
|
||||
auto bwl = ccore.config.BankwiseLogic;
|
||||
bool preq = bwl ? ccore.hasPendingRequests(b) : ccore.hasPendingRequests();
|
||||
bool canPostpone = preq && (arCmdCounter[b] < maxpostpone);
|
||||
bool canPullIn = !preq && (arCmdCounter[b] < maxpullin);
|
||||
@@ -176,7 +174,7 @@ void RGR::scheduleRefresh(tlm::tlm_generic_payload &p, sc_time t)
|
||||
nrt = SC_ZERO_TIME;
|
||||
} else {
|
||||
doRefresh(p, t);
|
||||
nrt = timing.tREFI;
|
||||
nrt = tREFIx;
|
||||
nextState[b] = ST_REFRESH;
|
||||
}
|
||||
break;
|
||||
@@ -199,7 +197,7 @@ void RGR::scheduleRefresh(tlm::tlm_generic_payload &p, sc_time t)
|
||||
nrt = SC_ZERO_TIME;
|
||||
} else {
|
||||
nextState[b] = ST_SKIP;
|
||||
nrt = timing.tREFI;
|
||||
nrt = tREFIx;
|
||||
}
|
||||
break;
|
||||
case ST_POSTPONE:
|
||||
@@ -213,7 +211,7 @@ void RGR::scheduleRefresh(tlm::tlm_generic_payload &p, sc_time t)
|
||||
} else {
|
||||
arCmdCounter[b]++;
|
||||
nextState[b] = ST_POSTPONE;
|
||||
nrt = timing.tREFI;
|
||||
nrt = tREFIx;
|
||||
}
|
||||
break;
|
||||
case ST_BURST:
|
||||
@@ -229,10 +227,10 @@ void RGR::scheduleRefresh(tlm::tlm_generic_payload &p, sc_time t)
|
||||
break;
|
||||
case ST_ALIGN:
|
||||
if (previousState[b] == ST_PULLIN) {
|
||||
nrt = timing.tREFI;
|
||||
nrt = tREFIx;
|
||||
nextState[b] = ST_SKIP;
|
||||
} else {
|
||||
nrt = timing.tREFI;
|
||||
nrt = tREFIx;
|
||||
nextState[b] = ST_REFRESH;
|
||||
}
|
||||
break;
|
||||
@@ -252,7 +250,7 @@ void RGR::planNextRefresh(Bank b, sc_time t)
|
||||
void RGR::reInitialize(Bank b, sc_time t)
|
||||
{
|
||||
nextPlannedRefreshs[b] = clkAlign(t, Alignment::DOWN);
|
||||
planNextRefresh(b, timing.tREFI);
|
||||
planNextRefresh(b, tREFIx);
|
||||
}
|
||||
|
||||
bool RGR::isInvalidated(tlm::tlm_generic_payload &p, sc_time t)
|
||||
@@ -264,3 +262,4 @@ void RGR::printDebugMessage(std::string msg)
|
||||
{
|
||||
DebugManager::getInstance().printDebugMessage(this->name(), msg);
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ public:
|
||||
void reInitialize(Bank bank, sc_time time) override;
|
||||
bool isInvalidated(tlm::tlm_generic_payload &payload, sc_time time) override;
|
||||
private:
|
||||
sc_time tREFIx;
|
||||
ControllerCore &ccore;
|
||||
RefreshTiming &timing;
|
||||
std::map<Bank, tlm::tlm_generic_payload> rps;
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
* Matthias Jung
|
||||
* Felipe S. Prado
|
||||
* Ana Mativi
|
||||
* Éder F. Zulian
|
||||
*/
|
||||
|
||||
#include "RefreshManager.h"
|
||||
@@ -44,22 +45,24 @@
|
||||
|
||||
using namespace tlm;
|
||||
|
||||
RefreshManager::RefreshManager(sc_module_name /*name*/,
|
||||
ControllerCore &controller) :
|
||||
RefreshManager::RefreshManager(sc_module_name, ControllerCore &controller) :
|
||||
controllerCore(controller),
|
||||
timing(controller.config.memSpec.refreshTimings[Bank(0)]),
|
||||
nextPlannedRefresh(SC_ZERO_TIME)
|
||||
{
|
||||
auto m = controllerCore.config.getRefMode();
|
||||
tREFIx = timing.tREFI / m;
|
||||
tRFCx = m == 4 ? timing.tRFC4 : m == 2 ? timing.tRFC2 : timing.tRFC;
|
||||
if (controllerCore.config.ControllerCoreEnableRefPostpone) {
|
||||
maxpostpone = controllerCore.config.ControllerCoreMaxPostponedARCmd;
|
||||
maxpostpone = controllerCore.config.ControllerCoreMaxPostponedARCmd * m;
|
||||
}
|
||||
if (controllerCore.config.ControllerCoreEnableRefPullIn) {
|
||||
maxpullin = controllerCore.config.ControllerCoreMaxPulledInARCmd;
|
||||
maxpullin = controllerCore.config.ControllerCoreMaxPulledInARCmd * m;
|
||||
}
|
||||
for (Bank bank : controller.getBanks()) {
|
||||
setUpDummy(refreshPayloads[bank], bank);
|
||||
}
|
||||
planNextRefresh(timing.tREFI);
|
||||
planNextRefresh(tREFIx);
|
||||
}
|
||||
|
||||
RefreshManager::~RefreshManager()
|
||||
@@ -74,20 +77,20 @@ bool RefreshManager::hasCollision(const ScheduledCommand &command)
|
||||
bool collisionWithNextRefStart = command.getEnd() >= nextPlannedRefresh;
|
||||
|
||||
if (controllerCore.config.ControllerCoreEnableRefPostpone
|
||||
&& (arCmdCounter <
|
||||
maxpostpone)) { // Flexible refresh is on and have "credits" to postpone
|
||||
collisionWithNextRefStart =
|
||||
false; // Then there will not be a collision with next refresh because nextPlannedRefresh will be updated
|
||||
&& (arCmdCounter < maxpostpone)) {
|
||||
// Flexible refresh is on and have "credits" to postpone
|
||||
// Then there will not be a collision with next refresh because
|
||||
// nextPlannedRefresh will be updated
|
||||
collisionWithNextRefStart = false;
|
||||
}
|
||||
return collisionWithPreviousRefEnd || collisionWithNextRefStart;
|
||||
}
|
||||
|
||||
void RefreshManager::doRefresh(tlm::tlm_generic_payload &payload __attribute__((
|
||||
unused)), sc_time time)
|
||||
void RefreshManager::doRefresh(tlm::tlm_generic_payload &payload, sc_time time)
|
||||
{
|
||||
sc_assert(!isInvalidated(payload, time));
|
||||
|
||||
//Check if any row on all banks is activated and if so, a PrechargeAll command must be scheduled before the refresh command.
|
||||
//Check if any row on all banks is activated and if so, a PrechargeAll
|
||||
//command must be scheduled before the refresh command.
|
||||
if (!controllerCore.state->rowBufferStates->allRowBuffersAreClosed()) {
|
||||
ScheduledCommand prechargeAllMaster(Command::PrechargeAll, time,
|
||||
getExecutionTime(Command::PrechargeAll, refreshPayloads[Bank(0)]),
|
||||
@@ -124,24 +127,22 @@ void RefreshManager::doRefresh(tlm::tlm_generic_payload &payload __attribute__((
|
||||
}
|
||||
|
||||
|
||||
void RefreshManager::scheduleRefresh(tlm::tlm_generic_payload &payload
|
||||
__attribute__((unused)), sc_time time)
|
||||
void RefreshManager::scheduleRefresh(tlm::tlm_generic_payload &payload,
|
||||
sc_time time)
|
||||
{
|
||||
sc_time nextRefTiming;
|
||||
bool pendingReq = controllerCore.hasPendingRequests();
|
||||
bool canPostpone = pendingReq && (arCmdCounter < maxpostpone);
|
||||
bool canPullIn = !pendingReq && (arCmdCounter < maxpullin);
|
||||
|
||||
previousState = currentState;
|
||||
currentState = nextState;
|
||||
|
||||
switch (currentState) {
|
||||
case ST_REFRESH:
|
||||
// Regular Refresh. It's possible to migrate from this to the flexible refresh states
|
||||
|
||||
assert(arCmdCounter ==
|
||||
0); // The arCmdCounter should always be equal to zero here
|
||||
|
||||
// Regular Refresh. It's possible to migrate from this to the flexible
|
||||
// refresh states
|
||||
// The arCmdCounter should always be equal to zero here
|
||||
assert(arCmdCounter == 0);
|
||||
if (canPostpone) {
|
||||
nextState = ST_POSTPONE;
|
||||
nextRefTiming = SC_ZERO_TIME;
|
||||
@@ -150,90 +151,89 @@ void RefreshManager::scheduleRefresh(tlm::tlm_generic_payload &payload
|
||||
nextRefTiming = SC_ZERO_TIME; // Attempt to burst pull-in
|
||||
} else {
|
||||
doRefresh(payload, time);
|
||||
nextRefTiming = timing.tREFI;
|
||||
nextRefTiming = tREFIx;
|
||||
nextState = ST_REFRESH;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_PULLIN:
|
||||
// Pull-In Refresh. Try to pull-in refreshes as long as the limit hasn't been reached yet and has credits
|
||||
|
||||
// Pull-In Refresh. Try to pull-in refreshes as long as the limit
|
||||
// hasn't been reached yet and has credits
|
||||
if (canPullIn) {
|
||||
doRefresh(payload, time);
|
||||
arCmdCounter++;
|
||||
nextState = ST_PULLIN;
|
||||
nextRefTiming = timing.tRFC;
|
||||
nextRefTiming = tRFCx;
|
||||
} else {
|
||||
alignValue = arCmdCounter; // Saving value to be used by ST_ALIGN
|
||||
// Saving value to be used by ST_ALIGN
|
||||
alignValue = arCmdCounter;
|
||||
nextState = ST_ALIGN;
|
||||
nextRefTiming = SC_ZERO_TIME;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_SKIP:
|
||||
// Skip Refresh. The arCmdCounter is used to skip the correct amount of refreshes
|
||||
|
||||
// Skip Refresh. The arCmdCounter is used to skip the correct amount
|
||||
// of refreshes
|
||||
arCmdCounter--;
|
||||
if (arCmdCounter == 0) {
|
||||
nextState = ST_REFRESH;
|
||||
nextRefTiming = SC_ZERO_TIME;
|
||||
} else {
|
||||
nextState = ST_SKIP;
|
||||
nextRefTiming = timing.tREFI;
|
||||
nextRefTiming = tREFIx;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_POSTPONE:
|
||||
// Postpone Refresh. Delaying refreshes as long as there are pending requests and credits to postpone. Should be followed by a burst refresh
|
||||
|
||||
// Postpone Refresh. Delaying refreshes as long as there are pending
|
||||
// requests and credits to postpone. Should be followed by a burst
|
||||
// refresh
|
||||
if ((arCmdCounter == maxpostpone) || ((!pendingReq)
|
||||
&& !controllerCore.config.ControllerCoreForceMaxRefBurst)) { // Burst conditions met
|
||||
if (arCmdCounter <
|
||||
maxpostpone) { // In case the burst was started by inactivity, need to also count the current REF
|
||||
&& !controllerCore.config.ControllerCoreForceMaxRefBurst)) {
|
||||
// Burst conditions met
|
||||
if (arCmdCounter < maxpostpone) {
|
||||
// In case the burst was started by inactivity, need to also
|
||||
// count the current REF
|
||||
arCmdCounter++;
|
||||
}
|
||||
alignValue =
|
||||
arCmdCounter; // Will start a burst next, so the value is saved to be used by ST_ALIGN
|
||||
// Will start a burst next, so the value is saved to be used by
|
||||
// ST_ALIGN
|
||||
alignValue = arCmdCounter;
|
||||
nextState = ST_BURST;
|
||||
nextRefTiming = SC_ZERO_TIME;
|
||||
} else {
|
||||
arCmdCounter++;
|
||||
nextState = ST_POSTPONE;
|
||||
nextRefTiming = timing.tREFI;
|
||||
nextRefTiming = tREFIx;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_BURST:
|
||||
// Burst Refresh. The arCmdCounter is used to issue the correct amount of refreshes
|
||||
|
||||
// Burst Refresh. The arCmdCounter is used to issue the correct amount
|
||||
// of refreshes
|
||||
arCmdCounter--;
|
||||
doRefresh(payload, time);
|
||||
if (arCmdCounter == 0) { // All bursts issued, next state will align to tREFI
|
||||
if (arCmdCounter == 0) {
|
||||
// All bursts issued, next state will align to tREFIx
|
||||
nextState = ST_ALIGN;
|
||||
nextRefTiming = SC_ZERO_TIME;
|
||||
} else {
|
||||
nextState = ST_BURST;
|
||||
nextRefTiming = timing.tRFC;
|
||||
nextRefTiming = tRFCx;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_ALIGN:
|
||||
// Align Refresh. Adjusting the timing so the next REF timing will be a in a time multiple of tREFI
|
||||
|
||||
// Align Refresh. Adjusting the timing so the next REF timing will be
|
||||
// a in a time multiple of tREFIx
|
||||
if (previousState == ST_PULLIN) {
|
||||
nextRefTiming = timing.tREFI - (timing.tRFC * (alignValue));
|
||||
nextRefTiming = tREFIx - (tRFCx * (alignValue));
|
||||
nextState = ST_SKIP;
|
||||
} else {
|
||||
nextRefTiming = timing.tREFI - (timing.tRFC * (alignValue - 1));
|
||||
nextRefTiming = tREFIx - (tRFCx * (alignValue - 1));
|
||||
nextState = ST_REFRESH;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
SC_REPORT_FATAL(this->name(), "Invalid State in Flexible Refresh FSM. Stop.");
|
||||
break;
|
||||
}
|
||||
|
||||
planNextRefresh(nextRefTiming);
|
||||
}
|
||||
|
||||
@@ -244,10 +244,10 @@ void RefreshManager::planNextRefresh(sc_time nextRefTiming)
|
||||
refreshPayloads[Bank(0)]);
|
||||
}
|
||||
|
||||
void RefreshManager::reInitialize(Bank /*bank*/, sc_time time)
|
||||
void RefreshManager::reInitialize(Bank, sc_time time)
|
||||
{
|
||||
nextPlannedRefresh = clkAlign(time, Alignment::DOWN);
|
||||
planNextRefresh(timing.tREFI);
|
||||
planNextRefresh(tREFIx);
|
||||
}
|
||||
|
||||
bool RefreshManager::isInvalidated(tlm::tlm_generic_payload &payload
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
* Authors:
|
||||
* Robert Gernhardt
|
||||
* Matthias Jung
|
||||
* Éder F. Zulian
|
||||
*/
|
||||
|
||||
#ifndef REFRESHMANAGER_H_
|
||||
@@ -59,6 +60,8 @@ private:
|
||||
ControllerCore &controllerCore;
|
||||
RefreshTiming &timing;
|
||||
sc_time nextPlannedRefresh;
|
||||
sc_time tREFIx;
|
||||
sc_time tRFCx;
|
||||
std::map<Bank, tlm::tlm_generic_payload> refreshPayloads;
|
||||
unsigned int maxpostpone = 0;
|
||||
unsigned int maxpullin = 0;
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
* Authors:
|
||||
* Janik Schlemminger
|
||||
* Matthias Jung
|
||||
* Éder F. Zulian
|
||||
*/
|
||||
|
||||
#include "RefreshManagerBankwise.h"
|
||||
@@ -45,12 +46,13 @@ RefreshManagerBankwise::RefreshManagerBankwise(sc_module_name,
|
||||
ControllerCore &controller) : controllerCore(controller),
|
||||
timing(controller.config.memSpec.refreshTimings[Bank(0)])
|
||||
{
|
||||
if (controllerCore.config.ControllerCoreEnableRefPostpone) {
|
||||
maxpostpone = controllerCore.config.ControllerCoreMaxPostponedARCmd;
|
||||
}
|
||||
if (controllerCore.config.ControllerCoreEnableRefPullIn) {
|
||||
maxpullin = controllerCore.config.ControllerCoreMaxPulledInARCmd;
|
||||
}
|
||||
auto m = controllerCore.config.getRefMode();
|
||||
tREFIx = timing.tREFI / m;
|
||||
tRFCx = m == 4 ? timing.tRFC4 : m == 2 ? timing.tRFC2 : timing.tRFC;
|
||||
if (controllerCore.config.ControllerCoreEnableRefPostpone)
|
||||
maxpostpone = controllerCore.config.ControllerCoreMaxPostponedARCmd * m;
|
||||
if (controllerCore.config.ControllerCoreEnableRefPullIn)
|
||||
maxpullin = controllerCore.config.ControllerCoreMaxPulledInARCmd * m;
|
||||
for (Bank bank : controller.getBanks()) {
|
||||
nextPlannedRefreshs[bank] = SC_ZERO_TIME;
|
||||
arCmdCounter[bank] = 0;
|
||||
@@ -59,7 +61,7 @@ RefreshManagerBankwise::RefreshManagerBankwise(sc_module_name,
|
||||
previousState[bank] = ST_REFRESH;
|
||||
nextState[bank] = ST_REFRESH;
|
||||
setUpDummy(refreshPayloads[bank], bank);
|
||||
planNextRefresh(bank, timing.tREFI);
|
||||
planNextRefresh(bank, tREFIx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +117,6 @@ void RefreshManagerBankwise::scheduleRefresh(tlm::tlm_generic_payload &payload,
|
||||
bool pendingReq = controllerCore.hasPendingRequests(bank);
|
||||
bool canPostpone = pendingReq && (arCmdCounter[bank] < maxpostpone);
|
||||
bool canPullIn = !pendingReq && (arCmdCounter[bank] < maxpullin);
|
||||
|
||||
previousState[bank] = currentState[bank];
|
||||
currentState[bank] = nextState[bank];
|
||||
|
||||
@@ -134,11 +135,10 @@ void RefreshManagerBankwise::scheduleRefresh(tlm::tlm_generic_payload &payload,
|
||||
nextRefTiming = SC_ZERO_TIME; // Attempt to burst pull-in
|
||||
} else {
|
||||
doRefresh(payload, time);
|
||||
nextRefTiming = timing.tREFI;
|
||||
nextRefTiming = tREFIx;
|
||||
nextState[bank] = ST_REFRESH;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_PULLIN:
|
||||
// Pull-In Refresh. Try to pull-in refreshes as long as the limit
|
||||
// hasn't been reached yet and has credits
|
||||
@@ -147,33 +147,30 @@ void RefreshManagerBankwise::scheduleRefresh(tlm::tlm_generic_payload &payload,
|
||||
doRefresh(payload, time);
|
||||
arCmdCounter[bank]++;
|
||||
nextState[bank] = ST_PULLIN;
|
||||
nextRefTiming = timing.tRFC;
|
||||
nextRefTiming = tRFCx;
|
||||
} else {
|
||||
alignValue[bank] = arCmdCounter[bank]; // Saving value to be used by ST_ALIGN
|
||||
// Saving value to be used by ST_ALIGN
|
||||
alignValue[bank] = arCmdCounter[bank];
|
||||
nextState[bank] = ST_ALIGN;
|
||||
nextRefTiming = SC_ZERO_TIME;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_SKIP:
|
||||
// Skip Refresh. The arCmdCounter[bank] is used to skip the correct
|
||||
// amount of refreshes
|
||||
|
||||
arCmdCounter[bank]--;
|
||||
if (arCmdCounter[bank] == 0) {
|
||||
nextState[bank] = ST_REFRESH;
|
||||
nextRefTiming = SC_ZERO_TIME;
|
||||
} else {
|
||||
nextState[bank] = ST_SKIP;
|
||||
nextRefTiming = timing.tREFI;
|
||||
nextRefTiming = tREFIx;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_POSTPONE:
|
||||
// Postpone Refresh. Delaying refreshes as long as there are pending
|
||||
// requests and credits to postpone. Should be followed by a burst
|
||||
// refresh.
|
||||
|
||||
if ((arCmdCounter[bank] == maxpostpone) || ((!pendingReq)
|
||||
&& !controllerCore.config.ControllerCoreForceMaxRefBurst)) {
|
||||
// Burst conditions met
|
||||
@@ -190,39 +187,35 @@ void RefreshManagerBankwise::scheduleRefresh(tlm::tlm_generic_payload &payload,
|
||||
} else {
|
||||
arCmdCounter[bank]++;
|
||||
nextState[bank] = ST_POSTPONE;
|
||||
nextRefTiming = timing.tREFI;
|
||||
nextRefTiming = tREFIx;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_BURST:
|
||||
// Burst Refresh. The arCmdCounter[bank] is used to issue the correct
|
||||
// amount of refreshes
|
||||
|
||||
arCmdCounter[bank]--;
|
||||
doRefresh(payload, time);
|
||||
if (arCmdCounter[bank] == 0) {
|
||||
// All bursts issued, next state will align to tREFI
|
||||
// All bursts issued, next state will align to tREFIx
|
||||
nextState[bank] = ST_ALIGN;
|
||||
nextRefTiming = SC_ZERO_TIME;
|
||||
} else {
|
||||
nextState[bank] = ST_BURST;
|
||||
nextRefTiming = timing.tRFC;
|
||||
nextRefTiming = tRFCx;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_ALIGN:
|
||||
// Align Refresh. Adjusting the timing so the next REF timing will be
|
||||
// a in a time multiple of tREFI.
|
||||
|
||||
// a in a time multiple of tREFIx.
|
||||
if (previousState[bank] == ST_PULLIN) {
|
||||
nextRefTiming = timing.tREFI - (timing.tRFC * (alignValue[bank]));
|
||||
nextRefTiming = tREFIx - (tRFCx * (alignValue[bank]));
|
||||
nextState[bank] = ST_SKIP;
|
||||
} else {
|
||||
nextRefTiming = timing.tREFI - (timing.tRFC * (alignValue[bank] - 1));
|
||||
nextRefTiming = tREFIx - (tRFCx * (alignValue[bank] - 1));
|
||||
nextState[bank] = ST_REFRESH;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
SC_REPORT_FATAL(this->name(), "Invalid State in Flexible Refresh FSM. Stop.");
|
||||
break;
|
||||
@@ -241,7 +234,7 @@ void RefreshManagerBankwise::planNextRefresh(Bank bank, sc_time nextRefTiming)
|
||||
void RefreshManagerBankwise::reInitialize(Bank bank, sc_time time)
|
||||
{
|
||||
nextPlannedRefreshs[bank] = clkAlign(time, Alignment::DOWN);
|
||||
planNextRefresh(bank, timing.tREFI);
|
||||
planNextRefresh(bank, tREFIx);
|
||||
}
|
||||
|
||||
bool RefreshManagerBankwise::isInvalidated(tlm::tlm_generic_payload &payload,
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
* Authors:
|
||||
* Janik Schlemminger
|
||||
* Matthias Jung
|
||||
* Éder F. Zulian
|
||||
*/
|
||||
|
||||
#ifndef BANKWISEREFRESHMANAGER_H_
|
||||
@@ -59,6 +60,8 @@ public:
|
||||
private:
|
||||
ControllerCore &controllerCore;
|
||||
RefreshTiming &timing;
|
||||
sc_time tREFIx;
|
||||
sc_time tRFCx;
|
||||
std::map<Bank, tlm::tlm_generic_payload> refreshPayloads;
|
||||
std::map<Bank, sc_time> nextPlannedRefreshs;
|
||||
unsigned int maxpostpone = 0;
|
||||
|
||||
@@ -45,7 +45,6 @@ bool ScheduledCommand::isNoCommand() const
|
||||
&& executionTime == SC_ZERO_TIME && end == SC_ZERO_TIME);
|
||||
}
|
||||
|
||||
|
||||
bool ScheduledCommand::isValidCommand() const
|
||||
{
|
||||
return !isNoCommand();
|
||||
|
||||
@@ -62,7 +62,6 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ScheduledCommand() :
|
||||
command(Command::NOP), start(SC_ZERO_TIME), executionTime(SC_ZERO_TIME),
|
||||
end(SC_ZERO_TIME), extension()
|
||||
|
||||
@@ -62,7 +62,13 @@ void ActBChecker::delayToSatisfyConstraints(ScheduledCommand &cmd) const
|
||||
config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR +
|
||||
config.memSpec.tRP);
|
||||
} else if (lcb.getCommand() == Command::AutoRefresh) {
|
||||
cmd.establishMinDistanceFromStart(lcb.getStart(), config.memSpec.tRFC);
|
||||
auto m = Configuration::getInstance().getRefMode();
|
||||
if (m == 4)
|
||||
cmd.establishMinDistanceFromStart(lcb.getStart(), config.memSpec.tRFC4);
|
||||
else if (m == 2)
|
||||
cmd.establishMinDistanceFromStart(lcb.getStart(), config.memSpec.tRFC2);
|
||||
else
|
||||
cmd.establishMinDistanceFromStart(lcb.getStart(), config.memSpec.tRFC);
|
||||
} else if (lcb.getCommand() == Command::PDNPX
|
||||
|| lcb.getCommand() == Command::PDNAX) {
|
||||
cmd.establishMinDistanceFromStart(lcb.getStart(), config.memSpec.tXP);
|
||||
|
||||
@@ -71,8 +71,16 @@ void ActivateChecker::delayToSatisfyConstraints(ScheduledCommand &command) const
|
||||
config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR +
|
||||
config.memSpec.tRP);
|
||||
} else if (lastCommandOnBank.getCommand() == Command::AutoRefresh) {
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tRFC);
|
||||
auto m = Configuration::getInstance().getRefMode();
|
||||
if (m == 4)
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tRFC4);
|
||||
else if (m == 2)
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tRFC2);
|
||||
else
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tRFC);
|
||||
} else if (lastCommandOnBank.getCommand() == Command::PDNPX
|
||||
|| lastCommandOnBank.getCommand() == Command::PDNAX) {
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
|
||||
@@ -54,7 +54,13 @@ sc_time PowerDownChecker::getTimeConstraintToEnterPowerDown(Command lastCmd,
|
||||
constraint = config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR +
|
||||
config.memSpec.clk;
|
||||
} else if (lastCmd == Command::AutoRefresh) {
|
||||
constraint = config.memSpec.tRFC;
|
||||
auto m = Configuration::getInstance().getRefMode();
|
||||
if (m == 4)
|
||||
constraint = config.memSpec.tRFC4;
|
||||
else if (m == 2)
|
||||
constraint = config.memSpec.tRFC2;
|
||||
else
|
||||
constraint = config.memSpec.tRFC;
|
||||
} else if (lastCmd == Command::PDNPX || lastCmd == Command::PDNAX) {
|
||||
constraint = config.memSpec.tXP;
|
||||
} else if (lastCmd == Command::SREFX) {
|
||||
|
||||
@@ -70,8 +70,16 @@ const
|
||||
config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR +
|
||||
config.memSpec.tRP);
|
||||
} else if (lastCommand.getCommand() == Command::AutoRefresh) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tRFC);
|
||||
auto m = Configuration::getInstance().getRefMode();
|
||||
if (m == 4)
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tRFC4);
|
||||
else if (m == 2)
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tRFC2);
|
||||
else
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tRFC);
|
||||
} else if (lastCommand.getCommand() == Command::PDNAX
|
||||
|| lastCommand.getCommand() == Command::PDNPX) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
void Fifo::schedule(gp *payload)
|
||||
void Fifo::storeRequest(gp *payload)
|
||||
{
|
||||
buffer[DramExtension::getExtension(payload).getBank()].emplace_back(payload);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
Fifo(ControllerCore &controllerCore) : IScheduler(controllerCore) {}
|
||||
virtual ~Fifo() {}
|
||||
|
||||
void schedule(gp *payload) override;
|
||||
void storeRequest(gp *payload) override;
|
||||
std::pair<Command, tlm::tlm_generic_payload *> getNextRequest(
|
||||
Bank bank) override;
|
||||
virtual gp *getPendingRequest(Bank bank) override;
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
#include "FifoStrict.h"
|
||||
|
||||
void FifoStrict::schedule(tlm::tlm_generic_payload *payload)
|
||||
void FifoStrict::storeRequest(tlm::tlm_generic_payload *payload)
|
||||
{
|
||||
Bank bank = DramExtension::getExtension(payload).getBank();
|
||||
buffer.push_back(std::pair<Bank, tlm::tlm_generic_payload *>(bank, payload));
|
||||
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
controller(controller) {}
|
||||
virtual ~FifoStrict() {}
|
||||
|
||||
void schedule(gp *payload) override;
|
||||
void storeRequest(gp *payload) override;
|
||||
std::pair<Command, tlm::tlm_generic_payload *> getNextRequest(
|
||||
Bank bank) override;
|
||||
virtual gp *getPendingRequest(Bank bank) override;
|
||||
|
||||
@@ -58,9 +58,8 @@ using namespace std;
|
||||
// Bank6: OOOOO0XX
|
||||
// Bank7: XXXXXXXX
|
||||
|
||||
void FR_FCFS::schedule(gp *payload)
|
||||
void FR_FCFS::storeRequest(gp *payload)
|
||||
{
|
||||
|
||||
// FIXME: Question: what if the buffer is full? IMHO the schedule function
|
||||
// should provide a true or false when the placement into the buffer worked
|
||||
// out or not (?).
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
FR_FCFS(ControllerCore &controllerCore) : IScheduler(controllerCore) {}
|
||||
virtual ~FR_FCFS() {}
|
||||
|
||||
void schedule(gp *payload) override;
|
||||
void storeRequest(gp *payload) override;
|
||||
std::pair<Command, tlm::tlm_generic_payload *> getNextRequest(
|
||||
Bank bank) override;
|
||||
virtual gp *getPendingRequest(Bank bank) override;
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
virtual ~IScheduler() {}
|
||||
IScheduler(ControllerCore &controllerCore) : controllerCore(controllerCore) {}
|
||||
|
||||
virtual void schedule(gp *payload) = 0;
|
||||
virtual void storeRequest(gp *payload) = 0;
|
||||
virtual std::pair<Command, gp *> getNextRequest(Bank bank) = 0;
|
||||
virtual gp *getPendingRequest(Bank bank) = 0;
|
||||
static std::string sendername;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
void SMS::schedule(gp *payload)
|
||||
void SMS::storeRequest(gp *payload)
|
||||
{
|
||||
Thread thread = DramExtension::getExtension(payload).getThread();
|
||||
bool wasEmpty = isRequestBuffersEmpty();
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
virtual void schedule(gp *payload) override;
|
||||
virtual void storeRequest(gp *payload) override;
|
||||
virtual std::pair<Command, gp *> getNextRequest(Bank bank) override;
|
||||
virtual gp *getPendingRequest(Bank bank) override;
|
||||
|
||||
|
||||
@@ -79,11 +79,6 @@ public:
|
||||
tSocket.register_transport_dbg(this, &Arbiter::transport_dbg);
|
||||
}
|
||||
|
||||
void setTlmRecorders(std::vector<TlmRecorder *> recorders)
|
||||
{
|
||||
tlmRecorders = recorders;
|
||||
}
|
||||
|
||||
private:
|
||||
tlm_utils::peq_with_cb_and_phase<Arbiter> payloadEventQueue;
|
||||
|
||||
@@ -96,8 +91,6 @@ private:
|
||||
// This is a queue of responses comming from the memory side. The phase of these transactions is BEGIN_RESP.
|
||||
std::map<unsigned int, queue<tlm_generic_payload *>> receivedResponses;
|
||||
|
||||
std::vector<TlmRecorder *> tlmRecorders;
|
||||
|
||||
//used to map the transaction from devices to the arbiter's target socket ID.
|
||||
std::map<tlm_generic_payload *, int> routeMap;
|
||||
|
||||
@@ -111,15 +104,10 @@ private:
|
||||
payload).getChannel().ID()) {
|
||||
SC_REPORT_FATAL("Arbiter", "Payload extension was corrupted");
|
||||
}
|
||||
sc_time recTime = bwDelay + sc_time_stamp();
|
||||
sc_time notDelay = bwDelay;
|
||||
|
||||
printDebugMessage("[bw] Recording " + phaseNameToString(
|
||||
phase) + " at " + recTime.to_string() + " notification in " +
|
||||
notDelay.to_string());
|
||||
|
||||
tlmRecorders[channelId]->recordPhase(payload, phase, recTime);
|
||||
payloadEventQueue.notify(payload, phase, notDelay);
|
||||
printDebugMessage("[bw] " + phaseNameToString(phase) + " notification in " +
|
||||
bwDelay.to_string());
|
||||
payloadEventQueue.notify(payload, phase, bwDelay);
|
||||
return TLM_ACCEPTED;
|
||||
}
|
||||
|
||||
@@ -128,6 +116,8 @@ private:
|
||||
tlm_sync_enum nb_transport_fw(int id, tlm_generic_payload &payload,
|
||||
tlm_phase &phase, sc_time &fwDelay)
|
||||
{
|
||||
sc_time notDelay = clkAlign(sc_time_stamp() + fwDelay) -
|
||||
(sc_time_stamp() + fwDelay);
|
||||
if (phase == BEGIN_REQ) {
|
||||
// adjust address offset:
|
||||
payload.set_address(payload.get_address() -
|
||||
@@ -141,12 +131,15 @@ private:
|
||||
appendDramExtension(id, payload);
|
||||
payload.acquire();
|
||||
} else if (phase == END_RESP) {
|
||||
notDelay += Configuration::getInstance().memSpec.clk;
|
||||
// Erase before the payload is released.
|
||||
routeMap.erase(&payload);
|
||||
payload.release();
|
||||
}
|
||||
|
||||
payloadEventQueue.notify(payload, phase, fwDelay);
|
||||
printDebugMessage("[fw] " + phaseNameToString(phase) + " notification in " +
|
||||
notDelay.to_string());
|
||||
payloadEventQueue.notify(payload, phase, notDelay);
|
||||
return TLM_ACCEPTED;
|
||||
}
|
||||
|
||||
|
||||
@@ -198,8 +198,7 @@ void DRAMSys::setupTlmRecorders(const string &traceName,
|
||||
TlmRecorder *tlmRecorder =
|
||||
new TlmRecorder(recorderName.c_str(),
|
||||
sqlScriptURI.c_str(),
|
||||
dbName.c_str(),
|
||||
Configuration::getInstance().DatabaseRecording);
|
||||
dbName.c_str());
|
||||
tlmRecorder->recordMCconfig(Configuration::getInstance().mcconfigUri);
|
||||
tlmRecorder->recordMemspec(Configuration::getInstance().memspecUri);
|
||||
|
||||
@@ -219,7 +218,9 @@ void DRAMSys::instantiateModules(const string &traceName,
|
||||
|
||||
// Create and properly initialize TLM recorders.
|
||||
// They need to be ready before creating some modules.
|
||||
setupTlmRecorders(traceName, pathToResources);
|
||||
bool recordingEnabled = Configuration::getInstance().DatabaseRecording;
|
||||
if (recordingEnabled)
|
||||
setupTlmRecorders(traceName, pathToResources);
|
||||
|
||||
// Create new ECC Controller
|
||||
switch (Configuration::getInstance().ECCMode) {
|
||||
@@ -236,19 +237,26 @@ void DRAMSys::instantiateModules(const string &traceName,
|
||||
|
||||
// Create arbiter
|
||||
arbiter = new Arbiter("arbiter");
|
||||
arbiter->setTlmRecorders(tlmRecorders);
|
||||
|
||||
// Create DRAM
|
||||
for (size_t i = 0;
|
||||
i < Configuration::getInstance().NumberOfMemChannels;
|
||||
i++) {
|
||||
std::string str = "controller" + std::to_string(i);
|
||||
Controller *controller = new Controller(str.c_str(), tlmRecorders[i]);
|
||||
|
||||
Controller *controller;
|
||||
if (recordingEnabled)
|
||||
controller = new RecordableController(str.c_str(), tlmRecorders[i]);
|
||||
else
|
||||
controller = new Controller(str.c_str());
|
||||
controllers.push_back(controller);
|
||||
|
||||
str = "dram" + std::to_string(i);
|
||||
Dram *dram = new Dram(str.c_str());
|
||||
dram->setTlmRecorder(tlmRecorders[i]);
|
||||
Dram *dram;
|
||||
if (recordingEnabled)
|
||||
dram = new RecordableDram(str.c_str(), tlmRecorders[i]);
|
||||
else
|
||||
dram = new Dram(str.c_str());
|
||||
dram->setDramController(controllers[i]);
|
||||
drams.push_back(dram);
|
||||
|
||||
|
||||
@@ -42,13 +42,13 @@
|
||||
#include <string>
|
||||
#include <systemc.h>
|
||||
|
||||
#include "Dram.h"
|
||||
#include "RecordableDram.h"
|
||||
#include "Arbiter.h"
|
||||
#include "TraceGenerator.h"
|
||||
#include "ReorderBuffer.h"
|
||||
#include <tlm_utils/multi_passthrough_target_socket.h>
|
||||
#include <tlm_utils/multi_passthrough_initiator_socket.h>
|
||||
#include "../controller/Controller.h"
|
||||
#include "../controller/RecordableController.h"
|
||||
#include "../common/third_party/tinyxml2/tinyxml2.h"
|
||||
#include "../common/tlm2_base_protocol_checker.h"
|
||||
#include "../error/eccbaseclass.h"
|
||||
|
||||
@@ -56,7 +56,6 @@
|
||||
#include "../controller/core/configuration/Configuration.h"
|
||||
#include "../common/protocol.h"
|
||||
#include "../common/Utils.h"
|
||||
#include "../common/TlmRecorder.h"
|
||||
#include "../common/third_party/DRAMPower/src/libdrampower/LibDRAMPower.h"
|
||||
#include "../error/errormodel.h"
|
||||
|
||||
@@ -72,8 +71,6 @@ struct Dram : sc_module {
|
||||
|
||||
// Power Model related
|
||||
bool powerAnalysis = Configuration::getInstance().PowerAnalysis;
|
||||
sc_time powerWindowSize = Configuration::getInstance().memSpec.clk *
|
||||
Configuration::getInstance().WindowSize;
|
||||
libDRAMPower *DRAMPower;
|
||||
|
||||
// Bandwidth realted:
|
||||
@@ -88,7 +85,6 @@ struct Dram : sc_module {
|
||||
// Data Storage:
|
||||
unsigned char *memory;
|
||||
|
||||
TlmRecorder *tlmRecorder;
|
||||
Controller *dramController;
|
||||
|
||||
SC_CTOR(Dram) : tSocket("socket")
|
||||
@@ -97,7 +93,6 @@ struct Dram : sc_module {
|
||||
bytesPerBurst = Configuration::getInstance().adjustNumBytesAfterECC(
|
||||
bytesPerBurst);
|
||||
dramController = NULL;
|
||||
tlmRecorder = NULL;
|
||||
|
||||
std::uint64_t memorySize = Configuration::getInstance().getSimMemSizeInBytes();
|
||||
// allocate and model storage of one DRAM channel using memory map
|
||||
@@ -151,7 +146,13 @@ struct Dram : sc_module {
|
||||
memTimingSpec.RC = Configuration::getInstance().memSpec.tRC / clk;
|
||||
memTimingSpec.RCD = Configuration::getInstance().memSpec.tRCD / clk;
|
||||
memTimingSpec.REFI = Configuration::getInstance().memSpec.tREFI / clk;
|
||||
memTimingSpec.RFC = Configuration::getInstance().memSpec.tRFC / 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;
|
||||
@@ -203,11 +204,6 @@ struct Dram : sc_module {
|
||||
memSpec.memArchSpec = memArchSpec;
|
||||
|
||||
DRAMPower = new libDRAMPower( memSpec, 0 );
|
||||
|
||||
// Create a thread that is triggered every $powerWindowSize
|
||||
// to generate a Power over Time plot in the Trace analyzer:
|
||||
if (Configuration::getInstance().EnableWindowing)
|
||||
SC_THREAD(powerWindow);
|
||||
}
|
||||
|
||||
// Bandwidth Calculation:
|
||||
@@ -238,13 +234,8 @@ struct Dram : sc_module {
|
||||
~Dram()
|
||||
{
|
||||
if (powerAnalysis == true) {
|
||||
// Obtain the residual energy which was not covered by
|
||||
// previous windows
|
||||
DRAMPower->calcEnergy();
|
||||
|
||||
tlmRecorder->recordPower(sc_time_stamp().to_seconds(),
|
||||
DRAMPower->getPower().window_average_power
|
||||
* Configuration::getInstance().NumberOfDevicesOnDIMM);
|
||||
if (!Configuration::getInstance().DatabaseRecording)
|
||||
DRAMPower->calcEnergy();
|
||||
|
||||
// Print the final total energy and the average power for
|
||||
// the simulation:
|
||||
@@ -307,88 +298,18 @@ struct Dram : sc_module {
|
||||
for (auto e : ememory) {
|
||||
delete e;
|
||||
}
|
||||
|
||||
tlmRecorder->closeConnection();
|
||||
}
|
||||
|
||||
// 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).
|
||||
bool is_equal(double a, double b, const double epsilon = 1e-05)
|
||||
{
|
||||
return std::fabs(a - b) < epsilon;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
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
|
||||
tlmRecorder->recordPower(sc_time_stamp().to_seconds(),
|
||||
DRAMPower->getPower().window_average_power *
|
||||
Configuration::getInstance().NumberOfDevicesOnDIMM);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (numberOfTransactionsServed == 0) {
|
||||
firstAccess = sc_time_stamp();
|
||||
} else {
|
||||
lastAccess = sc_time_stamp();
|
||||
}
|
||||
|
||||
|
||||
// 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("[fw] 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);
|
||||
|
||||
// This is only needed for power simulation:
|
||||
unsigned long long cycle = 0;
|
||||
@@ -644,10 +565,6 @@ struct Dram : sc_module {
|
||||
DebugManager::getInstance().printDebugMessage(name(), message);
|
||||
}
|
||||
|
||||
void setTlmRecorder(TlmRecorder *rec)
|
||||
{
|
||||
tlmRecorder = rec;
|
||||
}
|
||||
void setDramController(Controller *contr)
|
||||
{
|
||||
dramController = contr;
|
||||
|
||||
152
DRAMSys/library/src/simulation/RecordableDram.h
Normal file
152
DRAMSys/library/src/simulation/RecordableDram.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef RECORDABLEDRAM_H_
|
||||
#define RECORDABLEDRAM_H_
|
||||
|
||||
#include "Dram.h"
|
||||
#include "../common/TlmRecorder.h"
|
||||
|
||||
struct RecordableDram : public Dram {
|
||||
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();
|
||||
}
|
||||
|
||||
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).
|
||||
bool is_equal(double a, double b, const double epsilon = 1e-05)
|
||||
{
|
||||
return std::fabs(a - b) < epsilon;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* RECORDABLEDRAM_H_ */
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, University of Kaiserslautern
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors:
|
||||
* Janik Schlemminger
|
||||
* Robert Gernhardt
|
||||
* Matthias Jung
|
||||
* Éder F. Zulian
|
||||
* Felipe S. Prado
|
||||
*/
|
||||
|
||||
#include "StlPlayer.h"
|
||||
|
||||
StlPlayer::StlPlayer(sc_module_name,
|
||||
string pathToTrace,
|
||||
sc_time playerClk,
|
||||
TracePlayerListener *listener) :
|
||||
TracePlayer(listener),
|
||||
file(pathToTrace)
|
||||
{
|
||||
if (!file.is_open())
|
||||
SC_REPORT_FATAL(0, (string("Could not open trace ") + pathToTrace).c_str());
|
||||
|
||||
this->playerClk = playerClk;
|
||||
this->burstlength = Configuration::getInstance().memSpec.BurstLength;
|
||||
this->dataLength = Configuration::getInstance().getBytesPerBurst();
|
||||
this->lineCnt = 0;
|
||||
}
|
||||
|
||||
void StlPlayer::nextPayload()
|
||||
{
|
||||
std::string line;
|
||||
while (line.empty() && file) {
|
||||
// Get a new line from the input file.
|
||||
std::getline(file, line);
|
||||
lineCnt++;
|
||||
// If the line starts with '#' (commented lines) the transaction is ignored.
|
||||
if (!line.empty() && line.at(0) == '#')
|
||||
line.clear();
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
// The file is empty. Nothing more to do.
|
||||
this->finish();
|
||||
return;
|
||||
} else {
|
||||
numberOfTransactions++;
|
||||
}
|
||||
|
||||
// Allocate a generic payload for this request.
|
||||
gp *payload = this->allocatePayload();
|
||||
|
||||
// Allocate a data buffer and initialize it with zeroes. It may be
|
||||
// overwritten with data from the trace file depending on the storage
|
||||
// mode.
|
||||
unsigned char *data = new unsigned char[dataLength];
|
||||
std::fill(data, data + dataLength, 0);
|
||||
|
||||
// Trace files MUST provide timestamp, command and address for every
|
||||
// transaction. The data information depends on the storage mode
|
||||
// configuration.
|
||||
string time;
|
||||
string command;
|
||||
string address;
|
||||
string dataStr;
|
||||
|
||||
std::istringstream iss(line);
|
||||
|
||||
// Get the timestamp for the transaction.
|
||||
iss >> time;
|
||||
if (time.empty())
|
||||
SC_REPORT_FATAL("StlPlayer",
|
||||
("Malformed trace file. Timestamp could not be found (line " + to_string(
|
||||
lineCnt) + ").").c_str());
|
||||
sc_time sendingTime = std::stoull(time.c_str()) * playerClk;
|
||||
|
||||
// Get the command.
|
||||
iss >> command;
|
||||
if (command.empty())
|
||||
SC_REPORT_FATAL("StlPlayer",
|
||||
("Malformed trace file. Command could not be found (line " + to_string(
|
||||
lineCnt) + ").").c_str());
|
||||
enum tlm_command cmd;
|
||||
if (command == "read") {
|
||||
cmd = TLM_READ_COMMAND;
|
||||
} else if (command == "write") {
|
||||
cmd = TLM_WRITE_COMMAND;
|
||||
} else {
|
||||
SC_REPORT_FATAL("StlPlayer",
|
||||
(string("Corrupted tracefile, command ") + command +
|
||||
string(" unknown")).c_str());
|
||||
}
|
||||
|
||||
// Get the address.
|
||||
iss >> address;
|
||||
if (address.empty())
|
||||
SC_REPORT_FATAL("StlPlayer",
|
||||
("Malformed trace file. Address could not be found (line " + to_string(
|
||||
lineCnt) + ").").c_str());
|
||||
unsigned long long addr = std::stoull(address.c_str(), 0, 16);
|
||||
|
||||
// Get the data if necessary.
|
||||
if (Configuration::getInstance().StoreMode != StorageMode::NoStorage
|
||||
&& cmd != TLM_READ_COMMAND) {
|
||||
// The input trace file must provide the data to be stored into the memory.
|
||||
iss >> dataStr;
|
||||
if (dataStr.empty())
|
||||
SC_REPORT_FATAL("StlPlayer",
|
||||
("Malformed trace file. Data information could not be found (line " + to_string(
|
||||
lineCnt) + ").").c_str());
|
||||
|
||||
// Check if data length in the trace file is correct. We need two characters to represent 1 byte in hexadecimal.
|
||||
if (dataStr.length() != (dataLength * 2))
|
||||
SC_REPORT_FATAL("StlPlayer",
|
||||
("Data in the trace file has an invalid length (line " + to_string(
|
||||
lineCnt) + ").").c_str());
|
||||
|
||||
// Set data
|
||||
for (unsigned i = 0; i < dataLength; i++)
|
||||
data[i] = (unsigned char)std::stoi(dataStr.substr(i * 2, 2).c_str(), 0, 16);
|
||||
}
|
||||
|
||||
// Fill up the payload.
|
||||
payload->set_address(addr);
|
||||
payload->set_response_status(TLM_INCOMPLETE_RESPONSE);
|
||||
payload->set_dmi_allowed(false);
|
||||
payload->set_byte_enable_length(0);
|
||||
payload->set_streaming_width(burstlength);
|
||||
payload->set_data_length(dataLength);
|
||||
payload->set_data_ptr(data);
|
||||
payload->set_command(cmd);
|
||||
|
||||
// Send the transaction directly or schedule it to be sent in the future.
|
||||
if (sendingTime <= sc_time_stamp())
|
||||
this->payloadEventQueue.notify(*payload, BEGIN_REQ, SC_ZERO_TIME);
|
||||
else
|
||||
this->payloadEventQueue.notify(*payload, BEGIN_REQ,
|
||||
sendingTime - sc_time_stamp());
|
||||
}
|
||||
|
||||
@@ -46,14 +46,141 @@
|
||||
using namespace std;
|
||||
using namespace tlm;
|
||||
|
||||
struct StlPlayer: public TracePlayer {
|
||||
template <bool relative> class StlPlayer: public TracePlayer
|
||||
{
|
||||
public:
|
||||
StlPlayer(sc_module_name /*name*/,
|
||||
string pathToTrace,
|
||||
sc_time playerClk,
|
||||
TracePlayerListener *listener);
|
||||
TracePlayerListener *listener) :
|
||||
TracePlayer(listener),
|
||||
file(pathToTrace)
|
||||
{
|
||||
if (!file.is_open())
|
||||
SC_REPORT_FATAL(0, (string("Could not open trace ") + pathToTrace).c_str());
|
||||
|
||||
void nextPayload();
|
||||
this->playerClk = playerClk;
|
||||
this->burstlength = Configuration::getInstance().memSpec.BurstLength;
|
||||
this->dataLength = Configuration::getInstance().getBytesPerBurst();
|
||||
this->lineCnt = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void nextPayload()
|
||||
{
|
||||
std::string line;
|
||||
while (line.empty() && file) {
|
||||
// Get a new line from the input file.
|
||||
std::getline(file, line);
|
||||
lineCnt++;
|
||||
// If the line starts with '#' (commented lines) the transaction is ignored.
|
||||
if (!line.empty() && line.at(0) == '#')
|
||||
line.clear();
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
// The file is empty. Nothing more to do.
|
||||
this->finish();
|
||||
return;
|
||||
} else {
|
||||
numberOfTransactions++;
|
||||
}
|
||||
|
||||
// Allocate a generic payload for this request.
|
||||
gp *payload = this->allocatePayload();
|
||||
|
||||
// Allocate a data buffer and initialize it with zeroes. It may be
|
||||
// overwritten with data from the trace file depending on the storage
|
||||
// mode.
|
||||
unsigned char *data = new unsigned char[dataLength];
|
||||
std::fill(data, data + dataLength, 0);
|
||||
|
||||
// Trace files MUST provide timestamp, command and address for every
|
||||
// transaction. The data information depends on the storage mode
|
||||
// configuration.
|
||||
string time;
|
||||
string command;
|
||||
string address;
|
||||
string dataStr;
|
||||
|
||||
std::istringstream iss(line);
|
||||
|
||||
// Get the timestamp for the transaction.
|
||||
iss >> time;
|
||||
if (time.empty())
|
||||
SC_REPORT_FATAL("StlPlayer",
|
||||
("Malformed trace file. Timestamp could not be found (line " + to_string(
|
||||
lineCnt) + ").").c_str());
|
||||
sc_time sendingTime = std::stoull(time.c_str()) * playerClk;
|
||||
|
||||
// Get the command.
|
||||
iss >> command;
|
||||
if (command.empty())
|
||||
SC_REPORT_FATAL("StlPlayer",
|
||||
("Malformed trace file. Command could not be found (line " + to_string(
|
||||
lineCnt) + ").").c_str());
|
||||
enum tlm_command cmd;
|
||||
if (command == "read") {
|
||||
cmd = TLM_READ_COMMAND;
|
||||
} else if (command == "write") {
|
||||
cmd = TLM_WRITE_COMMAND;
|
||||
} else {
|
||||
SC_REPORT_FATAL("StlPlayer",
|
||||
(string("Corrupted tracefile, command ") + command +
|
||||
string(" unknown")).c_str());
|
||||
}
|
||||
|
||||
// Get the address.
|
||||
iss >> address;
|
||||
if (address.empty())
|
||||
SC_REPORT_FATAL("StlPlayer",
|
||||
("Malformed trace file. Address could not be found (line " + to_string(
|
||||
lineCnt) + ").").c_str());
|
||||
unsigned long long addr = std::stoull(address.c_str(), 0, 16);
|
||||
|
||||
// Get the data if necessary.
|
||||
if (Configuration::getInstance().StoreMode != StorageMode::NoStorage
|
||||
&& cmd != TLM_READ_COMMAND) {
|
||||
// The input trace file must provide the data to be stored into the memory.
|
||||
iss >> dataStr;
|
||||
if (dataStr.empty())
|
||||
SC_REPORT_FATAL("StlPlayer",
|
||||
("Malformed trace file. Data information could not be found (line " + to_string(
|
||||
lineCnt) + ").").c_str());
|
||||
|
||||
// Check if data length in the trace file is correct. We need two characters to represent 1 byte in hexadecimal.
|
||||
if (dataStr.length() != (dataLength * 2))
|
||||
SC_REPORT_FATAL("StlPlayer",
|
||||
("Data in the trace file has an invalid length (line " + to_string(
|
||||
lineCnt) + ").").c_str());
|
||||
|
||||
// Set data
|
||||
for (unsigned i = 0; i < dataLength; i++)
|
||||
data[i] = (unsigned char)std::stoi(dataStr.substr(i * 2, 2).c_str(), 0, 16);
|
||||
}
|
||||
|
||||
// Fill up the payload.
|
||||
payload->set_address(addr);
|
||||
payload->set_response_status(TLM_INCOMPLETE_RESPONSE);
|
||||
payload->set_dmi_allowed(false);
|
||||
payload->set_byte_enable_length(0);
|
||||
payload->set_streaming_width(burstlength);
|
||||
payload->set_data_length(dataLength);
|
||||
payload->set_data_ptr(data);
|
||||
payload->set_command(cmd);
|
||||
|
||||
if (relative == false) {
|
||||
// Send the transaction directly or schedule it to be sent in the future.
|
||||
if (sendingTime <= sc_time_stamp())
|
||||
this->payloadEventQueue.notify(*payload, BEGIN_REQ, SC_ZERO_TIME);
|
||||
else
|
||||
this->payloadEventQueue.notify(*payload, BEGIN_REQ,
|
||||
sendingTime - sc_time_stamp());
|
||||
} else {
|
||||
payloadEventQueue.notify(*payload, BEGIN_REQ, sendingTime);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ifstream file;
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
traceSetup::traceSetup(std::string uri,
|
||||
std::string pathToResources,
|
||||
std::vector<StlPlayer *> *devices)
|
||||
std::vector<TracePlayer *> *devices)
|
||||
{
|
||||
// Load Simulation:
|
||||
tinyxml2::XMLDocument simulationdoc;
|
||||
@@ -69,17 +69,31 @@ traceSetup::traceSetup(std::string uri,
|
||||
}
|
||||
|
||||
std::string name = device->GetText();
|
||||
|
||||
int pos = name.rfind('.');
|
||||
if (pos == std::string::npos) {
|
||||
throw std::runtime_error("Name of the trace file does not contain a valid extension.");
|
||||
}
|
||||
|
||||
// Get the extension and make it lower case
|
||||
std::string ext = name.substr(pos + 1);
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
|
||||
|
||||
std::string stlFile = pathToResources + string("traces/") + name;
|
||||
std::string moduleName = name;
|
||||
|
||||
// replace all '.' to '_'
|
||||
std::replace( moduleName.begin(), moduleName.end(), '.', '_');
|
||||
|
||||
StlPlayer *player = new StlPlayer(moduleName.c_str(),
|
||||
stlFile,
|
||||
playerClk,
|
||||
this);
|
||||
|
||||
TracePlayer *player;
|
||||
if (strcmp(ext.c_str(), "stl") == 0) {
|
||||
player = new StlPlayer<false>(moduleName.c_str(), stlFile, playerClk, this);
|
||||
} else if (strcmp(ext.c_str(), "rstl") == 0) {
|
||||
player = new StlPlayer<true>(moduleName.c_str(), stlFile, playerClk, this);
|
||||
} else {
|
||||
std::string error = "Unsupported file extension in " + name;
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
devices->push_back(player);
|
||||
|
||||
if (Configuration::getInstance().SimulationProgressBar) {
|
||||
|
||||
@@ -49,7 +49,7 @@ class traceSetup : public TracePlayerListener
|
||||
public:
|
||||
traceSetup(std::string uri,
|
||||
std::string pathToResources,
|
||||
std::vector<StlPlayer *> *devices);
|
||||
std::vector<TracePlayer *> *devices);
|
||||
|
||||
virtual void tracePlayerTerminates() override;
|
||||
virtual void transactionFinished() override;
|
||||
|
||||
@@ -72,7 +72,7 @@ int sc_main(int argc, char **argv)
|
||||
SimulationXML = resources + "simulations/ddr3-example.xml";
|
||||
}
|
||||
|
||||
std::vector<StlPlayer *> players;
|
||||
std::vector<TracePlayer *> players;
|
||||
|
||||
// Instantiate DRAMSys:
|
||||
DRAMSys *dramSys = new DRAMSys("DRAMSys", SimulationXML, resources);
|
||||
|
||||
@@ -200,8 +200,7 @@ shared_ptr<Transaction> TraceDB::getNextRefresh(ID currentTransactionId)
|
||||
{
|
||||
QSqlQuery query(database);
|
||||
QString queryText = queryTexts.queryHead +
|
||||
"WHERE TransactionID > :currentID AND PhaseName = 'AUTO_REFRESH' LIMIT 1";
|
||||
|
||||
"WHERE TransactionID > :currentID AND PhaseName IN ('REFA') LIMIT 1";
|
||||
query.prepare(queryText);
|
||||
query.bindValue(":currentID", currentTransactionId);
|
||||
executeQuery(query);
|
||||
|
||||
@@ -131,7 +131,7 @@ def memory_utilisation_percent_old(connection):
|
||||
|
||||
def refreshMissDecision(connection, calculatedMetrics):
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("""SELECT phases.ID,PhaseBegin,PhaseEnd,TBank FROM Phases INNER JOIN transactions on transactions.id = phases.transact WHERE PhaseName='AUTO_REFRESH' """)
|
||||
cursor.execute("""SELECT phases.ID,PhaseBegin,PhaseEnd,TBank FROM Phases INNER JOIN transactions on transactions.id = phases.transact WHERE PhaseName IN ('REFA')' """)
|
||||
queryMinREQ = """SELECT id,min(PhaseBegin) FROM (SELECT transactions.id, PhaseBegin FROM transactions
|
||||
inner join ranges on ranges.id = transactions.range inner join phases on phases.transact = transactions.id
|
||||
where tthread != 0 and tbank = :bank and PhaseName = "REQ" and ranges.begin<:begin and ranges.end>:end)"""
|
||||
|
||||
@@ -193,38 +193,57 @@ def memory_utilisation_window(connection, tracePath, steps):
|
||||
@plot
|
||||
def power_window(connection, tracePath, steps):
|
||||
|
||||
windowSize = getWindowSize(connection)
|
||||
|
||||
outputFile = ""
|
||||
cursor = connection.cursor()
|
||||
|
||||
cursor.execute(" SELECT * FROM Power")
|
||||
result = cursor.fetchone()
|
||||
if(result is not None):
|
||||
time = [0] * (steps+1)
|
||||
power = [0] * (steps+1)
|
||||
time[0] = 0
|
||||
power[0] = 0
|
||||
#pow(10,9): seconds to nanoseconds conversion
|
||||
time[1] = float(result[0])*pow(10,9)
|
||||
power[1] = float(result[1])
|
||||
for i in range((steps-1)):
|
||||
|
||||
power = [0] * (steps+1)
|
||||
window = float(windowSize) / pow(10,12)
|
||||
|
||||
for i in range(steps):
|
||||
sum = 0.0
|
||||
counter = 0
|
||||
result = cursor.fetchone()
|
||||
|
||||
while (result is not None):
|
||||
sum += float(result[1])
|
||||
counter = counter + 1
|
||||
if(result[0] > window*i):
|
||||
break
|
||||
result = cursor.fetchone()
|
||||
time[i+2] = float(result[0])*pow(10,9)
|
||||
power[i+2] = float(result[1])
|
||||
|
||||
outputFileName, basename = createOutputFilename(tracePath, 'power', '', 'pdf')
|
||||
outputFile = "{0}\n\t".format(outputFileName)
|
||||
if(counter == 0):
|
||||
break
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.backends.backend_pdf import PdfPages
|
||||
sum = sum / counter
|
||||
power[i] = sum
|
||||
|
||||
import numpy as np
|
||||
time = np.arange(0, windowSize*(steps+1)/1000/1000, windowSize/1000/1000)
|
||||
|
||||
outputFileName, basename = createOutputFilename(tracePath, 'power', '', 'pdf')
|
||||
outputFile = "{0}\n\t".format(outputFileName)
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.backends.backend_pdf import PdfPages
|
||||
|
||||
PowFigure = plt.figure(figsize=(10,5), dpi=300)
|
||||
PowFigurePlot = PowFigure.add_subplot(111)
|
||||
PowFigurePlot.set_xlabel('Time [us]')
|
||||
PowFigurePlot.set_ylabel('Power [mW]')
|
||||
PowFigurePlot.set_title('Power Consumption ' + str(basename))
|
||||
PowFigurePlot.grid(True)
|
||||
PowFigurePlot.plot(time, power, linewidth=0.5)
|
||||
|
||||
pdf = PdfPages(outputFileName)
|
||||
pdf.savefig(PowFigure)
|
||||
pdf.close()
|
||||
PowFigurePlot.clear()
|
||||
plt.close()
|
||||
|
||||
plt.plot(time, power)
|
||||
plt.xlabel('Time [ns]')
|
||||
plt.ylabel('Power [mW]')
|
||||
plt.grid(True)
|
||||
plt.title('Power Consumption ' + str(basename))
|
||||
pdf = PdfPages(outputFileName)
|
||||
pdf.savefig()
|
||||
pdf.close()
|
||||
plt.close()
|
||||
return outputFile
|
||||
|
||||
@plot
|
||||
|
||||
@@ -10,6 +10,7 @@ class DramConfig(object):
|
||||
memoryType = ""
|
||||
scheduler = ""
|
||||
bankwiseLogic = 0
|
||||
refMode = 1
|
||||
clk = 0
|
||||
unitOfTime = ""
|
||||
dataRate = 0
|
||||
@@ -38,7 +39,9 @@ class DramConfig(object):
|
||||
tXSR = 0 # min delay to row access command after srefx
|
||||
tXSRDLL = 0 # min delay to row access command after srefx for dll commands
|
||||
tAL = 0 # additive delay (delayed execution in dram)
|
||||
tRFC = 0 # min ref->act delay
|
||||
tRFC = 0 # min ref->act delay 1X
|
||||
tRFC2 = 0 # min ref->act delay 2X
|
||||
tRFC4 = 0 # min ref->act delay 4X
|
||||
tREFI = 0 # time between REF commands
|
||||
|
||||
def readConfigFromFiles(self, connection):
|
||||
@@ -52,6 +55,7 @@ class DramConfig(object):
|
||||
self.unitOfTime = clkWithUnit[1].lower()
|
||||
|
||||
self.bankwiseLogic = mcconfig.getValue("BankwiseLogic")
|
||||
self.refMode = mcconfig.getValue("ControllerCoreRefMode")
|
||||
self.scheduler = mcconfig.getValue("Scheduler")
|
||||
|
||||
self.numberOfBanks = memspec.getIntValue("nbrOfBanks")
|
||||
@@ -111,6 +115,8 @@ class DramConfig(object):
|
||||
self.tXSRDLL = self.clk * memspec.getIntValue("XSDLL")
|
||||
self.tAL = self.clk * memspec.getIntValue("AL")
|
||||
self.tRFC = self.clk * memspec.getIntValue("RFC")
|
||||
self.tRFC2 = self.clk * memspec.getIntValue("RFC2")
|
||||
self.tRFC4 = self.clk * memspec.getIntValue("RFC4")
|
||||
self.tREFI = self.clk * memspec.getIntValue("REFI")
|
||||
|
||||
elif (self. memoryType == "DDR3"):
|
||||
@@ -353,7 +359,12 @@ def timing_constraint(FirstPhase, SecondPhase):
|
||||
return dramconfig.tWL + dramconfig.getWriteAccessTime() + dramconfig.tWR + dramconfig.clk
|
||||
|
||||
elif (FirstPhaseName == "REFA"):
|
||||
return dramconfig.tRFC
|
||||
if dramconfig.refMode == "4":
|
||||
return dramconfig.tRFC4
|
||||
elif dramconfig.refMode == "2":
|
||||
return dramconfig.tRFC2
|
||||
else:
|
||||
return dramconfig.tRFC
|
||||
|
||||
elif (FirstPhaseName in ["PDNA", "PDNP"]):
|
||||
# print("{0}".format(FirstPhaseName))
|
||||
|
||||
212
README.md
212
README.md
@@ -381,11 +381,22 @@ configuration structure.
|
||||
The **device** configuration consists of two parameters - clkMhz
|
||||
(operation frequency for this device) - and a **trace file**.
|
||||
|
||||
#### Trace files
|
||||
|
||||
A **trace file** is a pre-recorded file containing memory transactions. Each
|
||||
memory transaction has a timestamp that tells the simulator when it shall
|
||||
happen, a transaction type (read or write) and a memory address given in
|
||||
hexadecimal.
|
||||
|
||||
There are two different kinds of trace files. They differ in their timing behaviour and are distingushed by their file extension.
|
||||
|
||||
##### STL Trace (.stl)
|
||||
|
||||
The timestamp corresponds to the time the request is to be issued and it is
|
||||
given in cycles of the bus master device. Example: the device is a FPGA with
|
||||
frequency 200 MHz (clock period of 5 ns). If the timestamp is 10 it means that
|
||||
the request is to be issued when time is 50 ns.
|
||||
|
||||
Here is an example syntax:
|
||||
|
||||
```
|
||||
@@ -397,10 +408,22 @@ Here is an example syntax:
|
||||
81: read 0x400180
|
||||
```
|
||||
|
||||
The timestamp corresponds to the time the request is to be issued and it is
|
||||
given in cycles of the bus master device. Example: the device is a FPGA with
|
||||
frequency 200 MHz (clock period of 5 ns). If the timestamp is 10 it means that
|
||||
the request is to be issued when time is 50 ns.
|
||||
##### Relative STL Traces (.rstl)
|
||||
|
||||
The timestamp corresponds to the time the request is to be issued relative to the end of the transaction before or the beginning of the trace. This results in a simulation in which the **trace player** is able to react to possible delays due to DRAM bottlenecks.
|
||||
|
||||
Here is an example syntax:
|
||||
|
||||
```
|
||||
# Comment lines begin with #
|
||||
# [clock-cyle]: [write|read] [hex-address]
|
||||
31: read 0x400140
|
||||
2: read 0x400160
|
||||
23: write 0x7fff8000
|
||||
25: read 0x400180
|
||||
```
|
||||
|
||||
#### Trace player
|
||||
|
||||
A **trace player** is **equivalent** to a bus master **device**
|
||||
(processor, FPGA, etc.). It reads an input trace file and translates each line into
|
||||
@@ -616,7 +639,7 @@ Below, the sub-configurations are listed and explained.
|
||||
- Key "Name": Name of the trace file which was used by ConGen
|
||||
- All items of the array "Solutions" but the first one: Alternative solution with same result.
|
||||
- Key "costs": Number of row misses which this configuration produces while playing the trace.
|
||||
|
||||
|
||||
Used data:
|
||||
- First item of array "Solution":
|
||||
- "XOR": Array of row and bank bits which are connected with an xor. Order of the bit: bank1, bank2, ..., row1, row2, ...
|
||||
@@ -674,56 +697,58 @@ Below, the sub-configurations are listed and explained.
|
||||
|
||||
- **Memory Controller Configuration**
|
||||
|
||||
An example follows.
|
||||
An example follows.
|
||||
|
||||
``` xml
|
||||
<mcconfig>
|
||||
<OpenPagePolicy value="1" />
|
||||
<MaxNrOfTransactions value="8" />
|
||||
<Scheduler value="FIFO" />
|
||||
<Capsize value="5" />
|
||||
<!-- 4 Modes: NoPowerDown, Staggered, TimeoutPDN, TimeoutSREF -->
|
||||
<PowerDownMode value="NoPowerDown" />
|
||||
<PowerDownTimeout value="100" />
|
||||
<!-- Bankwise -->
|
||||
<BankwiseLogic value="0"/>
|
||||
<!-- Refresh yes, no -->
|
||||
<ControllerCoreDisableRefresh value="0"/>
|
||||
<!-- RGR -->
|
||||
<ControllerCoreRowGranularRef value="1"/>
|
||||
<ControllerCoreRowGranularRefNumAR value="8192"/>
|
||||
<ControllerCoreRowGranularRefRowInc value="1"/>
|
||||
<!-- Banks to be refreshed in RGR mode. 1: yes, 0: no (max. 16 banks) -->
|
||||
<ControllerCoreRowGranularRefB0 value="1"/>
|
||||
<ControllerCoreRowGranularRefB1 value="1"/>
|
||||
<ControllerCoreRowGranularRefB2 value="1"/>
|
||||
<ControllerCoreRowGranularRefB3 value="1"/>
|
||||
<ControllerCoreRowGranularRefB4 value="1"/>
|
||||
<ControllerCoreRowGranularRefB5 value="1"/>
|
||||
<ControllerCoreRowGranularRefB6 value="1"/>
|
||||
<ControllerCoreRowGranularRefB7 value="1"/>
|
||||
<ControllerCoreRowGranularRefB8 value="0"/>
|
||||
<ControllerCoreRowGranularRefB9 value="0"/>
|
||||
<ControllerCoreRowGranularRefB10 value="0"/>
|
||||
<ControllerCoreRowGranularRefB11 value="0"/>
|
||||
<ControllerCoreRowGranularRefB12 value="0"/>
|
||||
<ControllerCoreRowGranularRefB13 value="0"/>
|
||||
<ControllerCoreRowGranularRefB14 value="0"/>
|
||||
<ControllerCoreRowGranularRefB15 value="0"/>
|
||||
<!-- Timings for RGR normal or optimal values -->
|
||||
<ControllerCoreRowGranularRefRASBInClkCycles value="22"/>
|
||||
<ControllerCoreRowGranularRefRRDB_LInClkCycles value="2"/>
|
||||
<ControllerCoreRowGranularRefRRDB_SInClkCycles value="2"/>
|
||||
<ControllerCoreRowGranularRefRPBInClkCycles value="15"/>
|
||||
<ControllerCoreRowGranularRefRCBInClkCycles value="37"/>
|
||||
<ControllerCoreRowGranularRefFAWBInClkCycles value="0"/>
|
||||
<!-- Postpone, pull-in -->
|
||||
<ControllerCoreEnableRefPostpone value="0"/>
|
||||
<ControllerCoreEnableRefPullIn value="1"/>
|
||||
<ControllerCoreMaxPostponedARCmd value="8"/>
|
||||
<ControllerCoreMaxPulledInARCmd value="8"/>
|
||||
<ControllerCoreForceMaxRefBurst value="0"/>
|
||||
</mcconfig>
|
||||
<mcconfig>
|
||||
<OpenPagePolicy value="1" />
|
||||
<MaxNrOfTransactions value="8" />
|
||||
<Scheduler value="FIFO" />
|
||||
<Capsize value="5" />
|
||||
<!-- 4 Modes: NoPowerDown, Staggered, TimeoutPDN, TimeoutSREF -->
|
||||
<PowerDownMode value="NoPowerDown" />
|
||||
<PowerDownTimeout value="100" />
|
||||
<!-- Bankwise -->
|
||||
<BankwiseLogic value="0"/>
|
||||
<!-- Disable refresh. 0: no (refresh enabled), 1: yes (refresh disableb) -->
|
||||
<ControllerCoreDisableRefresh value="0"/>
|
||||
<!-- Refresh Mode. 1: 1X, 2: 2X, 4: 4X (e.g., DDR4) -->
|
||||
<ControllerCoreRefMode value="1"/>
|
||||
<!-- RGR -->
|
||||
<ControllerCoreRowGranularRef value="0"/>
|
||||
<ControllerCoreRowGranularRefNumAR value="8192"/>
|
||||
<ControllerCoreRowGranularRefRowInc value="1"/>
|
||||
<!-- Banks to be refreshed in RGR mode. 1: yes, 0: no (max. 16 banks) -->
|
||||
<ControllerCoreRowGranularRefB0 value="1"/>
|
||||
<ControllerCoreRowGranularRefB1 value="1"/>
|
||||
<ControllerCoreRowGranularRefB2 value="1"/>
|
||||
<ControllerCoreRowGranularRefB3 value="1"/>
|
||||
<ControllerCoreRowGranularRefB4 value="1"/>
|
||||
<ControllerCoreRowGranularRefB5 value="1"/>
|
||||
<ControllerCoreRowGranularRefB6 value="1"/>
|
||||
<ControllerCoreRowGranularRefB7 value="1"/>
|
||||
<ControllerCoreRowGranularRefB8 value="0"/>
|
||||
<ControllerCoreRowGranularRefB9 value="0"/>
|
||||
<ControllerCoreRowGranularRefB10 value="0"/>
|
||||
<ControllerCoreRowGranularRefB11 value="0"/>
|
||||
<ControllerCoreRowGranularRefB12 value="0"/>
|
||||
<ControllerCoreRowGranularRefB13 value="0"/>
|
||||
<ControllerCoreRowGranularRefB14 value="0"/>
|
||||
<ControllerCoreRowGranularRefB15 value="0"/>
|
||||
<!-- Timings for RGR normal or optimal values -->
|
||||
<ControllerCoreRowGranularRefRASBInClkCycles value="22"/>
|
||||
<ControllerCoreRowGranularRefRRDB_LInClkCycles value="2"/>
|
||||
<ControllerCoreRowGranularRefRRDB_SInClkCycles value="2"/>
|
||||
<ControllerCoreRowGranularRefRPBInClkCycles value="15"/>
|
||||
<ControllerCoreRowGranularRefRCBInClkCycles value="37"/>
|
||||
<ControllerCoreRowGranularRefFAWBInClkCycles value="0"/>
|
||||
<!-- Postpone, pull-in -->
|
||||
<ControllerCoreEnableRefPostpone value="0"/>
|
||||
<ControllerCoreEnableRefPullIn value="0"/>
|
||||
<ControllerCoreMaxPostponedARCmd value="8"/>
|
||||
<ControllerCoreMaxPulledInARCmd value="8"/>
|
||||
<ControllerCoreForceMaxRefBurst value="0"/>
|
||||
</mcconfig>
|
||||
```
|
||||
|
||||
- *BankwiseLogic* (boolean)
|
||||
@@ -762,6 +787,12 @@ Below, the sub-configurations are listed and explained.
|
||||
- *ControllerCoreDisableRefresh* (boolean)
|
||||
- "1": disables refreshes
|
||||
- "0": normal operation (refreshes enabled)
|
||||
- ControllerCoreRefMode (unsigned int)
|
||||
- Refresh mode. 1: 1X, 2: 2X, 4: 4X. Refresh period is tREFI, tREFI/2, tREFI/4, respectively. Number of rows per refresh affected accordingly.
|
||||
The default refresh mode is fixed 1X mode where Refresh commands should be issued with the normal rate, i.e., tREFI. The duration of each refresh command is the normal refresh cycle time tRFC.
|
||||
In 2X mode Refresh commands are issued to the DRAM at the double frequency (tREFI/2).
|
||||
In 4X mode Refresh commands are issued to the DRAM at the quadruple frequency (tREFI/4).
|
||||
There is a tRFC value for each mode that comes from the memory specification.
|
||||
- *ControllerCoreForceMaxRefBurst* (boolean)
|
||||
- "1": always postpone, resulting in a ControllerCoreMaxPostponedARCmd burst
|
||||
- "0": normal operation
|
||||
@@ -772,77 +803,78 @@ Below, the sub-configurations are listed and explained.
|
||||
- "1": enables the pull-in refresh feature
|
||||
- "0": normal operation
|
||||
- *ControllerCoreMaxPostponedARCmd* (unsigned int)
|
||||
- Max AR commands to be postponed.
|
||||
- Max AR commands to be postponed. Refresh mode affects this config (multiplier).
|
||||
- *ControllerCoreMaxPulledInARCmd* (unsigned int)
|
||||
- Max AR commands to be pulled-in.
|
||||
- *ControllerCoreRowGranularRef* (boolean)
|
||||
- Max AR commands to be pulled-in. Refresh mode affects this config (multiplier).
|
||||
- *ControllerCoreRowGranularRef* (boolean)
|
||||
- "1": enables row granular refresh feature (RGR)
|
||||
- "0": normal operation
|
||||
- *ControllerCoreRowGranularRefNumAR* (unsigned int)
|
||||
- *ControllerCoreRowGranularRefNumAR* (unsigned int)
|
||||
- Number of AR commands to to be issued in a refresh period tREFI
|
||||
- *ControllerCoreRowGranularRefRowInc* (unsigned int)
|
||||
- *ControllerCoreRowGranularRefRowInc* (unsigned int)
|
||||
- Row increment for each AR command (selective refresh)
|
||||
- *ControllerCoreRowGranularRefB0* (boolean)
|
||||
- *ControllerCoreRowGranularRefB0* (boolean)
|
||||
- "1": RGR this bank
|
||||
- "0": skip this bank
|
||||
- *ControllerCoreRowGranularRefB1* (boolean)
|
||||
- *ControllerCoreRowGranularRefB1* (boolean)
|
||||
- "1": RGR this bank
|
||||
- "0": skip this bank
|
||||
- *ControllerCoreRowGranularRefB2* (boolean)
|
||||
- *ControllerCoreRowGranularRefB2* (boolean)
|
||||
- "1": RGR this bank
|
||||
- "0": skip this bank
|
||||
- *ControllerCoreRowGranularRefB3* (boolean)
|
||||
- *ControllerCoreRowGranularRefB3* (boolean)
|
||||
- "1": RGR this bank
|
||||
- "0": skip this bank
|
||||
- *ControllerCoreRowGranularRefB4* (boolean)
|
||||
- *ControllerCoreRowGranularRefB4* (boolean)
|
||||
- "1": RGR this bank
|
||||
- "0": skip this bank
|
||||
- *ControllerCoreRowGranularRefB5* (boolean)
|
||||
- *ControllerCoreRowGranularRefB5* (boolean)
|
||||
- "1": RGR this bank
|
||||
- "0": skip this bank
|
||||
- *ControllerCoreRowGranularRefB6* (boolean)
|
||||
- *ControllerCoreRowGranularRefB6* (boolean)
|
||||
- "1": RGR this bank
|
||||
- "0": skip this bank
|
||||
- *ControllerCoreRowGranularRefB7* (boolean)
|
||||
- *ControllerCoreRowGranularRefB7* (boolean)
|
||||
- "1": RGR this bank
|
||||
- "0": skip this bank
|
||||
- *ControllerCoreRowGranularRefB8* (boolean)
|
||||
- *ControllerCoreRowGranularRefB8* (boolean)
|
||||
- "1": RGR this bank
|
||||
- "0": skip this bank
|
||||
- *ControllerCoreRowGranularRefB9* (boolean)
|
||||
- *ControllerCoreRowGranularRefB9* (boolean)
|
||||
- "1": RGR this bank
|
||||
- "0": skip this bank
|
||||
- *ControllerCoreRowGranularRefB10* (boolean)
|
||||
- *ControllerCoreRowGranularRefB10* (boolean)
|
||||
- "1": RGR this bank
|
||||
- "0": skip this bank
|
||||
- *ControllerCoreRowGranularRefB11* (boolean)
|
||||
- *ControllerCoreRowGranularRefB11* (boolean)
|
||||
- "1": RGR this bank
|
||||
- "0": skip this bank
|
||||
- *ControllerCoreRowGranularRefB12* (boolean)
|
||||
- *ControllerCoreRowGranularRefB12* (boolean)
|
||||
- "1": RGR this bank
|
||||
- "0": skip this bank
|
||||
- *ControllerCoreRowGranularRefB13* (boolean)
|
||||
- *ControllerCoreRowGranularRefB13* (boolean)
|
||||
- "1": RGR this bank
|
||||
- "0": skip this bank
|
||||
- *ControllerCoreRowGranularRefB14* (boolean)
|
||||
- *ControllerCoreRowGranularRefB14* (boolean)
|
||||
- "1": RGR this bank
|
||||
- "0": skip this bank
|
||||
- *ControllerCoreRowGranularRefB15* (boolean)
|
||||
- *ControllerCoreRowGranularRefB15* (boolean)
|
||||
- "1": RGR this bank
|
||||
- "0": skip this bank
|
||||
- *ControllerCoreRowGranularRefRASBInClkCycles* (unsigned int)
|
||||
- *ControllerCoreRowGranularRefRASBInClkCycles* (unsigned int)
|
||||
- Timing can be changed to explore optimum row granular refresh (ORGR)
|
||||
- *ControllerCoreRowGranularRefRRDB_LInClkCycles* (unsigned int)
|
||||
- *ControllerCoreRowGranularRefRRDB_LInClkCycles* (unsigned int)
|
||||
- Timing can be changed to explore optimum row granular refresh (ORGR)
|
||||
- *ControllerCoreRowGranularRefRRDB_SInClkCycles* (unsigned int)
|
||||
- *ControllerCoreRowGranularRefRRDB_SInClkCycles* (unsigned int)
|
||||
- Timing can be changed to explore optimum row granular refresh (ORGR)
|
||||
- *ControllerCoreRowGranularRefRPBInClkCycles* (unsigned int)
|
||||
- *ControllerCoreRowGranularRefRPBInClkCycles* (unsigned int)
|
||||
- Timing can be changed to explore optimum row granular refresh (ORGR)
|
||||
- *ControllerCoreRowGranularRefRCBInClkCycles* (unsigned int)
|
||||
- *ControllerCoreRowGranularRefRCBInClkCycles* (unsigned int)
|
||||
- Timing can be changed to explore optimum row granular refresh (ORGR)
|
||||
- *ControllerCoreRowGranularRefFAWBInClkCycles* (unsigned int)
|
||||
- *ControllerCoreRowGranularRefFAWBInClkCycles* (unsigned int)
|
||||
- Timing can be changed to explore optimum row granular refresh (ORGR)
|
||||
|
||||
|
||||
- **Flexible Refresh**
|
||||
|
||||
The feature can be used together with regular refresh and also with row
|
||||
@@ -855,18 +887,21 @@ the memory is in an idle state. Therefore, in order to prepare for possible
|
||||
accesses that might happen in the future, a burst of REF commands is
|
||||
initiated. If, at any point, requests start coming in, the burst is
|
||||
interrupted, meaning that the maximum amount of time, considering the worst
|
||||
case scenario (a request arrives at the same time a REF was issued), is tRFC.
|
||||
The advantage of pulling-in refreshes is that they will not issued in the
|
||||
near future (in their actual times), allowing for more efficient accesses to
|
||||
the memory.
|
||||
case scenario (a request arrives at the same time a REF was issued), is a
|
||||
refresh cycle time (tRFC). The advantage of pulling-in refreshes is that they
|
||||
will not be issued in the near future (in their actual times), allowing for more
|
||||
efficient accesses to the memory.
|
||||
|
||||
**Postpone Refresh**
|
||||
|
||||
Similarly, the decision to postpone a refresh is done if there are pending
|
||||
requests on the buffer. Given that having requests might mean a hit, we want
|
||||
to postpone the refresh to minimize the PREA commands needed. If the memory
|
||||
enters an idle state, a burst is issued for the same number of REF commands
|
||||
that were postponed.
|
||||
requests on the buffer. Buffered requests may generate row-hits, so postponing
|
||||
refreshes may be beneficial for it avoids breaking row-hit sequences what
|
||||
reduces the number of commands (e.g., ACT, PRE) to carry out the memory
|
||||
accesses. If the memory enters an idle state, a burst is issued for the same
|
||||
number of REF commands that were postponed. When the maximum allowed
|
||||
number of postponed refreshes is reached a burst is issued in the next
|
||||
refresh interval despite the memory state (busy or idle).
|
||||
|
||||
**The Flexible Refresh FSM**
|
||||
|
||||
@@ -902,6 +937,7 @@ A description of the content each directory follows.
|
||||
- **simulations**: main configuration files.
|
||||
- **traces**: pre-recorded trace files that may be used as stimuli in simulations.
|
||||
|
||||
|
||||
#### Log Collector Script
|
||||
|
||||
Users can profit of running multiple simulations automatically with
|
||||
|
||||
Reference in New Issue
Block a user