Feature: Rewrote AddressDecoder

This commit is contained in:
Thomas Zimmermann
2025-09-22 12:00:49 +00:00
committed by Lukas Steiner
parent ee04212ddb
commit ce1332ca81
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)
{
auto decoder = addressDecoder();
tlm::tlm_generic_payload trans;
trans.set_address(0x0);
for (auto _ : state)
{
// Actual address has no significant impact on performance
auto decodedAddress = decoder.decodeAddress(0x0);
auto decodedAddress = decoder.decodeAddress(trans);
benchmark::DoNotOptimize(decodedAddress);
}
}

View File

@@ -59,6 +59,37 @@ struct AddressMapping
std::optional<std::vector<BitEntry>> STACK_BIT;
std::optional<std::vector<BitEntry>> PSEUDOCHANNEL_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,

View File

@@ -36,6 +36,14 @@
### 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
DRAMSys/common/DebugManager.cpp
DRAMSys/common/TlmRecorder.cpp

View File

@@ -598,8 +598,8 @@ void Controller::manageRequests(const sc_time& delay)
transToAcquire.payload->acquire();
// The following logic assumes that transactions are naturally aligned
uint64_t address = transToAcquire.payload->get_address();
[[maybe_unused]] uint64_t dataLength = transToAcquire.payload->get_data_length();
const uint64_t address = transToAcquire.payload->get_address();
const uint64_t dataLength = transToAcquire.payload->get_data_length();
assert((dataLength & (dataLength - 1)) == 0); // Data length must be a power of 2
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
DecodedAddress decodedAddress =
addressDecoder.decodeAddress(transToAcquire.payload->get_address());
addressDecoder.decodeAddress(*transToAcquire.payload);
ControllerExtension::setAutoExtension(
*transToAcquire.payload,
nextChannelPayloadIDToAppend++,
@@ -807,7 +807,7 @@ void Controller::createChildTranses(tlm::tlm_generic_payload& parentTrans)
for (auto* childTrans : childTranses)
{
DecodedAddress decodedAddress = addressDecoder.decodeAddress(childTrans->get_address());
DecodedAddress decodedAddress = addressDecoder.decodeAddress(*childTrans);
ControllerExtension::setAutoExtension(*childTrans,
nextChannelPayloadIDToAppend,
Rank(decodedAddress.rank),
@@ -816,8 +816,7 @@ void Controller::createChildTranses(tlm::tlm_generic_payload& parentTrans)
Bank(decodedAddress.bank),
Row(decodedAddress.row),
Column(decodedAddress.column),
(childTrans->get_data_length() * 8) /
memSpec.dataBusWidth);
memSpec.maxBurstLength);
}
nextChannelPayloadIDToAppend++;
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.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,288 +34,416 @@
* Lukas Steiner
* Luiza Correa
* Derek Christ
* Thomas Zimmermann
*/
#include "AddressDecoder.h"
#include "DRAMSys/config/AddressMapping.h"
#include <bit>
#include <bitset>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <cstdint>
#include <immintrin.h>
#include <set>
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<unsigned>& bitVector,
std::vector<std::vector<unsigned>>& xorVector)
{
for (const Config::AddressMapping::BitEntry& bitEntry : mappingVector)
{
if (bitEntry.get_type() == Config::AddressMapping::BitEntry::Type::SINGLE) {
bitVector.push_back(bitEntry.at(0));
} else {
bitVector.push_back(bitEntry.at(0));
xorVector.push_back(bitEntry);
std::vector<std::bitset<64>> AddressDecoder::transposeMatrix(const std::vector<std::bitset<64>>& matrix) {
size_t size = matrix.size();
std::vector<std::bitset<64>> transposedMatrix(size);
for (size_t i = 0; i < size; ++i) {
for (size_t j = 0; j < 64; ++j) {
if (matrix[i].test(j))
transposedMatrix[j].set(i);
}
}
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)
{
addMapping(*channelBits, vChannelBits, vXor);
}
#if defined(__clang__) || defined(__GNUC__)
uint64_t result = 0;
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)
{
addMapping(*rankBits, vRankBits, vXor);
}
for (size_t i = 0; i < matrix.size(); ++i) {
resultBits[i] = (inputBits & matrix[i]).count() % 2;
}
return resultBits.to_ullong();
#endif
if (const auto& stackBits = addressMapping.STACK_BIT)
{
addMapping(*stackBits, vStackBits, vXor);
}
// 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;
// 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;
// for (size_t i = 0; i < mappingMatrix.size(); ++i) {
// std::cout << "Row " << i << ":\t" << mappingMatrix[i] << " | " << resultBits[i] << std::endl;
// }
}
/****************************/
/* 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)
{
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()));
(*this).memSpec = &memSpec;
np2Flag = not allComponentsArePowerOfTwo(memSpec);
maximumAddress = static_cast<uint64_t>(bytes) * columns * rows * banks * bankGroups * stacks *
ranks * channels -
1;
// Check if all address bits are used
// TODO: Check if every bit occurs ~exactly~ once or just at least once?
std::bitset<64> orBitset(0);
for (auto bitset: mappingMatrix) {
orBitset |= bitset;
}
auto totalAddressBits = static_cast<unsigned>(std::log2(maximumAddress));
for (unsigned bitPosition = 0; bitPosition < totalAddressBits; bitPosition++)
{
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");
std::bitset<64> mask((1ULL << (highestBitValue + 1)) - 1);
if (orBitset != mask) {
SC_REPORT_FATAL("AddressDecoder", "Not all address bits are used");
}
int highestByteBit = -1;
if (!vByteBits.empty())
{
highestByteBit = static_cast<int>(*std::max_element(vByteBits.begin(), vByteBits.end()));
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");
}
// Check if the byte bits are continous and starting from 0
uint64_t row = 0;
for (size_t i = 0; i < byteBits.length; i++) {
row |= mappingMatrix[byteBits.idx + i].to_ullong();
}
if (row != ((1ULL << byteBits.length) - 1)) {
SC_REPORT_FATAL("AddressDecoder", "Not all address bits occur exactly once");
}
auto maxBurstLengthBits = static_cast<unsigned>(std::log2(memSpec.maxBurstLength));
for (unsigned bitPosition = highestByteBit + 1;
bitPosition < highestByteBit + 1 + maxBurstLengthBits;
bitPosition++)
{
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");
// Check if the addresss mapping is capable of matching the requirements of the memSpec
checkMemSpecCompatibility(memSpec);
checkMemorySize(memSpec);
checkByteBits(memSpec);
checkBurstLengthBits(memSpec);
}
DecodedAddress AddressDecoder::decodeAddress(uint64_t encAddr) const
{
if (encAddr > maximumAddress)
SC_REPORT_WARNING("AddressDecoder",
("Address " + std::to_string(encAddr) +
" out of range (maximum address is " + std::to_string(maximumAddress) +
")")
.c_str());
bool AddressDecoder::allComponentsArePowerOfTwo(const MemSpec& memSpec) const {
// TODO: What parts do we need to check?
return isPowerOfTwo(memSpec.numberOfChannels) &&
isPowerOfTwo(memSpec.ranksPerChannel) &&
isPowerOfTwo(memSpec.bankGroupsPerChannel) &&
isPowerOfTwo(memSpec.banksPerChannel) &&
isPowerOfTwo(memSpec.devicesPerRank) &&
isPowerOfTwo(memSpec.columnsPerRow);
}
// Apply XOR
// 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];
void AddressDecoder::checkMemorySize(const MemSpec& memSpec) {
bool isMemorySizeMismatch = memSpec.getSimMemSizeInBytes() > upperBoundAddress + 1 ||
(memSpec.getSimMemSizeInBytes() < upperBoundAddress + 1 && !np2Flag);
if (isMemorySizeMismatch) {
SC_REPORT_FATAL("AddressDecoder", "The mapped bits do not match the memory size");
}
}
void AddressDecoder::checkMemSpecCompatibility(const MemSpec& memSpec) {
unsigned channels = std::lround(std::pow(2.0, channelBits.length));
unsigned ranks = std::lround(std::pow(2.0, rankBits.length));
unsigned rows = std::lround(std::pow(2.0, rowBits.length));
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;
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++)
decAddr.channel |= ((encAddr >> vChannelBits[it]) & UINT64_C(1)) << it;
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;
if (np2Flag)
if (!isAddressValid(decAddr))
trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
// Important: This offsets must be added after(!) the address validation!
decAddr.bankgroup = decAddr.bankgroup + decAddr.rank * bankgroupsPerRank;
decAddr.bank = decAddr.bank + decAddr.bankgroup * banksPerGroup;
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
{
if (encAddr > maximumAddress)
if (encAddr > upperBoundAddress)
SC_REPORT_WARNING("AddressDecoder",
("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());
// Apply XOR
// 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];
}
uint64_t result = gf2Multiplication(encAddr, mappingMatrix);
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++)
channel |= ((encAddr >> vChannelBits[it]) & UINT64_C(1)) << it;
return channel;
return get_component(channelBits);
}
uint64_t AddressDecoder::encodeAddress(DecodedAddress decodedAddress) const
uint64_t AddressDecoder::encodeAddress(DecodedAddress decAddr) const
{
// Convert absoulte addressing for bank, bankgroup to relative
decodedAddress.bankgroup = decodedAddress.bankgroup % bankgroupsPerRank;
decodedAddress.bank = decodedAddress.bank % banksPerGroup;
// Convert absolute addressing for bank, bankgroup to relative
decAddr.bankgroup = decAddr.bankgroup % bankgroupsPerRank;
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++)
address |= ((decodedAddress.rank >> i) & 0x1) << vRankBits[i];
mappedAddr = set_component(channelBits, decAddr.channel);
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++)
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;
return gf2Multiplication(mappedAddr, transposedMappingMatrix);
}
void AddressDecoder::print() const
@@ -324,136 +452,24 @@ void AddressDecoder::print() const
std::cout << "Used Address Mapping:" << std::endl;
std::cout << std::endl;
for (int it = static_cast<int>(vChannelBits.size() - 1); it >= 0; it--)
{
uint64_t addressBits =
(UINT64_C(1) << vChannelBits[static_cast<std::vector<unsigned>::size_type>(it)]);
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;
}
auto printBits = [&](const AddressComponent& component) {
int startIdx = component.idx;
int length = component.length;
if (startIdx < 0) return;
for (int it = static_cast<int>(vRankBits.size() - 1); it >= 0; it--)
{
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);
}
for (int i = 0; i<length; ++i) {
std::cout << " " << component.name << " " << std::setw(2) << mappingMatrix[startIdx + i] << std::endl;
}
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--)
{
uint64_t addressBits =
(UINT64_C(1) << vStackBits[static_cast<std::vector<unsigned>::size_type>(it)]);
for (auto xorMapping : vXor)
{
if (xorMapping.at(0) == vStackBits[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 << " 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;
printBits(byteBits);
printBits(columnBits);
printBits(rowBits);
printBits(bankBits);
printBits(bankGroupBits);
printBits(stackBits);
printBits(rankBits);
printBits(pseudochannelBits);
printBits(channelBits);
}
} // namespace DRAMSys

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, RPTU Kaiserslautern-Landau
* Copyright (c) 2025, RPTU Kaiserslautern-Landau
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,15 +34,14 @@
* Lukas Steiner
* Luiza Correa
* Derek Christ
* Thomas Zimmermann
*/
#ifndef ADDRESSDECODER_H
#define ADDRESSDECODER_H
#include "DRAMSys/config/DRAMSysConfiguration.h"
#include "DRAMSys/configuration/memspec/MemSpec.h"
#include <utility>
#include "DRAMSys/config/AddressMapping.h"
#include <vector>
namespace DRAMSys
@@ -50,27 +49,6 @@ namespace DRAMSys
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 rank = 0;
unsigned stack = 0;
@@ -79,38 +57,198 @@ struct DecodedAddress
unsigned row = 0;
unsigned column = 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
{
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]] 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 plausibilityCheck(const MemSpec &memSpec);
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 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

View File

@@ -195,7 +195,7 @@ void Arbiter::b_transport([[maybe_unused]] int id,
{
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);
}
@@ -203,7 +203,7 @@ unsigned int Arbiter::transport_dbg([[maybe_unused]] int id, tlm::tlm_generic_pa
{
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);
}

View File

@@ -89,7 +89,7 @@ void EccModule::peqCallback(tlm::tlm_generic_payload& cbPayload, const tlm::tlm_
sc_time tDelay = SC_ZERO_TIME;
DRAMSys::DecodedAddress decodedAddress =
addressDecoder.decodeAddress(cbPayload.get_address());
addressDecoder.decodeAddress(cbPayload);
decodedAddress = calculateOffsetAddress(decodedAddress);
// 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;
DRAMSys::DecodedAddress decodedAddress =
addressDecoder.decodeAddress(tPayload.get_address());
addressDecoder.decodeAddress(tPayload);
decodedAddress = calculateOffsetAddress(decodedAddress);
#ifdef ECC_ENABLE

View File

@@ -86,6 +86,12 @@ Simulator::instantiateInitiator(const DRAMSys::Config::Initiator& initiator)
uint64_t memorySize = dramSys->getMemSpec().getSimMemSizeInBytes();
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(
[=](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 <bitset>
#include "gtest/gtest-spi.h"
#include <gtest/gtest.h>
#include <DRAMSys/simulation/AddressDecoder.h>
#include "DRAMSys/configuration/memspec/MemSpec.h"
#include "DRAMSys/configuration/memspec/MemSpecDDR4.h"
class AddressDecoderFixture : public ::testing::Test
{
protected:
@@ -55,10 +58,13 @@ protected:
DRAMSys::AddressDecoder addressDecoder;
};
TEST_F(AddressDecoderFixture, Decoding)
{
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 rank = decodedAddress.rank;
@@ -66,7 +72,6 @@ TEST_F(AddressDecoderFixture, Decoding)
unsigned int bank = decodedAddress.bank;
unsigned int row = decodedAddress.row;
unsigned int column = decodedAddress.column;
unsigned int byte = decodedAddress.byte;
EXPECT_EQ(channel, 0);
EXPECT_EQ(rank, 0);
@@ -74,7 +79,61 @@ TEST_F(AddressDecoderFixture, Decoding)
EXPECT_EQ(bank, 12);
EXPECT_EQ(row, 29874);
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)
@@ -98,14 +157,93 @@ TEST_F(AddressDecoderFixture, DeEncoding)
{
std::array testAddresses{std::uint64_t(0x3A59'1474),
std::uint64_t(0x0000'0000),
std::uint64_t(0x2FFA'1231),
std::uint64_t(0x0001'FFFF)};
std::uint64_t(0x2FFA'1230),
std::uint64_t(0x0001'FFF0)};
tlm::tlm_generic_payload trans;
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);
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), "");
}