diff --git a/.github/workflows/gitlab-ci.yml b/.github/workflows/gitlab-ci.yml index 053195c9..ed3416c6 100644 --- a/.github/workflows/gitlab-ci.yml +++ b/.github/workflows/gitlab-ci.yml @@ -4,7 +4,7 @@ # Author: Alessandro Nadalini -name: gitlab-Copyright +name: gitlab-CI on: push: branches: @@ -15,6 +15,7 @@ on: jobs: gitlab-ci: runs-on: ubuntu-latest + timeout-minutes: 960 steps: - name: Check GitLab CI uses: pulp-platform/pulp-actions/gitlab-ci@v2.5.0 @@ -24,4 +25,5 @@ jobs: domain: iis-git.ee.ethz.ch repo: github-mirror/magia token: ${{ secrets.GITLAB_TOKEN }} - poll-count: 2160 \ No newline at end of file + poll-count: 1000 + poll-period: 60 \ No newline at end of file diff --git a/.gitignore b/.gitignore index ac626b94..6696595f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .bender -Bender.lock bender scripts/compile.tcl scripts/synth_compile.tcl diff --git a/Bender.local b/Bender.local deleted file mode 100644 index f39d3bd1..00000000 --- a/Bender.local +++ /dev/null @@ -1,11 +0,0 @@ -overrides: - fpnew : { git: "https://github.com/pulp-platform/cvfpu.git" , rev: a8e0cba6dd50f357ece73c2c955d96efc3c6c315 } - cv32e40p : { git: "https://github.com/FondazioneChipsIT/cv32e40p.git" , rev: a8206ab02759f110c40dd907369816ea656381bc } # branch: ng/pulp_cluster - cv32e40x : { git: "https://github.com/pulp-platform/cv32e40x.git" , rev: a90101211048ba1a16cedbe4db963ab6e12569d7 } - axi : { git: "https://github.com/pulp-platform/axi.git" , version: 0.39.5 } - obi : { git: "https://github.com/pulp-platform/obi.git" , rev: 528dc65303d5ffb02fbc254324c6b53eac0dd6e5 } - register_interface : { git: "https://github.com/pulp-platform/register_interface.git", rev: e25b36670ff7aab3402f40efcc2b11ee0f31cf19 } - idma : { git: "https://github.com/pulp-platform/iDMA.git" , rev: ff5d56fffb3767814db88d6bf8f381974ea33aa5 } - tech_cells_generic : { git: "https://github.com/pulp-platform/tech_cells_generic.git", version: 0.2.13 } - cluster_icache : { git: "https://github.com/pulp-platform/cluster_icache.git" , version: 0.2.0 } - axi_riscv_atomics : { git: "https://github.com/pulp-platform/axi_riscv_atomics.git" , version: 0.8.2 } \ No newline at end of file diff --git a/Bender.lock b/Bender.lock new file mode 100644 index 00000000..d807b826 --- /dev/null +++ b/Bender.lock @@ -0,0 +1,265 @@ +packages: + apb: + revision: 77ddf073f194d44b9119949d2421be59789e69ae + version: 0.2.4 + source: + Git: https://github.com/pulp-platform/apb.git + dependencies: + - common_cells + axi: + revision: a8c53cee2520d328d390c507c88818e8ac144c8c + version: 0.39.10 + source: + Git: https://github.com/pulp-platform/axi.git + dependencies: + - common_cells + - common_verification + - tech_cells_generic + axi_obi: + revision: 3f29bd67369a093cf5be4ea3fdac3c6c216424cc + version: null + source: + Git: https://github.com/pulp-platform/axi_obi.git + dependencies: + - axi + - common_cells + - obi + axi_riscv_atomics: + revision: 97a1dd2ac643c276880420a0cf8eea697f228aa9 + version: 0.8.3 + source: + Git: https://github.com/pulp-platform/axi_riscv_atomics.git + dependencies: + - axi + - common_cells + - common_verification + axi_stream: + revision: 54891ff40455ca94a37641b9da4604647878cc07 + version: 0.1.1 + source: + Git: https://github.com/pulp-platform/axi_stream.git + dependencies: + - common_cells + cluster_icache: + revision: 64e21ae455bbdde850c4df13bef86ea55ac42537 + version: 0.2.0 + source: + Git: https://github.com/pulp-platform/cluster_icache.git + dependencies: + - axi + - common_cells + - scm + - tech_cells_generic + cluster_interconnect: + revision: 1284def6c0b7f7e9355eb093d00883ad9dead1b7 + version: null + source: + Git: https://github.com/pulp-platform/cluster_interconnect.git + dependencies: + - common_cells + common_cells: + revision: 1281545696eb3fcba50ec5b4275993476a3c710e + version: 1.40.0 + source: + Git: https://github.com/pulp-platform/common_cells.git + dependencies: + - common_verification + - tech_cells_generic + common_verification: + revision: fb1885f48ea46164a10568aeff51884389f67ae3 + version: 0.2.5 + source: + Git: https://github.com/pulp-platform/common_verification.git + dependencies: [] + cv32e40p: + revision: a8206ab02759f110c40dd907369816ea656381bc + version: null + source: + Git: https://github.com/FondazioneChipsIT/cv32e40p.git + dependencies: + - common_cells + - fpnew + - tech_cells_generic + cv32e40x: + revision: a90101211048ba1a16cedbe4db963ab6e12569d7 + version: null + source: + Git: https://github.com/pulp-platform/cv32e40x.git + dependencies: [] + event_unit_flex: + revision: 763c3b9977970f656326c70a96debfb2ac0f85b2 + version: null + source: + Git: https://github.com/pulp-platform/event_unit_flex.git + dependencies: + - common_cells + floo_noc: + revision: 6ac187326b222a491180cc3f77e0e4e5a69f5167 + version: 0.6.1 + source: + Git: https://github.com/pulp-platform/FlooNoC.git + dependencies: + - axi + - axi_riscv_atomics + - common_cells + - common_verification + - idma + fpnew: + revision: a8e0cba6dd50f357ece73c2c955d96efc3c6c315 + version: null + source: + Git: https://github.com/pulp-platform/cvfpu.git + dependencies: + - common_cells + - fpu_div_sqrt_mvp + fpu_div_sqrt_mvp: + revision: 86e1f558b3c95e91577c41b2fc452c86b04e85ac + version: 1.0.4 + source: + Git: https://github.com/pulp-platform/fpu_div_sqrt_mvp.git + dependencies: + - common_cells + fpu_ss: + revision: 8e2eff774d9d38a1e17a46bd56a0936dac9522f0 + version: null + source: + Git: https://github.com/pulp-platform/fpu_ss.git + dependencies: [] + fractal_sync: + revision: fdb619f40f99d769cfceb20ac2117ff8d99e98a3 + version: null + source: + Git: https://github.com/VictorIsachi/fractal_sync + dependencies: [] + hci: + revision: a8d8132b7f7839fd55f92df65cdc3e361ea80a6b + version: 2.6.1 + source: + Git: https://github.com/pulp-platform/hci.git + dependencies: + - cluster_interconnect + - common_cells + - hwpe-stream + - l2_tcdm_hybrid_interco + - redundancy_cells + - register_interface + hwpe-ctrl: + revision: a52dc9cd2a5a8bb68fbf7e445bf51ac5e2e3cade + version: 3.1.0 + source: + Git: https://github.com/pulp-platform/hwpe-ctrl.git + dependencies: + - common_cells + - tech_cells_generic + hwpe-stream: + revision: 05cb8303693065812e9d6bfe10976220fb455666 + version: 1.10.0 + source: + Git: https://github.com/pulp-platform/hwpe-stream.git + dependencies: + - tech_cells_generic + ibex: + revision: b18f7ef178ed07f5085051f96042c670a919fd5c + version: null + source: + Git: https://github.com/pulp-platform/ibex.git + dependencies: + - tech_cells_generic + idma: + revision: ff5d56fffb3767814db88d6bf8f381974ea33aa5 + version: 0.6.4 + source: + Git: https://github.com/pulp-platform/iDMA.git + dependencies: + - axi + - axi_stream + - common_cells + - common_verification + - obi + - register_interface + l2_tcdm_hybrid_interco: + revision: fa55e72859dcfb117a2788a77352193bef94ff2b + version: 1.0.0 + source: + Git: https://github.com/pulp-platform/L2_tcdm_hybrid_interco.git + dependencies: [] + obi: + revision: 528dc65303d5ffb02fbc254324c6b53eac0dd6e5 + version: null + source: + Git: https://github.com/pulp-platform/obi.git + dependencies: + - common_cells + - common_verification + redmule: + revision: 4c7bdf3c46483780c6f2e18f833be2ea664af36c + version: 2.1.0 + source: + Git: https://github.com/pulp-platform/redmule.git + dependencies: + - common_cells + - cv32e40p + - cv32e40x + - fpnew + - hci + - hwpe-ctrl + - hwpe-stream + - ibex + - tech_cells_generic + redundancy_cells: + revision: c37bdb47339bf70e8323de8df14ea8bbeafb6583 + version: null + source: + Git: https://github.com/pulp-platform/redundancy_cells.git + dependencies: + - common_cells + - common_verification + - register_interface + - tech_cells_generic + register_interface: + revision: d6e1d4cdaab7870f4faf3f88a1c788eaf5ac129d + version: 0.4.7 + source: + Git: https://github.com/pulp-platform/register_interface.git + dependencies: + - apb + - axi + - common_cells + - common_verification + riscv-dbg: + revision: 122510063a02e0d012f0497ffdbafca53d4e716b + version: 0.7.0 + source: + Git: https://github.com/pulp-platform/riscv-dbg.git + dependencies: + - common_cells + - tech_cells_generic + scm: + revision: 1976c7efb4979271eee2abe262fde0f9a20e2557 + version: 1.2.1 + source: + Git: https://github.com/pulp-platform/scm.git + dependencies: + - tech_cells_generic + spatz: + revision: 9380883fd36a4794d7f31e2c22e3fed3202aeb81 + version: null + source: + Git: https://github.com/pulp-platform/spatz.git + dependencies: + - axi + - axi_riscv_atomics + - cluster_icache + - common_cells + - fpnew + - idma + - register_interface + - riscv-dbg + - tech_cells_generic + tech_cells_generic: + revision: 3a3de73632a06826b1bd9c65a0a2e92b32016845 + version: 0.2.14 + source: + Git: https://github.com/pulp-platform/tech_cells_generic.git + dependencies: + - common_verification diff --git a/Bender.yml b/Bender.yml index 2c704487..b46a53ae 100644 --- a/Bender.yml +++ b/Bender.yml @@ -37,7 +37,7 @@ dependencies: fpu_ss : { git: "https://github.com/pulp-platform/fpu_ss.git" , rev: 8e2eff774d9d38a1e17a46bd56a0936dac9522f0 } # branch: vi/bender_manifest obi : { git: "https://github.com/pulp-platform/obi.git" , rev: 528dc65303d5ffb02fbc254324c6b53eac0dd6e5 } # branch: lb/fix_atop_resolver axi : { git: "https://github.com/pulp-platform/axi.git" , version: 0.39.5 } - register_interface: { git: "https://github.com/pulp-platform/register_interface.git", version: 0.4.4 } + register_interface: { git: "https://github.com/pulp-platform/register_interface.git", version: 0.4.7 } axi_obi : { git: "https://github.com/pulp-platform/axi_obi.git" , rev: 3f29bd67369a093cf5be4ea3fdac3c6c216424cc } # branch: vi/magia common_cells : { git: "https://github.com/pulp-platform/common_cells.git" , version: 1.21.0 } tech_cells_generic: { git: "https://github.com/pulp-platform/tech_cells_generic.git", version: 0.2.11 } diff --git a/Makefile b/Makefile index 5895f6ec..0ee5b8ec 100644 --- a/Makefile +++ b/Makefile @@ -62,12 +62,6 @@ else XABI ?= endif -#ifeq ($(REDMULE_COMPLEX),1) -# TEST_SRCS := sw/redmule_complex.c -#else -# TEST_SRCS := sw/redmule.c -#endif - # Auto-detect test location under sw/tests/ recursively — no cluster= flag needed. # A directory named $(test) is searched first (handles both sw/tests// and # sw/tests/cluster_tests//); single-file tests fall back to sw/tests/$(test).c. @@ -321,7 +315,6 @@ else cd $(TEST_BUILD_DIR); \ $(QUESTA) vsim vopt_tb $(questa_run_flag) -l transcript \ -do "add log -r sim:/$(tb)/*" \ - -do "source $(WAVES)" \ +INST_HEX=$(inst_hex_name) \ +DATA_HEX=$(data_hex_name) \ +INST_ENTRY=$(inst_entry) \ @@ -380,22 +373,12 @@ bender_targs += -t snitch_cluster bender_targs += -t idma_test bender_targs += -t spatz -#ifeq ($(REDMULE_COMPLEX),1) -# tb := redmule_complex_tb -# WAVES := $(mkfile_path)/wave_complex_xif.do -# bender_targs += -t redmule_complex -#else -# tb := redmule_tb -# WAVES := $(mkfile_path)/wave.do -# bender_targs += -t redmule_hwpe -#endif - ifeq ($(mesh_dv),1) tb := magia_tb else tb := magia_tile_tb endif -WAVES := $(mkfile_path)/wave.do + ifeq ($(core), CV32E40X) bender_targs += -t redmule_complex bender_targs += -t cv32e40x_bhv @@ -436,9 +419,9 @@ CV32E40P_REV := a8206ab02759f110c40dd907369816ea656381bc update-ips: ifeq ($(core), RI5CY) - @sed -i 's|^ cv32e40p .*| cv32e40p : { git: "$(RI5CY_CV32E40P_GIT)" , rev: $(RI5CY_CV32E40P_REV) } # RI5CY branch: lb/magia_core|' Bender.local + @sed -i '/^ cv32e40p:$$/,/^ cv32e40x:/ { s|^ revision: .*| revision: $(RI5CY_CV32E40P_REV)|; s|^ Git: .*| Git: $(RI5CY_CV32E40P_GIT)|; }' Bender.lock else - @sed -i 's|^ cv32e40p .*| cv32e40p : { git: "$(CV32E40P_GIT)" , rev: $(CV32E40P_REV) } # branch: ng/pulp_cluster|' Bender.local + @sed -i '/^ cv32e40p:$$/,/^ cv32e40x:/ { s|^ revision: .*| revision: $(CV32E40P_REV)|; s|^ Git: .*| Git: $(CV32E40P_GIT)|; }' Bender.lock endif $(BENDER) update $(BENDER) script vsim \ @@ -449,6 +432,11 @@ endif > ${compile_script} vsim-scripts: +ifeq ($(core), RI5CY) + @sed -i '/^ cv32e40p:$$/,/^ cv32e40x:/ { s|^ revision: .*| revision: $(RI5CY_CV32E40P_REV)|; s|^ Git: .*| Git: $(RI5CY_CV32E40P_GIT)|; }' Bender.lock +else + @sed -i '/^ cv32e40p:$$/,/^ cv32e40x:/ { s|^ revision: .*| revision: $(CV32E40P_REV)|; s|^ Git: .*| Git: $(CV32E40P_GIT)|; }' Bender.lock +endif $(BENDER) script vsim \ --vlog-arg="$(compile_flag)" \ --vcom-arg="-pedanticerrors" \ @@ -458,11 +446,10 @@ vsim-scripts: synth-ips: ifeq ($(core), RI5CY) - @sed -i 's|^ cv32e40p .*| cv32e40p : { git: "$(RI5CY_CV32E40P_GIT)" , rev: $(RI5CY_CV32E40P_REV) } # RI5CY branch: lb/magia_core|' Bender.local + @sed -i '/^ cv32e40p:$$/,/^ cv32e40x:/ { s|^ revision: .*| revision: $(RI5CY_CV32E40P_REV)|; s|^ Git: .*| Git: $(RI5CY_CV32E40P_GIT)|; }' Bender.lock else - @sed -i 's|^ cv32e40p .*| cv32e40p : { git: "$(CV32E40P_GIT)" , rev: $(CV32E40P_REV) } # branch: ng/pulp_cluster|' Bender.local + @sed -i '/^ cv32e40p:$$/,/^ cv32e40x:/ { s|^ revision: .*| revision: $(CV32E40P_REV)|; s|^ Git: .*| Git: $(CV32E40P_GIT)|; }' Bender.lock endif - $(BENDER) update $(MAKE) -C $(IDMA_ROOT) idma_hw_all IDMA_ADD_IDS=$(IDMA_ADD_IDS) $(BENDER) script synopsys \ $(common_targs) $(common_defs) \ @@ -586,7 +573,7 @@ hw-all: hw-clean hw-lib hw-compile hw-opt # Nonfree components MAGIA_NONFREE_REMOTE ?= git@iis-git.ee.ethz.ch:pulp-restricted/magia-nonfree MAGIA_NONFREE_DIR ?= nonfree -MAGIA_NONFREE_COMMIT ?= 1105ef2a69df5a6765c8362b6af007691c6ae3e5 +MAGIA_NONFREE_COMMIT ?= 825ec37e40a1b46749cbcd59ff77f75d7a8f0296 .PHONY: magia-nonfree-init MAGIA_NONFREE_DEPS ?= 1 diff --git a/README.md b/README.md index 5d1452b0..e1f9c47f 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ The following *optional* parameters can be specified: `gui`: **0**|**1** (**Default**: 0). 0 simulation without GUI; 1 simulation with GUI. +`core`: **CV32E40P**|**RI5CY**|**CV32E40X** (**Default**: CV32E40P). Control and cluster cores type. + **Instructions to build HW/SW and run simulations**: @@ -46,9 +48,10 @@ make python_deps ```bash make bender ``` +Remember to export the bender binary to your `PATH` variable. **4)** Clone the *dependencies* and generate the *compilation script* (`MAGIA` folder): ```bash -make update-ips > update-ips.log +make vsim-scripts > vsim-scripts.log ``` **4\*)** Apply FlooNoC *patch* - **currently FlooNoC requires this step but should not need it in the future** (`MAGIA` folder): ```bash @@ -56,15 +59,15 @@ make floonoc-patch ``` **5)** *Build* the hardware (`MAGIA` folder): ```bash -make build-hw > build-hw.log +make build-hw > build-hw.log ``` **6)** *Compile* the test code (`MAGIA` folder): ```bash -make all +make all ``` **7)** *Run* test (`MAGIA` folder): ```bash -make run +make run ``` **Full example**: @@ -73,7 +76,7 @@ make python_venv source setup_env.sh make python_deps make bender -make update-ips > update-ips.log +make vsim-scripts > vsim-scripts.log make build-hw > build-hw.log fast_sim=1 make all test=fsync_test make run test=fsync_test @@ -167,6 +170,16 @@ Cluster task sources live under `sw/tests//pulp_task/`. A test directory c **RTL/TB** : The `N_TILES_X` and `N_TILES_Y` parameters in `hw/mesh/magia_pkg.sv` specifie the number of tiles and allows the derivation of the appropriate data and syncrhonization networks. +## 🧪Local testing (semi-automatic) +To facilitate the functional verification, the [`bwruntests.py`](scripts/bwruntests.py) Python script can be used to locally run the same tests executed by the CI in an automated fashion. The two available sets of tests are defined in [`tile_tests.yml`](sw/tests/tile_tests.yml) and [`mesh_tests`](sw/tests/mesh_tests.yml). + +The Python script is supposed to be invoked from the main directory of this repository as follows: +```sh +python3 scripts/bwruntests.py -y [test_file.yml] +``` + +Differently from the CI flow, **the RTL must be MANUALLY compiled** with the correct `mesh_dv` flag depending on the target to be tested, i.e. single tile or full mesh. For a faster execution `fast_sim=1` is suggested. + ## 🔏 License MAGIA is an open-source project with a permissive license. All `software` sources are licensed under the Apache License 2.0 ([`LICENSE.APACHE`](LICENSE.APACHE)). All `hardware` sources are licensed under the Solderpad Hardware License 0.51 ([`LICENSE.SHL`](LICENSE.SHL)). diff --git a/requirements.txt b/requirements.txt index 8a0d844d..75ce169b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,5 @@ pyyaml mako hjson tabulate -matplotlib \ No newline at end of file +matplotlib +PrettyTable \ No newline at end of file diff --git a/scripts/bwruntests.py b/scripts/bwruntests.py new file mode 100644 index 00000000..b98681f5 --- /dev/null +++ b/scripts/bwruntests.py @@ -0,0 +1,327 @@ +#!/usr/bin/env python3 + +# Copyright 2020-2026 ETH Zurich and University of Bologna +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# Run shell commands listed in a file separated by newlines in a parallel +# fashion. If requested the results (tuples consisting of command, stdout, +# stderr and returncode) will be gathered in a junit.xml file. There a few +# knobs to tune the number of spawned processes and the junit.xml formatting. + +# Author: Robert Balas (balasr@iis.ee.ethz.ch) + +import argparse +from subprocess import (Popen, TimeoutExpired, + CalledProcessError, PIPE) +from threading import Lock +import shlex +import sys +import signal +import os +import multiprocessing +import errno +import pprint +import time + + +runtest = argparse.ArgumentParser( + prog='bwruntests', + formatter_class=argparse.RawDescriptionHelpFormatter, + description="""Run MAGIA tests in parallel""", + epilog=""" +Test_file needs to be either a .yaml file (set the --yaml switch) +which looks like this: + +mytests.yml +[...] +parallel_bare_tests: # name of the test set + parMatrixMul8: # name of the test + path: ./parallel_bare_tests/parMatrixMul8 # path to the test's folder + command: make clean all run # command to run in the test's folder +[...] + +or + +Test_file needs to be a list of commands to be executed. Each line corresponds +to a single command and a test + +commands.f +[...] +make -C ./ml_tests/mlGrad clean all run +make -C ./ml_tests/mlDct clean all run +[...] + +Example: +bwruntests.py --proc-verbose -v \\ + --report-junit -t 3600 --yaml \\ + -o simplified-runtime.xml runtime-tests.yaml + +This Runs a set of tests defined in runtime-tests.yaml and dumps the +resulting junit.xml into simplified-runtime.xml. The --proc-verbose +scripts makes sure to print the stdout of each process to the shell. To +prevent a broken process from running forever, a maximum timeout of 3600 +seconds was set. For debugging purposes we enabled -v (--verbose) which +shows the full set of commands being run.""") + +runtest.version = '0.2' + +runtest.add_argument('test_file', type=str, + help='file defining tests to be run') +runtest.add_argument('--version', action='version', + version='%(prog)s ' + runtest.version) +runtest.add_argument('-p', '--max-procs', type=int, + default=multiprocessing.cpu_count(), + help="""Number of parallel + processes used to run test. + Default is number of cpu cores.""") +runtest.add_argument('-t', '--timeout', type=float, + default=None, + help="""Timeout for all processes in seconds""") +runtest.add_argument('-v', '--verbose', action='store_true', + help="""Enable verbose output""") +runtest.add_argument('-s', '--proc-verbose', action='store_true', + help="""Write processes' stdout and stderr to shell stdout + after they terminate""") +runtest.add_argument('--report-junit', action='store_true', + help="""Generate a junit report""") +runtest.add_argument('--disable-junit-pp', action='store_true', + help="""Disable pretty print of junit report""") +runtest.add_argument('--disable-results-pp', action='store_true', + help="""Disable printing test results""") +runtest.add_argument('-y,', '--yaml', action='store_true', + help="""Read tests from yaml file instead of executing + from a list of commands""") +runtest.add_argument('-o,', '--output', type=str, + help="""Write junit.xml to file instead of stdout""") +stdout_lock = Lock() + + +class FinishedProcess(object): + """A process that has finished running. + """ + def __init__(self, name, cwd, args, returncode, + stdout=None, stderr=None, time=None): + self.name = name + self.cwd = cwd + self.args = args + self.returncode = returncode + self.stdout = stdout + self.stderr = stderr + self.time = time + + def __repr__(self): + args = ['name={!r}'.format(self.name)] + args += ['cwd={!r}'.format(self.cwd)] + args += ['args={!r}'.format(self.args), + 'returncode={!r}'.format(self.returncode)] + if self.stdout is not None: + args.append('stdout={!r}'.format(self.stdout)) + if self.stderr is not None: + args.append('stderr={!r}'.format(self.stderr)) + if self.time is not None: + args.append('time={!r}'.format(self.time)) + return "{}({})".format(type(self).__name__, ', '.join(args)) + + +def fork(name, cwd, *popenargs, check=False, shell=True, + **kwargs): + """Run subprocess and return process args, error code, stdout and stderr + """ + + def proc_out(cwd, stdout, stderr): + print('cwd={}'.format(cwd)) + print('stdout=') + print(stdout.decode('utf-8')) + print('stderr=') + print(stderr.decode('utf-8')) + + kwargs['stdout'] = PIPE + kwargs['stderr'] = PIPE + + with Popen(*popenargs, preexec_fn=os.setpgrp, cwd=cwd, + **kwargs) as process: + try: + # Child and parent are racing for setting/using the pgid so we have + # to set it in both processes. See glib manual. + try: + os.setpgid(process.pid, process.pid) + except OSError as e: + if e.errno != errno.EACCES: + raise + # measure runtime + start = time.time() + stdout, stderr = process.communicate(input, timeout=args.timeout) + except TimeoutExpired: + pgid = os.getpgid(process.pid) + os.killpg(pgid, signal.SIGKILL) + # process.kill() will only kill the immediate child but not its + # forks. This won't work since our commands will create a few forks + # (make -> vsim -> etc). We need to make a process group and kill + # that + stdout, stderr = process.communicate() + timeoutmsg = 'TIMEOUT after {:f}s'.format(args.timeout) + + if args.proc_verbose: + stdout_lock.acquire() + print(name) + print(timeoutmsg) + proc_out(cwd, stdout, stderr) + stdout_lock.release() + + return FinishedProcess(name, cwd, process.args, 1, + stdout.decode('utf-8'), + timeoutmsg + '\n' + + stderr.decode('utf-8'), + time.time() - start) + # Including KeyboardInterrupt, communicate handled that. + except: # noqa: E722 + pgid = os.getpgid(process.pid) + os.killpg(pgid, signal.SIGKILL) + # We don't call process.wait() as .__exit__ does that for us. + raise + retcode = process.poll() + if check and retcode: + raise CalledProcessError(retcode, process.args, + output=stdout, stderr=stderr) + if args.proc_verbose: + stdout_lock.acquire() + print(name) + proc_out(cwd, stdout, stderr) + stdout_lock.release() + + return FinishedProcess(name, cwd, process.args, retcode, + stdout.decode('utf-8'), + stderr.decode('utf-8'), + time.time() - start) + + +if __name__ == '__main__': + args = runtest.parse_args() + pp = pprint.PrettyPrinter(indent=4) + + # lazy importing so that we can work without junit_xml + if args.report_junit: + try: + from junit_xml import TestSuite, TestCase + except ImportError: + print("""Error: The --report-junit option requires +the junit_xml library which is not installed.""", + file=sys.stderr) + exit(1) + + # lazy import PrettyTable for displaying results + if not(args.disable_results_pp): + try: + from prettytable import PrettyTable + except ImportError: + print("""Warning: Displaying results requires the PrettyTable +library which is not installed""") + + tests = [] # list of tuple (testname, working dir, command) + + # load tests (yaml or command list) + if args.yaml: + try: + import yaml + except ImportError: + print("""Error: The --yaml option requires +the pyyaml library which is not installed.""", + file=sys.stderr) + exit(1) + with open(args.test_file) as f: + testyaml = yaml.load(f, Loader=yaml.Loader) + for testsetname, testv in testyaml.items(): + for testname, insn in testv.items(): + cmd = shlex.split(insn['command']) + cwd = insn['path'] + tests.append((testsetname + ':' + testname, cwd, cmd)) + if args.verbose: + pp.pprint(tests) + else: # (command list) + with open(args.test_file) as f: + testnames = list(map(str.rstrip, f)) + shellcmds = [shlex.split(e) for e in testnames] + cwds = ['./' for e in testnames] + tests = list(zip(testnames, cwds, shellcmds)) + if args.verbose: + print('Tests which we are running:') + pp.pprint(tests) + pp.pprint(shellcmds) + + # Spawning process pool + # Disable signals to prevent race. Child processes inherit SIGINT handler + original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN) + pool = multiprocessing.Pool(processes=args.max_procs) + # Restore SIGINT handler + signal.signal(signal.SIGINT, original_sigint_handler) + try: + procresults = pool.starmap(fork, tests) + except KeyboardInterrupt: + print("\nTerminating bwruntest.py") + pool.terminate() + pool.join() + exit(1) + + if args.verbose: + pp.pprint(procresults) + pool.close() + pool.join() + + # Generate junit.xml file. Junit.xml differentiates between failure and + # errors but we treat everything as errors. + if args.report_junit: + testcases = [] + for p in procresults: + # we can either expect p.name = testsetname:testname + # or p.name = testname + testcase = TestCase(p.name, + classname=((p.name).split(':'))[0], + stdout=p.stdout, + stderr=p.stderr, + elapsed_sec=p.time) + if p.returncode != 0: + testcase.add_failure_info(p.stderr) + testcases.append(testcase) + + testsuite = TestSuite('bwruntests', testcases) + if args.output: + with open(args.output, 'w') as f: + TestSuite.to_file(f, [testsuite], + prettyprint=not(args.disable_junit_pp)) + else: + print(TestSuite.to_xml_string([testsuite], + prettyprint=(args.disable_junit_pp))) + + # print summary of test results + if not(args.disable_results_pp): + testcount = sum(1 for x in tests) + testfailcount = sum(1 for p in procresults if p.returncode != 0) + testpassedcount = testcount - testfailcount + resulttable = PrettyTable(['test', 'time', 'passed/total']) + resulttable.align['test'] = "l" + resulttable.add_row(['bwruntest', '', '{0:d}/{1:d}'. + format(testpassedcount, testcount)]) + for p in procresults: + testpassed = 1 if p.returncode == 0 else 0 + testname = p.name + resulttable.add_row([testname, + '{0:.2f}s'.format(p.time), + '{0:d}/{1:d}'.format(testpassed, 1)]) + print(resulttable) \ No newline at end of file diff --git a/setup_env.sh b/setup_env.sh index b3fdd0d9..21a963f6 100644 --- a/setup_env.sh +++ b/setup_env.sh @@ -9,10 +9,6 @@ echo "Exporting bender path to $BENDER_DIR" export PATH=$BENDER_DIR:$PATH unset BENDER_DIR echo "Exporting SDK and GCC Toolchain paths" -export PATH=/usr/pack/pulpsdk-1.0-kgf/artifactory/pulp-sdk-release/pkg/pulp_riscv_gcc/1.0.16/bin:$PATH -export PATH=/usr/pack/gcc-5.2.0-af/x86_64-rhe6-linux/bin:$PATH -export PATH=/usr/local/anaconda3-2023.07/condabin:$PATH -export PATH=/home/visachi/.local/bin:$PATH export XLEN=32 if [[ "$core" == "CV32E40P" ]] || [[ "$core" == "RI5CY" ]]; then echo "Exporting ISA extentions: I, M, C, PULP" diff --git a/sw/kernel/crt0.S b/sw/kernel/crt0.S index 2bf26a93..e43adfa6 100644 --- a/sw/kernel/crt0.S +++ b/sw/kernel/crt0.S @@ -28,8 +28,42 @@ .section .text .global _start _start: - csrr a0, mhartid + + # Manually reset (latch-based) registers of the RF + addi x1, x0, 0 + addi x2, x0, 0 + addi x3, x0, 0 + addi x4, x0, 0 + addi x5, x0, 0 + addi x6, x0, 0 + addi x7, x0, 0 + addi x8, x0, 0 + addi x9, x0, 0 + addi x10, x0, 0 + addi x11, x0, 0 + addi x12, x0, 0 + addi x13, x0, 0 + addi x14, x0, 0 + addi x15, x0, 0 + addi x16, x0, 0 + addi x17, x0, 0 + addi x18, x0, 0 + addi x19, x0, 0 + addi x20, x0, 0 + addi x21, x0, 0 + addi x22, x0, 0 + addi x23, x0, 0 + addi x24, x0, 0 + addi x25, x0, 0 + addi x26, x0, 0 + addi x27, x0, 0 + addi x28, x0, 0 + addi x29, x0, 0 + addi x30, x0, 0 + addi x31, x0, 0 + # Compute (tile_y, tile_x) just in case the test needs them in a0/a1. + csrr a0, mhartid andi a1, a0, 0x1f srli a0, a0, 5 diff --git a/sw/tests/fpu_test.c b/sw/tests/fpu_test.c index 83379b7b..70019034 100644 --- a/sw/tests/fpu_test.c +++ b/sw/tests/fpu_test.c @@ -25,7 +25,13 @@ #define B_VAL (56.78f) #define C_EXP (69.12f) -#define FP_TH (0.1f) +#ifdef CV32E40P +#define FP_TH (1e-45f) +#else +#ifdef RI5CY +#define FP_TH (8e-6f) +#endif +#endif #define abs_diff(x, y) (((x) > (y)) ? ((x) - (y)) : ((y) - (x))) @@ -39,7 +45,7 @@ inline uint32_t f_add(volatile uint32_t op_a, volatile uint32_t op_b){ } int main(void) { - uint32_t exit_code; + uint32_t error = 0; #ifndef CV32E40X volatile float a, b, c; @@ -49,6 +55,7 @@ int main(void) { if (abs_diff(c, C_EXP) > FP_TH){ printf("Test FAILED\n"); + error++; }else{ printf("Test PASSED\n"); } @@ -60,5 +67,5 @@ int main(void) { printf("Float operation result: 0x%0x [expected: 0x428A3D71(69.12f)]\n", c); #endif - return 0; + return error; } diff --git a/sw/tests/mesh_tests.yml b/sw/tests/mesh_tests.yml new file mode 100644 index 00000000..272c3803 --- /dev/null +++ b/sw/tests/mesh_tests.yml @@ -0,0 +1,43 @@ +# Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Author: Alessandro Nadalini + +mesh-generic-tests: + inter_l1_test: + path: . + command: make clean all run mesh_dv=1 fast_sim=1 test=inter_l1_test +redmule-tests: + mm_tests/mesh_test_mm: + path: . + command: make clean all run mesh_dv=1 fast_sim=1 test=mm_tests/mesh_test_mm + eu_tests/mesh_test_event_unit: + path: . + command: make clean all run mesh_dv=1 fast_sim=1 test=eu_tests/mesh_test_event_unit + mm_tests/fsync_extended_test_mm: + path: . + command: make clean all run mesh_dv=1 fast_sim=1 test=mm_tests/fsync_extended_test_mm + eu_tests/fsync_extended_test_event_unit: + path: . + command: make clean all run mesh_dv=1 fast_sim=1 test=eu_tests/fsync_extended_test_event_unit +spatz-tests: + hello_mesh_spatz_test: + path: . + command: make clean all run mesh_dv=1 fast_sim=1 test=hello_mesh_spatz_test + atomic_mesh_spatz_test: + path: . + command: make clean all run mesh_dv=1 fast_sim=1 test=atomic_mesh_spatz_test + dotp_mesh_spatz_test: + path: . + command: make clean all run mesh_dv=1 fast_sim=1 test=dotp_mesh_spatz_test \ No newline at end of file diff --git a/sw/tests/tile_tests.yml b/sw/tests/tile_tests.yml new file mode 100644 index 00000000..965983a8 --- /dev/null +++ b/sw/tests/tile_tests.yml @@ -0,0 +1,55 @@ +# Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Author: Alessandro Nadalini + +tile-generic-tests: + hello_world: + path: . + command: make clean all run mesh_dv=0 fast_sim=1 test=hello_world + fpu_test: + path: . + command: make clean all run mesh_dv=0 fast_sim=1 test=fpu_test +redmule-tests: + mm_tests/tile_test_mm: + path: . + command: make clean all run mesh_dv=0 fast_sim=1 test=mm_tests/tile_test_mm + eu_tests/tile_test_event_unit: + path: . + command: make clean all run mesh_dv=0 fast_sim=1 test=eu_tests/tile_test_event_unit +spatz-tests: + simple_spatz_test: + path: . + command: make clean all run mesh_dv=0 fast_sim=1 test=simple_spatz_test + dotp_spatz_test: + path: . + command: make clean all run mesh_dv=0 fast_sim=1 test=dotp_spatz_test + gemm_spatz_test: + path: . + command: make clean all run mesh_dv=0 fast_sim=1 test=gemm_spatz_test + matmul_compare_spatz_test: + path: . + command: make clean all run mesh_dv=0 fast_sim=1 test=matmul_compare_spatz_test + vecsum_spatz_test: + path: . + command: make clean all run mesh_dv=0 fast_sim=1 test=vecsum_spatz_test +pulp_cluster_tests: + hello_pulp: + path: . + command: make clean all run mesh_dv=0 fast_sim=1 test=hello_pulp + fpu_cluster_test: + path: . + command: make clean all run mesh_dv=0 fast_sim=1 test=fpu_cluster_test + + \ No newline at end of file