Merge branch 'feat/addr_dec_matrix' into 'develop'

Feature: Rewrote AddressDecoder

See merge request ems/astdm/modeling.dram/dram.sys.5!131
This commit is contained in:
Lukas Steiner
2025-09-22 12:00:50 +00:00
11 changed files with 1708 additions and 455 deletions

View File

@@ -52,11 +52,12 @@ static DRAMSys::AddressDecoder addressDecoder()
static void addressdecoder_decode(benchmark::State& state) static void addressdecoder_decode(benchmark::State& state)
{ {
auto decoder = addressDecoder(); auto decoder = addressDecoder();
tlm::tlm_generic_payload trans;
trans.set_address(0x0);
for (auto _ : state) for (auto _ : state)
{ {
// Actual address has no significant impact on performance // Actual address has no significant impact on performance
auto decodedAddress = decoder.decodeAddress(0x0); auto decodedAddress = decoder.decodeAddress(trans);
benchmark::DoNotOptimize(decodedAddress); benchmark::DoNotOptimize(decodedAddress);
} }
} }

View File

@@ -59,6 +59,37 @@ struct AddressMapping
std::optional<std::vector<BitEntry>> STACK_BIT; std::optional<std::vector<BitEntry>> STACK_BIT;
std::optional<std::vector<BitEntry>> PSEUDOCHANNEL_BIT; std::optional<std::vector<BitEntry>> PSEUDOCHANNEL_BIT;
std::optional<std::vector<BitEntry>> CHANNEL_BIT; std::optional<std::vector<BitEntry>> CHANNEL_BIT;
unsigned int getHighestBit() const {
unsigned int highestBit = std::numeric_limits<unsigned int>::min();
bool found = false;
auto checkAndUpdate = [&](const std::optional<std::vector<BitEntry>>& bits) {
if (bits) {
for (const auto& vector : *bits) {
for (const auto& bit : vector) {
if (bit > highestBit) {
highestBit = bit;
found = true;
}
}
}
}
};
checkAndUpdate(BYTE_BIT);
checkAndUpdate(COLUMN_BIT);
checkAndUpdate(ROW_BIT);
checkAndUpdate(BANK_BIT);
checkAndUpdate(BANKGROUP_BIT);
checkAndUpdate(RANK_BIT);
checkAndUpdate(STACK_BIT);
checkAndUpdate(PSEUDOCHANNEL_BIT);
checkAndUpdate(CHANNEL_BIT);
return found ? highestBit : std::numeric_limits<unsigned int>::min(); // Rückgabe des höchsten Wertes oder des minimalen Wertes
}
}; };
NLOHMANN_JSONIFY_ALL_THINGS(AddressMapping, NLOHMANN_JSONIFY_ALL_THINGS(AddressMapping,

View File

@@ -36,6 +36,14 @@
### DRAMSys::libdramsys ### ### DRAMSys::libdramsys ###
######################################## ########################################
# Add AVX-512 flag
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
message("Enabling GFNI support")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
elseif(MSVC)
# Für MSVC können Sie entsprechende Optionen hinzufügen, falls erforderlich
endif()
add_library(libdramsys add_library(libdramsys
DRAMSys/common/DebugManager.cpp DRAMSys/common/DebugManager.cpp
DRAMSys/common/TlmRecorder.cpp DRAMSys/common/TlmRecorder.cpp

View File

@@ -598,8 +598,8 @@ void Controller::manageRequests(const sc_time& delay)
transToAcquire.payload->acquire(); transToAcquire.payload->acquire();
// The following logic assumes that transactions are naturally aligned // The following logic assumes that transactions are naturally aligned
uint64_t address = transToAcquire.payload->get_address(); const uint64_t address = transToAcquire.payload->get_address();
[[maybe_unused]] uint64_t dataLength = transToAcquire.payload->get_data_length(); const uint64_t dataLength = transToAcquire.payload->get_data_length();
assert((dataLength & (dataLength - 1)) == 0); // Data length must be a power of 2 assert((dataLength & (dataLength - 1)) == 0); // Data length must be a power of 2
assert(address % dataLength == 0); // Check if naturally aligned assert(address % dataLength == 0); // Check if naturally aligned
@@ -608,7 +608,7 @@ void Controller::manageRequests(const sc_time& delay)
{ {
// continuous block of data that can be fetched with a single burst // continuous block of data that can be fetched with a single burst
DecodedAddress decodedAddress = DecodedAddress decodedAddress =
addressDecoder.decodeAddress(transToAcquire.payload->get_address()); addressDecoder.decodeAddress(*transToAcquire.payload);
ControllerExtension::setAutoExtension( ControllerExtension::setAutoExtension(
*transToAcquire.payload, *transToAcquire.payload,
nextChannelPayloadIDToAppend++, nextChannelPayloadIDToAppend++,
@@ -807,7 +807,7 @@ void Controller::createChildTranses(tlm::tlm_generic_payload& parentTrans)
for (auto* childTrans : childTranses) for (auto* childTrans : childTranses)
{ {
DecodedAddress decodedAddress = addressDecoder.decodeAddress(childTrans->get_address()); DecodedAddress decodedAddress = addressDecoder.decodeAddress(*childTrans);
ControllerExtension::setAutoExtension(*childTrans, ControllerExtension::setAutoExtension(*childTrans,
nextChannelPayloadIDToAppend, nextChannelPayloadIDToAppend,
Rank(decodedAddress.rank), Rank(decodedAddress.rank),
@@ -816,8 +816,7 @@ void Controller::createChildTranses(tlm::tlm_generic_payload& parentTrans)
Bank(decodedAddress.bank), Bank(decodedAddress.bank),
Row(decodedAddress.row), Row(decodedAddress.row),
Column(decodedAddress.column), Column(decodedAddress.column),
(childTrans->get_data_length() * 8) / memSpec.maxBurstLength);
memSpec.dataBusWidth);
} }
nextChannelPayloadIDToAppend++; nextChannelPayloadIDToAppend++;
ParentExtension::setExtension(parentTrans, std::move(childTranses)); ParentExtension::setExtension(parentTrans, std::move(childTranses));

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, RPTU Kaiserslautern-Landau * Copyright (c) 2025, RPTU Kaiserslautern-Landau
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -34,288 +34,416 @@
* Lukas Steiner * Lukas Steiner
* Luiza Correa * Luiza Correa
* Derek Christ * Derek Christ
* Thomas Zimmermann
*/ */
#include "AddressDecoder.h" #include "AddressDecoder.h"
#include "DRAMSys/config/AddressMapping.h" #include "DRAMSys/config/AddressMapping.h"
#include <bit>
#include <bitset> #include <bitset>
#include <cmath> #include <cmath>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <cstdint>
#include <immintrin.h>
#include <set>
namespace DRAMSys namespace DRAMSys
{ {
/********************/
/* Helper Functions */
/********************/
/**
* @brief Creates a bitmask and stores it in a uint64_t.
*
* @param numBits The number of bits to set to 1.
* @param startIndex The index of the first bit to set to 1.
* @return result The uint64_t where the bitmask will be stored.
*/
uint64_t createBitmask(unsigned numBits, unsigned startIndex) {
// Create the mask by shifting 1's to the correct position
return ((UINT64_C(1) << numBits) - 1) << startIndex;
}
static void addMapping(std::vector<Config::AddressMapping::BitEntry> const& mappingVector, std::vector<std::bitset<64>> AddressDecoder::transposeMatrix(const std::vector<std::bitset<64>>& matrix) {
std::vector<unsigned>& bitVector, size_t size = matrix.size();
std::vector<std::vector<unsigned>>& xorVector) std::vector<std::bitset<64>> transposedMatrix(size);
{
for (const Config::AddressMapping::BitEntry& bitEntry : mappingVector) for (size_t i = 0; i < size; ++i) {
{ for (size_t j = 0; j < 64; ++j) {
if (bitEntry.get_type() == Config::AddressMapping::BitEntry::Type::SINGLE) { if (matrix[i].test(j))
bitVector.push_back(bitEntry.at(0)); transposedMatrix[j].set(i);
} else {
bitVector.push_back(bitEntry.at(0));
xorVector.push_back(bitEntry);
} }
} }
return transposedMatrix;
} }
AddressDecoder::AddressDecoder(const Config::AddressMapping& addressMapping) uint64_t AddressDecoder::gf2Multiplication(const uint64_t& inputVec, const std::vector<std::bitset<64>>& matrix) const
{ {
if (const auto& channelBits = addressMapping.CHANNEL_BIT) #if defined(__clang__) || defined(__GNUC__)
{ uint64_t result = 0;
addMapping(*channelBits, vChannelBits, vXor); for (size_t i = 0; i < matrix.size(); ++i) {
} uint64_t row = matrix[i].to_ullong();
uint64_t val = inputVec & row;
bool parity = __builtin_parityll(val);
result |= (uint64_t(parity) << i);
}
return result;
#else
std::bitset<64> resultBits;
std::bitset<64> inputBits(inputVec);
if (const auto& rankBits = addressMapping.RANK_BIT) for (size_t i = 0; i < matrix.size(); ++i) {
{ resultBits[i] = (inputBits & matrix[i]).count() % 2;
addMapping(*rankBits, vRankBits, vXor); }
} return resultBits.to_ullong();
#endif
if (const auto& stackBits = addressMapping.STACK_BIT) // Print input, mapping matrix and output in a readable way (useful for debugging)
{ // std::cout << "Vec " << ":\t" << std::bitset<64>(vector[0]) << std::endl << std::endl;
addMapping(*stackBits, vStackBits, vXor); // for (size_t i = 0; i < mappingMatrix.size(); ++i) {
} // std::cout << "Row " << i << ":\t" << mappingMatrix[i] << " | " << resultBits[i] << std::endl;
// }
// HBM pseudo channels are internally modelled as ranks
if (const auto& pseudoChannelBits = addressMapping.PSEUDOCHANNEL_BIT)
{
addMapping(*pseudoChannelBits, vRankBits, vXor);
}
if (const auto& bankGroupBits = addressMapping.BANKGROUP_BIT)
{
addMapping(*bankGroupBits, vBankGroupBits, vXor);
}
if (const auto& byteBits = addressMapping.BYTE_BIT)
{
addMapping(*byteBits, vByteBits, vXor);
}
if (const auto& bankBits = addressMapping.BANK_BIT)
{
addMapping(*bankBits, vBankBits, vXor);
}
if (const auto& rowBits = addressMapping.ROW_BIT)
{
addMapping(*rowBits, vRowBits, vXor);
}
if (const auto& columnBits = addressMapping.COLUMN_BIT)
{
addMapping(*columnBits, vColumnBits, vXor);
}
unsigned channels = std::lround(std::pow(2.0, vChannelBits.size()));
unsigned ranks = std::lround(std::pow(2.0, vRankBits.size()));
unsigned stacks = std::lround(std::pow(2.0, vStackBits.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 * stacks *
ranks * channels -
1;
bankgroupsPerRank = bankGroups;
banksPerGroup = banks;
} }
/****************************/
/* AddressDecoder Functions */
/****************************/
AddressDecoder::AddressDecoder(const DRAMSys::Config::AddressMapping& addressMapping) :
highestBitValue(addressMapping.getHighestBit())
{
mappingMatrix = std::vector<std::bitset<64>>(highestBitValue + 1);
upperBoundAddress = std::pow(2, highestBitValue + 1) - 1;
auto addBitsToMatrix = [&](const std::optional<std::vector<Config::AddressMapping::BitEntry>> bits, int *rowIndex, std::string_view name)
{
if (!bits.has_value())
return AddressComponent(-1, 0, name);
for (auto row : bits.value()) {
for (unsigned int bit : row) {
mappingMatrix[*rowIndex][bit] = true;
}
(*rowIndex)++;
}
// Care: The rowIndex has been changed. We want the lowest bit, so we must subtract the length!
return AddressComponent(*rowIndex - bits.value().size(), bits.value().size(), name);
};
int rowIndex = 0;
byteBits = addBitsToMatrix(addressMapping.BYTE_BIT, &rowIndex, "By");
columnBits = addBitsToMatrix(addressMapping.COLUMN_BIT, &rowIndex, "Co");
bankGroupBits = addBitsToMatrix(addressMapping.BANKGROUP_BIT, &rowIndex, "BG");
bankBits = addBitsToMatrix(addressMapping.BANK_BIT, &rowIndex, "Ba");
rowBits = addBitsToMatrix(addressMapping.ROW_BIT, &rowIndex, "Ro");
pseudochannelBits = addBitsToMatrix(addressMapping.PSEUDOCHANNEL_BIT, &rowIndex, "PC");
channelBits = addBitsToMatrix(addressMapping.CHANNEL_BIT, &rowIndex, "Ch");
rankBits = addBitsToMatrix(addressMapping.RANK_BIT, &rowIndex, "Ra");
stackBits = addBitsToMatrix(addressMapping.STACK_BIT, &rowIndex, "St");
transposedMappingMatrix = transposeMatrix(mappingMatrix);
bankgroupsPerRank = std::lround(std::pow(2.0, bankGroupBits.length));
banksPerGroup = std::lround(std::pow(2.0, bankBits.length));
}
void AddressDecoder::plausibilityCheck(const MemSpec& memSpec) void AddressDecoder::plausibilityCheck(const MemSpec& memSpec)
{ {
unsigned channels = std::lround(std::pow(2.0, vChannelBits.size())); (*this).memSpec = &memSpec;
unsigned ranks = std::lround(std::pow(2.0, vRankBits.size())); np2Flag = not allComponentsArePowerOfTwo(memSpec);
unsigned stacks = std::lround(std::pow(2.0, vStackBits.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 * stacks * // Check if all address bits are used
ranks * channels - // TODO: Check if every bit occurs ~exactly~ once or just at least once?
1; std::bitset<64> orBitset(0);
for (auto bitset: mappingMatrix) {
orBitset |= bitset;
}
auto totalAddressBits = static_cast<unsigned>(std::log2(maximumAddress)); std::bitset<64> mask((1ULL << (highestBitValue + 1)) - 1);
for (unsigned bitPosition = 0; bitPosition < totalAddressBits; bitPosition++) if (orBitset != mask) {
{ SC_REPORT_FATAL("AddressDecoder", "Not all address bits are used");
if (std::count(vChannelBits.begin(), vChannelBits.end(), bitPosition) +
std::count(vRankBits.begin(), vRankBits.end(), bitPosition) +
std::count(vStackBits.begin(), vStackBits.end(), bitPosition) +
std::count(vBankGroupBits.begin(), vBankGroupBits.end(), bitPosition) +
std::count(vBankBits.begin(), vBankBits.end(), bitPosition) +
std::count(vRowBits.begin(), vRowBits.end(), bitPosition) +
std::count(vColumnBits.begin(), vColumnBits.end(), bitPosition) +
std::count(vByteBits.begin(), vByteBits.end(), bitPosition) !=
1)
SC_REPORT_FATAL("AddressDecoder", "Not all address bits occur exactly once");
} }
int highestByteBit = -1; // Check if the byte bits are continous and starting from 0
uint64_t row = 0;
if (!vByteBits.empty()) for (size_t i = 0; i < byteBits.length; i++) {
{ row |= mappingMatrix[byteBits.idx + i].to_ullong();
highestByteBit = static_cast<int>(*std::max_element(vByteBits.begin(), vByteBits.end())); }
if (row != ((1ULL << byteBits.length) - 1)) {
for (unsigned bitPosition = 0; bitPosition <= static_cast<unsigned>(highestByteBit); SC_REPORT_FATAL("AddressDecoder", "Not all address bits occur exactly once");
bitPosition++)
{
if (std::find(vByteBits.begin(), vByteBits.end(), bitPosition) == vByteBits.end())
SC_REPORT_FATAL("AddressDecoder", "Byte bits are not continuous starting from 0");
}
} }
auto maxBurstLengthBits = static_cast<unsigned>(std::log2(memSpec.maxBurstLength)); // Check if the addresss mapping is capable of matching the requirements of the memSpec
checkMemSpecCompatibility(memSpec);
for (unsigned bitPosition = highestByteBit + 1; checkMemorySize(memSpec);
bitPosition < highestByteBit + 1 + maxBurstLengthBits; checkByteBits(memSpec);
bitPosition++) checkBurstLengthBits(memSpec);
{
if (std::find(vColumnBits.begin(), vColumnBits.end(), bitPosition) == vColumnBits.end())
SC_REPORT_FATAL("AddressDecoder", "No continuous column bits for maximum burst length");
}
unsigned absoluteBankGroups = bankgroupsPerRank * ranks;
unsigned absoluteBanks = banksPerGroup * absoluteBankGroups;
if (memSpec.numberOfChannels != channels || memSpec.ranksPerChannel != ranks ||
memSpec.bankGroupsPerChannel != absoluteBankGroups ||
memSpec.banksPerChannel != absoluteBanks || memSpec.rowsPerBank != rows ||
memSpec.columnsPerRow != columns)
SC_REPORT_FATAL("AddressDecoder", "Memspec and address mapping do not match");
} }
DecodedAddress AddressDecoder::decodeAddress(uint64_t encAddr) const bool AddressDecoder::allComponentsArePowerOfTwo(const MemSpec& memSpec) const {
{ // TODO: What parts do we need to check?
if (encAddr > maximumAddress) return isPowerOfTwo(memSpec.numberOfChannels) &&
SC_REPORT_WARNING("AddressDecoder", isPowerOfTwo(memSpec.ranksPerChannel) &&
("Address " + std::to_string(encAddr) + isPowerOfTwo(memSpec.bankGroupsPerChannel) &&
" out of range (maximum address is " + std::to_string(maximumAddress) + isPowerOfTwo(memSpec.banksPerChannel) &&
")") isPowerOfTwo(memSpec.devicesPerRank) &&
.c_str()); isPowerOfTwo(memSpec.columnsPerRow);
}
// Apply XOR void AddressDecoder::checkMemorySize(const MemSpec& memSpec) {
// For each used xor: bool isMemorySizeMismatch = memSpec.getSimMemSizeInBytes() > upperBoundAddress + 1 ||
// Get the first bit and second bit. Apply a bitwise xor operator and save it back to the (memSpec.getSimMemSizeInBytes() < upperBoundAddress + 1 && !np2Flag);
// first bit.
auto tempAddr = encAddr; if (isMemorySizeMismatch) {
for (const auto& it : vXor) SC_REPORT_FATAL("AddressDecoder", "The mapped bits do not match the memory size");
{ }
uint64_t xoredBit = std::accumulate(it.cbegin(), }
it.cend(),
0, void AddressDecoder::checkMemSpecCompatibility(const MemSpec& memSpec) {
[tempAddr](uint64_t acc, unsigned xorBit) unsigned channels = std::lround(std::pow(2.0, channelBits.length));
{ return acc ^= (tempAddr >> xorBit) & UINT64_C(1); }); unsigned ranks = std::lround(std::pow(2.0, rankBits.length));
encAddr &= ~(UINT64_C(1) << it[0]); unsigned rows = std::lround(std::pow(2.0, rowBits.length));
encAddr |= xoredBit << it[0]; unsigned columns = std::lround(std::pow(2.0, columnBits.length));
unsigned pseudochannels = std::lround(std::pow(2.0, pseudochannelBits.length));
unsigned absoluteBankGroups = bankgroupsPerRank * (ranks * pseudochannels);
unsigned absoluteBanks = banksPerGroup * absoluteBankGroups;
// Depending on the NP2 flag we must adapt the strictness of this check
if (np2Flag) {
if (memSpec.numberOfChannels > channels || memSpec.ranksPerChannel > (ranks * pseudochannels) ||
memSpec.bankGroupsPerChannel > absoluteBankGroups ||
memSpec.banksPerChannel > absoluteBanks || memSpec.rowsPerBank > rows ||
memSpec.columnsPerRow > columns)
SC_REPORT_FATAL("AddressDecoder", "Memspec and address mapping do not match");
}
else {
if (memSpec.numberOfChannels != channels || memSpec.ranksPerChannel != (ranks * pseudochannels) ||
memSpec.bankGroupsPerChannel != absoluteBankGroups ||
memSpec.banksPerChannel != absoluteBanks || memSpec.rowsPerBank != rows ||
memSpec.columnsPerRow != columns)
SC_REPORT_FATAL("AddressDecoder", "Memspec and address mapping do not match");
}
}
void AddressDecoder::checkAddressableLimits(const MemSpec& memSpec) {
validateAddressableLimit(memSpec.numberOfChannels, calculateAddressableElements(channelBits.length), "Channel");
validateAddressableLimit(memSpec.ranksPerChannel, calculateAddressableElements(bankBits.length), "Rank");
unsigned addressableBankGroups = calculateAddressableElements(bankGroupBits.length) * calculateAddressableElements(rankBits.length);
unsigned absoluteBanks = calculateAddressableElements(bankBits.length) * addressableBankGroups;
validateAddressableLimit(memSpec.bankGroupsPerChannel, addressableBankGroups, "Bank group");
validateAddressableLimit(memSpec.banksPerChannel, absoluteBanks, "Bank");
validateAddressableLimit(memSpec.rowsPerBank, calculateAddressableElements(rowBits.length), "Row");
validateAddressableLimit(memSpec.columnsPerRow, calculateAddressableElements(columnBits.length), "Column");
}
unsigned AddressDecoder::calculateAddressableElements(unsigned bitSize) const {
return std::lround(std::pow(2.0, bitSize));
}
void AddressDecoder::validateAddressableLimit(unsigned memSpecValue, unsigned addressableValue, const std::string& name) {
if (memSpecValue > addressableValue || memSpecValue <= (addressableValue >> 1)) {
SC_REPORT_FATAL("AddressDecoder", (name + " bit mapping does not match the memspec configuration").c_str());
}
}
bool AddressDecoder::isPowerOfTwo(unsigned value) const {
return value != 0 && (value & (value - 1)) == 0;
}
unsigned AddressDecoder::checkByteBits(const MemSpec& memSpec) {
unsigned bytesPerBeat = memSpec.dataBusWidth / 8;
unsigned numOfByteBits = std::ceil(std::log2(memSpec.dataBusWidth / 8.0));
if (!isPowerOfTwo(bytesPerBeat)) {
SC_REPORT_WARNING("AddressDecoder",
("Bytes per beat are not power of two! \nAssuming " +
std::to_string(numOfByteBits) + " reserved byte bits.").c_str());
} }
if (byteBits.length < numOfByteBits) {
SC_REPORT_FATAL("AddressDecoder",
("Byte bits are not continuous starting from 0. (bytesPerBeat: " +
std::to_string(bytesPerBeat) +
"B -> number of byte-bits: " +
std::to_string(numOfByteBits) + ")").c_str());
}
return numOfByteBits;
}
void AddressDecoder::checkBurstLengthBits(const MemSpec& memSpec) {
unsigned numOfMaxBurstLengthBits = std::ceil(std::log2(memSpec.maxBurstLength));
burstBitMask = createBitmask(numOfMaxBurstLengthBits, byteBits.length);
if (!isPowerOfTwo(memSpec.maxBurstLength)) {
SC_REPORT_WARNING("AddressDecoder",
("Maximum burst length (" + std::to_string(memSpec.maxBurstLength) +
") is not power of two! \nAssuming " +
std::to_string(numOfMaxBurstLengthBits) +
" reserved burst bits.").c_str());
}
std::bitset<64> burstBitset(((1 << numOfMaxBurstLengthBits) - 1) << columnBits.idx);
std::bitset<64> columnBitset;
for (size_t i = 0; i < columnBits.length; i++) {
columnBitset |= mappingMatrix[columnBits.idx + i];
}
if ((columnBits.length < numOfMaxBurstLengthBits) || ((columnBitset & burstBitset) != burstBitset)) {
SC_REPORT_FATAL("AddressDecoder",
("No continuous column bits for maximum burst length (maximumBurstLength: " +
std::to_string(memSpec.maxBurstLength) +
" -> required number of burst bits: " +
std::to_string(numOfMaxBurstLengthBits) + ")").c_str());
}
}
DecodedAddress AddressDecoder::decodeAddress(tlm::tlm_generic_payload& trans) const
{
uint64_t encAddr = trans.get_address();
if (encAddr > upperBoundAddress)
{
trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
SC_REPORT_WARNING("AddressDecoder",
("Address " + std::to_string(encAddr) +
" out of range (maximum address is " + std::to_string(upperBoundAddress) +
")")
.c_str());
}
uint64_t result = gf2Multiplication(encAddr, mappingMatrix);
/**
* @brief Extracts a specific AddressComponent from the result address.
*/
auto get_component = [&result](const AddressComponent& component) -> unsigned {
if (component.idx < 0 || component.length <= 0) {
return static_cast<unsigned>(0);
}
// Create mask
uint64_t mask = (1ULL << component.length) - 1;
// Shift and apply the mask
return static_cast<unsigned>((result >> component.idx) & mask);
};
DecodedAddress decAddr; DecodedAddress decAddr;
decAddr.channel = get_component(channelBits);
decAddr.rank = get_component(rankBits);
decAddr.rank |= get_component(pseudochannelBits);
decAddr.stack = get_component(stackBits);
decAddr.bankgroup = get_component(bankGroupBits);
decAddr.bank = get_component(bankBits);
decAddr.row = get_component(rowBits);
decAddr.column= get_component(columnBits);
decAddr.byte = get_component(byteBits);
for (unsigned it = 0; it < vChannelBits.size(); it++) if (np2Flag)
decAddr.channel |= ((encAddr >> vChannelBits[it]) & UINT64_C(1)) << it; if (!isAddressValid(decAddr))
trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
for (unsigned it = 0; it < vRankBits.size(); it++)
decAddr.rank |= ((encAddr >> vRankBits[it]) & UINT64_C(1)) << it;
for (unsigned it = 0; it < vStackBits.size(); it++)
decAddr.stack |= ((encAddr >> vStackBits[it]) & UINT64_C(1)) << it;
for (unsigned it = 0; it < vBankGroupBits.size(); it++)
decAddr.bankgroup |= ((encAddr >> vBankGroupBits[it]) & UINT64_C(1)) << it;
for (unsigned it = 0; it < vBankBits.size(); it++)
decAddr.bank |= ((encAddr >> vBankBits[it]) & UINT64_C(1)) << it;
for (unsigned it = 0; it < vRowBits.size(); it++)
decAddr.row |= ((encAddr >> vRowBits[it]) & UINT64_C(1)) << it;
for (unsigned it = 0; it < vColumnBits.size(); it++)
decAddr.column |= ((encAddr >> vColumnBits[it]) & UINT64_C(1)) << it;
for (unsigned it = 0; it < vByteBits.size(); it++)
decAddr.byte |= ((encAddr >> vByteBits[it]) & UINT64_C(1)) << it;
// Important: This offsets must be added after(!) the address validation!
decAddr.bankgroup = decAddr.bankgroup + decAddr.rank * bankgroupsPerRank; decAddr.bankgroup = decAddr.bankgroup + decAddr.rank * bankgroupsPerRank;
decAddr.bank = decAddr.bank + decAddr.bankgroup * banksPerGroup; decAddr.bank = decAddr.bank + decAddr.bankgroup * banksPerGroup;
return decAddr; return decAddr;
} }
bool AddressDecoder::isAddressValid(const DecodedAddress& decAddr) const
{
unsigned it;
// Check if burst address is within limits
auto mask = burstBitMask;
for (it = 0; ((mask >> it) & 1) == 0; it++) { }
if ((decAddr.column & (mask >> it)) >= memSpec->maxBurstLength)
{
SC_REPORT_WARNING("AddressDecoder", ("Burst address out of bounds (given: " +
std::to_string((decAddr.column & (mask >> it))) +
", MemSpec: " + std::to_string(memSpec->maxBurstLength) + ")")
.c_str()
);
return false;
}
// Check all address components for validity
if ((decAddr.channel >= memSpec->numberOfChannels) ||
(decAddr.rank >= memSpec->ranksPerChannel) ||
(decAddr.bankgroup >= memSpec->bankGroupsPerChannel) ||
(decAddr.bank >= memSpec->banksPerGroup) ||
(decAddr.row >= memSpec->rowsPerBank) ||
(decAddr.column >= memSpec->columnsPerRow))
{
SC_REPORT_WARNING("AddressDecoder",
"Invalid address: channel, rank, bankgroup, bank, row or column exeeds memSpec limits.");
return false;
}
return true;
}
unsigned AddressDecoder::decodeChannel(uint64_t encAddr) const unsigned AddressDecoder::decodeChannel(uint64_t encAddr) const
{ {
if (encAddr > maximumAddress) if (encAddr > upperBoundAddress)
SC_REPORT_WARNING("AddressDecoder", SC_REPORT_WARNING("AddressDecoder",
("Address " + std::to_string(encAddr) + ("Address " + std::to_string(encAddr) +
" out of range (maximum address is " + std::to_string(maximumAddress) + " out of range (maximum address is " + std::to_string(upperBoundAddress) +
")") ")")
.c_str()); .c_str());
// Apply XOR uint64_t result = gf2Multiplication(encAddr, mappingMatrix);
// 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 = 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; /**
* @brief Extracts a specific AddressComponent from the result address.
*/
auto get_component = [&result](const AddressComponent& component) -> unsigned {
if (component.idx < 0 || component.length <= 0) {
return static_cast<unsigned>(0);
}
// Create mask
uint64_t mask = (1ULL << component.length) - 1;
// Shift and apply the mask
return static_cast<unsigned>((result >> component.idx) & mask);
};
for (unsigned it = 0; it < vChannelBits.size(); it++) return get_component(channelBits);
channel |= ((encAddr >> vChannelBits[it]) & UINT64_C(1)) << it;
return channel;
} }
uint64_t AddressDecoder::encodeAddress(DecodedAddress decodedAddress) const uint64_t AddressDecoder::encodeAddress(DecodedAddress decAddr) const
{ {
// Convert absoulte addressing for bank, bankgroup to relative // Convert absolute addressing for bank, bankgroup to relative
decodedAddress.bankgroup = decodedAddress.bankgroup % bankgroupsPerRank; decAddr.bankgroup = decAddr.bankgroup % bankgroupsPerRank;
decodedAddress.bank = decodedAddress.bank % banksPerGroup; decAddr.bank = decAddr.bank % banksPerGroup;
uint64_t address = 0; uint64_t mappedAddr = 0;
for (unsigned i = 0; i < vChannelBits.size(); i++) /**
address |= ((decodedAddress.channel >> i) & 0x1) << vChannelBits[i]; * @brief Inserts a specific AddressComponent to the mappedAddress.
*/
auto set_component = [&mappedAddr](const AddressComponent& component, const unsigned int value) -> unsigned {
if (component.idx < 0 || component.length <= 0) {
return mappedAddr;
}
// Shift and add to mappedAddress
return static_cast<unsigned>((value << component.idx) | mappedAddr);
};
for (unsigned i = 0; i < vRankBits.size(); i++) mappedAddr = set_component(channelBits, decAddr.channel);
address |= ((decodedAddress.rank >> i) & 0x1) << vRankBits[i]; mappedAddr = set_component(rankBits, decAddr.rank);
mappedAddr = set_component(pseudochannelBits, decAddr.rank);
mappedAddr = set_component(stackBits, decAddr.stack);
mappedAddr = set_component(bankGroupBits, decAddr.bankgroup);
mappedAddr = set_component(bankBits, decAddr.bank);
mappedAddr = set_component(rowBits, decAddr.row);
mappedAddr = set_component(columnBits, decAddr.column);
mappedAddr = set_component(byteBits, decAddr.byte);
for (unsigned i = 0; i < vStackBits.size(); i++) return gf2Multiplication(mappedAddr, transposedMappingMatrix);
address |= ((decodedAddress.stack >> i) & 0x1) << vStackBits[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 void AddressDecoder::print() const
@@ -324,136 +452,24 @@ void AddressDecoder::print() const
std::cout << "Used Address Mapping:" << std::endl; std::cout << "Used Address Mapping:" << std::endl;
std::cout << std::endl; std::cout << std::endl;
for (int it = static_cast<int>(vChannelBits.size() - 1); it >= 0; it--) auto printBits = [&](const AddressComponent& component) {
{ int startIdx = component.idx;
uint64_t addressBits = int length = component.length;
(UINT64_C(1) << vChannelBits[static_cast<std::vector<unsigned>::size_type>(it)]); if (startIdx < 0) return;
for (auto xorMapping : vXor)
{
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;
}
for (int it = static_cast<int>(vRankBits.size() - 1); it >= 0; it--) for (int i = 0; i<length; ++i) {
{ std::cout << " " << component.name << " " << std::setw(2) << mappingMatrix[startIdx + i] << std::endl;
uint64_t addressBits =
(UINT64_C(1) << vRankBits[static_cast<std::vector<unsigned>::size_type>(it)]);
for (auto xorMapping : vXor)
{
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;
}
for (int it = static_cast<int>(vStackBits.size() - 1); it >= 0; it--) printBits(byteBits);
{ printBits(columnBits);
uint64_t addressBits = printBits(rowBits);
(UINT64_C(1) << vStackBits[static_cast<std::vector<unsigned>::size_type>(it)]); printBits(bankBits);
for (auto xorMapping : vXor) printBits(bankGroupBits);
{ printBits(stackBits);
if (xorMapping.at(0) == vStackBits[static_cast<std::vector<unsigned>::size_type>(it)]) printBits(rankBits);
{ printBits(pseudochannelBits);
for (auto it = xorMapping.cbegin() + 1; it != xorMapping.cend(); it++) printBits(channelBits);
addressBits |= (UINT64_C(1) << *it);
}
}
std::cout << " SID " << std::setw(2) << it << ": " << std::bitset<64>(addressBits)
<< std::endl;
}
for (int it = static_cast<int>(vBankGroupBits.size() - 1); it >= 0; it--)
{
uint64_t addressBits =
(UINT64_C(1) << vBankGroupBits[static_cast<std::vector<unsigned>::size_type>(it)]);
for (auto xorMapping : vXor)
{
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;
}
for (int it = static_cast<int>(vBankBits.size() - 1); it >= 0; it--)
{
uint64_t addressBits =
(UINT64_C(1) << vBankBits[static_cast<std::vector<unsigned>::size_type>(it)]);
for (auto xorMapping : vXor)
{
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;
}
for (int it = static_cast<int>(vRowBits.size() - 1); it >= 0; it--)
{
uint64_t addressBits =
(UINT64_C(1) << vRowBits[static_cast<std::vector<unsigned>::size_type>(it)]);
for (auto xorMapping : vXor)
{
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;
}
for (int it = static_cast<int>(vColumnBits.size() - 1); it >= 0; it--)
{
uint64_t addressBits =
(UINT64_C(1) << vColumnBits[static_cast<std::vector<unsigned>::size_type>(it)]);
for (auto xorMapping : vXor)
{
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;
}
for (int it = static_cast<int>(vByteBits.size() - 1); it >= 0; it--)
{
uint64_t addressBits =
(UINT64_C(1) << vByteBits[static_cast<std::vector<unsigned>::size_type>(it)]);
for (auto xorMapping : vXor)
{
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;
}
std::cout << std::endl;
} }
} // namespace DRAMSys } // namespace DRAMSys

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, RPTU Kaiserslautern-Landau * Copyright (c) 2025, RPTU Kaiserslautern-Landau
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -34,15 +34,14 @@
* Lukas Steiner * Lukas Steiner
* Luiza Correa * Luiza Correa
* Derek Christ * Derek Christ
* Thomas Zimmermann
*/ */
#ifndef ADDRESSDECODER_H #ifndef ADDRESSDECODER_H
#define ADDRESSDECODER_H #define ADDRESSDECODER_H
#include "DRAMSys/config/DRAMSysConfiguration.h"
#include "DRAMSys/configuration/memspec/MemSpec.h" #include "DRAMSys/configuration/memspec/MemSpec.h"
#include "DRAMSys/config/AddressMapping.h"
#include <utility>
#include <vector> #include <vector>
namespace DRAMSys namespace DRAMSys
@@ -50,27 +49,6 @@ namespace DRAMSys
struct DecodedAddress struct DecodedAddress
{ {
DecodedAddress(unsigned channel,
unsigned rank,
unsigned stack,
unsigned bankgroup,
unsigned bank,
unsigned row,
unsigned column,
unsigned bytes) :
channel(channel),
rank(rank),
stack(stack),
bankgroup(bankgroup),
bank(bank),
row(row),
column(column),
byte(bytes)
{
}
DecodedAddress() = default;
unsigned channel = 0; unsigned channel = 0;
unsigned rank = 0; unsigned rank = 0;
unsigned stack = 0; unsigned stack = 0;
@@ -79,38 +57,198 @@ struct DecodedAddress
unsigned row = 0; unsigned row = 0;
unsigned column = 0; unsigned column = 0;
unsigned byte = 0; unsigned byte = 0;
DecodedAddress(unsigned channel,
unsigned rank,
unsigned stack,
unsigned bankgroup,
unsigned bank,
unsigned row,
unsigned column,
unsigned byte) :
channel(channel),
rank(rank),
stack(stack),
bankgroup(bankgroup),
bank(bank),
row(row),
column(column),
byte(byte)
{}
DecodedAddress() = default;
};
struct AddressComponent {
AddressComponent() : idx(-1), length(0), name("undef") {}
AddressComponent(std::string_view name) : idx(-1), length(0), name(name) {}
explicit AddressComponent(int idx, int length, std::string_view name) : idx(idx), length(length), name(name) {}
int idx;
unsigned length;
std::string_view name;
}; };
class AddressDecoder class AddressDecoder
{ {
public: public:
AddressDecoder(const Config::AddressMapping& addressMapping); AddressDecoder(const DRAMSys::Config::AddressMapping& addressMapping);
[[nodiscard]] DecodedAddress decodeAddress(uint64_t encAddr) const; /**
* @brief Decodes an address from a transaction payload into its address components.
*
* @param trans The transaction payload.
* @return The decoded address.
*/
[[nodiscard]] DecodedAddress decodeAddress(tlm::tlm_generic_payload& trans) const;
/**
* @brief Decodes the channel component from an encoded address.
*
* @param encAddr The encoded address.
* @return The decoded channel number.
*/
[[nodiscard]] unsigned decodeChannel(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; }
/**
* @brief Encodes a DecodedAddress into an address value.
*
* @param decAddr The decoded address to encode.
* @return The encoded address.
*/
[[nodiscard]] uint64_t encodeAddress(DecodedAddress decAddr) const;
/**
* @brief Checks if all address mapping bits are used and validates compatibility with the memory specification.
*
* @param memSpec The memory specification to check.
*/
void plausibilityCheck(const MemSpec& memSpec);
/**
* @brief Prints the current address mapping configuration.
*/
void print() const; void print() const;
void plausibilityCheck(const MemSpec &memSpec);
private: private:
std::vector<std::bitset<64>> mappingMatrix;
std::vector<std::bitset<64>> transposedMappingMatrix;
uint64_t highestBitValue;
const MemSpec* memSpec;
uint64_t burstBitMask;
AddressComponent byteBits;
AddressComponent columnBits;
AddressComponent bankGroupBits;
AddressComponent bankBits;
AddressComponent rowBits;
AddressComponent pseudochannelBits;
AddressComponent channelBits;
AddressComponent rankBits;
AddressComponent stackBits;
unsigned banksPerGroup; unsigned banksPerGroup;
unsigned bankgroupsPerRank; unsigned bankgroupsPerRank;
uint64_t maximumAddress; uint64_t upperBoundAddress;
bool np2Flag = false;
/**
* @brief Transposes a matrix of 64-bit bitsets.
*
* @param matrix The matrix to transpose.
* @return The transposed matrix.
*/
[[nodiscard]] std::vector<std::bitset<64>> transposeMatrix(const std::vector<std::bitset<64>>& matrix);
/**
* @brief Multiplies a 64-bit vector with a matrix over GF(2).
*
* @param inputVec The input vector to multiply.
* @param matrix The GF(2) matrix.
* @return The result of the multiplication as a 64-bit unsinged integer.
*/
[[nodiscard]] uint64_t gf2Multiplication(const uint64_t& inputVec, const std::vector<std::bitset<64>>& matrix) const;
/**
* @brief Checks if all addressable components in the memory specification are powers of two.
*
* @param memSpec The memory specification.
* @return true if all components are powers of two, false otherwise.
*/
bool allComponentsArePowerOfTwo(const MemSpec& memSpec) const;
/**
* @brief Checks if the mapped address space matches the memory size from the memory specification.
*
* @param memSpec The memory specification.
*/
void checkMemorySize(const MemSpec& memSpec);
/**
* @brief Checks if the address mapping is compatible with the memory specification.
*
* @param memSpec The memory specification.
*/
void checkMemSpecCompatibility(const MemSpec& memSpec);
/**
* @brief Checks if the addressable limits for each memory component are sufficient.
*
* @param memSpec The memory specification.
*/
void checkAddressableLimits(const MemSpec& memSpec);
/**
* @brief Calculates the number of addressable elements for a given bit size.
*
* @param bitSize The number of bits.
* @return The number of addressable elements.
*/
[[nodiscard]] unsigned calculateAddressableElements(unsigned bitSize) const;
/**
* @brief Validates that the addressable value matches the value from the memory specification.
*
* @param memSpecValue The value from the memory specification.
* @param addressableValue The calculated addressable value.
* @param name The name of the component.
*/
void validateAddressableLimit(unsigned memSpecValue, unsigned addressableValue, const std::string& name);
/**
* @brief Checks if a given value is a power of two.
*
* @param value The value to check.
* @return true if the value is a power of two, false otherwise.
*/
[[nodiscard]] bool isPowerOfTwo(unsigned value) const;
/**
* @brief Calculates and checks the number of byte bits required for the memory specification.
*
* @param memSpec The memory specification.
* @return The number of byte bits.
*/
unsigned checkByteBits(const MemSpec& memSpec);
/**
* @brief Checks and handles burst lengths that are not a power of two.
*
* @param memSpec The memory specification.
*/
void checkBurstLengthBits(const MemSpec& memSpec);
/**
* @brief Checks if the decoded address is valid according to the memory specification.
*
* @param decAddr The address to check.
* @return true if the address is valid, false otherwise.
*/
bool isAddressValid(const DecodedAddress& decAddr) const;
// This container stores for each used xor gate a pair of address bits, the first bit is
// overwritten with the result
std::vector<std::vector<unsigned>> vXor;
std::vector<unsigned> vChannelBits;
std::vector<unsigned> vRankBits;
std::vector<unsigned> vStackBits;
std::vector<unsigned> vBankGroupBits;
std::vector<unsigned> vBankBits;
std::vector<unsigned> vRowBits;
std::vector<unsigned> vColumnBits;
std::vector<unsigned> vByteBits;
}; };
} // namespace DRAMSys } // namespace DRAMSys

View File

@@ -195,7 +195,7 @@ void Arbiter::b_transport([[maybe_unused]] int id,
{ {
trans.set_address(trans.get_address() - addressOffset); trans.set_address(trans.get_address() - addressOffset);
DecodedAddress decodedAddress = addressDecoder.decodeAddress(trans.get_address()); DecodedAddress decodedAddress = addressDecoder.decodeAddress(trans);
iSocket[static_cast<int>(decodedAddress.channel)]->b_transport(trans, delay); iSocket[static_cast<int>(decodedAddress.channel)]->b_transport(trans, delay);
} }
@@ -203,7 +203,7 @@ unsigned int Arbiter::transport_dbg([[maybe_unused]] int id, tlm::tlm_generic_pa
{ {
trans.set_address(trans.get_address() - addressOffset); trans.set_address(trans.get_address() - addressOffset);
DecodedAddress decodedAddress = addressDecoder.decodeAddress(trans.get_address()); DecodedAddress decodedAddress = addressDecoder.decodeAddress(trans);
return iSocket[static_cast<int>(decodedAddress.channel)]->transport_dbg(trans); return iSocket[static_cast<int>(decodedAddress.channel)]->transport_dbg(trans);
} }

View File

@@ -89,7 +89,7 @@ void EccModule::peqCallback(tlm::tlm_generic_payload& cbPayload, const tlm::tlm_
sc_time tDelay = SC_ZERO_TIME; sc_time tDelay = SC_ZERO_TIME;
DRAMSys::DecodedAddress decodedAddress = DRAMSys::DecodedAddress decodedAddress =
addressDecoder.decodeAddress(cbPayload.get_address()); addressDecoder.decodeAddress(cbPayload);
decodedAddress = calculateOffsetAddress(decodedAddress); decodedAddress = calculateOffsetAddress(decodedAddress);
// Update the original address to account for the offsets // Update the original address to account for the offsets
@@ -159,7 +159,7 @@ void EccModule::peqCallback(tlm::tlm_generic_payload& cbPayload, const tlm::tlm_
sc_time tDelay = SC_ZERO_TIME; sc_time tDelay = SC_ZERO_TIME;
DRAMSys::DecodedAddress decodedAddress = DRAMSys::DecodedAddress decodedAddress =
addressDecoder.decodeAddress(tPayload.get_address()); addressDecoder.decodeAddress(tPayload);
decodedAddress = calculateOffsetAddress(decodedAddress); decodedAddress = calculateOffsetAddress(decodedAddress);
#ifdef ECC_ENABLE #ifdef ECC_ENABLE

View File

@@ -86,6 +86,12 @@ Simulator::instantiateInitiator(const DRAMSys::Config::Initiator& initiator)
uint64_t memorySize = dramSys->getMemSpec().getSimMemSizeInBytes(); uint64_t memorySize = dramSys->getMemSpec().getSimMemSizeInBytes();
sc_core::sc_time interfaceClk = dramSys->getMemSpec().tCK; sc_core::sc_time interfaceClk = dramSys->getMemSpec().tCK;
// To support non-power-of-two values for the burst length and width, we round the BL
// down to the smaller-or-equal power-of-two.
unsigned int burstBits = std::log2(dramSys->getMemSpec().defaultBurstLength);
unsigned int widthBits = std::log2(dramSys->getMemSpec().dataBusWidth);
unsigned int defaultDataLength = std::pow(2, burstBits) * std::pow(2, widthBits) / 8;
return std::visit( return std::visit(
[=](auto&& config) -> std::unique_ptr<RequestIssuer> [=](auto&& config) -> std::unique_ptr<RequestIssuer>
{ {

File diff suppressed because it is too large Load Diff

View File

@@ -35,11 +35,14 @@
#include "AddressDecoderConfigs.h" #include "AddressDecoderConfigs.h"
#include <bitset> #include "gtest/gtest-spi.h"
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <DRAMSys/simulation/AddressDecoder.h> #include <DRAMSys/simulation/AddressDecoder.h>
#include "DRAMSys/configuration/memspec/MemSpec.h"
#include "DRAMSys/configuration/memspec/MemSpecDDR4.h"
class AddressDecoderFixture : public ::testing::Test class AddressDecoderFixture : public ::testing::Test
{ {
protected: protected:
@@ -55,10 +58,13 @@ protected:
DRAMSys::AddressDecoder addressDecoder; DRAMSys::AddressDecoder addressDecoder;
}; };
TEST_F(AddressDecoderFixture, Decoding) TEST_F(AddressDecoderFixture, Decoding)
{ {
uint64_t address = 0x3A59'1474; uint64_t address = 0x3A59'1474;
auto decodedAddress = addressDecoder.decodeAddress(address); tlm::tlm_generic_payload trans;
trans.set_address(address);
auto decodedAddress = addressDecoder.decodeAddress(trans);
unsigned int channel = decodedAddress.channel; unsigned int channel = decodedAddress.channel;
unsigned int rank = decodedAddress.rank; unsigned int rank = decodedAddress.rank;
@@ -66,7 +72,6 @@ TEST_F(AddressDecoderFixture, Decoding)
unsigned int bank = decodedAddress.bank; unsigned int bank = decodedAddress.bank;
unsigned int row = decodedAddress.row; unsigned int row = decodedAddress.row;
unsigned int column = decodedAddress.column; unsigned int column = decodedAddress.column;
unsigned int byte = decodedAddress.byte;
EXPECT_EQ(channel, 0); EXPECT_EQ(channel, 0);
EXPECT_EQ(rank, 0); EXPECT_EQ(rank, 0);
@@ -74,7 +79,61 @@ TEST_F(AddressDecoderFixture, Decoding)
EXPECT_EQ(bank, 12); EXPECT_EQ(bank, 12);
EXPECT_EQ(row, 29874); EXPECT_EQ(row, 29874);
EXPECT_EQ(column, 170); EXPECT_EQ(column, 170);
EXPECT_EQ(byte, 0); }
TEST_F(AddressDecoderFixture, DecodingNP2Failure)
{
addressMappingConfig = DRAMSys::Config::AddressMapping(nlohmann::json::parse(validAddressMappingJsonString)
.at("addressmapping")
.get<DRAMSys::Config::AddressMapping>());
auto memSpec = std::make_unique<const DRAMSys::MemSpecDDR4>(
nlohmann::json::parse(validNP2MemSpecJsonString)
.at("memspec").get< DRAMUtils::MemSpec::MemSpecDDR4>());
addressDecoder = DRAMSys::AddressDecoder(addressMappingConfig);
addressDecoder.plausibilityCheck(*memSpec);
uint64_t address = 0x3A59'1478;
tlm::tlm_generic_payload trans;
trans.set_address(address);
addressDecoder.decodeAddress(trans);
EXPECT_EQ(trans.get_response_status(), tlm::TLM_ADDRESS_ERROR_RESPONSE);
}
TEST_F(AddressDecoderFixture, DecodingNP2Success)
{
addressMappingConfig = DRAMSys::Config::AddressMapping(nlohmann::json::parse(validAddressMappingJsonString)
.at("addressmapping")
.get<DRAMSys::Config::AddressMapping>());
auto memSpec = std::make_unique<const DRAMSys::MemSpecDDR4>(
nlohmann::json::parse(validNP2MemSpecJsonString)
.at("memspec").get< DRAMUtils::MemSpec::MemSpecDDR4>());
addressDecoder = DRAMSys::AddressDecoder(addressMappingConfig);
addressDecoder.plausibilityCheck(*memSpec);
uint64_t address = 0x3A59'1477;
tlm::tlm_generic_payload trans;
trans.set_address(address);
trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
auto decodedAddress = addressDecoder.decodeAddress(trans);
unsigned int channel = decodedAddress.channel;
unsigned int rank = decodedAddress.rank;
unsigned int bankgroup = decodedAddress.bankgroup;
unsigned int bank = decodedAddress.bank;
unsigned int row = decodedAddress.row;
unsigned int column = decodedAddress.column;
EXPECT_EQ(channel, 0);
EXPECT_EQ(rank, 0);
EXPECT_EQ(bankgroup, 1);
EXPECT_EQ(bank, 4);
EXPECT_EQ(row, 7468);
EXPECT_EQ(column, 558);
EXPECT_EQ(trans.get_response_status(), tlm::TLM_INCOMPLETE_RESPONSE);
} }
TEST_F(AddressDecoderFixture, Encoding) TEST_F(AddressDecoderFixture, Encoding)
@@ -98,14 +157,93 @@ TEST_F(AddressDecoderFixture, DeEncoding)
{ {
std::array testAddresses{std::uint64_t(0x3A59'1474), std::array testAddresses{std::uint64_t(0x3A59'1474),
std::uint64_t(0x0000'0000), std::uint64_t(0x0000'0000),
std::uint64_t(0x2FFA'1231), std::uint64_t(0x2FFA'1230),
std::uint64_t(0x0001'FFFF)}; std::uint64_t(0x0001'FFF0)};
tlm::tlm_generic_payload trans;
for (auto address : testAddresses) for (auto address : testAddresses)
{ {
DRAMSys::DecodedAddress decodedAddress = addressDecoder.decodeAddress(address); trans.set_address(address);
DRAMSys::DecodedAddress decodedAddress = addressDecoder.decodeAddress(trans);
uint64_t encodedAddress = addressDecoder.encodeAddress(decodedAddress); uint64_t encodedAddress = addressDecoder.encodeAddress(decodedAddress);
EXPECT_EQ(encodedAddress, address); EXPECT_EQ(encodedAddress, address);
} }
} }
class AddressDecoderPlausibilityFixture : public ::testing::Test
{
protected:
std::unique_ptr<DRAMSys::AddressDecoder> addressDecoder = nullptr;
std::unique_ptr<DRAMSys::MemSpecDDR4> memSpecDDR4 = nullptr;
void setupDecoder(const std::string_view& memSpecJson,
const std::string_view& addressMappingJson)
{
DRAMUtils::MemSpec::MemSpecDDR4 memSpec =
nlohmann::json::parse(memSpecJson).at("memspec").get< DRAMUtils::MemSpec::MemSpecDDR4>();
memSpecDDR4 = std::make_unique<DRAMSys::MemSpecDDR4>(memSpec);
DRAMSys::Config::AddressMapping addressMappingConfig =
nlohmann::json::parse(addressMappingJson)
.at("addressmapping")
.get<DRAMSys::Config::AddressMapping>();
addressDecoder = std::make_unique<DRAMSys::AddressDecoder>(addressMappingConfig);
}
};
TEST_F(AddressDecoderPlausibilityFixture, ValidPlausibilityCheck)
{
setupDecoder(validMemSpecJsonString, validAddressMappingJsonString);
EXPECT_NO_THROW(addressDecoder->plausibilityCheck(*memSpecDDR4));
}
TEST_F(AddressDecoderPlausibilityFixture, ValidNP2PlausibilityCheck)
{
setupDecoder(validNP2MemSpecJsonString, validAddressMappingJsonString);
EXPECT_NO_THROW(addressDecoder->plausibilityCheck(*memSpecDDR4));
}
TEST_F(AddressDecoderPlausibilityFixture, InvalidMaxAddress)
{
setupDecoder(invalidMaxAddressMemSpecJsonString, validAddressMappingJsonString);
EXPECT_DEATH(addressDecoder->plausibilityCheck(*memSpecDDR4), "");
}
TEST_F(AddressDecoderPlausibilityFixture, DuplicateBits)
{
setupDecoder(validMemSpecJsonString, addressMappingWithDuplicatesJsonString);
EXPECT_DEATH(addressDecoder->plausibilityCheck(*memSpecDDR4), "");
}
TEST_F(AddressDecoderPlausibilityFixture, NonContinuousByteBits)
{
setupDecoder(validMemSpecJsonString, nonContinuousByteBitsAddressMappingJsonString);
EXPECT_DEATH(addressDecoder->plausibilityCheck(*memSpecDDR4), "");
}
TEST_F(AddressDecoderPlausibilityFixture, InvalidChannelMapping)
{
setupDecoder(invalidChannelMemSpecJsonString, validAddressMappingJsonString);
EXPECT_DEATH(addressDecoder->plausibilityCheck(*memSpecDDR4), "");
}
TEST_F(AddressDecoderPlausibilityFixture, InvalidBankGroups)
{
setupDecoder(invalidBankGroupMemSpecJsonString, validAddressMappingJsonString);
EXPECT_DEATH(addressDecoder->plausibilityCheck(*memSpecDDR4), "");
}
TEST_F(AddressDecoderPlausibilityFixture, InvalidRanks)
{
setupDecoder(invalidRanksMemSpecJsonString, validAddressMappingJsonString);
EXPECT_DEATH(addressDecoder->plausibilityCheck(*memSpecDDR4), "");
}