Merge branch 'develop' into wip/unit_test_preps

# Conflicts:
#	extensions/standards/DDR5/DRAMSys/controller/checker/CheckerDDR5.cpp
This commit is contained in:
Lukas Steiner
2023-04-14 11:35:32 +02:00
174 changed files with 6822 additions and 3684 deletions

View File

@@ -1,122 +0,0 @@
/*
* Copyright (c) 2021, 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:
* Derek Christ
*/
#include "AddressMapping.h"
#include <iostream>
namespace DRAMSys::Config
{
void to_json(json_t &j, const AddressMapping &m)
{
auto congen = json_t{{"BYTE_BIT", m.byteBits},
{"COLUMN_BIT", m.columnBits},
{"ROW_BIT", m.rowBits},
{"BANK_BIT", m.bankBits},
{"BANKGROUP_BIT", m.bankGroupBits},
{"RANK_BIT", m.rankBits},
{"CHANNEL_BIT", m.channelBits},
{"XOR", m.xorBits}};
remove_null_values(congen);
j["CONGEN"] = congen;
}
void from_json(const json_t &j, AddressMapping &m)
{
json_t j_addressmapping = get_config_json(j, addressMappingPath, "CONGEN");
json_t congen;
if (j_addressmapping["CONGEN"].is_null())
congen = j_addressmapping;
else
congen = j_addressmapping["CONGEN"];
if (congen.contains("BYTE_BIT"))
congen.at("BYTE_BIT").get_to(m.byteBits);
if (congen.contains("COLUMN_BIT"))
congen.at("COLUMN_BIT").get_to(m.columnBits);
if (congen.contains("ROW_BIT"))
congen.at("ROW_BIT").get_to(m.rowBits);
if (congen.contains("BANK_BIT"))
congen.at("BANK_BIT").get_to(m.bankBits);
if (congen.contains("BANKGROUP_BIT"))
congen.at("BANKGROUP_BIT").get_to(m.bankGroupBits);
if (congen.contains("RANK_BIT"))
congen.at("RANK_BIT").get_to(m.rankBits);
// HBM pseudo channels are internally modelled as ranks
if (congen.contains("PSEUDOCHANNEL_BIT"))
congen.at("PSEUDOCHANNEL_BIT").get_to(m.rankBits);
if (congen.contains("CHANNEL_BIT"))
congen.at("CHANNEL_BIT").get_to(m.channelBits);
if (congen.contains("XOR"))
congen.at("XOR").get_to(m.xorBits);
}
void to_json(json_t &j, const XorPair &x)
{
j = json_t{{"FIRST", x.first}, {"SECOND", x.second}};
}
void from_json(const json_t &j, XorPair &x)
{
j.at("FIRST").get_to(x.first);
j.at("SECOND").get_to(x.second);
}
void from_dump(const std::string &dump, AddressMapping &c)
{
json_t json_addressmapping = json_t::parse(dump).at("addressmapping");
json_addressmapping.get_to(c);
}
std::string dump(const AddressMapping &c, unsigned int indentation)
{
json_t json_addressmapping;
json_addressmapping["addressmapping"] = c;
return json_addressmapping.dump(indentation);
}
} // namespace DRAMSys::Config

View File

@@ -36,40 +36,47 @@
#ifndef DRAMSYSCONFIGURATION_ADDRESSMAPPING_H
#define DRAMSYSCONFIGURATION_ADDRESSMAPPING_H
#include "DRAMSys/config/ConfigUtil.h"
#include "DRAMSys/util/json.h"
#include <optional>
namespace DRAMSys::Config
{
const std::string addressMappingPath = "addressmapping";
struct XorPair
{
unsigned int first;
unsigned int second;
unsigned int FIRST;
unsigned int SECOND;
};
void to_json(json_t &j, const XorPair &x);
void from_json(const json_t &j, XorPair &x);
NLOHMANN_JSONIFY_ALL_THINGS(XorPair, FIRST, SECOND)
struct AddressMapping
{
std::optional<std::vector<unsigned int>> byteBits;
std::optional<std::vector<unsigned int>> columnBits;
std::optional<std::vector<unsigned int>> rowBits;
std::optional<std::vector<unsigned int>> bankBits;
std::optional<std::vector<unsigned int>> bankGroupBits;
std::optional<std::vector<unsigned int>> rankBits;
std::optional<std::vector<unsigned int>> channelBits;
std::optional<std::vector<XorPair>> xorBits;
static constexpr std::string_view KEY = "addressmapping";
static constexpr std::string_view SUB_DIR = "addressmapping";
std::optional<std::vector<unsigned int>> BYTE_BIT;
std::optional<std::vector<unsigned int>> COLUMN_BIT;
std::optional<std::vector<unsigned int>> ROW_BIT;
std::optional<std::vector<unsigned int>> BANK_BIT;
std::optional<std::vector<unsigned int>> BANKGROUP_BIT;
std::optional<std::vector<unsigned int>> RANK_BIT;
std::optional<std::vector<unsigned int>> PSEUDOCHANNEL_BIT;
std::optional<std::vector<unsigned int>> CHANNEL_BIT;
std::optional<std::vector<XorPair>> XOR;
};
void to_json(json_t &j, const AddressMapping &m);
void from_json(const json_t &j, AddressMapping &m);
void from_dump(const std::string &dump, AddressMapping &c);
std::string dump(const AddressMapping &c, unsigned int indentation = -1);
NLOHMANN_JSONIFY_ALL_THINGS(AddressMapping,
BYTE_BIT,
COLUMN_BIT,
ROW_BIT,
BANK_BIT,
BANKGROUP_BIT,
RANK_BIT,
PSEUDOCHANNEL_BIT,
CHANNEL_BIT,
XOR)
} // namespace Configuration

View File

@@ -1,116 +0,0 @@
/*
* Copyright (c) 2021, 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:
* Derek Christ
*/
#ifndef DRAMSYSCONFIGURATION_UTIL_H
#define DRAMSYSCONFIGURATION_UTIL_H
#include "DRAMSys/util/json.h"
#include <optional>
#include <utility>
namespace DRAMSys::Config
{
//using json_t = nlohmann::json;
// template <typename T>
// class Optional : public std::pair<T, bool>
// {
// public:
// Optional() : std::pair<T, bool>{{}, false}
// {
// }
// Optional(const T &v) : std::pair<T, bool>{v, true}
// {
// }
// bool isValid() const
// {
// return this->second;
// }
// const T &getValue() const
// {
// assert(this->second == true);
// return this->first;
// }
// void setValue(const T &v)
// {
// this->first = v;
// this->second = true;
// }
// void invalidate()
// {
// this->second = false;
// }
// /**
// * This methods only purpose is to make a optional type
// * valid so that it can be written to by reference.
// */
// T &setByReference()
// {
// this->second = true;
// return this->first;
// }
// };
template <typename T>
void invalidateEnum(T& value)
{
if (value.has_value() && value.value() == T::value_type::Invalid)
value.reset();
}
json_t get_config_json(const json_t& j, const std::string& configPath, const std::string& objectName);
inline void remove_null_values(json_t& j)
{
std::vector<std::string> keysToRemove;
for (const auto& element : j.items())
{
if (element.value() == nullptr)
keysToRemove.emplace_back(element.key());
}
std::for_each(keysToRemove.begin(), keysToRemove.end(), [&](const std::string& key) { j.erase(key); });
}
} // namespace DRAMSys::Config
#endif // DRAMSYSCONFIGURATION_UTIL_H

View File

@@ -35,62 +35,97 @@
#include "DRAMSysConfiguration.h"
#include "DRAMSys/config/ConfigUtil.h"
#include <fstream>
#include <iostream>
namespace DRAMSys::Config
{
std::string Configuration::resourceDirectory;
void to_json(json_t &j, const Configuration &c)
Configuration from_path(std::string_view path, std::string_view resourceDirectory)
{
j = json_t{{"addressmapping", c.addressMapping}, {"mcconfig", c.mcConfig}, {"memspec", c.memSpec},
{"simulationid", c.simulationId}, {"simconfig", c.simConfig}, {"tracesetup", c.traceSetup}};
std::ifstream file(path.data());
remove_null_values(j);
}
void from_json(const json_t &j, Configuration &c)
{
j.at("addressmapping").get_to(c.addressMapping);
j.at("mcconfig").get_to(c.mcConfig);
j.at("memspec").get_to(c.memSpec);
j.at("simulationid").get_to(c.simulationId);
j.at("simconfig").get_to(c.simConfig);
if (j.contains("tracesetup"))
j.at("tracesetup").get_to(c.traceSetup);
}
void from_dump(const std::string &dump, Configuration &c)
{
json_t json_simulation = json_t::parse(dump).at("simulation");
json_simulation.get_to(c);
}
std::string dump(const Configuration &c, unsigned int indentation)
{
json_t json_simulation;
json_simulation["simulation"] = c;
return json_simulation.dump(indentation);
}
Configuration from_path(const std::string &path, const std::string &resourceDirectory)
{
Configuration::resourceDirectory = resourceDirectory;
std::ifstream file(path);
if (file.is_open())
enum class SubConfig
{
json_t simulation = json_t::parse(file).at("simulation");
MemSpec,
AddressMapping,
McConfig,
SimConfig,
TraceSetup,
Unkown
} current_sub_config;
// This custom parser callback is responsible to swap out the paths to the sub-config json files
// with the actual json data.
std::function<bool(int depth, nlohmann::detail::parse_event_t event, json_t &parsed)>
parser_callback;
parser_callback =
[&parser_callback, &current_sub_config, resourceDirectory](
int depth, nlohmann::detail::parse_event_t event, json_t &parsed) -> bool {
using nlohmann::detail::parse_event_t;
if (depth != 2)
return true;
if (event == parse_event_t::key) {
assert(parsed.is_string());
if (parsed == MemSpec::KEY)
current_sub_config = SubConfig::MemSpec;
else if (parsed == AddressMapping::KEY)
current_sub_config = SubConfig::AddressMapping;
else if (parsed == McConfig::KEY)
current_sub_config = SubConfig::McConfig;
else if (parsed == SimConfig::KEY)
current_sub_config = SubConfig::SimConfig;
else if (parsed == TraceSetupConstants::KEY)
current_sub_config = SubConfig::TraceSetup;
else
current_sub_config = SubConfig::Unkown;
}
// In case we have an value (string) instead of an object, replace the value with the loaded
// json object.
if (event == parse_event_t::value && current_sub_config != SubConfig::Unkown) {
// Replace name of json file with actual json data
auto parse_json = [&parser_callback,
resourceDirectory](std::string_view base_dir,
std::string_view sub_config_key,
const std::string &filename) -> json_t {
std::filesystem::path path(resourceDirectory);
path /= base_dir;
path /= filename;
std::ifstream json_file(path);
if (!json_file.is_open())
throw std::runtime_error("Failed to open file " + std::string(path));
json_t json =
json_t::parse(json_file, parser_callback, true, true).at(sub_config_key);
return json;
};
if (current_sub_config == SubConfig::MemSpec)
parsed = parse_json(MemSpec::SUB_DIR, MemSpec::KEY, parsed);
else if (current_sub_config == SubConfig::AddressMapping)
parsed = parse_json(AddressMapping::SUB_DIR, AddressMapping::KEY, parsed);
else if (current_sub_config == SubConfig::McConfig)
parsed = parse_json(McConfig::SUB_DIR, McConfig::KEY, parsed);
else if (current_sub_config == SubConfig::SimConfig)
parsed = parse_json(SimConfig::SUB_DIR, SimConfig::KEY, parsed);
else if (current_sub_config == SubConfig::TraceSetup)
parsed = parse_json(TraceSetupConstants::SUB_DIR, TraceSetupConstants::KEY, parsed);
}
return true;
};
if (file.is_open()) {
json_t simulation = json_t::parse(file, parser_callback, true, true).at(Configuration::KEY);
return simulation.get<DRAMSys::Config::Configuration>();
}
else
{
throw std::runtime_error("Failed to open file " + path);
} else {
throw std::runtime_error("Failed to open file " + std::string(path));
}
}

View File

@@ -41,42 +41,45 @@
#include "DRAMSys/config/SimConfig.h"
#include "DRAMSys/config/TraceSetup.h"
#include "DRAMSys/config/memspec/MemSpec.h"
#include "DRAMSys/config/ConfigUtil.h"
#include <optional>
#include <string>
/**
* To support polymorphic configurations, a Json "type" tag is used
* to determine the correct type before further parsing.
*
* To support optional values, std::optional is used. The default
* values will be provided by DRAMSys itself.
*
* To achieve static polymorphism, std::variant is used.
* To achieve static polymorphism, std::variant is used. The concrete
* type is determined by the provided fields automatically.
*
* To achieve backwards compatibility, this library manipulates the json
* data type as it is parsed in to substitute paths to sub-configurations
* with the actual json object that is stored at this path.
*/
namespace DRAMSys::Config {
struct Configuration
{
AddressMapping addressMapping;
McConfig mcConfig;
MemSpec memSpec;
SimConfig simConfig;
std::string simulationId;
std::optional<TraceSetup> traceSetup;
static std::string resourceDirectory;
static constexpr std::string_view KEY = "simulation";
AddressMapping addressmapping;
McConfig mcconfig;
MemSpec memspec;
SimConfig simconfig;
std::string simulationid;
std::optional<TraceSetup> tracesetup;
};
void to_json(json &j, const Configuration &p);
void from_json(const json &j, Configuration &p);
NLOHMANN_JSONIFY_ALL_THINGS(Configuration,
addressmapping,
mcconfig,
memspec,
simconfig,
simulationid,
tracesetup)
void from_dump(const std::string &dump, Configuration &c);
std::string dump(const Configuration &c, unsigned int indentation = -1);
Configuration from_path(const std::string &path, const std::string &resourceDirectory = DRAMSYS_RESOURCE_DIR);
Configuration from_path(std::string_view path, std::string_view resourceDirectory = DRAMSYS_RESOURCE_DIR);
} // namespace DRAMSys::Config

View File

@@ -38,162 +38,36 @@
namespace DRAMSys::Config
{
void to_json(json_t &j, const McConfig &c)
void to_json(json_t &j, const RefreshPolicyType &r)
{
j = json_t{{"PagePolicy", c.pagePolicy},
{"Scheduler", c.scheduler},
{"HighWatermark", c.highWatermark},
{"LowWatermark", c.lowWatermark},
{"SchedulerBuffer", c.schedulerBuffer},
{"RequestBufferSize", c.requestBufferSize},
{"CmdMux", c.cmdMux},
{"RespQueue", c.respQueue},
{"RefreshPolicy", c.refreshPolicy},
{"RefreshMaxPostponed", c.refreshMaxPostponed},
{"RefreshMaxPulledin", c.refreshMaxPulledin},
{"PowerDownPolicy", c.powerDownPolicy},
{"Arbiter", c.arbiter},
{"MaxActiveTransactions", c.maxActiveTransactions},
{"RefreshManagement", c.refreshManagement},
{"ArbitrationDelayFw", c.arbitrationDelayFw},
{"ArbitrationDelayBw", c.arbitrationDelayBw},
{"ThinkDelayFw", c.thinkDelayFw},
{"ThinkDelayBw", c.thinkDelayBw},
{"PhyDelayFw", c.phyDelayFw},
{"PhyDelayBw", c.phyDelayBw},
{"BlockingReadDelay", c.blockingReadDelay},
{"BlockingWriteDelay", c.blockingWriteDelay}};
remove_null_values(j);
}
void from_json(const json_t &j, McConfig &c)
{
json_t j_mcconfig = get_config_json(j, mcConfigPath, "mcconfig");
if (j_mcconfig.contains("PagePolicy"))
j_mcconfig.at("PagePolicy").get_to(c.pagePolicy);
if (j_mcconfig.contains("Scheduler"))
j_mcconfig.at("Scheduler").get_to(c.scheduler);
if (j_mcconfig.contains("HighWatermark"))
j_mcconfig.at("HighWatermark").get_to(c.highWatermark);
if (j_mcconfig.contains("LowWatermark"))
j_mcconfig.at("LowWatermark").get_to(c.lowWatermark);
if (j_mcconfig.contains("SchedulerBuffer"))
j_mcconfig.at("SchedulerBuffer").get_to(c.schedulerBuffer);
if (j_mcconfig.contains("RequestBufferSize"))
j_mcconfig.at("RequestBufferSize").get_to(c.requestBufferSize);
if (j_mcconfig.contains("CmdMux"))
j_mcconfig.at("CmdMux").get_to(c.cmdMux);
if (j_mcconfig.contains("RespQueue"))
j_mcconfig.at("RespQueue").get_to(c.respQueue);
if (j_mcconfig.contains("RefreshPolicy"))
j_mcconfig.at("RefreshPolicy").get_to(c.refreshPolicy);
if (j_mcconfig.contains("RefreshMaxPostponed"))
j_mcconfig.at("RefreshMaxPostponed").get_to(c.refreshMaxPostponed);
if (j_mcconfig.contains("RefreshMaxPulledin"))
j_mcconfig.at("RefreshMaxPulledin").get_to(c.refreshMaxPulledin);
if (j_mcconfig.contains("PowerDownPolicy"))
j_mcconfig.at("PowerDownPolicy").get_to(c.powerDownPolicy);
if (j_mcconfig.contains("Arbiter"))
j_mcconfig.at("Arbiter").get_to(c.arbiter);
if (j_mcconfig.contains("MaxActiveTransactions"))
j_mcconfig.at("MaxActiveTransactions").get_to(c.maxActiveTransactions);
if (j_mcconfig.contains("RefreshManagement"))
j_mcconfig.at("RefreshManagement").get_to(c.refreshManagement);
if (j_mcconfig.contains("ArbitrationDelayFw"))
j_mcconfig.at("ArbitrationDelayFw").get_to(c.arbitrationDelayFw);
if (j_mcconfig.contains("ArbitrationDelayBw"))
j_mcconfig.at("ArbitrationDelayBw").get_to(c.arbitrationDelayBw);
if (j_mcconfig.contains("ThinkDelayFw"))
j_mcconfig.at("ThinkDelayFw").get_to(c.thinkDelayFw);
if (j_mcconfig.contains("ThinkDelayBw"))
j_mcconfig.at("ThinkDelayBw").get_to(c.thinkDelayBw);
if (j_mcconfig.contains("PhyDelayFw"))
j_mcconfig.at("PhyDelayFw").get_to(c.phyDelayFw);
if (j_mcconfig.contains("PhyDelayBw"))
j_mcconfig.at("PhyDelayBw").get_to(c.phyDelayBw);
if (j_mcconfig.contains("BlockingReadDelay"))
j_mcconfig.at("BlockingReadDelay").get_to(c.blockingReadDelay);
if (j_mcconfig.contains("BlockingWriteDelay"))
j_mcconfig.at("BlockingWriteDelay").get_to(c.blockingWriteDelay);
invalidateEnum(c.pagePolicy);
invalidateEnum(c.scheduler);
invalidateEnum(c.schedulerBuffer);
invalidateEnum(c.cmdMux);
invalidateEnum(c.respQueue);
invalidateEnum(c.refreshPolicy);
invalidateEnum(c.respQueue);
invalidateEnum(c.powerDownPolicy);
invalidateEnum(c.arbiter);
}
void to_json(json_t &j, const RefreshPolicy &r)
{
if (r == RefreshPolicy::NoRefresh)
if (r == RefreshPolicyType::NoRefresh)
j = "NoRefresh";
else if (r == RefreshPolicy::AllBank)
else if (r == RefreshPolicyType::AllBank)
j = "AllBank";
else if (r == RefreshPolicy::PerBank)
else if (r == RefreshPolicyType::PerBank)
j = "PerBank";
else if (r == RefreshPolicy::Per2Bank)
else if (r == RefreshPolicyType::Per2Bank)
j = "Per2Bank";
else if (r == RefreshPolicy::SameBank)
else if (r == RefreshPolicyType::SameBank)
j = "SameBank";
else
j = nullptr;
}
void from_json(const json_t &j, RefreshPolicy &r)
void from_json(const json_t &j, RefreshPolicyType &r)
{
if (j == "NoRefresh")
r = RefreshPolicy::NoRefresh;
r = RefreshPolicyType::NoRefresh;
else if (j == "AllBank" || j == "Rankwise")
r = RefreshPolicy::AllBank;
r = RefreshPolicyType::AllBank;
else if (j == "PerBank" || j == "Bankwise")
r = RefreshPolicy::PerBank;
r = RefreshPolicyType::PerBank;
else if (j == "SameBank" || j == "Groupwise")
r = RefreshPolicy::SameBank;
r = RefreshPolicyType::SameBank;
else if (j == "Per2Bank")
r = RefreshPolicy::Per2Bank;
r = RefreshPolicyType::Per2Bank;
else
r = RefreshPolicy::Invalid;
}
void from_dump(const std::string &dump, McConfig &c)
{
json_t json_mcconfig = json_t::parse(dump).at("mcconfig");
json_mcconfig.get_to(c);
}
std::string dump(const McConfig &c, unsigned int indentation)
{
json_t json_mcconfig;
json_mcconfig["mcconfig"] = c;
return json_mcconfig.dump(indentation);
r = RefreshPolicyType::Invalid;
}
} // namespace DRAMSys::Config

View File

@@ -36,7 +36,7 @@
#ifndef DRAMSYSCONFIGURATION_MCCONFIG_H
#define DRAMSYSCONFIGURATION_MCCONFIG_H
#include "DRAMSys/config/ConfigUtil.h"
#include "DRAMSys/util/json.h"
#include <optional>
#include <utility>
@@ -44,9 +44,8 @@
namespace DRAMSys::Config
{
const std::string mcConfigPath = "mcconfig";
enum class PagePolicy
enum class PagePolicyType
{
Open,
OpenAdaptive,
@@ -55,15 +54,15 @@ enum class PagePolicy
Invalid = -1
};
NLOHMANN_JSON_SERIALIZE_ENUM(PagePolicy, {
{PagePolicy::Invalid, nullptr},
{PagePolicy::Open, "Open"},
{PagePolicy::OpenAdaptive, "OpenAdaptive"},
{PagePolicy::Closed, "Closed"},
{PagePolicy::ClosedAdaptive, "ClosedAdaptive"},
NLOHMANN_JSON_SERIALIZE_ENUM(PagePolicyType, {
{PagePolicyType::Invalid, nullptr},
{PagePolicyType::Open, "Open"},
{PagePolicyType::OpenAdaptive, "OpenAdaptive"},
{PagePolicyType::Closed, "Closed"},
{PagePolicyType::ClosedAdaptive, "ClosedAdaptive"},
})
enum class Scheduler
enum class SchedulerType
{
Fifo,
FrFcfs,
@@ -73,14 +72,14 @@ enum class Scheduler
Invalid = -1
};
NLOHMANN_JSON_SERIALIZE_ENUM(Scheduler, {{Scheduler::Invalid, nullptr},
{Scheduler::Fifo, "Fifo"},
{Scheduler::FrFcfs, "FrFcfs"},
{Scheduler::FrFcfsGrp, "FrFcfsGrp"},
{Scheduler::GrpFrFcfs, "GrpFrFcfs"},
{Scheduler::GrpFrFcfsWm, "GrpFrFcfsWm"}})
NLOHMANN_JSON_SERIALIZE_ENUM(SchedulerType, {{SchedulerType::Invalid, nullptr},
{SchedulerType::Fifo, "Fifo"},
{SchedulerType::FrFcfs, "FrFcfs"},
{SchedulerType::FrFcfsGrp, "FrFcfsGrp"},
{SchedulerType::GrpFrFcfs, "GrpFrFcfs"},
{SchedulerType::GrpFrFcfsWm, "GrpFrFcfsWm"}})
enum class SchedulerBuffer
enum class SchedulerBufferType
{
Bankwise,
ReadWrite,
@@ -88,33 +87,33 @@ enum class SchedulerBuffer
Invalid = -1
};
NLOHMANN_JSON_SERIALIZE_ENUM(SchedulerBuffer, {{SchedulerBuffer::Invalid, nullptr},
{SchedulerBuffer::Bankwise, "Bankwise"},
{SchedulerBuffer::ReadWrite, "ReadWrite"},
{SchedulerBuffer::Shared, "Shared"}})
NLOHMANN_JSON_SERIALIZE_ENUM(SchedulerBufferType, {{SchedulerBufferType::Invalid, nullptr},
{SchedulerBufferType::Bankwise, "Bankwise"},
{SchedulerBufferType::ReadWrite, "ReadWrite"},
{SchedulerBufferType::Shared, "Shared"}})
enum class CmdMux
enum class CmdMuxType
{
Oldest,
Strict,
Invalid = -1
};
NLOHMANN_JSON_SERIALIZE_ENUM(CmdMux,
{{CmdMux::Invalid, nullptr}, {CmdMux::Oldest, "Oldest"}, {CmdMux::Strict, "Strict"}})
NLOHMANN_JSON_SERIALIZE_ENUM(CmdMuxType,
{{CmdMuxType::Invalid, nullptr}, {CmdMuxType::Oldest, "Oldest"}, {CmdMuxType::Strict, "Strict"}})
enum class RespQueue
enum class RespQueueType
{
Fifo,
Reorder,
Invalid = -1
};
NLOHMANN_JSON_SERIALIZE_ENUM(RespQueue, {{RespQueue::Invalid, nullptr},
{RespQueue::Fifo, "Fifo"},
{RespQueue::Reorder, "Reorder"}})
NLOHMANN_JSON_SERIALIZE_ENUM(RespQueueType, {{RespQueueType::Invalid, nullptr},
{RespQueueType::Fifo, "Fifo"},
{RespQueueType::Reorder, "Reorder"}})
enum class RefreshPolicy
enum class RefreshPolicyType
{
NoRefresh,
AllBank,
@@ -124,18 +123,18 @@ enum class RefreshPolicy
Invalid = -1
};
enum class PowerDownPolicy
enum class PowerDownPolicyType
{
NoPowerDown,
Staggered,
Invalid = -1
};
NLOHMANN_JSON_SERIALIZE_ENUM(PowerDownPolicy, {{PowerDownPolicy::Invalid, nullptr},
{PowerDownPolicy::NoPowerDown, "NoPowerDown"},
{PowerDownPolicy::Staggered, "Staggered"}})
NLOHMANN_JSON_SERIALIZE_ENUM(PowerDownPolicyType, {{PowerDownPolicyType::Invalid, nullptr},
{PowerDownPolicyType::NoPowerDown, "NoPowerDown"},
{PowerDownPolicyType::Staggered, "Staggered"}})
enum class Arbiter
enum class ArbiterType
{
Simple,
Fifo,
@@ -143,46 +142,71 @@ enum class Arbiter
Invalid = -1
};
NLOHMANN_JSON_SERIALIZE_ENUM(Arbiter, {{Arbiter::Invalid, nullptr},
{Arbiter::Simple, "Simple"},
{Arbiter::Fifo, "Fifo"},
{Arbiter::Reorder, "Reorder"}})
NLOHMANN_JSON_SERIALIZE_ENUM(ArbiterType, {{ArbiterType::Invalid, nullptr},
{ArbiterType::Simple, "Simple"},
{ArbiterType::Fifo, "Fifo"},
{ArbiterType::Reorder, "Reorder"}})
struct McConfig
{
std::optional<PagePolicy> pagePolicy;
std::optional<Scheduler> scheduler;
std::optional<unsigned int> highWatermark;
std::optional<unsigned int> lowWatermark;
std::optional<SchedulerBuffer> schedulerBuffer;
std::optional<unsigned int> requestBufferSize;
std::optional<CmdMux> cmdMux;
std::optional<RespQueue> respQueue;
std::optional<RefreshPolicy> refreshPolicy;
std::optional<unsigned int> refreshMaxPostponed;
std::optional<unsigned int> refreshMaxPulledin;
std::optional<PowerDownPolicy> powerDownPolicy;
std::optional<Arbiter> arbiter;
std::optional<unsigned int> maxActiveTransactions;
std::optional<bool> refreshManagement;
std::optional<unsigned int> arbitrationDelayFw;
std::optional<unsigned int> arbitrationDelayBw;
std::optional<unsigned int> thinkDelayFw;
std::optional<unsigned int> thinkDelayBw;
std::optional<unsigned int> phyDelayFw;
std::optional<unsigned int> phyDelayBw;
std::optional<unsigned int> blockingReadDelay;
std::optional<unsigned int> blockingWriteDelay;
static constexpr std::string_view KEY = "mcconfig";
static constexpr std::string_view SUB_DIR = "mcconfig";
std::optional<PagePolicyType> PagePolicy;
std::optional<SchedulerType> Scheduler;
std::optional<unsigned int> HighWatermark;
std::optional<unsigned int> LowWatermark;
std::optional<SchedulerBufferType> SchedulerBuffer;
std::optional<unsigned int> RequestBufferSize;
std::optional<CmdMuxType> CmdMux;
std::optional<RespQueueType> RespQueue;
std::optional<RefreshPolicyType> RefreshPolicy;
std::optional<unsigned int> RefreshMaxPostponed;
std::optional<unsigned int> RefreshMaxPulledin;
std::optional<PowerDownPolicyType> PowerDownPolicy;
std::optional<ArbiterType> Arbiter;
std::optional<unsigned int> MaxActiveTransactions;
std::optional<bool> RefreshManagement;
std::optional<unsigned int> ArbitrationDelayFw;
std::optional<unsigned int> ArbitrationDelayBw;
std::optional<unsigned int> ThinkDelayFw;
std::optional<unsigned int> ThinkDelayBw;
std::optional<unsigned int> PhyDelayFw;
std::optional<unsigned int> PhyDelayBw;
std::optional<unsigned int> BlockingReadDelay;
std::optional<unsigned int> BlockingWriteDelay;
};
void to_json(json_t &j, const McConfig &c);
void from_json(const json_t &j, McConfig &c);
NLOHMANN_JSONIFY_ALL_THINGS(McConfig,
PagePolicy,
Scheduler,
HighWatermark,
LowWatermark,
SchedulerBuffer,
RequestBufferSize,
CmdMux,
RespQueue,
RefreshPolicy,
RefreshMaxPostponed,
RefreshMaxPulledin,
PowerDownPolicy,
Arbiter,
MaxActiveTransactions,
RefreshManagement,
ArbitrationDelayFw,
ArbitrationDelayBw,
ThinkDelayFw,
ThinkDelayBw,
PhyDelayFw,
PhyDelayBw,
BlockingReadDelay,
BlockingWriteDelay)
void to_json(json_t &j, const RefreshPolicy &r);
void from_json(const json_t &j, RefreshPolicy &r);
void to_json(json_t &j, const RefreshPolicyType &r);
void from_json(const json_t &j, RefreshPolicyType &r);
void from_dump(const std::string &dump, McConfig &c);
std::string dump(const McConfig &c, unsigned int indentation = -1);
// void from_dump(const std::string &dump, McConfig &c);
// std::string dump(const McConfig &c, unsigned int indentation = -1);
} // namespace Configuration

View File

@@ -1,121 +0,0 @@
/*
* Copyright (c) 2021, 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:
* Derek Christ
*/
#include "SimConfig.h"
namespace DRAMSys::Config
{
void to_json(json_t &j, const SimConfig &c)
{
j = json_t{{"AddressOffset", c.addressOffset},
{"CheckTLM2Protocol", c.checkTLM2Protocol},
{"DatabaseRecording", c.databaseRecording},
{"Debug", c.debug},
{"EnableWindowing", c.enableWindowing},
{"ErrorCSVFile", c.errorCsvFile},
{"ErrorChipSeed", c.errorChipSeed},
{"PowerAnalysis", c.powerAnalysis},
{"SimulationName", c.simulationName},
{"SimulationProgressBar", c.simulationProgressBar},
{"StoreMode", c.storeMode},
{"ThermalSimulation", c.thermalSimulation},
{"UseMalloc", c.useMalloc},
{"WindowSize", c.windowSize}};
}
void from_json(const json_t &j, SimConfig &c)
{
json_t j_simconfig = get_config_json(j, simConfigPath, "simconfig");
if (j_simconfig.contains("AddressOffset"))
j_simconfig.at("AddressOffset").get_to(c.addressOffset);
if (j_simconfig.contains("CheckTLM2Protocol"))
j_simconfig.at("CheckTLM2Protocol").get_to(c.checkTLM2Protocol);
if (j_simconfig.contains("DatabaseRecording"))
j_simconfig.at("DatabaseRecording").get_to(c.databaseRecording);
if (j_simconfig.contains("Debug"))
j_simconfig.at("Debug").get_to(c.debug);
if (j_simconfig.contains("EnableWindowing"))
j_simconfig.at("EnableWindowing").get_to(c.enableWindowing);
if (j_simconfig.contains("ErrorCSVFile"))
j_simconfig.at("ErrorCSVFile").get_to(c.errorCsvFile);
if (j_simconfig.contains("ErrorChipSeed"))
j_simconfig.at("ErrorChipSeed").get_to(c.errorChipSeed);
if (j_simconfig.contains("PowerAnalysis"))
j_simconfig.at("PowerAnalysis").get_to(c.powerAnalysis);
if (j_simconfig.contains("SimulationName"))
j_simconfig.at("SimulationName").get_to(c.simulationName);
if (j_simconfig.contains("SimulationProgressBar"))
j_simconfig.at("SimulationProgressBar").get_to(c.simulationProgressBar);
if (j_simconfig.contains("StoreMode"))
j_simconfig.at("StoreMode").get_to(c.storeMode);
if (j_simconfig.contains("ThermalSimulation"))
j_simconfig.at("ThermalSimulation").get_to(c.thermalSimulation);
if (j_simconfig.contains("UseMalloc"))
j_simconfig.at("UseMalloc").get_to(c.useMalloc);
if (j_simconfig.contains("WindowSize"))
j_simconfig.at("WindowSize").get_to(c.windowSize);
invalidateEnum(c.storeMode);
}
void from_dump(const std::string &dump, SimConfig &c)
{
json_t json_simconfig = json_t::parse(dump).at("simconfig");
json_simconfig.get_to(c);
}
std::string dump(const SimConfig &c, unsigned int indentation)
{
json_t json_simconfig;
json_simconfig["simconfig"] = c;
return json_simconfig.dump(indentation);
}
} // namespace DRAMSys::Config

View File

@@ -36,15 +36,14 @@
#ifndef DRAMSYSCONFIGURATION_SIMCONFIG_H
#define DRAMSYSCONFIGURATION_SIMCONFIG_H
#include "DRAMSys/config/ConfigUtil.h"
#include "DRAMSys/util/json.h"
#include <optional>
namespace DRAMSys::Config
{
const std::string simConfigPath = "simconfig";
enum class StoreMode
enum class StoreModeType
{
NoStorage,
Store,
@@ -52,34 +51,47 @@ enum class StoreMode
Invalid = -1
};
NLOHMANN_JSON_SERIALIZE_ENUM(StoreMode, {{StoreMode::Invalid, nullptr},
{StoreMode::NoStorage, "NoStorage"},
{StoreMode::Store, "Store"},
{StoreMode::ErrorModel, "ErrorModel"}})
NLOHMANN_JSON_SERIALIZE_ENUM(StoreModeType, {{StoreModeType::Invalid, nullptr},
{StoreModeType::NoStorage, "NoStorage"},
{StoreModeType::Store, "Store"},
{StoreModeType::ErrorModel, "ErrorModel"}})
struct SimConfig
{
std::optional<uint64_t> addressOffset;
std::optional<bool> checkTLM2Protocol;
std::optional<bool> databaseRecording;
std::optional<bool> debug;
std::optional<bool> enableWindowing;
std::optional<std::string> errorCsvFile;
std::optional<unsigned int> errorChipSeed;
std::optional<bool> powerAnalysis;
std::optional<std::string> simulationName;
std::optional<bool> simulationProgressBar;
std::optional<StoreMode> storeMode;
std::optional<bool> thermalSimulation;
std::optional<bool> useMalloc;
std::optional<unsigned int> windowSize;
static constexpr std::string_view KEY = "simconfig";
static constexpr std::string_view SUB_DIR = "simconfig";
std::optional<uint64_t> AddressOffset;
std::optional<bool> CheckTLM2Protocol;
std::optional<bool> DatabaseRecording;
std::optional<bool> Debug;
std::optional<bool> EnableWindowing;
std::optional<std::string> ErrorCSVFile;
std::optional<unsigned int> ErrorChipSeed;
std::optional<bool> PowerAnalysis;
std::optional<std::string> SimulationName;
std::optional<bool> SimulationProgressBar;
std::optional<StoreModeType> StoreMode;
std::optional<bool> ThermalSimulation;
std::optional<bool> UseMalloc;
std::optional<unsigned int> WindowSize;
};
void to_json(json_t &j, const SimConfig &c);
void from_json(const json_t &j, SimConfig &c);
void from_dump(const std::string &dump, SimConfig &c);
std::string dump(const SimConfig &c, unsigned int indentation = -1);
NLOHMANN_JSONIFY_ALL_THINGS(SimConfig,
AddressOffset,
CheckTLM2Protocol,
DatabaseRecording,
Debug,
EnableWindowing,
ErrorCSVFile,
ErrorChipSeed,
PowerAnalysis,
SimulationName,
SimulationProgressBar,
StoreMode,
ThermalSimulation,
UseMalloc,
WindowSize)
} // namespace Configuration

View File

@@ -1,314 +0,0 @@
/*
* Copyright (c) 2021, 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:
* Derek Christ
*/
#include "TraceSetup.h"
#include <variant>
namespace DRAMSys::Config
{
TrafficInitiator::~TrafficInitiator()
{
}
TraceGeneratorState::~TraceGeneratorState()
{
}
void to_json(json_t &j, const TraceSetup &c)
{
// Create an empty array
j = json_t::array();
for (const auto &initiator : c.initiators)
{
json_t initiator_j;
std::visit(
[&initiator_j](auto &&initiator)
{
initiator_j["name"] = initiator.name;
initiator_j["clkMhz"] = initiator.clkMhz;
initiator_j["maxPendingReadRequests"] = initiator.maxPendingReadRequests;
initiator_j["maxPendingWriteRequests"] = initiator.maxPendingWriteRequests;
using T = std::decay_t<decltype(initiator)>;
if constexpr (std::is_same_v<T, TraceGenerator>)
{
initiator_j["type"] = "generator";
initiator_j["seed"] = initiator.seed;
initiator_j["maxTransactions"] = initiator.maxTransactions;
initiator_j["idleUntil"] = initiator.idleUntil;
// When there are less than 2 states, flatten out the json.
if (initiator.states.size() == 1)
{
std::visit(
[&initiator_j](auto &&state)
{
using U = std::decay_t<decltype(state)>;
if constexpr (std::is_same_v<U, TraceGeneratorTrafficState>)
{
initiator_j["numRequests"] = state.numRequests;
initiator_j["rwRatio"] = state.rwRatio;
initiator_j["addressDistribution"] = state.addressDistribution;
initiator_j["addressIncrement"] = state.addressIncrement;
initiator_j["minAddress"] = state.minAddress;
initiator_j["maxAddress"] = state.maxAddress;
initiator_j["clksPerRequest"] = state.clksPerRequest;
initiator_j["notify"] = state.notify;
}
else // if constexpr (std::is_same_v<U, TraceGeneratorIdleState>)
{
initiator_j["idleClks"] = state.idleClks;
}
},
initiator.states.at(0));
}
else
{
json_t states_j = json_t::array();
for (const auto &state : initiator.states)
{
json_t state_j;
state_j["id"] = state.first;
std::visit(
[&state_j](auto &&state)
{
using U = std::decay_t<decltype(state)>;
if constexpr (std::is_same_v<U, TraceGeneratorTrafficState>)
{
state_j["numRequests"] = state.numRequests;
state_j["rwRatio"] = state.rwRatio;
state_j["addressDistribution"] = state.addressDistribution;
state_j["addressIncrement"] = state.addressIncrement;
state_j["minAddress"] = state.minAddress;
state_j["maxAddress"] = state.maxAddress;
state_j["clksPerRequest"] = state.clksPerRequest;
state_j["notify"] = state.notify;
}
else // if constexpr (std::is_same_v<U, TraceGeneratorIdleState>)
{
state_j["idleClks"] = state.idleClks;
}
},
state.second);
remove_null_values(state_j);
states_j.insert(states_j.end(), state_j);
}
initiator_j["states"] = states_j;
json_t transitions_j = json_t::array();
for (const auto &transition : initiator.transitions)
{
json_t transition_j;
transition_j["from"] = transition.first;
transition_j["to"] = transition.second.to;
transition_j["probability"] = transition.second.probability;
remove_null_values(transition_j);
transitions_j.insert(transitions_j.end(), transition_j);
}
initiator_j["transitions"] = transitions_j;
}
}
else if constexpr (std::is_same_v<T, TraceHammer>)
{
initiator_j["type"] = "hammer";
initiator_j["numRequests"] = initiator.numRequests;
initiator_j["rowIncrement"] = initiator.rowIncrement;
}
else // if constexpr (std::is_same_v<T, TracePlayer>)
{
initiator_j["type"] = "player";
}
},
initiator);
remove_null_values(initiator_j);
j.insert(j.end(), initiator_j);
}
}
void from_json(const json_t&j, TraceSetup &c)
{
for (const auto &initiator_j : j)
{
// Default to Player, when not specified
TrafficInitiatorType type = initiator_j.value("type", TrafficInitiatorType::Player);
std::variant<TracePlayer, TraceGenerator, TraceHammer> initiator;
if (type == TrafficInitiatorType::Player)
{
initiator = TracePlayer{};
}
else if (type == TrafficInitiatorType::Generator)
{
TraceGenerator generator;
auto process_state = [](const json_t&state_j)
-> std::pair<unsigned int, std::variant<TraceGeneratorIdleState, TraceGeneratorTrafficState>>
{
std::variant<TraceGeneratorIdleState, TraceGeneratorTrafficState> state;
if (state_j.contains("idleClks"))
{
// Idle state
TraceGeneratorIdleState idleState;
state_j.at("idleClks").get_to(idleState.idleClks);
state = std::move(idleState);
}
else
{
// Traffic state
TraceGeneratorTrafficState trafficState;
state_j.at("numRequests").get_to(trafficState.numRequests);
state_j.at("rwRatio").get_to(trafficState.rwRatio);
state_j.at("addressDistribution").get_to(trafficState.addressDistribution);
if (state_j.contains("addressIncrement"))
state_j.at("addressIncrement").get_to(trafficState.addressIncrement);
if (state_j.contains("minAddress"))
state_j.at("minAddress").get_to(trafficState.minAddress);
if (state_j.contains("maxAddress"))
state_j.at("maxAddress").get_to(trafficState.maxAddress);
if (state_j.contains("clksPerRequest"))
state_j.at("clksPerRequest").get_to(trafficState.clksPerRequest);
if (state_j.contains("notify"))
state_j.at("notify").get_to(trafficState.notify);
state = std::move(trafficState);
}
// Default to 0
unsigned int id = 0;
if (state_j.contains("id"))
id = state_j.at("id");
return {id, std::move(state)};
};
if (initiator_j.contains("states"))
{
for (const auto &state_j : initiator_j.at("states"))
{
auto state = process_state(state_j);
generator.states[state.first] = std::move(state.second);
}
for (const auto &transition_j : initiator_j.at("transitions"))
{
TraceGeneratorStateTransition transition;
unsigned int from = transition_j.at("from");
transition.to = transition_j.at("to");
transition.probability = transition_j.at("probability");
generator.transitions.emplace(from, transition);
}
}
else // Only one state will be created
{
auto state = process_state(initiator_j);
generator.states[state.first] = std::move(state.second);
}
if (initiator_j.contains("seed"))
initiator_j.at("seed").get_to(generator.seed);
if (initiator_j.contains("maxTransactions"))
initiator_j.at("maxTransactions").get_to(generator.maxTransactions);
if (initiator_j.contains("dataLength"))
initiator_j.at("dataLength").get_to(generator.dataLength);
if (initiator_j.contains("idleUntil"))
initiator_j.at("idleUntil").get_to(generator.idleUntil);
initiator = generator;
}
else if (type == TrafficInitiatorType::Hammer)
{
TraceHammer hammer;
initiator_j.at("numRequests").get_to(hammer.numRequests);
initiator_j.at("rowIncrement").get_to(hammer.rowIncrement);
initiator = hammer;
}
std::visit(
[&initiator_j](auto &&initiator)
{
initiator_j.at("name").get_to(initiator.name);
initiator_j.at("clkMhz").get_to(initiator.clkMhz);
if (initiator_j.contains("maxPendingReadRequests"))
initiator_j.at("maxPendingReadRequests").get_to(initiator.maxPendingReadRequests);
if (initiator_j.contains("maxPendingWriteRequests"))
initiator_j.at("maxPendingWriteRequests").get_to(initiator.maxPendingWriteRequests);
},
initiator);
c.initiators.emplace_back(std::move(initiator));
}
}
void from_dump(const std::string &dump, TraceSetup &c)
{
json_t json_tracesetup = json_t::parse(dump).at("tracesetup");
json_tracesetup.get_to(c);
}
std::string dump(const TraceSetup &c, unsigned int indentation)
{
json_t json_tracesetup;
json_tracesetup["tracesetup"] = c;
return json_tracesetup.dump(indentation);
}
} // namespace DRAMSys::Config

View File

@@ -36,7 +36,7 @@
#ifndef DRAMSYSCONFIGURATION_TRACESETUP_H
#define DRAMSYSCONFIGURATION_TRACESETUP_H
#include "DRAMSys/config/ConfigUtil.h"
#include "DRAMSys/util/json.h"
#include <optional>
#include <variant>
@@ -68,74 +68,141 @@ NLOHMANN_JSON_SERIALIZE_ENUM(AddressDistribution, {{AddressDistribution::Invalid
{AddressDistribution::Random, "random"},
{AddressDistribution::Sequential, "sequential"}})
struct TrafficInitiator
struct TracePlayer
{
virtual ~TrafficInitiator() = 0;
uint64_t clkMhz;
std::string name;
std::optional<unsigned int> maxPendingReadRequests;
std::optional<unsigned int> maxPendingWriteRequests;
};
struct TracePlayer : public TrafficInitiator
{
};
NLOHMANN_JSONIFY_ALL_THINGS(
TracePlayer, clkMhz, name, maxPendingReadRequests, maxPendingWriteRequests)
struct TraceGeneratorState
struct TrafficGeneratorActiveState
{
virtual ~TraceGeneratorState() = 0;
};
unsigned int id;
struct TraceGeneratorTrafficState : public TraceGeneratorState
{
uint64_t numRequests;
double rwRatio;
AddressDistribution addressDistribution;
std::optional<uint64_t> addressIncrement;
std::optional<uint64_t> minAddress;
std::optional<uint64_t> maxAddress;
std::optional<uint64_t> clksPerRequest;
std::optional<std::string> notify;
};
struct TraceGeneratorIdleState : public TraceGeneratorState
NLOHMANN_JSONIFY_ALL_THINGS(TrafficGeneratorActiveState,
id,
numRequests,
rwRatio,
addressDistribution,
addressIncrement,
minAddress,
maxAddress)
struct TrafficGeneratorIdleState
{
unsigned int id;
uint64_t idleClks;
};
struct TraceGeneratorStateTransition
NLOHMANN_JSONIFY_ALL_THINGS(TrafficGeneratorIdleState, id, idleClks)
struct TrafficGeneratorStateTransition
{
unsigned int from;
unsigned int to;
float probability;
};
struct TraceGenerator : public TrafficInitiator
NLOHMANN_JSONIFY_ALL_THINGS(TrafficGeneratorStateTransition, from, to, probability)
struct TrafficGenerator
{
uint64_t clkMhz;
std::string name;
std::optional<unsigned int> maxPendingReadRequests;
std::optional<unsigned int> maxPendingWriteRequests;
std::optional<uint64_t> seed;
std::optional<uint64_t> maxTransactions;
std::optional<unsigned> dataLength;
std::map<unsigned int, std::variant<TraceGeneratorIdleState, TraceGeneratorTrafficState>> states;
std::multimap<unsigned int, TraceGeneratorStateTransition> transitions;
std::optional<std::string> idleUntil;
std::optional<unsigned> dataAlignment;
uint64_t numRequests;
double rwRatio;
AddressDistribution addressDistribution;
std::optional<uint64_t> addressIncrement;
std::optional<uint64_t> minAddress;
std::optional<uint64_t> maxAddress;
};
struct TraceHammer : public TrafficInitiator
NLOHMANN_JSONIFY_ALL_THINGS(TrafficGenerator,
clkMhz,
name,
maxPendingReadRequests,
maxPendingWriteRequests,
seed,
maxTransactions,
dataLength,
dataAlignment,
numRequests,
rwRatio,
addressDistribution,
addressIncrement,
minAddress,
maxAddress)
struct TrafficGeneratorStateMachine
{
uint64_t clkMhz;
std::string name;
std::optional<unsigned int> maxPendingReadRequests;
std::optional<unsigned int> maxPendingWriteRequests;
std::optional<uint64_t> seed;
std::optional<uint64_t> maxTransactions;
std::optional<unsigned> dataLength;
std::optional<unsigned> dataAlignment;
std::vector<std::variant<TrafficGeneratorActiveState, TrafficGeneratorIdleState>> states;
std::vector<TrafficGeneratorStateTransition> transitions;
};
NLOHMANN_JSONIFY_ALL_THINGS(TrafficGeneratorStateMachine,
clkMhz,
name,
maxPendingReadRequests,
maxPendingWriteRequests,
seed,
maxTransactions,
dataLength,
dataAlignment,
states,
transitions)
struct RowHammer
{
uint64_t clkMhz;
std::string name;
std::optional<unsigned int> maxPendingReadRequests;
std::optional<unsigned int> maxPendingWriteRequests;
uint64_t numRequests;
uint64_t rowIncrement;
};
struct TraceSetup
NLOHMANN_JSONIFY_ALL_THINGS(
RowHammer, clkMhz, name, maxPendingReadRequests, maxPendingWriteRequests, numRequests, rowIncrement)
struct TraceSetupConstants
{
std::vector<std::variant<TracePlayer, TraceGenerator, TraceHammer>> initiators;
static constexpr std::string_view KEY = "tracesetup";
static constexpr std::string_view SUB_DIR = "tracesetup";
};
void to_json(json_t &j, const TraceSetup &c);
void from_json(const json_t &j, TraceSetup &c);
void from_dump(const std::string &dump, TraceSetup &c);
std::string dump(const TraceSetup &c, unsigned int indentation = -1);
using TraceSetup = std::vector<
std::variant<TracePlayer, TrafficGenerator, TrafficGeneratorStateMachine, RowHammer>>;
} // namespace Configuration

View File

@@ -38,7 +38,7 @@
namespace DRAMSys::Config
{
void to_json(json_t &j, const MemArchitectureSpec &c)
void to_json(json_t &j, const MemArchitectureSpecType &c)
{
j = json_t{};
@@ -48,7 +48,7 @@ void to_json(json_t &j, const MemArchitectureSpec &c)
}
}
void from_json(const json_t &j, MemArchitectureSpec &c)
void from_json(const json_t &j, MemArchitectureSpecType &c)
{
for (const auto &entry : j.items())
{

View File

@@ -36,20 +36,20 @@
#ifndef DRAMSYSCONFIGURATION_MEMARCHITECTURESPEC_H
#define DRAMSYSCONFIGURATION_MEMARCHITECTURESPEC_H
#include "DRAMSys/config/ConfigUtil.h"
#include "DRAMSys/util/json.h"
#include <unordered_map>
namespace DRAMSys::Config
{
struct MemArchitectureSpec
struct MemArchitectureSpecType
{
std::unordered_map<std::string, unsigned int> entries;
};
void to_json(json_t &j, const MemArchitectureSpec &c);
void from_json(const json_t &j, MemArchitectureSpec &c);
void to_json(json_t &j, const MemArchitectureSpecType &c);
void from_json(const json_t &j, MemArchitectureSpecType &c);
} // namespace Configuration

View File

@@ -36,7 +36,7 @@
#ifndef DRAMSYSCONFIGURATION_MEMPOWERSPEC_H
#define DRAMSYSCONFIGURATION_MEMPOWERSPEC_H
#include "DRAMSys/config/ConfigUtil.h"
#include "DRAMSys/util/json.h"
#include <unordered_map>

View File

@@ -36,7 +36,7 @@
#ifndef DRAMSYSCONFIGURATION_MEMSPEC_H
#define DRAMSYSCONFIGURATION_MEMSPEC_H
#include "DRAMSys/config/ConfigUtil.h"
#include "DRAMSys/util/json.h"
#include "DRAMSys/config/memspec/MemArchitectureSpec.h"
#include "DRAMSys/config/memspec/MemPowerSpec.h"
#include "DRAMSys/config/memspec/MemTimingSpec.h"
@@ -45,22 +45,20 @@
namespace DRAMSys::Config {
const std::string memSpecPath = "memspec";
struct MemSpec
{
MemArchitectureSpec memArchitectureSpec;
static constexpr std::string_view KEY = "memspec";
static constexpr std::string_view SUB_DIR = "memspec";
MemArchitectureSpecType memarchitecturespec;
std::string memoryId;
std::string memoryType;
MemTimingSpec memTimingSpec;
std::optional<MemPowerSpec> memPowerSpec;
MemTimingSpecType memtimingspec;
std::optional<MemPowerSpec> mempowerspec;
};
void to_json(json &j, const MemSpec &c);
void from_json(const json &j, MemSpec &c);
void from_dump(const std::string &dump, MemSpec &c);
std::string dump(const MemSpec &c, unsigned int indentation = -1);
NLOHMANN_JSONIFY_ALL_THINGS(
MemSpec, memarchitecturespec, memoryId, memoryType, memtimingspec, mempowerspec)
} // namespace Configuration

View File

@@ -38,7 +38,7 @@
namespace DRAMSys::Config
{
void to_json(json_t &j, const MemTimingSpec &c)
void to_json(json_t &j, const MemTimingSpecType &c)
{
j = json_t{};
@@ -48,7 +48,7 @@ void to_json(json_t &j, const MemTimingSpec &c)
}
}
void from_json(const json_t &j, MemTimingSpec &c)
void from_json(const json_t &j, MemTimingSpecType &c)
{
for (const auto &entry : j.items())
{

View File

@@ -36,7 +36,7 @@
#ifndef DRAMSYSCONFIGURATION_MEMTIMINGSPEC_H
#define DRAMSYSCONFIGURATION_MEMTIMINGSPEC_H
#include "DRAMSys/config/ConfigUtil.h"
#include "DRAMSys/util/json.h"
#include <unordered_map>
@@ -44,13 +44,13 @@ namespace DRAMSys::Config
{
using json = nlohmann::json;
struct MemTimingSpec
struct MemTimingSpecType
{
std::unordered_map<std::string, unsigned int> entries;
};
void to_json(json &j, const MemTimingSpec &c);
void from_json(const json &j, MemTimingSpec &c);
void to_json(json &j, const MemTimingSpecType &c);
void from_json(const json &j, MemTimingSpecType &c);
} // namespace Configuration

View File

@@ -288,4 +288,18 @@ public:
static bool notifyChildTransCompletion(tlm::tlm_generic_payload& trans);
};
class EccExtension : public tlm::tlm_extension<EccExtension>
{
public:
tlm_extension_base* clone() const override
{
return new EccExtension;
}
void copy_from(tlm_extension_base const &ext) override
{
auto const &cpyFrom = static_cast<EccExtension const &>(ext);
}
};
#endif // DRAMEXTENSIONS_H

View File

@@ -86,202 +86,232 @@ enum sc_time_unit string2TimeUnit(const std::string &s)
}
void Configuration::loadSimConfig(const DRAMSys::Config::SimConfig &simConfig)
{
if (const auto& _addressOffset = simConfig.addressOffset)
addressOffset = *_addressOffset;
{
addressOffset = simConfig.AddressOffset.value_or(addressOffset);
checkTLM2Protocol = simConfig.CheckTLM2Protocol.value_or(checkTLM2Protocol);
databaseRecording = simConfig.DatabaseRecording.value_or(databaseRecording);
debug = simConfig.Debug.value_or(debug);
enableWindowing = simConfig.EnableWindowing.value_or(enableWindowing);
simulationName = simConfig.SimulationName.value_or(simulationName);
simulationProgressBar = simConfig.SimulationProgressBar.value_or(simulationProgressBar);
useMalloc = simConfig.UseMalloc.value_or(useMalloc);
if (const auto& _checkTLM2Protocol = simConfig.checkTLM2Protocol)
checkTLM2Protocol = *_checkTLM2Protocol;
if (const auto& _databaseRecording = simConfig.databaseRecording)
databaseRecording = *_databaseRecording;
if (const auto& _debug = simConfig.debug)
debug = *_debug;
if (const auto& _enableWindowing = simConfig.enableWindowing)
enableWindowing = *_enableWindowing;
if (const auto& _powerAnalysis = simConfig.powerAnalysis)
{
powerAnalysis = *_powerAnalysis;
#ifndef DRAMPOWER
if (powerAnalysis)
SC_REPORT_FATAL("Configuration", "Power analysis is only supported with included DRAMPower library!");
#endif
}
if (const auto& _simulationName = simConfig.simulationName)
simulationName = *_simulationName;
if (const auto& _simulationProgressBar = simConfig.simulationProgressBar)
simulationProgressBar = *_simulationProgressBar;
if (const auto& _useMalloc = simConfig.useMalloc)
useMalloc = *_useMalloc;
if (const auto& _windowSize = simConfig.windowSize)
windowSize = *_windowSize;
if (const auto &_storeMode = simConfig.StoreMode)
storeMode = [=]
{
switch (*_storeMode)
{
case DRAMSys::Config::StoreModeType::NoStorage:
return StoreMode::NoStorage;
case DRAMSys::Config::StoreModeType::Store:
return StoreMode::Store;
default:
SC_REPORT_FATAL("Configuration", "Invalid StoreMode");
return StoreMode::NoStorage; // Silence Warning
}
}();
windowSize = simConfig.WindowSize.value_or(windowSize);
if (windowSize == 0)
SC_REPORT_FATAL("Configuration", "Minimum window size is 1");
if (const auto& _storeMode = simConfig.storeMode)
storeMode = [=] {
if (_storeMode == DRAMSys::Config::StoreMode::NoStorage)
return StoreMode::NoStorage;
else // (_storeMode == DRAMSys::Config::StoreMode::Store)
return StoreMode::Store;
}();
powerAnalysis = simConfig.PowerAnalysis.value_or(powerAnalysis);
#ifndef DRAMPOWER
if (powerAnalysis)
SC_REPORT_FATAL("Configuration", "Power analysis is only supported with included DRAMPower library!");
#endif
}
void Configuration::loadMCConfig(const DRAMSys::Config::McConfig &mcConfig)
{
if (const auto& _pagePolicy = mcConfig.pagePolicy)
pagePolicy = [=] {
if (_pagePolicy == DRAMSys::Config::PagePolicy::Open)
if (const auto &_pagePolicy = mcConfig.PagePolicy)
pagePolicy = [=]
{
switch (*_pagePolicy)
{
case DRAMSys::Config::PagePolicyType::Open:
return PagePolicy::Open;
else if (_pagePolicy == DRAMSys::Config::PagePolicy::OpenAdaptive)
case DRAMSys::Config::PagePolicyType::OpenAdaptive:
return PagePolicy::OpenAdaptive;
else if (_pagePolicy == DRAMSys::Config::PagePolicy::Closed)
case DRAMSys::Config::PagePolicyType::Closed:
return PagePolicy::Closed;
else
case DRAMSys::Config::PagePolicyType::ClosedAdaptive:
return PagePolicy::ClosedAdaptive;
default:
SC_REPORT_FATAL("Configuration", "Invalid PagePolicy");
return PagePolicy::Open; // Silence Warning
}
}();
if (const auto& _scheduler = mcConfig.scheduler)
scheduler = [=] {
if (_scheduler == DRAMSys::Config::Scheduler::Fifo)
return Scheduler::Fifo;
else if (_scheduler == DRAMSys::Config::Scheduler::FrFcfs)
return Scheduler::FrFcfs;
else if (_scheduler == DRAMSys::Config::Scheduler::FrFcfsGrp)
return Scheduler::FrFcfsGrp;
else if (_scheduler == DRAMSys::Config::Scheduler::GrpFrFcfs)
return Scheduler::GrpFrFcfs;
else
return Scheduler::GrpFrFcfsWm;
if (const auto &_scheduler = mcConfig.Scheduler)
scheduler = [=]
{
switch (*_scheduler)
{
case DRAMSys::Config::SchedulerType::Fifo:
return Scheduler::Fifo;
case DRAMSys::Config::SchedulerType::FrFcfs:
return Scheduler::FrFcfs;
case DRAMSys::Config::SchedulerType::FrFcfsGrp:
return Scheduler::FrFcfsGrp;
case DRAMSys::Config::SchedulerType::GrpFrFcfs:
return Scheduler::GrpFrFcfs;
case DRAMSys::Config::SchedulerType::GrpFrFcfsWm:
return Scheduler::GrpFrFcfsWm;
default:
SC_REPORT_FATAL("Configuration", "Invalid Scheduler");
return Scheduler::Fifo; // Silence Warning
}
}();
if (const auto& _highWatermark = mcConfig.highWatermark)
highWatermark = *mcConfig.highWatermark;
if (const auto& _lowWatermark = mcConfig.lowWatermark)
lowWatermark = *mcConfig.lowWatermark;
if (const auto& _schedulerBuffer = mcConfig.schedulerBuffer)
schedulerBuffer = [=] {
if (_schedulerBuffer == DRAMSys::Config::SchedulerBuffer::Bankwise)
if (const auto &_schedulerBuffer = mcConfig.SchedulerBuffer)
schedulerBuffer = [=]
{
switch (*_schedulerBuffer)
{
case DRAMSys::Config::SchedulerBufferType::Bankwise:
return SchedulerBuffer::Bankwise;
else if (_schedulerBuffer == DRAMSys::Config::SchedulerBuffer::ReadWrite)
case DRAMSys::Config::SchedulerBufferType::ReadWrite:
return SchedulerBuffer::ReadWrite;
else
case DRAMSys::Config::SchedulerBufferType::Shared:
return SchedulerBuffer::Shared;
default:
SC_REPORT_FATAL("Configuration", "Invalid SchedulerBuffer");
return SchedulerBuffer::Bankwise; // Silence Warning
}
}();
if (const auto& _requestBufferSize = mcConfig.requestBufferSize)
requestBufferSize = *mcConfig.requestBufferSize;
if (const auto &_cmdMux = mcConfig.CmdMux)
cmdMux = [=]
{
switch (*_cmdMux)
{
case DRAMSys::Config::CmdMuxType::Oldest:
return CmdMux::Oldest;
case DRAMSys::Config::CmdMuxType::Strict:
return CmdMux::Strict;
default:
SC_REPORT_FATAL("Configuration", "Invalid CmdMux");
return CmdMux::Oldest; // Silence Warning
}
}();
if (const auto &_respQueue = mcConfig.RespQueue)
respQueue = [=]
{
switch (*_respQueue)
{
case DRAMSys::Config::RespQueueType::Fifo:
return RespQueue::Fifo;
case DRAMSys::Config::RespQueueType::Reorder:
return RespQueue::Reorder;
default:
SC_REPORT_FATAL("Configuration", "Invalid RespQueue");
return RespQueue::Fifo; // Silence Warning
}
}();
if (const auto &_refreshPolicy = mcConfig.RefreshPolicy)
refreshPolicy = [=]
{
switch (*_refreshPolicy)
{
case DRAMSys::Config::RefreshPolicyType::NoRefresh:
return RefreshPolicy::NoRefresh;
case DRAMSys::Config::RefreshPolicyType::AllBank:
return RefreshPolicy::AllBank;
case DRAMSys::Config::RefreshPolicyType::PerBank:
return RefreshPolicy::PerBank;
case DRAMSys::Config::RefreshPolicyType::Per2Bank:
return RefreshPolicy::Per2Bank;
case DRAMSys::Config::RefreshPolicyType::SameBank:
return RefreshPolicy::SameBank;
default:
SC_REPORT_FATAL("Configuration", "Invalid RefreshPolicy");
return RefreshPolicy::NoRefresh; // Silence Warning
}
}();
if (const auto &_powerDownPolicy = mcConfig.PowerDownPolicy)
powerDownPolicy = [=]
{
switch (*_powerDownPolicy)
{
case DRAMSys::Config::PowerDownPolicyType::NoPowerDown:
return PowerDownPolicy::NoPowerDown;
case DRAMSys::Config::PowerDownPolicyType::Staggered:
return PowerDownPolicy::Staggered;
default:
SC_REPORT_FATAL("Configuration", "Invalid PowerDownPolicy");
return PowerDownPolicy::NoPowerDown; // Silence Warning
}
}();
if (const auto &_arbiter = mcConfig.Arbiter)
arbiter = [=]
{
switch (*_arbiter)
{
case DRAMSys::Config::ArbiterType::Simple:
return Arbiter::Simple;
case DRAMSys::Config::ArbiterType::Fifo:
return Arbiter::Fifo;
case DRAMSys::Config::ArbiterType::Reorder:
return Arbiter::Reorder;
default:
SC_REPORT_FATAL("Configuration", "Invalid Arbiter");
return Arbiter::Simple; // Silence Warning
}
}();
refreshMaxPostponed = mcConfig.RefreshMaxPostponed.value_or(refreshMaxPostponed);
refreshMaxPulledin = mcConfig.RefreshMaxPulledin.value_or(refreshMaxPulledin);
highWatermark = mcConfig.HighWatermark.value_or(highWatermark);
lowWatermark = mcConfig.LowWatermark.value_or(lowWatermark);
maxActiveTransactions = mcConfig.MaxActiveTransactions.value_or(maxActiveTransactions);
refreshManagement = mcConfig.RefreshManagement.value_or(refreshManagement);
requestBufferSize = mcConfig.RequestBufferSize.value_or(requestBufferSize);
if (requestBufferSize == 0)
SC_REPORT_FATAL("Configuration", "Minimum request buffer size is 1!");
if (const auto& _cmdMux = mcConfig.cmdMux)
cmdMux = [=] {
if (_cmdMux == DRAMSys::Config::CmdMux::Oldest)
return CmdMux::Oldest;
else
return CmdMux::Strict;
}();
if (const auto& _respQueue = mcConfig.respQueue)
respQueue = [=] {
if (_respQueue == DRAMSys::Config::RespQueue::Fifo)
return RespQueue::Fifo;
else
return RespQueue::Reorder;
}();
if (const auto& _refreshPolicy = mcConfig.refreshPolicy)
refreshPolicy = [=] {
if (_refreshPolicy == DRAMSys::Config::RefreshPolicy::NoRefresh)
return RefreshPolicy::NoRefresh;
else if (_refreshPolicy == DRAMSys::Config::RefreshPolicy::AllBank)
return RefreshPolicy::AllBank;
else if (_refreshPolicy == DRAMSys::Config::RefreshPolicy::PerBank)
return RefreshPolicy::PerBank;
else if (_refreshPolicy == DRAMSys::Config::RefreshPolicy::Per2Bank)
return RefreshPolicy::Per2Bank;
else // if (policy == DRAMSys::Config::RefreshPolicy::SameBank)
return RefreshPolicy::SameBank;
}();
if (const auto& _refreshMaxPostponed = mcConfig.refreshMaxPostponed)
refreshMaxPostponed = *_refreshMaxPostponed;
if (const auto& _refreshMaxPulledin = mcConfig.refreshMaxPulledin)
refreshMaxPulledin = *_refreshMaxPulledin;
if (const auto& _powerDownPolicy = mcConfig.powerDownPolicy)
powerDownPolicy = [=] {
if (_powerDownPolicy == DRAMSys::Config::PowerDownPolicy::NoPowerDown)
return PowerDownPolicy::NoPowerDown;
else
return PowerDownPolicy::Staggered;
}();
if (const auto& _arbiter = mcConfig.arbiter)
arbiter = [=] {
if (_arbiter == DRAMSys::Config::Arbiter::Simple)
return Arbiter::Simple;
else if (_arbiter == DRAMSys::Config::Arbiter::Fifo)
return Arbiter::Fifo;
else
return Arbiter::Reorder;
}();
if (const auto& _maxActiveTransactions = mcConfig.maxActiveTransactions)
maxActiveTransactions = *_maxActiveTransactions;
if (const auto& _refreshManagement = mcConfig.refreshManagement)
refreshManagement = *_refreshManagement;
if (const auto& _arbitrationDelayFw = mcConfig.arbitrationDelayFw)
if (const auto& _arbitrationDelayFw = mcConfig.ArbitrationDelayFw)
{
arbitrationDelayFw = std::round(sc_time(*_arbitrationDelayFw, SC_NS) / memSpec->tCK) * memSpec->tCK;
}
if (const auto& _arbitrationDelayBw = mcConfig.arbitrationDelayBw)
if (const auto& _arbitrationDelayBw = mcConfig.ArbitrationDelayBw)
{
arbitrationDelayBw = std::round(sc_time(*_arbitrationDelayBw, SC_NS) / memSpec->tCK) * memSpec->tCK;
}
if (const auto& _thinkDelayFw = mcConfig.thinkDelayFw)
if (const auto& _thinkDelayFw = mcConfig.ThinkDelayFw)
{
thinkDelayFw = std::round(sc_time(*_thinkDelayFw, SC_NS) / memSpec->tCK) * memSpec->tCK;
}
if (const auto& _thinkDelayBw = mcConfig.thinkDelayBw)
if (const auto& _thinkDelayBw = mcConfig.ThinkDelayBw)
{
thinkDelayBw = std::round(sc_time(*_thinkDelayBw, SC_NS) / memSpec->tCK) * memSpec->tCK;
}
if (const auto& _phyDelayFw = mcConfig.phyDelayFw)
if (const auto& _phyDelayFw = mcConfig.PhyDelayFw)
{
phyDelayFw = std::round(sc_time(*_phyDelayFw, SC_NS) / memSpec->tCK) * memSpec->tCK;
}
if (const auto& _phyDelayBw = mcConfig.phyDelayBw)
if (const auto& _phyDelayBw = mcConfig.PhyDelayBw)
{
phyDelayBw = std::round(sc_time(*_phyDelayBw, SC_NS) / memSpec->tCK) * memSpec->tCK;
}
{
auto _blockingReadDelay = mcConfig.blockingReadDelay.value_or(60);
auto _blockingReadDelay = mcConfig.BlockingReadDelay.value_or(60);
blockingReadDelay = std::round(sc_time(_blockingReadDelay, SC_NS) / memSpec->tCK) * memSpec->tCK;
}
{
auto _blockingWriteDelay = mcConfig.blockingWriteDelay.value_or(60);
auto _blockingWriteDelay = mcConfig.BlockingWriteDelay.value_or(60);
blockingWriteDelay = std::round(sc_time(_blockingWriteDelay, SC_NS) / memSpec->tCK) * memSpec->tCK;
}
}

View File

@@ -55,20 +55,20 @@ MemSpec::MemSpec(const DRAMSys::Config::MemSpec& memSpec,
banksPerChannel(banksPerChannel),
bankGroupsPerChannel(bankGroupsPerChannel),
devicesPerRank(devicesPerRank),
rowsPerBank(memSpec.memArchitectureSpec.entries.at("nbrOfRows")),
columnsPerRow(memSpec.memArchitectureSpec.entries.at("nbrOfColumns")),
defaultBurstLength(memSpec.memArchitectureSpec.entries.at("burstLength")),
maxBurstLength(memSpec.memArchitectureSpec.entries.find("maxBurstLength") !=
memSpec.memArchitectureSpec.entries.end()
? memSpec.memArchitectureSpec.entries.at("maxBurstLength")
rowsPerBank(memSpec.memarchitecturespec.entries.at("nbrOfRows")),
columnsPerRow(memSpec.memarchitecturespec.entries.at("nbrOfColumns")),
defaultBurstLength(memSpec.memarchitecturespec.entries.at("burstLength")),
maxBurstLength(memSpec.memarchitecturespec.entries.find("maxBurstLength") !=
memSpec.memarchitecturespec.entries.end()
? memSpec.memarchitecturespec.entries.at("maxBurstLength")
: defaultBurstLength),
dataRate(memSpec.memArchitectureSpec.entries.at("dataRate")),
bitWidth(memSpec.memArchitectureSpec.entries.at("width")),
dataRate(memSpec.memarchitecturespec.entries.at("dataRate")),
bitWidth(memSpec.memarchitecturespec.entries.at("width")),
dataBusWidth(bitWidth* devicesPerRank),
bytesPerBeat(dataBusWidth / 8),
defaultBytesPerBurst((defaultBurstLength* dataBusWidth) / 8),
maxBytesPerBurst((maxBurstLength* dataBusWidth) / 8),
fCKMHz(memSpec.memTimingSpec.entries.at("clkMhz")),
fCKMHz(memSpec.memtimingspec.entries.at("clkMhz")),
tCK(sc_time(1.0 / fCKMHz, SC_US)),
memoryId(memSpec.memoryId),
memoryType(memoryType),

View File

@@ -45,61 +45,61 @@ using namespace tlm;
MemSpecDDR3::MemSpecDDR3(const DRAMSys::Config::MemSpec &memSpec)
: MemSpec(memSpec, MemoryType::DDR3,
memSpec.memArchitectureSpec.entries.at("nbrOfChannels"),
memSpec.memarchitecturespec.entries.at("nbrOfChannels"),
1,
memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks"),
memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks"),
1,
memSpec.memArchitectureSpec.entries.at("nbrOfBanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks")
* memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfDevices")),
tCKE (tCK * memSpec.memTimingSpec.entries.at("CKE")),
memSpec.memarchitecturespec.entries.at("nbrOfBanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks")
* memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfDevices")),
tCKE (tCK * memSpec.memtimingspec.entries.at("CKE")),
tPD (tCKE),
tCKESR (tCK * memSpec.memTimingSpec.entries.at("CKESR")),
tDQSCK (tCK * memSpec.memTimingSpec.entries.at("DQSCK")),
tRAS (tCK * memSpec.memTimingSpec.entries.at("RAS")),
tRC (tCK * memSpec.memTimingSpec.entries.at("RC")),
tRCD (tCK * memSpec.memTimingSpec.entries.at("RCD")),
tRL (tCK * memSpec.memTimingSpec.entries.at("RL")),
tRTP (tCK * memSpec.memTimingSpec.entries.at("RTP")),
tWL (tCK * memSpec.memTimingSpec.entries.at("WL")),
tWR (tCK * memSpec.memTimingSpec.entries.at("WR")),
tXP (tCK * memSpec.memTimingSpec.entries.at("XP")),
tXS (tCK * memSpec.memTimingSpec.entries.at("XS")),
tCCD (tCK * memSpec.memTimingSpec.entries.at("CCD")),
tFAW (tCK * memSpec.memTimingSpec.entries.at("FAW")),
tREFI (tCK * memSpec.memTimingSpec.entries.at("REFI")),
tRFC (tCK * memSpec.memTimingSpec.entries.at("RFC")),
tRP (tCK * memSpec.memTimingSpec.entries.at("RP")),
tRRD (tCK * memSpec.memTimingSpec.entries.at("RRD")),
tWTR (tCK * memSpec.memTimingSpec.entries.at("WTR")),
tAL (tCK * memSpec.memTimingSpec.entries.at("AL")),
tXPDLL (tCK * memSpec.memTimingSpec.entries.at("XPDLL")),
tXSDLL (tCK * memSpec.memTimingSpec.entries.at("XSDLL")),
tACTPDEN (tCK * memSpec.memTimingSpec.entries.at("ACTPDEN")),
tPRPDEN (tCK * memSpec.memTimingSpec.entries.at("PRPDEN")),
tREFPDEN (tCK * memSpec.memTimingSpec.entries.at("REFPDEN")),
tRTRS (tCK * memSpec.memTimingSpec.entries.at("RTRS")),
iDD0 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd0") : 0),
iDD2N (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd2n") : 0),
iDD3N (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd3n") : 0),
iDD4R (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd4r") : 0),
iDD4W (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd4w") : 0),
iDD5 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd5") : 0),
iDD6 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd6") : 0),
vDD (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("vdd") : 0),
iDD2P0 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd2p0") : 0),
iDD2P1 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd2p1") : 0),
iDD3P0 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd3p0") : 0),
iDD3P1 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd3p1") : 0)
tCKESR (tCK * memSpec.memtimingspec.entries.at("CKESR")),
tDQSCK (tCK * memSpec.memtimingspec.entries.at("DQSCK")),
tRAS (tCK * memSpec.memtimingspec.entries.at("RAS")),
tRC (tCK * memSpec.memtimingspec.entries.at("RC")),
tRCD (tCK * memSpec.memtimingspec.entries.at("RCD")),
tRL (tCK * memSpec.memtimingspec.entries.at("RL")),
tRTP (tCK * memSpec.memtimingspec.entries.at("RTP")),
tWL (tCK * memSpec.memtimingspec.entries.at("WL")),
tWR (tCK * memSpec.memtimingspec.entries.at("WR")),
tXP (tCK * memSpec.memtimingspec.entries.at("XP")),
tXS (tCK * memSpec.memtimingspec.entries.at("XS")),
tCCD (tCK * memSpec.memtimingspec.entries.at("CCD")),
tFAW (tCK * memSpec.memtimingspec.entries.at("FAW")),
tREFI (tCK * memSpec.memtimingspec.entries.at("REFI")),
tRFC (tCK * memSpec.memtimingspec.entries.at("RFC")),
tRP (tCK * memSpec.memtimingspec.entries.at("RP")),
tRRD (tCK * memSpec.memtimingspec.entries.at("RRD")),
tWTR (tCK * memSpec.memtimingspec.entries.at("WTR")),
tAL (tCK * memSpec.memtimingspec.entries.at("AL")),
tXPDLL (tCK * memSpec.memtimingspec.entries.at("XPDLL")),
tXSDLL (tCK * memSpec.memtimingspec.entries.at("XSDLL")),
tACTPDEN (tCK * memSpec.memtimingspec.entries.at("ACTPDEN")),
tPRPDEN (tCK * memSpec.memtimingspec.entries.at("PRPDEN")),
tREFPDEN (tCK * memSpec.memtimingspec.entries.at("REFPDEN")),
tRTRS (tCK * memSpec.memtimingspec.entries.at("RTRS")),
iDD0 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd0") : 0),
iDD2N (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd2n") : 0),
iDD3N (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd3n") : 0),
iDD4R (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd4r") : 0),
iDD4W (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd4w") : 0),
iDD5 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd5") : 0),
iDD6 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd6") : 0),
vDD (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("vdd") : 0),
iDD2P0 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd2p0") : 0),
iDD2P1 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd2p1") : 0),
iDD3P0 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd3p0") : 0),
iDD3P1 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd3p1") : 0)
{
uint64_t deviceSizeBits = static_cast<uint64_t>(banksPerRank) * rowsPerBank * columnsPerRow * bitWidth;
uint64_t deviceSizeBytes = deviceSizeBits / 8;
memorySizeBytes = deviceSizeBytes * devicesPerRank * ranksPerChannel * numberOfChannels;
if (!memSpec.memPowerSpec.has_value())
if (!memSpec.mempowerspec.has_value())
SC_REPORT_FATAL("MemSpec", "No power spec defined!");
std::cout << headline << std::endl;

View File

@@ -45,79 +45,79 @@ using namespace tlm;
MemSpecDDR4::MemSpecDDR4(const DRAMSys::Config::MemSpec &memSpec)
: MemSpec(memSpec, MemoryType::DDR4,
memSpec.memArchitectureSpec.entries.at("nbrOfChannels"),
memSpec.memarchitecturespec.entries.at("nbrOfChannels"),
1,
memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBankGroups"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks")
/ memSpec.memArchitectureSpec.entries.at("nbrOfBankGroups"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks")
* memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBankGroups")
* memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfDevices")),
tCKE (tCK * memSpec.memTimingSpec.entries.at("CKE")),
memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBankGroups"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks")
/ memSpec.memarchitecturespec.entries.at("nbrOfBankGroups"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks")
* memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBankGroups")
* memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfDevices")),
tCKE (tCK * memSpec.memtimingspec.entries.at("CKE")),
tPD (tCKE),
tCKESR (tCK * memSpec.memTimingSpec.entries.at("CKESR")),
tRAS (tCK * memSpec.memTimingSpec.entries.at("RAS")),
tRC (tCK * memSpec.memTimingSpec.entries.at("RC")),
tRCD (tCK * memSpec.memTimingSpec.entries.at("RCD")),
tRL (tCK * memSpec.memTimingSpec.entries.at("RL")),
tRPRE (tCK * memSpec.memTimingSpec.entries.at("RPRE")),
tRTP (tCK * memSpec.memTimingSpec.entries.at("RTP")),
tWL (tCK * memSpec.memTimingSpec.entries.at("WL")),
tWPRE (tCK * memSpec.memTimingSpec.entries.at("WPRE")),
tWR (tCK * memSpec.memTimingSpec.entries.at("WR")),
tXP (tCK * memSpec.memTimingSpec.entries.at("XP")),
tXS (tCK * memSpec.memTimingSpec.entries.at("XS")),
tREFI ((memSpec.memTimingSpec.entries.at("REFM") == 4) ?
(tCK * (static_cast<double>(memSpec.memTimingSpec.entries.at("REFI")) / 4)) :
((memSpec.memTimingSpec.entries.at("REFM") == 2) ?
(tCK * (static_cast<double>(memSpec.memTimingSpec.entries.at("REFI")) / 2)) :
(tCK * memSpec.memTimingSpec.entries.at("REFI")))),
tRFC ((memSpec.memTimingSpec.entries.at("REFM") == 4) ?
(tCK * memSpec.memTimingSpec.entries.at("RFC4")) :
((memSpec.memTimingSpec.entries.at("REFM") == 2) ?
(tCK * memSpec.memTimingSpec.entries.at("RFC2")) :
(tCK * memSpec.memTimingSpec.entries.at("RFC")))),
tRP (tCK * memSpec.memTimingSpec.entries.at("RP")),
tDQSCK (tCK * memSpec.memTimingSpec.entries.at("DQSCK")),
tCCD_S (tCK * memSpec.memTimingSpec.entries.at("CCD_S")),
tCCD_L (tCK * memSpec.memTimingSpec.entries.at("CCD_L")),
tFAW (tCK * memSpec.memTimingSpec.entries.at("FAW")),
tRRD_S (tCK * memSpec.memTimingSpec.entries.at("RRD_S")),
tRRD_L (tCK * memSpec.memTimingSpec.entries.at("RRD_L")),
tWTR_S (tCK * memSpec.memTimingSpec.entries.at("WTR_S")),
tWTR_L (tCK * memSpec.memTimingSpec.entries.at("WTR_L")),
tAL (tCK * memSpec.memTimingSpec.entries.at("AL")),
tXPDLL (tCK * memSpec.memTimingSpec.entries.at("XPDLL")),
tXSDLL (tCK * memSpec.memTimingSpec.entries.at("XSDLL")),
tACTPDEN (tCK * memSpec.memTimingSpec.entries.at("ACTPDEN")),
tPRPDEN (tCK * memSpec.memTimingSpec.entries.at("PRPDEN")),
tREFPDEN (tCK * memSpec.memTimingSpec.entries.at("REFPDEN")),
tRTRS (tCK * memSpec.memTimingSpec.entries.at("RTRS")),
iDD0 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd0") : 0),
iDD2N (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd2n") : 0),
iDD3N (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd3n") : 0),
iDD4R (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd4r") : 0),
iDD4W (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd4w") : 0),
iDD5 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd5") : 0),
iDD6 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd6") : 0),
vDD (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("vdd") : 0),
iDD02 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd02") : 0),
iDD2P0 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd2p0") : 0),
iDD2P1 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd2p1") : 0),
iDD3P0 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd3p0") : 0),
iDD3P1 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd3p1") : 0),
iDD62 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd62") : 0),
vDD2 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("vdd2") : 0)
tCKESR (tCK * memSpec.memtimingspec.entries.at("CKESR")),
tRAS (tCK * memSpec.memtimingspec.entries.at("RAS")),
tRC (tCK * memSpec.memtimingspec.entries.at("RC")),
tRCD (tCK * memSpec.memtimingspec.entries.at("RCD")),
tRL (tCK * memSpec.memtimingspec.entries.at("RL")),
tRPRE (tCK * memSpec.memtimingspec.entries.at("RPRE")),
tRTP (tCK * memSpec.memtimingspec.entries.at("RTP")),
tWL (tCK * memSpec.memtimingspec.entries.at("WL")),
tWPRE (tCK * memSpec.memtimingspec.entries.at("WPRE")),
tWR (tCK * memSpec.memtimingspec.entries.at("WR")),
tXP (tCK * memSpec.memtimingspec.entries.at("XP")),
tXS (tCK * memSpec.memtimingspec.entries.at("XS")),
tREFI ((memSpec.memtimingspec.entries.at("REFM") == 4) ?
(tCK * (static_cast<double>(memSpec.memtimingspec.entries.at("REFI")) / 4)) :
((memSpec.memtimingspec.entries.at("REFM") == 2) ?
(tCK * (static_cast<double>(memSpec.memtimingspec.entries.at("REFI")) / 2)) :
(tCK * memSpec.memtimingspec.entries.at("REFI")))),
tRFC ((memSpec.memtimingspec.entries.at("REFM") == 4) ?
(tCK * memSpec.memtimingspec.entries.at("RFC4")) :
((memSpec.memtimingspec.entries.at("REFM") == 2) ?
(tCK * memSpec.memtimingspec.entries.at("RFC2")) :
(tCK * memSpec.memtimingspec.entries.at("RFC")))),
tRP (tCK * memSpec.memtimingspec.entries.at("RP")),
tDQSCK (tCK * memSpec.memtimingspec.entries.at("DQSCK")),
tCCD_S (tCK * memSpec.memtimingspec.entries.at("CCD_S")),
tCCD_L (tCK * memSpec.memtimingspec.entries.at("CCD_L")),
tFAW (tCK * memSpec.memtimingspec.entries.at("FAW")),
tRRD_S (tCK * memSpec.memtimingspec.entries.at("RRD_S")),
tRRD_L (tCK * memSpec.memtimingspec.entries.at("RRD_L")),
tWTR_S (tCK * memSpec.memtimingspec.entries.at("WTR_S")),
tWTR_L (tCK * memSpec.memtimingspec.entries.at("WTR_L")),
tAL (tCK * memSpec.memtimingspec.entries.at("AL")),
tXPDLL (tCK * memSpec.memtimingspec.entries.at("XPDLL")),
tXSDLL (tCK * memSpec.memtimingspec.entries.at("XSDLL")),
tACTPDEN (tCK * memSpec.memtimingspec.entries.at("ACTPDEN")),
tPRPDEN (tCK * memSpec.memtimingspec.entries.at("PRPDEN")),
tREFPDEN (tCK * memSpec.memtimingspec.entries.at("REFPDEN")),
tRTRS (tCK * memSpec.memtimingspec.entries.at("RTRS")),
iDD0 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd0") : 0),
iDD2N (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd2n") : 0),
iDD3N (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd3n") : 0),
iDD4R (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd4r") : 0),
iDD4W (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd4w") : 0),
iDD5 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd5") : 0),
iDD6 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd6") : 0),
vDD (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("vdd") : 0),
iDD02 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd02") : 0),
iDD2P0 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd2p0") : 0),
iDD2P1 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd2p1") : 0),
iDD3P0 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd3p0") : 0),
iDD3P1 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd3p1") : 0),
iDD62 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd62") : 0),
vDD2 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("vdd2") : 0)
{
uint64_t deviceSizeBits = static_cast<uint64_t>(banksPerRank) * rowsPerBank * columnsPerRow * bitWidth;
uint64_t deviceSizeBytes = deviceSizeBits / 8;
memorySizeBytes = deviceSizeBytes * devicesPerRank * ranksPerChannel * numberOfChannels;
if (!memSpec.memPowerSpec.has_value())
if (!memSpec.mempowerspec.has_value())
SC_REPORT_WARNING("MemSpec", "No power spec defined!");
std::cout << headline << std::endl;

View File

@@ -45,52 +45,52 @@ using namespace tlm;
MemSpecGDDR5::MemSpecGDDR5(const DRAMSys::Config::MemSpec &memSpec)
: MemSpec(memSpec, MemoryType::GDDR5,
memSpec.memArchitectureSpec.entries.at("nbrOfChannels"),
memSpec.memarchitecturespec.entries.at("nbrOfChannels"),
1,
memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBankGroups"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks")
/ memSpec.memArchitectureSpec.entries.at("nbrOfBankGroups"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks")
* memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBankGroups")
* memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfDevices")),
tRP (tCK * memSpec.memTimingSpec.entries.at("RP")),
tRAS (tCK * memSpec.memTimingSpec.entries.at("RAS")),
tRC (tCK * memSpec.memTimingSpec.entries.at("RC")),
tRCDRD (tCK * memSpec.memTimingSpec.entries.at("RCDRD")),
tRCDWR (tCK * memSpec.memTimingSpec.entries.at("RCDWR")),
tRTP (tCK * memSpec.memTimingSpec.entries.at("RTP")),
tRRDS (tCK * memSpec.memTimingSpec.entries.at("RRDS")),
tRRDL (tCK * memSpec.memTimingSpec.entries.at("RRDL")),
tCCDS (tCK * memSpec.memTimingSpec.entries.at("CCDS")),
tCCDL (tCK * memSpec.memTimingSpec.entries.at("CCDL")),
tCL (tCK * memSpec.memTimingSpec.entries.at("CL")),
tWCK2CKPIN (tCK * memSpec.memTimingSpec.entries.at("WCK2CKPIN")),
tWCK2CK (tCK * memSpec.memTimingSpec.entries.at("WCK2CK")),
tWCK2DQO (tCK * memSpec.memTimingSpec.entries.at("WCK2DQO")),
tRTW (tCK * memSpec.memTimingSpec.entries.at("RTW")),
tWL (tCK * memSpec.memTimingSpec.entries.at("WL")),
tWCK2DQI (tCK * memSpec.memTimingSpec.entries.at("WCK2DQI")),
tWR (tCK * memSpec.memTimingSpec.entries.at("WR")),
tWTRS (tCK * memSpec.memTimingSpec.entries.at("WTRS")),
tWTRL (tCK * memSpec.memTimingSpec.entries.at("WTRL")),
tCKE (tCK * memSpec.memTimingSpec.entries.at("CKE")),
tPD (tCK * memSpec.memTimingSpec.entries.at("PD")),
tXPN (tCK * memSpec.memTimingSpec.entries.at("XPN")),
tREFI (tCK * memSpec.memTimingSpec.entries.at("REFI")),
tREFIPB (tCK * memSpec.memTimingSpec.entries.at("REFIPB")),
tRFC (tCK * memSpec.memTimingSpec.entries.at("RFC")),
tRFCPB (tCK * memSpec.memTimingSpec.entries.at("RFCPB")),
tRREFD (tCK * memSpec.memTimingSpec.entries.at("RREFD")),
tXS (tCK * memSpec.memTimingSpec.entries.at("XS")),
tFAW (tCK * memSpec.memTimingSpec.entries.at("FAW")),
t32AW (tCK * memSpec.memTimingSpec.entries.at("32AW")),
tPPD (tCK * memSpec.memTimingSpec.entries.at("PPD")),
tLK (tCK * memSpec.memTimingSpec.entries.at("LK")),
tRTRS (tCK * memSpec.memTimingSpec.entries.at("RTRS"))
memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBankGroups"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks")
/ memSpec.memarchitecturespec.entries.at("nbrOfBankGroups"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks")
* memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBankGroups")
* memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfDevices")),
tRP (tCK * memSpec.memtimingspec.entries.at("RP")),
tRAS (tCK * memSpec.memtimingspec.entries.at("RAS")),
tRC (tCK * memSpec.memtimingspec.entries.at("RC")),
tRCDRD (tCK * memSpec.memtimingspec.entries.at("RCDRD")),
tRCDWR (tCK * memSpec.memtimingspec.entries.at("RCDWR")),
tRTP (tCK * memSpec.memtimingspec.entries.at("RTP")),
tRRDS (tCK * memSpec.memtimingspec.entries.at("RRDS")),
tRRDL (tCK * memSpec.memtimingspec.entries.at("RRDL")),
tCCDS (tCK * memSpec.memtimingspec.entries.at("CCDS")),
tCCDL (tCK * memSpec.memtimingspec.entries.at("CCDL")),
tCL (tCK * memSpec.memtimingspec.entries.at("CL")),
tWCK2CKPIN (tCK * memSpec.memtimingspec.entries.at("WCK2CKPIN")),
tWCK2CK (tCK * memSpec.memtimingspec.entries.at("WCK2CK")),
tWCK2DQO (tCK * memSpec.memtimingspec.entries.at("WCK2DQO")),
tRTW (tCK * memSpec.memtimingspec.entries.at("RTW")),
tWL (tCK * memSpec.memtimingspec.entries.at("WL")),
tWCK2DQI (tCK * memSpec.memtimingspec.entries.at("WCK2DQI")),
tWR (tCK * memSpec.memtimingspec.entries.at("WR")),
tWTRS (tCK * memSpec.memtimingspec.entries.at("WTRS")),
tWTRL (tCK * memSpec.memtimingspec.entries.at("WTRL")),
tCKE (tCK * memSpec.memtimingspec.entries.at("CKE")),
tPD (tCK * memSpec.memtimingspec.entries.at("PD")),
tXPN (tCK * memSpec.memtimingspec.entries.at("XPN")),
tREFI (tCK * memSpec.memtimingspec.entries.at("REFI")),
tREFIPB (tCK * memSpec.memtimingspec.entries.at("REFIPB")),
tRFC (tCK * memSpec.memtimingspec.entries.at("RFC")),
tRFCPB (tCK * memSpec.memtimingspec.entries.at("RFCPB")),
tRREFD (tCK * memSpec.memtimingspec.entries.at("RREFD")),
tXS (tCK * memSpec.memtimingspec.entries.at("XS")),
tFAW (tCK * memSpec.memtimingspec.entries.at("FAW")),
t32AW (tCK * memSpec.memtimingspec.entries.at("32AW")),
tPPD (tCK * memSpec.memtimingspec.entries.at("PPD")),
tLK (tCK * memSpec.memtimingspec.entries.at("LK")),
tRTRS (tCK * memSpec.memtimingspec.entries.at("RTRS"))
{
uint64_t deviceSizeBits = static_cast<uint64_t>(banksPerRank) * rowsPerBank * columnsPerRow * bitWidth;
uint64_t deviceSizeBytes = deviceSizeBits / 8;

View File

@@ -45,52 +45,52 @@ using namespace tlm;
MemSpecGDDR5X::MemSpecGDDR5X(const DRAMSys::Config::MemSpec &memSpec)
: MemSpec(memSpec, MemoryType::GDDR5X,
memSpec.memArchitectureSpec.entries.at("nbrOfChannels"),
memSpec.memarchitecturespec.entries.at("nbrOfChannels"),
1,
memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBankGroups"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks")
/ memSpec.memArchitectureSpec.entries.at("nbrOfBankGroups"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks")
* memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBankGroups")
* memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfDevices")),
tRP (tCK * memSpec.memTimingSpec.entries.at("RP")),
tRAS (tCK * memSpec.memTimingSpec.entries.at("RAS")),
tRC (tCK * memSpec.memTimingSpec.entries.at("RC")),
tRCDRD (tCK * memSpec.memTimingSpec.entries.at("RCDRD")),
tRCDWR (tCK * memSpec.memTimingSpec.entries.at("RCDWR")),
tRTP (tCK * memSpec.memTimingSpec.entries.at("RTP")),
tRRDS (tCK * memSpec.memTimingSpec.entries.at("RRDS")),
tRRDL (tCK * memSpec.memTimingSpec.entries.at("RRDL")),
tCCDS (tCK * memSpec.memTimingSpec.entries.at("CCDS")),
tCCDL (tCK * memSpec.memTimingSpec.entries.at("CCDL")),
tRL (tCK * memSpec.memTimingSpec.entries.at("CL")),
tWCK2CKPIN (tCK * memSpec.memTimingSpec.entries.at("WCK2CKPIN")),
tWCK2CK (tCK * memSpec.memTimingSpec.entries.at("WCK2CK")),
tWCK2DQO (tCK * memSpec.memTimingSpec.entries.at("WCK2DQO")),
tRTW (tCK * memSpec.memTimingSpec.entries.at("RTW")),
tWL (tCK * memSpec.memTimingSpec.entries.at("WL")),
tWCK2DQI (tCK * memSpec.memTimingSpec.entries.at("WCK2DQI")),
tWR (tCK * memSpec.memTimingSpec.entries.at("WR")),
tWTRS (tCK * memSpec.memTimingSpec.entries.at("WTRS")),
tWTRL (tCK * memSpec.memTimingSpec.entries.at("WTRL")),
tCKE (tCK * memSpec.memTimingSpec.entries.at("CKE")),
tPD (tCK * memSpec.memTimingSpec.entries.at("PD")),
tXP (tCK * memSpec.memTimingSpec.entries.at("XP")),
tREFI (tCK * memSpec.memTimingSpec.entries.at("REFI")),
tREFIPB (tCK * memSpec.memTimingSpec.entries.at("REFIPB")),
tRFC (tCK * memSpec.memTimingSpec.entries.at("RFC")),
tRFCPB (tCK * memSpec.memTimingSpec.entries.at("RFCPB")),
tRREFD (tCK * memSpec.memTimingSpec.entries.at("RREFD")),
tXS (tCK * memSpec.memTimingSpec.entries.at("XS")),
tFAW (tCK * memSpec.memTimingSpec.entries.at("FAW")),
t32AW (tCK * memSpec.memTimingSpec.entries.at("32AW")),
tPPD (tCK * memSpec.memTimingSpec.entries.at("PPD")),
tLK (tCK * memSpec.memTimingSpec.entries.at("LK")),
tRTRS (tCK * memSpec.memTimingSpec.entries.at("TRS"))
memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBankGroups"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks")
/ memSpec.memarchitecturespec.entries.at("nbrOfBankGroups"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks")
* memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBankGroups")
* memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfDevices")),
tRP (tCK * memSpec.memtimingspec.entries.at("RP")),
tRAS (tCK * memSpec.memtimingspec.entries.at("RAS")),
tRC (tCK * memSpec.memtimingspec.entries.at("RC")),
tRCDRD (tCK * memSpec.memtimingspec.entries.at("RCDRD")),
tRCDWR (tCK * memSpec.memtimingspec.entries.at("RCDWR")),
tRTP (tCK * memSpec.memtimingspec.entries.at("RTP")),
tRRDS (tCK * memSpec.memtimingspec.entries.at("RRDS")),
tRRDL (tCK * memSpec.memtimingspec.entries.at("RRDL")),
tCCDS (tCK * memSpec.memtimingspec.entries.at("CCDS")),
tCCDL (tCK * memSpec.memtimingspec.entries.at("CCDL")),
tRL (tCK * memSpec.memtimingspec.entries.at("CL")),
tWCK2CKPIN (tCK * memSpec.memtimingspec.entries.at("WCK2CKPIN")),
tWCK2CK (tCK * memSpec.memtimingspec.entries.at("WCK2CK")),
tWCK2DQO (tCK * memSpec.memtimingspec.entries.at("WCK2DQO")),
tRTW (tCK * memSpec.memtimingspec.entries.at("RTW")),
tWL (tCK * memSpec.memtimingspec.entries.at("WL")),
tWCK2DQI (tCK * memSpec.memtimingspec.entries.at("WCK2DQI")),
tWR (tCK * memSpec.memtimingspec.entries.at("WR")),
tWTRS (tCK * memSpec.memtimingspec.entries.at("WTRS")),
tWTRL (tCK * memSpec.memtimingspec.entries.at("WTRL")),
tCKE (tCK * memSpec.memtimingspec.entries.at("CKE")),
tPD (tCK * memSpec.memtimingspec.entries.at("PD")),
tXP (tCK * memSpec.memtimingspec.entries.at("XP")),
tREFI (tCK * memSpec.memtimingspec.entries.at("REFI")),
tREFIPB (tCK * memSpec.memtimingspec.entries.at("REFIPB")),
tRFC (tCK * memSpec.memtimingspec.entries.at("RFC")),
tRFCPB (tCK * memSpec.memtimingspec.entries.at("RFCPB")),
tRREFD (tCK * memSpec.memtimingspec.entries.at("RREFD")),
tXS (tCK * memSpec.memtimingspec.entries.at("XS")),
tFAW (tCK * memSpec.memtimingspec.entries.at("FAW")),
t32AW (tCK * memSpec.memtimingspec.entries.at("32AW")),
tPPD (tCK * memSpec.memtimingspec.entries.at("PPD")),
tLK (tCK * memSpec.memtimingspec.entries.at("LK")),
tRTRS (tCK * memSpec.memtimingspec.entries.at("TRS"))
{
uint64_t deviceSizeBits = static_cast<uint64_t>(banksPerRank) * rowsPerBank * columnsPerRow * bitWidth;
uint64_t deviceSizeBytes = deviceSizeBits / 8;

View File

@@ -45,55 +45,55 @@ using namespace tlm;
MemSpecGDDR6::MemSpecGDDR6(const DRAMSys::Config::MemSpec &memSpec)
: MemSpec(memSpec, MemoryType::GDDR6,
memSpec.memArchitectureSpec.entries.at("nbrOfChannels"),
memSpec.memarchitecturespec.entries.at("nbrOfChannels"),
1,
memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks"),
memSpec.memArchitectureSpec.entries.at( "nbrOfBankGroups"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks")
/ memSpec.memArchitectureSpec.entries.at( "nbrOfBankGroups"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks")
* memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at( "nbrOfBankGroups")
* memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfDevices")),
per2BankOffset(memSpec.memArchitectureSpec.entries.at("per2BankOffset")),
tRP (tCK * memSpec.memTimingSpec.entries.at("RP")),
tRAS (tCK * memSpec.memTimingSpec.entries.at("RAS")),
tRC (tCK * memSpec.memTimingSpec.entries.at("RC")),
tRCDRD (tCK * memSpec.memTimingSpec.entries.at("RCDRD")),
tRCDWR (tCK * memSpec.memTimingSpec.entries.at("RCDWR")),
tRTP (tCK * memSpec.memTimingSpec.entries.at("RTP")),
tRRDS (tCK * memSpec.memTimingSpec.entries.at("RRDS")),
tRRDL (tCK * memSpec.memTimingSpec.entries.at("RRDL")),
tCCDS (tCK * memSpec.memTimingSpec.entries.at("CCDS")),
tCCDL (tCK * memSpec.memTimingSpec.entries.at("CCDL")),
tRL (tCK * memSpec.memTimingSpec.entries.at("RL")),
tWCK2CKPIN (tCK * memSpec.memTimingSpec.entries.at("WCK2CKPIN")),
tWCK2CK (tCK * memSpec.memTimingSpec.entries.at("WCK2CK")),
tWCK2DQO (tCK * memSpec.memTimingSpec.entries.at("WCK2DQO")),
tRTW (tCK * memSpec.memTimingSpec.entries.at("RTW")),
tWL (tCK * memSpec.memTimingSpec.entries.at("WL")),
tWCK2DQI (tCK * memSpec.memTimingSpec.entries.at("WCK2DQI")),
tWR (tCK * memSpec.memTimingSpec.entries.at("WR")),
tWTRS (tCK * memSpec.memTimingSpec.entries.at("WTRS")),
tWTRL (tCK * memSpec.memTimingSpec.entries.at("WTRL")),
tPD (tCK * memSpec.memTimingSpec.entries.at("PD")),
tCKESR (tCK * memSpec.memTimingSpec.entries.at("CKESR")),
tXP (tCK * memSpec.memTimingSpec.entries.at("XP")),
tREFI (tCK * memSpec.memTimingSpec.entries.at("REFI")),
tREFIpb (tCK * memSpec.memTimingSpec.entries.at("REFIpb")),
tRFCab (tCK * memSpec.memTimingSpec.entries.at("RFCab")),
tRFCpb (tCK * memSpec.memTimingSpec.entries.at("RFCpb")),
tRREFD (tCK * memSpec.memTimingSpec.entries.at("RREFD")),
tXS (tCK * memSpec.memTimingSpec.entries.at("XS")),
tFAW (tCK * memSpec.memTimingSpec.entries.at("FAW")),
tPPD (tCK * memSpec.memTimingSpec.entries.at("PPD")),
tLK (tCK * memSpec.memTimingSpec.entries.at("LK")),
tACTPDE (tCK * memSpec.memTimingSpec.entries.at("ACTPDE")),
tPREPDE (tCK * memSpec.memTimingSpec.entries.at("PREPDE")),
tREFPDE (tCK * memSpec.memTimingSpec.entries.at("REFPDE")),
tRTRS (tCK * memSpec.memTimingSpec.entries.at("RTRS"))
memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks"),
memSpec.memarchitecturespec.entries.at( "nbrOfBankGroups"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks")
/ memSpec.memarchitecturespec.entries.at( "nbrOfBankGroups"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks")
* memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at( "nbrOfBankGroups")
* memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfDevices")),
per2BankOffset(memSpec.memarchitecturespec.entries.at("per2BankOffset")),
tRP (tCK * memSpec.memtimingspec.entries.at("RP")),
tRAS (tCK * memSpec.memtimingspec.entries.at("RAS")),
tRC (tCK * memSpec.memtimingspec.entries.at("RC")),
tRCDRD (tCK * memSpec.memtimingspec.entries.at("RCDRD")),
tRCDWR (tCK * memSpec.memtimingspec.entries.at("RCDWR")),
tRTP (tCK * memSpec.memtimingspec.entries.at("RTP")),
tRRDS (tCK * memSpec.memtimingspec.entries.at("RRDS")),
tRRDL (tCK * memSpec.memtimingspec.entries.at("RRDL")),
tCCDS (tCK * memSpec.memtimingspec.entries.at("CCDS")),
tCCDL (tCK * memSpec.memtimingspec.entries.at("CCDL")),
tRL (tCK * memSpec.memtimingspec.entries.at("RL")),
tWCK2CKPIN (tCK * memSpec.memtimingspec.entries.at("WCK2CKPIN")),
tWCK2CK (tCK * memSpec.memtimingspec.entries.at("WCK2CK")),
tWCK2DQO (tCK * memSpec.memtimingspec.entries.at("WCK2DQO")),
tRTW (tCK * memSpec.memtimingspec.entries.at("RTW")),
tWL (tCK * memSpec.memtimingspec.entries.at("WL")),
tWCK2DQI (tCK * memSpec.memtimingspec.entries.at("WCK2DQI")),
tWR (tCK * memSpec.memtimingspec.entries.at("WR")),
tWTRS (tCK * memSpec.memtimingspec.entries.at("WTRS")),
tWTRL (tCK * memSpec.memtimingspec.entries.at("WTRL")),
tPD (tCK * memSpec.memtimingspec.entries.at("PD")),
tCKESR (tCK * memSpec.memtimingspec.entries.at("CKESR")),
tXP (tCK * memSpec.memtimingspec.entries.at("XP")),
tREFI (tCK * memSpec.memtimingspec.entries.at("REFI")),
tREFIpb (tCK * memSpec.memtimingspec.entries.at("REFIpb")),
tRFCab (tCK * memSpec.memtimingspec.entries.at("RFCab")),
tRFCpb (tCK * memSpec.memtimingspec.entries.at("RFCpb")),
tRREFD (tCK * memSpec.memtimingspec.entries.at("RREFD")),
tXS (tCK * memSpec.memtimingspec.entries.at("XS")),
tFAW (tCK * memSpec.memtimingspec.entries.at("FAW")),
tPPD (tCK * memSpec.memtimingspec.entries.at("PPD")),
tLK (tCK * memSpec.memtimingspec.entries.at("LK")),
tACTPDE (tCK * memSpec.memtimingspec.entries.at("ACTPDE")),
tPREPDE (tCK * memSpec.memtimingspec.entries.at("PREPDE")),
tREFPDE (tCK * memSpec.memtimingspec.entries.at("REFPDE")),
tRTRS (tCK * memSpec.memtimingspec.entries.at("RTRS"))
{
uint64_t deviceSizeBits = static_cast<uint64_t>(banksPerRank) * rowsPerBank * columnsPerRow * bitWidth;
uint64_t deviceSizeBytes = deviceSizeBits / 8;

View File

@@ -45,47 +45,47 @@ using namespace tlm;
MemSpecHBM2::MemSpecHBM2(const DRAMSys::Config::MemSpec &memSpec)
: MemSpec(memSpec, MemoryType::HBM2,
memSpec.memArchitectureSpec.entries.at("nbrOfChannels"),
memSpec.memArchitectureSpec.entries.at("nbrOfPseudoChannels"),
memSpec.memArchitectureSpec.entries.at("nbrOfPseudoChannels"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBankGroups"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks")
/ memSpec.memArchitectureSpec.entries.at("nbrOfBankGroups"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks")
* memSpec.memArchitectureSpec.entries.at("nbrOfPseudoChannels"),
memSpec.memArchitectureSpec.entries.at("nbrOfBankGroups")
* memSpec.memArchitectureSpec.entries.at("nbrOfPseudoChannels"),
memSpec.memArchitectureSpec.entries.at("nbrOfDevices")),
tDQSCK (tCK * memSpec.memTimingSpec.entries.at("DQSCK")),
tRC (tCK * memSpec.memTimingSpec.entries.at("RC")),
tRAS (tCK * memSpec.memTimingSpec.entries.at("RAS")),
tRCDRD (tCK * memSpec.memTimingSpec.entries.at("RCDRD")),
tRCDWR (tCK * memSpec.memTimingSpec.entries.at("RCDWR")),
tRRDL (tCK * memSpec.memTimingSpec.entries.at("RRDL")),
tRRDS (tCK * memSpec.memTimingSpec.entries.at("RRDS")),
tFAW (tCK * memSpec.memTimingSpec.entries.at("FAW")),
tRTP (tCK * memSpec.memTimingSpec.entries.at("RTP")),
tRP (tCK * memSpec.memTimingSpec.entries.at("RP")),
tRL (tCK * memSpec.memTimingSpec.entries.at("RL")),
tWL (tCK * memSpec.memTimingSpec.entries.at("WL")),
tPL (tCK * memSpec.memTimingSpec.entries.at("PL")),
tWR (tCK * memSpec.memTimingSpec.entries.at("WR")),
tCCDL (tCK * memSpec.memTimingSpec.entries.at("CCDL")),
tCCDS (tCK * memSpec.memTimingSpec.entries.at("CCDS")),
tWTRL (tCK * memSpec.memTimingSpec.entries.at("WTRL")),
tWTRS (tCK * memSpec.memTimingSpec.entries.at("WTRS")),
tRTW (tCK * memSpec.memTimingSpec.entries.at("RTW")),
tXP (tCK * memSpec.memTimingSpec.entries.at("XP")),
tCKE (tCK * memSpec.memTimingSpec.entries.at("CKE")),
memSpec.memarchitecturespec.entries.at("nbrOfChannels"),
memSpec.memarchitecturespec.entries.at("nbrOfPseudoChannels"),
memSpec.memarchitecturespec.entries.at("nbrOfPseudoChannels"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBankGroups"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks")
/ memSpec.memarchitecturespec.entries.at("nbrOfBankGroups"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks")
* memSpec.memarchitecturespec.entries.at("nbrOfPseudoChannels"),
memSpec.memarchitecturespec.entries.at("nbrOfBankGroups")
* memSpec.memarchitecturespec.entries.at("nbrOfPseudoChannels"),
memSpec.memarchitecturespec.entries.at("nbrOfDevices")),
tDQSCK (tCK * memSpec.memtimingspec.entries.at("DQSCK")),
tRC (tCK * memSpec.memtimingspec.entries.at("RC")),
tRAS (tCK * memSpec.memtimingspec.entries.at("RAS")),
tRCDRD (tCK * memSpec.memtimingspec.entries.at("RCDRD")),
tRCDWR (tCK * memSpec.memtimingspec.entries.at("RCDWR")),
tRRDL (tCK * memSpec.memtimingspec.entries.at("RRDL")),
tRRDS (tCK * memSpec.memtimingspec.entries.at("RRDS")),
tFAW (tCK * memSpec.memtimingspec.entries.at("FAW")),
tRTP (tCK * memSpec.memtimingspec.entries.at("RTP")),
tRP (tCK * memSpec.memtimingspec.entries.at("RP")),
tRL (tCK * memSpec.memtimingspec.entries.at("RL")),
tWL (tCK * memSpec.memtimingspec.entries.at("WL")),
tPL (tCK * memSpec.memtimingspec.entries.at("PL")),
tWR (tCK * memSpec.memtimingspec.entries.at("WR")),
tCCDL (tCK * memSpec.memtimingspec.entries.at("CCDL")),
tCCDS (tCK * memSpec.memtimingspec.entries.at("CCDS")),
tWTRL (tCK * memSpec.memtimingspec.entries.at("WTRL")),
tWTRS (tCK * memSpec.memtimingspec.entries.at("WTRS")),
tRTW (tCK * memSpec.memtimingspec.entries.at("RTW")),
tXP (tCK * memSpec.memtimingspec.entries.at("XP")),
tCKE (tCK * memSpec.memtimingspec.entries.at("CKE")),
tPD (tCKE),
tCKESR (tCKE + tCK),
tXS (tCK * memSpec.memTimingSpec.entries.at("XS")),
tRFC (tCK * memSpec.memTimingSpec.entries.at("RFC")),
tRFCSB (tCK * memSpec.memTimingSpec.entries.at("RFCSB")),
tRREFD (tCK * memSpec.memTimingSpec.entries.at("RREFD")),
tREFI (tCK * memSpec.memTimingSpec.entries.at("REFI")),
tREFISB (tCK * memSpec.memTimingSpec.entries.at("REFISB"))
tXS (tCK * memSpec.memtimingspec.entries.at("XS")),
tRFC (tCK * memSpec.memtimingspec.entries.at("RFC")),
tRFCSB (tCK * memSpec.memtimingspec.entries.at("RFCSB")),
tRREFD (tCK * memSpec.memtimingspec.entries.at("RREFD")),
tREFI (tCK * memSpec.memtimingspec.entries.at("REFI")),
tREFISB (tCK * memSpec.memtimingspec.entries.at("REFISB"))
{
commandLengthInCycles[Command::ACT] = 2;

View File

@@ -45,47 +45,47 @@ using namespace tlm;
MemSpecLPDDR4::MemSpecLPDDR4(const DRAMSys::Config::MemSpec &memSpec)
: MemSpec(memSpec, MemoryType::LPDDR4,
memSpec.memArchitectureSpec.entries.at("nbrOfChannels"),
memSpec.memarchitecturespec.entries.at("nbrOfChannels"),
1,
memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks"),
memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks"),
1,
memSpec.memArchitectureSpec.entries.at("nbrOfBanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks")
* memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfDevices")),
tREFI (tCK * memSpec.memTimingSpec.entries.at("REFI")),
tREFIpb (tCK * memSpec.memTimingSpec.entries.at("REFIPB")),
tRFCab (tCK * memSpec.memTimingSpec.entries.at("RFCAB")),
tRFCpb (tCK * memSpec.memTimingSpec.entries.at("RFCPB")),
tRPab (tCK * memSpec.memTimingSpec.entries.at("RPAB")),
tRPpb (tCK * memSpec.memTimingSpec.entries.at("RPPB")),
tRCab (tCK * memSpec.memTimingSpec.entries.at("RCAB")),
tRCpb (tCK * memSpec.memTimingSpec.entries.at("RCPB")),
tPPD (tCK * memSpec.memTimingSpec.entries.at("PPD")),
tRAS (tCK * memSpec.memTimingSpec.entries.at("RAS")),
tRCD (tCK * memSpec.memTimingSpec.entries.at("RCD")),
tFAW (tCK * memSpec.memTimingSpec.entries.at("FAW")),
tRRD (tCK * memSpec.memTimingSpec.entries.at("RRD")),
tCCD (tCK * memSpec.memTimingSpec.entries.at("CCD")),
tRL (tCK * memSpec.memTimingSpec.entries.at("RL")),
tRPST (tCK * memSpec.memTimingSpec.entries.at("RPST")),
tDQSCK (tCK * memSpec.memTimingSpec.entries.at("DQSCK")),
tRTP (tCK * memSpec.memTimingSpec.entries.at("RTP")),
tWL (tCK * memSpec.memTimingSpec.entries.at("WL")),
tDQSS (tCK * memSpec.memTimingSpec.entries.at("DQSS")),
tDQS2DQ (tCK * memSpec.memTimingSpec.entries.at("DQS2DQ")),
tWR (tCK * memSpec.memTimingSpec.entries.at("WR")),
tWPRE (tCK * memSpec.memTimingSpec.entries.at("WPRE")),
tWTR (tCK * memSpec.memTimingSpec.entries.at("WTR")),
tXP (tCK * memSpec.memTimingSpec.entries.at("XP")),
tSR (tCK * memSpec.memTimingSpec.entries.at("SR")),
tXSR (tCK * memSpec.memTimingSpec.entries.at("XSR")),
tESCKE (tCK * memSpec.memTimingSpec.entries.at("ESCKE")),
tCKE (tCK * memSpec.memTimingSpec.entries.at("CKE")),
tCMDCKE (tCK * memSpec.memTimingSpec.entries.at("CMDCKE")),
tRTRS (tCK * memSpec.memTimingSpec.entries.at("RTRS"))
memSpec.memarchitecturespec.entries.at("nbrOfBanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks")
* memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfDevices")),
tREFI (tCK * memSpec.memtimingspec.entries.at("REFI")),
tREFIpb (tCK * memSpec.memtimingspec.entries.at("REFIPB")),
tRFCab (tCK * memSpec.memtimingspec.entries.at("RFCAB")),
tRFCpb (tCK * memSpec.memtimingspec.entries.at("RFCPB")),
tRPab (tCK * memSpec.memtimingspec.entries.at("RPAB")),
tRPpb (tCK * memSpec.memtimingspec.entries.at("RPPB")),
tRCab (tCK * memSpec.memtimingspec.entries.at("RCAB")),
tRCpb (tCK * memSpec.memtimingspec.entries.at("RCPB")),
tPPD (tCK * memSpec.memtimingspec.entries.at("PPD")),
tRAS (tCK * memSpec.memtimingspec.entries.at("RAS")),
tRCD (tCK * memSpec.memtimingspec.entries.at("RCD")),
tFAW (tCK * memSpec.memtimingspec.entries.at("FAW")),
tRRD (tCK * memSpec.memtimingspec.entries.at("RRD")),
tCCD (tCK * memSpec.memtimingspec.entries.at("CCD")),
tRL (tCK * memSpec.memtimingspec.entries.at("RL")),
tRPST (tCK * memSpec.memtimingspec.entries.at("RPST")),
tDQSCK (tCK * memSpec.memtimingspec.entries.at("DQSCK")),
tRTP (tCK * memSpec.memtimingspec.entries.at("RTP")),
tWL (tCK * memSpec.memtimingspec.entries.at("WL")),
tDQSS (tCK * memSpec.memtimingspec.entries.at("DQSS")),
tDQS2DQ (tCK * memSpec.memtimingspec.entries.at("DQS2DQ")),
tWR (tCK * memSpec.memtimingspec.entries.at("WR")),
tWPRE (tCK * memSpec.memtimingspec.entries.at("WPRE")),
tWTR (tCK * memSpec.memtimingspec.entries.at("WTR")),
tXP (tCK * memSpec.memtimingspec.entries.at("XP")),
tSR (tCK * memSpec.memtimingspec.entries.at("SR")),
tXSR (tCK * memSpec.memtimingspec.entries.at("XSR")),
tESCKE (tCK * memSpec.memtimingspec.entries.at("ESCKE")),
tCKE (tCK * memSpec.memtimingspec.entries.at("CKE")),
tCMDCKE (tCK * memSpec.memtimingspec.entries.at("CMDCKE")),
tRTRS (tCK * memSpec.memtimingspec.entries.at("RTRS"))
{
commandLengthInCycles[Command::ACT] = 4;
commandLengthInCycles[Command::PREPB] = 2;

View File

@@ -45,40 +45,40 @@ using namespace tlm;
MemSpecSTTMRAM::MemSpecSTTMRAM(const DRAMSys::Config::MemSpec &memSpec)
: MemSpec(memSpec, MemoryType::STTMRAM,
memSpec.memArchitectureSpec.entries.at("nbrOfChannels"),
memSpec.memarchitecturespec.entries.at("nbrOfChannels"),
1,
memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks"),
memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks"),
1,
memSpec.memArchitectureSpec.entries.at("nbrOfBanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks")
* memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfDevices")),
tCKE (tCK * memSpec.memTimingSpec.entries.at("CKE")),
memSpec.memarchitecturespec.entries.at("nbrOfBanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks")
* memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfDevices")),
tCKE (tCK * memSpec.memtimingspec.entries.at("CKE")),
tPD (tCKE),
tCKESR (tCK * memSpec.memTimingSpec.entries.at("CKESR")),
tDQSCK (tCK * memSpec.memTimingSpec.entries.at("DQSCK")),
tRAS (tCK * memSpec.memTimingSpec.entries.at("RAS")),
tRC (tCK * memSpec.memTimingSpec.entries.at("RC")),
tRCD (tCK * memSpec.memTimingSpec.entries.at("RCD")),
tRL (tCK * memSpec.memTimingSpec.entries.at("RL")),
tRTP (tCK * memSpec.memTimingSpec.entries.at("RTP")),
tWL (tCK * memSpec.memTimingSpec.entries.at("WL")),
tWR (tCK * memSpec.memTimingSpec.entries.at("WR")),
tXP (tCK * memSpec.memTimingSpec.entries.at("XP")),
tXS (tCK * memSpec.memTimingSpec.entries.at("XS")),
tCCD (tCK * memSpec.memTimingSpec.entries.at("CCD")),
tFAW (tCK * memSpec.memTimingSpec.entries.at("FAW")),
tRP (tCK * memSpec.memTimingSpec.entries.at("RP")),
tRRD (tCK * memSpec.memTimingSpec.entries.at("RRD")),
tWTR (tCK * memSpec.memTimingSpec.entries.at("WTR")),
tAL (tCK * memSpec.memTimingSpec.entries.at("AL")),
tXPDLL (tCK * memSpec.memTimingSpec.entries.at("XPDLL")),
tXSDLL (tCK * memSpec.memTimingSpec.entries.at("XSDLL")),
tACTPDEN (tCK * memSpec.memTimingSpec.entries.at("ACTPDEN")),
tPRPDEN (tCK * memSpec.memTimingSpec.entries.at("PRPDEN")),
tRTRS (tCK * memSpec.memTimingSpec.entries.at("RTRS"))
tCKESR (tCK * memSpec.memtimingspec.entries.at("CKESR")),
tDQSCK (tCK * memSpec.memtimingspec.entries.at("DQSCK")),
tRAS (tCK * memSpec.memtimingspec.entries.at("RAS")),
tRC (tCK * memSpec.memtimingspec.entries.at("RC")),
tRCD (tCK * memSpec.memtimingspec.entries.at("RCD")),
tRL (tCK * memSpec.memtimingspec.entries.at("RL")),
tRTP (tCK * memSpec.memtimingspec.entries.at("RTP")),
tWL (tCK * memSpec.memtimingspec.entries.at("WL")),
tWR (tCK * memSpec.memtimingspec.entries.at("WR")),
tXP (tCK * memSpec.memtimingspec.entries.at("XP")),
tXS (tCK * memSpec.memtimingspec.entries.at("XS")),
tCCD (tCK * memSpec.memtimingspec.entries.at("CCD")),
tFAW (tCK * memSpec.memtimingspec.entries.at("FAW")),
tRP (tCK * memSpec.memtimingspec.entries.at("RP")),
tRRD (tCK * memSpec.memtimingspec.entries.at("RRD")),
tWTR (tCK * memSpec.memtimingspec.entries.at("WTR")),
tAL (tCK * memSpec.memtimingspec.entries.at("AL")),
tXPDLL (tCK * memSpec.memtimingspec.entries.at("XPDLL")),
tXSDLL (tCK * memSpec.memtimingspec.entries.at("XSDLL")),
tACTPDEN (tCK * memSpec.memtimingspec.entries.at("ACTPDEN")),
tPRPDEN (tCK * memSpec.memtimingspec.entries.at("PRPDEN")),
tRTRS (tCK * memSpec.memtimingspec.entries.at("RTRS"))
{
uint64_t deviceSizeBits = static_cast<uint64_t>(banksPerRank) * rowsPerBank * columnsPerRow * bitWidth;
uint64_t deviceSizeBytes = deviceSizeBits / 8;

View File

@@ -45,67 +45,67 @@ using namespace tlm;
MemSpecWideIO::MemSpecWideIO(const DRAMSys::Config::MemSpec &memSpec)
: MemSpec(memSpec, MemoryType::WideIO,
memSpec.memArchitectureSpec.entries.at("nbrOfChannels"),
memSpec.memarchitecturespec.entries.at("nbrOfChannels"),
1,
memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks"),
memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks"),
1,
memSpec.memArchitectureSpec.entries.at("nbrOfBanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks")
* memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfDevices")),
tCKE (tCK * memSpec.memTimingSpec.entries.at("CKE")),
tCKESR (tCK * memSpec.memTimingSpec.entries.at("CKESR")),
tDQSCK (tCK * memSpec.memTimingSpec.entries.at("DQSCK")),
tAC (tCK * memSpec.memTimingSpec.entries.at("AC")),
tRAS (tCK * memSpec.memTimingSpec.entries.at("RAS")),
tRC (tCK * memSpec.memTimingSpec.entries.at("RC")),
tRCD (tCK * memSpec.memTimingSpec.entries.at("RCD")),
tRL (tCK * memSpec.memTimingSpec.entries.at("RL")),
tWL (tCK * memSpec.memTimingSpec.entries.at("WL")),
tWR (tCK * memSpec.memTimingSpec.entries.at("WR")),
tXP (tCK * memSpec.memTimingSpec.entries.at("XP")),
tXSR (tCK * memSpec.memTimingSpec.entries.at("XSR")),
tCCD_R (tCK * memSpec.memTimingSpec.entries.at("CCD_R")),
tCCD_W (tCK * memSpec.memTimingSpec.entries.at("CCD_W")),
tREFI (tCK * memSpec.memTimingSpec.entries.at("REFI")),
tRFC (tCK * memSpec.memTimingSpec.entries.at("RFC")),
tRP (tCK * memSpec.memTimingSpec.entries.at("RP")),
tRRD (tCK * memSpec.memTimingSpec.entries.at("RRD")),
tTAW (tCK * memSpec.memTimingSpec.entries.at("TAW")),
tWTR (tCK * memSpec.memTimingSpec.entries.at("WTR")),
tRTRS (tCK * memSpec.memTimingSpec.entries.at("RTRS")),
iDD0 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd0") : 0),
iDD2N (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd2n") : 0),
iDD3N (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd3n") : 0),
iDD4R (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd4r") : 0),
iDD4W (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd4w") : 0),
iDD5 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd5") : 0),
iDD6 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd6") : 0),
vDD (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("vdd") : 0),
iDD02 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd02") : 0),
iDD2P0 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd2p0") : 0),
iDD2P02 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd2p02") : 0),
iDD2P1 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd2p1") : 0),
iDD2P12 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd2p12") : 0),
iDD2N2 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd2n2") : 0),
iDD3P0 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd3p0") : 0),
iDD3P02 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd3p02") : 0),
iDD3P1 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd3p1") : 0),
iDD3P12 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd3p12") : 0),
iDD3N2 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd3n2") : 0),
iDD4R2 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd4r2") : 0),
iDD4W2 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd4w2") : 0),
iDD52 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd52") : 0),
iDD62 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("idd62") : 0),
vDD2 (memSpec.memPowerSpec.has_value() ? memSpec.memPowerSpec.value().entries.at("vdd2") : 0)
memSpec.memarchitecturespec.entries.at("nbrOfBanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks")
* memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfDevices")),
tCKE (tCK * memSpec.memtimingspec.entries.at("CKE")),
tCKESR (tCK * memSpec.memtimingspec.entries.at("CKESR")),
tDQSCK (tCK * memSpec.memtimingspec.entries.at("DQSCK")),
tAC (tCK * memSpec.memtimingspec.entries.at("AC")),
tRAS (tCK * memSpec.memtimingspec.entries.at("RAS")),
tRC (tCK * memSpec.memtimingspec.entries.at("RC")),
tRCD (tCK * memSpec.memtimingspec.entries.at("RCD")),
tRL (tCK * memSpec.memtimingspec.entries.at("RL")),
tWL (tCK * memSpec.memtimingspec.entries.at("WL")),
tWR (tCK * memSpec.memtimingspec.entries.at("WR")),
tXP (tCK * memSpec.memtimingspec.entries.at("XP")),
tXSR (tCK * memSpec.memtimingspec.entries.at("XSR")),
tCCD_R (tCK * memSpec.memtimingspec.entries.at("CCD_R")),
tCCD_W (tCK * memSpec.memtimingspec.entries.at("CCD_W")),
tREFI (tCK * memSpec.memtimingspec.entries.at("REFI")),
tRFC (tCK * memSpec.memtimingspec.entries.at("RFC")),
tRP (tCK * memSpec.memtimingspec.entries.at("RP")),
tRRD (tCK * memSpec.memtimingspec.entries.at("RRD")),
tTAW (tCK * memSpec.memtimingspec.entries.at("TAW")),
tWTR (tCK * memSpec.memtimingspec.entries.at("WTR")),
tRTRS (tCK * memSpec.memtimingspec.entries.at("RTRS")),
iDD0 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd0") : 0),
iDD2N (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd2n") : 0),
iDD3N (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd3n") : 0),
iDD4R (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd4r") : 0),
iDD4W (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd4w") : 0),
iDD5 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd5") : 0),
iDD6 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd6") : 0),
vDD (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("vdd") : 0),
iDD02 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd02") : 0),
iDD2P0 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd2p0") : 0),
iDD2P02 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd2p02") : 0),
iDD2P1 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd2p1") : 0),
iDD2P12 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd2p12") : 0),
iDD2N2 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd2n2") : 0),
iDD3P0 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd3p0") : 0),
iDD3P02 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd3p02") : 0),
iDD3P1 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd3p1") : 0),
iDD3P12 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd3p12") : 0),
iDD3N2 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd3n2") : 0),
iDD4R2 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd4r2") : 0),
iDD4W2 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd4w2") : 0),
iDD52 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd52") : 0),
iDD62 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("idd62") : 0),
vDD2 (memSpec.mempowerspec.has_value() ? memSpec.mempowerspec.value().entries.at("vdd2") : 0)
{
uint64_t deviceSizeBits = static_cast<uint64_t>(banksPerRank) * rowsPerBank * columnsPerRow * bitWidth;
uint64_t deviceSizeBytes = deviceSizeBits / 8;
memorySizeBytes = deviceSizeBytes * ranksPerChannel * numberOfChannels;
if (!memSpec.memPowerSpec.has_value())
if (!memSpec.mempowerspec.has_value())
SC_REPORT_FATAL("MemSpec", "No power spec defined!");
std::cout << headline << std::endl;

View File

@@ -45,43 +45,43 @@ using namespace tlm;
MemSpecWideIO2::MemSpecWideIO2(const DRAMSys::Config::MemSpec &memSpec)
: MemSpec(memSpec, MemoryType::WideIO2,
memSpec.memArchitectureSpec.entries.at("nbrOfChannels"),
memSpec.memarchitecturespec.entries.at("nbrOfChannels"),
1,
memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks"),
memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks"),
1,
memSpec.memArchitectureSpec.entries.at("nbrOfBanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfBanks")
* memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfRanks"),
memSpec.memArchitectureSpec.entries.at("nbrOfDevices")),
tDQSCK (tCK * memSpec.memTimingSpec.entries.at("DQSCK")),
tDQSS (tCK * memSpec.memTimingSpec.entries.at("DQSS")),
tCKE (tCK * memSpec.memTimingSpec.entries.at("CKE")),
tRL (tCK * memSpec.memTimingSpec.entries.at("RL")),
tWL (tCK * memSpec.memTimingSpec.entries.at("WL")),
tRCpb (tCK * memSpec.memTimingSpec.entries.at("RCPB")),
tRCab (tCK * memSpec.memTimingSpec.entries.at("RCAB")),
tCKESR (tCK * memSpec.memTimingSpec.entries.at("CKESR")),
tXSR (tCK * memSpec.memTimingSpec.entries.at("XSR")),
tXP (tCK * memSpec.memTimingSpec.entries.at("XP")),
tCCD (tCK * memSpec.memTimingSpec.entries.at("CCD")),
tRTP (tCK * memSpec.memTimingSpec.entries.at("RTP")),
tRCD (tCK * memSpec.memTimingSpec.entries.at("RCD")),
tRPpb (tCK * memSpec.memTimingSpec.entries.at("RPPB")),
tRPab (tCK * memSpec.memTimingSpec.entries.at("RPAB")),
tRAS (tCK * memSpec.memTimingSpec.entries.at("RAS")),
tWR (tCK * memSpec.memTimingSpec.entries.at("WR")),
tWTR (tCK * memSpec.memTimingSpec.entries.at("WTR")),
tRRD (tCK * memSpec.memTimingSpec.entries.at("RRD")),
tFAW (tCK * memSpec.memTimingSpec.entries.at("FAW")),
tREFI (tCK * static_cast<unsigned>(memSpec.memTimingSpec.entries.at("REFI")
* memSpec.memTimingSpec.entries.at("REFM"))),
tREFIpb (tCK * static_cast<unsigned>(memSpec.memTimingSpec.entries.at("REFIPB")
* memSpec.memTimingSpec.entries.at("REFM"))),
tRFCab (tCK * memSpec.memTimingSpec.entries.at("RFCAB")),
tRFCpb (tCK * memSpec.memTimingSpec.entries.at("RFCPB")),
tRTRS (tCK * memSpec.memTimingSpec.entries.at("RTRS"))
memSpec.memarchitecturespec.entries.at("nbrOfBanks"),
memSpec.memarchitecturespec.entries.at("nbrOfBanks")
* memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfRanks"),
memSpec.memarchitecturespec.entries.at("nbrOfDevices")),
tDQSCK (tCK * memSpec.memtimingspec.entries.at("DQSCK")),
tDQSS (tCK * memSpec.memtimingspec.entries.at("DQSS")),
tCKE (tCK * memSpec.memtimingspec.entries.at("CKE")),
tRL (tCK * memSpec.memtimingspec.entries.at("RL")),
tWL (tCK * memSpec.memtimingspec.entries.at("WL")),
tRCpb (tCK * memSpec.memtimingspec.entries.at("RCPB")),
tRCab (tCK * memSpec.memtimingspec.entries.at("RCAB")),
tCKESR (tCK * memSpec.memtimingspec.entries.at("CKESR")),
tXSR (tCK * memSpec.memtimingspec.entries.at("XSR")),
tXP (tCK * memSpec.memtimingspec.entries.at("XP")),
tCCD (tCK * memSpec.memtimingspec.entries.at("CCD")),
tRTP (tCK * memSpec.memtimingspec.entries.at("RTP")),
tRCD (tCK * memSpec.memtimingspec.entries.at("RCD")),
tRPpb (tCK * memSpec.memtimingspec.entries.at("RPPB")),
tRPab (tCK * memSpec.memtimingspec.entries.at("RPAB")),
tRAS (tCK * memSpec.memtimingspec.entries.at("RAS")),
tWR (tCK * memSpec.memtimingspec.entries.at("WR")),
tWTR (tCK * memSpec.memtimingspec.entries.at("WTR")),
tRRD (tCK * memSpec.memtimingspec.entries.at("RRD")),
tFAW (tCK * memSpec.memtimingspec.entries.at("FAW")),
tREFI (tCK * static_cast<unsigned>(memSpec.memtimingspec.entries.at("REFI")
* memSpec.memtimingspec.entries.at("REFM"))),
tREFIpb (tCK * static_cast<unsigned>(memSpec.memtimingspec.entries.at("REFIPB")
* memSpec.memtimingspec.entries.at("REFM"))),
tRFCab (tCK * memSpec.memtimingspec.entries.at("RFCAB")),
tRFCpb (tCK * memSpec.memtimingspec.entries.at("RFCPB")),
tRTRS (tCK * memSpec.memtimingspec.entries.at("RTRS"))
{
uint64_t deviceSizeBits = static_cast<uint64_t>(banksPerRank) * rowsPerBank * columnsPerRow * bitWidth;
uint64_t deviceSizeBytes = deviceSizeBits / 8;

View File

@@ -546,7 +546,10 @@ void Controller::manageResponses()
tlm_generic_payload* nextTransInRespQueue = respQueue->nextPayload();
if (nextTransInRespQueue != nullptr)
{
numberOfBeatsServed += ControllerExtension::getBurstLength(*nextTransInRespQueue);
// Ignore ECC requests
if (nextTransInRespQueue->get_extension<EccExtension>() == nullptr)
numberOfBeatsServed += ControllerExtension::getBurstLength(*nextTransInRespQueue);
if (ChildExtension::isChildTrans(*nextTransInRespQueue))
{
tlm_generic_payload& parentTrans = ChildExtension::getParentTrans(*nextTransInRespQueue);

View File

@@ -37,53 +37,54 @@
*/
#include "AddressDecoder.h"
#include "DRAMSys/configuration/Configuration.h"
#include <cmath>
#include <iostream>
#include <iomanip>
#include <bitset>
AddressDecoder::AddressDecoder(const Configuration& config, const DRAMSys::Config::AddressMapping& addressMapping)
AddressDecoder::AddressDecoder(const DRAMSys::Config::AddressMapping &addressMapping, const MemSpec &memSpec)
{
if (const auto& channelBits = addressMapping.channelBits)
if (const auto &channelBits = addressMapping.CHANNEL_BIT)
{
std::copy(channelBits->begin(), channelBits->end(), std::back_inserter(vChannelBits));
}
if (const auto& rankBits = addressMapping.rankBits)
if (const auto &rankBits = addressMapping.RANK_BIT)
{
std::copy(rankBits->begin(), rankBits->end(), std::back_inserter(vRankBits));
}
if (const auto& bankGroupBits = addressMapping.bankGroupBits)
if (const auto& bankGroupBits = addressMapping.BANKGROUP_BIT)
{
std::copy(bankGroupBits->begin(), bankGroupBits->end(), std::back_inserter(vBankGroupBits));
}
if (const auto& byteBits = addressMapping.byteBits)
if (const auto &byteBits = addressMapping.BYTE_BIT)
{
std::copy(byteBits->begin(), byteBits->end(), std::back_inserter(vByteBits));
}
if (const auto& xorBits = addressMapping.xorBits)
if (const auto &xorBits = addressMapping.XOR)
{
for (const auto& xorBit : *xorBits)
{
vXor.emplace_back(xorBit.first, xorBit.second);
vXor.emplace_back(xorBit.FIRST, xorBit.SECOND);
}
}
if (const auto& bankBits = addressMapping.bankBits)
if (const auto &bankBits = addressMapping.BANK_BIT)
{
std::copy(bankBits->begin(), bankBits->end(), std::back_inserter(vBankBits));
}
if (const auto& rowBits = addressMapping.rowBits)
if (const auto &rowBits = addressMapping.ROW_BIT)
{
std::copy(rowBits->begin(), rowBits->end(), std::back_inserter(vRowBits));
}
if (const auto& columnBits = addressMapping.columnBits)
if (const auto &columnBits = addressMapping.COLUMN_BIT)
{
std::copy(columnBits->begin(), columnBits->end(), std::back_inserter(vColumnBits));
}
@@ -113,8 +114,6 @@ AddressDecoder::AddressDecoder(const Configuration& config, const DRAMSys::Confi
SC_REPORT_FATAL("AddressDecoder", "Not all address bits occur exactly once");
}
const MemSpec& memSpec = *config.memSpec;
unsigned highestByteBit = *std::max_element(vByteBits.begin(), vByteBits.end());
for (unsigned bitPosition = 0; bitPosition <= highestByteBit; bitPosition++)
@@ -213,6 +212,41 @@ unsigned AddressDecoder::decodeChannel(uint64_t encAddr) const
return channel;
}
uint64_t AddressDecoder::encodeAddress(DecodedAddress decodedAddress) const
{
// Convert absoulte addressing for bank, bankgroup to relative
decodedAddress.bankgroup = decodedAddress.bankgroup % bankgroupsPerRank;
decodedAddress.bank = decodedAddress.bank % banksPerGroup;
uint64_t address = 0;
for (unsigned i = 0; i < vChannelBits.size(); i++)
address |= ((decodedAddress.channel >> i) & 0x1) << vChannelBits[i];
for (unsigned i = 0; i < vRankBits.size(); i++)
address |= ((decodedAddress.rank >> i) & 0x1) << vRankBits[i];
for (unsigned i = 0; i < vBankGroupBits.size(); i++)
address |= ((decodedAddress.bankgroup >> i) & 0x1) << vBankGroupBits[i];
for (unsigned i = 0; i < vBankBits.size(); i++)
address |= ((decodedAddress.bank >> i) & 0x1) << vBankBits[i];
for (unsigned i = 0; i < vRowBits.size(); i++)
address |= ((decodedAddress.row >> i) & 0x1) << vRowBits[i];
for (unsigned i = 0; i < vColumnBits.size(); i++)
address |= ((decodedAddress.column >> i) & 0x1) << vColumnBits[i];
for (unsigned i = 0; i < vByteBits.size(); i++)
address |= ((decodedAddress.byte >> i) & 0x1) << vByteBits[i];
// TODO: XOR encoding
return address;
}
void AddressDecoder::print() const
{
std::cout << headline << std::endl;

View File

@@ -39,9 +39,8 @@
#ifndef ADDRESSDECODER_H
#define ADDRESSDECODER_H
#include "DRAMSys/configuration/Configuration.h"
#include "DRAMSys/config/DRAMSysConfiguration.h"
#include "DRAMSys/configuration/Configuration.h"
#include <vector>
#include <utility>
@@ -69,9 +68,10 @@ struct DecodedAddress
class AddressDecoder
{
public:
AddressDecoder(const Configuration& config, const DRAMSys::Config::AddressMapping& addressMapping);
AddressDecoder(const DRAMSys::Config::AddressMapping &addressMapping, const MemSpec &memSpec);
[[nodiscard]] DecodedAddress decodeAddress(uint64_t encAddr) const;
[[nodiscard]] unsigned decodeChannel(uint64_t encAddr) const;
[[nodiscard]] uint64_t encodeAddress(DecodedAddress decodedAddress) const;
void print() const;
private:

View File

@@ -86,9 +86,9 @@ DRAMSys::DRAMSys(const sc_core::sc_module_name& name,
// Load configLib and initialize modules
// Important: The memSpec needs to be the first configuration to be loaded!
config.loadMemSpec(configLib.memSpec);
config.loadMCConfig(configLib.mcConfig);
config.loadSimConfig(configLib.simConfig);
config.loadMemSpec(configLib.memspec);
config.loadMCConfig(configLib.mcconfig);
config.loadSimConfig(configLib.simconfig);
// Setup the debug manager:
setupDebugManager(config.simulationName);
@@ -96,7 +96,7 @@ DRAMSys::DRAMSys(const sc_core::sc_module_name& name,
if (initAndBind)
{
// Instantiate all internal DRAMSys modules:
instantiateModules(configLib.addressMapping);
instantiateModules(configLib.addressmapping);
// Connect all internal DRAMSys modules:
bindSockets();
report(headline);
@@ -157,7 +157,7 @@ void DRAMSys::setupDebugManager(NDEBUG_UNUSED(const std::string& traceName)) con
void DRAMSys::instantiateModules(const ::DRAMSys::Config::AddressMapping& addressMapping)
{
addressDecoder = std::make_unique<AddressDecoder>(config, addressMapping);
addressDecoder = std::make_unique<AddressDecoder>(addressMapping, *config.memSpec);
addressDecoder->print();
// Create arbiter

View File

@@ -70,6 +70,7 @@ public:
const ::DRAMSys::Config::Configuration& configLib);
const Configuration& getConfig() const;
const AddressDecoder &getAddressDecoder() const { return *addressDecoder; }
protected:
DRAMSys(const sc_core::sc_module_name& name,

View File

@@ -71,9 +71,9 @@ DRAMSysRecordable::DRAMSysRecordable(const sc_core::sc_module_name& name, const
// is prepended to the simulation name if found.
std::string traceName;
if (!configLib.simulationId.empty())
if (!configLib.simulationid.empty())
{
std::string sid = configLib.simulationId;
std::string sid = configLib.simulationid;
traceName = sid + '_' + config.simulationName;
}
else
@@ -110,9 +110,14 @@ void DRAMSysRecordable::setupTlmRecorders(const std::string& traceName,
std::string dbName = std::string(name()) + "_" + traceName + "_ch" + std::to_string(i) + ".tdb";
std::string recorderName = "tlmRecorder" + std::to_string(i);
nlohmann::json mcconfig;
nlohmann::json memspec;
mcconfig[Config::McConfig::KEY] = configLib.mcconfig;
memspec[Config::MemSpec::KEY] = configLib.memspec;
tlmRecorders.emplace_back(recorderName, config, dbName);
tlmRecorders.back().recordMcConfig(::DRAMSys::Config::dump(configLib.mcConfig));
tlmRecorders.back().recordMemspec(::DRAMSys::Config::dump(configLib.memSpec));
tlmRecorders.back().recordMcConfig(mcconfig.dump());
tlmRecorders.back().recordMemspec(memspec.dump());
tlmRecorders.back().recordTraceNames(config.simulationName);
}
}
@@ -120,7 +125,7 @@ void DRAMSysRecordable::setupTlmRecorders(const std::string& traceName,
void DRAMSysRecordable::instantiateModules(const std::string& traceName,
const ::DRAMSys::Config::Configuration& configLib)
{
addressDecoder = std::make_unique<AddressDecoder>(config, configLib.addressMapping);
addressDecoder = std::make_unique<AddressDecoder>(configLib.addressmapping, *config.memSpec);
addressDecoder->print();
// Create and properly initialize TLM recorders.

View File

@@ -43,15 +43,25 @@ project(DRAMSys_Simulator)
file(GLOB_RECURSE SOURCE_FILES CONFIGURE_DEPENDS *.cpp)
file(GLOB_RECURSE HEADER_FILES CONFIGURE_DEPENDS *.h;*.hpp)
add_executable(DRAMSys ${SOURCE_FILES} ${HEADER_FILES})
target_include_directories(DRAMSys PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
list(FILTER SOURCE_FILES EXCLUDE REGEX "main.cpp")
add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES} ${HEADER_FILES})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(${PROJECT_NAME}
PUBLIC
Threads::Threads
DRAMSys::libdramsys
)
add_executable(DRAMSys
main.cpp
)
target_link_libraries(DRAMSys
PRIVATE
Threads::Threads
SystemC::systemc
DRAMSys::libdramsys
DRAMSys_Simulator
)
build_source_group()
diagnostics_print(DRAMSys)

19
src/simulator/README.md Normal file
View File

@@ -0,0 +1,19 @@
# Simulator
The **standalone** simulator features a set of trace players, traffic generators and miscellaneous components that can be coupled with DRAMSys.
## Concept
Initiators in the simulator are split up into two disctinct components: **RequestProducers** and **RequestIssuers**.
**RequestProducers** are simple C++ classes that implement the `RequestProducer` interface. Upon calling the `nextRequest()` method of a producer, a new `Request` is either generated on-the-fly or constructed from a trace file.
**RequestIssuers** are the SystemC modules that connect with DRAMSys. Issuers have no knowledge of where the requests are coming from. They simply call their `nextRequest()` callback that it has been passed in the constructor to obtain the next request to be sent to DRAMSys. Using this concept, the generation and the issuing of request is completely decoupled to make very flexible initiator designs possible.
**Initiators** implement the `Initiator` interface, which describes how the initiator is bound to DRAMSys. This abstracts over the actual socket type used by the initiator.
Complex initiators may implement the interface directly, but for simple cases, there exists the templated `SimpleInitiator<Producer>` class. This specialized initiator consists of only one producer and one issuer that operate together. The `StlPlayer` and `RowHammer` issuers make use of the `SimpleInitiator`.
The `TrafficGenerator` is one example of a direct implementation of the `Initiator` interface, as it consists of many producers (which represent the states of the state machine) but of only one issuer.
**Requests** are an abstraction over the TLM payloads the issuer generates. A request describes whether it is a read or a write access or an internal `Stop` request that tells the initiator to terminate.
The **delay** field specifies the time that should pass between the issuance of the previous and the current request.
## Configuration
A detailed description on how to configure the traffic generators of the simulator can be found [here](../../configs/README.md).

197
src/simulator/main.cpp Normal file
View File

@@ -0,0 +1,197 @@
/*
* Copyright (c) 2023, 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:
* Derek Christ
*/
#include "simulator/Initiator.h"
#include "simulator/MemoryManager.h"
#include "simulator/SimpleInitiator.h"
#include "simulator/generator/TrafficGenerator.h"
#include "simulator/hammer/RowHammer.h"
#include "simulator/player/StlPlayer.h"
#include "simulator/util.h"
#include <DRAMSys/simulation/DRAMSysRecordable.h>
#include <systemc>
#include <tlm>
#include <tlm_utils/peq_with_cb_and_phase.h>
#include <tlm_utils/simple_initiator_socket.h>
#include <filesystem>
#include <fstream>
#include <random>
static constexpr std::string_view TRACE_DIRECTORY = "traces";
int sc_main(int argc, char **argv)
{
std::filesystem::path resourceDirectory = DRAMSYS_RESOURCE_DIR;
if (argc >= 3)
{
resourceDirectory = argv[2];
}
std::filesystem::path baseConfig = resourceDirectory / "ddr5-example.json";
if (argc >= 2)
{
baseConfig = argv[1];
}
DRAMSys::Config::Configuration configuration =
DRAMSys::Config::from_path(baseConfig.c_str(), resourceDirectory.c_str());
if (!configuration.tracesetup.has_value())
SC_REPORT_FATAL("Simulator", "No traffic initiators specified");
std::unique_ptr<DRAMSys::DRAMSys> dramSys;
if (configuration.simconfig.DatabaseRecording)
{
dramSys = std::make_unique<DRAMSys::DRAMSysRecordable>("DRAMSys", configuration);
}
else
{
dramSys = std::make_unique<DRAMSys::DRAMSys>("DRAMSys", configuration);
}
bool storageEnabled = dramSys->getConfig().storeMode == Configuration::StoreMode::Store;
MemoryManager memoryManager(storageEnabled);
std::vector<std::unique_ptr<Initiator>> initiators;
unsigned int terminatedInitiators = 0;
auto termianteInitiator = [&initiators, &terminatedInitiators]()
{
terminatedInitiators++;
if (terminatedInitiators == initiators.size())
sc_core::sc_stop();
};
uint64_t totalTransactions{};
uint64_t transactionsFinished = 0;
auto transactionFinished = [&totalTransactions, &transactionsFinished]()
{
transactionsFinished++;
loadBar(transactionsFinished, totalTransactions);
};
for (auto const &initiator_config : configuration.tracesetup.value())
{
uint64_t memorySize = dramSys->getConfig().memSpec->getSimMemSizeInBytes();
unsigned int defaultDataLength = dramSys->getConfig().memSpec->defaultBytesPerBurst;
auto initiator = std::visit(
[=, &memoryManager](auto &&config) -> std::unique_ptr<Initiator>
{
using T = std::decay_t<decltype(config)>;
if constexpr (std::is_same_v<T, DRAMSys::Config::TrafficGenerator> ||
std::is_same_v<T, DRAMSys::Config::TrafficGeneratorStateMachine>)
{
return std::make_unique<TrafficGenerator>(config,
memoryManager,
memorySize,
defaultDataLength,
transactionFinished,
termianteInitiator);
}
else if constexpr (std::is_same_v<T, DRAMSys::Config::TracePlayer>)
{
std::filesystem::path tracePath =
resourceDirectory / TRACE_DIRECTORY / config.name;
StlPlayer::TraceType traceType;
auto extension = tracePath.extension();
if (extension == ".stl")
traceType = StlPlayer::TraceType::Absolute;
else if (extension == ".rtl")
traceType = StlPlayer::TraceType::Relative;
else
{
std::string report = extension.string() + " is not a valid trace format.";
SC_REPORT_FATAL("Simulator", report.c_str());
}
StlPlayer player(
tracePath.c_str(), config.clkMhz, defaultDataLength, traceType, false);
return std::make_unique<SimpleInitiator<StlPlayer>>(config.name.c_str(),
memoryManager,
std::nullopt,
std::nullopt,
transactionFinished,
termianteInitiator,
std::move(player));
}
else if constexpr (std::is_same_v<T, DRAMSys::Config::RowHammer>)
{
RowHammer hammer(
config.numRequests, config.clkMhz, config.rowIncrement, defaultDataLength);
return std::make_unique<SimpleInitiator<RowHammer>>(config.name.c_str(),
memoryManager,
1,
1,
transactionFinished,
termianteInitiator,
std::move(hammer));
}
},
initiator_config);
totalTransactions += initiator->totalRequests();
initiator->bind(dramSys->tSocket);
initiators.push_back(std::move(initiator));
}
// Store the starting of the simulation in wall-clock time:
auto start = std::chrono::high_resolution_clock::now();
// Start the SystemC simulation
sc_set_stop_mode(sc_core::SC_STOP_FINISH_DELTA);
sc_core::sc_start();
if (!sc_core::sc_end_of_simulation_invoked())
{
SC_REPORT_WARNING("sc_main", "Simulation stopped without explicit sc_stop()");
sc_core::sc_stop();
}
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;
return 0;
}

View File

@@ -0,0 +1,639 @@
#include "Cache.h"
#include "MemoryManager.h"
#include <cstring>
#include <sysc/kernel/sc_simcontext.h>
#include <sysc/kernel/sc_time.h>
#include <sysc/utils/sc_report.h>
#include <tlm_core/tlm_2/tlm_generic_payload/tlm_gp.h>
#include <tlm_core/tlm_2/tlm_generic_payload/tlm_phase.h>
using namespace tlm;
using namespace sc_core;
DECLARE_EXTENDED_PHASE(HIT_HANDLING);
DECLARE_EXTENDED_PHASE(MISS_HANDLING);
Cache::Cache(const sc_module_name &name,
std::size_t size,
std::size_t associativity,
std::size_t lineSize,
std::size_t mshrDepth,
std::size_t writeBufferDepth,
std::size_t maxTargetListSize,
bool storageEnabled,
sc_core::sc_time cycleTime,
std::size_t hitCycles,
MemoryManager &memoryManager) :
sc_module(name),
payloadEventQueue(this, &Cache::peqCallback),
storageEnabled(storageEnabled),
cycleTime(cycleTime),
hitLatency(cycleTime * static_cast<double>(hitCycles)),
size(size),
associativity(associativity),
lineSize(lineSize),
numberOfSets(size / (lineSize * associativity)),
indexShifts(static_cast<std::size_t>(std::log2(lineSize))),
indexMask(numberOfSets - 1),
tagShifts(indexShifts + static_cast<std::size_t>(std::log2(numberOfSets))),
mshrDepth(mshrDepth),
writeBufferDepth(writeBufferDepth),
maxTargetListSize(maxTargetListSize),
memoryManager(memoryManager)
{
iSocket.register_nb_transport_bw(this, &Cache::nb_transport_bw);
tSocket.register_nb_transport_fw(this, &Cache::nb_transport_fw);
lineTable = std::vector<std::vector<CacheLine>>(numberOfSets, std::vector<CacheLine>(associativity));
if (storageEnabled)
{
dataMemory.reserve(size);
for (std::size_t set = 0; set < lineTable.size(); set++)
{
for (std::size_t way = 0; way < lineTable[set].size(); way++)
lineTable[set][way].dataPtr = dataMemory.data() + set * associativity * lineSize + way * lineSize;
}
}
}
tlm_sync_enum Cache::nb_transport_fw(tlm_generic_payload &trans, tlm_phase &phase, sc_time &delay) // core side --->
{
if (phase == BEGIN_REQ)
{
if (trans.get_data_length() > lineSize)
{
SC_REPORT_FATAL(name(), "Accesses larger than line size in non-blocking mode not supported!");
}
trans.acquire();
}
// TODO: early completion would be possible
payloadEventQueue.notify(trans, phase, ceilDelay(delay));
return TLM_ACCEPTED;
}
tlm_sync_enum Cache::nb_transport_bw(tlm_generic_payload &trans, tlm_phase &phase, sc_time &bwDelay) // DRAM side <---
{
// TODO: early completion would be possible
payloadEventQueue.notify(trans, phase, ceilDelay(bwDelay));
return TLM_ACCEPTED;
}
void Cache::peqCallback(tlm_generic_payload &trans, const tlm_phase &phase)
{
if (phase == BEGIN_REQ) // core side --->
{
assert(!endRequestPending);
fetchLineAndSendEndRequest(trans);
return;
}
else if (phase == END_REQ) // <--- DRAM side
{
lastEndReq = sc_time_stamp();
clearInitiatorBackpressureAndProcessBuffers();
return;
}
else if (phase == BEGIN_RESP && &trans == requestInProgress) // <--- DRAM side
{
// Shortcut, 2 phases in one
clearInitiatorBackpressureAndProcessBuffers();
sendEndResponseAndFillLine(trans);
return;
}
else if (phase == BEGIN_RESP) // <--- DRAM side
{
sendEndResponseAndFillLine(trans);
return;
}
else if (phase == END_RESP) // core side --->
{
clearTargetBackpressureAndProcessLines(trans);
return;
}
else if (phase == HIT_HANDLING) // direct hit, account for the hit delay
{
index_t index;
tag_t tag;
std::tie(index, tag, std::ignore) = decodeAddress(trans.get_address());
hitQueue.emplace_back(index, tag, &trans);
processHitQueue();
}
else if (phase == MISS_HANDLING) // fetched MSHR entry available, account for the hit delay
{
accessCacheAndSendResponse(trans);
index_t index;
tag_t tag;
std::tie(index, tag, std::ignore) = decodeAddress(trans.get_address());
auto mshrIt = std::find_if(mshrQueue.begin(), mshrQueue.end(),
[index, tag](const Mshr &mshr) { return mshr.index == index && mshr.tag == tag; });
assert(mshrIt != mshrQueue.end());
mshrIt->hitDelayAccounted = true;
if (mshrIt->requestList.empty())
{
mshrQueue.erase(mshrIt);
if (endRequestPending != nullptr && hasBufferSpace())
{
payloadEventQueue.notify(*endRequestPending, BEGIN_REQ, SC_ZERO_TIME);
endRequestPending = nullptr;
}
}
}
else
{
SC_REPORT_FATAL("Cache", "PEQ was triggered with unknown phase");
}
}
/// Handler for begin request from core side.
void Cache::fetchLineAndSendEndRequest(tlm_generic_payload &trans)
{
if (hasBufferSpace())
{
index_t index;
tag_t tag;
std::tie(index, tag, std::ignore) = decodeAddress(trans.get_address());
auto mshrEntry =
std::find_if(mshrQueue.begin(), mshrQueue.end(),
[index, tag](const Mshr &entry) { return (index == entry.index) && (tag == entry.tag); });
if (isHit(index, tag))
{
numberOfHits++;
// Handle hit
// Account for the 1 cycle accept delay.
payloadEventQueue.notify(trans, HIT_HANDLING, hitLatency + cycleTime);
}
else if (mshrEntry != mshrQueue.end()) // Miss with outstanding previous Miss, noted in MSHR
{
numberOfSecondaryMisses++;
assert(isAllocated(index, tag));
// A fetch for this cache line is already in progress
// Add request to the existing Mshr entry
if (mshrEntry->requestList.size() == maxTargetListSize)
{
// Insertion into requestList in mshrEntry not possible.
endRequestPending = &trans;
return;
}
mshrEntry->requestList.emplace_back(&trans);
}
else // Miss without MSHR entry:
{
numberOfPrimaryMisses++;
assert(!isAllocated(index, tag));
// Cache miss and no fetch in progress.
// So evict line and allocate empty line.
auto evictedLine = evictLine(index);
if (!evictedLine)
{
// Line eviction not possible.
endRequestPending = &trans;
return;
}
allocateLine(evictedLine, tag);
mshrQueue.emplace_back(index, tag, &trans);
processMshrQueue();
processWriteBuffer();
}
tlm_phase bwPhase = END_REQ;
sc_time bwDelay = SC_ZERO_TIME;
tSocket->nb_transport_bw(trans, bwPhase, bwDelay);
}
else
{
endRequestPending = &trans;
}
}
/// Handler for end request from DRAM side.
void Cache::clearInitiatorBackpressureAndProcessBuffers()
{
requestInProgress = nullptr;
processMshrQueue();
processWriteBuffer();
}
/// Handler for begin response from DRAM side.
void Cache::sendEndResponseAndFillLine(tlm_generic_payload &trans)
{
tlm_phase fwPhase = END_RESP;
sc_time fwDelay = SC_ZERO_TIME;
iSocket->nb_transport_fw(trans, fwPhase, fwDelay);
if (trans.is_read())
{
fillLine(trans);
processMshrResponse();
}
trans.release();
}
/// Handler for end response from core side.
void Cache::clearTargetBackpressureAndProcessLines(tlm_generic_payload &trans)
{
trans.release();
tSocketBackpressure = false;
processHitQueue();
processMshrResponse();
// When the cache currently only handles hits from the hit queue and
// no other requests to the DRAM side are pending, there is a chance
// that a endRequestPending will never be served.
// To circumvent this, pass it into the system again at this point.
if (endRequestPending != nullptr && hasBufferSpace())
{
payloadEventQueue.notify(*endRequestPending, BEGIN_REQ, SC_ZERO_TIME);
endRequestPending = nullptr;
}
}
unsigned int Cache::transport_dbg(tlm_generic_payload &trans)
{
return iSocket->transport_dbg(trans);
}
bool Cache::isHit(index_t index, tag_t tag) const
{
return std::find_if(lineTable[index].begin(), lineTable[index].end(),
[tag](const CacheLine &cacheLine)
{ return (cacheLine.tag == tag) && cacheLine.valid; }) != lineTable[index].end();
}
bool Cache::isHit(uint64_t address) const
{
index_t index;
tag_t tag;
std::tie(index, tag, std::ignore) = decodeAddress(address);
return isHit(index, tag);
}
std::tuple<Cache::index_t, Cache::tag_t, Cache::lineOffset_t> Cache::decodeAddress(uint64_t address) const
{
return {(address >> indexShifts) & indexMask, address >> tagShifts, address % lineSize};
}
uint64_t Cache::encodeAddress(Cache::index_t index, Cache::tag_t tag, Cache::lineOffset_t lineOffset) const
{
return static_cast<uint64_t>(tag << tagShifts) | index << indexShifts | lineOffset;
}
/// Write data to an available cache line, update flags
void Cache::writeLine(
index_t index, tag_t tag, lineOffset_t lineOffset, unsigned int dataLength, const unsigned char *dataPtr)
{
// SC_REPORT_ERROR("cache", "Write to Cache not allowed!");
CacheLine &currentLine = *std::find_if(lineTable[index].begin(), lineTable[index].end(),
[tag](const CacheLine &cacheLine) { return cacheLine.tag == tag; });
assert(currentLine.valid);
currentLine.lastAccessTime = sc_time_stamp();
currentLine.dirty = true;
if (storageEnabled)
std::copy(dataPtr, dataPtr + dataLength, currentLine.dataPtr + lineOffset);
}
/// Read data from an available cache line, update flags
void Cache::readLine(index_t index, tag_t tag, lineOffset_t lineOffset, unsigned int dataLength, unsigned char *dataPtr)
{
CacheLine &currentLine = *std::find_if(lineTable[index].begin(), lineTable[index].end(),
[tag](const CacheLine &cacheLine) { return cacheLine.tag == tag; });
assert(currentLine.valid);
currentLine.lastAccessTime = sc_time_stamp();
if (storageEnabled)
std::copy(currentLine.dataPtr + lineOffset, currentLine.dataPtr + lineOffset + dataLength, dataPtr);
}
/// Tries to evict oldest line (insert into write memory)
/// Returns the line or a nullptr if not possible
Cache::CacheLine *Cache::evictLine(Cache::index_t index)
{
CacheLine &oldestLine = *std::min_element(lineTable[index].begin(), lineTable[index].end(),
[](const CacheLine &lhs, const CacheLine &rhs)
{ return lhs.lastAccessTime < rhs.lastAccessTime; });
if (oldestLine.allocated && !oldestLine.valid)
{
// oldestline is allocated but not yet valid -> fetch in progress
return nullptr;
}
else if (std::find_if(mshrQueue.begin(), mshrQueue.end(),
[index, oldestLine](const Mshr &entry)
{ return (index == entry.index) && (oldestLine.tag == entry.tag); }) != mshrQueue.end())
{
// TODO: solve this in a more clever way
// There are still entries in mshrQueue to the oldest line -> do not evict it
return nullptr;
}
else if (std::find_if(hitQueue.begin(), hitQueue.end(),
[index, oldestLine](const BufferEntry &entry)
{ return (index == entry.index) && (oldestLine.tag == entry.tag); }) != hitQueue.end())
{
// TODO: solve this in a more clever way
// There are still hits in hitQueue to the oldest line -> do not evict it
return nullptr;
}
else
{
if (oldestLine.valid && oldestLine.dirty)
{
auto &wbTrans = memoryManager.allocate(lineSize);
wbTrans.acquire();
wbTrans.set_address(encodeAddress(index, oldestLine.tag));
wbTrans.set_write();
wbTrans.set_data_length(lineSize);
wbTrans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
if (storageEnabled)
std::copy(oldestLine.dataPtr, oldestLine.dataPtr + lineSize, wbTrans.get_data_ptr());
writeBuffer.emplace_back(index, oldestLine.tag, &wbTrans);
}
oldestLine.allocated = false;
oldestLine.valid = false;
oldestLine.dirty = false;
return &oldestLine;
}
}
/// Align address to cache line size
uint64_t Cache::getAlignedAddress(uint64_t address) const
{
return address - (address % lineSize);
}
/// Issue read requests for entries in the MshrQueue to the target
void Cache::processMshrQueue()
{
if (!requestInProgress && !mshrQueue.empty())
{
// Get the first entry that wasn't already issued to the target
auto mshrIt = std::find_if(mshrQueue.begin(), mshrQueue.end(), [](const Mshr &entry) { return !entry.issued; });
if (mshrIt == mshrQueue.end())
return;
// Note: This is the same address for all entries in the requests list
uint64_t alignedAddress = getAlignedAddress(mshrIt->requestList.front()->get_address());
index_t index;
tag_t tag;
std::tie(index, tag, std::ignore) = decodeAddress(alignedAddress);
// Search through the writeBuffer in reverse order to get the most recent entry.
auto writeBufferEntry = std::find_if(writeBuffer.rbegin(), writeBuffer.rbegin(),
[index, tag](const BufferEntry &entry)
{ return (index == entry.index) && (tag == entry.tag); });
if (writeBufferEntry != writeBuffer.rbegin())
{
// There is an entry for the required line in the write buffer.
// Snoop into it and get the data from there instead of the dram.
mshrIt->issued = true;
clearInitiatorBackpressureAndProcessBuffers();
fillLine(*writeBufferEntry->trans);
processMshrResponse();
return;
}
// Prevents that the cache line will get fetched multiple times from the target
mshrIt->issued = true;
auto &fetchTrans = memoryManager.allocate(lineSize);
fetchTrans.acquire();
fetchTrans.set_read();
fetchTrans.set_data_length(lineSize);
fetchTrans.set_streaming_width(lineSize);
fetchTrans.set_address(alignedAddress);
fetchTrans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
tlm_phase fwPhase = BEGIN_REQ;
// Always account for the cycle as either we just received the BEGIN_REQ
// or we cleared the backpressure from another END_REQ.
sc_time fwDelay = cycleTime;
requestInProgress = &fetchTrans;
tlm_sync_enum returnValue = iSocket->nb_transport_fw(fetchTrans, fwPhase, fwDelay);
if (returnValue == tlm::TLM_UPDATED)
{
// END_REQ or BEGIN_RESP
payloadEventQueue.notify(fetchTrans, fwPhase, fwDelay);
}
else if (returnValue == tlm::TLM_COMPLETED)
{
clearInitiatorBackpressureAndProcessBuffers();
fillLine(fetchTrans);
processMshrResponse();
fetchTrans.release();
}
if (endRequestPending != nullptr && hasBufferSpace())
{
payloadEventQueue.notify(*endRequestPending, BEGIN_REQ, SC_ZERO_TIME);
endRequestPending = nullptr;
}
}
}
/// Processes writeBuffer (dirty cache line evictions)
void Cache::processWriteBuffer()
{
if (!requestInProgress && !writeBuffer.empty())
{
tlm_generic_payload &wbTrans = *writeBuffer.front().trans;
tlm_phase fwPhase = BEGIN_REQ;
sc_time fwDelay = (lastEndReq == sc_time_stamp()) ? cycleTime : SC_ZERO_TIME;
requestInProgress = &wbTrans;
tlm_sync_enum returnValue = iSocket->nb_transport_fw(wbTrans, fwPhase, fwDelay);
if (returnValue == tlm::TLM_UPDATED)
{
// END_REQ or BEGIN_RESP
payloadEventQueue.notify(wbTrans, fwPhase, fwDelay);
}
else if (returnValue == tlm::TLM_COMPLETED)
{
clearInitiatorBackpressureAndProcessBuffers();
wbTrans.release();
}
if (endRequestPending != nullptr && hasBufferSpace())
{
payloadEventQueue.notify(*endRequestPending, BEGIN_REQ, SC_ZERO_TIME);
endRequestPending = nullptr;
}
writeBuffer.pop_front();
}
}
/// Fill allocated cache line with data from memory
void Cache::fillLine(tlm_generic_payload &trans)
{
index_t index;
tag_t tag;
std::tie(index, tag, std::ignore) = decodeAddress(trans.get_address());
CacheLine &allocatedLine =
*std::find_if(lineTable[index].begin(), lineTable[index].end(),
[tag](const CacheLine &cacheLine) { return cacheLine.allocated && cacheLine.tag == tag; });
allocatedLine.valid = true;
allocatedLine.dirty = false;
if (storageEnabled)
std::copy(trans.get_data_ptr(), trans.get_data_ptr() + lineSize, allocatedLine.dataPtr);
}
/// Make cache access for pending hits
void Cache::processHitQueue()
{
if (!tSocketBackpressure && !hitQueue.empty())
{
auto hit = hitQueue.front();
hitQueue.pop_front();
accessCacheAndSendResponse(*hit.trans);
}
}
/// Access the available cache line and send the response
void Cache::accessCacheAndSendResponse(tlm_generic_payload &trans)
{
assert(!tSocketBackpressure);
assert(isHit(trans.get_address()));
auto [index, tag, lineOffset] = decodeAddress(trans.get_address());
if (trans.is_read())
readLine(index, tag, lineOffset, trans.get_data_length(), trans.get_data_ptr());
else
writeLine(index, tag, lineOffset, trans.get_data_length(), trans.get_data_ptr());
tlm_phase bwPhase = BEGIN_RESP;
sc_time bwDelay = SC_ZERO_TIME;
trans.set_response_status(tlm::TLM_OK_RESPONSE);
tlm_sync_enum returnValue = tSocket->nb_transport_bw(trans, bwPhase, bwDelay);
if (returnValue == tlm::TLM_UPDATED) // TODO tlm_completed
payloadEventQueue.notify(trans, bwPhase, bwDelay);
tSocketBackpressure = true;
}
/// Allocates an empty line for later filling (lastAccessTime = sc_max_time())
void Cache::allocateLine(CacheLine *line, tag_t tag)
{
line->allocated = true;
line->tag = tag;
line->lastAccessTime = sc_max_time();
}
/// Checks whether a line with the corresponding tag is already allocated (fetch in progress or already valid)
bool Cache::isAllocated(Cache::index_t index, Cache::tag_t tag) const
{
return std::find_if(lineTable[index].begin(), lineTable[index].end(),
[tag](const CacheLine &cacheLine)
{ return (cacheLine.tag == tag) && cacheLine.allocated; }) != lineTable[index].end();
}
/// Process oldest hit in mshrQueue, accept pending request from initiator
void Cache::processMshrResponse()
{
if (!tSocketBackpressure) // TODO: Bedingung eigentlich zu streng, wenn man Hit delay berücksichtigt.
{
const auto hitIt = std::find_if(mshrQueue.begin(), mshrQueue.end(),
[this](const Mshr &entry) { return isHit(entry.index, entry.tag); });
// In case there are hits in mshrActive, handle them. Otherwise try again later.
if (hitIt == mshrQueue.end())
return;
// Another MSHR target already started the modeling of the hit delay.
// Try again later.
if (hitIt->hitDelayStarted && !hitIt->hitDelayAccounted)
return;
// Get the first request in the list and respond to it
tlm_generic_payload &returnTrans = *hitIt->requestList.front();
hitIt->requestList.pop_front();
if (hitIt->hitDelayAccounted)
accessCacheAndSendResponse(returnTrans);
else
{
hitIt->hitDelayStarted = true;
payloadEventQueue.notify(returnTrans, MISS_HANDLING, hitLatency);
return;
}
if (hitIt->requestList.empty())
{
mshrQueue.erase(hitIt);
if (endRequestPending != nullptr && hasBufferSpace())
{
payloadEventQueue.notify(*endRequestPending, BEGIN_REQ, SC_ZERO_TIME);
endRequestPending = nullptr;
}
}
}
}
/// Checks whether both mshrActive and writeBuffer have memory space
bool Cache::hasBufferSpace() const
{
return mshrQueue.size() < mshrDepth && writeBuffer.size() < writeBufferDepth;
}
sc_time Cache::ceilTime(const sc_time &inTime) const
{
return std::ceil(inTime / cycleTime) * cycleTime;
}
sc_time Cache::ceilDelay(const sc_time &inDelay) const
{
sc_time inTime = sc_time_stamp() + inDelay;
sc_time outTime = ceilTime(inTime);
sc_time outDelay = outTime - sc_time_stamp();
return outDelay;
}

View File

@@ -0,0 +1,216 @@
/*
* 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:
* Christian Malek
* Derek Christ
*/
#pragma once
#include "MemoryManager.h"
#include <list>
#include <queue>
#include <systemc>
#include <tlm>
#include <tlm_utils/peq_with_cb_and_phase.h>
#include <tlm_utils/simple_initiator_socket.h>
#include <tlm_utils/simple_target_socket.h>
class Cache : public sc_core::sc_module
{
public:
tlm_utils::simple_initiator_socket<Cache> iSocket;
tlm_utils::simple_target_socket<Cache> tSocket;
Cache(const sc_core::sc_module_name &name,
std::size_t size,
std::size_t associativity,
std::size_t lineSize,
std::size_t mshrDepth,
std::size_t writeBufferDepth,
std::size_t maxTargetListSize,
bool storageEnabled,
sc_core::sc_time cycleTime,
std::size_t hitCycles,
MemoryManager &memoryManager);
SC_HAS_PROCESS(Cache);
private:
void peqCallback(tlm::tlm_generic_payload &trans, const tlm::tlm_phase &phase);
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 &trans,
tlm::tlm_phase &phase,
sc_core::sc_time &bwDelay);
unsigned int transport_dbg(tlm::tlm_generic_payload &trans);
void fetchLineAndSendEndRequest(tlm::tlm_generic_payload &trans);
void clearInitiatorBackpressureAndProcessBuffers();
void sendEndResponseAndFillLine(tlm::tlm_generic_payload &trans);
void clearTargetBackpressureAndProcessLines(tlm::tlm_generic_payload &trans);
tlm_utils::peq_with_cb_and_phase<Cache> payloadEventQueue;
const bool storageEnabled;
sc_core::sc_time cycleTime;
const sc_core::sc_time hitLatency;
const std::size_t size;
// Lines per set.
const std::size_t associativity;
const std::size_t lineSize;
const std::size_t numberOfSets;
const std::size_t indexShifts;
const std::size_t indexMask;
const std::size_t tagShifts;
const std::size_t mshrDepth;
const std::size_t writeBufferDepth;
const std::size_t maxTargetListSize;
using index_t = std::uint64_t;
using tag_t = std::uint64_t;
using lineOffset_t = std::uint64_t;
struct CacheLine
{
tag_t tag = 0;
unsigned char *dataPtr = nullptr;
bool allocated = false;
bool valid = false;
bool dirty = false;
sc_core::sc_time lastAccessTime = sc_core::SC_ZERO_TIME;
};
std::vector<std::vector<CacheLine>> lineTable;
std::vector<uint8_t> dataMemory;
bool isHit(index_t index, tag_t tag) const;
bool isHit(std::uint64_t address) const;
void writeLine(index_t index,
tag_t tag,
lineOffset_t lineOffset,
unsigned int dataLength,
const unsigned char *dataPtr);
void readLine(index_t index,
tag_t tag,
lineOffset_t lineOffset,
unsigned int dataLength,
unsigned char *dataPtr);
CacheLine *evictLine(index_t index);
std::tuple<index_t, tag_t, lineOffset_t> decodeAddress(std::uint64_t address) const;
std::uint64_t encodeAddress(index_t index, tag_t tag, lineOffset_t lineOffset = 0) const;
struct BufferEntry
{
index_t index;
tag_t tag;
tlm::tlm_generic_payload *trans;
BufferEntry(index_t index, tag_t tag, tlm::tlm_generic_payload *trans)
: index(index), tag(tag), trans(trans)
{
}
};
struct Mshr
{
index_t index;
tag_t tag;
std::list<tlm::tlm_generic_payload *> requestList;
/// Whether the Mshr entry was already issued to the target.
bool issued = false;
/// Whether the hit delay was already accounted for.
/// Used to determine if the next entry in the request list
/// should be sent out without the hit delay.
bool hitDelayAccounted = false;
/// Whether the hit delay is being awaited on.
/// Used prevent other MSHR targets to wait on the hit
/// delay when it is already being waited on.
bool hitDelayStarted = false;
Mshr(index_t index, tag_t tag, tlm::tlm_generic_payload *request)
: index(index), tag(tag), requestList{request}
{
}
};
std::deque<Mshr> mshrQueue;
std::deque<BufferEntry> hitQueue;
using WriteBuffer = std::list<BufferEntry>;
WriteBuffer writeBuffer;
uint64_t numberOfHits = 0;
uint64_t numberOfPrimaryMisses = 0;
uint64_t numberOfSecondaryMisses = 0;
std::uint64_t getAlignedAddress(std::uint64_t address) const;
void processMshrResponse();
void processWriteBuffer();
void processHitQueue();
void processMshrQueue();
bool tSocketBackpressure = false;
// Request to the target
tlm::tlm_generic_payload *requestInProgress = nullptr;
// Backpressure on initiator
tlm::tlm_generic_payload *endRequestPending = nullptr;
sc_core::sc_time lastEndReq = sc_core::sc_max_time();
void fillLine(tlm::tlm_generic_payload &trans);
void accessCacheAndSendResponse(tlm::tlm_generic_payload &trans);
void allocateLine(CacheLine *line, tag_t tag);
bool isAllocated(index_t index, tag_t tag) const;
bool hasBufferSpace() const;
sc_core::sc_time ceilTime(const sc_core::sc_time &inTime) const;
sc_core::sc_time ceilDelay(const sc_core::sc_time &inDelay) const;
MemoryManager &memoryManager;
};

View File

@@ -0,0 +1,313 @@
/*
* 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:
* Christian Malek
* Derek Christ
*/
#include "EccModule.h"
#include "DRAMSys/common/dramExtensions.h"
#include <fstream>
using namespace sc_core;
using namespace tlm;
EccModule::EccModule(sc_module_name name, AddressDecoder const &addressDecoder) :
sc_core::sc_module(name),
payloadEventQueue(this, &EccModule::peqCallback),
addressDecoder(addressDecoder),
memoryManager(false)
{
iSocket.register_nb_transport_bw(this, &EccModule::nb_transport_bw);
tSocket.register_nb_transport_fw(this, &EccModule::nb_transport_fw);
}
tlm::tlm_sync_enum EccModule::nb_transport_fw(tlm::tlm_generic_payload &payload,
tlm::tlm_phase &phase,
sc_core::sc_time &fwDelay)
{
if (phase == BEGIN_REQ)
{
payload.acquire();
}
payloadEventQueue.notify(payload, phase, fwDelay);
return TLM_ACCEPTED;
}
tlm::tlm_sync_enum EccModule::nb_transport_bw(tlm::tlm_generic_payload &payload,
tlm::tlm_phase &phase,
sc_core::sc_time &bwDelay)
{
payloadEventQueue.notify(payload, phase, bwDelay);
return TLM_ACCEPTED;
}
void EccModule::peqCallback(tlm::tlm_generic_payload &cbPayload, const tlm::tlm_phase &cbPhase)
{
if (cbPhase == BEGIN_REQ) // from initiator
{
// Put transaction into latency map
payloadMap.emplace(&cbPayload, sc_time_stamp());
if (!targetBusy)
{
targetBusy = true;
tlm_phase tPhase = BEGIN_REQ;
sc_time tDelay = SC_ZERO_TIME;
DecodedAddress decodedAddress = addressDecoder.decodeAddress(cbPayload.get_address());
decodedAddress = calculateOffsetAddress(decodedAddress);
// Update the original address to account for the offsets
cbPayload.set_address(addressDecoder.encodeAddress(decodedAddress));
auto currentBlock = alignToBlock(decodedAddress.column);
// In case there is no entry yet.
activeEccBlocks.try_emplace(decodedAddress.bank);
#ifdef ECC_ENABLE
if (!activeEccBlock(decodedAddress.bank, decodedAddress.row, currentBlock))
{
blockedRequest = &cbPayload;
auto &eccFifo = activeEccBlocks[decodedAddress.bank];
eccFifo.push_back({currentBlock, decodedAddress.row});
// Only hold 4 elements at max.
if (eccFifo.size() >= 4)
eccFifo.pop_front();
tlm::tlm_generic_payload *eccPayload = generateEccPayload(decodedAddress);
iSocket->nb_transport_fw(*eccPayload, tPhase, tDelay);
}
else
#endif
{
iSocket->nb_transport_fw(cbPayload, tPhase, tDelay);
}
}
else
{
pendingRequest = &cbPayload;
}
}
else if (cbPhase == END_REQ) // from target
{
// Send payload to inititator in case it is not an ECC transaction
if (cbPayload.get_extension<EccExtension>() == nullptr)
{
tlm_phase tPhase = END_REQ;
sc_time tDelay = SC_ZERO_TIME;
tSocket->nb_transport_bw(cbPayload, tPhase, tDelay);
}
if (blockedRequest != nullptr)
{
tlm_generic_payload &tPayload = *blockedRequest;
blockedRequest = nullptr;
tlm_phase tPhase = BEGIN_REQ;
sc_time tDelay = SC_ZERO_TIME;
iSocket->nb_transport_fw(tPayload, tPhase, tDelay);
// Do not attempt to send another pending request and hold targetBusy high
return;
}
if (pendingRequest != nullptr)
{
tlm_generic_payload &tPayload = *pendingRequest;
tlm_phase tPhase = BEGIN_REQ;
sc_time tDelay = SC_ZERO_TIME;
DecodedAddress decodedAddress = addressDecoder.decodeAddress(tPayload.get_address());
decodedAddress = calculateOffsetAddress(decodedAddress);
auto currentBlock = alignToBlock(decodedAddress.column);
#ifdef ECC_ENABLE
if (!activeEccBlock(decodedAddress.bank, decodedAddress.row, currentBlock))
{
blockedRequest = pendingRequest;
pendingRequest = nullptr;
auto &eccFifo = activeEccBlocks[decodedAddress.bank];
eccFifo.push_back({currentBlock, decodedAddress.row});
// Only hold 4 elements at max.
if (eccFifo.size() >= 4)
eccFifo.pop_front();
tlm::tlm_generic_payload *eccPayload = generateEccPayload(decodedAddress);
iSocket->nb_transport_fw(*eccPayload, tPhase, tDelay);
}
else
#endif
{
iSocket->nb_transport_fw(tPayload, tPhase, tDelay);
pendingRequest = nullptr;
}
}
else
{
assert(!pendingRequest);
assert(!blockedRequest);
targetBusy = false;
}
}
else if (cbPhase == BEGIN_RESP) // from memory controller
{
// Send payload to inititator in case it is not an ECC transaction
if (cbPayload.get_extension<EccExtension>() == nullptr)
{
tlm_phase tPhase = BEGIN_RESP;
sc_time tDelay = SC_ZERO_TIME;
tlm_sync_enum returnValue = tSocket->nb_transport_bw(cbPayload, tPhase, tDelay);
// Early completion from initiator
if (returnValue == TLM_UPDATED)
{
payloadEventQueue.notify(cbPayload, tPhase, tDelay);
}
Latency latency = sc_time_stamp() - payloadMap.at(&cbPayload);
payloadMap.erase(&cbPayload);
latency = roundLatency(latency);
latencyMap.try_emplace(latency, 0);
latencyMap.at(latency)++;
}
else
{
// Send END_RESP by ourselfes
tlm_phase tPhase = END_RESP;
sc_time tDelay = SC_ZERO_TIME;
iSocket->nb_transport_fw(cbPayload, tPhase, tDelay);
}
}
else if (cbPhase == END_RESP) // from initiator
{
{
tlm_phase tPhase = END_RESP;
sc_time tDelay = SC_ZERO_TIME;
iSocket->nb_transport_fw(cbPayload, tPhase, tDelay);
}
cbPayload.release();
}
else
{
SC_REPORT_FATAL(0, "Payload event queue in arbiter was triggered with unknown phase");
}
}
tlm::tlm_generic_payload *EccModule::generateEccPayload(DecodedAddress decodedAddress)
{
unsigned int eccAtom = decodedAddress.column / 512;
uint64_t eccColumn = 1792 + eccAtom * 32;
decodedAddress.column = eccColumn;
uint64_t eccAddress = addressDecoder.encodeAddress(decodedAddress);
tlm_generic_payload &payload = memoryManager.allocate(32);
payload.acquire();
payload.set_address(eccAddress);
payload.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
payload.set_dmi_allowed(false);
payload.set_byte_enable_length(0);
payload.set_data_length(32);
payload.set_streaming_width(32);
payload.set_command(tlm::TLM_READ_COMMAND);
payload.set_extension<EccExtension>(new EccExtension);
return &payload;
}
unsigned int EccModule::alignToBlock(unsigned column)
{
return column & ~(512 - 1);
}
DecodedAddress EccModule::calculateOffsetAddress(DecodedAddress decodedAddress)
{
unsigned int newRow =
std::floor((decodedAddress.row * 256 + decodedAddress.column) / 1792) + decodedAddress.row;
unsigned int newColumn = (decodedAddress.row * 256 + decodedAddress.column) % 1792;
DecodedAddress offsetAddress(decodedAddress);
offsetAddress.row = newRow;
offsetAddress.column = newColumn;
return offsetAddress;
}
void EccModule::end_of_simulation()
{
uint64_t latencies = 0;
uint64_t numberOfLatencies = 0;
for (auto const &[latency, occurences] : latencyMap)
{
latencies += (latency.to_double() / 1000.0) * occurences;
numberOfLatencies += occurences;
}
std::cout << "Average latency: " << static_cast<double>(latencies) / numberOfLatencies << std::endl;
}
sc_time EccModule::roundLatency(sc_time latency)
{
static const sc_time BUCKET_SIZE = sc_time(1, SC_NS);
latency += BUCKET_SIZE / 2;
latency = latency - (latency % BUCKET_SIZE);
return latency;
}
bool EccModule::activeEccBlock(Bank bank, Row row, Block block) const
{
auto eccIt = std::find_if(activeEccBlocks.at(bank).cbegin(), activeEccBlocks.at(bank).cend(),
[block, row](EccIdentifier identifier) {
return (identifier.first == block) && (identifier.second == row);
});
return eccIt != activeEccBlocks.at(bank).cend();
}

View File

@@ -0,0 +1,107 @@
/*
* 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:
* Christian Malek
* Derek Christ
*/
#ifndef ECCMODULE_H
#define ECCMODULE_H
#include "simulator/MemoryManager.h"
#include <DRAMSys/simulation/AddressDecoder.h>
#include <systemc>
#include <tlm_utils/peq_with_cb_and_phase.h>
#include <tlm_utils/simple_initiator_socket.h>
#include <tlm_utils/simple_target_socket.h>
#include <unordered_map>
#include <map>
#include <deque>
class EccModule : public sc_core::sc_module
{
public:
tlm_utils::simple_initiator_socket<EccModule> iSocket;
tlm_utils::simple_target_socket<EccModule> tSocket;
EccModule(sc_core::sc_module_name name, AddressDecoder const &addressDecoder);
SC_HAS_PROCESS(EccModule);
private:
using Block = uint64_t;
using Row = uint64_t;
using Bank = unsigned int;
using EccIdentifier = std::pair<Block, Row>;
using EccQueue = std::deque<EccIdentifier>;
static DecodedAddress calculateOffsetAddress(DecodedAddress decodedAddress);
static sc_core::sc_time roundLatency(sc_core::sc_time latency);
bool activeEccBlock(Bank bank, Row row, Block block) const;
void end_of_simulation() override;
void peqCallback(tlm::tlm_generic_payload &payload, const tlm::tlm_phase &phase);
tlm::tlm_sync_enum nb_transport_fw(tlm::tlm_generic_payload &payload,
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);
tlm::tlm_generic_payload *generateEccPayload(DecodedAddress decodedAddress);
static unsigned int alignToBlock(unsigned int column);
tlm_utils::peq_with_cb_and_phase<EccModule> payloadEventQueue;
tlm::tlm_generic_payload *pendingRequest = nullptr;
tlm::tlm_generic_payload *blockedRequest = nullptr;
bool targetBusy = false;
const sc_core::sc_time tCK;
MemoryManager memoryManager;
AddressDecoder const &addressDecoder;
std::unordered_map<Bank, EccQueue> activeEccBlocks;
using EccPayload = tlm::tlm_generic_payload *;
using StartTime = sc_core::sc_time;
std::unordered_map<tlm::tlm_generic_payload*, StartTime> payloadMap;
using Latency = sc_core::sc_time;
std::map<Latency, uint64_t> latencyMap;
};
#endif // ECCMODULE_H

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2023, 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:
* Derek Christ
*/
#pragma once
#include <tlm_utils/multi_socket_bases.h>
class Initiator
{
public:
virtual ~Initiator() = default;
virtual void bind(tlm_utils::multi_target_base<> &target) = 0;
virtual uint64_t totalRequests() = 0;
};

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2023, 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:
* Derek Christ
*/
#pragma once
#include "Initiator.h"
#include "request/RequestIssuer.h"
template <typename Producer>
class SimpleInitiator : public Initiator
{
public:
SimpleInitiator(sc_core::sc_module_name const &name,
MemoryManager &memoryManager,
std::optional<unsigned int> maxPendingReadRequests,
std::optional<unsigned int> maxPendingWriteRequests,
std::function<void()> transactionFinished,
std::function<void()> terminate,
Producer &&producer)
: producer(std::forward<Producer>(producer)),
issuer(
name,
memoryManager,
maxPendingReadRequests,
maxPendingWriteRequests,
[this] { return this->producer.nextRequest(); },
std::move(transactionFinished),
std::move(terminate))
{
}
void bind(tlm_utils::multi_target_base<> &target) override { issuer.iSocket.bind(target); }
uint64_t totalRequests() override { return producer.totalRequests(); };
private:
Producer producer;
RequestIssuer issuer;
};

View File

@@ -1,236 +0,0 @@
/*
* Copyright (c) 2015, 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:
* Janik Schlemminger
* Robert Gernhardt
* Matthias Jung
* Éder F. Zulian
* Felipe S. Prado
* Derek Christ
*/
#include "StlPlayer.h"
using namespace sc_core;
using namespace tlm;
StlPlayer::StlPlayer(const sc_module_name &name, const Configuration& config, const std::string &pathToTrace,
const sc_time &playerClk, unsigned int maxPendingReadRequests, unsigned int maxPendingWriteRequests,
TraceSetup& setup, bool relative) :
TrafficInitiator(name, config, setup, maxPendingReadRequests, maxPendingWriteRequests,
config.memSpec->defaultBytesPerBurst),
file(pathToTrace), relative(relative), playerClk(playerClk)
{
currentBuffer = &lineContents[0];
parseBuffer = &lineContents[1];
if (!file.is_open())
SC_REPORT_FATAL("StlPlayer", (std::string("Could not open trace ") + pathToTrace).c_str());
else
{
std::string line;
while (std::getline(file, line))
{
if (line.size() > 1 && line[0] != '#')
numberOfLines++;
}
file.clear();
file.seekg(0);
if (numberOfLines == 0)
SC_REPORT_FATAL("StlPlayer", "Trace file is empty");
}
currentBuffer->reserve(lineBufferSize);
parseBuffer->reserve(lineBufferSize);
parseTraceFile();
lineIterator = currentBuffer->cend();
}
StlPlayer::~StlPlayer()
{
if (parserThread.joinable())
parserThread.join();
}
void StlPlayer::sendNextPayload()
{
if (lineIterator == currentBuffer->cend())
{
lineIterator = swapBuffers();
if (lineIterator == currentBuffer->cend())
{
// The file is empty. Nothing more to do.
finished = true;
return;
}
}
// Allocate a generic payload for this request.
tlm_generic_payload& payload = setup.allocatePayload(lineIterator->dataLength);
payload.acquire();
// Fill up the payload.
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_data_length(lineIterator->dataLength);
payload.set_command(lineIterator->command);
std::copy(lineIterator->data.begin(), lineIterator->data.end(), payload.get_data_ptr());
sc_time sendingTime;
sc_time sendingOffset;
if (transactionsSent == 0)
sendingOffset = SC_ZERO_TIME;
else
sendingOffset = playerClk - (sc_time_stamp() % playerClk);
if (!relative)
sendingTime = std::max(sc_time_stamp() + sendingOffset, lineIterator->sendingTime);
else
sendingTime = sc_time_stamp() + sendingOffset + lineIterator->sendingTime;
sendToTarget(payload, BEGIN_REQ, sendingTime - sc_time_stamp());
transactionsSent++;
if (payload.get_command() == tlm::TLM_READ_COMMAND)
pendingReadRequests++;
else if (payload.get_command() == tlm::TLM_WRITE_COMMAND)
pendingWriteRequests++;
PRINTDEBUGMESSAGE(name(), "Performing request #" + std::to_string(transactionsSent));
lineIterator++;
}
void StlPlayer::parseTraceFile()
{
unsigned parsedLines = 0;
parseBuffer->clear();
while (file && !file.eof() && parsedLines < lineBufferSize)
{
// Get a new line from the input file.
std::string line;
std::getline(file, line);
lineCnt++;
// If the line is empty (\n or \r\n) or starts with '#' (comment) the transaction is ignored.
if (line.size() <= 1 || line.at(0) == '#')
continue;
parsedLines++;
parseBuffer->emplace_back();
LineContent &content = parseBuffer->back();
// Trace files MUST provide timestamp, command and address for every
// transaction. The data information depends on the storage mode
// configuration.
std::string element;
std::istringstream iss;
iss.str(line);
// Get the timestamp for the transaction.
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 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
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 >> 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.command == TLM_WRITE_COMMAND)
{
// The input trace file must provide the data to be stored into the memory.
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 (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 < content.dataLength; i++)
content.data.emplace_back(static_cast<unsigned char>
(std::stoi(element.substr(i * 2 + 2, 2), nullptr, 16)));
}
}
}
std::vector<StlPlayer::LineContent>::const_iterator StlPlayer::swapBuffers()
{
// Wait for parser to finish
if (parserThread.joinable())
parserThread.join();
// Swap buffers
std::swap(currentBuffer, parseBuffer);
// Start new parser thread
parserThread = std::thread(&StlPlayer::parseTraceFile, this);
return currentBuffer->cbegin();
}
uint64_t StlPlayer::getNumberOfLines() const
{
return numberOfLines;
}

View File

@@ -1,237 +0,0 @@
/*
* Copyright (c) 2017, 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:
* Matthias Jung
* Luiza Correa
* Derek Christ
*/
#include "TraceSetup.h"
#include "simulator/StlPlayer.h"
#include "simulator/TrafficGenerator.h"
#include <algorithm>
#include <iomanip>
#include <map>
using namespace sc_core;
using namespace tlm;
TraceSetup::TraceSetup(const Configuration& config,
const DRAMSys::Config::TraceSetup& traceSetup,
const std::string& pathToResources,
std::vector<std::unique_ptr<TrafficInitiator>>& players)
: memoryManager(config.storeMode != Configuration::StoreMode::NoStorage)
{
if (traceSetup.initiators.empty())
SC_REPORT_FATAL("TraceSetup", "No traffic initiators specified");
for (const auto &initiator : traceSetup.initiators)
{
std::visit(
[&](auto &&initiator)
{
std::string name = initiator.name;
double frequencyMHz = initiator.clkMhz;
sc_time playerClk = sc_time(1.0 / frequencyMHz, SC_US);
unsigned int maxPendingReadRequests = [=]() -> unsigned int
{
if (const auto &maxPendingReadRequests = initiator.maxPendingReadRequests)
return *maxPendingReadRequests;
else
return 0;
}();
unsigned int maxPendingWriteRequests = [=]() -> unsigned int
{
if (const auto &maxPendingWriteRequests = initiator.maxPendingWriteRequests)
return *maxPendingWriteRequests;
else
return 0;
}();
using T = std::decay_t<decltype(initiator)>;
if constexpr (std::is_same_v<T, DRAMSys::Config::TracePlayer>)
{
size_t 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::stringstream stlFileStream;
stlFileStream << pathToResources << "/traces/" << name;
std::string stlFile = stlFileStream.str();
std::string moduleName = name;
// replace all '.' to '_'
std::replace(moduleName.begin(), moduleName.end(), '.', '_');
StlPlayer *player;
if (ext == "stl")
player = new StlPlayer(moduleName.c_str(), config, stlFile, playerClk, maxPendingReadRequests,
maxPendingWriteRequests, *this, false);
else if (ext == "rstl")
player = new StlPlayer(moduleName.c_str(), config, stlFile, playerClk, maxPendingReadRequests,
maxPendingWriteRequests, *this, true);
else
throw std::runtime_error("Unsupported file extension in " + name);
players.push_back(std::unique_ptr<TrafficInitiator>(player));
totalTransactions += player->getNumberOfLines();
}
else if constexpr (std::is_same_v<T, DRAMSys::Config::TraceGenerator>)
{
auto* trafficGenerator = new TrafficGenerator(name.c_str(), config, initiator, *this);
players.push_back(std::unique_ptr<TrafficInitiator>(trafficGenerator));
totalTransactions += trafficGenerator->getTotalTransactions();
}
else // if constexpr (std::is_same_v<T, DRAMSys::Config::TraceHammer>)
{
uint64_t numRequests = initiator.numRequests;
uint64_t rowIncrement = initiator.rowIncrement;
players.push_back(
std::unique_ptr<TrafficInitiator>(new TrafficGeneratorHammer(name.c_str(), config, initiator, *this)));
totalTransactions += numRequests;
}
},
initiator);
}
for (const auto &inititatorConf : traceSetup.initiators)
{
if (auto generatorConf = std::get_if<DRAMSys::Config::TraceGenerator>(&inititatorConf))
{
if (const auto &idleUntil = generatorConf->idleUntil)
{
const std::string name = generatorConf->name;
auto listenerIt = std::find_if(players.begin(), players.end(),
[&name](const std::unique_ptr<TrafficInitiator> &initiator)
{ return initiator->name() == name; });
// Should be found
auto listener = dynamic_cast<TrafficGenerator *>(listenerIt->get());
auto notifierIt =
std::find_if(players.begin(), players.end(),
[&idleUntil](const std::unique_ptr<TrafficInitiator> &initiator)
{
if (auto generator = dynamic_cast<const TrafficGenerator *>(initiator.get()))
{
if (generator->hasStateTransitionEvent(*idleUntil))
return true;
}
return false;
});
if (notifierIt == players.end())
SC_REPORT_FATAL("TraceSetup", "Event to listen on not found.");
auto notifier = dynamic_cast<TrafficGenerator *>(notifierIt->get());
listener->waitUntil(&notifier->getStateTransitionEvent(*idleUntil));
}
}
}
remainingTransactions = totalTransactions;
numberOfTrafficInitiators = players.size();
defaultDataLength = config.memSpec->defaultBytesPerBurst;
}
void TraceSetup::trafficInitiatorTerminates()
{
finishedTrafficInitiators++;
if (finishedTrafficInitiators == numberOfTrafficInitiators)
sc_stop();
}
void TraceSetup::transactionFinished()
{
remainingTransactions--;
loadBar(totalTransactions - remainingTransactions, totalTransactions);
if (remainingTransactions == 0)
std::cout << std::endl;
}
tlm_generic_payload& TraceSetup::allocatePayload(unsigned dataLength)
{
return memoryManager.allocate(dataLength);
}
tlm_generic_payload& TraceSetup::allocatePayload()
{
return allocatePayload(defaultDataLength);
}
void TraceSetup::loadBar(uint64_t x, uint64_t n, unsigned int w, unsigned int granularity)
{
if ((n < 100) || ((x != n) && (x % (n / 100 * granularity) != 0)))
return;
float ratio = x / (float)n;
unsigned int c = (ratio * w);
float rest = (ratio * w) - c;
std::cout << std::setw(3) << round(ratio * 100) << "% |";
for (unsigned int x = 0; x < c; x++)
std::cout << "";
if (rest >= 0 && rest < 0.125f && c != w)
std::cout << " ";
if (rest >= 0.125f && rest < 2 * 0.125f)
std::cout << "";
if (rest >= 2 * 0.125f && rest < 3 * 0.125f)
std::cout << "";
if (rest >= 3 * 0.125f && rest < 4 * 0.125f)
std::cout << "";
if (rest >= 4 * 0.125f && rest < 5 * 0.125f)
std::cout << "";
if (rest >= 5 * 0.125f && rest < 6 * 0.125f)
std::cout << "";
if (rest >= 6 * 0.125f && rest < 7 * 0.125f)
std::cout << "";
if (rest >= 7 * 0.125f && rest < 8 * 0.125f)
std::cout << "";
for (unsigned int x = c; x < (w - 1); x++)
std::cout << " ";
std::cout << "|\r" << std::flush;
}

View File

@@ -1,412 +0,0 @@
/*
* Copyright (c) 2015, 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:
* Janik Schlemminger
* Robert Gernhardt
* Matthias Jung
* Derek Christ
*/
#include "TrafficGenerator.h"
#include "simulator/TraceSetup.h"
#include <limits>
using namespace sc_core;
using namespace tlm;
TrafficGeneratorIf::TrafficGeneratorIf(const sc_core::sc_module_name& name, const Configuration& config,
TraceSetup& setup,
unsigned int maxPendingReadRequests, unsigned int maxPendingWriteRequests,
unsigned int dataLength)
: TrafficInitiator(name, config, setup, maxPendingReadRequests, maxPendingWriteRequests, dataLength)
{
}
void TrafficGeneratorIf::sendNextPayload()
{
prepareNextPayload();
if (finished)
return;
// TODO: column / burst breite
uint64_t address = getNextAddress();
tlm_command command = getNextCommand();
if (command == tlm::TLM_READ_COMMAND)
pendingReadRequests++;
else if (command == tlm::TLM_WRITE_COMMAND)
pendingWriteRequests++;
tlm_generic_payload& payload = setup.allocatePayload();
payload.acquire();
payload.set_address(address);
payload.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
payload.set_dmi_allowed(false);
payload.set_byte_enable_length(0);
payload.set_data_length(defaultDataLength);
payload.set_command(command);
sc_time generatorClk = getGeneratorClk();
sc_time sendingOffset;
if (transactionsSent == 0)
sendingOffset = SC_ZERO_TIME + generatorClk * clksToIdle();
else
sendingOffset = (generatorClk * clksPerRequest()) - (sc_time_stamp() % generatorClk) + generatorClk * clksToIdle();
// TODO: do not send two requests in the same cycle
sendToTarget(payload, tlm::BEGIN_REQ, sendingOffset);
transactionsSent++;
PRINTDEBUGMESSAGE(name(), "Performing request #" + std::to_string(transactionsSent));
payloadSent();
}
TrafficGenerator::TrafficGenerator(const sc_module_name& name, const Configuration& config,
const DRAMSys::Config::TraceGenerator& conf, TraceSetup& setup)
: TrafficGeneratorIf(name, config, setup, conf.maxPendingReadRequests.value_or(defaultMaxPendingReadRequests),
conf.maxPendingWriteRequests.value_or(defaultMaxPendingWriteRequests),
conf.dataLength.value_or(config.memSpec->defaultBytesPerBurst)),
generatorClk(TrafficInitiator::evaluateGeneratorClk(conf)), conf(conf),
maxTransactions(conf.maxTransactions.value_or(std::numeric_limits<uint64_t>::max())),
simMemSizeInBytes(config.memSpec->getSimMemSizeInBytes()),
randomGenerator(std::default_random_engine(conf.seed.value_or(defaultSeed)))
{
// Perform checks for all states
for (const auto &state : conf.states)
{
if (auto trafficState = std::get_if<DRAMSys::Config::TraceGeneratorTrafficState>(&state.second))
{
uint64_t minAddress = evaluateMinAddress(*trafficState);
uint64_t maxAddress = evaluateMaxAddress(*trafficState, simMemSizeInBytes);
double rwRatio = (*trafficState).rwRatio;
if (minAddress > config.memSpec->getSimMemSizeInBytes() - 1)
SC_REPORT_FATAL("TrafficGenerator", "minAddress is out of range.");
if (maxAddress > config.memSpec->getSimMemSizeInBytes() - 1)
SC_REPORT_FATAL("TrafficGenerator", "minAddress is out of range.");
if (maxAddress < minAddress)
SC_REPORT_FATAL("TrafficGenerator", "maxAddress is smaller than minAddress.");
if (rwRatio < 0 || rwRatio > 1)
SC_REPORT_FATAL("TraceSetup", "Read/Write ratio is not a number between 0 and 1.");
if (const auto &eventName = trafficState->notify)
{
stateTranstitionEvents.emplace(std::piecewise_construct, std::forward_as_tuple(*eventName),
std::forward_as_tuple(eventName->c_str(), state.first));
}
}
}
if (auto trafficState =
std::get_if<DRAMSys::Config::TraceGeneratorTrafficState>(&conf.states.at(currentState)))
{
uint64_t minAddress = evaluateMinAddress(*trafficState);
uint64_t maxAddress = evaluateMaxAddress(*trafficState, simMemSizeInBytes);
randomAddressDistribution = std::uniform_int_distribution<uint64_t>(minAddress, maxAddress);
currentClksPerRequest = trafficState->clksPerRequest.value_or(defaultClksPerRequest);
}
calculateTransitions();
}
void TrafficGenerator::calculateTransitions()
{
unsigned int state = 0;
uint64_t totalTransactions = 0;
stateSequence.push_back(state);
while (true)
{
auto transitionsIt = conf.transitions.equal_range(state);
float probabilityAccumulated = 0.0f;
std::map<unsigned int, std::pair<float, float>> transitionsDistribution;
for (auto it = transitionsIt.first; it != transitionsIt.second; ++it)
{
float lowerLimit = probabilityAccumulated;
probabilityAccumulated += it->second.probability;
float upperLimit = probabilityAccumulated;
transitionsDistribution[it->second.to] = {lowerLimit, upperLimit};
}
if (probabilityAccumulated > 1.001f)
SC_REPORT_WARNING("TrafficGenerator", "Sum of transition probabilities greater than 1.");
float random = randomDistribution(randomGenerator);
bool transitionFound = false;
for (const auto &transition : transitionsDistribution)
{
auto to = transition.first;
auto limits = transition.second;
if (limits.first < random && limits.second > random)
{
state = to;
stateSequence.push_back(state);
transitionFound = true;
break;
}
}
if (transitionFound)
{
if (auto trafficState =
std::get_if<DRAMSys::Config::TraceGeneratorTrafficState>(&conf.states.at(state)))
totalTransactions += trafficState->numRequests;
if (totalTransactions < maxTransactions)
continue;
}
break;
}
stateIt = stateSequence.cbegin();
}
bool TrafficGenerator::hasStateTransitionEvent(const std::string &eventName) const
{
auto it = stateTranstitionEvents.find(eventName);
if (it == stateTranstitionEvents.end())
return false;
return true;
}
const sc_core::sc_event &TrafficGenerator::getStateTransitionEvent(const std::string &eventName) const
{
auto it = stateTranstitionEvents.find(eventName);
if (it == stateTranstitionEvents.end())
SC_REPORT_FATAL("TraceSetup", "StateTransitionEvent not found.");
return it->second.event;
}
uint64_t TrafficGenerator::getTotalTransactions() const
{
uint64_t totalTransactions = 0;
for (auto state : stateSequence)
{
if (auto trafficState = std::get_if<DRAMSys::Config::TraceGeneratorTrafficState>(&conf.states.at(state)))
totalTransactions += trafficState->numRequests;
}
if (totalTransactions > maxTransactions)
totalTransactions = maxTransactions;
return totalTransactions;
}
void TrafficGenerator::waitUntil(const sc_core::sc_event *ev)
{
startEvent = ev;
}
void TrafficGenerator::transitionToNextState()
{
++stateIt;
if (stateIt == stateSequence.cend() || transactionsSent >= maxTransactions)
{
// No transition performed.
finished = true;
return;
}
currentState = *stateIt;
// Notify
for (auto &it : stateTranstitionEvents)
{
if (it.second.stateId == currentState)
it.second.event.notify();
}
if (auto idleState = std::get_if<DRAMSys::Config::TraceGeneratorIdleState>(&conf.states.at(currentState)))
{
currentClksToIdle += idleState->idleClks;
transitionToNextState();
return;
}
else if (auto trafficState =
std::get_if<DRAMSys::Config::TraceGeneratorTrafficState>(&conf.states.at(currentState)))
{
uint64_t minAddress = evaluateMinAddress(*trafficState);
uint64_t maxAddress = evaluateMaxAddress(*trafficState, simMemSizeInBytes);
randomAddressDistribution = std::uniform_int_distribution<uint64_t>(minAddress, maxAddress);
currentClksPerRequest = trafficState->clksPerRequest.value_or(defaultClksPerRequest);
}
currentAddress = 0x00;
transactionsSentInCurrentState = 0;
}
void TrafficGenerator::prepareNextPayload()
{
if (transactionsSent >= maxTransactions)
{
finished = true;
return;
}
if (startEvent && transactionsSent == 0)
wait(*startEvent);
if (auto trafficState =
std::get_if<DRAMSys::Config::TraceGeneratorTrafficState>(&conf.states.at(currentState)))
{
if (transactionsSentInCurrentState >= trafficState->numRequests)
transitionToNextState();
}
// In case we are in an idle state right at the beginning of the simulation,
// set the clksToIdle and transition to the next state.
if (auto idleState =
std::get_if<DRAMSys::Config::TraceGeneratorIdleState>(&conf.states.at(currentState)))
{
currentClksToIdle = idleState->idleClks;
transitionToNextState();
}
}
void TrafficGenerator::payloadSent()
{
// Reset clks to idle.
currentClksToIdle = 0;
transactionsSentInCurrentState++;
}
tlm::tlm_command TrafficGenerator::getNextCommand()
{
// An idle state should never reach this method.
auto &state = std::get<DRAMSys::Config::TraceGeneratorTrafficState>(conf.states.at(currentState));
tlm_command command;
if (randomDistribution(randomGenerator) < state.rwRatio)
command = tlm::TLM_READ_COMMAND;
else
command = tlm::TLM_WRITE_COMMAND;
return command;
}
sc_core::sc_time TrafficGenerator::getGeneratorClk() const
{
return generatorClk;
}
uint64_t TrafficGenerator::getNextAddress()
{
using DRAMSys::Config::AddressDistribution;
// An idle state should never reach this method.
auto &state = std::get<DRAMSys::Config::TraceGeneratorTrafficState>(conf.states.at(currentState));
uint64_t minAddress = evaluateMinAddress(state);
uint64_t maxAddress = evaluateMaxAddress(state, simMemSizeInBytes);
if (state.addressDistribution == AddressDistribution::Sequential)
{
uint64_t addressIncrement = state.addressIncrement.value_or(defaultAddressIncrement);
uint64_t address = currentAddress;
currentAddress += addressIncrement;
if (currentAddress > maxAddress)
currentAddress = minAddress;
return address;
}
else if (state.addressDistribution == AddressDistribution::Random)
{
return randomAddressDistribution(randomGenerator);
}
else
{
return 0x00;
}
}
uint64_t TrafficGenerator::evaluateMinAddress(const DRAMSys::Config::TraceGeneratorTrafficState &state)
{
return state.minAddress.value_or(0x00);
}
uint64_t TrafficGenerator::evaluateMaxAddress(const DRAMSys::Config::TraceGeneratorTrafficState &state,
uint64_t simMemSizeInBytes)
{
return state.maxAddress.value_or(simMemSizeInBytes - 1);
}
TrafficGeneratorHammer::TrafficGeneratorHammer(const sc_core::sc_module_name &name, const Configuration& config,
const DRAMSys::Config::TraceHammer &conf, TraceSetup& setup)
: TrafficGeneratorIf(name, config, setup, 1, 1, config.memSpec->defaultBytesPerBurst),
generatorClk(evaluateGeneratorClk(conf)), rowIncrement(conf.rowIncrement), numRequests(conf.numRequests)
{
}
tlm::tlm_command TrafficGeneratorHammer::getNextCommand()
{
return tlm::TLM_READ_COMMAND;
}
sc_core::sc_time TrafficGeneratorHammer::getGeneratorClk() const
{
return generatorClk;
}
uint64_t TrafficGeneratorHammer::getNextAddress()
{
if (currentAddress == 0x0)
currentAddress = rowIncrement;
else
currentAddress = 0x0;
return currentAddress;
}
void TrafficGeneratorHammer::prepareNextPayload()
{
if (transactionsSent >= numRequests)
finished = true;
}

View File

@@ -1,150 +0,0 @@
/*
* Copyright (c) 2015, 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:
* Janik Schlemminger
* Robert Gernhardt
* Matthias Jung
* Derek Christ
*/
#ifndef TRAFFICGENERATOR_H
#define TRAFFICGENERATOR_H
#include "simulator/TrafficInitiator.h"
#include "simulator/TraceSetup.h"
#include <cstdint>
#include <map>
#include <random>
class TrafficGeneratorIf : public TrafficInitiator
{
public:
TrafficGeneratorIf(const sc_core::sc_module_name &name, const Configuration& config, TraceSetup& setup,
unsigned int maxPendingReadRequests, unsigned int maxPendingWriteRequests,
unsigned int dataLength);
private:
void sendNextPayload() override;
virtual void prepareNextPayload(){};
virtual uint64_t getNextAddress() = 0;
virtual tlm::tlm_command getNextCommand() = 0;
virtual sc_core::sc_time getGeneratorClk() const = 0;
virtual void payloadSent(){};
virtual uint64_t clksPerRequest() const { return 1; }
virtual uint64_t clksToIdle() const { return 0; }
};
class TrafficGenerator : public TrafficGeneratorIf
{
public:
TrafficGenerator(const sc_core::sc_module_name &name, const Configuration& config,
const DRAMSys::Config::TraceGenerator &conf, TraceSetup& setup);
uint64_t getTotalTransactions() const;
void waitUntil(const sc_core::sc_event *ev);
bool hasStateTransitionEvent(const std::string &eventName) const;
const sc_core::sc_event &getStateTransitionEvent(const std::string &eventName) const;
private:
static uint64_t evaluateMinAddress(const DRAMSys::Config::TraceGeneratorTrafficState& state);
static uint64_t evaluateMaxAddress(const DRAMSys::Config::TraceGeneratorTrafficState& state,
uint64_t simMemSizeInBytes);
void prepareNextPayload() override;
uint64_t getNextAddress() override;
tlm::tlm_command getNextCommand() override;
sc_core::sc_time getGeneratorClk() const override;
void payloadSent() override;
uint64_t clksPerRequest() const override { return currentClksPerRequest; };
uint64_t clksToIdle() const override { return currentClksToIdle; }
void calculateTransitions();
void transitionToNextState();
sc_core::sc_time generatorClk;
const DRAMSys::Config::TraceGenerator &conf;
unsigned int currentState = 0;
uint64_t currentAddress = 0x00;
uint64_t currentClksPerRequest = 1;
uint64_t transactionsSentInCurrentState = 0;
const uint64_t maxTransactions;
const uint64_t simMemSizeInBytes;
uint64_t currentClksToIdle = 0;
std::vector<unsigned int> stateSequence;
std::vector<unsigned int>::const_iterator stateIt;
struct EventPair
{
EventPair(const std::string &name, unsigned int id) : event(name.c_str()), stateId(id)
{
}
sc_core::sc_event event;
unsigned int stateId;
};
std::map<std::string, EventPair> stateTranstitionEvents;
bool idleAtStart = false;
const sc_core::sc_event *startEvent = nullptr;
std::default_random_engine randomGenerator;
std::uniform_real_distribution<float> randomDistribution = std::uniform_real_distribution<float>(0.0f, 1.0f);
std::uniform_int_distribution<uint64_t> randomAddressDistribution;
static constexpr uint64_t defaultSeed = 0;
static constexpr uint64_t defaultClksPerRequest = 1;
static constexpr uint64_t defaultAddressIncrement = 0x00;
};
class TrafficGeneratorHammer final : public TrafficGeneratorIf
{
public:
TrafficGeneratorHammer(const sc_core::sc_module_name &name, const Configuration& config,
const DRAMSys::Config::TraceHammer &conf, TraceSetup& setup);
private:
void prepareNextPayload() override;
uint64_t getNextAddress() override;
tlm::tlm_command getNextCommand() override;
sc_core::sc_time getGeneratorClk() const override;
sc_core::sc_time generatorClk;
uint64_t rowIncrement;
uint64_t currentAddress = 0x0;
uint64_t numRequests;
};
#endif // TRAFFICGENERATOR_H

View File

@@ -1,138 +0,0 @@
/*
* Copyright (c) 2015, 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:
* Robert Gernhardt
* Matthias Jung
* Éder F. Zulian
* Felipe S. Prado
* Derek Christ
*/
#include "TrafficInitiator.h"
using namespace sc_core;
using namespace tlm;
TrafficInitiator::TrafficInitiator(const sc_module_name &name, const Configuration& config, TraceSetup& setup,
unsigned int maxPendingReadRequests, unsigned int maxPendingWriteRequests, unsigned int defaultDataLength) :
sc_module(name),
payloadEventQueue(this, &TrafficInitiator::peqCallback),
setup(setup),
maxPendingReadRequests(maxPendingReadRequests),
maxPendingWriteRequests(maxPendingWriteRequests),
defaultDataLength(defaultDataLength),
storageEnabled(config.storeMode != Configuration::StoreMode::NoStorage),
simulationProgressBar(config.simulationProgressBar)
{
SC_THREAD(sendNextPayload);
iSocket.register_nb_transport_bw(this, &TrafficInitiator::nb_transport_bw);
}
void TrafficInitiator::terminate()
{
std::cout << sc_time_stamp() << " " << this->name() << " terminated " << std::endl;
setup.trafficInitiatorTerminates();
}
tlm_sync_enum TrafficInitiator::nb_transport_bw(tlm_generic_payload &payload,
tlm_phase &phase, sc_time &bwDelay)
{
payloadEventQueue.notify(payload, phase, bwDelay);
return TLM_ACCEPTED;
}
void TrafficInitiator::peqCallback(tlm_generic_payload &payload,
const tlm_phase &phase)
{
if (phase == END_REQ)
{
if (nextPayloadSendable())
sendNextPayload();
else
payloadPostponed = true;
}
else if (phase == BEGIN_RESP)
{
payload.release();
sendToTarget(payload, END_RESP, SC_ZERO_TIME);
if (simulationProgressBar)
setup.transactionFinished();
transactionsReceived++;
if (payload.get_command() == tlm::TLM_READ_COMMAND)
pendingReadRequests--;
else if (payload.get_command() == tlm::TLM_WRITE_COMMAND)
pendingWriteRequests--;
// If the initiator wasn't able to send the next payload in the END_REQ phase, do it now.
if (payloadPostponed && nextPayloadSendable())
{
sendNextPayload();
payloadPostponed = false;
}
// If all answers were received:
if (finished && transactionsSent == transactionsReceived)
terminate();
}
else
{
SC_REPORT_FATAL("TrafficInitiator", "PEQ was triggered with unknown phase");
}
}
void TrafficInitiator::sendToTarget(tlm_generic_payload &payload, const tlm_phase &phase, const sc_time &delay)
{
tlm_phase TPhase = phase;
sc_time TDelay = delay;
iSocket->nb_transport_fw(payload, TPhase, TDelay);
}
bool TrafficInitiator::nextPayloadSendable() const
{
// If either the maxPendingReadRequests or maxPendingWriteRequests
// limit is reached, do not send next payload.
if (((pendingReadRequests >= maxPendingReadRequests) && (maxPendingReadRequests != 0))
|| ((pendingWriteRequests >= maxPendingWriteRequests) && (maxPendingWriteRequests != 0)))
return false;
else
return true;
}
sc_core::sc_time TrafficInitiator::evaluateGeneratorClk(const DRAMSys::Config::TrafficInitiator& conf)
{
double frequencyMHz = conf.clkMhz;
sc_time playerClk = sc_time(1.0 / frequencyMHz, SC_US);
return playerClk;
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) 2023, 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:
* Derek Christ
*/
#include "RandomProducer.h"
#include "definitions.h"
RandomProducer::RandomProducer(uint64_t numRequests,
std::optional<uint64_t> seed,
double rwRatio,
unsigned int clkMhz,
std::optional<uint64_t> minAddress,
std::optional<uint64_t> maxAddress,
uint64_t memorySize,
unsigned int dataLength,
unsigned int dataAlignment)
: numberOfRequests(numRequests),
seed(seed.value_or(DEFAULT_SEED)),
rwRatio(rwRatio),
randomGenerator(this->seed),
generatorPeriod(sc_core::sc_time(1.0 / static_cast<double>(clkMhz), sc_core::SC_US)),
dataLength(dataLength),
dataAlignment(dataAlignment),
randomAddressDistribution(minAddress.value_or(DEFAULT_MIN_ADDRESS),
maxAddress.value_or((memorySize) - dataLength))
{
if (minAddress > memorySize - 1)
SC_REPORT_FATAL("TrafficGenerator", "minAddress is out of range.");
if (maxAddress > memorySize - 1)
SC_REPORT_FATAL("TrafficGenerator", "minAddress is out of range.");
if (maxAddress < minAddress)
SC_REPORT_FATAL("TrafficGenerator", "maxAddress is smaller than minAddress.");
if (rwRatio < 0 || rwRatio > 1)
SC_REPORT_FATAL("TraceSetup", "Read/Write ratio is not a number between 0 and 1.");
}
Request RandomProducer::nextRequest()
{
Request request;
request.address = randomAddressDistribution(randomGenerator);
// Align address
request.address = request.address - (request.address % dataAlignment);
request.command = readWriteDistribution(randomGenerator) < rwRatio ? Request::Command::Read
: Request::Command::Write;
request.length = dataLength;
request.delay = generatorPeriod;
return request;
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2023, 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:
* Derek Christ
*/
#pragma once
#include "simulator/request/RequestProducer.h"
#include <optional>
#include <random>
class RandomProducer : public RequestProducer
{
public:
RandomProducer(uint64_t numRequests,
std::optional<uint64_t> seed,
double rwRatio,
unsigned int clkMhz,
std::optional<uint64_t> minAddress,
std::optional<uint64_t> maxAddress,
uint64_t memorySize,
unsigned int dataLength,
unsigned int dataAlignment);
Request nextRequest() override;
uint64_t totalRequests() override { return numberOfRequests; }
sc_core::sc_time clkPeriod() override { return generatorPeriod; }
const uint64_t numberOfRequests;
const uint64_t seed;
const double rwRatio;
const sc_core::sc_time generatorPeriod;
const unsigned int dataLength;
const unsigned int dataAlignment;
std::default_random_engine randomGenerator;
std::uniform_real_distribution<double> readWriteDistribution{0.0, 1.0};
std::uniform_int_distribution<uint64_t> randomAddressDistribution;
};

View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) 2023, 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:
* Derek Christ
*/
#include "SequentialProducer.h"
#include "definitions.h"
SequentialProducer::SequentialProducer(uint64_t numRequests,
std::optional<uint64_t> seed,
double rwRatio,
unsigned int clkMhz,
std::optional<uint64_t> addressIncrement,
std::optional<uint64_t> minAddress,
std::optional<uint64_t> maxAddress,
uint64_t memorySize,
unsigned int dataLength)
: numberOfRequests(numRequests),
addressIncrement(addressIncrement.value_or(dataLength)),
minAddress(minAddress.value_or(DEFAULT_MIN_ADDRESS)),
maxAddress(maxAddress.value_or(memorySize - 1)),
seed(seed.value_or(DEFAULT_SEED)),
rwRatio(rwRatio),
randomGenerator(this->seed),
generatorPeriod(sc_core::sc_time(1.0 / static_cast<double>(clkMhz), sc_core::SC_US)),
dataLength(dataLength)
{
if (minAddress > memorySize - 1)
SC_REPORT_FATAL("TrafficGenerator", "minAddress is out of range.");
if (maxAddress > memorySize - 1)
SC_REPORT_FATAL("TrafficGenerator", "minAddress is out of range.");
if (maxAddress < minAddress)
SC_REPORT_FATAL("TrafficGenerator", "maxAddress is smaller than minAddress.");
if (rwRatio < 0 || rwRatio > 1)
SC_REPORT_FATAL("TraceSetup", "Read/Write ratio is not a number between 0 and 1.");
}
Request SequentialProducer::nextRequest()
{
Request request;
request.address = generatedRequests * addressIncrement % (maxAddress - minAddress) + minAddress;
request.command = readWriteDistribution(randomGenerator) < rwRatio ? Request::Command::Read
: Request::Command::Write;
request.length = dataLength;
request.delay = generatorPeriod;
generatedRequests++;
return request;
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2023, 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:
* Derek Christ
*/
#pragma once
#include "simulator/request/RequestProducer.h"
#include <optional>
#include <random>
class SequentialProducer : public RequestProducer
{
public:
SequentialProducer(uint64_t numRequests,
std::optional<uint64_t> seed,
double rwRatio,
unsigned int clkMhz,
std::optional<uint64_t> addressIncrement,
std::optional<uint64_t> minAddress,
std::optional<uint64_t> maxAddress,
uint64_t memorySize,
unsigned int dataLength);
Request nextRequest() override;
uint64_t totalRequests() override { return numberOfRequests; }
sc_core::sc_time clkPeriod() override { return generatorPeriod; }
void reset() override { generatedRequests = 0; }
const uint64_t numberOfRequests;
const uint64_t addressIncrement;
const uint64_t minAddress;
const uint64_t maxAddress;
const uint64_t seed;
const double rwRatio;
const sc_core::sc_time generatorPeriod;
const unsigned int dataLength;
std::default_random_engine randomGenerator;
std::uniform_real_distribution<double> readWriteDistribution{0.0, 1.0};
uint64_t generatedRequests = 0;
};

View File

@@ -0,0 +1,246 @@
/*
* Copyright (c) 2023, 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:
* Derek Christ
*/
#include "TrafficGenerator.h"
TrafficGenerator::TrafficGenerator(DRAMSys::Config::TrafficGeneratorStateMachine const &config,
MemoryManager &memoryManager,
uint64_t memorySize,
unsigned int defaultDataLength,
std::function<void()> transactionFinished,
std::function<void()> terminateInitiator)
: consumer(
config.name.c_str(),
memoryManager,
config.maxPendingReadRequests,
config.maxPendingWriteRequests,
[this] { return nextRequest(); },
std::move(transactionFinished),
std::move(terminateInitiator)),
stateTransistions(config.transitions)
{
unsigned int dataLength = config.dataLength.value_or(defaultDataLength);
unsigned int dataAlignment = config.dataAlignment.value_or(dataLength);
for (auto const &state : config.states)
{
std::visit(
[=, &config](auto &&arg)
{
using DRAMSys::Config::TrafficGeneratorActiveState;
using DRAMSys::Config::TrafficGeneratorIdleState;
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, TrafficGeneratorActiveState>)
{
auto const &activeState = arg;
if (activeState.addressDistribution ==
DRAMSys::Config::AddressDistribution::Random)
{
auto producer = std::make_unique<RandomProducer>(activeState.numRequests,
config.seed,
activeState.rwRatio,
config.clkMhz,
activeState.minAddress,
activeState.maxAddress,
memorySize,
dataLength,
dataAlignment);
producers.emplace(activeState.id, std::move(producer));
}
else
{
auto producer =
std::make_unique<SequentialProducer>(activeState.numRequests,
config.seed,
activeState.rwRatio,
config.clkMhz,
activeState.addressIncrement,
activeState.minAddress,
activeState.maxAddress,
memorySize,
dataLength);
producers.emplace(activeState.id, std::move(producer));
}
}
else if constexpr (std::is_same_v<T, TrafficGeneratorIdleState>)
{
auto const &idleState = arg;
idleStateClks.emplace(idleState.id, idleState.idleClks);
}
},
state);
}
}
TrafficGenerator::TrafficGenerator(DRAMSys::Config::TrafficGenerator const &config,
MemoryManager &memoryManager,
uint64_t memorySize,
unsigned int defaultDataLength,
std::function<void()> transactionFinished,
std::function<void()> terminateInitiator)
: consumer(
config.name.c_str(),
memoryManager,
config.maxPendingReadRequests,
config.maxPendingWriteRequests,
[this] { return nextRequest(); },
std::move(transactionFinished),
std::move(terminateInitiator))
{
unsigned int dataLength = config.dataLength.value_or(defaultDataLength);
unsigned int dataAlignment = config.dataAlignment.value_or(dataLength);
if (config.addressDistribution == DRAMSys::Config::AddressDistribution::Random)
{
auto producer = std::make_unique<RandomProducer>(config.numRequests,
config.seed,
config.rwRatio,
config.clkMhz,
config.minAddress,
config.maxAddress,
memorySize,
dataLength,
dataAlignment);
producers.emplace(0, std::move(producer));
}
else
{
auto producer = std::make_unique<SequentialProducer>(config.numRequests,
config.seed,
config.rwRatio,
config.clkMhz,
config.addressIncrement,
config.minAddress,
config.maxAddress,
memorySize,
dataLength);
producers.emplace(0, std::move(producer));
}
}
Request TrafficGenerator::nextRequest()
{
uint64_t clksToIdle = 0;
if (requestsInState >= producers[currentState]->totalRequests())
{
// Reset current producer to its initial state
producers[currentState]->reset();
auto newState = stateTransition(currentState);
if (!newState.has_value())
return Request{.command = Request::Command::Stop};
auto idleStateIt = idleStateClks.find(newState.value());
while (idleStateIt != idleStateClks.cend())
{
clksToIdle += idleStateIt->second;
newState = stateTransition(currentState);
if (!newState.has_value())
return Request{.command = Request::Command::Stop};
currentState = newState.value();
idleStateIt = idleStateClks.find(newState.value());
}
currentState = newState.value();
requestsInState = 0;
}
requestsInState++;
Request request = producers[currentState]->nextRequest();
request.delay += producers[currentState]->clkPeriod() * clksToIdle;
return request;
}
uint64_t TrafficGenerator::totalRequests()
{
// Store current state of random generator
std::default_random_engine tempGenerator(randomGenerator);
// Reset generator to initial state
randomGenerator.seed();
uint64_t totalRequests = 0;
unsigned int currentState = 0;
if (producers.find(currentState) != producers.cend())
totalRequests += producers.at(currentState)->totalRequests();
while (auto nextState = stateTransition(currentState))
{
currentState = nextState.value();
if (producers.find(currentState) != producers.cend())
totalRequests += producers.at(currentState)->totalRequests();
}
// Restore state of random generator
randomGenerator = tempGenerator;
return totalRequests;
}
std::optional<unsigned int> TrafficGenerator::stateTransition(unsigned int from)
{
using Transition = DRAMSys::Config::TrafficGeneratorStateTransition;
std::vector<Transition> relevantTransitions;
std::copy_if(stateTransistions.cbegin(),
stateTransistions.cend(),
std::back_inserter(relevantTransitions),
[from](Transition transition) { return transition.from == from; });
if (relevantTransitions.empty())
return std::nullopt;
std::vector<double> propabilities;
std::for_each(relevantTransitions.cbegin(),
relevantTransitions.cend(),
[&propabilities](Transition transition)
{ propabilities.push_back(transition.probability); });
assert(propabilities.size() == relevantTransitions.size());
std::discrete_distribution<std::size_t> stateTransitionDistribution(propabilities.cbegin(),
propabilities.cend());
std::size_t index = stateTransitionDistribution(randomGenerator);
return relevantTransitions[index].to;
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) 2023, 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:
* Derek Christ
*/
#pragma once
#include "RandomProducer.h"
#include "SequentialProducer.h"
#include "simulator/Initiator.h"
#include "simulator/MemoryManager.h"
#include "simulator/request/RequestIssuer.h"
#include <DRAMSys/config/DRAMSysConfiguration.h>
class TrafficGenerator : public Initiator
{
public:
TrafficGenerator(DRAMSys::Config::TrafficGenerator const &config,
MemoryManager &memoryManager,
uint64_t memorySize,
unsigned int defaultDataLength,
std::function<void()> transactionFinished,
std::function<void()> terminateInitiator);
TrafficGenerator(DRAMSys::Config::TrafficGeneratorStateMachine const &config,
MemoryManager &memoryManager,
uint64_t memorySize,
unsigned int defaultDataLength,
std::function<void()> transactionFinished,
std::function<void()> terminateInitiator);
void bind(tlm_utils::multi_target_base<> &target) override { consumer.iSocket.bind(target); }
uint64_t totalRequests() override;
Request nextRequest();
std::optional<unsigned int> stateTransition(unsigned int from);
private:
uint64_t requestsInState = 0;
unsigned int currentState = 0;
const std::vector<DRAMSys::Config::TrafficGeneratorStateTransition> stateTransistions;
using IdleClks = uint64_t;
std::unordered_map<unsigned int, IdleClks> idleStateClks;
std::default_random_engine randomGenerator;
std::unordered_map<unsigned int, std::unique_ptr<RequestProducer>> producers;
RequestIssuer consumer;
};

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2023, 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:
* Derek Christ
*/
#pragma once
#include <cstdint>
inline constexpr uint64_t DEFAULT_SEED = 0;
inline constexpr uint64_t DEFAULT_MIN_ADDRESS = 0;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Technische Universität Kaiserslautern
* Copyright (c) 2023, Technische Universität Kaiserslautern
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,46 +33,35 @@
* Derek Christ
*/
#include "MemSpec.h"
#include "RowHammer.h"
namespace DRAMSys::Config
RowHammer::RowHammer(uint64_t numRequests,
unsigned int clkMhz,
uint64_t rowIncrement,
unsigned int dataLength)
: numberOfRequests(numRequests),
generatorPeriod(sc_core::sc_time(1.0 / static_cast<double>(clkMhz), sc_core::SC_US)),
dataLength(dataLength),
rowIncrement(rowIncrement)
{
void to_json(json &j, const MemSpec &c)
{
j = json{{"memarchitecturespec", c.memArchitectureSpec},
{"memoryId", c.memoryId},
{"memoryType", c.memoryType},
{"memtimingspec", c.memTimingSpec},
{"mempowerspec", c.memPowerSpec}};
remove_null_values(j);
}
void from_json(const json &j, MemSpec &c)
Request RowHammer::nextRequest()
{
json j_memspecs = get_config_json(j, memSpecPath, "memspec");
if (generatedRequests >= numberOfRequests)
return Request{.command = Request::Command::Stop};
generatedRequests++;
j_memspecs.at("memarchitecturespec").get_to(c.memArchitectureSpec);
j_memspecs.at("memoryId").get_to(c.memoryId);
j_memspecs.at("memoryType").get_to(c.memoryType);
j_memspecs.at("memtimingspec").get_to(c.memTimingSpec);
if (currentAddress == 0x00)
currentAddress = rowIncrement;
else
currentAddress = 0x00;
if (j_memspecs.contains("mempowerspec"))
j_memspecs.at("mempowerspec").get_to(c.memPowerSpec);
Request request;
request.address = currentAddress;
request.command = Request::Command::Read;
request.length = dataLength;
request.delay = generatorPeriod;
return request;
}
void from_dump(const std::string &dump, MemSpec &c)
{
json json_memspec = json::parse(dump).at("memspec");
json_memspec.get_to(c);
}
std::string dump(const MemSpec &c, unsigned int indentation)
{
json json_memspec;
json_memspec["memspec"] = c;
return json_memspec.dump(indentation);
}
} // namespace Configuration

View File

@@ -0,0 +1,61 @@
/*
* Copyright (c) 2023, 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:
* Derek Christ
*/
#pragma once
#include "simulator/request/RequestProducer.h"
#include <systemc>
class RowHammer : public RequestProducer
{
public:
RowHammer(uint64_t numRequests,
unsigned int clkMhz,
uint64_t rowIncrement,
unsigned int dataLength);
Request nextRequest() override;
sc_core::sc_time clkPeriod() override { return generatorPeriod; }
uint64_t totalRequests() override { return numberOfRequests; }
const uint64_t numberOfRequests;
const sc_core::sc_time generatorPeriod;
const unsigned int dataLength;
const uint64_t rowIncrement;
uint64_t generatedRequests = 0;
uint64_t currentAddress = 0x00;
};

View File

@@ -1,134 +0,0 @@
/*
* Copyright (c) 2015, 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:
* Robert Gernhardt
* Matthias Jung
* Luiza Correa
* Lukas Steiner
* Derek Christ
*/
#include "simulator/TraceSetup.h"
#include "simulator/TrafficInitiator.h"
#include "DRAMSys/simulation/DRAMSys.h"
#include "DRAMSys/simulation/DRAMSysRecordable.h"
#include "DRAMSys/config/DRAMSysConfiguration.h"
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <chrono>
#include <systemc>
using namespace sc_core;
std::string pathOfFile(const std::string &file)
{
return file.substr(0, file.find_last_of('/'));
}
int main(int argc, char **argv)
{
return sc_main(argc, argv);
}
int sc_main(int argc, char **argv)
{
sc_set_time_resolution(1, SC_PS);
std::string resources;
std::string simulationJson;
// Run only with default config (ddr3-example.json):
if (argc == 1)
{
// Get path of resources:
resources = pathOfFile(argv[0])
+ std::string("/../../configs/");
simulationJson = resources + "ddr4-example.json";
}
// Run with specific config but default resource folders:
else if (argc == 2)
{
// Get path of resources:
resources = pathOfFile(argv[0])
+ std::string("/../../configs/");
simulationJson = argv[1];
}
// Run with specific config and specific resource folder:
else if (argc == 3)
{
simulationJson = argv[1];
resources = argv[2];
}
std::vector<std::unique_ptr<TrafficInitiator>> players;
DRAMSys::Config::Configuration configLib = DRAMSys::Config::from_path(simulationJson, resources);
// Instantiate DRAMSys:
std::unique_ptr<DRAMSys::DRAMSys> dramSys;
if (configLib.simConfig.databaseRecording.value_or(false))
dramSys = std::make_unique<DRAMSys::DRAMSysRecordable>("DRAMSys", configLib);
else
dramSys = std::make_unique<DRAMSys::DRAMSys>("DRAMSys", configLib);
if (!configLib.traceSetup.has_value())
SC_REPORT_FATAL("sc_main", "No trace setup section provided.");
// Instantiate STL Players:
TraceSetup setup(dramSys->getConfig(), configLib.traceSetup.value(), resources, players);
// Bind STL Players with DRAMSys:
for (auto& player : players)
player->iSocket.bind(dramSys->tSocket);
// Store the starting of the simulation in wall-clock time:
auto start = std::chrono::high_resolution_clock::now();
// Start SystemC Simulation:
sc_set_stop_mode(SC_STOP_FINISH_DELTA);
sc_start();
if (!sc_end_of_simulation_invoked())
{
SC_REPORT_WARNING("sc_main", "Simulation stopped without explicit sc_stop()");
sc_stop();
}
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;
return 0;
}

View File

@@ -0,0 +1,226 @@
/*
* Copyright (c) 2023, 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:
* Janik Schlemminger
* Robert Gernhardt
* Matthias Jung
* Éder F. Zulian
* Felipe S. Prado
* Derek Christ
*/
#include "StlPlayer.h"
#include <sstream>
StlPlayer::StlPlayer(std::string_view tracePath,
unsigned int clkMhz,
unsigned int defaultDataLength,
TraceType traceType,
bool storageEnabled)
: traceFile(tracePath.data()),
playerPeriod(sc_core::sc_time(1.0 / static_cast<double>(clkMhz), sc_core::SC_US)),
defaultDataLength(defaultDataLength),
traceType(traceType),
storageEnabled(storageEnabled),
lineBuffers(
{std::make_shared<std::vector<Request>>(), std::make_shared<std::vector<Request>>()}),
readoutBuffer(lineBuffers.at(0)),
parseBuffer(lineBuffers.at(1))
{
readoutBuffer->reserve(LINE_BUFFER_SIZE);
parseBuffer->reserve(LINE_BUFFER_SIZE);
if (!traceFile.is_open())
SC_REPORT_FATAL("StlPlayer",
(std::string("Could not open trace ") + tracePath.data()).c_str());
{
std::string line;
while (std::getline(traceFile, line))
{
if (line.size() > 1 && line[0] != '#')
numberOfLines++;
}
traceFile.clear();
traceFile.seekg(0);
}
parseTraceFile();
readoutIt = readoutBuffer->cend();
}
Request StlPlayer::nextRequest()
{
if (readoutIt == readoutBuffer->cend())
{
readoutIt = swapBuffers();
if (readoutIt == readoutBuffer->cend())
{
if (parserThread.joinable())
parserThread.join();
// The file is read in completely. Nothing more to do.
return Request{.command = Request::Command::Stop};
}
}
sc_core::sc_time delay = readoutIt->delay;
sc_core::sc_time offset = playerPeriod - (sc_core::sc_time_stamp() % playerPeriod);
if (traceType == TraceType::Absolute)
{
delay = std::max(sc_core::sc_time_stamp() + offset, delay);
delay -= sc_core::sc_time_stamp();
}
else // if (traceType == TraceType::Relative)
{
delay = offset + delay;
}
Request request(*readoutIt);
request.delay = delay;
readoutIt++;
return request;
}
void StlPlayer::parseTraceFile()
{
unsigned parsedLines = 0;
parseBuffer->clear();
while (traceFile && !traceFile.eof() && parsedLines < LINE_BUFFER_SIZE)
{
// Get a new line from the input file.
std::string line;
std::getline(traceFile, line);
currentLine++;
// If the line is empty (\n or \r\n) or starts with '#' (comment) the transaction is
// ignored.
if (line.size() <= 1 || line.at(0) == '#')
continue;
parsedLines++;
parseBuffer->emplace_back();
Request &content = parseBuffer->back();
// Trace files MUST provide timestamp, command and address for every
// transaction. The data information depends on the storage mode
// configuration.
std::string element;
std::istringstream iss;
iss.str(line);
// Get the timestamp for the transaction.
iss >> element;
if (element.empty())
SC_REPORT_FATAL(
"StlPlayer",
("Malformed trace file line " + std::to_string(currentLine) + ".").c_str());
content.delay = playerPeriod * static_cast<double>(std::stoull(element));
// Get the optional burst length and command
iss >> element;
if (element.empty())
SC_REPORT_FATAL(
"StlPlayer",
("Malformed trace file line " + std::to_string(currentLine) + ".").c_str());
if (element.at(0) == '(')
{
element.erase(0, 1);
content.length = std::stoul(element);
iss >> element;
if (element.empty())
SC_REPORT_FATAL(
"StlPlayer",
("Malformed trace file line " + std::to_string(currentLine) + ".").c_str());
}
else
content.length = defaultDataLength;
if (element == "read")
content.command = Request::Command::Read;
else if (element == "write")
content.command = Request::Command::Write;
else
SC_REPORT_FATAL(
"StlPlayer",
("Malformed trace file line " + std::to_string(currentLine) + ".").c_str());
// Get the address.
iss >> element;
if (element.empty())
SC_REPORT_FATAL(
"StlPlayer",
("Malformed trace file line " + std::to_string(currentLine) + ".").c_str());
content.address = std::stoull(element, nullptr, 16);
// Get the data if necessary.
if (storageEnabled && content.command == Request::Command::Write)
{
// The input trace file must provide the data to be stored into the memory.
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 (element.length() != (content.length * 2 + 2))
SC_REPORT_FATAL(
"StlPlayer",
("Malformed trace file line " + std::to_string(currentLine) + ".").c_str());
// Set data
for (unsigned i = 0; i < content.length; i++)
content.data.emplace_back(static_cast<unsigned char>(
std::stoi(element.substr(i * 2 + 2, 2), nullptr, 16)));
}
}
}
std::vector<Request>::const_iterator StlPlayer::swapBuffers()
{
// Wait for parser to finish
if (parserThread.joinable())
parserThread.join();
// Swap buffers
std::swap(readoutBuffer, parseBuffer);
// Start new parser thread
parserThread = std::thread(&StlPlayer::parseTraceFile, this);
return readoutBuffer->cbegin();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Technische Universität Kaiserslautern
* Copyright (c) 2023, Technische Universität Kaiserslautern
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,65 +38,59 @@
* Derek Christ
*/
#ifndef STLPLAYER_H
#define STLPLAYER_H
#pragma once
#include "simulator/TraceSetup.h"
#include "simulator/TrafficInitiator.h"
#include "simulator/request/Request.h"
#include "simulator/request/RequestProducer.h"
#include <sstream>
#include <vector>
#include <array>
#include <thread>
#include <fstream>
#include <systemc>
#include <tlm>
class StlPlayer : public TrafficInitiator
#include <fstream>
#include <memory>
#include <thread>
#include <vector>
class StlPlayer : public RequestProducer
{
public:
StlPlayer(const sc_core::sc_module_name &name,
const Configuration& config,
const std::string &pathToTrace,
const sc_core::sc_time &playerClk,
unsigned int maxPendingReadRequests,
unsigned int maxPendingWriteRequests,
TraceSetup& setup,
bool relative);
~StlPlayer() override;
void sendNextPayload() override;
uint64_t getNumberOfLines() const;
private:
struct LineContent
enum class TraceType
{
sc_core::sc_time sendingTime;
unsigned dataLength;
tlm::tlm_command command;
uint64_t address;
std::vector<unsigned char> data;
Absolute,
Relative,
};
void parseTraceFile();
std::vector<LineContent>::const_iterator swapBuffers();
StlPlayer(std::string_view tracePath,
unsigned int clkMhz,
unsigned int defaultDataLength,
TraceType traceType,
bool storageEnabled);
std::ifstream file;
uint64_t lineCnt = 0;
Request nextRequest() override;
sc_core::sc_time clkPeriod() override { return playerPeriod; }
uint64_t totalRequests() override { return numberOfLines; }
private:
void parseTraceFile();
std::vector<Request>::const_iterator swapBuffers();
static constexpr std::size_t LINE_BUFFER_SIZE = 10000;
const TraceType traceType;
const bool storageEnabled;
const sc_core::sc_time playerPeriod;
const unsigned int defaultDataLength;
std::ifstream traceFile;
uint64_t currentLine = 0;
uint64_t numberOfLines = 0;
const sc_core::sc_time playerClk; // May be different from the memory clock!
std::array<std::shared_ptr<std::vector<Request>>, 2> lineBuffers;
std::shared_ptr<std::vector<Request>> parseBuffer;
std::shared_ptr<std::vector<Request>> readoutBuffer;
static constexpr unsigned lineBufferSize = 10000;
std::vector<LineContent>* currentBuffer;
std::vector<LineContent>* parseBuffer;
std::array<std::vector<LineContent>, 2> lineContents;
std::vector<LineContent>::const_iterator lineIterator;
std::vector<Request>::const_iterator readoutIt;
std::thread parserThread;
const bool relative;
};
#endif // STLPLAYER_H

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Technische Universität Kaiserslautern
* Copyright (c) 2023, Technische Universität Kaiserslautern
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,31 +33,21 @@
* Derek Christ
*/
#include "ConfigUtil.h"
#pragma once
#include "DRAMSys/config/DRAMSysConfiguration.h"
#include <cstdint>
#include <systemc>
#include <fstream>
#include <iostream>
namespace DRAMSys::Config
struct Request
{
json_t get_config_json(const json_t& j, const std::string& configPath, const std::string& objectName)
enum class Command
{
if (j.is_object())
{
return j;
}
else // j should be a string path to the real json file
{
std::string jsonFileName;
j.get_to(jsonFileName);
std::ifstream file(std::string(Configuration::resourceDirectory) + "/" + configPath + "/" + jsonFileName);
json_t j_object = json_t::parse(file);
return j_object.at(objectName);
}
}
} // namespace DRAMSys::Config
Read,
Write,
Stop
} command;
uint64_t address;
std::size_t length;
sc_core::sc_time delay;
std::vector<unsigned char> data;
};

View File

@@ -0,0 +1,156 @@
/*
* Copyright (c) 2023, 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:
* Derek Christ
*/
#include "RequestIssuer.h"
RequestIssuer::RequestIssuer(sc_core::sc_module_name const &name,
MemoryManager &memoryManager,
std::optional<unsigned int> maxPendingReadRequests,
std::optional<unsigned int> maxPendingWriteRequests,
std::function<Request()> nextRequest,
std::function<void()> transactionFinished,
std::function<void()> terminate)
: sc_module(name),
memoryManager(memoryManager),
maxPendingReadRequests(maxPendingReadRequests),
maxPendingWriteRequests(maxPendingWriteRequests),
nextRequest(std::move(nextRequest)),
transactionFinished(std::move(transactionFinished)),
terminate(std::move(terminate)),
payloadEventQueue(this, &RequestIssuer::peqCallback)
{
SC_THREAD(sendNextRequest);
iSocket.register_nb_transport_bw(this, &RequestIssuer::nb_transport_bw);
}
void RequestIssuer::sendNextRequest()
{
Request request = nextRequest();
if (request.command == Request::Command::Stop)
{
finished = true;
return;
}
tlm::tlm_generic_payload &payload = memoryManager.allocate(request.length);
payload.acquire();
payload.set_address(request.address);
payload.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
payload.set_dmi_allowed(false);
payload.set_byte_enable_length(0);
payload.set_data_length(request.length);
payload.set_streaming_width(request.length);
payload.set_command(request.command == Request::Command::Read ? tlm::TLM_READ_COMMAND
: tlm::TLM_WRITE_COMMAND);
tlm::tlm_phase phase = tlm::BEGIN_REQ;
sc_core::sc_time delay = request.delay;
if (request.address == 0x4000f000)
int x = 0;
if (transactionsSent == 0)
delay = sc_core::SC_ZERO_TIME;
iSocket->nb_transport_fw(payload, phase, delay);
transactionInProgress = true;
if (request.command == Request::Command::Read)
pendingReadRequests++;
else if (request.command == Request::Command::Write)
pendingWriteRequests++;
transactionsSent++;
}
bool RequestIssuer::nextRequestSendable() const
{
// If either the maxPendingReadRequests or maxPendingWriteRequests
// limit is reached, do not send next payload.
if (maxPendingReadRequests.has_value() && pendingReadRequests >= maxPendingReadRequests.value())
return false;
if (maxPendingWriteRequests.has_value() &&
pendingWriteRequests >= maxPendingWriteRequests.value())
return false;
return true;
}
void RequestIssuer::peqCallback(tlm::tlm_generic_payload &payload, const tlm::tlm_phase &phase)
{
if (phase == tlm::END_REQ)
{
if (nextRequestSendable())
sendNextRequest();
else
transactionPostponed = true;
}
else if (phase == tlm::BEGIN_RESP)
{
tlm::tlm_phase phase = tlm::END_RESP;
sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
iSocket->nb_transport_fw(payload, phase, delay);
payload.release();
transactionInProgress = false;
transactionFinished();
transactionsReceived++;
if (payload.get_command() == tlm::TLM_READ_COMMAND)
pendingReadRequests--;
else if (payload.get_command() == tlm::TLM_WRITE_COMMAND)
pendingWriteRequests--;
// If the initiator wasn't able to send the next payload in the END_REQ phase, do it
// now.
if (transactionPostponed && nextRequestSendable())
{
sendNextRequest();
transactionPostponed = false;
}
// If all answers were received:
if (finished && transactionsSent == transactionsReceived)
terminate();
}
else
{
SC_REPORT_FATAL("TrafficInitiator", "PEQ was triggered with unknown phase");
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Technische Universität Kaiserslautern
* Copyright (c) 2023, Technische Universität Kaiserslautern
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,70 +30,67 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors:
* Robert Gernhardt
* Matthias Jung
* Éder F. Zulian
* Felipe S. Prado
* Derek Christ
*/
#ifndef TRAFFICINITIATOR_H
#define TRAFFICINITIATOR_H
#pragma once
#include "simulator/TraceSetup.h"
#include "Request.h"
#include "simulator/MemoryManager.h"
#include "DRAMSys/configuration/Configuration.h"
#include "DRAMSys/common/DebugManager.h"
#include <deque>
#include <iostream>
#include <string>
#include <tlm>
#include <systemc>
#include <tlm_utils/simple_initiator_socket.h>
#include <tlm>
#include <tlm_utils/peq_with_cb_and_phase.h>
#include <tlm_utils/simple_initiator_socket.h>
class TrafficInitiator : public sc_core::sc_module
#include <optional>
class RequestIssuer : sc_core::sc_module
{
public:
tlm_utils::simple_initiator_socket<TrafficInitiator> iSocket;
TrafficInitiator(const sc_core::sc_module_name &name, const Configuration& config, TraceSetup& setup,
unsigned int maxPendingReadRequests, unsigned int maxPendingWriteRequests, unsigned int defaultDataLength);
SC_HAS_PROCESS(TrafficInitiator);
virtual void sendNextPayload() = 0;
tlm_utils::simple_initiator_socket<RequestIssuer> iSocket;
protected:
static sc_core::sc_time evaluateGeneratorClk(const DRAMSys::Config::TrafficInitiator &conf);
tlm_utils::peq_with_cb_and_phase<TrafficInitiator> payloadEventQueue;
void terminate();
TraceSetup& setup;
void sendToTarget(tlm::tlm_generic_payload &payload, const tlm::tlm_phase &phase,
const sc_core::sc_time &delay);
uint64_t transactionsReceived = 0;
uint64_t transactionsSent = 0;
unsigned int pendingReadRequests = 0;
unsigned int pendingWriteRequests = 0;
const unsigned int maxPendingReadRequests = 0;
const unsigned int maxPendingWriteRequests = 0;
bool payloadPostponed = false;
bool finished = false;
const unsigned int defaultDataLength;
const bool storageEnabled;
const bool simulationProgressBar;
// 0 disables the max value.
static constexpr unsigned int defaultMaxPendingWriteRequests = 0;
static constexpr unsigned int defaultMaxPendingReadRequests = 0;
RequestIssuer(sc_core::sc_module_name const &name,
MemoryManager &memoryManager,
std::optional<unsigned int> maxPendingReadRequests,
std::optional<unsigned int> maxPendingWriteRequests,
std::function<Request()> nextRequest,
std::function<void()> transactionFinished,
std::function<void()> terminate);
SC_HAS_PROCESS(RequestIssuer);
private:
tlm::tlm_sync_enum nb_transport_bw(tlm::tlm_generic_payload &payload, tlm::tlm_phase &phase,
sc_core::sc_time &bwDelay);
void peqCallback(tlm::tlm_generic_payload &payload, const tlm::tlm_phase &phase);
bool nextPayloadSendable() const;
};
tlm_utils::peq_with_cb_and_phase<RequestIssuer> payloadEventQueue;
MemoryManager &memoryManager;
#endif // TRAFFICINITIATOR_H
bool transactionInProgress = false;
bool transactionPostponed = false;
bool finished = false;
uint64_t transactionsSent = 0;
uint64_t transactionsReceived = 0;
unsigned int pendingReadRequests = 0;
unsigned int pendingWriteRequests = 0;
const std::optional<unsigned int> maxPendingReadRequests;
const std::optional<unsigned int> maxPendingWriteRequests;
unsigned int activeProducers = 0;
std::function<void()> transactionFinished;
std::function<void()> terminate;
std::function<Request()> nextRequest;
void sendNextRequest();
bool nextRequestSendable() const;
tlm::tlm_sync_enum nb_transport_bw(tlm::tlm_generic_payload &payload,
tlm::tlm_phase &phase,
sc_core::sc_time &bwDelay)
{
payloadEventQueue.notify(payload, phase, bwDelay);
return tlm::TLM_ACCEPTED;
}
void peqCallback(tlm::tlm_generic_payload &payload, const tlm::tlm_phase &phase);
};

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2023, 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:
* Derek Christ
*/
#pragma once
#include "Request.h"
class RequestProducer
{
public:
virtual ~RequestProducer() = default;
virtual Request nextRequest() = 0;
virtual uint64_t totalRequests() = 0;
virtual sc_core::sc_time clkPeriod() = 0;
virtual void reset(){};
};

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2023, 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:
* Matthias Jung
* Derek Christ
*/
#include "util.h"
#include <cmath>
#include <iomanip>
#include <iostream>
void loadBar(uint64_t x, uint64_t n, unsigned int w, unsigned int granularity)
{
if ((n < 100) || ((x != n) && (x % (n / 100 * granularity) != 0)))
return;
float ratio = x / (float)n;
unsigned int c = (ratio * w);
float rest = (ratio * w) - c;
std::cout << std::setw(3) << std::round(ratio * 100) << "% |";
for (unsigned int x = 0; x < c; x++)
std::cout << "";
if (rest >= 0 && rest < 0.125f && c != w)
std::cout << " ";
if (rest >= 0.125f && rest < 2 * 0.125f)
std::cout << "";
if (rest >= 2 * 0.125f && rest < 3 * 0.125f)
std::cout << "";
if (rest >= 3 * 0.125f && rest < 4 * 0.125f)
std::cout << "";
if (rest >= 4 * 0.125f && rest < 5 * 0.125f)
std::cout << "";
if (rest >= 5 * 0.125f && rest < 6 * 0.125f)
std::cout << "";
if (rest >= 6 * 0.125f && rest < 7 * 0.125f)
std::cout << "";
if (rest >= 7 * 0.125f && rest < 8 * 0.125f)
std::cout << "";
for (unsigned int x = c; x < (w - 1); x++)
std::cout << " ";
std::cout << "|\r" << std::flush;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Technische Universität Kaiserslautern
* Copyright (c) 2023, Technische Universität Kaiserslautern
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,43 +34,8 @@
* Derek Christ
*/
#ifndef TRACESETUP_H
#define TRACESETUP_H
#pragma once
#include "simulator/MemoryManager.h"
#include <cstdint>
#include "DRAMSys/config/DRAMSysConfiguration.h"
#include "DRAMSys/configuration/Configuration.h"
#include <vector>
#include <string>
#include <memory>
#include <tlm>
class TrafficInitiator;
class TraceSetup
{
public:
TraceSetup(const Configuration& config,
const DRAMSys::Config::TraceSetup &traceSetup,
const std::string &pathToResources,
std::vector<std::unique_ptr<TrafficInitiator>> &devices);
void trafficInitiatorTerminates();
void transactionFinished();
tlm::tlm_generic_payload& allocatePayload(unsigned dataLength);
tlm::tlm_generic_payload& allocatePayload();
private:
unsigned int numberOfTrafficInitiators;
uint64_t totalTransactions = 0;
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);
};
#endif // TRACESETUP_H
void loadBar(uint64_t x, uint64_t n, unsigned int w = 50, unsigned int granularity = 1);

View File

@@ -31,6 +31,7 @@
*
* Authors:
* Thomas Psota
* Derek Christ
*/
@@ -40,11 +41,83 @@
#include "nlohmann/json.hpp"
#include <optional>
#include <string>
#include <variant>
using json_t = nlohmann::json;
namespace DRAMSys::util {
// See https://www.kdab.com/jsonify-with-nlohmann-json/
// Try to set the value of type T into the variant data if it fails, do nothing
template <typename T, typename... Ts>
void variant_from_json(const nlohmann::json &j, std::variant<Ts...> &data)
{
try {
data = j.get<T>();
} catch (...) {
}
}
template <typename T>
void optional_to_json(nlohmann::json &j, std::string_view name, const std::optional<T> &value)
{
if (value)
j[name] = *value;
}
template <class T>
void optional_from_json(const nlohmann::json &j, std::string_view name, std::optional<T> &value)
{
const auto it = j.find(name);
if (it != j.end())
value = it->get<T>();
else
value = std::nullopt;
}
template <typename>
constexpr bool is_optional = false;
template <typename T>
constexpr bool is_optional<std::optional<T>> = true;
template <typename T>
void extended_to_json(const char *key, nlohmann::json &j, const T &value)
{
if constexpr (is_optional<T>)
optional_to_json(j, key, value);
else
j[key] = value;
}
template <typename T>
void extended_from_json(const char *key, const nlohmann::json &j, T &value)
{
if constexpr (is_optional<T>)
optional_from_json(j, key, value);
else
j.at(key).get_to(value);
}
} // namespace DRAMSys::util
NLOHMANN_JSON_NAMESPACE_BEGIN
template <typename... Ts>
struct adl_serializer<std::variant<Ts...>>
{
static void to_json(nlohmann::json &j, const std::variant<Ts...> &data)
{
std::visit([&j](const auto &v) { j = v; }, data);
}
static void from_json(const nlohmann::json &j, std::variant<Ts...> &data)
{
// Call variant_from_json for all types, only one will succeed
(DRAMSys::util::variant_from_json<Ts>(j, data), ...);
}
};
template <typename T>
struct adl_serializer<std::optional<T>> {
static void to_json(json_t& j, const std::optional<T>& opt) {
@@ -66,6 +139,18 @@ struct adl_serializer<std::optional<T>> {
}
};
NLOHMANN_JSON_NAMESPACE_END
#define EXTEND_JSON_TO(v1) DRAMSys::util::extended_to_json(#v1, nlohmann_json_j, nlohmann_json_t.v1);
#define EXTEND_JSON_FROM(v1) DRAMSys::util::extended_from_json(#v1, nlohmann_json_j, nlohmann_json_t.v1);
#define NLOHMANN_JSONIFY_ALL_THINGS(Type, ...) \
inline void to_json(nlohmann::json &nlohmann_json_j, const Type &nlohmann_json_t) { \
NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(EXTEND_JSON_TO, __VA_ARGS__)) \
} \
inline void from_json(const nlohmann::json &nlohmann_json_j, Type &nlohmann_json_t) { \
NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(EXTEND_JSON_FROM, __VA_ARGS__)) \
}
#endif