diff --git a/.github/workflows/ci-config.yml b/.github/workflows/ci-config.yml
index 37bd732..2a1dbe9 100644
--- a/.github/workflows/ci-config.yml
+++ b/.github/workflows/ci-config.yml
@@ -24,7 +24,11 @@ jobs:
- uses: actions/checkout@v4.1.1
- name: Configure CMake
- run: cmake -B ${{github.workspace}}/build -GNinja
+ run: cmake -B ${{github.workspace}}/build -GNinja -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} 2>&1 | tee ${{github.workspace}}/cmake.log
+
+ - name: Check versions
+ if: github.event.pull_request.base.ref == 'main'
+ run: (! grep -e "Using .* with unreleased version" ${{github.workspace}}/cmake.log)
- name: Cache build directory
if: always()
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 53d0913..37d88d7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,16 +19,15 @@
# You should have received a copy of the GNU General Public License
# along with ECAP5-DTESTLIB. If not, see .
-cmake_minimum_required(VERSION 3.12)
+cmake_minimum_required(VERSION 3.21)
include(FetchContent)
-project(ECAP5_DTESTLIB VERSION 1.0.0)
+project(ECAP5_DTESTLIB)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
set(CMAKE_PREFIX_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
# Create python virtual env
-message(STATUS "Creating python venv")
set(VENV_DIR ${CMAKE_BINARY_DIR}/venv)
if(NOT EXISTS "${VENV_DIR}")
find_package(Python3 COMPONENTS Interpreter)
@@ -41,32 +40,44 @@ find_package(Python3 COMPONENTS Interpreter Development)
# Dependencies
-message(STATUS "Collecting dependencies")
include(${CMAKE_CURRENT_LIST_DIR}/cmake/dependency.cmake)
-add_dependency(ECAP5_TREQ
- GIT ecap5/ecap5-treq
- TAG tags/v2.2.0
- BINARY ecap5-treq)
-
-add_dependency(sphinx-cmake
+add_dependency(
GIT ecap5/sphinx-cmake
TAG tags/v1.0.1)
-add_dependency(verilator-cmake
+add_dependency(
GIT ecap5/verilator-cmake
TAG tags/v1.0.1)
-# Configure dependencies
+add_dependency(
+ GIT ecap5/ecap5-treq
+ TAG 109-use-cmake-interface-libraries
+ BINARY ecap5-treq)
+
+# Define an interface library
-include(${verilator_cmake_SOURCE_DIR}/cmake/verilator-config.cmake)
-include(${ecap5_treq_SOURCE_DIR}/config.cmake)
-list(APPEND CMAKE_MODULE_PATH "${sphinx_cmake_SOURCE_DIR}/cmake")
-include(${CMAKE_CURRENT_LIST_DIR}/cmake/lint.cmake)
-include(${CMAKE_CURRENT_LIST_DIR}/cmake/testbench.cmake)
+add_library(ecap5_dtestlib INTERFACE)
+target_sources(ecap5_dtestlib INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/src/instr_wb_slave.sv
+)
-# Include subdirectories
+# Only perform if the project will be tested
-add_subdirectory(docs)
-add_subdirectory(tests)
+if(PROJECT_IS_TOP_LEVEL)
+ # Configure dependencies
+ list(APPEND CMAKE_MODULE_PATH "${ecap5_sphinx_cmake_SOURCE_DIR}/cmake")
+ include(${ecap5_verilator_cmake_SOURCE_DIR}/cmake/verilator-config.cmake)
+ include(${ecap5_ecap5_treq_SOURCE_DIR}/config.cmake)
+
+ # Include local cmake configuration files
+
+ include(${CMAKE_CURRENT_LIST_DIR}/cmake/lint.cmake)
+ include(${CMAKE_CURRENT_LIST_DIR}/cmake/testbench.cmake)
+
+ # Include subdirectories
+
+ add_subdirectory(docs)
+ add_subdirectory(tests)
+endif()
diff --git a/cmake/dependency.cmake b/cmake/dependency.cmake
index c82ee15..60e913a 100644
--- a/cmake/dependency.cmake
+++ b/cmake/dependency.cmake
@@ -1,26 +1,57 @@
-macro(add_dependency id)
+macro(add_dependency)
cmake_parse_arguments(ARG ""
"GIT;TAG;BINARY"
""
${ARGN})
- string(MAKE_C_IDENTIFIER "${id}" name)
- string(TOLOWER "${name}" name)
-
- FetchContent_Declare(${name}
- GIT_REPOSITORY https://github.com/${ARG_GIT}
- GIT_TAG ${ARG_TAG}
- SOURCE_SUBDIR __none__
- )
- FetchContent_MakeAvailable(${name})
-
- if(NOT DEFINED ${name}_EXECUTABLE)
- if(EXISTS "${${name}_SOURCE_DIR}/pyproject.toml")
- message(STATUS "Configuring ${name}")
- execute_process(COMMAND ${Python3_EXECUTABLE} -m pip install -e ${${name}_SOURCE_DIR} OUTPUT_QUIET RESULT_VARIABLE rv)
- if("${rv}" STREQUAL "0")
- set(${name}_EXECUTABLE ${VENV_DIR}/bin/${ARG_BINARY} CACHE STRING "path to the ${name} executable")
+ set(REPOSITORY_URL https://github.com/${ARG_GIT})
+
+ # Create a unique identifier for the dependency
+ string(MAKE_C_IDENTIFIER "${ARG_GIT}" DEPENDENCY_ID)
+ string(TOLOWER "${DEPENDENCY_ID}" DEPENDENCY_ID)
+
+ get_property(IS_DEPENDENCY_PRESENT GLOBAL PROPERTY ${DEPENDENCY_ID}_VERSION SET)
+
+ # Check if the dependency is already present
+ if(${IS_DEPENDENCY_PRESENT})
+ get_property(${DEPENDENCY_ID}_VERSION GLOBAL PROPERTY ${DEPENDENCY_ID}_VERSION)
+ # Check that the version is the same
+ if(NOT ${DEPENDENCY_ID}_VERSION STREQUAL ARG_TAG)
+ message(FATAL_ERROR "Dependency ${ARG_GIT} version mismatched\n\t${${DEPENDENCY_ID}_VERSION} != ${ARG_TAG}")
+ endif()
+ else()
+ message(STATUS "Configuring ${ARG_GIT}")
+
+ # Define the version
+ set_property(GLOBAL PROPERTY ${DEPENDENCY_ID}_VERSION ${ARG_TAG})
+
+ # Check if released version
+ if(CMAKE_BUILD_TYPE STREQUAL "Release")
+ if(NOT ${ARG_TAG} MATCHES "^tags/.*")
+ message(WARNING "Using ${ARG_GIT} with unreleased version ${ARG_TAG}")
endif()
endif()
- endif()
+ # Fetch the repository
+ FetchContent_Declare(${DEPENDENCY_ID}
+ GIT_REPOSITORY ${REPOSITORY_URL}
+ GIT_TAG ${ARG_TAG}
+ SOURCE_SUBDIR __none__
+ )
+ FetchContent_MakeAvailable(${DEPENDENCY_ID})
+
+ # Add cmake build if it exists
+ if(EXISTS "${${DEPENDENCY_ID}_SOURCE_DIR}/CMakeLists.txt")
+ add_subdirectory(${${DEPENDENCY_ID}_SOURCE_DIR} ${${DEPENDENCY_ID}_SOURCE_DIR}/../${DEPENDENCY_ID}-build)
+ endif()
+
+ # Handle python executable if it exists
+ if(NOT DEFINED ${DEPENDENCY_ID}_EXECUTABLE)
+ if(EXISTS "${${DEPENDENCY_ID}_SOURCE_DIR}/pyproject.toml")
+ execute_process(COMMAND ${Python3_EXECUTABLE} -m pip install -e ${${DEPENDENCY_ID}_SOURCE_DIR} OUTPUT_QUIET RESULT_VARIABLE rv)
+ if("${rv}" STREQUAL "0")
+ set(${DEPENDENCY_ID}_EXECUTABLE ${VENV_DIR}/bin/${ARG_BINARY} CACHE STRING "path to the ${DEPENDENCY_ID} executable")
+ endif()
+ endif()
+ endif()
+ endif()
endmacro()
diff --git a/cmake/lint.cmake b/cmake/lint.cmake
index d7436d5..91e0e24 100644
--- a/cmake/lint.cmake
+++ b/cmake/lint.cmake
@@ -24,15 +24,19 @@ set(DEFAULT_WAIVE_FILE ${CMAKE_CURRENT_LIST_DIR}/../config/default-verible-lint.
function(add_lint_target)
cmake_parse_arguments(ARG ""
- "TARGET;CUSTOM_RULE_FILE;CUSTOM_WAIVE_FILE"
- "SRC_DIRS"
+ "LIB;TARGET;CUSTOM_RULE_FILE;CUSTOM_WAIVE_FILE"
+ ""
${ARGN})
if (NOT ARG_TARGET)
message(FATAL_ERROR "Need a target name")
endif()
- if (NOT ARG_SRC_DIRS)
- message(FATAL_ERROR "Need a source directory")
+ if (NOT ARG_LIB)
+ message(FATAL_ERROR "Need an interface library")
+ endif()
+
+ if (NOT TARGET ${ARG_LIB})
+ message(FATAL_ERROR "Library ${ARG_LIB} not defined")
endif()
if (NOT CUSTOM_RULE_FILE)
@@ -43,9 +47,9 @@ function(add_lint_target)
set(CUSTOM_WAIVE_FILE ${DEFAULT_WAIVE_FILE})
endif()
- file(GLOB SRC_FILES ${ARG_SRC_DIRS}/*.sv)
add_custom_target(${ARG_TARGET}
- COMMAND verible-verilog-lint ${SRC_FILES} --rules_config="${CUSTOM_RULE_FILE}" --waiver_files="${CUSTOM_WAIVE_FILE}"
- DEPENDS ${SRC_FILES} ${CUSTOM_RULE_FILE} ${CUSTOM_WAIVE_FILE})
+ COMMAND verible-verilog-lint $ --rules_config="${CUSTOM_RULE_FILE}" --waiver_files="${CUSTOM_WAIVE_FILE}"
+ DEPENDS ${SRC_FILES} ${CUSTOM_RULE_FILE} ${CUSTOM_WAIVE_FILE}
+ COMMAND_EXPAND_LISTS)
endfunction()
diff --git a/cmake/testbench.cmake b/cmake/testbench.cmake
index 22e628e..715df29 100644
--- a/cmake/testbench.cmake
+++ b/cmake/testbench.cmake
@@ -19,10 +19,38 @@
# You should have received a copy of the GNU General Public License
# along with ECAP5-DTESTLIB. If not, see .
+function(get_all_sources_recursive TARGET_NAME OUTPUT_LIST)
+ set(CURRENT_FILES "")
+
+ get_target_property(RAW_SOURCES ${TARGET_NAME} INTERFACE_SOURCES)
+
+ if(RAW_SOURCES AND NOT "${RAW_SOURCES}" MATCHES "NOTFOUND")
+ list(APPEND CURRENT_FILES ${RAW_SOURCES})
+ endif()
+
+ get_target_property(RAW_LIBS ${TARGET_NAME} INTERFACE_LINK_LIBRARIES)
+ if(RAW_LIBS AND NOT "${RAW_LIBS}" MATCHES "NOTFOUND")
+ foreach(DEP ${RAW_LIBS})
+ if(TARGET ${DEP})
+ get_all_sources_recursive(${DEP} SUB_FILES_LIST)
+ list(APPEND CURRENT_FILES ${SUB_FILES_LIST})
+ else()
+ message(FATAL_ERROR "Recursive dependency ${DEP} not found")
+ endif()
+ endforeach()
+ endif()
+
+ if(CURRENT_FILES)
+ list(REMOVE_DUPLICATES CURRENT_FILES)
+ endif()
+
+ set(${OUTPUT_LIST} ${CURRENT_FILES} PARENT_SCOPE)
+endfunction()
+
macro(add_testbench)
cmake_parse_arguments(ARG ""
- "MODULE;BENCH_DIR;LIBS_DIR;BENCH;TESTDATA_DIR"
- "SRC_DIRS;INCLUDE_DIRS;LIBS;CUSTOM_DEPENDS"
+ "MODULE;BENCH_DIR;BENCH;TESTDATA_DIR"
+ "LIBS;CUSTOM_DEPENDS;TEST_INCLUDE_DIRS"
${ARGN})
if(NOT ARG_BENCH_DIR)
message(FATAL_ERROR "Need a bench directory")
@@ -36,10 +64,16 @@ macro(add_testbench)
message(FATAL_ERROR "Need a testdata directory")
endif()
- if(NOT ARG_SRC_DIRS)
- message(FATAL_ERROR "Need at least one source directory")
+ if(NOT ARG_LIBS)
+ message(FATAL_ERROR "Need at least one source library")
endif()
+ foreach(LIB ${ARG_LIBS})
+ if(NOT TARGET ${LIB})
+ message(FATAL_ERROR "Library ${LIB} not defined")
+ endif()
+ endforeach()
+
# Create folders for the waves and testdata
file(MAKE_DIRECTORY ${TESTDATA_DIR}/waves)
file(MAKE_DIRECTORY ${TESTDATA_DIR}/testdata)
@@ -49,22 +83,20 @@ macro(add_testbench)
endif()
set(TARGET tb_${ARG_BENCH})
- # Make a file list for testing libraries
- list(TRANSFORM ARG_LIBS APPEND ".sv")
- list(TRANSFORM ARG_LIBS PREPEND ${ARG_LIBS_DIR})
+ # Define a source collecting library
+ add_library(lib${TARGET} INTERFACE)
+ target_link_libraries(lib${TARGET} INTERFACE ${ARG_LIBS})
- # List include files
- file(GLOB INCLUDE_FILES ${ARG_INCLUDE_DIRS}/*.svh)
+ get_all_sources_recursive(lib${TARGET} ${TARGET}_SOURCES)
# Create the test executable
add_executable(${TARGET} ${ARG_BENCH_DIR}/${ARG_MODULE}/${TARGET}.cpp)
- target_include_directories(${TARGET} PUBLIC ${TEST_INCLUDE_DIR})
+ target_include_directories(${TARGET} PUBLIC ${ARG_TEST_INCLUDE_DIRS})
verilate(${TARGET}
- PREFIX V${TARGET}
- SOURCES ${INCLUDE_FILES}
- ${ARG_BENCH_DIR}/${ARG_MODULE}/${TARGET}.sv
- ${ARG_LIBS}
- INCLUDE_DIRS ${ARG_SRC_DIRS}
+ PREFIX V${TARGET}
+ TOP_MODULE ${TARGET}
+ SOURCES ${${TARGET}_SOURCES}
+ ${ARG_BENCH_DIR}/${ARG_MODULE}/${TARGET}.sv
TRACE)
set(TEST_TARGET simulate_${ARG_BENCH})
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 45895dd..ab451a1 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -22,27 +22,23 @@
# Bench parent directory
set(BENCH_DIR ${CMAKE_CURRENT_SOURCE_DIR}/benches/)
# C++ bench include directory
-set(TEST_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include/)
-# HDL source directories
-set(SRC_DIRS ${CMAKE_SOURCE_DIR}/src/)
-# HDL library directories
-set(LIBS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libs/)
+set(TEST_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/include/)
# Bench CSV output directory
-set(TESTDATA_DIR ${CMAKE_CURRENT_BINARY_DIR}/testdata/)
+set(TESTDATA_DIR ${CMAKE_CURRENT_BINARY_DIR}/)
# Lint
add_lint_target(
TARGET lint
- SRC_DIRS ${SRC_DIRS}
+ LIB ecap5_dtestlib
)
# Add testbenches
add_testbench(
- MODULE instr_wb_slave
- BENCH_DIR ${BENCH_DIR}
- LIBS_DIR ${LIBS_DIR}
- TESTDATA_DIR ${TESTDATA_DIR}
- SRC_DIRS ${SRC_DIRS}
+ MODULE instr_wb_slave
+ LIBS ecap5_dtestlib
+ BENCH_DIR ${BENCH_DIR}
+ TESTDATA_DIR ${TESTDATA_DIR}
+ TEST_INCLUDE_DIRS ${TEST_INCLUDE_DIRS}
)
# Main targets