Merge branch 'master' of git.rhrk.uni-kl.de:EIT-Wehn/dram.vp.system

This commit is contained in:
Matthias Jung
2018-07-08 14:06:32 +02:00
57 changed files with 1039 additions and 818 deletions

View File

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

View File

@@ -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"/>

View File

@@ -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>

View File

@@ -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

View File

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

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);

View File

@@ -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:

View File

@@ -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());
}

View File

@@ -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;

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

View 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

View File

@@ -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()

View File

@@ -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();

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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;

View File

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

View File

@@ -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:

View File

@@ -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)

View File

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

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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,

View File

@@ -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;

View File

@@ -45,7 +45,6 @@ bool ScheduledCommand::isNoCommand() const
&& executionTime == SC_ZERO_TIME && end == SC_ZERO_TIME);
}
bool ScheduledCommand::isValidCommand() const
{
return !isNoCommand();

View File

@@ -62,7 +62,6 @@ public:
{
}
ScheduledCommand() :
command(Command::NOP), start(SC_ZERO_TIME), executionTime(SC_ZERO_TIME),
end(SC_ZERO_TIME), extension()

View File

@@ -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);

View File

@@ -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(),

View File

@@ -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) {

View File

@@ -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(),

View File

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

View File

@@ -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;

View File

@@ -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));

View File

@@ -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;

View File

@@ -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 (?).

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

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

View File

@@ -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);

View File

@@ -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"

View File

@@ -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;

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

View File

@@ -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());
}

View File

@@ -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;

View 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) {

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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)"""

View File

@@ -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

View File

@@ -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
View File

@@ -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