[
  {
    "path": ".clang-format",
    "content": "AccessModifierOffset: '-4'\nAllowShortFunctionsOnASingleLine: InlineOnly\nAllowShortIfStatementsOnASingleLine: Never\nBinPackArguments: 'false'\nBinPackParameters: 'false'\nBreakBeforeBraces: Allman\nBreakConstructorInitializers: AfterColon\nColumnLimit: '100'\nIndentWidth: '4'\nPackConstructorInitializers: CurrentLine\nPointerAlignment: Left\n"
  },
  {
    "path": ".clang-tidy",
    "content": "Checks: > \n  clang-diagnostic-*,\n  clang-analyzer-*,\n  modernize-*,\n  bugprone-*,\n  concurrency-*,\n  cppcoreguidelines-*,\n  performance-*,\n  portability-*,\n  readability-*,\n  -modernize-use-trailing-return-type,\n  -readability-braces-around-statements,\n  -readability-identifier-length,\n  -readability-function-cognitive-complexity\nWarningsAsErrors: ''\nHeaderFilterRegex: ''\nAnalyzeTemporaryDtors: false\nFormatStyle: file\n"
  },
  {
    "path": ".github/workflows/CI.yml",
    "content": "name: Continuous Integration\n\non:\n  push:\n    branches: [ \"master\" ]\n  pull_request:\n    branches: [ \"master\" ]\n\nenv:\n  # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)\n  BUILD_TYPE: Release\n\njobs:\n  # Compile and test project on Linux based builds\n  build-gcc:\n    # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.\n    # You can convert this to a matrix build if you need cross-platform coverage.\n    # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Configure CMake\n      # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.\n      # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type\n      run: cmake --preset ci-unix\n\n    - name: Build\n      run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j4\n\n    - name: Test\n      working-directory: ${{github.workspace}}/build\n      # Execute tests defined by the CMake configuration.  \n      # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail\n      run: ctest -C ${{env.BUILD_TYPE}}\n      \n  # Compile and test project on Linux based builds using clang\n  build-clang:\n    # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.\n    # You can convert this to a matrix build if you need cross-platform coverage.\n    # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix\n    runs-on: ubuntu-latest\n    env:\n      CC: clang\n      CXX: clang++\n\n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Configure CMake\n      # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.\n      # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type\n      run: cmake --preset ci-unix\n\n    - name: Build\n      run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j4\n\n    - name: Test\n      working-directory: ${{github.workspace}}/build\n      # Execute tests defined by the CMake configuration.  \n      # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail\n      run: ctest -C ${{env.BUILD_TYPE}}\n\n  # Compile and test project on Windows based builds\n  build-msvc:\n    runs-on: windows-latest\n\n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Configure CMake\n      # Configure CMake in a 'build' subdirectory.\n      run: cmake --preset ci-msvc\n\n    - name: Build\n      run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j4\n\n    - name: Test\n      working-directory: ${{github.workspace}}/build\n      # Execute tests defined by the CMake configuration.  \n      # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail\n      run: ctest -C ${{env.BUILD_TYPE}}\n"
  },
  {
    "path": ".gitignore",
    "content": "# Prerequisites\n*.d\n\n# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Fortran module files\n*.mod\n*.smod\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\n\n# Executables\n*.exe\n*.app\n\n# Common project files\n.DS_Store\n.project\n.cproject\ncompile_commands.json\n.clangd/\n.vscode\n.idea\n\nbuild*/\nbin/\n*.swp\n.~*\ncmake-build-debug\ncmake-build-release\n.cache\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "# Copyright (c) 2022, Fraunhofer IESE\n# All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions are\n# met:\n#\n# 1. Redistributions of source code must retain the above copyright notice,\n#    this list of conditions and the following disclaimer.\n#\n# 2. Redistributions in binary form must reproduce the above copyright\n#    notice, this list of conditions and the following disclaimer in the\n#    documentation and/or other materials provided with the distribution.\n#\n# 3. Neither the name of the copyright holder nor the names of its\n#    contributors may be used to endorse or promote products derived from\n#    this software without specific prior written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n# \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER\n# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n#\n# Author:\n#    Thomas Psota\n#    Marco Mörz\n\n#########################################\n###             DRAMPower             ###\n#########################################\ncmake_minimum_required(VERSION 3.22.0)\n\n# TODO change for release\nset(DRAMPOWER_VERSION_MAJOR 6)\nset(DRAMPOWER_VERSION_MINOR 0)\nset(DRAMPOWER_VERSION_PATCH 0)\nset(DRAMPOWER_VERSION_STRING \"${DRAMPOWER_VERSION_MAJOR}.${DRAMPOWER_VERSION_MINOR}.${DRAMPOWER_VERSION_PATCH}\")\nadd_compile_definitions(DRAMPOWER_VERSION_STRING=\"${DRAMPOWER_VERSION_STRING}\")\n\nset(PROJECT_NAME \"DRAMPower ${DRAMPOWER_VERSION_STRING}\")\nset(PROJECT_SHORTNAME \"DRAMPower\")\n\nproject(${PROJECT_NAME} VERSION ${DRAMPOWER_VERSION_MAJOR}.${DRAMPOWER_VERSION_MINOR}.${DRAMPOWER_VERSION_PATCH} LANGUAGES CXX)\n\nif(POLICY CMP0135)\n    cmake_policy(SET CMP0135 NEW)\nendif()\n\n### CMake settings ###\nlist(APPEND CMAKE_MODULE_PATH \"${CMAKE_CURRENT_LIST_DIR}/cmake\")\ninclude(build_source_group)\ninclude(diagnostics_print)\ninclude(enable_clang_format)\ninclude(enable_clang_tidy)\ninclude(enable_cppcheck)\n\nif (PROJECT_IS_TOP_LEVEL)\n    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)\n    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)\n    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)\nendif()\n\n# set_property(GLOBAL PROPERTY USE_FOLDERS ON)\nset(CMAKE_EXPORT_COMPILE_COMMANDS ON)\n\n### Project settings ###\nmessage(STATUS \"CMAKE_SOURCE_DIR: ${CMAKE_SOURCE_DIR}\")\nmessage(STATUS \"CMAKE_BINARY_DIR: ${CMAKE_BINARY_DIR}\")\nmessage(STATUS \"\" )\n\n### Build options ###\noption(DRAMPOWER_BUILD_CLI \"Build DRAMPower Command Line Tool\" ${PROJECT_IS_TOP_LEVEL})\noption(DRAMPOWER_BUILD_BENCHMARKS \"Build DRAMPower Command Line Tool\" OFF)\noption(DRAMPOWER_BUILD_TESTS \"Build DRAMPower unit tests\" OFF)\n\n### Compiler optimization settings ###\nif(PROJECT_IS_TOP_LEVEL)\n    option(OPTIMIZE_FOR_NATIVE \"Build with -march=native (overrides CPU_TYPE if enabled)\" ON)\n    set(CPU_TYPE \"\" CACHE STRING \"CPU type for -march=CPU_TYPE and -mtune=CPU_TYPE compile options\")\n    # Set CPU_TYPE to native if OPTIMIZE_FOR_NATIVE is enabled\n    if(OPTIMIZE_FOR_NATIVE)\n        if(CPU_TYPE)\n            message(NOTICE \"OPTIMIZE_FOR_NATIVE is enabled. Overriding CPU_TYPE from \\\"${CPU_TYPE}\\\" to \\\"native\\\".\")\n        endif()\n        set(CPU_TYPE \"native\")\n    endif()\n\n    # add CPU_TYPE to cmake cxx flags\n    if(CPU_TYPE)\n        set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -march=${CPU_TYPE} -mtune=${CPU_TYPE}\")\n    endif()\nendif()\n\n# Use sane defaults for FetchContent:\n# In case we are the top-level project, get everything by default\n# In case we are included in another project, the user might want to provide their own system dependencies\noption(DRAMPOWER_USE_FETCH_CONTENT \"Enable the FetchContent module\" ${PROJECT_IS_TOP_LEVEL})\noption(DRAMPOWER_USE_FETCH_CONTENT_INTERNAL \"Enable FetchContent to provide internal dependencies\" ${DRAMPOWER_USE_FETCH_CONTENT})\noption(DRAMPOWER_USE_FETCH_CONTENT_CLI11 \"Enable FetchContent to provide CLI11\" ${DRAMPOWER_USE_FETCH_CONTENT})\noption(DRAMPOWER_USE_FETCH_CONTENT_SPDLOG \"Enable FetchContent to provide spdlog\" ${DRAMPOWER_USE_FETCH_CONTENT})\noption(DRAMPOWER_USE_FETCH_CONTENT_NLOHMANN_JSON \"Enable FetchContent to provide nlohmann json\" ${DRAMPOWER_USE_FETCH_CONTENT})\n\n### DRAMPower directories ###\nset(DRAMPOWER_SOURCE_DIR      \"${CMAKE_CURRENT_SOURCE_DIR}/src\")\nset(DRAMPOWER_LIBRARY_DIR     \"${CMAKE_CURRENT_SOURCE_DIR}/lib\")\nset(DRAMPOWER_TESTS_DIR       \"${CMAKE_CURRENT_SOURCE_DIR}/tests\")\n\n###############################################\n###           Library Settings              ###\n###############################################\n\n### Detect OS threading library ###\nfind_package(Threads)\n\nif (DRAMPOWER_USE_FETCH_CONTENT)\n    include(FetchContent)\n\n    # nlohmann_json for DRAMUtils\n    if (DRAMPOWER_USE_FETCH_CONTENT_NLOHMANN_JSON)\n            FetchContent_Declare(nlohmann_json\n            URL \"https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz\"\n            OVERRIDE_FIND_PACKAGE\n        )\n\n        FetchContent_MakeAvailable(nlohmann_json)\n    endif()\n\n    # DRAMUtils\n    if (DRAMPOWER_USE_FETCH_CONTENT_INTERNAL)\n        FetchContent_Declare(\n            DRAMUtils\n            URL \"https://github.com/tukl-msd/DRAMUtils/archive/refs/tags/v1.12.1.tar.gz\"\n            OVERRIDE_FIND_PACKAGE\n        )\n\n        FetchContent_MakeAvailable(DRAMUtils)\n    endif()\n\n    # cli11\n    if (DRAMPOWER_USE_FETCH_CONTENT_CLI11 AND DRAMPOWER_BUILD_CLI)\n        add_subdirectory(${DRAMPOWER_LIBRARY_DIR}/cli11)\n    endif()\n\n    # spdlog\n    if (DRAMPOWER_USE_FETCH_CONTENT_SPDLOG AND (DRAMPOWER_BUILD_CLI OR DRAMPOWER_BUILD_BENCHMARKS))\n        add_subdirectory(${DRAMPOWER_LIBRARY_DIR}/spdlog)\n    endif()\nendif()\n\n###############################################\n###           Source Directory              ###\n###############################################\n\nadd_subdirectory(src/DRAMPower)\n\nif(DRAMPOWER_BUILD_CLI OR DRAMPOWER_BUILD_BENCHMARKS)\n    add_subdirectory(src/cli)\nendif()\n\n###############################################\n###           Test Directory                ###\n###############################################\n\nif(DRAMPOWER_BUILD_TESTS)\n    enable_testing()\n    add_subdirectory(tests)\nendif()\n\n###############################################\n###         Benchmark Directory             ###\n###############################################\n\nif(DRAMPOWER_BUILD_BENCHMARKS)\n    add_subdirectory(benches)\nendif()\n\n###############################################\n###           Utility Projects              ###\n###############################################\n\nif(${DRAMPOWER_UTILITY_PROJECTS})\n    enable_clang_format()\n    enable_clang_tidy()\n    enable_cppcheck()\nendif()\n"
  },
  {
    "path": "CMakePresets.json",
    "content": "{\n\t\"version\": 3,\n\t\"cmakeMinimumRequired\": {\n\t\t\"major\": 3,\n\t\t\"minor\": 14,\n\t\t\"patch\": 0\n\t},\n\t\"configurePresets\": [\n\t\t{\n\t\t\t\"name\": \"cmake-pedantic\",\n\t\t\t\"hidden\": true,\n\t\t\t\"warnings\": {\n\t\t\t\t\"dev\": true,\n\t\t\t\t\"deprecated\": true,\n\t\t\t\t\"unusedCli\": true,\n\t\t\t\t\"systemVars\": false\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"dev-mode\",\n\t\t\t\"hidden\": true,\n\t\t\t\"binaryDir\": \"${sourceDir}/build\",\n\t\t\t\"inherits\": \"cmake-pedantic\",\n\t\t\t\"cacheVariables\": {\n\t\t\t\t\"DRAMPOWER_BUILD_TESTS\": \"ON\",\n\t\t\t\t\"CMAKE_BUILD_PARALLEL_LEVEL\": \"\",\n\t\t\t\t\"DRAMPOWER_BUILD_CLI\": \"ON\",\n\t\t\t\t\"DRAMPOWER_BUILD_BENCHMARKS\": \"ON\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"ci-common\",\n\t\t\t\"inherits\": [\n\t\t\t\t\"dev-mode\"\n\t\t\t],\n\t\t\t\"cacheVariables\": {\n\t\t\t\t\"CMAKE_BUILD_TYPE\": \"Release\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"ci-unix\",\n\t\t\t\"generator\": \"Unix Makefiles\",\n\t\t\t\"inherits\": [\n\t\t\t\t\"ci-common\"\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"name\": \"ci-msvc\",\n\t\t\t\"generator\": \"Visual Studio 17 2022\",\n\t\t\t\"inherits\": [\n\t\t\t\t\"ci-common\"\n\t\t\t],\n\t\t\t\"cacheVariables\": {\n\t\t\t\t\"CMAKE_CXX_FLAGS\": \"/DWIN32 /D_WINDOWS /W3 /GR /EHsc /MP\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"dev-unix\",\n\t\t\t\"generator\": \"Ninja\",\n\t\t\t\"binaryDir\": \"${sourceDir}/build\",\n\t\t\t\"inherits\": [\n\t\t\t\t\"dev-mode\"\n\t\t\t],\n\t\t\t\"cacheVariables\": {\n\t\t\t\t\"CMAKE_BUILD_TYPE\": \"Debug\",\n\t\t\t\t\"CMAKE_CXX_FLAGS\": \"-Wall -Wextra -Wpedantic\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"dev-msvc\",\n\t\t\t\"generator\": \"Visual Studio 17 2022\",\n\t\t\t\"inherits\": [\n\t\t\t\t\"dev-mode\"\n\t\t\t],\n\t\t\t\"cacheVariables\": {\n\t\t\t\t\"CMAKE_CXX_FLAGS\": \"/DWIN32 /D_WINDOWS /W3 /GR /EHsc /MP\"\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "LICENSE.txt",
    "content": "Copyright (c) 2022, Technische Universität Kaiserslautern, Fraunhofer IESE\nAll rights reserved.\n\nThis software is released under the BSD 3-Clause License. \nBy using this software, the user implicitly agrees to the licensing terms.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n1. Redistributions of source code must retain the above copyright notice,\n   this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n   contributors may be used to endorse or promote products derived from\n   this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\nTO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER\nOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\nEXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\nPROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\nPROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "<img src=\"docs/images/logo_drampower_5_0.png\" alt=\"DRAMPower 5.0\" width=\"350\" style=\"float: left;\"/>  \n\n# DRAM Power Model (DRAMPower 6.0.0)\n\n- [Releases](#releases)\n- [Installation of the DRAMPower library](#installation-of-the-drampower-library)\n- [Installation of the DRAMPower Command Line application](#installation-of-the-drampower-command-line-application)\n- [Project structure](#project-structure)\n- [Dependencies](#dependencies)\n- [Usage of the DRAMPower library](#usage-of-the-drampower-library)\n- [Usage of the DRAMPower Command Line application](#usage-of-the-drampower-command-line-application)\n- [Memory Specifications](#memory-specifications)\n- [Variation-aware Power And Energy Estimation](#variation-aware-power-and-energy-estimation)\n- [Authors & Acknowledgment](#authors--acknowledgment)\n- [Contact Information](#contact-information)\n\n## Releases\nThe last official release can be found here: https://github.com/tukl-msd/DRAMPower/releases/tag/v6.0.0\n\nThe master branch of the repository should be regarded as the bleeding-edge version, which has all the latest features, but also all the latest bugs. Use at your own discretion.\n\n## Installation of the DRAMPower library\nCMake is required for the building of DRAMPower. If DRAMPower is the top level project DRAMPower fetches the required dependencies.\nIf DRAMPower is not the top level project, the dependencies have to be fetched manually, provided by the top level project or the DRAMPower library can fetch the dependencies. Fetching content is enabled by the following cmake flag:\n\n```console\n$ -D DRAMPOWER_USE_FETCH_CONTENT=Y\n```\n\nBy default DRAMPower fetches all dependencies if `DRAMPOWER_USE_FETCH_CONTENT` is enabled. If you want to disable the fetching of a specific dependency, you can set the respective flag to N. The following flags are available:\n- `DRAMPOWER_USE_FETCH_CONTENT_INTERNAL` Fetches the internal dependencies of DRAMPower (DRAMUtils)\n- `DRAMPOWER_USE_FETCH_CONTENT_SPDLOG` Fetches the spdlog library used by the command line application\n- `DRAMPOWER_USE_FETCH_CONTENT_CLI11` Fetches the CLI11 library used by the command line application\n- `DRAMPOWER_USE_FETCH_CONTENT_NLOHMANN_JSON` Fetches the nlohmann_json library used by DRAMUtils\n\nThe following cmake flags show an example of how to disable the fetching of the spdlog and CLI11 libraries:\n```console\n$ -D DRAMPOWER_USE_FETCH_CONTENT=Y -D DRAMPOWER_USE_FETCH_CONTENT_SPDLOG=N -D DRAMPOWER_USE_FETCH_CONTENT_CLI11=N\n```\n\nFor building DRAMPower clone the repository, or download the zip file of the release you would like to use and use CMake to generate the build files, e.g.\n\n```console\n$ cd DRAMPower\n$ cmake -S . -B build\n$ cmake --build build --parallel\n```\n\nOptionally, test cases can be built by toggling the `DRAMPOWER_BUILD_TESTS` flag with CMake.\n\n## Installation of the DRAMPower Command Line application\nThe command line application is automatically build if DRAMPower is the top level project (see [Installation of the DRAMPower library](#installation-of-the-drampower-library)).\nAlternatively, the `DRAMPOWER_BUILD_CLI` flag can be set to Y to force the build of the command line tool.\nClone the repository, or download the zip file of the release you would like to use and use CMake to generate the build files. The following commands force the build of the command line application:\n\n```console\n$ cd DRAMPower\n$ cmake -S . -B build -D DRAMPOWER_BUILD_CLI=Y\n$ cmake --build build\n```\n\n## Project structure\nThe project is structured in a library part, a (optional) test part and an (optional) Command Line application.\nIntegration of DRAMPower in other projects can be easily achieved by including it as a git submodule or by using the CMake FetchContent directive.\n\nThis repository contains the following sub-directoires\n\n     DRAMPower                  # top directory\n     └── cmake                  # cmake scripts used by configuration step\n     ├── lib                    # contains bundled dependencies of the project\n     ├── src                    # top level directory containing the actual sources\n         ├── DRAMPower          # source code of the actual DRAMPower library\n         └── cli                # the optional Command Line tool\n     └── tests                  # test cases used by the project\n\n## Dependencies\nDRAMPower comes bundled with all necessary libraries and no installation of further system packages is required. DRAMPower uses the following libraries:\n - [DRAMUtils](https://github.com/tukl-msd/DRAMUtils)\n\nThe DRAMPower cli tool uses the following libraries:\n - DRAMPower\n - [DRAMUtils](https://github.com/tukl-msd/DRAMUtils)\n - [spdlog](https://github.com/gabime/spdlog/releases/tag/v1.9.2)\n - [CLI11 (CLI11 2.2 Copyright (c) 2017-2024 University of Cincinnati, developed by Henry Schreiner under NSF AWARD 1414736. All rights reserved.)](https://github.com/CLIUtils/CLI11/releases/tag/v2.4.2)\n\n## Usage of the DRAMPower library\n\nThe project is [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) ready and can be easily included in any other CMake based project.\n\n```cmake\ninclude(FetchContent)\n\nFetchContent_Declare(\ndrampower\nGIT_REPOSITORY https://github.com/tukl-msd/DRAMPower\nGIT_TAG master)\nFetchContent_MakeAvailable(drampower)\n```\n\nThe library target DRAMPower is then available to the rest of the project and can be consumed by any other target, e.g.\n\n```cmake\nadd_executable(drampower_app ${SOURCE_FILES})\ntarget_link_libraries(drampower_app PRIVATE DRAMPower::DRAMPower)\n```\n\nAll constructs inside DRAMPower are exposed through the DRAMPower namespace.\nTherefore all the following examples will refer to them with the implied usage of their namespace.\n\n```cpp\nusing namespace DRAMPower;\n```\n\nTo use the actual DRAM calculations, first a memspec has to be supplied. Some example memspecs are supplied in the [tests directory](https://github.com/tukl-msd/DRAMPower/tree/master/tests/tests_drampower/resources). The values in the memspecs are in SI units.\nAn example snippet to initialize a DDR4 based DRAM spec can look like this (only the DRAMPower related includes are shown):\n\n```cpp\n#include <DRAMUtils/memspec/MemSpec.h>\n#include <DRAMPower/memspec/MemSpecDDR4.h>\n#include <DRAMPower/standards/ddr4/DDR4.h>\n\n// optional for simulation with toggling rates\n#include <DRAMUtils/config/toggling_rate.h> \n\n// Use DRAMUtils library to parse the memspec\nauto memspec = DRAMUtils::parse_memspec_from_file(\n    std::filesystem::path(\"tests/tests_drampower/resources/ddr4.json\")\n);\nif (!memspec) {\n    throw std::runtime_error(\"Could not parse memspec\");\n}\n// Make the DRAMPower specific memspec from the parsed memspec and initialize the DRAM\n// The next line can throw std::bad_variant_access if the memspec is not a DDR4 memspec\n// or an exception derived from std::exception if the json object is not valid\nDDR4 dram(MemSpecDDR4::from_memspec(*memspec));\n// Optionally use toggle rates if no data is available for the traces\n// dram.setToggleRate(DRAMUtils::Config::ToggleRateDefinition{\n//     0.5, // togglingRateRead  0.0 to 1.0\n//     0.5, // togglingRateWrite 0.0 to 1.0\n//     0.5, // dutyCycleRead     0.0 to 1.0\n//     0.5, // dutyCycleWrite    0.0 to 1.0\n//     TogglingRateIdlePattern::H, // idlePatternRead  H, L, Z\n//     TogglingRateIdlePattern::H  // idlePatternWrite H, L, Z\n// });\n```\n\nThe created DRAM simulator then has to be fed with commands, e.g.\n\n```cpp\n#include <DRAMPower/command/Command.h>\n\n#define SZ_BITS(x) sizeof(x)*8\n\nuint8_t rd_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 1,\n};\n\nstd::vector<Command> testPattern = {\n    // {timestamp, commandtype, {bank_id, bank_group_id, rank_id, row_id}\n    {  0, CmdType::ACT,  {0, 0, 0, 0}},\n    // {timestamp, commandtype, {bank_id, bank_group_id, rank_id, row_id, column_id}, data, data_size}\n    { 15, CmdType::RD ,  {0, 0, 0, 0, 16}, rd_data, SZ_BITS(rd_data)},\n    // optional for simulation with toggling rates (dram.setToggleRate() was called)\n    // { 15, CmdType::RD ,  {0, 0, 0, 0, 16}, nullptr, 64}, \n    { 35, CmdType::PRE,  {0, 0, 0, 0}},\n    { 45, CmdType::END_OF_SIMULATION },\n};\n\nfor (const auto& command : testPattern) {\n    dram.doCoreInterfaceCommand(command);\n};\n```\n\nThe bank stats and energy calculations can then be accessed through their respective methods.\nIn the example energy_core holds the individual bank energy measures. total_energy_core holds the accumulated energy measures accessable through the energy type (e.g E_act, E_pre, E_RD, E_bg_act, E_bg_pre). total_core, total_interface and total_all hold the total energy measures for the core, interface and the sum of both as double values.\nAll values are returned in their respective SI units.\n\n```cpp\nauto stats = dram.getStats();\n\nstats.bank[0].counter.act;        // 1;\nstats.bank[0].counter.reads;      // 1;\nstats.bank[0].counter.pre;        // 1;\nstats.rank_total[0].cycles.act;   // 35;\nstats.rank_total[0].cycles.pre;   // 10;\nstats.bank[0].cycles.act;         // 35;\nstats.bank[0].cycles.pre;         // 10;\n\n// Core energy\nauto energy_core = dram.calcCoreEnergy(dram.getLastCommandTime());\n// Interface energy\nauto energy_interface = dram.calcInterfaceEnergy(dram.getLastCommandTime());\n// Total energy with core and interface energy\n\n// Accummulated bank energy\n// Note: total_core_detailed.E_bg_act holds holds the accumulated backgound activation energy plus the shared background activation energy \nauto total_energy_core = energy_core.total_energy();\n\nenergy_core.bank_energy[0].E_act;     // 1.7949519230769228e-10 J\ntotal_energy_core.E_act;              // 1.7949519230769228e-10 J\n\nenergy_core.E_bg_act_shared;          // 1.1832692307692309e-09 J\n\nenergy_core.bank_energy[0].E_bg_act;  // 5.8052884615384527e-12 J\ntotal_energy_core.E_bg_act;           // 1.1890745192307694e-09 J (5.8052884615384527e-12 J + 1.1832692307692309e-09 J)\n\ntotal_energy_core.E_pre;              // 2.076923076923077e-10 J\nenergy_core.bank_energy[0].E_pre;     // 2.076923076923077e-10 J\n\ntotal_energy_core.E_bg_pre;           // 3.1153846153846144e-10 J\nenergy_core.bank_energy[0].E_bg_pre;  // 1.9471153846153847e-11 J\n\ntotal_energy_core.E_RD;               // 4.3569230769230762e-10 J\nenergy_core.bank_energy[0].E_RD;      // 4.3569230769230762e-10 J\n\ndouble total_core = core_energy.total(); // 2.3234927884615384e-09 J\ndouble total_interface = interface_energy.total(); // 1.1102233846153846e-10 J\ndouble total_all = dram.getTotalEnergy(dram.getLastCommandTime()); // 2.4345151269230767e-09 J\n```\n\n## Usage of the DRAMPower Command Line application\n\nThe Command Line application can be built directly by setting the DRAMPOWER_BUILD_CLI flag with CMake (see [Installation Command Line application](#installation-command-line-application)).\nThe Command Line application can be used to calculate energy consumption of a DRAM memory using a command trace. The output can be printed to the console or written as a JSON file. The application needs the following arguments:\n\n- -m, --memspec (required): The path to the memory specification file (JSON format)\n- -c, --config  (required): Configuration file for the Command Line application (JSON format)\n- -t, --trace   (required): The path to the command trace file (CSV format) (see [tests directory](https://github.com/tukl-msd/DRAMPower/tree/master/tests/tests_drampower/resources))\n- -j, --json    (optional): The path to the output JSON file (default: print to console) (the output JSON file must exist and will be overwritten)\n\nThe configuration file has the following format:\n\n```json\n{\n    \"useToggleRate\": false,       // true or false\n    \"toggleRateConfig\": {\n        \"togglingRateRead\": 0.5,  // 0.0 to 1.0\n        \"togglingRateWrite\": 0.5, // 0.0 to 1.0\n        \"dutyCycleRead\": 0.5,     // 0.0 to 1.0\n        \"dutyCycleWrite\": 0.5,    // 0.0 to 1.0\n        \"idlePatternRead\": \"H\",   // \"H\", \"L\" or \"Z\"\n        \"idlePatternWrite\": \"H\"   // \"H\", \"L\" or \"Z\"\n    }\n}\n```\n\nThe Command Line application can be used as follows (in the following example the executable drampower_cli is located in the DRAMPower/build/bin directory):\n\n```console\n$ cd build/bin\n$ touch output.json\n$ touch config.json\n$ # The configuration file config.json must be filled with a valid configuration (see above)\n$ ./drampower_cli -c config.json -m ../../tests/tests_drampower/resources/ddr4.json -t ../../tests/tests_drampower/resources/ddr4.csv\n$ ./drampower_cli -c config.json -m ../../tests/tests_drampower/resources/ddr4.json -t ../../tests/tests_drampower/resources/ddr4.csv -j output.json\n```\n## Memory Specifications\n\nNote: The timing specifications in the JSONs are in clock cycles (cc). The current specifications for Reading and Writing do not include the I/O consumption. They are computed and included seperately. The IDD measures associated with different power supply sources of equal measure (VDD2, VDDCA and VDDQ). The current measures for dual-rank DIMMs reflect only the measures for the active rank. The default state of the idle rank is assumed to be the same as the complete memory state, for background power estimation. Accordingly, in all dual-rank memory specifications, IDD2P0 has been subtracted from the active currents and all background currents have been halved. They are also accounted for seperately by the power model. Stacking multiple Wide IO DRAM dies can also be captured by the nbrOfRanks parameter.\n\n## Variation-aware Power And Energy Estimation\n\n15 of the included datasheets reflect the impact of process-variations on DRAM currents for a selection of DDR3 memories manufactured at 50nm process technology. These memories include:\n(1) MICRON_128MB_DDR3-1066_8bit - revision G\n(2) MICRON_128MB_DDR3-1066_16bit - revision G\n(3) MICRON_128MB_DDR3-1600_8bit - revision G\n(4) MICRON_256MB_DDR3-1066_8bit - revision D\n(5) MICRON_256MB_DDR3-1600_16bit - revision D\n\nThe original vendor-provided datasheet current specifications are given in XMLs\nwithout suffixes such as _mu, _2s and _3s. XMLs including suffixes indicate that the\ncurrent measures are either: (1) typical (mu), or (2) include +2 sigma variation (2s),\nor (3) include +3 sigma variation (3s). These measures are derived based on the\nMonte-Carlo analysis performed on our SPICE-based DRAM cross-section.\n\nTo include these XMLs in your simulations, simply use them as the target memory.\n\n## Authors & Acknowledgment\n\nThe tool is based on the DRAM power model developed jointly by the Computer Engineering Research Group at TU Delft and the Electronic Systems Group at TU Eindhoven\nand verified by the Microelectronic System Design Research Group at TU Kaiserslautern with equivalent circuit-level simulations. This tool has been developed by\nKarthik Chandrasekar with Yonghui Li under the supervision of Dr. Benny Akesson and Prof. Kees Goossens. The IO and Termination Power measures have been employed\nfrom Micron's DRAM Power Calculator. If you decide to use DRAMPower in your research, please cite one of the following references:\n\n**To cite the DRAMPower Tool:**\n```\n[1] DRAMPower: Open-source DRAM Power & Energy Estimation Tool\nKarthik Chandrasekar, Christian Weis, Yonghui Li, Sven Goossens, Matthias Jung, Omar Naji, Benny Akesson, Norbert Wehn, and Kees Goossens\nURL: http://www.drampower.info\n```\n\n**To cite the DRAM power model:**\n```\n[2] \"Improved Power Modeling of DDR SDRAMs\"\nKarthik Chandrasekar, Benny Akesson, and Kees Goossens\nIn Proc. 14th Euromicro Conference on Digital System Design (DSD), 2011\n```\n\n**To cite the 3D-DRAM power model:**\n```\n[3] \"System and Circuit Level Power Modeling of Energy-Efficient 3D-Stacked Wide I/O DRAMs\"\nKarthik Chandrasekar, Christian Weis, Benny Akesson, Norbert Wehn, and Kees Goossens\nIn Proc. Design, Automation and Test in Europe (DATE), 2013\n```\n\n**To cite variation-aware DRAM power estimation:**\n```\n[4] \"Towards Variation-Aware System-Level Power Estimation of DRAMs: An Empirical Approach\"\nKarthik Chandrasekar, Christian Weis, Benny Akesson, Norbert Wehn, and Kees Goossens\nIn Proc. Design Automation Conference (DAC), 2013\n```\n\n## Contact Information\n\nFurther questions about the tool and the power model can be directed to:\n\nMatthias Jung (matthias.jung@iese.fraunhofer.de)\n\nFeel free to ask for updates to the tool's features and please do report any bugs\nand errors you encounter. This will encourage us to continuously improve the tool.\n\n## Disclaimer\n\nThe tool does not check the timing accuracy of the user's memory command trace\nand the use of commands and memory modes. It is expected that the user employs\na valid trace generated using a DRAM memory controller or simulator, which\nsatisfies all memory timing constraints and other requirements. The user DOES\nNOT get ANY WARRANTIES when using this tool. This software is released under the\nBSD 3-Clause License. By using this software, the user implicitly agrees to the\nlicensing terms.\n"
  },
  {
    "path": "benches/CMakeLists.txt",
    "content": "# Copyright (c) 2024, RPTU Kaiserslautern-Landau\n# All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions are\n# met:\n#\n# 1. Redistributions of source code must retain the above copyright notice,\n#    this list of conditions and the following disclaimer.\n#\n# 2. Redistributions in binary form must reproduce the above copyright\n#    notice, this list of conditions and the following disclaimer in the\n#    documentation and/or other materials provided with the distribution.\n#\n# 3. Neither the name of the copyright holder nor the names of its\n#    contributors may be used to endorse or promote products derived from\n#    this software without specific prior written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n# \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER\n# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n#\n# Authors:\n#    Derek Christ\n#    Marco Mörz\n\n###############################################\n###            benches_drampower            ###\n###############################################\n\noption(DRAMPOWER_USE_FETCH_CONTENT_GOOGLE_BENCHMARK \"Enable FetchContent to provide Google Benchmark\" ${DRAMPOWER_USE_FETCH_CONTENT})\n\nif(DRAMPOWER_USE_FETCH_CONTENT)\n    if(DRAMPOWER_USE_FETCH_CONTENT_GOOGLE_BENCHMARK AND DRAMPOWER_BUILD_BENCHMARKS)\n        set(BENCHMARK_ENABLE_TESTING OFF)\n\n        FetchContent_Declare(\n            benchmark\n            URL \"https://github.com/google/benchmark/archive/refs/tags/v1.8.3.tar.gz\"\n            OVERRIDE_FIND_PACKAGE\n        )\n\n        FetchContent_MakeAvailable(benchmark)\n    endif()\nendif()\n\nfind_package(benchmark REQUIRED)\n\nadd_executable(benches_drampower\n    main.cpp\n    simulation.cpp\n)\ntarget_link_libraries(benches_drampower\n    PRIVATE\n        DRAMPower::DRAMPower\n        DRAMPower::cli_lib\n        DRAMUtils::DRAMUtils\n        benchmark::benchmark\n)\n\ntarget_compile_definitions(benches_drampower PUBLIC DRAMPOWER_BENCHMARK_CONFIGS_DIR=\"${CMAKE_SOURCE_DIR}/tests/tests_drampower/resources\")\n"
  },
  {
    "path": "benches/main.cpp",
    "content": "/*\n * Copyright (c) 2023, RPTU Kaiserslautern-Landau\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * 3. Neither the name of the copyright holder nor the names of its\n *    contributors may be used to endorse or promote products derived from\n *    this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER\n * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * Authors:\n *    Derek Christ\n *    Marco Mörz\n */\n\n#include <benchmark/benchmark.h>\n\nint main(int argc, char** argv)\n{\n    ::benchmark::Initialize(&argc, argv);\n    ::benchmark::RunSpecifiedBenchmarks();\n    return 0;\n}\n"
  },
  {
    "path": "benches/simulation.cpp",
    "content": "/*\n * Copyright (c) 2023, RPTU Kaiserslautern-Landau\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * 3. Neither the name of the copyright holder nor the names of its\n *    contributors may be used to endorse or promote products derived from\n *    this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER\n * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * Authors:\n *    Derek Christ\n *    Marco Mörz\n */\n\n#include <DRAMPower/simconfig/simconfig.h>\n#include <DRAMPower/memspec/MemSpecLPDDR4.h>\n#include <DRAMUtils/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n#include <DRAMPower/dram/dram_base.h>\n#include <DRAMPower/command/CmdType.h>\n#include <DRAMPower/command/Command.h>\n\n#include <DRAMPower/cli/run.hpp>\n\n#include <benchmark/benchmark.h>\n#include <filesystem>\n#include <iostream>\n#include <exception>\n#include <optional>\n#include <string>\n#include <memory>\n\nclass LPDDR4_Bench : public benchmark::Fixture\n{\npublic:\n\n    using Command = DRAMPower::Command;\n    using CmdType = DRAMPower::CmdType;\n    using CommandList_t = std::vector<std::pair<Command, std::unique_ptr<uint8_t[]>>>;\n    using BaseDDR_t = DRAMPower::dram_base<CmdType>;\n\n    void SetUp(::benchmark::State&) {\n        std::string memspecFile{DRAMPOWER_BENCHMARK_CONFIGS_DIR\"/lpddr4.json\"};\n        std::string commandFile{DRAMPOWER_BENCHMARK_CONFIGS_DIR\"/lpddr4.csv\"};\n        \n        // Get dram\n        // auto ddr = DRAMPower::CLI::getMemory(memspecFile, std::nullopt);\n        auto memspeccontainer = DRAMUtils::parse_memspec_from_file(memspecFile);\n        if(!memspeccontainer)\n        {\n            throw std::runtime_error(\"Failed to parse memspec from file\");\n        }\n        memspec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*memspeccontainer));\n\n        // Parse command list\n        if (!DRAMPower::DRAMPowerCLI::parse_command_list(commandFile, commandlist))\n        {\n            throw std::runtime_error(\"Failed to parse command list\");\n        }\n    }\n\n    void TearDown(::benchmark::State&) {\n        commandlist.clear();\n    }\n    std::unique_ptr<DRAMPower::MemSpecLPDDR4> memspec;\n    CommandList_t commandlist;\n};\n\nBENCHMARK_DEFINE_F(LPDDR4_Bench, lpddr4PowerSimulation)(benchmark::State& state)\n{\n    auto rdbuf = std::cout.rdbuf(nullptr);\n    for (auto _ : state)\n    {\n        std::unique_ptr<BaseDDR_t> ddr = std::make_unique<DRAMPower::LPDDR4>(*memspec);\n        DRAMPower::DRAMPowerCLI::runCommands(ddr, commandlist);\n    }\n    std::cout.rdbuf(rdbuf);\n}\n\nBENCHMARK_REGISTER_F(LPDDR4_Bench, lpddr4PowerSimulation)->Unit(benchmark::kMicrosecond)->Iterations(10);\n\nBENCHMARK_DEFINE_F(LPDDR4_Bench, lpddr4PowerSimulationToggling)(benchmark::State& state)\n{\n    auto rdbuf = std::cout.rdbuf(nullptr);\n    for (auto _ : state)\n    {\n        auto trd = DRAMUtils::Config::ToggleRateDefinition{\n            0.5, // togglingRateRead\n            0.5, // togglingRateWrite\n            0.5, // dutyCycleRead\n            0.5, // dutyCycleWrite\n            DRAMUtils::Config::TogglingRateIdlePattern::L, // idlePatternRead\n            DRAMUtils::Config::TogglingRateIdlePattern::L  // idlePatternWrite\n        };\n        std::unique_ptr<BaseDDR_t> ddr = std::make_unique<DRAMPower::LPDDR4>(*memspec, DRAMPower::config::SimConfig{trd});\n        DRAMPower::DRAMPowerCLI::runCommands(ddr, commandlist);\n    }\n    std::cout.rdbuf(rdbuf);\n}\n\nBENCHMARK_REGISTER_F(LPDDR4_Bench, lpddr4PowerSimulationToggling)->Unit(benchmark::kMicrosecond)->Iterations(10);"
  },
  {
    "path": "cmake/build_source_group.cmake",
    "content": "###############################################\n###          build_source_group             ###\n###############################################\n###\n### Builds a source group from a set of files\n### for nicer display in IDEs\n###\n\nfunction( build_source_group )\n\tfile(GLOB_RECURSE files ${CMAKE_CURRENT_SOURCE_DIR}/*.* )\n\tlist(REMOVE_ITEM files \"CMakeLists.txt\")\n\tsource_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX \"[src]\" FILES ${files})\nendfunction()"
  },
  {
    "path": "cmake/diagnostics_print.cmake",
    "content": "###############################################\n###          diagnostics_print              ###\n###############################################\n###\n### Prints different diagnostics and infos\n### about the specified target\n###\n\nfunction( diagnostics_print target_name )\t\n\tmessage(STATUS \"${target_name} settings:\")\n\tmessage(STATUS \"==============\\n\")\n\n\tmessage(STATUS \"Source Files:\")\n\tget_target_property(SOURCE_FILES ${target_name} SOURCES)\n\tif(SOURCE_FILES)\n\t\tmessage(STATUS \"${SOURCE_FILES}\")\n\tendif()\n\t\n\tmessage(STATUS \"\\nInclude Directories:\")\n\tget_target_property(HEADER_DIR ${target_name} INCLUDE_DIRECTORIES)\n\tif(HEADER_DIR)\n\t\tmessage(STATUS \"${HEADER_DIR}\")\n\tendif()\n\t\n\tmessage(STATUS \"\\nLink Libraries:\")\n\tget_target_property(LINKED_LIBS ${target_name} LINK_LIBRARIES)\n\tif(LINKED_LIBS)\n\t\tmessage(STATUS \"${LINKED_LIBS}\")\n\tendif()\n\t\t\n\tmessage(STATUS \"\\n\")\nendfunction()"
  },
  {
    "path": "cmake/enable_clang_format.cmake",
    "content": "###############################################\n###          enable_clang_format            ###\n###############################################\n###\n### Enables a clang-format target, if\n### clang-format is installed, automatically\n### formatting all sources in the tree\n###\n\nfunction( enable_clang_format )\n\t\nendfunction()"
  },
  {
    "path": "cmake/enable_clang_tidy.cmake",
    "content": "###############################################\n###          enable_clang_tidy              ###\n###############################################\n###\n### Enables a clang-tidy target, if\n### clang-tidy is installed, to run static\n### code analysis on all sources\n###\n\nfunction( enable_clang_tidy )\n    file(GLOB_RECURSE SOURCE_FILES src/*.c src/*.cpp src/*.cxx src/*.cc )\n    file(GLOB_RECURSE HEADER_FILES src/*.h src/*.hpp src/*.hxx src/*.hh )\n\t\t\n\tfind_program(UTIL_TIDY_PATH clang-tidy)\n\tif(UTIL_TIDY_PATH)\n\t\tmessage(STATUS \"Using clang-tidy static-analysis: yes\")\n\t\tadd_custom_target(clang-tidy\n\t\t\tCOMMAND ${UTIL_TIDY_PATH} ${SOURCE_FILES} ${HEADER_FILES} -p=./ )\n\telse()\n\t\tmessage(STATUS \"Using clang-tidy static-analysis: no\")\n\tendif()\nendfunction()\n"
  },
  {
    "path": "cmake/enable_cppcheck.cmake",
    "content": "###############################################\n###          enable_cppcheck                ###\n###############################################\n###\n### Enables a cppcheck target, if\n### cppcheck is installed, to run static\n### analysis on all sources\n###\n\nfunction( enable_cppcheck )\n    file(GLOB_RECURSE SOURCE_FILES src/*.c src/*.cpp src/*.cxx src/*.cc )\n    file(GLOB_RECURSE HEADER_FILES src/*.h src/*.hpp src/*.hxx src/*.hh )\n\t\n\tfind_program(UTIL_CPPCHECK_PATH cppcheck)\n\tif(UTIL_CPPCHECK_PATH)\n\t\tmessage(STATUS \"Using cppcheck static-analysis: yes \")\n\t\tadd_custom_target(\n\t\t\t\tcppcheck\n\t\t\t\tCOMMAND ${UTIL_CPPCHECK_PATH}\n\t\t\t\t--enable=warning,performance,portability,information,missingInclude\n\t\t\t\t--language=c++\n\t\t\t\t--std=c++11\n\t\t\t\t--template=gcc\n\t\t\t\t--verbose\n\t\t\t\t--quiet\n\t\t\t\t${SOURCE_FILES} ${HEADER_FILES}\n\t\t)\n\telse()\n\t\tmessage(STATUS \"Using cppcheck static-analysis: no \")\n\tendif()\nendfunction()\n"
  },
  {
    "path": "lib/cli11/CMakeLists.txt",
    "content": "########################################\n###              CLI11               ###\n########################################\n\n\nFetchContent_Declare(cli11\n    URL \"https://github.com/CLIUtils/CLI11/archive/refs/tags/v2.4.2.tar.gz\"\n    OVERRIDE_FIND_PACKAGE\n)\n\nFetchContent_MakeAvailable(cli11)"
  },
  {
    "path": "lib/spdlog/CMakeLists.txt",
    "content": "########################################\n###              spdlog              ###\n########################################\n\n\nFetchContent_Declare(spdlog\n    URL \"https://github.com/gabime/spdlog/archive/refs/tags/v1.9.2.tar.gz\"\n    OVERRIDE_FIND_PACKAGE\n)\n\nFetchContent_MakeAvailable(spdlog)"
  },
  {
    "path": "src/DRAMPower/CMakeLists.txt",
    "content": "########################################\n###             DRAMPower            ###\n########################################\n\nfind_package(DRAMUtils REQUIRED)\n\nadd_library(DRAMPower\n    DRAMPower/command/Command.cpp\n    DRAMPower/command/Pattern.cpp\n    DRAMPower/data/energy.cpp\n    DRAMPower/dram/Interface.cpp\n    DRAMPower/dram/Rank.cpp\n    DRAMPower/memspec/MemSpecDDR4.cpp\n    DRAMPower/memspec/MemSpecDDR5.cpp\n    DRAMPower/memspec/MemSpecLPDDR4.cpp\n    DRAMPower/memspec/MemSpecLPDDR5.cpp\n    DRAMPower/standards/ddr4/core_calculation_DDR4.cpp\n    DRAMPower/standards/ddr4/DDR4.cpp\n    DRAMPower/standards/ddr4/DDR4Core.cpp\n    DRAMPower/standards/ddr4/DDR4Interface.cpp\n    DRAMPower/standards/ddr4/interface_calculation_DDR4.cpp\n    DRAMPower/standards/ddr5/core_calculation_DDR5.cpp\n    DRAMPower/standards/ddr5/DDR5.cpp\n    DRAMPower/standards/ddr5/DDR5Core.cpp\n    DRAMPower/standards/ddr5/DDR5Interface.cpp\n    DRAMPower/standards/ddr5/interface_calculation_DDR5.cpp\n    DRAMPower/standards/lpddr4/core_calculation_LPDDR4.cpp\n    DRAMPower/standards/lpddr4/LPDDR4.cpp\n    DRAMPower/standards/lpddr4/LPDDR4Core.cpp\n    DRAMPower/standards/lpddr4/LPDDR4Interface.cpp\n    DRAMPower/standards/lpddr4/interface_calculation_LPDDR4.cpp\n    DRAMPower/standards/lpddr5/core_calculation_LPDDR5.cpp\n    DRAMPower/standards/lpddr5/LPDDR5.cpp\n    DRAMPower/standards/lpddr5/LPDDR5Core.cpp\n    DRAMPower/standards/lpddr5/LPDDR5Interface.cpp\n    DRAMPower/standards/lpddr5/interface_calculation_LPDDR5.cpp\n    DRAMPower/util/extensions.cpp\n)\n\ntarget_sources(DRAMPower\nPUBLIC\n    FILE_SET api\nTYPE HEADERS\nFILES\n    DRAMPower/Types.h\n    DRAMPower/Exceptions.h\n\n    DRAMPower/dram/dram_base.h\n\n    DRAMPower/simconfig/simconfig.h\n\n    DRAMPower/command/Command.h\n    DRAMPower/data/energy.h\n    DRAMPower/data/stats.h\n\n    DRAMPower/util/extension_manager.h\n    DRAMPower/util/extensions.h\n    \n    DRAMPower/memspec/MemSpec.h\n\n    DRAMPower/memspec/MemSpecDDR4.h\n    DRAMPower/standards/ddr4/DDR4.h\n    DRAMPower/standards/ddr4/DDR4Core.h\n    DRAMPower/standards/ddr4/DDR4Interface.h\n    DRAMPower/standards/ddr4/core_calculation_DDR4.h\n    DRAMPower/standards/ddr4/interface_calculation_DDR4.h\n    DRAMPower/standards/ddr4/types.h\n    \n    DRAMPower/memspec/MemSpecDDR5.h\n    DRAMPower/standards/ddr5/DDR5.h\n    DRAMPower/standards/ddr5/DDR5Core.h\n    DRAMPower/standards/ddr5/DDR5Interface.h\n    DRAMPower/standards/ddr5/core_calculation_DDR5.h\n    DRAMPower/standards/ddr5/interface_calculation_DDR5.h\n    DRAMPower/standards/ddr5/types.h\n    \n    DRAMPower/memspec/MemSpecLPDDR4.h\n    DRAMPower/standards/lpddr4/LPDDR4.h\n    DRAMPower/standards/lpddr4/LPDDR4Core.h\n    DRAMPower/standards/lpddr4/LPDDR4Interface.h\n    DRAMPower/standards/lpddr4/core_calculation_LPDDR4.h\n    DRAMPower/standards/lpddr4/interface_calculation_LPDDR4.h\n    DRAMPower/standards/lpddr4/types.h\n    \n    DRAMPower/memspec/MemSpecLPDDR5.h\n    DRAMPower/standards/lpddr5/LPDDR5.h\n    DRAMPower/standards/lpddr5/LPDDR5Core.h\n    DRAMPower/standards/lpddr5/LPDDR5Interface.h\n    DRAMPower/standards/lpddr5/core_calculation_LPDDR5.h\n    DRAMPower/standards/lpddr5/interface_calculation_LPDDR5.h\n    DRAMPower/standards/lpddr5/types.h\n    \n    DRAMPower/util/Serialize.h\n    DRAMPower/util/Deserialize.h\n)\n\ntarget_include_directories(DRAMPower PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})\n\ntarget_compile_features(DRAMPower PUBLIC cxx_std_17)\nset_target_properties(DRAMPower PROPERTIES CXX_EXTENSIONS OFF)\nset_target_properties(DRAMPower PROPERTIES CXX_STANDARD_REQUIRED ON)\n\ntarget_link_libraries(DRAMPower\nPUBLIC \n    DRAMUtils::DRAMUtils\n)\n\n# Add test functions\nif(DRAMPOWER_BUILD_TESTS)\n    target_compile_definitions(DRAMPower PUBLIC DRAMPOWER_TESTING)\nendif()\n\nadd_library(DRAMPower::DRAMPower ALIAS DRAMPower)\n\ninstall(TARGETS DRAMPower FILE_SET api)\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/Exceptions.h",
    "content": "#ifndef DRAMPOWER_EXCEPTIONS_H\n#define DRAMPOWER_EXCEPTIONS_H\n\n#include <exception>\n#include <string>\n\n\nnamespace DRAMPower {\n\nclass Exception : public std::exception {\n// protected constructors\nprotected:\n\n// public constructors\npublic:\n    // Constructors with message\n    explicit Exception(const std::string &message) : m_message(message) {}\n    explicit Exception(std::string &&message) : m_message(std::move(message)) {}\n    \n    // Exception without message should not be allowed\n    Exception() = delete;\n    \n    // Copy and move constructors and assignment operators\n    Exception(const Exception &other) = default;\n    Exception &operator=(const Exception &other) = default;\n    Exception(Exception &&other) = default;\n    Exception &operator=(Exception &&other) = default;\n\n    // Destructor\n    virtual ~Exception() noexcept = default;\n\n// Public member functions\npublic:\n    const char *what() const noexcept override {\n        return m_message.c_str();\n    }\n\n// Private member variables\nprivate:\n    std::string m_message;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_EXCEPTIONS_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/Types.h",
    "content": "#ifndef DRAMPOWER_TYPES_H\n#define DRAMPOWER_TYPES_H\n\n#include <DRAMPower/util/cycle_stats.h>\n\n#include <stdint.h>\n\nnamespace DRAMPower {\n\nusing timestamp_t = uint64_t;\nusing interval_t = util::interval_counter<timestamp_t>;\n\n}\n\n#endif /* DRAMPOWER_TYPES_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/command/CmdType.h",
    "content": "#ifndef DRAMPOWER_COMMAND_CMDTYPE_H\n#define DRAMPOWER_COMMAND_CMDTYPE_H\n\n#include <iostream>\n#include <string>\n\nnamespace DRAMPower\n{\n\n// Taken from DRAM 4.0\n//\t\t\t\t\t\t\t\t\t\t\t\tDRAMSys  \n//\t\t\t\t\t\t\t\t\t\t\t\t\\\t\\__>  DRAMPower\n//\t\t\t\t\t\t\t\t\t\t\t\t \\            \\_v\n//\t\t\t\t\t\t\t\t\t\t\t\t  \\_______> DRAMCommon\t\nenum class CmdType {\n\tNOP = 0,    \t\t\t// 0\n\tRD,     \t\t\t\t// 1\n\tWR,     \t\t\t\t// 2\n\tRDA,    \t\t\t\t// 3\n\tWRA,    \t\t\t\t// 4\n\tACT,    \t\t\t\t// 5\n\tPRE,    \t\t\t\t// 6\n\tREFB,   \t\t\t\t// 7\n\tREFP2B,\t\t\t\t\t// 8\n\tPRESB,  \t\t\t\t// 9\n\tREFSB,  \t\t\t\t// 10\n\tPREA,   \t\t\t\t// 11\n\tREFA,   \t\t\t\t// 12\n\tPDEA,   \t\t\t\t// 13\n\tPDEP,   \t\t\t\t// 14\n\tPDXA,   \t\t\t\t// 15\n\tPDXP,   \t\t\t\t// 16\n\tSREFEN, \t\t\t\t// 17\n\tSREFEX,  \t\t\t\t// 18\n\tDSMEN,\t\t\t\t\t// 19\n\tDSMEX,\t\t\t\t\t// 20\n\tEND_OF_SIMULATION,\t\t// 21\n\tCOUNT,\t\t\t\t\t// 22\n};\n\nnamespace CmdTypeUtil\n{\n\tconstexpr bool needs_data(CmdType cmd)\n\t{\n\t\tswitch (cmd)\n\t\t{\n\t\tcase CmdType::RD:\n\t\tcase CmdType::RDA:\n\t\tcase CmdType::WR:\n\t\tcase CmdType::WRA:\n\t\t\treturn true;\n\t\tdefault:\n\t\t\treturn false;\n\t\t};\n\t};\n\n\tconstexpr CmdType from_string(const std::string_view& str)\n\t{\n\t\tif (str == \"NOP\")\n\t\t\treturn CmdType::NOP;\n\t\tif (str == \"ACT\")\n\t\t\treturn CmdType::ACT;\n\t\tif (str == \"PRE\")\n\t\t\treturn CmdType::PRE;\n\t\tif (str == \"PREA\")\n\t\t\treturn CmdType::PREA;\n\t\tif (str == \"PRESB\")\n\t\t\treturn CmdType::PRESB;\n\t\tif (str == \"REFA\")\n\t\t\treturn CmdType::REFA;\n\t\tif (str == \"REFB\")\n\t\t\treturn CmdType::REFB;\n\t\tif (str == \"REFSB\")\n\t\t\treturn CmdType::REFSB;\n\t\tif (str == \"REFP2B\")\n\t\t\treturn CmdType::REFP2B;\n\t\tif (str == \"RD\")\n\t\t\treturn CmdType::RD;\n\t\tif (str == \"RDA\")\n\t\t\treturn CmdType::RDA;\n\t\tif (str == \"WR\")\n\t\t\treturn CmdType::WR;\n\t\tif (str == \"WRA\")\n\t\t\treturn CmdType::WRA;\n\t\tif (str == \"PDEA\")\n\t\t\treturn CmdType::PDEA;\n\t\tif (str == \"PDEP\")\n\t\t\treturn CmdType::PDEP;\n\t\tif (str == \"PDXA\")\n\t\t\treturn CmdType::PDXA;\n\t\tif (str == \"PDXP\")\n\t\t\treturn CmdType::PDXP;\n\t\tif (str == \"SREFEN\")\n\t\t\treturn CmdType::SREFEN;\n\t\tif (str == \"SREFEX\")\n\t\t\treturn CmdType::SREFEX;\n\t\tif (str == \"DSMEN\")\n\t\t\treturn CmdType::DSMEN;\n\t\tif (str == \"DSMEX\")\n\t\t\treturn CmdType::DSMEX;\n\t\tif (str == \"END\")\n\t\t\treturn CmdType::END_OF_SIMULATION;\n\t\treturn CmdType::NOP;\n\t};\n\n\tconstexpr const char * to_string(CmdType cmd)\n\t{\n\t\tswitch (cmd)\n\t\t{\n\t\tcase CmdType::NOP:\n\t\t\treturn \"NOP\";\n\t\tcase CmdType::ACT:\n\t\t\treturn \"ACT\";\n\t\tcase CmdType::PRE:\n\t\t\treturn \"PRE\";\n\t\tcase CmdType::PREA:\n\t\t\treturn \"PREA\";\n\t\tcase CmdType::REFA:\n\t\t\treturn \"REFA\";\n\t\tcase CmdType::REFB:\n\t\t\treturn \"REFB\";\n\t\tcase CmdType::RD:\n\t\t\treturn \"RD\";\n\t\tcase CmdType::RDA:\n\t\t\treturn \"RDA\";\n\t\tcase CmdType::WR:\n\t\t\treturn \"WR\";\n\t\tcase CmdType::WRA:\n\t\t\treturn \"WRA\";\n\t\tcase CmdType::REFSB:\n\t\t\treturn \"REFSB\";\n\t\tcase CmdType::REFP2B:\n\t\t\treturn \"REFP2B\";\n\t\tcase CmdType::PRESB:\n\t\t\treturn \"PRESB\";\n\t\tcase CmdType::PDEA:\n\t\t\treturn \"PDEA\";\n\t\tcase CmdType::PDEP:\n\t\t\treturn \"PDEP\";\n\t\tcase CmdType::PDXA:\n\t\t\treturn \"PDXA\";\n\t\tcase CmdType::PDXP:\n\t\t\treturn \"PDXP\";\n\t\tcase CmdType::SREFEN:\n\t\t\treturn \"SREFEN\";\n\t\tcase CmdType::SREFEX:\n\t\t\treturn \"SREFEX\";\n\t\tcase CmdType::DSMEN:\n\t\t\treturn \"DSMEN\";\n\t\tcase CmdType::DSMEX:\n\t\t\treturn \"DSMEX\";\n\t\tcase CmdType::END_OF_SIMULATION:\n\t\t\treturn \"END_OF_SIMULATION\";\n\t\tdefault:\n\t\t\treturn \"to_string()\";\n\t\t}\n\t}\n\n\tinline std::ostream& operator<<(std::ostream& os, CmdType cmd) {\n\t\treturn os << to_string(cmd);\n\t}\n}\n}\n#endif /* DRAMPOWER_COMMAND_CMDTYPE_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/command/Command.cpp",
    "content": "#include \"Command.h\"\n\nnamespace DRAMPower {\n\n    TargetCoordinate::TargetCoordinate(std::size_t bank_id, std::size_t bank_group_id, std::size_t rank_id)\n        : bank(bank_id), bankGroup(bank_group_id), rank(rank_id)\n    {};\n\n    TargetCoordinate::TargetCoordinate(std::size_t bank_id, std::size_t bank_group_id, std::size_t rank_id, std::size_t row_id)\n        : bank(bank_id), bankGroup(bank_group_id), rank(rank_id), row(row_id)\n    {};\n\n    TargetCoordinate::TargetCoordinate(std::size_t bank_id, std::size_t bank_group_id, std::size_t rank_id, std::size_t row_id, std::size_t column_id)\n        : bank(bank_id), bankGroup(bank_group_id), rank(rank_id), row(row_id), column(column_id)\n    {};\n\n    Command::Command(timestamp_t timestamp, CmdType type, TargetCoordinate targetCoord, const uint8_t * data, std::size_t sz_bits)\n        : timestamp(timestamp)\n        , type(type)\n        , targetCoordinate(targetCoord)\n        , data(data)\n        , sz_bits(sz_bits)\n    {};\n\n} // namespace DRAMPower"
  },
  {
    "path": "src/DRAMPower/DRAMPower/command/Command.h",
    "content": "#ifndef DRAMPOWER_COMMAND_COMMAND_H\n#define DRAMPOWER_COMMAND_COMMAND_H\n\n#include <DRAMPower/Types.h>\n#include <DRAMPower/command/CmdType.h>\n\n#include <optional>\n\nnamespace DRAMPower {\n\nstruct TargetCoordinate {\n    std::size_t bank = 0;\n    std::size_t bankGroup = 0;\n    std::size_t rank = 0;\n\tstd::size_t row = 0;\n\tstd::size_t column = 0;\n\n\tTargetCoordinate() = default;\n\tTargetCoordinate(std::size_t bank_id, std::size_t bank_group_id, std::size_t rank_id);\n\tTargetCoordinate(std::size_t bank_id, std::size_t bank_group_id, std::size_t rank_id, std::size_t row_id);\n\tTargetCoordinate(std::size_t bank_id, std::size_t bank_group_id, std::size_t rank_id, std::size_t row_id, std::size_t column_id);\n};\n\nclass Command {\npublic:\n    Command() = default;\n\tCommand(timestamp_t timestamp, CmdType type, TargetCoordinate targetCoord = {}, const uint8_t * data = nullptr, std::size_t sz_bits = 0);\n\npublic:\n    timestamp_t timestamp = 0;\n    CmdType type;\n    TargetCoordinate targetCoordinate;\n\n\n    const uint8_t * data = 0x00;\n\tstd::size_t sz_bits;\n    //uint64_t burstLength;\npublic:\n};\n\n}\n\n#endif /* DRAMPOWER_COMMAND_COMMAND_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/command/Pattern.cpp",
    "content": "#include \"Pattern.h\"\n#include <limits>\n#include <cassert>\n#include <bitset>\n\nnamespace DRAMPower {\n\n    PatternEncoderOverrides::PatternEncoderOverrides(std::initializer_list<PatternEncoderSettingsEntry> _settings)\n    {\n        for (const auto &setting : _settings)\n        {\n            this->settings.emplace(setting.descriptor, setting.bitSpec);\n        }\n    }\n\n    void PatternEncoderOverrides::updateSettings(std::initializer_list<PatternEncoderSettingsEntry> _settings)\n    {\n        // Update settings if descriptor is already present\n        for (const auto &setting : _settings)\n        {\n            this->settings[setting.descriptor] = setting.bitSpec;\n        }\n    }\n\n    std::unordered_map<pattern_descriptor::t, PatternEncoderBitSpec> PatternEncoderOverrides::getSettings()\n    {\n        return this->settings;\n    }\n    \n    const std::unordered_map<pattern_descriptor::t, PatternEncoderBitSpec>& PatternEncoderOverrides::getSettings() const {\n        return this->settings;\n    }\n\n    PatternEncoderBitSpec PatternEncoderOverrides::getSetting(pattern_descriptor::t descriptor)\n    {\n        if (this->settings.find(descriptor) != this->settings.end())\n        {\n            return this->settings.at(descriptor);\n        }\n        return PatternEncoderBitSpec::INVALID;\n    }\n\n    bool PatternEncoderOverrides::hasSetting(pattern_descriptor::t descriptor)\n    {\n        return this->settings.find(descriptor) != this->settings.end();\n    }\n\n    bool PatternEncoderOverrides::removeSetting(pattern_descriptor::t descriptor)\n    {\n        return this->settings.erase(descriptor) > 0;\n    }\n\n    PatternEncoder::PatternEncoder(PatternEncoderOverrides settings)\n        : settings(settings) \n    {}\n\n    inline bool PatternEncoder::applyBitSpec(\n        PatternEncoderOverrides &spec,\n        pattern_descriptor::t descriptor,\n        bool LAST_BIT,\n        bool default_bit\n    )\n    {\n        auto setting = spec.getSetting(descriptor);\n        switch (setting)\n        {\n        case PatternEncoderBitSpec::L:\n            return false;\n        case PatternEncoderBitSpec::H:\n            return true;\n        case PatternEncoderBitSpec::LAST_BIT:\n            return LAST_BIT;\n        case PatternEncoderBitSpec::INVALID:\n            return default_bit;\n        default:\n            assert(false);\n            break;\n        }\n        return false;\n    }\n\n    uint64_t PatternEncoder::encode(const Command& cmd, const std::vector<pattern_descriptor::t>& pattern, const uint64_t lastpattern)\n    {\n        return encode(cmd.targetCoordinate, pattern, lastpattern);\n    }\n\n    uint64_t PatternEncoder::encode(const TargetCoordinate& targetCoordinate, const std::vector<pattern_descriptor::t>& pattern, const uint64_t lastpattern)\n    {\n        using namespace pattern_descriptor;\n\n        std::bitset<64> bitset(0);\n        std::bitset<32> bank_bits(targetCoordinate.bank);\n        std::bitset<32> row_bits(targetCoordinate.row);\n        std::bitset<32> column_bits(targetCoordinate.column);\n        std::bitset<32> bank_group_bits(targetCoordinate.bankGroup);\n\n        std::size_t n = pattern.size() - 1;\n        uint64_t opcodeshifter = 1;\n        uint16_t opcodecount = 0;\n\n        assert(n < 64);\n\n        for (const auto descriptor : pattern) {\n            // assert(n >= 0); // std::size_t is unsigned\n\n            switch (descriptor) {\n            case H:\n                bitset[n] = true;\n                break;\n            case L:\n                bitset[n] = false;\n                break;\n\n            // Command bits\n            case BL:\n            case CID0:\n            case CID1:\n            case CID2:\n            case CID3:\n                bitset[n] = applyBitSpec(settings, descriptor, ((lastpattern >> n) & 1) == 1, true);\n                break;\n            case V:\n            case X:\n            case AP:\n                bitset[n] = applyBitSpec(settings, descriptor, ((lastpattern >> n) & 1) == 1, false);\n                break;\n\n            // Target Coordinate bits\n\n            // Bank bits\n            case BA0:\n                bitset[n] = bank_bits[0];\n                break;\n            case BA1:\n                bitset[n] = bank_bits[1];\n                break;\n            case BA2:\n                bitset[n] = bank_bits[2];\n                break;\n            case BA3:\n                bitset[n] = bank_bits[3];\n                break;\n            case BA4:\n                bitset[n] = bank_bits[4];\n                break;\n            case BA5:\n                bitset[n] = bank_bits[5];\n                break;\n            case BA6:\n                bitset[n] = bank_bits[6];\n                break;\n            case BA7:\n                bitset[n] = bank_bits[7];\n                break;\n            case BA8:\n                bitset[n] = bank_bits[8];\n                break;\n\n            // BG bits\n            case BG0:\n                bitset[n] = bank_group_bits[0];\n                break;\n            case BG1:\n                bitset[n] = bank_group_bits[1];\n                break;\n            case BG2:\n                bitset[n] = bank_group_bits[2];\n                break;\n\n            case C0:\n                bitset[n] = applyBitSpec(settings, descriptor, ((lastpattern >> n) & 1) == 1, column_bits[0]);\n                break;\n            case C1:\n                bitset[n] = applyBitSpec(settings, descriptor, ((lastpattern >> n) & 1) == 1, column_bits[1]);\n                break;\n            case C2:\n                bitset[n] = applyBitSpec(settings, descriptor, ((lastpattern >> n) & 1) == 1, column_bits[2]);\n                break;\n            case C3:\n                bitset[n] = applyBitSpec(settings, descriptor, ((lastpattern >> n) & 1) == 1, column_bits[3]);\n                break;\n            case C4:\n                bitset[n] = applyBitSpec(settings, descriptor, ((lastpattern >> n) & 1) == 1, column_bits[4]);\n                break;\n            case C5:\n                bitset[n] = column_bits[5];\n                break;\n            case C6:\n                bitset[n] = column_bits[6];\n                break;\n            case C7:\n                bitset[n] = column_bits[7];\n                break;\n            case C8:\n                bitset[n] = column_bits[8];\n                break;\n            case C9:\n                bitset[n] = column_bits[9];\n                break;\n            case C10:\n                bitset[n] = applyBitSpec(settings, descriptor, ((lastpattern >> n) & 1) == 1, column_bits[10]);\n                break;\n            case C11:\n                bitset[n] = column_bits[C11];\n                break;\n            case C12:\n                bitset[n] = column_bits[C12];\n                break;\n            case C13:\n                bitset[n] = column_bits[C13];\n                break;\n            case C14:\n                bitset[n] = column_bits[C14];\n                break;\n            case C15:\n                bitset[n] = column_bits[C15];\n                break;\n            case C16:\n                bitset[n] = column_bits[C16];\n                break;\n            // Row bits\n            case R0:\n                bitset[n] = row_bits[0];\n                break;\n            case R1:\n                bitset[n] = row_bits[1];\n                break;\n            case R2:\n                bitset[n] = row_bits[2];\n                break;\n            case R3:\n                bitset[n] = row_bits[3];\n                break;\n            case R4:\n                bitset[n] = row_bits[4];\n                break;\n            case R5:\n                bitset[n] = row_bits[5];\n                break;\n            case R6:\n                bitset[n] = row_bits[6];\n                break;\n            case R7:\n                bitset[n] = row_bits[7];\n                break;\n            case R8:\n                bitset[n] = row_bits[8];\n                break;\n            case R9:\n                bitset[n] = row_bits[9];\n                break;\n            case R10:\n                bitset[n] = row_bits[10];\n                break;\n            case R11:\n                bitset[n] = row_bits[11];\n                break;\n            case R12:\n                bitset[n] = row_bits[12];\n                break;\n            case R13:\n                bitset[n] = row_bits[13];\n                break;\n            case R14:\n                bitset[n] = row_bits[14];\n                break;\n            case R15:\n                bitset[n] = row_bits[15];\n                break;\n            case R16:\n                bitset[n] = row_bits[16];\n                break;\n            case R17:\n                bitset[n] = row_bits[17];\n                break;\n            case OPCODE:\n                // Example: opcode 0x31 results in pattern 0b0011'0001\n                assert(m_opcodeLength > opcodecount);\n                bitset[n] = m_opcode & opcodeshifter;\n                opcodeshifter <<= 1;\n                ++opcodecount;\n                break;\n            \n            default:\n                break;\n            }\n\n            --n;\n        }\n\n        return bitset.to_ullong();\n    }\n\n    void PatternEncoder::setOpcode(uint64_t opcode, uint16_t opcodeLength) {\n        m_opcode = opcode;\n        m_opcodeLength = opcodeLength;\n    }\n\n    uint64_t PatternEncoder::getOpcode() const {\n        return m_opcode;\n    }\n\n    uint16_t PatternEncoder::getOpcodeLength() const {\n        return m_opcodeLength;\n    }\n\n    void PatternEncoder::serialize(std::ostream& stream) const {\n        stream.write(reinterpret_cast<const char*>(&m_opcode), sizeof(m_opcode));\n        stream.write(reinterpret_cast<const char*>(&m_opcodeLength), sizeof(m_opcodeLength));\n        // settings\n        const std::size_t settingsSize = settings.getSettings().size();\n        stream.write(reinterpret_cast<const char*>(&settingsSize), sizeof(settingsSize));\n        for (const auto& [descriptor, bitSpec] : settings.getSettings()) {\n            stream.write(reinterpret_cast<const char*>(&descriptor), sizeof(descriptor));\n            stream.write(reinterpret_cast<const char*>(&bitSpec), sizeof(bitSpec));\n        }\n    }\n\n    void PatternEncoder::deserialize(std::istream& stream) {\n        stream.read(reinterpret_cast<char*>(&m_opcode), sizeof(m_opcode));\n        stream.read(reinterpret_cast<char*>(&m_opcodeLength), sizeof(m_opcodeLength));\n        // settings\n        std::size_t settingsSize = 0;\n        stream.read(reinterpret_cast<char*>(&settingsSize), sizeof(settingsSize));\n        settings = PatternEncoderOverrides{};\n        for (std::size_t i = 0; i < settingsSize; ++i) {\n            pattern_descriptor::t descriptor;\n            PatternEncoderBitSpec bitSpec;\n            stream.read(reinterpret_cast<char*>(&descriptor), sizeof(descriptor));\n            stream.read(reinterpret_cast<char*>(&bitSpec), sizeof(bitSpec));\n            settings.updateSettings({{descriptor, bitSpec}});\n        }\n    }\n\n} // namespace DRAMPower"
  },
  {
    "path": "src/DRAMPower/DRAMPower/command/Pattern.h",
    "content": "#ifndef DRAMPOWER_COMMAND_PATTERN_H\n#define DRAMPOWER_COMMAND_PATTERN_H\n\n#include <DRAMPower/command/Command.h>\n#include <DRAMPower/util/Serialize.h>\n#include <DRAMPower/util/Deserialize.h>\n\n#include <unordered_map>\n#include <vector>\n\nnamespace DRAMPower {\nnamespace pattern_descriptor {\n    enum t {\n        H, L,\n        V, X,\n        A0,  A1,  A2,  A3,  A4,  A5,  A6,  A7,  A8,  A9,  A10, A11, A12, A13, A14, A15, A16, A17,\n        BG0, BG1, BG2, BA0, BA1, BA2, BA3, BA4, BA5, BA6, BA7, BA8,\n        C0,  C1,  C2,  C3,  C4,  C5,  C6,  C7,  C8,  C9,  C10, C11, C12, C13, C14, C15, C16,\n        R0,  R1,  R2,  R3,  R4,  R5,  R6,  R7,  R8,  R9,  R10, R11, R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R22, R23,\n        CID0, CID1, CID2, CID3,\n        AP,\n        BL,\n        OPCODE, // Example: opcode 0x03 pattern: {H, L, OPCODE, OPCODE, OPCODE, OPCODE} result in 0b100011\n    };\n}\n\nenum class PatternEncoderBitSpec\n{\n    L = 0,\n    H = 1,\n    LAST_BIT = 2,\n    INVALID = -1\n};\n\n// struct for initializer list in PatternEncoderSettings\nstruct PatternEncoderSettingsEntry {\n    pattern_descriptor::t descriptor;\n    PatternEncoderBitSpec bitSpec;\n};\n\n// class to store pattern descriptor overrides\nclass PatternEncoderOverrides\n{\n\nprivate:\n    std::unordered_map<pattern_descriptor::t, PatternEncoderBitSpec> settings;\npublic:\n    // Constructor with initializer list for settings\n    PatternEncoderOverrides() = default;\n    PatternEncoderOverrides(std::initializer_list<PatternEncoderSettingsEntry> _settings);\n\npublic:\n    void updateSettings(std::initializer_list<PatternEncoderSettingsEntry> _settings);\n    std::unordered_map<pattern_descriptor::t, PatternEncoderBitSpec> getSettings();\n    PatternEncoderBitSpec getSetting(pattern_descriptor::t descriptor);\n    const std::unordered_map<pattern_descriptor::t, PatternEncoderBitSpec>& getSettings() const;\n    bool hasSetting(pattern_descriptor::t descriptor);\n    bool removeSetting(pattern_descriptor::t descriptor);\n};\n\nclass PatternEncoder : public util::Serialize, public util::Deserialize // Currently LPDDR4\n{\npublic:\n    PatternEncoderOverrides settings;\n    PatternEncoder(PatternEncoderOverrides settings);\nprivate:\n    inline bool applyBitSpec(\n        PatternEncoderOverrides &spec,\n        pattern_descriptor::t descriptor,\n        bool LAST_BIT,\n        bool default_bit\n    );\n\npublic:\n    void setOpcode(uint64_t opcode, uint16_t opcodeLength);\n    uint64_t getOpcode() const;\n    uint16_t getOpcodeLength() const;\n\n// Overrides\npublic:\n    void serialize(std::ostream& stream) const override;\n    void deserialize(std::istream& stream) override;\n\npublic:\n    uint64_t encode(const Command& cmd, const std::vector<pattern_descriptor::t>& pattern, const uint64_t lastpattern);\n    uint64_t encode(const TargetCoordinate& coordinate, const std::vector<pattern_descriptor::t>& pattern, const uint64_t lastpattern);\n\n// Private member variables\nprivate:\n    uint64_t m_opcode = 0;\n    uint16_t m_opcodeLength = 0;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_COMMAND_PATTERN_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/data/energy.cpp",
    "content": "#include \"energy.h\"\n\nusing namespace DRAMPower;\n\ndouble energy_info_t::total() const\n{\n    auto total = E_act\n        + E_pre\n        + E_bg_act\n        + E_bg_pre\n\n        + E_RD\n        + E_WR\n        + E_RDA\n        + E_WRA\n        //+ E_pre_RDA\n        //+ E_pre_WRA\n\n        + E_ref_AB\n        + E_ref_PB\n        + E_ref_SB\n        + E_ref_2B;\n\n    return total;\n};\n\nvoid energy_info_t::to_json(json_t &j) const\n{\n    j = nlohmann::json{\n        {\"ACT\", E_act},\n        {\"PRE\", E_pre},\n        {\"BG_ACT\", E_bg_act},\n        {\"BG_PRE\", E_bg_pre},\n        {\"RD\", E_RD},\n        {\"WR\", E_WR},\n        {\"RDA\", E_RDA},\n        {\"WRA\", E_WRA},\n        {\"PRE_RDA\", E_pre_RDA},\n        {\"PRE_WRA\", E_pre_WRA},\n        {\"REF_AB\", E_ref_AB},\n        {\"REF_PB\", E_ref_PB},\n        {\"REF_SB\", E_ref_SB},\n        {\"REF_2B\", E_ref_2B}\n    };\n\n}\n\nenergy_info_t& energy_info_t::operator+=(const DRAMPower::energy_info_t& other)\n{\n    this->E_act += other.E_act;\n    this->E_pre += other.E_pre;\n    this->E_bg_act += other.E_bg_act;\n    this->E_bg_pre += other.E_bg_pre;\n\n    this->E_RD += other.E_RD;\n    this->E_WR += other.E_WR;\n    this->E_RDA += other.E_RDA;\n    this->E_WRA += other.E_WRA;\n    this->E_pre_RDA += other.E_pre_RDA;\n    this->E_pre_WRA += other.E_pre_WRA;\n\n    this->E_ref_AB += other.E_ref_AB;\n    this->E_ref_PB += other.E_ref_PB;\n    this->E_ref_SB += other.E_ref_SB;\n    this->E_ref_2B += other.E_ref_2B;\n\n    return *this;\n}\n\ndouble DRAMPower::energy_t::total() const\n{\n    double total = 0.0;\n\n    energy_info_t bank_energy_total;\n    for (const auto& bank_e : this->bank_energy)\n        bank_energy_total += bank_e;\n\n    total += bank_energy_total.total() + E_bg_act_shared + E_PDNA + E_PDNP + E_sref + E_dsm + E_refab;\n\n    return total;\n}\n\nvoid DRAMPower::interface_energy_info_t::to_json(json_t &j) const\n{\n    j = nlohmann::json{};\n    j[\"controller\"][\"dynamicEnergy\"] = controller.dynamicEnergy;\n    j[\"controller\"][\"staticEnergy\"] = controller.staticEnergy;\n    j[\"dram\"][\"dynamicEnergy\"] = dram.dynamicEnergy;\n    j[\"dram\"][\"staticEnergy\"] = dram.staticEnergy;\n}\n\nvoid DRAMPower::energy_t::to_json(json_t &j) const\n{\n    j = nlohmann::json{\n        {\"E_bg_act_shared\", E_bg_act_shared},\n        {\"E_PDNA\", E_PDNA},\n        {\"E_PDNP\", E_PDNP},\n        {\"E_sref\", E_sref},\n        {\"E_dsm\", E_dsm},\n        {\"E_refab\", E_refab}\n    };\n    // Bank energy\n    auto energy_arr = nlohmann::json::array();\n    for (const energy_info_t& energy : bank_energy)\n    {\n        json_t bank_energy_json;\n        energy.to_json(bank_energy_json);\n        energy_arr.push_back(bank_energy_json);\n    }\n    j[this->get_Bank_energy_keyword()] = energy_arr;\n}\n\nenergy_info_t DRAMPower::energy_t::aggregated_bank_energy() const\n{\n    energy_info_t total;\n\n    for (const auto& bank_e : this->bank_energy)\n        total += bank_e;\n\n    total.E_bg_act += this->E_bg_act_shared;\n\n    return total;\n}\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/data/energy.h",
    "content": "#ifndef DRAMPOWER_CALCULATION_ENERGY_H\n#define DRAMPOWER_CALCULATION_ENERGY_H\n\n#pragma once\n\n#include <vector>\n#include <iostream>\n\n#include <DRAMUtils/util/json_utils.h>\n\nnamespace DRAMPower {\n\nstruct energy_info_t\n{\n\tdouble E_act = 0.0;\n\tdouble E_pre = 0.0;\n\tdouble E_bg_act = 0.0;\n\tdouble E_bg_pre = 0.0;\n\n\tdouble E_RD = 0.0;\n\tdouble E_WR = 0.0;\n\tdouble E_RDA = 0.0;\n\tdouble E_WRA = 0.0;\n\tdouble E_pre_RDA = 0.0;\n\tdouble E_pre_WRA = 0.0;\n\n    double E_ref_AB = 0.0;\n\tdouble E_ref_PB = 0.0;\n\tdouble E_ref_SB = 0.0;\n\tdouble E_ref_2B = 0.0;\n\n\tdouble total() const;\n\tvoid to_json(json_t &j) const;\n\tenergy_info_t& operator+=(const energy_info_t & other);\n\t// Operator << for std::cout\n\tfriend std::ostream & operator<<(std::ostream & os, const energy_info_t & ei)\n\t{\n\t\tos << \"ACT: \" << ei.E_act << \" \";\n\t\tos << \"PRE: \" << ei.E_pre << \" \";\n\t\tos << \"BG_ACT: \" << ei.E_bg_act << \" \";\n\t\tos << \"BG_PRE: \" << ei.E_bg_pre << \" \";\n\t\tos << \"RD: \" << ei.E_RD << \" \";\n\t\tos << \"WR: \" << ei.E_WR << \" \";\n\t\tos << \"RDA: \" << ei.E_RDA << \" \";\n\t\tos << \"WRA: \" << ei.E_WRA << \" \";\n\t\tos << \"PRE_RDA: \" << ei.E_pre_RDA << \" \";\n\t\tos << \"PRE_WRA: \" << ei.E_pre_WRA << \" \";\n\t\tos << \"REF_AB: \" << ei.E_ref_AB << \" \";\n\t\tos << \"REF_PB: \" << ei.E_ref_PB << \" \";\n\t\tos << \"REF_SB: \" << ei.E_ref_SB << \" \";\n\t\tos << \"REF_2B: \" << ei.E_ref_2B << \" \";\n\n\t\treturn os;\n\t}\n};\n\nstruct energy_t\n{\n\tstd::vector<energy_info_t> bank_energy;\n\tenergy_info_t aggregated_bank_energy() const;\n\tvoid to_json(json_t &j) const;\n\tconstexpr inline const char * get_Bank_energy_keyword() const\n\t{\n\t\treturn \"BankEnergy\";\n\t}\n\n\n\n\tdouble E_bg_act_shared = 0.0;\n\tdouble E_PDNA = 0.0;\n\tdouble E_PDNP = 0.0;\n\tdouble E_sref = 0.0;\n\tdouble E_dsm = 0.0;\n\tdouble E_refab = 0.0;\n\n\tenergy_t(std::size_t num_banks) : bank_energy(num_banks) {};\n\t// get fields of os stream output\n\tfriend std::ostream & operator<<(std::ostream & os, const energy_t & e)\n\t{\n\t\tos << \"E_bg_act_shared: \" << e.E_bg_act_shared << \" \";\n\t\tos << \"E_PDNA: \" << e.E_PDNA << \" \";\n\t\tos << \"E_PDNP: \" << e.E_PDNP << \" \";\n\t\tos << \"E_sref: \" << e.E_sref << \" \";\n\t\tos << \"E_dsm: \" << e.E_dsm << \" \";\n\t\tos << \"E_refab: \" << e.E_refab << \" \";\n\n    \treturn os;\n\t}\n\tdouble total() const;\n};\n\nstruct interface_energy_t\n{\n\tdouble dynamicEnergy = 0.0;\n\tdouble staticEnergy = 0.0;\n\n\tinterface_energy_t &operator+=(const interface_energy_t &rhs) {\n\t\tdynamicEnergy += rhs.dynamicEnergy;\n\t\tstaticEnergy += rhs.staticEnergy;\n\t\treturn *this;\n\t}\n\n\tfriend interface_energy_t operator+(interface_energy_t lhs, const interface_energy_t &rhs) {\n\t\tlhs += rhs;\n\t\treturn lhs;\n\t}\n};\n\n\n\nstruct interface_energy_info_t\n{\n\tinterface_energy_t controller;\n\tinterface_energy_t dram;\n\n    double total() const {\n        return controller.dynamicEnergy + controller.staticEnergy + dram.dynamicEnergy + dram.staticEnergy;\n    }\n\n    interface_energy_info_t &operator+=(const interface_energy_info_t &rhs) {\n        controller += rhs.controller;\n        dram += rhs.dram;\n        return *this;\n    }\n\n\tfriend interface_energy_info_t operator+(interface_energy_info_t lhs,\n                                             const interface_energy_info_t &rhs) {\n        lhs += rhs;\n        return lhs;\n    }\n\n    friend std::ostream & operator<<(std::ostream & os, const interface_energy_info_t & e)\n\t{\n\t\tos << \"Controller: dynamicEnergy: \" << e.controller.dynamicEnergy << \" \";\n        os << \"staticEnergy: \" << e.controller.staticEnergy << std::endl;\n        os << \"DRAM: dynamicEnergy: \" << e.dram.dynamicEnergy << \" \";\n        os << \"staticEnergy: \" << e.dram.staticEnergy << std::endl;\n        os << \"Total: \" << e.total();\n    \treturn os;\n\t}\n\tvoid to_json(json_t &j) const;\n};\n\n};\n\n#endif /* DRAMPOWER_CALCULATION_ENERGY_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/data/stats.h",
    "content": "#ifndef DRAMPOWER_DATA_STATS_H\n#define DRAMPOWER_DATA_STATS_H\n\n#include <DRAMPower/util/bus.h>\n#include <DRAMPower/dram/Interface.h>\n#include <DRAMPower/util/Serialize.h>\n#include <DRAMPower/util/Deserialize.h>\n\n#include <cstdint>\n\nnamespace DRAMPower\n{\n\tstruct CycleStats : public util::Serialize, public util::Deserialize\n\t{\n\t\tstruct command_stats_t : public util::Serialize, public util::Deserialize {\n\t\t\tuint64_t act = 0;\n\t\t\tuint64_t pre = 0;\n\t\t\tuint64_t preSameBank = 0;\n\t\t\tuint64_t reads = 0;\n\t\t\tuint64_t writes = 0;\n\t\t\tuint64_t refAllBank = 0;\n\t\t\tuint64_t refPerBank = 0;\n\t\t\tuint64_t refPerTwoBanks = 0;\n\t\t\tuint64_t refSameBank = 0;\n\t\t\tuint64_t readAuto = 0;\n\t\t\tuint64_t writeAuto = 0;\n\n\t\t\tvoid serialize(std::ostream& stream) const override {\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&act), sizeof(act));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&pre), sizeof(pre));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&preSameBank), sizeof(preSameBank));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&reads), sizeof(reads));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&writes), sizeof(writes));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&refAllBank), sizeof(refAllBank));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&refPerBank), sizeof(refPerBank));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&refPerTwoBanks), sizeof(refPerTwoBanks));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&refSameBank), sizeof(refSameBank));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&readAuto), sizeof(readAuto));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&writeAuto), sizeof(writeAuto));\n\t\t\t}\n\t\t\tvoid deserialize(std::istream& stream) override {\n\t\t\t\tstream.read(reinterpret_cast<char *>(&act), sizeof(act));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&pre), sizeof(pre));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&preSameBank), sizeof(preSameBank));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&reads), sizeof(reads));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&writes), sizeof(writes));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&refAllBank), sizeof(refAllBank));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&refPerBank), sizeof(refPerBank));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&refPerTwoBanks), sizeof(refPerTwoBanks));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&refSameBank), sizeof(refSameBank));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&readAuto), sizeof(readAuto));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&writeAuto), sizeof(writeAuto));\n\t\t\t}\n\n\t\t\t// operator ==\n\t\t\tbool operator==(const command_stats_t& rhs) const {\n\t\t\t\treturn act == rhs.act &&\n\t\t\t\t\tpre == rhs.pre &&\n\t\t\t\t\tpreSameBank == rhs.preSameBank &&\n\t\t\t\t\treads == rhs.reads &&\n\t\t\t\t\twrites == rhs.writes &&\n\t\t\t\t\trefAllBank == rhs.refAllBank &&\n\t\t\t\t\trefPerBank == rhs.refPerBank &&\n\t\t\t\t\trefPerTwoBanks == rhs.refPerTwoBanks &&\n\t\t\t\t\trefSameBank == rhs.refSameBank &&\n\t\t\t\t\treadAuto == rhs.readAuto &&\n\t\t\t\t\twriteAuto == rhs.writeAuto;\n\t\t\t}\n\t\t} counter;\n\n\t\tstruct cycles_t : public util::Serialize, public util::Deserialize {\n\t\t\tuint64_t act = 0;\n\t\t\tuint64_t pre = 0;\n\t\t\tuint64_t powerDownAct = 0;\n\t\t\tuint64_t powerDownPre = 0;\n\t\t\tuint64_t selfRefresh = 0;\n\t\t\tuint64_t deepSleepMode = 0;\n\t\t\tuint64_t activeTime() const { return act; };\n\t\t\t//uint64_t prechargeTime;\n\n\t\t\tvoid serialize(std::ostream& stream) const override {\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&act), sizeof(act));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&pre), sizeof(pre));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&powerDownAct), sizeof(powerDownAct));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&powerDownPre), sizeof(powerDownPre));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&selfRefresh), sizeof(selfRefresh));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&deepSleepMode), sizeof(deepSleepMode));\n\t\t\t}\n\t\t\tvoid deserialize(std::istream& stream) override {\n\t\t\t\tstream.read(reinterpret_cast<char *>(&act), sizeof(act));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&pre), sizeof(pre));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&powerDownAct), sizeof(powerDownAct));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&powerDownPre), sizeof(powerDownPre));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&selfRefresh), sizeof(selfRefresh));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&deepSleepMode), sizeof(deepSleepMode));\n\t\t\t}\n\n\t\t\t// operator ==\n\t\t\tbool operator==(const cycles_t& rhs) const {\n\t\t\t\treturn act == rhs.act &&\n\t\t\t\t\tpre == rhs.pre &&\n\t\t\t\t\tpowerDownAct == rhs.powerDownAct &&\n\t\t\t\t\tpowerDownPre == rhs.powerDownPre &&\n\t\t\t\t\tselfRefresh == rhs.selfRefresh &&\n\t\t\t\t\tdeepSleepMode == rhs.deepSleepMode;\n\t\t\t}\n\t\t} cycles;\n\n\t\tstruct prepos_t : public util::Serialize, public util::Deserialize {\n\t\t\tuint64_t readMerged = 0;\n\t\t\tuint64_t readMergedTime = 0;\n\t\t\tuint64_t writeMerged = 0;\n\t\t\tuint64_t writeMergedTime = 0;\n\t\t\tuint64_t readSeamless = 0;\n\t\t\tuint64_t writeSeamless = 0;\n\n\t\t\tvoid serialize(std::ostream& stream) const override {\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&readMerged), sizeof(readMerged));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&readMergedTime), sizeof(readMergedTime));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&writeMerged), sizeof(writeMerged));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&writeMergedTime), sizeof(writeMergedTime));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&readSeamless), sizeof(readSeamless));\n\t\t\t\tstream.write(reinterpret_cast<const char *>(&writeSeamless), sizeof(writeSeamless));\n\t\t\t}\n\t\t\tvoid deserialize(std::istream& stream) override {\n\t\t\t\tstream.read(reinterpret_cast<char *>(&readMerged), sizeof(readMerged));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&readMergedTime), sizeof(readMergedTime));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&writeMerged), sizeof(writeMerged));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&writeMergedTime), sizeof(writeMergedTime));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&readSeamless), sizeof(readSeamless));\n\t\t\t\tstream.read(reinterpret_cast<char *>(&writeSeamless), sizeof(writeSeamless));\n\t\t\t}\n\n\t\t\t// operator ==\n\t\t\tbool operator==(const prepos_t& rhs) const {\n\t\t\t\treturn readMerged == rhs.readMerged &&\n\t\t\t\t\treadMergedTime == rhs.readMergedTime &&\n\t\t\t\t\twriteMerged == rhs.writeMerged &&\n\t\t\t\t\twriteMergedTime == rhs.writeMergedTime &&\n\t\t\t\t\treadSeamless == rhs.readSeamless &&\n\t\t\t\t\twriteSeamless == rhs.writeSeamless;\n\t\t\t}\n\t\t} prepos;\n\n\t\tvoid serialize(std::ostream& stream) const override {\n\t\t\tcounter.serialize(stream);\n\t\t\tcycles.serialize(stream);\n\t\t\tprepos.serialize(stream);\n\t\t}\n\t\tvoid deserialize(std::istream& stream) override {\n\t\t\tcounter.deserialize(stream);\n\t\t\tcycles.deserialize(stream);\n\t\t\tprepos.deserialize(stream);\n\t\t}\n\n\t\t// operator ==\n\t\tbool operator==(const CycleStats& rhs) const {\n\t\t\treturn counter == rhs.counter &&\n\t\t\t\tcycles == rhs.cycles &&\n\t\t\t\tprepos == rhs.prepos;\n\t\t}\n\t};\n\n    struct TogglingStats\n    {\n        util::bus_stats_t read;\n        util::bus_stats_t write;\n    };\n\n\tstruct SimulationStats\n\t{\n\t\tutil::bus_stats_t commandBus;\n\t\tutil::bus_stats_t readBus;\n\t\tutil::bus_stats_t writeBus;\n\t\tutil::bus_stats_t clockStats;\n\t\tutil::bus_stats_t wClockStats;\n\n\t\tutil::bus_stats_t readDBI;\n\t\tutil::bus_stats_t writeDBI;\n\n        TogglingStats togglingStats;\n\n\t\tutil::bus_stats_t readDQSStats;\n\t\tutil::bus_stats_t writeDQSStats;\n\n\t\tstd::vector<CycleStats> bank;\n\t\tstd::vector<CycleStats> rank_total;\n\n\t\t// Operator ==\n\t\tbool operator==(const SimulationStats& other) const {\n\t\t\t// Compare banks\n\t\t\tbool banksEqual = true;\n\t\t\tif (bank.size() != other.bank.size()) {\n\t\t\t\tbanksEqual = false;\n\t\t\t} else {\n\t\t\t\tfor (size_t i = 0; i < bank.size(); ++i) {\n\t\t\t\t\tif (!(bank[i] == other.bank[i])) {\n\t\t\t\t\t\tbanksEqual = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbool rank_totalEqual = true;\n\t\t\tif (rank_total.size() != other.rank_total.size()) {\n\t\t\t\trank_totalEqual = false;\n\t\t\t} else {\n\t\t\t\tfor (size_t i = 0; i < rank_total.size(); ++i) {\n\t\t\t\t\tif (!(rank_total[i] == other.rank_total[i])) {\n\t\t\t\t\t\trank_totalEqual = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn commandBus == other.commandBus &&\n\t\t\t\treadBus == other.readBus &&\n\t\t\t\twriteBus == other.writeBus &&\n\t\t\t\tclockStats == other.clockStats &&\n\t\t\t\twClockStats == other.wClockStats &&\n\t\t\t\treadDBI == other.readDBI &&\n\t\t\t\twriteDBI == other.writeDBI &&\n\t\t\t\ttogglingStats.read == other.togglingStats.read &&\n\t\t\t\ttogglingStats.write == other.togglingStats.write &&\n\t\t\t\treadDQSStats == other.readDQSStats &&\n\t\t\t\twriteDQSStats == other.writeDQSStats &&\n\t\t\t\tbanksEqual &&\n\t\t\t\trank_totalEqual;\n\t\t}\n\t};\n};\n\n\n#endif /* DRAMPOWER_DATA_STATS_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/dram/Bank.h",
    "content": "#ifndef DRAMPOWER_DDR_BANK_H\n#define DRAMPOWER_DDR_BANK_H\n\n#include <DRAMPower/data/stats.h>\n#include <DRAMPower/Types.h>\n#include <DRAMPower/util/Serialize.h>\n#include <DRAMPower/util/Deserialize.h>\n\n#include <stdint.h>\n\nnamespace DRAMPower {\n\nstruct Bank : public util::Serialize, public util::Deserialize {\npublic:\n    enum class BankState {\n        BANK_PRECHARGED = 0,\n        BANK_ACTIVE = 1,\n    };\npublic:\n    CycleStats::command_stats_t counter;\n\n    struct {\n        interval_t act;\n        interval_t powerDownAct;\n        interval_t powerDownPre;\n    } cycles;\n\n    BankState bankState;\npublic:\n    timestamp_t latestPre = 0;\n    timestamp_t refreshEndTime = 0;\n\n    void serialize(std::ostream& stream) const override {\n        stream.write(reinterpret_cast<const char *>(&bankState), sizeof(bankState));\n        stream.write(reinterpret_cast<const char *>(&latestPre), sizeof(latestPre));\n        stream.write(reinterpret_cast<const char *>(&refreshEndTime), sizeof(refreshEndTime));\n        cycles.act.serialize(stream);\n        cycles.powerDownAct.serialize(stream);\n        cycles.powerDownPre.serialize(stream);\n        counter.serialize(stream);\n    }\n    void deserialize(std::istream& stream) override {\n        stream.read(reinterpret_cast<char *>(&bankState), sizeof(bankState));\n        stream.read(reinterpret_cast<char *>(&latestPre), sizeof(latestPre));\n        stream.read(reinterpret_cast<char *>(&refreshEndTime), sizeof(refreshEndTime));\n        cycles.act.deserialize(stream);\n        cycles.powerDownAct.deserialize(stream);\n        cycles.powerDownPre.deserialize(stream);\n        counter.deserialize(stream);\n    }\n};\n\n}\n\n#endif /* DRAMPOWER_DDR_BANK_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/dram/Interface.cpp",
    "content": "#include \"Interface.h\"\n\nnamespace DRAMPower {\n\nusing namespace DRAMUtils::Config;\n\nvoid TogglingHandle::TogglingHandleLastBurst::serialize(std::ostream &stream) const\n{\n    stream.write(reinterpret_cast<const char*>(&last_length), sizeof(last_length));\n    stream.write(reinterpret_cast<const char*>(&last_load), sizeof(last_load));\n    stream.write(reinterpret_cast<const char*>(&handled), sizeof(handled));\n}\n\nvoid TogglingHandle::TogglingHandleLastBurst::deserialize(std::istream &stream) {\n    stream.read(reinterpret_cast<char*>(&last_length), sizeof(last_length));\n    stream.read(reinterpret_cast<char*>(&last_load), sizeof(last_load));\n    stream.read(reinterpret_cast<char*>(&handled), sizeof(handled));\n}\n\nTogglingHandle::TogglingHandle(const uint64_t width, const uint64_t datarate, const double toggling_rate, const double duty_cycle, const bool enabled)\n    : width(width)\n    , datarate(datarate)\n    , toggling_rate(toggling_rate)\n    , duty_cycle(duty_cycle)\n    , enableflag(enabled)\n{\n    assert(width > 0); // Check bounds\n    assert(datarate > 0); // Check bounds\n    assert(duty_cycle >= 0 && duty_cycle <= 1); // Check bounds\n    assert(toggling_rate >= 0 && toggling_rate <= 1); // Check bounds\n}\n\nTogglingHandle::TogglingHandle(const uint64_t width, const uint64_t datarate, const double toggling_rate, const double duty_cycle, DRAMUtils::Config::TogglingRateIdlePattern idlepattern, const bool enabled)\n    : width(width)\n    , datarate(datarate)\n    , toggling_rate(toggling_rate)\n    , duty_cycle(duty_cycle)\n    , enableflag(enabled)\n    , idlepattern(idlepattern)\n{\n    assert(width > 0); // Check bounds\n    assert(datarate > 0); // Check bounds\n    assert(duty_cycle >= 0 && duty_cycle <= 1); // Check bounds\n    assert(toggling_rate >= 0 && toggling_rate <= 1); // Check bounds\n}\n\nvoid TogglingHandle::disable(timestamp_t timestamp)\n{\n    timestamp_t virtualtimestamp = timestamp * this->datarate;\n    if(!this->enableflag) {\n        return;\n    }\n    if (this->last_burst) {\n        if(virtualtimestamp >= this->last_burst.last_length + this->last_burst.last_load) {\n            this->count += this->last_burst.last_length;\n        } else {\n            // Partial burst is lost\n            this->count += virtualtimestamp - this->last_burst.last_load;\n        }\n        this->last_burst.handled = true;\n    }\n    this->disable_timestamp = virtualtimestamp;\n    this->enableflag = false;\n}\n\nvoid TogglingHandle::enable(timestamp_t timestamp)\n{\n    if (this->enableflag) {\n        return;\n    }\n    this->disable_time += timestamp * this->datarate - this->disable_timestamp;\n    this->enableflag = true;\n}\n\nbool TogglingHandle::isEnabled() const\n{\n    return this->enableflag;\n}\n\ndouble TogglingHandle::getTogglingRate() const\n{\n    return this->toggling_rate;\n}\n\ndouble TogglingHandle::getDutyCycle() const\n{\n    return this->duty_cycle;\n}\nuint64_t TogglingHandle::getWidth() const\n{\n    return this->width;\n}\nvoid TogglingHandle::setWidth(const uint64_t width)\n{\n    this->width = width;\n}\nuint64_t TogglingHandle::getDatarate() const\n{\n    return this->datarate;\n}\nvoid TogglingHandle::setDataRate(const uint64_t datarate)\n{\n    this->datarate = datarate;\n}\n\nvoid TogglingHandle::setTogglingRateAndDutyCycle(const double toggling_rate, const double duty_cycle, const TogglingRateIdlePattern idlepattern)\n{\n    this->toggling_rate = toggling_rate;\n    this->duty_cycle = duty_cycle;\n    this->idlepattern = idlepattern;\n}\nuint64_t TogglingHandle::getCount() const\n{\n    return this->count;\n}\n\n// Returns timestamp of last burst\ntimestamp_t TogglingHandle::get_lastburst_timestamp(bool relative_to_clock) const\n{\n    timestamp_t lastburst = this->last_burst.last_load + this->last_burst.last_length;\n    if (relative_to_clock) {\n        auto remainder = lastburst % this->datarate;\n        if (remainder != 0) {\n            lastburst += this->datarate - remainder;\n        }\n        return lastburst / this->datarate;\n    }\n    return lastburst;\n}\n\nvoid TogglingHandle::incCountBurstLength(timestamp_t timestamp, uint64_t burstlength)\n{\n    // Convert to bus timings\n    timestamp_t virtual_timestamp = timestamp * this->datarate;\n    assert(virtual_timestamp / this->datarate == timestamp); // No overflow\n    assert(\n        (this->last_burst && (virtual_timestamp >= (this->last_burst.last_length + this->last_burst.last_load)))\n        || !this->last_burst\n    );\n    // Add last burst\n    if (!this->last_burst.handled) {\n        // Add last burst to count\n        this->count += this->last_burst.last_length;\n    }\n    // Store burst in last_length and last_load if enabled\n    if (this->enableflag) {\n        // Set last_length and last_load to new burst_length\n        this->last_burst = TogglingHandleLastBurst {\n            burstlength, // last_length\n            virtual_timestamp,   // last_load\n            false // handled\n        };\n    } else {\n        // Clear last_burst\n        this->last_burst.handled = true;\n    }\n}\nvoid TogglingHandle::incCountBitLength(timestamp_t timestamp, uint64_t bitlength)\n{\n    assert(bitlength % this->width == 0);\n    this->incCountBurstLength(timestamp, bitlength / this->width);\n}\nutil::bus_stats_t TogglingHandle::get_stats(timestamp_t timestamp) const\n{\n    // Convert to bus timings\n    timestamp_t virtual_timestamp = timestamp * this->datarate;\n    assert(virtual_timestamp / this->datarate == timestamp); // No overflow\n\n    util::bus_stats_t stats;\n\n    uint64_t count = this->count;\n    timestamp_t disable_time = this->disable_time;\n    if(this->enableflag) {\n        // Check if last burst is finished\n        if ((this->last_burst)\n            && (virtual_timestamp < this->last_burst.last_length + this->last_burst.last_load)\n        ) {\n            // last burst not finished\n            count += virtual_timestamp - this->last_burst.last_load;\n        } else if (this->last_burst) {\n            // last burst finished\n            count += this->last_burst.last_length;\n        }\n    } else {\n        disable_time += virtual_timestamp - this->disable_timestamp;\n    }\n    // Compute toggles\n    stats.ones = count * this->duty_cycle;\n    stats.zeroes = count * (1 - this->duty_cycle);\n    stats.ones_to_zeroes = count * this->toggling_rate / 2; // Round down\n    // Compute idle\n    switch (this->idlepattern) {\n        case TogglingRateIdlePattern::L:\n            stats.zeroes += virtual_timestamp - disable_time - count;\n            break;\n        case TogglingRateIdlePattern::H:\n            stats.ones += virtual_timestamp - disable_time - count;\n            break;\n        case TogglingRateIdlePattern::Invalid:\n            assert(false); // Fallback to Z\n        case TogglingRateIdlePattern::Z:\n            // Nothing to do in high impedance mode\n            break;\n    }\n    // Scale by bus width\n    stats.ones *= this->width;\n    stats.zeroes *= this->width;\n    stats.ones_to_zeroes *= this->width;\n    // Compute zeroes_to_ones and bit changes\n    stats.zeroes_to_ones = stats.ones_to_zeroes;\n    stats.bit_changes = stats.ones_to_zeroes + stats.zeroes_to_ones;\n    return stats;\n}\n\nvoid TogglingHandle::serialize(std::ostream &stream) const {\n    stream.write(reinterpret_cast<const char*>(&width), sizeof(width));\n    stream.write(reinterpret_cast<const char*>(&datarate), sizeof(datarate));\n    stream.write(reinterpret_cast<const char*>(&toggling_rate), sizeof(toggling_rate));\n    stream.write(reinterpret_cast<const char*>(&duty_cycle), sizeof(duty_cycle));\n    last_burst.serialize(stream);\n    stream.write(reinterpret_cast<const char*>(&enableflag), sizeof(enableflag));\n    stream.write(reinterpret_cast<const char*>(&count), sizeof(count));\n    stream.write(reinterpret_cast<const char*>(&disable_timestamp), sizeof(disable_timestamp));\n    stream.write(reinterpret_cast<const char*>(&disable_time), sizeof(disable_time));\n    stream.write(reinterpret_cast<const char*>(&idlepattern), sizeof(idlepattern));\n}\n\nvoid TogglingHandle::deserialize(std::istream &stream) {\n    stream.read(reinterpret_cast<char*>(&width), sizeof(width));\n    stream.read(reinterpret_cast<char*>(&datarate), sizeof(datarate));\n    stream.read(reinterpret_cast<char*>(&toggling_rate), sizeof(toggling_rate));\n    stream.read(reinterpret_cast<char*>(&duty_cycle), sizeof(duty_cycle));\n    last_burst.deserialize(stream);\n    stream.read(reinterpret_cast<char*>(&enableflag), sizeof(enableflag));\n    stream.read(reinterpret_cast<char*>(&count), sizeof(count));\n    stream.read(reinterpret_cast<char*>(&disable_timestamp), sizeof(disable_timestamp));\n    stream.read(reinterpret_cast<char*>(&disable_time), sizeof(disable_time));\n    stream.read(reinterpret_cast<char*>(&idlepattern), sizeof(idlepattern));\n}\n\n} // namespace DRAMPower"
  },
  {
    "path": "src/DRAMPower/DRAMPower/dram/Interface.h",
    "content": "#ifndef DRAMPOWER_DDR_INTERFACE_H\n#define DRAMPOWER_DDR_INTERFACE_H\n\n#pragma once \n\n#include <DRAMPower/Types.h>\n#include <DRAMPower/util/bus.h>\n#include <DRAMPower/util/Serialize.h>\n#include <DRAMPower/util/Deserialize.h>\n\n#include <DRAMUtils/config/toggling_rate.h>\n\n#include <stdint.h>\n#include <optional>\n\n\nnamespace DRAMPower {\n\nclass TogglingHandle : public util::Serialize, public util::Deserialize\n{\n\nstruct TogglingHandleLastBurst  : public util::Serialize, public util::Deserialize {\n    uint64_t last_length = 0;\n    timestamp_t last_load = 0;\n    bool handled = true;\n    TogglingHandleLastBurst() = default;\n    TogglingHandleLastBurst(uint64_t last_length, timestamp_t last_load, bool handled)\n        : last_length(last_length), last_load(last_load), handled(handled) {}\n    operator bool() const { return !this->handled; }\n    void serialize(std::ostream &stream) const override;\n    void deserialize(std::istream &stream) override;\n};\n\nprivate:\n    uint64_t width = 0;\n    uint64_t datarate = 1;\n    double toggling_rate = 0; // [0, 1] allowed\n    double duty_cycle = 0.0; // [0, 1] allowed\n    TogglingHandleLastBurst last_burst;\n    bool enableflag = false; // default disabled if default constructor is used\n    uint64_t count = 0;\n    timestamp_t disable_timestamp = 0;\n    timestamp_t disable_time = 0;\n    DRAMUtils::Config::TogglingRateIdlePattern idlepattern = DRAMUtils::Config::TogglingRateIdlePattern::Z;\n\npublic:\nTogglingHandle(const uint64_t width, const uint64_t datarate, const double toggling_rate, const double duty_cycle, const bool enabled = true);\nTogglingHandle(const uint64_t width, const uint64_t datarate, const double toggling_rate, const double duty_cycle, DRAMUtils::Config::TogglingRateIdlePattern idlepattern, const bool enabled = true);\n\n    TogglingHandle() = default;\npublic:\n// Getters and Setters\n    double getTogglingRate() const;\n    double getDutyCycle() const;\n    bool isEnabled() const;\n    uint64_t getWidth() const;\n    uint64_t getDatarate() const;\n    timestamp_t get_lastburst_timestamp(bool relative_to_clock = true) const;\n    \n    void setTogglingRateAndDutyCycle(const double toggling_rate, const double duty_cycle, const DRAMUtils::Config::TogglingRateIdlePattern idlepattern);\n    void disable(timestamp_t timestamp);\n    void enable(timestamp_t timestamp);\n    void setWidth(const uint64_t width);\n    void setDataRate(const uint64_t datarate);\n    uint64_t getCount() const;\npublic:\n    void incCountBurstLength(timestamp_t timestamp, uint64_t burstlength);\n    void incCountBitLength(timestamp_t timestamp, uint64_t bitlength);\n    util::bus_stats_t get_stats(timestamp_t timestamp) const;\n\n// Overrides\n    void serialize(std::ostream &stream) const override;\n    void deserialize(std::istream &stream) override;\n\n};\n\nstruct interface_stats_t \n{\n    util::bus_stats_t command_bus;\n    util::bus_stats_t read_bus;\n    util::bus_stats_t write_bus;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_DDR_INTERFACE_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/dram/Rank.cpp",
    "content": "#include \"Rank.h\"\n\n#include <algorithm>\n\nnamespace DRAMPower {\n\nRank::Rank(std::size_t numBanks)\n    : banks(numBanks)\n{};\n\nbool Rank::isActive(timestamp_t timestamp) {\n    if ( timestamp < this->endRefreshTime ) {\n        std::cout << \"[WARN] Rank::isActive() -> timestamp (\" << timestamp <<\") < \"  << \"endRefreshTime (\" << this->endRefreshTime << \")\"  << std::endl;\n    }\n    return countActiveBanks() > 0 || timestamp < this->endRefreshTime;\n}\n\nstd::size_t Rank::countActiveBanks() const {\n    return (unsigned)std::count_if(banks.begin(), banks.end(),\n        [](const auto& bank) {\n            return (bank.bankState == Bank::BankState::BANK_ACTIVE);\n    });\n}\n\nvoid Rank::serialize(std::ostream& stream) const {\n    stream.write(reinterpret_cast<const char*>(&memState), sizeof(memState));\n    stream.write(reinterpret_cast<const char *>(&endRefreshTime), sizeof(endRefreshTime));\n    commandCounter.serialize(stream);\n\n    stream.write(reinterpret_cast<const char* >(&counter.selfRefresh), sizeof(counter.selfRefresh));\n    stream.write(reinterpret_cast<const char* >(&counter.deepSleepMode), sizeof(counter.deepSleepMode));\n    stream.write(reinterpret_cast<const char* >(&endRefreshTime), sizeof(endRefreshTime));\n    cycles.pre.serialize(stream);\n    cycles.act.serialize(stream);\n    cycles.ref.serialize(stream);\n    cycles.sref.serialize(stream);\n    cycles.powerDownAct.serialize(stream);\n    cycles.powerDownPre.serialize(stream);\n    cycles.deepSleepMode.serialize(stream);\n\n    for (const auto& bank : banks) {\n        bank.serialize(stream);\n    }\n};\n\nvoid Rank::deserialize(std::istream& stream) {\n    stream.read(reinterpret_cast<char *>(&memState), sizeof(memState));\n    stream.read(reinterpret_cast<char *>(&endRefreshTime), sizeof(endRefreshTime));\n    commandCounter.deserialize(stream);\n\n    stream.read(reinterpret_cast<char* >(&counter.selfRefresh), sizeof(counter.selfRefresh));\n    stream.read(reinterpret_cast<char* >(&counter.deepSleepMode), sizeof(counter.deepSleepMode));\n    stream.read(reinterpret_cast<char* >(&endRefreshTime), sizeof(endRefreshTime));\n    cycles.pre.deserialize(stream);\n    cycles.act.deserialize(stream);\n    cycles.ref.deserialize(stream);\n    cycles.sref.deserialize(stream);\n    cycles.powerDownAct.deserialize(stream);\n    cycles.powerDownPre.deserialize(stream);\n    cycles.deepSleepMode.deserialize(stream);\n\n    for (auto & bank : banks) {\n        bank.deserialize(stream);\n    }\n};\n\n\nvoid RankInterface::serialize(std::ostream& stream) const {\n    stream.write(reinterpret_cast<const char*>(&seamlessPrePostambleCounter_read), sizeof(seamlessPrePostambleCounter_read));\n    stream.write(reinterpret_cast<const char*>(&seamlessPrePostambleCounter_write), sizeof(seamlessPrePostambleCounter_write));\n    stream.write(reinterpret_cast<const char*>(&mergedPrePostambleCounter_read), sizeof(mergedPrePostambleCounter_read));\n    stream.write(reinterpret_cast<const char*>(&mergedPrePostambleCounter_write), sizeof(mergedPrePostambleCounter_write));\n    stream.write(reinterpret_cast<const char*>(&mergedPrePostambleTime_read), sizeof(mergedPrePostambleTime_read));\n    stream.write(reinterpret_cast<const char*>(&mergedPrePostambleTime_write), sizeof(mergedPrePostambleTime_write));\n    stream.write(reinterpret_cast<const char*>(&lastReadEnd), sizeof(lastReadEnd));\n    stream.write(reinterpret_cast<const char*>(&lastWriteEnd), sizeof(lastWriteEnd));\n}\nvoid RankInterface::deserialize(std::istream& stream) {\n    stream.read(reinterpret_cast<char*>(&seamlessPrePostambleCounter_read), sizeof(seamlessPrePostambleCounter_read));\n    stream.read(reinterpret_cast<char*>(&seamlessPrePostambleCounter_write), sizeof(seamlessPrePostambleCounter_write));\n    stream.read(reinterpret_cast<char*>(&mergedPrePostambleCounter_read), sizeof(mergedPrePostambleCounter_read));\n    stream.read(reinterpret_cast<char*>(&mergedPrePostambleCounter_write), sizeof(mergedPrePostambleCounter_write));\n    stream.read(reinterpret_cast<char*>(&mergedPrePostambleTime_read), sizeof(mergedPrePostambleTime_read));\n    stream.read(reinterpret_cast<char*>(&mergedPrePostambleTime_write), sizeof(mergedPrePostambleTime_write));\n    stream.read(reinterpret_cast<char*>(&lastReadEnd), sizeof(lastReadEnd));\n    stream.read(reinterpret_cast<char*>(&lastWriteEnd), sizeof(lastWriteEnd));\n}\n\n} // namespace DRAMPower"
  },
  {
    "path": "src/DRAMPower/DRAMPower/dram/Rank.h",
    "content": "#ifndef DRAMPOWER_DDR_RANK_H\n#define DRAMPOWER_DDR_RANK_H\n\n#include <DRAMPower/util/command_counter.h>\n#include <DRAMPower/command/CmdType.h>\n#include <DRAMPower/dram/Bank.h>\n#include <DRAMPower/Types.h>\n\n#include <DRAMPower/util/Serialize.h>\n#include <DRAMPower/util/Deserialize.h>\n\n#include <vector>\n\nnamespace DRAMPower {\n\n// Power-Down and Self-refresh related memory states\nenum class MemState {\n\tNOT_IN_PD = 0,\n\tPDN_ACT,\n\tPDN_PRE,\n\tSREF,\n\tDSM,\n};\n\n\nstruct Rank : public util::Serialize, public util::Deserialize {\n\n// Type aliases\n\tusing commandCounter_t = util::CommandCounter<CmdType>;\n\npublic:\n// Variables\n\tMemState memState = MemState::NOT_IN_PD;\n\tcommandCounter_t commandCounter;\n\tstruct {\n\t\tinterval_t pre; // useful ???\n\t\tinterval_t act;\n\t\tinterval_t ref;\n\t\tinterval_t sref;\n\t\tinterval_t powerDownAct;\n\t\tinterval_t powerDownPre;\n\t\tinterval_t deepSleepMode;\n\t} cycles;\n\tstruct {\n\t\tuint64_t selfRefresh = 0;\n\t\tuint64_t deepSleepMode = 0;\n\t} counter = { 0 };\n\ttimestamp_t endRefreshTime = 0;\n\tstd::vector<Bank> banks;\n\npublic:\n// Constructors\n\tRank(std::size_t numBanks);\n\n// Functions\npublic:\n\tbool isActive(timestamp_t timestamp);\n\tstd::size_t countActiveBanks() const;\n// Overrides\n\tvoid serialize(std::ostream& stream) const override;\n\tvoid deserialize(std::istream& stream) override;\n};\n\nstruct RankInterface : public util::Serialize, public util::Deserialize {\n\tuint64_t \tseamlessPrePostambleCounter_read\t= 0;\n\tuint64_t \tseamlessPrePostambleCounter_write\t= 0;\n\tuint64_t\tmergedPrePostambleCounter_read\t\t= 0;\n\tuint64_t\tmergedPrePostambleCounter_write\t\t= 0;\n\ttimestamp_t\tmergedPrePostambleTime_read\t\t\t= 0;\n\ttimestamp_t\tmergedPrePostambleTime_write\t\t= 0;\n\ttimestamp_t lastReadEnd = 0;\n\ttimestamp_t lastWriteEnd = 0;\n\n// Overrides\n\tvoid serialize(std::ostream& stream) const override;\n\tvoid deserialize(std::istream& stream) override;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_DDR_RANK_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/dram/dram_base.h",
    "content": "#ifndef DRAMPOWER_DRAM_DRAM_BASE_H\n#define DRAMPOWER_DRAM_DRAM_BASE_H\n\n#include <DRAMPower/command/Command.h>\n\n#include <DRAMPower/data/energy.h>\n#include <DRAMPower/data/stats.h>\n#include <DRAMPower/util/extension_manager.h>\n#include <DRAMPower/util/extensions.h>\n\n#include <DRAMPower/util/Router.h>\n#include <DRAMPower/util/PatternHandler.h>\n#include <DRAMPower/util/ImplicitCommandHandler.h>\n#include <DRAMPower/util/cli_architecture_config.h>\n#include <DRAMPower/util/Serialize.h>\n#include <DRAMPower/util/Deserialize.h>\n\n#include <DRAMUtils/config/toggling_rate.h>\n\n#include <cassert>\n#include <vector>\n\nnamespace DRAMPower {\n\nusing namespace DRAMUtils::Config;\n\ntemplate <typename CommandEnum>\nclass dram_base : public util::Serialize, public util::Deserialize\n{\n// Public type definitions\npublic:\n    using commandEnum_t = CommandEnum;\n    using commandCount_t = std::vector<std::size_t>;\n    // ExtensionManager\n    using extension_manager_t = util::extension_manager::ExtensionManager<\n        extensions::Base\n    >;\n\n// Public constructors and assignment operators\npublic:\n    dram_base(const dram_base&) = default; // copy constructor\n    dram_base& operator=(const dram_base&) = default; // copy assignment operator\n    dram_base(dram_base&&) = default; // Move constructor\n    dram_base& operator=(dram_base&&) = default; // Move assignment operator\n    virtual ~dram_base() = 0;\n// Protected constructors\nprotected:\n    dram_base() = default;\n\n// Public member functions\npublic:\n    // ExtensionManager\n    extension_manager_t& getExtensionManager() { return m_extensionManager; }\n    const extension_manager_t& getExtensionManager() const { return m_extensionManager; }\n\n    void doCoreCommand(const Command& command) {\n        doCoreCommandImpl(command);\n    }\n    \n    void doInterfaceCommand(const Command& command) {\n        doInterfaceCommandImpl(command);\n    }\n\n    void doCommand(const Command& command) {\n        doCoreCommandImpl(command);\n        doInterfaceCommandImpl(command);\n    }\n\n    // deprecated\n    void doCoreInterfaceCommand(const Command& command) {\n        doCommand(command);\n    }\n\n    timestamp_t getLastCommandTime() const {\n        return getLastCommandTime_impl();\n    }\n\n    double getTotalEnergy(timestamp_t timestamp) {\n        return calcCoreEnergy(timestamp).total() + calcInterfaceEnergy(timestamp).total();\n    };\n\n    SimulationStats getStats() {\n        return getWindowStats(getLastCommandTime());\n    }\n\n    void serialize(std::ostream& stream) const override {\n        // Serialize the extension manager\n        m_extensionManager.serialize(stream);\n        serialize_impl(stream);\n    }\n\n    void deserialize(std::istream& stream) override {\n        // Deserialize the extension manager\n        m_extensionManager.deserialize(stream);\n        deserialize_impl(stream);\n    }\n\n// Public virtual methods\npublic:\n    virtual energy_t calcCoreEnergyStats(const SimulationStats& stats) const = 0;\n    energy_t calcCoreEnergy(timestamp_t timestamp) {\n        return calcCoreEnergyStats(getWindowStats(timestamp));\n    }\n    virtual interface_energy_info_t calcInterfaceEnergyStats(const SimulationStats& stats) const = 0;\n    interface_energy_info_t calcInterfaceEnergy(timestamp_t timestamp) {\n        return calcInterfaceEnergyStats(getWindowStats(timestamp));\n    }\n    virtual SimulationStats getWindowStats(timestamp_t timestamp) = 0;\n    virtual util::CLIArchitectureConfig getCLIArchitectureConfig() = 0;\n    virtual bool isSerializable() const = 0;\n\n// Private virtual methods\nprivate:\n    virtual void doCoreCommandImpl(const Command& command) = 0;\n    virtual void doInterfaceCommandImpl(const Command& command) = 0;\n    virtual timestamp_t getLastCommandTime_impl() const = 0;\n    virtual void serialize_impl(std::ostream& stream) const = 0;\n    virtual void deserialize_impl(std::istream& stream) = 0;\n\n// Private member variables\nprivate:\n    extension_manager_t m_extensionManager;\n};\n\ntemplate <typename CommandEnum>\ndram_base<CommandEnum>::~dram_base() = default;\n\n}\n\n#endif /* DRAMPOWER_DDR_DRAM_BASE_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/memspec/MemSpec.h",
    "content": "/*\n * Copyright (c) 2015-2020, University of Kaiserslautern\n * Copyright (c) 2012-2021, Fraunhofer IESE\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * 3. Neither the name of the copyright holder nor the names of its\n *    contributors may be used to endorse or promote products derived from\n *    this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER\n * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * Authors:\n *    Janik Schlemminger\n *    Matthias Jung\n *    Lukas Steiner\n *    Luiza Correa\n */\n\n#ifndef DRAMPOWER_MEMSPEC_MEMSPEC_H\n#define DRAMPOWER_MEMSPEC_MEMSPEC_H\n\n#include <DRAMPower/command/CmdType.h>\n\n#include <DRAMUtils/util/json_utils.h>\n#include <DRAMUtils/util/types.h>\n#include <DRAMUtils/memspec/MemSpec.h>\n\n#include <vector>\n#include <algorithm>\n\n\nnamespace DRAMPower {\n\ntemplate <typename T>\nclass MemSpec\n{\n    T rawmemspec;\npublic:\n    uint64_t numberOfBanks;\n\tuint64_t numberOfRows;\n\tuint64_t numberOfColumns;\n\tuint64_t numberOfDevices;   // Number of devices per rank\n\tuint64_t burstLength;\n\tuint64_t dataRate;\n\tuint64_t bitWidth;\n\n    /* MEMSPEC specific parameters\n    unsigned numberOfBankGroups;\n    unsigned numberOfDevicesOnDIMM;\n    unsigned numberOfRanks;\n    unsigned banksPerRank;\n    unsigned groupsPerRank;\n    unsigned banksPerGroup;\n    unsigned numberOfChannels;\n    */\n\n    std::string memoryId;\n    std::string memoryType;\n\n\n    uint64_t prechargeOffsetRD;\n    uint64_t prechargeOffsetWR;\n    MemSpec() = delete;\n    virtual ~MemSpec() = default;\n\n\t// MemSpec() = default;\n    MemSpec(const T &memspec) : rawmemspec(memspec)\n    {\n        numberOfBanks = memspec.memarchitecturespec.nbrOfBanks;\n        numberOfRows = memspec.memarchitecturespec.nbrOfRows;\n        numberOfColumns = memspec.memarchitecturespec.nbrOfColumns;\n        numberOfDevices = memspec.memarchitecturespec.nbrOfDevices;\n        if (numberOfDevices < 1)\n        {\n            numberOfDevices = 1;\n        }\n        burstLength = memspec.memarchitecturespec.burstLength;\n        dataRate = memspec.memarchitecturespec.dataRate;\n        bitWidth = memspec.memarchitecturespec.width;\n        memoryId = memspec.memoryId;\n        memoryType = memspec.id;\n    }\n\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_MEMSPEC_MEMSPEC_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/memspec/MemSpecDDR4.cpp",
    "content": "/*\n * Copyright (c) 2019, University of Kaiserslautern\n * Copyright (c) 2012-2021, Fraunhofer IESE\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * 3. Neither the name of the copyright holder nor the names of its\n *    contributors may be used to endorse or promote products derived from\n *    this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER\n * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * Authors:\n *    Lukas Steiner\n *    Luiza Correa\n */\n\n#include \"MemSpecDDR4.h\"\nusing namespace DRAMPower;\n\n\nMemSpecDDR4::MemSpecDDR4(const DRAMUtils::MemSpec::MemSpecDDR4 &memspec)\n    : MemSpec(memspec)\n{\n\n    numberOfBankGroups     = memspec.memarchitecturespec.nbrOfBankGroups;\n    numberOfRanks          = memspec.memarchitecturespec.nbrOfRanks;\n\n    memTimingSpec.tCK      = memspec.memtimingspec.tCK;\n    memTimingSpec.tRAS     = memspec.memtimingspec.RAS;\n    memTimingSpec.tRCD     = memspec.memtimingspec.RCD;\n    memTimingSpec.tRTP     = memspec.memtimingspec.RTP;\n    memTimingSpec.tWL      = memspec.memtimingspec.WL;\n    memTimingSpec.tWR      = memspec.memtimingspec.WR;\n    memTimingSpec.tRP      = memspec.memtimingspec.RP;\n    memTimingSpec.tAL      = memspec.memtimingspec.AL;\n\n\n    auto VDD = VoltageDomain::VDD;\n    auto VPP = VoltageDomain::VPP;\n\n    memPowerSpec.push_back(MemPowerSpec());\n\n    memPowerSpec[VDD].vXX       = memspec.mempowerspec.vdd;\n    memPowerSpec[VDD].iXX0      = memspec.mempowerspec.idd0;\n    memPowerSpec[VDD].iXX2N     = memspec.mempowerspec.idd2n;\n    memPowerSpec[VDD].iXX3N     = memspec.mempowerspec.idd3n;\n    memPowerSpec[VDD].iXX4R     = memspec.mempowerspec.idd4r;\n    memPowerSpec[VDD].iXX4W     = memspec.mempowerspec.idd4w;\n    memPowerSpec[VDD].iXX6N     = memspec.mempowerspec.idd6n;\n    memPowerSpec[VDD].iXX2P     = memspec.mempowerspec.idd2p;\n    memPowerSpec[VDD].iXX3P     = memspec.mempowerspec.idd3p;\n\n    memPowerSpec.push_back(MemPowerSpec());\n\n    memPowerSpec[VPP].vXX       = memspec.mempowerspec.vpp;\n    memPowerSpec[VPP].iXX0      = memspec.mempowerspec.ipp0;\n    memPowerSpec[VPP].iXX2N     = memspec.mempowerspec.ipp2n;\n    memPowerSpec[VPP].iXX3N     = memspec.mempowerspec.ipp3n;\n    memPowerSpec[VPP].iXX4R     = memspec.mempowerspec.ipp4r;\n    memPowerSpec[VPP].iXX4W     = memspec.mempowerspec.ipp4w;\n    memPowerSpec[VPP].iXX6N     = memspec.mempowerspec.ipp6n;\n    memPowerSpec[VPP].iXX2P     = memspec.mempowerspec.ipp2p;\n    memPowerSpec[VPP].iXX3P     = memspec.mempowerspec.ipp3p;\n\n    vddq = memspec.mempowerspec.vddq;\n\n    if (DRAMUtils::MemSpec::RefModeTypeDDR4::REF_MODE_2 == memspec.memarchitecturespec.RefMode) {\n        memPowerSpec[VDD].iXX5X      = memspec.mempowerspec.idd5F2;\n        memPowerSpec[VPP].iXX5X      = memspec.mempowerspec.ipp5F2;\n        memTimingSpec.tRFC = memspec.memtimingspec.RFC2;\n    } else if (DRAMUtils::MemSpec::RefModeTypeDDR4::REF_MODE_4 == memspec.memarchitecturespec.RefMode) {\n        memPowerSpec[VDD].iXX5X      = memspec.mempowerspec.idd5F4;\n        memPowerSpec[VPP].iXX5X      = memspec.mempowerspec.ipp5F4;\n        memTimingSpec.tRFC = memspec.memtimingspec.RFC4;\n    } else {\n        // RefModeTypeDDR4::REF_MODE_1 || RefModeTypeDDR4::INVALID\n        memPowerSpec[VDD].iXX5X      = memspec.mempowerspec.idd5B;\n        memPowerSpec[VPP].iXX5X      = memspec.mempowerspec.ipp5B;\n        memTimingSpec.tRFC = memspec.memtimingspec.RFC1;\n    }\n    memPowerSpec[VDD].iBeta = memspec.mempowerspec.iBeta_vdd.value_or(memspec.mempowerspec.idd0);\n    memPowerSpec[VPP].iBeta = memspec.mempowerspec.iBeta_vpp.value_or(memspec.mempowerspec.ipp0);\n\n    if(memspec.bankwisespec.has_value())\n    {\n        bwParams.bwPowerFactRho = memspec.bankwisespec.value().factRho.value_or(1);\n    }\n    else\n    {\n        bwParams.bwPowerFactRho = 1;\n    }\n\n    memTimingSpec.tBurst = burstLength/dataRate;\n    prechargeOffsetRD      =  memTimingSpec.tAL + memTimingSpec.tRTP;\n    prechargeOffsetWR      =  memTimingSpec.tBurst + memTimingSpec.tWL + memTimingSpec.tWR;\n\n    parseImpedanceSpec(memspec);\n    parsePrePostamble(memspec);\n}\n\nvoid MemSpecDDR4::parseImpedanceSpec(const DRAMUtils::MemSpec::MemSpecDDR4 &memspec) {\n    memImpedanceSpec = memspec.memimpedancespec;\n}\n\nvoid MemSpecDDR4::parsePrePostamble(const DRAMUtils::MemSpec::MemSpecDDR4 &memspec)\n{\n    prePostamble.read_zeroes = memspec.prepostamble.read_zeroes;\n    prePostamble.write_zeroes = memspec.prepostamble.write_zeroes;\n    prePostamble.read_ones = memspec.prepostamble.read_ones;\n    prePostamble.write_ones = memspec.prepostamble.write_ones;\n    prePostamble.read_zeroes_to_ones = memspec.prepostamble.read_zeroes_to_ones;\n    prePostamble.write_zeroes_to_ones = memspec.prepostamble.write_zeroes_to_ones;\n    prePostamble.write_ones_to_zeroes = memspec.prepostamble.write_ones_to_zeroes;\n    prePostamble.read_ones_to_zeroes = memspec.prepostamble.read_ones_to_zeroes;\n    prePostamble.readMinTccd = memspec.prepostamble.readMinTccd;\n    prePostamble.writeMinTccd = memspec.prepostamble.writeMinTccd;;\n}\n\nMemSpecDDR4 MemSpecDDR4::from_memspec(const DRAMUtils::MemSpec::MemSpecVariant& memSpec)\n{\n    return std::get<DRAMUtils::MemSpec::MemSpecDDR4>(memSpec.getVariant());\n}\n\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/memspec/MemSpecDDR4.h",
    "content": "/*\n* Copyright (c) 2019, University of Kaiserslautern\n* Copyright (c) 2012-2021, Fraunhofer IESE\n* All rights reserved.\n*\n* Redistribution and use in source and binary forms, with or without\n* modification, are permitted provided that the following conditions are\n* met:\n*\n* 1. Redistributions of source code must retain the above copyright notice,\n*    this list of conditions and the following disclaimer.\n*\n* 2. Redistributions in binary form must reproduce the above copyright\n*    notice, this list of conditions and the following disclaimer in the\n*    documentation and/or other materials provided with the distribution.\n*\n* 3. Neither the name of the copyright holder nor the names of its\n*    contributors may be used to endorse or promote products derived from\n*    this software without specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n* \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER\n* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*\n* Authors:\n*    Lukas Steiner\n*    Luiza Correa\n*/\n\n#ifndef DRAMPOWER_MEMSPEC_MEMSPECDDR4_H\n#define DRAMPOWER_MEMSPEC_MEMSPECDDR4_H\n\n#include \"MemSpec.h\"\n\n#include <DRAMUtils/memspec/standards/MemSpecDDR4.h>\n\n#include <DRAMUtils/util/json.h>\n\n\nnamespace DRAMPower {\n\nclass MemSpecDDR4 final : public MemSpec<DRAMUtils::MemSpec::MemSpecDDR4>\n{\npublic:\n\tusing MemImpedanceSpec = DRAMUtils::MemSpec::MemImpedanceSpecTypeDDR4;\n\n    enum VoltageDomain {\n        VDD = 0,\n        VPP = 1,\n    };\n\npublic:\n    MemSpecDDR4() = delete;\n    \n\tMemSpecDDR4(const DRAMUtils::MemSpec::MemSpecDDR4 &memspec);\n\n\tMemSpecDDR4(json_t &data) = delete;\n\tMemSpecDDR4(const json_t &data) = delete;\n\n    // Copy constructor and assignment operator\n    MemSpecDDR4(const MemSpecDDR4&) = default;\n\tMemSpecDDR4& operator=(const MemSpecDDR4&) = default;\n\n    // Move constructor and assignment operator\n    MemSpecDDR4(MemSpecDDR4&&) = default;\n\tMemSpecDDR4& operator=(MemSpecDDR4&&) = default;\n\n\tuint64_t numberOfBankGroups;\n\tuint64_t numberOfRanks;\n\n\tdouble vddq;\n\n\t// Memspec Variables:\n\tstruct MemTimingSpec \n\t{\n\t\tdouble fck;\n\t\tdouble tCK;\n\t\tuint64_t tRAS;\n\t\tuint64_t tRCD;\n\t\tuint64_t tRL;\n\t\tuint64_t tRTP;\n\t\tuint64_t tWL;\n\t\tuint64_t tWR;\n\t\tuint64_t tRFC;\n\t\tuint64_t tRP;\n\t\tuint64_t tAL;\n        uint64_t tBurst;\n\t};\n\n\t// Currents and Voltages:\n\tstruct MemPowerSpec \n\t{\n\t\tdouble iXX0;\n\t\tdouble iXX2N;\n\t\tdouble iXX3N;\n\t\tdouble iXX4R;\n\t\tdouble iXX4W;\n\t\tdouble iXX5X;\n\t\tdouble iXX6N;\n\t\tdouble vXX;\n\t\tdouble iXX2P;\n\t\tdouble iXX3P;\n        double iBeta;\n\t};\n\n\tstruct BankWiseParams \n\t{\n        // ACT Standby power factor\n        double bwPowerFactRho;\n\t};\n\n\t// Pre and Postamble\n\t// Total number of zero cycles relative to tCK (one cycle = tCK) for example, if tCK = 1ns, and read_zeroes = 2.5, then the total time is 2.5ns\n\tstruct PrePostamble\n\t{\n\t\t// Total number of zero/one cycles per DQs differential pair\n\t\t// relative to tCK (one cycle = tCK)\n\t\t// for example, if tCK = 1ns, and read_zeroes = 2.5, then the total time is 2.5ns\n\t\tdouble read_zeroes;\n\t\tdouble write_zeroes;\n\t\tdouble read_ones;\n\t\tdouble write_ones;\n\n\t\t// Total number of zero to one and one to zero transitions per DQs differential pair\n\t\tuint64_t read_zeroes_to_ones;\n\t\tuint64_t write_zeroes_to_ones;\n\t\tuint64_t write_ones_to_zeroes;\n\t\tuint64_t read_ones_to_zeroes;\n\n\t\t// Minimum time interval between two consecutive read/write commands to prevent merging or seamless transition.\n\t\tuint64_t readMinTccd;\n\t\tuint64_t writeMinTccd;\n\t};\n\n    uint64_t refreshMode;\n\tMemTimingSpec memTimingSpec;\n\tstd::vector<MemPowerSpec> memPowerSpec;\n\tMemImpedanceSpec memImpedanceSpec;\n\tPrePostamble prePostamble;\n\tBankWiseParams bwParams;\nprivate:\n\tvoid parseImpedanceSpec(const DRAMUtils::MemSpec::MemSpecDDR4 &memspec);\n\tvoid parsePrePostamble(const DRAMUtils::MemSpec::MemSpecDDR4 &memspec);\npublic:\n    static MemSpecDDR4 from_memspec(const DRAMUtils::MemSpec::MemSpecVariant&);\n    \n};\n\n}\n#endif /* DRAMPOWER_MEMSPEC_MEMSPECDDR4_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/memspec/MemSpecDDR5.cpp",
    "content": "#include \"MemSpecDDR5.h\"\nusing namespace DRAMPower;\n\n\nMemSpecDDR5::MemSpecDDR5(const DRAMUtils::MemSpec::MemSpecDDR5 &memspec)\n        : MemSpec(memspec)\n{\n    numberOfBankGroups      = memspec.memarchitecturespec.nbrOfBankGroups;\n    numberOfRanks           = memspec.memarchitecturespec.nbrOfRanks;\n    banksPerGroup           = numberOfBanks / numberOfBankGroups;\n\n    memTimingSpec.tCK       = memspec.memtimingspec.tCK;\n    memTimingSpec.tRAS      = memspec.memtimingspec.RAS;\n    memTimingSpec.tRCD      = memspec.memtimingspec.RCD;\n    memTimingSpec.tRTP      = memspec.memtimingspec.RTP;\n    memTimingSpec.tWL       = memspec.memtimingspec.WL;\n    memTimingSpec.tWR       = memspec.memtimingspec.WR;\n    memTimingSpec.tRP       = memspec.memtimingspec.RP;\n    memTimingSpec.tRFCsb    = memspec.memtimingspec.RFCsb_slr;\n\n    auto VDD = VoltageDomain::VDD;\n    auto VPP = VoltageDomain::VPP;\n\n    memPowerSpec.push_back(MemPowerSpec());\n    memPowerSpec[VDD].vXX       = memspec.mempowerspec.vdd;\n    memPowerSpec[VDD].iXX0      = memspec.mempowerspec.idd0;\n    memPowerSpec[VDD].iXX2N     = memspec.mempowerspec.idd2n;\n    memPowerSpec[VDD].iXX3N     = memspec.mempowerspec.idd3n;\n    memPowerSpec[VDD].iXX4R     = memspec.mempowerspec.idd4r;\n    memPowerSpec[VDD].iXX4W     = memspec.mempowerspec.idd4w;\n    memPowerSpec[VDD].iXX5C     = memspec.mempowerspec.idd5c;\n    memPowerSpec[VDD].iXX6N     = memspec.mempowerspec.idd6n;\n    memPowerSpec[VDD].iXX2P     = memspec.mempowerspec.idd2p;\n    memPowerSpec[VDD].iXX3P     = memspec.mempowerspec.idd3p;\n\n    memPowerSpec.push_back(MemPowerSpec());\n\n    memPowerSpec[VPP].vXX       = memspec.mempowerspec.vpp;\n    memPowerSpec[VPP].iXX0      = memspec.mempowerspec.ipp0;\n    memPowerSpec[VPP].iXX2N     = memspec.mempowerspec.ipp2n;\n    memPowerSpec[VPP].iXX3N     = memspec.mempowerspec.ipp3n;\n    memPowerSpec[VPP].iXX4R     = memspec.mempowerspec.ipp4r;\n    memPowerSpec[VPP].iXX4W     = memspec.mempowerspec.ipp4w;\n    memPowerSpec[VPP].iXX5C     = memspec.mempowerspec.ipp5c;\n    memPowerSpec[VPP].iXX6N     = memspec.mempowerspec.ipp6n;\n    memPowerSpec[VPP].iXX2P     = memspec.mempowerspec.ipp2p;\n    memPowerSpec[VPP].iXX3P     = memspec.mempowerspec.ipp3p;\n\n    vddq = memspec.mempowerspec.vddq;\n\n\n    if (DRAMUtils::MemSpec::RefModeTypeDDR5::REF_MODE_2 == memspec.memarchitecturespec.RefMode) {\n        memPowerSpec[VDD].iXX5X = memspec.mempowerspec.idd5f;\n        memPowerSpec[VPP].iXX5X = memspec.mempowerspec.ipp5f;\n        memTimingSpec.tRFC = memspec.memtimingspec.RFC2_slr;\n    } else {\n        // RefModeTypeDDR5::REF_MODE_1 || RefModeTypeDDR5::INVALID\n        memPowerSpec[VDD].iXX5X = memspec.mempowerspec.idd5b;\n        memPowerSpec[VPP].iXX5X = memspec.mempowerspec.ipp5b;\n        memTimingSpec.tRFC = memspec.memtimingspec.RFC1_slr;\n    }\n\n    memPowerSpec[VDD].iBeta = memspec.mempowerspec.iBeta_vdd.value_or(memspec.mempowerspec.idd0);\n    memPowerSpec[VPP].iBeta = memspec.mempowerspec.iBeta_vpp.value_or(memspec.mempowerspec.ipp0);\n\n\n    if (memspec.bankwisespec.has_value())\n    {\n        bwParams.bwPowerFactRho = memspec.bankwisespec.value().factRho.value_or(1);\n    }\n    else\n    {\n        bwParams.bwPowerFactRho = 1;\n    }\n\n    memTimingSpec.tBurst = burstLength/dataRate;\n    prechargeOffsetRD      =  memTimingSpec.tRTP;\n    prechargeOffsetWR      =  memTimingSpec.tBurst + memTimingSpec.tWL + memTimingSpec.tWR;\n\n    parseImpedanceSpec(memspec);\n    parseDataRateSpec(memspec);\n}\n\nvoid MemSpecDDR5::parseImpedanceSpec(const DRAMUtils::MemSpec::MemSpecDDR5 &memspec) {\n    memImpedanceSpec = memspec.memimpedancespec;\n}\n\nvoid MemSpecDDR5::parseDataRateSpec(const DRAMUtils::MemSpec::MemSpecDDR5 &memspec) {\n    if (!memspec.dataratespec.has_value()) {\n        dataRateSpec = {2, 2, 2};\n        return;\n    }\n\n    dataRateSpec.commandBusRate = memspec.dataratespec.value().ca_bus_rate;\n    dataRateSpec.dataBusRate =  memspec.dataratespec.value().dq_bus_rate;\n    dataRateSpec.dqsBusRate = memspec.dataratespec.value().dqs_bus_rate;\n}\n\nMemSpecDDR5 MemSpecDDR5::from_memspec(const DRAMUtils::MemSpec::MemSpecVariant& memSpec)\n{\n    return std::get<DRAMUtils::MemSpec::MemSpecDDR5>(memSpec.getVariant());\n}\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/memspec/MemSpecDDR5.h",
    "content": "#ifndef DRAMPOWER_MEMSPEC_MEMSPECDDR5_H\n#define DRAMPOWER_MEMSPEC_MEMSPECDDR5_H\n\n#include \"MemSpec.h\"\n\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n\n\nnamespace DRAMPower {\n\nclass MemSpecDDR5 final : public MemSpec<DRAMUtils::MemSpec::MemSpecDDR5> {\n    public:\n\t    using MemImpedanceSpec = DRAMUtils::MemSpec::MemImpedanceSpecTypeDDR5;\n\n        enum VoltageDomain {\n            VDD = 0,\n            VPP = 1,\n        };\n\n    public:\n        MemSpecDDR5() = delete;\n\n        MemSpecDDR5(const DRAMUtils::MemSpec::MemSpecDDR5 &memspec);\n\n        MemSpecDDR5(json_t &data) = delete;\n        MemSpecDDR5(const json_t &data) = delete;\n\n        // Copy constructor and assignment operator\n        MemSpecDDR5(const MemSpecDDR5&) = default;\n        MemSpecDDR5& operator=(const MemSpecDDR5&) = default;\n\n        // Move constructor and assignment operator\n        MemSpecDDR5(MemSpecDDR5&&) = default;\n        MemSpecDDR5& operator=(MemSpecDDR5&&) = default;\n\n        uint64_t numberOfBankGroups;\n        uint64_t banksPerGroup;\n        uint64_t numberOfRanks;\n\n        double vddq;\n\n        // Memspec Variables:\n        struct MemTimingSpec\n        {\n            double fck;\n            double tCK;\n            uint64_t tRAS;\n            uint64_t tRCD;\n            uint64_t tRL;\n            uint64_t tRTP;\n            uint64_t tWL;\n            uint64_t tWR;\n            uint64_t tRFC;\n            uint64_t tRFCsb;\n            uint64_t tRP;\n            uint64_t tBurst;\n        };\n\n        // Currents and Voltages:\n        struct MemPowerSpec\n        {\n            double vXX;\n            double iXX0;\n            double iXX2N;\n            double iXX3N;\n            double iXX2P;\n            double iXX3P;\n            double iXX4R;\n            double iXX4W;\n            double iXX5X;\n            double iXX5C;\n            double iXX6N;\n            double iBeta;\n        };\n\n        struct DataRateSpec {\n            uint64_t commandBusRate;\n            uint64_t dataBusRate;\n            uint64_t dqsBusRate;\n        };\n\n        struct BankWiseParams\n        {\n            // ACT Standby power factor\n            double bwPowerFactRho;\n        };\n\n        MemTimingSpec memTimingSpec;\n        MemImpedanceSpec memImpedanceSpec;\n        DataRateSpec dataRateSpec;\n        std::vector<MemPowerSpec> memPowerSpec;\n        BankWiseParams bwParams;\n\n    private:\n        void parseImpedanceSpec(const DRAMUtils::MemSpec::MemSpecDDR5 &memspec);\n        void parseDataRateSpec(const DRAMUtils::MemSpec::MemSpecDDR5 &memspec);\n    public:\n        static MemSpecDDR5 from_memspec(const DRAMUtils::MemSpec::MemSpecVariant&);\n    };\n\n}\n\n#endif /* DRAMPOWER_MEMSPEC_MEMSPECDDR5_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/memspec/MemSpecLPDDR4.cpp",
    "content": "#include \"MemSpecLPDDR4.h\"\nusing namespace DRAMPower;\n\n\nMemSpecLPDDR4::MemSpecLPDDR4(const DRAMUtils::MemSpec::MemSpecLPDDR4 &memspec)\n    : MemSpec(memspec), memImpedanceSpec{}\n{\n    numberOfBankGroups     = memspec.memarchitecturespec.nbrOfBankGroups;\n    numberOfRanks          = memspec.memarchitecturespec.nbrOfRanks;\n    banksPerGroup = numberOfBanks / numberOfBankGroups;\n\n    memTimingSpec.tCK      = memspec.memtimingspec.tCK;\n    memTimingSpec.tRAS     = memspec.memtimingspec.RAS;\n    memTimingSpec.tRCD     = memspec.memtimingspec.RCD;\n    memTimingSpec.tRL      = memspec.memtimingspec.RL;\n    memTimingSpec.tRTP     = memspec.memtimingspec.RTP;\n    memTimingSpec.tWL      = memspec.memtimingspec.WL;\n    memTimingSpec.tWR      = memspec.memtimingspec.WR;\n    memTimingSpec.tRP      = memspec.memtimingspec.RPpb;\n    memTimingSpec.tRFCPB   = memspec.memtimingspec.RFCpb;\n    memTimingSpec.tRFC     = memspec.memtimingspec.RFCab;\n    memTimingSpec.tREFI    = memspec.memtimingspec.REFI;\n\n    auto VDD1 = VoltageDomain::VDD1;\n    auto VDD2 = VoltageDomain::VDD2;\n\n    memPowerSpec.push_back(MemPowerSpec());\n    memPowerSpec.push_back(MemPowerSpec());\n\n    memPowerSpec[VDD1].vDDX       = memspec.mempowerspec.vdd1;\n    memPowerSpec[VDD1].iDD0X      = memspec.mempowerspec.idd01;\n    memPowerSpec[VDD1].iDD2NX     = memspec.mempowerspec.idd2n1;\n    memPowerSpec[VDD1].iDD3NX     = memspec.mempowerspec.idd3n1;\n    memPowerSpec[VDD1].iDD4RX     = memspec.mempowerspec.idd4r1;\n    memPowerSpec[VDD1].iDD4WX     = memspec.mempowerspec.idd4w1;\n    memPowerSpec[VDD1].iDD5X      = memspec.mempowerspec.idd51;\n    memPowerSpec[VDD1].iDD5PBX    = memspec.mempowerspec.idd5pb1;\n    memPowerSpec[VDD1].iDD6X     = memspec.mempowerspec.idd61;\n    memPowerSpec[VDD1].iDD2PX     = memspec.mempowerspec.idd2p1;\n    memPowerSpec[VDD1].iDD3PX     = memspec.mempowerspec.idd3p1;\n\n    memPowerSpec[VDD2].vDDX       = memspec.mempowerspec.vdd2;\n    memPowerSpec[VDD2].iDD0X      = memspec.mempowerspec.idd02;\n    memPowerSpec[VDD2].iDD2NX     = memspec.mempowerspec.idd2n2;\n    memPowerSpec[VDD2].iDD3NX     = memspec.mempowerspec.idd3n2;\n    memPowerSpec[VDD2].iDD4RX     = memspec.mempowerspec.idd4r2;\n    memPowerSpec[VDD2].iDD4WX     = memspec.mempowerspec.idd4w2;\n    memPowerSpec[VDD2].iDD5X      = memspec.mempowerspec.idd52;\n    memPowerSpec[VDD2].iDD5PBX    = memspec.mempowerspec.idd5pb2;\n    memPowerSpec[VDD2].iDD6X     = memspec.mempowerspec.idd62;\n    memPowerSpec[VDD2].iDD2PX     = memspec.mempowerspec.idd2p2;\n    memPowerSpec[VDD2].iDD3PX     = memspec.mempowerspec.idd3p2;\n\n    vddq = memspec.mempowerspec.vddq;\n\n    memPowerSpec[VDD1].iBeta = memspec.mempowerspec.iBeta_vdd1.value_or(memspec.mempowerspec.idd01);\n    memPowerSpec[VDD2].iBeta = memspec.mempowerspec.iBeta_vdd2.value_or(memspec.mempowerspec.idd02);\n\n\n    if(memspec.bankwisespec.has_value())\n    {\n        bwParams.bwPowerFactRho = memspec.bankwisespec.value().factRho.value_or(1);\n        bwParams.bwPowerFactSigma = memspec.bankwisespec.value().factSigma.value_or(1);\n        bwParams.flgPASR = memspec.bankwisespec.value().hasPASR.value_or(false);\n        if (memspec.bankwisespec.value().pasrMode.has_value())\n        {\n           if(memspec.bankwisespec.value().pasrMode.value() == DRAMUtils::MemSpec::pasrModesType::Invalid)\n           {\n                // pasrMode invalid\n                bwParams.pasrMode = 0;\n           }\n           else\n           {\n                // pasrMode valid\n                bwParams.pasrMode = static_cast<uint64_t>(memspec.bankwisespec.value().pasrMode.value());\n           }\n        }\n        else\n        {\n            bwParams.pasrMode = 0;\n        }\n    }\n    else\n    {\n        bwParams.bwPowerFactRho = 1;\n        bwParams.bwPowerFactSigma = 1;\n        bwParams.flgPASR = false;\n        bwParams.pasrMode = 0;\n    }\n\n    if (bwParams.flgPASR) {\n\n        ///////////////////////////////////////////////////////////\n        // Activate banks for self refresh based on the PASR mode\n        // ACTIVE     - X\n        // NOT ACTIVE - 0\n        ///////////////////////////////////////////////////////////\n        switch(bwParams.pasrMode) {\n\n        case(BankWiseParams::pasrModes::PASR_0): {\n            // PASR MODE 0\n            // FULL ARRAY\n            // |X X X X |\n            // |X X X X |\n            bwParams.activeBanks.resize(numberOfBanks);\n            std::iota(bwParams.activeBanks.begin(), bwParams.activeBanks.end(), 0);\n            break;\n        }\n        case(BankWiseParams::pasrModes::PASR_1): {\n            // PASR MODE 1\n            // (1/2) ARRAY\n            // |X X X X |\n            // |0 0 0 0 |\n            bwParams.activeBanks.resize(numberOfBanks - 4);\n            std::iota(bwParams.activeBanks.begin(), bwParams.activeBanks.end(), 0);\n            break;\n        }\n        case(BankWiseParams::pasrModes::PASR_2): {\n            // PASR MODE 2\n            // (1/4) ARRAY\n            // |X X 0 0 |\n            // |0 0 0 0 |\n            bwParams.activeBanks.resize(numberOfBanks - 6);\n            std::iota(bwParams.activeBanks.begin(), bwParams.activeBanks.end(), 0);\n            break;\n        }\n        case(BankWiseParams::pasrModes::PASR_3): {\n            // PASR MODE 3\n            // (1/8) ARRAY\n            // |X 0 0 0 |\n            // |0 0 0 0 |\n            bwParams.activeBanks.resize(numberOfBanks - 7);\n            std::iota(bwParams.activeBanks.begin(), bwParams.activeBanks.end(), 0);\n            break;\n        }\n        case(BankWiseParams::pasrModes::PASR_4): {\n            // PASR MODE 4\n            // (3/4) ARRAY\n            // |0 0 X X |\n            // |X X X X |\n            bwParams.activeBanks.resize(numberOfBanks - 2);\n            std::iota(bwParams.activeBanks.begin(), bwParams.activeBanks.end(), 2);\n            break;\n        }\n        case(BankWiseParams::pasrModes::PASR_5): {\n            // PASR MODE 5\n            // (1/2) ARRAY\n            // |0 0 0 0 |\n            // |X X X X |\n            bwParams.activeBanks.resize(numberOfBanks - 4);\n            std::iota(bwParams.activeBanks.begin(), bwParams.activeBanks.end(), 4);\n            break;\n        }\n        case(BankWiseParams::pasrModes::PASR_6): {\n            // PASR MODE 6\n            // (1/4) ARRAY\n            // |0 0 0 0 |\n            // |0 0 X X |\n            bwParams.activeBanks.resize(numberOfBanks - 6);\n            std::iota(bwParams.activeBanks.begin(), bwParams.activeBanks.end(), 6);\n            break;\n        }\n        case(BankWiseParams::pasrModes::PASR_7): {\n            // PASR MODE 7\n            // (1/8) ARRAY\n            // |0 0 0 0 |\n            // |0 0 0 X |\n            bwParams.activeBanks.resize(numberOfBanks - 7);\n            std::iota(bwParams.activeBanks.begin(), bwParams.activeBanks.end(), 7);\n            break;\n        }\n        default: {\n            // PASR MODE 0\n            // FULL ARRAY\n            // |X X X X |\n            // |X X X X |\n            bwParams.activeBanks.resize(numberOfBanks);\n            std::iota(bwParams.activeBanks.begin(), bwParams.activeBanks.end(), 0);\n            break;\n        }\n        } //end switch\n    } // end IF flgPASR\n\n    //Source: JESD209-4 (LPDDR4); Table 21\n    if(burstLength == 16){\n        prechargeOffsetRD      = memTimingSpec.tRTP;\n    }else{\n        prechargeOffsetRD      = 8 + memTimingSpec.tRTP;\n    }\n    prechargeOffsetWR      =  memTimingSpec.tWL + burstLength/2 + memTimingSpec.tWR + 1;\n    parseImpedanceSpec(memspec);\n}\n\nbool MemSpecLPDDR4::BankWiseParams::isBankActiveInPasr(const unsigned bankIdx) const\n{\n    return (std::find(activeBanks.begin(), activeBanks.end(), bankIdx)\n            != activeBanks.end());\n}\n\nvoid MemSpecLPDDR4::parseImpedanceSpec(const DRAMUtils::MemSpec::MemSpecLPDDR4 &memspec) {\n    memImpedanceSpec = memspec.memimpedancespec;\n}\n\nMemSpecLPDDR4 MemSpecLPDDR4::from_memspec(const DRAMUtils::MemSpec::MemSpecVariant& memSpec)\n{\n    return std::get<DRAMUtils::MemSpec::MemSpecLPDDR4>(memSpec.getVariant());\n}\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/memspec/MemSpecLPDDR4.h",
    "content": "#ifndef DRAMPOWER_MEMSPEC_MEMSPECLPDDR4_H\n#define DRAMPOWER_MEMSPEC_MEMSPECLPDDR4_H\n\n#include \"MemSpec.h\"\n\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n\n\nnamespace DRAMPower {\n\nclass MemSpecLPDDR4 final : public MemSpec<DRAMUtils::MemSpec::MemSpecLPDDR4>\n{\npublic:\n\tusing MemImpedanceSpec = DRAMUtils::MemSpec::MemImpedanceSpecTypeLPDDR4;\n\n    enum VoltageDomain {\n        VDD1 = 0,\n        VDD2 = 1,\n    };\n\npublic:\n\tMemSpecLPDDR4() = delete;\n\t\n\tMemSpecLPDDR4(const DRAMUtils::MemSpec::MemSpecLPDDR4 &memspec);\n\t\n\tMemSpecLPDDR4(json_t &data) = delete;\n\tMemSpecLPDDR4(const json_t &data) = delete;\n\n    // Copy constructor and assignment operator\n    MemSpecLPDDR4(const MemSpecLPDDR4&) = default;\n\tMemSpecLPDDR4& operator=(const MemSpecLPDDR4&) = default;\n\n    // Move constructor and assignment operator\n    MemSpecLPDDR4(MemSpecLPDDR4&&) = default;\n    MemSpecLPDDR4& operator=(MemSpecLPDDR4&&) = default;\n\n\t~MemSpecLPDDR4() = default;\n\n    uint64_t numberOfBankGroups;\n    uint64_t banksPerGroup;\n    uint64_t numberOfRanks;\n\n\tdouble vddq;\n\n\tstruct MemTimingSpec\n\t{\n\t\tdouble fck;\n\t\tdouble tCK;\n\t\tuint64_t tRAS;\n\t\tuint64_t tRCD;\n\t\tuint64_t tRL;\n\t\tuint64_t tRTP;\n\t\tuint64_t tWL;\n\t\tuint64_t tWR;\n\t\tuint64_t tREFI;\n\t\tuint64_t tRFC;\n\t\tuint64_t tRFCPB;\n\t\tuint64_t tRP;\n\t};\n\n\t// Currents and Voltages:\n\tstruct MemPowerSpec\n\t{\n        double vDDX;\n        double iDD0X;\n        double iDD2NX;\n        double iDD3NX;\n        double iDD2PX;\n        double iDD3PX;\n        double iDD4RX;\n        double iDD4WX;\n        double iDD5X;\n        double iDD5PBX;\n        double iDD6X;\n        double iBeta;\n\n\t};\n\n\tstruct BankWiseParams\n\t{\n\t\t// Set of possible PASR modes\n\t\tenum pasrModes {\n\t\t\tPASR_0,\n\t\t\tPASR_1,\n\t\t\tPASR_2,\n\t\t\tPASR_3,\n\t\t\tPASR_4,\n\t\t\tPASR_5,\n\t\t\tPASR_6,\n\t\t\tPASR_7\n\t\t};\n\n\t\t// List of active banks under the specified PASR mode\n\t\tstd::vector<uint64_t> activeBanks;\n\t\t// ACT Standby power factor\n\t\tdouble bwPowerFactRho;\n\t\t// Self-Refresh power factor\n\t\tdouble bwPowerFactSigma;\n\t\t// Whether PASR is enabled ( true : enabled )\n\t\tbool flgPASR;\n\t\t// PASR mode utilized (int 0-7)\n\t\tuint64_t pasrMode;\n\t\t// Whether bank is active in PASR\n\t\tbool isBankActiveInPasr(const unsigned bankIdx) const;\n\n\t};\n\n\tMemTimingSpec memTimingSpec;\n\tMemImpedanceSpec memImpedanceSpec;\n\tstd::vector<MemPowerSpec> memPowerSpec;\n\tBankWiseParams bwParams;\n\nprivate:\n    void parseImpedanceSpec(const DRAMUtils::MemSpec::MemSpecLPDDR4 &memspec);\n\npublic:\n    static MemSpecLPDDR4 from_memspec(const DRAMUtils::MemSpec::MemSpecVariant&);\n};\n\n}\n\n#endif /* DRAMPOWER_MEMSPEC_MEMSPECLPDDR4_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/memspec/MemSpecLPDDR5.cpp",
    "content": "#include \"DRAMPower/memspec/MemSpecLPDDR5.h\"\n\nusing namespace DRAMPower;\n\n\nMemSpecLPDDR5::MemSpecLPDDR5(const DRAMUtils::MemSpec::MemSpecLPDDR5 &memspec)\n        : MemSpec(memspec)\n{\n    numberOfBankGroups      = memspec.memarchitecturespec.nbrOfBankGroups;\n    numberOfRanks           = memspec.memarchitecturespec.nbrOfRanks;\n    banksPerGroup           = numberOfBanks / numberOfBankGroups;\n\n    memTimingSpec.tCK       = memspec.memtimingspec.tCK;\n    memTimingSpec.WCKtoCK   = memspec.memtimingspec.WCK2CK;\n    memTimingSpec.tWCK      = memTimingSpec.tCK / memTimingSpec.WCKtoCK;\n    memTimingSpec.tRAS      = memspec.memtimingspec.RAS;\n    memTimingSpec.tRCD      = memspec.memtimingspec.RCD_S;\n    memTimingSpec.tRBTP     = memspec.memtimingspec.RBTP;\n    memTimingSpec.tWL       = memspec.memtimingspec.WL;\n    memTimingSpec.tWR       = memspec.memtimingspec.WR;\n    memTimingSpec.tRP       = memspec.memtimingspec.RPpb;\n    memTimingSpec.tRFCPB    = memspec.memtimingspec.RFCpb;\n    memTimingSpec.tRFC      = memspec.memtimingspec.RFCab;\n    memTimingSpec.tREFI     = memspec.memtimingspec.REFI;\n\n    auto VDD1 = VoltageDomain::VDD1;\n    auto VDD2H = VoltageDomain::VDD2H;\n    auto VDD2L = VoltageDomain::VDD2L;\n\n    memPowerSpec.push_back(MemPowerSpec()); // VDD1\n    memPowerSpec.push_back(MemPowerSpec()); // VDD2H\n    memPowerSpec.push_back(MemPowerSpec()); // VDD2L\n\n    memPowerSpec[VDD1].vDDX       = memspec.mempowerspec.vdd1;\n    memPowerSpec[VDD1].iDD0X      = memspec.mempowerspec.idd01;\n    memPowerSpec[VDD1].iDD2NX     = memspec.mempowerspec.idd2n1;\n    memPowerSpec[VDD1].iDD3NX     = memspec.mempowerspec.idd3n1;\n    memPowerSpec[VDD1].iDD4RX     = memspec.mempowerspec.idd4r1;\n    memPowerSpec[VDD1].iDD4WX     = memspec.mempowerspec.idd4w1;\n    memPowerSpec[VDD1].iDD5X      = memspec.mempowerspec.idd51;\n    memPowerSpec[VDD1].iDD5PBX    = memspec.mempowerspec.idd5pb1;\n    memPowerSpec[VDD1].iDD6X      = memspec.mempowerspec.idd61;\n    memPowerSpec[VDD1].iDD6DSX    = memspec.mempowerspec.idd6ds1;\n    memPowerSpec[VDD1].iDD2PX     = memspec.mempowerspec.idd2p1;\n    memPowerSpec[VDD1].iDD3PX     = memspec.mempowerspec.idd3p1;\n\n    memPowerSpec[VDD2H].vDDX       = memspec.mempowerspec.vdd2h;\n    memPowerSpec[VDD2H].iDD0X      = memspec.mempowerspec.idd02h;\n    memPowerSpec[VDD2H].iDD2NX     = memspec.mempowerspec.idd2n2h;\n    memPowerSpec[VDD2H].iDD3NX     = memspec.mempowerspec.idd3n2h;\n    memPowerSpec[VDD2H].iDD4RX     = memspec.mempowerspec.idd4r2h;\n    memPowerSpec[VDD2H].iDD4WX     = memspec.mempowerspec.idd4w2h;\n    memPowerSpec[VDD2H].iDD5X      = memspec.mempowerspec.idd52h;\n    memPowerSpec[VDD2H].iDD5PBX    = memspec.mempowerspec.idd5pb2h;\n    memPowerSpec[VDD2H].iDD6X      = memspec.mempowerspec.idd62h;\n    memPowerSpec[VDD2H].iDD6DSX    = memspec.mempowerspec.idd6ds2h;\n    memPowerSpec[VDD2H].iDD2PX     = memspec.mempowerspec.idd2p2h;\n    memPowerSpec[VDD2H].iDD3PX     = memspec.mempowerspec.idd3p2h;\n\n    memPowerSpec[VDD2L].vDDX       = memspec.mempowerspec.vdd2l;\n    memPowerSpec[VDD2L].iDD0X      = memspec.mempowerspec.idd02l;\n    memPowerSpec[VDD2L].iDD2NX     = memspec.mempowerspec.idd2n2l;\n    memPowerSpec[VDD2L].iDD3NX     = memspec.mempowerspec.idd3n2l;\n    memPowerSpec[VDD2L].iDD4RX     = memspec.mempowerspec.idd4r2l;\n    memPowerSpec[VDD2L].iDD4WX     = memspec.mempowerspec.idd4w2l;\n    memPowerSpec[VDD2L].iDD5X      = memspec.mempowerspec.idd52l;\n    memPowerSpec[VDD2L].iDD5PBX    = memspec.mempowerspec.idd5pb2l;\n    memPowerSpec[VDD2L].iDD6X      = memspec.mempowerspec.idd62l;\n    memPowerSpec[VDD2L].iDD6DSX    = memspec.mempowerspec.idd6ds2l;\n    memPowerSpec[VDD2L].iDD2PX     = memspec.mempowerspec.idd2p2l;\n    memPowerSpec[VDD2L].iDD3PX     = memspec.mempowerspec.idd3p2l;\n\n    vddq       = memspec.mempowerspec.vddq;\n\n    memPowerSpec[VDD1].iBeta = memspec.mempowerspec.iBeta_vdd1.value_or(memspec.mempowerspec.idd01);\n    memPowerSpec[VDD2H].iBeta = memspec.mempowerspec.iBeta_vdd2h.value_or(memspec.mempowerspec.idd02h);\n    memPowerSpec[VDD2L].iBeta = memspec.mempowerspec.iBeta_vdd2l.value_or(memspec.mempowerspec.idd02l);\n\n    if (memspec.bankwisespec.has_value()) {\n        bwParams.bwPowerFactRho = memspec.bankwisespec.value().factRho.value_or(1);\n    }\n    else {\n        bwParams.bwPowerFactRho = 1;\n    }\n\n\n    auto BankArchError = [this]() {\n        std::cout << \"Invalid bank architecture selected\" << std::endl;\n        std::cout << \"Selected values:\" << std::endl;\n        std::cout << \"  - Number of banks: \" << numberOfBanks << std::endl;\n        std::cout << \"  - Number of bank groups: \" << numberOfBankGroups << std::endl;\n        std::cout << \"Valid values are 16|1 (16B mode), 16|4 (BG mode) or 8|1 (8B mode)\" << std::endl;\n        std::cout << std::endl << \"Assuming 16B architecture.\" << std::endl;\n        bank_arch = BankArchitectureMode::M16B;\n        numberOfBanks = 16;\n        numberOfBankGroups = 1;\n    };\n\n    if (numberOfBanks == 16) {\n        if (numberOfBankGroups == 1 || numberOfBankGroups == 0) {\n            bank_arch = BankArchitectureMode::M16B;\n        } else if (numberOfBankGroups == 4) {\n            bank_arch = BankArchitectureMode::MBG;\n        } else {\n            BankArchError();\n        }\n    } else if (numberOfBanks == 8) {\n        if (numberOfBankGroups > 1) {\n            BankArchError();\n        } else {\n            bank_arch = BankArchitectureMode::M8B;\n        }\n    } else {\n        BankArchError();\n    }\n\n    // Source: LPDDR5 standard; table 312\n    memTimingSpec.tBurst = burstLength/(dataRate * memTimingSpec.WCKtoCK);\n\n    // Source: LPDDR5 standard; figure 96\n    prechargeOffsetRD      =   memTimingSpec.tBurst + memTimingSpec.tRBTP;\n\n    // Source: LPDDR5 standard; figure 97\n    prechargeOffsetWR      =  memTimingSpec.tWL + memTimingSpec.tBurst + 1 + memTimingSpec.tWR;\n\n    wckAlwaysOnMode = memspec.memarchitecturespec.WCKalwaysOn;\n\n    parseImpedanceSpec(memspec);\n}\n\nvoid MemSpecLPDDR5::parseImpedanceSpec(const DRAMUtils::MemSpec::MemSpecLPDDR5 &memspec) {\n\n    memImpedanceSpec = memspec.memimpedancespec;\n}\n\nMemSpecLPDDR5 MemSpecLPDDR5::from_memspec(const DRAMUtils::MemSpec::MemSpecVariant& memSpec)\n{\n    return std::get<DRAMUtils::MemSpec::MemSpecLPDDR5>(memSpec.getVariant());\n}\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/memspec/MemSpecLPDDR5.h",
    "content": "#ifndef DRAMPOWER_MEMSPEC_MEMSPECLPDDR5_H\n#define DRAMPOWER_MEMSPEC_MEMSPECLPDDR5_H\n\n#include \"MemSpec.h\"\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n\nnamespace DRAMPower {\n\n    class MemSpecLPDDR5 final : public MemSpec<DRAMUtils::MemSpec::MemSpecLPDDR5> {\n    public:\n        using MemImpedanceSpec = DRAMUtils::MemSpec::MemImpedanceSpecTypeLPDDR5;\n        enum VoltageDomain {\n            VDD1 = 0,\n            VDD2H,\n            VDD2L,\n        };\n\n        enum BankArchitectureMode {\n            MBG,   // 4 banks, 4 bank groups\n            M16B,  // 16 banks, no bank groups\n            M8B    // 8 banks, no bank groups\n        };\n\n    public:\n        MemSpecLPDDR5() = delete;\n\n        MemSpecLPDDR5(const DRAMUtils::MemSpec::MemSpecLPDDR5 &memspec);\n\t\n        MemSpecLPDDR5(json_t &data) = delete;\n        MemSpecLPDDR5(const json_t &data) = delete;\n\n        // Copy constructor and assignment operator\n        MemSpecLPDDR5(const MemSpecLPDDR5&) = default;\n        MemSpecLPDDR5& operator=(const MemSpecLPDDR5&) = default;\n\n        // Move constructor and assignment operator\n        MemSpecLPDDR5(MemSpecLPDDR5&&) = default;\n        MemSpecLPDDR5& operator=(MemSpecLPDDR5&&) = default;\n\n\t    ~MemSpecLPDDR5() = default;\n\n        uint64_t numberOfBankGroups;\n        uint64_t banksPerGroup;\n        uint64_t numberOfRanks;\n        std::size_t perTwoBankOffset = 8;\n        BankArchitectureMode bank_arch;\n        bool wckAlwaysOnMode;\n\n        double vddq;\n\n        // Memspec Variables:\n        struct MemTimingSpec\n        {\n            double fck;\n            double tCK;\n            double tWCK;\n            uint64_t WCKtoCK;\n            uint64_t tRAS;\n            uint64_t tRCD;\n            uint64_t tRL;\n            uint64_t tWL;\n            uint64_t tWR;\n            uint64_t tRFC;\n            uint64_t tRFCPB;\n            uint64_t tREFI;\n            uint64_t tRP;\n            uint64_t tRBTP;\n            uint64_t tBurst;\n        };\n\n        // Currents and Voltages:\n        struct MemPowerSpec\n        {\n            double vDDX;\n            double iDD0X;\n            double iDD2NX;\n            double iDD3NX;\n            double iDD2PX;\n            double iDD3PX;\n            double iDD4RX;\n            double iDD4WX;\n            double iDD5X;\n            double iDD5PBX;\n            double iDD6X;\n            double iDD6DSX;\n            double iBeta;\n        };\n\n        struct BankWiseParams {\n            // ACT Standby power factor\n            double bwPowerFactRho;\n        };\n\n        MemTimingSpec memTimingSpec;\n        MemImpedanceSpec memImpedanceSpec;\n        std::vector<MemPowerSpec> memPowerSpec;\n        BankWiseParams bwParams;\n\n       private:\n        void parseImpedanceSpec(const DRAMUtils::MemSpec::MemSpecLPDDR5 &memspec);\n\n       public:\n        static MemSpecLPDDR5 from_memspec(const DRAMUtils::MemSpec::MemSpecVariant&);\n    };\n\n}  // namespace DRAMPower\n\n#endif /* DRAMPOWER_MEMSPEC_MEMSPECLPDDR5_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/simconfig/simconfig.h",
    "content": "#ifndef DRAMPOWER_SIMCONFIG_SIMCONFIG_H\n#define DRAMPOWER_SIMCONFIG_SIMCONFIG_H\n\n#include \"DRAMUtils/util/json_utils.h\"\n#include \"DRAMUtils/config/toggling_rate.h\"\n\nnamespace DRAMPower::config {\n\nstruct SimConfig {\n// Public type definitions\npublic:\n    using ToggleRateDefinition_t = DRAMUtils::Config::ToggleRateDefinition;\n\n// Public Constructors\npublic:\n    SimConfig() = default;\n\n// Public members\npublic:\n    std::optional<ToggleRateDefinition_t> toggleRateDefinition;\n};\nNLOHMANN_JSONIFY_ALL_THINGS(SimConfig, toggleRateDefinition);\n\n} // DRAMPower::config\n\n#endif /* DRAMPOWER_SIMCONFIG_SIMCONFIG_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr4/DDR4.cpp",
    "content": "#include \"DDR4.h\"\n#include \"DRAMPower/Types.h\"\n#include \"DRAMPower/data/stats.h\"\n#include \"DRAMPower/memspec/MemSpecDDR4.h\"\n#include \"DRAMPower/standards/ddr4/DDR4Interface.h\"\n#include \"DRAMPower/standards/ddr4/core_calculation_DDR4.h\"\n#include \"DRAMPower/standards/ddr4/interface_calculation_DDR4.h\"\n#include \"DRAMPower/util/cli_architecture_config.h\"\n\n#include <DRAMPower/command/Pattern.h>\n#include <DRAMPower/util/extensions.h>\n\nnamespace DRAMPower {\n\n    using namespace DRAMUtils::Config;\n\n    DDR4::DDR4(const MemSpecDDR4 &memSpec, const config::SimConfig &simConfig)\n        : m_memSpec(memSpec)\n        , m_interface(m_memSpec, simConfig)\n        , m_core(m_memSpec)\n    {\n        this->registerExtensions();\n    }\n\n// Extensions\n    void DDR4::registerExtensions() {\n        getExtensionManager().registerExtension<extensions::DBI>([this](const timestamp_t, const bool enable) {\n            // Assumption: the enabling of the DBI does not interleave with previous data on the bus\n            // x4,x8,x16 devices: only x8 and x16 support dbi\n            if (4 == m_memSpec.bitWidth) {\n                std::cout << \"[WARN] x4 devices don't support DBI\" << std::endl;\n                return false;\n            }\n            m_interface.enableDBI(enable);\n            return true;\n        }, false);\n    }\n\n// Getters for CLI\n    util::CLIArchitectureConfig DDR4::getCLIArchitectureConfig() {\n        return util::CLIArchitectureConfig{\n            m_memSpec.numberOfDevices,\n            m_memSpec.numberOfRanks,\n            m_memSpec.numberOfBanks\n        };\n    }\n\n// Calculation\n    energy_t DDR4::calcCoreEnergyStats(const SimulationStats& stats) const {\n        Calculation_DDR4 calculation(m_memSpec);\n        return calculation.calcEnergy(stats);\n    }\n\n    interface_energy_info_t DDR4::calcInterfaceEnergyStats(const SimulationStats& stats) const {\n        InterfaceCalculation_DDR4 calculation(m_memSpec);\n        return calculation.calculateEnergy(stats);\n    }\n\n// Stats\n    SimulationStats DDR4::getWindowStats(timestamp_t timestamp) {\n        SimulationStats stats;\n        m_core.getWindowStats(timestamp, stats);\n        m_interface.getWindowStats(timestamp, stats);\n        return stats;\n    }\n\n// Serialization\n    void DDR4::serialize_impl(std::ostream& stream) const {\n        m_core.serialize(stream);\n        m_interface.serialize(stream);\n    }\n\n    void DDR4::deserialize_impl(std::istream& stream) {\n        m_core.deserialize(stream);\n        m_interface.deserialize(stream);\n    }\n\n} // namespace DRAMPower\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr4/DDR4.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_DDR4_DDR4_H\n#define DRAMPOWER_STANDARDS_DDR4_DDR4_H\n\n#include \"DRAMPower/util/cli_architecture_config.h\"\n\n#include <DRAMPower/Types.h>\n#include <DRAMPower/dram/dram_base.h>\n#include <DRAMPower/command/Command.h>\n#include <DRAMPower/data/energy.h>\n#include <DRAMPower/data/stats.h>\n\n#include <DRAMPower/standards/ddr4/DDR4Interface.h>\n#include <DRAMPower/standards/ddr4/DDR4Core.h>\n#include <DRAMPower/memspec/MemSpecDDR4.h>\n#include <DRAMPower/standards/ddr4/core_calculation_DDR4.h>\n#include <DRAMPower/standards/ddr4/interface_calculation_DDR4.h>\n\n#include \"DRAMPower/simconfig/simconfig.h\"\n\n#include <algorithm>\n\nnamespace DRAMPower {\n\nclass DDR4 : public dram_base<CmdType> {\n// Public constructors and assignment operators\npublic:\n    DDR4() = delete; // No default constructor\n    DDR4(const DDR4& other) = default; // copy constructor\n    DDR4(DDR4&& other) noexcept = default; // move constructor\n    DDR4& operator=(const DDR4&) = default; // copy assignment operator\n    DDR4& operator=(DDR4&&) = default; // move assignment operator\n    ~DDR4() override = default;\n    \n    DDR4(const MemSpecDDR4 &memSpec, const config::SimConfig &simConfig = {});\n\n// Public member functions\npublic:\n// Member functions\n    DDR4Core& getCore() {\n        return m_core;\n    }\n    const DDR4Core& getCore() const {\n        return m_core;\n    }\n    DDR4Interface& getInterface() {\n        return m_interface;\n    }\n    const DDR4Interface& getInterface() const {\n        return m_interface;\n    }\n// Overrides\n    energy_t calcCoreEnergyStats(const SimulationStats& stats) const override;\n    interface_energy_info_t calcInterfaceEnergyStats(const SimulationStats& stats) const override;\n    SimulationStats getWindowStats(timestamp_t timestamp) override;\n    util::CLIArchitectureConfig getCLIArchitectureConfig() override;\n    bool isSerializable() const override {\n        return m_core.isSerializable();\n    }\n\n// Private member functions\nprivate:\n// Member functions\n    void registerExtensions();\n// Overrides\n    void doCoreCommandImpl(const Command& command) override {\n        m_core.doCommand(command);\n    }\n    void doInterfaceCommandImpl(const Command& command) override {\n        m_interface.doCommand(command);\n    }\n    timestamp_t getLastCommandTime_impl() const override {\n        return std::max(m_core.getLastCommandTime(), m_interface.getLastCommandTime());\n    }\n    void serialize_impl(std::ostream& stream) const override;\n    void deserialize_impl(std::istream& stream) override;\n\n// Private member variables\nprivate:\n    MemSpecDDR4 m_memSpec;\n    DDR4Interface m_interface;\n    DDR4Core m_core;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_DDR4_DDR4_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr4/DDR4Core.cpp",
    "content": "#include \"DDR4Core.h\"\n#include \"DRAMPower/Types.h\"\n#include \"DRAMPower/util/RegisterHelper.h\"\n#include <cstddef>\n\nnamespace DRAMPower {\n\nvoid DDR4Core::doCommand(const Command& cmd) {\n    m_implicitCommandHandler.processImplicitCommandQueue(*this, cmd.timestamp, m_last_command_time);\n    m_last_command_time = std::max(cmd.timestamp, m_last_command_time);\n    switch(cmd.type) {\n        case CmdType::ACT:\n            util::coreHelpers::bankHandler(cmd, m_ranks, this, &DDR4Core::handleAct);\n            break;\n        case CmdType::PRE:\n            util::coreHelpers::bankHandler(cmd, m_ranks, this, &DDR4Core::handlePre);\n            break;\n        case CmdType::PREA:\n            util::coreHelpers::rankHandler(cmd, m_ranks, this, &DDR4Core::handlePreAll);\n            break;\n        case CmdType::REFA:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &DDR4Core::handleRefAll);\n            break;\n        case CmdType::RD:\n            util::coreHelpers::bankHandler(cmd, m_ranks, this, &DDR4Core::handleRead);\n            break;\n        case CmdType::RDA:\n            util::coreHelpers::bankHandlerIdx(cmd, m_ranks, this, &DDR4Core::handleReadAuto);\n            break;\n        case CmdType::WR:\n            util::coreHelpers::bankHandler(cmd, m_ranks, this, &DDR4Core::handleWrite);\n            break;\n        case CmdType::WRA:\n            util::coreHelpers::bankHandlerIdx(cmd, m_ranks, this, &DDR4Core::handleWriteAuto);\n            break;\n        case CmdType::SREFEN:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &DDR4Core::handleSelfRefreshEntry);\n            break;\n        case CmdType::SREFEX:\n            util::coreHelpers::rankHandler(cmd, m_ranks, this, &DDR4Core::handleSelfRefreshExit);\n            break;\n        case CmdType::PDEA:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &DDR4Core::handlePowerDownActEntry);\n            break;\n        case CmdType::PDEP:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &DDR4Core::handlePowerDownPreEntry);\n            break;\n        case CmdType::PDXA:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &DDR4Core::handlePowerDownActExit);\n            break;\n        case CmdType::PDXP:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &DDR4Core::handlePowerDownPreExit);\n            break;\n        case CmdType::END_OF_SIMULATION:\n            break;\n        default:\n            assert(false && \"Unsupported command\");\n            break;\n    }\n}\n\ntimestamp_t DDR4Core::getLastCommandTime() const {\n    return m_last_command_time;\n}\n\nbool DDR4Core::isSerializable() const {\n    return 0 == m_implicitCommandHandler.implicitCommandCount();\n}\n\nvoid DDR4Core::handleAct(Rank &rank, Bank &bank, timestamp_t timestamp) {\n    bank.counter.act++;\n    bank.bankState = Bank::BankState::BANK_ACTIVE;\n\n    bank.cycles.act.start_interval(timestamp);\n    \n    rank.cycles.act.start_interval_if_not_running(timestamp);\n    //rank.cycles.pre.close_interval(timestamp);\n}\n\nvoid DDR4Core::handlePre(Rank &rank, Bank &bank, timestamp_t timestamp) {\n    // If statement necessary for core power calculation\n    // bank.counter.pre doesn't correspond to the number of pre commands\n    // It corresponds to the number of state transisitons to the pre state\n    if (bank.bankState == Bank::BankState::BANK_PRECHARGED) return;\n    bank.counter.pre++;\n\n    bank.bankState = Bank::BankState::BANK_PRECHARGED;\n    bank.cycles.act.close_interval(timestamp);\n    bank.latestPre = timestamp;                                                // used for earliest power down calculation\n    if ( !rank.isActive(timestamp) )                                            // stop rank active interval if no more banks active\n    {\n        // active counter increased if at least 1 bank is active, precharge counter increased if all banks are precharged\n        rank.cycles.act.close_interval(timestamp);\n        //rank.cycles.pre.start_interval_if_not_running(timestamp);             \n    }\n}\n\nvoid DDR4Core::handlePreAll(Rank &rank, timestamp_t timestamp) {\n    for (auto &bank: rank.banks) \n        handlePre(rank, bank, timestamp);\n}\n\nvoid DDR4Core::handleRefAll(std::size_t rank_idx, timestamp_t timestamp) {\n    auto timestamp_end = timestamp + m_memSpec.tRFC;\n    auto& rank = m_ranks[rank_idx];\n    rank.endRefreshTime = timestamp_end;\n    rank.cycles.act.start_interval_if_not_running(timestamp);\n    //rank.cycles.pre.close_interval(timestamp);\n    for (std::size_t bank_idx = 0; bank_idx < rank.banks.size(); ++bank_idx) {\n        auto& bank = rank.banks[bank_idx];\n        bank.bankState = Bank::BankState::BANK_ACTIVE;\n        \n        ++bank.counter.refAllBank;\n        bank.cycles.act.start_interval_if_not_running(timestamp);\n\n\n        bank.refreshEndTime = timestamp_end;                                    // used for earliest power down calculation\n\n        // Execute implicit pre-charge at refresh end\n        m_implicitCommandHandler.addImplicitCommand(timestamp_end, [rank_idx, bank_idx = bank_idx, timestamp_end](DDR4Core& self) {\n            auto& rank = self.m_ranks[rank_idx];\n            auto& bank = rank.banks[bank_idx];\n            bank.bankState = Bank::BankState::BANK_PRECHARGED;\n            bank.cycles.act.close_interval(timestamp_end);\n            // stop rank active interval if no more banks active\n            if (!rank.isActive(timestamp_end))                                  // stop rank active interval if no more banks active\n            {\n                rank.cycles.act.close_interval(timestamp_end);\n                //rank.cycles.pre.start_interval(timestamp_end);\n            }\n        });\n    }\n\n    // Required for precharge power-down\n}\n\nvoid DDR4Core::handleRead(Rank&, Bank &bank, timestamp_t) {\n    ++bank.counter.reads;\n}\n\nvoid DDR4Core::handleReadAuto(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp) {\n    auto& bank = m_ranks[rank_idx].banks[bank_idx];\n    ++bank.counter.readAuto;\n\n    auto minBankActiveTime = bank.cycles.act.get_start() + m_memSpec.tRAS;\n    auto minReadActiveTime = timestamp + m_memSpec.prechargeOffsetRD;\n\n    auto delayed_timestamp = std::max(minBankActiveTime, minReadActiveTime);\n\n    // Execute PRE after minimum active time\n    m_implicitCommandHandler.addImplicitCommand(delayed_timestamp, [rank_idx, bank_idx, delayed_timestamp](DDR4Core& self) {\n        self.handlePre(self.m_ranks[rank_idx], self.m_ranks[rank_idx].banks[bank_idx], delayed_timestamp);\n    });\n}\n\nvoid DDR4Core::handleWrite(Rank&, Bank &bank, timestamp_t) {\n    ++bank.counter.writes;\n}\n\nvoid DDR4Core::handleWriteAuto(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp) {\n    auto& bank = m_ranks[rank_idx].banks[bank_idx];\n    ++bank.counter.writeAuto;\n\n    auto minBankActiveTime = bank.cycles.act.get_start() + m_memSpec.tRAS;\n    auto minWriteActiveTime =  timestamp + m_memSpec.prechargeOffsetWR;\n\n    auto delayed_timestamp = std::max(minBankActiveTime, minWriteActiveTime);\n\n    // Execute PRE after minimum active time\n    m_implicitCommandHandler.addImplicitCommand(delayed_timestamp, [rank_idx, bank_idx, delayed_timestamp](DDR4Core& self) {\n        self.handlePre(self.m_ranks[rank_idx], self.m_ranks[rank_idx].banks[bank_idx], delayed_timestamp);\n    });\n}\n\nvoid DDR4Core::handleSelfRefreshEntry(std::size_t rank_idx, timestamp_t timestamp) {\n    // Issue implicit refresh\n    handleRefAll(rank_idx, timestamp);\n    // Handle self-refresh entry after tRFC\n    auto timestampSelfRefreshStart = timestamp + m_memSpec.tRFC;\n    m_implicitCommandHandler.addImplicitCommand(timestampSelfRefreshStart, [rank_idx, timestampSelfRefreshStart](DDR4Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.counter.selfRefresh++;\n        rank.cycles.sref.start_interval(timestampSelfRefreshStart);\n        rank.memState = MemState::SREF;\n    });\n}\n\nvoid DDR4Core::handleSelfRefreshExit(Rank &rank, timestamp_t timestamp) {\n    assert(rank.memState == MemState::SREF);                                    // check for previous SelfRefreshEntry\n    rank.cycles.sref.close_interval(timestamp);                                 // Duration between entry and exit\n    rank.memState = MemState::NOT_IN_PD;\n}\n\nvoid DDR4Core::handlePowerDownActEntry(std::size_t rank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    auto earliestPossibleEntry = this->earliestPossiblePowerDownEntryTime(rank);\n    auto entryTime = std::max(timestamp, earliestPossibleEntry);\n    m_implicitCommandHandler.addImplicitCommand(entryTime, [rank_idx, entryTime](DDR4Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.memState = MemState::PDN_ACT;\n        rank.cycles.powerDownAct.start_interval(entryTime);\n        rank.cycles.act.close_interval(entryTime);\n        //rank.cycles.pre.close_interval(entryTime);\n        for (auto & bank : rank.banks) {\n            bank.cycles.act.close_interval(entryTime);\n        }\n    });\n}\n\nvoid DDR4Core::handlePowerDownActExit(std::size_t rank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    assert(rank.memState == MemState::PDN_ACT);\n    auto earliestPossibleExit = this->earliestPossiblePowerDownEntryTime(rank);\n    auto exitTime = std::max(timestamp, earliestPossibleExit);\n\n    m_implicitCommandHandler.addImplicitCommand(exitTime, [rank_idx, exitTime](DDR4Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.memState = MemState::NOT_IN_PD;\n        rank.cycles.powerDownAct.close_interval(exitTime);\n\n        // Activate banks that were active prior to PDA\n        for (auto & bank : rank.banks)\n        {\n            if (bank.bankState==Bank::BankState::BANK_ACTIVE)\n            {\n                bank.cycles.act.start_interval(exitTime);\n            }\n        }\n        // Activate rank if at least one bank is active\n        // At least one bank must be active for PDA -> remove if statement?\n        if(rank.isActive(exitTime))\n            rank.cycles.act.start_interval(exitTime); \n\n    });\n}\n\nvoid DDR4Core::handlePowerDownPreEntry(std::size_t rank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    auto earliestPossibleEntry = this->earliestPossiblePowerDownEntryTime(rank);\n    auto entryTime = std::max(timestamp, earliestPossibleEntry);\n\n    m_implicitCommandHandler.addImplicitCommand(entryTime, [rank_idx, entryTime](DDR4Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        for (auto &bank : rank.banks)\n            bank.cycles.act.close_interval(entryTime);\n        rank.memState = MemState::PDN_PRE;\n        rank.cycles.powerDownPre.start_interval(entryTime);\n        //rank.cycles.pre.close_interval(entryTime);\n        rank.cycles.act.close_interval(entryTime);\n    });\n}\n\nvoid DDR4Core::handlePowerDownPreExit(std::size_t rank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    // The computation is necessary to exit at the earliest timestamp (upon entry)\n    auto earliestPossibleExit = this->earliestPossiblePowerDownEntryTime(rank);\n    auto exitTime = std::max(timestamp, earliestPossibleExit);\n\n    m_implicitCommandHandler.addImplicitCommand(exitTime, [rank_idx, exitTime](DDR4Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.memState = MemState::NOT_IN_PD;\n        rank.cycles.powerDownPre.close_interval(exitTime);\n\n        // Precharge banks that were precharged prior to PDP\n        for (auto & bank : rank.banks)\n        {\n            if (bank.bankState==Bank::BankState::BANK_ACTIVE)\n            {\n                bank.cycles.act.start_interval(exitTime);\n            }\n        }\n        // Precharge rank if all banks are precharged\n        // At least one bank must be precharged for PDP -> remove if statement?\n        // If statement ensures right state diagramm traversal\n        //if(!rank.isActive(exitTime))\n        //    rank.cycles.pre.start_interval(exitTime); \n    });\n}\n\ntimestamp_t DDR4Core::earliestPossiblePowerDownEntryTime(Rank & rank) const {\n    timestamp_t entryTime = 0;\n\n    for (const auto & bank : rank.banks) {\n        entryTime = std::max({ entryTime,\n                                bank.counter.act == 0 ? 0 :  bank.cycles.act.get_start() + m_memSpec.tRCD,\n                                bank.counter.pre == 0 ? 0 : bank.latestPre + m_memSpec.tRP,\n                                bank.refreshEndTime\n                                });\n    }\n\n    return entryTime;\n}\n\nvoid DDR4Core::getWindowStats(timestamp_t timestamp, SimulationStats &stats) {\n    m_implicitCommandHandler.processImplicitCommandQueue(*this, timestamp, m_last_command_time);\n    // resize banks and ranks\n    stats.bank.resize(m_memSpec.numberOfBanks * m_memSpec.numberOfRanks);\n    stats.rank_total.resize(m_memSpec.numberOfRanks);\n\n    auto simulation_duration = timestamp;\n    for (size_t i = 0; i < m_memSpec.numberOfRanks; ++i) {\n        const Rank &rank = m_ranks[i];\n        size_t bank_offset = i * m_memSpec.numberOfBanks;\n        for (size_t j = 0; j < m_memSpec.numberOfBanks; ++j) {\n            stats.bank[bank_offset + j].counter = rank.banks[j].counter;\n            stats.bank[bank_offset + j].cycles.act =\n                rank.banks[j].cycles.act.get_count_at(timestamp);\n            stats.bank[bank_offset + j].cycles.selfRefresh =\n                rank.cycles.sref.get_count_at(timestamp);\n            stats.bank[bank_offset + j].cycles.powerDownAct =\n                rank.cycles.powerDownAct.get_count_at(timestamp);\n            stats.bank[bank_offset + j].cycles.powerDownPre =\n                rank.cycles.powerDownPre.get_count_at(timestamp);\n            stats.bank[bank_offset + j].cycles.pre =\n                simulation_duration - (stats.bank[bank_offset + j].cycles.act +\n                                        rank.cycles.powerDownAct.get_count_at(timestamp) +\n                                        rank.cycles.powerDownPre.get_count_at(timestamp) +\n                                        rank.cycles.sref.get_count_at(timestamp));\n        }\n        stats.rank_total[i].cycles.act = rank.cycles.act.get_count_at(timestamp);\n        stats.rank_total[i].cycles.powerDownAct = rank.cycles.powerDownAct.get_count_at(timestamp);\n        stats.rank_total[i].cycles.powerDownPre = rank.cycles.powerDownPre.get_count_at(timestamp);\n        stats.rank_total[i].cycles.selfRefresh = rank.cycles.sref.get_count_at(timestamp);\n        stats.rank_total[i].cycles.pre = simulation_duration - \n        (\n            stats.rank_total[i].cycles.act +\n            stats.rank_total[i].cycles.powerDownAct +\n            stats.rank_total[i].cycles.powerDownPre +\n            stats.rank_total[i].cycles.selfRefresh\n        );\n        //stats.rank_total[i].cycles.pre = rank.cycles.pre.get_count_at(timestamp);\n    }\n}\n\nvoid DDR4Core::serialize(std::ostream& stream) const {\n    stream.write(reinterpret_cast<const char*>(&m_last_command_time), sizeof(m_last_command_time));\n    // Serialize the ranks\n    for (const auto& rank : m_ranks) {\n        rank.serialize(stream);\n    }\n}\n\nvoid DDR4Core::deserialize(std::istream& stream) {\n    stream.read(reinterpret_cast<char*>(&m_last_command_time), sizeof(m_last_command_time));\n    // Deserialize the ranks\n    for (auto &rank : m_ranks) {\n        rank.deserialize(stream);\n    }\n}\n\n} // namespace DRAMPower"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr4/DDR4Core.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_DDR4_DDR4CORE_H\n#define DRAMPOWER_STANDARDS_DDR4_DDR4CORE_H\n\n#include \"DRAMPower/util/Deserialize.h\"\n#include \"DRAMPower/util/Serialize.h\"\n#include <DRAMPower/Types.h>\n#include <DRAMPower/dram/Rank.h>\n#include <DRAMPower/command/Command.h>\n#include <DRAMPower/data/stats.h>\n#include <DRAMPower/util/ImplicitCommandHandler.h>\n#include <DRAMPower/simconfig/simconfig.h>\n\n#include <DRAMPower/memspec/MemSpecDDR4.h>\n\n#include <vector>\n\nnamespace DRAMPower {\n\nnamespace internal {\n    template<typename Core>\n    class TestAccessor;\n}\n\nstruct DDR4CoreMemSpec {\n    DDR4CoreMemSpec(const MemSpecDDR4& memSpec)\n        : numberOfBanks(memSpec.numberOfBanks)\n        , numberOfRanks(memSpec.numberOfRanks)\n        , tRFC(memSpec.memTimingSpec.tRFC)\n        , tRAS(memSpec.memTimingSpec.tRAS)\n        , tRCD(memSpec.memTimingSpec.tRCD)\n        , tRP(memSpec.memTimingSpec.tRP)\n        , prechargeOffsetRD(memSpec.prechargeOffsetRD)\n        , prechargeOffsetWR(memSpec.prechargeOffsetWR)\n    {}\n\n    uint64_t numberOfBanks;\n    uint64_t numberOfRanks;\n\n    uint64_t tRFC;\n    uint64_t tRAS;\n    uint64_t tRCD;\n    uint64_t tRP;\n    uint64_t prechargeOffsetRD;\n    uint64_t prechargeOffsetWR;\n};\n\nclass DDR4Core : public util::Serialize, public util::Deserialize {\n// Friend classes\nfriend class internal::TestAccessor<DDR4Core>;\n\n// Public constructors and assignment operators\npublic:\n    DDR4Core(const MemSpecDDR4& memSpec)\n        : m_memSpec(memSpec)\n        , m_ranks(memSpec.numberOfRanks, {static_cast<std::size_t>(memSpec.numberOfBanks)})\n    {}\n\n// Public member functions\npublic:\n// Member functions\n    void doCommand(const Command& cmd);\n    timestamp_t getLastCommandTime() const;\n    bool isSerializable() const;\n    void getWindowStats(timestamp_t timestamp, SimulationStats &stats);\n// Overrides\n    void serialize(std::ostream& stream) const override;\n    void deserialize(std::istream& stream) override;\n\n// Private member functions\nprivate:\n    void handleAct(Rank & rank, Bank & bank, timestamp_t timestamp);\n    void handlePre(Rank & rank, Bank & bank, timestamp_t timestamp);\n    void handlePreAll(Rank & rank, timestamp_t timestamp); \n    void handleRefAll(std::size_t rank_idx, timestamp_t timestamp);\n    void handleSelfRefreshEntry(std::size_t rank_idx, timestamp_t timestamp);\n    void handleSelfRefreshExit(Rank & rank, timestamp_t timestamp);\n    void handleRead(Rank & rank, Bank & bank, timestamp_t timestamp);\n    void handleWrite(Rank & rank, Bank & bank, timestamp_t timestamp);\n    void handleReadAuto(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp);\n    void handleWriteAuto(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp);\n    void handlePowerDownActEntry(std::size_t rank_idx, timestamp_t timestamp);\n    void handlePowerDownActExit(std::size_t rank_idx, timestamp_t timestamp);\n    void handlePowerDownPreEntry(std::size_t rank_idx, timestamp_t timestamp);\n    void handlePowerDownPreExit(std::size_t rank_idx, timestamp_t timestamp);\n\n    timestamp_t earliestPossiblePowerDownEntryTime(Rank & rank) const;\n\n\n// Private members variables\nprivate:\n    DDR4CoreMemSpec m_memSpec;\n    std::vector<Rank> m_ranks;\n    ImplicitCommandHandler<DDR4Core> m_implicitCommandHandler;\n    timestamp_t m_last_command_time = 0;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_DDR4_DDR4CORE_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr4/DDR4Interface.cpp",
    "content": "#include \"DDR4Interface.h\"\n#include \"DRAMPower/util/databus_types.h\"\n\nnamespace DRAMPower {\n\n    static constexpr DRAMUtils::Config::ToggleRateDefinition busConfig {\n        0,\n        0,\n        0,\n        0,\n        DRAMUtils::Config::TogglingRateIdlePattern::H,\n        DRAMUtils::Config::TogglingRateIdlePattern::H\n    };\n\n    DDR4Interface::DDR4Interface(const MemSpecDDR4& memSpec, const config::SimConfig &simConfig)\n        : m_memSpec(memSpec)\n        , m_commandBus{cmdBusWidth, 1,\n            util::BusIdlePatternSpec::H, util::BusInitPatternSpec::H}\n        , m_dataBus{\n            util::databus_presets::getDataBusPreset(\n                util::DataBusConfig{\n                    memSpec.bitWidth * memSpec.numberOfDevices,\n                    memSpec.dataRate,\n                    simConfig.toggleRateDefinition.value_or(busConfig)\n                },\n                simConfig.toggleRateDefinition.has_value()\n                    ? util::DataBusMode::TogglingRate\n                    : util::DataBusMode::Bus,\n                false\n            )\n        }\n        , m_readDQS(memSpec.dataRate, true)\n        , m_writeDQS(memSpec.dataRate, true)\n        , m_clock(2, false)\n        , m_dbi(memSpec.numberOfDevices * memSpec.bitWidth, memSpec.burstLength,\n            [this](timestamp_t load_timestamp, timestamp_t, std::size_t pin, bool inversion_state, bool read) {\n            this->handleDBIPinChange(load_timestamp, pin, inversion_state, read);\n        }, false)\n        , m_dbiread(m_dbi.getChunksPerWidth().value(), pin_dbi_t{m_dbi.getIdlePattern(), m_dbi.getIdlePattern()})\n        , m_dbiwrite(m_dbi.getChunksPerWidth().value(), pin_dbi_t{m_dbi.getIdlePattern(), m_dbi.getIdlePattern()})\n        , prepostambleReadMinTccd(memSpec.prePostamble.readMinTccd)\n        , prepostambleWriteMinTccd(memSpec.prePostamble.writeMinTccd)\n        , m_ranks(memSpec.numberOfRanks)\n        , m_patternHandler(PatternEncoderOverrides {\n            {pattern_descriptor::V, PatternEncoderBitSpec::H},\n            {pattern_descriptor::X, PatternEncoderBitSpec::H},\n        }, cmdBusInitPattern)\n    {\n        registerPatterns();\n    }\n\n    void DDR4Interface::registerPatterns() {\n        using namespace pattern_descriptor;\n        // ACT\n        m_patternHandler.registerPattern<CmdType::ACT>({\n            L, L, R16, R15, R14, BG0, BG1, BA0, BA1,\n            V, V, V, R12, R17, R13, R11, R10, R0,\n            R1, R2, R3, R4, R5, R6, R7, R8, R9\n        });\n        // PRE\n        m_patternHandler.registerPattern<CmdType::PRE>({\n            L, H, L, H, L, BG0, BG1, BA0, BA1,\n            V, V, V, V, V, V, V, L, V,\n            V, V, V, V, V, V, V, V, V\n        });\n        // PREA\n        m_patternHandler.registerPattern<CmdType::PREA>({\n            L, H, L, H, L, V, V, V, V,\n            V, V, V, V, V, V, V, H, V,\n            V, V, V, V, V, V, V, V, V\n        });\n        // REFA\n        m_patternHandler.registerPattern<CmdType::REFA>({\n            L, H, L, L, H, V, V, V, V,\n            V, V, V, V, V, V, V, V, V,\n            V, V, V, V, V, V, V, V, V\n        });\n        // RD\n        m_patternHandler.registerPattern<CmdType::RD>({\n            L, H, H, L, H, BG0, BG1, BA0, BA1,\n            V, V, V, V, V, V, V, L, C0,\n            C1, C2, C3, C4, C5, C6, C7, C8, C9\n        });\n        // RDA\n        m_patternHandler.registerPattern<CmdType::RDA>({\n            L, H, H, L, H, BG0, BG1, BA0, BA1,\n            V, V, V, V, V, V, V, H, C0,\n            C1, C2, C3, C4, C5, C6, C7, C8, C9\n        });\n        // WR\n        m_patternHandler.registerPattern<CmdType::WR>({\n            L, H, H, L, L, BG0, BG1, BA0, BA1,\n            V, V, V, V, V, V, V, L, C0,\n            C1, C2, C3, C4, C5, C6, C7, C8, C9\n        });\n        // WRA\n        m_patternHandler.registerPattern<CmdType::WRA>({\n            L, H, H, L, L, BG0, BG1, BA0, BA1,\n            V, V, V, V, V, V, V, H, C0,\n            C1, C2, C3, C4, C5, C6, C7, C8, C9\n        });\n        // SREFEN\n        m_patternHandler.registerPattern<CmdType::SREFEN>({\n            L, H, L, L, H, V, V, V, V,\n            V, V, V, V, V, V, V, V, V,\n            V, V, V, V, V, V, V, V, V\n        });\n        // SREFEX\n        m_patternHandler.registerPattern<CmdType::SREFEX>({\n            H, X, X, X, X, X, X, X, X,\n            X, X, X, X, X, X, X, X, X,\n            X, X, X, X, X, X, X, X, X,\n\n            L, H, H, H, H, V, V, V, V,\n            V, V, V, V, V, V, V, V, V,\n            V, V, V, V, V, V, V, V, V\n        });\n        // PDEA\n        m_patternHandler.registerPattern<CmdType::PDEA>({\n            H, X, X, X, X, X, X, X, X,\n            X, X, X, X, X, X, X, X, X,\n            X, X, X, X, X, X, X, X, X,\n        });\n        // PDEP\n        m_patternHandler.registerPattern<CmdType::PDEP>({\n            H, X, X, X, X, X, X, X, X,\n            X, X, X, X, X, X, X, X, X,\n            X, X, X, X, X, X, X, X, X,\n        });\n        // PDXA\n        m_patternHandler.registerPattern<CmdType::PDXA>({\n            H, X, X, X, X, X, X, X, X,\n            X, X, X, X, X, X, X, X, X,\n            X, X, X, X, X, X, X, X, X,\n        });\n        // PDXP\n        m_patternHandler.registerPattern<CmdType::PDXP>({\n            H, X, X, X, X, X, X, X, X,\n            X, X, X, X, X, X, X, X, X,\n            X, X, X, X, X, X, X, X, X,\n        });\n    }\n\n    timestamp_t DDR4Interface::getLastCommandTime() const {\n        return m_last_command_time;\n    }\n\n    void DDR4Interface::doCommand(const Command& cmd) {\n        switch(cmd.type) {\n            case CmdType::ACT:\n            case CmdType::PRE:\n            case CmdType::PREA:\n            case CmdType::REFA:\n            case CmdType::SREFEN:\n            case CmdType::SREFEX:\n            case CmdType::PDEA:\n            case CmdType::PDEP:\n            case CmdType::PDXA:\n            case CmdType::PDXP:\n                handleCommandBus(cmd);\n                break;\n            case CmdType::RD:\n            case CmdType::RDA:\n                handleData(cmd, true);\n                break;\n            case CmdType::WR:\n            case CmdType::WRA:\n                handleData(cmd, false);\n                break;\n            case CmdType::END_OF_SIMULATION:\n                endOfSimulation(cmd.timestamp);\n                break;\n            default:\n                assert(false && \"Invalid command\");\n                break;\n        }\n        m_last_command_time = cmd.timestamp;\n    }\n\n    void DDR4Interface::handleDBIPinChange(const timestamp_t load_timestamp, std::size_t pin, bool state, bool read) {\n        assert(pin < m_dbiread.size() || pin < m_dbiwrite.size());\n        if (read) {\n            this->m_dbiread[pin].set(load_timestamp, state ? util::PinState::L : util::PinState::H, 1);\n        } else {\n            this->m_dbiwrite[pin].set(load_timestamp, state ? util::PinState::L : util::PinState::H, 1);\n        }\n    }\n\n    std::optional<const uint8_t *> DDR4Interface::handleDBIInterface(timestamp_t timestamp, std::size_t n_bits, const uint8_t* data, bool read) {\n        if (0 == n_bits || !data || !m_dbi.isEnabled()) {\n            // No DBI or no data to process\n            return std::nullopt;\n        }\n        timestamp_t virtual_time = timestamp * m_memSpec.dataRate;\n        // updateDBI calls the given callback to handle pin changes\n        return m_dbi.updateDBI(virtual_time, n_bits, data, read);\n    }\n\n    void DDR4Interface::handlePrePostamble(\n        const timestamp_t   timestamp,\n        const uint64_t      length,\n        RankInterface       &rank,\n        bool                read\n    )\n    {\n        uint64_t *lastAccess = &rank.lastWriteEnd;\n        uint64_t diff = 0;\n\n        if(read)\n        {\n            lastAccess = &rank.lastReadEnd;\n            // minTccd = prepostambleReadMinTccd;\n        }\n        \n        assert(timestamp >= *lastAccess);\n        if(timestamp < *lastAccess)\n        {\n            std::cout << \"[Error] PrePostamble diff is negative. The last read/write transaction was not completed\" << std::endl;\n            return;\n        }\n        diff = timestamp - *lastAccess;\n        *lastAccess = timestamp + length;\n        \n        //assert(diff >= 0);\n        \n        // Pre and Postamble seamless\n        if(diff == 0)\n        {\n            // Seamless read or write\n            if(read)\n                rank.seamlessPrePostambleCounter_read++;\n            else\n                rank.seamlessPrePostambleCounter_write++;\n        }\n    }\n\n    void DDR4Interface::handleOverrides(size_t length, bool read)\n    {\n        // Set command bus pattern overrides\n        switch(length) {\n            case 4:\n                if(read)\n                {\n                    // Read\n                    \n                    m_patternHandler.getEncoder().settings.updateSettings({\n                        {pattern_descriptor::C2, PatternEncoderBitSpec::L},\n                        {pattern_descriptor::C1, PatternEncoderBitSpec::L},\n                        {pattern_descriptor::C0, PatternEncoderBitSpec::L},\n                    });\n                }\n                else\n                {\n                    // Write\n                    m_patternHandler.getEncoder().settings.updateSettings({\n                        {pattern_descriptor::C2, PatternEncoderBitSpec::L},\n                        {pattern_descriptor::C1, PatternEncoderBitSpec::H},\n                        {pattern_descriptor::C0, PatternEncoderBitSpec::H},\n                    });\n                }\n                break;\n            default:\n                // Pull up\n                // No interface power needed for PatternEncoderBitSpec::H\n                // Defaults to burst length 8\n            case 8:\n                if(read)\n                {\n                    // Read\n                    m_patternHandler.getEncoder().settings.updateSettings({\n                        {pattern_descriptor::C2, PatternEncoderBitSpec::L},\n                        {pattern_descriptor::C1, PatternEncoderBitSpec::L},\n                        {pattern_descriptor::C0, PatternEncoderBitSpec::L},\n                    });\n                }\n                else\n                {\n                    // Write\n                    m_patternHandler.getEncoder().settings.updateSettings({\n                        {pattern_descriptor::C2, PatternEncoderBitSpec::H},\n                        {pattern_descriptor::C1, PatternEncoderBitSpec::H},\n                        {pattern_descriptor::C0, PatternEncoderBitSpec::H},\n                    });\n                }\n                break;\n        }\n    }\n\n    void DDR4Interface::handleCommandBus(const Command &cmd) {\n        auto pattern = m_patternHandler.getCommandPattern(cmd);\n        auto ca_length = m_patternHandler.getPattern(cmd.type).size() / m_commandBus.get_width();\n        this->m_commandBus.load(cmd.timestamp, pattern, ca_length);\n    }\n\n    void DDR4Interface::handleDQs(const Command &cmd, util::Clock &dqs, const size_t length) {\n        dqs.start(cmd.timestamp);\n        dqs.stop(cmd.timestamp + length / m_memSpec.dataRate);\n    }\n\n    void DDR4Interface::handleData(const Command &cmd, bool read) {\n        auto loadfunc = read ? &databus_t::loadRead : &databus_t::loadWrite;\n        util::Clock &dqs = read ? m_readDQS : m_writeDQS;\n        size_t length = 0;\n        if (0 == cmd.sz_bits) {\n            // No data provided by command\n            // Use default burst length\n            if (m_dataBus.isTogglingRate()) {\n                // If bus is enabled skip loading data\n                length = m_memSpec.burstLength;\n                (m_dataBus.*loadfunc)(cmd.timestamp, length * m_dataBus.getWidth(), nullptr);\n            }\n        } else {\n            std::optional<const uint8_t *> dbi_data = std::nullopt;\n            // Data provided by command\n            if (m_dataBus.isBus() && m_dbi.isEnabled()) {\n                // Only compute dbi for bus mode\n                dbi_data = handleDBIInterface(cmd.timestamp, cmd.sz_bits, cmd.data, read);\n            }\n            length = cmd.sz_bits / (m_dataBus.getWidth());\n            (m_dataBus.*loadfunc)(cmd.timestamp, cmd.sz_bits, dbi_data.value_or(cmd.data));\n        }\n        handleOverrides(length, read);\n        handleDQs(cmd, dqs, length);\n        handleCommandBus(cmd);\n        assert(m_ranks.size()>cmd.targetCoordinate.rank);\n        auto & rank = m_ranks[cmd.targetCoordinate.rank];\n        handlePrePostamble(cmd.timestamp, length / m_memSpec.dataRate, rank, read);\n    }\n\n    void DDR4Interface::endOfSimulation(timestamp_t timestamp) {\n        m_dbi.dispatchResetCallback(timestamp);\n    }\n\n    void DDR4Interface::getWindowStats(timestamp_t timestamp, SimulationStats &stats) const {\n        // DDR4 x16 have 2 DQs differential pairs\n        uint_fast8_t NumDQsPairs = 1;\n        if(m_memSpec.bitWidth == 16) {\n            NumDQsPairs = 2;\n        }\n        stats.rank_total.resize(m_memSpec.numberOfRanks);\n        for (size_t i = 0; i < m_memSpec.numberOfRanks; ++i) {\n            const RankInterface &rank_interface = m_ranks[i];\n            stats.rank_total[i].prepos.readSeamless = rank_interface.seamlessPrePostambleCounter_read;\n            stats.rank_total[i].prepos.writeSeamless = rank_interface.seamlessPrePostambleCounter_write;\n            \n            stats.rank_total[i].prepos.readMerged = rank_interface.mergedPrePostambleCounter_read;\n            stats.rank_total[i].prepos.readMergedTime = rank_interface.mergedPrePostambleTime_read;\n            stats.rank_total[i].prepos.writeMerged = rank_interface.mergedPrePostambleCounter_write;\n            stats.rank_total[i].prepos.writeMergedTime = rank_interface.mergedPrePostambleTime_write;\n        }\n\n        stats.commandBus = m_commandBus.get_stats(timestamp);\n\n        m_dataBus.get_stats(timestamp,\n            stats.readBus,\n            stats.writeBus,\n            stats.togglingStats.read,\n            stats.togglingStats.write\n        );\n\n        // single line stored in stats\n        // differential power calculated in interface calculation\n        stats.clockStats = 2u * m_clock.get_stats_at(timestamp);\n        stats.readDQSStats = NumDQsPairs * 2u * m_readDQS.get_stats_at(timestamp);\n        stats.writeDQSStats = NumDQsPairs * 2u * m_writeDQS.get_stats_at(timestamp);\n\n        for (const auto &dbi_pin : m_dbiread) {\n            stats.readDBI += dbi_pin.get_stats_at(timestamp, 2);\n        }\n        for (const auto &dbi_pin : m_dbiwrite) {\n            stats.writeDBI += dbi_pin.get_stats_at(timestamp, 2);\n        }\n    }\n\n    void DDR4Interface::serialize(std::ostream& stream) const {\n        stream.write(reinterpret_cast<const char*>(&m_last_command_time), sizeof(m_last_command_time));\n        m_patternHandler.serialize(stream);\n        m_commandBus.serialize(stream);\n        m_dataBus.serialize(stream);\n        m_readDQS.serialize(stream);\n        m_writeDQS.serialize(stream);\n        m_clock.serialize(stream);\n        m_dbi.serialize(stream);\n        for (const auto& rank : m_ranks) {\n            rank.serialize(stream);\n        }\n        for (const auto& pin : m_dbiread) {\n            pin.serialize(stream);\n        }\n        for (const auto& pin : m_dbiwrite) {\n            pin.serialize(stream);\n        }\n    }\n\n    void DDR4Interface::deserialize(std::istream& stream) {\n        stream.read(reinterpret_cast<char*>(&m_last_command_time), sizeof(m_last_command_time));\n        m_patternHandler.deserialize(stream);\n        m_commandBus.deserialize(stream);\n        m_dataBus.deserialize(stream);\n        m_readDQS.deserialize(stream);\n        m_writeDQS.deserialize(stream);\n        m_clock.deserialize(stream);\n        m_dbi.deserialize(stream);\n        for (auto &rank : m_ranks) {\n            rank.deserialize(stream);\n        }\n        for (auto &pin : m_dbiread) {\n            pin.deserialize(stream);\n        }\n        for (auto &pin : m_dbiwrite) {\n            pin.deserialize(stream);\n        }\n    }\n\n} // namespace DRAMPower\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr4/DDR4Interface.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_DDR4_DDR4INTERFACE_H\n#define DRAMPOWER_STANDARDS_DDR4_DDR4INTERFACE_H\n\n#include \"DRAMPower/util/pin.h\"\n#include \"DRAMPower/util/bus.h\"\n#include \"DRAMPower/util/databus_presets.h\"\n#include \"DRAMPower/util/clock.h\"\n#include \"DRAMPower/util/Serialize.h\"\n#include \"DRAMPower/util/Deserialize.h\"\n\n#include \"DRAMPower/Types.h\"\n#include \"DRAMPower/command/Command.h\"\n#include \"DRAMPower/dram/Rank.h\"\n#include \"DRAMPower/data/stats.h\"\n\n#include \"DRAMPower/util/PatternHandler.h\"\n#include \"DRAMPower/util/dbi.h\"\n\n#include \"DRAMPower/memspec/MemSpecDDR4.h\"\n\n#include \"DRAMPower/simconfig/simconfig.h\"\n\n#include <stdint.h>\n#include <cstddef>\n#include <vector>\n#include <optional>\n\nnamespace DRAMPower {\n\nstruct DDR4InterfaceMemSpec {\n    DDR4InterfaceMemSpec(const MemSpecDDR4& memSpec)\n        : dataRate(memSpec.dataRate)\n        , burstLength(memSpec.burstLength)\n        , bitWidth(memSpec.bitWidth)\n        , numberOfRanks(memSpec.numberOfRanks)\n    {}\n\n    uint64_t dataRate;\n    uint64_t burstLength;\n    uint64_t bitWidth;\n    uint64_t numberOfRanks;\n};\n\nclass DDR4Interface : public util::Serialize, public util::Deserialize {\n// Public constants\npublic:\n    const static std::size_t cmdBusWidth = 27;\n    const static uint64_t cmdBusInitPattern = (1<<cmdBusWidth)-1;\n\n// Public type definitions\npublic:\n    using commandbus_t = util::Bus<cmdBusWidth>;\n    using pin_dbi_t = util::Pin<8>; // max_burst_length = 8\n    using databus_t = util::databus_presets::databus_preset_t;\n    using patternHandler_t = PatternHandler<CmdType>;\n\n// Public constructors and assignment operators\npublic:\n    DDR4Interface(const MemSpecDDR4& memSpec, const config::SimConfig &simConfig = {});\n\n// Public member functions\npublic:\n// Member functions\n    timestamp_t getLastCommandTime() const;\n    void doCommand(const Command& cmd);\n    void getWindowStats(timestamp_t timestamp, SimulationStats &stats) const;\n// Overrides\n    void serialize(std::ostream& stream) const override;\n    void deserialize(std::istream& stream) override;\n// Extensions\n    void enableDBI(bool enable) {\n        m_dbi.enable(enable);\n    }\n\n// Private member functions\nprivate:\n    void registerPatterns();\n    std::optional<const uint8_t *> handleDBIInterface(timestamp_t timestamp, std::size_t n_bits, const uint8_t* data, bool read);\n    void handleDBIPinChange(const timestamp_t load_timestamp, std::size_t pin, bool state, bool read);\n    void handleOverrides(size_t length, bool read);\n    void handleDQs(const Command& cmd, util::Clock &dqs, size_t length);\n    void handleCommandBus(const Command& cmd);\n    void handleData(const Command &cmd, bool read);\n    void handlePrePostamble(\n        const timestamp_t   timestamp,\n        const uint64_t      length,\n        RankInterface &     rank,\n        bool                read\n    );\n    void endOfSimulation(timestamp_t timestamp);\n\n// Private member variables\nprivate:\n    DDR4InterfaceMemSpec m_memSpec;\n    commandbus_t m_commandBus;\n    databus_t m_dataBus;\n    util::Clock m_readDQS;\n    util::Clock m_writeDQS;\n    util::Clock m_clock;\n    util::DBI<uint8_t, 1, util::PinState::H, util::StaticDBI> m_dbi;\n    std::vector<pin_dbi_t> m_dbiread;\n    std::vector<pin_dbi_t> m_dbiwrite;\n    uint64_t prepostambleReadMinTccd;\n    uint64_t prepostambleWriteMinTccd;\n    std::vector<RankInterface> m_ranks;\n    patternHandler_t m_patternHandler;\n    timestamp_t m_last_command_time = 0;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_DDR4_DDR4INTERFACE_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr4/core_calculation_DDR4.cpp",
    "content": "#include \"core_calculation_DDR4.h\"\n\nnamespace DRAMPower {\n\n    Calculation_DDR4::Calculation_DDR4(const MemSpecDDR4 &memSpec)\n        : m_memSpec(memSpec)\n    {}\n\n    inline double Calculation_DDR4::E_BG_pre(std::size_t B, double VDD, double IDD2_N, double T_BG_pre) const {\n\t\treturn (1.0 / B) * VDD * IDD2_N * T_BG_pre;\n\t};\n\n\tinline double Calculation_DDR4::E_BG_act_shared(double VDD, double I_rho, double T_BG_act) const {\n\t\treturn VDD * I_rho * T_BG_act;\n\t}\n\n\tinline double Calculation_DDR4::E_BG_act_star(std::size_t B, double VDD, double IDD3_N, double I_rho, double T_BG_act_star) const {\n        return VDD * (1.0 / B) * (IDD3_N - I_rho) * T_BG_act_star;\n\t}\n\n    inline double Calculation_DDR4::E_pre(double VDD, double IBeta, double IDD2_N, double t_RP, uint64_t N_pre) const {\n\t\treturn VDD * (IBeta - IDD2_N) * t_RP * N_pre;\n\t}\n\n\tinline double Calculation_DDR4::E_act(double VDD, double I_theta, double I_1, double t_RAS, uint64_t N_act) const {\n\t\treturn VDD * (I_theta - I_1) * t_RAS * N_act;\n\t}\n\n\tinline double Calculation_DDR4::E_RD(double VDD, double IDD4_R, double IDD3_N, double t_CK, std::size_t BL, std::size_t DR, uint64_t N_RD) const {\n        return VDD * (IDD4_R - IDD3_N) * (double(BL) / DR) * t_CK * N_RD;\n\t}\n\n\tinline double Calculation_DDR4::E_WR(double VDD, double IDD4_W, double IDD3_N, double t_CK, std::size_t BL, std::size_t DR, uint64_t N_WR) const {\n\t\treturn VDD * (IDD4_W - IDD3_N) * (BL / DR) * t_CK * N_WR;\n\t}\n\n\tinline double Calculation_DDR4::E_ref_ab(std::size_t B, double VDD, double IDD5B, double IDD3_N, double tRFC, uint64_t N_REF) const {\n        return (1.0 / B) * VDD * (IDD5B - IDD3_N) * tRFC * N_REF;\n\t}\n\n\tenergy_t Calculation_DDR4::calcEnergy(const SimulationStats &stats) const {\n\n            // Timings\n            double t_CK = m_memSpec.memTimingSpec.tCK;\n            auto t_RAS = m_memSpec.memTimingSpec.tRAS * t_CK;\n            auto t_RP = m_memSpec.memTimingSpec.tRP * t_CK;\n            auto t_RFC = m_memSpec.memTimingSpec.tRFC * t_CK;\n\n            auto rho = m_memSpec.bwParams.bwPowerFactRho;\n            auto BL = m_memSpec.burstLength;\n            auto DR = m_memSpec.dataRate;\n            auto B = m_memSpec.numberOfBanks;\n\n            energy_t energy(m_memSpec.numberOfBanks * m_memSpec.numberOfRanks * m_memSpec.numberOfDevices);\n\n            for (auto vd : {MemSpecDDR4::VoltageDomain::VDD, MemSpecDDR4::VoltageDomain::VPP}) {\n                auto VXX = m_memSpec.memPowerSpec[vd].vXX;\n                auto IXX_0 = m_memSpec.memPowerSpec[vd].iXX0;\n                auto IXX2N = m_memSpec.memPowerSpec[vd].iXX2N;\n                auto IXX3N = m_memSpec.memPowerSpec[vd].iXX3N;\n                auto IXX2P = m_memSpec.memPowerSpec[vd].iXX2P;\n                auto IXX3P = m_memSpec.memPowerSpec[vd].iXX3P;\n                auto IXX4R = m_memSpec.memPowerSpec[vd].iXX4R;\n                auto IXX4W = m_memSpec.memPowerSpec[vd].iXX4W;\n                auto IXX5X = m_memSpec.memPowerSpec[vd].iXX5X;\n                auto IXX6N = m_memSpec.memPowerSpec[vd].iXX6N;\n                auto IBeta = m_memSpec.memPowerSpec[vd].iBeta;\n\n                auto I_rho = rho * (IXX3N - IXX2N) + IXX2N;\n                auto I_theta = (IXX_0 * (t_RP + t_RAS) - IBeta * t_RP) * (1 / t_RAS);\n                auto I_1 = (1.0 / B) * (IXX3N + (B - 1) * (rho * (IXX3N - IXX2N) + IXX2N));\n\n                size_t energy_offset = 0;\n                size_t bank_offset = 0;\n                for (size_t r = 0; r < m_memSpec.numberOfRanks; ++r) {\n                    for(size_t d = 0; d < m_memSpec.numberOfDevices; d++)\n                    {\n                        energy_offset = r * m_memSpec.numberOfDevices * m_memSpec.numberOfBanks +\n                            d * m_memSpec.numberOfBanks;\n                        // Bank offset doesn't include numberOfDevices, because one device is simulated\n                        // The stats only contain one device per rank\n                        bank_offset = r * m_memSpec.numberOfBanks;\n                        for (size_t b = 0; b < m_memSpec.numberOfBanks; ++b) {\n                            const auto &bank = stats.bank[bank_offset + b];\n\n                            energy.bank_energy[energy_offset + b].E_act +=\n                                E_act(VXX, I_theta, I_1, t_RAS, bank.counter.act);\n                            energy.bank_energy[energy_offset + b].E_pre +=\n                                E_pre(VXX, IBeta, IXX2N, t_RP, bank.counter.pre);\n                            energy.bank_energy[energy_offset + b].E_bg_act +=\n                                E_BG_act_star(B, VXX, IXX3N, I_rho,\n                                    stats.bank[bank_offset + b].cycles.activeTime() * t_CK);\n                            energy.bank_energy[energy_offset + b].E_bg_pre +=\n                                E_BG_pre(B, VXX, IXX2N, stats.rank_total[r].cycles.pre * t_CK);\n                            energy.bank_energy[energy_offset + b].E_RD +=\n                                E_RD(VXX, IXX4R, IXX3N, t_CK, BL, DR, bank.counter.reads);\n                            energy.bank_energy[energy_offset + b].E_WR +=\n                                E_WR(VXX, IXX4W, IXX3N, t_CK, BL, DR, bank.counter.writes);\n                            energy.bank_energy[energy_offset + b].E_RDA +=\n                                E_RD(VXX, IXX4R, IXX3N, t_CK, BL, DR, bank.counter.readAuto);\n                            energy.bank_energy[energy_offset + b].E_WRA +=\n                                E_WR(VXX, IXX4W, IXX3N, t_CK, BL, DR, bank.counter.writeAuto);\n                            energy.bank_energy[energy_offset + b].E_pre_RDA +=\n                                E_pre(VXX, IBeta, IXX2N, t_RP, bank.counter.readAuto);\n                            energy.bank_energy[energy_offset + b].E_pre_WRA +=\n                                E_pre(VXX, IBeta, IXX2N, t_RP, bank.counter.writeAuto);\n                            energy.bank_energy[energy_offset + b].E_ref_AB +=\n                                E_ref_ab(B, VXX, IXX5X, IXX3N, t_RFC, bank.counter.refAllBank);\n                        }\n                    }\n\n                    energy.E_sref += VXX * IXX6N * stats.rank_total[r].cycles.selfRefresh * t_CK * m_memSpec.numberOfDevices;\n                    energy.E_PDNA += VXX * IXX3P * stats.rank_total[r].cycles.powerDownAct * t_CK * m_memSpec.numberOfDevices;\n                    energy.E_PDNP += VXX * IXX2P * stats.rank_total[r].cycles.powerDownPre * t_CK * m_memSpec.numberOfDevices;\n\n                    energy.E_bg_act_shared +=\n                        E_BG_act_shared(VXX, I_rho, stats.rank_total[r].cycles.act * t_CK) * m_memSpec.numberOfDevices;\n                }\n            }\n\n                return energy;\n\t}\n}\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr4/core_calculation_DDR4.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_DDR4_CALCULATION_DDR4_H\n#define DRAMPOWER_STANDARDS_DDR4_CALCULATION_DDR4_H\n\n#pragma once\n\n#include <DRAMPower/data/energy.h>\n\n#include <DRAMPower/Types.h>\n#include <DRAMPower/memspec/MemSpecDDR4.h>\n#include <DRAMPower/data/stats.h>\n\n#include <cstddef>\n#include <cstdint>\n\nnamespace DRAMPower \n{\n\nclass DDR4;\n\nclass Calculation_DDR4\n{\npublic:\n\tCalculation_DDR4(const MemSpecDDR4 &memSpec);\n\nprivate:\n\tinline double E_act(double VDD, double I_theta, double I_1, double t_RAS, uint64_t N_act) const;\n\tinline double E_pre(double VDD, double IBeta, double IDD2_N, double t_RP, uint64_t N_pre) const;\n\tinline double E_BG_pre(std::size_t B, double VDD, double IDD2_N, double T_BG_pre) const;\n\tinline double E_BG_act_star(std::size_t B, double VDD, double IDD3_N, double I_rho, double T_BG_act_star) const;\n\tinline double E_BG_act_shared(double VDD, double I_rho, double T_BG_act) const;\n\tinline double E_RD(double VDD, double IDD4_R, double IDD3_N, double t_CK, std::size_t BL, std::size_t DR, uint64_t N_RD) const;\n\tinline double E_WR(double VDD, double IDD4_W, double IDD3_N, double t_CK, std::size_t BL, std::size_t DR, uint64_t N_WR) const;\n\tinline double E_ref_ab(std::size_t B, double VDD, double IDD5B, double IDD3_N, double tRFC, uint64_t N_REF) const;\n\t\npublic:\n\tenergy_t calcEnergy(const SimulationStats &stats) const;\nprivate:\n\tconst MemSpecDDR4 &m_memSpec;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_DDR4_CALCULATION_DDR4_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr4/interface_calculation_DDR4.cpp",
    "content": "#include \"DRAMPower/standards/ddr4/interface_calculation_DDR4.h\"\n#include \"DRAMPower/data/energy.h\"\n\nnamespace DRAMPower {\n\n    \nstatic double calc_static_energy(double NxBits, double R_eq, double t_CK, double voltage) {\n    return NxBits * ((voltage * voltage) / R_eq) * t_CK; // N * P * t = N * E\n};\n\nstatic double calc_dynamic_energy(const uint64_t NxBits, const double energy) {\n    return NxBits * energy;\n};\n\nstatic double calcStaticTermination(const bool termination, const DRAMPower::util::bus_stats_t &stats, const double R_eq, const double t_CK, const uint64_t datarate, const double voltage) {\n    if (termination == false) {\n        return 0; // No static termination\n    }\n    // zeroes \n    return calc_static_energy(stats.zeroes, R_eq, t_CK / datarate, voltage);\n};\n\nInterfaceCalculation_DDR4::InterfaceCalculation_DDR4(const MemSpecDDR4 &memspec)\n    : memspec_(memspec)\n    , impedances_(memspec.memImpedanceSpec) \n    , t_CK_(memspec.memTimingSpec.tCK)\n    , VDD_(memspec.vddq)\n{}\n\ninterface_energy_info_t InterfaceCalculation_DDR4::calculateEnergy(const SimulationStats &stats) const {\n    interface_energy_info_t result;\n    result += calcClockEnergy(stats);\n    result += calcDQSEnergy(stats);\n    result += calcDQEnergyTogglingRate(stats.togglingStats);\n    result += calcDQEnergy(stats);\n    result += calcCAEnergy(stats);\n    result += calcDBIEnergy(stats);\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_DDR4::calcClockEnergy(const SimulationStats &stats) const {\n    interface_energy_info_t result;\n    // Pull up -> zeros\n    result.controller.staticEnergy =\n        calcStaticTermination(impedances_.ck_termination, stats.clockStats, impedances_.ck_R_eq, t_CK_, 2, VDD_); // datarate 2 -> half the time low other half high\n    result.controller.dynamicEnergy =\n        calc_dynamic_energy(stats.clockStats.zeroes_to_ones, impedances_.ck_dyn_E);\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_DDR4::calcDQSEnergy(const SimulationStats &stats) const {\n    interface_energy_info_t result;\n    // Pull up -> zeros\n    uint_fast8_t NumDQsPairs = 1;\n    if(memspec_.bitWidth == 16)\n        NumDQsPairs = 2;\n\n    uint64_t readcount = 0;\n    uint64_t writecount = 0;\n\n    uint64_t preposreadseamless = 0;\n    uint64_t preposwriteseamless = 0;\n\n    double preposreadzeroes = memspec_.prePostamble.read_zeroes;\n    double preposwritezeroes = memspec_.prePostamble.write_zeroes;\n    uint64_t preposreadzero_to_one = memspec_.prePostamble.read_zeroes_to_ones;\n    uint64_t preposwritezero_to_one = memspec_.prePostamble.write_zeroes_to_ones;\n    \n\n    for (auto& rank : stats.rank_total)\n    {\n        // Reads\n        readcount +=    rank.counter.reads +\n                        rank.counter.readAuto;\n\n        // Writes\n        writecount +=   rank.counter.writes +\n                        rank.counter.writeAuto;\n\n        // PrePostamble\n        preposreadseamless += rank.prepos.readSeamless;\n        preposwriteseamless += rank.prepos.writeSeamless;\n    }\n    \n    // PrePostamble\n    if (impedances_.wdqs_termination == true) {\n        // Write\n        result.controller.staticEnergy +=\n            calc_static_energy(NumDQsPairs * preposwritezeroes * (writecount - preposwriteseamless), impedances_.wdqs_R_eq, t_CK_, VDD_);\n        result.controller.dynamicEnergy +=\n            calc_dynamic_energy(NumDQsPairs * preposwritezero_to_one * (writecount - preposwriteseamless), impedances_.wdqs_dyn_E);\n    }\n    if (impedances_.rdqs_termination == true) {\n        // Read\n        result.dram.staticEnergy +=\n            calc_static_energy(NumDQsPairs * preposreadzeroes * (readcount - preposreadseamless), impedances_.rdqs_R_eq, t_CK_, VDD_);\n        result.dram.dynamicEnergy +=\n            calc_dynamic_energy(NumDQsPairs * preposreadzero_to_one * (readcount - preposreadseamless), impedances_.rdqs_dyn_E);\n    }\n\n    // Data\n    // Write\n    result.controller.staticEnergy +=\n        calcStaticTermination(impedances_.wdqs_termination, stats.writeDQSStats, impedances_.wdqs_R_eq, t_CK_, memspec_.dataRate, VDD_);\n    result.controller.dynamicEnergy +=\n        calc_dynamic_energy(stats.writeDQSStats.zeroes_to_ones, impedances_.wdqs_dyn_E);\n    \n    // Read\n    result.dram.staticEnergy +=\n        calcStaticTermination(impedances_.rdqs_termination, stats.readDQSStats, impedances_.rdqs_R_eq, t_CK_, memspec_.dataRate, VDD_);\n    result.dram.dynamicEnergy +=\n        calc_dynamic_energy(stats.readDQSStats.zeroes_to_ones, impedances_.rdqs_dyn_E);\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_DDR4::calcDQEnergyTogglingRate(const TogglingStats &stats) const\n{\n    interface_energy_info_t result;\n\n    // Write\n    result.controller.staticEnergy +=\n        calcStaticTermination(impedances_.wdq_termination, stats.write, impedances_.wdq_R_eq, t_CK_, memspec_.dataRate, VDD_);\n    result.controller.dynamicEnergy +=\n        calc_dynamic_energy(stats.write.zeroes_to_ones, impedances_.wdq_dyn_E);\n\n    // Read\n    result.dram.staticEnergy +=\n        calcStaticTermination(impedances_.rdq_termination, stats.read, impedances_.rdq_R_eq, t_CK_, memspec_.dataRate, VDD_);\n    result.dram.dynamicEnergy +=\n        calc_dynamic_energy(stats.read.zeroes_to_ones, impedances_.rdq_dyn_E);\n    \n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_DDR4::calcDQEnergy(const SimulationStats &stats) const {\n    interface_energy_info_t result;\n    // Read\n    result.dram.staticEnergy +=\n        calcStaticTermination(impedances_.rdq_termination, stats.readBus, impedances_.rdq_R_eq, t_CK_, memspec_.dataRate, VDD_);\n    result.dram.dynamicEnergy +=\n        calc_dynamic_energy(stats.readBus.zeroes_to_ones, impedances_.rdq_dyn_E);\n\n    // Write\n    result.controller.staticEnergy +=\n        calcStaticTermination(impedances_.wdq_termination, stats.writeBus, impedances_.wdq_R_eq, t_CK_, memspec_.dataRate, VDD_);\n    result.controller.dynamicEnergy +=\n        calc_dynamic_energy(stats.writeBus.zeroes_to_ones, impedances_.wdq_dyn_E);\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_DDR4::calcCAEnergy(const SimulationStats &stats) const {\n    interface_energy_info_t result;\n    // Pull up -> zeros\n    result.controller.staticEnergy =\n        calcStaticTermination(impedances_.ca_termination, stats.commandBus, impedances_.ca_R_eq, t_CK_, 1, VDD_);\n\n    result.controller.dynamicEnergy =\n        calc_dynamic_energy(stats.commandBus.zeroes_to_ones, impedances_.ca_dyn_E);\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_DDR4::calcDBIEnergy(const SimulationStats &stats) const {\n    interface_energy_info_t result;\n    // Read\n    result.dram.staticEnergy +=\n        calcStaticTermination(impedances_.rdbi_termination, stats.readDBI, impedances_.rdbi_R_eq, t_CK_, memspec_.dataRate, VDD_);\n    result.dram.dynamicEnergy +=\n        calc_dynamic_energy(stats.readDBI.zeroes_to_ones, impedances_.rdbi_dyn_E);\n\n    // Write\n    result.controller.staticEnergy +=\n        calcStaticTermination(impedances_.wdbi_termination, stats.writeDBI, impedances_.wdbi_R_eq, t_CK_, memspec_.dataRate, VDD_);\n    result.controller.dynamicEnergy +=\n        calc_dynamic_energy(stats.writeDBI.zeroes_to_ones, impedances_.wdbi_dyn_E);\n\n    return result;\n}\n\n}"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr4/interface_calculation_DDR4.h",
    "content": "#ifndef STANDARDS_DDR4_INTERFACE_CALCULATION_DDR4_H\n#define STANDARDS_DDR4_INTERFACE_CALCULATION_DDR4_H\n\n\n#include \"DRAMPower/data/energy.h\"\n#include \"DRAMPower/memspec/MemSpecDDR4.h\"\n#include \"DRAMPower/data/stats.h\"\n\nnamespace DRAMPower {\n\nclass InterfaceCalculation_DDR4 {\n   public:\n    InterfaceCalculation_DDR4(const MemSpecDDR4 &memspec);\n\n    interface_energy_info_t calculateEnergy(const SimulationStats &stats) const;\n\n   private:\n    const MemSpecDDR4 &memspec_;\n    const MemSpecDDR4::MemImpedanceSpec &impedances_;\n    double t_CK_;\n    double VDD_;\n\n    interface_energy_info_t calcClockEnergy(const SimulationStats &stats) const;\n    interface_energy_info_t calcDQSEnergy(const SimulationStats &stats) const;\n    interface_energy_info_t calcDQEnergyTogglingRate(const TogglingStats &stats) const;\n    interface_energy_info_t calcDQEnergy(const SimulationStats &stats) const;\n    interface_energy_info_t calcCAEnergy(const SimulationStats &stats) const;\n    interface_energy_info_t calcDBIEnergy(const SimulationStats &stats) const;\n};\n\n}  // namespace DRAMPower\n\n#endif /* STANDARDS_DDR4_INTERFACE_CALCULATION_DDR4_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr4/types.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_DDR4_TYPES_H\n#define DRAMPOWER_STANDARDS_DDR4_TYPES_H\n\n#include <DRAMUtils/memspec/standards/MemSpecDDR4.h>\n\n#include \"DRAMPower/memspec/MemSpecDDR4.h\"\n#include \"DRAMPower/standards/ddr4/DDR4Core.h\"\n#include \"DRAMPower/standards/ddr4/DDR4Interface.h\"\n#include \"DRAMPower/standards/ddr4/core_calculation_DDR4.h\"\n#include \"DRAMPower/standards/ddr4/interface_calculation_DDR4.h\"\n\nnamespace DRAMPower {\n\nstruct DDR4Types {\n    using DRAMUtilsMemSpec_t = DRAMUtils::MemSpec::MemSpecDDR4;\n    using MemSpec_t = MemSpecDDR4;\n    using Core_t = DDR4Core;\n    using Interface_t = DDR4Interface;\n    using CalcCore_t = Calculation_DDR4;\n    using CalcInterface_t = InterfaceCalculation_DDR4;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_DDR4_TYPES_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr5/DDR5.cpp",
    "content": "#include \"DRAMPower/standards/ddr5/DDR5.h\"\n\n#include <iostream>\n\n#include \"DRAMPower/data/stats.h\"\n#include \"DRAMPower/memspec/MemSpecDDR5.h\"\n#include \"DRAMPower/standards/ddr5/DDR5Interface.h\"\n#include \"DRAMPower/standards/ddr5/core_calculation_DDR5.h\"\n#include \"DRAMPower/standards/ddr5/interface_calculation_DDR5.h\"\n#include <DRAMPower/util/extensions.h>\n\nnamespace DRAMPower {\n\n    using namespace DRAMUtils::Config;\n\n    DDR5::DDR5(const MemSpecDDR5 &memSpec, const config::SimConfig &simConfig)\n        : m_memSpec(memSpec)\n        , m_interface(m_memSpec, simConfig)\n        , m_core(m_memSpec)\n    {}\n\n// Getters for CLI\n    util::CLIArchitectureConfig DDR5::getCLIArchitectureConfig() {\n        return util::CLIArchitectureConfig{\n            m_memSpec.numberOfDevices,\n            m_memSpec.numberOfRanks,\n            m_memSpec.numberOfBanks\n        };\n    }\n\n// Calculation\n    energy_t DDR5::calcCoreEnergyStats(const SimulationStats& stats) const {\n        Calculation_DDR5 calculation(m_memSpec);\n        return calculation.calcEnergy(stats);\n    }\n\n    interface_energy_info_t DDR5::calcInterfaceEnergyStats(const SimulationStats& stats) const {\n        InterfaceCalculation_DDR5 calculation(m_memSpec);\n        return calculation.calculateEnergy(stats);\n    }\n\n// Stats\n    SimulationStats DDR5::getWindowStats(timestamp_t timestamp) {\n        SimulationStats stats;\n        m_core.getWindowStats(timestamp, stats);\n        m_interface.getWindowStats(timestamp, stats);\n        return stats;\n    }\n\n// Serialization\n    void DDR5::serialize_impl(std::ostream &stream) const {\n        m_core.serialize(stream);\n        m_interface.serialize(stream);\n    }\n\n    void DDR5::deserialize_impl(std::istream &stream) {\n        m_core.deserialize(stream);\n        m_interface.deserialize(stream);\n    }\n\n} // namespace DRAMPower\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr5/DDR5.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_DDR5_DDR5_H\n#define DRAMPOWER_STANDARDS_DDR5_DDR5_H\n\n\n#include \"DRAMPower/util/cli_architecture_config.h\"\n\n#include \"DRAMPower/Types.h\"\n#include \"DRAMPower/dram/dram_base.h\"\n#include <DRAMPower/command/Command.h>\n#include \"DRAMPower/data/energy.h\"\n#include <DRAMPower/data/stats.h>\n\n#include \"DRAMPower/standards/ddr5/DDR5Core.h\"\n#include \"DRAMPower/standards/ddr5/DDR5Interface.h\"\n#include \"DRAMPower/memspec/MemSpecDDR5.h\"\n\n#include \"DRAMPower/simconfig/simconfig.h\"\n\n#include <algorithm>\n\nnamespace DRAMPower {\n\nclass DDR5 : public dram_base<CmdType> {\n// public constructors and assignment operators\npublic:\n    DDR5() = delete; // No default constructor\n    DDR5(const DDR5&) = default; // copy constructor\n    DDR5& operator=(const DDR5&) = default; // copy assignment operator\n    DDR5(DDR5&&) = default; // move constructor\n    DDR5& operator=(DDR5&&) = default; // move assignment operator\n    ~DDR5() override = default;\n\n    DDR5(const MemSpecDDR5& memSpec, const config::SimConfig &simConfig = {});\n\n// Public member functions\npublic:\n    energy_t calcCoreEnergyStats(const SimulationStats& stats) const override;\n    interface_energy_info_t calcInterfaceEnergyStats(const SimulationStats& stats) const override;\n    SimulationStats getWindowStats(timestamp_t timestamp) override;\n    util::CLIArchitectureConfig getCLIArchitectureConfig() override;\n    bool isSerializable() const override {\n        return m_core.isSerializable();\n    }\n// member functions\n    DDR5Core& getCore() {\n        return m_core;\n    }\n    const DDR5Core& getCore() const {\n        return m_core;\n    }\n    DDR5Interface& getInterface() {\n        return m_interface;\n    }\n    const DDR5Interface& getInterface() const {\n        return m_interface;\n    }\n\n// Private member functions\nprivate:\n// Overrides\n    void doCoreCommandImpl(const Command& command) override {\n        m_core.doCommand(command);\n    }\n    void doInterfaceCommandImpl(const Command& command) override {\n        m_interface.doCommand(command);\n    }\n    timestamp_t getLastCommandTime_impl() const override {\n        return std::max(m_core.getLastCommandTime(), m_interface.getLastCommandTime());\n    }\n    void serialize_impl(std::ostream& stream) const override;\n    void deserialize_impl(std::istream& stream) override;\n\n// Private member variables\nprivate:\n    MemSpecDDR5 m_memSpec;\n    DDR5Interface m_interface;\n    DDR5Core m_core;\n};\n\n}  // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_DDR5_DDR5_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr5/DDR5Core.cpp",
    "content": "#include \"DDR5Core.h\"\n#include \"DRAMPower/util/RegisterHelper.h\"\n\nnamespace DRAMPower {\n\nvoid DDR5Core::doCommand(const Command& cmd) {\n    m_implicitCommandHandler.processImplicitCommandQueue(*this, cmd.timestamp, m_last_command_time);\n    m_last_command_time = std::max(cmd.timestamp, m_last_command_time);\n    switch(cmd.type) {\n        case CmdType::ACT:\n            util::coreHelpers::bankHandler(cmd, m_ranks, this, &DDR5Core::handleAct);\n            break;\n        case CmdType::PRE:\n            util::coreHelpers::bankHandler(cmd, m_ranks, this, &DDR5Core::handlePre);\n            break;\n        case CmdType::RD:\n            util::coreHelpers::bankHandler(cmd, m_ranks, this, &DDR5Core::handleRead);\n            break;\n        case CmdType::RDA:\n            util::coreHelpers::bankHandlerIdx(cmd, m_ranks, this, &DDR5Core::handleReadAuto);\n            break;\n        case CmdType::WR:\n            util::coreHelpers::bankHandler(cmd, m_ranks, this, &DDR5Core::handleWrite);\n            break;\n        case CmdType::WRA:\n            util::coreHelpers::bankHandlerIdx(cmd, m_ranks, this, &DDR5Core::handleWriteAuto);\n            break;\n        case CmdType::PRESB:\n            util::coreHelpers::bankGroupHandler(cmd, m_ranks, this, &DDR5Core::handlePreSameBank);\n            break;\n        case CmdType::REFSB:\n            util::coreHelpers::bankGroupHandlerIdx(cmd, m_ranks, this, &DDR5Core::handleRefSameBank);\n            break;\n        case CmdType::REFA:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &DDR5Core::handleRefAll);\n            break;\n        case CmdType::PREA:\n            util::coreHelpers::rankHandler(cmd, m_ranks, this, &DDR5Core::handlePreAll);\n            break;\n        case CmdType::SREFEN:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &DDR5Core::handleSelfRefreshEntry);\n            break;\n        case CmdType::SREFEX:\n            util::coreHelpers::rankHandler(cmd, m_ranks, this, &DDR5Core::handleSelfRefreshExit);\n            break;\n        case CmdType::PDEA:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &DDR5Core::handlePowerDownActEntry);\n            break;\n        case CmdType::PDEP:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &DDR5Core::handlePowerDownPreEntry);\n            break;\n        case CmdType::PDXA:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &DDR5Core::handlePowerDownActExit);\n            break;\n        case CmdType::PDXP:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &DDR5Core::handlePowerDownPreExit);\n            break;\n        case CmdType::NOP:\n        case CmdType::END_OF_SIMULATION:\n            break;\n        default:\n            assert(false && \"Unsupported command\");\n            break;\n    }\n}\n\ntimestamp_t DDR5Core::getLastCommandTime() const {\n    return m_last_command_time;\n}\n\nbool DDR5Core::isSerializable() const {\n    return 0 == m_implicitCommandHandler.implicitCommandCount();\n}\n\nvoid DDR5Core::handleAct(Rank &rank, Bank &bank, timestamp_t timestamp) {\n    bank.counter.act++;\n\n    bank.cycles.act.start_interval(timestamp);\n\n    if ( !rank.isActive(timestamp) ) {\n        rank.cycles.act.start_interval(timestamp);\n    };\n\n    bank.bankState = Bank::BankState::BANK_ACTIVE;\n}\n\nvoid DDR5Core::handlePre(Rank &rank, Bank &bank, timestamp_t timestamp) {\n    if (bank.bankState == Bank::BankState::BANK_PRECHARGED)\n        return;\n\n    bank.counter.pre++;\n    bank.cycles.act.close_interval(timestamp);\n    bank.latestPre = timestamp;\n    bank.bankState = Bank::BankState::BANK_PRECHARGED;\n\n    if ( !rank.isActive(timestamp) ) {\n        rank.cycles.act.close_interval(timestamp);\n    }\n}\n\nvoid DDR5Core::handlePreSameBank(Rank & rank, std::size_t bank_id, timestamp_t timestamp) {\n    auto bank_id_inside_bg = bank_id % m_memSpec.banksPerGroup;\n    for(unsigned bank_group = 0; bank_group < m_memSpec.numberOfBankGroups; bank_group++) {\n        auto & bank = rank.banks[bank_group * m_memSpec.banksPerGroup + bank_id_inside_bg];\n        handlePre(rank, bank, timestamp);\n    }\n}\n\nvoid DDR5Core::handlePreAll(Rank &rank, timestamp_t timestamp) {\n    for (auto &bank: rank.banks) {\n        handlePre(rank, bank, timestamp);\n    }\n}\n\nvoid DDR5Core::handleRefSameBank(std::size_t rank_idx, std::size_t bank_id, timestamp_t timestamp) {\n    auto bank_id_inside_bg = bank_id % m_memSpec.banksPerGroup;\n    for(unsigned bank_group = 0; bank_group < m_memSpec.numberOfBankGroups; bank_group++) {\n        std::size_t bank_idx = bank_group * m_memSpec.banksPerGroup + bank_id_inside_bg;\n        auto& counter = m_ranks[rank_idx].banks[bank_idx].counter.refSameBank;\n        handleRefreshOnBank(rank_idx, bank_idx, timestamp, m_memSpec.tRFCsb, counter);\n    }\n}\n\nvoid DDR5Core::handleRefAll(std::size_t rank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    for (std::size_t bank_idx = 0; bank_idx < rank.banks.size(); ++bank_idx) {\n        auto& counter = m_ranks[rank_idx].banks[bank_idx].counter.refAllBank;\n        handleRefreshOnBank(rank_idx, bank_idx, timestamp, m_memSpec.tRFC, counter);\n    }\n\n    rank.endRefreshTime = timestamp + m_memSpec.tRFC;\n}\n\nvoid DDR5Core::handleRefreshOnBank(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp, uint64_t timing, uint64_t & counter){\n    ++counter;\n    auto& rank = m_ranks[rank_idx];\n    auto& bank = rank.banks[bank_idx];\n\n    if (!rank.isActive(timestamp)) {\n        rank.cycles.act.start_interval(timestamp);\n    }\n\n    bank.bankState = Bank::BankState::BANK_ACTIVE;\n\n    auto timestamp_end = timestamp + timing;\n\n    bank.refreshEndTime = timestamp_end;\n\n    if (!bank.cycles.act.is_open())\n        bank.cycles.act.start_interval(timestamp);\n\n    // Execute implicit pre-charge at refresh end\n    m_implicitCommandHandler.addImplicitCommand(timestamp_end, [rank_idx, bank_idx, timestamp_end](DDR5Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        auto& bank = rank.banks[bank_idx];\n        bank.bankState = Bank::BankState::BANK_PRECHARGED;\n        bank.cycles.act.close_interval(timestamp_end);\n\n        if (!rank.isActive(timestamp_end)) {\n            rank.cycles.act.close_interval(timestamp_end);\n        }\n    });\n}\n\nvoid DDR5Core::handleRead(Rank&, Bank &bank, timestamp_t){\n    ++bank.counter.reads;\n}\n\nvoid DDR5Core::handleReadAuto(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp) {\n    auto& bank = m_ranks[rank_idx].banks[bank_idx];\n    ++bank.counter.readAuto;\n\n    auto minBankActiveTime = bank.cycles.act.get_start() + m_memSpec.tRAS;\n    auto minReadActiveTime = timestamp + m_memSpec.prechargeOffsetRD;\n\n    auto delayed_timestamp = std::max(minBankActiveTime, minReadActiveTime);\n\n    // Execute PRE after minimum active time\n    m_implicitCommandHandler.addImplicitCommand(delayed_timestamp, [rank_idx, bank_idx, delayed_timestamp](DDR5Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        auto& bank = rank.banks[bank_idx];\n        self.handlePre(rank, bank, delayed_timestamp);\n    });\n}\n\nvoid DDR5Core::handleWrite(Rank&, Bank &bank, timestamp_t) {\n    ++bank.counter.writes;\n}\n\nvoid DDR5Core::handleWriteAuto(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp) {\n    auto& bank = m_ranks[rank_idx].banks[bank_idx];\n    ++bank.counter.writeAuto;\n\n    auto minBankActiveTime = bank.cycles.act.get_start() + m_memSpec.tRAS;\n    auto minWriteActiveTime = timestamp + m_memSpec.prechargeOffsetWR;\n\n    auto delayed_timestamp = std::max(minBankActiveTime, minWriteActiveTime);\n\n    // Execute PRE after minimum active time\n    m_implicitCommandHandler.addImplicitCommand(delayed_timestamp, [rank_idx, bank_idx, delayed_timestamp](DDR5Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        auto& bank = rank.banks[bank_idx];\n        self.handlePre(rank, bank, delayed_timestamp);\n    });\n}\n\nvoid DDR5Core::handleSelfRefreshEntry(std::size_t rank_idx, timestamp_t timestamp) {\n    // Issue implicit refresh\n    handleRefAll(rank_idx, timestamp);\n\n    // Handle self-refresh entry after tRFC\n    auto timestampSelfRefreshStart = timestamp + m_memSpec.tRFC;\n\n    m_implicitCommandHandler.addImplicitCommand(timestampSelfRefreshStart, [rank_idx, timestampSelfRefreshStart](DDR5Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.counter.selfRefresh++;\n        rank.cycles.sref.start_interval(timestampSelfRefreshStart);\n        rank.memState = MemState::SREF;\n    });\n}\n\nvoid DDR5Core::handleSelfRefreshExit(Rank &rank, timestamp_t timestamp) {\n    assert(rank.memState == MemState::SREF);\n    rank.cycles.sref.close_interval(timestamp);  // Duration between entry and exit\n    rank.memState = MemState::NOT_IN_PD;\n}\n\nvoid DDR5Core::handlePowerDownActEntry(std::size_t rank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    auto earliestPossibleEntry = this->earliestPossiblePowerDownEntryTime(rank);\n    auto entryTime = std::max(timestamp, earliestPossibleEntry);\n    m_implicitCommandHandler.addImplicitCommand(entryTime, [rank_idx, entryTime](DDR5Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.cycles.powerDownAct.start_interval(entryTime);\n        rank.memState = MemState::PDN_ACT;\n        if (rank.cycles.act.is_open()) {\n            rank.cycles.act.close_interval(entryTime);\n        }\n        for (auto & bank : rank.banks) {\n            if (bank.cycles.act.is_open()) {\n                bank.cycles.act.close_interval(entryTime);\n            }\n        };\n    });\n}\n\nvoid DDR5Core::handlePowerDownActExit(std::size_t rank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    auto earliestPossibleExit = this->earliestPossiblePowerDownEntryTime(rank);\n    auto exitTime = std::max(timestamp, earliestPossibleExit);\n\n    m_implicitCommandHandler.addImplicitCommand(exitTime, [rank_idx, exitTime](DDR5Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.memState = MemState::NOT_IN_PD;\n        rank.cycles.powerDownAct.close_interval(exitTime);\n\n        bool rank_active = false;\n\n        for (auto & bank : rank.banks) {\n            if (bank.counter.act != 0 && bank.cycles.act.get_end() == rank.cycles.powerDownAct.get_start()) {\n                rank_active = true;\n                bank.cycles.act.start_interval(exitTime);\n            }\n        }\n\n        if (rank_active) {\n            rank.cycles.act.start_interval(exitTime);\n        }\n\n    });\n}\n\nvoid DDR5Core::handlePowerDownPreEntry(std::size_t rank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    auto earliestPossibleEntry = this->earliestPossiblePowerDownEntryTime(rank);\n    auto entryTime = std::max(timestamp, earliestPossibleEntry);\n\n    m_implicitCommandHandler.addImplicitCommand(entryTime, [rank_idx, entryTime](DDR5Core &self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.cycles.powerDownPre.start_interval(entryTime);\n        rank.memState = MemState::PDN_PRE;\n    });\n}\n\nvoid DDR5Core::handlePowerDownPreExit(std::size_t rank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    auto earliestPossibleExit = this->earliestPossiblePowerDownEntryTime(rank);\n    auto exitTime = std::max(timestamp, earliestPossibleExit);\n\n    m_implicitCommandHandler.addImplicitCommand(exitTime, [rank_idx, exitTime](DDR5Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.memState = MemState::NOT_IN_PD;\n        rank.cycles.powerDownPre.close_interval(exitTime);\n    });\n}\n\ntimestamp_t DDR5Core::earliestPossiblePowerDownEntryTime(Rank &rank) {\n    timestamp_t entryTime = 0;\n\n    for (const auto &bank : rank.banks) {\n        entryTime = std::max(\n            {entryTime,\n                bank.counter.act == 0 ? 0\n                                    : bank.cycles.act.get_start() + m_memSpec.tRCD,\n                bank.counter.pre == 0 ? 0 : bank.latestPre + m_memSpec.tRP,\n                bank.refreshEndTime});\n    }\n\n    return entryTime;\n}\n\nvoid DDR5Core::getWindowStats(timestamp_t timestamp, SimulationStats &stats) {\n    m_implicitCommandHandler.processImplicitCommandQueue(*this, timestamp, m_last_command_time);\n    stats.bank.resize(m_memSpec.numberOfBanks * m_memSpec.numberOfRanks);\n    stats.rank_total.resize(m_memSpec.numberOfRanks);\n\n    auto simulation_duration = timestamp;\n    for (size_t i = 0; i < m_memSpec.numberOfRanks; ++i) {\n        const Rank &rank = m_ranks[i];\n        size_t bank_offset = i * m_memSpec.numberOfBanks;\n\n        for (std::size_t j = 0; j < m_memSpec.numberOfBanks; ++j) {\n            stats.bank[bank_offset + j].counter = rank.banks[j].counter;\n            stats.bank[bank_offset + j].cycles.act =\n                rank.banks[j].cycles.act.get_count_at(timestamp);\n            stats.bank[bank_offset + j].cycles.selfRefresh =\n                rank.cycles.sref.get_count_at(timestamp);\n            stats.bank[bank_offset + j].cycles.powerDownAct =\n                rank.cycles.powerDownAct.get_count_at(timestamp);\n            stats.bank[bank_offset + j].cycles.powerDownPre =\n                rank.cycles.powerDownPre.get_count_at(timestamp);\n            stats.bank[bank_offset + j].cycles.pre =\n                simulation_duration - (stats.bank[bank_offset + j].cycles.act +\n                                        rank.cycles.powerDownAct.get_count_at(timestamp) +\n                                        rank.cycles.powerDownPre.get_count_at(timestamp) +\n                                        rank.cycles.sref.get_count_at(timestamp));\n        }\n\n        stats.rank_total[i].cycles.pre =\n            simulation_duration - (rank.cycles.act.get_count_at(timestamp) +\n                                    rank.cycles.powerDownAct.get_count_at(timestamp) +\n                                    rank.cycles.powerDownPre.get_count_at(timestamp) +\n                                    rank.cycles.sref.get_count_at(timestamp));\n        stats.rank_total[i].cycles.act = rank.cycles.act.get_count_at(timestamp);\n        stats.rank_total[i].cycles.powerDownAct =\n            rank.cycles.powerDownAct.get_count_at(timestamp);\n        stats.rank_total[i].cycles.powerDownPre =\n            rank.cycles.powerDownPre.get_count_at(timestamp);\n        stats.rank_total[i].cycles.deepSleepMode =\n            rank.cycles.deepSleepMode.get_count_at(timestamp);\n        stats.rank_total[i].cycles.selfRefresh = rank.cycles.sref.get_count_at(timestamp);\n    }\n}\n\nvoid DDR5Core::serialize(std::ostream& stream) const {\n    stream.write(reinterpret_cast<const char*>(&m_last_command_time), sizeof(m_last_command_time));\n    for (const auto& rank : m_ranks) {\n        rank.serialize(stream);\n    }\n}\n\nvoid DDR5Core::deserialize(std::istream& stream) {\n    stream.read(reinterpret_cast<char*>(&m_last_command_time), sizeof(m_last_command_time));\n    for (auto& rank : m_ranks) {\n        rank.deserialize(stream);\n    }\n}\n\n} // namespace DRAMPower\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr5/DDR5Core.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_DDR5_DDR5CORE_H\n#define DRAMPOWER_STANDARDS_DDR5_DDR5CORE_H\n\n#include \"DRAMPower/command/Command.h\"\n#include \"DRAMPower/dram/Rank.h\"\n#include \"DRAMPower/util/ImplicitCommandHandler.h\"\n#include \"DRAMPower/util/Deserialize.h\"\n#include \"DRAMPower/util/Serialize.h\"\n\n#include \"DRAMPower/memspec/MemSpecDDR5.h\"\n\n#include <cstddef>\n#include <vector>\n\nnamespace DRAMPower {\n\nnamespace internal {\n    template<typename Core>\n    class TestAccessor;\n}\n\nstruct DDR5CoreMemSpec {\n    DDR5CoreMemSpec(const MemSpecDDR5& memSpec)\n        : numberOfBanks(memSpec.numberOfBanks)\n        , numberOfRanks(memSpec.numberOfRanks)\n        , banksPerGroup(memSpec.banksPerGroup)\n        , numberOfBankGroups(memSpec.numberOfBankGroups)\n        , tRFC(memSpec.memTimingSpec.tRFC)\n        , tRFCsb(memSpec.memTimingSpec.tRFCsb)\n        , tRAS(memSpec.memTimingSpec.tRAS)\n        , tRCD(memSpec.memTimingSpec.tRCD)\n        , tRP(memSpec.memTimingSpec.tRP)\n        , prechargeOffsetRD(memSpec.prechargeOffsetRD)\n        , prechargeOffsetWR(memSpec.prechargeOffsetWR)\n    {}\n\n    uint64_t numberOfBanks;\n    uint64_t numberOfRanks;\n    uint64_t banksPerGroup;\n    uint64_t numberOfBankGroups;\n\n    uint64_t tRFC;\n    uint64_t tRFCsb;\n    uint64_t tRAS;\n    uint64_t tRCD;\n    uint64_t tRP;\n    uint64_t prechargeOffsetRD;\n    uint64_t prechargeOffsetWR;\n};\n\nclass DDR5Core : public util::Serialize, public util::Deserialize {\n// Friend classes\nfriend class internal::TestAccessor<DDR5Core>;\n\n// Public constructors and assignment operators\npublic:\n    DDR5Core(const MemSpecDDR5& memSpec)\n        : m_memSpec(memSpec)\n        , m_ranks(memSpec.numberOfRanks, {static_cast<std::size_t>(memSpec.numberOfBanks)})\n    {}\n\n// Public member functions\npublic:\n// Member functions\n    void doCommand(const Command& cmd);\n    timestamp_t getLastCommandTime() const;\n    bool isSerializable() const;\n    void getWindowStats(timestamp_t timestamp, SimulationStats &stats);\n// Overrides\n    void serialize(std::ostream& stream) const override;\n    void deserialize(std::istream& stream) override;\n\n// Private member functions\nprivate:\n    void handleAct(Rank& rank, Bank& bank, timestamp_t timestamp);\n    void handlePre(Rank& rank, Bank& bank, timestamp_t timestamp);\n    void handlePreSameBank(Rank& rank, std::size_t bank_id, timestamp_t timestamp);\n    void handlePreAll(Rank& rank, timestamp_t timestamp);\n    void handleRefSameBank(std::size_t rank_idx, std::size_t bank_id, timestamp_t timestamp);\n    void handleRefAll(std::size_t rank_idx, timestamp_t timestamp);\n    void handleRefreshOnBank(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp, uint64_t timing, uint64_t& counter);\n    void handleSelfRefreshEntry(std::size_t rank_idx, timestamp_t timestamp);\n    void handleSelfRefreshExit(Rank& rank, timestamp_t timestamp);\n    void handleRead(Rank& rank, Bank& bank, timestamp_t timestamp);\n    void handleWrite(Rank& rank, Bank& bank, timestamp_t timestamp);\n    void handleReadAuto(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp);\n    void handleWriteAuto(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp);\n    void handlePowerDownActEntry(std::size_t rank_idx, timestamp_t timestamp);\n    void handlePowerDownActExit(std::size_t rank_idx, timestamp_t timestamp);\n    void handlePowerDownPreEntry(std::size_t rank_idx, timestamp_t timestamp);\n    void handlePowerDownPreExit(std::size_t rank_idx, timestamp_t timestamp);\n\n    timestamp_t earliestPossiblePowerDownEntryTime(Rank& rank);\n\n// Private member variables\nprivate:\n    DDR5CoreMemSpec m_memSpec;\n    std::vector<Rank> m_ranks;\n    ImplicitCommandHandler<DDR5Core> m_implicitCommandHandler;\n    timestamp_t m_last_command_time = 0;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_DDR5_DDR5CORE_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr5/DDR5Interface.cpp",
    "content": "#include \"DDR5Interface.h\"\n#include \"DRAMPower/simconfig/simconfig.h\"\n\nnamespace DRAMPower {\n\nstatic constexpr DRAMUtils::Config::ToggleRateDefinition busConfig {\n    0,\n    0,\n    0,\n    0,\n    DRAMUtils::Config::TogglingRateIdlePattern::H,\n    DRAMUtils::Config::TogglingRateIdlePattern::H\n};\n\nDDR5Interface::DDR5Interface(const MemSpecDDR5& memSpec, const config::SimConfig& simConfig)\n    : m_memSpec(memSpec)\n    , m_commandBus{cmdBusWidth, 1,\n        util::BusIdlePatternSpec::H, util::BusInitPatternSpec::H}\n    , m_dataBus{\n        util::databus_presets::getDataBusPreset(\n            util::DataBusConfig {\n                memSpec.bitWidth * memSpec.numberOfDevices,\n                memSpec.dataRate,\n                simConfig.toggleRateDefinition.value_or(busConfig)\n            },\n            simConfig.toggleRateDefinition.has_value()\n                ? util::DataBusMode::TogglingRate\n                : util::DataBusMode::Bus,\n            false\n        )\n    }\n    , m_readDQS(memSpec.dataRateSpec.dqsBusRate, true)\n    , m_writeDQS(memSpec.dataRateSpec.dqsBusRate, true)\n    , m_patternHandler(PatternEncoderOverrides{\n            {pattern_descriptor::V, PatternEncoderBitSpec::H},\n            {pattern_descriptor::X, PatternEncoderBitSpec::H},\n            {pattern_descriptor::C0, PatternEncoderBitSpec::H},\n            {pattern_descriptor::C1, PatternEncoderBitSpec::H},\n            // Default value for CID0-3 is H in Pattern.h\n            // {pattern_descriptor::CID0, PatternEncoderBitSpec::H},\n            // {pattern_descriptor::CID1, PatternEncoderBitSpec::H},\n            // {pattern_descriptor::CID2, PatternEncoderBitSpec::H},\n            // {pattern_descriptor::CID3, PatternEncoderBitSpec::H},\n          }, DDR5Interface::cmdBusInitPattern)\n    {\n        registerPatterns();\n    }\n\nvoid DDR5Interface::registerPatterns() {\n    using namespace pattern_descriptor;\n    // ACT\n    m_patternHandler.registerPattern<CmdType::ACT>({\n        // note: CID3 is mutually exclusive with R17 and depends on usage mode\n        L, L, R0, R1, R2, R3, BA0, BA1, BG0, BG1, BG2, CID0, CID1, CID2,\n        R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, CID3\n    });\n    // PRE\n    m_patternHandler.registerPattern<CmdType::PRE>({\n        H, H, L, H, H, CID3, BA0, BA1, BG0, BG1, BG2, CID0, CID1, CID2\n    });\n    // RD\n    m_patternHandler.registerPattern<CmdType::RD>({\n        H, L, H, H, H, H, BA0, BA1, BG0, BG1, BG2, CID0, CID1, CID2,\n        C2, C3, C4, C5, C6, C7, C8, C9, C10, V, H, V, V, CID3\n    });\n    // RDA\n    m_patternHandler.registerPattern<CmdType::RDA>({\n        H, L, H, H, H, H, BA0, BA1, BG0, BG1, BG2, CID0, CID1, CID2,\n        C2, C3, C4, C5, C6, C7, C8, C9, C10, V, L, V, V, CID3\n    });\n    // WR\n    m_patternHandler.registerPattern<CmdType::WR>({\n        H, L, H, H, L, H, BA0, BA1, BG0, BG1, BG2, CID0, CID1, CID2,\n        V, C3, C4, C5, C6, C7, C8, C9, C10, V, H, H, V, CID3\n    });\n    // WRA\n    m_patternHandler.registerPattern<CmdType::WRA>({\n        H, L, H, H, L, H, BA0, BA1, BG0, BG1, BG2, CID0, CID1, CID2,\n        V, C3, C4, C5, C6, C7, C8, C9, C10, V, L, H, V, CID3\n    });\n    // PRESB\n    m_patternHandler.registerPattern<CmdType::PRESB>({\n        H, H, L, H, L, CID3, BA0, BA1, V, V, H, CID0, CID1, CID2\n    });\n    // REFSB\n    m_patternHandler.registerPattern<CmdType::REFSB>({\n        H, H, L, L, H, CID3, BA0, BA1, V, V, H, CID0, CID1, CID2\n    });\n    // REFA\n    m_patternHandler.registerPattern<CmdType::REFA>({\n        H, H, L, L, H, CID3, V, V, V, V, L, CID0, CID1, CID2\n    });\n    // PREA\n    m_patternHandler.registerPattern<CmdType::PREA>({\n        H, H, L, H, L, CID3, V, V, V, V, L, CID0, CID1, CID2\n    });\n    // SREFEN\n    m_patternHandler.registerPattern<CmdType::SREFEN>({\n        H, H, H, L, H, V, V, V, V, H, L, V, V, V\n    });\n    // PDEA\n    m_patternHandler.registerPattern<CmdType::PDEA>({\n        H, H, H, L, H, V, V, V, V, V, H, L, V, V\n    });\n    // PDEP\n    m_patternHandler.registerPattern<CmdType::PDEP>({\n        H, H, H, L, H, V, V, V, V, V, H, L, V, V\n    });\n    // PDXA\n    m_patternHandler.registerPattern<CmdType::PDXA>({\n        H, H, H, H, H, V, V, V, V, V, V, V, V, V\n    });\n    // PDXP\n    m_patternHandler.registerPattern<CmdType::PDXP>({\n        H, H, H, H, H, V, V, V, V, V, V, V, V, V\n    });\n    // NOP\n    m_patternHandler.registerPattern<CmdType::NOP>({\n        H, H, H, H, H, V, V, V, V, V, V, V, V, V\n    });\n}\n\ntimestamp_t DDR5Interface::getLastCommandTime() const {\n    return m_last_command_time;\n}\n\nvoid DDR5Interface::doCommand(const Command& cmd) {\n    switch(cmd.type) {\n        case CmdType::NOP:\n        case CmdType::ACT:\n        case CmdType::PRE:\n        case CmdType::PRESB:\n        case CmdType::REFSB:\n        case CmdType::REFA:\n        case CmdType::PREA:\n        case CmdType::SREFEN:\n        case CmdType::SREFEX:\n        case CmdType::PDEA:\n        case CmdType::PDEP:\n        case CmdType::PDXA:\n        case CmdType::PDXP:\n            handleCommandBus(cmd);\n            break;\n        case CmdType::RD:\n        case CmdType::RDA:\n            handleData(cmd, true);\n            break;\n        case CmdType::WR:\n        case CmdType::WRA:\n            handleData(cmd, false);\n            break;\n        case CmdType::END_OF_SIMULATION:\n            break;\n        default:\n            assert(false && \"Invalid command\");\n            break;\n    }\n    m_last_command_time = cmd.timestamp;\n}\n\n// Interface\nvoid DDR5Interface::handleOverrides(size_t length, bool read)\n{\n    // Set command bus pattern overrides\n    switch(length) {\n        case 8:\n            m_patternHandler.getEncoder().settings.removeSetting(pattern_descriptor::C10);\n            if(read)\n            {\n                // Read\n                m_patternHandler.getEncoder().settings.updateSettings({\n                    {pattern_descriptor::C3, PatternEncoderBitSpec::L},\n                    {pattern_descriptor::C2, PatternEncoderBitSpec::L},\n                });\n            }\n            else\n            {\n                // Write\n                m_patternHandler.getEncoder().settings.updateSettings({\n                    {pattern_descriptor::C3, PatternEncoderBitSpec::L},\n                    {pattern_descriptor::C2, PatternEncoderBitSpec::H},\n                });\n            }\n            break;\n        default:\n            // Pull down\n            // No interface power needed for PatternEncoderBitSpec::L\n            // Defaults to burst length 16\n        case 16:\n            m_patternHandler.getEncoder().settings.removeSetting(pattern_descriptor::C10);\n            if(read)\n            {\n                // Read\n                m_patternHandler.getEncoder().settings.updateSettings({\n                    {pattern_descriptor::C3, PatternEncoderBitSpec::L},\n                    {pattern_descriptor::C2, PatternEncoderBitSpec::L},\n                });\n            }\n            else\n            {\n                // Write\n                m_patternHandler.getEncoder().settings.updateSettings({\n                    {pattern_descriptor::C3, PatternEncoderBitSpec::H},\n                    {pattern_descriptor::C2, PatternEncoderBitSpec::H},\n                });\n            }\n            break;\n        case 32:\n            if(read)\n            {\n                // Read\n                m_patternHandler.getEncoder().settings.updateSettings({\n                    {pattern_descriptor::C10, PatternEncoderBitSpec::L},\n                    {pattern_descriptor::C3, PatternEncoderBitSpec::L},\n                    {pattern_descriptor::C2, PatternEncoderBitSpec::L},\n                });\n            }\n            else\n            {\n                // Write\n                m_patternHandler.getEncoder().settings.updateSettings({\n                    {pattern_descriptor::C10, PatternEncoderBitSpec::L},\n                    {pattern_descriptor::C3, PatternEncoderBitSpec::H},\n                    {pattern_descriptor::C2, PatternEncoderBitSpec::H},\n                });\n            }\n            break;\n    }\n}\n\nvoid DDR5Interface::handleCommandBus(const Command& cmd) {\n    auto pattern = m_patternHandler.getCommandPattern(cmd);\n    auto ca_length = m_patternHandler.getPattern(cmd.type).size() / m_commandBus.get_width();\n    m_commandBus.load(cmd.timestamp, pattern, ca_length);\n}\n\nvoid DDR5Interface::handleDQs(const Command& cmd, util::Clock &dqs, size_t length) {\n    dqs.start(cmd.timestamp);\n    dqs.stop(cmd.timestamp + length / m_memSpec.dataRate);\n}\n\nvoid DDR5Interface::handleData(const Command &cmd, bool read) {\n    auto loadfunc = read ? &databus_t::loadRead : &databus_t::loadWrite;\n    util::Clock &dqs = read ? m_readDQS : m_writeDQS;\n    size_t length = 0;\n    if (0 == cmd.sz_bits) {\n        // No data provided by command\n        // Use default burst length\n        if (m_dataBus.isTogglingRate()) {\n            length = m_memSpec.burstLength;\n            (m_dataBus.*loadfunc)(cmd.timestamp, length * m_dataBus.getWidth(), nullptr);\n        }\n    } else {\n        // Data provided by command\n        length = cmd.sz_bits / (m_dataBus.getWidth());\n        (m_dataBus.*loadfunc)(cmd.timestamp, cmd.sz_bits, cmd.data);\n    }\n    handleDQs(cmd, dqs, length);\n    handleOverrides(length, read);\n    handleCommandBus(cmd);\n}\n\nvoid DDR5Interface::getWindowStats(timestamp_t timestamp, SimulationStats &stats) const {\n    stats.commandBus = m_commandBus.get_stats(timestamp);\n\n    m_dataBus.get_stats(timestamp,\n        stats.readBus,\n        stats.writeBus,\n        stats.togglingStats.read,\n        stats.togglingStats.write\n    );\n\n    stats.clockStats = 2 * m_clock.get_stats_at(timestamp);\n    stats.readDQSStats = 2 * m_readDQS.get_stats_at(timestamp);\n    stats.writeDQSStats = 2 * m_writeDQS.get_stats_at(timestamp);\n\n    // x16 devices have two dqs pairs\n    if(m_memSpec.bitWidth == 16)\n    {\n        stats.readDQSStats *= 2;\n        stats.writeDQSStats *= 2;\n    }\n}\n\nvoid DDR5Interface::serialize(std::ostream& stream) const {\n    stream.write(reinterpret_cast<const char*>(&m_last_command_time), sizeof(m_last_command_time));\n    m_patternHandler.serialize(stream);\n    m_commandBus.serialize(stream);\n    m_dataBus.serialize(stream);\n    m_readDQS.serialize(stream);\n    m_writeDQS.serialize(stream);\n    m_clock.serialize(stream);\n}\n\nvoid DDR5Interface::deserialize(std::istream& stream) {\n    stream.read(reinterpret_cast<char*>(&m_last_command_time), sizeof(m_last_command_time));\n    m_patternHandler.deserialize(stream);\n    m_commandBus.deserialize(stream);\n    m_dataBus.deserialize(stream);\n    m_readDQS.deserialize(stream);\n    m_writeDQS.deserialize(stream);\n    m_clock.deserialize(stream);\n}\n\n} // namespace DRAMPower\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr5/DDR5Interface.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_DDR5_DDR5INTERFACE_H\n#define DRAMPOWER_STANDARDS_DDR5_DDR5INTERFACE_H\n\n#include \"DRAMPower/util/bus.h\"\n#include \"DRAMPower/util/databus_presets.h\"\n#include \"DRAMPower/util/clock.h\"\n#include \"DRAMPower/util/Serialize.h\"\n#include \"DRAMPower/util/Deserialize.h\"\n\n#include \"DRAMPower/Types.h\"\n#include \"DRAMPower/command/Command.h\"\n#include \"DRAMPower/data/stats.h\"\n\n#include \"DRAMPower/util/PatternHandler.h\"\n\n#include \"DRAMPower/memspec/MemSpecDDR5.h\"\n\n#include \"DRAMPower/simconfig/simconfig.h\"\n\n#include <stdint.h>\n#include <cstddef>\n\nnamespace DRAMPower {\n\nstruct DDR5InterfaceMemSpec {\n    DDR5InterfaceMemSpec(const MemSpecDDR5& memSpec)\n        : dataRate(memSpec.dataRate)\n        , burstLength(memSpec.burstLength)\n        , bitWidth(memSpec.bitWidth)\n    {}\n\n    uint64_t dataRate;\n    uint64_t burstLength;\n    uint64_t bitWidth;\n};\n\nclass DDR5Interface : public util::Serialize, public util::Deserialize {\n// Public constants\npublic:\n    const static std::size_t cmdBusWidth = 14;\n    const static uint64_t cmdBusInitPattern = (1<<cmdBusWidth)-1;\n\n// Public type definitions\npublic:\n    using commandbus_t = util::Bus<cmdBusWidth>;\n    using databus_t = util::databus_presets::databus_preset_t;\n    using patternHandler_t = PatternHandler<CmdType>;\n\n// Public constructors and assignment operators\npublic:\n    DDR5Interface(const MemSpecDDR5& memSpec, const config::SimConfig &simConfig = {});\n\n// Public member functions\npublic:\n// Member functions\n    timestamp_t getLastCommandTime() const;\n    void doCommand(const Command& cmd);\n    void getWindowStats(timestamp_t timestamp, SimulationStats &stats) const;\n// Overrides\n    void serialize(std::ostream& stream) const override;\n    void deserialize(std::istream& stream) override;\n\n// Private member functions\nprivate:\n    void registerPatterns();\n    void handleOverrides(size_t length, bool read);\n    void handleDQs(const Command& cmd, util::Clock &dqs, size_t length);\n    void handleCommandBus(const Command& cmd);\n    void handleData(const Command &cmd, bool read);\n\n// Private member variables\nprivate:\n    DDR5InterfaceMemSpec m_memSpec;\n    commandbus_t m_commandBus;\n    databus_t m_dataBus;\n    util::Clock m_readDQS;\n    util::Clock m_writeDQS;\n    util::Clock m_clock;\n    patternHandler_t m_patternHandler;\n    timestamp_t m_last_command_time = 0;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_DDR5_DDR5INTERFACE_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr5/core_calculation_DDR5.cpp",
    "content": "#include \"core_calculation_DDR5.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n\nnamespace DRAMPower {\n\n    Calculation_DDR5::Calculation_DDR5(const MemSpecDDR5 &memSpec)\n        : m_memSpec(memSpec)\n    {}\n\n    double Calculation_DDR5::E_BG_pre(std::size_t B, double VDD, double IDD2_N, double T_BG_pre) const {\n        return (1.0 / B) * VDD * IDD2_N * T_BG_pre;\n    };\n\n    double Calculation_DDR5::E_BG_act_shared(double VDD, double I_rho, double T_BG_act) const {\n        return VDD * I_rho * T_BG_act;\n    }\n\n    double\n    Calculation_DDR5::E_BG_act_star(std::size_t B, double VDD, double IDD3_N, double I_rho, double T_BG_act_star) const {\n        return VDD * (1.0 / B) * (IDD3_N - I_rho) * T_BG_act_star;\n    }\n\n    double Calculation_DDR5::E_pre(double VDD, double IBeta, double IDD2_N, double t_RP, uint64_t N_pre) const {\n        return VDD * (IBeta - IDD2_N) * t_RP * N_pre;\n    }\n\n    double Calculation_DDR5::E_act(double VDD, double I_theta, double I_1, double t_RAS, uint64_t N_act) const {\n        return VDD * (I_theta - I_1) * t_RAS * N_act;\n    }\n\n    double Calculation_DDR5::E_RD(double VDD, double IDD4_R, double IDD3_N, double t_CK, std::size_t BL, std::size_t DR,\n                                  uint64_t N_RD) const {\n        return VDD * (IDD4_R - IDD3_N) * (double(BL) / DR) * t_CK * N_RD;\n    }\n\n    double Calculation_DDR5::E_WR(double VDD, double IDD4_W, double IDD3_N, double t_CK, std::size_t BL, std::size_t DR,\n                                  uint64_t N_WR) const {\n        return VDD * (IDD4_W - IDD3_N) * (BL / DR) * t_CK * N_WR;\n    }\n\n    double\n    Calculation_DDR5::E_ref_ab(std::size_t B, double VDD, double IDD5B, double IDD3_N, double tRFC, uint64_t N_REF) const {\n        return (1.0 / B) * VDD * (IDD5B - IDD3_N) * tRFC * N_REF;\n    }\n\n    double Calculation_DDR5::E_ref_sb(double VDD, double IDD5C, double I_BG, double tRFCsb, std::size_t BG,\n                                      uint64_t N_SB_REF) const {\n        return VDD * (IDD5C - I_BG) * tRFCsb * N_SB_REF * (1.0 / BG);\n    }\n\n    energy_t Calculation_DDR5::calcEnergy(const SimulationStats &stats) const {\n        double t_CK = m_memSpec.memTimingSpec.tCK;\n        auto t_RAS = m_memSpec.memTimingSpec.tRAS * t_CK;\n        auto t_RP = m_memSpec.memTimingSpec.tRP * t_CK;\n        auto t_RFC = m_memSpec.memTimingSpec.tRFC * t_CK;\n        auto t_RFCsb = m_memSpec.memTimingSpec.tRFCsb * t_CK;\n\n        auto rho = m_memSpec.bwParams.bwPowerFactRho;\n        auto BL = m_memSpec.burstLength;\n        auto DR = m_memSpec.dataRate;\n        auto B = m_memSpec.numberOfBanks;\n        auto BG = m_memSpec.numberOfBankGroups;\n\n        energy_t energy(m_memSpec.numberOfBanks * m_memSpec.numberOfRanks * m_memSpec.numberOfDevices);\n\n        for (auto vd : {MemSpecDDR5::VoltageDomain::VDD, MemSpecDDR5::VoltageDomain::VPP}) {\n            auto VXX = m_memSpec.memPowerSpec[vd].vXX;\n            auto IXX_0 = m_memSpec.memPowerSpec[vd].iXX0;\n            auto IXX2N = m_memSpec.memPowerSpec[vd].iXX2N;\n            auto IXX3N = m_memSpec.memPowerSpec[vd].iXX3N;\n            auto IXX2P = m_memSpec.memPowerSpec[vd].iXX2P;\n            auto IXX3P = m_memSpec.memPowerSpec[vd].iXX3P;\n            auto IXX4R = m_memSpec.memPowerSpec[vd].iXX4R;\n            auto IXX4W = m_memSpec.memPowerSpec[vd].iXX4W;\n            auto IXX5X = m_memSpec.memPowerSpec[vd].iXX5X;\n            auto IXX5C = m_memSpec.memPowerSpec[vd].iXX5C;\n            auto IXX6N = m_memSpec.memPowerSpec[vd].iXX6N;\n            auto IBeta = m_memSpec.memPowerSpec[vd].iBeta;\n\n            auto I_rho = rho * (IXX3N - IXX2N) + IXX2N;\n            auto I_theta = (IXX_0 * (t_RP + t_RAS) - IBeta * t_RP) * (1 / t_RAS);\n            auto I_1 = (1.0 / B) * (IXX3N + (B - 1) * (rho * (IXX3N - IXX2N) + IXX2N));\n            auto I_BG = I_rho + (I_1 - I_rho) * BG;\n\n            size_t energy_offset = 0;\n            size_t bank_offset = 0;\n            for (size_t i = 0; i < m_memSpec.numberOfRanks; ++i) {\n                for (size_t d = 0; d < m_memSpec.numberOfDevices; ++d) {\n                    energy_offset = i * m_memSpec.numberOfDevices * m_memSpec.numberOfBanks\n                                    + d * m_memSpec.numberOfBanks;\n                    bank_offset = i * m_memSpec.numberOfBanks;\n\n                    for (std::size_t b = 0; b < m_memSpec.numberOfBanks; ++b) {\n                        const auto &bank = stats.bank[bank_offset + b];\n\n                        energy.bank_energy[energy_offset + b].E_act +=\n                            E_act(VXX, I_theta, I_1, t_RAS, bank.counter.act);\n                        energy.bank_energy[energy_offset + b].E_pre +=\n                            E_pre(VXX, IBeta, IXX2N, t_RP, bank.counter.pre);\n                        energy.bank_energy[energy_offset + b].E_bg_act +=\n                            E_BG_act_star(B, VXX, IXX3N, I_rho,\n                                        stats.bank[bank_offset + b].cycles.activeTime() * t_CK);\n                        energy.bank_energy[energy_offset + b].E_bg_pre +=\n                            E_BG_pre(B, VXX, IXX2N, stats.rank_total[i].cycles.pre * t_CK);\n                        energy.bank_energy[energy_offset + b].E_RD +=\n                            E_RD(VXX, IXX4R, IXX3N, t_CK, BL, DR, bank.counter.reads);\n                        energy.bank_energy[energy_offset + b].E_WR +=\n                            E_WR(VXX, IXX4W, IXX3N, t_CK, BL, DR, bank.counter.writes);\n                        energy.bank_energy[energy_offset + b].E_RDA +=\n                            E_RD(VXX, IXX4R, IXX3N, t_CK, BL, DR, bank.counter.readAuto);\n                        energy.bank_energy[energy_offset + b].E_WRA +=\n                            E_WR(VXX, IXX4W, IXX3N, t_CK, BL, DR, bank.counter.writeAuto);\n                        energy.bank_energy[energy_offset + b].E_pre_RDA +=\n                            E_pre(VXX, IBeta, IXX2N, t_RP, bank.counter.readAuto);\n                        energy.bank_energy[energy_offset + b].E_pre_WRA +=\n                            E_pre(VXX, IBeta, IXX2N, t_RP, bank.counter.writeAuto);\n                        energy.bank_energy[energy_offset + b].E_ref_AB +=\n                            E_ref_ab(B, VXX, IXX5X, IXX3N, t_RFC, bank.counter.refAllBank);\n                        energy.bank_energy[energy_offset + b].E_ref_SB +=\n                            E_ref_sb(VXX, IXX5C, I_BG, t_RFCsb, BG, bank.counter.refSameBank);\n                    }\n                }\n\n                energy.E_sref += VXX * IXX6N * stats.rank_total[i].cycles.selfRefresh * t_CK * m_memSpec.numberOfDevices;\n                energy.E_PDNA += VXX * IXX3P * stats.rank_total[i].cycles.powerDownAct * t_CK * m_memSpec.numberOfDevices;\n                energy.E_PDNP += VXX * IXX2P * stats.rank_total[i].cycles.powerDownPre * t_CK * m_memSpec.numberOfDevices;\n\n                energy.E_bg_act_shared +=\n                    E_BG_act_shared(VXX, I_rho, stats.rank_total[i].cycles.act * t_CK) * m_memSpec.numberOfDevices;\n            }\n        }\n\n        return energy;\n    }\n}\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr5/core_calculation_DDR5.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_DDR5_CALCULATION_DDR5_H\n#define DRAMPOWER_STANDARDS_DDR5_CALCULATION_DDR5_H\n\n#include \"DRAMPower/data/stats.h\"\n#include \"DRAMPower/memspec/MemSpecDDR5.h\"\n#include <DRAMPower/data/energy.h>\n\n#include <DRAMPower/Types.h>\n\n#include <cstddef>\n#include <cstdint>\n\nnamespace DRAMPower\n{\n\nclass DDR5;\n\nclass Calculation_DDR5\n{\npublic:\n    Calculation_DDR5(const MemSpecDDR5 &memSpec);\n\nprivate:\n    inline double E_act(double VDD, double I_theta, double I_1, double t_RAS, uint64_t N_act) const;\n    inline double E_pre(double VDD, double IBeta, double IDD2_N, double t_RP, uint64_t N_pre) const;\n    inline double E_BG_pre(std::size_t B, double VDD, double IDD2_N, double T_BG_pre) const;\n    inline double E_BG_act_star(std::size_t B, double VDD, double IDD3_N, double I_rho, double T_BG_act_star) const;\n    inline double E_BG_act_shared(double VDD, double I_rho, double T_BG_act) const;\n    inline double E_RD(double VDD, double IDD4_R, double IDD3_N, double t_CK, std::size_t BL, std::size_t DR, uint64_t N_RD) const;\n    inline double E_WR(double VDD, double IDD4_W, double IDD3_N, double t_CK, std::size_t BL, std::size_t DR, uint64_t N_WR) const;\n    inline double E_ref_ab(std::size_t B, double VDD, double IDD5B, double IDD3_N, double tRFC, uint64_t N_REF) const;\n    inline double E_ref_sb(double VDD, double IDD5C, double I_BG, double tRFC, std::size_t BG, uint64_t N_SB_REF) const;\n\npublic:\n    energy_t calcEnergy(const SimulationStats &stats) const;\nprivate:\n    const MemSpecDDR5 &m_memSpec;\n};\n\n} // namespace DRAMPower\n\n\n#endif /* DRAMPOWER_STANDARDS_DDR5_CALCULATION_DDR5_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr5/interface_calculation_DDR5.cpp",
    "content": "#include \"DRAMPower/standards/ddr5/interface_calculation_DDR5.h\"\n#include \"DRAMPower/data/energy.h\"\n\nnamespace DRAMPower {\n\nstatic double calc_static_energy(uint64_t NxBits, const double R_eq, const double t_CK, const double voltage) {\n    return NxBits * (voltage * voltage) * t_CK / R_eq;\n};\n\nstatic double calc_dynamic_energy(const uint64_t transitions, const double energy) {\n    return transitions * energy;\n};\n\nstatic double calcStaticTermination(const bool termination, const DRAMPower::util::bus_stats_t &stats, const double R_eq, const double t_CK, const uint64_t datarate, const double voltage)\n{\n    if (termination == false) {\n        return 0; // No static termination\n    }\n    // zeroes\n    return calc_static_energy(stats.zeroes, R_eq, t_CK / datarate, voltage);\n}\n\nInterfaceCalculation_DDR5::InterfaceCalculation_DDR5(const MemSpecDDR5 &memspec)\n    : memspec_(memspec), impedances_(memspec_.memImpedanceSpec) {\n    t_CK_ = memspec_.memTimingSpec.tCK;\n    VDDQ_ = memspec_.vddq;\n}\n\ninterface_energy_info_t InterfaceCalculation_DDR5::calculateEnergy(const SimulationStats &stats) const {\n    interface_energy_info_t clock_energy = calcClockEnergy(stats);\n    interface_energy_info_t DQS_energy = calcDQSEnergy(stats);\n    interface_energy_info_t DQ_energy = calcDQEnergy(stats);\n    DQ_energy += calcDQEnergyTogglingRate(stats.togglingStats);\n    interface_energy_info_t CA_energy = calcCAEnergy(stats);\n\n    interface_energy_info_t result;\n    result += clock_energy;\n    result += DQS_energy;\n    result += CA_energy;\n    result += DQ_energy;\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_DDR5::calcClockEnergy(const SimulationStats &stats) const {\n    interface_energy_info_t result;\n\n    result.controller.staticEnergy =\n        calcStaticTermination(impedances_.ck_termination, stats.clockStats, impedances_.ck_R_eq, t_CK_, 2, VDDQ_); // datarate 2 -> half the time low other half high\n    result.controller.dynamicEnergy =\n       calc_dynamic_energy(stats.clockStats.zeroes_to_ones, impedances_.ck_dyn_E);\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_DDR5::calcDQSEnergy(const SimulationStats &stats) const {\n    interface_energy_info_t result;\n    result.dram.staticEnergy +=\n        calcStaticTermination(impedances_.rdqs_termination, stats.readDQSStats, impedances_.rdqs_R_eq, t_CK_, memspec_.dataRateSpec.dqsBusRate, VDDQ_);\n    result.controller.staticEnergy +=\n        calcStaticTermination(impedances_.wdqs_termination, stats.writeDQSStats, impedances_.wdqs_R_eq, t_CK_, memspec_.dataRateSpec.dqsBusRate, VDDQ_);\n\n    result.dram.dynamicEnergy +=\n        calc_dynamic_energy(stats.readDQSStats.zeroes_to_ones, impedances_.rdqs_dyn_E);\n    result.controller.dynamicEnergy +=\n        calc_dynamic_energy(stats.writeDQSStats.zeroes_to_ones, impedances_.wdqs_dyn_E);\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_DDR5::calcDQEnergyTogglingRate(const TogglingStats &stats) const {\n    interface_energy_info_t result;\n\n    // Read\n    result.dram.staticEnergy +=\n        calcStaticTermination(impedances_.rdq_R_eq, stats.read, impedances_.rdq_R_eq, t_CK_, memspec_.dataRate, VDDQ_);\n    result.dram.dynamicEnergy +=\n        calc_dynamic_energy(stats.read.zeroes_to_ones, impedances_.rdq_dyn_E);\n\n    // Write\n    result.controller.staticEnergy +=\n        calcStaticTermination(impedances_.wdq_R_eq, stats.write, impedances_.wdq_R_eq, t_CK_, memspec_.dataRate, VDDQ_);\n    result.controller.dynamicEnergy +=\n        calc_dynamic_energy(stats.write.zeroes_to_ones, impedances_.wdq_dyn_E);\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_DDR5::calcDQEnergy(const SimulationStats &stats) const {\n    interface_energy_info_t result;\n\n    // Read\n    result.dram.staticEnergy +=\n        calcStaticTermination(impedances_.rdq_termination, stats.readBus, impedances_.rdq_R_eq, t_CK_, memspec_.dataRate , VDDQ_);\n    result.dram.dynamicEnergy +=\n        calc_dynamic_energy(stats.readBus.zeroes_to_ones, impedances_.rdq_dyn_E);\n\n    // Write\n    result.controller.staticEnergy +=\n        calcStaticTermination(impedances_.wdq_termination, stats.writeBus, impedances_.wdq_R_eq, t_CK_, memspec_.dataRate , VDDQ_);\n    result.controller.dynamicEnergy +=\n        calc_dynamic_energy(stats.writeBus.zeroes_to_ones, impedances_.wdq_dyn_E);\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_DDR5::calcCAEnergy(const SimulationStats &stats) const {\n    interface_energy_info_t result;\n    result.controller.staticEnergy =\n        calcStaticTermination(impedances_.ca_termination, stats.commandBus, impedances_.ca_R_eq, t_CK_, 1, VDDQ_);\n\n    result.controller.dynamicEnergy =\n        calc_dynamic_energy(stats.commandBus.zeroes_to_ones, impedances_.ca_dyn_E);\n\n    return result;\n}\n\n}  // namespace DRAMPower\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr5/interface_calculation_DDR5.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_DDR5_INTERFACE_CALCULATION_DDR5_H\n#define DRAMPOWER_STANDARDS_DDR5_INTERFACE_CALCULATION_DDR5_H\n\n#include \"DRAMPower/Types.h\"\n#include \"DRAMPower/data/energy.h\"\n#include \"DRAMPower/memspec/MemSpecDDR5.h\"\n#include \"DRAMPower/data/stats.h\"\n\nnamespace DRAMPower {\n\nclass InterfaceCalculation_DDR5 {\n   public:\n    InterfaceCalculation_DDR5(const MemSpecDDR5 &memspec);\n\n    interface_energy_info_t calculateEnergy(const SimulationStats &stats) const;\n\n   private:\n    const MemSpecDDR5 &memspec_;\n    const MemSpecDDR5::MemImpedanceSpec &impedances_;\n    double t_CK_;\n    double VDDQ_;\n\n    interface_energy_info_t calcClockEnergy(const SimulationStats &stats) const;\n    interface_energy_info_t calcDQSEnergy(const SimulationStats &stats) const;\n    interface_energy_info_t calcDQEnergy(const SimulationStats &stats) const;\n    interface_energy_info_t calcCAEnergy(const SimulationStats &stats) const;\n    interface_energy_info_t calcDQEnergyTogglingRate(const TogglingStats &stats) const;\n};\n\n}  // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_DDR5_INTERFACE_CALCULATION_DDR5_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/ddr5/types.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_DDR5_TYPES_H\n#define DRAMPOWER_STANDARDS_DDR5_TYPES_H\n\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n\n#include \"DRAMPower/memspec/MemSpecDDR5.h\"\n#include \"DRAMPower/standards/ddr5/DDR5Core.h\"\n#include \"DRAMPower/standards/ddr5/DDR5Interface.h\"\n#include \"DRAMPower/standards/ddr5/core_calculation_DDR5.h\"\n#include \"DRAMPower/standards/ddr5/interface_calculation_DDR5.h\"\n\nnamespace DRAMPower {\n\nstruct DDR5Types {\n    using DRAMUtilsMemSpec_t = DRAMUtils::MemSpec::MemSpecDDR5;\n    using MemSpec_t = MemSpecDDR5;\n    using Core_t = DDR5Core;\n    using Interface_t = DDR5Interface;\n    using CalcCore_t = Calculation_DDR5;\n    using CalcInterface_t = InterfaceCalculation_DDR5;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_DDR5_TYPES_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr4/LPDDR4.cpp",
    "content": "#include \"LPDDR4.h\"\n#include \"DRAMPower/data/stats.h\"\n\n#include <DRAMPower/command/Pattern.h>\n#include <DRAMPower/standards/lpddr4/core_calculation_LPDDR4.h>\n#include <DRAMPower/standards/lpddr4/interface_calculation_LPDDR4.h>\n#include <DRAMPower/util/extensions.h>\n\n\nnamespace DRAMPower {\n\n    using namespace DRAMUtils::Config;\n\n    LPDDR4::LPDDR4(const MemSpecLPDDR4 &memSpec, const config::SimConfig &simConfig)\n        : m_memSpec(memSpec)\n        , m_interface(m_memSpec, simConfig)\n        , m_core(m_memSpec)\n    {\n        registerExtensions();\n    }\n\n// Extensions\n    void LPDDR4::registerExtensions() {\n        getExtensionManager().registerExtension<extensions::DBI>([this](const timestamp_t, const bool enable){\n            // Assumption: the enabling of the DBI does not interleave with previous data on the bus\n            // x8,x16 devices: support dbi\n            m_interface.enableDBI(enable);\n            return true;\n        }, false);\n    }\n\n// Getters for CLI\n    util::CLIArchitectureConfig LPDDR4::getCLIArchitectureConfig() {\n        return util::CLIArchitectureConfig{\n            m_memSpec.numberOfDevices,\n            m_memSpec.numberOfRanks,\n            m_memSpec.numberOfBanks\n        };\n    }\n\n// Calculation\n    energy_t LPDDR4::calcCoreEnergyStats(const SimulationStats& stats) const {\n        Calculation_LPDDR4 calculation(m_memSpec);\n        return calculation.calcEnergy(stats);\n    }\n\n    interface_energy_info_t LPDDR4::calcInterfaceEnergyStats(const SimulationStats& stats) const {\n        InterfaceCalculation_LPDDR4 interface_calc(m_memSpec);\n        return interface_calc.calculateEnergy(stats);\n    }\n\n// Stats\n    SimulationStats LPDDR4::getWindowStats(timestamp_t timestamp) {\n        SimulationStats stats;\n        m_core.getWindowStats(timestamp, stats);\n        m_interface.getWindowStats(timestamp, stats);\n        return stats;\n    }\n\n// Serialization\n    void LPDDR4::serialize_impl(std::ostream& stream) const {\n        m_core.serialize(stream);\n        m_interface.serialize(stream);\n    }\n\n    void LPDDR4::deserialize_impl(std::istream& stream) {\n        m_core.deserialize(stream);\n        m_interface.deserialize(stream);\n    }\n\n} // namespace DRAMPower\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr4/LPDDR4.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_LPDDR4_LPDDR4_H\n#define DRAMPOWER_STANDARDS_LPDDR4_LPDDR4_H\n\n#include \"DRAMPower/util/cli_architecture_config.h\"\n\n#include <DRAMPower/Types.h>\n#include <DRAMPower/dram/dram_base.h>\n#include <DRAMPower/command/Command.h>\n#include <DRAMPower/data/energy.h>\n#include <DRAMPower/data/stats.h>\n\n#include <DRAMPower/standards/lpddr4/LPDDR4Interface.h>\n#include <DRAMPower/standards/lpddr4/LPDDR4Core.h>\n#include <DRAMPower/memspec/MemSpecLPDDR4.h>\n\n#include \"DRAMPower/simconfig/simconfig.h\"\n\n#include <algorithm>\n\nnamespace DRAMPower {\n\nclass LPDDR4 : public dram_base<CmdType>{\n// public constructors and assignment operators\npublic:\n    LPDDR4() = delete; // No default constructor\n    LPDDR4(const LPDDR4&) = default; // copy constructor\n    LPDDR4& operator=(const LPDDR4&) = default; // copy assignment operator\n    LPDDR4(LPDDR4&&) = default; // move constructor\n    LPDDR4& operator=(LPDDR4&&) = default; // move assignment operator\n    ~LPDDR4() override = default;\n    \n    LPDDR4(const MemSpecLPDDR4& memSpec, const config::SimConfig &simConfig = {});\n\n// Public member functions\npublic:\n// Member functions\n    LPDDR4Core& getCore() {\n        return m_core;\n    }\n    const LPDDR4Core& getCore() const {\n        return m_core;\n    }\n    LPDDR4Interface& getInterface() {\n        return m_interface;\n    }\n    const LPDDR4Interface& getInterface() const {\n        return m_interface;\n    }\n// Overrides\n    energy_t calcCoreEnergyStats(const SimulationStats& stats) const override;\n    interface_energy_info_t calcInterfaceEnergyStats(const SimulationStats& stats) const override;\n    SimulationStats getWindowStats(timestamp_t timestamp) override;\n    util::CLIArchitectureConfig getCLIArchitectureConfig() override;\n    bool isSerializable() const override {\n        return m_core.isSerializable();\n    }\n\n\n// Private member functions\nprivate:\n// Member functions\n    void registerExtensions();\n// Overrides\n    void doCoreCommandImpl(const Command& command) override {\n        m_core.doCommand(command);\n    }\n    void doInterfaceCommandImpl(const Command& command) override {\n        m_interface.doCommand(command);\n    }\n    timestamp_t getLastCommandTime_impl() const override {\n        return std::max(m_core.getLastCommandTime(), m_interface.getLastCommandTime());\n    }\n    void serialize_impl(std::ostream& stream) const override;\n    void deserialize_impl(std::istream& stream) override;\n\n// Private member variables\nprivate:\n    MemSpecLPDDR4 m_memSpec;\n    LPDDR4Interface m_interface;\n    LPDDR4Core m_core;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_LPDDR4_LPDDR4_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr4/LPDDR4Core.cpp",
    "content": "#include \"LPDDR4Core.h\"\n#include \"DRAMPower/util/RegisterHelper.h\"\n\nnamespace DRAMPower {\n\nvoid LPDDR4Core::doCommand(const Command& cmd) {\n    m_implicitCommandHandler.processImplicitCommandQueue(*this, cmd.timestamp, m_last_command_time);\n    m_last_command_time = std::max(cmd.timestamp, m_last_command_time);\n    switch(cmd.type) {\n        case CmdType::ACT:\n            util::coreHelpers::bankHandler(cmd, m_ranks, this, &LPDDR4Core::handleAct);\n            break;\n        case CmdType::PRE:\n            util::coreHelpers::bankHandler(cmd, m_ranks, this, &LPDDR4Core::handlePre);\n            break;\n        case CmdType::PREA:\n            util::coreHelpers::rankHandler(cmd, m_ranks, this, &LPDDR4Core::handlePreAll);\n            break;\n        case CmdType::REFB:\n            util::coreHelpers::bankHandlerIdx(cmd, m_ranks, this, &LPDDR4Core::handleRefPerBank);\n            break;\n        case CmdType::RD:\n            util::coreHelpers::bankHandler(cmd, m_ranks, this, &LPDDR4Core::handleRead);\n            break;\n        case CmdType::RDA:\n            util::coreHelpers::bankHandlerIdx(cmd, m_ranks, this, &LPDDR4Core::handleReadAuto);\n            break;\n        case CmdType::WR:\n            util::coreHelpers::bankHandler(cmd, m_ranks, this, &LPDDR4Core::handleWrite);\n            break;\n        case CmdType::WRA:\n            util::coreHelpers::bankHandlerIdx(cmd, m_ranks, this, &LPDDR4Core::handleWriteAuto);\n            break;\n        case CmdType::REFA:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &LPDDR4Core::handleRefAll);\n            break;\n        case CmdType::PDEA:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &LPDDR4Core::handlePowerDownActEntry);\n            break;\n        case CmdType::PDXA:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &LPDDR4Core::handlePowerDownActExit);\n            break;\n        case CmdType::PDEP:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &LPDDR4Core::handlePowerDownPreEntry);\n            break;\n        case CmdType::PDXP:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &LPDDR4Core::handlePowerDownPreExit);\n            break;\n        case CmdType::SREFEN:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &LPDDR4Core::handleSelfRefreshEntry);\n            break;\n        case CmdType::SREFEX:\n            util::coreHelpers::rankHandler(cmd, m_ranks, this, &LPDDR4Core::handleSelfRefreshExit);\n            break;\n        case CmdType::END_OF_SIMULATION:\n            break;\n        default:\n            assert(false && \"Unsupported command\");\n            break;\n    }\n}\n\ntimestamp_t LPDDR4Core::getLastCommandTime() const {\n    return m_last_command_time;\n}\n\nbool LPDDR4Core::isSerializable() const {\n    return 0 == m_implicitCommandHandler.implicitCommandCount();\n}\n\nvoid LPDDR4Core::handleAct(Rank &rank, Bank &bank, timestamp_t timestamp) {\n    bank.counter.act++;\n\n    bank.cycles.act.start_interval(timestamp);\n\n    if (!rank.isActive(timestamp)) {\n        rank.cycles.act.start_interval(timestamp);\n    }\n\n    bank.bankState = Bank::BankState::BANK_ACTIVE;\n}\n\nvoid LPDDR4Core::handlePre(Rank &rank, Bank &bank, timestamp_t timestamp) {\n    if (bank.bankState == Bank::BankState::BANK_PRECHARGED)\n        return;\n\n    bank.counter.pre++;\n    bank.cycles.act.close_interval(timestamp);\n    bank.latestPre = timestamp;\n    bank.bankState = Bank::BankState::BANK_PRECHARGED;\n\n    if (!rank.isActive(timestamp)) {\n        rank.cycles.act.close_interval(timestamp);\n    }\n}\n\nvoid LPDDR4Core::handlePreAll(Rank &rank, timestamp_t timestamp) {\n    for (auto &bank: rank.banks) {\n        handlePre(rank, bank, timestamp);\n    }\n}\n\nvoid LPDDR4Core::handleRefreshOnBank(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp, uint64_t timing, uint64_t &counter) {\n    ++counter;\n    auto& rank = m_ranks[rank_idx];\n    auto& bank = rank.banks[bank_idx];\n\n    if (!rank.isActive(timestamp)) {\n        rank.cycles.act.start_interval(timestamp);\n    }\n\n    bank.bankState = Bank::BankState::BANK_ACTIVE;\n    auto timestamp_end = timestamp + timing;\n    bank.refreshEndTime = timestamp_end;\n    if (!bank.cycles.act.is_open())\n        bank.cycles.act.start_interval(timestamp);\n\n    // Execute implicit pre-charge at refresh end\n    m_implicitCommandHandler.addImplicitCommand(timestamp_end, [rank_idx, bank_idx, timestamp_end](LPDDR4Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        auto& bank = rank.banks[bank_idx];\n        bank.bankState = Bank::BankState::BANK_PRECHARGED;\n        bank.cycles.act.close_interval(timestamp_end);\n\n        if (!rank.isActive(timestamp_end)) {\n            rank.cycles.act.close_interval(timestamp_end);\n        }\n    });\n}\n\nvoid LPDDR4Core::handleRefAll(std::size_t rank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    for (std::size_t bank_idx = 0; bank_idx < rank.banks.size(); ++bank_idx) {\n        auto& counter = rank.banks[bank_idx].counter.refAllBank;\n        handleRefreshOnBank(rank_idx, bank_idx, timestamp, m_memSpec.tRFC, counter);\n    }\n    rank.endRefreshTime = timestamp + m_memSpec.tRFC;\n}\n\nvoid LPDDR4Core::handleRefPerBank(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp) {\n    auto& counter = m_ranks[rank_idx].banks[bank_idx].counter.refPerBank;\n    handleRefreshOnBank(rank_idx, bank_idx, timestamp, m_memSpec.tRFCPB, counter);\n}\n\nvoid LPDDR4Core::handleSelfRefreshEntry(std::size_t rank_idx, timestamp_t timestamp) {\n    // Issue implicit refresh\n    handleRefAll(rank_idx, timestamp);\n    // Handle self-refresh entry after tRFC\n    auto timestampSelfRefreshStart = timestamp + m_memSpec.tRFC;\n    m_implicitCommandHandler.addImplicitCommand(timestampSelfRefreshStart, [rank_idx, timestampSelfRefreshStart](LPDDR4Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.counter.selfRefresh++;\n        rank.cycles.sref.start_interval(timestampSelfRefreshStart);\n        rank.memState = MemState::SREF;\n    });\n}\n\nvoid LPDDR4Core::handleSelfRefreshExit(Rank &rank, timestamp_t timestamp) {\n    assert(rank.memState == MemState::SREF);\n    rank.cycles.sref.close_interval(timestamp);  // Duration start between entry and exit\n    rank.memState = MemState::NOT_IN_PD;\n}\n\nvoid LPDDR4Core::handlePowerDownActEntry(std::size_t rank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    auto earliestPossibleEntry = this->earliestPossiblePowerDownEntryTime(rank);\n    auto entryTime = std::max(timestamp, earliestPossibleEntry);\n    m_implicitCommandHandler.addImplicitCommand(entryTime, [rank_idx, entryTime](LPDDR4Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.cycles.powerDownAct.start_interval(entryTime);\n        rank.memState = MemState::PDN_ACT;\n        if (rank.cycles.act.is_open()) {\n            rank.cycles.act.close_interval(entryTime);\n        }\n        for (auto &bank: rank.banks) {\n            if (bank.cycles.act.is_open()) {\n                bank.cycles.act.close_interval(entryTime);\n            }\n        }\n    });\n}\n\nvoid LPDDR4Core::handlePowerDownActExit(std::size_t rank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    auto earliestPossibleExit = this->earliestPossiblePowerDownEntryTime(rank);\n    auto exitTime = std::max(timestamp, earliestPossibleExit);\n\n    m_implicitCommandHandler.addImplicitCommand(exitTime, [rank_idx, exitTime](LPDDR4Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.memState = MemState::NOT_IN_PD;\n        rank.cycles.powerDownAct.close_interval(exitTime);\n\n        bool rank_active = false;\n\n        for (auto & bank : rank.banks) {\n            if (bank.counter.act != 0 && bank.cycles.act.get_end() == rank.cycles.powerDownAct.get_start()) {\n                rank_active = true;\n                bank.cycles.act.start_interval(exitTime);\n            }\n        }\n\n        if (rank_active) {\n            rank.cycles.act.start_interval(exitTime);\n        }\n\n    });\n};\n\nvoid LPDDR4Core::handlePowerDownPreEntry(std::size_t rank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    auto earliestPossibleEntry = this->earliestPossiblePowerDownEntryTime(rank);\n    auto entryTime = std::max(timestamp, earliestPossibleEntry);\n    m_implicitCommandHandler.addImplicitCommand(entryTime, [rank_idx, entryTime](LPDDR4Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.cycles.powerDownPre.start_interval(entryTime);\n        rank.memState = MemState::PDN_PRE;\n    });\n}\n\nvoid LPDDR4Core::handlePowerDownPreExit(std::size_t rank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    auto earliestPossibleExit = this->earliestPossiblePowerDownEntryTime(rank);\n    auto exitTime = std::max(timestamp, earliestPossibleExit);\n\n    m_implicitCommandHandler.addImplicitCommand(exitTime, [rank_idx, exitTime](LPDDR4Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.memState = MemState::NOT_IN_PD;\n        rank.cycles.powerDownPre.close_interval(exitTime);\n    });\n}\n\nvoid LPDDR4Core::handleRead(Rank&, Bank &bank, timestamp_t) {\n    ++bank.counter.reads;\n}\n\nvoid LPDDR4Core::handleWrite(Rank&, Bank &bank, timestamp_t) {\n    ++bank.counter.writes;\n}\n\nvoid LPDDR4Core::handleReadAuto(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp) {\n    auto& bank = m_ranks[rank_idx].banks[bank_idx];\n    ++bank.counter.readAuto;\n\n    auto minBankActiveTime = bank.cycles.act.get_start() + m_memSpec.tRAS;\n    auto minReadActiveTime = timestamp + m_memSpec.prechargeOffsetRD;\n\n    auto delayed_timestamp = std::max(minBankActiveTime, minReadActiveTime);\n\n    // Execute PRE after minimum active time\n    m_implicitCommandHandler.addImplicitCommand(delayed_timestamp, [rank_idx, bank_idx, delayed_timestamp](LPDDR4Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        auto& bank = rank.banks[bank_idx];\n        self.handlePre(rank, bank, delayed_timestamp);\n    });\n}\n\nvoid LPDDR4Core::handleWriteAuto(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp) {\n    auto& bank = m_ranks[rank_idx].banks[bank_idx];\n    ++bank.counter.writeAuto;\n\n    auto minBankActiveTime = bank.cycles.act.get_start() + m_memSpec.tRAS;\n    auto minWriteActiveTime = timestamp + m_memSpec.prechargeOffsetWR;\n\n    auto delayed_timestamp = std::max(minBankActiveTime, minWriteActiveTime);\n\n    // Execute PRE after minimum active time\n    m_implicitCommandHandler.addImplicitCommand(delayed_timestamp, [rank_idx, bank_idx, delayed_timestamp](LPDDR4Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        auto& bank = rank.banks[bank_idx];\n        self.handlePre(rank, bank, delayed_timestamp);\n    });\n}\n\ntimestamp_t LPDDR4Core::earliestPossiblePowerDownEntryTime(Rank & rank) const {\n    timestamp_t entryTime = 0;\n\n    for (const auto & bank : rank.banks) {\n        entryTime = std::max({ entryTime,\n                                bank.counter.act == 0 ? 0 :  bank.cycles.act.get_start() + m_memSpec.tRCD,\n                                bank.counter.pre == 0 ? 0 : bank.latestPre + m_memSpec.tRP,\n                                bank.refreshEndTime\n                                });\n    }\n\n    return entryTime;\n};\n\nvoid LPDDR4Core::getWindowStats(timestamp_t timestamp, SimulationStats &stats) {\n    m_implicitCommandHandler.processImplicitCommandQueue(*this, timestamp, m_last_command_time);\n    stats.bank.resize(m_memSpec.numberOfBanks * m_memSpec.numberOfRanks);\n    stats.rank_total.resize(m_memSpec.numberOfRanks);\n\n    auto simulation_duration = timestamp;\n    for (size_t i = 0; i < m_memSpec.numberOfRanks; ++i) {\n        const Rank &rank = m_ranks[i];\n        size_t bank_offset = i * m_memSpec.numberOfBanks;\n\n        for (std::size_t j = 0; j < m_memSpec.numberOfBanks; ++j) {\n            stats.bank[bank_offset + j].counter = rank.banks[j].counter;\n            stats.bank[bank_offset + j].cycles.act =\n                rank.banks[j].cycles.act.get_count_at(timestamp);\n            stats.bank[bank_offset + j].cycles.selfRefresh =\n                rank.cycles.sref.get_count_at(timestamp) -\n                rank.cycles.deepSleepMode.get_count_at(timestamp);\n            stats.bank[bank_offset + j].cycles.deepSleepMode =\n                rank.cycles.deepSleepMode.get_count_at(timestamp);\n            stats.bank[bank_offset + j].cycles.powerDownAct =\n                rank.cycles.powerDownAct.get_count_at(timestamp);\n            stats.bank[bank_offset + j].cycles.powerDownPre =\n                rank.cycles.powerDownPre.get_count_at(timestamp);\n            stats.bank[bank_offset + j].cycles.pre =\n                simulation_duration - (stats.bank[bank_offset + j].cycles.act +\n                                        rank.cycles.powerDownAct.get_count_at(timestamp) +\n                                        rank.cycles.powerDownPre.get_count_at(timestamp) +\n                                        rank.cycles.sref.get_count_at(timestamp));\n        }\n\n        stats.rank_total[i].cycles.pre =\n            simulation_duration - (rank.cycles.act.get_count_at(timestamp) +\n                                    rank.cycles.powerDownAct.get_count_at(timestamp) +\n                                    rank.cycles.powerDownPre.get_count_at(timestamp) +\n                                    rank.cycles.sref.get_count_at(timestamp));\n\n        stats.rank_total[i].cycles.act = rank.cycles.act.get_count_at(timestamp);\n        stats.rank_total[i].cycles.powerDownAct =\n            rank.cycles.powerDownAct.get_count_at(timestamp);\n        stats.rank_total[i].cycles.powerDownPre =\n            rank.cycles.powerDownPre.get_count_at(timestamp);\n        stats.rank_total[i].cycles.selfRefresh = rank.cycles.sref.get_count_at(timestamp);\n    }\n}\n\nvoid LPDDR4Core::serialize(std::ostream& stream) const {\n    stream.write(reinterpret_cast<const char*>(&m_last_command_time), sizeof(m_last_command_time));\n    for (const auto& rank : m_ranks) {\n        rank.serialize(stream);\n    }\n}\n\nvoid LPDDR4Core::deserialize(std::istream& stream) {\n    stream.read(reinterpret_cast<char*>(&m_last_command_time), sizeof(m_last_command_time));\n    for (auto& rank : m_ranks) {\n        rank.deserialize(stream);\n    }\n}\n\n} // namespace DRAMPower"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr4/LPDDR4Core.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_LPDDR4_LPDDR4CORE_H\n#define DRAMPOWER_STANDARDS_LPDDR4_LPDDR4CORE_H\n\n#include \"DRAMPower/util/Deserialize.h\"\n#include \"DRAMPower/util/Serialize.h\"\n#include <DRAMPower/Types.h>\n#include \"DRAMPower/dram/Rank.h\"\n#include \"DRAMPower/command/Command.h\"\n#include <DRAMPower/data/stats.h>\n#include <DRAMPower/util/ImplicitCommandHandler.h>\n\n#include \"DRAMPower/memspec/MemSpecLPDDR4.h\"\n\n#include <vector>\n\nnamespace DRAMPower {\n\nnamespace internal {\n    template<typename Core>\n    class TestAccessor;\n}\n\nstruct LPDDR4CoreMemSpec {\n    LPDDR4CoreMemSpec(const MemSpecLPDDR4& memSpec)\n        : numberOfBanks(memSpec.numberOfBanks)\n        , numberOfRanks(memSpec.numberOfRanks)\n        , tRFC(memSpec.memTimingSpec.tRFC)\n        , tRFCPB(memSpec.memTimingSpec.tRFCPB)\n        , tRAS(memSpec.memTimingSpec.tRAS)\n        , tRCD(memSpec.memTimingSpec.tRCD)\n        , tRP(memSpec.memTimingSpec.tRP)\n        , prechargeOffsetRD(memSpec.prechargeOffsetRD)\n        , prechargeOffsetWR(memSpec.prechargeOffsetWR)\n    {}\n\n    uint64_t numberOfBanks;\n    uint64_t numberOfRanks;\n\n    uint64_t tRFC;\n    uint64_t tRFCPB;\n    uint64_t tRAS;\n    uint64_t tRCD;\n    uint64_t tRP;\n    uint64_t prechargeOffsetRD;\n    uint64_t prechargeOffsetWR;\n};\n\nclass LPDDR4Core : public util::Serialize, public util::Deserialize {\n// Friend classes\nfriend class internal::TestAccessor<LPDDR4Core>;\n\n// Public constructors amd assignment operators\npublic:\n    LPDDR4Core(const MemSpecLPDDR4& memSpec)\n        : m_memSpec(memSpec)\n        , m_ranks(memSpec.numberOfRanks, {static_cast<std::size_t>(memSpec.numberOfBanks)})\n    {}\n\n// Public member functions\npublic:\n// Member functions\n    void doCommand(const Command& cmd);\n    timestamp_t getLastCommandTime() const;\n    bool isSerializable() const;\n    void getWindowStats(timestamp_t timestamp, SimulationStats &stats);\n// Overrides\n    void serialize(std::ostream& stream) const override;\n    void deserialize(std::istream& stream) override;\n\n// Private member functions\nprivate:\n    void handleAct(Rank & rank, Bank & bank, timestamp_t timestamp);\n    void handlePre(Rank & rank, Bank & bank, timestamp_t timestamp);\n    void handlePreAll(Rank & rank, timestamp_t timestamp);\n    void handleRead(Rank & rank, Bank & bank, timestamp_t timestamp);\n    void handleWrite(Rank & rank, Bank & bank, timestamp_t timestamp);\n    void handleReadAuto(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp);\n    void handleWriteAuto(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp);\n    void handleRefAll(std::size_t rank_idx, timestamp_t timestamp);\n    void handleRefPerBank(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp);\n    void handleRefreshOnBank(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp, uint64_t timing, uint64_t & counter);\n    void handleSelfRefreshEntry(std::size_t rank_idx, timestamp_t timestamp);\n    void handleSelfRefreshExit(Rank & rank, timestamp_t timestamp);\n    void handlePowerDownActEntry(std::size_t rank_idx, timestamp_t timestamp);\n    void handlePowerDownActExit(std::size_t rank_idx, timestamp_t timestamp);\n    void handlePowerDownPreEntry(std::size_t rank_idx, timestamp_t timestamp);\n    void handlePowerDownPreExit(std::size_t rank_idx, timestamp_t timestamp);\n\n    timestamp_t earliestPossiblePowerDownEntryTime(Rank & rank) const;\n\n// Private member variables\nprivate:\n    LPDDR4CoreMemSpec m_memSpec;\n    std::vector<Rank> m_ranks;\n    ImplicitCommandHandler<LPDDR4Core> m_implicitCommandHandler;\n    timestamp_t m_last_command_time = 0;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_LPDDR4_LPDDR4CORE_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr4/LPDDR4Interface.cpp",
    "content": "#include \"LPDDR4Interface.h\"\n#include \"DRAMPower/command/CmdType.h\"\n#include \"DRAMPower/data/stats.h\"\n#include \"DRAMPower/util/pin.h\"\n\nnamespace DRAMPower {\n\nstatic constexpr DRAMUtils::Config::ToggleRateDefinition busConfig {\n    0,\n    0,\n    0,\n    0,\n    DRAMUtils::Config::TogglingRateIdlePattern::L,\n    DRAMUtils::Config::TogglingRateIdlePattern::L\n};\n\nLPDDR4Interface::LPDDR4Interface(const MemSpecLPDDR4& memSpec, const config::SimConfig& simConfig)\n    : m_memSpec(memSpec)\n    , m_commandBus{6, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L}\n    , m_dataBus{\n        util::databus_presets::getDataBusPreset(\n            util::DataBusConfig {\n                memSpec.bitWidth * memSpec.numberOfDevices,\n                memSpec.dataRate,\n                simConfig.toggleRateDefinition.value_or(busConfig)\n            },\n            simConfig.toggleRateDefinition.has_value()\n                ? util::DataBusMode::TogglingRate\n                : util::DataBusMode::Bus,\n            false\n        )\n    }\n    , m_readDQS(memSpec.dataRate, true)\n    , m_writeDQS(memSpec.dataRate, true)\n    , m_dbi(memSpec.numberOfDevices * memSpec.bitWidth, m_memSpec.burstLength,\n        [this](timestamp_t load_timestamp, timestamp_t, std::size_t pin, bool inversion_state, bool read) {\n        this->handleDBIPinChange(load_timestamp, pin, inversion_state, read);\n    }, false)\n    , m_dbiread(m_dbi.getChunksPerWidth().value(), pin_dbi_t{m_dbi.getIdlePattern(), m_dbi.getIdlePattern()})\n    , m_dbiwrite(m_dbi.getChunksPerWidth().value(), pin_dbi_t{m_dbi.getIdlePattern(), m_dbi.getIdlePattern()})\n    , m_patternHandler(PatternEncoderOverrides{\n        {pattern_descriptor::C0, PatternEncoderBitSpec::L},\n        {pattern_descriptor::C1, PatternEncoderBitSpec::L},\n    })\n{\n    registerPatterns();\n}\n\nvoid LPDDR4Interface::registerPatterns() {\n    using namespace pattern_descriptor;\n    // ACT\n    m_patternHandler.registerPattern<CmdType::ACT>({\n        H, L, R12, R13, R14, R15,\n        BA0, BA1, BA2, R16, R10, R11,\n        R17, R18, R6, R7, R8, R9,\n        R0, R1, R2, R3, R4, R5,\n    });\n    // PRE\n    m_patternHandler.registerPattern<CmdType::PRE>({\n        L, L, L, L, H, L,\n        BA0, BA1, BA2, V, V, V,\n    });\n    // PREA\n    m_patternHandler.registerPattern<CmdType::PREA>({\n        L, L, L, L, H, H,\n        V, V, V, V, V, V,\n    });\n    // REFB\n    m_patternHandler.registerPattern<CmdType::REFB>({\n        L, L, L, H, L, L,\n        BA0, BA1, BA2, V, V, V,\n    });\n    // RD\n    m_patternHandler.registerPattern<CmdType::RD>({\n        L, H, L, L, L, BL,\n        BA0, BA1, BA2, V, C9, L,\n        L, H, L, L, H, C8,\n        C2, C3, C4, C5, C6, C7\n    });\n    // RDA\n    m_patternHandler.registerPattern<CmdType::RDA>({\n        L, H, L, L, L, BL,\n        BA0, BA1, BA2, V, C9, H,\n        L, H, L, L, H, C8,\n        C2, C3, C4, C5, C6, C7\n    });\n    // WR\n    m_patternHandler.registerPattern<CmdType::WR>({\n        L, L, H, L, L, BL,\n        BA0, BA1, BA2, V, C9, L,\n        L, H, L, L, H, C8,\n        C2, C3, C4, C5, C6, C7,\n    });\n    // WRA\n    m_patternHandler.registerPattern<CmdType::WRA>({\n        L, L, H, L, L, BL,\n        BA0, BA1, BA2, V, C9, H,\n        L, H, L, L, H, C8,\n        C2, C3, C4, C5, C6, C7,\n    });\n    // REFA\n    m_patternHandler.registerPattern<CmdType::REFA>({\n        L, L, L, H, L, H,\n        V, V, V, V, V, V,\n    });\n    // SREFEN\n    m_patternHandler.registerPattern<CmdType::SREFEN>({\n        L, L, L, H, H, V,\n        V, V, V, V, V, V,\n    });\n    // SREFEX\n    m_patternHandler.registerPattern<CmdType::SREFEX>({\n        L, L, H, L, H, V,\n        V, V, V, V, V, V,\n    });\n}\n\n    timestamp_t LPDDR4Interface::getLastCommandTime() const {\n        return m_last_command_time;\n    }\n\n    void LPDDR4Interface::doCommand(const Command& cmd) {\n        switch(cmd.type) {\n            case CmdType::ACT:\n            case CmdType::PRE:\n            case CmdType::PREA:\n            case CmdType::REFB:\n            case CmdType::REFA:\n            case CmdType::SREFEN:\n            case CmdType::SREFEX:\n                handleCommandBus(cmd);\n                break;\n            case CmdType::RD:\n            case CmdType::RDA:\n                handleData(cmd, true);\n                break;\n            case CmdType::WR:\n            case CmdType::WRA:\n                handleData(cmd, false);\n                break;\n            case CmdType::END_OF_SIMULATION:\n                endOfSimulation(cmd.timestamp);\n                break;\n            case CmdType::PDEA:\n            case CmdType::PDXA:\n            case CmdType::PDEP:\n            case CmdType::PDXP:\n                break;\n            default:\n                assert(false && \"Invalid command\");\n                break;\n        }\n        m_last_command_time = cmd.timestamp;\n    }\n\nvoid LPDDR4Interface::handleDBIPinChange(const timestamp_t load_timestamp, std::size_t pin, bool state, bool read) {\n    assert(pin < m_dbiread.size() || pin < m_dbiwrite.size());\n    if (read) {\n        this->m_dbiread[pin].set(load_timestamp, state ? util::PinState::H : util::PinState::L, 1);\n    } else {\n        this->m_dbiwrite[pin].set(load_timestamp, state ? util::PinState::H : util::PinState::L, 1);\n    }\n}\n\nstd::optional<const uint8_t *> LPDDR4Interface::handleDBIInterface(timestamp_t timestamp, std::size_t n_bits, const uint8_t* data, bool read) {\n    if (0 == n_bits || !data || !m_dbi.isEnabled()) {\n        // No DBI or no data to process\n        return std::nullopt;\n    }\n    timestamp_t virtual_time = timestamp * m_memSpec.dataRate;\n    // updateDBI calls the given callback to handle pin changes\n    return m_dbi.updateDBI(virtual_time, n_bits, data, read);\n}\n\nvoid LPDDR4Interface::handleOverrides(size_t length, bool /*read*/)\n{\n    // Set command bus pattern overrides\n    switch(length) {\n        case 32:\n            m_patternHandler.getEncoder().settings.updateSettings({\n                {pattern_descriptor::C4, PatternEncoderBitSpec::L},\n                {pattern_descriptor::C3, PatternEncoderBitSpec::L},\n                {pattern_descriptor::C2, PatternEncoderBitSpec::L},\n                {pattern_descriptor::BL, PatternEncoderBitSpec::H},\n            });\n            break;\n        default:\n            // Pull down\n            // No interface power needed for PatternEncoderBitSpec::L\n            // Defaults to burst length 16\n        case 16:\n            m_patternHandler.getEncoder().settings.removeSetting(pattern_descriptor::C4);\n            m_patternHandler.getEncoder().settings.updateSettings({\n                {pattern_descriptor::C3, PatternEncoderBitSpec::L},\n                {pattern_descriptor::C2, PatternEncoderBitSpec::L},\n                {pattern_descriptor::BL, PatternEncoderBitSpec::L},\n            });\n            break;\n    }\n}\n\nvoid LPDDR4Interface::handleCommandBus(const Command &cmd) {\n    auto pattern = m_patternHandler.getCommandPattern(cmd);\n    auto ca_length = m_patternHandler.getPattern(cmd.type).size() / m_commandBus.get_width();\n    m_commandBus.load(cmd.timestamp, pattern, ca_length);\n}\n\nvoid LPDDR4Interface::handleDQs(const Command& cmd, util::Clock &dqs, size_t length) {\n    dqs.start(cmd.timestamp);\n    dqs.stop(cmd.timestamp + length / m_memSpec.dataRate);\n}\n\nvoid LPDDR4Interface::handleData(const Command &cmd, bool read) {\n    auto loadfunc = read ? &databus_t::loadRead : &databus_t::loadWrite;\n    util::Clock &dqs = read ? m_readDQS : m_writeDQS;\n    size_t length = 0;\n    if (0 == cmd.sz_bits) {\n        // No data provided by command\n        // Use default burst length\n        if (m_dataBus.isTogglingRate()) {\n            length = m_memSpec.burstLength;\n            (m_dataBus.*loadfunc)(cmd.timestamp, length * m_dataBus.getWidth(), nullptr);\n        }\n    } else {\n        std::optional<const uint8_t *> dbi_data = std::nullopt;\n        // Data provided by command\n        if (m_dataBus.isBus() && m_dbi.isEnabled()) {\n            // Only compute dbi for bus mode\n            dbi_data = handleDBIInterface(cmd.timestamp, cmd.sz_bits, cmd.data, read);\n        }\n        length = cmd.sz_bits / (m_dataBus.getWidth());\n        (m_dataBus.*loadfunc)(cmd.timestamp, cmd.sz_bits, dbi_data.value_or(cmd.data));\n    }\n    handleDQs(cmd, dqs, length);\n    handleOverrides(length, read);\n    handleCommandBus(cmd);\n}\n\nvoid LPDDR4Interface::endOfSimulation(timestamp_t timestamp) {\n    m_dbi.dispatchResetCallback(timestamp);\n}\n\nvoid LPDDR4Interface::getWindowStats(timestamp_t timestamp, SimulationStats &stats) const {\n    stats.commandBus = m_commandBus.get_stats(timestamp);\n    \n    m_dataBus.get_stats(timestamp,\n        stats.readBus,\n        stats.writeBus,\n        stats.togglingStats.read,\n        stats.togglingStats.write\n    );\n\n    stats.clockStats = 2 * m_clock.get_stats_at(timestamp);\n    stats.readDQSStats = 2 * m_readDQS.get_stats_at(timestamp);\n    stats.writeDQSStats = 2 * m_writeDQS.get_stats_at(timestamp);\n\n    for (const auto &dbi_pin : m_dbiread) {\n        stats.readDBI += dbi_pin.get_stats_at(timestamp, 2);\n    }\n    for (const auto &dbi_pin : m_dbiwrite) {\n        stats.writeDBI += dbi_pin.get_stats_at(timestamp, 2);\n    }\n\n    if (m_memSpec.bitWidth == 16) {\n        stats.readDQSStats *= 2;\n        stats.writeDQSStats *= 2;\n    }\n}\n\nvoid LPDDR4Interface::serialize(std::ostream& stream) const {\n    stream.write(reinterpret_cast<const char*>(&m_last_command_time), sizeof(m_last_command_time));\n    m_patternHandler.serialize(stream);\n    m_commandBus.serialize(stream);\n    m_dataBus.serialize(stream);\n    m_readDQS.serialize(stream);\n    m_writeDQS.serialize(stream);\n    m_clock.serialize(stream);\n}\nvoid LPDDR4Interface::deserialize(std::istream& stream) {\n    stream.read(reinterpret_cast<char*>(&m_last_command_time), sizeof(m_last_command_time));\n    m_patternHandler.deserialize(stream);\n    m_commandBus.deserialize(stream);\n    m_dataBus.deserialize(stream);\n    m_readDQS.deserialize(stream);\n    m_writeDQS.deserialize(stream);\n    m_clock.deserialize(stream);\n}\n\n\n} // namespace DRAMPower"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr4/LPDDR4Interface.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_LPDDR4_LPDDR4INTERFACE_H\n#define DRAMPOWER_STANDARDS_LPDDR4_LPDDR4INTERFACE_H\n\n#include \"DRAMPower/util/pin.h\"\n#include \"DRAMPower/util/bus.h\"\n#include \"DRAMPower/util/databus_presets.h\"\n#include \"DRAMPower/util/clock.h\"\n#include \"DRAMPower/util/Serialize.h\"\n#include \"DRAMPower/util/Deserialize.h\"\n\n#include \"DRAMPower/Types.h\"\n#include \"DRAMPower/command/Command.h\"\n#include \"DRAMPower/data/stats.h\"\n\n#include \"DRAMPower/util/PatternHandler.h\"\n#include \"DRAMPower/util/dbi.h\"\n\n#include \"DRAMPower/memspec/MemSpecLPDDR4.h\"\n\n#include \"DRAMPower/simconfig/simconfig.h\"\n\n#include <stdint.h>\n#include <cstddef>\n#include <vector>\n\nnamespace DRAMPower {\n\nstruct LPDDR4InterfaceMemSpec {\n    LPDDR4InterfaceMemSpec(const MemSpecLPDDR4& memSpec)\n        : dataRate(memSpec.dataRate)\n        , burstLength(memSpec.burstLength)\n        , bitWidth(memSpec.bitWidth)\n    {}\n\n    uint64_t dataRate;\n    uint64_t burstLength;\n    uint64_t bitWidth;\n};\n\nclass LPDDR4Interface : public util::Serialize, public util::Deserialize {\n// Public constants\npublic:\n    const static std::size_t cmdBusWidth = 6;\n    const static uint64_t cmdBusInitPattern = (1<<cmdBusWidth)-1;\n\n// Public type definitions\npublic:\n    using commandbus_t = util::Bus<cmdBusWidth>;\n    using pin_dbi_t = util::Pin<32>; // max_burst_length = 32\n    using databus_t = util::databus_presets::databus_preset_t;\n    using patternHandler_t = PatternHandler<CmdType>;\n\n// Public constructors and assignment operators\npublic:\n    LPDDR4Interface(const MemSpecLPDDR4& memSpec, const config::SimConfig &simConfig = {});\n\n// Public member functions\npublic:\n// Member functions\n    timestamp_t getLastCommandTime() const;\n    void doCommand(const Command& cmd);\n    void getWindowStats(timestamp_t timestamp, SimulationStats &stats) const;\n// Overrides\n    void serialize(std::ostream& stream) const override;\n    void deserialize(std::istream& stream) override;\n// Extensions\n    void enableDBI(bool enable) {\n        m_dbi.enable(enable);\n    }\n\n// Private Member functions\nprivate:\n    void registerPatterns();\n    std::optional<const uint8_t *> handleDBIInterface(timestamp_t timestamp, std::size_t n_bits, const uint8_t* data, bool read);\n    void handleDBIPinChange(const timestamp_t load_timestamp, std::size_t pin, bool state, bool read);\n    void handleOverrides(size_t length, bool read);\n    void handleDQs(const Command& cmd, util::Clock &dqs, size_t length);\n    void handleCommandBus(const Command& cmd);\n    void handleData(const Command &cmd, bool read);\n    void endOfSimulation(timestamp_t timestamp);\n\n// Public member variables\nprivate:\n    LPDDR4InterfaceMemSpec m_memSpec;\n    commandbus_t m_commandBus;\n    databus_t m_dataBus;\n    util::Clock m_readDQS;\n    util::Clock m_writeDQS;\n    util::Clock m_clock;\n    util::DBI<uint8_t, 1, util::PinState::L, util::StaticDBI> m_dbi;\n    std::vector<pin_dbi_t> m_dbiread;\n    std::vector<pin_dbi_t> m_dbiwrite;\n    patternHandler_t m_patternHandler;\n    timestamp_t m_last_command_time = 0;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_LPDDR4_LPDDR4INTERFACE_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr4/core_calculation_LPDDR4.cpp",
    "content": "#include \"core_calculation_LPDDR4.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n\nnamespace DRAMPower {\n\n    Calculation_LPDDR4::Calculation_LPDDR4(const MemSpecLPDDR4 &memSpec)\n        : m_memSpec(memSpec)\n    {}\n\n    double Calculation_LPDDR4::E_pre(double VDD, double IBeta, double IDD2N, double t_RP, uint64_t N_pre) const {\n        return VDD * (IBeta - IDD2N) * t_RP * N_pre;\n    }\n\n    double Calculation_LPDDR4::E_act(double VDD, double I_theta, double IDD3N, double t_RAS, uint64_t N_act) const {\n        return VDD * (I_theta - IDD3N) * t_RAS * N_act;\n    }\n\n    double Calculation_LPDDR4::E_BG_pre(std::size_t B, double VDD, double IDD2N, double T_BG_pre) const {\n        return (1.0 / B) * VDD * IDD2N * T_BG_pre;\n    }\n\n    double Calculation_LPDDR4::E_BG_act_star(std::size_t B, double VDD, double IDD3N, double I_p, double T_BG_act_star) const {\n        return VDD * (1.0 / B) * (IDD3N - I_p) * T_BG_act_star;\n    }\n\n    double Calculation_LPDDR4::E_BG_act_shared(double VDD, double I_p, double T_bg_act) const {\n        return VDD * I_p * T_bg_act;\n    }\n\n    double Calculation_LPDDR4::E_RD(double VDD, double IDD4_R, double IDD3N, std::size_t BL, std::size_t DR, double t_CK, uint64_t N_RD) const {\n        return VDD * (IDD4_R - IDD3N) * (BL / DR) * t_CK * N_RD;\n    }\n\n    double Calculation_LPDDR4::E_WR(double VDD, double IDD4_W, double IDD3N, std::size_t BL, std::size_t DR, double t_CK, uint64_t N_WR) const {\n        return VDD * (IDD4_W - IDD3N) * (BL / DR) * t_CK * N_WR;\n    }\n\n    double Calculation_LPDDR4::E_ref_ab(std::size_t B, double VDD, double IDD5, double approx_IDD3N, double tRFC, uint64_t N_REF) const {\n        return (1.0 / B) * VDD * (IDD5 - approx_IDD3N) * tRFC * N_REF;\n    }\n\n    double Calculation_LPDDR4::E_ref_pb(double VDD, double IDD5PB_B, double IDD3N, double tRFCPB, uint64_t N_PB_REF) const {\n        return VDD * (IDD5PB_B - IDD3N) * tRFCPB * N_PB_REF;\n    }\n\n    energy_t Calculation_LPDDR4::calcEnergy(const SimulationStats &stats) const {\n        auto t_CK = m_memSpec.memTimingSpec.tCK;\n        auto t_RAS = m_memSpec.memTimingSpec.tRAS * t_CK;\n        auto t_RP = m_memSpec.memTimingSpec.tRP * t_CK;\n        auto t_RFC = m_memSpec.memTimingSpec.tRFC * t_CK;\n        auto t_RFCPB = m_memSpec.memTimingSpec.tRFCPB * t_CK;\n        auto t_REFI = m_memSpec.memTimingSpec.tREFI * t_CK;\n\n        auto rho = m_memSpec.bwParams.bwPowerFactRho;\n        auto BL = m_memSpec.burstLength;\n        auto DR = m_memSpec.dataRate;\n        auto B = m_memSpec.numberOfBanks;\n\n        energy_t energy(m_memSpec.numberOfBanks * m_memSpec.numberOfRanks * m_memSpec.numberOfDevices);\n\n        for (auto vd : {MemSpecLPDDR4::VoltageDomain::VDD1, MemSpecLPDDR4::VoltageDomain::VDD2}) {\n            auto VDD = m_memSpec.memPowerSpec[vd].vDDX;\n            auto IDD_0 = m_memSpec.memPowerSpec[vd].iDD0X;\n            auto IDD2N = m_memSpec.memPowerSpec[vd].iDD2NX;\n            auto IDD3N = m_memSpec.memPowerSpec[vd].iDD3NX;\n            auto IDD2P = m_memSpec.memPowerSpec[vd].iDD2PX;\n            auto IDD3P = m_memSpec.memPowerSpec[vd].iDD3PX;\n            auto IDD4R = m_memSpec.memPowerSpec[vd].iDD4RX;\n            auto IDD4W = m_memSpec.memPowerSpec[vd].iDD4WX;\n            auto IDD5 = m_memSpec.memPowerSpec[vd].iDD5X;\n            auto IDD5PB = m_memSpec.memPowerSpec[vd].iDD5PBX;\n            auto IDD6 = m_memSpec.memPowerSpec[vd].iDD6X;\n            auto IBeta = m_memSpec.memPowerSpec[vd].iBeta;\n\n            auto I_rho = rho * (IDD3N - IDD2N) + IDD2N;\n            auto I_theta = (IDD_0 * (t_RP + t_RAS) - IBeta * t_RP) * (1 / t_RAS);\n            auto IDD5PB_B =\n                (IDD5PB * (t_REFI / 8) - IDD2N * ((t_REFI / 8) - t_RFCPB)) * (1.0 / t_RFCPB);\n            auto approx_IDD3N = I_rho + B * (IDD3N - I_rho);\n\n            size_t energy_offset = 0;\n            size_t bank_offset = 0;\n            for (size_t i = 0; i < m_memSpec.numberOfRanks; ++i) {\n                for (size_t d = 0; d < m_memSpec.numberOfDevices; ++d) {\n                    energy_offset = i * m_memSpec.numberOfDevices * m_memSpec.numberOfBanks\n                                    + d * m_memSpec.numberOfBanks;\n                    bank_offset = i * m_memSpec.numberOfBanks;\n                    for (std::size_t b = 0; b < m_memSpec.numberOfBanks; ++b) {\n                        const auto &bank = stats.bank[bank_offset + b];\n\n                        energy.bank_energy[energy_offset + b].E_act +=\n                            E_act(VDD, I_theta, IDD3N, t_RAS, bank.counter.act);\n                        energy.bank_energy[energy_offset + b].E_pre +=\n                            E_pre(VDD, IBeta, IDD2N, t_RP, bank.counter.pre);\n                        energy.bank_energy[energy_offset + b].E_bg_act +=\n                            E_BG_act_star(B, VDD, approx_IDD3N, I_rho,\n                                        stats.bank[bank_offset + b].cycles.activeTime() * t_CK);\n                        energy.bank_energy[energy_offset + b].E_bg_pre +=\n                            E_BG_pre(B, VDD, IDD2N, stats.rank_total[i].cycles.pre * t_CK);\n                        energy.bank_energy[energy_offset + b].E_RD +=\n                            E_RD(VDD, IDD4R, IDD3N, BL, DR, t_CK, bank.counter.reads);\n                        energy.bank_energy[energy_offset + b].E_WR +=\n                            E_WR(VDD, IDD4W, IDD3N, BL, DR, t_CK, bank.counter.writes);\n                        energy.bank_energy[energy_offset + b].E_RDA +=\n                            E_RD(VDD, IDD4R, IDD3N, BL, DR, t_CK, bank.counter.readAuto);\n                        energy.bank_energy[energy_offset + b].E_WRA +=\n                            E_WR(VDD, IDD4W, IDD3N, BL, DR, t_CK, bank.counter.writeAuto);\n                        energy.bank_energy[energy_offset + b].E_pre_RDA +=\n                            E_pre(VDD, IBeta, IDD2N, t_RP, bank.counter.readAuto);\n                        energy.bank_energy[energy_offset + b].E_pre_WRA +=\n                            E_pre(VDD, IBeta, IDD2N, t_RP, bank.counter.writeAuto);\n                        energy.bank_energy[energy_offset + b].E_ref_AB +=\n                            E_ref_ab(B, VDD, IDD5, approx_IDD3N, t_RFC, bank.counter.refAllBank);\n                        energy.bank_energy[energy_offset + b].E_ref_PB +=\n                            E_ref_pb(VDD, IDD5PB_B, IDD3N, t_RFCPB, bank.counter.refPerBank);\n                    }   \n                }\n\n                energy.E_sref += VDD * IDD6 * stats.rank_total[i].cycles.selfRefresh * t_CK * m_memSpec.numberOfDevices;\n                energy.E_PDNA += VDD * IDD3P * stats.rank_total[i].cycles.powerDownAct * t_CK * m_memSpec.numberOfDevices;\n                energy.E_PDNP += VDD * IDD2P * stats.rank_total[i].cycles.powerDownPre * t_CK * m_memSpec.numberOfDevices;\n\n                energy.E_bg_act_shared +=\n                    E_BG_act_shared(VDD, I_rho, stats.rank_total[i].cycles.act * t_CK) * m_memSpec.numberOfDevices;\n            }\n        }\n\n        return energy;\n    }\n}\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr4/core_calculation_LPDDR4.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_LPDDR4_CALCULATION_LPDDR4_H\n#define DRAMPOWER_STANDARDS_LPDDR4_CALCULATION_LPDDR4_H\n\n#include \"DRAMPower/data/stats.h\"\n#pragma once\n\n#include <DRAMPower/data/energy.h>\n#include <DRAMPower/memspec/MemSpecLPDDR4.h>\n\n#include <DRAMPower/Types.h>\n\n#include <cstddef>\n#include <cstdint>\n\nnamespace DRAMPower \n{\n\nclass LPDDR4;\n\nclass Calculation_LPDDR4\n{\npublic:\n    Calculation_LPDDR4(const MemSpecLPDDR4 &memSpec);\n\nprivate:\n    double E_act(double VDD, double I_theta, double IDD3N, double tRAS, uint64_t N_act) const;\n    double E_pre(double VDD, double IBeta, double IDD2N, double tRP, uint64_t N_pre) const;\n    double E_BG_pre(std::size_t B, double VDD, double IDD2N, double T_BG_pre) const;\n    double E_BG_act_star(std::size_t B, double VDD, double IDD3N, double I_rho, double T_BG_act_star) const;\n    double E_BG_act_shared(double VDD, double I_rho, double T_bg_act) const;\n\tdouble E_RD(double VDD, double IDD4R, double IDD3N, std::size_t BL, std::size_t DR, double t_CK, uint64_t N_RD) const;\n\tdouble E_WR(double VDD, double IDD4W, double IDD3N, std::size_t BL, std::size_t DR, double t_CK, uint64_t N_WR) const;\n    double E_ref_ab(std::size_t B, double VDD, double IDD5B, double approx_IDD3N, double tRFC, uint64_t N_REF) const;\n    double E_ref_pb(double VDD, double IDD5PB_B, double IDD3N, double tRFCPB, uint64_t N_PB_REF) const;\n\npublic:\n\tenergy_t calcEnergy(const SimulationStats &stats) const;\n\nprivate:\n    const MemSpecLPDDR4 &m_memSpec;\n};\n\n};\n\n#endif /* DRAMPOWER_STANDARDS_LPDDR4_CALCULATION_LPDDR4_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr4/interface_calculation_LPDDR4.cpp",
    "content": "#include \"interface_calculation_LPDDR4.h\"\n\nnamespace DRAMPower {\n\nInterfaceCalculation_LPDDR4::InterfaceCalculation_LPDDR4(const MemSpecLPDDR4 & memspec)\n: memspec_(memspec)\n, impedances_(memspec.memImpedanceSpec)\n, t_CK(memspec.memTimingSpec.tCK)\n, VDDQ(memspec.vddq)\n{}\n\nstatic double calc_static_energy(const uint64_t NxBits, const double R_eq, const double t_CK, const double voltage) {\n    return NxBits * ((voltage * voltage) / R_eq) * t_CK; // N * P * t = N * E\n}\n\nstatic double calc_dynamic_energy(const uint64_t NxBits, const double energy) {\n    return NxBits * energy;\n}\n\nstatic double calcStaticTermination(const bool termination, const DRAMPower::util::bus_stats_t &stats, const double R_eq, const double t_CK, const uint64_t datarate, const double voltage)\n{\n    if (termination == false) {\n        return 0; // No static termination\n    }\n    // ones \n    return calc_static_energy(stats.ones, R_eq, t_CK / datarate, voltage);\n}\n\ninterface_energy_info_t InterfaceCalculation_LPDDR4::calcClockEnergy(const SimulationStats &stats) const\n{\n    interface_energy_info_t result;\n\n    result.controller.staticEnergy =\n        calcStaticTermination(impedances_.ck_termination, stats.clockStats, impedances_.ck_R_eq, t_CK, 2, VDDQ); // datarate 2 -> half the time low other half high\n\n    result.controller.dynamicEnergy = \n        calc_dynamic_energy(stats.clockStats.zeroes_to_ones, impedances_.ck_dyn_E);\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_LPDDR4::calcDQSEnergy(const SimulationStats & stats) const\n{\n    // Datarate of data bus\n    interface_energy_info_t result;\n\n    // Write\n    result.controller.staticEnergy += calcStaticTermination(impedances_.wdqs_termination, stats.writeDQSStats, impedances_.wdqs_R_eq, t_CK, memspec_.dataRate, VDDQ);\n    result.controller.dynamicEnergy += calc_dynamic_energy(stats.writeDQSStats.zeroes_to_ones, impedances_.wdqs_dyn_E);\n\n    // Read\n    result.dram.staticEnergy += calcStaticTermination(impedances_.rdqs_termination, stats.readDQSStats, impedances_.rdqs_R_eq, t_CK, memspec_.dataRate, VDDQ);\n    result.dram.dynamicEnergy += calc_dynamic_energy(stats.readDQSStats.zeroes_to_ones, impedances_.rdqs_dyn_E);\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_LPDDR4::calcCAEnergy(const SimulationStats& bus_stats) const\n{\n    interface_energy_info_t result;\n    result.controller.staticEnergy = \n        calcStaticTermination(impedances_.ca_termination, bus_stats.commandBus, impedances_.ca_R_eq, t_CK, 1, VDDQ);\n    result.controller.dynamicEnergy =\n        calc_dynamic_energy(bus_stats.commandBus.zeroes_to_ones, impedances_.ca_dyn_E);;\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_LPDDR4::calcDQEnergy(const SimulationStats& bus_stats) const\n{\n    interface_energy_info_t result;\n\n    // Write\n    result.controller.staticEnergy +=\n        calcStaticTermination(impedances_.wdq_termination, bus_stats.writeBus, impedances_.wdq_R_eq, t_CK, memspec_.dataRate, VDDQ);\n    result.controller.dynamicEnergy +=\n        calc_dynamic_energy(bus_stats.writeBus.zeroes_to_ones, impedances_.wdq_dyn_E);\n\n    // Read\n    result.dram.staticEnergy +=\n        calcStaticTermination(impedances_.rdq_termination, bus_stats.readBus, impedances_.rdq_R_eq, t_CK, memspec_.dataRate, VDDQ);\n    result.dram.dynamicEnergy +=\n        calc_dynamic_energy(bus_stats.readBus.zeroes_to_ones, impedances_.rdq_dyn_E);\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_LPDDR4::calcDQEnergyTogglingRate(const TogglingStats &stats) const\n{\n    interface_energy_info_t result;\n\n    // Write\n    result.controller.staticEnergy +=\n        calcStaticTermination(impedances_.wdq_termination, stats.write, impedances_.wdq_R_eq, t_CK, memspec_.dataRate, VDDQ);\n    result.controller.dynamicEnergy +=\n        calc_dynamic_energy(stats.write.zeroes_to_ones, impedances_.wdq_dyn_E);\n\n    // Read\n    result.dram.staticEnergy +=\n        calcStaticTermination(impedances_.rdq_termination, stats.read, impedances_.rdq_R_eq, t_CK, memspec_.dataRate, VDDQ);\n    result.dram.dynamicEnergy +=\n        calc_dynamic_energy(stats.read.zeroes_to_ones, impedances_.rdq_dyn_E);\n    \n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_LPDDR4::calculateEnergy(const SimulationStats& stats) const\n{\n    interface_energy_info_t result;\n    \n    result += calcClockEnergy(stats);\n    result += calcDQSEnergy(stats);\n    result += calcDQEnergyTogglingRate(stats.togglingStats);\n    result += calcDQEnergy(stats);\n    result += calcCAEnergy(stats);\n    result += calcDBIEnergy(stats);\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_LPDDR4::calcDBIEnergy(const SimulationStats &stats) const {\n    interface_energy_info_t result;\n    // Read\n    result.dram.staticEnergy +=\n        calcStaticTermination(impedances_.rdbi_termination, stats.readDBI, impedances_.rdbi_R_eq, t_CK, memspec_.dataRate, VDDQ);\n    result.dram.dynamicEnergy +=\n        calc_dynamic_energy(stats.readDBI.zeroes_to_ones, impedances_.rdbi_dyn_E);\n\n    // Write\n    result.controller.staticEnergy +=\n        calcStaticTermination(impedances_.wdbi_termination, stats.writeDBI, impedances_.wdbi_R_eq, t_CK, memspec_.dataRate, VDDQ);\n    result.controller.dynamicEnergy +=\n        calc_dynamic_energy(stats.writeDBI.zeroes_to_ones, impedances_.wdbi_dyn_E);\n\n    return result;\n}\n\n} // namespace DRAMPower"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr4/interface_calculation_LPDDR4.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_LPDDR4_INTERFACE_CALCULATION_LPDDR4_H\n#define DRAMPOWER_STANDARDS_LPDDR4_INTERFACE_CALCULATION_LPDDR4_H\n\n#pragma once\n\n#include <DRAMPower/data/energy.h>\n#include <DRAMPower/data/stats.h>\n\n#include <DRAMPower/memspec/MemSpecLPDDR4.h>\n\n#include <DRAMPower/Types.h>\n\nnamespace DRAMPower\n{\n\nclass DRAM;\n\nclass InterfaceCalculation_LPDDR4\n{\nprivate:\n\tconst MemSpecLPDDR4 &memspec_;\n\tconst MemSpecLPDDR4::MemImpedanceSpec &impedances_;\n\tdouble t_CK;\n\tdouble VDDQ;\n\npublic:\n\tInterfaceCalculation_LPDDR4(const MemSpecLPDDR4 & memspec);\n\n\tinterface_energy_info_t calculateEnergy(const SimulationStats& stats) const;\n\nprivate:\n\tinterface_energy_info_t calcClockEnergy(const SimulationStats &stats) const;\n\tinterface_energy_info_t calcDQSEnergy(const SimulationStats & stats) const;\n\tinterface_energy_info_t calcCAEnergy(const SimulationStats& bus_stats) const;\n\tinterface_energy_info_t calcDQEnergy(const SimulationStats& bus_stats) const;\n\tinterface_energy_info_t calcDQEnergyTogglingRate(const TogglingStats &stats) const;\n    interface_energy_info_t calcDBIEnergy(const SimulationStats &stats) const;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_LPDDR4_INTERFACE_CALCULATION_LPDDR4_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr4/types.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_LPDDR4_TYPES_H\n#define DRAMPOWER_STANDARDS_LPDDR4_TYPES_H\n\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n\n#include \"DRAMPower/memspec/MemSpecLPDDR4.h\"\n#include \"DRAMPower/standards/lpddr4/LPDDR4Core.h\"\n#include \"DRAMPower/standards/lpddr4/LPDDR4Interface.h\"\n#include \"DRAMPower/standards/lpddr4/core_calculation_LPDDR4.h\"\n#include \"DRAMPower/standards/lpddr4/interface_calculation_LPDDR4.h\"\n\nnamespace DRAMPower {\n\nstruct LPDDR4Types {\n    using DRAMUtilsMemSpec_t = DRAMUtils::MemSpec::MemSpecLPDDR4;\n    using MemSpec_t = MemSpecLPDDR4;\n    using Core_t = LPDDR4Core;\n    using Interface_t = LPDDR4Interface;\n    using CalcCore_t = Calculation_LPDDR4;\n    using CalcInterface_t = InterfaceCalculation_LPDDR4;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_LPDDR4_TYPES_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr5/LPDDR5.cpp",
    "content": "#include \"LPDDR5.h\"\n#include \"DRAMPower/Types.h\"\n#include \"DRAMPower/data/stats.h\"\n\n#include <DRAMPower/command/Pattern.h>\n#include <DRAMPower/standards/lpddr5/core_calculation_LPDDR5.h>\n#include <DRAMPower/standards/lpddr5/interface_calculation_LPDDR5.h>\n#include <DRAMPower/util/extensions.h>\n#include <DRAMPower/Exceptions.h>\n\n#include <iostream>\n\n\nnamespace DRAMPower {\n\n    LPDDR5::LPDDR5(const MemSpecLPDDR5 &memSpec, const config::SimConfig& simConfig)\n        : m_memSpec(memSpec)\n        , m_interface(m_memSpec, simConfig)\n        , m_core(m_memSpec)\n    {\n        registerExtensions();\n    }\n\n// Extensions\n    void LPDDR5::registerExtensions() {\n        getExtensionManager().registerExtension<extensions::DBI>([this](const timestamp_t, const bool enable){\n            // Assumption: the enabling of the DBI does not interleave with previous data on the bus\n            m_interface.enableDBI(enable);\n            return true;\n        }, false);\n    }\n\n// Getters for CLI\n    util::CLIArchitectureConfig LPDDR5::getCLIArchitectureConfig() {\n        return util::CLIArchitectureConfig{\n            m_memSpec.numberOfDevices,\n            m_memSpec.numberOfRanks,\n            m_memSpec.numberOfBanks\n        };\n    }\n\n// Calculation\n    energy_t LPDDR5::calcCoreEnergyStats(const SimulationStats& stats) const {\n        Calculation_LPDDR5 calculation(m_memSpec);\n        return calculation.calcEnergy(stats);\n    }\n\n    interface_energy_info_t LPDDR5::calcInterfaceEnergyStats(const SimulationStats& stats) const {\n        InterfaceCalculation_LPDDR5 calculation(m_memSpec);\n        return calculation.calculateEnergy(stats);\n    }\n\n// Stats\n    SimulationStats LPDDR5::getWindowStats(timestamp_t timestamp) {\n        SimulationStats stats;\n        m_core.getWindowStats(timestamp, stats);\n        m_interface.getWindowStats(timestamp, stats);\n        return stats;\n    }\n\n// Serialization\n    void LPDDR5::serialize_impl(std::ostream& stream) const {\n        m_core.serialize(stream);\n        m_interface.serialize(stream);\n    }\n\n    void LPDDR5::deserialize_impl(std::istream& stream) {\n        m_core.deserialize(stream);\n        m_interface.deserialize(stream);\n    }\n\n\n} // namespace DRAMPower\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr5/LPDDR5.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_LPDDR5_LPDDR5_H\n#define DRAMPOWER_STANDARDS_LPDDR5_LPDDR5_H\n\n#include \"DRAMPower/util/cli_architecture_config.h\"\n\n#include <DRAMPower/Types.h>\n#include <DRAMPower/dram/dram_base.h>\n#include <DRAMPower/command/Command.h>\n#include <DRAMPower/data/energy.h>\n#include <DRAMPower/data/stats.h>\n\n#include <DRAMPower/standards/lpddr5/LPDDR5Interface.h>\n#include <DRAMPower/standards/lpddr5/LPDDR5Core.h>\n#include <DRAMPower/memspec/MemSpecLPDDR5.h>\n\n#include \"DRAMPower/simconfig/simconfig.h\"\n\n#include <algorithm>\n\nnamespace DRAMPower {\n\nclass LPDDR5 : public dram_base<CmdType> {\n// Public constructors and assignment operators\npublic:\n    LPDDR5() = delete; // No default constructor\n    LPDDR5(const LPDDR5&) = default; // copy constructor\n    LPDDR5& operator=(const LPDDR5&) = default; // copy assignment operator\n    LPDDR5(LPDDR5&&) = default; // move constructor\n    LPDDR5& operator=(LPDDR5&&) = default; // move assignment operator\n    ~LPDDR5() override = default;\n    LPDDR5(const MemSpecLPDDR5& memSpec, const config::SimConfig& toggleRate = {});\n\n// Public member functions\npublic:\n// Member functions\n    LPDDR5Core& getCore() {\n        return m_core;\n    }\n    const LPDDR5Core& getCore() const {\n        return m_core;\n    }\n    LPDDR5Interface& getInterface() {\n        return m_interface;\n    }\n    const LPDDR5Interface& getInterface() const {\n        return m_interface;\n    }\n// Overrides\n    energy_t calcCoreEnergyStats(const SimulationStats& stats) const override;\n    interface_energy_info_t calcInterfaceEnergyStats(const SimulationStats& stats) const override;\n    SimulationStats getWindowStats(timestamp_t timestamp) override;\n    util::CLIArchitectureConfig getCLIArchitectureConfig() override;\n    bool isSerializable() const override {\n        return m_core.isSerializable();\n    }\n\n// Private member functions\nprivate:\n// Member functions\n    void registerExtensions();\n// Overrides\n    void doCoreCommandImpl(const Command& command) override {\n        m_core.doCommand(command);\n    }\n    void doInterfaceCommandImpl(const Command& command) override {\n        m_interface.doCommand(command);\n    }\n    timestamp_t getLastCommandTime_impl() const override {\n        return std::max(m_core.getLastCommandTime(), m_interface.getLastCommandTime());\n    }\n    void serialize_impl(std::ostream& stream) const override;\n    void deserialize_impl(std::istream& stream) override;\n\n// Private member variables\nprivate:\n    MemSpecLPDDR5 m_memSpec;\n    LPDDR5Interface m_interface;\n    LPDDR5Core m_core;\n};\n\n}  // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_LPDDR5_LPDDR5_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr5/LPDDR5Core.cpp",
    "content": "#include \"LPDDR5Core.h\"\n#include \"DRAMPower/Exceptions.h\"\n#include \"DRAMPower/util/RegisterHelper.h\"\n\nnamespace DRAMPower {\n\nvoid LPDDR5Core::doCommand(const Command& cmd) {\n    m_implicitCommandHandler.processImplicitCommandQueue(*this, cmd.timestamp, m_last_command_time);\n    m_last_command_time = std::max(cmd.timestamp, m_last_command_time);\n    switch(cmd.type) {\n        case CmdType::ACT:\n            util::coreHelpers::bankHandler(cmd, m_ranks, this, &LPDDR5Core::handleAct);\n            break;\n        case CmdType::PRE:\n            util::coreHelpers::bankHandler(cmd, m_ranks, this, &LPDDR5Core::handlePre);\n            break;\n        case CmdType::PREA:\n            util::coreHelpers::rankHandler(cmd, m_ranks, this, &LPDDR5Core::handlePreAll);\n            break;\n        case CmdType::REFB:\n            util::coreHelpers::bankHandlerIdx(cmd, m_ranks, this, &LPDDR5Core::handleRefPerBank);\n            break;\n        case CmdType::RD:\n            util::coreHelpers::bankHandler(cmd, m_ranks, this, &LPDDR5Core::handleRead);\n            break;\n        case CmdType::RDA:\n            util::coreHelpers::bankHandlerIdx(cmd, m_ranks, this, &LPDDR5Core::handleReadAuto);\n            break;\n        case CmdType::WR:\n            util::coreHelpers::bankHandler(cmd, m_ranks, this, &LPDDR5Core::handleWrite);\n            break;\n        case CmdType::WRA:\n            util::coreHelpers::bankHandlerIdx(cmd, m_ranks, this, &LPDDR5Core::handleWriteAuto);\n            break;\n        case CmdType::REFP2B:\n            if (m_memSpec.bank_arch != MemSpecLPDDR5::MBG && m_memSpec.bank_arch != MemSpecLPDDR5::M16B) {\n                throw Exception(std::string(\"REFP2B command is not supported for this bank architecture: \") + CmdTypeUtil::to_string(CmdType::REFP2B));\n            }\n            util::coreHelpers::bankGroupHandlerIdx(cmd, m_ranks, this, &LPDDR5Core::handleRefPerTwoBanks);\n            break;\n        case CmdType::REFA:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &LPDDR5Core::handleRefAll);\n            break;\n        case CmdType::SREFEN:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &LPDDR5Core::handleSelfRefreshEntry);\n            break;\n        case CmdType::SREFEX:\n            util::coreHelpers::rankHandler(cmd, m_ranks, this, &LPDDR5Core::handleSelfRefreshExit);\n            break;\n        case CmdType::PDEA:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &LPDDR5Core::handlePowerDownActEntry);\n            break;\n        case CmdType::PDEP:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &LPDDR5Core::handlePowerDownPreEntry);\n            break;\n        case CmdType::PDXA:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &LPDDR5Core::handlePowerDownActExit);\n            break;\n        case CmdType::PDXP:\n            util::coreHelpers::rankHandlerIdx(cmd, m_ranks, this, &LPDDR5Core::handlePowerDownPreExit);\n            break;\n        case CmdType::DSMEN:\n            util::coreHelpers::rankHandler(cmd, m_ranks, this, &LPDDR5Core::handleDSMEntry);\n            break;\n        case CmdType::DSMEX:\n            util::coreHelpers::rankHandler(cmd, m_ranks, this, &LPDDR5Core::handleDSMExit);\n            break;\n        case CmdType::END_OF_SIMULATION:\n            break;\n        default:\n            assert(false && \"Unsupported command\");\n            break;\n    }\n}\n\ntimestamp_t LPDDR5Core::getLastCommandTime() const {\n    return m_last_command_time;\n}\n\nbool LPDDR5Core::isSerializable() const {\n    return 0 == m_implicitCommandHandler.implicitCommandCount();\n}\n\nvoid LPDDR5Core::handleAct(Rank &rank, Bank &bank, timestamp_t timestamp) {\n    bank.counter.act++;\n\n    bank.cycles.act.start_interval(timestamp);\n\n    if ( !rank.isActive(timestamp) ) {\n        rank.cycles.act.start_interval(timestamp);\n    }\n\n    bank.bankState = Bank::BankState::BANK_ACTIVE;\n}\n\nvoid LPDDR5Core::handlePre(Rank &rank, Bank &bank, timestamp_t timestamp) {\n    if (bank.bankState == Bank::BankState::BANK_PRECHARGED)\n        return;\n\n    bank.counter.pre++;\n    bank.cycles.act.close_interval(timestamp);\n    bank.latestPre = timestamp;\n    bank.bankState = Bank::BankState::BANK_PRECHARGED;\n\n    if (!rank.isActive(timestamp)) {\n        rank.cycles.act.close_interval(timestamp);\n    }\n}\n\nvoid LPDDR5Core::handlePreAll(Rank &rank, timestamp_t timestamp) {\n    for (auto &bank: rank.banks) {\n        handlePre(rank, bank, timestamp);\n    }\n}\n\nvoid LPDDR5Core::handleRefPerBank(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp) {\n    auto& counter = m_ranks[rank_idx].banks[bank_idx].counter.refPerBank;\n    handleRefreshOnBank(rank_idx, bank_idx, timestamp, m_memSpec.tRFCPB, counter);\n}\n\nvoid LPDDR5Core::handleRefPerTwoBanks(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    std::size_t bank_2_idx = (bank_idx + m_memSpec.perTwoBankOffset) % 16;\n    auto& counter1 = rank.banks[bank_idx].counter.refPerTwoBanks;\n    auto& counter2 = rank.banks[bank_2_idx].counter.refPerTwoBanks;\n    handleRefreshOnBank(rank_idx, bank_idx, timestamp, m_memSpec.tRFCPB, counter1);\n    handleRefreshOnBank(rank_idx, bank_2_idx, timestamp, m_memSpec.tRFCPB, counter2);\n}\n\nvoid LPDDR5Core::handleRefAll(std::size_t rank_idx, timestamp_t timestamp) {\n    auto &rank = m_ranks[rank_idx];\n    for (std::size_t bank_idx = 0; bank_idx < rank.banks.size(); ++bank_idx) {\n        auto& counter = rank.banks[bank_idx].counter.refAllBank;\n        handleRefreshOnBank(rank_idx, bank_idx, timestamp, m_memSpec.tRFC, counter);\n    }\n    rank.endRefreshTime = timestamp + m_memSpec.tRFC;\n}\n\nvoid LPDDR5Core::handleRefreshOnBank(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp, uint64_t timing, uint64_t & counter){\n    ++counter;\n    auto& rank = m_ranks[rank_idx];\n    auto& bank = rank.banks[bank_idx];\n    if (!rank.isActive(timestamp)) {\n        rank.cycles.act.start_interval(timestamp);\n    }\n    bank.bankState = Bank::BankState::BANK_ACTIVE;\n    auto timestamp_end = timestamp + timing;\n    bank.refreshEndTime = timestamp_end;\n    if (!bank.cycles.act.is_open())\n        bank.cycles.act.start_interval(timestamp);\n\n    // Execute implicit pre-charge at refresh end\n    m_implicitCommandHandler.addImplicitCommand(timestamp_end, [rank_idx, bank_idx, timestamp_end](LPDDR5Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        auto& bank = rank.banks[bank_idx];\n        bank.bankState = Bank::BankState::BANK_PRECHARGED;\n        bank.cycles.act.close_interval(timestamp_end);\n\n        if (!rank.isActive(timestamp_end)) {\n            rank.cycles.act.close_interval(timestamp_end);\n        }\n    });\n}\n\nvoid LPDDR5Core::handleRead(Rank&, Bank &bank, timestamp_t) {\n    ++bank.counter.reads;\n}\n\nvoid LPDDR5Core::handleReadAuto(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp) {\n    auto& bank = m_ranks[rank_idx].banks[bank_idx];\n    ++bank.counter.readAuto;\n\n    auto minBankActiveTime = bank.cycles.act.get_start() + this->m_memSpec.tRAS;\n    auto minReadActiveTime = timestamp + this->m_memSpec.prechargeOffsetRD;\n\n    auto delayed_timestamp = std::max(minBankActiveTime, minReadActiveTime);\n\n    // Execute PRE after minimum active time\n    m_implicitCommandHandler.addImplicitCommand(delayed_timestamp, [rank_idx, bank_idx, delayed_timestamp](LPDDR5Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        auto& bank = rank.banks[bank_idx];\n        self.handlePre(rank, bank, delayed_timestamp);\n    });\n}\n\nvoid LPDDR5Core::handleWrite(Rank&, Bank &bank, timestamp_t) {\n    ++bank.counter.writes;\n}\n\nvoid LPDDR5Core::handleWriteAuto(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp) {\n    auto& bank = m_ranks[rank_idx].banks[bank_idx];\n    ++bank.counter.writeAuto;\n\n    auto minBankActiveTime = bank.cycles.act.get_start() + this->m_memSpec.tRAS;\n    auto minWriteActiveTime = timestamp + this->m_memSpec.prechargeOffsetWR;\n\n    auto delayed_timestamp = std::max(minBankActiveTime, minWriteActiveTime);\n    // Execute PRE after minimum active time\n    m_implicitCommandHandler.addImplicitCommand(delayed_timestamp, [rank_idx, bank_idx, delayed_timestamp](LPDDR5Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        auto& bank = rank.banks[bank_idx];\n        self.handlePre(rank, bank, delayed_timestamp);\n    });\n}\n\nvoid LPDDR5Core::handleSelfRefreshEntry(std::size_t rank_idx, timestamp_t timestamp) {\n    // Issue implicit refresh\n    handleRefAll(rank_idx, timestamp);\n    // Handle self-refresh entry after tRFC\n    auto timestampSelfRefreshStart = timestamp + m_memSpec.tRFC;\n    m_implicitCommandHandler.addImplicitCommand(timestampSelfRefreshStart, [rank_idx, timestampSelfRefreshStart](LPDDR5Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.counter.selfRefresh++;\n        rank.cycles.sref.start_interval(timestampSelfRefreshStart);\n        rank.memState = MemState::SREF;\n    });\n}\n\nvoid LPDDR5Core::handleSelfRefreshExit(Rank &rank, timestamp_t timestamp) {\n    assert(rank.memState == MemState::SREF);\n    rank.cycles.sref.close_interval(timestamp);\n    rank.memState = MemState::NOT_IN_PD;\n}\n\nvoid LPDDR5Core::handlePowerDownActEntry(std::size_t rank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    auto earliestPossibleEntry = this->earliestPossiblePowerDownEntryTime(rank);\n    auto entryTime = std::max(timestamp, earliestPossibleEntry);\n    m_implicitCommandHandler.addImplicitCommand(entryTime, [rank_idx, entryTime](LPDDR5Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.cycles.powerDownAct.start_interval(entryTime);\n        rank.memState = MemState::PDN_ACT;\n        if (rank.cycles.act.is_open()) {\n            rank.cycles.act.close_interval(entryTime);\n        }\n        for (auto & bank : rank.banks) {\n            if (bank.cycles.act.is_open()) {\n                bank.cycles.act.close_interval(entryTime);\n            }\n        }\n    });\n}\n\nvoid LPDDR5Core::handlePowerDownActExit(std::size_t rank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    auto earliestPossibleExit = this->earliestPossiblePowerDownEntryTime(rank);\n    auto exitTime = std::max(timestamp, earliestPossibleExit);\n\n    m_implicitCommandHandler.addImplicitCommand(exitTime, [rank_idx, exitTime](LPDDR5Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.memState = MemState::NOT_IN_PD;\n        rank.cycles.powerDownAct.close_interval(exitTime);\n\n        bool rank_active = false;\n\n        for (auto & bank : rank.banks) {\n            if (bank.counter.act != 0 && bank.cycles.act.get_end() == rank.cycles.powerDownAct.get_start()) {\n                rank_active = true;\n                bank.cycles.act.start_interval(exitTime);\n            }\n        }\n\n        if (rank_active) {\n            rank.cycles.act.start_interval(exitTime);\n        }\n\n    });\n}\n\nvoid LPDDR5Core::handlePowerDownPreEntry(std::size_t rank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    auto earliestPossibleEntry = this->earliestPossiblePowerDownEntryTime(rank);\n    auto entryTime = std::max(timestamp, earliestPossibleEntry);\n    m_implicitCommandHandler.addImplicitCommand(entryTime, [rank_idx, entryTime](LPDDR5Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.cycles.powerDownPre.start_interval(entryTime);\n        rank.memState = MemState::PDN_PRE;\n    });\n}\n\nvoid LPDDR5Core::handlePowerDownPreExit(std::size_t rank_idx, timestamp_t timestamp) {\n    auto& rank = m_ranks[rank_idx];\n    auto earliestPossibleExit = this->earliestPossiblePowerDownEntryTime(rank);\n    auto exitTime = std::max(timestamp, earliestPossibleExit);\n\n    m_implicitCommandHandler.addImplicitCommand(exitTime, [rank_idx, exitTime](LPDDR5Core& self) {\n        auto& rank = self.m_ranks[rank_idx];\n        rank.memState = MemState::NOT_IN_PD;\n        rank.cycles.powerDownPre.close_interval(exitTime);\n    });\n}\n\nvoid LPDDR5Core::handleDSMEntry(Rank &rank, timestamp_t timestamp) {\n    assert(rank.memState == MemState::SREF);\n    rank.cycles.deepSleepMode.start_interval(timestamp);\n    rank.counter.deepSleepMode++;\n    rank.memState = MemState::DSM;\n}\n\nvoid LPDDR5Core::handleDSMExit(Rank &rank, timestamp_t timestamp) {\n    assert(rank.memState == MemState::DSM);\n    rank.cycles.deepSleepMode.close_interval(timestamp);\n    rank.memState = MemState::SREF;\n}\n\ntimestamp_t LPDDR5Core::earliestPossiblePowerDownEntryTime(Rank & rank) const {\n    timestamp_t entryTime = 0;\n\n    for (const auto &bank : rank.banks) {\n        entryTime = std::max(\n            {entryTime,\n                bank.counter.act == 0 ? 0\n                                    : bank.cycles.act.get_start() + m_memSpec.tRCD,\n                bank.counter.pre == 0 ? 0 : bank.latestPre + m_memSpec.tRP,\n                bank.refreshEndTime});\n    }\n\n    return entryTime;\n}\n\nvoid LPDDR5Core::getWindowStats(timestamp_t timestamp, SimulationStats &stats) {\n    m_implicitCommandHandler.processImplicitCommandQueue(*this, timestamp, m_last_command_time);\n    stats.bank.resize(m_memSpec.numberOfBanks * m_memSpec.numberOfRanks);\n    stats.rank_total.resize(m_memSpec.numberOfRanks);\n\n    auto simulation_duration = timestamp;\n    for (size_t i = 0; i < m_memSpec.numberOfRanks; ++i) {\n        const Rank &rank = m_ranks[i];\n        size_t bank_offset = i * m_memSpec.numberOfBanks;\n\n        for (std::size_t j = 0; j < m_memSpec.numberOfBanks; ++j) {\n            stats.bank[bank_offset + j].counter = rank.banks[j].counter;\n            stats.bank[bank_offset + j].cycles.act =\n                rank.banks[j].cycles.act.get_count_at(timestamp);\n            stats.bank[bank_offset + j].cycles.selfRefresh =\n                rank.cycles.sref.get_count_at(timestamp) -\n                rank.cycles.deepSleepMode.get_count_at(timestamp);\n            stats.bank[bank_offset + j].cycles.deepSleepMode =\n                rank.cycles.deepSleepMode.get_count_at(timestamp);\n            stats.bank[bank_offset + j].cycles.powerDownAct =\n                rank.cycles.powerDownAct.get_count_at(timestamp);\n            stats.bank[bank_offset + j].cycles.powerDownPre =\n                rank.cycles.powerDownPre.get_count_at(timestamp);\n            stats.bank[bank_offset + j].cycles.pre =\n                simulation_duration - (stats.bank[bank_offset + j].cycles.act +\n                                        rank.cycles.powerDownAct.get_count_at(timestamp) +\n                                        rank.cycles.powerDownPre.get_count_at(timestamp) +\n                                        rank.cycles.sref.get_count_at(timestamp));\n        }\n\n        stats.rank_total[i].cycles.pre =\n            simulation_duration - (rank.cycles.act.get_count_at(timestamp) +\n                                    rank.cycles.powerDownAct.get_count_at(timestamp) +\n                                    rank.cycles.powerDownPre.get_count_at(timestamp) +\n                                    rank.cycles.sref.get_count_at(timestamp));\n\n        stats.rank_total[i].cycles.act = rank.cycles.act.get_count_at(timestamp);\n        stats.rank_total[i].cycles.powerDownAct =\n            rank.cycles.powerDownAct.get_count_at(timestamp);\n        stats.rank_total[i].cycles.powerDownPre =\n            rank.cycles.powerDownPre.get_count_at(timestamp);\n        stats.rank_total[i].cycles.selfRefresh =\n            rank.cycles.sref.get_count_at(timestamp) -\n            rank.cycles.deepSleepMode.get_count_at(timestamp);\n        stats.rank_total[i].cycles.deepSleepMode =\n            rank.cycles.deepSleepMode.get_count_at(timestamp);\n    }\n}\n\nvoid LPDDR5Core::serialize(std::ostream& stream) const {\n    stream.write(reinterpret_cast<const char*>(&m_last_command_time), sizeof(m_last_command_time));\n    for (const auto& rank : m_ranks) {\n        rank.serialize(stream);\n    }\n}\nvoid LPDDR5Core::deserialize(std::istream& stream) {\n    stream.read(reinterpret_cast<char*>(&m_last_command_time), sizeof(m_last_command_time));\n    for (auto& rank : m_ranks) {\n        rank.deserialize(stream);\n    }\n}\n\n} // namespace DRAMPower"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr5/LPDDR5Core.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_LPDDR5_LPDDR5CORE_H\n#define DRAMPOWER_STANDARDS_LPDDR5_LPDDR5CORE_H\n\n#include \"DRAMPower/util/Deserialize.h\"\n#include \"DRAMPower/util/Serialize.h\"\n#include <DRAMPower/Types.h>\n#include \"DRAMPower/dram/Rank.h\"\n#include \"DRAMPower/command/Command.h\"\n#include <DRAMPower/data/stats.h>\n#include \"DRAMPower/util/ImplicitCommandHandler.h\"\n\n#include \"DRAMPower/memspec/MemSpecLPDDR5.h\"\n\n#include <vector>\n\nnamespace DRAMPower {\n\nnamespace internal {\n    template<typename Core>\n    class TestAccessor;\n}\n\nstruct LPDDR5CoreMemSpec {\n    LPDDR5CoreMemSpec(const MemSpecLPDDR5& memSpec)\n        : numberOfBanks(memSpec.numberOfBanks)\n        , numberOfRanks(memSpec.numberOfRanks)\n        , tRFC(memSpec.memTimingSpec.tRFC)\n        , tRFCPB(memSpec.memTimingSpec.tRFCPB)\n        , tRAS(memSpec.memTimingSpec.tRAS)\n        , tRCD(memSpec.memTimingSpec.tRCD)\n        , tRP(memSpec.memTimingSpec.tRP)\n        , bank_arch(memSpec.bank_arch)\n        , perTwoBankOffset(memSpec.perTwoBankOffset)\n        , prechargeOffsetRD(memSpec.prechargeOffsetRD)\n        , prechargeOffsetWR(memSpec.prechargeOffsetWR)\n    {}\n\n    uint64_t numberOfBanks;\n    uint64_t numberOfRanks;\n\n    uint64_t tRFC;\n    uint64_t tRFCPB;\n    uint64_t tRAS;\n    uint64_t tRCD;\n    uint64_t tRP;\n    MemSpecLPDDR5::BankArchitectureMode bank_arch;\n    std::size_t perTwoBankOffset;\n    uint64_t prechargeOffsetRD;\n    uint64_t prechargeOffsetWR;\n};\n\nclass LPDDR5Core : public util::Serialize, public util::Deserialize {\n// Friend classes\nfriend class internal::TestAccessor<LPDDR5Core>;\n\n// Public constructors\npublic:\n    LPDDR5Core(const MemSpecLPDDR5& memSpec)\n        : m_memSpec(memSpec)\n        , m_ranks(memSpec.numberOfRanks, {static_cast<std::size_t>(memSpec.numberOfBanks)})\n    {}\n\n// Public member functions\npublic:\n// Member functions\n    void doCommand(const Command& cmd);\n    timestamp_t getLastCommandTime() const;\n    bool isSerializable() const;\n    void getWindowStats(timestamp_t timestamp, SimulationStats &stats);\n// Overrides\n    void serialize(std::ostream& stream) const override;\n    void deserialize(std::istream& stream) override;\n\n// Private member functions\nprivate:\n    void handleAct(Rank& rank, Bank& bank, timestamp_t timestamp);\n    void handlePre(Rank& rank, Bank& bank, timestamp_t timestamp);\n    void handlePreAll(Rank& rank, timestamp_t timestamp);\n    void handleRead(Rank& rank, Bank& bank, timestamp_t timestamp);\n    void handleWrite(Rank& rank, Bank& bank, timestamp_t timestamp);\n    void handleReadAuto(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp);\n    void handleWriteAuto(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp);\n    void handleRefAll(std::size_t rank_idx, timestamp_t timestamp);\n    void handleRefPerBank(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp);\n    void handleRefPerTwoBanks(std::size_t rank_idx, std::size_t bank_id, timestamp_t timestamp);\n    void handleRefreshOnBank(std::size_t rank_idx, std::size_t bank_idx, timestamp_t timestamp, uint64_t timing,\n                             uint64_t& counter);\n    void handleSelfRefreshEntry(std::size_t rank_idx, timestamp_t timestamp);\n    void handleSelfRefreshExit(Rank& rank, timestamp_t timestamp);\n    void handlePowerDownActEntry(std::size_t rank_idx, timestamp_t timestamp);\n    void handlePowerDownActExit(std::size_t rank_idx, timestamp_t timestamp);\n    void handlePowerDownPreEntry(std::size_t rank_idx, timestamp_t timestamp);\n    void handlePowerDownPreExit(std::size_t rank_idx, timestamp_t timestamp);\n    void handleDSMEntry(Rank& rank, timestamp_t timestamp);\n    void handleDSMExit(Rank& rank, timestamp_t timestamp);\n\n    timestamp_t earliestPossiblePowerDownEntryTime(Rank & rank) const;\n\n// Private member variables\nprivate:\n    LPDDR5CoreMemSpec m_memSpec;\n    std::vector<Rank> m_ranks;\n    ImplicitCommandHandler<LPDDR5Core> m_implicitCommandHandler;\n    timestamp_t m_last_command_time = 0;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_LPDDR5_LPDDR5CORE_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr5/LPDDR5Interface.cpp",
    "content": "#include \"LPDDR5Interface.h\"\n#include \"DRAMPower/Exceptions.h\"\n\nnamespace DRAMPower {\n\nstatic constexpr DRAMUtils::Config::ToggleRateDefinition busConfig {\n    0,\n    0,\n    0,\n    0,\n    DRAMUtils::Config::TogglingRateIdlePattern::L,\n    DRAMUtils::Config::TogglingRateIdlePattern::L\n};\n\nLPDDR5Interface::LPDDR5Interface(const MemSpecLPDDR5& memSpec, const config::SimConfig& simConfig)\n    : m_memSpec(memSpec)\n    , m_commandBus{cmdBusWidth, 2, // modelled with datarate 2\n        util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L}\n    , m_dataBus{\n        util::databus_presets::getDataBusPreset(\n            util::DataBusConfig {\n                memSpec.bitWidth * memSpec.numberOfDevices,\n                memSpec.dataRate,\n                simConfig.toggleRateDefinition.value_or(busConfig)\n            },\n            simConfig.toggleRateDefinition.has_value()\n                ? util::DataBusMode::TogglingRate\n                : util::DataBusMode::Bus,\n            false\n        )\n    }\n    , m_readDQS(memSpec.dataRate, true)\n    , m_wck(memSpec.dataRate / memSpec.memTimingSpec.WCKtoCK, !memSpec.wckAlwaysOnMode)\n    , m_dbi(memSpec.numberOfDevices * memSpec.bitWidth, m_memSpec.burstLength,\n        [this](timestamp_t load_timestamp, timestamp_t, std::size_t pin, bool inversion_state, bool read) {\n        this->handleDBIPinChange(load_timestamp, pin, inversion_state, read);\n    }, false)\n    , m_dbiread(m_dbi.getChunksPerWidth().value(), pin_dbi_t{m_dbi.getIdlePattern(), m_dbi.getIdlePattern()})\n    , m_dbiwrite(m_dbi.getChunksPerWidth().value(), pin_dbi_t{m_dbi.getIdlePattern(), m_dbi.getIdlePattern()})\n    , m_patternHandler(PatternEncoderOverrides{}) // No overrides\n{\n    registerPatterns();\n}\n\nvoid LPDDR5Interface::registerPatterns() {\n    using namespace pattern_descriptor;\n    using commandPattern_t = std::vector<pattern_descriptor::t>;\n    // ACT\n    // LPDDR5 needs 2 commands for activation (ACT-1 and ACT-2)\n    // ACT-1 must be followed by ACT-2 in almost every case (CAS, WRITE,\n    // MASK WRITE and READ commands can be issued inbetween ACT-1 and ACT-2)\n    // Here we consider ACT = ACT-1 + ACT-2, not considering interleaving\n    commandPattern_t act_pattern = {\n        // ACT-1\n        // R1\n        H, H, H, R14, R15, R16, R17,\n        // F1\n        BA0, BA1, BA2, BA3, R11, R12, R13,\n        // ACT-2\n        // R2\n        H, H, L, R7, R8, R9, R10,\n        // F2\n        R0, R1, R2, R3, R4, R5, R6\n    };\n    if (m_memSpec.bank_arch == MemSpecLPDDR5::MBG) {\n        act_pattern[9] = BG0;\n        act_pattern[10] = BG1;\n    } else if (m_memSpec.bank_arch == MemSpecLPDDR5::M8B) {\n        act_pattern[10] = V;\n    }\n    m_patternHandler.registerPattern<CmdType::ACT>(act_pattern);\n    // PRE\n    commandPattern_t pre_pattern = {\n        // R1\n        L, L, L, H, H, H, H,\n        // F1\n        BA0, BA1, BA2, BA3, V, V, L\n    };\n    if (m_memSpec.bank_arch == MemSpecLPDDR5::MBG) {\n        pre_pattern[9] = BG0;\n        pre_pattern[10] = BG1;\n    } else if (m_memSpec.bank_arch == MemSpecLPDDR5::M8B) {\n        pre_pattern[10] = V;\n    }\n    m_patternHandler.registerPattern<CmdType::PRE>(pre_pattern);\n    // PREA\n    commandPattern_t prea_pattern = {\n        // R1\n        L, L, L, H, H, H, H,\n        // F1\n        V, V, V, V, V, V, H\n    };\n    if (m_memSpec.bank_arch == MemSpecLPDDR5::MBG) {\n        prea_pattern[9] = BG0;\n        prea_pattern[10] = BG1;\n    } else if (m_memSpec.bank_arch == MemSpecLPDDR5::M8B) {\n        prea_pattern[10] = V;\n    }\n    m_patternHandler.registerPattern<CmdType::PREA>(prea_pattern);\n    // REFB\n    // For refresh commands LPDDR5 has RFM (Refresh Management)\n    // Considering RFM is disabled, CA3 is V\n    commandPattern_t refb_pattern = {\n        // R1\n        L, L, L, H, H, H, L,\n        // F1\n        BA0, BA1, BA2, V, V, V, L\n    };\n    if (m_memSpec.bank_arch == MemSpecLPDDR5::MBG) {\n        refb_pattern[9] = BG0;\n    }\n    m_patternHandler.registerPattern<CmdType::REFB>(refb_pattern);\n    // RD\n    commandPattern_t rd_pattern = {\n        // R1\n        H, L, L, C0, C3, C4, C5,\n        // F1\n        BA0, BA1, BA2, BA3, C1, C2, L\n    };\n    if (m_memSpec.bank_arch == MemSpecLPDDR5::MBG) {\n        rd_pattern[9] = BG0;\n        rd_pattern[10] = BG1;\n    } else if (m_memSpec.bank_arch == MemSpecLPDDR5::M8B) {\n        rd_pattern[10] = L; // B4\n    }\n    m_patternHandler.registerPattern<CmdType::RD>(rd_pattern);\n    // RDA\n    commandPattern_t rda_pattern = {\n        // R1\n        H, L, L, C0, C3, C4, C5,\n        // F1\n        BA0, BA1, BA2, BA3, C1, C2, H\n    };\n    if (m_memSpec.bank_arch == MemSpecLPDDR5::MBG) {\n        rda_pattern[9] = BG0;\n        rda_pattern[10] = BG1;\n    } else if (m_memSpec.bank_arch == MemSpecLPDDR5::M8B) {\n        rda_pattern[10] = L;\n    }\n    m_patternHandler.registerPattern<CmdType::RDA>(rda_pattern);\n    // WR\n    commandPattern_t wr_pattern = {\n        // R1\n        L, H, H, C0, C3, C4, C5,\n        // F1\n        BA0, BA1, BA2, BA3, C1, C2, L\n    };\n    if (m_memSpec.bank_arch == MemSpecLPDDR5::MBG) {\n        wr_pattern[9] = BG0;\n        wr_pattern[10] = BG1;\n    } else if (m_memSpec.bank_arch == MemSpecLPDDR5::M8B) {\n        wr_pattern[10] = V;\n    }\n    m_patternHandler.registerPattern<CmdType::WR>(wr_pattern);\n    // WRA\n    commandPattern_t wra_pattern = {\n        // R1\n        L, H, H, C0, C3, C4, C5,\n        // F1\n        BA0, BA1, BA2, BA3, C1, C2, H\n    };\n    if (m_memSpec.bank_arch == MemSpecLPDDR5::MBG) {\n        wra_pattern[9] = BG0;\n        wra_pattern[10] = BG1;\n    } else if (m_memSpec.bank_arch == MemSpecLPDDR5::M8B) {\n        wra_pattern[10] = V;\n    }\n    m_patternHandler.registerPattern<CmdType::WRA>(wra_pattern);\n    // REFP2B\n    if (m_memSpec.bank_arch == MemSpecLPDDR5::MBG || m_memSpec.bank_arch == MemSpecLPDDR5::M16B) {\n        m_patternHandler.registerPattern<CmdType::REFP2B>(refb_pattern);\n    }\n    // REFA\n    commandPattern_t refa_pattern = {\n        // R1\n        L, L, L, H, H, H, L,\n        // F1\n        V, V, V, V, V, V, H\n    };\n    if (m_memSpec.bank_arch == MemSpecLPDDR5::MBG) {\n        refa_pattern[9] = BG0;\n    }\n    m_patternHandler.registerPattern<CmdType::REFA>(refa_pattern);\n    // SREFEN\n    m_patternHandler.registerPattern<CmdType::SREFEN>({\n        // R1\n        L, L, L, H, L, H, H,\n        // F1\n        V, V, V, V, V, L, L\n    });\n    // SREFEX\n    m_patternHandler.registerPattern<CmdType::SREFEX>({\n        // R1\n        L, L, L, H, L, H, L,\n        // F1\n        V, V, V, V, V, V, V\n    });\n    // PDEA\n    m_patternHandler.registerPattern<CmdType::PDEA>({\n        // R1\n        L, L, L, H, L, H, H,\n        // F1\n        V, V, V, V, V, L, H\n    });\n    // PDEP\n    m_patternHandler.registerPattern<CmdType::PDEP>({\n        // R1\n        L, L, L, H, L, H, H,\n        // F1\n        V, V, V, V, V, L, H\n    });\n    // PDXA\n    m_patternHandler.registerPattern<CmdType::PDXA>({\n        // R1\n        L, L, L, H, L, H, L,\n        // F1\n        V, V, V, V, V, V, V\n    });\n    // PDXP\n    m_patternHandler.registerPattern<CmdType::PDXP>({\n        // R1\n        L, L, L, H, L, H, L,\n        // F1\n        V, V, V, V, V, V, V\n    });\n    // DSMEN\n    m_patternHandler.registerPattern<CmdType::DSMEN>({\n        // R1\n        L, L, L, H, L, H, H,\n        // F1\n        V, V, V, V, V, H, L\n    });\n    // DSMEX\n    m_patternHandler.registerPattern<CmdType::DSMEX>({\n        // R1\n        L, L, L, H, L, H, L,\n        // F1\n        V, V, V, V, V, V, V\n    });\n}\n\n\ntimestamp_t LPDDR5Interface::getLastCommandTime() const {\n    return m_last_command_time;\n}\n\nvoid LPDDR5Interface::doCommand(const Command& cmd) {\n    switch(cmd.type) {\n        case CmdType::ACT:\n        case CmdType::PRE:\n        case CmdType::PREA:\n        case CmdType::REFB:\n        case CmdType::REFA:\n        case CmdType::SREFEN:\n        case CmdType::SREFEX:\n        case CmdType::PDEA:\n        case CmdType::PDEP:\n        case CmdType::PDXA:\n        case CmdType::PDXP:\n        case CmdType::DSMEN:\n        case CmdType::DSMEX:\n            handleCommandBus(cmd);\n            break;\n        case CmdType::REFP2B:\n            if (m_memSpec.bank_arch != MemSpecLPDDR5::MBG && m_memSpec.bank_arch != MemSpecLPDDR5::M16B) {\n                throw Exception(std::string(\"REFP2B command is not supported for this bank architecture: \") + CmdTypeUtil::to_string(CmdType::REFP2B));\n            }\n            handleCommandBus(cmd);\n            break;\n        case CmdType::RD:\n        case CmdType::RDA:\n            handleData(cmd, true);\n            break;\n        case CmdType::WR:\n        case CmdType::WRA:\n            handleData(cmd, false);\n            break;\n        case CmdType::END_OF_SIMULATION:\n            endOfSimulation(cmd.timestamp);\n            break;\n        default:\n            assert(false && \"Invalid command\");\n            break;\n    }\n    m_last_command_time = cmd.timestamp;\n}\n\nvoid LPDDR5Interface::handleDBIPinChange(const timestamp_t load_timestamp, std::size_t pin, bool state, bool read) {\n    assert(pin < m_dbiread.size() || pin < m_dbiwrite.size());\n    if (read) {\n        this->m_dbiread[pin].set(load_timestamp, state ? util::PinState::H : util::PinState::L, 1);\n    } else {\n        this->m_dbiwrite[pin].set(load_timestamp, state ? util::PinState::H : util::PinState::L, 1);\n    }\n}\n\nstd::optional<const uint8_t *> LPDDR5Interface::handleDBIInterface(timestamp_t timestamp, std::size_t n_bits, const uint8_t* data, bool read) {\n    if (0 == n_bits || !data || !m_dbi.isEnabled()) {\n        // No DBI or no data to process\n        return std::nullopt;\n    }\n    timestamp_t virtual_time = timestamp * m_memSpec.dataRate;\n    // updateDBI calls the given callback to handle pin changes\n    return m_dbi.updateDBI(virtual_time, n_bits, data, read);\n}\n\nvoid LPDDR5Interface::handleOverrides(size_t length, bool /*read*/) {\n    // Set command bus pattern overrides\n    switch(length) {\n        case 32:\n            m_patternHandler.getEncoder().settings.updateSettings({\n                {pattern_descriptor::C0, PatternEncoderBitSpec::L},\n            });\n            break;\n        default:\n            // Pull down\n            // No interface power needed for PatternEncoderBitSpec::L\n            // Defaults to burst length 16\n        case 16:\n            m_patternHandler.getEncoder().settings.removeSetting(pattern_descriptor::C0);\n            break;\n    }\n}\n\nvoid LPDDR5Interface::handleCommandBus(const Command &cmd) {\n    auto pattern = m_patternHandler.getCommandPattern(cmd);\n    auto ca_length = m_patternHandler.getPattern(cmd.type).size() / m_commandBus.get_width();\n    m_commandBus.load(cmd.timestamp, pattern, ca_length);\n}\n\nvoid LPDDR5Interface::handleData(const Command &cmd, bool read) {\n    auto loadfunc = read ? &databus_t::loadRead : &databus_t::loadWrite;\n    size_t length = 0;\n    if (0 == cmd.sz_bits) {\n        // No data provided by command\n        if (m_dataBus.isTogglingRate()) {\n            length = m_memSpec.burstLength;\n            (m_dataBus.*loadfunc)(cmd.timestamp, length * m_dataBus.getWidth(), nullptr);\n        }\n    } else {\n        std::optional<const uint8_t *> dbi_data = std::nullopt;\n        // Data provided by command\n        if (m_dataBus.isBus() && m_dbi.isEnabled()) {\n            // Only compute dbi for bus mode\n            dbi_data = handleDBIInterface(cmd.timestamp, cmd.sz_bits, cmd.data, read);\n        }\n        length = cmd.sz_bits / (m_dataBus.getWidth());\n        (m_dataBus.*loadfunc)(cmd.timestamp, cmd.sz_bits, dbi_data.value_or(cmd.data));\n    }\n    // DQS\n    if (read) {\n        // Read\n        m_readDQS.start(cmd.timestamp);\n        m_readDQS.stop(cmd.timestamp + length / m_memSpec.dataRate);\n        if (!m_memSpec.wckAlwaysOnMode) {\n            m_wck.start(cmd.timestamp);\n            m_wck.stop(cmd.timestamp + length / m_memSpec.dataRate);\n        }\n    } else {\n        // Write\n        if (!m_memSpec.wckAlwaysOnMode) {\n            m_wck.start(cmd.timestamp);\n            m_wck.stop(cmd.timestamp + length / m_memSpec.dataRate);\n        }\n    }\n    handleOverrides(length, read);\n    handleCommandBus(cmd);\n}\n\nvoid LPDDR5Interface::endOfSimulation(timestamp_t timestamp) {\n    m_dbi.dispatchResetCallback(timestamp);\n}\n\nvoid LPDDR5Interface::getWindowStats(timestamp_t timestamp, SimulationStats &stats) const {\n    stats.commandBus = m_commandBus.get_stats(timestamp);\n\n    m_dataBus.get_stats(timestamp,\n        stats.readBus,\n        stats.writeBus,\n        stats.togglingStats.read,\n        stats.togglingStats.write\n    );\n\n    stats.clockStats = 2.0 * m_clock.get_stats_at(timestamp);\n    stats.wClockStats = 2.0 * m_wck.get_stats_at(timestamp);\n    stats.readDQSStats = 2.0 * m_readDQS.get_stats_at(timestamp);\n\n    for (const auto &dbi_pin : m_dbiread) {\n        stats.readDBI += dbi_pin.get_stats_at(timestamp, 2);\n    }\n    for (const auto &dbi_pin : m_dbiwrite) {\n        stats.writeDBI += dbi_pin.get_stats_at(timestamp, 2);\n    }\n}\n\nvoid LPDDR5Interface::serialize(std::ostream& stream) const {\n    stream.write(reinterpret_cast<const char*>(&m_last_command_time), sizeof(m_last_command_time));\n    m_patternHandler.serialize(stream);\n    m_commandBus.serialize(stream);\n    m_dataBus.serialize(stream);\n    m_readDQS.serialize(stream);\n    m_wck.serialize(stream);\n    m_clock.serialize(stream);\n}\nvoid LPDDR5Interface::deserialize(std::istream& stream) {\n    stream.read(reinterpret_cast<char*>(&m_last_command_time), sizeof(m_last_command_time));\n    m_patternHandler.deserialize(stream);\n    m_commandBus.deserialize(stream);\n    m_dataBus.deserialize(stream);\n    m_readDQS.deserialize(stream);\n    m_wck.deserialize(stream);\n    m_clock.deserialize(stream);\n}\n\n} // namespace DRAMPower"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr5/LPDDR5Interface.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_LPDDR5_LPDDR5INTERFACE_H\n#define DRAMPOWER_STANDARDS_LPDDR5_LPDDR5INTERFACE_H\n\n#include \"DRAMPower/util/pin.h\"\n#include \"DRAMPower/util/bus.h\"\n#include \"DRAMPower/util/databus_presets.h\"\n#include \"DRAMPower/util/clock.h\"\n#include \"DRAMPower/util/Serialize.h\"\n#include \"DRAMPower/util/Deserialize.h\"\n\n#include \"DRAMPower/Types.h\"\n#include \"DRAMPower/command/Command.h\"\n#include \"DRAMPower/data/stats.h\"\n\n#include \"DRAMPower/util/PatternHandler.h\"\n#include \"DRAMPower/util/dbi.h\"\n\n#include \"DRAMPower/memspec/MemSpecLPDDR5.h\"\n\n#include \"DRAMPower/simconfig/simconfig.h\"\n\n#include <stdint.h>\n#include <cstddef>\n#include <vector>\n\nnamespace DRAMPower {\n\nstruct LPDDR5InterfaceMemSpec {\n    LPDDR5InterfaceMemSpec(const MemSpecLPDDR5& memSpec)\n        : dataRate(memSpec.dataRate)\n        , burstLength(memSpec.burstLength)\n        , bitWidth(memSpec.bitWidth)\n        , bank_arch(memSpec.bank_arch)\n        , wckAlwaysOnMode(memSpec.wckAlwaysOnMode)\n    {}\n\n    uint64_t dataRate;\n    uint64_t burstLength;\n    uint64_t bitWidth;\n    MemSpecLPDDR5::BankArchitectureMode bank_arch;\n    bool wckAlwaysOnMode;\n};\n\nclass LPDDR5Interface : public util::Serialize, public util::Deserialize {\n// Public constants\npublic:\n    const static std::size_t cmdBusWidth = 7;\n    const static uint64_t cmdBusInitPattern = (1<<cmdBusWidth)-1;\n\n// Public type definitions\npublic:\n    using commandbus_t = util::Bus<cmdBusWidth>;\n    using pin_dbi_t = util::Pin<32>; // max_burst_length = 32\n    using databus_t = util::databus_presets::databus_preset_t;\n    using patternHandler_t = PatternHandler<CmdType>;\n\n// Public constructors and assignment operators\npublic:\n    LPDDR5Interface(const MemSpecLPDDR5& memSpec, const config::SimConfig& simConfig);\n\n// Public member functions\npublic:\n// Member functions\n    timestamp_t getLastCommandTime() const;\n    void doCommand(const Command& cmd);\n    void getWindowStats(timestamp_t timestamp, SimulationStats &stats) const;\n// Override\n    void serialize(std::ostream& stream) const override;\n    void deserialize(std::istream& stream) override;\n// Extensions\n    void enableDBI(bool enable) {\n        m_dbi.enable(enable);\n    }\n\n// Public member functions\nprivate:\n    void registerPatterns();\n    std::optional<const uint8_t *> handleDBIInterface(timestamp_t timestamp, std::size_t n_bits, const uint8_t* data, bool read);\n    void handleDBIPinChange(const timestamp_t load_timestamp, std::size_t pin, bool state, bool read);\n    void handleOverrides(size_t length, bool read);\n    void handleDQs(const Command& cmd, util::Clock &dqs, size_t length, uint64_t datarate);\n    void handleCommandBus(const Command& cmd);\n    void handleData(const Command &cmd, bool read);\n    void endOfSimulation(timestamp_t timestamp);\n\n// Private member variables\nprivate:\n    LPDDR5InterfaceMemSpec m_memSpec;\n    commandbus_t m_commandBus;\n    databus_t m_dataBus;\n    util::Clock m_readDQS;\n    util::Clock m_wck;\n    util::Clock m_clock;\n    util::DBI<uint8_t, 1, util::PinState::L, util::StaticDBI> m_dbi;\n    std::vector<pin_dbi_t> m_dbiread;\n    std::vector<pin_dbi_t> m_dbiwrite;\n    patternHandler_t m_patternHandler;\n    timestamp_t m_last_command_time = 0;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_LPDDR5_LPDDR5INTERFACE_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr5/core_calculation_LPDDR5.cpp",
    "content": "#include \"core_calculation_LPDDR5.h\"\n#include \"DRAMPower/data/stats.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\nnamespace DRAMPower {\n\n    Calculation_LPDDR5::Calculation_LPDDR5(const MemSpecLPDDR5 &memSpec)\n        : m_memSpec(memSpec)\n    {}\n\n    double Calculation_LPDDR5::E_pre(double VDD, double IBeta, double IDD2_N, double t_RP, uint64_t N_pre) const {\n        return VDD * (IBeta - IDD2_N) * t_RP * N_pre;\n    }\n\n    double Calculation_LPDDR5::E_act(double VDD, double I_theta, double I_1, double t_RAS, uint64_t N_act) const {\n        return VDD * (I_theta - I_1) * t_RAS * N_act;\n    }\n\n    double Calculation_LPDDR5::E_BG_pre(std::size_t B, double VDD, double IDD2_N, double T_BG_pre) const {\n        return (1.0 / B) * VDD * IDD2_N * T_BG_pre;\n    }\n\n    double Calculation_LPDDR5::E_BG_act_star(std::size_t B, double VDD, double IDD3_N, double I_p, double T_BG_act_star) const {\n        return VDD * (1.0 / B) * (IDD3_N - I_p) * T_BG_act_star;\n    }\n\n    double Calculation_LPDDR5::E_BG_act_shared(double VDD, double I_p, double T_bg_act) const {\n        return VDD * I_p * T_bg_act;\n    }\n\n    double Calculation_LPDDR5::E_RD(double VDD, double IDD4_R, double I_i, std::size_t BL, std::size_t DR, double t_WCK, uint64_t N_RD) const {\n        return VDD * (IDD4_R - I_i) * (BL / DR) * t_WCK * N_RD;\n    }\n\n    double Calculation_LPDDR5::E_WR(double VDD, double IDD4_R, double I_i, std::size_t BL, std::size_t DR, double t_WCK, uint64_t N_WR) const {\n        return VDD * (IDD4_R - I_i) * (BL / DR) * t_WCK * N_WR;\n    }\n\n    double Calculation_LPDDR5::E_ref_ab(std::size_t B, double VDD, double IDD5B, double IDD3_N, double tRFC, uint64_t N_REF) const {\n        return (1.0 / B) * VDD * (IDD5B - IDD3_N) * tRFC * N_REF;\n    }\n\n    double Calculation_LPDDR5::E_ref_pb(double VDD, double IDD5PB_B, double I_1, double tRFCPB, uint64_t N_PB_REF) const {\n        return VDD * (IDD5PB_B - I_1) * tRFCPB * N_PB_REF;\n    }\n\n    double Calculation_LPDDR5::E_ref_p2b(double VDD, double IDD5PB_B, double I_2, double tRFCPB, uint64_t N_P2B_REF) const {\n        return 0.5 * VDD * (IDD5PB_B - I_2) * tRFCPB * N_P2B_REF;\n    }\n\n    energy_t Calculation_LPDDR5::calcEnergy(const SimulationStats &stats) const {\n        auto t_CK = m_memSpec.memTimingSpec.tCK;\n        auto t_WCK = m_memSpec.memTimingSpec.tWCK;\n        auto t_RAS = m_memSpec.memTimingSpec.tRAS * t_CK;\n        auto t_RP = m_memSpec.memTimingSpec.tRP * t_CK;\n        auto t_RFC = m_memSpec.memTimingSpec.tRFC * t_CK;\n        auto t_RFCPB = m_memSpec.memTimingSpec.tRFCPB * t_CK;\n        auto t_REFI = m_memSpec.memTimingSpec.tREFI * t_CK;\n\n        auto rho = m_memSpec.bwParams.bwPowerFactRho;\n        auto BL = m_memSpec.burstLength;\n        auto DR = m_memSpec.dataRate;\n        auto B = m_memSpec.numberOfBanks;\n\n        energy_t energy(m_memSpec.numberOfBanks * m_memSpec.numberOfRanks * m_memSpec.numberOfDevices);\n\n        for (auto vd : {MemSpecLPDDR5::VoltageDomain::VDD1, MemSpecLPDDR5::VoltageDomain::VDD2H, MemSpecLPDDR5::VoltageDomain::VDD2L}) {\n            auto VDD = m_memSpec.memPowerSpec[vd].vDDX;\n            auto IDD_0 = m_memSpec.memPowerSpec[vd].iDD0X;\n            auto IDD2N = m_memSpec.memPowerSpec[vd].iDD2NX;\n            auto IDD3N = m_memSpec.memPowerSpec[vd].iDD3NX;\n            auto IDD2P = m_memSpec.memPowerSpec[vd].iDD2PX;\n            auto IDD3P = m_memSpec.memPowerSpec[vd].iDD3PX;\n            auto IDD4R = m_memSpec.memPowerSpec[vd].iDD4RX;\n            auto IDD4W = m_memSpec.memPowerSpec[vd].iDD4WX;\n            auto IDD5 = m_memSpec.memPowerSpec[vd].iDD5X;\n            auto IDD5PB = m_memSpec.memPowerSpec[vd].iDD5PBX;\n            auto IDD6 = m_memSpec.memPowerSpec[vd].iDD6X;\n            auto IDD6DS = m_memSpec.memPowerSpec[vd].iDD6DSX;\n            auto IBeta = m_memSpec.memPowerSpec[vd].iBeta;\n\n            auto I_rho = rho * (IDD3N - IDD2N) + IDD2N;\n            auto I_2 = IDD3N + (IDD3N - I_rho);\n            auto I_theta = (IDD_0 * (t_RP + t_RAS) - IBeta * t_RP) * (1 / t_RAS);\n            auto IDD5PB_B =\n                (IDD5PB * (t_REFI / 8) - IDD2N * ((t_REFI / 8) - t_RFCPB)) * (1.0 / t_RFCPB);\n            auto approx_IDD3N = I_rho + B * (IDD3N - I_rho);\n\n            size_t energy_offset = 0;\n            size_t bank_offset = 0;\n            for (size_t i = 0; i < m_memSpec.numberOfRanks; ++i) {\n                for (size_t d = 0; d < m_memSpec.numberOfDevices; ++d) {\n                    energy_offset = i * m_memSpec.numberOfDevices * m_memSpec.numberOfBanks\n                                    + d * m_memSpec.numberOfBanks;\n                    bank_offset = i * m_memSpec.numberOfBanks;\n                    for (std::size_t b = 0; b < m_memSpec.numberOfBanks; ++b) {\n                        const auto &bank = stats.bank[bank_offset + b];\n\n                        energy.bank_energy[energy_offset + b].E_act +=\n                            E_act(VDD, I_theta, IDD3N, t_RAS, bank.counter.act);\n                        energy.bank_energy[energy_offset + b].E_pre +=\n                            E_pre(VDD, IBeta, IDD2N, t_RP, bank.counter.pre);\n                        energy.bank_energy[energy_offset + b].E_bg_act +=\n                            E_BG_act_star(B, VDD, approx_IDD3N, I_rho,\n                                        stats.bank[bank_offset + b].cycles.activeTime() * t_CK);\n                        energy.bank_energy[energy_offset + b].E_bg_pre +=\n                            E_BG_pre(B, VDD, IDD2N, stats.rank_total[i].cycles.pre * t_CK);\n                        if (m_memSpec.bank_arch == MemSpecLPDDR5::MBG) {\n                            energy.bank_energy[energy_offset + b].E_RD +=\n                                E_RD(VDD, IDD4R, I_2, BL, DR, t_WCK, bank.counter.reads);\n                            energy.bank_energy[energy_offset + b].E_WR +=\n                                E_WR(VDD, IDD4W, I_2, BL, DR, t_WCK, bank.counter.writes);\n                            energy.bank_energy[energy_offset + b].E_RDA +=\n                                E_RD(VDD, IDD4R, I_2, BL, DR, t_WCK, bank.counter.readAuto);\n                            energy.bank_energy[energy_offset + b].E_WRA +=\n                                E_WR(VDD, IDD4W, I_2, BL, DR, t_WCK, bank.counter.writeAuto);\n                        } else {\n                            energy.bank_energy[energy_offset + b].E_RD +=\n                                E_RD(VDD, IDD4R, IDD3N, BL, DR, t_WCK, bank.counter.reads);\n                            energy.bank_energy[energy_offset + b].E_WR +=\n                                E_WR(VDD, IDD4W, IDD3N, BL, DR, t_WCK, bank.counter.writes);\n                            energy.bank_energy[energy_offset + b].E_RDA +=\n                                E_RD(VDD, IDD4R, IDD3N, BL, DR, t_WCK, bank.counter.readAuto);\n                            energy.bank_energy[energy_offset + b].E_WRA +=\n                                E_WR(VDD, IDD4W, IDD3N, BL, DR, t_WCK, bank.counter.writeAuto);\n                        }\n                        energy.bank_energy[energy_offset + b].E_pre_RDA +=\n                            E_pre(VDD, IBeta, IDD2N, t_RP, bank.counter.readAuto);\n                        energy.bank_energy[energy_offset + b].E_pre_WRA +=\n                            E_pre(VDD, IBeta, IDD2N, t_RP, bank.counter.writeAuto);\n                        energy.bank_energy[energy_offset + b].E_ref_AB +=\n                            E_ref_ab(B, VDD, IDD5, approx_IDD3N, t_RFC, bank.counter.refAllBank);\n                        energy.bank_energy[energy_offset + b].E_ref_PB +=\n                            E_ref_pb(VDD, IDD5PB_B, IDD3N, t_RFCPB, bank.counter.refPerBank);\n                        energy.bank_energy[energy_offset + b].E_ref_2B +=\n                            E_ref_p2b(VDD, IDD5PB_B, I_2, t_RFCPB, bank.counter.refPerTwoBanks);\n                    }\n                }\n\n                energy.E_sref += VDD * IDD6 * stats.rank_total[i].cycles.selfRefresh * t_CK * m_memSpec.numberOfDevices;\n                energy.E_PDNA += VDD * IDD3P * stats.rank_total[i].cycles.powerDownAct * t_CK * m_memSpec.numberOfDevices;\n                energy.E_PDNP += VDD * IDD2P * stats.rank_total[i].cycles.powerDownPre * t_CK * m_memSpec.numberOfDevices;\n                energy.E_dsm += VDD * IDD6DS * stats.rank_total[i].cycles.deepSleepMode * t_CK * m_memSpec.numberOfDevices;\n                energy.E_bg_act_shared +=\n                    E_BG_act_shared(VDD, I_rho, stats.rank_total[i].cycles.act * t_CK) * m_memSpec.numberOfDevices;\n            }\n        }\n\n        return energy;\n    }\n}\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr5/core_calculation_LPDDR5.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_LPDDR5_CALCULATION_LPDDR5_H\n#define DRAMPOWER_STANDARDS_LPDDR5_CALCULATION_LPDDR5_H\n\n#include \"DRAMPower/data/stats.h\"\n#pragma once\n\n#include \"DRAMPower/memspec/MemSpecLPDDR5.h\"\n#include <DRAMPower/data/energy.h>\n\n#include <DRAMPower/Types.h>\n\n#include <cstddef>\n#include <cstdint>\n\nnamespace DRAMPower\n{\n\n    class LPDDR5;\n\n    class Calculation_LPDDR5\n    {\n    public:\n        Calculation_LPDDR5(const MemSpecLPDDR5 &memSpec);\n    private:\n        double E_act(double VDD, double I_theta, double I_1, double t_RAS, uint64_t N_act) const;\n        double E_pre(double VDD, double IBeta, double IDD2_N, double t_RP, uint64_t N_pre) const;\n        double E_BG_pre(std::size_t B, double VDD, double IDD2_N, double T_BG_pre) const;\n        double E_BG_act_star(std::size_t B, double VDD, double IDD3_N, double I_p, double T_BG_act_star) const;\n        double E_BG_act_shared(double VDD, double I_p, double T_bg_act) const;\n        double E_RD(double VDD, double IDD4_R, double I_i, std::size_t BL, std::size_t DR, double t_WCK, uint64_t N_RD) const;\n        double E_WR(double VDD, double IDD4_W, double I_i, std::size_t BL, std::size_t DR, double t_WCK, uint64_t N_WR) const;\n        double E_ref_ab(std::size_t B, double VDD, double IDD5B, double IDD3_N, double tRFC, uint64_t N_REF) const;\n        double E_ref_pb(double VDD, double IDD5PB_B, double I_1, double tRFCPB, uint64_t N_PB_REF) const;\n        double E_ref_p2b(double VDD, double IDD5PB_B, double I_2, double tRFCPB, uint64_t N_P2B_REF) const;\n\n    public:\n        energy_t calcEnergy(const SimulationStats &stats) const;\n    private:\n        const MemSpecLPDDR5 &m_memSpec;\n    };\n\n};\n\n\n#endif /* DRAMPOWER_STANDARDS_LPDDR5_CALCULATION_LPDDR5_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr5/interface_calculation_LPDDR5.cpp",
    "content": "#include \"DRAMPower/standards/lpddr5/interface_calculation_LPDDR5.h\"\n#include \"DRAMPower/data/energy.h\"\n\nnamespace DRAMPower {\n\nstatic double calc_static_energy(uint64_t NxBits, double R_eq, double t_CK, double voltage) {\n    return NxBits * (voltage * voltage) * t_CK / R_eq;\n};\n\nstatic double calc_dynamic_energy(const uint64_t NxBits, const double energy) {\n    return NxBits * energy;\n};\n\nstatic double calcStaticTermination(const bool termination, const DRAMPower::util::bus_stats_t &stats, const double R_eq, const double t_CK, const uint64_t datarate, const double voltage)\n{\n    if (termination == false) {\n        return 0; // No static termination\n    }\n    // ones \n    return calc_static_energy(stats.ones, R_eq, t_CK / datarate, voltage);\n}\n\nInterfaceCalculation_LPDDR5::InterfaceCalculation_LPDDR5(const MemSpecLPDDR5 &memspec)\n    : memspec_(memspec), impedances_(memspec_.memImpedanceSpec) {\n    t_CK_ = memspec_.memTimingSpec.tCK;\n    t_WCK_ = memspec_.memTimingSpec.tWCK;\n    VDDQ_ = memspec_.vddq;\n}\n\ninterface_energy_info_t InterfaceCalculation_LPDDR5::calculateEnergy(const SimulationStats &stats) const {\n    interface_energy_info_t clock_energy = calcClockEnergy(stats);\n    interface_energy_info_t DQS_energy = calcDQSEnergy(stats);\n    interface_energy_info_t DQ_energy = calcDQEnergy(stats);\n    DQ_energy += calcDQEnergyTogglingRate(stats.togglingStats);\n    interface_energy_info_t CA_energy = calcCAEnergy(stats);\n    interface_energy_info_t DBI_energy = calcDBIEnergy(stats);\n\n    interface_energy_info_t result;\n    result += clock_energy;\n    result += DQS_energy;\n    result += CA_energy;\n    result += DQ_energy;\n    result += DBI_energy;\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_LPDDR5::calcClockEnergy(const SimulationStats &stats) const {\n    interface_energy_info_t result;\n\n    result.controller.staticEnergy =\n        calcStaticTermination(impedances_.ck_termination, stats.clockStats, impedances_.ck_R_eq, t_CK_, 2, VDDQ_); // datarate 2 -> half the time low other half high\n    result.controller.dynamicEnergy =\n        calc_dynamic_energy(stats.clockStats.zeroes_to_ones, impedances_.ck_dyn_E);\n\n    result.controller.staticEnergy +=\n        calcStaticTermination(impedances_.wck_termination, stats.wClockStats, impedances_.wck_R_eq, t_WCK_, 2, VDDQ_); // datarate 2 -> half the time low other half high\n    result.controller.dynamicEnergy +=\n        calc_dynamic_energy(stats.wClockStats.zeroes_to_ones, impedances_.wck_dyn_E);\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_LPDDR5::calcDQSEnergy(const SimulationStats &stats) const {\n    interface_energy_info_t result;\n\n    // Read\n    result.dram.staticEnergy +=\n        calcStaticTermination(impedances_.rdqs_termination, stats.readDQSStats, impedances_.rdqs_R_eq, t_CK_, memspec_.dataRate, VDDQ_);\n    result.dram.dynamicEnergy +=\n        calc_dynamic_energy(stats.readDQSStats.zeroes_to_ones, impedances_.rdqs_dyn_E);\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_LPDDR5::calcDQEnergyTogglingRate(const TogglingStats &stats) const\n{\n    interface_energy_info_t result;\n\n    // Write\n    result.controller.staticEnergy +=\n        calcStaticTermination(impedances_.wdq_termination, stats.write, impedances_.wdq_R_eq, t_CK_, memspec_.dataRate, VDDQ_);\n    result.controller.dynamicEnergy +=\n        calc_dynamic_energy(stats.write.zeroes_to_ones, impedances_.wdq_dyn_E);\n\n    // Read\n    result.dram.staticEnergy +=\n        calcStaticTermination(impedances_.rdq_termination, stats.read, impedances_.rdq_R_eq, t_CK_, memspec_.dataRate, VDDQ_);\n    result.dram.dynamicEnergy +=\n        calc_dynamic_energy(stats.read.zeroes_to_ones, impedances_.rdq_dyn_E);\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_LPDDR5::calcDQEnergy(const SimulationStats &stats) const {\n    interface_energy_info_t result;\n\n    // Write\n    result.controller.staticEnergy +=\n        calcStaticTermination(impedances_.wdq_termination, stats.writeBus, impedances_.wdq_R_eq, t_CK_, memspec_.dataRate, VDDQ_);\n    result.controller.dynamicEnergy +=\n        calc_dynamic_energy(stats.writeBus.zeroes_to_ones, impedances_.wdq_dyn_E);\n\n    // Read\n    result.dram.staticEnergy +=\n        calcStaticTermination(impedances_.rdq_termination, stats.readBus, impedances_.rdq_R_eq, t_CK_, memspec_.dataRate, VDDQ_);\n    result.dram.dynamicEnergy +=\n        calc_dynamic_energy(stats.readBus.zeroes_to_ones, impedances_.rdq_dyn_E);\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_LPDDR5::calcCAEnergy(const SimulationStats &stats) const {\n    interface_energy_info_t result;\n\n    result.controller.staticEnergy =\n        calcStaticTermination(impedances_.ca_termination, stats.commandBus, impedances_.ca_R_eq, t_CK_, 2, VDDQ_);\n\n    result.controller.dynamicEnergy =\n        calc_dynamic_energy(stats.commandBus.zeroes_to_ones, impedances_.ca_dyn_E);\n\n    return result;\n}\n\ninterface_energy_info_t InterfaceCalculation_LPDDR5::calcDBIEnergy(const SimulationStats &stats) const {\n    interface_energy_info_t result;\n    // Read\n    result.dram.staticEnergy +=\n        calcStaticTermination(impedances_.rdbi_termination, stats.readDBI, impedances_.rdbi_R_eq, t_CK_, memspec_.dataRate, VDDQ_);\n    result.dram.dynamicEnergy +=\n        calc_dynamic_energy(stats.readDBI.zeroes_to_ones, impedances_.rdbi_dyn_E);\n\n    // Write\n    result.controller.staticEnergy +=\n        calcStaticTermination(impedances_.wdbi_termination, stats.writeDBI, impedances_.wdbi_R_eq, t_CK_, memspec_.dataRate, VDDQ_);\n    result.controller.dynamicEnergy +=\n        calc_dynamic_energy(stats.writeDBI.zeroes_to_ones, impedances_.wdbi_dyn_E);\n\n    return result;\n}\n\n}  // namespace DRAMPower\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr5/interface_calculation_LPDDR5.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_LPDDR5_INTERFACE_CALCULATION_LPDDR5_H\n#define DRAMPOWER_STANDARDS_LPDDR5_INTERFACE_CALCULATION_LPDDR5_H\n\n#include \"DRAMPower/Types.h\"\n#include \"DRAMPower/data/energy.h\"\n#include \"DRAMPower/memspec/MemSpecLPDDR5.h\"\n#include \"DRAMPower/data/stats.h\"\n\nnamespace DRAMPower {\n\nclass InterfaceCalculation_LPDDR5 {\n   public:\n    InterfaceCalculation_LPDDR5(const MemSpecLPDDR5 &memspec);\n\n    interface_energy_info_t calculateEnergy(const SimulationStats &stats) const;\n\n   private:\n    const MemSpecLPDDR5 &memspec_;\n    const MemSpecLPDDR5::MemImpedanceSpec &impedances_;\n    double t_CK_;\n    double t_WCK_;\n    double VDDQ_;\n\n    interface_energy_info_t calcClockEnergy(const SimulationStats &stats) const;\n    interface_energy_info_t calcDQSEnergy(const SimulationStats &stats) const;\n    interface_energy_info_t calcDQEnergy(const SimulationStats &stats) const;\n    interface_energy_info_t calcCAEnergy(const SimulationStats &stats) const;\n    interface_energy_info_t calcDQEnergyTogglingRate(const TogglingStats &stats) const;\n    interface_energy_info_t calcDBIEnergy(const SimulationStats &stats) const;\n};\n\n}  // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_LPDDR5_INTERFACE_CALCULATION_LPDDR5_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/lpddr5/types.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_LPDDR5_TYPES_H\n#define DRAMPOWER_STANDARDS_LPDDR5_TYPES_H\n\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n\n#include \"DRAMPower/memspec/MemSpecLPDDR5.h\"\n#include \"DRAMPower/standards/lpddr5/LPDDR5Core.h\"\n#include \"DRAMPower/standards/lpddr5/LPDDR5Interface.h\"\n#include \"DRAMPower/standards/lpddr5/core_calculation_LPDDR5.h\"\n#include \"DRAMPower/standards/lpddr5/interface_calculation_LPDDR5.h\"\n\nnamespace DRAMPower {\n\nstruct LPDDR5Types {\n    using DRAMUtilsMemSpec_t = DRAMUtils::MemSpec::MemSpecLPDDR5;\n    using MemSpec_t = MemSpecLPDDR5;\n    using Core_t = LPDDR5Core;\n    using Interface_t = LPDDR5Interface;\n    using CalcCore_t = Calculation_LPDDR5;\n    using CalcInterface_t = InterfaceCalculation_LPDDR5;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_STANDARDS_LPDDR5_TYPES_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/standards/test_accessor.h",
    "content": "#ifndef DRAMPOWER_STANDARDS_TEST_ACCESSOR_H\n#define DRAMPOWER_STANDARDS_TEST_ACCESSOR_H\n\n#include \"DRAMPower/standards/ddr4/DDR4Core.h\"\n#include \"DRAMPower/standards/ddr5/DDR5Core.h\"\n#include \"DRAMPower/standards/lpddr4/LPDDR4Core.h\"\n#include \"DRAMPower/standards/lpddr5/LPDDR5Core.h\"\n\nnamespace DRAMPower::internal {\n\n// Tests access to private members of DDR4, DDR5, LPDDR4, and LPDDR5 classes.\n// https://github.com/google/googletest/blob/main/docs/advanced.md#testing-private-code\ntemplate<typename Core>\nclass TestAccessor {\npublic:\n    static std::vector<Rank>& getRanks(Core& core) {\n        return core.m_ranks;\n    }\n};\n\n// Specializations for each standard\nstatic const TestAccessor<DDR4Core> DDR4TestAccessor;\nstatic const TestAccessor<DDR5Core> DDR5TestAccessor;\nstatic const TestAccessor<LPDDR4Core> LPDDR4TestAccessor;\nstatic const TestAccessor<LPDDR5Core> LPDDR5TestAccessor;\n\n#ifndef DRAMPOWER_TESTING\n#error \"test-internal.h should only be included in test files\"\n#endif\n\n} // namespace DRAMPower::internal\n\n#endif /* DRAMPOWER_STANDARDS_TEST_ACCESSOR_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/Deserialize.h",
    "content": "/*\n * Copyright (c) 2023, RPTU Kaiserslautern-Landau\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * 3. Neither the name of the copyright holder nor the names of its\n *    contributors may be used to endorse or promote products derived from\n *    this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER\n * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * Author:\n *    Derek Christ\n *    Marco Mörz\n */\n\n#ifndef DRAMPOWER_UTIL_DESERIALIZE_H\n#define DRAMPOWER_UTIL_DESERIALIZE_H\n\n#include <istream>\n\nnamespace DRAMPower::util\n{\nclass Deserialize\n{\nprotected:\n    Deserialize() = default;\n    Deserialize(const Deserialize&) = default;\n    Deserialize(Deserialize&&) = default;\n    Deserialize& operator=(const Deserialize&) = default;\n    Deserialize& operator=(Deserialize&&) = default;\n\npublic:\n    virtual ~Deserialize() = default;\n\n    virtual void deserialize(std::istream& stream) = 0;\n};\n\n} // namespace DRAMPower::util\n\n#endif /* DRAMPOWER_UTIL_DESERIALIZE_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/ImplicitCommandHandler.h",
    "content": "#ifndef DRAMPOWER_UTIL_IMPLICITCOMMANDHANDLER_H\n#define DRAMPOWER_UTIL_IMPLICITCOMMANDHANDLER_H\n\n#include <DRAMPower/Types.h>\n\n#include <deque>\n#include <functional>\n#include <type_traits>\n#include <utility>\n#include <algorithm>\n#include <cstddef>\n\nnamespace DRAMPower {\n\nnamespace details {\n    template <typename Queue, typename Func>\n    void addImplicitCommand(Queue& queue, timestamp_t timestamp, Func&& func)\n    {\n        auto entry = std::make_pair(timestamp, std::forward<Func>(func));\n\n        auto upper = std::upper_bound(queue.begin(), queue.end(),\n            entry,\n            [](const auto& lhs, const auto& rhs) { return lhs.first < rhs.first; });\n\n        queue.emplace(upper, entry);\n    }\n\n} // namespace details\n\ntemplate <typename CommandContext = void>\nclass ImplicitCommandHandler;\n\ntemplate<typename CommandContext>\nclass ImplicitCommandHandler {\n// Public type definitions\npublic:\n    using CommandContext_t = std::add_lvalue_reference_t<std::remove_reference_t<CommandContext>>;\n    using implicitCommand_t = std::function<void(CommandContext_t)>;\n    using implicitCommandListEntry_t = std::pair<timestamp_t, implicitCommand_t>;\n    using implicitCommandList_t = std::deque<implicitCommandListEntry_t>;\n\n    \n// Public member functions\npublic:\n    template <typename Func>\n    void addImplicitCommand(timestamp_t timestamp, Func&& func)\n    {\n        details::addImplicitCommand(m_implicitCommandList, timestamp, std::forward<Func>(func));\n    }\n\n    void processImplicitCommandQueue(CommandContext_t context, timestamp_t timestamp, timestamp_t &last_command_time) {\n        while (!m_implicitCommandList.empty() && m_implicitCommandList.front().first <= timestamp) {\n            // Execute implicit command functor\n            auto& [i_timestamp, i_implicitCommand] = m_implicitCommandList.front();\n            i_implicitCommand(context);\n            last_command_time = i_timestamp;\n            m_implicitCommandList.pop_front();\n        }\n    }\n\n    std::size_t implicitCommandCount() const {\n        return m_implicitCommandList.size();\n    }\n\n// Private member variables\nprivate:\n    implicitCommandList_t m_implicitCommandList;\n};\n\ntemplate<>\nclass ImplicitCommandHandler<void> {\n// Public type definitions\npublic:\n    using implicitCommand_t = std::function<void(void)>;\n    using implicitCommandListEntry_t = std::pair<timestamp_t, implicitCommand_t>;\n    using implicitCommandList_t = std::deque<implicitCommandListEntry_t>;\n\n// Public member functions\npublic:\n    template <typename Func>\n    void addImplicitCommand(timestamp_t timestamp, Func&& func)\n    {\n        details::addImplicitCommand(m_implicitCommandList, timestamp, std::forward<Func>(func));\n    }\n\n    void processImplicitCommandQueue(timestamp_t timestamp, timestamp_t &last_command_time) {\n        while (!m_implicitCommandList.empty() && m_implicitCommandList.front().first <= timestamp) {\n            // Execute implicit command functor\n            auto& [i_timestamp, i_implicitCommand] = m_implicitCommandList.front();\n            i_implicitCommand();\n            last_command_time = i_timestamp;\n            m_implicitCommandList.pop_front();\n        }\n    }\n\n    std::size_t implicitCommandCount() const {\n        return m_implicitCommandList.size();\n    }\n\n// Private member variables\nprivate:\n    implicitCommandList_t m_implicitCommandList;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_UTIL_IMPLICITCOMMANDHANDLER_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/PatternHandler.h",
    "content": "#ifndef DRAMPOWER_UTIL_PATTERNHANDLER_H\n#define DRAMPOWER_UTIL_PATTERNHANDLER_H\n\n#include <DRAMPower/command/Pattern.h>\n#include <DRAMPower/command/Command.h>\n#include <DRAMPower/util/Serialize.h>\n#include <DRAMPower/util/Deserialize.h>\n\n#include <vector>\n#include <cstddef>\n#include <cstdint>\n#include <cassert>\n#include <stdexcept>\n#include <initializer_list>\n\nnamespace DRAMPower {\n\ntemplate <typename CommandEnum>\nclass PatternHandler : public util::Serialize, public util::Deserialize {\n// Public type definitions+\npublic:\n    using commandEnum_t = CommandEnum;\n    using commandPattern_t = std::vector<pattern_descriptor::t>;\n    using commandPatternMap_t = std::vector<commandPattern_t>;\n\n// Constructors and assignment operators\npublic:\n    PatternHandler() = delete; // No default constructor\n    PatternHandler(const PatternHandler&) = default;\n    PatternHandler& operator=(const PatternHandler&) = default;\n    PatternHandler(PatternHandler&&) = default;\n    PatternHandler& operator=(PatternHandler&&) = default;\n    ~PatternHandler() = default;\n\n    // Constructor with encoder overrides and initial patterns\n    explicit PatternHandler(PatternEncoderOverrides encoderoverrides, uint64_t initPattern = 0)\n        : m_encoder(encoderoverrides)\n        , m_commandPatternMap(static_cast<std::size_t>(commandEnum_t::COUNT), commandPattern_t {})\n        , m_lastPattern(initPattern)\n    {}\n    // Constructor with no encoder overrides and initial patterns\n    explicit PatternHandler(uint64_t initPattern = 0)\n        : m_lastPattern(initPattern)\n        , m_commandPatternMap(static_cast<std::size_t>(commandEnum_t::COUNT), commandPattern_t {})\n    {}\n\n// Public member functions\npublic:\n    PatternEncoder& getEncoder() { return m_encoder; }\n    const PatternEncoder& getEncoder() const { return m_encoder; }\n\n    template <commandEnum_t cmd_type>\n    void registerPattern(const commandPattern_t &pattern)\n    {\n        assert(m_commandPatternMap.size() > static_cast<std::size_t>(cmd_type));\n        m_commandPatternMap[static_cast<std::size_t>(cmd_type)] = pattern;\n    }\n    template <commandEnum_t cmd_type>\n    void registerPattern(std::initializer_list<pattern_descriptor::t> pattern)\n    {\n        assert(m_commandPatternMap.size() > static_cast<std::size_t>(cmd_type));\n        m_commandPatternMap[static_cast<std::size_t>(cmd_type)] = commandPattern_t(pattern);\n    }\n\n    const commandPattern_t& getPattern(CmdType cmd_type) const\n    {\n        assert(m_commandPatternMap.size() > static_cast<std::size_t>(cmd_type));\n        return m_commandPatternMap[static_cast<std::size_t>(cmd_type)];\n    }\n    uint64_t getCommandPattern(const Command& cmd)\n    {\n        if (m_commandPatternMap[static_cast<std::size_t>(cmd.type)].empty()) {\n            // No pattern registered for this command\n            throw std::runtime_error(\"No pattern registered for this command\");\n        }\n        const auto& pattern = m_commandPatternMap[static_cast<std::size_t>(cmd.type)];\n        m_lastPattern = m_encoder.encode(cmd, pattern, m_lastPattern);\n        return m_lastPattern;\n    }\n\n    uint64_t getCoordinatePattern(const TargetCoordinate& coordinate, const commandPattern_t& pattern)\n    {\n        if (pattern.empty()) {\n            // No pattern provided\n            throw std::runtime_error(\"No pattern provided for this coordinate\");\n        }\n        m_lastPattern = m_encoder.encode(coordinate, pattern, m_lastPattern);\n        return m_lastPattern;\n    }\n\n// Overrides\npublic:\n    void serialize(std::ostream& stream) const override {\n        m_encoder.serialize(stream);\n    }\n    void deserialize(std::istream& stream) override {\n        m_encoder.deserialize(stream);\n    }\n\n// Private member variables\nprivate:\n    PatternEncoder m_encoder;\n    commandPatternMap_t m_commandPatternMap;\n    uint64_t m_lastPattern;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_UTIL_PATTERNHANDLER_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/RegisterHelper.h",
    "content": "#ifndef DRAMPOWER_UTIL_REGISTERHELPER_H\n#define DRAMPOWER_UTIL_REGISTERHELPER_H\n\n#include <vector>\n\n#include <DRAMPower/command/Command.h>\n#include <DRAMPower/dram/Rank.h>\n\nnamespace DRAMPower::util {\n\nnamespace coreHelpers {\n    template<typename Func, typename Owner>\n    decltype(auto) bankHandler(const Command& cmd, std::vector<Rank>& ranks, Owner owner, Func &&member_func) {\n        assert(ranks.size()>cmd.targetCoordinate.rank);\n        auto & rank = ranks.at(cmd.targetCoordinate.rank);\n\n        assert(rank.banks.size()>cmd.targetCoordinate.bank);\n        auto & bank = rank.banks.at(cmd.targetCoordinate.bank);\n\n        rank.commandCounter.inc(cmd.type);\n        return (owner->*member_func)(rank, bank, cmd.timestamp);\n    }\n\n    template<typename Func, typename Owner>\n    decltype(auto) bankHandlerIdx(const Command& cmd, std::vector<Rank>& ranks, Owner owner, Func &&member_func) {\n        assert(ranks.size()>cmd.targetCoordinate.rank);\n        assert(ranks.at(cmd.targetCoordinate.rank).banks.size()>cmd.targetCoordinate.bank);\n\n        ranks.at(cmd.targetCoordinate.rank).commandCounter.inc(cmd.type);\n        return (owner->*member_func)(cmd.targetCoordinate.rank, cmd.targetCoordinate.bank, cmd.timestamp);\n    }\n\n    template<typename Func, typename Owner>\n    decltype(auto) rankHandler(const Command& cmd, std::vector<Rank>& ranks, Owner owner, Func &&member_func) {\n        assert(ranks.size()>cmd.targetCoordinate.rank);\n        auto & rank = ranks.at(cmd.targetCoordinate.rank);\n\n        rank.commandCounter.inc(cmd.type);\n        return (owner->*member_func)(rank, cmd.timestamp);\n    }\n\n    template<typename Func, typename Owner>\n    decltype(auto) rankHandlerIdx(const Command& cmd, std::vector<Rank>& ranks, Owner owner, Func &&member_func) {\n        assert(ranks.size()>cmd.targetCoordinate.rank);\n        ranks.at(cmd.targetCoordinate.rank).commandCounter.inc(cmd.type);\n        return (owner->*member_func)(cmd.targetCoordinate.rank, cmd.timestamp);\n    }\n\n    template<typename Func, typename Owner>\n    decltype(auto) bankGroupHandler(const Command& cmd, std::vector<Rank>& ranks, Owner owner, Func &&member_func) {\n        assert(ranks.size()>cmd.targetCoordinate.rank);\n        auto& rank = ranks.at(cmd.targetCoordinate.rank);\n\n        assert(rank.banks.size()>cmd.targetCoordinate.bank);\n        if (cmd.targetCoordinate.bank >= rank.banks.size()) {\n            throw std::invalid_argument(\"Invalid bank targetcoordinate\");\n        }\n        auto bank_id = cmd.targetCoordinate.bank;\n\n        rank.commandCounter.inc(cmd.type);\n        return (owner->*member_func)(rank, bank_id, cmd.timestamp);\n    }\n\n    template<typename Func, typename Owner>\n    decltype(auto) bankGroupHandlerIdx(const Command& cmd, std::vector<Rank>& ranks, Owner owner, Func &&member_func) {\n        assert(ranks.size()>cmd.targetCoordinate.rank);\n        auto& rank = ranks.at(cmd.targetCoordinate.rank);\n\n        assert(rank.banks.size()>cmd.targetCoordinate.bank);\n        if (cmd.targetCoordinate.bank >= rank.banks.size()) {\n            throw std::invalid_argument(\"Invalid bank targetcoordinate\");\n        }\n        auto bank_id = cmd.targetCoordinate.bank;\n\n        rank.commandCounter.inc(cmd.type);\n        return (owner->*member_func)(cmd.targetCoordinate.rank, bank_id, cmd.timestamp);\n    }\n} // namespace coreHelpers\n\n} // namespace DRAMPower::util\n\n#endif /* DRAMPOWER_UTIL_REGISTERHELPER_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/Router.h",
    "content": "#ifndef DRAMPOWER_UTIL_ROUTER_H\n#define DRAMPOWER_UTIL_ROUTER_H\n\n#include <DRAMPower/command/Command.h>\n\n#include <optional>\n#include <vector>\n#include <functional>\n#include <cassert>\n#include <cstddef>\n\nnamespace DRAMPower {\n\ntemplate <typename CommandEnum>\nclass Router {\n// Public type definitions\npublic:\n    using commandEnum_t = CommandEnum;\n    using commandHandler_t = std::function<void(const Command&)>;\n    using commandRouter_t = std::vector<commandHandler_t>;\n\n// Constructors and assignment operators\npublic:\n    Router() = delete; // No default constructor\n    Router(const Router&) = default;\n    Router& operator=(const Router&) = default;\n    Router(Router&&) = default;\n    Router& operator=(Router&&) = default;\n    ~Router() = default;\n\n    // constructor with default handler\n    Router(std::optional<commandHandler_t> defaultHandler = std::nullopt)\n        : m_router(static_cast<std::size_t>(commandEnum_t::COUNT), defaultHandler.value_or([](const Command&) {}))\n    {}\n\n// Public member functions\npublic:\n    // Add a command handler to the router for the given command\n    template <commandEnum_t cmd, typename Func>\n    void routeCommand(Func&& func)\n    {\n        assert(m_router.size() > static_cast<std::size_t>(cmd));\n        m_router[static_cast<std::size_t>(cmd)] = std::forward<Func>(func);\n    }\n\n    // Execute the command handler for the given command\n    void executeCommand(const Command& command) const\n    {\n        assert(m_router.size() > static_cast<std::size_t>(command.type));\n        m_router[static_cast<std::size_t>(command.type)](command);\n    }\n    std::size_t size() const\n    {\n        return m_router.size();\n    }\n\n// Private member variables\nprivate:\n    commandRouter_t m_router;\n};\n\n} // namespace DRAMPower\n\n#endif /* DRAMPOWER_UTIL_ROUTER_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/Serialize.h",
    "content": "/*\n * Copyright (c) 2023, RPTU Kaiserslautern-Landau\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * 3. Neither the name of the copyright holder nor the names of its\n *    contributors may be used to endorse or promote products derived from\n *    this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER\n * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * Author:\n *    Derek Christ\n *    Marco Mörz\n */\n\n#ifndef DRAMPOWER_UTIL_SERIALIZE_H\n#define DRAMPOWER_UTIL_SERIALIZE_H\n\n#include <ostream>\n\nnamespace DRAMPower::util\n{\nclass Serialize\n{\nprotected:\n    Serialize() = default;\n    Serialize(const Serialize&) = default;\n    Serialize(Serialize&&) = default;\n    Serialize& operator=(const Serialize&) = default;\n    Serialize& operator=(Serialize&&) = default;\n\npublic:\n    virtual ~Serialize() = default;\n\n    virtual void serialize(std::ostream& stream) const = 0;\n};\n\n} // namespace DRAMPower::util\n\n#endif /* DRAMPOWER_UTIL_SERIALIZE_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/binary_ops.h",
    "content": "#ifndef DRAMPOWER_UTIL_BINARY_OPS_H\n#define DRAMPOWER_UTIL_BINARY_OPS_H\n\n#include <sstream>\n#include <bitset>\n\n#if defined(__GNUC__)\n\t#define POPCOUNT __builtin_popcountll\n#elif defined(_MSC_VER)\n\t#include <nmmintrin.h>\n\t#if defined(_M_X64)\n\t\t#define POPCOUNT _mm_popcnt_u64\n\t#else\n\t\t#define POPCOUNT _mm_popcnt_u32\n\t#endif\n#elif defined(__cpp_lib_bitops)\n\t#include <bit>\n\t#define POPCOUNT std::popcount\n#else\n\t#include <bitset>\n\tinline std::size_t popcount_(uint64_t n) { return std::bitset<64>(n).count(); };\n\t#define POPCOUNT popcount_\n#endif\n\nnamespace DRAMPower::util {\n\ntemplate <typename T>\ninline std::string to_string(const T& bitset)\n{\n    std::stringstream ss;\n    ss << '[';\n    for (std::size_t i = bitset.size(); i > 0;) {\n        ss << bitset[--i] ? '1' : '0';\n    }\n    ss << ']';\n\n    return ss.str();\n};\n\nstruct BinaryOps {\n    template <typename T>\n    static std::size_t popcount(const T& bitset) {\n        return POPCOUNT(bitset);\n    }\n\n    template <std::size_t N>\n    static std::size_t popcount(const std::bitset<N>& bitset)\n    {\n        return bitset.count();\n    }\n\n    template <typename T>\n    static std::size_t zero_to_ones(const T& p, const T& q)\n    {\n        return popcount(~p & q);\n    }\n\n    template <typename T>\n    static std::size_t one_to_zeroes(const T& p, const T& q)\n    {\n        return popcount(p & ~q);\n    }\n\n    template <typename T>\n    static std::size_t bit_changes(const T& p, const T& q)\n    {\n        return popcount(p ^ q);\n    }\n};\n\n};\n\n#endif /* DRAMPOWER_UTIL_BINARY_OPS_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/burst_storage.h",
    "content": "#ifndef DRAMPOWER_UTIL_BURST_STORAGE_H\n#define DRAMPOWER_UTIL_BURST_STORAGE_H\n\n#include \"DRAMUtils/util/types.h\"\n\n#include \"DRAMPower/Types.h\"\n#include \"DRAMPower/util/binary_ops.h\"\n#include \"DRAMPower/util/bus_types.h\"\n#include \"DRAMPower/util/Serialize.h\"\n#include \"DRAMPower/util/Deserialize.h\"\n\n#include <bitset>\n#include <cstddef>\n#include <iostream>\n#include <ostream>\n#include <vector>\n#include <array>\n#include <cassert>\n#include <cstdint>\n\n\nnamespace DRAMPower::util\n{\n\ntemplate <std::size_t bitset_size>\nstruct BitsetContainer {\n    using bitset_t = std::bitset<bitset_size>;\n    bitset_t bitset{};\n    std::size_t count = 0;\n    timestamp_t load_time = 0;\n};\n\ntemplate <std::size_t bitset_size>\nstruct BusContainer {\n    using bitset_t = std::bitset<bitset_size>;\n    std::vector<bitset_t> bursts{};\n    std::size_t width = 0;\n    std::size_t count = 0;\n    timestamp_t load_time = 0;\n};\n\n// Declaration\ntemplate <typename Burst>\nstruct burst_storage_impl {\n    static_assert(DRAMUtils::util::always_false<Burst>::value, \"No specialization available for type Burst\");\n};\n\n\n// Specializations\ntemplate <std::size_t bitset_size>\nstruct burst_storage_impl <BitsetContainer<bitset_size>>{\n    using burst_t = bool;\n    using data_t = BitsetContainer<bitset_size>;\n    using bitset_t = typename data_t::bitset_t;\n    using stats_t = util::bus_stats_t;\n\n    static inline void init(data_t&) { /* No initialization necessary */}\n\n    static inline stats_t count(const data_t& data, timestamp_t start, timestamp_t end, std::optional<burst_t> prev = std::nullopt) {\n        assert(start >= data.load_time && \"start timestamp must be greater or equal to load timestamp\");\n        std::size_t length = end - start;\n        // Clamp length to count\n        if (length > data.count) {\n            length = data.count;\n        }\n        const std::size_t offset = start - data.load_time;\n        assert(length + offset <= data.count && \"Invalid bitset access\");\n        bitset_t val = data.bitset >> offset;\n\n        // Mask calculation\n        bitset_t mask;\n        mask.set();\n        if (length < bitset_size) {\n            mask >>= (bitset_size - length);\n        }\n\n        if (0 == length) {\n            mask.reset();\n        }\n\n        // Extract window depending on load, start, end\n        val &= mask;\n\n        // Stats\n        bus_stats_t stats{};\n\n        // Prev to offset toggles\n        if (prev.has_value() && length != 0 && 0 == offset) {\n            stats.ones_to_zeroes = prev.value() && ~val[0];\n            stats.zeroes_to_ones = !prev.value() && val[0];\n            stats.bit_changes += (0 != stats.ones_to_zeroes && 0 != stats.zeroes_to_ones) ? 1 : 0;\n        }\n\n        // Count ones, zeroes\n        stats.ones = val.count();\n        stats.zeroes = length - stats.ones;\n\n        // Extract toggles\n        bitset_t shifted = val >> 1;\n        bitset_t trans_mask = mask >> 1;\n        bitset_t toggles = (val ^ shifted) & trans_mask;\n\n        // Calculate transitions\n        stats.bit_changes = util::BinaryOps::popcount(toggles);\n        bitset_t z2o = toggles & shifted;\n        stats.zeroes_to_ones = util::BinaryOps::popcount(z2o);\n        stats.ones_to_zeroes = stats.bit_changes - stats.zeroes_to_ones;\n\n        return stats;\n    }\n\n    static inline void resize(data_t&, std::size_t size) {\n        assert(size <= bitset_size && \"bitset_size not enough\");\n    }\n\n    static inline void push_back(data_t& data, timestamp_t load_time, burst_t bit) {\n        if (load_time != data.load_time) {\n            data.count = 0;\n            data.load_time = load_time;\n        }\n        resize(data, data.count + 1);\n        data.bitset.set(data.count, bit);\n        data.count++;\n    }\n\n    static inline burst_t& get(data_t& data, std::size_t index) {\n        assert((data.count > index) && \"Invalid access\");\n        return data.bitset[index];\n    }\n\n    static inline burst_t get_const(const data_t& data, std::size_t n) {\n        assert((data.count > n) && \"Invalid access\");\n        return data.bitset[data.count - 1 - n];\n    }\n\n    static inline std::size_t size(const data_t& data) {\n        return data.count;\n    }\n\n    static inline void clear(data_t& data) {\n        data.count = 0;\n        data.load_time = 0;\n    }\n\n    static inline std::size_t getCount(const data_t& data) {\n        return data.count;\n    }\n\n    static inline std::size_t setCount(data_t& data, std::size_t count) {\n        return data.count = count;\n    }\n\n    static inline timestamp_t endTime(const data_t& data) {\n        return data.load_time + data.count;\n    }\n\n    static inline void setLoadTime(data_t& data, timestamp_t timestamp) {\n        data.load_time = timestamp;\n    }\n\n\n    static inline void serialize(const data_t& data, std::ostream& stream) {\n\t\tstream.write(reinterpret_cast<const char*>(&data.count), sizeof(data.count));\n\t\tstream.write(reinterpret_cast<const char*>(&data.load_time), sizeof(data.load_time));\n\t\tstd::array<uint8_t, (bitset_size + 7) / 8> burst_data;\n\t\tfor (std::size_t i = 0; i < burst_data.size(); ++i) {\n\t\t\tburst_data[i] = 0;\n\t\t\tfor (std::size_t j = 0; j < 8 && (i * 8 + j) < bitset_size; ++j) {\n\t\t\t\tif (data.bitset.test(i * 8 + j)) {\n\t\t\t\t\tburst_data[i] |= (1 << j);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tstream.write(reinterpret_cast<const char*>(burst_data.data()), burst_data.size());\n    }\n\n    static inline void deserialize(data_t& data, std::istream& stream) {\n\t\tstream.read(reinterpret_cast<char*>(&data.count), sizeof(data.count));\n\t\tstream.read(reinterpret_cast<char*>(&data.load_time), sizeof(data.load_time));\n        std::array<uint8_t, (bitset_size +7) / 8> burst_data{};\n\t\tstream.read(reinterpret_cast<char*>(burst_data.data()), burst_data.size());\n\t\tfor (std::size_t i = 0; i < burst_data.size(); ++i) {\n\t\t\tfor (std::size_t j = 0; j < 8 && (i * 8 + j) < bitset_size; ++j) {\n\t\t\t\tdata.bitset.set(i * 8 + j, (burst_data[i] >> j) & 1);\n\t\t\t}\n\t\t}\n    }\n};\n\ntemplate <std::size_t bitset_size>\nstruct burst_storage_impl <BusContainer<bitset_size>> {\n    using data_t = BusContainer<bitset_size>;\n    // using data_t = BusContainer<32>;\n    using bitset_t = typename data_t::bitset_t;\n    using burst_t = bitset_t;\n    // using bitset_t = std::bitset<32>;\n    using stats_t = util::bus_stats_t;\n\n    static inline void init(data_t& data, std::size_t width) {\n        data.width = width;\n    }\n\n    static inline stats_t count(const data_t& data, timestamp_t start, timestamp_t end, std::optional<burst_t> prev = std::nullopt) {\n        assert(start >= data.load_time && \"start timestamp must be greater or equal to load timestamp\");\n        std::size_t length = end - start;\n        // Clamp length to count\n        if (length > data.count) {\n            length = data.count;\n        }\n\n        const std::size_t offset = start - data.load_time;\n        assert(length + offset <= data.bursts.size() && \"Invalid access\");\n\n        // Stats\n        bus_stats_t stats{};\n\n        for (std::size_t i = offset; i < length; i++) {\n            const auto& entry = data.bursts[i];\n            if (0 == offset) {\n                // Last Burst to this burst\n                stats += diff(data, prev, entry);\n            } else {\n                auto ones = util::BinaryOps::popcount(entry);\n                stats.ones += ones;\n                stats.zeroes += data.width - ones;\n                const auto& entry_prev = data.bursts[i - 1];\n                stats.bit_changes += util::BinaryOps::bit_changes(entry_prev, entry);\n                stats.ones_to_zeroes += util::BinaryOps::one_to_zeroes(entry_prev, entry);\n                stats.zeroes_to_ones += stats.bit_changes - stats.ones_to_zeroes;\n            }\n        }\n        return stats;\n    }\n\n    static inline void resize(data_t& data, std::size_t size) {\n        if (data.bursts.size() < size) {\n            data.bursts.resize(size);\n        }\n    }\n\n    static inline void push_back(data_t& data, timestamp_t load_time, burst_t burst) {\n        if (load_time != data.load_time) {\n            data.count = 0;\n            data.load_time = load_time;\n        }\n        resize(data, data.count + 1);\n        data.bursts[data.count] = burst;\n        data.count++;\n    }\n\n    static inline burst_t& get(data_t& data, std::size_t index) {\n        assert((data.bursts.size() > index) && \"Invalid access\");\n        return data.bursts[index];\n    }\n\n    static inline const burst_t& get_const(const data_t& data, std::size_t n) {\n        assert((data.count > n) && \"Invalid access\");\n        return data.bursts[data.count - 1 - n];\n    }\n\n    static inline std::size_t size(const data_t& data) {\n        return data.bursts.size();\n    }\n\n    static inline void clear(data_t& data) {\n        data.count = 0;\n        data.load_time = 0;\n    }\n\n    static inline std::size_t getCount(const data_t& data) {\n        return data.count;\n    }\n\n    static inline std::size_t setCount(data_t& data, std::size_t count) {\n        return data.count = count;\n    }\n\n    static inline timestamp_t endTime(const data_t& data) {\n        return data.load_time + data.count;\n    }\n\n    static inline void setLoadTime(data_t& data, timestamp_t timestamp) {\n        data.load_time = timestamp;\n    }\n\n\tstatic inline void serializeBurst(std::ostream& stream, const burst_t& burst) {\n\t\tstd::array<uint8_t, (bitset_size + 7) / 8> burst_data;\n\t\tfor (std::size_t i = 0; i < burst_data.size(); ++i) {\n\t\t\tburst_data[i] = 0;\n\t\t\tfor (std::size_t j = 0; j < 8 && (i * 8 + j) < bitset_size; ++j) {\n\t\t\t\tif (burst.test(i * 8 + j)) {\n\t\t\t\t\tburst_data[i] |= (1 << j);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tstream.write(reinterpret_cast<const char*>(burst_data.data()), burst_data.size());\n\t}\n\tstatic inline void deserializeBurst(std::istream& stream, burst_t& burst) {\n\t\tstd::array<uint8_t, (bitset_size +7) / 8> burst_data{};\n\t\tstream.read(reinterpret_cast<char*>(burst_data.data()), burst_data.size());\n\t\tfor (std::size_t i = 0; i < burst_data.size(); ++i) {\n\t\t\tfor (std::size_t j = 0; j < 8 && (i * 8 + j) < bitset_size; ++j) {\n\t\t\t\tburst.set(i * 8 + j, (burst_data[i] >> j) & 1);\n\t\t\t}\n\t\t}\n\t}\n\n    static inline void serialize(const data_t& data, std::ostream& stream) {\n        std::size_t totalBursts = data.bursts.size();\n\t\tstream.write(reinterpret_cast<const char*>(&data.count), sizeof(data.count));\n\t\tstream.write(reinterpret_cast<const char*>(&data.load_time), sizeof(data.load_time));\n        stream.write(reinterpret_cast<const char*>(&totalBursts), sizeof(totalBursts));\n        for (const auto& burst : data.bursts) {\n            serializeBurst(stream, burst);\n        }\n    }\n\n    static inline void deserialize(data_t& data, std::istream& stream) {\n        std::size_t totalBursts = 0;\n\t\tstream.read(reinterpret_cast<char*>(&data.count), sizeof(data.count));\n\t\tstream.read(reinterpret_cast<char*>(&data.load_time), sizeof(data.load_time));\n\t\tstream.read(reinterpret_cast<char*>(&totalBursts), sizeof(totalBursts));\n\t\tdata.bursts.clear();\n\t\tdata.bursts.resize(totalBursts);\n\t\tfor (std::size_t i = 0; i < totalBursts; ++i) {\n\t\t\tdeserializeBurst(stream, data.bursts[i]);\n\t\t}\n    }\n};\n\ntemplate<typename T>\nclass burst_storage : public Serialize, public Deserialize\n{\npublic:\n    using impl_data_t = T;\n    using impl_t = burst_storage_impl<T>;\n\n    using burst_t = typename impl_t::burst_t;\n\nprivate:\n\timpl_data_t m_bursts;\npublic:\n    template<typename... Args>\n\texplicit burst_storage(Args&&... args)\n\t{\n        impl_t::init(m_bursts, std::forward<Args>(args)...);\n\t}\npublic:\n\n\tvoid push_back(timestamp_t load_time, burst_t burst) {\n        impl_t::push_back(m_bursts, load_time, burst);\n\t}\n\n    inline decltype(auto) count(timestamp_t start, timestamp_t end, std::optional<burst_t> prev = std::nullopt) const {\n        return impl_t::count(m_bursts, start, end, prev);\n    }\n\n\tinline burst_t& get_or_add(std::size_t index) {\n        impl_t::resize(m_bursts, index + 1);\n\t\treturn impl_t::get(m_bursts, index);\n\t}\n\n\tvoid setCount(std::size_t count) {\n        impl_t::setCount(m_bursts, count);\n\t}\n\n\tbool empty() const { return 0 == impl_t::getCount(m_bursts); };\n\tstd::size_t size() const { return impl_t::getCount(m_bursts); };\n\n\tburst_t get_burst(std::size_t n) const {\n        return impl_t::get_const(m_bursts, n);\n    };\n\n    void clear() {\n        impl_t::clear(m_bursts);\n\t}\n\n    void setLoadTime(timestamp_t timestamp) {\n        impl_t::setLoadTime(m_bursts, timestamp);\n    }\n\n    timestamp_t endTime() const {\n        return impl_t::endTime(m_bursts);\n    }\n\n\tvoid serialize(std::ostream& stream) const override {\n        impl_t::serialize(m_bursts, stream);\n\t}\n\tvoid deserialize(std::istream& stream) override {\n        impl_t::deserialize(m_bursts, stream);\n\t}\n};\n\n\n\nstruct BurstStorageInsertHelper {\n\n    template <std::size_t bitset_width>\n    static inline void insert_data(burst_storage<BusContainer<bitset_width>>& burst_storage, timestamp_t timestamp, std::size_t width, const uint8_t* data, std::size_t n_bits, bool invert = false) {\n        size_t n_bursts = n_bits / width;\n        size_t burst_offset = 0;\n        size_t byte_index = 0;\n        size_t bit_index = 0;\n        for (std::size_t i = 0; i < n_bursts; ++i) {\n            // Extract bursts\n            std::bitset<bitset_width> &bits = burst_storage.get_or_add(i);\n            burst_offset = i * width;\n            for (std::size_t j = 0; j < width && (burst_offset + j) < n_bits; ++j) {\n                // Extract bit\n                std::size_t bit_position = bit_index % 8;\n                bool bit_value = (data[byte_index] >> bit_position) & 1;\n                bits.set(j, invert ? !bit_value : bit_value);\n                bit_index++;\n                if (bit_index % 8 == 0) {\n                    ++byte_index;\n                }\n            }\n        }\n        burst_storage.setLoadTime(timestamp);\n        burst_storage.setCount(n_bursts);\n    }\n\n};\n\n} // namespace DRAMPower::util\n\n#endif /* DRAMPOWER_UTIL_BURST_STORAGE_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/bus.cpp",
    "content": ""
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/bus.h",
    "content": "#ifndef DRAMPOWER_UTIL_BUS_H\n#define DRAMPOWER_UTIL_BUS_H\n\n#include <DRAMPower/util/binary_ops.h>\n#include <DRAMPower/util/burst_storage.h>\n#include <DRAMPower/util/bus_types.h>\n#include <DRAMPower/util/pending_stats.h>\n#include <DRAMPower/util/Serialize.h>\n#include <DRAMPower/util/Deserialize.h>\n#include <DRAMPower/Types.h>\n\n#include <DRAMUtils/util/types.h>\n\n#include <optional>\n\n#include <cmath>\n#include <cstdint>\n#include <limits>\n#include <cassert>\n#include <limits.h>\n\n#include <iostream>\n\nnamespace DRAMPower::util\n{\n\ntemplate <std::size_t max_bitset_size = 0>\nclass Bus : public Serialize, public Deserialize {\n\nprivate:\n\tenum class BusInitPatternSpec_\n\t{\n\t\tL = 0,\n\t\tH = 1,\n\t\tZ = 2,\n\t\tCUSTOM = 3\n\t};\n\npublic:\n\t\n\tusing burst_storage_t = util::burst_storage<BusContainer<max_bitset_size>>;\n\tusing burst_t = typename burst_storage_t::burst_t;\n\tusing stats_t = bus_stats_t;\n\n\tstats_t stats;\n\nprivate:\n\tburst_storage_t burst_storage;\n\t\n\ttimestamp_t last_load = 0;\n\tbool enableflag = true;\n\ttimestamp_t virtual_disable_timestamp = 0;\n\tstd::size_t width = 0;\n\tuint64_t datarate = 1;\n\tbool init_load = false;\n\t\n\tPendingStats<stats_t> pending_stats;\n\t\n\tstd::optional<burst_t> last_pattern;\n\n\tburst_t zero_pattern;\n\tburst_t one_pattern;\n\t\n\tBusIdlePatternSpec idle_pattern;\n\tBusInitPatternSpec_ init_pattern;\n\tstd::optional<burst_t> custom_init_pattern;\n\nprivate:\n\tBus(std::size_t width, uint64_t datarate, BusIdlePatternSpec idle_pattern, BusInitPatternSpec_ init_pattern,\n\t\tstd::optional<burst_t> custom_init_pattern = std::nullopt, bool enableflag = true\n\t) \n\t\t: burst_storage(width)\n\t\t, enableflag(enableflag)\n\t\t, width(width)\n\t\t, datarate(datarate)\n\t\t, idle_pattern(idle_pattern)\n\t\t, init_pattern(init_pattern)\n\t\t, custom_init_pattern (custom_init_pattern)\n\t{\n\t\t\n\t\t// Initialize zero and one patterns\n\t\tthis->zero_pattern = burst_t();\n\t\tthis->one_pattern = burst_t();\n\t\tthis->zero_pattern.reset();\n\t\tfor (std::size_t i = 0; i < width; i++)\n\t\t{\n\t\t\tthis->one_pattern.set(i, true);\n\t\t}\n\n\t\t// Initialize last pattern and init stats\n\t\tswitch(init_pattern)\n\t\t{\n\t\t\tcase BusInitPatternSpec_::L:\n\t\t\t\tthis->last_pattern = zero_pattern;\n\t\t\t\tbreak;\n\t\t\tcase BusInitPatternSpec_::H:\n\t\t\t\tthis->last_pattern = one_pattern;\n\t\t\t\tbreak;\n\t\t\tcase BusInitPatternSpec_::Z:\n\t\t\t\tthis->last_pattern = std::nullopt;\n\t\t\t\tbreak;\n\t\t\tcase BusInitPatternSpec_::CUSTOM:\n\t\t\t\t// Custom init pattern with no value is equivalent to Z\n\t\t\t\tthis->last_pattern = custom_init_pattern;\n\t\t\t\tif(custom_init_pattern.has_value())\n\t\t\t\t{\n\t\t\t\t\tassert(custom_init_pattern.value().size() == width);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tthis->init_pattern = BusInitPatternSpec_::Z;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tassert(false);\n\t\t\t\tthis->last_pattern = std::nullopt;\n\t\t}\n\t};\n\n\tstatic BusInitPatternSpec_ convertInitPattern(BusInitPatternSpec pattern) {\n\t\tswitch(pattern) {\n\t\t\tcase BusInitPatternSpec::L: return BusInitPatternSpec_::L;\n\t\t\tcase BusInitPatternSpec::H: return BusInitPatternSpec_::H;\n\t\t\tcase BusInitPatternSpec::Z: return BusInitPatternSpec_::Z;\n\t\t\tdefault: \n\t\t\t\tassert(false); // Invalid init pattern\n\t\t\t\treturn BusInitPatternSpec_::Z;\n\t\t}\n\t}\n\n\tvoid add_previous_stats(timestamp_t virtual_timestamp)\n\t{\n\t\t// Add pending stats from last load\n\t\tassert(this->pending_stats.getTimestamp() <= virtual_timestamp); // No interleaved commands\n\t\tif(this->pending_stats.isPending() && this->pending_stats.getTimestamp() < virtual_timestamp)\n\t\t{\n\t\t\tthis->stats += this->pending_stats.getStats();\n\t\t\tthis->pending_stats.clear();\n\t\t}\n\n\t\t// Advance counters to new timestamp\n\t\tfor (auto n = this->last_load; virtual_timestamp != 0 && n < virtual_timestamp - 1; n++) {\n\t\t\tthis->stats += diff(this->at(n), this->at(n + 1)); // Last: (virtual_timestamp - 2, virtual_timestamp - 1)\n\t\t};\n\n\t\t// Pattern for pending stats (virtual_timestamp - 1, virtual_timestamp)\n\t\tif(virtual_timestamp > 0)\n\t\t{\n\t\t\tthis->last_pattern = this->at(virtual_timestamp - 1);\n\t\t}\n\t}\n\n\tvoid add_data(timestamp_t virtual_timestamp, const uint8_t * data, std::size_t n_bits)\n\t{\n\t\t// Add new burst to storage\n\t\tBurstStorageInsertHelper::insert_data(this->burst_storage, virtual_timestamp, width, data, n_bits);\n\n\t\t// Adjust statistics for new data\n\t\tthis->pending_stats.setPendingStats(virtual_timestamp, diff(\n\t\t\tthis->last_pattern,\n\t\t\tthis->at(this->last_load)\n\t\t));\n\n\t\t// last pattern for idle pattern\n\t\tif (this->burst_storage.size() != 0) {\n\t\t\tthis->last_pattern = this->burst_storage.get_burst(this->burst_storage.size()-1);\n\t\t}\n\t}\n\npublic: // Ensure type safety for init_pattern with 2 seperate constructors\n\tBus(std::size_t width, uint64_t datarate, BusIdlePatternSpec idle_pattern, BusInitPatternSpec init_pattern, bool enable = true)\n\t\t: Bus(width, datarate, idle_pattern, convertInitPattern(init_pattern), std::nullopt, enable) {}\n\t\n\tBus(std::size_t width, uint64_t datarate, BusIdlePatternSpec idle_pattern, burst_t custom_init_pattern, bool enable)\n\t\t: Bus(width, datarate, idle_pattern, BusInitPatternSpec_::CUSTOM, custom_init_pattern, enable) {}\n\n\tvoid set_idle_pattern(BusIdlePatternSpec idle_pattern)\n\t{\n\t\tthis->idle_pattern = idle_pattern;\n\t}\n\n\tvoid load(timestamp_t timestamp, const uint8_t * data, std::size_t n_bits) {\n\t\tif (!this->enableflag) {\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t// check timestamp * this->datarate no overflow\n\t\tassert(timestamp <= std::numeric_limits<timestamp_t>::max() / this->datarate);\n\t\tif(timestamp > std::numeric_limits<timestamp_t>::max() / this->datarate)\n\t\t{\n\t\t\tstd::cout << \"[Error] timestamp * datarate overflows\" << std::endl;\n\t\t}\n\t\ttimestamp_t virtual_timestamp = timestamp * this->datarate;\n\n\t\tassert(this->last_load + burst_storage.size() <= virtual_timestamp); // No interleaved commands\n\t\t\n\t\t// Init stats\n\t\tif(!this->init_load && virtual_timestamp == 0) {\n\t\t\t// stats added as pending_stats\n\t\t\tthis->init_load = true;\n\t\t} else if(!this->init_load) {\n\t\t\t// virtual_timestamp > 0\n\t\t\tthis->init_load = true;\n\t\t\tthis->stats += diff(this->last_pattern, this->at(0));\n\t\t}\n\n\t\tadd_previous_stats(virtual_timestamp);\n\t\tthis->last_load = virtual_timestamp;\n\n\t\t// Assumption: A load can only be executed with a virtual_timestamp > last_load + burst_storage.size()\n\t\t// given the assumption the burst_storage can safely be cleared\n\t\tthis->burst_storage.clear();\n\n\t\tadd_data(virtual_timestamp, data, n_bits);\n\t};\n\t\n\tvoid load(timestamp_t timestamp, uint64_t data, std::size_t burst_length) {\n\t\tconst std::size_t n_bits = burst_length * width;\n\t\t\n\t\tassert(n_bits <= std::numeric_limits<uint64_t>::digits); // Ensure data fits in a uint64_t\n\t\t\n\t\tconst std::size_t n_bytes = (n_bits + 7) / 8; // Round up to nearest byte\n\t\tstd::array<uint8_t, 8> bytes;\n\n\t\t// Extract bytes in little-endian order for consistency across platforms\n\t\tfor (std::size_t i = 0; i < n_bytes; ++i) {\n\t\t\tbytes[i] = static_cast<uint8_t>((data >> (i * 8)) & 0xFF);\n\t\t}\n\t\tthis->load(timestamp, bytes.data(), n_bits);\n\t};\n\n\t// Returns optional burst (std::nullopt if idle pattern is Z)\n\tstd::optional<burst_t> at(timestamp_t n) const\n\t{\n\t\t// Assert timestamp does not lie in past\n\t\tassert(n >= last_load);\n\n\t\tif (n - this->last_load >= burst_storage.size()) {\n\t\t\tswitch(this->idle_pattern)\n\t\t\t{\n\t\t\t\tcase BusIdlePatternSpec::L:\n\t\t\t\t\treturn std::make_optional(this->zero_pattern);\n\t\t\t\tcase BusIdlePatternSpec::H:\n\t\t\t\t\treturn std::make_optional(this->one_pattern);\n\t\t\t\tcase BusIdlePatternSpec::Z:\n\t\t\t\t\treturn std::nullopt;\n\t\t\t\tcase BusIdlePatternSpec::LAST_PATTERN:\n\t\t\t\t\treturn this->last_pattern;\n\t\t\t\tdefault:\n\t\t\t\t\tassert(false);\n\t\t\t\t\treturn std::nullopt;\n\t\t\t}\n\t\t}\n\n\t\tauto burst = this->burst_storage.get_burst(std::size_t(n - this->last_load));\n\n\t\treturn std::make_optional(burst);\n\t};\n\n\t// Returns timestamp of last burst not including burst to idle_pattern transition\n\ttimestamp_t get_lastburst_timestamp(bool relative_to_clock = true) const\n\t{\n\t\ttimestamp_t lastburst = this->last_load;\n\t\t// an init load with burst can be checked with the burst_storage size\n\t\t// if there is no init_load the toggles are computed in get_stats\n\t\tif (this->burst_storage.size() != 0) {\n\t\t\t// for each load there is at least one burst\n\t\t\t// get last burst timestamp\n\t\t\tlastburst += this->burst_storage.size();\n\t\t}\n\n\t\t// no burst or pending_stats present -> no load of the bus (last_load == 0)\n\t\tif (relative_to_clock) {\n\t\t\tauto remainder = lastburst % this->datarate;\n\t\t\tif (remainder != 0) {\n\t\t\t\tlastburst += this->datarate - remainder;\n\t\t\t}\n\t\t\treturn lastburst / this->datarate;\n\t\t}\n\t\treturn lastburst;\n\t}\n\n\t// Returns the timestamp when the bus is disabled\n\ttimestamp_t disable(timestamp_t timestamp) {\n\t\t// Already disabled\n\t\tif (!this->enableflag) {\n\t\t\tassert(timestamp * this->datarate >= this->virtual_disable_timestamp);\n\t\t\treturn timestamp;\n\t\t}\n\t\tthis->virtual_disable_timestamp = timestamp * this->datarate;\n\t\tassert(this->virtual_disable_timestamp  >= this->last_load);\n\n\t\t// Init stats\n\t\tif(!this->init_load && this->virtual_disable_timestamp == 0) {\n\t\t\t// tranition from init_pattern cannot be computed\n\t\t\tthis->init_load = true;\n\t\t} else if(!this->init_load) {\n\t\t\t// virtual_disable_timestamp > 0\n\t\t\tthis->init_load = true;\n\t\t\tthis->stats += diff(this->last_pattern, this->at(0));\n\t\t}\n\n\t\tadd_previous_stats(this->virtual_disable_timestamp);\n\t\t// Clear pending stats\n\t\tthis->burst_storage.clear();\n\n\t\tthis->last_load = this->virtual_disable_timestamp;\n\t\tthis->enableflag = false;\n\t\treturn this->virtual_disable_timestamp / this->datarate;\n\t}\n\n\tvoid enable(timestamp_t timestamp) {\n\t\tif (this->enableflag) {\n\t\t\treturn;\n\t\t}\n\t\tassert(timestamp * datarate > this->virtual_disable_timestamp);\n\t\t// Shift the counters to the enabled timestamp\n\t\tthis->last_load = timestamp * this->datarate;\n\t\t// Add pending stats at enable timestamp\n\t\tthis->pending_stats.setPendingStats(this->last_load, this->diff(std::nullopt, this->at(this->last_load)));\n\t\tthis->enableflag = true;\n\t}\n\n\tsize_t get_width() const { return width; };\n\n\t// Get stats not including timestamp t\n\tstats_t get_stats(timestamp_t timestamp) const \n\t{\n\n\t\ttimestamp_t t_virtual = timestamp * this->datarate;\n\t\tassert(t_virtual >= this->last_load);\n\t\t// Return empty stats for t_virtual = 0\n\t\tif(t_virtual == 0)\n\t\t{\n\t\t\treturn this->stats;\n\t\t}\n\n\t\tauto stats = this->stats;\n\n\t\tif(!this->init_load && this->enableflag)\n\t\t{\n\t\t\t// t > 0 and no load on bus\n\t\t\t// only add init_transition if the bus was enabled at t=0\n\t\t\t// Add transition from init pattern to idle pattern\n\t\t\tstats += diff(this->last_pattern, this->at(0));\n\t\t}\n\t\t\n\t\t// Add pending stats from last load\n\t\tif(this->pending_stats.isPending() && this->pending_stats.getTimestamp() < t_virtual)\n\t\t{\n\t\t\tstats += this->pending_stats.getStats();\n\t\t}\n\n\t\t// Advance stats to new timestamp if enabled\n\t\tif (this->enableflag) {\n\t\t\t// stats += burst_storage.count(this->last_load, t_virtual - 1);\n\t\t\tfor (auto n = this->last_load; n < t_virtual - 1; n++) {\n\t\t\t\tstats += diff(this->at(n), this->at(n + 1)); // Last: (timestamp - 2, timestamp - 1)\n\t\t\t}\n\t\t}\n\n\t\treturn stats;\n\t};\n\n\tstats_t diff(std::optional<burst_t> high, std::optional<burst_t> low) const {\n\t\tstats_t stats;\n\t\tif(low.has_value())\n\t\t{\n\t\t\tstats.ones += util::BinaryOps::popcount(low.value());\n\t\t\tstats.zeroes += width - stats.ones;\n\t\t}\n\n\t\tif(high.has_value() && low.has_value())\n\t\t{\n\t\t\tstats.bit_changes += util::BinaryOps::bit_changes(high.value(), low.value());\n\t\t\tstats.ones_to_zeroes += util::BinaryOps::one_to_zeroes(high.value(), low.value());\n\t\t\tstats.zeroes_to_ones += util::BinaryOps::zero_to_ones(high.value(), low.value());\n\t\t}\n\t\treturn stats;\n\t};\n\n\tstats_t diff(std::optional<burst_t> high, burst_t low) const {\n\t\treturn diff(high, std::make_optional(low));\n\t};\n\n\tvoid serialize(std::ostream& stream) const override {\n\t\tthis->stats.serialize(stream);\n\t\tthis->burst_storage.serialize(stream);\n\t\tstream.write(reinterpret_cast<const char*>(&this->last_load), sizeof(this->last_load));\n\t\tstream.write(reinterpret_cast<const char*>(&this->enableflag), sizeof(this->enableflag));\n\t\tstream.write(reinterpret_cast<const char*>(&this->virtual_disable_timestamp), sizeof(this->virtual_disable_timestamp));\n\t\tstream.write(reinterpret_cast<const char*>(&this->init_load), sizeof(this->init_load));\n\t\tthis->pending_stats.serialize(stream);\n\t\tstream.write(reinterpret_cast<const char*>(&this->idle_pattern), sizeof(this->idle_pattern));\n\t\tstream.write(reinterpret_cast<const char*>(&this->init_pattern), sizeof(this->init_pattern));\n\t};\n\n\tvoid deserialize(std::istream& stream) override {\n\t\tthis->stats.deserialize(stream);\n\t\tthis->burst_storage.deserialize(stream);\n\t\tstream.read(reinterpret_cast<char*>(&this->last_load), sizeof(this->last_load));\n\t\tstream.read(reinterpret_cast<char*>(&this->enableflag), sizeof(this->enableflag));\n\t\tstream.read(reinterpret_cast<char*>(&this->virtual_disable_timestamp), sizeof(this->virtual_disable_timestamp));\n\t\tstream.read(reinterpret_cast<char*>(&this->init_load), sizeof(this->init_load));\n\t\tthis->pending_stats.deserialize(stream);\n\t\tstream.read(reinterpret_cast<char*>(&this->idle_pattern), sizeof(this->idle_pattern));\n\t\tstream.read(reinterpret_cast<char*>(&this->init_pattern), sizeof(this->init_pattern));\n\t};\n};\n\n}\n\n#endif /* DRAMPOWER_UTIL_BUS_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/bus_types.h",
    "content": "#ifndef DRAMPOWER_UTIL_BUS_TYPES\n#define DRAMPOWER_UTIL_BUS_TYPES\n\n#include <cstdint>\n\n#include <DRAMPower/util/Serialize.h>\n#include <DRAMPower/util/Deserialize.h>\n\nnamespace DRAMPower::util {\n\nenum class BusIdlePatternSpec\n{\n    L = 0,\n    H = 1,\n    Z = 2,\n    LAST_PATTERN\n};\n\nenum class BusInitPatternSpec\n{\n    L = 0,\n    H = 1,\n    Z = 2,\n};\n\nstruct bus_stats_t :public Serialize, public Deserialize {\n\tuint64_t ones = 0;\n\tuint64_t zeroes = 0;\n\tuint64_t bit_changes = 0;\n\tuint64_t ones_to_zeroes = 0;\n\tuint64_t zeroes_to_ones = 0;\n\n\tbus_stats_t& operator+=(const bus_stats_t& rhs) {\n\t\tthis->bit_changes += rhs.bit_changes;\n\t\tthis->ones += rhs.ones;\n\t\tthis->zeroes += rhs.zeroes;\n\t\tthis->ones_to_zeroes += rhs.ones_to_zeroes;\n\t\tthis->zeroes_to_ones += rhs.zeroes_to_ones;\n\t\treturn *this;\n\t};\n\n\tbus_stats_t& operator*=(const uint64_t rhs) {\n\t\tthis->bit_changes *= rhs;\n\t\tthis->ones *= rhs;\n\t\tthis->zeroes *= rhs;\n\t\tthis->ones_to_zeroes *= rhs;\n\t\tthis->zeroes_to_ones *= rhs;\n\t\treturn *this;\n\t};\n\n\tfriend bus_stats_t operator+(bus_stats_t lhs, const bus_stats_t& rhs) {\n\t\treturn lhs += rhs;\n\t}\n\n\tfriend bus_stats_t operator*(bus_stats_t lhs, const uint64_t rhs) {\n\t\treturn lhs *= rhs;\n\t}\n\n\tfriend bus_stats_t operator*(const uint64_t lhs, bus_stats_t rhs) {\n\t\treturn rhs *= lhs;\n\t}\n\n\tvoid serialize(std::ostream& stream) const override {\n\t\tstream.write(reinterpret_cast<const char*>(&ones), sizeof(ones));\n\t\tstream.write(reinterpret_cast<const char*>(&zeroes), sizeof(zeroes));\n\t\tstream.write(reinterpret_cast<const char*>(&bit_changes), sizeof(bit_changes));\n\t\tstream.write(reinterpret_cast<const char*>(&ones_to_zeroes), sizeof(ones_to_zeroes));\n\t\tstream.write(reinterpret_cast<const char*>(&zeroes_to_ones), sizeof(zeroes_to_ones));\n\t}\n\tvoid deserialize(std::istream& stream) override {\n\t\tstream.read(reinterpret_cast<char*>(&ones), sizeof(ones));\n\t\tstream.read(reinterpret_cast<char*>(&zeroes), sizeof(zeroes));\n\t\tstream.read(reinterpret_cast<char*>(&bit_changes), sizeof(bit_changes));\n\t\tstream.read(reinterpret_cast<char*>(&ones_to_zeroes), sizeof(ones_to_zeroes));\n\t\tstream.read(reinterpret_cast<char*>(&zeroes_to_ones), sizeof(zeroes_to_ones));\n\t}\n\n\t// Operator ==\n\tbool operator==(const bus_stats_t& rhs) const {\n\t\treturn ones == rhs.ones &&\n\t\t       zeroes == rhs.zeroes &&\n\t\t       bit_changes == rhs.bit_changes &&\n\t\t       ones_to_zeroes == rhs.ones_to_zeroes &&\n\t\t       zeroes_to_ones == rhs.zeroes_to_ones;\n\t}\n\t\n};\n\n} // namespace DRAMPower::util\n\n#endif /* DRAMPOWER_UTIL_BUS_TYPES */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/cli_architecture_config.h",
    "content": "#ifndef DRAMPOWER_UTIL_CLI_ARCHITECTURE_CONFIG_H\n#define DRAMPOWER_UTIL_CLI_ARCHITECTURE_CONFIG_H\n\n#include <cstdint>\n\nnamespace DRAMPower::util {\n\nstruct CLIArchitectureConfig {\n    uint64_t deviceCount;\n    uint64_t rankCount;\n    uint64_t bankCount;\n};\n\n};\n\n#endif /* DRAMPOWER_UTIL_CLI_ARCHITECTURE_CONFIG_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/clock.h",
    "content": "#ifndef DRAMPOWER_UTIL_CLOCK_H\n#define DRAMPOWER_UTIL_CLOCK_H\n\n#include <DRAMPower/Types.h>\n#include <DRAMPower/util/bus_types.h>\n#include <DRAMPower/util/Serialize.h>\n#include <DRAMPower/util/Deserialize.h>\n\n#include <optional>\n#include <cassert>\n#include <cstddef>\n\nnamespace DRAMPower::util {\n\nclass Clock : public Serialize, public Deserialize {\npublic:\n    using clock_stats_t = bus_stats_t;\n\nprivate:\n    std::optional<timestamp_t> last_start;\n    clock_stats_t stats;\n    std::size_t dataRate;\n\nprivate:\n    clock_stats_t count(timestamp_t duration) const\n    {\n        // __--__--__--__--__--__--__--__--__--__--__--__--\n        // f(t)\t= t / 2;\n\n        clock_stats_t stats;\n        stats.ones = duration * dataRate / 2;\n        stats.zeroes = duration * dataRate / 2;\n        stats.zeroes_to_ones = duration * dataRate / 2;\n        stats.ones_to_zeroes = duration * dataRate / 2;\n        stats.bit_changes = stats.zeroes_to_ones + stats.ones_to_zeroes;\n        return stats;\n    };\n\npublic:\n    Clock(std::size_t _dataRate = 2, bool stopped = false)\n        : dataRate(_dataRate)\n    {\n        if (stopped)\n            last_start = std::nullopt;\n        else\n            last_start = 0;\n    };\n\npublic:\n    void stop(timestamp_t t)\n    {\n        assert(last_start.has_value());\n        assert(*last_start < t);\n\n        this->stats += count(t - *last_start);\n        last_start.reset();\n    };\n\n    void start(timestamp_t t)\n    {\n        assert(!last_start.has_value());\n        last_start = t;\n    };\n\n    clock_stats_t get_stats_at(timestamp_t t) const\n    {\n        auto stats = this->stats;\n\n        if (last_start) {\n            stats += count(t - *last_start);\n        };\n\n        return stats;\n    };\n\n    void serialize(std::ostream& stream) const override\n    {\n        bool hasLastStart = last_start.has_value();\n        stream.write(reinterpret_cast<const char*>(&hasLastStart), sizeof(hasLastStart));\n        if (hasLastStart) {\n            stream.write(reinterpret_cast<const char*>(&last_start), sizeof(last_start));\n        }\n        stats.serialize(stream);\n    };\n\n    void deserialize(std::istream& stream) override\n    {\n        bool hasLastStart = false;\n        stream.read(reinterpret_cast<char*>(&hasLastStart), sizeof(hasLastStart));\n        if (hasLastStart) {\n            last_start = timestamp_t();\n            stream.read(reinterpret_cast<char*>(&last_start), sizeof(last_start));\n        } else {\n            last_start.reset();\n        }\n        stats.deserialize(stream);\n    };\n};\n\n};\n\n#endif /* DRAMPOWER_UTIL_CLOCK_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/command_counter.h",
    "content": "#ifndef DRAMPOWER_UTIL_COMMAND_COUNTER_H\n#define DRAMPOWER_UTIL_COMMAND_COUNTER_H\n\n#include <vector>\n#include <array>\n#include <cassert>\n\n#include \"DRAMPower/util/Serialize.h\"\n#include \"DRAMPower/util/Deserialize.h\"\n\nnamespace DRAMPower::util\n{\n\ntemplate<typename CommandEnum>\nclass CommandCounter : public Serialize, public Deserialize\n{\npublic:\n\tusing counter_t = std::array<std::size_t, static_cast<std::size_t>(CommandEnum::COUNT)>;\nprivate:\n\tcounter_t counter = {0};\npublic:\n\tCommandCounter() = default;\npublic:\n\tvoid inc(CommandEnum cmd) {\n\t\tassert(counter.size() > static_cast<std::size_t>(cmd));\n\t\tcounter[static_cast<std::size_t>(cmd)] += 1;\n\t};\n\n\tstd::size_t get(CommandEnum cmd) const {\n\t\tassert(counter.size() > static_cast<std::size_t>(cmd));\n\t\treturn counter[static_cast<std::size_t>(cmd)];\n\t};\n\n\tvoid serialize(std::ostream& stream) const override {\n\t\tfor (const auto &count : counter) {\n\t\t\tstream.write(reinterpret_cast<const char *>(&count), sizeof(count));\n\t\t}\n\t}\n\tvoid deserialize(std::istream& stream) override {\n\t\tfor (auto &count : counter) {\n\t\t\tstream.read(reinterpret_cast<char *>(&count), sizeof(count));\n\t\t}\n\t}\n};\n\n}\n\n#endif /* DRAMPOWER_UTIL_COMMAND_COUNTER_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/cycle_stats.h",
    "content": "#ifndef DRAMPOWER_UTIL_CYCLE_STATS_H\n#define DRAMPOWER_UTIL_CYCLE_STATS_H\n\n#include <stdint.h>\n#include <optional>\n\n#include <DRAMPower/util/Serialize.h>\n#include <DRAMPower/util/Deserialize.h>\n\nnamespace DRAMPower::util\n{\n\ntemplate<typename T>\nclass interval_counter : public Serialize, public Deserialize\n{\nprivate:\n\tT count{ 0 };\n\n\tstd::optional<T> start;\n\tstd::optional<T> end;\npublic:\n\tinterval_counter() = default;\n\tinterval_counter(T start) : start(start) {};\n\n\tinterval_counter(const interval_counter<T>&) = default;\n\tinterval_counter& operator=(const interval_counter<T>&) = default;\n\n\tinterval_counter(interval_counter<T>&&) = default;\n\tinterval_counter& operator=(interval_counter<T>&&) = default;\npublic:\n\tT get_start() const { return start.value_or(0); };\n\tT get_end() const { return end.value_or(0); };\npublic:\n\tbool is_open() const { return start && !end; };\n\tbool is_closed() const { return start && end; };\n\n\tT get_count() const { \n\t\treturn count;\n\t};\n\n\tT get_count_at(T timestamp) const { \n\t\tif (is_open() && timestamp > *start)\n\t\t\treturn count + timestamp - *start;\n\n\t\treturn get_count();\n\t}\n\n\tvoid add(T value) {\n\t\tthis->count += value;\n\t};\n\n\tuint64_t close_interval(uint64_t timestamp) { \n\t\tif (!is_open())\n\t\t\treturn T{ 0 };\n\n\t\tend = timestamp;\n\t\tauto diff = timestamp - *start;\n\t\tcount += diff;\n\n\t\treturn diff;\n\t}\n\n\tvoid reset_interval() {\n\t\tthis->start.reset();\n\t\tthis->end.reset();\n\t}\n\n\tvoid start_interval(T start) {\n\t\tthis->start = start;\n\t\tthis->end.reset();\n\t}\n\n\tvoid start_interval_if_not_running(T start) {\n\t\tif(!is_open())\n\t\t\tstart_interval(start);\n\t}\n\n\tvoid serialize(std::ostream& stream) const override  {\n\t\tstream.write(reinterpret_cast<const char *>(&count), sizeof(count));\n\t\tbool starthasValue = start.has_value();\n\t\tstream.write(reinterpret_cast<const char *>(&starthasValue), sizeof(starthasValue));\n\t\tif (starthasValue) {\n\t\t\tstream.write(reinterpret_cast<const char *>(&start), sizeof(start));\n\t\t}\n\t\tbool endhasValue = end.has_value();\n\t\tstream.write(reinterpret_cast<const char *>(&endhasValue), sizeof(endhasValue));\n\t\tif (endhasValue) {\n\t\t\tstream.write(reinterpret_cast<const char *>(&end), sizeof(end));\n\t\t}\n\t}\n\tvoid deserialize(std::istream& stream) override {\n\t\tstream.read(reinterpret_cast<char *>(&count), sizeof(count));\n\t\tbool starthasValue = false;\n\t\tstream.read(reinterpret_cast<char *>(&starthasValue), sizeof(starthasValue));\n\t\tif (starthasValue) {\n\t\t\tstream.read(reinterpret_cast<char *>(&start), sizeof(start));\n\t\t} else {\n\t\t\tstart.reset();\n\t\t}\n\t\tbool endhasValue = false;\n\t\tstream.read(reinterpret_cast<char *>(&endhasValue), sizeof(endhasValue));\n\t\tif (endhasValue) {\n\t\t\tstream.read(reinterpret_cast<char *>(&end), sizeof(end));\n\t\t} else {\n\t\t\tend.reset();\n\t\t}\n\t}\n};\n\n}\n\n#endif /* DRAMPOWER_UTIL_CYCLE_STATS_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/databus.h",
    "content": "#ifndef DRAMPOWER_UTIL_DATABUS\n#define DRAMPOWER_UTIL_DATABUS\n\n#include \"DRAMPower/Exceptions.h\"\n#include \"DRAMPower/util/bus_types.h\"\n#include <cstddef>\n#include <type_traits>\n#include <utility>\n\n\n#include <DRAMPower/util/bus.h>\n#include <DRAMPower/util/databus_types.h>\n#include <DRAMPower/util/databus_types.h>\n#include <DRAMPower/dram/Interface.h>\n#include <DRAMPower/util/Serialize.h>\n#include <DRAMPower/util/Deserialize.h>\n\n#include <DRAMUtils/config/toggling_rate.h>\n#include <DRAMUtils/util/types.h>\n\nnamespace DRAMPower::util {\n\n// DataBus class\ntemplate<std::size_t max_bitset_size = 0>\nclass DataBus : public Serialize, public Deserialize {\n\npublic:\n    using Bus_t = util::Bus<max_bitset_size>;\n    using IdlePattern_t = util::BusIdlePatternSpec;\n    using InitPattern_t = util::BusInitPatternSpec;\n\nstatic constexpr BusIdlePatternSpec convertIdlePattern(const DRAMUtils::Config::TogglingRateIdlePattern idlePattern, bool lastPattern) {\n    using namespace DRAMUtils::Config;\n    if (lastPattern) {\n        return BusIdlePatternSpec::LAST_PATTERN;\n    }\n    switch(idlePattern) {\n        case TogglingRateIdlePattern::L:\n            return BusIdlePatternSpec::L;\n        case TogglingRateIdlePattern::H:\n            return BusIdlePatternSpec::H;\n        case TogglingRateIdlePattern::Z:\n            return BusIdlePatternSpec::Z;\n        case TogglingRateIdlePattern::Invalid:\n            throw Exception(\"Invalid TogglingRateIdlePattern\");\n    }\n    return BusIdlePatternSpec::Z; // Unreachable\n}\n\nstatic constexpr BusInitPatternSpec convertInitPattern(const DRAMUtils::Config::TogglingRateIdlePattern initPattern) {\n    using namespace DRAMUtils::Config;\n    switch(initPattern) {\n        case TogglingRateIdlePattern::L:\n            return BusInitPatternSpec::L;\n        case TogglingRateIdlePattern::H:\n            return BusInitPatternSpec::H;\n        case TogglingRateIdlePattern::Z:\n            return BusInitPatternSpec::Z;\n        case TogglingRateIdlePattern::Invalid:\n            throw Exception(\"Invalid TogglingRateIdlePattern\");\n    }\n    return BusInitPatternSpec::Z; // Unreachable\n}\n\n// BusInitPatternSpec\npublic:\n    DataBus(DataBusConfig&& config, DataBusMode mode, bool IdlelastPatternOverride)\n        : busRead(\n            config.width,\n            config.dataRate,\n            convertIdlePattern(config.toggleRateConf.idlePatternRead, IdlelastPatternOverride),\n            convertInitPattern(config.toggleRateConf.idlePatternRead),\n            DataBusMode::Bus == mode\n        )\n        , busWrite(\n            config.width,\n            config.dataRate,\n            convertIdlePattern(config.toggleRateConf.idlePatternWrite, IdlelastPatternOverride),\n            convertInitPattern(config.toggleRateConf.idlePatternWrite),\n            DataBusMode::Bus == mode\n        )\n        , togglingHandleRead(\n            config.width,\n            config.dataRate,\n            config.toggleRateConf.togglingRateRead,\n            config.toggleRateConf.dutyCycleRead,\n            config.toggleRateConf.idlePatternRead,\n            DataBusMode::TogglingRate == mode\n        )\n        , togglingHandleWrite(\n            config.width,\n            config.dataRate,\n            config.toggleRateConf.togglingRateWrite,\n            config.toggleRateConf.dutyCycleWrite,\n            config.toggleRateConf.idlePatternWrite,\n            DataBusMode::TogglingRate == mode\n        )\n        , busType(mode)\n        , dataRate(config.dataRate)\n        , width(config.width)\n    {}\n\nprivate:\n    void load(Bus_t &bus, TogglingHandle &togglingHandle, timestamp_t timestamp, std::size_t n_bits, const uint8_t *data = nullptr) {\n        switch(busType) {\n            case DataBusMode::Bus: {\n                if (nullptr == data || 0 == n_bits) {\n                    // No data to load, skip burst\n                    return;\n                }\n                bus.load(timestamp, data, n_bits);\n                break;\n            }\n            case DataBusMode::TogglingRate:\n                togglingHandle.incCountBitLength(timestamp, n_bits);\n                break;\n        }\n    }\n\npublic:\n    void loadWrite(timestamp_t timestamp, std::size_t n_bits, const uint8_t *data = nullptr) {\n        load(busWrite, togglingHandleWrite, timestamp, n_bits, data);\n    }\n    void loadRead(timestamp_t timestamp, std::size_t n_bits, const uint8_t *data = nullptr) {\n        load(busRead, togglingHandleRead, timestamp, n_bits, data);\n    }\n\n    void enableBus(timestamp_t timestamp) {\n        busRead.enable(timestamp);\n        busWrite.enable(timestamp);\n        togglingHandleRead.disable(timestamp);\n        togglingHandleWrite.disable(timestamp);\n        busType = DataBusMode::Bus;\n    }\n\n    void enableTogglingRate(timestamp_t timestamp) {\n        busRead.disable(timestamp);\n        busWrite.disable(timestamp);\n        togglingHandleRead.enable(timestamp);\n        togglingHandleWrite.enable(timestamp);\n        busType = DataBusMode::TogglingRate;\n    }\n\n    void setTogglingRateDefinition(DRAMUtils::Config::ToggleRateDefinition toggleratedefinition) {\n        togglingHandleRead.setTogglingRateAndDutyCycle(toggleratedefinition.togglingRateRead, toggleratedefinition.dutyCycleRead, toggleratedefinition.idlePatternRead);\n        togglingHandleWrite.setTogglingRateAndDutyCycle(toggleratedefinition.togglingRateWrite, toggleratedefinition.dutyCycleWrite, toggleratedefinition.idlePatternWrite);\n    }\n\n    timestamp_t lastBurst() const {\n        switch(busType) {\n            case DataBusMode::Bus:\n                return std::max(busWrite.get_lastburst_timestamp(), busRead.get_lastburst_timestamp());\n            case DataBusMode::TogglingRate:\n                return std::max(togglingHandleRead.get_lastburst_timestamp(), togglingHandleWrite.get_lastburst_timestamp());\n        }\n        assert(false);\n        return 0;\n    }\n\n    bool isBus() const {\n        return DataBusMode::Bus == busType;\n    }\n\n    bool isTogglingRate() const {\n        return DataBusMode::TogglingRate == busType;\n    }\n\n    std::size_t getWidth() const {\n        return width;\n    }\n\n    std::size_t getDataRate() const {\n        return dataRate;\n    }\n\n    void get_stats(timestamp_t timestamp,\n        util::bus_stats_t &busReadStats,\n        util::bus_stats_t &busWriteStats,\n        util::bus_stats_t &togglingHandleReadStats,\n        util::bus_stats_t &togglingHandleWriteStats) const\n    {\n        busReadStats += busRead.get_stats(timestamp);\n        busWriteStats += busWrite.get_stats(timestamp);\n        togglingHandleReadStats += togglingHandleRead.get_stats(timestamp);\n        togglingHandleWriteStats += togglingHandleWrite.get_stats(timestamp);\n    }\n\n    void serialize(std::ostream &stream) const override {\n        busRead.serialize(stream);\n        busWrite.serialize(stream);\n        togglingHandleRead.serialize(stream);\n        togglingHandleWrite.serialize(stream);\n        stream.write(reinterpret_cast<const char*>(&busType), sizeof(busType));\n    }\n\n    void deserialize(std::istream &stream) override {\n        busRead.deserialize(stream);\n        busWrite.deserialize(stream);\n        togglingHandleRead.deserialize(stream);\n        togglingHandleWrite.deserialize(stream);\n        stream.read(reinterpret_cast<char*>(&busType), sizeof(busType));\n    }\n\nprivate:\n    Bus_t busRead;\n    Bus_t busWrite;\n    TogglingHandle togglingHandleRead;\n    TogglingHandle togglingHandleWrite;\n    DataBusMode busType;\n    std::size_t dataRate;\n    std::size_t width;\n};\n\n/** DataBusContainer class\n *  This class allows the selection of multiple DataBus types.\n *  The DataBus types are defined in a type_sequence and must be unique.\n *  At least one DataBus type must be defined.\n *  Internally, the DataBusContainer uses a std::variant to store the DataBus types.\n */\ntemplate <typename Seq, typename = void>\nclass DataBusContainer\n{\n    static_assert(DRAMUtils::util::always_false<Seq>::value, \"DataBusContainer cannot be initialized. Check the DataBus type_sequence.\");\n};\n\ntemplate <typename... Ts>\nclass DataBusContainer<DRAMUtils::util::type_sequence<Ts...>,\n    // Types must be unique and the sequence length must be greater than 0\n    std::enable_if_t<DRAMUtils::util::unique_types<Ts...>::value && sizeof...(Ts) != 0>\n> {\n\n// Public type definitions\npublic:\n    using UnifiedVariantSequence_t = DRAMUtils::util::type_sequence<Ts...>;\n    using UnifiedVariant_t = std::variant<Ts...>;\n\n// Internal storage\nprivate:\n    std::size_t m_width;\n    UnifiedVariant_t m_databusVariant;\n    \n// Constructors\npublic:\n    // The constructor is only valid if T is in the valid variant types Ts... / in the type sequence of the variant\n    template <typename T, std::enable_if_t<DRAMUtils::util::is_one_of<std::decay_t<T>, UnifiedVariantSequence_t>::value, int> = 0>\n    explicit DataBusContainer(T&& databus)\n        : m_width(databus.getWidth())\n        , m_databusVariant(std::move(databus))\n    {\n    }\n\n    // No default constructor\n    DataBusContainer() = delete;\n\n// Member functions\npublic:\n    std::size_t getWidth() const {\n        return m_width;\n    }\n\n    UnifiedVariant_t& getVariant() {\n        return m_databusVariant;\n    }\n\n    const UnifiedVariant_t& getVariant() const {\n        return m_databusVariant;\n    }\n\n};\n\ntemplate <typename Seq>\nclass DataBusContainerProxy\n{\n    static_assert(DRAMUtils::util::always_false<Seq>::value, \"DataBusContainerProxy cannot be initialized. Check the DataBus type_sequence.\");\n};\n\ntemplate <typename... Tss>\nclass DataBusContainerProxy<DRAMUtils::util::type_sequence<Tss...>> : public Serialize, public Deserialize\n{\n\n// Public type definitions\npublic:\n    using DataBusContainer_t = DataBusContainer<DRAMUtils::util::type_sequence<Tss...>>;\n\n// Private member variables\nprivate:\n    DataBusContainer_t m_dataBusContainer;\n\npublic:\n// Forwarding constructor\n    template<typename... Args>\n    DataBusContainerProxy(Args&&... args) : m_dataBusContainer(std::forward<Args>(args)...) {}\n\n// Deleted default constructor\n    DataBusContainerProxy() = delete;\n\n// Forwarding member functions\n    void loadWrite(timestamp_t timestamp, std::size_t n_bits, const uint8_t *data = nullptr) {\n        std::visit([timestamp, n_bits, data](auto && arg) {\n            arg.loadWrite(timestamp, n_bits, data);\n        }, m_dataBusContainer.getVariant());\n    }\n\n    void loadRead(timestamp_t timestamp, std::size_t n_bits, const uint8_t *data = nullptr) {\n        std::visit([timestamp, n_bits, data](auto && arg) {\n            arg.loadRead(timestamp, n_bits, data);\n        }, m_dataBusContainer.getVariant());\n    }\n\n    void enableTogglingRate(timestamp_t timestamp) {\n        std::visit([timestamp](auto && arg) {\n            arg.enableTogglingRate(timestamp);\n        }, m_dataBusContainer.getVariant());\n    }\n\n    void enableBus(timestamp_t timestamp) {\n        std::visit([timestamp](auto && arg) {\n            arg.enableBus(timestamp);\n        }, m_dataBusContainer.getVariant());\n    }\n\n    void setTogglingRateDefinition(const DRAMUtils::Config::ToggleRateDefinition &toggleRateDefinition) {\n        std::visit([&toggleRateDefinition](auto && arg) {\n            arg.setTogglingRateDefinition(toggleRateDefinition);\n        }, m_dataBusContainer.getVariant());\n    }\n\n    bool isTogglingRate() const {\n        return std::visit([](auto && arg) {\n            return arg.isTogglingRate();\n        }, m_dataBusContainer.getVariant());\n    }\n\n    bool isBus() const {\n        return std::visit([](auto && arg) {\n            return arg.isBus();\n        }, m_dataBusContainer.getVariant());\n    }\n\n    timestamp_t lastBurst() const {\n        return std::visit([](auto && arg) {\n            return arg.lastBurst();\n        }, m_dataBusContainer.getVariant());\n    }\n\n    std::size_t getWidth() const {\n        return m_dataBusContainer.getWidth();\n    }\n\n    void get_stats(timestamp_t timestamp, util::bus_stats_t &busReadStats, util::bus_stats_t &busWriteStats, util::bus_stats_t &togglingReadState, util::bus_stats_t &togglingWriteState) const {\n        std::visit([timestamp, &busReadStats, &busWriteStats, &togglingReadState, &togglingWriteState](auto && arg) {\n            arg.get_stats(timestamp, busReadStats, busWriteStats, togglingReadState, togglingWriteState);\n        }, m_dataBusContainer.getVariant());\n    }\n\n    void serialize(std::ostream& stream) const override {\n        std::visit([&stream](const auto& arg) {\n            arg.serialize(stream);\n        }, m_dataBusContainer.getVariant());\n    }\n\n    void deserialize(std::istream& stream) override {\n        std::visit([&stream](auto& arg) {\n            arg.deserialize(stream);\n        }, m_dataBusContainer.getVariant());\n    }\n};\n\n} // namespace DRAMPower::util\n\n#endif /* DRAMPOWER_UTIL_DATABUS */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/databus_presets.h",
    "content": "#ifndef DRAMPOWER_UTIL_DATABUS_PRESETS\n#define DRAMPOWER_UTIL_DATABUS_PRESETS\n\n#include \"DRAMPower/util/databus_types.h\"\n#include <optional>\n\n#include <DRAMPower/util/databus.h>\n#include <DRAMUtils/util/types.h>\n\nnamespace DRAMPower::util::databus_presets {\n\n    using databus_64_t = DataBus<64>;\n    using databus_256_t = DataBus<256>;\n    using databus_1024_t = DataBus<1024>;\n    using databus_4096_t = DataBus<4096>;\n\n    using databus_preset_sequence_t = DRAMUtils::util::type_sequence<\n        databus_64_t,\n        databus_256_t,\n        databus_1024_t,\n        databus_4096_t\n    >;\n\n    using databus_preset_t = util::DataBusContainerProxy<databus_preset_sequence_t>;\n\n    inline databus_preset_t getDataBusPreset(\n        DataBusConfig&& busConfig,\n        util::DataBusMode mode,\n        bool IdleLastPatternOverride\n    ) {\n        if (busConfig.width <= 64) {\n            return databus_64_t(std::move(busConfig), mode, IdleLastPatternOverride);\n        } else if (busConfig.width <= 256) {\n            return databus_256_t(std::move(busConfig), mode, IdleLastPatternOverride);\n        } else if (busConfig.width <= 1024) {\n            return databus_1024_t(std::move(busConfig), mode, IdleLastPatternOverride);\n        } else if (busConfig.width > 4096) {\n            assert(false);\n            throw std::runtime_error(\"Data bus width exceeds maximum.\");\n        }\n        return databus_4096_t(std::move(busConfig), mode, IdleLastPatternOverride);\n    }\n\n} // namespace DRAMPower::util::databus_presets\n\n#endif /* DRAMPOWER_UTIL_DATABUS_PRESETS */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/databus_types.h",
    "content": "#ifndef DRAMPOWER_UTIL_DATABUS_TYPES\n#define DRAMPOWER_UTIL_DATABUS_TYPES\n\n#include <cstddef>\n\n#include <DRAMPower/util/bus_types.h>\n\n#include <DRAMUtils/config/toggling_rate.h>\n\n\nnamespace DRAMPower::util {\n\nenum class DataBusMode {\n    Bus = 0,\n    TogglingRate\n};\n\nstruct DataBusConfig {\n    std::size_t width;\n    std::size_t dataRate;\n    DRAMUtils::Config::ToggleRateDefinition toggleRateConf;\n};\n\n} // namespace DRAMPower::util\n\n#endif /* DRAMPOWER_UTIL_DATABUS_TYPES */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/dbi.h",
    "content": "#ifndef DRAMPOWER_UTIL_DBI_H\n#define DRAMPOWER_UTIL_DBI_H\n\n#include \"DRAMPower/Types.h\"\n#include \"DRAMPower/util/pin_types.h\"\n#include \"DRAMPower/util/Serialize.h\"\n#include \"DRAMPower/util/Deserialize.h\"\n\n#include \"DRAMPower/util/dbialgos.h\"\n#include \"DRAMPower/util/dbitypes.h\"\n#include \"DRAMPower/util/dbihelpers.h\"\n\n#include <algorithm>\n#include <bitset>\n#include <climits>\n#include <cstddef>\n#include <cstdint>\n#include <functional>\n#include <optional>\n#include <utility>\n#include <vector>\n#include <cstring>\n#include <cassert>\n#include <tuple>\n#include <type_traits>\n\nnamespace DRAMPower::util {\n\n\n// Valid types for DataType_t are -> integral types f.e. uint8_t, uint16_t, uint32_t or bitset<N>\ntemplate<typename DataType_t, std::size_t SUBCHUNKS, PinState IDLEPATTERN, typename Algorithm>\nclass DBI : public Serialize, public Deserialize {\nstatic_assert(std::is_integral_v<DataType_t> || types::is_bitset_v<DataType_t>, \"DataType_t must be an integral type or a std::bitset.\");\n// Public type definitions\npublic:\n    using Self_t = DBI;\n\n    using DataBuffer_t = std::vector<DataType_t>;\n    using DataBufferIterator_t = typename DataBuffer_t::iterator;\n\n    static constexpr std::size_t DATATYPEDIGITS = types::digit_count_v<DataType_t>;\n    static constexpr std::size_t ChunkSize = SUBCHUNKS * DATATYPEDIGITS;\n\n    // This limitation allows future algorithm improvements\n    static_assert(types::is_contiguous_container_v<DataBuffer_t>, \"DataBuffer_t must contain a buffer with contiguous data.\");\n    static_assert(DATATYPEDIGITS > 0, \"The BufferType must contain at least one digit.\");\n\n    // Algorithm\n    using Algorithm_t = Algorithm;\n    using SelectedAlgorithmType_t = typename Algorithm_t::iterator_type_t;\n    using IteratorType_t = typename IteratorSelector<DBI, SelectedAlgorithmType_t>::type;\n    using AlgorithmPreviousConcat_t = ConcatIterator<IteratorType_t, IteratorType_t>;\n    using AlgorithmPrevious_t = std::tuple<AlgorithmPreviousConcat_t, AlgorithmPreviousConcat_t>;\n    using AlgorithmPreviousOptional_t = std::optional<AlgorithmPrevious_t>;\n\n\n    using State_t = bool; // true for inverted, false for normal\n\n    // Callback signature void(timestamp_t load_time, timestamp_t chunk_time, std::size_t chunk_idx, bool inversion_state, bool read)\n    // chunk_time equals load_time if no bus width is provided. The chunk_idx is then absolute to the beginning of the request\n    using ChangeCallback_t = std::function<void(timestamp_t, timestamp_t, std::size_t, bool, bool)>;\n    \n    using IdlePattern_t = PinState;\n\n// Private type definitions\nprivate:\n    class LastBurst_t : public Serialize, public Deserialize {\n    public:\n        std::size_t beats() const {\n            return m_end - m_start;\n        }\n        std::size_t chunks() const {\n            return m_n_chunks;\n        }\n        std::size_t entries() const {\n            return m_n_chunks * SUBCHUNKS;\n        }\n        timestamp_t end() const {\n            return m_end;\n        }\n        bool isInitialized() const {\n            return m_init;\n        }\n        const std::vector<bool>& getInversionState() const {\n            return m_inversions;\n        }\n        std::vector<bool>& getInversionState() {\n            return m_inversions;\n        }\n\n        void update(timestamp_t timestamp, const std::optional<std::size_t>& m_width, std::size_t m_burstLength, std::size_t n_bits) {\n            m_start = timestamp;\n            if (m_width.has_value()) {\n                m_end = timestamp + (n_bits / m_width.value());\n            } else {\n                m_end = timestamp + m_burstLength;\n            }\n            m_n_chunks = n_bits / ChunkSize;\n            m_init = true;\n        }\n\n        void serialize(std::ostream &stream) const override {\n            stream.write(reinterpret_cast<const char*>(&m_start), sizeof(m_start));\n            stream.write(reinterpret_cast<const char*>(&m_end), sizeof(m_end));\n            stream.write(reinterpret_cast<const char*>(&m_n_chunks), sizeof(m_n_chunks));\n            stream.write(reinterpret_cast<const char*>(&m_n_bits), sizeof(m_n_bits));\n            stream.write(reinterpret_cast<const char*>(&m_init), sizeof(m_init));\n            std::size_t m_inversionsSize = m_inversions.size();\n            stream.write(reinterpret_cast<const char*>(&m_inversionsSize), sizeof(m_inversionsSize));\n            for (const auto& entry : m_inversions) {\n                stream.write(reinterpret_cast<const char*>(&entry), sizeof(entry));\n            }\n            std::size_t m_lastbeatSize = m_lastbeat.size();\n            stream.write(reinterpret_cast<const char*>(&m_lastbeatSize), sizeof(m_lastbeatSize));\n            for (const auto& entry : m_lastbeat) {\n                stream.write(reinterpret_cast<const char*>(&entry), sizeof(entry));\n            }\n        }\n\n        void deserialize(std::istream& stream) override {\n            stream.read(reinterpret_cast<char*>(&m_start), sizeof(m_start));\n            stream.read(reinterpret_cast<char*>(&m_end), sizeof(m_end));\n            stream.read(reinterpret_cast<char*>(&m_n_chunks), sizeof(m_n_chunks));\n            stream.read(reinterpret_cast<char*>(&m_n_bits), sizeof(m_n_bits));\n            stream.read(reinterpret_cast<char*>(&m_init), sizeof(m_init));\n            std::size_t m_inversionsSize;\n            stream.read(reinterpret_cast<char*>(&m_inversionsSize), sizeof(m_inversionsSize));\n            m_inversions.clear();\n            m_inversions.reserve(m_inversionsSize);\n            for (std::size_t i = 0; i < m_inversionsSize; ++i) {\n                bool entry;\n                stream.read(reinterpret_cast<char*>(&entry), sizeof(entry));\n                m_inversions.push_back(entry);\n            }\n            std::size_t m_lastbeatSize;\n            stream.read(reinterpret_cast<char*>(&m_lastbeatSize), sizeof(m_lastbeatSize));\n            m_lastbeat.clear();\n            m_lastbeat.reserve(m_lastbeatSize);\n            for (std::size_t i = 0; i < m_lastbeatSize; ++i) {\n                bool entry;\n                stream.read(reinterpret_cast<char*>(&entry), sizeof(entry));\n                m_lastbeat.push_back(entry);\n            }\n        }\n    public:\n        DataBuffer_t m_lastbeat{};\n        bool m_init = false;\n    private:\n        timestamp_t m_start = 0; // Start timestamp of the last burst\n        timestamp_t m_end = 0; // End timestamp of the last burst\n        std::size_t m_n_chunks = 0;\n        std::size_t m_n_bits = 0;\n        std::vector<bool> m_inversions;\n    };\n\n// Public contructors, destructors and assignment operators\npublic:\n    template<typename T>\n    constexpr std::enable_if_t<std::is_integral_v<T>> set_all_bits(bool ones, T& out_val) const {\n        out_val = ones ? ~T{0} : T{0};\n    }\n\n    template<std::size_t N>\n    constexpr void set_all_bits(bool ones, std::bitset<N>& out_val) const {\n        out_val = ones ? std::bitset<N>{}.set() : std::bitset<N>{};\n    }\n\n    DataBuffer_t getIdlePattern(std::size_t busWidth) const {\n        DataType_t data{};\n        if constexpr (PinState::H == IDLEPATTERN) {\n            set_all_bits(true, data);\n        } else {\n            // (PinState::L == IDLEPATTERN) || (PinState::Z == IDLEPATTERN)\n            set_all_bits(false, data);\n        }\n        // Size: SubChunks per busWidth\n        return DataBuffer_t(static_cast<std::size_t>(busWidth / DATATYPEDIGITS), data);\n    }\n\n    template<typename Func, typename... Args>\n    DBI (std::optional<std::size_t> busWidth, std::size_t burstLength, Func&& func, bool enable, Args&&... args)\n        : m_width(busWidth)\n        , m_burstLength(burstLength)\n        , m_idleData(busWidth.has_value() ? std::optional<DataBuffer_t>{getIdlePattern(busWidth.value())} : std::nullopt)\n        , m_changeCallback(std::forward<Func>(func))\n        , m_enable(enable)\n        , m_algorithm(std::forward<Args>(args)...)\n    {\n        assert(!busWidth.has_value() || (0 == (busWidth.value() % ChunkSize) && \"busWidth must be a multiple of CHUNKSIZE\"));\n    }\n\n// Private member functions\nprivate:\n    void invertChunk(std::size_t chunk_start) {\n        std::size_t subchunk_start = chunk_start * SUBCHUNKS;\n        for (std::size_t subchunk = subchunk_start; subchunk < subchunk_start + SUBCHUNKS; ++subchunk) {\n            m_invertedData[subchunk] = ~m_invertedData[subchunk];\n        }\n    }\n\n// Public member functions\npublic:\n    void enable(bool enable) {\n        m_enable = enable;\n    }\n    bool isEnabled() const {\n        return m_enable;\n    }\n\n    const std::vector<bool>& getInversionStateRead() const {\n        return m_lastBurst_read.getInversionState();\n    }\n    std::size_t getInversionSizeRead() const {\n        return m_lastBurst_read.entries();\n    }\n    const std::vector<bool>& getInversionStateWrite() const {\n        return m_lastBurst_write.getInversionState();\n    }\n    \n    std::size_t getInversionSizeWrite() const {\n        return m_lastBurst_write.entries();\n    }\n\n    std::optional<timestamp_t> getLastBurstEnd(bool read) const {\n        const auto& lastBurst = read ? m_lastBurst_read : m_lastBurst_write;\n        if (lastBurst.isInitialized()) {\n            return read ? m_lastBurst_read.end() : m_lastBurst_write.end();\n        }\n        return std::nullopt;\n    }\n\n    std::optional<std::size_t> getChunksPerWidth() const {\n        return m_width.has_value() ? std::optional<std::size_t>(m_width.value() / ChunkSize) : std::nullopt;\n    }\n\n    IdlePattern_t getIdlePattern() const {\n        return IDLEPATTERN;\n    }\n\n    template<typename Func>\n    void setChangeCallback(Func&& func) {\n        m_changeCallback = std::forward<Func>(func);\n    }\n\n    std::optional<const DataType_t*> updateDBI(timestamp_t timestamp, std::size_t n_bits, const DataType_t* data, bool read) {\n        if (!data || 0 == n_bits || !m_enable || IdlePattern_t::Z == IDLEPATTERN) return std::nullopt;\n\n        // Select read or write members\n        auto &lastInvert = read ? m_lastBurst_read.getInversionState() : m_lastBurst_write.getInversionState();\n        auto &m_lastBurst = read ? m_lastBurst_read : m_lastBurst_write;\n\n        // Reset to Idle Pattern if this burst and the last burst are not seamless\n        dispatchResetCallback(timestamp, read);\n        \n        // Calculate number of bytes needed to store the data\n        assert(0 == (n_bits % DATATYPEDIGITS) && \"n_bits must be a multiple of DATATYPEDIGITS\");\n        std::size_t entries_needed = n_bits / DATATYPEDIGITS;\n\n        // Save lastBeat for seamless Bursts\n        saveLastBurst(timestamp, m_lastBurst);\n\n        // SAFETY: the assigning is necessary so there are no data copies during dbi calculation\n        m_invertedData.assign(data, data + entries_needed);\n\n        // Create previousIterator from last burst\n        auto previous_iterator = createPreviousIterator(timestamp, m_lastBurst);\n\n        // Process each chunk independently\n        assert(n_bits % ChunkSize == 0); // Ensure n_bits is a multiple of chunk size\n        std::size_t n_chunks = n_bits / ChunkSize;\n        \n        // Resize lastInvert vector if needed\n        if (lastInvert.capacity() < n_chunks) {\n            lastInvert.resize(n_chunks, false);\n        }\n        \n        // SAFETY: inverting the chunk while iterating over the data is safe because the invertedData is resized to the maximum size\n        auto invert_visitor = [this, &lastInvert, timestamp, read] (bool invert_chunk, const std::size_t chunk) {\n            dispatchCallback(timestamp, chunk, invert_chunk, read);\n\n            // Update the last inversion state\n            lastInvert[chunk] = invert_chunk;\n\n            // Invert Chunk\n            if (invert_chunk) {\n                invertChunk(chunk);\n            }\n        };\n\n        // Compute DBI\n        m_algorithm.computeDBI(\n            std::make_tuple<IteratorType_t, IteratorType_t>(m_invertedData.begin(), m_invertedData.end()),\n            previous_iterator,\n        IDLEPATTERN, std::move(invert_visitor));\n\n        // Store burst information\n        m_lastBurst.update(timestamp, m_width, m_burstLength, n_bits);\n        lastBurstRead = read;\n        return m_invertedData.data();\n    }\n\n    std::tuple<const uint8_t *, std::size_t> getInvertedData() const {\n        auto &m_lastBurst = lastBurstRead ? m_lastBurst_read : m_lastBurst_write;\n        assert(m_invertedData.size() >= m_lastBurst.chunks() * SUBCHUNKS && \"invalid inverted Data container size\");\n        return std::make_tuple(m_invertedData.data(), m_lastBurst.chunks() * SUBCHUNKS);\n    }\n    \n    inline std::size_t getInvertedDataSize() const {\n        auto &m_lastBurst = lastBurstRead ? m_lastBurst_read : m_lastBurst_write;\n        return m_lastBurst.chunks() * SUBCHUNKS;\n    }\n\n    void dispatchResetCallback(timestamp_t timestamp) {\n        dispatchResetCallback(timestamp, true);\n        dispatchResetCallback(timestamp, false);\n    }\n\n\n    void serialize(std::ostream& stream) const override {\n        stream.write(reinterpret_cast<const char*>(&m_enable), sizeof(m_enable));\n        stream.write(reinterpret_cast<const char*>(&lastBurstRead), sizeof(lastBurstRead));\n\n        m_lastBurst_read.serialize(stream);\n        m_lastBurst_write.serialize(stream);\n\n        std::size_t invertedDataSize = m_invertedData.size();\n        stream.write(reinterpret_cast<const char*>(&invertedDataSize), sizeof(invertedDataSize));\n        for (const auto& byte : m_invertedData) {\n            stream.write(reinterpret_cast<const char*>(&byte), sizeof(byte));\n        }\n    }\n    void deserialize(std::istream& stream) override {\n        stream.read(reinterpret_cast<char*>(&m_enable), sizeof(m_enable));\n        stream.read(reinterpret_cast<char*>(&lastBurstRead), sizeof(lastBurstRead));\n\n        m_lastBurst_read.deserialize(stream);\n        m_lastBurst_write.deserialize(stream);\n\n        std::size_t invertedDataSize;\n        stream.read(reinterpret_cast<char*>(&invertedDataSize), sizeof(invertedDataSize));\n        m_invertedData.clear();\n        m_invertedData.reserve(invertedDataSize);\n        for (std::size_t i = 0; i < invertedDataSize; ++i) {\n            uint8_t byte;\n            stream.read(reinterpret_cast<char*>(&byte), sizeof(byte));\n            m_invertedData.push_back(byte);\n        }\n    }\n\n\n// Private member functions\nprivate:\n    void saveLastBurst(timestamp_t timestamp, LastBurst_t& m_lastBurst) {\n        if (m_lastBurst.m_init && m_lastBurst.end() == timestamp && m_width.has_value() // seamless burst and busWidth provided\n            && m_lastBurst.beats() != 0 && m_invertedData.size() > m_width.value() / DATATYPEDIGITS) // at least one beat is required\n        {\n            assert(0 <= (m_invertedData.size() - (m_width.value() / DATATYPEDIGITS)) && \"Invalid m_invertedData size\");\n            m_lastBurst.m_lastbeat.clear();\n            std::size_t n_subChunks = m_width.value() / DATATYPEDIGITS;\n            m_lastBurst.m_lastbeat.resize(n_subChunks);\n            std::copy(m_invertedData.end() - n_subChunks, m_invertedData.end(), m_lastBurst.m_lastbeat.begin());\n        }\n    }\n\n    AlgorithmPreviousOptional_t createPreviousIterator(timestamp_t timestamp, LastBurst_t& m_lastBurst) {\n        if (m_lastBurst.m_init && m_lastBurst.end() == timestamp && m_width.has_value() // seamless burst and busWidth provided\n            && m_lastBurst.beats() != 0 && m_invertedData.size() > m_width.value() / DATATYPEDIGITS) // at least one beat is required\n        {\n            assert(0 <= (m_invertedData.size() - (m_width.value() / DATATYPEDIGITS)) && \"Invalid m_invertedData size\");\n            // Create concat iterator of lastburst and current burst\n            return std::make_optional<AlgorithmPrevious_t>(std::make_tuple<AlgorithmPreviousConcat_t, AlgorithmPreviousConcat_t>(\n                AlgorithmPreviousConcat_t{m_lastBurst.m_lastbeat.begin(), m_lastBurst.m_lastbeat.end(), m_invertedData.begin()},\n                AlgorithmPreviousConcat_t{m_lastBurst.m_lastbeat.end(), m_lastBurst.m_lastbeat.end(), m_invertedData.end() - m_width.value() / DATATYPEDIGITS}\n            ));\n        } else if (m_width.has_value() && m_idleData.has_value()) {\n            assert(0 <= (m_invertedData.size() - (m_width.value() / DATATYPEDIGITS)) && \"Invalid m_invertedData size\");\n            // Create concat iterator of idleData and current burst\n            return std::make_optional<AlgorithmPrevious_t>(std::make_tuple<AlgorithmPreviousConcat_t, AlgorithmPreviousConcat_t>(\n                AlgorithmPreviousConcat_t{m_idleData.value().begin(), m_idleData.value().end(), m_invertedData.begin()},\n                AlgorithmPreviousConcat_t{m_idleData.value().end(), m_idleData.value().end(), m_invertedData.end() - m_width.value() / DATATYPEDIGITS}\n            ));\n        } else {\n            return std::nullopt;\n        }\n    }\n\n    void dispatchCallback(timestamp_t timestamp, std::size_t chunk, bool invert_chunk, bool read) {\n        std::optional<std::size_t> chunks_per_width = getChunksPerWidth();\n        if (nullptr != m_changeCallback) {\n            if (!chunks_per_width.has_value()) {\n                m_changeCallback(timestamp, timestamp, chunk, invert_chunk, read);\n            } else {\n                std::size_t beat_idx = chunk % chunks_per_width.value();\n                timestamp_t t = timestamp + (chunk / chunks_per_width.value());\n                m_changeCallback(timestamp, t, beat_idx, invert_chunk, read);\n            }\n        }\n    }\n\n    void dispatchResetCallback(timestamp_t timestamp, bool read) {\n        const auto &m_lastBurst = read ? m_lastBurst_read : m_lastBurst_write;\n        auto &lastInvert = read ? m_lastBurst_read.getInversionState() : m_lastBurst_write.getInversionState();\n         // Ensure there is at least one chunk in the last inversion\n        assert(!m_lastBurst.m_init || (!getChunksPerWidth().has_value() || m_lastBurst.chunks() >= getChunksPerWidth().value()));\n        if (!m_lastBurst.m_init) {\n            return;\n        } else if (timestamp < m_lastBurst.end()) {\n            // previous burst present and timestamp is before the last burst end\n            return;\n        } else if (m_lastBurst.end() == timestamp) {\n            // Seamless burst\n            // if new burstlength is smaller then last burstlength not all pins are reset for a seamless burst in absolute chunk mode (m_width not set)\n            // In absolute mode the callback is called for every chunk\n            return;\n        }\n\n        // The last burst is initialized\n        //    and no seamleass burst\n        //    and timestamp >= m_lastBurst.end\n\n        // Dispatch callback for the inversion back to the idle pattern\n        if (nullptr != m_changeCallback) {\n            timestamp_t t = m_lastBurst.end();\n            if (getChunksPerWidth().has_value()) {\n                // First timestamp after the last chunk\n                std::size_t start = m_lastBurst.chunks() - getChunksPerWidth().value();\n                // Loop over the chunks/dbi_pins in the last pattern\n                for (std::size_t chunk = start; chunk < m_lastBurst.chunks(); ++chunk) {\n                    std::size_t chunk_idx = chunk % getChunksPerWidth().value(); // Pin index\n                    if (lastInvert[chunk]) {\n                        // Reset the inversion state\n                        m_changeCallback(timestamp, t, chunk_idx, false, read);\n                    }\n                    // Reset the inversion state for next pin updates\n                    lastInvert[chunk] = false;\n                }\n            } else {\n                // TODO split the callbacks in dedicated update / reset callbacks?\n                // no bus width is defined. The dbi executes in absolute chunk mode.\n                // The number of dbi pins cannot be calculated\n                // Looping over all chunks of the lastBurst\n                for (std::size_t chunk = 0; chunk < m_lastBurst.chunks(); chunk++) {\n                    if (lastInvert[chunk]) {\n                        m_changeCallback(timestamp, t, chunk, false, read);\n                    }\n                    // Reset the inversion state for next updates\n                    lastInvert[chunk] = false;\n                }\n            }\n        }\n    }\n\n\n// Private member variables\nprivate:\n\n    std::optional<std::size_t> m_width = std::nullopt; // Width of the complete bus\n    std::size_t m_burstLength = 0; // Width of the complete bus\n\n    bool lastBurstRead = false;\n    LastBurst_t m_lastBurst_read;  // Last burst end timestamp\n    LastBurst_t m_lastBurst_write; // Last burst end timestamp\n\n    DataBuffer_t m_invertedData; // Buffer for inverted data\n    std::optional<DataBuffer_t> m_idleData; // Buffer for idle data\n\n    ChangeCallback_t m_changeCallback = nullptr; // Callback called in updateDBI\n    bool m_enable = false;\n    Algorithm_t m_algorithm;\n};\n\n} // namespace DRAMPower::util\n\n#endif /* DRAMPOWER_UTIL_DBI_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/dbialgos.h",
    "content": "#ifndef DRAMPOWER_UTIL_DBIALGOS_H\n#define DRAMPOWER_UTIL_DBIALGOS_H\n\n#include \"DRAMPower/util/dbihelpers.h\"\n#include \"DRAMPower/util/binary_ops.h\"\n#include \"DRAMPower/util/pin_types.h\"\n\n#include \"DRAMUtils/util/types.h\"\n\n#include <optional>\n\n\nnamespace DRAMPower::util {\n\n// Iterator selector for algorithms\nstruct AlgorithmIteratorType_SubChunk {};\n\n// Iterator selector for dbi class\ntemplate<typename DBI, typename AlgorithmType>\nstruct IteratorSelector {\n    static_assert(DRAMUtils::util::always_false<AlgorithmType>::value, \"No matching Iterator found for AlgorithmType.\");\n};\ntemplate<typename DBI>\nstruct IteratorSelector<DBI, AlgorithmIteratorType_SubChunk> {\n    using type = SubChunkView<typename DBI::DataBufferIterator_t, DBI::ChunkSize>;\n};\n\n// Algorithms\nstruct StaticDBI {\n\n    using iterator_type_t = AlgorithmIteratorType_SubChunk;\n\n    template <typename Iterator1, typename Iterator2, typename InvertCallbackFunctor>\n    static void computeDBI(std::tuple<Iterator1, Iterator1> current,\n        std::optional<std::tuple<Iterator2, Iterator2>>,\n        PinState idlePattern,\n        InvertCallbackFunctor&& invert_callback\n    ) {\n        auto [cur_it, cur_end] = current;\n\n        std::size_t ones = 0;\n        std::size_t zeros = 0;\n        for (; cur_it != cur_end; ++cur_it) {\n            auto chunk_value = *cur_it;\n            ones += BinaryOps::popcount(chunk_value);\n            zeros += cur_it.getDigits() - BinaryOps::popcount(chunk_value);\n            if (cur_it.last()) {\n                const bool invert =\n                    (idlePattern == PinState::L && zeros < ones) ||\n                    (idlePattern == PinState::H && ones < zeros);\n                std::forward<InvertCallbackFunctor>(invert_callback)(invert, cur_it.getTotalChunkIdx());\n                ones = 0;\n                zeros = 0;\n            }\n        }\n    }\n\n};\n\ntemplate <std::size_t threshold>\nstruct DynamicDBI {\n\n    using iterator_type_t = AlgorithmIteratorType_SubChunk;\n\n    template <typename Iterator1, typename Iterator2, typename InvertCallbackFunctor>\n    static void computeDBI(std::tuple<Iterator1, Iterator1> current,\n        std::optional<std::tuple<Iterator2, Iterator2>> previous,\n        PinState,\n        InvertCallbackFunctor&& invert_callback\n    ) {\n        auto [cur_it, cur_end] = current;\n\n        if (!previous) {\n            // No previous burst -> cannot compute transitions\n            for (; cur_it != cur_end; ++cur_it) {\n                std::forward<InvertCallbackFunctor>(invert_callback)(\n                    false, cur_it.getTotalChunkIdx());\n            }\n        } else {\n            auto [prev_it, prev_end] = *previous;\n            std::size_t costnormal = 0;\n            for (; cur_it != cur_end; ++cur_it, ++prev_it) {\n\n                // normal transition cost\n                costnormal +=\n                    BinaryOps::popcount(*cur_it ^ *prev_it);\n\n                if (cur_it.last()) {\n                    const bool invert = costnormal > threshold;\n                    std::forward<InvertCallbackFunctor>(invert_callback)(\n                        invert, cur_it.getTotalChunkIdx());\n                    costnormal = 0;\n                }\n            }\n        }\n    }\n};\n\n} // namespace DRAMPower::util\n\n#endif /* DRAMPOWER_UTIL_DBIALGOS_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/dbihelpers.h",
    "content": "#ifndef DRAMPOWER_UTIL_DBIHELPERS_H\n#define DRAMPOWER_UTIL_DBIHELPERS_H\n\n#include <type_traits>\n#include <bitset>\n#include \"DRAMPower/util/dbitypes.h\"\n\nnamespace DRAMPower::util {\n\n\ntemplate<typename It1, typename It2>\nclass ConcatIterator\n{\npublic:\n    using value_type        = std::common_type_t<\n        typename std::iterator_traits<It1>::value_type,\n        typename std::iterator_traits<It2>::value_type>;\n\n    using reference         = std::common_type_t<\n        typename std::iterator_traits<It1>::reference,\n        typename std::iterator_traits<It2>::reference>;\n\n    using iterator_category = std::input_iterator_tag;\n\n    ConcatIterator(It1 cur1, It1 end1, It2 cur2)\n        : m_it1(cur1), m_end1(end1), m_it2(cur2) {}\n\n    reference operator*() const\n    {\n        return (m_it1 != m_end1) ? *m_it1 : *m_it2;\n    }\n\n    ConcatIterator& operator++()\n    {\n        if (m_it1 != m_end1) {\n            ++m_it1;\n        } else {\n            ++m_it2;\n        }\n        return *this;\n    }\n\n    bool operator==(const ConcatIterator& other) const\n    {\n        return (m_it1 == other.m_it1) && (m_it2 == other.m_it2) && (m_end1 == other.m_end1);\n    }\n\n    bool operator!=(const ConcatIterator& other) const\n    {\n        return !(*this == other);\n    }\n\nprivate:\n    It1 m_it1;\n    It1 m_end1;\n    It2 m_it2;\n};\n\n/** SubChunkView\n* SubChunkView is a iterator_value class for iterating over the chunks in a burst if\n* the bus width is a multiple of the chunk size. The class itself provides\n*/\ntemplate <typename iterator, std::size_t CHUNKSIZE>\nclass SubChunkView {\n// Public type definitions, constructors, member functions\npublic:\n\n    using parent_iterator_value_type = typename iterator::value_type;\n\n    using iterator_category = std::input_iterator_tag;\n    using value_type = typename iterator::value_type;\n    using difference_type = typename iterator::difference_type;\n    using pointer = typename iterator::pointer;\n    using reference = typename iterator::reference;\n\n    static constexpr std::size_t DATATYPEDIGITS = types::digit_count_v<parent_iterator_value_type>;\n    static_assert(DATATYPEDIGITS > 0, \"The BufferType must contain at least one digit\");\n    static_assert(std::is_integral_v<parent_iterator_value_type> || std::is_same_v<parent_iterator_value_type, std::bitset<CHUNKSIZE>>, \"Parent iterator value type must be an integral type or a std::bitset of the chunk size\");\n    static_assert(0 == (CHUNKSIZE % DATATYPEDIGITS), \"CHUNKSIZE must be a multiple of DATATYPEDIGITS.\");\n    static_assert(CHUNKSIZE >= DATATYPEDIGITS, \"CHUNKSIZE must be greater or equal to DATATYPEDIGITS\");\n\n    static constexpr std::size_t COUNT_DATA = CHUNKSIZE / DATATYPEDIGITS;\n\nprivate:\n    SubChunkView(iterator it, std::size_t current_chunk_idx, std::size_t current_data_idx)\n        : m_it(it)\n        , m_current_chunk_idx(current_chunk_idx)\n        , m_current_data_idx(current_data_idx)\n    {}\n\npublic:\n    SubChunkView(iterator it)\n        : SubChunkView{it, 0, 0}\n    {}\n\npublic:\n\n    SubChunkView& operator++() {\n        m_current_data_idx++;\n        m_it++;\n        if (m_current_data_idx >= COUNT_DATA) {\n            m_current_data_idx = 0;\n            m_current_chunk_idx++;\n        }\n        return *this;\n    }\n\n    SubChunkView operator++(int) {\n        SubChunkView tmp = *this;\n        ++(*this);\n        return tmp;\n    }\n\n    inline const std::size_t& getDataIdx() const {\n        return m_current_data_idx;\n    }\n    inline std::size_t getTotalChunkIdx() const {\n        return m_current_chunk_idx;\n    }\n\n    inline bool last() const {\n        return 0 == (m_current_data_idx % COUNT_DATA);\n    }\n\n    inline static constexpr std::size_t getDataTotal() {\n        return COUNT_DATA;\n    }\n    inline static constexpr std::size_t getDigits() {\n        return DATATYPEDIGITS;\n    }\n\n    bool operator==(const SubChunkView& other) const noexcept {\n        return (m_it == other.m_it);\n    }\n\n    bool operator!=(const SubChunkView& other) const noexcept {\n        return !(*this == other);\n    }\n\n    decltype(auto) operator*() const {\n        return *m_it;\n    }\n\n// Private members\nprivate:\n    iterator m_it;\n    std::size_t m_current_chunk_idx = 0;\n    std::size_t m_current_data_idx = 0;\n};\n\n} // namespace DRAMPower::util\n\n#endif /* DRAMPOWER_UTIL_DBIHELPERS_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/dbitypes.h",
    "content": "#ifndef DRAMPOWER_UTIL_DBI_TYPES_H\n#define DRAMPOWER_UTIL_DBI_TYPES_H\n\n#include <type_traits>\n#include <limits>\n#include <vector>\n#include <array>\n#include <bitset>\n\nnamespace DRAMPower::util::types {\n\n\n// contiguous containers\n// non contiguous container fallback\ntemplate <typename T>\nstruct is_contiguous_container : std::false_type {};\n// std::vector specialization\ntemplate <typename T, typename Alloc>\nstruct is_contiguous_container<std::vector<T, Alloc>> : std::true_type {};\n// std::array specialization\ntemplate <typename T, typename std::size_t N>\nstruct is_contiguous_container<std::array<T, N>> : std::true_type {};\n// std::string specialization\ntemplate <typename CharT, typename Traits, typename Alloc>\nstruct is_contiguous_container<std::basic_string<CharT, Traits, Alloc>> : std::true_type {};\n// value shortcut\ntemplate <typename T>\ninline constexpr bool is_contiguous_container_v = is_contiguous_container<T>::value;\n\n// is_bitset\n// no bitset fallback\ntemplate<typename _Tp>\nstruct is_bitset : std::false_type{};\n// std::bitset specialization\ntemplate <std::size_t N>\nstruct is_bitset<std::bitset<N>> : std::true_type {};\n// value shortcut\ntemplate<typename _Tp>\ninline constexpr bool is_bitset_v = is_bitset<_Tp>::value;\n\n// digit_count\n// std::numeric_limits<T> fallback\ntemplate <typename T>\nstruct digit_count {\n    static constexpr std::size_t value = std::numeric_limits<T>::digits;\n};\n// std::bitset specialization\ntemplate <std::size_t N>\nstruct digit_count<std::bitset<N>> {\n    static constexpr std::size_t value = N;\n};\n// value shortcut\ntemplate <typename T>\nconstexpr std::size_t digit_count_v = digit_count<T>::value;\n\n\n} // namespace DRAMPower::util::types\n\n#endif /* DRAMPOWER_UTIL_DBI_TYPES_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/dynamic_bitset.h",
    "content": "#ifndef DRAMPOWER_UTIL_DYNAMIC_BITSET_H\n#define DRAMPOWER_UTIL_DYNAMIC_BITSET_H\n\n#include <DRAMPower/Types.h>\n\n#include <optional>\n#include <bitset>\n#include <vector>\n#include <cmath>\n#include <cstdint>\n#include <cassert>\n#include <bitset>\n#include <type_traits>\n\nnamespace DRAMPower::util\n{\n\ntemplate <std::size_t blocksize>\nclass dynamic_bitset\n{\npublic:\n    using buffer_element_t = std::bitset<blocksize>;\n    using buffer_t = std::vector<buffer_element_t>;\nprivate:\n    std::size_t num_bits = 0;\n    std::bitset<blocksize> lastelementmask;\n    buffer_t buffer;\npublic:\n    explicit dynamic_bitset(std::size_t num_bits)\n    : num_bits(num_bits)\n    , buffer(static_cast<std::size_t>((0 != num_bits % blocksize) ? ((num_bits / blocksize) + 1) : (num_bits / blocksize)), 0)\n    {\n        makeLastElementMask();\n    }\n    explicit dynamic_bitset(std::size_t num_bits, uint64_t value)\n        : num_bits(num_bits)\n        , buffer(static_cast<std::size_t>((0 != num_bits % blocksize) ? ((num_bits / blocksize) + 1) : (num_bits / blocksize)))\n    {\n        uint64_t accumulator = 1;\n        for (std::size_t bit_index = 0; bit_index < num_bits; ++bit_index) {\n            buffer[bit_index / blocksize][bit_index % blocksize] = value & accumulator;\n            accumulator <<= 1;\n        }\n        lastelementmask = std::bitset<blocksize>(0);\n        for (std::size_t i = 0; i < num_bits % blocksize; ++i) {\n            lastelementmask.set(i);\n        }\n    }\n    dynamic_bitset() = default;\npublic:\n    dynamic_bitset(const dynamic_bitset&) = default;\n    dynamic_bitset(dynamic_bitset&&) noexcept = default;\n\n    dynamic_bitset& operator=(const dynamic_bitset&) = default;\n    dynamic_bitset& operator=(dynamic_bitset&&) noexcept = default;\npublic:\n    inline void makeLastElementMask() {\n        lastelementmask.reset();\n        for (std::size_t i = 0; i < num_bits % blocksize; ++i) {\n            lastelementmask.set(i);\n        }\n    }\n    inline std::size_t size() const { return num_bits; };\n    std::size_t count() const {\n        std::size_t n = 0;\n        // Iterate over all block including the last block which can be smaller than the block_size\n        std::size_t i_blocks = blocksize;\n        for (auto &element : buffer) {\n            if (i_blocks > num_bits) {\n                n += (element & lastelementmask).count();\n            } else {\n                n += element.count();\n            } \n            i_blocks += blocksize;\n        }\n        return n;\n    }\npublic: // element manipulation\n    void push_back(bool bit) {\n        if (num_bits % blocksize == 0) {\n            // New entry\n            buffer.push_back(buffer_element_t{0});\n        }\n        buffer.back().set(num_bits % blocksize, bit);\n        num_bits++;\n        makeLastElementMask();\n    }\n    void set(std::size_t n, bool value) {\n        buffer.at(n / blocksize).set(n % blocksize, value);\n    }\n    void set() {\n        for (auto &element : buffer) {\n            element.set();\n        }\n    }\n    void reset() {\n        for (auto &element : buffer) {\n            element.reset();\n        }\n    }\n    void flip() {\n        for (auto &element : buffer) {\n            element.flip();\n        }\n    }\n    void flip(std::size_t n) {\n        buffer.at(n / blocksize).flip(n % blocksize);\n    }\n    void clear() {\n        buffer.clear();\n        num_bits = 0;\n    }\npublic: // element access\n    // inline auto at(std::size_t n) -> decltype(buffer.at(n)) { return buffer.at(n); }\n    // inline auto at(std::size_t n) -> decltype(buffer.at(n)) const { return buffer.at(n); }\npublic:\n    inline auto operator[](std::size_t n) { return buffer.at(n / blocksize).test(n % blocksize); };\n    inline auto operator[](std::size_t n) const { return buffer.at(n / blocksize).test(n % blocksize); };\npublic: // comparison operations\n    template <std::size_t blocksize_rhs, std::enable_if_t<blocksize == blocksize_rhs, int> = 0>\n    bool operator==(const dynamic_bitset<blocksize_rhs>& rhs) const {\n        if (this->size() != rhs.size()) {\n            return false;\n        }\n    \n        for (std::size_t i = 0; i < this->buffer.size(); ++i) {\n            if (buffer.at(i) != rhs.buffer.at(i)) {\n                return false;\n            }\n        }\n    \n        return true;\n    }\n    template <std::size_t blocksize_rhs, std::enable_if_t<blocksize != blocksize_rhs, int> = 0>\n    bool operator==(const dynamic_bitset<blocksize_rhs>& rhs) const {\n        if (this->size() != rhs.size()) {\n            return false;\n        }\n    \n        for (std::size_t i = 0; i < this->size(); ++i) {\n            if (this->operator[](i) != rhs[i]) {\n                return false;\n            }\n        }\n    \n        return true;\n    }\n    template <std::size_t blocksize_rhs>\n    bool operator!=(const dynamic_bitset<blocksize_rhs>& rhs) const {\n        return !(*this == rhs);\n    }\n    bool operator==(unsigned long rhs) const {\n        return *this == dynamic_bitset<blocksize> { this->size(), rhs };\n    }\n    bool operator!=(unsigned long rhs) const {\n        return !(*this == rhs);\n    }\npublic: // bitset operations\n    dynamic_bitset operator~() const {\n        auto bitset = *this;\n    \n        for (std::size_t i = 0; i < this->buffer.size(); ++i) {\n            bitset.buffer.at(i) = ~buffer.at(i);\n        };\n    \n        return bitset;\n    }\n    dynamic_bitset& operator^=(const dynamic_bitset& rhs) {\n        assert(this->size() == rhs.size());\n    \n        for (std::size_t i = 0; i < this->buffer.size(); ++i) {\n            buffer.at(i) = buffer.at(i) ^ rhs.buffer.at(i);\n        };\n    \n        return *this;\n    }\n    dynamic_bitset& operator&=(const dynamic_bitset& rhs) {\n        assert(this->size() == rhs.size());\n    \n        for (std::size_t i = 0; i < this->buffer.size(); ++i) {\n            buffer.at(i) &= rhs.buffer.at(i);\n        };\n    \n        return *this;\n    }\n    dynamic_bitset& operator|=(const dynamic_bitset& rhs) {\n        assert(this->size() == rhs.size());\n    \n        for (std::size_t i = 0; i < this->buffer.size(); ++i) {\n            buffer.at(i) |= rhs.buffer.at(i);\n        };\n    \n        return *this;\n    }\npublic:\n};\n\ntemplate<std::size_t blocksize>\ninline dynamic_bitset<blocksize> operator^(dynamic_bitset<blocksize> lhs, const dynamic_bitset<blocksize>& rhs) { return lhs ^= rhs; };\ntemplate<std::size_t blocksize>\ninline dynamic_bitset<blocksize> operator&(dynamic_bitset<blocksize> lhs, const dynamic_bitset<blocksize>& rhs) { return lhs &= rhs; };\ntemplate<std::size_t blocksize>\ninline dynamic_bitset<blocksize> operator|(dynamic_bitset<blocksize> lhs, const dynamic_bitset<blocksize>& rhs) { return lhs |= rhs; };\n\n} // namespace DRAMPower::util\n\n#endif /* DRAMPOWER_UTIL_DYNAMIC_BITSET_H */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/extension_base.h",
    "content": "#ifndef DRAMPOWER_UTIL_EXTENSION_BASE\n#define DRAMPOWER_UTIL_EXTENSION_BASE\n\nnamespace DRAMPower::util::extension_manager {\n\n// dynamic extension base\nclass Extension {\npublic:\n    Extension() = default;\n    virtual ~Extension() = default;\n};\n\n// dynamic extension with hooks\ntemplate <typename Hooks>\nclass ExtensionWithHooks : public Extension {\npublic:\n    using Extension::Extension;\n\n    // Return supported hooks\n    virtual Hooks getSupportedHooks() const = 0;\n};\n\n} // namespace DRAMPower::util::extension_manager\n\n#endif /* DRAMPOWER_UTIL_EXTENSION_BASE */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/extension_manager.h",
    "content": "#ifndef DRAMPOWER_UTIL_EXTENSION_MANAGER\n#define DRAMPOWER_UTIL_EXTENSION_MANAGER\n\n#include \"DRAMPower/util/Serialize.h\"\n#include <cstddef>\n#include <unordered_map>\n#include <typeindex>\n#include <memory>\n#include <type_traits>\n#include <utility>\n#include <vector>\n#include <limits>\n#include <cassert>\n#include <iostream>\n\n#include <DRAMPower/util/extension_base.h>\n#include <DRAMPower/util/Serialize.h>\n#include <DRAMPower/util/Deserialize.h>\n#include <DRAMPower/Exceptions.h>\n\n#include <DRAMUtils/util/types.h>\n\nnamespace DRAMPower::util::extension_manager {\n\n// Helper function to count trailing zeros in an integral type\ntemplate <typename T>\nconstexpr int countZeros(T value) {\n    static_assert(std::is_integral_v<T>, \"countZeros only works with integral types\");\n    if (value == 0) return std::numeric_limits<T>::digits;\n\n    int count = 0;\n    constexpr T one = 1;\n    while ((value & one) == 0) {\n        count++;\n        value >>= 1;\n    }\n    return count;\n}\n\n// dynamic extension manager\n// BaseExtension class is used for type erasure\ntemplate <typename BaseExtension>\nclass ExtensionManager : public util::Serialize, public util::Deserialize {\nprivate:\n// Type definitions\n    using Extension_storage_t = std::unordered_map<std::type_index, std::shared_ptr<BaseExtension>>;\n    using Serialize_storage_t = std::vector<std::weak_ptr<BaseExtension>>;\n\n// Member variables\n    Extension_storage_t m_extensions;\n    Serialize_storage_t m_serStorage; // The std::vector guarantees the order of the Extensions\n\n// Asserts\n    static_assert(std::is_base_of_v<util::Serialize, BaseExtension>, \"BaseExtension must derive from util::Serialize\");\n    static_assert(std::is_base_of_v<util::Deserialize, BaseExtension>, \"BaseExtension must derive from util::Deserialize\");\n\nprotected:\n// Protected member functions\n    template <typename T, typename... Args>\n    decltype(auto) registerExtension_impl(Args&&... args) {\n        static_assert(std::is_base_of_v<BaseExtension, T>,\n            \"T must derive from BaseExtension\");\n\n        auto ext = std::make_shared<T>(std::forward<Args>(args)...);\n        auto typeIndex = std::type_index(typeid(T));\n        m_extensions[typeIndex] = ext;\n        m_serStorage.emplace_back(ext);\n        return ext;\n    }\n\npublic:\n// Constructor\n    ExtensionManager() = default;\n\n// Public member functions\n    // Register an extension, forwarding any additional arguments.\n    template <typename T, typename... Args>\n    void registerExtension(Args&&... args) {\n        registerExtension_impl<T>(std::forward<Args>(args)...);\n    }\n\n    // Retrieve an extension (returns an empty weak_ptr if not found)\n    template <typename T>\n    std::weak_ptr<T> getExtension() {\n        static_assert(std::is_base_of_v<BaseExtension, T>,\n            \"T must derive from BaseExtension\");\n        if (m_extensions.empty()) {\n            return std::weak_ptr<T>{};\n        }\n        auto it = m_extensions.find(std::type_index(typeid(T)));\n        if (it != m_extensions.end()) {\n            return std::static_pointer_cast<T>(it->second);\n        }\n        return std::weak_ptr<T>{};\n    }\n\n    // Check if an extension is registered\n    template <typename T>\n    bool hasExtension() const {\n        static_assert(std::is_base_of_v<BaseExtension, T>,\n            \"T must derive from BaseExtension\");\n        if (m_extensions.empty()) {\n            return false;\n        }\n        return m_extensions.find(std::type_index(typeid(T))) != m_extensions.end();\n    }\n\n    // Visitor pattern for extensions\n    template <typename T, typename Func>\n    void withExtension(Func&& func) {\n        static_assert(std::is_base_of_v<BaseExtension, T>,\n            \"T must derive from BaseExtension\");\n        if (!m_extensions.empty()) {\n            auto it = m_extensions.find(std::type_index(typeid(T)));\n            if (it != m_extensions.end()) {\n                std::forward<Func>(func)(*std::static_pointer_cast<T>(it->second));\n            }\n        }\n    }\n\n    void serialize(std::ostream& stream) const override {\n        for (const auto& wp : m_serStorage) {\n            if(auto sp = wp.lock()) {\n                sp->serialize(stream);\n            } else {\n                throw Exception(\"Empty shared_pointer in ExtensionManager is not allowed\");\n            }\n        }\n    };\n    void deserialize(std::istream& stream) override {\n        for (auto& wp : m_serStorage) {\n            if (auto sp = wp.lock()) {\n                sp->deserialize(stream);\n            } else {\n                throw Exception(\"Empty shared_pointer in ExtensionManager is not allowed\");\n            }\n        }\n    }\n};\n\ntemplate <typename BaseExtension, typename Hooks, typename enable = void>\nclass ExtensionManagerWithHooks : ExtensionManager<BaseExtension> {\n    static_assert(DRAMUtils::util::always_false<BaseExtension>::value,\n        \"BaseExtension must inherit from ExtensionWithHooks<Hooks>\"\n    );\n};\ntemplate <typename BaseExtension, typename Hooks>\nclass ExtensionManagerWithHooks<\n    BaseExtension,\n    Hooks,\n    std::enable_if_t<std::is_base_of_v<ExtensionWithHooks<Hooks>, BaseExtension>>\n>\n: public ExtensionManager<BaseExtension> {\nprivate:\n// Type definitions\n    using Hooks_t = Hooks;\n    using HookValue_t = std::underlying_type_t<Hooks_t>;\n    using HookCache_t = std::vector<std::vector<std::shared_ptr<BaseExtension>>>;\n\n// Member variables\n    constexpr static std::size_t m_numHooks = std::numeric_limits<HookValue_t>::digits;\n    HookCache_t m_hookCache;\n\n// Private member functions\n    static constexpr std::size_t getHookPosition(Hooks_t hook) {\n        return countZeros(static_cast<HookValue_t>(hook));\n    }\n\n    void initializeHooks() {\n        if (m_hookCache.empty()) {\n            m_hookCache.resize(m_numHooks);\n        }\n    }\n\n    void updateHookCache(std::shared_ptr<BaseExtension>&& extension) {\n        // dynamic cast used for additional type safety\n        auto hookExt = std::dynamic_pointer_cast<ExtensionWithHooks<Hooks>>(extension);\n        if (!hookExt) return; // dynamic_cast checked in std::enable_if_t\n\n        const HookValue_t supportedHooks = static_cast<HookValue_t>(hookExt->getSupportedHooks());\n        for (std::size_t i = 0; i < m_hookCache.size(); ++i) {\n            if ((supportedHooks & (1 << i)) != 0) {\n                m_hookCache[i].push_back(extension);\n            }\n        }\n    }\n\npublic:\n// Constructor\n    ExtensionManagerWithHooks() {\n        initializeHooks();\n    }\n\n// Public member functions\n    // Register an extension, forwarding any additional arguments.\n    template <typename T, typename... Args>\n    void registerExtension(Args&&... args) {\n        updateHookCache(this->template registerExtension_impl<T>(std::forward<Args>(args)...));\n    }\n\n    // Call the hook function for all registered extensions supporting the hook\n    template<typename Func>\n    void callHook(Hooks_t hook, Func&& func) {\n        const std::size_t bitPosition = getHookPosition(hook);\n        if (bitPosition < 0 || bitPosition >= m_hookCache.size()) {\n            return; // Invalid hook\n        }\n\n        for (const auto& extension_ptr : m_hookCache[bitPosition]) {\n            std::forward<Func>(func)(*extension_ptr);\n        }\n    }\n\n};\n\n} // namespace DRAMPower::util::extension_manager\n\n#endif /* DRAMPOWER_UTIL_EXTENSION_MANAGER */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/extension_manager_static.h",
    "content": "#ifndef DRAMPOWER_UTIL_EXTENSION_MANAGER_STATIC\n#define DRAMPOWER_UTIL_EXTENSION_MANAGER_STATIC\n\n#include <cstddef>\n#include <unordered_map>\n#include <typeindex>\n#include <memory>\n#include <tuple>\n#include <type_traits>\n#include <utility>\n#include <functional>\n#include <vector>\n#include <stdint.h>\n\n#include <DRAMUtils/util/types.h>\n\nnamespace DRAMPower::util::extension_manager_static {\n\n// Helpers\nnamespace detail {\n    template <typename Func, typename Ext>\n    constexpr auto tryCallFunctor(Func&& func, Ext& ext) -> decltype(std::forward<Func>(func)(ext)) {\n        if constexpr (std::is_invocable_v<Func, Ext&>) {\n            return std::forward<Func>(func)(ext);\n        } else {\n            // If the function is not invocable, do nothing\n            return;\n        }\n    }\n\n    template <typename Ext, typename FuncTuple, std::size_t... Is>\n    constexpr void callHookIfSupportedImpl(Ext& extension, FuncTuple&& funcTuple, std::index_sequence<Is...>) {\n        (detail::tryCallFunctor(std::get<Is>(std::forward<FuncTuple>(funcTuple)), extension), ...);\n    }\n} // namespace detail\n\n/** static extensionmanager\n * Template arguments:\n * - Parent: Parent type of the type which holds the StaticExtensionManager\n * - Seq: DRAMUtils::util::type_sequence of the StaticExtensions\n * - Hook: enum for retrieving the extensions supporting the given hook in callHook\n */ \ntemplate <typename Seq, typename Hook>\nclass StaticExtensionManager{\n    static_assert(DRAMUtils::util::always_false<Seq>::value, \"Cannot construct StaticExtensionManager.\");\n};\ntemplate <typename Hook, typename... StaticExtensions>\nclass StaticExtensionManager<DRAMUtils::util::type_sequence<StaticExtensions...>, Hook> {\nprivate:\n// Type definitions\n    using Extension_type_sequence_t = DRAMUtils::util::type_sequence<StaticExtensions...>;\n    using Extension_tuple_t = std::tuple<StaticExtensions...>;\n    using Extension_index_sequence_t = std::index_sequence_for<StaticExtensions...>;\n    using Hook_t = Hook;\n    using Hook_value_t = std::underlying_type_t<Hook>;\n// Constexpr helpers\n    constexpr static std::size_t m_numExtensions = sizeof...(StaticExtensions);\n// Members\n    Extension_tuple_t m_extensions;\n\nprivate:\n// Private member functions\n    template <Hook_t hook, typename FuncTuple, std::size_t... Is>\n    constexpr void callHookImpl(FuncTuple&& funcTuple, std::index_sequence<Is...>) {\n        // use index_sequence to loop over callHookIfSupported\n        // example: callHookIfSupported<0>(...), callHookIfSupported<1>(...), ...\n        if constexpr (sizeof...(Is) > 0) {\n            (callHookIfSupported<hook, Is>(std::forward<FuncTuple>(funcTuple)), ...);\n        }/* else {\n            // Prevent \"unused parameter\" warning\n            (void) hook;\n            (void) func;\n        }*/\n    }\n\n    template <Hook_t hook, std::size_t I, typename FuncTuple>\n    constexpr void callHookIfSupported(FuncTuple&& funcTuple) {\n        // Use index from callHookImpl to get the tuple elementtype to query for the supported hooks\n        using ExtensionType = std::tuple_element_t<I, Extension_tuple_t>;\n        constexpr Hook_t supportedHooks = ExtensionType::getSupportedHooks();\n        if constexpr ((static_cast<Hook_value_t>(supportedHooks) & static_cast<Hook_value_t>(hook)) != 0) {\n            // retrieve the extension from the tuple and call the functor if the extension is supported\n            auto& extension = std::get<I>(m_extensions);\n            detail::callHookIfSupportedImpl(extension, std::forward<FuncTuple>(funcTuple),\n                std::make_index_sequence<std::tuple_size_v<std::decay_t<FuncTuple>>>{});\n        }\n    }\n\n    \n\npublic:\n// Constructor\n    StaticExtensionManager()\n    : m_extensions(StaticExtensions{}...)\n    {}\n// Public member functions\n    template <Hook_t hook, typename... Func>\n    constexpr void callHook(Func&&... funcs) {\n        using FuncTuple = std::tuple<Func...>;\n        // Explicit functor copy to ensure memory safety\n        FuncTuple funcTuple{std::forward<Func>(funcs)...};\n        if constexpr (sizeof...(Func) > 0) {\n            // Call Hook implementation with integer sequence of length sizeof...(StaticExtensions)\n            callHookImpl<hook>(std::move(funcTuple), Extension_index_sequence_t{});\n        }\n    }\n\n    // has extension\n    template <typename T>\n    constexpr static bool hasExtension() {\n        return DRAMUtils::util::is_one_of<T, Extension_type_sequence_t>::value;\n    }\n\n    // get extension reference\n    template <typename T>\n    constexpr T& getExtension() {\n        static_assert(hasExtension<T>(), \"Extension not found\");\n        return std::get<T>(m_extensions);\n    }\n    // get extension reference\n    template <typename T>\n    constexpr const T& getExtension() const {\n        static_assert(hasExtension<T>(), \"Extension not found\");\n        return std::get<T>(m_extensions);\n    }\n\n    // visitor\n    template <typename Extension, typename Func>\n    constexpr decltype(auto) withExtension(Func&& func) {\n        static_assert(hasExtension<Extension>(), \"Extension not found\");\n        return std::forward<Func>(func)(getExtension<Extension>());\n    }\n};\n\n} // namespace DRAMPower::util::extension_manager_static\n\n#endif /* DRAMPOWER_UTIL_EXTENSION_MANAGER_STATIC */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/extensions.cpp",
    "content": "#include <DRAMPower/util/extensions.h>\n#include <DRAMPower/command/Command.h>\n\nnamespace DRAMPower::extensions {\n\nusing namespace DRAMPower::util;\n\nbool DBI::enable(timestamp_t timestamp, bool enable) {\n    bool result = true;\n    // Dispatch callback if set\n    if (m_callback) {\n        result = (*m_callback)(timestamp, enable);\n    }\n    if (result) {\n        // Update member\n        m_enabled = enable;\n    }\n    return result;\n}\n\nbool DBI::isEnabled() const {\n    return m_enabled;\n}\n\nvoid DBI::serialize(std::ostream& stream) const {\n    stream.write(reinterpret_cast<const char*>(&m_enabled), sizeof(m_enabled));\n}\nvoid DBI::deserialize(std::istream& stream) {\n    stream.read(reinterpret_cast<char*>(&m_enabled), sizeof(m_enabled));\n}\n\n} // namespace DRAMPower::extensions"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/extensions.h",
    "content": "#ifndef DRAMPOWER_UTIL_EXTENSIONS\n#define DRAMPOWER_UTIL_EXTENSIONS\n\n#include <DRAMPower/command/Command.h>\n#include <DRAMPower/util/extension_base.h>\n#include <DRAMPower/util/databus_presets.h>\n#include <DRAMPower/Types.h>\n#include <DRAMPower/util/Serialize.h>\n#include <DRAMPower/util/Deserialize.h>\n\n#include <functional>\n#include <optional>\n\nnamespace DRAMPower::extensions {\n\nclass Base : public util::Serialize, public util::Deserialize {\nprotected:\n    // Protected constructor to prevent instantiation of Base class\n    Base() = default;\n\n    Base(const Base&) = default;\n    Base(Base&&) = default;\n    Base& operator=(const Base&) = default;\n    Base& operator=(Base&&) = default;\n\npublic:\n    virtual ~Base() = default;\n};\n\nclass DBI : public Base {\n\n// Public type definitions\npublic:\n    using enable_callback_t = std::function<bool(const timestamp_t, const bool)>;\n    using timestamp_t = DRAMPower::timestamp_t;\n\n// Constructors\npublic:\n    template<typename Func>\n    explicit DBI(Func&& callback, bool initstate)\n    : m_enabled(initstate)\n    , m_callback(std::forward<Func>(callback))\n    {}\n\n// Public member functions\npublic:\n    bool enable(timestamp_t timestamp, bool enable);\n    bool isEnabled() const;\n\n// Overrides\npublic:\n    void serialize(std::ostream& stream) const override;\n    void deserialize(std::istream& stream) override;\n\n// Private member variables\nprivate:\n    bool m_enabled = false;\n    std::optional<enable_callback_t> m_callback;\n};\n\n} // namespace DRAMPower::extensions\n\n#endif /* DRAMPOWER_UTIL_EXTENSIONS */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/pending_stats.h",
    "content": "#ifndef DRAMPOWER_UTIL_PENDING_STATS\n#define DRAMPOWER_UTIL_PENDING_STATS\n\n#include <DRAMPower/Types.h>\n#include <DRAMPower/util/bus_types.h>\n\n#include <DRAMPower/util/Serialize.h>\n#include <DRAMPower/util/Deserialize.h>\n\nnamespace DRAMPower::util\n{\n\ntemplate <typename T = bus_stats_t>\nclass PendingStats\n{\n// Constructor, assignment operator and destructor\npublic:\n    PendingStats()\n    : m_timestamp(0)\n    , m_stats()\n    , m_pending(false)\n    {}\n    ~PendingStats() = default;\n\n    PendingStats(const PendingStats&) = default;\n    PendingStats& operator=(const PendingStats&) = default;\n    PendingStats(PendingStats&&) = default;\n    PendingStats& operator=(PendingStats&&) = default;\n\n// Public member functions\npublic:\n    void setPendingStats(timestamp_t timestamp, T stats)\n    {\n        m_timestamp = timestamp;\n        m_stats = stats;\n        m_pending = true;\n    }\n    \n    bool isPending() const\n    {\n        return m_pending;\n    }\n\n    void clear()\n    {\n        m_pending = false;\n    }\n    \n    timestamp_t getTimestamp() const\n    {\n        return m_timestamp;\n    }\n    \n    T getStats() const\n    {\n        return m_stats;\n    }\n\n    void serialize(std::ostream& stream) const\n    {\n        stream.write(reinterpret_cast<const char*>(&m_timestamp), sizeof(m_timestamp));\n        m_stats.serialize(stream);\n        stream.write(reinterpret_cast<const char*>(&m_pending), sizeof(m_pending));\n    }\n    void deserialize(std::istream& stream)\n    {\n        stream.read(reinterpret_cast<char*>(&m_timestamp), sizeof(m_timestamp));\n        m_stats.deserialize(stream);\n        stream.read(reinterpret_cast<char*>(&m_pending), sizeof(m_pending));\n    }\n\n// Private member variables\nprivate:\n    timestamp_t m_timestamp;\n    T           m_stats;\n    bool        m_pending;\n};\n\n} // namespace DRAMPower::util\n\n#endif /* DRAMPOWER_UTIL_PENDING_STATS */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/pin.h",
    "content": "#ifndef DRAMPOWER_UTIL_PINH\n#define DRAMPOWER_UTIL_PINH\n\n#include <DRAMPower/util/burst_storage.h>\n#include <DRAMPower/Types.h>\n#include <DRAMPower/util/bus_types.h>\n#include <DRAMPower/util/pin_types.h>\n#include <DRAMPower/util/pending_stats.h>\n#include <DRAMPower/util/Serialize.h>\n#include <DRAMPower/util/Deserialize.h>\n\n#include <cassert>\n#include <cstddef>\n\nnamespace DRAMPower::util {\n\nstruct PinPendingStats : public Serialize, public Deserialize {\n    PinState fromstate;\n    PinState newstate;\n\n    PinPendingStats() = default;\n    PinPendingStats(PinState from, PinState to) : fromstate(from), newstate(to) {}\n\n    void serialize(std::ostream &stream) const override {\n        stream.write(reinterpret_cast<const char *>(&fromstate), sizeof(fromstate));\n        stream.write(reinterpret_cast<const char *>(&newstate), sizeof(newstate));\n    }\n    void deserialize(std::istream &stream) override {\n        stream.read(reinterpret_cast<char *>(&fromstate), sizeof(fromstate));\n        stream.read(reinterpret_cast<char *>(&newstate), sizeof(newstate));\n    }\n};\n\nstruct PinTempChange {\n    timestamp_t change_time;\n    PinState state;\n};\n\ntemplate<std::size_t max_burst_length>\nclass Pin : public Serialize, public Deserialize {\n// Public type definitions\npublic:\n    using pin_stats_t = bus_stats_t;\n    using burst_storage_t = util::burst_storage<util::BitsetContainer<max_burst_length>>;\n    using burst_t = typename burst_storage_t::burst_t;\n\n// Constructor\npublic:\n    explicit Pin(PinState initstate, PinState idlestate)\n        : m_last_state(initstate)\n        , m_idle_state(idlestate)\n    {}\n\n// Private member functions\nprivate:\n    void addPendingStats(timestamp_t t, PendingStats<PinPendingStats> pending_stats, pin_stats_t &stats) const {\n        // add stats from last load stored in pending_stats\n        if (pending_stats.isPending() && pending_stats.getTimestamp() < t) {\n            stats += getPinChangeStats(pending_stats.getStats().fromstate, pending_stats.getStats().newstate);\n        }\n    }\n\n    void addPendingStats(timestamp_t t, timestamp_t pending_t, PinState to, PinState from, pin_stats_t &stats) const {\n        auto pending_change = PendingStats<PinPendingStats>{};\n        pending_change.setPendingStats(pending_t, {\n            from, // from\n            to    // to\n        });\n        addPendingStats(t, pending_change, stats);\n    }\n\n   [[nodiscard]] pin_stats_t getPinChangeStats(const PinState &fromState, const PinState &newState) const {\n        pin_stats_t stats;\n        // Add pin change stats\n        if (newState != fromState) {\n            // L to H or H to L result in bit changes\n            // X to Z or Z to X are not counted\n            if (fromState == PinState::L && newState == PinState::H) {\n                stats.bit_changes++;\n                stats.zeroes_to_ones++;\n            } else if (fromState == PinState::H && newState == PinState::L) {\n                stats.bit_changes++;\n                stats.ones_to_zeroes++;\n            }\n        }\n        return stats;\n    }\n\n    void count(timestamp_t end, timestamp_t start, const PinState& state, pin_stats_t &stats) const {\n        if (end <= start) {\n            return;\n        }\n\n        // Burst Storage\n        if (m_burst_storage.endTime() > start) { // TODO\n            stats += m_burst_storage.count(start, end);\n            // Adjust start for idle counting\n            start = m_burst_storage.endTime();\n            // Transitions last burst to idle_pattern\n            if (end > start) {\n                burst_t lastburst = m_burst_storage.get_burst(0);\n                stats += getPinChangeStats(lastburst ? PinState::H : PinState::L, state);\n            }\n        }\n\n        // Add duration of state\n        if (end > start) {\n            switch (state) {\n                case PinState::L:\n                    stats.zeroes += end - start;\n                    break;\n                case PinState::H:\n                    stats.ones += end - start;\n                    break;\n                case PinState::Z:\n                    // Nothing to do\n                    break;\n            }\n        }\n    }\n    void set_internal(timestamp_t t, std::size_t dataRate, PendingStats<PinPendingStats> pending_stats, pin_stats_t &stats) const {\n        // Check if change is needed\n        // if (m_last_state == state) {\n        //     return;\n        // }\n        timestamp_t virtual_time = t * dataRate;\n        assert(virtual_time >= m_last_set);\n\n        // Count init transition\n        if (m_init_load && (0 < virtual_time)) {\n            stats += getPinChangeStats(m_last_state, m_idle_state);\n        }\n\n        // count stats\n        addPendingStats(virtual_time, pending_stats, stats);\n        count(virtual_time, m_last_set, m_idle_state, stats);\n    }\n\n// Public member functions\npublic:\n    // The timestamp t is relative to the clock frequency\n    void set(timestamp_t load_time, PinState state, std::size_t dataRate = 1) {\n        timestamp_t virtual_load_time  = load_time * dataRate;\n\n        // Count stats to virtual_load_time\n        set_internal(virtual_load_time, dataRate, m_pending_stats, m_stats);\n        if (m_pending_stats.isPending() && m_pending_stats.getTimestamp() < virtual_load_time) {\n            m_pending_stats.clear();\n        }\n\n\n        if ((m_last_set != virtual_load_time) || m_init_load) {\n            // New Burst\n            const PinState& laststate =  [this, virtual_load_time](){\n                if ((virtual_load_time == m_last_set + m_burst_storage.size())\n                    || (m_init_load && (0 == virtual_load_time))) {\n                    // seamless or first load\n                    return m_last_state;\n                }\n                return m_idle_state;\n            }();\n            m_pending_stats.setPendingStats(virtual_load_time, {\n                laststate, // From state\n                state // New state\n            });\n        }\n        m_burst_storage.push_back(virtual_load_time, PinState::H == state);\n\n        m_last_set = virtual_load_time;\n        m_last_state = state;\n        m_init_load = false;\n    }\n\n    // The timestamp t is relative to the clock frequency\n    [[nodiscard]] pin_stats_t get_stats_at(timestamp_t t, std::size_t dataRate = 1) const {\n        timestamp_t virtual_time = t * dataRate;\n        assert(virtual_time >= m_last_set);\n        if (virtual_time == m_last_set) {\n            return m_stats;\n        }\n        // virtual_time > m_last_set\n\n    \n        // Add stats from m_last_set to t\n        auto stats = m_stats;\n\n        // Init stats\n        if (m_init_load && (0 < virtual_time)) {\n            stats += getPinChangeStats(m_last_state, m_idle_state);\n        }\n\n        addPendingStats(virtual_time, m_pending_stats, stats);\n        count(virtual_time, m_last_set, m_idle_state, stats);\n        return stats;\n    }\n\n\n// Overrides\npublic:\n    void serialize(std::ostream &stream) const override  {\n        stream.write(reinterpret_cast<const char *>(&m_last_state), sizeof(m_last_state));\n        stream.write(reinterpret_cast<const char *>(&m_last_set), sizeof(m_last_set));\n        stream.write(reinterpret_cast<const char *>(&m_init_load), sizeof(m_init_load));\n        m_burst_storage.serialize(stream);\n        m_pending_stats.serialize(stream);\n        m_stats.serialize(stream);\n    }\n    void deserialize(std::istream &stream) override  {\n        stream.read(reinterpret_cast<char *>(&m_last_state), sizeof(m_last_state));\n        stream.read(reinterpret_cast<char *>(&m_last_set), sizeof(m_last_set));\n        stream.read(reinterpret_cast<char *>(&m_init_load), sizeof(m_init_load));\n        m_burst_storage.deserialize(stream);\n        m_pending_stats.deserialize(stream);\n        m_stats.deserialize(stream);\n    }\n\n// Private member variables\nprivate:\n    PendingStats<PinPendingStats> m_pending_stats;\n\n    pin_stats_t m_stats;\n\n    PinState m_last_state = PinState::Z;\n    const PinState m_idle_state = PinState::L;\n\n    bool m_init_load = true;\n\n    timestamp_t m_last_set = 0;\n    burst_storage_t m_burst_storage{};\n\n};\n\n};\n\n#endif /* DRAMPOWER_UTIL_PINH */"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/pin_types.h",
    "content": "#ifndef DRAMPOWER_UTIL_PIN_TYPES\n#define DRAMPOWER_UTIL_PIN_TYPES\n\nnamespace DRAMPower::util {\n\nenum class PinState\n{\n    L = 0,\n    H = 1,\n    Z = 2,\n};\n\n} // namespace DRAMPower::util\n\n#endif /* DRAMPOWER_UTIL_PIN_TYPES */\n"
  },
  {
    "path": "src/DRAMPower/DRAMPower/util/sub_bitset.h",
    "content": "#ifndef DRAMPOWER_UTIL_SUB_BITSET\n#define DRAMPOWER_UTIL_SUB_BITSET\n\n#include <DRAMPower/Types.h>\n\n#include <bitset>\n#include <cmath>\n#include <cassert>\n#include <bitset>\n#include <stdexcept>\n\nnamespace DRAMPower::util\n{\n\ntemplate <std::size_t max_width>\nclass sub_bitset\n{\npublic:\n    using buffer_t = std::bitset<max_width>;\nprivate:\n    std::size_t width = 0;\n    buffer_t buffer;\n    buffer_t mask;\npublic:\n    explicit sub_bitset(std::size_t width)\n    : width(width)\n    , buffer(0)\n    {\n        assert(width <= max_width);\n        if (width > max_width) {\n            throw std::out_of_range(\"Width exceeds maximum width\");\n        }\n        makeMask();\n    }\n    explicit sub_bitset(std::size_t width, uint64_t value)\n        : width(width)\n        , buffer(0)\n    {\n        assert(width <= max_width);\n        if (width > max_width) {\n            throw std::out_of_range(\"Width exceeds maximum width\");\n        }\n        uint64_t accumulator = 1;\n        for (std::size_t bit_index = 0; bit_index < width; ++bit_index) {\n            buffer.set(bit_index, value & accumulator);\n            accumulator <<= 1;\n        }\n        makeMask();\n    }\n    sub_bitset() = default; // width is 0\npublic:\n    sub_bitset(const sub_bitset&) = default;\n    sub_bitset(sub_bitset&&) noexcept = default;\n\n    sub_bitset& operator=(const sub_bitset&) = default;\n    sub_bitset& operator=(sub_bitset&&) noexcept = default;\npublic:\n    inline void makeMask() {\n        mask.reset();\n        for (std::size_t i = 0; i < width; ++i) {\n            mask.set(i);\n        }\n    }\n    inline std::size_t size() const { return width; };\n    inline std::size_t count() const {\n        return buffer.count();\n    }\npublic:\n    inline void set(std::size_t n, bool value) {\n        assert(n < width);\n        if (n >= width) {\n            throw std::out_of_range(\"Index out of range\");\n        }\n        buffer.set(n, value);\n    }\n    inline void set() {\n        buffer.set();\n        buffer &= mask;\n    }\n    inline void reset() {\n        buffer.reset();\n    }\n    inline void flip() {\n        buffer.flip();\n        buffer &= mask;\n    }\n    inline void flip(std::size_t n) {\n        assert(n < width);\n        if (n >= width) {\n            throw std::out_of_range(\"Index out of range\");\n        }\n        buffer.flip(n);\n    }\npublic:\n    inline auto operator[](std::size_t n) { \n        assert(n < width);\n        if (n >= width) {\n            throw std::out_of_range(\"Index out of range\");\n        }\n        return buffer.test(n);\n    }\n    inline auto operator[](std::size_t n) const {\n        assert(n < width);\n        if (n >= width) {\n            throw std::out_of_range(\"Index out of range\");\n        }\n        return buffer.test(n);\n    }\npublic:\n    template <std::size_t max_width_rhs>\n    bool operator==(const sub_bitset<max_width_rhs>& rhs) const {\n        if (this->size() != rhs.size()) {\n            return false;\n        }\n        return buffer == rhs.buffer;\n    }\n    template <std::size_t max_width_rhs>\n    bool operator!=(const sub_bitset<max_width_rhs>& rhs) const {\n        return !(*this == rhs);\n    }\n    bool operator==(unsigned long rhs) const {\n        return *this == sub_bitset<max_width> { this->size(), rhs };\n    }\n    bool operator!=(unsigned long rhs) const {\n        return !(*this == rhs);\n    }\npublic: // bitset operations\n    sub_bitset operator~() const {\n        auto result = *this;\n        result.buffer = ~buffer;\n        result.buffer &= mask;\n        return result;\n    }\n    template <std::size_t max_width_rhs>\n    auto& operator^=(const sub_bitset<max_width_rhs>& rhs) {\n        assert(this->size() == rhs.size());\n        buffer ^= rhs.buffer;\n        buffer &= mask;\n        return *this;\n    }\n    template <std::size_t max_width_rhs>\n    auto& operator&=(const sub_bitset<max_width_rhs>& rhs) {\n        assert(this->size() == rhs.size());\n        buffer &= rhs.buffer;\n        return *this;\n    }\n    template <std::size_t max_width_rhs>\n    auto& operator|=(const sub_bitset<max_width_rhs>& rhs) {\n        assert(this->size() == rhs.size());\n        buffer |= rhs.buffer;\n        buffer &= mask;\n        return *this;\n    }\npublic:\n};\n\ntemplate<std::size_t max_width>\ninline sub_bitset<max_width> operator^(sub_bitset<max_width> lhs, const sub_bitset<max_width>& rhs) { return lhs ^= rhs; };\ntemplate<std::size_t max_width>\ninline sub_bitset<max_width> operator&(sub_bitset<max_width> lhs, const sub_bitset<max_width>& rhs) { return lhs &= rhs; };\ntemplate<std::size_t max_width>\ninline sub_bitset<max_width> operator|(sub_bitset<max_width> lhs, const sub_bitset<max_width>& rhs) { return lhs |= rhs; };\n\n} // namespace DRAMPower::util\n\n#endif /* DRAMPOWER_UTIL_SUB_BITSET */\n"
  },
  {
    "path": "src/cli/CMakeLists.txt",
    "content": "\nif (DRAMPOWER_BUILD_CLI)\n    add_subdirectory(main)\nendif()\nif (DRAMPOWER_BUILD_CLI OR DRAMPOWER_BUILD_BENCHMARKS)\n    add_subdirectory(lib)\nendif()\n"
  },
  {
    "path": "src/cli/lib/CMakeLists.txt",
    "content": "###############################\n###         cli_lib         ###\n###############################\n\nfind_package(spdlog REQUIRED)\n\nadd_library(cli_lib \n    DRAMPower/cli/run.cpp\n    DRAMPower/cli/util.cpp\n)\n\ntarget_include_directories(cli_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})\n\ntarget_compile_features(cli_lib PUBLIC cxx_std_17)\nset_target_properties(cli_lib PROPERTIES CXX_EXTENSIONS OFF)\nset_target_properties(cli_lib PROPERTIES CXX_STANDARD_REQUIRED ON)\n\ntarget_link_libraries(cli_lib \nPUBLIC\n    DRAMPower::DRAMPower\n    DRAMUtils::DRAMUtils\n    spdlog::spdlog\n)\n\ntarget_compile_definitions(cli_lib PRIVATE DRAMPOWER_VERSION_STRING=\"${DRAMPOWER_VERSION_STRING}\")\nadd_library(DRAMPower::cli_lib ALIAS cli_lib)"
  },
  {
    "path": "src/cli/lib/DRAMPower/cli/config.h",
    "content": "#ifndef CLI_CONFIG_H\n#define CLI_CONFIG_H\n\n#include <DRAMUtils/util/json.h>\n#include <DRAMUtils/util/json_utils.h>\n\n#include <DRAMPower/simconfig/simconfig.h>\n\nnamespace DRAMPower::DRAMPowerCLI::config {\n\nstruct CLIConfig {\n    bool useToggleRate;\n    DRAMPower::config::SimConfig simconfig;\n};\n\nNLOHMANN_JSONIFY_ALL_THINGS(CLIConfig, useToggleRate, simconfig)\n\n} // namespace DRAMPower::DRAMPowerCLI::config\n\n\n#endif /* CLI_CONFIG_H */\n"
  },
  {
    "path": "src/cli/lib/DRAMPower/cli/csv.hpp",
    "content": "#pragma once\n/*\nCSV for C++, version 2.1.3\nhttps://github.com/vincentlaucsb/csv-parser\n\nMIT License\n\nCopyright (c) 2017-2020 Vincent La\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#ifndef CSV_HPP\n#define CSV_HPP\n\n/** @file\n *  @brief Defines functionality needed for basic CSV parsing\n */\n\n\n#include <algorithm>\n#include <deque>\n#include <fstream>\n#include <iterator>\n#include <memory>\n#include <mutex>\n#include <thread>\n#include <sstream>\n#include <string>\n#include <vector>\n\n/* Copyright 2017 https://github.com/mandreyel\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this\n * software and associated documentation files (the \"Software\"), to deal in the Software\n * without restriction, including without limitation the rights to use, copy, modify,\n * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to the following\n * conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies\n * or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\n * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE\n * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef MIO_MMAP_HEADER\n#define MIO_MMAP_HEADER\n\n// #include \"mio/page.hpp\"\n/* Copyright 2017 https://github.com/mandreyel\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this\n * software and associated documentation files (the \"Software\"), to deal in the Software\n * without restriction, including without limitation the rights to use, copy, modify,\n * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to the following\n * conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies\n * or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\n * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE\n * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef MIO_PAGE_HEADER\n#define MIO_PAGE_HEADER\n\n#ifdef _WIN32\n# include <windows.h>\n#else\n# include <unistd.h>\n#endif\n\nnamespace mio {\n\n/**\n * This is used by `basic_mmap` to determine whether to create a read-only or\n * a read-write memory mapping.\n */\nenum class access_mode\n{\n    read,\n    write\n};\n\n/**\n * Determines the operating system's page allocation granularity.\n *\n * On the first call to this function, it invokes the operating system specific syscall\n * to determine the page size, caches the value, and returns it. Any subsequent call to\n * this function serves the cached value, so no further syscalls are made.\n */\ninline size_t page_size()\n{\n    static const size_t page_size = []\n    {\n#ifdef _WIN32\n        SYSTEM_INFO SystemInfo;\n        GetSystemInfo(&SystemInfo);\n        return SystemInfo.dwAllocationGranularity;\n#else\n        return sysconf(_SC_PAGE_SIZE);\n#endif\n    }();\n    return page_size;\n}\n\n/**\n * Alligns `offset` to the operating's system page size such that it subtracts the\n * difference until the nearest page boundary before `offset`, or does nothing if\n * `offset` is already page aligned.\n */\ninline size_t make_offset_page_aligned(size_t offset) noexcept\n{\n    const size_t page_size_ = page_size();\n    // Use integer division to round down to the nearest page alignment.\n    return offset / page_size_ * page_size_;\n}\n\n} // namespace mio\n\n#endif // MIO_PAGE_HEADER\n\n\n#include <iterator>\n#include <string>\n#include <system_error>\n#include <cstdint>\n\n#ifdef _WIN32\n# ifndef WIN32_LEAN_AND_MEAN\n#  define WIN32_LEAN_AND_MEAN\n# endif // WIN32_LEAN_AND_MEAN\n# include <windows.h>\n#else // ifdef _WIN32\n# define INVALID_HANDLE_VALUE -1\n#endif // ifdef _WIN32\n\nnamespace mio {\n\n// This value may be provided as the `length` parameter to the constructor or\n// `map`, in which case a memory mapping of the entire file is created.\nenum { map_entire_file = 0 };\n\n#ifdef _WIN32\nusing file_handle_type = HANDLE;\n#else\nusing file_handle_type = int;\n#endif\n\n// This value represents an invalid file handle type. This can be used to\n// determine whether `basic_mmap::file_handle` is valid, for example.\nconst static file_handle_type invalid_handle = INVALID_HANDLE_VALUE;\n\ntemplate<access_mode AccessMode, typename ByteT>\nstruct basic_mmap\n{\n    using value_type = ByteT;\n    using size_type = size_t;\n    using reference = value_type&;\n    using const_reference = const value_type&;\n    using pointer = value_type*;\n    using const_pointer = const value_type*;\n    using difference_type = std::ptrdiff_t;\n    using iterator = pointer;\n    using const_iterator = const_pointer;\n    using reverse_iterator = std::reverse_iterator<iterator>;\n    using const_reverse_iterator = std::reverse_iterator<const_iterator>;\n    using iterator_category = std::random_access_iterator_tag;\n    using handle_type = file_handle_type;\n\n    static_assert(sizeof(ByteT) == sizeof(char), \"ByteT must be the same size as char.\");\n\nprivate:\n    // Points to the first requested byte, and not to the actual start of the mapping.\n    pointer data_ = nullptr;\n\n    // Length--in bytes--requested by user (which may not be the length of the\n    // full mapping) and the length of the full mapping.\n    size_type length_ = 0;\n    size_type mapped_length_ = 0;\n\n    // Letting user map a file using both an existing file handle and a path\n    // introcudes some complexity (see `is_handle_internal_`).\n    // On POSIX, we only need a file handle to create a mapping, while on\n    // Windows systems the file handle is necessary to retrieve a file mapping\n    // handle, but any subsequent operations on the mapped region must be done\n    // through the latter.\n    handle_type file_handle_ = INVALID_HANDLE_VALUE;\n#ifdef _WIN32\n    handle_type file_mapping_handle_ = INVALID_HANDLE_VALUE;\n#endif\n\n    // Letting user map a file using both an existing file handle and a path\n    // introcudes some complexity in that we must not close the file handle if\n    // user provided it, but we must close it if we obtained it using the\n    // provided path. For this reason, this flag is used to determine when to\n    // close `file_handle_`.\n    bool is_handle_internal_;\n\npublic:\n    /**\n     * The default constructed mmap object is in a non-mapped state, that is,\n     * any operation that attempts to access nonexistent underlying data will\n     * result in undefined behaviour/segmentation faults.\n     */\n    basic_mmap() = default;\n\n#ifdef __cpp_exceptions\n    /**\n     * The same as invoking the `map` function, except any error that may occur\n     * while establishing the mapping is wrapped in a `std::system_error` and is\n     * thrown.\n     */\n    template<typename String>\n    basic_mmap(const String& path, const size_type offset = 0, const size_type length = map_entire_file)\n    {\n        std::error_code error;\n        map(path, offset, length, error);\n        if(error) { throw std::system_error(error); }\n    }\n\n    /**\n     * The same as invoking the `map` function, except any error that may occur\n     * while establishing the mapping is wrapped in a `std::system_error` and is\n     * thrown.\n     */\n    basic_mmap(const handle_type handle, const size_type offset = 0, const size_type length = map_entire_file)\n    {\n        std::error_code error;\n        map(handle, offset, length, error);\n        if(error) { throw std::system_error(error); }\n    }\n#endif // __cpp_exceptions\n\n    /**\n     * `basic_mmap` has single-ownership semantics, so transferring ownership\n     * may only be accomplished by moving the object.\n     */\n    basic_mmap(const basic_mmap&) = delete;\n    basic_mmap(basic_mmap&&);\n    basic_mmap& operator=(const basic_mmap&) = delete;\n    basic_mmap& operator=(basic_mmap&&);\n\n    /**\n     * If this is a read-write mapping, the destructor invokes sync. Regardless\n     * of the access mode, unmap is invoked as a final step.\n     */\n    ~basic_mmap();\n\n    /**\n     * On UNIX systems 'file_handle' and 'mapping_handle' are the same. On Windows,\n     * however, a mapped region of a file gets its own handle, which is returned by\n     * 'mapping_handle'.\n     */\n    handle_type file_handle() const noexcept { return file_handle_; }\n    handle_type mapping_handle() const noexcept;\n\n    /** Returns whether a valid memory mapping has been created. */\n    bool is_open() const noexcept { return file_handle_ != invalid_handle; }\n\n    /**\n     * Returns true if no mapping was established, that is, conceptually the\n     * same as though the length that was mapped was 0. This function is\n     * provided so that this class has Container semantics.\n     */\n    bool empty() const noexcept { return length() == 0; }\n\n    /** Returns true if a mapping was established. */\n    bool is_mapped() const noexcept;\n\n    /**\n     * `size` and `length` both return the logical length, i.e. the number of bytes\n     * user requested to be mapped, while `mapped_length` returns the actual number of\n     * bytes that were mapped which is a multiple of the underlying operating system's\n     * page allocation granularity.\n     */\n    size_type size() const noexcept { return length(); }\n    size_type length() const noexcept { return length_; }\n    size_type mapped_length() const noexcept { return mapped_length_; }\n\n    /** Returns the offset relative to the start of the mapping. */\n    size_type mapping_offset() const noexcept\n    {\n        return mapped_length_ - length_;\n    }\n\n    /**\n     * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping\n     * exists.\n     */\n    template<\n        access_mode A = AccessMode,\n        typename = typename std::enable_if<A == access_mode::write>::type\n    > pointer data() noexcept { return data_; }\n    const_pointer data() const noexcept { return data_; }\n\n    /**\n     * Returns an iterator to the first requested byte, if a valid memory mapping\n     * exists, otherwise this function call is undefined behaviour.\n     */\n    template<\n        access_mode A = AccessMode,\n        typename = typename std::enable_if<A == access_mode::write>::type\n    > iterator begin() noexcept { return data(); }\n    const_iterator begin() const noexcept { return data(); }\n    const_iterator cbegin() const noexcept { return data(); }\n\n    /**\n     * Returns an iterator one past the last requested byte, if a valid memory mapping\n     * exists, otherwise this function call is undefined behaviour.\n     */\n    template<\n        access_mode A = AccessMode,\n        typename = typename std::enable_if<A == access_mode::write>::type\n    > iterator end() noexcept { return data() + length(); }\n    const_iterator end() const noexcept { return data() + length(); }\n    const_iterator cend() const noexcept { return data() + length(); }\n\n    /**\n     * Returns a reverse iterator to the last memory mapped byte, if a valid\n     * memory mapping exists, otherwise this function call is undefined\n     * behaviour.\n     */\n    template<\n        access_mode A = AccessMode,\n        typename = typename std::enable_if<A == access_mode::write>::type\n    > reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }\n    const_reverse_iterator rbegin() const noexcept\n    { return const_reverse_iterator(end()); }\n    const_reverse_iterator crbegin() const noexcept\n    { return const_reverse_iterator(end()); }\n\n    /**\n     * Returns a reverse iterator past the first mapped byte, if a valid memory\n     * mapping exists, otherwise this function call is undefined behaviour.\n     */\n    template<\n        access_mode A = AccessMode,\n        typename = typename std::enable_if<A == access_mode::write>::type\n    > reverse_iterator rend() noexcept { return reverse_iterator(begin()); }\n    const_reverse_iterator rend() const noexcept\n    { return const_reverse_iterator(begin()); }\n    const_reverse_iterator crend() const noexcept\n    { return const_reverse_iterator(begin()); }\n\n    /**\n     * Returns a reference to the `i`th byte from the first requested byte (as returned\n     * by `data`). If this is invoked when no valid memory mapping has been created\n     * prior to this call, undefined behaviour ensues.\n     */\n    reference operator[](const size_type i) noexcept { return data_[i]; }\n    const_reference operator[](const size_type i) const noexcept { return data_[i]; }\n\n    /**\n     * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the\n     * reason is reported via `error` and the object remains in a state as if this\n     * function hadn't been called.\n     *\n     * `path`, which must be a path to an existing file, is used to retrieve a file\n     * handle (which is closed when the object destructs or `unmap` is called), which is\n     * then used to memory map the requested region. Upon failure, `error` is set to\n     * indicate the reason and the object remains in an unmapped state.\n     *\n     * `offset` is the number of bytes, relative to the start of the file, where the\n     * mapping should begin. When specifying it, there is no need to worry about\n     * providing a value that is aligned with the operating system's page allocation\n     * granularity. This is adjusted by the implementation such that the first requested\n     * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at\n     * `offset` from the start of the file.\n     *\n     * `length` is the number of bytes to map. It may be `map_entire_file`, in which\n     * case a mapping of the entire file is created.\n     */\n    template<typename String>\n    void map(const String& path, const size_type offset,\n            const size_type length, std::error_code& error);\n\n    /**\n     * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the\n     * reason is reported via `error` and the object remains in a state as if this\n     * function hadn't been called.\n     *\n     * `path`, which must be a path to an existing file, is used to retrieve a file\n     * handle (which is closed when the object destructs or `unmap` is called), which is\n     * then used to memory map the requested region. Upon failure, `error` is set to\n     * indicate the reason and the object remains in an unmapped state.\n     * \n     * The entire file is mapped.\n     */\n    template<typename String>\n    void map(const String& path, std::error_code& error)\n    {\n        map(path, 0, map_entire_file, error);\n    }\n\n    /**\n     * Establishes a memory mapping with AccessMode. If the mapping is\n     * unsuccesful, the reason is reported via `error` and the object remains in\n     * a state as if this function hadn't been called.\n     *\n     * `handle`, which must be a valid file handle, which is used to memory map the\n     * requested region. Upon failure, `error` is set to indicate the reason and the\n     * object remains in an unmapped state.\n     *\n     * `offset` is the number of bytes, relative to the start of the file, where the\n     * mapping should begin. When specifying it, there is no need to worry about\n     * providing a value that is aligned with the operating system's page allocation\n     * granularity. This is adjusted by the implementation such that the first requested\n     * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at\n     * `offset` from the start of the file.\n     *\n     * `length` is the number of bytes to map. It may be `map_entire_file`, in which\n     * case a mapping of the entire file is created.\n     */\n    void map(const handle_type handle, const size_type offset,\n            const size_type length, std::error_code& error);\n\n    /**\n     * Establishes a memory mapping with AccessMode. If the mapping is\n     * unsuccesful, the reason is reported via `error` and the object remains in\n     * a state as if this function hadn't been called.\n     *\n     * `handle`, which must be a valid file handle, which is used to memory map the\n     * requested region. Upon failure, `error` is set to indicate the reason and the\n     * object remains in an unmapped state.\n     * \n     * The entire file is mapped.\n     */\n    void map(const handle_type handle, std::error_code& error)\n    {\n        map(handle, 0, map_entire_file, error);\n    }\n\n    /**\n     * If a valid memory mapping has been created prior to this call, this call\n     * instructs the kernel to unmap the memory region and disassociate this object\n     * from the file.\n     *\n     * The file handle associated with the file that is mapped is only closed if the\n     * mapping was created using a file path. If, on the other hand, an existing\n     * file handle was used to create the mapping, the file handle is not closed.\n     */\n    void unmap();\n\n    void swap(basic_mmap& other);\n\n    /** Flushes the memory mapped page to disk. Errors are reported via `error`. */\n    template<access_mode A = AccessMode>\n    typename std::enable_if<A == access_mode::write, void>::type\n    sync(std::error_code& error);\n\n    /**\n     * All operators compare the address of the first byte and size of the two mapped\n     * regions.\n     */\n\nprivate:\n    template<\n        access_mode A = AccessMode,\n        typename = typename std::enable_if<A == access_mode::write>::type\n    > pointer get_mapping_start() noexcept\n    {\n        return !data() ? nullptr : data() - mapping_offset();\n    }\n\n    const_pointer get_mapping_start() const noexcept\n    {\n        return !data() ? nullptr : data() - mapping_offset();\n    }\n\n    /**\n     * The destructor syncs changes to disk if `AccessMode` is `write`, but not\n     * if it's `read`, but since the destructor cannot be templated, we need to\n     * do SFINAE in a dedicated function, where one syncs and the other is a noop.\n     */\n    template<access_mode A = AccessMode>\n    typename std::enable_if<A == access_mode::write, void>::type\n    conditional_sync();\n    template<access_mode A = AccessMode>\n    typename std::enable_if<A == access_mode::read, void>::type conditional_sync();\n};\n\ntemplate<access_mode AccessMode, typename ByteT>\nbool operator==(const basic_mmap<AccessMode, ByteT>& a,\n        const basic_mmap<AccessMode, ByteT>& b);\n\ntemplate<access_mode AccessMode, typename ByteT>\nbool operator!=(const basic_mmap<AccessMode, ByteT>& a,\n        const basic_mmap<AccessMode, ByteT>& b);\n\ntemplate<access_mode AccessMode, typename ByteT>\nbool operator<(const basic_mmap<AccessMode, ByteT>& a,\n        const basic_mmap<AccessMode, ByteT>& b);\n\ntemplate<access_mode AccessMode, typename ByteT>\nbool operator<=(const basic_mmap<AccessMode, ByteT>& a,\n        const basic_mmap<AccessMode, ByteT>& b);\n\ntemplate<access_mode AccessMode, typename ByteT>\nbool operator>(const basic_mmap<AccessMode, ByteT>& a,\n        const basic_mmap<AccessMode, ByteT>& b);\n\ntemplate<access_mode AccessMode, typename ByteT>\nbool operator>=(const basic_mmap<AccessMode, ByteT>& a,\n        const basic_mmap<AccessMode, ByteT>& b);\n\n/**\n * This is the basis for all read-only mmap objects and should be preferred over\n * directly using `basic_mmap`.\n */\ntemplate<typename ByteT>\nusing basic_mmap_source = basic_mmap<access_mode::read, ByteT>;\n\n/**\n * This is the basis for all read-write mmap objects and should be preferred over\n * directly using `basic_mmap`.\n */\ntemplate<typename ByteT>\nusing basic_mmap_sink = basic_mmap<access_mode::write, ByteT>;\n\n/**\n * These aliases cover the most common use cases, both representing a raw byte stream\n * (either with a char or an unsigned char/uint8_t).\n */\nusing mmap_source = basic_mmap_source<char>;\nusing ummap_source = basic_mmap_source<unsigned char>;\n\nusing mmap_sink = basic_mmap_sink<char>;\nusing ummap_sink = basic_mmap_sink<unsigned char>;\n\n/**\n * Convenience factory method that constructs a mapping for any `basic_mmap` or\n * `basic_mmap` type.\n */\ntemplate<\n    typename MMap,\n    typename MappingToken\n> MMap make_mmap(const MappingToken& token,\n        int64_t offset, int64_t length, std::error_code& error)\n{\n    MMap mmap;\n    mmap.map(token, offset, length, error);\n    return mmap;\n}\n\n/**\n * Convenience factory method.\n *\n * MappingToken may be a String (`std::string`, `std::string_view`, `const char*`,\n * `std::filesystem::path`, `std::vector<char>`, or similar), or a\n * `mmap_source::handle_type`.\n */\ntemplate<typename MappingToken>\nmmap_source make_mmap_source(const MappingToken& token, mmap_source::size_type offset,\n        mmap_source::size_type length, std::error_code& error)\n{\n    return make_mmap<mmap_source>(token, offset, length, error);\n}\n\ntemplate<typename MappingToken>\nmmap_source make_mmap_source(const MappingToken& token, std::error_code& error)\n{\n    return make_mmap_source(token, 0, map_entire_file, error);\n}\n\n/**\n * Convenience factory method.\n *\n * MappingToken may be a String (`std::string`, `std::string_view`, `const char*`,\n * `std::filesystem::path`, `std::vector<char>`, or similar), or a\n * `mmap_sink::handle_type`.\n */\ntemplate<typename MappingToken>\nmmap_sink make_mmap_sink(const MappingToken& token, mmap_sink::size_type offset,\n        mmap_sink::size_type length, std::error_code& error)\n{\n    return make_mmap<mmap_sink>(token, offset, length, error);\n}\n\ntemplate<typename MappingToken>\nmmap_sink make_mmap_sink(const MappingToken& token, std::error_code& error)\n{\n    return make_mmap_sink(token, 0, map_entire_file, error);\n}\n\n} // namespace mio\n\n// #include \"detail/mmap.ipp\"\n/* Copyright 2017 https://github.com/mandreyel\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this\n * software and associated documentation files (the \"Software\"), to deal in the Software\n * without restriction, including without limitation the rights to use, copy, modify,\n * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to the following\n * conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies\n * or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\n * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE\n * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef MIO_BASIC_MMAP_IMPL\n#define MIO_BASIC_MMAP_IMPL\n\n// #include \"mio/mmap.hpp\"\n\n// #include \"mio/page.hpp\"\n\n// #include \"mio/detail/string_util.hpp\"\n/* Copyright 2017 https://github.com/mandreyel\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this\n * software and associated documentation files (the \"Software\"), to deal in the Software\n * without restriction, including without limitation the rights to use, copy, modify,\n * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to the following\n * conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies\n * or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\n * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE\n * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef MIO_STRING_UTIL_HEADER\n#define MIO_STRING_UTIL_HEADER\n\n#include <type_traits>\n\nnamespace mio {\nnamespace detail {\n\ntemplate<\n    typename S,\n    typename C = typename std::decay<S>::type,\n    typename = decltype(std::declval<C>().data()),\n    typename = typename std::enable_if<\n        std::is_same<typename C::value_type, char>::value\n#ifdef _WIN32\n        || std::is_same<typename C::value_type, wchar_t>::value\n#endif\n    >::type\n> struct char_type_helper {\n    using type = typename C::value_type;\n};\n\ntemplate<class T>\nstruct char_type {\n    using type = typename char_type_helper<T>::type;\n};\n\n// TODO: can we avoid this brute force approach?\ntemplate<>\nstruct char_type<char*> {\n    using type = char;\n};\n\ntemplate<>\nstruct char_type<const char*> {\n    using type = char;\n};\n\ntemplate<size_t N>\nstruct char_type<char[N]> {\n    using type = char;\n};\n\ntemplate<size_t N>\nstruct char_type<const char[N]> {\n    using type = char;\n};\n\n#ifdef _WIN32\ntemplate<>\nstruct char_type<wchar_t*> {\n    using type = wchar_t;\n};\n\ntemplate<>\nstruct char_type<const wchar_t*> {\n    using type = wchar_t;\n};\n\ntemplate<size_t N>\nstruct char_type<wchar_t[N]> {\n    using type = wchar_t;\n};\n\ntemplate<size_t N>\nstruct char_type<const wchar_t[N]> {\n    using type = wchar_t;\n};\n#endif // _WIN32\n\ntemplate<typename CharT, typename S>\nstruct is_c_str_helper\n{\n    static constexpr bool value = std::is_same<\n        CharT*,\n        // TODO: I'm so sorry for this... Can this be made cleaner?\n        typename std::add_pointer<\n            typename std::remove_cv<\n                typename std::remove_pointer<\n                    typename std::decay<\n                        S\n                    >::type\n                >::type\n            >::type\n        >::type\n    >::value;\n};\n\ntemplate<typename S>\nstruct is_c_str\n{\n    static constexpr bool value = is_c_str_helper<char, S>::value;\n};\n\n#ifdef _WIN32\ntemplate<typename S>\nstruct is_c_wstr\n{\n    static constexpr bool value = is_c_str_helper<wchar_t, S>::value;\n};\n#endif // _WIN32\n\ntemplate<typename S>\nstruct is_c_str_or_c_wstr\n{\n    static constexpr bool value = is_c_str<S>::value\n#ifdef _WIN32\n        || is_c_wstr<S>::value\n#endif\n        ;\n};\n\ntemplate<\n    typename String,\n    typename = decltype(std::declval<String>().data()),\n    typename = typename std::enable_if<!is_c_str_or_c_wstr<String>::value>::type\n> const typename char_type<String>::type* c_str(const String& path)\n{\n    return path.data();\n}\n\ntemplate<\n    typename String,\n    typename = decltype(std::declval<String>().empty()),\n    typename = typename std::enable_if<!is_c_str_or_c_wstr<String>::value>::type\n> bool empty(const String& path)\n{\n    return path.empty();\n}\n\ntemplate<\n    typename String,\n    typename = typename std::enable_if<is_c_str_or_c_wstr<String>::value>::type\n> const typename char_type<String>::type* c_str(String path)\n{\n    return path;\n}\n\ntemplate<\n    typename String,\n    typename = typename std::enable_if<is_c_str_or_c_wstr<String>::value>::type\n> bool empty(String path)\n{\n    return !path || (*path == 0);\n}\n\n} // namespace detail\n} // namespace mio\n\n#endif // MIO_STRING_UTIL_HEADER\n\n\n#include <algorithm>\n\n#ifndef _WIN32\n# include <unistd.h>\n# include <fcntl.h>\n# include <sys/mman.h>\n# include <sys/stat.h>\n#endif\n\nnamespace mio {\nnamespace detail {\n\n#ifdef _WIN32\nnamespace win {\n\n/** Returns the 4 upper bytes of an 8-byte integer. */\ninline DWORD int64_high(int64_t n) noexcept\n{\n    return n >> 32;\n}\n\n/** Returns the 4 lower bytes of an 8-byte integer. */\ninline DWORD int64_low(int64_t n) noexcept\n{\n    return n & 0xffffffff;\n}\n\ntemplate<\n    typename String,\n    typename = typename std::enable_if<\n        std::is_same<typename char_type<String>::type, char>::value\n    >::type\n> file_handle_type open_file_helper(const String& path, const access_mode mode)\n{\n    return ::CreateFileA(c_str(path),\n            mode == access_mode::read ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,\n            FILE_SHARE_READ | FILE_SHARE_WRITE,\n            0,\n            OPEN_EXISTING,\n            FILE_ATTRIBUTE_NORMAL,\n            0);\n}\n\ntemplate<typename String>\ntypename std::enable_if<\n    std::is_same<typename char_type<String>::type, wchar_t>::value,\n    file_handle_type\n>::type open_file_helper(const String& path, const access_mode mode)\n{\n    return ::CreateFileW(c_str(path),\n            mode == access_mode::read ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,\n            FILE_SHARE_READ | FILE_SHARE_WRITE,\n            0,\n            OPEN_EXISTING,\n            FILE_ATTRIBUTE_NORMAL,\n            0);\n}\n\n} // win\n#endif // _WIN32\n\n/**\n * Returns the last platform specific system error (errno on POSIX and\n * GetLastError on Win) as a `std::error_code`.\n */\ninline std::error_code last_error() noexcept\n{\n    std::error_code error;\n#ifdef _WIN32\n    error.assign(GetLastError(), std::system_category());\n#else\n    error.assign(errno, std::system_category());\n#endif\n    return error;\n}\n\ntemplate<typename String>\nfile_handle_type open_file(const String& path, const access_mode mode,\n        std::error_code& error)\n{\n    error.clear();\n    if(detail::empty(path))\n    {\n        error = std::make_error_code(std::errc::invalid_argument);\n        return invalid_handle;\n    }\n#ifdef _WIN32\n    const auto handle = win::open_file_helper(path, mode);\n#else // POSIX\n    const auto handle = ::open(c_str(path),\n            mode == access_mode::read ? O_RDONLY : O_RDWR);\n#endif\n    if(handle == invalid_handle)\n    {\n        error = detail::last_error();\n    }\n    return handle;\n}\n\ninline size_t query_file_size(file_handle_type handle, std::error_code& error)\n{\n    error.clear();\n#ifdef _WIN32\n    LARGE_INTEGER file_size;\n    if(::GetFileSizeEx(handle, &file_size) == 0)\n    {\n        error = detail::last_error();\n        return 0;\n    }\n\treturn static_cast<int64_t>(file_size.QuadPart);\n#else // POSIX\n    struct stat sbuf;\n    if(::fstat(handle, &sbuf) == -1)\n    {\n        error = detail::last_error();\n        return 0;\n    }\n    return sbuf.st_size;\n#endif\n}\n\nstruct mmap_context\n{\n    char* data;\n    int64_t length;\n    int64_t mapped_length;\n#ifdef _WIN32\n    file_handle_type file_mapping_handle;\n#endif\n};\n\ninline mmap_context memory_map(const file_handle_type file_handle, const int64_t offset,\n    const int64_t length, const access_mode mode, std::error_code& error)\n{\n    const int64_t aligned_offset = make_offset_page_aligned(offset);\n    const int64_t length_to_map = offset - aligned_offset + length;\n#ifdef _WIN32\n    const int64_t max_file_size = offset + length;\n    const auto file_mapping_handle = ::CreateFileMapping(\n            file_handle,\n            0,\n            mode == access_mode::read ? PAGE_READONLY : PAGE_READWRITE,\n            win::int64_high(max_file_size),\n            win::int64_low(max_file_size),\n            0);\n    if(file_mapping_handle == invalid_handle)\n    {\n        error = detail::last_error();\n        return {};\n    }\n    char* mapping_start = static_cast<char*>(::MapViewOfFile(\n            file_mapping_handle,\n            mode == access_mode::read ? FILE_MAP_READ : FILE_MAP_WRITE,\n            win::int64_high(aligned_offset),\n            win::int64_low(aligned_offset),\n            length_to_map));\n    if(mapping_start == nullptr)\n    {\n        // Close file handle if mapping it failed.\n        ::CloseHandle(file_mapping_handle);\n        error = detail::last_error();\n        return {};\n    }\n#else // POSIX\n    char* mapping_start = static_cast<char*>(::mmap(\n            0, // Don't give hint as to where to map.\n            length_to_map,\n            mode == access_mode::read ? PROT_READ : PROT_WRITE,\n            MAP_SHARED,\n            file_handle,\n            aligned_offset));\n    if(mapping_start == MAP_FAILED)\n    {\n        error = detail::last_error();\n        return {};\n    }\n#endif\n    mmap_context ctx;\n    ctx.data = mapping_start + offset - aligned_offset;\n    ctx.length = length;\n    ctx.mapped_length = length_to_map;\n#ifdef _WIN32\n    ctx.file_mapping_handle = file_mapping_handle;\n#endif\n    return ctx;\n}\n\n} // namespace detail\n\n// -- basic_mmap --\n\ntemplate<access_mode AccessMode, typename ByteT>\nbasic_mmap<AccessMode, ByteT>::~basic_mmap()\n{\n    conditional_sync();\n    unmap();\n}\n\ntemplate<access_mode AccessMode, typename ByteT>\nbasic_mmap<AccessMode, ByteT>::basic_mmap(basic_mmap&& other)\n    : data_(std::move(other.data_))\n    , length_(std::move(other.length_))\n    , mapped_length_(std::move(other.mapped_length_))\n    , file_handle_(std::move(other.file_handle_))\n#ifdef _WIN32\n    , file_mapping_handle_(std::move(other.file_mapping_handle_))\n#endif\n    , is_handle_internal_(std::move(other.is_handle_internal_))\n{\n    other.data_ = nullptr;\n    other.length_ = other.mapped_length_ = 0;\n    other.file_handle_ = invalid_handle;\n#ifdef _WIN32\n    other.file_mapping_handle_ = invalid_handle;\n#endif\n}\n\ntemplate<access_mode AccessMode, typename ByteT>\nbasic_mmap<AccessMode, ByteT>&\nbasic_mmap<AccessMode, ByteT>::operator=(basic_mmap&& other)\n{\n    if(this != &other)\n    {\n        // First the existing mapping needs to be removed.\n        unmap();\n        data_ = std::move(other.data_);\n        length_ = std::move(other.length_);\n        mapped_length_ = std::move(other.mapped_length_);\n        file_handle_ = std::move(other.file_handle_);\n#ifdef _WIN32\n        file_mapping_handle_ = std::move(other.file_mapping_handle_);\n#endif\n        is_handle_internal_ = std::move(other.is_handle_internal_);\n\n        // The moved from basic_mmap's fields need to be reset, because\n        // otherwise other's destructor will unmap the same mapping that was\n        // just moved into this.\n        other.data_ = nullptr;\n        other.length_ = other.mapped_length_ = 0;\n        other.file_handle_ = invalid_handle;\n#ifdef _WIN32\n        other.file_mapping_handle_ = invalid_handle;\n#endif\n        other.is_handle_internal_ = false;\n    }\n    return *this;\n}\n\ntemplate<access_mode AccessMode, typename ByteT>\ntypename basic_mmap<AccessMode, ByteT>::handle_type\nbasic_mmap<AccessMode, ByteT>::mapping_handle() const noexcept\n{\n#ifdef _WIN32\n    return file_mapping_handle_;\n#else\n    return file_handle_;\n#endif\n}\n\ntemplate<access_mode AccessMode, typename ByteT>\ntemplate<typename String>\nvoid basic_mmap<AccessMode, ByteT>::map(const String& path, const size_type offset,\n        const size_type length, std::error_code& error)\n{\n    error.clear();\n    if(detail::empty(path))\n    {\n        error = std::make_error_code(std::errc::invalid_argument);\n        return;\n    }\n    const auto handle = detail::open_file(path, AccessMode, error);\n    if(error)\n    {\n        return;\n    }\n\n    map(handle, offset, length, error);\n    // This MUST be after the call to map, as that sets this to true.\n    if(!error)\n    {\n        is_handle_internal_ = true;\n    }\n}\n\ntemplate<access_mode AccessMode, typename ByteT>\nvoid basic_mmap<AccessMode, ByteT>::map(const handle_type handle,\n        const size_type offset, const size_type length, std::error_code& error)\n{\n    error.clear();\n    if(handle == invalid_handle)\n    {\n        error = std::make_error_code(std::errc::bad_file_descriptor);\n        return;\n    }\n\n    const auto file_size = detail::query_file_size(handle, error);\n    if(error)\n    {\n        return;\n    }\n\n    if(offset + length > file_size)\n    {\n        error = std::make_error_code(std::errc::invalid_argument);\n        return;\n    }\n\n    const auto ctx = detail::memory_map(handle, offset,\n            length == map_entire_file ? (file_size - offset) : length,\n            AccessMode, error);\n    if(!error)\n    {\n        // We must unmap the previous mapping that may have existed prior to this call.\n        // Note that this must only be invoked after a new mapping has been created in\n        // order to provide the strong guarantee that, should the new mapping fail, the\n        // `map` function leaves this instance in a state as though the function had\n        // never been invoked.\n        unmap();\n        file_handle_ = handle;\n        is_handle_internal_ = false;\n        data_ = reinterpret_cast<pointer>(ctx.data);\n        length_ = ctx.length;\n        mapped_length_ = ctx.mapped_length;\n#ifdef _WIN32\n        file_mapping_handle_ = ctx.file_mapping_handle;\n#endif\n    }\n}\n\ntemplate<access_mode AccessMode, typename ByteT>\ntemplate<access_mode A>\ntypename std::enable_if<A == access_mode::write, void>::type\nbasic_mmap<AccessMode, ByteT>::sync(std::error_code& error)\n{\n    error.clear();\n    if(!is_open())\n    {\n        error = std::make_error_code(std::errc::bad_file_descriptor);\n        return;\n    }\n\n    if(data())\n    {\n#ifdef _WIN32\n        if(::FlushViewOfFile(get_mapping_start(), mapped_length_) == 0\n           || ::FlushFileBuffers(file_handle_) == 0)\n#else // POSIX\n        if(::msync(get_mapping_start(), mapped_length_, MS_SYNC) != 0)\n#endif\n        {\n            error = detail::last_error();\n            return;\n        }\n    }\n#ifdef _WIN32\n    if(::FlushFileBuffers(file_handle_) == 0)\n    {\n        error = detail::last_error();\n    }\n#endif\n}\n\ntemplate<access_mode AccessMode, typename ByteT>\nvoid basic_mmap<AccessMode, ByteT>::unmap()\n{\n    if(!is_open()) { return; }\n    // TODO do we care about errors here?\n#ifdef _WIN32\n    if(is_mapped())\n    {\n        ::UnmapViewOfFile(get_mapping_start());\n        ::CloseHandle(file_mapping_handle_);\n    }\n#else // POSIX\n    if(data_) { ::munmap(const_cast<pointer>(get_mapping_start()), mapped_length_); }\n#endif\n\n    // If `file_handle_` was obtained by our opening it (when map is called with\n    // a path, rather than an existing file handle), we need to close it,\n    // otherwise it must not be closed as it may still be used outside this\n    // instance.\n    if(is_handle_internal_)\n    {\n#ifdef _WIN32\n        ::CloseHandle(file_handle_);\n#else // POSIX\n        ::close(file_handle_);\n#endif\n    }\n\n    // Reset fields to their default values.\n    data_ = nullptr;\n    length_ = mapped_length_ = 0;\n    file_handle_ = invalid_handle;\n#ifdef _WIN32\n    file_mapping_handle_ = invalid_handle;\n#endif\n}\n\ntemplate<access_mode AccessMode, typename ByteT>\nbool basic_mmap<AccessMode, ByteT>::is_mapped() const noexcept\n{\n#ifdef _WIN32\n    return file_mapping_handle_ != invalid_handle;\n#else // POSIX\n    return is_open();\n#endif\n}\n\ntemplate<access_mode AccessMode, typename ByteT>\nvoid basic_mmap<AccessMode, ByteT>::swap(basic_mmap& other)\n{\n    if(this != &other)\n    {\n        using std::swap;\n        swap(data_, other.data_);\n        swap(file_handle_, other.file_handle_);\n#ifdef _WIN32\n        swap(file_mapping_handle_, other.file_mapping_handle_);\n#endif\n        swap(length_, other.length_);\n        swap(mapped_length_, other.mapped_length_);\n        swap(is_handle_internal_, other.is_handle_internal_);\n    }\n}\n\ntemplate<access_mode AccessMode, typename ByteT>\ntemplate<access_mode A>\ntypename std::enable_if<A == access_mode::write, void>::type\nbasic_mmap<AccessMode, ByteT>::conditional_sync()\n{\n    // This is invoked from the destructor, so not much we can do about\n    // failures here.\n    std::error_code ec;\n    sync(ec);\n}\n\ntemplate<access_mode AccessMode, typename ByteT>\ntemplate<access_mode A>\ntypename std::enable_if<A == access_mode::read, void>::type\nbasic_mmap<AccessMode, ByteT>::conditional_sync()\n{\n    // noop\n}\n\ntemplate<access_mode AccessMode, typename ByteT>\nbool operator==(const basic_mmap<AccessMode, ByteT>& a,\n        const basic_mmap<AccessMode, ByteT>& b)\n{\n    return a.data() == b.data()\n        && a.size() == b.size();\n}\n\ntemplate<access_mode AccessMode, typename ByteT>\nbool operator!=(const basic_mmap<AccessMode, ByteT>& a,\n        const basic_mmap<AccessMode, ByteT>& b)\n{\n    return !(a == b);\n}\n\ntemplate<access_mode AccessMode, typename ByteT>\nbool operator<(const basic_mmap<AccessMode, ByteT>& a,\n        const basic_mmap<AccessMode, ByteT>& b)\n{\n    if(a.data() == b.data()) { return a.size() < b.size(); }\n    return a.data() < b.data();\n}\n\ntemplate<access_mode AccessMode, typename ByteT>\nbool operator<=(const basic_mmap<AccessMode, ByteT>& a,\n        const basic_mmap<AccessMode, ByteT>& b)\n{\n    return !(a > b);\n}\n\ntemplate<access_mode AccessMode, typename ByteT>\nbool operator>(const basic_mmap<AccessMode, ByteT>& a,\n        const basic_mmap<AccessMode, ByteT>& b)\n{\n    if(a.data() == b.data()) { return a.size() > b.size(); }\n    return a.data() > b.data();\n}\n\ntemplate<access_mode AccessMode, typename ByteT>\nbool operator>=(const basic_mmap<AccessMode, ByteT>& a,\n        const basic_mmap<AccessMode, ByteT>& b)\n{\n    return !(a < b);\n}\n\n} // namespace mio\n\n#endif // MIO_BASIC_MMAP_IMPL\n\n\n#endif // MIO_MMAP_HEADER\n/* Copyright 2017 https://github.com/mandreyel\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this\n * software and associated documentation files (the \"Software\"), to deal in the Software\n * without restriction, including without limitation the rights to use, copy, modify,\n * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to the following\n * conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies\n * or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\n * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE\n * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef MIO_PAGE_HEADER\n#define MIO_PAGE_HEADER\n\n#ifdef _WIN32\n# include <windows.h>\n#else\n# include <unistd.h>\n#endif\n\nnamespace mio {\n\n/**\n * This is used by `basic_mmap` to determine whether to create a read-only or\n * a read-write memory mapping.\n */\nenum class access_mode\n{\n    read,\n    write\n};\n\n/**\n * Determines the operating system's page allocation granularity.\n *\n * On the first call to this function, it invokes the operating system specific syscall\n * to determine the page size, caches the value, and returns it. Any subsequent call to\n * this function serves the cached value, so no further syscalls are made.\n */\ninline size_t page_size()\n{\n    static const size_t page_size = []\n    {\n#ifdef _WIN32\n        SYSTEM_INFO SystemInfo;\n        GetSystemInfo(&SystemInfo);\n        return SystemInfo.dwAllocationGranularity;\n#else\n        return sysconf(_SC_PAGE_SIZE);\n#endif\n    }();\n    return page_size;\n}\n\n/**\n * Alligns `offset` to the operating's system page size such that it subtracts the\n * difference until the nearest page boundary before `offset`, or does nothing if\n * `offset` is already page aligned.\n */\ninline size_t make_offset_page_aligned(size_t offset) noexcept\n{\n    const size_t page_size_ = page_size();\n    // Use integer division to round down to the nearest page alignment.\n    return offset / page_size_ * page_size_;\n}\n\n} // namespace mio\n\n#endif // MIO_PAGE_HEADER\n/* Copyright 2017 https://github.com/mandreyel\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this\n * software and associated documentation files (the \"Software\"), to deal in the Software\n * without restriction, including without limitation the rights to use, copy, modify,\n * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to the following\n * conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies\n * or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\n * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE\n * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef MIO_SHARED_MMAP_HEADER\n#define MIO_SHARED_MMAP_HEADER\n\n// #include \"mio/mmap.hpp\"\n\n\n#include <system_error> // std::error_code\n#include <memory> // std::shared_ptr\n\nnamespace mio {\n\n/**\n * Exposes (nearly) the same interface as `basic_mmap`, but endowes it with\n * `std::shared_ptr` semantics.\n *\n * This is not the default behaviour of `basic_mmap` to avoid allocating on the heap if\n * shared semantics are not required.\n */\ntemplate<\n    access_mode AccessMode,\n    typename ByteT\n> class basic_shared_mmap\n{\n    using impl_type = basic_mmap<AccessMode, ByteT>;\n    std::shared_ptr<impl_type> pimpl_;\n\npublic:\n    using value_type = typename impl_type::value_type;\n    using size_type = typename impl_type::size_type;\n    using reference = typename impl_type::reference;\n    using const_reference = typename impl_type::const_reference;\n    using pointer = typename impl_type::pointer;\n    using const_pointer = typename impl_type::const_pointer;\n    using difference_type = typename impl_type::difference_type;\n    using iterator = typename impl_type::iterator;\n    using const_iterator = typename impl_type::const_iterator;\n    using reverse_iterator = typename impl_type::reverse_iterator;\n    using const_reverse_iterator = typename impl_type::const_reverse_iterator;\n    using iterator_category = typename impl_type::iterator_category;\n    using handle_type = typename impl_type::handle_type;\n    using mmap_type = impl_type;\n\n    basic_shared_mmap() = default;\n    basic_shared_mmap(const basic_shared_mmap&) = default;\n    basic_shared_mmap& operator=(const basic_shared_mmap&) = default;\n    basic_shared_mmap(basic_shared_mmap&&) = default;\n    basic_shared_mmap& operator=(basic_shared_mmap&&) = default;\n\n    /** Takes ownership of an existing mmap object. */\n    basic_shared_mmap(mmap_type&& mmap)\n        : pimpl_(std::make_shared<mmap_type>(std::move(mmap)))\n    {}\n\n    /** Takes ownership of an existing mmap object. */\n    basic_shared_mmap& operator=(mmap_type&& mmap)\n    {\n        pimpl_ = std::make_shared<mmap_type>(std::move(mmap));\n        return *this;\n    }\n\n    /** Initializes this object with an already established shared mmap. */\n    basic_shared_mmap(std::shared_ptr<mmap_type> mmap) : pimpl_(std::move(mmap)) {}\n\n    /** Initializes this object with an already established shared mmap. */\n    basic_shared_mmap& operator=(std::shared_ptr<mmap_type> mmap)\n    {\n        pimpl_ = std::move(mmap);\n        return *this;\n    }\n\n#ifdef __cpp_exceptions\n    /**\n     * The same as invoking the `map` function, except any error that may occur\n     * while establishing the mapping is wrapped in a `std::system_error` and is\n     * thrown.\n     */\n    template<typename String>\n    basic_shared_mmap(const String& path, const size_type offset = 0, const size_type length = map_entire_file)\n    {\n        std::error_code error;\n        map(path, offset, length, error);\n        if(error) { throw std::system_error(error); }\n    }\n\n    /**\n     * The same as invoking the `map` function, except any error that may occur\n     * while establishing the mapping is wrapped in a `std::system_error` and is\n     * thrown.\n     */\n    basic_shared_mmap(const handle_type handle, const size_type offset = 0, const size_type length = map_entire_file)\n    {\n        std::error_code error;\n        map(handle, offset, length, error);\n        if(error) { throw std::system_error(error); }\n    }\n#endif // __cpp_exceptions\n\n    /**\n     * If this is a read-write mapping and the last reference to the mapping,\n     * the destructor invokes sync. Regardless of the access mode, unmap is\n     * invoked as a final step.\n     */\n    ~basic_shared_mmap() = default;\n\n    /** Returns the underlying `std::shared_ptr` instance that holds the mmap. */\n    std::shared_ptr<mmap_type> get_shared_ptr() { return pimpl_; }\n\n    /**\n     * On UNIX systems 'file_handle' and 'mapping_handle' are the same. On Windows,\n     * however, a mapped region of a file gets its own handle, which is returned by\n     * 'mapping_handle'.\n     */\n    handle_type file_handle() const noexcept\n    {\n        return pimpl_ ? pimpl_->file_handle() : invalid_handle;\n    }\n\n    handle_type mapping_handle() const noexcept\n    {\n        return pimpl_ ? pimpl_->mapping_handle() : invalid_handle;\n    }\n\n    /** Returns whether a valid memory mapping has been created. */\n    bool is_open() const noexcept { return pimpl_ && pimpl_->is_open(); }\n\n    /**\n     * Returns true if no mapping was established, that is, conceptually the\n     * same as though the length that was mapped was 0. This function is\n     * provided so that this class has Container semantics.\n     */\n    bool empty() const noexcept { return !pimpl_ || pimpl_->empty(); }\n\n    /**\n     * `size` and `length` both return the logical length, i.e. the number of bytes\n     * user requested to be mapped, while `mapped_length` returns the actual number of\n     * bytes that were mapped which is a multiple of the underlying operating system's\n     * page allocation granularity.\n     */\n    size_type size() const noexcept { return pimpl_ ? pimpl_->length() : 0; }\n    size_type length() const noexcept { return pimpl_ ? pimpl_->length() : 0; }\n    size_type mapped_length() const noexcept\n    {\n        return pimpl_ ? pimpl_->mapped_length() : 0;\n    }\n\n    /**\n     * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping\n     * exists.\n     */\n    template<\n        access_mode A = AccessMode,\n        typename = typename std::enable_if<A == access_mode::write>::type\n    > pointer data() noexcept { return pimpl_->data(); }\n    const_pointer data() const noexcept { return pimpl_ ? pimpl_->data() : nullptr; }\n\n    /**\n     * Returns an iterator to the first requested byte, if a valid memory mapping\n     * exists, otherwise this function call is undefined behaviour.\n     */\n    iterator begin() noexcept { return pimpl_->begin(); }\n    const_iterator begin() const noexcept { return pimpl_->begin(); }\n    const_iterator cbegin() const noexcept { return pimpl_->cbegin(); }\n\n    /**\n     * Returns an iterator one past the last requested byte, if a valid memory mapping\n     * exists, otherwise this function call is undefined behaviour.\n     */\n    template<\n        access_mode A = AccessMode,\n        typename = typename std::enable_if<A == access_mode::write>::type\n    > iterator end() noexcept { return pimpl_->end(); }\n    const_iterator end() const noexcept { return pimpl_->end(); }\n    const_iterator cend() const noexcept { return pimpl_->cend(); }\n\n    /**\n     * Returns a reverse iterator to the last memory mapped byte, if a valid\n     * memory mapping exists, otherwise this function call is undefined\n     * behaviour.\n     */\n    template<\n        access_mode A = AccessMode,\n        typename = typename std::enable_if<A == access_mode::write>::type\n    > reverse_iterator rbegin() noexcept { return pimpl_->rbegin(); }\n    const_reverse_iterator rbegin() const noexcept { return pimpl_->rbegin(); }\n    const_reverse_iterator crbegin() const noexcept { return pimpl_->crbegin(); }\n\n    /**\n     * Returns a reverse iterator past the first mapped byte, if a valid memory\n     * mapping exists, otherwise this function call is undefined behaviour.\n     */\n    template<\n        access_mode A = AccessMode,\n        typename = typename std::enable_if<A == access_mode::write>::type\n    > reverse_iterator rend() noexcept { return pimpl_->rend(); }\n    const_reverse_iterator rend() const noexcept { return pimpl_->rend(); }\n    const_reverse_iterator crend() const noexcept { return pimpl_->crend(); }\n\n    /**\n     * Returns a reference to the `i`th byte from the first requested byte (as returned\n     * by `data`). If this is invoked when no valid memory mapping has been created\n     * prior to this call, undefined behaviour ensues.\n     */\n    reference operator[](const size_type i) noexcept { return (*pimpl_)[i]; }\n    const_reference operator[](const size_type i) const noexcept { return (*pimpl_)[i]; }\n\n    /**\n     * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the\n     * reason is reported via `error` and the object remains in a state as if this\n     * function hadn't been called.\n     *\n     * `path`, which must be a path to an existing file, is used to retrieve a file\n     * handle (which is closed when the object destructs or `unmap` is called), which is\n     * then used to memory map the requested region. Upon failure, `error` is set to\n     * indicate the reason and the object remains in an unmapped state.\n     *\n     * `offset` is the number of bytes, relative to the start of the file, where the\n     * mapping should begin. When specifying it, there is no need to worry about\n     * providing a value that is aligned with the operating system's page allocation\n     * granularity. This is adjusted by the implementation such that the first requested\n     * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at\n     * `offset` from the start of the file.\n     *\n     * `length` is the number of bytes to map. It may be `map_entire_file`, in which\n     * case a mapping of the entire file is created.\n     */\n    template<typename String>\n    void map(const String& path, const size_type offset,\n        const size_type length, std::error_code& error)\n    {\n        map_impl(path, offset, length, error);\n    }\n\n    /**\n     * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the\n     * reason is reported via `error` and the object remains in a state as if this\n     * function hadn't been called.\n     *\n     * `path`, which must be a path to an existing file, is used to retrieve a file\n     * handle (which is closed when the object destructs or `unmap` is called), which is\n     * then used to memory map the requested region. Upon failure, `error` is set to\n     * indicate the reason and the object remains in an unmapped state.\n     *\n     * The entire file is mapped.\n     */\n    template<typename String>\n    void map(const String& path, std::error_code& error)\n    {\n        map_impl(path, 0, map_entire_file, error);\n    }\n\n    /**\n     * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the\n     * reason is reported via `error` and the object remains in a state as if this\n     * function hadn't been called.\n     *\n     * `handle`, which must be a valid file handle, which is used to memory map the\n     * requested region. Upon failure, `error` is set to indicate the reason and the\n     * object remains in an unmapped state.\n     *\n     * `offset` is the number of bytes, relative to the start of the file, where the\n     * mapping should begin. When specifying it, there is no need to worry about\n     * providing a value that is aligned with the operating system's page allocation\n     * granularity. This is adjusted by the implementation such that the first requested\n     * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at\n     * `offset` from the start of the file.\n     *\n     * `length` is the number of bytes to map. It may be `map_entire_file`, in which\n     * case a mapping of the entire file is created.\n     */\n    void map(const handle_type handle, const size_type offset,\n        const size_type length, std::error_code& error)\n    {\n        map_impl(handle, offset, length, error);\n    }\n\n    /**\n     * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the\n     * reason is reported via `error` and the object remains in a state as if this\n     * function hadn't been called.\n     *\n     * `handle`, which must be a valid file handle, which is used to memory map the\n     * requested region. Upon failure, `error` is set to indicate the reason and the\n     * object remains in an unmapped state.\n     *\n     * The entire file is mapped.\n     */\n    void map(const handle_type handle, std::error_code& error)\n    {\n        map_impl(handle, 0, map_entire_file, error);\n    }\n\n    /**\n     * If a valid memory mapping has been created prior to this call, this call\n     * instructs the kernel to unmap the memory region and disassociate this object\n     * from the file.\n     *\n     * The file handle associated with the file that is mapped is only closed if the\n     * mapping was created using a file path. If, on the other hand, an existing\n     * file handle was used to create the mapping, the file handle is not closed.\n     */\n    void unmap() { if(pimpl_) pimpl_->unmap(); }\n\n    void swap(basic_shared_mmap& other) { pimpl_.swap(other.pimpl_); }\n\n    /** Flushes the memory mapped page to disk. Errors are reported via `error`. */\n    template<\n        access_mode A = AccessMode,\n        typename = typename std::enable_if<A == access_mode::write>::type\n    > void sync(std::error_code& error) { if(pimpl_) pimpl_->sync(error); }\n\n    /** All operators compare the underlying `basic_mmap`'s addresses. */\n\n    friend bool operator==(const basic_shared_mmap& a, const basic_shared_mmap& b)\n    {\n        return a.pimpl_ == b.pimpl_;\n    }\n\n    friend bool operator!=(const basic_shared_mmap& a, const basic_shared_mmap& b)\n    {\n        return !(a == b);\n    }\n\n    friend bool operator<(const basic_shared_mmap& a, const basic_shared_mmap& b)\n    {\n        return a.pimpl_ < b.pimpl_;\n    }\n\n    friend bool operator<=(const basic_shared_mmap& a, const basic_shared_mmap& b)\n    {\n        return a.pimpl_ <= b.pimpl_;\n    }\n\n    friend bool operator>(const basic_shared_mmap& a, const basic_shared_mmap& b)\n    {\n        return a.pimpl_ > b.pimpl_;\n    }\n\n    friend bool operator>=(const basic_shared_mmap& a, const basic_shared_mmap& b)\n    {\n        return a.pimpl_ >= b.pimpl_;\n    }\n\nprivate:\n    template<typename MappingToken>\n    void map_impl(const MappingToken& token, const size_type offset,\n        const size_type length, std::error_code& error)\n    {\n        if(!pimpl_)\n        {\n            mmap_type mmap = make_mmap<mmap_type>(token, offset, length, error);\n            if(error) { return; }\n            pimpl_ = std::make_shared<mmap_type>(std::move(mmap));\n        }\n        else\n        {\n            pimpl_->map(token, offset, length, error);\n        }\n    }\n};\n\n/**\n * This is the basis for all read-only mmap objects and should be preferred over\n * directly using basic_shared_mmap.\n */\ntemplate<typename ByteT>\nusing basic_shared_mmap_source = basic_shared_mmap<access_mode::read, ByteT>;\n\n/**\n * This is the basis for all read-write mmap objects and should be preferred over\n * directly using basic_shared_mmap.\n */\ntemplate<typename ByteT>\nusing basic_shared_mmap_sink = basic_shared_mmap<access_mode::write, ByteT>;\n\n/**\n * These aliases cover the most common use cases, both representing a raw byte stream\n * (either with a char or an unsigned char/uint8_t).\n */\nusing shared_mmap_source = basic_shared_mmap_source<char>;\nusing shared_ummap_source = basic_shared_mmap_source<unsigned char>;\n\nusing shared_mmap_sink = basic_shared_mmap_sink<char>;\nusing shared_ummap_sink = basic_shared_mmap_sink<unsigned char>;\n\n} // namespace mio\n\n#endif // MIO_SHARED_MMAP_HEADER\n\n/** @file\n *  @brief Contains the main CSV parsing algorithm and various utility functions\n */\n\n#include <algorithm>\n#include <array>\n#include <condition_variable>\n#include <deque>\n#include <fstream>\n#include <memory>\n#include <mutex>\n#include <unordered_map>\n#include <unordered_set>\n#include <thread>\n#include <vector>\n\n#include <memory>\n#include <unordered_map>\n#include <string>\n#include <vector>\n\n/** @file\n *  A standalone header file containing shared code\n */\n\n#include <algorithm>\n#include <array>\n#include <cmath>\n#include <cstdlib>\n#include <deque>\n\n#if defined(_WIN32)\n# ifndef WIN32_LEAN_AND_MEAN\n#  define WIN32_LEAN_AND_MEAN\n# endif\n# include <Windows.h>\n# undef max\n# undef min\n#elif defined(__linux__)\n# include <unistd.h>\n#endif\n\n /** Helper macro which should be #defined as \"inline\"\n  *  in the single header version\n  */\n#define CSV_INLINE inline\n\n#include <type_traits>\n\n// Copyright 2017-2019 by Martin Moene\n//\n// string-view lite, a C++17-like string_view for C++98 and later.\n// For more information see https://github.com/martinmoene/string-view-lite\n//\n// Distributed under the Boost Software License, Version 1.0.\n// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n\n\n#ifndef NONSTD_SV_LITE_H_INCLUDED\n#define NONSTD_SV_LITE_H_INCLUDED\n\n#define string_view_lite_MAJOR  1\n#define string_view_lite_MINOR  1\n#define string_view_lite_PATCH  0\n\n#define string_view_lite_VERSION  nssv_STRINGIFY(string_view_lite_MAJOR) \".\" nssv_STRINGIFY(string_view_lite_MINOR) \".\" nssv_STRINGIFY(string_view_lite_PATCH)\n\n#define nssv_STRINGIFY(  x )  nssv_STRINGIFY_( x )\n#define nssv_STRINGIFY_( x )  #x\n\n// string-view lite configuration:\n\n#define nssv_STRING_VIEW_DEFAULT  0\n#define nssv_STRING_VIEW_NONSTD   1\n#define nssv_STRING_VIEW_STD      2\n\n#if !defined( nssv_CONFIG_SELECT_STRING_VIEW )\n# define nssv_CONFIG_SELECT_STRING_VIEW  ( nssv_HAVE_STD_STRING_VIEW ? nssv_STRING_VIEW_STD : nssv_STRING_VIEW_NONSTD )\n#endif\n\n#if defined( nssv_CONFIG_SELECT_STD_STRING_VIEW ) || defined( nssv_CONFIG_SELECT_NONSTD_STRING_VIEW )\n# error nssv_CONFIG_SELECT_STD_STRING_VIEW and nssv_CONFIG_SELECT_NONSTD_STRING_VIEW are deprecated and removed, please use nssv_CONFIG_SELECT_STRING_VIEW=nssv_STRING_VIEW_...\n#endif\n\n#ifndef  nssv_CONFIG_STD_SV_OPERATOR\n# define nssv_CONFIG_STD_SV_OPERATOR  0\n#endif\n\n#ifndef  nssv_CONFIG_USR_SV_OPERATOR\n# define nssv_CONFIG_USR_SV_OPERATOR  1\n#endif\n\n#ifdef   nssv_CONFIG_CONVERSION_STD_STRING\n# define nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS   nssv_CONFIG_CONVERSION_STD_STRING\n# define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS  nssv_CONFIG_CONVERSION_STD_STRING\n#endif\n\n#ifndef  nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS\n# define nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS  1\n#endif\n\n#ifndef  nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS\n# define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS  1\n#endif\n\n// Control presence of exception handling (try and auto discover):\n\n#ifndef nssv_CONFIG_NO_EXCEPTIONS\n# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)\n#  define nssv_CONFIG_NO_EXCEPTIONS  0\n# else\n#  define nssv_CONFIG_NO_EXCEPTIONS  1\n# endif\n#endif\n\n// C++ language version detection (C++20 is speculative):\n// Note: VC14.0/1900 (VS2015) lacks too much from C++14.\n\n#ifndef   nssv_CPLUSPLUS\n# if defined(_MSVC_LANG ) && !defined(__clang__)\n#  define nssv_CPLUSPLUS  (_MSC_VER == 1900 ? 201103L : _MSVC_LANG )\n# else\n#  define nssv_CPLUSPLUS  __cplusplus\n# endif\n#endif\n\n#define nssv_CPP98_OR_GREATER  ( nssv_CPLUSPLUS >= 199711L )\n#define nssv_CPP11_OR_GREATER  ( nssv_CPLUSPLUS >= 201103L )\n#define nssv_CPP11_OR_GREATER_ ( nssv_CPLUSPLUS >= 201103L )\n#define nssv_CPP14_OR_GREATER  ( nssv_CPLUSPLUS >= 201402L )\n#define nssv_CPP17_OR_GREATER  ( nssv_CPLUSPLUS >= 201703L )\n#define nssv_CPP20_OR_GREATER  ( nssv_CPLUSPLUS >= 202000L )\n\n// use C++17 std::string_view if available and requested:\n\n#if nssv_CPP17_OR_GREATER && defined(__has_include )\n# if __has_include( <string_view> )\n#  define nssv_HAVE_STD_STRING_VIEW  1\n# else\n#  define nssv_HAVE_STD_STRING_VIEW  0\n# endif\n#else\n# define  nssv_HAVE_STD_STRING_VIEW  0\n#endif\n\n#define  nssv_USES_STD_STRING_VIEW  ( (nssv_CONFIG_SELECT_STRING_VIEW == nssv_STRING_VIEW_STD) || ((nssv_CONFIG_SELECT_STRING_VIEW == nssv_STRING_VIEW_DEFAULT) && nssv_HAVE_STD_STRING_VIEW) )\n\n#define nssv_HAVE_STARTS_WITH ( nssv_CPP20_OR_GREATER || !nssv_USES_STD_STRING_VIEW )\n#define nssv_HAVE_ENDS_WITH     nssv_HAVE_STARTS_WITH\n\n//\n// Use C++17 std::string_view:\n//\n\n#if nssv_USES_STD_STRING_VIEW\n\n#include <string_view>\n\n// Extensions for std::string:\n\n#if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS\n\nnamespace nonstd {\n\ntemplate< class CharT, class Traits, class Allocator = std::allocator<CharT> >\nstd::basic_string<CharT, Traits, Allocator>\nto_string( std::basic_string_view<CharT, Traits> v, Allocator const & a = Allocator() )\n{\n    return std::basic_string<CharT,Traits, Allocator>( v.begin(), v.end(), a );\n}\n\ntemplate< class CharT, class Traits, class Allocator >\nstd::basic_string_view<CharT, Traits>\nto_string_view( std::basic_string<CharT, Traits, Allocator> const & s )\n{\n    return std::basic_string_view<CharT, Traits>( s.data(), s.size() );\n}\n\n// Literal operators sv and _sv:\n\n#if nssv_CONFIG_STD_SV_OPERATOR\n\nusing namespace std::literals::string_view_literals;\n\n#endif\n\n#if nssv_CONFIG_USR_SV_OPERATOR\n\ninline namespace literals {\ninline namespace string_view_literals {\n\n\nconstexpr std::string_view operator \"\" _sv( const char* str, size_t len ) noexcept  // (1)\n{\n    return std::string_view{ str, len };\n}\n\nconstexpr std::u16string_view operator \"\" _sv( const char16_t* str, size_t len ) noexcept  // (2)\n{\n    return std::u16string_view{ str, len };\n}\n\nconstexpr std::u32string_view operator \"\" _sv( const char32_t* str, size_t len ) noexcept  // (3)\n{\n    return std::u32string_view{ str, len };\n}\n\nconstexpr std::wstring_view operator \"\" _sv( const wchar_t* str, size_t len ) noexcept  // (4)\n{\n    return std::wstring_view{ str, len };\n}\n\n}} // namespace literals::string_view_literals\n\n#endif // nssv_CONFIG_USR_SV_OPERATOR\n\n} // namespace nonstd\n\n#endif // nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS\n\nnamespace nonstd {\n\nusing std::string_view;\nusing std::wstring_view;\nusing std::u16string_view;\nusing std::u32string_view;\nusing std::basic_string_view;\n\n// literal \"sv\" and \"_sv\", see above\n\nusing std::operator==;\nusing std::operator!=;\nusing std::operator<;\nusing std::operator<=;\nusing std::operator>;\nusing std::operator>=;\n\nusing std::operator<<;\n\n} // namespace nonstd\n\n#else // nssv_HAVE_STD_STRING_VIEW\n\n//\n// Before C++17: use string_view lite:\n//\n\n// Compiler versions:\n//\n// MSVC++ 6.0  _MSC_VER == 1200 (Visual Studio 6.0)\n// MSVC++ 7.0  _MSC_VER == 1300 (Visual Studio .NET 2002)\n// MSVC++ 7.1  _MSC_VER == 1310 (Visual Studio .NET 2003)\n// MSVC++ 8.0  _MSC_VER == 1400 (Visual Studio 2005)\n// MSVC++ 9.0  _MSC_VER == 1500 (Visual Studio 2008)\n// MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)\n// MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)\n// MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)\n// MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)\n// MSVC++ 14.1 _MSC_VER >= 1910 (Visual Studio 2017)\n\n#if defined(_MSC_VER ) && !defined(__clang__)\n# define nssv_COMPILER_MSVC_VER      (_MSC_VER )\n# define nssv_COMPILER_MSVC_VERSION  (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) )\n#else\n# define nssv_COMPILER_MSVC_VER      0\n# define nssv_COMPILER_MSVC_VERSION  0\n#endif\n\n#define nssv_COMPILER_VERSION( major, minor, patch )  (10 * ( 10 * major + minor) + patch)\n\n#if defined(__clang__)\n# define nssv_COMPILER_CLANG_VERSION  nssv_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)\n#else\n# define nssv_COMPILER_CLANG_VERSION    0\n#endif\n\n#if defined(__GNUC__) && !defined(__clang__)\n# define nssv_COMPILER_GNUC_VERSION  nssv_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)\n#else\n# define nssv_COMPILER_GNUC_VERSION    0\n#endif\n\n// half-open range [lo..hi):\n#define nssv_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) )\n\n// Presence of language and library features:\n\n#ifdef _HAS_CPP0X\n# define nssv_HAS_CPP0X  _HAS_CPP0X\n#else\n# define nssv_HAS_CPP0X  0\n#endif\n\n// Unless defined otherwise below, consider VC14 as C++11 for variant-lite:\n\n#if nssv_COMPILER_MSVC_VER >= 1900\n# undef  nssv_CPP11_OR_GREATER\n# define nssv_CPP11_OR_GREATER  1\n#endif\n\n#define nssv_CPP11_90   (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1500)\n#define nssv_CPP11_100  (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1600)\n#define nssv_CPP11_110  (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1700)\n#define nssv_CPP11_120  (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1800)\n#define nssv_CPP11_140  (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1900)\n#define nssv_CPP11_141  (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1910)\n\n#define nssv_CPP14_000  (nssv_CPP14_OR_GREATER)\n#define nssv_CPP17_000  (nssv_CPP17_OR_GREATER)\n\n// Presence of C++11 language features:\n\n#define nssv_HAVE_CONSTEXPR_11          nssv_CPP11_140\n#define nssv_HAVE_EXPLICIT_CONVERSION   nssv_CPP11_140\n#define nssv_HAVE_INLINE_NAMESPACE      nssv_CPP11_140\n#define nssv_HAVE_NOEXCEPT              nssv_CPP11_140\n#define nssv_HAVE_NULLPTR               nssv_CPP11_100\n#define nssv_HAVE_REF_QUALIFIER         nssv_CPP11_140\n#define nssv_HAVE_UNICODE_LITERALS      nssv_CPP11_140\n#define nssv_HAVE_USER_DEFINED_LITERALS nssv_CPP11_140\n#define nssv_HAVE_WCHAR16_T             nssv_CPP11_100\n#define nssv_HAVE_WCHAR32_T             nssv_CPP11_100\n\n#if ! ( ( nssv_CPP11 && nssv_COMPILER_CLANG_VERSION ) || nssv_BETWEEN( nssv_COMPILER_CLANG_VERSION, 300, 400 ) )\n# define nssv_HAVE_STD_DEFINED_LITERALS  nssv_CPP11_140\n#endif\n\n// Presence of C++14 language features:\n\n#define nssv_HAVE_CONSTEXPR_14          nssv_CPP14_000\n\n// Presence of C++17 language features:\n\n#define nssv_HAVE_NODISCARD             nssv_CPP17_000\n\n// Presence of C++ library features:\n\n#define nssv_HAVE_STD_HASH              nssv_CPP11_120\n\n// C++ feature usage:\n\n#if nssv_HAVE_CONSTEXPR_11\n# define nssv_constexpr  constexpr\n#else\n# define nssv_constexpr  /*constexpr*/\n#endif\n\n#if  nssv_HAVE_CONSTEXPR_14\n# define nssv_constexpr14  constexpr\n#else\n# define nssv_constexpr14  /*constexpr*/\n#endif\n\n#if nssv_HAVE_EXPLICIT_CONVERSION\n# define nssv_explicit  explicit\n#else\n# define nssv_explicit  /*explicit*/\n#endif\n\n#if nssv_HAVE_INLINE_NAMESPACE\n# define nssv_inline_ns  inline\n#else\n# define nssv_inline_ns  /*inline*/\n#endif\n\n#if nssv_HAVE_NOEXCEPT\n# define nssv_noexcept  noexcept\n#else\n# define nssv_noexcept  /*noexcept*/\n#endif\n\n//#if nssv_HAVE_REF_QUALIFIER\n//# define nssv_ref_qual  &\n//# define nssv_refref_qual  &&\n//#else\n//# define nssv_ref_qual  /*&*/\n//# define nssv_refref_qual  /*&&*/\n//#endif\n\n#if nssv_HAVE_NULLPTR\n# define nssv_nullptr  nullptr\n#else\n# define nssv_nullptr  NULL\n#endif\n\n#if nssv_HAVE_NODISCARD\n# define nssv_nodiscard  [[nodiscard]]\n#else\n# define nssv_nodiscard  /*[[nodiscard]]*/\n#endif\n\n// Additional includes:\n\n#include <algorithm>\n#include <cassert>\n#include <iterator>\n#include <limits>\n#include <ostream>\n#include <string>   // std::char_traits<>\n\n#if ! nssv_CONFIG_NO_EXCEPTIONS\n# include <stdexcept>\n#endif\n\n#if nssv_CPP11_OR_GREATER\n# include <type_traits>\n#endif\n\n// Clang, GNUC, MSVC warning suppression macros:\n\n#if defined(__clang__)\n# pragma clang diagnostic ignored \"-Wreserved-user-defined-literal\"\n# pragma clang diagnostic push\n# pragma clang diagnostic ignored \"-Wuser-defined-literals\"\n#elif defined(__GNUC__)\n# pragma  GCC  diagnostic push\n# pragma  GCC  diagnostic ignored \"-Wliteral-suffix\"\n#endif // __clang__\n\n#if nssv_COMPILER_MSVC_VERSION >= 140\n# define nssv_SUPPRESS_MSGSL_WARNING(expr)        [[gsl::suppress(expr)]]\n# define nssv_SUPPRESS_MSVC_WARNING(code, descr)  __pragma(warning(suppress: code) )\n# define nssv_DISABLE_MSVC_WARNINGS(codes)        __pragma(warning(push))  __pragma(warning(disable: codes))\n#else\n# define nssv_SUPPRESS_MSGSL_WARNING(expr)\n# define nssv_SUPPRESS_MSVC_WARNING(code, descr)\n# define nssv_DISABLE_MSVC_WARNINGS(codes)\n#endif\n\n#if defined(__clang__)\n# define nssv_RESTORE_WARNINGS()  _Pragma(\"clang diagnostic pop\")\n#elif defined(__GNUC__)\n# define nssv_RESTORE_WARNINGS()  _Pragma(\"GCC diagnostic pop\")\n#elif nssv_COMPILER_MSVC_VERSION >= 140\n# define nssv_RESTORE_WARNINGS()  __pragma(warning(pop ))\n#else\n# define nssv_RESTORE_WARNINGS()\n#endif\n\n// Suppress the following MSVC (GSL) warnings:\n// - C4455, non-gsl   : 'operator \"\"sv': literal suffix identifiers that do not\n//                      start with an underscore are reserved\n// - C26472, gsl::t.1 : don't use a static_cast for arithmetic conversions;\n//                      use brace initialization, gsl::narrow_cast or gsl::narow\n// - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead\n\nnssv_DISABLE_MSVC_WARNINGS( 4455 26481 26472 )\n//nssv_DISABLE_CLANG_WARNINGS( \"-Wuser-defined-literals\" )\n//nssv_DISABLE_GNUC_WARNINGS( -Wliteral-suffix )\n\nnamespace nonstd { namespace sv_lite {\n\ntemplate\n<\n    class CharT,\n    class Traits = std::char_traits<CharT>\n>\nclass basic_string_view;\n\n//\n// basic_string_view:\n//\n\ntemplate\n<\n    class CharT,\n    class Traits /* = std::char_traits<CharT> */\n>\nclass basic_string_view\n{\npublic:\n    // Member types:\n\n    typedef Traits traits_type;\n    typedef CharT  value_type;\n\n    typedef CharT       * pointer;\n    typedef CharT const * const_pointer;\n    typedef CharT       & reference;\n    typedef CharT const & const_reference;\n\n    typedef const_pointer iterator;\n    typedef const_pointer const_iterator;\n    typedef std::reverse_iterator< const_iterator > reverse_iterator;\n    typedef\tstd::reverse_iterator< const_iterator > const_reverse_iterator;\n\n    typedef std::size_t     size_type;\n    typedef std::ptrdiff_t  difference_type;\n\n    // 24.4.2.1 Construction and assignment:\n\n    nssv_constexpr basic_string_view() nssv_noexcept\n        : data_( nssv_nullptr )\n        , size_( 0 )\n    {}\n\n#if nssv_CPP11_OR_GREATER\n    nssv_constexpr basic_string_view( basic_string_view const & other ) nssv_noexcept = default;\n#else\n    nssv_constexpr basic_string_view( basic_string_view const & other ) nssv_noexcept\n        : data_( other.data_)\n        , size_( other.size_)\n    {}\n#endif\n\n    nssv_constexpr basic_string_view( CharT const * s, size_type count )\n        : data_( s )\n        , size_( count )\n    {}\n\n    nssv_constexpr basic_string_view( CharT const * s)\n        : data_( s )\n        , size_( Traits::length(s) )\n    {}\n\n    // Assignment:\n\n#if nssv_CPP11_OR_GREATER\n    nssv_constexpr14 basic_string_view & operator=( basic_string_view const & other ) nssv_noexcept = default;\n#else\n    nssv_constexpr14 basic_string_view & operator=( basic_string_view const & other ) nssv_noexcept\n    {\n        data_ = other.data_;\n        size_ = other.size_;\n        return *this;\n    }\n#endif\n\n    // 24.4.2.2 Iterator support:\n\n    nssv_constexpr const_iterator begin()  const nssv_noexcept { return data_;         }\n    nssv_constexpr const_iterator end()    const nssv_noexcept { return data_ + size_; }\n\n    nssv_constexpr const_iterator cbegin() const nssv_noexcept { return begin(); }\n    nssv_constexpr const_iterator cend()   const nssv_noexcept { return end();   }\n\n    nssv_constexpr const_reverse_iterator rbegin()  const nssv_noexcept { return const_reverse_iterator( end() );   }\n    nssv_constexpr const_reverse_iterator rend()    const nssv_noexcept { return const_reverse_iterator( begin() ); }\n\n    nssv_constexpr const_reverse_iterator crbegin() const nssv_noexcept { return rbegin(); }\n    nssv_constexpr const_reverse_iterator crend()   const nssv_noexcept { return rend();   }\n\n    // 24.4.2.3 Capacity:\n\n    nssv_constexpr size_type size()     const nssv_noexcept { return size_; }\n    nssv_constexpr size_type length()   const nssv_noexcept { return size_; }\n    nssv_constexpr size_type max_size() const nssv_noexcept { return (std::numeric_limits< size_type >::max)(); }\n\n    // since C++20\n    nssv_nodiscard nssv_constexpr bool empty() const nssv_noexcept\n    {\n        return 0 == size_;\n    }\n\n    // 24.4.2.4 Element access:\n\n    nssv_constexpr const_reference operator[]( size_type pos ) const\n    {\n        return data_at( pos );\n    }\n\n    nssv_constexpr14 const_reference at( size_type pos ) const\n    {\n#if nssv_CONFIG_NO_EXCEPTIONS\n        assert( pos < size() );\n#else\n        if ( pos >= size() )\n        {\n            throw std::out_of_range(\"nonst::string_view::at()\");\n        }\n#endif\n        return data_at( pos );\n    }\n\n    nssv_constexpr const_reference front() const { return data_at( 0 );          }\n    nssv_constexpr const_reference back()  const { return data_at( size() - 1 ); }\n\n    nssv_constexpr const_pointer   data()  const nssv_noexcept { return data_; }\n\n    // 24.4.2.5 Modifiers:\n\n    nssv_constexpr14 void remove_prefix( size_type n )\n    {\n        assert( n <= size() );\n        data_ += n;\n        size_ -= n;\n    }\n\n    nssv_constexpr14 void remove_suffix( size_type n )\n    {\n        assert( n <= size() );\n        size_ -= n;\n    }\n\n    nssv_constexpr14 void swap( basic_string_view & other ) nssv_noexcept\n    {\n        using std::swap;\n        swap( data_, other.data_ );\n        swap( size_, other.size_ );\n    }\n\n    // 24.4.2.6 String operations:\n\n    size_type copy( CharT * dest, size_type n, size_type pos = 0 ) const\n    {\n#if nssv_CONFIG_NO_EXCEPTIONS\n        assert( pos <= size() );\n#else\n        if ( pos > size() )\n        {\n            throw std::out_of_range(\"nonst::string_view::copy()\");\n        }\n#endif\n        const size_type rlen = (std::min)( n, size() - pos );\n\n        (void) Traits::copy( dest, data() + pos, rlen );\n\n        return rlen;\n    }\n\n    nssv_constexpr14 basic_string_view substr( size_type pos = 0, size_type n = npos ) const\n    {\n#if nssv_CONFIG_NO_EXCEPTIONS\n        assert( pos <= size() );\n#else\n        if ( pos > size() )\n        {\n            throw std::out_of_range(\"nonst::string_view::substr()\");\n        }\n#endif\n        return basic_string_view( data() + pos, (std::min)( n, size() - pos ) );\n    }\n\n    // compare(), 6x:\n\n    nssv_constexpr14 int compare( basic_string_view other ) const nssv_noexcept // (1)\n    {\n        if ( const int result = Traits::compare( data(), other.data(), (std::min)( size(), other.size() ) ) )\n            return result;\n\n        return size() == other.size() ? 0 : size() < other.size() ? -1 : 1;\n    }\n\n    nssv_constexpr int compare( size_type pos1, size_type n1, basic_string_view other ) const // (2)\n    {\n        return substr( pos1, n1 ).compare( other );\n    }\n\n    nssv_constexpr int compare( size_type pos1, size_type n1, basic_string_view other, size_type pos2, size_type n2 ) const // (3)\n    {\n        return substr( pos1, n1 ).compare( other.substr( pos2, n2 ) );\n    }\n\n    nssv_constexpr int compare( CharT const * s ) const // (4)\n    {\n        return compare( basic_string_view( s ) );\n    }\n\n    nssv_constexpr int compare( size_type pos1, size_type n1, CharT const * s ) const // (5)\n    {\n        return substr( pos1, n1 ).compare( basic_string_view( s ) );\n    }\n\n    nssv_constexpr int compare( size_type pos1, size_type n1, CharT const * s, size_type n2 ) const // (6)\n    {\n        return substr( pos1, n1 ).compare( basic_string_view( s, n2 ) );\n    }\n\n    // 24.4.2.7 Searching:\n\n    // starts_with(), 3x, since C++20:\n\n    nssv_constexpr bool starts_with( basic_string_view v ) const nssv_noexcept  // (1)\n    {\n        return size() >= v.size() && compare( 0, v.size(), v ) == 0;\n    }\n\n    nssv_constexpr bool starts_with( CharT c ) const nssv_noexcept  // (2)\n    {\n        return starts_with( basic_string_view( &c, 1 ) );\n    }\n\n    nssv_constexpr bool starts_with( CharT const * s ) const  // (3)\n    {\n        return starts_with( basic_string_view( s ) );\n    }\n\n    // ends_with(), 3x, since C++20:\n\n    nssv_constexpr bool ends_with( basic_string_view v ) const nssv_noexcept  // (1)\n    {\n        return size() >= v.size() && compare( size() - v.size(), npos, v ) == 0;\n    }\n\n    nssv_constexpr bool ends_with( CharT c ) const nssv_noexcept  // (2)\n    {\n        return ends_with( basic_string_view( &c, 1 ) );\n    }\n\n    nssv_constexpr bool ends_with( CharT const * s ) const  // (3)\n    {\n        return ends_with( basic_string_view( s ) );\n    }\n\n    // find(), 4x:\n\n    nssv_constexpr14 size_type find( basic_string_view v, size_type pos = 0 ) const nssv_noexcept  // (1)\n    {\n        return assert( v.size() == 0 || v.data() != nssv_nullptr )\n            , pos >= size()\n            ? npos\n            : to_pos( std::search( cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq ) );\n    }\n\n    nssv_constexpr14 size_type find( CharT c, size_type pos = 0 ) const nssv_noexcept  // (2)\n    {\n        return find( basic_string_view( &c, 1 ), pos );\n    }\n\n    nssv_constexpr14 size_type find( CharT const * s, size_type pos, size_type n ) const  // (3)\n    {\n        return find( basic_string_view( s, n ), pos );\n    }\n\n    nssv_constexpr14 size_type find( CharT const * s, size_type pos = 0 ) const  // (4)\n    {\n        return find( basic_string_view( s ), pos );\n    }\n\n    // rfind(), 4x:\n\n    nssv_constexpr14 size_type rfind( basic_string_view v, size_type pos = npos ) const nssv_noexcept  // (1)\n    {\n        if ( size() < v.size() )\n            return npos;\n\n        if ( v.empty() )\n            return (std::min)( size(), pos );\n\n        const_iterator last   = cbegin() + (std::min)( size() - v.size(), pos ) + v.size();\n        const_iterator result = std::find_end( cbegin(), last, v.cbegin(), v.cend(), Traits::eq );\n\n        return result != last ? size_type( result - cbegin() ) : npos;\n    }\n\n    nssv_constexpr14 size_type rfind( CharT c, size_type pos = npos ) const nssv_noexcept  // (2)\n    {\n        return rfind( basic_string_view( &c, 1 ), pos );\n    }\n\n    nssv_constexpr14 size_type rfind( CharT const * s, size_type pos, size_type n ) const  // (3)\n    {\n        return rfind( basic_string_view( s, n ), pos );\n    }\n\n    nssv_constexpr14 size_type rfind( CharT const * s, size_type pos = npos ) const  // (4)\n    {\n        return rfind( basic_string_view( s ), pos );\n    }\n\n    // find_first_of(), 4x:\n\n    nssv_constexpr size_type find_first_of( basic_string_view v, size_type pos = 0 ) const nssv_noexcept  // (1)\n    {\n        return pos >= size()\n            ? npos\n            : to_pos( std::find_first_of( cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq ) );\n    }\n\n    nssv_constexpr size_type find_first_of( CharT c, size_type pos = 0 ) const nssv_noexcept  // (2)\n    {\n        return find_first_of( basic_string_view( &c, 1 ), pos );\n    }\n\n    nssv_constexpr size_type find_first_of( CharT const * s, size_type pos, size_type n ) const  // (3)\n    {\n        return find_first_of( basic_string_view( s, n ), pos );\n    }\n\n    nssv_constexpr size_type find_first_of(  CharT const * s, size_type pos = 0 ) const  // (4)\n    {\n        return find_first_of( basic_string_view( s ), pos );\n    }\n\n    // find_last_of(), 4x:\n\n    nssv_constexpr size_type find_last_of( basic_string_view v, size_type pos = npos ) const nssv_noexcept  // (1)\n    {\n        return empty()\n            ? npos\n            : pos >= size()\n            ? find_last_of( v, size() - 1 )\n            : to_pos( std::find_first_of( const_reverse_iterator( cbegin() + pos + 1 ), crend(), v.cbegin(), v.cend(), Traits::eq ) );\n    }\n\n    nssv_constexpr size_type find_last_of( CharT c, size_type pos = npos ) const nssv_noexcept  // (2)\n    {\n        return find_last_of( basic_string_view( &c, 1 ), pos );\n    }\n\n    nssv_constexpr size_type find_last_of( CharT const * s, size_type pos, size_type count ) const  // (3)\n    {\n        return find_last_of( basic_string_view( s, count ), pos );\n    }\n\n    nssv_constexpr size_type find_last_of( CharT const * s, size_type pos = npos ) const  // (4)\n    {\n        return find_last_of( basic_string_view( s ), pos );\n    }\n\n    // find_first_not_of(), 4x:\n\n    nssv_constexpr size_type find_first_not_of( basic_string_view v, size_type pos = 0 ) const nssv_noexcept  // (1)\n    {\n        return pos >= size()\n            ? npos\n            : to_pos( std::find_if( cbegin() + pos, cend(), not_in_view( v ) ) );\n    }\n\n    nssv_constexpr size_type find_first_not_of( CharT c, size_type pos = 0 ) const nssv_noexcept  // (2)\n    {\n        return find_first_not_of( basic_string_view( &c, 1 ), pos );\n    }\n\n    nssv_constexpr size_type find_first_not_of( CharT const * s, size_type pos, size_type count ) const  // (3)\n    {\n        return find_first_not_of( basic_string_view( s, count ), pos );\n    }\n\n    nssv_constexpr size_type find_first_not_of( CharT const * s, size_type pos = 0 ) const  // (4)\n    {\n        return find_first_not_of( basic_string_view( s ), pos );\n    }\n\n    // find_last_not_of(), 4x:\n\n    nssv_constexpr size_type find_last_not_of( basic_string_view v, size_type pos = npos ) const nssv_noexcept  // (1)\n    {\n        return empty()\n            ? npos\n            : pos >= size()\n            ? find_last_not_of( v, size() - 1 )\n            : to_pos( std::find_if( const_reverse_iterator( cbegin() + pos + 1 ), crend(), not_in_view( v ) ) );\n    }\n\n    nssv_constexpr size_type find_last_not_of( CharT c, size_type pos = npos ) const nssv_noexcept  // (2)\n    {\n        return find_last_not_of( basic_string_view( &c, 1 ), pos );\n    }\n\n    nssv_constexpr size_type find_last_not_of( CharT const * s, size_type pos, size_type count ) const  // (3)\n    {\n        return find_last_not_of( basic_string_view( s, count ), pos );\n    }\n\n    nssv_constexpr size_type find_last_not_of( CharT const * s, size_type pos = npos ) const  // (4)\n    {\n        return find_last_not_of( basic_string_view( s ), pos );\n    }\n\n    // Constants:\n\n#if nssv_CPP17_OR_GREATER\n    static nssv_constexpr size_type npos = size_type(-1);\n#elif nssv_CPP11_OR_GREATER\n    enum : size_type { npos = size_type(-1) };\n#else\n    enum { npos = size_type(-1) };\n#endif\n\nprivate:\n    struct not_in_view\n    {\n        const basic_string_view v;\n\n        nssv_constexpr not_in_view( basic_string_view v ) : v( v ) {}\n\n        nssv_constexpr bool operator()( CharT c ) const\n        {\n            return npos == v.find_first_of( c );\n        }\n    };\n\n    nssv_constexpr size_type to_pos( const_iterator it ) const\n    {\n        return it == cend() ? npos : size_type( it - cbegin() );\n    }\n\n    nssv_constexpr size_type to_pos( const_reverse_iterator it ) const\n    {\n        return it == crend() ? npos : size_type( crend() - it - 1 );\n    }\n\n    nssv_constexpr const_reference data_at( size_type pos ) const\n    {\n#if nssv_BETWEEN( nssv_COMPILER_GNUC_VERSION, 1, 500 )\n        return data_[pos];\n#else\n        return assert( pos < size() ), data_[pos];\n#endif\n    }\n\nprivate:\n    const_pointer data_;\n    size_type     size_;\n\npublic:\n#if nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS\n\n    template< class Allocator >\n    basic_string_view( std::basic_string<CharT, Traits, Allocator> const & s ) nssv_noexcept\n        : data_( s.data() )\n        , size_( s.size() )\n    {}\n\n#if nssv_HAVE_EXPLICIT_CONVERSION\n\n    template< class Allocator >\n    explicit operator std::basic_string<CharT, Traits, Allocator>() const\n    {\n        return to_string( Allocator() );\n    }\n\n#endif // nssv_HAVE_EXPLICIT_CONVERSION\n\n#if nssv_CPP11_OR_GREATER\n\n    template< class Allocator = std::allocator<CharT> >\n    std::basic_string<CharT, Traits, Allocator>\n    to_string( Allocator const & a = Allocator() ) const\n    {\n        return std::basic_string<CharT, Traits, Allocator>( begin(), end(), a );\n    }\n\n#else\n\n    std::basic_string<CharT, Traits>\n    to_string() const\n    {\n        return std::basic_string<CharT, Traits>( begin(), end() );\n    }\n\n    template< class Allocator >\n    std::basic_string<CharT, Traits, Allocator>\n    to_string( Allocator const & a ) const\n    {\n        return std::basic_string<CharT, Traits, Allocator>( begin(), end(), a );\n    }\n\n#endif // nssv_CPP11_OR_GREATER\n\n#endif // nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS\n};\n\n//\n// Non-member functions:\n//\n\n// 24.4.3 Non-member comparison functions:\n// lexicographically compare two string views (function template):\n\ntemplate< class CharT, class Traits >\nnssv_constexpr bool operator== (\n    basic_string_view <CharT, Traits> lhs,\n    basic_string_view <CharT, Traits> rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) == 0 ; }\n\ntemplate< class CharT, class Traits >\nnssv_constexpr bool operator!= (\n    basic_string_view <CharT, Traits> lhs,\n    basic_string_view <CharT, Traits> rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) != 0 ; }\n\ntemplate< class CharT, class Traits >\nnssv_constexpr bool operator< (\n    basic_string_view <CharT, Traits> lhs,\n    basic_string_view <CharT, Traits> rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) < 0 ; }\n\ntemplate< class CharT, class Traits >\nnssv_constexpr bool operator<= (\n    basic_string_view <CharT, Traits> lhs,\n    basic_string_view <CharT, Traits> rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) <= 0 ; }\n\ntemplate< class CharT, class Traits >\nnssv_constexpr bool operator> (\n    basic_string_view <CharT, Traits> lhs,\n    basic_string_view <CharT, Traits> rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) > 0 ; }\n\ntemplate< class CharT, class Traits >\nnssv_constexpr bool operator>= (\n    basic_string_view <CharT, Traits> lhs,\n    basic_string_view <CharT, Traits> rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) >= 0 ; }\n\n// Let S be basic_string_view<CharT, Traits>, and sv be an instance of S.\n// Implementations shall provide sufficient additional overloads marked\n// constexpr and noexcept so that an object t with an implicit conversion\n// to S can be compared according to Table 67.\n\n#if nssv_CPP11_OR_GREATER && ! nssv_BETWEEN( nssv_COMPILER_MSVC_VERSION, 100, 141 )\n\n#define nssv_BASIC_STRING_VIEW_I(T,U)  typename std::decay< basic_string_view<T,U> >::type\n\n#if nssv_BETWEEN( nssv_COMPILER_MSVC_VERSION, 140, 150 )\n# define nssv_MSVC_ORDER(x)  , int=x\n#else\n# define nssv_MSVC_ORDER(x)  /*, int=x*/\n#endif\n\n// ==\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(1) >\nnssv_constexpr bool operator==(\n         basic_string_view  <CharT, Traits> lhs,\n    nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) == 0; }\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(2) >\nnssv_constexpr bool operator==(\n    nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs,\n         basic_string_view  <CharT, Traits> rhs ) nssv_noexcept\n{ return lhs.size() == rhs.size() && lhs.compare( rhs ) == 0; }\n\n// !=\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(1) >\nnssv_constexpr bool operator!= (\n         basic_string_view  < CharT, Traits > lhs,\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept\n{ return lhs.size() != rhs.size() || lhs.compare( rhs ) != 0 ; }\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(2) >\nnssv_constexpr bool operator!= (\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,\n         basic_string_view  < CharT, Traits > rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) != 0 ; }\n\n// <\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(1) >\nnssv_constexpr bool operator< (\n         basic_string_view  < CharT, Traits > lhs,\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) < 0 ; }\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(2) >\nnssv_constexpr bool operator< (\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,\n         basic_string_view  < CharT, Traits > rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) < 0 ; }\n\n// <=\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(1) >\nnssv_constexpr bool operator<= (\n         basic_string_view  < CharT, Traits > lhs,\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) <= 0 ; }\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(2) >\nnssv_constexpr bool operator<= (\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,\n         basic_string_view  < CharT, Traits > rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) <= 0 ; }\n\n// >\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(1) >\nnssv_constexpr bool operator> (\n         basic_string_view  < CharT, Traits > lhs,\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) > 0 ; }\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(2) >\nnssv_constexpr bool operator> (\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,\n         basic_string_view  < CharT, Traits > rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) > 0 ; }\n\n// >=\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(1) >\nnssv_constexpr bool operator>= (\n         basic_string_view  < CharT, Traits > lhs,\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) >= 0 ; }\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(2) >\nnssv_constexpr bool operator>= (\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,\n         basic_string_view  < CharT, Traits > rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) >= 0 ; }\n\n#undef nssv_MSVC_ORDER\n#undef nssv_BASIC_STRING_VIEW_I\n\n#endif // nssv_CPP11_OR_GREATER\n\n// 24.4.4 Inserters and extractors:\n\nnamespace detail {\n\ntemplate< class Stream >\nvoid write_padding( Stream & os, std::streamsize n )\n{\n    for ( std::streamsize i = 0; i < n; ++i )\n        os.rdbuf()->sputc( os.fill() );\n}\n\ntemplate< class Stream, class View >\nStream & write_to_stream( Stream & os, View const & sv )\n{\n    typename Stream::sentry sentry( os );\n\n    if ( !os )\n        return os;\n\n    const std::streamsize length = static_cast<std::streamsize>( sv.length() );\n\n    // Whether, and how, to pad:\n    const bool      pad = ( length < os.width() );\n    const bool left_pad = pad && ( os.flags() & std::ios_base::adjustfield ) == std::ios_base::right;\n\n    if ( left_pad )\n        write_padding( os, os.width() - length );\n\n    // Write span characters:\n    os.rdbuf()->sputn( sv.begin(), length );\n\n    if ( pad && !left_pad )\n        write_padding( os, os.width() - length );\n\n    // Reset output stream width:\n    os.width( 0 );\n\n    return os;\n}\n\n} // namespace detail\n\ntemplate< class CharT, class Traits >\nstd::basic_ostream<CharT, Traits> &\noperator<<(\n    std::basic_ostream<CharT, Traits>& os,\n    basic_string_view <CharT, Traits> sv )\n{\n    return detail::write_to_stream( os, sv );\n}\n\n// Several typedefs for common character types are provided:\n\ntypedef basic_string_view<char>      string_view;\ntypedef basic_string_view<wchar_t>   wstring_view;\n#if nssv_HAVE_WCHAR16_T\ntypedef basic_string_view<char16_t>  u16string_view;\ntypedef basic_string_view<char32_t>  u32string_view;\n#endif\n\n}} // namespace nonstd::sv_lite\n\n//\n// 24.4.6 Suffix for basic_string_view literals:\n//\n\n#if nssv_HAVE_USER_DEFINED_LITERALS\n\nnamespace nonstd {\nnssv_inline_ns namespace literals {\nnssv_inline_ns namespace string_view_literals {\n\n#if nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS\n\nnssv_constexpr nonstd::sv_lite::string_view operator \"\" sv( const char* str, size_t len ) nssv_noexcept  // (1)\n{\n    return nonstd::sv_lite::string_view{ str, len };\n}\n\nnssv_constexpr nonstd::sv_lite::u16string_view operator \"\" sv( const char16_t* str, size_t len ) nssv_noexcept  // (2)\n{\n    return nonstd::sv_lite::u16string_view{ str, len };\n}\n\nnssv_constexpr nonstd::sv_lite::u32string_view operator \"\" sv( const char32_t* str, size_t len ) nssv_noexcept  // (3)\n{\n    return nonstd::sv_lite::u32string_view{ str, len };\n}\n\nnssv_constexpr nonstd::sv_lite::wstring_view operator \"\" sv( const wchar_t* str, size_t len ) nssv_noexcept  // (4)\n{\n    return nonstd::sv_lite::wstring_view{ str, len };\n}\n\n#endif // nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS\n\n#if nssv_CONFIG_USR_SV_OPERATOR\n\nnssv_constexpr nonstd::sv_lite::string_view operator \"\" _sv( const char* str, size_t len ) nssv_noexcept  // (1)\n{\n    return nonstd::sv_lite::string_view{ str, len };\n}\n\nnssv_constexpr nonstd::sv_lite::u16string_view operator \"\" _sv( const char16_t* str, size_t len ) nssv_noexcept  // (2)\n{\n    return nonstd::sv_lite::u16string_view{ str, len };\n}\n\nnssv_constexpr nonstd::sv_lite::u32string_view operator \"\" _sv( const char32_t* str, size_t len ) nssv_noexcept  // (3)\n{\n    return nonstd::sv_lite::u32string_view{ str, len };\n}\n\nnssv_constexpr nonstd::sv_lite::wstring_view operator \"\" _sv( const wchar_t* str, size_t len ) nssv_noexcept  // (4)\n{\n    return nonstd::sv_lite::wstring_view{ str, len };\n}\n\n#endif // nssv_CONFIG_USR_SV_OPERATOR\n\n}}} // namespace nonstd::literals::string_view_literals\n\n#endif\n\n//\n// Extensions for std::string:\n//\n\n#if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS\n\nnamespace nonstd {\nnamespace sv_lite {\n\n// Exclude MSVC 14 (19.00): it yields ambiguous to_string():\n\n#if nssv_CPP11_OR_GREATER && nssv_COMPILER_MSVC_VERSION != 140\n\ntemplate< class CharT, class Traits, class Allocator = std::allocator<CharT> >\nstd::basic_string<CharT, Traits, Allocator>\nto_string( basic_string_view<CharT, Traits> v, Allocator const & a = Allocator() )\n{\n    return std::basic_string<CharT,Traits, Allocator>( v.begin(), v.end(), a );\n}\n\n#else\n\ntemplate< class CharT, class Traits >\nstd::basic_string<CharT, Traits>\nto_string( basic_string_view<CharT, Traits> v )\n{\n    return std::basic_string<CharT, Traits>( v.begin(), v.end() );\n}\n\ntemplate< class CharT, class Traits, class Allocator >\nstd::basic_string<CharT, Traits, Allocator>\nto_string( basic_string_view<CharT, Traits> v, Allocator const & a )\n{\n    return std::basic_string<CharT, Traits, Allocator>( v.begin(), v.end(), a );\n}\n\n#endif // nssv_CPP11_OR_GREATER\n\ntemplate< class CharT, class Traits, class Allocator >\nbasic_string_view<CharT, Traits>\nto_string_view( std::basic_string<CharT, Traits, Allocator> const & s )\n{\n    return basic_string_view<CharT, Traits>( s.data(), s.size() );\n}\n\n}} // namespace nonstd::sv_lite\n\n#endif // nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS\n\n//\n// make types and algorithms available in namespace nonstd:\n//\n\nnamespace nonstd {\n\nusing sv_lite::basic_string_view;\nusing sv_lite::string_view;\nusing sv_lite::wstring_view;\n\n#if nssv_HAVE_WCHAR16_T\nusing sv_lite::u16string_view;\n#endif\n#if nssv_HAVE_WCHAR32_T\nusing sv_lite::u32string_view;\n#endif\n\n// literal \"sv\"\n\nusing sv_lite::operator==;\nusing sv_lite::operator!=;\nusing sv_lite::operator<;\nusing sv_lite::operator<=;\nusing sv_lite::operator>;\nusing sv_lite::operator>=;\n\nusing sv_lite::operator<<;\n\n#if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS\nusing sv_lite::to_string;\nusing sv_lite::to_string_view;\n#endif\n\n} // namespace nonstd\n\n// 24.4.5 Hash support (C++11):\n\n// Note: The hash value of a string view object is equal to the hash value of\n// the corresponding string object.\n\n#if nssv_HAVE_STD_HASH\n\n#include <functional>\n\nnamespace std {\n\ntemplate<>\nstruct hash< nonstd::string_view >\n{\npublic:\n    std::size_t operator()( nonstd::string_view v ) const nssv_noexcept\n    {\n        return std::hash<std::string>()( std::string( v.data(), v.size() ) );\n    }\n};\n\ntemplate<>\nstruct hash< nonstd::wstring_view >\n{\npublic:\n    std::size_t operator()( nonstd::wstring_view v ) const nssv_noexcept\n    {\n        return std::hash<std::wstring>()( std::wstring( v.data(), v.size() ) );\n    }\n};\n\ntemplate<>\nstruct hash< nonstd::u16string_view >\n{\npublic:\n    std::size_t operator()( nonstd::u16string_view v ) const nssv_noexcept\n    {\n        return std::hash<std::u16string>()( std::u16string( v.data(), v.size() ) );\n    }\n};\n\ntemplate<>\nstruct hash< nonstd::u32string_view >\n{\npublic:\n    std::size_t operator()( nonstd::u32string_view v ) const nssv_noexcept\n    {\n        return std::hash<std::u32string>()( std::u32string( v.data(), v.size() ) );\n    }\n};\n\n} // namespace std\n\n#endif // nssv_HAVE_STD_HASH\n\nnssv_RESTORE_WARNINGS()\n\n#endif // nssv_HAVE_STD_STRING_VIEW\n#endif // NONSTD_SV_LITE_H_INCLUDED\n\n\n  // If there is another version of Hedley, then the newer one \n  // takes precedence.\n  // See: https://github.com/nemequ/hedley\n/* Hedley - https://nemequ.github.io/hedley\n * Created by Evan Nemerson <evan@nemerson.com>\n *\n * To the extent possible under law, the author(s) have dedicated all\n * copyright and related and neighboring rights to this software to\n * the public domain worldwide. This software is distributed without\n * any warranty.\n *\n * For details, see <http://creativecommons.org/publicdomain/zero/1.0/>.\n * SPDX-License-Identifier: CC0-1.0\n */\n\n#if !defined(HEDLEY_VERSION) || (HEDLEY_VERSION < 9)\n#if defined(HEDLEY_VERSION)\n#  undef HEDLEY_VERSION\n#endif\n#define HEDLEY_VERSION 9\n\n#if defined(HEDLEY_STRINGIFY_EX)\n#  undef HEDLEY_STRINGIFY_EX\n#endif\n#define HEDLEY_STRINGIFY_EX(x) #x\n\n#if defined(HEDLEY_STRINGIFY)\n#  undef HEDLEY_STRINGIFY\n#endif\n#define HEDLEY_STRINGIFY(x) HEDLEY_STRINGIFY_EX(x)\n\n#if defined(HEDLEY_CONCAT_EX)\n#  undef HEDLEY_CONCAT_EX\n#endif\n#define HEDLEY_CONCAT_EX(a,b) a##b\n\n#if defined(HEDLEY_CONCAT)\n#  undef HEDLEY_CONCAT\n#endif\n#define HEDLEY_CONCAT(a,b) HEDLEY_CONCAT_EX(a,b)\n\n#if defined(HEDLEY_VERSION_ENCODE)\n#  undef HEDLEY_VERSION_ENCODE\n#endif\n#define HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision))\n\n#if defined(HEDLEY_VERSION_DECODE_MAJOR)\n#  undef HEDLEY_VERSION_DECODE_MAJOR\n#endif\n#define HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000)\n\n#if defined(HEDLEY_VERSION_DECODE_MINOR)\n#  undef HEDLEY_VERSION_DECODE_MINOR\n#endif\n#define HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000)\n\n#if defined(HEDLEY_VERSION_DECODE_REVISION)\n#  undef HEDLEY_VERSION_DECODE_REVISION\n#endif\n#define HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000)\n\n#if defined(HEDLEY_GNUC_VERSION)\n#  undef HEDLEY_GNUC_VERSION\n#endif\n#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__)\n#  define HEDLEY_GNUC_VERSION HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)\n#elif defined(__GNUC__)\n#  define HEDLEY_GNUC_VERSION HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0)\n#endif\n\n#if defined(HEDLEY_GNUC_VERSION_CHECK)\n#  undef HEDLEY_GNUC_VERSION_CHECK\n#endif\n#if defined(HEDLEY_GNUC_VERSION)\n#  define HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (HEDLEY_GNUC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n#  define HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(HEDLEY_MSVC_VERSION)\n#  undef HEDLEY_MSVC_VERSION\n#endif\n#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000)\n#  define HEDLEY_MSVC_VERSION HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100)\n#elif defined(_MSC_FULL_VER)\n#  define HEDLEY_MSVC_VERSION HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10)\n#elif defined(_MSC_VER)\n#  define HEDLEY_MSVC_VERSION HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0)\n#endif\n\n#if defined(HEDLEY_MSVC_VERSION_CHECK)\n#  undef HEDLEY_MSVC_VERSION_CHECK\n#endif\n#if !defined(_MSC_VER)\n#  define HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0)\n#elif defined(_MSC_VER) && (_MSC_VER >= 1400)\n#  define HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch)))\n#elif defined(_MSC_VER) && (_MSC_VER >= 1200)\n#  define HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch)))\n#else\n#  define HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor)))\n#endif\n\n#if defined(HEDLEY_INTEL_VERSION)\n#  undef HEDLEY_INTEL_VERSION\n#endif\n#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE)\n#  define HEDLEY_INTEL_VERSION HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE)\n#elif defined(__INTEL_COMPILER)\n#  define HEDLEY_INTEL_VERSION HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0)\n#endif\n\n#if defined(HEDLEY_INTEL_VERSION_CHECK)\n#  undef HEDLEY_INTEL_VERSION_CHECK\n#endif\n#if defined(HEDLEY_INTEL_VERSION)\n#  define HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (HEDLEY_INTEL_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n#  define HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(HEDLEY_PGI_VERSION)\n#  undef HEDLEY_PGI_VERSION\n#endif\n#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__)\n#  define HEDLEY_PGI_VERSION HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__)\n#endif\n\n#if defined(HEDLEY_PGI_VERSION_CHECK)\n#  undef HEDLEY_PGI_VERSION_CHECK\n#endif\n#if defined(HEDLEY_PGI_VERSION)\n#  define HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (HEDLEY_PGI_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n#  define HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(HEDLEY_SUNPRO_VERSION)\n#  undef HEDLEY_SUNPRO_VERSION\n#endif\n#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)\n#  define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10)\n#elif defined(__SUNPRO_C)\n#  define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf)\n#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)\n#  define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10)\n#elif defined(__SUNPRO_CC)\n#  define HEDLEY_SUNPRO_VERSION HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf)\n#endif\n\n#if defined(HEDLEY_SUNPRO_VERSION_CHECK)\n#  undef HEDLEY_SUNPRO_VERSION_CHECK\n#endif\n#if defined(HEDLEY_SUNPRO_VERSION)\n#  define HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (HEDLEY_SUNPRO_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n#  define HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(HEDLEY_EMSCRIPTEN_VERSION)\n#  undef HEDLEY_EMSCRIPTEN_VERSION\n#endif\n#if defined(__EMSCRIPTEN__)\n#  define HEDLEY_EMSCRIPTEN_VERSION HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__)\n#endif\n\n#if defined(HEDLEY_EMSCRIPTEN_VERSION_CHECK)\n#  undef HEDLEY_EMSCRIPTEN_VERSION_CHECK\n#endif\n#if defined(HEDLEY_EMSCRIPTEN_VERSION)\n#  define HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (HEDLEY_EMSCRIPTEN_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n#  define HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(HEDLEY_ARM_VERSION)\n#  undef HEDLEY_ARM_VERSION\n#endif\n#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION)\n#  define HEDLEY_ARM_VERSION HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100)\n#elif defined(__CC_ARM) && defined(__ARMCC_VERSION)\n#  define HEDLEY_ARM_VERSION HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100)\n#endif\n\n#if defined(HEDLEY_ARM_VERSION_CHECK)\n#  undef HEDLEY_ARM_VERSION_CHECK\n#endif\n#if defined(HEDLEY_ARM_VERSION)\n#  define HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (HEDLEY_ARM_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n#  define HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(HEDLEY_IBM_VERSION)\n#  undef HEDLEY_IBM_VERSION\n#endif\n#if defined(__ibmxl__)\n#  define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__)\n#elif defined(__xlC__) && defined(__xlC_ver__)\n#  define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff)\n#elif defined(__xlC__)\n#  define HEDLEY_IBM_VERSION HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0)\n#endif\n\n#if defined(HEDLEY_IBM_VERSION_CHECK)\n#  undef HEDLEY_IBM_VERSION_CHECK\n#endif\n#if defined(HEDLEY_IBM_VERSION)\n#  define HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (HEDLEY_IBM_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n#  define HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(HEDLEY_TI_VERSION)\n#  undef HEDLEY_TI_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__)\n#  define HEDLEY_TI_VERSION HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(HEDLEY_TI_VERSION_CHECK)\n#  undef HEDLEY_TI_VERSION_CHECK\n#endif\n#if defined(HEDLEY_TI_VERSION)\n#  define HEDLEY_TI_VERSION_CHECK(major,minor,patch) (HEDLEY_TI_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n#  define HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(HEDLEY_CRAY_VERSION)\n#  undef HEDLEY_CRAY_VERSION\n#endif\n#if defined(_CRAYC)\n#  if defined(_RELEASE_PATCHLEVEL)\n#    define HEDLEY_CRAY_VERSION HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL)\n#  else\n#    define HEDLEY_CRAY_VERSION HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0)\n#  endif\n#endif\n\n#if defined(HEDLEY_CRAY_VERSION_CHECK)\n#  undef HEDLEY_CRAY_VERSION_CHECK\n#endif\n#if defined(HEDLEY_CRAY_VERSION)\n#  define HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (HEDLEY_CRAY_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n#  define HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(HEDLEY_IAR_VERSION)\n#  undef HEDLEY_IAR_VERSION\n#endif\n#if defined(__IAR_SYSTEMS_ICC__)\n#  if __VER__ > 1000\n#    define HEDLEY_IAR_VERSION HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000))\n#  else\n#    define HEDLEY_IAR_VERSION HEDLEY_VERSION_ENCODE(VER / 100, __VER__ % 100, 0)\n#  endif\n#endif\n\n#if defined(HEDLEY_IAR_VERSION_CHECK)\n#  undef HEDLEY_IAR_VERSION_CHECK\n#endif\n#if defined(HEDLEY_IAR_VERSION)\n#  define HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (HEDLEY_IAR_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n#  define HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(HEDLEY_TINYC_VERSION)\n#  undef HEDLEY_TINYC_VERSION\n#endif\n#if defined(__TINYC__)\n#  define HEDLEY_TINYC_VERSION HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100)\n#endif\n\n#if defined(HEDLEY_TINYC_VERSION_CHECK)\n#  undef HEDLEY_TINYC_VERSION_CHECK\n#endif\n#if defined(HEDLEY_TINYC_VERSION)\n#  define HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (HEDLEY_TINYC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n#  define HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(HEDLEY_DMC_VERSION)\n#  undef HEDLEY_DMC_VERSION\n#endif\n#if defined(__DMC__)\n#  define HEDLEY_DMC_VERSION HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf)\n#endif\n\n#if defined(HEDLEY_DMC_VERSION_CHECK)\n#  undef HEDLEY_DMC_VERSION_CHECK\n#endif\n#if defined(HEDLEY_DMC_VERSION)\n#  define HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (HEDLEY_DMC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n#  define HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(HEDLEY_COMPCERT_VERSION)\n#  undef HEDLEY_COMPCERT_VERSION\n#endif\n#if defined(__COMPCERT_VERSION__)\n#  define HEDLEY_COMPCERT_VERSION HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100)\n#endif\n\n#if defined(HEDLEY_COMPCERT_VERSION_CHECK)\n#  undef HEDLEY_COMPCERT_VERSION_CHECK\n#endif\n#if defined(HEDLEY_COMPCERT_VERSION)\n#  define HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (HEDLEY_COMPCERT_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n#  define HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(HEDLEY_PELLES_VERSION)\n#  undef HEDLEY_PELLES_VERSION\n#endif\n#if defined(__POCC__)\n#  define HEDLEY_PELLES_VERSION HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0)\n#endif\n\n#if defined(HEDLEY_PELLES_VERSION_CHECK)\n#  undef HEDLEY_PELLES_VERSION_CHECK\n#endif\n#if defined(HEDLEY_PELLES_VERSION)\n#  define HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (HEDLEY_PELLES_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n#  define HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(HEDLEY_GCC_VERSION)\n#  undef HEDLEY_GCC_VERSION\n#endif\n#if \\\n  defined(HEDLEY_GNUC_VERSION) && \\\n  !defined(__clang__) && \\\n  !defined(HEDLEY_INTEL_VERSION) && \\\n  !defined(HEDLEY_PGI_VERSION) && \\\n  !defined(HEDLEY_ARM_VERSION) && \\\n  !defined(HEDLEY_TI_VERSION) && \\\n  !defined(__COMPCERT__)\n#  define HEDLEY_GCC_VERSION HEDLEY_GNUC_VERSION\n#endif\n\n#if defined(HEDLEY_GCC_VERSION_CHECK)\n#  undef HEDLEY_GCC_VERSION_CHECK\n#endif\n#if defined(HEDLEY_GCC_VERSION)\n#  define HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (HEDLEY_GCC_VERSION >= HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n#  define HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(HEDLEY_HAS_ATTRIBUTE)\n#  undef HEDLEY_HAS_ATTRIBUTE\n#endif\n#if defined(__has_attribute)\n#  define HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute)\n#else\n#  define HEDLEY_HAS_ATTRIBUTE(attribute) (0)\n#endif\n\n#if defined(HEDLEY_GNUC_HAS_ATTRIBUTE)\n#  undef HEDLEY_GNUC_HAS_ATTRIBUTE\n#endif\n#if defined(__has_attribute)\n#  define HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute)\n#else\n#  define HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(HEDLEY_GCC_HAS_ATTRIBUTE)\n#  undef HEDLEY_GCC_HAS_ATTRIBUTE\n#endif\n#if defined(__has_attribute)\n#  define HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute)\n#else\n#  define HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(HEDLEY_HAS_CPP_ATTRIBUTE)\n#  undef HEDLEY_HAS_CPP_ATTRIBUTE\n#endif\n#if defined(__has_cpp_attribute) && defined(__cplusplus)\n#  define HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute)\n#else\n#  define HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0)\n#endif\n\n#if defined(HEDLEY_GNUC_HAS_CPP_ATTRIBUTE)\n#  undef HEDLEY_GNUC_HAS_CPP_ATTRIBUTE\n#endif\n#if defined(__has_cpp_attribute) && defined(__cplusplus)\n#  define HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)\n#else\n#  define HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(HEDLEY_GCC_HAS_CPP_ATTRIBUTE)\n#  undef HEDLEY_GCC_HAS_CPP_ATTRIBUTE\n#endif\n#if defined(__has_cpp_attribute) && defined(__cplusplus)\n#  define HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)\n#else\n#  define HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(HEDLEY_HAS_BUILTIN)\n#  undef HEDLEY_HAS_BUILTIN\n#endif\n#if defined(__has_builtin)\n#  define HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin)\n#else\n#  define HEDLEY_HAS_BUILTIN(builtin) (0)\n#endif\n\n#if defined(HEDLEY_GNUC_HAS_BUILTIN)\n#  undef HEDLEY_GNUC_HAS_BUILTIN\n#endif\n#if defined(__has_builtin)\n#  define HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)\n#else\n#  define HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(HEDLEY_GCC_HAS_BUILTIN)\n#  undef HEDLEY_GCC_HAS_BUILTIN\n#endif\n#if defined(__has_builtin)\n#  define HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)\n#else\n#  define HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(HEDLEY_HAS_FEATURE)\n#  undef HEDLEY_HAS_FEATURE\n#endif\n#if defined(__has_feature)\n#  define HEDLEY_HAS_FEATURE(feature) __has_feature(feature)\n#else\n#  define HEDLEY_HAS_FEATURE(feature) (0)\n#endif\n\n#if defined(HEDLEY_GNUC_HAS_FEATURE)\n#  undef HEDLEY_GNUC_HAS_FEATURE\n#endif\n#if defined(__has_feature)\n#  define HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)\n#else\n#  define HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(HEDLEY_GCC_HAS_FEATURE)\n#  undef HEDLEY_GCC_HAS_FEATURE\n#endif\n#if defined(__has_feature)\n#  define HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)\n#else\n#  define HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(HEDLEY_HAS_EXTENSION)\n#  undef HEDLEY_HAS_EXTENSION\n#endif\n#if defined(__has_extension)\n#  define HEDLEY_HAS_EXTENSION(extension) __has_extension(extension)\n#else\n#  define HEDLEY_HAS_EXTENSION(extension) (0)\n#endif\n\n#if defined(HEDLEY_GNUC_HAS_EXTENSION)\n#  undef HEDLEY_GNUC_HAS_EXTENSION\n#endif\n#if defined(__has_extension)\n#  define HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)\n#else\n#  define HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(HEDLEY_GCC_HAS_EXTENSION)\n#  undef HEDLEY_GCC_HAS_EXTENSION\n#endif\n#if defined(__has_extension)\n#  define HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)\n#else\n#  define HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(HEDLEY_HAS_DECLSPEC_ATTRIBUTE)\n#  undef HEDLEY_HAS_DECLSPEC_ATTRIBUTE\n#endif\n#if defined(__has_declspec_attribute)\n#  define HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute)\n#else\n#  define HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0)\n#endif\n\n#if defined(HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE)\n#  undef HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE\n#endif\n#if defined(__has_declspec_attribute)\n#  define HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)\n#else\n#  define HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE)\n#  undef HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE\n#endif\n#if defined(__has_declspec_attribute)\n#  define HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)\n#else\n#  define HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(HEDLEY_HAS_WARNING)\n#  undef HEDLEY_HAS_WARNING\n#endif\n#if defined(__has_warning)\n#  define HEDLEY_HAS_WARNING(warning) __has_warning(warning)\n#else\n#  define HEDLEY_HAS_WARNING(warning) (0)\n#endif\n\n#if defined(HEDLEY_GNUC_HAS_WARNING)\n#  undef HEDLEY_GNUC_HAS_WARNING\n#endif\n#if defined(__has_warning)\n#  define HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)\n#else\n#  define HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(HEDLEY_GCC_HAS_WARNING)\n#  undef HEDLEY_GCC_HAS_WARNING\n#endif\n#if defined(__has_warning)\n#  define HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)\n#else\n#  define HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if \\\n  (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \\\n  defined(__clang__) || \\\n  HEDLEY_GCC_VERSION_CHECK(3,0,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  HEDLEY_IAR_VERSION_CHECK(8,0,0) || \\\n  HEDLEY_PGI_VERSION_CHECK(18,4,0) || \\\n  HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  HEDLEY_TI_VERSION_CHECK(6,0,0) || \\\n  HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \\\n  HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \\\n  HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \\\n  (HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR))\n#  define HEDLEY_PRAGMA(value) _Pragma(#value)\n#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0)\n#  define HEDLEY_PRAGMA(value) __pragma(value)\n#else\n#  define HEDLEY_PRAGMA(value)\n#endif\n\n#if defined(HEDLEY_DIAGNOSTIC_PUSH)\n#  undef HEDLEY_DIAGNOSTIC_PUSH\n#endif\n#if defined(HEDLEY_DIAGNOSTIC_POP)\n#  undef HEDLEY_DIAGNOSTIC_POP\n#endif\n#if defined(__clang__)\n#  define HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"clang diagnostic push\")\n#  define HEDLEY_DIAGNOSTIC_POP _Pragma(\"clang diagnostic pop\")\n#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"warning(push)\")\n#  define HEDLEY_DIAGNOSTIC_POP _Pragma(\"warning(pop)\")\n#elif HEDLEY_GCC_VERSION_CHECK(4,6,0)\n#  define HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"GCC diagnostic push\")\n#  define HEDLEY_DIAGNOSTIC_POP _Pragma(\"GCC diagnostic pop\")\n#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0)\n#  define HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push))\n#  define HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop))\n#elif HEDLEY_ARM_VERSION_CHECK(5,6,0)\n#  define HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"push\")\n#  define HEDLEY_DIAGNOSTIC_POP _Pragma(\"pop\")\n#elif HEDLEY_TI_VERSION_CHECK(8,1,0)\n#  define HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"diag_push\")\n#  define HEDLEY_DIAGNOSTIC_POP _Pragma(\"diag_pop\")\n#elif HEDLEY_PELLES_VERSION_CHECK(2,90,0)\n#  define HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"warning(push)\")\n#  define HEDLEY_DIAGNOSTIC_POP _Pragma(\"warning(pop)\")\n#else\n#  define HEDLEY_DIAGNOSTIC_PUSH\n#  define HEDLEY_DIAGNOSTIC_POP\n#endif\n\n#if defined(HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED)\n#  undef HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED\n#endif\n#if HEDLEY_HAS_WARNING(\"-Wdeprecated-declarations\")\n#  define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"clang diagnostic ignored \\\"-Wdeprecated-declarations\\\"\")\n#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"warning(disable:1478 1786)\")\n#elif HEDLEY_PGI_VERSION_CHECK(17,10,0)\n#  define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"diag_suppress 1215,1444\")\n#elif HEDLEY_GCC_VERSION_CHECK(4,3,0)\n#  define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"GCC diagnostic ignored \\\"-Wdeprecated-declarations\\\"\")\n#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0)\n#  define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996))\n#elif HEDLEY_TI_VERSION_CHECK(8,0,0)\n#  define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"diag_suppress 1291,1718\")\n#elif HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus)\n#  define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)\")\n#elif HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus)\n#  define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"error_messages(off,symdeprecated,symdeprecated2)\")\n#elif HEDLEY_IAR_VERSION_CHECK(8,0,0)\n#  define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"diag_suppress=Pe1444,Pe1215\")\n#elif HEDLEY_PELLES_VERSION_CHECK(2,90,0)\n#  define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"warn(disable:2241)\")\n#else\n#  define HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED\n#endif\n\n#if defined(HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS)\n#  undef HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS\n#endif\n#if HEDLEY_HAS_WARNING(\"-Wunknown-pragmas\")\n#  define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"clang diagnostic ignored \\\"-Wunknown-pragmas\\\"\")\n#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"warning(disable:161)\")\n#elif HEDLEY_PGI_VERSION_CHECK(17,10,0)\n#  define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"diag_suppress 1675\")\n#elif HEDLEY_GCC_VERSION_CHECK(4,3,0)\n#  define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"GCC diagnostic ignored \\\"-Wunknown-pragmas\\\"\")\n#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0)\n#  define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068))\n#elif HEDLEY_TI_VERSION_CHECK(8,0,0)\n#  define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"diag_suppress 163\")\n#elif HEDLEY_IAR_VERSION_CHECK(8,0,0)\n#  define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"diag_suppress=Pe161\")\n#else\n#  define HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS\n#endif\n\n#if defined(HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL)\n#  undef HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL\n#endif\n#if HEDLEY_HAS_WARNING(\"-Wcast-qual\")\n#  define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma(\"clang diagnostic ignored \\\"-Wcast-qual\\\"\")\n#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma(\"warning(disable:2203 2331)\")\n#elif HEDLEY_GCC_VERSION_CHECK(3,0,0)\n#  define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma(\"GCC diagnostic ignored \\\"-Wcast-qual\\\"\")\n#else\n#  define HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL\n#endif\n\n#if defined(HEDLEY_DEPRECATED)\n#  undef HEDLEY_DEPRECATED\n#endif\n#if defined(HEDLEY_DEPRECATED_FOR)\n#  undef HEDLEY_DEPRECATED_FOR\n#endif\n#if defined(__cplusplus) && (__cplusplus >= 201402L)\n#  define HEDLEY_DEPRECATED(since) [[deprecated(\"Since \" #since)]]\n#  define HEDLEY_DEPRECATED_FOR(since, replacement) [[deprecated(\"Since \" #since \"; use \" #replacement)]]\n#elif \\\n  HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || \\\n  HEDLEY_GCC_VERSION_CHECK(4,5,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  HEDLEY_ARM_VERSION_CHECK(5,6,0) || \\\n  HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \\\n  HEDLEY_PGI_VERSION_CHECK(17,10,0) || \\\n  HEDLEY_TI_VERSION_CHECK(8,3,0)\n#  define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__(\"Since \" #since)))\n#  define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__(\"Since \" #since \"; use \" #replacement)))\n#elif \\\n  HEDLEY_HAS_ATTRIBUTE(deprecated) || \\\n  HEDLEY_GCC_VERSION_CHECK(3,1,0) || \\\n  HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  HEDLEY_TI_VERSION_CHECK(8,0,0) || \\\n  (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))\n#  define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__))\n#  define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__))\n#elif HEDLEY_MSVC_VERSION_CHECK(14,0,0)\n#  define HEDLEY_DEPRECATED(since) __declspec(deprecated(\"Since \" # since))\n#  define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated(\"Since \" #since \"; use \" #replacement))\n#elif \\\n  HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \\\n  HEDLEY_PELLES_VERSION_CHECK(6,50,0)\n#  define HEDLEY_DEPRECATED(since) _declspec(deprecated)\n#  define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated)\n#elif HEDLEY_IAR_VERSION_CHECK(8,0,0)\n#  define HEDLEY_DEPRECATED(since) _Pragma(\"deprecated\")\n#  define HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma(\"deprecated\")\n#else\n#  define HEDLEY_DEPRECATED(since)\n#  define HEDLEY_DEPRECATED_FOR(since, replacement)\n#endif\n\n#if defined(HEDLEY_UNAVAILABLE)\n#  undef HEDLEY_UNAVAILABLE\n#endif\n#if \\\n  HEDLEY_HAS_ATTRIBUTE(warning) || \\\n  HEDLEY_GCC_VERSION_CHECK(4,3,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__(\"Not available until \" #available_since)))\n#else\n#  define HEDLEY_UNAVAILABLE(available_since)\n#endif\n\n#if defined(HEDLEY_WARN_UNUSED_RESULT)\n#  undef HEDLEY_WARN_UNUSED_RESULT\n#endif\n#if defined(__cplusplus) && (__cplusplus >= 201703L)\n#  define HEDLEY_WARN_UNUSED_RESULT [[nodiscard]]\n#elif \\\n  HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \\\n  HEDLEY_GCC_VERSION_CHECK(3,4,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  HEDLEY_TI_VERSION_CHECK(8,0,0) || \\\n  (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  (HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \\\n  HEDLEY_PGI_VERSION_CHECK(17,10,0)\n#  define HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))\n#elif defined(_Check_return_) /* SAL */\n#  define HEDLEY_WARN_UNUSED_RESULT _Check_return_\n#else\n#  define HEDLEY_WARN_UNUSED_RESULT\n#endif\n\n#if defined(HEDLEY_SENTINEL)\n#  undef HEDLEY_SENTINEL\n#endif\n#if \\\n  HEDLEY_HAS_ATTRIBUTE(sentinel) || \\\n  HEDLEY_GCC_VERSION_CHECK(4,0,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  HEDLEY_ARM_VERSION_CHECK(5,4,0)\n#  define HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position)))\n#else\n#  define HEDLEY_SENTINEL(position)\n#endif\n\n#if defined(HEDLEY_NO_RETURN)\n#  undef HEDLEY_NO_RETURN\n#endif\n#if HEDLEY_IAR_VERSION_CHECK(8,0,0)\n#  define HEDLEY_NO_RETURN __noreturn\n#elif HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define HEDLEY_NO_RETURN __attribute__((__noreturn__))\n#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L\n#  define HEDLEY_NO_RETURN _Noreturn\n#elif defined(__cplusplus) && (__cplusplus >= 201103L)\n#  define HEDLEY_NO_RETURN [[noreturn]]\n#elif \\\n  HEDLEY_HAS_ATTRIBUTE(noreturn) || \\\n  HEDLEY_GCC_VERSION_CHECK(3,2,0) || \\\n  HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n  HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n  HEDLEY_TI_VERSION_CHECK(18,0,0) || \\\n  (HEDLEY_TI_VERSION_CHECK(17,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))\n#  define HEDLEY_NO_RETURN __attribute__((__noreturn__))\n#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0)\n#  define HEDLEY_NO_RETURN __declspec(noreturn)\n#elif HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus)\n#  define HEDLEY_NO_RETURN _Pragma(\"FUNC_NEVER_RETURNS;\")\n#elif HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)\n#  define HEDLEY_NO_RETURN __attribute((noreturn))\n#elif HEDLEY_PELLES_VERSION_CHECK(9,0,0)\n#  define HEDLEY_NO_RETURN __declspec(noreturn)\n#else\n#  define HEDLEY_NO_RETURN\n#endif\n\n#if defined(HEDLEY_UNREACHABLE)\n#  undef HEDLEY_UNREACHABLE\n#endif\n#if defined(HEDLEY_UNREACHABLE_RETURN)\n#  undef HEDLEY_UNREACHABLE_RETURN\n#endif\n#if \\\n  (HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(HEDLEY_ARM_VERSION))) || \\\n  HEDLEY_GCC_VERSION_CHECK(4,5,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  HEDLEY_IBM_VERSION_CHECK(13,1,5)\n#  define HEDLEY_UNREACHABLE() __builtin_unreachable()\n#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0)\n#  define HEDLEY_UNREACHABLE() __assume(0)\n#elif HEDLEY_TI_VERSION_CHECK(6,0,0)\n#  if defined(__cplusplus)\n#    define HEDLEY_UNREACHABLE() std::_nassert(0)\n#  else\n#    define HEDLEY_UNREACHABLE() _nassert(0)\n#  endif\n#  define HEDLEY_UNREACHABLE_RETURN(value) return value\n#elif defined(EXIT_FAILURE)\n#  define HEDLEY_UNREACHABLE() abort()\n#else\n#  define HEDLEY_UNREACHABLE()\n#  define HEDLEY_UNREACHABLE_RETURN(value) return value\n#endif\n#if !defined(HEDLEY_UNREACHABLE_RETURN)\n#  define HEDLEY_UNREACHABLE_RETURN(value) HEDLEY_UNREACHABLE()\n#endif\n\n#if defined(HEDLEY_ASSUME)\n#  undef HEDLEY_ASSUME\n#endif\n#if \\\n  HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define HEDLEY_ASSUME(expr) __assume(expr)\n#elif HEDLEY_HAS_BUILTIN(__builtin_assume)\n#  define HEDLEY_ASSUME(expr) __builtin_assume(expr)\n#elif HEDLEY_TI_VERSION_CHECK(6,0,0)\n#  if defined(__cplusplus)\n#    define HEDLEY_ASSUME(expr) std::_nassert(expr)\n#  else\n#    define HEDLEY_ASSUME(expr) _nassert(expr)\n#  endif\n#elif \\\n  (HEDLEY_HAS_BUILTIN(__builtin_unreachable) && !defined(HEDLEY_ARM_VERSION)) || \\\n  HEDLEY_GCC_VERSION_CHECK(4,5,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  HEDLEY_IBM_VERSION_CHECK(13,1,5)\n#  define HEDLEY_ASSUME(expr) ((void) ((expr) ? 1 : (__builtin_unreachable(), 1)))\n#else\n#  define HEDLEY_ASSUME(expr) ((void) (expr))\n#endif\n\n\nHEDLEY_DIAGNOSTIC_PUSH\n#if \\\n  HEDLEY_HAS_WARNING(\"-Wvariadic-macros\") || \\\n  HEDLEY_GCC_VERSION_CHECK(4,0,0)\n#  if defined(__clang__)\n#    pragma clang diagnostic ignored \"-Wvariadic-macros\"\n#  elif defined(HEDLEY_GCC_VERSION)\n#    pragma GCC diagnostic ignored \"-Wvariadic-macros\"\n#  endif\n#endif\n#if defined(HEDLEY_NON_NULL)\n#  undef HEDLEY_NON_NULL\n#endif\n#if \\\n  HEDLEY_HAS_ATTRIBUTE(nonnull) || \\\n  HEDLEY_GCC_VERSION_CHECK(3,3,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  HEDLEY_ARM_VERSION_CHECK(4,1,0)\n#  define HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__)))\n#else\n#  define HEDLEY_NON_NULL(...)\n#endif\nHEDLEY_DIAGNOSTIC_POP\n\n#if defined(HEDLEY_PRINTF_FORMAT)\n#  undef HEDLEY_PRINTF_FORMAT\n#endif\n#if defined(__MINGW32__) && HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO)\n#  define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check)))\n#elif defined(__MINGW32__) && HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO)\n#  define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check)))\n#elif \\\n  HEDLEY_HAS_ATTRIBUTE(format) || \\\n  HEDLEY_GCC_VERSION_CHECK(3,1,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  HEDLEY_ARM_VERSION_CHECK(5,6,0) || \\\n  HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n  HEDLEY_TI_VERSION_CHECK(8,0,0) || \\\n  (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))\n#  define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check)))\n#elif HEDLEY_PELLES_VERSION_CHECK(6,0,0)\n#  define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check))\n#else\n#  define HEDLEY_PRINTF_FORMAT(string_idx,first_to_check)\n#endif\n\n#if defined(HEDLEY_CONSTEXPR)\n#  undef HEDLEY_CONSTEXPR\n#endif\n#if defined(__cplusplus)\n#  if __cplusplus >= 201103L\n#    define HEDLEY_CONSTEXPR constexpr\n#  endif\n#endif\n#if !defined(HEDLEY_CONSTEXPR)\n#  define HEDLEY_CONSTEXPR\n#endif\n\n#if defined(HEDLEY_PREDICT)\n#  undef HEDLEY_PREDICT\n#endif\n#if defined(HEDLEY_LIKELY)\n#  undef HEDLEY_LIKELY\n#endif\n#if defined(HEDLEY_UNLIKELY)\n#  undef HEDLEY_UNLIKELY\n#endif\n#if defined(HEDLEY_UNPREDICTABLE)\n#  undef HEDLEY_UNPREDICTABLE\n#endif\n#if HEDLEY_HAS_BUILTIN(__builtin_unpredictable)\n#  define HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable(!!(expr))\n#endif\n#if \\\n  HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) || \\\n  HEDLEY_GCC_VERSION_CHECK(9,0,0)\n#  define HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(expr, value, probability)\n#  define HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1, probability)\n#  define HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0, probability)\n#  define HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1)\n#  define HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0)\n#  if !defined(HEDLEY_BUILTIN_UNPREDICTABLE)\n#    define HEDLEY_BUILTIN_UNPREDICTABLE(expr) __builtin_expect_with_probability(!!(expr), 1, 0.5)\n#  endif\n#elif \\\n  HEDLEY_HAS_BUILTIN(__builtin_expect) || \\\n  HEDLEY_GCC_VERSION_CHECK(3,0,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  (HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \\\n  HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n  HEDLEY_TI_VERSION_CHECK(6,1,0) || \\\n  HEDLEY_TINYC_VERSION_CHECK(0,9,27)\n#  define HEDLEY_PREDICT(expr, expected, probability) \\\n  (((probability) >= 0.9) ? __builtin_expect(!!(expr), (expected)) : (((void) (expected)), !!(expr)))\n#  define HEDLEY_PREDICT_TRUE(expr, probability) \\\n     (__extension__ ({ \\\n       HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \\\n       ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \\\n     }))\n#  define HEDLEY_PREDICT_FALSE(expr, probability) \\\n     (__extension__ ({ \\\n       HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \\\n       ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \\\n     }))\n#  define HEDLEY_LIKELY(expr)   __builtin_expect(!!(expr), 1)\n#  define HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0)\n#else\n#  define HEDLEY_PREDICT(expr, expected, probability) (((void) (expected)), !!(expr))\n#  define HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr))\n#  define HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr))\n#  define HEDLEY_LIKELY(expr) (!!(expr))\n#  define HEDLEY_UNLIKELY(expr) (!!(expr))\n#endif\n#if !defined(HEDLEY_UNPREDICTABLE)\n#  define HEDLEY_UNPREDICTABLE(expr) HEDLEY_PREDICT(expr, 1, 0.5)\n#endif\n\n#if defined(HEDLEY_MALLOC)\n#  undef HEDLEY_MALLOC\n#endif\n#if \\\n  HEDLEY_HAS_ATTRIBUTE(malloc) || \\\n  HEDLEY_GCC_VERSION_CHECK(3,1,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n  HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  HEDLEY_IBM_VERSION_CHECK(12,1,0) || \\\n  HEDLEY_TI_VERSION_CHECK(8,0,0) || \\\n  (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))\n#  define HEDLEY_MALLOC __attribute__((__malloc__))\n#elif HEDLEY_MSVC_VERSION_CHECK(14, 0, 0)\n#  define HEDLEY_MALLOC __declspec(restrict)\n#else\n#  define HEDLEY_MALLOC\n#endif\n\n#if defined(HEDLEY_PURE)\n#  undef HEDLEY_PURE\n#endif\n#if \\\n  HEDLEY_HAS_ATTRIBUTE(pure) || \\\n  HEDLEY_GCC_VERSION_CHECK(2,96,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n  HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n  HEDLEY_TI_VERSION_CHECK(8,0,0) || \\\n  (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  HEDLEY_PGI_VERSION_CHECK(17,10,0)\n#  define HEDLEY_PURE __attribute__((__pure__))\n#elif HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus)\n#  define HEDLEY_PURE _Pragma(\"FUNC_IS_PURE;\")\n#else\n#  define HEDLEY_PURE\n#endif\n\n#if defined(HEDLEY_CONST)\n#  undef HEDLEY_CONST\n#endif\n#if \\\n  HEDLEY_HAS_ATTRIBUTE(const) || \\\n  HEDLEY_GCC_VERSION_CHECK(2,5,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n  HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n  HEDLEY_TI_VERSION_CHECK(8,0,0) || \\\n  (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  HEDLEY_PGI_VERSION_CHECK(17,10,0)\n#  define HEDLEY_CONST __attribute__((__const__))\n#else\n#  define HEDLEY_CONST HEDLEY_PURE\n#endif\n\n#if defined(HEDLEY_RESTRICT)\n#  undef HEDLEY_RESTRICT\n#endif\n#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus)\n#  define HEDLEY_RESTRICT restrict\n#elif \\\n  HEDLEY_GCC_VERSION_CHECK(3,1,0) || \\\n  HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n  HEDLEY_PGI_VERSION_CHECK(17,10,0) || \\\n  HEDLEY_TI_VERSION_CHECK(8,0,0) || \\\n  (HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \\\n  HEDLEY_IAR_VERSION_CHECK(8,0,0) || \\\n  defined(__clang__)\n#  define HEDLEY_RESTRICT __restrict\n#elif HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus)\n#  define HEDLEY_RESTRICT _Restrict\n#else\n#  define HEDLEY_RESTRICT\n#endif\n\n#if defined(HEDLEY_INLINE)\n#  undef HEDLEY_INLINE\n#endif\n#if \\\n  (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \\\n  (defined(__cplusplus) && (__cplusplus >= 199711L))\n#  define HEDLEY_INLINE inline\n#elif \\\n  defined(HEDLEY_GCC_VERSION) || \\\n  HEDLEY_ARM_VERSION_CHECK(6,2,0)\n#  define HEDLEY_INLINE __inline__\n#elif \\\n  HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \\\n  HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  HEDLEY_TI_VERSION_CHECK(8,0,0)\n#  define HEDLEY_INLINE __inline\n#else\n#  define HEDLEY_INLINE\n#endif\n\n#if defined(HEDLEY_ALWAYS_INLINE)\n#  undef HEDLEY_ALWAYS_INLINE\n#endif\n#if \\\n  HEDLEY_HAS_ATTRIBUTE(always_inline) || \\\n  HEDLEY_GCC_VERSION_CHECK(4,0,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n  HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n  HEDLEY_TI_VERSION_CHECK(8,0,0) || \\\n  (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))\n#  define HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) HEDLEY_INLINE\n#elif HEDLEY_MSVC_VERSION_CHECK(12,0,0)\n#  define HEDLEY_ALWAYS_INLINE __forceinline\n#elif HEDLEY_TI_VERSION_CHECK(7,0,0) && defined(__cplusplus)\n#  define HEDLEY_ALWAYS_INLINE _Pragma(\"FUNC_ALWAYS_INLINE;\")\n#elif HEDLEY_IAR_VERSION_CHECK(8,0,0)\n#  define HEDLEY_ALWAYS_INLINE _Pragma(\"inline=forced\")\n#else\n#  define HEDLEY_ALWAYS_INLINE HEDLEY_INLINE\n#endif\n\n#if defined(HEDLEY_NEVER_INLINE)\n#  undef HEDLEY_NEVER_INLINE\n#endif\n#if \\\n  HEDLEY_HAS_ATTRIBUTE(noinline) || \\\n  HEDLEY_GCC_VERSION_CHECK(4,0,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n  HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n  HEDLEY_TI_VERSION_CHECK(8,0,0) || \\\n  (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))\n#  define HEDLEY_NEVER_INLINE __attribute__((__noinline__))\n#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0)\n#  define HEDLEY_NEVER_INLINE __declspec(noinline)\n#elif HEDLEY_PGI_VERSION_CHECK(10,2,0)\n#  define HEDLEY_NEVER_INLINE _Pragma(\"noinline\")\n#elif HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus)\n#  define HEDLEY_NEVER_INLINE _Pragma(\"FUNC_CANNOT_INLINE;\")\n#elif HEDLEY_IAR_VERSION_CHECK(8,0,0)\n#  define HEDLEY_NEVER_INLINE _Pragma(\"inline=never\")\n#elif HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)\n#  define HEDLEY_NEVER_INLINE __attribute((noinline))\n#elif HEDLEY_PELLES_VERSION_CHECK(9,0,0)\n#  define HEDLEY_NEVER_INLINE __declspec(noinline)\n#else\n#  define HEDLEY_NEVER_INLINE\n#endif\n\n#if defined(HEDLEY_PRIVATE)\n#  undef HEDLEY_PRIVATE\n#endif\n#if defined(HEDLEY_PUBLIC)\n#  undef HEDLEY_PUBLIC\n#endif\n#if defined(HEDLEY_IMPORT)\n#  undef HEDLEY_IMPORT\n#endif\n#if defined(_WIN32) || defined(__CYGWIN__)\n#  define HEDLEY_PRIVATE\n#  define HEDLEY_PUBLIC   __declspec(dllexport)\n#  define HEDLEY_IMPORT   __declspec(dllimport)\n#else\n#  if \\\n    HEDLEY_HAS_ATTRIBUTE(visibility) || \\\n    HEDLEY_GCC_VERSION_CHECK(3,3,0) || \\\n    HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n    HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    HEDLEY_IBM_VERSION_CHECK(13,1,0) || \\\n    HEDLEY_TI_VERSION_CHECK(8,0,0) || \\\n    (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_EABI__) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))\n#    define HEDLEY_PRIVATE __attribute__((__visibility__(\"hidden\")))\n#    define HEDLEY_PUBLIC  __attribute__((__visibility__(\"default\")))\n#  else\n#    define HEDLEY_PRIVATE\n#    define HEDLEY_PUBLIC\n#  endif\n#  define HEDLEY_IMPORT    extern\n#endif\n\n#if defined(HEDLEY_NO_THROW)\n#  undef HEDLEY_NO_THROW\n#endif\n#if \\\n  HEDLEY_HAS_ATTRIBUTE(nothrow) || \\\n  HEDLEY_GCC_VERSION_CHECK(3,3,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define HEDLEY_NO_THROW __attribute__((__nothrow__))\n#elif \\\n  HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \\\n  HEDLEY_ARM_VERSION_CHECK(4,1,0)\n#  define HEDLEY_NO_THROW __declspec(nothrow)\n#else\n#  define HEDLEY_NO_THROW\n#endif\n\n#if defined(HEDLEY_FALL_THROUGH)\n#  undef HEDLEY_FALL_THROUGH\n#endif\n#if \\\n     defined(__cplusplus) && \\\n     (!defined(HEDLEY_SUNPRO_VERSION) || HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \\\n     !defined(HEDLEY_PGI_VERSION)\n#  if \\\n     (__cplusplus >= 201703L) || \\\n     ((__cplusplus >= 201103L) && HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough))\n#    define HEDLEY_FALL_THROUGH [[fallthrough]]\n#  elif (__cplusplus >= 201103L) && HEDLEY_HAS_CPP_ATTRIBUTE(clang::fallthrough)\n#    define HEDLEY_FALL_THROUGH [[clang::fallthrough]]\n#  elif (__cplusplus >= 201103L) && HEDLEY_GCC_VERSION_CHECK(7,0,0)\n#    define HEDLEY_FALL_THROUGH [[gnu::fallthrough]]\n#  endif\n#endif\n#if !defined(HEDLEY_FALL_THROUGH)\n#  if HEDLEY_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(HEDLEY_PGI_VERSION)\n#    define HEDLEY_FALL_THROUGH __attribute__((__fallthrough__))\n#  elif defined(__fallthrough) /* SAL */\n#    define HEDLEY_FALL_THROUGH __fallthrough\n#  else\n#    define HEDLEY_FALL_THROUGH\n#  endif\n#endif\n\n#if defined(HEDLEY_RETURNS_NON_NULL)\n#  undef HEDLEY_RETURNS_NON_NULL\n#endif\n#if \\\n  HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \\\n  HEDLEY_GCC_VERSION_CHECK(4,9,0)\n#  define HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__))\n#elif defined(_Ret_notnull_) /* SAL */\n#  define HEDLEY_RETURNS_NON_NULL _Ret_notnull_\n#else\n#  define HEDLEY_RETURNS_NON_NULL\n#endif\n\n#if defined(HEDLEY_ARRAY_PARAM)\n#  undef HEDLEY_ARRAY_PARAM\n#endif\n#if \\\n  defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \\\n  !defined(__STDC_NO_VLA__) && \\\n  !defined(__cplusplus) && \\\n  !defined(HEDLEY_PGI_VERSION) && \\\n  !defined(HEDLEY_TINYC_VERSION)\n#  define HEDLEY_ARRAY_PARAM(name) (name)\n#else\n#  define HEDLEY_ARRAY_PARAM(name)\n#endif\n\n#if defined(HEDLEY_IS_CONSTANT)\n#  undef HEDLEY_IS_CONSTANT\n#endif\n#if defined(HEDLEY_REQUIRE_CONSTEXPR)\n#  undef HEDLEY_REQUIRE_CONSTEXPR\n#endif\n/* Note the double-underscore. For internal use only; no API\n * guarantees! */\n#if defined(HEDLEY__IS_CONSTEXPR)\n#  undef HEDLEY__IS_CONSTEXPR\n#endif\n\n#if \\\n  HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \\\n  HEDLEY_GCC_VERSION_CHECK(3,4,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \\\n  HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  HEDLEY_IBM_VERSION_CHECK(13,1,0) || \\\n  HEDLEY_TI_VERSION_CHECK(6,1,0) || \\\n  HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) || \\\n  HEDLEY_CRAY_VERSION_CHECK(8,1,0)\n#  define HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr)\n#endif\n#if !defined(__cplusplus)\n#  if \\\n       HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \\\n       HEDLEY_GCC_VERSION_CHECK(3,4,0) || \\\n       HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n       HEDLEY_IBM_VERSION_CHECK(13,1,0) || \\\n       HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \\\n       HEDLEY_ARM_VERSION_CHECK(5,4,0) || \\\n       HEDLEY_TINYC_VERSION_CHECK(0,9,24)\n#    if defined(__INTPTR_TYPE__)\n#      define HEDLEY__IS_CONSTEXPR(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*)\n#    else\n#      include <stdint.h>\n#      define HEDLEY__IS_CONSTEXPR(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*)\n#    endif\n#  elif \\\n       (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(HEDLEY_SUNPRO_VERSION) && !defined(HEDLEY_PGI_VERSION)) || \\\n       HEDLEY_HAS_EXTENSION(c_generic_selections) || \\\n       HEDLEY_GCC_VERSION_CHECK(4,9,0) || \\\n       HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \\\n       HEDLEY_IBM_VERSION_CHECK(12,1,0) || \\\n       HEDLEY_ARM_VERSION_CHECK(5,3,0)\n#    if defined(__INTPTR_TYPE__)\n#      define HEDLEY__IS_CONSTEXPR(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0)\n#    else\n#      include <stdint.h>\n#      define HEDLEY__IS_CONSTEXPR(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0)\n#    endif\n#  elif \\\n       defined(HEDLEY_GCC_VERSION) || \\\n       defined(HEDLEY_INTEL_VERSION) || \\\n       defined(HEDLEY_TINYC_VERSION) || \\\n       defined(HEDLEY_TI_VERSION) || \\\n       defined(__clang__)\n#    define HEDLEY__IS_CONSTEXPR(expr) ( \\\n         sizeof(void) != \\\n         sizeof(*( \\\n           1 ? \\\n             ((void*) ((expr) * 0L) ) : \\\n             ((struct { char v[sizeof(void) * 2]; } *) 1) \\\n           ) \\\n         ) \\\n       )\n#  endif\n#endif\n#if defined(HEDLEY__IS_CONSTEXPR)\n#  if !defined(HEDLEY_IS_CONSTANT)\n#    define HEDLEY_IS_CONSTANT(expr) HEDLEY__IS_CONSTEXPR(expr)\n#  endif\n#  define HEDLEY_REQUIRE_CONSTEXPR(expr) (HEDLEY__IS_CONSTEXPR(expr) ? (expr) : (-1))\n#else\n#  if !defined(HEDLEY_IS_CONSTANT)\n#    define HEDLEY_IS_CONSTANT(expr) (0)\n#  endif\n#  define HEDLEY_REQUIRE_CONSTEXPR(expr) (expr)\n#endif\n\n#if defined(HEDLEY_BEGIN_C_DECLS)\n#  undef HEDLEY_BEGIN_C_DECLS\n#endif\n#if defined(HEDLEY_END_C_DECLS)\n#  undef HEDLEY_END_C_DECLS\n#endif\n#if defined(HEDLEY_C_DECL)\n#  undef HEDLEY_C_DECL\n#endif\n#if defined(__cplusplus)\n#  define HEDLEY_BEGIN_C_DECLS extern \"C\" {\n#  define HEDLEY_END_C_DECLS }\n#  define HEDLEY_C_DECL extern \"C\"\n#else\n#  define HEDLEY_BEGIN_C_DECLS\n#  define HEDLEY_END_C_DECLS\n#  define HEDLEY_C_DECL\n#endif\n\n#if defined(HEDLEY_STATIC_ASSERT)\n#  undef HEDLEY_STATIC_ASSERT\n#endif\n#if \\\n  !defined(__cplusplus) && ( \\\n      (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \\\n      HEDLEY_HAS_FEATURE(c_static_assert) || \\\n      HEDLEY_GCC_VERSION_CHECK(6,0,0) || \\\n      HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n      defined(_Static_assert) \\\n    )\n#  define HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message)\n#elif \\\n  (defined(__cplusplus) && (__cplusplus >= 201703L)) || \\\n  HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \\\n  (defined(__cplusplus) && HEDLEY_TI_VERSION_CHECK(8,3,0))\n#  define HEDLEY_STATIC_ASSERT(expr, message) static_assert(expr, message)\n#elif defined(__cplusplus) && (__cplusplus >= 201103L)\n#  define HEDLEY_STATIC_ASSERT(expr, message) static_assert(expr)\n#else\n#  define HEDLEY_STATIC_ASSERT(expr, message)\n#endif\n\n#if defined(HEDLEY_CONST_CAST)\n#  undef HEDLEY_CONST_CAST\n#endif\n#if defined(__cplusplus)\n#  define HEDLEY_CONST_CAST(T, expr) (const_cast<T>(expr))\n#elif \\\n  HEDLEY_HAS_WARNING(\"-Wcast-qual\") || \\\n  HEDLEY_GCC_VERSION_CHECK(4,6,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \\\n      HEDLEY_DIAGNOSTIC_PUSH \\\n      HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \\\n      ((T) (expr)); \\\n      HEDLEY_DIAGNOSTIC_POP \\\n    }))\n#else\n#  define HEDLEY_CONST_CAST(T, expr) ((T) (expr))\n#endif\n\n#if defined(HEDLEY_REINTERPRET_CAST)\n#  undef HEDLEY_REINTERPRET_CAST\n#endif\n#if defined(__cplusplus)\n#  define HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast<T>(expr))\n#else\n#  define HEDLEY_REINTERPRET_CAST(T, expr) (*((T*) &(expr)))\n#endif\n\n#if defined(HEDLEY_STATIC_CAST)\n#  undef HEDLEY_STATIC_CAST\n#endif\n#if defined(__cplusplus)\n#  define HEDLEY_STATIC_CAST(T, expr) (static_cast<T>(expr))\n#else\n#  define HEDLEY_STATIC_CAST(T, expr) ((T) (expr))\n#endif\n\n#if defined(HEDLEY_CPP_CAST)\n#  undef HEDLEY_CPP_CAST\n#endif\n#if defined(__cplusplus)\n#  define HEDLEY_CPP_CAST(T, expr) static_cast<T>(expr)\n#else\n#  define HEDLEY_CPP_CAST(T, expr) (expr)\n#endif\n\n#if defined(HEDLEY_MESSAGE)\n#  undef HEDLEY_MESSAGE\n#endif\n#if HEDLEY_HAS_WARNING(\"-Wunknown-pragmas\")\n#  define HEDLEY_MESSAGE(msg) \\\n  HEDLEY_DIAGNOSTIC_PUSH \\\n  HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \\\n  HEDLEY_PRAGMA(message msg) \\\n  HEDLEY_DIAGNOSTIC_POP\n#elif \\\n  HEDLEY_GCC_VERSION_CHECK(4,4,0) || \\\n  HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message msg)\n#elif HEDLEY_CRAY_VERSION_CHECK(5,0,0)\n#  define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(_CRI message msg)\n#elif HEDLEY_IAR_VERSION_CHECK(8,0,0)\n#  define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message(msg))\n#elif HEDLEY_PELLES_VERSION_CHECK(2,0,0)\n#  define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message(msg))\n#else\n#  define HEDLEY_MESSAGE(msg)\n#endif\n\n#if defined(HEDLEY_WARNING)\n#  undef HEDLEY_WARNING\n#endif\n#if HEDLEY_HAS_WARNING(\"-Wunknown-pragmas\")\n#  define HEDLEY_WARNING(msg) \\\n  HEDLEY_DIAGNOSTIC_PUSH \\\n  HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \\\n  HEDLEY_PRAGMA(clang warning msg) \\\n  HEDLEY_DIAGNOSTIC_POP\n#elif \\\n  HEDLEY_GCC_VERSION_CHECK(4,8,0) || \\\n  HEDLEY_PGI_VERSION_CHECK(18,4,0)\n#  define HEDLEY_WARNING(msg) HEDLEY_PRAGMA(GCC warning msg)\n#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0)\n#  define HEDLEY_WARNING(msg) HEDLEY_PRAGMA(message(msg))\n#else\n#  define HEDLEY_WARNING(msg) HEDLEY_MESSAGE(msg)\n#endif\n\n#if defined(HEDLEY_REQUIRE_MSG)\n#  undef HEDLEY_REQUIRE_MSG\n#endif\n#if HEDLEY_HAS_ATTRIBUTE(diagnose_if)\n#  if HEDLEY_HAS_WARNING(\"-Wgcc-compat\")\n#    define HEDLEY_REQUIRE_MSG(expr, msg) \\\n  HEDLEY_DIAGNOSTIC_PUSH \\\n  _Pragma(\"clang diagnostic ignored \\\"-Wgcc-compat\\\"\") \\\n  __attribute__((__diagnose_if__(!(expr), msg, \"error\"))) \\\n  HEDLEY_DIAGNOSTIC_POP\n#  else\n#    define HEDLEY_REQUIRE_MSG(expr, msg) __attribute__((__diagnose_if__(!(expr), msg, \"error\")))\n#  endif\n#else\n#  define HEDLEY_REQUIRE_MSG(expr, msg)\n#endif\n\n#if defined(HEDLEY_REQUIRE)\n#  undef HEDLEY_REQUIRE\n#endif\n#define HEDLEY_REQUIRE(expr) HEDLEY_REQUIRE_MSG(expr, #expr)\n\n#if defined(HEDLEY_FLAGS)\n#  undef HEDLEY_FLAGS\n#endif\n#if HEDLEY_HAS_ATTRIBUTE(flag_enum)\n#  define HEDLEY_FLAGS __attribute__((__flag_enum__))\n#endif\n\n#if defined(HEDLEY_FLAGS_CAST)\n#  undef HEDLEY_FLAGS_CAST\n#endif\n#if HEDLEY_INTEL_VERSION_CHECK(19,0,0)\n#  define HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \\\n  HEDLEY_DIAGNOSTIC_PUSH \\\n      _Pragma(\"warning(disable:188)\") \\\n      ((T) (expr)); \\\n      HEDLEY_DIAGNOSTIC_POP \\\n    }))\n#else\n#  define HEDLEY_FLAGS_CAST(T, expr) HEDLEY_STATIC_CAST(T, expr)\n#endif\n\n/* Remaining macros are deprecated. */\n\n#if defined(HEDLEY_GCC_NOT_CLANG_VERSION_CHECK)\n#  undef HEDLEY_GCC_NOT_CLANG_VERSION_CHECK\n#endif\n#if defined(__clang__)\n#  define HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0)\n#else\n#  define HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(HEDLEY_CLANG_HAS_ATTRIBUTE)\n#  undef HEDLEY_CLANG_HAS_ATTRIBUTE\n#endif\n#define HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) HEDLEY_HAS_ATTRIBUTE(attribute)\n\n#if defined(HEDLEY_CLANG_HAS_CPP_ATTRIBUTE)\n#  undef HEDLEY_CLANG_HAS_CPP_ATTRIBUTE\n#endif\n#define HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) HEDLEY_HAS_CPP_ATTRIBUTE(attribute)\n\n#if defined(HEDLEY_CLANG_HAS_BUILTIN)\n#  undef HEDLEY_CLANG_HAS_BUILTIN\n#endif\n#define HEDLEY_CLANG_HAS_BUILTIN(builtin) HEDLEY_HAS_BUILTIN(builtin)\n\n#if defined(HEDLEY_CLANG_HAS_FEATURE)\n#  undef HEDLEY_CLANG_HAS_FEATURE\n#endif\n#define HEDLEY_CLANG_HAS_FEATURE(feature) HEDLEY_HAS_FEATURE(feature)\n\n#if defined(HEDLEY_CLANG_HAS_EXTENSION)\n#  undef HEDLEY_CLANG_HAS_EXTENSION\n#endif\n#define HEDLEY_CLANG_HAS_EXTENSION(extension) HEDLEY_HAS_EXTENSION(extension)\n\n#if defined(HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE)\n#  undef HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE\n#endif\n#define HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute)\n\n#if defined(HEDLEY_CLANG_HAS_WARNING)\n#  undef HEDLEY_CLANG_HAS_WARNING\n#endif\n#define HEDLEY_CLANG_HAS_WARNING(warning) HEDLEY_HAS_WARNING(warning)\n\n#endif /* !defined(HEDLEY_VERSION) || (HEDLEY_VERSION < X) */\n\n\nnamespace csv {\n#ifdef _MSC_VER\n#pragma region Compatibility Macros\n#endif\n    /**\n     *  @def IF_CONSTEXPR\n     *  Expands to `if constexpr` in C++17 and `if` otherwise\n     *\n     *  @def CONSTEXPR_VALUE\n     *  Expands to `constexpr` in C++17 and `const` otherwise.\n     *  Mainly used for global variables.\n     *\n     *  @def CONSTEXPR\n     *  Expands to `constexpr` in decent compilers and `inline` otherwise.\n     *  Intended for functions and methods.\n     */\n\n#define STATIC_ASSERT(x) static_assert(x, \"Assertion failed\")\n\n#if CMAKE_CXX_STANDARD == 17 || __cplusplus >= 201703L\n#define CSV_HAS_CXX17\n#endif\n\n#if CMAKE_CXX_STANDARD >= 14 || __cplusplus >= \t201402L\n#define CSV_HAS_CXX14\n#endif\n\n#ifdef CSV_HAS_CXX17\n#include <string_view>\n     /** @typedef string_view\n      *  The string_view class used by this library.\n      */\n    using string_view = std::string_view;\n#else\n     /** @typedef string_view\n      *  The string_view class used by this library.\n      */\n    using string_view = nonstd::string_view;\n#endif\n\n#ifdef CSV_HAS_CXX17\n    #define IF_CONSTEXPR if constexpr\n    #define CONSTEXPR_VALUE constexpr\n\n    #define CONSTEXPR_17 constexpr\n#else\n    #define IF_CONSTEXPR if\n    #define CONSTEXPR_VALUE const\n\n    #define CONSTEXPR_17 inline\n#endif\n\n#ifdef CSV_HAS_CXX14\n    template<bool B, class T = void>\n    using enable_if_t = std::enable_if_t<B, T>;\n\n    #define CONSTEXPR_14 constexpr\n    #define CONSTEXPR_VALUE_14 constexpr\n#else\n    template<bool B, class T = void>\n    using enable_if_t = typename std::enable_if<B, T>::type;\n\n    #define CONSTEXPR_14 inline\n    #define CONSTEXPR_VALUE_14 const\n#endif\n\n    // Resolves g++ bug with regard to constexpr methods\n    // See: https://stackoverflow.com/questions/36489369/constexpr-non-static-member-function-with-non-constexpr-constructor-gcc-clang-d\n#if defined __GNUC__ && !defined __clang__\n    #if (__GNUC__ >= 7 &&__GNUC_MINOR__ >= 2) || (__GNUC__ >= 8)\n        #define CONSTEXPR constexpr\n    #endif\n    #else\n        #ifdef CSV_HAS_CXX17\n        #define CONSTEXPR constexpr\n    #endif\n#endif\n\n#ifndef CONSTEXPR\n#define CONSTEXPR inline\n#endif\n\n#ifdef _MSC_VER\n#pragma endregion\n#endif\n\n    namespace internals {\n        // PAGE_SIZE macro could be already defined by the host system.\n#if defined(PAGE_SIZE)\n#undef PAGE_SIZE\n#endif\n\n// Get operating system specific details\n#if defined(_WIN32)\n        inline int getpagesize() {\n            _SYSTEM_INFO sys_info = {};\n            GetSystemInfo(&sys_info);\n            return std::max(sys_info.dwPageSize, sys_info.dwAllocationGranularity);\n        }\n\n        const int PAGE_SIZE = getpagesize();\n#elif defined(__linux__) \n        const int PAGE_SIZE = getpagesize();\n#else\n        /** Size of a memory page in bytes. Used by\n         *  csv::internals::CSVFieldArray when allocating blocks.\n         */\n        const int PAGE_SIZE = 4096;\n#endif\n\n        /** For functions that lazy load a large CSV, this determines how\n         *  many bytes are read at a time\n         */\n        constexpr size_t ITERATION_CHUNK_SIZE = 10000000; // 10MB\n\n        template<typename T>\n        inline bool is_equal(T a, T b, T epsilon = 0.001) {\n            /** Returns true if two floating point values are about the same */\n            static_assert(std::is_floating_point<T>::value, \"T must be a floating point type.\");\n            return std::abs(a - b) < epsilon;\n        }\n\n        /**  @typedef ParseFlags\n         *   An enum used for describing the significance of each character\n         *   with respect to CSV parsing\n         *\n         *   @see quote_escape_flag\n         */\n        enum class ParseFlags {\n            QUOTE_ESCAPE_QUOTE = 0, /**< A quote inside or terminating a quote_escaped field */\n            QUOTE = 2 | 1,          /**< Characters which may signify a quote escape */\n            NOT_SPECIAL = 4,        /**< Characters with no special meaning or escaped delimiters and newlines */\n            DELIMITER = 4 | 2,      /**< Characters which signify a new field */\n            NEWLINE = 4 | 2 | 1     /**< Characters which signify a new row */\n        };\n\n        /** Transform the ParseFlags given the context of whether or not the current\n         *  field is quote escaped */\n        constexpr ParseFlags quote_escape_flag(ParseFlags flag, bool quote_escape) noexcept {\n            return (ParseFlags)((int)flag & ~((int)ParseFlags::QUOTE * quote_escape));\n        }\n\n        // Assumed to be true by parsing functions: allows for testing\n        // if an item is DELIMITER or NEWLINE with a >= statement\n        STATIC_ASSERT(ParseFlags::DELIMITER < ParseFlags::NEWLINE);\n\n        /** Optimizations for reducing branching in parsing loop\n         *\n         *  Idea: The meaning of all non-quote characters changes depending\n         *  on whether or not the parser is in a quote-escaped mode (0 or 1)\n         */\n        STATIC_ASSERT(quote_escape_flag(ParseFlags::NOT_SPECIAL, false) == ParseFlags::NOT_SPECIAL);\n        STATIC_ASSERT(quote_escape_flag(ParseFlags::QUOTE, false) == ParseFlags::QUOTE);\n        STATIC_ASSERT(quote_escape_flag(ParseFlags::DELIMITER, false) == ParseFlags::DELIMITER);\n        STATIC_ASSERT(quote_escape_flag(ParseFlags::NEWLINE, false) == ParseFlags::NEWLINE);\n\n        STATIC_ASSERT(quote_escape_flag(ParseFlags::NOT_SPECIAL, true) == ParseFlags::NOT_SPECIAL);\n        STATIC_ASSERT(quote_escape_flag(ParseFlags::QUOTE, true) == ParseFlags::QUOTE_ESCAPE_QUOTE);\n        STATIC_ASSERT(quote_escape_flag(ParseFlags::DELIMITER, true) == ParseFlags::NOT_SPECIAL);\n        STATIC_ASSERT(quote_escape_flag(ParseFlags::NEWLINE, true) == ParseFlags::NOT_SPECIAL);\n\n        /** An array which maps ASCII chars to a parsing flag */\n        using ParseFlagMap = std::array<ParseFlags, 256>;\n\n        /** An array which maps ASCII chars to a flag indicating if it is whitespace */\n        using WhitespaceMap = std::array<bool, 256>;\n    }\n\n    /** Integer indicating a requested column wasn't found. */\n    constexpr int CSV_NOT_FOUND = -1;\n}\n\n\nnamespace csv {\n    namespace internals {\n        struct ColNames;\n        using ColNamesPtr = std::shared_ptr<ColNames>;\n\n        /** @struct ColNames\n             *  A data structure for handling column name information.\n             *\n             *  These are created by CSVReader and passed (via smart pointer)\n             *  to CSVRow objects it creates, thus\n             *  allowing for indexing by column name.\n             */\n        struct ColNames {\n        public:\n            ColNames() = default;\n            ColNames(const std::vector<std::string>& names) {\n                set_col_names(names);\n            }\n\n            std::vector<std::string> get_col_names() const;\n            void set_col_names(const std::vector<std::string>&);\n            int index_of(csv::string_view) const;\n\n            bool empty() const noexcept { return this->col_names.empty(); }\n            size_t size() const noexcept;\n\n        private:\n            std::vector<std::string> col_names;\n            std::unordered_map<std::string, size_t> col_pos;\n        };\n    }\n}\n/** @file\n *  Defines an object used to store CSV format settings\n */\n\n#include <iterator>\n#include <stdexcept>\n#include <string>\n#include <vector>\n\n\nnamespace csv {\n    namespace internals {\n        class IBasicCSVParser;\n    }\n\n    class CSVReader;\n\n    /** Determines how to handle rows that are shorter or longer than the majority */\n    enum class VariableColumnPolicy {\n        THROW = -1,\n        IGNORE_ROW = 0,\n        KEEP   = 1\n    };\n\n    /** Stores the inferred format of a CSV file. */\n    struct CSVGuessResult {\n        char delim;\n        int header_row;\n    };\n\n    /** Stores information about how to parse a CSV file.\n     *  Can be used to construct a csv::CSVReader. \n     */\n    class CSVFormat {\n    public:\n        /** Settings for parsing a RFC 4180 CSV file */\n        CSVFormat() = default;\n\n        /** Sets the delimiter of the CSV file\n         *\n         *  @throws `std::runtime_error` thrown if trim, quote, or possible delimiting characters overlap\n         */\n        CSVFormat& delimiter(char delim);\n\n        /** Sets a list of potential delimiters\n         *  \n         *  @throws `std::runtime_error` thrown if trim, quote, or possible delimiting characters overlap\n         *  @param[in] delim An array of possible delimiters to try parsing the CSV with\n         */\n        CSVFormat& delimiter(const std::vector<char> & delim);\n\n        /** Sets the whitespace characters to be trimmed\n         *\n         *  @throws `std::runtime_error` thrown if trim, quote, or possible delimiting characters overlap\n         *  @param[in] ws An array of whitespace characters that should be trimmed\n         */\n        CSVFormat& trim(const std::vector<char> & ws);\n\n        /** Sets the quote character\n         *\n         *  @throws `std::runtime_error` thrown if trim, quote, or possible delimiting characters overlap\n         */\n        CSVFormat& quote(char quote);\n\n        /** Sets the column names.\n         *\n         *  @note Unsets any values set by header_row()\n         */\n        CSVFormat& column_names(const std::vector<std::string>& names);\n\n        /** Sets the header row\n         *\n         *  @note Unsets any values set by column_names()\n         */\n        CSVFormat& header_row(int row);\n\n        /** Tells the parser that this CSV has no header row\n         *\n         *  @note Equivalent to `header_row(-1)`\n         *\n         */\n        CSVFormat& no_header() {\n            this->header_row(-1);\n            return *this;\n        }\n\n        /** Turn quoting on or off */\n        CSVFormat& quote(bool use_quote) {\n            this->no_quote = !use_quote;\n            return *this;\n        }\n\n        /** Tells the parser how to handle columns of a different length than the others */\n        CONSTEXPR_14 CSVFormat& variable_columns(VariableColumnPolicy policy = VariableColumnPolicy::IGNORE_ROW) {\n            this->variable_column_policy = policy;\n            return *this;\n        }\n\n        /** Tells the parser how to handle columns of a different length than the others */\n        CONSTEXPR_14 CSVFormat& variable_columns(bool policy) {\n            this->variable_column_policy = (VariableColumnPolicy)policy;\n            return *this;\n        }\n\n        #ifndef DOXYGEN_SHOULD_SKIP_THIS\n        char get_delim() const {\n            // This error should never be received by end users.\n            if (this->possible_delimiters.size() > 1) {\n                throw std::runtime_error(\"There is more than one possible delimiter.\");\n            }\n\n            return this->possible_delimiters.at(0);\n        }\n\n        CONSTEXPR bool is_quoting_enabled() const { return !this->no_quote; }\n        CONSTEXPR char get_quote_char() const { return this->quote_char; }\n        CONSTEXPR int get_header() const { return this->header; }\n        std::vector<char> get_possible_delims() const { return this->possible_delimiters; }\n        std::vector<char> get_trim_chars() const { return this->trim_chars; }\n        CONSTEXPR VariableColumnPolicy get_variable_column_policy() const { return this->variable_column_policy; }\n        #endif\n        \n        /** CSVFormat for guessing the delimiter */\n        CSV_INLINE static CSVFormat guess_csv() {\n            CSVFormat format;\n            format.delimiter({ ',', '|', '\\t', ';', '^' })\n                .quote('\"')\n                .header_row(0);\n\n            return format;\n        }\n\n        bool guess_delim() {\n            return this->possible_delimiters.size() > 1;\n        }\n\n        friend CSVReader;\n        friend internals::IBasicCSVParser;\n        \n    private:\n        /**< Throws an error if delimiters and trim characters overlap */\n        void assert_no_char_overlap();\n\n        /**< Set of possible delimiters */\n        std::vector<char> possible_delimiters = { ',' };\n\n        /**< Set of whitespace characters to trim */\n        std::vector<char> trim_chars = {};\n\n        /**< Row number with columns (ignored if col_names is non-empty) */\n        int header = 0;\n\n        /**< Whether or not to use quoting */\n        bool no_quote = false;\n\n        /**< Quote character */\n        char quote_char = '\"';\n\n        /**< Should be left empty unless file doesn't include header */\n        std::vector<std::string> col_names = {};\n\n        /**< Allow variable length columns? */\n        VariableColumnPolicy variable_column_policy = VariableColumnPolicy::IGNORE_ROW;\n    };\n}\n/** @file\n *  Defines the data type used for storing information about a CSV row\n */\n\n#include <cmath>\n#include <iterator>\n#include <memory> // For CSVField\n#include <limits> // For CSVField\n#include <unordered_map>\n#include <unordered_set>\n#include <string>\n#include <sstream>\n#include <vector>\n\n/** @file\n *  @brief Implements data type parsing functionality\n */\n\n#include <cmath>\n#include <cctype>\n#include <string>\n#include <cassert>\n\n\nnamespace csv {\n    /** Enumerates the different CSV field types that are\n     *  recognized by this library\n     *\n     *  @note Overflowing integers will be stored and classified as doubles.\n     *  @note Unlike previous releases, integer enums here are platform agnostic.\n     */\n    enum class DataType {\n        UNKNOWN = -1,\n        CSV_NULL,   /**< Empty string */\n        CSV_STRING, /**< Non-numeric string */\n        CSV_INT8,   /**< 8-bit integer */\n        CSV_INT16,  /**< 16-bit integer (short on MSVC/GCC) */\n        CSV_INT32,  /**< 32-bit integer (int on MSVC/GCC) */\n        CSV_INT64,  /**< 64-bit integer (long long on MSVC/GCC) */\n        CSV_DOUBLE  /**< Floating point value */\n    };\n\n    static_assert(DataType::CSV_STRING < DataType::CSV_INT8, \"String type should come before numeric types.\");\n    static_assert(DataType::CSV_INT8 < DataType::CSV_INT64, \"Smaller integer types should come before larger integer types.\");\n    static_assert(DataType::CSV_INT64 < DataType::CSV_DOUBLE, \"Integer types should come before floating point value types.\");\n\n    namespace internals {\n        /** Compute 10 to the power of n */\n        template<typename T>\n        HEDLEY_CONST CONSTEXPR_14\n        long double pow10(const T& n) noexcept {\n            long double multiplicand = n > 0 ? 10 : 0.1,\n                ret = 1;\n\n            // Make all numbers positive\n            T iterations = n > 0 ? n : -n;\n            \n            for (T i = 0; i < iterations; i++) {\n                ret *= multiplicand;\n            }\n\n            return ret;\n        }\n\n        /** Compute 10 to the power of n */\n        template<>\n        HEDLEY_CONST CONSTEXPR_14\n        long double pow10(const unsigned& n) noexcept {\n            long double multiplicand = n > 0 ? 10 : 0.1,\n                ret = 1;\n\n            for (unsigned i = 0; i < n; i++) {\n                ret *= multiplicand;\n            }\n\n            return ret;\n        }\n\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\n        /** Private site-indexed array mapping byte sizes to an integer size enum */\n        constexpr DataType int_type_arr[8] = {\n            DataType::CSV_INT8,  // 1\n            DataType::CSV_INT16, // 2\n            DataType::UNKNOWN,\n            DataType::CSV_INT32, // 4\n            DataType::UNKNOWN,\n            DataType::UNKNOWN,\n            DataType::UNKNOWN,\n            DataType::CSV_INT64  // 8\n        };\n\n        template<typename T>\n        inline DataType type_num() {\n            static_assert(std::is_integral<T>::value, \"T should be an integral type.\");\n            static_assert(sizeof(T) <= 8, \"Byte size must be no greater than 8.\");\n            return int_type_arr[sizeof(T) - 1];\n        }\n\n        template<> inline DataType type_num<float>() { return DataType::CSV_DOUBLE; }\n        template<> inline DataType type_num<double>() { return DataType::CSV_DOUBLE; }\n        template<> inline DataType type_num<long double>() { return DataType::CSV_DOUBLE; }\n        template<> inline DataType type_num<std::nullptr_t>() { return DataType::CSV_NULL; }\n        template<> inline DataType type_num<std::string>() { return DataType::CSV_STRING; }\n\n        CONSTEXPR_14 DataType data_type(csv::string_view in, long double* const out = nullptr);\n#endif\n\n        /** Given a byte size, return the largest number than can be stored in\n         *  an integer of that size\n         *\n         *  Note: Provides a platform-agnostic way of mapping names like \"long int\" to\n         *  byte sizes\n         */\n        template<size_t Bytes>\n        CONSTEXPR_14 long double get_int_max() {\n            static_assert(Bytes == 1 || Bytes == 2 || Bytes == 4 || Bytes == 8,\n                \"Bytes must be a power of 2 below 8.\");\n\n            IF_CONSTEXPR (sizeof(signed char) == Bytes) {\n                return (long double)std::numeric_limits<signed char>::max();\n            }\n\n            IF_CONSTEXPR (sizeof(short) == Bytes) {\n                return (long double)std::numeric_limits<short>::max();\n            }\n\n            IF_CONSTEXPR (sizeof(int) == Bytes) {\n                return (long double)std::numeric_limits<int>::max();\n            }\n\n            IF_CONSTEXPR (sizeof(long int) == Bytes) {\n                return (long double)std::numeric_limits<long int>::max();\n            }\n\n            IF_CONSTEXPR (sizeof(long long int) == Bytes) {\n                return (long double)std::numeric_limits<long long int>::max();\n            }\n\n            HEDLEY_UNREACHABLE();\n        }\n\n        /** Given a byte size, return the largest number than can be stored in\n         *  an unsigned integer of that size\n         */\n        template<size_t Bytes>\n        CONSTEXPR_14 long double get_uint_max() {\n            static_assert(Bytes == 1 || Bytes == 2 || Bytes == 4 || Bytes == 8,\n                \"Bytes must be a power of 2 below 8.\");\n\n            IF_CONSTEXPR(sizeof(unsigned char) == Bytes) {\n                return (long double)std::numeric_limits<unsigned char>::max();\n            }\n\n            IF_CONSTEXPR(sizeof(unsigned short) == Bytes) {\n                return (long double)std::numeric_limits<unsigned short>::max();\n            }\n\n            IF_CONSTEXPR(sizeof(unsigned int) == Bytes) {\n                return (long double)std::numeric_limits<unsigned int>::max();\n            }\n\n            IF_CONSTEXPR(sizeof(unsigned long int) == Bytes) {\n                return (long double)std::numeric_limits<unsigned long int>::max();\n            }\n\n            IF_CONSTEXPR(sizeof(unsigned long long int) == Bytes) {\n                return (long double)std::numeric_limits<unsigned long long int>::max();\n            }\n\n            HEDLEY_UNREACHABLE();\n        }\n\n        /** Largest number that can be stored in a 8-bit integer */\n        CONSTEXPR_VALUE_14 long double CSV_INT8_MAX = get_int_max<1>();\n\n        /** Largest number that can be stored in a 16-bit integer */\n        CONSTEXPR_VALUE_14 long double CSV_INT16_MAX = get_int_max<2>();\n\n        /** Largest number that can be stored in a 32-bit integer */\n        CONSTEXPR_VALUE_14 long double CSV_INT32_MAX = get_int_max<4>();\n\n        /** Largest number that can be stored in a 64-bit integer */\n        CONSTEXPR_VALUE_14 long double CSV_INT64_MAX = get_int_max<8>();\n\n        /** Largest number that can be stored in a 8-bit ungisned integer */\n        CONSTEXPR_VALUE_14 long double CSV_UINT8_MAX = get_uint_max<1>();\n\n        /** Largest number that can be stored in a 16-bit unsigned integer */\n        CONSTEXPR_VALUE_14 long double CSV_UINT16_MAX = get_uint_max<2>();\n\n        /** Largest number that can be stored in a 32-bit unsigned integer */\n        CONSTEXPR_VALUE_14 long double CSV_UINT32_MAX = get_uint_max<4>();\n\n        /** Largest number that can be stored in a 64-bit unsigned integer */\n        CONSTEXPR_VALUE_14 long double CSV_UINT64_MAX = get_uint_max<8>();\n\n        /** Given a pointer to the start of what is start of\n         *  the exponential part of a number written (possibly) in scientific notation\n         *  parse the exponent\n         */\n        HEDLEY_PRIVATE CONSTEXPR_14\n        DataType _process_potential_exponential(\n            csv::string_view exponential_part,\n            const long double& coeff,\n            long double * const out) {\n            long double exponent = 0;\n            auto result = data_type(exponential_part, &exponent);\n\n            // Exponents in scientific notation should not be decimal numbers\n            if (result >= DataType::CSV_INT8 && result < DataType::CSV_DOUBLE) {\n                if (out) *out = coeff * pow10(exponent);\n                return DataType::CSV_DOUBLE;\n            }\n\n            return DataType::CSV_STRING;\n        }\n\n        /** Given the absolute value of an integer, determine what numeric type\n         *  it fits in\n         */\n        HEDLEY_PRIVATE HEDLEY_PURE CONSTEXPR_14\n        DataType _determine_integral_type(const long double& number) noexcept {\n            // We can assume number is always non-negative\n            assert(number >= 0);\n\n            if (number <= internals::CSV_INT8_MAX)\n                return DataType::CSV_INT8;\n            else if (number <= internals::CSV_INT16_MAX)\n                return DataType::CSV_INT16;\n            else if (number <= internals::CSV_INT32_MAX)\n                return DataType::CSV_INT32;\n            else if (number <= internals::CSV_INT64_MAX)\n                return DataType::CSV_INT64;\n            else // Conversion to long long will cause an overflow\n                return DataType::CSV_DOUBLE;\n        }\n\n        /** Distinguishes numeric from other text values. Used by various\n         *  type casting functions, like csv_parser::CSVReader::read_row()\n         *\n         *  #### Rules\n         *   - Leading and trailing whitespace (\"padding\") ignored\n         *   - A string of just whitespace is NULL\n         *\n         *  @param[in]  in  String value to be examined\n         *  @param[out] out Pointer to long double where results of numeric parsing\n         *                  get stored\n         */\n        CONSTEXPR_14\n        DataType data_type(csv::string_view in, long double* const out) {\n            // Empty string --> NULL\n            if (in.size() == 0)\n                return DataType::CSV_NULL;\n\n            bool ws_allowed = true,\n                neg_allowed = true,\n                dot_allowed = true,\n                digit_allowed = true,\n                has_digit = false,\n                prob_float = false;\n\n            unsigned places_after_decimal = 0;\n            long double integral_part = 0,\n                decimal_part = 0;\n\n            for (size_t i = 0, ilen = in.size(); i < ilen; i++) {\n                const char& current = in[i];\n\n                switch (current) {\n                case ' ':\n                    if (!ws_allowed) {\n                        if (isdigit(in[i - 1])) {\n                            digit_allowed = false;\n                            ws_allowed = true;\n                        }\n                        else {\n                            // Ex: '510 123 4567'\n                            return DataType::CSV_STRING;\n                        }\n                    }\n                    break;\n                case '-':\n                    if (!neg_allowed) {\n                        // Ex: '510-123-4567'\n                        return DataType::CSV_STRING;\n                    }\n\n                    neg_allowed = false;\n                    break;\n                case '.':\n                    if (!dot_allowed) {\n                        return DataType::CSV_STRING;\n                    }\n\n                    dot_allowed = false;\n                    prob_float = true;\n                    break;\n                case 'e':\n                case 'E':\n                    // Process scientific notation\n                    if (prob_float || (i && i + 1 < ilen && isdigit(in[i - 1]))) {\n                        size_t exponent_start_idx = i + 1;\n                        prob_float = true;\n\n                        // Strip out plus sign\n                        if (in[i + 1] == '+') {\n                            exponent_start_idx++;\n                        }\n\n                        return _process_potential_exponential(\n                            in.substr(exponent_start_idx),\n                            neg_allowed ? integral_part + decimal_part : -(integral_part + decimal_part),\n                            out\n                        );\n                    }\n\n                    return DataType::CSV_STRING;\n                    break;\n                default:\n                    short digit = static_cast<short>(current - '0');\n                    if (digit >= 0 && digit <= 9) {\n                        // Process digit\n                        has_digit = true;\n\n                        if (!digit_allowed)\n                            return DataType::CSV_STRING;\n                        else if (ws_allowed) // Ex: '510 456'\n                            ws_allowed = false;\n\n                        // Build current number\n                        if (prob_float)\n                            decimal_part += digit / pow10(++places_after_decimal);\n                        else\n                            integral_part = (integral_part * 10) + digit;\n                    }\n                    else {\n                        return DataType::CSV_STRING;\n                    }\n                }\n            }\n\n            // No non-numeric/non-whitespace characters found\n            if (has_digit) {\n                long double number = integral_part + decimal_part;\n                if (out) {\n                    *out = neg_allowed ? number : -number;\n                }\n\n                return prob_float ? DataType::CSV_DOUBLE : _determine_integral_type(number);\n            }\n\n            // Just whitespace\n            return DataType::CSV_NULL;\n        }\n    }\n}\n\nnamespace csv {\n    namespace internals {\n        class IBasicCSVParser;\n\n        static const std::string ERROR_NAN = \"Not a number.\";\n        static const std::string ERROR_OVERFLOW = \"Overflow error.\";\n        static const std::string ERROR_FLOAT_TO_INT =\n            \"Attempted to convert a floating point value to an integral type.\";\n        static const std::string ERROR_NEG_TO_UNSIGNED = \"Negative numbers cannot be converted to unsigned types.\";\n    \n        std::string json_escape_string(csv::string_view s) noexcept;\n\n        /** A barebones class used for describing CSV fields */\n        struct RawCSVField {\n            RawCSVField() = default;\n            RawCSVField(size_t _start, size_t _length, bool _double_quote = false) {\n                start = _start;\n                length = _length;\n                has_double_quote = _double_quote;\n            }\n\n            /** The start of the field, relative to the beginning of the row */\n            size_t start;\n\n            /** The length of the row, ignoring quote escape characters */\n            size_t length; \n\n            /** Whether or not the field contains an escaped quote */\n            bool has_double_quote;\n        };\n\n        /** A class used for efficiently storing RawCSVField objects and expanding as necessary\n         *\n         *  @par Implementation\n         *  This data structure stores RawCSVField in continguous blocks. When more capacity\n         *  is needed, a new block is allocated, but previous data stays put.\n         *\n         *  @par Thread Safety\n         *  This class may be safely read from multiple threads and written to from one,\n         *  as long as the writing thread does not actively touch fields which are being\n         *  read.\n         */\n        class CSVFieldList {\n        public:\n            /** Construct a CSVFieldList which allocates blocks of a certain size */\n            CSVFieldList(size_t single_buffer_capacity = (size_t)(internals::PAGE_SIZE / sizeof(RawCSVField))) :\n                _single_buffer_capacity(single_buffer_capacity) {\n                this->allocate();\n            }\n\n            // No copy constructor\n            CSVFieldList(const CSVFieldList& other) = delete;\n\n            // CSVFieldArrays may be moved\n            CSVFieldList(CSVFieldList&& other) :\n                _single_buffer_capacity(other._single_buffer_capacity) {\n                buffers = std::move(other.buffers);\n                _current_buffer_size = other._current_buffer_size;\n                _back = other._back;\n            }\n\n            ~CSVFieldList() {\n                for (auto& buffer : buffers)\n                    delete[] buffer;\n            }\n\n            template <class... Args>\n            void emplace_back(Args&&... args) {\n                if (this->_current_buffer_size == this->_single_buffer_capacity) {\n                    this->allocate();\n                }\n\n                *(_back++) = RawCSVField(std::forward<Args>(args)...);\n                _current_buffer_size++;\n            }\n\n            size_t size() const noexcept {\n                return this->_current_buffer_size + ((this->buffers.size() - 1) * this->_single_buffer_capacity);\n            }\n\n            RawCSVField& operator[](size_t n) const;\n\n        private:\n            const size_t _single_buffer_capacity;\n\n            std::vector<RawCSVField*> buffers = {};\n\n            /** Number of items in the current buffer */\n            size_t _current_buffer_size = 0;\n\n            /** Pointer to the current empty field */\n            RawCSVField* _back = nullptr;\n\n            /** Allocate a new page of memory */\n            void allocate();\n        };\n\n\n        /** A class for storing raw CSV data and associated metadata */\n        struct RawCSVData {\n            std::shared_ptr<void> _data = nullptr;\n            csv::string_view data = \"\";\n\n            internals::CSVFieldList fields;\n\n            std::unordered_set<size_t> has_double_quotes = {};\n\n            // TODO: Consider replacing with a more thread-safe structure\n            std::unordered_map<size_t, std::string> double_quote_fields = {};\n\n            internals::ColNamesPtr col_names = nullptr;\n            internals::ParseFlagMap parse_flags;\n            internals::WhitespaceMap ws_flags;\n        };\n\n        using RawCSVDataPtr = std::shared_ptr<RawCSVData>;\n    }\n\n    /**\n    * @class CSVField\n    * @brief Data type representing individual CSV values.\n    *        CSVFields can be obtained by using CSVRow::operator[]\n    */\n    class CSVField {\n    public:\n        /** Constructs a CSVField from a string_view */\n        constexpr explicit CSVField(csv::string_view _sv) noexcept : sv(_sv) { };\n\n        operator std::string() const {\n            return std::string(\"<CSVField> \") + std::string(this->sv);\n        }\n\n        /** Returns the value casted to the requested type, performing type checking before.\n        *\n        *  \\par Valid options for T\n        *   - std::string or csv::string_view\n        *   - signed integral types (signed char, short, int, long int, long long int)\n        *   - floating point types (float, double, long double)\n        *   - unsigned integers are not supported at this time, but may be in a later release\n        *\n        *  \\par Invalid conversions\n        *   - Converting non-numeric values to any numeric type\n        *   - Converting floating point values to integers\n        *   - Converting a large integer to a smaller type that will not hold it\n        *\n        *  @note    This method is capable of parsing scientific E-notation.\n        *           See [this page](md_docs_source_scientific_notation.html)\n        *           for more details.\n        *\n        *  @throws  std::runtime_error Thrown if an invalid conversion is performed.\n        *\n        *  @warning Currently, conversions to floating point types are not\n        *           checked for loss of precision\n        *\n        *  @warning Any string_views returned are only guaranteed to be valid\n        *           if the parent CSVRow is still alive. If you are concerned\n        *           about object lifetimes, then grab a std::string or a\n        *           numeric value.\n        *\n        */\n        template<typename T = std::string> T get() {\n            IF_CONSTEXPR(std::is_arithmetic<T>::value) {\n                // Note: this->type() also converts the CSV value to float\n                if (this->type() <= DataType::CSV_STRING) {\n                    throw std::runtime_error(internals::ERROR_NAN);\n                }\n            }\n\n            IF_CONSTEXPR(std::is_integral<T>::value) {\n                // Note: this->is_float() also converts the CSV value to float\n                if (this->is_float()) {\n                    throw std::runtime_error(internals::ERROR_FLOAT_TO_INT);\n                }\n\n                IF_CONSTEXPR(std::is_unsigned<T>::value) {\n                    if (this->value < 0) {\n                        throw std::runtime_error(internals::ERROR_NEG_TO_UNSIGNED);\n                    }\n                }\n            }\n\n            // Allow fallthrough from previous if branch\n            IF_CONSTEXPR(!std::is_floating_point<T>::value) {\n                IF_CONSTEXPR(std::is_unsigned<T>::value) {\n                    // Quick hack to perform correct unsigned integer boundary checks\n                    if (this->value > internals::get_uint_max<sizeof(T)>()) {\n                        throw std::runtime_error(internals::ERROR_OVERFLOW);\n                    }\n                }\n                else if (internals::type_num<T>() < this->_type) {\n                    throw std::runtime_error(internals::ERROR_OVERFLOW);\n                }\n            }\n\n            return static_cast<T>(this->value);\n        }\n\n        /** Parse a hexadecimal value, returning false if the value is not hex. */\n        bool try_parse_hex(int& parsedValue);\n\n        /** Compares the contents of this field to a numeric value. If this\n         *  field does not contain a numeric value, then all comparisons return\n         *  false.\n         *\n         *  @note    Floating point values are considered equal if they are within\n         *           `0.000001` of each other.\n         *\n         *  @warning Multiple numeric comparisons involving the same field can\n         *           be done more efficiently by calling the CSVField::get<>() method.\n         *\n         *  @sa      csv::CSVField::operator==(const char * other)\n         *  @sa      csv::CSVField::operator==(csv::string_view other)\n         */\n        template<typename T>\n        CONSTEXPR_14 bool operator==(T other) const noexcept\n        {\n            static_assert(std::is_arithmetic<T>::value,\n                \"T should be a numeric value.\");\n\n            if (this->_type != DataType::UNKNOWN) {\n                if (this->_type == DataType::CSV_STRING) {\n                    return false;\n                }\n\n                return internals::is_equal(value, static_cast<long double>(other), 0.000001L);\n            }\n\n            long double out = 0;\n            if (internals::data_type(this->sv, &out) == DataType::CSV_STRING) {\n                return false;\n            }\n\n            return internals::is_equal(out, static_cast<long double>(other), 0.000001L);\n        }\n\n        /** Return a string view over the field's contents */\n        CONSTEXPR csv::string_view get_sv() const noexcept { return this->sv; }\n\n        /** Returns true if field is an empty string or string of whitespace characters */\n        CONSTEXPR_14 bool is_null() noexcept { return type() == DataType::CSV_NULL; }\n\n        /** Returns true if field is a non-numeric, non-empty string */\n        CONSTEXPR_14 bool is_str() noexcept { return type() == DataType::CSV_STRING; }\n\n        /** Returns true if field is an integer or float */\n        CONSTEXPR_14 bool is_num() noexcept { return type() >= DataType::CSV_INT8; }\n\n        /** Returns true if field is an integer */\n        CONSTEXPR_14 bool is_int() noexcept {\n            return (type() >= DataType::CSV_INT8) && (type() <= DataType::CSV_INT64);\n        }\n\n        /** Returns true if field is a floating point value */\n        CONSTEXPR_14 bool is_float() noexcept { return type() == DataType::CSV_DOUBLE; };\n\n        /** Return the type of the underlying CSV data */\n        CONSTEXPR_14 DataType type() noexcept {\n            this->get_value();\n            return _type;\n        }\n\n    private:\n        long double value = 0;    /**< Cached numeric value */\n        csv::string_view sv = \"\"; /**< A pointer to this field's text */\n        DataType _type = DataType::UNKNOWN; /**< Cached data type value */\n        CONSTEXPR_14 void get_value() noexcept {\n            /* Check to see if value has been cached previously, if not\n             * evaluate it\n             */\n            if ((int)_type < 0) {\n                this->_type = internals::data_type(this->sv, &this->value);\n            }\n        }\n    };\n\n    /** Data structure for representing CSV rows */\n    class CSVRow {\n    public:\n        friend internals::IBasicCSVParser;\n\n        CSVRow() = default;\n        \n        /** Construct a CSVRow from a RawCSVDataPtr */\n        CSVRow(internals::RawCSVDataPtr _data) : data(_data) {}\n        CSVRow(internals::RawCSVDataPtr _data, size_t _data_start, size_t _field_bounds)\n            : data(_data), data_start(_data_start), fields_start(_field_bounds) {}\n\n        /** Indicates whether row is empty or not */\n        CONSTEXPR bool empty() const noexcept { return this->size() == 0; }\n\n        /** Return the number of fields in this row */\n        CONSTEXPR size_t size() const noexcept { return row_length; }\n\n        /** @name Value Retrieval */\n        ///@{\n        CSVField operator[](size_t n) const;\n        CSVField operator[](const std::string&) const;\n        std::string to_json(const std::vector<std::string>& subset = {}) const;\n        std::string to_json_array(const std::vector<std::string>& subset = {}) const;\n\n        /** Retrieve this row's associated column names */\n        std::vector<std::string> get_col_names() const {\n            return this->data->col_names->get_col_names();\n        }\n\n        /** Convert this CSVRow into a vector of strings.\n         *  **Note**: This is a less efficient method of\n         *  accessing data than using the [] operator.\n         */\n        operator std::vector<std::string>() const;\n        ///@}\n\n        /** A random access iterator over the contents of a CSV row.\n         *  Each iterator points to a CSVField.\n         */\n        class iterator {\n        public:\n#ifndef DOXYGEN_SHOULD_SKIP_THIS\n            using value_type = CSVField;\n            using difference_type = int;\n\n            // Using CSVField * as pointer type causes segfaults in MSVC debug builds\n            // but using shared_ptr as pointer type won't compile in g++\n#ifdef _MSC_BUILD\n            using pointer = std::shared_ptr<CSVField>;\n#else\n            using pointer = CSVField * ;\n#endif\n\n            using reference = CSVField & ;\n            using iterator_category = std::random_access_iterator_tag;\n#endif\n            iterator(const CSVRow*, int i);\n\n            reference operator*() const;\n            pointer operator->() const;\n\n            iterator operator++(int);\n            iterator& operator++();\n            iterator operator--(int);\n            iterator& operator--();\n            iterator operator+(difference_type n) const;\n            iterator operator-(difference_type n) const;\n\n            /** Two iterators are equal if they point to the same field */\n            CONSTEXPR bool operator==(const iterator& other) const noexcept {\n                return this->i == other.i;\n            };\n\n            CONSTEXPR bool operator!=(const iterator& other) const noexcept { return !operator==(other); }\n\n#ifndef NDEBUG\n            friend CSVRow;\n#endif\n\n        private:\n            const CSVRow * daddy = nullptr;            // Pointer to parent\n            std::shared_ptr<CSVField> field = nullptr; // Current field pointed at\n            int i = 0;                                 // Index of current field\n        };\n\n        /** A reverse iterator over the contents of a CSVRow. */\n        using reverse_iterator = std::reverse_iterator<iterator>;\n\n        /** @name Iterators\n         *  @brief Each iterator points to a CSVField object.\n         */\n         ///@{\n        iterator begin() const;\n        iterator end() const noexcept;\n        reverse_iterator rbegin() const noexcept;\n        reverse_iterator rend() const;\n        ///@}\n\n    private:\n        /** Retrieve a string view corresponding to the specified index */\n        csv::string_view get_field(size_t index) const;\n\n        internals::RawCSVDataPtr data;\n\n        /** Where in RawCSVData.data we start */\n        size_t data_start = 0;\n\n        /** Where in the RawCSVDataPtr.fields array we start */\n        size_t fields_start = 0;\n\n        /** How many columns this row spans */\n        size_t row_length = 0;\n    };\n\n#ifdef _MSC_VER\n#pragma region CSVField::get Specializations\n#endif\n    /** Retrieve this field's original string */\n    template<>\n    inline std::string CSVField::get<std::string>() {\n        return std::string(this->sv);\n    }\n\n    /** Retrieve a view over this field's string\n     *\n     *  @warning This string_view is only guaranteed to be valid as long as this\n     *           CSVRow is still alive.\n     */\n    template<>\n    CONSTEXPR_14 csv::string_view CSVField::get<csv::string_view>() {\n        return this->sv;\n    }\n\n    /** Retrieve this field's value as a long double */\n    template<>\n    CONSTEXPR_14 long double CSVField::get<long double>() {\n        if (!is_num())\n            throw std::runtime_error(internals::ERROR_NAN);\n\n        return this->value;\n    }\n#ifdef _MSC_VER\n#pragma endregion CSVField::get Specializations\n#endif\n\n    /** Compares the contents of this field to a string */\n    template<>\n    CONSTEXPR bool CSVField::operator==(const char * other) const noexcept\n    {\n        return this->sv == other;\n    }\n\n    /** Compares the contents of this field to a string */\n    template<>\n    CONSTEXPR bool CSVField::operator==(csv::string_view other) const noexcept\n    {\n        return this->sv == other;\n    }\n}\n\ninline std::ostream& operator << (std::ostream& os, csv::CSVField const& value) {\n    os << std::string(value);\n    return os;\n}\n\n\nnamespace csv {\n    namespace internals {\n        /** Create a vector v where each index i corresponds to the\n         *  ASCII number for a character and, v[i + 128] labels it according to\n         *  the CSVReader::ParseFlags enum\n         */\n        HEDLEY_CONST CONSTEXPR_17 ParseFlagMap make_parse_flags(char delimiter) {\n            std::array<ParseFlags, 256> ret = {};\n            for (int i = -128; i < 128; i++) {\n                const int arr_idx = i + 128;\n                char ch = char(i);\n\n                if (ch == delimiter)\n                    ret[arr_idx] = ParseFlags::DELIMITER;\n                else if (ch == '\\r' || ch == '\\n')\n                    ret[arr_idx] = ParseFlags::NEWLINE;\n                else\n                    ret[arr_idx] = ParseFlags::NOT_SPECIAL;\n            }\n\n            return ret;\n        }\n\n        /** Create a vector v where each index i corresponds to the\n         *  ASCII number for a character and, v[i + 128] labels it according to\n         *  the CSVReader::ParseFlags enum\n         */\n        HEDLEY_CONST CONSTEXPR_17 ParseFlagMap make_parse_flags(char delimiter, char quote_char) {\n            std::array<ParseFlags, 256> ret = make_parse_flags(delimiter);\n            ret[(size_t)quote_char + 128] = ParseFlags::QUOTE;\n            return ret;\n        }\n\n        /** Create a vector v where each index i corresponds to the\n         *  ASCII number for a character c and, v[i + 128] is true if\n         *  c is a whitespace character\n         */\n        HEDLEY_CONST CONSTEXPR_17 WhitespaceMap make_ws_flags(const char* ws_chars, size_t n_chars) {\n            std::array<bool, 256> ret = {};\n            for (int i = -128; i < 128; i++) {\n                const int arr_idx = i + 128;\n                char ch = char(i);\n                ret[arr_idx] = false;\n\n                for (size_t j = 0; j < n_chars; j++) {\n                    if (ws_chars[j] == ch) {\n                        ret[arr_idx] = true;\n                    }\n                }\n            }\n\n            return ret;\n        }\n\n        inline WhitespaceMap make_ws_flags(const std::vector<char>& flags) {\n            return make_ws_flags(flags.data(), flags.size());\n        }\n\n        CSV_INLINE size_t get_file_size(csv::string_view filename);\n\n        CSV_INLINE std::string get_csv_head(csv::string_view filename);\n\n        /** Read the first 500KB of a CSV file */\n        CSV_INLINE std::string get_csv_head(csv::string_view filename, size_t file_size);\n\n        /** A std::deque wrapper which allows multiple read and write threads to concurrently\n         *  access it along with providing read threads the ability to wait for the deque\n         *  to become populated\n         */\n        template<typename T>\n        class ThreadSafeDeque {\n        public:\n            ThreadSafeDeque(size_t notify_size = 100) : _notify_size(notify_size) {};\n            ThreadSafeDeque(const ThreadSafeDeque& other) {\n                this->data = other.data;\n                this->_notify_size = other._notify_size;\n            }\n\n            ThreadSafeDeque(const std::deque<T>& source) : ThreadSafeDeque() {\n                this->data = source;\n            }\n\n            void clear() noexcept { this->data.clear(); }\n\n            bool empty() const noexcept {\n                return this->data.empty();\n            }\n\n            T& front() noexcept {\n                return this->data.front();\n            }\n\n            T& operator[](size_t n) {\n                return this->data[n];\n            }\n\n            void push_back(T&& item) {\n                std::lock_guard<std::mutex> lock{ this->_lock };\n                this->data.push_back(std::move(item));\n\n                if (this->size() >= _notify_size) {\n                    this->_cond.notify_all();\n                }\n            }\n\n            T pop_front() noexcept {\n                std::lock_guard<std::mutex> lock{ this->_lock };\n                T item = std::move(data.front());\n                data.pop_front();\n                return item;\n            }\n\n            size_t size() const noexcept { return this->data.size(); }\n\n            /** Returns true if a thread is actively pushing items to this deque */\n            constexpr bool is_waitable() const noexcept { return this->_is_waitable; }\n\n            /** Wait for an item to become available */\n            void wait() {\n                if (!is_waitable()) {\n                    return;\n                }\n\n                std::unique_lock<std::mutex> lock{ this->_lock };\n                this->_cond.wait(lock, [this] { return this->size() >= _notify_size || !this->is_waitable(); });\n                lock.unlock();\n            }\n\n            typename std::deque<T>::iterator begin() noexcept {\n                return this->data.begin();\n            }\n\n            typename std::deque<T>::iterator end() noexcept {\n                return this->data.end();\n            }\n\n            /** Tell listeners that this deque is actively being pushed to */\n            void notify_all() {\n                std::unique_lock<std::mutex> lock{ this->_lock };\n                this->_is_waitable = true;\n                this->_cond.notify_all();\n            }\n\n            /** Tell all listeners to stop */\n            void kill_all() {\n                std::unique_lock<std::mutex> lock{ this->_lock };\n                this->_is_waitable = false;\n                this->_cond.notify_all();\n            }\n\n        private:\n            bool _is_waitable = false;\n            size_t _notify_size;\n            std::mutex _lock;\n            std::condition_variable _cond;\n            std::deque<T> data;\n        };\n\n        constexpr const int UNINITIALIZED_FIELD = -1;\n    }\n\n    /** Standard type for storing collection of rows */\n    using RowCollection = internals::ThreadSafeDeque<CSVRow>;\n\n    namespace internals {\n        /** Abstract base class which provides CSV parsing logic.\n         *\n         *  Concrete implementations may customize this logic across\n         *  different input sources, such as memory mapped files, stringstreams,\n         *  etc...\n         */\n        class IBasicCSVParser {\n        public:\n            IBasicCSVParser() = default;\n            IBasicCSVParser(const CSVFormat&, const ColNamesPtr&);\n            IBasicCSVParser(const ParseFlagMap& parse_flags, const WhitespaceMap& ws_flags\n            ) : _parse_flags(parse_flags), _ws_flags(ws_flags) {};\n\n            virtual ~IBasicCSVParser() {}\n\n            /** Whether or not we have reached the end of source */\n            bool eof() { return this->_eof; }\n\n            /** Parse the next block of data */\n            virtual void next(size_t bytes) = 0;\n\n            /** Indicate the last block of data has been parsed */\n            void end_feed();\n\n            CONSTEXPR_17 ParseFlags parse_flag(const char ch) const noexcept {\n                return _parse_flags.data()[ch + 128];\n            }\n\n            CONSTEXPR_17 ParseFlags compound_parse_flag(const char ch) const noexcept {\n                return quote_escape_flag(parse_flag(ch), this->quote_escape);\n            }\n\n            /** Whether or not this CSV has a UTF-8 byte order mark */\n            CONSTEXPR bool utf8_bom() const { return this->_utf8_bom; }\n\n            void set_output(RowCollection& rows) { this->_records = &rows; }\n\n        protected:\n            /** @name Current Parser State */\n            ///@{\n            CSVRow current_row;\n            RawCSVDataPtr data_ptr = nullptr;\n            ColNamesPtr _col_names = nullptr;\n            CSVFieldList* fields = nullptr;\n            int field_start = UNINITIALIZED_FIELD;\n            size_t field_length = 0;\n\n            /** An array where the (i + 128)th slot gives the ParseFlags for ASCII character i */\n            ParseFlagMap _parse_flags;\n            ///@}\n\n            /** @name Current Stream/File State */\n            ///@{\n            bool _eof = false;\n\n            /** The size of the incoming CSV */\n            size_t source_size = 0;\n            ///@}\n\n            /** Whether or not source needs to be read in chunks */\n            CONSTEXPR bool no_chunk() const { return this->source_size < ITERATION_CHUNK_SIZE; }\n\n            /** Parse the current chunk of data *\n             *\n             *  @returns How many character were read that are part of complete rows\n             */\n            size_t parse();\n\n            /** Create a new RawCSVDataPtr for a new chunk of data */\n            void reset_data_ptr();\n        private:\n            /** An array where the (i + 128)th slot determines whether ASCII character i should\n             *  be trimmed\n             */\n            WhitespaceMap _ws_flags;\n            bool quote_escape = false;\n            bool field_has_double_quote = false;\n\n            /** Where we are in the current data block */\n            size_t data_pos = 0;\n\n            /** Whether or not an attempt to find Unicode BOM has been made */\n            bool unicode_bom_scan = false;\n            bool _utf8_bom = false;\n\n            /** Where complete rows should be pushed to */\n            RowCollection* _records = nullptr;\n\n            CONSTEXPR_17 bool ws_flag(const char ch) const noexcept {\n                return _ws_flags.data()[ch + 128];\n            }\n\n            size_t& current_row_start() {\n                return this->current_row.data_start;\n            }\n\n            void parse_field() noexcept;\n\n            /** Finish parsing the current field */\n            void push_field();\n\n            /** Finish parsing the current row */\n            void push_row();\n\n            /** Handle possible Unicode byte order mark */\n            void trim_utf8_bom();\n        };\n\n        /** A class for parsing CSV data from a `std::stringstream`\n         *  or an `std::ifstream`\n         */\n        template<typename TStream>\n        class StreamParser: public IBasicCSVParser {\n            using RowCollection = ThreadSafeDeque<CSVRow>;\n\n        public:\n            StreamParser(TStream& source,\n                const CSVFormat& format,\n                const ColNamesPtr& col_names = nullptr\n            ) : IBasicCSVParser(format, col_names), _source(std::move(source)) {};\n\n            StreamParser(\n                TStream& source,\n                internals::ParseFlagMap parse_flags,\n                internals::WhitespaceMap ws_flags) :\n                IBasicCSVParser(parse_flags, ws_flags),\n                _source(std::move(source))\n            {};\n\n            ~StreamParser() {}\n\n            void next(size_t bytes = ITERATION_CHUNK_SIZE) override {\n                if (this->eof()) return;\n\n                this->reset_data_ptr();\n                this->data_ptr->_data = std::make_shared<std::string>();\n\n                if (source_size == 0) {\n                    const auto start = _source.tellg();\n                    _source.seekg(0, std::ios::end);\n                    const auto end = _source.tellg();\n                    _source.seekg(0, std::ios::beg);\n\n                    source_size = end - start;\n                }\n\n                // Read data into buffer\n                size_t length = std::min(source_size - stream_pos, bytes);\n                std::unique_ptr<char[]> buff(new char[length]);\n                _source.seekg(stream_pos, std::ios::beg);\n                _source.read(buff.get(), length);\n                stream_pos = _source.tellg();\n                ((std::string*)(this->data_ptr->_data.get()))->assign(buff.get(), length);\n\n                // Create string_view\n                this->data_ptr->data = *((std::string*)this->data_ptr->_data.get());\n\n                // Parse\n                this->current_row = CSVRow(this->data_ptr);\n                size_t remainder = this->parse();\n\n                if (stream_pos == source_size || no_chunk()) {\n                    this->_eof = true;\n                    this->end_feed();\n                }\n                else {\n                    this->stream_pos -= (length - remainder);\n                }\n            }\n\n        private:\n            TStream _source;\n            size_t stream_pos = 0;\n        };\n\n        /** Parser for memory-mapped files\n         *\n         *  @par Implementation\n         *  This class constructs moving windows over a file to avoid\n         *  creating massive memory maps which may require more RAM\n         *  than the user has available. It contains logic to automatically\n         *  re-align each memory map to the beginning of a CSV row.\n         *\n         */\n        class MmapParser : public IBasicCSVParser {\n        public:\n            MmapParser(csv::string_view filename,\n                const CSVFormat& format,\n                const ColNamesPtr& col_names = nullptr\n            ) : IBasicCSVParser(format, col_names) {\n                this->_filename = filename.data();\n                this->source_size = get_file_size(filename);\n            };\n\n            ~MmapParser() {}\n\n            void next(size_t bytes) override;\n\n        private:\n            std::string _filename;\n            size_t mmap_pos = 0;\n        };\n    }\n}\n\n\n/** The all encompassing namespace */\nnamespace csv {\n    /** Stuff that is generally not of interest to end-users */\n    namespace internals {\n        std::string format_row(const std::vector<std::string>& row, csv::string_view delim = \", \");\n\n        std::vector<std::string> _get_col_names( csv::string_view head, const CSVFormat format = CSVFormat::guess_csv());\n\n        struct GuessScore {\n            double score;\n            size_t header;\n        };\n\n        CSV_INLINE GuessScore calculate_score(csv::string_view head, CSVFormat format);\n\n        CSVGuessResult _guess_format(csv::string_view head, const std::vector<char>& delims = { ',', '|', '\\t', ';', '^', '~' });\n    }\n\n    std::vector<std::string> get_col_names(\n        csv::string_view filename,\n        const CSVFormat format = CSVFormat::guess_csv());\n\n    /** Guess the delimiter used by a delimiter-separated values file */\n    CSVGuessResult guess_format(csv::string_view filename,\n        const std::vector<char>& delims = { ',', '|', '\\t', ';', '^', '~' });\n\n    /** @class CSVReader\n     *  @brief Main class for parsing CSVs from files and in-memory sources\n     *\n     *  All rows are compared to the column names for length consistency\n     *  - By default, rows that are too short or too long are dropped\n     *  - Custom behavior can be defined by overriding bad_row_handler in a subclass\n     */\n    class CSVReader {\n    public:\n        /**\n         * An input iterator capable of handling large files.\n         * @note Created by CSVReader::begin() and CSVReader::end().\n         *\n         * @par Iterating over a file\n         * @snippet tests/test_csv_iterator.cpp CSVReader Iterator 1\n         *\n         * @par Using with `<algorithm>` library\n         * @snippet tests/test_csv_iterator.cpp CSVReader Iterator 2\n         */\n        class iterator {\n        public:\n            #ifndef DOXYGEN_SHOULD_SKIP_THIS\n            using value_type = CSVRow;\n            using difference_type = std::ptrdiff_t;\n            using pointer = CSVRow * ;\n            using reference = CSVRow & ;\n            using iterator_category = std::input_iterator_tag;\n            #endif\n\n            iterator() = default;\n            iterator(CSVReader* reader) : daddy(reader) {};\n            iterator(CSVReader*, CSVRow&&);\n\n            /** Access the CSVRow held by the iterator */\n            CONSTEXPR_14 reference operator*() { return this->row; }\n\n            /** Return a pointer to the CSVRow the iterator has stopped at */\n            CONSTEXPR_14 pointer operator->() { return &(this->row); }\n\n            iterator& operator++();   /**< Pre-increment iterator */\n            iterator operator++(int); /**< Post-increment ierator */\n            iterator& operator--();\n\n            /** Returns true if iterators were constructed from the same CSVReader\n             *  and point to the same row\n             */\n            CONSTEXPR bool operator==(const iterator& other) const noexcept {\n                return (this->daddy == other.daddy) && (this->i == other.i);\n            }\n\n            CONSTEXPR bool operator!=(const iterator& other) const noexcept { return !operator==(other); }\n        private:\n            CSVReader * daddy = nullptr;  // Pointer to parent\n            CSVRow row;                   // Current row\n            size_t i = 0;               // Index of current row\n        };\n\n        /** @name Constructors\n         *  Constructors for iterating over large files and parsing in-memory sources.\n         */\n         ///@{\n        CSVReader(csv::string_view filename, CSVFormat format = CSVFormat::guess_csv());\n\n        /** Allows parsing stream sources such as `std::stringstream` or `std::ifstream`\n         *\n         *  @tparam TStream An input stream deriving from `std::istream`\n         *  @note   Currently this constructor requires special CSV dialects to be manually\n         *          specified.\n         */\n        template<typename TStream,\n            csv::enable_if_t<std::is_base_of<std::istream, TStream>::value, int> = 0>\n        CSVReader(TStream& source, CSVFormat format = CSVFormat()) : _format(format) {\n            using Parser = internals::StreamParser<TStream>;\n\n            if (!format.col_names.empty())\n                this->set_col_names(format.col_names);\n\n            this->parser = std::unique_ptr<Parser>(\n                new Parser(source, format, col_names)); // For C++11\n            this->initial_read();\n        }\n        ///@}\n\n        CSVReader(const CSVReader&) = delete; // No copy constructor\n        CSVReader(CSVReader&&) = default;     // Move constructor\n        CSVReader& operator=(const CSVReader&) = delete; // No copy assignment\n        CSVReader& operator=(CSVReader&& other) = default;\n        ~CSVReader() {\n            if (this->read_csv_worker.joinable()) {\n                this->read_csv_worker.join();\n            }\n        }\n\n        /** @name Retrieving CSV Rows */\n        ///@{\n        bool read_row(CSVRow &row);\n        iterator begin();\n        HEDLEY_CONST iterator end() const noexcept;\n\n        /** Returns true if we have reached end of file */\n        bool eof() const noexcept { return this->parser->eof(); };\n        ///@}\n\n        /** @name CSV Metadata */\n        ///@{\n        CSVFormat get_format() const;\n        std::vector<std::string> get_col_names() const;\n        int index_of(csv::string_view col_name) const;\n        ///@}\n\n        /** @name CSV Metadata: Attributes */\n        ///@{\n        /** Whether or not the file or stream contains valid CSV rows,\n         *  not including the header.\n         *\n         *  @note Gives an accurate answer regardless of when it is called.\n         *\n         */\n        CONSTEXPR bool empty() const noexcept { return this->n_rows() == 0; }\n\n        /** Retrieves the number of rows that have been read so far */\n        CONSTEXPR size_t n_rows() const noexcept { return this->_n_rows; }\n\n        /** Whether or not CSV was prefixed with a UTF-8 bom */\n        bool utf8_bom() const noexcept { return this->parser->utf8_bom(); }\n        ///@}\n\n    protected:\n        /**\n         * \\defgroup csv_internal CSV Parser Internals\n         * @brief Internals of CSVReader. Only maintainers and those looking to\n         *        extend the parser should read this.\n         * @{\n         */\n\n        /** Sets this reader's column names and associated data */\n        void set_col_names(const std::vector<std::string>&);\n\n        /** @name CSV Settings **/\n        ///@{\n        CSVFormat _format;\n        ///@}\n\n        /** @name Parser State */\n        ///@{\n        /** Pointer to a object containing column information */\n        internals::ColNamesPtr col_names = std::make_shared<internals::ColNames>();\n\n        /** Helper class which actually does the parsing */\n        std::unique_ptr<internals::IBasicCSVParser> parser = nullptr;\n\n        /** Queue of parsed CSV rows */\n        std::unique_ptr<RowCollection> records{new RowCollection(100)};\n\n        size_t n_cols = 0;  /**< The number of columns in this CSV */\n        size_t _n_rows = 0; /**< How many rows (minus header) have been read so far */\n\n        /** @name Multi-Threaded File Reading Functions */\n        ///@{\n        bool read_csv(size_t bytes = internals::ITERATION_CHUNK_SIZE);\n        ///@}\n\n        /**@}*/\n\n    private:\n        /** Whether or not rows before header were trimmed */\n        bool header_trimmed = false;\n\n        /** @name Multi-Threaded File Reading: Flags and State */\n        ///@{\n        std::thread read_csv_worker; /**< Worker thread for read_csv() */\n        ///@}\n\n        /** Read initial chunk to get metadata */\n        void initial_read() {\n            this->read_csv_worker = std::thread(&CSVReader::read_csv, this, internals::ITERATION_CHUNK_SIZE);\n            this->read_csv_worker.join();\n        }\n\n        void trim_header();\n    };\n}\n\n/** @file\n *  Calculates statistics from CSV files\n */\n\n#include <unordered_map>\n#include <sstream>\n#include <vector>\n\nnamespace csv {\n    /** Class for calculating statistics from CSV files and in-memory sources\n     *\n     *  **Example**\n     *  \\include programs/csv_stats.cpp\n     *\n     */\n    class CSVStat {\n    public:\n        using FreqCount = std::unordered_map<std::string, size_t>;\n        using TypeCount = std::unordered_map<DataType, size_t>;\n\n        std::vector<long double> get_mean() const;\n        std::vector<long double> get_variance() const;\n        std::vector<long double> get_mins() const;\n        std::vector<long double> get_maxes() const;\n        std::vector<FreqCount> get_counts() const;\n        std::vector<TypeCount> get_dtypes() const;\n\n        std::vector<std::string> get_col_names() const {\n            return this->reader.get_col_names();\n        }\n\n        CSVStat(csv::string_view filename, CSVFormat format = CSVFormat::guess_csv());\n        CSVStat(std::stringstream& source, CSVFormat format = CSVFormat());\n    private:\n        // An array of rolling averages\n        // Each index corresponds to the rolling mean for the column at said index\n        std::vector<long double> rolling_means;\n        std::vector<long double> rolling_vars;\n        std::vector<long double> mins;\n        std::vector<long double> maxes;\n        std::vector<FreqCount> counts;\n        std::vector<TypeCount> dtypes;\n        std::vector<long double> n;\n\n        // Statistic calculators\n        void variance(const long double&, const size_t&);\n        void count(CSVField&, const size_t&);\n        void min_max(const long double&, const size_t&);\n        void dtype(CSVField&, const size_t&);\n\n        void calc();\n        void calc_chunk();\n        void calc_worker(const size_t&);\n\n        CSVReader reader;\n        std::deque<CSVRow> records = {};\n    };\n}\n\n#include <string>\n#include <type_traits>\n#include <unordered_map>\n\nnamespace csv {\n    /** Returned by get_file_info() */\n    struct CSVFileInfo {\n        std::string filename;               /**< Filename */\n        std::vector<std::string> col_names; /**< CSV column names */\n        char delim;                         /**< Delimiting character */\n        size_t n_rows;                      /**< Number of rows in a file */\n        size_t n_cols;                      /**< Number of columns in a CSV */\n    };\n\n    /** @name Shorthand Parsing Functions\n     *  @brief Convienience functions for parsing small strings\n     */\n     ///@{\n    CSVReader operator \"\"_csv(const char*, size_t);\n    CSVReader operator \"\"_csv_no_header(const char*, size_t);\n    CSVReader parse(csv::string_view in, CSVFormat format = CSVFormat());\n    CSVReader parse_no_header(csv::string_view in);\n    ///@}\n\n    /** @name Utility Functions */\n    ///@{\n    std::unordered_map<std::string, DataType> csv_data_types(const std::string&);\n    CSVFileInfo get_file_info(const std::string& filename);\n    int get_col_pos(csv::string_view filename, csv::string_view col_name,\n        const CSVFormat& format = CSVFormat::guess_csv());\n    ///@}\n}\n/** @file\n  *  A standalone header file for writing delimiter-separated files\n  */\n\n#include <fstream>\n#include <iostream>\n#include <string>\n#include <tuple>\n#include <type_traits>\n#include <vector>\n\n\nnamespace csv {\n    namespace internals {\n        static int DECIMAL_PLACES = 5;\n\n        /** to_string() for unsigned integers */\n        template<typename T,\n            csv::enable_if_t<std::is_unsigned<T>::value, int> = 0>\n        inline std::string to_string(T value) {\n            std::string digits_reverse = \"\";\n\n            if (value == 0) return \"0\";\n\n            while (value > 0) {\n                digits_reverse += (char)('0' + (value % 10));\n                value /= 10;\n            }\n\n            return std::string(digits_reverse.rbegin(), digits_reverse.rend());\n        }\n\n        /** to_string() for signed integers */\n        template<\n            typename T,\n            csv::enable_if_t<std::is_integral<T>::value && std::is_signed<T>::value, int> = 0\n        >\n        inline std::string to_string(T value) {\n            if (value >= 0)\n                return to_string((size_t)value);\n\n            return \"-\" + to_string((size_t)(value * -1));\n        }\n\n        /** to_string() for floating point numbers */\n        template<\n            typename T,\n            csv::enable_if_t<std::is_floating_point<T>::value, int> = 0\n        >\n            inline std::string to_string(T value) {\n                std::string result;\n\n                T integral_part;\n                T fractional_part = std::abs(std::modf(value, &integral_part));\n                integral_part = std::abs(integral_part);\n\n                // Integral part\n                if (value < 0) result = \"-\";\n\n                if (integral_part == 0) {\n                    result = \"0\";\n                }\n                else {\n                    for (int n_digits = (int)(std::log(integral_part) / std::log(10));\n                         n_digits + 1 > 0; n_digits --) {\n                        int digit = (int)(std::fmod(integral_part, pow10(n_digits + 1)) / pow10(n_digits));\n                        result += (char)('0' + digit);\n                    }\n                }\n\n                // Decimal part\n                result += \".\";\n\n                if (fractional_part > 0) {\n                    fractional_part *= (T)(pow10(DECIMAL_PLACES));\n                    for (int n_digits = DECIMAL_PLACES; n_digits > 0; n_digits--) {\n                        int digit = (int)(std::fmod(fractional_part, pow10(n_digits)) / pow10(n_digits - 1));\n                        result += (char)('0' + digit);\n                    }\n                }\n                else {\n                    result += \"0\";\n                }\n\n                return result;\n        }\n    }\n\n    /** Sets how many places after the decimal will be written for floating point numbers\n     *\n     *  @param  precision   Number of decimal places\n     */\n    inline static void set_decimal_places(int precision) {\n        internals::DECIMAL_PLACES = precision;\n    }\n\n    /** @name CSV Writing */\n    ///@{\n    /** \n     *  Class for writing delimiter separated values files\n     *\n     *  To write formatted strings, one should\n     *   -# Initialize a DelimWriter with respect to some output stream \n     *   -# Call write_row() on std::vector<std::string>s of unformatted text\n     *\n     *  @tparam OutputStream The output stream, e.g. `std::ofstream`, `std::stringstream`\n     *  @tparam Delim        The delimiter character\n     *  @tparam Quote        The quote character\n     *  @tparam Flush        True: flush after every writing function,\n     *                       false: you need to flush explicitly if needed.\n     *                       In both cases the destructor will flush.\n     *\n     *  @par Hint\n     *  Use the aliases csv::CSVWriter<OutputStream> to write CSV\n     *  formatted strings and csv::TSVWriter<OutputStream>\n     *  to write tab separated strings\n     *\n     *  @par Example w/ std::vector, std::deque, std::list\n     *  @snippet test_write_csv.cpp CSV Writer Example\n     *\n     *  @par Example w/ std::tuple\n     *  @snippet test_write_csv.cpp CSV Writer Tuple Example\n     */\n    template<class OutputStream, char Delim, char Quote, bool Flush>\n    class DelimWriter {\n    public:\n        /** Construct a DelimWriter over the specified output stream\n         *\n         *  @param  _out           Stream to write to\n         *  @param  _quote_minimal Limit field quoting to only when necessary\n        */\n\n        DelimWriter(OutputStream& _out, bool _quote_minimal = true)\n            : out(_out), quote_minimal(_quote_minimal) {};\n\n        /** Construct a DelimWriter over the file\n         *\n         *  @param[out] filename  File to write to\n         */\n        DelimWriter(const std::string& filename) : DelimWriter(std::ifstream(filename)) {};\n\n        /** Destructor will flush remaining data\n         *\n         */\n        ~DelimWriter() {\n            out.flush();\n        }\n\n        /** Format a sequence of strings and write to CSV according to RFC 4180\n         *\n         *  @warning This does not check to make sure row lengths are consistent\n         *\n         *  @param[in]  record          Sequence of strings to be formatted\n         *\n         *  @return  The current DelimWriter instance (allowing for operator chaining)\n         */\n        template<typename T, size_t Size>\n        DelimWriter& operator<<(const std::array<T, Size>& record) {\n            for (size_t i = 0; i < Size; i++) {\n                out << csv_escape(record[i]);\n                if (i + 1 != Size) out << Delim;\n            }\n\n            end_out();\n            return *this;\n        }\n\n        /** @copydoc operator<< */\n        template<typename... T>\n        DelimWriter& operator<<(const std::tuple<T...>& record) {\n            this->write_tuple<0, T...>(record);\n            return *this;\n        }\n\n        /**\n         * @tparam T A container such as std::vector, std::deque, or std::list\n         * \n         * @copydoc operator<<\n         */\n        template<\n            typename T, typename Alloc, template <typename, typename> class Container,\n\n            // Avoid conflicting with tuples with two elements\n            csv::enable_if_t<std::is_class<Alloc>::value, int> = 0\n        >\n            DelimWriter& operator<<(const Container<T, Alloc>& record) {\n            const size_t ilen = record.size();\n            size_t i = 0;\n            for (const auto& field : record) {\n                out << csv_escape(field);\n                if (i + 1 != ilen) out << Delim;\n                i++;\n            }\n\n            end_out();\n            return *this;\n        }\n\n        /** Flushes the written data\n         *\n         */\n        void flush() {\n            out.flush();\n        }\n\n    private:\n        template<\n            typename T,\n            csv::enable_if_t<\n                !std::is_convertible<T, std::string>::value\n                && !std::is_convertible<T, csv::string_view>::value\n            , int> = 0\n        >\n        std::string csv_escape(T in) {\n            return internals::to_string(in);\n        }\n\n        template<\n            typename T,\n            csv::enable_if_t<\n                std::is_convertible<T, std::string>::value\n                || std::is_convertible<T, csv::string_view>::value\n            , int> = 0\n        >\n        std::string csv_escape(T in) {\n            IF_CONSTEXPR(std::is_convertible<T, csv::string_view>::value) {\n                return _csv_escape(in);\n            }\n            \n            return _csv_escape(std::string(in));\n        }\n\n        std::string _csv_escape(csv::string_view in) {\n            /** Format a string to be RFC 4180-compliant\n             *  @param[in]  in              String to be CSV-formatted\n             *  @param[out] quote_minimal   Only quote fields if necessary.\n             *                              If False, everything is quoted.\n             */\n\n            // Do we need a quote escape\n            bool quote_escape = false;\n\n            for (auto ch : in) {\n                if (ch == Quote || ch == Delim || ch == '\\r' || ch == '\\n') {\n                    quote_escape = true;\n                    break;\n                }\n            }\n\n            if (!quote_escape) {\n                if (quote_minimal) return std::string(in);\n                else {\n                    std::string ret(1, Quote);\n                    ret += in.data();\n                    ret += Quote;\n                    return ret;\n                }\n            }\n\n            // Start initial quote escape sequence\n            std::string ret(1, Quote);\n            for (auto ch: in) {\n                if (ch == Quote) ret += std::string(2, Quote);\n                else ret += ch;\n            }\n\n            // Finish off quote escape\n            ret += Quote;\n            return ret;\n        }\n\n        /** Recurisve template for writing std::tuples */\n        template<size_t Index = 0, typename... T>\n        typename std::enable_if<Index < sizeof...(T), void>::type write_tuple(const std::tuple<T...>& record) {\n            out << csv_escape(std::get<Index>(record));\n\n            IF_CONSTEXPR (Index + 1 < sizeof...(T)) out << Delim;\n\n            this->write_tuple<Index + 1>(record);\n        }\n\n        /** Base case for writing std::tuples */\n        template<size_t Index = 0, typename... T>\n        typename std::enable_if<Index == sizeof...(T), void>::type write_tuple(const std::tuple<T...>& record) {\n            (void)record;\n            end_out();\n        }\n\n        /** Ends a line in 'out' and flushes, if Flush is true.*/\n        void end_out() {\n            out << '\\n';\n            IF_CONSTEXPR(Flush) out.flush();\n        }\n\n        OutputStream & out;\n        bool quote_minimal;\n    };\n\n    /** An alias for csv::DelimWriter for writing standard CSV files\n     *\n     *  @sa csv::DelimWriter::operator<<()\n     *\n     *  @note Use `csv::make_csv_writer()` to in instatiate this class over\n     *        an actual output stream.\n     */\n    template<class OutputStream, bool Flush = true>\n    using CSVWriter = DelimWriter<OutputStream, ',', '\"', Flush>;\n\n    /** Class for writing tab-separated values files\n    *\n     *  @sa csv::DelimWriter::write_row()\n     *  @sa csv::DelimWriter::operator<<()\n     *\n     *  @note Use `csv::make_tsv_writer()` to in instatiate this class over\n     *        an actual output stream.\n     */\n    template<class OutputStream, bool Flush = true>\n    using TSVWriter = DelimWriter<OutputStream, '\\t', '\"', Flush>;\n\n    /** Return a csv::CSVWriter over the output stream */\n    template<class OutputStream>\n    inline CSVWriter<OutputStream> make_csv_writer(OutputStream& out, bool quote_minimal=true) {\n        return CSVWriter<OutputStream>(out, quote_minimal);\n    }\n\n    /** Return a buffered csv::CSVWriter over the output stream (does not auto flush) */\n    template<class OutputStream>\n    inline CSVWriter<OutputStream, false> make_csv_writer_buffered(OutputStream& out, bool quote_minimal=true) {\n        return CSVWriter<OutputStream, false>(out, quote_minimal);\n    }\n\n    /** Return a csv::TSVWriter over the output stream */\n    template<class OutputStream>\n    inline TSVWriter<OutputStream> make_tsv_writer(OutputStream& out, bool quote_minimal=true) {\n        return TSVWriter<OutputStream>(out, quote_minimal);\n    }\n\n    /** Return a buffered csv::TSVWriter over the output stream (does not auto flush) */\n    template<class OutputStream>\n    inline TSVWriter<OutputStream, false> make_tsv_writer_buffered(OutputStream& out, bool quote_minimal=true) {\n        return TSVWriter<OutputStream, false>(out, quote_minimal);\n    }\n    ///@}\n}\n\n\nnamespace csv {\n    namespace internals {\n        CSV_INLINE size_t get_file_size(csv::string_view filename) {\n            std::ifstream infile(std::string(filename), std::ios::binary);\n            const auto start = infile.tellg();\n            infile.seekg(0, std::ios::end);\n            const auto end = infile.tellg();\n\n            return end - start;\n        }\n\n        CSV_INLINE std::string get_csv_head(csv::string_view filename) {\n            return get_csv_head(filename, get_file_size(filename));\n        }\n\n        CSV_INLINE std::string get_csv_head(csv::string_view filename, size_t file_size) {\n            const size_t bytes = 500000;\n\n            std::error_code error;\n            size_t length = std::min((size_t)file_size, bytes);\n            auto mmap = mio::make_mmap_source(std::string(filename), 0, length, error);\n\n            if (error) {\n                throw std::runtime_error(\"Cannot open file \" + std::string(filename));\n            }\n\n            return std::string(mmap.begin(), mmap.end());\n        }\n\n#ifdef _MSC_VER\n#pragma region IBasicCVParser\n#endif\n        CSV_INLINE IBasicCSVParser::IBasicCSVParser(\n            const CSVFormat& format,\n            const ColNamesPtr& col_names\n        ) : _col_names(col_names) {\n            if (format.no_quote) {\n                _parse_flags = internals::make_parse_flags(format.get_delim());\n            }\n            else {\n                _parse_flags = internals::make_parse_flags(format.get_delim(), format.quote_char);\n            }\n\n            _ws_flags = internals::make_ws_flags(\n                format.trim_chars.data(), format.trim_chars.size()\n            );\n        }\n\n        CSV_INLINE void IBasicCSVParser::end_feed() {\n            using internals::ParseFlags;\n\n            bool empty_last_field = this->data_ptr\n                && this->data_ptr->_data\n                && !this->data_ptr->data.empty()\n                && parse_flag(this->data_ptr->data.back()) == ParseFlags::DELIMITER;\n\n            // Push field\n            if (this->field_length > 0 || empty_last_field) {\n                this->push_field();\n            }\n\n            // Push row\n            if (this->current_row.size() > 0)\n                this->push_row();\n        }\n\n        CSV_INLINE void IBasicCSVParser::parse_field() noexcept {\n            using internals::ParseFlags;\n            auto& in = this->data_ptr->data;\n\n            // Trim off leading whitespace\n            while (data_pos < in.size() && ws_flag(in[data_pos]))\n                data_pos++;\n\n            if (field_start == UNINITIALIZED_FIELD)\n                field_start = (int)(data_pos - current_row_start());\n\n            // Optimization: Since NOT_SPECIAL characters tend to occur in contiguous\n            // sequences, use the loop below to avoid having to go through the outer\n            // switch statement as much as possible\n            while (data_pos < in.size() && compound_parse_flag(in[data_pos]) == ParseFlags::NOT_SPECIAL)\n                data_pos++;\n\n            field_length = data_pos - (field_start + current_row_start());\n\n            // Trim off trailing whitespace, this->field_length constraint matters\n            // when field is entirely whitespace\n            for (size_t j = data_pos - 1; ws_flag(in[j]) && this->field_length > 0; j--)\n                this->field_length--;\n        }\n\n        CSV_INLINE void IBasicCSVParser::push_field()\n        {\n            // Update\n            if (field_has_double_quote) {\n                fields->emplace_back(\n                    field_start == UNINITIALIZED_FIELD ? 0 : (unsigned int)field_start,\n                    field_length,\n                    true\n                );\n                field_has_double_quote = false;\n\n            }\n            else {\n                fields->emplace_back(\n                    field_start == UNINITIALIZED_FIELD ? 0 : (unsigned int)field_start,\n                    field_length\n                );\n            }\n\n            current_row.row_length++;\n\n            // Reset field state\n            field_start = UNINITIALIZED_FIELD;\n            field_length = 0;\n        }\n\n        /** @return The number of characters parsed that belong to complete rows */\n        CSV_INLINE size_t IBasicCSVParser::parse()\n        {\n            using internals::ParseFlags;\n\n            this->quote_escape = false;\n            this->data_pos = 0;\n            this->current_row_start() = 0;\n            this->trim_utf8_bom();\n\n            auto& in = this->data_ptr->data;\n            while (this->data_pos < in.size()) {\n                switch (compound_parse_flag(in[this->data_pos])) {\n                case ParseFlags::DELIMITER:\n                    this->push_field();\n                    this->data_pos++;\n                    break;\n\n                case ParseFlags::NEWLINE:\n                    this->data_pos++;\n\n                    // Catches CRLF (or LFLF)\n                    if (this->data_pos < in.size() && parse_flag(in[this->data_pos]) == ParseFlags::NEWLINE)\n                        this->data_pos++;\n\n                    // End of record -> Write record\n                    this->push_field();\n                    this->push_row();\n\n                    // Reset\n                    this->current_row = CSVRow(data_ptr, this->data_pos, fields->size());\n                    break;\n\n                case ParseFlags::NOT_SPECIAL:\n                    this->parse_field();\n                    break;\n\n                case ParseFlags::QUOTE_ESCAPE_QUOTE:\n                    if (data_pos + 1 == in.size()) return this->current_row_start();\n                    else if (data_pos + 1 < in.size()) {\n                        auto next_ch = parse_flag(in[data_pos + 1]);\n                        if (next_ch >= ParseFlags::DELIMITER) {\n                            quote_escape = false;\n                            data_pos++;\n                            break;\n                        }\n                        else if (next_ch == ParseFlags::QUOTE) {\n                            // Case: Escaped quote\n                            data_pos += 2;\n                            this->field_length += 2;\n                            this->field_has_double_quote = true;\n                            break;\n                        }\n                    }\n                    \n                    // Case: Unescaped single quote => not strictly valid but we'll keep it\n                    this->field_length++;\n                    data_pos++;\n\n                    break;\n\n                default: // Quote (currently not quote escaped)\n                    if (this->field_length == 0) {\n                        quote_escape = true;\n                        data_pos++;\n                        if (field_start == UNINITIALIZED_FIELD && data_pos < in.size() && !ws_flag(in[data_pos]))\n                            field_start = (int)(data_pos - current_row_start());\n                        break;\n                    }\n\n                    // Case: Unescaped quote\n                    this->field_length++;\n                    data_pos++;\n\n                    break;\n                }\n            }\n\n            return this->current_row_start();\n        }\n\n        CSV_INLINE void IBasicCSVParser::push_row() {\n            current_row.row_length = fields->size() - current_row.fields_start;\n            this->_records->push_back(std::move(current_row));\n        }\n\n        CSV_INLINE void IBasicCSVParser::reset_data_ptr() {\n            this->data_ptr = std::make_shared<RawCSVData>();\n            this->data_ptr->parse_flags = this->_parse_flags;\n            this->data_ptr->col_names = this->_col_names;\n            this->fields = &(this->data_ptr->fields);\n        }\n\n        CSV_INLINE void IBasicCSVParser::trim_utf8_bom() {\n            auto& data = this->data_ptr->data;\n\n            if (!this->unicode_bom_scan && data.size() >= 3) {\n                if (data[0] == '\\xEF' && data[1] == '\\xBB' && data[2] == '\\xBF') {\n                    this->data_pos += 3; // Remove BOM from input string\n                    this->_utf8_bom = true;\n                }\n\n                this->unicode_bom_scan = true;\n            }\n        }\n#ifdef _MSC_VER\n#pragma endregion\n#endif\n\n#ifdef _MSC_VER\n#pragma region Specializations\n#endif\n        CSV_INLINE void MmapParser::next(size_t bytes = ITERATION_CHUNK_SIZE) {\n            // Reset parser state\n            this->field_start = UNINITIALIZED_FIELD;\n            this->field_length = 0;\n            this->reset_data_ptr();\n\n            // Create memory map\n            size_t length = std::min(this->source_size - this->mmap_pos, bytes);\n            std::error_code error;\n            this->data_ptr->_data = std::make_shared<mio::basic_mmap_source<char>>(mio::make_mmap_source(this->_filename, this->mmap_pos, length, error));\n            this->mmap_pos += length;\n            if (error) throw error;\n\n            auto mmap_ptr = (mio::basic_mmap_source<char>*)(this->data_ptr->_data.get());\n\n            // Create string view\n            this->data_ptr->data = csv::string_view(mmap_ptr->data(), mmap_ptr->length());\n\n            // Parse\n            this->current_row = CSVRow(this->data_ptr);\n            size_t remainder = this->parse();            \n\n            if (this->mmap_pos == this->source_size || no_chunk()) {\n                this->_eof = true;\n                this->end_feed();\n            }\n\n            this->mmap_pos -= (length - remainder);\n        }\n#ifdef _MSC_VER\n#pragma endregion\n#endif\n    }\n}\n\n\nnamespace csv {\n    namespace internals {\n        CSV_INLINE std::vector<std::string> ColNames::get_col_names() const {\n            return this->col_names;\n        }\n\n        CSV_INLINE void ColNames::set_col_names(const std::vector<std::string>& cnames) {\n            this->col_names = cnames;\n\n            for (size_t i = 0; i < cnames.size(); i++) {\n                this->col_pos[cnames[i]] = i;\n            }\n        }\n\n        CSV_INLINE int ColNames::index_of(csv::string_view col_name) const {\n            auto pos = this->col_pos.find(col_name.data());\n            if (pos != this->col_pos.end())\n                return (int)pos->second;\n\n            return CSV_NOT_FOUND;\n        }\n\n        CSV_INLINE size_t ColNames::size() const noexcept {\n            return this->col_names.size();\n        }\n\n    }\n}\n/** @file\n *  Defines an object used to store CSV format settings\n */\n\n#include <algorithm>\n#include <set>\n\n\nnamespace csv {\n    CSV_INLINE CSVFormat& CSVFormat::delimiter(char delim) {\n        this->possible_delimiters = { delim };\n        this->assert_no_char_overlap();\n        return *this;\n    }\n\n    CSV_INLINE CSVFormat& CSVFormat::delimiter(const std::vector<char> & delim) {\n        this->possible_delimiters = delim;\n        this->assert_no_char_overlap();\n        return *this;\n    }\n\n    CSV_INLINE CSVFormat& CSVFormat::quote(char quote) {\n        this->no_quote = false;\n        this->quote_char = quote;\n        this->assert_no_char_overlap();\n        return *this;\n    }\n\n    CSV_INLINE CSVFormat& CSVFormat::trim(const std::vector<char> & chars) {\n        this->trim_chars = chars;\n        this->assert_no_char_overlap();\n        return *this;\n    }\n\n    CSV_INLINE CSVFormat& CSVFormat::column_names(const std::vector<std::string>& names) {\n        this->col_names = names;\n        this->header = -1;\n        return *this;\n    }\n\n    CSV_INLINE CSVFormat& CSVFormat::header_row(int row) {\n        if (row < 0) this->variable_column_policy = VariableColumnPolicy::KEEP;\n\n        this->header = row;\n        this->col_names = {};\n        return *this;\n    }\n\n    CSV_INLINE void CSVFormat::assert_no_char_overlap()\n    {\n        auto delims = std::set<char>(\n            this->possible_delimiters.begin(), this->possible_delimiters.end()),\n            trims = std::set<char>(\n                this->trim_chars.begin(), this->trim_chars.end());\n\n        // Stores intersection of possible delimiters and trim characters\n        std::vector<char> intersection = {};\n\n        // Find which characters overlap, if any\n        std::set_intersection(\n            delims.begin(), delims.end(),\n            trims.begin(), trims.end(),\n            std::back_inserter(intersection));\n\n        // Make sure quote character is not contained in possible delimiters\n        // or whitespace characters\n        if (delims.find(this->quote_char) != delims.end() ||\n            trims.find(this->quote_char) != trims.end()) {\n            intersection.push_back(this->quote_char);\n        }\n\n        if (!intersection.empty()) {\n            std::string err_msg = \"There should be no overlap between the quote character, \"\n                \"the set of possible delimiters \"\n                \"and the set of whitespace characters. Offending characters: \";\n\n            // Create a pretty error message with the list of overlapping\n            // characters\n            for (size_t i = 0; i < intersection.size(); i++) {\n                err_msg += \"'\";\n                err_msg += intersection[i];\n                err_msg += \"'\";\n\n                if (i + 1 < intersection.size())\n                    err_msg += \", \";\n            }\n\n            throw std::runtime_error(err_msg + '.');\n        }\n    }\n}\n/** @file\n *  @brief Defines functionality needed for basic CSV parsing\n */\n\n\nnamespace csv {\n    namespace internals {\n        CSV_INLINE std::string format_row(const std::vector<std::string>& row, csv::string_view delim) {\n            /** Print a CSV row */\n            std::stringstream ret;\n            for (size_t i = 0; i < row.size(); i++) {\n                ret << row[i];\n                if (i + 1 < row.size()) ret << delim;\n                else ret << '\\n';\n            }\n            ret.flush();\n\n            return ret.str();\n        }\n\n        /** Return a CSV's column names\n         *\n         *  @param[in] filename  Path to CSV file\n         *  @param[in] format    Format of the CSV file\n         *\n         */\n        CSV_INLINE std::vector<std::string> _get_col_names(csv::string_view head, CSVFormat format) {\n            // Parse the CSV\n            auto trim_chars = format.get_trim_chars();\n            std::stringstream source(head.data());\n            RowCollection rows;\n\n            StreamParser<std::stringstream> parser(source, format);\n            parser.set_output(rows);\n            parser.next();\n\n            return CSVRow(std::move(rows[format.get_header()]));\n        }\n\n        CSV_INLINE GuessScore calculate_score(csv::string_view head, CSVFormat format) {\n            // Frequency counter of row length\n            std::unordered_map<size_t, size_t> row_tally = { { 0, 0 } };\n\n            // Map row lengths to row num where they first occurred\n            std::unordered_map<size_t, size_t> row_when = { { 0, 0 } };\n\n            // Parse the CSV\n            std::stringstream source(head.data());\n            RowCollection rows;\n\n            StreamParser<std::stringstream> parser(source, format);\n            parser.set_output(rows);\n            parser.next();\n\n            for (size_t i = 0; i < rows.size(); i++) {\n                auto& row = rows[i];\n\n                // Ignore zero-length rows\n                if (row.size() > 0) {\n                    if (row_tally.find(row.size()) != row_tally.end()) {\n                        row_tally[row.size()]++;\n                    }\n                    else {\n                        row_tally[row.size()] = 1;\n                        row_when[row.size()] = i;\n                    }\n                }\n            }\n\n            double final_score = 0;\n            size_t header_row = 0;\n\n            // Final score is equal to the largest\n            // row size times rows of that size\n            for (auto& pair : row_tally) {\n                auto row_size = pair.first;\n                auto row_count = pair.second;\n                double score = (double)(row_size * row_count);\n                if (score > final_score) {\n                    final_score = score;\n                    header_row = row_when[row_size];\n                }\n            }\n\n            return {\n                final_score,\n                header_row\n            };\n        }\n\n        /** Guess the delimiter used by a delimiter-separated values file */\n        CSV_INLINE CSVGuessResult _guess_format(csv::string_view head, const std::vector<char>& delims) {\n            /** For each delimiter, find out which row length was most common.\n             *  The delimiter with the longest mode row length wins.\n             *  Then, the line number of the header row is the first row with\n             *  the mode row length.\n             */\n\n            CSVFormat format;\n            size_t max_score = 0,\n                header = 0;\n            char current_delim = delims[0];\n\n            for (char cand_delim : delims) {\n                auto result = calculate_score(head, format.delimiter(cand_delim));\n\n                if ((size_t)result.score > max_score) {\n                    max_score = (size_t)result.score;\n                    current_delim = cand_delim;\n                    header = result.header;\n                }\n            }\n\n            return { current_delim, (int)header };\n        }\n    }\n\n    /** Return a CSV's column names\n     *\n     *  @param[in] filename  Path to CSV file\n     *  @param[in] format    Format of the CSV file\n     *\n     */\n    CSV_INLINE std::vector<std::string> get_col_names(csv::string_view filename, CSVFormat format) {\n        auto head = internals::get_csv_head(filename);\n\n        /** Guess delimiter and header row */\n        if (format.guess_delim()) {\n            auto guess_result = guess_format(filename, format.get_possible_delims());\n            format.delimiter(guess_result.delim).header_row(guess_result.header_row);\n        }\n\n        return internals::_get_col_names(head, format);\n    }\n\n    /** Guess the delimiter used by a delimiter-separated values file */\n    CSV_INLINE CSVGuessResult guess_format(csv::string_view filename, const std::vector<char>& delims) {\n        auto head = internals::get_csv_head(filename);\n        return internals::_guess_format(head, delims);\n    }\n\n    /** Reads an arbitrarily large CSV file using memory-mapped IO.\n     *\n     *  **Details:** Reads the first block of a CSV file synchronously to get information\n     *               such as column names and delimiting character.\n     *\n     *  @param[in] filename  Path to CSV file\n     *  @param[in] format    Format of the CSV file\n     *\n     *  \\snippet tests/test_read_csv.cpp CSVField Example\n     *\n     */\n\tCSV_INLINE CSVReader::CSVReader(csv::string_view filename, CSVFormat format) : _format(format) {\n        auto head = internals::get_csv_head(filename);\n        using Parser = internals::MmapParser;\n\n        /** Guess delimiter and header row */\n        if (format.guess_delim()) {\n            auto guess_result = internals::_guess_format(head, format.possible_delimiters);\n            format.delimiter(guess_result.delim);\n            format.header = guess_result.header_row;\n            this->_format = format;\n        }\n\n        if (!format.col_names.empty())\n            this->set_col_names(format.col_names);\n\n        this->parser = std::unique_ptr<Parser>(new Parser(filename, format, this->col_names)); // For C++11\n        this->initial_read();\n    }\n\n    /** Return the format of the original raw CSV */\n    CSV_INLINE CSVFormat CSVReader::get_format() const {\n        CSVFormat new_format = this->_format;\n\n        // Since users are normally not allowed to set\n        // column names and header row simulatenously,\n        // we will set the backing variables directly here\n        new_format.col_names = this->col_names->get_col_names();\n        new_format.header = this->_format.header;\n\n        return new_format;\n    }\n\n    /** Return the CSV's column names as a vector of strings. */\n    CSV_INLINE std::vector<std::string> CSVReader::get_col_names() const {\n        if (this->col_names) {\n            return this->col_names->get_col_names();\n        }\n\n        return std::vector<std::string>();\n    }\n\n    /** Return the index of the column name if found or\n     *         csv::CSV_NOT_FOUND otherwise.\n     */\n    CSV_INLINE int CSVReader::index_of(csv::string_view col_name) const {\n        auto _col_names = this->get_col_names();\n        for (size_t i = 0; i < _col_names.size(); i++)\n            if (_col_names[i] == col_name) return (int)i;\n\n        return CSV_NOT_FOUND;\n    }\n\n    CSV_INLINE void CSVReader::trim_header() {\n        if (!this->header_trimmed) {\n            for (int i = 0; i <= this->_format.header && !this->records->empty(); i++) {\n                if (i == this->_format.header && this->col_names->empty()) {\n                    this->set_col_names(this->records->pop_front());\n                }\n                else {\n                    this->records->pop_front();\n                }\n            }\n\n            this->header_trimmed = true;\n        }\n    }\n\n    /**\n     *  @param[in] names Column names\n     */\n    CSV_INLINE void CSVReader::set_col_names(const std::vector<std::string>& names)\n    {\n        this->col_names->set_col_names(names);\n        this->n_cols = names.size();\n    }\n\n    /**\n     * Read a chunk of CSV data.\n     *\n     * @note This method is meant to be run on its own thread. Only one `read_csv()` thread\n     *       should be active at a time.\n     *\n     * @param[in] bytes Number of bytes to read.\n     *\n     * @see CSVReader::read_csv_worker\n     * @see CSVReader::read_row()\n     */\n    CSV_INLINE bool CSVReader::read_csv(size_t bytes) {\n        // Tell read_row() to listen for CSV rows\n        this->records->notify_all();\n\n        this->parser->set_output(*this->records);\n        this->parser->next(bytes);\n\n        if (!this->header_trimmed) {\n            this->trim_header();\n        }\n\n        // Tell read_row() to stop waiting\n        this->records->kill_all();\n\n        return true;\n    }\n\n    /**\n     * Retrieve rows as CSVRow objects, returning true if more rows are available.\n     *\n     * @par Performance Notes\n     *  - Reads chunks of data that are csv::internals::ITERATION_CHUNK_SIZE bytes large at a time\n     *  - For performance details, read the documentation for CSVRow and CSVField.\n     *\n     * @param[out] row The variable where the parsed row will be stored\n     * @see CSVRow, CSVField\n     *\n     * **Example:**\n     * \\snippet tests/test_read_csv.cpp CSVField Example\n     *\n     */\n    CSV_INLINE bool CSVReader::read_row(CSVRow &row) {\n        while (true) {\n            if (this->records->empty()) {\n                if (this->records->is_waitable())\n                    // Reading thread is currently active => wait for it to populate records\n                    this->records->wait();\n                else if (this->parser->eof())\n                    // End of file and no more records\n                    return false;\n                else {\n                    // Reading thread is not active => start another one\n                    if (this->read_csv_worker.joinable())\n                        this->read_csv_worker.join();\n\n                    this->read_csv_worker = std::thread(&CSVReader::read_csv, this, internals::ITERATION_CHUNK_SIZE);\n                }\n            }\n            else if (this->records->front().size() != this->n_cols &&\n                this->_format.variable_column_policy != VariableColumnPolicy::KEEP) {\n                auto errored_row = this->records->pop_front();\n\n                if (this->_format.variable_column_policy == VariableColumnPolicy::THROW) {\n                    if (errored_row.size() < this->n_cols)\n                        throw std::runtime_error(\"Line too short \" + internals::format_row(errored_row));\n\n                    throw std::runtime_error(\"Line too long \" + internals::format_row(errored_row));\n                }\n            }\n            else {\n                row = this->records->pop_front();\n                this->_n_rows++;\n                return true;\n            }\n        }\n\n        return false;\n    }\n}\n\n/** @file\n *  Defines an input iterator for csv::CSVReader\n */\n\n\nnamespace csv {\n    /** Return an iterator to the first row in the reader */\n    CSV_INLINE CSVReader::iterator CSVReader::begin() {\n        if (this->records->empty()) {\n            this->read_csv_worker = std::thread(&CSVReader::read_csv, this, internals::ITERATION_CHUNK_SIZE);\n            this->read_csv_worker.join();\n\n            // Still empty => return end iterator\n            if (this->records->empty()) return this->end();\n        }\n\n        CSVReader::iterator ret(this, this->records->pop_front());\n        return ret;\n    }\n\n    /** A placeholder for the imaginary past the end row in a CSV.\n     *  Attempting to deference this will lead to bad things.\n     */\n    CSV_INLINE HEDLEY_CONST CSVReader::iterator CSVReader::end() const noexcept {\n        return CSVReader::iterator();\n    }\n\n    /////////////////////////\n    // CSVReader::iterator //\n    /////////////////////////\n\n    CSV_INLINE CSVReader::iterator::iterator(CSVReader* _daddy, CSVRow&& _row) :\n        daddy(_daddy) {\n        row = std::move(_row);\n    }\n\n    /** Advance the iterator by one row. If this CSVReader has an\n     *  associated file, then the iterator will lazily pull more data from\n     *  that file until the end of file is reached.\n     *\n     *  @note This iterator does **not** block the thread responsible for parsing CSV.\n     *\n     */\n    CSV_INLINE CSVReader::iterator& CSVReader::iterator::operator++() {\n        if (!daddy->read_row(this->row)) {\n            this->daddy = nullptr; // this == end()\n        }\n\n        return *this;\n    }\n\n    /** Post-increment iterator */\n    CSV_INLINE CSVReader::iterator CSVReader::iterator::operator++(int) {\n        auto temp = *this;\n        if (!daddy->read_row(this->row)) {\n            this->daddy = nullptr; // this == end()\n        }\n\n        return temp;\n    }\n}\n\n/** @file\n *  Defines the data type used for storing information about a CSV row\n */\n\n#include <cassert>\n#include <functional>\n\nnamespace csv {\n    namespace internals {\n        CSV_INLINE RawCSVField& CSVFieldList::operator[](size_t n) const {\n            const size_t page_no = n / _single_buffer_capacity;\n            const size_t buffer_idx = (page_no < 1) ? n : n % _single_buffer_capacity;\n            return this->buffers[page_no][buffer_idx];\n        }\n\n        CSV_INLINE void CSVFieldList::allocate() {\n            RawCSVField * buffer = new RawCSVField[_single_buffer_capacity];\n            buffers.push_back(buffer);\n            _current_buffer_size = 0;\n            _back = &(buffers.back()[0]);\n        }\n    }\n\n    /** Return a CSVField object corrsponding to the nth value in the row.\n     *\n     *  @note This method performs bounds checking, and will throw an\n     *        `std::runtime_error` if n is invalid.\n     *\n     *  @complexity\n     *  Constant, by calling csv::CSVRow::get_csv::string_view()\n     *\n     */\n    CSV_INLINE CSVField CSVRow::operator[](size_t n) const {\n        return CSVField(this->get_field(n));\n    }\n\n    /** Retrieve a value by its associated column name. If the column\n     *  specified can't be round, a runtime error is thrown.\n     *\n     *  @complexity\n     *  Constant. This calls the other CSVRow::operator[]() after\n     *  converting column names into indices using a hash table.\n     *\n     *  @param[in] col_name The column to look for\n     */\n    CSV_INLINE CSVField CSVRow::operator[](const std::string& col_name) const {\n        auto & col_names = this->data->col_names;\n        auto col_pos = col_names->index_of(col_name);\n        if (col_pos > -1) {\n            return this->operator[](col_pos);\n        }\n\n        throw std::runtime_error(\"Can't find a column named \" + col_name);\n    }\n\n    CSV_INLINE CSVRow::operator std::vector<std::string>() const {\n        std::vector<std::string> ret;\n        for (size_t i = 0; i < size(); i++)\n            ret.push_back(std::string(this->get_field(i)));\n\n        return ret;\n    }\n\n    CSV_INLINE csv::string_view CSVRow::get_field(size_t index) const\n    {\n        using internals::ParseFlags;\n\n        if (index >= this->size())\n            throw std::runtime_error(\"Index out of bounds.\");\n\n        const size_t field_index = this->fields_start + index;\n        auto& field = this->data->fields[field_index];\n        auto field_str = csv::string_view(this->data->data).substr(this->data_start + field.start);\n\n        if (field.has_double_quote) {\n            auto& value = this->data->double_quote_fields[field_index];\n            if (value.empty()) {\n                bool prev_ch_quote = false;\n                for (size_t i = 0; i < field.length; i++) {\n                    if (this->data->parse_flags[field_str[i] + 128] == ParseFlags::QUOTE) {\n                        if (prev_ch_quote) {\n                            prev_ch_quote = false;\n                            continue;\n                        }\n                        else {\n                            prev_ch_quote = true;\n                        }\n                    }\n\n                    value += field_str[i];\n                }\n            }\n\n            return csv::string_view(value);\n        }\n\n        return field_str.substr(0, field.length);\n    }\n\n    CSV_INLINE bool CSVField::try_parse_hex(int& parsedValue) {\n        size_t start = 0, end = 0;\n\n        // Trim out whitespace chars\n        for (; start < this->sv.size() && this->sv[start] == ' '; start++);\n        for (end = start; end < this->sv.size() && this->sv[end] != ' '; end++);\n        \n        unsigned long long int value = 0;\n\n        size_t digits = (end - start);\n        size_t base16_exponent = digits - 1;\n\n        if (digits == 0) return false;\n\n        for (const auto& ch : this->sv.substr(start, digits)) {\n            int digit = 0;\n\n            switch (ch) {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n                digit = static_cast<int>(ch - '0');\n                break;\n            case 'a':\n            case 'A':\n                digit = 10;\n                break;\n            case 'b':\n            case 'B':\n                digit = 11;\n                break;\n            case 'c':\n            case 'C':\n                digit = 12;\n                break;\n            case 'd':\n            case 'D':\n                digit = 13;\n                break;\n            case 'e':\n            case 'E':\n                digit = 14;\n                break;\n            case 'f':\n            case 'F':\n                digit = 15;\n                break;\n            default:\n                return false;\n            }\n\n            value += digit * pow(16, base16_exponent);\n            base16_exponent--;\n        }\n\n        parsedValue = value;\n        return true;\n    }\n\n#ifdef _MSC_VER\n#pragma region CSVRow Iterator\n#endif\n    /** Return an iterator pointing to the first field. */\n    CSV_INLINE CSVRow::iterator CSVRow::begin() const {\n        return CSVRow::iterator(this, 0);\n    }\n\n    /** Return an iterator pointing to just after the end of the CSVRow.\n     *\n     *  @warning Attempting to dereference the end iterator results\n     *           in dereferencing a null pointer.\n     */\n    CSV_INLINE CSVRow::iterator CSVRow::end() const noexcept {\n        return CSVRow::iterator(this, (int)this->size());\n    }\n\n    CSV_INLINE CSVRow::reverse_iterator CSVRow::rbegin() const noexcept {\n        return std::reverse_iterator<CSVRow::iterator>(this->end());\n    }\n\n    CSV_INLINE CSVRow::reverse_iterator CSVRow::rend() const {\n        return std::reverse_iterator<CSVRow::iterator>(this->begin());\n    }\n\n    CSV_INLINE HEDLEY_NON_NULL(2)\n    CSVRow::iterator::iterator(const CSVRow* _reader, int _i)\n        : daddy(_reader), i(_i) {\n        if (_i < (int)this->daddy->size())\n            this->field = std::make_shared<CSVField>(\n                this->daddy->operator[](_i));\n        else\n            this->field = nullptr;\n    }\n\n    CSV_INLINE CSVRow::iterator::reference CSVRow::iterator::operator*() const {\n        return *(this->field.get());\n    }\n\n    CSV_INLINE CSVRow::iterator::pointer CSVRow::iterator::operator->() const {\n        // Using CSVField * as pointer type causes segfaults in MSVC debug builds\n        #ifdef _MSC_BUILD\n        return this->field;\n        #else\n        return this->field.get();\n        #endif\n    }\n\n    CSV_INLINE CSVRow::iterator& CSVRow::iterator::operator++() {\n        // Pre-increment operator\n        this->i++;\n        if (this->i < (int)this->daddy->size())\n            this->field = std::make_shared<CSVField>(\n                this->daddy->operator[](i));\n        else // Reached the end of row\n            this->field = nullptr;\n        return *this;\n    }\n\n    CSV_INLINE CSVRow::iterator CSVRow::iterator::operator++(int) {\n        // Post-increment operator\n        auto temp = *this;\n        this->operator++();\n        return temp;\n    }\n\n    CSV_INLINE CSVRow::iterator& CSVRow::iterator::operator--() {\n        // Pre-decrement operator\n        this->i--;\n        this->field = std::make_shared<CSVField>(\n            this->daddy->operator[](this->i));\n        return *this;\n    }\n\n    CSV_INLINE CSVRow::iterator CSVRow::iterator::operator--(int) {\n        // Post-decrement operator\n        auto temp = *this;\n        this->operator--();\n        return temp;\n    }\n    \n    CSV_INLINE CSVRow::iterator CSVRow::iterator::operator+(difference_type n) const {\n        // Allows for iterator arithmetic\n        return CSVRow::iterator(this->daddy, i + (int)n);\n    }\n\n    CSV_INLINE CSVRow::iterator CSVRow::iterator::operator-(difference_type n) const {\n        // Allows for iterator arithmetic\n        return CSVRow::iterator::operator+(-n);\n    }\n#ifdef _MSC_VER\n#pragma endregion CSVRow Iterator\n#endif\n}\n\n/** @file\n *  Implements JSON serialization abilities\n */\n\n\nnamespace csv {\n    /*\n    The implementations for json_extra_space() and json_escape_string()\n    were modified from source code for JSON for Modern C++.\n\n    The respective license is below:\n\n    The code is licensed under the [MIT\n    License](http://opensource.org/licenses/MIT):\n    \n    Copyright &copy; 2013-2015 Niels Lohmann.\n    \n    Permission is hereby granted, free of charge, to any person\n    obtaining a copy of this software and associated documentation files\n    (the \"Software\"), to deal in the Software without restriction,\n    including without limitation the rights to use, copy, modify, merge,\n    publish, distribute, sublicense, and/or sell copies of the Software,\n    and to permit persons to whom the Software is furnished to do so,\n    subject to the following conditions:\n    \n    The above copyright notice and this permission notice shall be\n    included in all copies or substantial portions of the Software.\n    \n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n    BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n    SOFTWARE.\n    */\n\n    namespace internals {\n        /*!\n         @brief calculates the extra space to escape a JSON string\n\n         @param[in] s  the string to escape\n         @return the number of characters required to escape string @a s\n\n         @complexity Linear in the length of string @a s.\n        */\n        static std::size_t json_extra_space(csv::string_view& s) noexcept\n        {\n            std::size_t result = 0;\n\n\n            for (const auto& c : s)\n            {\n                switch (c)\n                {\n                case '\"':\n                case '\\\\':\n                case '\\b':\n                case '\\f':\n                case '\\n':\n                case '\\r':\n                case '\\t':\n                {\n                    // from c (1 byte) to \\x (2 bytes)\n                    result += 1;\n                    break;\n                }\n\n\n                default:\n                {\n                    if (c >= 0x00 && c <= 0x1f)\n                    {\n                        // from c (1 byte) to \\uxxxx (6 bytes)\n                        result += 5;\n                    }\n                    break;\n                }\n                }\n            }\n\n\n            return result;\n        }\n\n        CSV_INLINE std::string json_escape_string(csv::string_view s) noexcept\n        {\n            const auto space = json_extra_space(s);\n            if (space == 0)\n            {\n                return std::string(s);\n            }\n\n            // create a result string of necessary size\n            std::string result(s.size() + space, '\\\\');\n            std::size_t pos = 0;\n\n            for (const auto& c : s)\n            {\n                switch (c)\n                {\n                // quotation mark (0x22)\n                case '\"':\n                {\n                    result[pos + 1] = '\"';\n                    pos += 2;\n                    break;\n                }\n\n\n                // reverse solidus (0x5c)\n                case '\\\\':\n                {\n                    // nothing to change\n                    pos += 2;\n                    break;\n                }\n\n\n                // backspace (0x08)\n                case '\\b':\n                {\n                    result[pos + 1] = 'b';\n                    pos += 2;\n                    break;\n                }\n\n\n                // formfeed (0x0c)\n                case '\\f':\n                {\n                    result[pos + 1] = 'f';\n                    pos += 2;\n                    break;\n                }\n\n\n                // newline (0x0a)\n                case '\\n':\n                {\n                    result[pos + 1] = 'n';\n                    pos += 2;\n                    break;\n                }\n\n\n                // carriage return (0x0d)\n                case '\\r':\n                {\n                    result[pos + 1] = 'r';\n                    pos += 2;\n                    break;\n                }\n\n\n                // horizontal tab (0x09)\n                case '\\t':\n                {\n                    result[pos + 1] = 't';\n                    pos += 2;\n                    break;\n                }\n\n\n                default:\n                {\n                    if (c >= 0x00 && c <= 0x1f)\n                    {\n                        // print character c as \\uxxxx\n                        sprintf(&result[pos + 1], \"u%04x\", int(c));\n                        pos += 6;\n                        // overwrite trailing null character\n                        result[pos] = '\\\\';\n                    }\n                    else\n                    {\n                        // all other characters are added as-is\n                        result[pos++] = c;\n                    }\n                    break;\n                }\n                }\n            }\n\n            return result;\n        }\n    }\n\n    /** Convert a CSV row to a JSON object, i.e.\n     *  `{\"col1\":\"value1\",\"col2\":\"value2\"}`\n     *\n     *  @note All strings are properly escaped. Numeric values are not quoted.\n     *  @param[in] subset A subset of columns to contain in the JSON.\n     *                    Leave empty for original columns.\n     */\n    CSV_INLINE std::string CSVRow::to_json(const std::vector<std::string>& subset) const {\n        std::vector<std::string> col_names = subset;\n        if (subset.empty()) {\n            col_names = this->data ? this->get_col_names() : std::vector<std::string>({});\n        }\n\n        const size_t _n_cols = col_names.size();\n        std::string ret = \"{\";\n        \n        for (size_t i = 0; i < _n_cols; i++) {\n            auto& col = col_names[i];\n            auto field = this->operator[](col);\n\n            // TODO: Possible performance enhancements by caching escaped column names\n            ret += '\"' + internals::json_escape_string(col) + \"\\\":\";\n\n            // Add quotes around strings but not numbers\n            if (field.is_num())\n                 ret += internals::json_escape_string(field.get<csv::string_view>());\n            else\n                ret += '\"' + internals::json_escape_string(field.get<csv::string_view>()) + '\"';\n\n            // Do not add comma after last string\n            if (i + 1 < _n_cols)\n                ret += ',';\n        }\n\n        ret += '}';\n        return ret;\n    }\n\n    /** Convert a CSV row to a JSON array, i.e.\n     *  `[\"value1\",\"value2\",...]`\n     *\n     *  @note All strings are properly escaped. Numeric values are not quoted.\n     *  @param[in] subset A subset of columns to contain in the JSON.\n     *                    Leave empty for all columns.\n     */\n    CSV_INLINE std::string CSVRow::to_json_array(const std::vector<std::string>& subset) const {\n        std::vector<std::string> col_names = subset;\n        if (subset.empty())\n            col_names = this->data ? this->get_col_names() : std::vector<std::string>({});\n\n        const size_t _n_cols = col_names.size();\n        std::string ret = \"[\";\n\n        for (size_t i = 0; i < _n_cols; i++) {\n            auto field = this->operator[](col_names[i]);\n\n            // Add quotes around strings but not numbers\n            if (field.is_num())\n                ret += internals::json_escape_string(field.get<csv::string_view>());\n            else\n                ret += '\"' + internals::json_escape_string(field.get<csv::string_view>()) + '\"';\n\n            // Do not add comma after last string\n            if (i + 1 < _n_cols)\n                ret += ',';\n        }\n\n        ret += ']';\n        return ret;\n    }\n}\n/** @file\n *  Calculates statistics from CSV files\n */\n\n#include <string>\n\nnamespace csv {\n    /** Calculate statistics for an arbitrarily large file. When this constructor\n     *  is called, CSVStat will process the entire file iteratively. Once finished,\n     *  methods like get_mean(), get_counts(), etc... can be used to retrieve statistics.\n     */\n    CSV_INLINE CSVStat::CSVStat(csv::string_view filename, CSVFormat format) :\n        reader(filename, format) {\n        this->calc();\n    }\n\n    /** Calculate statistics for a CSV stored in a std::stringstream */\n    CSV_INLINE CSVStat::CSVStat(std::stringstream& stream, CSVFormat format) :\n        reader(stream, format) {\n        this->calc();\n    }\n\n    /** Return current means */\n    CSV_INLINE std::vector<long double> CSVStat::get_mean() const {\n        std::vector<long double> ret;        \n        for (size_t i = 0; i < this->get_col_names().size(); i++) {\n            ret.push_back(this->rolling_means[i]);\n        }\n        return ret;\n    }\n\n    /** Return current variances */\n    CSV_INLINE std::vector<long double> CSVStat::get_variance() const {\n        std::vector<long double> ret;        \n        for (size_t i = 0; i < this->get_col_names().size(); i++) {\n            ret.push_back(this->rolling_vars[i]/(this->n[i] - 1));\n        }\n        return ret;\n    }\n\n    /** Return current mins */\n    CSV_INLINE std::vector<long double> CSVStat::get_mins() const {\n        std::vector<long double> ret;        \n        for (size_t i = 0; i < this->get_col_names().size(); i++) {\n            ret.push_back(this->mins[i]);\n        }\n        return ret;\n    }\n\n    /** Return current maxes */\n    CSV_INLINE std::vector<long double> CSVStat::get_maxes() const {\n        std::vector<long double> ret;        \n        for (size_t i = 0; i < this->get_col_names().size(); i++) {\n            ret.push_back(this->maxes[i]);\n        }\n        return ret;\n    }\n\n    /** Get counts for each column */\n    CSV_INLINE std::vector<CSVStat::FreqCount> CSVStat::get_counts() const {\n        std::vector<FreqCount> ret;\n        for (size_t i = 0; i < this->get_col_names().size(); i++) {\n            ret.push_back(this->counts[i]);\n        }\n        return ret;\n    }\n\n    /** Get data type counts for each column */\n    CSV_INLINE std::vector<CSVStat::TypeCount> CSVStat::get_dtypes() const {\n        std::vector<TypeCount> ret;        \n        for (size_t i = 0; i < this->get_col_names().size(); i++) {\n            ret.push_back(this->dtypes[i]);\n        }\n        return ret;\n    }\n\n    CSV_INLINE void CSVStat::calc_chunk() {\n        /** Only create stats counters the first time **/\n        if (dtypes.empty()) {\n            /** Go through all records and calculate specified statistics */\n            for (size_t i = 0; i < this->get_col_names().size(); i++) {\n                dtypes.push_back({});\n                counts.push_back({});\n                rolling_means.push_back(0);\n                rolling_vars.push_back(0);\n                mins.push_back(NAN);\n                maxes.push_back(NAN);\n                n.push_back(0);\n            }\n        }\n\n        // Start threads\n        std::vector<std::thread> pool;\n        for (size_t i = 0; i < this->get_col_names().size(); i++)\n            pool.push_back(std::thread(&CSVStat::calc_worker, this, i));\n\n        // Block until done\n        for (auto& th : pool)\n            th.join();\n\n        this->records.clear();\n    }\n\n    CSV_INLINE void CSVStat::calc() {\n        constexpr size_t CALC_CHUNK_SIZE = 5000;\n\n        for (auto& row : reader) {\n            this->records.push_back(std::move(row));\n\n            /** Chunk rows */\n            if (this->records.size() == CALC_CHUNK_SIZE) {\n                calc_chunk();\n            }\n        }\n\n        if (!this->records.empty()) {\n          calc_chunk();\n        }\n    }\n\n    CSV_INLINE void CSVStat::calc_worker(const size_t &i) {\n        /** Worker thread for CSVStat::calc() which calculates statistics for one column.\n         * \n         *  @param[in] i Column index\n         */\n\n        auto current_record = this->records.begin();\n\n        for (size_t processed = 0; current_record != this->records.end(); processed++) {\n            if (current_record->size() == this->get_col_names().size()) {\n                auto current_field = (*current_record)[i];\n\n                // Optimization: Don't count() if there's too many distinct values in the first 1000 rows\n                if (processed < 1000 || this->counts[i].size() <= 500)\n                    this->count(current_field, i);\n\n                this->dtype(current_field, i);\n\n                // Numeric Stuff\n                if (current_field.is_num()) {\n                    long double x_n = current_field.get<long double>();\n\n                    // This actually calculates mean AND variance\n                    this->variance(x_n, i);\n                    this->min_max(x_n, i);\n                }\n            }\n            else if (this->reader.get_format().get_variable_column_policy() == VariableColumnPolicy::THROW) {\n                throw std::runtime_error(\"Line has different length than the others \" + internals::format_row(*current_record));\n            }\n\n            ++current_record;\n        }\n    }\n\n    CSV_INLINE void CSVStat::dtype(CSVField& data, const size_t &i) {\n        /** Given a record update the type counter\n         *  @param[in]  record Data observation\n         *  @param[out] i      The column index that should be updated\n         */\n        \n        auto type = data.type();\n        if (this->dtypes[i].find(type) !=\n            this->dtypes[i].end()) {\n            // Increment count\n            this->dtypes[i][type]++;\n        } else {\n            // Initialize count\n            this->dtypes[i].insert(std::make_pair(type, 1));\n        }\n    }\n\n    CSV_INLINE void CSVStat::count(CSVField& data, const size_t &i) {\n        /** Given a record update the frequency counter\n         *  @param[in]  record Data observation\n         *  @param[out] i      The column index that should be updated\n         */\n\n        auto item = data.get<std::string>();\n\n        if (this->counts[i].find(item) !=\n            this->counts[i].end()) {\n            // Increment count\n            this->counts[i][item]++;\n        } else {\n            // Initialize count\n            this->counts[i].insert(std::make_pair(item, 1));\n        }\n    }\n\n    CSV_INLINE void CSVStat::min_max(const long double &x_n, const size_t &i) {\n        /** Update current minimum and maximum\n         *  @param[in]  x_n Data observation\n         *  @param[out] i   The column index that should be updated\n         */\n        if (std::isnan(this->mins[i]))\n            this->mins[i] = x_n;\n        if (std::isnan(this->maxes[i]))\n            this->maxes[i] = x_n;\n        \n        if (x_n < this->mins[i])\n            this->mins[i] = x_n;\n        else if (x_n > this->maxes[i])\n            this->maxes[i] = x_n;\n    }\n\n    CSV_INLINE void CSVStat::variance(const long double &x_n, const size_t &i) {\n        /** Given a record update rolling mean and variance for all columns\n         *  using Welford's Algorithm\n         *  @param[in]  x_n Data observation\n         *  @param[out] i   The column index that should be updated\n         */\n        long double& current_rolling_mean = this->rolling_means[i];\n        long double& current_rolling_var = this->rolling_vars[i];\n        long double& current_n = this->n[i];\n        long double delta;\n        long double delta2;\n\n        current_n++;\n        \n        if (current_n == 1) {\n            current_rolling_mean = x_n;\n        } else {\n            delta = x_n - current_rolling_mean;\n            current_rolling_mean += delta/current_n;\n            delta2 = x_n - current_rolling_mean;\n            current_rolling_var += delta*delta2;\n        }\n    }\n\n    /** Useful for uploading CSV files to SQL databases.\n     *\n     *  Return a data type for each column such that every value in a column can be\n     *  converted to the corresponding data type without data loss.\n     *  @param[in]  filename The CSV file\n     *\n     *  \\return A mapping of column names to csv::DataType enums\n     */\n    CSV_INLINE std::unordered_map<std::string, DataType> csv_data_types(const std::string& filename) {\n        CSVStat stat(filename);\n        std::unordered_map<std::string, DataType> csv_dtypes;\n\n        auto col_names = stat.get_col_names();\n        auto temp = stat.get_dtypes();\n\n        for (size_t i = 0; i < stat.get_col_names().size(); i++) {\n            auto& col = temp[i];\n            auto& col_name = col_names[i];\n\n            if (col[DataType::CSV_STRING])\n                csv_dtypes[col_name] = DataType::CSV_STRING;\n            else if (col[DataType::CSV_INT64])\n                csv_dtypes[col_name] = DataType::CSV_INT64;\n            else if (col[DataType::CSV_INT32])\n                csv_dtypes[col_name] = DataType::CSV_INT32;\n            else if (col[DataType::CSV_INT16])\n                csv_dtypes[col_name] = DataType::CSV_INT16;\n            else if (col[DataType::CSV_INT8])\n                csv_dtypes[col_name] = DataType::CSV_INT8;\n            else\n                csv_dtypes[col_name] = DataType::CSV_DOUBLE;\n        }\n\n        return csv_dtypes;\n    }\n}\n#include <sstream>\n#include <vector>\n\n\nnamespace csv {\n    /** Shorthand function for parsing an in-memory CSV string\n     *\n     *  @return A collection of CSVRow objects\n     *\n     *  @par Example\n     *  @snippet tests/test_read_csv.cpp Parse Example\n     */\n    CSV_INLINE CSVReader parse(csv::string_view in, CSVFormat format) {\n        std::stringstream stream(in.data());\n        return CSVReader(stream, format);\n    }\n\n    /** Parses a CSV string with no headers\n     *\n     *  @return A collection of CSVRow objects\n     */\n    CSV_INLINE CSVReader parse_no_header(csv::string_view in) {\n        CSVFormat format;\n        format.header_row(-1);\n\n        return parse(in, format);\n    }\n\n    /** Parse a RFC 4180 CSV string, returning a collection\n     *  of CSVRow objects\n     *\n     *  @par Example\n     *  @snippet tests/test_read_csv.cpp Escaped Comma\n     *\n     */\n    CSV_INLINE CSVReader operator \"\"_csv(const char* in, size_t n) {\n        return parse(csv::string_view(in, n));\n    }\n\n    /** A shorthand for csv::parse_no_header() */\n    CSV_INLINE CSVReader operator \"\"_csv_no_header(const char* in, size_t n) {\n        return parse_no_header(csv::string_view(in, n));\n    }\n\n    /**\n     *  Find the position of a column in a CSV file or CSV_NOT_FOUND otherwise\n     *\n     *  @param[in] filename  Path to CSV file\n     *  @param[in] col_name  Column whose position we should resolve\n     *  @param[in] format    Format of the CSV file\n     */\n    CSV_INLINE int get_col_pos(\n        csv::string_view filename,\n        csv::string_view col_name,\n        const CSVFormat& format) {\n        CSVReader reader(filename, format);\n        return reader.index_of(col_name);\n    }\n\n    /** Get basic information about a CSV file\n     *  @include programs/csv_info.cpp\n     */\n    CSV_INLINE CSVFileInfo get_file_info(const std::string& filename) {\n        CSVReader reader(filename);\n        CSVFormat format = reader.get_format();\n        for (auto it = reader.begin(); it != reader.end(); ++it);\n\n        CSVFileInfo info = {\n            filename,\n            reader.get_col_names(),\n            format.get_delim(),\n            reader.n_rows(),\n            reader.get_col_names().size()\n        };\n\n        return info;\n    }\n}\n\n\n#endif\n"
  },
  {
    "path": "src/cli/lib/DRAMPower/cli/run.cpp",
    "content": "#include \"run.hpp\"\n\n#include <memory>\n#include <vector>\n#include <fstream>\n#include <exception>\n#include <string>\n\n#include <spdlog/spdlog.h>\n#include <spdlog/fmt/ostr.h>\n\n#include <DRAMPower/Types.h>\n\n#include <DRAMPower/dram/dram_base.h>\n\n#include <DRAMPower/data/energy.h>\n\n#include <DRAMPower/util/cli_architecture_config.h>\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n#include <DRAMPower/memspec/MemSpecDDR4.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR4.h>\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n#include <DRAMPower/memspec/MemSpecDDR5.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n#include <DRAMPower/memspec/MemSpecLPDDR4.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n#include <DRAMPower/memspec/MemSpecLPDDR5.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n\n#include <DRAMUtils/util/json_utils.h>\n#include <DRAMUtils/memspec/MemSpec.h>\n\n#include \"csv.hpp\"\n#include \"util.hpp\"\n#include \"config.h\"\n\nnamespace DRAMPower::DRAMPowerCLI {\n\nusing namespace DRAMPower;\n\nstd::unique_ptr<dram_base<CmdType>> getMemory(const std::string_view &data, const DRAMPower::config::SimConfig& simconfig)\n{\n\ttry\n\t{\n\t\tstd::unique_ptr<dram_base<CmdType>> result = nullptr;\n\t\t// Get memspec\n        auto memspec = DRAMUtils::parse_memspec_from_file(std::filesystem::path(data));\n        if (!memspec) {\n            return result;\n\t\t}\n\t\t// Get ddr\n\t\tstd::visit( [&result, &simconfig] (auto&& arg) {\n\t\t\tusing T = std::decay_t<decltype(arg)>;\n\t\t\tif constexpr (std::is_same_v<T, DRAMUtils::MemSpec::MemSpecDDR4>)\n\t\t\t{\n\t\t\t\tMemSpecDDR4 ddr (static_cast<DRAMUtils::MemSpec::MemSpecDDR4>(arg));\n\t\t\t\tresult = std::make_unique<DDR4>(ddr, simconfig);\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<T, DRAMUtils::MemSpec::MemSpecDDR5>)\n\t\t\t{\n\t\t\t\tMemSpecDDR5 ddr (static_cast<DRAMUtils::MemSpec::MemSpecDDR5>(arg));\n\t\t\t\tresult = std::make_unique<DDR5>(ddr, simconfig);\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<T, DRAMUtils::MemSpec::MemSpecLPDDR4>)\n\t\t\t{\n\t\t\t\tMemSpecLPDDR4 ddr (static_cast<DRAMUtils::MemSpec::MemSpecLPDDR4>(arg));\n\t\t\t\tresult = std::make_unique<LPDDR4>(ddr, simconfig);\n\t\t\t}\n\t\t\telse if constexpr (std::is_same_v<T, DRAMUtils::MemSpec::MemSpecLPDDR5>)\n\t\t\t{\n\t\t\t\tMemSpecLPDDR5 ddr (static_cast<DRAMUtils::MemSpec::MemSpecLPDDR5>(arg));\n\t\t\t\tresult = std::make_unique<LPDDR5>(ddr, simconfig);\n\t\t\t}\n\t\t}, memspec->getVariant());\n\n\t\treturn result;\n\t}\n\tcatch(const std::exception& e)\n\t{\n\t\treturn nullptr;\n\t}\n}\n\nbool parse_command_list(std::string_view csv_file, std::vector<std::pair<Command, std::unique_ptr<uint8_t[]>>> &commandList)\n{\n\t// Read csv file\n\tcsv::CSVFormat format;\n\tformat.no_header();\n\tformat.trim({ ' ', '\\t' });\n\n\tcsv::CSVReader reader{ csv_file, format };\n\t\n\t// loop variables\n\tuint64_t rowcounter = 0;\n\tstd::size_t rowidx, size, rank_id, bank_group_id, bank_id, row_id, column_id = 0;\n\n\ttimestamp_t timestamp = 0;\n\tcsv::string_view cmdType;\n\tstd::unordered_map<csv::string_view, DRAMPower::CmdType>::iterator cmdit;\n\tCmdType cmd;\n\n\t// Parse csv file\n\t// timestamp, command, rank, bank_group, bank, row, column, [data]\n\tconstexpr std::size_t MINCSVSIZE = 7;\n\tfor ( csv::CSVRow& row : reader ) {\n\t\trowidx = 0;\n\n\t\t// Read csv row\n\t\tif ( row.size() < MINCSVSIZE )\n\t\t{\n            return false;\n\t\t}\n\t\t\t\n\t\ttimestamp = row[rowidx++].get<timestamp_t>();\n\t\tcmdType = row[rowidx++].get_sv();\n\t\trank_id = row[rowidx++].get<std::size_t>();\n\t\tbank_group_id = row[rowidx++].get<std::size_t>();\n\t\tbank_id = row[rowidx++].get<std::size_t>();\n\t\trow_id = row[rowidx++].get<std::size_t>();\n\t\tcolumn_id = row[rowidx++].get<std::size_t>();\n\n\t\t// Get command\n\t\tcmd = DRAMPower::CmdTypeUtil::from_string(cmdType);\n\n\t\t// Get data if needed\n\t\tif ( DRAMPower::CmdTypeUtil::needs_data(cmd) ) {\n\t\t\tif ( row.size() < MINCSVSIZE + 1 ) {\n                return false;\n\t\t\t}\n\t\t\t// uint64_t length = 0;\n\t\t\tcsv::string_view data = row[rowidx++].get_sv();\n\t\t\tstd::unique_ptr<uint8_t[]> arr;\n\t\t\ttry\n\t\t\t{\n\t\t\t\tarr = util::hexStringToUint8Array(data, size);\n\t\t\t}\n\t\t\tcatch (std::exception &e)\n\t\t\t{\n                return false;\n\t\t\t}\n\t\t\tcommandList.emplace_back(Command{ timestamp, cmd, { bank_id, bank_group_id, rank_id, row_id, column_id}, arr.get(), size * 8}, std::move(arr));\n\t\t}\n\t\telse {\n\t\t\tcommandList.emplace_back(Command{ timestamp, cmd, { bank_id, bank_group_id, rank_id, row_id, column_id} }, nullptr);\n\t\t}\n\t\t// Increment row counter\n\t\t++rowcounter;\n\t}\n\n\treturn true;\n};\n\nbool jsonFileResult(const std::string &jsonfile, const std::unique_ptr<dram_base<CmdType>> &ddr, const energy_t &core_energy, const interface_energy_info_t &interface_energy)\n{\n\tstd::ofstream out;\n\tout = std::ofstream(jsonfile);\n\tif ( !out.is_open() ) {\n        return false;\n\t}\n\tjson_t j;\n\tsize_t energy_offset = 0;\n\tDRAMPower::util::CLIArchitectureConfig cli_config = ddr->getCLIArchitectureConfig();\n\tauto bankcount = cli_config.bankCount;\n\tauto rankcount = cli_config.rankCount;\n\tauto devicecount = cli_config.deviceCount;\n\n\tj[\"RankCount\"] = rankcount;\n\tj[\"DeviceCount\"] = devicecount;\n\tj[\"BankCount\"] = bankcount;\n\tj[\"TotalEnergy\"] = core_energy.total() + interface_energy.total();\n\n\t// Energy object to json\n\tcore_energy.to_json(j[\"CoreEnergy\"]);\n\tinterface_energy.to_json(j[\"InterfaceEnergy\"]);\n\n\t// Validate array length\n\tif ( !j[\"CoreEnergy\"][core_energy.get_Bank_energy_keyword()].is_array() || j[\"CoreEnergy\"][core_energy.get_Bank_energy_keyword()].size() != rankcount * bankcount * devicecount )\n\t{\n\t\tassert(false); // (should not happen)\n        return false;\n\t}\n\t\n\t// Add rank,device,bank description\n\tfor ( std::size_t r = 0; r < rankcount; r++ ) {\n\t\tfor ( std::size_t d = 0; d < devicecount; d++ ) {\n\t\t\tenergy_offset = r * bankcount * devicecount + d * bankcount;\n\t\t\tfor ( std::size_t b = 0; b < bankcount; b++ ) {\n\t\t\t\t// Rank,Device,Bank -> bank_energy\n\t\t\t\tj[\"CoreEnergy\"][core_energy.get_Bank_energy_keyword()].at(energy_offset + b)[\"Rank\"] = r;\n\t\t\t\tj[\"CoreEnergy\"][core_energy.get_Bank_energy_keyword()].at(energy_offset + b)[\"Device\"] = d;\n\t\t\t\tj[\"CoreEnergy\"][core_energy.get_Bank_energy_keyword()].at(energy_offset + b)[\"Bank\"] = b;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tout << j.dump(4) << std::endl;\n\tout.close();\n\treturn true;\n}\n\nbool stdoutResult(const std::unique_ptr<dram_base<CmdType>> &ddr, const energy_t &core_energy, const interface_energy_info_t &interface_energy)\n{\n\t// Setup output format\n\tstd::cout << std::defaultfloat << std::setprecision(3);\n\t// Print stats\n\tDRAMPower::util::CLIArchitectureConfig cli_config = ddr->getCLIArchitectureConfig();\n\tauto bankcount = cli_config.bankCount;\n\tauto rankcount = cli_config.rankCount;\n\tauto devicecount = cli_config.deviceCount;\n\tsize_t energy_offset = 0;\n\t// NOTE: ensure the same order of calculation in the interface\n\tspdlog::info(\"Rank,Device,Bank -> bank_energy:\");\n\tfor ( std::size_t r = 0; r < rankcount; r++ ) {\n\t\tfor ( std::size_t d = 0; d < devicecount; d++ ) {\n\t\t\tenergy_offset = r * bankcount * devicecount + d * bankcount;\n\t\t\tfor ( std::size_t b = 0; b < bankcount; b++ ) {\n\t\t\t\t// Rank,Device,Bank -> bank_energy\n\t\t\t\tspdlog::info(\"{},{},{} -> {}\",\n\t\t\t\t\tr, d, b,\n\t\t\t\t\tcore_energy.bank_energy[energy_offset + b]\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\tspdlog::info(\"Cumulated bank energy with bg_act_shared -> {}\", core_energy.aggregated_bank_energy());\n\tspdlog::info(\"Shared energy -> {}\", core_energy);\n\tspdlog::info(\"Interface Energy:\\n{}\", interface_energy);\n\tspdlog::info(\"Total Energy -> {}\", core_energy.total() + interface_energy.total());\n\treturn true;\n}\n\nbool getConfig(const std::string &configfile, config::CLIConfig &config)\n{\n    try {\n        std::ifstream file(configfile);\n        if (!file.is_open()) {\n            return false;\n        }\n        json_t json_obj = json_t::parse(file, nullptr, false, true);\n        config = json_obj;\n        if (!config.useToggleRate) {\n            config.simconfig.toggleRateDefinition = std::nullopt;\n        }\n        if (config.useToggleRate && !config.simconfig.toggleRateDefinition.has_value()) {\n            spdlog::error(\"Provide a toggleRateDefinition for a simulation with toggling rates\");\n            return false;\n        }\n    } catch (std::exception&) {\n        return false;\n    }\n    return true;\n}\n\nbool makeResult(std::optional<std::string> jsonfile, const std::unique_ptr<dram_base<CmdType>> &ddr)\n{\n    energy_t core_energy = ddr->calcCoreEnergy(ddr->getLastCommandTime());\n    interface_energy_info_t interface_energy = ddr->calcInterfaceEnergy(ddr->getLastCommandTime());\n    if(jsonfile)\n\t{\n\t\treturn jsonFileResult(*jsonfile, std::move(ddr), core_energy, interface_energy);\n\t}\n\telse\n\t{\n\t\treturn stdoutResult(std::move(ddr), core_energy, interface_energy);\n\t}\n}\n\nbool runCommands(std::unique_ptr<dram_base<CmdType>> &ddr, const std::vector<std::pair<Command, std::unique_ptr<uint8_t[]>>> &commandList)\n{\n    try {\n\t\tfor (auto &command : commandList ) {\n\t\t\tddr->doCommand(command.first);\n\t\t}\n\t} catch (std::exception &e) {\n\t\treturn false;\n\t}\n    return true;\n}\n\n} // namespace DRAMPower::DRAMPowerCLI"
  },
  {
    "path": "src/cli/lib/DRAMPower/cli/run.hpp",
    "content": "#ifndef LIB_DRAMPOWERCLI_RUN_H\n#define LIB_DRAMPOWERCLI_RUN_H\n\n#include <optional>\n#include <vector>\n#include <memory>\n#include <string>\n\n#include <DRAMUtils/config/toggling_rate.h>\n#include <DRAMPower/command/Command.h>\n#include <DRAMPower/dram/dram_base.h>\n#include <DRAMPower/command/CmdType.h>\n#include <DRAMPower/simconfig/simconfig.h>\n\n#include \"config.h\"\n\nnamespace DRAMPower::DRAMPowerCLI {\n\nstd::unique_ptr<dram_base<CmdType>> getMemory(const std::string_view &data, const DRAMPower::config::SimConfig& simconfig);\nbool parse_command_list(std::string_view csv_file, std::vector<std::pair<Command, std::unique_ptr<uint8_t[]>>> &commandList);\nbool makeResult(std::optional<std::string> jsonfile, const std::unique_ptr<dram_base<CmdType>> &ddr);\nbool jsonFileResult(const std::string &jsonfile, const std::unique_ptr<dram_base<CmdType>> &ddr, const energy_t &core_energy, const interface_energy_info_t &interface_energy);\nbool stdoutResult(const std::unique_ptr<dram_base<CmdType>> &ddr, const energy_t &core_energy, const interface_energy_info_t &interface_energy);\nbool getConfig(const std::string &configfile, config::CLIConfig &config);\nbool runCommands(std::unique_ptr<dram_base<CmdType>> &ddr, const std::vector<std::pair<Command, std::unique_ptr<uint8_t[]>>> &commandList);\n\n\n} // namespace DRAMPower::DRAMPowerCLI\n\n#endif /* LIB_DRAMPOWERCLI_RUN_H */\n"
  },
  {
    "path": "src/cli/lib/DRAMPower/cli/util.cpp",
    "content": "#include \"util.hpp\"\n\nnamespace DRAMPower::DRAMPowerCLI {\n\nstd::unique_ptr<uint8_t[]> util::hexStringToUint8Array(const csv::string_view data, size_t &size)\n{\n\t// Check if the string has valid length\n\tif ( ( data.length() % 2 ) != 0)\n\t{\n\t\tthrow std::invalid_argument(\"Invalid hex string length\");\n\t}\n\n\t// String conversion\n\tstd::string hexString;\n\tsize = data.length() / 2;\n\t\n\t// Remove 0x or 0X prefix if present\n\tif (data.substr(0, 2) == \"0x\" || data.substr(0, 2) == \"0X\")\n\t{\n\t\tsize--;\n\t\thexString = data.substr(2);\n\t}\n\telse\n\t{\n\t\thexString = data;\n\t}\n\t\n\t// Allocate memory for the array and fill it\n\tauto content = std::make_unique<uint8_t[]>(size);\n\tfor (size_t i = 0; i < size; i++)\n\t{\n\t\tcontent[i] = static_cast<uint8_t>(std::stoi(hexString.substr(i * 2, 2), nullptr, 16));\n\t}\n\treturn content;\n}\n\n} // namespace DRAMPower::DRAMPowerCLI"
  },
  {
    "path": "src/cli/lib/DRAMPower/cli/util.hpp",
    "content": "#ifndef UTIL_HPP\n#define UTIL_HPP\n\n\n#include <stdint.h>\n#include \"csv.hpp\"\n\nnamespace DRAMPower::DRAMPowerCLI::util {\n\n    // Util function to get the memory\n    std::unique_ptr<uint8_t[]> hexStringToUint8Array(const csv::string_view data, size_t &size);\n\n} // namespace DRAMPower::DRAMPowerCLI::util\n\n\n#endif"
  },
  {
    "path": "src/cli/main/CMakeLists.txt",
    "content": "###############################\n###           cli           ###\n###############################\n\nfind_package(spdlog REQUIRED)\nfind_package(cli11 REQUIRED)\n\nadd_executable(cli \n    main.cpp\n    validators.cpp\n)\n\ntarget_compile_features(cli PUBLIC cxx_std_17)\nset_target_properties(cli PROPERTIES CXX_EXTENSIONS OFF)\nset_target_properties(cli PROPERTIES CXX_STANDARD_REQUIRED ON)\n\ntarget_link_libraries(cli \nPRIVATE\n    DRAMPower::cli_lib\n    DRAMPower::DRAMPower\n    spdlog::spdlog\n    CLI11::CLI11\n)\ntarget_compile_definitions(cli PRIVATE DRAMPOWER_VERSION_STRING=\"${DRAMPOWER_VERSION_STRING}\")"
  },
  {
    "path": "src/cli/main/main.cpp",
    "content": "\n#include <stdint.h>\n#include <utility>\n#include <optional>\n#include <string_view>\n\n#include <DRAMPower/cli/run.hpp>\n#include <DRAMPower/cli/config.h>\n\n#include <CLI/CLI.hpp>\n\n#include <spdlog/spdlog.h>\n#include <spdlog/fmt/ostr.h>\n\n#include \"validators.h\"\n\n\nnamespace cli11 = ::CLI; \nusing namespace DRAMPower;\n\nint parseArgs(int argc, char *argv[], std::string &configfile, std::string &tracefile, std::string &memspec, std::optional<std::string> &jsonfile)\n{\n\t// Application description\n\tcli11::App app{\"DRAMPower v\" DRAMPOWER_VERSION_STRING};\n\targv = app.ensure_utf8(argv);\n\t\n\t// Configfile\n\tapp.add_option(\"-c,--config\", configfile, \"config\")\n\t\t->required(true)\n\t\t->check(cli11::ExistingFile);\n\t// Tracefile\n\tapp.add_option(\"-t,--trace\", tracefile, \"csv trace file\")\n\t\t->required(true)\n\t\t->check(cli11::ExistingFile);\n\t// Memspec\n\tapp.add_option(\"-m,--memspec\", memspec, \"json memspec file\")\n\t\t->required(true)\n\t\t->check(cli11::ExistingFile);\n\t// JSON output file\n\tapp.add_option(\"-j,--json\", jsonfile, \"json output file path\")\n\t\t->required(false)\n\t\t->check(validators::EnsureFileExists);\n\t// Parse arguments\n\ttry { \n\t\tapp.parse(argc, argv); \n\t} catch(const cli11::ParseError &e) {\n\t\treturn app.exit(e);\n\t}\n\treturn 0;\n}\n\nint main(int argc, char *argv[])\n{\n\t// Options\n\tstd::string configfile;\n\tstd::string tracefile;\n\tstd::string memspec;\n\tstd::optional<std::string> jsonfile = std::nullopt;\n\tint res = parseArgs(argc, argv, configfile, tracefile, memspec, jsonfile);\n\tif(res != 0)\n\t{\n\t\treturn res;\n\t}\n\n\t// Set spdlog pattern\n\tspdlog::set_pattern(\"%v\");\n\n\t// Read config\n\tDRAMPower::DRAMPowerCLI::config::CLIConfig config;\n\tif (!DRAMPower::DRAMPowerCLI::getConfig(configfile, config)) {\n\t\tspdlog::info(\"Invalid config file\");\n\t\treturn 1;\n\t}\n\n\t// Parse command list (load command list in memory)\n\tstd::vector<std::pair<Command, std::unique_ptr<uint8_t[]>>> commandList;\n\tif(!DRAMPower::DRAMPowerCLI::parse_command_list(tracefile, commandList))\n\t{\n\t\tspdlog::error(\"Error while parsing command list. Exiting application\");\n\t\treturn 1;\n\t}\n\n\t// Initialize memory / Create memory object\n\tstd::unique_ptr<dram_base<CmdType>> ddr = DRAMPower::DRAMPowerCLI::getMemory(std::string_view(memspec), config.simconfig);\n\tif (!ddr) {\n\t\tspdlog::error(\"Invalid memory specification\");\n\t\treturn 1;\n\t}\n\n\t// Execute commands\n\tif(!DRAMPower::DRAMPowerCLI::runCommands(ddr, commandList))\n\t{\n\t\tspdlog::error(\"Error while running commands. Exiting application\");\n\t\treturn 1;\n\t}\n\n\t// Calculate energy and stats\n\tif(!DRAMPower::DRAMPowerCLI::makeResult(jsonfile, std::move(ddr)))\n\t{\n\t\tspdlog::error(\"Error while creating result. Exiting application\");\n\t\treturn 1;\n\t}\n\treturn 0;\n};\n"
  },
  {
    "path": "src/cli/main/validators.cpp",
    "content": "#include \"validators.h\"\n\n#include <string>\n#include <filesystem>\n#include <fstream>\n#include <optional>\n\nnamespace validators {\n\nstruct ResolveSymlinkResult {\n    enum class Type {\n        FILE,\n        DIRECTORY, // included for future default filename creation\n        NOT_FOUND // File does not exist but a parent directory could exist\n    };\n    Type type;\n    std::string path;\n};\n\nstd::optional<ResolveSymlinkResult> resolve_symlink(const std::string &filepath, const uint_fast8_t max_iter)\n{\n    // Check if path exists and is a symlink\n    if (!std::filesystem::is_symlink(filepath)) {\n        // File does not exist or is not a symlink\n        return std::nullopt;\n    }\n\n    // The path exists and is a symlink -> resolve the symlink chain\n    std::filesystem::path resolved = filepath;\n    for (uint_fast8_t iter = 0; iter < max_iter; ++iter) {\n        resolved = std::filesystem::read_symlink(resolved);\n        // Check if the provided path exists\n        if (!std::filesystem::exists(resolved)) {\n            // symlink resolved to a non-existing path\n            return std::make_optional(ResolveSymlinkResult{\n                ResolveSymlinkResult::Type::NOT_FOUND, // type\n                resolved.string() // path\n            }); \n        } else\n\n        if (std::filesystem::is_regular_file(resolved)) {\n            // symlink resolved to a file\n            return std::make_optional(ResolveSymlinkResult{\n                ResolveSymlinkResult::Type::FILE, // type\n                resolved.string() // path\n            }); \n        } else if (std::filesystem::is_directory(resolved)) {\n            // symlink resolved to a non-file\n            return std::make_optional(ResolveSymlinkResult{\n                ResolveSymlinkResult::Type::DIRECTORY, // type \n                resolved.string() // path\n            });\n        } else if (std::filesystem::is_symlink(resolved)) {\n            // symlink resolved to another symlink\n            // continue to next iteration\n        } else {\n            // symlink resolved to an unknown type\n            return std::nullopt;\n        }\n    }\n\n    // The symlink chain was not resolved in the maximum number of iterations\n    return std::nullopt;\n}\n\n// This function assumes the filepath does not exist\nstd::string createFileInParentDirectory(const std::filesystem::path& filepath)\n{\n// Check parent directory exists\n    std::filesystem::path path = filepath.parent_path();\n\n    // No path directory provided -> create the file in current directory\n    if (path.empty() && filepath.is_relative()) {\n        path = std::filesystem::current_path();\n    }\n    if (!std::filesystem::exists(path)) {\n        // parent directory does not exist\n        return std::string{\"Parent directory does not exist\"};\n    } else if (!std::filesystem::is_directory(path)) {\n        // parent is not a directory. The path is invalid\n        return std::string{\"Invlid path\"};\n    }\n\n// File does not exist and the parent directory exists\n    // Try to create the file\n    try { // Catch std::ofstream exceptions\n        std::ofstream file{filepath};\n        if (!file.is_open()) {\n            // Could not create the file\n            // creation failed ofstream closes the file in destructor\n            return std::string{\"Could not create the file\"};\n        }\n        // explicitly close the file to ensure that the file is created and closed\n        file.close();\n        if (!file.good()) {\n            // Could not create the file\n            return std::string{\"Could not create the file\"};\n        }\n    } catch (const std::exception&) {\n        // Could not create the file\n        return std::string{\"Could not create the file\"};\n    }\n// File was created successfully\n    return std::string{};\n}\n\nEnsureFileExists_t::EnsureFileExists_t() {\n    name_ = \"EnsureFileExists\";\n    non_modifying_ = false; // The validator modifies the input for a symlink\n    func_ = [](std::string &filepath) {\n// Check if file exists\n        if (std::filesystem::is_symlink(filepath)) {\n// resolve symlink chain for at most MAX_SYMLINK_RESOLVE_ITERATIONS iterations\n            auto resolved = resolve_symlink(filepath, MAX_SYMLINK_RESOLVE_ITERATIONS);\n            if (!resolved) {\n                return std::string{\"Could not resolve the symlink\"};\n            }\n            // resolved is valid\n            if (resolved->type == ResolveSymlinkResult::Type::FILE) {\n                // resolved to a file\n                filepath = resolved->path;\n                return std::string{};\n            } else if (resolved->type == ResolveSymlinkResult::Type::DIRECTORY) {\n                // resolved to a directory\n                return std::string{\"Path is a directory\"};\n            } else if (resolved->type == ResolveSymlinkResult::Type::NOT_FOUND) {\n                // file not found but a parent directory could exist\n                filepath = resolved->path;\n                return createFileInParentDirectory(filepath);\n            }\n        } else if (std::filesystem::is_regular_file(filepath)) {\n            // file exists\n            return std::string{};\n        } else if(std::filesystem::exists(filepath)) {\n            // the path exists but is not a file or a symlink\n            return std::string{\"Path is not a file\"};\n        }\n        // The filepath does not exist\n// Try to create the file in the parent directory\n        return createFileInParentDirectory(filepath);\n    };\n}\n\n} // namespace validators"
  },
  {
    "path": "src/cli/main/validators.h",
    "content": "#ifndef CLI_VALIDATORS_H\n#define CLI_VALIDATORS_H\n\n#include <CLI/CLI.hpp>\n#include <stdint.h>\n\nnamespace validators\n{\n\n#define MAX_SYMLINK_RESOLVE_ITERATIONS 10\n\nstruct EnsureFileExists_t : public CLI::Validator {\n    EnsureFileExists_t();\n};\nconst static EnsureFileExists_t EnsureFileExists;\n\n} // namespace validators\n\n#endif /* CLI_VALIDATORS_H */\n"
  },
  {
    "path": "tests/CMakeLists.txt",
    "content": "include(GoogleTest)\n\noption(DRAMPOWER_USE_FETCH_CONTENT_GOOGLE_TEST \"Enable FetchContent to provide Google Test\" ${DRAMPOWER_USE_FETCH_CONTENT})\n\nif (DRAMPOWER_USE_FETCH_CONTENT)\n    if (DRAMPOWER_USE_FETCH_CONTENT_GOOGLE_TEST)\n        FetchContent_Declare(\n            GTest\n            URL https://github.com/google/googletest/releases/download/v1.15.2/googletest-1.15.2.tar.gz\n            OVERRIDE_FIND_PACKAGE\n        )\n        # For Windows: Prevent overriding the parent project's compiler/linker settings\n        set(gtest_force_shared_crt ON CACHE BOOL \"\" FORCE)\n\n        FetchContent_MakeAvailable(GTest)\n        # TODO: Necessary target properties?\n        set_target_properties(gmock PROPERTIES FOLDER lib)\n        set_target_properties(gmock_main PROPERTIES FOLDER lib)\n        set_target_properties(gtest PROPERTIES FOLDER lib)\n        set_target_properties(gtest_main PROPERTIES FOLDER lib)\n    endif()\nendif()\n\nfind_package(GTest REQUIRED)\n\nadd_subdirectory(tests_drampower)\nadd_subdirectory(tests_misc)\n"
  },
  {
    "path": "tests/tests_drampower/CMakeLists.txt",
    "content": "###############################################\n###              tests_drampower            ###\n###############################################\n\nadd_executable(tests_drampower\n\tbase/test_ddr_serialize.cpp\n\tbase/test_ddr_base.cpp\n\tbase/test_ddr_data.cpp\n\tbase/test_pattern_pre_cycles.cpp\n\n\tcore/DDR4/ddr4_multidevice_tests.cpp\n\tcore/DDR4/ddr4_multirank_tests.cpp\n\tcore/DDR4/ddr4_test_pattern_0.cpp\n\tcore/DDR4/ddr4_test_pattern_1.cpp\n\tcore/DDR4/ddr4_test_pattern_2.cpp\n\tcore/DDR4/ddr4_test_pattern_3.cpp\n\tcore/DDR4/ddr4_test_pattern_4.cpp\n\tcore/DDR4/ddr4_test_pattern_5.cpp\n\tcore/DDR4/ddr4_test_pattern_6.cpp\n\tcore/DDR4/ddr4_test_pattern_7.cpp\n\tcore/DDR4/ddr4_test_pattern_8.cpp\n\tcore/DDR4/ddr4_test_pattern_9.cpp\n\tcore/DDR4/ddr4_test_pattern_10.cpp\n\tcore/DDR4/ddr4_test_pattern_11.cpp\n\tcore/DDR4/ddr4_test_pattern_12.cpp\n\tcore/DDR4/ddr4_test_pattern_13.cpp\n\tcore/DDR4/ddr4_test_pattern_14.cpp\n\tcore/DDR4/ddr4_test_pattern_15.cpp\n\n\tcore/DDR5/ddr5_multidevice_tests.cpp\n\tcore/DDR5/ddr5_multirank_tests.cpp\n\tcore/DDR5/ddr5_test_pattern_0.cpp\n\tcore/DDR5/ddr5_test_pattern_1.cpp\n\tcore/DDR5/ddr5_test_pattern_2.cpp\n\tcore/DDR5/ddr5_test_pattern_3.cpp\n\tcore/DDR5/ddr5_test_pattern_4.cpp\n\tcore/DDR5/ddr5_test_pattern_5.cpp\n\tcore/DDR5/ddr5_test_pattern_6.cpp\n\tcore/DDR5/ddr5_test_pattern_7.cpp\n\tcore/DDR5/ddr5_test_pattern_8.cpp\n\tcore/DDR5/ddr5_test_pattern_9.cpp\n\tcore/DDR5/ddr5_test_pattern_10.cpp\n\tcore/DDR5/ddr5_test_pattern_11.cpp\n\tcore/DDR5/ddr5_test_pattern_12.cpp\n\tcore/DDR5/ddr5_test_pattern_13.cpp\n\tcore/DDR5/ddr5_test_pattern_14.cpp\n\tcore/DDR5/ddr5_test_pattern_15.cpp\n\tcore/DDR5/ddr5_test_pattern_16.cpp\n\tcore/DDR5/ddr5_test_pattern_17.cpp\n\tcore/DDR5/ddr5_test_pattern_18.cpp\n\n\tcore/LPDDR4/lpddr4_multidevice_tests.cpp\n\tcore/LPDDR4/lpddr4_multirank_tests.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_0.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_1.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_2.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_3.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_4.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_5.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_6.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_7.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_8.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_9.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_10.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_11.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_12.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_13.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_14.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_15.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_16.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_17.cpp\n\tcore/LPDDR4/lpddr4_test_pattern_18.cpp\n\n\tcore/LPDDR5/lpddr5_multidevice_tests.cpp\n\tcore/LPDDR5/lpddr5_multirank_tests.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_0.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_1.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_2.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_3.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_4.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_5.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_6.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_7.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_8.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_9.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_10.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_11.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_12.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_13.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_14.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_15.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_16.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_17.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_18.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_19.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_20.cpp\n\tcore/LPDDR5/lpddr5_test_pattern_21.cpp\n\n\tinterface/test_interface_ddr4.cpp\n\tinterface/test_interface_ddr5.cpp\n\tinterface/test_interface_lpddr4.cpp\n\tinterface/test_interface_lpddr5.cpp\n\n\tinterface/test_togglingrate_ddr4.cpp\n\tinterface/test_togglingrate_ddr5.cpp\n\tinterface/test_togglingrate_lpddr4.cpp\n\tinterface/test_togglingrate_lpddr5.cpp\n\n\tinterface/test_dbi_ddr4.cpp\n\tinterface/test_dbi_lpddr4.cpp\n\tinterface/test_dbi_lpddr5.cpp\n)\n\nset_target_properties(tests_drampower PROPERTIES FOLDER tests/drampower)\n\ntarget_compile_definitions(tests_drampower PUBLIC TEST_RESOURCE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/resources/\")\ntarget_include_directories(tests_drampower PUBLIC ${PROJECT_SOURCE_DIR})\n\ntarget_link_libraries(tests_drampower\n\tDRAMPower::DRAMPower\n\tgtest\n\tgtest_main\n)\n\ngtest_discover_tests(tests_drampower\n\tWORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}\n)\n"
  },
  {
    "path": "tests/tests_drampower/base/test_ddr_base.cpp",
    "content": "#include <algorithm>\n#include <gtest/gtest.h>\n\n#include \"DRAMPower/Types.h\"\n#include \"DRAMPower/command/Command.h\"\n\n#include \"DRAMPower/data/stats.h\"\n#include \"DRAMPower/dram/dram_base.h\"\n\n#include \"DRAMPower/util/cli_architecture_config.h\"\n\n#include <memory>\n#include <stdexcept>\n\nusing namespace DRAMPower;\n\nclass test_ddr : public dram_base<CmdType>\n{\npublic:\n    energy_t calcCoreEnergyStats(const SimulationStats&) const override { return energy_t(1); };\n    interface_energy_info_t calcInterfaceEnergyStats(const SimulationStats&) const override { return interface_energy_info_t(); };\n    SimulationStats getWindowStats(timestamp_t) override { return {}; };\n    util::CLIArchitectureConfig getCLIArchitectureConfig() override { return util::CLIArchitectureConfig{}; };\n    bool isSerializable() const override {\n        return false;\n    }\n    \n\n\ttest_ddr() = default;\n\nprivate:\n    void serialize_impl(std::ostream&) const override {}\n    void deserialize_impl(std::istream&) override {}\n    void doCoreCommandImpl(const Command& command) override {\n        implicitCommandHandler.processImplicitCommandQueue(command.timestamp, last_command_time);\n        __doCoreCommand(command);\n    }\n    void doInterfaceCommandImpl(const Command& command) override {\n        implicitCommandHandler.processImplicitCommandQueue(command.timestamp, last_command_time);\n        __doInterfaceCommand(command);\n    }\n\n    void __doInterfaceCommand(const Command&) {\n        return;\n    }\n    void __doCoreCommand(const Command& command) {\n        auto next_timestamp = command.timestamp;\n        switch (command.type) {\n            case CmdType::ACT:\n                break;\n            case CmdType::PRE:\n                next_timestamp += 10;\n                implicitCommandHandler.addImplicitCommand(next_timestamp, [this, next_timestamp]() {\n                    execution_order.push_back(next_timestamp);\n                });\n                break;\n            case CmdType::PREA:\n                next_timestamp += 1;\n                implicitCommandHandler.addImplicitCommand(next_timestamp, [this, next_timestamp]() {\n                    execution_order.push_back(next_timestamp);\n                });\n                break;\n            default:\n                throw std::runtime_error(\"Invalid type\");\n        }\n        execution_order.push_back(command.timestamp);\n        last_command_time = std::max(last_command_time, command.timestamp);\n    }\n    timestamp_t getLastCommandTime_impl() const override {\n        return last_command_time;\n    }\n\n    timestamp_t last_command_time;\n\npublic:\n\tstd::vector<timestamp_t> execution_order;\n    ImplicitCommandHandler<> implicitCommandHandler;\n};\n\nclass DDR_Base_Test : public ::testing::Test {\nprotected:\n    // Test variables\n    std::unique_ptr<test_ddr> ddr;\n\n    virtual void SetUp()\n    {\n        ddr = std::make_unique<test_ddr>();\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DDR_Base_Test, DoCommand)\n{\n    this->ddr->doCoreCommand({ 10, CmdType::ACT, { 1, 0, 0 } });\n\n\tASSERT_EQ(ddr->execution_order.size(), 1);\n\tASSERT_EQ(ddr->execution_order[0], 10);\n}\n\nTEST_F(DDR_Base_Test, ImplicitCommand)\n{\n\tthis->ddr->doCoreCommand({ 10, CmdType::PRE, { 1, 0, 0 } });\n\tthis->ddr->doCoreCommand({ 15, CmdType::PREA, { 1, 0, 0 } });\n\tthis->ddr->doCoreCommand({ 50, CmdType::ACT, { 1, 0, 0 } });\n\n\tASSERT_EQ(ddr->execution_order.size(), 5);\n\tASSERT_EQ(ddr->execution_order[0], 10);\n\tASSERT_EQ(ddr->execution_order[1], 15);\n\tASSERT_EQ(ddr->execution_order[2], 16);\n\tASSERT_EQ(ddr->execution_order[3], 20);\n\tASSERT_EQ(ddr->execution_order[4], 50);\n}\n"
  },
  {
    "path": "tests/tests_drampower/base/test_ddr_data.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include \"DRAMPower/dram/dram_base.h\"\n\n#include <memory>\n\nusing namespace DRAMPower;\n\ntemplate<CmdType Type, uint64_t Pattern>\nstruct CommandPattern\n{\n\tconstexpr static auto type() { return Type; };\n\tconstexpr static auto pattern() { return Pattern; };\n};\n\ntemplate<typename Head, typename... Tail>\nstruct pattern_helper\n{\n\tconstexpr static uint64_t get(CmdType type)\n\t{\n\t\tif (Head::type() == type)\n\t\t\treturn Head::pattern();\n\n\t\treturn pattern_helper<Tail...>::get(type);\n\t};\n};\n\ntemplate<typename Head>\nstruct pattern_helper<Head>\n{\n\tconstexpr static uint64_t get(CmdType type)\n\t{\n\t\tif (Head::type() == type)\n\t\t\treturn Head::pattern();\n\n\t\treturn 0x00;\n\t};\n};\n\ntemplate<typename... PatternList>\nstruct CommandPatternMap\n{\n\tconstexpr static uint64_t getPattern(CmdType type)\n\t{\n\t\treturn pattern_helper<PatternList...>::get(type);\n\t};\n};\n\n\n\nclass DramPowerDataTest : public ::testing::Test {\nprotected:\n\n\tvirtual void SetUp()\n\t{\n\t}\n\n\tvirtual void TearDown()\n\t{\n\t}\n};\n\nTEST_F(DramPowerDataTest, Test_1)\n{\n\tCommand command{ 10, CmdType::ACT, {} };\n\n\tusing TestPatterMap = CommandPatternMap<\n\t\tCommandPattern<CmdType::ACT, 0x1001>,\n\t\tCommandPattern<CmdType::PRE, 0x1011>\n\t>;\n\t\n\tASSERT_EQ(TestPatterMap::getPattern(CmdType::ACT), 0x1001);\n\tASSERT_EQ(TestPatterMap::getPattern(CmdType::PRE), 0x1011);\n\tASSERT_EQ(TestPatterMap::getPattern(CmdType::NOP), 0x0000);\n};"
  },
  {
    "path": "tests/tests_drampower/base/test_ddr_serialize.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n#include \"DRAMPower/simconfig/simconfig.h\"\n#include \"DRAMUtils/config/toggling_rate.h\"\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n#include <DRAMPower/standards/ddr5/DDR5.h>\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR4.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <optional>\n#include <stdint.h>\n\n#include <memory>\n\nusing namespace DRAMPower;\n\ntemplate <typename Standard, typename MemSpec>\nclass DramPowerTest_DDR_Serialize : public ::testing::Test {\nprotected:\n    using Pattern_t = std::vector<Command>;\n    using PatternList_t = std::vector<Pattern_t>;\n\n    static constexpr uint8_t wr_data[] = {\n        0x00, 0xFF, 0x01, 0x10, 0x00, 0xFF, 0x00, 0xFF\n    };\n    static constexpr uint8_t rd_data[] = {\n        0x00, 0xFF, 0x01, 0x10, 0x00, 0xFF, 0x00, 0xFF\n    };\n\n    // Test pattern\n    PatternList_t testPattern = {\n        {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            Command{15, CmdType::WR, TargetCoordinate{\n                0,\n                0,\n                0,\n                0,\n                0,\n            }, wr_data, sizeof(wr_data) * 8}, // TODO: for sz_bits 0 not working\n            Command{25, CmdType::RD, TargetCoordinate{\n                0,\n                0,\n                0,\n                0,\n                0,\n            }, rd_data, sizeof(wr_data) * 8},\n            {   35, CmdType::PRE,  { 0, 0, 0 }},\n            {   45, CmdType::REFA,  { 0, 0, 0 }},\n            {   80, CmdType::END_OF_SIMULATION },\n        },\n        {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            Command{15, CmdType::WR, TargetCoordinate{\n                0,\n                0,\n                0,\n                0,\n                0,\n            }, nullptr},\n            Command{25, CmdType::RD, TargetCoordinate{\n                0,\n                0,\n                0,\n                0,\n                0,\n            }, nullptr},\n            {   35, CmdType::PRE,  { 0, 0, 0 }},\n            {   45, CmdType::REFA,  { 0, 0, 0 }},\n            {   80, CmdType::END_OF_SIMULATION },\n        }\n    };\n\n\n    // Test variables\n    std::unique_ptr<Standard> ddr1;\n    std::unique_ptr<Standard> ddr2;\n    std::unique_ptr<MemSpec> memSpec;\n\n    virtual void getPath(std::filesystem::path& path) const = 0;\n\n    virtual void SetUp()\n    {\n        std::filesystem::path path;\n        getPath(path);\n        auto data = DRAMUtils::parse_memspec_from_file(path);\n        memSpec = std::make_unique<MemSpec>(MemSpec::from_memspec(*data));\n    }\n\n    void createStandard(std::optional<DRAMUtils::Config::ToggleRateDefinition> trd) {\n        if (!trd.has_value()) {\n            ddr1 = std::make_unique<Standard>(*memSpec);\n            ddr2 = std::make_unique<Standard>(*memSpec);\n        } else {\n            ddr1 = std::make_unique<Standard>(*memSpec, config::SimConfig{trd.value()});\n            ddr2 = std::make_unique<Standard>(*memSpec, config::SimConfig{trd.value()});\n        }\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nclass DramPowerTest_DDR4_Serialize : public DramPowerTest_DDR_Serialize<DDR4, MemSpecDDR4> {\nprotected:\n    void getPath(std::filesystem::path& path) const override {\n        path = std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\";\n    }\n};\nclass DramPowerTest_DDR5_Serialize : public DramPowerTest_DDR_Serialize<DDR5, MemSpecDDR5> {\nprotected:\n    void getPath(std::filesystem::path& path) const override {\n        path = std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\";\n    }\n};\nclass DramPowerTest_LPDDR4_Serialize : public DramPowerTest_DDR_Serialize<LPDDR4, MemSpecLPDDR4> {\nprotected:\n    void getPath(std::filesystem::path& path) const override {\n        path = std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\";\n    }\n};\nclass DramPowerTest_LPDDR5_Serialize : public DramPowerTest_DDR_Serialize<LPDDR5, MemSpecLPDDR5> {\nprotected:\n    void getPath(std::filesystem::path& path) const override {\n        path = std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\";\n    }\n};\n\ntemplate <typename Standard>\nvoid compareStats(const std::vector<Command>& testPattern, std::unique_ptr<Standard>& ddr1, std::unique_ptr<Standard>& ddr2) {\n    assert(testPattern.size() == 6);\n    // Enable dbi if possible\n    ddr1->getExtensionManager().template withExtension<DRAMPower::extensions::DBI>([](DRAMPower::extensions::DBI& dbi) {\n        dbi.enable(0, false);\n    });\n    // ACT\n    ddr1->doCoreCommand(testPattern[0]);\n    ddr1->doInterfaceCommand(testPattern[0]);\n    // WR\n    ddr1->doCoreCommand(testPattern[1]);\n    ddr1->doInterfaceCommand(testPattern[1]);\n    // Serialize and deserialize\n    auto streamout = std::ostringstream();\n    ddr1->serialize(streamout);\n    auto streamin = std::istringstream(streamout.str());\n    ddr2->deserialize(streamin);\n    // RD\n    ddr1->doCoreCommand(testPattern[2]);\n    ddr1->doInterfaceCommand(testPattern[2]);\n    ddr2->doCoreCommand(testPattern[2]);\n    ddr2->doInterfaceCommand(testPattern[2]);\n    // PRE\n    ddr1->doCoreCommand(testPattern[3]);\n    ddr1->doInterfaceCommand(testPattern[3]);\n    ddr2->doCoreCommand(testPattern[3]);\n    ddr2->doInterfaceCommand(testPattern[3]);\n    // REFA\n    ddr1->doCoreCommand(testPattern[4]);\n    ddr1->doInterfaceCommand(testPattern[4]);\n    ddr2->doCoreCommand(testPattern[4]);\n    ddr2->doInterfaceCommand(testPattern[4]);\n    // EOS\n    ddr1->doCoreCommand(testPattern[5]);\n    ddr1->doInterfaceCommand(testPattern[5]);\n    ddr2->doCoreCommand(testPattern[5]);\n    ddr2->doInterfaceCommand(testPattern[5]);\n\n    auto stats1 = ddr1->getStats();\n    auto stats2 = ddr2->getStats();\n\n    // Compare the stats of both DDR4 instances are equal\n    ASSERT_EQ(stats1, stats2);\n}\n\nTEST_F(DramPowerTest_DDR4_Serialize, Test0){\n    createStandard(std::nullopt);\n    compareStats(testPattern.at(0), ddr1, ddr2);\n}\n\nTEST_F(DramPowerTest_DDR5_Serialize, Test0){\n    createStandard(std::nullopt);\n    compareStats(testPattern.at(0), ddr1, ddr2);\n}\n\nTEST_F(DramPowerTest_LPDDR4_Serialize, Test0){\n    createStandard(std::nullopt);\n    compareStats(testPattern.at(0), ddr1, ddr2);\n}\n\nTEST_F(DramPowerTest_LPDDR5_Serialize, Test0){\n    createStandard(std::nullopt);\n    compareStats(testPattern.at(0), ddr1, ddr2);\n}\n\nTEST_F(DramPowerTest_DDR4_Serialize, Test1){\n    createStandard(DRAMUtils::Config::ToggleRateDefinition {\n        0.6,\n        0.4,\n        0.3,\n        0.2,\n        TogglingRateIdlePattern::L,\n        TogglingRateIdlePattern::L,\n    });\n    compareStats(testPattern.at(1), ddr1, ddr2);\n}\n\nTEST_F(DramPowerTest_DDR5_Serialize, Test1){\n    createStandard(DRAMUtils::Config::ToggleRateDefinition {\n        0.6,\n        0.4,\n        0.3,\n        0.2,\n        TogglingRateIdlePattern::L,\n        TogglingRateIdlePattern::L,\n    });\n    compareStats(testPattern.at(1), ddr1, ddr2);\n}\n\nTEST_F(DramPowerTest_LPDDR4_Serialize, Test1){\n    createStandard(DRAMUtils::Config::ToggleRateDefinition {\n        0.6,\n        0.4,\n        0.3,\n        0.2,\n        TogglingRateIdlePattern::L,\n        TogglingRateIdlePattern::L,\n    });\n    compareStats(testPattern.at(1), ddr1, ddr2);\n}\n\nTEST_F(DramPowerTest_LPDDR5_Serialize, Test1){\n    createStandard(DRAMUtils::Config::ToggleRateDefinition {\n        0.6,\n        0.4,\n        0.3,\n        0.2,\n        TogglingRateIdlePattern::L,\n        TogglingRateIdlePattern::L,\n    });\n    compareStats(testPattern.at(1), ddr1, ddr2);\n}\n"
  },
  {
    "path": "tests/tests_drampower/base/test_pattern_pre_cycles.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_Pre_Cycles : public ::testing::Test {\nprotected:\n\t// Test pattern\n\t// TODO invalid state transitions\n\tstd::vector<Command> testPattern = {\n\t\t// Timestamp,   Cmd,  { Bank, BG, Rank}\n\t\t\t{   0, CmdType::ACT,  { 0, 0, 0 } },\n\t\t\t{  30, CmdType::PDEA, { 0, 0, 0 } },\n\t\t\t{  40, CmdType::PDXA, { 0, 0, 0 } },\n\t\t\t{  70, CmdType::PRE,  { 0, 0, 0 } },\n\t\t\t{  80, CmdType::ACT,  { 1, 0, 0 } },\n\t\t\t{  90, CmdType::PRE,  { 1, 0, 0 } },\n\t\t\t{ 100,  CmdType::END_OF_SIMULATION },\n\t};\n\n\t// Test variables\n\tstd::unique_ptr<DRAMPower::DDR4> ddr;\n\n\tvirtual void SetUp()\n\t{\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        auto memSpec = DRAMPower::MemSpecDDR4::from_memspec(*data);\n\n\t\tmemSpec.numberOfRanks = 1;\n\t\tmemSpec.numberOfBanks = 2;\n\t\tmemSpec.numberOfBankGroups = 2;\n\t\t//memSpec.banksPerGroup = 4;\n\n\t\tmemSpec.memTimingSpec.tRAS = 10;\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n\t\tmemSpec.memTimingSpec.tRCD = 20;\n\t\tmemSpec.memTimingSpec.tRFC = 10;\n\t\t//memSpec.memTimingSpec.tRFCPB = 25;\n\t\t//memSpec.memTimingSpec.tRFCsb_slr = 25;\n\n\t\tmemSpec.memTimingSpec.tWR = 20;\n\t\tmemSpec.memTimingSpec.tRP = 20;\n\t\tmemSpec.memTimingSpec.tWL = 0;\n\t\tmemSpec.memTimingSpec.tCK = 1;\n\t\t//memSpec.memTimingSpec.tREFI = 1;\n\n\t\tmemSpec.memPowerSpec[0].vXX = 1;\n\t\tmemSpec.memPowerSpec[0].iXX0 = 64;\n\t\tmemSpec.memPowerSpec[0].iXX2N = 8;\n\t\tmemSpec.memPowerSpec[0].iXX2P = 6;\n\t\tmemSpec.memPowerSpec[0].iXX3N = 32;\n\t\tmemSpec.memPowerSpec[0].iXX3P = 20;\n\t\tmemSpec.memPowerSpec[0].iXX4R = 72;\n\t\tmemSpec.memPowerSpec[0].iXX4W = 72;\n\t\t//memSpec.memPowerSpec[0].iXX5C = 28;\n\t\t//memSpec.memPowerSpec[0].iXX5PB_B = 30;\n\n\t\tmemSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\n\t\tddr = std::make_unique<DDR4>(memSpec);\n\t}\n\n\tvirtual void TearDown()\n\t{\n\t}\n};\n\nTEST_F(DramPowerTest_Pre_Cycles, Test)\n{\n\tfor (const auto& command : testPattern) {\n\t\tddr->doCoreCommand(command);\n\t};\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 60);\n\tASSERT_EQ(stats.bank[1].cycles.act, 10);\n\n\t// Check per-bank PRE count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 30);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 80);\n\n\t// Check global cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 70);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 20);\n}\n\nTEST_F(DramPowerTest_Pre_Cycles, Test_Detailed)\n{\n\tSimulationStats window;\n\n\tauto iterate_to_timestamp = [this, command = testPattern.begin()](timestamp_t timestamp) mutable {\n\t\twhile (command != this->testPattern.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\n\t\treturn this->ddr->getWindowStats(timestamp);\n\t};\n\n\t// Cycle 5\n\twindow = iterate_to_timestamp(5);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 5);    ASSERT_EQ(window.rank_total[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[0].cycles.act, 5);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 5);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 10\n\twindow = iterate_to_timestamp(10);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 10);    ASSERT_EQ(window.rank_total[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[0].cycles.act, 10);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 10);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 30\n\twindow = iterate_to_timestamp(30);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 35\n\twindow = iterate_to_timestamp(35);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 5); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 40\n\twindow = iterate_to_timestamp(40);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR4/ddr4_multidevice_tests.cpp",
    "content": "/* Note\nThis test is based on ddr4_test_pattern_4.cpp and assumes the correctness of the test.\n\nCalculation for 5 devices:\nE_act: \t\t\t\t\t358.99038461538458\nE_pre: \t\t\t\t\t415.38461538461542\nE_bg_act:\t\t\t\t1703.6538461538462\nE_bg_act_shared:\t\t1690.3846153846155\nE_bg_pre:\t\t\t\t623.07692307692309\nE_RD:\t\t\t\t\t1307.0769230769231\nTotal:\t\t\t\t\t4408.1826923076924\n\nE_act * 5:\t\t\t\t1794.9519230769229\nE_bg_act_shared * 5:\t8451.9230769230775\nE_pre * 5:\t\t\t\t2076.9230769230771\nE_bg_act * 5:\t\t\t8518.269230769231\nE_bg_pre * 5:\t\t\t3115.38461538461545\nE_RD * 5:\t\t\t\t6535.3846153846155\nTotal * 5:\t\t\t\t22040.913461538462\n*/\n\n\n#include <gtest/gtest.h>\n\n#include <DRAMPower/command/Command.h>\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <memory>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR4_MultiDevice : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::RD,  { 3, 0, 0 }},\n            {   40, CmdType::RD,  { 0, 0, 0 }},\n            {   50, CmdType::PREA,  { 0, 0, 0 }},\n            { 70, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecDDR4> memSpec;\n    std::unique_ptr<DRAMPower::DDR4> ddr;\n    uint64_t numberOfDevices;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR4>(DRAMPower::MemSpecDDR4::from_memspec(*data));\n\n        memSpec->numberOfDevices = 5;\n\n        numberOfDevices = memSpec->numberOfDevices;\n        ddr = std::make_unique<DDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR4_MultiDevice, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].counter.reads, 2);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    };\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 50);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 20);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 50);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 30);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 0);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 20);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 40);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 70);\n    }\n}\n\nTEST_F(DramPowerTest_DDR4_MultiDevice, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(energy.bank_energy.size(), numberOfDevices * memSpec->numberOfBanks);\n\n    // Validate every device has the same bank energy\n    for(size_t i = 0; i < numberOfDevices; i++){\n        for(size_t j = 0; j < memSpec->numberOfBanks; j++){\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_act, energy.bank_energy[j].E_act);\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_pre, energy.bank_energy[j].E_pre);\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_RD, energy.bank_energy[j].E_RD);\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_bg_act, energy.bank_energy[j].E_bg_act);\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_bg_pre, energy.bank_energy[j].E_bg_pre);\n        }\n    }\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 1795);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 2077);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 6535);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 8518);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 8452);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 3115);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 22041);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR4/ddr4_multirank_tests.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <fstream>\n#include <memory>\n\n#include \"DRAMPower/command/Command.h\"\n#include \"DRAMPower/standards/ddr4/DDR4.h\"\n#include \"DRAMPower/memspec/MemSpecDDR4.h\"\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR4.h>\n#include <variant>\n\nusing DRAMPower::CmdType;\nusing DRAMPower::Command;\nusing DRAMPower::DDR4;\nusing DRAMPower::MemSpecDDR4;\nusing DRAMPower::SimulationStats;\n\n#define SZ_BITS(x) sizeof(x)*8\n\nstatic constexpr uint8_t wr_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 255\n};\n\nstatic constexpr uint8_t rd_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 1\n};\n\nclass DDR4_MultirankTests : public ::testing::Test {\n  public:\n    virtual void SetUp() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        spec = std::make_unique<DRAMPower::MemSpecDDR4>(DRAMPower::MemSpecDDR4::from_memspec(*data));\n\n        spec->numberOfRanks = 2;\n        ddr = std::make_unique<DDR4>(*spec);\n    }\n\n    void runCommands(const std::vector<Command> &commands) {\n        for (const Command &command : commands) {\n            ddr->doCoreCommand(command);\n            ddr->doInterfaceCommand(command);\n        }\n    }\n\n    inline size_t bankIndex(int bank, int rank) {\n        return rank * spec->numberOfBanks + bank;\n    }\n\n    std::unique_ptr<MemSpecDDR4> spec;\n    std::unique_ptr<DDR4> ddr;\n};\n\nTEST_F(DDR4_MultirankTests, Pattern_1) {\n    runCommands({\n        {0, CmdType::ACT, {1, 0, 0}},\n        {2, CmdType::ACT, {1, 0, 1}},  // rank 1\n        {4, CmdType::WR, {1, 0, 0, 0, 4}, wr_data, SZ_BITS(wr_data)},\n        {6, CmdType::RD, {1, 0, 1, 0, 4}, rd_data, SZ_BITS(rd_data)},  // rank 1\n        {10, CmdType::PRE, {1, 0, 1}},  // rank 1\n        {15, CmdType::PRE, {1, 0, 0}},\n        {20, CmdType::END_OF_SIMULATION}\n    });\n\n    SimulationStats stats = ddr->getStats();\n    EXPECT_EQ(stats.bank.size(), spec->numberOfBanks * spec->numberOfRanks);\n    EXPECT_EQ(stats.bank[bankIndex(1, 0)].cycles.act, 15);\n    EXPECT_EQ(stats.bank[bankIndex(1, 1)].cycles.act, 8);\n    EXPECT_EQ(stats.bank[bankIndex(1, 0)].cycles.pre, 5);\n    EXPECT_EQ(stats.bank[bankIndex(1, 1)].cycles.pre, 12);\n\n    EXPECT_EQ(stats.rank_total[0].cycles.act, 15);\n    EXPECT_EQ(stats.rank_total[1].cycles.act, 8);\n}\n\nTEST_F(DDR4_MultirankTests, Pattern_2) {\n    // TODO error no read data\n    runCommands({\n        {0, CmdType::ACT, {0, 0, 0}},\n        {5, CmdType::ACT, {0, 0, 1}},  // r1\n        {15, CmdType::RDA, {0, 0, 0}, rd_data, SZ_BITS(rd_data)},\n        {20, CmdType::ACT, {3, 0, 1}},  // r1\n        {35, CmdType::RD, {3, 0, 1}, rd_data, SZ_BITS(rd_data)},  // r1\n        {40, CmdType::RD, {0, 0, 0}, rd_data, SZ_BITS(rd_data)},\n        {50, CmdType::PREA, {0, 0, 0}},\n        {55, CmdType::PREA, {0, 0, 1}},  // r1\n        {65, CmdType::REFA, {0, 0, 0}},\n        {70, CmdType::REFA, {0, 0, 1}},  // r1\n        {100, CmdType::END_OF_SIMULATION},\n    });\n\n    SimulationStats stats = ddr->getStats();\n    EXPECT_EQ(stats.bank.size(), spec->numberOfBanks * spec->numberOfRanks);\n    EXPECT_EQ(stats.bank[bankIndex(0, 0)].cycles.act, 45);\n    EXPECT_EQ(stats.bank[bankIndex(0, 1)].cycles.act, 75);\n    EXPECT_EQ(stats.bank[bankIndex(3, 1)].cycles.act, 60);\n\n    EXPECT_EQ(stats.bank[bankIndex(0, 0)].cycles.pre, 55);\n    EXPECT_EQ(stats.bank[bankIndex(0, 1)].cycles.pre, 25);\n    EXPECT_EQ(stats.bank[bankIndex(3, 1)].cycles.pre, 40);\n\n    EXPECT_EQ(stats.rank_total[0].cycles.act, 45);\n    EXPECT_EQ(stats.rank_total[1].cycles.act, 75);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR4/ddr4_test_pattern_0.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <memory>\n\n#include <fstream>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR4_0 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::PRE,  { 0, 0, 0 }},\n            { 15, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR4> ddr;\n    std::unique_ptr<DRAMPower::MemSpecDDR4> memSpec;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR4>(DRAMPower::MemSpecDDR4::from_memspec(*data));\n        ddr = std::make_unique<DDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR4_0, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n        ddr->doInterfaceCommand(command);\n        //TODO remove\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    ASSERT_EQ(stats.bank[0].counter.act, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].counter.act, 0);\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 15);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 0);\n\n    // Check bank specific ACT cycle count\n    ASSERT_EQ(stats.bank[0].cycles.act, 15);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.act, 0);\n\n    // Check bank specific PRE cycle count\n    ASSERT_EQ(stats.bank[0].cycles.pre, 0);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.pre, 15);\n}\n\nTEST_F(DramPowerTest_DDR4_0, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 179);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 208);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 510);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 507);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 897);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR4/ddr4_test_pattern_1.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <memory>\n\n#include <fstream>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR4_1 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   35, CmdType::PRE,  { 0, 0, 0 }},\n            { 35, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR4> ddr;\n    std::unique_ptr<DRAMPower::MemSpecDDR4> memSpec;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR4>(DRAMPower::MemSpecDDR4::from_memspec(*data));\n        ddr = std::make_unique<DDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR4_1, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    ASSERT_EQ(stats.bank[0].counter.act, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.act, 0);\n\n    // Check bank command count: RD\n    ASSERT_EQ(stats.bank[0].counter.reads, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.reads, 0);\n\n    // Check bank command count: PRE\n    ASSERT_EQ(stats.bank[0].counter.pre, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.pre, 0);\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 35);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 0);\n\n    // Check bank specific ACT cycle count\n    ASSERT_EQ(stats.bank[0].cycles.act, 35);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.act, 0);\n\n    // Check bank specific PRE cycle count\n    ASSERT_EQ(stats.bank[0].cycles.pre, 0);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.pre, 35);\n}\n\nTEST_F(DramPowerTest_DDR4_1, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 179);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 208);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 436);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1189);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1183);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 2012);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR4/ddr4_test_pattern_10.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <DRAMPower/command/Command.h>\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n#include <DRAMPower/standards/test_accessor.h>\n\n#include <memory>\n\n#include <iostream>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR4_10 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n    // Timestamp,   Cmd,  { Bank, BG, Rank}\n        {   0, CmdType::ACT, { 0, 0, 0 } },\n        {  10, CmdType::ACT, { 1, 0, 0 } },\n        {  15, CmdType::PRE, { 0, 0, 0 } },\n        {  25, CmdType::ACT, { 3, 0, 0 } },\n        {  25, CmdType::PRE, { 1, 0, 0 } },\n        {  30, CmdType::ACT, { 0, 0, 0 } },\n        {  35, CmdType::ACT, { 2, 0, 0 } },\n        {  40, CmdType::PRE, { 1, 0, 0 } },\n        {  40, CmdType::PRE, { 3, 0, 0 } },\n        {  45, CmdType::PRE, { 0, 0, 0 } },\n        {  50, CmdType::PRE, { 2, 0, 0 } },\n        {  85, CmdType::ACT, { 7, 0, 0 } },\n        { 100, CmdType::PRE, { 7, 0, 0 } },\n        { 120, CmdType::ACT, { 6, 0, 0 } },\n        { 125, CmdType::END_OF_SIMULATION},\n    };\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR4> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        auto memSpec = DRAMPower::MemSpecDDR4::from_memspec(*data);\n\n        memSpec.numberOfRanks = 1;\n\t\tmemSpec.numberOfDevices = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.numberOfBankGroups = 1;\n        memSpec.burstLength = 8;\n        memSpec.dataRate = 2;\n\n        memSpec.memTimingSpec.tCK = 1;\n        memSpec.memTimingSpec.tRAS = 10;\n\t\tmemSpec.memTimingSpec.tRP = 10;\n\n\t\tmemSpec.memPowerSpec[0].vXX = 1;\n\t\tmemSpec.memPowerSpec[0].iXX0 = 64;\n\t\tmemSpec.memPowerSpec[0].iXX2N = 8;\n\t\tmemSpec.memPowerSpec[0].iXX3N = 32;\n\t\tmemSpec.memPowerSpec[0].iXX4R = 0;\n\t\tmemSpec.memPowerSpec[0].iXX4W = 0;\n\t\tmemSpec.memPowerSpec[0].iXX5X = 0;\n\t\tmemSpec.memPowerSpec[0].iXX6N = 0;\n\t\tmemSpec.memPowerSpec[0].iXX2P = 0;\n\t\tmemSpec.memPowerSpec[0].iXX3P = 0;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iXX0;\n\t\tmemSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n\n        ddr = std::make_unique<DDR4>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR4_10, Pattern1)\n{\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\t// Inspect first rank\n\tconst auto & rank_1 = internal::DDR4TestAccessor.getRanks(ddr->getCore()).at(0);\n\tauto stats = ddr->getStats();\n\n\t// Check global count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 70);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 55);\n\n\t// Check per-bank ACT count\n\tASSERT_EQ(stats.bank[0].cycles.act, 30);\n\n\tASSERT_EQ(stats.bank[1].cycles.act, 15);\n\tASSERT_EQ(stats.bank[2].cycles.act, 15);\n\tASSERT_EQ(stats.bank[3].cycles.act, 15);\n\tASSERT_EQ(stats.bank[7].cycles.act, 15);\n\n\tASSERT_EQ(stats.bank[6].cycles.act, 5);\n\n\tASSERT_EQ(stats.bank[4].cycles.act, 0);\n\tASSERT_EQ(stats.bank[5].cycles.act, 0);\n\n\t// Check per-bank PRE count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 95);\n\n\tASSERT_EQ(stats.bank[1].cycles.pre, 110);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 110);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 110);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 110);\n\n\tASSERT_EQ(stats.bank[6].cycles.pre, 120);\n\n\tASSERT_EQ(stats.bank[4].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 125);\n\n\t// Check global command count\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::ACT), 7);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::PRE), 7);\n\n\t// per-bank ACT command count\n\tASSERT_EQ(stats.bank[0].counter.act, 2);\n\n\tASSERT_EQ(stats.bank[1].counter.act, 1);\n\tASSERT_EQ(stats.bank[2].counter.act, 1);\n\tASSERT_EQ(stats.bank[3].counter.act, 1);\n\tASSERT_EQ(stats.bank[6].counter.act, 1);\n\tASSERT_EQ(stats.bank[7].counter.act, 1);\n\n\tASSERT_EQ(stats.bank[4].counter.act, 0);\n\tASSERT_EQ(stats.bank[5].counter.act, 0);\n\n\t// per-bank PRE command count\n\tASSERT_EQ(stats.bank[0].counter.pre, 2);\n\n\tASSERT_EQ(stats.bank[1].counter.pre, 1);\n\tASSERT_EQ(stats.bank[2].counter.pre, 1);\n\tASSERT_EQ(stats.bank[3].counter.pre, 1);\n\tASSERT_EQ(stats.bank[7].counter.pre, 1);\n\n\tASSERT_EQ(stats.bank[6].counter.pre, 0);\n\tASSERT_EQ(stats.bank[4].counter.pre, 0);\n\tASSERT_EQ(stats.bank[5].counter.pre, 0);\n}\n\nTEST_F(DramPowerTest_DDR4_10, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n    auto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ((int)total_energy.E_act, 3220);\n\tASSERT_EQ((int)energy.bank_energy[0].E_act, 920);\n\tASSERT_EQ((int)energy.bank_energy[1].E_act, 460);\n\tASSERT_EQ((int)energy.bank_energy[2].E_act, 460);\n\tASSERT_EQ((int)energy.bank_energy[3].E_act, 460);\n\tASSERT_EQ((int)energy.bank_energy[4].E_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_act, 460);\n\tASSERT_EQ((int)energy.bank_energy[7].E_act, 460);\n\n\tASSERT_EQ((int)total_energy.E_pre, 3360);\n\tASSERT_EQ((int)energy.bank_energy[0].E_pre, 1120);\n\tASSERT_EQ((int)energy.bank_energy[1].E_pre, 560);\n\tASSERT_EQ((int)energy.bank_energy[2].E_pre, 560);\n\tASSERT_EQ((int)energy.bank_energy[3].E_pre, 560);\n\tASSERT_EQ((int)energy.bank_energy[4].E_pre, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_pre, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_pre, 0);\n\tASSERT_EQ((int)energy.bank_energy[7].E_pre, 560);\n\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_act, 60);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_act, 30);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_act, 30);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_act, 30);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_act, 10);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_act, 30);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared), 1120);\n\tASSERT_EQ(std::round(total_energy.E_bg_act), 1310);\n\n\tASSERT_EQ((int)total_energy.E_bg_pre, 440);\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_pre, 55);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR4/ddr4_test_pattern_11.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <DRAMPower/command/Command.h>\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n#include <DRAMPower/standards/test_accessor.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR4_11 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{   0, CmdType::ACT, { 0, 0, 0} },\n\t\t{   5, CmdType::ACT, { 1, 0, 0} },\n\t\t{  10, CmdType::ACT, { 2, 0, 0} },\n\t\t{  15, CmdType::ACT, { 3, 0, 0} },\n\t\t{  20, CmdType::ACT, { 4, 0, 0} },\n\t\t{  25, CmdType::ACT, { 5, 0, 0} },\n\t\t{  30, CmdType::ACT, { 6, 0, 0} },\n\t\t{  35, CmdType::ACT, { 7, 0, 0} },\n\t\t{  35, CmdType::RD,  { 0, 0, 0} },\n\t\t{  40, CmdType::RD,  { 0, 0, 0} },\n\t\t{  40, CmdType::RD,  { 1, 0, 0} },\n\t\t{  45, CmdType::RD,  { 0, 0, 0} },\n\t\t{  45, CmdType::RD,  { 2, 0, 0} },\n\t\t{  50, CmdType::RD,  { 3, 0, 0} },\n\t\t{  55, CmdType::RD,  { 4, 0, 0} },\n\t\t{  60, CmdType::RD,  { 5, 0, 0} },\n\t\t{  65, CmdType::RD,  { 6, 0, 0} },\n\t\t{  70, CmdType::RD,  { 7, 0, 0} },\n\t\t{  75, CmdType::RD,  { 7, 0, 0} },\n\t\t{  80, CmdType::RD,  { 7, 0, 0} },\n\t\t{  85, CmdType::WR,  { 7, 0, 0} },\n\t\t{  90, CmdType::WR,  { 6, 0, 0} },\n\t\t{  95, CmdType::WR,  { 5, 0, 0} },\n\t\t{ 100, CmdType::WR,  { 4, 0, 0} },\n\t\t{ 105, CmdType::WR,  { 3, 0, 0} },\n\t\t{ 110, CmdType::WR,  { 2, 0, 0} },\n\t\t{ 110, CmdType::WR,  { 0, 0, 0} },\n\t\t{ 115, CmdType::WR,  { 1, 0, 0} },\n\t\t{ 115, CmdType::RD,  { 0, 0, 0} },\n\t\t{ 120, CmdType::WR,  { 0, 0, 0} },\n\t\t{ 120, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR4> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        auto memSpec = DRAMPower::MemSpecDDR4::from_memspec(*data);\n\n\t\tmemSpec.numberOfRanks = 1;\n\t\tmemSpec.numberOfDevices = 1;\n        memSpec.numberOfBanks = 8;\n\t\tmemSpec.numberOfBankGroups = 1;\n\n\t\tmemSpec.memTimingSpec.tCK = 1;\n\n\t\tmemSpec.memPowerSpec[0].vXX = 1;\n\t\tmemSpec.memPowerSpec[0].iXX0 = 64;\n\t\tmemSpec.memPowerSpec[0].iXX3N = 32;\n\t\tmemSpec.memPowerSpec[0].iXX4R = 72;\n\t\tmemSpec.memPowerSpec[0].iXX4W = 96;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iXX0;\n\n\n        memSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\n        ddr = std::make_unique<DDR4>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR4_11, Pattern_2)\n{\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\t// Inspect first rank\n\tconst Rank & rank_1 = internal::DDR4TestAccessor.getRanks(ddr->getCore()).at(0);\n\n\t// Check global command count\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::RD), 13);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::WR), 9);\n\n\t// Check bank RD command count\n\tASSERT_EQ(rank_1.banks[0].counter.reads, 4);\n\tASSERT_EQ(rank_1.banks[1].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[2].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[3].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[4].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[5].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[6].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[7].counter.reads, 3);\n\n\t// Check bank WR command count\n\tASSERT_EQ(rank_1.banks[0].counter.writes, 2);\n\tASSERT_EQ(rank_1.banks[1].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[2].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[3].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[4].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[5].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[6].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[7].counter.writes, 1);\n}\n\nTEST_F(DramPowerTest_DDR4_11, CalcEnergy)\n{\n    auto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ((int)total_energy.E_RD, 4160);\n\tASSERT_EQ((int)energy.bank_energy[0].E_RD, 1280);\n\tASSERT_EQ((int)energy.bank_energy[1].E_RD, 320);\n\tASSERT_EQ((int)energy.bank_energy[2].E_RD, 320);\n\tASSERT_EQ((int)energy.bank_energy[3].E_RD, 320);\n\tASSERT_EQ((int)energy.bank_energy[4].E_RD, 320);\n\tASSERT_EQ((int)energy.bank_energy[5].E_RD, 320);\n\tASSERT_EQ((int)energy.bank_energy[6].E_RD, 320);\n\tASSERT_EQ((int)energy.bank_energy[7].E_RD, 960);\n\n\tASSERT_EQ((int)total_energy.E_WR, 4608);\n\tASSERT_EQ((int)energy.bank_energy[0].E_WR, 1024);\n\tASSERT_EQ((int)energy.bank_energy[1].E_WR, 512);\n\tASSERT_EQ((int)energy.bank_energy[2].E_WR, 512);\n\tASSERT_EQ((int)energy.bank_energy[3].E_WR, 512);\n\tASSERT_EQ((int)energy.bank_energy[4].E_WR, 512);\n\tASSERT_EQ((int)energy.bank_energy[5].E_WR, 512);\n\tASSERT_EQ((int)energy.bank_energy[6].E_WR, 512);\n\tASSERT_EQ((int)energy.bank_energy[7].E_WR, 512);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR4/ddr4_test_pattern_12.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <DRAMPower/command/Command.h>\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n#include <DRAMPower/standards/test_accessor.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR4_12 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t// Timestamp,   Cmd,  { Bank, BG, Rank}\n\t\t{   0, CmdType::ACT, { 0, 0, 0 }  },\n\t\t{  10, CmdType::RDA, { 0, 0, 0 }  },\n\t\t{  15, CmdType::ACT, { 1, 0, 0 }  },\n\t\t{  15, CmdType::ACT, { 2, 0, 0 }  },\n\t\t{  25, CmdType::WRA, { 1, 0, 0 }  },\n\t\t{  30, CmdType::PRE, { 0, 0, 0 }  },\n\t\t{  35, CmdType::RDA, { 2, 0, 0 }  },\n\t\t{  50, CmdType::ACT, { 0, 0, 0 }  },\n\t\t{  50, CmdType::ACT, { 2, 0, 0 }  },\n\t\t{  60, CmdType::WRA, { 0, 0, 0 }  },\n\t\t{  60, CmdType::RDA, { 2, 0, 0 }  },\n\t\t{  75, CmdType::ACT, { 1, 0, 0 }  },\n\t\t{  80, CmdType::ACT, { 0, 0, 0 }  },\n\t\t{  85, CmdType::WRA, { 0, 0, 0 }  },\n\t\t{  95, CmdType::RDA, { 1, 0, 0 }  },\n\t\t{ 125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR4> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        auto memSpec = DRAMPower::MemSpecDDR4::from_memspec(*data);\n\n\t\tmemSpec.bitWidth = 16;\n\t\t\n\t\tmemSpec.numberOfRanks = 1;\n\t\tmemSpec.numberOfDevices = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.numberOfBankGroups = 1;\n\n        memSpec.memTimingSpec.tAL = 0;\n\t\tmemSpec.memTimingSpec.tRAS = 20;\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n\t\tmemSpec.memTimingSpec.tWR = 12;\n\t\tmemSpec.memTimingSpec.tWL = 0;\n\t\tmemSpec.memTimingSpec.tCK = 1;\n\t\tmemSpec.memTimingSpec.tRP = 10;\n\n\t\tmemSpec.memPowerSpec[0].vXX = 1;\n\t\tmemSpec.memPowerSpec[0].iXX0 = 64;\n\t\tmemSpec.memPowerSpec[0].iXX2N = 8;\n\t\tmemSpec.memPowerSpec[0].iXX3N = 32;\n\t\tmemSpec.memPowerSpec[0].iXX4R = 72;\n\t\tmemSpec.memPowerSpec[0].iXX4W = 96;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iXX0;\n\t\tmemSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\n        memSpec.memTimingSpec.tBurst = memSpec.burstLength/memSpec.dataRate;\n        memSpec.prechargeOffsetRD    =  memSpec.memTimingSpec.tAL + memSpec.memTimingSpec.tRTP;\n        memSpec.prechargeOffsetWR    =  memSpec.memTimingSpec.tBurst + memSpec.memTimingSpec.tWL + memSpec.memTimingSpec.tWR;\n\n        ddr = std::make_unique<DDR4>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR4_12, Test)\n{\n\tfor (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\tconst Rank & rank_1 = internal::DDR4TestAccessor.getRanks(ddr->getCore()).at(0);\n\tauto stats = ddr->getStats();\n\n\t// Check global command count\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::ACT), 7);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::PRE), 1);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::RDA), 4);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::WRA), 3);\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 3);\n\tASSERT_EQ(stats.bank[1].counter.act, 2);\n\tASSERT_EQ(stats.bank[2].counter.act, 2);\n\tASSERT_EQ(stats.bank[3].counter.act, 0);\n\tASSERT_EQ(stats.bank[4].counter.act, 0);\n\tASSERT_EQ(stats.bank[5].counter.act, 0);\n\tASSERT_EQ(stats.bank[6].counter.act, 0);\n\tASSERT_EQ(stats.bank[7].counter.act, 0);\n\n\t// Check bank command count: RDA\n\tASSERT_EQ(stats.bank[0].counter.readAuto, 1);\n\tASSERT_EQ(stats.bank[1].counter.readAuto, 1);\n\tASSERT_EQ(stats.bank[2].counter.readAuto, 2);\n\tASSERT_EQ(stats.bank[3].counter.readAuto, 0);\n\tASSERT_EQ(stats.bank[4].counter.readAuto, 0);\n\tASSERT_EQ(stats.bank[5].counter.readAuto, 0);\n\tASSERT_EQ(stats.bank[6].counter.readAuto, 0);\n\tASSERT_EQ(stats.bank[7].counter.readAuto, 0);\n\n\t// Check bank command count: WRA\n\tASSERT_EQ(stats.bank[0].counter.writeAuto, 2);\n\tASSERT_EQ(stats.bank[1].counter.writeAuto, 1);\n\tASSERT_EQ(stats.bank[2].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[3].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[4].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[5].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[6].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[7].counter.writeAuto, 0);\n\n\t// Check cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 100);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 25);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 75);\n\tASSERT_EQ(stats.bank[1].cycles.act, 60);\n\tASSERT_EQ(stats.bank[2].cycles.act, 50);\n\tASSERT_EQ(stats.bank[3].cycles.act, 0);\n\tASSERT_EQ(stats.bank[4].cycles.act, 0);\n\tASSERT_EQ(stats.bank[5].cycles.act, 0);\n\tASSERT_EQ(stats.bank[6].cycles.act, 0);\n\tASSERT_EQ(stats.bank[7].cycles.act, 0);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 50);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 65);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 75);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[6].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 125);\n}\n\nTEST_F(DramPowerTest_DDR4_12, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ(std::round(total_energy.E_bg_act), 1970);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared), 1600);\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_act, 150);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_act, 120);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_act, 100);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_act, 0);\n\n\tASSERT_EQ((int)total_energy.E_bg_pre, 200);\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_pre, 25);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_pre, 25);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_pre, 25);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_pre, 25);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_pre, 25);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_pre, 25);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_pre, 25);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_pre, 25);\n\n\tASSERT_EQ((int)total_energy.E_RDA, 1280);\n\tASSERT_EQ((int)energy.bank_energy[0].E_RDA, 320);\n\tASSERT_EQ((int)energy.bank_energy[1].E_RDA, 320);\n\tASSERT_EQ((int)energy.bank_energy[2].E_RDA, 640);\n\tASSERT_EQ((int)energy.bank_energy[3].E_RDA, 0);\n\tASSERT_EQ((int)energy.bank_energy[4].E_RDA, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_RDA, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_RDA, 0);\n\tASSERT_EQ((int)energy.bank_energy[7].E_RDA, 0);\n\n\tASSERT_EQ((int)total_energy.E_WRA, 1536);\n\tASSERT_EQ((int)energy.bank_energy[0].E_WRA, 1024);\n\tASSERT_EQ((int)energy.bank_energy[1].E_WRA, 512);\n\tASSERT_EQ((int)energy.bank_energy[2].E_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[3].E_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[4].E_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[7].E_WRA, 0);\n\n\tASSERT_EQ((int)total_energy.E_pre_RDA, 2240);\n\tASSERT_EQ((int)energy.bank_energy[0].E_pre_RDA, 560);\n\tASSERT_EQ((int)energy.bank_energy[1].E_pre_RDA, 560);\n\tASSERT_EQ((int)energy.bank_energy[2].E_pre_RDA, 1120);\n\tASSERT_EQ((int)energy.bank_energy[3].E_pre_RDA, 0);\n\tASSERT_EQ((int)energy.bank_energy[4].E_pre_RDA, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_pre_RDA, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_pre_RDA, 0);\n\tASSERT_EQ((int)energy.bank_energy[7].E_pre_RDA, 0);\n\n\tASSERT_EQ((int)total_energy.E_pre_WRA, 1120+560);\n\tASSERT_EQ((int)energy.bank_energy[0].E_pre_WRA, 1120);\n\tASSERT_EQ((int)energy.bank_energy[1].E_pre_WRA, 560);\n\tASSERT_EQ((int)energy.bank_energy[2].E_pre_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[3].E_pre_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[4].E_pre_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_pre_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_pre_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[7].E_pre_WRA, 0);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR4/ddr4_test_pattern_13.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <DRAMPower/command/Command.h>\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR4_13 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{   0, CmdType::ACT,  { 0, 0, 0 }},\n\t\t{   5, CmdType::ACT,  { 1, 0, 0 }},\n\t\t{  10, CmdType::ACT,  { 2, 0, 0 }},\n\t\t{  15, CmdType::PRE,  { 0, 0, 0 }},\n\t\t{  20, CmdType::PREA, { 0, 0, 0 }},\n\t\t{  25, CmdType::PRE,  { 1, 0, 0 }},\n\t\t{  30, CmdType::PREA, { 0, 0, 0 }},\n\t\t{  40, CmdType::ACT,  { 0, 0, 0 }},\n\t\t{  40, CmdType::ACT,  { 3, 0, 0 }},\n\t\t{  50, CmdType::PRE,  { 3, 0, 0 }},\n\t\t{ 125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR4> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        auto memSpec = DRAMPower::MemSpecDDR4::from_memspec(*data);\n\n\t\tmemSpec.numberOfRanks = 1;\n\t\tmemSpec.numberOfDevices = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.numberOfBankGroups = 1;\n\n\t\tmemSpec.memTimingSpec.tRAS = 20;\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n\t\tmemSpec.memTimingSpec.tWR = 20;\n\n\t\tmemSpec.memTimingSpec.tRAS = 20;\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n\t\tmemSpec.memTimingSpec.tWR = 12;\n\t\tmemSpec.memTimingSpec.tWL = 0;\n\t\tmemSpec.memTimingSpec.tCK = 1;\n\t\tmemSpec.memTimingSpec.tRP = 10;\n\n\t\tmemSpec.memPowerSpec[0].vXX = 1;\n\t\tmemSpec.memPowerSpec[0].iXX0 = 64;\n\t\tmemSpec.memPowerSpec[0].iXX2N = 8;\n\t\tmemSpec.memPowerSpec[0].iXX3N = 32;\n\t\tmemSpec.memPowerSpec[0].iXX4R = 72;\n\t\tmemSpec.memPowerSpec[0].iXX4W = 72;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iXX0;\n\n\t\tmemSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\n        ddr = std::make_unique<DDR4>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR4_13, Test)\n{\n\tfor (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 2);\n\tASSERT_EQ(stats.bank[1].counter.act, 1);\n\tASSERT_EQ(stats.bank[2].counter.act, 1);\n\tASSERT_EQ(stats.bank[3].counter.act, 1);\n\tASSERT_EQ(stats.bank[4].counter.act, 0);\n\n\t// Check cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 105);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 20);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 100);\n\tASSERT_EQ(stats.bank[1].cycles.act, 15);\n\tASSERT_EQ(stats.bank[2].cycles.act, 10);\n\tASSERT_EQ(stats.bank[3].cycles.act, 10);\n\tASSERT_EQ(stats.bank[4].cycles.act, 0);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 25);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 110);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 115);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 115);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 125);\n}\n\nTEST_F(DramPowerTest_DDR4_13, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ((int)total_energy.E_act, 2300*2);\n\tASSERT_EQ((int)energy.bank_energy[0].E_act, 920*2);\n\tASSERT_EQ((int)energy.bank_energy[1].E_act, 460*2);\n\tASSERT_EQ((int)energy.bank_energy[2].E_act, 460*2);\n\tASSERT_EQ((int)energy.bank_energy[3].E_act, 460*2);\n\tASSERT_EQ((int)energy.bank_energy[4].E_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[7].E_act, 0);\n\n\tASSERT_EQ((int)total_energy.E_pre, 2240);\n\tASSERT_EQ((int)energy.bank_energy[0].E_pre, 560);\n\tASSERT_EQ((int)energy.bank_energy[1].E_pre, 560);\n\tASSERT_EQ((int)energy.bank_energy[2].E_pre, 560);\n\tASSERT_EQ((int)energy.bank_energy[3].E_pre, 560);\n\tASSERT_EQ((int)energy.bank_energy[4].E_pre, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_pre, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_pre, 0);\n\tASSERT_EQ((int)energy.bank_energy[7].E_pre, 0);\n\n\tASSERT_EQ(std::round(total_energy.E_bg_act), 1950);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared), 1680);\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_act, 200);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_act, 30);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_act, 20);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_act, 20);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_act, 0);\n\n\tASSERT_EQ((int)total_energy.E_bg_pre, 160);\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_pre, 20);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_pre, 20);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_pre, 20);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_pre, 20);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_pre, 20);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_pre, 20);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_pre, 20);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_pre, 20);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR4/ddr4_test_pattern_14.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <DRAMPower/command/Command.h>\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR4_14 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{  0,  CmdType::ACT, {0, 0, 0} },\n\t\t{ 20,  CmdType::PDEA },\n\t\t{ 30,  CmdType::PDXA },\n\t\t{ 40,  CmdType::PRE, {0, 0, 0} },\n\t\t{ 60,  CmdType::PDEP },\n\t\t{ 65,  CmdType::PDXP },\n\t\t{ 75,  CmdType::REFA },\n\t\t{100,  CmdType::PDEP },\n\t\t{125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR4> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        auto memSpec = DRAMPower::MemSpecDDR4::from_memspec(*data);\n\n\t\tmemSpec.numberOfRanks = 1;\n\t\tmemSpec.numberOfDevices = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.numberOfBankGroups = 2;\n\n\t\tmemSpec.memTimingSpec.tRAS = 10;\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n\t\tmemSpec.memTimingSpec.tRCD = 20;\n\t\tmemSpec.memTimingSpec.tRFC = 25;\n\n\t\tmemSpec.memTimingSpec.tWR = 20;\n\t\tmemSpec.memTimingSpec.tRP = 20;\n\t\tmemSpec.memTimingSpec.tWL = 0;\n\t\tmemSpec.memTimingSpec.tCK = 1;\n\n\t\tmemSpec.memPowerSpec[0].vXX = 1;\n\t\tmemSpec.memPowerSpec[0].iXX0 = 64;\n\t\tmemSpec.memPowerSpec[0].iXX2N = 8;\n\t\tmemSpec.memPowerSpec[0].iXX2P = 6;\n\t\tmemSpec.memPowerSpec[0].iXX3N = 32;\n\t\tmemSpec.memPowerSpec[0].iXX3P = 20;\n\t\tmemSpec.memPowerSpec[0].iXX4R = 72;\n\t\tmemSpec.memPowerSpec[0].iXX4W = 72;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iXX0;\n\n\n        memSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\n        ddr = std::make_unique<DDR4>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR4_14, Test)\n{\n\tfor (const auto& command : testPattern) {\n\t\tddr->doCoreCommand(command);\n\t};\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 1);\n\n\t// Check bank command count: PRE\n\tASSERT_EQ(stats.bank[0].counter.pre, 1);\n\n\t// Check global cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.activeTime(), 55);\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 55);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 30);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 55); ASSERT_EQ(stats.bank[0].cycles.activeTime(), 55);\n\tASSERT_EQ(stats.bank[1].cycles.act, 25); ASSERT_EQ(stats.bank[1].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[2].cycles.act, 25); ASSERT_EQ(stats.bank[2].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[3].cycles.act, 25); ASSERT_EQ(stats.bank[3].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[4].cycles.act, 25); ASSERT_EQ(stats.bank[4].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[5].cycles.act, 25); ASSERT_EQ(stats.bank[5].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[6].cycles.act, 25); ASSERT_EQ(stats.bank[6].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[7].cycles.act, 25); ASSERT_EQ(stats.bank[7].cycles.activeTime(), 25);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 30);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[6].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 60);\n}\n\nTEST_F(DramPowerTest_DDR4_14, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ(std::round(total_energy.E_bg_act), 1340);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared), 880);\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_act, 110);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_act, 50);\n\n\tASSERT_EQ((int)total_energy.E_bg_pre, 240);\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_pre, 30);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_pre, 30);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_pre, 30);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_pre, 30);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_pre, 30);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_pre, 30);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_pre, 30);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_pre, 30);\n\n\tASSERT_EQ((int)energy.E_PDNA, 200);\n\tASSERT_EQ((int)energy.E_PDNP, 180);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR4/ddr4_test_pattern_15.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR4_15 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{  0,  CmdType::ACT, { 0,0,0} },\n\t\t{  5,  CmdType::PDEA },\n\t\t{ 30,  CmdType::PDXA },\n\t\t{ 40,  CmdType::PRE, {0,0,0} },\n\t\t{ 45,  CmdType::PDEP },\n\t\t{ 65,  CmdType::PDXP },\n\t\t{ 75,  CmdType::REFA },\n\t\t{ 85,  CmdType::PDEP },\n\t\t{ 90,  CmdType::PDXP },\n\t\t{125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR4> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        auto memSpec = DRAMPower::MemSpecDDR4::from_memspec(*data);\n\n\t\tmemSpec.bitWidth = 16;\n\n\t\tmemSpec.numberOfRanks = 1;\n\t\tmemSpec.numberOfDevices = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.numberOfBankGroups = 2;\n\n\t\tmemSpec.memTimingSpec.tRAS = 10;\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n\t\tmemSpec.memTimingSpec.tRCD = 20;\n\t\tmemSpec.memTimingSpec.tRFC = 25;\n\n\t\tmemSpec.memTimingSpec.tWR = 20;\n\t\tmemSpec.memTimingSpec.tRP = 20;\n\t\tmemSpec.memTimingSpec.tWL = 0;\n\t\tmemSpec.memTimingSpec.tCK = 1;\n\n\t\tmemSpec.memPowerSpec[0].vXX = 1;\n\t\tmemSpec.memPowerSpec[0].iXX0 = 64;\n\t\tmemSpec.memPowerSpec[0].iXX2N = 8;\n\t\tmemSpec.memPowerSpec[0].iXX2P = 6;\n\t\tmemSpec.memPowerSpec[0].iXX3N = 32;\n\t\tmemSpec.memPowerSpec[0].iXX3P = 20;\n\t\tmemSpec.memPowerSpec[0].iXX4R = 72;\n\t\tmemSpec.memPowerSpec[0].iXX4W = 72;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iXX0;\n\n\t\tmemSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\n        ddr = std::make_unique<DDR4>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR4_15, Test)\n{\n\tfor (const auto& command : testPattern) {\n\t\tddr->doCoreCommand(command);\n\t};\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 1);\n\n\t// Check bank command count: PRE\n\tASSERT_EQ(stats.bank[0].counter.pre, 1);\n\n\t// Check global cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 55);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 55);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 5);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 55);\n\tASSERT_EQ(stats.bank[1].cycles.act, 25);\n\tASSERT_EQ(stats.bank[2].cycles.act, 25);\n\tASSERT_EQ(stats.bank[3].cycles.act, 25);\n\tASSERT_EQ(stats.bank[4].cycles.act, 25);\n\tASSERT_EQ(stats.bank[5].cycles.act, 25);\n\tASSERT_EQ(stats.bank[6].cycles.act, 25);\n\tASSERT_EQ(stats.bank[7].cycles.act, 25);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 55);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[6].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 85);\n}\n\nTEST_F(DramPowerTest_DDR4_15, CalcWindow)\n{\n\tSimulationStats window;\n\n\tauto iterate_to_timestamp = [this](auto & command, timestamp_t timestamp) {\n\t\twhile (command != this->testPattern.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\n\t\treturn this->ddr->getWindowStats(timestamp);\n\t};\n\n\tauto command = testPattern.begin();\n\n\n\t// Cycle 5\n\twindow = iterate_to_timestamp(command, 5);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 5);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 5);\n\n\t// Cycle 10\n\twindow = iterate_to_timestamp(command, 10);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 10);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act,  0);   ASSERT_EQ(window.bank[1].cycles.pre, 10);\n\n\t// Cycle 15\n\twindow = iterate_to_timestamp(command, 15);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 15);\n\tASSERT_EQ(window.bank[0].cycles.act, 15);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 15);\n\n\t// Cycle 20\n\twindow = iterate_to_timestamp(command, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 20);\n\tASSERT_EQ(window.bank[0].cycles.act, 20);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 20);\n\n\t// Cycle 25\n\twindow = iterate_to_timestamp(command, 25);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 20);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 20);\n\n\t// Cycle 30\n\twindow = iterate_to_timestamp(command, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 20);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 20);\n\n\t// Cycle 35\n\twindow = iterate_to_timestamp(command, 35);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 25);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 25);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 25);\n\n\t// Cycle 40\n\twindow = iterate_to_timestamp(command, 40);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act,  0);  ASSERT_EQ(window.bank[1].cycles.pre, 30);\n\n\t// Cycle 45\n\twindow = iterate_to_timestamp(command, 45);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre,  5);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 35);\n\n\t// Cycle 50\n\twindow = iterate_to_timestamp(command, 50);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 10);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 10);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 40);\n\n\t// Cycle 55\n\twindow = iterate_to_timestamp(command, 55);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 15);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 15);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 45);\n\n\t// Cycle 60\n\twindow = iterate_to_timestamp(command, 60);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 20);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 50);\n\n\t// Cycle 65\n\twindow = iterate_to_timestamp(command, 65);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 20);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 50);\n\n\t// Cycle 70\n\twindow = iterate_to_timestamp(command, 70);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 25);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 25);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 55);\n\n\t// Cycle 75\n\twindow = iterate_to_timestamp(command, 75);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 80\n\twindow = iterate_to_timestamp(command, 80);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 35);    ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 35);  ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 5);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 85\n\twindow = iterate_to_timestamp(command, 85);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 40);     ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 40);   ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 10);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 90\n\twindow = iterate_to_timestamp(command, 90);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 45);     ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 45);   ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 15);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 95\n\twindow = iterate_to_timestamp(command, 95);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 50);     ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 50);   ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 20);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 100\n\twindow = iterate_to_timestamp(command, 100);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 105\n\twindow = iterate_to_timestamp(command, 105);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 35);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 35);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 65);\n\n\t// Cycle 110\n\twindow = iterate_to_timestamp(command, 110);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 40);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 40);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 70);\n\n\t// Cycle 115\n\twindow = iterate_to_timestamp(command, 115);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 45);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 45);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 75);\n\n\t// Cycle 120\n\twindow = iterate_to_timestamp(command, 120);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 50);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 50);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 80);\n\n\t// Cycle 125\n\twindow = iterate_to_timestamp(command, 125);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 55);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 55);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 85);\n};\n\n\n\nTEST_F(DramPowerTest_DDR4_15, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ(std::round(total_energy.E_bg_act), 1340);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared), 880);\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_act, 110);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_act, 50);\n\n\tASSERT_EQ((int)total_energy.E_bg_pre, 440);\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_pre, 55);\n\n\tASSERT_EQ((int)energy.E_PDNA, 200);\n\tASSERT_EQ((int)energy.E_PDNP, 30);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR4/ddr4_test_pattern_2.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <memory>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR4_2 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   35, CmdType::PRE,  { 0, 0, 0 }},\n            { 50, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR4> ddr;\n    std::unique_ptr<DRAMPower::MemSpecDDR4> memSpec;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR4>(DRAMPower::MemSpecDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<DDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR4_2, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    ASSERT_EQ(stats.bank[0].counter.act, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.act, 0);\n\n    // Check bank command count: RD\n    ASSERT_EQ(stats.bank[0].counter.reads, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.reads, 0);\n\n    // Check bank command count: PRE\n    ASSERT_EQ(stats.bank[0].counter.pre, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.pre, 0);\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 35);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 15);\n\n    // Check bank specific ACT cycle count\n    ASSERT_EQ(stats.bank[0].cycles.act, 35);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.act, 0);\n\n    // Check bank specific PRE cycle count\n    ASSERT_EQ(stats.bank[0].cycles.pre, 15);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.pre, 50);\n}\n\nTEST_F(DramPowerTest_DDR4_2, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 179);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 208);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 436);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1189);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1183);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 467);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 2479);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR4/ddr4_test_pattern_3.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <memory>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR4_3 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::PRE,  { 0, 0, 0 }},\n            {   45, CmdType::PRE,  { 3, 0, 0 }},\n            { 50, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR4> ddr;\n    std::unique_ptr<DRAMPower::MemSpecDDR4> memSpec;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR4>(DRAMPower::MemSpecDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<DDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR4_3, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    }\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 45);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 5);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 35);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 25);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 0);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 15);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 25);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 50);\n    }\n}\n\nTEST_F(DramPowerTest_DDR4_3, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 359);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 436);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1531);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1521);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 156);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 2897);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR4/ddr4_test_pattern_4.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <DRAMPower/command/Command.h>\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR4_4 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::RD,  { 3, 0, 0 }},\n            {   40, CmdType::RD,  { 0, 0, 0 }},\n            {   50, CmdType::PREA,  { 0, 0, 0 }},\n            { 70, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR4> ddr;\n    std::unique_ptr<DRAMPower::MemSpecDDR4> memSpec;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR4>(DRAMPower::MemSpecDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<DDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR4_4, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].counter.reads, 2);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    };\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 50);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 20);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 50);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 30);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 0);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 20);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 40);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 70);\n    }\n}\n\nTEST_F(DramPowerTest_DDR4_4, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 359);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 1307);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1704);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1690);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 623);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 4408);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR4/ddr4_test_pattern_5.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <memory>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR4_5 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::RD,  { 3, 0, 0 }},\n            {   40, CmdType::RD,  { 0, 0, 0 }},\n            {   50, CmdType::PREA,  { 0, 0, 0 }},\n            {   65, CmdType::REFA,  { 0, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR4> ddr;\n    std::unique_ptr<DRAMPower::MemSpecDDR4> memSpec;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR4>(DRAMPower::MemSpecDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<DDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR4_5, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].counter.reads, 2);\n        else if( b == 3)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    };\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check bank command count: REFA\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        ASSERT_EQ(stats.bank[b].counter.refAllBank, 1);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 75);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 25);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 75);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 55);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 25);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 25);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 45);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 75);\n    }\n}\n\nTEST_F(DramPowerTest_DDR4_5, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 359);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 1307);\n    ASSERT_EQ(std::round(total_energy.E_ref_AB*1e12), 1812);\n    ASSERT_EQ(std::round(total_energy.E_ref_SB*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 2615);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 2536);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 779);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 7287);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR4/ddr4_test_pattern_6.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR4_6 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RDA,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::RD,  { 3, 0, 0 }},\n            {   50, CmdType::PREA,  { 0, 0, 0 }},\n            {   65, CmdType::REFA,  { 0, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR4> ddr;\n    std::unique_ptr<DRAMPower::MemSpecDDR4> memSpec;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR4>(DRAMPower::MemSpecDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<DDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR4_6, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 3)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    }\n\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].counter.readAuto, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.readAuto, 0);\n    }\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check bank command count: REFA\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        ASSERT_EQ(stats.bank[b].counter.refAllBank, 1);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 75);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 25);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 45);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 55);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 25);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 55);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 45);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 75);\n    }\n}\n\nTEST_F(DramPowerTest_DDR4_6, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 359);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 436);\n    ASSERT_EQ(std::round(total_energy.E_RDA*1e12), 436);\n    ASSERT_EQ(std::round(total_energy.E_ref_AB*1e12), 1812);\n    ASSERT_EQ(std::round(total_energy.E_ref_SB*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 2610);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 2536);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 779);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 6846);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR4/ddr4_test_pattern_7.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR4_7 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::SREFEN,  { 0, 0, 0 }},\n            {   40, CmdType::SREFEX,  { 0, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR4> ddr;\n    std::unique_ptr<DRAMPower::MemSpecDDR4> memSpec;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR4>(DRAMPower::MemSpecDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<DDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR4_7, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].counter.act, 0);\n\n    // Check bank command count: REFA\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].counter.refAllBank, 1);\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 25);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 60);\n    ASSERT_EQ(stats.rank_total[0].cycles.selfRefresh, 15);\n\n    // Check bank specific ACT cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.act, 25);\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.pre, 60);\n\n    // Check bank specific SREF cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.selfRefresh, 15);\n\n}\n\nTEST_F(DramPowerTest_DDR4_7, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_ref_AB*1e12), 1812);\n    ASSERT_EQ(std::round(energy.E_sref*1e12), 280);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 912);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 845);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 1869);\n    ASSERT_EQ(std::round((total_energy.total() + energy.E_sref)*1e12), 4872);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR4/ddr4_test_pattern_8.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n#include <string>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR4_8 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            //{   0, CmdType::ACT,    { 0, 0, 0 }},\n            {   0, CmdType::PDEA,   { 0, 0, 0 }}, // Keep in mind earliest power down (entry 13 cycles)\n            {   30, CmdType::PDXA,  { 0, 0, 0 }},\n            //{   30, CmdType::PRE,   { 0, 0, 0 }},\n            {   45, CmdType::PDEP,  { 0, 0, 0 }},\n            {   70, CmdType::PDXP,  { 0, 0, 0 }},\n            { 85, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR4> ddr;\n    std::unique_ptr<DRAMPower::MemSpecDDR4> memSpec;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR4>(DRAMPower::MemSpecDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<DDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR4_8, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 30);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 30);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 25);\n    ASSERT_EQ(stats.rank_total[0].cycles.selfRefresh, 0);\n\n    // TODO pre for banks 2-16 invalid\n\n    // Check bank specific ACT cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.act, 0);\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.pre, 30);\n\n    // Check bank specific PDNA cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownAct, 30);\n\n    // Check bank specific PDNP cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownPre, 25);\n\n    // Check bank specific SREF cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.selfRefresh, 0);\n}\n\nTEST_F(DramPowerTest_DDR4_8, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_sref*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_PDNA*1e12), 623);\n    ASSERT_EQ(std::round(energy.E_PDNP*1e12), 392);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 935);\n    ASSERT_EQ(std::round((total_energy.total() + energy.E_sref + energy.E_PDNA + energy.E_PDNP)*1e12), 1950);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR4/ddr4_test_pattern_9.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr4/DDR4.h>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <memory>\n\n#include <fstream>\n#include <string>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR4_9 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   5, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::ACT,  { 5, 0, 0 }},\n            {   20, CmdType::RD,  { 0, 0, 0 }},\n            {   30, CmdType::PDEA,  { 0, 0, 0 }},\n            {   50, CmdType::PDXA,  { 0, 0, 0 }},\n            {   55, CmdType::RD,  { 5, 0, 0 }},\n            {   60, CmdType::RD,  { 0, 0, 0 }},\n            {   70, CmdType::PREA,  { 0, 0, 0 }},\n            {   80, CmdType::PDEP,  { 0, 0, 0 }},\n            {   95, CmdType::PDXP,  { 0, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR4> ddr;\n    std::unique_ptr<DRAMPower::MemSpecDDR4> memSpec;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR4>(DRAMPower::MemSpecDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<DDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR4_9, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 45);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 20);\n    ASSERT_EQ(stats.rank_total[0].cycles.selfRefresh, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 20);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 15);\n\n    // Check bank specific ACT cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0){\n            ASSERT_EQ(stats .bank[b].cycles.act, 45);\n        }else if (b == 5){\n            ASSERT_EQ(stats .bank[b].cycles.act, 35);\n        }else{\n            ASSERT_EQ(stats .bank[b].cycles.act, 0);\n        }\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 20);\n        }else if (b == 5){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 30);\n        }else{\n            ASSERT_EQ(stats.bank[b].cycles.pre, 65);\n        }\n    }\n\n    // Check bank specific PDNA cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownAct, 20);\n\n    // Check bank specific PDNP cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownPre, 15);\n\n    // Check bank specific SREF cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.selfRefresh, 0);\n}\n\nTEST_F(DramPowerTest_DDR4_9, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 359);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 1307);\n    ASSERT_EQ(std::round(energy.E_sref*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_PDNA*1e12), 415);\n    ASSERT_EQ(std::round(energy.E_PDNP*1e12), 235);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1535);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1521);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 623);\n    ASSERT_EQ(std::round((total_energy.total() + energy.E_sref + energy.E_PDNA + energy.E_PDNP)*1e12), 4890);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_multidevice_tests.cpp",
    "content": "/* Note\nThis test is based on ddr5_test_pattern_4.cpp and assumes the correctness of the test.\n\nCalculation for 5 devices:\nE_act: \t\t\t\t\t358.99038461538458\nE_pre: \t\t\t\t\t415.38461538461542\nE_RD:\t\t\t\t\t1307.0769230769231\nE_bg_act:\t\t\t\t1703.6538461538462\nE_bg_act_shared:\t\t1690.3846153846155\nE_bg_pre:\t\t\t\t623.07692307692309\nTotal:\t\t\t\t\t4408.1826923076924\n\nE_act * 5:\t\t\t\t1794.9519230769229\nE_pre * 5:\t\t\t\t2076.9230769230771\nE_RD * 5:\t\t\t\t6535.3846153846155\nE_bg_act * 5:\t\t\t8518.269230769231\nE_bg_act_shared * 5:\t8451.9230769230775\nE_bg_pre * 5:\t\t\t3115.38461538461545\nTotal * 5:\t\t\t\t22040.913461538462\n*/\n\n\n#include <gtest/gtest.h>\n\n#include <DRAMPower/command/Command.h>\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_MultiDevice : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::RD,  { 3, 0, 0 }},\n            {   40, CmdType::RD,  { 0, 0, 0 }},\n            {   50, CmdType::PREA,  { 0, 0, 0 }},\n            { 70, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecDDR5> memSpec;\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n    uint64_t numberOfDevices;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR5>(DRAMPower::MemSpecDDR5::from_memspec(*data));\n\n        memSpec->numberOfDevices = 5;\n\n        numberOfDevices = memSpec->numberOfDevices;\n        ddr = std::make_unique<DDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_MultiDevice, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].counter.reads, 2);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    };\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 50);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 20);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 50);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 30);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 0);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 20);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 40);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 70);\n    }\n}\n\nTEST_F(DramPowerTest_DDR5_MultiDevice, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(energy.bank_energy.size(), numberOfDevices * memSpec->numberOfBanks);\n\n    // Validate every device has the same bank energy\n    for(size_t i = 0; i < numberOfDevices; i++){\n        for(size_t j = 0; j < memSpec->numberOfBanks; j++){\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_act, energy.bank_energy[j].E_act);\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_pre, energy.bank_energy[j].E_pre);\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_RD, energy.bank_energy[j].E_RD);\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_bg_act, energy.bank_energy[j].E_bg_act);\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_bg_pre, energy.bank_energy[j].E_bg_pre);\n        }\n    }\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 1795);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 2077);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 6535);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 8518);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 8452);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 3115);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 22041);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_multirank_tests.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <fstream>\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n#include <variant>\n\n#include \"DRAMPower/command/Command.h\"\n#include \"DRAMPower/standards/ddr5/DDR5.h\"\n#include \"DRAMPower/memspec/MemSpecDDR5.h\"\n\nusing DRAMPower::CmdType;\nusing DRAMPower::Command;\nusing DRAMPower::DDR5;\nusing DRAMPower::MemSpecDDR5;\nusing DRAMPower::SimulationStats;\nusing DRAMPower::TargetCoordinate;\n\n#define SZ_BITS(x) sizeof(x)*8\n\nstatic constexpr uint8_t wr_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 255,  0, 0, 0, 0,  0, 0, 0, 0,\n    0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 255,\n};\n\nstatic constexpr uint8_t rd_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 1,  0, 0, 0, 0,  0, 0, 0, 0,\n    0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,\n};\n\nclass DDR5_MultirankTests : public ::testing::Test {\n  public:\n    void SetUp()\n    {\n        initSpec();\n        ddr = std::make_unique<DDR5>(*spec);\n    }\n\n    void initSpec() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        spec = std::make_unique<DRAMPower::MemSpecDDR5>(DRAMPower::MemSpecDDR5::from_memspec(*data));\n\n        spec->numberOfRanks = 2;\n    }\n\n    void runCommands(const std::vector<Command> &commands) {\n        for (const Command &command : commands) {\n            ddr->doCoreCommand(command);\n            ddr->doInterfaceCommand(command);\n        }\n    }\n\n    inline size_t bankIndex(int bank, int rank) {\n        return rank * spec->numberOfBanks + bank;\n    }\n\n    std::unique_ptr<MemSpecDDR5> spec;\n    std::unique_ptr<DDR5> ddr;\n};\n\nTEST_F(DDR5_MultirankTests, Pattern_1) {\n    runCommands({\n        {0, CmdType::ACT, {1, 0, 0}},\n        {2, CmdType::ACT, {1, 0, 1}},  // rank 1\n        {4, CmdType::WR, {1, 0, 0, 0, 4}, wr_data, SZ_BITS(wr_data)},\n        {6, CmdType::RD, {1, 0, 1, 0, 4}, rd_data, SZ_BITS(rd_data)},  // rank 1\n        {10, CmdType::PRE, {1, 0, 1}},  // rank 1\n        {15, CmdType::PRE, {1, 0, 0}},\n        {20, CmdType::END_OF_SIMULATION}\n    });\n\n    SimulationStats stats = ddr->getStats();\n    EXPECT_EQ(stats.bank.size(), spec->numberOfBanks * spec->numberOfRanks);\n    EXPECT_EQ(stats.bank[bankIndex(1, 0)].cycles.act, 15);\n    EXPECT_EQ(stats.bank[bankIndex(1, 1)].cycles.act, 8);\n    EXPECT_EQ(stats.bank[bankIndex(1, 0)].cycles.pre, 5);\n    EXPECT_EQ(stats.bank[bankIndex(1, 1)].cycles.pre, 12);\n\n    EXPECT_EQ(stats.rank_total[0].cycles.act, 15);\n    EXPECT_EQ(stats.rank_total[1].cycles.act, 8);\n}\n\nTEST_F(DDR5_MultirankTests, Pattern_2) {\n    runCommands({ // TODO invalid state traversal\n        {0, CmdType::ACT,   TargetCoordinate{0, 0, 0}}, // r0\n        {5, CmdType::ACT,   TargetCoordinate{0, 0, 1}}, // r1\n        {15, CmdType::RDA,  TargetCoordinate{0, 0, 0, 0, 4}, rd_data, SZ_BITS(rd_data)}, // r0\n        {22, CmdType::ACT,  TargetCoordinate{3, 0, 0}},  // r0\n        {35, CmdType::RD,   TargetCoordinate{0, 0, 1, 0, 0}, rd_data, SZ_BITS(rd_data)}, // r1\n        {55, CmdType::RD,   TargetCoordinate{3, 0, 0, 0, 3}, rd_data, SZ_BITS(rd_data)}, // r0\n        {60, CmdType::PREA, TargetCoordinate{0, 0, 0}}, // r0\n        {65, CmdType::PREA, TargetCoordinate{0, 0, 1}}, // r1\n        {75, CmdType::REFA, TargetCoordinate{0, 0, 0}}, // r0\n        {80, CmdType::REFA, TargetCoordinate{0, 0, 1}}, // r1\n        {130, CmdType::END_OF_SIMULATION},\n    });\n\n    // t = 0 ACT               -> Start activate // r0, b0\n    // t = 5 ACT               -> Start activate // r1, b0\n    // t = 15 RDA              -> delayed pre after 5 cycles // r0, b0\n    // t = 20 RDA (implicit)   -> End activate // r0, b0\n    // t = 22 ACT              -> Start activate // r0, b3\n    // t = 35 RD               -> Read // r1, b0\n    // t = 55 RD               -> Read // r0, b3\n    // t = 60 PREA             -> End activate // r0, b0, b3\n    // t = 65 PREA             -> End activate // r1, b0\n    // t = 75 REFA             -> Start activate // r0, b0, b3\n    // t = 80 REFA             -> Start activate // r1, b0\n    // t = 100 REFA (implicit) -> End activate // r0, b0, b3\n    // t = 105 REFA (implicit) -> End activate // r1, b0\n    // t = 130 END_OF_SIMULATION\n\n    SimulationStats stats = ddr->getStats();\n    EXPECT_EQ(stats.bank.size(), spec->numberOfBanks * spec->numberOfRanks);\n    EXPECT_EQ(stats.bank[bankIndex(0, 0)].cycles.act, 45);\n    EXPECT_EQ(stats.bank[bankIndex(3, 0)].cycles.act, 63);\n    EXPECT_EQ(stats.bank[bankIndex(0, 1)].cycles.act, 85);\n\n    EXPECT_EQ(stats.bank[bankIndex(0, 0)].cycles.pre, 130 - 45);\n    EXPECT_EQ(stats.bank[bankIndex(3, 0)].cycles.pre, 130 - 63);\n    EXPECT_EQ(stats.bank[bankIndex(0, 1)].cycles.pre, 130 - 85);\n\n    EXPECT_EQ(stats.rank_total[0].cycles.act, 83);\n    EXPECT_EQ(stats.rank_total[1].cycles.act, 85);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_0.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_0 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {  0, CmdType::ACT,  { 0, 0, 0 }},\n            { 15, CmdType::PRE,  { 0, 0, 0 }},\n            { 15, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecDDR5> memSpec;\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR5>(DRAMPower::MemSpecDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<DDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_0, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    ASSERT_EQ(stats.bank[0].counter.act, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].counter.act, 0);\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 15);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 0);\n\n    // Check bank specific ACT cycle count\n    ASSERT_EQ(stats.bank[0].cycles.act, 15);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.act, 0);\n\n    // Check bank specific PRE cycle count\n    ASSERT_EQ(stats.bank[0].cycles.pre, 0);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.pre, 15);\n}\n\nTEST_F(DramPowerTest_DDR5_0, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 179);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 208);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 510);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 507);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 897);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_1.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_1 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   35, CmdType::PRE,  { 0, 0, 0 }},\n            { 35, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecDDR5> memSpec;\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR5>(DRAMPower::MemSpecDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<DDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_1, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    ASSERT_EQ(stats.bank[0].counter.act, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.act, 0);\n\n    // Check bank command count: RD\n    ASSERT_EQ(stats.bank[0].counter.reads, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.reads, 0);\n\n    // Check bank command count: PRE\n    ASSERT_EQ(stats.bank[0].counter.pre, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.pre, 0);\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 35);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 0);\n\n    // Check bank specific ACT cycle count\n    ASSERT_EQ(stats.bank[0].cycles.act, 35);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.act, 0);\n\n    // Check bank specific PRE cycle count\n    ASSERT_EQ(stats.bank[0].cycles.pre, 0);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.pre, 35);\n}\n\nTEST_F(DramPowerTest_DDR5_1, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 179);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 208);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 436);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1189);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1183);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 2012);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_10.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_10 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 11, 0, 0 }},\n            {   55, CmdType::PREA,  { 0, 0, 0 }},\n            {   70, CmdType::REFSB,  { 0, 0, 0 }},\n            {   75, CmdType::REFSB,  { 11, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecDDR5> memSpec;\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR5>(DRAMPower::MemSpecDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<DDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_10, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 80);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 20);\n    ASSERT_EQ(stats.rank_total[0].cycles.selfRefresh, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 0);\n\n    // Check bank specific ACT cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0){\n            ASSERT_EQ(stats.bank[b].cycles.act, 75);\n        }else if (b == 3 || b == 8){\n            ASSERT_EQ(stats.bank[b].cycles.act, 20);\n        }else if (b == 11){\n            ASSERT_EQ(stats.bank[b].cycles.act, 55);\n        }else{\n            ASSERT_EQ(stats.bank[b].cycles.act, 0);\n        }\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 25);\n        }else if (b == 3 || b == 8){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 80);\n        }else if (b == 11){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 45);\n        }else{\n            ASSERT_EQ(stats.bank[b].cycles.pre, 100);\n        }\n    }\n\n    // Check bank specific PDNA cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownAct, 0);\n\n    // Check bank specific PDNP cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownPre, 0);\n\n    // Check bank specific SREF cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.selfRefresh, 0);\n}\n\nTEST_F(DramPowerTest_DDR5_10, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 359);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 436);\n    ASSERT_EQ(std::round(energy.E_sref*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_PDNA*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_PDNP*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 2733);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 2705);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 623);\n    ASSERT_EQ(std::round(total_energy.E_ref_SB*1e12), 2696);\n    ASSERT_EQ(std::round((total_energy.total() + energy.E_sref + energy.E_PDNA + energy.E_PDNP)*1e12), 7262);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_11.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_11 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 11, 0, 0 }},\n            {   25, CmdType::ACT,  { 3, 0, 0 }},\n            {   40, CmdType::WR,  { 11, 0, 0 }},\n            {   45, CmdType::RD,  { 3, 0, 0 }},\n            {   55, CmdType::PRESB,  { 0, 0, 0 }},\n            {   65, CmdType::PRESB,  { 11, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecDDR5> memSpec;\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR5>(DRAMPower::MemSpecDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<DDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_11, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 65);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 35);\n    ASSERT_EQ(stats.rank_total[0].cycles.selfRefresh, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 0);\n\n    // Check bank specific ACT cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0){\n            ASSERT_EQ(stats.bank[b].cycles.act, 55);\n        }else if (b == 3){\n            ASSERT_EQ(stats.bank[b].cycles.act, 40);\n        }else if (b == 11){\n            ASSERT_EQ(stats.bank[b].cycles.act, 45);\n        }else{\n            ASSERT_EQ(stats.bank[b].cycles.act, 0);\n        }\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 45);\n        }else if (b == 3){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 60);\n        }else if (b == 11){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 55);\n        }else{\n            ASSERT_EQ(stats.bank[b].cycles.pre, 100);\n        }\n    }\n\n    // Check bank specific PDNA cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownAct, 0);\n\n    // Check bank specific PDNP cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownPre, 0);\n\n    // Check bank specific SREF cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.selfRefresh, 0);\n\n}\n\nTEST_F(DramPowerTest_DDR5_11, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 538);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 623);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 871);\n    ASSERT_EQ(std::round(total_energy.E_WR*1e12), 353);\n    ASSERT_EQ(std::round(energy.E_sref*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_PDNA*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_PDNP*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 2221);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 2198);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 1090);\n    ASSERT_EQ(std::round(total_energy.E_ref_SB*1e12), 0);\n    ASSERT_EQ(std::round((total_energy.total() + energy.E_sref + energy.E_PDNA + energy.E_PDNP)*1e12), 5697);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_12.cpp",
    "content": "#include <gtest/gtest.h>\n#include \"DRAMPower/command/Command.h\"\n#include <DRAMPower/standards/ddr5/DDR5.h>\n#include <DRAMPower/standards/test_accessor.h>\n#include <memory>\n#include <fstream>\n#include <string>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_12 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n    // Timestamp,   Cmd,  { Bank, BG, Rank}\n        {   0, CmdType::ACT, { 0, 0, 0 } },\n        {  10, CmdType::ACT, { 1, 0, 0 } },\n        {  15, CmdType::PRE, { 0, 0, 0 } },\n        {  25, CmdType::ACT, { 3, 0, 0 } },\n        {  25, CmdType::PRE, { 1, 0, 0 } },\n        {  30, CmdType::ACT, { 0, 0, 0 } },\n        {  35, CmdType::ACT, { 2, 0, 0 } },\n        {  40, CmdType::PRE, { 1, 0, 0 } },\n        {  40, CmdType::PRE, { 3, 0, 0 } },\n        {  45, CmdType::PRE, { 0, 0, 0 } },\n        {  50, CmdType::PRE, { 2, 0, 0 } },\n        {  85, CmdType::ACT, { 7, 0, 0 } },\n        { 100, CmdType::PRE, { 7, 0, 0 } },\n        { 120, CmdType::ACT, { 6, 0, 0 } },\n        { 125, CmdType::END_OF_SIMULATION},\n    };\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        auto memSpec = DRAMPower::MemSpecDDR5::from_memspec(*data);\n\n\t\tmemSpec.bitWidth = 16;\n\t\tmemSpec.numberOfDevices = 1;\n        memSpec.numberOfRanks = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.banksPerGroup = 8;\n        memSpec.numberOfBankGroups = 1;\n        memSpec.burstLength = 8;\n        memSpec.dataRate = 2;\n\n        memSpec.memTimingSpec.tCK = 1;\n\t\tmemSpec.memTimingSpec.tRAS = 10;\n\t\tmemSpec.memTimingSpec.tRP = 10;\n\n\t\tmemSpec.memPowerSpec[0].vXX = 1;\n\t\tmemSpec.memPowerSpec[0].iXX0 = 64;\n\t\tmemSpec.memPowerSpec[0].iXX3N = 32;\n\t\tmemSpec.memPowerSpec[0].iXX2N = 8;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iXX0;\n        memSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n\n        ddr = std::make_unique<DDR5>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_12, Pattern1)\n{\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\t// Inspect first rank\n\tconst auto & rank_1 = internal::DDR5TestAccessor.getRanks(ddr->getCore()).at(0);\n\tauto stats = ddr->getStats();\n\n\t// Check global count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 70);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 55);\n\n\t// Check per-bank ACT count\n\tASSERT_EQ(stats.bank[0].cycles.act, 30);\n\n\tASSERT_EQ(stats.bank[1].cycles.act, 15);\n\tASSERT_EQ(stats.bank[2].cycles.act, 15);\n\tASSERT_EQ(stats.bank[3].cycles.act, 15);\n\tASSERT_EQ(stats.bank[7].cycles.act, 15);\n\n\tASSERT_EQ(stats.bank[6].cycles.act, 5);\n\n\tASSERT_EQ(stats.bank[4].cycles.act, 0);\n\tASSERT_EQ(stats.bank[5].cycles.act, 0);\n\n\t// Check per-bank PRE count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 95);\n\n\tASSERT_EQ(stats.bank[1].cycles.pre, 110);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 110);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 110);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 110);\n\n\tASSERT_EQ(stats.bank[6].cycles.pre, 120);\n\n\tASSERT_EQ(stats.bank[4].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 125);\n\n\t// Check global command count\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::ACT), 7);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::PRE), 7);\n\n\t// per-bank ACT command count\n\tASSERT_EQ(stats.bank[0].counter.act, 2);\n\n\tASSERT_EQ(stats.bank[1].counter.act, 1);\n\tASSERT_EQ(stats.bank[2].counter.act, 1);\n\tASSERT_EQ(stats.bank[3].counter.act, 1);\n\tASSERT_EQ(stats.bank[6].counter.act, 1);\n\tASSERT_EQ(stats.bank[7].counter.act, 1);\n\n\tASSERT_EQ(stats.bank[4].counter.act, 0);\n\tASSERT_EQ(stats.bank[5].counter.act, 0);\n\n\t// per-bank PRE command count\n\tASSERT_EQ(stats.bank[0].counter.pre, 2);\n\n\tASSERT_EQ(stats.bank[1].counter.pre, 1);\n\tASSERT_EQ(stats.bank[2].counter.pre, 1);\n\tASSERT_EQ(stats.bank[3].counter.pre, 1);\n\tASSERT_EQ(stats.bank[7].counter.pre, 1);\n\n\tASSERT_EQ(stats.bank[6].counter.pre, 0);\n\tASSERT_EQ(stats.bank[4].counter.pre, 0);\n\tASSERT_EQ(stats.bank[5].counter.pre, 0);\n}\n\nTEST_F(DramPowerTest_DDR5_12, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n    auto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ((int)total_energy.E_act, 3220);\n\tASSERT_EQ((int)energy.bank_energy[0].E_act, 920);\n\tASSERT_EQ((int)energy.bank_energy[1].E_act, 460);\n\tASSERT_EQ((int)energy.bank_energy[2].E_act, 460);\n\tASSERT_EQ((int)energy.bank_energy[3].E_act, 460);\n\tASSERT_EQ((int)energy.bank_energy[4].E_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_act, 460);\n\tASSERT_EQ((int)energy.bank_energy[7].E_act, 460);\n\n\tASSERT_EQ((int)total_energy.E_pre, 3360);\n\tASSERT_EQ((int)energy.bank_energy[0].E_pre, 1120);\n\tASSERT_EQ((int)energy.bank_energy[1].E_pre, 560);\n\tASSERT_EQ((int)energy.bank_energy[2].E_pre, 560);\n\tASSERT_EQ((int)energy.bank_energy[3].E_pre, 560);\n\tASSERT_EQ((int)energy.bank_energy[4].E_pre, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_pre, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_pre, 0);\n\tASSERT_EQ((int)energy.bank_energy[7].E_pre, 560);\n\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_act, 60);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_act, 30);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_act, 30);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_act, 30);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_act, 10);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_act, 30);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared), 1120);\n\tASSERT_EQ(std::round(total_energy.E_bg_act), 1310);\n\n    ASSERT_EQ((int)total_energy.E_bg_pre, 440);\n    ASSERT_EQ((int)energy.bank_energy[0].E_bg_pre, 55);\n    ASSERT_EQ((int)energy.bank_energy[1].E_bg_pre, 55);\n    ASSERT_EQ((int)energy.bank_energy[2].E_bg_pre, 55);\n    ASSERT_EQ((int)energy.bank_energy[3].E_bg_pre, 55);\n    ASSERT_EQ((int)energy.bank_energy[4].E_bg_pre, 55);\n    ASSERT_EQ((int)energy.bank_energy[5].E_bg_pre, 55);\n    ASSERT_EQ((int)energy.bank_energy[6].E_bg_pre, 55);\n    ASSERT_EQ((int)energy.bank_energy[7].E_bg_pre, 55);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_13.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n#include <DRAMPower/standards/test_accessor.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_13 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{   0, CmdType::ACT, { 0, 0, 0} },\n\t\t{   5, CmdType::ACT, { 1, 0, 0} },\n\t\t{  10, CmdType::ACT, { 2, 0, 0} },\n\t\t{  15, CmdType::ACT, { 3, 0, 0} },\n\t\t{  20, CmdType::ACT, { 4, 0, 0} },\n\t\t{  25, CmdType::ACT, { 5, 0, 0} },\n\t\t{  30, CmdType::ACT, { 6, 0, 0} },\n\t\t{  35, CmdType::ACT, { 7, 0, 0} },\n\t\t{  35, CmdType::RD,  { 0, 0, 0} },\n\t\t{  40, CmdType::RD,  { 0, 0, 0} },\n\t\t{  40, CmdType::RD,  { 1, 0, 0} },\n\t\t{  45, CmdType::RD,  { 0, 0, 0} },\n\t\t{  45, CmdType::RD,  { 2, 0, 0} },\n\t\t{  50, CmdType::RD,  { 3, 0, 0} },\n\t\t{  55, CmdType::RD,  { 4, 0, 0} },\n\t\t{  60, CmdType::RD,  { 5, 0, 0} },\n\t\t{  65, CmdType::RD,  { 6, 0, 0} },\n\t\t{  70, CmdType::RD,  { 7, 0, 0} },\n\t\t{  75, CmdType::RD,  { 7, 0, 0} },\n\t\t{  80, CmdType::RD,  { 7, 0, 0} },\n\t\t{  85, CmdType::WR,  { 7, 0, 0} },\n\t\t{  90, CmdType::WR,  { 6, 0, 0} },\n\t\t{  95, CmdType::WR,  { 5, 0, 0} },\n\t\t{ 100, CmdType::WR,  { 4, 0, 0} },\n\t\t{ 105, CmdType::WR,  { 3, 0, 0} },\n\t\t{ 110, CmdType::WR,  { 2, 0, 0} },\n\t\t{ 110, CmdType::WR,  { 0, 0, 0} },\n\t\t{ 115, CmdType::WR,  { 1, 0, 0} },\n\t\t{ 115, CmdType::RD,  { 0, 0, 0} },\n\t\t{ 120, CmdType::WR,  { 0, 0, 0} },\n\t\t{ 120, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        auto memSpec = DRAMPower::MemSpecDDR5::from_memspec(*data);\n\n\t\tmemSpec.bitWidth = 16;\n\t\tmemSpec.numberOfDevices = 1;\n\t\tmemSpec.numberOfRanks = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.banksPerGroup = 8;\n\t\tmemSpec.numberOfBankGroups = 1;\n\n\t\tmemSpec.memTimingSpec.tCK = 1;\n\n\t\tmemSpec.memPowerSpec[0].vXX = 1;\n\t\tmemSpec.memPowerSpec[0].iXX0 = 64;\n\t\tmemSpec.memPowerSpec[0].iXX3N = 32;\n\t\tmemSpec.memPowerSpec[0].iXX4R = 72;\n\t\tmemSpec.memPowerSpec[0].iXX4W = 96;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iXX0;\n\n\n        memSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\n        ddr = std::make_unique<DDR5>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_13, Pattern_2)\n{\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\t// Inspect first rank\n\tconst Rank & rank_1 = internal::DDR5TestAccessor.getRanks(ddr->getCore()).at(0);\n\n\t// Check global command count\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::RD), 13);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::WR), 9);\n\n\t// Check bank RD command count\n\tASSERT_EQ(rank_1.banks[0].counter.reads, 4);\n\tASSERT_EQ(rank_1.banks[1].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[2].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[3].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[4].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[5].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[6].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[7].counter.reads, 3);\n\n\t// Check bank WR command count\n\tASSERT_EQ(rank_1.banks[0].counter.writes, 2);\n\tASSERT_EQ(rank_1.banks[1].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[2].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[3].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[4].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[5].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[6].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[7].counter.writes, 1);\n}\n\nTEST_F(DramPowerTest_DDR5_13, CalcEnergy)\n{\n    auto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ((int)total_energy.E_RD, 4160);\n\tASSERT_EQ((int)energy.bank_energy[0].E_RD, 1280);\n\tASSERT_EQ((int)energy.bank_energy[1].E_RD, 320);\n\tASSERT_EQ((int)energy.bank_energy[2].E_RD, 320);\n\tASSERT_EQ((int)energy.bank_energy[3].E_RD, 320);\n\tASSERT_EQ((int)energy.bank_energy[4].E_RD, 320);\n\tASSERT_EQ((int)energy.bank_energy[5].E_RD, 320);\n\tASSERT_EQ((int)energy.bank_energy[6].E_RD, 320);\n\tASSERT_EQ((int)energy.bank_energy[7].E_RD, 960);\n\n\tASSERT_EQ((int)total_energy.E_WR, 4608);\n\tASSERT_EQ((int)energy.bank_energy[0].E_WR, 1024);\n\tASSERT_EQ((int)energy.bank_energy[1].E_WR, 512);\n\tASSERT_EQ((int)energy.bank_energy[2].E_WR, 512);\n\tASSERT_EQ((int)energy.bank_energy[3].E_WR, 512);\n\tASSERT_EQ((int)energy.bank_energy[4].E_WR, 512);\n\tASSERT_EQ((int)energy.bank_energy[5].E_WR, 512);\n\tASSERT_EQ((int)energy.bank_energy[6].E_WR, 512);\n\tASSERT_EQ((int)energy.bank_energy[7].E_WR, 512);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_14.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n#include <DRAMPower/standards/test_accessor.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_14 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t// Timestamp,   Cmd,  { Bank, BG, Rank}\n\t\t{   0, CmdType::ACT, { 0, 0, 0 }  },\n\t\t{  10, CmdType::RDA, { 0, 0, 0 }  },\n\t\t{  15, CmdType::ACT, { 1, 0, 0 }  },\n\t\t{  15, CmdType::ACT, { 2, 0, 0 }  },\n\t\t{  25, CmdType::WRA, { 1, 0, 0 }  },\n\t\t{  30, CmdType::PRE, { 0, 0, 0 }  },\n\t\t{  35, CmdType::RDA, { 2, 0, 0 }  },\n\t\t{  50, CmdType::ACT, { 0, 0, 0 }  },\n\t\t{  50, CmdType::ACT, { 2, 0, 0 }  },\n\t\t{  60, CmdType::WRA, { 0, 0, 0 }  },\n\t\t{  60, CmdType::RDA, { 2, 0, 0 }  },\n\t\t{  75, CmdType::ACT, { 1, 0, 0 }  },\n\t\t{  80, CmdType::ACT, { 0, 0, 0 }  },\n\t\t{  85, CmdType::WRA, { 0, 0, 0 }  },\n\t\t{  95, CmdType::RDA, { 1, 0, 0 }  },\n\t\t{ 125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        auto memSpec = DRAMPower::MemSpecDDR5::from_memspec(*data);\n\n\t\tmemSpec.bitWidth = 16;\n\t\tmemSpec.numberOfDevices = 1;\n\t\tmemSpec.numberOfRanks = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.banksPerGroup = 8;\n        memSpec.numberOfBankGroups = 1;\n\n\t\tmemSpec.memTimingSpec.tRAS = 20;\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n\t\tmemSpec.memTimingSpec.tWR = 12;\n\t\tmemSpec.memTimingSpec.tWL = 0;\n\t\tmemSpec.memTimingSpec.tCK = 1;\n\t\tmemSpec.memTimingSpec.tRP = 10;\n\n\t\tmemSpec.memPowerSpec[0].vXX = 1;\n\t\tmemSpec.memPowerSpec[0].iXX0 = 64;\n\t\tmemSpec.memPowerSpec[0].iXX2N = 8;\n\t\tmemSpec.memPowerSpec[0].iXX3N = 32;\n\t\tmemSpec.memPowerSpec[0].iXX4R = 72;\n\t\tmemSpec.memPowerSpec[0].iXX4W = 96;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iXX0;\n\t\tmemSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\n        memSpec.memTimingSpec.tBurst = memSpec.burstLength/memSpec.dataRate;\n        memSpec.prechargeOffsetRD      =  memSpec.memTimingSpec.tRTP;\n        memSpec.prechargeOffsetWR      =  memSpec.memTimingSpec.tBurst + memSpec.memTimingSpec.tWL + memSpec.memTimingSpec.tWR;\n\n\n        ddr = std::make_unique<DDR5>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_14, Test)\n{\n\tfor (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\tconst Rank & rank_1 = internal::DDR5TestAccessor.getRanks(ddr->getCore()).at(0);\n\tauto stats = ddr->getStats();\n\n\t// Check global command count\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::ACT), 7);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::PRE), 1);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::RDA), 4);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::WRA), 3);\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 3);\n\tASSERT_EQ(stats.bank[1].counter.act, 2);\n\tASSERT_EQ(stats.bank[2].counter.act, 2);\n\tASSERT_EQ(stats.bank[3].counter.act, 0);\n\tASSERT_EQ(stats.bank[4].counter.act, 0);\n\tASSERT_EQ(stats.bank[5].counter.act, 0);\n\tASSERT_EQ(stats.bank[6].counter.act, 0);\n\tASSERT_EQ(stats.bank[7].counter.act, 0);\n\n\t// Check bank command count: RDA\n\tASSERT_EQ(stats.bank[0].counter.readAuto, 1);\n\tASSERT_EQ(stats.bank[1].counter.readAuto, 1);\n\tASSERT_EQ(stats.bank[2].counter.readAuto, 2);\n\tASSERT_EQ(stats.bank[3].counter.readAuto, 0);\n\tASSERT_EQ(stats.bank[4].counter.readAuto, 0);\n\tASSERT_EQ(stats.bank[5].counter.readAuto, 0);\n\tASSERT_EQ(stats.bank[6].counter.readAuto, 0);\n\tASSERT_EQ(stats.bank[7].counter.readAuto, 0);\n\n\t// Check bank command count: WRA\n\tASSERT_EQ(stats.bank[0].counter.writeAuto, 2);\n\tASSERT_EQ(stats.bank[1].counter.writeAuto, 1);\n\tASSERT_EQ(stats.bank[2].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[3].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[4].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[5].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[6].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[7].counter.writeAuto, 0);\n\n\t// Check cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 100);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 25);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 75);\n\tASSERT_EQ(stats.bank[1].cycles.act, 60);\n\tASSERT_EQ(stats.bank[2].cycles.act, 50);\n\tASSERT_EQ(stats.bank[3].cycles.act, 0);\n\tASSERT_EQ(stats.bank[4].cycles.act, 0);\n\tASSERT_EQ(stats.bank[5].cycles.act, 0);\n\tASSERT_EQ(stats.bank[6].cycles.act, 0);\n\tASSERT_EQ(stats.bank[7].cycles.act, 0);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 50);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 65);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 75);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[6].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 125);\n}\n\nTEST_F(DramPowerTest_DDR5_14, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ(std::round(total_energy.E_bg_act), 1970);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared), 1600);\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_act, 150);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_act, 120);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_act, 100);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_act, 0);\n\n    ASSERT_EQ((int)total_energy.E_bg_pre, 200);\n    ASSERT_EQ((int)energy.bank_energy[0].E_bg_pre, 25);\n    ASSERT_EQ((int)energy.bank_energy[1].E_bg_pre, 25);\n    ASSERT_EQ((int)energy.bank_energy[2].E_bg_pre, 25);\n    ASSERT_EQ((int)energy.bank_energy[3].E_bg_pre, 25);\n    ASSERT_EQ((int)energy.bank_energy[4].E_bg_pre, 25);\n    ASSERT_EQ((int)energy.bank_energy[5].E_bg_pre, 25);\n    ASSERT_EQ((int)energy.bank_energy[6].E_bg_pre, 25);\n    ASSERT_EQ((int)energy.bank_energy[7].E_bg_pre, 25);\n\n\tASSERT_EQ((int)total_energy.E_RDA, 1280);\n\tASSERT_EQ((int)energy.bank_energy[0].E_RDA, 320);\n\tASSERT_EQ((int)energy.bank_energy[1].E_RDA, 320);\n\tASSERT_EQ((int)energy.bank_energy[2].E_RDA, 640);\n\tASSERT_EQ((int)energy.bank_energy[3].E_RDA, 0);\n\tASSERT_EQ((int)energy.bank_energy[4].E_RDA, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_RDA, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_RDA, 0);\n\tASSERT_EQ((int)energy.bank_energy[7].E_RDA, 0);\n\n\tASSERT_EQ((int)total_energy.E_WRA, 1536);\n\tASSERT_EQ((int)energy.bank_energy[0].E_WRA, 1024);\n\tASSERT_EQ((int)energy.bank_energy[1].E_WRA, 512);\n\tASSERT_EQ((int)energy.bank_energy[2].E_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[3].E_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[4].E_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[7].E_WRA, 0);\n\n\tASSERT_EQ((int)total_energy.E_pre_RDA, 2240);\n\tASSERT_EQ((int)energy.bank_energy[0].E_pre_RDA, 560);\n\tASSERT_EQ((int)energy.bank_energy[1].E_pre_RDA, 560);\n\tASSERT_EQ((int)energy.bank_energy[2].E_pre_RDA, 1120);\n\tASSERT_EQ((int)energy.bank_energy[3].E_pre_RDA, 0);\n\tASSERT_EQ((int)energy.bank_energy[4].E_pre_RDA, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_pre_RDA, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_pre_RDA, 0);\n\tASSERT_EQ((int)energy.bank_energy[7].E_pre_RDA, 0);\n\n\tASSERT_EQ((int)total_energy.E_pre_WRA, 1120+560);\n\tASSERT_EQ((int)energy.bank_energy[0].E_pre_WRA, 1120);\n\tASSERT_EQ((int)energy.bank_energy[1].E_pre_WRA, 560);\n\tASSERT_EQ((int)energy.bank_energy[2].E_pre_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[3].E_pre_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[4].E_pre_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_pre_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_pre_WRA, 0);\n\tASSERT_EQ((int)energy.bank_energy[7].E_pre_WRA, 0);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_15.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_15 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{   0, CmdType::ACT,  { 0, 0, 0 }},\n\t\t{   5, CmdType::ACT,  { 1, 0, 0 }},\n\t\t{  10, CmdType::ACT,  { 2, 0, 0 }},\n\t\t{  15, CmdType::PRE,  { 0, 0, 0 }},\n\t\t{  20, CmdType::PREA, { 0, 0, 0 }},\n\t\t{  25, CmdType::PRE,  { 1, 0, 0 }},\n\t\t{  30, CmdType::PREA, { 0, 0, 0 }},\n\t\t{  40, CmdType::ACT,  { 0, 0, 0 }},\n\t\t{  40, CmdType::ACT,  { 3, 0, 0 }},\n\t\t{  50, CmdType::PRE,  { 3, 0, 0 }},\n\t\t{ 125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        auto memSpec = DRAMPower::MemSpecDDR5::from_memspec(*data);\n\n\t\tmemSpec.bitWidth = 16;\n\t\tmemSpec.numberOfDevices = 1;\n\t\tmemSpec.numberOfRanks = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.banksPerGroup = 8;\n        memSpec.numberOfBankGroups = 1;\n\n\t\tmemSpec.memTimingSpec.tRAS = 20;\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n\t\tmemSpec.memTimingSpec.tWR = 20;\n\n\t\tmemSpec.memTimingSpec.tRAS = 20;\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n\t\tmemSpec.memTimingSpec.tWR = 12;\n\t\tmemSpec.memTimingSpec.tWL = 0;\n\t\tmemSpec.memTimingSpec.tCK = 1;\n\t\tmemSpec.memTimingSpec.tRP = 10;\n\n\t\tmemSpec.memPowerSpec[0].vXX = 1;\n\t\tmemSpec.memPowerSpec[0].iXX0 = 64;\n\t\tmemSpec.memPowerSpec[0].iXX2N = 8;\n\t\tmemSpec.memPowerSpec[0].iXX3N = 32;\n\t\tmemSpec.memPowerSpec[0].iXX4R = 72;\n\t\tmemSpec.memPowerSpec[0].iXX4W = 72;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iXX0;\n\n\n        memSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\n        ddr = std::make_unique<DDR5>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_15, Test)\n{\n\tfor (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 2);\n\tASSERT_EQ(stats.bank[1].counter.act, 1);\n\tASSERT_EQ(stats.bank[2].counter.act, 1);\n\tASSERT_EQ(stats.bank[3].counter.act, 1);\n\tASSERT_EQ(stats.bank[4].counter.act, 0);\n\n\t// Check cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 105);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 20);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 100);\n\tASSERT_EQ(stats.bank[1].cycles.act, 15);\n\tASSERT_EQ(stats.bank[2].cycles.act, 10);\n\tASSERT_EQ(stats.bank[3].cycles.act, 10);\n\tASSERT_EQ(stats.bank[4].cycles.act, 0);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 25);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 110);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 115);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 115);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 125);\n}\n\nTEST_F(DramPowerTest_DDR5_15, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ((int)total_energy.E_act, 2300*2);\n\tASSERT_EQ((int)energy.bank_energy[0].E_act, 920*2);\n\tASSERT_EQ((int)energy.bank_energy[1].E_act, 460*2);\n\tASSERT_EQ((int)energy.bank_energy[2].E_act, 460*2);\n\tASSERT_EQ((int)energy.bank_energy[3].E_act, 460*2);\n\tASSERT_EQ((int)energy.bank_energy[4].E_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[7].E_act, 0);\n\n\tASSERT_EQ((int)total_energy.E_pre, 2240);\n\tASSERT_EQ((int)energy.bank_energy[0].E_pre, 560);\n\tASSERT_EQ((int)energy.bank_energy[1].E_pre, 560);\n\tASSERT_EQ((int)energy.bank_energy[2].E_pre, 560);\n\tASSERT_EQ((int)energy.bank_energy[3].E_pre, 560);\n\tASSERT_EQ((int)energy.bank_energy[4].E_pre, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_pre, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_pre, 0);\n\tASSERT_EQ((int)energy.bank_energy[7].E_pre, 0);\n\n\tASSERT_EQ(std::round(total_energy.E_bg_act), 1950);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared), 1680);\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_act, 200);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_act, 30);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_act, 20);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_act, 20);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_act, 0);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_act, 0);\n\n\tASSERT_EQ((int)total_energy.E_bg_pre, 160);\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_pre, 20);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_pre, 20);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_pre, 20);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_pre, 20);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_pre, 20);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_pre, 20);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_pre, 20);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_pre, 20);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_16.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_16 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{  0, CmdType::REFSB, {0, 0, 0 }},\n\t\t{ 10, CmdType::REFSB, {1, 0, 0 }},\n\t\t{ 45, CmdType::REFSB, {2, 0, 0 }},\n\t\t{ 50, CmdType::ACT  , {7, 0, 0 }},\n\t\t{ 55, CmdType::ACT  , {3, 0, 0 }},\n\t\t{ 70, CmdType::PRE  , {7, 0, 0 }},\n\t\t{ 80, CmdType::PRESB, {3, 0, 0 }},\n\t\t{ 95, CmdType::REFSB, {3, 0, 0 }},\n\t\t{100, CmdType::REFSB, {0, 0, 0 }},\n\t\t{125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        auto memSpec = DRAMPower::MemSpecDDR5::from_memspec(*data);\n\n\t\tmemSpec.bitWidth = 16;\n\t\tmemSpec.numberOfDevices = 1;\n        memSpec.numberOfRanks = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.numberOfBankGroups = 2;\n        memSpec.banksPerGroup = 4;\n\n        memSpec.memTimingSpec.tRAS = 10;\n        memSpec.memTimingSpec.tRTP = 10;\n        memSpec.memTimingSpec.tRFCsb = 25;\n\n        memSpec.memTimingSpec.tWR = 20;\n        memSpec.memTimingSpec.tWL = 0;\n        memSpec.memTimingSpec.tCK = 1;\n        memSpec.memTimingSpec.tRP = 10;\n\n        memSpec.memPowerSpec[0].vXX = 1;\n        memSpec.memPowerSpec[0].iXX0 = 64;\n        memSpec.memPowerSpec[0].iXX2N = 8;\n        memSpec.memPowerSpec[0].iXX3N = 32;\n        memSpec.memPowerSpec[0].iXX4R = 72;\n        memSpec.memPowerSpec[0].iXX4W = 72;\n        memSpec.memPowerSpec[0].iXX5C = 28;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iXX0;\n\n\n        memSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n        memSpec.burstLength = 16;\n        memSpec.dataRate = 2;\n\n\n        ddr = std::make_unique<DDR5>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_16, Test)\n{\n\tfor (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[3].counter.act, 1);\n\tASSERT_EQ(stats.bank[7].counter.act, 1);\n\n\t// Check bank command count: PRE\n\tASSERT_EQ(stats.bank[3].counter.pre, 1);\n\tASSERT_EQ(stats.bank[7].counter.pre, 1);\n\n\t// Check bank command count: REFSB\n\tASSERT_EQ(stats.bank[0].counter.refSameBank, 2);\n    ASSERT_EQ(stats.bank[4].counter.refSameBank, 2);\n\n\tASSERT_EQ(stats.bank[1].counter.refSameBank, 1);\n\tASSERT_EQ(stats.bank[2].counter.refSameBank, 1);\n\tASSERT_EQ(stats.bank[3].counter.refSameBank, 1);\n\tASSERT_EQ(stats.bank[5].counter.refSameBank, 1);\n\tASSERT_EQ(stats.bank[6].counter.refSameBank, 1);\n\tASSERT_EQ(stats.bank[7].counter.refSameBank, 1);\n\n\t// Check global cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 100);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 25);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 50);\n\tASSERT_EQ(stats.bank[4].cycles.act, 50);\n\tASSERT_EQ(stats.bank[3].cycles.act, 50);\n\tASSERT_EQ(stats.bank[1].cycles.act, 25);\n\tASSERT_EQ(stats.bank[2].cycles.act, 25);\n\tASSERT_EQ(stats.bank[5].cycles.act, 25);\n\tASSERT_EQ(stats.bank[6].cycles.act, 25);\n\tASSERT_EQ(stats.bank[7].cycles.act, 45);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 75);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 75);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 75);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 100);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 100);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 100);\n\tASSERT_EQ(stats.bank[6].cycles.pre, 100);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 80);\n}\n\nTEST_F(DramPowerTest_DDR5_16, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ(std::round(total_energy.E_bg_act), 2190);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared), 1600);\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_act, 100);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_act, 100);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_act, 100);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_act, 90);\n\n\tASSERT_EQ((int)total_energy.E_bg_pre, 200);\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_pre, 25);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_pre, 25);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_pre, 25);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_pre, 25);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_pre, 25);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_pre, 25);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_pre, 25);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_pre, 25);\n\n\tASSERT_EQ((int)total_energy.E_pre, 1120);\n\tASSERT_EQ((int)energy.bank_energy[3].E_pre, 560);\n\tASSERT_EQ((int)energy.bank_energy[7].E_pre, 560);\n\n    ASSERT_EQ((int)total_energy.E_ref_SB, 1000);\n\tASSERT_EQ((int)energy.bank_energy[0].E_ref_SB, 200);\n\tASSERT_EQ((int)energy.bank_energy[1].E_ref_SB, 100);\n\tASSERT_EQ((int)energy.bank_energy[2].E_ref_SB, 100);\n\tASSERT_EQ((int)energy.bank_energy[3].E_ref_SB, 100);\n\tASSERT_EQ((int)energy.bank_energy[4].E_ref_SB, 200);\n\tASSERT_EQ((int)energy.bank_energy[5].E_ref_SB, 100);\n\tASSERT_EQ((int)energy.bank_energy[6].E_ref_SB, 100);\n\tASSERT_EQ((int)energy.bank_energy[7].E_ref_SB, 100);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_17.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_17 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{  0,  CmdType::ACT, {0, 0, 0} },\n\t\t{ 20,  CmdType::PDEA },\n\t\t{ 30,  CmdType::PDXA },\n\t\t{ 40,  CmdType::PRE, {0, 0, 0} },\n\t\t{ 60,  CmdType::PDEP },\n\t\t{ 65,  CmdType::PDXP },\n\t\t{ 75,  CmdType::REFA },\n\t\t{100,  CmdType::PDEP },\n\t\t{125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        auto memSpec = DRAMPower::MemSpecDDR5::from_memspec(*data);\n\n\t\tmemSpec.bitWidth = 16;\n\t\tmemSpec.numberOfDevices = 1;\n\t\tmemSpec.numberOfRanks = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.numberOfBankGroups = 2;\n        memSpec.banksPerGroup = 4;\n\n\t\tmemSpec.memTimingSpec.tRAS = 10;\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n\t\tmemSpec.memTimingSpec.tRCD = 20;\n\t\tmemSpec.memTimingSpec.tRFC = 25;\n\n\t\tmemSpec.memTimingSpec.tWR = 20;\n\t\tmemSpec.memTimingSpec.tRP = 20;\n\t\tmemSpec.memTimingSpec.tWL = 0;\n\t\tmemSpec.memTimingSpec.tCK = 1;\n\n\t\tmemSpec.memPowerSpec[0].vXX = 1;\n\t\tmemSpec.memPowerSpec[0].iXX0 = 64;\n\t\tmemSpec.memPowerSpec[0].iXX2N = 8;\n\t\tmemSpec.memPowerSpec[0].iXX2P = 6;\n\t\tmemSpec.memPowerSpec[0].iXX3N = 32;\n\t\tmemSpec.memPowerSpec[0].iXX3P = 20;\n\t\tmemSpec.memPowerSpec[0].iXX4R = 72;\n\t\tmemSpec.memPowerSpec[0].iXX4W = 72;\n\t\tmemSpec.memPowerSpec[0].iXX5C = 28;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iXX0;\n\n\n        memSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\n        ddr = std::make_unique<DDR5>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_17, Test)\n{\n\tfor (const auto& command : testPattern) {\n\t\tddr->doCoreCommand(command);\n\t};\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 1);\n\n\t// Check bank command count: PRE\n\tASSERT_EQ(stats.bank[0].counter.pre, 1);\n\n\t// Check global cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.activeTime(), 55);\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 55);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 30);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 55); ASSERT_EQ(stats.bank[0].cycles.activeTime(), 55);\n\tASSERT_EQ(stats.bank[1].cycles.act, 25); ASSERT_EQ(stats.bank[1].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[2].cycles.act, 25); ASSERT_EQ(stats.bank[2].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[3].cycles.act, 25); ASSERT_EQ(stats.bank[3].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[4].cycles.act, 25); ASSERT_EQ(stats.bank[4].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[5].cycles.act, 25); ASSERT_EQ(stats.bank[5].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[6].cycles.act, 25); ASSERT_EQ(stats.bank[6].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[7].cycles.act, 25); ASSERT_EQ(stats.bank[7].cycles.activeTime(), 25);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 30);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[6].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 60);\n}\n\nTEST_F(DramPowerTest_DDR5_17, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ(std::round(total_energy.E_bg_act), 1340);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared), 880);\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_act, 110);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_act, 50);\n\n\tASSERT_EQ((int)total_energy.E_bg_pre, 240);\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_pre, 30);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_pre, 30);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_pre, 30);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_pre, 30);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_pre, 30);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_pre, 30);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_pre, 30);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_pre, 30);\n\n\tASSERT_EQ((int)energy.E_PDNA, 200);\n\tASSERT_EQ((int)energy.E_PDNP, 180);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_18.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_18 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{  0,  CmdType::ACT, { 0,0,0} },\n\t\t{  5,  CmdType::PDEA },\n\t\t{ 30,  CmdType::PDXA },\n\t\t{ 40,  CmdType::PRE, {0,0,0} },\n\t\t{ 45,  CmdType::PDEP },\n\t\t{ 65,  CmdType::PDXP },\n\t\t{ 75,  CmdType::REFA },\n\t\t{ 85,  CmdType::PDEP },\n\t\t{ 90,  CmdType::PDXP },\n\t\t{125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        auto memSpec = DRAMPower::MemSpecDDR5::from_memspec(*data);\n\n\t\tmemSpec.bitWidth = 16;\n\t\tmemSpec.numberOfDevices = 1;\n\t\tmemSpec.numberOfRanks = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.numberOfBankGroups = 2;\n        memSpec.banksPerGroup = 4;\n\n\t\tmemSpec.memTimingSpec.tRAS = 10;\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n\t\tmemSpec.memTimingSpec.tRCD = 20;\n\t\tmemSpec.memTimingSpec.tRFC = 25;\n\n\t\tmemSpec.memTimingSpec.tWR = 20;\n\t\tmemSpec.memTimingSpec.tRP = 20;\n\t\tmemSpec.memTimingSpec.tWL = 0;\n\t\tmemSpec.memTimingSpec.tCK = 1;\n\n\t\tmemSpec.memPowerSpec[0].vXX = 1;\n\t\tmemSpec.memPowerSpec[0].iXX0 = 64;\n\t\tmemSpec.memPowerSpec[0].iXX2N = 8;\n\t\tmemSpec.memPowerSpec[0].iXX2P = 6;\n\t\tmemSpec.memPowerSpec[0].iXX3N = 32;\n\t\tmemSpec.memPowerSpec[0].iXX3P = 20;\n\t\tmemSpec.memPowerSpec[0].iXX4R = 72;\n\t\tmemSpec.memPowerSpec[0].iXX4W = 72;\n\t\tmemSpec.memPowerSpec[0].iXX5C = 28;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iXX0;\n\n\n        memSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\n        ddr = std::make_unique<DDR5>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_18, Test)\n{\n\tfor (const auto& command : testPattern) {\n\t\tddr->doCoreCommand(command);\n\t};\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 1);\n\n\t// Check bank command count: PRE\n\tASSERT_EQ(stats.bank[0].counter.pre, 1);\n\n\t// Check global cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 55);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 55);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 5);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 55);\n\tASSERT_EQ(stats.bank[1].cycles.act, 25);\n\tASSERT_EQ(stats.bank[2].cycles.act, 25);\n\tASSERT_EQ(stats.bank[3].cycles.act, 25);\n\tASSERT_EQ(stats.bank[4].cycles.act, 25);\n\tASSERT_EQ(stats.bank[5].cycles.act, 25);\n\tASSERT_EQ(stats.bank[6].cycles.act, 25);\n\tASSERT_EQ(stats.bank[7].cycles.act, 25);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 55);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[6].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 85);\n}\n\nTEST_F(DramPowerTest_DDR5_18, CalcWindow)\n{\n\tSimulationStats window;\n\n\tauto iterate_to_timestamp = [this](auto & command, timestamp_t timestamp) {\n\t\twhile (command != this->testPattern.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\n\t\treturn this->ddr->getWindowStats(timestamp);\n\t};\n\n\tauto command = testPattern.begin();\n\n\n\t// Cycle 5\n\twindow = iterate_to_timestamp(command, 5);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 5);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 5);\n\n\t// Cycle 10\n\twindow = iterate_to_timestamp(command, 10);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 10);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act,  0);   ASSERT_EQ(window.bank[1].cycles.pre, 10);\n\n\t// Cycle 15\n\twindow = iterate_to_timestamp(command, 15);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 15);\n\tASSERT_EQ(window.bank[0].cycles.act, 15);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 15);\n\n\t// Cycle 20\n\twindow = iterate_to_timestamp(command, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 20);\n\tASSERT_EQ(window.bank[0].cycles.act, 20);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 20);\n\n\t// Cycle 25\n\twindow = iterate_to_timestamp(command, 25);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 20);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 20);\n\n\t// Cycle 30\n\twindow = iterate_to_timestamp(command, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 20);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 20);\n\n\t// Cycle 35\n\twindow = iterate_to_timestamp(command, 35);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 25);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 25);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 25);\n\n\t// Cycle 40\n\twindow = iterate_to_timestamp(command, 40);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act,  0);  ASSERT_EQ(window.bank[1].cycles.pre, 30);\n\n\t// Cycle 45\n\twindow = iterate_to_timestamp(command, 45);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre,  5);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 35);\n\n\t// Cycle 50\n\twindow = iterate_to_timestamp(command, 50);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 10);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 10);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 40);\n\n\t// Cycle 55\n\twindow = iterate_to_timestamp(command, 55);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 15);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 15);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 45);\n\n\t// Cycle 60\n\twindow = iterate_to_timestamp(command, 60);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 20);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 50);\n\n\t// Cycle 65\n\twindow = iterate_to_timestamp(command, 65);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 20);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 50);\n\n\t// Cycle 70\n\twindow = iterate_to_timestamp(command, 70);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 25);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 25);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 55);\n\n\t// Cycle 75\n\twindow = iterate_to_timestamp(command, 75);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 80\n\twindow = iterate_to_timestamp(command, 80);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 35);    ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 35);  ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 5);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 85\n\twindow = iterate_to_timestamp(command, 85);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 40);     ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 40);   ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 10);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 90\n\twindow = iterate_to_timestamp(command, 90);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 45);     ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 45);   ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 15);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 95\n\twindow = iterate_to_timestamp(command, 95);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 50);     ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 50);   ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 20);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 100\n\twindow = iterate_to_timestamp(command, 100);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 105\n\twindow = iterate_to_timestamp(command, 105);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 35);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 35);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 65);\n\n\t// Cycle 110\n\twindow = iterate_to_timestamp(command, 110);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 40);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 40);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 70);\n\n\t// Cycle 115\n\twindow = iterate_to_timestamp(command, 115);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 45);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 45);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 75);\n\n\t// Cycle 120\n\twindow = iterate_to_timestamp(command, 120);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 50);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 50);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 80);\n\n\t// Cycle 125\n\twindow = iterate_to_timestamp(command, 125);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 55);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 55);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 85);\n};\n\n\n\nTEST_F(DramPowerTest_DDR5_18, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ(std::round(total_energy.E_bg_act), 1340);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared), 880);\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_act, 110);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_act, 50);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_act, 50);\n\n\tASSERT_EQ((int)total_energy.E_bg_pre, 440);\n\tASSERT_EQ((int)energy.bank_energy[0].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[1].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[2].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[3].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[4].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[5].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[6].E_bg_pre, 55);\n\tASSERT_EQ((int)energy.bank_energy[7].E_bg_pre, 55);\n\n\tASSERT_EQ((int)energy.E_PDNA, 200);\n\tASSERT_EQ((int)energy.E_PDNP, 30);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_2.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_2 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   35, CmdType::PRE,  { 0, 0, 0 }},\n            { 50, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecDDR5> memSpec;\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR5>(DRAMPower::MemSpecDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<DDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_2, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    ASSERT_EQ(stats.bank[0].counter.act, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.act, 0);\n\n    // Check bank command count: RD\n    ASSERT_EQ(stats.bank[0].counter.reads, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.reads, 0);\n\n    // Check bank command count: PRE\n    ASSERT_EQ(stats.bank[0].counter.pre, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.pre, 0);\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 35);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 15);\n\n    // Check bank specific ACT cycle count\n    ASSERT_EQ(stats.bank[0].cycles.act, 35);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.act, 0);\n\n    // Check bank specific PRE cycle count\n    ASSERT_EQ(stats.bank[0].cycles.pre, 15);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.pre, 50);\n}\n\nTEST_F(DramPowerTest_DDR5_2, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 179);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 208);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 436);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1189);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1183);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 467);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 2479);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_3.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_3 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::PRE,  { 0, 0, 0 }},\n            {   45, CmdType::PRE,  { 3, 0, 0 }},\n            { 50, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecDDR5> memSpec;\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR5>(DRAMPower::MemSpecDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<DDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_3, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    };\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 45);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 5);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 35);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 25);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 0);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 15);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 25);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 50);\n    }\n}\n\nTEST_F(DramPowerTest_DDR5_3, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 359);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 436);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1531);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1521);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 156);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 2897);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_4.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_4 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::RD,  { 3, 0, 0 }},\n            {   40, CmdType::RD,  { 0, 0, 0 }},\n            {   50, CmdType::PREA,  { 0, 0, 0 }},\n            { 70, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecDDR5> memSpec;\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR5>(DRAMPower::MemSpecDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<DDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_4, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].counter.reads, 2);\n        else if( b == 3)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    };\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 50);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 20);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 50);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 30);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 0);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 20);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 40);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 70);\n    }\n}\n\nTEST_F(DramPowerTest_DDR5_4, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 359);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 1307);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1704);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1690);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 623);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 4408);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_5.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_5 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::RD,  { 3, 0, 0 }},\n            {   40, CmdType::RD,  { 0, 0, 0 }},\n            {   50, CmdType::PREA,  { 0, 0, 0 }},\n            {   65, CmdType::REFA,  { 0, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecDDR5> memSpec;\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR5>(DRAMPower::MemSpecDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<DDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_5, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].counter.reads, 2);\n        else if( b == 3)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    };\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check bank command count: REFA\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        ASSERT_EQ(stats.bank[b].counter.refAllBank, 1);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 75);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 25);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 75);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 55);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 25);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 25);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 45);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 75);\n    }\n}\n\nTEST_F(DramPowerTest_DDR5_5, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 359);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 1307);\n    ASSERT_EQ(std::round(total_energy.E_ref_AB*1e12), 1812);\n    ASSERT_EQ(std::round(total_energy.E_ref_SB*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 2615);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 2536);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 779);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 7287);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_6.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_6 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RDA,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::RD,  { 3, 0, 0 }},\n            {   50, CmdType::PREA,  { 0, 0, 0 }},\n            {   65, CmdType::REFA,  { 0, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecDDR5> memSpec;\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR5>(DRAMPower::MemSpecDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<DDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_6, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 3)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    }\n\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].counter.readAuto, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.readAuto, 0);\n    }\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check bank command count: REFA\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        ASSERT_EQ(stats.bank[b].counter.refAllBank, 1);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 75);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 25);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 45);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 55);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 25);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 55);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 45);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 75);\n    }\n}\n\nTEST_F(DramPowerTest_DDR5_6, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 359);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 436);\n    ASSERT_EQ(std::round(total_energy.E_RDA*1e12), 436);\n    ASSERT_EQ(std::round(total_energy.E_ref_AB*1e12), 1812);\n    ASSERT_EQ(std::round(total_energy.E_ref_SB*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 2610);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 2536);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 779);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 6846);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_7.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_7 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::SREFEN,  { 0, 0, 0 }},\n            {   40, CmdType::SREFEX,  { 0, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecDDR5> memSpec;\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR5>(DRAMPower::MemSpecDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<DDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_7, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].counter.act, 0);\n\n    // Check bank command count: REFA\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].counter.refAllBank, 1);\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 25);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 60);\n    ASSERT_EQ(stats.rank_total[0].cycles.selfRefresh, 15);\n\n    // Check bank specific ACT cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.act, 25);\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.pre, 60);\n\n    // Check bank specific SREF cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.selfRefresh, 15);\n}\n\nTEST_F(DramPowerTest_DDR5_7, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_ref_AB*1e12), 1812);\n    ASSERT_EQ(std::round(energy.E_sref*1e12), 280);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 912);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 845);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 1869);\n    ASSERT_EQ(std::round((total_energy.total() + energy.E_sref)*1e12), 4873);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_8.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_8 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::PDEA,  { 0, 0, 0 }},\n            {   30, CmdType::PDXA,  { 0, 0, 0 }},\n            {   45, CmdType::PDEP,  { 0, 0, 0 }},\n            {   70, CmdType::PDXP,  { 0, 0, 0 }},\n            { 85, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecDDR5> memSpec;\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR5>(DRAMPower::MemSpecDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<DDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_8, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 30);\n    ASSERT_EQ(stats.rank_total[0].cycles.selfRefresh, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 30);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 25);\n\n    // Check bank specific ACT cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.act, 0);\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.pre, 30);\n\n    // Check bank specific PDNA cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownAct, 30);\n\n    // Check bank specific PDNP cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownPre, 25);\n\n    // Check bank specific SREF cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.selfRefresh, 0);\n}\n\nTEST_F(DramPowerTest_DDR5_8, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_sref*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_PDNA*1e12), 623);\n    ASSERT_EQ(std::round(energy.E_PDNP*1e12), 392);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 935);\n    ASSERT_EQ(std::round((total_energy.total() + energy.E_sref + energy.E_PDNA + energy.E_PDNP)*1e12), 1950);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/DDR5/ddr5_test_pattern_9.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/ddr5/DDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_DDR5_9 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   5, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::ACT,  { 5, 0, 0 }},\n            {   20, CmdType::RD,  { 0, 0, 0 }},\n            {   30, CmdType::PDEA,  { 0, 0, 0 }},\n            {   50, CmdType::PDXA,  { 0, 0, 0 }},\n            {   55, CmdType::RD,  { 5, 0, 0 }},\n            {   60, CmdType::RD,  { 0, 0, 0 }},\n            {   70, CmdType::PREA,  { 0, 0, 0 }},\n            {   80, CmdType::PDEP,  { 0, 0, 0 }},\n            {   95, CmdType::PDXP,  { 0, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecDDR5> memSpec;\n    std::unique_ptr<DRAMPower::DDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecDDR5>(DRAMPower::MemSpecDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<DDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_DDR5_9, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 45);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 20);\n    ASSERT_EQ(stats.rank_total[0].cycles.selfRefresh, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 20);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 15);\n\n    // Check bank specific ACT cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0){\n            ASSERT_EQ(stats .bank[b].cycles.act, 45);\n        }else if (b == 5){\n            ASSERT_EQ(stats .bank[b].cycles.act, 35);\n        }else{\n            ASSERT_EQ(stats .bank[b].cycles.act, 0);\n        }\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 20);\n        }else if (b == 5){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 30);\n        }else{\n            ASSERT_EQ(stats.bank[b].cycles.pre, 65);\n        }\n    }\n\n    // Check bank specific PDNA cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownAct, 20);\n\n    // Check bank specific PDNP cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownPre, 15);\n\n    // Check bank specific SREF cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.selfRefresh, 0);\n}\n\nTEST_F(DramPowerTest_DDR5_9, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 359);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 1307);\n    ASSERT_EQ(std::round(energy.E_sref*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_PDNA*1e12), 415);\n    ASSERT_EQ(std::round(energy.E_PDNP*1e12), 235);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1535);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1521);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 623);\n    ASSERT_EQ(std::round((total_energy.total() + energy.E_sref + energy.E_PDNA + energy.E_PDNP)*1e12), 4890);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_multidevice_tests.cpp",
    "content": "/* Note\nThis test is based on lpddr4_test_pattern_4.cpp and assumes the correctness of the test.\n\nCalculation for 5 devices:\nE_act: \t\t\t\t\t392.30769230769232\nE_pre: \t\t\t\t\t415.38461538461542\nE_RD:\t\t\t\t\t1356.9230769230769\nE_bg_act:\t\t\t\t1632.6923076923078\nE_bg_act_shared:\t\t1586.5384615384617\nE_bg_pre:\t\t\t\t623.07692307692309\nTotal:\t\t\t\t\t4420.3846153846162\n\nE_act * 5:\t\t\t\t1961.5384615384616\nE_pre * 5:\t\t\t\t2076.9230769230771\nE_RD * 5:\t\t\t\t6784.6153846153845\nE_bg_act * 5:\t\t\t8163.461538461539\nE_bg_act_shared * 5:\t7932.6923076923085\nE_bg_pre * 5:\t\t\t3115.38461538461545\nTotal * 5:\t\t\t\t22101.923076923081\n*/\n\n\n#include <gtest/gtest.h>\n\n#include <DRAMPower/command/Command.h>\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_MultiDevice : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::RD,  { 3, 0, 0 }},\n            {   40, CmdType::RD,  { 0, 0, 0 }},\n            {   50, CmdType::PREA,  { 0, 0, 0 }},\n            { 70, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR4> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n    uint64_t numberOfDevices;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*data));\n\n        memSpec->numberOfDevices = 5;\n\n        numberOfDevices = memSpec->numberOfDevices;\n        ddr = std::make_unique<LPDDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_MultiDevice, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].counter.reads, 2);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    };\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 50);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 20);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 50);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 30);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 0);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 20);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 40);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 70);\n    }\n}\n\nTEST_F(DramPowerTest_LPDDR4_MultiDevice, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(energy.bank_energy.size(), numberOfDevices * memSpec->numberOfBanks);\n\n    // Validate every device has the same bank energy\n    for(size_t i = 0; i < numberOfDevices; i++){\n        for(size_t j = 0; j < memSpec->numberOfBanks; j++){\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_act, energy.bank_energy[j].E_act);\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_pre, energy.bank_energy[j].E_pre);\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_RD, energy.bank_energy[j].E_RD);\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_bg_act, energy.bank_energy[j].E_bg_act);\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_bg_pre, energy.bank_energy[j].E_bg_pre);\n        }\n    }\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 1962);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 2077);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 6785);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 8163);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 7933);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 3115);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 22102);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_multirank_tests.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <fstream>\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n#include <variant>\n\n#include \"DRAMPower/command/Command.h\"\n#include \"DRAMPower/standards/lpddr4/LPDDR4.h\"\n#include \"DRAMPower/memspec/MemSpecLPDDR4.h\"\n\nusing DRAMPower::CmdType;\nusing DRAMPower::Command;\nusing DRAMPower::LPDDR4;\nusing DRAMPower::MemSpecLPDDR4;\nusing DRAMPower::SimulationStats;\nusing DRAMPower::TargetCoordinate;\n\n#define SZ_BITS(x) sizeof(x)*8\n\nstatic constexpr uint8_t wr_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 255,  0, 0, 0, 0,  0, 0, 0, 0,\n    0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 255,\n};\n\nstatic constexpr uint8_t rd_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 1,  0, 0, 0, 0,  0, 0, 0, 0,\n    0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,\n};\n\nclass LPDDR4_MultirankTests : public ::testing::Test {\n  public:\n    LPDDR4_MultirankTests() {\n\n        initSpec();\n        ddr = std::make_unique<LPDDR4>(*spec);\n    }\n\n    void initSpec() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        spec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*data));\n\n        spec->numberOfRanks = 2;\n    }\n\n    void runCommands(const std::vector<Command> &commands) {\n        for (const Command &command : commands) {\n            ddr->doCoreCommand(command);\n            ddr->doInterfaceCommand(command);\n        }\n    }\n\n    inline size_t bankIndex(int bank, int rank) {\n        return rank * spec->numberOfBanks + bank;\n    }\n\n    std::unique_ptr<MemSpecLPDDR4> spec;\n    std::unique_ptr<LPDDR4> ddr;\n};\n\nTEST_F(LPDDR4_MultirankTests, Pattern_1) {\n    runCommands({\n        {0, CmdType::ACT, {1, 0, 0}},  // rank 0\n        {4, CmdType::ACT, {1, 0, 1}},  // rank 1\n        {8, CmdType::WR, {1, 0, 0, 0, 4}, wr_data, SZ_BITS(wr_data)},   // rank 0\n        {24, CmdType::RD, {1, 0, 1, 0, 4}, rd_data, SZ_BITS(rd_data)},  // rank 1\n        {38, CmdType::PRE, {1, 0, 1}},  // rank 1\n        {40, CmdType::PRE, {1, 0, 0}},  // rank 0\n        {45, CmdType::END_OF_SIMULATION}\n    });\n    // Act count for rank 0: act = 40 - 0 = 40\n    // Act count for rank 1: act = 38 - 4 = 34\n    // Pre count for rank 0: pre = 45 - 40 = 5\n    // Pre count for rank 1: pre = 45 - 34 = 11\n\n    SimulationStats stats = ddr->getStats();\n    EXPECT_EQ(stats.bank.size(), spec->numberOfBanks * spec->numberOfRanks);\n    EXPECT_EQ(stats.bank[bankIndex(1, 0)].cycles.act, 40);\n    EXPECT_EQ(stats.bank[bankIndex(1, 1)].cycles.act, 34);\n    EXPECT_EQ(stats.bank[bankIndex(1, 0)].cycles.pre, 5);\n    EXPECT_EQ(stats.bank[bankIndex(1, 1)].cycles.pre, 11);\n\n    EXPECT_EQ(stats.rank_total[0].cycles.act, 40);\n    EXPECT_EQ(stats.rank_total[1].cycles.act, 34);\n}\n\nTEST_F(LPDDR4_MultirankTests, Pattern_2) {\n    runCommands({\n        {0, CmdType::ACT,   TargetCoordinate{0, 0, 0}}, // r0\n        {5, CmdType::ACT,   TargetCoordinate{0, 0, 1}}, // r1\n        {22, CmdType::ACT,  TargetCoordinate{3, 0, 1}}, // r1\n        {35, CmdType::RD,   TargetCoordinate{3, 0, 1, 0, 0}, rd_data, SZ_BITS(rd_data)}, // r1\n        {55, CmdType::RD,   TargetCoordinate{0, 0, 0, 0, 3}, rd_data, SZ_BITS(rd_data)}, // r0\n        {60, CmdType::PREA, TargetCoordinate{0, 0, 0}}, // r0\n        {65, CmdType::PREA, TargetCoordinate{0, 0, 1}}, // r1\n        {75, CmdType::REFA, TargetCoordinate{0, 0, 0}}, // r0\n        {80, CmdType::REFA, TargetCoordinate{0, 0, 1}}, // r1\n        {130, CmdType::END_OF_SIMULATION},\n    });\n\n    // t = 0 ACT               -> Start activate // r0, b0\n    // t = 5 ACT               -> Start activate // r1, b0\n    // t = 22 ACT              -> Start activate // r1, b3\n    // t = 35 RD               -> Read // r1, b3\n    // t = 55 RD               -> Read // r0, b0\n    // t = 60 PREA             -> End activate // r0, b0\n    // t = 65 PREA             -> End activate // r1, b0, b3\n    // t = 75 REFA             -> Start activate // r0, b0\n    // t = 80 REFA             -> Start activate // r1, b0, b3\n    // t = 100 REFA (implicit) -> End activate // r0, b0\n    // t = 105 REFA (implicit) -> End activate // r1, b0, b3\n    // t = 130 END_OF_SIMULATION\n\n    SimulationStats stats = ddr->getStats();\n    EXPECT_EQ(stats.bank.size(), spec->numberOfBanks * spec->numberOfRanks);\n    EXPECT_EQ(stats.bank[bankIndex(0, 0)].cycles.act, 85);\n    EXPECT_EQ(stats.bank[bankIndex(0, 1)].cycles.act, 85);\n    EXPECT_EQ(stats.bank[bankIndex(3, 1)].cycles.act, 68);\n\n    EXPECT_EQ(stats.bank[bankIndex(0, 0)].cycles.pre, 130 - 85);\n    EXPECT_EQ(stats.bank[bankIndex(0, 1)].cycles.pre, 130 - 85);\n    EXPECT_EQ(stats.bank[bankIndex(3, 1)].cycles.pre,  130 - 68);\n\n    EXPECT_EQ(stats.rank_total[0].cycles.act, 85);\n    EXPECT_EQ(stats.rank_total[1].cycles.act, 85);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_0.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_0 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::PRE,  { 0, 0, 0 }},\n            { 15, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR4> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_0, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    ASSERT_EQ(stats.bank[0].counter.act, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].counter.act, 0);\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 15);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 0);\n\n    // Check bank specific ACT cycle count\n    ASSERT_EQ(stats.bank[0].cycles.act, 15);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.act, 0);\n\n    // Check bank specific PRE cycle count\n    ASSERT_EQ(stats.bank[0].cycles.pre, 0);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.pre, 15);\n}\n\nTEST_F(DramPowerTest_LPDDR4_0, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 196);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 208);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 476);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 485);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 888);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_1.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_1 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   35, CmdType::PRE,  { 0, 0, 0 }},\n            { 35, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR4> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_1, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    ASSERT_EQ(stats.bank[0].counter.act, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.act, 0);\n\n    // Check bank command count: RD\n    ASSERT_EQ(stats.bank[0].counter.reads, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.reads, 0);\n\n    // Check bank command count: PRE\n    ASSERT_EQ(stats.bank[0].counter.pre, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.pre, 0);\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 35);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 0);\n\n    // Check bank specific ACT cycle count\n    ASSERT_EQ(stats.bank[0].cycles.act, 35);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.act, 0);\n\n    // Check bank specific PRE cycle count\n    ASSERT_EQ(stats.bank[0].cycles.pre, 0);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.pre, 35);\n}\n\nTEST_F(DramPowerTest_LPDDR4_1, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 196);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 208);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 452);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1131);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1111);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 1987);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_10.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_10 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   5, CmdType::ACT,  { 2, 0, 0 }},\n            {   15, CmdType::ACT,  { 10, 0, 0 }},\n            {   30, CmdType::PREA,  { 0, 0, 0 }},\n            {   40, CmdType::REFB,  { 9, 0, 0 }},\n            {   50, CmdType::REFB,  { 5, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR4> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_10, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 60);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 40);\n    ASSERT_EQ(stats.rank_total[0].cycles.selfRefresh, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 0);\n\n    // Check bank specific ACT cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0){\n            ASSERT_EQ(stats .bank[b].cycles.act, 30);\n        }else if (b == 2){\n            ASSERT_EQ(stats .bank[b].cycles.act, 25);\n        }else if(b == 10){\n            ASSERT_EQ(stats .bank[b].cycles.act, 15);\n        }else if (b == 5 || b == 9){\n            ASSERT_EQ(stats .bank[b].cycles.act, 20);\n        }else{\n            ASSERT_EQ(stats .bank[b].cycles.act, 0);\n        }\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 70);\n        }else if (b == 2){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 75);\n        }else if (b== 10){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 85);\n        }else if (b == 5 || b == 9){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 80);\n        }else{\n            ASSERT_EQ(stats.bank[b].cycles.pre, 100);\n        }\n    }\n\n    // Check bank specific PDNA cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownAct, 0);\n\n    // Check bank specific PDNP cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownPre, 0);\n\n    // Check bank specific SREF cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.selfRefresh, 0);\n}\n\nTEST_F(DramPowerTest_LPDDR4_10, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 588);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 623);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_ref_2B*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_ref_PB*1e12), 140);\n    ASSERT_EQ(std::round(energy.E_sref*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_PDNA*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_PDNP*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1967);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1904);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 1246);\n    ASSERT_EQ(std::round((total_energy.total() + energy.E_sref + energy.E_PDNA + energy.E_PDNP)*1e12), 4565);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_11.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n#include <DRAMPower/standards/test_accessor.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_11 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n    // Timestamp,   Cmd,  { Bank, BG, Rank}\n        {   0, CmdType::ACT, { 0, 0, 0 } },\n        {  10, CmdType::ACT, { 1, 0, 0 } },\n        {  15, CmdType::PRE, { 0, 0, 0 } },\n        {  25, CmdType::ACT, { 3, 0, 0 } },\n        {  25, CmdType::PRE, { 1, 0, 0 } },\n        {  30, CmdType::ACT, { 0, 0, 0 } },\n        {  35, CmdType::ACT, { 2, 0, 0 } },\n        {  40, CmdType::PRE, { 1, 0, 0 } },\n        {  40, CmdType::PRE, { 3, 0, 0 } },\n        {  45, CmdType::PRE, { 0, 0, 0 } },\n        {  50, CmdType::PRE, { 2, 0, 0 } },\n        {  85, CmdType::ACT, { 7, 0, 0 } },\n        { 100, CmdType::PRE, { 7, 0, 0 } },\n        { 120, CmdType::ACT, { 6, 0, 0 } },\n        { 125, CmdType::END_OF_SIMULATION},\n    };\n\n    // Test variables\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        auto memSpec = DRAMPower::MemSpecLPDDR4::from_memspec(*data);\n\n        memSpec.numberOfRanks = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.banksPerGroup = 8;\n        memSpec.numberOfBankGroups = 1;\n        memSpec.burstLength = 8;\n        memSpec.dataRate = 2;\n\t\tmemSpec.bitWidth = 16;\n\t\tmemSpec.numberOfDevices = 1;\n\n\t\tmemSpec.memTimingSpec.tRAS = 10;\n\t\tmemSpec.memTimingSpec.tRP = 10;\n        memSpec.memTimingSpec.tCK = 1e-9;\n\n\t\tmemSpec.memPowerSpec[0].vDDX = 1;\n\t\tmemSpec.memPowerSpec[0].iDD0X = 64e-3;\n\t\tmemSpec.memPowerSpec[0].iDD3NX = 32e-3;\n\t\tmemSpec.memPowerSpec[0].iDD2NX = 8e-3;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iDD0X;\n\t\tmemSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n\n        ddr = std::make_unique<LPDDR4>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_11, Pattern1)\n{\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\t// Inspect first rank\n\tconst auto & rank_1 = internal::LPDDR4TestAccessor.getRanks(ddr->getCore()).at(0);\n\tauto stats = ddr->getStats();\n\n\t// Check global count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 70);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 55);\n\n\t// Check per-bank ACT count\n\tASSERT_EQ(stats.bank[0].cycles.act, 30);\n\n\tASSERT_EQ(stats.bank[1].cycles.act, 15);\n\tASSERT_EQ(stats.bank[2].cycles.act, 15);\n\tASSERT_EQ(stats.bank[3].cycles.act, 15);\n\tASSERT_EQ(stats.bank[7].cycles.act, 15);\n\n\tASSERT_EQ(stats.bank[6].cycles.act, 5);\n\n\tASSERT_EQ(stats.bank[4].cycles.act, 0);\n\tASSERT_EQ(stats.bank[5].cycles.act, 0);\n\n\t// Check per-bank PRE count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 95);\n\n\tASSERT_EQ(stats.bank[1].cycles.pre, 110);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 110);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 110);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 110);\n\n\tASSERT_EQ(stats.bank[6].cycles.pre, 120);\n\n\tASSERT_EQ(stats.bank[4].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 125);\n\n\t// Check global command count\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::ACT), 7);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::PRE), 7);\n\n\t// per-bank ACT command count\n\tASSERT_EQ(stats.bank[0].counter.act, 2);\n\n\tASSERT_EQ(stats.bank[1].counter.act, 1);\n\tASSERT_EQ(stats.bank[2].counter.act, 1);\n\tASSERT_EQ(stats.bank[3].counter.act, 1);\n\tASSERT_EQ(stats.bank[6].counter.act, 1);\n\tASSERT_EQ(stats.bank[7].counter.act, 1);\n\n\tASSERT_EQ(stats.bank[4].counter.act, 0);\n\tASSERT_EQ(stats.bank[5].counter.act, 0);\n\n\t// per-bank PRE command count\n\tASSERT_EQ(stats.bank[0].counter.pre, 2);\n\n\tASSERT_EQ(stats.bank[1].counter.pre, 1);\n\tASSERT_EQ(stats.bank[2].counter.pre, 1);\n\tASSERT_EQ(stats.bank[3].counter.pre, 1);\n\tASSERT_EQ(stats.bank[7].counter.pre, 1);\n\n\tASSERT_EQ(stats.bank[6].counter.pre, 0);\n\tASSERT_EQ(stats.bank[4].counter.pre, 0);\n\tASSERT_EQ(stats.bank[5].counter.pre, 0);\n}\n\nTEST_F(DramPowerTest_LPDDR4_11, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n    auto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 2240);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_act*1e12), 640);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_act*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_act*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_act*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_act*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_act*1e12), 320);\n\n\tASSERT_EQ(std::round(total_energy.E_pre*1e12), 3360);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_pre*1e12), 1120);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_pre*1e12), 560);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_pre*1e12), 560);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_pre*1e12), 560);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_pre*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_pre*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_pre*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_pre*1e12), 560);\n\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_bg_act*1e12), 480);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_bg_act*1e12), 240);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_bg_act*1e12), 240);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_bg_act*1e12), 240);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_bg_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_bg_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_bg_act*1e12), 80);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_bg_act*1e12), 240);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1120);\n\tASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 2640);\n\n\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 440);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_pre*1e12), 55);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_12.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n#include <DRAMPower/standards/test_accessor.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_12 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{   0, CmdType::ACT, { 0, 0, 0} },\n\t\t{   5, CmdType::ACT, { 1, 0, 0} },\n\t\t{  10, CmdType::ACT, { 2, 0, 0} },\n\t\t{  15, CmdType::ACT, { 3, 0, 0} },\n\t\t{  20, CmdType::ACT, { 4, 0, 0} },\n\t\t{  25, CmdType::ACT, { 5, 0, 0} },\n\t\t{  30, CmdType::ACT, { 6, 0, 0} },\n\t\t{  35, CmdType::ACT, { 7, 0, 0} },\n\t\t{  35, CmdType::RD,  { 0, 0, 0} },\n\t\t{  40, CmdType::RD,  { 0, 0, 0} },\n\t\t{  40, CmdType::RD,  { 1, 0, 0} },\n\t\t{  45, CmdType::RD,  { 0, 0, 0} },\n\t\t{  45, CmdType::RD,  { 2, 0, 0} },\n\t\t{  50, CmdType::RD,  { 3, 0, 0} },\n\t\t{  55, CmdType::RD,  { 4, 0, 0} },\n\t\t{  60, CmdType::RD,  { 5, 0, 0} },\n\t\t{  65, CmdType::RD,  { 6, 0, 0} },\n\t\t{  70, CmdType::RD,  { 7, 0, 0} },\n\t\t{  75, CmdType::RD,  { 7, 0, 0} },\n\t\t{  80, CmdType::RD,  { 7, 0, 0} },\n\t\t{  85, CmdType::WR,  { 7, 0, 0} },\n\t\t{  90, CmdType::WR,  { 6, 0, 0} },\n\t\t{  95, CmdType::WR,  { 5, 0, 0} },\n\t\t{ 100, CmdType::WR,  { 4, 0, 0} },\n\t\t{ 105, CmdType::WR,  { 3, 0, 0} },\n\t\t{ 110, CmdType::WR,  { 2, 0, 0} },\n\t\t{ 110, CmdType::WR,  { 0, 0, 0} },\n\t\t{ 115, CmdType::WR,  { 1, 0, 0} },\n\t\t{ 115, CmdType::RD,  { 0, 0, 0} },\n\t\t{ 120, CmdType::WR,  { 0, 0, 0} },\n\t\t{ 120, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        auto memSpec = DRAMPower::MemSpecLPDDR4::from_memspec(*data);\n\n\t\tmemSpec.numberOfRanks = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.banksPerGroup = 8;\n\t\tmemSpec.numberOfBankGroups = 1;\n\t\tmemSpec.bitWidth = 16;\n\t\tmemSpec.numberOfDevices = 1;\n\n\t\tmemSpec.memTimingSpec.tCK = 1e-9;\n\n\t\tmemSpec.memPowerSpec[0].vDDX = 1;\n\t\tmemSpec.memPowerSpec[0].iDD0X = 64e-3;\n\t\tmemSpec.memPowerSpec[0].iDD3NX = 32e-3;\n\t\tmemSpec.memPowerSpec[0].iDD4RX = 72e-3;\n\t\tmemSpec.memPowerSpec[0].iDD4WX = 96e-3;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iDD0X;\n        memSpec.bwParams.bwPowerFactRho = 1;\n\n        memSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\n        ddr = std::make_unique<LPDDR4>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_12, Pattern_2)\n{\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\t// Inspect first rank\n\tconst Rank & rank_1 = internal::LPDDR4TestAccessor.getRanks(ddr->getCore()).at(0);\n\n\t// Check global command count\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::RD), 13);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::WR), 9);\n\n\t// Check bank RD command count\n\tASSERT_EQ(rank_1.banks[0].counter.reads, 4);\n\tASSERT_EQ(rank_1.banks[1].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[2].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[3].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[4].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[5].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[6].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[7].counter.reads, 3);\n\n\t// Check bank WR command count\n\tASSERT_EQ(rank_1.banks[0].counter.writes, 2);\n\tASSERT_EQ(rank_1.banks[1].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[2].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[3].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[4].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[5].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[6].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[7].counter.writes, 1);\n}\n\nTEST_F(DramPowerTest_LPDDR4_12, CalcEnergy)\n{\n    auto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ(std::round(total_energy.E_RD*1e12), 4160);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_RD*1e12), 1280);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_RD*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_RD*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_RD*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_RD*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_RD*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_RD*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_RD*1e12), 960);\n\n\tASSERT_EQ(std::round(total_energy.E_WR*1e12), 4608);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_WR*1e12), 1024);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_WR*1e12), 512);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_WR*1e12), 512);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_WR*1e12), 512);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_WR*1e12), 512);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_WR*1e12), 512);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_WR*1e12), 512);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_WR*1e12), 512);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_13.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n#include <DRAMPower/standards/test_accessor.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_13 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t// Timestamp,   Cmd,  { Bank, BG, Rank}\n\t\t{   0, CmdType::ACT, { 0, 0, 0 }  },\n\t\t{  10, CmdType::RDA, { 0, 0, 0 }  },\n\t\t{  15, CmdType::ACT, { 1, 0, 0 }  },\n\t\t{  15, CmdType::ACT, { 2, 0, 0 }  },\n\t\t{  25, CmdType::WRA, { 1, 0, 0 }  },\n\t\t{  30, CmdType::PRE, { 0, 0, 0 }  },\n\t\t{  35, CmdType::RDA, { 2, 0, 0 }  },\n\t\t{  50, CmdType::ACT, { 0, 0, 0 }  },\n\t\t{  50, CmdType::ACT, { 2, 0, 0 }  },\n\t\t{  60, CmdType::WRA, { 0, 0, 0 }  },\n\t\t{  60, CmdType::RDA, { 2, 0, 0 }  },\n\t\t{  75, CmdType::ACT, { 1, 0, 0 }  },\n\t\t{  80, CmdType::ACT, { 0, 0, 0 }  },\n\t\t{  85, CmdType::WRA, { 0, 0, 0 }  },\n\t\t{  95, CmdType::RDA, { 1, 0, 0 }  },\n\t\t{ 125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        auto memSpec = DRAMPower::MemSpecLPDDR4::from_memspec(*data);\n\n\t\tmemSpec.numberOfRanks = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.banksPerGroup = 8;\n        memSpec.numberOfBankGroups = 1;\n\t\tmemSpec.bitWidth = 16;\n\t\tmemSpec.numberOfDevices = 1;\n\n\t\tmemSpec.memTimingSpec.tRAS = 20;\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n\t\tmemSpec.memTimingSpec.tWR = 11;\n\t\tmemSpec.memTimingSpec.tWL = 0;\n\t\tmemSpec.memTimingSpec.tCK = 1e-9;\n        memSpec.memTimingSpec.tRP = 10;\n\n\t\tmemSpec.memPowerSpec[0].vDDX = 1;\n\t\tmemSpec.memPowerSpec[0].iDD0X = 64e-3;\n\t\tmemSpec.memPowerSpec[0].iDD2NX = 8e-3;\n\t\tmemSpec.memPowerSpec[0].iDD3NX = 32e-3;\n\t\tmemSpec.memPowerSpec[0].iDD4RX = 72e-3;\n\t\tmemSpec.memPowerSpec[0].iDD4WX = 96e-3;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iDD0X;\n\n\t\tmemSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\n        memSpec.prechargeOffsetRD      =   memSpec.memTimingSpec.tRTP;\n        memSpec.prechargeOffsetWR      =  memSpec.memTimingSpec.tWL + memSpec.burstLength/2 + memSpec.memTimingSpec.tWR + 1;\n\n        ddr = std::make_unique<LPDDR4>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_13, Test)\n{\n\tfor (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\tconst Rank & rank_1 = internal::LPDDR4TestAccessor.getRanks(ddr->getCore()).at(0);\n\tauto stats = ddr->getStats();\n\n\t// Check global command count\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::ACT), 7);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::PRE), 1);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::RDA), 4);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::WRA), 3);\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 3);\n\tASSERT_EQ(stats.bank[1].counter.act, 2);\n\tASSERT_EQ(stats.bank[2].counter.act, 2);\n\tASSERT_EQ(stats.bank[3].counter.act, 0);\n\tASSERT_EQ(stats.bank[4].counter.act, 0);\n\tASSERT_EQ(stats.bank[5].counter.act, 0);\n\tASSERT_EQ(stats.bank[6].counter.act, 0);\n\tASSERT_EQ(stats.bank[7].counter.act, 0);\n\n\t// Check bank command count: RDA\n\tASSERT_EQ(stats.bank[0].counter.readAuto, 1);\n\tASSERT_EQ(stats.bank[1].counter.readAuto, 1);\n\tASSERT_EQ(stats.bank[2].counter.readAuto, 2);\n\tASSERT_EQ(stats.bank[3].counter.readAuto, 0);\n\tASSERT_EQ(stats.bank[4].counter.readAuto, 0);\n\tASSERT_EQ(stats.bank[5].counter.readAuto, 0);\n\tASSERT_EQ(stats.bank[6].counter.readAuto, 0);\n\tASSERT_EQ(stats.bank[7].counter.readAuto, 0);\n\n\t// Check bank command count: WRA\n\tASSERT_EQ(stats.bank[0].counter.writeAuto, 2);\n\tASSERT_EQ(stats.bank[1].counter.writeAuto, 1);\n\tASSERT_EQ(stats.bank[2].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[3].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[4].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[5].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[6].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[7].counter.writeAuto, 0);\n\n\t// Check cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 100);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 25);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 75);\n\tASSERT_EQ(stats.bank[1].cycles.act, 60);\n\tASSERT_EQ(stats.bank[2].cycles.act, 50);\n\tASSERT_EQ(stats.bank[3].cycles.act, 0);\n\tASSERT_EQ(stats.bank[4].cycles.act, 0);\n\tASSERT_EQ(stats.bank[5].cycles.act, 0);\n\tASSERT_EQ(stats.bank[6].cycles.act, 0);\n\tASSERT_EQ(stats.bank[7].cycles.act, 0);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 50);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 65);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 75);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[6].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 125);\n}\n\nTEST_F(DramPowerTest_LPDDR4_13, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 4560);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1600);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_bg_act*1e12), 1200);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_bg_act*1e12), 960);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_bg_act*1e12), 800);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_bg_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_bg_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_bg_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_bg_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_bg_act*1e12), 0);\n\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 200);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_pre*1e12), 25);\n\n\tASSERT_EQ(std::round(total_energy.E_RDA*1e12), 1280);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_RDA*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_RDA*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_RDA*1e12), 640);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_RDA*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_RDA*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_RDA*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_RDA*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_RDA*1e12), 0);\n\n\tASSERT_EQ(std::round(total_energy.E_WRA*1e12), 1536);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_WRA*1e12), 1024);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_WRA*1e12), 512);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_WRA*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_WRA*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_WRA*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_WRA*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_WRA*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_WRA*1e12), 0);\n\n\tASSERT_EQ(std::round(total_energy.E_pre_RDA*1e12), 2240);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_pre_RDA*1e12), 560);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_pre_RDA*1e12), 560);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_pre_RDA*1e12), 1120);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_pre_RDA*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_pre_RDA*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_pre_RDA*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_pre_RDA*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_pre_RDA*1e12), 0);\n\n\tASSERT_EQ(std::round(total_energy.E_pre_WRA*1e12), 1120+560);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_pre_WRA*1e12), 1120);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_pre_WRA*1e12), 560);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_pre_WRA*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_pre_WRA*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_pre_WRA*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_pre_WRA*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_pre_WRA*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_pre_WRA*1e12), 0);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_14.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_14 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{   0, CmdType::ACT,  { 0, 0, 0 }},\n\t\t{   5, CmdType::ACT,  { 1, 0, 0 }},\n\t\t{  10, CmdType::ACT,  { 2, 0, 0 }},\n\t\t{  15, CmdType::PRE,  { 0, 0, 0 }},\n\t\t{  20, CmdType::PREA, { 0, 0, 0 }},\n\t\t{  25, CmdType::PRE,  { 1, 0, 0 }},\n\t\t{  30, CmdType::PREA, { 0, 0, 0 }},\n\t\t{  40, CmdType::ACT,  { 0, 0, 0 }},\n\t\t{  40, CmdType::ACT,  { 3, 0, 0 }},\n\t\t{  50, CmdType::PRE,  { 3, 0, 0 }},\n\t\t{ 125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        auto memSpec = DRAMPower::MemSpecLPDDR4::from_memspec(*data);\n\n\t\tmemSpec.numberOfRanks = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.banksPerGroup = 8;\n        memSpec.numberOfBankGroups = 1;\n\t\tmemSpec.bitWidth = 16;\n\t\tmemSpec.numberOfDevices = 1;\n\n\t\tmemSpec.memTimingSpec.tRAS = 10;\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n\t\tmemSpec.memTimingSpec.tWR = 20;\n\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n\t\tmemSpec.memTimingSpec.tWR = 12;\n\t\tmemSpec.memTimingSpec.tWL = 0;\n\t\tmemSpec.memTimingSpec.tCK = 1e-9;\n\t\tmemSpec.memTimingSpec.tRP = 10;\n\n\t\tmemSpec.memPowerSpec[0].vDDX = 1;\n\t\tmemSpec.memPowerSpec[0].iDD0X = 64e-3;\n\t\tmemSpec.memPowerSpec[0].iDD2NX = 8e-3;\n\t\tmemSpec.memPowerSpec[0].iDD3NX = 32e-3;\n\t\tmemSpec.memPowerSpec[0].iDD4RX = 72e-3;\n\t\tmemSpec.memPowerSpec[0].iDD4WX = 72e-3;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iDD0X;\n\n\t\tmemSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\n        ddr = std::make_unique<LPDDR4>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_14, Test)\n{\n\tfor (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 2);\n\tASSERT_EQ(stats.bank[1].counter.act, 1);\n\tASSERT_EQ(stats.bank[2].counter.act, 1);\n\tASSERT_EQ(stats.bank[3].counter.act, 1);\n\tASSERT_EQ(stats.bank[4].counter.act, 0);\n\n\t// Check cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 105);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 20);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 100);\n\tASSERT_EQ(stats.bank[1].cycles.act, 15);\n\tASSERT_EQ(stats.bank[2].cycles.act, 10);\n\tASSERT_EQ(stats.bank[3].cycles.act, 10);\n\tASSERT_EQ(stats.bank[4].cycles.act, 0);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 25);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 110);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 115);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 115);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 125);\n}\n\nTEST_F(DramPowerTest_LPDDR4_14, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ(std::round(total_energy.E_act*1e12), 1600);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_act*1e12), 640);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_act*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_act*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_act*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_act*1e12), 0);\n\n\tASSERT_EQ(std::round(total_energy.E_pre*1e12), 2240);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_pre*1e12), 560);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_pre*1e12), 560);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_pre*1e12), 560);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_pre*1e12), 560);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_pre*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_pre*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_pre*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_pre*1e12), 0);\n\n\tASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 3840);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1680);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_bg_act*1e12), 1600);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_bg_act*1e12), 240);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_bg_act*1e12), 160);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_bg_act*1e12), 160);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_bg_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_bg_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_bg_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_bg_act*1e12), 0);\n\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 160);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_pre*1e12), 20);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_pre*1e12), 20);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_pre*1e12), 20);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_pre*1e12), 20);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_pre*1e12), 20);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_pre*1e12), 20);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_pre*1e12), 20);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_pre*1e12), 20);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_15.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_15 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{  0, CmdType::ACT,  { 0, 0, 0}},\n\t\t{  0, CmdType::ACT,  { 1, 0, 0}},\n\t\t{  0, CmdType::ACT,  { 2, 0, 0}},\n\t\t{ 15, CmdType::PRE,  { 0, 0, 0}},\n\t\t{ 20, CmdType::REFB, { 0, 0, 0}},\n\t\t{ 25, CmdType::PRE,  { 1, 0, 0}},\n\t\t{ 30, CmdType::RDA,  { 2, 0, 0}},\n\t\t{ 50, CmdType::REFB, { 2, 0, 0}},\n\t\t{ 60, CmdType::ACT,  { 1, 0, 0}},\n\t\t{ 80, CmdType::PRE,  { 1, 0, 0}},\n\t\t{ 85, CmdType::REFB, { 1, 0, 0}},\n\t\t{ 85, CmdType::REFB, { 0, 0, 0}},\n\t\t{ 125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        auto memSpec = DRAMPower::MemSpecLPDDR4::from_memspec(*data);\n\n\t\tmemSpec.numberOfRanks = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.banksPerGroup = 8;\n        memSpec.numberOfBankGroups = 1;\n\t\tmemSpec.bitWidth = 16;\n\t\tmemSpec.numberOfDevices = 1;\n\n\t\tmemSpec.memTimingSpec.tRAS = 10;\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n        memSpec.memTimingSpec.tRFCPB = 25;\n\t\tmemSpec.memTimingSpec.tWR = 20;\n\t\tmemSpec.memTimingSpec.tWL = 0;\n\t\tmemSpec.memTimingSpec.tCK = 1e-9;\n        memSpec.memTimingSpec.tRP = 10;\n\t\tmemSpec.memTimingSpec.tREFI = 1;\n\n\n\t\tmemSpec.memPowerSpec[0].vDDX = 1;\n\t\tmemSpec.memPowerSpec[0].iDD0X = 64e-3;\n\t\tmemSpec.memPowerSpec[0].iDD2NX = 8e-3;\n\t\tmemSpec.memPowerSpec[0].iDD3NX = 32e-3;\n\t\tmemSpec.memPowerSpec[0].iDD4RX = 72e-3;\n\t\tmemSpec.memPowerSpec[0].iDD4WX = 72e-3;\n\t\tmemSpec.memPowerSpec[0].iDD5PBX = 6008e-3;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iDD0X;\n\n        memSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\n        memSpec.prechargeOffsetRD      =   memSpec.memTimingSpec.tRTP;\n        memSpec.prechargeOffsetWR      =  memSpec.memTimingSpec.tWL + memSpec.burstLength/2 + memSpec.memTimingSpec.tWR + 1;\n\n        ddr = std::make_unique<LPDDR4>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_15, Test)\n{\n\tfor (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 1);\n\tASSERT_EQ(stats.bank[1].counter.act, 2);\n\tASSERT_EQ(stats.bank[2].counter.act, 1);\n\tASSERT_EQ(stats.bank[3].counter.act, 0);\n\n\t// Check bank command count: PRE\n\tASSERT_EQ(stats.bank[0].counter.pre, 1);\n\tASSERT_EQ(stats.bank[1].counter.pre, 2);\n\tASSERT_EQ(stats.bank[2].counter.pre, 1);\n\tASSERT_EQ(stats.bank[3].counter.pre, 0);\n\n\t// Check bank command count: REFPB\n\tASSERT_EQ(stats.bank[0].counter.refPerBank, 2);\n\tASSERT_EQ(stats.bank[1].counter.refPerBank, 1);\n\tASSERT_EQ(stats.bank[2].counter.refPerBank, 1);\n\tASSERT_EQ(stats.bank[3].counter.refPerBank, 0);\n\n\t// Check global cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 100);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 25);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 65);\n\tASSERT_EQ(stats.bank[1].cycles.act, 70);\n\tASSERT_EQ(stats.bank[2].cycles.act, 65);\n\tASSERT_EQ(stats.bank[3].cycles.act, 0);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 55);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 125);\n}\n\nTEST_F(DramPowerTest_LPDDR4_15, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 4800);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1600);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_bg_act*1e12), 1040);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_bg_act*1e12), 1120);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_bg_act*1e12), 1040);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_bg_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_bg_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_bg_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_bg_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_bg_act*1e12), 0);\n\n\tASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 200);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_bg_pre*1e12), 25);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_bg_pre*1e12), 25);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_bg_pre*1e12), 25);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_bg_pre*1e12), 25);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_bg_pre*1e12), 25);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_bg_pre*1e12), 25);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_bg_pre*1e12), 25);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_bg_pre*1e12), 25);\n\n\tASSERT_EQ(std::round(total_energy.E_ref_PB*1e12), 600);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_ref_PB*1e12), 300);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_ref_PB*1e12), 150);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_ref_PB*1e12), 150);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_ref_PB*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_ref_PB*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_ref_PB*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_ref_PB*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_ref_PB*1e12), 0);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_16.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_16  : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{  0,  CmdType::ACT, {0, 0, 0} },\n\t\t{ 20,  CmdType::PDEA },\n\t\t{ 30,  CmdType::PDXA },\n\t\t{ 40,  CmdType::PRE, {0, 0, 0} },\n\t\t{ 60,  CmdType::PDEP },\n\t\t{ 65,  CmdType::PDXP },\n\t\t{ 75,  CmdType::REFA },\n\t\t{100,  CmdType::PDEP },\n\t\t{125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        auto memSpec = DRAMPower::MemSpecLPDDR4::from_memspec(*data);\n\n\t\tmemSpec.numberOfRanks = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.numberOfBankGroups = 2;\n        memSpec.banksPerGroup = 4;\n\t\tmemSpec.bitWidth = 16;\n\t\tmemSpec.numberOfDevices = 1;\n\n\t\tmemSpec.memTimingSpec.tRAS = 10;\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n\t\tmemSpec.memTimingSpec.tRCD = 20;\n\t\tmemSpec.memTimingSpec.tRFC = 25;\n\t\t//memSpec.memTimingSpec.tRFCPB = 3;\n\n\t\tmemSpec.memTimingSpec.tWR = 20;\n\t\tmemSpec.memTimingSpec.tRP = 20;\n\t\tmemSpec.memTimingSpec.tWL = 0;\n\t\tmemSpec.memTimingSpec.tCK = 1e-9;\n        memSpec.memTimingSpec.tREFI = 1;\n\n\t\tmemSpec.memPowerSpec[0].vDDX = 1;\n\t\tmemSpec.memPowerSpec[0].iDD0X = 64e-3;\n\t\tmemSpec.memPowerSpec[0].iDD2NX = 8e-3;\n\t\tmemSpec.memPowerSpec[0].iDD2PX = 6e-3;\n\t\tmemSpec.memPowerSpec[0].iDD3NX = 32e-3;\n\t\tmemSpec.memPowerSpec[0].iDD3PX = 20e-3;\n\t\tmemSpec.memPowerSpec[0].iDD4RX = 72e-3;\n\t\tmemSpec.memPowerSpec[0].iDD4WX = 72e-3;\n\t\t//memSpec.memPowerSpec[0].iDD5PBX = 30;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iDD0X;\n\n\n        memSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\n        ddr = std::make_unique<LPDDR4>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_16, Test)\n{\n\tfor (const auto& command : testPattern) {\n\t\tddr->doCoreCommand(command);\n\t};\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 1);\n\n\t// Check bank command count: PRE\n\tASSERT_EQ(stats.bank[0].counter.pre, 1);\n\n\t// Check global cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.activeTime(), 55);\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 55);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 30);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 55); ASSERT_EQ(stats.bank[0].cycles.activeTime(), 55);\n\tASSERT_EQ(stats.bank[1].cycles.act, 25); ASSERT_EQ(stats.bank[1].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[2].cycles.act, 25); ASSERT_EQ(stats.bank[2].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[3].cycles.act, 25); ASSERT_EQ(stats.bank[3].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[4].cycles.act, 25); ASSERT_EQ(stats.bank[4].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[5].cycles.act, 25); ASSERT_EQ(stats.bank[5].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[6].cycles.act, 25); ASSERT_EQ(stats.bank[6].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[7].cycles.act, 25); ASSERT_EQ(stats.bank[7].cycles.activeTime(), 25);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 30);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[6].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 60);\n}\n\nTEST_F(DramPowerTest_LPDDR4_16, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 4560);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 880);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_bg_act*1e12), 880);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_bg_act*1e12), 400);\n\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 240);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_pre*1e12), 30);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_pre*1e12), 30);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_pre*1e12), 30);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_pre*1e12), 30);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_pre*1e12), 30);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_pre*1e12), 30);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_pre*1e12), 30);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_pre*1e12), 30);\n\n\tASSERT_EQ(std::round(energy.E_PDNA*1e12), 200);\n\tASSERT_EQ(std::round(energy.E_PDNP*1e12), 180);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_17.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_17 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{  0,  CmdType::ACT, { 0,0,0} },\n\t\t{  5,  CmdType::PDEA },\n\t\t{ 30,  CmdType::PDXA },\n\t\t{ 40,  CmdType::PRE, {0,0,0} },\n\t\t{ 45,  CmdType::PDEP },\n\t\t{ 65,  CmdType::PDXP },\n\t\t{ 75,  CmdType::REFA },\n\t\t{ 85,  CmdType::PDEP },\n\t\t{ 90,  CmdType::PDXP },\n\t\t{125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        auto memSpec = DRAMPower::MemSpecLPDDR4::from_memspec(*data);\n\n\t\tmemSpec.numberOfRanks = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.numberOfBankGroups = 2;\n        memSpec.banksPerGroup = 4;\n\t\tmemSpec.bitWidth = 16;\n\t\tmemSpec.numberOfDevices = 1;\n\n\t\tmemSpec.memTimingSpec.tRAS = 10;\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n\t\tmemSpec.memTimingSpec.tRCD = 20;\n\t\tmemSpec.memTimingSpec.tRFC = 25;\n\t\tmemSpec.memTimingSpec.tRFCPB = 25;\n\n\t\tmemSpec.memTimingSpec.tWR = 20;\n\t\tmemSpec.memTimingSpec.tRP = 20;\n\t\tmemSpec.memTimingSpec.tWL = 0;\n\t\tmemSpec.memTimingSpec.tCK = 1e-9;\n        memSpec.memTimingSpec.tREFI = 1;\n\n\t\tmemSpec.memPowerSpec[0].vDDX = 1;\n\t\tmemSpec.memPowerSpec[0].iDD0X = 64e-3;\n\t\tmemSpec.memPowerSpec[0].iDD2NX = 8e-3;\n\t\tmemSpec.memPowerSpec[0].iDD2PX = 6e-3;\n\t\tmemSpec.memPowerSpec[0].iDD3NX = 32e-3;\n\t\tmemSpec.memPowerSpec[0].iDD3PX = 20e-3;\n\t\tmemSpec.memPowerSpec[0].iDD4RX = 72e-3;\n\t\tmemSpec.memPowerSpec[0].iDD4WX = 72e-3;\n\t\tmemSpec.memPowerSpec[0].iDD5PBX = 30e-3;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iDD0X;\n\n\n        memSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\n        ddr = std::make_unique<LPDDR4>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_17, Test)\n{\n\tfor (const auto& command : testPattern) {\n\t\tddr->doCoreCommand(command);\n\t};\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 1);\n\n\t// Check bank command count: PRE\n\tASSERT_EQ(stats.bank[0].counter.pre, 1);\n\n\t// Check global cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 55);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 55);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 5);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 55);\n\tASSERT_EQ(stats.bank[1].cycles.act, 25);\n\tASSERT_EQ(stats.bank[2].cycles.act, 25);\n\tASSERT_EQ(stats.bank[3].cycles.act, 25);\n\tASSERT_EQ(stats.bank[4].cycles.act, 25);\n\tASSERT_EQ(stats.bank[5].cycles.act, 25);\n\tASSERT_EQ(stats.bank[6].cycles.act, 25);\n\tASSERT_EQ(stats.bank[7].cycles.act, 25);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 55);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[6].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 85);\n}\n\nTEST_F(DramPowerTest_LPDDR4_17, CalcWindow)\n{\n\tSimulationStats window;\n\n\tauto iterate_to_timestamp = [this](auto & command, timestamp_t timestamp) {\n\t\twhile (command != this->testPattern.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\n\t\treturn this->ddr->getWindowStats(timestamp);\n\t};\n\n\tauto command = testPattern.begin();\n\n\n\t// Cycle 5\n\twindow = iterate_to_timestamp(command, 5);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 5);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 5);\n\n\t// Cycle 10\n\twindow = iterate_to_timestamp(command, 10);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 10);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act,  0);   ASSERT_EQ(window.bank[1].cycles.pre, 10);\n\n\t// Cycle 15\n\twindow = iterate_to_timestamp(command, 15);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 15);\n\tASSERT_EQ(window.bank[0].cycles.act, 15);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 15);\n\n\t// Cycle 20\n\twindow = iterate_to_timestamp(command, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 20);\n\tASSERT_EQ(window.bank[0].cycles.act, 20);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 20);\n\n\t// Cycle 25\n\twindow = iterate_to_timestamp(command, 25);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 20);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 20);\n\n\t// Cycle 30\n\twindow = iterate_to_timestamp(command, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 20);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 20);\n\n\t// Cycle 35\n\twindow = iterate_to_timestamp(command, 35);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 25);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 25);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 25);\n\n\t// Cycle 40\n\twindow = iterate_to_timestamp(command, 40);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act,  0);  ASSERT_EQ(window.bank[1].cycles.pre, 30);\n\n\t// Cycle 45\n\twindow = iterate_to_timestamp(command, 45);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre,  5);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 35);\n\n\t// Cycle 50\n\twindow = iterate_to_timestamp(command, 50);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 10);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 10);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 40);\n\n\t// Cycle 55\n\twindow = iterate_to_timestamp(command, 55);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 15);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 15);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 45);\n\n\t// Cycle 60\n\twindow = iterate_to_timestamp(command, 60);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 20);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 50);\n\n\t// Cycle 65\n\twindow = iterate_to_timestamp(command, 65);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 20);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 50);\n\n\t// Cycle 70\n\twindow = iterate_to_timestamp(command, 70);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 25);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 25);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 55);\n\n\t// Cycle 75\n\twindow = iterate_to_timestamp(command, 75);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 80\n\twindow = iterate_to_timestamp(command, 80);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 35);    ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 35);  ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 5);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 85\n\twindow = iterate_to_timestamp(command, 85);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 40);     ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 40);   ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 10);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 90\n\twindow = iterate_to_timestamp(command, 90);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 45);     ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 45);   ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 15);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 95\n\twindow = iterate_to_timestamp(command, 95);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 50);     ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 50);   ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 20);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 100\n\twindow = iterate_to_timestamp(command, 100);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 105\n\twindow = iterate_to_timestamp(command, 105);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 35);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 35);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 65);\n\n\t// Cycle 110\n\twindow = iterate_to_timestamp(command, 110);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 40);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 40);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 70);\n\n\t// Cycle 115\n\twindow = iterate_to_timestamp(command, 115);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 45);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 45);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 75);\n\n\t// Cycle 120\n\twindow = iterate_to_timestamp(command, 120);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 50);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 50);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 80);\n\n\t// Cycle 125\n\twindow = iterate_to_timestamp(command, 125);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 55);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 55);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 85);\n};\n\n\n\nTEST_F(DramPowerTest_LPDDR4_17, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 4560);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 880);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_bg_act*1e12), 880);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_bg_act*1e12), 400);\n\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 440);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_pre*1e12), 55);\n\n\tASSERT_EQ(std::round(energy.E_PDNA*1e12), 200);\n\tASSERT_EQ(std::round(energy.E_PDNP*1e12), 30);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_18.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_18 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{  0, CmdType::REFA },\n\t\t{  5, CmdType::PDEP },\n\t\t{ 15, CmdType::PDXP },\n\t\t{ 30, CmdType::REFB, { 0,0,0} },\n\t\t{ 40, CmdType::ACT, { 1,0,0,}},\n\t\t{ 45, CmdType::PDEA },\n\t\t{ 75, CmdType::PDXA },\n\t\t{125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        auto memSpec = DRAMPower::MemSpecLPDDR4::from_memspec(*data);\n\n\t\tmemSpec.numberOfRanks = 1;\n        memSpec.numberOfBanks = 8;\n        memSpec.numberOfBankGroups = 2;\n        memSpec.banksPerGroup = 4;\n\t\tmemSpec.bitWidth = 16;\n\t\tmemSpec.numberOfDevices = 1;\n\n\t\tmemSpec.memTimingSpec.tRAS = 10;\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n\t\tmemSpec.memTimingSpec.tRCD = 20;\n\t\tmemSpec.memTimingSpec.tRFC = 25;\n\t\tmemSpec.memTimingSpec.tRFCPB = 25;\n\n\t\tmemSpec.memTimingSpec.tWR = 20;\n\t\tmemSpec.memTimingSpec.tRP = 20;\n\t\tmemSpec.memTimingSpec.tWL = 0;\n\t\tmemSpec.memTimingSpec.tCK = 1e-9;\n        memSpec.memTimingSpec.tREFI = 1;\n\n\t\tmemSpec.memPowerSpec[0].vDDX = 1;\n\t\tmemSpec.memPowerSpec[0].iDD0X = 64e-3;\n\t\tmemSpec.memPowerSpec[0].iDD2NX = 8e-3;\n\t\tmemSpec.memPowerSpec[0].iDD2PX = 6e-3;\n\t\tmemSpec.memPowerSpec[0].iDD3NX = 32e-3;\n\t\tmemSpec.memPowerSpec[0].iDD3PX = 20e-3;\n\t\tmemSpec.memPowerSpec[0].iDD4RX = 72e-3;\n\t\tmemSpec.memPowerSpec[0].iDD4WX = 72e-3;\n\t\tmemSpec.memPowerSpec[0].iDD5PBX = 30e-3;\n        memSpec.memPowerSpec[0].iBeta = memSpec.memPowerSpec[0].iDD0X;\n\n\n        memSpec.bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\n        ddr = std::make_unique<LPDDR4>(memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_18, Test)\n{\n\tfor (const auto& command : testPattern) {\n\t\tddr->doCoreCommand(command);\n\t};\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[1].counter.act, 1);\n\n\t// Check global cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 105);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 15);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 50);\n\tASSERT_EQ(stats.bank[1].cycles.act, 95);\n\tASSERT_EQ(stats.bank[2].cycles.act, 25);\n\tASSERT_EQ(stats.bank[3].cycles.act, 25);\n\tASSERT_EQ(stats.bank[4].cycles.act, 25);\n\tASSERT_EQ(stats.bank[5].cycles.act, 25);\n\tASSERT_EQ(stats.bank[6].cycles.act, 25);\n\tASSERT_EQ(stats.bank[7].cycles.act, 25);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 15);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[6].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 85);\n}\n\nTEST_F(DramPowerTest_LPDDR4_18, CalcWindow)\n{\n\tSimulationStats window;\n\n\tauto iterate_to_timestamp = [this](auto & command, timestamp_t timestamp) {\n\t\twhile (command != this->testPattern.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\n\t\treturn this->ddr->getWindowStats(timestamp);\n\t};\n\n\tauto command = testPattern.begin();\n\n\n\t// Cycle 5\n\twindow = iterate_to_timestamp(command, 5);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 5);    ASSERT_EQ(window.rank_total[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[0].cycles.act, 5);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 5);  ASSERT_EQ(window.bank[1].cycles.pre, 0);\n\tASSERT_EQ(window.bank[2].cycles.act, 5);  ASSERT_EQ(window.bank[2].cycles.pre, 0);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 25\n\twindow = iterate_to_timestamp(command, 25);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 25);    ASSERT_EQ(window.rank_total[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[0].cycles.act, 25);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);  ASSERT_EQ(window.bank[1].cycles.pre, 0);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 0);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 30\n\twindow = iterate_to_timestamp(command, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 25);    ASSERT_EQ(window.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 25);  ASSERT_EQ(window.bank[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);  ASSERT_EQ(window.bank[1].cycles.pre, 5);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 5);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 35\n\twindow = iterate_to_timestamp(command, 35);\n\tASSERT_EQ(window.rank_total[0].cycles.act,   30);  ASSERT_EQ(window.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);  ASSERT_EQ(window.bank[1].cycles.pre, 10);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 10);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 40\n\twindow = iterate_to_timestamp(command, 40);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 35);\t   ASSERT_EQ(window.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 35);  ASSERT_EQ(window.bank[0].cycles.pre, 5 );\n\tASSERT_EQ(window.bank[1].cycles.act, 25);  ASSERT_EQ(window.bank[1].cycles.pre, 15);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 15);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 50\n\twindow = iterate_to_timestamp(command, 50);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 45);\t   ASSERT_EQ(window.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 45);  ASSERT_EQ(window.bank[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[1].cycles.act, 35);  ASSERT_EQ(window.bank[1].cycles.pre, 15);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 25);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 55\n\twindow = iterate_to_timestamp(command, 55);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 50);\t   ASSERT_EQ(window.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 50);  ASSERT_EQ(window.bank[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[1].cycles.act, 40);  ASSERT_EQ(window.bank[1].cycles.pre, 15);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 60\n\twindow = iterate_to_timestamp(command, 60);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);\t   ASSERT_EQ(window.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 50);  ASSERT_EQ(window.bank[0].cycles.pre, 10);\n\tASSERT_EQ(window.bank[1].cycles.act, 45);  ASSERT_EQ(window.bank[1].cycles.pre, 15);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 35);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 75\n\twindow = iterate_to_timestamp(command, 75);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);\t   ASSERT_EQ(window.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 50);  ASSERT_EQ(window.bank[0].cycles.pre, 10);\n\tASSERT_EQ(window.bank[1].cycles.act, 45);  ASSERT_EQ(window.bank[1].cycles.pre, 15);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 35);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 15); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 95\n\twindow = iterate_to_timestamp(command, 95);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 75);\t   ASSERT_EQ(window.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 50);  ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 65);  ASSERT_EQ(window.bank[1].cycles.pre, 15);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 55);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 15); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 125\n\twindow = iterate_to_timestamp(command, 125);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 105);\t   ASSERT_EQ(window.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 50);  ASSERT_EQ(window.bank[0].cycles.pre, 60);\n\tASSERT_EQ(window.bank[1].cycles.act, 95);  ASSERT_EQ(window.bank[1].cycles.pre, 15);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 85);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 15); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n};\n\n\nTEST_F(DramPowerTest_LPDDR4_18, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 6400);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1680);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_bg_act*1e12), 800);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_bg_act*1e12), 1520);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_bg_act*1e12), 400);\n\n\tASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 40);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_bg_pre*1e12), 5);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_bg_pre*1e12), 5);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_bg_pre*1e12), 5);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_bg_pre*1e12), 5);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_bg_pre*1e12), 5);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_bg_pre*1e12), 5);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_bg_pre*1e12), 5);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_bg_pre*1e12), 5);\n\n\tASSERT_EQ(std::round(energy.E_PDNA*1e12), 300);\n\tASSERT_EQ(std::round(energy.E_PDNP*1e12), 0);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_2.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_2 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   35, CmdType::PRE,  { 0, 0, 0 }},\n            { 50, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR4> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_2, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    ASSERT_EQ(stats.bank[0].counter.act, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.act, 0);\n\n    // Check bank command count: RD\n    ASSERT_EQ(stats.bank[0].counter.reads, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.reads, 0);\n\n    // Check bank command count: PRE\n    ASSERT_EQ(stats.bank[0].counter.pre, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.pre, 0);\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 35);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 15);\n\n    // Check bank specific ACT cycle count\n    ASSERT_EQ(stats.bank[0].cycles.act, 35);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.act, 0);\n\n    // Check bank specific PRE cycle count\n    ASSERT_EQ(stats.bank[0].cycles.pre, 15);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.pre, 50);\n}\n\nTEST_F(DramPowerTest_LPDDR4_2, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 196);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 208);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 452);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1131);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1111);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 467);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 2454);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_3.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_3 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::PRE,  { 0, 0, 0 }},\n            {   45, CmdType::PRE,  { 3, 0, 0 }},\n            { 50, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR4> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_3, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    }\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 45);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 5);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 35);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 25);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 0);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 15);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 25);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 50);\n    }\n}\n\nTEST_F(DramPowerTest_LPDDR4_3, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 392);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 452);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1463);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1428);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 156);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 2878);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_4.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_4 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::RD,  { 3, 0, 0 }},\n            {   40, CmdType::RD,  { 0, 0, 0 }},\n            {   50, CmdType::PREA,  { 0, 0, 0 }},\n            { 70, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR4> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_4, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].counter.reads, 2);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    };\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 50);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 20);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 50);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 30);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 0);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 20);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 40);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 70);\n    }\n}\n\nTEST_F(DramPowerTest_LPDDR4_4, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 392);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 1357);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1633);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1587);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 623);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 4420);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_5.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_5 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::RD,  { 3, 0, 0 }},\n            {   40, CmdType::RD,  { 0, 0, 0 }},\n            {   50, CmdType::PREA,  { 0, 0, 0 }},\n            {   65, CmdType::REFA,  { 0, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR4> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_5, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].counter.reads, 2);\n        else if( b == 3)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    };\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check bank command count: REFA\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        ASSERT_EQ(stats.bank[b].counter.refAllBank, 1);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 75);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 25);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 75);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 55);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 25);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 25);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 45);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 75);\n    }\n}\n\nTEST_F(DramPowerTest_LPDDR4_5, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 392);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 1357);\n    ASSERT_EQ(std::round(total_energy.E_ref_AB*1e12), 1699);\n    ASSERT_EQ(std::round(total_energy.E_ref_SB*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_ref_PB*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_ref_2B*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 2657);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 2380);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 779);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 7299);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_6.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_6 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RDA,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::RD,  { 3, 0, 0 }},\n            {   50, CmdType::PREA,  { 0, 0, 0 }},\n            {   65, CmdType::REFA,  { 0, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR4> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_6, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 3)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    }\n\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].counter.readAuto, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.readAuto, 0);\n    }\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check bank command count: REFA\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        ASSERT_EQ(stats.bank[b].counter.refAllBank, 1);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 75);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 25);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 50);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 55);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 25);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 50);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 45);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 75);\n    }\n}\n\nTEST_F(DramPowerTest_LPDDR4_6, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 392);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 452);\n    ASSERT_EQ(std::round(total_energy.E_RDA*1e12), 452);\n    ASSERT_EQ(std::round(total_energy.E_ref_AB*1e12), 1699);\n    ASSERT_EQ(std::round(total_energy.E_ref_SB*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_ref_2B*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 2642);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 2380);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 779);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 6833);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_7.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_7 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::SREFEN,  { 0, 0, 0 }},\n            {   40, CmdType::SREFEX,  { 0, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR4> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_7, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].counter.act, 0);\n\n    // Check bank command count: REFA\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].counter.refAllBank, 1);\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 25);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 60);\n    ASSERT_EQ(stats.rank_total[0].cycles.selfRefresh, 15);\n\n    // Check bank specific ACT cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.act, 25);\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.pre, 60);\n\n    // Check bank specific SREF cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.selfRefresh, 15);\n\n}\n\nTEST_F(DramPowerTest_LPDDR4_7, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_ref_AB*1e12), 1699);\n    ASSERT_EQ(std::round(energy.E_sref*1e12), 280);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1024);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 793);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 1869);\n    ASSERT_EQ(std::round((total_energy.total() + energy.E_sref)*1e12), 4873);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_8.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_8 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::PDEA,  { 0, 0, 0 }},\n            {   30, CmdType::PDXA,  { 0, 0, 0 }},\n            {   45, CmdType::PDEP,  { 0, 0, 0 }},\n            {   70, CmdType::PDXP,  { 0, 0, 0 }},\n            { 85, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR4> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_8, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 30);\n    ASSERT_EQ(stats.rank_total[0].cycles.selfRefresh, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 30);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 25);\n\n    // Check bank specific ACT cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.act, 0);\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.pre, 30);\n\n    // Check bank specific PDNA cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownAct, 30);\n\n    // Check bank specific PDNP cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownPre, 25);\n\n    // Check bank specific SREF cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.selfRefresh, 0);\n}\n\nTEST_F(DramPowerTest_LPDDR4_8, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_sref*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_PDNA*1e12), 623);\n    ASSERT_EQ(std::round(energy.E_PDNP*1e12), 392);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 935);\n    ASSERT_EQ(std::round((total_energy.total() + energy.E_sref + energy.E_PDNA + energy.E_PDNP)*1e12), 1950);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR4/lpddr4_test_pattern_9.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR4_9 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   5, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::ACT,  { 5, 0, 0 }},\n            {   20, CmdType::RD,  { 0, 0, 0 }},\n            {   30, CmdType::PDEA,  { 0, 0, 0 }},\n            {   50, CmdType::PDXA,  { 0, 0, 0 }},\n            {   55, CmdType::RD,  { 5, 0, 0 }},\n            {   60, CmdType::RD,  { 0, 0, 0 }},\n            {   70, CmdType::PREA,  { 0, 0, 0 }},\n            {   80, CmdType::PDEP,  { 0, 0, 0 }},\n            {   95, CmdType::PDXP,  { 0, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR4> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR4> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR4>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR4_9, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 45);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 20);\n    ASSERT_EQ(stats.rank_total[0].cycles.selfRefresh, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 20);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 15);\n\n    // Check bank specific ACT cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0){\n            ASSERT_EQ(stats .bank[b].cycles.act, 45);\n        }else if (b == 5){\n            ASSERT_EQ(stats .bank[b].cycles.act, 35);\n        }else{\n            ASSERT_EQ(stats .bank[b].cycles.act, 0);\n        }\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 20);\n        }else if (b == 5){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 30);\n        }else{\n            ASSERT_EQ(stats.bank[b].cycles.pre, 65);\n        }\n    }\n\n    // Check bank specific PDNA cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownAct, 20);\n\n    // Check bank specific PDNP cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownPre, 15);\n\n    // Check bank specific SREF cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.selfRefresh, 0);\n}\n\nTEST_F(DramPowerTest_LPDDR4_9, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 392);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 1357);\n    ASSERT_EQ(std::round(energy.E_sref*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_PDNA*1e12), 415);\n    ASSERT_EQ(std::round(energy.E_PDNP*1e12), 235);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1474);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1428);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 623);\n    ASSERT_EQ(std::round((total_energy.total() + energy.E_sref + energy.E_PDNA + energy.E_PDNP)*1e12), 4912);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_multidevice_tests.cpp",
    "content": "/* Note\nThis test is based on lpddr5_test_pattern_4.cpp and assumes the correctness of the test.\n\nCalculation for 5 devices:\nE_act: \t\t\t\t\t392.30769230769232\nE_pre: \t\t\t\t\t415.38461538461542\nE_RD:\t\t\t\t\t678.46153846153845\nE_bg_act:\t\t\t\t1632.6923076923078\nE_bg_act_shared:\t\t1586.5384615384617\nE_bg_pre:\t\t\t\t623.07692307692309\nTotal:\t\t\t\t\t3741.9230769230776\n\nE_act * 5:\t\t\t\t1961.5384615384616\nE_pre * 5:\t\t\t\t2076.9230769230771\nE_RD * 5:\t\t\t\t3392.30769230769225\nE_bg_act * 5:\t\t\t8163.461538461539\nE_bg_act_shared * 5:\t7932.6923076923085\nE_bg_pre * 5:\t\t\t3115.38461538461545\nTotal * 5:\t\t\t\t18709.615384615388\n*/\n\n\n#include \"DRAMPower/memspec/MemSpecLPDDR5.h\"\n#include <gtest/gtest.h>\n\n#include <DRAMPower/command/Command.h>\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_MultiDevice : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::RD,  { 3, 0, 0 }},\n            {   40, CmdType::RD,  { 0, 0, 0 }},\n            {   50, CmdType::PREA,  { 0, 0, 0 }},\n            { 70, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n    uint64_t numberOfDevices;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        memSpec->numberOfDevices = 5;\n\n        numberOfDevices = memSpec->numberOfDevices;\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_MultiDevice, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].counter.reads, 2);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    };\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 50);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 20);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 50);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 30);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 0);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 20);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 40);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 70);\n    }\n}\n\nTEST_F(DramPowerTest_LPDDR5_MultiDevice, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(energy.bank_energy.size(), numberOfDevices * memSpec->numberOfBanks);\n\n    // Validate every device has the same bank energy\n    for(size_t i = 0; i < numberOfDevices; i++){\n        for(size_t j = 0; j < memSpec->numberOfBanks; j++){\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_act, energy.bank_energy[j].E_act);\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_pre, energy.bank_energy[j].E_pre);\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_RD, energy.bank_energy[j].E_RD);\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_bg_act, energy.bank_energy[j].E_bg_act);\n            ASSERT_EQ(energy.bank_energy[i * memSpec->numberOfBanks + j].E_bg_pre, energy.bank_energy[j].E_bg_pre);\n        }\n    }\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 1962);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 2077);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 3392);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 8163);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 7933);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 3115);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 18710);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_multirank_tests.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <fstream>\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n#include <variant>\n\n#include \"DRAMPower/command/Command.h\"\n#include \"DRAMPower/standards/lpddr5/LPDDR5.h\"\n#include \"DRAMPower/memspec/MemSpecLPDDR5.h\"\n\nusing DRAMPower::CmdType;\nusing DRAMPower::Command;\nusing DRAMPower::LPDDR5;\nusing DRAMPower::MemSpecLPDDR5;\nusing DRAMPower::SimulationStats;\nusing DRAMPower::TargetCoordinate;\n\n#define SZ_BITS(x) sizeof(x)*8\n\nstatic constexpr uint8_t wr_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 255,  0, 0, 0, 0,  0, 0, 0, 0,\n    0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 255,\n};\n\nstatic constexpr uint8_t rd_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 1,  0, 0, 0, 0,  0, 0, 0, 0,\n    0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,\n};\n\nclass LPDDR5_MultirankTests : public ::testing::Test {\n  public:\n    LPDDR5_MultirankTests() {\n\n        initSpec();\n        ddr = std::make_unique<LPDDR5>(*spec);\n    }\n\n    void initSpec() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        spec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n        spec->numberOfRanks = 2;\n    }\n\n    void runCommands(const std::vector<Command> &commands) {\n        for (const Command &command : commands) {\n            ddr->doCoreCommand(command);\n            ddr->doInterfaceCommand(command);\n        }\n    }\n\n    inline size_t bankIndex(int bank, int rank) {\n        return rank * spec->numberOfBanks + bank;\n    }\n\n    std::unique_ptr<MemSpecLPDDR5> spec;\n    std::unique_ptr<LPDDR5> ddr;\n};\n\nTEST_F(LPDDR5_MultirankTests, Pattern_1) {\n    runCommands({\n        {0, CmdType::ACT, {1, 0, 0}},\n        {2, CmdType::ACT, {1, 0, 1}},  // rank 1\n        {4, CmdType::WR, {1, 0, 0, 0, 4}, wr_data, SZ_BITS(wr_data)},\n        {6, CmdType::RD, {1, 0, 1, 0, 4}, rd_data, SZ_BITS(rd_data)},  // rank 1\n        {10, CmdType::PRE, {1, 0, 1}},  // rank 1\n        {15, CmdType::PRE, {1, 0, 0}},\n        {20, CmdType::END_OF_SIMULATION}\n    });\n\n    SimulationStats stats = ddr->getStats();\n    EXPECT_EQ(stats.bank.size(), spec->numberOfBanks * spec->numberOfRanks);\n    EXPECT_EQ(stats.bank[bankIndex(1, 0)].cycles.act, 15);\n    EXPECT_EQ(stats.bank[bankIndex(1, 1)].cycles.act, 8);\n    EXPECT_EQ(stats.bank[bankIndex(1, 0)].cycles.pre, 5);\n    EXPECT_EQ(stats.bank[bankIndex(1, 1)].cycles.pre, 12);\n\n    EXPECT_EQ(stats.rank_total[0].cycles.act, 15);\n    EXPECT_EQ(stats.rank_total[1].cycles.act, 8);\n}\n\nTEST_F(LPDDR5_MultirankTests, Pattern_2) {\n    runCommands({\n        {0, CmdType::ACT,   TargetCoordinate{0, 0, 0}}, // r0\n        {5, CmdType::ACT,   TargetCoordinate{0, 0, 1}}, // r1\n        {22, CmdType::ACT,  TargetCoordinate{3, 0, 1}}, // r1\n        {35, CmdType::RD,   TargetCoordinate{3, 0, 1, 0, 0}, rd_data, SZ_BITS(rd_data)}, // r1\n        {55, CmdType::RD,   TargetCoordinate{0, 0, 0, 0, 3}, rd_data, SZ_BITS(rd_data)}, // r0\n        {60, CmdType::PREA, TargetCoordinate{0, 0, 0}}, // r0\n        {65, CmdType::PREA, TargetCoordinate{0, 0, 1}}, // r1\n        {75, CmdType::REFA, TargetCoordinate{0, 0, 0}}, // r0\n        {80, CmdType::REFA, TargetCoordinate{0, 0, 1}}, // r1\n        {130, CmdType::END_OF_SIMULATION},\n    });\n\n    SimulationStats stats = ddr->getStats();\n    EXPECT_EQ(stats.bank.size(), spec->numberOfBanks * spec->numberOfRanks);\n    EXPECT_EQ(stats.bank[bankIndex(0, 0)].cycles.act, 85);\n    EXPECT_EQ(stats.bank[bankIndex(0, 1)].cycles.act, 85);\n    EXPECT_EQ(stats.bank[bankIndex(3, 1)].cycles.act, 68);\n\n    EXPECT_EQ(stats.bank[bankIndex(0, 0)].cycles.pre, 130 - 85);\n    EXPECT_EQ(stats.bank[bankIndex(0, 1)].cycles.pre,  130 - 85);\n    EXPECT_EQ(stats.bank[bankIndex(3, 1)].cycles.pre,  130 - 68);\n\n    EXPECT_EQ(stats.rank_total[0].cycles.act, 85);\n    EXPECT_EQ(stats.rank_total[1].cycles.act, 85);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_0.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_0 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::PRE,  { 0, 0, 0 }},\n            { 15, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_0, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    ASSERT_EQ(stats.bank[0].counter.act, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].counter.act, 0);\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 15);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 0);\n\n    // Check bank specific ACT cycle count\n    ASSERT_EQ(stats.bank[0].cycles.act, 15);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.act, 0);\n\n    // Check bank specific PRE cycle count\n    ASSERT_EQ(stats.bank[0].cycles.pre, 0);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.pre, 15);\n}\n\nTEST_F(DramPowerTest_LPDDR5_0, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 196);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 208);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 476);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 485);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre)*1e12, 0);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 888);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_1.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_1 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   35, CmdType::PRE,  { 0, 0, 0 }},\n            { 35, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_1, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    ASSERT_EQ(stats.bank[0].counter.act, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.act, 0);\n\n    // Check bank command count: RD\n    ASSERT_EQ(stats.bank[0].counter.reads, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.reads, 0);\n\n    // Check bank command count: PRE\n    ASSERT_EQ(stats.bank[0].counter.pre, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.pre, 0);\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 35);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 0);\n\n    // Check bank specific ACT cycle count\n    ASSERT_EQ(stats.bank[0].cycles.act, 35);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.act, 0);\n\n    // Check bank specific PRE cycle count\n    ASSERT_EQ(stats.bank[0].cycles.pre, 0);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.pre, 35);\n}\n\nTEST_F(DramPowerTest_LPDDR5_1, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 196);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 208);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 226);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1131);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1111);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 1761);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_10.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_10 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   10, CmdType::ACT,  { 0, 0, 0 }},\n            {   30, CmdType::PRE,  { 0, 0, 0 }},\n            {   45, CmdType::SREFEN,  { 0, 0, 0 }},\n            {   70, CmdType::DSMEN,  { 0, 0, 0 }},\n            {   85, CmdType::DSMEX,  { 0, 0, 0 }},\n            {   95, CmdType::SREFEX,  { 0, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_10, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 45);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 30);\n    ASSERT_EQ(stats.rank_total[0].cycles.selfRefresh, 10);\n    ASSERT_EQ(stats.rank_total[0].cycles.deepSleepMode, 15);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 0);\n\n    // Check bank specific ACT cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0){\n            ASSERT_EQ(stats.bank[b].cycles.act, 45);\n        }else{\n            ASSERT_EQ(stats.bank[b].cycles.act, 25);\n        }\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 30);\n        }else{\n            ASSERT_EQ(stats.bank[b].cycles.pre, 50);\n        }\n    }\n\n    // Check bank specific PDNA cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownAct, 0);\n\n    // Check bank specific PDNP cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownPre, 0);\n\n    // Check bank specific SREF cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.selfRefresh, 10);\n\n    // Check bank specific DSM cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.deepSleepMode, 15);\n}\n\nTEST_F(DramPowerTest_LPDDR5_10, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 196);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 208);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_sref*1e12), 187);\n    ASSERT_EQ(std::round(energy.E_PDNA*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_PDNP*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_dsm*1e12), 183);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1670);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1428);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 935);\n    ASSERT_EQ(std::round((total_energy.total() + energy.E_dsm +energy.E_sref + energy.E_PDNA + energy.E_PDNP)*1e12), 5078);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_11.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_11 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   5, CmdType::ACT,  { 2, 0, 0 }},\n            {   15, CmdType::ACT,  { 10, 0, 0 }},\n            {   30, CmdType::PREA,  { 0, 0, 0 }},\n            {   40, CmdType::REFP2B,  { 9, 0, 0 }},\n            {   50, CmdType::REFP2B,  { 5, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_11, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 60);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 40);\n    ASSERT_EQ(stats.rank_total[0].cycles.selfRefresh, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 0);\n\n    // Check bank specific ACT cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0){\n            ASSERT_EQ(stats .bank[b].cycles.act, 30);\n        }else if (b == 2){\n            ASSERT_EQ(stats .bank[b].cycles.act, 25);\n        }else if(b == 10){\n            ASSERT_EQ(stats .bank[b].cycles.act, 15);\n        }else if (b == 1 || b == 9 || b == 5 || b == 13){\n            ASSERT_EQ(stats .bank[b].cycles.act, 20);\n        }else{\n            ASSERT_EQ(stats .bank[b].cycles.act, 0);\n        }\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 70);\n        }else if (b == 2){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 75);\n        }else if (b== 10){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 85);\n        }else if (b == 1 || b == 9 || b == 5 || b == 13){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 80);\n        }else{\n            ASSERT_EQ(stats.bank[b].cycles.pre, 100);\n        }\n    }\n\n    // Check bank specific PDNA cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownAct, 0);\n\n    // Check bank specific PDNP cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownPre, 0);\n\n    // Check bank specific SREF cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.selfRefresh, 0);\n}\n\nTEST_F(DramPowerTest_LPDDR5_11, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 588);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 623);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_ref_2B*1e12), 117);\n    ASSERT_EQ(std::round(total_energy.E_ref_PB*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_sref*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_PDNA*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_PDNP*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1990);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1904);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 1246);\n    ASSERT_EQ(std::round((total_energy.total() + energy.E_sref + energy.E_PDNA + energy.E_PDNP)*1e12), 4565);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_12.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n#include <DRAMPower/standards/test_accessor.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\n#include <iostream>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_12 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n    // Timestamp,   Cmd,  { Bank, BG, Rank}\n        {   0, CmdType::ACT, { 0, 0, 0 } },\n        {  10, CmdType::ACT, { 1, 0, 0 } },\n        {  15, CmdType::PRE, { 0, 0, 0 } },\n        {  25, CmdType::ACT, { 3, 0, 0 } },\n        {  25, CmdType::PRE, { 1, 0, 0 } },\n        {  30, CmdType::ACT, { 0, 0, 0 } },\n        {  35, CmdType::ACT, { 2, 0, 0 } },\n        {  40, CmdType::PRE, { 1, 0, 0 } },\n        {  40, CmdType::PRE, { 3, 0, 0 } },\n        {  45, CmdType::PRE, { 0, 0, 0 } },\n        {  50, CmdType::PRE, { 2, 0, 0 } },\n        {  85, CmdType::ACT, { 7, 0, 0 } },\n        { 100, CmdType::PRE, { 7, 0, 0 } },\n        { 120, CmdType::ACT, { 6, 0, 0 } },\n        { 125, CmdType::END_OF_SIMULATION},\n    };\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        memSpec->numberOfRanks = 1;\n        memSpec->numberOfBanks = 8;\n        memSpec->banksPerGroup = 8;\n        memSpec->numberOfBankGroups = 1;\n        memSpec->burstLength = 8;\n        memSpec->dataRate = 2;\n        memSpec->bank_arch = MemSpecLPDDR5::M16B;\n        memSpec->numberOfDevices = 1;\n        memSpec->bitWidth = 16;\n\n\t\tmemSpec->memTimingSpec.tRAS = 10;\n\t\tmemSpec->memTimingSpec.tRP = 10;\n        memSpec->memTimingSpec.tCK = 1e-9;\n        memSpec->memTimingSpec.tWCK = 1e-9;\n        memSpec->memTimingSpec.WCKtoCK = 2;\n\n\t\tmemSpec->memPowerSpec[0].vDDX = 1;\n\t\tmemSpec->memPowerSpec[0].iDD0X = 64e-3;\n\t\tmemSpec->memPowerSpec[0].iDD3NX = 32e-3;\n\t\tmemSpec->memPowerSpec[0].iDD2NX = 8e-3;\n        memSpec->memPowerSpec[0].iBeta = memSpec->memPowerSpec[0].iDD0X;\n\t\tmemSpec->bwParams.bwPowerFactRho = 0.333333333;\n\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_12, Pattern1)\n{\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\t// Inspect first rank\n\tconst auto & rank_1 = internal::LPDDR5TestAccessor.getRanks(ddr->getCore()).at(0);\n\tauto stats = ddr->getStats();\n\n\t// Check global count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 70);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 55);\n\n\t// Check per-bank ACT count\n\tASSERT_EQ(stats.bank[0].cycles.act, 30);\n\n\tASSERT_EQ(stats.bank[1].cycles.act, 15);\n\tASSERT_EQ(stats.bank[2].cycles.act, 15);\n\tASSERT_EQ(stats.bank[3].cycles.act, 15);\n\tASSERT_EQ(stats.bank[7].cycles.act, 15);\n\n\tASSERT_EQ(stats.bank[6].cycles.act, 5);\n\n\tASSERT_EQ(stats.bank[4].cycles.act, 0);\n\tASSERT_EQ(stats.bank[5].cycles.act, 0);\n\n\t// Check per-bank PRE count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 95);\n\n\tASSERT_EQ(stats.bank[1].cycles.pre, 110);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 110);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 110);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 110);\n\n\tASSERT_EQ(stats.bank[6].cycles.pre, 120);\n\n\tASSERT_EQ(stats.bank[4].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 125);\n\n\t// Check global command count\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::ACT), 7);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::PRE), 7);\n\n\t// per-bank ACT command count\n\tASSERT_EQ(stats.bank[0].counter.act, 2);\n\n\tASSERT_EQ(stats.bank[1].counter.act, 1);\n\tASSERT_EQ(stats.bank[2].counter.act, 1);\n\tASSERT_EQ(stats.bank[3].counter.act, 1);\n\tASSERT_EQ(stats.bank[6].counter.act, 1);\n\tASSERT_EQ(stats.bank[7].counter.act, 1);\n\n\tASSERT_EQ(stats.bank[4].counter.act, 0);\n\tASSERT_EQ(stats.bank[5].counter.act, 0);\n\n\t// per-bank PRE command count\n\tASSERT_EQ(stats.bank[0].counter.pre, 2);\n\n\tASSERT_EQ(stats.bank[1].counter.pre, 1);\n\tASSERT_EQ(stats.bank[2].counter.pre, 1);\n\tASSERT_EQ(stats.bank[3].counter.pre, 1);\n\tASSERT_EQ(stats.bank[7].counter.pre, 1);\n\n\tASSERT_EQ(stats.bank[6].counter.pre, 0);\n\tASSERT_EQ(stats.bank[4].counter.pre, 0);\n\tASSERT_EQ(stats.bank[5].counter.pre, 0);\n}\n\nTEST_F(DramPowerTest_LPDDR5_12, CalcEnergy)\n{\n    auto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n        while (command != container.end() && command->timestamp <= timestamp) {\n            ddr->doCoreCommand(*command);\n            ++command;\n        }\n    };\n\n    auto command = testPattern.begin();\n    iterate_to_timestamp(command, testPattern, 125);\n    auto energy = ddr->calcCoreEnergy(125);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 2240);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_act*1e12), 640);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_act*1e12), 320);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_act*1e12), 320);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_act*1e12), 320);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_act*1e12), 320);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_act*1e12), 320);\n\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 3360);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_pre*1e12), 1120);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_pre*1e12), 560);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_pre*1e12), 560);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_pre*1e12), 560);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_pre*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_pre*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_pre*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_pre*1e12), 560);\n\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_act*1e12), 480);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_act*1e12), 240);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_act*1e12), 240);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_act*1e12), 240);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_act*1e12), 80);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_act*1e12), 240);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1120);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 2640);\n\n\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 440);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_pre*1e12), 55);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_13.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n#include <DRAMPower/standards/test_accessor.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_13 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{   0, CmdType::ACT, { 0, 0, 0} },\n\t\t{   5, CmdType::ACT, { 1, 0, 0} },\n\t\t{  10, CmdType::ACT, { 2, 0, 0} },\n\t\t{  15, CmdType::ACT, { 3, 0, 0} },\n\t\t{  20, CmdType::ACT, { 4, 0, 0} },\n\t\t{  25, CmdType::ACT, { 5, 0, 0} },\n\t\t{  30, CmdType::ACT, { 6, 0, 0} },\n\t\t{  35, CmdType::ACT, { 7, 0, 0} },\n\t\t{  35, CmdType::RD,  { 0, 0, 0} },\n\t\t{  40, CmdType::RD,  { 0, 0, 0} },\n\t\t{  40, CmdType::RD,  { 1, 0, 0} },\n\t\t{  45, CmdType::RD,  { 0, 0, 0} },\n\t\t{  45, CmdType::RD,  { 2, 0, 0} },\n\t\t{  50, CmdType::RD,  { 3, 0, 0} },\n\t\t{  55, CmdType::RD,  { 4, 0, 0} },\n\t\t{  60, CmdType::RD,  { 5, 0, 0} },\n\t\t{  65, CmdType::RD,  { 6, 0, 0} },\n\t\t{  70, CmdType::RD,  { 7, 0, 0} },\n\t\t{  75, CmdType::RD,  { 7, 0, 0} },\n\t\t{  80, CmdType::RD,  { 7, 0, 0} },\n\t\t{  85, CmdType::WR,  { 7, 0, 0} },\n\t\t{  90, CmdType::WR,  { 6, 0, 0} },\n\t\t{  95, CmdType::WR,  { 5, 0, 0} },\n\t\t{ 100, CmdType::WR,  { 4, 0, 0} },\n\t\t{ 105, CmdType::WR,  { 3, 0, 0} },\n\t\t{ 110, CmdType::WR,  { 2, 0, 0} },\n\t\t{ 110, CmdType::WR,  { 0, 0, 0} },\n\t\t{ 115, CmdType::WR,  { 1, 0, 0} },\n\t\t{ 115, CmdType::RD,  { 0, 0, 0} },\n\t\t{ 120, CmdType::WR,  { 0, 0, 0} },\n\t\t{ 120, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n\t\tmemSpec->numberOfRanks = 1;\n        memSpec->numberOfBanks = 8;\n        memSpec->banksPerGroup = 8;\n\t\tmemSpec->numberOfBankGroups = 1;\n        memSpec->bank_arch = MemSpecLPDDR5::M16B;\n        memSpec->numberOfDevices = 1;\n        memSpec->bitWidth = 16;\n\n\t\tmemSpec->memTimingSpec.tCK = 1e-9;\n        memSpec->memTimingSpec.tWCK = 1e-9;\n        memSpec->memTimingSpec.WCKtoCK = 1;\n\n\t\tmemSpec->memPowerSpec[0].vDDX = 1;\n\t\tmemSpec->memPowerSpec[0].iDD0X = 64e-3;\n\t\tmemSpec->memPowerSpec[0].iDD3NX = 32e-3;\n\t\tmemSpec->memPowerSpec[0].iDD4RX = 72e-3;\n\t\tmemSpec->memPowerSpec[0].iDD4WX = 96e-3;\n        memSpec->memPowerSpec[0].iBeta = memSpec->memPowerSpec[0].iDD0X;\n        memSpec->bwParams.bwPowerFactRho = 1;\n\n        memSpec->burstLength = 16;\n\t\tmemSpec->dataRate = 2;\n\n        memSpec->memTimingSpec.tBurst = memSpec->burstLength/(memSpec->dataRate * memSpec->memTimingSpec.WCKtoCK);\n        memSpec->prechargeOffsetRD      =   memSpec->memTimingSpec.tBurst + memSpec->memTimingSpec.tRBTP;\n        memSpec->prechargeOffsetWR      =  memSpec->memTimingSpec.tWL + memSpec->memTimingSpec.tBurst + 1 + memSpec->memTimingSpec.tWR;\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_13, Pattern_2)\n{\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\t// Inspect first rank\n\tconst Rank & rank_1 = internal::LPDDR5TestAccessor.getRanks(ddr->getCore()).at(0);\n\n\t// Check global command count\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::RD), 13);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::WR), 9);\n\n\t// Check bank RD command count\n\tASSERT_EQ(rank_1.banks[0].counter.reads, 4);\n\tASSERT_EQ(rank_1.banks[1].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[2].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[3].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[4].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[5].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[6].counter.reads, 1);\n\tASSERT_EQ(rank_1.banks[7].counter.reads, 3);\n\n\t// Check bank WR command count\n\tASSERT_EQ(rank_1.banks[0].counter.writes, 2);\n\tASSERT_EQ(rank_1.banks[1].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[2].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[3].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[4].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[5].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[6].counter.writes, 1);\n\tASSERT_EQ(rank_1.banks[7].counter.writes, 1);\n}\n\nTEST_F(DramPowerTest_LPDDR5_13, CalcEnergy)\n{\n    auto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ(std::round(total_energy.E_RD*1e12), 4160);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_RD*1e12), 1280);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_RD*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_RD*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_RD*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_RD*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_RD*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_RD*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_RD*1e12), 960);\n\n\tASSERT_EQ(std::round(total_energy.E_WR*1e12), 4608);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_WR*1e12), 1024);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_WR*1e12), 512);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_WR*1e12), 512);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_WR*1e12), 512);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_WR*1e12), 512);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_WR*1e12), 512);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_WR*1e12), 512);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_WR*1e12), 512);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_14.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n#include <DRAMPower/standards/test_accessor.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_14 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t// Timestamp,   Cmd,  { Bank, BG, Rank}\n\t\t{   0, CmdType::ACT, { 0, 0, 0 }  },\n\t\t{  10, CmdType::RDA, { 0, 0, 0 }  },\n\t\t{  15, CmdType::ACT, { 1, 0, 0 }  },\n\t\t{  15, CmdType::ACT, { 2, 0, 0 }  },\n\t\t{  25, CmdType::WRA, { 1, 0, 0 }  },\n\t\t{  30, CmdType::PRE, { 0, 0, 0 }  },\n\t\t{  35, CmdType::RDA, { 2, 0, 0 }  },\n\t\t{  50, CmdType::ACT, { 0, 0, 0 }  },\n\t\t{  50, CmdType::ACT, { 2, 0, 0 }  },\n\t\t{  60, CmdType::WRA, { 0, 0, 0 }  },\n\t\t{  60, CmdType::RDA, { 2, 0, 0 }  },\n\t\t{  75, CmdType::ACT, { 1, 0, 0 }  },\n\t\t{  80, CmdType::ACT, { 0, 0, 0 }  },\n\t\t{  85, CmdType::WRA, { 0, 0, 0 }  },\n\t\t{  95, CmdType::RDA, { 1, 0, 0 }  },\n\t\t{ 125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n\t\tmemSpec->numberOfRanks = 1;\n        memSpec->numberOfBanks = 8;\n        memSpec->banksPerGroup = 8;\n        memSpec->numberOfBankGroups = 1;\n        memSpec->bank_arch = MemSpecLPDDR5::M16B;\n        memSpec->numberOfDevices = 1;\n        memSpec->bitWidth = 16;\n\n\n        memSpec->memTimingSpec.tRAS = 20;\n\t\tmemSpec->memTimingSpec.tWR = 11;\n\t\tmemSpec->memTimingSpec.tWL = 0;\n\t\tmemSpec->memTimingSpec.tCK = 1e-9;\n        memSpec->memTimingSpec.tWCK = 1e-9;\n        memSpec->memTimingSpec.WCKtoCK = 1;\n        memSpec->memTimingSpec.tRP = 10;\n        memSpec->memTimingSpec.tRBTP = 2;\n\n\t\tmemSpec->memPowerSpec[0].vDDX = 1;\n\t\tmemSpec->memPowerSpec[0].iDD0X = 64e-3;\n\t\tmemSpec->memPowerSpec[0].iDD2NX = 8e-3;\n\t\tmemSpec->memPowerSpec[0].iDD3NX = 32e-3;\n\t\tmemSpec->memPowerSpec[0].iDD4RX = 72e-3;\n\t\tmemSpec->memPowerSpec[0].iDD4WX = 96e-3;\n        memSpec->memPowerSpec[0].iBeta = memSpec->memPowerSpec[0].iDD0X;\n\n\t\tmemSpec->bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec->burstLength = 16;\n\t\tmemSpec->dataRate = 2;\n\n        memSpec->memTimingSpec.tBurst = memSpec->burstLength/(memSpec->dataRate * memSpec->memTimingSpec.WCKtoCK);\n        memSpec->prechargeOffsetRD      =   memSpec->memTimingSpec.tBurst + memSpec->memTimingSpec.tRBTP;\n        memSpec->prechargeOffsetWR      =  memSpec->memTimingSpec.tWL + memSpec->memTimingSpec.tBurst + 1 + memSpec->memTimingSpec.tWR;\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_14, Test)\n{\n\tfor (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\tconst Rank & rank_1 = internal::LPDDR5TestAccessor.getRanks(ddr->getCore()).at(0);\n\n\tauto stats = ddr->getStats();\n\n\t// Check global command count\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::ACT), 7);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::PRE), 1);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::RDA), 4);\n\tASSERT_EQ(rank_1.commandCounter.get(CmdType::WRA), 3);\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 3);\n\tASSERT_EQ(stats.bank[1].counter.act, 2);\n\tASSERT_EQ(stats.bank[2].counter.act, 2);\n\tASSERT_EQ(stats.bank[3].counter.act, 0);\n\tASSERT_EQ(stats.bank[4].counter.act, 0);\n\tASSERT_EQ(stats.bank[5].counter.act, 0);\n\tASSERT_EQ(stats.bank[6].counter.act, 0);\n\tASSERT_EQ(stats.bank[7].counter.act, 0);\n\n\t// Check bank command count: RDA\n\tASSERT_EQ(stats.bank[0].counter.readAuto, 1);\n\tASSERT_EQ(stats.bank[1].counter.readAuto, 1);\n\tASSERT_EQ(stats.bank[2].counter.readAuto, 2);\n\tASSERT_EQ(stats.bank[3].counter.readAuto, 0);\n\tASSERT_EQ(stats.bank[4].counter.readAuto, 0);\n\tASSERT_EQ(stats.bank[5].counter.readAuto, 0);\n\tASSERT_EQ(stats.bank[6].counter.readAuto, 0);\n\tASSERT_EQ(stats.bank[7].counter.readAuto, 0);\n\n\t// Check bank command count: WRA\n\tASSERT_EQ(stats.bank[0].counter.writeAuto, 2);\n\tASSERT_EQ(stats.bank[1].counter.writeAuto, 1);\n\tASSERT_EQ(stats.bank[2].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[3].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[4].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[5].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[6].counter.writeAuto, 0);\n\tASSERT_EQ(stats.bank[7].counter.writeAuto, 0);\n\n\t// Check cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 100);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 25);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 75);\n\tASSERT_EQ(stats.bank[1].cycles.act, 60);\n\tASSERT_EQ(stats.bank[2].cycles.act, 50);\n\tASSERT_EQ(stats.bank[3].cycles.act, 0);\n\tASSERT_EQ(stats.bank[4].cycles.act, 0);\n\tASSERT_EQ(stats.bank[5].cycles.act, 0);\n\tASSERT_EQ(stats.bank[6].cycles.act, 0);\n\tASSERT_EQ(stats.bank[7].cycles.act, 0);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 50);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 65);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 75);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[6].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 125);\n}\n\nTEST_F(DramPowerTest_LPDDR5_14, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 4560);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1600);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_act*1e12), 1200);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_act*1e12), 960);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_act*1e12), 800);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_act*1e12), 0);\n\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 200);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_pre*1e12), 25);\n\n    ASSERT_EQ(std::round(total_energy.E_RDA*1e12), 1280);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_RDA*1e12), 320);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_RDA*1e12), 320);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_RDA*1e12), 640);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_RDA*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_RDA*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_RDA*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_RDA*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_RDA*1e12), 0);\n\n    ASSERT_EQ(std::round(total_energy.E_WRA*1e12), 1536);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_WRA*1e12), 1024);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_WRA*1e12), 512);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_WRA*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_WRA*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_WRA*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_WRA*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_WRA*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_WRA*1e12), 0);\n\n    ASSERT_EQ(std::round(total_energy.E_pre_RDA*1e12), 2240);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_pre_RDA*1e12), 560);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_pre_RDA*1e12), 560);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_pre_RDA*1e12), 1120);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_pre_RDA*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_pre_RDA*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_pre_RDA*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_pre_RDA*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_pre_RDA*1e12), 0);\n\n    ASSERT_EQ(std::round(total_energy.E_pre_WRA*1e12), 1120+560);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_pre_WRA*1e12), 1120);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_pre_WRA*1e12), 560);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_pre_WRA*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_pre_WRA*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_pre_WRA*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_pre_WRA*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_pre_WRA*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_pre_WRA*1e12), 0);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_15.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_15 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{   0, CmdType::ACT,  { 0, 0, 0 }},\n\t\t{   5, CmdType::ACT,  { 1, 0, 0 }},\n\t\t{  10, CmdType::ACT,  { 2, 0, 0 }},\n\t\t{  15, CmdType::PRE,  { 0, 0, 0 }},\n\t\t{  20, CmdType::PREA, { 0, 0, 0 }},\n\t\t{  25, CmdType::PRE,  { 1, 0, 0 }},\n\t\t{  30, CmdType::PREA, { 0, 0, 0 }},\n\t\t{  40, CmdType::ACT,  { 0, 0, 0 }},\n\t\t{  40, CmdType::ACT,  { 3, 0, 0 }},\n\t\t{  50, CmdType::PRE,  { 3, 0, 0 }},\n\t\t{ 125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n\t\tmemSpec->numberOfRanks = 1;\n        memSpec->numberOfBanks = 8;\n        memSpec->banksPerGroup = 8;\n        memSpec->numberOfBankGroups = 1;\n        memSpec->bank_arch = MemSpecLPDDR5::M16B;\n        memSpec->numberOfDevices = 1;\n        memSpec->bitWidth = 16;\n\n\n        memSpec->memTimingSpec.tRAS = 10;\n\t\tmemSpec->memTimingSpec.tWR = 20;\n\n\t\tmemSpec->memTimingSpec.tWR = 12;\n\t\tmemSpec->memTimingSpec.tWL = 0;\n\t\tmemSpec->memTimingSpec.tCK = 1e-9;\n        memSpec->memTimingSpec.tWCK = 1e-9;\n\t\tmemSpec->memTimingSpec.tRP = 10;\n\t\tmemSpec->memTimingSpec.WCKtoCK = 2;\n\n\t\tmemSpec->memPowerSpec[0].vDDX = 1;\n\t\tmemSpec->memPowerSpec[0].iDD0X = 64e-3;\n\t\tmemSpec->memPowerSpec[0].iDD2NX = 8e-3;\n\t\tmemSpec->memPowerSpec[0].iDD3NX = 32e-3;\n\t\tmemSpec->memPowerSpec[0].iDD4RX = 72e-3;\n\t\tmemSpec->memPowerSpec[0].iDD4WX = 72e-3;\n        memSpec->memPowerSpec[0].iBeta = memSpec->memPowerSpec[0].iDD0X;\n\n\t\tmemSpec->bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec->burstLength = 16;\n\t\tmemSpec->dataRate = 2;\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_15, Test)\n{\n\tfor (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 2);\n\tASSERT_EQ(stats.bank[1].counter.act, 1);\n\tASSERT_EQ(stats.bank[2].counter.act, 1);\n\tASSERT_EQ(stats.bank[3].counter.act, 1);\n\tASSERT_EQ(stats.bank[4].counter.act, 0);\n\n\t// Check cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 105);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 20);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 100);\n\tASSERT_EQ(stats.bank[1].cycles.act, 15);\n\tASSERT_EQ(stats.bank[2].cycles.act, 10);\n\tASSERT_EQ(stats.bank[3].cycles.act, 10);\n\tASSERT_EQ(stats.bank[4].cycles.act, 0);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 25);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 110);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 115);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 115);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 125);\n}\n\nTEST_F(DramPowerTest_LPDDR5_15, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 1600);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_act*1e12), 640);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_act*1e12), 320);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_act*1e12), 320);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_act*1e12), 320);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_act*1e12), 0);\n\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 2240);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_pre*1e12), 560);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_pre*1e12), 560);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_pre*1e12), 560);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_pre*1e12), 560);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_pre*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_pre*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_pre*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_pre*1e12), 0);\n\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 3840);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1680);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_act*1e12), 1600);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_act*1e12), 240);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_act*1e12), 160);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_act*1e12), 160);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_act*1e12), 0);\n\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 160);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_pre*1e12), 20);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_pre*1e12), 20);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_pre*1e12), 20);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_pre*1e12), 20);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_pre*1e12), 20);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_pre*1e12), 20);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_pre*1e12), 20);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_pre*1e12), 20);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_16.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_16 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{  0, CmdType::ACT,  { 0, 0, 0}},\n\t\t{  0, CmdType::ACT,  { 1, 0, 0}},\n\t\t{  0, CmdType::ACT,  { 2, 0, 0}},\n\t\t{ 15, CmdType::PRE,  { 0, 0, 0}},\n\t\t{ 20, CmdType::REFB, { 0, 0, 0}},\n\t\t{ 25, CmdType::PRE,  { 1, 0, 0}},\n\t\t{ 30, CmdType::RDA,  { 2, 0, 0}},\n\t\t{ 50, CmdType::REFB, { 2, 0, 0}},\n\t\t{ 60, CmdType::ACT,  { 1, 0, 0}},\n\t\t{ 80, CmdType::PRE,  { 1, 0, 0}},\n\t\t{ 85, CmdType::REFB, { 1, 0, 0}},\n\t\t{ 85, CmdType::REFB, { 0, 0, 0}},\n\t\t{ 125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n\t\tmemSpec->numberOfRanks = 1;\n        memSpec->numberOfBanks = 8;\n        memSpec->banksPerGroup = 8;\n        memSpec->numberOfBankGroups = 1;\n        memSpec->bank_arch = MemSpecLPDDR5::M16B;\n        memSpec->numberOfDevices = 1;\n        memSpec->bitWidth = 16;\n\n\n        memSpec->memTimingSpec.tRAS = 10;\n        memSpec->memTimingSpec.tRFCPB = 25;\n\t\tmemSpec->memTimingSpec.tWR = 20;\n\t\tmemSpec->memTimingSpec.tWL = 0;\n\t\tmemSpec->memTimingSpec.tCK = 1e-9;\n        memSpec->memTimingSpec.tWCK = 1e-9;\n        memSpec->memTimingSpec.tRP = 10;\n\t\tmemSpec->memTimingSpec.tREFI = 1;\n        memSpec->memTimingSpec.WCKtoCK = 1;\n        memSpec->memTimingSpec.tRBTP = 2;\n\n\n\t\tmemSpec->memPowerSpec[0].vDDX = 1;\n\t\tmemSpec->memPowerSpec[0].iDD0X = 64e-3;\n\t\tmemSpec->memPowerSpec[0].iDD2NX = 8e-3;\n\t\tmemSpec->memPowerSpec[0].iDD3NX = 32e-3;\n\t\tmemSpec->memPowerSpec[0].iDD4RX = 72e-3;\n\t\tmemSpec->memPowerSpec[0].iDD4WX = 72e-3;\n\t\tmemSpec->memPowerSpec[0].iDD5PBX = 6008e-3;\n        memSpec->memPowerSpec[0].iBeta = memSpec->memPowerSpec[0].iDD0X;\n\n        memSpec->bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec->burstLength = 16;\n\t\tmemSpec->dataRate = 2;\n\n        memSpec->memTimingSpec.tBurst = memSpec->burstLength/(memSpec->dataRate * memSpec->memTimingSpec.WCKtoCK);\n        memSpec->prechargeOffsetRD      =   memSpec->memTimingSpec.tBurst + memSpec->memTimingSpec.tRBTP;\n        memSpec->prechargeOffsetWR      =  memSpec->memTimingSpec.tWL + memSpec->memTimingSpec.tBurst + 1 + memSpec->memTimingSpec.tWR;\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_16, Test)\n{\n\tfor (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 1);\n\tASSERT_EQ(stats.bank[1].counter.act, 2);\n\tASSERT_EQ(stats.bank[2].counter.act, 1);\n\tASSERT_EQ(stats.bank[3].counter.act, 0);\n\n\t// Check bank command count: PRE\n\tASSERT_EQ(stats.bank[0].counter.pre, 1);\n\tASSERT_EQ(stats.bank[1].counter.pre, 2);\n\tASSERT_EQ(stats.bank[2].counter.pre, 1);\n\tASSERT_EQ(stats.bank[3].counter.pre, 0);\n\n\t// Check bank command count: REFPB\n\tASSERT_EQ(stats.bank[0].counter.refPerBank, 2);\n\tASSERT_EQ(stats.bank[1].counter.refPerBank, 1);\n\tASSERT_EQ(stats.bank[2].counter.refPerBank, 1);\n\tASSERT_EQ(stats.bank[3].counter.refPerBank, 0);\n\n\t// Check global cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 100);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 25);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 65);\n\tASSERT_EQ(stats.bank[1].cycles.act, 70);\n\tASSERT_EQ(stats.bank[2].cycles.act, 65);\n\tASSERT_EQ(stats.bank[3].cycles.act, 0);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 55);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 125);\n}\n\nTEST_F(DramPowerTest_LPDDR5_16, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 4800);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1600);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_act*1e12), 1040);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_act*1e12), 1120);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_act*1e12), 1040);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_act*1e12), 0);\n\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 200);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_pre*1e12), 25);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_pre*1e12), 25);\n\n    ASSERT_EQ(std::round(total_energy.E_ref_PB*1e12), 600);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_ref_PB*1e12), 300);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_ref_PB*1e12), 150);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_ref_PB*1e12), 150);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_ref_PB*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_ref_PB*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_ref_PB*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_ref_PB*1e12), 0);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_ref_PB*1e12), 0);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_17.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_17 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{  0, CmdType::REFP2B, { 0, 0, 0 }},\n\t\t{  5, CmdType::REFP2B, { 1, 0, 0 }},\n\t\t{ 40, CmdType::REFP2B, { 4, 0, 0 }},\n\t\t{ 45, CmdType::ACT,    { 0, 0, 0 }},\n\t\t{ 70, CmdType::PRE,    { 0, 0, 0 }},\n\t\t{ 80, CmdType::REFP2B, { 0, 0, 0 }},\n\t\t{125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n\t\tmemSpec->numberOfRanks = 1;\n        memSpec->numberOfBanks = 8;\n        memSpec->numberOfBankGroups = 2;\n\t\tmemSpec->perTwoBankOffset = 2;\n        memSpec->bank_arch = MemSpecLPDDR5::MBG;\n        memSpec->numberOfDevices = 1;\n        memSpec->bitWidth = 16;\n\n\n        memSpec->memTimingSpec.tRAS = 10;\n\t\tmemSpec->memTimingSpec.tRFCPB = 25;\n\n\t\tmemSpec->memTimingSpec.tWR = 20;\n\t\tmemSpec->memTimingSpec.tWL = 0;\n\t\tmemSpec->memTimingSpec.tCK = 1e-9;\n        memSpec->memTimingSpec.tWCK = 1e-9;\n        memSpec->memTimingSpec.tRP = 10;\n\t\tmemSpec->memTimingSpec.tREFI = 1;\n\t\tmemSpec->memTimingSpec.WCKtoCK = 2;\n\n\t\tmemSpec->memPowerSpec[0].vDDX = 1;\n\t\tmemSpec->memPowerSpec[0].iDD0X = 64e-3;\n\t\tmemSpec->memPowerSpec[0].iDD2NX = 8e-3;\n\t\tmemSpec->memPowerSpec[0].iDD3NX = 32e-3;\n\t\tmemSpec->memPowerSpec[0].iDD4RX = 72e-3;\n\t\tmemSpec->memPowerSpec[0].iDD4WX = 72e-3;\n\t\tmemSpec->memPowerSpec[0].iDD5PBX = 10009e-3;\n        memSpec->memPowerSpec[0].iBeta = memSpec->memPowerSpec[0].iDD0X;\n\n\n        memSpec->bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec->burstLength = 16;\n\t\tmemSpec->dataRate = 2;\n\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_17, Test)\n{\n\tfor (const auto& command : testPattern) {\n\t\tddr->doCoreCommand(command);\n\t};\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 1);\n\n\t// Check bank command count: PRE\n\tASSERT_EQ(stats.bank[0].counter.pre, 1);\n\n\t// Check bank command count: REF2B\n\tASSERT_EQ(stats.bank[0].counter.refPerTwoBanks, 2);\n\tASSERT_EQ(stats.bank[2].counter.refPerTwoBanks, 2);\n\n\tASSERT_EQ(stats.bank[1].counter.refPerTwoBanks, 1);\n\tASSERT_EQ(stats.bank[3].counter.refPerTwoBanks, 1);\n\tASSERT_EQ(stats.bank[4].counter.refPerTwoBanks, 1);\n\tASSERT_EQ(stats.bank[6].counter.refPerTwoBanks, 1);\n\n\t// Check global cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 85);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 40);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 75);\n\n\tASSERT_EQ(stats.bank[2].cycles.act, 50);\n\n\tASSERT_EQ(stats.bank[1].cycles.act, 25);\n\tASSERT_EQ(stats.bank[3].cycles.act, 25);\n\tASSERT_EQ(stats.bank[4].cycles.act, 25);\n\tASSERT_EQ(stats.bank[6].cycles.act, 25);\n\n\tASSERT_EQ(stats.bank[5].cycles.act, 0);\n\tASSERT_EQ(stats.bank[7].cycles.act, 0);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 50);\n\n\tASSERT_EQ(stats.bank[2].cycles.pre, 75);\n\n\tASSERT_EQ(stats.bank[1].cycles.pre, 100);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 100);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 100);\n\tASSERT_EQ(stats.bank[6].cycles.pre, 100);\n\n\tASSERT_EQ(stats.bank[5].cycles.pre, 125);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 125);\n}\n\nTEST_F(DramPowerTest_LPDDR5_17, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n\tASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 4960);\n\tASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1360);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_bg_act*1e12), 1200);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_bg_act*1e12), 800);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_bg_act*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_bg_act*1e12), 400);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_bg_act*1e12), 0);\n\n\tASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 320);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_bg_pre*1e12), 40);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_bg_pre*1e12), 40);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_bg_pre*1e12), 40);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_bg_pre*1e12), 40);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_bg_pre*1e12), 40);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_bg_pre*1e12), 40);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_bg_pre*1e12), 40);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_bg_pre*1e12), 40);\n\n\tASSERT_EQ(std::round(total_energy.E_ref_2B*1e12), 1000);\n\tASSERT_EQ(std::round(energy.bank_energy[0].E_ref_2B*1e12), 250);\n\tASSERT_EQ(std::round(energy.bank_energy[1].E_ref_2B*1e12), 125);\n\tASSERT_EQ(std::round(energy.bank_energy[2].E_ref_2B*1e12), 250);\n\tASSERT_EQ(std::round(energy.bank_energy[3].E_ref_2B*1e12), 125);\n\tASSERT_EQ(std::round(energy.bank_energy[4].E_ref_2B*1e12), 125);\n\tASSERT_EQ(std::round(energy.bank_energy[5].E_ref_2B*1e12), 0);\n\tASSERT_EQ(std::round(energy.bank_energy[6].E_ref_2B*1e12), 125);\n\tASSERT_EQ(std::round(energy.bank_energy[7].E_ref_2B*1e12), 0);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_18.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_18 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{  0,  CmdType::ACT, {0, 0, 0} },\n\t\t{ 20,  CmdType::PDEA },\n\t\t{ 30,  CmdType::PDXA },\n\t\t{ 40,  CmdType::PRE, {0, 0, 0} },\n\t\t{ 60,  CmdType::PDEP },\n\t\t{ 65,  CmdType::PDXP },\n\t\t{ 75,  CmdType::REFA },\n\t\t{100,  CmdType::PDEP },\n\t\t{125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n\t\tmemSpec->numberOfRanks = 1;\n        memSpec->numberOfBanks = 8;\n        memSpec->numberOfBankGroups = 2;\n        memSpec->banksPerGroup = 4;\n\t\tmemSpec->perTwoBankOffset = 2;\n        memSpec->bank_arch = MemSpecLPDDR5::MBG;\n        memSpec->numberOfDevices = 1;\n        memSpec->bitWidth = 16;\n\n\n        memSpec->memTimingSpec.tRAS = 10;\n\t\tmemSpec->memTimingSpec.tRCD = 20;\n\t\tmemSpec->memTimingSpec.tRFC = 25;\n\t\tmemSpec->memTimingSpec.tRFCPB = 25;\n\n\t\tmemSpec->memTimingSpec.tWR = 20;\n\t\tmemSpec->memTimingSpec.tRP = 20;\n\t\tmemSpec->memTimingSpec.tWL = 0;\n\t\tmemSpec->memTimingSpec.tCK = 1e-9;\n        memSpec->memTimingSpec.tWCK = 1e-9;\n        memSpec->memTimingSpec.tREFI = 1;\n\t\tmemSpec->memTimingSpec.WCKtoCK = 2;\n\n\t\tmemSpec->memPowerSpec[0].vDDX = 1;\n\t\tmemSpec->memPowerSpec[0].iDD0X = 64e-3;\n\t\tmemSpec->memPowerSpec[0].iDD2NX = 8e-3;\n\t\tmemSpec->memPowerSpec[0].iDD2PX = 6e-3;\n\t\tmemSpec->memPowerSpec[0].iDD3NX = 32e-3;\n\t\tmemSpec->memPowerSpec[0].iDD3PX = 20e-3;\n\t\tmemSpec->memPowerSpec[0].iDD4RX = 72e-3;\n\t\tmemSpec->memPowerSpec[0].iDD4WX = 72e-3;\n\t\tmemSpec->memPowerSpec[0].iDD5PBX = 30e-3;\n        memSpec->memPowerSpec[0].iBeta = memSpec->memPowerSpec[0].iDD0X;\n\n\n        memSpec->bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec->burstLength = 16;\n\t\tmemSpec->dataRate = 2;\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_18, Test)\n{\n\tfor (const auto& command : testPattern) {\n\t\tddr->doCoreCommand(command);\n\t};\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 1);\n\n\t// Check bank command count: PRE\n\tASSERT_EQ(stats.bank[0].counter.pre, 1);\n\n\t// Check global cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.activeTime(), 55);\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 55);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 30);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 55); ASSERT_EQ(stats.bank[0].cycles.activeTime(), 55);\n\tASSERT_EQ(stats.bank[1].cycles.act, 25); ASSERT_EQ(stats.bank[1].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[2].cycles.act, 25); ASSERT_EQ(stats.bank[2].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[3].cycles.act, 25); ASSERT_EQ(stats.bank[3].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[4].cycles.act, 25); ASSERT_EQ(stats.bank[4].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[5].cycles.act, 25); ASSERT_EQ(stats.bank[5].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[6].cycles.act, 25); ASSERT_EQ(stats.bank[6].cycles.activeTime(), 25);\n\tASSERT_EQ(stats.bank[7].cycles.act, 25); ASSERT_EQ(stats.bank[7].cycles.activeTime(), 25);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 30);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[6].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 60);\n}\n\nTEST_F(DramPowerTest_LPDDR5_18, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 4560);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 880);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_act*1e12), 880);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_act*1e12), 400);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_act*1e12), 400);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_act*1e12), 400);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_act*1e12), 400);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_act*1e12), 400);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_act*1e12), 400);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_act*1e12), 400);\n\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 240);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_pre*1e12), 30);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_pre*1e12), 30);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_pre*1e12), 30);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_pre*1e12), 30);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_pre*1e12), 30);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_pre*1e12), 30);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_pre*1e12), 30);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_pre*1e12), 30);\n\n    ASSERT_EQ(std::round(energy.E_PDNA*1e12), 200);\n    ASSERT_EQ(std::round(energy.E_PDNP*1e12), 180);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_19.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_19 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{  0,  CmdType::ACT, { 0,0,0} },\n\t\t{  5,  CmdType::PDEA },\n\t\t{ 30,  CmdType::PDXA },\n\t\t{ 40,  CmdType::PRE, {0,0,0} },\n\t\t{ 45,  CmdType::PDEP },\n\t\t{ 65,  CmdType::PDXP },\n\t\t{ 75,  CmdType::REFA },\n\t\t{ 85,  CmdType::PDEP },\n\t\t{ 90,  CmdType::PDXP },\n\t\t{125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n\t\tmemSpec->numberOfRanks = 1;\n        memSpec->numberOfBanks = 8;\n        memSpec->numberOfBankGroups = 2;\n        memSpec->banksPerGroup = 4;\n        memSpec->bank_arch = MemSpecLPDDR5::MBG;\n        memSpec->numberOfDevices = 1;\n        memSpec->bitWidth = 16;\n\n\n        memSpec->memTimingSpec.tRAS = 10;\n\t\tmemSpec->memTimingSpec.tRCD = 20;\n\t\tmemSpec->memTimingSpec.tRFC = 25;\n\t\tmemSpec->memTimingSpec.tRFCPB = 25;\n\n\t\tmemSpec->memTimingSpec.tWR = 20;\n\t\tmemSpec->memTimingSpec.tRP = 20;\n\t\tmemSpec->memTimingSpec.tWL = 0;\n\t\tmemSpec->memTimingSpec.tCK = 1e-9;\n        memSpec->memTimingSpec.tWCK = 1e-9;\n        memSpec->memTimingSpec.tREFI = 1;\n\t\tmemSpec->memTimingSpec.WCKtoCK = 2;\n\n\t\tmemSpec->memPowerSpec[0].vDDX = 1;\n\t\tmemSpec->memPowerSpec[0].iDD0X = 64e-3;\n\t\tmemSpec->memPowerSpec[0].iDD2NX = 8e-3;\n\t\tmemSpec->memPowerSpec[0].iDD2PX = 6e-3;\n\t\tmemSpec->memPowerSpec[0].iDD3NX = 32e-3;\n\t\tmemSpec->memPowerSpec[0].iDD3PX = 20e-3;\n\t\tmemSpec->memPowerSpec[0].iDD4RX = 72e-3;\n\t\tmemSpec->memPowerSpec[0].iDD4WX = 72e-3;\n\t\tmemSpec->memPowerSpec[0].iDD5PBX = 30e-3;\n        memSpec->memPowerSpec[0].iBeta = memSpec->memPowerSpec[0].iDD0X;\n\n\n        memSpec->bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec->burstLength = 16;\n\t\tmemSpec->dataRate = 2;\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_19, Test)\n{\n\tfor (const auto& command : testPattern) {\n\t\tddr->doCoreCommand(command);\n\t};\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[0].counter.act, 1);\n\n\t// Check bank command count: PRE\n\tASSERT_EQ(stats.bank[0].counter.pre, 1);\n\n\t// Check global cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 55);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 55);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 5);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 55);\n\tASSERT_EQ(stats.bank[1].cycles.act, 25);\n\tASSERT_EQ(stats.bank[2].cycles.act, 25);\n\tASSERT_EQ(stats.bank[3].cycles.act, 25);\n\tASSERT_EQ(stats.bank[4].cycles.act, 25);\n\tASSERT_EQ(stats.bank[5].cycles.act, 25);\n\tASSERT_EQ(stats.bank[6].cycles.act, 25);\n\tASSERT_EQ(stats.bank[7].cycles.act, 25);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 55);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[6].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 85);\n}\n\nTEST_F(DramPowerTest_LPDDR5_19, CalcWindow)\n{\n\tSimulationStats window;\n\n\tauto iterate_to_timestamp = [this](auto & command, timestamp_t timestamp) {\n\t\twhile (command != this->testPattern.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\n\t\treturn this->ddr->getWindowStats(timestamp);\n\t};\n\n\tauto command = testPattern.begin();\n\n\n\t// Cycle 5\n\twindow = iterate_to_timestamp(command, 5);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 5);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 5);\n\n\t// Cycle 10\n\twindow = iterate_to_timestamp(command, 10);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 10);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act,  0);   ASSERT_EQ(window.bank[1].cycles.pre, 10);\n\n\t// Cycle 15\n\twindow = iterate_to_timestamp(command, 15);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 15);\n\tASSERT_EQ(window.bank[0].cycles.act, 15);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 15);\n\n\t// Cycle 20\n\twindow = iterate_to_timestamp(command, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 20);\n\tASSERT_EQ(window.bank[0].cycles.act, 20);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 20);\n\n\t// Cycle 25\n\twindow = iterate_to_timestamp(command, 25);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 20);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 20);\n\n\t// Cycle 30\n\twindow = iterate_to_timestamp(command, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 20);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 20);\n\n\t// Cycle 35\n\twindow = iterate_to_timestamp(command, 35);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 25);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 25);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);  ASSERT_EQ(window.bank[1].cycles.pre, 25);\n\n\t// Cycle 40\n\twindow = iterate_to_timestamp(command, 40);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act,  0);  ASSERT_EQ(window.bank[1].cycles.pre, 30);\n\n\t// Cycle 45\n\twindow = iterate_to_timestamp(command, 45);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre,  5);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 35);\n\n\t// Cycle 50\n\twindow = iterate_to_timestamp(command, 50);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 10);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 10);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 40);\n\n\t// Cycle 55\n\twindow = iterate_to_timestamp(command, 55);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 15);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 15);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 45);\n\n\t// Cycle 60\n\twindow = iterate_to_timestamp(command, 60);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 20);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 50);\n\n\t// Cycle 65\n\twindow = iterate_to_timestamp(command, 65);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 20);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 20);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 50);\n\n\t// Cycle 70\n\twindow = iterate_to_timestamp(command, 70);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 25);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 25);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 55);\n\n\t// Cycle 75\n\twindow = iterate_to_timestamp(command, 75);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 30);    ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 0);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 80\n\twindow = iterate_to_timestamp(command, 80);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 35);    ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 35);  ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 5);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 85\n\twindow = iterate_to_timestamp(command, 85);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 40);     ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 40);   ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 10);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 90\n\twindow = iterate_to_timestamp(command, 90);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 45);     ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 45);   ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 15);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 95\n\twindow = iterate_to_timestamp(command, 95);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 50);     ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 50);   ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 20);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 100\n\twindow = iterate_to_timestamp(command, 100);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 60);\n\n\t// Cycle 105\n\twindow = iterate_to_timestamp(command, 105);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 35);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 35);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 65);\n\n\t// Cycle 110\n\twindow = iterate_to_timestamp(command, 110);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 40);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 40);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 70);\n\n\t// Cycle 115\n\twindow = iterate_to_timestamp(command, 115);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 45);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 45);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 75);\n\n\t// Cycle 120\n\twindow = iterate_to_timestamp(command, 120);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 50);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 50);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 80);\n\n\t// Cycle 125\n\twindow = iterate_to_timestamp(command, 125);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);     ASSERT_EQ(window.rank_total[0].cycles.pre, 55);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 10); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 55);   ASSERT_EQ(window.bank[0].cycles.pre, 55);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);   ASSERT_EQ(window.bank[1].cycles.pre, 85);\n};\n\n\n\nTEST_F(DramPowerTest_LPDDR5_19, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 4560);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 880);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_act*1e12), 880);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_act*1e12), 400);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_act*1e12), 400);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_act*1e12), 400);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_act*1e12), 400);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_act*1e12), 400);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_act*1e12), 400);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_act*1e12), 400);\n\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 440);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_pre*1e12), 55);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_pre*1e12), 55);\n\n    ASSERT_EQ(std::round(energy.E_PDNA*1e12), 200);\n    ASSERT_EQ(std::round(energy.E_PDNP*1e12), 30);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_2.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_2 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   35, CmdType::PRE,  { 0, 0, 0 }},\n            { 50, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_2, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    ASSERT_EQ(stats.bank[0].counter.act, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.act, 0);\n\n    // Check bank command count: RD\n    ASSERT_EQ(stats.bank[0].counter.reads, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.reads, 0);\n\n    // Check bank command count: PRE\n    ASSERT_EQ(stats.bank[0].counter.pre, 1);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].counter.pre, 0);\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 35);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 15);\n\n    // Check bank specific ACT cycle count\n    ASSERT_EQ(stats.bank[0].cycles.act, 35);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.act, 0);\n\n    // Check bank specific PRE cycle count\n    ASSERT_EQ(stats.bank[0].cycles.pre, 15);\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++)\n        ASSERT_EQ(stats.bank[b].cycles.pre, 50);\n}\n\nTEST_F(DramPowerTest_LPDDR5_2, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 196);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 208);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 226);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1131);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1111);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 467);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 2228);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_20.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_20 : public ::testing::Test {\nprotected:\n    // Test pattern\n\tstd::vector<Command> testPattern = {\n\t\t{  0, CmdType::REFA },\n\t\t{  5, CmdType::PDEP },\n\t\t{ 15, CmdType::PDXP },\n\t\t{ 30, CmdType::REFB, { 0,0,0} },\n\t\t{ 40, CmdType::ACT, { 1,0,0,}},\n\t\t{ 45, CmdType::PDEA },\n\t\t{ 75, CmdType::PDXA },\n\t\t{125, CmdType::END_OF_SIMULATION },\n\t};\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n\t\tmemSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n\t\tmemSpec->numberOfRanks = 1;\n        memSpec->numberOfBanks = 8;\n        memSpec->numberOfBankGroups = 2;\n        memSpec->banksPerGroup = 4;\n        memSpec->bank_arch = MemSpecLPDDR5::MBG;\n        memSpec->numberOfDevices = 1;\n        memSpec->bitWidth = 16;\n\n\n        memSpec->memTimingSpec.tRAS = 10;\n\t\tmemSpec->memTimingSpec.tRCD = 20;\n\t\tmemSpec->memTimingSpec.tRFC = 25;\n\t\tmemSpec->memTimingSpec.tRFCPB = 25;\n\n\t\tmemSpec->memTimingSpec.tWR = 20;\n\t\tmemSpec->memTimingSpec.tRP = 20;\n\t\tmemSpec->memTimingSpec.tWL = 0;\n\t\tmemSpec->memTimingSpec.tCK = 1e-9;\n        memSpec->memTimingSpec.tWCK = 1e-9;\n        memSpec->memTimingSpec.tREFI = 1;\n\t\tmemSpec->memTimingSpec.WCKtoCK = 2;\n\n\t\tmemSpec->memPowerSpec[0].vDDX = 1;\n\t\tmemSpec->memPowerSpec[0].iDD0X = 64e-3;\n\t\tmemSpec->memPowerSpec[0].iDD2NX = 8e-3;\n\t\tmemSpec->memPowerSpec[0].iDD2PX = 6e-3;\n\t\tmemSpec->memPowerSpec[0].iDD3NX = 32e-3;\n\t\tmemSpec->memPowerSpec[0].iDD3PX = 20e-3;\n\t\tmemSpec->memPowerSpec[0].iDD4RX = 72e-3;\n\t\tmemSpec->memPowerSpec[0].iDD4WX = 72e-3;\n\t\tmemSpec->memPowerSpec[0].iDD5PBX = 30e-3;\n        memSpec->memPowerSpec[0].iBeta = memSpec->memPowerSpec[0].iDD0X;\n\n\n        memSpec->bwParams.bwPowerFactRho = 0.333333333;\n\n\t\tmemSpec->burstLength = 16;\n\t\tmemSpec->dataRate = 2;\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_20, Test)\n{\n\tfor (const auto& command : testPattern) {\n\t\tddr->doCoreCommand(command);\n\t};\n\n\tauto stats = ddr->getStats();\n\n\t// Check bank command count: ACT\n\tASSERT_EQ(stats.bank[1].counter.act, 1);\n\n\t// Check global cycles count\n\tASSERT_EQ(stats.rank_total[0].cycles.act, 105);\n\tASSERT_EQ(stats.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 15);\n\tASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Check bank specific ACT cycle count\n\tASSERT_EQ(stats.bank[0].cycles.act, 50);\n\tASSERT_EQ(stats.bank[1].cycles.act, 95);\n\tASSERT_EQ(stats.bank[2].cycles.act, 25);\n\tASSERT_EQ(stats.bank[3].cycles.act, 25);\n\tASSERT_EQ(stats.bank[4].cycles.act, 25);\n\tASSERT_EQ(stats.bank[5].cycles.act, 25);\n\tASSERT_EQ(stats.bank[6].cycles.act, 25);\n\tASSERT_EQ(stats.bank[7].cycles.act, 25);\n\n\t// Check bank specific PRE cycle count\n\tASSERT_EQ(stats.bank[0].cycles.pre, 60);\n\tASSERT_EQ(stats.bank[1].cycles.pre, 15);\n\tASSERT_EQ(stats.bank[2].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[3].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[4].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[5].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[6].cycles.pre, 85);\n\tASSERT_EQ(stats.bank[7].cycles.pre, 85);\n}\n\nTEST_F(DramPowerTest_LPDDR5_20, CalcWindow)\n{\n\tSimulationStats window;\n\n\tauto iterate_to_timestamp = [this](auto & command, timestamp_t timestamp) {\n\t\twhile (command != this->testPattern.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\n\t\treturn this->ddr->getWindowStats(timestamp);\n\t};\n\n\tauto command = testPattern.begin();\n\n\n\t// Cycle 5\n\twindow = iterate_to_timestamp(command, 5);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 5);    ASSERT_EQ(window.rank_total[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[0].cycles.act, 5);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 5);  ASSERT_EQ(window.bank[1].cycles.pre, 0);\n\tASSERT_EQ(window.bank[2].cycles.act, 5);  ASSERT_EQ(window.bank[2].cycles.pre, 0);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 25\n\twindow = iterate_to_timestamp(command, 25);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 25);    ASSERT_EQ(window.rank_total[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[0].cycles.act, 25);  ASSERT_EQ(window.bank[0].cycles.pre, 0);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);  ASSERT_EQ(window.bank[1].cycles.pre, 0);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 0);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 30\n\twindow = iterate_to_timestamp(command, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 25);    ASSERT_EQ(window.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 25);  ASSERT_EQ(window.bank[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);  ASSERT_EQ(window.bank[1].cycles.pre, 5);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 5);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 35\n\twindow = iterate_to_timestamp(command, 35);\n\tASSERT_EQ(window.rank_total[0].cycles.act,   30);  ASSERT_EQ(window.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 30);  ASSERT_EQ(window.bank[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[1].cycles.act, 25);  ASSERT_EQ(window.bank[1].cycles.pre, 10);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 10);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 40\n\twindow = iterate_to_timestamp(command, 40);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 35);\t   ASSERT_EQ(window.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 35);  ASSERT_EQ(window.bank[0].cycles.pre, 5 );\n\tASSERT_EQ(window.bank[1].cycles.act, 25);  ASSERT_EQ(window.bank[1].cycles.pre, 15);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 15);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 50\n\twindow = iterate_to_timestamp(command, 50);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 45);\t   ASSERT_EQ(window.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 45);  ASSERT_EQ(window.bank[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[1].cycles.act, 35);  ASSERT_EQ(window.bank[1].cycles.pre, 15);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 25);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 55\n\twindow = iterate_to_timestamp(command, 55);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 50);\t   ASSERT_EQ(window.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 50);  ASSERT_EQ(window.bank[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[1].cycles.act, 40);  ASSERT_EQ(window.bank[1].cycles.pre, 15);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 30);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 60\n\twindow = iterate_to_timestamp(command, 60);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);\t   ASSERT_EQ(window.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 50);  ASSERT_EQ(window.bank[0].cycles.pre, 10);\n\tASSERT_EQ(window.bank[1].cycles.act, 45);  ASSERT_EQ(window.bank[1].cycles.pre, 15);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 35);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 0); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 75\n\twindow = iterate_to_timestamp(command, 75);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 55);\t   ASSERT_EQ(window.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 50);  ASSERT_EQ(window.bank[0].cycles.pre, 10);\n\tASSERT_EQ(window.bank[1].cycles.act, 45);  ASSERT_EQ(window.bank[1].cycles.pre, 15);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 35);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 15); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 95\n\twindow = iterate_to_timestamp(command, 95);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 75);\t   ASSERT_EQ(window.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 50);  ASSERT_EQ(window.bank[0].cycles.pre, 30);\n\tASSERT_EQ(window.bank[1].cycles.act, 65);  ASSERT_EQ(window.bank[1].cycles.pre, 15);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 55);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 15); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n\n\t// Cycle 125\n\twindow = iterate_to_timestamp(command, 125);\n\tASSERT_EQ(window.rank_total[0].cycles.act, 105);\t   ASSERT_EQ(window.rank_total[0].cycles.pre, 5);\n\tASSERT_EQ(window.bank[0].cycles.act, 50);  ASSERT_EQ(window.bank[0].cycles.pre, 60);\n\tASSERT_EQ(window.bank[1].cycles.act, 95);  ASSERT_EQ(window.bank[1].cycles.pre, 15);\n\tASSERT_EQ(window.bank[2].cycles.act, 25);  ASSERT_EQ(window.bank[2].cycles.pre, 85);\n\tASSERT_EQ(window.rank_total[0].cycles.powerDownAct, 15); ASSERT_EQ(window.rank_total[0].cycles.powerDownPre, 0);\n};\n\n\nTEST_F(DramPowerTest_LPDDR5_20, CalcEnergy)\n{\n\tauto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n\t\twhile (command != container.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\t++command;\n\t\t}\n\t};\n\n\tauto command = testPattern.begin();\n\titerate_to_timestamp(command, testPattern, 125);\n\tauto energy = ddr->calcCoreEnergy(125);\n\tauto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 6400);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1680);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_act*1e12), 800);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_act*1e12), 1520);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_act*1e12), 400);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_act*1e12), 400);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_act*1e12), 400);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_act*1e12), 400);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_act*1e12), 400);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_act*1e12), 400);\n\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 40);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_pre*1e12), 5);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_pre*1e12), 5);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_pre*1e12), 5);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_pre*1e12), 5);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_pre*1e12), 5);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_pre*1e12), 5);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_pre*1e12), 5);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_pre*1e12), 5);\n\n    ASSERT_EQ(std::round(energy.E_PDNA*1e12), 300);\n    ASSERT_EQ(std::round(energy.E_PDNP*1e12), 0);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_21.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n#include <DRAMPower/standards/test_accessor.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_21 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   5,  CmdType::SREFEN },\n            {  15,  CmdType::SREFEX },\n            {  25,  CmdType::SREFEN },\n            {  35,  CmdType::DSMEN  },\n            {  45,  CmdType::DSMEX  },\n            {  55,  CmdType::SREFEX },\n            {  80,  CmdType::SREFEN },\n            { 100,  CmdType::DSMEN  },\n            { 125,  CmdType::END_OF_SIMULATION },\n    };\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        memSpec->numberOfRanks = 1;\n        memSpec->numberOfBanks = 8;\n        memSpec->numberOfBankGroups = 2;\n        memSpec->banksPerGroup = 4;\n        memSpec->bank_arch = MemSpecLPDDR5::MBG;\n        memSpec->numberOfDevices = 1;\n        memSpec->bitWidth = 16;\n\n\n        memSpec->memTimingSpec.tRAS = 10;\n        memSpec->memTimingSpec.tRCD = 20;\n        memSpec->memTimingSpec.tRFC = 10;\n        memSpec->memTimingSpec.tRFCPB = 25;\n\n        memSpec->memTimingSpec.tWR = 20;\n        memSpec->memTimingSpec.tRP = 20;\n        memSpec->memTimingSpec.tWL = 0;\n        memSpec->memTimingSpec.tCK = 1e-9;\n        memSpec->memTimingSpec.tWCK = 1e-9;\n        memSpec->memTimingSpec.tREFI = 1;\n        memSpec->memTimingSpec.WCKtoCK = 2;\n\n        memSpec->memPowerSpec[0].vDDX = 1;\n        memSpec->memPowerSpec[0].iDD0X = 64e-3;\n        memSpec->memPowerSpec[0].iDD2NX = 8e-3;\n        memSpec->memPowerSpec[0].iDD2PX = 6e-3;\n        memSpec->memPowerSpec[0].iDD3NX = 32e-3;\n        memSpec->memPowerSpec[0].iDD3PX = 20e-3;\n        memSpec->memPowerSpec[0].iDD4RX = 72e-3;\n        memSpec->memPowerSpec[0].iDD4WX = 72e-3;\n        memSpec->memPowerSpec[0].iDD5PBX = 30e-3;\n        memSpec->memPowerSpec[0].iBeta = memSpec->memPowerSpec[0].iDD0X;\n        memSpec->memPowerSpec[0].iDD6X = 5e-3;\n\n        memSpec->bwParams.bwPowerFactRho = 0.333333333;\n\n        memSpec->burstLength = 16;\n        memSpec->dataRate = 2;\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_21, Test)\n{\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    };\n\n    const Rank & rank_1 = internal::LPDDR5TestAccessor.getRanks(ddr->getCore()).at(0);\n    auto stats = ddr->getStats();\n\n    // Check counter\n    ASSERT_EQ(rank_1.counter.selfRefresh, 3);\n\n    // Check global cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 30);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 40);\n    ASSERT_EQ(stats.rank_total[0].cycles.selfRefresh, 20);\n    ASSERT_EQ(stats.rank_total[0].cycles.deepSleepMode, 35);\n\n    // Check bank specific ACT cycle count\n    ASSERT_EQ(stats.bank[0].cycles.act, 30);\n    ASSERT_EQ(stats.bank[1].cycles.act, 30);\n    ASSERT_EQ(stats.bank[2].cycles.act, 30);\n    ASSERT_EQ(stats.bank[3].cycles.act, 30);\n    ASSERT_EQ(stats.bank[4].cycles.act, 30);\n    ASSERT_EQ(stats.bank[5].cycles.act, 30);\n    ASSERT_EQ(stats.bank[6].cycles.act, 30);\n    ASSERT_EQ(stats.bank[7].cycles.act, 30);\n}\n\nTEST_F(DramPowerTest_LPDDR5_21, CalcEnergy)\n{\n    auto iterate_to_timestamp = [this](auto & command, const auto & container, timestamp_t timestamp) {\n        while (command != container.end() && command->timestamp <= timestamp) {\n            ddr->doCoreCommand(*command);\n            ++command;\n        }\n    };\n\n    auto command = testPattern.begin();\n    iterate_to_timestamp(command, testPattern, 125);\n    auto energy = ddr->calcCoreEnergy(125);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 4320);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 480);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_act*1e12), 480);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_act*1e12), 480);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_act*1e12), 480);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_act*1e12), 480);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_act*1e12), 480);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_act*1e12), 480);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_act*1e12), 480);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_act*1e12), 480);\n\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 320);\n    ASSERT_EQ(std::round(energy.bank_energy[0].E_bg_pre*1e12), 40);\n    ASSERT_EQ(std::round(energy.bank_energy[1].E_bg_pre*1e12), 40);\n    ASSERT_EQ(std::round(energy.bank_energy[2].E_bg_pre*1e12), 40);\n    ASSERT_EQ(std::round(energy.bank_energy[3].E_bg_pre*1e12), 40);\n    ASSERT_EQ(std::round(energy.bank_energy[4].E_bg_pre*1e12), 40);\n    ASSERT_EQ(std::round(energy.bank_energy[5].E_bg_pre*1e12), 40);\n    ASSERT_EQ(std::round(energy.bank_energy[6].E_bg_pre*1e12), 40);\n    ASSERT_EQ(std::round(energy.bank_energy[7].E_bg_pre*1e12), 40);\n\n    ASSERT_EQ(std::round(energy.E_sref*1e12), 100);\n};\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_3.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_3 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::PRE,  { 0, 0, 0 }},\n            {   45, CmdType::PRE,  { 3, 0, 0 }},\n            { 50, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_3, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    }\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 45);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 5);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 35);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 25);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 0);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 15);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 25);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 50);\n    }\n}\n\nTEST_F(DramPowerTest_LPDDR5_3, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 392);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 226);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1463);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1428);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 156);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 2652);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_4.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_4 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::RD,  { 3, 0, 0 }},\n            {   40, CmdType::RD,  { 0, 0, 0 }},\n            {   50, CmdType::PREA,  { 0, 0, 0 }},\n            { 70, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_4, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].counter.reads, 2);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    };\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 50);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 20);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 50);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 30);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 0);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 20);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 40);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 70);\n    }\n}\n\nTEST_F(DramPowerTest_LPDDR5_4, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 392);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 678);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1633);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1587);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 623);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 3742);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_5.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_5 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RD,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::RD,  { 3, 0, 0 }},\n            {   40, CmdType::RD,  { 0, 0, 0 }},\n            {   50, CmdType::PREA,  { 0, 0, 0 }},\n            {   65, CmdType::REFA,  { 0, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_5, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].counter.reads, 2);\n        else if( b == 3)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    };\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check bank command count: REFA\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        ASSERT_EQ(stats.bank[b].counter.refAllBank, 1);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 75);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 25);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 75);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 55);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 25);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 25);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 45);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 75);\n    }\n}\n\nTEST_F(DramPowerTest_LPDDR5_5, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 392);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 678);\n    ASSERT_EQ(std::round(total_energy.E_ref_AB*1e12), 1699);\n    ASSERT_EQ(std::round(total_energy.E_ref_SB*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_ref_PB*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_ref_2B*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 2657);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 2380);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 779);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 6621);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_6.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_6 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::RDA,  { 0, 0, 0 }},\n            {   20, CmdType::ACT,  { 3, 0, 0 }},\n            {   35, CmdType::RD,  { 3, 0, 0 }},\n            {   50, CmdType::PREA,  { 0, 0, 0 }},\n            {   65, CmdType::REFA,  { 0, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_6, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.act, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.act, 0);\n    }\n\n    // Check bank command count: RD\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 3)\n            ASSERT_EQ(stats.bank[b].counter.reads, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.reads, 0);\n    }\n\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].counter.readAuto, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.readAuto, 0);\n    }\n\n    // Check bank command count: PRE\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0 || b == 3)\n            ASSERT_EQ(stats.bank[b].counter.pre, 1);\n        else\n            ASSERT_EQ(stats.bank[b].counter.pre, 0);\n    }\n\n    // Check bank command count: REFA\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        ASSERT_EQ(stats.bank[b].counter.refAllBank, 1);\n    }\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 75);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 25);\n\n    // Check bank specific ACT cycle count;\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if (b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.act, 45);\n        else if(b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.act, 55);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.act, 25);\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 1; b < memSpec->numberOfBanks; b++){\n        if(b == 0)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 55);\n        else if (b == 3)\n            ASSERT_EQ(stats.bank[b].cycles.pre, 45);\n        else\n            ASSERT_EQ(stats.bank[b].cycles.pre, 75);\n    }\n}\n\nTEST_F(DramPowerTest_LPDDR5_6, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 392);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 226);\n    ASSERT_EQ(std::round(total_energy.E_RDA*1e12), 226);\n    ASSERT_EQ(std::round(total_energy.E_ref_AB*1e12), 1699);\n    ASSERT_EQ(std::round(total_energy.E_ref_SB*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_ref_2B*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 2639);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 2380);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 779);\n    ASSERT_EQ(std::round(total_energy.total()*1e12), 6377);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_7.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_7 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::SREFEN,  { 0, 0, 0 }},\n            {   40, CmdType::SREFEX,  { 0, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_7, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n    // Check bank command count: ACT\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].counter.act, 0);\n\n    // Check bank command count: REFA\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].counter.refAllBank, 1);\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 25);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 60);\n    ASSERT_EQ(stats.rank_total[0].cycles.selfRefresh, 15);\n\n    // Check bank specific ACT cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.act, 25);\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.pre, 60);\n\n    // Check bank specific SREF cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.selfRefresh, 15);\n\n}\n\nTEST_F(DramPowerTest_LPDDR5_7, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_ref_AB*1e12), 1699);\n    ASSERT_EQ(std::round(energy.E_sref*1e12), 280);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1024);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 793);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 1869);\n    ASSERT_EQ(std::round((total_energy.total() + energy.E_sref)*1e12), 4873);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_8.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_8 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   0, CmdType::PDEA,  { 0, 0, 0 }},\n            {   30, CmdType::PDXA,  { 0, 0, 0 }},\n            {   45, CmdType::PDEP,  { 0, 0, 0 }},\n            {   70, CmdType::PDXP,  { 0, 0, 0 }},\n            { 85, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_8, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 30);\n    ASSERT_EQ(stats.rank_total[0].cycles.selfRefresh, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 30);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 25);\n\n    // Check bank specific ACT cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.act, 0);\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.pre, 30);\n\n    // Check bank specific PDNA cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownAct, 30);\n\n    // Check bank specific PDNP cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownPre, 25);\n\n    // Check bank specific SREF cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.selfRefresh, 0);\n}\n\nTEST_F(DramPowerTest_LPDDR5_8, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_sref*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_PDNA*1e12), 623);\n    ASSERT_EQ(std::round(energy.E_PDNP*1e12), 392);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 0);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 935);\n    ASSERT_EQ(std::round((total_energy.total() + energy.E_sref + energy.E_PDNA + energy.E_PDNP)*1e12), 1950);\n}\n"
  },
  {
    "path": "tests/tests_drampower/core/LPDDR5/lpddr5_test_pattern_9.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include \"DRAMPower/command/Command.h\"\n\n#include <DRAMPower/standards/lpddr5/LPDDR5.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n#include <variant>\n#include <stdint.h>\n\n#include <fstream>\n\n\nusing namespace DRAMPower;\n\nclass DramPowerTest_LPDDR5_9 : public ::testing::Test {\nprotected:\n    // Test pattern\n    std::vector<Command> testPattern = {\n            {   5, CmdType::ACT,  { 0, 0, 0 }},\n            {   15, CmdType::ACT,  { 5, 0, 0 }},\n            {   20, CmdType::RD,  { 0, 0, 0 }},\n            {   30, CmdType::PDEA,  { 0, 0, 0 }},\n            {   50, CmdType::PDXA,  { 0, 0, 0 }},\n            {   55, CmdType::RD,  { 5, 0, 0 }},\n            {   60, CmdType::RD,  { 0, 0, 0 }},\n            {   70, CmdType::PREA,  { 0, 0, 0 }},\n            {   80, CmdType::PDEP,  { 0, 0, 0 }},\n            {   95, CmdType::PDXP,  { 0, 0, 0 }},\n            { 100, CmdType::END_OF_SIMULATION },\n    };\n\n\n    // Test variables\n    std::unique_ptr<DRAMPower::MemSpecLPDDR5> memSpec;\n    std::unique_ptr<DRAMPower::LPDDR5> ddr;\n\n    virtual void SetUp()\n    {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        memSpec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        ddr = std::make_unique<LPDDR5>(*memSpec);\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(DramPowerTest_LPDDR5_9, Counters_and_Cycles){\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto stats = ddr->getStats();\n\n\n    // Check cycles count\n    ASSERT_EQ(stats.rank_total[0].cycles.act, 45);\n    ASSERT_EQ(stats.rank_total[0].cycles.pre, 20);\n    ASSERT_EQ(stats.rank_total[0].cycles.selfRefresh, 0);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownAct, 20);\n    ASSERT_EQ(stats.rank_total[0].cycles.powerDownPre, 15);\n\n    // Check bank specific ACT cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0){\n            ASSERT_EQ(stats .bank[b].cycles.act, 45);\n        }else if (b == 5){\n            ASSERT_EQ(stats .bank[b].cycles.act, 35);\n        }else{\n            ASSERT_EQ(stats .bank[b].cycles.act, 0);\n        }\n    }\n\n    // Check bank specific PRE cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++){\n        if(b == 0){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 20);\n        }else if (b == 5){\n            ASSERT_EQ(stats.bank[b].cycles.pre, 30);\n        }else{\n            ASSERT_EQ(stats.bank[b].cycles.pre, 65);\n        }\n    }\n\n    // Check bank specific PDNA cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownAct, 20);\n\n    // Check bank specific PDNP cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.powerDownPre, 15);\n\n    // Check bank specific SREF cycle count\n    for(uint64_t b = 0; b < memSpec->numberOfBanks; b++)  ASSERT_EQ(stats.bank[b].cycles.selfRefresh, 0);\n}\n\nTEST_F(DramPowerTest_LPDDR5_9, Energy) {\n    for (const auto& command : testPattern) {\n        ddr->doCoreCommand(command);\n    }\n\n    auto energy = ddr->calcCoreEnergy(testPattern.back().timestamp);\n    auto total_energy = energy.aggregated_bank_energy();\n\n\n    ASSERT_EQ(std::round(total_energy.E_act*1e12), 392);\n    ASSERT_EQ(std::round(total_energy.E_pre*1e12), 415);\n    ASSERT_EQ(std::round(total_energy.E_RD*1e12), 678);\n    ASSERT_EQ(std::round(energy.E_sref*1e12), 0);\n    ASSERT_EQ(std::round(energy.E_PDNA*1e12), 415);\n    ASSERT_EQ(std::round(energy.E_PDNP*1e12), 235);\n    ASSERT_EQ(std::round(total_energy.E_bg_act*1e12), 1474);\n    ASSERT_EQ(std::round(energy.E_bg_act_shared*1e12), 1428);\n    ASSERT_EQ(std::round(total_energy.E_bg_pre*1e12), 623);\n    ASSERT_EQ(std::round((total_energy.total() + energy.E_sref + energy.E_PDNA + energy.E_PDNP)*1e12), 4234);\n}\n"
  },
  {
    "path": "tests/tests_drampower/interface/test_dbi_ddr4.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMPower/standards/ddr4/interface_calculation_DDR4.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR4.h>\n\n#include \"DRAMPower/data/stats.h\"\n#include \"DRAMPower/memspec/MemSpecDDR4.h\"\n#include \"DRAMPower/standards/ddr4/DDR4.h\"\n#include \"DRAMPower/util/extensions.h\"\n\n\nusing DRAMPower::interface_energy_info_t;\nusing DRAMPower::InterfaceCalculation_DDR4;\nusing DRAMPower::CmdType;\nusing DRAMPower::Command;\nusing DRAMPower::DDR4;\nusing DRAMPower::MemSpecDDR4;\nusing DRAMPower::SimulationStats;\n\n#define SZ_BITS(x) sizeof(x)*8\n\n// burst length = 8 for x8 devices\nstatic constexpr uint8_t wr_data[] = {\n    0xF0, 0x0F, 0xE0, 0xF1,  0x00, 0xFF, 0xFF, 0xFF, // inverted to 0xF0,0x0F,0x1F,0xF1, 0xFF,0xFF,0xFF,0xFF\n    // DBI Line:\n    // H // before burst\n    // H // burst 1 time = 4, virtual_time = 8 ok\n    // H // burst 2 vt = 9 ok\n    // L // burst 3 vt = 10 ok\n    // H // burst 4 vt = 11 ok\n    // L // burst 5 vt = 12 ok\n    // H // burst 6 vt = 13 ok\n    // H // burst 7 vt = 14 ok\n    // H // burst 8 vt = 15 ok\n    // H // after burst ok\n    // 2 inversions\n    // 0xFF to 0xF0; 4 ones to zeroes, 0 zeroes to ones, 8 ones, 0 zeroes // before burst\n    // 0xF0 to 0x0F; 4 ones to zeroes, 4 zeroes to ones, 4 ones, 4 zeroes\n    // 0x0F to 0x1F; 0 ones to zeroes, 1 zeroes to ones, 4 ones, 4 zeroes\n    // 0x1F to 0xF1; 3 ones to zeroes, 3 zeroes to ones, 5 ones, 3 zeroes\n    // 0xF1 to 0xFF; 0 ones to zeroes, 3 zeroes to ones, 5 ones, 3 zeroes\n    // 0xFF to 0xFF; 0 ones to zeroes, 0 zeroes to ones, 8 ones, 0 zeroes\n    // 0xFF to 0xFF; 0 ones to zeroes, 0 zeroes to ones, 8 ones, 0 zeroes\n    // 0xFF to 0xFF; 0 ones to zeroes, 0 zeroes to ones, 8 ones, 0 zeroes\n    // 0xFF to 0xFF; 0 ones to zeroes, 0 zeroes to ones, 8 ones, 0 zeroes\n    // 0xFF to 0xFF; 0 ones to zeroes, 0 zeroes to ones, 8 ones, 0 zeroes // after burst\n    // ones to zeroes: 11, zeroes to ones: 11, zeroes 14\n};\n\n// burst length = 8 for x8 devices\nstatic constexpr uint8_t rd_data[] = {\n    0, 0, 0, 0,  0, 0, 255, 1, // inverted to 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE\n    // DBI Line:\n    // H // before burst for test_patterns[0] or test_patterns[1] burst 1\n    // L // before burst for test_patterns[1] burst 2\n    // L // burst 1 time = 11, virtual_time = 22 ok\n    // L // burst 2 vt = 23 ok\n    // L // burst 3 vt = 24 ok\n    // L // burst 4 vt = 25 ok\n    // L // burst 5 vt = 26 ok\n    // L // burst 6 vt = 27 ok\n    // H // burst 7 vt = 28 ok\n    // L // burst 8 vt = 29 ok\n    // H // after burst for test_patterns[0]\n    // L // after burst for test_patterns[1] burst 2\n    // 7 inversions\n    // 0xFF to 0xFF; 0 ones to zeroes, 0 zeroes to ones, 8 ones, 0 zeroes // before burst\n    // 0xFF to 0xFF; 0 ones to zeroes, 0 zeroes to ones, 8 ones, 0 zeroes\n    // 0xFF to 0xFF; 0 ones to zeroes, 0 zeroes to ones, 8 ones, 0 zeroes\n    // 0xFF to 0xFF; 0 ones to zeroes, 0 zeroes to ones, 8 ones, 0 zeroes\n    // 0xFF to 0xFF; 0 ones to zeroes, 0 zeroes to ones, 8 ones, 0 zeroes\n    // 0xFF to 0xFF; 0 ones to zeroes, 0 zeroes to ones, 8 ones, 0 zeroes\n    // 0xFF to 0xFF; 0 ones to zeroes, 0 zeroes to ones, 8 ones, 0 zeroes\n    // 0xFF to 0xFF; 0 ones to zeroes, 0 zeroes to ones, 8 ones, 0 zeroes\n    // 0xFF to 0xFE; 1 ones to zeroes, 0 zeroes to ones, 8 ones, 0 zeroes\n    // 0xFE to 0xFF; 0 ones to zeroes, 1 zeroes to ones, 8 ones, 1 zeroes // after burst\n    // ones to zeroes: 1, zeroes to ones: 1, zeroes 1\n};\n\nclass DDR4_DBI_Tests : public ::testing::Test {\n   public:\n    DDR4_DBI_Tests() {\n        test_patterns.push_back({\n            {0, CmdType::ACT, {1, 0, 0, 2}},\n            {4, CmdType::WR, {1, 0, 0, 0, 16}, wr_data, SZ_BITS(wr_data)},\n            {11, CmdType::RD, {1, 0, 0, 0, 16}, rd_data, SZ_BITS(rd_data)},\n            {16, CmdType::PRE, {1, 0, 0, 2}},\n            {24, CmdType::END_OF_SIMULATION},\n        });\n        test_patterns.push_back({\n            {0, CmdType::ACT, {1, 0, 0, 2}},\n            {4, CmdType::WR, {1, 0, 0, 0, 16}, wr_data, SZ_BITS(wr_data)},\n            {11, CmdType::RD, {1, 0, 0, 0, 16}, rd_data, SZ_BITS(rd_data)},\n            {15, CmdType::RD, {1, 0, 0, 0, 16}, rd_data, SZ_BITS(rd_data)}, // Seamless read\n            {20, CmdType::PRE, {1, 0, 0, 2}},\n            {24, CmdType::END_OF_SIMULATION},\n        });\n\n        initSpec();\n        ddr = std::make_unique<DDR4>(*spec);\n    }\n\n    void initSpec() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        spec = std::make_unique<DRAMPower::MemSpecDDR4>(DRAMPower::MemSpecDDR4::from_memspec(*data));\n    }\n\n    void runCommands(const std::vector<Command> &commands) {\n        for (const Command &command : commands) {\n            ddr->doCoreCommand(command);\n            ddr->doInterfaceCommand(command);\n        }\n    }\n\n    std::vector<std::vector<Command>> test_patterns;\n    std::unique_ptr<MemSpecDDR4> spec;\n    std::unique_ptr<DDR4> ddr;\n};\n\n// Test patterns for stats (counter)\nTEST_F(DDR4_DBI_Tests, Pattern_0) {\n    ddr->getExtensionManager().withExtension<DRAMPower::extensions::DBI>([](DRAMPower::extensions::DBI& dbi) {\n        dbi.enable(0, true);\n    });\n    runCommands(test_patterns[0]);\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n    // Data bus\n    EXPECT_EQ(stats.writeBus.ones, 370); // 2 (datarate) * 24 (time) * 8 (bus width) - 14 (zeroes)\n    EXPECT_EQ(stats.writeBus.zeroes, 14);\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 11);  // 0 transitions 1 -> 0\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 11);  // back to 1\n\n    EXPECT_EQ(stats.readBus.ones, 383);  // 2 (datarate) * 24 (time) * 8 (bus width) - 1 (zeroes) \n    EXPECT_EQ(stats.readBus.zeroes, 1);  // 1 (zeroes)\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 1); // 1 transition 1 -> 0\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 1); // back to 1\n\n    // DBI\n    EXPECT_EQ(stats.readDBI.ones, 48 - 7);\n    EXPECT_EQ(stats.readDBI.zeroes, 7);\n    EXPECT_EQ(stats.readDBI.ones_to_zeroes, 2);\n    EXPECT_EQ(stats.readDBI.zeroes_to_ones, 2);\n\n    EXPECT_EQ(stats.writeDBI.ones, 48 - 2);\n    EXPECT_EQ(stats.writeDBI.zeroes, 2);\n    EXPECT_EQ(stats.writeDBI.ones_to_zeroes, 2);\n    EXPECT_EQ(stats.writeDBI.zeroes_to_ones, 2);\n\n}\n\nTEST_F(DDR4_DBI_Tests, Pattern_1) {\n    ddr->getExtensionManager().withExtension<DRAMPower::extensions::DBI>([](DRAMPower::extensions::DBI& dbi) {\n        dbi.enable(0, true);\n    });\n    runCommands(test_patterns[1]);\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n    // Data bus\n    EXPECT_EQ(stats.writeBus.ones, 370); // 2 (datarate) * 24 (time) * 8 (bus width) - 14 (zeroes)\n    EXPECT_EQ(stats.writeBus.zeroes, 14);\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 11);  // 0 transitions 1 -> 0\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 11);  // back to 1\n\n    EXPECT_EQ(stats.readBus.ones, 382);  // 2 (datarate) * 24 (time) * 8 (bus width) - 2 (zeroes) \n    EXPECT_EQ(stats.readBus.zeroes, 2);  // 2 (zeroes)\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 2); // 2 transitions 1 -> 0\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 2); // back to 1\n\n    // DBI\n    EXPECT_EQ(stats.readDBI.ones, 48 - 14);\n    EXPECT_EQ(stats.readDBI.zeroes, 14);\n    EXPECT_EQ(stats.readDBI.ones_to_zeroes, 3);\n    EXPECT_EQ(stats.readDBI.zeroes_to_ones, 3);\n\n    EXPECT_EQ(stats.writeDBI.ones, 48 - 2);\n    EXPECT_EQ(stats.writeDBI.zeroes, 2);\n    EXPECT_EQ(stats.writeDBI.ones_to_zeroes, 2);\n    EXPECT_EQ(stats.writeDBI.zeroes_to_ones, 2);\n}\nclass DDR4_DBI_Energy_Tests : public ::testing::Test {\n   public:\n    DDR4_DBI_Energy_Tests() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        spec = std::make_unique<DRAMPower::MemSpecDDR4>(DRAMPower::MemSpecDDR4::from_memspec(*data));\n\n        t_CK = spec->memTimingSpec.tCK;\n        voltage = spec->vddq;\n\n        // Change impedances to different values from each other\n        spec->memImpedanceSpec.rdbi_R_eq = 1;\n        spec->memImpedanceSpec.wdbi_R_eq = 2;\n\n        spec->memImpedanceSpec.rdbi_dyn_E = 3;\n        spec->memImpedanceSpec.wdbi_dyn_E = 4;\n\n        io_calc = std::make_unique<InterfaceCalculation_DDR4>(*spec);\n    }\n\n    std::unique_ptr<MemSpecDDR4> spec;\n    double t_CK;\n    double voltage;\n    std::unique_ptr<InterfaceCalculation_DDR4> io_calc;\n};\n\nTEST_F(DDR4_DBI_Energy_Tests, Energy) {\n    SimulationStats stats;\n    stats.readDBI.ones = 1;\n    stats.readDBI.zeroes = 2;\n    stats.readDBI.ones_to_zeroes = 3;\n    stats.readDBI.zeroes_to_ones = 4;\n\n    // Controller -> write power\n    // Dram -> read power\n    // data rate dbi is 2 -> t_per_bit = 0.5 * t_CK\n    double expected_static_controller =\n        stats.writeDBI.zeroes * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.wdbi_R_eq;\n    double expected_static_dram =\n        stats.readDBI.zeroes * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.rdbi_R_eq;\n\n    // Dynamic power is consumed on 0 -> 1 transition\n    double expected_dynamic_controller = stats.writeDBI.zeroes_to_ones *\n                            spec->memImpedanceSpec.wdbi_dyn_E;\n    double expected_dynamic_dram = stats.readDBI.zeroes_to_ones *\n                            spec->memImpedanceSpec.rdbi_dyn_E;\n\n\n    // DBI\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, expected_static_dram);\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, expected_dynamic_dram);\n}\n"
  },
  {
    "path": "tests/tests_drampower/interface/test_dbi_lpddr4.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMPower/standards/lpddr4/interface_calculation_LPDDR4.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n\n#include \"DRAMPower/data/stats.h\"\n#include \"DRAMPower/memspec/MemSpecLPDDR4.h\"\n#include \"DRAMPower/standards/lpddr4/LPDDR4.h\"\n#include \"DRAMPower/util/extensions.h\"\n\n\nusing DRAMPower::interface_energy_info_t;\nusing DRAMPower::InterfaceCalculation_LPDDR4;\nusing DRAMPower::CmdType;\nusing DRAMPower::Command;\nusing DRAMPower::LPDDR4;\nusing DRAMPower::MemSpecLPDDR4;\nusing DRAMPower::SimulationStats;\n\n#define SZ_BITS(x) sizeof(x)*8\n\n// burst length = 8 for x8 devices\nstatic constexpr uint8_t wr_data[] = {\n    0xF0, 0x0F, 0xE0, 0xF1,  0x00, 0xFF, 0xFF, 0xFF, // inverted to 0xF0,0x0F,0xE0,0x0E, 0x00,0x00,0x00,0x00\n    // DBI Line:\n    // L // before burst\n    // L // burst 1 time = 4, virtual_time = 8 ok\n    // L // burst 2 vt = 9 ok\n    // L // burst 3 vt = 10 ok\n    // H // burst 4 vt = 11 ok\n    // L // burst 5 vt = 12 ok\n    // H // burst 6 vt = 13 ok\n    // H // burst 7 vt = 14 ok\n    // H // burst 8 vt = 15 ok\n    // L // after burst ok\n    // 4 inversions\n    // 0x00 to 0xF0; 0 ones to zeroes, 4 zeroes to ones, 0 ones, 8 zeroes // before burst\n    // 0xF0 to 0x0F; 4 ones to zeroes, 4 zeroes to ones, 4 ones, 4 zeroes\n    // 0x0F to 0xE0; 4 ones to zeroes, 3 zeroes to ones, 4 ones, 4 zeroes\n    // 0xE0 to 0x0E; 3 ones to zeroes, 3 zeroes to ones, 3 ones, 5 zeroes\n    // 0x0E to 0x00; 3 ones to zeroes, 0 zeroes to ones, 3 ones, 5 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes // after burst\n    // ones to zeroes: 14, zeroes to ones: 14, ones: 14\n};\n\n// burst length = 8 for x8 devices\nstatic constexpr uint8_t rd_data[] = {\n    0, 0, 0, 0,  0, 0, 255, 1, // inverted to 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x01\n    // DBI Line:\n    // L // before burst for test_patterns[0] or test_patterns[1] burst 1\n    // L // before burst for test_patterns[1] burst 2\n    // L // burst 1 time = 11, virtual_time = 22 ok\n    // L // burst 2 vt = 23 ok\n    // L // burst 3 vt = 24 ok\n    // L // burst 4 vt = 25 ok\n    // L // burst 5 vt = 26 ok\n    // L // burst 6 vt = 27 ok\n    // H // burst 7 vt = 28 ok\n    // L // burst 8 vt = 29 ok\n    // L // after burst for test_patterns[0]\n    // L // after burst for test_patterns[1] burst 2\n    // 1 inversions\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes // before burst\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x01; 1 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x01 to 0x00; 0 ones to zeroes, 1 zeroes to ones, 1 ones, 1 zeroes // after burst\n    // ones to zeroes: 1, zeroes to ones: 1, ones 1\n};\n\nclass LPDDR4_DBI_Tests : public ::testing::Test {\n   public:\n    LPDDR4_DBI_Tests() {\n        test_patterns.push_back({\n            {0, CmdType::ACT, {1, 0, 0, 2}},\n            {4, CmdType::WR, {1, 0, 0, 0, 16}, wr_data, SZ_BITS(wr_data)},\n            {11, CmdType::RD, {1, 0, 0, 0, 16}, rd_data, SZ_BITS(rd_data)},\n            {16, CmdType::PRE, {1, 0, 0, 2}},\n            {24, CmdType::END_OF_SIMULATION},\n        });\n        test_patterns.push_back({\n            {0, CmdType::ACT, {1, 0, 0, 2}},\n            {4, CmdType::WR, {1, 0, 0, 0, 16}, wr_data, SZ_BITS(wr_data)},\n            {11, CmdType::RD, {1, 0, 0, 0, 16}, rd_data, SZ_BITS(rd_data)},\n            {15, CmdType::RD, {1, 0, 0, 0, 16}, rd_data, SZ_BITS(rd_data)}, // Seamless read\n            {20, CmdType::PRE, {1, 0, 0, 2}},\n            {24, CmdType::END_OF_SIMULATION},\n        });\n\n        initSpec();\n        ddr = std::make_unique<LPDDR4>(*spec);\n    }\n\n    void initSpec() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        spec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*data));\n    }\n\n    void runCommands(const std::vector<Command> &commands) {\n        for (const Command &command : commands) {\n            ddr->doCoreCommand(command);\n            ddr->doInterfaceCommand(command);\n        }\n    }\n\n    std::vector<std::vector<Command>> test_patterns;\n    std::unique_ptr<MemSpecLPDDR4> spec;\n    std::unique_ptr<LPDDR4> ddr;\n};\n\n// Test patterns for stats (counter)\nTEST_F(LPDDR4_DBI_Tests, Pattern_0) {\n    ddr->getExtensionManager().withExtension<DRAMPower::extensions::DBI>([](DRAMPower::extensions::DBI& dbi) {\n        dbi.enable(0, true);\n    });\n    runCommands(test_patterns[0]);\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n    // Data bus\n    EXPECT_EQ(stats.writeBus.ones, 14);\n    EXPECT_EQ(stats.writeBus.zeroes, 370); // 2 (datarate) * 24 (time) * 8 (bus width) - 14 (ones)\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 14);\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 14);\n\n    EXPECT_EQ(stats.readBus.ones, 1);\n    EXPECT_EQ(stats.readBus.zeroes, 383); // 2 (datarate) * 24 (time) * 8 (bus width) - 1 (ones)\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 1);\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 1);\n\n    // DBI\n    EXPECT_EQ(stats.readDBI.ones, 1);\n    EXPECT_EQ(stats.readDBI.zeroes, 48-1);\n    EXPECT_EQ(stats.readDBI.ones_to_zeroes, 1);\n    EXPECT_EQ(stats.readDBI.zeroes_to_ones, 1);\n\n    EXPECT_EQ(stats.writeDBI.ones, 4);\n    EXPECT_EQ(stats.writeDBI.zeroes, 48-4);\n    EXPECT_EQ(stats.writeDBI.ones_to_zeroes, 2);\n    EXPECT_EQ(stats.writeDBI.zeroes_to_ones, 2);\n\n}\n\nTEST_F(LPDDR4_DBI_Tests, Pattern_1) {\n    ddr->getExtensionManager().withExtension<DRAMPower::extensions::DBI>([](DRAMPower::extensions::DBI& dbi) {\n        dbi.enable(0, true);\n    });\n    runCommands(test_patterns[1]);\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n    // Data bus\n    EXPECT_EQ(stats.writeBus.ones, 14);\n    EXPECT_EQ(stats.writeBus.zeroes, 370); // 2 (datarate) * 24 (time) * 8 (bus width) - 14 (ones)\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 14);\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 14);\n\n    EXPECT_EQ(stats.readBus.ones, 2);\n    EXPECT_EQ(stats.readBus.zeroes, 382);  // 2 (datarate) * 24 (time) * 8 (bus width) - 2 (ones) \n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 2);\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 2);\n\n    // DBI\n    EXPECT_EQ(stats.readDBI.ones, 2);\n    EXPECT_EQ(stats.readDBI.zeroes, 48-2);\n    EXPECT_EQ(stats.readDBI.ones_to_zeroes, 2);\n    EXPECT_EQ(stats.readDBI.zeroes_to_ones, 2);\n\n    EXPECT_EQ(stats.writeDBI.ones, 4);\n    EXPECT_EQ(stats.writeDBI.zeroes, 48 - 4);\n    EXPECT_EQ(stats.writeDBI.ones_to_zeroes, 2);\n    EXPECT_EQ(stats.writeDBI.zeroes_to_ones, 2);\n}\nclass LPDDR4_DBI_Energy_Tests : public ::testing::Test {\n   public:\n    LPDDR4_DBI_Energy_Tests() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        spec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*data));\n\n        t_CK = spec->memTimingSpec.tCK;\n        voltage = spec->vddq;\n\n        // Change impedances to different values from each other\n        spec->memImpedanceSpec.rdbi_R_eq = 1;\n        spec->memImpedanceSpec.wdbi_R_eq = 2;\n\n        spec->memImpedanceSpec.rdbi_dyn_E = 3;\n        spec->memImpedanceSpec.wdbi_dyn_E = 4;\n\n        io_calc = std::make_unique<InterfaceCalculation_LPDDR4>(*spec);\n    }\n\n    std::unique_ptr<MemSpecLPDDR4> spec;\n    double t_CK;\n    double voltage;\n    std::unique_ptr<InterfaceCalculation_LPDDR4> io_calc;\n};\n\nTEST_F(LPDDR4_DBI_Energy_Tests, Energy) {\n    SimulationStats stats;\n    stats.readDBI.ones = 1;\n    stats.readDBI.zeroes = 2;\n    stats.readDBI.ones_to_zeroes = 3;\n    stats.readDBI.zeroes_to_ones = 4;\n\n    // Controller -> write power\n    // Dram -> read power\n    // data rate dbi is 2 -> t_per_bit = 0.5 * t_CK\n    double expected_static_controller =\n        stats.writeDBI.ones * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.wdbi_R_eq;\n    double expected_static_dram =\n        stats.readDBI.ones * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.rdbi_R_eq;\n\n    // Dynamic power is consumed on 0 -> 1 transition\n    double expected_dynamic_controller = stats.writeDBI.zeroes_to_ones *\n                            spec->memImpedanceSpec.wdbi_dyn_E;\n    double expected_dynamic_dram = stats.readDBI.zeroes_to_ones *\n                            spec->memImpedanceSpec.rdbi_dyn_E;\n\n\n    // DBI\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, expected_static_dram);\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, expected_dynamic_dram);\n}\n"
  },
  {
    "path": "tests/tests_drampower/interface/test_dbi_lpddr5.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <memory>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMPower/standards/lpddr5/interface_calculation_LPDDR5.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n\n#include \"DRAMPower/data/stats.h\"\n#include \"DRAMPower/memspec/MemSpecLPDDR5.h\"\n#include \"DRAMPower/standards/lpddr5/LPDDR5.h\"\n#include \"DRAMPower/util/extensions.h\"\n\n\nusing DRAMPower::interface_energy_info_t;\nusing DRAMPower::InterfaceCalculation_LPDDR5;\nusing DRAMPower::CmdType;\nusing DRAMPower::Command;\nusing DRAMPower::LPDDR5;\nusing DRAMPower::MemSpecLPDDR5;\nusing DRAMPower::SimulationStats;\n\n#define SZ_BITS(x) sizeof(x)*8\n\n// burst length = 8 for x8 devices\nstatic constexpr uint8_t wr_data[] = {\n    0xF0, 0x0F, 0xE0, 0xF1,  0x00, 0xFF, 0xFF, 0xFF, // inverted to 0xF0,0x0F,0xE0,0x0E, 0x00,0x00,0x00,0x00\n    // DBI Line:\n    // L // before burst\n    // L // burst 1 time = 4, virtual_time = 8 ok\n    // L // burst 2 vt = 9 ok\n    // L // burst 3 vt = 10 ok\n    // H // burst 4 vt = 11 ok\n    // L // burst 5 vt = 12 ok\n    // H // burst 6 vt = 13 ok\n    // H // burst 7 vt = 14 ok\n    // H // burst 8 vt = 15 ok\n    // L // after burst ok\n    // 4 inversions\n    // 0x00 to 0xF0; 0 ones to zeroes, 4 zeroes to ones, 0 ones, 8 zeroes // before burst\n    // 0xF0 to 0x0F; 4 ones to zeroes, 4 zeroes to ones, 4 ones, 4 zeroes\n    // 0x0F to 0xE0; 4 ones to zeroes, 3 zeroes to ones, 4 ones, 4 zeroes\n    // 0xE0 to 0x0E; 3 ones to zeroes, 3 zeroes to ones, 3 ones, 5 zeroes\n    // 0x0E to 0x00; 3 ones to zeroes, 0 zeroes to ones, 3 ones, 5 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes // after burst\n    // ones to zeroes: 14, zeroes to ones: 14, ones: 14\n};\n\n// burst length = 8 for x8 devices\nstatic constexpr uint8_t rd_data[] = {\n    0, 0, 0, 0,  0, 0, 255, 1, // inverted to 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x01\n    // DBI Line:\n    // L // before burst for test_patterns[0] or test_patterns[1] burst 1\n    // L // before burst for test_patterns[1] burst 2\n    // L // burst 1 time = 11, virtual_time = 22 ok\n    // L // burst 2 vt = 23 ok\n    // L // burst 3 vt = 24 ok\n    // L // burst 4 vt = 25 ok\n    // L // burst 5 vt = 26 ok\n    // L // burst 6 vt = 27 ok\n    // H // burst 7 vt = 28 ok\n    // L // burst 8 vt = 29 ok\n    // L // after burst for test_patterns[0]\n    // L // after burst for test_patterns[1] burst 2\n    // 1 inversions\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes // before burst\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x00; 0 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x00 to 0x01; 1 ones to zeroes, 0 zeroes to ones, 0 ones, 8 zeroes\n    // 0x01 to 0x00; 0 ones to zeroes, 1 zeroes to ones, 1 ones, 1 zeroes // after burst\n    // ones to zeroes: 1, zeroes to ones: 1, ones 1\n};\n\nclass LPDDR5_DBI_Tests : public ::testing::Test {\n   public:\n    LPDDR5_DBI_Tests() {\n        test_patterns.push_back({\n            {0, CmdType::ACT, {1, 0, 0, 2}},\n            {4, CmdType::WR, {1, 0, 0, 0, 16}, wr_data, SZ_BITS(wr_data)},\n            {11, CmdType::RD, {1, 0, 0, 0, 16}, rd_data, SZ_BITS(rd_data)},\n            {16, CmdType::PRE, {1, 0, 0, 2}},\n            {24, CmdType::END_OF_SIMULATION},\n        });\n        test_patterns.push_back({\n            {0, CmdType::ACT, {1, 0, 0, 2}},\n            {4, CmdType::WR, {1, 0, 0, 0, 16}, wr_data, SZ_BITS(wr_data)},\n            {11, CmdType::RD, {1, 0, 0, 0, 16}, rd_data, SZ_BITS(rd_data)},\n            {15, CmdType::RD, {1, 0, 0, 0, 16}, rd_data, SZ_BITS(rd_data)}, // Seamless read\n            {20, CmdType::PRE, {1, 0, 0, 2}},\n            {24, CmdType::END_OF_SIMULATION},\n        });\n\n        initSpec();\n        ddr = std::make_unique<LPDDR5>(*spec);\n    }\n\n    void initSpec() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        spec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n    }\n\n    void runCommands(const std::vector<Command> &commands) {\n        for (const Command &command : commands) {\n            ddr->doCoreCommand(command);\n            ddr->doInterfaceCommand(command);\n        }\n    }\n\n    std::vector<std::vector<Command>> test_patterns;\n    std::unique_ptr<MemSpecLPDDR5> spec;\n    std::unique_ptr<LPDDR5> ddr;\n};\n\n// Test patterns for stats (counter)\nTEST_F(LPDDR5_DBI_Tests, Pattern_0) {\n    ddr->getExtensionManager().withExtension<DRAMPower::extensions::DBI>([](DRAMPower::extensions::DBI& dbi) {\n        dbi.enable(0, true);\n    });\n    runCommands(test_patterns[0]);\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n    // Data bus\n    EXPECT_EQ(stats.writeBus.ones, 14);\n    EXPECT_EQ(stats.writeBus.zeroes, 370); // 2 (datarate) * 24 (time) * 8 (bus width) - 14 (ones)\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 14);\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 14);\n\n    EXPECT_EQ(stats.readBus.ones, 1);\n    EXPECT_EQ(stats.readBus.zeroes, 383); // 2 (datarate) * 24 (time) * 8 (bus width) - 1 (ones)\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 1);\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 1);\n\n    // DBI\n    EXPECT_EQ(stats.readDBI.ones, 1);\n    EXPECT_EQ(stats.readDBI.zeroes, 48-1);\n    EXPECT_EQ(stats.readDBI.ones_to_zeroes, 1);\n    EXPECT_EQ(stats.readDBI.zeroes_to_ones, 1);\n\n    EXPECT_EQ(stats.writeDBI.ones, 4);\n    EXPECT_EQ(stats.writeDBI.zeroes, 48-4);\n    EXPECT_EQ(stats.writeDBI.ones_to_zeroes, 2);\n    EXPECT_EQ(stats.writeDBI.zeroes_to_ones, 2);\n\n}\n\nTEST_F(LPDDR5_DBI_Tests, Pattern_1) {\n    ddr->getExtensionManager().withExtension<DRAMPower::extensions::DBI>([](DRAMPower::extensions::DBI& dbi) {\n        dbi.enable(0, true);\n    });\n    runCommands(test_patterns[1]);\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n    // Data bus\n    EXPECT_EQ(stats.writeBus.ones, 14);\n    EXPECT_EQ(stats.writeBus.zeroes, 370); // 2 (datarate) * 24 (time) * 8 (bus width) - 14 (ones)\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 14);\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 14);\n\n    EXPECT_EQ(stats.readBus.ones, 2);\n    EXPECT_EQ(stats.readBus.zeroes, 382);  // 2 (datarate) * 24 (time) * 8 (bus width) - 2 (ones) \n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 2);\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 2);\n\n    // DBI\n    EXPECT_EQ(stats.readDBI.ones, 2);\n    EXPECT_EQ(stats.readDBI.zeroes, 48-2);\n    EXPECT_EQ(stats.readDBI.ones_to_zeroes, 2);\n    EXPECT_EQ(stats.readDBI.zeroes_to_ones, 2);\n\n    EXPECT_EQ(stats.writeDBI.ones, 4);\n    EXPECT_EQ(stats.writeDBI.zeroes, 48 - 4);\n    EXPECT_EQ(stats.writeDBI.ones_to_zeroes, 2);\n    EXPECT_EQ(stats.writeDBI.zeroes_to_ones, 2);\n}\nclass LPDDR5_DBI_Energy_Tests : public ::testing::Test {\n   public:\n    LPDDR5_DBI_Energy_Tests() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        spec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        t_CK = spec->memTimingSpec.tCK;\n        voltage = spec->vddq;\n\n        // Change impedances to different values from each other\n        spec->memImpedanceSpec.rdbi_R_eq = 1;\n        spec->memImpedanceSpec.wdbi_R_eq = 2;\n\n        spec->memImpedanceSpec.rdbi_dyn_E = 3;\n        spec->memImpedanceSpec.wdbi_dyn_E = 4;\n\n        io_calc = std::make_unique<InterfaceCalculation_LPDDR5>(*spec);\n    }\n\n    std::unique_ptr<MemSpecLPDDR5> spec;\n    double t_CK;\n    double voltage;\n    std::unique_ptr<InterfaceCalculation_LPDDR5> io_calc;\n};\n\nTEST_F(LPDDR5_DBI_Energy_Tests, Energy) {\n    SimulationStats stats;\n    stats.readDBI.ones = 1;\n    stats.readDBI.zeroes = 2;\n    stats.readDBI.ones_to_zeroes = 3;\n    stats.readDBI.zeroes_to_ones = 4;\n\n    // Controller -> write power\n    // Dram -> read power\n    // data rate dbi is 2 -> t_per_bit = 0.5 * t_CK\n    double expected_static_controller =\n        stats.writeDBI.ones * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.wdbi_R_eq;\n    double expected_static_dram =\n        stats.readDBI.ones * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.rdbi_R_eq;\n\n    // Dynamic power is consumed on 0 -> 1 transition\n    double expected_dynamic_controller = stats.writeDBI.zeroes_to_ones *\n                            spec->memImpedanceSpec.wdbi_dyn_E;\n    double expected_dynamic_dram = stats.readDBI.zeroes_to_ones *\n                            spec->memImpedanceSpec.rdbi_dyn_E;\n\n\n    // DBI\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, expected_static_dram);\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, expected_dynamic_dram);\n}\n"
  },
  {
    "path": "tests/tests_drampower/interface/test_interface_ddr4.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <memory>\n#include <fstream>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR4.h>\n#include <DRAMPower/standards/test_accessor.h>\n#include <variant>\n\n#include \"DRAMPower/data/energy.h\"\n#include \"DRAMPower/data/stats.h\"\n#include \"DRAMPower/memspec/MemSpecDDR4.h\"\n#include \"DRAMPower/standards/ddr4/DDR4.h\"\n#include \"DRAMPower/standards/ddr4/interface_calculation_DDR4.h\"\n\nusing DRAMPower::CmdType;\nusing DRAMPower::Command;\nusing DRAMPower::DDR4;\nusing DRAMPower::interface_energy_info_t;\nusing DRAMPower::InterfaceCalculation_DDR4;\nusing DRAMPower::MemSpecDDR4;\nusing DRAMPower::SimulationStats;\n\n#define SZ_BITS(x) sizeof(x)*8\n\n// burst length = 8 for x8 devices\nstatic constexpr uint8_t wr_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 255,\n};\n\n// burst length = 8 for x8 devices\nstatic constexpr uint8_t rd_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 1,\n};\n\nclass DDR4_WindowStats_Tests : public ::testing::Test {\n   public:\n    DDR4_WindowStats_Tests() {\n        test_patterns.push_back({\n            {0, CmdType::ACT, {1, 0, 0, 2}},\n            {4, CmdType::WR, {1, 0, 0, 0, 16}, wr_data, SZ_BITS(wr_data)},\n            {11, CmdType::RD, {1, 0, 0, 0, 16}, rd_data, SZ_BITS(rd_data)},\n            {16, CmdType::PRE, {1, 0, 0, 2}},\n            {24, CmdType::END_OF_SIMULATION},\n        });\n\n        test_patterns.push_back({\n            {0, CmdType::ACT, {1, 0, 0, 2}},\n            {4, CmdType::WR, {1, 0, 0, 0, 16}, wr_data, SZ_BITS(wr_data)},\n            {8, CmdType::WR, {1, 0, 0, 0, 16}, wr_data, SZ_BITS(wr_data)},\n            {16, CmdType::PRE, {1, 0, 0, 2}},\n            {24, CmdType::END_OF_SIMULATION},\n        });\n\n        test_patterns.push_back({\n            {0, CmdType::ACT, {1, 0, 0, 2}},\n            {4, CmdType::RD, {1, 0, 0, 0, 16}, rd_data, SZ_BITS(rd_data)},\n            {8, CmdType::RD, {1, 0, 0, 0, 16}, rd_data, SZ_BITS(rd_data)},\n            {16, CmdType::PRE, {1, 0, 0, 2}},\n            {24, CmdType::END_OF_SIMULATION},\n        });\n\n        test_patterns.push_back({\n            {0, CmdType::ACT, {1, 0, 0, 2}},\n            {4, CmdType::WR, {1, 0, 0, 0, 16}, wr_data, SZ_BITS(wr_data)},\n            {10, CmdType::WR, {1, 0, 0, 0, 16}, wr_data, SZ_BITS(wr_data)},\n            {15, CmdType::PRE, {1, 0, 0, 2}},\n            {24, CmdType::END_OF_SIMULATION},\n        });\n\n        test_patterns.push_back({\n            {0, CmdType::ACT, {1, 0, 0, 2}},\n            {4, CmdType::RD, {1, 0, 0, 0, 16}, rd_data, SZ_BITS(rd_data)},\n            {11, CmdType::RD, {1, 0, 0, 0, 16}, rd_data, SZ_BITS(rd_data)},\n            {16, CmdType::PRE, {1, 0, 0, 2}},\n            {24, CmdType::END_OF_SIMULATION},\n        });\n\n        initSpec();\n        ddr = std::make_unique<DDR4>(*spec);\n    }\n\n    void initSpec() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        spec = std::make_unique<DRAMPower::MemSpecDDR4>(DRAMPower::MemSpecDDR4::from_memspec(*data));\n    }\n\n    void runCommands(const std::vector<Command> &commands) {\n        for (const Command &command : commands) {\n            ddr->doCoreCommand(command);\n            ddr->doInterfaceCommand(command);\n        }\n    }\n\n    std::vector<std::vector<Command>> test_patterns;\n    std::unique_ptr<MemSpecDDR4> spec;\n    std::unique_ptr<DDR4> ddr;\n};\n\n// Test patterns for stats (counter)\nTEST_F(DDR4_WindowStats_Tests, Pattern_0) {\n    runCommands(test_patterns[0]);\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n    // Clock\n    EXPECT_EQ(stats.clockStats.ones, 48);\n    EXPECT_EQ(stats.clockStats.zeroes, 48);\n    EXPECT_EQ(stats.clockStats.ones_to_zeroes, 48);\n    EXPECT_EQ(stats.clockStats.zeroes_to_ones, 48);\n\n    // Data bus\n    EXPECT_EQ(stats.writeBus.ones, 328); // 2 (datarate) * 24 (time) * 8 (bus width) - 56 (zeroes) \n    EXPECT_EQ(stats.writeBus.zeroes, 56);  // 7 (length) * 8 (bus width)\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 8);  // 8 transitions 1 -> 0\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 8);  // back to 1\n\n    EXPECT_EQ(stats.readBus.ones, 321);  // 2 (datarate) * 24 (time) * 8 (bus width) - 63 (zeroes) \n    EXPECT_EQ(stats.readBus.zeroes, 63);  // 7 (length zero bursts) * 8 (bus width) + 7 (zeroes in last burst)\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 8);\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 8);\n\n    EXPECT_EQ(stats.commandBus.ones, 591);\n    EXPECT_EQ(stats.commandBus.zeroes, 57);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 57);\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 57);\n\n    // DQs bus\n    EXPECT_EQ(SZ_BITS(wr_data), SZ_BITS(rd_data));\n    uint_fast8_t NumDQsPairs = spec->bitWidth == 16 ? 2 : 1;\n    uint64_t number_of_cycles = (SZ_BITS(wr_data) / spec->bitWidth);\n    uint_fast8_t scale = NumDQsPairs * 2; // Differential_Pairs * 2(pairs of 2)\n    // f(t) = t / 2;\n    uint64_t DQS_ones = scale * (number_of_cycles / 2); // scale * (cycles / 2)\n    uint64_t DQS_zeros = DQS_ones;\n    uint64_t DQS_zeros_to_ones = DQS_ones;\n    uint64_t DQS_ones_to_zeros = DQS_zeros;\n    EXPECT_EQ(stats.writeDQSStats.ones, DQS_ones);\n    EXPECT_EQ(stats.writeDQSStats.zeroes, DQS_zeros);\n    EXPECT_EQ(stats.writeDQSStats.ones_to_zeroes, DQS_zeros_to_ones);\n    EXPECT_EQ(stats.writeDQSStats.zeroes_to_ones, DQS_ones_to_zeros);\n\n    // Read strobe should be the same (only because wr_data is same as rd_data in this test)\n    EXPECT_EQ(stats.readDQSStats.ones, DQS_ones);\n    EXPECT_EQ(stats.readDQSStats.zeroes, DQS_zeros);\n    EXPECT_EQ(stats.readDQSStats.ones_to_zeroes, DQS_zeros_to_ones);\n    EXPECT_EQ(stats.readDQSStats.zeroes_to_ones, DQS_ones_to_zeros);\n\n    // PrePostamble\n    // No seamless preambles or postambles\n    auto prepos = stats.rank_total[0].prepos;\n    EXPECT_EQ(prepos.readSeamless, 0);\n    EXPECT_EQ(prepos.writeSeamless, 0);\n    EXPECT_EQ(prepos.readMerged, 0);\n    EXPECT_EQ(prepos.readMergedTime, 0);\n    EXPECT_EQ(prepos.writeMerged, 0);\n    EXPECT_EQ(prepos.writeMergedTime, 0);\n}\n\nTEST_F(DDR4_WindowStats_Tests, Pattern_1) {\n    runCommands(test_patterns[1]);\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n    // Clock\n    EXPECT_EQ(stats.clockStats.ones, 48);\n    EXPECT_EQ(stats.clockStats.zeroes, 48);\n    EXPECT_EQ(stats.clockStats.ones_to_zeroes, 48);\n    EXPECT_EQ(stats.clockStats.zeroes_to_ones, 48);\n\n    // Data bus\n    EXPECT_EQ(stats.writeBus.ones, 272);  // 2 (datarate) * 24 (time) * 8 (bus width) - 112 (zeroes)\n    EXPECT_EQ(stats.writeBus.zeroes, 112);  // 7 (zeroe bursts) * 8 (width) * 2 (2 writes)\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 16);  // 0 -> 255 * 2 = 16 transitions,\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 16);  // back to 0\n\n    EXPECT_EQ(stats.readBus.ones, 384); // 2 (datarate) * 24 (time) * 8 (bus width)\n    EXPECT_EQ(stats.readBus.zeroes, 0);\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 0);\n\n    EXPECT_EQ(stats.commandBus.ones, 593);\n    EXPECT_EQ(stats.commandBus.zeroes, 55);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 55);\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 55);\n\n    // DQs bus\n    EXPECT_EQ(SZ_BITS(wr_data), SZ_BITS(rd_data));\n    uint_fast8_t NumDQsPairs = spec->bitWidth == 16 ? 2 : 1;\n    uint64_t number_of_cycles = (SZ_BITS(wr_data) / spec->bitWidth);\n    uint_fast8_t scale = NumDQsPairs * 2; // Differential_Pairs * 2(pairs of 2)\n    // f(t) = t / 2;\n    uint64_t DQS_ones = scale * (number_of_cycles / 2); // scale * (cycles / 2)\n    uint64_t DQS_zeros = DQS_ones;\n    uint64_t DQS_zeros_to_ones = DQS_ones;\n    uint64_t DQS_ones_to_zeros = DQS_zeros;\n    EXPECT_EQ(stats.writeDQSStats.ones, DQS_ones * 2); // 2 writes\n    EXPECT_EQ(stats.writeDQSStats.zeroes, DQS_zeros* 2);\n    EXPECT_EQ(stats.writeDQSStats.ones_to_zeroes, DQS_zeros_to_ones * 2);\n    EXPECT_EQ(stats.writeDQSStats.zeroes_to_ones, DQS_ones_to_zeros * 2);\n\n    // Read strobe should be zero (no reads in this test)\n    EXPECT_EQ(stats.readDQSStats.ones, 0);\n    EXPECT_EQ(stats.readDQSStats.zeroes, 0);\n    EXPECT_EQ(stats.readDQSStats.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.readDQSStats.zeroes_to_ones, 0);\n\n    // PrePostamble\n    auto prepos = stats.rank_total[0].prepos;\n    EXPECT_EQ(prepos.readSeamless, 0);\n    EXPECT_EQ(prepos.writeSeamless, 1);\n    EXPECT_EQ(prepos.readMerged, 0);\n    EXPECT_EQ(prepos.readMergedTime, 0);\n    EXPECT_EQ(prepos.writeMerged, 0);\n    EXPECT_EQ(prepos.writeMergedTime, 0);\n}\n\nTEST_F(DDR4_WindowStats_Tests, Pattern_2) {\n    runCommands(test_patterns[2]);\n\n    SimulationStats stats = ddr->getStats();\n\n    // Clock\n    EXPECT_EQ(stats.clockStats.ones, 48);\n    EXPECT_EQ(stats.clockStats.zeroes, 48);\n    EXPECT_EQ(stats.clockStats.ones_to_zeroes, 48);\n    EXPECT_EQ(stats.clockStats.zeroes_to_ones, 48);\n\n    // Data bus\n    EXPECT_EQ(stats.writeBus.ones, 384); // 2 (datarate) * 24 (time) * 8 (bus width)\n    EXPECT_EQ(stats.writeBus.zeroes, 0);\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 0);\n\n    EXPECT_EQ(stats.readBus.ones, 258); // 2 (datarate) * 24 (time) * 8 (bus width) - 126 (zeroes)\n    EXPECT_EQ(stats.readBus.zeroes, 126); // 2 (reads) * [ 7 (length zero bursts) * 8 (bus width) + 7 (zeroes in last burst)]\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 9); // 8 (1->0 begin burst) + 1 (1->0 burst to burst data)\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 9); // 8 (0->1 end burst (last burst data included)) + 1 (0->1 burst to burst data)\n\n    EXPECT_EQ(stats.commandBus.ones, 589);\n    EXPECT_EQ(stats.commandBus.zeroes, 59);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 59);\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 59);\n\n    // DQs bus\n    EXPECT_EQ(SZ_BITS(wr_data), SZ_BITS(rd_data));\n    uint_fast8_t NumDQsPairs = spec->bitWidth == 16 ? 2 : 1;\n    uint64_t number_of_cycles = (SZ_BITS(wr_data) / spec->bitWidth);\n    uint_fast8_t scale = NumDQsPairs * 2; // Differential_Pairs * 2(pairs of 2)\n    // f(t) = t / 2;\n    uint64_t DQS_ones = scale * (number_of_cycles / 2); // scale * (cycles / 2)\n    uint64_t DQS_zeros = DQS_ones;\n    uint64_t DQS_zeros_to_ones = DQS_ones;\n    uint64_t DQS_ones_to_zeros = DQS_zeros;\n    EXPECT_EQ(stats.readDQSStats.ones, DQS_ones * 2); // 2 reads\n    EXPECT_EQ(stats.readDQSStats.zeroes, DQS_zeros * 2);\n    EXPECT_EQ(stats.readDQSStats.ones_to_zeroes, DQS_zeros_to_ones * 2);\n    EXPECT_EQ(stats.readDQSStats.zeroes_to_ones, DQS_ones_to_zeros * 2);\n\n    // Write strobe should be zero (no writes in this test)\n    EXPECT_EQ(stats.writeDQSStats.ones, 0);\n    EXPECT_EQ(stats.writeDQSStats.zeroes, 0);\n    EXPECT_EQ(stats.writeDQSStats.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.writeDQSStats.zeroes_to_ones, 0);\n\n    // PrePostamble\n    auto prepos = stats.rank_total[0].prepos;\n    EXPECT_EQ(prepos.readSeamless, 1);\n    EXPECT_EQ(prepos.writeSeamless, 0);\n    EXPECT_EQ(prepos.readMerged, 0);\n    EXPECT_EQ(prepos.readMergedTime, 0);\n    EXPECT_EQ(prepos.writeMerged, 0);\n    EXPECT_EQ(prepos.writeMergedTime, 0);\n}\n\nTEST_F(DDR4_WindowStats_Tests, Pattern_3) {\n    runCommands(test_patterns[3]);\n\n    SimulationStats stats = ddr->getStats();\n\n    // Clock\n    EXPECT_EQ(stats.clockStats.ones, 48);\n    EXPECT_EQ(stats.clockStats.zeroes, 48);\n    EXPECT_EQ(stats.clockStats.ones_to_zeroes, 48);\n    EXPECT_EQ(stats.clockStats.zeroes_to_ones, 48);\n\n    // Data bus\n    EXPECT_EQ(stats.writeBus.ones, 272); // 2 (datarate) * 24 (time) * 8 (bus width) - 112 (zeroes)\n    EXPECT_EQ(stats.writeBus.zeroes, 112);  // 7 (length) * 8 (bus width)\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 16); // 8 (begin first burst) + 8 (end first burst, begin second burst)\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 16); // 8 (end first burst) + 8 (end second burst)\n\n    EXPECT_EQ(stats.readBus.ones, 384); // 2 (datarate) * 24 (time) * 8 (bus width)\n    EXPECT_EQ(stats.readBus.zeroes, 0);\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 0);\n\n    EXPECT_EQ(stats.commandBus.ones, 593);\n    EXPECT_EQ(stats.commandBus.zeroes, 55);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 55);\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 55);\n\n    // DQs bus\n    EXPECT_EQ(SZ_BITS(wr_data), SZ_BITS(rd_data));\n    uint_fast8_t NumDQsPairs = spec->bitWidth == 16 ? 2 : 1;\n    uint64_t number_of_cycles = (SZ_BITS(wr_data) / spec->bitWidth);\n    uint_fast8_t scale = NumDQsPairs * 2; // Differential_Pairs * 2(pairs of 2)\n    // f(t) = t / 2;\n    uint64_t DQS_ones = scale * (number_of_cycles / 2); // scale * (cycles / 2)\n    uint64_t DQS_zeros = DQS_ones;\n    uint64_t DQS_zeros_to_ones = DQS_ones;\n    uint64_t DQS_ones_to_zeros = DQS_zeros;\n    EXPECT_EQ(stats.writeDQSStats.ones, DQS_ones * 2); // 2 writes\n    EXPECT_EQ(stats.writeDQSStats.zeroes, DQS_zeros * 2);\n    EXPECT_EQ(stats.writeDQSStats.ones_to_zeroes, DQS_zeros_to_ones * 2);\n    EXPECT_EQ(stats.writeDQSStats.zeroes_to_ones, DQS_ones_to_zeros * 2);\n\n    // Read strobe should be zero (no reads in this test)\n    EXPECT_EQ(stats.readDQSStats.ones, 0);\n    EXPECT_EQ(stats.readDQSStats.zeroes, 0);\n    EXPECT_EQ(stats.readDQSStats.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.readDQSStats.zeroes_to_ones, 0);\n\n    // PrePostamble\n    auto prepos = stats.rank_total[0].prepos;\n    EXPECT_EQ(prepos.readSeamless, 0);\n    EXPECT_EQ(prepos.writeSeamless, 0);\n    EXPECT_EQ(prepos.readMerged, 0);\n    EXPECT_EQ(prepos.readMergedTime, 0);\n    EXPECT_EQ(prepos.writeMerged, 0);\n    EXPECT_EQ(prepos.writeMergedTime, 0);\n}\n\nTEST_F(DDR4_WindowStats_Tests, Pattern_4) {\n    runCommands(test_patterns[4]);\n\n    SimulationStats stats = ddr->getStats();\n\n    // Clock\n    EXPECT_EQ(stats.clockStats.ones, 48);\n    EXPECT_EQ(stats.clockStats.zeroes, 48);\n    EXPECT_EQ(stats.clockStats.ones_to_zeroes, 48);\n    EXPECT_EQ(stats.clockStats.zeroes_to_ones, 48);\n\n    // Data bus\n    EXPECT_EQ(stats.writeBus.ones, 384); // 2 (datarate) * 24 (time) * 8 (bus width)\n    EXPECT_EQ(stats.writeBus.zeroes, 0);\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 0);\n\n    EXPECT_EQ(stats.readBus.ones, 258); // 2 (datarate) * 24 (time) * 8 (bus width) - 126 (zeroes)\n    EXPECT_EQ(stats.readBus.zeroes, 126); // 2 (reads) * [ 7 (length zero bursts) * 8 (bus width) + 7 (zeroes in last burst)]\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 16); // 8 (first burst begin) + 8 (second burst begin)\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 16); // 8 (end first burst) + 8 (end second burst)\n\n    EXPECT_EQ(stats.commandBus.ones, 589);\n    EXPECT_EQ(stats.commandBus.zeroes, 59);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 59);\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 59);\n\n    // DQs bus\n    EXPECT_EQ(SZ_BITS(wr_data), SZ_BITS(rd_data));\n    uint_fast8_t NumDQsPairs = spec->bitWidth == 16 ? 2 : 1;\n    uint64_t number_of_cycles = (SZ_BITS(wr_data) / spec->bitWidth);\n    uint_fast8_t scale = NumDQsPairs * 2; // Differential_Pairs * 2(pairs of 2)\n    // f(t) = t / 2;\n    uint64_t DQS_ones = scale * (number_of_cycles / 2); // scale * (cycles / 2)\n    uint64_t DQS_zeros = DQS_ones;\n    uint64_t DQS_zeros_to_ones = DQS_ones;\n    uint64_t DQS_ones_to_zeros = DQS_zeros;\n    EXPECT_EQ(stats.readDQSStats.ones, DQS_ones * 2); // 2 reads\n    EXPECT_EQ(stats.readDQSStats.zeroes, DQS_zeros * 2);\n    EXPECT_EQ(stats.readDQSStats.ones_to_zeroes, DQS_zeros_to_ones * 2);\n    EXPECT_EQ(stats.readDQSStats.zeroes_to_ones, DQS_ones_to_zeros * 2);\n\n    // Write strobe should be zero (no writes in this test)\n    EXPECT_EQ(stats.writeDQSStats.ones, 0);\n    EXPECT_EQ(stats.writeDQSStats.zeroes, 0);\n    EXPECT_EQ(stats.writeDQSStats.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.writeDQSStats.zeroes_to_ones, 0);\n\n    // PrePostamble\n    auto prepos = stats.rank_total[0].prepos;\n    EXPECT_EQ(prepos.readSeamless, 0);\n    EXPECT_EQ(prepos.writeSeamless, 0);\n    EXPECT_EQ(prepos.readMerged, 0);\n    EXPECT_EQ(prepos.readMergedTime, 0);\n    EXPECT_EQ(prepos.writeMerged, 0);\n    EXPECT_EQ(prepos.writeMergedTime, 0);\n}\n\n// Tests for power consumption (given a known SimulationStats)\nclass DDR4_Energy_Tests : public ::testing::Test {\n   public:\n    DDR4_Energy_Tests() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        spec = std::make_unique<DRAMPower::MemSpecDDR4>(DRAMPower::MemSpecDDR4::from_memspec(*data));\n\n        t_CK = spec->memTimingSpec.tCK;\n        voltage = spec->vddq;\n\n        // Change impedances to different values from each other\n        spec->memImpedanceSpec.ca_R_eq = 2;\n        spec->memImpedanceSpec.ck_R_eq = 3;\n        spec->memImpedanceSpec.rdqs_R_eq = 4;\n        spec->memImpedanceSpec.wdqs_R_eq = 5;\n        spec->memImpedanceSpec.rdq_R_eq = 6;\n        spec->memImpedanceSpec.wdq_R_eq = 7;\n\n        spec->memImpedanceSpec.ca_dyn_E = 8;\n        spec->memImpedanceSpec.ck_dyn_E = 9;\n        spec->memImpedanceSpec.rdqs_dyn_E = 10;\n        spec->memImpedanceSpec.wdqs_dyn_E = 11;\n        spec->memImpedanceSpec.rdq_dyn_E = 12;\n        spec->memImpedanceSpec.wdq_dyn_E = 13;\n\n        // PrePostamble is a possible DDR4 pattern\n        // Preamble 2tCK, Postamble 0.5tCK\n        spec->prePostamble.read_ones = 2.5;\n        spec->prePostamble.read_zeroes = 2.5;\n        spec->prePostamble.read_zeroes_to_ones = 2;\n        spec->prePostamble.read_ones_to_zeroes = 2;\n\n        // Preamble 1tCK, Postamble 0.5tCK\n        spec->prePostamble.write_ones = 1.5;\n        spec->prePostamble.write_zeroes = 1.5;\n        spec->prePostamble.write_zeroes_to_ones = 2;\n        spec->prePostamble.write_ones_to_zeroes = 2;\n\n        spec->prePostamble.readMinTccd = 3;\n        spec->prePostamble.writeMinTccd = 2;\n\n        io_calc = std::make_unique<InterfaceCalculation_DDR4>(*spec);\n    }\n\n    std::unique_ptr<MemSpecDDR4> spec;\n    double t_CK;\n    double voltage;\n    std::unique_ptr<InterfaceCalculation_DDR4> io_calc;\n};\n\nTEST_F(DDR4_Energy_Tests, Parameters) {\n    ASSERT_TRUE(t_CK > 0.0);\n    ASSERT_TRUE(voltage > 0.0);\n}\n\n// Test pattern for energy consumption\nTEST_F(DDR4_Energy_Tests, Clock_Energy) {\n    SimulationStats stats;\n    stats.clockStats.ones = 200;\n    stats.clockStats.zeroes_to_ones = 200;\n\n    stats.clockStats.zeroes = 400;  // different number to validate termination\n    stats.clockStats.ones_to_zeroes = 400;\n\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n    // Clock is provided by the controller not the device\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, 0.0);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, 0.0);\n\n    // Note\n    // The clock stats include both lines of the differential pair\n\n    // DDR4 clock power consumed on 0's\n    double expected_static = stats.clockStats.zeroes * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.ck_R_eq;\n    // Dynamic power is consumed on 0 -> 1 transition\n    double expected_dynamic = stats.clockStats.zeroes_to_ones * spec->memImpedanceSpec.ck_dyn_E;\n\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static);  // value itself doesn't matter, only that it matches the formula\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic);\n}\n\nTEST_F(DDR4_Energy_Tests, DQS_Energy) {\n    SimulationStats stats;\n    stats.readDQSStats.ones = 200;\n    stats.readDQSStats.zeroes = 400;\n    stats.readDQSStats.zeroes_to_ones = 700;\n    stats.readDQSStats.ones_to_zeroes = 1000;\n\n    stats.writeDQSStats.ones = 300;\n    stats.writeDQSStats.zeroes = 100;\n    stats.writeDQSStats.ones_to_zeroes = 2000;\n    stats.writeDQSStats.zeroes_to_ones = 999;\n\n    // Note\n    // The DQS stats include both lines of the differential pair\n\n    // Controller -> write power\n    // Dram -> read power\n    // Note dqs is modeled as clock. The clock class incorporates the data rate\n    double expected_static_controller = stats.writeDQSStats.zeroes *\n                        voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.wdqs_R_eq;\n    double expected_static_dram = stats.readDQSStats.zeroes *\n                        voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.rdqs_R_eq;\n\n    // Dynamic power is consumed on 0 -> 1 transition\n    double expected_dynamic_controller = stats.writeDQSStats.zeroes_to_ones *\n                                         spec->memImpedanceSpec.wdqs_dyn_E;\n    double expected_dynamic_dram = stats.readDQSStats.zeroes_to_ones *\n                                   spec->memImpedanceSpec.rdqs_dyn_E;\n\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, expected_static_dram);\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, expected_dynamic_dram);\n}\n\nTEST_F(DDR4_Energy_Tests, DQ_Energy) {\n    SimulationStats stats;\n    stats.readBus.ones = 7;\n    stats.readBus.zeroes = 11;\n    stats.readBus.zeroes_to_ones = 19;\n    stats.readBus.ones_to_zeroes = 39;\n\n    stats.writeBus.ones = 43;\n    stats.writeBus.zeroes = 59;\n    stats.writeBus.zeroes_to_ones = 13;\n    stats.writeBus.ones_to_zeroes = 17;\n\n    // Controller -> write power\n    // Dram -> read power\n    // zeroes and ones of the data bus are the zeroes and ones per pattern (data rate is not modeled in the bus)\n    // data rate data bus is 2 -> t_per_bit = 0.5 * t_CK\n    double expected_static_controller =\n        stats.writeBus.zeroes * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.wdq_R_eq;\n    double expected_static_dram =\n        stats.readBus.zeroes * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.rdq_R_eq;\n\n    // Dynamic power is consumed on 0 -> 1 transition\n    double expected_dynamic_controller = stats.writeBus.zeroes_to_ones *\n                            spec->memImpedanceSpec.wdq_dyn_E;\n    double expected_dynamic_dram = stats.readBus.zeroes_to_ones *\n                            spec->memImpedanceSpec.rdq_dyn_E;\n\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, expected_static_dram);\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, expected_dynamic_dram);\n}\n\nTEST_F(DDR4_Energy_Tests, CA_Energy) {\n    SimulationStats stats;\n    stats.commandBus.ones = 11;\n    stats.commandBus.zeroes = 29;\n    stats.commandBus.zeroes_to_ones = 39;\n    stats.commandBus.ones_to_zeroes = 49;\n\n    double expected_static_controller = stats.commandBus.zeroes * \n                            voltage * voltage * t_CK / spec->memImpedanceSpec.ca_R_eq;\n    double expected_dynamic_controller = stats.commandBus.zeroes_to_ones *\n                            spec->memImpedanceSpec.ca_dyn_E;\n\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n\n    // CA bus power is provided by the controller\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, 0.0);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, 0.0);\n\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n}\n\nTEST_F(DDR4_Energy_Tests, PrePostamble_Energy) {\n    SimulationStats stats;\n    stats.readDQSStats.ones = 200;\n    stats.readDQSStats.zeroes = 400;\n    stats.readDQSStats.zeroes_to_ones = 700;\n    stats.readDQSStats.ones_to_zeroes = 1000;\n\n    stats.writeDQSStats.ones = 300;\n    stats.writeDQSStats.zeroes = 100;\n    stats.writeDQSStats.ones_to_zeroes = 2000;\n    stats.writeDQSStats.zeroes_to_ones = 999;\n\n    // DDR4 doesn't support merged preambles or postambles\n    stats.rank_total.resize(1);\n    stats.rank_total[0].prepos.readMerged = 0;\n    stats.rank_total[0].prepos.readMergedTime = 0;\n    stats.rank_total[0].prepos.writeMerged = 0;\n    stats.rank_total[0].prepos.writeMergedTime = 0;\n\n    // Required reads + readAuto > readSeamless\n    // Required writes + writeAuto > writeSeamless\n    stats.rank_total[0].prepos.readSeamless = 4;\n    stats.rank_total[0].counter.reads = 4;\n    stats.rank_total[0].counter.readAuto = 10;\n    stats.rank_total[0].prepos.writeSeamless = 5;\n    stats.rank_total[0].counter.writes = 6;\n    stats.rank_total[0].counter.writeAuto = 11;\n\n    uint64_t writecount = stats.rank_total[0].counter.writes + stats.rank_total[0].counter.writeAuto;\n    uint64_t readcount = stats.rank_total[0].counter.reads + stats.rank_total[0].counter.readAuto;\n\n    // Dynamic power is consumed on 0 -> 1 transition\n    double expected_dynamic_controller = stats.writeDQSStats.zeroes_to_ones *\n                                         spec->memImpedanceSpec.wdqs_dyn_E;\n    double expected_dynamic_dram = stats.readDQSStats.zeroes_to_ones *\n                                   spec->memImpedanceSpec.rdqs_dyn_E;\n       \n    // Controller -> write power\n    // Dram -> read power\n    // Note dqs is modeled as clock. The clock class incorporates the data rate\n    double expected_static_controller = stats.writeDQSStats.zeroes *\n                        voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.wdqs_R_eq;\n    double expected_static_dram = stats.readDQSStats.zeroes *\n                        voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.rdqs_R_eq;\n\n    // Note DQS already tested in DDR4_Energy_Tests.DQS_Energy\n\n    // Add seamless preambles and postambles power\n    // Note read_zeroes incorporates the data rate\n    // Note write_zeroes incorporates the data rate\n    expected_static_controller += spec->prePostamble.write_zeroes * (writecount - stats.rank_total[0].prepos.writeSeamless) *\n                            voltage * voltage * t_CK / spec->memImpedanceSpec.wdqs_R_eq;\n    expected_static_dram += spec->prePostamble.read_zeroes * (readcount - stats.rank_total[0].prepos.readSeamless) *\n                          voltage * voltage * t_CK / spec->memImpedanceSpec.rdqs_R_eq;\n\n    expected_dynamic_controller += spec->prePostamble.write_zeroes_to_ones * (writecount - stats.rank_total[0].prepos.writeSeamless) *\n                            spec->memImpedanceSpec.wdqs_dyn_E;\n    expected_dynamic_dram += spec->prePostamble.read_zeroes_to_ones * (readcount - stats.rank_total[0].prepos.readSeamless) *\n                            spec->memImpedanceSpec.rdqs_dyn_E;\n\n\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, expected_static_dram);\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, expected_dynamic_dram);\n}"
  },
  {
    "path": "tests/tests_drampower/interface/test_interface_ddr5.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <memory>\n#include <fstream>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecDDR5.h>\n#include <DRAMPower/standards/test_accessor.h>\n#include <variant>\n\n#include \"DRAMPower/data/energy.h\"\n#include \"DRAMPower/data/stats.h\"\n#include \"DRAMPower/memspec/MemSpecDDR5.h\"\n#include \"DRAMPower/standards/ddr5/DDR5.h\"\n#include \"DRAMPower/standards/ddr5/interface_calculation_DDR5.h\"\n\nusing DRAMPower::CmdType;\nusing DRAMPower::Command;\nusing DRAMPower::DDR5;\nusing DRAMPower::interface_energy_info_t;\nusing DRAMPower::InterfaceCalculation_DDR5;\nusing DRAMPower::MemSpecDDR5;\nusing DRAMPower::SimulationStats;\n\n#define SZ_BITS(x) sizeof(x)*8\n\nstatic constexpr uint8_t wr_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 255,  0, 0, 0, 0,  0, 0, 0, 0,\n    0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 255,\n};\n\nstatic constexpr uint8_t rd_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 1,  0, 0, 0, 0,  0, 0, 0, 0,\n    0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,\n};\n\nclass DDR5_WindowStats_Tests : public ::testing::Test {\n   public:\n    DDR5_WindowStats_Tests() {\n        test_patterns.push_back({\n            {0, CmdType::ACT, {1, 0, 0, 2}},\n            {3, CmdType::WR, {1, 0, 0, 0, 4}, wr_data, SZ_BITS(wr_data)},\n            {12, CmdType::RD, {1, 0, 0, 0, 4}, rd_data, SZ_BITS(rd_data)},\n            {21, CmdType::PRE, {1, 0, 0, 2}},\n            {24, CmdType::END_OF_SIMULATION},\n        });\n\n        test_patterns.push_back({\n            {0, CmdType::ACT, {2, 0, 0, 372}},\n            {3, CmdType::WR, {2, 0, 0, 372, 27}, wr_data, SZ_BITS(wr_data)},\n            {12, CmdType::PRE, {2, 0, 0, 372}},\n            {15, CmdType::SREFEN},\n            {42, CmdType::END_OF_SIMULATION}\n        });\n\n        test_patterns.push_back({\n            {0, CmdType::ACT, {2, 0, 0, 372}},\n            {3, CmdType::RD, {2, 0, 0, 372, 27}, rd_data, SZ_BITS(rd_data)},\n            {12, CmdType::WRA, {2, 0, 0, 372, 27}, wr_data, SZ_BITS(wr_data)},\n            {28, CmdType::SREFEN},\n            {55, CmdType::END_OF_SIMULATION}\n        });\n\n        initSpec();\n        ddr = std::make_unique<DDR5>(*spec);\n    }\n\n    void initSpec() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        spec = std::make_unique<DRAMPower::MemSpecDDR5>(DRAMPower::MemSpecDDR5::from_memspec(*data));\n\n        spec->bitWidth = 16;\n    }\n\n    void runCommands(const std::vector<Command> &commands) {\n        for (const Command &command : commands) {\n            ddr->doCoreCommand(command);\n            ddr->doInterfaceCommand(command);\n        }\n    }\n\n    std::vector<std::vector<Command>> test_patterns;\n    std::unique_ptr<MemSpecDDR5> spec;\n    std::unique_ptr<DDR5> ddr;\n};\n\n// Tests for the window stats (ones to zeros, ones etc)\n// Write and Read bus are trivial\n// Command bus needs to be calculated from command patterns\nTEST_F(DDR5_WindowStats_Tests, Pattern_0) {\n    runCommands(test_patterns[0]);\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(stats.writeBus.ones, 528); // 2 (datarate) * 16 (bus width) * 24 (time) - 240 (zeroes)\n    EXPECT_EQ(stats.writeBus.zeroes, 240);  // 14 (bursts) * 16 (bus width) + 2 (bursts) * 8 (zeroes in data burst)\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 24);  // 16 (first burst) + 8 (data ones to zeroes in bursts)\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 24);  // 8 (data ones to zeroes in bursts) + 8 (last burst data) + 8 (end last burst)\n\n    EXPECT_EQ(stats.readBus.ones, 513); // 2 (datarate) * 16 (bus width) * 24 (time) - 255 (zeroes)\n    EXPECT_EQ(stats.readBus.zeroes, 255);  // 15 (bursts) * 16 (bus width) + 15 (zeroes in data burst)\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 17); // 16 (first burst) + 1 (data ones to zeroes in bursts)\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 17); // 1 (data ones to zeroes in bursts) + 16 (end last burst)\n\n    // Clock\n    EXPECT_EQ(stats.clockStats.ones, 48);\n    EXPECT_EQ(stats.clockStats.zeroes, 48);\n    EXPECT_EQ(stats.clockStats.ones_to_zeroes, 48);\n    EXPECT_EQ(stats.clockStats.zeroes_to_ones, 48);\n\n    // Notes\n    // Pattern.h: first 4 bits of column (C0-C3) are set to 0 (for reads and writes) // TODO correct???\n    EXPECT_EQ(stats.commandBus.ones, 282);\n    EXPECT_EQ(stats.commandBus.zeroes, 54);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 39);\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 39);\n\n    // In this example read data and write data are the same size, so stats should be the same\n    EXPECT_EQ(SZ_BITS(wr_data), SZ_BITS(rd_data));\n    uint_fast8_t NumDQsPairs = spec->bitWidth == 16 ? 2 : 1;\n    uint64_t number_of_cycles = (SZ_BITS(wr_data) / spec->bitWidth);\n    uint_fast8_t scale = NumDQsPairs * 2; // Differential_Pairs * 2(pairs of 2)\n    // f(t) = t / 2;\n    uint64_t DQS_ones = scale * (number_of_cycles / 2); // scale * (cycles / 2)\n    uint64_t DQS_zeros = DQS_ones;\n    uint64_t DQS_zeros_to_ones = DQS_ones;\n    uint64_t DQS_ones_to_zeros = DQS_zeros;\n    EXPECT_EQ(stats.writeDQSStats.ones, DQS_ones);\n    EXPECT_EQ(stats.writeDQSStats.zeroes, DQS_zeros);\n    EXPECT_EQ(stats.writeDQSStats.ones_to_zeroes, DQS_zeros_to_ones);\n    EXPECT_EQ(stats.writeDQSStats.zeroes_to_ones, DQS_ones_to_zeros);\n\n    // Read strobe should be the same (only because wr_data is same as rd_data in this test)\n    EXPECT_EQ(stats.readDQSStats.ones, DQS_ones);\n    EXPECT_EQ(stats.readDQSStats.zeroes, DQS_zeros);\n    EXPECT_EQ(stats.readDQSStats.ones_to_zeroes, DQS_zeros_to_ones);\n    EXPECT_EQ(stats.readDQSStats.zeroes_to_ones, DQS_ones_to_zeros);\n}\n\nTEST_F(DDR5_WindowStats_Tests, Pattern_1) {\n    runCommands(test_patterns[1]);\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(stats.writeBus.ones, 1104); // 2 (datarate) * 16 (bus width) * 42 (time) - 240 (zeroes)\n    EXPECT_EQ(stats.writeBus.zeroes, 240); // 14 (bursts) * 16 (bus width) + 2 (bursts) * 8 (zeroes in data burst)\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 24); // 16 (first burst) + 8 (data ones to zeroes in bursts)\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 24); // 8 (data ones to zeroes in bursts) + 8 (last burst data) + 8 (end last burst)\n\n    EXPECT_EQ(stats.readBus.ones, 1344); // 2 (datarate) * 16 (bus width) * 42 (time)\n    EXPECT_EQ(stats.readBus.zeroes, 0);\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 0);\n\n    EXPECT_EQ(stats.commandBus.ones, 551);\n    EXPECT_EQ(stats.commandBus.zeroes, 37);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 28);\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 28);\n}\n\nTEST_F(DDR5_WindowStats_Tests, Pattern_2) {\n    runCommands(test_patterns[2]);\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(stats.writeBus.ones, 1520); // 2 (datarate) * 16 (bus width) * 55 (time) - 240 (zeroes)\n    EXPECT_EQ(stats.writeBus.zeroes, 240);  // 14 (bursts) * 16 (bus width) + 2 (bursts) * 8 (zeroes in data burst)\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 24);  // 16 (first burst) + 8 (data ones to zeroes in bursts)\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 24);  // 8 (data ones to zeroes in bursts) + 8 (last burst data) + 8 (end last burst)\n\n    EXPECT_EQ(stats.readBus.ones, 1505); // 2 (datarate) * 16 (bus width) * 55 (time) - 255 (zeroes)\n    EXPECT_EQ(stats.readBus.zeroes, 255);  // 15 (bursts) * 16 (bus width) + 15 (zeroes in data burst)\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 17); // 16 (first burst) + 1 (data ones to zeroes in bursts)\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 17); // 1 (data ones to zeroes in bursts) + 16 (end last burst)\n\n    EXPECT_EQ(stats.commandBus.ones, 724);\n    EXPECT_EQ(stats.commandBus.zeroes, 46);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 33);\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 33);\n}\n\n// Tests for power consumption (given a known SimulationStats)\nclass DDR5_Energy_Tests : public ::testing::Test {\n   public:\n    DDR5_Energy_Tests() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        spec = std::make_unique<DRAMPower::MemSpecDDR5>(DRAMPower::MemSpecDDR5::from_memspec(*data));\n\n        t_CK = spec->memTimingSpec.tCK;\n        voltage = spec->vddq;\n\n        // Change impedances to different values from each other\n\t\tspec->memImpedanceSpec.ca_R_eq = 2;\n        spec->memImpedanceSpec.ck_R_eq = 3;\n        spec->memImpedanceSpec.rdqs_R_eq = 4;\n        spec->memImpedanceSpec.wdqs_R_eq = 5;\n\t\tspec->memImpedanceSpec.rdq_R_eq = 6;\n\t\tspec->memImpedanceSpec.wdq_R_eq = 7;\n\n        spec->memImpedanceSpec.ca_dyn_E = 8;\n\t\tspec->memImpedanceSpec.ck_dyn_E = 9;\n\t\tspec->memImpedanceSpec.rdqs_dyn_E = 10;\n\t\tspec->memImpedanceSpec.wdqs_dyn_E = 11;\n\t\tspec->memImpedanceSpec.rdq_dyn_E = 12;\n\t\tspec->memImpedanceSpec.wdq_dyn_E = 13;\n\n        io_calc = std::make_unique<InterfaceCalculation_DDR5>(*spec);\n    }\n\n    std::unique_ptr<MemSpecDDR5> spec;\n    double t_CK;\n    double voltage;\n    std::unique_ptr<InterfaceCalculation_DDR5> io_calc;\n};\n\nTEST_F(DDR5_Energy_Tests, Parameters) {\n    ASSERT_TRUE(t_CK > 0.0);\n    ASSERT_TRUE(voltage > 0.0);\n}\n\nTEST_F(DDR5_Energy_Tests, Clock_Energy) {\n    // Note: stats of both clock lines\n    SimulationStats stats;\n    stats.clockStats.ones = 200;\n    stats.clockStats.zeroes_to_ones = 200;\n\n    stats.clockStats.zeroes = 400;  // different number to validate termination\n    stats.clockStats.ones_to_zeroes = 400;\n\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n    // Clock is provided by the controller not the device\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, 0.0);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, 0.0);\n\n    // DDR5 clock power consumed on 1's\n    double expected_static = stats.clockStats.zeroes * voltage * voltage * 0.5 * t_CK / spec->memImpedanceSpec.ck_R_eq;\n    // Dynamic power is consumed on 0 -> 1 transition\n    double expected_dynamic = stats.clockStats.zeroes_to_ones * spec->memImpedanceSpec.ck_dyn_E;\n\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static);  // value itself doesn't matter, only that it matches the formula\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic);\n}\n\nTEST_F(DDR5_Energy_Tests, DQS_Energy) {\n    SimulationStats stats;\n    stats.readDQSStats.ones = 200;\n    stats.readDQSStats.zeroes = 400;\n    stats.readDQSStats.zeroes_to_ones = 700;\n    stats.readDQSStats.ones_to_zeroes = 1000;\n\n    stats.writeDQSStats.ones = 300;\n    stats.writeDQSStats.zeroes = 100;\n    stats.writeDQSStats.ones_to_zeroes = 2000;\n    stats.writeDQSStats.zeroes_to_ones = 999;\n\n    // Term power if consumed by 1's\n    // Controller -> write power\n    // Dram -> read power\n    double expected_static_controller =\n        0.5 * stats.writeDQSStats.zeroes * voltage * voltage * t_CK / spec->memImpedanceSpec.wdqs_R_eq;\n    double expected_static_dram =\n        0.5 * stats.readDQSStats.zeroes * voltage * voltage * t_CK / spec->memImpedanceSpec.rdqs_R_eq;\n\n    // Dynamic power is consumed on 0 -> 1 transition\n    double expected_dynamic_controller = stats.writeDQSStats.zeroes_to_ones *\n                                         spec->memImpedanceSpec.wdqs_dyn_E;\n    double expected_dynamic_dram = stats.readDQSStats.zeroes_to_ones *\n                                   spec->memImpedanceSpec.rdqs_dyn_E;\n\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, expected_static_dram);\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, expected_dynamic_dram);\n}\n\nTEST_F(DDR5_Energy_Tests, DQ_Energy) {\n    SimulationStats stats;\n    stats.readBus.ones = 7;\n    stats.readBus.zeroes = 11;\n    stats.readBus.zeroes_to_ones = 19;\n    stats.readBus.ones_to_zeroes = 39;\n\n    stats.writeBus.ones = 43;\n    stats.writeBus.zeroes = 59;\n    stats.writeBus.zeroes_to_ones = 13;\n    stats.writeBus.ones_to_zeroes = 17;\n\n    // Term power if consumed by 0's on DDR 5 (pullup terminated)\n    // Controller -> write power\n    // Dram -> read power\n    double expected_static_controller =\n        stats.writeBus.zeroes * voltage * voltage * 0.5 * t_CK / spec->memImpedanceSpec.wdq_R_eq;\n    double expected_static_dram =\n        stats.readBus.zeroes * voltage * voltage * 0.5 * t_CK / spec->memImpedanceSpec.rdq_R_eq;\n\n    // Dynamic power is consumed on 0 -> 1 transition\n    double expected_dynamic_controller =\n        stats.writeBus.zeroes_to_ones * spec->memImpedanceSpec.wdq_dyn_E;\n    double expected_dynamic_dram =\n        stats.readBus.zeroes_to_ones * spec->memImpedanceSpec.rdq_dyn_E;\n\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, expected_static_dram);\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, expected_dynamic_dram);\n}\n\nTEST_F(DDR5_Energy_Tests, CA_Energy) {\n    SimulationStats stats;\n    stats.commandBus.ones = 11;\n    stats.commandBus.zeroes = 29;\n    stats.commandBus.zeroes_to_ones = 39;\n    stats.commandBus.ones_to_zeroes = 49;\n\n    double expected_static_controller = stats.commandBus.zeroes * voltage * voltage * t_CK / spec->memImpedanceSpec.ca_R_eq;\n    double expected_dynamic_controller = stats.commandBus.zeroes_to_ones * spec->memImpedanceSpec.ca_dyn_E;\n\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n\n    // CA bus power is provided by the controller\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, 0.0);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, 0.0);\n\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n}\n"
  },
  {
    "path": "tests/tests_drampower/interface/test_interface_lpddr4.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <DRAMPower/command/Command.h>\n\n#include <DRAMPower/standards/lpddr4/LPDDR4.h>\n#include <DRAMPower/standards/lpddr4/interface_calculation_LPDDR4.h>\n\n#include <memory>\n#include <fstream>\n#include <string>\n#include <stdint.h>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR4.h>\n#include <DRAMPower/standards/test_accessor.h>\n#include <variant>\n\nusing namespace DRAMPower;\n\n#define SZ_BITS(x) sizeof(x)*8\n\nclass DramPowerTest_Interface_LPDDR4 : public ::testing::Test {\nprotected:\n\tstatic constexpr uint8_t wr_data[] = {\n\t\t0, 0, 0, 0,  0, 0, 0, 255,  0, 0, 0, 0,  0, 0, 0, 0,\n\t\t0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 255,\n\t};\n\t// Cycles: 16\n\t// Ones: 16\n\t// Zeroes: 240\n\t// 0 -> 1: 16\n\t// 1 -> 0: 16\n\t// Toggles: 32\n\n\tstatic constexpr uint8_t rd_data[] = {\n\t\t0, 0, 0, 0,  0, 0, 0, 1,  0, 0, 0, 0,  0, 0, 0, 0,\n\t\t0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,\n\t};\n\t// Cycles: 16\n\t// Ones: 1\n\t// Zeroes: 255\n\t// 0 -> 1: 1\n\t// 1 -> 0: 1\n\t// Toggles: 2\n\n\t// Test pattern #1\n\tstd::vector<Command> testPattern = {\n\t\t// Timestamp,   Cmd,  { Bank, BG, Rank, Row, Co-lumn}\n\t\t\t{  0, CmdType::ACT, { 1, 0, 0, 2 } },\n\t\t\t{  5, CmdType::WR,  { 1, 0, 0, 0, 16 }, wr_data, SZ_BITS(wr_data) },\n\t\t\t{ 14, CmdType::RD,  { 1, 0, 0, 0, 16 }, rd_data, SZ_BITS(rd_data) },\n\t\t\t{ 23, CmdType::PRE, { 1, 0, 0, 2 } },\n\t\t\t{ 26,  CmdType::END_OF_SIMULATION },\n\t};\n\n\t// Test pattern #2\n\tstd::vector<Command> testPattern_2 = {\n\t\t// Timestamp,   Cmd,  { Bank, BG, Rank, Row, Co-lumn}\n\t\t\t{  0, CmdType::ACT, { 1, 0, 0, 2 } },\n\t\t\t{  5, CmdType::WR,  { 1, 0, 0, 0, 16 }, wr_data, SZ_BITS(wr_data) },\n\t\t\t{ 14, CmdType::RD,  { 1, 0, 0, 0, 16 }, rd_data, SZ_BITS(rd_data) },\n\t\t\t{ 23, CmdType::WR,  { 1, 0, 0, 0, 16 }, wr_data, SZ_BITS(wr_data) },\n\t\t\t{ 31, CmdType::WR,  { 1, 0, 0, 0, 16 }, wr_data, SZ_BITS(wr_data) },\n\t\t\t{ 40, CmdType::RD,  { 1, 0, 0, 0, 16 }, rd_data, SZ_BITS(rd_data) },\n\t\t\t{ 49, CmdType::WR,  { 1, 0, 0, 0, 16 }, wr_data, SZ_BITS(wr_data) },\n\t\t\t{ 57, CmdType::RD,  { 1, 0, 0, 0, 16 }, rd_data, SZ_BITS(rd_data) },\n\t\t\t{ 70,  CmdType::END_OF_SIMULATION },\n\t};\n\n\n\t// Test variables\n\tstd::unique_ptr<LPDDR4> ddr;\n    std::unique_ptr<MemSpecLPDDR4> spec;\n\n\tvirtual void SetUp()\n\t{\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        auto memSpec = MemSpecLPDDR4::from_memspec(*data);\n\n\t\tmemSpec.numberOfRanks = 1;\n\t\tmemSpec.numberOfBanks = 2;\n\t\tmemSpec.bitWidth = 16;\n\t\tmemSpec.burstLength = 16;\n\t\tmemSpec.dataRate = 2;\n\t\tmemSpec.numberOfDevices = 1;\n\n\t\t// mem timings\n\t\tmemSpec.memTimingSpec.tRAS = 10;\n\t\tmemSpec.memTimingSpec.tRTP = 10;\n\t\tmemSpec.memTimingSpec.tRCD = 20;\n\t\tmemSpec.memTimingSpec.tRFC = 10;\n\t\tmemSpec.memTimingSpec.tRFCPB = 25;\n\n\t\tmemSpec.memTimingSpec.tWR = 20;\n\t\tmemSpec.memTimingSpec.tRP = 20;\n\t\tmemSpec.memTimingSpec.tWL = 0;\n\t\tmemSpec.memTimingSpec.tCK = 1;\n\t\tmemSpec.memTimingSpec.tREFI = 1;\n\n\t\t// Voltage domains\n\t\tmemSpec.memPowerSpec[0].vDDX = 1;\n\t\tmemSpec.memPowerSpec[0].iDD0X = 64;\n\t\tmemSpec.memPowerSpec[0].iDD2NX = 8;\n\t\tmemSpec.memPowerSpec[0].iDD2PX = 6;\n\t\tmemSpec.memPowerSpec[0].iDD3NX = 32;\n\t\tmemSpec.memPowerSpec[0].iDD3PX = 20;\n\t\tmemSpec.memPowerSpec[0].iDD4RX = 72;\n\t\tmemSpec.memPowerSpec[0].iDD4WX = 72;\n\n\t\tmemSpec.memPowerSpec[1].vDDX = 1;\n\t\tmemSpec.memPowerSpec[1].iDD0X = 64;\n\t\tmemSpec.memPowerSpec[1].iDD2NX = 8;\n\t\tmemSpec.memPowerSpec[1].iDD2PX = 6;\n\t\tmemSpec.memPowerSpec[1].iDD3NX = 32;\n\t\tmemSpec.memPowerSpec[1].iDD3PX = 20;\n\t\tmemSpec.memPowerSpec[1].iDD4RX = 72;\n\t\tmemSpec.memPowerSpec[1].iDD4WX = 72;\n\n\t\tmemSpec.bwParams.bwPowerFactRho = 0.333333333;\n\t\n\t\tspec = std::make_unique<MemSpecLPDDR4>(memSpec);\n\t\tddr = std::make_unique<LPDDR4>(memSpec);\n\t}\n\n\tvirtual void TearDown()\n\t{\n\t}\n};\n\nTEST_F(DramPowerTest_Interface_LPDDR4, TestStats)\n{\n\tfor (const auto& command : testPattern) {\n\t\tddr->doCoreCommand(command);\n\t\tddr->doInterfaceCommand(command);\n\t};\n\n\tauto stats = ddr->getStats();\n\n\tASSERT_EQ(stats.commandBus.ones, 15);\n\tASSERT_EQ(stats.commandBus.zeroes, 141);\n\tASSERT_EQ(stats.commandBus.ones_to_zeroes, 14);\n\tASSERT_EQ(stats.commandBus.zeroes_to_ones, 14);\n\n\t// Verify read bus stats\n\tASSERT_EQ(stats.readBus.ones, 1);\t// 1\n\tASSERT_EQ(stats.readBus.zeroes, 831);  // 2 (datarate) * 26 (time) * 16 (bus width) - 1 (ones) \n\tASSERT_EQ(stats.readBus.ones_to_zeroes, 1);\n\tASSERT_EQ(stats.readBus.zeroes_to_ones, 1);\n\tASSERT_EQ(stats.readBus.bit_changes, 2);\n\n\t// Verify write bus stats\n\tASSERT_EQ(stats.writeBus.ones, 16);\t   // 2 (bursts) * 8 (ones per burst)\n\tASSERT_EQ(stats.writeBus.zeroes, 816); // 2 (datarate) * 26 (time) * 16 (bus width) - 16 (ones) \n\tASSERT_EQ(stats.writeBus.ones_to_zeroes, 16);\n\tASSERT_EQ(stats.writeBus.zeroes_to_ones, 16);\n\tASSERT_EQ(stats.writeBus.bit_changes, 32);\n}\n\nTEST_F(DramPowerTest_Interface_LPDDR4, TestPower)\n{\n\tfor (const auto& command : testPattern) {\n\t\tddr->doCoreCommand(command);\n\t\tddr->doInterfaceCommand(command);\n\t};\n\n\tauto stats = ddr->getStats();\n\n\t// TODO add tests\n\n\tInterfaceCalculation_LPDDR4 interface_calc(*spec);\n\n\t// auto interface_stats = interface_calc.calcEnergy(stats);\n\t// auto dqs_stats = interface_calc.calcDQSEnergy(stats);\n}\n\nTEST_F(DramPowerTest_Interface_LPDDR4, TestDQS)\n{\n\tfor (const auto& command : testPattern_2) {\n\t\tauto stats = ddr->getWindowStats(command.timestamp);\n\n\t\tddr->doCoreCommand(command);\n\t\tddr->doInterfaceCommand(command);\n\t};\n\n\tauto stats = ddr->getStats();\n\t// DQs bus\n    EXPECT_EQ(sizeof(wr_data), sizeof(rd_data));\n    int number_of_cycles = (SZ_BITS(wr_data) / spec->bitWidth);\n\tuint_fast8_t NumDQsPairs = spec->bitWidth == 16 ? 2 : 1;\n    uint_fast8_t scale = NumDQsPairs * 2; // Differential_Pairs * 2(pairs of 2)\n    // f(t) = t / 2;\n    int DQS_ones = scale * (number_of_cycles / 2); // scale * (cycles / 2)\n    int DQS_zeros = DQS_ones;\n    int DQS_zeros_to_ones = DQS_ones;\n    int DQS_ones_to_zeros = DQS_zeros;\n\n\t// 4 writes\n    EXPECT_EQ(stats.writeDQSStats.ones, DQS_ones * 4);\n    EXPECT_EQ(stats.writeDQSStats.zeroes, DQS_zeros * 4);\n    EXPECT_EQ(stats.writeDQSStats.ones_to_zeroes, DQS_zeros_to_ones * 4);\n    EXPECT_EQ(stats.writeDQSStats.zeroes_to_ones, DQS_ones_to_zeros * 4);\n\t// 3 reads\n    EXPECT_EQ(stats.readDQSStats.ones, DQS_ones * 3);\n    EXPECT_EQ(stats.readDQSStats.zeroes, DQS_zeros * 3);\n    EXPECT_EQ(stats.readDQSStats.ones_to_zeroes, DQS_zeros_to_ones * 3);\n    EXPECT_EQ(stats.readDQSStats.zeroes_to_ones, DQS_ones_to_zeros * 3);\n\n\t// ASSERT_EQ(stats.readDQSStats.ones, 16 *3); // 16 (burst length) * 3 (reads)\n\t// ASSERT_EQ(stats.readDQSStats.zeroes, 16*3);\n\n\t// ASSERT_EQ(stats.writeDQSStats.ones, 16*4); // 16 (burst length) * 4 (writes)\n\t// ASSERT_EQ(stats.writeDQSStats.zeroes, 16*4);\n}\n\n\nTEST_F(DramPowerTest_Interface_LPDDR4, Test_Detailed)\n{\n\tSimulationStats window;\n\n\tauto iterate_to_timestamp = [this, command = testPattern.begin()](timestamp_t timestamp) mutable {\n\t\twhile (command != this->testPattern.end() && command->timestamp <= timestamp) {\n\t\t\tddr->doCoreCommand(*command);\n\t\t\tddr->doInterfaceCommand(*command);\n\t\t\t++command;\n\t\t}\n\n\t\treturn this->ddr->getWindowStats(timestamp);\n\t};\n\n\t// Cycle 0 to 0 (0 delta)\n\twindow = iterate_to_timestamp(0);\n\tASSERT_EQ(window.commandBus.ones, 0);\n\tASSERT_EQ(window.commandBus.zeroes, 0);\n\n\t// Cycle 0 to 1 (1 delta)\n\twindow = iterate_to_timestamp(1);\n\tASSERT_EQ(window.commandBus.ones, 1);\n\tASSERT_EQ(window.commandBus.zeroes, 5);\n\n\t// Cycle 0 to 2 (2 delta)\n\twindow = iterate_to_timestamp(2);\n\tASSERT_EQ(window.commandBus.ones, 2);\n\tASSERT_EQ(window.commandBus.zeroes, 10);\n\n\t// Cycle 0 to 3 (3 delta)\n\twindow = iterate_to_timestamp(3);\n\tASSERT_EQ(window.commandBus.ones, 2);\n\tASSERT_EQ(window.commandBus.zeroes, 16);\n\n\t// Cycle 0 to 4 (4 delta)\n\twindow = iterate_to_timestamp(4);\n\tASSERT_EQ(window.commandBus.ones, 3);\n\tASSERT_EQ(window.commandBus.zeroes, 21);\n\n\t// Cycle 0 to 5 (5 delta)\n\twindow = iterate_to_timestamp(5);\n\tASSERT_EQ(window.commandBus.ones, 3);\n\tASSERT_EQ(window.commandBus.zeroes, 27);\n\n\t// Cycle 0 to 6 (6 delta)\n\twindow = iterate_to_timestamp(6);\n\tASSERT_EQ(window.commandBus.ones, 4);\n\tASSERT_EQ(window.commandBus.zeroes, 32);\n\n\t// Cycle 0 to 7 (7 delta)\n\twindow = iterate_to_timestamp(7);\n\tASSERT_EQ(window.commandBus.ones, 5);\n\tASSERT_EQ(window.commandBus.zeroes, 37);\n\n\t// Cycle 0 to 8 (8 delta)\n\twindow = iterate_to_timestamp(8);\n\tASSERT_EQ(window.commandBus.ones, 7);\n\tASSERT_EQ(window.commandBus.zeroes, 41);\n\n\t// Cycle 0 to 9 (9 delta)\n\twindow = iterate_to_timestamp(9);\n\tASSERT_EQ(window.commandBus.ones, 8);\n\tASSERT_EQ(window.commandBus.zeroes, 46);\n\n\t// Cycle 0 to 10 (10 delta)\n\twindow = iterate_to_timestamp(10);\n\tASSERT_EQ(window.commandBus.ones, 8);\n\tASSERT_EQ(window.commandBus.zeroes, 52);\n\n\t// Cycle 0 to 14 (14 delta)\n\twindow = iterate_to_timestamp(14);\n\tASSERT_EQ(window.commandBus.ones, 8);\n\tASSERT_EQ(window.commandBus.zeroes, 76);\n\n\t// Cycle 0 to 15 (15 delta)\n\twindow = iterate_to_timestamp(15);\n\tASSERT_EQ(window.commandBus.ones, 9);\n\tASSERT_EQ(window.commandBus.zeroes, 81);\n\n\t// Cycle 0 to 16 (16 delta)\n\twindow = iterate_to_timestamp(16);\n\tASSERT_EQ(window.commandBus.ones, 10);\n\tASSERT_EQ(window.commandBus.zeroes, 86);\n\n\t// Cycle 0 to 17 (17 delta)\n\twindow = iterate_to_timestamp(17);\n\tASSERT_EQ(window.commandBus.ones, 12);\n\tASSERT_EQ(window.commandBus.zeroes, 90);\n\n\t// Cycle 0 to 18 (18 delta)\n\twindow = iterate_to_timestamp(18);\n\tASSERT_EQ(window.commandBus.ones, 13);\n\tASSERT_EQ(window.commandBus.zeroes, 95);\n\n\t// Cycle 0 to 19 (19 delta)\n\twindow = iterate_to_timestamp(19);\n\tASSERT_EQ(window.commandBus.ones, 13);\n\tASSERT_EQ(window.commandBus.zeroes, 101);\n\n\t// Cycle 0 to 23 (23 delta)\n\twindow = iterate_to_timestamp(23);\n\tASSERT_EQ(window.commandBus.ones, 13);\n\tASSERT_EQ(window.commandBus.zeroes, 125);\n\n\t// Cycle 0 to 24 (24 delta)\n\twindow = iterate_to_timestamp(24);\n\tASSERT_EQ(window.commandBus.ones, 14);\n\tASSERT_EQ(window.commandBus.zeroes, 130);\n\n\t\n\twindow = iterate_to_timestamp(25);\n\tASSERT_EQ(window.commandBus.ones, 15);\n\tASSERT_EQ(window.commandBus.zeroes, 135);\n\n\twindow = iterate_to_timestamp(26);\n\tASSERT_EQ(window.commandBus.ones, 15);\n\tASSERT_EQ(window.commandBus.zeroes, 141);\n\n\twindow = iterate_to_timestamp(26);\n\tASSERT_EQ(window.commandBus.ones, 15);\n\tASSERT_EQ(window.commandBus.zeroes, 141);\n\n\twindow = iterate_to_timestamp(26);\n\tASSERT_EQ(window.commandBus.ones, 15);\n\tASSERT_EQ(window.commandBus.zeroes, 141);\n\n\t// EOS\n\twindow = iterate_to_timestamp(26);\n\tASSERT_EQ(window.commandBus.ones, 15);\n\tASSERT_EQ(window.commandBus.zeroes, 141);\n\n\t// After EOS\n\tfor(auto i = 1; i <= 100; i++) {\n\t\twindow = iterate_to_timestamp(26+i);\n\t\tASSERT_EQ(window.commandBus.ones, 15);\n\t\tASSERT_EQ(window.commandBus.zeroes, 141+i*6);\n\t}\n}\n\n// Tests for power consumption (given a known SimulationStats)\nclass LPDDR4_Energy_Tests : public ::testing::Test {\n   public:\n\tLPDDR4_Energy_Tests() {\n\t\tauto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n\t\tspec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*data));\n\n\t\tt_CK = spec->memTimingSpec.tCK;\n\t\tvoltage = spec->vddq;\n\n\t\t// Change impedances to different values from each other\n\t\tspec->memImpedanceSpec.ca_R_eq = 2;\n        spec->memImpedanceSpec.ck_R_eq = 3;\n        spec->memImpedanceSpec.rdqs_R_eq = 4;\n        spec->memImpedanceSpec.wdqs_R_eq = 5;\n\t\tspec->memImpedanceSpec.rdq_R_eq = 6;\n\t\tspec->memImpedanceSpec.wdq_R_eq = 7;\n\n        spec->memImpedanceSpec.ca_dyn_E = 8;\n\t\tspec->memImpedanceSpec.ck_dyn_E = 9;\n\t\tspec->memImpedanceSpec.rdqs_dyn_E = 10;\n\t\tspec->memImpedanceSpec.wdqs_dyn_E = 11;\n\t\tspec->memImpedanceSpec.rdq_dyn_E = 12;\n\t\tspec->memImpedanceSpec.wdq_dyn_E = 13;\n\n\t\tio_calc = std::make_unique<InterfaceCalculation_LPDDR4>(*spec);\n\t}\n\n\tstd::unique_ptr<MemSpecLPDDR4> spec;\n\tdouble t_CK;\n\tdouble voltage;\n\tstd::unique_ptr<InterfaceCalculation_LPDDR4> io_calc;\n};\n\nTEST_F(LPDDR4_Energy_Tests, Parameters) {\n\tASSERT_TRUE(t_CK > 0.0);\n\tASSERT_TRUE(voltage > 0.0);\n}\n\nTEST_F(LPDDR4_Energy_Tests, Clock_Energy) {\n\tSimulationStats stats;\n\tstats.clockStats.ones = 43;\n\tstats.clockStats.zeroes_to_ones = 47;\n\tstats.clockStats.zeroes = 53;\n\tstats.clockStats.ones_to_zeroes = 59;\n\n\tinterface_energy_info_t result = io_calc->calculateEnergy(stats);\n\t// Clock is provided by the controller not the device\n\tEXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, 0.0);\n\tEXPECT_DOUBLE_EQ(result.dram.staticEnergy, 0.0);\n\n\t// Clock is differential so there is always going to be one signal that consumes power\n\t// Calculation is done considering number of ones but could also be zeroes, since clock is\n\t// a symmetrical signal\n\t// f(t) = t / 2\n\t// Differential pair 2 limes in N = 2 * N_single\n\t// E = f(N * t_CK) * U^2/R\n\tdouble expected_static =\n\t\tstats.clockStats.ones * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.ck_R_eq;\n\t// E = N * 1/2 * C * U^2\n\tdouble expected_dynamic =\n\t\tstats.clockStats.zeroes_to_ones * spec->memImpedanceSpec.ck_dyn_E;\n\n\tEXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static);  // value itself doesn't matter, only that it matches the formula\n\tEXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic);\n\tEXPECT_TRUE(result.controller.staticEnergy > 0.0);\n\tEXPECT_TRUE(result.controller.dynamicEnergy > 0.0);\n}\n\nTEST_F(LPDDR4_Energy_Tests, DQS_Energy) {\n\t// TODO implement test with new interface model\n\tSimulationStats stats;\n\tstats.readDQSStats.ones = 200;\n\tstats.readDQSStats.zeroes = 400;\n\tstats.readDQSStats.zeroes_to_ones = 700;\n\tstats.readDQSStats.ones_to_zeroes = 1000;\n\n\tstats.writeDQSStats.ones = 300;\n\tstats.writeDQSStats.zeroes = 100;\n\tstats.writeDQSStats.ones_to_zeroes = 2000;\n\tstats.writeDQSStats.zeroes_to_ones = 999;\n\n\t// Term power if consumed by 1's\n\t// Controller -> write power\n\t// Dram -> read power\n\tdouble expected_static_controller = stats.writeDQSStats.ones * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.wdqs_R_eq;\n\tdouble expected_static_dram = stats.readDQSStats.ones * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.rdqs_R_eq;\n\n\n\t// Dynamic power is consumed on 0 -> 1 transition\n\tdouble expected_dynamic_controller = stats.writeDQSStats.zeroes_to_ones * spec->memImpedanceSpec.wdqs_dyn_E;\n\tdouble expected_dynamic_dram = stats.readDQSStats.zeroes_to_ones * spec->memImpedanceSpec.rdqs_dyn_E;\n\n\tinterface_energy_info_t result = io_calc->calculateEnergy(stats);\n\tEXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n\tEXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n\tEXPECT_DOUBLE_EQ(result.dram.staticEnergy, expected_static_dram);\n\tEXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, expected_dynamic_dram);\n\n\tEXPECT_TRUE(result.dram.staticEnergy > 0.0);\n\tEXPECT_TRUE(result.dram.dynamicEnergy > 0.0);\n}\n\nTEST_F(LPDDR4_Energy_Tests, DQ_Energy) {\n\tSimulationStats stats;\n\tstats.readBus.ones = 7;\n\tstats.readBus.zeroes = 11;\n\tstats.readBus.zeroes_to_ones = 19;\n\tstats.readBus.ones_to_zeroes = 39;\n\n\tstats.writeBus.ones = 43;\n\tstats.writeBus.zeroes = 59;\n\tstats.writeBus.zeroes_to_ones = 13;\n\tstats.writeBus.ones_to_zeroes = 17;\n\n\t// Term power if consumed by 1's on LPDDR4 (pulldown terminated)\n\t// Controller -> write power\n\t// Dram -> read power\n\tdouble expected_static_controller =\n\t\tstats.writeBus.ones * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.wdq_R_eq;\n\tdouble expected_static_dram =\n\t\tstats.readBus.ones * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.rdq_R_eq;\n\n\t// Dynamic power is consumed on 0 -> 1 transition\n\tdouble expected_dynamic_controller = stats.writeBus.zeroes_to_ones * spec->memImpedanceSpec.wdq_dyn_E;\n\tdouble expected_dynamic_dram = stats.readBus.zeroes_to_ones * spec->memImpedanceSpec.rdq_dyn_E;\n\n\tinterface_energy_info_t result = io_calc->calculateEnergy(stats);\n\tEXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n\tEXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n\tEXPECT_DOUBLE_EQ(result.dram.staticEnergy, expected_static_dram);\n\tEXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, expected_dynamic_dram);\n\n\tEXPECT_TRUE(result.controller.staticEnergy > 0.0);\n\tEXPECT_TRUE(result.controller.dynamicEnergy > 0.0);\n\tEXPECT_TRUE(result.dram.staticEnergy > 0.0);\n\tEXPECT_TRUE(result.dram.dynamicEnergy > 0.0);\n}\n\nTEST_F(LPDDR4_Energy_Tests, CA_Energy) {\n\tSimulationStats stats;\n\tstats.commandBus.ones = 11;\n\tstats.commandBus.zeroes = 29;\n\tstats.commandBus.zeroes_to_ones = 39;\n\tstats.commandBus.ones_to_zeroes = 49;\n\n\tdouble expected_static_controller =\n\t\tstats.commandBus.ones * voltage * voltage * t_CK / spec->memImpedanceSpec.ca_R_eq;\n\tdouble expected_dynamic_controller = stats.commandBus.zeroes_to_ones * spec->memImpedanceSpec.ca_dyn_E;\n\n\tinterface_energy_info_t result = io_calc->calculateEnergy(stats);\n\n\t// CA bus power is provided by the controller\n\tEXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, 0.0);\n\tEXPECT_DOUBLE_EQ(result.dram.staticEnergy, 0.0);\n\n\tEXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n\tEXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n\n\tEXPECT_TRUE(result.controller.staticEnergy > 0.0);\n\tEXPECT_TRUE(result.controller.dynamicEnergy > 0.0);\n}\n"
  },
  {
    "path": "tests/tests_drampower/interface/test_interface_lpddr5.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <memory>\n#include <fstream>\n\n#include <DRAMPower/memspec/MemSpec.h>\n#include <DRAMUtils/memspec/standards/MemSpecLPDDR5.h>\n#include <DRAMPower/standards/test_accessor.h>\n#include <variant>\n\n#include \"DRAMPower/data/energy.h\"\n#include \"DRAMPower/data/stats.h\"\n#include \"DRAMPower/memspec/MemSpecLPDDR5.h\"\n#include \"DRAMPower/standards/lpddr5/LPDDR5.h\"\n#include \"DRAMPower/standards/lpddr5/interface_calculation_LPDDR5.h\"\n\nusing DRAMPower::CmdType;\nusing DRAMPower::Command;\nusing DRAMPower::LPDDR5;\nusing DRAMPower::interface_energy_info_t;\nusing DRAMPower::InterfaceCalculation_LPDDR5;\nusing DRAMPower::MemSpecLPDDR5;\nusing DRAMPower::SimulationStats;\n\n#define SZ_BITS(x) sizeof(x)*8\n\nusing namespace DRAMPower;\n\nstatic constexpr uint8_t wr_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 255,  0, 0, 0, 0,  0, 0, 0, 0,\n    0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 255,\n};\n\nstatic constexpr uint8_t rd_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 1,  0, 0, 0, 0,  0, 0, 0, 0,\n    0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,\n};\n\nclass LPDDR5_WindowStats_Tests : public ::testing::Test {\n   public:\n    LPDDR5_WindowStats_Tests() {\n\t\t// Timestamp,   Cmd,  { Bank, BG, Rank, Row, Co-lumn}\n        test_patterns.push_back({\n            {0, CmdType::ACT, {1, 0, 0, 2}},\n            {3, CmdType::WR, {1, 0, 0, 0, 8}, wr_data, SZ_BITS(wr_data)},\n            {12, CmdType::RD, {1, 0, 0, 0, 8}, rd_data, SZ_BITS(rd_data)},\n            {21, CmdType::PRE, {1, 0, 0, 2}},\n            {24, CmdType::END_OF_SIMULATION},\n        });\n\n        test_patterns.push_back({\n            {0, CmdType::ACT, {2, 0, 0, 372}},\n            {3, CmdType::WRA, {2, 0, 0, 372, 27}, wr_data, SZ_BITS(wr_data)},\n            {18, CmdType::SREFEN},\n            {45, CmdType::SREFEX},\n            {48, CmdType::END_OF_SIMULATION}\n        });\n\n        test_patterns.push_back({\n            {0, CmdType::ACT, {2, 0, 0, 372}},\n            {3, CmdType::WR, {2, 0, 0, 372, 27}, wr_data, SZ_BITS(wr_data)},\n            {12, CmdType::RDA, {2, 0, 0, 372, 27}, rd_data, SZ_BITS(rd_data)},\n            {24, CmdType::END_OF_SIMULATION}  // RD needs time to finish fully\n        });\n\n        // With BG != 0 for testing BG mode\n        test_patterns.push_back({\n            {0, CmdType::ACT, {1, 1, 0, 2}},\n            {3, CmdType::WR, {1, 1, 0, 0, 19}, wr_data, SZ_BITS(wr_data)},\n            {12, CmdType::RD, {1, 1, 0, 0, 19}, rd_data, SZ_BITS(rd_data)},\n            {21, CmdType::PRE, {1, 1, 0, 2}},\n            {24, CmdType::END_OF_SIMULATION},\n        });\n\n        initSpec();\n        ddr = std::make_unique<LPDDR5>(*spec);\n    }\n\n    void initSpec() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        spec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        spec->numberOfDevices = 1;\n        spec->bitWidth = 16;\n    }\n\n    void runCommands(const std::vector<Command> &commands) {\n        for (const Command &command : commands) {\n            ddr->doCoreCommand(command);\n            ddr->doInterfaceCommand(command);\n        }\n    }\n\n    std::vector<std::vector<Command>> test_patterns;\n    std::unique_ptr<MemSpecLPDDR5> spec;\n    std::unique_ptr<LPDDR5> ddr;\n};\n\n// Tests for the window stats (ones to zeros, ones etc)\n// Write and Read bus are trivial\n// Command bus needs to be calculated from command patterns\nTEST_F(LPDDR5_WindowStats_Tests, Pattern_0) {\n    // auto test_pattern = test_patterns[0];\n    \n    // auto iterate_to_timestamp = [this, command = test_pattern.begin(), end = test_pattern.end()](timestamp_t timestamp) mutable {\n\t// \twhile (command != end && command->timestamp <= timestamp) {\n\t// \t\tddr->doCommand(*command);\n\t// \t\tddr->handleInterfaceCommand(*command);\n\t// \t\t++command;\n\t// \t}\n\n\t// \treturn this->ddr->getWindowStats(timestamp);\n\t// };\n    // for(auto i = 0; i < 26; i++)\n    // {\n    //     SimulationStats window = iterate_to_timestamp(i);\n    //     std::cout << \"Timestamp: \" << i << std::endl;\n    // }\n\n    // iterate_to_timestamp(test_patterns[0].back().timestamp);\n    runCommands(test_patterns[0]);\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(stats.writeBus.ones, 16);\n    EXPECT_EQ(stats.writeBus.zeroes, 752);  // 2 (datarate) * 24 (time) * 16 (bus width) - 16 (ones)\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 16);  // 0 -> 255 = 8 transitions, *2 = 16\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 16);  // back to 0\n\n    EXPECT_EQ(stats.readBus.ones, 1);\n    EXPECT_EQ(stats.readBus.zeroes, 767);  // 2 (datarate) * 24 (time) * 16 (bus width) - 1 (ones)\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 1);\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 1);\n\n    EXPECT_EQ(stats.commandBus.ones, 19);\n    EXPECT_EQ(stats.commandBus.zeroes, 317);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 15);\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 15);\n\n    // For read the number of clock cycles the strobes stay on is\n    EXPECT_EQ(sizeof(wr_data), sizeof(rd_data));\n    uint64_t number_of_cycles = (SZ_BITS(wr_data) / spec->bitWidth);\n    uint_fast8_t scale = 1 * 2; // Differential_Pairs * 2(pairs of 2)\n    // f(t) = t / 2;\n    uint64_t DQS_ones = scale * (number_of_cycles / 2); // scale * (cycles / 2)\n    uint64_t DQS_zeros = DQS_ones;\n    uint64_t DQS_zeros_to_ones = DQS_ones;\n    uint64_t DQS_ones_to_zeros = DQS_zeros;\n\n    EXPECT_EQ(stats.readDQSStats.ones, DQS_ones);\n    EXPECT_EQ(stats.readDQSStats.zeroes, DQS_zeros);\n    EXPECT_EQ(stats.readDQSStats.ones_to_zeroes, DQS_zeros_to_ones);\n    EXPECT_EQ(stats.readDQSStats.zeroes_to_ones, DQS_ones_to_zeros);\n\n    // TODO WCK\n}\n\nTEST_F(LPDDR5_WindowStats_Tests, Pattern_1) {\n    // auto test_pattern = test_patterns[1];\n    // auto iterate_to_timestamp = [this, command = test_pattern.begin(), end = test_pattern.end()](timestamp_t timestamp) mutable {\n\t// \twhile (command != end && command->timestamp <= timestamp) {\n\t// \t\tddr->doCommand(*command);\n\t// \t\tddr->handleInterfaceCommand(*command);\n\t// \t\t++command;\n\t// \t}\n\n\t// \treturn this->ddr->getWindowStats(timestamp);\n\t// };\n    // for(auto i = 0; i < 50; i++)\n    // {\n    //     SimulationStats window = iterate_to_timestamp(i);\n    //     std::cout << \"Timestamp: \" << i << std::endl;\n    // }\n\n    // iterate_to_timestamp(test_patterns[1].back().timestamp);\n    runCommands(test_patterns[1]);\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(stats.writeBus.ones, 16);\n    EXPECT_EQ(stats.writeBus.zeroes, 1520); // 2 (datarate) * 48 (time) * 16 (bus width) - 16 (ones)\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 16);\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 16);\n\n    EXPECT_EQ(stats.readBus.ones, 0);\n    EXPECT_EQ(stats.readBus.zeroes, 1536); // 2 (datarate) * 48 (time) * 16 (bus width)\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 0);\n\n    EXPECT_EQ(stats.commandBus.ones, 24);\n    EXPECT_EQ(stats.commandBus.zeroes, 648);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 19);\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 19);\n\n    EXPECT_EQ(stats.readDQSStats.ones, 0);\n    EXPECT_EQ(stats.readDQSStats.zeroes, 0);\n    EXPECT_EQ(stats.readDQSStats.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.readDQSStats.zeroes_to_ones, 0);\n}\n\nTEST_F(LPDDR5_WindowStats_Tests, Pattern_2) {\n    // auto test_pattern = test_patterns[2];\n    \n    // auto iterate_to_timestamp = [this, command = test_pattern.begin(), end = test_pattern.end()](timestamp_t timestamp) mutable {\n\t// \twhile (command != end && command->timestamp <= timestamp) {\n\t// \t\tddr->doCommand(*command);\n\t// \t\tddr->handleInterfaceCommand(*command);\n\t// \t\t++command;\n\t// \t}\n\n\t// \treturn this->ddr->getWindowStats(timestamp);\n\t// };\n    // for(auto i = 0; i < 30; i++)\n    // {\n    //     SimulationStats window = iterate_to_timestamp(i);\n    //     std::cout << \"Timestamp: \" << i << std::endl;\n    // }\n\n    // iterate_to_timestamp(test_patterns[2].back().timestamp);\n    runCommands(test_patterns[2]);\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(stats.writeBus.ones, 16);\n    EXPECT_EQ(stats.writeBus.zeroes, 752); // 2 (datarate) * 24 (time) * 16 (bus width) - 16 (ones)\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 16);\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 16);\n\n    EXPECT_EQ(stats.readBus.ones, 1);\n    EXPECT_EQ(stats.readBus.zeroes, 767); // 2 (datarate) * 24 (time) * 16 (bus width) - 1 (ones)\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 1);\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 1);\n\n    EXPECT_EQ(stats.commandBus.ones, 25);\n    EXPECT_EQ(stats.commandBus.zeroes, 311);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 19);\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 19);\n}\n\n// Write clock tests\nTEST_F(LPDDR5_WindowStats_Tests, WriteClockAlwaysOn) {\n    runCommands(test_patterns[0]);\n\n    SimulationStats stats = ddr->getStats();\n\n    uint64_t wck_rate = spec->dataRate / spec->memTimingSpec.WCKtoCK;\n\n    // Number of cycles for always on is the simulation time\n    uint64_t wck_ones = 24 * wck_rate;\n    EXPECT_EQ(stats.wClockStats.ones, wck_ones);\n    EXPECT_EQ(stats.wClockStats.zeroes, wck_ones);\n    EXPECT_EQ(stats.wClockStats.ones_to_zeroes, wck_ones);\n    EXPECT_EQ(stats.wClockStats.zeroes_to_ones, wck_ones);\n}\n\nTEST_F(LPDDR5_WindowStats_Tests, WriteClockOnDemand) {\n    spec->wckAlwaysOnMode = false;\n    ddr = std::make_unique<LPDDR5>(*spec);\n\n    runCommands(test_patterns[0]);\n\n    SimulationStats stats = ddr->getStats();\n    uint64_t wck_rate = spec->dataRate / spec->memTimingSpec.WCKtoCK;\n\n    // Number of clocks of WCK is the length of the write data\n    uint64_t cycles = SZ_BITS(wr_data) / 16;\n\n    uint64_t wck_ones = cycles * wck_rate;\n    EXPECT_EQ(stats.wClockStats.ones, wck_ones);\n    EXPECT_EQ(stats.wClockStats.zeroes, wck_ones);\n    EXPECT_EQ(stats.wClockStats.ones_to_zeroes, wck_ones);\n    EXPECT_EQ(stats.wClockStats.zeroes_to_ones, wck_ones);\n}\n\nTEST_F(LPDDR5_WindowStats_Tests, Pattern_3_BG_Mode) {\n    spec->bank_arch = MemSpecLPDDR5::MBG;\n    ddr = std::make_unique<LPDDR5>(*spec);\n\n    // auto test_pattern = test_patterns[3];\n    \n    // auto iterate_to_timestamp = [this, command = test_pattern.begin(), end = test_pattern.end()](timestamp_t timestamp) mutable {\n\t// \twhile (command != end && command->timestamp <= timestamp) {\n\t// \t\tddr->doCommand(*command);\n\t// \t\tddr->handleInterfaceCommand(*command);\n\t// \t\t++command;\n\t// \t}\n\n\t// \treturn this->ddr->getWindowStats(timestamp);\n\t// };\n    // for(auto i = 0; i < 30; i++)\n    // {\n    //     SimulationStats window = iterate_to_timestamp(i);\n    //     std::cout << \"Timestamp: \" << i << std::endl;\n    // }\n\n    // iterate_to_timestamp(test_patterns[2].back().timestamp);\n    runCommands(test_patterns[3]);\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(stats.writeBus.ones, 16);\n    EXPECT_EQ(stats.writeBus.zeroes, 752); // 2 (datarate) * 24 (time) * 16 (bus width) - 16 (ones)\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 16);\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 16);\n\n    EXPECT_EQ(stats.readBus.ones, 1);\n    EXPECT_EQ(stats.readBus.zeroes, 767); // 2 (datarate) * 24 (time) * 16 (bus width) - 1 (ones)\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 1);\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 1);\n\n    EXPECT_EQ(stats.commandBus.ones, 27);\n    EXPECT_EQ(stats.commandBus.zeroes, 309);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 21);\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 21);\n\n    EXPECT_EQ(sizeof(wr_data), sizeof(rd_data));\n    uint64_t number_of_cycles = (SZ_BITS(wr_data) / spec->bitWidth);\n    uint_fast8_t scale = 1 * 2; // Differential_Pairs * 2(pairs of 2)\n    // f(t) = t / 2;\n    uint64_t DQS_ones = scale * (number_of_cycles / 2); // scale * (cycles / 2)\n    uint64_t DQS_zeros = DQS_ones;\n    uint64_t DQS_zeros_to_ones = DQS_ones;\n    uint64_t DQS_ones_to_zeros = DQS_zeros;\n\n    EXPECT_EQ(stats.readDQSStats.ones, DQS_ones);\n    EXPECT_EQ(stats.readDQSStats.zeroes, DQS_zeros);\n    EXPECT_EQ(stats.readDQSStats.ones_to_zeroes, DQS_zeros_to_ones);\n    EXPECT_EQ(stats.readDQSStats.zeroes_to_ones, DQS_ones_to_zeros);\n}\n\n// Tests for power consumption (given a known SimulationStats)\nclass LPDDR5_Energy_Tests : public ::testing::Test {\n   public:\n    LPDDR5_Energy_Tests() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        spec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        t_CK = spec->memTimingSpec.tCK;\n        t_WCK = spec->memTimingSpec.tWCK;\n        voltage = spec->vddq;\n\n        // Change impedances to different values from each other\n\t\tspec->memImpedanceSpec.ca_R_eq = 2;\n        spec->memImpedanceSpec.ck_R_eq = 3;\n        spec->memImpedanceSpec.rdqs_R_eq = 4;\n        spec->memImpedanceSpec.wck_R_eq = 5;\n\t\tspec->memImpedanceSpec.rdq_R_eq = 6;\n\t\tspec->memImpedanceSpec.wdq_R_eq = 7;\n\n        spec->memImpedanceSpec.ca_dyn_E = 8;\n\t\tspec->memImpedanceSpec.ck_dyn_E = 9;\n\t\tspec->memImpedanceSpec.rdqs_dyn_E = 10;\n\t\tspec->memImpedanceSpec.wck_dyn_E = 11;\n\t\tspec->memImpedanceSpec.rdq_dyn_E = 12;\n\t\tspec->memImpedanceSpec.wdq_dyn_E = 13;\n\n        io_calc = std::make_unique<InterfaceCalculation_LPDDR5>(*spec);\n    }\n\n    std::unique_ptr<MemSpecLPDDR5> spec;\n    double t_CK;\n    double t_WCK;\n    double voltage;\n    std::unique_ptr<InterfaceCalculation_LPDDR5> io_calc;\n};\n\nTEST_F(LPDDR5_Energy_Tests, Parameters) {\n    ASSERT_TRUE(t_CK > 0.0);\n    ASSERT_TRUE(voltage > 0.0);\n    ASSERT_TRUE(t_WCK > 0.0);\n}\n\nTEST_F(LPDDR5_Energy_Tests, Clock_Energy) {\n    SimulationStats stats;\n    stats.clockStats.ones = 43;\n    stats.clockStats.zeroes_to_ones = 47;\n    stats.clockStats.zeroes = 53;\n    stats.clockStats.ones_to_zeroes = 59;\n\n    stats.wClockStats.ones = 61;\n    stats.wClockStats.zeroes = 67;\n    stats.wClockStats.zeroes_to_ones = 71;\n    stats.wClockStats.ones_to_zeroes = 73;\n\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n    // Clock is provided by the controller not the device\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, 0.0);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, 0.0);\n\n    // Clock is differential so there is always going to be one signal that consumes power\n    // Calculation is done considering number of ones but could also be zeroes, since clock is\n    // a symmetrical signal\n    double expected_static = stats.clockStats.ones * voltage * voltage * 0.5 * t_CK / spec->memImpedanceSpec.ck_R_eq;\n    expected_static += stats.wClockStats.ones * voltage * voltage * 0.5 * t_WCK / spec->memImpedanceSpec.wck_R_eq;\n\n    double expected_dynamic = stats.clockStats.zeroes_to_ones * spec->memImpedanceSpec.ck_dyn_E;\n    expected_dynamic += stats.wClockStats.zeroes_to_ones * spec->memImpedanceSpec.wck_dyn_E;\n\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static);  // value itself doesn't matter, only that it matches the formula\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic);\n    EXPECT_TRUE(result.controller.staticEnergy > 0.0);\n    EXPECT_TRUE(result.controller.dynamicEnergy > 0.0);\n}\n\nTEST_F(LPDDR5_Energy_Tests, DQS_Energy) {\n    SimulationStats stats;\n    stats.readDQSStats.ones = 200;\n    stats.readDQSStats.zeroes = 400;\n    stats.readDQSStats.zeroes_to_ones = 700;\n    stats.readDQSStats.ones_to_zeroes = 1000;\n\n    // Write DQS is not used in LPDDR5, instead there is WCK\n    stats.writeDQSStats.ones = 300;\n    stats.writeDQSStats.zeroes = 100;\n    stats.writeDQSStats.ones_to_zeroes = 2000;\n    stats.writeDQSStats.zeroes_to_ones = 999;\n\n    // Term power if consumed by 1's\n    // Controller -> write power\n    // Dram -> read power\n    double expected_static_controller = 0.0;\n    double expected_static_dram =\n        0.5 * stats.readDQSStats.ones * voltage * voltage * t_CK / spec->memImpedanceSpec.rdqs_R_eq;\n\n    // Dynamic power is consumed on 0 -> 1 transition\n    double expected_dynamic_controller = 0;\n    double expected_dynamic_dram = stats.readDQSStats.zeroes_to_ones *\n                                   spec->memImpedanceSpec.rdqs_dyn_E;\n\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, expected_static_dram);\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, expected_dynamic_dram);\n\n    EXPECT_TRUE(result.dram.staticEnergy > 0.0);\n    EXPECT_TRUE(result.dram.dynamicEnergy > 0.0);\n}\n\nTEST_F(LPDDR5_Energy_Tests, DQ_Energy) {\n    SimulationStats stats;\n    stats.readBus.ones = 7;\n    stats.readBus.zeroes = 11;\n    stats.readBus.zeroes_to_ones = 19;\n    stats.readBus.ones_to_zeroes = 39;\n\n    stats.writeBus.ones = 43;\n    stats.writeBus.zeroes = 59;\n    stats.writeBus.zeroes_to_ones = 13;\n    stats.writeBus.ones_to_zeroes = 17;\n\n    // Term power if consumed by 1's on LPDDR5 (pulldown terminated)\n    // Controller -> write power\n    // Dram -> read power\n    double expected_static_controller =\n        0.5 * stats.writeBus.ones * voltage * voltage * t_CK / spec->memImpedanceSpec.wdq_R_eq;\n    double expected_static_dram =\n        0.5 * stats.readBus.ones * voltage * voltage * t_CK / spec->memImpedanceSpec.rdq_R_eq;\n\n    // Dynamic power is consumed on 0 -> 1 transition\n    double expected_dynamic_controller =\n        stats.writeBus.zeroes_to_ones * spec->memImpedanceSpec.wdq_dyn_E;\n    double expected_dynamic_dram =\n        stats.readBus.zeroes_to_ones * spec->memImpedanceSpec.rdq_dyn_E;\n\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, expected_static_dram);\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, expected_dynamic_dram);\n\n    EXPECT_TRUE(result.controller.staticEnergy > 0.0);\n    EXPECT_TRUE(result.controller.dynamicEnergy > 0.0);\n    EXPECT_TRUE(result.dram.staticEnergy > 0.0);\n    EXPECT_TRUE(result.dram.dynamicEnergy > 0.0);\n}\n\nTEST_F(LPDDR5_Energy_Tests, CA_Energy) {\n    SimulationStats stats;\n    stats.commandBus.ones = 11;\n    stats.commandBus.zeroes = 29;\n    stats.commandBus.zeroes_to_ones = 39;\n    stats.commandBus.ones_to_zeroes = 49;\n\n    // Data rate 2\n    double expected_static_controller = stats.commandBus.ones * voltage * voltage * 0.5 * t_CK / spec->memImpedanceSpec.ca_R_eq;\n    double expected_dynamic_controller = stats.commandBus.zeroes_to_ones * spec->memImpedanceSpec.ca_dyn_E;\n\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n\n    // CA bus power is provided by the controller\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, 0.0);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, 0.0);\n\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n\n    EXPECT_TRUE(result.controller.staticEnergy > 0.0);\n    EXPECT_TRUE(result.controller.dynamicEnergy > 0.0);\n}\n"
  },
  {
    "path": "tests/tests_drampower/interface/test_togglingrate_ddr4.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <memory>\n#include <vector>\n#include <cmath>\n\n#include <DRAMUtils/config/toggling_rate.h>\n\n#include \"DRAMPower/simconfig/simconfig.h\"\n#include \"DRAMPower/standards/ddr4/DDR4.h\"\n#include \"DRAMPower/standards/test_accessor.h\"\n#include \"DRAMPower/memspec/MemSpecDDR4.h\"\n#include \"DRAMPower/standards/ddr4/interface_calculation_DDR4.h\"\n\n#include \"DRAMPower/data/energy.h\"\n#include \"DRAMPower/data/stats.h\"\n\nusing namespace DRAMPower;\nusing namespace DRAMUtils::Config;\n\n#define SZ_BITS(x) sizeof(x)*8\n\n// burst length = 16 for x8 devices\nstatic constexpr uint8_t wr_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 255,  0, 0, 0, 0,  0, 0, 0, 0,\n};\n\n// burst length = 16 for x8 devices\nstatic constexpr uint8_t rd_data[] = {\n    255, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,\n};\n\nclass DDR4_TogglingRate_Tests : public ::testing::Test {\n   public:\n\n    void SetUp() override {\n        test_patterns.push_back({\n            {0, CmdType::ACT, {1, 0, 0, 2}},\n            {4, CmdType::WR, {1, 0, 0, 0, 16}, nullptr, datasize_bits},\n            {11, CmdType::RD, {1, 0, 0, 0, 16}, nullptr, datasize_bits},\n            {16, CmdType::PRE, {1, 0, 0, 2}},\n            {24, CmdType::END_OF_SIMULATION},\n        });\n\n        initSpec();\n    }\n\n    void initSpec() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        spec = std::make_unique<DRAMPower::MemSpecDDR4>(DRAMPower::MemSpecDDR4::from_memspec(*data));\n    }\n\n    void initDDR(const ToggleRateDefinition& trd) {\n        ddr = std::make_unique<DDR4>(*spec, config::SimConfig{trd});\n    }\n\n    void runCommands(const std::vector<Command> &commands) {\n        for (const Command &command : commands) {\n            ddr->doCoreCommand(command);\n            ddr->doInterfaceCommand(command);\n        }\n    }\n\n    std::vector<std::vector<Command>> test_patterns;\n    std::unique_ptr<MemSpecDDR4> spec;\n    std::unique_ptr<DDR4> ddr;\n    uint64_t datasize_bits = 8 * 8; // 8 bytes\n};\n\nTEST_F(DDR4_TogglingRate_Tests, Pattern_0_LH) {\n    // Setup toggling rate\n    double togglingRateRead = 0.7;\n    double togglingRateWrite = 0.3;\n    double dutyCycleRead = 0.6;\n    double dutyCycleWrite = 0.4;\n    TogglingRateIdlePattern idlePatternRead = TogglingRateIdlePattern::L;\n    TogglingRateIdlePattern idlePatternWrite = TogglingRateIdlePattern::H;\n    auto trd = ToggleRateDefinition {\n        togglingRateRead, // togglingRateRead\n        togglingRateWrite, // togglingRateWrite\n        dutyCycleRead, // dutyCycleRead\n        dutyCycleWrite, // dutyCycleWrite\n        idlePatternRead, // idlePatternRead\n        idlePatternWrite  // idlePatternWrite\n    };\n    initDDR(trd);\n    // Run commands\n    runCommands(test_patterns.at(0));\n    // SZ_BITS: 64, width: 8 -> Burstlength: 8 (datarate bus)\n    // 0: ACT, 4: WR, 11: RD, 16: PRE, 24: EOS\n    // Read bus: idle: L\n        // 0 to 11 idle\n        // 11 to 15 toggle\n        // 15 to 24 idle\n        // idle: 20 zeroes, toggle: 4 (datarate clock)\n        // idle: 40 zeroes, toggle: 8 (datarate bus)\n    // Write bus: idle: H\n        // 0 to 4 idle\n        // 4 to 8 toggle\n        // 8 to 24 idle\n        // idle: 20 ones, toggle: 4 (datarate clock)\n        // idle: 40 ones, toggle: 8 (datarate bus)\n    uint64_t toggles_read = 8;\n    uint64_t toggles_write = 8;\n\n    uint64_t idleread_ones = 0;\n    uint64_t idleread_zeroes = 40;\n    uint64_t idlewrite_ones = 40;\n    uint64_t idlewrite_zeroes = 0;\n\n\n    SimulationStats stats = ddr->getStats();\n    \n    EXPECT_EQ(spec->dataRate, 2);\n\n// Data bus\n    // Read bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.ones, (idleread_ones +  static_cast<uint64_t>(std::floor(dutyCycleRead * toggles_read))) * spec->bitWidth); // 32\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes, (idleread_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleRead) * toggles_read))) * spec->bitWidth); // 344\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.ones_to_zeroes, std::floor((togglingRateRead / 2) * toggles_read) * spec->bitWidth); // 16\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateRead / 2) * toggles_read)) *  spec->bitWidth); // 16\n    \n    // Write bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.ones, (idlewrite_ones +  static_cast<uint64_t>(std::floor(dutyCycleWrite * toggles_write))) * spec->bitWidth); // 344\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes, (idlewrite_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleWrite) * toggles_write))) * spec->bitWidth); // 32\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.ones_to_zeroes, std::floor((togglingRateWrite / 2) * toggles_write) * spec->bitWidth); // 8\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateWrite / 2) * toggles_write)) * spec->bitWidth); // 8\n\n// Clock (see test_interface_ddr4)\n    EXPECT_EQ(stats.clockStats.ones, 48);\n    EXPECT_EQ(stats.clockStats.zeroes, 48);\n    EXPECT_EQ(stats.clockStats.ones_to_zeroes, 48);\n    EXPECT_EQ(stats.clockStats.zeroes_to_ones, 48);\n\n// Command bus (see test_interface_ddr4)\n    EXPECT_EQ(stats.commandBus.ones, 591);\n    EXPECT_EQ(stats.commandBus.zeroes, 57);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 57);\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 57);\n\n// DQs (see test_interface_ddr4)\n    uint_fast8_t NumDQsPairs = spec->bitWidth == 16 ? 2 : 1;\n    int number_of_cycles = (datasize_bits / spec->bitWidth);\n    uint_fast8_t scale = NumDQsPairs * 2; // Differential_Pairs * 2(pairs of 2)\n    // f(t) = t / 2;\n    int DQS_ones = scale * (number_of_cycles / 2); // scale * (cycles / 2)\n    int DQS_zeros = DQS_ones;\n    int DQS_zeros_to_ones = DQS_ones;\n    int DQS_ones_to_zeros = DQS_zeros;\n    EXPECT_EQ(stats.writeDQSStats.ones, DQS_ones);\n    EXPECT_EQ(stats.writeDQSStats.zeroes, DQS_zeros);\n    EXPECT_EQ(stats.writeDQSStats.ones_to_zeroes, DQS_zeros_to_ones);\n    EXPECT_EQ(stats.writeDQSStats.zeroes_to_ones, DQS_ones_to_zeros);\n    EXPECT_EQ(stats.readDQSStats.ones, DQS_ones);\n    EXPECT_EQ(stats.readDQSStats.zeroes, DQS_zeros);\n    EXPECT_EQ(stats.readDQSStats.ones_to_zeroes, DQS_zeros_to_ones);\n    EXPECT_EQ(stats.readDQSStats.zeroes_to_ones, DQS_ones_to_zeros);\n\n// PrePostamble\n    auto prepos = stats.rank_total[0].prepos;\n    EXPECT_EQ(prepos.readSeamless, 0);\n    EXPECT_EQ(prepos.writeSeamless, 0);\n    EXPECT_EQ(prepos.readMerged, 0);\n    EXPECT_EQ(prepos.readMergedTime, 0);\n    EXPECT_EQ(prepos.writeMerged, 0);\n    EXPECT_EQ(prepos.writeMergedTime, 0);\n}\n\nTEST_F(DDR4_TogglingRate_Tests, Pattern_0_HZ) {\n    // Setup toggling rate\n    double togglingRateRead = 0.7;\n    double togglingRateWrite = 0.3;\n    double dutyCycleRead = 0.6;\n    double dutyCycleWrite = 0.4;\n    TogglingRateIdlePattern idlePatternRead = TogglingRateIdlePattern::H;\n    TogglingRateIdlePattern idlePatternWrite = TogglingRateIdlePattern::Z;\n    auto trd = ToggleRateDefinition {\n        togglingRateRead, // togglingRateRead\n        togglingRateWrite, // togglingRateWrite\n        dutyCycleRead, // dutyCycleRead\n        dutyCycleWrite, // dutyCycleWrite\n        idlePatternRead, // idlePatternRead\n        idlePatternWrite  // idlePatternWrite\n    };\n    \n    initDDR(trd);\n    // Run commands\n    runCommands(test_patterns[0]);\n    // SZ_BITS: 64, width: 8 -> Burstlength: 8 (datarate bus)\n    // 0: ACT, 4: WR, 11: RD, 16: PRE, 24: EOS\n    // Read bus: idle: H\n        // 0 to 11 idle\n        // 11 to 15 toggle\n        // 15 to 24 idle\n        // idle: 20 ones, toggle: 4 (datarate clock)\n        // idle: 40 ones, toggle: 8 (datarate bus)\n    // Write bus: idle: Z\n        // 0 to 4 idle\n        // 4 to 8 toggle\n        // 8 to 24 idle\n        // idle: 0 ones/zeroes, toggle: 4 (datarate clock)\n        // idle: 0 ones/zeroes, toggle: 8 (datarate bus)\n    uint64_t toggles_read = 8;\n    uint64_t toggles_write = 8;\n\n    uint64_t idleread_zeroes = 0;\n    uint64_t idleread_ones = 40;\n    uint64_t idlewrite_ones = 0;\n    uint64_t idlewrite_zeroes = 0;\n\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n// Data bus\n    // Read bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.ones, (idleread_ones +  static_cast<uint64_t>(std::floor(dutyCycleRead * toggles_read))) * spec->bitWidth); // 352\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes, (idleread_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleRead) * toggles_read))) * spec->bitWidth); // 24\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.ones_to_zeroes, std::floor((togglingRateRead / 2) * toggles_read) * spec->bitWidth); // 16\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateRead / 2) * toggles_read)) *  spec->bitWidth); // 16\n    \n    // Write bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.ones, (idlewrite_ones +  static_cast<uint64_t>(std::floor(dutyCycleWrite * toggles_write))) * spec->bitWidth); // 24\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes, (idlewrite_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleWrite) * toggles_write))) * spec->bitWidth); // 32\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.ones_to_zeroes, std::floor((togglingRateWrite / 2) * toggles_write) * spec->bitWidth); // 8\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateWrite / 2) * toggles_write)) * spec->bitWidth); // 8\n}\n\n// Tests for power consumption (given a known SimulationStats)\nclass DDR4_TogglingRateEnergy_Tests : public ::testing::Test {\n   public:\n    DDR4_TogglingRateEnergy_Tests() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr4.json\");\n        spec = std::make_unique<DRAMPower::MemSpecDDR4>(DRAMPower::MemSpecDDR4::from_memspec(*data));\n\n        t_CK = spec->memTimingSpec.tCK;\n        voltage = spec->memPowerSpec[MemSpecDDR4::VoltageDomain::VDD].vXX;\n\n        // Change impedances to different values from each other\n\t\tspec->memImpedanceSpec.ca_R_eq = 2;\n        spec->memImpedanceSpec.ck_R_eq = 3;\n        spec->memImpedanceSpec.rdqs_R_eq = 4;\n        spec->memImpedanceSpec.wdqs_R_eq = 5;\n\t\tspec->memImpedanceSpec.rdq_R_eq = 6;\n\t\tspec->memImpedanceSpec.wdq_R_eq = 7;\n\n        spec->memImpedanceSpec.ca_dyn_E = 8;\n\t\tspec->memImpedanceSpec.ck_dyn_E = 9;\n\t\tspec->memImpedanceSpec.rdqs_dyn_E = 10;\n\t\tspec->memImpedanceSpec.wdqs_dyn_E = 11;\n\t\tspec->memImpedanceSpec.rdq_dyn_E = 12;\n\t\tspec->memImpedanceSpec.wdq_dyn_E = 13;\n\n        // PrePostamble is a possible DDR4 pattern\n        // Preamble 2tCK, Postamble 0.5tCK\n        spec->prePostamble.read_ones = 2.5;\n        spec->prePostamble.read_zeroes = 2.5;\n        spec->prePostamble.read_zeroes_to_ones = 2;\n        spec->prePostamble.read_ones_to_zeroes = 2;\n\n        io_calc = std::make_unique<InterfaceCalculation_DDR4>(*spec);\n    }\n\n    std::unique_ptr<MemSpecDDR4> spec;\n    double t_CK;\n    double voltage;\n    std::unique_ptr<InterfaceCalculation_DDR4> io_calc;\n};\n\nTEST_F(DDR4_TogglingRateEnergy_Tests, DQ_Energy) {\n    SimulationStats stats;\n    stats.togglingStats = TogglingStats();\n    stats.togglingStats.read.ones = 7;\n    stats.togglingStats.read.zeroes = 11;\n    stats.togglingStats.read.zeroes_to_ones = 19;\n    stats.togglingStats.read.ones_to_zeroes = 39;\n\n    stats.togglingStats.write.ones = 43;\n    stats.togglingStats.write.zeroes = 59;\n    stats.togglingStats.write.zeroes_to_ones = 13;\n    stats.togglingStats.write.ones_to_zeroes = 17;\n\n    // Controller -> write power\n    // Dram -> read power\n    double expected_static_controller =\n        stats.togglingStats.write.zeroes * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.wdq_R_eq;\n    double expected_static_dram =\n        stats.togglingStats.read.zeroes * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.rdq_R_eq;\n\n    // Dynamic power is consumed on 0 -> 1 transition\n    double expected_dynamic_controller = stats.togglingStats.write.zeroes_to_ones *\n                            spec->memImpedanceSpec.wdq_dyn_E;\n    double expected_dynamic_dram = stats.togglingStats.read.zeroes_to_ones *\n                            spec->memImpedanceSpec.rdq_dyn_E;\n\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, expected_static_dram);\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, expected_dynamic_dram);\n}\n\nTEST_F(DDR4_TogglingRate_Tests, Pattern_1) {\n    // Setup toggling rate\n    double togglingRateRead = 0.7;\n    double togglingRateWrite = 0.3;\n    double dutyCycleRead = 0.6;\n    double dutyCycleWrite = 0.4;\n    TogglingRateIdlePattern idlePatternRead = TogglingRateIdlePattern::L;\n    TogglingRateIdlePattern idlePatternWrite = TogglingRateIdlePattern::H;\n\n    auto trd = ToggleRateDefinition {\n        togglingRateRead, // togglingRateRead\n        togglingRateWrite, // togglingRateWrite\n        dutyCycleRead, // dutyCycleRead\n        dutyCycleWrite, // dutyCycleWrite\n        idlePatternRead, // idlePatternRead\n        idlePatternWrite  // idlePatternWrite\n    };\n    initDDR(trd);\n\n    // Run commands\n    ddr->doCommand({0, CmdType::ACT, {1, 0, 0, 2}});\n    ddr->doCommand({5, CmdType::WR, {1, 0, 0, 0, 16}, wr_data, SZ_BITS(wr_data)});\n    ddr->doCommand({14, CmdType::RD, {1, 0, 0, 0, 16}, rd_data, SZ_BITS(rd_data)});\n    ddr->doCommand({23, CmdType::PRE, {1, 0, 0, 2}});\n    ddr->doCommand({30, CmdType::ACT, {1, 0, 0, 2}});\n    ddr->doCommand({35, CmdType::WR, {1, 0, 0, 0, 16}, nullptr, 16*8}); // burst length = 16\n    ddr->doCommand({44, CmdType::RD, {1, 0, 0, 0, 16}, nullptr, 16*8}); // burst length = 16\n    ddr->doCommand({53, CmdType::PRE, {1, 0, 0, 2}});\n    ddr->doCommand({56, CmdType::END_OF_SIMULATION});\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n// Toggling rate\n    uint64_t toggles_read = 2 * 16;\n    uint64_t idleread_ones = 0;\n    uint64_t idleread_zeroes = 2 * 56 - toggles_read; // TogglingRateIdlePattern::L\n\n    uint64_t toggles_write = 2 * 16;\n    uint64_t idlewrite_ones = 2 * 56 - toggles_write; // TogglingRateIdlePattern::H\n    uint64_t idlewrite_zeroes = 0;\n\n    // Read bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.ones, (idleread_ones +  static_cast<uint64_t>(std::floor(dutyCycleRead * toggles_read))) * spec->bitWidth); // 112\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes, (idleread_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleRead) * toggles_read))) * spec->bitWidth); // 296\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.ones_to_zeroes, std::floor((togglingRateRead / 2) * toggles_read) * spec->bitWidth); // 64\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateRead / 2) * toggles_read)) * spec->bitWidth); // 64\n    \n    // Write bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.ones, (idlewrite_ones +  static_cast<uint64_t>(std::floor(dutyCycleWrite * toggles_write))) * spec->bitWidth); // 256\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes, (idlewrite_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleWrite) * toggles_write))) * spec->bitWidth); // 152\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.ones_to_zeroes, std::floor((togglingRateWrite / 2) * toggles_write) * spec->bitWidth); // 32\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateWrite / 2) * toggles_write)) * spec->bitWidth); // 32\n\n// Data bus\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 0);\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.readBus.zeroes, 0);\n    EXPECT_EQ(stats.readBus.ones, 0);\n\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 0);\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.writeBus.zeroes, 0);\n    EXPECT_EQ(stats.writeBus.ones, 0);\n\n// Clock (see test_interface_ddr4)\n    EXPECT_EQ(stats.clockStats.zeroes_to_ones, 112);\n    EXPECT_EQ(stats.clockStats.ones_to_zeroes, 112);\n    EXPECT_EQ(stats.clockStats.zeroes, 112);\n    EXPECT_EQ(stats.clockStats.ones, 112);\n\n// Command bus (see test_interface_ddr4)\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 114);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 114);\n    EXPECT_EQ(stats.commandBus.zeroes, 114);\n    EXPECT_EQ(stats.commandBus.ones, 1398);\n\n// DQs (see test_interface_ddr4)\n    EXPECT_EQ(stats.writeDQSStats.zeroes_to_ones, 32);\n    EXPECT_EQ(stats.writeDQSStats.ones_to_zeroes, 32);\n    EXPECT_EQ(stats.writeDQSStats.zeroes, 32);\n    EXPECT_EQ(stats.writeDQSStats.ones, 32);\n    EXPECT_EQ(stats.readDQSStats.zeroes_to_ones, 32);\n    EXPECT_EQ(stats.readDQSStats.ones_to_zeroes, 32);\n    EXPECT_EQ(stats.readDQSStats.zeroes, 32);\n    EXPECT_EQ(stats.readDQSStats.ones, 32);\n\n// PrePostamble\n    auto prepos = stats.rank_total[0].prepos;\n    EXPECT_EQ(prepos.readSeamless, 0);\n    EXPECT_EQ(prepos.writeSeamless, 0);\n    EXPECT_EQ(prepos.readMerged, 0);\n    EXPECT_EQ(prepos.readMergedTime, 0);\n    EXPECT_EQ(prepos.writeMerged, 0);\n    EXPECT_EQ(prepos.writeMergedTime, 0);\n}\n"
  },
  {
    "path": "tests/tests_drampower/interface/test_togglingrate_ddr5.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <memory>\n#include <vector>\n#include <cmath>\n\n#include <DRAMUtils/config/toggling_rate.h>\n\n#include \"DRAMPower/simconfig/simconfig.h\"\n#include \"DRAMPower/standards/ddr5/DDR5.h\"\n#include \"DRAMPower/memspec/MemSpecDDR5.h\"\n#include <DRAMPower/standards/test_accessor.h>\n#include \"DRAMPower/standards/ddr5/interface_calculation_DDR5.h\"\n\n#include \"DRAMPower/data/energy.h\"\n#include \"DRAMPower/data/stats.h\"\n\nusing namespace DRAMPower;\nusing namespace DRAMUtils::Config;\n\n#define SZ_BITS(x) sizeof(x)*8\n\n// burst length = 16 for x8 devices\nstatic constexpr uint8_t wr_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 255,  0, 0, 0, 0,  0, 0, 0, 0,\n};\n\n// burst length = 16 for x8 devices\nstatic constexpr uint8_t rd_data[] = {\n    255, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,\n};\n\nclass DDR5_TogglingRate_Tests : public ::testing::Test {\n   public:\n    void SetUp() override {\n        test_patterns.push_back({\n            {0, CmdType::ACT, {1, 0, 0, 2}},\n            {3, CmdType::WR, {1, 0, 0, 0, 4}, nullptr, datasize_bits},\n            {12, CmdType::RD, {1, 0, 0, 0, 4}, nullptr, datasize_bits},\n            {21, CmdType::PRE, {1, 0, 0, 2}},\n            {24, CmdType::END_OF_SIMULATION},\n        });\n\n        initSpec();\n    }\n\n    void initSpec() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        spec = std::make_unique<DRAMPower::MemSpecDDR5>(DRAMPower::MemSpecDDR5::from_memspec(*data));\n    }\n\n    void initDDR(const ToggleRateDefinition& trd) {\n        ddr = std::make_unique<DDR5>(*spec, config::SimConfig{trd});\n    }\n\n    void runCommands(const std::vector<Command> &commands) {\n        for (const Command &command : commands) {\n            ddr->doCoreCommand(command);\n            ddr->doInterfaceCommand(command);\n        }\n    }\n\n    std::vector<std::vector<Command>> test_patterns;\n    std::unique_ptr<MemSpecDDR5> spec;\n    std::unique_ptr<DDR5> ddr;\n    uint_fast16_t datasize_bits = 32 * 8; // 32 bytes\n};\n\nTEST_F(DDR5_TogglingRate_Tests, Pattern_0_LH) {\n    // Setup toggling rate\n    double togglingRateRead = 0.7;\n    double togglingRateWrite = 0.3;\n    double dutyCycleRead = 0.6;\n    double dutyCycleWrite = 0.4;\n    TogglingRateIdlePattern idlePatternRead = TogglingRateIdlePattern::L;\n    TogglingRateIdlePattern idlePatternWrite = TogglingRateIdlePattern::H;\n    auto trd = ToggleRateDefinition {\n        togglingRateRead, // togglingRateRead\n        togglingRateWrite, // togglingRateWrite\n        dutyCycleRead, // dutyCycleRead\n        dutyCycleWrite, // dutyCycleWrite\n        idlePatternRead, // idlePatternRead\n        idlePatternWrite  // idlePatternWrite\n    };\n    initDDR(trd);\n    // Run commands\n    runCommands(test_patterns.at(0));\n    // SZ_BITS: 256, width: 8 -> Burstlength: 32 (datarate bus)\n    // 0: ACT, 3: WR, 12: RD, 21: PRE, 24: EOS\n    // Read bus: idle: L\n        // 0 to 12 idle\n        // 12 to 24 toggle -> toggle cut off by EOS\n        // idle: 12 zeroes, toggle: 12 (datarate clock)\n        // idle: 24 zeroes, toggle: 24 (datarate bus)\n    // Write bus: idle: H\n        // 0 to 3 idle\n        // 3 to 19 toggle\n        // 19 to 24 idle\n        // idle: 8 ones, toggle: 16 (datarate clock)\n        // idle: 16 zeroes, toggle: 32 (datarate bus)\n    uint64_t toggles_read = 24;\n    uint64_t toggles_write = 32;\n\n    uint64_t idleread_ones = 0;\n    uint64_t idleread_zeroes = 24;\n    uint64_t idlewrite_ones = 16;\n    uint64_t idlewrite_zeroes = 0;\n\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n// Data bus\n    // Read bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.ones, (idleread_ones +  static_cast<uint64_t>(std::floor(dutyCycleRead * toggles_read))) * spec->bitWidth); // 112\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes, (idleread_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleRead) * toggles_read))) * spec->bitWidth); // 264\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.ones_to_zeroes, std::floor((togglingRateRead / 2) * toggles_read) * spec->bitWidth); // 64\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateRead / 2) * toggles_read)) * spec->bitWidth); // 64\n    \n    // Write bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.ones, (idlewrite_ones +  static_cast<uint64_t>(std::floor(dutyCycleWrite * toggles_write))) * spec->bitWidth); // 224\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes, (idlewrite_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleWrite) * toggles_write))) * spec->bitWidth); // 152\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.ones_to_zeroes, std::floor((togglingRateWrite / 2) * toggles_write) * spec->bitWidth); // 32\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateWrite / 2) * toggles_write)) * spec->bitWidth); // 32\n\n// Clock (see test_interface_ddr5)\n    EXPECT_EQ(stats.clockStats.ones, 48);\n    EXPECT_EQ(stats.clockStats.zeroes, 48);\n    EXPECT_EQ(stats.clockStats.ones_to_zeroes, 48);\n    EXPECT_EQ(stats.clockStats.zeroes_to_ones, 48);\n\n// Command bus (see test_interface_ddr5)\n    EXPECT_EQ(stats.commandBus.ones, 282);\n    EXPECT_EQ(stats.commandBus.zeroes, 54);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 39);\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 39);\n\n// DQs (see test_interface_ddr5)\n    uint_fast8_t NumDQsPairs = spec->bitWidth == 16 ? 2 : 1;\n    int number_of_cycles = (datasize_bits / spec->bitWidth);\n    uint_fast8_t scale = NumDQsPairs * 2; // Differential_Pairs * 2(pairs of 2)\n    // f(t) = t / 2;\n    int DQS_ones = scale * (number_of_cycles / 2); // scale * (cycles / 2)\n    int DQS_zeros = DQS_ones;\n    int DQS_zeros_to_ones = DQS_ones;\n    int DQS_ones_to_zeros = DQS_zeros;\n    EXPECT_EQ(stats.writeDQSStats.ones, DQS_ones);\n    EXPECT_EQ(stats.writeDQSStats.zeroes, DQS_zeros);\n    EXPECT_EQ(stats.writeDQSStats.ones_to_zeroes, DQS_zeros_to_ones);\n    EXPECT_EQ(stats.writeDQSStats.zeroes_to_ones, DQS_ones_to_zeros);\n    EXPECT_EQ(stats.readDQSStats.ones, DQS_ones);\n    EXPECT_EQ(stats.readDQSStats.zeroes, DQS_zeros);\n    EXPECT_EQ(stats.readDQSStats.ones_to_zeroes, DQS_zeros_to_ones);\n    EXPECT_EQ(stats.readDQSStats.zeroes_to_ones, DQS_ones_to_zeros);\n}\n\nTEST_F(DDR5_TogglingRate_Tests, Pattern_0_HZ) {\n    // Setup toggling rate\n    double togglingRateRead = 0.7;\n    double togglingRateWrite = 0.3;\n    double dutyCycleRead = 0.6;\n    double dutyCycleWrite = 0.4;\n    TogglingRateIdlePattern idlePatternRead = TogglingRateIdlePattern::H;\n    TogglingRateIdlePattern idlePatternWrite = TogglingRateIdlePattern::Z;\n    auto trd = ToggleRateDefinition {\n        togglingRateRead, // togglingRateRead\n        togglingRateWrite, // togglingRateWrite\n        dutyCycleRead, // dutyCycleRead\n        dutyCycleWrite, // dutyCycleWrite\n        idlePatternRead, // idlePatternRead\n        idlePatternWrite  // idlePatternWrite\n    };\n    \n    initDDR(trd);\n    // Run commands\n    runCommands(test_patterns[0]);\n    // SZ_BITS: 256, width: 8 -> Burstlength: 32 (datarate bus)\n    // 0: ACT, 3: WR, 12: RD, 21: PRE, 24: EOS\n    // Read bus: idle: H\n        // 0 to 12 idle\n        // 12 to 24 toggle -> toggle cut off by EOS\n        // idle: 12 ones, toggle: 12 (datarate clock)\n        // idle: 24 ones, toggle: 24 (datarate bus)\n    // Write bus: idle: Z\n        // 0 to 3 idle\n        // 3 to 19 toggle\n        // 19 to 24 idle\n        // idle: 0 ones/zeroes, toggle: 16 (datarate clock)\n        // idle: 0 ones/zeroes, toggle: 32 (datarate bus)\n    uint64_t toggles_read = 24;\n    uint64_t toggles_write = 32;\n\n    uint64_t idleread_zeroes = 0;\n    uint64_t idleread_ones = 24;\n    uint64_t idlewrite_ones = 0;\n    uint64_t idlewrite_zeroes = 0;\n\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n// Data bus\n    // Read bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.ones, (idleread_ones +  static_cast<uint64_t>(std::floor(dutyCycleRead * toggles_read))) * spec->bitWidth); // 304\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes, (idleread_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleRead) * toggles_read))) * spec->bitWidth); // 72\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.ones_to_zeroes, std::floor((togglingRateRead / 2) * toggles_read) * spec->bitWidth); // 64\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateRead / 2) * toggles_read)) * spec->bitWidth); // 64\n    \n    // Write bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.ones, (idlewrite_ones +  static_cast<uint64_t>(std::floor(dutyCycleWrite * toggles_write))) * spec->bitWidth); // 96\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes, (idlewrite_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleWrite) * toggles_write))) * spec->bitWidth); // 152\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.ones_to_zeroes, std::floor((togglingRateWrite / 2) * toggles_write) * spec->bitWidth); // 32\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateWrite / 2) * toggles_write)) * spec->bitWidth); // 32\n}\n\n// Tests for power consumption (given a known SimulationStats)\nclass DDR5_TogglingRateEnergy_Tests : public ::testing::Test {\n   public:\n    DDR5_TogglingRateEnergy_Tests() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"ddr5.json\");\n        spec = std::make_unique<DRAMPower::MemSpecDDR5>(DRAMPower::MemSpecDDR5::from_memspec(*data));\n\n        t_CK = spec->memTimingSpec.tCK;\n        voltage = spec->vddq;\n\n        // Change impedances to different values from each other\n\t\tspec->memImpedanceSpec.ca_R_eq = 2;\n        spec->memImpedanceSpec.ck_R_eq = 3;\n        spec->memImpedanceSpec.rdqs_R_eq = 4;\n        spec->memImpedanceSpec.wdqs_R_eq = 5;\n\t\tspec->memImpedanceSpec.rdq_R_eq = 6;\n\t\tspec->memImpedanceSpec.wdq_R_eq = 7;\n\n        spec->memImpedanceSpec.ca_dyn_E = 8;\n\t\tspec->memImpedanceSpec.ck_dyn_E = 9;\n\t\tspec->memImpedanceSpec.rdqs_dyn_E = 10;\n\t\tspec->memImpedanceSpec.wdqs_dyn_E = 11;\n\t\tspec->memImpedanceSpec.rdq_dyn_E = 12;\n\t\tspec->memImpedanceSpec.wdq_dyn_E = 13;\n\n        io_calc = std::make_unique<InterfaceCalculation_DDR5>(*spec);\n    }\n\n    std::unique_ptr<MemSpecDDR5> spec;\n    double t_CK;\n    double voltage;\n    std::unique_ptr<InterfaceCalculation_DDR5> io_calc;\n};\n\nTEST_F(DDR5_TogglingRateEnergy_Tests, DQ_Energy) {\n    SimulationStats stats;\n    stats.togglingStats = TogglingStats();\n    stats.togglingStats.read.ones = 7;\n    stats.togglingStats.read.zeroes = 11;\n    stats.togglingStats.read.zeroes_to_ones = 19;\n    stats.togglingStats.read.ones_to_zeroes = 39;\n\n    stats.togglingStats.write.ones = 43;\n    stats.togglingStats.write.zeroes = 59;\n    stats.togglingStats.write.zeroes_to_ones = 13;\n    stats.togglingStats.write.ones_to_zeroes = 17;\n\n    // Controller -> write power\n    // Dram -> read power\n    double expected_static_controller =\n        stats.togglingStats.write.zeroes * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.wdq_R_eq;\n    double expected_static_dram =\n        stats.togglingStats.read.zeroes * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.rdq_R_eq;\n\n    // Dynamic power is consumed on 0 -> 1 transition\n    double expected_dynamic_controller = stats.togglingStats.write.zeroes_to_ones *\n                           spec->memImpedanceSpec.wdq_dyn_E;\n    double expected_dynamic_dram = stats.togglingStats.read.zeroes_to_ones *\n                           spec->memImpedanceSpec.rdq_dyn_E;\n\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, expected_static_dram);\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, expected_dynamic_dram);\n}\n\nTEST_F(DDR5_TogglingRate_Tests, Pattern_1) {\n    // Setup toggling rate\n    double togglingRateRead = 0.7;\n    double togglingRateWrite = 0.3;\n    double dutyCycleRead = 0.6;\n    double dutyCycleWrite = 0.4;\n    TogglingRateIdlePattern idlePatternRead = TogglingRateIdlePattern::L;\n    TogglingRateIdlePattern idlePatternWrite = TogglingRateIdlePattern::H;\n\n    auto trd = ToggleRateDefinition {\n        togglingRateRead, // togglingRateRead\n        togglingRateWrite, // togglingRateWrite\n        dutyCycleRead, // dutyCycleRead\n        dutyCycleWrite, // dutyCycleWrite\n        idlePatternRead, // idlePatternRead\n        idlePatternWrite  // idlePatternWrite\n    };\n    initDDR(trd);\n\n    // Run commands\n    ddr->doCommand({0, CmdType::ACT, {1, 0, 0, 2}});\n    ddr->doCommand({5, CmdType::WR, {1, 0, 0, 0, 4}, wr_data, SZ_BITS(wr_data)});\n    ddr->doCommand({14, CmdType::RD, {1, 0, 0, 0, 4}, rd_data, SZ_BITS(rd_data)});\n    ddr->doCommand({23, CmdType::PRE, {1, 0, 0, 2}});\n    ddr->doCommand({30, CmdType::ACT, {1, 0, 0, 2}});\n    ddr->doCommand({35, CmdType::WR, {1, 0, 0, 0, 4}, nullptr, 16*8}); // burst length = 16\n    ddr->doCommand({44, CmdType::RD, {1, 0, 0, 0, 4}, nullptr, 16*8}); // burst length = 16\n    ddr->doCommand({53, CmdType::PRE, {1, 0, 0, 2}});\n    ddr->doCommand({56, CmdType::END_OF_SIMULATION});\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n// Toggling rate\n    uint64_t toggles_read = 2 * 16;\n    uint64_t idleread_ones = 0;\n    uint64_t idleread_zeroes = 2 * 56 - toggles_read; // TogglingRateIdlePattern::L\n\n    uint64_t toggles_write = 2 * 16;\n    uint64_t idlewrite_ones = 2 * 56 - toggles_write; // TogglingRateIdlePattern::H\n    uint64_t idlewrite_zeroes = 0;\n\n    // Read bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.ones, (idleread_ones +  static_cast<uint64_t>(std::floor(dutyCycleRead * toggles_read))) * spec->bitWidth); // 112\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes, (idleread_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleRead) * toggles_read))) * spec->bitWidth); // 296\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.ones_to_zeroes, std::floor((togglingRateRead / 2) * toggles_read) * spec->bitWidth); // 64\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateRead / 2) * toggles_read)) * spec->bitWidth); // 64\n    \n    // Write bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.ones, (idlewrite_ones +  static_cast<uint64_t>(std::floor(dutyCycleWrite * toggles_write))) * spec->bitWidth); // 256\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes, (idlewrite_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleWrite) * toggles_write))) * spec->bitWidth); // 152\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.ones_to_zeroes, std::floor((togglingRateWrite / 2) * toggles_write) * spec->bitWidth); // 32\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateWrite / 2) * toggles_write)) * spec->bitWidth); // 32\n\n// Data bus\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 0);\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.readBus.zeroes, 0);\n    EXPECT_EQ(stats.readBus.ones, 0);\n\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 0);\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.writeBus.zeroes, 0);\n    EXPECT_EQ(stats.writeBus.ones, 0);\n\n// Clock (see test_interface_ddr5)\n    EXPECT_EQ(stats.clockStats.zeroes_to_ones, 112);\n    EXPECT_EQ(stats.clockStats.ones_to_zeroes, 112);\n    EXPECT_EQ(stats.clockStats.zeroes, 112);\n    EXPECT_EQ(stats.clockStats.ones, 112);\n\n// Command bus (see test_interface_ddr5)\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 78);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 78);\n    EXPECT_EQ(stats.commandBus.zeroes, 108);\n    EXPECT_EQ(stats.commandBus.ones, 676);\n\n// DQs (see test_interface_ddr5)\n    EXPECT_EQ(stats.writeDQSStats.zeroes_to_ones, 32);\n    EXPECT_EQ(stats.writeDQSStats.ones_to_zeroes, 32);\n    EXPECT_EQ(stats.writeDQSStats.zeroes, 32);\n    EXPECT_EQ(stats.writeDQSStats.ones, 32);\n    EXPECT_EQ(stats.readDQSStats.zeroes_to_ones, 32);\n    EXPECT_EQ(stats.readDQSStats.ones_to_zeroes, 32);\n    EXPECT_EQ(stats.readDQSStats.zeroes, 32);\n    EXPECT_EQ(stats.readDQSStats.ones, 32);\n\n// PrePostamble\n    auto prepos = stats.rank_total[0].prepos;\n    EXPECT_EQ(prepos.readSeamless, 0);\n    EXPECT_EQ(prepos.writeSeamless, 0);\n    EXPECT_EQ(prepos.readMerged, 0);\n    EXPECT_EQ(prepos.readMergedTime, 0);\n    EXPECT_EQ(prepos.writeMerged, 0);\n    EXPECT_EQ(prepos.writeMergedTime, 0);\n}\n"
  },
  {
    "path": "tests/tests_drampower/interface/test_togglingrate_lpddr4.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <memory>\n#include <vector>\n#include <cmath>\n\n#include <DRAMUtils/config/toggling_rate.h>\n\n#include \"DRAMPower/standards/lpddr4/LPDDR4.h\"\n#include \"DRAMPower/memspec/MemSpecLPDDR4.h\"\n#include <DRAMPower/standards/test_accessor.h>\n#include \"DRAMPower/standards/lpddr4/interface_calculation_LPDDR4.h\"\n\n#include \"DRAMPower/data/energy.h\"\n#include \"DRAMPower/data/stats.h\"\n\nusing namespace DRAMPower;\nusing namespace DRAMUtils::Config;\n\n#define SZ_BITS(x) sizeof(x)*8\n\n// burst length = 16 for x8 devices\nstatic constexpr uint8_t wr_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 255,  0, 0, 0, 0,  0, 0, 0, 0,\n};\n\n// burst length = 16 for x8 devices\nstatic constexpr uint8_t rd_data[] = {\n    255, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,\n};\n\nclass LPDDR4_TogglingRate_Tests : public ::testing::Test {\n   public:\n\n    void SetUp() override {\n        test_patterns.push_back(\n        { // Pattern 1\n            {0, CmdType::ACT, {1, 0, 0, 2}},\n            {5, CmdType::WR, {1, 0, 0, 0, 16}, nullptr, datasize_bits},\n            {14, CmdType::RD, {1, 0, 0, 0, 16}, nullptr, datasize_bits},\n            {23, CmdType::PRE, {1, 0, 0, 2}},\n            {26, CmdType::END_OF_SIMULATION},\n        });\n        initSpec();\n    }\n\n    void initSpec() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        spec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*data));\n    }\n\n    void initDDR(const ToggleRateDefinition& trd) {\n        ddr = std::make_unique<LPDDR4>(*spec, config::SimConfig{trd});\n    }\n\n    void runCommands(const std::vector<Command> &commands) {\n        for (const Command &command : commands) {\n            ddr->doCoreCommand(command);\n            ddr->doInterfaceCommand(command);\n        }\n    }\n\n    std::vector<std::vector<Command>> test_patterns;\n    std::unique_ptr<MemSpecLPDDR4> spec;\n    std::unique_ptr<LPDDR4> ddr;\n    uint_fast16_t datasize_bits = 32 * 8; // 32 bytes\n};\n\nTEST_F(LPDDR4_TogglingRate_Tests, Pattern_0_LH) {\n    // Setup toggling rate\n    double togglingRateRead = 0.7;\n    double togglingRateWrite = 0.3;\n    double dutyCycleRead = 0.6;\n    double dutyCycleWrite = 0.4;\n    TogglingRateIdlePattern idlePatternRead = TogglingRateIdlePattern::L;\n    TogglingRateIdlePattern idlePatternWrite = TogglingRateIdlePattern::H;\n    auto trd = ToggleRateDefinition {\n        togglingRateRead, // togglingRateRead\n        togglingRateWrite, // togglingRateWrite\n        dutyCycleRead, // dutyCycleRead\n        dutyCycleWrite, // dutyCycleWrite\n        idlePatternRead, // idlePatternRead\n        idlePatternWrite  // idlePatternWrite\n    };\n    initDDR(trd);\n    // Run commands\n    runCommands(test_patterns.at(0));\n    // SZ_BITS: 256, width: 8 -> Burstlength: 32 (datarate bus)\n    // 0: ACT, 5: WR, 14: RD, 23: PRE, 26: EOS\n    // Read bus: idle: L\n        // 0 to 14 idle\n        // 14 to 26 toggle -> toggle cut off by EOS\n        // idle: 14 zeroes, toggle: 12 (datarate clock)\n        // idle: 28 zeroes, toggle: 24 (datarate bus)\n    // Write bus: idle: H\n        // 0 to 5 idle\n        // 5 to 21 toggle\n        // 21 to 26 idle\n        // idle: 10 ones, toggle: 16 (datarate clock)\n        // idle: 20 ones, toggle: 32 (datarate bus)\n    uint64_t toggles_read = 24;\n    uint64_t toggles_write = 32;\n\n    uint64_t idleread_ones = 0;\n    uint64_t idleread_zeroes = 28;\n    uint64_t idlewrite_ones = 20;\n    uint64_t idlewrite_zeroes = 0;\n\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n// Data bus\n    // Read bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.ones, (idleread_ones +  static_cast<uint64_t>(std::floor(dutyCycleRead * toggles_read))) * spec->bitWidth); // 112\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes, (idleread_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleRead) * toggles_read))) * spec->bitWidth); // 296\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.ones_to_zeroes, std::floor((togglingRateRead / 2) * toggles_read) * spec->bitWidth); // 64\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateRead / 2) * toggles_read)) * spec->bitWidth); // 64\n    \n    // Write bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.ones, (idlewrite_ones +  static_cast<uint64_t>(std::floor(dutyCycleWrite * toggles_write))) * spec->bitWidth); // 256\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes, (idlewrite_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleWrite) * toggles_write))) * spec->bitWidth); // 152\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.ones_to_zeroes, std::floor((togglingRateWrite / 2) * toggles_write) * spec->bitWidth); // 32\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateWrite / 2) * toggles_write)) * spec->bitWidth); // 32\n\n// Clock (see test_interface_lpddr4)\n    EXPECT_EQ(stats.clockStats.ones, 52);\n    EXPECT_EQ(stats.clockStats.zeroes, 52);\n    EXPECT_EQ(stats.clockStats.ones_to_zeroes, 52);\n    EXPECT_EQ(stats.clockStats.zeroes_to_ones, 52);\n\n// Command bus (see test_interface_lpddr4)\n    EXPECT_EQ(stats.commandBus.ones, 15);\n    EXPECT_EQ(stats.commandBus.zeroes, 141);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 14);\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 14);\n\n// DQs (see test_interface_lpddr4)\n    int number_of_cycles = (datasize_bits / spec->bitWidth);\n    uint_fast8_t scale = 1 * 2; // Differential_Pairs * 2(pairs of 2)\n    // f(t) = t / 2;\n    int DQS_ones = scale * (number_of_cycles / 2); // scale * (cycles / 2\n    int DQS_zeros = DQS_ones;\n    int DQS_zeros_to_ones = DQS_ones;\n    int DQS_ones_to_zeros = DQS_zeros;\n    EXPECT_EQ(stats.writeDQSStats.ones, DQS_ones);\n    EXPECT_EQ(stats.writeDQSStats.zeroes, DQS_zeros);\n    EXPECT_EQ(stats.writeDQSStats.ones_to_zeroes, DQS_zeros_to_ones);\n    EXPECT_EQ(stats.writeDQSStats.zeroes_to_ones, DQS_ones_to_zeros);\n    EXPECT_EQ(stats.readDQSStats.ones, DQS_ones);\n    EXPECT_EQ(stats.readDQSStats.zeroes, DQS_zeros);\n    EXPECT_EQ(stats.readDQSStats.ones_to_zeroes, DQS_zeros_to_ones);\n    EXPECT_EQ(stats.readDQSStats.zeroes_to_ones, DQS_ones_to_zeros);\n\n// PrePostamble\n    auto prepos = stats.rank_total[0].prepos;\n    EXPECT_EQ(prepos.readSeamless, 0);\n    EXPECT_EQ(prepos.writeSeamless, 0);\n    EXPECT_EQ(prepos.readMerged, 0);\n    EXPECT_EQ(prepos.readMergedTime, 0);\n    EXPECT_EQ(prepos.writeMerged, 0);\n    EXPECT_EQ(prepos.writeMergedTime, 0);\n}\n\nTEST_F(LPDDR4_TogglingRate_Tests, Pattern_0_HZ) {\n    // Setup toggling rate\n    double togglingRateRead = 0.7;\n    double togglingRateWrite = 0.3;\n    double dutyCycleRead = 0.6;\n    double dutyCycleWrite = 0.4;\n    TogglingRateIdlePattern idlePatternRead = TogglingRateIdlePattern::H;\n    TogglingRateIdlePattern idlePatternWrite = TogglingRateIdlePattern::Z;\n    auto trd = ToggleRateDefinition {\n        togglingRateRead, // togglingRateRead\n        togglingRateWrite, // togglingRateWrite\n        dutyCycleRead, // dutyCycleRead\n        dutyCycleWrite, // dutyCycleWrite\n        idlePatternRead, // idlePatternRead\n        idlePatternWrite  // idlePatternWrite\n    };\n    initDDR(trd);\n    // Run commands\n    runCommands(test_patterns[0]);\n    // SZ_BITS: 256, width: 8 -> Burstlength: 32 (datarate bus)\n    // 0: ACT, 5: WR, 14: RD, 23: PRE, 26: EOS\n    // Read bus: idle: H\n        // 0 to 14 idle\n        // 14 to 26 toggle -> toggle cut off by EOS\n        // idle: 14 ones, toggle: 12 (datarate clock)\n        // idle: 28 ones, toggle: 24 (datarate bus)\n    // Write bus: idle: H\n        // 0 to 5 idle\n        // 5 to 21 toggle\n        // 21 to 26 idle\n        // idle: 0 ones/zeroes, toggle: 16 (datarate clock)\n        // idle: 0 ones/zeroes, toggle: 32 (datarate bus)\n    uint64_t toggles_read = 24;\n    uint64_t toggles_write = 32;\n\n    uint64_t idleread_ones = 28;\n    uint64_t idleread_zeroes = 0;\n    uint64_t idlewrite_ones = 0;\n    uint64_t idlewrite_zeroes = 0;\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n// Data bus\n    // Read bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.ones, (idleread_ones +  static_cast<uint64_t>(std::floor(dutyCycleRead * toggles_read))) * spec->bitWidth); // 336\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes, (idleread_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleRead) * toggles_read))) * spec->bitWidth); // 72\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.ones_to_zeroes, std::floor((togglingRateRead / 2) * toggles_read) * spec->bitWidth); // 64\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateRead / 2) * toggles_read)) * spec->bitWidth); // 64\n    \n    // Write bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.ones, (idlewrite_ones +  static_cast<uint64_t>(std::floor(dutyCycleWrite * toggles_write))) * spec->bitWidth); // 96\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes, (idlewrite_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleWrite) * toggles_write))) * spec->bitWidth); // 152\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.ones_to_zeroes, std::floor((togglingRateWrite / 2) * toggles_write) * spec->bitWidth); // 32\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateWrite / 2) * toggles_write)) * spec->bitWidth); // 32\n}\n\n// Tests for power consumption (given a known SimulationStats)\nclass LPDDR4_TogglingRateEnergy_Tests : public ::testing::Test {\n   public:\n    LPDDR4_TogglingRateEnergy_Tests() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr4.json\");\n        spec = std::make_unique<DRAMPower::MemSpecLPDDR4>(DRAMPower::MemSpecLPDDR4::from_memspec(*data));\n\n        t_CK = spec->memTimingSpec.tCK;\n        voltage = spec->vddq;\n\n        // Change impedances to different values from each other\n\t\tspec->memImpedanceSpec.ca_R_eq = 2;\n        spec->memImpedanceSpec.ck_R_eq = 3;\n        spec->memImpedanceSpec.rdqs_R_eq = 4;\n        spec->memImpedanceSpec.wdqs_R_eq = 5;\n\t\tspec->memImpedanceSpec.rdq_R_eq = 6;\n\t\tspec->memImpedanceSpec.wdq_R_eq = 7;\n\n        spec->memImpedanceSpec.ca_dyn_E = 8;\n\t\tspec->memImpedanceSpec.ck_dyn_E = 9;\n\t\tspec->memImpedanceSpec.rdqs_dyn_E = 10;\n\t\tspec->memImpedanceSpec.wdqs_dyn_E = 11;\n\t\tspec->memImpedanceSpec.rdq_dyn_E = 12;\n\t\tspec->memImpedanceSpec.wdq_dyn_E = 13;\n\n        io_calc = std::make_unique<InterfaceCalculation_LPDDR4>(*spec);\n    }\n\n    std::unique_ptr<MemSpecLPDDR4> spec;\n    double t_CK;\n    double voltage;\n    std::unique_ptr<InterfaceCalculation_LPDDR4> io_calc;\n};\n\nTEST_F(LPDDR4_TogglingRateEnergy_Tests, DQ_Energy) {\n    // TODO implement test with new interface model\n    SimulationStats stats;\n    stats.togglingStats = TogglingStats();\n    stats.togglingStats.read.ones = 7;\n    stats.togglingStats.read.zeroes = 11;\n    stats.togglingStats.read.zeroes_to_ones = 19;\n    stats.togglingStats.read.ones_to_zeroes = 39;\n\n    stats.togglingStats.write.ones = 43;\n    stats.togglingStats.write.zeroes = 59;\n    stats.togglingStats.write.zeroes_to_ones = 13;\n    stats.togglingStats.write.ones_to_zeroes = 17;\n\n    // Controller -> write power\n    // Dram -> read power\n    double expected_static_controller =\n        stats.togglingStats.write.ones * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.wdq_R_eq;\n    double expected_static_dram =\n        stats.togglingStats.read.ones * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.rdq_R_eq;\n\n    // Dynamic power is consumed on 0 -> 1 transition\n    double expected_dynamic_controller = stats.togglingStats.write.zeroes_to_ones * spec->memImpedanceSpec.wdq_dyn_E;\n    double expected_dynamic_dram = stats.togglingStats.read.zeroes_to_ones * spec->memImpedanceSpec.rdq_dyn_E;\n\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, expected_static_dram);\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, expected_dynamic_dram);\n}\n\nTEST_F(LPDDR4_TogglingRate_Tests, Pattern_1) {\n    // Setup toggling rate\n    double togglingRateRead = 0.7;\n    double togglingRateWrite = 0.3;\n    double dutyCycleRead = 0.6;\n    double dutyCycleWrite = 0.4;\n    TogglingRateIdlePattern idlePatternRead = TogglingRateIdlePattern::L;\n    TogglingRateIdlePattern idlePatternWrite = TogglingRateIdlePattern::H;\n\n    auto trd = ToggleRateDefinition {\n        togglingRateRead, // togglingRateRead\n        togglingRateWrite, // togglingRateWrite\n        dutyCycleRead, // dutyCycleRead\n        dutyCycleWrite, // dutyCycleWrite\n        idlePatternRead, // idlePatternRead\n        idlePatternWrite  // idlePatternWrite\n    };\n    initDDR(trd);\n\n    // Run commands\n    ddr->doCommand({0, CmdType::ACT, {1, 0, 0, 2}});\n    ddr->doCommand({5, CmdType::WR, {1, 0, 0, 0, 16}, wr_data, SZ_BITS(wr_data)});\n    ddr->doCommand({14, CmdType::RD, {1, 0, 0, 0, 16}, rd_data, SZ_BITS(rd_data)});\n    ddr->doCommand({23, CmdType::PRE, {1, 0, 0, 2}});\n    ddr->doCommand({30, CmdType::ACT, {1, 0, 0, 2}});\n    ddr->doCommand({35, CmdType::WR, {1, 0, 0, 0, 16}, nullptr, 16*8}); // burst length = 16\n    ddr->doCommand({44, CmdType::RD, {1, 0, 0, 0, 16}, nullptr, 16*8}); // burst length = 16\n    ddr->doCommand({53, CmdType::PRE, {1, 0, 0, 2}});\n    ddr->doCommand({56, CmdType::END_OF_SIMULATION});\n\n\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n// Toggling rate\n    uint64_t toggles_read = 2 * 16;\n    uint64_t idleread_ones = 0;\n    uint64_t idleread_zeroes = 2 * 56 - toggles_read; // TogglingRateIdlePattern::L\n\n    uint64_t toggles_write = 2 * 16;\n    uint64_t idlewrite_ones = 2 * 56 - toggles_write; // TogglingRateIdlePattern::H\n    uint64_t idlewrite_zeroes = 0;\n\n    // Read bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.ones, (idleread_ones +  static_cast<uint64_t>(std::floor(dutyCycleRead * toggles_read))) * spec->bitWidth); // 112\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes, (idleread_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleRead) * toggles_read))) * spec->bitWidth); // 296\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.ones_to_zeroes, std::floor((togglingRateRead / 2) * toggles_read) * spec->bitWidth); // 64\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateRead / 2) * toggles_read)) * spec->bitWidth); // 64\n    \n    // Write bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.ones, (idlewrite_ones +  static_cast<uint64_t>(std::floor(dutyCycleWrite * toggles_write))) * spec->bitWidth); // 256\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes, (idlewrite_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleWrite) * toggles_write))) * spec->bitWidth); // 152\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.ones_to_zeroes, std::floor((togglingRateWrite / 2) * toggles_write) * spec->bitWidth); // 32\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateWrite / 2) * toggles_write)) * spec->bitWidth); // 32\n\n// Data bus\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 0);\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.readBus.zeroes, 0);\n    EXPECT_EQ(stats.readBus.ones, 0);\n\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 0);\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.writeBus.zeroes, 0);\n    EXPECT_EQ(stats.writeBus.ones, 0);\n\n// Clock (see test_interface_lpddr4)\n    EXPECT_EQ(stats.clockStats.zeroes_to_ones, 112);\n    EXPECT_EQ(stats.clockStats.ones_to_zeroes, 112);\n    EXPECT_EQ(stats.clockStats.zeroes, 112);\n    EXPECT_EQ(stats.clockStats.ones, 112);\n\n// Command bus (see test_interface_lpddr4)\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 28);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 28);\n    EXPECT_EQ(stats.commandBus.zeroes, 306);\n    EXPECT_EQ(stats.commandBus.ones, 30);\n\n// DQs (see test_interface_lpddr4)\n    EXPECT_EQ(stats.writeDQSStats.zeroes_to_ones, 32);\n    EXPECT_EQ(stats.writeDQSStats.ones_to_zeroes, 32);\n    EXPECT_EQ(stats.writeDQSStats.zeroes, 32);\n    EXPECT_EQ(stats.writeDQSStats.ones, 32);\n    EXPECT_EQ(stats.readDQSStats.zeroes_to_ones, 32);\n    EXPECT_EQ(stats.readDQSStats.ones_to_zeroes, 32);\n    EXPECT_EQ(stats.readDQSStats.zeroes, 32);\n    EXPECT_EQ(stats.readDQSStats.ones, 32);\n\n// PrePostamble\n    auto prepos = stats.rank_total[0].prepos;\n    EXPECT_EQ(prepos.readSeamless, 0);\n    EXPECT_EQ(prepos.writeSeamless, 0);\n    EXPECT_EQ(prepos.readMerged, 0);\n    EXPECT_EQ(prepos.readMergedTime, 0);\n    EXPECT_EQ(prepos.writeMerged, 0);\n    EXPECT_EQ(prepos.writeMergedTime, 0);\n}\n"
  },
  {
    "path": "tests/tests_drampower/interface/test_togglingrate_lpddr5.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <memory>\n#include <vector>\n#include <cmath>\n\n#include <DRAMUtils/config/toggling_rate.h>\n\n#include \"DRAMPower/standards/lpddr5/LPDDR5.h\"\n#include \"DRAMPower/memspec/MemSpecLPDDR5.h\"\n#include \"DRAMPower/standards/lpddr5/interface_calculation_LPDDR5.h\"\n\n#include \"DRAMPower/data/energy.h\"\n#include \"DRAMPower/data/stats.h\"\n\nusing namespace DRAMPower;\nusing namespace DRAMUtils::Config;\n\n#define SZ_BITS(x) sizeof(x)*8\n\n// burst length = 16 for x8 devices\nstatic constexpr uint8_t wr_data[] = {\n    0, 0, 0, 0,  0, 0, 0, 255,  0, 0, 0, 0,  0, 0, 0, 0,\n};\n\n// burst length = 16 for x8 devices\nstatic constexpr uint8_t rd_data[] = {\n    255, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,\n};\n\nclass LPDDR5_TogglingRate_Tests : public ::testing::Test {\n   public:\n\n    void SetUp() override {\n        test_patterns.push_back({\n            {0, CmdType::ACT, {1, 0, 0, 2}},\n            {3, CmdType::WR, {1, 0, 0, 0, 8}, nullptr, datasize_bits},\n            {12, CmdType::RD, {1, 0, 0, 0, 8}, nullptr, datasize_bits},\n            {21, CmdType::PRE, {1, 0, 0, 2}},\n            {24, CmdType::END_OF_SIMULATION},\n        });\n\n        initSpec();\n    }\n\n    void initSpec() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        spec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n    }\n\n    void initDDR(const ToggleRateDefinition& trd) {\n        ddr = std::make_unique<LPDDR5>(*spec, config::SimConfig{trd});\n    }\n\n    void runCommands(const std::vector<Command> &commands) {\n        for (const Command &command : commands) {\n            ddr->doCoreCommand(command);\n            ddr->doInterfaceCommand(command);\n        }\n    }\n\n    std::vector<std::vector<Command>> test_patterns;\n    std::unique_ptr<MemSpecLPDDR5> spec;\n    std::unique_ptr<LPDDR5> ddr;\n    uint_fast16_t datasize_bits = 32 * 8; // 32 bytes\n};\n\nTEST_F(LPDDR5_TogglingRate_Tests, Pattern_0_LH) {\n    // Setup toggling rate\n    double togglingRateRead = 0.7;\n    double togglingRateWrite = 0.3;\n    double dutyCycleRead = 0.6;\n    double dutyCycleWrite = 0.4;\n    TogglingRateIdlePattern idlePatternRead = TogglingRateIdlePattern::L;\n    TogglingRateIdlePattern idlePatternWrite = TogglingRateIdlePattern::H;\n    auto trd = ToggleRateDefinition {\n        togglingRateRead, // togglingRateRead\n        togglingRateWrite, // togglingRateWrite\n        dutyCycleRead, // dutyCycleRead\n        dutyCycleWrite, // dutyCycleWrite\n        idlePatternRead, // idlePatternRead\n        idlePatternWrite  // idlePatternWrite\n    };\n    initDDR(trd);\n    // Run commands\n    runCommands(test_patterns.at(0));\n    // SZ_BITS: 256, width: 8 -> Burstlength: 32  (datarate bus)\n    // 0: ACT, 3: WR, 12: RD, 21: PRE, 24: EOS\n    // Read bus: idle: L\n        // 0 to 12 idle\n        // 12 to 24 toggle -> toggle cut off by EOS\n        // idle: 12 zeroes, toggle: 12 (datarate clock)\n        // idle: 24 zeroes, toggle: 24 (datarate bus)\n    // Write bus: idle: H\n        // 0 to 3 idle\n        // 3 to 19 toggle\n        // 19 to 24 idle\n        // idle: 8 ones, toggle: 16 (datarate clock)\n        // idle: 16 ones, toggle: 32 (datarate bus)\n    uint64_t toggles_read = 24;\n    uint64_t toggles_write = 32;\n\n    uint64_t idleread_ones = 0;\n    uint64_t idleread_zeroes = 24;\n    uint64_t idlewrite_ones = 16;\n    uint64_t idlewrite_zeroes = 0;\n\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n// Data bus\n    // Read bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.ones, (idleread_ones +  static_cast<uint64_t>(std::floor(dutyCycleRead * toggles_read))) * spec->bitWidth); // 112\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes, (idleread_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleRead) * toggles_read))) * spec->bitWidth); // 264\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.ones_to_zeroes, std::floor((togglingRateRead / 2) * toggles_read) * spec->bitWidth); // 64\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateRead / 2) * toggles_read)) * spec->bitWidth); // 64\n    \n    // Write bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.ones, (idlewrite_ones +  static_cast<uint64_t>(std::floor(dutyCycleWrite * toggles_write))) * spec->bitWidth); // 224\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes, (idlewrite_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleWrite) * toggles_write))) * spec->bitWidth); // 152\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.ones_to_zeroes, std::floor((togglingRateWrite / 2) * toggles_write) * spec->bitWidth); // 32\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateWrite / 2) * toggles_write)) * spec->bitWidth); // 32\n\n// Clock (see test_interface_lpddr5)\n    EXPECT_EQ(stats.clockStats.ones, 48);\n    EXPECT_EQ(stats.clockStats.zeroes, 48);\n    EXPECT_EQ(stats.clockStats.ones_to_zeroes, 48);\n    EXPECT_EQ(stats.clockStats.zeroes_to_ones, 48);\n\n// Command bus (see test_interface_lpddr5)\n    EXPECT_EQ(stats.commandBus.ones, 19);\n    EXPECT_EQ(stats.commandBus.zeroes, 317);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 15);\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 15);\n\n// DQs (see test_interface_lpddr5)\n    int number_of_cycles = (datasize_bits / spec->bitWidth);\n    uint_fast8_t scale = 1 * 2; // Differential_Pairs * 2(pairs of 2)\n    // f(t) = t / 2;\n    int DQS_ones = scale * (number_of_cycles / 2); // scale * (cycles / 2)\n    int DQS_zeros = DQS_ones;\n    int DQS_zeros_to_ones = DQS_ones;\n    int DQS_ones_to_zeros = DQS_zeros;\n    EXPECT_EQ(stats.readDQSStats.ones, DQS_ones);\n    EXPECT_EQ(stats.readDQSStats.zeroes, DQS_zeros);\n    EXPECT_EQ(stats.readDQSStats.ones_to_zeroes, DQS_zeros_to_ones);\n    EXPECT_EQ(stats.readDQSStats.zeroes_to_ones, DQS_ones_to_zeros);\n\n// PrePostamble\n    auto prepos = stats.rank_total[0].prepos;\n    EXPECT_EQ(prepos.readSeamless, 0);\n    EXPECT_EQ(prepos.writeSeamless, 0);\n    EXPECT_EQ(prepos.readMerged, 0);\n    EXPECT_EQ(prepos.readMergedTime, 0);\n    EXPECT_EQ(prepos.writeMerged, 0);\n    EXPECT_EQ(prepos.writeMergedTime, 0);\n}\n\nTEST_F(LPDDR5_TogglingRate_Tests, Pattern_0_HZ) {\n    // Setup toggling rate\n    double togglingRateRead = 0.7;\n    double togglingRateWrite = 0.3;\n    double dutyCycleRead = 0.6;\n    double dutyCycleWrite = 0.4;\n    TogglingRateIdlePattern idlePatternRead = TogglingRateIdlePattern::H;\n    TogglingRateIdlePattern idlePatternWrite = TogglingRateIdlePattern::Z;\n    auto trd = ToggleRateDefinition {\n        togglingRateRead, // togglingRateRead\n        togglingRateWrite, // togglingRateWrite\n        dutyCycleRead, // dutyCycleRead\n        dutyCycleWrite, // dutyCycleWrite\n        idlePatternRead, // idlePatternRead\n        idlePatternWrite  // idlePatternWrite\n    };\n    \n    initDDR(trd);\n    // Run commands\n    runCommands(test_patterns[0]);\n    // SZ_BITS: 256, width: 8 -> Burstlength: 32  (datarate bus)\n    // 0: ACT, 3: WR, 12: RD, 21: PRE, 24: EOS\n    // Read bus: idle: H\n        // 0 to 12 idle\n        // 12 to 24 toggle -> toggle cut off by EOS\n        // idle: 12 ones, toggle: 12 (datarate clock)\n        // idle: 24 ones, toggle: 24 (datarate bus)\n    // Write bus: idle: Z\n        // 0 to 3 idle\n        // 3 to 19 toggle\n        // 19 to 24 idle\n        // idle: 0 ones/zeroes, toggle: 16 (datarate clock)\n        // idle: 0 ones/zeroes, toggle: 32 (datarate bus)\n    uint64_t toggles_read = 24;\n    uint64_t toggles_write = 32;\n\n    uint64_t idleread_ones = 24;\n    uint64_t idleread_zeroes = 0;\n    uint64_t idlewrite_ones = 0;\n    uint64_t idlewrite_zeroes = 0;\n\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n// Data bus\n    // Read bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.ones, (idleread_ones +  static_cast<uint64_t>(std::floor(dutyCycleRead * toggles_read))) * spec->bitWidth); // 304\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes, (idleread_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleRead) * toggles_read))) * spec->bitWidth); // 72\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.ones_to_zeroes, std::floor((togglingRateRead / 2) * toggles_read) * spec->bitWidth); // 64\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateRead / 2) * toggles_read)) * spec->bitWidth); // 64\n    \n    // Write bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.ones, (idlewrite_ones +  static_cast<uint64_t>(std::floor(dutyCycleWrite * toggles_write))) * spec->bitWidth); // 96\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes, (idlewrite_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleWrite) * toggles_write))) * spec->bitWidth); // 152\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.ones_to_zeroes, std::floor((togglingRateWrite / 2) * toggles_write) * spec->bitWidth); // 32\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateWrite / 2) * toggles_write)) * spec->bitWidth); // 32\n}\n\n// Tests for power consumption (given a known SimulationStats)\nclass LPDDR5_TogglingRateEnergy_Tests : public ::testing::Test {\n   public:\n    LPDDR5_TogglingRateEnergy_Tests() {\n        auto data = DRAMUtils::parse_memspec_from_file(std::filesystem::path(TEST_RESOURCE_DIR) / \"lpddr5.json\");\n        spec = std::make_unique<DRAMPower::MemSpecLPDDR5>(DRAMPower::MemSpecLPDDR5::from_memspec(*data));\n\n        t_CK = spec->memTimingSpec.tCK;\n        voltage = spec->vddq;\n\n        // Change impedances to different values from each other\n\t\tspec->memImpedanceSpec.ca_R_eq = 2;\n        spec->memImpedanceSpec.ck_R_eq = 3;\n        spec->memImpedanceSpec.rdqs_R_eq = 4;\n        spec->memImpedanceSpec.wck_R_eq = 5;\n\t\tspec->memImpedanceSpec.rdq_R_eq = 6;\n\t\tspec->memImpedanceSpec.wdq_R_eq = 7;\n\n        spec->memImpedanceSpec.ca_dyn_E = 8;\n\t\tspec->memImpedanceSpec.ck_dyn_E = 9;\n\t\tspec->memImpedanceSpec.rdqs_dyn_E = 10;\n\t\tspec->memImpedanceSpec.wck_dyn_E = 11;\n\t\tspec->memImpedanceSpec.rdq_dyn_E = 12;\n\t\tspec->memImpedanceSpec.wdq_dyn_E = 13;\n\n        io_calc = std::make_unique<InterfaceCalculation_LPDDR5>(*spec);\n    }\n\n    std::unique_ptr<MemSpecLPDDR5> spec;\n    double t_CK;\n    double voltage;\n    std::unique_ptr<InterfaceCalculation_LPDDR5> io_calc;\n};\n\nTEST_F(LPDDR5_TogglingRateEnergy_Tests, DQ_Energy) {\n    SimulationStats stats;\n    stats.togglingStats = TogglingStats();\n    stats.togglingStats.read.ones = 7;\n    stats.togglingStats.read.zeroes = 11;\n    stats.togglingStats.read.zeroes_to_ones = 19;\n    stats.togglingStats.read.ones_to_zeroes = 39;\n\n    stats.togglingStats.write.ones = 43;\n    stats.togglingStats.write.zeroes = 59;\n    stats.togglingStats.write.zeroes_to_ones = 13;\n    stats.togglingStats.write.ones_to_zeroes = 17;\n\n    // Controller -> write power\n    // Dram -> read power\n    double expected_static_controller =\n        stats.togglingStats.write.ones * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.wdq_R_eq;\n    double expected_static_dram =\n        stats.togglingStats.read.ones * voltage * voltage * (0.5 * t_CK) / spec->memImpedanceSpec.rdq_R_eq;\n\n    // Dynamic power is consumed on 0 -> 1 transition\n    double expected_dynamic_controller = stats.togglingStats.write.zeroes_to_ones *\n                            spec->memImpedanceSpec.wdq_dyn_E;\n    double expected_dynamic_dram = stats.togglingStats.read.zeroes_to_ones *\n                            spec->memImpedanceSpec.rdq_dyn_E;\n\n    interface_energy_info_t result = io_calc->calculateEnergy(stats);\n    EXPECT_DOUBLE_EQ(result.controller.staticEnergy, expected_static_controller);\n    EXPECT_DOUBLE_EQ(result.controller.dynamicEnergy, expected_dynamic_controller);\n    EXPECT_DOUBLE_EQ(result.dram.staticEnergy, expected_static_dram);\n    EXPECT_DOUBLE_EQ(result.dram.dynamicEnergy, expected_dynamic_dram);\n}\n\nTEST_F(LPDDR5_TogglingRate_Tests, Pattern_1) {\n    // Setup toggling rate\n    double togglingRateRead = 0.7;\n    double togglingRateWrite = 0.3;\n    double dutyCycleRead = 0.6;\n    double dutyCycleWrite = 0.4;\n    TogglingRateIdlePattern idlePatternRead = TogglingRateIdlePattern::L;\n    TogglingRateIdlePattern idlePatternWrite = TogglingRateIdlePattern::H;\n    auto trd = ToggleRateDefinition {\n        togglingRateRead, // togglingRateRead\n        togglingRateWrite, // togglingRateWrite\n        dutyCycleRead, // dutyCycleRead\n        dutyCycleWrite, // dutyCycleWrite\n        idlePatternRead, // idlePatternRead\n        idlePatternWrite  // idlePatternWrite\n    };\n    \n    initDDR(trd);\n    // Run commands\n    ddr->doCommand({0, CmdType::ACT, {1, 0, 0, 2}});\n    ddr->doCommand({5, CmdType::WR, {1, 0, 0, 0, 8}, wr_data, SZ_BITS(wr_data)});\n    ddr->doCommand({14, CmdType::RD, {1, 0, 0, 0, 8}, rd_data, SZ_BITS(rd_data)});\n    ddr->doCommand({23, CmdType::PRE, {1, 0, 0, 2}});\n    ddr->doCommand({30, CmdType::ACT, {1, 0, 0, 2}});\n    ddr->doCommand({35, CmdType::WR, {1, 0, 0, 0, 8}, nullptr, 16*8}); // burst length = 16\n    ddr->doCommand({44, CmdType::RD, {1, 0, 0, 0, 8}, nullptr, 16*8}); // burst length = 16\n    ddr->doCommand({53, CmdType::PRE, {1, 0, 0, 2}});\n    ddr->doCommand({56, CmdType::END_OF_SIMULATION});\n\n    SimulationStats stats = ddr->getStats();\n\n    EXPECT_EQ(spec->dataRate, 2);\n\n// Toggling rate\n    uint64_t toggles_read = 2 * 16;\n    uint64_t idleread_ones = 0;\n    uint64_t idleread_zeroes = 2 * 56 - toggles_read; // TogglingRateIdlePattern::L\n\n    uint64_t toggles_write = 2 * 16;\n    uint64_t idlewrite_ones = 2 * 56 - toggles_write; // TogglingRateIdlePattern::H\n    uint64_t idlewrite_zeroes = 0;\n\n    // Read bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.ones, (idleread_ones +  static_cast<uint64_t>(std::floor(dutyCycleRead * toggles_read))) * spec->bitWidth); // 112\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes, (idleread_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleRead) * toggles_read))) * spec->bitWidth); // 296\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.ones_to_zeroes, std::floor((togglingRateRead / 2) * toggles_read) * spec->bitWidth); // 64\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.read.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateRead / 2) * toggles_read)) * spec->bitWidth); // 64\n    \n    // Write bus\n    // ones: {idle + floor[duty_cycle * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.ones, (idlewrite_ones +  static_cast<uint64_t>(std::floor(dutyCycleWrite * toggles_write))) * spec->bitWidth); // 256\n    // zeroes: {idle + floor[(1 - duty_cycle) * toggling_count]} * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes, (idlewrite_zeroes +  static_cast<uint64_t>(std::floor((1 - dutyCycleWrite) * toggles_write))) * spec->bitWidth); // 152\n    // onestozeroes: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.ones_to_zeroes, std::floor((togglingRateWrite / 2) * toggles_write) * spec->bitWidth); // 32\n    // zeroestoones: floor[(toggle_rate / 2) * toggling_count] * width\n    EXPECT_EQ(stats.togglingStats.write.zeroes_to_ones,  static_cast<uint64_t>(std::floor((togglingRateWrite / 2) * toggles_write)) * spec->bitWidth); // 32\n\n// Data bus\n    EXPECT_EQ(stats.readBus.zeroes_to_ones, 0);\n    EXPECT_EQ(stats.readBus.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.readBus.zeroes, 0);\n    EXPECT_EQ(stats.readBus.ones, 0);\n\n    EXPECT_EQ(stats.writeBus.zeroes_to_ones, 0);\n    EXPECT_EQ(stats.writeBus.ones_to_zeroes, 0);\n    EXPECT_EQ(stats.writeBus.zeroes, 0);\n    EXPECT_EQ(stats.writeBus.ones, 0);\n\n// Clock (see test_interface_lpddr5)\n    EXPECT_EQ(stats.clockStats.zeroes_to_ones, 112);\n    EXPECT_EQ(stats.clockStats.ones_to_zeroes, 112);\n    EXPECT_EQ(stats.clockStats.zeroes, 112);\n    EXPECT_EQ(stats.clockStats.ones, 112);\n\n// Command bus (see test_interface_lpddr5)\n    EXPECT_EQ(stats.commandBus.zeroes_to_ones, 30);\n    EXPECT_EQ(stats.commandBus.ones_to_zeroes, 30);\n    EXPECT_EQ(stats.commandBus.zeroes, 746);\n    EXPECT_EQ(stats.commandBus.ones, 38);\n\n// DQs (see test_interface_lpddr5)\n    EXPECT_EQ(stats.readDQSStats.zeroes_to_ones, 32);\n    EXPECT_EQ(stats.readDQSStats.ones_to_zeroes, 32);\n    EXPECT_EQ(stats.readDQSStats.zeroes, 32);\n    EXPECT_EQ(stats.readDQSStats.ones, 32);\n\n// PrePostamble\n    auto prepos = stats.rank_total[0].prepos;\n    EXPECT_EQ(prepos.readSeamless, 0);\n    EXPECT_EQ(prepos.writeSeamless, 0);\n    EXPECT_EQ(prepos.readMerged, 0);\n    EXPECT_EQ(prepos.readMergedTime, 0);\n    EXPECT_EQ(prepos.writeMerged, 0);\n    EXPECT_EQ(prepos.writeMergedTime, 0);\n}\n"
  },
  {
    "path": "tests/tests_drampower/resources/cliconfig.json",
    "content": "{\n    \"useToggleRate\": true,\n    \"simconfig\": {\n        \"toggleRateDefinition\": {\n            \"togglingRateRead\": 0.5,\n            \"togglingRateWrite\": 0.5,\n            \"dutyCycleRead\": 0.5,\n            \"dutyCycleWrite\": 0.5,\n            \"idlePatternRead\": \"L\",\n            \"idlePatternWrite\": \"L\"\n        }\n    }\n}\n"
  },
  {
    "path": "tests/tests_drampower/resources/ddr4.csv",
    "content": "0 ,ACT,0,0,0,0,0\n15,WR,0,0,0,0,0,0x0102030405060708\n20,RD,0,0,0,0,0,0102030405060708\n40,PRE,0,0,0,0,0\n45,END,0,0,0,0,0"
  },
  {
    "path": "tests/tests_drampower/resources/ddr4.json",
    "content": "{\n  \"memspec\": {\n    \"memoryId\": \"ddr4\",\n    \"memoryType\": \"DDR4\",\n    \"memarchitecturespec\": {\n      \"nbrOfChannels\": 0,\n      \"nbrOfColumns\": 1024,\n      \"nbrOfRows\": 65536,\n      \"width\": 8,\n      \"burstLength\": 8,\n      \"maxBurstLength\": 8,\n      \"dataRate\": 2,\n      \"nbrOfBankGroups\": 2,\n      \"nbrOfBanks\": 16,\n      \"nbrOfRanks\": 1,\n      \"nbrOfDevices\": 1,\n      \"RefMode\": 1\n    },\n    \"mempowerspec\": {\n      \"vdd\": 1.2,\n      \"idd0\": 56.25e-3,\n      \"idd2n\": 33.75e-3,\n      \"idd3n\": 39.5e-3,\n      \"idd4r\": 157.5e-3,\n      \"idd4w\": 135.0e-3,\n      \"idd6n\": 20.20e-3,\n      \"idd2p\": 17.0e-3,\n      \"idd3p\": 22.5e-3,\n      \"idd5B\": 118.0e-3,\n      \"idd5F2\": 118.0e-3,\n      \"idd5F4\": 118.0e-3,\n      \"vpp\": 1.2,\n      \"ipp0\": 0,\n      \"ipp2n\": 0,\n      \"ipp3n\": 0,\n      \"ipp4r\": 0,\n      \"ipp4w\": 0,\n      \"ipp6n\": 0,\n      \"ipp2p\": 0,\n      \"ipp3p\": 0,\n      \"ipp5B\": 0,\n      \"ipp5F2\": 0,\n      \"ipp5F4\": 0,\n      \"vddq\": 1.2,\n      \"iBeta_vdd\": 56.25e-3,\n      \"iBeta_vpp\": 0\n    },\n    \"memtimingspec\": {\n      \"tCK\": 0.76923076923076923076923076923077e-9,\n      \"CKE\": 0,\n      \"CKESR\": 0,\n      \"RAS\": 10,\n      \"RC\": 0,\n      \"RCD\": 13,\n      \"RL\": 0,\n      \"RPRE\": 0,\n      \"RTP\": 5,\n      \"WL\": 5,\n      \"WPRE\": 0,\n      \"WR\": 5,\n      \"XP\": 0,\n      \"XS\": 0,\n      \"REFM\": 0,\n      \"REFI\": 0,\n      \"RFC1\": 25,\n      \"RFC2\": 0,\n      \"RFC4\": 0,\n      \"RP\": 10,\n      \"DQSCK\": 0,\n      \"CCD_S\": 0,\n      \"CCD_L\": 0,\n      \"FAW\": 0,\n      \"RRD_S\": 0,\n      \"RRD_L\": 0,\n      \"WTR_S\": 0,\n      \"WTR_L\": 0,\n      \"XPDLL\": 0,\n      \"XSDLL\": 0,\n      \"AL\": 0,\n      \"ACTPDEN\": 0,\n      \"PRPDEN\": 0,\n      \"REFPDEN\": 0,\n      \"RTRS\": 0\n    },\n    \"bankwisespec\":{\n      \"factRho\":0.5\n    },\n    \"memimpedancespec\": {\n      \"ck_termination\": true,\n      \"ck_R_eq\": 1e6,\n      \"ck_dyn_E\": 1e-12,\n\n      \"ca_termination\": true,\n      \"ca_R_eq\": 1e6,\n      \"ca_dyn_E\": 1e-12,\n\n      \"rdq_termination\": true,\n      \"rdq_R_eq\": 1e6,\n      \"rdq_dyn_E\": 1e-12,\n      \"wdq_termination\": true,\n      \"wdq_R_eq\": 1e6,\n      \"wdq_dyn_E\": 1e-12,\n\n      \"wdqs_termination\": true,\n      \"wdqs_R_eq\": 1e6,\n      \"wdqs_dyn_E\": 1e-12,\n      \"rdqs_termination\": true,\n      \"rdqs_R_eq\": 1e6,\n      \"rdqs_dyn_E\": 1e-12,\n\n      \"wdbi_termination\": true,\n      \"wdbi_R_eq\": 1e6,\n      \"wdbi_dyn_E\": 1e-12,\n      \"rdbi_termination\": true,\n      \"rdbi_R_eq\": 1e6,\n      \"rdbi_dyn_E\": 1e-12\n    },\n    \"prepostamble\":{\n      \"read_zeroes\": 2.5,\n      \"write_zeroes\": 2.5,\n      \"read_ones\": 2.5,\n      \"write_ones\": 2.5,\n      \"read_zeroes_to_ones\": 2,\n      \"write_zeroes_to_ones\": 2,\n      \"read_ones_to_zeroes\": 2,\n      \"write_ones_to_zeroes\": 2,\n      \"readMinTccd\": 3,\n      \"writeMinTccd\": 3\n    }\n  }\n}\n\n\n"
  },
  {
    "path": "tests/tests_drampower/resources/ddr5.csv",
    "content": "0 ,ACT,0,0,0,0,0\n15,PRE,0,0,0,0,0\n15,END,0,0,0,0,0"
  },
  {
    "path": "tests/tests_drampower/resources/ddr5.json",
    "content": "{\n  \"memspec\": {\n    \"memoryId\": \"ddr5\",\n    \"memoryType\": \"DDR5\",\n    \"memarchitecturespec\": {\n      \"nbrOfChannels\": 0,\n      \"nbrOfColumns\": 1024,\n      \"nbrOfRows\": 65536,\n      \"width\": 8,\n      \"burstLength\": 8,\n      \"maxBurstLength\": 8,\n      \"dataRate\": 2,\n      \"nbrOfBankGroups\": 2,\n      \"nbrOfBanks\": 16,\n      \"nbrOfRanks\": 1,\n      \"nbrOfDevices\": 1,\n      \"nbrOfDIMMRanks\": 0,\n      \"nbrOfPhysicalRanks\": 0,\n      \"nbrOfLogicalRanks\": 0,\n      \"cmdMode\": 0,\n      \"RefMode\": 1,\n      \"RAAIMT\": 0,\n      \"RAAMMT\": 0,\n      \"RAADEC\": 0\n    },\n    \"mempowerspec\": {\n      \"vdd\": 1.2,\n      \"idd0\": 56.25e-3,\n      \"idd2n\": 33.75e-3,\n      \"idd3n\": 39.5e-3,\n      \"idd4r\": 157.5e-3,\n      \"idd4w\": 135.0e-3,\n      \"idd5b\": 118.0e-3,\n      \"idd5c\": 110.0e-3,\n      \"idd5f\": 135.0e-3,\n      \"idd6n\": 20.25e-3,\n      \"idd2p\": 17.0e-3,\n      \"idd3p\": 22.5e-3,\n      \"vpp\": 1.2,\n      \"ipp0\": 0,\n      \"ipp2n\": 0,\n      \"ipp3n\": 0,\n      \"ipp4r\": 0,\n      \"ipp4w\": 0,\n      \"ipp5b\": 0,\n      \"ipp5c\": 0,\n      \"ipp5f\": 0,\n      \"ipp6n\": 0,\n      \"ipp2p\": 0,\n      \"ipp3p\": 0,\n      \"vddq\": 1.1,\n      \"iBeta_vdd\": 56.25e-3,\n      \"iBeta_vpp\": 0\n    },\n    \"memtimingspec\": {\n      \"tCK\": 0.76923076923076923076923076923077e-9,\n      \"RAS\": 10,\n      \"RCD\": 13,\n      \"RTP\": 5,\n      \"WL\": 5,\n      \"WR\": 5,\n      \"RP\": 10,\n      \"RFCsb\": 20,\n      \"RFC1\": 25,\n      \"RFC2\": 30,\n      \"PPD\": 0,\n      \"RL\": 0,\n      \"RPRE\": 0,\n      \"RPST\": 0,\n      \"RDDQS\": 0,\n      \"WPRE\": 0,\n      \"WPST\": 0,\n      \"CCD_L_slr\": 0,\n      \"CCD_L_WR_slr\": 0,\n      \"CCD_L_WR2_slr\": 0,\n      \"CCD_M_slr\": 0,\n      \"CCD_M_WR_slr\": 0,\n      \"CCD_S_slr\": 0,\n      \"CCD_S_WR_slr\": 0,\n      \"CCD_dlr\": 0,\n      \"CCD_WR_dlr\": 0,\n      \"CCD_WR_dpr\": 0,\n      \"RRD_L_slr\": 0,\n      \"RRD_S_slr\": 0,\n      \"RRD_dlr\": 0,\n      \"FAW_slr\": 0,\n      \"FAW_dlr\": 0,\n      \"WTR_L\": 0,\n      \"WTR_M\": 0,\n      \"WTR_S\": 0,\n      \"RFC1_slr\": 25,\n      \"RFC2_slr\": 30,\n      \"RFC1_dlr\": 0,\n      \"RFC2_dlr\": 0,\n      \"RFC1_dpr\": 0,\n      \"RFC2_dpr\": 0,\n      \"RFCsb_slr\": 20,\n      \"RFCsb_dlr\": 0,\n      \"REFI1\": 0,\n      \"REFI2\": 0,\n      \"REFISB\": 0,\n      \"REFSBRD_slr\": 0,\n      \"REFSBRD_dlr\": 0,\n      \"RTRS\": 0,\n      \"CPDED\": 0,\n      \"PD\": 0,\n      \"XP\": 0,\n      \"ACTPDEN\": 0,\n      \"PRPDEN\": 0,\n      \"REFPDEN\": 0\n    },\n    \"bankwisespec\":{\n      \"factRho\":0.5\n    },\n    \"memimpedancespec\": {\n      \"ck_termination\": true,\n      \"ck_R_eq\": 1e6,\n      \"ck_dyn_E\": 1e-12,\n\n      \"ca_termination\": true,\n      \"ca_R_eq\": 1e6,\n      \"ca_dyn_E\": 1e-12,\n\n      \"rdq_termination\": true,\n      \"rdq_R_eq\": 1e6,\n      \"rdq_dyn_E\": 1e-12,\n      \"wdq_termination\": true,\n      \"wdq_R_eq\": 1e6,\n      \"wdq_dyn_E\": 1e-12,\n\n      \"wdqs_termination\": true,\n      \"wdqs_R_eq\": 1e6,\n      \"wdqs_dyn_E\": 1e-12,\n      \"rdqs_termination\": true,\n      \"rdqs_R_eq\": 1e6,\n      \"rdqs_dyn_E\": 1e-12\n    },\n    \"dataratespec\": {\n        \"ca_bus_rate\": 2,\n        \"dq_bus_rate\": 2,\n        \"dqs_bus_rate\": 2\n    }\n  }\n}\n"
  },
  {
    "path": "tests/tests_drampower/resources/lpddr4.csv",
    "content": "0 ,ACT,0,0,0,0,0\n15,PRE,0,0,0,0,0\n15,END,0,0,0,0,0"
  },
  {
    "path": "tests/tests_drampower/resources/lpddr4.json",
    "content": "{\n  \"memspec\": {\n    \"memoryId\": \"lpddr4\",\n    \"memoryType\": \"LPDDR4\",\n    \"memarchitecturespec\": {\n      \"nbrOfChannels\": 0,\n      \"nbrOfColumns\": 1024,\n      \"nbrOfRows\": 65536,\n      \"width\": 8,\n      \"burstLength\": 8,\n      \"maxBurstLength\": 8,\n      \"dataRate\": 2,\n      \"nbrOfBankGroups\": 1,\n      \"nbrOfBanks\": 16,\n      \"nbrOfRanks\": 1,\n      \"nbrOfDevices\": 1\n    },\n    \"mempowerspec\": {\n      \"vdd1\": 1.2,\n      \"idd01\": 56.25e-3,\n      \"idd2n1\": 33.75e-3,\n      \"idd3n1\": 35e-3,\n      \"idd4r1\": 157.5e-3,\n      \"idd4w1\": 135.0e-3,\n      \"idd51\": 118.0e-3,\n      \"idd5pb1\": 74.0e-3,\n      \"idd61\": 20.25e-3,\n      \"idd2p1\": 17.0e-3,\n      \"idd3p1\": 22.5e-3,\n      \"vdd2\": 1.2,\n      \"idd02\": 0,\n      \"idd2n2\": 0,\n      \"idd3n2\": 0,\n      \"idd4r2\": 0,\n      \"idd4w2\": 0,\n      \"idd52\": 0,\n      \"idd5pb2\": 0,\n      \"idd62\": 0,\n      \"idd2p2\": 0,\n      \"idd3p2\": 0,\n      \"vddq\": 1.2,\n      \"iBeta_vdd1\": 56.25e-3,\n      \"iBeta_vdd2\": 0\n    },\n    \"memtimingspec\": {\n      \"tCK\": 0.76923076923076923076923076923077e-9,\n      \"CKE\": 0,\n      \"ESCKE\": 0,\n      \"CMDCKE\": 0,\n      \"RAS\": 10,\n      \"RCD\": 13,\n      \"RL\": 0,\n      \"REFM\": 0,\n      \"REFI\": 20,\n      \"REFIpb\": 0,\n      \"RFCpb\": 20,\n      \"RFCab\": 25,\n      \"RPpb\": 10,\n      \"RPab\": 0,\n      \"RCpb\": 0,\n      \"RCab\": 0,\n      \"PPD\": 0,\n      \"FAW\": 0,\n      \"RRD\": 0,\n      \"CCD\": 0,\n      \"CCDMW\": 0,\n      \"RPST\": 0,\n      \"DQSCK\": 0,\n      \"RTP\": 2,\n      \"WL\": 5,\n      \"DQSS\": 0,\n      \"DQS2DQ\": 0,\n      \"WR\": 5,\n      \"WPRE\": 0,\n      \"WTR\": 0,\n      \"XP\": 0,\n      \"SR\": 0,\n      \"XSR\": 0,\n      \"RTRS\": 0\n    },\n    \"bankwisespec\":{\n      \"factRho\":0.5,\n      \"factSigma\": 1.0,\n      \"pasrMode\": 0,\n      \"hasPASR\": false\n    },\n    \"memimpedancespec\": {\n      \"ck_termination\": true,\n      \"ck_R_eq\": 1e6,\n      \"ck_dyn_E\": 1e-12,\n\n      \"ca_termination\": true,\n      \"ca_R_eq\": 1e6,\n      \"ca_dyn_E\": 1e-12,\n\n      \"rdq_termination\": true,\n      \"rdq_R_eq\": 1e6,\n      \"rdq_dyn_E\": 1e-12,\n      \"wdq_termination\": true,\n      \"wdq_R_eq\": 1e6,\n      \"wdq_dyn_E\": 1e-12,\n\n      \"wdqs_termination\": true,\n      \"wdqs_R_eq\": 1e6,\n      \"wdqs_dyn_E\": 1e-12,\n      \"rdqs_termination\": true,\n      \"rdqs_R_eq\": 1e6,\n      \"rdqs_dyn_E\": 1e-12,\n\n      \"wdbi_termination\": true,\n      \"wdbi_R_eq\": 1e6,\n      \"wdbi_dyn_E\": 1e-12,\n      \"rdbi_termination\": true,\n      \"rdbi_R_eq\": 1e6,\n      \"rdbi_dyn_E\": 1e-12\n    }\n  }\n}\n\n\n"
  },
  {
    "path": "tests/tests_drampower/resources/lpddr5.csv",
    "content": "0 ,ACT,0,0,0,0,0\n15,PRE,0,0,0,0,0\n15,END,0,0,0,0,0"
  },
  {
    "path": "tests/tests_drampower/resources/lpddr5.json",
    "content": "{\n  \"memspec\": {\n    \"memoryId\": \"lpddr5\",\n    \"memoryType\": \"LPDDR5\",\n    \"memarchitecturespec\": {\n      \"nbrOfChannels\": 0,\n      \"nbrOfColumns\": 1024,\n      \"nbrOfRows\": 65536,\n      \"width\": 8,\n      \"burstLength\": 8,\n      \"maxBurstLength\": 8,\n      \"dataRate\": 2,\n      \"nbrOfBankGroups\": 1,\n      \"nbrOfBanks\": 16,\n      \"nbrOfRanks\": 1,\n      \"nbrOfDevices\": 1,\n      \"per2BankOffset\": 0,\n      \"WCKalwaysOn\": true\n    },\n    \"mempowerspec\": {\n      \"vdd1\": 1.2,\n      \"idd01\": 56.25e-3,\n      \"idd2n1\": 33.75e-3,\n      \"idd3n1\": 35.0e-3,\n      \"idd4r1\": 157.5e-3,\n      \"idd4w1\": 135.0e-3,\n      \"idd51\": 118.0e-3,\n      \"idd5pb1\": 74.0e-3,\n      \"idd61\": 20.25e-3,\n      \"idd6ds1\": 13.25e-3,\n      \"idd2p1\": 17.0e-3,\n      \"idd3p1\": 22.5e-3,\n      \"vdd2h\": 1.2,\n      \"idd02h\": 0,\n      \"idd2n2h\": 0,\n      \"idd3n2h\": 0,\n      \"idd4r2h\": 0,\n      \"idd4w2h\": 0,\n      \"idd52h\": 0,\n      \"idd5pb2h\": 0,\n      \"idd62h\": 0,\n      \"idd6ds2h\": 0,\n      \"idd2p2h\": 0,\n      \"idd3p2h\": 0,\n      \"vdd2l\": 1.2,\n      \"idd02l\": 0,\n      \"idd2n2l\": 0,\n      \"idd3n2l\": 0,\n      \"idd4r2l\": 0,\n      \"idd4w2l\": 0,\n      \"idd52l\": 0,\n      \"idd5pb2l\": 0,\n      \"idd62l\": 0,\n      \"idd6ds2l\": 0,\n      \"idd2p2l\": 0,\n      \"idd3p2l\": 0,\n      \"vddq\": 0.5,\n      \"iBeta_vdd1\": 56.25e-3,\n      \"iBeta_vdd2h\": 0,\n      \"iBeta_vdd2l\": 0\n    },\n    \"memtimingspec\": {\n      \"tCK\": 0.76923076923076923076923076923077e-9,\n      \"REFI\": 20,\n      \"REFIpb\": 0,\n      \"RFCab\": 25,\n      \"RFCpb\": 20,\n      \"RAS\": 10,\n      \"RPab\": 0,\n      \"RPpb\": 10,\n      \"RCpb\": 0,\n      \"RCab\": 0,\n      \"PPD\": 0,\n      \"RCD\": 13,\n      \"RCD_L\": 0,\n      \"RCD_S\": 0,\n      \"FAW\": 0,\n      \"RRD\": 0,\n      \"RL\": 0,\n      \"RBTP\": 3,\n      \"WL\": 5,\n      \"WR\": 5,\n      \"RTRS\": 0,\n      \"BL_n_min_16\": 0,\n      \"BL_n_max_16\": 0,\n      \"BL_n_L_16\": 0,\n      \"BL_n_S_16\": 0,\n      \"BL_n_min_32\": 0,\n      \"BL_n_max_32\": 0,\n      \"BL_n_L_32\": 0,\n      \"BL_n_S_32\": 0,\n      \"WTR_L\": 0,\n      \"WTR_S\": 0,\n      \"WCK2DQO\": 2,\n      \"WCK2CK\": 2,\n      \"pbR2act\": 0,\n      \"pbR2pbR\": 0\n    },\n    \"bankwisespec\":{\n      \"factRho\":0.5\n    },\n    \"memimpedancespec\": {\n      \"ck_termination\": true,\n      \"ck_R_eq\": 1e6,\n      \"ck_dyn_E\": 1e-12,\n\n      \"ca_termination\": true,\n      \"ca_R_eq\": 1e6,\n      \"ca_dyn_E\": 1e-12,\n\n      \"rdq_termination\": true,\n      \"rdq_R_eq\": 1e6,\n      \"rdq_dyn_E\": 1e-12,\n      \"wdq_termination\": true,\n      \"wdq_R_eq\": 1e6,\n      \"wdq_dyn_E\": 1e-12,\n\n      \"wck_termination\": true,\n      \"wck_R_eq\": 1e6,\n      \"wck_dyn_E\": 1e-12,\n      \"rdqs_termination\": true,\n      \"rdqs_R_eq\": 1e6,\n      \"rdqs_dyn_E\": 1e-12,\n\n      \"wdbi_termination\": true,\n      \"wdbi_R_eq\": 1e6,\n      \"wdbi_dyn_E\": 1e-12,\n      \"rdbi_termination\": true,\n      \"rdbi_R_eq\": 1e6,\n      \"rdbi_dyn_E\": 1e-12\n    }\n  }\n}\n"
  },
  {
    "path": "tests/tests_misc/CMakeLists.txt",
    "content": "###############################################\n###              tests_misc                 ###\n###############################################\n\nadd_executable(tests_misc\n\ttest_bus_extended.cpp\n\ttest_bus.cpp\n\ttest_pin.cpp\n\ttest_clock.cpp\n\ttest_dynamic_bitset.cpp\n\ttest_interval.cpp\n\ttest_misc.cpp\n\ttest_pattern.cpp\n\ttest_static_extension_manager.cpp\n\ttest_dynamic_extension_manager.cpp\n)\n\ntarget_link_libraries(tests_misc\n\tDRAMPower::DRAMPower\n\tDRAMUtils::DRAMUtils\n\tgtest\n\tgtest_main\n)\n\ngtest_discover_tests(tests_misc\n\tWORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}\n)\n"
  },
  {
    "path": "tests/tests_misc/test_bus.cpp",
    "content": "#include <gtest/gtest.h>\n#include <bitset>\n\n#include <DRAMPower/util/bus.h>\n\nusing namespace DRAMPower;\n\nusing Bus_512 = util::Bus<512>;\nusing Bus_128 = util::Bus<128>;\nusing Bus_64 = util::Bus<64>;\nusing Bus_16 = util::Bus<16>;\nusing Bus_8 = util::Bus<8>;\nusing Bus_6 = util::Bus<6>;\nusing Bus_4 = util::Bus<4>;\n\nclass BusTest : public ::testing::Test {\nprotected:\n\tvirtual void SetUp()\n\t{\n\t}\n\n\tvirtual void TearDown()\n\t{\n\t}\n};\n\n#define ASSERT_HAS_DATA(lhs) ASSERT_TRUE(lhs.has_value())\n#define ASSERT_NO_DATA(lhs) ASSERT_FALSE(lhs.has_value())\n#define ASSERT_EQ_BITSET(N, lhs, rhs) ASSERT_HAS_DATA(lhs); ASSERT_EQ(lhs.value(), std::bitset<N>(rhs))\n\nTEST_F(BusTest, EmptyTest)\n{\n\tBus_8 bus(8, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L);\n\n\t// auto [hasData, data] = bus.at(0);\n\n\tASSERT_HAS_DATA(bus.at(0));\n\tASSERT_EQ(bus.at(0).value(), Bus_8::burst_t(0b0000'0000));\n\tASSERT_EQ_BITSET(8, bus.at(1), 0b0000'0000);\n};\n\nTEST_F(BusTest, Load_Width_8_Single)\n{\n\tBus_8 bus(8, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L);\n\n\tbus.load(0, 0b1010'1111, 1);\n\tASSERT_EQ_BITSET(8, bus.at(0), 0b1010'1111);\n\tASSERT_EQ_BITSET(8, bus.at(1), 0b0000'0000);\n};\n\nTEST_F(BusTest, Load_Width_4)\n{\n\tBus_4 bus(4, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L);\n\n\tbus.load(0, 0b1010'1111, 2);\n\tASSERT_EQ_BITSET(4, bus.at(0), 0b1010);\n\tASSERT_EQ_BITSET(4, bus.at(1), 0b1111);\n};\n\nTEST_F(BusTest, Load_HighImpedance_Width_4_0)\n{\n\tBus_4 bus(4, 1, util::BusIdlePatternSpec::Z, util::BusInitPatternSpec::L);\n\t\n\t// Bursts\n\t// -1 LLLL\n\t//  0 ZZZZ\n\t//  1 ZZZZ\n\t//  2 ZZZZ\n\t//  3 1010\n\t//  4 1111\n\t//  5 ZZZZ\n\n\tASSERT_NO_DATA(bus.at(0));\n\tASSERT_NO_DATA(bus.at(1));\n\tASSERT_NO_DATA(bus.at(2));\n\n\tauto stats = bus.get_stats(3);\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\tASSERT_EQ(stats.bit_changes, 0);\n\n\tbus.load(3, 0b1010'1111, 2);\n\n\tASSERT_EQ_BITSET(4, bus.at(3), 0b1010);\n\tASSERT_EQ_BITSET(4, bus.at(4), 0b1111);\n\tASSERT_NO_DATA(bus.at(5));\n\t\n\tstats = bus.get_stats(4); // ZZZZ -> 1010\n\tASSERT_EQ(stats.ones, 2);\n\tASSERT_EQ(stats.zeroes, 2);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\tASSERT_EQ(stats.bit_changes, 0);\n\n\tstats = bus.get_stats(5); // 1010 -> 1111\n\tASSERT_EQ(stats.ones, 2 + 4);\n\tASSERT_EQ(stats.zeroes, 2 + 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0 + 2);\n\tASSERT_EQ(stats.bit_changes, 0 + 2);\n};\n\nTEST_F(BusTest, Load_HighImpedance_Width_4_1)\n{\n\tBus_4 bus(4, 1, util::BusIdlePatternSpec::Z, util::BusInitPatternSpec::Z);\n\n\t// Bursts\n\t// -1 ZZZZ\n\t//  0 ZZZZ\n\t//  1 ZZZZ\n\t//  2 ZZZZ\n\t//  3 1010\n\t//  4 1111\n\t//  5 ZZZZ\n\n\tASSERT_NO_DATA(bus.at(0));\n\tASSERT_NO_DATA(bus.at(1));\n\tASSERT_NO_DATA(bus.at(2));\n\n\tbus.load(3, 0b1010'1111, 2);\n\n\tASSERT_EQ_BITSET(4, bus.at(3), 0b1010);\n\tASSERT_EQ_BITSET(4, bus.at(4), 0b1111);\n\tASSERT_NO_DATA(bus.at(5));\n\n\tauto stats = bus.get_stats(3);\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\tASSERT_EQ(stats.bit_changes, 0);\n\n\tstats = bus.get_stats(4); // ZZZZ -> 1010\n\tASSERT_EQ(stats.ones, 2);\n\tASSERT_EQ(stats.zeroes, 2);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\tASSERT_EQ(stats.bit_changes, 0);\n\n\tstats = bus.get_stats(5); // 1010 -> 1111\n\tASSERT_EQ(stats.ones, 2 + 4);\n\tASSERT_EQ(stats.zeroes, 2 + 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0 + 2);\n\tASSERT_EQ(stats.bit_changes, 0 + 2);\n};\n\nTEST_F(BusTest, Load_HighImpedance_Width_4_2)\n{\n\tBus_4 bus(4, 1, util::BusIdlePatternSpec::LAST_PATTERN, util::BusInitPatternSpec::Z);\n\n\t// Bursts\n\t// -1 ZZZZ\n\t//  0 ZZZZ\n\t//  1 ZZZZ\n\t//  2 ZZZZ\n\t//  3 1010\n\t//  4 0101\n\t//  5 0101\n\t//  6 0101\n\n\tASSERT_NO_DATA(bus.at(0));\n\tASSERT_NO_DATA(bus.at(1));\n\tASSERT_NO_DATA(bus.at(2));\n\n\tbus.load(3, 0b1010'0101, 2);\n\n\tASSERT_EQ_BITSET(4, bus.at(3), 0b1010);\n\tASSERT_EQ_BITSET(4, bus.at(4), 0b0101);\n\tASSERT_HAS_DATA(bus.at(5));\n\tASSERT_HAS_DATA(bus.at(6));\n\n\tauto stats = bus.get_stats(3);\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\tASSERT_EQ(stats.bit_changes, 0);\n\n\tstats = bus.get_stats(4); // ZZZZ -> 1010\n\tASSERT_EQ(stats.ones, 2);\n\tASSERT_EQ(stats.zeroes, 2);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\tASSERT_EQ(stats.bit_changes, 0);\n\n\tstats = bus.get_stats(5); // 1010 -> 0101\n\tASSERT_EQ(stats.ones, 2 + 2);\n\tASSERT_EQ(stats.zeroes, 2 + 2);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 2);\n\tASSERT_EQ(stats.zeroes_to_ones, 0 + 2);\n\tASSERT_EQ(stats.bit_changes, 0 + 4);\n\n\tstats = bus.get_stats(7); // 0101 -> 0101 -> 0101\n\tASSERT_EQ(stats.ones, 2 + 2 + 2 + 2);\n\tASSERT_EQ(stats.zeroes, 2 + 2 + 2 + 2);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 2 + 0 + 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0 + 2 + 0 + 0);\n\tASSERT_EQ(stats.bit_changes, 0 + 4 + 0 + 0);\n};\n\nTEST_F(BusTest, Load_HighImpedance_Width_4_3)\n{\n\tBus_4 bus(4, 1, util::BusIdlePatternSpec::Z, util::BusInitPatternSpec::L);\n\n\t// Bursts\n\t// -1 0000\n\t//  0 1010\n\t//  1 0101\n\t//  2 ZZZZ\n\t//  3 ZZZZ\n\n\tbus.load(0, 0b1010'0101, 2);\n\tASSERT_EQ_BITSET(4, bus.at(0), 0b1010);\n\tASSERT_EQ_BITSET(4, bus.at(1), 0b0101);\n\tASSERT_NO_DATA(bus.at(2));\n\tASSERT_NO_DATA(bus.at(3));\n\n\tauto stats = bus.get_stats(0);\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\tASSERT_EQ(stats.bit_changes, 0);\n\n\tstats = bus.get_stats(1); // 0000 -> 1010\n\tASSERT_EQ(stats.ones, 2);\n\tASSERT_EQ(stats.zeroes, 2);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 2);\n\tASSERT_EQ(stats.bit_changes, 2);\n\n\tstats = bus.get_stats(2); // 1010 -> 0101\n\tASSERT_EQ(stats.ones, 2 + 2);\n\tASSERT_EQ(stats.zeroes, 2 + 2);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 2);\n\tASSERT_EQ(stats.zeroes_to_ones, 2 + 2);\n\tASSERT_EQ(stats.bit_changes, 2 + 4);\n\n\tstats = bus.get_stats(4); // 0101 -> ZZZZ -> ZZZZ\n\tASSERT_EQ(stats.ones, 2 + 2 + 0 + 0);\n\tASSERT_EQ(stats.zeroes, 2 + 2 + 0 + 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 2 + 0 + 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 2 + 2 + 0 + 0);\n\tASSERT_EQ(stats.bit_changes, 2 + 4 + 0 + 0);\n};\n\nTEST_F(BusTest, Load_Width_8)\n{\n\tBus_8 bus(8, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L);\n\n\tbus.load(0, 0b0010'1010'1001'0110, 2);\n\tASSERT_EQ_BITSET(8, bus.at(0), 0b0010'1010);\n\tASSERT_EQ_BITSET(8, bus.at(1), 0b1001'0110);\n};\n\n\nTEST_F(BusTest, Load_Width_4_Cont)\n{\n\tBus_4 bus(4, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L);\n\n\tbus.load(0, 0b1010'1111, 2);\n\tASSERT_EQ_BITSET(4, bus.at(0), 0b1010);\n\tASSERT_EQ_BITSET(4, bus.at(1), 0b1111);\n\tASSERT_EQ_BITSET(4, bus.at(2), 0b0000);\n\n\tbus.load(2, 0b0101'0001, 2);\n\tASSERT_EQ_BITSET(4, bus.at(2), 0b0101);\n\tASSERT_EQ_BITSET(4, bus.at(3), 0b0001);\n\tASSERT_EQ_BITSET(4, bus.at(4), 0b0000);\n\n\tbus.load(5, 0b0101'0001'1111, 3);\n\tASSERT_EQ_BITSET(4, bus.at(5), 0b0101);\n\tASSERT_EQ_BITSET(4, bus.at(6), 0b0001);\n\tASSERT_EQ_BITSET(4, bus.at(7), 0b1111);\n\tASSERT_EQ_BITSET(4, bus.at(8), 0b0000);\n};\n\nTEST_F(BusTest, Stats_Empty_1)\n{\n\tBus_4 bus(4, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L);\n\tauto stats = bus.get_stats(0);\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, 0);\n\tASSERT_EQ(stats.bit_changes, 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n};\n\nTEST_F(BusTest, Stats_Empty_2)\n{\n\tBus_4 bus(4, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L);\n\tbus.load(0, 0b1010'1111, 2);\n\tauto stats = bus.get_stats(0);\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, 0);\n\tASSERT_EQ(stats.bit_changes, 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n};\n\nTEST_F(BusTest, Stats_Basic_1)\n{\n\tBus_4 bus(4, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::H);\n\n\tauto stats = bus.get_stats(0);\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, 0);\n\tASSERT_EQ(stats.bit_changes, 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\n\tbus.load(1, 0b1111, 1);\n\tstats = bus.get_stats(1);\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, 4);\n\tASSERT_EQ(stats.ones_to_zeroes, 4);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\tASSERT_EQ(stats.bit_changes, 4);\n\n\tstats = bus.get_stats(2);\n\tASSERT_EQ(stats.ones, 4);\n\tASSERT_EQ(stats.zeroes, 4);\n\tASSERT_EQ(stats.ones_to_zeroes, 4);\n\tASSERT_EQ(stats.zeroes_to_ones, 4);\n\tASSERT_EQ(stats.bit_changes, 8);\n\n\tstats = bus.get_stats(3);\n\tASSERT_EQ(stats.ones, 4);\n\tASSERT_EQ(stats.zeroes, 8);\n\tASSERT_EQ(stats.ones_to_zeroes, 8);\n\tASSERT_EQ(stats.zeroes_to_ones, 4);\n\tASSERT_EQ(stats.bit_changes, 12);\n\n\tstats = bus.get_stats(4);\n\tASSERT_EQ(stats.ones, 4);\n\tASSERT_EQ(stats.zeroes, 12);\n\tASSERT_EQ(stats.ones_to_zeroes, 8);\n\tASSERT_EQ(stats.zeroes_to_ones, 4);\n\tASSERT_EQ(stats.bit_changes, 12);\n};\n\nTEST_F(BusTest, Stats_Basic_2)\n{\n\tBus_4 bus(4, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::H);\n\n\tauto stats = bus.get_stats(0);\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, 0);\n\tASSERT_EQ(stats.bit_changes, 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\n\tstats = bus.get_stats(1);\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, 4);\n\tASSERT_EQ(stats.ones_to_zeroes, 4);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\tASSERT_EQ(stats.bit_changes, 4);\n\n\tbus.load(2, 0b1111, 1);\n\tstats = bus.get_stats(2);\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, 8);\n\tASSERT_EQ(stats.ones_to_zeroes, 4);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\tASSERT_EQ(stats.bit_changes, 4);\n\n\tstats = bus.get_stats(3);\n\tASSERT_EQ(stats.ones, 4);\n\tASSERT_EQ(stats.zeroes, 8);\n\tASSERT_EQ(stats.ones_to_zeroes, 4);\n\tASSERT_EQ(stats.zeroes_to_ones, 4);\n\tASSERT_EQ(stats.bit_changes, 8);\n\n\tstats = bus.get_stats(4);\n\tASSERT_EQ(stats.ones, 4);\n\tASSERT_EQ(stats.zeroes, 12);\n\tASSERT_EQ(stats.ones_to_zeroes, 8);\n\tASSERT_EQ(stats.zeroes_to_ones, 4);\n\tASSERT_EQ(stats.bit_changes, 12);\n};\n\nTEST_F(BusTest, Stats_Basic_3)\n{\n\tBus_4 bus(4, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::H);\n\n\tauto stats = bus.get_stats(0);\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, 0);\n\tASSERT_EQ(stats.bit_changes, 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\n\tstats = bus.get_stats(1);\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, 4);\n\tASSERT_EQ(stats.ones_to_zeroes, 4);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\tASSERT_EQ(stats.bit_changes, 4);\n\n\tstats = bus.get_stats(2);\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, 8);\n\tASSERT_EQ(stats.ones_to_zeroes, 4);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\tASSERT_EQ(stats.bit_changes, 4);\n\n\tstats = bus.get_stats(3);\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, 12);\n\tASSERT_EQ(stats.ones_to_zeroes, 4);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\tASSERT_EQ(stats.bit_changes, 4);\n\n\tbus.load(4, 0b1111, 1);\n\tstats = bus.get_stats(4);\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, 16);\n\tASSERT_EQ(stats.ones_to_zeroes, 4);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\tASSERT_EQ(stats.bit_changes, 4);\n};\n\nTEST_F(BusTest, Stats_4)\n{\n\tBus_4 bus(4, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L);\n\n\tbus.load(0, 0b1010'1111, 2);\n\n\tauto stats = bus.get_stats(0);\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, 0);\n\tASSERT_EQ(stats.bit_changes, 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\n\tstats = bus.get_stats(1);\n\tASSERT_EQ(stats.ones, 2);\n\tASSERT_EQ(stats.zeroes, 2);\n\tASSERT_EQ(stats.bit_changes, 2);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 2);\n\n\tstats = bus.get_stats(2);\n\tASSERT_EQ(stats.ones, 2 + 4);\n\tASSERT_EQ(stats.zeroes, 2 + 0);\n\tASSERT_EQ(stats.bit_changes, 2 + 2);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 2 + 2);\n\n\tstats = bus.get_stats(3);\n\tASSERT_EQ(stats.ones, 2 + 4 + 0);\n\tASSERT_EQ(stats.zeroes, 2 + 0 + 4);\n\tASSERT_EQ(stats.bit_changes, 2 + 2 + 4);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 0 + 4);\n\tASSERT_EQ(stats.zeroes_to_ones, 2 + 2 + 0);\n};\n\nTEST_F(BusTest, Stats_4_Idle)\n{\n\tBus_4 bus(4, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L);\n\n\tbus.load(0, 0b1010'1111, 2);\n\n\tauto stats = bus.get_stats(3);\n\tASSERT_EQ(stats.ones, 6);\n\tASSERT_EQ(stats.zeroes, 6);\n\tASSERT_EQ(stats.bit_changes, 8);\n\tASSERT_EQ(stats.ones_to_zeroes, 4);\n\tASSERT_EQ(stats.zeroes_to_ones, 4);\n\n\tstats = bus.get_stats(4);\n\tASSERT_EQ(stats.ones, 6);\n\tASSERT_EQ(stats.zeroes, 6 + 4);\n\tASSERT_EQ(stats.bit_changes, 8);\n\tASSERT_EQ(stats.ones_to_zeroes, 4);\n\tASSERT_EQ(stats.zeroes_to_ones, 4);\n\n\tstats = bus.get_stats(5);\n\tASSERT_EQ(stats.ones, 6);\n\tASSERT_EQ(stats.zeroes, 6 + 4 + 4);\n\tASSERT_EQ(stats.bit_changes, 8);\n\tASSERT_EQ(stats.ones_to_zeroes, 4);\n\tASSERT_EQ(stats.zeroes_to_ones, 4);\n\n};\n\nTEST_F(BusTest, Stats_8)\n{\n\tBus_8 bus(8, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L);\n\n\tbus.load(0, 0b1010'1111'0110'1001, 2);\n\t// 1010'1111\n\t// 0110'1001\n\n\tauto stats = bus.get_stats(1);\n\tASSERT_EQ(stats.ones, 6);\n\tASSERT_EQ(stats.zeroes, 2);\n\tASSERT_EQ(stats.bit_changes, 6);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 6);\n\n\tstats = bus.get_stats(2);\n\tASSERT_EQ(stats.ones, 6 + 4);\n\tASSERT_EQ(stats.zeroes, 2 + 4);\n\tASSERT_EQ(stats.bit_changes, 6 + 4);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 3);\n\tASSERT_EQ(stats.zeroes_to_ones, 6 + 1);\n};\n\nTEST_F(BusTest, Stats_Second_Load_4)\n{\n\tBus_4 bus(4, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L);\n\n\tbus.load(0, 0b1010'1111, 2);\n\n\tauto stats = bus.get_stats(2);\n\tASSERT_EQ(stats.ones, 6);\n\tASSERT_EQ(stats.zeroes, 2);\n\tASSERT_EQ(stats.bit_changes, 4);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 4);\n\n\tbus.load(2, 0b0110'1001, 2);\n\n\tstats = bus.get_stats(3);  // 1111 -> 0110\n\tASSERT_EQ(stats.ones, 6 + 2);\n\tASSERT_EQ(stats.zeroes, 2 + 2);\n\tASSERT_EQ(stats.bit_changes, 4 + 2);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 2);\n\tASSERT_EQ(stats.zeroes_to_ones, 4 + 0);\n\n\tstats = bus.get_stats(4);  // 0110 -> 1001\n\tASSERT_EQ(stats.ones, 6 + 2 + 2);\n\tASSERT_EQ(stats.zeroes, 2 + 2 + 2);\n\tASSERT_EQ(stats.bit_changes, 4 + 2 + 4);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 2 + 2);\n\tASSERT_EQ(stats.zeroes_to_ones, 4 + 0 + 2);\n};\n\nTEST_F(BusTest, Load_4_cycles)\n{\n\tBus_4 bus(4, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L);\n\n\tbus.load(0, 0b1010'1111'1001'0011, 4);\n\n\t/*\n\t1010'\n\t1111'\n\t1001'\n\t0011\n\t0000\n\t*/\n\n\tauto stats = bus.get_stats(1);\n\tASSERT_EQ(stats.ones, 2);\n\tASSERT_EQ(stats.zeroes, 2);\n\tASSERT_EQ(stats.bit_changes, 2);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 2);\n\n\tstats = bus.get_stats(2);\n\tASSERT_EQ(stats.ones, 2 + 4);\n\tASSERT_EQ(stats.zeroes, 2 + 0);\n\tASSERT_EQ(stats.bit_changes, 2 + 2);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 2 + 2);\n\n\tstats = bus.get_stats(3);\n\tASSERT_EQ(stats.ones, 2 + 4 + 2);\n\tASSERT_EQ(stats.zeroes, 2 + 0 + 2);\n\tASSERT_EQ(stats.bit_changes, 2 + 2 + 2);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 0 + 2);\n\tASSERT_EQ(stats.zeroes_to_ones, 2 + 2 + 0);\n\n\tstats = bus.get_stats(4);\n\tASSERT_EQ(stats.ones, 2 + 4 + 2 + 2);\n\tASSERT_EQ(stats.zeroes, 2 + 0 + 2 + 2);\n\tASSERT_EQ(stats.bit_changes, 2 + 2 + 2 + 2);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 0 + 2 + 1);\n\tASSERT_EQ(stats.zeroes_to_ones, 2 + 2 + 0 + 1);\n\n\tstats = bus.get_stats(5);\n\tASSERT_EQ(stats.ones, 2 + 4 + 2 + 2 + 0);\n\tASSERT_EQ(stats.zeroes, 2 + 0 + 2 + 2 + 4);\n\tASSERT_EQ(stats.bit_changes, 2 + 2 + 2 + 2 + 2);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 0 + 2 + 1 + 2);\n\tASSERT_EQ(stats.zeroes_to_ones, 2 + 2 + 0 + 1 + 0);\n};\n\nTEST_F(BusTest, Load_Data)\n{\n\tconstexpr uint8_t data[] = {\n\t\t0, 0,\n\t\t0, 0b0000'0011,\n\t\t0, 0,\n\t\t0, 0b0000'0010,\n\t\t0, 0,\n\t\t0, 0b0000'0001,\n\t\t0, 0,\n\t\t0, 0b0000'0001,\n\t};\n\n\tBus_16 bus{16, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L};\n\n\tbus.load(0, data, sizeof(data) * 8);\n\n\tauto stats = bus.get_stats(1); //  0x0000 -> 0...0b0000'0001\n\tASSERT_EQ(stats.ones, 1);\n\tASSERT_EQ(stats.zeroes, 15);\n\tASSERT_EQ(stats.zeroes_to_ones, 1);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\n\tstats = bus.get_stats(2); // 0...0b0000'0001 -> 0x0000\n\tASSERT_EQ(stats.ones, 1 + 0);\n\tASSERT_EQ(stats.zeroes, 15 + 16);\n\tASSERT_EQ(stats.zeroes_to_ones, 1);\n\tASSERT_EQ(stats.ones_to_zeroes, 1);\n\n\tstats = bus.get_stats(3); //  0x0000 -> 0...0b0000'0001\n\tASSERT_EQ(stats.ones, 1 + 0 + 1);\n\tASSERT_EQ(stats.zeroes, 15 + 16 + 15);\n\tASSERT_EQ(stats.zeroes_to_ones, 1 + 1);\n\tASSERT_EQ(stats.ones_to_zeroes, 1);\n\n\tstats = bus.get_stats(4); // 0...0b0000'0001 -> 0x0000\n\tASSERT_EQ(stats.ones, 1 + 0 + 1 + 0);\n\tASSERT_EQ(stats.zeroes, 15 + 16 + 15 + 16);\n\tASSERT_EQ(stats.zeroes_to_ones, 1 + 1);\n\tASSERT_EQ(stats.ones_to_zeroes, 1 + 1);\n\n\tstats = bus.get_stats(5); //  0x0000 -> 0...0b0000'0010\n\tASSERT_EQ(stats.ones, 1 + 0 + 1 + 0 + 1);\n\tASSERT_EQ(stats.zeroes, 15 + 16 + 15 + 16 + 15);\n\tASSERT_EQ(stats.zeroes_to_ones, 1 + 1 + 1);\n\tASSERT_EQ(stats.ones_to_zeroes, 1 + 1);\n\n\tstats = bus.get_stats(6); // 0...0b0000'0010 -> 0x0000\n\tASSERT_EQ(stats.ones, 1 + 0 + 1 + 0 + 1 + 0);\n\tASSERT_EQ(stats.zeroes, 15 + 16 + 15 + 16 + 15 + 16);\n\tASSERT_EQ(stats.zeroes_to_ones, 1 + 1 + 1);\n\tASSERT_EQ(stats.ones_to_zeroes, 1 + 1 + 1);\n\n\tstats = bus.get_stats(7); //  0x0000 -> 0...0b0000'0011\n\tASSERT_EQ(stats.ones, 1 + 0 + 1 + 0 + 1 + 0 + 2);\n\tASSERT_EQ(stats.zeroes, 15 + 16 + 15 + 16 + 15 + 16 + 14);\n\tASSERT_EQ(stats.zeroes_to_ones, 1 + 1 + 1 + 2);\n\tASSERT_EQ(stats.ones_to_zeroes, 1 + 1 + 1);\n\n\tstats = bus.get_stats(8); //  0...0b0000'0011 -> 0x0000\n\tASSERT_EQ(stats.ones, 1 + 0 + 1 + 0 + 1 + 0 + 2);\n\tASSERT_EQ(stats.zeroes, 15 + 16 + 15 + 16 + 15 + 16 + 14 + 16);\n\tASSERT_EQ(stats.zeroes_to_ones, 1 + 1 + 1 + 2 + 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 1 + 1 + 1 + 2);\n\n\tstats = bus.get_stats(9); //  0x0000 -> 0x0000\n\tASSERT_EQ(stats.ones, 1 + 0 + 1 + 0 + 1 + 0 + 2);\n\tASSERT_EQ(stats.zeroes, 15 + 16 + 15 + 16 + 15 + 16 + 14 + 16 + 16);\n\tASSERT_EQ(stats.zeroes_to_ones, 1 + 1 + 1 + 2 + 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 1 + 1 + 1 + 2);\n};\n\nTEST_F(BusTest, Test_001)\n{\n\t// constexpr uint8_t data[] = {\n\t// \t0b1010'0000,\n\t// \t0b0000'0100,\n\t// \t0b0010'0110,\n\t// \t0b0001'0000,\n\t// \t0b0000'0000,\n\t// \t0b1000'0010,\n\t// };\n\n\tstd::bitset<6 * 4> cmd_1(\"100000100000000000010000\");\n\tstd::bitset<6 * 4> cmd_2(\"001001100000010010100000\");\n\tstd::bitset<6 * 4> cmd_3(\"010001100000010010100000\");\n\n\t/*\n\t1 0 0 0 0 0\n\t1 0 0 0 0 0\n\t0 0 0 0 0 0\n\t0 1 0 0 0 0\n\t0 0 1 0 0 1\n\t1 0 0 0 0 0\n\t0 1 0 0 1 0\n\t1 0 0 0 0 0\n\t*/\n\n\n\tBus_6 bus{6, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L};\n\n\tbus.load(0, cmd_1.to_ulong(), 4);\n\n\tauto stats = bus.get_stats(1);\n\tASSERT_EQ(stats.ones, 1);\n\tASSERT_EQ(stats.zeroes, 5);\n\tASSERT_EQ(stats.zeroes_to_ones, 1);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\n\tstats = bus.get_stats(2);\n\tASSERT_EQ(stats.ones, 2);\n\tASSERT_EQ(stats.zeroes, 10);\n\tASSERT_EQ(stats.zeroes_to_ones, 1);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\n\tstats = bus.get_stats(3);\n\tASSERT_EQ(stats.ones, 2);\n\tASSERT_EQ(stats.zeroes, 16);\n\tASSERT_EQ(stats.zeroes_to_ones, 1);\n\tASSERT_EQ(stats.ones_to_zeroes, 1);\n\n\tstats = bus.get_stats(4);\n\tASSERT_EQ(stats.ones, 3);\n\tASSERT_EQ(stats.zeroes, 21);\n\tASSERT_EQ(stats.zeroes_to_ones, 2);\n\tASSERT_EQ(stats.ones_to_zeroes, 1);\n\n\tbus.load(4, cmd_2.to_ulong(), 4);\n\n\tstats = bus.get_stats(5);\n\tASSERT_EQ(stats.ones, 5);\n\tASSERT_EQ(stats.zeroes, 25);\n\tASSERT_EQ(stats.zeroes_to_ones, 4);\n\tASSERT_EQ(stats.ones_to_zeroes, 2);\n\n\tstats = bus.get_stats(6);\n\tASSERT_EQ(stats.ones, 6);\n\tASSERT_EQ(stats.zeroes, 30);\n\tASSERT_EQ(stats.zeroes_to_ones, 5);\n\tASSERT_EQ(stats.ones_to_zeroes, 4);\n\n\tstats = bus.get_stats(7);\n\tASSERT_EQ(stats.ones, 8);\n\tASSERT_EQ(stats.zeroes, 34);\n\tASSERT_EQ(stats.zeroes_to_ones, 7);\n\tASSERT_EQ(stats.ones_to_zeroes, 5);\n\n\tstats = bus.get_stats(8);\n\tASSERT_EQ(stats.ones, 9);\n\tASSERT_EQ(stats.zeroes, 39);\n\tASSERT_EQ(stats.zeroes_to_ones, 8);\n\tASSERT_EQ(stats.ones_to_zeroes, 7);\n\n\tstats = bus.get_stats(9);\n\tASSERT_EQ(stats.ones, 9);\n\tASSERT_EQ(stats.zeroes, 45);\n\tASSERT_EQ(stats.zeroes_to_ones, 8);\n\tASSERT_EQ(stats.ones_to_zeroes, 8);\n\n\tstats = bus.get_stats(10);\n\n\tbus.load(10, cmd_3.to_ulong(), 4);\n\n\tstats = bus.get_stats(11);\n\tASSERT_EQ(stats.ones, 11);\n\tASSERT_EQ(stats.zeroes, 55);\n\tASSERT_EQ(stats.zeroes_to_ones, 10);\n\tASSERT_EQ(stats.ones_to_zeroes, 8);\n};"
  },
  {
    "path": "tests/tests_misc/test_bus_extended.cpp",
    "content": "#include <gtest/gtest.h>\n#include <bitset>\n\n#include <DRAMPower/util/bus.h>\n#include <array>\n#include <optional>\n#include <algorithm>\n\nusing namespace DRAMPower;\nusing Bus_512 = util::Bus<512>;\nusing Bus_128 = util::Bus<128>;\nusing Bus_64 = util::Bus<64>;\nusing Bus_8 = util::Bus<8>;\n\nclass ExtendedBusIdlePatternTest : public ::testing::Test {\nprotected:\n\n\ttemplate<size_t N>\n\tvoid Init(\n\t\ttypename util::Bus<N>::burst_t& burst_ones,\n\t\ttypename util::Bus<N>::burst_t& burst_zeroes,\n\t\ttypename util::Bus<N>::burst_t& burst_custom\n\t) {\n\t\tburst_ones.set();\n\t\tburst_zeroes.reset();\n\t\tfor(size_t i = 0; i < N; i++)\n\t\t{\n\t\t\tburst_custom.set(i, (i % 3) ? true : false);\n\t\t}\n\t}\n\n\tvirtual void SetUp()\n\t{\n\t}\n\n\tvirtual void TearDown()\n\t{\n\t}\n};\n\n#define ASSERT_HAS_DATA(lhs) ASSERT_TRUE(lhs.has_value())\n#define ASSERT_NO_DATA(lhs) ASSERT_FALSE(!lhs.has_value())\n#define ASSERT_EQ_BITSET(N, lhs, rhs) ASSERT_HAS_DATA(lhs); ASSERT_EQ(lhs.value(), std::bitset<N>(rhs))\n#define ASSERT_EQ_BURST(lhs, rhs) ASSERT_HAS_DATA(lhs); ASSERT_EQ(lhs.value(), rhs)\n\nTEST_F(ExtendedBusIdlePatternTest, EmptyIdleLow_1)\n{\n\tBus_8::burst_t burst_ones;\n\tBus_8::burst_t burst_zeroes;\n\tBus_8::burst_t burst_custom;\n\tInit<8>(burst_ones, burst_zeroes, burst_custom);\n\tBus_8 bus(8, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L);\n\n\tASSERT_EQ_BURST(bus.at(0), burst_zeroes);\n\tASSERT_EQ_BURST(bus.at(1), burst_zeroes);\n};\n\nTEST_F(ExtendedBusIdlePatternTest, EmptyIdleLow_2)\n{\n\tBus_8::burst_t burst_ones;\n\tBus_8::burst_t burst_zeroes;\n\tBus_8::burst_t burst_custom;\n\tInit<8>(burst_ones, burst_zeroes, burst_custom);\n\tBus_8 bus(8, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::H);\n\n\tASSERT_EQ_BURST(bus.at(0), burst_zeroes);\n\tASSERT_EQ_BURST(bus.at(1), burst_zeroes);\n};\n\nTEST_F(ExtendedBusIdlePatternTest, EmptyIdleLow_3)\n{\n\tBus_8::burst_t burst_ones;\n\tBus_8::burst_t burst_zeroes;\n\tBus_8::burst_t burst_custom;\n\tInit<8>(burst_ones, burst_zeroes, burst_custom);\n\tBus_8 bus(8, 1, util::BusIdlePatternSpec::L, burst_custom, true);\n\n\tASSERT_EQ_BURST(bus.at(0), burst_zeroes);\n\tASSERT_EQ_BURST(bus.at(1), burst_zeroes);\n};\n\nTEST_F(ExtendedBusIdlePatternTest, EmptyIdleHigh_1)\n{\n\tBus_8::burst_t burst_ones;\n\tBus_8::burst_t burst_zeroes;\n\tBus_8::burst_t burst_custom;\n\tInit<8>(burst_ones, burst_zeroes, burst_custom);\n\tBus_8 bus(8, 1, util::BusIdlePatternSpec::H, util::BusInitPatternSpec::L);\n\n\tASSERT_EQ_BURST(bus.at(0), burst_ones);\n\tASSERT_EQ_BURST(bus.at(1), burst_ones);\n};\n\nTEST_F(ExtendedBusIdlePatternTest, EmptyIdleHigh_2)\n{\n\tBus_8::burst_t burst_ones;\n\tBus_8::burst_t burst_zeroes;\n\tBus_8::burst_t burst_custom;\n\tInit<8>(burst_ones, burst_zeroes, burst_custom);\n\tBus_8 bus(8, 1, util::BusIdlePatternSpec::H, util::BusInitPatternSpec::H);\n\n\tASSERT_EQ_BURST(bus.at(0), burst_ones);\n\tASSERT_EQ_BURST(bus.at(1), burst_ones);\n};\n\nTEST_F(ExtendedBusIdlePatternTest, EmptyIdleHigh_3)\n{\n\tBus_8::burst_t burst_ones;\n\tBus_8::burst_t burst_zeroes;\n\tBus_8::burst_t burst_custom;\n\tInit<8>(burst_ones, burst_zeroes, burst_custom);\n\tBus_8 bus(8, 1, util::BusIdlePatternSpec::H, burst_custom, true);\n\n\tASSERT_EQ_BURST(bus.at(0), burst_ones);\n\tASSERT_EQ_BURST(bus.at(1), burst_ones);\n};\n\nTEST_F(ExtendedBusIdlePatternTest, EmptyIdleLastPattern_1)\n{\n\tBus_8::burst_t burst_ones;\n\tBus_8::burst_t burst_zeroes;\n\tBus_8::burst_t burst_custom;\n\tInit<8>(burst_ones, burst_zeroes, burst_custom);\n\tBus_8 bus(8, 1, util::BusIdlePatternSpec::LAST_PATTERN, util::BusInitPatternSpec::L);\n\n\tASSERT_EQ_BURST(bus.at(0), burst_zeroes);\n\tASSERT_EQ_BURST(bus.at(1), burst_zeroes);\n};\n\nTEST_F(ExtendedBusIdlePatternTest, EmptyIdleLastPattern_2)\n{\n\tBus_8::burst_t burst_ones;\n\tBus_8::burst_t burst_zeroes;\n\tBus_8::burst_t burst_custom;\n\tInit<8>(burst_ones, burst_zeroes, burst_custom);\n\tBus_8 bus(8, 1, util::BusIdlePatternSpec::LAST_PATTERN, util::BusInitPatternSpec::H);\n\n\tASSERT_EQ_BURST(bus.at(0), burst_ones);\n\tASSERT_EQ_BURST(bus.at(1), burst_ones);\n};\n\nTEST_F(ExtendedBusIdlePatternTest, EmptyIdleLastPattern_3)\n{\n\tBus_8::burst_t burst_ones;\n\tBus_8::burst_t burst_zeroes;\n\tBus_8::burst_t burst_custom;\n\tInit<8>(burst_ones, burst_zeroes, burst_custom);\n\tBus_8 bus(8, 1, util::BusIdlePatternSpec::LAST_PATTERN, burst_custom, true);\n\n\tASSERT_EQ_BURST(bus.at(0), burst_custom);\n\tASSERT_EQ_BURST(bus.at(1), burst_custom);\n};\n\nTEST_F(ExtendedBusIdlePatternTest, Load_Width_8)\n{\n\tBus_8::burst_t burst_ones;\n\tBus_8::burst_t burst_zeroes;\n\tBus_8::burst_t burst_custom;\n\tInit<8>(burst_ones, burst_zeroes, burst_custom);\n\tBus_8 bus(8, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L);\n\n\t// Init load overrides init pattern\n\tbus.load(0, 0b0010'1010'1001'0110, 2);\n\tASSERT_EQ_BITSET(8, bus.at(0), 0b0010'1010);\n\tASSERT_EQ_BITSET(8, bus.at(1), 0b1001'0110);\n};\n\nTEST_F(ExtendedBusIdlePatternTest, Load_Width_64)\n{\n\tBus_64::burst_t burst_ones;\n\tBus_64::burst_t burst_zeroes;\n\tBus_64::burst_t burst_custom;\n\tInit<64>(burst_ones, burst_zeroes, burst_custom);\n\tconst uint32_t buswidth = 8 * 8;\n\tconst uint32_t number_bytes = (buswidth + 7) / 8;\n\n\tBus_64 bus(64, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L);\n\tstd::array<uint8_t, number_bytes> data = { 0 }; \n\t\n\tauto expected = Bus_64::burst_t(64);\n\n\tauto pattern_gen = [] (size_t i) -> uint8_t {\n\t\treturn static_cast<uint8_t>(i);\n\t};\n\n\t// Load bus\n\tfor (size_t i = 0; i < number_bytes; i++) {\n\t\tdata[i] = pattern_gen(i);\n\t}\n\tbus.load(0, data.data(), buswidth);\n\n\t// Create expected burst\n\tuint8_t byte = 0;\n\tsize_t byteidx = 0;\n\tfor (size_t i = 0; i < buswidth; i++) {\n\t\tif (i % 8 == 0) {\n\t\t\tbyte = pattern_gen(byteidx++);\n\t\t}\n\t\texpected.set(i, ((byte >> (i % 8)) & 1));\n\t}\n\t\n\tASSERT_EQ_BURST(bus.at(0), expected);\n};\n\nTEST_F(ExtendedBusIdlePatternTest, Load_Width_512)\n{\n\tconst uint32_t buswidth = 64 * 8;\n\tconst uint32_t number_bytes = (buswidth + 7) / 8;\n\n\tBus_512 bus(512, 1, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L);\n\tstd::array<uint8_t, number_bytes> data = { 0 }; \n\t\n\tauto expected = Bus_512::burst_t(512);\n\n\tauto pattern_gen = [] (size_t i) -> uint8_t {\n\t\treturn static_cast<uint8_t>(i);\n\t};\n\n\t// Load bus\n\tfor (size_t i = 0; i < number_bytes; i++) {\n\t\tdata[i] = pattern_gen(i);\n\t}\n\tbus.load(0, data.data(), buswidth);\n\n\t// Create expected burst\n\tuint8_t byte = 0;\n\tsize_t byteidx = 0;\n\tfor (size_t i = 0; i < buswidth; i++) {\n\t\tif (i % 8 == 0) {\n\t\t\tbyte = pattern_gen(byteidx++);\n\t\t}\n\t\texpected.set(i, ((byte >> (i % 8)) & 1));\n\t}\n\t\n\tASSERT_EQ_BURST(bus.at(0), expected);\n};\n\nclass ExtendedBusStatsTest : public ::testing::Test {\nprotected:\n\n\tstd::bitset<128> burst_ones{128};\n\tstd::bitset<128> burst_zeroes{128};\n\tstd::bitset<128> burst_custom{128};\n\tconst static constexpr size_t buswidth = 128; // test bus width greater than 64\n\tconst static constexpr size_t bus_array_size = (buswidth + 7) / 8;\n\n\t\n\ttemplate<size_t N>\n\tvoid Init(\n\t\ttypename util::Bus<N>::burst_t& burst_ones,\n\t\ttypename util::Bus<N>::burst_t& burst_zeroes,\n\t\ttypename util::Bus<N>::burst_t& burst_custom\n\t) {\n\t\tburst_ones.set();\n\t\tburst_zeroes.reset();\n\t\tfor(size_t i = 0; i < N; i++)\n\t\t{\n\t\t\tburst_custom.set(i, (i % 3 ? true : false));\n\t\t}\n\t}\n\n\tvirtual void SetUp()\n\t{\n\t}\n\n\tvirtual void TearDown()\n\t{\n\t}\n};\n\nTEST_F(ExtendedBusStatsTest, Stats_Pattern_Datarate_1)\n{\n\tuint_fast8_t datarate = 2;\n\ttimestamp_t timestamp = 3;\n\tBus_128 bus(128, datarate, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L);\n\n\tauto stats = bus.get_stats(timestamp); // 3 cycles with double data rate\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, buswidth * timestamp * datarate);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\tASSERT_EQ(stats.bit_changes, 0);\n}\n\nTEST_F(ExtendedBusStatsTest, Stats_Pattern_Datarate_2)\n{\n\tuint_fast8_t datarate = 13;\n\ttimestamp_t timestamp = 47;\n\tBus_128 bus(128, datarate, util::BusIdlePatternSpec::L, util::BusInitPatternSpec::L);\n\n\n\tauto stats = bus.get_stats(timestamp); // 3 cycles with double data rate\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, buswidth * timestamp * datarate);\n\tASSERT_EQ(stats.ones_to_zeroes, 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\tASSERT_EQ(stats.bit_changes, 0);\n}\n\nTEST_F(ExtendedBusStatsTest, Stats_Pattern_1)\n{\n\tBus_128::burst_t burst_ones{128};\n\tBus_128::burst_t burst_zeroes{128};\n\tBus_128::burst_t burst_custom{128};\n\tInit<128>(burst_ones, burst_zeroes, burst_custom);\n\n\tBus_128 bus(128, 1, util::BusIdlePatternSpec::L, burst_custom, true);\n\tstd::size_t custom_ones = burst_custom.count();\n\tstd::size_t custom_zeroes = buswidth - custom_ones;\n\tuint8_t burst_ones_data[bus_array_size];\n\tstd::fill_n(burst_ones_data, bus_array_size, 0xFF);\n\n\tASSERT_EQ(buswidth, 128);\n\tASSERT_EQ(custom_ones, 85);\n\tASSERT_EQ(custom_zeroes, 43);\n\n\tauto stats = bus.get_stats(1);\n\tASSERT_EQ(stats.ones, 0);\n\tASSERT_EQ(stats.zeroes, 128);\n\tASSERT_EQ(stats.ones_to_zeroes, 85);\n\tASSERT_EQ(stats.zeroes_to_ones, 0);\n\tASSERT_EQ(stats.bit_changes, 85);\n\n\tstats = bus.get_stats(2);\n\tASSERT_EQ(stats.ones, 0 + 0);\n\tASSERT_EQ(stats.zeroes, 128 + 128);\n\tASSERT_EQ(stats.ones_to_zeroes, 85 + 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0 + 0);\n\tASSERT_EQ(stats.bit_changes, 85 + 0);\n\n\tbus.load(2, burst_ones_data, buswidth);\n\t\n\tstats = bus.get_stats(3);\n\tASSERT_EQ(stats.ones, 0 + 0 + 128);\n\tASSERT_EQ(stats.zeroes, 128 + 128 + 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 85 + 0 + 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0 + 0 + 128);\n\tASSERT_EQ(stats.bit_changes, 85 + 0 + 128);\n\n\tstats = bus.get_stats(4);\n\tASSERT_EQ(stats.ones, 0 + 0 + 128 + 0);\n\tASSERT_EQ(stats.zeroes, 128 + 128 + 0 + 128);\n\tASSERT_EQ(stats.ones_to_zeroes, 85 + 0 + 0 + 128);\n\tASSERT_EQ(stats.zeroes_to_ones, 0 + 0 + 128 + 0);\n\tASSERT_EQ(stats.bit_changes, 85 + 0 + 128 + 128);\n\n\tbus.load(4, burst_ones_data, buswidth);\n\n\tstats = bus.get_stats(5);\n\tASSERT_EQ(stats.ones, 0 + 0 + 128 + 0 + 128);\n\tASSERT_EQ(stats.zeroes, 128 + 128 + 0 + 128 + 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 85 + 0 + 0 + 128 + 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0 + 0 + 128 + 0 + 128);\n\tASSERT_EQ(stats.bit_changes, 85 + 0 + 128 + 128 + 128);\n\n\tstats = bus.get_stats(6);\n\tASSERT_EQ(stats.ones, 0 + 0 + 128 + 0 + 128 + 0);\n\tASSERT_EQ(stats.zeroes, 128 + 128 + 0 + 128 + 0 + 128);\n\tASSERT_EQ(stats.ones_to_zeroes, 85 + 0 + 0 + 128 + 0 + 128);\n\tASSERT_EQ(stats.zeroes_to_ones, 0 + 0 + 128 + 0 + 128 + 0);\n\tASSERT_EQ(stats.bit_changes, 85 + 0 + 128 + 128 + 128 + 128);\n};\n\nTEST_F(ExtendedBusStatsTest, Stats_Pattern_2)\n{\n\tBus_128::burst_t burst_ones{128};\n\tBus_128::burst_t burst_zeroes{128};\n\tBus_128::burst_t burst_custom{128};\n\tInit<128>(burst_ones, burst_zeroes, burst_custom);\n\n\tBus_128 bus(128, 1, util::BusIdlePatternSpec::LAST_PATTERN, burst_custom, true);\n\tstd::size_t custom_ones = burst_custom.count();\n\tstd::size_t custom_zeroes = buswidth - custom_ones;\n\tuint8_t burst_ones_data[bus_array_size];\n\tstd::fill_n(burst_ones_data, bus_array_size, 0xFF);\n\n\tASSERT_EQ(buswidth, 128);\n\tASSERT_EQ(custom_ones, 85);\n\tASSERT_EQ(custom_zeroes, 43);\n\n\tauto stats = bus.get_stats(1);\n\tASSERT_EQ(stats.ones, 85); // 85\n\tASSERT_EQ(stats.zeroes, 43); // 43\n\tASSERT_EQ(stats.ones_to_zeroes, 0); // 0\n\tASSERT_EQ(stats.zeroes_to_ones, 0); // 0\n\tASSERT_EQ(stats.bit_changes, 0); // 0\n\n\tstats = bus.get_stats(2);\n\tASSERT_EQ(stats.ones, 85 + 85); // 85 + 0\n\tASSERT_EQ(stats.zeroes, 43 + 43); // 43 + 128\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 0); // 0 + 85\n\tASSERT_EQ(stats.zeroes_to_ones, 0 + 0); // 0 + 0\n\tASSERT_EQ(stats.bit_changes, 0 + 0); // 0 + 85\n\n\tbus.load(2, burst_ones_data, buswidth);\n\t\n\tstats = bus.get_stats(3);\n\tASSERT_EQ(stats.ones, 85 + 85 + 128);  // 85 + 0 + 128\n\tASSERT_EQ(stats.zeroes, 43 + 43 + 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 0 + 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0 + 0 + 43);\n\tASSERT_EQ(stats.bit_changes, 0 + 0 + 43);\n\n\tstats = bus.get_stats(4);\n\tASSERT_EQ(stats.ones, 85 + 85 + 128 + 128);\n\tASSERT_EQ(stats.zeroes, 43 + 43 + 0 + 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 0 + 0 + 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0 + 0 + 43 + 0);\n\tASSERT_EQ(stats.bit_changes, 0 + 0 + 43 + 0);\n\n\tbus.load(4, burst_ones_data, buswidth);\n\n\tstats = bus.get_stats(5);\n\tASSERT_EQ(stats.ones, 85 + 85 + 128 + 128 + 128);\n\tASSERT_EQ(stats.zeroes, 43 + 43 + 0 + 0 + 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 0 + 0 + 0 + 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0 + 0 + 43 + 0 + 0);\n\tASSERT_EQ(stats.bit_changes, 0 + 0 + 43 + 0 + 0);\n\n\tstats = bus.get_stats(6);\n\tASSERT_EQ(stats.ones,  85 + 85 + 128 + 128 + 128 + 128);\n\tASSERT_EQ(stats.zeroes, 43 + 43 + 0 + 0 + 0 + 0);\n\tASSERT_EQ(stats.ones_to_zeroes, 0 + 0 + 0 + 0 + 0 + 0);\n\tASSERT_EQ(stats.zeroes_to_ones, 0 + 0 + 43 + 0 + 0 + 0);\n\tASSERT_EQ(stats.bit_changes, 0 + 0 + 43 + 0 + 0 + 0);\n};\n"
  },
  {
    "path": "tests/tests_misc/test_clock.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <DRAMPower/util/clock.h>\n\nusing namespace DRAMPower;\n\n\nclass ClockTest : public ::testing::Test {\nprotected:\n\tvirtual void SetUp()\n\t{\n\t}\n\n\tvirtual void TearDown()\n\t{\n\t}\n};\n\nTEST_F(ClockTest, Test_1)\n{\n\tutil::Clock clock;\n\n\tutil::Clock::clock_stats_t stats;\n\n\tstats = clock.get_stats_at(0);\n\tASSERT_EQ(stats.zeroes, 0);\n\tASSERT_EQ(stats.ones, 0);\n\n\tstats = clock.get_stats_at(1);\n\tASSERT_EQ(stats.zeroes, 1);\n\tASSERT_EQ(stats.ones, 1);\n\n\tstats = clock.get_stats_at(2);\n\tASSERT_EQ(stats.zeroes, 2);\n\tASSERT_EQ(stats.ones, 2);\n\n\tstats = clock.get_stats_at(10);\n\tASSERT_EQ(stats.zeroes, 10);\n\tASSERT_EQ(stats.ones, 10);\n};\n\nTEST_F(ClockTest, Test_Period)\n{\n\tutil::Clock clock;\n\n\tutil::Clock::clock_stats_t stats;\n\n\t// _ _ - - _ _ - -\n\n\tstats = clock.get_stats_at(0);\n\tASSERT_EQ(stats.zeroes, 0);\n\tASSERT_EQ(stats.ones, 0);\n\n\tstats = clock.get_stats_at(1);\n\tASSERT_EQ(stats.zeroes, 1);\n\tASSERT_EQ(stats.ones, 1);\n\n\tstats = clock.get_stats_at(2);\n\tASSERT_EQ(stats.zeroes, 2);\n\tASSERT_EQ(stats.ones, 2);\n\n\tstats = clock.get_stats_at(3);\n\tASSERT_EQ(stats.zeroes, 3);\n\tASSERT_EQ(stats.ones, 3);\n\n\tstats = clock.get_stats_at(4);\n\tASSERT_EQ(stats.zeroes, 4);\n\tASSERT_EQ(stats.ones, 4);\t\n\t\n\tstats = clock.get_stats_at(5);\n\tASSERT_EQ(stats.zeroes, 5);\n\tASSERT_EQ(stats.ones, 5);\n\n\tstats = clock.get_stats_at(6);\n\tASSERT_EQ(stats.zeroes, 6);\n\tASSERT_EQ(stats.ones, 6);\n\n\tstats = clock.get_stats_at(7);\n\tASSERT_EQ(stats.zeroes, 7);\n\tASSERT_EQ(stats.ones, 7);\n};\n\nTEST_F(ClockTest, Test_Stop_Start)\n{\n\tutil::Clock clock;\n\n\tutil::Clock::clock_stats_t stats;\n\n\tclock.stop(5);\n\n\tstats = clock.get_stats_at(5);\n\tASSERT_EQ(stats.zeroes, 5);\n\tASSERT_EQ(stats.ones, 5);\n\n\tstats = clock.get_stats_at(6);\n\tASSERT_EQ(stats.zeroes, 5);\n\tASSERT_EQ(stats.ones, 5);\n\n\tclock.start(7);\n\n\tstats = clock.get_stats_at(7);\n\tASSERT_EQ(stats.zeroes, 5);\n\tASSERT_EQ(stats.ones, 5);\n\n\tstats = clock.get_stats_at(8);\n\tASSERT_EQ(stats.zeroes, 6);\n\tASSERT_EQ(stats.ones, 6);\n};"
  },
  {
    "path": "tests/tests_misc/test_dynamic_bitset.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <DRAMPower/util/dynamic_bitset.h>\n\nusing namespace DRAMPower;\n\n\nclass DynamicBitsetTest : public ::testing::Test {\nprotected:\n\tvirtual void SetUp()\n\t{\n\t}\n\n\tvirtual void TearDown()\n\t{\n\t}\n};\n\nTEST_F(DynamicBitsetTest, Constructor_1)\n{\n\tutil::dynamic_bitset<4> bitset{};\n\tASSERT_EQ(bitset.size(), 0);\n};\n\nTEST_F(DynamicBitsetTest, Constructor_2)\n{\n\tutil::dynamic_bitset<8> bitset{8, 0b11110011};\n\tASSERT_EQ(bitset.size(), 8);\n};\n\nTEST_F(DynamicBitsetTest, Constructor_3)\n{\n\tutil::dynamic_bitset<4> bitset{4, 0b101010};\n\tASSERT_EQ(bitset.size(), 4);\n};\n\nTEST_F(DynamicBitsetTest, Clear_1)\n{\n\tutil::dynamic_bitset<8> bitset{ 8, 0b11110011 };\n\tASSERT_EQ(bitset.size(), 8);\n\n\tbitset.clear();\n\tASSERT_EQ(bitset.size(), 0);\n};\n\nTEST_F(DynamicBitsetTest, PushBack_1)\n{\n\tutil::dynamic_bitset<4> bitset;\n\tASSERT_EQ(bitset.size(), 0);\n\n\tbitset.push_back(false);\n\tASSERT_EQ(bitset.size(), 1);\n\n\tbitset.push_back(true);\n\tASSERT_EQ(bitset.size(), 2);\n};\n\nTEST_F(DynamicBitsetTest, ElementAccess_1)\n{\n\tutil::dynamic_bitset<4> bitset{ 4, 0b10101010 };\n\tASSERT_EQ(bitset[0], false);\n\tASSERT_EQ(bitset[1], true);\n\tASSERT_EQ(bitset[2], false);\n\tASSERT_EQ(bitset[3], true);\n};\n\nTEST_F(DynamicBitsetTest, ElementAccess_2)\n{\n\tutil::dynamic_bitset<4> bitset;\n\tbitset.push_back(false);\n\tASSERT_EQ(bitset[0], false);\n\n\tbitset.push_back(true);\n\tASSERT_EQ(bitset[1], true);\n};\n\nTEST_F(DynamicBitsetTest, ElementAccess_3)\n{\n\tutil::dynamic_bitset<4> bitset;\n\tbitset.push_back(false);\n\tASSERT_EQ(bitset[0], false);\n\n\tbitset.set(0, true);\n\tASSERT_EQ(bitset[0], true);\n};\n\nTEST_F(DynamicBitsetTest, Count_1)\n{\n\tutil::dynamic_bitset<4> bitset_1{ 4, 0b00001111 };\n\tutil::dynamic_bitset<4> bitset_2{ 4, 0b11110000 };\n\tutil::dynamic_bitset<6> bitset_3{ 6, 0b11111111 };\n\tutil::dynamic_bitset<8> bitset_4{ 8, 0b11110000 };\n\tutil::dynamic_bitset<4> bitset_5{ 8, 0b00001111 };\n\tutil::dynamic_bitset<5> bitset_6{ 8, 0b10010110 };\n\n\tASSERT_EQ(bitset_1.count(), 4);\n\tASSERT_EQ(bitset_2.count(), 0);\n\tASSERT_EQ(bitset_3.count(), 6);\n\tASSERT_EQ(bitset_4.count(), 4);\n\tASSERT_EQ(bitset_5.count(), 4);\n\tASSERT_EQ(bitset_6.count(), 4);\n};\n\nTEST_F(DynamicBitsetTest, Compare_1)\n{\n\tutil::dynamic_bitset<4> bitset_1;\n\tutil::dynamic_bitset<4> bitset_2;\n\n\tASSERT_EQ(bitset_1, bitset_2);\n};\n\nTEST_F(DynamicBitsetTest, Compare_2)\n{\n\tutil::dynamic_bitset<4> bitset_1{ 4, 0b00001111 };\n\tutil::dynamic_bitset<8> bitset_2{ 4, 0b11111111 };\n\tutil::dynamic_bitset<2> bitset_3{ 4, 0b11110000 };\n\tutil::dynamic_bitset<1> bitset_4{ 8, 0b00001111 };\n\n\tASSERT_EQ(bitset_1, bitset_1);\n\tASSERT_EQ(bitset_1, bitset_2);\n\n\tASSERT_NE(bitset_1, bitset_3);\n\tASSERT_NE(bitset_2, bitset_3);\n\tASSERT_NE(bitset_2, bitset_4);\n};\n\nTEST_F(DynamicBitsetTest, Compare_3)\n{\n\tutil::dynamic_bitset<4> bitset_1{ 4, 0b00001111 };\n\n\tASSERT_EQ(bitset_1, 0b1111);\n\tASSERT_EQ(bitset_1, 0b00001111);\n\tASSERT_EQ(bitset_1, 0b11111111);\n\n\tASSERT_NE(bitset_1, 0b11);\n\tASSERT_NE(bitset_1, 0b11110000);\n};\n\nTEST_F(DynamicBitsetTest, Flip_1)\n{\n\tutil::dynamic_bitset<4> bitset;\n\tbitset.push_back(true);\n\tASSERT_EQ(bitset[0], true);\n\tbitset.flip(0);\n\tASSERT_EQ(bitset[0], false);\n};\n\nTEST_F(DynamicBitsetTest, Negate_1)\n{\n\tutil::dynamic_bitset<8> bitset{8, 0b0000'1111};\n\tASSERT_NE(bitset, ~bitset);\n\tASSERT_EQ(~bitset, 0b1111'0000);\n\tASSERT_NE(~bitset, 0b1111'1111);\n\tASSERT_NE(~bitset, 0b0000'0000);\n};\n\nTEST_F(DynamicBitsetTest, BitwiseOp_1)\n{\n\tutil::dynamic_bitset<8> bitset_1{ 8, 0b0000'0000 };\n\tutil::dynamic_bitset<8> bitset_2{ 8, 0b1111'1111 };\n\tutil::dynamic_bitset<8> bitset_3{ 8, 0b1000'0001 };\n\tutil::dynamic_bitset<8> bitset_4{ 8, 0b1001'1001 };\n\n\tASSERT_EQ(bitset_1 & bitset_1, 0);\n\tASSERT_EQ(bitset_1 & bitset_2, 0);\n\tASSERT_EQ(bitset_2 & bitset_3, 0b1000'0001);\n\tASSERT_EQ(bitset_3 & bitset_4, 0b1000'0001);\n\tASSERT_EQ(bitset_4 & bitset_4, bitset_4);\n};\n\nTEST_F(DynamicBitsetTest, BitwiseOp_2)\n{\n\tutil::dynamic_bitset<8> bitset_1{ 8, 0b0000'0000 };\n\tutil::dynamic_bitset<8> bitset_2{ 8, 0b1111'1111 };\n\tutil::dynamic_bitset<8> bitset_3{ 8, 0b1000'0000 };\n\tutil::dynamic_bitset<8> bitset_4{ 8, 0b0001'1001 };\n\n\tASSERT_EQ(bitset_1 | bitset_1, 0);\n\tASSERT_EQ(bitset_1 | bitset_2, 0b1111'1111);\n\tASSERT_EQ(bitset_1 | bitset_3, bitset_3);\n\tASSERT_EQ(bitset_3 | bitset_4, 0b1001'1001);\n};\n\nTEST_F(DynamicBitsetTest, BitwiseOp_3)\n{\n\tutil::dynamic_bitset<8> bitset_1{ 8, 0b0000'0000 };\n\tutil::dynamic_bitset<8> bitset_2{ 8, 0b1110'1111 };\n\tutil::dynamic_bitset<8> bitset_3{ 8, 0b1000'0000 };\n\tutil::dynamic_bitset<8> bitset_4{ 8, 0b0001'1001 };\n\n\tASSERT_EQ(bitset_1 ^ bitset_1, 0);\n\tASSERT_EQ(bitset_1 ^ bitset_2, 0b1110'1111);\n\tASSERT_EQ(bitset_2 ^ bitset_3, 0b0110'1111);\n\tASSERT_EQ(bitset_1 ^ bitset_3, bitset_3);\n\tASSERT_EQ(bitset_3 ^ bitset_4, 0b1001'1001);\n};"
  },
  {
    "path": "tests/tests_misc/test_dynamic_extension_manager.cpp",
    "content": "#include \"DRAMPower/util/Serialize.h\"\n#include <gtest/gtest.h>\n#include <cstddef>\n#include <cstdint>\n#include <iostream>\n#include <type_traits>\n\n#include <DRAMUtils/util/types.h>\n\n#include <DRAMPower/util/extension_manager.h>\n\nusing namespace DRAMPower;\nusing namespace DRAMPower::util;\n\n\n// dynamic extension example without hooks\nclass DynamicExtensionBase : public util::Serialize, public util::Deserialize {\nprotected:\n    int m_base_variable = 47;\n\n    virtual void serialize_impl(std::ostream& stream) const = 0;\n    virtual void deserialize_impl(std::istream& stream) = 0;\npublic:\n    void serialize(std::ostream& stream) const override {\n        stream.write(reinterpret_cast<const char*>(&m_base_variable), sizeof(m_base_variable));\n        serialize_impl(stream);\n    }\n    void deserialize(std::istream& stream) override {\n        stream.read(reinterpret_cast<char*>(&m_base_variable), sizeof(m_base_variable));\n        deserialize_impl(stream);\n    }\n};\n// dynamic extension example without hooks\n// This class can also inherit from extension_manager::Extension\nclass DynamicExtensionExample : public DynamicExtensionBase {\npublic:\n    explicit DynamicExtensionExample(bool initstate, int& captured_int)\n    : m_state(initstate)\n    , m_captured_int(captured_int)\n    {\n        captured_int = m_state ? 1 : 0;\n    }\n\n    bool getState() const {\n        return m_state;\n    }\n    void setState(bool state) {\n        m_state = state;\n        // Also update a captured variable\n        m_captured_int = state ? 1 : 0;\n    }\n    int getBaseVariable() const {\n        return m_base_variable;\n    }\n    void serialize_impl(std::ostream& stream) const override {\n        // Serialize additional data if needed\n        stream.write(reinterpret_cast<const char*>(&m_state), sizeof(m_state));\n        stream.write(reinterpret_cast<const char*>(&m_captured_int), sizeof(m_captured_int));\n    }\n    void deserialize_impl(std::istream& stream) override {\n        // Deserialize additional data if needed\n        stream.read(reinterpret_cast<char*>(&m_state), sizeof(m_state));\n        stream.read(reinterpret_cast<char*>(&m_captured_int), sizeof(m_captured_int));\n    }\nprivate:\n    bool m_state = false;\n    int& m_captured_int;\n};\n\n\n\n// Hook example\nenum class DynamicExtensionHookExample : uint64_t {\n    Hook_0 = 1 << 0,\n    Hook_1 = 1 << 1,\n    Hook_2 = 1 << 2,\n    Hook_3 = 1 << 3,\n    Hook_4 = 1 << 4,\n    // ...\n    ALL = Hook_0 | Hook_1 | Hook_2 | Hook_3 | Hook_4\n};\nconstexpr DynamicExtensionHookExample operator|(DynamicExtensionHookExample lhs, DynamicExtensionHookExample rhs) {\n    return static_cast<DynamicExtensionHookExample>(static_cast<std::underlying_type<DynamicExtensionHookExample>::type>(lhs) |\n        static_cast<std::underlying_type<DynamicExtensionHookExample>::type>(rhs));\n}\nconstexpr DynamicExtensionHookExample operator&(DynamicExtensionHookExample lhs, DynamicExtensionHookExample rhs) {\n    return static_cast<DynamicExtensionHookExample>(static_cast<std::underlying_type<DynamicExtensionHookExample>::type>(lhs) &\n        static_cast<std::underlying_type<DynamicExtensionHookExample>::type>(rhs));\n}\nconstexpr bool operator!=(DynamicExtensionHookExample lhs, size_t rhs) {\n    return static_cast<std::underlying_type<DynamicExtensionHookExample>::type>(lhs) != rhs;\n}\n\n// dynamic extension base with hooks\nclass DynamicExtensionWithHooksBase : public extension_manager::ExtensionWithHooks<DynamicExtensionHookExample> , public util::Serialize, public util::Deserialize {\npublic:\n    using extension_manager::ExtensionWithHooks<DynamicExtensionHookExample>::ExtensionWithHooks;\n\n    int getBaseVariable() const {\n        return m_base_variable;\n    }\n\n    // Hook functions with default implementation\n    virtual void Hook_0(int&) {}\n    virtual void Hook_1(int&) const {}\n    virtual void Hook_2(int&) {}\n    virtual void Hook_3(int&) const {}\n    virtual void Hook_4(int&) {}\n\n    virtual void serialize_impl(std::ostream& stream) const = 0;\n    virtual void deserialize_impl(std::istream& stream) = 0;\n\n    void serialize(std::ostream& stream) const override {\n        stream.write(reinterpret_cast<const char*>(&m_base_variable), sizeof(m_base_variable));\n        serialize_impl(stream);\n    }\n    void deserialize(std::istream& stream) override {\n        stream.read(reinterpret_cast<char*>(&m_base_variable), sizeof(m_base_variable));\n        deserialize_impl(stream);\n    }\nprivate:\n    int m_base_variable = 47;\n};\n\n// dynamic extension example with hooks\nclass DynamicExtensionWithHooksExample : public DynamicExtensionWithHooksBase {\n    public:\n        explicit DynamicExtensionWithHooksExample(bool initstate, int& captured_int)\n        : m_state(initstate)\n        , m_captured_int(captured_int)\n        {\n            captured_int = m_state ? 1 : 0;\n        }\n    \n        bool getState() const {\n            return m_state;\n        }\n        void setState(bool state) {\n            m_state = state;\n            m_captured_int = state ? 1 : 0;\n        }\n\n        DynamicExtensionHookExample getSupportedHooks() const override {\n            return DynamicExtensionHookExample::Hook_0\n                | DynamicExtensionHookExample::Hook_3\n                | DynamicExtensionHookExample::Hook_4;\n        }\n        void Hook_0(int& i) override {\n            i = 0;\n            m_captured_int = 10;\n        }\n        void Hook_3(int& i) const override{\n            i = 3;\n            m_captured_int = 30;\n        }\n        void Hook_4(int& i) override {\n            i = 4;\n            m_captured_int = 40;\n        }\n        void serialize_impl(std::ostream& stream) const override {\n            // Serialize additional data if needed\n            stream.write(reinterpret_cast<const char*>(&m_state), sizeof(m_state));\n            stream.write(reinterpret_cast<const char*>(&m_captured_int), sizeof(m_captured_int));\n        }\n        void deserialize_impl(std::istream& stream) override {\n            // Deserialize additional data if needed\n            stream.read(reinterpret_cast<char*>(&m_state), sizeof(m_state));\n            stream.read(reinterpret_cast<char*>(&m_captured_int), sizeof(m_captured_int));\n        }\n    private:\n        bool m_state = false;\n        int& m_captured_int;\n};\n\nclass DynamicExtensionExampleType {\npublic:\n// Type definitions\n    using Extension_manager_t = util::extension_manager::ExtensionManager<\n        DynamicExtensionBase\n    >;\n// Member variables\n    Extension_manager_t m_extensionManager;\n// Retrieve extension manager\n    Extension_manager_t& getExtensionManager() {\n        return m_extensionManager;\n    }\n    const Extension_manager_t& getExtensionManager() const {\n        return m_extensionManager;\n    }\n};\n\nclass DynamicExtensionHookExampleType {\npublic:\n// Type definitions\n    using Extension_manager_Hooks_t = util::extension_manager::ExtensionManagerWithHooks<\n        DynamicExtensionWithHooksBase,\n        DynamicExtensionHookExample\n    >;\n// Member variables\n    Extension_manager_Hooks_t m_extensionManagerHooks;\n// Retrieve extension manager\n    Extension_manager_Hooks_t& getExtensionManager() {\n        return m_extensionManagerHooks;\n    }\n    const Extension_manager_Hooks_t& getExtensionManager() const {\n        return m_extensionManagerHooks;\n    }\n\n// Member functions\n    void testhook0(int &i) {\n        m_extensionManagerHooks.callHook(DynamicExtensionHookExample::Hook_0, [&i](auto& ext) {\n            ext.Hook_0(i);\n        });\n    }\n    void testhook1(int &i) {\n        m_extensionManagerHooks.callHook(DynamicExtensionHookExample::Hook_1, [&i](const auto& ext) {\n            ext.Hook_1(i);\n        });\n    }\n    void testhook2(int &i) {\n        m_extensionManagerHooks.callHook(DynamicExtensionHookExample::Hook_2, [&i](auto& ext) {\n            ext.Hook_2(i);\n        });\n    }\n    void testhook3(int &i) {\n        m_extensionManagerHooks.callHook(DynamicExtensionHookExample::Hook_3, [&i](const auto& ext) {\n            ext.Hook_3(i);\n        });\n    }\n    void testhook4(int &i) {\n        m_extensionManagerHooks.callHook(DynamicExtensionHookExample::Hook_4, [&i](auto& ext) {\n            ext.Hook_4(i);\n        });\n    }\n};\n\nclass MiscTestExtension : public ::testing::Test {\nprotected:\n    // Test variables\n    using testclass_t = DynamicExtensionExampleType;\n    using testclass_hook_t = DynamicExtensionHookExampleType;\n\n    std::unique_ptr<testclass_t> dut;\n    std::unique_ptr<testclass_hook_t> dut_hook;\n\n    virtual void SetUp()\n    {\n        dut = std::make_unique<testclass_t>();\n        dut_hook = std::make_unique<testclass_hook_t>();\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\n#define ASSERT_EQ_BITSET(N, lhs, rhs) ASSERT_EQ(lhs, util::dynamic_bitset<N>(N, rhs))\n\nTEST_F(MiscTestExtension, DynamicExtension0)\n{\n    // Get reference to extension manager\n    auto& ext_manager = dut->getExtensionManager();\n    \n    // no extension registered\n    ASSERT_FALSE(ext_manager.hasExtension<DynamicExtensionExample>());\n    auto ext = ext_manager.getExtension<DynamicExtensionExample>();\n    ASSERT_TRUE(ext.expired());\n\n    // Register extension with captured reference\n    int captured_int = 0;\n    ext_manager.registerExtension<DynamicExtensionExample>(true, captured_int);\n    \n    // Test registration\n    ASSERT_EQ(ext_manager.hasExtension<DynamicExtensionExample>(), true);\n    ext = ext_manager.getExtension<DynamicExtensionExample>();\n    ASSERT_FALSE(ext.expired());\n    ASSERT_EQ(ext.lock()->getState(), true);\n    ASSERT_EQ(ext.lock()->getBaseVariable(), 47);\n    ASSERT_EQ(captured_int, 1);\n    ext.lock()->setState(false);\n    ASSERT_EQ(ext.lock()->getState(), false);\n    ASSERT_EQ(captured_int, 0);\n    ext.lock()->setState(true);\n    ASSERT_EQ(ext.lock()->getState(), true);\n    ASSERT_EQ(captured_int, 1);\n    ASSERT_EQ(dut->getExtensionManager().getExtension<DynamicExtensionExample>().lock()->getState(), true);\n}\n\nTEST_F(MiscTestExtension, DynamicExtensionHooks0)\n{\n    // Get reference to extension manager\n    auto& ext_manager = dut_hook->getExtensionManager();\n    \n    // no extension registered\n    ASSERT_FALSE(ext_manager.hasExtension<DynamicExtensionWithHooksExample>());\n    auto ext = ext_manager.getExtension<DynamicExtensionWithHooksExample>();\n    ASSERT_TRUE(ext.expired());\n\n    // Register extension with captured reference\n    int captured_int = 0;\n    ext_manager.registerExtension<DynamicExtensionWithHooksExample>(true, captured_int);\n    \n    // Test registration\n    ASSERT_EQ(ext_manager.hasExtension<DynamicExtensionWithHooksExample>(), true);\n    ext = ext_manager.getExtension<DynamicExtensionWithHooksExample>();\n    ASSERT_FALSE(ext.expired());\n    ASSERT_EQ(ext.lock()->getState(), true);\n    ASSERT_EQ(ext.lock()->getBaseVariable(), 47);\n    ASSERT_EQ(captured_int, 1);\n    ext.lock()->setState(false);\n    ASSERT_EQ(ext.lock()->getState(), false);\n    ASSERT_EQ(captured_int, 0);\n    ext.lock()->setState(true);\n    ASSERT_EQ(ext.lock()->getState(), true);\n    ASSERT_EQ(captured_int, 1);\n    ASSERT_EQ(dut_hook->getExtensionManager().getExtension<DynamicExtensionWithHooksExample>().lock()->getState(), true);\n\n    // Test visitor\n    dut_hook->getExtensionManager().withExtension<DynamicExtensionWithHooksExample>([](auto& ext) {\n        ext.setState(false);\n    });\n    ASSERT_EQ(dut_hook->getExtensionManager().getExtension<DynamicExtensionWithHooksExample>().lock()->getState(), false);\n    dut_hook->getExtensionManager().withExtension<DynamicExtensionWithHooksExample>([](auto& ext) {\n        ext.setState(true);\n    });\n\n    // Test hooks\n    ASSERT_EQ(captured_int, 1);\n    int i = -1;\n    dut_hook->testhook0(i);\n    ASSERT_EQ(i, 0);\n    ASSERT_EQ(captured_int, 10);\n    i = -1;\n    dut_hook->testhook1(i);\n    ASSERT_EQ(i, -1);\n    ASSERT_EQ(captured_int, 10);\n    i = -1;\n    dut_hook->testhook2(i);\n    ASSERT_EQ(i, -1);\n    ASSERT_EQ(captured_int, 10);\n    i = -1;\n    dut_hook->testhook3(i);\n    ASSERT_EQ(i, 3);\n    ASSERT_EQ(captured_int, 30);\n    i = -1;\n    dut_hook->testhook4(i);\n    ASSERT_EQ(i, 4);\n    ASSERT_EQ(captured_int, 40);\n}\n"
  },
  {
    "path": "tests/tests_misc/test_interval.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <DRAMPower/util/cycle_stats.h>\n\nusing namespace DRAMPower;\n\n\nclass IntervalTest : public ::testing::Test {\nprotected:\n\tvirtual void SetUp()\n\t{\n\t}\n\n\tvirtual void TearDown()\n\t{\n\t}\n};\n\nTEST_F(IntervalTest, Constructor)\n{\n\tutil::interval_counter<uint64_t> i;\n\n\tASSERT_FALSE(i.is_open());\n\tASSERT_FALSE(i.is_closed());\n\tASSERT_EQ(i.get_count(), 0);\n\tASSERT_EQ(i.get_count_at(50), 0);\n};\n\nTEST_F(IntervalTest, Open)\n{\n\tutil::interval_counter<uint64_t> i(20);\n\n\tASSERT_TRUE(i.is_open());\n\tASSERT_FALSE(i.is_closed());\n\n\tASSERT_EQ(i.get_start(), 20);\n\n\tASSERT_EQ(i.get_count(), 0);\n\tASSERT_EQ(i.get_count_at(15), 0);\n\tASSERT_EQ(i.get_count_at(20),  0);\n\tASSERT_EQ(i.get_count_at(25),  5);\n};\n\nTEST_F(IntervalTest, Close)\n{\n\tutil::interval_counter<uint64_t> i(20);\n\n\tASSERT_TRUE(i.is_open());\n\tASSERT_FALSE(i.is_closed());\n\n\tASSERT_EQ(i.close_interval(30), 10);\n\n\tASSERT_FALSE(i.is_open());\n\tASSERT_TRUE(i.is_closed());\n\n\tASSERT_EQ(i.get_count(), 10);\n\tASSERT_EQ(i.get_count_at(30), 10);\n\tASSERT_EQ(i.get_count_at(35), 10);\n};\n\nTEST_F(IntervalTest, Reset)\n{\n\tutil::interval_counter<uint64_t> i;\n\ti.start_interval(20);\n\tASSERT_EQ(i.close_interval(30), 10);\n\n\ti.reset_interval();\n\n\tASSERT_FALSE(i.is_open());\n\tASSERT_FALSE(i.is_closed());\n\n\tASSERT_EQ(i.get_count(), 10);\n\tASSERT_EQ(i.get_count_at(30), 10);\n\tASSERT_EQ(i.get_count_at(35), 10);\n};\n\n\nTEST_F(IntervalTest, Restart)\n{\n\tutil::interval_counter<uint64_t> i;\n\ti.start_interval(20);\n\tASSERT_EQ(i.close_interval(30), 10);\n\n\ti.start_interval(50);\n\n\tASSERT_TRUE(i.is_open());\n\tASSERT_FALSE(i.is_closed());\n\n\tASSERT_EQ(i.get_count(), 10);\n\tASSERT_EQ(i.get_count_at(55), 15);\n\n\tASSERT_EQ(i.close_interval(60), 10);\n\tASSERT_EQ(i.get_count(), 20);\n\tASSERT_EQ(i.get_count_at(65), 20);\n};"
  },
  {
    "path": "tests/tests_misc/test_misc.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <DRAMPower/util/binary_ops.h>\n\n#include <bitset>\n#include <array>\n#include <optional>\n\n#include <DRAMPower/util/burst_storage.h>\n\nusing namespace DRAMPower;\t\n\ntemplate <std::size_t n>\nusing burst_storage_t = util::burst_storage<util::BusContainer<n>>;\n\nclass MiscTest : public ::testing::Test {\nprotected:\n    // Test variables\n\tusing input_t = std::tuple<uint64_t, uint64_t>;\n\tusing test_list_t = std::vector<input_t>;\n\n\tusing data_t = std::array<uint8_t, 12>;\n\n\ttest_list_t pattern = {\n\t\t{ \n\t\t\t0b0000000000000000000000000000000000000000000000000000000000000000,\n\t\t\t0b1111111111111111111111111111111111111111111111111111111111111111\n\t\t},\n\t\t{\n\t\t\t0b1111111111111111111111111111111111111111111111111111111111111111,\n\t\t\t0b0000000000000000000000000000000000000000000000000000000000000000\n\t\t},\n\t\t{\n\t\t\t0b1111111111111111111111111111111111111111111111111111111111111111,\n\t\t\t0b1111111111111111111111111111111111111111111111111111111111111111\n\t\t},\n\t\t{\n\t\t\t0b0000000000000000000000000000000000000000000000000000000000000000,\n\t\t\t0b0000000000000000000000000000000000000000000000000000000000000001\n\t\t},\n\t\t{\n\t\t\t0b1000000000000000000000000000000000000000000000000000000000000000,\n\t\t\t0b0000000000000000000000000000000000000000000000000000000000000001\n\t\t},\n\t\t{\n\t\t\t0b0000000000000000000000000000000000000000000000000000000010101010,\n\t\t\t0b0000000000000000000000000000000000000000000000000000000001010101\n\t\t},\n\t\t{\n\t\t\t0b0000000000000000000000000000000000000000000000000000000000000000,\n\t\t\t0b0000000000000000000000000000000000000000000000000000000000001010\n\t\t}\n\t};\n\n    virtual void SetUp()\n    {\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\n#define ASSERT_EQ_BITSET(N, lhs, rhs) ASSERT_EQ(lhs, std::bitset<N>(rhs))\n\nTEST_F(MiscTest, TestChunking)\n{\n\t// Test data\n\tdata_t data = {\n\t\t0b1100'0000,\n\t\t0b1010'1111,\n\t\t0b0000'0010,\n\t\t0b0011'1111,\n\n\t\t0b1111'0000,\n\t\t0b1010'1011,\n\t\t0b0001'0101,\n\t\t0b1111'0000,\n\n\t\t0b1010'1011,\n\t\t0b1100'0000,\n\t\t0b0000'1111,\n\t\t0b1111'1100,\n\t};\n\n\t// Test setup\n\tconstexpr std::size_t width = 6;\n\tburst_storage_t<width> burst_storage{width};\n\n\tutil::BurstStorageInsertHelper::insert_data(burst_storage, 0, width, data.data(), data.size() * 8);\n\n\t// Test assertions\n\tASSERT_EQ(burst_storage.size(), 16);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst( 0), 0b111111);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst( 1), 0b000000);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst( 2), 0b111111);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst( 3), 0b000000);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst( 4), 0b101010);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst( 5), 0b111111);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst( 6), 0b000000);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst( 7), 0b010101);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst( 8), 0b101010);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst( 9), 0b111111);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst(10), 0b000000);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst(11), 0b111111);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst(12), 0b000000);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst(13), 0b101010);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst(14), 0b111111);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst(15), 0b000000);\n};\n\nTEST_F(MiscTest, TestBurstLoad_Uneven)\n{\n\t// Test data\n\tdata_t data = {\n\t\t0b0001'0101,\n\t\t0b1010'1111,\n\t};\n\n\t// Test setup\n\tconstexpr std::size_t width = 4;\n\tburst_storage_t<width> burst_storage{width};\n\n\tutil::BurstStorageInsertHelper::insert_data(burst_storage, 0, width, data.data(), 12);\n\n\t// Test assertions\n\tASSERT_EQ(burst_storage.size(), 3);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst(0), 0b1111);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst(1), 0b0001);\n\tASSERT_EQ_BITSET(width, burst_storage.get_burst(2), 0b0101);\n};\n\nTEST_F(MiscTest, BitChanges)\n{\n\tauto apply = [](const input_t & input) {\n\t\treturn util::BinaryOps::bit_changes(std::get<0>(input), std::get<1>(input));\n\t};\n\n\tASSERT_EQ(apply(pattern[0]), 64);\n\tASSERT_EQ(apply(pattern[1]), 64);\n\tASSERT_EQ(apply(pattern[2]), 0);\n\tASSERT_EQ(apply(pattern[3]), 1);\n\tASSERT_EQ(apply(pattern[4]), 2);\n\tASSERT_EQ(apply(pattern[5]), 8);\n\tASSERT_EQ(apply(pattern[6]), 2);\n}\n\nTEST_F(MiscTest, ZeroToOne)\n{\n\tauto apply = [](const input_t & input) {\n\t\treturn util::BinaryOps::zero_to_ones(std::get<0>(input), std::get<1>(input));\n\t};\n\n\tASSERT_EQ(apply(pattern[0]), 64);\n\tASSERT_EQ(apply(pattern[1]), 0);\n\tASSERT_EQ(apply(pattern[2]), 0);\n\tASSERT_EQ(apply(pattern[3]), 1);\n\tASSERT_EQ(apply(pattern[4]), 1);\n\tASSERT_EQ(apply(pattern[5]), 4);\n\tASSERT_EQ(apply(pattern[6]), 2);\n}\n\nTEST_F(MiscTest, OneToZero)\n{\n\tauto apply = [](const input_t & input) {\n\t\treturn util::BinaryOps::one_to_zeroes(std::get<0>(input), std::get<1>(input));\n\t};\n\n\tASSERT_EQ(apply(pattern[0]), 0);\n\tASSERT_EQ(apply(pattern[1]), 64);\n\tASSERT_EQ(apply(pattern[2]), 0);\n\tASSERT_EQ(apply(pattern[3]), 0);\n\tASSERT_EQ(apply(pattern[4]), 1);\n\tASSERT_EQ(apply(pattern[5]), 4);\n\tASSERT_EQ(apply(pattern[6]), 0);\n}\n"
  },
  {
    "path": "tests/tests_misc/test_pattern.cpp",
    "content": "#include <gtest/gtest.h>\n\n#include <DRAMPower/util/bus.h>\n\n#include <DRAMPower/command/Command.h>\n#include <DRAMPower/command/Pattern.h>\n\n#include <bitset>\n#include <initializer_list>\n\nusing namespace DRAMPower;\n\n\nclass PatternTest : public ::testing::Test {\nprotected:\n\n\tstd::vector<DRAMPower::pattern_descriptor::t> pattern;\n\tstd::vector<DRAMPower::pattern_descriptor::t> pattern2;\n\tstd::vector<DRAMPower::pattern_descriptor::t> pattern3;\n\n\tvirtual void SetUp()\n\t{\n\t\tusing namespace pattern_descriptor;\n\t\tpattern = {\n\t\t\tH, L, X, V, AP, BL, H, L, // 8\n\t\t\tBA0, BA1, BA2, BA3, BA4, BA5, BA6, BA7, // 8\n\t\t\tBG0, BG1, BG2, X, X, X, X, X, // 8\n\t\t\tC0,  C1,  C2,  C3, C4, // 5\n\t\t\tR0, R1, R2, // 3\n\t\t};\n\t\tpattern2 = {\n\t\t\tH, L, H, \n\t\t\tOPCODE, OPCODE, OPCODE, OPCODE,\n\t\t\tOPCODE, OPCODE, OPCODE, OPCODE,\n\t\t\tL, H, L\n\t\t};\n\t\tpattern3 = {\n\t\t\tBA0, BA1, BA2, BA3, X, X, X, X,\n\t\t};\n\t}\n\n\tvirtual void TearDown()\n\t{\n\t}\n};\n\nTEST_F(PatternTest, Test_Override_Low)\n{\n\tusing namespace pattern_descriptor;\n\n\tauto encoder = PatternEncoder(PatternEncoderOverrides{\n\t\t{X, PatternEncoderBitSpec::L},\n\t\t{V, PatternEncoderBitSpec::L},\n\t\t{AP, PatternEncoderBitSpec::L},\n\t\t{BL, PatternEncoderBitSpec::L},\n\t});\n\n\t// Bank, Bank Group, Rank, Row, Column\n\tauto result = encoder.encode(Command{0, CmdType::ACT, { 1,2,3,4,17} }, pattern, 0);\n\tASSERT_EQ(result, 2189443209);\n};\n\nTEST_F(PatternTest, Test_Pattern_LastBit)\n{\n\tusing namespace pattern_descriptor;\n\n\tauto encoder = PatternEncoder(PatternEncoderOverrides{\n\t\t{X, PatternEncoderBitSpec::LAST_BIT},\n\t});\n\tconst uint64_t init_pattern = 0b0101;\n\t// Bank, Bank Group, Rank, Row, Column\n\tauto result = encoder.encode({ 0xB, 2,\n\t\t3, 4,}, pattern3, init_pattern);\n\tASSERT_EQ(result, 0b1101'0101);\n};\n\nTEST_F(PatternTest, Test_Override_High)\n{\n\tusing namespace pattern_descriptor;\n\n\tauto encoder = PatternEncoder(PatternEncoderOverrides{\n\t\t{X, PatternEncoderBitSpec::H},\n\t\t{V, PatternEncoderBitSpec::H},\n\t\t{AP, PatternEncoderBitSpec::H},\n\t\t{BL, PatternEncoderBitSpec::H},\n\t});\n\n\t// Bank, Bank Group, Rank, Row, Column\n\tauto result = encoder.encode(Command{0, CmdType::ACT, { 1,2,3,4,17} }, pattern, 0);\n\tASSERT_EQ(result, 3196084105);\n};\n\nTEST_F(PatternTest, Test_Override_Last)\n{\n\tusing namespace pattern_descriptor;\n\n\tauto encoder = PatternEncoder(PatternEncoderOverrides{\n\t\t{X, PatternEncoderBitSpec::LAST_BIT},\n\t\t{V, PatternEncoderBitSpec::LAST_BIT},\n\t\t{AP, PatternEncoderBitSpec::LAST_BIT},\n\t\t{BL, PatternEncoderBitSpec::LAST_BIT},\n\t});\n\n\t// last_pattern\n\tuint64_t init_pattern = 0xAA'AA'AA'AA'AA'AA'AA'AA; // 0b10101010...\n\n\t// Bank, Bank Group, Rank, Row, Column\n\tauto result = encoder.encode(Command{0, CmdType::ACT, { 1,2,3,4,17} }, pattern, init_pattern);\n\tASSERT_EQ(result, 2860534409);\n};\n\nTEST_F(PatternTest, Test_Override_2_Patterns)\n{\n\tusing namespace pattern_descriptor;\n\n\tauto encoder = PatternEncoder(PatternEncoderOverrides{\n\t\t{X, PatternEncoderBitSpec::LAST_BIT},\n\t\t{V, PatternEncoderBitSpec::LAST_BIT},\n\t\t{AP, PatternEncoderBitSpec::LAST_BIT},\n\t\t{BL, PatternEncoderBitSpec::LAST_BIT},\n\t});\n\n\t// last_pattern\n\tuint64_t init_pattern = 0xAA'AA'AA'AA'AA'AA'AA'AA; // 0b10101010...\n\n\t// Set X after BG2 to one\n\tinit_pattern |= 0b1111100000000;\n\n\t// Bank, Bank Group, Rank, Row, Column\n\tauto result = encoder.encode(Command{0, CmdType::ACT, { 1,2,3,4,17} }, pattern, init_pattern);\n\tASSERT_EQ(result, 2860539785);\n\tresult = encoder.encode(Command{0, CmdType::ACT, { 7,3,3,7,17} }, pattern, result);\n\tASSERT_EQ(result, 2866864015);\n};\n\nTEST_F(PatternTest, Test_Opcode_Patterns)\n{\n\tusing namespace pattern_descriptor;\n\n\tauto encoder = PatternEncoder(PatternEncoderOverrides{\n\t\t{X, PatternEncoderBitSpec::LAST_BIT},\n\t\t{V, PatternEncoderBitSpec::LAST_BIT},\n\t\t{AP, PatternEncoderBitSpec::LAST_BIT},\n\t\t{BL, PatternEncoderBitSpec::LAST_BIT},\n\t});\n\n\t// last_pattern\n\tuint64_t init_pattern = 0x0;\n\n\tconst uint64_t opcode = 0x1234'56A5; // 0b...10100101\n\tconst uint16_t opcodeLength = 32; // 32 bits\n\tencoder.setOpcode(opcode, opcodeLength);\n\n\t// Bank, Bank Group, Rank, Row, Column\n\tauto result = encoder.encode(TargetCoordinate{ 1,2,3,4,17}, pattern2, init_pattern);\n\t// HLH\n\tuint64_t result_expected = 0b101 << 11;\n\t// OPCODE\n\tresult_expected |= (opcode & 0xFF) << 3;\n\t// LHL\n\tresult_expected |= 0b010;\n\n\tASSERT_EQ(result, result_expected);\n\tresult = encoder.encode(TargetCoordinate{ 7,6,3,7,21}, pattern2, result);\n\tASSERT_EQ(result, result_expected);\n};\n"
  },
  {
    "path": "tests/tests_misc/test_pin.cpp",
    "content": "#include \"DRAMPower/util/bus_types.h\"\n#include \"DRAMPower/util/pin_types.h\"\n#include <cstddef>\n#include <cstdint>\n#include <gtest/gtest.h>\n\n#include <DRAMPower/util/pin.h>\n\nusing namespace DRAMPower;\n\n// Use builder to make sure all fields are checked in the tests\nstruct StatsBuilder {\n    using stats_t = util::bus_stats_t;\n\n    StatsBuilder& z(uint64_t z) {\n        m_mask |= 0b00001;\n        m_target.zeroes = z;\n        return *this;\n    }\n\n    StatsBuilder& o(uint64_t o) {\n        m_mask |= 0b00010;\n        m_target.ones = o;\n        return *this;\n    }\n\n    StatsBuilder& zto(uint64_t z2o) {\n        m_mask |= 0b00100;\n        m_target.zeroes_to_ones = z2o;\n        return *this;\n    }\n\n    StatsBuilder& otz(uint64_t o2z) {\n        m_mask |= 0b01000;\n        m_target.ones_to_zeroes = o2z;\n        return *this;\n    }\n\n    StatsBuilder& bc(uint64_t bc) {\n        m_mask |= 0b10000;\n        m_target.bit_changes = bc;\n        return *this;\n    }\n\n    StatsBuilder& infer_changes() {\n        m_mask |= 0b10000;\n        m_target.bit_changes = m_target.ones_to_zeroes + m_target.zeroes_to_ones;\n        return *this;\n    }\n\n    stats_t build() {\n        // All fields of stats must be set\n        EXPECT_EQ(m_mask, 0b11111);\n        return m_target;\n    }\n\nprivate:\n    stats_t m_target{}; // Default constructor\n    uint8_t m_mask = 0;\n};\n\nclass PinTest : public ::testing::Test {\nprotected:\n\n\tvirtual void SetUp()\n\t{\n\t}\n\n\tvirtual void TearDown()\n\t{\n\t}\n};\n\nTEST_F(PinTest, Idle_L_0)\n{\n    util::Pin<8> pin_8{util::PinState::H, util::PinState::L};\n    auto builder = StatsBuilder{}\n        .o(0)\n        .zto(0)\n        .otz(0)\n        .infer_changes();\n\n    // First cycle\n    util::bus_stats_t stats_0_1 = pin_8.get_stats_at(0, 1);\n    util::bus_stats_t stats_0_2 = pin_8.get_stats_at(0, 2);\n    EXPECT_EQ(stats_0_1, stats_0_2);\n    EXPECT_EQ(stats_0_1, builder.z(0).build());\n\n    // Second cycle\n    util::bus_stats_t stats_1_1 = pin_8.get_stats_at(1, 1);\n    EXPECT_EQ(stats_1_1, builder.z(1).otz(1).infer_changes().build());\n\n    util::bus_stats_t stats_48_1 = pin_8.get_stats_at(48, 1);\n    util::bus_stats_t stats_24_2 = pin_8.get_stats_at(24, 2);\n    EXPECT_EQ(stats_48_1, stats_24_2);\n    EXPECT_EQ(stats_48_1, builder.z(48).build());\n\n    util::bus_stats_t stats_96_1 = pin_8.get_stats_at(96, 1);\n    util::bus_stats_t stats_48_2 = pin_8.get_stats_at(48, 2);\n    EXPECT_EQ(stats_96_1, stats_48_2);\n    EXPECT_EQ(stats_96_1, builder.z(96).build());\n\n    // Cycles\n    for (std::size_t i = 97; i < 1024; i ++) {\n        EXPECT_EQ(pin_8.get_stats_at(i, 1), builder.z(i).build());\n    }\n};\n\nTEST_F(PinTest, Idle_H_0)\n{\n    util::Pin<8> pin_8{util::PinState::L, util::PinState::H};\n    auto builder = StatsBuilder{}\n        .z(0)\n        .zto(0)\n        .otz(0)\n        .infer_changes();\n\n    // First cycle\n    util::bus_stats_t stats_0_1 = pin_8.get_stats_at(0, 1);\n    util::bus_stats_t stats_0_2 = pin_8.get_stats_at(0, 2);\n    EXPECT_EQ(stats_0_1, stats_0_2);\n    EXPECT_EQ(stats_0_1, builder.o(0).build());\n\n    // Second cycle\n    util::bus_stats_t stats_1_1 = pin_8.get_stats_at(1, 1);\n    EXPECT_EQ(stats_1_1, builder.o(1).zto(1).infer_changes().build());\n\n    util::bus_stats_t stats_48_1 = pin_8.get_stats_at(48, 1);\n    util::bus_stats_t stats_24_2 = pin_8.get_stats_at(24, 2);\n    EXPECT_EQ(stats_48_1, stats_24_2);\n    EXPECT_EQ(stats_48_1, builder.o(48).infer_changes().build());\n\n    util::bus_stats_t stats_96_1 = pin_8.get_stats_at(96, 1);\n    util::bus_stats_t stats_48_2 = pin_8.get_stats_at(48, 2);\n    EXPECT_EQ(stats_96_1, stats_48_2);\n    EXPECT_EQ(stats_96_1, builder.o(96).build());\n\n    // Cycles\n    for (std::size_t i = 97; i < 1024; i ++) {\n        EXPECT_EQ(pin_8.get_stats_at(i, 1), builder.o(i).build());\n    }\n};\n\nTEST_F(PinTest, Load_Init_L_Idle_L_0)\n{\n    util::Pin<8> pin_8{util::PinState::L, util::PinState::L};\n\n    pin_8.set(0, util::PinState::H);\n\n    EXPECT_EQ( // t = 0\n        pin_8.get_stats_at(0, 1),\n        StatsBuilder{}.z(0).o(0).zto(0).otz(0).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 1\n        pin_8.get_stats_at(1, 1),\n        StatsBuilder{}.z(0).o(1).zto(1).otz(0).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 2\n        pin_8.get_stats_at(2, 1),\n        StatsBuilder{}.z(1).o(1).zto(1).otz(1).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 23\n        pin_8.get_stats_at(23, 1),\n        StatsBuilder{}.z(22).o(1).zto(1).otz(1).infer_changes().build()\n    );\n\n    pin_8.set(24, util::PinState::L);\n\n    EXPECT_EQ( // t = 45\n        pin_8.get_stats_at(45, 1),\n        StatsBuilder{}.z(44).o(1).zto(1).otz(1).infer_changes().build()\n    );\n};\n\nTEST_F(PinTest, Load_Init_H_Idle_L_0)\n{\n    util::Pin<8> pin_8{util::PinState::H, util::PinState::L};\n\n    pin_8.set(0, util::PinState::H);\n\n    EXPECT_EQ( // t = 0\n        pin_8.get_stats_at(0, 1),\n        StatsBuilder{}.z(0).o(0).zto(0).otz(0).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 1\n        pin_8.get_stats_at(1, 1),\n        StatsBuilder{}.z(0).o(1).zto(0).otz(0).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 2\n        pin_8.get_stats_at(2, 1),\n        StatsBuilder{}.z(1).o(1).zto(0).otz(1).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 23\n        pin_8.get_stats_at(23, 1),\n        StatsBuilder{}.z(22).o(1).zto(0).otz(1).infer_changes().build()\n    );\n\n    pin_8.set(24, util::PinState::L);\n\n    EXPECT_EQ( // t = 45\n        pin_8.get_stats_at(45, 1),\n        StatsBuilder{}.z(44).o(1).zto(0).otz(1).infer_changes().build()\n    );\n};\n\nTEST_F(PinTest, Load_Init_H_Idle_H_1)\n{\n    util::Pin<8> pin_8{util::PinState::H, util::PinState::H};\n\n    EXPECT_EQ( // t = 0\n        pin_8.get_stats_at(0, 1),\n        StatsBuilder{}.z(0).o(0).zto(0).otz(0).infer_changes().build()\n    );\n\n    pin_8.set(1, util::PinState::L);\n    \n    EXPECT_EQ( // t = 1\n        pin_8.get_stats_at(1, 1),\n        StatsBuilder{}.z(0).o(1).zto(0).otz(0).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 2\n        pin_8.get_stats_at(2, 1),\n        StatsBuilder{}.z(1).o(1).zto(0).otz(1).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 3\n        pin_8.get_stats_at(3, 1),\n        StatsBuilder{}.z(1).o(2).zto(1).otz(1).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 23\n        pin_8.get_stats_at(23, 1),\n        StatsBuilder{}.z(1).o(22).zto(1).otz(1).infer_changes().build()\n    );\n\n    pin_8.set(24, util::PinState::L);\n\n    EXPECT_EQ( // t = 46\n        pin_8.get_stats_at(46, 1),\n        StatsBuilder{}.z(2).o(44).zto(2).otz(2).infer_changes().build()\n    );\n};\n\nTEST_F(PinTest, Load_Init_L_Idle_H_1)\n{\n    util::Pin<8> pin_8{util::PinState::L, util::PinState::H};\n\n    EXPECT_EQ( // t = 0\n        pin_8.get_stats_at(0, 1),\n        StatsBuilder{}.z(0).o(0).zto(0).otz(0).infer_changes().build()\n    );\n\n    pin_8.set(1, util::PinState::L);\n\n    EXPECT_EQ( // t = 1\n        pin_8.get_stats_at(1, 1),\n        StatsBuilder{}.z(0).o(1).zto(1).otz(0).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 2\n        pin_8.get_stats_at(2, 1),\n        StatsBuilder{}.z(1).o(1).zto(1).otz(1).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 2\n        pin_8.get_stats_at(3, 1),\n        StatsBuilder{}.z(1).o(2).zto(2).otz(1).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 23\n        pin_8.get_stats_at(23, 1),\n        StatsBuilder{}.z(1).o(22).zto(2).otz(1).infer_changes().build()\n    );\n\n    pin_8.set(24, util::PinState::L);\n\n    EXPECT_EQ( // t = 45\n        pin_8.get_stats_at(46, 1),\n        StatsBuilder{}.z(2).o(44).zto(3).otz(2).infer_changes().build()\n    );\n};\n\nTEST_F(PinTest, Idle_to_Burst_to_Idle)\n{\n    util::Pin<8> pin_8{util::PinState::L, util::PinState::L};\n\n    EXPECT_EQ( // t = 9\n        pin_8.get_stats_at(9, 1),\n        StatsBuilder{}.z(9).o(0).zto(0).otz(0).infer_changes().build()\n    );\n\n    // Burst length 5\n    pin_8.set(10, util::PinState::H);\n    pin_8.set(10, util::PinState::H);\n    pin_8.set(10, util::PinState::H);\n    pin_8.set(10, util::PinState::H);\n    pin_8.set(10, util::PinState::H);\n    \n    EXPECT_EQ( // t = 10\n        pin_8.get_stats_at(10, 1),\n        StatsBuilder{}.z(10).o(0).zto(0).otz(0).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 11 // H\n        pin_8.get_stats_at(11, 1),\n        StatsBuilder{}.z(10).o(1).zto(1).otz(0).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 12 // H\n        pin_8.get_stats_at(12, 1),\n        StatsBuilder{}.z(10).o(2).zto(1).otz(0).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 13 // H\n        pin_8.get_stats_at(13, 1),\n        StatsBuilder{}.z(10).o(3).zto(1).otz(0).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 14 // H\n        pin_8.get_stats_at(14, 1),\n        StatsBuilder{}.z(10).o(4).zto(1).otz(0).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 15 // H\n        pin_8.get_stats_at(15, 1),\n        StatsBuilder{}.z(10).o(5).zto(1).otz(0).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 16\n        pin_8.get_stats_at(16, 1),\n        StatsBuilder{}.z(11).o(5).zto(1).otz(1).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 24\n        pin_8.get_stats_at(24, 1),\n        StatsBuilder{}.z(19).o(5).zto(1).otz(1).infer_changes().build()\n    );\n\n    // Burst length 3\n    pin_8.set(25, util::PinState::H);\n    pin_8.set(25, util::PinState::L);\n    pin_8.set(25, util::PinState::H);\n\n    \n    EXPECT_EQ( // t = 25\n        pin_8.get_stats_at(25, 1),\n        StatsBuilder{}.z(20).o(5).zto(1).otz(1).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 26 // H\n        pin_8.get_stats_at(26, 1),\n        StatsBuilder{}.z(20).o(6).zto(2).otz(1).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 27 // L\n        pin_8.get_stats_at(27, 1),\n        StatsBuilder{}.z(21).o(6).zto(2).otz(2).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 28 // H\n        pin_8.get_stats_at(28, 1),\n        StatsBuilder{}.z(21).o(7).zto(3).otz(2).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 29\n        pin_8.get_stats_at(29, 1),\n        StatsBuilder{}.z(22).o(7).zto(3).otz(3).infer_changes().build()\n    );\n\n    EXPECT_EQ( // t = 48\n        pin_8.get_stats_at(48, 1),\n        StatsBuilder{}.z(41).o(7).zto(3).otz(3).infer_changes().build()\n    );\n\n};\n\nTEST_F(PinTest, SeamlessBursts)\n{\n\n    util::Pin<8> pin_8{util::PinState::L, util::PinState::L};\n\n    EXPECT_EQ( // t = 9\n        pin_8.get_stats_at(9, 1),\n        StatsBuilder{}.z(9).o(0).zto(0).otz(0).infer_changes().build()\n    );\n\n    // Burst length 5\n    pin_8.set(10, util::PinState::H);\n    pin_8.set(10, util::PinState::H);\n    pin_8.set(10, util::PinState::H);\n    pin_8.set(10, util::PinState::H);\n    pin_8.set(10, util::PinState::H);\n    \n    EXPECT_EQ( // t = 10\n        pin_8.get_stats_at(10, 1),\n        StatsBuilder{}.z(10).o(0).zto(0).otz(0).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 11 // B1: H\n        pin_8.get_stats_at(11, 1),\n        StatsBuilder{}.z(10).o(1).zto(1).otz(0).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 12 // B1: H\n        pin_8.get_stats_at(12, 1),\n        StatsBuilder{}.z(10).o(2).zto(1).otz(0).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 13 // B1: H\n        pin_8.get_stats_at(13, 1),\n        StatsBuilder{}.z(10).o(3).zto(1).otz(0).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 14 // B1: H\n        pin_8.get_stats_at(14, 1),\n        StatsBuilder{}.z(10).o(4).zto(1).otz(0).infer_changes().build()\n    );\n\n    // Burst length 3\n    pin_8.set(15, util::PinState::H);\n    pin_8.set(15, util::PinState::L);\n    pin_8.set(15, util::PinState::H);\n\n    EXPECT_EQ( // t = 15 // B1: H\n        pin_8.get_stats_at(15, 1),\n        StatsBuilder{}.z(10).o(5).zto(1).otz(0).infer_changes().build()\n    );\n\n    EXPECT_EQ( // t = 16 // B2: H\n        pin_8.get_stats_at(16, 1),\n        StatsBuilder{}.z(10).o(6).zto(1).otz(0).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 17 // B2: L\n        pin_8.get_stats_at(17, 1),\n        StatsBuilder{}.z(11).o(6).zto(1).otz(1).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 18 // B2: H\n        pin_8.get_stats_at(18, 1),\n        StatsBuilder{}.z(11).o(7).zto(2).otz(1).infer_changes().build()\n    );\n    EXPECT_EQ( // t = 19\n        pin_8.get_stats_at(19, 1),\n        StatsBuilder{}.z(12).o(7).zto(2).otz(2).infer_changes().build()\n    );\n\n    EXPECT_EQ( // t = 48\n        pin_8.get_stats_at(48, 1),\n        StatsBuilder{}.z(41).o(7).zto(2).otz(2).infer_changes().build()\n    );\n};\n"
  },
  {
    "path": "tests/tests_misc/test_static_extension_manager.cpp",
    "content": "#include <gtest/gtest.h>\n#include <cstddef>\n#include <cstdint>\n#include <type_traits>\n\n#include <DRAMUtils/util/types.h>\n\n#include <DRAMPower/util/extension_manager_static.h>\n\nusing namespace DRAMPower;\n\n// Hook example\nenum class StaticExtensionHookExample : uint64_t {\n    Hook_0 = 1 << 0,\n    Hook_1 = 1 << 1,\n    Hook_2 = 1 << 2,\n    Hook_3 = 1 << 3,\n    Hook_4 = 1 << 4,\n    // ...\n    ALL = Hook_0 | Hook_1 | Hook_2 | Hook_3 | Hook_4\n};\nconstexpr StaticExtensionHookExample operator|(StaticExtensionHookExample lhs, StaticExtensionHookExample rhs) {\n    return static_cast<StaticExtensionHookExample>(static_cast<std::underlying_type<StaticExtensionHookExample>::type>(lhs) |\n        static_cast<std::underlying_type<StaticExtensionHookExample>::type>(rhs));\n}\nconstexpr StaticExtensionHookExample operator&(StaticExtensionHookExample lhs, StaticExtensionHookExample rhs) {\n    return static_cast<StaticExtensionHookExample>(static_cast<std::underlying_type<StaticExtensionHookExample>::type>(lhs) &\n        static_cast<std::underlying_type<StaticExtensionHookExample>::type>(rhs));\n}\nconstexpr bool operator!=(StaticExtensionHookExample lhs, size_t rhs) {\n    return static_cast<std::underlying_type<StaticExtensionHookExample>::type>(lhs) != rhs;\n}\n\n// static extension with hook example\nclass StaticExtensionWithHookExample {\npublic:\n\n    static constexpr StaticExtensionHookExample getSupportedHooks() {\n        return StaticExtensionHookExample::Hook_0\n            | StaticExtensionHookExample::Hook_3\n            | StaticExtensionHookExample::Hook_4;\n    }\n\n// Hooks\n    void Hook_0(int& i) {i = 0;}\n    void Hook_3(int& i) {i = 3;}\n    void Hook_4(int& i) {i = 4;}\n\n// Member functions\n    void setState(int state) {\n        m_state = state;\n    }\n    int getState() const {\n        return m_state;\n    }\nprivate:\n    int m_state = -1;\n};\n\ntemplate <typename... Extensions>\nclass StaticExtensionHookExampleType {\npublic:\n// Type definitions\n    using Extension_manager_t = util::extension_manager_static::StaticExtensionManager<\n        DRAMUtils::util::type_sequence<Extensions...>,\n        StaticExtensionHookExample\n    >;\n// Member variables\n    Extension_manager_t extensionManager;\n// Hook helper\n    template <StaticExtensionHookExample hook, typename... Args>\n    void invokeHook(Args&&... args) {\n        extensionManager.template callHook<hook>(std::forward<Args>(args)...);\n    }\n\n// Member functions\n    void testhook0(int &i) {\n        invokeHook<StaticExtensionHookExample::Hook_0>([&i](auto& ext) {\n            ext.Hook_0(i);\n        });\n    }\n    void testhook1(int &i) {\n        invokeHook<StaticExtensionHookExample::Hook_1>([&i](auto& ext) {\n            ext.Hook_1(i);\n        });\n    }\n    void testhook2(int &i) {\n        invokeHook<StaticExtensionHookExample::Hook_2>([&i](auto& ext) {\n            ext.Hook_2(i);\n        });\n    }\n    void testhook3(int &i) {\n        invokeHook<StaticExtensionHookExample::Hook_3>([&i](auto& ext) {\n            ext.Hook_3(i);\n        });\n    }\n    void testhook4(int &i) {\n        invokeHook<StaticExtensionHookExample::Hook_4>([&i](auto& ext) {\n            ext.Hook_4(i);\n        });\n    }\n};\n\nclass MiscTestStaticExtensionHook : public ::testing::Test {\nprotected:\n    // Test variables\n    using testclass_t = StaticExtensionHookExampleType<StaticExtensionWithHookExample>;\n\n    std::unique_ptr<testclass_t> dut;\n\n    virtual void SetUp()\n    {\n        dut = std::make_unique<testclass_t>();\n    }\n\n    virtual void TearDown()\n    {\n    }\n};\n\nTEST_F(MiscTestStaticExtensionHook, StaticExtensionManager0)\n{\n    // Extension registered\n    ASSERT_TRUE(dut->extensionManager.hasExtension<StaticExtensionWithHookExample>());\n\n    // Set Extension directly\n    ASSERT_EQ(dut->extensionManager.getExtension<StaticExtensionWithHookExample>().getState(), -1);\n    dut->extensionManager.getExtension<StaticExtensionWithHookExample>().setState(1);\n    ASSERT_EQ(dut->extensionManager.getExtension<StaticExtensionWithHookExample>().getState(), 1);\n\n    // Set Extension with a visitor lambda\n    dut->extensionManager.withExtension<StaticExtensionWithHookExample>([](auto& ext) {\n        ext.setState(2);\n    });\n    ASSERT_EQ(dut->extensionManager.getExtension<StaticExtensionWithHookExample>().getState(), 2);\n}\n\nTEST_F(MiscTestStaticExtensionHook, StaticExtensionManager1)\n{\n    // Test assertions\n    int i = -1;\n    dut->testhook0(i);\n    ASSERT_EQ(i, 0);\n    i = -1;\n    dut->testhook1(i);\n    ASSERT_EQ(i, -1);\n    i = -1;\n    dut->testhook2(i);\n    ASSERT_EQ(i, -1);\n    i = -1;\n    dut->testhook3(i);\n    ASSERT_EQ(i, 3);\n    i = -1;\n    dut->testhook4(i);\n    ASSERT_EQ(i, 4);\n    i = -1;\n}\n"
  }
]