From d0e998703a560df20c99dfe5c599410fda9e771b Mon Sep 17 00:00:00 2001 From: Greg Chadwick Date: Fri, 30 Aug 2024 13:33:53 +0100 Subject: [PATCH] Update lowrisc_ibex to lowrisc/cheriot-ibex@091ccfc3 Update code from upstream repository https://github.com/lowrisc/cheriot-ibex.git to revision 091ccfc3ce5c9c8dad4acfe200ee45b9401e6a9c * [rtl] Remove stray comma (Greg Chadwick) * [rtl] Enable use of ICache with ibexc_top (Greg Chadwick) * [util] Update check_tool_requirements.py (Gary Guo) * Update lowrisc_ip to lowRISC/opentitan@f235838a9e (Marno van der Maas) * Added patch to remove alert prim from all group (Marno van der Maas) * [vendor] Patch updated based on OpenTitan/36a2d3c (Marno van der Maas) * [dv] Alter cov_merge.tcl patch so icache coverage collection works (Greg Chadwick) * Add patch for lowrisc_ip (Harry Callahan) * [vendor] Update patch file based on upstream OpenTitan (Marno van der Maas) * Feed CHERI errors out to top module (Marno van der Maas) * Remove prim alert from build (Marno van der Maas) * Fix tracing (Marno van der Maas) * Update two port RAM for Sonata (Marno van der Maas) * Patch reading memory files taken from upstream (Marno van der Maas) * Various Verilator lint patches (Marno van der Maas) * Use ibexc_top since that is used in SAFE (Marno van der Maas) * Add FPGA primitives (Marno van der Maas) * fixed cheri_csr_always_ok (missing h counters) in ibex_decoder (Kunyan Liu) * updated functional coverage, minor RTL cleanup (rf_we) (Kunyan Liu) * updated dv/cheriot/tests for the new forward/backward sentry types (Kunyan Liu) * added support for the new forward/backward sentry types (Kunyan Liu) * more exception-related assertion fixes in ibex_controller (Kunyan Liu) * fixed IbexDontSkipExceptionReq assertion in controller (Kunyan Liu) * added illegal_regs_cheri to decoder (generate exceptions for regaddr > 15) (Kunyan Liu) * added handling for pc wraparound case in if_stage (issue lowrisc/cheriot-ibex#34) (Kunyan Liu) * added coremark test (Kunyan Liu) * checking in sanity tests (Kunyan Liu) * Update README.md (Kunyan Liu) * fixed illegal instruction warning in controller (Kunyan Liu) * added CSR cheri safe-list (no ASR) access feature (Kunyan Liu) * removed speculative fetching for cjal/cjalr, rvfi and assertion fixes (Kunyan Liu) * fixed mprv (see cheriot-ibex issue lowrisc/cheriot-ibex#35) and data-dependent behavior in fetch_fifo (potential side-channel leakage (Kunyan Liu) * fixed FV issues (pcc2mepcc, csr/mret ASR permission fault, etc) (Kunyan Liu) * updated core_ibex_fcov (added csethigh) (Kunyan Liu) * Ignore build directory (Marno van der Maas) * Fix reference to rst_ni in tb code (Marno van der Maas) * Fix assignments in memory model (Marno van der Maas) * Add missing files for Verlator build (Marno van der Maas) * Add flags for Verilator version 5 (Marno van der Maas) * fixed mtcc/mepcc legalization to match sail (Kunyan Liu) * fixed more exception handling priority issues (Kunyan Liu) * checked in more dv/cheriot files (Kunyan Liu) * added csethigh insn and updated test case (Kunyan Liu) Signed-off-by: Greg Chadwick --- vendor/lowrisc_ibex.lock.hjson | 4 +- vendor/lowrisc_ibex/README.md | 6 +- vendor/lowrisc_ibex/dv/cheriot/run/.gitignore | 1 + vendor/lowrisc_ibex/dv/cheriot/run/all.f | 11 +- .../lowrisc_ibex/dv/cheriot/run/ibexc.vcs.f | 3 + vendor/lowrisc_ibex/dv/cheriot/run/vcscomp2 | 3 +- .../dv/cheriot/scripts/build_coremark.sh | 46 + .../dv/cheriot/scripts/compare_trace.py | 155 ++- .../lowrisc_ibex/dv/cheriot/tb/cap_err_gen.sv | 75 +- .../dv/cheriot/tb/cheriot_dv_pkg.sv | 118 ++ .../dv/cheriot/tb/cheriot_main.cc | 6 +- .../dv/cheriot/tb/core_ibex_fcov_if.sv | 905 ++++++++++++-- .../dv/cheriot/tb/data_mem_model.sv | 16 +- .../lowrisc_ibex/dv/cheriot/tb/mem_monitor.sv | 69 +- .../lowrisc_ibex/dv/cheriot/tb/mem_obi_if.sv | 2 +- .../dv/cheriot/tb/module_dv_ext.sv | 109 +- .../dv/cheriot/tb/tb_cheriot_top.sv | 7 +- .../lowrisc_ibex/dv/cheriot/tb/tbre_bg_gen.sv | 8 +- .../dv/cheriot/tests/coremark/Makefile | 139 +++ .../dv/cheriot/tests/coremark/README | 26 + .../tests/coremark/barebones/core_portme.c | 128 ++ .../tests/coremark/barebones/core_portme.h | 199 ++++ .../tests/coremark/barebones/core_portme.mak | 87 ++ .../dv/cheriot/tests/coremark/barebones/cvt.c | 117 ++ .../tests/coremark/barebones/ee_printf.c | 597 ++++++++++ .../tests/coremark/cheri/cheri_atest.S | 131 ++ .../tests/coremark/cheri/core_portme.c | 129 ++ .../tests/coremark/cheri/core_portme.h | 216 ++++ .../tests/coremark/cheri/core_portme.mak | 87 ++ .../dv/cheriot/tests/coremark/cheri/cvt.c | 117 ++ .../cheriot/tests/coremark/cheri/ee_printf.c | 601 ++++++++++ .../cheriot/tests/coremark/core_list_join.c | 495 ++++++++ .../dv/cheriot/tests/coremark/core_main.c | 371 ++++++ .../dv/cheriot/tests/coremark/core_matrix.c | 308 +++++ .../dv/cheriot/tests/coremark/core_state.c | 277 +++++ .../dv/cheriot/tests/coremark/core_util.c | 210 ++++ .../dv/cheriot/tests/coremark/coremark.h | 174 +++ .../dv/cheriot/tests/coremark/coremark.md5 | 6 + .../tests/coremark/riscv32/core_portme.c | 129 ++ .../tests/coremark/riscv32/core_portme.h | 215 ++++ .../tests/coremark/riscv32/core_portme.mak | 87 ++ .../dv/cheriot/tests/coremark/riscv32/cvt.c | 117 ++ .../tests/coremark/riscv32/ee_printf.c | 599 ++++++++++ .../tests/coremark/simple/core_portme.c | 128 ++ .../tests/coremark/simple/core_portme.h | 196 +++ .../tests/coremark/simple/core_portme.mak | 60 + .../dv/cheriot/tests/csrc_cheri/cstart.c | 14 +- .../dv/cheriot/tests/csrc_cheri/startup.S | 31 +- .../dv/cheriot/tests/csrc_cheri/util.c | 11 +- .../dv/cheriot/tests/csrc_cheri/util.h | 5 + .../cheriot/tests/hello_world/cheri_atest.S | 131 ++ .../cheriot/tests/hello_world/hello_world.c | 16 - .../dv/cheriot/tests/hello_world/test_main.c | 34 + .../dv/cheriot/tests/isa_test1/cheri_atest.S | 1049 +++++++++++++++++ .../dv/cheriot/tests/isa_test1/test_main.c | 34 + .../dv/cheriot/tests/isa_test1a/cheri_atest.S | 686 +++++++++++ .../dv/cheriot/tests/isa_test1a/test_main.c | 34 + .../dv/cheriot/tests/isa_test2/cheri_atest.S | 132 +++ .../dv/cheriot/tests/isa_test2/test_main.c | 71 ++ .../dv/cheriot/tests/link_coremark.ld | 33 + .../dv/cheriot/tests/link_test.ld | 2 +- vendor/lowrisc_ibex/ibex_top.core | 5 +- vendor/lowrisc_ibex/rtl/cheri_decoder.sv | 17 +- vendor/lowrisc_ibex/rtl/cheri_ex.sv | 82 +- vendor/lowrisc_ibex/rtl/cheri_pkg.sv | 27 +- vendor/lowrisc_ibex/rtl/ibex_controller.sv | 76 +- vendor/lowrisc_ibex/rtl/ibex_core.sv | 9 +- vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv | 23 +- vendor/lowrisc_ibex/rtl/ibex_decoder.sv | 52 +- vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv | 14 +- vendor/lowrisc_ibex/rtl/ibex_id_stage.sv | 18 +- vendor/lowrisc_ibex/rtl/ibex_if_stage.sv | 38 +- .../lowrisc_ibex/rtl/ibex_prefetch_buffer.sv | 3 + vendor/lowrisc_ibex/rtl/ibex_tracer.sv | 1 + vendor/lowrisc_ibex/rtl/ibex_tracer_pkg.sv | 1 + vendor/lowrisc_ibex/rtl/ibexc_top.sv | 84 +- vendor/lowrisc_ibex/rtl/ibexc_top_tracing.sv | 6 +- .../ip/prim/rtl/prim_util_memload.svh | 2 - 78 files changed, 9850 insertions(+), 381 deletions(-) create mode 100644 vendor/lowrisc_ibex/dv/cheriot/run/.gitignore create mode 100755 vendor/lowrisc_ibex/dv/cheriot/scripts/build_coremark.sh create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/Makefile create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/README create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/core_portme.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/core_portme.h create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/core_portme.mak create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/cvt.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/ee_printf.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/cheri_atest.S create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/core_portme.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/core_portme.h create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/core_portme.mak create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/cvt.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/ee_printf.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/core_list_join.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/core_main.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/core_matrix.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/core_state.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/core_util.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/coremark.h create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/coremark.md5 create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/core_portme.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/core_portme.h create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/core_portme.mak create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/cvt.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/ee_printf.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/simple/core_portme.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/simple/core_portme.h create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/coremark/simple/core_portme.mak create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/hello_world/cheri_atest.S delete mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/hello_world/hello_world.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/hello_world/test_main.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/isa_test1/cheri_atest.S create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/isa_test1/test_main.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/isa_test1a/cheri_atest.S create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/isa_test1a/test_main.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/isa_test2/cheri_atest.S create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/isa_test2/test_main.c create mode 100755 vendor/lowrisc_ibex/dv/cheriot/tests/link_coremark.ld diff --git a/vendor/lowrisc_ibex.lock.hjson b/vendor/lowrisc_ibex.lock.hjson index 4e7960654..c21511619 100644 --- a/vendor/lowrisc_ibex.lock.hjson +++ b/vendor/lowrisc_ibex.lock.hjson @@ -1,4 +1,4 @@ -// Copyright lowRISC contributors. +// Copyright lowRISC contributors (OpenTitan project). // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 @@ -9,6 +9,6 @@ upstream: { url: https://github.com/lowrisc/cheriot-ibex.git - rev: 3081de9f03af988bf2c5200b9787d81c6a2d8bc7 + rev: 091ccfc3ce5c9c8dad4acfe200ee45b9401e6a9c } } diff --git a/vendor/lowrisc_ibex/README.md b/vendor/lowrisc_ibex/README.md index a85f0faf2..1797dcded 100644 --- a/vendor/lowrisc_ibex/README.md +++ b/vendor/lowrisc_ibex/README.md @@ -21,7 +21,7 @@ Use of Microsoft trademarks or logos in modified versions of this project must n Any use of third-party trademarks or logos are subject to those third-party's policies. ## Introduction -cheriot-ibex is 32-bit RISC-V microcontroller which implements the CHERIoT ISA extension in addition to RV32IMCB. Same as the original ibex core, the design can be configured either with a 2-stage or a 3-stage pipeline. It has passed preliminary simulation and FPGA validation, and is currently undergoing further verification as well as PPA analysis at Microsoft. +cheriot-ibex is 32-bit RISC-V microcontroller which implements the CHERIoT ISA extension in addition to RV32IMCB. Same as the original ibex core, the design can be configured either with a 2-stage or a 3-stage pipeline. It has passed preliminary simulation, formal verification and FPGA validation, and is currently under further verification at Microsoft. ![image](https://github.com/microsoft/cheriot-ibex/assets/116126768/51b768f5-a528-4d93-bce4-392ac2fe1488) @@ -29,7 +29,7 @@ cheriot-ibex is 32-bit RISC-V microcontroller which implements the CHERIoT ISA e cheriot-ibex supports all instructions listed in the [CHERIoT ISA specification](https://github.com/microsoft/cheriot-sail/tree/main/archdoc), including -- To query or test capabilities: cgetaddr, cgetbase, cgetlen, cgetperm, cgettag, cgettop, cgettype, ctestsubset, csetequalexact, csub +- To query or test capabilities: cgetaddr, cgetbase, cgethigh, cgetlen, cgetperm, cgettag, cgettop, cgettype, ctestsubset, csetequalexact, csub, csethigh - To modify or derive capabilities: auicgp, auipcc, candperm, ccleartag, cincaddr, cincaddrimm, cmove, cram, crrl, csetaddr, csetbounds, csetboundsexact, csetboundsimm, cseal, cunseal - To load/store capabilities from memory: clc, csc - To control the program flow: cjal, cjalr @@ -120,7 +120,7 @@ A PPA study conducted at Microsoft shows that cheriot-ibex is similar to the ori cheriot-ibex (configured as 3-stage pipeline) has been synthesized successfully using Synopsys DC-topo at 250MHz using TSMC 28nm (28LP) libraries (ss 1.03v) and 550MHz using TSMC 5nm (N5) libraries (ss 0.6v). Timing is mostly limited by TCM read access time (which approaches 1.6ns in the N5 case). -The design area is ~60k gate equivalents (~25% more the original ibex design). Both dynamic and leakage power are shown as similar to the original ibex design. +The design area is ~60k gate equivalents. Both dynamic and leakage power are shown as similar to the original ibex design. ## Build the design for simulation and emulation diff --git a/vendor/lowrisc_ibex/dv/cheriot/run/.gitignore b/vendor/lowrisc_ibex/dv/cheriot/run/.gitignore new file mode 100644 index 000000000..697cf4f49 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/run/.gitignore @@ -0,0 +1 @@ +obj_dir/ diff --git a/vendor/lowrisc_ibex/dv/cheriot/run/all.f b/vendor/lowrisc_ibex/dv/cheriot/run/all.f index d26e863c0..2278cf0ae 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/run/all.f +++ b/vendor/lowrisc_ibex/dv/cheriot/run/all.f @@ -1,5 +1,4 @@ --Wno-WIDTHEXPAND --Wno-WIDTHTRUNC +-Wno-WIDTH -Wno-USERFATAL -Wno-UNOPTFLAT -Wno-IMPLICIT @@ -8,6 +7,7 @@ -Wno-UNSIGNED -Wno-INITIALDLY -Wno-CASEX +--timing +incdir+$rtlRoot +incdir+$primRoot +incdir+$dvutilsRoot @@ -18,6 +18,7 @@ $rtlRoot/cheri_pkg.sv $rtlRoot/ibex_pkg.sv $rtlRoot/ibex_tracer_pkg.sv +$verifRoot/tb/cheriot_dv_pkg.sv $rtlRoot/cheri_decoder.sv $rtlRoot/cheri_ex.sv $rtlRoot/cheri_regfile.sv @@ -48,5 +49,9 @@ $rtlRoot/ibexc_top.sv $rtlRoot/ibex_tracer.sv $rtlRoot/ibexc_top_tracing.sv -$verifRoot/tb/mem_model.sv +$verifRoot/tb/data_mem_model.sv +$verifRoot/tb/dii_if.sv +$verifRoot/tb/instr_mem_model.sv +$verifRoot/tb/mem_monitor.sv +$verifRoot/tb/mem_obi_if.sv $verifRoot/tb/tb_cheriot_top.sv diff --git a/vendor/lowrisc_ibex/dv/cheriot/run/ibexc.vcs.f b/vendor/lowrisc_ibex/dv/cheriot/run/ibexc.vcs.f index de366d3d3..b7f3afb0f 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/run/ibexc.vcs.f +++ b/vendor/lowrisc_ibex/dv/cheriot/run/ibexc.vcs.f @@ -39,12 +39,15 @@ $rtlRoot/ibexc_top.sv $rtlRoot/ibex_tracer.sv $rtlRoot/ibexc_top_tracing.sv +$verifRoot/tb/cheriot_dv_pkg.sv $verifRoot/tb/mem_obi_if.sv $verifRoot/tb/instr_mem_model.sv $verifRoot/tb/data_mem_model.sv +$verifRoot/tb/mem_monitor.sv $verifRoot/tb/dii_if.sv $verifRoot/tb/intr_gen.sv $verifRoot/tb/cap_err_gen.sv +$verifRoot/tb/tbre_bg_gen.sv $verifRoot/tb/tb_cheriot_top.sv $verifRoot/tb/module_dv_ext.sv $verifRoot/tb/core_ibex_fcov_if.sv diff --git a/vendor/lowrisc_ibex/dv/cheriot/run/vcscomp2 b/vendor/lowrisc_ibex/dv/cheriot/run/vcscomp2 index 2b40e66b1..e5489fc3c 100755 --- a/vendor/lowrisc_ibex/dv/cheriot/run/vcscomp2 +++ b/vendor/lowrisc_ibex/dv/cheriot/run/vcscomp2 @@ -3,5 +3,4 @@ export primRoot=../../../vendor/lowrisc_ip/ip/prim/rtl export dvutilsRoot=../../../vendor/lowrisc_ip/dv/sv/dv_utils export verifRoot=.. -#vnc run -Ir -wl -r vcs RAM/64000 x86_64 redhat7 -- vcs -full64 -sverilog +systemverilogext+sv -timescale=1ns/1ps -debug_acc+all -f ibexc.vcs.f -vcs -full64 -sverilog +systemverilogext+sv -timescale=1ns/1ps -debug_acc+all -f ibexc.vcs.f +vcs -full64 -sverilog -xlrm uniq_prior_final +systemverilogext+sv -timescale=1ns/1ps -debug_acc+all -f ibexc.vcs.f $* diff --git a/vendor/lowrisc_ibex/dv/cheriot/scripts/build_coremark.sh b/vendor/lowrisc_ibex/dv/cheriot/scripts/build_coremark.sh new file mode 100755 index 000000000..9ff40461b --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/scripts/build_coremark.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +set -e + +source ../scripts/common_setup.sh +mkdir -p work +cd work + +pwd + +export TESTNAME=coremark +export CSRC=../csrc_cheri +export SRC=../coremark +export S_FILES="$CSRC/startup.S" +export OBJ_FILES="startup.o" +export C_COMMON="$CSRC/cstart.c $CSRC/util.c" +export C_FILES="$C_COMMON $SRC/core_main.c $SRC/core_list_join.c $SRC/core_matrix.c $SRC/core_util.c $SRC/core_state.c $SRC/cheri/core_portme.c $SRC/cheri/ee_printf.c $SRC/cheri/cheri_atest.S" +export LD_FILE="../link_coremark.ld" +export ELF_OUTPUT=$TESTNAME.elf +export BIN_OUTPUT=$TESTNAME.bin +export HEX_OUTPUT=$TESTNAME.vhx + +# run the compile +BASE_FLAGS="-target riscv32-unknown-unknown -mcpu=cheriot -mabi=cheriot -mxcheri-rvc -Oz -g -nostdlib" +ADDON_CFLAGS="-DNDEBUG -DCOREMARK -I$SRC -I$CSRC -I$SRC/cheri" + +#RUN_CFLAGS="-DVALIDATION_RUN=1 -DITERATIONS=1 -DCLOCKS_PER_SEC=10000000" +RUN_CFLAGS="-DPERFORMACE_RUN=1 -DITERATIONS=1 -DCLOCKS_PER_SEC=10000000" +CLANG_FLAGS="$BASE_FLAGS $ADDON_CFLAGS $RUN_CFLAGS" + +echo "compile and linking.." +echo $CLANG_FLAGS +$CLANG $BASE_FLAGS -c $S_FILES +$CLANG $CLANG_FLAGS -DFLAGS_STR="\"$CLANG_FLAGS\"" -T$LD_FILE -o $ELF_OUTPUT $C_FILES $OBJ_FILES + +$GCC_OBJCOPY -O binary -S $ELF_OUTPUT $BIN_OUTPUT + +$BIN2HEX $BIN_OUTPUT > $HEX_OUTPUT + +echo "Generating disassembled text.." +$LLVM_HOME/llvm-objdump -xdCS --mcpu=cheriot $ELF_OUTPUT > $TESTNAME.dis + +echo "Copying binaries to run area.." +cp $HEX_OUTPUT ../../run/bin +cp $ELF_OUTPUT ../../run/bin + diff --git a/vendor/lowrisc_ibex/dv/cheriot/scripts/compare_trace.py b/vendor/lowrisc_ibex/dv/cheriot/scripts/compare_trace.py index f8b2dfc4e..454ac883f 100755 --- a/vendor/lowrisc_ibex/dv/cheriot/scripts/compare_trace.py +++ b/vendor/lowrisc_ibex/dv/cheriot/scripts/compare_trace.py @@ -1,5 +1,9 @@ #!/usr/bin/env python3 +# Copyright Microsoft Corporation +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + import sys import re import argparse @@ -43,7 +47,7 @@ def expand_perms(cperms_in): perms |= (cperms & 0x1) << PERM_LG perms |= ((cperms & 0x2)>>1) << PERM_LM perms |= PERM_LC_IMSK - elif cperms == 0x8 : + elif cperms == 0x10 : perms |= PERM_SC_IMSK elif (cperms>>2) == 0x4 : perms |= (cperms & 0x1) << PERM_SD @@ -125,8 +129,12 @@ def parse_ibex_cap(cap_val, addr_val): else : base_cor = 0; - top = (top9 << exp) + (((addr_val >> (exp+9)) + top_cor) << (exp+9)); - base = (base9 << exp) + (((addr_val >> (exp+9)) + base_cor) << (exp+9)); + if (exp == 24): + top = (top9 << exp); + base = (base9 << exp); + else: + top = (top9 << exp) + (((addr_val >> (exp+9)) + top_cor) << (exp+9)); + base = (base9 << exp) + (((addr_val >> (exp+9)) + base_cor) << (exp+9)); perm = expand_perms(cperms) @@ -141,8 +149,12 @@ def __init__(self): self.cycle = 0 self.pc = 0 self.instr = 0 # encoded instruction - self.excp = 0 + self.is_clc = 0 + self.trap = 0 + self.trap_nxt = 0 + self.trap_pc = 0 self.intr = 0 + self.reg_wr = 0 self.reg_waddr = 0 self.reg_wdata = 0 @@ -160,27 +172,42 @@ def __init__(self): self.reg_rd2 = 0 self.reg_raddr2 = 0 self.reg_rdata2 = 0 - self.reg_rcap2 = (0, 0, 0, 0, 0, 0) + self.reg_rcap2 = (0, 0, 0, 0, 0, 0) + self.uart_wr = 0 def almost_eq (self, other): if isinstance(other, trace_obj): # Check if the other object is of the same type t1 = ((self.valid == 1) and (other.valid == 1) and (self.pc == other.pc) and - (self.instr == other.instr) and (self.excp == other.excp)) + (self.trap == other.trap)) # register write check, excluding the wcap tag value (for delayed clc revocation) - t2 = ((self.reg_wr == other.reg_wr) and + t2 = ((self.instr == other.instr) and (self.reg_wr == other.reg_wr) and ((self.reg_wr == 0) or ((self.reg_wr == 1) and (self.reg_waddr == other.reg_waddr) and (self.reg_wdata == other.reg_wdata) and (self.reg_wcap[1:5] == other.reg_wcap[1:5])))) - t3 = ((self.mem_wr == other.mem_wr) and (self.mem_rd == other.mem_rd) and - (((self.mem_wr == 0) and (self.mem_rd == 0)) or - ((self.mem_addr == other.mem_addr) and (self.mem_size == other.mem_size) and - (self.mem_data == other.mem_data)))) - - result = t1 and ((self.excp == 1) or ((self.excp == 0) and t2 and t3)) - #print(t1, t2, t3) + # no memory access + t3 = ((self.mem_wr == other.mem_wr) and (self.mem_rd == other.mem_rd) and + (self.mem_rd == 0) and (self.mem_rd == 0)) + + # memory write good + t4 = ((self.mem_wr == other.mem_wr) and (self.mem_wr == 1) and + (self.mem_addr == other.mem_addr) and (self.mem_size == other.mem_size) and + (self.mem_data == other.mem_data)) + + # memory read good. + # don't need to compare mem data since it goes to registers anyway. also the clcperms + # makes it hard to compare mem rdata + t5 = ((self.mem_rd == other.mem_rd) and (self.mem_rd == 1) and + (self.mem_addr == other.mem_addr) and (self.mem_size == other.mem_size)) + # and (self.mem_data == other.mem_data)) + + # uart write good + t6 = (self.uart_wr == 1) and (other.uart_wr == 1) # ignore UART writes + + result = t1 and ((self.trap == 1) or ((self.trap == 0) and t2 and (t3 or t4 or t5 or t6))) + #print(t1, t2, t3, t4) return result else: return False @@ -196,7 +223,7 @@ def __eq__(self, other): # return result def __str__(self): # for printing - pstr = f"trace_obj: {self.valid}, {self.excp}, {self.cycle}, 0x{self.pc:08x}, 0x{self.instr:08x}, " + pstr = f"trace_obj: {self.valid}, {self.trap}, {self.cycle}, 0x{self.pc:08x}, 0x{self.instr:08x}, " pstr += f"[{self.reg_wr}, {self.reg_waddr}, 0x{self.reg_wdata:X}, " pstr += f"({self.reg_wcap[0]}, 0x{self.reg_wcap[1]:x}, 0x{self.reg_wcap[2]:x}, " pstr += f"0x{self.reg_wcap[3]:x}, 0x{self.reg_wcap[4]:x}, 0x{self.reg_wcap[5]:x})], " @@ -225,7 +252,7 @@ def load(self): if hasattr(self, 'file') and not self.file.closed: self.file.close() - print(f"File '{self.filename}' content loaded successfully.") + print(f"File '{self.filename}' loaded successfully, {len(self.lines)} lines.") # @@ -238,18 +265,19 @@ def find_nxt(self): while True: if (self.line_ptr >= len(self.lines)): - break + return nxt_obj matches1 = re.findall(pattern1, self.lines[self.line_ptr]) if len(matches1) == 0: self.line_ptr += 1 else: break + if len(matches1) != 0: nxt_obj.valid = 1 nxt_obj.cycle = int(matches1[0][1]) nxt_obj.pc = int(matches1[0][2], 16) nxt_obj.instr = int(matches1[0][3], 16) - nxt_obj.excp = 1 if re.search(r'-->', matches1[0][4]) else 0 + nxt_obj.trap = 1 if re.search(r'-->', matches1[0][4]) else 0 nxt_obj.intr = 1 if re.search(r'==>', matches1[0][4]) else 0 mnemonic = matches1[0][4] @@ -309,9 +337,12 @@ def find_nxt(self): elif (nxt_obj.mem_size == 2) and nxt_obj.mem_rd : nxt_obj.mem_data &= 0xffff; + if (nxt_obj.mem_wr == 1) and (nxt_obj.mem_addr >= 0x10000000) and (nxt_obj.mem_addr < 0x10000100): + nxt_obj.uart_wr = 1 + # cap reg rd (cs1 and cs2) pattern6 = r'x(\d+):0x([0-9A-Fa-f]+)\+0x([0-9A-Fa-f]+)' - matches6 = re.findall(pattern2, self.lines[self.line_ptr]) + matches6 = re.findall(pattern6, self.lines[self.line_ptr]) nxt_obj.reg_rd1 = 0 nxt_obj.reg_rd2 = 0 @@ -342,7 +373,7 @@ def find_nxt(self): while True: if (self.line_ptr >= len(self.lines)): - break + return nxt_obj # ending search matches1 = re.findall(pattern1, self.lines[self.line_ptr]) if len(matches1) == 0: self.line_ptr += 1 @@ -360,22 +391,26 @@ def find_nxt(self): self.line_ptr += 1 while True: - if (self.line_ptr >= len(self.lines)): + if (self.line_ptr >= len(self.lines)): # end of file break - if re.search(r'^\s*$', self.lines[self.line_ptr]) : # empty lines + if re.search(r'^\s*mem\[X', self.lines[self.line_ptr]) : # another instr self.line_ptr += 1 break - else: - full_instr += " " - full_instr += self.lines[self.line_ptr] + if re.search(r'^\s*$', self.lines[self.line_ptr]) : # empty lines self.line_ptr += 1 + break + full_instr += " " + full_instr += self.lines[self.line_ptr] + self.line_ptr += 1 pattern2_0 = r'x(\d+)\s*<-\s*0x([0-9A-Fa-f]+)\s*' # reg wr pattern2_1 = r'\(v:(\d)\s+0x([0-9A-Fa-f]+)-0x([0-9A-Fa-f]+)\s+l:\S+\s+o:0x([0-9A-Fa-f]+)\s+p:(.*?)\)' - pattern2_2 = r'trapping' + pattern2_2 = r'CHERI.*Violation.*PC=0x([0-9A-Fa-f]+)' + pattern2_3 = r'trapping' matches2_0 = re.findall(pattern2_0, full_instr) matches2_1 = re.findall(pattern2_1, full_instr) matches2_2 = re.findall(pattern2_2, full_instr) + matches2_3 = re.findall(pattern2_3, full_instr) #print(full_instr) #print(matches2_0[0]) #print(matches2_1[0]) @@ -391,7 +426,16 @@ def find_nxt(self): int(matches2_1[0][2], 16), int(matches2_1[0][1], 16)) if len(matches2_2) != 0 : - nxt_obj.excp = 1 + nxt_obj.trap_pc = int(matches2_2[0], 16) + else : + nxt_obj.trap_pc = nxt_obj.pc + + # QQQ Notewe can have a corner case (not sure how to handle it yet) + # where mepc == current execution pc (basically trying to trigger a mret fault) + if len(matches2_3) != 0 and (nxt_obj.trap_pc == nxt_obj.pc): + nxt_obj.trap = 1 + elif len(matches2_3) != 0 and (nxt_obj.trap_pc != nxt_obj.pc): + nxt_obj.trap_nxt = 1 # ?: makes non-grouping pattern3 = r'(?:mem|htif)\[.*?0x([0-9A-Fa-f]+)\]\s*(<-|->)\s*0x([0-9A-Fa-f]+)' @@ -411,6 +455,12 @@ def find_nxt(self): #printf ("tag = %d\n", tag) nxt_obj.mem_data += (tag<<64) + pattern5 = r'uart\[\S+\]\s*<-' + matches5 = re.findall(pattern5, full_instr) + + if len(matches5) != 0: + nxt_obj.uart_wr = 1 + return nxt_obj # @@ -453,14 +503,17 @@ def find_nxt(self): cmp_cnt = 0; eq_cnt = 0; neq_cnt = 0; revoke_err_cnt = 0; ibex_isr_cnt = 0; pending_revoke_regs = [0] * 32 ibex_in_isr = 0 +outstanding_trap = 0 while True: if args.skip_isr : # skipping ISR if specified while True: ibex_obj = ibex_trace.find_nxt() - if (ibex_obj.excp == 0) and (ibex_obj.intr == 0) and (ibex_in_isr == 0): + if (ibex_obj.valid == 0): break - if (ibex_obj.excp == 1) or (ibex_obj.intr == 1): + if (ibex_obj.trap == 0) and (ibex_obj.intr == 0) and (ibex_in_isr == 0): + break + if (ibex_obj.trap == 1) or (ibex_obj.intr == 1): ibex_in_isr = 1 ibex_isr_cnt += 1 if (ibex_in_isr == 1) and (ibex_obj.instr == 0x30200073): # mret @@ -468,7 +521,15 @@ def find_nxt(self): else : ibex_obj = ibex_trace.find_nxt() - sail_obj = sail_trace.find_nxt() + if (outstanding_trap == 0): + sail_obj = sail_trace.find_nxt() + else: + sail_obj = trace_obj() + sail_obj.valid = 1 + sail_obj.trap = 1 + sail_obj.trap_nxt = 0 + sail_obj.pc = outstanding_trap_pc + if (ibex_obj.valid == 0) or (sail_obj.valid == 0): break @@ -476,6 +537,7 @@ def find_nxt(self): if ((pending_revoke_regs[ibex_obj.reg_raddr1] == 1) and (ibex_obj.reg_rd1 == 1) and (ibex_obj.reg_rcap1[0] == 1)): revoke_err_cnt += 1; + printf("cheriot-ibex: revocation error found for cs1 reg c%d at %x\n", ibex_obj.reg_raddr1, ibex_obj.pc) elif ((pending_revoke_regs[ibex_obj.reg_raddr1] == 1) and (ibex_obj.reg_rd1 == 1) and (ibex_obj.reg_rcap1[0] == 0)): pending_revoke_regs[ibex_obj.reg_raddr1] = 0; @@ -485,12 +547,17 @@ def find_nxt(self): if ((pending_revoke_regs[ibex_obj.reg_raddr2] == 1) and (ibex_obj.reg_rd2 == 1) and (ibex_obj.reg_rcap2[0] == 1)): revoke_err_cnt += 1; + printf("cheriot-ibex: revocation error found for cs2 reg c%d at %x\n", ibex_obj.reg_raddr2, ibex_obj.pc) elif ((pending_revoke_regs[ibex_obj.reg_raddr1] == 1) and (ibex_obj.reg_rd2 == 1) and (ibex_obj.reg_rcap2[0] == 0)): pending_revoke_regs[ibex_obj.reg_raddr2] = 0; eq_cnt += 1 printf("cheriot-ibex: cap revocation for reg c%d verified at %x\n", ibex_obj.reg_raddr2, ibex_obj.pc) + if ((pending_revoke_regs[ibex_obj.reg_waddr] == 1) and (ibex_obj.reg_wr == 1)): + pending_revoke_regs[ibex_obj.reg_waddr] = 0; + eq_cnt += 1 + printf("cheriot-ibex: cap revocation for reg c%d cancelled by write at %x\n", ibex_obj.reg_waddr, ibex_obj.pc) # compare current trace object if (ibex_obj == sail_obj): @@ -506,13 +573,29 @@ def find_nxt(self): cmp_cnt += 1 + if (sail_obj.trap_nxt == 1): + outstanding_trap = 1 + outstanding_trap_pc = sail_obj.trap_pc + # printf("--- outstanding trap\n") + else : + outstanding_trap = 0 + outstanding_trap_pc = 0 + del ibex_obj del sail_obj -printf("%d trace objects compared, %d equal, %d not equal, %d recocation errors, %d ISRs found in ibex trace\n", +printf("%d trace objects compared, %d equal, %d not equal, %d revocation errors, %d ISRs found in ibex trace\n", cmp_cnt, eq_cnt, neq_cnt, revoke_err_cnt, ibex_isr_cnt) +ibex_lines_total = len(ibex_trace.lines) +sail_lines_total = len(sail_trace.lines) +ibex_lines_left = len(ibex_trace.lines) - ibex_trace.line_ptr +sail_lines_left = len(sail_trace.lines) - sail_trace.line_ptr + +printf("%d/%d lines left in ibex_trace, %d/%d lines left in sail trace\n", + ibex_lines_left, ibex_lines_total, sail_lines_left, sail_lines_total) + revoke_pending = 0; for i in range(len(pending_revoke_regs)): if (pending_revoke_regs[i] != 0): @@ -521,4 +604,14 @@ def find_nxt(self): if (revoke_pending != 0): printf("Pending revocations found!\n"); print(pending_revoke_regs) + +# ibex usually have more instructions left at the end of simulation since the RTL simulation +# does not immediate stop after UART request. Worst case is when we have TBRE/stkz transfer still +# in progress, could take > 500 cycles to complete.. +if ((neq_cnt == 0) and (revoke_pending == 0) and + (not ((ibex_lines_total == 0) and (sail_lines_total == 0))) and + ((ibex_lines_left < 1000) and (sail_lines_left == 0))): + printf("Compare_trace.py: comparison passed :)\n") +else: + printf("Compare_trace.py: comparison failed :(\n") diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/cap_err_gen.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/cap_err_gen.sv index c162df79b..358432386 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/cap_err_gen.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/cap_err_gen.sv @@ -96,7 +96,8 @@ module cap_err_gen import ibex_pkg::*; import cheri_pkg::*; ( return lsu_acc_out; endfunction - + + `define EX_PATH dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex logic cheri_exec_id, cheri_ex_valid; logic [35:0] cheri_operator; @@ -104,6 +105,7 @@ module cap_err_gen import ibex_pkg::*; import cheri_pkg::*; ( logic [31:0] pc_id; logic is_rv32_lsu, is_cheri_lsu; logic [31:0] rv32_lsu_start_addr; + logic is_cjalr; logic cap_err_schd; logic [31:0] cap_err_seed; @@ -114,36 +116,37 @@ module cap_err_gen import ibex_pkg::*; import cheri_pkg::*; ( lsu_access_t lsu_acc_orig, lsu_acc_mod; - assign cheri_exec_id = dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.cheri_exec_id_i; - assign cheri_ex_valid = dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.cheri_ex_valid_o; - assign cheri_operator = dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.cheri_operator_i; + assign cheri_exec_id = `EX_PATH.cheri_exec_id_i; + assign cheri_ex_valid = `EX_PATH.cheri_ex_valid_o; + assign cheri_operator = `EX_PATH.cheri_operator_i; - assign rv32_lsu_start_addr = dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.rv32_lsu_addr_i - - {29'h0, dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.addr_incr_req_i, 2'b00}; + assign rv32_lsu_start_addr = `EX_PATH.rv32_lsu_addr_i - + {29'h0, `EX_PATH.addr_incr_req_i, 2'b00}; assign lsu_acc_orig = is_rv32_lsu ? - '{8'h0, 1'b0, dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.rv32_lsu_we_i, - dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.rv32_lsu_type_i, + '{8'h0, 1'b0, `EX_PATH.rv32_lsu_we_i, + `EX_PATH.rv32_lsu_type_i, rv32_lsu_start_addr, rcap_a, rdata_a} : '{8'h0, 1'b1, cheri_operator[CSTORE_CAP], 2'b00, - dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.cs1_addr_plusimm, + `EX_PATH.cs1_addr_plusimm, rcap_a, rdata_a}; assign instr_done = dut.u_ibex_top.u_ibex_core.id_stage_i.instr_done; assign pc_id = dut.u_ibex_top.u_ibex_core.id_stage_i.pc_id_i; - assign rcap_a = dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.rf_rcap_ng_a; - assign rcap_b = dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.rf_rcap_ng_b; - assign rdata_a = dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.rf_rdata_ng_a; - assign rdata_b = dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.rf_rdata_ng_b; + assign rcap_a = `EX_PATH.rf_rcap_ng_a; + assign rcap_b = `EX_PATH.rf_rcap_ng_b; + assign rdata_a = `EX_PATH.rf_rdata_ng_a; + assign rdata_b = `EX_PATH.rf_rdata_ng_b; - assign is_rv32_lsu = dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.rv32_lsu_req_i; + assign is_rv32_lsu = `EX_PATH.rv32_lsu_req_i; assign is_cheri_lsu = cheri_exec_id & (cheri_operator[CLOAD_CAP] | cheri_operator[CSTORE_CAP]); - assign pc_in_isr = dut.u_ibex_top.u_ibex_core.id_stage_i.controller_i.controller_dv_ext_i.cpu_in_isr; + assign is_cjalr = cheri_exec_id & cheri_operator[CJALR]; + assign pc_in_isr = dut.u_ibex_top.u_ibex_core.id_stage_i.controller_i.controller_dv_ext_i.cpu_in_isr; - assign err_failed = err_active & dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.lsu_req_o & - (~dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.lsu_cheri_err_o) & + assign err_failed = err_active & `EX_PATH.lsu_req_o & + (~`EX_PATH.lsu_cheri_err_o) & (~lsu_acc_mod.flag[7]); always @(posedge clk, negedge rst_n) begin @@ -151,14 +154,13 @@ module cap_err_gen import ibex_pkg::*; import cheri_pkg::*; ( cap_err_schd <= 1'b0; cap_err_seed <= 32'h0; end else begin - if ((is_cheri_lsu | is_rv32_lsu) & instr_done) begin + if ((is_cheri_lsu | is_rv32_lsu | is_cjalr) & instr_done) begin cap_err_schd <= err_enable & ((ERR_RATE == 0) ? 1'b0 : ($urandom()%(2**(8-ERR_RATE))==0)); cap_err_seed <= $urandom(); end end end - initial begin err_active = 1'b1; @@ -167,21 +169,42 @@ module cap_err_gen import ibex_pkg::*; import cheri_pkg::*; ( while (1) begin @(posedge clk); #1; - force dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.rf_rcap_a = rcap_a; // default + + // inject load/store cheri errors + force `EX_PATH.rf_rcap_a = rcap_a; // default if ((is_cheri_lsu | is_rv32_lsu) & cap_err_schd & ~pc_in_isr) begin lsu_acc_mod = inject_ls_cap_err(lsu_acc_orig, cap_err_seed); - force dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.rf_rcap_a = lsu_acc_mod.cs1_cap; + force `EX_PATH.rf_rcap_a = lsu_acc_mod.cs1_cap; if (is_rv32_lsu && (lsu_acc_mod.flag[7:6] == 2'b01)) // modify address - force dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.rv32_ls_chkaddr = lsu_acc_mod.addr; + force `EX_PATH.rv32_ls_chkaddr = lsu_acc_mod.addr; else if (lsu_acc_mod.flag[7:6] == 2'b01) - force dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.cheri_ls_chkaddr = lsu_acc_mod.addr; + force `EX_PATH.cheri_ls_chkaddr = lsu_acc_mod.addr; + err_active = 1'b1; + end else if (is_cjalr & cap_err_schd & ~pc_in_isr) begin + if (cap_err_seed[1:0] == 2'b00) + force `EX_PATH.rf_rcap_a.valid = 1'b0; + if (cap_err_seed[3:2] == 2'b00) + force `EX_PATH.rf_rcap_a.cperms = 6'b010011; // LD/SD only, no EX + if (cap_err_seed[5:4] == 2'b00) + force `EX_PATH.rf_rcap_a.otype = {2'b11, cap_err_seed[8]}; // sealed but not sentry + //randomize otypes - this causes mismatch with sail.. QQQ + //end else if (is_cjalr & ~pc_in_isr) begin + // force `EX_PATH.rf_rcap_a.otype = {cap_err_seed[9:8]}; // otype 0/1/2/3 end else begin - release dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.rf_rcap_a; - release dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.rv32_ls_chkaddr; - release dut.u_ibex_top.u_ibex_core.g_cheri_ex.u_cheri_ex.cheri_ls_chkaddr; + release `EX_PATH.rf_rcap_a; + release `EX_PATH.rv32_ls_chkaddr; + release `EX_PATH.cheri_ls_chkaddr; err_active = 1'b0; end + + // Error injection for branch/cjal/cjalr instructions + // -- limited value since branch/cjal can only cause address bound vio lations + // which is defered to fetch stage, and thus lumped into instr_fetch_err. + // -- we already have random instr fetch error (mem error) generation so from + // pipeline timing perspective this doesn't add much new. + + // -- cjalr perm/seal errors can just be checked by point tests.. end end endmodule diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/cheriot_dv_pkg.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/cheriot_dv_pkg.sv index de876b2cc..b724f7f66 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/cheriot_dv_pkg.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/cheriot_dv_pkg.sv @@ -31,4 +31,122 @@ package cheriot_dv_pkg; logic err; } lsu_cmd_t; + function automatic logic is_representable(full_cap_t in_cap, logic [31:0] address); + logic result; + logic [32:0] rep_top; + + rep_top = 33'h1 << (9+in_cap.exp); + + if (in_cap.exp == 24) + result = 1'b1; + else if ((address >= in_cap.base32) && ((address - in_cap.base32) < rep_top)) + result = 1'b1; + else + result = 1'b0; + + return result; + endfunction + + function automatic logic[2:0] repr_cases (full_cap_t in_cap, logic [31:0] address); + logic [2:0] result; + logic [32:0] rep_top; + + rep_top = 33'h1 << (9+in_cap.exp); + + // error cases to be covered, will add more later + if (address < in_cap.base32) + result = 1; + else if ((address - in_cap.base32) >= rep_top) + result = 2; + else + result = 0; + + return result; + endfunction + + function automatic logic[5:0] count32_zeros (logic [31:0] address); + logic [5:0] result; + int i; + + result = 0; + for (i = 0; i <=31; i++) + if (address[i] == 1'b0) result += 1; + + return result; + endfunction + + function automatic logic[8:0] bound_check_cases (full_cap_t in_cap, logic [31:0] address); + logic [8:0] result; + logic [33:0] room; + + result[0] = (address < in_cap.base32); // impossible value = 2'b11 + result[1] = (address == in_cap.base32); + + result[2] = (address > in_cap.top33); // impossible value = 2'b11 + result[3] = (address == in_cap.top33); + + room = in_cap.top33 - address; + if ((room > 0) && (room < 8)) result[6:4] = room[2:0]; + else result[6:4] = 0; + + // cornercases + result[7] = (in_cap.top33 == 33'h1_0000_0000); + result[8] = (in_cap.base32 == 33'h0); + + return result; + endfunction + + function automatic logic[4:0] setbounds_cases (full_cap_t cs1_cap, logic [31:0] cs1_address, logic [31:0] req_len); + logic [4:0] result; + + logic [32:0] cs1_len; + + result[0] = (cs1_address < cs1_cap.base32); // impossible value = 2'b11 + result[1] = (cs1_address == cs1_cap.base32); + + result[2] = (cs1_address > cs1_cap.top33); // impossible value = 2'b11 + result[3] = (cs1_address == cs1_cap.top33); + + cs1_len = cs1_cap.top33 - cs1_cap.base32; + result[4] = (req_len <= cs1_len); + + return result; + endfunction + + function automatic full_cap_t mem2fullcap_fmt0_raw (logic [32:0] msw, logic [32:0] addr33); + reg_cap_t regcap; + full_cap_t result_cap; + + logic [EXP_W-1:0] tmp5; + logic [3:0] tmp4; + logic [CPERMS_W-1:0] cperms_mem; + logic [BOT_W-1:0] addrmi9; + logic valid_in; + + valid_in = msw[32] & addr33[32]; + regcap.valid = valid_in; + + tmp5 = {1'b0, msw[CEXP_LO+:CEXP_W]}; + if (tmp5 == EXP_W'(RESETCEXP)) tmp5 = RESETEXP; + regcap.exp = tmp5; + + regcap.top = msw[TOP_LO+:TOP_W]; + regcap.base = msw[BASE_LO+:BOT_W]; + regcap.otype = msw[OTYPE_LO+:OTYPE_W]; + + cperms_mem = msw[CPERMS_LO+:CPERMS_W]; + regcap.cperms = cperms_mem; + addrmi9 = BOT_W'({1'b0, addr33[31:0]} >> regcap.exp); // ignore the tag valid bit + tmp4 = update_temp_fields(regcap.top, regcap.base, addrmi9); + regcap.top_cor = tmp4[3:2]; + regcap.base_cor = tmp4[1:0]; + + regcap.rsvd = msw[RSVD_LO]; + + result_cap = reg2fullcap(regcap, addr33[31:0]); + + return result_cap; + + endfunction + endpackage diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/cheriot_main.cc b/vendor/lowrisc_ibex/dv/cheriot/tb/cheriot_main.cc index 21c468e9d..85e5a4e7a 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/cheriot_main.cc +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/cheriot_main.cc @@ -44,7 +44,7 @@ int main(int argc, char** argv, char** env) { uint64_t sim_time = 0; dut->clk_i = 0; - dut->rstn_i = 1; + dut->rst_ni = 1; dut->dii_insn_i = 0x1; first_cycle = 1; @@ -83,8 +83,8 @@ int main(int argc, char** argv, char** env) { dut->eval(); sim_time++; - if (sim_time == 10) { dut->rstn_i = 0;} - else if (sim_time == 20) { dut->rstn_i = 1; } + if (sim_time == 10) { dut->rst_ni = 0; } + else if (sim_time == 20) { dut->rst_ni = 1; } } #ifdef VCD_TRACE diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/core_ibex_fcov_if.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/core_ibex_fcov_if.sv index cd195760e..306e892fe 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/core_ibex_fcov_if.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/core_ibex_fcov_if.sv @@ -31,7 +31,8 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( InstrCategoryMul, InstrCategoryDiv, InstrCategoryBranch, - InstrCategoryJump, + InstrCategoryCJAL, + InstrCategoryCJALR, InstrCategoryLoad, InstrCategoryStore, InstrCategoryCSRAccess, @@ -43,15 +44,12 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( InstrCategoryWFI, InstrCategoryFence, InstrCategoryFenceI, - InstrCategoryCheriQuery, // cs1, [cs2] --> rd + InstrCategoryCheriQuery, // cs1 --> rd InstrCategoryCheriMod, // cs1, rs2|cs2 --> cd InstrCategoryCheriAddr, // cs1, [rs2] --> cd InstrCategoryCheriBounds, // cs1, [rs2] --> cd - InstrCategoryCheriAUIPCC, // PCC (c3) --> cd InstrCategoryCheriCLC, InstrCategoryCheriCSC, - // InstrCategoryCheriCJAL, - // InstrCategoryCheriCJALR, InstrCategoryCheriSCR, InstrCategoryNone, InstrCategoryFetchError, @@ -74,7 +72,8 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( IdStallTypeTRVK } id_stall_type_e; - instr_category_e id_instr_category; + instr_category_e id_instr_category, wb_instr_category, id_instr_category_q; + // Set `id_instr_category` to the appropriate category for the uncompressed instruction in the // ID/EX stage. Compressed instructions are not handled (`id_stage_i.instr_rdata_i` is always // uncompressed). When the `id_stage.instr_valid_i` isn't set `InstrCategoryNone` is the given @@ -95,9 +94,9 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( case (id_stage_i.instr_rdata_i[6:0]) ibex_pkg::OPCODE_LUI: id_instr_category = InstrCategoryALU; - ibex_pkg::OPCODE_AUIPC: id_instr_category = InstrCategoryALU; - ibex_pkg::OPCODE_JAL: id_instr_category = InstrCategoryJump; - ibex_pkg::OPCODE_JALR: id_instr_category = InstrCategoryJump; + // ibex_pkg::OPCODE_AUIPC: id_instr_category = InstrCategoryALU; + ibex_pkg::OPCODE_JAL: id_instr_category = InstrCategoryCJAL; + ibex_pkg::OPCODE_JALR: id_instr_category = InstrCategoryCJALR; ibex_pkg::OPCODE_BRANCH: id_instr_category = InstrCategoryBranch; ibex_pkg::OPCODE_LOAD: id_instr_category = InstrCategoryLoad; ibex_pkg::OPCODE_STORE: id_instr_category = InstrCategoryStore; @@ -146,7 +145,7 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( default: id_instr_category = InstrCategoryOther; endcase - // CHERI decoding + // CHERI decoding takes precedance case(1'b1) cheri_ops[CCSR_RW]: id_instr_category = InstrCategoryCheriSCR; @@ -154,15 +153,12 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( id_instr_category = InstrCategoryCheriAddr; cheri_ops[CSET_BOUNDS_IMM], cheri_ops[CSET_BOUNDS], cheri_ops[CSET_BOUNDS_EX], cheri_ops[CRRL], cheri_ops[CRAM]: id_instr_category = InstrCategoryCheriBounds; - cheri_ops[CCLEAR_TAG], cheri_ops[CMOVE_CAP], cheri_ops[CSEAL], cheri_ops[CUNSEAL], cheri_ops[CAND_PERM]: + cheri_ops[CCLEAR_TAG], cheri_ops[CMOVE_CAP], cheri_ops[CSEAL], cheri_ops[CUNSEAL], cheri_ops[CAND_PERM], + cheri_ops[CSUB_CAP], cheri_ops[CIS_SUBSET], cheri_ops[CIS_EQUAL], cheri_ops[CSET_HIGH]: id_instr_category = InstrCategoryCheriMod; - cheri_ops[CGET_PERM], cheri_ops[CGET_TYPE], cheri_ops[CGET_BASE], cheri_ops[CGET_TOP], cheri_ops[CGET_LEN], - cheri_ops[CGET_TAG], cheri_ops[CGET_ADDR], cheri_ops[CSUB_CAP], cheri_ops[CIS_SUBSET], cheri_ops[CIS_EQUAL]: + cheri_ops[CGET_PERM], cheri_ops[CGET_TYPE], cheri_ops[CGET_BASE], cheri_ops[CGET_TOP], + cheri_ops[CGET_LEN], cheri_ops[CGET_TAG], cheri_ops[CGET_ADDR], cheri_ops[CGET_HIGH]: id_instr_category = InstrCategoryCheriQuery; - // cheri_ops[CJAL]: - // id_instr_category = InstrCategoryCheriCJAL; - // cheri_ops[CJALR]: - // id_instr_category = InstrCategoryCheriCJALR; cheri_ops[CLOAD_CAP]: id_instr_category = InstrCategoryCheriCLC; cheri_ops[CSTORE_CAP]: @@ -195,6 +191,25 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( end end + logic [1:0] fcov_id_exc_int, fcov_id_exc_int_q; + + assign fcov_id_exc_int = {id_stage_i.controller_i.handle_irq, id_stage_i.controller_i.special_req_pc_change}; + + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + wb_instr_category <= InstrCategoryNone; + id_instr_category_q <= InstrCategoryNone; + fcov_id_exc_int_q <= 0; + end else begin + wb_instr_category <= id_instr_category; + if (id_stage_i.instr_done | id_stage_i.gen_stall_mem.instr_kill) begin + id_instr_category_q <= id_instr_category; + fcov_id_exc_int_q <= fcov_id_exc_int; + end + end + end + + // Check instruction categories calculated from instruction bits match what decoder has produced. // The ALU category is tricky as there's no specific ALU enable and instructions that actively use @@ -214,8 +229,15 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( `ASSERT(InstrCategoryBranchCorrect, id_instr_category == InstrCategoryBranch |-> id_stage_i.branch_in_dec) - // `ASSERT(InstrCategoryJumpCorrect, - // id_instr_category == InstrCategoryJump |-> id_stage_i.jump_in_dec) + `ASSERT(InstrCategoryJALCorrect, + id_instr_category == InstrCategoryCJAL |-> + ((~id_stage_i.cheri_pmode_i & id_stage_i.jump_in_dec) || + (id_stage_i.cheri_pmode_i & id_stage_i.decoder_i.cheri_jal_en))) + + `ASSERT(InstrCategoryJALRCorrect, + id_instr_category == InstrCategoryCJALR |-> + ((~id_stage_i.cheri_pmode_i & id_stage_i.jump_in_dec) || + (id_stage_i.cheri_pmode_i & id_stage_i.decoder_i.cheri_jalr_en))) `ASSERT(InstrCategoryLoadCorrect, id_instr_category == InstrCategoryLoad |-> id_stage_i.lsu_req_dec && !id_stage_i.lsu_we) @@ -265,7 +287,7 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( end if (id_stage_i.stall_multdiv || id_stage_i.stall_branch || - id_stage_i.stall_jump) begin + id_stage_i.stall_jump || id_stage_i.stall_cheri) begin id_stall_type = IdStallTypeInstr; end @@ -447,6 +469,65 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( assign fcov_tag_clear_cs1cd = g_cheri_ex.u_cheri_ex.rf_fullcap_a.valid & ~g_cheri_ex.u_cheri_ex.result_cap_o.valid; + // representablility and bound check cases + logic [2:0] fcov_cd_cs1_repr_cases; + logic [2:0] fcov_cd_pcc_repr_cases; + + assign fcov_cd_cs1_repr_cases = repr_cases(g_cheri_ex.u_cheri_ex.rf_fullcap_a, g_cheri_ex.u_cheri_ex.result_data_o); + assign fcov_cd_pcc_repr_cases = repr_cases(pcc2fullcap(cs_registers_i.pcc_cap_o), g_cheri_ex.u_cheri_ex.result_data_o); + + // address range representation + // let's use # of 0's now - will change if figoure out something better QQQ + logic [5:0] fcov_cs1_address_0cnt, fcov_cs2_address_0cnt, fcov_cd_address_0cnt; + + assign fcov_cs1_address_0cnt = count32_zeros(g_cheri_ex.u_cheri_ex.rf_rdata_a); + assign fcov_cs2_address_0cnt = count32_zeros(g_cheri_ex.u_cheri_ex.rf_rdata_b); + assign fcov_cd_address_0cnt = count32_zeros(g_cheri_ex.u_cheri_ex.result_data_o); + + + logic [8:0] fcov_cjal_target_bound_cases; + assign fcov_cjal_target_bound_cases = bound_check_cases(pcc2fullcap(cs_registers_i.pcc_cap_o), + g_cheri_ex.u_cheri_ex.branch_target_o); + + logic [8:0] fcov_cjalr_target_bound_cases; + assign fcov_cjalr_target_bound_cases = bound_check_cases(g_cheri_ex.u_cheri_ex.rf_fullcap_a, + g_cheri_ex.u_cheri_ex.branch_target_o); + + logic [8:0] fcov_branch_target_bound_cases; + assign fcov_branch_target_bound_cases = bound_check_cases(pcc2fullcap(cs_registers_i.pcc_cap_o), + ex_block_i.branch_target_o[31:0]); + + logic [8:0] fcov_clsc_bound_cases; + assign fcov_clsc_bound_cases = bound_check_cases(g_cheri_ex.u_cheri_ex.rf_fullcap_a, + g_cheri_ex.u_cheri_ex.cheri_ls_chkaddr); + + logic [3:0] fcov_seal_bound_cases; + logic [8:0] tmp9; + assign tmp9 = bound_check_cases(g_cheri_ex.u_cheri_ex.rf_fullcap_b, g_cheri_ex.u_cheri_ex.cheri_ls_chkaddr); + + assign fcov_seal_bound_cases = tmp9[3:0]; + + logic [4:0] fcov_setbounds_cases; + assign fcov_setbounds_cases = setbounds_cases(g_cheri_ex.u_cheri_ex.rf_fullcap_a, g_cheri_ex.u_cheri_ex.rf_rdata_a, + g_cheri_ex.u_cheri_ex.rf_rdata_b); + + logic [4:0] fcov_setboundsimm_cases; + assign fcov_setboundsimm_cases = setbounds_cases(g_cheri_ex.u_cheri_ex.rf_fullcap_a, g_cheri_ex.u_cheri_ex.rf_rdata_a, + g_cheri_ex.u_cheri_ex.cheri_imm12_i); + + logic [5:0] fcov_rs1_bitsize; + assign fcov_rs1_bitsize = get_size(g_cheri_ex.u_cheri_ex.rf_rdata_a); + + logic fcov_id_error, fcov_wb_err; + assign fcov_id_error = id_stage_i.controller_i.instr_fetch_err_prio | id_stage_i.controller_i.illegal_insn_prio | + id_stage_i.controller_i.ecall_insn_prio | id_stage_i.controller_i.ebrk_insn_prio | + id_stage_i.controller_i.cheri_ex_err_prio | id_stage_i.controller_i.cheri_ex_err_prio | + id_stage_i.controller_i.cheri_asr_err_prio; + assign fcov_wb_error = id_stage_i.controller_i.load_err_prio | id_stage_i.controller_i.store_err_prio | + id_stage_i.controller_i.cheri_wb_err_prio; + + + covergroup uarch_cg @(posedge clk_i); option.per_instance = 1; option.name = "uarch_cg"; @@ -476,21 +557,21 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( cp_mprv: coverpoint cs_registers_i.mstatus_q.mprv; - // cp_ls_error_exception: coverpoint load_store_unit_i.lsu_dv_ext_i.fcov_ls_error_exception; - // cp_ls_pmp_exception: coverpoint load_store_unit_i.lsu_dv_ext_i.fcov_ls_pmp_exception; - // cp_ls_cheri_exception: coverpoint load_store_unit_i.lsu_dv_ext_i.fcov_ls_cheri_exception; + // ls err: mem_err, pmp_err, cheri_err cp_ls_exception: coverpoint load_store_unit_i.lsu_dv_ext_i.fcov_ls_exception_type; cp_branch_taken: coverpoint id_stage_i.fcov_branch_taken; cp_branch_not_taken: coverpoint id_stage_i.fcov_branch_not_taken; // KLIU - for CHERIoT priv mode doesn't matter -// cp_priv_mode_id: coverpoint priv_mode_id { -// illegal_bins illegal = {PRIV_LVL_H, PRIV_LVL_S}; -// } -// cp_priv_mode_lsu: coverpoint priv_mode_lsu { -// illegal_bins illegal = {PRIV_LVL_H, PRIV_LVL_S}; -// } + cp_priv_mode_id: coverpoint priv_mode_id { + ignore_bins ignore = {PRIV_LVL_U}; + illegal_bins illegal = {PRIV_LVL_H, PRIV_LVL_S}; + } + cp_priv_mode_lsu: coverpoint priv_mode_lsu { + ignore_bins ignore = {PRIV_LVL_U}; + illegal_bins illegal = {PRIV_LVL_H, PRIV_LVL_S}; + } cp_if_stage_state : coverpoint if_stage_state; cp_id_stage_state : coverpoint id_stage_state; @@ -516,7 +597,7 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( // Each stage sees a dummy instruction. cp_dummy_instr_if_stage: coverpoint if_stage_i.if_stage_dv_ext_i.fcov_insert_dummy_instr; cp_dummy_instr_id_stage: coverpoint if_stage_i.dummy_instr_id_o; - // cp_dummy_instr_wb_stage: coverpoint wb_stage_i.dummy_instr_wb_o; // QQQ why need this? + //cp_dummy_instr_wb_stage: coverpoint wb_stage_i.dummy_instr_wb_o; // QQQ why need this? `DV_FCOV_EXPR_SEEN(rf_a_ecc_err, ibex_core_dv_ext_i.fcov_rf_ecc_err_a_id) `DV_FCOV_EXPR_SEEN(rf_b_ecc_err, ibex_core_dv_ext_i.fcov_rf_ecc_err_b_id) @@ -609,19 +690,19 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( `DV_FCOV_EXPR_SEEN(single_step_taken, id_stage_i.controller_i.controller_dv_ext_i.fcov_debug_single_step_taken) `DV_FCOV_EXPR_SEEN(single_step_exception, id_stage_i.controller_i.do_single_step_d && id_stage_i.controller_i.controller_dv_ext_i.fcov_pipe_flush) -// `DV_FCOV_EXPR_SEEN(insn_trigger_enter_debug, instr_id_matches_trigger_q) + `DV_FCOV_EXPR_SEEN(insn_trigger_enter_debug, instr_id_matches_trigger_q) cp_nmi_taken: coverpoint ((fcov_irqs[5] || fcov_irqs[4])) iff (id_stage_i.controller_i.fcov_interrupt_taken); cp_interrupt_taken: coverpoint fcov_irqs iff (id_stage_i.controller_i.fcov_interrupt_taken){ - // wildcard bins nmi_external = {6'b1?????}; - // wildcard bins nmi_internal = {6'b01????}; - // wildcard bins irq_fast = {6'b001???}; + wildcard bins nmi_external = {6'b1?????}; + wildcard bins nmi_internal = {6'b01????}; + wildcard bins irq_fast = {6'b001???}; wildcard bins irq_external = {6'b0001??}; - // wildcard bins irq_software = {6'b00001?}; // QQQ - let's worry about different interrupt sources later - // wildcard bins irq_timer = {6'b000001}; - //ignore_bins ignore = default; + wildcard bins irq_software = {6'b00001?}; // QQQ - let's worry about different interrupt sources later + wildcard bins irq_timer = {6'b000001}; + // ignore_bins ignore = default; } cp_controller_fsm: coverpoint id_stage_i.controller_i.ctrl_fsm_cs { @@ -643,14 +724,14 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( bins out_of_wait_sleep = (WAIT_SLEEP => SLEEP); bins out_of_sleep = (SLEEP => FIRST_FETCH); // TODO: VCS does not implement default sequence so illegal_bins will be empty - illegal_bins illegal_transitions = default sequence; + // illegal_bins illegal_transitions = default sequence; } cp_controller_fsm_sleep: coverpoint id_stage_i.controller_i.ctrl_fsm_cs { bins out_of_sleep = (SLEEP => FIRST_FETCH); bins enter_sleep = (WAIT_SLEEP => SLEEP); // TODO: VCS does not implement default sequence so illegal_bins will be empty - illegal_bins illegal_transitions = default sequence; + // illegal_bins illegal_transitions = default sequence; } // This will only be seen when specific interrupt is disabled by MIE CSR @@ -695,21 +776,21 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( // New coverage points // - cp_rs1_addr: coverpoint id_stage_i.rf_raddr_a_o[4:0] iff (id_stage_i.rf_ren_a) { + cp_rs1_regaddr: coverpoint id_stage_i.rf_raddr_a_o[4:0] iff (id_stage_i.rf_ren_a) { bins bin0 = {0}; bins bin1to14 = {[1:14]}; bins bin15 = {15}; bins bin16to31 = {[16:31]}; // for CHERIoT negative case } - cp_rs2_addr: coverpoint id_stage_i.rf_raddr_b_o[4:0] iff (id_stage_i.rf_ren_b) { + cp_rs2_regaddr: coverpoint id_stage_i.rf_raddr_b_o[4:0] iff (id_stage_i.rf_ren_b) { bins bin0 = {0}; bins bin1to14 = {[1:14]}; bins bin15 = {15}; bins bin16to31 = {[16:31]}; // for CHERIoT negative case } - cp_rd_addr: coverpoint id_stage_i.rf_waddr_id_o[4:0] iff + cp_rd_regaddr: coverpoint id_stage_i.rf_waddr_id_o[4:0] iff (id_stage_i.rf_we_id_o | g_cheri_ex.u_cheri_ex.cheri_rf_we_o) { bins bin0 = {0}; bins bin1to14 = {[1:14]}; @@ -717,8 +798,17 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( bins bin16to31 = {[16:31]}; // for CHERIoT negative case } + // for cincaddr rs2 argument + cp_rs2_as_inc: coverpoint g_cheri_ex.u_cheri_ex.rf_rdata_b { + bins bin1 ={0}; + bins bin2 ={[1:32'h7fff_ffff]}; + bins bin3 ={32'h8000_0000}; + bins bin4 ={[32'h8000_0001:32'hffff_fffe]}; + bins bin5 ={32'hffff_ffff}; + } + // all CHERIoT instructions enumerated - cp_cheri_instr_set: coverpoint fcov_cheri_instr iff (|cheri_ops); + cp_cheri_instr_set: coverpoint fcov_cheri_instr iff ((|cheri_ops) && g_cheri_ex.u_cheri_ex.cheri_exec_id_i); // coverage points for PCC cp_pcc_tag: coverpoint cs_registers_i.pcc_cap_o.valid; @@ -730,58 +820,208 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( illegal_bins illegal = default; } - cp_pcc_otype: coverpoint cs_registers_i.pcc_cap_o.otype iff (cs_registers_i.pcc_cap_o.valid) { - bins bin0 = {0}; - bins bin1 = {[1:7]}; + // valid pcc now will always have otype == 0 and perm_ex set (assertion in cs_reg_dv_ext) + cp_pcc_perm_asr: coverpoint cs_registers_i.pcc_cap_o.perms[PERM_SR]; + cp_pcc_perm_ex: coverpoint cs_registers_i.pcc_cap_o.perms[PERM_EX]; + + + // cheriot instruction immediates + cp_cheri_imm20: coverpoint g_cheri_ex.u_cheri_ex.cheri_imm20_i { + bins bin1 ={0}; + bins bin2 ={[1:20'h7_ffff]}; + bins bin3 ={20'h8_0000}; + bins bin4 ={[20'h8_0001:20'hf_fffe]}; + bins bin5 ={20'hf_ffff}; + } + + cp_cheri_imm12: coverpoint g_cheri_ex.u_cheri_ex.cheri_imm12_i { + bins bin1 ={0}; + bins bin2 ={[1:12'h7ff]}; + bins bin3 ={12'h800}; + bins bin4 ={[12'h801:12'hffe]}; + bins bin5 ={12'hfff}; } - cp_pcc_perm_ex: coverpoint cs_registers_i.pcc_cap_o.perms[PERM_EX] iff - (cs_registers_i.pcc_cap_o.valid); // coverage points for CS1 cp_cs1_tag: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_a.valid; - cp_cs1_exp: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_a.exp iff - (g_cheri_ex.u_cheri_ex.rf_fullcap_a.valid) { + cp_cs1_exp: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_a.exp { bins bin0 = {0}; bins bin1 = {[1:14]}; bins bin2 = {24}; - illegal_bins illegal = default; } - cp_cs1_otype: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_a.otype iff - (g_cheri_ex.u_cheri_ex.rf_fullcap_a.valid) { + cp_cs1_otype: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_a.otype { bins bin[] = {[0:7]}; // including reserved values for coverage } + cp_cs1_sealed: coverpoint ~(|g_cheri_ex.u_cheri_ex.rf_fullcap_a.otype) iff + (g_cheri_ex.u_cheri_ex.rf_fullcap_a.valid); + cp_cs1_cor: coverpoint {g_cheri_ex.u_cheri_ex.rf_fullcap_a.base_cor, - g_cheri_ex.u_cheri_ex.rf_fullcap_a.top_cor} iff - (g_cheri_ex.u_cheri_ex.rf_fullcap_a.valid) { + g_cheri_ex.u_cheri_ex.rf_fullcap_a.top_cor} { bins bin0 = {4'b0000}; bins bin1 = {4'b0001}; // bins bin2 = {4'b0011}; // base_cor = 0, top_cor = -1, impossible case bins bin3 = {4'b1100}; // bins bin4 = {4'b1101}; // impossible case bins bin5 = {4'b1111}; + } + + cp_cs1_top: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_a.top { + bins bin_all1 = {9'h1ff}; + bins bin_all0 = {9'h0}; + bins bin1 = {[9'h1:9'h1fe]}; + } + + cp_cs1_base: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_a.base { + bins bin_all1 = {9'h1ff}; + bins bin_all0 = {9'h0}; + bins bin1 = {[9'h1:9'h1fe]}; + } + + cp_cs1_perms: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_a.perms { + wildcard bins gl0 = {13'b?_????_????_???0}; + wildcard bins gl1 = {13'b?_????_????_???1}; + wildcard bins lg0 = {13'b?_????_????_??0?}; + wildcard bins lg1 = {13'b?_????_????_??1?}; + wildcard bins sd0 = {13'b?_????_????_?0??}; + wildcard bins sd1 = {13'b?_????_????_?1??}; + wildcard bins lm0 = {13'b?_????_????_0???}; + wildcard bins lm1 = {13'b?_????_????_1???}; + wildcard bins sl0 = {13'b?_????_???0_????}; + wildcard bins sl1 = {13'b?_????_???1_????}; + wildcard bins ld0 = {13'b?_????_??0?_????}; + wildcard bins ld1 = {13'b?_????_??1?_????}; + wildcard bins mc0 = {13'b?_????_?0??_????}; + wildcard bins mc1 = {13'b?_????_?1??_????}; + wildcard bins sr0 = {13'b?_????_0???_????}; + wildcard bins sr1 = {13'b?_????_1???_????}; + wildcard bins ex0 = {13'b?_???0_????_????}; + wildcard bins ex1 = {13'b?_???1_????_????}; + wildcard bins us0 = {13'b?_??0?_????_????}; + wildcard bins us1 = {13'b?_??1?_????_????}; + wildcard bins se0 = {13'b?_?0??_????_????}; + wildcard bins se1 = {13'b?_?1??_????_????}; + wildcard bins u00 = {13'b?_0???_????_????}; + wildcard bins u01 = {13'b?_1???_????_????}; + wildcard bins u10 = {13'b0_????_????_????}; + wildcard ignore_bins u11 = {13'b1_????_????_????}; illegal_bins illegal = default; } - cp_cs1_top: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_a.top iff - (g_cheri_ex.u_cheri_ex.rf_fullcap_a.valid) { + cp_cs1_perms_load: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_a.perms { + wildcard bins lg0 = {13'b?_????_????_??0?}; + wildcard bins lg1 = {13'b?_????_????_??1?}; + wildcard bins lm0 = {13'b?_????_????_0???}; + wildcard bins lm1 = {13'b?_????_????_1???}; + wildcard bins ld0 = {13'b?_????_??0?_????}; + wildcard bins ld1 = {13'b?_????_??1?_????}; + wildcard bins mc0 = {13'b?_????_?0??_????}; + wildcard bins mc1 = {13'b?_????_?1??_????}; + } + + cp_cs1_perms_store: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_a.perms { + wildcard bins sd0 = {13'b?_????_????_?0??}; + wildcard bins sd1 = {13'b?_????_????_?1??}; + wildcard bins sl0 = {13'b?_????_???0_????}; + wildcard bins sl1 = {13'b?_????_???1_????}; + wildcard bins mc0 = {13'b?_????_?0??_????}; + wildcard bins mc1 = {13'b?_????_?1??_????}; + } + + cp_cs1_perm_ex: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_a.perms[PERM_EX]; + cp_cs1_perm_gl: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_a.perms[PERM_GL]; + + cp_cs1_address: coverpoint fcov_cs1_address_0cnt { + bins valid[] = {[0:32]}; + ignore_bins ignore = {[33:$]}; + } + + cp_cs1_base32: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_a.base32 { + bins bin0 = {0}; + bins bin1 = {[1: 32'hffff_fffd]}; + bins bin2 = {[1: 32'hffff_fffe]}; + bins bin3 = {32'hffff_ffff}; + } + + cp_cs1_top33: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_a.top33 { + bins bin0 = {0}; + bins bin1 = {[1: 33'hffff_fffe]}; + bins bin2 = {33'hffff_ffff}; + bins bin3 = {33'h1_0000_0000}; + } + + cp_rs2_perm_mask: coverpoint g_cheri_ex.u_cheri_ex.rf_rdata_b[12:0] { + wildcard bins gl0 = {13'b?_????_????_???0}; + wildcard bins gl1 = {13'b?_????_????_???1}; + wildcard bins lg0 = {13'b?_????_????_??0?}; + wildcard bins lg1 = {13'b?_????_????_??1?}; + wildcard bins sd0 = {13'b?_????_????_?0??}; + wildcard bins sd1 = {13'b?_????_????_?1??}; + wildcard bins lm0 = {13'b?_????_????_0???}; + wildcard bins lm1 = {13'b?_????_????_1???}; + wildcard bins sl0 = {13'b?_????_???0_????}; + wildcard bins sl1 = {13'b?_????_???1_????}; + wildcard bins ld0 = {13'b?_????_??0?_????}; + wildcard bins ld1 = {13'b?_????_??1?_????}; + wildcard bins mc0 = {13'b?_????_?0??_????}; + wildcard bins mc1 = {13'b?_????_?1??_????}; + wildcard bins sr0 = {13'b?_????_0???_????}; + wildcard bins sr1 = {13'b?_????_1???_????}; + wildcard bins ex0 = {13'b?_???0_????_????}; + wildcard bins ex1 = {13'b?_???1_????_????}; + wildcard bins us0 = {13'b?_??0?_????_????}; + wildcard bins us1 = {13'b?_??1?_????_????}; + wildcard bins se0 = {13'b?_?0??_????_????}; + wildcard bins se1 = {13'b?_?1??_????_????}; + wildcard bins u00 = {13'b?_0???_????_????}; + wildcard bins u01 = {13'b?_1???_????_????}; + wildcard bins u10 = {13'b0_????_????_????}; + wildcard ignore_bins u11 = {13'b1_????_????_????}; + } + + // coverage points for CS2. CS2 is only used for CSEAL/CUNSEAL, CSUB, CSEQX, CTESTSUBSET + + cp_cs2_tag: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_b.valid; + + cp_cs2_exp: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_b.exp { + bins bin0 = {0}; + bins bin1 = {[1:14]}; + bins bin2 = {24}; + } + + cp_cs2_otype: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_b.otype { + bins bin[] = {[0:7]}; // including reserved values for coverage + } + + cp_cs2_sealed: coverpoint ~(|g_cheri_ex.u_cheri_ex.rf_fullcap_b.otype) iff + (g_cheri_ex.u_cheri_ex.rf_fullcap_a.valid); + + cp_cs2_cor: coverpoint {g_cheri_ex.u_cheri_ex.rf_fullcap_b.base_cor, + g_cheri_ex.u_cheri_ex.rf_fullcap_b.top_cor} { + bins bin0 = {4'b0000}; + bins bin1 = {4'b0001}; + // bins bin2 = {4'b0011}; // base_cor = 0, top_cor = -1, impossible case + bins bin3 = {4'b1100}; + // bins bin4 = {4'b1101}; // impossible case + bins bin5 = {4'b1111}; + } + + cp_cs2_top: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_b.top { bins bin_all1 = {9'h1ff}; bins bin_all0 = {9'h0}; bins bin1 = {[9'h1:9'h1fe]}; } - cp_cs1_base: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_a.base iff - (g_cheri_ex.u_cheri_ex.rf_fullcap_a.valid) { + cp_cs2_base: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_b.base { bins bin_all1 = {9'h1ff}; bins bin_all0 = {9'h0}; bins bin1 = {[9'h1:9'h1fe]}; } - cp_cs1_perms: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_a.perms iff - (g_cheri_ex.u_cheri_ex.rf_fullcap_a.valid) { + cp_cs2_perms: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_b.perms { wildcard bins gl0 = {13'b?_????_????_???0}; wildcard bins gl1 = {13'b?_????_????_???1}; wildcard bins lg0 = {13'b?_????_????_??0?}; @@ -811,20 +1051,65 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( illegal_bins illegal = default; } - cp_cd_tag: coverpoint g_cheri_ex.u_cheri_ex.result_cap_o.valid iff (g_cheri_ex.u_cheri_ex.cheri_rf_we_o); + cp_cs2_perm_gl: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_b.perms[PERM_GL]; + cp_cs2_perm_se: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_b.perms[PERM_SE]; + cp_cs2_perm_us: coverpoint g_cheri_ex.u_cheri_ex.rf_fullcap_b.perms[PERM_US]; + + cp_cs2_address: coverpoint fcov_cs2_address_0cnt { + bins valid[] = {[0:32]}; + ignore_bins ignore = {[33:$]}; + } + + cp_cs2_seal_type: coverpoint g_cheri_ex.u_cheri_ex.rf_rdata_b { + bins bin_hi = {[16:$]}; + bins bin_mi[] = {[8:15]}; // seal otype 8:15 + bins bin_lo[] = {[0:7]}; // seal otype 0:7 + } + + + // coverage points for CD + cp_cd_tag: coverpoint g_cheri_ex.u_cheri_ex.result_cap_o.valid; + + cp_cd_exp: coverpoint g_cheri_ex.u_cheri_ex.result_cap_o.exp { + bins bin0 = {0}; + bins bin1 = {[1:14]}; + bins bin2 = {24}; + } + + cp_cd_otype: coverpoint g_cheri_ex.u_cheri_ex.result_cap_o.otype { + bins bin[] = {[0:7]}; // including reserved values for coverage + } cp_cd_cor: coverpoint {g_cheri_ex.u_cheri_ex.result_cap_o.base_cor, - g_cheri_ex.u_cheri_ex.result_cap_o.top_cor} iff - (g_cheri_ex.u_cheri_ex.cheri_rf_we_o && g_cheri_ex.u_cheri_ex.result_cap_o.valid) { + g_cheri_ex.u_cheri_ex.result_cap_o.top_cor} { bins bin0 = {4'b0000}; bins bin1 = {4'b0001}; // bins bin2 = {4'b0011}; bins bin3 = {4'b1100}; // bins bin4 = {4'b1101}; bins bin5 = {4'b1111}; - illegal_bins illegal = default; } + cp_cd_top: coverpoint g_cheri_ex.u_cheri_ex.result_cap_o.top { + bins bin_all1 = {9'h1ff}; + bins bin_all0 = {9'h0}; + bins bin1 = {[9'h1:9'h1fe]}; + } + + cp_cd_base: coverpoint g_cheri_ex.u_cheri_ex.result_cap_o.base { + bins bin_all1 = {9'h1ff}; + bins bin_all0 = {9'h0}; + bins bin1 = {[9'h1:9'h1fe]}; + } + + cp_cd_cperms: coverpoint g_cheri_ex.u_cheri_ex.result_cap_o.cperms; + + cp_cd_address: coverpoint fcov_cd_address_0cnt { + bins valid[] = {[0:32]}; + ignore_bins ignore = {[33:$]}; + } + + // addr/perm violations. this may cause either tag clearing or exception cp_cheri_vio: coverpoint {g_cheri_ex.u_cheri_ex.perm_vio_vec, g_cheri_ex.u_cheri_ex.addr_bound_vio} iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { @@ -846,12 +1131,12 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( // coverage points for exception conditions cp_cheri_wb_exception_causes: coverpoint g_cheri_ex.u_cheri_ex.cheri_err_cause iff (g_cheri_ex.u_cheri_ex.cheri_wb_err_d) { - bins bounds = {5'h1}; + // bins bounds = {5'h1}; // no bound violation reported by cheri_wb exception (coverted to fetch_err) bins tag = {5'h2}; bins seal = {5'h3}; bins perm_ex = {5'h11}; bins perm_sr = {5'h18}; - bins align = {5'h0}; + bins other = {5'h0}; // used for scr invalide address (treated as illegal instructions in RV32) illegal_bins illegal = default; } @@ -863,7 +1148,7 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( bins perm_load = {5'h12}; bins perm_store = {5'h13}; bins perm_sc = {5'h15}; - bins align = {5'h0}; + bins other = {5'h0}; // alignment error is reported as a different mcause/mtval code illegal_bins illegal = default; } @@ -884,6 +1169,11 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( wildcard illegal_bins illegal = {5'b1????} ; } + cp_scr_addr: coverpoint id_stage_i.rf_raddr_b_o[4:0] { + bins good[] = {[28:31]}; // ZTOPC goes to a separate interface + bins bad = {[0:23]}; + ignore_bins ignore = {[24:26]}; // debug SCR + } cp_scr_read_only: coverpoint g_cheri_ex.u_cheri_ex.csr_addr_o iff ( g_cheri_ex.u_cheri_ex.cheri_ex_dv_ext_i.fcov_scr_read_only) { @@ -901,8 +1191,6 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( // QQQ need to add mtcc/mepcc related coverage - cp_csr_mshwm: coverpoint g_cheri_ex.u_cheri_ex.csr_mshwm_set_o; - cp_cpu_lsu_req: coverpoint g_cheri_ex.u_cheri_ex.cheri_ex_dv_ext_i.fcov_cpu_lsu_acc; cp_cpu_lsu_err: coverpoint g_cheri_ex.u_cheri_ex.cheri_ex_dv_ext_i.fcov_cpu_lsu_err; @@ -927,13 +1215,58 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( cp_stkz_stall0: coverpoint g_cheri_ex.u_cheri_ex.cpu_stkz_stall0 iff (g_cheri_ex.u_cheri_ex.cheri_ex_dv_ext_i.fcov_cpu_lsu_req); - cp_sktz_err: coverpoint g_cheri_ex.u_cheri_ex.cpu_stkz_err; + cp_sktz_err: coverpoint g_cheri_ex.u_cheri_ex.cpu_stkz_err; // abort error (exception) cp_clsc_mem_err: coverpoint load_store_unit_i.lsu_dv_ext_i.fcov_clsc_mem_err { illegal_bins illegal = {7}; // rsvd value } - cp_cheri_fetch_vio: coverpoint if_stage_i.cheri_acc_vio iff (if_stage_i.fetch_valid); + + // + // clc: loaded memory cap coverage + // + cp_clc_clrperm: coverpoint load_store_unit_i.resp_lc_clrperm_q[3:0] iff + (~load_store_unit_i.data_we_q & load_store_unit_i.lsu_resp_valid_o) { + wildcard illegal_bins illegal = {4'b?1??}; // rsvd value + } + + cp_clc_mem_cap_perms: coverpoint load_store_unit_i.lsu_dv_ext_i.fcov_clc_mem_cap.perms iff + (~load_store_unit_i.data_we_q & load_store_unit_i.lsu_resp_valid_o) { + wildcard bins gl0 = {13'b?_????_????_???0}; + wildcard bins gl1 = {13'b?_????_????_???1}; + wildcard bins lg0 = {13'b?_????_????_??0?}; + wildcard bins lg1 = {13'b?_????_????_??1?}; + wildcard bins sd0 = {13'b?_????_????_?0??}; + wildcard bins sd1 = {13'b?_????_????_?1??}; + wildcard bins lm0 = {13'b?_????_????_0???}; + wildcard bins lm1 = {13'b?_????_????_1???}; + } + + cp_clc_mem_cap_valid: coverpoint load_store_unit_i.lsu_dv_ext_i.fcov_clc_mem_cap_valid iff + (~load_store_unit_i.data_we_q & load_store_unit_i.lsu_resp_valid_o); + + cp_clc_mem_cap_exp: coverpoint load_store_unit_i.lsu_dv_ext_i.fcov_clc_mem_cap.exp iff + (~load_store_unit_i.data_we_q & load_store_unit_i.lsu_resp_valid_o) { + bins bin0 = {0}; + bins bin1 = {[1:14]}; + bins bin2 = {24}; + } + + cp_clc_mem_cap_cor: coverpoint {load_store_unit_i.lsu_dv_ext_i.fcov_clc_mem_cap.top_cor, + load_store_unit_i.lsu_dv_ext_i.fcov_clc_mem_cap.base_cor} iff + (~load_store_unit_i.data_we_q & load_store_unit_i.lsu_resp_valid_o) { + bins bin0 = {4'b0000}; + bins bin1 = {4'b0001}; + // bins bin2 = {4'b0011}; // base_cor = 0, top_cor = -1, impossible case + bins bin3 = {4'b1100}; + // bins bin4 = {4'b1101}; // impossible case + bins bin5 = {4'b1111}; + } + + cp_cheri_fetch_tag_vio: coverpoint id_stage_i.instr_fetch_cheri_acc_vio_i iff + (id_stage_i.instr_valid_i); + cp_cheri_fetch_bound_vio: coverpoint id_stage_i.instr_fetch_cheri_bound_vio_i iff + (id_stage_i.instr_valid_i); cp_trvk_addr: coverpoint g_trvk_stage.cheri_trvk_stage_i.rf_trvk_addr_o[3:0] iff (g_trvk_stage.cheri_trvk_stage_i.rf_trvk_en_o); @@ -1003,6 +1336,72 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( cp_stkz_mem_err: coverpoint cheri_tbre_wrapper_i.g_stkz.cheri_stkz_i.stkz_err_o; + // mtcc and mepcc legalization + cp_mtcc_legalization_addr: coverpoint g_cheri_ex.u_cheri_ex.rf_rdata_a[1:0] iff + (cs_registers_i.mtvec_en_cheri) { + bins good = {2'h0}; + bins bad[] = {[2'h1: 2'h3]}; + } + + cp_mtcc_legalization_perm: coverpoint cs_registers_i.cs_reg_dv_ext_i.fcov_scr_wfcap.perms[PERM_EX] iff + (cs_registers_i.mtvec_en_cheri); + + cp_mtcc_legalization_sealed: coverpoint cs_registers_i.cs_reg_dv_ext_i.fcov_scr_wfcap.otype iff + (cs_registers_i.mtvec_en_cheri) { + bins good = {3'h0}; + bins bad = {[3'h1:3'h7]}; + } + + cp_mepcc_legalization_addr: coverpoint g_cheri_ex.u_cheri_ex.rf_rdata_a[0] iff + (cs_registers_i.mepc_en_cheri); + + cp_mepcc_legalization_perm: coverpoint cs_registers_i.cs_reg_dv_ext_i.fcov_scr_wfcap.perms[PERM_EX] iff + (cs_registers_i.mepc_en_cheri); + + cp_mepcc_legalization_sealed: coverpoint cs_registers_i.cs_reg_dv_ext_i.fcov_scr_wfcap.otype iff + (cs_registers_i.mepc_en_cheri) { + bins good = {3'h0}; + bins bad = {[3'h1:3'h7]}; + } + + // mret when PCC doesn't have PERM_SR + cp_illegal_mret_cheri: coverpoint id_stage_i.controller_i.mret_cheri_asr_err; + + + //pending fetch fault and interrupt + cp_pending_vio_intr: coverpoint {id_stage_i.controller_i.handle_irq,if_stage_i.if_stage_dv_ext_i.fcov_pending_fetch_bound_vio}; + + // + // Encoded coverage cases for address/bound checking + // + cp_cd_cs1_repr_cases: coverpoint fcov_cd_cs1_repr_cases { + bins case0 = {0}; + bins case1 = {1}; + bins case2 = {2}; + } + + cp_cd_pcc_repr_cases: coverpoint fcov_cd_pcc_repr_cases { + bins case0 = {0}; + bins case1 = {1}; + bins case2 = {2}; + } + + cp_cjal_target_bound_cases: coverpoint fcov_cjal_target_bound_cases; + cp_cjalr_target_bound_cases: coverpoint fcov_cjalr_target_bound_cases; + cp_branch_target_bound_cases: coverpoint fcov_branch_target_bound_cases; + + cp_clsc_bound_cases: coverpoint fcov_clsc_bound_cases; + cp_seal_bound_cases: coverpoint fcov_seal_bound_cases; + + cp_clsc_addr_lsb: coverpoint g_cheri_ex.u_cheri_ex.cheri_ls_chkaddr[2:0]; + + cp_setbounds_cases: coverpoint fcov_setbounds_cases; + cp_setboundsimm_cases: coverpoint fcov_setboundsimm_cases; + cp_rs1_bitsize: coverpoint fcov_rs1_bitsize; + + cp_mstatus_mie: coverpoint cs_registers_i.csr_mstatus_mie_o; + + /////////////////// // Cross coverage /////////////////// @@ -1017,31 +1416,34 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( debug_wfi_cross: cross cp_controller_fsm_sleep, cp_all_debug_req iff (id_stage_i.controller_i.controller_dv_ext_i.fcov_all_debug_req); -// priv_mode_instr_cross: cross cp_priv_mode_id, cp_id_instr_category { -// // No un-privileged CSRs on Ibex so no InstrCategoryCSRAccess in U mode (any CSR instruction -// // becomes InstrCategoryCSRIllegal). -// illegal_bins umode_csr_access_illegal = -// binsof(cp_id_instr_category) intersect {InstrCategoryCSRAccess} && -// binsof(cp_priv_mode_id) intersect {PRIV_LVL_U}; -// } - -// priv_mode_irq_cross: cross cp_priv_mode_id, cp_interrupt_taken, cs_registers_i.mstatus_q.mie { -// // No interrupt would be taken in M-mode when its mstatus.MIE = 0 unless it's an NMI -// illegal_bins mmode_mstatus_mie = -// binsof(cs_registers_i.mstatus_q.mie) intersect {1'b0} && -// binsof(cp_priv_mode_id) intersect {PRIV_LVL_M} with (cp_interrupt_taken >> 4 == 6'd0); -// } - -// priv_mode_exception_cross: cross cp_priv_mode_id, cp_ls_pmp_exception, cp_ls_error_exception { -// illegal_bins pmp_and_error_exeption_both = -// (binsof(cp_ls_pmp_exception) intersect {1'b1} && -// binsof(cp_ls_error_exception) intersect {1'b1}); -// } + priv_mode_instr_cross: cross cp_priv_mode_id, cp_id_instr_category { + // No un-privileged CSRs on Ibex so no InstrCategoryCSRAccess in U mode (any CSR instruction + // becomes InstrCategoryCSRIllegal). + illegal_bins umode_csr_access_illegal = + binsof(cp_id_instr_category) intersect {InstrCategoryCSRAccess} && + binsof(cp_priv_mode_id) intersect {PRIV_LVL_U}; + } + + priv_mode_irq_cross: cross cp_priv_mode_id, cp_interrupt_taken, cs_registers_i.mstatus_q.mie { + // No interrupt would be taken in M-mode when its mstatus.MIE = 0 unless it's an NMI + illegal_bins mmode_mstatus_mie = + binsof(cs_registers_i.mstatus_q.mie) intersect {1'b0} && + binsof(cp_priv_mode_id) intersect {PRIV_LVL_M} with (cp_interrupt_taken >> 4 == 6'd0); + } + + // priv_mode_exception_cross: cross cp_priv_mode_id, cp_ls_pmp_exception, cp_ls_error_exception { + priv_mode_exception_cross: cross cp_priv_mode_id, cp_ls_exception; + // { + // illegal_bins pmp_and_error_exeption_both = + // (binsof(cp_ls_pmp_exception) intersect {1'b1} && + // binsof(cp_ls_error_exception) intersect {1'b1}); + //} `define ListOfInstrRegOperands {InstrCategoryALU, InstrCategoryMul, \ InstrCategoryDiv, InstrCategoryBranch, \ - InstrCategoryJump, InstrCategoryLoad, \ - InstrCategoryStore, InstrCategoryCSRAccess, \ + InstrCategoryCJAL, InstrCategoryCJALR, \ + InstrCategoryLoad, InstrCategoryStore, \ + InstrCategoryCSRAccess, \ InstrCategoryCheriQuery, InstrCategoryCheriSCR, \ InstrCategoryCheriMod, \ InstrCategoryCheriAddr, InstrCategoryCheriBounds, \ @@ -1051,7 +1453,7 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( illegal_bins illegal = // Only Div, Mul, Branch and Jump instructions can see an instruction stall (!binsof(cp_id_instr_category) intersect {InstrCategoryDiv, InstrCategoryMul, - InstrCategoryBranch, InstrCategoryJump} && + InstrCategoryBranch, InstrCategoryCJAL, InstrCategoryCJALR} && binsof(cp_stall_type_id) intersect {IdStallTypeInstr}) || // Only ALU, Mul, Div, Branch, Jump, Load, Store and CSR Access can see a load hazard stall @@ -1100,7 +1502,7 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( illegal_bins illegal = // Only Div, Mul, Branch and Jump instructions can see an instruction stall (!binsof(cp_id_instr_category) intersect {InstrCategoryDiv, InstrCategoryMul, - InstrCategoryBranch, InstrCategoryJump} && + InstrCategoryBranch, InstrCategoryCJAL, InstrCategoryCJALR} && binsof(cp_stall_type_id) intersect {IdStallTypeInstr}) || // Only ALU, Mul, Div, Branch, Jump, Load, Store and CSR Access can see a load hazard stall @@ -1114,16 +1516,14 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( (!binsof(cp_id_instr_category) intersect {InstrCategoryLoad, InstrCategoryStore, InstrCategoryCheriCLC, InstrCategoryCheriCSC, InstrCategoryFetchError} && binsof(cp_stall_type_id) intersect {IdStallTypeMem}) with (cp_ls_exception == 2'h2 || cp_ls_exception == 2'h3); - // (cp_ls_pmp_exception == 1'b1 || cp_ls_cheri_exception == 1'b1); - // (cp_ls_pmp_exception == 1'b1 || cp_ls_error_exception == 1'b1); // QQQ // When pipeline has unstalled stall type will always be none illegal_bins unstalled_illegal = !binsof(cp_stall_type_id) intersect {IdStallTypeNone} with (instr_unstalled == 1'b1); } -// csr_read_only_priv_cross: cross cp_csr_read_only, cp_priv_mode_id; -// csr_write_priv_cross: cross cp_csr_write, cp_priv_mode_id; + csr_read_only_priv_cross: cross cp_csr_read_only, cp_priv_mode_id; + csr_write_priv_cross: cross cp_csr_write, cp_priv_mode_id; csr_read_only_debug_cross: cross cp_csr_read_only, cp_debug_mode { // Only care about specific debug CSRs @@ -1159,7 +1559,7 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( // // cs1/cs2/cd cross. QQQ need to further cross with instr types. - rs_rd_cross: cross cp_rs1_addr, cp_rs2_addr, cp_rd_addr; + rs_rd_cross: cross cp_rs1_regaddr, cp_rs2_regaddr, cp_rd_regaddr; // Cap manipulation and tag clearing // QQQ CAUIPCC/CJAL/CJALR needs to be treated separately since it's from PCC, not cs1 @@ -1193,9 +1593,9 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( // non-load/store CHERI exceptions cheri_jump_exception_cross: cross cp_cheri_wb_exception_causes, cp_cheri_instr_set { ignore_bins ignore0 = - (!binsof(cp_cheri_instr_set) intersect {CJAL, CJALR}) || - ((binsof(cp_cheri_instr_set) intersect {CJAL}) && (binsof(cp_cheri_wb_exception_causes) intersect {5'h2, 5'h3, 5'h11, 5'h18})) || - ((binsof(cp_cheri_instr_set) intersect {CJALR}) && (binsof(cp_cheri_wb_exception_causes) intersect {5'h18})); + (!binsof(cp_cheri_instr_set) intersect {CJALR}); // only CJALR generate exceptions now.. + illegal_bins illegal1 = + ((binsof(cp_cheri_instr_set) intersect {CJALR}) && (binsof(cp_cheri_wb_exception_causes) intersect {5'h0, 5'h1, 5'h18})); } cheri_scr_exception_cross: cross cp_cheri_wb_exception_causes, cp_cheri_instr_set { @@ -1205,14 +1605,10 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( } // LSU access cross QQQ + cheri_clc_clrperm_cross: cross cp_clc_clrperm, cp_clc_mem_cap_perms; // IF fetch violation - cheri_fetch_cross: cross cp_cheri_fetch_vio, cp_pcc_tag, cp_pcc_perm_ex, cp_pcc_otype { - illegal_bins illegal = (binsof(cp_cheri_fetch_vio) intersect {1'b0}) && - ((binsof(cp_pcc_tag) intersect {1'b0}) || - (binsof(cp_pcc_perm_ex) intersect {1'b0}) || - (binsof(cp_pcc_otype) intersect {[1:7]})); - } + cheri_fetch_cross: cross cp_cheri_fetch_tag_vio, cp_cheri_fetch_bound_vio; // trvk stall cheri_trvk_cross: cross cp_trvk_stall, cp_rd_a_hz, cp_rd_b_hz; @@ -1222,7 +1618,296 @@ interface core_ibex_fcov_if import ibex_pkg::*; import cheri_pkg::*; ( ignore_bins igore0 = (binsof(cp_stkz_sm) intersect {2'b10}); // ABORT state } + // Instruction/error/interrupt sequence coverage + // -- note instructions faulted at ID stage doesn't go to WB stage, so we need both cross items below + instr_error_sequence_cross0: cross id_instr_category, wb_instr_category, id_stage_i.controller_i.handle_irq, fcov_id_error, fcov_wb_err; + instr_error_sequence_cross1: cross id_instr_category, id_instr_category_q, fcov_id_exc_int, fcov_id_exc_int_q; + + + ///////////////////////////////////////////// + // CHERIoT instruction (cross) coverage + ///////////////////////////////////////////// + + // + // Capability address computation instructions + // + + // AUICGP + cp_instr_auicgp: coverpoint cheri_ops[CAUICGP] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_auicgp_cross: cross cp_cs1_tag, cp_cd_cs1_repr_cases, cp_cs1_sealed, cp_cs1_exp, cp_cheri_imm20, cp_instr_auicgp; + + // AUIPCC + cp_instr_auipcc: coverpoint cheri_ops[CAUIPCC] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_auipcc_cross: cross cp_cd_pcc_repr_cases, cp_pcc_exp, cp_cheri_imm20, cp_instr_auipcc; + + // CINCADDRIMM + cp_instr_cincaddrimm: coverpoint cheri_ops[CINC_ADDR_IMM] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_cincaddrimm_cross: cross cp_cs1_tag, cp_cd_cs1_repr_cases, cp_cs1_sealed, cp_cs1_exp, cp_cheri_imm12, cp_instr_cincaddrimm; + // CINCADDR + cp_instr_cincaddr: coverpoint cheri_ops[CINC_ADDR] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_cincaddr_cross: cross cp_cs1_tag, cp_cd_cs1_repr_cases, cp_cs1_sealed, cp_cs1_exp, cp_rs2_as_inc, cp_instr_cincaddr; + + // CSETADDR + cp_instr_csetaddr: coverpoint cheri_ops[CSET_ADDR] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_csetaddr_cross: cross cp_cs1_tag, cp_cd_cs1_repr_cases, cp_cs1_sealed, cp_cs1_exp, cp_instr_csetaddr; + + // + // Capbility mod/simple arithmetic instructions + // + + // CANDPERM + cp_instr_candperm: coverpoint cheri_ops[CAND_PERM] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_candperm_cross: cross cp_cs1_tag, cp_cs1_sealed, cp_cs1_perms, cp_rs2_perm_mask, cp_instr_csetaddr; + + // CCLEARTAG + cp_instr_ccleartag: coverpoint cheri_ops[CCLEAR_TAG] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_ccleartag_cross: cross cp_cs1_tag, cp_cs1_sealed, cp_instr_ccleartag; + + // CMOVE + cp_instr_cmove: coverpoint cheri_ops[CMOVE_CAP] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_cmove_cross: cross cp_cs1_tag, cp_cs1_sealed, cp_instr_cmove; + + // CSEQX + cp_instr_cseqx: coverpoint cheri_ops[CIS_EQUAL] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_cseqx_cross0: cross cp_cs1_tag, cp_cs1_otype, cp_cs2_tag, cp_cs2_otype, cp_instr_cseqx; + cheriot_instr_cseqx_cross1: cross cp_cs1_perms, cp_cs1_cor, cp_cs2_perms, cp_cs2_cor, cp_instr_cseqx; + cheriot_instr_cseqx_cross2: cross cp_cs1_top, cp_cs1_base, cp_cs2_top, cp_cs2_base, cp_instr_cseqx; + cheriot_instr_cseqx_cross3: cross cp_cs1_address, cp_cs2_address, cp_instr_cseqx; + + // CTESTSUBSET + cp_instr_ctestsubset: coverpoint cheri_ops[CIS_SUBSET] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_ctestsubset_cross0: cross cp_cs1_tag, cp_cs1_otype, cp_cs2_tag, cp_cs2_otype, cp_instr_ctestsubset; + cheriot_instr_ctestsubset_cross1: cross cp_cs1_perms, cp_cs1_cor, cp_cs2_perms, cp_cs2_cor, cp_instr_ctestsubset; + cheriot_instr_ctestsubset_cross2: cross cp_cs1_top, cp_cs1_base, cp_cs2_top, cp_cs2_base, cp_instr_ctestsubset; + + // CSUB + cp_instr_csub: coverpoint cheri_ops[CSUB_CAP] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_csub_cross: cross cp_cs1_tag, cp_cs1_address, cp_cs2_tag, cp_cs2_address, cp_instr_csub; + + // CSETHIGH + cp_instr_csethigh: coverpoint cheri_ops[CSET_HIGH] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_csethigh_cross0: cross cp_cd_tag, cp_cd_otype, cp_cd_cperms, cp_instr_csethigh; + cheriot_instr_csethigh_cross1: cross cp_cd_cor, cp_cd_exp, cp_cd_top, cp_cd_base, cp_cd_address, cp_instr_csethigh; + + // + // Capbility query (cget*) instructions + // + + // CGETADDR + cp_instr_cgetaddr: coverpoint cheri_ops[CGET_ADDR] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_cgetaddr_cross: cross cp_cs1_tag, cp_cs1_address, cp_instr_cgetaddr; + + // CGETBASE + cp_instr_cgetbase: coverpoint cheri_ops[CGET_BASE] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_cgetbase_cross: cross cp_cs1_tag, cp_cs1_base32, cp_instr_cgetbase; + + // CGETTOP + cp_instr_cgettop: coverpoint cheri_ops[CGET_TOP] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_cgettop_cross: cross cp_cs1_tag, cp_cs1_top33, cp_instr_cgettop; + + // CGETTYPE + cp_instr_cgettype: coverpoint cheri_ops[CGET_TYPE] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_cgettype_cross: cross cp_cs1_tag, cp_cs1_otype, cp_instr_cgettype; + + // CGETPERM + cp_instr_cgetperm: coverpoint cheri_ops[CGET_PERM] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_cgetperm_cross: cross cp_cs1_tag, cp_cs1_perms, cp_instr_cgetperm; + + // CGETTAG + cp_instr_cgettag: coverpoint cheri_ops[CGET_TAG] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_cgettag_cross: cross cp_cs1_tag, cp_instr_cgettag; + + // CGETLEN + cp_instr_cgetlen: coverpoint cheri_ops[CGET_LEN] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_cgetlen_cross: cross cp_cs1_tag, cp_cs1_top33, cp_cs1_base32, cp_cs1_exp, cp_instr_cgetlen; + + // CGETHIGH + cp_instr_cgethigh: coverpoint cheri_ops[CGET_HIGH] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_cgethigh_cross0: cross cp_cs1_tag, cp_cs1_otype, cp_cs1_perms, cp_instr_cgethigh; + cheriot_instr_cgethigh_cross1: cross cp_cs1_cor, cp_cs1_exp, cp_cs1_top, cp_cs1_base, cp_cs1_address, cp_instr_cgethigh; + + // + // Cspecialrw instruction + // + // + cp_instr_cspecialrw: coverpoint cheri_ops[CCSR_RW] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_cspecialrw_cross: cross cp_scr_addr, cp_rs1_regaddr, cp_rd_regaddr, cp_pcc_perm_asr, cp_instr_cspecialrw; + + + // + // Jump and branch instructions + // + + // CJAL + cp_instr_cjal: coverpoint cheri_ops[CJAL] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_cjal_cross: cross cp_rd_regaddr, cp_cjal_target_bound_cases, cp_cheri_imm20, cp_mstatus_mie, cp_instr_cjal; + + // CJALR + cp_instr_cjalr: coverpoint cheri_ops[CJALR] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + // -- imm12 is part of seal violation evaluation + cheriot_instr_cjalr_cross0: cross cp_cs1_tag, cp_cs1_otype, cp_rd_regaddr, cp_mstatus_mie, cp_cheri_imm12, cp_instr_cjalr; + cheriot_instr_cjalr_cross1: cross cp_cs1_tag, cp_cs1_perm_ex, cp_cjalr_target_bound_cases, cp_cheri_imm12, cp_instr_cjalr; + + // Branch + cp_instr_branch: coverpoint ((id_stage_i.instr_rdata_i[6:0] == OPCODE_BRANCH) & id_stage_i.branch_decision_i) iff + (id_stage_i.instr_executing) { + bins bin1 = {1'b1}; + } + + cheriot_instr_branch_cross: cross cp_branch_target_bound_cases, cp_instr_branch; + + // + // Load and store instructions + // + + // CLC + cp_instr_clc: coverpoint cheri_ops[CLOAD_CAP] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_clc_cross0: cross cp_cs1_tag, cp_cs1_sealed, cp_cs1_perms_load, cp_clc_mem_cap_perms, cp_instr_clc; + cheriot_instr_clc_cross1: cross cp_cs1_tag, cp_clsc_bound_cases, cp_cheri_imm12, cp_clsc_addr_lsb, cp_instr_clc; + + // CSC + cp_instr_csc: coverpoint cheri_ops[CSTORE_CAP] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_csc_cross0: cross cp_cs1_tag, cp_cs1_sealed, cp_cs1_perms_store, cp_cs2_perm_gl, cp_instr_csc; + cheriot_instr_csc_cross1: cross cp_cs1_tag, cp_clsc_bound_cases, cp_cheri_imm12, cp_clsc_addr_lsb, cp_instr_csc; + + // + // Seal/unseal instructions + // + + // CSeal + cp_instr_cseal: coverpoint cheri_ops[CSEAL] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_cseal_cross0: cross cp_cs1_tag, cp_cs1_sealed, cp_cs2_tag, cp_cs2_sealed, cp_instr_cseal; + cheriot_instr_cseal_cross1: cross cp_cs1_perm_ex, cp_cs2_tag, cp_cs2_perm_se, cp_cs2_seal_type, cp_seal_bound_cases, cp_instr_cseal; + + // CUnseal + cp_instr_cunseal: coverpoint cheri_ops[CUNSEAL] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_cunseal_cross0: cross cp_cs1_tag, cp_cs1_sealed, cp_cs1_perm_gl, + cp_cs2_tag, cp_cs2_sealed, cp_cs2_perm_us, cp_cs2_perm_gl, cp_instr_cunseal; + cheriot_instr_cunseal_cross1: cross cp_cs1_otype, cp_cs1_perm_ex, + cp_cs2_tag, cp_cs2_seal_type, cp_seal_bound_cases, cp_instr_cunseal; + // + // Set_bounds instructions + // + + // CSetbounds + cp_instr_csetbounds: coverpoint cheri_ops[CSET_BOUNDS] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_csetbounds_cross0: cross cp_cs1_tag, cp_cs1_sealed, cp_setbounds_cases, cp_cs1_base32, cp_cs1_top33, cp_cs1_exp, + cp_cd_tag, cp_instr_csetbounds; + + // CSetboundsexact + cp_instr_csetboundsexact: coverpoint cheri_ops[CSET_BOUNDS_EX] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_csetboundsexact_cross0: cross cp_cs1_tag, cp_cs1_sealed, cp_setbounds_cases, cp_cs1_base32, cp_cs1_top33, cp_cs1_exp, + cp_cd_tag, cp_instr_csetboundsexact; + + // CSetboundsimm + cp_instr_csetboundsimm: coverpoint cheri_ops[CSET_BOUNDS_IMM] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + cheriot_instr_csetboundsimm_cross0: cross cp_cs1_tag, cp_cs1_sealed, cp_setboundsimm_cases, cp_cs1_base32, cp_cs1_top33, cp_cs1_exp, + cp_cd_tag, cp_instr_csetboundsimm; + + // CRAM + cp_instr_cram: coverpoint cheri_ops[CRAM] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_cram_cross: cross cp_cs1_tag, cp_rs1_bitsize, cp_instr_cram; + + // CRRL + cp_instr_crrl: coverpoint cheri_ops[CRRL] iff (g_cheri_ex.u_cheri_ex.cheri_exec_id_i) { + bins bin1 = {1'b1}; + } + + cheriot_instr_crrl_cross: cross cp_cs1_tag, cp_rs1_bitsize, cp_instr_crrl; + endgroup bit en_uarch_cov; diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/data_mem_model.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/data_mem_model.sv index 81501eafb..67e2bc401 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/data_mem_model.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/data_mem_model.sv @@ -76,6 +76,9 @@ module data_mem_model import cheriot_dv_pkg::*; ( logic mmreg_sel, mmreg_cs; logic [7:0] mmreg_addr32; + logic uart_cs0, uart_cs1; + logic [7:0] uart_addr32; + logic [7:0] mem_flag; mem_obi_if #( @@ -191,7 +194,7 @@ module data_mem_model import cheriot_dv_pkg::*; ( always @(posedge clk, negedge rst_n) begin int i; if (~rst_n) begin - for (i=0; i<2**TSRAM_AW; i++) tsram[i] <= 32'h0; // initialize tsram to match sail + for (i=0; i<2**TSRAM_AW; i++) tsram[i] = 32'h0; // initialize tsram to match sail end else begin if (tsram_p0_cs && mem_we) begin // p0 read/write @@ -232,7 +235,6 @@ module data_mem_model import cheriot_dv_pkg::*; ( // 0x8380_0000: TBRE control // 0x8380_0080: scratch register 0,1 // 0x8380_0100: TB error_enable, Intr_ack - // 0x8380_0200: UART // // logic [64:0] tbre_ctrl_vec; @@ -316,6 +318,13 @@ module data_mem_model import cheriot_dv_pkg::*; ( end end + // + // 0x8380_0200: UART (also aliased to 0x1000_0000) + // + assign uart_addr32 = mem_addr32[7:0]; + assign uart_cs0 = mem_cs && (mem_addr32[29:22] == 8'h83) && (mem_addr32[21:8] == 14'h2000); + assign uart_cs1 = mem_cs && (mem_addr32[29:22] == 8'h10) && (mem_addr32[21:8] == 14'h0000); + // UART printout initial begin uart_stop_sim = 1'b0; @@ -323,7 +332,8 @@ module data_mem_model import cheriot_dv_pkg::*; ( while (1) begin @(posedge clk); - if (mmreg_cs && mem_we && (mmreg_addr32 == 'h80)) // 0x8380_0200 + if ((uart_cs0 && mem_we && (uart_addr32 == 'h80)) || + (uart_cs1 && mem_we && (uart_addr32 == 'h00))) if (mem_wdata[7]) uart_stop_sim = 1'b1; else diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/mem_monitor.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/mem_monitor.sv index 06731fe07..baf44531f 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/mem_monitor.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/mem_monitor.sv @@ -48,6 +48,16 @@ module mem_monitor import cheri_pkg::*; import cheriot_dv_pkg::*; # ( function automatic mem_2cmd_t lsu2mem_cmd (lsu_cmd_t lsu_cmd); mem_2cmd_t result; + + logic [65:0] cap_data66; + +`ifdef MEMCAPFMT1 + cap_data66 = reg2mem_fmt1(lsu_cmd.wcap, lsu_cmd.wdata); +`else + cap_data66[65:33] = reg2memcap_fmt0(lsu_cmd.wcap); + cap_data66[32:0] = {lsu_cmd.wcap.valid, lsu_cmd.wdata}; +`endif + result.valid = 2'b00; if (lsu_cmd.is_cap) begin @@ -58,13 +68,14 @@ module mem_monitor import cheri_pkg::*; import cheriot_dv_pkg::*; # ( result.cmd0.we = lsu_cmd.we; result.cmd0.be = 4'hf; result.cmd0.addr32 = lsu_cmd.addr[31:2] - {31'h0, 1'b1}; // we capture at lsu_req_done (after addr_incr) - result.cmd0.wdata = {lsu_cmd.wcap.valid, lsu_cmd.wdata}; + + result.cmd0.wdata = cap_data66[32:0]; result.cmd1.flag = 8'h0; result.cmd1.is_cap = 1'b1; result.cmd1.we = lsu_cmd.we; result.cmd1.be = 4'hf; result.cmd1.addr32 = lsu_cmd.addr[31:2]; - result.cmd1.wdata = reg2memcap_fmt0(lsu_cmd.wcap); // QQQ add fmt1 support later + result.cmd1.wdata = cap_data66[65:33]; end else if (lsu_cmd.rv32_type == 2'b00) begin // full word logic [63:0] tmp64; @@ -152,11 +163,28 @@ module mem_monitor import cheri_pkg::*; import cheriot_dv_pkg::*; # ( mem_cmd_t mem_resp0, mem_cmd_t mem_resp1); logic [7:0] result; reg_cap_t mcap; + logic [31:0] mdata; + logic [65:0] cap_wdata66; + +`ifdef MEMCAPFMT1 + cap_wdata66 = reg2mem_fmt1(req.wcap, req.wdata); + mcap = mem2regcap_fmt1(mem_resp1.rdata, mem_resp0.rdata, 0); + mdata = mem2regaddr_fmt1(mem_resp1.rdata, mem_resp0.rdata, mcap); +`else + cap_wdata66[65:33] = reg2memcap_fmt0(req.wcap); + cap_wdata66[32:0] = {req.wcap.valid, req.wdata}; + mcap = mem2regcap_fmt0(mem_resp1.rdata, mem_resp0.rdata, 0); + mdata = mem_resp0.rdata[31:0]; +`endif result = 0; if (resp.err != (mem_resp0.err || mem_resp1.err)) result |= 8'h1; + + if (resp.err) + return result; + if ((~mem_resp0.is_cap) || (mem_resp0.we != req.we) || (mem_resp0.be != 4'hf) || (mem_resp0.addr32[0]) || (mem_resp0.addr32 != (req.addr[31:2] - 1))) result |= (8'h1 << 1); @@ -164,15 +192,18 @@ module mem_monitor import cheri_pkg::*; import cheriot_dv_pkg::*; # ( (~mem_resp1.addr32[0]) || (mem_resp1.addr32 != (mem_resp0.addr32+1))) result |= (8'h1 << 2); - // QQQ let's just do fmt0 for now and add fmt1 later - if (req.we && ((mem_resp0.wdata[31:0] != req.wdata) || mem_resp1.wdata != reg2memcap_fmt0(req.wcap))) + // if (req.we && ((mem_resp0.wdata[31:0] != cap_wdata66[31:0]) || mem_resp1.wdata[31:0] != cap_wdata66[64:33])) + if (req.we && ((mem_resp0.wdata != cap_wdata66[32:0]) || mem_resp1.wdata != cap_wdata66[65:33])) result |= (8'h1 << 3); - if (~req.we && (mem_resp0.rdata[31:0] != resp.rdata)) + + // src == 0: cpu, src == 1: tbre (use raw mem data) + if (~req.we && ((srcID == 0) && (mdata != resp.rdata) || (srcID == 1) && (mem_resp0.rdata[31:0] != resp.rdata))) result |= (8'h1 << 4); + //$display("@%t, mdata = %x (%x, %x), resp.rdata = %x", $time, mdata, mem_resp1.rdata, mem_resp0.rdata,resp.rdata);//result |= (8'h1 << 4); - mcap = mem2regcap_fmt0(mem_resp1.rdata, mem_resp0.rdata, 0); + // note we are not fully checking tag/perms since they can be cleared based on auth_cap(cs1) if (~req.we && (srcID == 0) && (~resp.err) && // ignore read cap for TBRE and STKZ - ((mcap.valid != resp.rcap.valid) || (mcap.top_cor != resp.rcap.top_cor) || + ((~mcap.valid & resp.rcap.valid) || (mcap.top_cor != resp.rcap.top_cor) || (mcap.base_cor != resp.rcap.base_cor) || (mcap.exp != resp.rcap.exp) || (mcap.top != resp.rcap.top) || (mcap.base != resp.rcap.base) || (mcap.otype != resp.rcap.otype))) @@ -194,6 +225,9 @@ module mem_monitor import cheri_pkg::*; import cheriot_dv_pkg::*; # ( if (resp.err != (mem_resp0.err || mem_resp1.err)) result |= 8'h1; + if (resp.err) + return result; + if ((mem_resp0.is_cap) || (mem_resp0.we != req.we) || (mem_resp0.addr32 != (req.addr[31:2] - 1))) result |= (8'h1 << 1); if ((mem_resp1.is_cap) || (mem_resp1.we != req.we) || @@ -213,6 +247,9 @@ module mem_monitor import cheri_pkg::*; import cheriot_dv_pkg::*; # ( if (resp.err != mem_resp.err) result |= 8'h1; + if (resp.err) + return result; + if ((mem_resp.is_cap) || (mem_resp.we != req.we) || (mem_resp.addr32 != req.addr[31:2])) result |= (8'h1 << 1); @@ -305,7 +342,8 @@ module mem_monitor import cheri_pkg::*; import cheriot_dv_pkg::*; # ( dbg_mem_resp_head = mem_resp_queue[0]; check_result_mem = check_mem_cmd(mem_req_queue[0], mem_resp_queue[0]); - if (check_result_mem != 0) $error("TB> %s: check failed: mem_req vs mem_resp", mon_str); + assert (check_result_mem == 0) else $error("TB> %s: check failed: mem_req vs mem_resp, %x", + mon_str, check_result_mem); src_mem_resp_queue = {src_mem_resp_queue, mem_resp_queue[0]}; src_mem_resp_cnt += 1; @@ -336,7 +374,8 @@ module mem_monitor import cheri_pkg::*; import cheriot_dv_pkg::*; # ( if (lsu_req_queue[0].is_cap && (src_mem_resp_queue.size() >= 2)) begin check_result_src = check_src_req_cap(lsu_req_queue[0], lsu_resp_queue[0], src_mem_resp_queue[0], src_mem_resp_queue[1]); - if (check_result_src != 0) $error("TB> %s: check failed: src req vs resp 1", mon_str); + assert (check_result_src == 0) else $error("TB> %s: check failed: src req vs resp 1, %x", + mon_str, check_result_src); lsu_req_queue = lsu_req_queue[1:$]; lsu_resp_queue = lsu_resp_queue[1:$]; @@ -345,14 +384,16 @@ module mem_monitor import cheri_pkg::*; import cheriot_dv_pkg::*; # ( (src_mem_resp_queue.size() >= 2)) begin check_result_src = check_src_req_rv32_unaligned(lsu_req_queue[0], lsu_resp_queue[0], src_mem_resp_queue[0], src_mem_resp_queue[1]); - if (check_result_src != 0) $error("TB> %s: check failed: src req vs resp 2", mon_str); + assert (check_result_src == 0) else $error("TB> %s: check failed: src req vs resp 2, %x", + mon_str, check_result_src); lsu_req_queue = lsu_req_queue[1:$]; lsu_resp_queue = lsu_resp_queue[1:$]; src_mem_resp_queue = src_mem_resp_queue[2:$]; end else if (src_mem_resp_queue.size() > 0) begin check_result_src = check_src_req_rv32(lsu_req_queue[0], lsu_resp_queue[0], src_mem_resp_queue[0]); - if (check_result_src != 0) $error("TB> %s: check failed: src_req vs resp 3", mon_str); + assert (check_result_src == 0) else $error("TB> %s: check failed: src_req vs resp 3, %x", + mon_str, check_result_src); lsu_req_queue = lsu_req_queue[1:$]; lsu_resp_queue = lsu_resp_queue[1:$]; @@ -382,10 +423,10 @@ module mem_monitor import cheri_pkg::*; import cheriot_dv_pkg::*; # ( $display("TB> %s: pending terms in queues: %d, %d, %d, %d, %d", mon_str, dbg_mem_req_size, dbg_mem_resp_size, dbg_src_mem_resp_size, dbg_lsu_req_size, dbg_lsu_resp_size); - if ((lsu_req_cnt != lsu_resp_cnt) || (mem_req_cnt != src_mem_resp_cnt)) + assert (!((lsu_req_cnt != lsu_resp_cnt) || (mem_req_cnt != src_mem_resp_cnt))) else $error("TB> %s: ERROR! memory transactions count mismatch", mon_str); - if ((dbg_mem_req_size != 0) || (dbg_mem_resp_size != 0) || (dbg_src_mem_resp_size != 0) || - (dbg_lsu_req_size != 0) || (dbg_lsu_resp_size != 0)) + assert (!((dbg_mem_req_size != 0) || (dbg_mem_resp_size != 0) || (dbg_src_mem_resp_size != 0) || + (dbg_lsu_req_size != 0) || (dbg_lsu_resp_size != 0))) else $error("TB> %s: ERROR! Unresolved transactions found", mon_str); end end diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/mem_obi_if.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/mem_obi_if.sv index dba14f77b..e099da3ff 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/mem_obi_if.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/mem_obi_if.sv @@ -103,7 +103,6 @@ module mem_obi_if import cheriot_dv_pkg::*; #( cmd_wr_ptr_ext <= 0; resp_valid <= 1'b0; resp_idle <= 1'b1; - resp_waits <= 0; resp_cntr <= 0; cmd_fifo_rd <= 1'b0; end else begin @@ -156,6 +155,7 @@ module mem_obi_if import cheriot_dv_pkg::*; #( data_rvalid <= 1'b0; data_err <= 1'b0; cmd_rd_ptr_ext <= 0; + resp_waits <= 0; end else begin data_rvalid <= resp_valid; data_err <= resp_valid & mem_err; diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/module_dv_ext.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/module_dv_ext.sv index 1086b9e9a..9cf75ffbb 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/module_dv_ext.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/module_dv_ext.sv @@ -17,6 +17,7 @@ module bindfiles; bind cheri_tbre_wrapper cheri_tbre_wrapper_dv_ext tbre_wrapper_dv_ext_i (.*); bind cheri_tbre cheri_tbre_dv_ext tbre_dv_ext_i (.*); bind cheri_stkz cheri_stkz_dv_ext stkz_dv_ext_i (.*); + bind ibex_cs_registers ibex_cs_registers_dv_ext cs_reg_dv_ext_i (.*); bind ibex_core ibex_core_dv_ext ibex_core_dv_ext_i (.*); bind ibex_top ibex_top_dv_ext ibex_top_dv_ext_i (.*); endmodule @@ -26,16 +27,23 @@ endmodule // ibex_if_stage //////////////////////////////////////////////////////////////// -module ibex_if_stage_dv_ext ( +module ibex_if_stage_dv_ext import cheri_pkg::*; import cheriot_dv_pkg::*; ( input logic clk_i, - input logic rst_ni + input logic rst_ni, + input logic if_instr_valid, + input logic [31:0] pc_if_o, + input pcc_cap_t pcc_cap_i ); + logic fcov_pending_fetch_bound_vio; + `DV_FCOV_SIGNAL_GEN_IF(logic [1:0], dummy_instr_type, gen_dummy_instr.dummy_instr_i.lfsr_data.instr_type, if_stage_i.DummyInstructions) `DV_FCOV_SIGNAL_GEN_IF(logic, insert_dummy_instr, gen_dummy_instr.insert_dummy_instr, if_stage_i.DummyInstructions) + assign fcov_pending_fetch_bound_vio = ~if_instr_valid & ~is_representable(pcc2fullcap(pcc_cap_i), pc_if_o); + endmodule //////////////////////////////////////////////////////////////// @@ -50,7 +58,8 @@ module ibex_id_stage_dv_ext ( input logic [4:0] rf_raddr_a_o, input logic rf_ren_b, input logic [4:0] rf_raddr_b_o, - input logic cheri_rf_we, + input logic rf_we_id_o, + input logic rf_we_dec, input logic [4:0] rf_waddr_id_o, input logic cheri_exec_id_o, input logic instr_executing @@ -60,9 +69,12 @@ module ibex_id_stage_dv_ext ( assign fcov_trvk_stall_cause[0] = rf_ren_a && ~rf_reg_rdy_i[rf_raddr_a_o]; assign fcov_trvk_stall_cause[1] = rf_ren_b && ~rf_reg_rdy_i[rf_raddr_b_o]; - assign fcov_trvk_stall_cause[2] = cheri_rf_we && ~rf_reg_rdy_i[rf_waddr_id_o]; + assign fcov_trvk_stall_cause[2] = rf_we_id_o && ~rf_reg_rdy_i[rf_waddr_id_o]; `ASSERT(IbexExecInclCheri, (cheri_exec_id_o |-> instr_executing)) + + // rf_we_dec is now a superset of cheri_rf_we_dec + `ASSERT(IbexCheriRfWe, (decoder_i.cheri_rf_we_dec |-> rf_we_dec)) @@ -149,9 +161,13 @@ module ibex_lsu_dv_ext import ibex_pkg::*; import cheri_pkg::*; ( input logic resp_is_tbre_q, input cap_rx_fsm_t cap_rx_fsm_q, input logic data_we_q, - input logic cap_lsw_err_q - + input logic cap_lsw_err_q, + input logic [32:0] data_rdata_i, + input logic [32:0] cap_lsw_q ); + + localparam MemCapFmt = load_store_unit_i.MemCapFmt; + // Set when awaiting the response for the second half of a misaligned access logic fcov_mis_2_en_d, fcov_mis_2_en_q; @@ -197,33 +213,43 @@ module ibex_lsu_dv_ext import ibex_pkg::*; import cheri_pkg::*; ( `DV_FCOV_SIGNAL(logic, ls_mis_pmp_err_2, (ls_fsm_cs inside {WAIT_RVALID_MIS, WAIT_RVALID_MIS_GNTS_DONE}) && data_pmp_err_i) - logic [1:0] fcov_ls_exception_type; - assign fcov_ls_exception_type = fcov_ls_error_exception ? 1 : fcov_ls_pmp_exception ? 2 : - fcov_ls_cheri_exception ? 3 : 0; - - logic [2:0] fcov_clsc_mem_err; - always_comb begin - fcov_clsc_mem_err = 3'h0; // no error; - if ((cap_rx_fsm_q == CRX_WAIT_RESP2) && data_rvalid_i) begin - if (data_err_i & ~data_we_q & cap_lsw_err_q) - fcov_clsc_mem_err = 3'h1; // clc both word error - else if (data_err_i & ~data_we_q & ~cap_lsw_err_q) - fcov_clsc_mem_err = 3'h2; // clc word 1 error only - else if (~data_err_i & ~data_we_q & ~cap_lsw_err_q) - fcov_clsc_mem_err = 3'h3; // clc word 0 error only - else if (data_err_i & data_we_q & cap_lsw_err_q) - fcov_clsc_mem_err = 3'h4; // csc both word error - else if (data_err_i & data_we_q & ~cap_lsw_err_q) - fcov_clsc_mem_err = 3'h5; // csc word 1 error only - else if (~data_err_i & data_we_q & cap_lsw_err_q) - fcov_clsc_mem_err = 3'h6; // csc word 0 error only - else - fcov_clsc_mem_err = 3'h0; // no error; - end - end - + logic [1:0] fcov_ls_exception_type; + assign fcov_ls_exception_type = fcov_ls_error_exception ? 1 : fcov_ls_pmp_exception ? 2 : + fcov_ls_cheri_exception ? 3 : 0; + logic [2:0] fcov_clsc_mem_err; + always_comb begin + fcov_clsc_mem_err = 3'h0; // no error; + if ((cap_rx_fsm_q == CRX_WAIT_RESP2) && data_rvalid_i) begin + if (data_err_i & ~data_we_q & cap_lsw_err_q) + fcov_clsc_mem_err = 3'h1; // clc both word error + else if (data_err_i & ~data_we_q & ~cap_lsw_err_q) + fcov_clsc_mem_err = 3'h2; // clc word 1 error only + else if (~data_err_i & ~data_we_q & ~cap_lsw_err_q) + fcov_clsc_mem_err = 3'h3; // clc word 0 error only + else if (data_err_i & data_we_q & cap_lsw_err_q) + fcov_clsc_mem_err = 3'h4; // csc both word error + else if (data_err_i & data_we_q & ~cap_lsw_err_q) + fcov_clsc_mem_err = 3'h5; // csc word 1 error only + else if (~data_err_i & data_we_q & cap_lsw_err_q) + fcov_clsc_mem_err = 3'h6; // csc word 0 error only + else + fcov_clsc_mem_err = 3'h0; // no error; + end + end + + full_cap_t fcov_clc_mem_cap; + logic [12:0] mem_raw_perms; + logic [1:0] fcov_clc_mem_cap_valid; + + //if (MemCapFmt) begin + assign fcov_clc_mem_cap = mem2fullcap_fmt0_raw(data_rdata_i, cap_lsw_q); + //end else begin + //assign mem_raw_cap = mem2regcap_fmt1(data_rdata_i, cap_lsw_q, 4'h0); + //end + assign fcov_clc_mem_cap_valid = {cap_lsw_q[32], data_rdata_i[32]}; + //////////////// // Assertions // @@ -662,6 +688,27 @@ module cheri_stkz_dv_ext import ibex_pkg::*; import cheri_pkg::*; ( endmodule +//////////////////////////////////////////////////////////////// +// ibex_if_stage +//////////////////////////////////////////////////////////////// + +module ibex_cs_registers_dv_ext import ibex_pkg::*; import cheri_pkg::*; ( + input logic clk_i, + input logic rst_ni, + input logic [31:0] cheri_csr_wdata_i, + input reg_cap_t cheri_csr_wcap_i, + input pcc_cap_t pcc_cap_o + ); + + full_cap_t fcov_scr_wfcap; + + assign fcov_scr_wfcap = reg2fullcap(cheri_csr_wcap_i, cheri_csr_wdata_i); + + `ASSERT(PccOtypeInvalid, (pcc_cap_o.valid |-> (pcc_cap_o.otype==0))) + `ASSERT(PccPermEx0, (pcc_cap_o.valid |-> pcc_cap_o.perms[PERM_EX])) + +endmodule + //////////////////////////////////////////////////////////////// // ibex_core //////////////////////////////////////////////////////////////// diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/tb_cheriot_top.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/tb_cheriot_top.sv index 973bf1d45..5e45f9608 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/tb_cheriot_top.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/tb_cheriot_top.sv @@ -337,6 +337,7 @@ module tb_cheriot_top ( i = $value$plusargs("STKZ_INTVL=%d", cfg_stkz_intvl); if (i == 1) stkz_intvl = cfg_stkz_intvl[3:0]; + $display("TB> CFG.memCapFmt=%1d", dut.u_ibex_top.MemCapFmt); $display("TB> INSTR_GNTW = %d, INSTR_RESPW = %d, DATA_GNTW = %d, DATA_RESPW = %d", instr_gnt_wmax, instr_resp_wmax, data_gnt_wmax, data_resp_wmax); $display("TB> INSTR_ERR_RATE = %d, DATA_ERR_RATE = %d, INTR_INTVL = %d, CAP_ERR_RATE = %d", @@ -352,8 +353,8 @@ module tb_cheriot_top ( data_err_enable = err_enable_vec[1]; intr_enable = err_enable_vec[2]; cap_err_enable = err_enable_vec[3]; - tbre_bg_enable = |err_enable_vec; - stkz_bg_enable = |err_enable_vec; + tbre_bg_enable = 1'b1; // embedded firmware doesn't need to be aware of bg traffic + stkz_bg_enable = 1'b1; // if it's not using tbre/stkz in the foreground end // end of simulation @@ -397,7 +398,7 @@ module tb_cheriot_top ( .instr_err (instr_err ) ); - assign ignore_stkz = stkz_bg_enable & (stkz_intvl != 0); + assign ignore_stkz = (stkz_intvl != 0); data_mem_model u_data_mem ( .clk (clk_i ), diff --git a/vendor/lowrisc_ibex/dv/cheriot/tb/tbre_bg_gen.sv b/vendor/lowrisc_ibex/dv/cheriot/tb/tbre_bg_gen.sv index 2b4ea5f70..24a4220d5 100644 --- a/vendor/lowrisc_ibex/dv/cheriot/tb/tbre_bg_gen.sv +++ b/vendor/lowrisc_ibex/dv/cheriot/tb/tbre_bg_gen.sv @@ -98,13 +98,14 @@ module tbre_bg_gen ( tsmap_offset = tsmap_offset[7:3]; if ((u_tb_top.u_data_mem.tsram[tsmap_addr][tsmap_offset] && dw0[32]) || (~u_tb_top.u_data_mem.tsram[tsmap_addr][tsmap_offset] && (dw0[32]!=dw1[32]))) - $error("TB> tbre_bg_gen: check_result tag ERROR, %x, %x/%x, %x, %x, %x", - i, dw0, dw1, tsmap_addr, tsmap_offset, u_tb_top.u_data_mem.tsram[tsmap_addr]); + $error("TB> tbre_bg_gen: check_result tag ERROR, %x, %x/%x, %x, %x, %x @ %x", + i, dw0, dw1, tsmap_addr, tsmap_offset, u_tb_top.u_data_mem.tsram[tsmap_addr], + base+2*i); // check dw1 to make sure we didn't overwrite the wrong location if ((dw1[32] != dw1[31]) || (dw1[30:22] != 9'h15a) || (dw1[21:18] != 0) || (dw1[17:9] != dw1[8:0]) || (dw0[8:0] != dw1[8:0])) - $error("TB> tbre_bg_gen: check_result dw1 ERROR, %x, %x", dw0, dw1); + $error("TB> tbre_bg_gen: check_result dw1 ERROR, %x, %x @%x", dw0, dw1, base+2*i); end end endtask @@ -219,6 +220,7 @@ module tbre_bg_gen ( //$display("stkz start = %8x, end = %8x", stkz_start_addr, stkz_end_addr); ztop_wfcap.valid = 1'b1; + ztop_wfcap.perms = 1'b1 << PERM_SD; ztop_wfcap.top33 = stkz_start_addr; ztop_wfcap.base32 = stkz_end_addr; diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/Makefile b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/Makefile new file mode 100755 index 000000000..5f90912de --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/Makefile @@ -0,0 +1,139 @@ +# Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) +# +# 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. +# +# Original Author: Shay Gal-on + +# Make sure the default target is to simply build and run the benchmark. +RSTAMP = v1.0 + +.PHONY: run score +run: $(OUTFILE) rerun score + +score: + @echo "Check run1.log and run2.log for results." + @echo "See README.md for run and reporting rules." + +ifndef PORT_DIR +# Ports for a couple of common self hosted platforms +UNAME=$(shell if command -v uname 2> /dev/null; then uname ; fi) +ifneq (,$(findstring CYGWIN,$(UNAME))) +PORT_DIR=cygwin +endif +ifneq (,$(findstring Linux,$(UNAME))) +MACHINE=$(shell uname -m) +ifneq (,$(findstring 64,$(MACHINE))) +PORT_DIR=linux64 +else +PORT_DIR=linux +endif +endif +endif +ifndef PORT_DIR +$(error PLEASE define PORT_DIR! (e.g. make PORT_DIR=simple)) +endif +vpath %.c $(PORT_DIR) +vpath %.h $(PORT_DIR) +vpath %.mak $(PORT_DIR) +include $(PORT_DIR)/core_portme.mak + +ifndef ITERATIONS +ITERATIONS=0 +endif +ifdef REBUILD +FORCE_REBUILD=force_rebuild +endif + +CFLAGS += -DITERATIONS=$(ITERATIONS) + +CORE_FILES = core_list_join core_main core_matrix core_state core_util +ORIG_SRCS = $(addsuffix .c,$(CORE_FILES)) +SRCS = $(ORIG_SRCS) $(PORT_SRCS) +OBJS = $(addprefix $(OPATH),$(addsuffix $(OEXT),$(CORE_FILES)) $(PORT_OBJS)) +OUTNAME = coremark$(EXE) +OUTFILE = $(OPATH)$(OUTNAME) +LOUTCMD = $(OFLAG) $(OUTFILE) $(LFLAGS_END) +OUTCMD = $(OUTFLAG) $(OUTFILE) $(LFLAGS_END) + +HEADERS = coremark.h +CHECK_FILES = $(ORIG_SRCS) $(HEADERS) + +$(OPATH): + $(MKDIR) $(OPATH) + +.PHONY: compile link +ifdef SEPARATE_COMPILE +$(OPATH)$(PORT_DIR): + $(MKDIR) $(OPATH)$(PORT_DIR) + +compile: $(OPATH) $(OPATH)$(PORT_DIR) $(OBJS) $(HEADERS) +link: compile + $(LD) $(LFLAGS) $(XLFLAGS) $(OBJS) $(LOUTCMD) + +else + +compile: $(OPATH) $(SRCS) $(HEADERS) + $(CC) $(CFLAGS) $(XCFLAGS) $(SRCS) $(OUTCMD) +link: compile + @echo "Link performed along with compile" + +endif + +$(OUTFILE): $(SRCS) $(HEADERS) Makefile core_portme.mak $(FORCE_REBUILD) + $(MAKE) port_prebuild + $(MAKE) link + $(MAKE) port_postbuild + +.PHONY: rerun +rerun: + $(MAKE) XCFLAGS="$(XCFLAGS) -DPERFORMANCE_RUN=1" load run1.log + $(MAKE) XCFLAGS="$(XCFLAGS) -DVALIDATION_RUN=1" load run2.log + +PARAM1=$(PORT_PARAMS) 0x0 0x0 0x66 $(ITERATIONS) +PARAM2=$(PORT_PARAMS) 0x3415 0x3415 0x66 $(ITERATIONS) +PARAM3=$(PORT_PARAMS) 8 8 8 $(ITERATIONS) + +run1.log-PARAM=$(PARAM1) 7 1 2000 +run2.log-PARAM=$(PARAM2) 7 1 2000 +run3.log-PARAM=$(PARAM3) 7 1 1200 + +run1.log run2.log run3.log: load + $(MAKE) port_prerun + $(RUN) $(OUTFILE) $($(@)-PARAM) > $(OPATH)$@ + $(MAKE) port_postrun + +.PHONY: gen_pgo_data +gen_pgo_data: run3.log + +.PHONY: load +load: $(OUTFILE) + $(MAKE) port_preload + $(LOAD) $(OUTFILE) + $(MAKE) port_postload + +.PHONY: clean +clean: + rm -f $(OUTFILE) $(OPATH)*.log *.info $(OPATH)index.html $(PORT_CLEAN) + +.PHONY: force_rebuild +force_rebuild: + echo "Forcing Rebuild" + +.PHONY: check +check: + md5sum -c coremark.md5 + +ifdef ETC +# Targets related to testing and releasing CoreMark. Not part of the general release! +include Makefile.internal +endif diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/README b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/README new file mode 100755 index 000000000..d5acf500e --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/README @@ -0,0 +1,26 @@ +Compile flags used (riscv32 GCC): + + PULP_CFLAGS_BASE="-static -mcmodel=medany -march=rv32imc -mabi=ilp32 -nostartfiles -fvisibility=hidden -ffast-math -fno-common -fno-builtin-printf -std=gnu99 -nostdlib -ffreestanding" + ADDON_CFLAGS="-DNDEBUG -I$SRC -I$SRC/riscv32" + RUN_CFLAGS="-DPERFORMACE_RUN=1 -DITERATIONS=1 -DCLOCKS_PER_SEC=10000000" + CFLAGS="$PULP_CFLAGS_BASE $ADDON_CFLAGS $RUN_CFLAGS -O2 -T$LD_FILE" + +linker load script: + OUTPUT_ARCH( "riscv" ) + /*ENTRY(_start) */ + + SECTIONS + { + . = 0x20000000; + .text.vec : {vector.o(.text)} + . = 0x20000080; + .text.start : {startup.o(.text)} + . = ALIGN(0x100); + .tohost : { *(.tohost) } + . = ALIGN(0x0100); + .text : { *(.text) } + . = ALIGN(0x0100); + .rodata : { *(.rodata*) } + .data : { *(.data) } + .bss : { *(.bss) } + _end = .; diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/core_portme.c b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/core_portme.c new file mode 100755 index 000000000..336468191 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/core_portme.c @@ -0,0 +1,128 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ +#include "coremark.h" +#include "core_portme.h" + +#if VALIDATION_RUN + volatile ee_s32 seed1_volatile=0x3415; + volatile ee_s32 seed2_volatile=0x3415; + volatile ee_s32 seed3_volatile=0x66; +#endif +#if PERFORMANCE_RUN + volatile ee_s32 seed1_volatile=0x0; + volatile ee_s32 seed2_volatile=0x0; + volatile ee_s32 seed3_volatile=0x66; +#endif +#if PROFILE_RUN + volatile ee_s32 seed1_volatile=0x8; + volatile ee_s32 seed2_volatile=0x8; + volatile ee_s32 seed3_volatile=0x8; +#endif + volatile ee_s32 seed4_volatile=ITERATIONS; + volatile ee_s32 seed5_volatile=0; +/* Porting : Timing functions + How to capture time and convert to seconds must be ported to whatever is supported by the platform. + e.g. Read value from on board RTC, read value from cpu clock cycles performance counter etc. + Sample implementation for standard time.h and windows.h definitions included. +*/ +CORETIMETYPE barebones_clock() { + #error "You must implement a method to measure time in barebones_clock()! This function should return current time.\n" +} +/* Define : TIMER_RES_DIVIDER + Divider to trade off timer resolution and total time that can be measured. + + Use lower values to increase resolution, but make sure that overflow does not occur. + If there are issues with the return value overflowing, increase this value. + */ +#define GETMYTIME(_t) (*_t=barebones_clock()) +#define MYTIMEDIFF(fin,ini) ((fin)-(ini)) +#define TIMER_RES_DIVIDER 1 +#define SAMPLE_TIME_IMPLEMENTATION 1 +#define EE_TICKS_PER_SEC (CLOCKS_PER_SEC / TIMER_RES_DIVIDER) + +/** Define Host specific (POSIX), or target specific global time variables. */ +static CORETIMETYPE start_time_val, stop_time_val; + +/* Function : start_time + This function will be called right before starting the timed portion of the benchmark. + + Implementation may be capturing a system timer (as implemented in the example code) + or zeroing some system parameters - e.g. setting the cpu clocks cycles to 0. +*/ +void start_time(void) { + GETMYTIME(&start_time_val ); +} +/* Function : stop_time + This function will be called right after ending the timed portion of the benchmark. + + Implementation may be capturing a system timer (as implemented in the example code) + or other system parameters - e.g. reading the current value of cpu cycles counter. +*/ +void stop_time(void) { + GETMYTIME(&stop_time_val ); +} +/* Function : get_time + Return an abstract "ticks" number that signifies time on the system. + + Actual value returned may be cpu cycles, milliseconds or any other value, + as long as it can be converted to seconds by . + This methodology is taken to accomodate any hardware or simulated platform. + The sample implementation returns millisecs by default, + and the resolution is controlled by +*/ +CORE_TICKS get_time(void) { + CORE_TICKS elapsed=(CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val)); + return elapsed; +} +/* Function : time_in_secs + Convert the value returned by get_time to seconds. + + The type is used to accomodate systems with no support for floating point. + Default implementation implemented by the EE_TICKS_PER_SEC macro above. +*/ +secs_ret time_in_secs(CORE_TICKS ticks) { + secs_ret retval=((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC; + return retval; +} + +ee_u32 default_num_contexts=1; + +/* Function : portable_init + Target specific initialization code + Test for some common mistakes. +*/ +void portable_init(core_portable *p, int *argc, char *argv[]) +{ + #error "Call board initialization routines in portable init (if needed), in particular initialize UART!\n" + if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) { + ee_printf("ERROR! Please define ee_ptr_int to a type that holds a pointer!\n"); + } + if (sizeof(ee_u32) != 4) { + ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n"); + } + p->portable_id=1; +} +/* Function : portable_fini + Target specific final code +*/ +void portable_fini(core_portable *p) +{ + p->portable_id=0; +} + + diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/core_portme.h b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/core_portme.h new file mode 100755 index 000000000..23a155888 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/core_portme.h @@ -0,0 +1,199 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ +/* Topic : Description + This file contains configuration constants required to execute on different platforms +*/ +#ifndef CORE_PORTME_H +#define CORE_PORTME_H +/************************/ +/* Data types and settings */ +/************************/ +/* Configuration : HAS_FLOAT + Define to 1 if the platform supports floating point. +*/ +#ifndef HAS_FLOAT +#define HAS_FLOAT 1 +#endif +/* Configuration : HAS_TIME_H + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef HAS_TIME_H +#define HAS_TIME_H 1 +#endif +/* Configuration : USE_CLOCK + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef USE_CLOCK +#define USE_CLOCK 1 +#endif +/* Configuration : HAS_STDIO + Define to 1 if the platform has stdio.h. +*/ +#ifndef HAS_STDIO +#define HAS_STDIO 0 +#endif +/* Configuration : HAS_PRINTF + Define to 1 if the platform has stdio.h and implements the printf function. +*/ +#ifndef HAS_PRINTF +#define HAS_PRINTF 0 +#endif + + +/* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION + Initialize these strings per platform +*/ +#ifndef COMPILER_VERSION + #ifdef __GNUC__ + #define COMPILER_VERSION "GCC"__VERSION__ + #else + #define COMPILER_VERSION "Please put compiler version here (e.g. gcc 4.1)" + #endif +#endif +#ifndef COMPILER_FLAGS + #define COMPILER_FLAGS FLAGS_STR /* "Please put compiler flags here (e.g. -o3)" */ +#endif +#ifndef MEM_LOCATION + #define MEM_LOCATION "STACK" +#endif + +/* Data Types : + To avoid compiler issues, define the data types that need ot be used for 8b, 16b and 32b in . + + *Imprtant* : + ee_ptr_int needs to be the data type used to hold pointers, otherwise coremark may fail!!! +*/ +typedef signed short ee_s16; +typedef unsigned short ee_u16; +typedef signed int ee_s32; +typedef double ee_f32; +typedef unsigned char ee_u8; +typedef unsigned int ee_u32; +typedef ee_u32 ee_ptr_int; +typedef size_t ee_size_t; +#define NULL ((void *)0) +/* align_mem : + This macro is used to align an offset to point to a 32b value. It is used in the Matrix algorithm to initialize the input memory blocks. +*/ +#define align_mem(x) (void *)(4 + (((ee_ptr_int)(x) - 1) & ~3)) + +/* Configuration : CORE_TICKS + Define type of return from the timing functions. + */ +#define CORETIMETYPE ee_u32 +typedef ee_u32 CORE_TICKS; + +/* Configuration : SEED_METHOD + Defines method to get seed values that cannot be computed at compile time. + + Valid values : + SEED_ARG - from command line. + SEED_FUNC - from a system function. + SEED_VOLATILE - from volatile variables. +*/ +#ifndef SEED_METHOD +#define SEED_METHOD SEED_VOLATILE +#endif + +/* Configuration : MEM_METHOD + Defines method to get a block of memry. + + Valid values : + MEM_MALLOC - for platforms that implement malloc and have malloc.h. + MEM_STATIC - to use a static memory array. + MEM_STACK - to allocate the data block on the stack (NYI). +*/ +#ifndef MEM_METHOD +#define MEM_METHOD MEM_STACK +#endif + +/* Configuration : MULTITHREAD + Define for parallel execution + + Valid values : + 1 - only one context (default). + N>1 - will execute N copies in parallel. + + Note : + If this flag is defined to more then 1, an implementation for launching parallel contexts must be defined. + + Two sample implementations are provided. Use or to enable them. + + It is valid to have a different implementation of and in , + to fit a particular architecture. +*/ +#ifndef MULTITHREAD +#define MULTITHREAD 1 +#define USE_PTHREAD 0 +#define USE_FORK 0 +#define USE_SOCKET 0 +#endif + +/* Configuration : MAIN_HAS_NOARGC + Needed if platform does not support getting arguments to main. + + Valid values : + 0 - argc/argv to main is supported + 1 - argc/argv to main is not supported + + Note : + This flag only matters if MULTITHREAD has been defined to a value greater then 1. +*/ +#ifndef MAIN_HAS_NOARGC +#define MAIN_HAS_NOARGC 0 +#endif + +/* Configuration : MAIN_HAS_NORETURN + Needed if platform does not support returning a value from main. + + Valid values : + 0 - main returns an int, and return value will be 0. + 1 - platform does not support returning a value from main +*/ +#ifndef MAIN_HAS_NORETURN +#define MAIN_HAS_NORETURN 0 +#endif + +/* Variable : default_num_contexts + Not used for this simple port, must cintain the value 1. +*/ +extern ee_u32 default_num_contexts; + +typedef struct CORE_PORTABLE_S { + ee_u8 portable_id; +} core_portable; + +/* target specific init/fini */ +void portable_init(core_portable *p, int *argc, char *argv[]); +void portable_fini(core_portable *p); + +#if !defined(PROFILE_RUN) && !defined(PERFORMANCE_RUN) && !defined(VALIDATION_RUN) +#if (TOTAL_DATA_SIZE==1200) +#define PROFILE_RUN 1 +#elif (TOTAL_DATA_SIZE==2000) +#define PERFORMANCE_RUN 1 +#else +#define VALIDATION_RUN 1 +#endif +#endif + +int ee_printf(const char *fmt, ...); + +#endif /* CORE_PORTME_H */ diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/core_portme.mak b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/core_portme.mak new file mode 100755 index 000000000..81594697d --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/core_portme.mak @@ -0,0 +1,87 @@ +# Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) +# +# 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. +# +# Original Author: Shay Gal-on + +#File : core_portme.mak + +# Flag : OUTFLAG +# Use this flag to define how to to get an executable (e.g -o) +OUTFLAG= -o +# Flag : CC +# Use this flag to define compiler to use +CC = gcc +# Flag : LD +# Use this flag to define compiler to use +LD = gld +# Flag : AS +# Use this flag to define compiler to use +AS = gas +# Flag : CFLAGS +# Use this flag to define compiler options. Note, you can add compiler options from the command line using XCFLAGS="other flags" +PORT_CFLAGS = -O0 -g +FLAGS_STR = "$(PORT_CFLAGS) $(XCFLAGS) $(XLFLAGS) $(LFLAGS_END)" +CFLAGS = $(PORT_CFLAGS) -I$(PORT_DIR) -I. -DFLAGS_STR=\"$(FLAGS_STR)\" +#Flag : LFLAGS_END +# Define any libraries needed for linking or other flags that should come at the end of the link line (e.g. linker scripts). +# Note : On certain platforms, the default clock_gettime implementation is supported but requires linking of librt. +SEPARATE_COMPILE=1 +# Flag : SEPARATE_COMPILE +# You must also define below how to create an object file, and how to link. +OBJOUT = -o +LFLAGS = +ASFLAGS = +OFLAG = -o +COUT = -c + +LFLAGS_END = +# Flag : PORT_SRCS +# Port specific source files can be added here +# You may also need cvt.c if the fcvt functions are not provided as intrinsics by your compiler! +PORT_SRCS = $(PORT_DIR)/core_portme.c $(PORT_DIR)/ee_printf.c +vpath %.c $(PORT_DIR) +vpath %.s $(PORT_DIR) + +# Flag : LOAD +# For a simple port, we assume self hosted compile and run, no load needed. + +# Flag : RUN +# For a simple port, we assume self hosted compile and run, simple invocation of the executable + +LOAD = echo "Please set LOAD to the process of loading the executable to the flash" +RUN = echo "Please set LOAD to the process of running the executable (e.g. via jtag, or board reset)" + +OEXT = .o +EXE = .bin + +$(OPATH)$(PORT_DIR)/%$(OEXT) : %.c + $(CC) $(CFLAGS) $(XCFLAGS) $(COUT) $< $(OBJOUT) $@ + +$(OPATH)%$(OEXT) : %.c + $(CC) $(CFLAGS) $(XCFLAGS) $(COUT) $< $(OBJOUT) $@ + +$(OPATH)$(PORT_DIR)/%$(OEXT) : %.s + $(AS) $(ASFLAGS) $< $(OBJOUT) $@ + +# Target : port_pre% and port_post% +# For the purpose of this simple port, no pre or post steps needed. + +.PHONY : port_prebuild port_postbuild port_prerun port_postrun port_preload port_postload +port_pre% port_post% : + +# FLAG : OPATH +# Path to the output folder. Default - current folder. +OPATH = ./ +MKDIR = mkdir -p + diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/cvt.c b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/cvt.c new file mode 100755 index 000000000..ee0506d54 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/cvt.c @@ -0,0 +1,117 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. +*/ +#include +#define CVTBUFSIZE 80 +static char CVTBUF[CVTBUFSIZE]; + +static char *cvt(double arg, int ndigits, int *decpt, int *sign, char *buf, int eflag) +{ + int r2; + double fi, fj; + char *p, *p1; + + if (ndigits < 0) ndigits = 0; + if (ndigits >= CVTBUFSIZE - 1) ndigits = CVTBUFSIZE - 2; + r2 = 0; + *sign = 0; + p = &buf[0]; + if (arg < 0) + { + *sign = 1; + arg = -arg; + } + arg = modf(arg, &fi); + p1 = &buf[CVTBUFSIZE]; + + if (fi != 0) + { + p1 = &buf[CVTBUFSIZE]; + while (fi != 0) + { + fj = modf(fi / 10, &fi); + *--p1 = (int)((fj + .03) * 10) + '0'; + r2++; + } + while (p1 < &buf[CVTBUFSIZE]) *p++ = *p1++; + } + else if (arg > 0) + { + while ((fj = arg * 10) < 1) + { + arg = fj; + r2--; + } + } + p1 = &buf[ndigits]; + if (eflag == 0) p1 += r2; + *decpt = r2; + if (p1 < &buf[0]) + { + buf[0] = '\0'; + return buf; + } + while (p <= p1 && p < &buf[CVTBUFSIZE]) + { + arg *= 10; + arg = modf(arg, &fj); + *p++ = (int) fj + '0'; + } + if (p1 >= &buf[CVTBUFSIZE]) + { + buf[CVTBUFSIZE - 1] = '\0'; + return buf; + } + p = p1; + *p1 += 5; + while (*p1 > '9') + { + *p1 = '0'; + if (p1 > buf) + ++*--p1; + else + { + *p1 = '1'; + (*decpt)++; + if (eflag == 0) + { + if (p > buf) *p = '0'; + p++; + } + } + } + *p = '\0'; + return buf; +} + +char *ecvt(double arg, int ndigits, int *decpt, int *sign) +{ + return cvt(arg, ndigits, decpt, sign, CVTBUF, 1); +} + +char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 1); +} + +char *fcvt(double arg, int ndigits, int *decpt, int *sign) +{ + return cvt(arg, ndigits, decpt, sign, CVTBUF, 0); +} + +char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 0); +} diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/ee_printf.c b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/ee_printf.c new file mode 100755 index 000000000..b08f59dbe --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/barebones/ee_printf.c @@ -0,0 +1,597 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. +*/ + +#include +#include + +#define ZEROPAD (1<<0) /* Pad with zero */ +#define SIGN (1<<1) /* Unsigned/signed long */ +#define PLUS (1<<2) /* Show plus */ +#define SPACE (1<<3) /* Spacer */ +#define LEFT (1<<4) /* Left justified */ +#define HEX_PREP (1<<5) /* 0x */ +#define UPPERCASE (1<<6) /* 'ABCDEF' */ + +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; +static char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static ee_size_t strnlen(const char *s, ee_size_t count); + +static ee_size_t strnlen(const char *s, ee_size_t count) +{ + const char *sc; + for (sc = s; *sc != '\0' && count--; ++sc); + return sc - s; +} + +static int skip_atoi(const char **s) +{ + int i = 0; + while (is_digit(**s)) i = i*10 + *((*s)++) - '0'; + return i; +} + +static char *number(char *str, long num, int base, int size, int precision, int type) +{ + char c, sign, tmp[66]; + char *dig = digits; + int i; + + if (type & UPPERCASE) dig = upper_digits; + if (type & LEFT) type &= ~ZEROPAD; + if (base < 2 || base > 36) return 0; + + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) + { + if (num < 0) + { + sign = '-'; + num = -num; + size--; + } + else if (type & PLUS) + { + sign = '+'; + size--; + } + else if (type & SPACE) + { + sign = ' '; + size--; + } + } + + if (type & HEX_PREP) + { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + + i = 0; + + if (num == 0) + tmp[i++] = '0'; + else + { + while (num != 0) + { + tmp[i++] = dig[((unsigned long) num) % (unsigned) base]; + num = ((unsigned long) num) / (unsigned) base; + } + } + + if (i > precision) precision = i; + size -= precision; + if (!(type & (ZEROPAD | LEFT))) while (size-- > 0) *str++ = ' '; + if (sign) *str++ = sign; + + if (type & HEX_PREP) + { + if (base == 8) + *str++ = '0'; + else if (base == 16) + { + *str++ = '0'; + *str++ = digits[33]; + } + } + + if (!(type & LEFT)) while (size-- > 0) *str++ = c; + while (i < precision--) *str++ = '0'; + while (i-- > 0) *str++ = tmp[i]; + while (size-- > 0) *str++ = ' '; + + return str; +} + +static char *eaddr(char *str, unsigned char *addr, int size, int precision, int type) +{ + char tmp[24]; + char *dig = digits; + int i, len; + + if (type & UPPERCASE) dig = upper_digits; + len = 0; + for (i = 0; i < 6; i++) + { + if (i != 0) tmp[len++] = ':'; + tmp[len++] = dig[addr[i] >> 4]; + tmp[len++] = dig[addr[i] & 0x0F]; + } + + if (!(type & LEFT)) while (len < size--) *str++ = ' '; + for (i = 0; i < len; ++i) *str++ = tmp[i]; + while (len < size--) *str++ = ' '; + + return str; +} + +static char *iaddr(char *str, unsigned char *addr, int size, int precision, int type) +{ + char tmp[24]; + int i, n, len; + + len = 0; + for (i = 0; i < 4; i++) + { + if (i != 0) tmp[len++] = '.'; + n = addr[i]; + + if (n == 0) + tmp[len++] = digits[0]; + else + { + if (n >= 100) + { + tmp[len++] = digits[n / 100]; + n = n % 100; + tmp[len++] = digits[n / 10]; + n = n % 10; + } + else if (n >= 10) + { + tmp[len++] = digits[n / 10]; + n = n % 10; + } + + tmp[len++] = digits[n]; + } + } + + if (!(type & LEFT)) while (len < size--) *str++ = ' '; + for (i = 0; i < len; ++i) *str++ = tmp[i]; + while (len < size--) *str++ = ' '; + + return str; +} + +#if HAS_FLOAT + +char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +static void ee_bufcpy(char *d, char *s, int count); + +void ee_bufcpy(char *pd, char *ps, int count) { + char *pe=ps+count; + while (ps!=pe) + *pd++=*ps++; +} + +static void parse_float(double value, char *buffer, char fmt, int precision) +{ + int decpt, sign, exp, pos; + char *digits = NULL; + char cvtbuf[80]; + int capexp = 0; + int magnitude; + + if (fmt == 'G' || fmt == 'E') + { + capexp = 1; + fmt += 'a' - 'A'; + } + + if (fmt == 'g') + { + digits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf); + magnitude = decpt - 1; + if (magnitude < -4 || magnitude > precision - 1) + { + fmt = 'e'; + precision -= 1; + } + else + { + fmt = 'f'; + precision -= decpt; + } + } + + if (fmt == 'e') + { + digits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf); + + if (sign) *buffer++ = '-'; + *buffer++ = *digits; + if (precision > 0) *buffer++ = '.'; + ee_bufcpy(buffer, digits + 1, precision); + buffer += precision; + *buffer++ = capexp ? 'E' : 'e'; + + if (decpt == 0) + { + if (value == 0.0) + exp = 0; + else + exp = -1; + } + else + exp = decpt - 1; + + if (exp < 0) + { + *buffer++ = '-'; + exp = -exp; + } + else + *buffer++ = '+'; + + buffer[2] = (exp % 10) + '0'; + exp = exp / 10; + buffer[1] = (exp % 10) + '0'; + exp = exp / 10; + buffer[0] = (exp % 10) + '0'; + buffer += 3; + } + else if (fmt == 'f') + { + digits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf); + if (sign) *buffer++ = '-'; + if (*digits) + { + if (decpt <= 0) + { + *buffer++ = '0'; + *buffer++ = '.'; + for (pos = 0; pos < -decpt; pos++) *buffer++ = '0'; + while (*digits) *buffer++ = *digits++; + } + else + { + pos = 0; + while (*digits) + { + if (pos++ == decpt) *buffer++ = '.'; + *buffer++ = *digits++; + } + } + } + else + { + *buffer++ = '0'; + if (precision > 0) + { + *buffer++ = '.'; + for (pos = 0; pos < precision; pos++) *buffer++ = '0'; + } + } + } + + *buffer = '\0'; +} + +static void decimal_point(char *buffer) +{ + while (*buffer) + { + if (*buffer == '.') return; + if (*buffer == 'e' || *buffer == 'E') break; + buffer++; + } + + if (*buffer) + { + int n = strnlen(buffer,256); + while (n > 0) + { + buffer[n + 1] = buffer[n]; + n--; + } + + *buffer = '.'; + } + else + { + *buffer++ = '.'; + *buffer = '\0'; + } +} + +static void cropzeros(char *buffer) +{ + char *stop; + + while (*buffer && *buffer != '.') buffer++; + if (*buffer++) + { + while (*buffer && *buffer != 'e' && *buffer != 'E') buffer++; + stop = buffer--; + while (*buffer == '0') buffer--; + if (*buffer == '.') buffer--; + while (buffer!=stop) + *++buffer=0; + } +} + +static char *flt(char *str, double num, int size, int precision, char fmt, int flags) +{ + char tmp[80]; + char c, sign; + int n, i; + + // Left align means no zero padding + if (flags & LEFT) flags &= ~ZEROPAD; + + // Determine padding and sign char + c = (flags & ZEROPAD) ? '0' : ' '; + sign = 0; + if (flags & SIGN) + { + if (num < 0.0) + { + sign = '-'; + num = -num; + size--; + } + else if (flags & PLUS) + { + sign = '+'; + size--; + } + else if (flags & SPACE) + { + sign = ' '; + size--; + } + } + + // Compute the precision value + if (precision < 0) + precision = 6; // Default precision: 6 + + // Convert floating point number to text + parse_float(num, tmp, fmt, precision); + + if ((flags & HEX_PREP) && precision == 0) decimal_point(tmp); + if (fmt == 'g' && !(flags & HEX_PREP)) cropzeros(tmp); + + n = strnlen(tmp,256); + + // Output number with alignment and padding + size -= n; + if (!(flags & (ZEROPAD | LEFT))) while (size-- > 0) *str++ = ' '; + if (sign) *str++ = sign; + if (!(flags & LEFT)) while (size-- > 0) *str++ = c; + for (i = 0; i < n; i++) *str++ = tmp[i]; + while (size-- > 0) *str++ = ' '; + + return str; +} + +#endif + +static int ee_vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char *str; + char *s; + + int flags; // Flags to number() + + int field_width; // Width of output field + int precision; // Min. # of digits for integers; max number of chars for from string + int qualifier; // 'h', 'l', or 'L' for integer fields + + for (str = buf; *fmt; fmt++) + { + if (*fmt != '%') + { + *str++ = *fmt; + continue; + } + + // Process flags + flags = 0; +repeat: + fmt++; // This also skips first '%' + switch (*fmt) + { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= HEX_PREP; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + // Get field width + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') + { + fmt++; + field_width = va_arg(args, int); + if (field_width < 0) + { + field_width = -field_width; + flags |= LEFT; + } + } + + // Get the precision + precision = -1; + if (*fmt == '.') + { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') + { + ++fmt; + precision = va_arg(args, int); + } + if (precision < 0) precision = 0; + } + + // Get the conversion qualifier + qualifier = -1; + if (*fmt == 'l' || *fmt == 'L') + { + qualifier = *fmt; + fmt++; + } + + // Default base + base = 10; + + switch (*fmt) + { + case 'c': + if (!(flags & LEFT)) while (--field_width > 0) *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) s = ""; + len = strnlen(s, precision); + if (!(flags & LEFT)) while (len < field_width--) *str++ = ' '; + for (i = 0; i < len; ++i) *str++ = *s++; + while (len < field_width--) *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) + { + field_width = 2 * sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, (unsigned long) va_arg(args, void *), 16, field_width, precision, flags); + continue; + + case 'A': + flags |= UPPERCASE; + + case 'a': + if (qualifier == 'l') + str = eaddr(str, va_arg(args, unsigned char *), field_width, precision, flags); + else + str = iaddr(str, va_arg(args, unsigned char *), field_width, precision, flags); + continue; + + // Integer number formats - set up the flags and "break" + case 'o': + base = 8; + break; + + case 'X': + flags |= UPPERCASE; + + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + + case 'u': + break; + +#if HAS_FLOAT + + case 'f': + str = flt(str, va_arg(args, double), field_width, precision, *fmt, flags | SIGN); + continue; + +#endif + + default: + if (*fmt != '%') *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + + str = number(str, num, base, field_width, precision, flags); + } + + *str = '\0'; + return str - buf; +} + +void uart_send_char(char c) { +#error "You must implement the method uart_send_char to use this file!\n"; +/* Output of a char to a UART usually follows the following model: + Wait until UART is ready + Write char to UART + Wait until UART is done + + Or in code: + while (*UART_CONTROL_ADDRESS != UART_READY); + *UART_DATA_ADDRESS = c; + while (*UART_CONTROL_ADDRESS != UART_READY); + + Check the UART sample code on your platform or the board documentation. +*/ +} + +int ee_printf(const char *fmt, ...) +{ + char buf[256],*p; + va_list args; + int n=0; + + va_start(args, fmt); + ee_vsprintf(buf, fmt, args); + va_end(args); + p=buf; + while (*p) { + uart_send_char(*p); + n++; + p++; + } + + return n; +} + diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/cheri_atest.S b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/cheri_atest.S new file mode 100755 index 000000000..3704d1a43 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/cheri_atest.S @@ -0,0 +1,131 @@ +#.option norelax + +.section .text +#.globl cheri_fault_handler +.globl cheri_atest + +.macro PRINTMSG reg, symbol + lui \reg, %hi(\symbol) + addi \reg, \reg, %lo(\symbol) + csetaddr c9, c6, \reg + ccall print_string +.endm + +print_string: # print a string pointed by C9 + cincoffset csp, csp, -8 + csc c11, (csp) + + clb x11, (c9) +print_loop: + csb x11, 512(c5) + cincoffset c9, c9, 0x1 + clb x11, (c9) + bne x11, x0, print_loop + + clc c11, (csp) + cincoffset csp, csp, 8 + cret + +# +# Register allocation for this test +# +# Globals +# -- c2: as the stack capability (created at startup) +# -- c3: as a "full" memory capability (entire address space) +# -- c4: base capability for code execution from SRAM (code r/x) +# -- c5: base capability for peripheral accesses in tb_top +# -- c6: base capability for accessing SRAM (data and cap r/w) +# -- c7: reserved for further use +# +# -- x1/cra: return address +# -- x10/a0: argument/return value for subroutines +# -- x15/a5: is used to pass "argument" to the fault handler. +# +# -- x8, x9(s0,s1): temp variables +# -- x11-x14 (a1-a4): temp varaibles + + + +# /////////////////////////////////////// +# init +# /////////////////////////////////////// + +test_init: + cspecialrw c3, 29, c0 # read MTDC address 'd29, memory root + + lui x11, 0x83800 + csetaddr c5, c3, x11 # set base address to 0x8400_0000 + csetboundsimm c5, c5, 0x800 # set bounds to 0x800 + addi x11, x0, 0x24 + candperm c5, c5, x11 # load/store data permission only + + lui x11, 0x80000 + csetaddr c6, c3, x11 # set base address to 0x8000_0000 + lui x11, 0x4000 + csetbounds c6, c6, x11 # set lengths to 0x400_0000 + addi x11, x0, 0x7f + candperm c6, c6, x11 # full mem data/cap permission only + + auipcc c4, 0 # get PCC capability + lui x11, 0x80000 + csetaddr c4, c4, x11 # set address to 0x8000_0000 + lui x11, 0x40 + csetbounds c4, c4, x11 # set length to 0x80000 + + li x11, 0x83800100 # write to this location to tell TB end of init + csetaddr c8, c6, x11 + li x11, 0xf + csw x11, (c8) + + li x9, 0x800 # enable machine-mode ext/tmr/sw interrupts + csrs mie, x9 + + li a0, 0x0 + cret + +# /////////////////////////////////////// +# --- cheri_test (main test for CHERI instructions) +# /////////////////////////////////////// + +cheri_atest: + # save register context so that we won't have issue talking with the C program + # note RISC-V uses x10/x11 (a0/a1) for args/return values, and x12-x17 (a2-7) for args + cincoffset csp, csp, -64 + csc c1, 0(csp) + csc c3, 8(csp) + csc c4, 16(csp) + csc c5, 24(csp) + csc c6, 32(csp) + csc c7, 40(csp) + csc c8, 48(csp) + csc c9, 56(csp) + + ccall test_init + PRINTMSG x11, hello_msg + + j test_exit + +test_exit: + # restore register context + clc c1, 0(csp) + clc c3, 8(csp) + clc c4, 16(csp) + clc c5, 24(csp) + clc c6, 32(csp) + clc c7, 40(csp) + clc c8, 48(csp) + clc c9, 56(csp) + cincoffset csp, csp, 64 + + cret + +.section .rodata + +hello_msg : + .string "Doing something in assembly..\n" + +#.section .tohost +#tohost : +# .dword 0 +#fromhost : +# .dword 0 diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/core_portme.c b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/core_portme.c new file mode 100755 index 000000000..c34af22de --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/core_portme.c @@ -0,0 +1,129 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ +#include "coremark.h" +#include "core_portme.h" +#include "util.h" + +#if VALIDATION_RUN + volatile ee_s32 seed1_volatile=0x3415; + volatile ee_s32 seed2_volatile=0x3415; + volatile ee_s32 seed3_volatile=0x66; +#endif +#if PERFORMANCE_RUN + volatile ee_s32 seed1_volatile=0x0; + volatile ee_s32 seed2_volatile=0x0; + volatile ee_s32 seed3_volatile=0x66; +#endif +#if PROFILE_RUN + volatile ee_s32 seed1_volatile=0x8; + volatile ee_s32 seed2_volatile=0x8; + volatile ee_s32 seed3_volatile=0x8; +#endif + volatile ee_s32 seed4_volatile=ITERATIONS; + volatile ee_s32 seed5_volatile=0; +/* Porting : Timing functions + How to capture time and convert to seconds must be ported to whatever is supported by the platform. + e.g. Read value from on board RTC, read value from cpu clock cycles performance counter etc. + Sample implementation for standard time.h and windows.h definitions included. +*/ +CORETIMETYPE barebones_clock() { + //#error "You must implement a method to measure time in barebones_clock()! This function should return current time.\n" + return (get_tmrval()); +} +/* Define : TIMER_RES_DIVIDER + Divider to trade off timer resolution and total time that can be measured. + + Use lower values to increase resolution, but make sure that overflow does not occur. + If there are issues with the return value overflowing, increase this value. + */ +#define GETMYTIME(_t) (*_t=barebones_clock()) +#define MYTIMEDIFF(fin,ini) ((fin)-(ini)) +#define TIMER_RES_DIVIDER 1 +#define SAMPLE_TIME_IMPLEMENTATION 1 +#define EE_TICKS_PER_SEC (CLOCKS_PER_SEC / TIMER_RES_DIVIDER) + +/** Define Host specific (POSIX), or target specific global time variables. */ +static CORETIMETYPE start_time_val, stop_time_val; + +/* Function : start_time + This function will be called right before starting the timed portion of the benchmark. + + Implementation may be capturing a system timer (as implemented in the example code) + or zeroing some system parameters - e.g. setting the cpu clocks cycles to 0. +*/ +void start_time(void) { + GETMYTIME(&start_time_val ); +} +/* Function : stop_time + This function will be called right after ending the timed portion of the benchmark. + + Implementation may be capturing a system timer (as implemented in the example code) + or other system parameters - e.g. reading the current value of cpu cycles counter. +*/ +void stop_time(void) { + GETMYTIME(&stop_time_val ); +} +/* Function : get_time + Return an abstract "ticks" number that signifies time on the system. + + Actual value returned may be cpu cycles, milliseconds or any other value, + as long as it can be converted to seconds by . + This methodology is taken to accomodate any hardware or simulated platform. + The sample implementation returns millisecs by default, + and the resolution is controlled by +*/ +CORE_TICKS get_time(void) { + CORE_TICKS elapsed=(CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val)); + return elapsed; +} +/* Function : time_in_secs + Convert the value returned by get_time to seconds. + + The type is used to accomodate systems with no support for floating point. + Default implementation implemented by the EE_TICKS_PER_SEC macro above. +*/ +secs_ret time_in_secs(CORE_TICKS ticks) { + secs_ret retval=((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC; + return retval; +} + +ee_u32 default_num_contexts=1; + +/* Function : portable_init + Target specific initialization code + Test for some common mistakes. +*/ +void portable_init(core_portable *p, int *argc, char *argv[]) +{ + //#error "Call board initialization routines in portable init (if needed), in particular initialize UART!\n" + if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) { +// ee_printf("ERROR! Please define ee_ptr_int to a type that holds a pointer! %d %d %d\n", sizeof(ee_ptr_int), sizeof(ee_u8 *), sizeof(ee_u32) ); + } + if (sizeof(ee_u32) != 4) { + ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n"); + } + p->portable_id=1; +} +/* Function : portable_fini + Target specific final code +*/ +void portable_fini(core_portable *p) +{ + p->portable_id=0; +} + diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/core_portme.h b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/core_portme.h new file mode 100755 index 000000000..aa2c61aad --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/core_portme.h @@ -0,0 +1,216 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ +/* Topic : Description + This file contains configuration constants required to execute on different platforms +*/ +#ifndef CORE_PORTME_H +#define CORE_PORTME_H + +#define HAS_FLOAT 0 +#define USE_CLOCK 0 +#define HAS_STDIO 0 +#define HAS_PRINTF 0 +#define MEM_LOCATION "STATIC" +#define SEED_METHOD SEED_VOLATILE +#define MEM_METHOD MEM_STATIC +#define MAIN_HAS_NOARGC 1 +#define MAIN_HAS_NORETURN 1 +#define MULTITHREAD 1 + +/************************/ +/* Data types and settings */ +/************************/ +/* Configuration : HAS_FLOAT + Define to 1 if the platform supports floating point. +*/ +#ifndef HAS_FLOAT +#define HAS_FLOAT 0 +#endif +/* Configuration : HAS_TIME_H + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef HAS_TIME_H +#define HAS_TIME_H 0 +#endif +/* Configuration : USE_CLOCK + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef USE_CLOCK +#define USE_CLOCK 0 +#endif +/* Configuration : HAS_STDIO + Define to 1 if the platform has stdio.h. +*/ +#ifndef HAS_STDIO +#define HAS_STDIO 0 +#endif +/* Configuration : HAS_PRINTF + Define to 1 if the platform has stdio.h and implements the printf function. +*/ +#ifndef HAS_PRINTF +#define HAS_PRINTF 0 +#endif + + +/* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION + Initialize these strings per platform +*/ +#ifndef COMPILER_VERSION + #ifdef __GNUC__ + #define COMPILER_VERSION "GCC"__VERSION__ + #else + #define COMPILER_VERSION "Please put compiler version here (e.g. gcc 4.1)" + #endif +#endif +#ifndef COMPILER_FLAGS + #define COMPILER_FLAGS FLAGS_STR /* "Please put compiler flags here (e.g. -o3)" */ +#endif +#ifndef MEM_LOCATION + #define MEM_LOCATION "STACK" +#endif + +/* Data Types : + To avoid compiler issues, define the data types that need ot be used for 8b, 16b and 32b in . + + *Imprtant* : + ee_ptr_int needs to be the data type used to hold pointers, otherwise coremark may fail!!! +*/ +typedef signed short ee_s16; +typedef unsigned short ee_u16; +typedef signed int ee_s32; +typedef double ee_f32; +typedef unsigned char ee_u8; +typedef unsigned int ee_u32; +typedef ee_u32 ee_ptr_int; +//typedef size_t ee_size_t; +typedef unsigned int ee_size_t; +#define NULL ((void *)0) +/* align_mem : + This macro is used to align an offset to point to a 32b value. It is used in the Matrix algorithm to initialize the input memory blocks. +*/ +#define align_mem(x) (void *)(((__UINTPTR_TYPE__)(x) + 3) & ~3) + +/* Configuration : CORE_TICKS + Define type of return from the timing functions. + */ +#define CORETIMETYPE ee_u32 +typedef ee_u32 CORE_TICKS; + +/* Configuration : SEED_METHOD + Defines method to get seed values that cannot be computed at compile time. + + Valid values : + SEED_ARG - from command line. + SEED_FUNC - from a system function. + SEED_VOLATILE - from volatile variables. +*/ +#ifndef SEED_METHOD +#define SEED_METHOD SEED_VOLATILE +#endif + +/* Configuration : MEM_METHOD + Defines method to get a block of memry. + + Valid values : + MEM_MALLOC - for platforms that implement malloc and have malloc.h. + MEM_STATIC - to use a static memory array. + MEM_STACK - to allocate the data block on the stack (NYI). +*/ +#ifndef MEM_METHOD +//#define MEM_METHOD MEM_STACK +#define MEM_METHOD MEM_STATIC +#endif + +/* Configuration : MULTITHREAD + Define for parallel execution + + Valid values : + 1 - only one context (default). + N>1 - will execute N copies in parallel. + + Note : + If this flag is defined to more then 1, an implementation for launching parallel contexts must be defined. + + Two sample implementations are provided. Use or to enable them. + + It is valid to have a different implementation of and in , + to fit a particular architecture. +*/ +#ifndef MULTITHREAD +#define MULTITHREAD 1 +#define USE_PTHREAD 0 +#define USE_FORK 0 +#define USE_SOCKET 0 +#endif + +/* Configuration : MAIN_HAS_NOARGC + Needed if platform does not support getting arguments to main. + + Valid values : + 0 - argc/argv to main is supported + 1 - argc/argv to main is not supported + + Note : + This flag only matters if MULTITHREAD has been defined to a value greater then 1. +*/ +#ifndef MAIN_HAS_NOARGC +#define MAIN_HAS_NOARGC 0 +#endif + +/* Configuration : MAIN_HAS_NORETURN + Needed if platform does not support returning a value from main. + + Valid values : + 0 - main returns an int, and return value will be 0. + 1 - platform does not support returning a value from main +*/ +#ifndef MAIN_HAS_NORETURN +#define MAIN_HAS_NORETURN 0 +#endif + +/* Variable : default_num_contexts + Not used for this simple port, must cintain the value 1. +*/ +extern ee_u32 default_num_contexts; + +typedef struct CORE_PORTABLE_S { + ee_u8 portable_id; +} core_portable; + +/* target specific init/fini */ +void portable_init(core_portable *p, int *argc, char *argv[]); +void portable_fini(core_portable *p); + +#if !defined(PROFILE_RUN) && !defined(PERFORMANCE_RUN) && !defined(VALIDATION_RUN) +#if (TOTAL_DATA_SIZE==1200) +#define PROFILE_RUN 1 +#elif (TOTAL_DATA_SIZE==2000) +#define PERFORMANCE_RUN 1 +#else +#define VALIDATION_RUN 1 +#endif +#endif + +int ee_printf(const char *fmt, ...); + +void stop_sim(void); +#define STOP_SIM stop_sim() + +#endif /* CORE_PORTME_H */ diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/core_portme.mak b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/core_portme.mak new file mode 100755 index 000000000..81594697d --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/core_portme.mak @@ -0,0 +1,87 @@ +# Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) +# +# 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. +# +# Original Author: Shay Gal-on + +#File : core_portme.mak + +# Flag : OUTFLAG +# Use this flag to define how to to get an executable (e.g -o) +OUTFLAG= -o +# Flag : CC +# Use this flag to define compiler to use +CC = gcc +# Flag : LD +# Use this flag to define compiler to use +LD = gld +# Flag : AS +# Use this flag to define compiler to use +AS = gas +# Flag : CFLAGS +# Use this flag to define compiler options. Note, you can add compiler options from the command line using XCFLAGS="other flags" +PORT_CFLAGS = -O0 -g +FLAGS_STR = "$(PORT_CFLAGS) $(XCFLAGS) $(XLFLAGS) $(LFLAGS_END)" +CFLAGS = $(PORT_CFLAGS) -I$(PORT_DIR) -I. -DFLAGS_STR=\"$(FLAGS_STR)\" +#Flag : LFLAGS_END +# Define any libraries needed for linking or other flags that should come at the end of the link line (e.g. linker scripts). +# Note : On certain platforms, the default clock_gettime implementation is supported but requires linking of librt. +SEPARATE_COMPILE=1 +# Flag : SEPARATE_COMPILE +# You must also define below how to create an object file, and how to link. +OBJOUT = -o +LFLAGS = +ASFLAGS = +OFLAG = -o +COUT = -c + +LFLAGS_END = +# Flag : PORT_SRCS +# Port specific source files can be added here +# You may also need cvt.c if the fcvt functions are not provided as intrinsics by your compiler! +PORT_SRCS = $(PORT_DIR)/core_portme.c $(PORT_DIR)/ee_printf.c +vpath %.c $(PORT_DIR) +vpath %.s $(PORT_DIR) + +# Flag : LOAD +# For a simple port, we assume self hosted compile and run, no load needed. + +# Flag : RUN +# For a simple port, we assume self hosted compile and run, simple invocation of the executable + +LOAD = echo "Please set LOAD to the process of loading the executable to the flash" +RUN = echo "Please set LOAD to the process of running the executable (e.g. via jtag, or board reset)" + +OEXT = .o +EXE = .bin + +$(OPATH)$(PORT_DIR)/%$(OEXT) : %.c + $(CC) $(CFLAGS) $(XCFLAGS) $(COUT) $< $(OBJOUT) $@ + +$(OPATH)%$(OEXT) : %.c + $(CC) $(CFLAGS) $(XCFLAGS) $(COUT) $< $(OBJOUT) $@ + +$(OPATH)$(PORT_DIR)/%$(OEXT) : %.s + $(AS) $(ASFLAGS) $< $(OBJOUT) $@ + +# Target : port_pre% and port_post% +# For the purpose of this simple port, no pre or post steps needed. + +.PHONY : port_prebuild port_postbuild port_prerun port_postrun port_preload port_postload +port_pre% port_post% : + +# FLAG : OPATH +# Path to the output folder. Default - current folder. +OPATH = ./ +MKDIR = mkdir -p + diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/cvt.c b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/cvt.c new file mode 100755 index 000000000..ee0506d54 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/cvt.c @@ -0,0 +1,117 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. +*/ +#include +#define CVTBUFSIZE 80 +static char CVTBUF[CVTBUFSIZE]; + +static char *cvt(double arg, int ndigits, int *decpt, int *sign, char *buf, int eflag) +{ + int r2; + double fi, fj; + char *p, *p1; + + if (ndigits < 0) ndigits = 0; + if (ndigits >= CVTBUFSIZE - 1) ndigits = CVTBUFSIZE - 2; + r2 = 0; + *sign = 0; + p = &buf[0]; + if (arg < 0) + { + *sign = 1; + arg = -arg; + } + arg = modf(arg, &fi); + p1 = &buf[CVTBUFSIZE]; + + if (fi != 0) + { + p1 = &buf[CVTBUFSIZE]; + while (fi != 0) + { + fj = modf(fi / 10, &fi); + *--p1 = (int)((fj + .03) * 10) + '0'; + r2++; + } + while (p1 < &buf[CVTBUFSIZE]) *p++ = *p1++; + } + else if (arg > 0) + { + while ((fj = arg * 10) < 1) + { + arg = fj; + r2--; + } + } + p1 = &buf[ndigits]; + if (eflag == 0) p1 += r2; + *decpt = r2; + if (p1 < &buf[0]) + { + buf[0] = '\0'; + return buf; + } + while (p <= p1 && p < &buf[CVTBUFSIZE]) + { + arg *= 10; + arg = modf(arg, &fj); + *p++ = (int) fj + '0'; + } + if (p1 >= &buf[CVTBUFSIZE]) + { + buf[CVTBUFSIZE - 1] = '\0'; + return buf; + } + p = p1; + *p1 += 5; + while (*p1 > '9') + { + *p1 = '0'; + if (p1 > buf) + ++*--p1; + else + { + *p1 = '1'; + (*decpt)++; + if (eflag == 0) + { + if (p > buf) *p = '0'; + p++; + } + } + } + *p = '\0'; + return buf; +} + +char *ecvt(double arg, int ndigits, int *decpt, int *sign) +{ + return cvt(arg, ndigits, decpt, sign, CVTBUF, 1); +} + +char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 1); +} + +char *fcvt(double arg, int ndigits, int *decpt, int *sign) +{ + return cvt(arg, ndigits, decpt, sign, CVTBUF, 0); +} + +char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 0); +} diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/ee_printf.c b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/ee_printf.c new file mode 100755 index 000000000..6b8af5010 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/cheri/ee_printf.c @@ -0,0 +1,601 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. +*/ + +#include +#include + +#include + +#define ZEROPAD (1<<0) /* Pad with zero */ +#define SIGN (1<<1) /* Unsigned/signed long */ +#define PLUS (1<<2) /* Show plus */ +#define SPACE (1<<3) /* Spacer */ +#define LEFT (1<<4) /* Left justified */ +#define HEX_PREP (1<<5) /* 0x */ +#define UPPERCASE (1<<6) /* 'ABCDEF' */ + +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; +static char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static ee_size_t strnlen(const char *s, ee_size_t count); + +static ee_size_t strnlen(const char *s, ee_size_t count) +{ + const char *sc; + for (sc = s; *sc != '\0' && count--; ++sc); + return sc - s; +} + +static int skip_atoi(const char **s) +{ + int i = 0; + while (is_digit(**s)) i = i*10 + *((*s)++) - '0'; + return i; +} + +static char *number(char *str, long num, int base, int size, int precision, int type) +{ + char c, sign, tmp[66]; + char *dig = digits; + int i; + + if (type & UPPERCASE) dig = upper_digits; + if (type & LEFT) type &= ~ZEROPAD; + if (base < 2 || base > 36) return 0; + + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) + { + if (num < 0) + { + sign = '-'; + num = -num; + size--; + } + else if (type & PLUS) + { + sign = '+'; + size--; + } + else if (type & SPACE) + { + sign = ' '; + size--; + } + } + + if (type & HEX_PREP) + { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + + i = 0; + + if (num == 0) + tmp[i++] = '0'; + else + { + while (num != 0) + { + tmp[i++] = dig[((unsigned long) num) % (unsigned) base]; + num = ((unsigned long) num) / (unsigned) base; + } + } + + if (i > precision) precision = i; + size -= precision; + if (!(type & (ZEROPAD | LEFT))) while (size-- > 0) *str++ = ' '; + if (sign) *str++ = sign; + + if (type & HEX_PREP) + { + if (base == 8) + *str++ = '0'; + else if (base == 16) + { + *str++ = '0'; + *str++ = digits[33]; + } + } + + if (!(type & LEFT)) while (size-- > 0) *str++ = c; + while (i < precision--) *str++ = '0'; + while (i-- > 0) *str++ = tmp[i]; + while (size-- > 0) *str++ = ' '; + + return str; +} + +static char *eaddr(char *str, unsigned char *addr, int size, int precision, int type) +{ + char tmp[24]; + char *dig = digits; + int i, len; + + if (type & UPPERCASE) dig = upper_digits; + len = 0; + for (i = 0; i < 6; i++) + { + if (i != 0) tmp[len++] = ':'; + tmp[len++] = dig[addr[i] >> 4]; + tmp[len++] = dig[addr[i] & 0x0F]; + } + + if (!(type & LEFT)) while (len < size--) *str++ = ' '; + for (i = 0; i < len; ++i) *str++ = tmp[i]; + while (len < size--) *str++ = ' '; + + return str; +} + +static char *iaddr(char *str, unsigned char *addr, int size, int precision, int type) +{ + char tmp[24]; + int i, n, len; + + len = 0; + for (i = 0; i < 4; i++) + { + if (i != 0) tmp[len++] = '.'; + n = addr[i]; + + if (n == 0) + tmp[len++] = digits[0]; + else + { + if (n >= 100) + { + tmp[len++] = digits[n / 100]; + n = n % 100; + tmp[len++] = digits[n / 10]; + n = n % 10; + } + else if (n >= 10) + { + tmp[len++] = digits[n / 10]; + n = n % 10; + } + + tmp[len++] = digits[n]; + } + } + + if (!(type & LEFT)) while (len < size--) *str++ = ' '; + for (i = 0; i < len; ++i) *str++ = tmp[i]; + while (len < size--) *str++ = ' '; + + return str; +} + +#if HAS_FLOAT + +char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +static void ee_bufcpy(char *d, char *s, int count); + +void ee_bufcpy(char *pd, char *ps, int count) { + char *pe=ps+count; + while (ps!=pe) + *pd++=*ps++; +} + +static void parse_float(double value, char *buffer, char fmt, int precision) +{ + int decpt, sign, exp, pos; + char *digits = NULL; + char cvtbuf[80]; + int capexp = 0; + int magnitude; + + if (fmt == 'G' || fmt == 'E') + { + capexp = 1; + fmt += 'a' - 'A'; + } + + if (fmt == 'g') + { + digits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf); + magnitude = decpt - 1; + if (magnitude < -4 || magnitude > precision - 1) + { + fmt = 'e'; + precision -= 1; + } + else + { + fmt = 'f'; + precision -= decpt; + } + } + + if (fmt == 'e') + { + digits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf); + + if (sign) *buffer++ = '-'; + *buffer++ = *digits; + if (precision > 0) *buffer++ = '.'; + ee_bufcpy(buffer, digits + 1, precision); + buffer += precision; + *buffer++ = capexp ? 'E' : 'e'; + + if (decpt == 0) + { + if (value == 0.0) + exp = 0; + else + exp = -1; + } + else + exp = decpt - 1; + + if (exp < 0) + { + *buffer++ = '-'; + exp = -exp; + } + else + *buffer++ = '+'; + + buffer[2] = (exp % 10) + '0'; + exp = exp / 10; + buffer[1] = (exp % 10) + '0'; + exp = exp / 10; + buffer[0] = (exp % 10) + '0'; + buffer += 3; + } + else if (fmt == 'f') + { + digits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf); + if (sign) *buffer++ = '-'; + if (*digits) + { + if (decpt <= 0) + { + *buffer++ = '0'; + *buffer++ = '.'; + for (pos = 0; pos < -decpt; pos++) *buffer++ = '0'; + while (*digits) *buffer++ = *digits++; + } + else + { + pos = 0; + while (*digits) + { + if (pos++ == decpt) *buffer++ = '.'; + *buffer++ = *digits++; + } + } + } + else + { + *buffer++ = '0'; + if (precision > 0) + { + *buffer++ = '.'; + for (pos = 0; pos < precision; pos++) *buffer++ = '0'; + } + } + } + + *buffer = '\0'; +} + +static void decimal_point(char *buffer) +{ + while (*buffer) + { + if (*buffer == '.') return; + if (*buffer == 'e' || *buffer == 'E') break; + buffer++; + } + + if (*buffer) + { + int n = strnlen(buffer,256); + while (n > 0) + { + buffer[n + 1] = buffer[n]; + n--; + } + + *buffer = '.'; + } + else + { + *buffer++ = '.'; + *buffer = '\0'; + } +} + +static void cropzeros(char *buffer) +{ + char *stop; + + while (*buffer && *buffer != '.') buffer++; + if (*buffer++) + { + while (*buffer && *buffer != 'e' && *buffer != 'E') buffer++; + stop = buffer--; + while (*buffer == '0') buffer--; + if (*buffer == '.') buffer--; + while (buffer!=stop) + *++buffer=0; + } +} + +static char *flt(char *str, double num, int size, int precision, char fmt, int flags) +{ + char tmp[80]; + char c, sign; + int n, i; + + // Left align means no zero padding + if (flags & LEFT) flags &= ~ZEROPAD; + + // Determine padding and sign char + c = (flags & ZEROPAD) ? '0' : ' '; + sign = 0; + if (flags & SIGN) + { + if (num < 0.0) + { + sign = '-'; + num = -num; + size--; + } + else if (flags & PLUS) + { + sign = '+'; + size--; + } + else if (flags & SPACE) + { + sign = ' '; + size--; + } + } + + // Compute the precision value + if (precision < 0) + precision = 6; // Default precision: 6 + + // Convert floating point number to text + parse_float(num, tmp, fmt, precision); + + if ((flags & HEX_PREP) && precision == 0) decimal_point(tmp); + if (fmt == 'g' && !(flags & HEX_PREP)) cropzeros(tmp); + + n = strnlen(tmp,256); + + // Output number with alignment and padding + size -= n; + if (!(flags & (ZEROPAD | LEFT))) while (size-- > 0) *str++ = ' '; + if (sign) *str++ = sign; + if (!(flags & LEFT)) while (size-- > 0) *str++ = c; + for (i = 0; i < n; i++) *str++ = tmp[i]; + while (size-- > 0) *str++ = ' '; + + return str; +} + +#endif + +static int ee_vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char *str; + char *s; + + int flags; // Flags to number() + + int field_width; // Width of output field + int precision; // Min. # of digits for integers; max number of chars for from string + int qualifier; // 'h', 'l', or 'L' for integer fields + + for (str = buf; *fmt; fmt++) + { + if (*fmt != '%') + { + *str++ = *fmt; + continue; + } + + // Process flags + flags = 0; +repeat: + fmt++; // This also skips first '%' + switch (*fmt) + { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= HEX_PREP; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + // Get field width + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') + { + fmt++; + field_width = va_arg(args, int); + if (field_width < 0) + { + field_width = -field_width; + flags |= LEFT; + } + } + + // Get the precision + precision = -1; + if (*fmt == '.') + { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') + { + ++fmt; + precision = va_arg(args, int); + } + if (precision < 0) precision = 0; + } + + // Get the conversion qualifier + qualifier = -1; + if (*fmt == 'l' || *fmt == 'L') + { + qualifier = *fmt; + fmt++; + } + + // Default base + base = 10; + + switch (*fmt) + { + case 'c': + if (!(flags & LEFT)) while (--field_width > 0) *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) s = ""; + len = strnlen(s, precision); + if (!(flags & LEFT)) while (len < field_width--) *str++ = ' '; + for (i = 0; i < len; ++i) *str++ = *s++; + while (len < field_width--) *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) + { + field_width = 2 * sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, (unsigned long) va_arg(args, void *), 16, field_width, precision, flags); + continue; + + case 'A': + flags |= UPPERCASE; + + case 'a': + if (qualifier == 'l') + str = eaddr(str, va_arg(args, unsigned char *), field_width, precision, flags); + else + str = iaddr(str, va_arg(args, unsigned char *), field_width, precision, flags); + continue; + + // Integer number formats - set up the flags and "break" + case 'o': + base = 8; + break; + + case 'X': + flags |= UPPERCASE; + + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + + case 'u': + break; + +#if HAS_FLOAT + + case 'f': + str = flt(str, va_arg(args, double), field_width, precision, *fmt, flags | SIGN); + continue; + +#endif + + default: + if (*fmt != '%') *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + + str = number(str, num, base, field_width, precision, flags); + } + + *str = '\0'; + return str - buf; +} + +void uart_send_char(char c) { +//#error "You must implement the method uart_send_char to use this file!\n"; +/* Output of a char to a UART usually follows the following model: + Wait until UART is ready + Write char to UART + Wait until UART is done + + Or in code: + while (*UART_CONTROL_ADDRESS != UART_READY); + *UART_DATA_ADDRESS = c; + while (*UART_CONTROL_ADDRESS != UART_READY); + + Check the UART sample code on your platform or the board documentation. +*/ + UART_SEND_CHAR(c); +} + +int ee_printf(const char *fmt, ...) +{ + // char buf[256],*p; + char buf[512],*p; + va_list args; + int n=0; + + va_start(args, fmt); + ee_vsprintf(buf, fmt, args); + va_end(args); + p=buf; + while (*p) { + uart_send_char(*p); + n++; + p++; + } + + return n; +} + diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/core_list_join.c b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/core_list_join.c new file mode 100755 index 000000000..a5154284a --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/core_list_join.c @@ -0,0 +1,495 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ + +#include "coremark.h" +/* +Topic: Description + Benchmark using a linked list. + + Linked list is a common data structure used in many applications. + + For our purposes, this will excercise the memory units of the processor. + In particular, usage of the list pointers to find and alter data. + + We are not using Malloc since some platforms do not support this library. + + Instead, the memory block being passed in is used to create a list, + and the benchmark takes care not to add more items then can be + accomodated by the memory block. The porting layer will make sure + that we have a valid memory block. + + All operations are done in place, without using any extra memory. + + The list itself contains list pointers and pointers to data items. + Data items contain the following: + + idx - An index that captures the initial order of the list. + data - Variable data initialized based on the input parameters. The 16b are divided as follows: + o Upper 8b are backup of original data. + o Bit 7 indicates if the lower 7 bits are to be used as is or calculated. + o Bits 0-2 indicate type of operation to perform to get a 7b value. + o Bits 3-6 provide input for the operation. + +*/ + +/* local functions */ + +list_head *core_list_find(list_head *list,list_data *info); +list_head *core_list_reverse(list_head *list); +list_head *core_list_remove(list_head *item); +list_head *core_list_undo_remove(list_head *item_removed, list_head *item_modified); +list_head *core_list_insert_new(list_head *insert_point + , list_data *info, list_head **memblock, list_data **datablock + , list_head *memblock_end, list_data *datablock_end); +typedef ee_s32(*list_cmp)(list_data *a, list_data *b, core_results *res); +list_head *core_list_mergesort(list_head *list, list_cmp cmp, core_results *res); + +ee_s16 calc_func(ee_s16 *pdata, core_results *res) { + ee_s16 data=*pdata; + ee_s16 retval; + ee_u8 optype=(data>>7) & 1; /* bit 7 indicates if the function result has been cached */ + if (optype) /* if cached, use cache */ + return (data & 0x007f); + else { /* otherwise calculate and cache the result */ + ee_s16 flag=data & 0x7; /* bits 0-2 is type of function to perform */ + ee_s16 dtype=((data>>3) & 0xf); /* bits 3-6 is specific data for the operation */ + dtype |= dtype << 4; /* replicate the lower 4 bits to get an 8b value */ + switch (flag) { + case 0: + if (dtype<0x22) /* set min period for bit corruption */ + dtype=0x22; + retval=core_bench_state(res->size,res->memblock[3],res->seed1,res->seed2,dtype,res->crc); + if (res->crcstate==0) + res->crcstate=retval; + break; + case 1: + retval=core_bench_matrix(&(res->mat),dtype,res->crc); + if (res->crcmatrix==0) + res->crcmatrix=retval; + break; + default: + retval=data; + break; + } + res->crc=crcu16(retval,res->crc); + retval &= 0x007f; + *pdata = (data & 0xff00) | 0x0080 | retval; /* cache the result */ + return retval; + } +} +/* Function: cmp_complex + Compare the data item in a list cell. + + Can be used by mergesort. +*/ +ee_s32 cmp_complex(list_data *a, list_data *b, core_results *res) { + ee_s16 val1=calc_func(&(a->data16),res); + ee_s16 val2=calc_func(&(b->data16),res); + return val1 - val2; +} + +/* Function: cmp_idx + Compare the idx item in a list cell, and regen the data. + + Can be used by mergesort. +*/ +ee_s32 cmp_idx(list_data *a, list_data *b, core_results *res) { + if (res==NULL) { + a->data16 = (a->data16 & 0xff00) | (0x00ff & (a->data16>>8)); + b->data16 = (b->data16 & 0xff00) | (0x00ff & (b->data16>>8)); + } + return a->idx - b->idx; +} + +void copy_info(list_data *to,list_data *from) { + to->data16=from->data16; + to->idx=from->idx; +} + +/* Benchmark for linked list: + - Try to find multiple data items. + - List sort + - Operate on data from list (crc) + - Single remove/reinsert + * At the end of this function, the list is back to original state +*/ +ee_u16 core_bench_list(core_results *res, ee_s16 finder_idx) { + ee_u16 retval=0; + ee_u16 found=0,missed=0; + list_head *list=res->list; + ee_s16 find_num=res->seed3; + list_head *this_find; + list_head *finder, *remover; + list_data info; + ee_s16 i; + + info.idx=finder_idx; + /* find values in the list, and change the list each time (reverse and cache if value found) */ + for (i=0; inext->info->data16 >> 8) & 1; + } + else { + found++; + if (this_find->info->data16 & 0x1) /* use found value */ + retval+=(this_find->info->data16 >> 9) & 1; + /* and cache next item at the head of the list (if any) */ + if (this_find->next != NULL) { + finder = this_find->next; + this_find->next = finder->next; + finder->next=list->next; + list->next=finder; + } + } + if (info.idx>=0) + info.idx++; +#if CORE_DEBUG + ee_printf("List find %d: [%d,%d,%d]\n",i,retval,missed,found); +#endif + } + retval+=found*4-missed; + /* sort the list by data content and remove one item*/ + if (finder_idx>0) + list=core_list_mergesort(list,cmp_complex,res); + remover=core_list_remove(list->next); + /* CRC data content of list from location of index N forward, and then undo remove */ + finder=core_list_find(list,&info); + if (!finder) + finder=list->next; + while (finder) { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } +#if CORE_DEBUG + ee_printf("List sort 1: %04x\n",retval); +#endif + remover=core_list_undo_remove(remover,list->next); + /* sort the list by index, in effect returning the list to original state */ + list=core_list_mergesort(list,cmp_idx,NULL); + /* CRC data content of list */ + finder=list->next; + while (finder) { + retval=crc16(list->info->data16,retval); + finder=finder->next; + } +#if CORE_DEBUG + ee_printf("List sort 2: %04x\n",retval); +#endif + return retval; +} +/* Function: core_list_init + Initialize list with data. + + Parameters: + blksize - Size of memory to be initialized. + memblock - Pointer to memory block. + seed - Actual values chosen depend on the seed parameter. + The seed parameter MUST be supplied from a source that cannot be determined at compile time + + Returns: + Pointer to the head of the list. + +*/ +list_head *core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed) { + /* calculated pointers for the list */ + ee_u32 per_item=16+sizeof(struct list_data_s); + ee_u32 size=(blksize/per_item)-2; /* to accomodate systems with 64b pointers, and make sure same code is executed, set max list elements */ + list_head *memblock_end=memblock+size; + list_data *datablock=(list_data *)(memblock_end); + list_data *datablock_end=datablock+size; + /* some useful variables */ + ee_u32 i; + list_head *finder,*list=memblock; + list_data info; + + /* create a fake items for the list head and tail */ + list->next=NULL; + list->info=datablock; + list->info->idx=0x0000; + list->info->data16=(ee_s16)0x8080; + memblock++; + datablock++; + info.idx=0x7fff; + info.data16=(ee_s16)0xffff; + core_list_insert_new(list,&info,&memblock,&datablock,memblock_end,datablock_end); + + /* then insert size items */ + for (i=0; inext; + i=1; + while (finder->next!=NULL) { + if (iinfo->idx=i++; + else { + ee_u16 pat=(ee_u16)(i++ ^ seed); /* get a pseudo random number */ + finder->info->idx=0x3fff & (((i & 0x07) << 8) | pat); /* make sure the mixed items end up after the ones in sequence */ + } + finder=finder->next; + } + list = core_list_mergesort(list,cmp_idx,NULL); +#if CORE_DEBUG + ee_printf("Initialized list:\n"); + finder=list; + while (finder) { + ee_printf("[%04x,%04x]",finder->info->idx,(ee_u16)finder->info->data16); + finder=finder->next; + } + ee_printf("\n"); +#endif + return list; +} + +/* Function: core_list_insert + Insert an item to the list + + Parameters: + insert_point - where to insert the item. + info - data for the cell. + memblock - pointer for the list header + datablock - pointer for the list data + memblock_end - end of region for list headers + datablock_end - end of region for list data + + Returns: + Pointer to new item. +*/ +list_head *core_list_insert_new(list_head *insert_point, list_data *info, list_head **memblock, list_data **datablock + , list_head *memblock_end, list_data *datablock_end) { + list_head *newitem; + + if ((*memblock+1) >= memblock_end) + return NULL; + if ((*datablock+1) >= datablock_end) + return NULL; + + newitem=*memblock; + (*memblock)++; + newitem->next=insert_point->next; + insert_point->next=newitem; + + newitem->info=*datablock; + (*datablock)++; + copy_info(newitem->info,info); + + return newitem; +} + +/* Function: core_list_remove + Remove an item from the list. + + Operation: + For a singly linked list, remove by copying the data from the next item + over to the current cell, and unlinking the next item. + + Note: + since there is always a fake item at the end of the list, no need to check for NULL. + + Returns: + Removed item. +*/ +list_head *core_list_remove(list_head *item) { + list_data *tmp; + list_head *ret=item->next; + /* swap data pointers */ + tmp=item->info; + item->info=ret->info; + ret->info=tmp; + /* and eliminate item */ + item->next=item->next->next; + ret->next=NULL; + return ret; +} + +/* Function: core_list_undo_remove + Undo a remove operation. + + Operation: + Since we want each iteration of the benchmark to be exactly the same, + we need to be able to undo a remove. + Link the removed item back into the list, and switch the info items. + + Parameters: + item_removed - Return value from the + item_modified - List item that was modified during + + Returns: + The item that was linked back to the list. + +*/ +list_head *core_list_undo_remove(list_head *item_removed, list_head *item_modified) { + list_data *tmp; + /* swap data pointers */ + tmp=item_removed->info; + item_removed->info=item_modified->info; + item_modified->info=tmp; + /* and insert item */ + item_removed->next=item_modified->next; + item_modified->next=item_removed; + return item_removed; +} + +/* Function: core_list_find + Find an item in the list + + Operation: + Find an item by idx (if not 0) or specific data value + + Parameters: + list - list head + info - idx or data to find + + Returns: + Found item, or NULL if not found. +*/ +list_head *core_list_find(list_head *list,list_data *info) { + if (info->idx>=0) { + while (list && (list->info->idx != info->idx)) + list=list->next; + return list; + } else { + while (list && ((list->info->data16 & 0xff) != info->data16)) + list=list->next; + return list; + } +} +/* Function: core_list_reverse + Reverse a list + + Operation: + Rearrange the pointers so the list is reversed. + + Parameters: + list - list head + info - idx or data to find + + Returns: + Found item, or NULL if not found. +*/ + +list_head *core_list_reverse(list_head *list) { + list_head *next=NULL, *tmp; + while (list) { + tmp=list->next; + list->next=next; + next=list; + list=tmp; + } + return next; +} +/* Function: core_list_mergesort + Sort the list in place without recursion. + + Description: + Use mergesort, as for linked list this is a realistic solution. + Also, since this is aimed at embedded, care was taken to use iterative rather then recursive algorithm. + The sort can either return the list to original order (by idx) , + or use the data item to invoke other other algorithms and change the order of the list. + + Parameters: + list - list to be sorted. + cmp - cmp function to use + + Returns: + New head of the list. + + Note: + We have a special header for the list that will always be first, + but the algorithm could theoretically modify where the list starts. + + */ +list_head *core_list_mergesort(list_head *list, list_cmp cmp, core_results *res) { + list_head *p, *q, *e, *tail; + ee_s32 insize, nmerges, psize, qsize, i; + + insize = 1; + + while (1) { + p = list; + list = NULL; + tail = NULL; + + nmerges = 0; /* count number of merges we do in this pass */ + + while (p) { + nmerges++; /* there exists a merge to be done */ + /* step `insize' places along from p */ + q = p; + psize = 0; + for (i = 0; i < insize; i++) { + psize++; + q = q->next; + if (!q) break; + } + + /* if q hasn't fallen off end, we have two lists to merge */ + qsize = insize; + + /* now we have two lists; merge them */ + while (psize > 0 || (qsize > 0 && q)) { + + /* decide whether next element of merge comes from p or q */ + if (psize == 0) { + /* p is empty; e must come from q. */ + e = q; q = q->next; qsize--; + } else if (qsize == 0 || !q) { + /* q is empty; e must come from p. */ + e = p; p = p->next; psize--; + } else if (cmp(p->info,q->info,res) <= 0) { + /* First element of p is lower (or same); e must come from p. */ + e = p; p = p->next; psize--; + } else { + /* First element of q is lower; e must come from q. */ + e = q; q = q->next; qsize--; + } + + /* add the next element to the merged list */ + if (tail) { + tail->next = e; + } else { + list = e; + } + tail = e; + } + + /* now p has stepped `insize' places along, and q has too */ + p = q; + } + + tail->next = NULL; + + /* If we have done only one merge, we're finished. */ + if (nmerges <= 1) /* allow for nmerges==0, the empty list case */ + return list; + + /* Otherwise repeat, merging lists twice the size */ + insize *= 2; + } +#if COMPILER_REQUIRES_SORT_RETURN + return list; +#endif +} diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/core_main.c b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/core_main.c new file mode 100755 index 000000000..4b48cc062 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/core_main.c @@ -0,0 +1,371 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ + +/* File: core_main.c + This file contains the framework to acquire a block of memory, seed initial parameters, tun t he benchmark and report the results. +*/ +#include "coremark.h" + +/* Function: iterate + Run the benchmark for a specified number of iterations. + + Operation: + For each type of benchmarked algorithm: + a - Initialize the data block for the algorithm. + b - Execute the algorithm N times. + + Returns: + NULL. +*/ +static ee_u16 list_known_crc[] = {(ee_u16)0xd4b0,(ee_u16)0x3340,(ee_u16)0x6a79,(ee_u16)0xe714,(ee_u16)0xe3c1}; +static ee_u16 matrix_known_crc[] = {(ee_u16)0xbe52,(ee_u16)0x1199,(ee_u16)0x5608,(ee_u16)0x1fd7,(ee_u16)0x0747}; +static ee_u16 state_known_crc[] = {(ee_u16)0x5e47,(ee_u16)0x39bf,(ee_u16)0xe5a4,(ee_u16)0x8e3a,(ee_u16)0x8d84}; +void *iterate(void *pres) { + ee_u32 i; + ee_u16 crc; + core_results *res=(core_results *)pres; + ee_u32 iterations=res->iterations; + res->crc=0; + res->crclist=0; + res->crcmatrix=0; + res->crcstate=0; + + for (i=0; icrc=crcu16(crc,res->crc); + crc=core_bench_list(res,-1); + res->crc=crcu16(crc,res->crc); + if (i==0) res->crclist=res->crc; + } + return NULL; +} + +#if (SEED_METHOD==SEED_ARG) +ee_s32 get_seed_args(int i, int argc, char *argv[]); +#define get_seed(x) (ee_s16)get_seed_args(x,argc,argv) +#define get_seed_32(x) get_seed_args(x,argc,argv) +#else /* via function or volatile */ +ee_s32 get_seed_32(int i); +#define get_seed(x) (ee_s16)get_seed_32(x) +#endif + +#if (MEM_METHOD==MEM_STATIC) +ee_u8 static_memblk[TOTAL_DATA_SIZE]; +#endif +char *mem_name[3] = {"Static","Heap","Stack"}; +/* Function: main + Main entry routine for the benchmark. + This function is responsible for the following steps: + + 1 - Initialize input seeds from a source that cannot be determined at compile time. + 2 - Initialize memory block for use. + 3 - Run and time the benchmark. + 4 - Report results, testing the validity of the output if the seeds are known. + + Arguments: + 1 - first seed : Any value + 2 - second seed : Must be identical to first for iterations to be identical + 3 - third seed : Any value, should be at least an order of magnitude less then the input size, but bigger then 32. + 4 - Iterations : Special, if set to 0, iterations will be automatically determined such that the benchmark will run between 10 to 100 secs + +*/ + +#if MAIN_HAS_NOARGC +MAIN_RETURN_TYPE core_main(void) { + int argc=0; + char *argv[1]; +#else +MAIN_RETURN_TYPE core_main(int argc, char *argv[]) { +#endif + ee_u16 i,j=0,num_algorithms=0; + ee_s16 known_id=-1,total_errors=0; + ee_u16 seedcrc=0; + CORE_TICKS total_time; + core_results results[MULTITHREAD]; +#if (MEM_METHOD==MEM_STACK) + ee_u8 stack_memblock[TOTAL_DATA_SIZE*MULTITHREAD]; +#endif + /* first call any initializations needed */ + portable_init(&(results[0].port), &argc, argv); + /* First some checks to make sure benchmark will run ok */ + if (sizeof(struct list_head_s)>128) { + ee_printf("list_head structure too big for comparable data!\n"); + return MAIN_RETURN_VAL; + } + results[0].seed1=get_seed(1); + results[0].seed2=get_seed(2); + results[0].seed3=get_seed(3); + results[0].iterations=get_seed_32(4); +ee_printf("--A0\n"); +#if CORE_DEBUG + results[0].iterations=1; +#endif + results[0].execs=get_seed_32(5); + if (results[0].execs==0) { /* if not supplied, execute all algorithms */ + results[0].execs=ALL_ALGORITHMS_MASK; + } + /* put in some default values based on one seed only for easy testing */ + if ((results[0].seed1==0) && (results[0].seed2==0) && (results[0].seed3==0)) { /* validation run */ + results[0].seed1=0; + results[0].seed2=0; + results[0].seed3=0x66; + } + if ((results[0].seed1==1) && (results[0].seed2==0) && (results[0].seed3==0)) { /* perfromance run */ + results[0].seed1=0x3415; + results[0].seed2=0x3415; + results[0].seed3=0x66; + } +ee_printf("--A1\n"); +#if (MEM_METHOD==MEM_STATIC) + results[0].memblock[0]=(void *)static_memblk; + results[0].size=TOTAL_DATA_SIZE; + results[0].err=0; + #if (MULTITHREAD>1) + #error "Cannot use a static data area with multiple contexts!" + #endif +#elif (MEM_METHOD==MEM_MALLOC) + + for (i=0 ; i1) + if (default_num_contexts>MULTITHREAD) { + default_num_contexts=MULTITHREAD; + } + for (i=0 ; i=0) { + for (i=0 ; i 0) + ee_printf("Iterations/Sec : %f\n",default_num_contexts*results[0].iterations/time_in_secs(total_time)); +#else + ee_printf("Total time (secs): %d\n",time_in_secs(total_time)); + if (time_in_secs(total_time) > 0) + ee_printf("Iterations/Sec : %d\n",default_num_contexts*results[0].iterations/time_in_secs(total_time)); +#endif + // Remove error report if execution time low. + // On Ibex a few loops suffices to get an accurate result. With this check in + // the verilator simulation of coremark will report failure (unless left running + // for a significant number of iterations greatly increasing simulation time). + // The other error checking is useful to determine if the benchmark has been + // broken in some way which is masked if this check is left in. + //if (time_in_secs(total_time) < 10) { + // ee_printf("ERROR! Must execute for at least 10 secs for a valid result!\n"); + // total_errors++; + //} + + ee_printf("Iterations : %lu\n", (long unsigned) default_num_contexts*results[0].iterations); + ee_printf("Compiler version : %s\n",COMPILER_VERSION); + ee_printf("Compiler flags : %s\n",COMPILER_FLAGS); +#if (MULTITHREAD>1) + ee_printf("Parallel %s : %d\n",PARALLEL_METHOD,default_num_contexts); +#endif + ee_printf("Memory location : %s\n",MEM_LOCATION); + /* output for verification */ + ee_printf("seedcrc : 0x%04x\n",seedcrc); + if (results[0].execs & ID_LIST) + for (i=0 ; i1) + ee_printf(" / %d:%s",default_num_contexts,PARALLEL_METHOD); +#endif + ee_printf("\n"); + } +#endif + } + if (total_errors>0) + ee_printf("Errors detected\n"); + if (total_errors<0) + ee_printf("Cannot validate operation for these seed values, please compare with results on a known platform.\n"); + +#if (MEM_METHOD==MEM_MALLOC) + for (i=0 ; i>(from)) & (~(0xffffffff << (to)))) + +#if CORE_DEBUG +void printmat(MATDAT *A, ee_u32 N, char *name) { + ee_u32 i,j; + ee_printf("Matrix %s [%dx%d]:\n",name,N,N); + for (i=0; i N times, + changing the matrix values slightly by a constant amount each time. +*/ +ee_u16 core_bench_matrix(mat_params *p, ee_s16 seed, ee_u16 crc) { + ee_u32 N=p->N; + MATRES *C=p->C; + MATDAT *A=p->A; + MATDAT *B=p->B; + MATDAT val=(MATDAT)seed; + + crc=crc16(matrix_test(N,C,A,B,val),crc); + + return crc; +} + +/* Function: matrix_test + Perform matrix manipulation. + + Parameters: + N - Dimensions of the matrix. + C - memory for result matrix. + A - input matrix + B - operator matrix (not changed during operations) + + Returns: + A CRC value that captures all results calculated in the function. + In particular, crc of the value calculated on the result matrix + after each step by . + + Operation: + + 1 - Add a constant value to all elements of a matrix. + 2 - Multiply a matrix by a constant. + 3 - Multiply a matrix by a vector. + 4 - Multiply a matrix by a matrix. + 5 - Add a constant value to all elements of a matrix. + + After the last step, matrix A is back to original contents. +*/ +ee_s16 matrix_test(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B, MATDAT val) { + ee_u16 crc=0; + MATDAT clipval=matrix_big(val); + + matrix_add_const(N,A,val); /* make sure data changes */ +#if CORE_DEBUG + printmat(A,N,"matrix_add_const"); +#endif + matrix_mul_const(N,C,A,val); + crc=crc16(matrix_sum(N,C,clipval),crc); +#if CORE_DEBUG + printmatC(C,N,"matrix_mul_const"); +#endif + matrix_mul_vect(N,C,A,B); + crc=crc16(matrix_sum(N,C,clipval),crc); +#if CORE_DEBUG + printmatC(C,N,"matrix_mul_vect"); +#endif + matrix_mul_matrix(N,C,A,B); + crc=crc16(matrix_sum(N,C,clipval),crc); +#if CORE_DEBUG + printmatC(C,N,"matrix_mul_matrix"); +#endif + matrix_mul_matrix_bitextract(N,C,A,B); + crc=crc16(matrix_sum(N,C,clipval),crc); +#if CORE_DEBUG + printmatC(C,N,"matrix_mul_matrix_bitextract"); +#endif + + matrix_add_const(N,A,-val); /* return matrix to initial value */ + return crc; +} + +/* Function : matrix_init + Initialize the memory block for matrix benchmarking. + + Parameters: + blksize - Size of memory to be initialized. + memblk - Pointer to memory block. + seed - Actual values chosen depend on the seed parameter. + p - pointers to containing initialized matrixes. + + Returns: + Matrix dimensions. + + Note: + The seed parameter MUST be supplied from a source that cannot be determined at compile time +*/ +ee_u32 core_init_matrix(ee_u32 blksize, void *memblk, ee_s32 seed, mat_params *p) { + ee_u32 N=0; + MATDAT *A; + MATDAT *B; + ee_s32 order=1; + MATDAT val; + ee_u32 i=0,j=0; + if (seed==0) + seed=1; + while (jA=A; + p->B=B; + p->C=(MATRES *)align_mem(B+N*N); + p->N=N; +#if CORE_DEBUG + printmat(A,N,"A"); + printmat(B,N,"B"); +#endif + return N; +} + +/* Function: matrix_sum + Calculate a function that depends on the values of elements in the matrix. + + For each element, accumulate into a temporary variable. + + As long as this value is under the parameter clipval, + add 1 to the result if the element is bigger then the previous. + + Otherwise, reset the accumulator and add 10 to the result. +*/ +ee_s16 matrix_sum(ee_u32 N, MATRES *C, MATDAT clipval) { + MATRES tmp=0,prev=0,cur=0; + ee_s16 ret=0; + ee_u32 i,j; + for (i=0; iclipval) { + ret+=10; + tmp=0; + } else { + ret += (cur>prev) ? 1 : 0; + } + prev=cur; + } + } + return ret; +} + +/* Function: matrix_mul_const + Multiply a matrix by a constant. + This could be used as a scaler for instance. +*/ +void matrix_mul_const(ee_u32 N, MATRES *C, MATDAT *A, MATDAT val) { + ee_u32 i,j; + for (i=0; i0) { + for(i=0;i>3) & 0x3]; + next=4; + break; + case 3: /* float */ + case 4: /* float */ + buf=floatpat[(seed>>3) & 0x3]; + next=8; + break; + case 5: /* scientific */ + case 6: /* scientific */ + buf=scipat[(seed>>3) & 0x3]; + next=8; + break; + case 7: /* invalid */ + buf=errpat[(seed>>3) & 0x3]; + next=8; + break; + default: /* Never happen, just to make some compilers happy */ + break; + } + } + size++; + while (total='0') & (c<='9')) ? 1 : 0; + return retval; +} + +/* Function: core_state_transition + Actual state machine. + + The state machine will continue scanning until either: + 1 - an invalid input is detcted. + 2 - a valid number has been detected. + + The input pointer is updated to point to the end of the token, and the end state is returned (either specific format determined or invalid). +*/ + +enum CORE_STATE core_state_transition( ee_u8 **instr , ee_u32 *transition_count) { + ee_u8 *str=*instr; + ee_u8 NEXT_SYMBOL; + enum CORE_STATE state=CORE_START; + for( ; *str && state != CORE_INVALID; str++ ) { + NEXT_SYMBOL = *str; + if (NEXT_SYMBOL==',') /* end of this input */ { + str++; + break; + } + switch(state) { + case CORE_START: + if(ee_isdigit(NEXT_SYMBOL)) { + state = CORE_INT; + } + else if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) { + state = CORE_S1; + } + else if( NEXT_SYMBOL == '.' ) { + state = CORE_FLOAT; + } + else { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + transition_count[CORE_START]++; + break; + case CORE_S1: + if(ee_isdigit(NEXT_SYMBOL)) { + state = CORE_INT; + transition_count[CORE_S1]++; + } + else if( NEXT_SYMBOL == '.' ) { + state = CORE_FLOAT; + transition_count[CORE_S1]++; + } + else { + state = CORE_INVALID; + transition_count[CORE_S1]++; + } + break; + case CORE_INT: + if( NEXT_SYMBOL == '.' ) { + state = CORE_FLOAT; + transition_count[CORE_INT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) { + state = CORE_INVALID; + transition_count[CORE_INT]++; + } + break; + case CORE_FLOAT: + if( NEXT_SYMBOL == 'E' || NEXT_SYMBOL == 'e' ) { + state = CORE_S2; + transition_count[CORE_FLOAT]++; + } + else if(!ee_isdigit(NEXT_SYMBOL)) { + state = CORE_INVALID; + transition_count[CORE_FLOAT]++; + } + break; + case CORE_S2: + if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) { + state = CORE_EXPONENT; + transition_count[CORE_S2]++; + } + else { + state = CORE_INVALID; + transition_count[CORE_S2]++; + } + break; + case CORE_EXPONENT: + if(ee_isdigit(NEXT_SYMBOL)) { + state = CORE_SCIENTIFIC; + transition_count[CORE_EXPONENT]++; + } + else { + state = CORE_INVALID; + transition_count[CORE_EXPONENT]++; + } + break; + case CORE_SCIENTIFIC: + if(!ee_isdigit(NEXT_SYMBOL)) { + state = CORE_INVALID; + transition_count[CORE_INVALID]++; + } + break; + default: + break; + } + } + *instr=str; + return state; +} diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/core_util.c b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/core_util.c new file mode 100755 index 000000000..79d7cadda --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/core_util.c @@ -0,0 +1,210 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ + +#include "coremark.h" +/* Function: get_seed + Get a values that cannot be determined at compile time. + + Since different embedded systems and compilers are used, 3 different methods are provided: + 1 - Using a volatile variable. This method is only valid if the compiler is forced to generate code that + reads the value of a volatile variable from memory at run time. + Please note, if using this method, you would need to modify core_portme.c to generate training profile. + 2 - Command line arguments. This is the preferred method if command line arguments are supported. + 3 - System function. If none of the first 2 methods is available on the platform, + a system function which is not a stub can be used. + + e.g. read the value on GPIO pins connected to switches, or invoke special simulator functions. +*/ +#if (SEED_METHOD==SEED_VOLATILE) + extern volatile ee_s32 seed1_volatile; + extern volatile ee_s32 seed2_volatile; + extern volatile ee_s32 seed3_volatile; + extern volatile ee_s32 seed4_volatile; + extern volatile ee_s32 seed5_volatile; + ee_s32 get_seed_32(int i) { + ee_s32 retval; + switch (i) { + case 1: + retval=seed1_volatile; + break; + case 2: + retval=seed2_volatile; + break; + case 3: + retval=seed3_volatile; + break; + case 4: + retval=seed4_volatile; + break; + case 5: + retval=seed5_volatile; + break; + default: + retval=0; + break; + } + return retval; + } +#elif (SEED_METHOD==SEED_ARG) +ee_s32 parseval(char *valstring) { + ee_s32 retval=0; + ee_s32 neg=1; + int hexmode=0; + if (*valstring == '-') { + neg=-1; + valstring++; + } + if ((valstring[0] == '0') && (valstring[1] == 'x')) { + hexmode=1; + valstring+=2; + } + /* first look for digits */ + if (hexmode) { + while (((*valstring >= '0') && (*valstring <= '9')) || ((*valstring >= 'a') && (*valstring <= 'f'))) { + ee_s32 digit=*valstring-'0'; + if (digit>9) + digit=10+*valstring-'a'; + retval*=16; + retval+=digit; + valstring++; + } + } else { + while ((*valstring >= '0') && (*valstring <= '9')) { + ee_s32 digit=*valstring-'0'; + retval*=10; + retval+=digit; + valstring++; + } + } + /* now add qualifiers */ + if (*valstring=='K') + retval*=1024; + if (*valstring=='M') + retval*=1024*1024; + + retval*=neg; + return retval; +} + +ee_s32 get_seed_args(int i, int argc, char *argv[]) { + if (argc>i) + return parseval(argv[i]); + return 0; +} + +#elif (SEED_METHOD==SEED_FUNC) +/* If using OS based function, you must define and implement the functions below in core_portme.h and core_portme.c ! */ +ee_s32 get_seed_32(int i) { + ee_s32 retval; + switch (i) { + case 1: + retval=portme_sys1(); + break; + case 2: + retval=portme_sys2(); + break; + case 3: + retval=portme_sys3(); + break; + case 4: + retval=portme_sys4(); + break; + case 5: + retval=portme_sys5(); + break; + default: + retval=0; + break; + } + return retval; +} +#endif + +/* Function: crc* + Service functions to calculate 16b CRC code. + +*/ +ee_u16 crcu8(ee_u8 data, ee_u16 crc ) +{ + ee_u8 i=0,x16=0,carry=0; + + for (i = 0; i < 8; i++) + { + x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1)); + data >>= 1; + + if (x16 == 1) + { + crc ^= 0x4002; + carry = 1; + } + else + carry = 0; + crc >>= 1; + if (carry) + crc |= 0x8000; + else + crc &= 0x7fff; + } + return crc; +} +ee_u16 crcu16(ee_u16 newval, ee_u16 crc) { + crc=crcu8( (ee_u8) (newval) ,crc); + crc=crcu8( (ee_u8) ((newval)>>8) ,crc); + return crc; +} +ee_u16 crcu32(ee_u32 newval, ee_u16 crc) { + crc=crc16((ee_s16) newval ,crc); + crc=crc16((ee_s16) (newval>>16) ,crc); + return crc; +} +ee_u16 crc16(ee_s16 newval, ee_u16 crc) { + return crcu16((ee_u16)newval, crc); +} + +ee_u8 check_data_types() { + ee_u8 retval=0; + if (sizeof(ee_u8) != 1) { + ee_printf("ERROR: ee_u8 is not an 8b datatype!\n"); + retval++; + } + if (sizeof(ee_u16) != 2) { + ee_printf("ERROR: ee_u16 is not a 16b datatype!\n"); + retval++; + } + if (sizeof(ee_s16) != 2) { + ee_printf("ERROR: ee_s16 is not a 16b datatype!\n"); + retval++; + } + if (sizeof(ee_s32) != 4) { + ee_printf("ERROR: ee_s32 is not a 32b datatype!\n"); + retval++; + } + if (sizeof(ee_u32) != 4) { + ee_printf("ERROR: ee_u32 is not a 32b datatype!\n"); + retval++; + } + if (sizeof(ee_ptr_int) != sizeof(int *)) { + // ee_printf("ERROR: ee_ptr_int is not a datatype that holds an int pointer!\n"); + // retval++; + } + if (retval>0) { + ee_printf("ERROR: Please modify the datatypes in core_portme.h!\n"); + } + return retval; +} diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/coremark.h b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/coremark.h new file mode 100755 index 000000000..29b775ac0 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/coremark.h @@ -0,0 +1,174 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ + +/* Topic: Description + This file contains declarations of the various benchmark functions. +*/ + +/* Configuration: TOTAL_DATA_SIZE + Define total size for data algorithms will operate on +*/ +#ifndef TOTAL_DATA_SIZE +#define TOTAL_DATA_SIZE 2*1000 +#endif + +#define SEED_ARG 0 +#define SEED_FUNC 1 +#define SEED_VOLATILE 2 + +#define MEM_STATIC 0 +#define MEM_MALLOC 1 +#define MEM_STACK 2 + +#include "core_portme.h" + +#if HAS_STDIO +#include +#endif +#if HAS_PRINTF +#define ee_printf printf +#endif + +/* Actual benchmark execution in iterate */ +void *iterate(void *pres); + +/* Typedef: secs_ret + For machines that have floating point support, get number of seconds as a double. + Otherwise an unsigned int. +*/ +#if HAS_FLOAT +typedef double secs_ret; +#else +typedef ee_u32 secs_ret; +#endif + +#if MAIN_HAS_NORETURN +#define MAIN_RETURN_VAL +#define MAIN_RETURN_TYPE void +#else +#define MAIN_RETURN_VAL 0 +#define MAIN_RETURN_TYPE int +#endif + +void start_time(void); +void stop_time(void); +CORE_TICKS get_time(void); +secs_ret time_in_secs(CORE_TICKS ticks); + +/* Misc useful functions */ +ee_u16 crcu8(ee_u8 data, ee_u16 crc); +ee_u16 crc16(ee_s16 newval, ee_u16 crc); +ee_u16 crcu16(ee_u16 newval, ee_u16 crc); +ee_u16 crcu32(ee_u32 newval, ee_u16 crc); +ee_u8 check_data_types(void); +void *portable_malloc(ee_size_t size); +void portable_free(void *p); +ee_s32 parseval(char *valstring); + +/* Algorithm IDS */ +#define ID_LIST (1<<0) +#define ID_MATRIX (1<<1) +#define ID_STATE (1<<2) +#define ALL_ALGORITHMS_MASK (ID_LIST|ID_MATRIX|ID_STATE) +#define NUM_ALGORITHMS 3 + +/* list data structures */ +typedef struct list_data_s { + ee_s16 data16; + ee_s16 idx; +} list_data; + +typedef struct list_head_s { + struct list_head_s *next; + struct list_data_s *info; +} list_head; + + +/*matrix benchmark related stuff */ +#define MATDAT_INT 1 +#if MATDAT_INT +typedef ee_s16 MATDAT; +typedef ee_s32 MATRES; +#else +typedef ee_f16 MATDAT; +typedef ee_f32 MATRES; +#endif + +typedef struct MAT_PARAMS_S { + int N; + MATDAT *A; + MATDAT *B; + MATRES *C; +} mat_params; + +/* state machine related stuff */ +/* List of all the possible states for the FSM */ +typedef enum CORE_STATE { + CORE_START=0, + CORE_INVALID, + CORE_S1, + CORE_S2, + CORE_INT, + CORE_FLOAT, + CORE_EXPONENT, + CORE_SCIENTIFIC, + NUM_CORE_STATES +} core_state_e ; + + +/* Helper structure to hold results */ +typedef struct RESULTS_S { + /* inputs */ + ee_s16 seed1; /* Initializing seed */ + ee_s16 seed2; /* Initializing seed */ + ee_s16 seed3; /* Initializing seed */ + void *memblock[4]; /* Pointer to safe memory location */ + ee_u32 size; /* Size of the data */ + ee_u32 iterations; /* Number of iterations to execute */ + ee_u32 execs; /* Bitmask of operations to execute */ + struct list_head_s *list; + mat_params mat; + /* outputs */ + ee_u16 crc; + ee_u16 crclist; + ee_u16 crcmatrix; + ee_u16 crcstate; + ee_s16 err; + /* ultithread specific */ + core_portable port; +} core_results; + +/* Multicore execution handling */ +#if (MULTITHREAD>1) +ee_u8 core_start_parallel(core_results *res); +ee_u8 core_stop_parallel(core_results *res); +#endif + +/* list benchmark functions */ +list_head *core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed); +ee_u16 core_bench_list(core_results *res, ee_s16 finder_idx); + +/* state benchmark functions */ +void core_init_state(ee_u32 size, ee_s16 seed, ee_u8 *p); +ee_u16 core_bench_state(ee_u32 blksize, ee_u8 *memblock, + ee_s16 seed1, ee_s16 seed2, ee_s16 step, ee_u16 crc); + +/* matrix benchmark functions */ +ee_u32 core_init_matrix(ee_u32 blksize, void *memblk, ee_s32 seed, mat_params *p); +ee_u16 core_bench_matrix(mat_params *p, ee_s16 seed, ee_u16 crc); + diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/coremark.md5 b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/coremark.md5 new file mode 100755 index 000000000..0c92b14e3 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/coremark.md5 @@ -0,0 +1,6 @@ +f837f8c5c5c6c0f5ef33bb1badc5ebef core_list_join.c +3c7e2aeca881577ae02d628ad56a584a core_main.c +6fef286af62d28486aa6e6c61fb11841 core_matrix.c +640f7d70fab3ce61da49d0f9eef04f7f core_state.c +85a5a29a1c55be49787bc1e1e7082f80 core_util.c +9233fff3d437a831187153be4da64d23 coremark.h diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/core_portme.c b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/core_portme.c new file mode 100755 index 000000000..75e8b12c6 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/core_portme.c @@ -0,0 +1,129 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ +#include "coremark.h" +#include "core_portme.h" + +#if VALIDATION_RUN + volatile ee_s32 seed1_volatile=0x3415; + volatile ee_s32 seed2_volatile=0x3415; + volatile ee_s32 seed3_volatile=0x66; +#endif +#if PERFORMANCE_RUN + volatile ee_s32 seed1_volatile=0x0; + volatile ee_s32 seed2_volatile=0x0; + volatile ee_s32 seed3_volatile=0x66; +#endif +#if PROFILE_RUN + volatile ee_s32 seed1_volatile=0x8; + volatile ee_s32 seed2_volatile=0x8; + volatile ee_s32 seed3_volatile=0x8; +#endif + volatile ee_s32 seed4_volatile=ITERATIONS; + volatile ee_s32 seed5_volatile=0; +/* Porting : Timing functions + How to capture time and convert to seconds must be ported to whatever is supported by the platform. + e.g. Read value from on board RTC, read value from cpu clock cycles performance counter etc. + Sample implementation for standard time.h and windows.h definitions included. +*/ +CORETIMETYPE barebones_clock() { + //#error "You must implement a method to measure time in barebones_clock()! This function should return current time.\n" + return (*((volatile unsigned int *)0x21000100)); +} +/* Define : TIMER_RES_DIVIDER + Divider to trade off timer resolution and total time that can be measured. + + Use lower values to increase resolution, but make sure that overflow does not occur. + If there are issues with the return value overflowing, increase this value. + */ +#define GETMYTIME(_t) (*_t=barebones_clock()) +#define MYTIMEDIFF(fin,ini) ((fin)-(ini)) +#define TIMER_RES_DIVIDER 1 +#define SAMPLE_TIME_IMPLEMENTATION 1 +#define EE_TICKS_PER_SEC (CLOCKS_PER_SEC / TIMER_RES_DIVIDER) + +/** Define Host specific (POSIX), or target specific global time variables. */ +static CORETIMETYPE start_time_val, stop_time_val; + +/* Function : start_time + This function will be called right before starting the timed portion of the benchmark. + + Implementation may be capturing a system timer (as implemented in the example code) + or zeroing some system parameters - e.g. setting the cpu clocks cycles to 0. +*/ +void start_time(void) { + GETMYTIME(&start_time_val ); +} +/* Function : stop_time + This function will be called right after ending the timed portion of the benchmark. + + Implementation may be capturing a system timer (as implemented in the example code) + or other system parameters - e.g. reading the current value of cpu cycles counter. +*/ +void stop_time(void) { + GETMYTIME(&stop_time_val ); +} +/* Function : get_time + Return an abstract "ticks" number that signifies time on the system. + + Actual value returned may be cpu cycles, milliseconds or any other value, + as long as it can be converted to seconds by . + This methodology is taken to accomodate any hardware or simulated platform. + The sample implementation returns millisecs by default, + and the resolution is controlled by +*/ +CORE_TICKS get_time(void) { + CORE_TICKS elapsed=(CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val)); + return elapsed; +} +/* Function : time_in_secs + Convert the value returned by get_time to seconds. + + The type is used to accomodate systems with no support for floating point. + Default implementation implemented by the EE_TICKS_PER_SEC macro above. +*/ +secs_ret time_in_secs(CORE_TICKS ticks) { + secs_ret retval=((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC; + return retval; +} + +ee_u32 default_num_contexts=1; + +/* Function : portable_init + Target specific initialization code + Test for some common mistakes. +*/ +void portable_init(core_portable *p, int *argc, char *argv[]) +{ + //#error "Call board initialization routines in portable init (if needed), in particular initialize UART!\n" + if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) { + ee_printf("ERROR! Please define ee_ptr_int to a type that holds a pointer!\n"); + } + if (sizeof(ee_u32) != 4) { + ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n"); + } + p->portable_id=1; +} +/* Function : portable_fini + Target specific final code +*/ +void portable_fini(core_portable *p) +{ + p->portable_id=0; +} + + diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/core_portme.h b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/core_portme.h new file mode 100755 index 000000000..5b69a283c --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/core_portme.h @@ -0,0 +1,215 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ +/* Topic : Description + This file contains configuration constants required to execute on different platforms +*/ +#ifndef CORE_PORTME_H +#define CORE_PORTME_H + +#define HAS_FLOAT 0 +#define USE_CLOCK 0 +#define HAS_STDIO 0 +#define HAS_PRINTF 0 +#define MEM_LOCATION "STATIC" +#define SEED_METHOD SEED_VOLATILE +#define MEM_METHOD MEM_STATIC +#define MAIN_HAS_NOARGC 1 +#define MAIN_HAS_NORETURN 1 +#define MULTITHREAD 1 + +/************************/ +/* Data types and settings */ +/************************/ +/* Configuration : HAS_FLOAT + Define to 1 if the platform supports floating point. +*/ +#ifndef HAS_FLOAT +#define HAS_FLOAT 0 +#endif +/* Configuration : HAS_TIME_H + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef HAS_TIME_H +#define HAS_TIME_H 0 +#endif +/* Configuration : USE_CLOCK + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef USE_CLOCK +#define USE_CLOCK 0 +#endif +/* Configuration : HAS_STDIO + Define to 1 if the platform has stdio.h. +*/ +#ifndef HAS_STDIO +#define HAS_STDIO 0 +#endif +/* Configuration : HAS_PRINTF + Define to 1 if the platform has stdio.h and implements the printf function. +*/ +#ifndef HAS_PRINTF +#define HAS_PRINTF 0 +#endif + + +/* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION + Initialize these strings per platform +*/ +#ifndef COMPILER_VERSION + #ifdef __GNUC__ + #define COMPILER_VERSION "GCC"__VERSION__ + #else + #define COMPILER_VERSION "Please put compiler version here (e.g. gcc 4.1)" + #endif +#endif +#ifndef COMPILER_FLAGS + #define COMPILER_FLAGS FLAGS_STR /* "Please put compiler flags here (e.g. -o3)" */ +#endif +#ifndef MEM_LOCATION + #define MEM_LOCATION "STACK" +#endif + +/* Data Types : + To avoid compiler issues, define the data types that need ot be used for 8b, 16b and 32b in . + + *Imprtant* : + ee_ptr_int needs to be the data type used to hold pointers, otherwise coremark may fail!!! +*/ +typedef signed short ee_s16; +typedef unsigned short ee_u16; +typedef signed int ee_s32; +typedef double ee_f32; +typedef unsigned char ee_u8; +typedef unsigned int ee_u32; +typedef ee_u32 ee_ptr_int; +//typedef size_t ee_size_t; +typedef unsigned int ee_size_t; +#define NULL ((void *)0) +/* align_mem : + This macro is used to align an offset to point to a 32b value. It is used in the Matrix algorithm to initialize the input memory blocks. +*/ +#define align_mem(x) (void *)(4 + (((ee_ptr_int)(x) - 1) & ~3)) + +/* Configuration : CORE_TICKS + Define type of return from the timing functions. + */ +#define CORETIMETYPE ee_u32 +typedef ee_u32 CORE_TICKS; + +/* Configuration : SEED_METHOD + Defines method to get seed values that cannot be computed at compile time. + + Valid values : + SEED_ARG - from command line. + SEED_FUNC - from a system function. + SEED_VOLATILE - from volatile variables. +*/ +#ifndef SEED_METHOD +#define SEED_METHOD SEED_VOLATILE +#endif + +/* Configuration : MEM_METHOD + Defines method to get a block of memry. + + Valid values : + MEM_MALLOC - for platforms that implement malloc and have malloc.h. + MEM_STATIC - to use a static memory array. + MEM_STACK - to allocate the data block on the stack (NYI). +*/ +#ifndef MEM_METHOD +//#define MEM_METHOD MEM_STACK +#define MEM_METHOD MEM_STATIC +#endif + +/* Configuration : MULTITHREAD + Define for parallel execution + + Valid values : + 1 - only one context (default). + N>1 - will execute N copies in parallel. + + Note : + If this flag is defined to more then 1, an implementation for launching parallel contexts must be defined. + + Two sample implementations are provided. Use or to enable them. + + It is valid to have a different implementation of and in , + to fit a particular architecture. +*/ +#ifndef MULTITHREAD +#define MULTITHREAD 1 +#define USE_PTHREAD 0 +#define USE_FORK 0 +#define USE_SOCKET 0 +#endif + +/* Configuration : MAIN_HAS_NOARGC + Needed if platform does not support getting arguments to main. + + Valid values : + 0 - argc/argv to main is supported + 1 - argc/argv to main is not supported + + Note : + This flag only matters if MULTITHREAD has been defined to a value greater then 1. +*/ +#ifndef MAIN_HAS_NOARGC +#define MAIN_HAS_NOARGC 0 +#endif + +/* Configuration : MAIN_HAS_NORETURN + Needed if platform does not support returning a value from main. + + Valid values : + 0 - main returns an int, and return value will be 0. + 1 - platform does not support returning a value from main +*/ +#ifndef MAIN_HAS_NORETURN +#define MAIN_HAS_NORETURN 0 +#endif + +/* Variable : default_num_contexts + Not used for this simple port, must cintain the value 1. +*/ +extern ee_u32 default_num_contexts; + +typedef struct CORE_PORTABLE_S { + ee_u8 portable_id; +} core_portable; + +/* target specific init/fini */ +void portable_init(core_portable *p, int *argc, char *argv[]); +void portable_fini(core_portable *p); + +#if !defined(PROFILE_RUN) && !defined(PERFORMANCE_RUN) && !defined(VALIDATION_RUN) +#if (TOTAL_DATA_SIZE==1200) +#define PROFILE_RUN 1 +#elif (TOTAL_DATA_SIZE==2000) +#define PERFORMANCE_RUN 1 +#else +#define VALIDATION_RUN 1 +#endif +#endif + +int ee_printf(const char *fmt, ...); + +#define STOP_SIM ((*(volatile unsigned long *)0x21000000) = 0x000055aa) + +#endif /* CORE_PORTME_H */ diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/core_portme.mak b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/core_portme.mak new file mode 100755 index 000000000..81594697d --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/core_portme.mak @@ -0,0 +1,87 @@ +# Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) +# +# 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. +# +# Original Author: Shay Gal-on + +#File : core_portme.mak + +# Flag : OUTFLAG +# Use this flag to define how to to get an executable (e.g -o) +OUTFLAG= -o +# Flag : CC +# Use this flag to define compiler to use +CC = gcc +# Flag : LD +# Use this flag to define compiler to use +LD = gld +# Flag : AS +# Use this flag to define compiler to use +AS = gas +# Flag : CFLAGS +# Use this flag to define compiler options. Note, you can add compiler options from the command line using XCFLAGS="other flags" +PORT_CFLAGS = -O0 -g +FLAGS_STR = "$(PORT_CFLAGS) $(XCFLAGS) $(XLFLAGS) $(LFLAGS_END)" +CFLAGS = $(PORT_CFLAGS) -I$(PORT_DIR) -I. -DFLAGS_STR=\"$(FLAGS_STR)\" +#Flag : LFLAGS_END +# Define any libraries needed for linking or other flags that should come at the end of the link line (e.g. linker scripts). +# Note : On certain platforms, the default clock_gettime implementation is supported but requires linking of librt. +SEPARATE_COMPILE=1 +# Flag : SEPARATE_COMPILE +# You must also define below how to create an object file, and how to link. +OBJOUT = -o +LFLAGS = +ASFLAGS = +OFLAG = -o +COUT = -c + +LFLAGS_END = +# Flag : PORT_SRCS +# Port specific source files can be added here +# You may also need cvt.c if the fcvt functions are not provided as intrinsics by your compiler! +PORT_SRCS = $(PORT_DIR)/core_portme.c $(PORT_DIR)/ee_printf.c +vpath %.c $(PORT_DIR) +vpath %.s $(PORT_DIR) + +# Flag : LOAD +# For a simple port, we assume self hosted compile and run, no load needed. + +# Flag : RUN +# For a simple port, we assume self hosted compile and run, simple invocation of the executable + +LOAD = echo "Please set LOAD to the process of loading the executable to the flash" +RUN = echo "Please set LOAD to the process of running the executable (e.g. via jtag, or board reset)" + +OEXT = .o +EXE = .bin + +$(OPATH)$(PORT_DIR)/%$(OEXT) : %.c + $(CC) $(CFLAGS) $(XCFLAGS) $(COUT) $< $(OBJOUT) $@ + +$(OPATH)%$(OEXT) : %.c + $(CC) $(CFLAGS) $(XCFLAGS) $(COUT) $< $(OBJOUT) $@ + +$(OPATH)$(PORT_DIR)/%$(OEXT) : %.s + $(AS) $(ASFLAGS) $< $(OBJOUT) $@ + +# Target : port_pre% and port_post% +# For the purpose of this simple port, no pre or post steps needed. + +.PHONY : port_prebuild port_postbuild port_prerun port_postrun port_preload port_postload +port_pre% port_post% : + +# FLAG : OPATH +# Path to the output folder. Default - current folder. +OPATH = ./ +MKDIR = mkdir -p + diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/cvt.c b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/cvt.c new file mode 100755 index 000000000..ee0506d54 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/cvt.c @@ -0,0 +1,117 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. +*/ +#include +#define CVTBUFSIZE 80 +static char CVTBUF[CVTBUFSIZE]; + +static char *cvt(double arg, int ndigits, int *decpt, int *sign, char *buf, int eflag) +{ + int r2; + double fi, fj; + char *p, *p1; + + if (ndigits < 0) ndigits = 0; + if (ndigits >= CVTBUFSIZE - 1) ndigits = CVTBUFSIZE - 2; + r2 = 0; + *sign = 0; + p = &buf[0]; + if (arg < 0) + { + *sign = 1; + arg = -arg; + } + arg = modf(arg, &fi); + p1 = &buf[CVTBUFSIZE]; + + if (fi != 0) + { + p1 = &buf[CVTBUFSIZE]; + while (fi != 0) + { + fj = modf(fi / 10, &fi); + *--p1 = (int)((fj + .03) * 10) + '0'; + r2++; + } + while (p1 < &buf[CVTBUFSIZE]) *p++ = *p1++; + } + else if (arg > 0) + { + while ((fj = arg * 10) < 1) + { + arg = fj; + r2--; + } + } + p1 = &buf[ndigits]; + if (eflag == 0) p1 += r2; + *decpt = r2; + if (p1 < &buf[0]) + { + buf[0] = '\0'; + return buf; + } + while (p <= p1 && p < &buf[CVTBUFSIZE]) + { + arg *= 10; + arg = modf(arg, &fj); + *p++ = (int) fj + '0'; + } + if (p1 >= &buf[CVTBUFSIZE]) + { + buf[CVTBUFSIZE - 1] = '\0'; + return buf; + } + p = p1; + *p1 += 5; + while (*p1 > '9') + { + *p1 = '0'; + if (p1 > buf) + ++*--p1; + else + { + *p1 = '1'; + (*decpt)++; + if (eflag == 0) + { + if (p > buf) *p = '0'; + p++; + } + } + } + *p = '\0'; + return buf; +} + +char *ecvt(double arg, int ndigits, int *decpt, int *sign) +{ + return cvt(arg, ndigits, decpt, sign, CVTBUF, 1); +} + +char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 1); +} + +char *fcvt(double arg, int ndigits, int *decpt, int *sign) +{ + return cvt(arg, ndigits, decpt, sign, CVTBUF, 0); +} + +char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return cvt(arg, ndigits, decpt, sign, buf, 0); +} diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/ee_printf.c b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/ee_printf.c new file mode 100755 index 000000000..d2f505d34 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/riscv32/ee_printf.c @@ -0,0 +1,599 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. +*/ + +#include +#include + +#define ZEROPAD (1<<0) /* Pad with zero */ +#define SIGN (1<<1) /* Unsigned/signed long */ +#define PLUS (1<<2) /* Show plus */ +#define SPACE (1<<3) /* Spacer */ +#define LEFT (1<<4) /* Left justified */ +#define HEX_PREP (1<<5) /* 0x */ +#define UPPERCASE (1<<6) /* 'ABCDEF' */ + +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; +static char *upper_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static ee_size_t strnlen(const char *s, ee_size_t count); + +static ee_size_t strnlen(const char *s, ee_size_t count) +{ + const char *sc; + for (sc = s; *sc != '\0' && count--; ++sc); + return sc - s; +} + +static int skip_atoi(const char **s) +{ + int i = 0; + while (is_digit(**s)) i = i*10 + *((*s)++) - '0'; + return i; +} + +static char *number(char *str, long num, int base, int size, int precision, int type) +{ + char c, sign, tmp[66]; + char *dig = digits; + int i; + + if (type & UPPERCASE) dig = upper_digits; + if (type & LEFT) type &= ~ZEROPAD; + if (base < 2 || base > 36) return 0; + + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) + { + if (num < 0) + { + sign = '-'; + num = -num; + size--; + } + else if (type & PLUS) + { + sign = '+'; + size--; + } + else if (type & SPACE) + { + sign = ' '; + size--; + } + } + + if (type & HEX_PREP) + { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + + i = 0; + + if (num == 0) + tmp[i++] = '0'; + else + { + while (num != 0) + { + tmp[i++] = dig[((unsigned long) num) % (unsigned) base]; + num = ((unsigned long) num) / (unsigned) base; + } + } + + if (i > precision) precision = i; + size -= precision; + if (!(type & (ZEROPAD | LEFT))) while (size-- > 0) *str++ = ' '; + if (sign) *str++ = sign; + + if (type & HEX_PREP) + { + if (base == 8) + *str++ = '0'; + else if (base == 16) + { + *str++ = '0'; + *str++ = digits[33]; + } + } + + if (!(type & LEFT)) while (size-- > 0) *str++ = c; + while (i < precision--) *str++ = '0'; + while (i-- > 0) *str++ = tmp[i]; + while (size-- > 0) *str++ = ' '; + + return str; +} + +static char *eaddr(char *str, unsigned char *addr, int size, int precision, int type) +{ + char tmp[24]; + char *dig = digits; + int i, len; + + if (type & UPPERCASE) dig = upper_digits; + len = 0; + for (i = 0; i < 6; i++) + { + if (i != 0) tmp[len++] = ':'; + tmp[len++] = dig[addr[i] >> 4]; + tmp[len++] = dig[addr[i] & 0x0F]; + } + + if (!(type & LEFT)) while (len < size--) *str++ = ' '; + for (i = 0; i < len; ++i) *str++ = tmp[i]; + while (len < size--) *str++ = ' '; + + return str; +} + +static char *iaddr(char *str, unsigned char *addr, int size, int precision, int type) +{ + char tmp[24]; + int i, n, len; + + len = 0; + for (i = 0; i < 4; i++) + { + if (i != 0) tmp[len++] = '.'; + n = addr[i]; + + if (n == 0) + tmp[len++] = digits[0]; + else + { + if (n >= 100) + { + tmp[len++] = digits[n / 100]; + n = n % 100; + tmp[len++] = digits[n / 10]; + n = n % 10; + } + else if (n >= 10) + { + tmp[len++] = digits[n / 10]; + n = n % 10; + } + + tmp[len++] = digits[n]; + } + } + + if (!(type & LEFT)) while (len < size--) *str++ = ' '; + for (i = 0; i < len; ++i) *str++ = tmp[i]; + while (len < size--) *str++ = ' '; + + return str; +} + +#if HAS_FLOAT + +char *ecvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +char *fcvtbuf(double arg, int ndigits, int *decpt, int *sign, char *buf); +static void ee_bufcpy(char *d, char *s, int count); + +void ee_bufcpy(char *pd, char *ps, int count) { + char *pe=ps+count; + while (ps!=pe) + *pd++=*ps++; +} + +static void parse_float(double value, char *buffer, char fmt, int precision) +{ + int decpt, sign, exp, pos; + char *digits = NULL; + char cvtbuf[80]; + int capexp = 0; + int magnitude; + + if (fmt == 'G' || fmt == 'E') + { + capexp = 1; + fmt += 'a' - 'A'; + } + + if (fmt == 'g') + { + digits = ecvtbuf(value, precision, &decpt, &sign, cvtbuf); + magnitude = decpt - 1; + if (magnitude < -4 || magnitude > precision - 1) + { + fmt = 'e'; + precision -= 1; + } + else + { + fmt = 'f'; + precision -= decpt; + } + } + + if (fmt == 'e') + { + digits = ecvtbuf(value, precision + 1, &decpt, &sign, cvtbuf); + + if (sign) *buffer++ = '-'; + *buffer++ = *digits; + if (precision > 0) *buffer++ = '.'; + ee_bufcpy(buffer, digits + 1, precision); + buffer += precision; + *buffer++ = capexp ? 'E' : 'e'; + + if (decpt == 0) + { + if (value == 0.0) + exp = 0; + else + exp = -1; + } + else + exp = decpt - 1; + + if (exp < 0) + { + *buffer++ = '-'; + exp = -exp; + } + else + *buffer++ = '+'; + + buffer[2] = (exp % 10) + '0'; + exp = exp / 10; + buffer[1] = (exp % 10) + '0'; + exp = exp / 10; + buffer[0] = (exp % 10) + '0'; + buffer += 3; + } + else if (fmt == 'f') + { + digits = fcvtbuf(value, precision, &decpt, &sign, cvtbuf); + if (sign) *buffer++ = '-'; + if (*digits) + { + if (decpt <= 0) + { + *buffer++ = '0'; + *buffer++ = '.'; + for (pos = 0; pos < -decpt; pos++) *buffer++ = '0'; + while (*digits) *buffer++ = *digits++; + } + else + { + pos = 0; + while (*digits) + { + if (pos++ == decpt) *buffer++ = '.'; + *buffer++ = *digits++; + } + } + } + else + { + *buffer++ = '0'; + if (precision > 0) + { + *buffer++ = '.'; + for (pos = 0; pos < precision; pos++) *buffer++ = '0'; + } + } + } + + *buffer = '\0'; +} + +static void decimal_point(char *buffer) +{ + while (*buffer) + { + if (*buffer == '.') return; + if (*buffer == 'e' || *buffer == 'E') break; + buffer++; + } + + if (*buffer) + { + int n = strnlen(buffer,256); + while (n > 0) + { + buffer[n + 1] = buffer[n]; + n--; + } + + *buffer = '.'; + } + else + { + *buffer++ = '.'; + *buffer = '\0'; + } +} + +static void cropzeros(char *buffer) +{ + char *stop; + + while (*buffer && *buffer != '.') buffer++; + if (*buffer++) + { + while (*buffer && *buffer != 'e' && *buffer != 'E') buffer++; + stop = buffer--; + while (*buffer == '0') buffer--; + if (*buffer == '.') buffer--; + while (buffer!=stop) + *++buffer=0; + } +} + +static char *flt(char *str, double num, int size, int precision, char fmt, int flags) +{ + char tmp[80]; + char c, sign; + int n, i; + + // Left align means no zero padding + if (flags & LEFT) flags &= ~ZEROPAD; + + // Determine padding and sign char + c = (flags & ZEROPAD) ? '0' : ' '; + sign = 0; + if (flags & SIGN) + { + if (num < 0.0) + { + sign = '-'; + num = -num; + size--; + } + else if (flags & PLUS) + { + sign = '+'; + size--; + } + else if (flags & SPACE) + { + sign = ' '; + size--; + } + } + + // Compute the precision value + if (precision < 0) + precision = 6; // Default precision: 6 + + // Convert floating point number to text + parse_float(num, tmp, fmt, precision); + + if ((flags & HEX_PREP) && precision == 0) decimal_point(tmp); + if (fmt == 'g' && !(flags & HEX_PREP)) cropzeros(tmp); + + n = strnlen(tmp,256); + + // Output number with alignment and padding + size -= n; + if (!(flags & (ZEROPAD | LEFT))) while (size-- > 0) *str++ = ' '; + if (sign) *str++ = sign; + if (!(flags & LEFT)) while (size-- > 0) *str++ = c; + for (i = 0; i < n; i++) *str++ = tmp[i]; + while (size-- > 0) *str++ = ' '; + + return str; +} + +#endif + +static int ee_vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char *str; + char *s; + + int flags; // Flags to number() + + int field_width; // Width of output field + int precision; // Min. # of digits for integers; max number of chars for from string + int qualifier; // 'h', 'l', or 'L' for integer fields + + for (str = buf; *fmt; fmt++) + { + if (*fmt != '%') + { + *str++ = *fmt; + continue; + } + + // Process flags + flags = 0; +repeat: + fmt++; // This also skips first '%' + switch (*fmt) + { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= HEX_PREP; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + // Get field width + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') + { + fmt++; + field_width = va_arg(args, int); + if (field_width < 0) + { + field_width = -field_width; + flags |= LEFT; + } + } + + // Get the precision + precision = -1; + if (*fmt == '.') + { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') + { + ++fmt; + precision = va_arg(args, int); + } + if (precision < 0) precision = 0; + } + + // Get the conversion qualifier + qualifier = -1; + if (*fmt == 'l' || *fmt == 'L') + { + qualifier = *fmt; + fmt++; + } + + // Default base + base = 10; + + switch (*fmt) + { + case 'c': + if (!(flags & LEFT)) while (--field_width > 0) *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) s = ""; + len = strnlen(s, precision); + if (!(flags & LEFT)) while (len < field_width--) *str++ = ' '; + for (i = 0; i < len; ++i) *str++ = *s++; + while (len < field_width--) *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) + { + field_width = 2 * sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, (unsigned long) va_arg(args, void *), 16, field_width, precision, flags); + continue; + + case 'A': + flags |= UPPERCASE; + + case 'a': + if (qualifier == 'l') + str = eaddr(str, va_arg(args, unsigned char *), field_width, precision, flags); + else + str = iaddr(str, va_arg(args, unsigned char *), field_width, precision, flags); + continue; + + // Integer number formats - set up the flags and "break" + case 'o': + base = 8; + break; + + case 'X': + flags |= UPPERCASE; + + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + + case 'u': + break; + +#if HAS_FLOAT + + case 'f': + str = flt(str, va_arg(args, double), field_width, precision, *fmt, flags | SIGN); + continue; + +#endif + + default: + if (*fmt != '%') *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + + str = number(str, num, base, field_width, precision, flags); + } + + *str = '\0'; + return str - buf; +} + +void uart_send_char(char c) { +//#error "You must implement the method uart_send_char to use this file!\n"; +/* Output of a char to a UART usually follows the following model: + Wait until UART is ready + Write char to UART + Wait until UART is done + + Or in code: + while (*UART_CONTROL_ADDRESS != UART_READY); + *UART_DATA_ADDRESS = c; + while (*UART_CONTROL_ADDRESS != UART_READY); + + Check the UART sample code on your platform or the board documentation. +*/ +*((volatile unsigned char *)0x21000200) = c; +} + +int ee_printf(const char *fmt, ...) +{ + // char buf[256],*p; + char buf[512],*p; + va_list args; + int n=0; + + va_start(args, fmt); + ee_vsprintf(buf, fmt, args); + va_end(args); + p=buf; + while (*p) { + uart_send_char(*p); + n++; + p++; + } + + return n; +} + diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/simple/core_portme.c b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/simple/core_portme.c new file mode 100755 index 000000000..33c863d1e --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/simple/core_portme.c @@ -0,0 +1,128 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ + +#include +#include +#include "coremark.h" + +#if VALIDATION_RUN + volatile ee_s32 seed1_volatile=0x3415; + volatile ee_s32 seed2_volatile=0x3415; + volatile ee_s32 seed3_volatile=0x66; +#endif +#if PERFORMANCE_RUN + volatile ee_s32 seed1_volatile=0x0; + volatile ee_s32 seed2_volatile=0x0; + volatile ee_s32 seed3_volatile=0x66; +#endif +#if PROFILE_RUN + volatile ee_s32 seed1_volatile=0x8; + volatile ee_s32 seed2_volatile=0x8; + volatile ee_s32 seed3_volatile=0x8; +#endif + volatile ee_s32 seed4_volatile=ITERATIONS; + volatile ee_s32 seed5_volatile=0; +/* Porting : Timing functions + How to capture time and convert to seconds must be ported to whatever is supported by the platform. + e.g. Read value from on board RTC, read value from cpu clock cycles performance counter etc. + Sample implementation for standard time.h and windows.h definitions included. +*/ +/* Define : TIMER_RES_DIVIDER + Divider to trade off timer resolution and total time that can be measured. + + Use lower values to increase resolution, but make sure that overflow does not occur. + If there are issues with the return value overflowing, increase this value. + */ +#define NSECS_PER_SEC CLOCKS_PER_SEC +#define CORETIMETYPE clock_t +#define GETMYTIME(_t) (*_t=clock()) +#define MYTIMEDIFF(fin,ini) ((fin)-(ini)) +#define TIMER_RES_DIVIDER 1 +#define SAMPLE_TIME_IMPLEMENTATION 1 +#define EE_TICKS_PER_SEC (NSECS_PER_SEC / TIMER_RES_DIVIDER) + +/** Define Host specific (POSIX), or target specific global time variables. */ +static CORETIMETYPE start_time_val, stop_time_val; + +/* Function : start_time + This function will be called right before starting the timed portion of the benchmark. + + Implementation may be capturing a system timer (as implemented in the example code) + or zeroing some system parameters - e.g. setting the cpu clocks cycles to 0. +*/ +void start_time(void) { + GETMYTIME(&start_time_val ); +} +/* Function : stop_time + This function will be called right after ending the timed portion of the benchmark. + + Implementation may be capturing a system timer (as implemented in the example code) + or other system parameters - e.g. reading the current value of cpu cycles counter. +*/ +void stop_time(void) { + GETMYTIME(&stop_time_val ); +} +/* Function : get_time + Return an abstract "ticks" number that signifies time on the system. + + Actual value returned may be cpu cycles, milliseconds or any other value, + as long as it can be converted to seconds by . + This methodology is taken to accomodate any hardware or simulated platform. + The sample implementation returns millisecs by default, + and the resolution is controlled by +*/ +CORE_TICKS get_time(void) { + CORE_TICKS elapsed=(CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val)); + return elapsed; +} +/* Function : time_in_secs + Convert the value returned by get_time to seconds. + + The type is used to accomodate systems with no support for floating point. + Default implementation implemented by the EE_TICKS_PER_SEC macro above. +*/ +secs_ret time_in_secs(CORE_TICKS ticks) { + secs_ret retval=((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC; + return retval; +} + +ee_u32 default_num_contexts=1; + +/* Function : portable_init + Target specific initialization code + Test for some common mistakes. +*/ +void portable_init(core_portable *p, int *argc, char *argv[]) +{ + if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) { + ee_printf("ERROR! Please define ee_ptr_int to a type that holds a pointer!\n"); + } + if (sizeof(ee_u32) != 4) { + ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n"); + } + p->portable_id=1; +} +/* Function : portable_fini + Target specific final code +*/ +void portable_fini(core_portable *p) +{ + p->portable_id=0; +} + + diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/simple/core_portme.h b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/simple/core_portme.h new file mode 100755 index 000000000..a3607bfbb --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/simple/core_portme.h @@ -0,0 +1,196 @@ +/* +Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) + +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. + +Original Author: Shay Gal-on +*/ + +/* Topic : Description + This file contains configuration constants required to execute on different platforms +*/ +#ifndef CORE_PORTME_H +#define CORE_PORTME_H +/************************/ +/* Data types and settings */ +/************************/ +/* Configuration : HAS_FLOAT + Define to 1 if the platform supports floating point. +*/ +#ifndef HAS_FLOAT +#define HAS_FLOAT 1 +#endif +/* Configuration : HAS_TIME_H + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef HAS_TIME_H +#define HAS_TIME_H 1 +#endif +/* Configuration : USE_CLOCK + Define to 1 if platform has the time.h header file, + and implementation of functions thereof. +*/ +#ifndef USE_CLOCK +#define USE_CLOCK 1 +#endif +/* Configuration : HAS_STDIO + Define to 1 if the platform has stdio.h. +*/ +#ifndef HAS_STDIO +#define HAS_STDIO 1 +#endif +/* Configuration : HAS_PRINTF + Define to 1 if the platform has stdio.h and implements the printf function. +*/ +#ifndef HAS_PRINTF +#define HAS_PRINTF 1 +#endif + +/* Configuration : CORE_TICKS + Define type of return from the timing functions. + */ +#include +typedef clock_t CORE_TICKS; + +/* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION + Initialize these strings per platform +*/ +#ifndef COMPILER_VERSION + #ifdef __GNUC__ + #define COMPILER_VERSION "GCC"__VERSION__ + #else + #define COMPILER_VERSION "Please put compiler version here (e.g. gcc 4.1)" + #endif +#endif +#ifndef COMPILER_FLAGS + #define COMPILER_FLAGS FLAGS_STR /* "Please put compiler flags here (e.g. -o3)" */ +#endif +#ifndef MEM_LOCATION + #define MEM_LOCATION "STACK" +#endif + +/* Data Types : + To avoid compiler issues, define the data types that need ot be used for 8b, 16b and 32b in . + + *Imprtant* : + ee_ptr_int needs to be the data type used to hold pointers, otherwise coremark may fail!!! +*/ +typedef signed short ee_s16; +typedef unsigned short ee_u16; +typedef signed int ee_s32; +typedef double ee_f32; +typedef unsigned char ee_u8; +typedef unsigned int ee_u32; +typedef ee_u32 ee_ptr_int; +typedef size_t ee_size_t; +/* align_mem : + This macro is used to align an offset to point to a 32b value. It is used in the Matrix algorithm to initialize the input memory blocks. +*/ +#define align_mem(x) (void *)(4 + (((ee_ptr_int)(x) - 1) & ~3)) + +/* Configuration : SEED_METHOD + Defines method to get seed values that cannot be computed at compile time. + + Valid values : + SEED_ARG - from command line. + SEED_FUNC - from a system function. + SEED_VOLATILE - from volatile variables. +*/ +#ifndef SEED_METHOD +#define SEED_METHOD SEED_VOLATILE +#endif + +/* Configuration : MEM_METHOD + Defines method to get a block of memry. + + Valid values : + MEM_MALLOC - for platforms that implement malloc and have malloc.h. + MEM_STATIC - to use a static memory array. + MEM_STACK - to allocate the data block on the stack (NYI). +*/ +#ifndef MEM_METHOD +#define MEM_METHOD MEM_STACK +#endif + +/* Configuration : MULTITHREAD + Define for parallel execution + + Valid values : + 1 - only one context (default). + N>1 - will execute N copies in parallel. + + Note : + If this flag is defined to more then 1, an implementation for launching parallel contexts must be defined. + + Two sample implementations are provided. Use or to enable them. + + It is valid to have a different implementation of and in , + to fit a particular architecture. +*/ +#ifndef MULTITHREAD +#define MULTITHREAD 1 +#define USE_PTHREAD 0 +#define USE_FORK 0 +#define USE_SOCKET 0 +#endif + +/* Configuration : MAIN_HAS_NOARGC + Needed if platform does not support getting arguments to main. + + Valid values : + 0 - argc/argv to main is supported + 1 - argc/argv to main is not supported + + Note : + This flag only matters if MULTITHREAD has been defined to a value greater then 1. +*/ +#ifndef MAIN_HAS_NOARGC +#define MAIN_HAS_NOARGC 0 +#endif + +/* Configuration : MAIN_HAS_NORETURN + Needed if platform does not support returning a value from main. + + Valid values : + 0 - main returns an int, and return value will be 0. + 1 - platform does not support returning a value from main +*/ +#ifndef MAIN_HAS_NORETURN +#define MAIN_HAS_NORETURN 0 +#endif + +/* Variable : default_num_contexts + Not used for this simple port, must cintain the value 1. +*/ +extern ee_u32 default_num_contexts; + +typedef struct CORE_PORTABLE_S { + ee_u8 portable_id; +} core_portable; + +/* target specific init/fini */ +void portable_init(core_portable *p, int *argc, char *argv[]); +void portable_fini(core_portable *p); + +#if !defined(PROFILE_RUN) && !defined(PERFORMANCE_RUN) && !defined(VALIDATION_RUN) +#if (TOTAL_DATA_SIZE==1200) +#define PROFILE_RUN 1 +#elif (TOTAL_DATA_SIZE==2000) +#define PERFORMANCE_RUN 1 +#else +#define VALIDATION_RUN 1 +#endif +#endif + +#endif /* CORE_PORTME_H */ diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/simple/core_portme.mak b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/simple/core_portme.mak new file mode 100755 index 000000000..61c3db683 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/coremark/simple/core_portme.mak @@ -0,0 +1,60 @@ +# Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC) +# +# 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. +# +# Original Author: Shay Gal-on + +#File : core_portme.mak + +# Flag : OUTFLAG +# Use this flag to define how to to get an executable (e.g -o) +OUTFLAG= -o +# Flag : CC +# Use this flag to define compiler to use +CC = gcc +# Flag : CFLAGS +# Use this flag to define compiler options. Note, you can add compiler options from the command line using XCFLAGS="other flags" +PORT_CFLAGS = -O2 +FLAGS_STR = "$(PORT_CFLAGS) $(XCFLAGS) $(XLFLAGS) $(LFLAGS_END)" +CFLAGS = $(PORT_CFLAGS) -I$(PORT_DIR) -I. -DFLAGS_STR=\"$(FLAGS_STR)\" +#Flag : LFLAGS_END +# Define any libraries needed for linking or other flags that should come at the end of the link line (e.g. linker scripts). +# Note : On certain platforms, the default clock_gettime implementation is supported but requires linking of librt. +LFLAGS_END = +# Flag : PORT_SRCS +# Port specific source files can be added here +PORT_SRCS = $(PORT_DIR)/core_portme.c +# Flag : LOAD +# For a simple port, we assume self hosted compile and run, no load needed. + +# Flag : RUN +# For a simple port, we assume self hosted compile and run, simple invocation of the executable + +#For native compilation and execution +LOAD = echo Loading done +RUN = + +OEXT = .o +EXE = .exe + +# Target : port_pre% and port_post% +# For the purpose of this simple port, no pre or post steps needed. + +.PHONY : port_prebuild port_postbuild port_prerun port_postrun port_preload port_postload +port_pre% port_post% : + +# FLAG : OPATH +# Path to the output folder. Default - current folder. +OPATH = ./ +MKDIR = mkdir -p + diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/csrc_cheri/cstart.c b/vendor/lowrisc_ibex/dv/cheriot/tests/csrc_cheri/cstart.c index 7c6695504..b1a6e1cb0 100755 --- a/vendor/lowrisc_ibex/dv/cheriot/tests/csrc_cheri/cstart.c +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/csrc_cheri/cstart.c @@ -1,6 +1,11 @@ #include +#ifdef COREMARK +extern int cheri_atest(int); +extern void core_main(void); +#else extern int mymain(int, int); +#endif volatile unsigned int* ramBase; volatile unsigned int* romBase; @@ -8,6 +13,7 @@ volatile unsigned int* uartReg; void* globalRoot; + // Ideally we also set the bounds and permissions when deriving from root, but I don't have enough // information now. void* from_root(unsigned int addr) { @@ -47,9 +53,15 @@ void cstart(void* gRoot, CapReloc* caprelocs, unsigned int nCaprelocs) { romBase = from_root(0x00004000U); ramBase = from_root(0x80000000U); - uartReg = from_root(0x80040200U); + uartReg = from_root(0x83800200U); +#ifdef COREMARK + cheri_atest(0); + core_main(); +#else mymain(0, 0); +#endif + stop_sim(); while (1) {;} diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/csrc_cheri/startup.S b/vendor/lowrisc_ibex/dv/cheriot/tests/csrc_cheri/startup.S index 018f8eb09..c5bc7ce13 100755 --- a/vendor/lowrisc_ibex/dv/cheriot/tests/csrc_cheri/startup.S +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/csrc_cheri/startup.S @@ -11,7 +11,7 @@ _start: cspecialr c3, mtdc # read MTDC address 'd29 (the SL root should be in MTCC which is 28, but how the roots work will change, so probably not worth fixing) - li x11, 0x8003ff00 # setup sp + li x11, 0x8001fff0 # setup sp csetaddr csp, c3, x11 @@ -70,11 +70,32 @@ cont1: nop w3: j w3 .align 4 + +# +# default exception handler +# mtvec: - cincoffset csp, csp, -8 # SP-16 - csc cra, 0(csp) + cincoffset csp, csp, -16 # SP-16 + csc ct0, 0(csp) + csc ct1, 8(csp) + #ccall cheri_fault_handler - clc cra, 0(csp) - cincoffset csp, csp, 8 # SP-16 + + csrr t0, mcause // is this an interrupt or exception + li t1, 0x80000000 + and t0, t0, t1 + beq t0, x0, mtvec_done + + li t1, 0x83800104 // acknowledge interrupts + cspecialr ct0, mtdc + csetaddr ct0, ct0, t1 + li t1, 0x3 + csw t1, (ct0) + +mtvec_done: + clc ct0, 0(csp) + clc ct1, 8(csp) + cincoffset csp, csp, 16 # SP-16 + mret diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/csrc_cheri/util.c b/vendor/lowrisc_ibex/dv/cheriot/tests/csrc_cheri/util.c index 8e1ab8b39..38b2fec44 100755 --- a/vendor/lowrisc_ibex/dv/cheriot/tests/csrc_cheri/util.c +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/csrc_cheri/util.c @@ -10,6 +10,15 @@ void send_char(unsigned char dts) { *uartReg = dts; } +static unsigned int mcycle = 0; +unsigned int get_tmrval(void) { + // volatile unsigned int mcycle; + + // __asm__ __volatile__("csrr %0, mcycle": "=r" (mcycle)); + mcycle += 100000; + + return (mcycle); +} void stop_sim(void) { tohost[0] = 0x1; @@ -21,7 +30,7 @@ void prints(char *buf) { int i; i = 0; - while ((i<32) && (buf[i]!='\0')) { + while ((i<100) && (buf[i]!='\0')) { send_char(buf[i]); i++; } diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/csrc_cheri/util.h b/vendor/lowrisc_ibex/dv/cheriot/tests/csrc_cheri/util.h index 9dbed6798..664f1d402 100755 --- a/vendor/lowrisc_ibex/dv/cheriot/tests/csrc_cheri/util.h +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/csrc_cheri/util.h @@ -1,5 +1,10 @@ +extern volatile unsigned int* uartReg; void send_char(unsigned char); void prints(char *); void stop_sim(void); +unsigned int get_tmrval(void); + +#define UART_SEND_CHAR(x) (*uartReg = (x)) + diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/hello_world/cheri_atest.S b/vendor/lowrisc_ibex/dv/cheriot/tests/hello_world/cheri_atest.S new file mode 100755 index 000000000..695783a17 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/hello_world/cheri_atest.S @@ -0,0 +1,131 @@ +#.option norelax + +.section .text +#.globl cheri_fault_handler +.globl cheri_atest + +.macro PRINTMSG reg, symbol + lui \reg, %hi(\symbol) + addi \reg, \reg, %lo(\symbol) + csetaddr c9, c6, \reg + ccall print_string +.endm + +print_string: # print a string pointed by C9 + cincoffset csp, csp, -8 + csc c11, (csp) + + clb x11, (c9) +print_loop: + csb x11, 512(c5) + cincoffset c9, c9, 0x1 + clb x11, (c9) + bne x11, x0, print_loop + + clc c11, (csp) + cincoffset csp, csp, 8 + cret + +# +# Register allocation for this test +# +# Globals +# -- c2: as the stack capability (created at startup) +# -- c3: as a "full" memory capability (entire address space) +# -- c4: base capability for code execution from SRAM (code r/x) +# -- c5: base capability for peripheral accesses in tb_top +# -- c6: base capability for accessing SRAM (data and cap r/w) +# -- c7: reserved for further use +# +# -- x1/cra: return address +# -- x10/a0: argument/return value for subroutines +# -- x15/a5: is used to pass "argument" to the fault handler. +# +# -- x8, x9(s0,s1): temp variables +# -- x11-x14 (a1-a4): temp varaibles + + +# /////////////////////////////////////// +# init +# /////////////////////////////////////// + +test_init: + + cspecialrw c3, 29, c0 # read MTDC address 'd29, memory root + + lui x11, 0x83800 + csetaddr c5, c3, x11 # set base address to 0x8400_0000 + csetboundsimm c5, c5, 0x800 # set bounds to 0x800 + addi x11, x0, 0x24 + candperm c5, c5, x11 # load/store data permission only + + lui x11, 0x80000 + csetaddr c6, c3, x11 # set base address to 0x8000_0000 + lui x11, 0x4000 + csetbounds c6, c6, x11 # set lengths to 0x400_0000 + addi x11, x0, 0x7f + candperm c6, c6, x11 # full mem data/cap permission only + + auipcc c4, 0 # get PCC capability + lui x11, 0x80000 + csetaddr c4, c4, x11 # set address to 0x8000_0000 + lui x11, 0x40 + csetbounds c4, c4, x11 # set length to 0x80000 + + li x11, 0x83800100 # write to this location to tell TB end of init + csetaddr c8, c6, x11 + li x11, 0xf # enable all faults/interrupts + csw x11, (c8) + + li x9, 0x800 # enable machine-mode ext/tmr/sw interrupts + csrs mie, x9 + + li a0, 0x0 + cret + +# /////////////////////////////////////// +# --- cheri_test (main test for CHERI instructions) +# /////////////////////////////////////// + +cheri_atest: + # save register context so that we won't have issue talking with the C program + # note RISC-V uses x10/x11 (a0/a1) for args/return values, and x12-x17 (a2-7) for args + cincoffset csp, csp, -64 + csc c1, 0(csp) + csc c3, 8(csp) + csc c4, 16(csp) + csc c5, 24(csp) + csc c6, 32(csp) + csc c7, 40(csp) + csc c8, 48(csp) + csc c9, 56(csp) + + ccall test_init + PRINTMSG x11, hello_msg + + j test_exit + +test_exit: + # restore register context + clc c1, 0(csp) + clc c3, 8(csp) + clc c4, 16(csp) + clc c5, 24(csp) + clc c6, 32(csp) + clc c7, 40(csp) + clc c8, 48(csp) + clc c9, 56(csp) + cincoffset csp, csp, 64 + + cret + +.section .rodata + +hello_msg : + .string "Doing something in assembly..\n" + +#.section .tohost +#tohost : +# .dword 0 +#fromhost : +# .dword 0 diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/hello_world/hello_world.c b/vendor/lowrisc_ibex/dv/cheriot/tests/hello_world/hello_world.c deleted file mode 100755 index 639dc3f9d..000000000 --- a/vendor/lowrisc_ibex/dv/cheriot/tests/hello_world/hello_world.c +++ /dev/null @@ -1,16 +0,0 @@ -#include - -// Should not be inlined, because we expect arguments -// in particular registers. -//__attribute__((noinline)) - -extern int cheri_atest(int); - -int mymain () { - char *hello_msg = "Hello world!\n"; - - prints(hello_msg); - - cheri_atest(0); -} - diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/hello_world/test_main.c b/vendor/lowrisc_ibex/dv/cheriot/tests/hello_world/test_main.c new file mode 100755 index 000000000..9d400b973 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/hello_world/test_main.c @@ -0,0 +1,34 @@ +#include + +// Should not be inlined, because we expect arguments +// in particular registers. +//__attribute__((noinline)) + +extern int cheri_atest(int); + +int mymain () { + int fail_flag, result; + + char *hello_msg = "Hello World!\n"; + char *pass_msg = "\nTest passed :-)\n"; + char *fail_msg = "\nTest failed :-(((((\n"; + + prints(hello_msg); + + fail_flag = 0; + + result = cheri_atest(0); + if (result != 0) { + prints(fail_msg); + fail_flag += result; + return -1; + } + + if (fail_flag == 0) { + prints(pass_msg); + } + + return 0; + +} + diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/isa_test1/cheri_atest.S b/vendor/lowrisc_ibex/dv/cheriot/tests/isa_test1/cheri_atest.S new file mode 100755 index 000000000..50f8154cb --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/isa_test1/cheri_atest.S @@ -0,0 +1,1049 @@ +#.option norelax + +.section .text +#.globl cheri_fault_handler +.globl cheri_atest + +.macro PRINTMSG reg, symbol + lui \reg, %hi(\symbol) + addi \reg, \reg, %lo(\symbol) + csetaddr c9, c6, \reg + ccall print_string +.endm + +print_string: # print a string pointed by C9 + cincoffset csp, csp, -8 + csc c11, (csp) + + clb x11, (c9) +print_loop: + csb x11, 512(c5) + cincoffset c9, c9, 0x1 + clb x11, (c9) + bne x11, x0, print_loop + + clc c11, (csp) + cincoffset csp, csp, 8 + cret + +# +# Register allocation for this test +# +# Globals +# -- c2: as the stack capability (created at startup) +# -- c3: as a "full" memory capability (entire address space) +# -- c4: base capability for code execution from SRAM (code r/x) +# -- c5: base capability for peripheral accesses in tb_top +# -- c6: base capability for accessing SRAM (data and cap r/w) +# -- c7: sealing root +# +# -- x1/cra: return address +# -- x10/a0: argument/return value for subroutines +# -- x15/a5: is used to pass "argument" to the fault handler. +# +# -- x8, x9(s0,s1): temp variables +# -- x11-x14 (a1-a4): temp varaibles + + +# /////////////////////////////////////// +# --- CHERI fault hander +# - called by the exception handler (startup) +# /////////////////////////////////////// + +.align 4 # riscv vectors must be 4-bytes aligned + +cheri_fault_handler: + # save context to stack QQQ + cincoffset csp, csp, -24 # SP-16 + csc cra, (csp) + csc c13, 8(csp) + csc c14, 16(csp) + + addi x14, x0, 0 + beq x15, x14, case0 # load/store fault (cheri error) + addi x14, x0, 1 + beq x15, x14, case1 # jump fault + addi x14, x0, 2 + beq x15, x14, case2 # load/store fault (rv32 cheri error) + addi x14, x0, 3 + beq x15, x14, case3 # SCR access fault + addi x14, x0, 4 + beq x15, x14, case4 # CSR access fault + addi x14, x0, 5 + beq x15, x14, case5 # CSR access fault + + j echo1 + +case0: + cmove c12, c8 + j echo1 + +case1: + cmove c8, c12 + j echo1 + +case2: + cmove c12, c8 + j echo1 + +case3: +case4: +case5: + cspecialw mepcc, c8 + j echo1 + +echo1: + addi x13, x0, 0x66 + csb x13, 512(c5) + addi x13, x0, 0x61 + csb x13, 512(c5) + addi x13, x0, 0x75 + csb x13, 512(c5) + addi x13, x0, 0x6c + csb x13, 512(c5) + addi x13, x0, 0x74 + csb x13, 512(c5) + addi x13, x15, 0x30 + csb x13, 512(c5) + addi x13, x0,0x20 + csb x13, 512(c5) + addi x13, x0,0x4f + csb x13, 512(c5) + addi x13, x0,0x4b + csb x13, 512(c5) + addi x13, x0, 0xa + csb x13, 512(c5) + addi x13, x0,0xd + csb x13, 512(c5) + +exit_handler: + clc cra, (csp) + clc c13, 8(csp) + clc c14, 16(csp) + cincoffset csp, csp, 24 # SP+16 + mret + + +# /////////////////////////////////////// +# init +# /////////////////////////////////////// + +test_init: + # setup fault handler for this test suite + cspecialr ct0, mtcc +1: auipcc ct1, %cheri_compartment_pccrel_hi(cheri_fault_handler) + cincoffset ct1, ct1, %cheri_compartment_pccrel_lo(1b) + csetaddr ct0, ct0, t1 + cspecialw mtcc, ct0 + + cspecialrw c3, mtdc, c0 # read MTDC address 'd29, memory root + + lui x11, 0x83800 + csetaddr c5, c3, x11 # set base address to 0x8380_0000 + csetboundsimm c5, c5, 0x800 # set bounds to 0x800 + addi x11, x0, 0x24 + candperm c5, c5, x11 # load/store data permission only + + lui x11, 0x80000 + csetaddr c6, c3, x11 # set base address to 0x8000_0000 + lui x11, 0x4000 + csetbounds c6, c6, x11 # set lengths to 0x400_0000 + addi x11, x0, 0x7f + candperm c6, c6, x11 # full mem data/cap permission only + + auipcc c4, 0 # get PCC capability + lui x11, 0x80000 + csetaddr c4, c4, x11 # set address to 0x8000_0000 + lui x11, 0x40 + csetbounds c4, c4, x11 # set length to 0x80000 + + cspecialr c7, mscratchc + + li a0, 0x0 + cret + + +# /////////////////////////////////////// +# /////////////////////////////////////// +# test set_bounds +# /////////////////////////////////////// +test_bounds: + cincoffset csp, csp, -48 + csc c8, 0(csp) + csc c9, 8(csp) + csc c11, 16(csp) + csc c12, 24(csp) + csc c13, 32(csp) + csc c14, 40(csp) + + # test set_bounds operations + # first start with an unaligned address, so set_bounds should work but + # set_bounds_exact should fail + li x11, 0x80010123 + csetaddr c8, c6, x11 + li x11, 0x800 + csetbounds c12, c8, x11 + csetboundsimm c13, c8, 0x800 + csetequalexact x14, c12, c13 + beq x14, x0, bounds_fail1 + cgettag x14, c12 + beq x14, x0, bounds_fail1 + cgetbase x14, c12 + + csetboundsexact c12, c8, x11 + cgettag x14, c12 + bne x14, x0, bounds_fail1 + + # now align the address so that set_bounds_ext passes + li x11, 0x80010128 + csetaddr c8, c6, x11 + li x11, 0x800 + csetboundsexact c12, c8, x11 + cgettag x14, c12 + beq x14, x0, bounds_fail1 + + # build caps with corner case top/base values (0x0 and 0x1ff) + li x11, 0x800101ff + csetaddr c8, c6, x11 + csetboundsimm c8, c8, 0x1 # top = 0x0, base = 0x1ff + andi x11, x11, 0xff + csb x11, (c8) + clbu x12, (c8) + bne x11, x12, bounds_fail2 + + li x11, 0x80010000 + csetaddr c8, c6, x11 + li x11, 0x1ff0 + csetbounds c8, c8, x11 # top = 0x1ff, base = 0x0 + csw x11, 12(c8) + clw x12, 12(c8) + bne x11, x12, bounds_fail2 + + # test crrl/cram, different length value + li x11, 127 + crrl x12, x11 + cram x12, x11 + li x11, 4096 + crrl x12, x11 + cram x12, x11 + li x11, 8193 + crrl x12, x11 + cram x12, x11 + li x11, 65535 + crrl x12, x11 + cram x12, x11 + + li a0, 0x0 + j bounds_exit + +bounds_fail1: + li a0, 0xf1 # error code + j bounds_exit + +bounds_fail2: + li a0, 0xf2 # error code + j bounds_exit + +bounds_exit: + clc c8, 0(csp) + clc c9, 8(csp) + clc c11, 16(csp) + clc c12, 24(csp) + clc c13, 32(csp) + clc c14, 40(csp) + cincoffset csp, csp, 48 + cret + +# /////////////////////////////////////// +# test set_addr, etc. corner cases +# /////////////////////////////////////// +test_addr: + cincoffset csp, csp, -48 + csc c8, 0(csp) + csc c9, 8(csp) + csc c11, 16(csp) + csc c12, 24(csp) + csc c13, 32(csp) + csc c14, 40(csp) + + # test the exp=24 case (set_addr allows addr < base32) + cspecialr c8, mtdc + li x9, 0x74000010 + cincoffset c8, c8, x9 + csetbounds c8, c8, x9 + cincoffsetimm c8, c8, -0x7d1 + csetbounds c8, c8, x9 + cgettag x11, c8 + bne x11, x0, addr_fail + + # test rollowver case of incaddr + li x12, 1024 + cmove c8, c5 // length = 800, offset = 0; + cincoffsetimm c8, c8, 0x400 + cmove c9, c8 + +test_addr1: + cincoffsetimm c8, c8, 4 + cincoffsetimm c9, c9, -4 + addi x12, x12, -1 + bne x12, x0, test_addr1 + + li a0, 0x0 + j addr_exit + +addr_fail: + li a0, 0xb1 # error code + j bounds_exit + +addr_exit: + clc c8, 0(csp) + clc c9, 8(csp) + clc c11, 16(csp) + clc c12, 24(csp) + clc c13, 32(csp) + clc c14, 40(csp) + cincoffset csp, csp, 48 + cret + +# /////////////////////////////////////// +# test seal/unseal +# /////////////////////////////////////// +test_seal: + cincoffset csp, csp, -64 + csc c8, 0(csp) + csc c9, 8(csp) + csc c11, 16(csp) + csc c12, 24(csp) + csc c13, 32(csp) + csc c14, 40(csp) + csc c1, 48(csp) + + # seal/unseal, interrupt enable/disable with sentries + cmove c8, c7 # sealing root + addi x11, x0, 14 + csetaddr c8, c8, x11 + + # seal+unseal should get the original cap back + cseal c11, c6, c8 + cunseal c11, c11, c8 + csetequalexact x9, c11, c6 + beq x9, x0, seal_fail + + # jump to sentries with interrupt disabled + li x11, 0x2 # sentry = disable intr + csetaddr c8, c8, x11 +2: + auipcc c9, %cheri_compartment_pccrel_hi(seal_cont1) + cincoffset c9, c9, %cheri_compartment_pccrel_lo(2b) + cseal c9, c9, c8 # seal with + cjalr c1, 0(c9) + cjal seal_cont2 + +seal_cont1: + nop + nop + csrr x11, mstatus # find mie status + andi x11, x11, 0x08 + bne x11, x0, seal_fail + + # jump to sentries with interrupt enabled + cjalr c0, 0(c1) + +seal_cont2: + nop + nop + csrr x11, mstatus + andi x11, x11, 0x08 + beq x11, x0, seal_fail + + li a0, 0x0 + j seal_exit +seal_fail: + li a0, 0xf2 # error code + +seal_exit: + clc c8, 0(csp) + clc c9, 8(csp) + clc c11, 16(csp) + clc c12, 24(csp) + clc c13, 32(csp) + clc c14, 40(csp) + clc c1, 48(csp) + cincoffset csp, csp, 64 + cret + +# /////////////////////////////////////// +# test revocation +# /////////////////////////////////////// +test_tsafe: + cincoffset csp, csp, -48 + csc c8, 0(csp) + csc c9, 8(csp) + csc c11, 16(csp) + csc c12, 24(csp) + csc c13, 32(csp) + csc c14, 40(csp) + + lui x11, 0x80010 + csetaddr c8, c6, x11 # set address to 0x8001_0000 + + # build a new capability in c11 + lui x11, 0x80001 + csetaddr c11, c6, x11 + csetboundsimm c11, c11, 0x800 # set lengths to 0x800, base/address to 0x8000_1000 + + # store + load, unrevoked + csc c11, 32(c8) + clc c9, 32(c8) + csetequalexact x12, c9, c11 + beq x12, x0, tsafe_fail + + # revoke the memory pointed by c11 + lui x12, 0x83000 + csetaddr c13, c6, x12 # set address to 0x8300_0000 (revocation map base) + li x12, 1 + csw x12, 64(c13) # set revocation map bit + + clc c9, 32(c8) + cgettag x12, c9 + bne x12, x0, tsafe_fail # returned cap.tag should be cleared + cincoffset c9, c9, 0 # verify ECC updated correctly + + # test the WAR corner case, make sure CLC/tag clearing doesn't affect the write + clc c9, 32(c8) + cmove c9, c8 # this should stall till CLC/trvk is done + csetequalexact x12, c9, c8 + beq x12, x0, tsafe_fail + + li x11, 0x12345678 + clc c9, 32(c8) + add x9, x0, x11 # this should not stall but tag doesn't matter + bne x11, x9, tsafe_fail + + li a0, 0x0 + j tsafe_exit + +tsafe_fail: + li a0, 0xf4 # error code + +tsafe_exit: + clc c8, 0(csp) + clc c9, 8(csp) + clc c11, 16(csp) + clc c12, 24(csp) + clc c13, 32(csp) + clc c14, 40(csp) + cincoffset csp, csp, 48 + cret + +# /////////////////////////////////////// +# test jump faults +# /////////////////////////////////////// + +test_jump: + cincoffset csp, csp, -64 + csc c8, 0(csp) + csc c9, 8(csp) + csc c11, 16(csp) + csc c12, 24(csp) + csc c13, 32(csp) + csc c14, 40(csp) + csc c1, 48(csp) + + # enable ts_safe and do load cap again + # JAL test case + + li x13, 0x246 + add x12, x0, x0 + cjal c1, test_jal1 + beq x12, x13, test_jalr + j jump_fail + +test_jal1: + addi x12, x12, 0x123 + addi x12, x12, 0x123 + cjr c1 + + # JALR test case 1, tag+perm_ex violation +test_jalr: + lui x11, %hi(jalr_ok1) # "correct" jump target + addi x11, x11, %lo(jalr_ok1) + addi x11, x11, -4 # artificially introduce an offset to test JALR + csetaddr c12, c4, x11 + + cincoffset c8, c5, 1024 # just some code here to check cincoffset with sail, + cincoffset c8, c8, 1028 + ccleartag c8, c8 + addi x15, x0, 1 # use x15 to pass argument to fault handler + cjalr c9, 4(c8) # go to fault for the 1st time, handler will fix c8 and resume + +jalr_ok1: + csrr x13, mcause # check mcause and mtval + li x11, 0x1c + bne x11, x13, jump_fail + csrr x13, mtval + li x11, 0x0102 # cause = tag violation + bne x11, x13, jump_fail + + # JALR test case 2, perm_ex violation only + lui x11, %hi(jalr_ok2) # "correct" jump target + addi x11, x11, %lo(jalr_ok2) + addi x11, x11, -16 # artificially introduce an offset to test JALR + csetaddr c12, c4, x11 + + lui x11, %hi(jump_fail) # "failure" jump target + addi x11, x11, %lo(jump_fail) + addi x11, x11, -16 + csetaddr c8, c4, x11 + li x11, 0x1eff + candperm c8, c8, x11 # clear EX permission + addi x15, x0, 1 + cjalr c9, 16(c8) + +jalr_ok2: + csrr x13, mcause # check mcause and mtval + li x11, 0x1c + bne x11, x13, jump_fail + csrr x13, mtval + li x11, 0x0111 + bne x11, x13, jump_fail + + # JALR test case 3, sealed jump target + lui x11, %hi(jalr_ok3) # "correct" jump target + addi x11, x11, %lo(jalr_ok3) + addi x11, x11, -24 # artificially introduce an offset to test JALR + csetaddr c12, c4, x11 + + lui x11, %hi(jump_fail) # "failure" jump target + addi x11, x11, %lo(jump_fail) + addi x11, x11, -16 + csetaddr c8, c4, x11 + + cmove c9, c7 # sealing root + addi x11, x0, 7 + csetaddr c9, c9, x11 + cseal c8, c8, c9 # seal jump target + + addi x15, x0, 1 + cjalr c9, 24(c8) + +jalr_ok3: + csrr x13, mcause # check mcause and mtval + li x11, 0x1c + bne x11, x13, jump_fail + csrr x13, mtval + li x11, 0x0103 + bne x11, x13, jump_fail + + # verify unaligned offset doesn't cause exceptions + lui x11, %hi(jalr_ok4) + addi x11, x11, %lo(jalr_ok4) + csetaddr c8, c8, x11 + j jalr_ok4 +.align 4 +jalr_ok4: + cjalr c0, 5(c8) # offset rounded down to 4, no exceptions, just move to next instr + nop + nop + nop + nop + + li a0, 0x0 + j jump_exit + +jump_fail: + li a0, 0xf5 # error code + +jump_exit: + clc c8, 0(csp) + clc c9, 8(csp) + clc c11, 16(csp) + clc c12, 24(csp) + clc c13, 32(csp) + clc c14, 40(csp) + clc c1, 48(csp) + cincoffset csp, csp, 64 + cret + + +# /////////////////////////////////////// +# test load/store fault conditions +# /////////////////////////////////////// + +test_lsft: + cincoffset csp, csp, -48 + csc c8, 0(csp) + csc c9, 8(csp) + csc c11, 16(csp) + csc c12, 24(csp) + csc c13, 32(csp) + csc c14, 40(csp) + + + # test clc/csc with cheri fault + lui x11, 0x80010 + csetaddr c8, c6, x11 # set address to 08001_0000 + + addi x15, x0, 0 # pass argument to fault handler + li x12, 0x80010011 # clear tag, misaligned address + csetaddr c12, c5, x12 + csc c5, (c12) # introduce a store fault + + csrr x13, mcause # check mcause and mtval + li x12, 0x1c + bne x13, x12, lsft_fail1 + csrr x13, mtval + li x12, 0x182 + bne x13, x12, lsft_fail1 + +lsft_case1: + li x12, 0x80010011 # clear tag, misaligned address + csetaddr c12, c5, x12 + clc c11, (c12) # introduce a load fault + + csrr x13, mcause # check mcause and mtval + li x12, 0x1c + bne x13, x12, lsft_fail1 + csrr x13, mtval + li x12, 0x182 + bne x13, x12, lsft_fail1 + + li x12, 0x80010011 # misaligned address only + csetaddr c12, c6, x12 + clc c11, (c12) # introduce a load fault + csrr x13, mcause # check mcause and mtval + li x12, 0x4 + bne x13, x12, lsft_fail1 + csrr x13, mtval + li x12, 0x80010011 + bne x13, x12, lsft_fail1 + +lsft_case2: + li x12, 0x80010000 # address bound vio, misaligned address + csetaddr c12, c6, x12 + csetboundsimm c12, c12, 0x20 + cincoffsetimm c12, c12, 29 + clc c11, (c12) # introduce a load fault + + csrr x13, mcause # check mcause and mtval + li x12, 0x1c + bne x13, x12, lsft_fail2 + csrr x13, mtval + li x12, 0x181 + bne x13, x12, lsft_fail2 + +# test rv32 access cheri faults +lsft_case3: + li x11, 0x80010013 # unaligned access + csetaddr c8, c6, x11 # set address to 08001_0000 + addi x15, x0, 2 # pass argument to fault handler + + li x11, 0xfffffffc # address bound vio, top oaddress space + csetaddr c12, c3, x11 + csetboundsimm c12, c12, 4 + li x11, 0xffffffff + csetaddr c12, c12, x11 + li x11, 0xdeadbeef + csw x11, (c12) # introduce a store fault + + csrr x13, mcause # check mcause and mtval + li x12, 0x1c + bne x13, x12, lsft_fail3 + csrr x13, mtval + li x12, 0x181 + bne x13, x12, lsft_fail3 + + li a0, 0x0 + j lsft_exit + +lsft_fail1: + li a0, 0xf6 # error code + j lsft_exit + +lsft_fail2: + li a0, 0xf7 # error code + j lsft_exit + +lsft_fail3: + li a0, 0xf7 # error code + j lsft_exit + + +lsft_exit: + clc c8, 0(csp) + clc c9, 8(csp) + clc c11, 16(csp) + clc c12, 24(csp) + clc c13, 32(csp) + clc c14, 40(csp) + cincoffset csp, csp, 48 + cret + + +# /////////////////////////////////////// +# test scr accesses +# /////////////////////////////////////// + +test_scr: + cincoffset csp, csp, -48 + csc c8, 0(csp) + csc c9, 8(csp) + csc c11, 16(csp) + csc c12, 24(csp) + csc c13, 32(csp) + csc c14, 40(csp) + + # + # test SCR access wo/ ASR permission + # + cspecialr c11, mtcc # save content +5: + auipcc c8, %cheri_compartment_pccrel_hi(scr_cont2) # save original pcc/pc in C8 + cincoffset c8, c8, %cheri_compartment_pccrel_lo(5b) +6: + auipcc c9, %cheri_compartment_pccrel_hi(scr_cont1) + cincoffset c9, c9, %cheri_compartment_pccrel_lo(6b) + li x13, 0xff7f + candperm c9, c9, x13 # remove SR permission + cjalr c0, 0(c9) + nop + nop +scr_cont1: + li x13, 0x11223344 + li x15, 0x3 + cspecialrw c0, mtcc, c13 + nop + nop +scr_cont2: + nop + nop + cspecialr c8, mtcc + csetequalexact x9, c8, c11 + beq x9, x0, scr_fail + + csrr x13, mcause # check mcause and mtval + li x12, 0x1c + bne x12, x13, scr_fail + csrr x13, mtval + li x12, 0x0798 + bne x12, x13, scr_fail + + + # + # write to mtdc + # + cspecialr c11, mtdc + cspecialw mtdc,c5 + cspecialr c12, mtdc + csetequalexact x9, c5, c12 + beq x9, x0, scr_fail + cspecialw mtdc, c11 # restore mtdc + cspecialr c12, mtdc + csetequalexact x9, c11, c12 + beq x9, x0, scr_fail + + # + # read/write an illegal SCR address + # +7: + auipcc c8, %cheri_compartment_pccrel_hi(scr_cont3) # save original pcc/pc in C8 + cincoffset c8, c8, %cheri_compartment_pccrel_lo(7b) + nop + li x13, 0x11223344 + li x15, 0x3 + cspecialr c11, 22 # illegal SCR address + nop + nop +scr_cont3: + nop + nop + + csrr x13, mcause # check mcause and mtval + li x12, 0x2 + bne x12, x13, scr_fail + csrr x13, mtval + li x12, 0x0 + bne x12, x13, scr_fail + +8: + auipcc c8, %cheri_compartment_pccrel_hi(scr_cont4) # save original pcc/pc in C8 + cincoffset c8, c8, %cheri_compartment_pccrel_lo(8b) + nop + li x13, 0x11223344 + li x15, 0x3 + cspecialw 22, c11 # illegal SCR address + nop + nop +scr_cont4: + nop + nop + + # this doesn't match sail for now.. QQQ + #csrr x13, mcause # check mcause and mtval + li x12, 0x1c + #bne x12, x13, scr_fail + #csrr x13, mtval + li x12, 0x06d8 + #bne x12, x13, scr_fail + + li a0, 0x0 + j scr_exit + +scr_fail: + li a0, 0xf8 # error code + +scr_exit: + clc c8, 0(csp) + clc c9, 8(csp) + clc c11, 16(csp) + clc c12, 24(csp) + clc c13, 32(csp) + clc c14, 40(csp) + cincoffset csp, csp, 48 + cret + +# /////////////////////////////////////// +# test misc instructions +# /////////////////////////////////////// + +test_misc_instr: + cincoffset csp, csp, -48 + csc c8, 0(csp) + csc c9, 8(csp) + csc c11, 16(csp) + csc c12, 24(csp) + csc c13, 32(csp) + csc c14, 40(csp) + + # doon't worry about checking results here, just compare with sail + cgetlen x11, c5 + cgetlen x12, c4 + cgetperm x11, c5 + cgetperm x12, c4 + cgettype x11, c5 + cgettype x12, c4 + j misc_0 + .align 4 +misc_0: + # cgettop x11, c5 # compiler can't handle this??? + .word 0xff8285db + # cgettop x12, c4 + .word 0xff82065b + # cgethigh x11, c5 # compiler can't handle this yet + .word 0xff7285db + # cgethigh x12, c4 + .word 0xff72065b + + # csethigh c11, c4, x12 # should get c11 = c4, c11.tag = 0 + .word 0x2cc205db + + ctestsubset x11, c5, c5 + ctestsubset x11, c5, c6 + ctestsubset x11, c6, c5 + + # auicgp c11, 8 # compiler can't handle this??? + .word 0x000085fb + # auicgp c11, 0xf8123 + .word 0xf81235fb + + addi x11, x11, 1 # let's verify the meta-data in c11 will cleared by this + # cgethigh x12, c11 + .word 0xff75865b + + li a0, 0x0 + j misc_exit + +misc_fail: + li a0, 0xb8 # error code + +misc_exit: + clc c8, 0(csp) + clc c9, 8(csp) + clc c11, 16(csp) + clc c12, 24(csp) + clc c13, 32(csp) + clc c14, 40(csp) + cincoffset csp, csp, 48 + cret + +# /////////////////////////////////////// +# test ASR permission (CSR/MRET case) +# /////////////////////////////////////// + +test_asr: + cincoffset csp, csp, -48 + csc c8, 0(csp) + csc c9, 8(csp) + csc c11, 16(csp) + csc c12, 24(csp) + csc c13, 32(csp) + csc c14, 40(csp) + + # + # test CSR access wo/ ASR permission + # + lui x11, %hi(asr_cont1) + addi x11, x11, %lo(asr_cont1) + csetaddr c8, c4, x11 + csetaddr c9, c4, x11 + li x13, 0xff7f + candperm c9, c9, x13 # remove SR permission + + li x15, 0x4 + cjalr c0, 0(c9) + nop + nop +asr_cont1: + csrr x13, mcause # check mcause and mtval + li x12, 0x1c + bne x12, x13, asr_fail + csrr x13, mtval + li x12, 0x0418 + bne x12, x13, asr_fail + + # + # test MRET wo/ ASR permission + # + lui x11, %hi(asr_cont2) + addi x11, x11, %lo(asr_cont2) + csetaddr c8, c4, x11 + csetaddr c9, c4, x11 + li x13, 0xff7f + candperm c9, c9, x13 # remove SR permission + + cspecialw mepcc, c9 + + li x15, 0x5 + li x12, 0x00001800 // bit 12:11 (MPP) = 3 to stay in M-priv level + csrs mstatus, x12 + mret // jump to the new PCC + + nop + nop +asr_cont2: + csrr x13, mcause # check mcause and mtval + li x12, 0x1c + bne x12, x13, asr_fail + csrr x13, mtval + li x12, 0x0418 + bne x12, x13, asr_fail + + li a0, 0x0 + j asr_exit + +asr_fail: + li a0, 0xe9 # error code + +asr_exit: + clc c8, 0(csp) + clc c9, 8(csp) + clc c11, 16(csp) + clc c12, 24(csp) + clc c13, 32(csp) + clc c14, 40(csp) + cincoffset csp, csp, 48 + cret + + + + +# /////////////////////////////////////// +# --- cheri_test (main test for CHERI instructions) +# /////////////////////////////////////// + +cheri_atest: + # save register context so that we won't have issue talking with the C program + # note RISC-V uses x10/x11 (a0/a1) for args/return values, and x12-x17 (a2-7) for args + cincoffset csp, csp, -64 + csc c1, 0(csp) + csc c3, 8(csp) + csc c4, 16(csp) + csc c5, 24(csp) + csc c6, 32(csp) + csc c7, 40(csp) + csc c8, 48(csp) + csc c9, 56(csp) + + ccall test_init + PRINTMSG x11, hello_msg + + PRINTMSG x11, test_bounds_msg + ccall test_bounds + bne a0, x0, test_exit + + PRINTMSG x11, test_addr_msg + ccall test_addr + bne a0, x0, test_exit + + PRINTMSG x11, test_seal_msg + ccall test_seal + bne a0, x0, test_exit + + PRINTMSG x11, test_tsafe_msg + ccall test_tsafe + bne a0, x0, test_exit + + PRINTMSG x11, test_jump_msg + ccall test_jump + bne a0, x0, test_exit + + PRINTMSG x11, test_lsft_msg + ccall test_lsft + bne a0, x0, test_exit + + PRINTMSG x11, test_scr_msg + ccall test_scr + bne a0, x0, test_exit + + PRINTMSG x11, test_misc_instr_msg + ccall test_misc_instr + bne a0, x0, test_exit + + PRINTMSG x11, test_asr_msg + ccall test_asr + bne a0, x0, test_exit + + j test_exit + +test_exit: + # restore register context + clc c1, 0(csp) + clc c3, 8(csp) + clc c4, 16(csp) + clc c5, 24(csp) + clc c6, 32(csp) + clc c7, 40(csp) + clc c8, 48(csp) + clc c9, 56(csp) + cincoffset csp, csp, 64 + + cret + +.section .rodata + +hello_msg : + .string "Running assembly test suite \n" +test_bounds_msg : + .string "Testing set_bounds.. \n" +test_addr_msg : + .string "Testing set_addr corner cases.. \n" +test_seal_msg : + .string "Testing seal/unseal.. \n" +test_tsafe_msg : + .string "Testing tsafe.. \n" +test_jump_msg : + .string "Testing cjal/cjalr/jump fault.. \n" +test_lsft_msg : + .string "Testing load/store faults.. \n" +test_scr_msg : + .string "Testing SCR accesses.. \n" +test_misc_instr_msg : + .string "Testing misc instructions.. \n" +test_asr_msg : + .string "Testing ASR perm faults.. \n" + +#.section .tohost +#tohost : +# .dword 0 +#fromhost : +# .dword 0 diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/isa_test1/test_main.c b/vendor/lowrisc_ibex/dv/cheriot/tests/isa_test1/test_main.c new file mode 100755 index 000000000..21ecda66f --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/isa_test1/test_main.c @@ -0,0 +1,34 @@ +#include + +// Should not be inlined, because we expect arguments +// in particular registers. +//__attribute__((noinline)) + +extern int cheri_atest(int); + +int mymain () { + int fail_flag, result; + + char *hello_msg = "Running ISA test 1!\n"; + char *pass_msg = "\nTest passed :-)\n"; + char *fail_msg = "\nTest failed :-(((((\n"; + + prints(hello_msg); + + fail_flag = 0; + + result = cheri_atest(0); + if (result != 0) { + prints(fail_msg); + fail_flag += result; + return -1; + } + + if (fail_flag == 0) { + prints(pass_msg); + } + + return 0; + +} + diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/isa_test1a/cheri_atest.S b/vendor/lowrisc_ibex/dv/cheriot/tests/isa_test1a/cheri_atest.S new file mode 100755 index 000000000..c42b90165 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/isa_test1a/cheri_atest.S @@ -0,0 +1,686 @@ +#.option norelax + +.section .text +#.globl cheri_fault_handler +.globl cheri_atest + +.macro PRINTMSG reg, symbol + lui \reg, %hi(\symbol) + addi \reg, \reg, %lo(\symbol) + csetaddr c9, c6, \reg + ccall print_string +.endm + +print_string: # print a string pointed by C9 + cincoffset csp, csp, -8 + csc c11, (csp) + + clb x11, (c9) +print_loop: + csb x11, 512(c5) + cincoffset c9, c9, 0x1 + clb x11, (c9) + bne x11, x0, print_loop + + clc c11, (csp) + cincoffset csp, csp, 8 + cret + +# +# Register allocation for this test +# +# Globals +# -- c2: as the stack capability (created at startup) +# -- c3: as a "full" memory capability (entire address space) +# -- c4: base capability for code execution from SRAM (code r/x) +# -- c5: base capability for peripheral accesses in tb_top +# -- c6: base capability for accessing SRAM (data and cap r/w) +# -- c7: reserved for further use +# +# -- x1/cra: return address +# -- x10/a0: argument/return value for subroutines +# -- x15/a5: is used to pass "argument" to the fault handler. +# +# -- x8, x9(s0,s1): temp variables +# -- x11-x14 (a1-a4): temp varaibles + + +# /////////////////////////////////////// +# --- CHERI fault hander +# - called by the exception handler (startup) +# /////////////////////////////////////// + +.align 4 # riscv vectors must be 4-bytes aligned + +cheri_fault_handler: + # save context to stack QQQ + cincoffset csp, csp, -24 # SP-16 + csc cra, (csp) + csc c13, 8(csp) + csc c14, 16(csp) + + addi x14, x0, 0 + beq x15, x14, case0 # load/store fault (cheri error) + addi x14, x0, 1 + beq x15, x14, case1 # jump fault + addi x14, x0, 3 + beq x15, x14, case3 # misc fault + addi x14, x0, 5 + beq x15, x14, case5 # pcc fault + addi x14, x0, 6 + beq x15, x14, case6 # pcc fault + addi x14, x0, 7 + beq x15, x14, case7 # pcc fault + addi x14, x0, 8 + beq x15, x14, case8 # pcc fault + + j echo1 + +case0: + # cmove c12, c8 # not used + j echo1 + +case1: + #csetaddr c8, c4, x11 # not used + j echo1 + +case3: + #cspecialw mepcc, c8 # not used + j echo1 + +case5: + cspecialw mepcc, c8 # restart the faulted instruction with a good cap + j echo1 + +case6: + cspecialr c13, mepcc + cspecialw mscratchc, c13 + li x15, 7 # move on the case 7 to recover from the fault + j echo1 + +case7: + cspecialw mepcc, c8 # restart the faulted instruction with a good cap + j echo1 + +case8: + cspecialw mepcc, c8 # restart the faulted instruction with a good cap + j echo1 + +echo1: + addi x13, x0, 0x66 + csb x13, 512(c5) + addi x13, x0, 0x61 + csb x13, 512(c5) + addi x13, x0, 0x75 + csb x13, 512(c5) + addi x13, x0, 0x6c + csb x13, 512(c5) + addi x13, x0, 0x74 + csb x13, 512(c5) + addi x13, x15, 0x30 + csb x13, 512(c5) + addi x13, x0,0x20 + csb x13, 512(c5) + addi x13, x0,0x4f + csb x13, 512(c5) + addi x13, x0,0x4b + csb x13, 512(c5) + addi x13, x0, 0xa + csb x13, 512(c5) + addi x13, x0,0xd + csb x13, 512(c5) + +exit_handler: + clc cra, (csp) + clc c13, 8(csp) + clc c14, 16(csp) + cincoffset csp, csp, 24 # SP+16 + mret + + +# /////////////////////////////////////// +# init +# /////////////////////////////////////// + +test_init: + # setup fault handler for this test suite + cspecialr ct0, mtcc +1: auipcc ct1, %cheri_compartment_pccrel_hi(cheri_fault_handler) + cincoffset ct1, ct1, %cheri_compartment_pccrel_lo(1b) + csetaddr ct0, ct0, t1 + cspecialw mtcc, ct0 + + cspecialrw c3, mtdc, c0 # read MTDC address 'd29, memory root + + lui x11, 0x83800 + csetaddr c5, c3, x11 # set base address to 0x8400_0000 + csetboundsimm c5, c5, 0x800 # set bounds to 0x800 + addi x11, x0, 0x24 + candperm c5, c5, x11 # load/store data permission only + + lui x11, 0x80000 + csetaddr c6, c3, x11 # set base address to 0x8000_0000 + lui x11, 0x4000 + csetbounds c6, c6, x11 # set lengths to 0x400_0000 + addi x11, x0, 0x7f + candperm c6, c6, x11 # full mem data/cap permission only + + auipcc c4, 0 # get PCC capability + lui x11, 0x80000 + csetaddr c4, c4, x11 # set address to 0x8000_0000 + lui x11, 0x40 + csetbounds c4, c4, x11 # set length to 0x80000 + + cspecialr c7, mscratchc # sealing root + + li a0, 0x0 + cret + +# /////////////////////////////////////// +# Test PCC fetch faults and mepcc, test 1 +# /////////////////////////////////////// + +test_pccft1: + cincoffset csp, csp, -48 + csc c8, 0(csp) + csc c9, 8(csp) + csc c11, 16(csp) + csc c12, 24(csp) + csc c13, 32(csp) + csc c14, 40(csp) + + # After the sail change of delayed bound checking (PR37) + # case 1 and case 2 became similar (both clears tag of mepcc) + + # case 1: pcc fetch bound violation, + # handler recovers mepcc (by writing a saved cap to it) + lui x11, %hi(pccft1_1) + addi x11, x11, %lo(pccft1_1) + cmove c8, c4 + csetaddr c8, c8, x11 + csetboundsimm c9, c8, 8 + li x15, 5 // call argument for fault handler + cjalr c0, 0(c9) // tighten PCC bounds + +pccft1_1: + beq x0, x0, pccft1_1_ok // this should cause a fetch error + nop + nop + nop + nop + nop + nop + nop + +pccft1_1_ok: + csrr x13, mcause # check mcause and mtval + li x12, 0x1c + bne x12, x13, pccft1_fail + csrr x13, mtval + li x12, 0x401 + bne x12, x13, pccft1_fail + nop + + # case 2: pcc fetch violation + # 2 faults (first by fectch violation, 2nd by mret/illegal mepcc) + # handler does NOT recover mepcc on the 1st fault, thus mret causes 2 nd fault + lui x11, %hi(pccft1_2) + addi x11, x11, %lo(pccft1_2) + cmove c8, c4 + csetaddr c8, c8, x11 + csetboundsimm c9, c8, 8 + + lui x11, %hi(pccft1_2_ok) // allow c8 to jump to pccft1_2_ok (recover) + addi x11, x11, %lo(pccft1_2_ok) + cmove c8, c4 + csetaddr c8, c8, x11 + + li x15, 6 // call argument for fault handler + cjalr c0, 0(c9) // tighten PCC bounds + +pccft1_2: + beq x0, x0, -100 // somewhere far away enough? 0000 + nop + nop + nop + +pccft1_2_ok: + cspecialr c13, mscratchc # check mepcc from case 6 (tag cleared) + cgettag x11, c13 + bne x11, x0, pccft1_fail + csrr x13, mcause # check mcause and mtval + li x12, 0x1c + bne x12, x13, pccft1_fail + csrr x13, mtval + li x12, 0x402 # tag violation (mepcc tag cleared) + bne x12, x13, pccft1_fail + + li a0, 0x0 + j pccft1_exit + +pccft1_fail: + li a0, 0xfa # error code + +pccft1_exit: + clc c8, 0(csp) + clc c9, 8(csp) + clc c11, 16(csp) + clc c12, 24(csp) + clc c13, 32(csp) + clc c14, 40(csp) + cincoffset csp, csp, 48 + cret + +# /////////////////////////////////////// +# Test PCC fetch faults and mepcc, test 2 +# /////////////////////////////////////// +test_pccft2: + cincoffset csp, csp, -48 + csc c8, 0(csp) + csc c9, 8(csp) + csc c11, 16(csp) + csc c12, 24(csp) + csc c13, 32(csp) + csc c14, 40(csp) + + # case 1: pcc fetch violation, + # write an tag = 0 capability to mepc and use mret to jump to it (PCC) + + lui x11, %hi(pccft2_1) + addi x11, x11, %lo(pccft2_1) + cmove c8, c4 + csetaddr c8, c8, x11 // save recovery address + + csetboundsimm c9, c8, 8 + li x15, 8 // call argument for fault handler + + cspecialw mepcc, c11 + + li x12, 0x00001800 // bit 12:11 (MPP) = 3 to stay in M-priv level + csrs mstatus, x12 + mret // jump to the new PCC + +pccft2_1: + csrr x13, mcause # check mcause and mtval + li x12, 0x1c + bne x12, x13, pccft2_fail + csrr x13, mtval + li x12, 0x402 # tag violation + bne x12, x13, pccft2_fail + nop + + # case 2: pcc fetch violation, + # Write a perm_ex = 0 capability to mepc and use mret to jump to it (PCC) + + lui x11, %hi(pccft2_2) + addi x11, x11, %lo(pccft2_2) + cmove c8, c4 + csetaddr c8, c8, x11 // save recovery address + + csetboundsimm c9, c8, 8 + li x15, 8 // call argument for fault handler + + li x12, 0xfe00 + auipcc c11, 0 + candperm c11, c11, x12 // remove PERM_EX + cspecialw mepcc, c11 + cspecialr c11, mepcc + cgettag x11, c11 + bne x11, x0, pccft2_fail // mepcc legalization should clear tag + + li x12, 0x00001800 // bit 12:11 (MPP) = 3 to stay in M-priv level + csrs mstatus, x12 + mret // jump to the new PCC + +pccft2_2: + csrr x13, mcause # check mcause and mtval + li x12, 0x1c + bne x12, x13, pccft2_fail + csrr x13, mtval + li x12, 0x402 # tag violation + bne x12, x13, pccft2_fail + + # case 3: pcc fetch violation, + # Write a sealed capability to mepc and use mret to jump to it (PCC) + + lui x11, %hi(pccft2_3) + addi x11, x11, %lo(pccft2_3) + cmove c8, c4 + csetaddr c8, c8, x11 // save recovery address + + csetboundsimm c9, c8, 8 + li x15, 8 // call argument for fault handler + + cmove c12, c7 # sealing root + addi x11, x0, 0x7 + csetaddr c12, c12, x11 + + auipcc c11, 0 + cseal c11, c11, c12 + cspecialw mepcc, c11 + + li x12, 0x00001800 // bit 12:11 (MPP) = 3 to stay in M-priv level + csrs mstatus, x12 + mret // jump to the new PCC + +pccft2_3: + csrr x13, mcause # check mcause and mtval + li x12, 0x1 + #bne x12, x13, pccft2_fail + + li a0, 0x0 + j pccft2_exit + +pccft2_fail: + li a0, 0xfc # error code + +pccft2_exit: + clc c8, 0(csp) + clc c9, 8(csp) + clc c11, 16(csp) + clc c12, 24(csp) + clc c13, 32(csp) + clc c14, 40(csp) + cincoffset csp, csp, 48 + cret + +# /////////////////////////////////////// +# Test stack high watermark feature +# /////////////////////////////////////// +test_shwm: + cincoffset csp, csp, -48 + csc c8, 0(csp) + csc c9, 8(csp) + csc c11, 16(csp) + csc c12, 24(csp) + csc c13, 32(csp) + csc c14, 40(csp) + + cspecialrw c6, mtdc, c0 # read MTDC address 'd29, memory root + li x11, 0x80010000 + csetaddr c8, c6, x11 + csw x11, 28(c8) # initialize the address so that we won't get X complaints + + li x11, 0x80010000 + csrw 0xbc2, x11 # WM Base + li x11, 0x80010020 + csrw 0xbc1, x11 # WM ptr + csrr x12, 0xbc1 # verify we can write to the newCSR + bne x12, x11, shwm_fail + + clw x11, 28(c8) # verify read access won't change WM + csrr x12, 0xbc1 + li x11, 0x80010020 + bne x12, x11, shwm_fail + + csw x11, 28(c8) # verify update WM (round down) + csrr x12, 0xbc1 + li x11, 0x80010010 + bne x12, x11, shwm_fail + csw x11, 16(c8) + csrr x12, 0xbc1 + li x11, 0x80010010 + bne x12, x11, shwm_fail + + csw x11, -16(c8) # verify out-of-bound access won't change WM + csrr x12, 0xbc1 + li x11, 0x80010010 + bne x12, x11, shwm_fail + + csw x11, 4(c8) # verify round down to base + csrr x12, 0xbc1 + li x11, 0x80010000 + bne x12, x11, shwm_fail + + csrr x12, 0xbc2 + li x11, 0x80010000 + bne x12, x11, shwm_fail + +shwm_done: + li a0, 0x0 + j shwm_exit + +shwm_fail: + li a0, 0xe0 # error code + +shwm_exit: + clc c8, 0(csp) + clc c9, 8(csp) + clc c11, 16(csp) + clc c12, 24(csp) + clc c13, 32(csp) + clc c14, 40(csp) + cincoffset csp, csp, 48 + cret + +# /////////////////////////////////////// +# Test MTCC/mepcc legalization +# /////////////////////////////////////// +test_mtcc: + cincoffset csp, csp, -48 + csc c8, 0(csp) + csc c9, 8(csp) + csc c11, 16(csp) + csc c12, 24(csp) + csc c13, 32(csp) + csc c14, 40(csp) + + # test mtvec legalization + cspecialr c8, mtcc # save mtcc + cgettag x11, c8 + beq x11, x0, mtcc_fail + + cmove c9, c8 + li x11, 0x1eff + candperm c9, c9, x11 # remove perm_ex + cspecialw mtcc, c9 + cspecialr c9, mtcc + cgettag x11, c9 + bne x11, x0, mtcc_fail + + cmove c10, c7 # sealing root + addi x11, x0, 0x5 + csetaddr c10, c10, x11 + cmove c9, c8 + cseal c9, c9, c10 # seal and write to mtcc + cspecialw mtcc, c9 + cspecialr c9, mtcc + cgettag x11, c9 + bne x11, x0, mtcc_fail + + cmove c9, c8 + cincoffset c9, c9, 1 # addr[1:0] != 0; + cspecialw mtcc, c9 + cspecialr c9, mtcc + cgettag x11, c9 + bne x11, x0, mtcc_fail + + cmove c9, c8 + cincoffset c9, c9, 2 # addr[1:0] != 0; + cspecialw mtcc, c9 + cspecialr c9, mtcc + cgettag x11, c9 + bne x11, x0, mtcc_fail + + cmove c9, c8 + cincoffset c9, c9, 3 # addr[1:0] != 0; + cspecialw mtcc, c9 + cspecialr c9, mtcc + cgettag x11, c9 + bne x11, x0, mtcc_fail + + cspecialw mtcc, c8 # restore mtcc + cspecialr c9, mtcc + cseqx x11, c8, c9 + beq x11, x0, mtcc_fail + + # test address[0] of mepcc write +mepcc_test: + auipcc c9, 0 + cspecialw mepcc, c9 + cspecialr c9, mepcc + cgettag x11, c9 + beq x11, x0, mtcc_fail + + cincoffset c9, c9, 1 # addr[1:0] != 0; + cspecialw mepcc, c9 + cspecialr c9, mepcc + cgettag x11, c9 + bne x11, x0, mtcc_fail + + li a0, 0x0 + j mtcc_exit + +mtcc_fail: + li a0, 0xea # error code + +mtcc_exit: + clc c8, 0(csp) + clc c9, 8(csp) + clc c11, 16(csp) + clc c12, 24(csp) + clc c13, 32(csp) + clc c14, 40(csp) + cincoffset csp, csp, 48 + cret + +# /////////////////////////////////////// +# Test CLC permission behaviors +# /////////////////////////////////////// +test_clcp: + cincoffset csp, csp, -48 + csc c8, 0(csp) + csc c9, 8(csp) + csc c11, 16(csp) + csc c12, 24(csp) + csc c13, 32(csp) + csc c14, 40(csp) + + li x11, 0x80010000 + csetaddr c8, c6, x11 + csc c6, 32(c8) + + li x11, 0x1fbf # remove PERM_MC + candperm c9, c8, x11 + + # tag is cleared if auth_cap doesn't have PERM_MC + clc c12, 32(c8) + cseqx x11, c12, c6 + beq x11, x0, clcp_fail + + clc c13, 32(c9) + ccleartag c12, c12 + cseqx x11, c12, c13 + beq x11, x0, clcp_fail + + # //if tag is already cleared, remove PERM_LG from cs1 does not change perms + clc c12, 32(c8) + li x11, 0x1fbd # remove PERM_MC and PERM_LG + candperm c9, c8, x11 + clc c13, 32(c9) + ccleartag c12, c12 + cseqx x11, c12, c13 + beq x11, x0, clcp_fail + + # //if tag is not cleared, remove PERM_LG from cs1 clears PERM_LG/PERM_GL on loaded cap + clc c12, 32(c8) + li x11, 0x1ffd # remove PERM_MC and PERM_LG + candperm c9, c8, x11 + clc c13, 32(c9) + li x11, 0x1ffc + candperm c12, c12, x11 + cseqx x11, c12, c13 + beq x11, x0, clcp_fail + +clcp_done: + li a0, 0x0 + j clcp_exit + +clcp_fail: + li a0, 0xe0 # error code + +clcp_exit: + clc c8, 0(csp) + clc c9, 8(csp) + clc c11, 16(csp) + clc c12, 24(csp) + clc c13, 32(csp) + clc c14, 40(csp) + cincoffset csp, csp, 48 + cret + + +# /////////////////////////////////////// +# --- cheri_test (main test for CHERI instructions) +# /////////////////////////////////////// + +cheri_atest: + # save register context so that we won't have issue talking with the C program + # note RISC-V uses x10/x11 (a0/a1) for args/return values, and x12-x17 (a2-7) for args + cincoffset csp, csp, -64 + csc c1, 0(csp) + csc c3, 8(csp) + csc c4, 16(csp) + csc c5, 24(csp) + csc c6, 32(csp) + csc c7, 40(csp) + csc c8, 48(csp) + csc c9, 56(csp) + + ccall test_init + PRINTMSG x11, hello_msg + + PRINTMSG x11, test_pccft1_msg + ccall test_pccft1 + bne a0, x0, test_exit + + PRINTMSG x11, test_pccft2_msg + ccall test_pccft2 + bne a0, x0, test_exit + + PRINTMSG x11, test_mtcc_msg + ccall test_mtcc + bne a0, x0, test_exit + + PRINTMSG x11, test_clcp_msg + ccall test_clcp + bne a0, x0, test_exit + + PRINTMSG x11, test_shwm_msg + ccall test_shwm + bne a0, x0, test_exit + +test_exit: + # restore register context + clc c1, 0(csp) + clc c3, 8(csp) + clc c4, 16(csp) + clc c5, 24(csp) + clc c6, 32(csp) + clc c7, 40(csp) + clc c8, 48(csp) + clc c9, 56(csp) + cincoffset csp, csp, 64 + + cret + +.section .rodata + +hello_msg : + .string "Running assembly test suite\n" +test_pccft1_msg : + .string "Testing PCC fetch fault, part 1.. \n" +test_pccft2_msg : + .string "Testing PCC fetch fault, part 2.. \n" +test_shwm_msg : + .string "Testing MSHWM.. \n" +test_mtcc_msg : + .string "Testing SCR.. \n" +test_clcp_msg : + .string "Testing CLC permissions.. \n" + +#.section .tohost +#tohost : +# .dword 0 +#fromhost : +# .dword 0 diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/isa_test1a/test_main.c b/vendor/lowrisc_ibex/dv/cheriot/tests/isa_test1a/test_main.c new file mode 100755 index 000000000..4117da581 --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/isa_test1a/test_main.c @@ -0,0 +1,34 @@ +#include + +// Should not be inlined, because we expect arguments +// in particular registers. +//__attribute__((noinline)) + +extern int cheri_atest(int); + +int mymain () { + int fail_flag, result; + + char *hello_msg = "Running ISA test 1a!\n"; + char *pass_msg = "\nTest passed :-)\n"; + char *fail_msg = "\nTest failed :-(((((\n"; + + prints(hello_msg); + + fail_flag = 0; + + result = cheri_atest(0); + if (result != 0) { + prints(fail_msg); + fail_flag += result; + return -1; + } + + if (fail_flag == 0) { + prints(pass_msg); + } + + return 0; + +} + diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/isa_test2/cheri_atest.S b/vendor/lowrisc_ibex/dv/cheriot/tests/isa_test2/cheri_atest.S new file mode 100755 index 000000000..44043ee6e --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/isa_test2/cheri_atest.S @@ -0,0 +1,132 @@ +#.option norelax + +.section .text +.globl cheri_atest + +.macro PRINTMSG reg, symbol + lui \reg, %hi(\symbol) + addi \reg, \reg, %lo(\symbol) + csetaddr c9, c6, \reg + ccall print_string +.endm + +print_string: # print a string pointed by C9 + cincoffset csp, csp, -8 + csc c11, (csp) + + clb x11, (c9) +print_loop: + csb x11, 512(c5) + cincoffset c9, c9, 0x1 + clb x11, (c9) + bne x11, x0, print_loop + + clc c11, (csp) + cincoffset csp, csp, 8 + cret + +# +# Register allocation for this test +# +# Globals +# -- c2: as the stack capability (created at startup) +# -- c3: as a "full" memory capability (entire address space) +# -- c4: base capability for code execution from SRAM (code r/x) +# -- c5: base capability for peripheral accesses in tb_top +# -- c6: base capability for accessing SRAM (data and cap r/w) +# -- c7: reserved for further use +# +# -- x1/cra: return address +# -- x10/a0: argument/return value for subroutines +# -- x15/a5: is used to pass "argument" to the fault handler. +# +# -- x8, x9(s0,s1): temp variables +# -- x11-x14 (a1-a4): temp varaibles + + +# /////////////////////////////////////// +# init +# /////////////////////////////////////// + +test_init: + cspecialrw c3, mtdc, c0 # read MTDC address 'd29, memory root + + lui x11, 0x83800 + csetaddr c5, c3, x11 # set base address to 0x8400_0000 + csetboundsimm c5, c5, 0x800 # set bounds to 0x800 + addi x11, x0, 0x24 + candperm c5, c5, x11 # load/store data permission only + + lui x11, 0x80000 + csetaddr c6, c3, x11 # set base address to 0x8000_0000 + lui x11, 0x4000 + csetbounds c6, c6, x11 # set lengths to 0x400_0000 + addi x11, x0, 0x7f + candperm c6, c6, x11 # full mem data/cap permission only + + auipcc c4, 0 # get PCC capability + lui x11, 0x80000 + csetaddr c4, c4, x11 # set address to 0x8000_0000 + lui x11, 0x40 + csetbounds c4, c4, x11 # set length to 0x80000 + + cspecialr c7, mscratchc + + li x11, 0x83800100 # write to this location to tell TB end of init + csetaddr c8, c6, x11 + li x11, 0xf + csw x11, (c8) + + li x9, 0x800 # enable machine-mode ext/tmr/sw interrupts + csrs mie, x9 + + li a0, 0x0 + cret + + +# /////////////////////////////////////// +# --- cheri_test (main test for CHERI instructions) +# /////////////////////////////////////// + +cheri_atest: + # save register context so that we won't have issue talking with the C program + # note RISC-V uses x10/x11 (a0/a1) for args/return values, and x12-x17 (a2-7) for args + cincoffset csp, csp, -64 + csc c1, 0(csp) + csc c3, 8(csp) + csc c4, 16(csp) + csc c5, 24(csp) + csc c6, 32(csp) + csc c7, 40(csp) + csc c8, 48(csp) + csc c9, 56(csp) + + ccall test_init + PRINTMSG x11, hello_msg + + j test_exit + +test_exit: + # restore register context + clc c1, 0(csp) + clc c3, 8(csp) + clc c4, 16(csp) + clc c5, 24(csp) + clc c6, 32(csp) + clc c7, 40(csp) + clc c8, 48(csp) + clc c9, 56(csp) + cincoffset csp, csp, 64 + + cret + +.section .rodata + +hello_msg : + .string "Doing something in assembly..\n" + +#.section .tohost +#tohost : +# .dword 0 +#fromhost : +# .dword 0 diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/isa_test2/test_main.c b/vendor/lowrisc_ibex/dv/cheriot/tests/isa_test2/test_main.c new file mode 100755 index 000000000..9663eec7a --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/isa_test2/test_main.c @@ -0,0 +1,71 @@ +#include + +// Should not be inlined, because we expect arguments +// in particular registers. +//__attribute__((noinline)) + +extern int cheri_atest(int); + +unsigned int temp_array[16]; +volatile unsigned char *ptr1; + +int mymain () { + int fail_flag, result; + int i, j; + unsigned int tint1, tint2; + unsigned short ts1, ts2; + + char *hello_msg = "Running ISA test 2!\n"; + char *unaligned_msg = "Testing unaligned load/stores..\n"; + char *pass_msg = "\nTest passed :-)\n"; + char *fail_msg = "\nTest failed :-(((((\n"; + + prints(hello_msg); + + fail_flag = 0; + + result = cheri_atest(0); + if (result != 0) { + prints(fail_msg); + fail_flag += result; + return -1; + } + + // initialze the array to get rid of the IbexDataRPayloadX assertions + for (i=0; i<16;i++) temp_array[i] = 0; + + // test unaligned word accesses + prints(unaligned_msg); + + for (i=0; i< 20; i++) { + tint1 = 0xdeadbeef; + ptr1 = (unsigned char *) &temp_array; + for (j=0; j < 32; j++) { + ptr1++; + *((volatile unsigned int *) ptr1) = tint1; + tint2 = *((volatile unsigned int *) ptr1); + if (tint1 != tint2) {fail_flag++;} + tint1 += 0x12345678; + } + } + + for (i=0; i< 20; i++) { + ts1 = 0xabcd; + ptr1 = (unsigned char *) &temp_array; + for (j=0; j < 32; j++) { + ptr1++; + *((volatile unsigned short *) ptr1) = ts1; + ts2 = *((volatile unsigned short *) ptr1); + if (ts1 != ts2) {fail_flag++;} + ts1 += 0x1213; + } + } + + if (fail_flag == 0) { + prints(pass_msg); + } + + return 0; + +} + diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/link_coremark.ld b/vendor/lowrisc_ibex/dv/cheriot/tests/link_coremark.ld new file mode 100755 index 000000000..16c4d0bec --- /dev/null +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/link_coremark.ld @@ -0,0 +1,33 @@ +ENTRY(_start) + +SECTIONS +{ + . = 0x80000000; + .pcc : + { + HIDDEN(__pcc_start = .); + . = 0x80000080; + startup.o(.text) + . = ALIGN(0x100); + *(.text .text.*); + *(.data.rel.ro); + *(.rodata .rodata.*); + HIDDEN(__pcc_end = .); + } + + . = 0x80004000; + .cgp : ALIGN(0x8) + { + HIDDEN(__cgp_start = .); + *(.data .data.*); + *(.sdata .sdata.*); + *(.bss .bss.*); + *(.sbss .sbss.*); + HIDDEN(__cgp_end = .); + } + __cap_relocs : + { + __cap_relocs = .; + } + __cap_relocs_end = .; +} diff --git a/vendor/lowrisc_ibex/dv/cheriot/tests/link_test.ld b/vendor/lowrisc_ibex/dv/cheriot/tests/link_test.ld index e6d31b3f7..c11621362 100755 --- a/vendor/lowrisc_ibex/dv/cheriot/tests/link_test.ld +++ b/vendor/lowrisc_ibex/dv/cheriot/tests/link_test.ld @@ -14,7 +14,7 @@ SECTIONS HIDDEN(__pcc_end = .); } - . = 0x80010000; + . = 0x80004000; .cgp : ALIGN(0x8) { HIDDEN(__cgp_start = .); diff --git a/vendor/lowrisc_ibex/ibex_top.core b/vendor/lowrisc_ibex/ibex_top.core index a0dfa2ee7..ceda43052 100644 --- a/vendor/lowrisc_ibex/ibex_top.core +++ b/vendor/lowrisc_ibex/ibex_top.core @@ -13,7 +13,10 @@ filesets: - lowrisc:prim:buf - lowrisc:prim:clock_mux2 - lowrisc:prim:flop - - lowrisc:prim:ram_1p_scr + # Note this should be ram_1p_scr however with ibexc_top only the + # unscrambled ICache is supported so there's no need for the scrambling + # primitives + - lowrisc:prim:ram_1p files: - rtl/ibex_register_file_ff.sv # generic FF-based - rtl/ibex_register_file_fpga.sv # FPGA diff --git a/vendor/lowrisc_ibex/rtl/cheri_decoder.sv b/vendor/lowrisc_ibex/rtl/cheri_decoder.sv index cf078c8d7..3fe80262b 100644 --- a/vendor/lowrisc_ibex/rtl/cheri_decoder.sv +++ b/vendor/lowrisc_ibex/rtl/cheri_decoder.sv @@ -62,6 +62,7 @@ module cheri_decoder import cheri_pkg::*; # ( cheri_operator_o[CSET_ADDR] = cheri_opcode_en_i && (func3_op==0) && (func7_op==7'h10); cheri_operator_o[CINC_ADDR] = cheri_opcode_en_i && (func3_op==0) && (func7_op==7'h11); cheri_operator_o[CSUB_CAP] = cheri_opcode_en_i && (func3_op==0) && (func7_op==7'h14); + cheri_operator_o[CSET_HIGH] = cheri_opcode_en_i && (func3_op==0) && (func7_op==7'h16); cheri_operator_o[CIS_SUBSET] = cheri_opcode_en_i && (func3_op==0) && (func7_op==7'h20); cheri_operator_o[CIS_EQUAL] = cheri_opcode_en_i && (func3_op==0) && (func7_op==7'h21); @@ -109,18 +110,16 @@ module cheri_decoder import cheri_pkg::*; # ( assign cheri_imm21_o = cheri_operator_o[CJAL] ? {instr_rdata_i[31], instr_rdata_i[19:12], instr_rdata_i[20], instr_rdata_i[30:21], 1'b0} : 0; - // register dependency decoding + // register dependency decoding (ren_a, ren_b, we) // only handled opcode=0x5b case here. // Will be qualified and combined with other cases by ibexc_decoder - // - note: rf_reb_b_o actually should be '0' for CSPECIALRW. - // however that's the only mismatch case so performance loss due to stalling - // should be small, and so we choose to have simpler decoder for timing assign cheri_rf_ren_a_o = 1'b1; - assign cheri_rf_ren_b_o = (func3_op == 0) && (func7_op != 7'h7f); - - // this will be used separately, so include full decoding - assign cheri_rf_we_dec_o = cheri_opcode_en_i | cheri_auipcc_en_i | cheri_auicgp_en_i | - cheri_jal_en_i | cheri_jalr_en_i | cheri_cload_en_i; + assign cheri_rf_ren_b_o = (func3_op == 0) && (func7_op != 7'h7f) && (func7_op !=7'h01); + + // cheri_rf_we_dec_o is not used to generate the actual regfile write enables in the case of + // cheri instructions (which is in cheri_ex and muxed with rf_we in wb_stage). + // However it is merged into the overall rf_we and used to generate stall_cheri_trvk + assign cheri_rf_we_dec_o = cheri_opcode_en_i & (|cheri_operator_o); assign cheri_multicycle_dec_o = (cheri_operator_o[CLOAD_CAP] & cheri_tsafe_en_i & ~CheriPPLBC) | (CheriSBND2 & (cheri_operator_o[CSET_BOUNDS] | diff --git a/vendor/lowrisc_ibex/rtl/cheri_ex.sv b/vendor/lowrisc_ibex/rtl/cheri_ex.sv index fddaf900c..dca4d4ed2 100644 --- a/vendor/lowrisc_ibex/rtl/cheri_ex.sv +++ b/vendor/lowrisc_ibex/rtl/cheri_ex.sv @@ -37,6 +37,7 @@ module cheri_ex import cheri_pkg::*; #( input logic [31:0] rf_rdata_b_i, input reg_cap_t rf_rcap_b_i, output logic rf_trsv_en_o, + input logic [4:0] rf_waddr_i, // pcc interface input pcc_cap_t pcc_cap_i, @@ -175,7 +176,7 @@ module cheri_ex import cheri_pkg::*; #( logic is_intl, is_lbc; logic addr_bound_vio; - logic perm_vio; + logic perm_vio, perm_vio_slc; logic rv32_lsu_err; logic addr_bound_vio_rv32; logic perm_vio_rv32; @@ -223,6 +224,7 @@ module cheri_ex import cheri_pkg::*; #( logic cpu_lsu_cheri_err, cpu_lsu_is_cap; logic illegal_scr_addr; + logic scr_legalization; // data forwarding for CHERI instructions // - note address 0 is a read-only location per RISC-V @@ -302,6 +304,7 @@ module cheri_ex import cheri_pkg::*; #( csr_wcap_o = NULL_REG_CAP; csr_op_o = CHERI_CSR_NULL; csr_op_en_raw = 1'b0; + scr_legalization = 1'b0; branch_req_raw = 1'b0; branch_req_spec_raw = 1'b0; @@ -406,6 +409,14 @@ module cheri_ex import cheri_pkg::*; #( cheri_rf_we_raw = 1'b1; cheri_ex_valid_raw = 1'b1; end + cheri_operator_i[CSET_HIGH]: // cd <-- cs1; cd.high <-- convert(rs2) + begin + // this only works for memcap_fmt0 for now QQQ + result_data_o = rf_rdata_a; + result_cap_o = mem2regcap_fmt0({1'b0, rf_rdata_b}, {1'b0, rf_rdata_a}, 4'h0); + cheri_rf_we_raw = 1'b1; + cheri_ex_valid_raw = 1'b1; + end // setaddr/incoffset: cd <-- cs1; cd.offset <-- rs2, or cs1.addr + rs2, or cs1.addr + imm12 // auipcc: cd <-- pcc, cd.address <-- pcc.address + (imm20 << 12) @@ -521,7 +532,7 @@ module cheri_ex import cheri_pkg::*; #( cheri_ex_valid_raw = 1'b1; cheri_ex_err_raw = 1'b0; // acc err passed to LSU and processed later in WB csc_wcap = rf_rcap_b; - csc_wcap.valid = rf_rcap_b.valid & ~perm_vio_vec[PVIO_SLC]; + csc_wcap.valid = rf_rcap_b.valid & ~perm_vio_slc; end cheri_operator_i[CCSR_RW]: // cd <-- scr; scr <-- cs1 if cs1 != C0 begin @@ -541,20 +552,29 @@ module cheri_ex import cheri_pkg::*; #( csr_addr_o = cheri_cs2_dec_i; if (cheri_cs2_dec_i == CHERI_SCR_MTCC) begin - // MTVEC/MTCC or MEPCC, legalization (clear tag if checking fails) + // MTVEC/MTCC legalization (clear tag if checking fails) + // note we don't reall need set_address checks here - it's only used to update temp fields + // so that RTL behavior would match sail + scr_legalization = 1'b1; csr_wdata_o = {rf_rdata_a[31:2], 2'b00}; - trcap = rf_rcap_a; + trcap = full2regcap(setaddr1_outcap); if ((rf_rdata_a[1:0] != 2'b00) || ~rf_fullcap_a.perms[PERM_EX] || (rf_fullcap_a.otype != 0)) trcap.valid = 1'b0; + else + trcap.valid = rf_fullcap_a.valid; csr_wcap_o = trcap; end else if (cheri_cs2_dec_i == CHERI_SCR_MEPCC) begin - // MTVEC/MTCC or MEPCC, legalization (clear tag if checking fails) + // MEPCC legalization (clear tag if checking fails) + scr_legalization = 1'b1; csr_wdata_o = {rf_rdata_a[31:1], 1'b0}; - trcap = rf_rcap_a; + trcap = full2regcap(setaddr1_outcap); if ((rf_rdata_a[0] != 1'b0) || ~rf_fullcap_a.perms[PERM_EX] || (rf_fullcap_a.otype != 0)) trcap.valid = 1'b0; + else + trcap.valid = rf_fullcap_a.valid; csr_wcap_o = trcap; end else begin + scr_legalization = 1'b0; csr_wdata_o = rf_rdata_a; csr_wcap_o = rf_rcap_a; end @@ -586,7 +606,7 @@ module cheri_ex import cheri_pkg::*; #( // (link address == pc_id + delta, but pc_if should be the next executed PC (the jump target) // if branch prediction works) result_data_o = pc_id_nxt; - seal_type = csr_mstatus_mie_i ? OTYPE_SENTRY_IE : OTYPE_SENTRY_ID; + seal_type = csr_mstatus_mie_i ? OTYPE_SENTRY_IE_BKWD : OTYPE_SENTRY_ID_BKWD; tfcap = seal_cap(setaddr1_outcap, seal_type); result_cap_o = full2regcap(tfcap); @@ -601,14 +621,17 @@ module cheri_ex import cheri_pkg::*; #( cheri_rf_we_raw = ~instr_fault; // err -> wb exception branch_req_raw = ~instr_fault & cheri_operator_i[CJALR]; // update PCC in CSR - branch_req_spec_raw = 1'b1; + // branch_req_spec_raw = 1'b1; + branch_req_spec_raw = ~instr_fault; // set fetch PC cheri_wb_err_raw = instr_fault; cheri_ex_err_raw = 1'b0; csr_set_mie_raw = ~instr_fault && cheri_operator_i[CJALR] && - (rf_fullcap_a.otype == OTYPE_SENTRY_IE); + ((rf_fullcap_a.otype == OTYPE_SENTRY_IE_FWD) || + (rf_fullcap_a.otype == OTYPE_SENTRY_IE_BKWD)) ; csr_clr_mie_raw = ~instr_fault && cheri_operator_i[CJALR] && - (rf_fullcap_a.otype == OTYPE_SENTRY_ID); + ((rf_fullcap_a.otype == OTYPE_SENTRY_ID_FWD) || + (rf_fullcap_a.otype == OTYPE_SENTRY_ID_BKWD)) ; cheri_ex_valid_raw = 1'b1; end default:; @@ -688,8 +711,8 @@ module cheri_ex import cheri_pkg::*; #( // - break out to make sure we can properly gate off operands to save power // always_comb begin: set_address_comb - full_cap_t tfcap1, tfcap2; - logic [31:0] taddr1, taddr2; + full_cap_t tfcap1; + logic [31:0] taddr1; // set_addr operation 1 if (cheri_operator_i[CJAL] | cheri_operator_i[CJALR]) begin @@ -703,6 +726,9 @@ module cheri_ex import cheri_pkg::*; #( cheri_operator_i[CINC_ADDR_IMM] | cheri_operator_i[CAUICGP]) begin tfcap1 = rf_fullcap_a; taddr1 = addr_result; + end else if (scr_legalization) begin + tfcap1 = rf_fullcap_a; + taddr1 = csr_wdata_o; end else begin tfcap1 = NULL_FULL_CAP; taddr1 = 32'h0; @@ -835,6 +861,7 @@ module cheri_ex import cheri_pkg::*; #( logic [32:0] top_chkaddr; logic top_vio, base_vio, top_equal; logic cs2_bad_type; + logic cs1_otype_0, cs1_otype_1, cs1_otype_45, cs1_otype_23; // generate the address used to check top bound violation if (cheri_operator_i[CSEAL] | cheri_operator_i[CUNSEAL]) @@ -879,9 +906,16 @@ module cheri_ex import cheri_pkg::*; #( // main permission logic perm_vio_vec = 0; + perm_vio = 0; + perm_vio_slc = 0; cs2_bad_type = 1'b0; illegal_scr_addr = 1'b0; + cs1_otype_0 = (rf_fullcap_a.otype == 3'h0); + cs1_otype_1 = (rf_fullcap_a.otype == 3'h1); + cs1_otype_45 = (rf_fullcap_a.otype == 3'h4) || (rf_fullcap_a.otype == 3'h5); + cs1_otype_23 = (rf_fullcap_a.otype == 3'h2) || (rf_fullcap_a.otype == 3'h3); + // note cseal/unseal/cis_subject doesn't generate exceptions, // so for all exceptions, violations can always be attributed to cs1, thus no need to further split // exceptions based on source operands. @@ -896,7 +930,7 @@ module cheri_ex import cheri_pkg::*; #( perm_vio_vec[PVIO_SD] = ~rf_fullcap_a.perms[PERM_SD]; perm_vio_vec[PVIO_SC] = (~rf_fullcap_a.perms[PERM_MC] && rf_fullcap_b.valid); perm_vio_vec[PVIO_ALIGN] = (cheri_ls_chkaddr[2:0] != 0); - perm_vio_vec[PVIO_SLC] = ~rf_fullcap_a.perms[PERM_SL] && rf_fullcap_b.valid && ~rf_fullcap_b.perms[PERM_GL]; + perm_vio_slc = ~rf_fullcap_a.perms[PERM_SL] && rf_fullcap_b.valid && ~rf_fullcap_b.perms[PERM_GL]; end else if (cheri_operator_i[CSEAL]) begin cs2_bad_type = rf_fullcap_a.perms[PERM_EX] ? ((rf_rdata_b[31:3]!=0)||(rf_rdata_b[2:0]==0)||(rf_rdata_b[2:0]==3'h4)||(rf_rdata_b[2:0]==3'h5)) : @@ -912,8 +946,12 @@ module cheri_ex import cheri_pkg::*; #( (~rf_fullcap_b.perms[PERM_US]); end else if (cheri_operator_i[CJALR]) begin perm_vio_vec[PVIO_TAG] = ~rf_fullcap_a.valid; - perm_vio_vec[PVIO_SEAL] = is_cap_sealed(rf_fullcap_a) && - (~is_cap_sentry(rf_fullcap_a) || (cheri_imm12_i != 0)); + perm_vio_vec[PVIO_SEAL] = (is_cap_sealed(rf_fullcap_a) && (cheri_imm12_i != 0)) || + ~(((rf_waddr_i == 0) && (rf_raddr_a_i == 5'h1) && cs1_otype_45) || + ((rf_waddr_i == 0) && (rf_raddr_a_i != 5'h1) && (cs1_otype_0 || cs1_otype_1)) || + ((rf_waddr_i == 5'h1) && (cs1_otype_0 | cs1_otype_23)) || + ((rf_waddr_i != 0) && (cs1_otype_0 | cs1_otype_1))); + perm_vio_vec[PVIO_EX] = ~rf_fullcap_a.perms[PERM_EX]; end else if (cheri_operator_i[CCSR_RW]) begin perm_vio_vec[PVIO_ASR] = ~pcc_cap_i.perms[PERM_SR]; @@ -923,12 +961,13 @@ module cheri_ex import cheri_pkg::*; #( end perm_vio = | perm_vio_vec; + end // qualified by lsu_req later // store_local error only causes tag clearing unless escalated to fault for debugging assign cheri_lsu_err = cheri_pmode_i & ~debug_mode_i & - (addr_bound_vio | (|perm_vio_vec[7:0]) | (csr_dbg_tclr_fault_i & perm_vio_vec[PVIO_SLC])); + (addr_bound_vio | perm_vio | (csr_dbg_tclr_fault_i & perm_vio_slc)); // // fault case mtval generation @@ -955,7 +994,8 @@ module cheri_ex import cheri_pkg::*; #( cheri_err_cause = vio_cause_enc(addr_bound_vio_ext, perm_vio_vec); rv32_err_cause = vio_cause_enc(addr_bound_vio_rv32, perm_vio_vec_rv32); - ls_addr_misaligned_only = perm_vio_vec[PVIO_ALIGN] && (cheri_err_cause == 0); + + ls_addr_misaligned_only = perm_vio_vec[PVIO_ALIGN] && (perm_vio_vec[PVIO_ALIGN-1:0] == 0) && ~addr_bound_vio_ext; if (cheri_exec_id_i & ~CheriPPLBC & cheri_tsafe_en_i & is_load_cap & cheri_lsu_err) // 2-stage ppl load/store, error treated as EX error, cheri CLC check error @@ -971,12 +1011,12 @@ module cheri_ex import cheri_pkg::*; #( // bit 12: illegal_scr_addr // bit 11: alignment error (load/store) // bit 10:0 mtval as defined by CHERIoT arch spec - if (cheri_operator_i[CCSR_RW] & cheri_wb_err_raw & perm_vio & cheri_exec_id_i) - // cspecialrw traps, PERM_SR - cheri_wb_err_info_d = {5'h0, 1'b1, cheri_cs2_dec_i, cheri_err_cause}; - else if (cheri_operator_i[CCSR_RW] & cheri_wb_err_raw & cheri_exec_id_i) + if (cheri_operator_i[CCSR_RW] & cheri_wb_err_raw & illegal_scr_addr & cheri_exec_id_i) // cspecialrw trap, illegal addr, treated as illegal_insn cheri_wb_err_info_d = {3'h0, 1'b1, 12'h0}; + else if (cheri_operator_i[CCSR_RW] & cheri_wb_err_raw & cheri_exec_id_i) + // cspecialrw traps, PERM_SR + cheri_wb_err_info_d = {5'h0, 1'b1, cheri_cs2_dec_i, cheri_err_cause}; else if (cheri_wb_err_raw & cheri_exec_id_i) cheri_wb_err_info_d = {5'h0, 1'b0, rf_raddr_a_i, cheri_err_cause}; else if ((is_load_cap | is_store_cap) & cheri_lsu_err & cheri_exec_id_i) diff --git a/vendor/lowrisc_ibex/rtl/cheri_pkg.sv b/vendor/lowrisc_ibex/rtl/cheri_pkg.sv index 9ac7d4076..a7a24846e 100644 --- a/vendor/lowrisc_ibex/rtl/cheri_pkg.sv +++ b/vendor/lowrisc_ibex/rtl/cheri_pkg.sv @@ -40,8 +40,10 @@ package cheri_pkg; parameter int unsigned PERM_U1 = 12; // // parameter int unsigned PERM_U2 = 13; // temp workaround - parameter logic [2:0] OTYPE_SENTRY_IE = 3'd3; - parameter logic [2:0] OTYPE_SENTRY_ID = 3'd2; + parameter logic [2:0] OTYPE_SENTRY_IE_BKWD = 3'd5; + parameter logic [2:0] OTYPE_SENTRY_ID_BKWD = 3'd4; + parameter logic [2:0] OTYPE_SENTRY_IE_FWD = 3'd3; + parameter logic [2:0] OTYPE_SENTRY_ID_FWD = 3'd2; parameter logic [2:0] OTYPE_SENTRY = 3'd1; parameter logic [2:0] OTYPE_UNSEALED = 3'd0; @@ -485,13 +487,13 @@ $display("--- set_bounds: b1 = %x, t1 = %x, b2 = %x, t2 = %x", base1, top1, bas return result; endfunction - function automatic logic is_cap_sentry (full_cap_t in_cap); - logic result; + //function automatic logic is_cap_sentry (full_cap_t in_cap); + // logic result; - result = (in_cap.otype == OTYPE_SENTRY) || (in_cap.otype == OTYPE_SENTRY_ID) || - (in_cap.otype == OTYPE_SENTRY_IE); - return result; - endfunction + // result = (in_cap.perms[PERM_EX]) && ((in_cap.otype == OTYPE_SENTRY) || (in_cap.otype == OTYPE_SENTRY_ID) || + // (in_cap.otype == OTYPE_SENTRY_IE)); + // return result; + //endfunction function automatic logic [3:0] decode_otype (logic [2:0] otype3, logic perm_ex); @@ -592,9 +594,9 @@ $display("--- set_bounds: b1 = %x, t1 = %x, b2 = %x, t2 = %x", base1, top1, bas full_cap_t tfcap0, tfcap1; tfcap0 = pcc2fullcap(pcc_cap); - // we really only need to update_temp_files here - // (representability check is unnecessary due to fetch time bound check). will remove later + // Still need representability check to cover save_pc_if and save_pc_wb cases tfcap1 = set_address(tfcap0, address, 0, 0); + reg_cap = full2regcap(tfcap1); if (clrtag) reg_cap.valid = 1'b0; @@ -831,7 +833,7 @@ $display("--- set_bounds: b1 = %x, t1 = %x, b2 = %x, t2 = %x", base1, top1, bas CSUB_CAP = 6'h14, CCLEAR_TAG = 6'h15, CLOAD_CAP = 6'h16, - //CLBC = 6'h17, + CSET_HIGH = 6'h17, CSTORE_CAP = 6'h18, CCSR_RW = 6'h19, CJALR = 6'h1a, @@ -867,7 +869,6 @@ $display("--- set_bounds: b1 = %x, t1 = %x, b2 = %x, t2 = %x", base1, top1, bas parameter logic [3:0] PVIO_SC = 4'h5; parameter logic [3:0] PVIO_ASR = 4'h6; parameter logic [3:0] PVIO_ALIGN = 4'h7; - parameter logic [3:0] PVIO_SLC = 4'h8; function automatic logic [4:0] vio_cause_enc (logic bound_vio, logic[W_PVIO-1:0] perm_vio_vec); @@ -885,8 +886,6 @@ $display("--- set_bounds: b1 = %x, t1 = %x, b2 = %x, t2 = %x", base1, top1, bas vio_cause = 5'h13; else if (perm_vio_vec[PVIO_SC]) vio_cause = 5'h15; - else if (perm_vio_vec[PVIO_SLC]) - vio_cause = 5'h16; else if (perm_vio_vec[PVIO_ASR]) vio_cause = 5'h18; else if (bound_vio) diff --git a/vendor/lowrisc_ibex/rtl/ibex_controller.sv b/vendor/lowrisc_ibex/rtl/ibex_controller.sv index 0d92dc3c3..99ff9ef25 100644 --- a/vendor/lowrisc_ibex/rtl/ibex_controller.sv +++ b/vendor/lowrisc_ibex/rtl/ibex_controller.sv @@ -35,6 +35,8 @@ module ibex_controller #( input logic wfi_insn_i, // decoder has WFI instr input logic ebrk_insn_i, // decoder has EBREAK instr input logic csr_pipe_flush_i, // do CSR-related pipeline flush + input logic csr_access_i, // decoder has CSR access instr + input logic csr_cheri_always_ok_i, // cheri safe-listed CSR registers // instr from IF-ID pipeline stage input logic instr_valid_i, // instr is valid @@ -150,6 +152,7 @@ module ibex_controller #( logic illegal_insn_q, illegal_insn_d; logic cheri_ex_err_q, cheri_ex_err_d; logic cheri_wb_err_q; + logic cheri_asr_err_q, cheri_asr_err_d; // Of the various exception/fault signals, which one takes priority in FLUSH and hence controls // what happens next (setting exc_cause, csr_mtval etc) @@ -161,6 +164,7 @@ module ibex_controller #( logic load_err_prio; logic cheri_ex_err_prio; logic cheri_wb_err_prio; + logic cheri_asr_err_prio; logic stall; logic halt_if; @@ -192,7 +196,8 @@ module ibex_controller #( logic csr_pipe_flush; logic instr_fetch_err; logic cheri_ex_err; - logic illegal_mret_cheri; + logic mret_cheri_asr_err; + logic csr_cheri_asr_err; `ifndef SYNTHESIS // synopsys translate_off @@ -200,7 +205,7 @@ module ibex_controller #( // glitches always_ff @(negedge clk_i) begin // print warning in case of decoding errors - if ((ctrl_fsm_cs == DECODE) && instr_valid_i && !instr_fetch_err_i && illegal_insn_d) begin + if ((ctrl_fsm_cs == DECODE) && instr_valid_i && !instr_fetch_err_i && !wb_exception_o && illegal_insn_d) begin $display("%t: Illegal instruction (hart %0x) at PC 0x%h: 0x%h", $time, ibex_core.hart_id_i, ibex_id_stage.pc_id_i, ibex_id_stage.instr_rdata_i); end @@ -234,25 +239,28 @@ module ibex_controller #( // MRET must be in M-Mode. TW means trap WFI to M-Mode. (mret_insn | (csr_mstatus_tw_i & wfi_insn)); - assign illegal_mret_cheri = CHERIoTEn & cheri_pmode_i & ~csr_pcc_perm_sr_i & mret_insn; + assign mret_cheri_asr_err = CHERIoTEn & cheri_pmode_i & ~csr_pcc_perm_sr_i & mret_insn; + assign csr_cheri_asr_err = CHERIoTEn & cheri_pmode_i & ~csr_pcc_perm_sr_i & instr_valid_i & + csr_access_i & ~illegal_insn_i & ~csr_cheri_always_ok_i; // This is recorded in the illegal_insn_q flop to help timing. Specifically // it is needed to break the path from ibex_cs_registers/illegal_csr_insn_o // to pc_set_o. Clear when controller is in FLUSH so it won't remain set // once illegal instruction is handled. // All terms in this expression are qualified by instr_valid_i - assign illegal_insn_d = (illegal_insn_i | illegal_dret | illegal_umode | (cheri_pmode_i & illegal_mret_cheri)) & - (ctrl_fsm_cs != FLUSH); + assign illegal_insn_d = illegal_insn_i | illegal_dret | illegal_umode; assign cheri_ex_err_d = cheri_pmode_i & cheri_ex_err & (ctrl_fsm_cs != FLUSH); + assign cheri_asr_err_d = (~illegal_insn_i & csr_cheri_asr_err) | mret_cheri_asr_err; + // exception requests // requests are flopped in exc_req_q. This is cleared when controller is in // the FLUSH state so the cycle following exc_req_q won't remain set for an // exception request that has just been handled. // All terms in this expression are qualified by instr_valid_i - assign exc_req_d = (ecall_insn | ebrk_insn | illegal_insn_d | instr_fetch_err | (cheri_pmode_i & cheri_ex_err)) & - (ctrl_fsm_cs != FLUSH); - assign exc_req_nc = (ecall_insn | ebrk_insn | illegal_insn_d | instr_fetch_err) & + assign exc_req_d = (ecall_insn | ebrk_insn | illegal_insn_d | instr_fetch_err | (cheri_pmode_i & cheri_ex_err) | + cheri_asr_err_d) & (ctrl_fsm_cs != FLUSH); + assign exc_req_nc = (ecall_insn | ebrk_insn | illegal_insn_d | instr_fetch_err | cheri_asr_err_d) & (ctrl_fsm_cs != FLUSH); // LSU exception requests @@ -290,6 +298,7 @@ module ibex_controller #( load_err_prio = 0; cheri_ex_err_prio = 0; cheri_wb_err_prio = 0; + cheri_asr_err_prio = 0; // Note that with the writeback stage store/load errors occur on the instruction in writeback, // all other exception/faults occur on the instruction in ID/EX. The faults from writeback @@ -310,6 +319,8 @@ module ibex_controller #( ebrk_insn_prio = 1'b1; end else if (cheri_pmode_i & cheri_ex_err_q) begin cheri_ex_err_prio = 1'b1; + end else if (cheri_asr_err_q) begin + cheri_asr_err_prio = 1'b1; end end @@ -325,6 +336,7 @@ module ibex_controller #( load_err_prio = 0; cheri_wb_err_prio = 0; cheri_ex_err_prio = 0; + cheri_asr_err_prio = 0; if (instr_fetch_err) begin instr_fetch_err_prio = 1'b1; @@ -342,6 +354,8 @@ module ibex_controller #( load_err_prio = 1'b1; end else if (cheri_wb_err_q) begin cheri_wb_err_prio = 1'b1; + end else if (cheri_asr_err_q) begin + cheri_asr_err_prio = 1'b1; end end assign wb_exception_o = 1'b0; @@ -354,8 +368,10 @@ module ibex_controller #( ebrk_insn_prio, store_err_prio, load_err_prio, - cheri_ex_err_prio}), - (ctrl_fsm_cs == FLUSH) & exc_req_q) + cheri_wb_err_prio, + cheri_ex_err_prio, + cheri_asr_err_prio}), + (ctrl_fsm_cs == FLUSH) & csr_save_cause_o) //////////////// // Interrupts // @@ -736,7 +752,8 @@ module ibex_controller #( end illegal_insn_prio: begin exc_cause_o = EXC_CAUSE_ILLEGAL_INSN; - csr_mtval_o = instr_is_compressed_i ? {16'b0, instr_compressed_i} : instr_i; + csr_mtval_o = (CHERIoTEn & cheri_pmode_i) ? 32'h0 : + (instr_is_compressed_i ? {16'b0, instr_compressed_i} : instr_i); end ecall_insn_prio: begin exc_cause_o = (priv_mode_i == PRIV_LVL_M) ? EXC_CAUSE_ECALL_MMODE : @@ -820,6 +837,11 @@ module ibex_controller #( end end end + cheri_asr_err_prio: begin + exc_cause_o = EXC_CAUSE_CHERI_FAULT; + //csr_mtval_o = instr_is_compressed_i ? {16'b0, instr_compressed_i} : instr_i; + csr_mtval_o = {21'b0, 1'b1, 5'h0, 5'h18}; // S=1, cap_idx=0 (pcc), err=0x18 + end default: ; endcase @@ -908,6 +930,7 @@ module ibex_controller #( illegal_insn_q <= 1'b0; cheri_ex_err_q <= 1'b0; cheri_wb_err_q <= 1'b0; + cheri_asr_err_q <= 1'b0; end else begin ctrl_fsm_cs <= ctrl_fsm_ns; nmi_mode_q <= nmi_mode_d; @@ -920,7 +943,8 @@ module ibex_controller #( exc_req_q <= exc_req_d; illegal_insn_q <= illegal_insn_d; cheri_ex_err_q <= cheri_ex_err_d; - cheri_wb_err_q <= cheri_pmode_i & cheri_wb_err_i; + cheri_wb_err_q <= cheri_wb_err_i; + cheri_asr_err_q <= cheri_asr_err_d; end end @@ -955,14 +979,30 @@ module ibex_controller #( logic exception_req, exception_req_pending, exception_req_accepted, exception_req_done; logic exception_pc_set, seen_exception_pc_set, expect_exception_pc_set; logic exception_req_needs_pc_set; + logic cs_taken_exception, ns_taken_exception; + + assign cs_taken_exception = (ctrl_fsm_cs == FLUSH) || (ctrl_fsm_cs == DBG_TAKEN_IF) || + (ctrl_fsm_cs == DBG_TAKEN_ID); + assign ns_taken_exception = (ctrl_fsm_ns == FLUSH) || (ctrl_fsm_ns == DBG_TAKEN_IF) || + (ctrl_fsm_ns == DBG_TAKEN_ID); + + // kliu 05242024: excluding handle_irq here since handle_irq may not be processed if + // mstatus.mie is clearaed by the current instruction (either cssrw to mstatus or cjalr to + // an interrupt-disabled sentry) + // assign exception_req = (special_req | enter_debug_mode | handle_irq); + assign exception_req = (special_req | enter_debug_mode); - assign exception_req = (special_req | enter_debug_mode | handle_irq); // Any exception rquest will cause a transition out of DECODE, once the controller transitions // back into DECODE we're done handling the request. + // kliu 05242024: change the condition to cover the wfi case ( + // assign exception_req_done = + // exception_req_pending & (ctrl_fsm_cs != DECODE) & (ctrl_fsm_ns == DECODE); assign exception_req_done = - exception_req_pending & (ctrl_fsm_cs != DECODE) & (ctrl_fsm_ns == DECODE); + exception_req_pending & cs_taken_exception; - assign exception_req_needs_pc_set = enter_debug_mode | handle_irq | special_req_pc_change; + // kliu 05242024: excluding handle_irq + // assign exception_req_needs_pc_set = enter_debug_mode | handle_irq | special_req_pc_change; + assign exception_req_needs_pc_set = enter_debug_mode | special_req_pc_change; // An exception PC set uses specific PC types assign exception_pc_set = @@ -979,8 +1019,12 @@ module ibex_controller #( exception_req_pending <= (exception_req_pending | exception_req) & ~exception_req_done; // The exception req has been accepted once the controller transitions out of decode + // kliu 05242024 + //exception_req_accepted <= (exception_req_accepted & ~exception_req_done) | + // (exception_req & ctrl_fsm_ns != DECODE); exception_req_accepted <= (exception_req_accepted & ~exception_req_done) | - (exception_req & ctrl_fsm_ns != DECODE); + (exception_req & ns_taken_exception); + // Set `expect_exception_pc_set` if exception req needs one and keep it asserted until // exception req is done diff --git a/vendor/lowrisc_ibex/rtl/ibex_core.sv b/vendor/lowrisc_ibex/rtl/ibex_core.sv index 94e39a7b3..4bd8db59d 100644 --- a/vendor/lowrisc_ibex/rtl/ibex_core.sv +++ b/vendor/lowrisc_ibex/rtl/ibex_core.sv @@ -900,6 +900,7 @@ module ibex_core import ibex_pkg::*; import cheri_pkg::*; #( .rf_rdata_b_i (rf_rdata_b), .rf_rcap_b_i (rf_rcap_b_i), .rf_trsv_en_o (rf_trsv_en), + .rf_waddr_i (rf_waddr_id), .pcc_cap_i (pcc_cap_r), .pcc_cap_o (pcc_cap_w), .pc_id_i (pc_id), @@ -1783,8 +1784,14 @@ end // Factor in exceptions taken in ID so RVFI tracking picks up flushed instructions that took // a trap + // kliu 05082024: add the ~wb_exception_o iterm to handle the corner case where + // ID and WB both faulted, e.g., illegal_insn in ID and cheri_wb_err in WB + // The previous behavior is 2 rvfi items in the trace (both traps), + // even if the instruction in the ID is never executed. + // The new behavior only generate 1 rvfi item for wb stage fault assign rvfi_id_done = instr_id_done | (id_stage_i.controller_i.rvfi_flush_next & - id_stage_i.controller_i.id_exception_o); + id_stage_i.controller_i.id_exception_o & + ~id_stage_i.controller_i.wb_exception_o); if (WritebackStage) begin : gen_rvfi_wb_stage logic unused_instr_new_id; diff --git a/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv b/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv index 6f1b43ff1..6089620f4 100644 --- a/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv +++ b/vendor/lowrisc_ibex/rtl/ibex_cs_registers.sv @@ -814,6 +814,11 @@ module ibex_cs_registers import cheri_pkg::*; #( mstatus_en = 1'b1; mstatus_d.mie = mstatus_q.mpie; // re-enable interrupts + // merge in upstream change 9/7/2022 // LEC_NOT_COMPATIBLE + if (mstatus_q.mpp != PRIV_LVL_M) begin + mstatus_d.mprv = 1'b0; + end + cpuctrl_we = 1'b1; cpuctrl_d.sync_exc_seen = 1'b0; @@ -867,17 +872,17 @@ module ibex_cs_registers import cheri_pkg::*; #( // only write CSRs during one clock cycle // enforcing the CHERI CSR access policy. - // -- is reading zero back ok? or do we need to generate illegal access exception?? - // -- also note IBEX didn't implement user-mode TIME/counters. - // for now we are allowing reading the M-mode counters (assuming only use single priv level) - - logic read_ok; - assign read_ok = ~CHERIoTEn || ~cheri_pmode_i || debug_mode_i || pcc_cap_q.perms[PERM_SR] || - ((csr_addr_i>=CSR_MCYCLE) && (csr_addr_i<=CSR_CDBG_CTRL)); - // ((csr_addr_i>=CSR_MCYCLE) && (csr_addr_i=CSR_MCYCLE) && (csr_addr_i<=CSR_CDBG_CTRL)); assign csr_we_int = csr_wr & csr_op_en_i & (~CHERIoTEn | ~cheri_pmode_i | debug_mode_i | pcc_cap_q.perms[PERM_SR]) & ~illegal_csr_insn_o; - assign csr_rdata_o = read_ok ? csr_rdata_int : 0; + + // assign csr_rdata_o = read_ok ? csr_rdata_int : 0; + assign csr_rdata_o = csr_rdata_int; // directly output some registers assign csr_mepc_o = mepc_q; diff --git a/vendor/lowrisc_ibex/rtl/ibex_decoder.sv b/vendor/lowrisc_ibex/rtl/ibex_decoder.sv index 58a007928..a3d613b48 100644 --- a/vendor/lowrisc_ibex/rtl/ibex_decoder.sv +++ b/vendor/lowrisc_ibex/rtl/ibex_decoder.sv @@ -93,6 +93,7 @@ module ibex_decoder import cheri_pkg::*; #( // CSRs output logic csr_access_o, // access to CSR output ibex_pkg::csr_op_e csr_op_o, // operation to perform on CSR + output logic csr_cheri_always_ok_o, // CHERI safe-listed (no ASR needed) CSRs // LSU output logic data_req_o, // start transaction to data memory @@ -114,17 +115,17 @@ module ibex_decoder import cheri_pkg::*; #( output logic [19:0] cheri_imm20_o, output logic [20:0] cheri_imm21_o, output logic [OPDW-1:0] cheri_operator_o, - output logic [4:0] cheri_cs2_dec_o, - output logic cheri_rf_we_dec_o, + output logic [4:0] cheri_cs2_dec_o, output logic cheri_multicycle_dec_o ); import ibex_pkg::*; - localparam bit CheriLimit16Regs = 1'b1; + localparam bit CheriLimit16Regs = CHERIoTEn; logic illegal_insn; logic illegal_reg_rv32e; + logic illegal_reg_cheri; logic csr_illegal; logic rf_we; @@ -154,6 +155,7 @@ module ibex_decoder import cheri_pkg::*; #( logic cheri_cstore_en; logic instr_is_legal_cheri; logic cheri_rf_ren_a, cheri_rf_ren_b; + logic cheri_rf_we_dec; // To help timing the flops containing the current instruction are replicated to reduce fan-out. // instr_alu is used to determine the ALU control logic and associated operand/imm select signals @@ -208,7 +210,7 @@ module ibex_decoder import cheri_pkg::*; #( assign raddr_a = cheri_auicgp_en ? 5'h3 : ((use_rs3_q & ~instr_first_cycle_i) ? instr_rs3 : instr_rs1); // rs3 / rs1 assign raddr_b = instr_rs2; // rs2 - // cheri only uses 16 registers and repurposes the MSB addr bits + // cheriot only uses 16 registers and repurposes the MSB addr bits if (CheriLimit16Regs) begin assign rf_raddr_a_o = cheri_pmode_i ?{1'b0, raddr_a[3:0]} : raddr_a; assign rf_raddr_b_o = cheri_pmode_i ?{1'b0, raddr_b[3:0]} : raddr_b; @@ -236,6 +238,17 @@ module ibex_decoder import cheri_pkg::*; #( assign illegal_reg_rv32e = 1'b0; end + if (CheriLimit16Regs) begin : gen_cheri_reg_check_active + assign illegal_reg_cheri = cheri_pmode_i & + ((rf_raddr_a_o[4] & (alu_op_a_mux_sel_o == OP_A_REG_A)) | + (rf_raddr_a_o[4] & cheri_rf_ren_a) | + (rf_raddr_b_o[4] & (alu_op_b_mux_sel_o == OP_B_REG_B)) | + (rf_raddr_b_o[4] & cheri_rf_ren_b) | + (rf_waddr_o[4] & rf_we)); + end else begin : gen_cheri_reg_check_inactive + assign illegal_reg_cheri = 1'b0; + end + /////////////////////// // CSR operand check // /////////////////////// @@ -271,6 +284,7 @@ module ibex_decoder import cheri_pkg::*; #( csr_access_o = 1'b0; csr_illegal = 1'b0; csr_op = CSR_OP_READ; + csr_cheri_always_ok_o = 1'b0; data_we_o = 1'b0; data_type_o = 2'b00; @@ -305,9 +319,10 @@ module ibex_decoder import cheri_pkg::*; #( if (CHERIoTEn & cheri_pmode_i & ~illegal_c_insn_i) begin // cheri_ex takes over JAL now as a single-cycle jump cheri_jal_en = 1'b1; - illegal_insn = ~instr_is_legal_cheri; + illegal_insn = 1'b0; + rf_we = 1'b1; end else begin - jump_in_dec_o = 1'b1; + jump_in_dec_o = 1'b1; if (instr_first_cycle_i) begin // Calculate jump target (and store PC + 4 if BranchTargetALU is configured) @@ -325,7 +340,8 @@ module ibex_decoder import cheri_pkg::*; #( // cheri_ex takes over JALR now as a single-cycle jump cheri_jalr_en = (instr[14:12] == 3'b0); rf_ren_a_o = 1'b1; - illegal_insn = ~instr_is_legal_cheri; + rf_we = 1'b1; + illegal_insn = 1'b0; end else begin jump_in_dec_o = 1'b1; @@ -447,7 +463,8 @@ module ibex_decoder import cheri_pkg::*; #( OPCODE_AUIPC: begin if (CHERIoTEn & cheri_pmode_i & ~illegal_c_insn_i) begin cheri_auipcc_en = 1'b1; - illegal_insn = ~instr_is_legal_cheri; + illegal_insn = 1'b0; + rf_we = 1'b1; end else begin // OPCODE_AUIPC: begin // Add Upper Immediate to PC rf_we = 1'b1; @@ -741,6 +758,14 @@ module ibex_decoder import cheri_pkg::*; #( default: csr_illegal = 1'b1; endcase + // always allow access to the following CSRs even without ASR permission + // -- 0xC01-0xC9F (unpriviledged counters) + // -- 0xB01-0xB9F (m-mode counters). + // note 0xb01 is undefined per rvi spec. CSR register logic will handle it. + csr_cheri_always_ok_o = CHERIoTEn & cheri_pmode_i & + (((instr[31:28] == 4'hb) || (instr[31:28] == 4'hc)) && + ((instr[27] == 1'b0) || (instr[26:25] == 2'b00))); + illegal_insn = csr_illegal; end end @@ -750,11 +775,13 @@ module ibex_decoder import cheri_pkg::*; #( cheri_opcode_en = 1'b1; rf_ren_a_o = cheri_rf_ren_a; rf_ren_b_o = cheri_rf_ren_b; + rf_we = cheri_rf_we_dec; illegal_insn = ~instr_is_legal_cheri; end else begin cheri_opcode_en = 1'b0; rf_ren_a_o = 1'b0; rf_ren_b_o = 1'b0; + rf_we = 1'b0; illegal_insn = 1'b1; end end @@ -764,6 +791,7 @@ module ibex_decoder import cheri_pkg::*; #( cheri_auicgp_en = 1'b1; rf_ren_a_o = 1'b1; rf_ren_b_o = 1'b0; + rf_we = 1'b1; illegal_insn = 1'b0; end else begin cheri_opcode_en = 1'b0; @@ -1327,10 +1355,10 @@ module ibex_decoder import cheri_pkg::*; #( // make sure instructions accessing non-available registers in RV32E cause illegal // instruction exceptions - assign illegal_insn_o = illegal_insn | illegal_reg_rv32e; + assign illegal_insn_o = illegal_insn | illegal_reg_rv32e | illegal_reg_cheri; // do not propgate regfile write enable if non-available registers are accessed in RV32E - assign rf_we_o = rf_we & ~illegal_reg_rv32e; + assign rf_we_o = rf_we & ~illegal_reg_rv32e & ~illegal_reg_cheri; // Not all bits are used assign unused_instr_alu = {instr_alu[19:15],instr_alu[11:7]}; @@ -1360,7 +1388,7 @@ module ibex_decoder import cheri_pkg::*; #( .cheri_cs2_dec_o (cheri_cs2_dec_o), .cheri_rf_ren_a_o (cheri_rf_ren_a), .cheri_rf_ren_b_o (cheri_rf_ren_b), - .cheri_rf_we_dec_o (cheri_rf_we_dec_o), + .cheri_rf_we_dec_o (cheri_rf_we_dec), .cheri_multicycle_dec_o (cheri_multicycle_dec_o) ); end else begin @@ -1374,7 +1402,7 @@ module ibex_decoder import cheri_pkg::*; #( assign cheri_cs2_dec_o = 1'b0; assign cheri_rf_ren_a = 1'b0; assign cheri_rf_ren_b = 1'b0; - assign cheri_rf_we_dec_o = 1'b0; + assign cheri_rf_we_dec = 1'b0; assign cheri_multicycle_dec_o = 1'b0; end diff --git a/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv b/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv index ae252cf46..00fbc802c 100644 --- a/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv +++ b/vendor/lowrisc_ibex/rtl/ibex_fetch_fifo.sv @@ -29,6 +29,8 @@ module ibex_fetch_fifo #( input logic [31:0] in_rdata_i, input logic in_err_i, + input logic cheri_force_uc_i, // force unaligned compressed based on CHERI bounds check + // output port output logic out_valid_o, input logic out_ready_i, @@ -108,13 +110,19 @@ module ibex_fetch_fifo #( logic [31:0] instr_pc; logic instr_ack; - assign unaligned_is_compressed = (instr_rdata_dii[1:0] != 2'b11) & ~err; - assign aligned_is_compressed = (instr_rdata_dii[1:0] != 2'b11) & ~err; + // for DII we directly force out_rdata_o (re-aligned instruction) + // to keep the unaligned/aligned_is_compressed signals in sync + // 32-bit instruction; instr_rdata_dii[31:0] = instr + // 16-bit instruction: instr_rdata_dii[15:0] = compressed instruction + // instr_rdata_dii[31:0] = don't care + + assign unaligned_is_compressed = out_addr_o[1] & cheri_force_uc_i | ((instr_rdata_dii[1:0] != 2'b11) & ~err); + assign aligned_is_compressed = ~out_addr_o[1] & (instr_rdata_dii[1:0] != 2'b11) & ~err; assign instr_ack = out_ready_i & out_valid_o; assign instr_pc = out_addr_o; `else - assign unaligned_is_compressed = (rdata[17:16] != 2'b11) & ~err; + assign unaligned_is_compressed = cheri_force_uc_i | ((rdata[17:16] != 2'b11) & ~err); assign aligned_is_compressed = (rdata[ 1: 0] != 2'b11) & ~err; `endif diff --git a/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv b/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv index dc060a212..f0ad97b4b 100644 --- a/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv +++ b/vendor/lowrisc_ibex/rtl/ibex_id_stage.sv @@ -321,15 +321,13 @@ module ibex_id_stage import cheri_pkg::*; #( // CSR control logic csr_pipe_flush; + logic csr_cheri_always_ok; logic [31:0] alu_operand_a; logic [31:0] alu_operand_b; - logic cheri_rf_we, cheri_rf_we_dec; logic stall_cheri_trvk; - assign cheri_rf_we = CHERIoTEn & cheri_pmode_i & instr_valid_i & ~instr_fetch_err_i & ~illegal_insn_o & cheri_rf_we_dec; - ///////////// // LSU Mux // ///////////// @@ -537,6 +535,7 @@ module ibex_id_stage import cheri_pkg::*; #( // CSRs .csr_access_o(csr_access_o), .csr_op_o (csr_op_o), + .csr_cheri_always_ok_o (csr_cheri_always_ok), // LSU .data_req_o (lsu_req_dec), @@ -557,7 +556,6 @@ module ibex_id_stage import cheri_pkg::*; #( .cheri_imm21_o (cheri_imm21_o), .cheri_operator_o (cheri_operator_o), .cheri_cs2_dec_o (cheri_cs2_dec_o), - .cheri_rf_we_dec_o (cheri_rf_we_dec), .cheri_multicycle_dec_o (cheri_multicycle_dec) ); @@ -622,6 +620,8 @@ module ibex_id_stage import cheri_pkg::*; #( .wfi_insn_i (wfi_insn_dec), .ebrk_insn_i (ebrk_insn), .csr_pipe_flush_i(csr_pipe_flush), + .csr_access_i (csr_access_o), + .csr_cheri_always_ok_i (csr_cheri_always_ok), // from IF-ID pipeline .instr_valid_i (instr_valid_i), @@ -1021,11 +1021,11 @@ module ibex_id_stage import cheri_pkg::*; #( // - There was an error on instruction fetch // cheri instr can only generate exception after execution - // exclude cheri exception from insr_kill improves timing + // exclude cheri EX exception from insr_kill improves timing assign instr_kill = instr_fetch_err_i | wb_exception | - id_exception_nc | // exclude cheri exceptions + id_exception_nc | // exclude cheri EX exceptions ~controller_run; // With writeback stage instructions must be prevented from executing if there is: @@ -1113,10 +1113,14 @@ module ibex_id_stage import cheri_pkg::*; #( assign stall_ld_hz = outstanding_load_wb_i & (rf_rd_a_hz | rf_rd_b_hz); + logic rf_we_valid; + assign rf_we_valid = rf_we_dec & instr_valid_i & ~instr_fetch_err_i; + + assign stall_cheri_trvk = (CHERIoTEn & cheri_pmode_i & CheriPPLBC) ? ((rf_ren_a && ~rf_reg_rdy_i[rf_raddr_a_o]) | (rf_ren_b && ~rf_reg_rdy_i[rf_raddr_b_o]) | - (cheri_rf_we && ~ rf_reg_rdy_i[rf_waddr_id_o])) : + (rf_we_valid && ~rf_reg_rdy_i[rf_waddr_id_o])) : 1'b0; assign instr_type_wb_o = ~lsu_req_dec ? WB_INSTR_OTHER : diff --git a/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv b/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv index 4f0e31f33..aad2f1e97 100644 --- a/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv +++ b/vendor/lowrisc_ibex/rtl/ibex_if_stage.sv @@ -176,6 +176,7 @@ module ibex_if_stage import ibex_pkg::*; import cheri_pkg::*; #( logic [7:0] unused_csr_mtvec; logic cheri_acc_vio, cheri_bound_vio; + logic cheri_force_uc; assign unused_boot_addr = boot_addr_i[7:0]; assign unused_csr_mtvec = csr_mtvec_i[7:0]; @@ -290,6 +291,8 @@ module ibex_if_stage import ibex_pkg::*; import cheri_pkg::*; #( .err_o ( fetch_err ), .err_plus2_o ( fetch_err_plus2 ), + .cheri_force_uc_i ( cheri_force_uc ), + .instr_req_o ( instr_req_o ), .instr_addr_o ( instr_addr_o ), .instr_gnt_i ( instr_gnt_i ), @@ -352,28 +355,39 @@ module ibex_if_stage import ibex_pkg::*; import cheri_pkg::*; #( assign if_instr_err = if_instr_bus_err | if_instr_pmp_err | cheri_acc_vio | cheri_bound_vio; // Capture the second half of the address for errors on the second part of an instruction + // LEC_NOT_COMPATIBLE assign if_instr_err_plus2 = ((if_instr_addr[1] & ~instr_is_compressed & pmp_err_if_plus2_i) | fetch_err_plus2) & ~pmp_err_if_i; - // let's only check this in pure-cap mode. otherwise jalr/ret gives so much headache // pre-calculate headroom to improve memory read timing - logic [2:0] unused_instr_len; - logic [32:0] instr_hdrm; - logic hdrm_ge4, hdrm_ge2, hdrm_ok; + logic [33:0] instr_hdrm; + logic hdrm_ge4, hdrm_ge2, hdrm_ok, base_ok; + logic allow_all; + + // allow_all is used to permit the pc wraparound case (pc = 0xffff_fffe, uncompressed instruction) + // - in this case fetch should be allowed if pcc bounds is specified as the entire 32-bit space. + // - If we don't treat this as a specail case the fetch would be erred since headroom < 4 + assign allow_all = (pcc_cap_i.base32==0) & (pcc_cap_i.top33==33'h1_0000_0000); - assign unused_instr_len = (fetch_valid & ~fetch_err & instr_is_compressed) ? 2 : 4; - assign instr_hdrm = pcc_cap_i.top33 - if_instr_addr; - assign hdrm_ge4 = (instr_hdrm >= 4); - assign hdrm_ge2 = (instr_hdrm >= 2); - assign hdrm_ok = instr_is_compressed ? hdrm_ge2 : hdrm_ge4; + assign instr_hdrm = {1'b0, pcc_cap_i.top33} - {2'b00, if_instr_addr}; + assign hdrm_ge4 = (|instr_hdrm[32:2]) & ~instr_hdrm[33]; // >= 4 + assign hdrm_ge2 = (|instr_hdrm[32:1]) & ~instr_hdrm[33]; // >= 2 + assign hdrm_ok = allow_all || (instr_is_compressed ? hdrm_ge2 : hdrm_ge4); + assign base_ok = ~(if_instr_addr < pcc_cap_i.base32); // only issue cheri_acc_vio on valid fetches - assign cheri_bound_vio = CHERIoTEn & cheri_pmode_i & ~debug_mode_i & fetch_valid & ~fetch_err & pcc_cap_i.valid & - ((if_instr_addr < pcc_cap_i.base32) || instr_hdrm[32] || ~hdrm_ok); + assign cheri_bound_vio = CHERIoTEn & cheri_pmode_i & ~debug_mode_i & (~base_ok || ~hdrm_ok); + + // In order to have constant timing (avoid side-channel leakage due to data-dependent behavior), + // if base vio or headroom < 4 (we are only authorized to fetch 2 bytes), force the fetch_fifo + // to treat the current rdata as a unaligned compressed instruction if pc[1]=1, and push it to + // ID stage without waiting for the 2nd part of 32-bit instruciton. + // + assign cheri_force_uc = CHERIoTEn & cheri_pmode_i & ~allow_all & (~base_ok | ~hdrm_ge4); // we still check seal/perm here to be safe, however by ISA those can't happen at fetch time // since they are check elsewhere already - assign cheri_acc_vio = CHERIoTEn & cheri_pmode_i & ~debug_mode_i & fetch_valid & ~fetch_err & + assign cheri_acc_vio = CHERIoTEn & cheri_pmode_i & ~debug_mode_i & (~pcc_cap_i.perms[PERM_EX] || ~pcc_cap_i.valid || (pcc_cap_i.otype!=0)); // compressed instruction decoding, or more precisely compressed instruction diff --git a/vendor/lowrisc_ibex/rtl/ibex_prefetch_buffer.sv b/vendor/lowrisc_ibex/rtl/ibex_prefetch_buffer.sv index 5b834ce2d..77131f27f 100644 --- a/vendor/lowrisc_ibex/rtl/ibex_prefetch_buffer.sv +++ b/vendor/lowrisc_ibex/rtl/ibex_prefetch_buffer.sv @@ -30,6 +30,8 @@ module ibex_prefetch_buffer #( output logic err_o, output logic err_plus2_o, + input logic cheri_force_uc_i, + // goes to instruction memory / instruction cache output logic instr_req_o, input logic instr_gnt_i, @@ -108,6 +110,7 @@ module ibex_prefetch_buffer #( .in_addr_i ( fifo_addr ), .in_rdata_i ( instr_rdata_i ), .in_err_i ( instr_err_i ), + .cheri_force_uc_i ( cheri_force_uc_i ), .out_valid_o ( valid_raw ), .out_ready_i ( ready_i ), diff --git a/vendor/lowrisc_ibex/rtl/ibex_tracer.sv b/vendor/lowrisc_ibex/rtl/ibex_tracer.sv index 64692a6a9..b12e5833e 100644 --- a/vendor/lowrisc_ibex/rtl/ibex_tracer.sv +++ b/vendor/lowrisc_ibex/rtl/ibex_tracer.sv @@ -1372,6 +1372,7 @@ module ibex_tracer import cheri_pkg::*; # ( INSN_CHMOVE: decode_cheri_cd_cs1_insn("CH.cmove"); INSN_CHTESTSUB: decode_cheri_rd_cs1_cs2_insn("CH.ctestsubset"); INSN_CHSETEQUAL: decode_cheri_rd_cs1_cs2_insn("CH.csetequalexact"); + INSN_CHSETHIGH: decode_cheri_cd_cs1_rs2_insn("CH.csethigh"); //INSN_CHJALR: decode_cheri_cd_cs1_insn("CH.jalr"); INSN_CHCSRRW: decode_cheri_scrrw_insn(); INSN_AUIPC: decode_cheri_auipcc_insn(); diff --git a/vendor/lowrisc_ibex/rtl/ibex_tracer_pkg.sv b/vendor/lowrisc_ibex/rtl/ibex_tracer_pkg.sv index 04bfdd723..a79d88579 100644 --- a/vendor/lowrisc_ibex/rtl/ibex_tracer_pkg.sv +++ b/vendor/lowrisc_ibex/rtl/ibex_tracer_pkg.sv @@ -368,6 +368,7 @@ package ibex_tracer_pkg; parameter logic [31:0] INSN_CHMOVE = {7'h7f, 5'ha, 5'h?, 3'b000, 5'h?, {OPCODE_CHERI} }; parameter logic [31:0] INSN_CHTESTSUB = {7'h20, 5'h?, 5'h?, 3'b000, 5'h?, {OPCODE_CHERI} }; parameter logic [31:0] INSN_CHSETEQUAL = {7'h21, 5'h?, 5'h?, 3'b000, 5'h?, {OPCODE_CHERI} }; + parameter logic [31:0] INSN_CHSETHIGH = {7'h16, 5'h?, 5'h?, 3'b000, 5'h?, {OPCODE_CHERI} }; parameter logic [31:0] INSN_CHJALR = {7'h7f, 5'hc, 5'h?, 3'b000, 5'h?, {OPCODE_CHERI} }; diff --git a/vendor/lowrisc_ibex/rtl/ibexc_top.sv b/vendor/lowrisc_ibex/rtl/ibexc_top.sv index 408c19ba9..32278085f 100644 --- a/vendor/lowrisc_ibex/rtl/ibexc_top.sv +++ b/vendor/lowrisc_ibex/rtl/ibexc_top.sv @@ -40,7 +40,8 @@ module ibexc_top import ibex_pkg::*; import cheri_pkg::*; #( parameter bit CheriSBND2 = 1'b0, parameter bit CheriTBRE = 1'b0, parameter int unsigned MMRegDinW = 128, - parameter int unsigned MMRegDoutW = 64 + parameter int unsigned MMRegDoutW = 64, + parameter bit ICache = 1'b0 ) ( // Clock and Reset input logic clk_i, @@ -158,6 +159,10 @@ module ibexc_top import ibex_pkg::*; import cheri_pkg::*; #( localparam bit ResetAll = 1'b1; localparam int unsigned RegFileDataWidth = 32; + localparam int unsigned BusSizeECC = BUS_SIZE; + localparam int unsigned LineSizeECC = BusSizeECC * IC_LINE_BEATS; + localparam int unsigned TagSizeECC = IC_TAG_SIZE; + // Clock signals logic clk; logic core_busy_d, core_busy_q; @@ -181,6 +186,17 @@ module ibexc_top import ibex_pkg::*; import cheri_pkg::*; #( logic [4:0] rf_trsv_addr; logic rf_trsv_en; + logic [IC_NUM_WAYS-1:0] ic_tag_req; + logic ic_tag_write; + logic [IC_INDEX_W-1:0] ic_tag_addr; + logic [TagSizeECC-1:0] ic_tag_wdata; + logic [TagSizeECC-1:0] ic_tag_rdata [IC_NUM_WAYS]; + logic [IC_NUM_WAYS-1:0] ic_data_req; + logic ic_data_write; + logic [IC_INDEX_W-1:0] ic_data_addr; + logic [LineSizeECC-1:0] ic_data_wdata; + logic [LineSizeECC-1:0] ic_data_rdata [IC_NUM_WAYS]; + fetch_enable_t fetch_enable_buf; ///////////////////// @@ -244,7 +260,7 @@ module ibexc_top import ibex_pkg::*; import cheri_pkg::*; #( .RV32M (RV32MFast), .RV32B (RV32BNone), .BranchTargetALU (1'b1), - .ICache (1'b0), + .ICache (ICache), .ICacheECC (1'b0), .BusSizeECC (BUS_SIZE), .TagSizeECC (IC_TAG_SIZE), @@ -379,17 +395,18 @@ module ibexc_top import ibex_pkg::*; import cheri_pkg::*; #( .alert_major_o(alert_major_internal_o), .icache_inval_o(), .core_busy_o (core_busy_d), - .ic_scr_key_valid_i (1'b0), - .ic_data_rdata_i (), - .ic_data_wdata_o (), - .ic_data_addr_o (), - .ic_data_write_o (), - .ic_data_req_o (), - .ic_tag_rdata_i (), - .ic_tag_wdata_o (), - .ic_tag_addr_o (), - .ic_tag_write_o (), - .ic_tag_req_o () + + .ic_tag_req_o (ic_tag_req), + .ic_tag_write_o (ic_tag_write), + .ic_tag_addr_o (ic_tag_addr), + .ic_tag_wdata_o (ic_tag_wdata), + .ic_tag_rdata_i (ic_tag_rdata), + .ic_data_req_o (ic_data_req), + .ic_data_write_o (ic_data_write), + .ic_data_addr_o (ic_data_addr), + .ic_data_wdata_o (ic_data_wdata), + .ic_data_rdata_i (ic_data_rdata), + .ic_scr_key_valid_i(1'b0) ); assign data_wdata_intg_o = 7'h0; @@ -458,6 +475,47 @@ module ibexc_top import ibex_pkg::*; import cheri_pkg::*; #( ); end + for (genvar way = 0; way < IC_NUM_WAYS; way++) begin : gen_rams_inner + + // Tag RAM instantiation + prim_ram_1p #( + .Width (TagSizeECC), + .Depth (IC_NUM_LINES), + .DataBitsPerMask (TagSizeECC) + ) tag_bank ( + .clk_i, + + .req_i (ic_tag_req[way]), + + .write_i (ic_tag_write), + .addr_i (ic_tag_addr), + .wdata_i (ic_tag_wdata), + .wmask_i ({TagSizeECC{1'b1}}), + + .rdata_o (ic_tag_rdata[way]), + .cfg_i (ram_cfg_i) + ); + + // Data RAM instantiation + prim_ram_1p #( + .Width (LineSizeECC), + .Depth (IC_NUM_LINES), + .DataBitsPerMask (LineSizeECC) + ) data_bank ( + .clk_i, + + .req_i (ic_data_req[way]), + + .write_i (ic_data_write), + .addr_i (ic_data_addr), + .wdata_i (ic_data_wdata), + .wmask_i ({LineSizeECC{1'b1}}), + + .rdata_o (ic_data_rdata[way]), + .cfg_i (ram_cfg_i) + ); + end + assign scramble_req_o = 0; endmodule diff --git a/vendor/lowrisc_ibex/rtl/ibexc_top_tracing.sv b/vendor/lowrisc_ibex/rtl/ibexc_top_tracing.sv index b0d40c113..c12646ae1 100644 --- a/vendor/lowrisc_ibex/rtl/ibexc_top_tracing.sv +++ b/vendor/lowrisc_ibex/rtl/ibexc_top_tracing.sv @@ -22,7 +22,8 @@ module ibexc_top_tracing import ibex_pkg::*; import cheri_pkg::*; #( parameter int unsigned TSMapSize = 1024, // in words parameter int unsigned MMRegDinW = 128, parameter int unsigned MMRegDoutW = 64, - parameter int unsigned DataWidth = 33 // this enables testbench to use defparam to override + parameter int unsigned DataWidth = 33, // this enables testbench to use defparam to override + parameter bit ICache = 1'b0 ) ( // Clock and Reset input logic clk_i, @@ -164,7 +165,8 @@ module ibexc_top_tracing import ibex_pkg::*; import cheri_pkg::*; #( .CheriSBND2 (1'b0), .CheriTBRE (1'b1), .MMRegDinW (MMRegDinW), - .MMRegDoutW (MMRegDoutW) + .MMRegDoutW (MMRegDoutW), + .ICache (ICache) ) u_ibex_top ( .clk_i, .rst_ni, diff --git a/vendor/lowrisc_ibex/vendor/lowrisc_ip/ip/prim/rtl/prim_util_memload.svh b/vendor/lowrisc_ibex/vendor/lowrisc_ip/ip/prim/rtl/prim_util_memload.svh index dea7ddc60..7f8c6da92 100644 --- a/vendor/lowrisc_ibex/vendor/lowrisc_ip/ip/prim/rtl/prim_util_memload.svh +++ b/vendor/lowrisc_ibex/vendor/lowrisc_ip/ip/prim/rtl/prim_util_memload.svh @@ -55,13 +55,11 @@ `endif initial begin -`ifndef SYNTHESIS logic show_mem_paths; // Print the hierarchical path to the memory to help make formal connectivity checks easy. void'($value$plusargs("show_mem_paths=%0b", show_mem_paths)); if (show_mem_paths) $display("%m"); -`endif if (MemInitFile != "") begin : gen_meminit $display("Initializing memory %m from file '%s'.", MemInitFile);