diff --git a/.ci/fpga/scripts/cleanup_incomplete_ip_builds.py b/.ci/fpga/scripts/cleanup_incomplete_ip_builds.py deleted file mode 100644 index 75c08db72..000000000 --- a/.ci/fpga/scripts/cleanup_incomplete_ip_builds.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2021 Ettus Research, a National Instruments Brand -# -# SPDX-License-Identifier: LGPL-3.0-or-later -# -# Description: -# -# Our pipelines reuse IP builds to save time. In the case where an IP build -# fails or is terminated before completion, it is sometimes necessary to -# clean up the build so that the next build can complete properly. This -# script searches for and deletes any incomplete IP builds. -# - -import argparse -import os -import shutil - -# argument parsing -parser = argparse.ArgumentParser(description="This script removes all directories where the .build_lock file still exists") -parser.add_argument('--directory', '-d', required=True, help='directory to search for lock files (recursively)') -args = parser.parse_args() - -# search .build_lock files -lockFiles = [] -for root, dirs, files in os.walk(args.directory): - for file in files: - if file == ".build_lock": - lockFiles.append(os.path.join(root, file)) - -# remove all directories containing lock files -for lockFile in lockFiles: - dirPath = os.path.dirname(lockFile) - print("delete " + dirPath) - shutil.rmtree(dirPath) diff --git a/.ci/fpga/scripts/merge_modelsim_ini.py b/.ci/fpga/scripts/merge_modelsim_ini.py new file mode 100755 index 000000000..8e90e7367 --- /dev/null +++ b/.ci/fpga/scripts/merge_modelsim_ini.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +""" +Copyright 2025 Ettus Research, a National Instruments Brand + +SPDX-License-Identifier: LGPL-3.0-or-later + +Merge multiple INI files into a single one. +""" + +import configparser +import argparse + +parser = argparse.ArgumentParser(description=__doc__) +parser.add_argument('files', type=str, nargs='+', help='a list of INI files to merge') +parser.add_argument('-o', '--output', type=str, default='modelsim.ini', help='the output file name') +args = parser.parse_args() + +config = configparser.ConfigParser() +config.read(args.files) + +with open(args.output, 'w') as configfile: + config.write(configfile) diff --git a/.ci/fpga/scripts/run_setup.sh b/.ci/fpga/scripts/run_setup.sh index ee53b5c01..144917e1a 100644 --- a/.ci/fpga/scripts/run_setup.sh +++ b/.ci/fpga/scripts/run_setup.sh @@ -37,11 +37,20 @@ source hwsetup.sh hwtools=0.1.3 popd echo "---- Fetch the FPGA simulation libraries ----" -# The simulation libraries for our versions have been pre-compiled, so this -# should simply copy them if they're not already on this agent. -compileFpgaLibs vivado -# This is where compileFpgaLibs puts the simulation libraries -export MODELSIM_INI_DIR=/usr/hwlibs/vivado/2021.1/modelsim_SE-64_2020 +# Compiling the simulation libraries. +# Extracting the modelsim.ini path from the output. +# Creating a temporary modelsim.mpf file for the scripting to work. +echo "[Library]" > modelsim.mpf +compileFpgaLibs vivado | tee compileFpgaLib.log +VIVADO_MODELSIM_INI_PATH=$(grep Reading compileFpgaLib.log | awk '{print $3}' | sed 's/\x1b\[[0-9;]*m//g') +compileFpgaLibs diamond | tee compileFpgaLib.log +DIAMOND_MODELSIM_INI_PATH=$(grep Reading compileFpgaLib.log | awk '{print $3}' | sed 's/\x1b\[[0-9;]*m//g') +# Combine all modelsim.ini files to local copy +python $(dirname $BASH_SOURCE)/merge_modelsim_ini.py \ + -o $BUILD_SOURCESDIRECTORY/modelsim.ini \ + $VIVADO_MODELSIM_INI_PATH $DIAMOND_MODELSIM_INI_PATH +# Removing the temporary files +rm -f modelsim.mpf compileFpgaLib.log echo "---- Fetch Vivado patches ----" export PATCHES_DIR=$BUILD_SOURCESDIRECTORY/patches @@ -61,8 +70,7 @@ echo "---- Apply the Vivado patches ----" pushd $BUILD_SOURCESDIRECTORY # Apply the patch to Vivado export XILINX_PATH=$PATCHES_DIR/AR76780_Vivado_2021/vivado -# Create a local copy of modelsim.ini and add the FIR compiler simulation model -cp $MODELSIM_INI_DIR/modelsim.ini ./ +# Add the FIR compiler simulation model to local modelsim.ini # Delete all lines containing "fir_compiler_v7_2_76780" to avoid duplicates sed -i -e '/fir_compiler_v7_2_76780/d' ./modelsim.ini # Duplicate line containing "fir_compiler_v7_2_16" diff --git a/.ci/fpga/templates/job-build-cpld.yml b/.ci/fpga/templates/job-build-cpld.yml new file mode 100644 index 000000000..06f113300 --- /dev/null +++ b/.ci/fpga/templates/job-build-cpld.yml @@ -0,0 +1,93 @@ +# +# Copyright 2025 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: LGPL-3.0-or-later +# +# Description: +# +# This template should be used for CPLD builds. +# Exports the final programming files as pipeline artifacts. +# +# See description for the parameters below. +# + +parameters: + # Publishes the intermediate files from the build-* directories as pipeline artifacts. + - name: publish_int_files + type: boolean + default: false + + # cpldBuilds: List of CPLD builds to be executed + # each element is a list of 3 strings (displayName, workingDirectory, artifactName) + # e.g ['ZBX CPLD Build', './top/x400/dboards/zbx/cpld', 'CPLD_ZBX'] + - name: cpldBuilds + type: object + default: [] + +jobs: +- ${{ each cpldBuild in parameters.cpldBuilds }}: + - job: + displayName: ${{ cpldBuild.displayName }} + timeoutInMinutes: 30 + pool: + name: Drivers-NIBuildFarm-RFMIBUILD + demands: + - Agent.OS -equals Linux + variables: + - group: sdr-pipeline-vars + steps: + - template: setup_steps.yml + + - bash: | + # Find the directory containing setupenv.sh by searching upwards from the working directory + search_dir="${{ cpldBuild.workingDirectory }}" + while [[ "$search_dir" != "." && "$search_dir" != "/" ]]; do + if [[ -f "$search_dir/setupenv.sh" ]]; then + setup_dir="$search_dir" + break + fi + search_dir="$(dirname "$search_dir")" + done + + if [[ -z "$setup_dir" ]]; then + echo "setupenv.sh not found in hierarchy." + exit 1 + else + echo "Found setupenv.sh in: $setup_dir" + fi + + source $(Build.SourcesDirectory)/uhddev/.ci/fpga/scripts/run_setup.sh $setup_dir + + echo "---- Run build: ${{ cpldBuild.displayName }} ----" + cd ${{ cpldBuild.workingDirectory }} + make + workingDirectory: uhddev/fpga/usrp3 + env: + PATCHES_PATH: $(sdr-vivado-patches) + displayName: ${{ cpldBuild.displayName }} + + # Publish the final result only if all previous steps passed + - publish: uhddev/fpga/usrp3/${{ cpldBuild.workingDirectory }}/build + artifact: ${{ cpldBuild.artifactName }} + displayName: 'Publish ${{ cpldBuild.displayName }}' + + # Publish CPLD build intermediate files on request (even if the build failed) + # Publish uhddev/fpga/usrp3/${{ cpldBuild.workingDirectory }}/build-* + - bash: | + cd ${{ cpldBuild.workingDirectory }} + cp -r build-* $(Build.ArtifactStagingDirectory) + workingDirectory: uhddev/fpga/usrp3 + env: + PATCHES_PATH: $(sdr-vivado-patches) + displayName: 'Copy build directories' + condition: and(always(), eq('${{ parameters.publish_int_files }}', true)) + + - publish: $(Build.ArtifactStagingDirectory) + artifact: '${{ cpldBuild.artifactName }}_Build_Directory Attempt $(System.JobAttempt)' + displayName: 'Publish ${{ cpldBuild.displayName }} Directory' + condition: and(always(), eq('${{ parameters.publish_int_files }}', true)) + + # Check if CPLD build left any untracked files. + - template: check_clean_repo_steps.yml + parameters: + directory: uhddev/ diff --git a/.ci/fpga/templates/mb_cpld_build.yml b/.ci/fpga/templates/mb_cpld_build.yml deleted file mode 100644 index 53aa0736f..000000000 --- a/.ci/fpga/templates/mb_cpld_build.yml +++ /dev/null @@ -1,67 +0,0 @@ -# -# Copyright 2021 Ettus Research, a National Instruments Brand -# -# SPDX-License-Identifier: LGPL-3.0-or-later -# -# Description: -# -# This template is used to build the MB CPLD within the uhddev repository. -# Exports the CPLD build results (from build directory) as artifacts 'MB CPLD -# image'. -# -# See description for the parameters below. -# - -parameters: - ### Optional parameters - # Set to true if the intermediate files from build- directory should - # be exported for debugging as artifact 'MB CPLD build ()' - - name: debug - type: boolean - default: false - # Checkout repository in a clean state as described in - # https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&tabs=schema%2Cparameter-schema#checkout - - name: clean - type: boolean - default: true - -jobs: -- job: MB_CPLD - displayName: 'Build MB CPLD' - pool: - name: de-dre-lab - demands: - - ettus_fpga_build - - quartus18.1_lite - timeoutInMinutes: 30 - steps: - # Currently limited to be executed in same repo. - # Removes all unversioned files if necessary. - # Checkout path defined by single repository case in - # https://docs.microsoft.com/en-us/azure/devops/pipelines/repos/multi-repo-checkout?view=azure-devops#checkout-path - - checkout: self - clean: ${{ parameters.clean }} - - # Run CPLD build - # Increase license server timeout as there might appear timeouts during - # static timing analysis which end up setting the build to fail. - - script: | - call set FLEXLM_TIMEOUT=20000000 - call make - workingDirectory: $(Agent.BuildDirectory)/s/fpga/usrp3/top/x400/cpld - displayName: 'Build CPLD' - - # Publish the final result only if all previous steps passed - - publish: $(Agent.BuildDirectory)/s/fpga/usrp3/top/x400/cpld/build - artifact: 'MB CPLD image' - displayName: 'Publish CPLD' - - # always publish intermediate files - - publish: $(Agent.BuildDirectory)/s/fpga/usrp3/top/x400/cpld/output_files - artifact: 'MB CPLD build ($(System.JobAttempt))' - condition: and(always(), eq('${{ parameters.debug }}', true)) - displayName: 'Publish Build Directory' - - # Check if FPGA build left any untracked files. - - ${{ if eq(parameters.debug, true) }}: - - template: check_clean_repo_steps.yml diff --git a/.ci/fpga/templates/zbx_cpld_build.yml b/.ci/fpga/templates/zbx_cpld_build.yml deleted file mode 100644 index b1fb598f2..000000000 --- a/.ci/fpga/templates/zbx_cpld_build.yml +++ /dev/null @@ -1,67 +0,0 @@ -# -# Copyright 2021 Ettus Research, a National Instruments Brand -# -# SPDX-License-Identifier: LGPL-3.0-or-later -# -# Description: -# -# This template is used to build the ZBX daughterboard CPLD within the uhddev -# repository. Exports the CPLD build results (from build directory) as -# artifacts 'ZBX CPLD image'. -# -# See description for the parameters below. -# - -parameters: - ### Optional parameters - # Set to true if the intermediate files from build- directory should - # be exported for debugging as artifact 'ZBX CPLD build ()' - - name: debug - type: boolean - default: false - # Checkout repository in a clean state as described in - # https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&tabs=schema%2Cparameter-schema#checkout - - name: clean - type: boolean - default: true - -jobs: -- job: ZBX_CPLD - displayName: 'Build ZBX CPLD' - pool: - name: de-dre-lab - demands: - - ettus_fpga_build - - quartus18.1_lite - timeoutInMinutes: 30 - steps: - # Currently limited to be executed in same repo. - # Removes all unversioned files if necessary. - # Checkout path defined by single repository case in - # https://docs.microsoft.com/en-us/azure/devops/pipelines/repos/multi-repo-checkout?view=azure-devops#checkout-path - - checkout: self - clean: ${{ parameters.clean }} - - # Run CPLD build - # Increase license server timeout as there might appear timeouts during - # static timing analysis which end up setting the build to fail. - - script: | - call set FLEXLM_TIMEOUT=20000000 - call make - workingDirectory: $(Agent.BuildDirectory)/s/fpga/usrp3/top/x400/dboards/zbx/cpld - displayName: 'Build CPLD' - - # Publish the final result only if all previous steps passed - - publish: $(Agent.BuildDirectory)/s/fpga/usrp3/top/x400/dboards/zbx/cpld/build - artifact: 'ZBX CPLD image' - displayName: 'Publish CPLD' - - # Always publish intermediate files - - publish: $(Agent.BuildDirectory)/s/fpga/usrp3/top/x400/dboards/zbx/cpld/output_files - artifact: 'ZBX CPLD build ($(System.JobAttempt))' - condition: and(always(), eq('${{ parameters.debug }}', true)) - displayName: 'Publish Build Directory' - - # Check if FPGA build left any untracked files. - - ${{ if eq(parameters.debug, true) }}: - - template: check_clean_repo_steps.yml diff --git a/.ci/hwtools/root.py b/.ci/hwtools/root.py index 0c36411cc..6859a6492 100644 --- a/.ci/hwtools/root.py +++ b/.ci/hwtools/root.py @@ -21,6 +21,8 @@ def do_setup(): rootapi.add_tool(name="hwtools", version="head") rootapi.add_tool(name="Vivado", version="2021.1", allowlater=False) rootapi.add_tool(name="modelsim", version="2020.4", allowlater=True) + rootapi.add_tool(name="Diamond", version="3.12" , allowlater=True) + rootapi.add_tool(name="Quartus", version="20.1" , allowlater=True) def do_finish(): pass diff --git a/.ci/templates/stages-uhd-pipeline.yml b/.ci/templates/stages-uhd-pipeline.yml index 9e12c0229..517217133 100644 --- a/.ci/templates/stages-uhd-pipeline.yml +++ b/.ci/templates/stages-uhd-pipeline.yml @@ -485,6 +485,29 @@ stages: ### END: Testbenches stage +### START: CPLD Build Stage + +- stage: build_cpld_stage + displayName: x4xx CPLD Build Stage + dependsOn: analyze_changeset + condition: > + and(succeeded(), + contains(dependencies.analyze_changeset.outputs['analyze.gen_testlist.UhdTestList'], 'fpga.usrp3.cpld.x4xx') + ) + jobs: + - template: ../fpga/templates/job-build-cpld.yml + parameters: + publish_int_files: true + cpldBuilds: + - displayName: 'MB CPLD Build' + workingDirectory: './top/x400/cpld' + artifactName: 'CPLD_MB' + - displayName: 'ZBX CPLD Build' + workingDirectory: './top/x400/dboards/zbx/cpld' + artifactName: 'CPLD_ZBX' + +### END: CPLD Build Stage + - template: ../fpga/templates/job-build-fpga-all.yml parameters: clean_ip_build: ${{ parameters.clean_ip_build }} diff --git a/fpga/.ci/fpga-pipeline.yml b/fpga/.ci/fpga-pipeline.yml index ca67ce76c..59e514bb3 100644 --- a/fpga/.ci/fpga-pipeline.yml +++ b/fpga/.ci/fpga-pipeline.yml @@ -45,6 +45,10 @@ parameters: type: boolean displayName: Build X440 default: false +- name: build_x4xx_cplds + type: boolean + displayName: Build X4xx CPLDs + default: false - name: package_and_publish_images type: boolean displayName: Package & Publish Images @@ -137,14 +141,15 @@ extends: parameters: add_tests: ${{ format( - '{0};{1};{2};{3};{4};{5};{6};', + '{0};{1};{2};{3};{4};{5};{6};{7};', iif(parameters.run_testbenches,'fpga.usrp3.testbenches',''), iif(parameters.build_x3x0,'fpga.usrp3.x3xx',''), iif(parameters.build_n3xx,'fpga.usrp3.n3xx',''), iif(parameters.build_e31x,'fpga.usrp3.e31x',''), iif(parameters.build_e32x,'fpga.usrp3.e32x',''), iif(parameters.build_x410,'fpga.usrp3.x410',''), - iif(parameters.build_x440,'fpga.usrp3.x440','') + iif(parameters.build_x440,'fpga.usrp3.x440',''), + iif(parameters.build_x4xx_cplds,'fpga.usrp3.cpld.x4xx','') ) }} skip_rule_checking: true diff --git a/tools/changeset_testlist.yaml b/tools/changeset_testlist.yaml index 20816fef3..0a7d83404 100644 --- a/tools/changeset_testlist.yaml +++ b/tools/changeset_testlist.yaml @@ -229,6 +229,7 @@ add: - fpga.usrp3.all - uhd.rfnoc_modtool.all + - fpga.usrp3.cpld.x4xx # image builder changes - re: host/utils/rfnoc_image_builder.py @@ -287,6 +288,17 @@ add: - fpga.usrp3.n3xx +# CPLD related changes +- re: fpga/usrp3/top/x400/cpld + add: + - fpga.usrp3.cpld.x4xx +- re: fpga/usrp3/top/x400/dboards + add: + - fpga.usrp3.cpld.x4xx +- re: fpga/usrp3/top/x400/constraints/timing/shared_constants.sdc + add: + - fpga.usrp3.cpld.x4xx + ############################################################################### # CI CHANGES ############################################################################### @@ -329,9 +341,16 @@ - uhd.rfnoc_modtool.all -- re: fpga/.ci/templates* +- re: fpga/.ci/templates add: - fpga.usrp3.all + - fpga.usrp3.cpld.x4xx + - fpga.usrp3.testbenches +- re: fpga/.ci/scripts + add: + - fpga.usrp3.all + - fpga.usrp3.cpld.x4xx + - fpga.usrp3.testbenches # Device-specific pipeline changes. - re: .ci/fpga/devices/job-build-x400.yml add: