diff --git a/.github/workflows/build-apps-job/setup.sh b/.github/workflows/build-apps-job/setup.sh index c53816c5b..ebf262e4f 100755 --- a/.github/workflows/build-apps-job/setup.sh +++ b/.github/workflows/build-apps-job/setup.sh @@ -7,8 +7,9 @@ echo ======================================== echo ======================================== # Create the virtual environment and install the requirements. -make venv -. .venv/bin/activate +conda init bash +source /root/.bashrc +conda activate core-v-mini-mcu echo ======================================== echo ======================================== @@ -17,7 +18,7 @@ echo ======================================== echo ======================================== # The variable could also be obtained from the container. -export RISCV='/home/root/tools/riscv' &&\ +export RISCV='/tools/riscv' &&\ # All peripherals are included to make sure all apps can be built. sed 's/is_included: "no",/is_included: "yes",/' -i mcu_cfg.hjson diff --git a/.github/workflows/building.yml b/.github/workflows/building.yml index 12b2cdb83..893822c61 100644 --- a/.github/workflows/building.yml +++ b/.github/workflows/building.yml @@ -5,7 +5,7 @@ jobs: test_applications: runs-on: ubuntu-latest container: - image: ghcr.io/esl-epfl/xheep-compiler:latest + image: ghcr.io/esl-epfl/x-heep-toolchain:latest name: Builds apps with gcc and clang. All must build successfully. steps: - name: Checkout the pushed code. diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 2a69ed391..e1baeeb7c 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,16 +1,12 @@ # Copyright 2022 OpenHW Group # Solderpad Hardware License, Version 2.1, see LICENSE.md for details. # SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 - # Run all lint checks name: lint on: [push, pull_request] - env: VERIBLE_VERSION: 0.0-1824-ga3b5bedf - jobs: - ##################### # Vendor Up-to-Date # ##################### @@ -28,9 +24,9 @@ jobs: - name: Re-vendor and diff run: | find . \ - -name '*.vendor.hjson' \ - | xargs -n1 util/vendor.py --verbose \ - && util/git-diff.py --error-msg "::error ::Found differences, please re-vendor." + -name '*.vendor.hjson' \ + | xargs -n1 util/vendor.py --verbose \ + && util/git-diff.py --error-msg "::error ::Found differences, please re-vendor." ################## # MCU Generator # ################## diff --git a/.github/workflows/sim-apps-job/test_apps.py b/.github/workflows/sim-apps-job/test_apps.py new file mode 100755 index 000000000..0d3cdfce7 --- /dev/null +++ b/.github/workflows/sim-apps-job/test_apps.py @@ -0,0 +1,188 @@ +""" +This script compiles and runs all the apps in the sw/applications directory +""" + +import os +import subprocess +import re + + +class BColors: + """ + Class to define colors in the terminal output. + """ + HEADER = "\033[95m" + OKBLUE = "\033[94m" + OKCYAN = "\033[96m" + OKGREEN = "\033[92m" + WARNING = "\033[93m" + FAIL = "\033[91m" + ENDC = "\033[0m" + BOLD = "\033[1m" + UNDERLINE = "\033[4m" + + +# Define parameters for the test_apps.py script +SIMULATOR = "verilator" +SIM_TIMEOUT_S = 120 +LINKER = "on_chip" +COMPILER = "gcc" + +# Blacklist of apps to skip +blacklist = [ + "example_spi_read", + "example_spi_host_dma_power_gate", + "example_spi_write", +] + +app_list = [app for app in os.listdir("sw/applications")] + +print(BColors.OKCYAN + "Apps to test:" + BColors.ENDC) +for app in app_list: + if app not in blacklist: + print(BColors.OKCYAN + f" - {app}" + BColors.ENDC) + +apps = {app: {"building": "", "simulation": ""} for app in app_list} + + +# Compile the {SIMULATOR} model and suppress the output +print(BColors.OKBLUE + f"Generating {SIMULATOR} model of X-HEEP..." + BColors.ENDC) +try: + simulation_build_output = subprocess.run( + ["make", f"{SIMULATOR}-sim"], capture_output=True, check=False + ) +except subprocess.CalledProcessError as exc: + print(BColors.FAIL + "=====================================" + BColors.ENDC) + print(BColors.FAIL + "Error building verilated model!" + BColors.ENDC) + print(BColors.FAIL + "=====================================" + BColors.ENDC) + print(str(exc.stderr.decode("utf-8"))) + exit(1) +else: + print( + BColors.OKGREEN + + f"Generated {SIMULATOR} model of X-HEEP successfully!" + + BColors.ENDC + ) + +error_pattern = r"Program Finished with value (\d+)" + +# Compile every app and run the simulator +for an_app in apps.keys(): + if an_app not in blacklist: + apps[an_app] = {"building": "OK", "simulation": "OK"} + print(BColors.OKBLUE + f"Compiling {an_app}..." + BColors.ENDC) + try: + compile_output = subprocess.run( + [ + "make", + "app", + f"PROJECT={an_app}", + f"COMPILER={COMPILER}", + f"LINKER={LINKER}", + ], + capture_output=True, + check=True, + ) + except subprocess.CalledProcessError as exc: + print(BColors.FAIL + f"Error compiling {an_app}!" + BColors.ENDC) + print(exc.stderr.decode("utf-8")) + apps[an_app] = {"building": "Failed", "simulation": "Skipped"} + else: + apps[an_app] = {"building": "OK", "simulation": "Skipped"} + print(BColors.OKGREEN + f"Compiled successfully {an_app}!" + BColors.ENDC) + print( + BColors.OKBLUE + + f"Running {SIMULATOR} simulation of {an_app}..." + + BColors.ENDC + ) + try: + run_output = subprocess.run( + ["./Vtestharness", "+firmware=../../../sw/build/main.hex"], + cwd="build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-verilator", + capture_output=True, + timeout=SIM_TIMEOUT_S, + check=False, + ) + except subprocess.TimeoutExpired: + print( + BColors.FAIL + f"Simulation of {an_app} timed out!" + BColors.ENDC + ) + apps[an_app] = {"building": "OK", "simulation": "Timed out"} + else: + match = re.search(error_pattern, str(run_output.stdout.decode("utf-8"))) + if ( + "Error" in str(run_output.stdout.decode("utf-8")) + or match.group(1) != "0" + ): + print( + BColors.FAIL + + str(run_output.stdout.decode("utf-8")) + + BColors.ENDC + ) + uart_output = open( + "build/openhwgroup.org_systems_core-v-mini-mcu_0/sim-verilator/uart0.log", + "r", + encoding="utf-8", + ) + print(BColors.FAIL + "UART output:" + BColors.ENDC) + print(BColors.FAIL + uart_output.read() + BColors.ENDC) + uart_output.close() + apps[an_app] = {"building": "OK", "simulation": "Failed"} + else: + apps[an_app] = {"building": "OK", "simulation": "OK"} + print( + BColors.OKGREEN + f"Ran {an_app} successfully!" + BColors.ENDC + ) + print(BColors.OKBLUE + f"Finished running {an_app}." + BColors.ENDC) + else: + print(BColors.WARNING + f"Skipping {an_app}..." + BColors.ENDC) + apps[an_app] = {"building": "Skipped", "simulation": "Skipped"} + +# Print the results +print(BColors.BOLD + "=================================" + BColors.ENDC) +print(BColors.BOLD + "Results:" + BColors.ENDC) +print(BColors.BOLD + "=================================" + BColors.ENDC) + +# Filter the dictionary by values +ok_apps = [ + app + for app, status in apps.items() + if (status["simulation"] == "OK" and status["building"] == "OK") +] +no_build_apps = [app for app, status in apps.items() if status["building"] == "Failed"] +no_sim_apps = [app for app, status in apps.items() if status["simulation"] == "Failed"] +skipped_apps = [ + app + for app, status in apps.items() + if (status["simulation"] == "Skipped" or status["building"] == "Skipped") +] +timed_out_apps = [ + app for app, status in apps.items() if status["simulation"] == "Timed out" +] + +# Print the filtered results +print( + BColors.OKGREEN + + f"{len(ok_apps)} out of {len(app_list)} apps compiled and ran successfully!" + + BColors.ENDC +) +if len(no_build_apps) > 0: + print(BColors.FAIL + f"{len(no_build_apps)} apps failed to build!" + BColors.ENDC) + for failed_build_app in no_build_apps: + print(BColors.FAIL + f" - {failed_build_app}" + BColors.ENDC) +if len(no_sim_apps) > 0: + print(BColors.FAIL + f"{len(no_sim_apps)} apps failed to run!" + BColors.ENDC) + for failed_run_app in no_sim_apps: + print(BColors.FAIL + f" - {failed_run_app}" + BColors.ENDC) +if len(skipped_apps) > 0: + print(BColors.WARNING + f"{len(skipped_apps)} apps were skipped!" + BColors.ENDC) + for skipped_app in skipped_apps: + print(BColors.WARNING + f" - {skipped_app}" + BColors.ENDC) +if len(timed_out_apps) > 0: + print(BColors.FAIL + f"{len(timed_out_apps)} apps timed out!" + BColors.ENDC) + for timed_out_app in timed_out_apps: + print(BColors.FAIL + f" - {timed_out_app}" + BColors.ENDC) +print(BColors.BOLD + "=================================" + BColors.ENDC) + +if len(no_build_apps) > 0 or len(no_sim_apps) > 0: + exit(1) diff --git a/.github/workflows/simulate.yml b/.github/workflows/simulate.yml new file mode 100644 index 000000000..ffb167220 --- /dev/null +++ b/.github/workflows/simulate.yml @@ -0,0 +1,21 @@ +name: Simulate all apps +on: [pull_request] + +jobs: + simulate: + runs-on: ubuntu-latest + container: + image: ghcr.io/esl-epfl/x-heep-toolchain:latest + name: Simulate all apps. All must pass. + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Run all apps + run: | + conda init bash + source /root/.bashrc + conda activate core-v-mini-mcu + make clean-all + sed 's/is_included: "no",/is_included: "yes",/' -i mcu_cfg.hjson + make mcu-gen MEMORY_BANKS=6 + python3 .github/workflows/sim-apps-job/test_apps.py \ No newline at end of file diff --git a/README.md b/README.md index 848943251..c97054740 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,29 @@ To format your RTL code type: ``` make verible ``` + +## Docker alternative + +A docker image containing all the required software dependancies is available on [github-packages](https://github.com/orgs/esl-epfl/packages/container/package/x-heep-toolchain). + +It is only required to install [`docker`](https://docs.docker.com/get-docker/) and pull the image. + +```bash +docker pull ghcr.io/esl-epfl/x-heep-toolchain:latest +``` + +Assuming that X-HEEP has been cloned to `X-HEEP-DIR=\absolute\path\to\x-HEEP\folder`, it is possible to directly run the docker mounting `X-HEEP-DIR` to the path `\workspace\x-heep` in the docker. + +```bash +docker run -it -v ${X-HEEP-DIR}:/workspace/x-heep ghcr.io/esl-epfl/x-heep-toolchain +``` + +Take care to indicate the absolute path to the local clone of X-HEEP, otherwise `docker` will not be able to properly nount the local folder in the container. + +All the command listed in the README can be execute in the docker container, except for: +- Simulation with Questasim and VCS, synthesis with Design Compiler (licenses are required to use these tools, so they are not installed in the container) +- OpenRoad flow is not installed in the container, so it is not possible to run the related make commands + ## Compilation Flow and Package Manager We use [FuseSoC](https://github.com/olofk/fusesoc) for all the tools we use.