Merge branch 'work/addressdecoder' into 'develop'

Add support for arbitrary XOR address manipulation

See merge request ems/astdm/modeling.dram/dram.sys.5!60
This commit is contained in:
Lukas Steiner
2024-02-23 08:33:59 +00:00
17 changed files with 665 additions and 174 deletions

View File

@@ -43,28 +43,21 @@
namespace DRAMSys::Config
{
struct XorPair
{
unsigned int FIRST;
unsigned int SECOND;
};
NLOHMANN_JSONIFY_ALL_THINGS(XorPair, FIRST, SECOND)
struct AddressMapping
{
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;
using BitEntry = std::variant<unsigned int, std::vector<unsigned int>>;
std::optional<std::vector<BitEntry>> BYTE_BIT;
std::optional<std::vector<BitEntry>> COLUMN_BIT;
std::optional<std::vector<BitEntry>> ROW_BIT;
std::optional<std::vector<BitEntry>> BANK_BIT;
std::optional<std::vector<BitEntry>> BANKGROUP_BIT;
std::optional<std::vector<BitEntry>> RANK_BIT;
std::optional<std::vector<BitEntry>> PSEUDOCHANNEL_BIT;
std::optional<std::vector<BitEntry>> CHANNEL_BIT;
};
NLOHMANN_JSONIFY_ALL_THINGS(AddressMapping,
@@ -75,8 +68,7 @@ NLOHMANN_JSONIFY_ALL_THINGS(AddressMapping,
BANKGROUP_BIT,
RANK_BIT,
PSEUDOCHANNEL_BIT,
CHANNEL_BIT,
XOR)
CHANNEL_BIT)
} // namespace DRAMSys::Config

View File

@@ -47,57 +47,71 @@
namespace DRAMSys
{
AddressDecoder::AddressDecoder(const DRAMSys::Config::AddressMapping& addressMapping,
const MemSpec& memSpec)
static void addMapping(std::vector<Config::AddressMapping::BitEntry> const& mappingVector,
std::vector<unsigned>& bitVector,
std::vector<std::vector<unsigned>>& xorVector)
{
for (const auto& bitEntry : mappingVector)
{
std::visit(
[&bitVector, &xorVector](auto&& arg)
{
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, unsigned>)
{
bitVector.push_back(arg);
}
else if constexpr (std::is_same_v<T, std::vector<unsigned>>)
{
bitVector.push_back(arg.at(0));
xorVector.push_back(arg);
}
},
bitEntry);
}
}
AddressDecoder::AddressDecoder(const DRAMSys::Config::AddressMapping& addressMapping)
{
if (const auto& channelBits = addressMapping.CHANNEL_BIT)
{
std::copy(channelBits->begin(), channelBits->end(), std::back_inserter(vChannelBits));
addMapping(*channelBits, vChannelBits, vXor);
}
if (const auto& rankBits = addressMapping.RANK_BIT)
{
std::copy(rankBits->begin(), rankBits->end(), std::back_inserter(vRankBits));
addMapping(*rankBits, vRankBits, vXor);
}
// HBM pseudo channels are internally modelled as ranks
if (const auto& pseudoChannelBits = addressMapping.PSEUDOCHANNEL_BIT)
{
std::copy(
pseudoChannelBits->begin(), pseudoChannelBits->end(), std::back_inserter(vRankBits));
addMapping(*pseudoChannelBits, vRankBits, vXor);
}
if (const auto& bankGroupBits = addressMapping.BANKGROUP_BIT)
{
std::copy(bankGroupBits->begin(), bankGroupBits->end(), std::back_inserter(vBankGroupBits));
addMapping(*bankGroupBits, vBankGroupBits, vXor);
}
if (const auto& byteBits = addressMapping.BYTE_BIT)
{
std::copy(byteBits->begin(), byteBits->end(), std::back_inserter(vByteBits));
}
if (const auto& xorBits = addressMapping.XOR)
{
for (const auto& xorBit : *xorBits)
{
vXor.emplace_back(xorBit.FIRST, xorBit.SECOND);
}
addMapping(*byteBits, vByteBits, vXor);
}
if (const auto& bankBits = addressMapping.BANK_BIT)
{
std::copy(bankBits->begin(), bankBits->end(), std::back_inserter(vBankBits));
addMapping(*bankBits, vBankBits, vXor);
}
if (const auto& rowBits = addressMapping.ROW_BIT)
{
std::copy(rowBits->begin(), rowBits->end(), std::back_inserter(vRowBits));
addMapping(*rowBits, vRowBits, vXor);
}
if (const auto& columnBits = addressMapping.COLUMN_BIT)
{
std::copy(columnBits->begin(), columnBits->end(), std::back_inserter(vColumnBits));
addMapping(*columnBits, vColumnBits, vXor);
}
unsigned channels = std::lround(std::pow(2.0, vChannelBits.size()));
@@ -108,6 +122,23 @@ AddressDecoder::AddressDecoder(const DRAMSys::Config::AddressMapping& addressMap
unsigned columns = std::lround(std::pow(2.0, vColumnBits.size()));
unsigned bytes = std::lround(std::pow(2.0, vByteBits.size()));
maximumAddress =
static_cast<uint64_t>(bytes) * columns * rows * banks * bankGroups * ranks * channels - 1;
bankgroupsPerRank = bankGroups;
banksPerGroup = banks;
}
void AddressDecoder::plausibilityCheck(const MemSpec& memSpec)
{
unsigned channels = std::lround(std::pow(2.0, vChannelBits.size()));
unsigned ranks = std::lround(std::pow(2.0, vRankBits.size()));
unsigned bankGroups = std::lround(std::pow(2.0, vBankGroupBits.size()));
unsigned banks = std::lround(std::pow(2.0, vBankBits.size()));
unsigned rows = std::lround(std::pow(2.0, vRowBits.size()));
unsigned columns = std::lround(std::pow(2.0, vColumnBits.size()));
unsigned bytes = std::lround(std::pow(2.0, vByteBits.size()));
maximumAddress =
static_cast<uint64_t>(bytes) * columns * rows * banks * bankGroups * ranks * channels - 1;
@@ -131,7 +162,8 @@ AddressDecoder::AddressDecoder(const DRAMSys::Config::AddressMapping& addressMap
{
highestByteBit = static_cast<int>(*std::max_element(vByteBits.begin(), vByteBits.end()));
for (unsigned bitPosition = 0; bitPosition <= static_cast<unsigned>(highestByteBit); bitPosition++)
for (unsigned bitPosition = 0; bitPosition <= static_cast<unsigned>(highestByteBit);
bitPosition++)
{
if (std::find(vByteBits.begin(), vByteBits.end(), bitPosition) == vByteBits.end())
SC_REPORT_FATAL("AddressDecoder", "Byte bits are not continuous starting from 0");
@@ -148,16 +180,13 @@ AddressDecoder::AddressDecoder(const DRAMSys::Config::AddressMapping& addressMap
SC_REPORT_FATAL("AddressDecoder", "No continuous column bits for maximum burst length");
}
bankgroupsPerRank = bankGroups;
bankGroups = bankgroupsPerRank * ranks;
banksPerGroup = banks;
banks = banksPerGroup * bankGroups;
unsigned absoluteBankGroups = bankgroupsPerRank * ranks;
unsigned absoluteBanks = banksPerGroup * absoluteBankGroups;
if (memSpec.numberOfChannels != channels || memSpec.ranksPerChannel != ranks ||
memSpec.bankGroupsPerChannel != bankGroups || memSpec.banksPerChannel != banks ||
memSpec.rowsPerBank != rows || memSpec.columnsPerRow != columns ||
memSpec.devicesPerRank * memSpec.bitWidth != bytes * 8)
memSpec.bankGroupsPerChannel != absoluteBankGroups ||
memSpec.banksPerChannel != absoluteBanks || memSpec.rowsPerBank != rows ||
memSpec.columnsPerRow != columns || memSpec.devicesPerRank * memSpec.bitWidth != bytes * 8)
SC_REPORT_FATAL("AddressDecoder", "Memspec and address mapping do not match");
}
@@ -174,12 +203,16 @@ DecodedAddress AddressDecoder::decodeAddress(uint64_t encAddr) const
// For each used xor:
// Get the first bit and second bit. Apply a bitwise xor operator and save it back to the
// first bit.
auto tempAddr = encAddr;
for (const auto& it : vXor)
{
uint64_t xoredBit =
(((encAddr >> it.first) & UINT64_C(1)) ^ ((encAddr >> it.second) & UINT64_C(1)));
encAddr &= ~(UINT64_C(1) << it.first);
encAddr |= xoredBit << it.first;
uint64_t xoredBit = std::accumulate(it.cbegin(),
it.cend(),
0,
[tempAddr](uint64_t acc, unsigned xorBit)
{ return acc ^= (tempAddr >> xorBit) & UINT64_C(1); });
encAddr &= ~(UINT64_C(1) << it[0]);
encAddr |= xoredBit << it[0];
}
DecodedAddress decAddr;
@@ -224,12 +257,16 @@ unsigned AddressDecoder::decodeChannel(uint64_t encAddr) const
// For each used xor:
// Get the first bit and second bit. Apply a bitwise xor operator and save it back to the
// first bit.
auto tempAddr = encAddr;
for (const auto& it : vXor)
{
uint64_t xoredBit =
(((encAddr >> it.first) & UINT64_C(1)) ^ ((encAddr >> it.second) & UINT64_C(1)));
encAddr &= ~(UINT64_C(1) << it.first);
encAddr |= xoredBit << it.first;
uint64_t xoredBit = std::accumulate(it.cbegin(),
it.cend(),
0,
[tempAddr](uint64_t acc, unsigned xorBit)
{ return acc ^= (tempAddr >> xorBit) & UINT64_C(1); });
encAddr &= ~(UINT64_C(1) << it[0]);
encAddr |= xoredBit << it[0];
}
unsigned channel = 0;
@@ -284,10 +321,13 @@ void AddressDecoder::print() const
{
uint64_t addressBits =
(UINT64_C(1) << vChannelBits[static_cast<std::vector<unsigned>::size_type>(it)]);
for (auto it2 : vXor)
for (auto xorMapping : vXor)
{
if (it2.first == vChannelBits[static_cast<std::vector<unsigned>::size_type>(it)])
addressBits |= (UINT64_C(1) << it2.second);
if (xorMapping.at(0) == vChannelBits[static_cast<std::vector<unsigned>::size_type>(it)])
{
for (auto it = xorMapping.cbegin() + 1; it != xorMapping.cend(); it++)
addressBits |= (UINT64_C(1) << *it);
}
}
std::cout << " Ch " << std::setw(2) << it << ": " << std::bitset<64>(addressBits)
<< std::endl;
@@ -297,10 +337,13 @@ void AddressDecoder::print() const
{
uint64_t addressBits =
(UINT64_C(1) << vRankBits[static_cast<std::vector<unsigned>::size_type>(it)]);
for (auto it2 : vXor)
for (auto xorMapping : vXor)
{
if (it2.first == vRankBits[static_cast<std::vector<unsigned>::size_type>(it)])
addressBits |= (UINT64_C(1) << it2.second);
if (xorMapping.at(0) == vRankBits[static_cast<std::vector<unsigned>::size_type>(it)])
{
for (auto it = xorMapping.cbegin() + 1; it != xorMapping.cend(); it++)
addressBits |= (UINT64_C(1) << *it);
}
}
std::cout << " Ra " << std::setw(2) << it << ": " << std::bitset<64>(addressBits)
<< std::endl;
@@ -310,10 +353,14 @@ void AddressDecoder::print() const
{
uint64_t addressBits =
(UINT64_C(1) << vBankGroupBits[static_cast<std::vector<unsigned>::size_type>(it)]);
for (auto it2 : vXor)
for (auto xorMapping : vXor)
{
if (it2.first == vBankGroupBits[static_cast<std::vector<unsigned>::size_type>(it)])
addressBits |= (UINT64_C(1) << it2.second);
if (xorMapping.at(0) ==
vBankGroupBits[static_cast<std::vector<unsigned>::size_type>(it)])
{
for (auto it = xorMapping.cbegin() + 1; it != xorMapping.cend(); it++)
addressBits |= (UINT64_C(1) << *it);
}
}
std::cout << " Bg " << std::setw(2) << it << ": " << std::bitset<64>(addressBits)
<< std::endl;
@@ -323,10 +370,13 @@ void AddressDecoder::print() const
{
uint64_t addressBits =
(UINT64_C(1) << vBankBits[static_cast<std::vector<unsigned>::size_type>(it)]);
for (auto it2 : vXor)
for (auto xorMapping : vXor)
{
if (it2.first == vBankBits[static_cast<std::vector<unsigned>::size_type>(it)])
addressBits |= (UINT64_C(1) << it2.second);
if (xorMapping.at(0) == vBankBits[static_cast<std::vector<unsigned>::size_type>(it)])
{
for (auto it = xorMapping.cbegin() + 1; it != xorMapping.cend(); it++)
addressBits |= (UINT64_C(1) << *it);
}
}
std::cout << " Ba " << std::setw(2) << it << ": " << std::bitset<64>(addressBits)
<< std::endl;
@@ -336,10 +386,13 @@ void AddressDecoder::print() const
{
uint64_t addressBits =
(UINT64_C(1) << vRowBits[static_cast<std::vector<unsigned>::size_type>(it)]);
for (auto it2 : vXor)
for (auto xorMapping : vXor)
{
if (it2.first == vRowBits[static_cast<std::vector<unsigned>::size_type>(it)])
addressBits |= (UINT64_C(1) << it2.second);
if (xorMapping.at(0) == vRowBits[static_cast<std::vector<unsigned>::size_type>(it)])
{
for (auto it = xorMapping.cbegin() + 1; it != xorMapping.cend(); it++)
addressBits |= (UINT64_C(1) << *it);
}
}
std::cout << " Ro " << std::setw(2) << it << ": " << std::bitset<64>(addressBits)
<< std::endl;
@@ -349,10 +402,13 @@ void AddressDecoder::print() const
{
uint64_t addressBits =
(UINT64_C(1) << vColumnBits[static_cast<std::vector<unsigned>::size_type>(it)]);
for (auto it2 : vXor)
for (auto xorMapping : vXor)
{
if (it2.first == vColumnBits[static_cast<std::vector<unsigned>::size_type>(it)])
addressBits |= (UINT64_C(1) << it2.second);
if (xorMapping.at(0) == vColumnBits[static_cast<std::vector<unsigned>::size_type>(it)])
{
for (auto it = xorMapping.cbegin() + 1; it != xorMapping.cend(); it++)
addressBits |= (UINT64_C(1) << *it);
}
}
std::cout << " Co " << std::setw(2) << it << ": " << std::bitset<64>(addressBits)
<< std::endl;
@@ -362,10 +418,13 @@ void AddressDecoder::print() const
{
uint64_t addressBits =
(UINT64_C(1) << vByteBits[static_cast<std::vector<unsigned>::size_type>(it)]);
for (auto it2 : vXor)
for (auto xorMapping : vXor)
{
if (it2.first == vByteBits[static_cast<std::vector<unsigned>::size_type>(it)])
addressBits |= (UINT64_C(1) << it2.second);
if (xorMapping.at(0) == vByteBits[static_cast<std::vector<unsigned>::size_type>(it)])
{
for (auto it = xorMapping.cbegin() + 1; it != xorMapping.cend(); it++)
addressBits |= (UINT64_C(1) << *it);
}
}
std::cout << " By " << std::setw(2) << it << ": " << std::bitset<64>(addressBits)
<< std::endl;

View File

@@ -81,11 +81,15 @@ struct DecodedAddress
class AddressDecoder
{
public:
AddressDecoder(const DRAMSys::Config::AddressMapping& addressMapping, const MemSpec& memSpec);
AddressDecoder(const DRAMSys::Config::AddressMapping& addressMapping);
[[nodiscard]] DecodedAddress decodeAddress(uint64_t encAddr) const;
[[nodiscard]] unsigned decodeChannel(uint64_t encAddr) const;
[[nodiscard]] uint64_t encodeAddress(DecodedAddress decodedAddress) const;
[[nodiscard]] uint64_t maxAddress() const { return maximumAddress; }
void print() const;
void plausibilityCheck(const MemSpec &memSpec);
private:
unsigned banksPerGroup;
@@ -95,7 +99,7 @@ private:
// This container stores for each used xor gate a pair of address bits, the first bit is
// overwritten with the result
std::vector<std::pair<unsigned, unsigned>> vXor;
std::vector<std::vector<unsigned>> vXor;
std::vector<unsigned> vChannelBits;
std::vector<unsigned> vRankBits;
std::vector<unsigned> vBankGroupBits;

View File

@@ -151,7 +151,8 @@ void DRAMSys::setupDebugManager([[maybe_unused]] const std::string& traceName) c
void DRAMSys::instantiateModules(const ::DRAMSys::Config::AddressMapping& addressMapping)
{
addressDecoder = std::make_unique<AddressDecoder>(addressMapping, *config.memSpec);
addressDecoder = std::make_unique<AddressDecoder>(addressMapping);
addressDecoder->plausibilityCheck(*config.memSpec);
addressDecoder->print();
// Create arbiter

View File

@@ -106,7 +106,8 @@ void DRAMSysRecordable::setupTlmRecorders(const std::string& traceName,
void DRAMSysRecordable::instantiateModules(const std::string& traceName,
const ::DRAMSys::Config::Configuration& configLib)
{
addressDecoder = std::make_unique<AddressDecoder>(configLib.addressmapping, *config.memSpec);
addressDecoder = std::make_unique<AddressDecoder>(configLib.addressmapping);
addressDecoder->plausibilityCheck(*config.memSpec);
addressDecoder->print();
// Create and properly initialize TLM recorders.

View File

@@ -55,6 +55,8 @@ target_link_libraries(${PROJECT_NAME}
DRAMSys::libdramsys
)
add_library(DRAMSys::simulator ALIAS ${PROJECT_NAME})
add_executable(DRAMSys
main.cpp
)