Automatic testing
X-HEEP includes a script to perform automatic tests on your modifications. In addition, it also has a CI setup that checks the code by simulating all the existing applications and handles publishing new X-HEEP releases.
Simulation script
The testing script (test/test_apps/test_apps.py) can be used to perform local tests. For quick
debugging, you can check the global variables in the script such as the BLACKLIST and WHITELIST.
You can run it with the following command:
make test
This will output the results in the terminal and in the test/test_apps/test_apps.log file.
Additionally, you can check only the compilation of the applications with the following command:
make test TEST_FLAGS=--compile-only
This script is also integrated in the CI workflow described in the following section.
Github CIs
The project’s Continuous Integration (CI) is managed through GitHub Actions. The workflows are defined in the .github/workflows directory. The main CI workflow is ci.yml, which is triggered on every push and pull request to the main branch.
CI Workflow (ci.yml)
This workflow ensures the stability and integrity of the codebase by running a series of checks, compilations, and simulations.
Triggers:
Push to any branch (
push: branches: [ "**" ]).Pull request to the
mainbranch (pull_request: branches: [ "main" ]).
Jobs:
determine-image-tag:Purpose: Determines the Docker image tag to be used by subsequent jobs.
Details: It checks the Git history for the most recent tag. If no tag is found in the current branch, it looks for one in the
mainbranch. If no tags are found at all, it defaults tolatest. This ensures that the CI always uses a relevant toolchain version.
compile-apps:Purpose: Compiles all software applications with both GCC and Clang to ensure they build correctly.
Dependencies: Depends on
determine-image-tagto select the correct Docker image.Environment: Runs inside the
ghcr.io/x-heep/x-heep/x-heep-toolchainDocker container.Steps:
Generates the MCU configuration using
make mcu-gen X_HEEP_CFG=configs/ci.hjson.Executes
test/test_apps/test_apps.pywith the--compile-onlyflag to build all applications, without simulating them. This is done to offer a quick feedback about the apps’ integrity, before their runtime behaviour is checked in RTL simulation.
simulate-apps:Purpose: Runs Verilator RTL simulations for all applications (except the blacklisted ones) to verify their runtime behavior.
Condition: This job only runs on pull requests to
main.Dependencies: Depends on
determine-image-tag.Environment: Runs inside the
x-heep-toolchainDocker container.Steps:
Generates the MCU configuration using
make mcu-gen X_HEEP_CFG=configs/ci.hjson.Executes
test/test_apps/test_apps.pyto compile and simulate all applications.
lint:Purpose: Checks that all auto-generated hardware files are up-to-date and have been formatted .
Dependencies: Depends on
determine-image-tag.Environment: Runs inside the
x-heep-toolchainDocker container.Steps:
Runs
make mcu-gento regenerate all hardware files.Uses
util/git-diff.pyto check for any differences between the working directory and the git HEAD. The job fails if any differences are found.
gen-peripherals:Purpose: Tests the Python-based peripheral generation scripts and templates.
Dependencies: Depends on
determine-image-tag.Environment: Runs inside the
x-heep-toolchainDocker container.Steps:
Runs
make clean-allto ensure a clean state.Executes
test/test_x_heep_gen/test_peripherals.py.
check-vendor:Purpose: Verifies that all third-party vendored dependencies are up-to-date.
Environment: Runs inside a
ubuntu-latestVM.Steps:
Installs Python dependencies.
Runs the
util/vendor.pyscript for all.vendor.hjsonfiles to re-vendor all dependencies.Uses
util/git-diff.pyto check for any differences, ensuring that any changes to vendored repositories are properly committed.
black-formatter:Purpose: Checks that all Python code adheres to the
blackformatting standard.Environment: Runs inside a
ubuntu-latestVM.Steps:
Uses the
psf/blackGitHub Action to check the formatting of all relevant Python files.
Release Workflows
The project includes a robust, automated process for creating and publishing releases. This is handled by two GitHub Actions workflows: create-release.yml and publish-release.yml. This system ensures that every release is consistently built, tested, and published with its corresponding toolchain and Docker image.
Create X-HEEP Release Workflow (create-release.yml)
This workflow prepares a new release. It is a comprehensive process that builds the toolchain, packages it, creates a draft release, builds a Docker container, and opens a version bump pull request. It’s designed to be triggered manually when a new release is needed.
Trigger:
Manual dispatch (
workflow_dispatch) from the GitHub Actions tab.Inputs:
llvm_version: The LLVM version tag to build (default:llvmorg-19.1.4).gcc_version: The GCC version tag to build (default:2023.01.03).release_tag: The tag for the new GitHub release (e.g.,v1.0.0).
Note
This workflow is intended for major releases that:
Introduce support for new tools
Bump existing tools to newer versions
Modify the CI workflows
Represent a significant update in general
Minor bug fixes or feature improvements may not require/justify a full new release.
Jobs:
check-changes:Checks previous release tag.
Downloads
tool-versions.envfrom the previous release to compare GCC, LLVM, Verilator, and Verible versions.Checks for changes in Docker-related files (
util/docker/,util/conda_environment.yml,util/python-requirements.txt,docs/python-requirements.txt).Sets outputs
rebuild_toolchainandrebuild_dockerto avoid unnecessary rebuilds.
prepare-release:Creates a new release branch (
release/<release_tag>).Updates the version in
core-v-mini-mcu.coreand the toolchain version inutil/docker/dockerfile.Commits and pushes the changes to the new branch.
Creates a draft GitHub release.
build-and-upload-toolchain:Conditional: Runs the build only if
rebuild_toolchainis true.Builds the RISC-V GCC and Clang/LLVM toolchains from the sources specified in the workflow inputs.
Packages the compiled toolchains into a
.tar.gzfile.If
rebuild_toolchainis false, it downloads the toolchain asset from the previous release.Uploads the toolchain tarball as an asset to the draft GitHub release.
Uploads a
tool-versions.envfile containing version metadata.
build-docker:Conditional: Runs the build only if
rebuild_dockeris true.Downloads the toolchain asset from the draft release.
Builds the
x-heep-toolchainDocker image, injecting the new toolchain.Pushes the new Docker image to the GitHub Container Registry (GHCR) with the release tag.
If
rebuild_dockeris false, it retags the previous release’s Docker image with the new tag.
create-version-pr:Creates a new pull request to merge the release branch back into
main. This PR contains the version bumps.
cleanup-on-failure:This job runs only if any of the previous jobs fail.
It automatically cleans up by deleting the draft release, the release tag, the remote release branch, and the pushed Docker image from GHCR. This prevents leftovers from partial, broken releases.
Publish Release Workflow (publish-release.yml)
This workflow finalizes the release process. It is triggered automatically after the version bump PR (created by the create-release.yml workflow) is merged into the main branch.
Trigger:
A pull request from a
release/*branch is merged intomain.
Jobs:
publish-release:Identifies the release tag from the merged branch name.
Converts the corresponding draft release into a public release.
Deletes the now-merged remote release branch to keep the repository clean.
tag-latest:After the release is published, this job pulls the newly released Docker image from GHCR.
It then re-tags this image with the
latesttag and pushes it.This ensures that the main
ci.ymlworkflow will use the most up-to-date toolchain for future runs on themainbranch.
Compare mcu-gen runs
The test/test_x_heep_gen/compare_mcu_gen.py script is a utility to compare the outputs of mcu-gen between the current branch and main. This can be useful to manually check if changes in the configuration or in the MCU-Gen code have an effect on the generated files.
You can run it with the following command:
make compare-mcu-gen
This will generate the mcu-gen outputs in the _mcu_gen_current and _mcu_gen_main directories inside test/test_x_heep_gen, and then list the files that differ between them. You can check the differences to see if they are expected or if they indicate an unintended change in the generated files.