Merge branch 'develop' into wip/unit_test_preps
# Conflicts: # extensions/standards/DDR5/DRAMSys/controller/checker/CheckerDDR5.cpp
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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, ¤t_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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
19
src/simulator/README.md
Normal 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
197
src/simulator/main.cpp
Normal 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;
|
||||
}
|
||||
639
src/simulator/simulator/Cache.cpp
Normal file
639
src/simulator/simulator/Cache.cpp
Normal 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 ¤tLine = *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 ¤tLine = *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;
|
||||
}
|
||||
216
src/simulator/simulator/Cache.h
Normal file
216
src/simulator/simulator/Cache.h
Normal 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;
|
||||
};
|
||||
313
src/simulator/simulator/EccModule.cpp
Normal file
313
src/simulator/simulator/EccModule.cpp
Normal 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();
|
||||
}
|
||||
107
src/simulator/simulator/EccModule.h
Normal file
107
src/simulator/simulator/EccModule.h
Normal 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
|
||||
47
src/simulator/simulator/Initiator.h
Normal file
47
src/simulator/simulator/Initiator.h
Normal 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;
|
||||
};
|
||||
70
src/simulator/simulator/SimpleInitiator.h
Normal file
70
src/simulator/simulator/SimpleInitiator.h
Normal 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;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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(¬ifier->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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
85
src/simulator/simulator/generator/RandomProducer.cpp
Normal file
85
src/simulator/simulator/generator/RandomProducer.cpp
Normal 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;
|
||||
}
|
||||
71
src/simulator/simulator/generator/RandomProducer.h
Normal file
71
src/simulator/simulator/generator/RandomProducer.h
Normal 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;
|
||||
};
|
||||
82
src/simulator/simulator/generator/SequentialProducer.cpp
Normal file
82
src/simulator/simulator/generator/SequentialProducer.cpp
Normal 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;
|
||||
}
|
||||
75
src/simulator/simulator/generator/SequentialProducer.h
Normal file
75
src/simulator/simulator/generator/SequentialProducer.h
Normal 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;
|
||||
};
|
||||
246
src/simulator/simulator/generator/TrafficGenerator.cpp
Normal file
246
src/simulator/simulator/generator/TrafficGenerator.cpp
Normal 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;
|
||||
}
|
||||
82
src/simulator/simulator/generator/TrafficGenerator.h
Normal file
82
src/simulator/simulator/generator/TrafficGenerator.h
Normal 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;
|
||||
};
|
||||
41
src/simulator/simulator/generator/definitions.h
Normal file
41
src/simulator/simulator/generator/definitions.h
Normal 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;
|
||||
@@ -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
|
||||
61
src/simulator/simulator/hammer/RowHammer.h
Normal file
61
src/simulator/simulator/hammer/RowHammer.h
Normal 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;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
226
src/simulator/simulator/player/StlPlayer.cpp
Normal file
226
src/simulator/simulator/player/StlPlayer.cpp
Normal 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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
};
|
||||
156
src/simulator/simulator/request/RequestIssuer.cpp
Normal file
156
src/simulator/simulator/request/RequestIssuer.cpp
Normal 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");
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
49
src/simulator/simulator/request/RequestProducer.h
Normal file
49
src/simulator/simulator/request/RequestProducer.h
Normal 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(){};
|
||||
};
|
||||
75
src/simulator/simulator/util.cpp
Normal file
75
src/simulator/simulator/util.cpp
Normal 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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user