From 2bb49b086de285086da6cd5050b5abd42aabf705 Mon Sep 17 00:00:00 2001 From: Marco Andorno Date: Mon, 16 Mar 2026 13:50:11 +0100 Subject: [PATCH 1/7] Fix copy_rtl_files --- cmake/utils/copy_rtl_files/copy_rtl_files.py | 26 ++++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/cmake/utils/copy_rtl_files/copy_rtl_files.py b/cmake/utils/copy_rtl_files/copy_rtl_files.py index ff49abd9..e75f133d 100644 --- a/cmake/utils/copy_rtl_files/copy_rtl_files.py +++ b/cmake/utils/copy_rtl_files/copy_rtl_files.py @@ -48,7 +48,7 @@ def main(): # Get the used files list from vhier try: - cells_output = subprocess.run([*vhier_base_args, '--cells'], capture_output=True, check=True) + cells_output = subprocess.run([*vhier_base_args, '--module-files'], capture_output=True, check=True) except subprocess.CalledProcessError as e: print(f"Fatal: error({e.returncode}): {e.stderr.decode('ascii')}", file=sys.stderr) raise @@ -94,13 +94,29 @@ def main(): print(f"Fatal: error({e.returncode}): {e.stderr.decode('ascii')}", file=sys.stderr) raise - output_inc = sorted(set([f.decode() for f in includes_output.stdout.split()])) + output_inc = sorted(set([ + line.strip() + for line in includes_output.stdout.decode().splitlines() + if line.strip() and not line.strip().startswith('/') + ])) - # Copy the include files in a include folder + # Resolve each include filename to a full path by searching inc_dirs dest_dir = os.path.join(args.outdir, 'include') os.makedirs(dest_dir, exist_ok=True) - for i in output_inc: - shutil.copy2(i, dest_dir) + + for inc_file in output_inc: + matches = [ + os.path.join(inc_dir, inc_file) + for inc_dir in args.inc_dirs + if os.path.isfile(os.path.join(inc_dir, inc_file)) + ] + if len(matches) == 0: + print(f"Fatal: include file '{inc_file}' not found in any include directory", file=sys.stderr) + raise FileNotFoundError(f"Include file not found: {inc_file}") + if len(matches) > 1: + print(f"Fatal: include file '{inc_file}' found in multiple include directories: {matches}", file=sys.stderr) + raise FileExistsError(f"Ambiguous include file: {inc_file}") + shutil.copy2(matches[0], dest_dir) if __name__ == "__main__": main() From b398eb8f18605a90266543c0a3050abe6c694910 Mon Sep 17 00:00:00 2001 From: Adrian Fiergolski Date: Mon, 16 Mar 2026 20:41:04 +0100 Subject: [PATCH 2/7] refactor(utils): replace copy_rtl_files with generate_sources_list - Remove copy_rtl_files.cmake and copy_rtl_files.py utilities - Add generate_sources_list.cmake and generate_sources_list.py using slang - Move and update read_rtl_sources.cmake for new source list format - Update SoCMakeConfig.cmake and tests to use new utilities --- SoCMakeConfig.cmake | 4 +- .../utils/copy_rtl_files/copy_rtl_files.cmake | 91 ------------- cmake/utils/copy_rtl_files/copy_rtl_files.py | 122 ------------------ .../generate_sources_list.cmake | 84 ++++++++++++ .../generate_sources_list.py | 56 ++++++++ .../read_rtl_sources.cmake | 0 6 files changed, 142 insertions(+), 215 deletions(-) delete mode 100644 cmake/utils/copy_rtl_files/copy_rtl_files.cmake delete mode 100644 cmake/utils/copy_rtl_files/copy_rtl_files.py create mode 100644 cmake/utils/generate_sources_list/generate_sources_list.cmake create mode 100644 cmake/utils/generate_sources_list/generate_sources_list.py rename cmake/utils/{copy_rtl_files => generate_sources_list}/read_rtl_sources.cmake (100%) diff --git a/SoCMakeConfig.cmake b/SoCMakeConfig.cmake index 8484c45d..f8850648 100644 --- a/SoCMakeConfig.cmake +++ b/SoCMakeConfig.cmake @@ -20,8 +20,8 @@ include("${CMAKE_CURRENT_LIST_DIR}/cmake/utils/uniquify_files_by_basename.cmake" # ==================================== # ======== Additional utilities ====== # ==================================== -include("${CMAKE_CURRENT_LIST_DIR}/cmake/utils/copy_rtl_files/copy_rtl_files.cmake") -include("${CMAKE_CURRENT_LIST_DIR}/cmake/utils/copy_rtl_files/read_rtl_sources.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/cmake/utils/generate_sources_list/generate_sources_list.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/cmake/utils/generate_sources_list/read_rtl_sources.cmake") include("${CMAKE_CURRENT_LIST_DIR}/cmake/utils/copy_rtl_files/vhier.cmake") # ==================================== diff --git a/cmake/utils/copy_rtl_files/copy_rtl_files.cmake b/cmake/utils/copy_rtl_files/copy_rtl_files.cmake deleted file mode 100644 index f631d6fd..00000000 --- a/cmake/utils/copy_rtl_files/copy_rtl_files.cmake +++ /dev/null @@ -1,91 +0,0 @@ -#[[[ -# This function copies the RTL sources of an IP to a given location. -# -# This function gets an IP_LIB target and get its RTL source files (exluding SIM/TB/FPGA files) and include directories and copy -# them to a default or given location. The output location contains a file listing all the sources, an include directory containing -# all the include files and the source files with a preserved hierarchy folder. It uses the vhier tool to parse and build the library -# hierachy and copy only the files instantiated in the hierarchy. -# vhier is part of a set of tools: -# https://github.com/gitpan/Verilog-Perl -# https://metacpan.org/pod/vhier -# -# :param IP_LIB: IP library to get RTL sources from. -# :type IP_LIB: string -# -# **Keyword Arguments** -# -# :keyword SYNTHESIS: Define SYNTHESIS, and ignore text between "ambit", "pragma", "synopsys" or "synthesis" translate_off and translate_on meta comments. -# :type SYNTHESIS: string -# :keyword OUTDIR: Change the default copy location ${CMAKE_BINARY_DIR}/ip_sources to OUTDIR. -# :type OUTDIR: string -# :keyword TOP_MODULE: Start the report at the specified module name, ignoring all modules that are not the one specified with --top-module or below, and report an error if the --top-module specified does not exist. -# :type TOP_MODULE: string -# :keyword SKIPLIST_FILE: Given file contains a list of regular expressions, one per line. If a module name in the design hierarchy matches one of these expressions, skip showing that module and any sub-hierarchy. -# :type SKIPLIST_FILE: string -#]] -function(copy_rtl_files IP_LIB) - cmake_parse_arguments(ARG "SYNTHESIS" "OUTDIR;TOP_MODULE;SKIPLIST_FILE" "" ${ARGN}) - if(ARG_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}") - endif() - - include("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../hwip.cmake") - - alias_dereference(IP_LIB ${IP_LIB}) - - if(NOT ARG_OUTDIR) - set(OUTDIR ${CMAKE_BINARY_DIR}/ip_sources) - else() - set(OUTDIR ${ARG_OUTDIR}) - endif() - - # Check if a top module is provided. In this case only the modules in its hierarchy are kept - if(ARG_TOP_MODULE) - set(TOP_MODULE_ARG --top-module ${ARG_TOP_MODULE}) - endif() - - if(ARG_SKIPLIST_FILE) - set(SKIPLIST_ARG --skiplist ${ARG_SKIPLIST_FILE}) - endif() - - if(ARG_SYNTHESIS) - set(SYNTHESIS_ARG --synthesis) - endif() - - # Get the list of RTL sources - get_ip_sources(RTL_SOURCES ${IP_LIB} SYSTEMVERILOG VERILOG) - get_ip_include_directories(RTL_INCDIRS ${IP_LIB} SYSTEMVERILOG) - foreach(_i ${RTL_INCDIRS}) - set(INCDIR_ARG ${INCDIR_ARG} --include ${_i}) - endforeach() - - find_python3() - set(__CMD ${Python3_EXECUTABLE} ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/copy_rtl_files.py - ${TOP_MODULE_ARG} ${SKIPLIST_ARG} ${SYNTHESIS_ARG} - --deps_dir ${FETCHCONTENT_BASE_DIR} - ${INCDIR_ARG} - --outdir ${OUTDIR} - ${RTL_SOURCES} - ) - - # # Call the Python script with the output directory and the RTL files - # set(STAMP_FILE "${CMAKE_BINARY_DIR}/${IP_LIB}_${CMAKE_CURRENT_FUNCTION}.stamp") - # add_custom_command( - # OUTPUT ${STAMP_FILE} - # COMMAND ${__CMD} - # COMMAND /bin/sh -c date > ${STAMP_FILE} - # COMMENT "Copying RTL files to ${OUTDIR}" - # VERBATIM - # ) - - # Create a target to run the custom command - add_custom_target( - ${IP_LIB}_copy_rtl - ALL # This forces the target to be run every time as outputs are not known in advance - COMMAND ${__CMD} - COMMENT "Copying RTL files to ${OUTDIR}" - DEPENDS ${IP_LIB} ${STAMP_FILE} - VERBATIM - ) - -endfunction() diff --git a/cmake/utils/copy_rtl_files/copy_rtl_files.py b/cmake/utils/copy_rtl_files/copy_rtl_files.py deleted file mode 100644 index e75f133d..00000000 --- a/cmake/utils/copy_rtl_files/copy_rtl_files.py +++ /dev/null @@ -1,122 +0,0 @@ -import argparse -import shutil -import subprocess -import os -import sys - -def make_parser(): - parser = argparse.ArgumentParser(description="Filter RTL files based on module hierarchy.") - parser.add_argument("--top-module", dest="top_module", action="store", help="Specify top module name") - parser.add_argument("--skiplist", dest="skiplist", action="store", help="Optional list of modules to skip") - parser.add_argument("--synthesis", dest="synthesis", action="store_true", help="Define SYNTHESIS") - parser.add_argument("--deps_dir", dest="deps_dir", action="store", default="", help="Base directory of the dependencies") - parser.add_argument("--include", dest="inc_dirs", action='append', type=str, help="Directories where to look for include files") - parser.add_argument('--outdir', dest='outdir', action='store', default='.', help='Output directory where files will be copied') - parser.add_argument('sources', metavar='FILE', nargs='+', type=str, help='List of RTL file paths') - return parser - - -def main(): - parser = make_parser() - args = parser.parse_args() - - # Check if vhier is available - try: - vhier = shutil.which('vhier') - if vhier is None: - raise FileNotFoundError - except FileNotFoundError: - print("Error: 'vhier' executable not found", file=sys.stderr) - - # Initialize the output list with all the packages, - # because they're not retained by vhier - output_src = [f for f in args.sources if "_pkg" in f] - - # Set common vhier arguments - top_module = ('--top-module', args.top_module) if args.top_module is not None else () - skiplist = ('--skiplist', args.skiplist) if args.skiplist is not None else () - synthesis = ('--synthesis',) if args.synthesis is not None else () - vhier_base_args = [ - vhier, - '--no-missing', - *top_module, - *skiplist, - *synthesis, - *[f'+incdir+{i}' for i in args.inc_dirs], - *args.sources, - ] - - # Get the used files list from vhier - try: - cells_output = subprocess.run([*vhier_base_args, '--module-files'], capture_output=True, check=True) - except subprocess.CalledProcessError as e: - print(f"Fatal: error({e.returncode}): {e.stderr.decode('ascii')}", file=sys.stderr) - raise - - output_src.extend(sorted(set([f.decode() for f in cells_output.stdout.split()]))) - - # Check if the output directory exists - if os.path.isdir(args.outdir): - # Clean everything inside if it exists - for filename in os.listdir(args.outdir): - file_path = os.path.join(args.outdir, filename) - try: - if os.path.isfile(file_path) or os.path.islink(file_path): - os.unlink(file_path) - elif os.path.isdir(file_path): - shutil.rmtree(file_path) - except Exception as e: - print('Failed to delete %s. Reason: %s' % (file_path, e)) - else: - # Create the directory - os.makedirs(args.outdir, exist_ok=False) - - # Copy files to output directory - copied_src = [] - for i in output_src: - if args.deps_dir in i: - dest_dir = os.path.join(args.outdir, i.replace(args.deps_dir, '').split('/')[1].rsplit('-', 1)[0]) - else: - dest_dir = args.outdir - os.makedirs(dest_dir, exist_ok=True) - copied_src.append(shutil.copy2(i, dest_dir)) - - # Write copied files list to outdir - with open(os.path.join(args.outdir, 'rtl_sources.f'), 'w') as outfile: - for file_path in copied_src: - # Keep only the relative path not to be user dependent - outfile.write(f'{os.path.relpath(file_path, args.outdir)}\n') - - # Get the includes list from vhier - try: - includes_output = subprocess.run([*vhier_base_args, '--includes'], capture_output=True, check=True) - except subprocess.CalledProcessError as e: - print(f"Fatal: error({e.returncode}): {e.stderr.decode('ascii')}", file=sys.stderr) - raise - - output_inc = sorted(set([ - line.strip() - for line in includes_output.stdout.decode().splitlines() - if line.strip() and not line.strip().startswith('/') - ])) - - # Resolve each include filename to a full path by searching inc_dirs - dest_dir = os.path.join(args.outdir, 'include') - os.makedirs(dest_dir, exist_ok=True) - - for inc_file in output_inc: - matches = [ - os.path.join(inc_dir, inc_file) - for inc_dir in args.inc_dirs - if os.path.isfile(os.path.join(inc_dir, inc_file)) - ] - if len(matches) == 0: - print(f"Fatal: include file '{inc_file}' not found in any include directory", file=sys.stderr) - raise FileNotFoundError(f"Include file not found: {inc_file}") - if len(matches) > 1: - print(f"Fatal: include file '{inc_file}' found in multiple include directories: {matches}", file=sys.stderr) - raise FileExistsError(f"Ambiguous include file: {inc_file}") - shutil.copy2(matches[0], dest_dir) - -if __name__ == "__main__": - main() diff --git a/cmake/utils/generate_sources_list/generate_sources_list.cmake b/cmake/utils/generate_sources_list/generate_sources_list.cmake new file mode 100644 index 00000000..44f6a85f --- /dev/null +++ b/cmake/utils/generate_sources_list/generate_sources_list.cmake @@ -0,0 +1,84 @@ +#[[[ +# Generates a filtered and organized list of RTL (Register Transfer Level) source files for a specified IP library target. +# +# This function collects all relevant RTL source files (excluding simulation, testbench, and FPGA-specific files) associated +# with the given ~IP_LIB~ target. It produces a file containing: +# * All source files required for synthesis, preserving their directory hierarchy. +# * All include directories and files needed for compilation. +# * Only the files instantiated in the design hierarchy, as determined by the `slang` tool. +# +# The hierarchy is parsed using `slang` (https://github.com/MikePopoloski/slang), ensuring that only the necessary +# files for the specified top module (if provided) and its dependencies are included. +# +# :param IP_LIB: Name of the IP library target to analyze. +# :type IP_LIB: string +# +# **Keyword Arguments** +# :keyword SYNTHESIS: (Optional) If specified, defines SYNTHESIS macro while parsing the HDL sources. +# :type SYNTHESIS: boolean +# :keyword OUTDIR: (Optional) Output directory for the copied RTL sources. Defaults to ${CMAKE_BINARY_DIR}/ip_sources +# :type OUTDIR: string +# :keyword TOP_MODULE: (Optional) Name of the top module to use as the root of the hierarchy. Only modules below this point are included. An error is reported if the specified module does not exist. +# :type TOP_MODULE: string +#]] +function(generate_sources_list IP_LIB) + cmake_parse_arguments(ARG "SYNTHESIS" "OUTDIR;TOP_MODULE" "" ${ARGN}) + if(ARG_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}") + endif() + + # Initialize variables + set(INCDIR_ARG "") + set(TOP_MODULE_ARG "") + set(SYNTHESIS_ARG "") + + # Check if the Python script exists + if(NOT EXISTS "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/generate_sources_list.py") + message(FATAL_ERROR "generate_sources_list.py not found!") + endif() + + include("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../hwip.cmake") + + alias_dereference(IP_LIB ${IP_LIB}) + + if(NOT ARG_OUTDIR) + set(OUTDIR ${CMAKE_BINARY_DIR}/ip_sources) + else() + set(OUTDIR ${ARG_OUTDIR}) + endif() + + # If a top module is provided, only modules in its hierarchy are included. + if(ARG_TOP_MODULE) + set(TOP_MODULE_ARG --top-module ${ARG_TOP_MODULE}) + endif() + + # Get the list of RTL sources + get_ip_sources(RTL_SOURCES ${IP_LIB} SYSTEMVERILOG VERILOG) + get_ip_include_directories(RTL_INCDIRS ${IP_LIB} SYSTEMVERILOG) + foreach(_i ${RTL_INCDIRS}) + set(INCDIR_ARG ${INCDIR_ARG} --include ${_i}) + endforeach() + + if(ARG_SYNTHESIS) + set(SYNTHESIS_ARG --synthesis) + endif() + + find_python3() + set(__CMD ${Python3_EXECUTABLE} ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/generate_sources_list.py + ${TOP_MODULE_ARG} ${SYNTHESIS_ARG} + ${INCDIR_ARG} + --outdir ${OUTDIR} + ${RTL_SOURCES} + ) + + # Create a target to run the custom command + add_custom_target( + ${IP_LIB}_source_list + ALL # This forces the target to be run every time as outputs are not known in advance + COMMAND ${__CMD} + COMMENT "Generating list of the RTL source files in ${OUTDIR}" + DEPENDS ${IP_LIB} + VERBATIM + ) + +endfunction() diff --git a/cmake/utils/generate_sources_list/generate_sources_list.py b/cmake/utils/generate_sources_list/generate_sources_list.py new file mode 100644 index 00000000..89391959 --- /dev/null +++ b/cmake/utils/generate_sources_list/generate_sources_list.py @@ -0,0 +1,56 @@ +import argparse +import shutil +import subprocess +import os +import sys + +def make_parser(): + parser = argparse.ArgumentParser(description="Filter RTL files based on module hierarchy.") + parser.add_argument("--top-module", dest="top_module", action="store", help="Specify top module name") + parser.add_argument("--synthesis", dest="synthesis", action="store_true", help="Define SYNTHESIS") + parser.add_argument("--include", dest="inc_dirs", action='append', type=str, help="Directories where to look for include files") + parser.add_argument('--outdir', dest='outdir', action='store', default='.', help='Output directory where files will be copied') + parser.add_argument('sources', metavar='FILE', nargs='+', type=str, help='List of RTL file paths') + return parser + + +def main(): + parser = make_parser() + args = parser.parse_args() + + # Check if slang is available + slang = shutil.which('slang') + if slang is None: + print("Error: 'slang' executable not found", file=sys.stderr) + sys.exit(1) + + # Initialize inc_dirs if not defined + if args.inc_dirs is None: + args.inc_dirs = [] + + # Set common slang arguments + top_module = ('--top', args.top_module) if args.top_module is not None else () + synthesis = ('-DSYNTHESIS',) if args.synthesis else () + + # Create the output directory + os.makedirs(args.outdir, exist_ok=True) + output_file = os.path.join(args.outdir, 'rtl_sources.f') + + slang_base_args = [ + slang, + '--depfile-trim', '--Mall', output_file, + *top_module, + *synthesis, + *['-I' + ','.join(args.inc_dirs)], + *args.sources, + ] + + # Get the used files list from slang + try: + subprocess.run([*slang_base_args], capture_output=True, check=True) + except subprocess.CalledProcessError as e: + print(f"Fatal: error({e.returncode}): {e.stderr.decode('utf-8', errors='replace')}", file=sys.stderr) + raise + +if __name__ == "__main__": + main() diff --git a/cmake/utils/copy_rtl_files/read_rtl_sources.cmake b/cmake/utils/generate_sources_list/read_rtl_sources.cmake similarity index 100% rename from cmake/utils/copy_rtl_files/read_rtl_sources.cmake rename to cmake/utils/generate_sources_list/read_rtl_sources.cmake From 132980342006f39cb3c5f9e69b187a3ce8d42648 Mon Sep 17 00:00:00 2001 From: Adrian Fiergolski Date: Mon, 16 Mar 2026 20:42:18 +0100 Subject: [PATCH 3/7] chore: remove vhier and related CMake integration - Remove vhier.cmake and its inclusion from SoCMakeConfig.cmake - Remove vhier module source files and submodule definitions - Delete vhier test directory, CMakeLists, and golden.xml - Update tests CMakeLists to drop vhier subdirectory --- SoCMakeConfig.cmake | 1 - cmake/utils/copy_rtl_files/vhier.cmake | 54 ------------------- tests/tests/CMakeLists.txt | 1 - tests/tests/vhier/CMakeLists.txt | 31 ----------- tests/tests/vhier/golden.xml | 12 ----- tests/tests/vhier/ips/mod1/CMakeLists.txt | 18 ------- .../vhier/ips/mod1/ips/submod1/CMakeLists.txt | 13 ----- .../vhier/ips/mod1/ips/submod1/rtl/submod1.sv | 4 -- .../vhier/ips/mod1/ips/submod2/CMakeLists.txt | 13 ----- .../vhier/ips/mod1/ips/submod2/rtl/submod2.sv | 5 -- tests/tests/vhier/ips/mod1/rtl/mod1.sv | 5 -- tests/tests/vhier/rtl/top.sv | 5 -- 12 files changed, 162 deletions(-) delete mode 100644 cmake/utils/copy_rtl_files/vhier.cmake delete mode 100644 tests/tests/vhier/CMakeLists.txt delete mode 100644 tests/tests/vhier/golden.xml delete mode 100644 tests/tests/vhier/ips/mod1/CMakeLists.txt delete mode 100644 tests/tests/vhier/ips/mod1/ips/submod1/CMakeLists.txt delete mode 100644 tests/tests/vhier/ips/mod1/ips/submod1/rtl/submod1.sv delete mode 100644 tests/tests/vhier/ips/mod1/ips/submod2/CMakeLists.txt delete mode 100644 tests/tests/vhier/ips/mod1/ips/submod2/rtl/submod2.sv delete mode 100644 tests/tests/vhier/ips/mod1/rtl/mod1.sv delete mode 100644 tests/tests/vhier/rtl/top.sv diff --git a/SoCMakeConfig.cmake b/SoCMakeConfig.cmake index f8850648..adcf0377 100644 --- a/SoCMakeConfig.cmake +++ b/SoCMakeConfig.cmake @@ -22,7 +22,6 @@ include("${CMAKE_CURRENT_LIST_DIR}/cmake/utils/uniquify_files_by_basename.cmake" # ==================================== include("${CMAKE_CURRENT_LIST_DIR}/cmake/utils/generate_sources_list/generate_sources_list.cmake") include("${CMAKE_CURRENT_LIST_DIR}/cmake/utils/generate_sources_list/read_rtl_sources.cmake") -include("${CMAKE_CURRENT_LIST_DIR}/cmake/utils/copy_rtl_files/vhier.cmake") # ==================================== # ======== Simulation ================ diff --git a/cmake/utils/copy_rtl_files/vhier.cmake b/cmake/utils/copy_rtl_files/vhier.cmake deleted file mode 100644 index 2dbd9682..00000000 --- a/cmake/utils/copy_rtl_files/vhier.cmake +++ /dev/null @@ -1,54 +0,0 @@ -function(vhier IP_LIB) - cmake_parse_arguments(ARG "XML;FILES;MODULES;FOREST" "TOP_MODULE" "" ${ARGN}) - if(ARG_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}") - endif() - - include("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../hwip.cmake") - alias_dereference(IP_LIB ${IP_LIB}) - - get_target_property(IP_NAME ${IP_LIB} IP_NAME) - - get_ip_sources(RTL_SOURCES ${IP_LIB} SYSTEMVERILOG VERILOG) - get_ip_include_directories(INCDIRS ${IP_LIB} SYSTEMVERILOG VERILOG) - foreach(_i ${INCDIRS}) - set(INCDIR_ARG ${INCDIR_ARG} -y ${_i}) - endforeach() - - get_ip_compile_definitions(COMP_DEFS ${IP_LIB} SYSTEMVERILOG VERILOG) - foreach(_d ${COMP_DEFS}) - set(COMPDEF_ARG ${COMPDEF_ARG} -D${_d}) - endforeach() - - find_program(VHIER_EXECUTABLE vhier) - set(__CMD ${VHIER_EXECUTABLE} - --top-module $,${ARG_TOP_MODULE},${IP_NAME}> - ${RTL_SOURCES} - ${INCDIR_ARG} - ${COMPDEF_ARG} - $<$:--xml> - $<$:--module-files> - $<$:--modules> - $<$:--forest> - ) - - set(DESCRIPTION "Extract verilog hierarchy of ${IP_LIB} with ${CMAKE_CURRENT_FUNCTION}") - - set(OUT_FILE ${CMAKE_BINARY_DIR}/${IP_LIB}_${CMAKE_CURRENT_FUNCTION}.$,xml,txt>) - set(STAMP_FILE "${CMAKE_BINARY_DIR}/${IP_LIB}_${CMAKE_CURRENT_FUNCTION}.stamp") - add_custom_command( - OUTPUT ${STAMP_FILE} ${OUT_FILE} - COMMAND touch ${STAMP_FILE} - COMMAND ${__CMD} | tee ${OUT_FILE} - DEPENDS ${RTL_SOURCES} ${IP_LIB} - COMMENT ${DESCRIPTION} - ) - - add_custom_target( - ${IP_LIB}_${CMAKE_CURRENT_FUNCTION} - DEPENDS ${IP_LIB} ${STAMP_FILE} ${OUT_FILE} - ) - - set_property(TARGET ${IP_LIB}_${CMAKE_CURRENT_FUNCTION} PROPERTY DESCRIPTION ${DESCRIPTION}) -endfunction() - diff --git a/tests/tests/CMakeLists.txt b/tests/tests/CMakeLists.txt index 2dd24372..cf652c59 100644 --- a/tests/tests/CMakeLists.txt +++ b/tests/tests/CMakeLists.txt @@ -14,7 +14,6 @@ add_custom_target(check_cdash ) add_subdirectory(iverilog) -add_subdirectory(vhier) add_subdirectory(peakrdl) include("getcmaketest.cmake") diff --git a/tests/tests/vhier/CMakeLists.txt b/tests/tests/vhier/CMakeLists.txt deleted file mode 100644 index 28923830..00000000 --- a/tests/tests/vhier/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -include("../../../SoCMakeConfig.cmake") - -cmake_minimum_required(VERSION 3.25) -project(vhier_test) - -add_subdirectory("ips/mod1") - -add_ip(top - VENDOR test - LIBRARY ip - VERSION 0.0.1 - ) - -ip_sources(${IP} SYSTEMVERILOG - ${CMAKE_CURRENT_LIST_DIR}/rtl/top.sv - ) - -ip_include_directories(${IP} SYSTEMVERILOG - ${CMAKE_CURRENT_LIST_DIR}/rtl - ) - -ip_link(${IP} test::ip::mod1) - -vhier(${IP} FILES MODULES XML) - -include(CTest) - -add_test(NAME ${PROJECT_NAME} - COMMAND /bin/bash -c "make ${IP}_vhier && sed -i 's#${CMAKE_CURRENT_LIST_DIR}/##g' ${CMAKE_BINARY_DIR}/${IP}_vhier.xml && diff ${CMAKE_BINARY_DIR}/${IP}_vhier.xml ${CMAKE_CURRENT_LIST_DIR}/golden.xml" - # Need to do sed to make relative file paths, because of the golden.xml that was generated (and sed) on my filesystem, in CI it would be different - ) diff --git a/tests/tests/vhier/golden.xml b/tests/tests/vhier/golden.xml deleted file mode 100644 index fa685dce..00000000 --- a/tests/tests/vhier/golden.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - rtl/top.sv - ips/mod1/rtl/mod1.sv - ips/mod1/ips/submod1/rtl/submod1.sv - - diff --git a/tests/tests/vhier/ips/mod1/CMakeLists.txt b/tests/tests/vhier/ips/mod1/CMakeLists.txt deleted file mode 100644 index 57c48bc9..00000000 --- a/tests/tests/vhier/ips/mod1/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -add_ip(mod1 - VENDOR test - LIBRARY ip - VERSION 0.0.1 - ) - -add_subdirectory("./ips/submod1/") -add_subdirectory("./ips/submod2/") - -ip_sources(${IP} SYSTEMVERILOG - ${CMAKE_CURRENT_LIST_DIR}/rtl/mod1.sv - ) - -ip_include_directories(${IP} SYSTEMVERILOG - ${CMAKE_CURRENT_LIST_DIR}/rtl - ) - -ip_link(${IP} test::ip::submod1 test::ip::submod2) diff --git a/tests/tests/vhier/ips/mod1/ips/submod1/CMakeLists.txt b/tests/tests/vhier/ips/mod1/ips/submod1/CMakeLists.txt deleted file mode 100644 index 30df0d68..00000000 --- a/tests/tests/vhier/ips/mod1/ips/submod1/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -add_ip(submod1 - VENDOR test - LIBRARY ip - VERSION 0.0.1 - ) - -ip_sources(${IP} SYSTEMVERILOG - ${CMAKE_CURRENT_LIST_DIR}/rtl/submod1.sv - ) - -ip_include_directories(${IP} SYSTEMVERILOG - ${CMAKE_CURRENT_LIST_DIR}/rtl - ) diff --git a/tests/tests/vhier/ips/mod1/ips/submod1/rtl/submod1.sv b/tests/tests/vhier/ips/mod1/ips/submod1/rtl/submod1.sv deleted file mode 100644 index 2d6a785f..00000000 --- a/tests/tests/vhier/ips/mod1/ips/submod1/rtl/submod1.sv +++ /dev/null @@ -1,4 +0,0 @@ -module submod1; - -endmodule; - diff --git a/tests/tests/vhier/ips/mod1/ips/submod2/CMakeLists.txt b/tests/tests/vhier/ips/mod1/ips/submod2/CMakeLists.txt deleted file mode 100644 index 58890c34..00000000 --- a/tests/tests/vhier/ips/mod1/ips/submod2/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -add_ip(submod2 - VENDOR test - LIBRARY ip - VERSION 0.0.1 - ) - -ip_sources(${IP} SYSTEMVERILOG - ${CMAKE_CURRENT_LIST_DIR}/rtl/submod2.sv - ) - -ip_include_directories(${IP} SYSTEMVERILOG - ${CMAKE_CURRENT_LIST_DIR}/rtl - ) diff --git a/tests/tests/vhier/ips/mod1/ips/submod2/rtl/submod2.sv b/tests/tests/vhier/ips/mod1/ips/submod2/rtl/submod2.sv deleted file mode 100644 index 69f861f0..00000000 --- a/tests/tests/vhier/ips/mod1/ips/submod2/rtl/submod2.sv +++ /dev/null @@ -1,5 +0,0 @@ -module submod2; - -endmodule; - - diff --git a/tests/tests/vhier/ips/mod1/rtl/mod1.sv b/tests/tests/vhier/ips/mod1/rtl/mod1.sv deleted file mode 100644 index dbac705a..00000000 --- a/tests/tests/vhier/ips/mod1/rtl/mod1.sv +++ /dev/null @@ -1,5 +0,0 @@ -module mod1; - - submod1 submod1_i(); - -endmodule; diff --git a/tests/tests/vhier/rtl/top.sv b/tests/tests/vhier/rtl/top.sv deleted file mode 100644 index a3c0d65c..00000000 --- a/tests/tests/vhier/rtl/top.sv +++ /dev/null @@ -1,5 +0,0 @@ -module top; - - mod1 mod1_i(); - -endmodule; From ceb38e29a74f60be41e1bdba10101f00fc52b9d1 Mon Sep 17 00:00:00 2001 From: Adrian Fiergolski Date: Tue, 17 Mar 2026 15:06:13 +0100 Subject: [PATCH 4/7] fix(generate_sources_list): split output into rtl and include sources files - Generate separate rtl_sources.f and include_sources.f files - Update slang arguments to use --Mmodule and --Minclude options --- cmake/utils/generate_sources_list/generate_sources_list.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmake/utils/generate_sources_list/generate_sources_list.py b/cmake/utils/generate_sources_list/generate_sources_list.py index 89391959..f64e9be6 100644 --- a/cmake/utils/generate_sources_list/generate_sources_list.py +++ b/cmake/utils/generate_sources_list/generate_sources_list.py @@ -34,11 +34,12 @@ def main(): # Create the output directory os.makedirs(args.outdir, exist_ok=True) - output_file = os.path.join(args.outdir, 'rtl_sources.f') + rtl_file = os.path.join(args.outdir, 'rtl_sources.f') + include_file = os.path.join(args.outdir, 'include_sources.f') slang_base_args = [ slang, - '--depfile-trim', '--Mall', output_file, + '--depfile-trim', '--Mmodule', rtl_file, '--Minclude', include_file, *top_module, *synthesis, *['-I' + ','.join(args.inc_dirs)], From 2bcf95c11147d303e4645f35f261f3ca26a87bc2 Mon Sep 17 00:00:00 2001 From: Adrian Fiergolski Date: Thu, 19 Mar 2026 14:50:33 +0100 Subject: [PATCH 5/7] refactor(generate_sources_list): replace Python script with direct slang invocation in CMake It follows @Risto97 feedback in the MR [1] - Remove generate_sources_list.py and its invocation - Integrate slang command directly into CMake function - Add checks for slang executable and improve error messages - Use add_custom_command and add_custom_target for output generation - Update argument handling for top module and synthesis options [1] https://github.com/HEP-SoC/SoCMake/pull/198#issuecomment-4085503120 --- .../generate_sources_list.cmake | 110 ++++++++++-------- .../generate_sources_list.py | 57 --------- 2 files changed, 62 insertions(+), 105 deletions(-) delete mode 100644 cmake/utils/generate_sources_list/generate_sources_list.py diff --git a/cmake/utils/generate_sources_list/generate_sources_list.cmake b/cmake/utils/generate_sources_list/generate_sources_list.cmake index 44f6a85f..c9c5baed 100644 --- a/cmake/utils/generate_sources_list/generate_sources_list.cmake +++ b/cmake/utils/generate_sources_list/generate_sources_list.cmake @@ -22,63 +22,77 @@ # :type TOP_MODULE: string #]] function(generate_sources_list IP_LIB) - cmake_parse_arguments(ARG "SYNTHESIS" "OUTDIR;TOP_MODULE" "" ${ARGN}) - if(ARG_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}") - endif() + cmake_parse_arguments(ARG "SYNTHESIS" "OUTDIR;TOP_MODULE" "" ${ARGN}) + if(ARG_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}") + endif() - # Initialize variables - set(INCDIR_ARG "") - set(TOP_MODULE_ARG "") - set(SYNTHESIS_ARG "") + # Find slang executable + find_program(SLANG_EXECUTABLE slang) + if(NOT SLANG_EXECUTABLE) + message(FATAL_ERROR "slang executable not found! Please install slang or set SLANG_EXECUTABLE.") + endif() - # Check if the Python script exists - if(NOT EXISTS "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/generate_sources_list.py") - message(FATAL_ERROR "generate_sources_list.py not found!") - endif() + # Initialize variables + set(INCDIR_ARG "") + set(TOP_MODULE_ARG "") + set(SYNTHESIS_ARG "") - include("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../hwip.cmake") + include("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../hwip.cmake") + alias_dereference(IP_LIB ${IP_LIB}) - alias_dereference(IP_LIB ${IP_LIB}) + if(NOT ARG_OUTDIR) + set(OUTDIR ${CMAKE_BINARY_DIR}/ip_sources) + else() + set(OUTDIR ${ARG_OUTDIR}) + endif() - if(NOT ARG_OUTDIR) - set(OUTDIR ${CMAKE_BINARY_DIR}/ip_sources) - else() - set(OUTDIR ${ARG_OUTDIR}) - endif() + # If a top module is provided, only modules in its hierarchy are included. + if(ARG_TOP_MODULE) + list(APPEND TOP_MODULE_ARG --top ${ARG_TOP_MODULE}) + endif() - # If a top module is provided, only modules in its hierarchy are included. - if(ARG_TOP_MODULE) - set(TOP_MODULE_ARG --top-module ${ARG_TOP_MODULE}) - endif() + # Get the list of RTL sources + get_ip_sources(RTL_SOURCES ${IP_LIB} SYSTEMVERILOG VERILOG) + get_ip_include_directories(RTL_INCDIRS ${IP_LIB} SYSTEMVERILOG) + foreach(_i ${RTL_INCDIRS}) + list(APPEND INCDIR_ARG -I${_i}) + endforeach() - # Get the list of RTL sources - get_ip_sources(RTL_SOURCES ${IP_LIB} SYSTEMVERILOG VERILOG) - get_ip_include_directories(RTL_INCDIRS ${IP_LIB} SYSTEMVERILOG) - foreach(_i ${RTL_INCDIRS}) - set(INCDIR_ARG ${INCDIR_ARG} --include ${_i}) - endforeach() + if(ARG_SYNTHESIS) + list(APPEND SYNTHESIS_ARGS -DSYNTHESIS) + endif() - if(ARG_SYNTHESIS) - set(SYNTHESIS_ARG --synthesis) - endif() + set(RTL_FILE ${OUTDIR}/rtl_sources.f) + set(INCLUDE_FILE ${OUTDIR}/include_sources.f) + file(MAKE_DIRECTORY ${OUTDIR}) - find_python3() - set(__CMD ${Python3_EXECUTABLE} ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/generate_sources_list.py - ${TOP_MODULE_ARG} ${SYNTHESIS_ARG} - ${INCDIR_ARG} - --outdir ${OUTDIR} - ${RTL_SOURCES} - ) + set(SLANG_CMD + ${SLANG_EXECUTABLE} + --depfile-trim --Mmodule ${RTL_FILE} --Minclude ${INCLUDE_FILE} + ${TOP_MODULE_ARG} + ${SYNTHESIS_ARG} + ${INCDIR_ARG} + ${RTL_SOURCES} + ) - # Create a target to run the custom command - add_custom_target( - ${IP_LIB}_source_list - ALL # This forces the target to be run every time as outputs are not known in advance - COMMAND ${__CMD} - COMMENT "Generating list of the RTL source files in ${OUTDIR}" - DEPENDS ${IP_LIB} - VERBATIM - ) + get_ip_links(DEPENDENT_TARGETS ${IP_LIB}) + + add_custom_command( + OUTPUT ${RTL_FILE} ${INCLUDE_FILE} + COMMAND ${SLANG_CMD} + DEPENDS ${DEPENDENT_TARGETS} ${RTL_SOURCES} + COMMENT "Generating list of the RTL source files in ${OUTDIR}" + VERBATIM + ) + + add_custom_target( + ${IP_LIB}_source_list + DEPENDS ${RTL_FILE} ${INCLUDE_FILE} + COMMENT "Target for generating filtered RTL source list for ${IP_LIB}" + VERBATIM + ) + + message(STATUS "To generate RTL source list for ${IP_LIB}, build the target: ${IP_LIB}_source_list") endfunction() diff --git a/cmake/utils/generate_sources_list/generate_sources_list.py b/cmake/utils/generate_sources_list/generate_sources_list.py deleted file mode 100644 index f64e9be6..00000000 --- a/cmake/utils/generate_sources_list/generate_sources_list.py +++ /dev/null @@ -1,57 +0,0 @@ -import argparse -import shutil -import subprocess -import os -import sys - -def make_parser(): - parser = argparse.ArgumentParser(description="Filter RTL files based on module hierarchy.") - parser.add_argument("--top-module", dest="top_module", action="store", help="Specify top module name") - parser.add_argument("--synthesis", dest="synthesis", action="store_true", help="Define SYNTHESIS") - parser.add_argument("--include", dest="inc_dirs", action='append', type=str, help="Directories where to look for include files") - parser.add_argument('--outdir', dest='outdir', action='store', default='.', help='Output directory where files will be copied') - parser.add_argument('sources', metavar='FILE', nargs='+', type=str, help='List of RTL file paths') - return parser - - -def main(): - parser = make_parser() - args = parser.parse_args() - - # Check if slang is available - slang = shutil.which('slang') - if slang is None: - print("Error: 'slang' executable not found", file=sys.stderr) - sys.exit(1) - - # Initialize inc_dirs if not defined - if args.inc_dirs is None: - args.inc_dirs = [] - - # Set common slang arguments - top_module = ('--top', args.top_module) if args.top_module is not None else () - synthesis = ('-DSYNTHESIS',) if args.synthesis else () - - # Create the output directory - os.makedirs(args.outdir, exist_ok=True) - rtl_file = os.path.join(args.outdir, 'rtl_sources.f') - include_file = os.path.join(args.outdir, 'include_sources.f') - - slang_base_args = [ - slang, - '--depfile-trim', '--Mmodule', rtl_file, '--Minclude', include_file, - *top_module, - *synthesis, - *['-I' + ','.join(args.inc_dirs)], - *args.sources, - ] - - # Get the used files list from slang - try: - subprocess.run([*slang_base_args], capture_output=True, check=True) - except subprocess.CalledProcessError as e: - print(f"Fatal: error({e.returncode}): {e.stderr.decode('utf-8', errors='replace')}", file=sys.stderr) - raise - -if __name__ == "__main__": - main() From a3247ed1e1a1b96b0f46d95842b703c9dcf80315 Mon Sep 17 00:00:00 2001 From: Adrian Fiergolski Date: Fri, 20 Mar 2026 10:38:50 +0100 Subject: [PATCH 6/7] docs(generate_sources_list): clarify OUTDIR keyword description in comments --- cmake/utils/generate_sources_list/generate_sources_list.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/utils/generate_sources_list/generate_sources_list.cmake b/cmake/utils/generate_sources_list/generate_sources_list.cmake index c9c5baed..84952560 100644 --- a/cmake/utils/generate_sources_list/generate_sources_list.cmake +++ b/cmake/utils/generate_sources_list/generate_sources_list.cmake @@ -16,7 +16,7 @@ # **Keyword Arguments** # :keyword SYNTHESIS: (Optional) If specified, defines SYNTHESIS macro while parsing the HDL sources. # :type SYNTHESIS: boolean -# :keyword OUTDIR: (Optional) Output directory for the copied RTL sources. Defaults to ${CMAKE_BINARY_DIR}/ip_sources +# :keyword OUTDIR: (Optional) Output directory for the generated file lists. Defaults to ${CMAKE_BINARY_DIR}/ip_sources # :type OUTDIR: string # :keyword TOP_MODULE: (Optional) Name of the top module to use as the root of the hierarchy. Only modules below this point are included. An error is reported if the specified module does not exist. # :type TOP_MODULE: string From 4fd034f9a2eb3f2e7e8100e61695026f829221ba Mon Sep 17 00:00:00 2001 From: Adrian Fiergolski Date: Fri, 20 Mar 2026 10:39:47 +0100 Subject: [PATCH 7/7] feat(generate_sources_list): add SLANG_ARGS option for extra slang arguments It follows @Risto97 feedback in MR [1]. - Introduce SLANG_ARGS keyword argument to pass extra arguments to slang - Remove deprecated SYNTHESIS option and related code - Update argument parsing and variable handling for new option [1] https://github.com/HEP-SoC/SoCMake/pull/198#issuecomment-4092478118 --- .../generate_sources_list.cmake | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cmake/utils/generate_sources_list/generate_sources_list.cmake b/cmake/utils/generate_sources_list/generate_sources_list.cmake index 84952560..07e2eede 100644 --- a/cmake/utils/generate_sources_list/generate_sources_list.cmake +++ b/cmake/utils/generate_sources_list/generate_sources_list.cmake @@ -14,15 +14,15 @@ # :type IP_LIB: string # # **Keyword Arguments** -# :keyword SYNTHESIS: (Optional) If specified, defines SYNTHESIS macro while parsing the HDL sources. -# :type SYNTHESIS: boolean # :keyword OUTDIR: (Optional) Output directory for the generated file lists. Defaults to ${CMAKE_BINARY_DIR}/ip_sources # :type OUTDIR: string # :keyword TOP_MODULE: (Optional) Name of the top module to use as the root of the hierarchy. Only modules below this point are included. An error is reported if the specified module does not exist. # :type TOP_MODULE: string +# :keyword SLANG_ARGS: (Optional) Extra arguments to pass directly to slang. +# :type SLANG_ARGS: list #]] function(generate_sources_list IP_LIB) - cmake_parse_arguments(ARG "SYNTHESIS" "OUTDIR;TOP_MODULE" "" ${ARGN}) + cmake_parse_arguments(ARG "" "OUTDIR;TOP_MODULE;SLANG_ARGS" "" ${ARGN}) if(ARG_UNPARSED_ARGUMENTS) message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}") endif() @@ -34,9 +34,9 @@ function(generate_sources_list IP_LIB) endif() # Initialize variables - set(INCDIR_ARG "") - set(TOP_MODULE_ARG "") - set(SYNTHESIS_ARG "") + set(INCDIR_ARG) + set(TOP_MODULE_ARG) + set(USER_SLANG_ARGS) include("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../hwip.cmake") alias_dereference(IP_LIB ${IP_LIB}) @@ -59,8 +59,8 @@ function(generate_sources_list IP_LIB) list(APPEND INCDIR_ARG -I${_i}) endforeach() - if(ARG_SYNTHESIS) - list(APPEND SYNTHESIS_ARGS -DSYNTHESIS) + if(ARG_SLANG_ARGS) + list(APPEND USER_SLANG_ARGS ${ARG_SLANG_ARGS}) endif() set(RTL_FILE ${OUTDIR}/rtl_sources.f) @@ -71,8 +71,8 @@ function(generate_sources_list IP_LIB) ${SLANG_EXECUTABLE} --depfile-trim --Mmodule ${RTL_FILE} --Minclude ${INCLUDE_FILE} ${TOP_MODULE_ARG} - ${SYNTHESIS_ARG} ${INCDIR_ARG} + ${USER_SLANG_ARGS} ${RTL_SOURCES} )