Skip to content

Commit

Permalink
fix (#4)
Browse files Browse the repository at this point in the history
* Porting Ultrascale ZCU104 board (esl-epfl#435)

Porting for Ultrascale

* fix num of FPGAs in README

* Update ci (esl-epfl#454)

docker image integration plus CI update

* Fix cmake error (esl-epfl#473)

* Fix edit that breaks external applications

* Fix MATCH string

* Consider entire path when matching `PROJECT` as well

- prevent build from failing if any part of the path includes `${PROJECT}` (e.g., the name of one of the applications.

* Restrict regular expression on `main` as well

---------

Co-authored-by: Michele Caon <st.miky77@gmail.com>

---------

Co-authored-by: Davide Schiavone <davide@openhwgroup.org>
Co-authored-by: Luigi Giuffrida <32927727+Luigi2898@users.noreply.github.com>
Co-authored-by: Michele Caon <st.miky77@gmail.com>
  • Loading branch information
4 people authored Mar 19, 2024
1 parent d8c789c commit e3a390b
Show file tree
Hide file tree
Showing 7 changed files with 253 additions and 24 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/build-apps-job/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 ========================================
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/building.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
10 changes: 3 additions & 7 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -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 #
#####################
Expand All @@ -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 #
##################
Expand Down
188 changes: 188 additions & 0 deletions .github/workflows/sim-apps-job/test_apps.py
Original file line number Diff line number Diff line change
@@ -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)
21 changes: 21 additions & 0 deletions .github/workflows/simulate.yml
Original file line number Diff line number Diff line change
@@ -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
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -545,7 +568,7 @@ This project offers two different X-HEEP implementetions on Xilinx FPGAs, called

In this version, the X-HEEP architecture is implemented on the programmable logic (PL) side of the FPGA, and its input/output are connected to the available headers on the FPGA board.

Two FPGA boards are supported: the Xilinx Pynq-z2, Nexys-A7-100t, Zynq Ultrascale+ ZCU104.
Three FPGA boards are supported: the Xilinx Pynq-z2, Nexys-A7-100t, Zynq Ultrascale+ ZCU104.

Make sure you have the FPGA board files installed in your Vivado.

Expand Down
24 changes: 12 additions & 12 deletions sw/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,19 +63,19 @@ FILE(GLOB_RECURSE new_list FOLLOW_SYMLINKS ${SOURCE_PATH}*.h)
SET(dir_list_str "")
FOREACH(file_path ${new_list})
SET(add 0) # This variable is set to 1 if the file_pth needs to be added to the list
if(${file_path} MATCHES "${ROOT_PROJECT}device/")
if(${file_path} MATCHES "${ROOT_PROJECT}device/target/") # Add it if its not in target, or if its in target/${TARGET}
if(${file_path} MATCHES "${ROOT_PROJECT}device/target/${TARGET}")
if(${file_path} MATCHES "${SOURCE_PATH}device/")
if(${file_path} MATCHES "${SOURCE_PATH}device/target/") # Add it if its not in target, or if its in target/${TARGET}
if(${file_path} MATCHES "${SOURCE_PATH}device/target/${TARGET}")
SET(add 1)
endif()
else()
SET(add 1)
endif()
elseif(${file_path} MATCHES ${PROJECT})
elseif(${file_path} MATCHES ${SOURCE_PATH}applications/${PROJECT}/)
SET(add 1)
elseif( ( ${file_path} MATCHES "${ROOT_PROJECT}freertos/" ) AND ( ${PROJECT} MATCHES "freertos" ) )
elseif( ( ${file_path} MATCHES "${SOURCE_PATH}freertos/" ) AND ( ${PROJECT} MATCHES "freertos" ) )
SET(add 1)
elseif( ${file_path} MATCHES "${ROOT_PROJECT}external/" )
elseif( ${file_path} MATCHES "${SOURCE_PATH}external/" )
SET(add 1)
endif()

Expand Down Expand Up @@ -124,14 +124,14 @@ SET( c_dir_list "" )
SET( app_found 0 )
FOREACH(file_path IN LISTS new_list)
SET(add 0) # This variable is set to 1 if the file_pth needs to be added to the list
if(${file_path} MATCHES "${ROOT_PROJECT}device/")
if(${file_path} MATCHES "${SOURCE_PATH}device/")
SET(add 1)
elseif( ${file_path} MATCHES "${ROOT_PROJECT}external/" )
elseif( ${file_path} MATCHES "${SOURCE_PATH}external/" )
SET(add 1)
elseif( ( ${file_path} MATCHES "/${PROJECT}/" ) AND ( NOT ${file_path} MATCHES ${MAINFILE} ) )
SET(add 1)
elseif( ( ${file_path} MATCHES "/${PROJECT}/" ) AND ( ${file_path} MATCHES ${MAINFILE} ) )
elseif( ${file_path} MATCHES "${SOURCE_PATH}applications/${PROJECT}/.*${MAINFILE}\." ) # look for main.*
SET(app_found 1)
elseif( ${file_path} MATCHES "${SOURCE_PATH}applications/${PROJECT}/" ) # other sources
SET(add 1)
endif()

if( add EQUAL 1 ) # If the file path mathced one of the criterion, add it to the list
Expand All @@ -155,7 +155,7 @@ if( app_found EQUAL 0 )
SET(add 0) # This variable is set to 1 if the file_pth needs to be added to the list
if(${file_path} MATCHES "${ROOT_PROJECT}device/")
SET(add 1)
elseif( ( ${file_path} MATCHES "/${PROJECT}/" ) AND ( NOT ${file_path} MATCHES ${MAINFILE} ) )
elseif( ( ${file_path} MATCHES "${ROOT_PROJECT}/applications/${PROJECT}/" ) AND ( NOT ${file_path} MATCHES "${ROOT_PROJECT}applications/${PROJECT}/.*${MAINFILE}\." ) )
SET(add 1)
endif()

Expand Down

0 comments on commit e3a390b

Please sign in to comment.