Merge branch 'feat/addr_dec_matrix' into 'develop'
Feature: Rewrote AddressDecoder See merge request ems/astdm/modeling.dram/dram.sys.5!131
This commit is contained in:
@@ -52,11 +52,12 @@ static DRAMSys::AddressDecoder addressDecoder()
|
|||||||
static void addressdecoder_decode(benchmark::State& state)
|
static void addressdecoder_decode(benchmark::State& state)
|
||||||
{
|
{
|
||||||
auto decoder = addressDecoder();
|
auto decoder = addressDecoder();
|
||||||
|
tlm::tlm_generic_payload trans;
|
||||||
|
trans.set_address(0x0);
|
||||||
for (auto _ : state)
|
for (auto _ : state)
|
||||||
{
|
{
|
||||||
// Actual address has no significant impact on performance
|
// Actual address has no significant impact on performance
|
||||||
auto decodedAddress = decoder.decodeAddress(0x0);
|
auto decodedAddress = decoder.decodeAddress(trans);
|
||||||
benchmark::DoNotOptimize(decodedAddress);
|
benchmark::DoNotOptimize(decodedAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,37 @@ struct AddressMapping
|
|||||||
std::optional<std::vector<BitEntry>> STACK_BIT;
|
std::optional<std::vector<BitEntry>> STACK_BIT;
|
||||||
std::optional<std::vector<BitEntry>> PSEUDOCHANNEL_BIT;
|
std::optional<std::vector<BitEntry>> PSEUDOCHANNEL_BIT;
|
||||||
std::optional<std::vector<BitEntry>> CHANNEL_BIT;
|
std::optional<std::vector<BitEntry>> CHANNEL_BIT;
|
||||||
|
|
||||||
|
unsigned int getHighestBit() const {
|
||||||
|
unsigned int highestBit = std::numeric_limits<unsigned int>::min();
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
auto checkAndUpdate = [&](const std::optional<std::vector<BitEntry>>& bits) {
|
||||||
|
if (bits) {
|
||||||
|
for (const auto& vector : *bits) {
|
||||||
|
for (const auto& bit : vector) {
|
||||||
|
if (bit > highestBit) {
|
||||||
|
highestBit = bit;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
checkAndUpdate(BYTE_BIT);
|
||||||
|
checkAndUpdate(COLUMN_BIT);
|
||||||
|
checkAndUpdate(ROW_BIT);
|
||||||
|
checkAndUpdate(BANK_BIT);
|
||||||
|
checkAndUpdate(BANKGROUP_BIT);
|
||||||
|
checkAndUpdate(RANK_BIT);
|
||||||
|
checkAndUpdate(STACK_BIT);
|
||||||
|
checkAndUpdate(PSEUDOCHANNEL_BIT);
|
||||||
|
checkAndUpdate(CHANNEL_BIT);
|
||||||
|
|
||||||
|
return found ? highestBit : std::numeric_limits<unsigned int>::min(); // Rückgabe des höchsten Wertes oder des minimalen Wertes
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
NLOHMANN_JSONIFY_ALL_THINGS(AddressMapping,
|
NLOHMANN_JSONIFY_ALL_THINGS(AddressMapping,
|
||||||
|
|||||||
@@ -36,6 +36,14 @@
|
|||||||
### DRAMSys::libdramsys ###
|
### DRAMSys::libdramsys ###
|
||||||
########################################
|
########################################
|
||||||
|
|
||||||
|
# Add AVX-512 flag
|
||||||
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
|
message("Enabling GFNI support")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
|
||||||
|
elseif(MSVC)
|
||||||
|
# Für MSVC können Sie entsprechende Optionen hinzufügen, falls erforderlich
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(libdramsys
|
add_library(libdramsys
|
||||||
DRAMSys/common/DebugManager.cpp
|
DRAMSys/common/DebugManager.cpp
|
||||||
DRAMSys/common/TlmRecorder.cpp
|
DRAMSys/common/TlmRecorder.cpp
|
||||||
|
|||||||
@@ -598,8 +598,8 @@ void Controller::manageRequests(const sc_time& delay)
|
|||||||
transToAcquire.payload->acquire();
|
transToAcquire.payload->acquire();
|
||||||
|
|
||||||
// The following logic assumes that transactions are naturally aligned
|
// The following logic assumes that transactions are naturally aligned
|
||||||
uint64_t address = transToAcquire.payload->get_address();
|
const uint64_t address = transToAcquire.payload->get_address();
|
||||||
[[maybe_unused]] uint64_t dataLength = transToAcquire.payload->get_data_length();
|
const uint64_t dataLength = transToAcquire.payload->get_data_length();
|
||||||
assert((dataLength & (dataLength - 1)) == 0); // Data length must be a power of 2
|
assert((dataLength & (dataLength - 1)) == 0); // Data length must be a power of 2
|
||||||
assert(address % dataLength == 0); // Check if naturally aligned
|
assert(address % dataLength == 0); // Check if naturally aligned
|
||||||
|
|
||||||
@@ -608,7 +608,7 @@ void Controller::manageRequests(const sc_time& delay)
|
|||||||
{
|
{
|
||||||
// continuous block of data that can be fetched with a single burst
|
// continuous block of data that can be fetched with a single burst
|
||||||
DecodedAddress decodedAddress =
|
DecodedAddress decodedAddress =
|
||||||
addressDecoder.decodeAddress(transToAcquire.payload->get_address());
|
addressDecoder.decodeAddress(*transToAcquire.payload);
|
||||||
ControllerExtension::setAutoExtension(
|
ControllerExtension::setAutoExtension(
|
||||||
*transToAcquire.payload,
|
*transToAcquire.payload,
|
||||||
nextChannelPayloadIDToAppend++,
|
nextChannelPayloadIDToAppend++,
|
||||||
@@ -807,7 +807,7 @@ void Controller::createChildTranses(tlm::tlm_generic_payload& parentTrans)
|
|||||||
|
|
||||||
for (auto* childTrans : childTranses)
|
for (auto* childTrans : childTranses)
|
||||||
{
|
{
|
||||||
DecodedAddress decodedAddress = addressDecoder.decodeAddress(childTrans->get_address());
|
DecodedAddress decodedAddress = addressDecoder.decodeAddress(*childTrans);
|
||||||
ControllerExtension::setAutoExtension(*childTrans,
|
ControllerExtension::setAutoExtension(*childTrans,
|
||||||
nextChannelPayloadIDToAppend,
|
nextChannelPayloadIDToAppend,
|
||||||
Rank(decodedAddress.rank),
|
Rank(decodedAddress.rank),
|
||||||
@@ -816,8 +816,7 @@ void Controller::createChildTranses(tlm::tlm_generic_payload& parentTrans)
|
|||||||
Bank(decodedAddress.bank),
|
Bank(decodedAddress.bank),
|
||||||
Row(decodedAddress.row),
|
Row(decodedAddress.row),
|
||||||
Column(decodedAddress.column),
|
Column(decodedAddress.column),
|
||||||
(childTrans->get_data_length() * 8) /
|
memSpec.maxBurstLength);
|
||||||
memSpec.dataBusWidth);
|
|
||||||
}
|
}
|
||||||
nextChannelPayloadIDToAppend++;
|
nextChannelPayloadIDToAppend++;
|
||||||
ParentExtension::setExtension(parentTrans, std::move(childTranses));
|
ParentExtension::setExtension(parentTrans, std::move(childTranses));
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, RPTU Kaiserslautern-Landau
|
* Copyright (c) 2025, RPTU Kaiserslautern-Landau
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -34,288 +34,416 @@
|
|||||||
* Lukas Steiner
|
* Lukas Steiner
|
||||||
* Luiza Correa
|
* Luiza Correa
|
||||||
* Derek Christ
|
* Derek Christ
|
||||||
|
* Thomas Zimmermann
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "AddressDecoder.h"
|
#include "AddressDecoder.h"
|
||||||
#include "DRAMSys/config/AddressMapping.h"
|
#include "DRAMSys/config/AddressMapping.h"
|
||||||
|
|
||||||
|
#include <bit>
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <immintrin.h>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
namespace DRAMSys
|
namespace DRAMSys
|
||||||
{
|
{
|
||||||
|
/********************/
|
||||||
|
/* Helper Functions */
|
||||||
|
/********************/
|
||||||
|
/**
|
||||||
|
* @brief Creates a bitmask and stores it in a uint64_t.
|
||||||
|
*
|
||||||
|
* @param numBits The number of bits to set to 1.
|
||||||
|
* @param startIndex The index of the first bit to set to 1.
|
||||||
|
* @return result The uint64_t where the bitmask will be stored.
|
||||||
|
*/
|
||||||
|
uint64_t createBitmask(unsigned numBits, unsigned startIndex) {
|
||||||
|
// Create the mask by shifting 1's to the correct position
|
||||||
|
return ((UINT64_C(1) << numBits) - 1) << startIndex;
|
||||||
|
}
|
||||||
|
|
||||||
static void addMapping(std::vector<Config::AddressMapping::BitEntry> const& mappingVector,
|
std::vector<std::bitset<64>> AddressDecoder::transposeMatrix(const std::vector<std::bitset<64>>& matrix) {
|
||||||
std::vector<unsigned>& bitVector,
|
size_t size = matrix.size();
|
||||||
std::vector<std::vector<unsigned>>& xorVector)
|
std::vector<std::bitset<64>> transposedMatrix(size);
|
||||||
{
|
|
||||||
for (const Config::AddressMapping::BitEntry& bitEntry : mappingVector)
|
for (size_t i = 0; i < size; ++i) {
|
||||||
{
|
for (size_t j = 0; j < 64; ++j) {
|
||||||
if (bitEntry.get_type() == Config::AddressMapping::BitEntry::Type::SINGLE) {
|
if (matrix[i].test(j))
|
||||||
bitVector.push_back(bitEntry.at(0));
|
transposedMatrix[j].set(i);
|
||||||
} else {
|
|
||||||
bitVector.push_back(bitEntry.at(0));
|
|
||||||
xorVector.push_back(bitEntry);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return transposedMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddressDecoder::AddressDecoder(const Config::AddressMapping& addressMapping)
|
uint64_t AddressDecoder::gf2Multiplication(const uint64_t& inputVec, const std::vector<std::bitset<64>>& matrix) const
|
||||||
{
|
{
|
||||||
if (const auto& channelBits = addressMapping.CHANNEL_BIT)
|
#if defined(__clang__) || defined(__GNUC__)
|
||||||
{
|
uint64_t result = 0;
|
||||||
addMapping(*channelBits, vChannelBits, vXor);
|
for (size_t i = 0; i < matrix.size(); ++i) {
|
||||||
}
|
uint64_t row = matrix[i].to_ullong();
|
||||||
|
uint64_t val = inputVec & row;
|
||||||
|
bool parity = __builtin_parityll(val);
|
||||||
|
result |= (uint64_t(parity) << i);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
#else
|
||||||
|
std::bitset<64> resultBits;
|
||||||
|
std::bitset<64> inputBits(inputVec);
|
||||||
|
|
||||||
if (const auto& rankBits = addressMapping.RANK_BIT)
|
for (size_t i = 0; i < matrix.size(); ++i) {
|
||||||
{
|
resultBits[i] = (inputBits & matrix[i]).count() % 2;
|
||||||
addMapping(*rankBits, vRankBits, vXor);
|
}
|
||||||
}
|
return resultBits.to_ullong();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (const auto& stackBits = addressMapping.STACK_BIT)
|
// Print input, mapping matrix and output in a readable way (useful for debugging)
|
||||||
{
|
// std::cout << "Vec " << ":\t" << std::bitset<64>(vector[0]) << std::endl << std::endl;
|
||||||
addMapping(*stackBits, vStackBits, vXor);
|
// for (size_t i = 0; i < mappingMatrix.size(); ++i) {
|
||||||
}
|
// std::cout << "Row " << i << ":\t" << mappingMatrix[i] << " | " << resultBits[i] << std::endl;
|
||||||
|
// }
|
||||||
// HBM pseudo channels are internally modelled as ranks
|
|
||||||
if (const auto& pseudoChannelBits = addressMapping.PSEUDOCHANNEL_BIT)
|
|
||||||
{
|
|
||||||
addMapping(*pseudoChannelBits, vRankBits, vXor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const auto& bankGroupBits = addressMapping.BANKGROUP_BIT)
|
|
||||||
{
|
|
||||||
addMapping(*bankGroupBits, vBankGroupBits, vXor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const auto& byteBits = addressMapping.BYTE_BIT)
|
|
||||||
{
|
|
||||||
addMapping(*byteBits, vByteBits, vXor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const auto& bankBits = addressMapping.BANK_BIT)
|
|
||||||
{
|
|
||||||
addMapping(*bankBits, vBankBits, vXor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const auto& rowBits = addressMapping.ROW_BIT)
|
|
||||||
{
|
|
||||||
addMapping(*rowBits, vRowBits, vXor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const auto& columnBits = addressMapping.COLUMN_BIT)
|
|
||||||
{
|
|
||||||
addMapping(*columnBits, vColumnBits, vXor);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned channels = std::lround(std::pow(2.0, vChannelBits.size()));
|
|
||||||
unsigned ranks = std::lround(std::pow(2.0, vRankBits.size()));
|
|
||||||
unsigned stacks = std::lround(std::pow(2.0, vStackBits.size()));
|
|
||||||
unsigned bankGroups = std::lround(std::pow(2.0, vBankGroupBits.size()));
|
|
||||||
unsigned banks = std::lround(std::pow(2.0, vBankBits.size()));
|
|
||||||
unsigned rows = std::lround(std::pow(2.0, vRowBits.size()));
|
|
||||||
unsigned columns = std::lround(std::pow(2.0, vColumnBits.size()));
|
|
||||||
unsigned bytes = std::lround(std::pow(2.0, vByteBits.size()));
|
|
||||||
|
|
||||||
maximumAddress = static_cast<uint64_t>(bytes) * columns * rows * banks * bankGroups * stacks *
|
|
||||||
ranks * channels -
|
|
||||||
1;
|
|
||||||
|
|
||||||
bankgroupsPerRank = bankGroups;
|
|
||||||
banksPerGroup = banks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************/
|
||||||
|
/* AddressDecoder Functions */
|
||||||
|
/****************************/
|
||||||
|
|
||||||
|
AddressDecoder::AddressDecoder(const DRAMSys::Config::AddressMapping& addressMapping) :
|
||||||
|
highestBitValue(addressMapping.getHighestBit())
|
||||||
|
{
|
||||||
|
mappingMatrix = std::vector<std::bitset<64>>(highestBitValue + 1);
|
||||||
|
upperBoundAddress = std::pow(2, highestBitValue + 1) - 1;
|
||||||
|
|
||||||
|
auto addBitsToMatrix = [&](const std::optional<std::vector<Config::AddressMapping::BitEntry>> bits, int *rowIndex, std::string_view name)
|
||||||
|
{
|
||||||
|
if (!bits.has_value())
|
||||||
|
return AddressComponent(-1, 0, name);
|
||||||
|
for (auto row : bits.value()) {
|
||||||
|
for (unsigned int bit : row) {
|
||||||
|
mappingMatrix[*rowIndex][bit] = true;
|
||||||
|
}
|
||||||
|
(*rowIndex)++;
|
||||||
|
}
|
||||||
|
// Care: The rowIndex has been changed. We want the lowest bit, so we must subtract the length!
|
||||||
|
return AddressComponent(*rowIndex - bits.value().size(), bits.value().size(), name);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int rowIndex = 0;
|
||||||
|
byteBits = addBitsToMatrix(addressMapping.BYTE_BIT, &rowIndex, "By");
|
||||||
|
columnBits = addBitsToMatrix(addressMapping.COLUMN_BIT, &rowIndex, "Co");
|
||||||
|
bankGroupBits = addBitsToMatrix(addressMapping.BANKGROUP_BIT, &rowIndex, "BG");
|
||||||
|
bankBits = addBitsToMatrix(addressMapping.BANK_BIT, &rowIndex, "Ba");
|
||||||
|
rowBits = addBitsToMatrix(addressMapping.ROW_BIT, &rowIndex, "Ro");
|
||||||
|
pseudochannelBits = addBitsToMatrix(addressMapping.PSEUDOCHANNEL_BIT, &rowIndex, "PC");
|
||||||
|
channelBits = addBitsToMatrix(addressMapping.CHANNEL_BIT, &rowIndex, "Ch");
|
||||||
|
rankBits = addBitsToMatrix(addressMapping.RANK_BIT, &rowIndex, "Ra");
|
||||||
|
stackBits = addBitsToMatrix(addressMapping.STACK_BIT, &rowIndex, "St");
|
||||||
|
transposedMappingMatrix = transposeMatrix(mappingMatrix);
|
||||||
|
|
||||||
|
bankgroupsPerRank = std::lround(std::pow(2.0, bankGroupBits.length));
|
||||||
|
banksPerGroup = std::lround(std::pow(2.0, bankBits.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void AddressDecoder::plausibilityCheck(const MemSpec& memSpec)
|
void AddressDecoder::plausibilityCheck(const MemSpec& memSpec)
|
||||||
{
|
{
|
||||||
unsigned channels = std::lround(std::pow(2.0, vChannelBits.size()));
|
(*this).memSpec = &memSpec;
|
||||||
unsigned ranks = std::lround(std::pow(2.0, vRankBits.size()));
|
np2Flag = not allComponentsArePowerOfTwo(memSpec);
|
||||||
unsigned stacks = std::lround(std::pow(2.0, vStackBits.size()));
|
|
||||||
unsigned bankGroups = std::lround(std::pow(2.0, vBankGroupBits.size()));
|
|
||||||
unsigned banks = std::lround(std::pow(2.0, vBankBits.size()));
|
|
||||||
unsigned rows = std::lround(std::pow(2.0, vRowBits.size()));
|
|
||||||
unsigned columns = std::lround(std::pow(2.0, vColumnBits.size()));
|
|
||||||
unsigned bytes = std::lround(std::pow(2.0, vByteBits.size()));
|
|
||||||
|
|
||||||
maximumAddress = static_cast<uint64_t>(bytes) * columns * rows * banks * bankGroups * stacks *
|
// Check if all address bits are used
|
||||||
ranks * channels -
|
// TODO: Check if every bit occurs ~exactly~ once or just at least once?
|
||||||
1;
|
std::bitset<64> orBitset(0);
|
||||||
|
for (auto bitset: mappingMatrix) {
|
||||||
|
orBitset |= bitset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
auto totalAddressBits = static_cast<unsigned>(std::log2(maximumAddress));
|
std::bitset<64> mask((1ULL << (highestBitValue + 1)) - 1);
|
||||||
for (unsigned bitPosition = 0; bitPosition < totalAddressBits; bitPosition++)
|
if (orBitset != mask) {
|
||||||
{
|
SC_REPORT_FATAL("AddressDecoder", "Not all address bits are used");
|
||||||
if (std::count(vChannelBits.begin(), vChannelBits.end(), bitPosition) +
|
|
||||||
std::count(vRankBits.begin(), vRankBits.end(), bitPosition) +
|
|
||||||
std::count(vStackBits.begin(), vStackBits.end(), bitPosition) +
|
|
||||||
std::count(vBankGroupBits.begin(), vBankGroupBits.end(), bitPosition) +
|
|
||||||
std::count(vBankBits.begin(), vBankBits.end(), bitPosition) +
|
|
||||||
std::count(vRowBits.begin(), vRowBits.end(), bitPosition) +
|
|
||||||
std::count(vColumnBits.begin(), vColumnBits.end(), bitPosition) +
|
|
||||||
std::count(vByteBits.begin(), vByteBits.end(), bitPosition) !=
|
|
||||||
1)
|
|
||||||
SC_REPORT_FATAL("AddressDecoder", "Not all address bits occur exactly once");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int highestByteBit = -1;
|
// Check if the byte bits are continous and starting from 0
|
||||||
|
uint64_t row = 0;
|
||||||
if (!vByteBits.empty())
|
for (size_t i = 0; i < byteBits.length; i++) {
|
||||||
{
|
row |= mappingMatrix[byteBits.idx + i].to_ullong();
|
||||||
highestByteBit = static_cast<int>(*std::max_element(vByteBits.begin(), vByteBits.end()));
|
}
|
||||||
|
if (row != ((1ULL << byteBits.length) - 1)) {
|
||||||
for (unsigned bitPosition = 0; bitPosition <= static_cast<unsigned>(highestByteBit);
|
SC_REPORT_FATAL("AddressDecoder", "Not all address bits occur exactly once");
|
||||||
bitPosition++)
|
|
||||||
{
|
|
||||||
if (std::find(vByteBits.begin(), vByteBits.end(), bitPosition) == vByteBits.end())
|
|
||||||
SC_REPORT_FATAL("AddressDecoder", "Byte bits are not continuous starting from 0");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto maxBurstLengthBits = static_cast<unsigned>(std::log2(memSpec.maxBurstLength));
|
// Check if the addresss mapping is capable of matching the requirements of the memSpec
|
||||||
|
checkMemSpecCompatibility(memSpec);
|
||||||
for (unsigned bitPosition = highestByteBit + 1;
|
checkMemorySize(memSpec);
|
||||||
bitPosition < highestByteBit + 1 + maxBurstLengthBits;
|
checkByteBits(memSpec);
|
||||||
bitPosition++)
|
checkBurstLengthBits(memSpec);
|
||||||
{
|
|
||||||
if (std::find(vColumnBits.begin(), vColumnBits.end(), bitPosition) == vColumnBits.end())
|
|
||||||
SC_REPORT_FATAL("AddressDecoder", "No continuous column bits for maximum burst length");
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned absoluteBankGroups = bankgroupsPerRank * ranks;
|
|
||||||
unsigned absoluteBanks = banksPerGroup * absoluteBankGroups;
|
|
||||||
|
|
||||||
if (memSpec.numberOfChannels != channels || memSpec.ranksPerChannel != ranks ||
|
|
||||||
memSpec.bankGroupsPerChannel != absoluteBankGroups ||
|
|
||||||
memSpec.banksPerChannel != absoluteBanks || memSpec.rowsPerBank != rows ||
|
|
||||||
memSpec.columnsPerRow != columns)
|
|
||||||
SC_REPORT_FATAL("AddressDecoder", "Memspec and address mapping do not match");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DecodedAddress AddressDecoder::decodeAddress(uint64_t encAddr) const
|
bool AddressDecoder::allComponentsArePowerOfTwo(const MemSpec& memSpec) const {
|
||||||
{
|
// TODO: What parts do we need to check?
|
||||||
if (encAddr > maximumAddress)
|
return isPowerOfTwo(memSpec.numberOfChannels) &&
|
||||||
SC_REPORT_WARNING("AddressDecoder",
|
isPowerOfTwo(memSpec.ranksPerChannel) &&
|
||||||
("Address " + std::to_string(encAddr) +
|
isPowerOfTwo(memSpec.bankGroupsPerChannel) &&
|
||||||
" out of range (maximum address is " + std::to_string(maximumAddress) +
|
isPowerOfTwo(memSpec.banksPerChannel) &&
|
||||||
")")
|
isPowerOfTwo(memSpec.devicesPerRank) &&
|
||||||
.c_str());
|
isPowerOfTwo(memSpec.columnsPerRow);
|
||||||
|
}
|
||||||
|
|
||||||
// Apply XOR
|
void AddressDecoder::checkMemorySize(const MemSpec& memSpec) {
|
||||||
// For each used xor:
|
bool isMemorySizeMismatch = memSpec.getSimMemSizeInBytes() > upperBoundAddress + 1 ||
|
||||||
// Get the first bit and second bit. Apply a bitwise xor operator and save it back to the
|
(memSpec.getSimMemSizeInBytes() < upperBoundAddress + 1 && !np2Flag);
|
||||||
// first bit.
|
|
||||||
auto tempAddr = encAddr;
|
if (isMemorySizeMismatch) {
|
||||||
for (const auto& it : vXor)
|
SC_REPORT_FATAL("AddressDecoder", "The mapped bits do not match the memory size");
|
||||||
{
|
}
|
||||||
uint64_t xoredBit = std::accumulate(it.cbegin(),
|
}
|
||||||
it.cend(),
|
|
||||||
0,
|
void AddressDecoder::checkMemSpecCompatibility(const MemSpec& memSpec) {
|
||||||
[tempAddr](uint64_t acc, unsigned xorBit)
|
unsigned channels = std::lround(std::pow(2.0, channelBits.length));
|
||||||
{ return acc ^= (tempAddr >> xorBit) & UINT64_C(1); });
|
unsigned ranks = std::lround(std::pow(2.0, rankBits.length));
|
||||||
encAddr &= ~(UINT64_C(1) << it[0]);
|
unsigned rows = std::lround(std::pow(2.0, rowBits.length));
|
||||||
encAddr |= xoredBit << it[0];
|
unsigned columns = std::lround(std::pow(2.0, columnBits.length));
|
||||||
|
unsigned pseudochannels = std::lround(std::pow(2.0, pseudochannelBits.length));
|
||||||
|
|
||||||
|
unsigned absoluteBankGroups = bankgroupsPerRank * (ranks * pseudochannels);
|
||||||
|
unsigned absoluteBanks = banksPerGroup * absoluteBankGroups;
|
||||||
|
|
||||||
|
// Depending on the NP2 flag we must adapt the strictness of this check
|
||||||
|
if (np2Flag) {
|
||||||
|
if (memSpec.numberOfChannels > channels || memSpec.ranksPerChannel > (ranks * pseudochannels) ||
|
||||||
|
memSpec.bankGroupsPerChannel > absoluteBankGroups ||
|
||||||
|
memSpec.banksPerChannel > absoluteBanks || memSpec.rowsPerBank > rows ||
|
||||||
|
memSpec.columnsPerRow > columns)
|
||||||
|
SC_REPORT_FATAL("AddressDecoder", "Memspec and address mapping do not match");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (memSpec.numberOfChannels != channels || memSpec.ranksPerChannel != (ranks * pseudochannels) ||
|
||||||
|
memSpec.bankGroupsPerChannel != absoluteBankGroups ||
|
||||||
|
memSpec.banksPerChannel != absoluteBanks || memSpec.rowsPerBank != rows ||
|
||||||
|
memSpec.columnsPerRow != columns)
|
||||||
|
SC_REPORT_FATAL("AddressDecoder", "Memspec and address mapping do not match");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressDecoder::checkAddressableLimits(const MemSpec& memSpec) {
|
||||||
|
validateAddressableLimit(memSpec.numberOfChannels, calculateAddressableElements(channelBits.length), "Channel");
|
||||||
|
validateAddressableLimit(memSpec.ranksPerChannel, calculateAddressableElements(bankBits.length), "Rank");
|
||||||
|
unsigned addressableBankGroups = calculateAddressableElements(bankGroupBits.length) * calculateAddressableElements(rankBits.length);
|
||||||
|
unsigned absoluteBanks = calculateAddressableElements(bankBits.length) * addressableBankGroups;
|
||||||
|
validateAddressableLimit(memSpec.bankGroupsPerChannel, addressableBankGroups, "Bank group");
|
||||||
|
validateAddressableLimit(memSpec.banksPerChannel, absoluteBanks, "Bank");
|
||||||
|
validateAddressableLimit(memSpec.rowsPerBank, calculateAddressableElements(rowBits.length), "Row");
|
||||||
|
validateAddressableLimit(memSpec.columnsPerRow, calculateAddressableElements(columnBits.length), "Column");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned AddressDecoder::calculateAddressableElements(unsigned bitSize) const {
|
||||||
|
return std::lround(std::pow(2.0, bitSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddressDecoder::validateAddressableLimit(unsigned memSpecValue, unsigned addressableValue, const std::string& name) {
|
||||||
|
if (memSpecValue > addressableValue || memSpecValue <= (addressableValue >> 1)) {
|
||||||
|
SC_REPORT_FATAL("AddressDecoder", (name + " bit mapping does not match the memspec configuration").c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AddressDecoder::isPowerOfTwo(unsigned value) const {
|
||||||
|
return value != 0 && (value & (value - 1)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned AddressDecoder::checkByteBits(const MemSpec& memSpec) {
|
||||||
|
unsigned bytesPerBeat = memSpec.dataBusWidth / 8;
|
||||||
|
unsigned numOfByteBits = std::ceil(std::log2(memSpec.dataBusWidth / 8.0));
|
||||||
|
|
||||||
|
if (!isPowerOfTwo(bytesPerBeat)) {
|
||||||
|
SC_REPORT_WARNING("AddressDecoder",
|
||||||
|
("Bytes per beat are not power of two! \nAssuming " +
|
||||||
|
std::to_string(numOfByteBits) + " reserved byte bits.").c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (byteBits.length < numOfByteBits) {
|
||||||
|
SC_REPORT_FATAL("AddressDecoder",
|
||||||
|
("Byte bits are not continuous starting from 0. (bytesPerBeat: " +
|
||||||
|
std::to_string(bytesPerBeat) +
|
||||||
|
"B -> number of byte-bits: " +
|
||||||
|
std::to_string(numOfByteBits) + ")").c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return numOfByteBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AddressDecoder::checkBurstLengthBits(const MemSpec& memSpec) {
|
||||||
|
unsigned numOfMaxBurstLengthBits = std::ceil(std::log2(memSpec.maxBurstLength));
|
||||||
|
burstBitMask = createBitmask(numOfMaxBurstLengthBits, byteBits.length);
|
||||||
|
|
||||||
|
if (!isPowerOfTwo(memSpec.maxBurstLength)) {
|
||||||
|
SC_REPORT_WARNING("AddressDecoder",
|
||||||
|
("Maximum burst length (" + std::to_string(memSpec.maxBurstLength) +
|
||||||
|
") is not power of two! \nAssuming " +
|
||||||
|
std::to_string(numOfMaxBurstLengthBits) +
|
||||||
|
" reserved burst bits.").c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::bitset<64> burstBitset(((1 << numOfMaxBurstLengthBits) - 1) << columnBits.idx);
|
||||||
|
std::bitset<64> columnBitset;
|
||||||
|
for (size_t i = 0; i < columnBits.length; i++) {
|
||||||
|
columnBitset |= mappingMatrix[columnBits.idx + i];
|
||||||
|
}
|
||||||
|
if ((columnBits.length < numOfMaxBurstLengthBits) || ((columnBitset & burstBitset) != burstBitset)) {
|
||||||
|
SC_REPORT_FATAL("AddressDecoder",
|
||||||
|
("No continuous column bits for maximum burst length (maximumBurstLength: " +
|
||||||
|
std::to_string(memSpec.maxBurstLength) +
|
||||||
|
" -> required number of burst bits: " +
|
||||||
|
std::to_string(numOfMaxBurstLengthBits) + ")").c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DecodedAddress AddressDecoder::decodeAddress(tlm::tlm_generic_payload& trans) const
|
||||||
|
{
|
||||||
|
uint64_t encAddr = trans.get_address();
|
||||||
|
if (encAddr > upperBoundAddress)
|
||||||
|
{
|
||||||
|
trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
|
||||||
|
SC_REPORT_WARNING("AddressDecoder",
|
||||||
|
("Address " + std::to_string(encAddr) +
|
||||||
|
" out of range (maximum address is " + std::to_string(upperBoundAddress) +
|
||||||
|
")")
|
||||||
|
.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t result = gf2Multiplication(encAddr, mappingMatrix);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Extracts a specific AddressComponent from the result address.
|
||||||
|
*/
|
||||||
|
auto get_component = [&result](const AddressComponent& component) -> unsigned {
|
||||||
|
if (component.idx < 0 || component.length <= 0) {
|
||||||
|
return static_cast<unsigned>(0);
|
||||||
|
}
|
||||||
|
// Create mask
|
||||||
|
uint64_t mask = (1ULL << component.length) - 1;
|
||||||
|
// Shift and apply the mask
|
||||||
|
return static_cast<unsigned>((result >> component.idx) & mask);
|
||||||
|
};
|
||||||
|
|
||||||
DecodedAddress decAddr;
|
DecodedAddress decAddr;
|
||||||
|
decAddr.channel = get_component(channelBits);
|
||||||
|
decAddr.rank = get_component(rankBits);
|
||||||
|
decAddr.rank |= get_component(pseudochannelBits);
|
||||||
|
decAddr.stack = get_component(stackBits);
|
||||||
|
decAddr.bankgroup = get_component(bankGroupBits);
|
||||||
|
decAddr.bank = get_component(bankBits);
|
||||||
|
decAddr.row = get_component(rowBits);
|
||||||
|
decAddr.column= get_component(columnBits);
|
||||||
|
decAddr.byte = get_component(byteBits);
|
||||||
|
|
||||||
for (unsigned it = 0; it < vChannelBits.size(); it++)
|
if (np2Flag)
|
||||||
decAddr.channel |= ((encAddr >> vChannelBits[it]) & UINT64_C(1)) << it;
|
if (!isAddressValid(decAddr))
|
||||||
|
trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
|
||||||
for (unsigned it = 0; it < vRankBits.size(); it++)
|
|
||||||
decAddr.rank |= ((encAddr >> vRankBits[it]) & UINT64_C(1)) << it;
|
|
||||||
|
|
||||||
for (unsigned it = 0; it < vStackBits.size(); it++)
|
|
||||||
decAddr.stack |= ((encAddr >> vStackBits[it]) & UINT64_C(1)) << it;
|
|
||||||
|
|
||||||
for (unsigned it = 0; it < vBankGroupBits.size(); it++)
|
|
||||||
decAddr.bankgroup |= ((encAddr >> vBankGroupBits[it]) & UINT64_C(1)) << it;
|
|
||||||
|
|
||||||
for (unsigned it = 0; it < vBankBits.size(); it++)
|
|
||||||
decAddr.bank |= ((encAddr >> vBankBits[it]) & UINT64_C(1)) << it;
|
|
||||||
|
|
||||||
for (unsigned it = 0; it < vRowBits.size(); it++)
|
|
||||||
decAddr.row |= ((encAddr >> vRowBits[it]) & UINT64_C(1)) << it;
|
|
||||||
|
|
||||||
for (unsigned it = 0; it < vColumnBits.size(); it++)
|
|
||||||
decAddr.column |= ((encAddr >> vColumnBits[it]) & UINT64_C(1)) << it;
|
|
||||||
|
|
||||||
for (unsigned it = 0; it < vByteBits.size(); it++)
|
|
||||||
decAddr.byte |= ((encAddr >> vByteBits[it]) & UINT64_C(1)) << it;
|
|
||||||
|
|
||||||
|
// Important: This offsets must be added after(!) the address validation!
|
||||||
decAddr.bankgroup = decAddr.bankgroup + decAddr.rank * bankgroupsPerRank;
|
decAddr.bankgroup = decAddr.bankgroup + decAddr.rank * bankgroupsPerRank;
|
||||||
decAddr.bank = decAddr.bank + decAddr.bankgroup * banksPerGroup;
|
decAddr.bank = decAddr.bank + decAddr.bankgroup * banksPerGroup;
|
||||||
|
|
||||||
return decAddr;
|
return decAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AddressDecoder::isAddressValid(const DecodedAddress& decAddr) const
|
||||||
|
{
|
||||||
|
unsigned it;
|
||||||
|
|
||||||
|
// Check if burst address is within limits
|
||||||
|
auto mask = burstBitMask;
|
||||||
|
for (it = 0; ((mask >> it) & 1) == 0; it++) { }
|
||||||
|
if ((decAddr.column & (mask >> it)) >= memSpec->maxBurstLength)
|
||||||
|
{
|
||||||
|
SC_REPORT_WARNING("AddressDecoder", ("Burst address out of bounds (given: " +
|
||||||
|
std::to_string((decAddr.column & (mask >> it))) +
|
||||||
|
", MemSpec: " + std::to_string(memSpec->maxBurstLength) + ")")
|
||||||
|
.c_str()
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check all address components for validity
|
||||||
|
if ((decAddr.channel >= memSpec->numberOfChannels) ||
|
||||||
|
(decAddr.rank >= memSpec->ranksPerChannel) ||
|
||||||
|
(decAddr.bankgroup >= memSpec->bankGroupsPerChannel) ||
|
||||||
|
(decAddr.bank >= memSpec->banksPerGroup) ||
|
||||||
|
(decAddr.row >= memSpec->rowsPerBank) ||
|
||||||
|
(decAddr.column >= memSpec->columnsPerRow))
|
||||||
|
{
|
||||||
|
SC_REPORT_WARNING("AddressDecoder",
|
||||||
|
"Invalid address: channel, rank, bankgroup, bank, row or column exeeds memSpec limits.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned AddressDecoder::decodeChannel(uint64_t encAddr) const
|
unsigned AddressDecoder::decodeChannel(uint64_t encAddr) const
|
||||||
{
|
{
|
||||||
if (encAddr > maximumAddress)
|
if (encAddr > upperBoundAddress)
|
||||||
SC_REPORT_WARNING("AddressDecoder",
|
SC_REPORT_WARNING("AddressDecoder",
|
||||||
("Address " + std::to_string(encAddr) +
|
("Address " + std::to_string(encAddr) +
|
||||||
" out of range (maximum address is " + std::to_string(maximumAddress) +
|
" out of range (maximum address is " + std::to_string(upperBoundAddress) +
|
||||||
")")
|
")")
|
||||||
.c_str());
|
.c_str());
|
||||||
|
|
||||||
// Apply XOR
|
uint64_t result = gf2Multiplication(encAddr, mappingMatrix);
|
||||||
// For each used xor:
|
|
||||||
// Get the first bit and second bit. Apply a bitwise xor operator and save it back to the
|
|
||||||
// first bit.
|
|
||||||
auto tempAddr = encAddr;
|
|
||||||
for (const auto& it : vXor)
|
|
||||||
{
|
|
||||||
uint64_t xoredBit = std::accumulate(it.cbegin(),
|
|
||||||
it.cend(),
|
|
||||||
0,
|
|
||||||
[tempAddr](uint64_t acc, unsigned xorBit)
|
|
||||||
{ return acc ^= (tempAddr >> xorBit) & UINT64_C(1); });
|
|
||||||
encAddr &= ~(UINT64_C(1) << it[0]);
|
|
||||||
encAddr |= xoredBit << it[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned channel = 0;
|
/**
|
||||||
|
* @brief Extracts a specific AddressComponent from the result address.
|
||||||
|
*/
|
||||||
|
auto get_component = [&result](const AddressComponent& component) -> unsigned {
|
||||||
|
if (component.idx < 0 || component.length <= 0) {
|
||||||
|
return static_cast<unsigned>(0);
|
||||||
|
}
|
||||||
|
// Create mask
|
||||||
|
uint64_t mask = (1ULL << component.length) - 1;
|
||||||
|
// Shift and apply the mask
|
||||||
|
return static_cast<unsigned>((result >> component.idx) & mask);
|
||||||
|
};
|
||||||
|
|
||||||
for (unsigned it = 0; it < vChannelBits.size(); it++)
|
return get_component(channelBits);
|
||||||
channel |= ((encAddr >> vChannelBits[it]) & UINT64_C(1)) << it;
|
|
||||||
|
|
||||||
return channel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t AddressDecoder::encodeAddress(DecodedAddress decodedAddress) const
|
uint64_t AddressDecoder::encodeAddress(DecodedAddress decAddr) const
|
||||||
{
|
{
|
||||||
// Convert absoulte addressing for bank, bankgroup to relative
|
// Convert absolute addressing for bank, bankgroup to relative
|
||||||
decodedAddress.bankgroup = decodedAddress.bankgroup % bankgroupsPerRank;
|
decAddr.bankgroup = decAddr.bankgroup % bankgroupsPerRank;
|
||||||
decodedAddress.bank = decodedAddress.bank % banksPerGroup;
|
decAddr.bank = decAddr.bank % banksPerGroup;
|
||||||
|
|
||||||
uint64_t address = 0;
|
uint64_t mappedAddr = 0;
|
||||||
|
|
||||||
for (unsigned i = 0; i < vChannelBits.size(); i++)
|
/**
|
||||||
address |= ((decodedAddress.channel >> i) & 0x1) << vChannelBits[i];
|
* @brief Inserts a specific AddressComponent to the mappedAddress.
|
||||||
|
*/
|
||||||
|
auto set_component = [&mappedAddr](const AddressComponent& component, const unsigned int value) -> unsigned {
|
||||||
|
if (component.idx < 0 || component.length <= 0) {
|
||||||
|
return mappedAddr;
|
||||||
|
}
|
||||||
|
// Shift and add to mappedAddress
|
||||||
|
return static_cast<unsigned>((value << component.idx) | mappedAddr);
|
||||||
|
};
|
||||||
|
|
||||||
for (unsigned i = 0; i < vRankBits.size(); i++)
|
mappedAddr = set_component(channelBits, decAddr.channel);
|
||||||
address |= ((decodedAddress.rank >> i) & 0x1) << vRankBits[i];
|
mappedAddr = set_component(rankBits, decAddr.rank);
|
||||||
|
mappedAddr = set_component(pseudochannelBits, decAddr.rank);
|
||||||
|
mappedAddr = set_component(stackBits, decAddr.stack);
|
||||||
|
mappedAddr = set_component(bankGroupBits, decAddr.bankgroup);
|
||||||
|
mappedAddr = set_component(bankBits, decAddr.bank);
|
||||||
|
mappedAddr = set_component(rowBits, decAddr.row);
|
||||||
|
mappedAddr = set_component(columnBits, decAddr.column);
|
||||||
|
mappedAddr = set_component(byteBits, decAddr.byte);
|
||||||
|
|
||||||
for (unsigned i = 0; i < vStackBits.size(); i++)
|
return gf2Multiplication(mappedAddr, transposedMappingMatrix);
|
||||||
address |= ((decodedAddress.stack >> i) & 0x1) << vStackBits[i];
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < vBankGroupBits.size(); i++)
|
|
||||||
address |= ((decodedAddress.bankgroup >> i) & 0x1) << vBankGroupBits[i];
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < vBankBits.size(); i++)
|
|
||||||
address |= ((decodedAddress.bank >> i) & 0x1) << vBankBits[i];
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < vRowBits.size(); i++)
|
|
||||||
address |= ((decodedAddress.row >> i) & 0x1) << vRowBits[i];
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < vColumnBits.size(); i++)
|
|
||||||
address |= ((decodedAddress.column >> i) & 0x1) << vColumnBits[i];
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < vByteBits.size(); i++)
|
|
||||||
address |= ((decodedAddress.byte >> i) & 0x1) << vByteBits[i];
|
|
||||||
|
|
||||||
// TODO: XOR encoding
|
|
||||||
|
|
||||||
return address;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddressDecoder::print() const
|
void AddressDecoder::print() const
|
||||||
@@ -324,136 +452,24 @@ void AddressDecoder::print() const
|
|||||||
std::cout << "Used Address Mapping:" << std::endl;
|
std::cout << "Used Address Mapping:" << std::endl;
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
for (int it = static_cast<int>(vChannelBits.size() - 1); it >= 0; it--)
|
auto printBits = [&](const AddressComponent& component) {
|
||||||
{
|
int startIdx = component.idx;
|
||||||
uint64_t addressBits =
|
int length = component.length;
|
||||||
(UINT64_C(1) << vChannelBits[static_cast<std::vector<unsigned>::size_type>(it)]);
|
if (startIdx < 0) return;
|
||||||
for (auto xorMapping : vXor)
|
|
||||||
{
|
|
||||||
if (xorMapping.at(0) == vChannelBits[static_cast<std::vector<unsigned>::size_type>(it)])
|
|
||||||
{
|
|
||||||
for (auto it = xorMapping.cbegin() + 1; it != xorMapping.cend(); it++)
|
|
||||||
addressBits |= (UINT64_C(1) << *it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::cout << " Ch " << std::setw(2) << it << ": " << std::bitset<64>(addressBits)
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int it = static_cast<int>(vRankBits.size() - 1); it >= 0; it--)
|
for (int i = 0; i<length; ++i) {
|
||||||
{
|
std::cout << " " << component.name << " " << std::setw(2) << mappingMatrix[startIdx + i] << std::endl;
|
||||||
uint64_t addressBits =
|
|
||||||
(UINT64_C(1) << vRankBits[static_cast<std::vector<unsigned>::size_type>(it)]);
|
|
||||||
for (auto xorMapping : vXor)
|
|
||||||
{
|
|
||||||
if (xorMapping.at(0) == vRankBits[static_cast<std::vector<unsigned>::size_type>(it)])
|
|
||||||
{
|
|
||||||
for (auto it = xorMapping.cbegin() + 1; it != xorMapping.cend(); it++)
|
|
||||||
addressBits |= (UINT64_C(1) << *it);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
std::cout << " Ra " << std::setw(2) << it << ": " << std::bitset<64>(addressBits)
|
};
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int it = static_cast<int>(vStackBits.size() - 1); it >= 0; it--)
|
printBits(byteBits);
|
||||||
{
|
printBits(columnBits);
|
||||||
uint64_t addressBits =
|
printBits(rowBits);
|
||||||
(UINT64_C(1) << vStackBits[static_cast<std::vector<unsigned>::size_type>(it)]);
|
printBits(bankBits);
|
||||||
for (auto xorMapping : vXor)
|
printBits(bankGroupBits);
|
||||||
{
|
printBits(stackBits);
|
||||||
if (xorMapping.at(0) == vStackBits[static_cast<std::vector<unsigned>::size_type>(it)])
|
printBits(rankBits);
|
||||||
{
|
printBits(pseudochannelBits);
|
||||||
for (auto it = xorMapping.cbegin() + 1; it != xorMapping.cend(); it++)
|
printBits(channelBits);
|
||||||
addressBits |= (UINT64_C(1) << *it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::cout << " SID " << std::setw(2) << it << ": " << std::bitset<64>(addressBits)
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int it = static_cast<int>(vBankGroupBits.size() - 1); it >= 0; it--)
|
|
||||||
{
|
|
||||||
uint64_t addressBits =
|
|
||||||
(UINT64_C(1) << vBankGroupBits[static_cast<std::vector<unsigned>::size_type>(it)]);
|
|
||||||
for (auto xorMapping : vXor)
|
|
||||||
{
|
|
||||||
if (xorMapping.at(0) ==
|
|
||||||
vBankGroupBits[static_cast<std::vector<unsigned>::size_type>(it)])
|
|
||||||
{
|
|
||||||
for (auto it = xorMapping.cbegin() + 1; it != xorMapping.cend(); it++)
|
|
||||||
addressBits |= (UINT64_C(1) << *it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::cout << " Bg " << std::setw(2) << it << ": " << std::bitset<64>(addressBits)
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int it = static_cast<int>(vBankBits.size() - 1); it >= 0; it--)
|
|
||||||
{
|
|
||||||
uint64_t addressBits =
|
|
||||||
(UINT64_C(1) << vBankBits[static_cast<std::vector<unsigned>::size_type>(it)]);
|
|
||||||
for (auto xorMapping : vXor)
|
|
||||||
{
|
|
||||||
if (xorMapping.at(0) == vBankBits[static_cast<std::vector<unsigned>::size_type>(it)])
|
|
||||||
{
|
|
||||||
for (auto it = xorMapping.cbegin() + 1; it != xorMapping.cend(); it++)
|
|
||||||
addressBits |= (UINT64_C(1) << *it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::cout << " Ba " << std::setw(2) << it << ": " << std::bitset<64>(addressBits)
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int it = static_cast<int>(vRowBits.size() - 1); it >= 0; it--)
|
|
||||||
{
|
|
||||||
uint64_t addressBits =
|
|
||||||
(UINT64_C(1) << vRowBits[static_cast<std::vector<unsigned>::size_type>(it)]);
|
|
||||||
for (auto xorMapping : vXor)
|
|
||||||
{
|
|
||||||
if (xorMapping.at(0) == vRowBits[static_cast<std::vector<unsigned>::size_type>(it)])
|
|
||||||
{
|
|
||||||
for (auto it = xorMapping.cbegin() + 1; it != xorMapping.cend(); it++)
|
|
||||||
addressBits |= (UINT64_C(1) << *it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::cout << " Ro " << std::setw(2) << it << ": " << std::bitset<64>(addressBits)
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int it = static_cast<int>(vColumnBits.size() - 1); it >= 0; it--)
|
|
||||||
{
|
|
||||||
uint64_t addressBits =
|
|
||||||
(UINT64_C(1) << vColumnBits[static_cast<std::vector<unsigned>::size_type>(it)]);
|
|
||||||
for (auto xorMapping : vXor)
|
|
||||||
{
|
|
||||||
if (xorMapping.at(0) == vColumnBits[static_cast<std::vector<unsigned>::size_type>(it)])
|
|
||||||
{
|
|
||||||
for (auto it = xorMapping.cbegin() + 1; it != xorMapping.cend(); it++)
|
|
||||||
addressBits |= (UINT64_C(1) << *it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::cout << " Co " << std::setw(2) << it << ": " << std::bitset<64>(addressBits)
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int it = static_cast<int>(vByteBits.size() - 1); it >= 0; it--)
|
|
||||||
{
|
|
||||||
uint64_t addressBits =
|
|
||||||
(UINT64_C(1) << vByteBits[static_cast<std::vector<unsigned>::size_type>(it)]);
|
|
||||||
for (auto xorMapping : vXor)
|
|
||||||
{
|
|
||||||
if (xorMapping.at(0) == vByteBits[static_cast<std::vector<unsigned>::size_type>(it)])
|
|
||||||
{
|
|
||||||
for (auto it = xorMapping.cbegin() + 1; it != xorMapping.cend(); it++)
|
|
||||||
addressBits |= (UINT64_C(1) << *it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::cout << " By " << std::setw(2) << it << ": " << std::bitset<64>(addressBits)
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace DRAMSys
|
} // namespace DRAMSys
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, RPTU Kaiserslautern-Landau
|
* Copyright (c) 2025, RPTU Kaiserslautern-Landau
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -34,15 +34,14 @@
|
|||||||
* Lukas Steiner
|
* Lukas Steiner
|
||||||
* Luiza Correa
|
* Luiza Correa
|
||||||
* Derek Christ
|
* Derek Christ
|
||||||
|
* Thomas Zimmermann
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ADDRESSDECODER_H
|
#ifndef ADDRESSDECODER_H
|
||||||
#define ADDRESSDECODER_H
|
#define ADDRESSDECODER_H
|
||||||
|
|
||||||
#include "DRAMSys/config/DRAMSysConfiguration.h"
|
|
||||||
#include "DRAMSys/configuration/memspec/MemSpec.h"
|
#include "DRAMSys/configuration/memspec/MemSpec.h"
|
||||||
|
#include "DRAMSys/config/AddressMapping.h"
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace DRAMSys
|
namespace DRAMSys
|
||||||
@@ -50,27 +49,6 @@ namespace DRAMSys
|
|||||||
|
|
||||||
struct DecodedAddress
|
struct DecodedAddress
|
||||||
{
|
{
|
||||||
DecodedAddress(unsigned channel,
|
|
||||||
unsigned rank,
|
|
||||||
unsigned stack,
|
|
||||||
unsigned bankgroup,
|
|
||||||
unsigned bank,
|
|
||||||
unsigned row,
|
|
||||||
unsigned column,
|
|
||||||
unsigned bytes) :
|
|
||||||
channel(channel),
|
|
||||||
rank(rank),
|
|
||||||
stack(stack),
|
|
||||||
bankgroup(bankgroup),
|
|
||||||
bank(bank),
|
|
||||||
row(row),
|
|
||||||
column(column),
|
|
||||||
byte(bytes)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
DecodedAddress() = default;
|
|
||||||
|
|
||||||
unsigned channel = 0;
|
unsigned channel = 0;
|
||||||
unsigned rank = 0;
|
unsigned rank = 0;
|
||||||
unsigned stack = 0;
|
unsigned stack = 0;
|
||||||
@@ -79,38 +57,198 @@ struct DecodedAddress
|
|||||||
unsigned row = 0;
|
unsigned row = 0;
|
||||||
unsigned column = 0;
|
unsigned column = 0;
|
||||||
unsigned byte = 0;
|
unsigned byte = 0;
|
||||||
|
|
||||||
|
DecodedAddress(unsigned channel,
|
||||||
|
unsigned rank,
|
||||||
|
unsigned stack,
|
||||||
|
unsigned bankgroup,
|
||||||
|
unsigned bank,
|
||||||
|
unsigned row,
|
||||||
|
unsigned column,
|
||||||
|
unsigned byte) :
|
||||||
|
channel(channel),
|
||||||
|
rank(rank),
|
||||||
|
stack(stack),
|
||||||
|
bankgroup(bankgroup),
|
||||||
|
bank(bank),
|
||||||
|
row(row),
|
||||||
|
column(column),
|
||||||
|
byte(byte)
|
||||||
|
{}
|
||||||
|
|
||||||
|
DecodedAddress() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AddressComponent {
|
||||||
|
AddressComponent() : idx(-1), length(0), name("undef") {}
|
||||||
|
AddressComponent(std::string_view name) : idx(-1), length(0), name(name) {}
|
||||||
|
explicit AddressComponent(int idx, int length, std::string_view name) : idx(idx), length(length), name(name) {}
|
||||||
|
int idx;
|
||||||
|
unsigned length;
|
||||||
|
std::string_view name;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AddressDecoder
|
class AddressDecoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AddressDecoder(const Config::AddressMapping& addressMapping);
|
AddressDecoder(const DRAMSys::Config::AddressMapping& addressMapping);
|
||||||
|
|
||||||
[[nodiscard]] DecodedAddress decodeAddress(uint64_t encAddr) const;
|
/**
|
||||||
|
* @brief Decodes an address from a transaction payload into its address components.
|
||||||
|
*
|
||||||
|
* @param trans The transaction payload.
|
||||||
|
* @return The decoded address.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] DecodedAddress decodeAddress(tlm::tlm_generic_payload& trans) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decodes the channel component from an encoded address.
|
||||||
|
*
|
||||||
|
* @param encAddr The encoded address.
|
||||||
|
* @return The decoded channel number.
|
||||||
|
*/
|
||||||
[[nodiscard]] unsigned decodeChannel(uint64_t encAddr) const;
|
[[nodiscard]] unsigned decodeChannel(uint64_t encAddr) const;
|
||||||
[[nodiscard]] uint64_t encodeAddress(DecodedAddress decodedAddress) const;
|
|
||||||
[[nodiscard]] uint64_t maxAddress() const { return maximumAddress; }
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Encodes a DecodedAddress into an address value.
|
||||||
|
*
|
||||||
|
* @param decAddr The decoded address to encode.
|
||||||
|
* @return The encoded address.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] uint64_t encodeAddress(DecodedAddress decAddr) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if all address mapping bits are used and validates compatibility with the memory specification.
|
||||||
|
*
|
||||||
|
* @param memSpec The memory specification to check.
|
||||||
|
*/
|
||||||
|
void plausibilityCheck(const MemSpec& memSpec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prints the current address mapping configuration.
|
||||||
|
*/
|
||||||
void print() const;
|
void print() const;
|
||||||
void plausibilityCheck(const MemSpec &memSpec);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::vector<std::bitset<64>> mappingMatrix;
|
||||||
|
std::vector<std::bitset<64>> transposedMappingMatrix;
|
||||||
|
uint64_t highestBitValue;
|
||||||
|
const MemSpec* memSpec;
|
||||||
|
uint64_t burstBitMask;
|
||||||
|
|
||||||
|
AddressComponent byteBits;
|
||||||
|
AddressComponent columnBits;
|
||||||
|
AddressComponent bankGroupBits;
|
||||||
|
AddressComponent bankBits;
|
||||||
|
AddressComponent rowBits;
|
||||||
|
AddressComponent pseudochannelBits;
|
||||||
|
AddressComponent channelBits;
|
||||||
|
AddressComponent rankBits;
|
||||||
|
AddressComponent stackBits;
|
||||||
|
|
||||||
unsigned banksPerGroup;
|
unsigned banksPerGroup;
|
||||||
unsigned bankgroupsPerRank;
|
unsigned bankgroupsPerRank;
|
||||||
|
|
||||||
uint64_t maximumAddress;
|
uint64_t upperBoundAddress;
|
||||||
|
|
||||||
|
bool np2Flag = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transposes a matrix of 64-bit bitsets.
|
||||||
|
*
|
||||||
|
* @param matrix The matrix to transpose.
|
||||||
|
* @return The transposed matrix.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] std::vector<std::bitset<64>> transposeMatrix(const std::vector<std::bitset<64>>& matrix);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Multiplies a 64-bit vector with a matrix over GF(2).
|
||||||
|
*
|
||||||
|
* @param inputVec The input vector to multiply.
|
||||||
|
* @param matrix The GF(2) matrix.
|
||||||
|
* @return The result of the multiplication as a 64-bit unsinged integer.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] uint64_t gf2Multiplication(const uint64_t& inputVec, const std::vector<std::bitset<64>>& matrix) const;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if all addressable components in the memory specification are powers of two.
|
||||||
|
*
|
||||||
|
* @param memSpec The memory specification.
|
||||||
|
* @return true if all components are powers of two, false otherwise.
|
||||||
|
*/
|
||||||
|
bool allComponentsArePowerOfTwo(const MemSpec& memSpec) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if the mapped address space matches the memory size from the memory specification.
|
||||||
|
*
|
||||||
|
* @param memSpec The memory specification.
|
||||||
|
*/
|
||||||
|
void checkMemorySize(const MemSpec& memSpec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if the address mapping is compatible with the memory specification.
|
||||||
|
*
|
||||||
|
* @param memSpec The memory specification.
|
||||||
|
*/
|
||||||
|
void checkMemSpecCompatibility(const MemSpec& memSpec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if the addressable limits for each memory component are sufficient.
|
||||||
|
*
|
||||||
|
* @param memSpec The memory specification.
|
||||||
|
*/
|
||||||
|
void checkAddressableLimits(const MemSpec& memSpec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculates the number of addressable elements for a given bit size.
|
||||||
|
*
|
||||||
|
* @param bitSize The number of bits.
|
||||||
|
* @return The number of addressable elements.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] unsigned calculateAddressableElements(unsigned bitSize) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Validates that the addressable value matches the value from the memory specification.
|
||||||
|
*
|
||||||
|
* @param memSpecValue The value from the memory specification.
|
||||||
|
* @param addressableValue The calculated addressable value.
|
||||||
|
* @param name The name of the component.
|
||||||
|
*/
|
||||||
|
void validateAddressableLimit(unsigned memSpecValue, unsigned addressableValue, const std::string& name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if a given value is a power of two.
|
||||||
|
*
|
||||||
|
* @param value The value to check.
|
||||||
|
* @return true if the value is a power of two, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool isPowerOfTwo(unsigned value) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculates and checks the number of byte bits required for the memory specification.
|
||||||
|
*
|
||||||
|
* @param memSpec The memory specification.
|
||||||
|
* @return The number of byte bits.
|
||||||
|
*/
|
||||||
|
unsigned checkByteBits(const MemSpec& memSpec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks and handles burst lengths that are not a power of two.
|
||||||
|
*
|
||||||
|
* @param memSpec The memory specification.
|
||||||
|
*/
|
||||||
|
void checkBurstLengthBits(const MemSpec& memSpec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if the decoded address is valid according to the memory specification.
|
||||||
|
*
|
||||||
|
* @param decAddr The address to check.
|
||||||
|
* @return true if the address is valid, false otherwise.
|
||||||
|
*/
|
||||||
|
bool isAddressValid(const DecodedAddress& decAddr) const;
|
||||||
|
|
||||||
|
|
||||||
// This container stores for each used xor gate a pair of address bits, the first bit is
|
|
||||||
// overwritten with the result
|
|
||||||
std::vector<std::vector<unsigned>> vXor;
|
|
||||||
std::vector<unsigned> vChannelBits;
|
|
||||||
std::vector<unsigned> vRankBits;
|
|
||||||
std::vector<unsigned> vStackBits;
|
|
||||||
std::vector<unsigned> vBankGroupBits;
|
|
||||||
std::vector<unsigned> vBankBits;
|
|
||||||
std::vector<unsigned> vRowBits;
|
|
||||||
std::vector<unsigned> vColumnBits;
|
|
||||||
std::vector<unsigned> vByteBits;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace DRAMSys
|
} // namespace DRAMSys
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ void Arbiter::b_transport([[maybe_unused]] int id,
|
|||||||
{
|
{
|
||||||
trans.set_address(trans.get_address() - addressOffset);
|
trans.set_address(trans.get_address() - addressOffset);
|
||||||
|
|
||||||
DecodedAddress decodedAddress = addressDecoder.decodeAddress(trans.get_address());
|
DecodedAddress decodedAddress = addressDecoder.decodeAddress(trans);
|
||||||
iSocket[static_cast<int>(decodedAddress.channel)]->b_transport(trans, delay);
|
iSocket[static_cast<int>(decodedAddress.channel)]->b_transport(trans, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +203,7 @@ unsigned int Arbiter::transport_dbg([[maybe_unused]] int id, tlm::tlm_generic_pa
|
|||||||
{
|
{
|
||||||
trans.set_address(trans.get_address() - addressOffset);
|
trans.set_address(trans.get_address() - addressOffset);
|
||||||
|
|
||||||
DecodedAddress decodedAddress = addressDecoder.decodeAddress(trans.get_address());
|
DecodedAddress decodedAddress = addressDecoder.decodeAddress(trans);
|
||||||
return iSocket[static_cast<int>(decodedAddress.channel)]->transport_dbg(trans);
|
return iSocket[static_cast<int>(decodedAddress.channel)]->transport_dbg(trans);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ void EccModule::peqCallback(tlm::tlm_generic_payload& cbPayload, const tlm::tlm_
|
|||||||
sc_time tDelay = SC_ZERO_TIME;
|
sc_time tDelay = SC_ZERO_TIME;
|
||||||
|
|
||||||
DRAMSys::DecodedAddress decodedAddress =
|
DRAMSys::DecodedAddress decodedAddress =
|
||||||
addressDecoder.decodeAddress(cbPayload.get_address());
|
addressDecoder.decodeAddress(cbPayload);
|
||||||
decodedAddress = calculateOffsetAddress(decodedAddress);
|
decodedAddress = calculateOffsetAddress(decodedAddress);
|
||||||
|
|
||||||
// Update the original address to account for the offsets
|
// Update the original address to account for the offsets
|
||||||
@@ -159,7 +159,7 @@ void EccModule::peqCallback(tlm::tlm_generic_payload& cbPayload, const tlm::tlm_
|
|||||||
sc_time tDelay = SC_ZERO_TIME;
|
sc_time tDelay = SC_ZERO_TIME;
|
||||||
|
|
||||||
DRAMSys::DecodedAddress decodedAddress =
|
DRAMSys::DecodedAddress decodedAddress =
|
||||||
addressDecoder.decodeAddress(tPayload.get_address());
|
addressDecoder.decodeAddress(tPayload);
|
||||||
decodedAddress = calculateOffsetAddress(decodedAddress);
|
decodedAddress = calculateOffsetAddress(decodedAddress);
|
||||||
|
|
||||||
#ifdef ECC_ENABLE
|
#ifdef ECC_ENABLE
|
||||||
|
|||||||
@@ -86,6 +86,12 @@ Simulator::instantiateInitiator(const DRAMSys::Config::Initiator& initiator)
|
|||||||
uint64_t memorySize = dramSys->getMemSpec().getSimMemSizeInBytes();
|
uint64_t memorySize = dramSys->getMemSpec().getSimMemSizeInBytes();
|
||||||
sc_core::sc_time interfaceClk = dramSys->getMemSpec().tCK;
|
sc_core::sc_time interfaceClk = dramSys->getMemSpec().tCK;
|
||||||
|
|
||||||
|
// To support non-power-of-two values for the burst length and width, we round the BL
|
||||||
|
// down to the smaller-or-equal power-of-two.
|
||||||
|
unsigned int burstBits = std::log2(dramSys->getMemSpec().defaultBurstLength);
|
||||||
|
unsigned int widthBits = std::log2(dramSys->getMemSpec().dataBusWidth);
|
||||||
|
unsigned int defaultDataLength = std::pow(2, burstBits) * std::pow(2, widthBits) / 8;
|
||||||
|
|
||||||
return std::visit(
|
return std::visit(
|
||||||
[=](auto&& config) -> std::unique_ptr<RequestIssuer>
|
[=](auto&& config) -> std::unique_ptr<RequestIssuer>
|
||||||
{
|
{
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -35,11 +35,14 @@
|
|||||||
|
|
||||||
#include "AddressDecoderConfigs.h"
|
#include "AddressDecoderConfigs.h"
|
||||||
|
|
||||||
#include <bitset>
|
#include "gtest/gtest-spi.h"
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include <DRAMSys/simulation/AddressDecoder.h>
|
#include <DRAMSys/simulation/AddressDecoder.h>
|
||||||
|
|
||||||
|
#include "DRAMSys/configuration/memspec/MemSpec.h"
|
||||||
|
#include "DRAMSys/configuration/memspec/MemSpecDDR4.h"
|
||||||
|
|
||||||
class AddressDecoderFixture : public ::testing::Test
|
class AddressDecoderFixture : public ::testing::Test
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@@ -55,10 +58,13 @@ protected:
|
|||||||
DRAMSys::AddressDecoder addressDecoder;
|
DRAMSys::AddressDecoder addressDecoder;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
TEST_F(AddressDecoderFixture, Decoding)
|
TEST_F(AddressDecoderFixture, Decoding)
|
||||||
{
|
{
|
||||||
uint64_t address = 0x3A59'1474;
|
uint64_t address = 0x3A59'1474;
|
||||||
auto decodedAddress = addressDecoder.decodeAddress(address);
|
tlm::tlm_generic_payload trans;
|
||||||
|
trans.set_address(address);
|
||||||
|
auto decodedAddress = addressDecoder.decodeAddress(trans);
|
||||||
|
|
||||||
unsigned int channel = decodedAddress.channel;
|
unsigned int channel = decodedAddress.channel;
|
||||||
unsigned int rank = decodedAddress.rank;
|
unsigned int rank = decodedAddress.rank;
|
||||||
@@ -66,7 +72,6 @@ TEST_F(AddressDecoderFixture, Decoding)
|
|||||||
unsigned int bank = decodedAddress.bank;
|
unsigned int bank = decodedAddress.bank;
|
||||||
unsigned int row = decodedAddress.row;
|
unsigned int row = decodedAddress.row;
|
||||||
unsigned int column = decodedAddress.column;
|
unsigned int column = decodedAddress.column;
|
||||||
unsigned int byte = decodedAddress.byte;
|
|
||||||
|
|
||||||
EXPECT_EQ(channel, 0);
|
EXPECT_EQ(channel, 0);
|
||||||
EXPECT_EQ(rank, 0);
|
EXPECT_EQ(rank, 0);
|
||||||
@@ -74,7 +79,61 @@ TEST_F(AddressDecoderFixture, Decoding)
|
|||||||
EXPECT_EQ(bank, 12);
|
EXPECT_EQ(bank, 12);
|
||||||
EXPECT_EQ(row, 29874);
|
EXPECT_EQ(row, 29874);
|
||||||
EXPECT_EQ(column, 170);
|
EXPECT_EQ(column, 170);
|
||||||
EXPECT_EQ(byte, 0);
|
}
|
||||||
|
|
||||||
|
TEST_F(AddressDecoderFixture, DecodingNP2Failure)
|
||||||
|
{
|
||||||
|
addressMappingConfig = DRAMSys::Config::AddressMapping(nlohmann::json::parse(validAddressMappingJsonString)
|
||||||
|
.at("addressmapping")
|
||||||
|
.get<DRAMSys::Config::AddressMapping>());
|
||||||
|
|
||||||
|
auto memSpec = std::make_unique<const DRAMSys::MemSpecDDR4>(
|
||||||
|
nlohmann::json::parse(validNP2MemSpecJsonString)
|
||||||
|
.at("memspec").get< DRAMUtils::MemSpec::MemSpecDDR4>());
|
||||||
|
|
||||||
|
addressDecoder = DRAMSys::AddressDecoder(addressMappingConfig);
|
||||||
|
addressDecoder.plausibilityCheck(*memSpec);
|
||||||
|
|
||||||
|
uint64_t address = 0x3A59'1478;
|
||||||
|
tlm::tlm_generic_payload trans;
|
||||||
|
trans.set_address(address);
|
||||||
|
addressDecoder.decodeAddress(trans);
|
||||||
|
EXPECT_EQ(trans.get_response_status(), tlm::TLM_ADDRESS_ERROR_RESPONSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AddressDecoderFixture, DecodingNP2Success)
|
||||||
|
{
|
||||||
|
addressMappingConfig = DRAMSys::Config::AddressMapping(nlohmann::json::parse(validAddressMappingJsonString)
|
||||||
|
.at("addressmapping")
|
||||||
|
.get<DRAMSys::Config::AddressMapping>());
|
||||||
|
|
||||||
|
auto memSpec = std::make_unique<const DRAMSys::MemSpecDDR4>(
|
||||||
|
nlohmann::json::parse(validNP2MemSpecJsonString)
|
||||||
|
.at("memspec").get< DRAMUtils::MemSpec::MemSpecDDR4>());
|
||||||
|
|
||||||
|
addressDecoder = DRAMSys::AddressDecoder(addressMappingConfig);
|
||||||
|
addressDecoder.plausibilityCheck(*memSpec);
|
||||||
|
|
||||||
|
uint64_t address = 0x3A59'1477;
|
||||||
|
tlm::tlm_generic_payload trans;
|
||||||
|
trans.set_address(address);
|
||||||
|
trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
|
||||||
|
auto decodedAddress = addressDecoder.decodeAddress(trans);
|
||||||
|
|
||||||
|
unsigned int channel = decodedAddress.channel;
|
||||||
|
unsigned int rank = decodedAddress.rank;
|
||||||
|
unsigned int bankgroup = decodedAddress.bankgroup;
|
||||||
|
unsigned int bank = decodedAddress.bank;
|
||||||
|
unsigned int row = decodedAddress.row;
|
||||||
|
unsigned int column = decodedAddress.column;
|
||||||
|
|
||||||
|
EXPECT_EQ(channel, 0);
|
||||||
|
EXPECT_EQ(rank, 0);
|
||||||
|
EXPECT_EQ(bankgroup, 1);
|
||||||
|
EXPECT_EQ(bank, 4);
|
||||||
|
EXPECT_EQ(row, 7468);
|
||||||
|
EXPECT_EQ(column, 558);
|
||||||
|
EXPECT_EQ(trans.get_response_status(), tlm::TLM_INCOMPLETE_RESPONSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AddressDecoderFixture, Encoding)
|
TEST_F(AddressDecoderFixture, Encoding)
|
||||||
@@ -98,14 +157,93 @@ TEST_F(AddressDecoderFixture, DeEncoding)
|
|||||||
{
|
{
|
||||||
std::array testAddresses{std::uint64_t(0x3A59'1474),
|
std::array testAddresses{std::uint64_t(0x3A59'1474),
|
||||||
std::uint64_t(0x0000'0000),
|
std::uint64_t(0x0000'0000),
|
||||||
std::uint64_t(0x2FFA'1231),
|
std::uint64_t(0x2FFA'1230),
|
||||||
std::uint64_t(0x0001'FFFF)};
|
std::uint64_t(0x0001'FFF0)};
|
||||||
|
|
||||||
|
tlm::tlm_generic_payload trans;
|
||||||
for (auto address : testAddresses)
|
for (auto address : testAddresses)
|
||||||
{
|
{
|
||||||
DRAMSys::DecodedAddress decodedAddress = addressDecoder.decodeAddress(address);
|
trans.set_address(address);
|
||||||
|
DRAMSys::DecodedAddress decodedAddress = addressDecoder.decodeAddress(trans);
|
||||||
uint64_t encodedAddress = addressDecoder.encodeAddress(decodedAddress);
|
uint64_t encodedAddress = addressDecoder.encodeAddress(decodedAddress);
|
||||||
|
|
||||||
EXPECT_EQ(encodedAddress, address);
|
EXPECT_EQ(encodedAddress, address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AddressDecoderPlausibilityFixture : public ::testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
std::unique_ptr<DRAMSys::AddressDecoder> addressDecoder = nullptr;
|
||||||
|
std::unique_ptr<DRAMSys::MemSpecDDR4> memSpecDDR4 = nullptr;
|
||||||
|
|
||||||
|
void setupDecoder(const std::string_view& memSpecJson,
|
||||||
|
const std::string_view& addressMappingJson)
|
||||||
|
{
|
||||||
|
DRAMUtils::MemSpec::MemSpecDDR4 memSpec =
|
||||||
|
nlohmann::json::parse(memSpecJson).at("memspec").get< DRAMUtils::MemSpec::MemSpecDDR4>();
|
||||||
|
memSpecDDR4 = std::make_unique<DRAMSys::MemSpecDDR4>(memSpec);
|
||||||
|
|
||||||
|
DRAMSys::Config::AddressMapping addressMappingConfig =
|
||||||
|
nlohmann::json::parse(addressMappingJson)
|
||||||
|
.at("addressmapping")
|
||||||
|
.get<DRAMSys::Config::AddressMapping>();
|
||||||
|
addressDecoder = std::make_unique<DRAMSys::AddressDecoder>(addressMappingConfig);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(AddressDecoderPlausibilityFixture, ValidPlausibilityCheck)
|
||||||
|
{
|
||||||
|
setupDecoder(validMemSpecJsonString, validAddressMappingJsonString);
|
||||||
|
|
||||||
|
EXPECT_NO_THROW(addressDecoder->plausibilityCheck(*memSpecDDR4));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AddressDecoderPlausibilityFixture, ValidNP2PlausibilityCheck)
|
||||||
|
{
|
||||||
|
setupDecoder(validNP2MemSpecJsonString, validAddressMappingJsonString);
|
||||||
|
|
||||||
|
EXPECT_NO_THROW(addressDecoder->plausibilityCheck(*memSpecDDR4));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AddressDecoderPlausibilityFixture, InvalidMaxAddress)
|
||||||
|
{
|
||||||
|
setupDecoder(invalidMaxAddressMemSpecJsonString, validAddressMappingJsonString);
|
||||||
|
|
||||||
|
EXPECT_DEATH(addressDecoder->plausibilityCheck(*memSpecDDR4), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AddressDecoderPlausibilityFixture, DuplicateBits)
|
||||||
|
{
|
||||||
|
setupDecoder(validMemSpecJsonString, addressMappingWithDuplicatesJsonString);
|
||||||
|
|
||||||
|
EXPECT_DEATH(addressDecoder->plausibilityCheck(*memSpecDDR4), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AddressDecoderPlausibilityFixture, NonContinuousByteBits)
|
||||||
|
{
|
||||||
|
setupDecoder(validMemSpecJsonString, nonContinuousByteBitsAddressMappingJsonString);
|
||||||
|
|
||||||
|
EXPECT_DEATH(addressDecoder->plausibilityCheck(*memSpecDDR4), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AddressDecoderPlausibilityFixture, InvalidChannelMapping)
|
||||||
|
{
|
||||||
|
setupDecoder(invalidChannelMemSpecJsonString, validAddressMappingJsonString);
|
||||||
|
|
||||||
|
EXPECT_DEATH(addressDecoder->plausibilityCheck(*memSpecDDR4), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AddressDecoderPlausibilityFixture, InvalidBankGroups)
|
||||||
|
{
|
||||||
|
setupDecoder(invalidBankGroupMemSpecJsonString, validAddressMappingJsonString);
|
||||||
|
|
||||||
|
EXPECT_DEATH(addressDecoder->plausibilityCheck(*memSpecDDR4), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AddressDecoderPlausibilityFixture, InvalidRanks)
|
||||||
|
{
|
||||||
|
setupDecoder(invalidRanksMemSpecJsonString, validAddressMappingJsonString);
|
||||||
|
|
||||||
|
EXPECT_DEATH(addressDecoder->plausibilityCheck(*memSpecDDR4), "");
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user