From c86b7fab642abf70f9dae78cbed60d622716887a Mon Sep 17 00:00:00 2001 From: piotro888 Date: Sun, 3 Dec 2023 17:26:32 +0100 Subject: [PATCH] Run riscv-arch-test suite in CI (#513) --- .github/workflows/main.yml | 134 ++++++++++++- ci/riscof_compare.sh | 53 ++++++ ci/riscof_run_makefile.sh | 22 +++ scripts/run_signature.py | 2 +- test/external/riscof/config.ini | 19 ++ .../riscof/coreblocks/coreblocks_isa.yaml | 7 + .../coreblocks/coreblocks_platform.yaml | 4 + .../riscof/coreblocks/riscof_coreblocks.py | 180 ++++++++++++++++++ test/external/riscof/spike_simple/__init__.py | 2 + test/external/riscof/spike_simple/env/link.ld | 17 ++ .../riscof/spike_simple/env/model_test.h | 60 ++++++ .../spike_simple/riscof_spike_simple.py | 98 ++++++++++ .../riscof/spike_simple/spike_simple_isa.yaml | 28 +++ .../spike_simple/spike_simple_platform.yaml | 10 + test/regression/signature.py | 2 +- 15 files changed, 629 insertions(+), 9 deletions(-) create mode 100755 ci/riscof_compare.sh create mode 100755 ci/riscof_run_makefile.sh create mode 100644 test/external/riscof/config.ini create mode 100644 test/external/riscof/coreblocks/coreblocks_isa.yaml create mode 100644 test/external/riscof/coreblocks/coreblocks_platform.yaml create mode 100644 test/external/riscof/coreblocks/riscof_coreblocks.py create mode 100644 test/external/riscof/spike_simple/__init__.py create mode 100644 test/external/riscof/spike_simple/env/link.ld create mode 100644 test/external/riscof/spike_simple/env/model_test.h create mode 100644 test/external/riscof/spike_simple/riscof_spike_simple.py create mode 100644 test/external/riscof/spike_simple/spike_simple_isa.yaml create mode 100644 test/external/riscof/spike_simple/spike_simple_platform.yaml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1bcdac433..d32c7ce1b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,8 +12,128 @@ on: workflow_dispatch: jobs: + build-core: + name: Synthethise full core + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Install Coreblocks dependencies + run: | + python3 -m venv venv + . venv/bin/activate + python3 -m pip install --upgrade pip + python3 -m pip install -r requirements-dev.txt + + - name: Generate Verilog + run: | + . venv/bin/activate + PYTHONHASHSEED=0 ./scripts/gen_verilog.py --verbose --config full + + - uses: actions/upload-artifact@v3 + with: + name: "verilog-full-core" + path: core.v + + + build-riscof-tests: + name: Build regression tests (riscv-arch-test) + runs-on: ubuntu-latest + container: ghcr.io/kuznia-rdzeni/riscv-toolchain:2023.11.19_v + timeout-minutes: 10 + env: + PYENV_ROOT: "/root/.pyenv" + LC_ALL: "C.UTF8" + LANG: "C.UTF8" + defaults: + run: + working-directory: test/external/riscof/ + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup PATH + run: echo "/.pyenv/bin" >> $GITHUB_PATH + + - name: Setup pyenv python + run: | + eval "$(pyenv init --path)" + pyenv global 3.6.15 + . /venv3.6/bin/activate + + - name: Setup arch test suite + run: | + . /venv3.6/bin/activate + riscof --verbose info arch-test --clone + riscof testlist --config=config.ini --suite=riscv-arch-test/riscv-test-suite/ --env=riscv-arch-test/riscv-test-suite/env + + - name: Build and run tests on reference and generate Makefiles + run: | + . /venv3.6/bin/activate + riscof run --config=config.ini --suite=riscv-arch-test/riscv-test-suite/ --env=riscv-arch-test/riscv-test-suite/env + + - name: Build tests for Coreblocks + run: | + MAKEFILE_PATH=riscof_work/Makefile.build-DUT-coreblocks ../../../ci/riscof_run_makefile.sh + + - uses: actions/upload-artifact@v3 + with: + name: "riscof-tests" + path: | + test/external/riscof/riscv-arch-test/**/*.elf + test/external/riscof/riscof_work/**/*.signature + test/external/riscof/**/*Makefile* + + run-riscof-tests: + name: Run regression tests (riscv-arch-test) + runs-on: ubuntu-latest + container: ghcr.io/kuznia-rdzeni/verilator:v5.008-2023.11.19_v + needs: [ build-riscof-tests, build-core ] + timeout-minutes: 20 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Install Coreblocks dependencies + run: | + python3 -m venv venv + . venv/bin/activate + python3 -m pip install --upgrade pip + python3 -m pip install -r requirements-dev.txt + + - uses: actions/download-artifact@v3 + with: + name: "verilog-full-core" + path: . + + - uses: actions/download-artifact@v3 + with: + name: "riscof-tests" + path: test/external/riscof/ + + - name: Run tests on Coreblocks + run: | + . venv/bin/activate + MAKEFILE_PATH=test/external/riscof/riscof_work/Makefile.run-DUT-coreblocks NPROC=1 ./ci/riscof_run_makefile.sh + + - name: Compare signatures (test results) + run: MAKEFILE_PATH=test/external/riscof/riscof_work/Makefile.run-DUT-coreblocks ./ci/riscof_compare.sh + + build-regression-tests: - name: Build regression tests + name: Build regression tests (riscv-tests) runs-on: ubuntu-latest container: ghcr.io/kuznia-rdzeni/riscv-toolchain:2023.11.19_v outputs: @@ -31,7 +151,7 @@ jobs: cache-name: cache-regression-tests with: path: test/external/riscv-tests/test-* - + key: ${{ env.cache-name }}-${{ runner.os }}-${{ hashFiles( '**/test/external/riscv-tests/environment/**', '**/test/external/riscv-tests/Makefile', @@ -51,7 +171,7 @@ jobs: path: test/external/riscv-tests run-regression-tests: - name: Run regression tests + name: Run regression tests (riscv-tests) runs-on: ubuntu-latest timeout-minutes: 10 container: ghcr.io/kuznia-rdzeni/verilator:v5.008-2023.11.19_v @@ -74,10 +194,10 @@ jobs: python3 -m pip install --upgrade pip python3 -m pip install -r requirements-dev.txt - - name: Generate Verilog - run: | - . venv/bin/activate - PYTHONHASHSEED=0 ./scripts/gen_verilog.py --verbose --config full + - uses: actions/download-artifact@v3 + with: + name: "verilog-full-core" + path: . - uses: actions/cache@v3 env: diff --git a/ci/riscof_compare.sh b/ci/riscof_compare.sh new file mode 100755 index 000000000..db5e76d90 --- /dev/null +++ b/ci/riscof_compare.sh @@ -0,0 +1,53 @@ +#!/bin/sh + +if [ -z "$MAKEFILE_PATH" ]; then + echo "Makefile path not specifed. Exiting... " + exit 1 +fi + +[ ! -z "$DIFF_QUIET" ] && [ "$DIFF_QUIET" -eq 1 ] && diff_add_args="-q" + +RED="\033[1;31m" +GREEN="\033[1;32m" +RED_BG="\033[0;41m" +GREEN_BG="\033[0;42m" +NO_COLOR="\033[0m" + +signature_files="$(cat $MAKEFILE_PATH | sed -n 's/^.*-o=\(.*\.signature\).*$/\1/p')" + +REFERENCE_DIR_SUFF="/../ref/Reference-Spike.signature" + +echo "> Veryfing signatures" +target_cnt=0 +fail_cnt=0 + +for sig in $signature_files +do + ref="$(dirname "$sig")$REFERENCE_DIR_SUFF" + echo ">> Comparing $sig (TARGET$target_cnt) to $ref" + + diff -b --strip-trailing-cr $diff_add_args "$sig" "$ref" + res=$? + + [ -f "$ref" ] || echo -e "${RED}!${NO_COLOR} Reference signature file not found!" + [ -f "$sig" ] || echo -e "${RED}!${NO_COLOR} Coreblocks signature file not found! Check signature run logs" + [ -s "$sig" ] || echo -e "${RED}!${NO_COLOR} Coreblock signature file is empty! Check signature run logs" + + if [ $res = 0 ] + then + echo -e "${GREEN}[PASS] Signature verification passed (TARGET$target_cnt)${NO_COLOR}" + else + echo -e "${RED}[FAIL] Signature verification failed (TARGET$target_cnt)${NO_COLOR}" + fail_cnt=$(( $fail_cnt+1 )) + fi + + target_cnt=$(( $target_cnt+1 )) +done + +rc=1 +[ $fail_cnt -eq 0 ] && rc=0 + +bg=${GREEN_BG} +[ $rc = 1 ] && bg=$RED_BG +echo -e "${bg}>>> Compared $target_cnt signatures, FAILED=$fail_cnt, PASSED=$(($target_cnt-$fail_cnt))${NO_COLOR}" +exit $rc diff --git a/ci/riscof_run_makefile.sh b/ci/riscof_run_makefile.sh new file mode 100755 index 000000000..7363893cc --- /dev/null +++ b/ci/riscof_run_makefile.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +if [ -z "$MAKEFILE_PATH" ]; then + echo "Makefile path not specifed. Exiting... " + exit 1 +fi + +[ -z "$NPROC" ] && NPROC=$(nproc) + +target_cnt=$(cat $MAKEFILE_PATH | grep TARGET | tail -n 1 | tr -d -c 0-9) + +echo "> Running for $target_cnt Makefile targets" + +targets="" + +for i in $(seq 0 $target_cnt) +do + targets="$targets TARGET$i" +done + +echo "Starting for targets: $targets" +make -f $MAKEFILE_PATH -i -j $NPROC $targets diff --git a/scripts/run_signature.py b/scripts/run_signature.py index 6acb4e311..7d45bae7f 100755 --- a/scripts/run_signature.py +++ b/scripts/run_signature.py @@ -19,7 +19,7 @@ def run_with_cocotb(test_name: str, traces: bool, output: str) -> bool: arglist = [ "make", "-C", - parent + "/" if parent else "" + "test/regression/cocotb", + (parent + "/" if parent else "") + "test/regression/cocotb", "-f", "signature.Makefile", "--no-print-directory", diff --git a/test/external/riscof/config.ini b/test/external/riscof/config.ini new file mode 100644 index 000000000..82ac943be --- /dev/null +++ b/test/external/riscof/config.ini @@ -0,0 +1,19 @@ +[RISCOF] +ReferencePlugin=spike_simple +ReferencePluginPath=./spike_simple +DUTPlugin=coreblocks +DUTPluginPath=./coreblocks + +[coreblocks] +pluginpath=./coreblocks +PATH=../../../../ +ispec=./coreblocks/coreblocks_isa.yaml +pspec=./coreblocks/coreblocks_platform.yaml +target_run=0 + +[spike_simple] +pluginpath=./spike_simple +PATH=/spike/install/bin/ +ispec=./spike_simple/spike_simple_isa.yaml +pspec=./spike_simple/spike_simple_platform.yaml +compare_run=0 diff --git a/test/external/riscof/coreblocks/coreblocks_isa.yaml b/test/external/riscof/coreblocks/coreblocks_isa.yaml new file mode 100644 index 000000000..483e8b41f --- /dev/null +++ b/test/external/riscof/coreblocks/coreblocks_isa.yaml @@ -0,0 +1,7 @@ +hart_ids: [0] +hart0: + ISA: RV32I + physical_addr_sz: 32 + + User_Spec_Version: '2.3' + supported_xlen: [32] diff --git a/test/external/riscof/coreblocks/coreblocks_platform.yaml b/test/external/riscof/coreblocks/coreblocks_platform.yaml new file mode 100644 index 000000000..21b02790b --- /dev/null +++ b/test/external/riscof/coreblocks/coreblocks_platform.yaml @@ -0,0 +1,4 @@ +reset: + label: reset_vector +nmi: + label: nmi_vector diff --git a/test/external/riscof/coreblocks/riscof_coreblocks.py b/test/external/riscof/coreblocks/riscof_coreblocks.py new file mode 100644 index 000000000..549e24934 --- /dev/null +++ b/test/external/riscof/coreblocks/riscof_coreblocks.py @@ -0,0 +1,180 @@ +import os +import logging + +import riscof.utils as utils +from riscof.pluginTemplate import pluginTemplate + +logger = logging.getLogger() + + +# This is a slightly modified default configuration for RISCOF DUT +# Changes: +# * adapt to other toolchain and run scripts +# * produce two makefiles instead of one +# * always generate all makefiles and just skip execution on target_run=0 option + + +class coreblocks(pluginTemplate): # noqa: N801 + __model__ = "coreblocks" + + __version__ = "XXX" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + config = kwargs.get("config") + + # If the config node for this DUT is missing or empty. Raise an error. At minimum we need + # the paths to the ispec and pspec files + if config is None: + print("Please enter input file paths in configuration.") + raise SystemExit(1) + + # In case of an RTL based DUT, this would be point to the final binary executable of your + # test-bench produced by a simulator (like verilator, vcs, incisive, etc). In case of an iss or + # emulator, this variable could point to where the iss binary is located. If 'PATH variable + # is missing in the config.ini we can hardcode the alternate here. + # temporary! + coreblocks_path = config["PATH"] if "PATH" in config else "coreblocks" + self.dut_exe = "python3 " + os.path.join(coreblocks_path, "scripts", "run_signature.py") + self.dut_exe += " -b cocotb" + + # Number of parallel jobs that can be spawned off by RISCOF + # for various actions performed in later functions, specifically to run the tests in + # parallel on the DUT executable. Can also be used in the build function if required. + self.num_jobs = str(config["jobs"] if "jobs" in config else 1) + + # Path to the directory where this python file is located. Collect it from the config.ini + self.pluginpath = os.path.abspath(config["pluginpath"]) + + # Collect the paths to the riscv-config absed ISA and platform yaml files. One can choose + # to hardcode these here itself instead of picking it from the config.ini file. + self.isa_spec = os.path.abspath(config["ispec"]) + self.platform_spec = os.path.abspath(config["pspec"]) + + # We capture if the user would like the run the tests on the target or + # not. If you are interested in just compiling the tests and not running + # them on the target, then following variable should be set to False + if "target_run" in config and config["target_run"] == "0": + self.target_run = False + else: + self.target_run = True + + def initialise(self, suite, work_dir, archtest_env): + # capture the working directory. Any artifacts that the DUT creates should be placed in this + # directory. Other artifacts from the framework and the Reference plugin will also be placed + # here itself. + self.work_dir = work_dir + + # capture the architectural test-suite directory. + self.suite_dir = suite + + # Note the march is not hardwired here, because it will change for each + # test. Similarly the output elf name and compile macros will be assigned later in the + # runTests function + # Change: Always use riscv64 + self.compile_cmd = ( + "riscv64-unknown-elf-gcc -march={0} \ + -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles -g\ + -T " + + self.pluginpath + + "/env/link.ld\ + -I " + + self.pluginpath + + "/env/\ + -I " + + archtest_env + + " {2} -o {3} {4}" + ) + + # add more utility snippets here + + def build(self, isa_yaml, platform_yaml): + # load the isa yaml as a dictionary in python. + ispec = utils.load_yaml(isa_yaml)["hart0"] + + # capture the XLEN value by picking the max value in 'supported_xlen' field of isa yaml. This + # will be useful in setting integer value in the compiler string (if not already hardcoded); + self.xlen = "64" if 64 in ispec["supported_xlen"] else "32" + + # for coreblocks start building the '--isa' argument. the self.isa is dut specific and may not be + # useful for all DUTs + self.isa = "rv" + self.xlen + if "I" in ispec["ISA"]: + self.isa += "i" + if "M" in ispec["ISA"]: + self.isa += "m" + if "F" in ispec["ISA"]: + self.isa += "f" + if "D" in ispec["ISA"]: + self.isa += "d" + if "C" in ispec["ISA"]: + self.isa += "c" + if "B" in ispec["ISA"]: + self.isa += "b" + + # TODO: The following assumes you are using the riscv-gcc toolchain. If + # not please change appropriately + self.compile_cmd = self.compile_cmd + " -mabi=" + ("lp64 " if 64 in ispec["supported_xlen"] else "ilp32 ") + + def runTests(self, testList): # noqa: N802 N803 + # Delete Makefile if it already exists. + if os.path.exists(self.work_dir + "/Makefile." + self.name[:-1]): + os.remove(self.work_dir + "/Makefile." + self.name[:-1]) + + # For coreblocks generate two makefiles - one for build and one for run. + # It is needed because of use of separate containers, and allows caching built tests + make_build = utils.makeUtil(makefilePath=os.path.join(self.work_dir, "Makefile.build-" + self.name[:-1])) + make_run = utils.makeUtil(makefilePath=os.path.join(self.work_dir, "Makefile.run-" + self.name[:-1])) + + # set the make command that will be used. The num_jobs parameter was set in the __init__ + # function earlier + make_build.makeCommand = "make -k -j" + self.num_jobs + make_run.makeCommand = "make -k -j" + self.num_jobs + + # we will iterate over each entry in the testList. Each entry node will be refered to by the + # variable testname. + for testname in testList: + # for each testname we get all its fields (as described by the testList format) + testentry = testList[testname] + + # we capture the path to the assembly file of this test + test = testentry["test_path"] + + # capture the directory where the artifacts of this test will be dumped/created. RISCOF is + # going to look into this directory for the signature files + test_dir = testentry["work_dir"] + + # name of the elf file after compilation of the test + elf = testname + ".elf" + + # name of the signature file as per requirement of RISCOF. RISCOF expects the signature to + # be named as DUT-.signature. The below variable creates an absolute path of + # signature file. + sig_file = os.path.join(test_dir, self.name[:-1] + ".signature") + + # for each test there are specific compile macros that need to be enabled. The macros in + # the testList node only contain the macros/values. For the gcc toolchain we need to + # prefix with "-D". The following does precisely that. + compile_macros = " -D" + " -D".join(testentry["macros"]) + + # substitute all variables in the compile command that we created in the initialize + # function + buildcmd = self.compile_cmd.format(testentry["isa"].lower(), self.xlen, test, elf, compile_macros) + + simcmd = self.dut_exe + " -o={0} {1}".format(sig_file, elf) + + # concatenate all commands that need to be executed within a make-target. + target_build = "cd {0}; {1};".format(testentry["work_dir"], buildcmd) + target_run = "mkdir -p {0}; cd {1}; {2};".format(testentry["work_dir"], self.work_dir, simcmd) + + # create a target. The makeutil will create a target with the name "TARGET" where num + # starts from 0 and increments automatically for each new target that is added + make_build.add_target(target_build) + make_run.add_target(target_run) + + if self.target_run: + # once the make-targets are done and the makefile has been created, run all the targets in + # parallel using the make command set above. + make_build.execute_all(self.work_dir) + make_run.execute_all(self.work_dir) diff --git a/test/external/riscof/spike_simple/__init__.py b/test/external/riscof/spike_simple/__init__.py new file mode 100644 index 000000000..3ad9513f4 --- /dev/null +++ b/test/external/riscof/spike_simple/__init__.py @@ -0,0 +1,2 @@ +from pkgutil import extend_path +__path__ = extend_path(__path__, __name__) diff --git a/test/external/riscof/spike_simple/env/link.ld b/test/external/riscof/spike_simple/env/link.ld new file mode 100644 index 000000000..26538d5bd --- /dev/null +++ b/test/external/riscof/spike_simple/env/link.ld @@ -0,0 +1,17 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY(rvtest_entry_point) + +SECTIONS +{ + . = 0x80000000; + .text.init : { *(.text.init) } + . = ALIGN(0x1000); + .tohost : { *(.tohost) } + . = ALIGN(0x1000); + .text : { *(.text) } + . = ALIGN(0x1000); + .data : { *(.data) } + .data.string : { *(.data.string)} + .bss : { *(.bss) } + _end = .; +} diff --git a/test/external/riscof/spike_simple/env/model_test.h b/test/external/riscof/spike_simple/env/model_test.h new file mode 100644 index 000000000..b93e53a01 --- /dev/null +++ b/test/external/riscof/spike_simple/env/model_test.h @@ -0,0 +1,60 @@ +#ifndef _COMPLIANCE_MODEL_H +#define _COMPLIANCE_MODEL_H +#if XLEN == 64 + #define ALIGNMENT 3 +#else + #define ALIGNMENT 2 +#endif + +#define RVMODEL_DATA_SECTION \ + .pushsection .tohost,"aw",@progbits; \ + .align 8; .global tohost; tohost: .dword 0; \ + .align 8; .global fromhost; fromhost: .dword 0; \ + .popsection; \ + .align 8; .global begin_regstate; begin_regstate: \ + .word 128; \ + .align 8; .global end_regstate; end_regstate: \ + .word 4; + +//RV_COMPLIANCE_HALT +#define RVMODEL_HALT \ + li x1, 1; \ + write_tohost: \ + sw x1, tohost, t2; \ + j write_tohost; + +#define RVMODEL_BOOT + +//RV_COMPLIANCE_DATA_BEGIN +#define RVMODEL_DATA_BEGIN \ + RVMODEL_DATA_SECTION \ + .align ALIGNMENT;\ + .global begin_signature; begin_signature: + +//RV_COMPLIANCE_DATA_END +#define RVMODEL_DATA_END \ + .global end_signature; end_signature: + +//RVTEST_IO_INIT +#define RVMODEL_IO_INIT +//RVTEST_IO_WRITE_STR +#define RVMODEL_IO_WRITE_STR(_R, _STR) +//RVTEST_IO_CHECK +#define RVMODEL_IO_CHECK() +//RVTEST_IO_ASSERT_GPR_EQ +#define RVMODEL_IO_ASSERT_GPR_EQ(_S, _R, _I) +//RVTEST_IO_ASSERT_SFPR_EQ +#define RVMODEL_IO_ASSERT_SFPR_EQ(_F, _R, _I) +//RVTEST_IO_ASSERT_DFPR_EQ +#define RVMODEL_IO_ASSERT_DFPR_EQ(_D, _R, _I) + +#define RVMODEL_SET_MSW_INT + +#define RVMODEL_CLEAR_MSW_INT + +#define RVMODEL_CLEAR_MTIMER_INT + +#define RVMODEL_CLEAR_MEXT_INT + + +#endif // _COMPLIANCE_MODEL_H diff --git a/test/external/riscof/spike_simple/riscof_spike_simple.py b/test/external/riscof/spike_simple/riscof_spike_simple.py new file mode 100644 index 000000000..5e06de990 --- /dev/null +++ b/test/external/riscof/spike_simple/riscof_spike_simple.py @@ -0,0 +1,98 @@ +import os +import re +import shutil +import subprocess +import shlex +import logging +import random +import string +from string import Template +import sys + +import riscof.utils as utils +from riscof.pluginTemplate import pluginTemplate +import riscof.constants as constants + +logger = logging.getLogger() + +class spike_simple(pluginTemplate): + __model__ = "Spike" + __version__ = "0.5.0" + + def __init__(self, *args, **kwargs): + sclass = super().__init__(*args, **kwargs) + + config = kwargs.get('config') + self.spike_exe = os.path.join(config['PATH'] if 'PATH' in config else "","spike") + if config is None: + print("Please enter input file paths in configuration.") + raise SystemExit + try: + self.isa_spec = os.path.abspath(config['ispec']) + self.platform_spec = os.path.abspath(config['pspec']) + self.pluginpath = os.path.abspath(config['pluginpath']) + except KeyError as e: + logger.error("Please check the spike_simple section in config for missing values.") + logger.error(e) + raise SystemExit + logger.debug("SPIKE Simple plugin initialised using the following configuration.") + for entry in config: + logger.debug(entry+' : '+config[entry]) + + self.compare_run = not ("compare_run" in config and config["compare_run"] == "0") + + return sclass + + def initialise(self, suite, work_dir, compliance_env): + self.work_dir = work_dir + self.compile_cmd = 'riscv64-unknown-elf-gcc -march={0} \ + -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles\ + -T '+self.pluginpath+'/env/link.ld\ + -I '+self.pluginpath+'/env/\ + -I ' + compliance_env + + def build(self, isa_yaml, platform_yaml): + ispec = utils.load_yaml(isa_yaml)['hart0'] + self.xlen = ('64' if 64 in ispec['supported_xlen'] else '32') + self.isa = 'rv' + self.xlen + if "64I" in ispec["ISA"]: + self.compile_cmd = self.compile_cmd+' -mabi='+'lp64 ' + elif "32I" in ispec["ISA"]: + self.compile_cmd = self.compile_cmd+' -mabi='+'ilp32 ' + elif "32E" in ispec["ISA"]: + self.compile_cmd = self.compile_cmd+' -mabi='+'ilp32e ' + if "I" in ispec["ISA"]: + self.isa += 'i' + if "M" in ispec["ISA"]: + self.isa += 'm' + if "C" in ispec["ISA"]: + self.isa += 'c' + compiler = "riscv64-unknown-elf-gcc".format(self.xlen) + if shutil.which(compiler) is None: + logger.error(compiler+": executable not found. Please check environment setup.") + raise SystemExit + if shutil.which(self.spike_exe) is None: + logger.error(self.spike_exe+ ": executable not found. Please check environment setup.") + raise SystemExit + + def runTests(self, testList): + for file in testList: + testentry = testList[file] + test = testentry['test_path'] + test_dir = testentry['work_dir'] + + elf = 'my.elf' + sig_file = os.path.join(test_dir, self.name[:-1] + ".signature") + + cmd = self.compile_cmd.format(testentry['isa'].lower(), self.xlen) + ' ' + test + ' -o ' + elf + compile_cmd = cmd + ' -D' + " -D".join(testentry['macros']) + logger.debug('Compiling test: ' + test) + utils.shellCommand(compile_cmd).run(cwd=test_dir) + + execute = self.spike_exe + ' --isa={0} +signature={1} +signature-granularity=4 {2}'.format(self.isa, sig_file, elf) + logger.debug('Executing on Spike ' + execute) + utils.shellCommand(execute).run(cwd=test_dir) + + if not self.compare_run: + # exit now if we don't want to run compare of signatures + raise SystemExit(0) diff --git a/test/external/riscof/spike_simple/spike_simple_isa.yaml b/test/external/riscof/spike_simple/spike_simple_isa.yaml new file mode 100644 index 000000000..dad55a4f1 --- /dev/null +++ b/test/external/riscof/spike_simple/spike_simple_isa.yaml @@ -0,0 +1,28 @@ +hart_ids: [0] +hart0: + ISA: RV32IMCZicsr_Zifencei + physical_addr_sz: 32 + User_Spec_Version: '2.3' + supported_xlen: [32] + misa: + reset-val: 0x40001104 + rv32: + accessible: true + mxl: + implemented: true + type: + warl: + dependency_fields: [] + legal: + - mxl[1:0] in [0x1] + wr_illegal: + - Unchanged + extensions: + implemented: true + type: + warl: + dependency_fields: [] + legal: + - extensions[25:0] bitmask [0x0001104, 0x0000000] + wr_illegal: + - Unchanged diff --git a/test/external/riscof/spike_simple/spike_simple_platform.yaml b/test/external/riscof/spike_simple/spike_simple_platform.yaml new file mode 100644 index 000000000..8e1a3d8e3 --- /dev/null +++ b/test/external/riscof/spike_simple/spike_simple_platform.yaml @@ -0,0 +1,10 @@ +mtime: + implemented: true + address: 0xbff8 +mtimecmp: + implemented: true + address: 0x4000 +nmi: + label: nmi_vector +reset: + label: reset_vector diff --git a/test/regression/signature.py b/test/regression/signature.py index 96b661199..e741d3493 100644 --- a/test/regression/signature.py +++ b/test/regression/signature.py @@ -46,7 +46,7 @@ async def run_test(sim_backend: SimulationBackend, test_path: str, signature_pat mem_segments.append(signature_ram) mem_model = CoreMemoryModel(mem_segments) - success = await sim_backend.run(mem_model, timeout_cycles=100000) + success = await sim_backend.run(mem_model, timeout_cycles=200000) if not success: raise RuntimeError(f"{test_path}: Simulation timed out")