From ce1332ca81be66b577d0eae2b66136727e6e5b90 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 22 Sep 2025 12:00:49 +0000 Subject: [PATCH] Feature: Rewrote AddressDecoder --- benches/addressdecoder.cpp | 5 +- .../DRAMSys/config/AddressMapping.h | 31 + src/libdramsys/CMakeLists.txt | 8 + .../DRAMSys/controller/Controller.cpp | 11 +- .../DRAMSys/simulation/AddressDecoder.cpp | 718 ++++++------ .../DRAMSys/simulation/AddressDecoder.h | 222 +++- src/libdramsys/DRAMSys/simulation/Arbiter.cpp | 4 +- src/simulator/simulator/EccModule.cpp | 4 +- src/simulator/simulator/Simulator.cpp | 6 + tests/tests_dramsys/AddressDecoderConfigs.h | 1002 ++++++++++++++++- tests/tests_dramsys/AddressDecoderTests.cpp | 152 ++- 11 files changed, 1708 insertions(+), 455 deletions(-) diff --git a/benches/addressdecoder.cpp b/benches/addressdecoder.cpp index 193f98ad..ee1b21bb 100644 --- a/benches/addressdecoder.cpp +++ b/benches/addressdecoder.cpp @@ -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); } } diff --git a/src/configuration/DRAMSys/config/AddressMapping.h b/src/configuration/DRAMSys/config/AddressMapping.h index 6cef8ee9..cf97ae0d 100644 --- a/src/configuration/DRAMSys/config/AddressMapping.h +++ b/src/configuration/DRAMSys/config/AddressMapping.h @@ -59,6 +59,37 @@ struct AddressMapping std::optional> STACK_BIT; std::optional> PSEUDOCHANNEL_BIT; std::optional> CHANNEL_BIT; + + unsigned int getHighestBit() const { + unsigned int highestBit = std::numeric_limits::min(); + bool found = false; + + auto checkAndUpdate = [&](const std::optional>& 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::min(); // Rückgabe des höchsten Wertes oder des minimalen Wertes + } + }; NLOHMANN_JSONIFY_ALL_THINGS(AddressMapping, diff --git a/src/libdramsys/CMakeLists.txt b/src/libdramsys/CMakeLists.txt index ad802e0c..f70ac4fb 100644 --- a/src/libdramsys/CMakeLists.txt +++ b/src/libdramsys/CMakeLists.txt @@ -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 diff --git a/src/libdramsys/DRAMSys/controller/Controller.cpp b/src/libdramsys/DRAMSys/controller/Controller.cpp index 39598248..9bab626d 100644 --- a/src/libdramsys/DRAMSys/controller/Controller.cpp +++ b/src/libdramsys/DRAMSys/controller/Controller.cpp @@ -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)); diff --git a/src/libdramsys/DRAMSys/simulation/AddressDecoder.cpp b/src/libdramsys/DRAMSys/simulation/AddressDecoder.cpp index e49f2baf..0025138e 100644 --- a/src/libdramsys/DRAMSys/simulation/AddressDecoder.cpp +++ b/src/libdramsys/DRAMSys/simulation/AddressDecoder.cpp @@ -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 #include #include #include #include +#include +#include +#include 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 const& mappingVector, - std::vector& bitVector, - std::vector>& 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> AddressDecoder::transposeMatrix(const std::vector>& matrix) { + size_t size = matrix.size(); + std::vector> 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>& 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(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>(highestBitValue + 1); + upperBoundAddress = std::pow(2, highestBitValue + 1) - 1; + + auto addBitsToMatrix = [&](const std::optional> 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(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(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(*std::max_element(vByteBits.begin(), vByteBits.end())); - - for (unsigned bitPosition = 0; bitPosition <= static_cast(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(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(0); + } + // Create mask + uint64_t mask = (1ULL << component.length) - 1; + // Shift and apply the mask + return static_cast((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(0); + } + // Create mask + uint64_t mask = (1ULL << component.length) - 1; + // Shift and apply the mask + return static_cast((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((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(vChannelBits.size() - 1); it >= 0; it--) - { - uint64_t addressBits = - (UINT64_C(1) << vChannelBits[static_cast::size_type>(it)]); - for (auto xorMapping : vXor) - { - if (xorMapping.at(0) == vChannelBits[static_cast::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(vRankBits.size() - 1); it >= 0; it--) - { - uint64_t addressBits = - (UINT64_C(1) << vRankBits[static_cast::size_type>(it)]); - for (auto xorMapping : vXor) - { - if (xorMapping.at(0) == vRankBits[static_cast::size_type>(it)]) - { - for (auto it = xorMapping.cbegin() + 1; it != xorMapping.cend(); it++) - addressBits |= (UINT64_C(1) << *it); - } + for (int i = 0; i(addressBits) - << std::endl; - } + }; - for (int it = static_cast(vStackBits.size() - 1); it >= 0; it--) - { - uint64_t addressBits = - (UINT64_C(1) << vStackBits[static_cast::size_type>(it)]); - for (auto xorMapping : vXor) - { - if (xorMapping.at(0) == vStackBits[static_cast::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(vBankGroupBits.size() - 1); it >= 0; it--) - { - uint64_t addressBits = - (UINT64_C(1) << vBankGroupBits[static_cast::size_type>(it)]); - for (auto xorMapping : vXor) - { - if (xorMapping.at(0) == - vBankGroupBits[static_cast::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(vBankBits.size() - 1); it >= 0; it--) - { - uint64_t addressBits = - (UINT64_C(1) << vBankBits[static_cast::size_type>(it)]); - for (auto xorMapping : vXor) - { - if (xorMapping.at(0) == vBankBits[static_cast::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(vRowBits.size() - 1); it >= 0; it--) - { - uint64_t addressBits = - (UINT64_C(1) << vRowBits[static_cast::size_type>(it)]); - for (auto xorMapping : vXor) - { - if (xorMapping.at(0) == vRowBits[static_cast::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(vColumnBits.size() - 1); it >= 0; it--) - { - uint64_t addressBits = - (UINT64_C(1) << vColumnBits[static_cast::size_type>(it)]); - for (auto xorMapping : vXor) - { - if (xorMapping.at(0) == vColumnBits[static_cast::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(vByteBits.size() - 1); it >= 0; it--) - { - uint64_t addressBits = - (UINT64_C(1) << vByteBits[static_cast::size_type>(it)]); - for (auto xorMapping : vXor) - { - if (xorMapping.at(0) == vByteBits[static_cast::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 diff --git a/src/libdramsys/DRAMSys/simulation/AddressDecoder.h b/src/libdramsys/DRAMSys/simulation/AddressDecoder.h index b2ab3642..a73ca7a7 100644 --- a/src/libdramsys/DRAMSys/simulation/AddressDecoder.h +++ b/src/libdramsys/DRAMSys/simulation/AddressDecoder.h @@ -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 +#include "DRAMSys/config/AddressMapping.h" #include 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> mappingMatrix; + std::vector> 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> transposeMatrix(const std::vector>& 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>& 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> vXor; - std::vector vChannelBits; - std::vector vRankBits; - std::vector vStackBits; - std::vector vBankGroupBits; - std::vector vBankBits; - std::vector vRowBits; - std::vector vColumnBits; - std::vector vByteBits; }; } // namespace DRAMSys diff --git a/src/libdramsys/DRAMSys/simulation/Arbiter.cpp b/src/libdramsys/DRAMSys/simulation/Arbiter.cpp index b81d1dd1..ef82d4d7 100644 --- a/src/libdramsys/DRAMSys/simulation/Arbiter.cpp +++ b/src/libdramsys/DRAMSys/simulation/Arbiter.cpp @@ -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(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(decodedAddress.channel)]->transport_dbg(trans); } diff --git a/src/simulator/simulator/EccModule.cpp b/src/simulator/simulator/EccModule.cpp index 363cf4c3..c8cf3d16 100644 --- a/src/simulator/simulator/EccModule.cpp +++ b/src/simulator/simulator/EccModule.cpp @@ -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 diff --git a/src/simulator/simulator/Simulator.cpp b/src/simulator/simulator/Simulator.cpp index 369548b0..cf92e8af 100644 --- a/src/simulator/simulator/Simulator.cpp +++ b/src/simulator/simulator/Simulator.cpp @@ -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 { diff --git a/tests/tests_dramsys/AddressDecoderConfigs.h b/tests/tests_dramsys/AddressDecoderConfigs.h index 4f997e93..14eeec31 100644 --- a/tests/tests_dramsys/AddressDecoderConfigs.h +++ b/tests/tests_dramsys/AddressDecoderConfigs.h @@ -35,52 +35,968 @@ #pragma once -#include +#include inline constexpr std::string_view addressMappingJsonString = R"( + { + "addressmapping": { + "BYTE_BIT": [ + 0 + ], + "COLUMN_BIT": [ + 1, + 2, + 3, + 4, + 9, + 10, + 11, + 12, + 13, + 14 + ], + "BANKGROUP_BIT": [ + 5, + 6 + ], + "BANK_BIT": [ + 7, + 8 + ], + "ROW_BIT": [ + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30 + ] + } + } + )"; + +inline constexpr std::string_view validAddressMappingJsonString = R"( + { + "addressmapping": { + "BYTE_BIT": [ + 0, + 1, + 2 + ], + "COLUMN_BIT": [ + 3, + 4, + 5, + 10, + 11, + 12, + 13, + 14, + 15, + 16 + ], + "BANKGROUP_BIT": [ + 6, + 9 + ], + "BANK_BIT": [ + 7, + 8 + ], + "ROW_BIT": [ + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30 + ] + } + } + )"; + +inline constexpr std::string_view validMemSpecJsonString = R"( { - "addressmapping": { - "BYTE_BIT": [ - 0 - ], - "COLUMN_BIT": [ - 1, - 2, - 3, - 4, - 9, - 10, - 11, - 12, - 13, - 14 - ], - "BANKGROUP_BIT": [ - 5, - 6 - ], - "BANK_BIT": [ - 7, - 8 - ], - "ROW_BIT": [ - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30 - ] +"memspec": { + "memarchitecturespec": { + "burstLength": 8, + "dataRate": 2, + "nbrOfBankGroups": 4, + "nbrOfBanks": 16, + "nbrOfColumns": 1024, + "nbrOfRanks": 1, + "nbrOfRows": 16384, + "width": 8, + "nbrOfDevices": 8, + "nbrOfChannels": 1, + "RefMode": 1 + }, + "memoryId": "MICRON_4Gb_DDR4-2400_8bit_A", + "memoryType": "DDR4", + "mempowerspec": { + "vdd": 1.2, + "idd0": 60.75e-3, + "idd2n": 38.25e-3, + "idd3n": 44.0e-3, + "idd4r": 184.5e-3, + "idd4w": 168.75e-3, + "idd6n": 20.25e-3, + "idd2p": 17.0e-3, + "idd3p": 22.5e-3, + + "vpp": 2.5, + "ipp0": 4.05e-3, + "ipp2n": 0, + "ipp3n": 0, + "ipp4r": 0, + "ipp4w": 0, + "ipp6n": 2.6e-3, + "ipp2p": 17.0e-3, + "ipp3p": 22.5e-3, + + "idd5B": 118.0e-3, + "ipp5B": 0.0, + "idd5F2": 0.0, + "ipp5F2": 0.0, + "idd5F4": 0.0, + "ipp5F4": 0.0, + "vddq": 0.0, + + "iBeta_vdd": 60.75e-3, + "iBeta_vpp": 4.05e-3 + }, + "memtimingspec": { + "AL": 0, + "CCD_L": 6, + "CCD_S": 4, + "CKE": 6, + "CKESR": 7, + "CL": 16, + "DQSCK": 2, + "FAW": 26, + "RAS": 39, + "RC": 55, + "RCD": 16, + "REFM": 1, + "REFI": 4680, + "RFC1": 313, + "RFC2": 0, + "RFC4": 0, + "RL": 16, + "RPRE": 1, + "RP": 16, + "RRD_L": 6, + "RRD_S": 4, + "RTP": 12, + "WL": 16, + "WPRE": 1, + "WR": 18, + "WTR_L": 9, + "WTR_S": 3, + "XP": 8, + "XPDLL": 325, + "XS": 324, + "XSDLL": 512, + "ACTPDEN": 2, + "PRPDEN": 2, + "REFPDEN": 2, + "RTRS": 1, + "tCK": 833e-12 + }, + "bankwisespec": { + "factRho": 1.0 + }, + "memimpedancespec": { + "ck_termination": true, + "ck_R_eq": 1e6, + "ck_dyn_E": 1e-12, + + "ca_termination": true, + "ca_R_eq": 1e6, + "ca_dyn_E": 1e-12, + + "rdq_termination": true, + "rdq_R_eq": 1e6, + "rdq_dyn_E": 1e-12, + "wdq_termination": true, + "wdq_R_eq": 1e6, + "wdq_dyn_E": 1e-12, + + "wdqs_termination": true, + "wdqs_R_eq": 1e6, + "wdqs_dyn_E": 1e-12, + "rdqs_termination": true, + "rdqs_R_eq": 1e6, + "rdqs_dyn_E": 1e-12 + }, + "prepostamble": { + "read_zeroes": 0.0, + "write_zeroes": 0.0, + "read_ones": 0.0, + "write_ones": 0.0, + "read_zeroes_to_ones": 0, + "write_zeroes_to_ones": 0, + "write_ones_to_zeroes": 0, + "read_ones_to_zeroes": 0, + "readMinTccd": 0, + "writeMinTccd": 0 + } } } )"; + +inline constexpr std::string_view validNP2MemSpecJsonString = R"( +{ +"memspec": { + "memarchitecturespec": { + "burstLength": 7, + "dataRate": 2, + "nbrOfBankGroups": 4, + "nbrOfBanks": 16, + "nbrOfColumns": 1024, + "nbrOfRanks": 1, + "nbrOfRows": 16384, + "width": 8, + "nbrOfDevices": 7, + "nbrOfChannels": 1, + "RefMode": 1 + }, + "memoryId": "MICRON_4Gb_DDR4-2400_8bit_A", + "memoryType": "DDR4", + "mempowerspec": { + "vdd": 1.2, + "idd0": 60.75e-3, + "idd2n": 38.25e-3, + "idd3n": 44.0e-3, + "idd4r": 184.5e-3, + "idd4w": 168.75e-3, + "idd6n": 20.25e-3, + "idd2p": 17.0e-3, + "idd3p": 22.5e-3, + + "vpp": 2.5, + "ipp0": 4.05e-3, + "ipp2n": 0, + "ipp3n": 0, + "ipp4r": 0, + "ipp4w": 0, + "ipp6n": 2.6e-3, + "ipp2p": 17.0e-3, + "ipp3p": 22.5e-3, + + "idd5B": 118.0e-3, + "ipp5B": 0.0, + "idd5F2": 0.0, + "ipp5F2": 0.0, + "idd5F4": 0.0, + "ipp5F4": 0.0, + "vddq": 0.0, + + "iBeta_vdd": 60.75e-3, + "iBeta_vpp": 4.05e-3 + }, + "memtimingspec": { + "AL": 0, + "CCD_L": 6, + "CCD_S": 4, + "CKE": 6, + "CKESR": 7, + "CL": 16, + "DQSCK": 2, + "FAW": 26, + "RAS": 39, + "RC": 55, + "RCD": 16, + "REFM": 1, + "REFI": 4680, + "RFC1": 313, + "RFC2": 0, + "RFC4": 0, + "RL": 16, + "RPRE": 1, + "RP": 16, + "RRD_L": 6, + "RRD_S": 4, + "RTP": 12, + "WL": 16, + "WPRE": 1, + "WR": 18, + "WTR_L": 9, + "WTR_S": 3, + "XP": 8, + "XPDLL": 325, + "XS": 324, + "XSDLL": 512, + "ACTPDEN": 2, + "PRPDEN": 2, + "REFPDEN": 2, + "RTRS": 1, + "tCK": 833e-12 + }, + "bankwisespec": { + "factRho": 1.0 + }, + "memimpedancespec": { + "ck_termination": true, + "ck_R_eq": 1e6, + "ck_dyn_E": 1e-12, + + "ca_termination": true, + "ca_R_eq": 1e6, + "ca_dyn_E": 1e-12, + + "rdq_termination": true, + "rdq_R_eq": 1e6, + "rdq_dyn_E": 1e-12, + "wdq_termination": true, + "wdq_R_eq": 1e6, + "wdq_dyn_E": 1e-12, + + "wdqs_termination": true, + "wdqs_R_eq": 1e6, + "wdqs_dyn_E": 1e-12, + "rdqs_termination": true, + "rdqs_R_eq": 1e6, + "rdqs_dyn_E": 1e-12 + }, + "prepostamble": { + "read_zeroes": 0.0, + "write_zeroes": 0.0, + "read_ones": 0.0, + "write_ones": 0.0, + "read_zeroes_to_ones": 0, + "write_zeroes_to_ones": 0, + "write_ones_to_zeroes": 0, + "read_ones_to_zeroes": 0, + "readMinTccd": 0, + "writeMinTccd": 0 + } + } +} +)"; + +inline constexpr std::string_view invalidMaxAddressMemSpecJsonString = R"( +{ +"memspec": { + "memarchitecturespec": { + "burstLength": 8, + "dataRate": 2, + "nbrOfBankGroups": 4, + "nbrOfBanks": 16, + "nbrOfColumns": 1024, + "nbrOfRanks": 1, + "nbrOfRows": 16385, + "width": 8, + "nbrOfDevices": 8, + "nbrOfChannels": 1, + "RefMode": 1 + }, + "memoryId": "MICRON_4Gb_DDR4-2400_8bit_A", + "memoryType": "DDR4", + "mempowerspec": { + "vdd": 1.2, + "idd0": 60.75e-3, + "idd2n": 38.25e-3, + "idd3n": 44.0e-3, + "idd4r": 184.5e-3, + "idd4w": 168.75e-3, + "idd6n": 20.25e-3, + "idd2p": 17.0e-3, + "idd3p": 22.5e-3, + + "vpp": 2.5, + "ipp0": 4.05e-3, + "ipp2n": 0, + "ipp3n": 0, + "ipp4r": 0, + "ipp4w": 0, + "ipp6n": 2.6e-3, + "ipp2p": 17.0e-3, + "ipp3p": 22.5e-3, + + "idd5B": 118.0e-3, + "ipp5B": 0.0, + "idd5F2": 0.0, + "ipp5F2": 0.0, + "idd5F4": 0.0, + "ipp5F4": 0.0, + "vddq": 0.0, + + "iBeta_vdd": 60.75e-3, + "iBeta_vpp": 4.05e-3 + }, + "memtimingspec": { + "AL": 0, + "CCD_L": 6, + "CCD_S": 4, + "CKE": 6, + "CKESR": 7, + "CL": 16, + "DQSCK": 2, + "FAW": 26, + "RAS": 39, + "RC": 55, + "RCD": 16, + "REFM": 1, + "REFI": 4680, + "RFC1": 313, + "RFC2": 0, + "RFC4": 0, + "RL": 16, + "RPRE": 1, + "RP": 16, + "RRD_L": 6, + "RRD_S": 4, + "RTP": 12, + "WL": 16, + "WPRE": 1, + "WR": 18, + "WTR_L": 9, + "WTR_S": 3, + "XP": 8, + "XPDLL": 325, + "XS": 324, + "XSDLL": 512, + "ACTPDEN": 2, + "PRPDEN": 2, + "REFPDEN": 2, + "RTRS": 1, + "tCK": 833e-12 + }, + "bankwisespec": { + "factRho": 1.0 + }, + "memimpedancespec": { + "ck_termination": true, + "ck_R_eq": 1e6, + "ck_dyn_E": 1e-12, + + "ca_termination": true, + "ca_R_eq": 1e6, + "ca_dyn_E": 1e-12, + + "rdq_termination": true, + "rdq_R_eq": 1e6, + "rdq_dyn_E": 1e-12, + "wdq_termination": true, + "wdq_R_eq": 1e6, + "wdq_dyn_E": 1e-12, + + "wdqs_termination": true, + "wdqs_R_eq": 1e6, + "wdqs_dyn_E": 1e-12, + "rdqs_termination": true, + "rdqs_R_eq": 1e6, + "rdqs_dyn_E": 1e-12 + }, + "prepostamble": { + "read_zeroes": 0.0, + "write_zeroes": 0.0, + "read_ones": 0.0, + "write_ones": 0.0, + "read_zeroes_to_ones": 0, + "write_zeroes_to_ones": 0, + "write_ones_to_zeroes": 0, + "read_ones_to_zeroes": 0, + "readMinTccd": 0, + "writeMinTccd": 0 + } + } +} +)"; + +inline constexpr std::string_view addressMappingWithDuplicatesJsonString = R"( + { + "addressmapping": { + "BYTE_BIT": [ + 0, + 1, + 2 + ], + "COLUMN_BIT": [ + 3, + 4, + 5, + 3, + 10, + 11 + ], + "BANKGROUP_BIT": [ + 6, + 9 + ], + "BANK_BIT": [ + 7, + 8 + ], + "ROW_BIT": [ + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30 + ] + } + } + )"; + +inline constexpr std::string_view nonContinuousByteBitsAddressMappingJsonString = R"( + { + "addressmapping": { + "BYTE_BIT": [ + 0, + 1, + 3 + ], + "COLUMN_BIT": [ + 2, + 4, + 5, + 10, + 11, + 12 + ], + "BANKGROUP_BIT": [ + 6, + 9 + ], + "BANK_BIT": [ + 7, + 8 + ], + "ROW_BIT": [ + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30 + ] + } + } + )"; + +inline constexpr std::string_view invalidChannelMemSpecJsonString = R"( +{ +"memspec": { + "memarchitecturespec": { + "burstLength": 8, + "dataRate": 2, + "nbrOfBankGroups": 4, + "nbrOfBanks": 8, + "nbrOfColumns": 1024, + "nbrOfRanks": 1, + "nbrOfRows": 16384, + "width": 8, + "nbrOfDevices": 8, + "nbrOfChannels": 2, + "RefMode": 1 + }, + "memoryId": "MICRON_4Gb_DDR4-2400_8bit_A", + "memoryType": "DDR4", + "mempowerspec": { + "vdd": 1.2, + "idd0": 60.75e-3, + "idd2n": 38.25e-3, + "idd3n": 44.0e-3, + "idd4r": 184.5e-3, + "idd4w": 168.75e-3, + "idd6n": 20.25e-3, + "idd2p": 17.0e-3, + "idd3p": 22.5e-3, + + "vpp": 2.5, + "ipp0": 4.05e-3, + "ipp2n": 0, + "ipp3n": 0, + "ipp4r": 0, + "ipp4w": 0, + "ipp6n": 2.6e-3, + "ipp2p": 17.0e-3, + "ipp3p": 22.5e-3, + + "idd5B": 118.0e-3, + "ipp5B": 0.0, + "idd5F2": 0.0, + "ipp5F2": 0.0, + "idd5F4": 0.0, + "ipp5F4": 0.0, + "vddq": 0.0, + + "iBeta_vdd": 60.75e-3, + "iBeta_vpp": 4.05e-3 + }, + "memtimingspec": { + "AL": 0, + "CCD_L": 6, + "CCD_S": 4, + "CKE": 6, + "CKESR": 7, + "CL": 16, + "DQSCK": 2, + "FAW": 26, + "RAS": 39, + "RC": 55, + "RCD": 16, + "REFM": 1, + "REFI": 4680, + "RFC1": 313, + "RFC2": 0, + "RFC4": 0, + "RL": 16, + "RPRE": 1, + "RP": 16, + "RRD_L": 6, + "RRD_S": 4, + "RTP": 12, + "WL": 16, + "WPRE": 1, + "WR": 18, + "WTR_L": 9, + "WTR_S": 3, + "XP": 8, + "XPDLL": 325, + "XS": 324, + "XSDLL": 512, + "ACTPDEN": 2, + "PRPDEN": 2, + "REFPDEN": 2, + "RTRS": 1, + "tCK": 833e-12 + }, + "bankwisespec": { + "factRho": 1.0 + }, + "memimpedancespec": { + "ck_termination": true, + "ck_R_eq": 1e6, + "ck_dyn_E": 1e-12, + + "ca_termination": true, + "ca_R_eq": 1e6, + "ca_dyn_E": 1e-12, + + "rdq_termination": true, + "rdq_R_eq": 1e6, + "rdq_dyn_E": 1e-12, + "wdq_termination": true, + "wdq_R_eq": 1e6, + "wdq_dyn_E": 1e-12, + + "wdqs_termination": true, + "wdqs_R_eq": 1e6, + "wdqs_dyn_E": 1e-12, + "rdqs_termination": true, + "rdqs_R_eq": 1e6, + "rdqs_dyn_E": 1e-12 + }, + "prepostamble": { + "read_zeroes": 0.0, + "write_zeroes": 0.0, + "read_ones": 0.0, + "write_ones": 0.0, + "read_zeroes_to_ones": 0, + "write_zeroes_to_ones": 0, + "write_ones_to_zeroes": 0, + "read_ones_to_zeroes": 0, + "readMinTccd": 0, + "writeMinTccd": 0 + } + } +} +)"; + +inline constexpr std::string_view invalidBankGroupMemSpecJsonString = R"( + { + "memspec": { + "memarchitecturespec": { + "burstLength": 8, + "dataRate": 2, + "nbrOfBankGroups": 8, + "nbrOfBanks": 8, + "nbrOfColumns": 1024, + "nbrOfRanks": 1, + "nbrOfRows": 16384, + "width": 8, + "nbrOfDevices": 8, + "nbrOfChannels": 1, + "RefMode": 1 + }, + "memoryId": "MICRON_4Gb_DDR4-2400_8bit_A", + "memoryType": "DDR4", + "mempowerspec": { + "vdd": 1.2, + "idd0": 60.75e-3, + "idd2n": 38.25e-3, + "idd3n": 44.0e-3, + "idd4r": 184.5e-3, + "idd4w": 168.75e-3, + "idd6n": 20.25e-3, + "idd2p": 17.0e-3, + "idd3p": 22.5e-3, + + "vpp": 2.5, + "ipp0": 4.05e-3, + "ipp2n": 0, + "ipp3n": 0, + "ipp4r": 0, + "ipp4w": 0, + "ipp6n": 2.6e-3, + "ipp2p": 17.0e-3, + "ipp3p": 22.5e-3, + + "idd5B": 118.0e-3, + "ipp5B": 0.0, + "idd5F2": 0.0, + "ipp5F2": 0.0, + "idd5F4": 0.0, + "ipp5F4": 0.0, + "vddq": 0.0, + + "iBeta_vdd": 60.75e-3, + "iBeta_vpp": 4.05e-3 + }, + "memtimingspec": { + "AL": 0, + "CCD_L": 6, + "CCD_S": 4, + "CKE": 6, + "CKESR": 7, + "CL": 16, + "DQSCK": 2, + "FAW": 26, + "RAS": 39, + "RC": 55, + "RCD": 16, + "REFM": 1, + "REFI": 4680, + "RFC1": 313, + "RFC2": 0, + "RFC4": 0, + "RL": 16, + "RPRE": 1, + "RP": 16, + "RRD_L": 6, + "RRD_S": 4, + "RTP": 12, + "WL": 16, + "WPRE": 1, + "WR": 18, + "WTR_L": 9, + "WTR_S": 3, + "XP": 8, + "XPDLL": 325, + "XS": 324, + "XSDLL": 512, + "ACTPDEN": 2, + "PRPDEN": 2, + "REFPDEN": 2, + "RTRS": 1, + "tCK": 833e-12 + }, + "bankwisespec": { + "factRho": 1.0 + }, + "memimpedancespec": { + "ck_termination": true, + "ck_R_eq": 1e6, + "ck_dyn_E": 1e-12, + + "ca_termination": true, + "ca_R_eq": 1e6, + "ca_dyn_E": 1e-12, + + "rdq_termination": true, + "rdq_R_eq": 1e6, + "rdq_dyn_E": 1e-12, + "wdq_termination": true, + "wdq_R_eq": 1e6, + "wdq_dyn_E": 1e-12, + + "wdqs_termination": true, + "wdqs_R_eq": 1e6, + "wdqs_dyn_E": 1e-12, + "rdqs_termination": true, + "rdqs_R_eq": 1e6, + "rdqs_dyn_E": 1e-12 + }, + "prepostamble": { + "read_zeroes": 0.0, + "write_zeroes": 0.0, + "read_ones": 0.0, + "write_ones": 0.0, + "read_zeroes_to_ones": 0, + "write_zeroes_to_ones": 0, + "write_ones_to_zeroes": 0, + "read_ones_to_zeroes": 0, + "readMinTccd": 0, + "writeMinTccd": 0 + } + } + } + )"; + + inline constexpr std::string_view invalidRanksMemSpecJsonString = R"( + { + "memspec": { + "memarchitecturespec": { + "burstLength": 8, + "dataRate": 2, + "nbrOfBankGroups": 2, + "nbrOfBanks": 8, + "nbrOfColumns": 1024, + "nbrOfRanks": 2, + "nbrOfRows": 16384, + "width": 8, + "nbrOfDevices": 8, + "nbrOfChannels": 1, + "RefMode": 1 + }, + "memoryId": "MICRON_4Gb_DDR4-2400_8bit_A", + "memoryType": "DDR4", + "mempowerspec": { + "vdd": 1.2, + "idd0": 60.75e-3, + "idd2n": 38.25e-3, + "idd3n": 44.0e-3, + "idd4r": 184.5e-3, + "idd4w": 168.75e-3, + "idd6n": 20.25e-3, + "idd2p": 17.0e-3, + "idd3p": 22.5e-3, + + "vpp": 2.5, + "ipp0": 4.05e-3, + "ipp2n": 0, + "ipp3n": 0, + "ipp4r": 0, + "ipp4w": 0, + "ipp6n": 2.6e-3, + "ipp2p": 17.0e-3, + "ipp3p": 22.5e-3, + + "idd5B": 118.0e-3, + "ipp5B": 0.0, + "idd5F2": 0.0, + "ipp5F2": 0.0, + "idd5F4": 0.0, + "ipp5F4": 0.0, + "vddq": 0.0, + + "iBeta_vdd": 60.75e-3, + "iBeta_vpp": 4.05e-3 + }, + "memtimingspec": { + "AL": 0, + "CCD_L": 6, + "CCD_S": 4, + "CKE": 6, + "CKESR": 7, + "CL": 16, + "DQSCK": 2, + "FAW": 26, + "RAS": 39, + "RC": 55, + "RCD": 16, + "REFM": 1, + "REFI": 4680, + "RFC1": 313, + "RFC2": 0, + "RFC4": 0, + "RL": 16, + "RPRE": 1, + "RP": 16, + "RRD_L": 6, + "RRD_S": 4, + "RTP": 12, + "WL": 16, + "WPRE": 1, + "WR": 18, + "WTR_L": 9, + "WTR_S": 3, + "XP": 8, + "XPDLL": 325, + "XS": 324, + "XSDLL": 512, + "ACTPDEN": 2, + "PRPDEN": 2, + "REFPDEN": 2, + "RTRS": 1, + "tCK": 833e-12 + }, + "bankwisespec": { + "factRho": 1.0 + }, + "memimpedancespec": { + "ck_termination": true, + "ck_R_eq": 1e6, + "ck_dyn_E": 1e-12, + + "ca_termination": true, + "ca_R_eq": 1e6, + "ca_dyn_E": 1e-12, + + "rdq_termination": true, + "rdq_R_eq": 1e6, + "rdq_dyn_E": 1e-12, + "wdq_termination": true, + "wdq_R_eq": 1e6, + "wdq_dyn_E": 1e-12, + + "wdqs_termination": true, + "wdqs_R_eq": 1e6, + "wdqs_dyn_E": 1e-12, + "rdqs_termination": true, + "rdqs_R_eq": 1e6, + "rdqs_dyn_E": 1e-12 + }, + "prepostamble": { + "read_zeroes": 0.0, + "write_zeroes": 0.0, + "read_ones": 0.0, + "write_ones": 0.0, + "read_zeroes_to_ones": 0, + "write_zeroes_to_ones": 0, + "write_ones_to_zeroes": 0, + "read_ones_to_zeroes": 0, + "readMinTccd": 0, + "writeMinTccd": 0 + } + } + } + )"; \ No newline at end of file diff --git a/tests/tests_dramsys/AddressDecoderTests.cpp b/tests/tests_dramsys/AddressDecoderTests.cpp index dd5c6ade..fbbece0e 100644 --- a/tests/tests_dramsys/AddressDecoderTests.cpp +++ b/tests/tests_dramsys/AddressDecoderTests.cpp @@ -35,11 +35,14 @@ #include "AddressDecoderConfigs.h" -#include +#include "gtest/gtest-spi.h" #include #include +#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()); + + auto memSpec = std::make_unique( + 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()); + + auto memSpec = std::make_unique( + 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 addressDecoder = nullptr; + std::unique_ptr 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(memSpec); + + DRAMSys::Config::AddressMapping addressMappingConfig = + nlohmann::json::parse(addressMappingJson) + .at("addressmapping") + .get(); + addressDecoder = std::make_unique(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), ""); +}