[bazel] Build and run RISC-V compliance tests with Bazel Signed-off-by: Miguel Young de la Sota <mcyoung@google.com>
diff --git a/third_party/riscv-compliance/0001-Add-configurable-trap-alignment-and-entry-point-to-p.patch b/third_party/riscv-compliance/0001-Add-configurable-trap-alignment-and-entry-point-to-p.patch new file mode 100644 index 0000000..f454667 --- /dev/null +++ b/third_party/riscv-compliance/0001-Add-configurable-trap-alignment-and-entry-point-to-p.patch
@@ -0,0 +1,91 @@ +From e8b82ff045fca264917a7c5539bfcbe8ed22b7a0 Mon Sep 17 00:00:00 2001 +From: Greg Chadwick <gac@lowrisc.org> +Date: Wed, 15 Apr 2020 15:45:31 +0100 +Subject: [PATCH 1/5] Add configurable trap alignment and entry point to p + test-env + + +diff --git a/riscv-test-env/p/riscv_test.h b/riscv-test-env/p/riscv_test.h +index eaa6758..9423523 100644 +--- a/riscv-test-env/p/riscv_test.h ++++ b/riscv-test-env/p/riscv_test.h +@@ -60,14 +60,14 @@ + csrw pmpaddr0, t0; \ + li t0, PMP_NAPOT | PMP_R | PMP_W | PMP_X; \ + csrw pmpcfg0, t0; \ +- .align 2; \ ++ .align TRAPALIGN; \ + 1: + + #define INIT_SPTBR \ + la t0, 1f; \ + csrw mtvec, t0; \ + csrwi sptbr, 0; \ +- .align 2; \ ++ .align TRAPALIGN; \ + 1: + + #define DELEGATE_NO_TRAPS \ +@@ -76,7 +76,7 @@ + csrwi medeleg, 0; \ + csrwi mideleg, 0; \ + csrwi mie, 0; \ +- .align 2; \ ++ .align TRAPALIGN; \ + 1: + + #define RVTEST_ENABLE_SUPERVISOR \ +@@ -125,6 +125,14 @@ + #if defined(TRAPHANDLER) + #include TRAPHANDLER + #endif ++#if !defined(TRAPALIGN) ++#define TRAPALIGN 2 ++#endif ++ ++#if !defined(RVTEST_ENTRY) ++#define RVTEST_ENTRY _start ++#endif ++ + + #define INTERRUPT_HANDLER j other_exception /* No interrupts should occur */ + +@@ -133,11 +141,11 @@ + .align 6; \ + .weak stvec_handler; \ + .weak mtvec_handler; \ +- .globl _start; \ +-_start: \ ++ .globl RVTEST_ENTRY; \ ++RVTEST_ENTRY: \ + /* reset vector */ \ + j reset_vector; \ +- .align 2; \ ++ .align TRAPALIGN; \ + trap_vector: \ + /* test whether the test came from pass/fail */ \ + csrr t5, mcause; \ +diff --git a/riscv-test-suite/rv32i/src/I-EBREAK-01.S b/riscv-test-suite/rv32i/src/I-EBREAK-01.S +index 958eebc..32c074c 100644 +--- a/riscv-test-suite/rv32i/src/I-EBREAK-01.S ++++ b/riscv-test-suite/rv32i/src/I-EBREAK-01.S +@@ -71,6 +71,7 @@ RV_COMPLIANCE_CODE_BEGIN + + # --------------------------------------------------------------------------------------------- + # Exception handler ++.align TRAPALIGN + _trap_handler: + # increment return address + csrr x30, mepc +diff --git a/riscv-test-suite/rv32i/src/I-ECALL-01.S b/riscv-test-suite/rv32i/src/I-ECALL-01.S +index 5278207..0bdee2a 100644 +--- a/riscv-test-suite/rv32i/src/I-ECALL-01.S ++++ b/riscv-test-suite/rv32i/src/I-ECALL-01.S +@@ -73,6 +73,7 @@ RV_COMPLIANCE_CODE_BEGIN + + # --------------------------------------------------------------------------------------------- + # Exception handler ++.align TRAPALIGN + _trap_handler: + # increment return address + csrr x30, mepc
diff --git a/third_party/riscv-compliance/BUILD b/third_party/riscv-compliance/BUILD new file mode 100644 index 0000000..c4061cd --- /dev/null +++ b/third_party/riscv-compliance/BUILD
@@ -0,0 +1,9 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +load(":defs.bzl", "TESTS", "rv_compliance_test") + +package(default_visibility = ["//visibility:public"]) + +[[rv_compliance_test(test, arch) for test in tests] for arch, tests in TESTS.items()]
diff --git a/third_party/riscv-compliance/BUILD.riscv-compliance.bazel b/third_party/riscv-compliance/BUILD.riscv-compliance.bazel new file mode 100644 index 0000000..510f055 --- /dev/null +++ b/third_party/riscv-compliance/BUILD.riscv-compliance.bazel
@@ -0,0 +1,98 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +package(default_visibility = ["//visibility:public"]) + +exports_files(glob(["**/*"])) + +# NOTE: The files below are included as genrules rather than as patches so that +# they can be easilly edited without having to rebuild the patchset. +genrule( + name = "compliance_test_hdr", + outs = ["compliance_test.h"], + cmd = """echo '\ +// RISC-V Compliance Test Header File + +#ifndef _COMPLIANCE_TEST_H +#define _COMPLIANCE_TEST_H + +#include "riscv_test.h" + +//----------------------------------------------------------------------- +// RV Compliance Macros +//----------------------------------------------------------------------- +#define RV_COMPLIANCE_HALT \ + j end_rvc_test; \ + +#define RV_COMPLIANCE_RV32M \ + RVTEST_RV32M \ + + +#define RV_COMPLIANCE_CODE_BEGIN \ + RVTEST_CODE_BEGIN \ + +#define RV_COMPLIANCE_CODE_END \ + RVTEST_CODE_END \ + +#define RV_COMPLIANCE_DATA_BEGIN \ + .section .data; \ + RVTEST_DATA_BEGIN \ + +#define RV_COMPLIANCE_DATA_END \ + RVTEST_DATA_END \ + +#endif // _COMPLIANCE_TEST_H +' > $@ + """, + visibility = ["//visibility:private"], +) + +genrule( + name = "compliance_io_hdr", + outs = ["compliance_io.h"], + cmd = """echo '\ +// RISC-V Compliance IO Test Header File + +#ifndef _COMPLIANCE_IO_H +#define _COMPLIANCE_IO_H + +//----------------------------------------------------------------------- +// RV IO Macros (Non functional) +//----------------------------------------------------------------------- + +#define RVTEST_IO_INIT +#define RVTEST_IO_WRITE_STR(_SP, _STR) +#define RVTEST_IO_CHECK() +#define RVTEST_IO_ASSERT_GPR_EQ(_SP, _R, _I) +#define RVTEST_IO_ASSERT_SFPR_EQ(_F, _R, _I) +#define RVTEST_IO_ASSERT_DFPR_EQ(_D, _R, _I) + +#endif // _COMPLIANCE_IO_H +' > $@ + """, + visibility = ["//visibility:private"], +) + +cc_library( + name = "riscv-test-env", + hdrs = [ + "compliance_io.h", + "compliance_test.h", + "riscv-test-env/aw_test_macros.h", + "riscv-test-env/encoding.h", + "riscv-test-env/p/riscv_test.h", + "riscv-test-env/riscv_test_macros.h", + "riscv-test-env/test_macros.h", + ], + defines = [ + "PRIV_MISA_S=0", + "PRIV_MISA_U=0", + "RVTEST_ENTRY=_rvc_start", + "TRAPALIGN=8", + ], + includes = [ + "riscv-test-env", + "riscv-test-env/p", + ], +)
diff --git a/third_party/riscv-compliance/compliance_main.S b/third_party/riscv-compliance/compliance_main.S new file mode 100644 index 0000000..a39bf08 --- /dev/null +++ b/third_party/riscv-compliance/compliance_main.S
@@ -0,0 +1,94 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + + .section .bss +arch_state_store: + // Allocate space in .bss for saving architectural state before jumping + // into the test + .balign 4 + .zero 4 * 17 // ra, sp, gp, tp, s0-s11, mtvec + .size arch_state_store, .-arch_state_store + + .section .text + +run_rvc_test: + .globl run_rvc_test + + // Save the architectural state. There is no need to save caller preserved + // registers as C calling run_rvc_test will expect them to be clobbered anyway + // and act appropriately. RA is the exception as we need to know where to jump + // back to after the test is complete. mtvec is saved as the compliance test + // environment alters it, other CSRs may also be changed but no adverse + // effects have yet been observed from this. + la t0, arch_state_store + + sw ra, 0(t0) + sw sp, 4(t0) + sw gp, 8(t0) + sw tp, 12(t0) + sw s0, 16(t0) + sw s1, 20(t0) + sw s2, 24(t0) + sw s3, 28(t0) + sw s4, 32(t0) + sw s5, 36(t0) + sw s6, 40(t0) + sw s7, 44(t0) + sw s8, 48(t0) + sw s9, 52(t0) + sw s10, 56(t0) + sw s11, 60(t0) + + csrr t1, mtvec + sw t1, 64(t0) + + // Tail-call to compliance test. + // + // The test will jump to `end_rvc_test` at the end rather than + // return, so we don't want to do a `call`. + tail _rvc_start + +end_rvc_test: + .globl end_rvc_test + + // Restore architectural state. + la t0, arch_state_store + + lw ra, 0(t0) + lw sp, 4(t0) + lw gp, 8(t0) + lw tp, 12(t0) + lw s0, 16(t0) + lw s1, 20(t0) + lw s2, 24(t0) + lw s3, 28(t0) + lw s4, 32(t0) + lw s5, 36(t0) + lw s6, 40(t0) + lw s7, 44(t0) + lw s8, 48(t0) + lw s9, 52(t0) + lw s10, 56(t0) + lw s11, 60(t0) + + lw t1, 64(t0) + csrw mtvec, t1 + + ret + +// riscv-compliance loads its own mtvec that will jump to mtvec_handler if the +// symbol exists. This will only be jumped to in situations where we are not +// expected to recover. +mtvec_handler: + .globl mtvec_handler + + // Restore gp/sp so handler from the OTTF will work correctly. + la t0, arch_state_store + + lw sp, 4(t0) + lw gp, 8(t0) + + // Virtual-tail-call into the OTTF's handler. + lw t1, 64(t0) + jr t1
diff --git a/third_party/riscv-compliance/compliance_main.c b/third_party/riscv-compliance/compliance_main.c new file mode 100644 index 0000000..07aebbe --- /dev/null +++ b/third_party/riscv-compliance/compliance_main.c
@@ -0,0 +1,30 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include <stddef.h> +#include <stdint.h> + +#include "sw/device/lib/testing/check.h" +#include "sw/device/lib/testing/test_framework/ottf.h" + +// These symbols are provided by the riscv-compliance libraries. +extern uint32_t begin_signature[]; +extern uint32_t end_signature[]; + +// This symbol is provided by the genrule that converts the reference +// output file. +extern const uint32_t kExpectedSignature[]; + +// This symbol is defined in compliance_main.S +extern void run_rvc_test(void); + +const test_config_t kTestConfig; +bool test_main(void) { + run_rvc_test(); + + ptrdiff_t words = end_signature - begin_signature; + CHECK_BUFFER(begin_signature, kExpectedSignature, (size_t)words); + + return true; +}
diff --git a/third_party/riscv-compliance/defs.bzl b/third_party/riscv-compliance/defs.bzl new file mode 100644 index 0000000..4bd387c --- /dev/null +++ b/third_party/riscv-compliance/defs.bzl
@@ -0,0 +1,147 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +"""Helper macros for generating RISC-V compliance test targets.""" + +load("//rules:opentitan.bzl", "opentitan_functest", "verilator_params") + +def rv_compliance_test(name, arch): + test_file = "@riscv-compliance//:riscv-test-suite/{}/src/{}.S".format(arch, name) + reference_output = "@riscv-compliance//:riscv-test-suite/{}/references/{}.reference_output".format(arch, name) + expected_signature = "{}.expected_signature.S".format(name) + + native.genrule( + name = "{}_expected_signature".format(name), + srcs = [reference_output], + outs = [expected_signature], + cmd = """ + echo "kExpectedSignature:" >> $@ + echo ".global kExpectedSignature" >> $@ + perl -pe 's/([a-fA-F0-9]+)/.word 0x$$1/' \ + $(location {}) \ + >> $@ + """.format(reference_output), + ) + + opentitan_functest( + name = name, + srcs = [ + test_file, + expected_signature, + "compliance_main.c", + "compliance_main.S", + ], + verilator = verilator_params( + timeout = "long", + ), + linkopts = ["-Wl,--no-relax"], + deps = [ + "@riscv-compliance//:riscv-test-env", + ], + ) + +TESTS = { + "rv32i": [ + "I-ADD-01", + "I-ADDI-01", + "I-AND-01", + "I-ANDI-01", + "I-AUIPC-01", + "I-BEQ-01", + "I-BGE-01", + "I-BGEU-01", + "I-BLT-01", + "I-BLTU-01", + "I-BNE-01", + "I-DELAY_SLOTS-01", + + # TODO(lowrisc/opentitan#11876): Failing for unnknown reasons. + #"I-EBREAK-01", + "I-ECALL-01", + "I-ENDIANESS-01", + "I-IO-01", + "I-JAL-01", + "I-JALR-01", + "I-LB-01", + "I-LBU-01", + "I-LH-01", + "I-LHU-01", + "I-LUI-01", + "I-LW-01", + + # TODO(lowrisc/ibex#100): These tests are broken due to flaws in + # riscv-compliance rather than Ibex/OpenTitan. + #"I-MISALIGN_JMP-01", + #"I-MISALIGN_LDST-01", + + # TODO(lowrisc/opentitan#11876): Failing for unnknown reasons. + #"I-NOP-01", + "I-OR-01", + "I-ORI-01", + "I-RF_size-01", + "I-RF_width-01", + "I-RF_x0-01", + "I-SB-01", + "I-SH-01", + "I-SLL-01", + "I-SLLI-01", + "I-SLT-01", + "I-SLTI-01", + "I-SLTIU-01", + "I-SLTU-01", + "I-SRA-01", + "I-SRAI-01", + "I-SRL-01", + "I-SRLI-01", + "I-SUB-01", + "I-SW-01", + "I-XOR-01", + "I-XORI-01", + ], + "rv32im": [ + "DIV", + "DIVU", + "MUL", + "MULH", + "MULHSU", + "MULHU", + "REM", + "REMU", + ], + "rv32imc": [ + "C-ADD", + "C-ADDI", + "C-ADDI16SP", + "C-ADDI4SPN", + "C-AND", + "C-ANDI", + "C-BEQZ", + "C-BNEZ", + "C-J", + "C-JAL", + "C-JALR", + "C-JR", + "C-LI", + "C-LUI", + "C-LW", + "C-LWSP", + "C-MV", + "C-OR", + "C-SLLI", + "C-SRAI", + "C-SRLI", + "C-SUB", + "C-SW", + "C-SWSP", + "C-XOR", + ], + "rv32Zicsr": [ + "I-CSRRC-01", + "I-CSRRCI-01", + "I-CSRRS-01", + "I-CSRRSI-01", + "I-CSRRW-01", + "I-CSRRWI-01", + ], +}
diff --git a/third_party/riscv-compliance/deps.bzl b/third_party/riscv-compliance/deps.bzl new file mode 100644 index 0000000..ad9ee09 --- /dev/null +++ b/third_party/riscv-compliance/deps.bzl
@@ -0,0 +1,30 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +load("@bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository") + +def riscv_compliance_deps(): + #new_git_repository( + # name = "riscv-compliance", + # build_file = Label("//third_party/riscv-compliance:BUILD.riscv-compliance.bazel"), + # remote = "https://github.com/riscv/riscv-compliance.git", + # commit = "5a978cfd444d5e640150d46703deda99057b2bbb", + # shallow_since = "1628817357 -0700", + # patches = [ + # Label("//third_party/riscv-compliance:0001-Add-configurable-trap-alignment-and-entry-point-to-p.patch") + # ], + # patch_args = ["-p1"], + #) + + # TODO(lowRISC/opentitan#11877) + # For the time being, use a local repo, but it should really be replaced with + # the git repo defined above. + # + # Everything else in this directory is set up so that we can uncomment the above + # without any other changes. + native.new_local_repository( + name = "riscv-compliance", + path = "sw/vendor/riscv_compliance", + build_file = "//third_party/riscv-compliance:BUILD.riscv-compliance.bazel", + )