Merge branch 'feat/length_conversion' into 'develop'

Length conversion, variable transaction length in stl files.

See merge request ems/astdm/modeling.dram/dram.sys!342
This commit is contained in:
Lukas Steiner
2022-02-16 10:05:42 +00:00
49 changed files with 812 additions and 419 deletions

View File

@@ -34,6 +34,7 @@
* Robert Gernhardt
* Matthias Jung
* Eder F. Zulian
* Lukas Steiner
*/
#include <fstream>
@@ -69,7 +70,7 @@ TlmRecorder::TlmRecorder(const std::string &name, const std::string &dbName) :
PRINTDEBUGMESSAGE(name, "Starting new database transaction");
}
TlmRecorder::~TlmRecorder()
void TlmRecorder::finalize()
{
if (db)
closeConnection();

View File

@@ -34,6 +34,7 @@
* Robert Gernhardt
* Matthias Jung
* Eder F. Zulian
* Lukas Steiner
*/
#ifndef TLMRECORDER_H
@@ -54,7 +55,8 @@ class TlmRecorder
{
public:
TlmRecorder(const std::string &name, const std::string &dbName);
~TlmRecorder();
TlmRecorder(const TlmRecorder&) = delete;
TlmRecorder(TlmRecorder&&) = default;
void recordMcConfig(std::string _mcconfig)
{
@@ -78,7 +80,7 @@ public:
void recordDebugMessage(const std::string &message, const sc_core::sc_time &time);
void updateDataStrobe(const sc_core::sc_time &begin, const sc_core::sc_time &end,
tlm::tlm_generic_payload &trans);
void closeConnection();
void finalize();
private:
struct Transaction
@@ -113,6 +115,7 @@ private:
static void executeSqlStatement(sqlite3_stmt *statement);
void openDB(const std::string &dbName);
void closeConnection();
void introduceTransactionSystem(tlm::tlm_generic_payload &trans);
void removeTransactionFromSystem(tlm::tlm_generic_payload &trans);

View File

@@ -163,7 +163,6 @@ public:
BankGroup bankGroup, Bank bank, Row row,
Column column, unsigned int burstLength,
uint64_t threadPayloadID, uint64_t channelPayloadID);
tlm::tlm_extension_base *clone() const override;
void copy_from(const tlm::tlm_extension_base &ext) override;

View File

@@ -163,7 +163,7 @@ void setUpDummy(tlm_generic_payload &payload, uint64_t channelPayloadID, Rank ra
payload.set_dmi_allowed(false);
payload.set_byte_enable_length(0);
payload.set_streaming_width(0);
payload.set_extension(new DramExtension(Thread(UINT_MAX), Channel(0), rank, bankGroup,
bank, Row(0), Column(0), 0, 0, channelPayloadID));
payload.set_extension(new DramExtension(Thread(UINT_MAX), Channel(0), rank, bankGroup, bank, Row(0), Column(0),
0, 0, channelPayloadID));
payload.set_extension(new GenerationExtension(SC_ZERO_TIME));
}

View File

@@ -38,8 +38,6 @@
* Luiza Correa
*/
#include <cassert>
#include "Configuration.h"
#include "memspec/MemSpecDDR3.h"
#include "memspec/MemSpecDDR4.h"
@@ -227,15 +225,6 @@ void Configuration::setParameter(const std::string &name, const nlohmann::json &
useMalloc = value;
else if (name == "CheckTLM2Protocol")
checkTLM2Protocol = value;
else if (name == "ECCControllerMode")
{
if (value == "Disabled")
eccMode = ECCMode::Disabled;
else if (value == "Hamming")
eccMode = ECCMode::Hamming;
else
SC_REPORT_FATAL("Configuration", "Unsupported ECC mode!");
}
// Specification for ErrorChipSeed, ErrorCSVFile path and StoreMode
else if (name == "ErrorChipSeed")
errorChipSeed = value;
@@ -285,8 +274,8 @@ void Configuration::setParameter(const std::string &name, const nlohmann::json &
else if (name == "GeneratePowerMap")
temperatureSim.generatePowerMap = value;
else
SC_REPORT_FATAL("Configuration",
("Parameter " + name + " not defined in Configuration").c_str());
SC_REPORT_WARNING("Configuration",
("Parameter " + name + " not defined in Configuration").c_str());
}
void Configuration::setPathToResources(const std::string &path)
@@ -294,19 +283,6 @@ void Configuration::setPathToResources(const std::string &path)
temperatureSim.setPathToResources(path);
}
// 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) const
{
// Manipulate the number of bytes only if there is an ECC Controller selected
if (eccMode == ECCMode::Disabled)
return nBytes;
else // if (eccMode == ECCMode::Hamming)
{
assert(pECC != nullptr);
return pECC->AllocationSize(nBytes);
}
}
void Configuration::loadSimConfig(Configuration &config, const std::string &simconfigUri)
{
json doc = parseJSON(simconfigUri);

View File

@@ -45,7 +45,6 @@
#include <systemc>
#include "memspec/MemSpec.h"
#include "../error/eccbaseclass.h"
#include "TemperatureSimConfig.h"
class Configuration
@@ -97,8 +96,6 @@ public:
bool thermalSimulation = false;
bool simulationProgressBar = false;
bool checkTLM2Protocol = false;
enum class ECCMode {Disabled, Hamming} eccMode = ECCMode::Disabled;
ECCBaseClass *pECC = nullptr;
bool useMalloc = false;
unsigned long long int addressOffset = 0;
@@ -115,7 +112,6 @@ public:
// Temperature Simulation related
TemperatureSimConfig temperatureSim;
unsigned int adjustNumBytesAfterECC(unsigned bytes) const;
void setPathToResources(const std::string &path);
static void loadMCConfig(Configuration &config, const std::string &_mcconfigUri);

View File

@@ -55,16 +55,19 @@ MemSpec::MemSpec(json &memspec, MemoryType memoryType,
numberOfDevices(numberOfDevices),
numberOfRows(parseUint(memspec["memarchitecturespec"], "nbrOfRows")),
numberOfColumns(parseUint(memspec["memarchitecturespec"], "nbrOfColumns")),
burstLength(parseUint(memspec["memarchitecturespec"], "burstLength")),
defaultBurstLength(parseUint(memspec["memarchitecturespec"], "burstLength")),
maxBurstLength(memspec["memarchitecturespec"]["maxBurstLength"].is_number_unsigned() ?
static_cast<unsigned>(memspec["memarchitecturespec"]["maxBurstLength"]) : defaultBurstLength),
dataRate(parseUint(memspec["memarchitecturespec"], "dataRate")),
bitWidth(parseUint(memspec["memarchitecturespec"], "width")),
dataBusWidth(bitWidth * numberOfDevices),
bytesPerBurst((burstLength * dataBusWidth) / 8),
defaultBytesPerBurst((defaultBurstLength * dataBusWidth) / 8),
maxBytesPerBurst((maxBurstLength * dataBusWidth) / 8),
fCKMHz(parseUdouble(memspec["memtimingspec"], "clkMhz")),
tCK(sc_time(1.0 / fCKMHz, SC_US)),
memoryId(parseString(memspec, "memoryId")),
memoryType(memoryType),
burstDuration(tCK * (static_cast<double>(burstLength) / dataRate)),
burstDuration(tCK * (static_cast<double>(defaultBurstLength) / dataRate)),
memorySizeBytes(0)
{
commandLengthInCycles = std::vector<unsigned>(Command::numberOfCommands(), 1);

View File

@@ -60,11 +60,13 @@ public:
const unsigned numberOfDevices;
const unsigned numberOfRows;
const unsigned numberOfColumns;
const unsigned burstLength;
const unsigned defaultBurstLength;
const unsigned maxBurstLength;
const unsigned dataRate;
const unsigned bitWidth;
const unsigned dataBusWidth;
const unsigned bytesPerBurst;
const unsigned defaultBytesPerBurst;
const unsigned maxBytesPerBurst;
// Clock
const double fCKMHz;

View File

@@ -39,7 +39,7 @@
using namespace sc_core;
using namespace tlm;
ControllerRecordable::ControllerRecordable(const sc_module_name &name, TlmRecorder *tlmRecorder)
ControllerRecordable::ControllerRecordable(const sc_module_name &name, TlmRecorder& tlmRecorder)
: Controller(name), tlmRecorder(tlmRecorder)
{
if (Configuration::getInstance().enableWindowing)
@@ -78,7 +78,7 @@ void ControllerRecordable::sendToDram(Command command, tlm_generic_payload *payl
if (command.isCasCommand())
{
TimeInterval dataStrobe = Configuration::getInstance().memSpec->getIntervalOnDataStrobe(command, *payload);
tlmRecorder->updateDataStrobe(sc_time_stamp() + delay + dataStrobe.start,
tlmRecorder.updateDataStrobe(sc_time_stamp() + delay + dataStrobe.start,
sc_time_stamp() + delay + dataStrobe.end, *payload);
}
tlm_phase phase = command.toPhase();
@@ -103,7 +103,7 @@ void ControllerRecordable::recordPhase(tlm_generic_payload &trans, const tlm_pha
bg) + " bank " + std::to_string(bank) + " row " + std::to_string(row) + " column " +
std::to_string(col) + " id " + std::to_string(id) + " at " + recTime.to_string());
tlmRecorder->recordPhase(trans, phase, recTime);
tlmRecorder.recordPhase(trans, phase, recTime);
}
void ControllerRecordable::controllerMethod()
@@ -128,7 +128,7 @@ void ControllerRecordable::controllerMethod()
slidingAverageBufferDepth[index] = SC_ZERO_TIME;
}
tlmRecorder->recordBufferDepth(sc_time_stamp().to_seconds(), windowAverageBufferDepth);
tlmRecorder.recordBufferDepth(sc_time_stamp().to_seconds(), windowAverageBufferDepth);
Controller::controllerMethod();
@@ -136,7 +136,7 @@ void ControllerRecordable::controllerMethod()
lastNumberOfBeatsServed = numberOfBeatsServed;
sc_time windowActiveTime = activeTimeMultiplier * static_cast<double>(windowNumberOfBeatsServed);
double windowAverageBandwidth = windowActiveTime / windowSizeTime;
tlmRecorder->recordBandwidth(sc_time_stamp().to_seconds(), windowAverageBandwidth);
tlmRecorder.recordBandwidth(sc_time_stamp().to_seconds(), windowAverageBandwidth);
}
else
{

View File

@@ -43,7 +43,7 @@
class ControllerRecordable final : public Controller
{
public:
ControllerRecordable(const sc_core::sc_module_name &name, TlmRecorder *tlmRecorder);
ControllerRecordable(const sc_core::sc_module_name &name, TlmRecorder& tlmRecorder);
~ControllerRecordable() override = default;
protected:
@@ -59,7 +59,7 @@ protected:
private:
void recordPhase(tlm::tlm_generic_payload &trans, const tlm::tlm_phase &phase, const sc_core::sc_time &delay);
TlmRecorder *tlmRecorder;
TlmRecorder& tlmRecorder;
sc_core::sc_event windowEvent;
sc_core::sc_time windowSizeTime;

View File

@@ -54,7 +54,7 @@ CheckerDDR3::CheckerDDR3()
lastCommandOnBus = sc_max_time();
last4Activates = std::vector<std::queue<sc_time>>(memSpec->numberOfRanks);
tBURST = memSpec->burstLength / memSpec->dataRate * memSpec->tCK;
tBURST = memSpec->defaultBurstLength / memSpec->dataRate * memSpec->tCK;
tRDWR = memSpec->tRL + tBURST + 2 * memSpec->tCK - memSpec->tWL;
tRDWR_R = memSpec->tRL + tBURST + memSpec->tRTRS - memSpec->tWL;
tWRRD = memSpec->tWL + tBURST + memSpec->tWTR - memSpec->tAL;
@@ -75,6 +75,8 @@ sc_time CheckerDDR3::timeToSatisfyConstraints(Command command, tlm_generic_paylo
if (command == Command::RD || command == Command::RDA)
{
assert(DramExtension::getBurstLength(payload) == 8);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCD - memSpec->tAL);
@@ -128,6 +130,8 @@ sc_time CheckerDDR3::timeToSatisfyConstraints(Command command, tlm_generic_paylo
}
else if (command == Command::WR || command == Command::WRA)
{
assert(DramExtension::getBurstLength(payload) == 8);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCD - memSpec->tAL);

View File

@@ -56,7 +56,7 @@ CheckerDDR4::CheckerDDR4()
lastCommandOnBus = sc_max_time();
last4Activates = std::vector<std::queue<sc_time>>(memSpec->numberOfRanks);
tBURST = memSpec->burstLength / memSpec->dataRate * memSpec->tCK;
tBURST = memSpec->defaultBurstLength / memSpec->dataRate * memSpec->tCK;
tRDWR = memSpec->tRL + tBURST + memSpec->tCK - memSpec->tWL + memSpec->tWPRE;
tRDWR_R = memSpec->tRL + tBURST + memSpec->tRTRS - memSpec->tWL + memSpec->tWPRE;
tWRRD_S = memSpec->tWL + tBURST + memSpec->tWTR_S - memSpec->tAL;
@@ -79,6 +79,8 @@ sc_time CheckerDDR4::timeToSatisfyConstraints(Command command, tlm_generic_paylo
if (command == Command::RD || command == Command::RDA)
{
assert(DramExtension::getBurstLength(payload) == 8);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCD - memSpec->tAL);
@@ -148,6 +150,8 @@ sc_time CheckerDDR4::timeToSatisfyConstraints(Command command, tlm_generic_paylo
}
else if (command == Command::WR || command == Command::WRA)
{
assert(DramExtension::getBurstLength(payload) == 8);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCD - memSpec->tAL);

View File

@@ -131,7 +131,9 @@ sc_time CheckerDDR5::timeToSatisfyConstraints(Command command, tlm_generic_paylo
if (command == Command::RD || command == Command::RDA)
{
unsigned burstLength = DramExtension::getBurstLength(payload);
assert((burstLength == 16) || (burstLength == 32));
assert(!(burstLength == 32) || (memSpec->bitWidth == 4));
assert(burstLength <= memSpec->maxBurstLength);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
@@ -316,7 +318,9 @@ sc_time CheckerDDR5::timeToSatisfyConstraints(Command command, tlm_generic_paylo
else if (command == Command::WR || command == Command::WRA)
{
unsigned burstLength = DramExtension::getBurstLength(payload);
assert((burstLength == 16) || (burstLength == 32));
assert(!(burstLength == 32) || (memSpec->bitWidth == 4));
assert(burstLength <= memSpec->maxBurstLength);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())

View File

@@ -59,7 +59,7 @@ CheckerGDDR5::CheckerGDDR5()
bankwiseRefreshCounter = std::vector<unsigned>(memSpec->numberOfRanks);
tBURST = memSpec->burstLength / memSpec->dataRate * memSpec->tCK;
tBURST = memSpec->defaultBurstLength / memSpec->dataRate * memSpec->tCK;
tRDSRE = memSpec->tCL + memSpec->tWCK2CKPIN + memSpec->tWCK2CK + memSpec->tWCK2DQO + tBURST;
tWRSRE = memSpec->tWL + memSpec->tWCK2CKPIN + memSpec->tWCK2CK + memSpec->tWCK2DQI + tBURST;
tRDWR_R = memSpec->tCL + tBURST + memSpec->tRTRS - memSpec->tWL;
@@ -80,6 +80,8 @@ sc_time CheckerGDDR5::timeToSatisfyConstraints(Command command, tlm_generic_payl
if (command == Command::RD || command == Command::RDA)
{
assert(DramExtension::getBurstLength(payload) == 8);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCDRD);
@@ -149,6 +151,8 @@ sc_time CheckerGDDR5::timeToSatisfyConstraints(Command command, tlm_generic_payl
}
else if (command == Command::WR || command == Command::WRA)
{
assert(DramExtension::getBurstLength(payload) == 8);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCDWR);

View File

@@ -59,7 +59,7 @@ CheckerGDDR5X::CheckerGDDR5X()
bankwiseRefreshCounter = std::vector<unsigned>(memSpec->numberOfRanks);
tBURST = memSpec->burstLength / memSpec->dataRate * memSpec->tCK;
tBURST = memSpec->defaultBurstLength / memSpec->dataRate * memSpec->tCK;
tRDSRE = memSpec->tRL + memSpec->tWCK2CKPIN + memSpec->tWCK2CK + memSpec->tWCK2DQO + tBURST;
tWRSRE = memSpec->tWL + memSpec->tWCK2CKPIN + memSpec->tWCK2CK + memSpec->tWCK2DQI + tBURST;
tRDWR_R = memSpec->tRL + tBURST + memSpec->tRTRS - memSpec->tWL;
@@ -80,6 +80,10 @@ sc_time CheckerGDDR5X::timeToSatisfyConstraints(Command command, tlm_generic_pay
if (command == Command::RD || command == Command::RDA)
{
unsigned burstLength = DramExtension::getBurstLength(payload);
assert(!(memSpec->dataRate == 4) || (burstLength == 8)); // DDR mode (QDR wrt CK)
assert(!(memSpec->dataRate == 8) || (burstLength == 16)); // QDR mode (ODR wrt CK)
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCDRD);
@@ -149,6 +153,10 @@ sc_time CheckerGDDR5X::timeToSatisfyConstraints(Command command, tlm_generic_pay
}
else if (command == Command::WR || command == Command::WRA)
{
unsigned burstLength = DramExtension::getBurstLength(payload);
assert(!(memSpec->dataRate == 4) || (burstLength == 8)); // DDR mode (QDR wrt CK)
assert(!(memSpec->dataRate == 8) || (burstLength == 16)); // QDR mode (ODR wrt CK)
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCDWR);

View File

@@ -58,7 +58,7 @@ CheckerGDDR6::CheckerGDDR6()
bankwiseRefreshCounter = std::vector<unsigned>(memSpec->numberOfRanks);
tBURST = memSpec->burstLength / memSpec->dataRate * memSpec->tCK;
tBURST = memSpec->defaultBurstLength / memSpec->dataRate * memSpec->tCK;
tRDSRE = memSpec->tRL + memSpec->tWCK2CKPIN + memSpec->tWCK2CK + memSpec->tWCK2DQO + tBURST;
tWRSRE = memSpec->tWL + memSpec->tWCK2CKPIN + memSpec->tWCK2CK + memSpec->tWCK2DQI + tBURST;
tRDWR_R = memSpec->tRL + tBURST + memSpec->tRTRS - memSpec->tWL;
@@ -79,6 +79,8 @@ sc_time CheckerGDDR6::timeToSatisfyConstraints(Command command, tlm_generic_payl
if (command == Command::RD || command == Command::RDA)
{
assert(DramExtension::getBurstLength(payload) == 16);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCDRD);
@@ -148,6 +150,8 @@ sc_time CheckerGDDR6::timeToSatisfyConstraints(Command command, tlm_generic_payl
}
else if (command == Command::WR || command == Command::WRA)
{
assert(DramExtension::getBurstLength(payload) == 16);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCDWR);

View File

@@ -59,7 +59,7 @@ CheckerHBM2::CheckerHBM2()
bankwiseRefreshCounter = std::vector<unsigned>(memSpec->numberOfRanks);
tBURST = memSpec->burstLength / memSpec->dataRate * memSpec->tCK;
tBURST = memSpec->defaultBurstLength / memSpec->dataRate * memSpec->tCK;
tRDPDE = memSpec->tRL + memSpec->tPL + tBURST + memSpec->tCK;
tRDSRE = tRDPDE;
tWRPRE = memSpec->tWL + tBURST + memSpec->tWR;
@@ -80,6 +80,10 @@ sc_time CheckerHBM2::timeToSatisfyConstraints(Command command, tlm_generic_paylo
if (command == Command::RD || command == Command::RDA)
{
unsigned burstLength = DramExtension::getBurstLength(payload);
assert(!(memSpec->numberOfRanks == 1) || (burstLength == 2)); // Legacy mode
assert(!(memSpec->numberOfRanks == 2) || (burstLength == 4)); // Pseudo-channel mode
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCDRD + memSpec->tCK);
@@ -131,6 +135,10 @@ sc_time CheckerHBM2::timeToSatisfyConstraints(Command command, tlm_generic_paylo
}
else if (command == Command::WR || command == Command::WRA)
{
unsigned burstLength = DramExtension::getBurstLength(payload);
assert(!(memSpec->numberOfRanks == 1) || (burstLength == 2)); // Legacy mode
assert(!(memSpec->numberOfRanks == 2) || (burstLength == 4)); // Pseudo-channel mode
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCDWR + memSpec->tCK);

View File

@@ -54,7 +54,7 @@ CheckerLPDDR4::CheckerLPDDR4()
lastCommandOnBus = sc_max_time();
last4Activates = std::vector<std::queue<sc_time>>(memSpec->numberOfRanks);
tBURST = memSpec->burstLength / memSpec->dataRate * memSpec->tCK;
tBURST = memSpec->defaultBurstLength / memSpec->dataRate * memSpec->tCK;
tRDWR = memSpec->tRL + memSpec->tDQSCK + tBURST - memSpec->tWL + memSpec->tWPRE + memSpec->tRPST;
tRDWR_R = memSpec->tRL + tBURST + memSpec->tRTRS - memSpec->tWL;
tWRRD = memSpec->tWL + memSpec->tCK + tBURST + memSpec->tWTR;
@@ -81,6 +81,10 @@ sc_time CheckerLPDDR4::timeToSatisfyConstraints(Command command, tlm_generic_pay
if (command == Command::RD || command == Command::RDA)
{
unsigned burstLength = DramExtension::getBurstLength(payload);
assert((burstLength == 16) || (burstLength == 32)); // TODO: BL16/32 OTF
assert(burstLength <= memSpec->maxBurstLength);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCD);
@@ -130,6 +134,10 @@ sc_time CheckerLPDDR4::timeToSatisfyConstraints(Command command, tlm_generic_pay
}
else if (command == Command::WR || command == Command::WRA)
{
unsigned burstLength = DramExtension::getBurstLength(payload);
assert((burstLength == 16) || (burstLength == 32));
assert(burstLength <= memSpec->maxBurstLength);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCD);

View File

@@ -84,7 +84,8 @@ sc_time CheckerLPDDR5::timeToSatisfyConstraints(Command command, tlm_generic_pay
{
unsigned burstLength = DramExtension::getBurstLength(payload);
assert(!(memSpec->bitWidth == 8) || (burstLength == 32)); // x8 device -> BL32
assert(!(memSpec->groupsPerRank > 1) || (burstLength == 16)); // BG mode -> BL16
assert(!(memSpec->groupsPerRank > 1) || (burstLength == 16)); // BG mode -> BL16 (TODO: BL32)
assert(burstLength <= memSpec->maxBurstLength);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
@@ -195,7 +196,8 @@ sc_time CheckerLPDDR5::timeToSatisfyConstraints(Command command, tlm_generic_pay
{
unsigned burstLength = DramExtension::getBurstLength(payload);
assert(!(memSpec->bitWidth == 8) || (burstLength == 32)); // x8 device -> BL32
assert(!(memSpec->groupsPerRank > 1) || (burstLength == 16)); // BG mode -> BL16
assert(!(memSpec->groupsPerRank > 1) || (burstLength == 16)); // BG mode -> BL16 (TODO: BL32)
assert(burstLength <= memSpec->maxBurstLength);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())

View File

@@ -54,7 +54,7 @@ CheckerSTTMRAM::CheckerSTTMRAM()
lastCommandOnBus = sc_max_time();
last4Activates = std::vector<std::queue<sc_time>>(memSpec->numberOfRanks);
tBURST = memSpec->burstLength / memSpec->dataRate * memSpec->tCK;
tBURST = memSpec->defaultBurstLength / memSpec->dataRate * memSpec->tCK;
tRDWR = memSpec->tRL + tBURST + 2 * memSpec->tCK - memSpec->tWL;
tRDWR_R = memSpec->tRL + tBURST + memSpec->tRTRS - memSpec->tWL;
tWRRD = memSpec->tWL + tBURST + memSpec->tWTR - memSpec->tAL;
@@ -75,6 +75,8 @@ sc_time CheckerSTTMRAM::timeToSatisfyConstraints(Command command, tlm_generic_pa
if (command == Command::RD || command == Command::RDA)
{
assert(DramExtension::getBurstLength(payload) == 8);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCD - memSpec->tAL);
@@ -130,6 +132,8 @@ sc_time CheckerSTTMRAM::timeToSatisfyConstraints(Command command, tlm_generic_pa
}
else if (command == Command::WR || command == Command::WRA)
{
assert(DramExtension::getBurstLength(payload) == 8);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCD - memSpec->tAL);

View File

@@ -54,7 +54,7 @@ CheckerWideIO::CheckerWideIO()
lastCommandOnBus = sc_max_time();
last2Activates = std::vector<std::queue<sc_time>>(memSpec->numberOfRanks);
tBURST = memSpec->burstLength * memSpec->tCK;
tBURST = memSpec->defaultBurstLength * memSpec->tCK;
tRDWR = memSpec->tRL + tBURST + memSpec->tCK;
tRDWR_R = memSpec->tRL + tBURST + memSpec->tRTRS - memSpec->tWL;
tWRPRE = memSpec->tWL + tBURST - memSpec->tCK + memSpec->tWR;
@@ -75,6 +75,10 @@ sc_time CheckerWideIO::timeToSatisfyConstraints(Command command, tlm_generic_pay
if (command == Command::RD || command == Command::RDA)
{
unsigned burstLength = DramExtension::getBurstLength(payload);
assert((burstLength == 2) || (burstLength == 4));
assert(burstLength <= memSpec->maxBurstLength);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCD);
@@ -124,6 +128,10 @@ sc_time CheckerWideIO::timeToSatisfyConstraints(Command command, tlm_generic_pay
}
else if (command == Command::WR || command == Command::WRA)
{
unsigned burstLength = DramExtension::getBurstLength(payload);
assert((burstLength == 2) || (burstLength == 4));
assert(burstLength <= memSpec->maxBurstLength);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCD);

View File

@@ -54,7 +54,7 @@ CheckerWideIO2::CheckerWideIO2()
lastCommandOnBus = sc_max_time();
last4Activates = std::vector<std::queue<sc_time>>(memSpec->numberOfRanks);
tBURST = memSpec->burstLength / memSpec->dataRate * memSpec->tCK;
tBURST = memSpec->defaultBurstLength / memSpec->dataRate * memSpec->tCK;
tRDPRE = tBURST + std::max(2 * memSpec->tCK, memSpec->tRTP) - 2 * memSpec->tCK;
tRDPDEN = memSpec->tRL + memSpec->tDQSCK + tBURST + memSpec->tCK;
tRDWR = memSpec->tRL + memSpec->tDQSCK + tBURST + memSpec->tCK - memSpec->tWL;
@@ -76,6 +76,10 @@ sc_time CheckerWideIO2::timeToSatisfyConstraints(Command command, tlm_generic_pa
if (command == Command::RD || command == Command::RDA)
{
unsigned burstLength = DramExtension::getBurstLength(payload);
assert((burstLength == 4) || (burstLength == 8)); // TODO: BL4/8 OTF
assert(burstLength <= memSpec->maxBurstLength);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCD);
@@ -125,6 +129,10 @@ sc_time CheckerWideIO2::timeToSatisfyConstraints(Command command, tlm_generic_pa
}
else if (command == Command::WR || command == Command::WRA)
{
unsigned burstLength = DramExtension::getBurstLength(payload);
assert((burstLength == 4) || (burstLength == 8));
assert(burstLength <= memSpec->maxBurstLength);
lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()];
if (lastCommandStart != sc_max_time())
earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCD);

View File

@@ -53,13 +53,12 @@ void errorModel::init()
powerAnalysis = Configuration::getInstance().powerAnalysis;
thermalSim = Configuration::getInstance().thermalSimulation;
// Get Configuration parameters:
burstLenght = Configuration::getInstance().memSpec->burstLength;
burstLenght = Configuration::getInstance().memSpec->defaultBurstLength;
numberOfColumns = Configuration::getInstance().memSpec->numberOfColumns;
bytesPerColumn = std::log2(Configuration::getInstance().memSpec->dataBusWidth);
// Adjust number of bytes per column dynamically to the selected ecc controller
bytesPerColumn = Configuration::getInstance().adjustNumBytesAfterECC(
bytesPerColumn);
//TODO: bytesPerColumn = Configuration::getInstance().adjustNumBytesAfterECC(bytesPerColumn);
numberOfRows = Configuration::getInstance().memSpec->numberOfRows;
numberOfBitErrorEvents = 0;

View File

@@ -74,9 +74,6 @@ DRAMSys::DRAMSys(const sc_core::sc_module_name &name,
bool initAndBind)
: sc_module(name), tSocket("DRAMSys_tSocket")
{
// Initialize ecc pointer
ecc = nullptr;
logo();
// Read Configuration Setup:
@@ -119,25 +116,6 @@ DRAMSys::DRAMSys(const sc_core::sc_module_name &name,
}
}
DRAMSys::~DRAMSys()
{
delete ecc;
delete arbiter;
for (auto dram : drams)
delete dram;
for (auto controller : controllers)
delete controller;
for (auto tlmChecker : playersTlmCheckers)
delete tlmChecker;
for (auto tlmChecker : controllersTlmCheckers)
delete tlmChecker;
}
void DRAMSys::logo()
{
#define GREENTXT(s) std::string(("\u001b[38;5;28m"+std::string((s))+"\033[0m"))
@@ -182,69 +160,47 @@ void DRAMSys::instantiateModules(const std::string &pathToResources,
TemperatureController::getInstance();
Configuration &config = Configuration::getInstance();
// Create new ECC Controller
if (config.eccMode == Configuration::ECCMode::Hamming)
ecc = new ECCHamming("ECCHamming");
else if (config.eccMode == Configuration::ECCMode::Disabled)
ecc = nullptr;
// Save ECC Controller into the configuration struct to adjust it dynamically
config.pECC = ecc;
// Create arbiter
if (config.arbiter == Configuration::Arbiter::Simple)
arbiter = new ArbiterSimple("arbiter", pathToResources + "configs/amconfigs/" + amconfig);
arbiter = std::unique_ptr<Arbiter>(new ArbiterSimple("arbiter", pathToResources + "configs/amconfigs/" + amconfig));
else if (config.arbiter == Configuration::Arbiter::Fifo)
arbiter = new ArbiterFifo("arbiter", pathToResources + "configs/amconfigs/" + amconfig);
arbiter = std::unique_ptr<Arbiter>(new ArbiterFifo("arbiter", pathToResources + "configs/amconfigs/" + amconfig));
else if (config.arbiter == Configuration::Arbiter::Reorder)
arbiter = new ArbiterReorder("arbiter", pathToResources + "configs/amconfigs/" + amconfig);
arbiter = std::unique_ptr<Arbiter>(new ArbiterReorder("arbiter", pathToResources + "configs/amconfigs/" + amconfig));
// Create controllers and DRAMs
MemSpec::MemoryType memoryType = config.memSpec->memoryType;
for (std::size_t i = 0; i < config.memSpec->numberOfChannels; i++)
{
std::string str = "controller" + std::to_string(i);
ControllerIF *controller = new Controller(str.c_str());
controllers.push_back(controller);
str = "dram" + std::to_string(i);
Dram *dram;
controllers.emplace_back(new Controller(("controller" + std::to_string(i)).c_str()));
if (memoryType == MemSpec::MemoryType::DDR3)
dram = new DramDDR3(str.c_str());
drams.emplace_back(new DramDDR3(("dram" + std::to_string(i)).c_str()));
else if (memoryType == MemSpec::MemoryType::DDR4)
dram = new DramDDR4(str.c_str());
drams.emplace_back(new DramDDR4(("dram" + std::to_string(i)).c_str()));
else if (memoryType == MemSpec::MemoryType::DDR5)
dram = new DramDDR5(str.c_str());
drams.emplace_back(new DramDDR5(("dram" + std::to_string(i)).c_str()));
else if (memoryType == MemSpec::MemoryType::WideIO)
dram = new DramWideIO(str.c_str());
drams.emplace_back(new DramWideIO(("dram" + std::to_string(i)).c_str()));
else if (memoryType == MemSpec::MemoryType::LPDDR4)
dram = new DramLPDDR4(str.c_str());
drams.emplace_back(new DramLPDDR4(("dram" + std::to_string(i)).c_str()));
else if (memoryType == MemSpec::MemoryType::LPDDR5)
dram = new DramLPDDR5(str.c_str());
drams.emplace_back(new DramLPDDR5(("dram" + std::to_string(i)).c_str()));
else if (memoryType == MemSpec::MemoryType::WideIO2)
dram = new DramWideIO2(str.c_str());
drams.emplace_back(new DramWideIO2(("dram" + std::to_string(i)).c_str()));
else if (memoryType == MemSpec::MemoryType::HBM2)
dram = new DramHBM2(str.c_str());
drams.emplace_back(new DramHBM2(("dram" + std::to_string(i)).c_str()));
else if (memoryType == MemSpec::MemoryType::GDDR5)
dram = new DramGDDR5(str.c_str());
drams.emplace_back(new DramGDDR5(("dram" + std::to_string(i)).c_str()));
else if (memoryType == MemSpec::MemoryType::GDDR5X)
dram = new DramGDDR5X(str.c_str());
drams.emplace_back(new DramGDDR5X(("dram" + std::to_string(i)).c_str()));
else if (memoryType == MemSpec::MemoryType::GDDR6)
dram = new DramGDDR6(str.c_str());
drams.emplace_back(new DramGDDR6(("dram" + std::to_string(i)).c_str()));
else if (memoryType == MemSpec::MemoryType::STTMRAM)
dram = new DramSTTMRAM(str.c_str());
drams.emplace_back(new DramSTTMRAM(("dram" + std::to_string(i)).c_str()));
drams.push_back(dram);
if (Configuration::getInstance().checkTLM2Protocol)
{
str = "TLMCheckerController" + std::to_string(i);
tlm_utils::tlm2_base_protocol_checker<> *controllerTlmChecker =
new tlm_utils::tlm2_base_protocol_checker<>(str.c_str());
controllersTlmCheckers.push_back(controllerTlmChecker);
}
if (config.checkTLM2Protocol)
controllersTlmCheckers.push_back(new tlm_utils::tlm2_base_protocol_checker<>(("TlmCheckerController" + std::to_string(i)).c_str()));
}
}
@@ -252,32 +208,20 @@ void DRAMSys::bindSockets()
{
Configuration &config = Configuration::getInstance();
// If ECC Controller enabled, put it between Trace and arbiter
if (config.eccMode == Configuration::ECCMode::Hamming)
{
assert(ecc != nullptr);
tSocket.bind(ecc->t_socket);
ecc->i_socket.bind(arbiter->tSocket);
}
else if (config.eccMode == Configuration::ECCMode::Disabled)
tSocket.bind(arbiter->tSocket);
tSocket.bind(arbiter->tSocket);
if (config.checkTLM2Protocol)
for (unsigned i = 0; i < config.memSpec->numberOfChannels; i++)
{
for (std::size_t i = 0; i < config.memSpec->numberOfChannels; i++)
if (config.checkTLM2Protocol)
{
arbiter->iSocket.bind(controllersTlmCheckers[i]->target_socket);
controllersTlmCheckers[i]->initiator_socket.bind(controllers[i]->tSocket);
controllers[i]->iSocket.bind(drams[i]->tSocket);
}
}
else
{
for (std::size_t i = 0; i < config.memSpec->numberOfChannels; i++)
else
{
arbiter->iSocket.bind(controllers[i]->tSocket);
controllers[i]->iSocket.bind(drams[i]->tSocket);
}
controllers[i]->iSocket.bind(drams[i]->tSocket);
}
}

View File

@@ -41,6 +41,8 @@
#define DRAMSYS_H
#include <string>
#include <list>
#include <memory>
#include <systemc>
#include "dram/Dram.h"
@@ -57,16 +59,11 @@ class DRAMSys : public sc_core::sc_module
public:
tlm_utils::multi_passthrough_target_socket<DRAMSys> tSocket;
std::vector<tlm_utils::tlm2_base_protocol_checker<>*>
playersTlmCheckers;
SC_HAS_PROCESS(DRAMSys);
DRAMSys(const sc_core::sc_module_name &name,
const std::string &simulationToRun,
const std::string &pathToResources);
~DRAMSys() override;
protected:
DRAMSys(const sc_core::sc_module_name &name,
const std::string &simulationToRun,
@@ -74,32 +71,28 @@ protected:
bool initAndBind);
//TLM 2.0 Protocol Checkers
std::vector<tlm_utils::tlm2_base_protocol_checker<>*>
controllersTlmCheckers;
// All transactions pass first through the ECC Controller
ECCBaseClass *ecc;
std::vector<tlm_utils::tlm2_base_protocol_checker<>*> controllersTlmCheckers;
// TODO: Each DRAM has a reorder buffer (check this!)
ReorderBuffer *reorder;
std::unique_ptr<ReorderBuffer> reorder;
// All transactions pass through the same arbiter
Arbiter *arbiter;
std::unique_ptr<Arbiter> arbiter;
// Each DRAM unit has a controller
std::vector<ControllerIF *> controllers;
std::vector<std::unique_ptr<ControllerIF>> controllers;
// DRAM units
std::vector<Dram *> drams;
std::vector<std::unique_ptr<Dram>> drams;
void report(const std::string &message);
void bindSockets();
private:
static void logo();
void instantiateModules(const std::string &pathToResources,
const std::string &amconfig);
void bindSockets();
static void setupDebugManager(const std::string &traceName);
};

View File

@@ -80,17 +80,17 @@ DRAMSysRecordable::DRAMSysRecordable(const sc_module_name &name,
report(headline);
}
DRAMSysRecordable::~DRAMSysRecordable()
void DRAMSysRecordable::end_of_simulation()
{
// Report power before TLM recorders are deleted
if (Configuration::getInstance().powerAnalysis)
{
for (auto dram : drams)
for (auto& dram : drams)
dram->reportPower();
}
for (auto rec : tlmRecorders)
delete rec;
for (auto& tlmRecorder : tlmRecorders)
tlmRecorder.finalize();
}
void DRAMSysRecordable::setupTlmRecorders(const std::string &traceName)
@@ -99,18 +99,12 @@ void DRAMSysRecordable::setupTlmRecorders(const std::string &traceName)
for (std::size_t i = 0; i < Configuration::getInstance().memSpec->numberOfChannels; i++)
{
std::string dbName = traceName + std::string("_ch") + std::to_string(i) + ".tdb";
std::string recorderName = "tlmRecorder" + std::to_string(i);
TlmRecorder *tlmRecorder =
new TlmRecorder(recorderName, dbName);
tlmRecorder->recordMcConfig(Configuration::mcconfigUri);
tlmRecorder->recordMemspec(Configuration::memspecUri);
std::string traceNames = Configuration::getInstance().simulationName;
tlmRecorder->recordTraceNames(traceNames);
tlmRecorders.push_back(tlmRecorder);
tlmRecorders.emplace_back(recorderName, dbName);
tlmRecorders.back().recordMcConfig(Configuration::mcconfigUri);
tlmRecorders.back().recordMemspec(Configuration::memspecUri);
tlmRecorders.back().recordTraceNames(Configuration::getInstance().simulationName);
}
}
@@ -128,101 +122,47 @@ void DRAMSysRecordable::instantiateModules(const std::string &traceName,
// They need to be ready before creating some modules.
setupTlmRecorders(traceName);
// Create new ECC Controller
if (config.eccMode == Configuration::ECCMode::Hamming)
ecc = new ECCHamming("ECCHamming");
else if (config.eccMode == Configuration::ECCMode::Disabled)
ecc = nullptr;
// Save ECC Controller into the configuration struct to adjust it dynamically
config.pECC = ecc;
// Create arbiter
if (config.arbiter == Configuration::Arbiter::Simple)
arbiter = new ArbiterSimple("arbiter", pathToResources + "configs/amconfigs/" + amconfig);
arbiter = std::unique_ptr<Arbiter>(new ArbiterSimple("arbiter", pathToResources + "configs/amconfigs/" + amconfig));
else if (config.arbiter == Configuration::Arbiter::Fifo)
arbiter = new ArbiterFifo("arbiter", pathToResources + "configs/amconfigs/" + amconfig);
arbiter = std::unique_ptr<Arbiter>(new ArbiterFifo("arbiter", pathToResources + "configs/amconfigs/" + amconfig));
else if (config.arbiter == Configuration::Arbiter::Reorder)
arbiter = new ArbiterReorder("arbiter", pathToResources + "configs/amconfigs/" + amconfig);
arbiter = std::unique_ptr<Arbiter>(new ArbiterReorder("arbiter", pathToResources + "configs/amconfigs/" + amconfig));
// Create controllers and DRAMs
MemSpec::MemoryType memoryType = config.memSpec->memoryType;
for (std::size_t i = 0; i < config.memSpec->numberOfChannels; i++)
{
std::string str = "controller" + std::to_string(i);
ControllerIF *controller = new ControllerRecordable(str.c_str(), tlmRecorders[i]);
controllers.push_back(controller);
str = "dram" + std::to_string(i);
Dram *dram;
controllers.emplace_back(new ControllerRecordable(("controller" + std::to_string(i)).c_str(), tlmRecorders[i]));
if (memoryType == MemSpec::MemoryType::DDR3)
dram = new DramRecordable<DramDDR3>(str.c_str(), tlmRecorders[i]);
drams.emplace_back(new DramRecordable<DramDDR3>(("dram" + std::to_string(i)).c_str(), tlmRecorders[i]));
else if (memoryType == MemSpec::MemoryType::DDR4)
dram = new DramRecordable<DramDDR4>(str.c_str(), tlmRecorders[i]);
drams.emplace_back(new DramRecordable<DramDDR4>(("dram" + std::to_string(i)).c_str(), tlmRecorders[i]));
else if (memoryType == MemSpec::MemoryType::DDR5)
dram = new DramRecordable<DramDDR5>(str.c_str(), tlmRecorders[i]);
drams.emplace_back(new DramRecordable<DramDDR5>(("dram" + std::to_string(i)).c_str(), tlmRecorders[i]));
else if (memoryType == MemSpec::MemoryType::WideIO)
dram = new DramRecordable<DramWideIO>(str.c_str(), tlmRecorders[i]);
drams.emplace_back(new DramRecordable<DramWideIO>(("dram" + std::to_string(i)).c_str(), tlmRecorders[i]));
else if (memoryType == MemSpec::MemoryType::LPDDR4)
dram = new DramRecordable<DramLPDDR4>(str.c_str(), tlmRecorders[i]);
drams.emplace_back(new DramRecordable<DramLPDDR4>(("dram" + std::to_string(i)).c_str(), tlmRecorders[i]));
else if (memoryType == MemSpec::MemoryType::LPDDR5)
dram = new DramRecordable<DramLPDDR5>(str.c_str(), tlmRecorders[i]);
drams.emplace_back(new DramRecordable<DramLPDDR5>(("dram" + std::to_string(i)).c_str(), tlmRecorders[i]));
else if (memoryType == MemSpec::MemoryType::WideIO2)
dram = new DramRecordable<DramWideIO2>(str.c_str(), tlmRecorders[i]);
drams.emplace_back(new DramRecordable<DramWideIO2>(("dram" + std::to_string(i)).c_str(), tlmRecorders[i]));
else if (memoryType == MemSpec::MemoryType::HBM2)
dram = new DramRecordable<DramHBM2>(str.c_str(), tlmRecorders[i]);
drams.emplace_back(new DramRecordable<DramHBM2>(("dram" + std::to_string(i)).c_str(), tlmRecorders[i]));
else if (memoryType == MemSpec::MemoryType::GDDR5)
dram = new DramRecordable<DramGDDR5>(str.c_str(), tlmRecorders[i]);
drams.emplace_back(new DramRecordable<DramGDDR5>(("dram" + std::to_string(i)).c_str(), tlmRecorders[i]));
else if (memoryType == MemSpec::MemoryType::GDDR5X)
dram = new DramRecordable<DramGDDR5X>(str.c_str(), tlmRecorders[i]);
drams.emplace_back(new DramRecordable<DramGDDR5X>(("dram" + std::to_string(i)).c_str(), tlmRecorders[i]));
else if (memoryType == MemSpec::MemoryType::GDDR6)
dram = new DramRecordable<DramGDDR6>(str.c_str(), tlmRecorders[i]);
drams.emplace_back(new DramRecordable<DramGDDR6>(("dram" + std::to_string(i)).c_str(), tlmRecorders[i]));
else if (memoryType == MemSpec::MemoryType::STTMRAM)
dram = new DramRecordable<DramSTTMRAM>(str.c_str(), tlmRecorders[i]);
drams.push_back(dram);
drams.emplace_back(new DramRecordable<DramSTTMRAM>(("dram" + std::to_string(i)).c_str(), tlmRecorders[i]));
if (config.checkTLM2Protocol)
{
str = "TLMCheckerController" + std::to_string(i);
tlm_utils::tlm2_base_protocol_checker<> *controllerTlmChecker =
new tlm_utils::tlm2_base_protocol_checker<>(str.c_str());
controllersTlmCheckers.push_back(controllerTlmChecker);
}
}
}
void DRAMSysRecordable::bindSockets()
{
Configuration &config = Configuration::getInstance();
// If ECC Controller enabled, put it between Trace and arbiter
if (config.eccMode == Configuration::ECCMode::Hamming)
{
assert(ecc != nullptr);
tSocket.bind(ecc->t_socket);
ecc->i_socket.bind(arbiter->tSocket);
}
else if (config.eccMode == Configuration::ECCMode::Disabled)
tSocket.bind(arbiter->tSocket);
if (config.checkTLM2Protocol)
{
for (std::size_t i = 0; i < config.memSpec->numberOfChannels; i++)
{
arbiter->iSocket.bind(controllersTlmCheckers[i]->target_socket);
controllersTlmCheckers[i]->initiator_socket.bind(controllers[i]->tSocket);
controllers[i]->iSocket.bind(drams[i]->tSocket);
}
}
else
{
for (std::size_t i = 0; i < config.memSpec->numberOfChannels; i++)
{
arbiter->iSocket.bind(controllers[i]->tSocket);
controllers[i]->iSocket.bind(drams[i]->tSocket);
}
controllersTlmCheckers.emplace_back(new tlm_utils::tlm2_base_protocol_checker<>(("TLMCheckerController"
+ std::to_string(i)).c_str()));
}
}

View File

@@ -46,20 +46,18 @@ public:
const std::string &simulationToRun,
const std::string &pathToResources);
~DRAMSysRecordable() override;
private:
// Transaction Recorders (one per channel).
// They generate the output databases.
std::vector<TlmRecorder *> tlmRecorders;
std::vector<TlmRecorder> tlmRecorders;
void end_of_simulation() override;
void setupTlmRecorders(const std::string &traceName);
void instantiateModules(const std::string &traceName,
const std::string &pathToResources,
const std::string &amconfig);
void bindSockets();
};
#endif // DRAMSYSRECORDABLE_H

View File

@@ -65,8 +65,6 @@ using namespace DRAMPower;
Dram::Dram(const sc_module_name &name) : sc_module(name), tSocket("socket")
{
Configuration &config = Configuration::getInstance();
// Adjust number of bytes per burst dynamically to the selected ecc controller
bytesPerBurst = config.adjustNumBytesAfterECC(bytesPerBurst);
storeMode = config.storeMode;

View File

@@ -50,7 +50,6 @@
class Dram : public sc_core::sc_module
{
private:
unsigned int bytesPerBurst = Configuration::getInstance().memSpec->bytesPerBurst;
bool powerReported = false;
protected:

View File

@@ -53,7 +53,7 @@ DramDDR3::DramDDR3(const sc_module_name &name) : Dram(name)
SC_REPORT_FATAL("DramDDR3", "Wrong MemSpec chosen");
MemArchitectureSpec memArchSpec;
memArchSpec.burstLength = memSpec->burstLength;
memArchSpec.burstLength = memSpec->defaultBurstLength;
memArchSpec.dataRate = memSpec->dataRate;
memArchSpec.nbrOfRows = memSpec->numberOfRows;
memArchSpec.nbrOfBanks = memSpec->numberOfBanks;

View File

@@ -53,7 +53,7 @@ DramDDR4::DramDDR4(const sc_module_name &name) : Dram(name)
SC_REPORT_FATAL("DramDDR4", "Wrong MemSpec chosen");
MemArchitectureSpec memArchSpec;
memArchSpec.burstLength = memSpec->burstLength;
memArchSpec.burstLength = memSpec->defaultBurstLength;
memArchSpec.dataRate = memSpec->dataRate;
memArchSpec.nbrOfRows = memSpec->numberOfRows;
memArchSpec.nbrOfBanks = memSpec->numberOfBanks;

View File

@@ -55,7 +55,7 @@ using namespace sc_core;
using namespace tlm;
template<class BaseDram>
DramRecordable<BaseDram>::DramRecordable(const sc_module_name &name, TlmRecorder *tlmRecorder)
DramRecordable<BaseDram>::DramRecordable(const sc_module_name &name, TlmRecorder& tlmRecorder)
: BaseDram(name), tlmRecorder(tlmRecorder)
{
// Create a thread that is triggered every $powerWindowSize
@@ -68,7 +68,7 @@ template<class BaseDram>
void DramRecordable<BaseDram>::reportPower()
{
BaseDram::reportPower();
tlmRecorder->recordPower(sc_time_stamp().to_seconds(),
tlmRecorder.recordPower(sc_time_stamp().to_seconds(),
this->DRAMPower->getPower().window_average_power
* Configuration::getInstance().memSpec->numberOfDevices);
}
@@ -103,12 +103,12 @@ void DramRecordable<BaseDram>::recordPhase(tlm_generic_payload &trans, const tlm
bg) + " bank " + std::to_string(bank) + " row " + std::to_string(row) + " column " +
std::to_string(col) + " at " + recTime.to_string());
tlmRecorder->recordPhase(trans, phase, recTime);
tlmRecorder.recordPhase(trans, phase, recTime);
if (phaseNeedsEnd(phase))
{
recTime += this->memSpec->getExecutionTime(Command(phase), trans);
tlmRecorder->recordPhase(trans, getEndPhase(phase), recTime);
tlmRecorder.recordPhase(trans, getEndPhase(phase), recTime);
}
}
@@ -134,7 +134,7 @@ void DramRecordable<BaseDram>::powerWindow()
assert(!isEqual(this->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(),
tlmRecorder.recordPower(sc_time_stamp().to_seconds(),
this->DRAMPower->getPower().window_average_power
* Configuration::getInstance().memSpec->numberOfDevices);

View File

@@ -46,7 +46,7 @@ template<class BaseDram>
class DramRecordable final : public BaseDram
{
public:
DramRecordable(const sc_core::sc_module_name &name, TlmRecorder *);
DramRecordable(const sc_core::sc_module_name &name, TlmRecorder& tlmRecorder);
SC_HAS_PROCESS(DramRecordable);
void reportPower() override;
@@ -57,7 +57,7 @@ private:
void recordPhase(tlm::tlm_generic_payload &trans, const tlm::tlm_phase &phase, const sc_core::sc_time &delay);
TlmRecorder *tlmRecorder;
TlmRecorder& tlmRecorder;
sc_core::sc_time powerWindowSize = Configuration::getInstance().memSpec->tCK *
Configuration::getInstance().windowSize;

View File

@@ -54,7 +54,7 @@ DramWideIO::DramWideIO(const sc_module_name &name) : Dram(name)
SC_REPORT_FATAL("DramWideIO", "Wrong MemSpec chosen");
MemArchitectureSpec memArchSpec;
memArchSpec.burstLength = memSpec->burstLength;
memArchSpec.burstLength = memSpec->defaultBurstLength;
memArchSpec.dataRate = memSpec->dataRate;
memArchSpec.nbrOfRows = memSpec->numberOfRows;
memArchSpec.nbrOfBanks = memSpec->numberOfBanks;
@@ -74,9 +74,9 @@ DramWideIO::DramWideIO(const sc_module_name &name) : Dram(name)
//FIXME: memTimingSpec.RRDB_L = memSpec->tRRD / memSpec->tCK;
//FIXME: memTimingSpec.RRDB_S = memSpec->tRRD / memSpec->tCK;
memTimingSpec.AL = 0;
memTimingSpec.CCD = memSpec->burstLength;
memTimingSpec.CCD_L = memSpec->burstLength;
memTimingSpec.CCD_S = memSpec->burstLength;
memTimingSpec.CCD = memSpec->defaultBurstLength;
memTimingSpec.CCD_L = memSpec->defaultBurstLength;
memTimingSpec.CCD_S = memSpec->defaultBurstLength;
memTimingSpec.CKE = memSpec->tCKE / memSpec->tCK;
memTimingSpec.CKESR = memSpec->tCKESR / memSpec->tCK;
memTimingSpec.clkMhz = memSpec->fCKMHz;
@@ -94,7 +94,7 @@ DramWideIO::DramWideIO(const sc_module_name &name) : Dram(name)
memTimingSpec.RRD = memSpec->tRRD / memSpec->tCK;
memTimingSpec.RRD_L = memSpec->tRRD / memSpec->tCK;
memTimingSpec.RRD_S = memSpec->tRRD / memSpec->tCK;
memTimingSpec.RTP = memSpec->burstLength;
memTimingSpec.RTP = memSpec->defaultBurstLength;
memTimingSpec.TAW = memSpec->tTAW / memSpec->tCK;
memTimingSpec.WL = memSpec->tWL / memSpec->tCK;
memTimingSpec.WR = memSpec->tWR / memSpec->tCK;

View File

@@ -52,6 +52,7 @@ add_executable(DRAMSys
TrafficGenerator.cpp
TrafficInitiator.cpp
TraceSetup.cpp
LengthConverter.cpp
)
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/../library/src/simulation/DRAMSysRecordable.cpp)

View File

@@ -0,0 +1,236 @@
/*
* Copyright (c) 2022, Technische Universität 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:
* Lukas Steiner
*/
#include "LengthConverter.h"
using namespace sc_core;
using namespace tlm;
// TODO: return status, TLM_INCOMPLETE_RESPONSE, acquire + release
LengthConverter::LengthConverter(const sc_module_name &name, unsigned maxOutputLength, bool storageEnabled) :
sc_module(name), payloadEventQueue(this, &LengthConverter::peqCallback), storageEnabled(storageEnabled),
memoryManager(storageEnabled, maxOutputLength), maxOutputLength(maxOutputLength)
{
iSocket.register_nb_transport_bw(this, &LengthConverter::nb_transport_bw);
tSocket.register_nb_transport_fw(this, &LengthConverter::nb_transport_fw);
tSocket.register_transport_dbg(this, &LengthConverter::transport_dbg);
}
tlm_sync_enum LengthConverter::nb_transport_fw(tlm_generic_payload& trans,
tlm_phase& phase, sc_time& fwDelay)
{
if (phase == BEGIN_REQ)
trans.acquire();
payloadEventQueue.notify(trans, phase, fwDelay);
return TLM_ACCEPTED;
}
tlm_sync_enum LengthConverter::nb_transport_bw(tlm_generic_payload &payload,
tlm_phase &phase, sc_time &bwDelay)
{
payloadEventQueue.notify(payload, phase, bwDelay);
return TLM_ACCEPTED;
}
unsigned int LengthConverter::transport_dbg(tlm_generic_payload &trans)
{
return iSocket->transport_dbg(trans);
}
void LengthConverter::peqCallback(tlm_generic_payload &cbTrans, const tlm_phase &cbPhase)
{
if (cbPhase == BEGIN_REQ) // from initiator
{
if (cbTrans.get_data_length() <= maxOutputLength)
{
// pipe transaction through
tlm_phase fwPhase = BEGIN_REQ;
sc_time fwDelay = SC_ZERO_TIME;
tlm_sync_enum returnStatus = iSocket->nb_transport_fw(cbTrans, fwPhase, fwDelay);
// TODO: END_REQ/BEGIN_RESP shortcut
}
else
{
// split transaction up into multiple sub-transactions
createChildTranses(&cbTrans);
tlm_generic_payload* firstChildTrans = cbTrans.get_extension<ParentExtension>()->getNextChildTrans();
tlm_phase fwPhase = BEGIN_REQ;
sc_time fwDelay = SC_ZERO_TIME;
tlm_sync_enum returnStatus = iSocket->nb_transport_fw(*firstChildTrans, fwPhase, fwDelay);
}
}
else if (cbPhase == END_REQ)
{
if (ChildExtension::isChildTrans(&cbTrans))
{
tlm_generic_payload* nextChildTrans = cbTrans.get_extension<ChildExtension>()->getNextChildTrans();
if (nextChildTrans != nullptr)
{
tlm_phase fwPhase = BEGIN_REQ;
//sc_time fwDelay = SC_ZERO_TIME;
sc_time fwDelay = sc_time(1, SC_NS);
tlm_sync_enum returnStatus = iSocket->nb_transport_fw(*nextChildTrans, fwPhase, fwDelay);
}
else
{
tlm_generic_payload* parentTrans = cbTrans.get_extension<ChildExtension>()->getParentTrans();
tlm_phase bwPhase = END_REQ;
sc_time bwDelay = SC_ZERO_TIME;
tlm_sync_enum returnStatus = tSocket->nb_transport_bw(*parentTrans, bwPhase, bwDelay);
}
}
else
{
tlm_phase bwPhase = END_REQ;
sc_time bwDelay = SC_ZERO_TIME;
tlm_sync_enum returnStatus = tSocket->nb_transport_bw(cbTrans, bwPhase, bwDelay);
}
}
else if (cbPhase == BEGIN_RESP)
{
if (ChildExtension::isChildTrans(&cbTrans))
{
{
tlm_phase fwPhase = END_RESP;
sc_time fwDelay = SC_ZERO_TIME;
tlm_sync_enum returnStatus = iSocket->nb_transport_fw(cbTrans, fwPhase, fwDelay);
}
if (storageEnabled && cbTrans.is_read())
{
tlm_generic_payload* parentTrans = cbTrans.get_extension<ChildExtension>()->getParentTrans();
std::copy(cbTrans.get_data_ptr(), cbTrans.get_data_ptr() + maxOutputLength,
parentTrans->get_data_ptr() + (cbTrans.get_address() - parentTrans->get_address()));
}
if (cbTrans.get_extension<ChildExtension>()->notifyChildTransCompletion()) // all children finished
{
// BEGIN_RESP über tSocket
tlm_generic_payload* parentTrans = cbTrans.get_extension<ChildExtension>()->getParentTrans();
tlm_phase bwPhase = BEGIN_RESP;
sc_time bwDelay = SC_ZERO_TIME;
tlm_sync_enum returnStatus = tSocket->nb_transport_bw(*parentTrans, bwPhase, bwDelay);
}
}
else
{
tlm_phase bwPhase = BEGIN_RESP;
sc_time bwDelay = SC_ZERO_TIME;
tlm_sync_enum returnStatus = tSocket->nb_transport_bw(cbTrans, bwPhase, bwDelay);
}
}
else if (cbPhase == END_RESP)
{
if (ParentExtension::isParentTrans(&cbTrans))
{
cbTrans.get_extension<ParentExtension>()->releaseChildTranses();
}
else
{
tlm_phase fwPhase = END_RESP;
sc_time fwDelay = SC_ZERO_TIME;
tlm_sync_enum returnStatus = iSocket->nb_transport_fw(cbTrans, fwPhase, fwDelay);
}
cbTrans.release();
}
else
SC_REPORT_FATAL(0, "Payload event queue in LengthConverter was triggered with unknown phase");
}
void LengthConverter::createChildTranses(tlm_generic_payload* parentTrans)
{
unsigned numChildTranses = parentTrans->get_data_length() / maxOutputLength;
std::vector<tlm_generic_payload*> childTranses;
for (unsigned childId = 0; childId < numChildTranses; childId++)
{
tlm_generic_payload* childTrans = memoryManager.allocate();
childTrans->acquire();
childTrans->set_command(parentTrans->get_command());
childTrans->set_address(parentTrans->get_address() + childId * maxOutputLength);
childTrans->set_data_length(maxOutputLength);
if (storageEnabled && parentTrans->is_write())
std::copy(parentTrans->get_data_ptr() + childId * maxOutputLength, parentTrans->get_data_ptr() +
(childId + 1) * maxOutputLength, childTrans->get_data_ptr());
ChildExtension::setExtension(childTrans, parentTrans);
childTranses.push_back(childTrans);
}
ParentExtension::setExtension(parentTrans, std::move(childTranses));
}
LengthConverter::MemoryManager::MemoryManager(bool storageEnabled, unsigned maxDataLength)
: storageEnabled(storageEnabled), maxDataLength(maxDataLength)
{}
LengthConverter::MemoryManager::~MemoryManager()
{
while (!freePayloads.empty())
{
tlm_generic_payload* payload = freePayloads.top();
if (storageEnabled)
delete[] payload->get_data_ptr();
payload->reset();
delete payload;
freePayloads.pop();
}
}
tlm_generic_payload* LengthConverter::MemoryManager::allocate()
{
if (freePayloads.empty())
{
auto* payload = new tlm_generic_payload(this);
if (storageEnabled)
{
auto* data = new unsigned char[maxDataLength];
payload->set_data_ptr(data);
}
return payload;
}
else
{
tlm_generic_payload* result = freePayloads.top();
freePayloads.pop();
return result;
}
}
void LengthConverter::MemoryManager::free(tlm_generic_payload* payload)
{
freePayloads.push(payload);
}

View File

@@ -0,0 +1,233 @@
/*
* Copyright (c) 2022, Technische Universität 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:
* Lukas Steiner
*/
#ifndef LENGTHCONVERTER_H
#define LENGTHCONVERTER_H
#include <iostream>
#include <utility>
#include <vector>
#include <queue>
#include <set>
#include <unordered_map>
#include <stack>
#include <tlm>
#include <systemc>
#include <tlm_utils/simple_initiator_socket.h>
#include <tlm_utils/simple_target_socket.h>
#include <tlm_utils/peq_with_cb_and_phase.h>
//TLM_DECLARE_EXTENDED_PHASE(REQ_ARBITRATION);
//TLM_DECLARE_EXTENDED_PHASE(RESP_ARBITRATION);
class LengthConverter : public sc_core::sc_module
{
public:
tlm_utils::simple_initiator_socket<LengthConverter> iSocket;
tlm_utils::simple_target_socket<LengthConverter> tSocket;
LengthConverter(const sc_core::sc_module_name& name, unsigned maxOutputLength, bool storageEnabled);
SC_HAS_PROCESS(LengthConverter);
private:
tlm_utils::peq_with_cb_and_phase<LengthConverter> payloadEventQueue;
void peqCallback(tlm::tlm_generic_payload &payload, const tlm::tlm_phase &phase);
//std::vector<bool> tSocketIsBusy;
//std::vector<bool> iSocketIsBusy;
const unsigned maxOutputLength;
const bool storageEnabled;
void createChildTranses(tlm::tlm_generic_payload* parentTrans);
//std::uint64_t getTargetAddress(std::uint64_t address) const;
//int getISocketId(std::uint64_t address) const;
//std::vector<std::queue<tlm::tlm_generic_payload *>> pendingRequests;
tlm::tlm_sync_enum nb_transport_fw(tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase,
sc_core::sc_time &fwDelay);
tlm::tlm_sync_enum nb_transport_bw(tlm::tlm_generic_payload &payload, tlm::tlm_phase &phase,
sc_core::sc_time &bwDelay);
unsigned int transport_dbg(tlm::tlm_generic_payload &trans);
class MemoryManager : public tlm::tlm_mm_interface
{
public:
MemoryManager(bool storageEnabled, unsigned maxDataLength);
~MemoryManager() override;
tlm::tlm_generic_payload* allocate();
void free(tlm::tlm_generic_payload* payload) override;
private:
std::stack<tlm::tlm_generic_payload*> freePayloads;
bool storageEnabled = false;
unsigned maxDataLength;
} memoryManager;
class ChildExtension : public tlm::tlm_extension<ChildExtension>
{
private:
tlm::tlm_generic_payload* parentTrans;
explicit ChildExtension(tlm::tlm_generic_payload* parentTrans) : parentTrans(parentTrans) {}
public:
//ChildExtension() = delete;
tlm_extension_base* clone() const override
{
return new ChildExtension(parentTrans);
}
void copy_from(tlm_extension_base const &ext) override
{
const auto& cpyFrom = dynamic_cast<const ChildExtension&>(ext);
parentTrans = cpyFrom.parentTrans;
}
tlm::tlm_generic_payload* getParentTrans()
{
return parentTrans;
}
static void setExtension(tlm::tlm_generic_payload* childTrans, tlm::tlm_generic_payload* parentTrans)
{
auto *extension = childTrans->get_extension<ChildExtension>();
if (extension != nullptr)
{
extension->parentTrans = parentTrans;
}
else
{
extension = new ChildExtension(parentTrans);
childTrans->set_auto_extension(extension);
}
}
static bool isChildTrans(const tlm::tlm_generic_payload* trans)
{
if (trans->get_extension<ChildExtension>() != nullptr)
return true;
else
return false;
}
tlm::tlm_generic_payload* getNextChildTrans()
{
return parentTrans->get_extension<ParentExtension>()->getNextChildTrans();
}
bool notifyChildTransCompletion()
{
return parentTrans->get_extension<ParentExtension>()->notifyChildTransCompletion();
}
};
class ParentExtension : public tlm::tlm_extension<ParentExtension>
{
private:
std::vector<tlm::tlm_generic_payload*> childTranses;
unsigned nextEndReqChildId = 0;
unsigned completedChildTranses = 0;
explicit ParentExtension(std::vector<tlm::tlm_generic_payload*> _childTranses)
: childTranses(std::move(_childTranses)) {}
public:
ParentExtension() = delete;
tlm_extension_base* clone() const override
{
return new ParentExtension(childTranses);
}
void copy_from(tlm_extension_base const &ext) override
{
const auto& cpyFrom = dynamic_cast<const ParentExtension&>(ext);
childTranses = cpyFrom.childTranses;
}
static bool isParentTrans(const tlm::tlm_generic_payload* trans)
{
auto* extension = trans->get_extension<ParentExtension>();
if (extension != nullptr)
return !extension->childTranses.empty();
else
return false;
}
static void setExtension(tlm::tlm_generic_payload* parentTrans, std::vector<tlm::tlm_generic_payload*> childTranses)
{
auto* extension = parentTrans->get_extension<ParentExtension>();
if (extension != nullptr)
{
extension->childTranses = std::move(childTranses);
extension->nextEndReqChildId = 0;
extension->completedChildTranses = 0;
}
else
{
extension = new ParentExtension(std::move(childTranses));
parentTrans->set_auto_extension(extension);
}
}
tlm::tlm_generic_payload* getNextChildTrans()
{
if (nextEndReqChildId < childTranses.size())
return childTranses[nextEndReqChildId++];
else
return nullptr;
}
bool notifyChildTransCompletion()
{
completedChildTranses++;
return completedChildTranses == childTranses.size();
}
void releaseChildTranses()
{
std::for_each(childTranses.begin(), childTranses.end(),
[](tlm::tlm_generic_payload* childTrans){childTrans->release();});
childTranses.clear();
}
};
};
#endif // LENGTHCONVERTER_H

View File

@@ -51,17 +51,18 @@ MemoryManager::MemoryManager()
MemoryManager::~MemoryManager()
{
for (tlm_generic_payload *payload : freePayloads)
for (auto& innerBuffer : freePayloads)
{
if (storageEnabled)
while (!innerBuffer.second.empty())
{
// Delete data buffer
delete[] payload->get_data_ptr();
tlm_generic_payload* payload = innerBuffer.second.top();
if (storageEnabled)
delete[] payload->get_data_ptr();
payload->reset();
delete payload;
innerBuffer.second.pop();
numberOfFrees++;
}
// Delete all extensions
payload->reset();
delete payload;
numberOfFrees++;
}
// Comment in if you are suspecting a memory leak in the manager
@@ -69,18 +70,17 @@ MemoryManager::~MemoryManager()
//PRINTDEBUGMESSAGE("MemoryManager","Number of freed payloads: " + to_string(numberOfFrees));
}
tlm_generic_payload *MemoryManager::allocate()
tlm_generic_payload *MemoryManager::allocate(unsigned dataLength)
{
if (freePayloads.empty())
if (freePayloads[dataLength].empty())
{
numberOfAllocations++;
tlm_generic_payload *payload = new tlm_generic_payload(this);
auto* payload = new tlm_generic_payload(this);
if (storageEnabled)
{
// Allocate a data buffer and initialize it with zeroes:
unsigned int dataLength = Configuration::getInstance().memSpec->bytesPerBurst;
unsigned char *data = new unsigned char[dataLength];
auto* data = new unsigned char[dataLength];
std::fill(data, data + dataLength, 0);
payload->set_data_ptr(data);
}
@@ -89,13 +89,14 @@ tlm_generic_payload *MemoryManager::allocate()
}
else
{
tlm_generic_payload *result = freePayloads.back();
freePayloads.pop_back();
tlm_generic_payload *result = freePayloads[dataLength].top();
freePayloads[dataLength].pop();
return result;
}
}
void MemoryManager::free(tlm_generic_payload *payload)
{
freePayloads.push_back(payload);
unsigned dataLength = payload->get_data_length();
freePayloads[dataLength].push(payload);
}

View File

@@ -37,7 +37,8 @@
#ifndef MEMORYMANAGER_H
#define MEMORYMANAGER_H
#include <vector>
#include <unordered_map>
#include <stack>
#include <tlm>
@@ -46,13 +47,13 @@ class MemoryManager : public tlm::tlm_mm_interface
public:
MemoryManager();
~MemoryManager() override;
tlm::tlm_generic_payload *allocate();
tlm::tlm_generic_payload *allocate(unsigned dataLength);
void free(tlm::tlm_generic_payload *payload) override;
private:
uint64_t numberOfAllocations;
uint64_t numberOfFrees;
std::vector<tlm::tlm_generic_payload *> freePayloads;
std::unordered_map<unsigned, std::stack<tlm::tlm_generic_payload *>> freePayloads;
bool storageEnabled = false;
};

View File

@@ -48,9 +48,10 @@ StlPlayer::StlPlayer(const sc_module_name &name,
const sc_time &playerClk,
unsigned int maxPendingReadRequests,
unsigned int maxPendingWriteRequests,
bool addLengthConverter,
TraceSetup *setup,
bool relative) :
TrafficInitiator(name, setup, maxPendingReadRequests, maxPendingWriteRequests),
TrafficInitiator(name, setup, maxPendingReadRequests, maxPendingWriteRequests, addLengthConverter),
file(pathToTrace), relative(relative), playerClk(playerClk)
{
currentBuffer = &lineContents[0];
@@ -73,9 +74,6 @@ StlPlayer::StlPlayer(const sc_module_name &name,
SC_REPORT_FATAL("StlPlayer", "Trace file is empty");
}
burstLength = Configuration::getInstance().memSpec->burstLength;
dataLength = Configuration::getInstance().memSpec->bytesPerBurst;
currentBuffer->reserve(lineBufferSize);
parseBuffer->reserve(lineBufferSize);
@@ -103,17 +101,16 @@ void StlPlayer::sendNextPayload()
}
// Allocate a generic payload for this request.
tlm_generic_payload *payload = setup->allocatePayload();
tlm_generic_payload *payload = setup->allocatePayload(lineIterator->dataLength);
payload->acquire();
// Fill up the payload.
payload->set_address(lineIterator->addr);
payload->set_address(lineIterator->address);
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_command(lineIterator->cmd);
payload->set_data_length(lineIterator->dataLength);
payload->set_command(lineIterator->command);
std::copy(lineIterator->data.begin(), lineIterator->data.end(), payload->get_data_ptr());
sc_time sendingTime;
@@ -164,64 +161,60 @@ void StlPlayer::parseTraceFile()
// Trace files MUST provide timestamp, command and address for every
// transaction. The data information depends on the storage mode
// configuration.
std::string time, command, address, dataStr;
std::string element;
std::istringstream iss;
iss.str(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 " + std::to_string(
lineCnt) + ").").c_str());
content.sendingTime = playerClk * static_cast<double>(std::stoull(time));
iss >> element;
if (element.empty())
SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ".").c_str());
content.sendingTime = playerClk * static_cast<double>(std::stoull(element));
// Get the command.
iss >> command;
if (command.empty())
SC_REPORT_FATAL("StlPlayer",
("Malformed trace file. Command could not be found (line " + std::to_string(
lineCnt) + ").").c_str());
if (command == "read")
content.cmd = TLM_READ_COMMAND;
else if (command == "write")
content.cmd = TLM_WRITE_COMMAND;
// Get the optional burst length and command
iss >> element;
if (element.empty())
SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ".").c_str());
if (element.at(0) == '(')
{
element.erase(0, 1);
content.dataLength = std::stoul(element);
iss >> element;
if (element.empty())
SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ".").c_str());
}
else
SC_REPORT_FATAL("StlPlayer",
(std::string("Corrupted tracefile, command ") + command +
std::string(" unknown")).c_str());
content.dataLength = defaultDataLength;
if (element == "read")
content.command = TLM_READ_COMMAND;
else if (element == "write")
content.command = TLM_WRITE_COMMAND;
else
SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ".").c_str());
// Get the address.
iss >> address;
if (address.empty())
SC_REPORT_FATAL("StlPlayer",
("Malformed trace file. Address could not be found (line "
+ std::to_string(lineCnt) + ").").c_str());
content.addr = std::stoull(address, nullptr, 16);
iss >> element;
if (element.empty())
SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ".").c_str());
content.address = std::stoull(element, nullptr, 16);
// Get the data if necessary.
if (storageEnabled && content.cmd == TLM_WRITE_COMMAND)
if (storageEnabled && content.command == TLM_WRITE_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 " + std::to_string(
lineCnt) + ").").c_str());
iss >> element;
// Check if data length in the trace file is correct.
// We need two characters to represent 1 byte in hexadecimal. Offset for 0x prefix.
if (dataStr.length() != (dataLength * 2 + 2))
SC_REPORT_FATAL("StlPlayer",
("Data in the trace file has an invalid length (line " + std::to_string(
lineCnt) + ").").c_str());
if (element.length() != (content.dataLength * 2 + 2))
SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ".").c_str());
// Set data
for (unsigned i = 0; i < dataLength; i++)
for (unsigned i = 0; i < content.dataLength; i++)
content.data.emplace_back(static_cast<unsigned char>
(std::stoi(dataStr.substr(i * 2 + 2, 2), nullptr, 16)));
(std::stoi(element.substr(i * 2 + 2, 2), nullptr, 16)));
}
}
}

View File

@@ -55,8 +55,9 @@
struct LineContent
{
sc_core::sc_time sendingTime;
tlm::tlm_command cmd;
uint64_t addr;
unsigned dataLength;
tlm::tlm_command command;
uint64_t address;
std::vector<unsigned char> data;
};
@@ -68,6 +69,7 @@ public:
const sc_core::sc_time &playerClk,
unsigned int maxPendingReadRequests,
unsigned int maxPendingWriteRequests,
bool addLengthConverter,
TraceSetup *setup,
bool relative);

View File

@@ -45,7 +45,7 @@ using namespace tlm;
TraceSetup::TraceSetup(const std::string &uri,
const std::string &pathToResources,
std::vector<TrafficInitiator *> &players)
std::vector<std::unique_ptr<TrafficInitiator>> &players)
{
// Load Simulation:
nlohmann::json simulationdoc = parseJSON(uri);
@@ -83,6 +83,10 @@ TraceSetup::TraceSetup(const std::string &uri,
if (value["maxPendingWriteRequests"].is_number_unsigned())
maxPendingWriteRequests = value["maxPendingWriteRequests"];
bool addLengthConverter = false;
if (value["addLengthConverter"].is_boolean())
addLengthConverter = value["addLengthConverter"];
std::string type;
// Defaulting to type "player" when not specified
@@ -112,16 +116,17 @@ TraceSetup::TraceSetup(const std::string &uri,
StlPlayer *player;
if (ext == "stl")
player = new StlPlayer(moduleName.c_str(), stlFile, playerClk,
maxPendingReadRequests, maxPendingWriteRequests, this, false);
maxPendingReadRequests, maxPendingWriteRequests,
addLengthConverter, this, false);
else if (ext == "rstl")
player = new StlPlayer(moduleName.c_str(), stlFile, playerClk,
maxPendingReadRequests, maxPendingWriteRequests, this, true);
maxPendingReadRequests, maxPendingWriteRequests,
addLengthConverter, this, true);
else
throw std::runtime_error("Unsupported file extension in " + name);
players.push_back(player);
totalTransactions += player->getNumberOfLines();
players.push_back(std::unique_ptr<TrafficInitiator>(player));
}
else if (type == "generator")
{
@@ -180,8 +185,6 @@ TraceSetup::TraceSetup(const std::string &uri,
if (maxAddress < minAddress)
SC_REPORT_FATAL("TraceSetup", "maxAddress is smaller than minAddress.");
TrafficInitiator* generator;
if (addressDistribution == "sequential")
{
uint64_t addressIncrement = 0x0;
@@ -190,20 +193,17 @@ TraceSetup::TraceSetup(const std::string &uri,
else
addressIncrement = value["addressIncrement"];
generator = new TrafficGeneratorSequential(name.c_str(), playerClk, numRequests,
maxPendingReadRequests, maxPendingWriteRequests,
minAddress, maxAddress, rwRatio, addressIncrement, seed,
this);
players.push_back(std::unique_ptr<TrafficInitiator>(new TrafficGeneratorSequential(name.c_str(),
playerClk, numRequests, maxPendingReadRequests, maxPendingWriteRequests, addLengthConverter,
minAddress, maxAddress, rwRatio, addressIncrement, seed, this)));
}
else
{
generator = new TrafficGeneratorRandom(name.c_str(), playerClk, numRequests,
maxPendingReadRequests, maxPendingWriteRequests,
minAddress, maxAddress, rwRatio, seed, this);
players.push_back(std::unique_ptr<TrafficInitiator>(new TrafficGeneratorRandom(name.c_str(),
playerClk, numRequests, maxPendingReadRequests, maxPendingWriteRequests, addLengthConverter,
minAddress, maxAddress, rwRatio, seed, this)));
}
players.push_back(generator);
totalTransactions += numRequests;
}
else if (type == "hammer")
@@ -216,9 +216,8 @@ TraceSetup::TraceSetup(const std::string &uri,
SC_REPORT_FATAL("TraceSetup", "Row increment is not a number.");
uint64_t rowIncrement = value["rowIncrement"];
TrafficInitiator* generator = new TrafficGeneratorHammer(name.c_str(), playerClk, numRequests,
rowIncrement, this);
players.push_back(generator);
players.push_back(std::unique_ptr<TrafficInitiator>(new TrafficGeneratorHammer(name.c_str(), playerClk,
numRequests, rowIncrement, this)));
}
}
else
@@ -227,6 +226,7 @@ TraceSetup::TraceSetup(const std::string &uri,
remainingTransactions = totalTransactions;
numberOfTrafficInitiators = players.size();
defaultDataLength = Configuration::getInstance().memSpec->defaultBytesPerBurst;
}
void TraceSetup::trafficInitiatorTerminates()
@@ -247,9 +247,14 @@ void TraceSetup::transactionFinished()
std::cout << std::endl;
}
tlm_generic_payload *TraceSetup::allocatePayload(unsigned dataLength)
{
return memoryManager.allocate(dataLength);
}
tlm_generic_payload *TraceSetup::allocatePayload()
{
return memoryManager.allocate();
return allocatePayload(defaultDataLength);
}
void TraceSetup::loadBar(uint64_t x, uint64_t n, unsigned int w, unsigned int granularity)

View File

@@ -39,6 +39,7 @@
#include <vector>
#include <string>
#include <memory>
#include <tlm>
#include "MemoryManager.h"
@@ -50,10 +51,11 @@ class TraceSetup
public:
TraceSetup(const std::string &uri,
const std::string &pathToResources,
std::vector<TrafficInitiator *> &devices);
std::vector<std::unique_ptr<TrafficInitiator>> &devices);
void trafficInitiatorTerminates();
void transactionFinished();
tlm::tlm_generic_payload *allocatePayload(unsigned dataLength);
tlm::tlm_generic_payload *allocatePayload();
private:
@@ -62,6 +64,7 @@ private:
uint64_t remainingTransactions;
unsigned int finishedTrafficInitiators = 0;
MemoryManager memoryManager;
unsigned defaultDataLength = 64;
static void loadBar(uint64_t x, uint64_t n, unsigned int w = 50, unsigned int granularity = 1);
};

View File

@@ -46,17 +46,14 @@ TrafficGenerator::TrafficGenerator(const sc_module_name &name,
uint64_t numRequests,
unsigned int maxPendingReadRequests,
unsigned int maxPendingWriteRequests,
bool addLengthConverter,
float rwRatio,
unsigned int seed,
TraceSetup *setup) :
TrafficInitiator(name, setup, maxPendingReadRequests, maxPendingWriteRequests),
generatorClk(generatorClk), numRequests(numRequests), rwRatio(rwRatio)
{
burstLength = Configuration::getInstance().memSpec->burstLength;
dataLength = Configuration::getInstance().memSpec->bytesPerBurst;
randomGenerator = std::default_random_engine(seed);
}
TrafficInitiator(name, setup, maxPendingReadRequests, maxPendingWriteRequests, addLengthConverter),
generatorClk(generatorClk), numRequests(numRequests), rwRatio(rwRatio),
randomGenerator(std::default_random_engine(seed))
{}
void TrafficGenerator::sendNextPayload()
{
@@ -89,8 +86,7 @@ void TrafficGenerator::sendNextPayload()
payload->set_response_status(tlm::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_length(defaultDataLength);
payload->set_command(command);
sc_time sendingOffset;
@@ -111,13 +107,14 @@ TrafficGeneratorRandom::TrafficGeneratorRandom(const sc_core::sc_module_name &na
uint64_t numRequests,
unsigned int maxPendingReadRequests,
unsigned int maxPendingWriteRequests,
bool addLengthConverter,
uint64_t minAddress,
uint64_t maxAddress,
float rwRatio,
unsigned int seed,
TraceSetup *setup) :
TrafficGenerator(name, generatorClk, numRequests, maxPendingReadRequests, maxPendingWriteRequests, rwRatio, seed,
setup)
TrafficGenerator(name, generatorClk, numRequests, maxPendingReadRequests, maxPendingWriteRequests,
addLengthConverter, rwRatio, seed, setup)
{
randomAddressDistribution = std::uniform_int_distribution<uint64_t> (minAddress, maxAddress);
}
@@ -132,14 +129,16 @@ TrafficGeneratorSequential::TrafficGeneratorSequential(const sc_core::sc_module_
uint64_t numRequests,
unsigned int maxPendingReadRequests,
unsigned int maxPendingWriteRequests,
bool addLengthConverter,
uint64_t minAddress,
uint64_t maxAddress,
float rwRatio,
uint64_t addressIncrement,
unsigned int seed,
TraceSetup *setup) :
TrafficGenerator(name, generatorClk, numRequests, maxPendingReadRequests, maxPendingWriteRequests, rwRatio, seed,
setup), minAddress(minAddress), maxAddress(maxAddress), addressIncrement(addressIncrement),
TrafficGenerator(name, generatorClk, numRequests, maxPendingReadRequests, maxPendingWriteRequests,
addLengthConverter, rwRatio, seed, setup),
minAddress(minAddress), maxAddress(maxAddress), addressIncrement(addressIncrement),
currentAddress(minAddress)
{
}
@@ -159,7 +158,7 @@ TrafficGeneratorHammer::TrafficGeneratorHammer(const sc_core::sc_module_name &na
uint64_t numRequests,
uint64_t rowIncrement,
TraceSetup *setup) :
TrafficGenerator(name, generatorClk, numRequests, 1, 1, 1.0f, 1, setup), rowIncrement(rowIncrement)
TrafficGenerator(name, generatorClk, numRequests, 1, 1, false, 1.0f, 1, setup), rowIncrement(rowIncrement)
{
}

View File

@@ -52,6 +52,7 @@ protected:
uint64_t numRequests,
unsigned int maxPendingReadRequests,
unsigned int maxPendingWriteRequests,
bool addLengthConverter,
float rwRatio,
unsigned int seed,
TraceSetup *setup);
@@ -78,6 +79,7 @@ public:
uint64_t numRequests,
unsigned int maxPendingReadRequests,
unsigned int maxPendingWriteRequests,
bool addLengthConverter,
uint64_t minAddress,
uint64_t maxAddress,
float rwRatio,
@@ -98,6 +100,7 @@ public:
uint64_t numRequests,
unsigned int maxPendingReadRequests,
unsigned int maxPendingWriteRequests,
bool addLengthConverter,
uint64_t minAddress,
uint64_t maxAddress,
float rwRatio,

View File

@@ -44,18 +44,18 @@ using namespace sc_core;
using namespace tlm;
TrafficInitiator::TrafficInitiator(const sc_module_name &name, TraceSetup *setup,
unsigned int maxPendingReadRequests, unsigned int maxPendingWriteRequests) :
sc_module(name), payloadEventQueue(this, &TrafficInitiator::peqCallback),
unsigned int maxPendingReadRequests, unsigned int maxPendingWriteRequests, bool addLengthConverter) :
sc_module(name),
payloadEventQueue(this, &TrafficInitiator::peqCallback),
setup(setup),
maxPendingReadRequests(maxPendingReadRequests), maxPendingWriteRequests(maxPendingWriteRequests)
maxPendingReadRequests(maxPendingReadRequests),
maxPendingWriteRequests(maxPendingWriteRequests),
addLengthConverter(addLengthConverter),
defaultDataLength(Configuration::getInstance().memSpec->defaultBytesPerBurst),
storageEnabled(Configuration::getInstance().storeMode != Configuration::StoreMode::NoStorage)
{
SC_METHOD(sendNextPayload);
iSocket.register_nb_transport_bw(this, &TrafficInitiator::nb_transport_bw);
if (Configuration::getInstance().storeMode == Configuration::StoreMode::NoStorage)
storageEnabled = false;
else
storageEnabled = true;
}
void TrafficInitiator::terminate()

View File

@@ -57,14 +57,14 @@ class TrafficInitiator : public sc_core::sc_module
public:
tlm_utils::simple_initiator_socket<TrafficInitiator> iSocket;
TrafficInitiator(const sc_core::sc_module_name &name, TraceSetup *setup,
unsigned int maxPendingReadRequests, unsigned int maxPendingWriteRequests);
unsigned int maxPendingReadRequests, unsigned int maxPendingWriteRequests, bool addLengthConverter);
SC_HAS_PROCESS(TrafficInitiator);
virtual void sendNextPayload() = 0;
const bool addLengthConverter = false;
protected:
tlm_utils::peq_with_cb_and_phase<TrafficInitiator> payloadEventQueue;
void terminate();
bool storageEnabled = false;
TraceSetup *setup;
void sendToTarget(tlm::tlm_generic_payload &payload, const tlm::tlm_phase &phase,
const sc_core::sc_time &delay);
@@ -73,13 +73,12 @@ protected:
uint64_t transactionsSent = 0;
unsigned int pendingReadRequests = 0;
unsigned int pendingWriteRequests = 0;
unsigned int maxPendingReadRequests = 0;
unsigned int maxPendingWriteRequests = 0;
const unsigned int maxPendingReadRequests = 0;
const unsigned int maxPendingWriteRequests = 0;
bool payloadPostponed = false;
bool finished = false;
unsigned int burstLength;
unsigned int dataLength;
const unsigned int defaultDataLength = 64;
const bool storageEnabled = false;
private:
tlm::tlm_sync_enum nb_transport_bw(tlm::tlm_generic_payload &payload, tlm::tlm_phase &phase,

View File

@@ -40,12 +40,15 @@
#include <string>
#include <utility>
#include <vector>
#include <list>
#include <chrono>
#include <memory>
#include <systemc>
#include "simulation/DRAMSys.h"
#include "TraceSetup.h"
#include "TrafficInitiator.h"
#include "LengthConverter.h"
#ifdef RECORDING
#include "simulation/DRAMSysRecordable.h"
@@ -95,39 +98,40 @@ int sc_main(int argc, char **argv)
resources = argv[2];
}
std::vector<TrafficInitiator *> players;
std::vector<std::unique_ptr<TrafficInitiator>> players;
std::vector<std::unique_ptr<LengthConverter>> lengthConverters;
// Instantiate DRAMSys:
DRAMSys *dramSys;
std::unique_ptr<DRAMSys> dramSys;
#ifdef RECORDING
json simulationdoc = parseJSON(simulationJson);
json simulatordoc = parseJSON(resources + "configs/simulator/"
+ std::string(simulationdoc["simulation"]["simconfig"]));
if (simulatordoc["simconfig"]["DatabaseRecording"])
dramSys = new DRAMSysRecordable("DRAMSys", simulationJson, resources);
if (simulatordoc["simconfig"]["DatabaseRecording"].is_boolean() && simulatordoc["simconfig"]["DatabaseRecording"])
dramSys = std::unique_ptr<DRAMSys>(new DRAMSysRecordable("DRAMSys", simulationJson, resources));
else
#endif
dramSys = new DRAMSys("DRAMSys", simulationJson, resources);
dramSys = std::unique_ptr<DRAMSys>(new DRAMSys("DRAMSys", simulationJson, resources));
// Instantiate STL Players:
TraceSetup *setup = new TraceSetup(simulationJson, resources, players);
// Instantiate STL Players (config of DRAMSys required!):
TraceSetup setup(simulationJson, resources, players);
// Bind STL Players with DRAMSys:
for (size_t i = 0; i < players.size(); i++)
for (auto& player : players)
{
if (Configuration::getInstance().checkTLM2Protocol)
if (player->addLengthConverter)
{
std::string str = "TLMCheckerPlayer" + std::to_string(i);
tlm_utils::tlm2_base_protocol_checker<> *playerTlmChecker =
new tlm_utils::tlm2_base_protocol_checker<>(str.c_str());
dramSys->playersTlmCheckers.push_back(playerTlmChecker);
players[i]->iSocket.bind(dramSys->playersTlmCheckers[i]->target_socket);
dramSys->playersTlmCheckers[i]->initiator_socket.bind(dramSys->tSocket);
std::string converterName("Converter_");
lengthConverters.emplace_back(new LengthConverter(converterName.append(player->name()).c_str(),
Configuration::getInstance().memSpec->maxBytesPerBurst,
Configuration::getInstance().storeMode != Configuration::StoreMode::NoStorage));
player->iSocket.bind(lengthConverters.back()->tSocket);
lengthConverters.back()->iSocket.bind(dramSys->tSocket);
}
else
{
players[i]->iSocket.bind(dramSys->tSocket);
player->iSocket.bind(dramSys->tSocket);
}
}
@@ -147,11 +151,5 @@ int sc_main(int argc, char **argv)
auto finish = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed = finish - start;
std::cout << "Simulation took " + std::to_string(elapsed.count()) + " seconds." << std::endl;
delete dramSys;
for (auto player : players)
delete player;
delete setup;
return 0;
}

View File

@@ -123,7 +123,8 @@ The JSON code below shows an example configuration:
"tracesetup": [
{
"clkMhz": 300,
"name": "ddr3_example.stl"
"name": "ddr3_example.stl",
"addLengthConverter": true
},
{
"clkMhz": 2000,
@@ -160,6 +161,7 @@ Fields Description:
Each **trace setup** device configuration can be a **trace player** ("type": "player"), a **traffic generator** ("type": "generator") or a **row hammer generator** ("type": "hammer"). By not specifing the **type** parameter, the device will act as a **trace player**.
All device configurations must define a **clkMhz** (operation frequency of the **traffic initiator**) and a **name** (in case of a trace player this specifies the **trace file** to play; in case of a generator this field is only for identification purposes).
The optional parameter **addLengthConverter** adds a transaction length converter between initiator and DRAMSys. This unit divides a large transaction up into several smaller transactions with the maximum length of one DRAM burst access.
The **maxPendingReadRequests** and **maxPendingWriteRequests** parameters define the maximum number of outstanding read/write requests. The current implementation delays all memory accesses when one limit is reached. The default value (0) disables the limit.
A **traffic generator** can be configured to generate **numRequests** requests in total, of which the **rwRatio** field defines the probability of one request being a read request. The **seed** parameter can be used to produce identical results for all simulations. **minAddress** and **maxAddress** specify the address range, by default the whole address range is used. The parameter **addressDistribution** can either be set to **"random"** or **"sequential"**. In case of **"sequential"** the additional **addressIncrement** field must be specified, defining the address increment after each request.
@@ -171,7 +173,7 @@ Most configuration fields reference other JSON files which contain more speciali
#### Trace Files
A **trace file** is a prerecorded file containing memory transactions. Each memory transaction has a time stamp that tells the simulator when it shall happen, a transaction type (*read* or *write*) and a hexadecimal memory address.
A **trace file** is a prerecorded file containing memory transactions. Each memory transaction has a time stamp that tells the simulator when it shall happen, a transaction type (*read* or *write*) and a hexadecimal memory address. The optional length parameter (in bytes) allows sending transactions with a custom length that does not match the length of a single DRAM burst access. In this case a length converter has to be added. Write transactions also have to specify a data field when storage is enabled in DRAMSys.
There are two different kinds of trace files. They differ in their timing behavior and are distinguished by their file extension.
@@ -183,11 +185,11 @@ Syntax example:
```
# Comment lines begin with #
# [clock-cyle]: [write|read] [hex-address] [hex-data (optional)]
31: read 0x400140
33: read 0x400160
56: write 0x7fff8000 0x123456789abcdef...
81: read 0x400180
# cycle: [(length)] command hex-address [hex-data]
31: read 0x400140
33: read 0x400160
56: write 0x7fff8000 0x123456789abcdef...
81: (128) read 0x400180
```
##### Relative STL Traces (.rstl)
@@ -198,11 +200,11 @@ Syntax example:
```
# Comment lines begin with #
# [clock-cyle]: [write|read] [hex-address] [hex-data (optional)]
31: read 0x400140
2: read 0x400160
23: write 0x7fff8000 0x123456789abcdef...
25: read 0x400180
# cycle: [(length)] command hex-address [hex-data]
31: read 0x400140
2: (512) read 0x400160
23: write 0x7fff8000 0x123456789abcdef...
10: read 0x400180
```
##### Elastic Traces